jinzd-ai-cli 0.4.267 → 0.4.269

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 (31) hide show
  1. package/dist/{batch-GY5MAN5F.js → batch-HUOYPVJQ.js} +2 -2
  2. package/dist/{chunk-THHPKZJ3.js → chunk-3TOMHXDW.js} +1 -1
  3. package/dist/{chunk-7HECI3U5.js → chunk-4HTJMLFY.js} +3 -1
  4. package/dist/{chunk-EWRZMIQE.js → chunk-5IUFUCIT.js} +1 -1
  5. package/dist/{chunk-WPN7LDLM.js → chunk-5PRWBJCI.js} +1 -1
  6. package/dist/{chunk-QN7WD2SM.js → chunk-6PROC2JO.js} +3 -3
  7. package/dist/{chunk-6C6FLDGH.js → chunk-AAERHPBN.js} +1 -1
  8. package/dist/{chunk-5AEOIETL.js → chunk-DJNGUPM3.js} +4 -4
  9. package/dist/{chunk-FI6IWUXW.js → chunk-KIHNZBEA.js} +1 -1
  10. package/dist/{chunk-ARYCWJN6.js → chunk-NVN3FHXI.js} +1 -1
  11. package/dist/{chunk-RVNL7MQG.js → chunk-QPPUYCRF.js} +1 -1
  12. package/dist/{chunk-JH343BDI.js → chunk-S3F5LOV3.js} +313 -2
  13. package/dist/{chunk-XLLUQEGO.js → chunk-V6KQ67VF.js} +1 -1
  14. package/dist/{chunk-5CU72V6P.js → chunk-XJAGGJVU.js} +3 -3
  15. package/dist/{ci-MUEQSNKU.js → ci-4QS2J7BG.js} +4 -4
  16. package/dist/{ci-format-2ZGGSOFK.js → ci-format-6L6M67WC.js} +2 -2
  17. package/dist/{constants-SZTJESDF.js → constants-IO5VJLEE.js} +1 -1
  18. package/dist/{doctor-cli-Z272364P.js → doctor-cli-ZU4E2DDL.js} +4 -4
  19. package/dist/electron-server.js +455 -58
  20. package/dist/{hub-MRLGKMRI.js → hub-AMDWXSKZ.js} +1 -1
  21. package/dist/index.js +117 -245
  22. package/dist/{persistent-memory-3FTOC7QT.js → persistent-memory-52SE5K44.js} +2 -2
  23. package/dist/{persistent-memory-HZASMDJQ.js → persistent-memory-H4DNDIOQ.js} +2 -2
  24. package/dist/{pr-VLLIALRK.js → pr-Z4O5H6I3.js} +4 -4
  25. package/dist/{run-tests-NTDZ6DDU.js → run-tests-FZSYHWYX.js} +2 -2
  26. package/dist/{run-tests-6MWE6D5S.js → run-tests-PYKKYMPA.js} +2 -2
  27. package/dist/{server-IALCWKSU.js → server-WTJSM2MT.js} +147 -41
  28. package/dist/{server-SP3AEHRQ.js → server-ZSTVYSYC.js} +5 -5
  29. package/dist/{task-orchestrator-Q6WFFI4J.js → task-orchestrator-PNLI3V36.js} +5 -5
  30. package/dist/{usage-DJDLHICZ.js → usage-GVFUVYUG.js} +2 -2
  31. package/package.json +1 -1
@@ -158,7 +158,7 @@ ${content}`);
158
158
  }
159
159
  }
160
160
  async function runTaskMode(config, providers, configManager, topic) {
161
- const { TaskOrchestrator } = await import("./task-orchestrator-Q6WFFI4J.js");
161
+ const { TaskOrchestrator } = await import("./task-orchestrator-PNLI3V36.js");
162
162
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
163
163
  let interrupted = false;
164
164
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -1,23 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ AUTO_COMPACT_INSTRUCTION,
3
4
  McpManager,
4
5
  SNAPSHOT_PROMPT,
5
6
  SkillManager,
7
+ applyProfileCommand,
6
8
  applyThinkCommand,
7
9
  autoTrimSessionIfNeeded,
8
10
  buildInitPrompt,
9
11
  buildSessionCostReport,
10
12
  clearDevState,
11
13
  costSourceNote,
14
+ decideModel,
15
+ estimateConversationTokens,
16
+ evaluateContextPressure,
17
+ filterMemoryEntries,
12
18
  loadDevState,
19
+ parseMemoryShowFilters,
13
20
  parseSimpleYaml,
14
21
  persistToolRound,
15
22
  readGitDiff,
16
23
  saveDevState,
17
24
  scanProject,
18
25
  sessionHasMeaningfulContent,
19
- setupProxy
20
- } from "./chunk-JH343BDI.js";
26
+ setupProxy,
27
+ stripRoutingTags
28
+ } from "./chunk-S3F5LOV3.js";
21
29
  import {
22
30
  CostTracker,
23
31
  computeCost,
@@ -55,7 +63,7 @@ import {
55
63
  setMaxOutputCap,
56
64
  spawnAgentContext,
57
65
  undoStack
58
- } from "./chunk-5AEOIETL.js";
66
+ } from "./chunk-DJNGUPM3.js";
59
67
  import {
60
68
  addMemoryEntry,
61
69
  backupMemoryStore,
@@ -68,7 +76,6 @@ import {
68
76
  findSimilarMemory,
69
77
  formatMemoryForPrompt,
70
78
  isMemoryExpired,
71
- isMemoryStale,
72
79
  listMemoryEntries,
73
80
  listOrphanedProjectMemories,
74
81
  loadMemoryEntries,
@@ -81,7 +88,7 @@ import {
81
88
  touchMemoryReferences,
82
89
  updateMemoryApproval,
83
90
  updateMemoryEntry
84
- } from "./chunk-RVNL7MQG.js";
91
+ } from "./chunk-QPPUYCRF.js";
85
92
  import "./chunk-GLSR2NR3.js";
86
93
  import "./chunk-UUSRWSSX.js";
87
94
  import "./chunk-CKH4KQ4E.js";
@@ -99,14 +106,14 @@ import {
99
106
  formatDoctorReport,
100
107
  loadContextFiles,
101
108
  writeCrashLog
102
- } from "./chunk-QN7WD2SM.js";
109
+ } from "./chunk-6PROC2JO.js";
103
110
  import {
104
111
  ProviderRegistry,
105
112
  listBuiltInProviderMetadata
106
113
  } from "./chunk-AUEX6RNY.js";
107
114
  import {
108
115
  ConfigManager
109
- } from "./chunk-EWRZMIQE.js";
116
+ } from "./chunk-5IUFUCIT.js";
110
117
  import {
111
118
  describePlugin,
112
119
  getActivePluginAssets,
@@ -123,7 +130,7 @@ import {
123
130
  trustHook,
124
131
  trustPlugin,
125
132
  untrustHook
126
- } from "./chunk-WPN7LDLM.js";
133
+ } from "./chunk-5PRWBJCI.js";
127
134
  import {
128
135
  CONTENT_ONLY_STREAM_REMINDER,
129
136
  TEE_FINAL_USER_NUDGE,
@@ -157,13 +164,12 @@ import {
157
164
  import {
158
165
  fileCheckpoints
159
166
  } from "./chunk-4BKXL7SM.js";
160
- import "./chunk-XLLUQEGO.js";
167
+ import "./chunk-V6KQ67VF.js";
161
168
  import {
162
169
  AGENTIC_BEHAVIOR_GUIDELINE,
163
170
  AUTHOR,
164
171
  AUTHOR_EMAIL,
165
172
  CONFIG_DIR_NAME,
166
- CONTEXT_PRESSURE_THRESHOLD,
167
173
  CUSTOM_COMMANDS_DIR_NAME,
168
174
  DEFAULT_MAX_TOKENS,
169
175
  DEFAULT_MAX_TOOL_ROUNDS,
@@ -176,7 +182,7 @@ import {
176
182
  SKILLS_DIR_NAME,
177
183
  VERSION,
178
184
  buildUserIdentityPrompt
179
- } from "./chunk-THHPKZJ3.js";
185
+ } from "./chunk-3TOMHXDW.js";
180
186
  import {
181
187
  buildChatIndex,
182
188
  clearChatIndex,
@@ -1259,9 +1265,9 @@ function createToolingCommands() {
1259
1265
  builtin.push({ name, description: t.definition.description });
1260
1266
  }
1261
1267
  }
1262
- const matches2 = (row) => !filter || row.name.toLowerCase().includes(filter) || row.description.toLowerCase().includes(filter);
1263
- const builtinShown = builtin.filter(matches2);
1264
- const serverShown = [...byServer.entries()].map(([id, rows]) => [id, rows.filter(matches2)]).filter(([, rows]) => rows.length > 0);
1268
+ const matches = (row) => !filter || row.name.toLowerCase().includes(filter) || row.description.toLowerCase().includes(filter);
1269
+ const builtinShown = builtin.filter(matches);
1270
+ const serverShown = [...byServer.entries()].map(([id, rows]) => [id, rows.filter(matches)]).filter(([, rows]) => rows.length > 0);
1265
1271
  const total = builtinShown.length + serverShown.reduce((a, [, r]) => a + r.length, 0);
1266
1272
  if (total === 0) {
1267
1273
  console.log(filter ? `
@@ -1397,7 +1403,7 @@ No tools match "${filter}".
1397
1403
  const { join: join6 } = await import("path");
1398
1404
  const { existsSync: existsSync6 } = await import("fs");
1399
1405
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1400
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-SZTJESDF.js");
1406
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-IO5VJLEE.js");
1401
1407
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1402
1408
  const cwd = process.cwd();
1403
1409
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -1601,15 +1607,6 @@ No tools match "${filter}".
1601
1607
  // src/repl/commands/security-commands.ts
1602
1608
  import { platform as platform2 } from "os";
1603
1609
  import chalk2 from "chalk";
1604
- function stripSurroundingQuotes(value) {
1605
- const pairs = [['"', '"'], ["'", "'"], ["\u201C", "\u201D"], ["\u2018", "\u2019"], ["\u300C", "\u300D"]];
1606
- for (const [open, close] of pairs) {
1607
- if (value.length >= 2 && value.startsWith(open) && value.endsWith(close)) {
1608
- return value.slice(open.length, value.length - close.length).trim();
1609
- }
1610
- }
1611
- return value;
1612
- }
1613
1610
  function createSecurityCommands() {
1614
1611
  return [
1615
1612
  {
@@ -1673,58 +1670,32 @@ function createSecurityCommands() {
1673
1670
  {
1674
1671
  name: "profile",
1675
1672
  description: 'View or edit your identity profile (the "soul" of AI)',
1676
- usage: "/profile [show|edit|set <field> <value>|clear]",
1673
+ usage: "/profile [show|set <field> <value>|clear|edit]",
1677
1674
  execute(args, ctx) {
1678
- const sub = args[0] ?? "show";
1679
- const profile = ctx.config.get("userProfile") ?? {};
1680
- if (sub === "show" || sub === "view") {
1681
- const hasProfile = profile.name || profile.nickname || profile.role;
1682
- if (!hasProfile) {
1683
- console.log(theme.dim("\n No profile configured yet. Use /profile edit or /config to set up.\n"));
1684
- return;
1675
+ const outcome = applyProfileCommand(args, ctx.config.get("userProfile") ?? {});
1676
+ if (outcome.profile) {
1677
+ ctx.config.set("userProfile", outcome.profile);
1678
+ ctx.config.save();
1679
+ }
1680
+ if (outcome.isError) {
1681
+ ctx.renderer.printInfo(outcome.summary);
1682
+ } else if (outcome.changed) {
1683
+ ctx.renderer.printSuccess(outcome.summary);
1684
+ } else if (outcome.rows.length > 0) {
1685
+ console.log(theme.heading(`
1686
+ ${outcome.summary}
1687
+ `) + theme.dim("\u2500".repeat(50)));
1688
+ const pad = Math.max(...outcome.rows.map(([label]) => label.length)) + 1;
1689
+ for (const [label, value] of outcome.rows) {
1690
+ console.log(` ${theme.dim((label + ":").padEnd(pad + 1))} ${chalk2.white(value)}`);
1685
1691
  }
1686
- console.log(theme.heading("\n\u{1F464} Your Profile\n") + theme.dim("\u2500".repeat(50)));
1687
- if (profile.name) console.log(` ${theme.dim("Name:")} ${chalk2.white(profile.name)}`);
1688
- if (profile.nickname) console.log(` ${theme.dim("Nickname:")} ${theme.accent(profile.nickname)}`);
1689
- if (profile.role) console.log(` ${theme.dim("Role:")} ${chalk2.white(profile.role)}`);
1690
- if (profile.bio) console.log(` ${theme.dim("Bio:")} ${chalk2.white(profile.bio)}`);
1691
- if (profile.interests?.length) console.log(` ${theme.dim("Interests:")} ${chalk2.white(profile.interests.join(", "))}`);
1692
- if (profile.locale) console.log(` ${theme.dim("Locale:")} ${chalk2.white(profile.locale)}`);
1693
- if (profile.extra) console.log(` ${theme.dim("Extra:")} ${chalk2.white(profile.extra.slice(0, 80))}${profile.extra.length > 80 ? "\u2026" : ""}`);
1694
1692
  console.log(theme.dim("\u2500".repeat(50)));
1695
- console.log(theme.dim(" This identity is injected into every AI conversation.\n"));
1696
- } else if (sub === "edit") {
1697
- ctx.renderer.printInfo("Use /config to open the interactive profile editor, or use:\n /profile set <field> <value>\n Fields: name, nickname, role, bio, interests, locale, extra");
1698
- } else if (sub === "set") {
1699
- const field = args[1];
1700
- const value = args.slice(2).join(" ").trim();
1701
- const validFields = ["name", "nickname", "role", "bio", "interests", "locale", "extra"];
1702
- if (!field || !validFields.includes(field)) {
1703
- ctx.renderer.printInfo(`Usage: /profile set <field> <value>
1704
- Fields: ${validFields.join(", ")}`);
1705
- return;
1706
- }
1707
- if (!value) {
1708
- ctx.renderer.printInfo(`Usage: /profile set ${field} <value>`);
1709
- return;
1710
- }
1711
- const updated = { ...profile };
1712
- if (field === "interests") {
1713
- updated.interests = value.split(",").map((s) => stripSurroundingQuotes(s.trim())).filter(Boolean);
1714
- } else {
1715
- updated[field] = stripSurroundingQuotes(value);
1716
- }
1717
- ctx.config.set("userProfile", updated);
1718
- ctx.config.save();
1719
- const displayVal = field === "interests" ? updated.interests : value;
1720
- ctx.renderer.printSuccess(`Profile updated: ${field} = ${JSON.stringify(displayVal)}`);
1721
- } else if (sub === "clear") {
1722
- ctx.config.set("userProfile", {});
1723
- ctx.config.save();
1724
- ctx.renderer.printSuccess("Profile cleared. AI will no longer know who you are.");
1725
1693
  } else {
1726
- ctx.renderer.printInfo("Usage: /profile [show|edit|set <field> <value>|clear]");
1694
+ console.log(theme.dim(`
1695
+ ${outcome.summary}`));
1727
1696
  }
1697
+ for (const line of outcome.details) console.log(theme.dim(` ${line}`));
1698
+ console.log();
1728
1699
  }
1729
1700
  },
1730
1701
  // ── /memory ────────────────────────────────────────────────────────────────
@@ -2385,7 +2356,7 @@ function createReviewCommands() {
2385
2356
  usage: "/test [command|filter]",
2386
2357
  async execute(args, ctx) {
2387
2358
  try {
2388
- const { executeTests } = await import("./run-tests-NTDZ6DDU.js");
2359
+ const { executeTests } = await import("./run-tests-FZSYHWYX.js");
2389
2360
  const argStr = args.join(" ").trim();
2390
2361
  let testArgs = {};
2391
2362
  if (argStr) {
@@ -2880,41 +2851,17 @@ function createMemoryCommands() {
2880
2851
  }
2881
2852
  return { flags, text: text.join(" ").trim() };
2882
2853
  };
2883
- const asScope = (value) => value === "personal" || value === "project" || value === "session" || value === "team" ? value : void 0;
2884
2854
  const asSensitivity = (value) => value === "low" || value === "medium" || value === "high" ? value : void 0;
2885
2855
  if (sub === "show" || sub === "view" || sub === "list") {
2886
- const parsed = parseFlags(args.slice(1));
2887
- const scopeFilter = asScope(parsed.flags.scope);
2888
- const searchText = typeof parsed.flags.search === "string" ? parsed.flags.search.toLowerCase() : (parsed.text || void 0)?.toLowerCase();
2889
- const filters = [];
2890
- let entries;
2891
- if (parsed.flags.orphaned === true) {
2892
- entries = listOrphanedProjectMemories(configDir);
2893
- filters.push("orphaned");
2894
- } else {
2895
- entries = listMemoryEntries(configDir, { includeExpired: true, includeRejected: true });
2896
- }
2897
- if (parsed.flags.pending === true) {
2898
- entries = entries.filter((m) => !m.approved && !isMemoryExpired(m));
2899
- filters.push("pending");
2900
- }
2901
- if (scopeFilter) {
2902
- entries = entries.filter((m) => m.scope === scopeFilter);
2903
- filters.push(`scope:${scopeFilter}`);
2904
- }
2905
- if (searchText) {
2906
- entries = entries.filter((m) => m.content.toLowerCase().includes(searchText) || m.id.startsWith(searchText));
2907
- filters.push(`search:"${searchText}"`);
2908
- }
2909
- const staleDays = typeof parsed.flags.stale === "string" ? Number(parsed.flags.stale) : void 0;
2910
- if (staleDays !== void 0) {
2911
- if (!Number.isFinite(staleDays) || staleDays <= 0) {
2912
- ctx.renderer.renderError("Usage: /memory show --stale <days> (positive number)");
2913
- return;
2914
- }
2915
- entries = entries.filter((m) => isMemoryStale(m, staleDays));
2916
- filters.push(`stale>${staleDays}d`);
2856
+ const showFilters = parseMemoryShowFilters(args.slice(1));
2857
+ if (showFilters.invalidStale) {
2858
+ ctx.renderer.renderError("Usage: /memory show --stale <days> (positive number)");
2859
+ return;
2917
2860
  }
2861
+ const sourceEntries = showFilters.orphaned ? listOrphanedProjectMemories(configDir) : listMemoryEntries(configDir, { includeExpired: true, includeRejected: true });
2862
+ const filtered = filterMemoryEntries(sourceEntries, showFilters);
2863
+ const entries = filtered.entries;
2864
+ const filters = filtered.applied;
2918
2865
  if (entries.length === 0) {
2919
2866
  ctx.renderer.printInfo(filters.length > 0 ? `No memory entries match [${filters.join(", ")}]` : "Memory is empty");
2920
2867
  return;
@@ -3327,18 +3274,18 @@ function createSessionCommands() {
3327
3274
  return;
3328
3275
  }
3329
3276
  const sessions = ctx.sessions.listSessions();
3330
- const matches2 = sessions.filter((s) => s.id.startsWith(id));
3331
- if (matches2.length === 0) {
3277
+ const matches = sessions.filter((s) => s.id.startsWith(id));
3278
+ if (matches.length === 0) {
3332
3279
  ctx.renderer.renderError(`Session '${id}' not found.`);
3333
3280
  return;
3334
3281
  }
3335
- if (matches2.length > 1) {
3336
- console.log(theme.warning(` \u26A0 Ambiguous prefix '${id}' matches ${matches2.length} sessions \u2014 loading most recent:`));
3337
- for (const m of matches2.slice(0, 5)) {
3282
+ if (matches.length > 1) {
3283
+ console.log(theme.warning(` \u26A0 Ambiguous prefix '${id}' matches ${matches.length} sessions \u2014 loading most recent:`));
3284
+ for (const m of matches.slice(0, 5)) {
3338
3285
  console.log(theme.dim(` ${m.id.slice(0, 12)} ${m.title ?? "(untitled)"}`));
3339
3286
  }
3340
3287
  }
3341
- const match = matches2[0];
3288
+ const match = matches[0];
3342
3289
  ctx.sessions.loadSession(match.id);
3343
3290
  ctx.setProvider(match.provider, match.model);
3344
3291
  ctx.resetSessionTokenUsage();
@@ -3397,24 +3344,24 @@ function createSessionCommands() {
3397
3344
  return;
3398
3345
  }
3399
3346
  const allSessions = ctx.sessions.listSessions();
3400
- const matches3 = allSessions.filter((s) => s.messageCount === filterMessages);
3401
- if (matches3.length === 0) {
3347
+ const matches2 = allSessions.filter((s) => s.messageCount === filterMessages);
3348
+ if (matches2.length === 0) {
3402
3349
  ctx.renderer.printInfo(`No sessions with ${filterMessages} message(s) found.`);
3403
3350
  return;
3404
3351
  }
3405
3352
  console.log();
3406
3353
  console.log(
3407
- theme.warning(` Found ${matches3.length} session(s) with ${filterMessages} message(s):`)
3354
+ theme.warning(` Found ${matches2.length} session(s) with ${filterMessages} message(s):`)
3408
3355
  );
3409
- for (const s of matches3.slice(0, 20)) {
3356
+ for (const s of matches2.slice(0, 20)) {
3410
3357
  console.log(
3411
3358
  theme.dim(
3412
3359
  ` ${s.id.slice(0, 12)} ${s.provider}/${s.model} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${truncateTitle(s.title ?? "(untitled)", 60)}`
3413
3360
  )
3414
3361
  );
3415
3362
  }
3416
- if (matches3.length > 20) {
3417
- console.log(theme.dim(` ... and ${matches3.length - 20} more`));
3363
+ if (matches2.length > 20) {
3364
+ console.log(theme.dim(` ... and ${matches2.length - 20} more`));
3418
3365
  }
3419
3366
  if (dryRun) {
3420
3367
  console.log(
@@ -3425,7 +3372,7 @@ function createSessionCommands() {
3425
3372
  }
3426
3373
  console.log();
3427
3374
  const choice2 = await ctx.select(
3428
- `Delete all ${matches3.length} matching sessions?`,
3375
+ `Delete all ${matches2.length} matching sessions?`,
3429
3376
  [
3430
3377
  { label: "No \u2014 keep them", value: "no" },
3431
3378
  { label: "Yes \u2014 delete permanently", value: "yes", hint: "unlinks all matching history files" }
@@ -3437,7 +3384,7 @@ function createSessionCommands() {
3437
3384
  }
3438
3385
  let deleted = 0;
3439
3386
  let failed = 0;
3440
- for (const s of matches3) {
3387
+ for (const s of matches2) {
3441
3388
  if (ctx.sessions.deleteSession(s.id)) {
3442
3389
  deleted++;
3443
3390
  } else {
@@ -3462,19 +3409,19 @@ function createSessionCommands() {
3462
3409
  return;
3463
3410
  }
3464
3411
  const sessions = ctx.sessions.listSessions();
3465
- const matches2 = sessions.filter((s) => s.id.startsWith(id));
3466
- if (matches2.length === 0) {
3412
+ const matches = sessions.filter((s) => s.id.startsWith(id));
3413
+ if (matches.length === 0) {
3467
3414
  ctx.renderer.renderError(`Session '${id}' not found.`);
3468
3415
  return;
3469
3416
  }
3470
- if (matches2.length > 1) {
3471
- ctx.renderer.renderError(`Ambiguous prefix '${id}' matches ${matches2.length} sessions \u2014 be more specific:`);
3472
- for (const m of matches2.slice(0, 10)) {
3417
+ if (matches.length > 1) {
3418
+ ctx.renderer.renderError(`Ambiguous prefix '${id}' matches ${matches.length} sessions \u2014 be more specific:`);
3419
+ for (const m of matches.slice(0, 10)) {
3473
3420
  console.log(theme.dim(` ${m.id.slice(0, 12)} ${String(m.messageCount).padStart(4)} msgs ${m.updated.toLocaleDateString()} ${m.title ?? "(untitled)"}`));
3474
3421
  }
3475
3422
  return;
3476
3423
  }
3477
- const match = matches2[0];
3424
+ const match = matches[0];
3478
3425
  const isCurrent = ctx.sessions.current?.id === match.id;
3479
3426
  console.log();
3480
3427
  console.log(theme.warning(" About to permanently delete session (no undo):"));
@@ -4072,13 +4019,13 @@ No commands match "${filter}".
4072
4019
  ${theme.heading(`Found ${results.length} session(s) containing "${query}"`)}
4073
4020
  `);
4074
4021
  for (const r of results) {
4075
- const { sessionMeta, matches: matches2 } = r;
4022
+ const { sessionMeta, matches } = r;
4076
4023
  const dateStr = sessionMeta.updated.toLocaleDateString();
4077
4024
  console.log(
4078
4025
  ` ${theme.accent(sessionMeta.id.slice(0, 8))}` + theme.dim(` [${dateStr}] ${sessionMeta.provider} / ${sessionMeta.model}`) + (sessionMeta.title ? `
4079
4026
  ${theme.dim(" " + sessionMeta.title)}` : "")
4080
4027
  );
4081
- for (const m of matches2) {
4028
+ for (const m of matches) {
4082
4029
  const icon = m.role === "user" ? "\u{1F464}" : "\u{1F916}";
4083
4030
  console.log(` ${icon} ${theme.warning(m.snippet)}`);
4084
4031
  }
@@ -4255,10 +4202,20 @@ function createAgentCommands() {
4255
4202
  {
4256
4203
  name: "yolo",
4257
4204
  description: "Toggle session auto-approve for write tools (/yolo)",
4258
- usage: "/yolo [on|off]",
4205
+ usage: "/yolo [on|off|status]",
4259
4206
  execute(args, ctx) {
4260
4207
  const sub = args[0]?.toLowerCase();
4261
4208
  const executor = ctx.getToolExecutor();
4209
+ if (sub === "status") {
4210
+ console.log(theme.info(` YOLO mode: ${executor.sessionAutoApprove ? "ON (write tools auto-approved)" : "OFF"}`));
4211
+ console.log();
4212
+ return;
4213
+ }
4214
+ if (sub !== void 0 && sub !== "on" && sub !== "off") {
4215
+ console.log(theme.warning(` Unknown /yolo option "${sub}" \u2014 expected on | off | status`));
4216
+ console.log();
4217
+ return;
4218
+ }
4262
4219
  if (sub === "off") {
4263
4220
  executor.sessionAutoApprove = false;
4264
4221
  console.log(theme.info(" \u{1F512} Auto-approve disabled \u2014 confirmations restored for this session."));
@@ -4854,74 +4811,6 @@ function installUnicodeBackspaceRepair(input, rl, shouldHandle = () => true) {
4854
4811
  return () => input.off("keypress", onKeypress);
4855
4812
  }
4856
4813
 
4857
- // src/core/model-router.ts
4858
- var TAG_REGEX = /(?:^|\s)#([a-zA-Z][\w-]{0,31})\b/g;
4859
- function extractTags(message) {
4860
- const tags = /* @__PURE__ */ new Set();
4861
- let m;
4862
- TAG_REGEX.lastIndex = 0;
4863
- while ((m = TAG_REGEX.exec(message)) !== null) {
4864
- tags.add(m[1].toLowerCase());
4865
- }
4866
- return tags;
4867
- }
4868
- function matches(message, matcher) {
4869
- const trimmed = message.trim();
4870
- const lower = trimmed.toLowerCase();
4871
- if (matcher.tag) {
4872
- const tags = extractTags(trimmed);
4873
- if (!tags.has(matcher.tag.toLowerCase())) return false;
4874
- }
4875
- if (matcher.contains && matcher.contains.length > 0) {
4876
- const hit = matcher.contains.some((kw) => lower.includes(kw.toLowerCase()));
4877
- if (!hit) return false;
4878
- }
4879
- if (typeof matcher.maxLength === "number") {
4880
- if (trimmed.length > matcher.maxLength) return false;
4881
- }
4882
- if (typeof matcher.minLength === "number") {
4883
- if (trimmed.length < matcher.minLength) return false;
4884
- }
4885
- const hasAnyCondition = !!matcher.tag || matcher.contains && matcher.contains.length > 0 || typeof matcher.maxLength === "number" || typeof matcher.minLength === "number";
4886
- return !!hasAnyCondition;
4887
- }
4888
- function pickModel(message, currentModel, config, availableModels = []) {
4889
- if (!config.enabled || config.rules.length === 0) {
4890
- return { model: currentModel, reason: "routing disabled", overridden: false };
4891
- }
4892
- const isAvailable = (m) => availableModels.length === 0 || availableModels.includes(m);
4893
- for (let i = 0; i < config.rules.length; i++) {
4894
- const rule = config.rules[i];
4895
- if (!matches(message, rule.match)) continue;
4896
- if (!isAvailable(rule.model)) continue;
4897
- if (rule.model === currentModel) {
4898
- return {
4899
- model: currentModel,
4900
- reason: `rule "${rule.name ?? `#${i}`}" matched (same as current)`,
4901
- overridden: false,
4902
- ruleIdx: i
4903
- };
4904
- }
4905
- return {
4906
- model: rule.model,
4907
- reason: `rule "${rule.name ?? `#${i}`}" matched`,
4908
- overridden: true,
4909
- ruleIdx: i
4910
- };
4911
- }
4912
- if (config.fallback && config.fallback !== currentModel && isAvailable(config.fallback)) {
4913
- return {
4914
- model: config.fallback,
4915
- reason: "fallback",
4916
- overridden: true
4917
- };
4918
- }
4919
- return { model: currentModel, reason: "no rule matched", overridden: false };
4920
- }
4921
- function stripRoutingTags(message) {
4922
- return message.replace(/(?:^|\s)#(fast|deep|default)\b/gi, " ").replace(/\s{2,}/g, " ").trim();
4923
- }
4924
-
4925
4814
  // src/providers/fallback.ts
4926
4815
  var TRANSIENT_CODES = /* @__PURE__ */ new Set([
4927
4816
  "ECONNRESET",
@@ -6264,18 +6153,18 @@ Session '${this.resumeSessionId}' not found.
6264
6153
  * When routing is disabled or no rule matches, returns the current model unchanged.
6265
6154
  */
6266
6155
  computeRoutingDecision(userInput) {
6267
- const routingConfig = this.config.get("routing");
6268
- if (!routingConfig || !routingConfig.enabled) {
6269
- return { model: this.currentModel, reason: "routing disabled", overridden: false };
6270
- }
6271
6156
  let availableModels = [];
6272
6157
  try {
6273
- const provider = this.providers.get(this.currentProvider);
6274
- availableModels = provider.info.models.map((m) => m.id);
6158
+ availableModels = this.providers.get(this.currentProvider).info.models.map((m) => m.id);
6275
6159
  } catch {
6276
6160
  availableModels = [];
6277
6161
  }
6278
- return pickModel(userInput, this.currentModel, routingConfig, availableModels);
6162
+ return decideModel({
6163
+ userInput,
6164
+ currentModel: this.currentModel,
6165
+ routingConfig: this.config.get("routing"),
6166
+ availableModels
6167
+ });
6279
6168
  }
6280
6169
  // ─── Context 自动管理 ───────────────────────────────────────────────────
6281
6170
  /**
@@ -6289,28 +6178,11 @@ Session '${this.resumeSessionId}' not found.
6289
6178
  * 估算当前对话的总 token 消耗(system prompt + 所有 session messages)。
6290
6179
  */
6291
6180
  estimateConversationTokens() {
6292
- let total = 0;
6293
6181
  const { stable: estStable, volatile: estVolatile } = this.buildCurrentSystemPrompt();
6294
- const sysPrompt = [estStable, estVolatile].filter(Boolean).join("\n\n---\n\n");
6295
- if (sysPrompt) total += this.estimateTokens(sysPrompt);
6296
- const session = this.sessions.current;
6297
- if (session) {
6298
- for (const msg of session.messages) {
6299
- if (typeof msg.content === "string") {
6300
- total += this.estimateTokens(msg.content);
6301
- } else if (Array.isArray(msg.content)) {
6302
- for (const part of msg.content) {
6303
- if (part.type === "text" && part.text) total += this.estimateTokens(part.text);
6304
- }
6305
- }
6306
- if (msg.toolCalls) {
6307
- for (const tc of msg.toolCalls) {
6308
- total += this.estimateTokens(JSON.stringify(tc.arguments));
6309
- }
6310
- }
6311
- }
6312
- }
6313
- return total;
6182
+ return estimateConversationTokens({
6183
+ systemPrompt: [estStable, estVolatile].filter(Boolean).join("\n\n---\n\n"),
6184
+ messages: this.sessions.current?.messages ?? []
6185
+ });
6314
6186
  }
6315
6187
  /**
6316
6188
  * 估算 agentic 循环当前请求的 token 数(包含 session messages + extraMessages + system prompt)。
@@ -6349,20 +6221,20 @@ Session '${this.resumeSessionId}' not found.
6349
6221
  * 在每次 AI 回复后调用。
6350
6222
  */
6351
6223
  async checkContextPressure() {
6352
- if (!this.config.get("autoCompact")) return;
6353
6224
  const contextWindow = this.getContextWindowSize();
6354
- if (contextWindow <= 0) return;
6355
- const estimated = this.estimateConversationTokens();
6356
- const ratio = estimated / contextWindow;
6357
- if (ratio >= CONTEXT_PRESSURE_THRESHOLD) {
6358
- console.log(
6359
- theme.warning(
6360
- `
6361
- \u26A0 Context pressure: ~${Math.round(ratio * 100)}% of ${fmtTokens(contextWindow)} window used. Auto-compacting...`
6362
- )
6363
- );
6364
- await this.compactSession("Preserve key context, compress old content, ensure seamless continuation");
6365
- }
6225
+ const pressure = evaluateContextPressure({
6226
+ autoCompactEnabled: this.config.get("autoCompact") === true,
6227
+ estimatedTokens: contextWindow > 0 ? this.estimateConversationTokens() : 0,
6228
+ contextWindow
6229
+ });
6230
+ if (!pressure.shouldCompact) return;
6231
+ console.log(
6232
+ theme.warning(
6233
+ `
6234
+ \u26A0 Context pressure: ~${pressure.percent}% of ${fmtTokens(contextWindow)} window used. Auto-compacting...`
6235
+ )
6236
+ );
6237
+ await this.compactSession(AUTO_COMPACT_INSTRUCTION);
6366
6238
  }
6367
6239
  // ─── Tab 自动补全 ──────────────────────────────────────────────────────
6368
6240
  /**
@@ -7688,7 +7560,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7688
7560
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7689
7561
  process.exit(1);
7690
7562
  }
7691
- const { startWebServer } = await import("./server-IALCWKSU.js");
7563
+ const { startWebServer } = await import("./server-WTJSM2MT.js");
7692
7564
  await startWebServer({ port, host: options.host });
7693
7565
  });
7694
7566
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -7855,11 +7727,11 @@ program.command("sessions").description("List recent conversation sessions").opt
7855
7727
  console.log(footer + "\n");
7856
7728
  });
7857
7729
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
7858
- const { runUsageCli } = await import("./usage-DJDLHICZ.js");
7730
+ const { runUsageCli } = await import("./usage-GVFUVYUG.js");
7859
7731
  await runUsageCli(options);
7860
7732
  });
7861
7733
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
7862
- const { runDoctorCli } = await import("./doctor-cli-Z272364P.js");
7734
+ const { runDoctorCli } = await import("./doctor-cli-ZU4E2DDL.js");
7863
7735
  const argv = process.argv.slice(2);
7864
7736
  await runDoctorCli({
7865
7737
  json: !!options.json || argv.includes("--json"),
@@ -7868,7 +7740,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
7868
7740
  });
7869
7741
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
7870
7742
  try {
7871
- const batch = await import("./batch-GY5MAN5F.js");
7743
+ const batch = await import("./batch-HUOYPVJQ.js");
7872
7744
  switch (action) {
7873
7745
  case "submit":
7874
7746
  if (!arg) {
@@ -7911,7 +7783,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7911
7783
  }
7912
7784
  });
7913
7785
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
7914
- const { startMcpServer } = await import("./server-SP3AEHRQ.js");
7786
+ const { startMcpServer } = await import("./server-ZSTVYSYC.js");
7915
7787
  await startMcpServer({
7916
7788
  allowDestructive: !!options.allowDestructive,
7917
7789
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7924,7 +7796,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7924
7796
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
7925
7797
  process.exit(1);
7926
7798
  }
7927
- const { runPrCli } = await import("./pr-VLLIALRK.js");
7799
+ const { runPrCli } = await import("./pr-Z4O5H6I3.js");
7928
7800
  const result = await runPrCli({
7929
7801
  action,
7930
7802
  target,
@@ -7944,8 +7816,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7944
7816
  process.exit(result.exitCode);
7945
7817
  });
7946
7818
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).option("--base <ref>", "Base ref for git diff <ref>...HEAD (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
7947
- const { runCi } = await import("./ci-MUEQSNKU.js");
7948
- const { formatCiResult } = await import("./ci-format-2ZGGSOFK.js");
7819
+ const { runCi } = await import("./ci-4QS2J7BG.js");
7820
+ const { formatCiResult } = await import("./ci-format-6L6M67WC.js");
7949
7821
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
7950
7822
  if (formats > 1) {
7951
7823
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -8103,7 +7975,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
8103
7975
  config.get("customProviders"),
8104
7976
  config.getConfigDir()
8105
7977
  );
8106
- const { startHub } = await import("./hub-MRLGKMRI.js");
7978
+ const { startHub } = await import("./hub-AMDWXSKZ.js");
8107
7979
  await startHub(
8108
7980
  {
8109
7981
  topic: topic ?? "",