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.
Files changed (30) hide show
  1. package/README.md +1 -0
  2. package/dist/{batch-7V7OTMUP.js → batch-CHAPYRVM.js} +2 -2
  3. package/dist/chunk-3I4RZYYO.js +638 -0
  4. package/dist/{chunk-L4UREAID.js → chunk-4ZN6L6K5.js} +3 -3
  5. package/dist/{chunk-VGFTM3XT.js → chunk-64NUW3WL.js} +1 -1
  6. package/dist/{chunk-C2Z42DI5.js → chunk-EGMORH5W.js} +1 -1
  7. package/dist/{chunk-GX3HSGJX.js → chunk-GEN4O5QH.js} +165 -637
  8. package/dist/chunk-GGKQHPB3.js +604 -0
  9. package/dist/{chunk-P4VBLXKS.js → chunk-KIEZBTVD.js} +1 -1
  10. package/dist/{chunk-H2UIHGHH.js → chunk-QUFYBR6Q.js} +29 -189
  11. package/dist/{chunk-NTCB7CMT.js → chunk-U7KVU25H.js} +1 -1
  12. package/dist/{chunk-5CA2TJ5F.js → chunk-VADHBW7T.js} +1 -1
  13. package/dist/{ci-L6GH2WVC.js → ci-QPP66T53.js} +4 -4
  14. package/dist/{ci-format-WW7454AY.js → ci-format-5S3EEYRK.js} +2 -2
  15. package/dist/{constants-NCTFSHDU.js → constants-FJOLBABC.js} +1 -1
  16. package/dist/doctor-cli-KB2LUDF3.js +17 -0
  17. package/dist/electron-server.js +419 -116
  18. package/dist/{hub-CDL6T7CP.js → hub-DIM7SKKY.js} +1 -1
  19. package/dist/index.js +71 -181
  20. package/dist/{pr-D6PEKEGK.js → pr-YQGH72N6.js} +4 -4
  21. package/dist/{run-tests-SWU2XEV7.js → run-tests-GEZSSNJM.js} +2 -2
  22. package/dist/{run-tests-NXVVKAK2.js → run-tests-O76JIBCW.js} +1 -1
  23. package/dist/{server-LHYSS6CK.js → server-5E2AIXVX.js} +39 -75
  24. package/dist/{server-WUT7VYTD.js → server-Z6O3G2LY.js} +9 -9
  25. package/dist/{task-orchestrator-C5AA2BI5.js → task-orchestrator-5HBW4O64.js} +9 -9
  26. package/dist/{usage-6ZUUJBI2.js → usage-BMK6M5U3.js} +2 -2
  27. package/package.json +1 -1
  28. package/dist/chunk-MWKE2TNS.js +0 -129
  29. package/dist/chunk-OUC75QCF.js +0 -166
  30. package/dist/doctor-cli-EWMFBP5Q.js +0 -226
@@ -38,7 +38,7 @@ import {
38
38
  VERSION,
39
39
  buildUserIdentityPrompt,
40
40
  runTestsTool
41
- } from "./chunk-C2Z42DI5.js";
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 join23, dirname as dirname8, resolve as resolve11, relative as relative4, sep as sep3 } from "path";
68
- import { existsSync as existsSync28, readFileSync as readFileSync22, readdirSync as readdirSync14, statSync as statSync10, realpathSync } from "fs";
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 existsSync26, readFileSync as readFileSync20, writeFileSync as writeFileSync2, mkdirSync as mkdirSync12, readdirSync as readdirSync12, statSync as statSync9, createWriteStream } from "fs";
13590
- import { join as join21, resolve as resolve10, dirname as dirname7 } from "path";
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 join20 } from "path";
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: join20(config.getHistoryDir(), `${session.id}.json`) };
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
- mkdirSync12(dirname7(pendingTeeSave), { recursive: true });
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
- mkdirSync12(dirname7(saveToFile), { recursive: true });
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 = existsSync26(filePath) ? (() => {
16385
+ const currentContent = existsSync28(filePath) ? (() => {
16043
16386
  try {
16044
- return readFileSync20(filePath, "utf-8");
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-NXVVKAK2.js");
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 = join21(cwd, "AICLI.md");
16920
+ const targetPath = join23(cwd, "AICLI.md");
16578
16921
  const force = args.includes("--force");
16579
- if (existsSync26(targetPath) && !force) {
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
- writeFileSync2(targetPath, content, "utf-8");
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 lines = ["\u{1FA7A} **AI-CLI Health Check**", ""];
16600
- lines.push("**API Keys:**");
16601
- const providersList = this.providers.listAll();
16602
- for (const p of providersList) {
16603
- const icon = p.configured ? "\u2713" : "\u25CB";
16604
- const status = p.configured ? "configured" : "not configured";
16605
- lines.push(` ${icon} ${p.id.padEnd(14)} ${status}`);
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 (!existsSync26(dirPath)) {
17115
+ if (!existsSync28(dirPath)) {
16813
17116
  this.send({ type: "error", message: `Directory not found: ${dirPath}` });
16814
17117
  break;
16815
17118
  }
16816
- if (!statSync9(dirPath).isDirectory()) {
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 = join21(configDir, CUSTOM_COMMANDS_DIR_NAME);
16829
- if (!existsSync26(commandsDir)) {
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 = readdirSync12(commandsDir).filter((f) => f.endsWith(".md"));
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 = join21(configDir, PLUGINS_DIR_NAME);
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(join21(configDir, MEMORY_FILE_NAME), "");
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 existsSync27, readFileSync as readFileSync21, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync13, copyFileSync } from "fs";
17420
- import { join as join22 } from "path";
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 = join22(baseDir, USERS_FILE);
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 = join22(USERS_DIR, username);
17465
- const fullDataDir = join22(this.baseDir, dataDir);
17466
- mkdirSync13(join22(fullDataDir, "history"), { recursive: true });
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 join22(this.baseDir, user.dataDir);
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 = join22(this.baseDir, "config.json");
17618
- if (existsSync27(globalConfig)) {
17920
+ const globalConfig = join24(this.baseDir, "config.json");
17921
+ if (existsSync29(globalConfig)) {
17619
17922
  try {
17620
- const content = readFileSync21(globalConfig, "utf-8");
17621
- writeFileSync3(join22(userDir, "config.json"), content, "utf-8");
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 = join22(this.baseDir, "memory.md");
17626
- if (existsSync27(globalMemory)) {
17928
+ const globalMemory = join24(this.baseDir, "memory.md");
17929
+ if (existsSync29(globalMemory)) {
17627
17930
  try {
17628
- const content = readFileSync21(globalMemory, "utf-8");
17629
- writeFileSync3(join22(userDir, "memory.md"), content, "utf-8");
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 = join22(this.baseDir, "history");
17634
- if (existsSync27(globalHistory)) {
17936
+ const globalHistory = join24(this.baseDir, "history");
17937
+ if (existsSync29(globalHistory)) {
17635
17938
  try {
17636
- const files = readdirSync13(globalHistory).filter((f) => f.endsWith(".json"));
17637
- const userHistory = join22(userDir, "history");
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(join22(globalHistory, f), join22(userHistory, f));
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 (existsSync27(this.usersFile)) {
17954
+ if (existsSync29(this.usersFile)) {
17652
17955
  try {
17653
- return JSON.parse(readFileSync21(this.usersFile, "utf-8"));
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
- mkdirSync13(this.baseDir, { recursive: true });
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 = join23(config.getConfigDir(), SKILLS_DIR_NAME);
17773
- if (existsSync28(skillsDir)) {
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 = join23(moduleDir, "web", "client");
17845
- if (!existsSync28(clientDir)) {
17846
- clientDir = join23(moduleDir, "client");
18147
+ let clientDir = join25(moduleDir, "web", "client");
18148
+ if (!existsSync30(clientDir)) {
18149
+ clientDir = join25(moduleDir, "client");
17847
18150
  }
17848
- if (!existsSync28(clientDir)) {
17849
- clientDir = join23(moduleDir, "..", "..", "src", "web", "client");
18151
+ if (!existsSync30(clientDir)) {
18152
+ clientDir = join25(moduleDir, "..", "..", "src", "web", "client");
17850
18153
  }
17851
- if (!existsSync28(clientDir)) {
17852
- clientDir = join23(process.cwd(), "src", "web", "client");
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(join23(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
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 = join23(cwd, prefix);
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 = readdirSync14(targetDir, { withFileTypes: true });
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, join23(targetDir, e.name)).replace(/\\/g, "/"),
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 = join23(histDir, `${id}.json`);
17976
- if (!existsSync28(filePath)) {
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(readFileSync22(filePath, "utf-8"));
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(join23(cwd, filePath));
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 = statSync10(fullPath);
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 = readFileSync22(fullPath, "utf-8");
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 = join23(projectRoot, MCP_PROJECT_CONFIG_NAME);
18278
- return existsSync28(configPath) ? configPath : null;
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 = join23(projectRoot, MCP_PROJECT_CONFIG_NAME);
18285
- if (!existsSync28(configPath)) return null;
18587
+ const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
18588
+ if (!existsSync30(configPath)) return null;
18286
18589
  try {
18287
- const raw = JSON.parse(readFileSync22(configPath, "utf-8"));
18590
+ const raw = JSON.parse(readFileSync23(configPath, "utf-8"));
18288
18591
  return raw.mcpServers ?? raw;
18289
18592
  } catch {
18290
18593
  return null;