jinzd-ai-cli 0.4.277 → 0.4.278

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-7Y4NAA6N.js} +2 -2
  2. package/dist/{chunk-OCOGYIRY.js → chunk-2BYQP6JX.js} +1 -1
  3. package/dist/{chunk-I3PYD2YN.js → chunk-4Z6GAYB5.js} +3 -3
  4. package/dist/{chunk-HCF442WL.js → chunk-H7QC5VMQ.js} +1 -1
  5. package/dist/{chunk-HJVKCOAG.js → chunk-JJCNNQTU.js} +183 -3
  6. package/dist/{chunk-UWQCTTP4.js → chunk-L3CPM472.js} +1 -1
  7. package/dist/{chunk-BYNNKJUC.js → chunk-LOXEYWC3.js} +1 -1
  8. package/dist/{chunk-7IPMONKZ.js → chunk-LTZFUYBT.js} +3 -3
  9. package/dist/{chunk-7YYUITED.js → chunk-LXXQTWT2.js} +1 -1
  10. package/dist/{chunk-7BO5H2QI.js → chunk-RFSKPCYC.js} +1 -1
  11. package/dist/{chunk-3VFOXEIL.js → chunk-SB4XONS4.js} +1 -1
  12. package/dist/{chunk-Z752LDYF.js → chunk-SJCOE4C7.js} +1 -1
  13. package/dist/{chunk-KIGKL3PZ.js → chunk-WOXIKQRI.js} +4 -4
  14. package/dist/{chunk-ZP3RCZKM.js → chunk-X3722RFA.js} +1 -1
  15. package/dist/{ci-JFC45LIS.js → ci-WDF2CYR4.js} +4 -4
  16. package/dist/{ci-format-P3LIZHUR.js → ci-format-7B5VAZGA.js} +2 -2
  17. package/dist/{constants-N3CHKZJY.js → constants-DC3TNLTL.js} +1 -1
  18. package/dist/{doctor-cli-Z3TGHTSX.js → doctor-cli-CDDG5XOY.js} +4 -4
  19. package/dist/electron-server.js +307 -49
  20. package/dist/{hub-NEWIFMQ3.js → hub-TO7ODOIA.js} +1 -1
  21. package/dist/index.js +150 -162
  22. package/dist/{persistent-memory-6Q5FDFJ7.js → persistent-memory-BU63CSGK.js} +2 -2
  23. package/dist/{persistent-memory-ZFR5GI7D.js → persistent-memory-JCENBMCJ.js} +2 -2
  24. package/dist/{pr-ZUGSWQ5R.js → pr-GVSZYX6I.js} +4 -4
  25. package/dist/{run-tests-USV7IJ7X.js → run-tests-2Q5MJHXB.js} +2 -2
  26. package/dist/{run-tests-76M6AC3G.js → run-tests-R4IQS6IF.js} +2 -2
  27. package/dist/{server-C523CIGN.js → server-KAURBKFI.js} +148 -54
  28. package/dist/{server-R7D5RR36.js → server-WXLE53HG.js} +5 -5
  29. package/dist/{task-orchestrator-G2MQDNGQ.js → task-orchestrator-RJ6FXYY5.js} +5 -5
  30. package/dist/{usage-EFHXXMYX.js → usage-V3R7DA7M.js} +2 -2
  31. package/dist/web/client/app.js +4 -1
  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
@@ -4,6 +4,7 @@ import {
4
4
  McpManager,
5
5
  SNAPSHOT_PROMPT,
6
6
  SkillManager,
7
+ applyPlanCommand,
7
8
  applyProfileCommand,
8
9
  applyThinkCommand,
9
10
  armDeferredSave,
@@ -14,21 +15,28 @@ import {
14
15
  costSourceNote,
15
16
  decideDeferredSave,
16
17
  decideModel,
18
+ describeRouting,
17
19
  estimateConversationTokens,
18
20
  evaluateContextPressure,
19
21
  filterMemoryEntries,
20
22
  loadDevState,
21
23
  parseMemoryShowFilters,
24
+ parseModelCommand,
25
+ parseRouteCommand,
22
26
  parseSimpleYaml,
23
27
  persistToolRound,
24
28
  readGitDiff,
29
+ resolveModelSwitch,
30
+ resolveProviderSwitch,
31
+ routeDecisionRows,
32
+ routingEmptyRulesNote,
25
33
  saveDevState,
26
34
  scanProject,
27
35
  sessionHasMeaningfulContent,
28
36
  setupProxy,
29
37
  snapshotFile,
30
38
  stripRoutingTags
31
- } from "./chunk-HJVKCOAG.js";
39
+ } from "./chunk-JJCNNQTU.js";
32
40
  import {
33
41
  CostTracker,
34
42
  computeCost,
@@ -58,7 +66,7 @@ import {
58
66
  setMaxOutputCap,
59
67
  spawnAgentContext,
60
68
  undoStack
61
- } from "./chunk-KIGKL3PZ.js";
69
+ } from "./chunk-WOXIKQRI.js";
62
70
  import {
63
71
  buildReviewPrompt,
64
72
  buildSecurityReviewPrompt
@@ -99,7 +107,7 @@ import {
99
107
  touchMemoryReferences,
100
108
  updateMemoryApproval,
101
109
  updateMemoryEntry
102
- } from "./chunk-7BO5H2QI.js";
110
+ } from "./chunk-RFSKPCYC.js";
103
111
  import "./chunk-4DEMGCK4.js";
104
112
  import "./chunk-UUSRWSSX.js";
105
113
  import "./chunk-CKH4KQ4E.js";
@@ -123,7 +131,7 @@ import {
123
131
  formatDoctorReport,
124
132
  loadContextFiles,
125
133
  writeCrashLog
126
- } from "./chunk-7IPMONKZ.js";
134
+ } from "./chunk-LTZFUYBT.js";
127
135
  import {
128
136
  describePlugin,
129
137
  getActivePluginAssets,
@@ -140,14 +148,14 @@ import {
140
148
  trustHook,
141
149
  trustPlugin,
142
150
  untrustHook
143
- } from "./chunk-UWQCTTP4.js";
151
+ } from "./chunk-L3CPM472.js";
144
152
  import {
145
153
  ProviderRegistry,
146
154
  listBuiltInProviderMetadata
147
155
  } from "./chunk-UGY5SVNX.js";
148
156
  import {
149
157
  ConfigManager
150
- } from "./chunk-OCOGYIRY.js";
158
+ } from "./chunk-2BYQP6JX.js";
151
159
  import {
152
160
  CONTENT_ONLY_STREAM_REMINDER,
153
161
  TEE_FINAL_USER_NUDGE,
@@ -185,7 +193,7 @@ import {
185
193
  import {
186
194
  fileCheckpoints
187
195
  } from "./chunk-4BKXL7SM.js";
188
- import "./chunk-3VFOXEIL.js";
196
+ import "./chunk-SB4XONS4.js";
189
197
  import {
190
198
  AGENTIC_BEHAVIOR_GUIDELINE,
191
199
  AUTHOR,
@@ -203,7 +211,7 @@ import {
203
211
  SKILLS_DIR_NAME,
204
212
  VERSION,
205
213
  buildUserIdentityPrompt
206
- } from "./chunk-ZP3RCZKM.js";
214
+ } from "./chunk-X3722RFA.js";
207
215
 
208
216
  // src/index.ts
209
217
  import { program } from "commander";
@@ -979,34 +987,41 @@ function createProviderCommands() {
979
987
  } else {
980
988
  targetId = args[0];
981
989
  }
982
- if (!ctx.providers.has(targetId)) {
983
- ctx.renderer.renderError(`Provider '${targetId}' is not configured. Run: aicli config`);
984
- return;
985
- }
986
- const targetProvider = ctx.providers.get(targetId);
987
- if (targetProvider.info.models.length === 0) {
988
- const models = await targetProvider.listModels();
989
- if (models.length === 0) {
990
- ctx.renderer.renderError(
991
- `Provider '${targetId}' has no available models. ` + (targetId === "ollama" ? "Make sure Ollama is running (`ollama serve`) and has models (`ollama pull <model>`)." : "Check provider configuration.")
992
- );
993
- return;
990
+ const configured = ctx.providers.has(targetId);
991
+ let availableModels = [];
992
+ let providerDefaultModel = "";
993
+ if (configured) {
994
+ const target = ctx.providers.get(targetId);
995
+ providerDefaultModel = target.info.defaultModel;
996
+ availableModels = target.info.models.map((m) => m.id);
997
+ if (availableModels.length === 0) {
998
+ availableModels = (await target.listModels()).map((m) => m.id);
994
999
  }
995
1000
  }
996
- if (targetId === ctx.getCurrentProvider()) {
997
- ctx.renderer.printInfo(`Already using provider: ${targetId}`);
1001
+ const session = ctx.sessions.current;
1002
+ const outcome = resolveProviderSwitch({
1003
+ targetId,
1004
+ currentProvider: ctx.getCurrentProvider(),
1005
+ configured,
1006
+ availableModels,
1007
+ configuredDefaultModel: ctx.config.get("defaultModels")[targetId],
1008
+ providerDefaultModel,
1009
+ messageCount: session?.messages.length ?? 0
1010
+ });
1011
+ if (outcome.status === "not-configured" || outcome.status === "no-models") {
1012
+ ctx.renderer.renderError(outcome.message);
998
1013
  return;
999
1014
  }
1000
- const session = ctx.sessions.current;
1001
- const msgCount = session?.messages.length ?? 0;
1002
- ctx.setProvider(targetId);
1015
+ if (outcome.status === "unchanged") {
1016
+ ctx.renderer.printInfo(outcome.message);
1017
+ return;
1018
+ }
1019
+ ctx.setProvider(outcome.providerId, outcome.model);
1003
1020
  if (session) {
1004
- session.updateProvider(targetId, ctx.getCurrentModel());
1021
+ session.updateProvider(outcome.providerId, outcome.model);
1005
1022
  await ctx.sessions.save();
1006
1023
  }
1007
- ctx.renderer.printSuccess(
1008
- `Switched to provider: ${targetId}` + (msgCount > 0 ? ` (conversation preserved: ${msgCount} messages)` : "")
1009
- );
1024
+ ctx.renderer.printSuccess(outcome.message);
1010
1025
  }
1011
1026
  },
1012
1027
  {
@@ -1014,29 +1029,29 @@ function createProviderCommands() {
1014
1029
  description: "Switch model, refresh live model list, or inspect model cache",
1015
1030
  usage: "/model [name|refresh [provider]|cache [clear [provider]]]",
1016
1031
  async execute(args, ctx) {
1017
- const sub = (args[0] ?? "").toLowerCase();
1018
- if (sub === "refresh") {
1019
- const providerId = args[1] ?? ctx.getCurrentProvider();
1020
- if (!ctx.providers.has(providerId)) {
1021
- ctx.renderer.printInfo(`Provider is not configured: ${providerId}`);
1032
+ const intent = parseModelCommand(args, ctx.getCurrentProvider());
1033
+ if (intent.kind === "refresh") {
1034
+ if (!ctx.providers.has(intent.providerId)) {
1035
+ ctx.renderer.printInfo(`Provider is not configured: ${intent.providerId}`);
1022
1036
  return;
1023
1037
  }
1024
- ctx.renderer.printInfo(`Refreshing models for ${providerId}...`);
1038
+ ctx.renderer.printInfo(`Refreshing models for ${intent.providerId}...`);
1025
1039
  try {
1026
- const models = await ctx.providers.refreshModels(providerId);
1027
- ctx.renderer.printSuccess(`Refreshed ${models.length} model(s) for ${providerId}.`);
1040
+ const models = await ctx.providers.refreshModels(intent.providerId);
1041
+ ctx.renderer.printSuccess(`Refreshed ${models.length} model(s) for ${intent.providerId}.`);
1028
1042
  } catch (err) {
1029
1043
  ctx.renderer.printInfo(`Model refresh failed: ${err instanceof Error ? err.message : String(err)}`);
1030
1044
  }
1031
1045
  return;
1032
1046
  }
1033
- if (sub === "cache") {
1034
- if ((args[1] ?? "").toLowerCase() === "clear") {
1035
- const providerId = args[2];
1036
- ctx.providers.clearModelCache(providerId);
1037
- ctx.renderer.printSuccess(providerId ? `Cleared model cache for ${providerId}.` : "Cleared model cache.");
1038
- return;
1039
- }
1047
+ if (intent.kind === "cache-clear") {
1048
+ ctx.providers.clearModelCache(intent.providerId);
1049
+ ctx.renderer.printSuccess(
1050
+ intent.providerId ? `Cleared model cache for ${intent.providerId}.` : "Cleared model cache."
1051
+ );
1052
+ return;
1053
+ }
1054
+ if (intent.kind === "cache-show") {
1040
1055
  const rows = ctx.providers.getModelCacheStatus();
1041
1056
  if (rows.length === 0) {
1042
1057
  ctx.renderer.printInfo("Model cache is empty. Use /model refresh to populate it.");
@@ -1048,9 +1063,11 @@ function createProviderCommands() {
1048
1063
  );
1049
1064
  return;
1050
1065
  }
1066
+ let knownModels = ctx.providers.has(ctx.getCurrentProvider()) ? ctx.providers.get(ctx.getCurrentProvider()).info.models.map((m) => m.id) : [];
1051
1067
  let targetModel;
1052
- if (!args[0]) {
1068
+ if (intent.kind === "select") {
1053
1069
  const models = await ctx.providers.listModels(ctx.getCurrentProvider());
1070
+ knownModels = models.map((m) => m.id);
1054
1071
  const currentModel = ctx.getCurrentModel();
1055
1072
  const items = models.map((m) => ({
1056
1073
  value: m.id,
@@ -1069,22 +1086,27 @@ function createProviderCommands() {
1069
1086
  if (!chosen) return;
1070
1087
  targetModel = chosen;
1071
1088
  } else {
1072
- targetModel = args[0];
1089
+ targetModel = intent.modelId;
1073
1090
  }
1074
- if (targetModel === ctx.getCurrentModel()) {
1075
- ctx.renderer.printInfo(`Already using model: ${targetModel}`);
1091
+ const session = ctx.sessions.current;
1092
+ const outcome = resolveModelSwitch({
1093
+ targetModel,
1094
+ currentModel: ctx.getCurrentModel(),
1095
+ provider: ctx.getCurrentProvider(),
1096
+ knownModels,
1097
+ messageCount: session?.messages.length ?? 0
1098
+ });
1099
+ if (outcome.status === "unchanged") {
1100
+ ctx.renderer.printInfo(outcome.message);
1076
1101
  return;
1077
1102
  }
1078
- const session = ctx.sessions.current;
1079
- const msgCount = session?.messages.length ?? 0;
1080
- ctx.setProvider(ctx.getCurrentProvider(), targetModel);
1103
+ ctx.setProvider(ctx.getCurrentProvider(), outcome.model);
1081
1104
  if (session) {
1082
- session.updateProvider(ctx.getCurrentProvider(), targetModel);
1105
+ session.updateProvider(ctx.getCurrentProvider(), outcome.model);
1083
1106
  await ctx.sessions.save();
1084
1107
  }
1085
- ctx.renderer.printSuccess(
1086
- `Switched to model: ${targetModel}` + (msgCount > 0 ? ` (conversation preserved: ${msgCount} messages)` : "")
1087
- );
1108
+ ctx.renderer.printSuccess(outcome.message);
1109
+ if (outcome.warning) console.log(theme.warning(` ${outcome.warning}`));
1088
1110
  }
1089
1111
  },
1090
1112
  {
@@ -1092,72 +1114,61 @@ function createProviderCommands() {
1092
1114
  description: "Smart model routing \u2014 enable/disable or inspect routing rules",
1093
1115
  usage: "/route [on|off|show|test <message>]",
1094
1116
  async execute(args, ctx) {
1095
- const sub = (args[0] ?? "show").toLowerCase();
1117
+ const intent = parseRouteCommand(args);
1096
1118
  const routing = ctx.config.get("routing");
1097
- if (sub === "on" || sub === "enable") {
1119
+ if (intent.kind === "enable") {
1098
1120
  ctx.config.setByPath("routing.enabled", "true");
1099
1121
  ctx.renderer.printSuccess("Smart model routing enabled.");
1100
- if (!routing || routing.rules.length === 0) {
1101
- ctx.renderer.printInfo(
1102
- 'No rules configured yet. Add rules under `routing.rules` in ~/.aicli/config.json.\nExample: { match: { tag: "fast" }, model: "claude-haiku-4-5" }'
1103
- );
1104
- }
1122
+ const note = routingEmptyRulesNote(routing);
1123
+ if (note) ctx.renderer.printInfo(note);
1105
1124
  return;
1106
1125
  }
1107
- if (sub === "off" || sub === "disable") {
1126
+ if (intent.kind === "disable") {
1108
1127
  ctx.config.setByPath("routing.enabled", "false");
1109
1128
  ctx.renderer.printSuccess("Smart model routing disabled.");
1110
1129
  return;
1111
1130
  }
1112
- if (sub === "test") {
1113
- const msg = args.slice(1).join(" ").trim();
1114
- if (!msg) {
1115
- console.log(theme.warning(" Usage: /route test <message>"));
1116
- return;
1117
- }
1118
- const decision = ctx.computeRoutingDecision(msg);
1119
- const marker = decision.overridden ? theme.accent("\u2192 ROUTED") : theme.dim("(unchanged)");
1120
- console.log();
1121
- console.log(` Input: ${theme.dim(msg)}`);
1122
- console.log(` Current: ${theme.info(ctx.getCurrentModel())}`);
1123
- console.log(` Decision: ${theme.info(decision.model)} ${marker}`);
1124
- console.log(` Reason: ${theme.dim(decision.reason)}`);
1125
- if (typeof decision.ruleIdx === "number") {
1126
- console.log(` Rule: #${decision.ruleIdx}`);
1127
- }
1128
- console.log();
1131
+ if (intent.kind === "usage" || intent.kind === "unknown") {
1132
+ console.log(theme.warning(` ${intent.message}`));
1129
1133
  return;
1130
1134
  }
1131
- if (sub === "show" || sub === "status") {
1135
+ if (intent.kind === "test") {
1136
+ const decision = ctx.computeRoutingDecision(intent.message);
1132
1137
  console.log();
1133
- console.log(` ${theme.heading("Smart Model Routing")}`);
1134
- console.log(` Status: ${routing?.enabled ? theme.success("enabled") : theme.dim("disabled")}`);
1135
- console.log(` Provider: ${theme.info(ctx.getCurrentProvider())}`);
1136
- console.log(` Current: ${theme.info(ctx.getCurrentModel())}`);
1137
- if (routing?.fallback) {
1138
- console.log(` Fallback: ${theme.info(routing.fallback)}`);
1139
- }
1140
- console.log();
1141
- if (!routing || routing.rules.length === 0) {
1142
- console.log(` ${theme.dim("(no rules configured \u2014 edit ~/.aicli/config.json `routing.rules`)")}`);
1143
- } else {
1144
- console.log(` ${theme.heading("Rules")} ${theme.dim(`(evaluated top-to-bottom)`)}:`);
1145
- routing.rules.forEach((r, i) => {
1146
- const parts = [];
1147
- if (r.match.tag) parts.push(`tag=#${r.match.tag}`);
1148
- if (r.match.contains && r.match.contains.length > 0) parts.push(`contains=[${r.match.contains.slice(0, 3).join(", ")}${r.match.contains.length > 3 ? ", \u2026" : ""}]`);
1149
- if (typeof r.match.maxLength === "number") parts.push(`maxLen=${r.match.maxLength}`);
1150
- if (typeof r.match.minLength === "number") parts.push(`minLen=${r.match.minLength}`);
1151
- const cond = parts.length > 0 ? parts.join(" & ") : theme.warning("(empty \u2014 never matches)");
1152
- console.log(` ${theme.dim(`#${i}`)} ${r.name ? theme.accent(r.name) + " " : ""}${cond} ${theme.dim("\u2192")} ${theme.info(r.model)}`);
1153
- });
1138
+ for (const row of routeDecisionRows(intent.message, ctx.getCurrentModel(), decision)) {
1139
+ const pad = `${row.label}:`.padEnd(10);
1140
+ const value = row.label === "Input" || row.label === "Reason" || row.label === "Rule" ? theme.dim(row.value) : theme.info(row.value);
1141
+ console.log(` ${pad}${value}`);
1154
1142
  }
1155
1143
  console.log();
1156
- console.log(` ${theme.dim("Commands: /route on | off | test <msg> | show")}`);
1157
- console.log();
1158
1144
  return;
1159
1145
  }
1160
- console.log(theme.warning(` Unknown subcommand: ${sub}. Usage: /route [on|off|show|test <message>]`));
1146
+ const view = describeRouting({
1147
+ routing,
1148
+ provider: ctx.getCurrentProvider(),
1149
+ currentModel: ctx.getCurrentModel()
1150
+ });
1151
+ console.log();
1152
+ console.log(` ${theme.heading("Smart Model Routing")}`);
1153
+ console.log(` Status: ${view.enabled ? theme.success("enabled") : theme.dim("disabled")}`);
1154
+ console.log(` Provider: ${theme.info(view.provider)}`);
1155
+ console.log(` Current: ${theme.info(view.currentModel)}`);
1156
+ if (view.fallback) console.log(` Fallback: ${theme.info(view.fallback)}`);
1157
+ console.log();
1158
+ if (view.noRulesNote) {
1159
+ console.log(` ${theme.dim(view.noRulesNote)}`);
1160
+ } else {
1161
+ console.log(` ${theme.heading("Rules")} ${theme.dim(`(evaluated top-to-bottom)`)}:`);
1162
+ for (const rule of view.rules) {
1163
+ const cond = rule.empty ? theme.warning(rule.condition) : rule.condition;
1164
+ console.log(
1165
+ ` ${theme.dim(`#${rule.index}`)} ${rule.name ? theme.accent(rule.name) + " " : ""}${cond} ${theme.dim("\u2192")} ${theme.info(rule.model)}`
1166
+ );
1167
+ }
1168
+ }
1169
+ console.log();
1170
+ console.log(` ${theme.dim(view.hint)}`);
1171
+ console.log();
1161
1172
  }
1162
1173
  },
1163
1174
  {
@@ -1191,56 +1202,33 @@ function createProviderCommands() {
1191
1202
  description: "Enter Plan Mode (read-only): AI can only read files and plan, not modify anything",
1192
1203
  usage: "/plan [execute|exit|status]",
1193
1204
  execute(args, ctx) {
1194
- const sub = args[0]?.toLowerCase();
1195
- if (!sub || sub === "enter") {
1196
- if (ctx.getPlanMode()) {
1197
- ctx.renderer.printInfo("Already in Plan Mode. Use /plan execute to start executing, or /plan exit to leave.");
1205
+ const outcome = applyPlanCommand(args[0], ctx.getPlanMode());
1206
+ if (outcome.changed) ctx.setPlanMode(outcome.planMode);
1207
+ switch (outcome.status) {
1208
+ case "entered":
1209
+ console.log();
1210
+ console.log(theme.warning(` ${outcome.summary}`));
1211
+ console.log(theme.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1212
+ for (const line of outcome.details) console.log(theme.dim(` ${line}`));
1213
+ console.log();
1198
1214
  return;
1199
- }
1200
- ctx.setPlanMode(true);
1201
- console.log();
1202
- console.log(theme.warning(" \u{1F4CB} Plan Mode activated"));
1203
- console.log(theme.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1204
- console.log(theme.dim(" AI can now ONLY use read-only tools:"));
1205
- console.log(theme.dim(" read_file \xB7 list_dir \xB7 grep_files \xB7 glob_files"));
1206
- console.log(theme.dim(" web_fetch \xB7 google_search \xB7 ask_user \xB7 write_todos"));
1207
- console.log(theme.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1208
- console.log(theme.dim(" Describe your task and the AI will analyze the codebase"));
1209
- console.log(theme.dim(" and create a detailed implementation plan."));
1210
- console.log(theme.dim(" When ready: /plan execute | To cancel: /plan exit"));
1211
- console.log();
1212
- return;
1213
- }
1214
- if (sub === "execute") {
1215
- if (!ctx.getPlanMode()) {
1216
- ctx.renderer.printInfo("Not in Plan Mode. Enter first with /plan");
1215
+ case "executing":
1216
+ ctx.renderer.printSuccess(outcome.summary);
1217
1217
  return;
1218
- }
1219
- ctx.setPlanMode(false);
1220
- ctx.renderer.printSuccess("Plan Mode ended \u2014 switching to execute mode. AI now has full tool access.");
1221
- return;
1222
- }
1223
- if (sub === "exit" || sub === "cancel") {
1224
- if (!ctx.getPlanMode()) {
1225
- ctx.renderer.printInfo("Not in Plan Mode.");
1218
+ case "already-active":
1219
+ case "not-active":
1220
+ case "cancelled":
1221
+ ctx.renderer.printInfo(outcome.summary);
1226
1222
  return;
1227
- }
1228
- ctx.setPlanMode(false);
1229
- ctx.renderer.printInfo("Plan Mode cancelled. Returning to normal mode.");
1230
- return;
1231
- }
1232
- if (sub === "status") {
1233
- const active = ctx.getPlanMode();
1234
- console.log();
1235
- console.log(` Plan Mode: ${active ? theme.warning("ACTIVE \u{1F4CB}") : theme.dim("inactive")}`);
1236
- if (active) {
1237
- console.log(theme.dim(" Tools restricted to read-only set."));
1238
- console.log(theme.dim(" Use /plan execute to start executing, or /plan exit to cancel."));
1239
- }
1240
- console.log();
1241
- return;
1223
+ case "status":
1224
+ console.log();
1225
+ console.log(` ${outcome.planMode ? theme.warning(outcome.summary) : theme.dim(outcome.summary)}`);
1226
+ for (const line of outcome.details) console.log(theme.dim(` ${line}`));
1227
+ console.log();
1228
+ return;
1229
+ default:
1230
+ ctx.renderer.renderError(outcome.summary);
1242
1231
  }
1243
- ctx.renderer.renderError("Usage: /plan [execute|exit|status]");
1244
1232
  }
1245
1233
  }
1246
1234
  ];
@@ -1409,7 +1397,7 @@ No tools match "${filter}".
1409
1397
  const { join: join6 } = await import("path");
1410
1398
  const { existsSync: existsSync6 } = await import("fs");
1411
1399
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1412
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-N3CHKZJY.js");
1400
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-DC3TNLTL.js");
1413
1401
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1414
1402
  const cwd = process.cwd();
1415
1403
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2329,7 +2317,7 @@ function createReviewCommands() {
2329
2317
  usage: "/test [command|filter]",
2330
2318
  async execute(args, ctx) {
2331
2319
  try {
2332
- const { executeTests } = await import("./run-tests-76M6AC3G.js");
2320
+ const { executeTests } = await import("./run-tests-R4IQS6IF.js");
2333
2321
  const argStr = args.join(" ").trim();
2334
2322
  let testArgs = {};
2335
2323
  if (argStr) {
@@ -7559,7 +7547,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7559
7547
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7560
7548
  process.exit(1);
7561
7549
  }
7562
- const { startWebServer } = await import("./server-C523CIGN.js");
7550
+ const { startWebServer } = await import("./server-KAURBKFI.js");
7563
7551
  await startWebServer({ port, host: options.host });
7564
7552
  });
7565
7553
  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) => {
@@ -7726,11 +7714,11 @@ program.command("sessions").description("List recent conversation sessions").opt
7726
7714
  console.log(footer + "\n");
7727
7715
  });
7728
7716
  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) => {
7729
- const { runUsageCli } = await import("./usage-EFHXXMYX.js");
7717
+ const { runUsageCli } = await import("./usage-V3R7DA7M.js");
7730
7718
  await runUsageCli(options);
7731
7719
  });
7732
7720
  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) => {
7733
- const { runDoctorCli } = await import("./doctor-cli-Z3TGHTSX.js");
7721
+ const { runDoctorCli } = await import("./doctor-cli-CDDG5XOY.js");
7734
7722
  const argv = process.argv.slice(2);
7735
7723
  await runDoctorCli({
7736
7724
  json: !!options.json || argv.includes("--json"),
@@ -7739,7 +7727,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
7739
7727
  });
7740
7728
  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) => {
7741
7729
  try {
7742
- const batch = await import("./batch-2I5TPZA2.js");
7730
+ const batch = await import("./batch-7Y4NAA6N.js");
7743
7731
  switch (action) {
7744
7732
  case "submit":
7745
7733
  if (!arg) {
@@ -7782,7 +7770,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7782
7770
  }
7783
7771
  });
7784
7772
  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) => {
7785
- const { startMcpServer } = await import("./server-R7D5RR36.js");
7773
+ const { startMcpServer } = await import("./server-WXLE53HG.js");
7786
7774
  await startMcpServer({
7787
7775
  allowDestructive: !!options.allowDestructive,
7788
7776
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7795,7 +7783,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7795
7783
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
7796
7784
  process.exit(1);
7797
7785
  }
7798
- const { runPrCli } = await import("./pr-ZUGSWQ5R.js");
7786
+ const { runPrCli } = await import("./pr-GVSZYX6I.js");
7799
7787
  const result = await runPrCli({
7800
7788
  action,
7801
7789
  target,
@@ -7815,8 +7803,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
7815
7803
  process.exit(result.exitCode);
7816
7804
  });
7817
7805
  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) => {
7818
- const { runCi } = await import("./ci-JFC45LIS.js");
7819
- const { formatCiResult } = await import("./ci-format-P3LIZHUR.js");
7806
+ const { runCi } = await import("./ci-WDF2CYR4.js");
7807
+ const { formatCiResult } = await import("./ci-format-7B5VAZGA.js");
7820
7808
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
7821
7809
  if (formats > 1) {
7822
7810
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -7974,7 +7962,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7974
7962
  config.get("customProviders"),
7975
7963
  config.getConfigDir()
7976
7964
  );
7977
- const { startHub } = await import("./hub-NEWIFMQ3.js");
7965
+ const { startHub } = await import("./hub-TO7ODOIA.js");
7978
7966
  await startHub(
7979
7967
  {
7980
7968
  topic: topic ?? "",
@@ -28,11 +28,11 @@ import {
28
28
  touchMemoryReferences,
29
29
  updateMemoryApproval,
30
30
  updateMemoryEntry
31
- } from "./chunk-7BO5H2QI.js";
31
+ } from "./chunk-RFSKPCYC.js";
32
32
  import "./chunk-3FEZSLGI.js";
33
33
  import "./chunk-HOSJZMQS.js";
34
34
  import "./chunk-IW3Q7AE5.js";
35
- import "./chunk-ZP3RCZKM.js";
35
+ import "./chunk-X3722RFA.js";
36
36
  export {
37
37
  addMemoryEntry,
38
38
  backupMemoryStore,
@@ -27,9 +27,9 @@ import {
27
27
  touchMemoryReferences,
28
28
  updateMemoryApproval,
29
29
  updateMemoryEntry
30
- } from "./chunk-7YYUITED.js";
30
+ } from "./chunk-LXXQTWT2.js";
31
31
  import "./chunk-FSC6KEWU.js";
32
- import "./chunk-Z752LDYF.js";
32
+ import "./chunk-SJCOE4C7.js";
33
33
  import "./chunk-6BUTA5VW.js";
34
34
  export {
35
35
  addMemoryEntry,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  countSeverity,
4
4
  runCi
5
- } from "./chunk-I3PYD2YN.js";
6
- import "./chunk-HCF442WL.js";
5
+ } from "./chunk-4Z6GAYB5.js";
6
+ import "./chunk-H7QC5VMQ.js";
7
7
  import {
8
8
  buildReviewPrompt,
9
9
  buildSecurityReviewPrompt,
@@ -17,13 +17,13 @@ import {
17
17
  } from "./chunk-UGY5SVNX.js";
18
18
  import {
19
19
  ConfigManager
20
- } from "./chunk-OCOGYIRY.js";
20
+ } from "./chunk-2BYQP6JX.js";
21
21
  import "./chunk-TEXT4DAT.js";
22
22
  import "./chunk-TU3L3PW7.js";
23
23
  import "./chunk-IW3Q7AE5.js";
24
24
  import {
25
25
  VERSION
26
- } from "./chunk-ZP3RCZKM.js";
26
+ } from "./chunk-X3722RFA.js";
27
27
 
28
28
  // src/cli/pr.ts
29
29
  import { execFileSync } from "child_process";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-BYNNKJUC.js";
5
- import "./chunk-Z752LDYF.js";
4
+ } from "./chunk-LOXEYWC3.js";
5
+ import "./chunk-SJCOE4C7.js";
6
6
  export {
7
7
  executeTests,
8
8
  runTestsTool
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-3VFOXEIL.js";
6
- import "./chunk-ZP3RCZKM.js";
5
+ } from "./chunk-SB4XONS4.js";
6
+ import "./chunk-X3722RFA.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool