jinzd-ai-cli 0.4.278 → 0.4.280

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-7Y4NAA6N.js → batch-F27NOTWC.js} +2 -2
  2. package/dist/{chunk-LTZFUYBT.js → chunk-B3FHA6IN.js} +3 -3
  3. package/dist/{chunk-WOXIKQRI.js → chunk-CP5LAA52.js} +4 -4
  4. package/dist/{chunk-2BYQP6JX.js → chunk-EOP775JU.js} +1 -1
  5. package/dist/{chunk-JJCNNQTU.js → chunk-IIO2SMEJ.js} +354 -3
  6. package/dist/{chunk-H7QC5VMQ.js → chunk-LPZNOYRJ.js} +1 -1
  7. package/dist/{chunk-LOXEYWC3.js → chunk-NHJ4GHL4.js} +1 -1
  8. package/dist/{chunk-SJCOE4C7.js → chunk-PN42JO74.js} +1 -1
  9. package/dist/{chunk-LXXQTWT2.js → chunk-PUC277TH.js} +1 -1
  10. package/dist/{chunk-4Z6GAYB5.js → chunk-TAIZZY3N.js} +3 -3
  11. package/dist/{chunk-X3722RFA.js → chunk-UBPRUSAF.js} +1 -1
  12. package/dist/{chunk-L3CPM472.js → chunk-UMWDNNPS.js} +1 -1
  13. package/dist/{chunk-RFSKPCYC.js → chunk-V7EZ4SDC.js} +1 -1
  14. package/dist/{chunk-SB4XONS4.js → chunk-VQCFEA4Z.js} +1 -1
  15. package/dist/{ci-WDF2CYR4.js → ci-HJ4OVHCM.js} +4 -4
  16. package/dist/{ci-format-7B5VAZGA.js → ci-format-NKJRZ3QI.js} +2 -2
  17. package/dist/{constants-DC3TNLTL.js → constants-6LCZOBJC.js} +1 -1
  18. package/dist/{doctor-cli-CDDG5XOY.js → doctor-cli-7JGPC5G4.js} +4 -4
  19. package/dist/electron-server.js +525 -140
  20. package/dist/{hub-TO7ODOIA.js → hub-NX7HYN7V.js} +1 -1
  21. package/dist/index.js +151 -429
  22. package/dist/{persistent-memory-JCENBMCJ.js → persistent-memory-E6WECUTW.js} +2 -2
  23. package/dist/{persistent-memory-BU63CSGK.js → persistent-memory-MHHX7F25.js} +2 -2
  24. package/dist/{pr-GVSZYX6I.js → pr-GLUFBQLI.js} +4 -4
  25. package/dist/{run-tests-2Q5MJHXB.js → run-tests-LWAFPVS3.js} +2 -2
  26. package/dist/{run-tests-R4IQS6IF.js → run-tests-YPJDOEJA.js} +2 -2
  27. package/dist/{server-KAURBKFI.js → server-CXXYIPMU.js} +226 -145
  28. package/dist/{server-WXLE53HG.js → server-P6DI27CY.js} +5 -5
  29. package/dist/{task-orchestrator-RJ6FXYY5.js → task-orchestrator-FW4LBPTS.js} +5 -5
  30. package/dist/{usage-V3R7DA7M.js → usage-CJUHQDT2.js} +2 -2
  31. package/dist/web/client/app.js +14 -2
  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
package/dist/index.js CHANGED
@@ -11,6 +11,11 @@ import {
11
11
  autoTrimSessionIfNeeded,
12
12
  buildInitPrompt,
13
13
  buildSessionCostReport,
14
+ buildSessionExport,
15
+ checkpointDeletedMessage,
16
+ checkpointNotFoundMessage,
17
+ checkpointRestoredMessage,
18
+ checkpointSavedMessage,
14
19
  clearDevState,
15
20
  costSourceNote,
16
21
  decideDeferredSave,
@@ -19,24 +24,36 @@ import {
19
24
  estimateConversationTokens,
20
25
  evaluateContextPressure,
21
26
  filterMemoryEntries,
27
+ formatCheckpointList,
28
+ formatSessionSummaryLine,
22
29
  loadDevState,
30
+ parseBatchDeleteArgs,
31
+ parseCheckpointCommand,
32
+ parseCleanArgs,
33
+ parseExportArgs,
23
34
  parseMemoryShowFilters,
24
35
  parseModelCommand,
25
36
  parseRouteCommand,
37
+ parseSessionListArgs,
26
38
  parseSimpleYaml,
27
39
  persistToolRound,
28
40
  readGitDiff,
29
41
  resolveModelSwitch,
30
42
  resolveProviderSwitch,
43
+ resolveSessionRef,
31
44
  routeDecisionRows,
32
45
  routingEmptyRulesNote,
33
46
  saveDevState,
34
47
  scanProject,
48
+ selectSessions,
49
+ selectStaleSessions,
35
50
  sessionHasMeaningfulContent,
51
+ sessionListJsonRow,
52
+ sessionListSummary,
36
53
  setupProxy,
37
54
  snapshotFile,
38
55
  stripRoutingTags
39
- } from "./chunk-JJCNNQTU.js";
56
+ } from "./chunk-IIO2SMEJ.js";
40
57
  import {
41
58
  CostTracker,
42
59
  computeCost,
@@ -66,7 +83,7 @@ import {
66
83
  setMaxOutputCap,
67
84
  spawnAgentContext,
68
85
  undoStack
69
- } from "./chunk-WOXIKQRI.js";
86
+ } from "./chunk-CP5LAA52.js";
70
87
  import {
71
88
  buildReviewPrompt,
72
89
  buildSecurityReviewPrompt
@@ -107,7 +124,7 @@ import {
107
124
  touchMemoryReferences,
108
125
  updateMemoryApproval,
109
126
  updateMemoryEntry
110
- } from "./chunk-RFSKPCYC.js";
127
+ } from "./chunk-V7EZ4SDC.js";
111
128
  import "./chunk-4DEMGCK4.js";
112
129
  import "./chunk-UUSRWSSX.js";
113
130
  import "./chunk-CKH4KQ4E.js";
@@ -131,7 +148,7 @@ import {
131
148
  formatDoctorReport,
132
149
  loadContextFiles,
133
150
  writeCrashLog
134
- } from "./chunk-LTZFUYBT.js";
151
+ } from "./chunk-B3FHA6IN.js";
135
152
  import {
136
153
  describePlugin,
137
154
  getActivePluginAssets,
@@ -148,14 +165,14 @@ import {
148
165
  trustHook,
149
166
  trustPlugin,
150
167
  untrustHook
151
- } from "./chunk-L3CPM472.js";
168
+ } from "./chunk-UMWDNNPS.js";
152
169
  import {
153
170
  ProviderRegistry,
154
171
  listBuiltInProviderMetadata
155
172
  } from "./chunk-UGY5SVNX.js";
156
173
  import {
157
174
  ConfigManager
158
- } from "./chunk-2BYQP6JX.js";
175
+ } from "./chunk-EOP775JU.js";
159
176
  import {
160
177
  CONTENT_ONLY_STREAM_REMINDER,
161
178
  TEE_FINAL_USER_NUDGE,
@@ -193,7 +210,7 @@ import {
193
210
  import {
194
211
  fileCheckpoints
195
212
  } from "./chunk-4BKXL7SM.js";
196
- import "./chunk-SB4XONS4.js";
213
+ import "./chunk-VQCFEA4Z.js";
197
214
  import {
198
215
  AGENTIC_BEHAVIOR_GUIDELINE,
199
216
  AUTHOR,
@@ -211,7 +228,7 @@ import {
211
228
  SKILLS_DIR_NAME,
212
229
  VERSION,
213
230
  buildUserIdentityPrompt
214
- } from "./chunk-X3722RFA.js";
231
+ } from "./chunk-UBPRUSAF.js";
215
232
 
216
233
  // src/index.ts
217
234
  import { program } from "commander";
@@ -730,7 +747,6 @@ import { platform } from "os";
730
747
 
731
748
  // src/repl/commands/constants.ts
732
749
  var SESSION_PAGE_SIZE = 20;
733
- var DEFAULT_SESSION_LIST_LIMIT = 50;
734
750
  var MAX_TITLE_WIDTH = 40;
735
751
 
736
752
  // src/repl/commands/utils.ts
@@ -809,73 +825,6 @@ function formatSessionDate(date) {
809
825
  if (diffDays < 7) return `${abs} (${diffDays} days ago)`;
810
826
  return abs;
811
827
  }
812
- function parseSessionListArgs(args) {
813
- let limit = DEFAULT_SESSION_LIST_LIMIT;
814
- let all = false;
815
- const filter = {};
816
- const warnings = [];
817
- let search = null;
818
- let days = null;
819
- let since = null;
820
- let sort = { field: "updated", order: "desc" };
821
- let json = false;
822
- let stale = null;
823
- let verbose = false;
824
- for (let i = 1; i < args.length; i++) {
825
- const a = args[i];
826
- if (a === "--all" || a === "-a") {
827
- all = true;
828
- } else if ((a === "--limit" || a === "-n") && i + 1 < args.length) {
829
- const n = Number(args[i + 1]);
830
- if (Number.isFinite(n) && n > 0) {
831
- limit = n;
832
- i++;
833
- }
834
- } else if (a === "--filter" && i + 1 < args.length) {
835
- const val = args[++i];
836
- const eq = val.indexOf("=");
837
- if (eq > 0) {
838
- const key = val.slice(0, eq);
839
- const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
840
- if (key === "provider") filter.provider = vals;
841
- else if (key === "model") filter.model = vals;
842
- else if (key === "messages") {
843
- const n = Number(vals[0]);
844
- if (Number.isFinite(n) && n >= 0) filter.messages = n;
845
- else warnings.push(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
846
- } else {
847
- warnings.push(`Unknown filter key: "${key}". Supported keys: provider, model, messages`);
848
- }
849
- } else {
850
- warnings.push(`Invalid --filter syntax: "${val}". Expected key=value`);
851
- }
852
- } else if ((a === "--search" || a === "-s") && i + 1 < args.length) {
853
- search = args[++i];
854
- } else if (a === "--days" && i + 1 < args.length) {
855
- const n = Number(args[++i]);
856
- if (Number.isFinite(n) && n > 0) days = n;
857
- } else if (a === "--since" && i + 1 < args.length) {
858
- since = args[++i];
859
- } else if (a === "--sort" && i + 1 < args.length) {
860
- const sv = args[++i];
861
- const colon = sv.indexOf(":");
862
- const field = colon > 0 ? sv.slice(0, colon) : sv;
863
- const order = colon > 0 ? sv.slice(colon + 1) : "desc";
864
- if (field === "updated" || field === "created" || field === "messages" || field === "size") {
865
- sort = { field, order: order === "asc" ? "asc" : "desc" };
866
- }
867
- } else if (a === "--json") {
868
- json = true;
869
- } else if (a === "--verbose" || a === "-v") {
870
- verbose = true;
871
- } else if (a === "--stale" && i + 1 < args.length) {
872
- const n = Number(args[++i]);
873
- if (Number.isFinite(n) && n > 0) stale = n;
874
- }
875
- }
876
- if (all) limit = -1;
877
- return { limit, all, filter, search, days, since, sort, json, stale, verbose, warnings };
878
- }
879
828
  function renderTranscriptMessage(msg, renderer) {
880
829
  if (msg.role === "user") {
881
830
  const text = getContentText(msg.content);
@@ -1397,7 +1346,7 @@ No tools match "${filter}".
1397
1346
  const { join: join6 } = await import("path");
1398
1347
  const { existsSync: existsSync6 } = await import("fs");
1399
1348
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1400
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-DC3TNLTL.js");
1349
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-6LCZOBJC.js");
1401
1350
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1402
1351
  const cwd = process.cwd();
1403
1352
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2317,7 +2266,7 @@ function createReviewCommands() {
2317
2266
  usage: "/test [command|filter]",
2318
2267
  async execute(args, ctx) {
2319
2268
  try {
2320
- const { executeTests } = await import("./run-tests-R4IQS6IF.js");
2269
+ const { executeTests } = await import("./run-tests-YPJDOEJA.js");
2321
2270
  const argStr = args.join(" ").trim();
2322
2271
  let testArgs = {};
2323
2272
  if (argStr) {
@@ -3081,7 +3030,7 @@ function createSessionCommands() {
3081
3030
  {
3082
3031
  name: "session",
3083
3032
  description: "Session management",
3084
- usage: "/session new|list [--limit N|--all] [--filter provider=|model=|messages=N] [--search kw] [--days N|--stale N] [--sort f[:o]] [--json] [--verbose]|load <id>|show <id> [page]|page <n>|remove <id>|clean --stale N [--dry-run]",
3033
+ usage: "/session new|list [--limit N|--all] [--filter provider=|model=|messages=N] [--search kw] [--days N|--stale N] [--sort f[:o]] [--json] [--verbose]|load <id>|show <id> [page]|page <n>|rename <id> <title>|remove <id>|clean --stale N [--dry-run]",
3085
3034
  async execute(args, ctx) {
3086
3035
  const sub = args[0];
3087
3036
  if (sub === "new") {
@@ -3093,139 +3042,44 @@ function createSessionCommands() {
3093
3042
  ctx.renderer.printSuccess("New session started.");
3094
3043
  } else if (sub === "list") {
3095
3044
  const opts = parseSessionListArgs(args);
3096
- for (const w of opts.warnings) {
3097
- ctx.renderer.printInfo(`\u26A0 ${w}`);
3098
- }
3099
- const needFileSize = opts.verbose || opts.sort.field === "size";
3100
- let allSessions = ctx.sessions.listSessions({ includeFileSize: needFileSize });
3101
- if (allSessions.length === 0) {
3045
+ for (const w of opts.warnings) ctx.renderer.printInfo(`\u26A0 ${w}`);
3046
+ const all = ctx.sessions.listSessions({ includeFileSize: opts.verbose || opts.sort.field === "size" });
3047
+ if (all.length === 0) {
3102
3048
  ctx.renderer.printInfo("No saved sessions.");
3103
3049
  return;
3104
3050
  }
3105
- const hasFilters = opts.filter.provider || opts.filter.model || opts.filter.messages !== void 0;
3106
- const hasSearch = !!opts.search;
3107
- const hasTimeFilter = opts.days !== null || opts.since !== null;
3108
- const hasStale = opts.stale !== null;
3109
- if (hasFilters) {
3110
- const p = opts.filter.provider;
3111
- const m = opts.filter.model;
3112
- const msg = opts.filter.messages;
3113
- allSessions = allSessions.filter((s) => {
3114
- if (p && !p.includes(s.provider.toLowerCase())) return false;
3115
- if (m && !m.some((kw) => s.model.toLowerCase().includes(kw))) return false;
3116
- if (msg !== void 0 && s.messageCount !== msg) return false;
3117
- return true;
3118
- });
3119
- }
3120
- if (hasSearch) {
3121
- const q = opts.search.toLowerCase();
3122
- allSessions = allSessions.filter(
3123
- (s) => (s.title ?? "").toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
3124
- );
3125
- }
3126
- if (hasTimeFilter) {
3127
- const now = Date.now();
3128
- let cutoff = 0;
3129
- if (opts.since) {
3130
- cutoff = new Date(opts.since).getTime();
3131
- } else if (opts.days !== null) {
3132
- cutoff = now - opts.days * 24 * 60 * 60 * 1e3;
3133
- }
3134
- if (!isNaN(cutoff)) {
3135
- allSessions = allSessions.filter((s) => s.updated.getTime() >= cutoff);
3136
- }
3137
- }
3138
- const staleCutoff = hasStale ? Date.now() - opts.stale * 24 * 60 * 60 * 1e3 : 0;
3139
- if (hasStale) {
3140
- allSessions = allSessions.filter((s) => s.updated.getTime() < staleCutoff);
3141
- }
3142
- const defaultSort = opts.sort.field === "updated" && opts.sort.order === "desc";
3143
- if (!defaultSort) {
3144
- const mul = opts.sort.order === "asc" ? 1 : -1;
3145
- allSessions = [...allSessions].sort((a, b) => {
3146
- switch (opts.sort.field) {
3147
- case "created":
3148
- return (a.created.getTime() - b.created.getTime()) * mul;
3149
- case "messages":
3150
- return (a.messageCount - b.messageCount) * mul;
3151
- case "size":
3152
- return ((a.fileSize ?? 0) - (b.fileSize ?? 0)) * mul;
3153
- default:
3154
- return (a.updated.getTime() - b.updated.getTime()) * mul;
3155
- }
3156
- });
3157
- }
3158
- const totalCount = allSessions.length;
3159
- if (totalCount === 0) {
3051
+ const view = selectSessions(all, opts);
3052
+ if (view.totalCount === 0) {
3160
3053
  ctx.renderer.printInfo("No sessions match the filter criteria.");
3161
3054
  return;
3162
3055
  }
3163
3056
  if (opts.json) {
3164
- const sliced2 = opts.limit > 0 ? allSessions.slice(0, opts.limit) : allSessions;
3165
- const payload = sliced2.map((s) => ({
3166
- id: s.id,
3167
- title: s.title ?? null,
3168
- provider: s.provider,
3169
- model: s.model,
3170
- messageCount: s.messageCount,
3171
- created: s.created.toISOString(),
3172
- updated: s.updated.toISOString(),
3173
- ...needFileSize ? { fileSize: s.fileSize } : {},
3174
- ...s.branchCount !== void 0 ? { branchCount: s.branchCount, activeBranch: s.activeBranch } : {}
3175
- }));
3176
- console.log(JSON.stringify(payload, null, 2));
3177
- if (opts.limit > 0 && totalCount > opts.limit) {
3057
+ console.log(JSON.stringify(view.shown.map((s) => sessionListJsonRow(s, view.needsFileSize)), null, 2));
3058
+ if (view.shown.length < view.totalCount) {
3178
3059
  console.error(
3179
3060
  `
3180
- (truncated: ${opts.limit} of ${totalCount} sessions shown; use --all for full list)`
3061
+ (truncated: ${view.shown.length} of ${view.totalCount} sessions shown; use --all for full list)`
3181
3062
  );
3182
3063
  }
3183
3064
  return;
3184
3065
  }
3185
- const sliced = opts.limit > 0 ? allSessions.slice(0, opts.limit) : allSessions;
3186
3066
  const headers = ["ID (short)", "Provider", "Model", "Messages"];
3187
- if (opts.verbose) {
3188
- headers.push("Size");
3189
- headers.push("Br");
3190
- }
3067
+ if (opts.verbose) headers.push("Size", "Br");
3191
3068
  headers.push("Date", "Title");
3192
- const rows = sliced.map((s) => {
3193
- const isStale = hasStale ? s.updated.getTime() < staleCutoff : false;
3069
+ const rows = view.shown.map((s) => {
3070
+ const isStale = view.staleCutoff !== null && s.updated.getTime() < view.staleCutoff;
3194
3071
  const dim = isStale ? theme.dim : (x) => String(x);
3195
- const row = [
3196
- dim(s.id.slice(0, 8)),
3197
- dim(s.provider),
3198
- dim(s.model),
3199
- s.messageCount
3200
- ];
3072
+ const row = [dim(s.id.slice(0, 8)), dim(s.provider), dim(s.model), s.messageCount];
3201
3073
  if (opts.verbose) {
3202
- row.push(
3203
- s.fileSize !== void 0 ? formatFileSize(s.fileSize) : "\u2014",
3204
- s.branchCount ?? 1
3205
- );
3074
+ row.push(s.fileSize !== void 0 ? formatFileSize(s.fileSize) : "\u2014", s.branchCount ?? 1);
3206
3075
  }
3207
- row.push(
3208
- formatSessionDate(s.updated),
3209
- dim(truncateTitle(s.title ?? "(untitled)", MAX_TITLE_WIDTH))
3210
- );
3076
+ row.push(formatSessionDate(s.updated), dim(truncateTitle(s.title ?? "(untitled)", MAX_TITLE_WIDTH)));
3211
3077
  return row;
3212
3078
  });
3213
3079
  console.log();
3214
3080
  ctx.renderer.printTable(headers, rows);
3215
- const totalMessages = allSessions.reduce((sum, s) => sum + s.messageCount, 0);
3216
- const shown = sliced.length;
3217
- const filterHints = [];
3218
- if (hasFilters) filterHints.push("filtered");
3219
- if (hasSearch) filterHints.push("searched");
3220
- if (hasTimeFilter) filterHints.push("time-limited");
3221
- if (hasStale) filterHints.push(`stale >${opts.stale}d`);
3222
- const filterTag = filterHints.length > 0 ? ` (${filterHints.join(", ")})` : "";
3223
- console.log(
3224
- theme.dim(
3225
- ` \u2500\u2500 ${shown} of ${totalCount} sessions${filterTag} \xB7 ${totalMessages} messages total`
3226
- )
3227
- );
3228
- if (shown < totalCount) {
3081
+ console.log(theme.dim(` \u2500\u2500 ${sessionListSummary(view)}`));
3082
+ if (view.shown.length < view.totalCount) {
3229
3083
  console.log(theme.dim(` Use --all to show all, or --limit N to change count.`));
3230
3084
  }
3231
3085
  } else if (sub === "load" || sub === "show") {
@@ -3234,19 +3088,18 @@ function createSessionCommands() {
3234
3088
  ctx.renderer.renderError(`Usage: /session ${sub} <id>${sub === "show" ? " [page]" : ""}`);
3235
3089
  return;
3236
3090
  }
3237
- const sessions = ctx.sessions.listSessions();
3238
- const matches = sessions.filter((s) => s.id.startsWith(id));
3239
- if (matches.length === 0) {
3240
- ctx.renderer.renderError(`Session '${id}' not found.`);
3091
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "most-recent");
3092
+ if (ref.status !== "ok") {
3093
+ ctx.renderer.renderError(ref.message);
3241
3094
  return;
3242
3095
  }
3243
- if (matches.length > 1) {
3244
- console.log(theme.warning(` \u26A0 Ambiguous prefix '${id}' matches ${matches.length} sessions \u2014 loading most recent:`));
3245
- for (const m of matches.slice(0, 5)) {
3096
+ if (ref.message) {
3097
+ console.log(theme.warning(` ${ref.message}`));
3098
+ for (const m of ref.ambiguousWith.slice(0, 5)) {
3246
3099
  console.log(theme.dim(` ${m.id.slice(0, 12)} ${m.title ?? "(untitled)"}`));
3247
3100
  }
3248
3101
  }
3249
- const match = matches[0];
3102
+ const match = ref.match;
3250
3103
  ctx.sessions.loadSession(match.id);
3251
3104
  ctx.setProvider(match.provider, match.model);
3252
3105
  ctx.resetSessionTokenUsage();
@@ -3270,70 +3123,54 @@ function createSessionCommands() {
3270
3123
  return;
3271
3124
  }
3272
3125
  renderTranscriptPage(cur.messages, ctx.renderer, n);
3126
+ } else if (sub === "rename") {
3127
+ const id = args[1];
3128
+ const newTitle = args.slice(2).join(" ").trim();
3129
+ if (!id || !newTitle) {
3130
+ ctx.renderer.renderError("Usage: /session rename <id> <new title>");
3131
+ return;
3132
+ }
3133
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "strict");
3134
+ if (ref.status !== "ok") {
3135
+ ctx.renderer.renderError(ref.message);
3136
+ if (ref.status === "ambiguous") {
3137
+ for (const m of ref.matches.slice(0, 10)) console.log(theme.dim(` ${formatSessionSummaryLine(m)}`));
3138
+ }
3139
+ return;
3140
+ }
3141
+ const priorId = ctx.sessions.current?.id ?? null;
3142
+ const isCurrent = priorId === ref.match.id;
3143
+ const session = isCurrent ? ctx.sessions.current : ctx.sessions.loadSession(ref.match.id);
3144
+ session.title = newTitle;
3145
+ await ctx.sessions.save();
3146
+ if (!isCurrent && priorId) {
3147
+ ctx.sessions.loadSession(priorId);
3148
+ }
3149
+ ctx.renderer.printSuccess(`Renamed session ${ref.match.id.slice(0, 8)}: "${newTitle}"`);
3273
3150
  } else if (sub === "remove" || sub === "delete") {
3274
3151
  if (args[1] === "--filter") {
3275
- let filterMessages;
3276
- let dryRun = false;
3277
- for (let i = 1; i < args.length; i++) {
3278
- if (args[i] === "--filter" && i + 1 < args.length) {
3279
- const val = args[++i];
3280
- const eq = val.indexOf("=");
3281
- if (eq > 0) {
3282
- const key = val.slice(0, eq);
3283
- const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
3284
- if (key === "messages") {
3285
- const n = Number(vals[0]);
3286
- if (Number.isFinite(n) && n >= 0) filterMessages = n;
3287
- else {
3288
- ctx.renderer.renderError(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
3289
- return;
3290
- }
3291
- } else {
3292
- ctx.renderer.renderError(`Unsupported filter key for remove: "${key}". Only "messages" is supported.`);
3293
- return;
3294
- }
3295
- } else {
3296
- ctx.renderer.renderError(`Invalid --filter syntax: "${val}". Expected key=value (e.g., messages=0)`);
3297
- return;
3298
- }
3299
- } else if (args[i] === "--dry-run") {
3300
- dryRun = true;
3301
- }
3302
- }
3303
- if (filterMessages === void 0) {
3304
- ctx.renderer.renderError("Usage: /session remove --filter messages=N [--dry-run]");
3152
+ const opts = parseBatchDeleteArgs(args);
3153
+ if (opts.error) {
3154
+ ctx.renderer.renderError(opts.error);
3305
3155
  return;
3306
3156
  }
3307
- const allSessions = ctx.sessions.listSessions();
3308
- const matches2 = allSessions.filter((s) => s.messageCount === filterMessages);
3309
- if (matches2.length === 0) {
3310
- ctx.renderer.printInfo(`No sessions with ${filterMessages} message(s) found.`);
3157
+ const matches = ctx.sessions.listSessions().filter((s) => s.messageCount === opts.messages);
3158
+ if (matches.length === 0) {
3159
+ ctx.renderer.printInfo(`No sessions with ${opts.messages} message(s) found.`);
3311
3160
  return;
3312
3161
  }
3313
3162
  console.log();
3314
- console.log(
3315
- theme.warning(` Found ${matches2.length} session(s) with ${filterMessages} message(s):`)
3316
- );
3317
- for (const s of matches2.slice(0, 20)) {
3318
- console.log(
3319
- theme.dim(
3320
- ` ${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)}`
3321
- )
3322
- );
3323
- }
3324
- if (matches2.length > 20) {
3325
- console.log(theme.dim(` ... and ${matches2.length - 20} more`));
3326
- }
3327
- if (dryRun) {
3328
- console.log(
3329
- theme.info(`
3330
- --dry-run: no sessions were deleted. Remove --dry-run to actually delete.`)
3331
- );
3163
+ console.log(theme.warning(` Found ${matches.length} session(s) with ${opts.messages} message(s):`));
3164
+ for (const s of matches.slice(0, 20)) console.log(theme.dim(` ${formatSessionSummaryLine(s)}`));
3165
+ if (matches.length > 20) console.log(theme.dim(` ... and ${matches.length - 20} more`));
3166
+ if (opts.dryRun) {
3167
+ console.log(theme.info(`
3168
+ --dry-run: no sessions were deleted. Remove --dry-run to actually delete.`));
3332
3169
  return;
3333
3170
  }
3334
3171
  console.log();
3335
3172
  const choice2 = await ctx.select(
3336
- `Delete all ${matches2.length} matching sessions?`,
3173
+ `Delete all ${matches.length} matching sessions?`,
3337
3174
  [
3338
3175
  { label: "No \u2014 keep them", value: "no" },
3339
3176
  { label: "Yes \u2014 delete permanently", value: "yes", hint: "unlinks all matching history files" }
@@ -3345,17 +3182,12 @@ function createSessionCommands() {
3345
3182
  }
3346
3183
  let deleted = 0;
3347
3184
  let failed = 0;
3348
- for (const s of matches2) {
3349
- if (ctx.sessions.deleteSession(s.id)) {
3350
- deleted++;
3351
- } else {
3352
- failed++;
3353
- }
3185
+ for (const s of matches) {
3186
+ if (ctx.sessions.deleteSession(s.id)) deleted++;
3187
+ else failed++;
3354
3188
  }
3355
3189
  const currentStillExists = ctx.sessions.current !== null;
3356
- ctx.renderer.printSuccess(
3357
- `Removed: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`
3358
- );
3190
+ ctx.renderer.printSuccess(`Removed: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`);
3359
3191
  if (!currentStillExists) {
3360
3192
  ctx.sessions.createSession(ctx.getCurrentProvider(), ctx.getCurrentModel());
3361
3193
  ctx.resetSessionTokenUsage();
@@ -3369,20 +3201,15 @@ function createSessionCommands() {
3369
3201
  ctx.renderer.renderError("Usage: /session remove <id> | /session remove --filter messages=N [--dry-run]");
3370
3202
  return;
3371
3203
  }
3372
- const sessions = ctx.sessions.listSessions();
3373
- const matches = sessions.filter((s) => s.id.startsWith(id));
3374
- if (matches.length === 0) {
3375
- ctx.renderer.renderError(`Session '${id}' not found.`);
3376
- return;
3377
- }
3378
- if (matches.length > 1) {
3379
- ctx.renderer.renderError(`Ambiguous prefix '${id}' matches ${matches.length} sessions \u2014 be more specific:`);
3380
- for (const m of matches.slice(0, 10)) {
3381
- console.log(theme.dim(` ${m.id.slice(0, 12)} ${String(m.messageCount).padStart(4)} msgs ${m.updated.toLocaleDateString()} ${m.title ?? "(untitled)"}`));
3204
+ const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "strict");
3205
+ if (ref.status !== "ok") {
3206
+ ctx.renderer.renderError(ref.message);
3207
+ if (ref.status === "ambiguous") {
3208
+ for (const m of ref.matches.slice(0, 10)) console.log(theme.dim(` ${formatSessionSummaryLine(m)}`));
3382
3209
  }
3383
3210
  return;
3384
3211
  }
3385
- const match = matches[0];
3212
+ const match = ref.match;
3386
3213
  const isCurrent = ctx.sessions.current?.id === match.id;
3387
3214
  console.log();
3388
3215
  console.log(theme.warning(" About to permanently delete session (no undo):"));
@@ -3409,44 +3236,19 @@ function createSessionCommands() {
3409
3236
  ctx.renderer.printInfo("Current session was deleted \u2014 started a fresh session.");
3410
3237
  }
3411
3238
  } else if (sub === "clean") {
3412
- let staleDays = 90;
3413
- let dryRun = false;
3414
- for (let i = 1; i < args.length; i++) {
3415
- if (args[i] === "--stale" && i + 1 < args.length) {
3416
- const n = Number(args[++i]);
3417
- if (Number.isFinite(n) && n > 0) staleDays = n;
3418
- } else if (args[i] === "--dry-run") {
3419
- dryRun = true;
3420
- }
3421
- }
3422
- const cutoff = Date.now() - staleDays * 24 * 60 * 60 * 1e3;
3423
- const allSessions = ctx.sessions.listSessions();
3424
- const stale = allSessions.filter((s) => s.updated.getTime() < cutoff);
3239
+ const opts = parseCleanArgs(args);
3240
+ const stale = selectStaleSessions(ctx.sessions.listSessions(), opts.staleDays);
3425
3241
  if (stale.length === 0) {
3426
- ctx.renderer.printInfo(`No sessions older than ${staleDays} days found.`);
3242
+ ctx.renderer.printInfo(`No sessions older than ${opts.staleDays} days found.`);
3427
3243
  return;
3428
3244
  }
3429
3245
  console.log();
3430
- console.log(
3431
- theme.warning(
3432
- ` Found ${stale.length} session(s) not updated in ${staleDays}+ days:`
3433
- )
3434
- );
3435
- for (const s of stale.slice(0, 20)) {
3436
- console.log(
3437
- theme.dim(
3438
- ` ${s.id.slice(0, 12)} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${truncateTitle(s.title ?? "(untitled)", 60)}`
3439
- )
3440
- );
3441
- }
3442
- if (stale.length > 20) {
3443
- console.log(theme.dim(` ... and ${stale.length - 20} more`));
3444
- }
3445
- if (dryRun) {
3446
- console.log(
3447
- theme.info(`
3448
- --dry-run: no sessions were deleted. Remove --dry-run to actually delete.`)
3449
- );
3246
+ console.log(theme.warning(` Found ${stale.length} session(s) not updated in ${opts.staleDays}+ days:`));
3247
+ for (const s of stale.slice(0, 20)) console.log(theme.dim(` ${formatSessionSummaryLine(s)}`));
3248
+ if (stale.length > 20) console.log(theme.dim(` ... and ${stale.length - 20} more`));
3249
+ if (opts.dryRun) {
3250
+ console.log(theme.info(`
3251
+ --dry-run: no sessions were deleted. Remove --dry-run to actually delete.`));
3450
3252
  return;
3451
3253
  }
3452
3254
  console.log();
@@ -3464,17 +3266,12 @@ function createSessionCommands() {
3464
3266
  let deleted = 0;
3465
3267
  let failed = 0;
3466
3268
  for (const s of stale) {
3467
- if (ctx.sessions.deleteSession(s.id)) {
3468
- deleted++;
3469
- } else {
3470
- failed++;
3471
- }
3269
+ if (ctx.sessions.deleteSession(s.id)) deleted++;
3270
+ else failed++;
3472
3271
  }
3473
- ctx.renderer.printSuccess(
3474
- `Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`
3475
- );
3272
+ ctx.renderer.printSuccess(`Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`);
3476
3273
  } else {
3477
- ctx.renderer.renderError("Usage: /session new|list|load <id>|show <id> [page]|page <n>|remove <id>|remove --filter messages=N [--dry-run]|clean --stale N [--dry-run]");
3274
+ ctx.renderer.renderError("Usage: /session new|list|load <id>|show <id> [page]|page <n>|rename <id> <title>|remove <id>|remove --filter messages=N [--dry-run]|clean --stale N [--dry-run]");
3478
3275
  }
3479
3276
  }
3480
3277
  },
@@ -3492,76 +3289,20 @@ function createSessionCommands() {
3492
3289
  description: "Export current session to file or stdout",
3493
3290
  usage: "/export [md|json] [filename]",
3494
3291
  execute(args, ctx) {
3495
- let format = "md";
3496
- let outFile = null;
3497
- for (const arg of args) {
3498
- if (arg === "md" || arg === "json") {
3499
- format = arg;
3500
- } else if (arg) {
3501
- outFile = arg;
3502
- }
3503
- }
3292
+ const { format, outFile } = parseExportArgs(args);
3504
3293
  const session = ctx.sessions.current;
3505
3294
  if (!session || session.messages.length === 0) {
3506
3295
  ctx.renderer.printInfo("No messages to export.");
3507
3296
  return;
3508
3297
  }
3509
- let output;
3510
- if (format === "json") {
3511
- output = JSON.stringify(session.toJSON(), null, 2);
3512
- } else {
3513
- const dateStr = session.created.toISOString().replace("T", " ").slice(0, 19);
3514
- let md = `# Conversation Export
3515
-
3516
- `;
3517
- md += `| Field | Value |
3518
- |----------|-------|
3519
- `;
3520
- md += `| Provider | ${session.provider} |
3521
- `;
3522
- md += `| Model | ${session.model} |
3523
- `;
3524
- md += `| Date | ${dateStr} |
3525
- `;
3526
- md += `| Session | ${session.id.slice(0, 8)} |
3527
-
3528
- ---
3529
-
3530
- `;
3531
- for (const msg of session.messages) {
3532
- const role = msg.role === "user" ? "## \u{1F464} You" : "## \u{1F916} Assistant";
3533
- const text = getContentText(msg.content);
3534
- md += `${role}
3535
-
3536
- ${text}
3537
-
3538
- ---
3539
-
3540
- `;
3541
- }
3542
- output = md;
3543
- }
3544
- if (outFile) {
3545
- const absPath = resolve(process.cwd(), outFile);
3546
- try {
3547
- mkdirSync2(dirname2(absPath), { recursive: true });
3548
- writeFileSync2(absPath, output, "utf-8");
3549
- ctx.renderer.printSuccess(`Exported ${session.messages.length} messages \u2192 ${absPath}`);
3550
- } catch (err) {
3551
- ctx.renderer.renderError(`Failed to write file: ${err instanceof Error ? err.message : String(err)}`);
3552
- }
3553
- } else {
3554
- const shortId = session.id.slice(0, 8);
3555
- const dateTag = session.created.toISOString().slice(0, 10);
3556
- const ext = format === "json" ? "json" : "md";
3557
- const autoName = `session-${dateTag}-${shortId}.${ext}`;
3558
- const absPath = resolve(process.cwd(), autoName);
3559
- try {
3560
- writeFileSync2(absPath, output, "utf-8");
3561
- ctx.renderer.printSuccess(`Exported ${session.messages.length} messages \u2192 ${absPath}`);
3562
- } catch (err) {
3563
- ctx.renderer.renderError(`Failed to write file: ${err instanceof Error ? err.message : String(err)}`);
3564
- }
3298
+ const exported = buildSessionExport(session, format, outFile);
3299
+ const absPath = resolve(process.cwd(), exported.filename);
3300
+ try {
3301
+ mkdirSync2(dirname2(absPath), { recursive: true });
3302
+ writeFileSync2(absPath, exported.content, "utf-8");
3303
+ ctx.renderer.printSuccess(`Exported ${exported.messageCount} messages \u2192 ${absPath}`);
3304
+ } catch (err) {
3305
+ ctx.renderer.renderError(`Failed to write file: ${err instanceof Error ? err.message : String(err)}`);
3565
3306
  }
3566
3307
  }
3567
3308
  },
@@ -3575,59 +3316,40 @@ ${text}
3575
3316
  ctx.renderer.renderError("No active session.");
3576
3317
  return;
3577
3318
  }
3578
- const sub = args[0]?.toLowerCase();
3579
- if (!sub || sub === "list") {
3580
- const cps = ctx.listCheckpoints();
3581
- if (cps.length === 0) {
3582
- console.log(theme.dim(" No checkpoints. Use /checkpoint save <name> to create one."));
3583
- return;
3584
- }
3585
- console.log(theme.dim(` Checkpoints (${cps.length}):`));
3586
- for (const cp of cps) {
3587
- const ts = cp.timestamp.toLocaleString();
3588
- console.log(theme.accent(` ${cp.name.padEnd(20)} `) + theme.dim(`msg #${cp.messageIndex} ${ts}`));
3319
+ const intent = parseCheckpointCommand(args);
3320
+ if (intent.kind === "list") {
3321
+ const lines = formatCheckpointList(ctx.listCheckpoints());
3322
+ console.log(theme.dim(` ${lines[0]}`));
3323
+ for (const line of lines.slice(1)) {
3324
+ const [name, rest] = [line.slice(0, 24), line.slice(24)];
3325
+ console.log(theme.accent(` ${name}`) + theme.dim(rest));
3589
3326
  }
3590
3327
  console.log();
3591
3328
  return;
3592
3329
  }
3593
- const name = args.slice(1).join(" ").trim();
3594
- if (sub === "save") {
3595
- if (!name) {
3596
- ctx.renderer.renderError("Usage: /checkpoint save <name>");
3597
- return;
3598
- }
3599
- ctx.createCheckpoint(name);
3600
- console.log(theme.success(` \u2713 Checkpoint "${name}" saved at message #${session.messages.length}`));
3330
+ if (intent.kind === "usage" || intent.kind === "unknown") {
3331
+ ctx.renderer.renderError(intent.message);
3601
3332
  return;
3602
3333
  }
3603
- if (sub === "restore") {
3604
- if (!name) {
3605
- ctx.renderer.renderError("Usage: /checkpoint restore <name>");
3606
- return;
3607
- }
3608
- const ok = ctx.restoreCheckpoint(name);
3609
- if (ok) {
3610
- ctx.resetSessionTokenUsage();
3611
- console.log(theme.success(` \u2713 Restored to checkpoint "${name}" (${session.messages.length} messages, token usage reset)`));
3612
- } else {
3613
- ctx.renderer.renderError(`Checkpoint "${name}" not found.`);
3614
- }
3334
+ if (intent.kind === "save") {
3335
+ ctx.createCheckpoint(intent.name);
3336
+ console.log(theme.success(` ${checkpointSavedMessage(intent.name, session.messages.length)}`));
3615
3337
  return;
3616
3338
  }
3617
- if (sub === "delete") {
3618
- if (!name) {
3619
- ctx.renderer.renderError("Usage: /checkpoint delete <name>");
3339
+ if (intent.kind === "restore") {
3340
+ if (!ctx.restoreCheckpoint(intent.name)) {
3341
+ ctx.renderer.renderError(checkpointNotFoundMessage(intent.name));
3620
3342
  return;
3621
3343
  }
3622
- const ok = ctx.deleteCheckpoint(name);
3623
- if (ok) {
3624
- console.log(theme.success(` \u2713 Deleted checkpoint "${name}"`));
3625
- } else {
3626
- ctx.renderer.renderError(`Checkpoint "${name}" not found.`);
3627
- }
3344
+ ctx.resetSessionTokenUsage();
3345
+ console.log(theme.success(` ${checkpointRestoredMessage(intent.name, session.messages.length)}`));
3346
+ return;
3347
+ }
3348
+ if (!ctx.deleteCheckpoint(intent.name)) {
3349
+ ctx.renderer.renderError(checkpointNotFoundMessage(intent.name));
3628
3350
  return;
3629
3351
  }
3630
- ctx.renderer.renderError(`Unknown subcommand: ${sub}. Use save/restore/list/delete.`);
3352
+ console.log(theme.success(` ${checkpointDeletedMessage(intent.name)}`));
3631
3353
  }
3632
3354
  },
3633
3355
  // ── /review ──────────────────────────────────────────────────
@@ -7547,7 +7269,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7547
7269
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7548
7270
  process.exit(1);
7549
7271
  }
7550
- const { startWebServer } = await import("./server-KAURBKFI.js");
7272
+ const { startWebServer } = await import("./server-CXXYIPMU.js");
7551
7273
  await startWebServer({ port, host: options.host });
7552
7274
  });
7553
7275
  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) => {
@@ -7714,11 +7436,11 @@ program.command("sessions").description("List recent conversation sessions").opt
7714
7436
  console.log(footer + "\n");
7715
7437
  });
7716
7438
  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) => {
7717
- const { runUsageCli } = await import("./usage-V3R7DA7M.js");
7439
+ const { runUsageCli } = await import("./usage-CJUHQDT2.js");
7718
7440
  await runUsageCli(options);
7719
7441
  });
7720
7442
  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) => {
7721
- const { runDoctorCli } = await import("./doctor-cli-CDDG5XOY.js");
7443
+ const { runDoctorCli } = await import("./doctor-cli-7JGPC5G4.js");
7722
7444
  const argv = process.argv.slice(2);
7723
7445
  await runDoctorCli({
7724
7446
  json: !!options.json || argv.includes("--json"),
@@ -7727,7 +7449,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
7727
7449
  });
7728
7450
  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) => {
7729
7451
  try {
7730
- const batch = await import("./batch-7Y4NAA6N.js");
7452
+ const batch = await import("./batch-F27NOTWC.js");
7731
7453
  switch (action) {
7732
7454
  case "submit":
7733
7455
  if (!arg) {
@@ -7770,7 +7492,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7770
7492
  }
7771
7493
  });
7772
7494
  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) => {
7773
- const { startMcpServer } = await import("./server-WXLE53HG.js");
7495
+ const { startMcpServer } = await import("./server-P6DI27CY.js");
7774
7496
  await startMcpServer({
7775
7497
  allowDestructive: !!options.allowDestructive,
7776
7498
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7783,7 +7505,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7783
7505
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
7784
7506
  process.exit(1);
7785
7507
  }
7786
- const { runPrCli } = await import("./pr-GVSZYX6I.js");
7508
+ const { runPrCli } = await import("./pr-GLUFBQLI.js");
7787
7509
  const result = await runPrCli({
7788
7510
  action,
7789
7511
  target,
@@ -7803,8 +7525,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7803
7525
  process.exit(result.exitCode);
7804
7526
  });
7805
7527
  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) => {
7806
- const { runCi } = await import("./ci-WDF2CYR4.js");
7807
- const { formatCiResult } = await import("./ci-format-7B5VAZGA.js");
7528
+ const { runCi } = await import("./ci-HJ4OVHCM.js");
7529
+ const { formatCiResult } = await import("./ci-format-NKJRZ3QI.js");
7808
7530
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
7809
7531
  if (formats > 1) {
7810
7532
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -7962,7 +7684,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7962
7684
  config.get("customProviders"),
7963
7685
  config.getConfigDir()
7964
7686
  );
7965
- const { startHub } = await import("./hub-TO7ODOIA.js");
7687
+ const { startHub } = await import("./hub-NX7HYN7V.js");
7966
7688
  await startHub(
7967
7689
  {
7968
7690
  topic: topic ?? "",