jinzd-ai-cli 0.4.330 → 0.4.333

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 (47) hide show
  1. package/dist/{batch-GXITPLER.js → batch-TYKULVIK.js} +2 -2
  2. package/dist/{chunk-LLXHA2LA.js → chunk-3JGBKYCN.js} +8 -8
  3. package/dist/{chunk-DX2U6QK4.js → chunk-4RVLGIK3.js} +1 -1
  4. package/dist/{chunk-DU44SD6A.js → chunk-4TKEA7RE.js} +1 -1
  5. package/dist/{chunk-GEC3MEVQ.js → chunk-5MUAJ742.js} +6 -4
  6. package/dist/{chunk-LUJ4JVMI.js → chunk-6WQCZTAJ.js} +4 -4
  7. package/dist/{chunk-M5B6G6AY.js → chunk-A4KKNBG3.js} +9 -7
  8. package/dist/{chunk-E2W2MI6H.js → chunk-C6GA7H5D.js} +1 -72
  9. package/dist/{chunk-C2Z77RTU.js → chunk-DAAR4XOY.js} +17 -4
  10. package/dist/{chunk-265M6ZLH.js → chunk-H4UIWMA5.js} +4 -4
  11. package/dist/{chunk-AJITHMRE.js → chunk-JTXHWIBO.js} +1 -1
  12. package/dist/{chunk-GWEBO4RF.js → chunk-K4AYNZF7.js} +1 -1
  13. package/dist/{chunk-72AR23R2.js → chunk-NP2GRK2N.js} +54 -2
  14. package/dist/{chunk-CCFCPAKN.js → chunk-NRDCQGAN.js} +1 -1
  15. package/dist/chunk-W4P2KJZN.js +75 -0
  16. package/dist/{chunk-HMQA2R3O.js → chunk-YIEOU7NG.js} +1 -1
  17. package/dist/{chunk-3YVZJHTF.js → chunk-YUQYVOY2.js} +1 -1
  18. package/dist/{chunk-2SYDIWRU.js → chunk-ZQ5HR7XN.js} +1 -1
  19. package/dist/{chunk-QU74ONFF.js → chunk-ZQFOY5FB.js} +1 -1
  20. package/dist/{ci-6K3JNHB4.js → ci-MYKIATCI.js} +7 -6
  21. package/dist/{ci-format-2L3RFJVH.js → ci-format-QOXT6E3A.js} +2 -2
  22. package/dist/{constants-J5SJ232X.js → constants-C55HE2E5.js} +1 -1
  23. package/dist/{constants-DLJECTGQ.js → constants-WK2I2UCZ.js} +1 -1
  24. package/dist/{doctor-cli-BHS7G2XY.js → doctor-cli-63GBR2D3.js} +7 -6
  25. package/dist/electron-server.js +195 -130
  26. package/dist/{hub-PPG4N6QQ.js → hub-J4FZ4GXX.js} +8 -18
  27. package/dist/{hub-server-JLC7CNP7.js → hub-server-HOQ6S3NK.js} +2 -1
  28. package/dist/index.js +20 -19
  29. package/dist/{persistent-memory-3XTSZ3QR.js → persistent-memory-6JN7AWD6.js} +2 -2
  30. package/dist/{persistent-memory-O4T2OTVV.js → persistent-memory-AEIRTKWX.js} +2 -2
  31. package/dist/{pr-M6ZY4CEK.js → pr-C53TJRXV.js} +7 -6
  32. package/dist/{run-tests-WQE3XTUL.js → run-tests-BKFV3HUZ.js} +2 -2
  33. package/dist/{run-tests-H3DIUCDB.js → run-tests-CZLZW5RL.js} +2 -2
  34. package/dist/{server-J2B26DZK.js → server-2GYX4CJC.js} +7 -6
  35. package/dist/{server-5NQSYQ2T.js → server-2UB74CEK.js} +29 -19
  36. package/dist/{task-orchestrator-CI7EDT25.js → task-orchestrator-EVONAO6V.js} +9 -7
  37. package/dist/{usage-AJYZ5A7P.js → usage-6Y7K2GNN.js} +2 -2
  38. package/dist/web/client/app.js +40 -16
  39. package/dist/web/client/app.js.br +0 -0
  40. package/dist/web/client/app.js.gz +0 -0
  41. package/dist/web/client/index.html +2 -1
  42. package/dist/web/client/index.html.br +0 -0
  43. package/dist/web/client/index.html.gz +0 -0
  44. package/dist/web/client/style.css +1 -0
  45. package/dist/web/client/style.css.br +0 -0
  46. package/dist/web/client/style.css.gz +0 -0
  47. package/package.json +1 -1
@@ -55,7 +55,7 @@ import {
55
55
  touchMemoryReferences,
56
56
  updateMemoryApproval,
57
57
  updateMemoryEntry
58
- } from "./chunk-2SYDIWRU.js";
58
+ } from "./chunk-ZQ5HR7XN.js";
59
59
  import {
60
60
  DEFAULT_PATTERNS,
61
61
  redactJson,
@@ -81,7 +81,7 @@ import {
81
81
  recoverGbkMojibake,
82
82
  runTestsTool,
83
83
  shellInvocation
84
- } from "./chunk-DU44SD6A.js";
84
+ } from "./chunk-4TKEA7RE.js";
85
85
  import {
86
86
  getCurrentSessionKey,
87
87
  getExecutionConfigDir,
@@ -123,7 +123,7 @@ import {
123
123
  SUBAGENT_MAX_ROUNDS_LIMIT,
124
124
  VERSION,
125
125
  buildUserIdentityPrompt
126
- } from "./chunk-3YVZJHTF.js";
126
+ } from "./chunk-YUQYVOY2.js";
127
127
 
128
128
  // src/web/access.ts
129
129
  import { randomBytes, timingSafeEqual } from "crypto";
@@ -205,8 +205,8 @@ function imageValidationError(images) {
205
205
  }
206
206
 
207
207
  // src/web/server.ts
208
- import { join as join25, dirname as dirname12, resolve as resolve12, relative as relative6, sep as sep5, extname as extname3, resolve as resolvePath } from "path";
209
- import { existsSync as existsSync31, readFileSync as readFileSync22, readdirSync as readdirSync15, statSync as statSync16, realpathSync as realpathSync3, createReadStream } from "fs";
208
+ import { join as join26, dirname as dirname12, resolve as resolve12, relative as relative6, sep as sep5, extname as extname3, resolve as resolvePath } from "path";
209
+ import { existsSync as existsSync32, readFileSync as readFileSync23, readdirSync as readdirSync16, statSync as statSync16, realpathSync as realpathSync3, createReadStream } from "fs";
210
210
  import { networkInterfaces as networkInterfaces2 } from "os";
211
211
 
212
212
  // src/config/config-manager.ts
@@ -2859,12 +2859,12 @@ function findPhantomClaims(content, extraMessages) {
2859
2859
  const claimed = extractClaimedFilePaths(content);
2860
2860
  if (claimed.length === 0) return [];
2861
2861
  const normalize = (p) => p.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
2862
- const basename11 = (p) => {
2862
+ const basename12 = (p) => {
2863
2863
  const parts = normalize(p).split("/");
2864
2864
  return parts[parts.length - 1] ?? "";
2865
2865
  };
2866
2866
  const written = extractWrittenFilePaths(extraMessages).map(normalize);
2867
- const writtenBases = new Set(written.map(basename11));
2867
+ const writtenBases = new Set(written.map(basename12));
2868
2868
  const writtenFull = new Set(written);
2869
2869
  const bashText = extractBashCommands(extraMessages).map((c) => c.replace(/\\/g, "/").toLowerCase()).join("\n");
2870
2870
  return claimed.filter((raw) => {
@@ -2873,8 +2873,8 @@ function findPhantomClaims(content, extraMessages) {
2873
2873
  for (const w of writtenFull) {
2874
2874
  if (w.endsWith("/" + norm2) || norm2.endsWith("/" + w)) return false;
2875
2875
  }
2876
- if (writtenBases.has(basename11(norm2))) return false;
2877
- const base = basename11(norm2);
2876
+ if (writtenBases.has(basename12(norm2))) return false;
2877
+ const base = basename12(norm2);
2878
2878
  if (base && bashText.includes(base)) return false;
2879
2879
  return true;
2880
2880
  });
@@ -16004,8 +16004,14 @@ function stripConvergedMarker(content) {
16004
16004
 
16005
16005
  // src/hub/agent.ts
16006
16006
  var PASS_MARKER = "[PASS]";
16007
+ function stripThinkBlocks(raw) {
16008
+ const filter = new ThinkTagFilter();
16009
+ return filter.push(raw) + filter.flush();
16010
+ }
16011
+ var REASONING_ONLY_NOTICE = "(no reply this round \u2014 reasoning ran past the output limit)";
16007
16012
  function parseTurn(raw) {
16008
- const trimmed = raw.trim();
16013
+ let trimmed = stripThinkBlocks(raw).trim();
16014
+ if (!trimmed && /<think>/i.test(raw)) trimmed = REASONING_ONLY_NOTICE;
16009
16015
  const upper = trimmed.toUpperCase();
16010
16016
  if (upper.startsWith(PASS_MARKER) || upper === PASS_MARKER) {
16011
16017
  return { content: "", passed: true, converged: false };
@@ -16085,6 +16091,7 @@ var HubAgent = class {
16085
16091
  const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
16086
16092
  const messages = this.buildMessages(history);
16087
16093
  let raw = "";
16094
+ const thinkFilter = new ThinkTagFilter();
16088
16095
  const stream = provider.chatStream({
16089
16096
  messages,
16090
16097
  model: this.modelId,
@@ -16099,13 +16106,16 @@ var HubAgent = class {
16099
16106
  for await (const chunk of stream) {
16100
16107
  if (chunk.delta) {
16101
16108
  raw += chunk.delta;
16102
- onToken?.(chunk.delta);
16109
+ const visible = thinkFilter.push(chunk.delta);
16110
+ if (visible) onToken?.(visible);
16103
16111
  }
16104
16112
  if (opts?.signal?.aborted) break;
16105
16113
  }
16106
16114
  } catch (error) {
16107
16115
  if (!opts?.signal?.aborted) throw error;
16108
16116
  }
16117
+ const tail = thinkFilter.flush();
16118
+ if (tail) onToken?.(tail);
16109
16119
  const { content, passed, converged } = parseTurn(raw);
16110
16120
  return {
16111
16121
  speaker: this.role.id,
@@ -16140,7 +16150,7 @@ var HubAgent = class {
16140
16150
  maxTokens: 4096,
16141
16151
  ...this.thinking ?? {}
16142
16152
  });
16143
- return response.content.trim();
16153
+ return stripThinkBlocks(response.content).trim();
16144
16154
  }
16145
16155
  // ── Private ──────────────────────────────────────────────────────
16146
16156
  buildSystemPrompt(topic, round, maxRounds, voteConverge) {
@@ -16221,7 +16231,7 @@ Produce a structured, decision-oriented synthesis with these exact sections:
16221
16231
  4. **Action Items** \u2014 concrete next steps as a checklist. For each, suggest which role/expertise should own it, e.g. "- [ ] (\u67B6\u6784\u5E08) \u8BC4\u4F30\u670D\u52A1\u62C6\u5206\u8FB9\u754C".
16222
16232
  5. **Risks & Open Questions** \u2014 unresolved issues and what to watch.
16223
16233
 
16224
- Keep it tight (within ~600 words). Use the same language as the discussion.`;
16234
+ Keep it tight (within ~600 words). Use the same language as the discussion \u2014 including the section headings (translate them, e.g. \u51B3\u7B56 / \u5EFA\u8BAE\u3001\u5173\u952E\u5171\u8BC6\u3001\u5206\u6B67\u70B9\u3001\u884C\u52A8\u9879\u3001\u98CE\u9669\u4E0E\u5F00\u653E\u95EE\u9898 for a Chinese discussion).`;
16225
16235
  }
16226
16236
  };
16227
16237
 
@@ -16597,8 +16607,57 @@ function resolveRoleProviders(roles, lookup, defaultProvider, defaultModel, avai
16597
16607
  return { roles: outRoles, assignments, warnings };
16598
16608
  }
16599
16609
 
16610
+ // src/hub/custom-presets.ts
16611
+ import { existsSync as existsSync25, readdirSync as readdirSync12, readFileSync as readFileSync18 } from "fs";
16612
+ import { join as join18, basename as basename10 } from "path";
16613
+ var CUSTOM_PRESET_PREFIX = "custom:";
16614
+ var HUB_ROLES_DIRNAME = "hub-roles";
16615
+ function parseRolesJson(parsed) {
16616
+ const rawRoles = Array.isArray(parsed) ? parsed : parsed?.roles;
16617
+ if (!Array.isArray(rawRoles) || rawRoles.length === 0) {
16618
+ throw new Error("roles must be a non-empty array");
16619
+ }
16620
+ return rawRoles.map((r) => ({
16621
+ id: r.id ?? r.name?.toLowerCase().replace(/\s+/g, "-") ?? "agent",
16622
+ name: r.name ?? r.id ?? "Agent",
16623
+ persona: r.persona ?? r.description ?? `You are ${r.name ?? "an AI assistant"}.`,
16624
+ ...r.provider && { provider: r.provider },
16625
+ ...r.model && { model: r.model },
16626
+ ...r.color && { color: r.color }
16627
+ }));
16628
+ }
16629
+ function loadCustomPresets(configDir) {
16630
+ const dir = join18(configDir, HUB_ROLES_DIRNAME);
16631
+ const presets = [];
16632
+ const warnings = [];
16633
+ if (!existsSync25(dir)) return { presets, warnings };
16634
+ let files;
16635
+ try {
16636
+ files = readdirSync12(dir).filter((f) => f.toLowerCase().endsWith(".json")).sort();
16637
+ } catch (err) {
16638
+ return { presets, warnings: [`${dir}: ${err.message}`] };
16639
+ }
16640
+ for (const file of files) {
16641
+ const stem = basename10(file, file.slice(file.lastIndexOf(".")));
16642
+ try {
16643
+ const parsed = JSON.parse(readFileSync18(join18(dir, file), "utf-8").replace(/^/, ""));
16644
+ const roles = parseRolesJson(parsed);
16645
+ const meta = Array.isArray(parsed) ? {} : parsed;
16646
+ presets.push({
16647
+ id: `${CUSTOM_PRESET_PREFIX}${stem}`,
16648
+ name: typeof meta.name === "string" && meta.name.trim() ? meta.name.trim() : stem,
16649
+ description: typeof meta.description === "string" && meta.description.trim() ? meta.description.trim() : roles.map((r) => r.name).join("\xB7"),
16650
+ roles
16651
+ });
16652
+ } catch (err) {
16653
+ warnings.push(`${HUB_ROLES_DIRNAME}/${file}: ${err.message}`);
16654
+ }
16655
+ }
16656
+ return { presets, warnings };
16657
+ }
16658
+
16600
16659
  // src/hub/persist.ts
16601
- import { join as join18 } from "path";
16660
+ import { join as join19 } from "path";
16602
16661
  function discussionToMessages(state2) {
16603
16662
  const out = [];
16604
16663
  const t0 = state2.messages[0]?.timestamp ?? /* @__PURE__ */ new Date();
@@ -16636,7 +16695,7 @@ async function persistDiscussion(state2, config, defaultProvider, defaultModel)
16636
16695
  session.title = `[Hub] ${state2.topic.slice(0, 48)}`.replace(/\n/g, " ");
16637
16696
  session.titleAiGenerated = true;
16638
16697
  await sm.save();
16639
- return { id: session.id, path: join18(config.getHistoryDir(), `${session.id}.json`) };
16698
+ return { id: session.id, path: join19(config.getHistoryDir(), `${session.id}.json`) };
16640
16699
  }
16641
16700
 
16642
16701
  // src/core/think-command.ts
@@ -17097,8 +17156,8 @@ function costSourceNote(source2) {
17097
17156
  }
17098
17157
 
17099
17158
  // src/web/commands/_shared.ts
17100
- import { existsSync as existsSync27, readFileSync as readFileSync19, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync13, statSync as statSync14, createWriteStream } from "fs";
17101
- import { join as join21, resolve as resolve9, dirname as dirname9 } from "path";
17159
+ import { existsSync as existsSync28, readFileSync as readFileSync20, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync14, statSync as statSync14, createWriteStream } from "fs";
17160
+ import { join as join22, resolve as resolve9, dirname as dirname9 } from "path";
17102
17161
 
17103
17162
  // src/cli/review-prompts.ts
17104
17163
  function buildReviewPrompt(diff, gitContextStr, detailed) {
@@ -17170,47 +17229,47 @@ function readGitDiff(options = {}) {
17170
17229
  }
17171
17230
 
17172
17231
  // src/diagnostics/doctor-report.ts
17173
- import { existsSync as existsSync26, statSync as statSync13 } from "fs";
17174
- import { join as join20 } from "path";
17232
+ import { existsSync as existsSync27, statSync as statSync13 } from "fs";
17233
+ import { join as join21 } from "path";
17175
17234
  import { arch as arch2, platform as platform5, release as release2 } from "os";
17176
17235
 
17177
17236
  // src/diagnostics/crash-log.ts
17178
17237
  import {
17179
- existsSync as existsSync25,
17238
+ existsSync as existsSync26,
17180
17239
  mkdirSync as mkdirSync12,
17181
- readdirSync as readdirSync12,
17182
- readFileSync as readFileSync18,
17240
+ readdirSync as readdirSync13,
17241
+ readFileSync as readFileSync19,
17183
17242
  statSync as statSync12,
17184
17243
  unlinkSync as unlinkSync6,
17185
17244
  writeFileSync as writeFileSync2
17186
17245
  } from "fs";
17187
- import { join as join19 } from "path";
17246
+ import { join as join20 } from "path";
17188
17247
  import { homedir as homedir7, platform as platform4, release, arch } from "os";
17189
17248
  var LOGS_DIR_NAME = "logs";
17190
17249
  var CRASH_LOG_PREFIX = "crash-";
17191
17250
  function getLogsDir(configDir) {
17192
- const base = configDir ?? join19(homedir7(), CONFIG_DIR_NAME);
17193
- return join19(base, LOGS_DIR_NAME);
17251
+ const base = configDir ?? join20(homedir7(), CONFIG_DIR_NAME);
17252
+ return join20(base, LOGS_DIR_NAME);
17194
17253
  }
17195
17254
  function truncate(s, n) {
17196
17255
  return s.length <= n ? s : s.slice(0, n) + "\u2026";
17197
17256
  }
17198
17257
  function listRecentCrashes(limit = 10, configDir) {
17199
17258
  const dir = getLogsDir(configDir);
17200
- if (!existsSync25(dir)) return [];
17259
+ if (!existsSync26(dir)) return [];
17201
17260
  const files = [];
17202
17261
  let names;
17203
17262
  try {
17204
- names = readdirSync12(dir);
17263
+ names = readdirSync13(dir);
17205
17264
  } catch {
17206
17265
  return [];
17207
17266
  }
17208
17267
  for (const name of names) {
17209
17268
  if (!name.startsWith(CRASH_LOG_PREFIX) || !name.endsWith(".log")) continue;
17210
- const full = join19(dir, name);
17269
+ const full = join20(dir, name);
17211
17270
  try {
17212
17271
  const st = statSync12(full);
17213
- const head = readFileSync18(full, "utf-8").split("\n").slice(0, 20);
17272
+ const head = readFileSync19(full, "utf-8").split("\n").slice(0, 20);
17214
17273
  const tsLine = head.find((l) => l.startsWith("timestamp:"));
17215
17274
  const kindLine = head.find((l) => l.startsWith("kind:"));
17216
17275
  const msgIdx = head.findIndex((l) => l.trim() === "## message");
@@ -17229,18 +17288,18 @@ function listRecentCrashes(limit = 10, configDir) {
17229
17288
  return files.slice(0, limit);
17230
17289
  }
17231
17290
  function getConfigDirUsage(configDir) {
17232
- const base = configDir ?? join19(homedir7(), CONFIG_DIR_NAME);
17233
- if (!existsSync25(base)) return { totalBytes: 0, entries: [] };
17291
+ const base = configDir ?? join20(homedir7(), CONFIG_DIR_NAME);
17292
+ if (!existsSync26(base)) return { totalBytes: 0, entries: [] };
17234
17293
  const entries = [];
17235
17294
  let total = 0;
17236
17295
  let names;
17237
17296
  try {
17238
- names = readdirSync12(base);
17297
+ names = readdirSync13(base);
17239
17298
  } catch {
17240
17299
  return { totalBytes: 0, entries: [] };
17241
17300
  }
17242
17301
  for (const name of names) {
17243
- const full = join19(base, name);
17302
+ const full = join20(base, name);
17244
17303
  const bytes = dirSize(full);
17245
17304
  entries.push({ name, bytes });
17246
17305
  total += bytes;
@@ -17254,8 +17313,8 @@ function dirSize(path3) {
17254
17313
  if (st.isFile()) return st.size;
17255
17314
  if (!st.isDirectory()) return 0;
17256
17315
  let sum = 0;
17257
- for (const name of readdirSync12(path3)) {
17258
- sum += dirSize(join19(path3, name));
17316
+ for (const name of readdirSync13(path3)) {
17317
+ sum += dirSize(join20(path3, name));
17259
17318
  }
17260
17319
  return sum;
17261
17320
  } catch {
@@ -17265,7 +17324,7 @@ function dirSize(path3) {
17265
17324
 
17266
17325
  // src/diagnostics/doctor-report.ts
17267
17326
  function checkFile(label, path3) {
17268
- const exists = existsSync26(path3);
17327
+ const exists = existsSync27(path3);
17269
17328
  let sizeBytes = null;
17270
17329
  if (exists) {
17271
17330
  try {
@@ -17308,12 +17367,12 @@ function buildDoctorReport(options) {
17308
17367
  configDir,
17309
17368
  providers: options.providers.listAll().map((p) => ({ id: p.id, displayName: p.displayName, configured: p.configured })),
17310
17369
  files: [
17311
- checkFile("config.json", join20(configDir, "config.json")),
17312
- checkFile("memory.md", join20(configDir, MEMORY_FILE_NAME)),
17313
- checkFile("memory.jsonl", join20(configDir, "memory.jsonl")),
17314
- checkFile("dev-state.md", join20(configDir, DEV_STATE_FILE_NAME)),
17315
- checkFile("hooks-trust.json", join20(configDir, "hooks-trust.json")),
17316
- checkFile("plugin-state.json", join20(configDir, "plugins", "plugin-state.json"))
17370
+ checkFile("config.json", join21(configDir, "config.json")),
17371
+ checkFile("memory.md", join21(configDir, MEMORY_FILE_NAME)),
17372
+ checkFile("memory.jsonl", join21(configDir, "memory.jsonl")),
17373
+ checkFile("dev-state.md", join21(configDir, DEV_STATE_FILE_NAME)),
17374
+ checkFile("hooks-trust.json", join21(configDir, "hooks-trust.json")),
17375
+ checkFile("plugin-state.json", join21(configDir, "plugins", "plugin-state.json"))
17317
17376
  ],
17318
17377
  context: {
17319
17378
  enabled: contextSetting !== false,
@@ -17348,7 +17407,7 @@ function buildDoctorReport(options) {
17348
17407
  disabled: hooks.filter((h) => h.disabled).length
17349
17408
  },
17350
17409
  plugins: {
17351
- root: join20(configDir, "plugins"),
17410
+ root: join21(configDir, "plugins"),
17352
17411
  installed: plugins.length,
17353
17412
  active: activeAssets.plugins.length,
17354
17413
  invalid: plugins.filter((p) => !p.valid).length,
@@ -17363,7 +17422,7 @@ function buildDoctorReport(options) {
17363
17422
  mcp: {
17364
17423
  enabled: config.get("mcpEnabled"),
17365
17424
  configured: Object.keys(mcpServers).length,
17366
- projectConfigExists: existsSync26(join20(projectRoot, MCP_PROJECT_CONFIG_NAME)),
17425
+ projectConfigExists: existsSync27(join21(projectRoot, MCP_PROJECT_CONFIG_NAME)),
17367
17426
  statuses: options.mcpStatuses ?? []
17368
17427
  },
17369
17428
  recentCrashes: listRecentCrashes(5, configDir),
@@ -17885,7 +17944,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
17885
17944
  Cost: ${formatCost(cost)}` : "";
17886
17945
  let memoryLine = "";
17887
17946
  try {
17888
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-3XTSZ3QR.js");
17947
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-6JN7AWD6.js");
17889
17948
  const pending = countPendingMemories2(ctx.config.getConfigDir());
17890
17949
  if (pending > 0) memoryLine = `
17891
17950
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -18626,7 +18685,7 @@ async function handlePlugin(args, ctx) {
18626
18685
  lines.push("");
18627
18686
  }
18628
18687
  if (pluginTools.length > 0) {
18629
- const legacyDir = join21(configDir, PLUGINS_DIR_NAME);
18688
+ const legacyDir = join22(configDir, PLUGINS_DIR_NAME);
18630
18689
  lines.push(`**Legacy JS tools** (${pluginTools.length}):`);
18631
18690
  lines.push(`Dir: ${legacyDir}`);
18632
18691
  for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
@@ -18766,14 +18825,14 @@ ${note}` : head });
18766
18825
  }
18767
18826
  async function handleCommands(_args, ctx) {
18768
18827
  const configDir = ctx.config.getConfigDir();
18769
- const commandsDir = join21(configDir, CUSTOM_COMMANDS_DIR_NAME);
18770
- if (!existsSync27(commandsDir)) {
18828
+ const commandsDir = join22(configDir, CUSTOM_COMMANDS_DIR_NAME);
18829
+ if (!existsSync28(commandsDir)) {
18771
18830
  ctx.send({ type: "info", message: `No custom commands directory.
18772
18831
  Create: ${commandsDir}/ with .md files.` });
18773
18832
  return;
18774
18833
  }
18775
18834
  try {
18776
- const files = readdirSync13(commandsDir).filter((f) => f.endsWith(".md"));
18835
+ const files = readdirSync14(commandsDir).filter((f) => f.endsWith(".md"));
18777
18836
  if (files.length === 0) {
18778
18837
  ctx.send({ type: "info", message: `No custom commands found in ${commandsDir}
18779
18838
  Add .md files to create commands.` });
@@ -18873,7 +18932,7 @@ async function handleTest(args, ctx) {
18873
18932
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
18874
18933
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
18875
18934
  }
18876
- const runTests = ctx.runTests ?? (await import("./run-tests-WQE3XTUL.js")).executeTests;
18935
+ const runTests = ctx.runTests ?? (await import("./run-tests-BKFV3HUZ.js")).executeTests;
18877
18936
  const report = await runTests(testArgs);
18878
18937
  ctx.send({ type: "info", message: report });
18879
18938
  } catch (err) {
@@ -18897,9 +18956,9 @@ async function handleDiff(args, ctx) {
18897
18956
  let modifiedFiles = 0;
18898
18957
  const diffLines2 = [];
18899
18958
  for (const [filePath, { earliest }] of fileMap) {
18900
- const currentContent = existsSync27(filePath) ? (() => {
18959
+ const currentContent = existsSync28(filePath) ? (() => {
18901
18960
  try {
18902
- return readFileSync19(filePath, "utf-8");
18961
+ return readFileSync20(filePath, "utf-8");
18903
18962
  } catch {
18904
18963
  return null;
18905
18964
  }
@@ -18934,9 +18993,9 @@ async function handleDiff(args, ctx) {
18934
18993
  }
18935
18994
  async function handleInit(args, ctx) {
18936
18995
  const cwd = process.cwd();
18937
- const targetPath = join21(cwd, "AICLI.md");
18996
+ const targetPath = join22(cwd, "AICLI.md");
18938
18997
  const force = args.includes("--force");
18939
- if (existsSync27(targetPath) && !force) {
18998
+ if (existsSync28(targetPath) && !force) {
18940
18999
  ctx.send({ type: "info", message: `AICLI.md already exists at ${targetPath}
18941
19000
  Use /init --force to overwrite.` });
18942
19001
  return;
@@ -19264,7 +19323,7 @@ async function handleMemory(args, ctx) {
19264
19323
  }
19265
19324
  if (intent.kind === "status") {
19266
19325
  const { getChatIndexStatus: getChatIndexStatus2 } = await import("./chat-index-RLVLQRRC.js");
19267
- const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-3XTSZ3QR.js");
19326
+ const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-6JN7AWD6.js");
19268
19327
  const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
19269
19328
  const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
19270
19329
  const view = buildMemoryStatusView({
@@ -19287,7 +19346,7 @@ async function handleMemory(args, ctx) {
19287
19346
  return;
19288
19347
  }
19289
19348
  if (intent.kind === "recall") {
19290
- const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-3XTSZ3QR.js");
19349
+ const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-6JN7AWD6.js");
19291
19350
  const { searchChatMemory: searchChatMemory2 } = await import("./chat-index-RLVLQRRC.js");
19292
19351
  const persistentHits = searchPersistentMemories2(configDir, intent.query, process.cwd(), 3);
19293
19352
  if (persistentHits.length > 0) {
@@ -19408,7 +19467,7 @@ async function handleMemory(args, ctx) {
19408
19467
  ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
19409
19468
  } else if (intent.kind === "export") {
19410
19469
  if (args[1] === "md") {
19411
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-3XTSZ3QR.js");
19470
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-6JN7AWD6.js");
19412
19471
  ctx.send({
19413
19472
  type: "export_data",
19414
19473
  format: "md",
@@ -19446,7 +19505,7 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
19446
19505
  return;
19447
19506
  }
19448
19507
  const dirPath = resolve9(sub);
19449
- if (!existsSync27(dirPath)) {
19508
+ if (!existsSync28(dirPath)) {
19450
19509
  ctx.send({ type: "error", message: `Directory not found: ${dirPath}` });
19451
19510
  return;
19452
19511
  }
@@ -20411,16 +20470,16 @@ No tools match "${filter}".
20411
20470
  usage: "/mcp [reconnect [serverId] | trust-project]",
20412
20471
  async execute(args, ctx) {
20413
20472
  if (args[0] === "trust-project") {
20414
- const { join: join26 } = await import("path");
20415
- const { existsSync: existsSync32 } = await import("fs");
20473
+ const { join: join27 } = await import("path");
20474
+ const { existsSync: existsSync33 } = await import("fs");
20416
20475
  const { getGitRoot: getGitRoot2 } = await import("./git-context-VNCA2GU7.js");
20417
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-J5SJ232X.js");
20476
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-C55HE2E5.js");
20418
20477
  const { approveProject, hashMcpFile } = await import("./project-trust-6CJB5ZMX.js");
20419
20478
  const cwd = process.cwd();
20420
20479
  const projectRoot = getGitRoot2(cwd) ?? cwd;
20421
- const mcpPath = join26(projectRoot, MCP_PROJECT_CONFIG_NAME2);
20480
+ const mcpPath = join27(projectRoot, MCP_PROJECT_CONFIG_NAME2);
20422
20481
  console.log();
20423
- if (!existsSync32(mcpPath)) {
20482
+ if (!existsSync33(mcpPath)) {
20424
20483
  console.log(theme.dim(` No .mcp.json in ${projectRoot}.`));
20425
20484
  console.log();
20426
20485
  return;
@@ -20855,12 +20914,12 @@ ${outcome.summary}
20855
20914
  if (scanAll) {
20856
20915
  const metas = ctx.sessions.listSessions();
20857
20916
  console.log(theme.info(` Scanning ${metas.length} session(s)\u2026`));
20858
- const { readFileSync: readFileSync23 } = await import("fs");
20859
- const { join: join26 } = await import("path");
20917
+ const { readFileSync: readFileSync24 } = await import("fs");
20918
+ const { join: join27 } = await import("path");
20860
20919
  const historyDir = ctx.config.getHistoryDir();
20861
20920
  for (const m of metas) {
20862
20921
  try {
20863
- const content = readFileSync23(join26(historyDir, `${m.id}.json`), "utf-8");
20922
+ const content = readFileSync24(join27(historyDir, `${m.id}.json`), "utf-8");
20864
20923
  const hits2 = scanString(content, opts);
20865
20924
  if (hits2.length) {
20866
20925
  filesWithHits++;
@@ -20907,8 +20966,8 @@ ${outcome.summary}
20907
20966
  }
20908
20967
 
20909
20968
  // src/repl/commands/review-commands.ts
20910
- import { existsSync as existsSync28, readFileSync as readFileSync20, writeFileSync as writeFileSync4 } from "fs";
20911
- import { join as join22 } from "path";
20969
+ import { existsSync as existsSync29, readFileSync as readFileSync21, writeFileSync as writeFileSync4 } from "fs";
20970
+ import { join as join23 } from "path";
20912
20971
  function createReviewCommands() {
20913
20972
  return [
20914
20973
  {
@@ -21267,9 +21326,9 @@ function createReviewCommands() {
21267
21326
  usage: "/init [--force]",
21268
21327
  async execute(args, ctx) {
21269
21328
  const cwd = process.cwd();
21270
- const targetPath = join22(cwd, "AICLI.md");
21329
+ const targetPath = join23(cwd, "AICLI.md");
21271
21330
  const force = args.includes("--force");
21272
- if (existsSync28(targetPath) && !force) {
21331
+ if (existsSync29(targetPath) && !force) {
21273
21332
  ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
21274
21333
  ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
21275
21334
  return;
@@ -21333,7 +21392,7 @@ function createReviewCommands() {
21333
21392
  usage: "/test [command|filter]",
21334
21393
  async execute(args, ctx) {
21335
21394
  try {
21336
- const { executeTests } = await import("./run-tests-WQE3XTUL.js");
21395
+ const { executeTests } = await import("./run-tests-BKFV3HUZ.js");
21337
21396
  const argStr = args.join(" ").trim();
21338
21397
  let testArgs = {};
21339
21398
  if (argStr) {
@@ -21368,9 +21427,9 @@ function createReviewCommands() {
21368
21427
  let newFiles = 0;
21369
21428
  let modifiedFiles = 0;
21370
21429
  for (const [filePath, { earliest }] of fileMap) {
21371
- const currentContent = existsSync28(filePath) ? (() => {
21430
+ const currentContent = existsSync29(filePath) ? (() => {
21372
21431
  try {
21373
- return readFileSync20(filePath, "utf-8");
21432
+ return readFileSync21(filePath, "utf-8");
21374
21433
  } catch {
21375
21434
  return null;
21376
21435
  }
@@ -22532,17 +22591,17 @@ function createSessionCommands() {
22532
22591
  }
22533
22592
 
22534
22593
  // src/repl/commands/misc-commands.ts
22535
- import { basename as basename10 } from "path";
22594
+ import { basename as basename11 } from "path";
22536
22595
  import { platform as platform8 } from "os";
22537
22596
 
22538
22597
  // src/repl/clipboard.ts
22539
22598
  import { execSync as execSync3 } from "child_process";
22540
- import { existsSync as existsSync29, statSync as statSync15, unlinkSync as unlinkSync7 } from "fs";
22599
+ import { existsSync as existsSync30, statSync as statSync15, unlinkSync as unlinkSync7 } from "fs";
22541
22600
  import { tmpdir as tmpdir3 } from "os";
22542
- import { join as join23 } from "path";
22601
+ import { join as join24 } from "path";
22543
22602
  var CLIPBOARD_TIMEOUT = 5e3;
22544
22603
  function readClipboardImage() {
22545
- const outPath = join23(tmpdir3(), `aicli-paste-${Date.now()}.png`);
22604
+ const outPath = join24(tmpdir3(), `aicli-paste-${Date.now()}.png`);
22546
22605
  try {
22547
22606
  if (process.platform === "win32") {
22548
22607
  _readWin32(outPath);
@@ -22555,7 +22614,7 @@ function readClipboardImage() {
22555
22614
  _cleanup(outPath);
22556
22615
  return null;
22557
22616
  }
22558
- if (!existsSync29(outPath) || statSync15(outPath).size === 0) {
22617
+ if (!existsSync30(outPath) || statSync15(outPath).size === 0) {
22559
22618
  _cleanup(outPath);
22560
22619
  return null;
22561
22620
  }
@@ -22608,7 +22667,7 @@ function _readLinux(outPath) {
22608
22667
  }
22609
22668
  function _cleanup(path3) {
22610
22669
  try {
22611
- if (existsSync29(path3)) unlinkSync7(path3);
22670
+ if (existsSync30(path3)) unlinkSync7(path3);
22612
22671
  } catch {
22613
22672
  }
22614
22673
  }
@@ -22878,7 +22937,7 @@ ${hint}` : "")
22878
22937
  return;
22879
22938
  }
22880
22939
  const description = args.join(" ").trim() || "Please describe this image";
22881
- ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename10(imgPath)}`);
22940
+ ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename11(imgPath)}`);
22882
22941
  await ctx.sendAsChat(`@${imgPath} ${description}`);
22883
22942
  }
22884
22943
  },
@@ -23434,6 +23493,11 @@ var SessionHandler = class _SessionHandler {
23434
23493
  costCnyPerUsd: CNY_PER_USD,
23435
23494
  costPricingUnknown,
23436
23495
  providers: providerList,
23496
+ hubPresets: loadCustomPresets(this.config.getConfigDir()).presets.map((p) => ({
23497
+ id: p.id,
23498
+ name: p.name,
23499
+ description: p.description
23500
+ })),
23437
23501
  branches,
23438
23502
  activeBranchId: sess?.activeBranchId ?? "main",
23439
23503
  agents: listAgentRuns().slice(0, 20).map((run) => ({
@@ -23687,7 +23751,8 @@ var SessionHandler = class _SessionHandler {
23687
23751
  this.send({ type: "error", message: "Hub topic is required." });
23688
23752
  return;
23689
23753
  }
23690
- const preset = getPreset(msg.preset ?? "brainstorm");
23754
+ const presetId = msg.preset ?? "brainstorm";
23755
+ const preset = presetId.startsWith(CUSTOM_PRESET_PREFIX) ? loadCustomPresets(this.config.getConfigDir()).presets.find((p) => p.id === presetId) : getPreset(presetId);
23691
23756
  if (!preset) {
23692
23757
  this.send({ type: "error", message: `Unknown preset "${msg.preset}".` });
23693
23758
  return;
@@ -24890,8 +24955,8 @@ async function setupProxy(configProxy) {
24890
24955
  }
24891
24956
 
24892
24957
  // src/web/auth.ts
24893
- import { existsSync as existsSync30, readFileSync as readFileSync21, mkdirSync as mkdirSync16, readdirSync as readdirSync14, openSync, closeSync, unlinkSync as unlinkSync8 } from "fs";
24894
- import { isAbsolute as isAbsolute3, join as join24, relative as relative5 } from "path";
24958
+ import { existsSync as existsSync31, readFileSync as readFileSync22, mkdirSync as mkdirSync16, readdirSync as readdirSync15, openSync, closeSync, unlinkSync as unlinkSync8 } from "fs";
24959
+ import { isAbsolute as isAbsolute3, join as join25, relative as relative5 } from "path";
24895
24960
  import { createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2, pbkdf2Sync, pbkdf2 } from "crypto";
24896
24961
  var USERS_FILE = "users.json";
24897
24962
  var TOKEN_EXPIRY_HOURS = 24;
@@ -24907,7 +24972,7 @@ var AuthManager = class {
24907
24972
  loadedRaw;
24908
24973
  constructor(baseDir) {
24909
24974
  this.baseDir = baseDir;
24910
- this.usersFile = join24(baseDir, USERS_FILE);
24975
+ this.usersFile = join25(baseDir, USERS_FILE);
24911
24976
  this.db = this.loadOrCreate();
24912
24977
  }
24913
24978
  // ── Public API ─────────────────────────────────────────────────
@@ -24949,10 +25014,10 @@ var AuthManager = class {
24949
25014
  }
24950
25015
  const salt = prepared?.salt ?? randomBytes2(16).toString("hex");
24951
25016
  const passwordHash = prepared?.hash ?? this.hashPassword(password, salt);
24952
- const dataDir = join24(USERS_DIR, username);
24953
- const fullDataDir = join24(this.baseDir, dataDir);
25017
+ const dataDir = join25(USERS_DIR, username);
25018
+ const fullDataDir = join25(this.baseDir, dataDir);
24954
25019
  mkdirSync16(fullDataDir, { recursive: true, mode: 448 });
24955
- mkdirSync16(join24(fullDataDir, "history"), { recursive: true, mode: 448 });
25020
+ mkdirSync16(join25(fullDataDir, "history"), { recursive: true, mode: 448 });
24956
25021
  const user = {
24957
25022
  username,
24958
25023
  passwordHash,
@@ -25112,7 +25177,7 @@ var AuthManager = class {
25112
25177
  this.refresh();
25113
25178
  const user = this.db.users.find((u) => u.username === username);
25114
25179
  if (!user) throw new Error(`User not found: ${username}`);
25115
- return join24(this.baseDir, user.dataDir);
25180
+ return join25(this.baseDir, user.dataDir);
25116
25181
  }
25117
25182
  /** List all usernames */
25118
25183
  listUsers() {
@@ -25151,30 +25216,30 @@ var AuthManager = class {
25151
25216
  const err = this.register(username, password);
25152
25217
  if (err) return err;
25153
25218
  const userDir = this.getUserDataDir(username);
25154
- const globalConfig = join24(this.baseDir, "config.json");
25155
- if (existsSync30(globalConfig)) {
25219
+ const globalConfig = join25(this.baseDir, "config.json");
25220
+ if (existsSync31(globalConfig)) {
25156
25221
  try {
25157
- const content = readFileSync21(globalConfig, "utf-8");
25158
- atomicWriteFileSync(join24(userDir, "config.json"), content, { mode: 384 });
25222
+ const content = readFileSync22(globalConfig, "utf-8");
25223
+ atomicWriteFileSync(join25(userDir, "config.json"), content, { mode: 384 });
25159
25224
  } catch {
25160
25225
  }
25161
25226
  }
25162
- const globalMemory = join24(this.baseDir, "memory.md");
25163
- if (existsSync30(globalMemory)) {
25227
+ const globalMemory = join25(this.baseDir, "memory.md");
25228
+ if (existsSync31(globalMemory)) {
25164
25229
  try {
25165
- const content = readFileSync21(globalMemory, "utf-8");
25166
- atomicWriteFileSync(join24(userDir, "memory.md"), content, { mode: 384 });
25230
+ const content = readFileSync22(globalMemory, "utf-8");
25231
+ atomicWriteFileSync(join25(userDir, "memory.md"), content, { mode: 384 });
25167
25232
  } catch {
25168
25233
  }
25169
25234
  }
25170
- const globalHistory = join24(this.baseDir, "history");
25171
- if (existsSync30(globalHistory)) {
25235
+ const globalHistory = join25(this.baseDir, "history");
25236
+ if (existsSync31(globalHistory)) {
25172
25237
  try {
25173
- const files = readdirSync14(globalHistory).filter((f) => f.endsWith(".json"));
25174
- const userHistory = join24(userDir, "history");
25238
+ const files = readdirSync15(globalHistory).filter((f) => f.endsWith(".json"));
25239
+ const userHistory = join25(userDir, "history");
25175
25240
  for (const f of files) {
25176
25241
  try {
25177
- atomicWriteFileSync(join24(userHistory, f), readFileSync21(join24(globalHistory, f), "utf8"), { mode: 384 });
25242
+ atomicWriteFileSync(join25(userHistory, f), readFileSync22(join25(globalHistory, f), "utf8"), { mode: 384 });
25178
25243
  } catch {
25179
25244
  }
25180
25245
  }
@@ -25185,16 +25250,16 @@ var AuthManager = class {
25185
25250
  }
25186
25251
  // ── Private methods ────────────────────────────────────────────
25187
25252
  refresh() {
25188
- const raw = readFileSync21(this.usersFile, "utf8");
25253
+ const raw = readFileSync22(this.usersFile, "utf8");
25189
25254
  const parsed = JSON.parse(raw);
25190
25255
  if (!this.isValidUsersDB(parsed)) throw new Error("Authentication database is invalid; access refused");
25191
25256
  this.db = parsed;
25192
25257
  this.loadedRaw = raw;
25193
25258
  }
25194
25259
  loadOrCreate() {
25195
- if (existsSync30(this.usersFile)) {
25260
+ if (existsSync31(this.usersFile)) {
25196
25261
  try {
25197
- const raw = readFileSync21(this.usersFile, "utf-8");
25262
+ const raw = readFileSync22(this.usersFile, "utf-8");
25198
25263
  const parsed = JSON.parse(raw);
25199
25264
  if (!this.isValidUsersDB(parsed)) {
25200
25265
  throw new Error("database structure is invalid");
@@ -25230,7 +25295,7 @@ var AuthManager = class {
25230
25295
  if (typeof record.username !== "string" || !/^[a-z0-9_-]{2,32}$/.test(record.username) || usernames.has(record.username) || typeof record.passwordHash !== "string" || record.passwordHash.length === 0 || typeof record.salt !== "string" || record.salt.length === 0 || typeof record.createdAt !== "string" || typeof record.dataDir !== "string" || record.dataDir.length === 0 || isAbsolute3(record.dataDir)) {
25231
25296
  return false;
25232
25297
  }
25233
- const dataDirFromBase = relative5(this.baseDir, join24(this.baseDir, record.dataDir));
25298
+ const dataDirFromBase = relative5(this.baseDir, join25(this.baseDir, record.dataDir));
25234
25299
  if (dataDirFromBase.startsWith("..") || isAbsolute3(dataDirFromBase)) return false;
25235
25300
  if (record.hashVersion !== void 0 && record.hashVersion !== 1 && record.hashVersion !== 2) return false;
25236
25301
  if (record.tokensRevokedBefore !== void 0 && !Number.isFinite(record.tokensRevokedBefore)) return false;
@@ -25246,7 +25311,7 @@ var AuthManager = class {
25246
25311
  const lock = this.usersFile + ".lock";
25247
25312
  const fd = openSync(lock, "wx", 384);
25248
25313
  try {
25249
- const current = existsSync30(this.usersFile) ? readFileSync21(this.usersFile, "utf8") : void 0;
25314
+ const current = existsSync31(this.usersFile) ? readFileSync22(this.usersFile, "utf8") : void 0;
25250
25315
  if (current !== this.loadedRaw) throw new Error("Authentication database changed concurrently; retry the operation");
25251
25316
  const raw = JSON.stringify(db, null, 2);
25252
25317
  atomicWriteFileSync(this.usersFile, raw, { mode: 384 });
@@ -25380,8 +25445,8 @@ async function startWebServer(options = {}) {
25380
25445
  }
25381
25446
  }
25382
25447
  let skillManager = null;
25383
- const skillsDir = join25(config.getConfigDir(), SKILLS_DIR_NAME);
25384
- if (existsSync31(skillsDir)) {
25448
+ const skillsDir = join26(config.getConfigDir(), SKILLS_DIR_NAME);
25449
+ if (existsSync32(skillsDir)) {
25385
25450
  skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
25386
25451
  skillManager.loadSkills(pluginAssets.skillDirs);
25387
25452
  const count = skillManager.listSkills().length;
@@ -25474,15 +25539,15 @@ async function startWebServer(options = {}) {
25474
25539
  next();
25475
25540
  };
25476
25541
  const moduleDir = getModuleDir();
25477
- let clientDir = join25(moduleDir, "web", "client");
25478
- if (!existsSync31(clientDir)) {
25479
- clientDir = join25(moduleDir, "client");
25542
+ let clientDir = join26(moduleDir, "web", "client");
25543
+ if (!existsSync32(clientDir)) {
25544
+ clientDir = join26(moduleDir, "client");
25480
25545
  }
25481
- if (!existsSync31(clientDir)) {
25482
- clientDir = join25(moduleDir, "..", "..", "src", "web", "client");
25546
+ if (!existsSync32(clientDir)) {
25547
+ clientDir = join26(moduleDir, "..", "..", "src", "web", "client");
25483
25548
  }
25484
- if (!existsSync31(clientDir)) {
25485
- clientDir = join25(process.cwd(), "src", "web", "client");
25549
+ if (!existsSync32(clientDir)) {
25550
+ clientDir = join26(process.cwd(), "src", "web", "client");
25486
25551
  }
25487
25552
  console.log(` Static files: ${clientDir}`);
25488
25553
  const PRECOMPRESSED_TYPES = {
@@ -25502,14 +25567,14 @@ async function startWebServer(options = {}) {
25502
25567
  const encoding = /\bbr\b/.test(accept) ? "br" : /\bgzip\b/.test(accept) ? "gzip" : null;
25503
25568
  if (!encoding) return next();
25504
25569
  const target = resolvePath(clientDir, `.${req.path}`) + (encoding === "br" ? ".br" : ".gz");
25505
- if (!target.startsWith(clientDir) || !existsSync31(target)) return next();
25570
+ if (!target.startsWith(clientDir) || !existsSync32(target)) return next();
25506
25571
  res.setHeader("Content-Type", contentType);
25507
25572
  res.setHeader("Content-Encoding", encoding);
25508
25573
  res.setHeader("Vary", "Accept-Encoding");
25509
25574
  if (req.path.startsWith("/vendor/")) res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
25510
25575
  createReadStream(target).pipe(res);
25511
25576
  });
25512
- app.use("/vendor", express.static(join25(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
25577
+ app.use("/vendor", express.static(join26(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
25513
25578
  app.use(express.static(clientDir));
25514
25579
  app.get("/api/status", (_req, res) => {
25515
25580
  res.json({
@@ -25600,7 +25665,7 @@ async function startWebServer(options = {}) {
25600
25665
  app.get("/api/files", requireAuth, (req, res) => {
25601
25666
  const cwd = process.cwd();
25602
25667
  const prefix = req.query.prefix || "";
25603
- const targetDir = join25(cwd, prefix);
25668
+ const targetDir = join26(cwd, prefix);
25604
25669
  try {
25605
25670
  const canonicalTarget = realpathSync3(resolve12(targetDir));
25606
25671
  const canonicalCwd = realpathSync3(resolve12(cwd));
@@ -25614,10 +25679,10 @@ async function startWebServer(options = {}) {
25614
25679
  }
25615
25680
  try {
25616
25681
  const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", "__pycache__", ".next", ".nuxt", "coverage", ".cache"]);
25617
- const entries = readdirSync15(targetDir, { withFileTypes: true });
25682
+ const entries = readdirSync16(targetDir, { withFileTypes: true });
25618
25683
  const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
25619
25684
  name: e.name,
25620
- path: relative6(cwd, join25(targetDir, e.name)).replace(/\\/g, "/"),
25685
+ path: relative6(cwd, join26(targetDir, e.name)).replace(/\\/g, "/"),
25621
25686
  isDir: e.isDirectory()
25622
25687
  }));
25623
25688
  res.json({ files });
@@ -25657,8 +25722,8 @@ async function startWebServer(options = {}) {
25657
25722
  try {
25658
25723
  const authUser = req._authUser;
25659
25724
  const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
25660
- const filePath = join25(histDir, `${id}.json`);
25661
- if (!existsSync31(filePath)) {
25725
+ const filePath = join26(histDir, `${id}.json`);
25726
+ if (!existsSync32(filePath)) {
25662
25727
  res.status(404).json({ error: "Session not found" });
25663
25728
  return;
25664
25729
  }
@@ -25673,7 +25738,7 @@ async function startWebServer(options = {}) {
25673
25738
  res.status(404).json({ error: "Session not found" });
25674
25739
  return;
25675
25740
  }
25676
- const data = JSON.parse(readFileSync22(filePath, "utf-8"));
25741
+ const data = JSON.parse(readFileSync23(filePath, "utf-8"));
25677
25742
  res.json({ session: data });
25678
25743
  } catch (err) {
25679
25744
  res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
@@ -25686,7 +25751,7 @@ async function startWebServer(options = {}) {
25686
25751
  return;
25687
25752
  }
25688
25753
  const cwd = process.cwd();
25689
- const fullPath = resolve12(join25(cwd, filePath));
25754
+ const fullPath = resolve12(join26(cwd, filePath));
25690
25755
  try {
25691
25756
  const canonicalFull = realpathSync3(fullPath);
25692
25757
  assertReadablePath(canonicalFull);
@@ -25705,7 +25770,7 @@ async function startWebServer(options = {}) {
25705
25770
  res.json({ error: `File too large (${(stat.size / 1024).toFixed(0)} KB, max 512 KB)` });
25706
25771
  return;
25707
25772
  }
25708
- const content = readFileSync22(fullPath, "utf-8");
25773
+ const content = readFileSync23(fullPath, "utf-8");
25709
25774
  res.json({ content, size: stat.size });
25710
25775
  } catch {
25711
25776
  res.json({ error: "Cannot read file" });
@@ -26042,17 +26107,17 @@ function resolveProjectMcpPath() {
26042
26107
  const cwd = process.cwd();
26043
26108
  const gitRoot = getGitRoot(cwd);
26044
26109
  const projectRoot = gitRoot ?? cwd;
26045
- const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
26046
- return existsSync31(configPath) ? configPath : null;
26110
+ const configPath = join26(projectRoot, MCP_PROJECT_CONFIG_NAME);
26111
+ return existsSync32(configPath) ? configPath : null;
26047
26112
  }
26048
26113
  function loadProjectMcpConfig() {
26049
26114
  const cwd = process.cwd();
26050
26115
  const gitRoot = getGitRoot(cwd);
26051
26116
  const projectRoot = gitRoot ?? cwd;
26052
- const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
26053
- if (!existsSync31(configPath)) return null;
26117
+ const configPath = join26(projectRoot, MCP_PROJECT_CONFIG_NAME);
26118
+ if (!existsSync32(configPath)) return null;
26054
26119
  try {
26055
- const raw = JSON.parse(readFileSync22(configPath, "utf-8"));
26120
+ const raw = JSON.parse(readFileSync23(configPath, "utf-8"));
26056
26121
  return raw.mcpServers ?? raw;
26057
26122
  } catch {
26058
26123
  return null;