jinzd-ai-cli 0.4.277 → 0.4.279

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 (34) hide show
  1. package/dist/{batch-2I5TPZA2.js → batch-6QZSWCBL.js} +2 -2
  2. package/dist/{chunk-ZP3RCZKM.js → chunk-2BKRWTEQ.js} +1 -1
  3. package/dist/{chunk-Z752LDYF.js → chunk-5XHEXRMN.js} +1 -1
  4. package/dist/{chunk-7BO5H2QI.js → chunk-6WMT7OQG.js} +1 -1
  5. package/dist/{chunk-HJVKCOAG.js → chunk-7L4TEK7Q.js} +419 -3
  6. package/dist/{chunk-7YYUITED.js → chunk-CMNXAJLH.js} +1 -1
  7. package/dist/{chunk-KIGKL3PZ.js → chunk-FQJFGGKN.js} +4 -4
  8. package/dist/{chunk-UWQCTTP4.js → chunk-IIXZ7IPN.js} +1 -1
  9. package/dist/{chunk-7IPMONKZ.js → chunk-JLOQBYU4.js} +3 -3
  10. package/dist/{chunk-I3PYD2YN.js → chunk-JS6VAPWM.js} +3 -3
  11. package/dist/{chunk-3VFOXEIL.js → chunk-NZPHEUJM.js} +1 -1
  12. package/dist/{chunk-HCF442WL.js → chunk-RJY3HJS4.js} +1 -1
  13. package/dist/{chunk-BYNNKJUC.js → chunk-SIVM2YQQ.js} +1 -1
  14. package/dist/{chunk-OCOGYIRY.js → chunk-UD3BVNC5.js} +1 -1
  15. package/dist/{ci-JFC45LIS.js → ci-F4ESOYI5.js} +4 -4
  16. package/dist/{ci-format-P3LIZHUR.js → ci-format-AIRW3TVQ.js} +2 -2
  17. package/dist/{constants-N3CHKZJY.js → constants-3VMMZJDS.js} +1 -1
  18. package/dist/{doctor-cli-Z3TGHTSX.js → doctor-cli-WVMEWMYE.js} +4 -4
  19. package/dist/electron-server.js +699 -101
  20. package/dist/{hub-NEWIFMQ3.js → hub-JJCCCU3O.js} +1 -1
  21. package/dist/index.js +243 -466
  22. package/dist/{persistent-memory-6Q5FDFJ7.js → persistent-memory-KSZKM4JG.js} +2 -2
  23. package/dist/{persistent-memory-ZFR5GI7D.js → persistent-memory-QZN4Q3W4.js} +2 -2
  24. package/dist/{pr-ZUGSWQ5R.js → pr-GFB5JC26.js} +4 -4
  25. package/dist/{run-tests-76M6AC3G.js → run-tests-EL54INOI.js} +2 -2
  26. package/dist/{run-tests-USV7IJ7X.js → run-tests-HMHHIG7Y.js} +2 -2
  27. package/dist/{server-R7D5RR36.js → server-6C7GITHY.js} +5 -5
  28. package/dist/{server-C523CIGN.js → server-WUSJWC3A.js} +324 -106
  29. package/dist/{task-orchestrator-G2MQDNGQ.js → task-orchestrator-C7RUUA2Q.js} +5 -5
  30. package/dist/{usage-EFHXXMYX.js → usage-CW6BT2UV.js} +2 -2
  31. package/dist/web/client/app.js +18 -3
  32. package/dist/web/client/app.js.br +0 -0
  33. package/dist/web/client/app.js.gz +0 -0
  34. package/package.json +1 -1
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigManager
4
- } from "./chunk-OCOGYIRY.js";
4
+ } from "./chunk-UD3BVNC5.js";
5
5
  import "./chunk-TU3L3PW7.js";
6
6
  import {
7
7
  atomicWriteFileSync
8
8
  } from "./chunk-IW3Q7AE5.js";
9
- import "./chunk-ZP3RCZKM.js";
9
+ import "./chunk-2BKRWTEQ.js";
10
10
 
11
11
  // src/cli/batch.ts
12
12
  import Anthropic from "@anthropic-ai/sdk";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/core/constants.ts
4
- var VERSION = "0.4.277";
4
+ var VERSION = "0.4.279";
5
5
  var APP_NAME = "ai-cli";
6
6
  var CONFIG_DIR_NAME = ".aicli";
7
7
  var CONFIG_FILE_NAME = "config.json";
@@ -1,5 +1,5 @@
1
1
  // src/core/constants.ts
2
- var VERSION = "0.4.277";
2
+ var VERSION = "0.4.279";
3
3
  var APP_NAME = "ai-cli";
4
4
  var CONFIG_DIR_NAME = ".aicli";
5
5
  var CONFIG_FILE_NAME = "config.json";
@@ -13,7 +13,7 @@ import {
13
13
  MEMORY_FILE_NAME,
14
14
  MEMORY_MAX_CHARS,
15
15
  MEMORY_STORE_FILE_NAME
16
- } from "./chunk-ZP3RCZKM.js";
16
+ } from "./chunk-2BKRWTEQ.js";
17
17
 
18
18
  // src/memory/persistent-memory.ts
19
19
  import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync } from "fs";
@@ -5,11 +5,11 @@ import {
5
5
  import {
6
6
  estimateTokens,
7
7
  truncateForPersist
8
- } from "./chunk-KIGKL3PZ.js";
8
+ } from "./chunk-FQJFGGKN.js";
9
9
  import {
10
10
  isMemoryExpired,
11
11
  isMemoryStale
12
- } from "./chunk-7BO5H2QI.js";
12
+ } from "./chunk-6WMT7OQG.js";
13
13
  import {
14
14
  isCleanDocumentBody,
15
15
  stripOuterCodeFence
@@ -27,7 +27,7 @@ import {
27
27
  MCP_PROTOCOL_VERSION,
28
28
  MCP_TOOL_PREFIX,
29
29
  VERSION
30
- } from "./chunk-ZP3RCZKM.js";
30
+ } from "./chunk-2BKRWTEQ.js";
31
31
 
32
32
  // src/mcp/client.ts
33
33
  import { spawn } from "child_process";
@@ -1382,6 +1382,404 @@ function applyThinkCommand(sub, state) {
1382
1382
  return stay(`Unknown /think option "${sub}" \u2014 expected on | off | low | high | max | status`);
1383
1383
  }
1384
1384
 
1385
+ // src/core/provider-command.ts
1386
+ function preservedSuffix(messageCount) {
1387
+ return messageCount > 0 ? ` (conversation preserved: ${messageCount} messages)` : "";
1388
+ }
1389
+ function resolveProviderSwitch(input) {
1390
+ const id = input.targetId;
1391
+ if (!input.configured) {
1392
+ return {
1393
+ status: "not-configured",
1394
+ message: `Provider '${id}' is not configured. Run: aicli config`
1395
+ };
1396
+ }
1397
+ if (input.availableModels.length === 0) {
1398
+ return {
1399
+ status: "no-models",
1400
+ message: `Provider '${id}' has no available models. ` + (id === "ollama" ? "Make sure Ollama is running (`ollama serve`) and has models (`ollama pull <model>`)." : "Check provider configuration.")
1401
+ };
1402
+ }
1403
+ if (id === input.currentProvider) {
1404
+ return { status: "unchanged", message: `Already using provider: ${id}` };
1405
+ }
1406
+ const model = input.configuredDefaultModel || input.providerDefaultModel;
1407
+ return {
1408
+ status: "switched",
1409
+ providerId: id,
1410
+ model,
1411
+ message: `Switched to provider: ${id} (${model})` + preservedSuffix(input.messageCount)
1412
+ };
1413
+ }
1414
+ function parseModelCommand(args, currentProvider) {
1415
+ const raw = args[0];
1416
+ if (!raw) return { kind: "select" };
1417
+ const sub = raw.toLowerCase();
1418
+ if (sub === "refresh") return { kind: "refresh", providerId: args[1] ?? currentProvider };
1419
+ if (sub === "cache") {
1420
+ if ((args[1] ?? "").toLowerCase() === "clear") return { kind: "cache-clear", providerId: args[2] };
1421
+ return { kind: "cache-show" };
1422
+ }
1423
+ return { kind: "set", modelId: raw };
1424
+ }
1425
+ function resolveModelSwitch(input) {
1426
+ if (input.targetModel === input.currentModel) {
1427
+ return { status: "unchanged", message: `Already using model: ${input.targetModel}` };
1428
+ }
1429
+ const known = input.knownModels.includes(input.targetModel);
1430
+ return {
1431
+ status: "switched",
1432
+ model: input.targetModel,
1433
+ message: `Switched to model: ${input.targetModel}` + preservedSuffix(input.messageCount),
1434
+ warning: known ? void 0 : `'${input.targetModel}' is not in the known model list for ${input.provider}. If the provider rejects it, check the spelling or run /model refresh ${input.provider}.`
1435
+ };
1436
+ }
1437
+ var PLAN_MODE_TOOL_HINT = [
1438
+ "read_file \xB7 list_dir \xB7 grep_files \xB7 glob_files",
1439
+ "web_fetch \xB7 google_search \xB7 ask_user \xB7 write_todos"
1440
+ ];
1441
+ function applyPlanCommand(sub, active) {
1442
+ const key = (sub ?? "enter").toLowerCase() === "toggle" ? active ? "exit" : "enter" : (sub ?? "enter").toLowerCase();
1443
+ if (key === "enter") {
1444
+ if (active) {
1445
+ return {
1446
+ planMode: true,
1447
+ changed: false,
1448
+ status: "already-active",
1449
+ summary: "Already in Plan Mode. Use /plan execute to start executing, or /plan exit to leave.",
1450
+ details: []
1451
+ };
1452
+ }
1453
+ return {
1454
+ planMode: true,
1455
+ changed: true,
1456
+ status: "entered",
1457
+ summary: "\u{1F4CB} Plan Mode activated",
1458
+ details: [
1459
+ "AI can now ONLY use read-only tools:",
1460
+ ...PLAN_MODE_TOOL_HINT,
1461
+ "Describe your task and the AI will analyze the codebase and create a detailed implementation plan.",
1462
+ "When ready: /plan execute | To cancel: /plan exit"
1463
+ ]
1464
+ };
1465
+ }
1466
+ if (key === "execute") {
1467
+ if (!active) {
1468
+ return { planMode: false, changed: false, status: "not-active", summary: "Not in Plan Mode. Enter first with /plan", details: [] };
1469
+ }
1470
+ return {
1471
+ planMode: false,
1472
+ changed: true,
1473
+ status: "executing",
1474
+ summary: "Plan Mode ended \u2014 switching to execute mode. AI now has full tool access.",
1475
+ details: []
1476
+ };
1477
+ }
1478
+ if (key === "exit" || key === "cancel") {
1479
+ if (!active) {
1480
+ return { planMode: false, changed: false, status: "not-active", summary: "Not in Plan Mode.", details: [] };
1481
+ }
1482
+ return { planMode: false, changed: true, status: "cancelled", summary: "Plan Mode cancelled. Returning to normal mode.", details: [] };
1483
+ }
1484
+ if (key === "status" || key === "show") {
1485
+ return {
1486
+ planMode: active,
1487
+ changed: false,
1488
+ status: "status",
1489
+ summary: `Plan Mode: ${active ? "ACTIVE \u{1F4CB}" : "inactive"}`,
1490
+ details: active ? ["Tools restricted to read-only set.", "Use /plan execute to start executing, or /plan exit to cancel."] : []
1491
+ };
1492
+ }
1493
+ return {
1494
+ planMode: active,
1495
+ changed: false,
1496
+ status: "unknown",
1497
+ summary: `Unknown /plan option "${sub}" \u2014 expected execute | exit | status`,
1498
+ details: []
1499
+ };
1500
+ }
1501
+ function parseRouteCommand(args) {
1502
+ const sub = (args[0] ?? "show").toLowerCase();
1503
+ if (sub === "on" || sub === "enable") return { kind: "enable" };
1504
+ if (sub === "off" || sub === "disable") return { kind: "disable" };
1505
+ if (sub === "test") {
1506
+ const message = args.slice(1).join(" ").trim();
1507
+ return message ? { kind: "test", message } : { kind: "usage", message: "Usage: /route test <message>" };
1508
+ }
1509
+ if (sub === "show" || sub === "status") return { kind: "show" };
1510
+ return { kind: "unknown", message: `Unknown subcommand: ${sub}. Usage: /route [on|off|show|test <message>]` };
1511
+ }
1512
+ function routingEmptyRulesNote(routing) {
1513
+ if (routing && routing.rules.length > 0) return null;
1514
+ return 'No rules configured yet. Add rules under `routing.rules` in ~/.aicli/config.json.\nExample: { match: { tag: "fast" }, model: "claude-haiku-4-5" }';
1515
+ }
1516
+ function describeRoutingRule(rule, index) {
1517
+ const parts = [];
1518
+ if (rule.match.tag) parts.push(`tag=#${rule.match.tag}`);
1519
+ if (rule.match.contains && rule.match.contains.length > 0) {
1520
+ const shown = rule.match.contains.slice(0, 3).join(", ");
1521
+ parts.push(`contains=[${shown}${rule.match.contains.length > 3 ? ", \u2026" : ""}]`);
1522
+ }
1523
+ if (typeof rule.match.maxLength === "number") parts.push(`maxLen=${rule.match.maxLength}`);
1524
+ if (typeof rule.match.minLength === "number") parts.push(`minLen=${rule.match.minLength}`);
1525
+ const empty = parts.length === 0;
1526
+ return {
1527
+ index,
1528
+ name: rule.name,
1529
+ condition: empty ? "(empty \u2014 never matches)" : parts.join(" & "),
1530
+ model: rule.model,
1531
+ empty
1532
+ };
1533
+ }
1534
+ function describeRouting(input) {
1535
+ const rules = input.routing?.rules ?? [];
1536
+ return {
1537
+ enabled: input.routing?.enabled === true,
1538
+ provider: input.provider,
1539
+ currentModel: input.currentModel,
1540
+ fallback: input.routing?.fallback,
1541
+ rules: rules.map((r, i) => describeRoutingRule(r, i)),
1542
+ noRulesNote: rules.length === 0 ? "(no rules configured \u2014 edit ~/.aicli/config.json `routing.rules`)" : null,
1543
+ hint: "Commands: /route on | off | test <msg> | show"
1544
+ };
1545
+ }
1546
+ function routeDecisionRows(message, currentModel, decision) {
1547
+ const rows = [
1548
+ { label: "Input", value: message },
1549
+ { label: "Current", value: currentModel },
1550
+ { label: "Decision", value: `${decision.model} ${decision.overridden ? "\u2192 ROUTED" : "(unchanged)"}` },
1551
+ { label: "Reason", value: decision.reason }
1552
+ ];
1553
+ if (typeof decision.ruleIdx === "number") rows.push({ label: "Rule", value: `#${decision.ruleIdx}` });
1554
+ return rows;
1555
+ }
1556
+
1557
+ // src/core/session-command.ts
1558
+ var DEFAULT_SESSION_LIST_LIMIT = 50;
1559
+ function parseSessionListArgs(args) {
1560
+ let limit = DEFAULT_SESSION_LIST_LIMIT;
1561
+ let all = false;
1562
+ const filter = {};
1563
+ const warnings = [];
1564
+ let search = null;
1565
+ let days = null;
1566
+ let since = null;
1567
+ let sort = { field: "updated", order: "desc" };
1568
+ let json = false;
1569
+ let stale = null;
1570
+ let verbose = false;
1571
+ for (let i = 1; i < args.length; i++) {
1572
+ const a = args[i];
1573
+ if (a === "--all" || a === "-a") {
1574
+ all = true;
1575
+ } else if ((a === "--limit" || a === "-n") && i + 1 < args.length) {
1576
+ const n = Number(args[i + 1]);
1577
+ if (Number.isFinite(n) && n > 0) {
1578
+ limit = n;
1579
+ i++;
1580
+ }
1581
+ } else if (a === "--filter" && i + 1 < args.length) {
1582
+ const val = args[++i];
1583
+ const eq = val.indexOf("=");
1584
+ if (eq > 0) {
1585
+ const key = val.slice(0, eq);
1586
+ const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
1587
+ if (key === "provider") filter.provider = vals;
1588
+ else if (key === "model") filter.model = vals;
1589
+ else if (key === "messages") {
1590
+ const n = Number(vals[0]);
1591
+ if (Number.isFinite(n) && n >= 0) filter.messages = n;
1592
+ else warnings.push(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
1593
+ } else {
1594
+ warnings.push(`Unknown filter key: "${key}". Supported keys: provider, model, messages`);
1595
+ }
1596
+ } else {
1597
+ warnings.push(`Invalid --filter syntax: "${val}". Expected key=value`);
1598
+ }
1599
+ } else if ((a === "--search" || a === "-s") && i + 1 < args.length) {
1600
+ search = args[++i];
1601
+ } else if (a === "--days" && i + 1 < args.length) {
1602
+ const n = Number(args[++i]);
1603
+ if (Number.isFinite(n) && n > 0) days = n;
1604
+ } else if (a === "--since" && i + 1 < args.length) {
1605
+ since = args[++i];
1606
+ } else if (a === "--sort" && i + 1 < args.length) {
1607
+ const sv = args[++i];
1608
+ const colon = sv.indexOf(":");
1609
+ const field = colon > 0 ? sv.slice(0, colon) : sv;
1610
+ const order = colon > 0 ? sv.slice(colon + 1) : "desc";
1611
+ if (field === "updated" || field === "created" || field === "messages" || field === "size") {
1612
+ sort = { field, order: order === "asc" ? "asc" : "desc" };
1613
+ }
1614
+ } else if (a === "--json") {
1615
+ json = true;
1616
+ } else if (a === "--verbose" || a === "-v") {
1617
+ verbose = true;
1618
+ } else if (a === "--stale" && i + 1 < args.length) {
1619
+ const n = Number(args[++i]);
1620
+ if (Number.isFinite(n) && n > 0) stale = n;
1621
+ }
1622
+ }
1623
+ if (all) limit = -1;
1624
+ return { limit, all, filter, search, days, since, sort, json, stale, verbose, warnings };
1625
+ }
1626
+ function sessionListNeedsFileSize(opts) {
1627
+ return opts.verbose || opts.sort.field === "size";
1628
+ }
1629
+ function selectSessions(sessions, opts, now = Date.now()) {
1630
+ let matched = sessions;
1631
+ const hasFilters = !!opts.filter.provider || !!opts.filter.model || opts.filter.messages !== void 0;
1632
+ const hasSearch = !!opts.search;
1633
+ const hasTimeFilter = opts.days !== null || opts.since !== null;
1634
+ const hasStale = opts.stale !== null;
1635
+ if (hasFilters) {
1636
+ const p = opts.filter.provider;
1637
+ const m = opts.filter.model;
1638
+ const msg = opts.filter.messages;
1639
+ matched = matched.filter((s) => {
1640
+ if (p && !p.includes(s.provider.toLowerCase())) return false;
1641
+ if (m && !m.some((kw) => s.model.toLowerCase().includes(kw))) return false;
1642
+ if (msg !== void 0 && s.messageCount !== msg) return false;
1643
+ return true;
1644
+ });
1645
+ }
1646
+ if (hasSearch) {
1647
+ const q = opts.search.toLowerCase();
1648
+ matched = matched.filter(
1649
+ (s) => (s.title ?? "").toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
1650
+ );
1651
+ }
1652
+ if (hasTimeFilter) {
1653
+ let cutoff = 0;
1654
+ if (opts.since) cutoff = new Date(opts.since).getTime();
1655
+ else if (opts.days !== null) cutoff = now - opts.days * 24 * 60 * 60 * 1e3;
1656
+ if (!Number.isNaN(cutoff)) {
1657
+ matched = matched.filter((s) => s.updated.getTime() >= cutoff);
1658
+ }
1659
+ }
1660
+ const staleCutoff = hasStale ? now - opts.stale * 24 * 60 * 60 * 1e3 : null;
1661
+ if (staleCutoff !== null) {
1662
+ matched = matched.filter((s) => s.updated.getTime() < staleCutoff);
1663
+ }
1664
+ const defaultSort = opts.sort.field === "updated" && opts.sort.order === "desc";
1665
+ if (!defaultSort) {
1666
+ const mul = opts.sort.order === "asc" ? 1 : -1;
1667
+ matched = [...matched].sort((a, b) => {
1668
+ switch (opts.sort.field) {
1669
+ case "created":
1670
+ return (a.created.getTime() - b.created.getTime()) * mul;
1671
+ case "messages":
1672
+ return (a.messageCount - b.messageCount) * mul;
1673
+ case "size":
1674
+ return ((a.fileSize ?? 0) - (b.fileSize ?? 0)) * mul;
1675
+ default:
1676
+ return (a.updated.getTime() - b.updated.getTime()) * mul;
1677
+ }
1678
+ });
1679
+ }
1680
+ const filterTags = [];
1681
+ if (hasFilters) filterTags.push("filtered");
1682
+ if (hasSearch) filterTags.push("searched");
1683
+ if (hasTimeFilter) filterTags.push("time-limited");
1684
+ if (hasStale) filterTags.push(`stale >${opts.stale}d`);
1685
+ return {
1686
+ matched,
1687
+ shown: opts.limit > 0 ? matched.slice(0, opts.limit) : matched,
1688
+ totalCount: matched.length,
1689
+ totalMessages: matched.reduce((sum, s) => sum + s.messageCount, 0),
1690
+ staleCutoff,
1691
+ filterTags,
1692
+ needsFileSize: sessionListNeedsFileSize(opts)
1693
+ };
1694
+ }
1695
+ function sessionListSummary(view) {
1696
+ const tag = view.filterTags.length > 0 ? ` (${view.filterTags.join(", ")})` : "";
1697
+ return `${view.shown.length} of ${view.totalCount} sessions${tag} \xB7 ${view.totalMessages} messages total`;
1698
+ }
1699
+ function sessionListJsonRow(s, includeFileSize) {
1700
+ return {
1701
+ id: s.id,
1702
+ title: s.title ?? null,
1703
+ provider: s.provider,
1704
+ model: s.model,
1705
+ messageCount: s.messageCount,
1706
+ created: s.created.toISOString(),
1707
+ updated: s.updated.toISOString(),
1708
+ ...includeFileSize ? { fileSize: s.fileSize } : {},
1709
+ ...s.branchCount !== void 0 ? { branchCount: s.branchCount, activeBranch: s.activeBranch } : {}
1710
+ };
1711
+ }
1712
+ function resolveSessionRef(sessions, prefix, policy) {
1713
+ const matches2 = sessions.filter((s) => s.id.startsWith(prefix));
1714
+ if (matches2.length === 0) {
1715
+ return { status: "not-found", message: `Session '${prefix}' not found.` };
1716
+ }
1717
+ if (matches2.length > 1 && policy === "strict") {
1718
+ return {
1719
+ status: "ambiguous",
1720
+ matches: matches2,
1721
+ message: `Ambiguous prefix '${prefix}' matches ${matches2.length} sessions \u2014 be more specific:`
1722
+ };
1723
+ }
1724
+ return {
1725
+ status: "ok",
1726
+ match: matches2[0],
1727
+ ambiguousWith: matches2.length > 1 ? matches2 : [],
1728
+ message: matches2.length > 1 ? `\u26A0 Ambiguous prefix '${prefix}' matches ${matches2.length} sessions \u2014 loading most recent:` : void 0
1729
+ };
1730
+ }
1731
+ function formatSessionSummaryLine(s, titleWidth = 60) {
1732
+ const title = s.title ?? "(untitled)";
1733
+ const shown = title.length > titleWidth ? `${title.slice(0, titleWidth - 1)}\u2026` : title;
1734
+ return `${s.id.slice(0, 12)} ${s.provider}/${s.model} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${shown}`;
1735
+ }
1736
+ function parseBatchDeleteArgs(args) {
1737
+ let messages;
1738
+ let dryRun = false;
1739
+ for (let i = 1; i < args.length; i++) {
1740
+ if (args[i] === "--filter" && i + 1 < args.length) {
1741
+ const val = args[++i];
1742
+ const eq = val.indexOf("=");
1743
+ if (eq <= 0) {
1744
+ return { dryRun, error: `Invalid --filter syntax: "${val}". Expected key=value (e.g., messages=0)` };
1745
+ }
1746
+ const key = val.slice(0, eq);
1747
+ const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
1748
+ if (key !== "messages") {
1749
+ return { dryRun, error: `Unsupported filter key for delete: "${key}". Only "messages" is supported.` };
1750
+ }
1751
+ const n = Number(vals[0]);
1752
+ if (!Number.isFinite(n) || n < 0) {
1753
+ return { dryRun, error: `Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"` };
1754
+ }
1755
+ messages = n;
1756
+ } else if (args[i] === "--dry-run") {
1757
+ dryRun = true;
1758
+ }
1759
+ }
1760
+ if (messages === void 0) {
1761
+ return { dryRun, error: "Usage: /session delete --filter messages=N [--dry-run]" };
1762
+ }
1763
+ return { messages, dryRun };
1764
+ }
1765
+ function parseCleanArgs(args) {
1766
+ let staleDays = 90;
1767
+ let dryRun = false;
1768
+ for (let i = 1; i < args.length; i++) {
1769
+ if (args[i] === "--stale" && i + 1 < args.length) {
1770
+ const n = Number(args[++i]);
1771
+ if (Number.isFinite(n) && n > 0) staleDays = n;
1772
+ } else if (args[i] === "--dry-run") {
1773
+ dryRun = true;
1774
+ }
1775
+ }
1776
+ return { staleDays, dryRun };
1777
+ }
1778
+ function selectStaleSessions(sessions, staleDays, now = Date.now()) {
1779
+ const cutoff = now - staleDays * 24 * 60 * 60 * 1e3;
1780
+ return sessions.filter((s) => s.updated.getTime() < cutoff);
1781
+ }
1782
+
1385
1783
  // src/core/profile-command.ts
1386
1784
  var PROFILE_FIELDS = ["name", "nickname", "role", "bio", "interests", "locale", "extra"];
1387
1785
  function stripSurroundingQuotes(value) {
@@ -1543,6 +1941,24 @@ function costSourceNote(source) {
1543
1941
 
1544
1942
  export {
1545
1943
  applyThinkCommand,
1944
+ resolveProviderSwitch,
1945
+ parseModelCommand,
1946
+ resolveModelSwitch,
1947
+ applyPlanCommand,
1948
+ parseRouteCommand,
1949
+ routingEmptyRulesNote,
1950
+ describeRouting,
1951
+ routeDecisionRows,
1952
+ parseSessionListArgs,
1953
+ sessionListNeedsFileSize,
1954
+ selectSessions,
1955
+ sessionListSummary,
1956
+ sessionListJsonRow,
1957
+ resolveSessionRef,
1958
+ formatSessionSummaryLine,
1959
+ parseBatchDeleteArgs,
1960
+ parseCleanArgs,
1961
+ selectStaleSessions,
1546
1962
  applyProfileCommand,
1547
1963
  readGitDiff,
1548
1964
  scanDirTree,
@@ -6,7 +6,7 @@ import {
6
6
  MEMORY_FILE_NAME,
7
7
  MEMORY_MAX_CHARS,
8
8
  MEMORY_STORE_FILE_NAME
9
- } from "./chunk-Z752LDYF.js";
9
+ } from "./chunk-5XHEXRMN.js";
10
10
  import {
11
11
  atomicWriteFileSync
12
12
  } from "./chunk-6BUTA5VW.js";
@@ -11,7 +11,7 @@ import {
11
11
  searchPersistentMemories,
12
12
  touchMemoryReferences,
13
13
  updateMemoryEntry
14
- } from "./chunk-7BO5H2QI.js";
14
+ } from "./chunk-6WMT7OQG.js";
15
15
  import {
16
16
  indexProject
17
17
  } from "./chunk-4DEMGCK4.js";
@@ -30,7 +30,7 @@ import {
30
30
  runHook,
31
31
  runLifecycleHooks,
32
32
  runTool
33
- } from "./chunk-UWQCTTP4.js";
33
+ } from "./chunk-IIXZ7IPN.js";
34
34
  import {
35
35
  buildTruncatedArgumentsError,
36
36
  getDangerLevel,
@@ -50,14 +50,14 @@ import {
50
50
  } from "./chunk-4BKXL7SM.js";
51
51
  import {
52
52
  runTestsTool
53
- } from "./chunk-3VFOXEIL.js";
53
+ } from "./chunk-NZPHEUJM.js";
54
54
  import {
55
55
  CONFIG_DIR_NAME,
56
56
  DEFAULT_MAX_TOOL_OUTPUT_CHARS_CAP,
57
57
  SUBAGENT_ALLOWED_TOOLS,
58
58
  SUBAGENT_DEFAULT_MAX_ROUNDS,
59
59
  SUBAGENT_MAX_ROUNDS_LIMIT
60
- } from "./chunk-ZP3RCZKM.js";
60
+ } from "./chunk-2BKRWTEQ.js";
61
61
 
62
62
  // src/tools/shell-pool.ts
63
63
  import { spawn as spawn2 } from "child_process";
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  CONFIG_DIR_NAME,
7
7
  PLUGINS_DIR_NAME
8
- } from "./chunk-ZP3RCZKM.js";
8
+ } from "./chunk-2BKRWTEQ.js";
9
9
 
10
10
  // src/diagnostics/tool-stats.ts
11
11
  import { existsSync, readFileSync, mkdirSync } from "fs";
@@ -8,13 +8,13 @@ import {
8
8
  listHooks,
9
9
  listInstalledPlugins,
10
10
  resetStats
11
- } from "./chunk-UWQCTTP4.js";
11
+ } from "./chunk-IIXZ7IPN.js";
12
12
  import {
13
13
  ProviderRegistry
14
14
  } from "./chunk-UGY5SVNX.js";
15
15
  import {
16
16
  ConfigManager
17
- } from "./chunk-OCOGYIRY.js";
17
+ } from "./chunk-UD3BVNC5.js";
18
18
  import {
19
19
  getGitRoot
20
20
  } from "./chunk-HOSJZMQS.js";
@@ -26,7 +26,7 @@ import {
26
26
  MCP_PROJECT_CONFIG_NAME,
27
27
  MEMORY_FILE_NAME,
28
28
  VERSION
29
- } from "./chunk-ZP3RCZKM.js";
29
+ } from "./chunk-2BKRWTEQ.js";
30
30
 
31
31
  // src/diagnostics/doctor-report.ts
32
32
  import { existsSync as existsSync3, statSync as statSync2 } from "fs";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  evaluateCiGate,
4
4
  normalizeCiThresholds
5
- } from "./chunk-HCF442WL.js";
5
+ } from "./chunk-RJY3HJS4.js";
6
6
  import {
7
7
  buildReviewPrompt,
8
8
  buildSecurityReviewPrompt,
@@ -16,10 +16,10 @@ import {
16
16
  } from "./chunk-UGY5SVNX.js";
17
17
  import {
18
18
  ConfigManager
19
- } from "./chunk-OCOGYIRY.js";
19
+ } from "./chunk-UD3BVNC5.js";
20
20
  import {
21
21
  VERSION
22
- } from "./chunk-ZP3RCZKM.js";
22
+ } from "./chunk-2BKRWTEQ.js";
23
23
 
24
24
  // src/cli/ci.ts
25
25
  import { execFileSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-ZP3RCZKM.js";
4
+ } from "./chunk-2BKRWTEQ.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION
4
- } from "./chunk-ZP3RCZKM.js";
4
+ } from "./chunk-2BKRWTEQ.js";
5
5
 
6
6
  // src/cli/ci-format.ts
7
7
  var DEFAULT_CI_THRESHOLDS = {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TEST_TIMEOUT
3
- } from "./chunk-Z752LDYF.js";
3
+ } from "./chunk-5XHEXRMN.js";
4
4
 
5
5
  // src/tools/builtin/run-tests.ts
6
6
  import { execSync, spawnSync } from "child_process";
@@ -11,7 +11,7 @@ import {
11
11
  CONFIG_FILE_NAME,
12
12
  HISTORY_DIR_NAME,
13
13
  PLUGINS_DIR_NAME
14
- } from "./chunk-ZP3RCZKM.js";
14
+ } from "./chunk-2BKRWTEQ.js";
15
15
 
16
16
  // src/config/config-manager.ts
17
17
  import { readFileSync, existsSync, mkdirSync } from "fs";
@@ -3,16 +3,16 @@ import {
3
3
  CI_COMMENT_MARKER,
4
4
  countSeverity,
5
5
  runCi
6
- } from "./chunk-I3PYD2YN.js";
7
- import "./chunk-HCF442WL.js";
6
+ } from "./chunk-JS6VAPWM.js";
7
+ import "./chunk-RJY3HJS4.js";
8
8
  import "./chunk-HLWUDRBO.js";
9
9
  import "./chunk-6YZEZFX5.js";
10
10
  import "./chunk-UGY5SVNX.js";
11
- import "./chunk-OCOGYIRY.js";
11
+ import "./chunk-UD3BVNC5.js";
12
12
  import "./chunk-TEXT4DAT.js";
13
13
  import "./chunk-TU3L3PW7.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
- import "./chunk-ZP3RCZKM.js";
15
+ import "./chunk-2BKRWTEQ.js";
16
16
  export {
17
17
  CI_COMMENT_MARKER,
18
18
  countSeverity,
@@ -6,8 +6,8 @@ import {
6
6
  formatCiResult,
7
7
  formatCiSarif,
8
8
  normalizeCiThresholds
9
- } from "./chunk-HCF442WL.js";
10
- import "./chunk-ZP3RCZKM.js";
9
+ } from "./chunk-RJY3HJS4.js";
10
+ import "./chunk-2BKRWTEQ.js";
11
11
  export {
12
12
  DEFAULT_CI_THRESHOLDS,
13
13
  detectCiGateSignals,
@@ -38,7 +38,7 @@ import {
38
38
  TEST_TIMEOUT,
39
39
  VERSION,
40
40
  buildUserIdentityPrompt
41
- } from "./chunk-ZP3RCZKM.js";
41
+ } from "./chunk-2BKRWTEQ.js";
42
42
  export {
43
43
  AGENTIC_BEHAVIOR_GUIDELINE,
44
44
  APP_NAME,