jinzd-ai-cli 0.4.276 → 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 (39) hide show
  1. package/dist/{batch-F7SKIBI3.js → batch-7Y4NAA6N.js} +2 -2
  2. package/dist/{chunk-VF7DMSKF.js → chunk-2BYQP6JX.js} +1 -1
  3. package/dist/{chunk-GLSR2NR3.js → chunk-4DEMGCK4.js} +4 -3
  4. package/dist/{chunk-MXPUOF5K.js → chunk-4Z6GAYB5.js} +4 -4
  5. package/dist/{chunk-NXAHXWPF.js → chunk-H7QC5VMQ.js} +1 -1
  6. package/dist/{chunk-MCKUGWOY.js → chunk-JJCNNQTU.js} +183 -3
  7. package/dist/{chunk-AOISQVXS.js → chunk-L3CPM472.js} +1 -1
  8. package/dist/{chunk-ATD2Y3PB.js → chunk-LOXEYWC3.js} +1 -1
  9. package/dist/{chunk-WYDP2WEQ.js → chunk-LTZFUYBT.js} +4 -4
  10. package/dist/{chunk-4NH4Q7QK.js → chunk-LXXQTWT2.js} +1 -1
  11. package/dist/{chunk-QCG6UU2S.js → chunk-PPIISCFN.js} +4 -3
  12. package/dist/{chunk-KWSGSSWN.js → chunk-RFSKPCYC.js} +1 -1
  13. package/dist/{chunk-OMBKLWLJ.js → chunk-SB4XONS4.js} +1 -1
  14. package/dist/{chunk-UNL7NR55.js → chunk-SJCOE4C7.js} +1 -1
  15. package/dist/{chunk-4KTK2OYU.js → chunk-UGY5SVNX.js} +46 -20
  16. package/dist/{chunk-NXNXWM6H.js → chunk-WOXIKQRI.js} +16 -7
  17. package/dist/{chunk-FLDYAXJR.js → chunk-X3722RFA.js} +1 -1
  18. package/dist/{ci-VURFRMWQ.js → ci-WDF2CYR4.js} +5 -5
  19. package/dist/{ci-format-AFJJIURF.js → ci-format-7B5VAZGA.js} +2 -2
  20. package/dist/{constants-WO7ERENL.js → constants-DC3TNLTL.js} +1 -1
  21. package/dist/{doctor-cli-BGGILTHE.js → doctor-cli-CDDG5XOY.js} +5 -5
  22. package/dist/electron-server.js +378 -78
  23. package/dist/{hub-Z73RLNJI.js → hub-TO7ODOIA.js} +1 -1
  24. package/dist/index.js +175 -188
  25. package/dist/{indexer-M2LJGTY2.js → indexer-RBEKMFT4.js} +1 -1
  26. package/dist/{indexer-VZETNE4H.js → indexer-TNDWGFRI.js} +1 -1
  27. package/dist/{persistent-memory-5QMARQJF.js → persistent-memory-BU63CSGK.js} +2 -2
  28. package/dist/{persistent-memory-CI544RLT.js → persistent-memory-JCENBMCJ.js} +2 -2
  29. package/dist/{pr-24REDMGV.js → pr-GVSZYX6I.js} +5 -5
  30. package/dist/{run-tests-72VNZXNT.js → run-tests-2Q5MJHXB.js} +2 -2
  31. package/dist/{run-tests-JJ3KOY5E.js → run-tests-R4IQS6IF.js} +2 -2
  32. package/dist/{server-JMXC2N3F.js → server-KAURBKFI.js} +167 -62
  33. package/dist/{server-QJHCJDA7.js → server-WXLE53HG.js} +6 -6
  34. package/dist/{task-orchestrator-DJN36HP5.js → task-orchestrator-RJ6FXYY5.js} +8 -8
  35. package/dist/{usage-HXJVDETY.js → usage-V3R7DA7M.js} +2 -2
  36. package/dist/web/client/app.js +4 -1
  37. package/dist/web/client/app.js.br +0 -0
  38. package/dist/web/client/app.js.gz +0 -0
  39. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  indexProject,
3
3
  updateFile
4
- } from "./chunk-QCG6UU2S.js";
4
+ } from "./chunk-PPIISCFN.js";
5
5
  import "./chunk-RWM2GFRC.js";
6
6
  import "./chunk-6BUTA5VW.js";
7
7
  export {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  indexProject,
4
4
  updateFile
5
- } from "./chunk-GLSR2NR3.js";
5
+ } from "./chunk-4DEMGCK4.js";
6
6
  import "./chunk-CKH4KQ4E.js";
7
7
  import "./chunk-IW3Q7AE5.js";
8
8
  export {
@@ -28,11 +28,11 @@ import {
28
28
  touchMemoryReferences,
29
29
  updateMemoryApproval,
30
30
  updateMemoryEntry
31
- } from "./chunk-KWSGSSWN.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-FLDYAXJR.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-4NH4Q7QK.js";
30
+ } from "./chunk-LXXQTWT2.js";
31
31
  import "./chunk-FSC6KEWU.js";
32
- import "./chunk-UNL7NR55.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-MXPUOF5K.js";
6
- import "./chunk-NXAHXWPF.js";
5
+ } from "./chunk-4Z6GAYB5.js";
6
+ import "./chunk-H7QC5VMQ.js";
7
7
  import {
8
8
  buildReviewPrompt,
9
9
  buildSecurityReviewPrompt,
@@ -14,16 +14,16 @@ import {
14
14
  } from "./chunk-6YZEZFX5.js";
15
15
  import {
16
16
  ProviderRegistry
17
- } from "./chunk-4KTK2OYU.js";
17
+ } from "./chunk-UGY5SVNX.js";
18
18
  import {
19
19
  ConfigManager
20
- } from "./chunk-VF7DMSKF.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-FLDYAXJR.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-ATD2Y3PB.js";
5
- import "./chunk-UNL7NR55.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-OMBKLWLJ.js";
6
- import "./chunk-FLDYAXJR.js";
5
+ } from "./chunk-SB4XONS4.js";
6
+ import "./chunk-X3722RFA.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -16,6 +16,7 @@ import {
16
16
  AUTO_COMPACT_INSTRUCTION,
17
17
  McpManager,
18
18
  SkillManager,
19
+ applyPlanCommand,
19
20
  applyProfileCommand,
20
21
  applyThinkCommand,
21
22
  armDeferredSave,
@@ -25,19 +26,26 @@ import {
25
26
  costSourceNote,
26
27
  decideDeferredSave,
27
28
  decideModel,
29
+ describeRouting,
28
30
  estimateConversationTokens,
29
31
  evaluateContextPressure,
30
32
  filterMemoryEntries,
31
33
  loadDevState,
32
34
  parseMemoryShowFilters,
35
+ parseModelCommand,
36
+ parseRouteCommand,
33
37
  persistToolRound,
34
38
  readGitDiff,
39
+ resolveModelSwitch,
40
+ resolveProviderSwitch,
41
+ routeDecisionRows,
42
+ routingEmptyRulesNote,
35
43
  scanDirTree,
36
44
  scanProject,
37
45
  setupProxy,
38
46
  snapshotFile,
39
47
  stripRoutingTags
40
- } from "./chunk-MCKUGWOY.js";
48
+ } from "./chunk-JJCNNQTU.js";
41
49
  import {
42
50
  CNY_PER_USD,
43
51
  CostTracker,
@@ -63,6 +71,7 @@ import {
63
71
  getRecentlyDeniedAutoActions,
64
72
  googleSearchContext,
65
73
  groupCallsByPhase,
74
+ isToolCapableProvider,
66
75
  listAgentConfigs,
67
76
  listAgentRuns,
68
77
  recordRecentlyDeniedAutoAction,
@@ -78,7 +87,7 @@ import {
78
87
  spawnAgentContext,
79
88
  truncateOutput,
80
89
  undoStack
81
- } from "./chunk-NXNXWM6H.js";
90
+ } from "./chunk-WOXIKQRI.js";
82
91
  import {
83
92
  buildReviewPrompt,
84
93
  buildSecurityReviewPrompt
@@ -105,8 +114,8 @@ import {
105
114
  restoreMemoryEntries,
106
115
  updateMemoryApproval,
107
116
  updateMemoryEntry
108
- } from "./chunk-KWSGSSWN.js";
109
- import "./chunk-GLSR2NR3.js";
117
+ } from "./chunk-RFSKPCYC.js";
118
+ import "./chunk-4DEMGCK4.js";
110
119
  import "./chunk-UUSRWSSX.js";
111
120
  import "./chunk-CKH4KQ4E.js";
112
121
  import "./chunk-BXP6YZ2P.js";
@@ -124,7 +133,7 @@ import {
124
133
  buildDoctorReport,
125
134
  formatDoctorReport,
126
135
  loadContextFiles
127
- } from "./chunk-WYDP2WEQ.js";
136
+ } from "./chunk-LTZFUYBT.js";
128
137
  import {
129
138
  describePlugin,
130
139
  getActivePluginAssets,
@@ -139,13 +148,13 @@ import {
139
148
  runTool,
140
149
  setPluginEnabled,
141
150
  trustPlugin
142
- } from "./chunk-AOISQVXS.js";
151
+ } from "./chunk-L3CPM472.js";
143
152
  import {
144
153
  ProviderRegistry
145
- } from "./chunk-4KTK2OYU.js";
154
+ } from "./chunk-UGY5SVNX.js";
146
155
  import {
147
156
  ConfigManager
148
- } from "./chunk-VF7DMSKF.js";
157
+ } from "./chunk-2BYQP6JX.js";
149
158
  import {
150
159
  CONTENT_ONLY_STREAM_REMINDER,
151
160
  TEE_FINAL_USER_NUDGE,
@@ -175,7 +184,7 @@ import {
175
184
  maskConfigSecrets
176
185
  } from "./chunk-XNFIYS7G.js";
177
186
  import "./chunk-4BKXL7SM.js";
178
- import "./chunk-OMBKLWLJ.js";
187
+ import "./chunk-SB4XONS4.js";
179
188
  import {
180
189
  AGENTIC_BEHAVIOR_GUIDELINE,
181
190
  AUTHOR,
@@ -191,7 +200,7 @@ import {
191
200
  SKILLS_DIR_NAME,
192
201
  VERSION,
193
202
  buildUserIdentityPrompt
194
- } from "./chunk-FLDYAXJR.js";
203
+ } from "./chunk-X3722RFA.js";
195
204
 
196
205
  // src/web/server.ts
197
206
  import express from "express";
@@ -720,47 +729,86 @@ import { mkdirSync as mkdirSync2, createWriteStream as createWriteStream2 } from
720
729
  import { dirname as dirname2 } from "path";
721
730
 
722
731
  // src/web/commands/provider-commands.ts
732
+ function syncSessionProvider(ctx) {
733
+ const session = ctx.sessions.current;
734
+ if (!session) return;
735
+ session.updateProvider(ctx.currentProvider, ctx.currentModel);
736
+ ctx.saveIfNeeded();
737
+ }
723
738
  async function handleProvider(args, ctx) {
724
739
  const id = args[0];
725
740
  if (!id) {
726
741
  ctx.send({ type: "error", message: "Usage: /provider <id>" });
727
742
  return;
728
743
  }
729
- const p = ctx.providers.get(id);
730
- if (!p) {
731
- ctx.send({ type: "error", message: `Provider "${id}" not available` });
744
+ const configured = ctx.providers.has(id);
745
+ let availableModels = [];
746
+ let providerDefaultModel = "";
747
+ if (configured) {
748
+ const target = ctx.providers.get(id);
749
+ providerDefaultModel = target.info.defaultModel;
750
+ availableModels = target.info.models.map((m) => m.id);
751
+ if (availableModels.length === 0) {
752
+ try {
753
+ availableModels = (await target.listModels()).map((m) => m.id);
754
+ } catch {
755
+ availableModels = [];
756
+ }
757
+ }
758
+ }
759
+ const outcome = resolveProviderSwitch({
760
+ targetId: id,
761
+ currentProvider: ctx.currentProvider,
762
+ configured,
763
+ availableModels,
764
+ configuredDefaultModel: ctx.config.get("defaultModels")[id],
765
+ providerDefaultModel,
766
+ messageCount: ctx.sessions.current?.messages.length ?? 0
767
+ });
768
+ if (outcome.status === "not-configured" || outcome.status === "no-models") {
769
+ ctx.send({ type: "error", message: outcome.message });
770
+ return;
771
+ }
772
+ if (outcome.status === "unchanged") {
773
+ ctx.send({ type: "info", message: outcome.message });
732
774
  return;
733
775
  }
734
- ctx.currentProvider = id;
735
- ctx.currentModel = p.info.defaultModel;
776
+ ctx.currentProvider = outcome.providerId;
777
+ ctx.currentModel = outcome.model;
736
778
  ctx.updateContextWindow();
737
- ctx.send({ type: "info", message: `Switched to provider: ${id} (${ctx.currentModel})` });
779
+ syncSessionProvider(ctx);
780
+ ctx.send({ type: "info", message: outcome.message });
738
781
  ctx.sendStatus();
739
782
  }
740
783
  async function handleModel(args, ctx) {
741
- const sub = args[0];
742
- if (!sub) {
784
+ const intent = parseModelCommand(args, ctx.currentProvider);
785
+ if (intent.kind === "select") {
743
786
  ctx.send({ type: "error", message: "Usage: /model <id>|refresh [provider]|cache [clear [provider]]" });
744
787
  return;
745
788
  }
746
- if (sub === "refresh") {
747
- const providerId = args[1] ?? ctx.currentProvider;
789
+ if (intent.kind === "refresh") {
790
+ if (!ctx.providers.has(intent.providerId)) {
791
+ ctx.send({ type: "error", message: `Provider is not configured: ${intent.providerId}` });
792
+ return;
793
+ }
748
794
  try {
749
- const models2 = await ctx.providers.refreshModels(providerId);
750
- ctx.send({ type: "info", message: `Refreshed ${models2.length} model(s) for ${providerId}.` });
795
+ const models2 = await ctx.providers.refreshModels(intent.providerId);
796
+ ctx.send({ type: "info", message: `Refreshed ${models2.length} model(s) for ${intent.providerId}.` });
751
797
  ctx.sendStatus();
752
798
  } catch (err) {
753
799
  ctx.send({ type: "error", message: `Model refresh failed: ${err instanceof Error ? err.message : String(err)}` });
754
800
  }
755
801
  return;
756
802
  }
757
- if (sub === "cache") {
758
- if ((args[1] ?? "").toLowerCase() === "clear") {
759
- const providerId = args[2];
760
- ctx.providers.clearModelCache(providerId);
761
- ctx.send({ type: "info", message: providerId ? `Cleared model cache for ${providerId}.` : "Cleared model cache." });
762
- return;
763
- }
803
+ if (intent.kind === "cache-clear") {
804
+ ctx.providers.clearModelCache(intent.providerId);
805
+ ctx.send({
806
+ type: "info",
807
+ message: intent.providerId ? `Cleared model cache for ${intent.providerId}.` : "Cleared model cache."
808
+ });
809
+ return;
810
+ }
811
+ if (intent.kind === "cache-show") {
764
812
  const rows = ctx.providers.getModelCacheStatus();
765
813
  ctx.send({
766
814
  type: "info",
@@ -768,16 +816,25 @@ async function handleModel(args, ctx) {
768
816
  });
769
817
  return;
770
818
  }
771
- const modelId = sub;
772
819
  const models = await ctx.providers.listModels(ctx.currentProvider);
773
- const found = models.find((m) => m.id === modelId);
774
- if (!found) {
775
- ctx.send({ type: "error", message: `Model "${modelId}" not found` });
820
+ const outcome = resolveModelSwitch({
821
+ targetModel: intent.modelId,
822
+ currentModel: ctx.currentModel,
823
+ provider: ctx.currentProvider,
824
+ knownModels: models.map((m) => m.id),
825
+ messageCount: ctx.sessions.current?.messages.length ?? 0
826
+ });
827
+ if (outcome.status === "unchanged") {
828
+ ctx.send({ type: "info", message: outcome.message });
776
829
  return;
777
830
  }
778
- ctx.currentModel = modelId;
831
+ ctx.currentModel = outcome.model;
779
832
  ctx.updateContextWindow();
780
- ctx.send({ type: "info", message: `Switched to model: ${modelId}` });
833
+ syncSessionProvider(ctx);
834
+ ctx.send({
835
+ type: "info",
836
+ message: outcome.warning ? `${outcome.message} \u2014 ${outcome.warning}` : outcome.message
837
+ });
781
838
  ctx.sendStatus();
782
839
  }
783
840
  async function handleThink(args, ctx) {
@@ -787,7 +844,7 @@ async function handleThink(args, ctx) {
787
844
  runtimeEffort: ctx.runtimeThinkingEffort,
788
845
  configuredThinking: modelParams?.thinking,
789
846
  configuredEffort: modelParams?.thinkingEffort,
790
- supportsEffort: ctx.providers.get(ctx.currentProvider)?.supportsReasoningEffort ?? false,
847
+ supportsEffort: ctx.providers.has(ctx.currentProvider) ? ctx.providers.get(ctx.currentProvider).supportsReasoningEffort : false,
791
848
  provider: ctx.currentProvider
792
849
  });
793
850
  if (outcome.changed) {
@@ -801,24 +858,59 @@ async function handleThink(args, ctx) {
801
858
  if (outcome.changed) ctx.sendStatus();
802
859
  }
803
860
  async function handlePlan(args, ctx) {
804
- const sub = args[0];
805
- if (sub === "exit" || sub === "cancel") {
806
- ctx.planMode = false;
807
- ctx.send({ type: "info", message: "Plan mode OFF." });
808
- } else if (sub === "execute") {
809
- ctx.planMode = false;
810
- ctx.send({ type: "info", message: "Plan mode OFF. Executing with all tools enabled." });
811
- } else if (sub === "status" || sub === "show") {
812
- ctx.send({ type: "info", message: `Plan mode: ${ctx.planMode ? "ON (read-only tools only)" : "OFF"}` });
861
+ const outcome = applyPlanCommand(args[0], ctx.planMode);
862
+ if (outcome.changed) ctx.planMode = outcome.planMode;
863
+ ctx.send({
864
+ type: outcome.status === "unknown" ? "error" : "info",
865
+ message: [outcome.summary, ...outcome.details].join(" \u2014 ")
866
+ });
867
+ if (outcome.changed) ctx.sendStatus();
868
+ }
869
+ async function handleRoute(args, ctx) {
870
+ const intent = parseRouteCommand(args);
871
+ const routing = ctx.config.get("routing");
872
+ if (intent.kind === "enable" || intent.kind === "disable") {
873
+ const on = intent.kind === "enable";
874
+ ctx.config.setByPath("routing.enabled", on ? "true" : "false");
875
+ const note = on ? routingEmptyRulesNote(routing) : null;
876
+ ctx.send({
877
+ type: "info",
878
+ message: `Smart model routing ${on ? "enabled" : "disabled"}.` + (note ? `
879
+ ${note}` : "")
880
+ });
881
+ ctx.sendStatus();
882
+ return;
883
+ }
884
+ if (intent.kind === "usage" || intent.kind === "unknown") {
885
+ ctx.send({ type: "error", message: intent.message });
813
886
  return;
814
- } else if (sub !== void 0) {
815
- ctx.send({ type: "error", message: `Unknown /plan option "${sub}" \u2014 expected execute | exit | status` });
887
+ }
888
+ if (intent.kind === "test") {
889
+ const decision = ctx.computeRoutingDecision(intent.message);
890
+ ctx.send({
891
+ type: "info",
892
+ message: routeDecisionRows(intent.message, ctx.currentModel, decision).map((row) => `${row.label}: ${row.value}`).join("\n")
893
+ });
816
894
  return;
895
+ }
896
+ const view = describeRouting({ routing, provider: ctx.currentProvider, currentModel: ctx.currentModel });
897
+ const lines = [
898
+ "Smart Model Routing",
899
+ `Status: ${view.enabled ? "enabled" : "disabled"}`,
900
+ `Provider: ${view.provider}`,
901
+ `Current: ${view.currentModel}`
902
+ ];
903
+ if (view.fallback) lines.push(`Fallback: ${view.fallback}`);
904
+ if (view.noRulesNote) {
905
+ lines.push(view.noRulesNote);
817
906
  } else {
818
- ctx.planMode = !ctx.planMode;
819
- ctx.send({ type: "info", message: `Plan mode: ${ctx.planMode ? "ON (read-only tools only)" : "OFF"}` });
907
+ lines.push("Rules (evaluated top-to-bottom):");
908
+ for (const rule of view.rules) {
909
+ lines.push(` #${rule.index} ${rule.name ? `${rule.name} ` : ""}${rule.condition} \u2192 ${rule.model}`);
910
+ }
820
911
  }
821
- ctx.sendStatus();
912
+ lines.push(view.hint);
913
+ ctx.send({ type: "info", message: lines.join("\n") });
822
914
  }
823
915
 
824
916
  // src/web/commands/_shared.ts
@@ -862,7 +954,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
862
954
  Cost: ${formatCost(cost)}` : "";
863
955
  let memoryLine = "";
864
956
  try {
865
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-5QMARQJF.js");
957
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-BU63CSGK.js");
866
958
  const pending = countPendingMemories2(ctx.config.getConfigDir());
867
959
  if (pending > 0) memoryLine = `
868
960
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -1675,7 +1767,7 @@ async function handleTest(args, ctx) {
1675
1767
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
1676
1768
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
1677
1769
  }
1678
- const runTests = ctx.runTests ?? (await import("./run-tests-JJ3KOY5E.js")).executeTests;
1770
+ const runTests = ctx.runTests ?? (await import("./run-tests-R4IQS6IF.js")).executeTests;
1679
1771
  const report = await runTests(testArgs);
1680
1772
  ctx.send({ type: "info", message: report });
1681
1773
  } catch (err) {
@@ -1853,7 +1945,7 @@ async function handleIndex(args, ctx) {
1853
1945
  const sub = (args[0] ?? "status").toLowerCase();
1854
1946
  const root = process.cwd();
1855
1947
  const { loadIndex, clearIndex } = await import("./store-MWNHVGJT.js");
1856
- const { indexProject } = await import("./indexer-VZETNE4H.js");
1948
+ const { indexProject } = await import("./indexer-TNDWGFRI.js");
1857
1949
  const { loadVectorStore, clearVectorStore } = await import("./vector-store-BBDXB5IQ.js");
1858
1950
  if (sub === "status") {
1859
1951
  const idx = loadIndex(root);
@@ -2011,7 +2103,7 @@ async function handleMemory(args, ctx) {
2011
2103
  ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
2012
2104
  } else if (sub === "export") {
2013
2105
  if (args[1] === "md") {
2014
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-5QMARQJF.js");
2106
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-BU63CSGK.js");
2015
2107
  ctx.send({
2016
2108
  type: "export_data",
2017
2109
  format: "md",
@@ -2265,7 +2357,8 @@ async function handleHelp(_args, ctx) {
2265
2357
  " /clear \u2014 Clear conversation & start new session",
2266
2358
  " /compact [hint] \u2014 Compress conversation history",
2267
2359
  " /think [on|off] \u2014 Toggle extended thinking mode",
2268
- " /plan [enter|exit] \u2014 Toggle read-only planning mode",
2360
+ " /plan [execute|exit|status] \u2014 Read-only planning mode (bare /plan enters it)",
2361
+ " /route [on|off|show|test <msg>] \u2014 Smart model routing",
2269
2362
  " /session new|list|load|delete <id> \u2014 Session management",
2270
2363
  " /system [prompt|clear] \u2014 Set/view/reset system prompt",
2271
2364
  " /context [status|reload] \u2014 Show/reload context layers",
@@ -2402,8 +2495,9 @@ var CLI_ONLY_WEB_COMMANDS = /* @__PURE__ */ new Map([
2402
2495
  ["snapshot", "Dev-state snapshots are written when the terminal REPL exits."],
2403
2496
  ["hooks", "Hook trust is granted per machine from the terminal."],
2404
2497
  ["hook", "Hook trust is granted per machine from the terminal."],
2405
- // 以下两条并非「终端才有意义」,而是 Web 侧尚未实现——如实说明,别假装是设计。
2406
- ["route", "Smart model routing is not applied to Web sessions yet (config.routing is REPL-only)."],
2498
+ // 以下一条并非「终端才有意义」,而是 Web 侧尚未实现——如实说明,别假装是设计。
2499
+ // (`route` 曾在这里,理由写的是「Web 尚未应用智能路由」;v0.4.269 让 routing 在 Web
2500
+ // 上真正生效之后那句话就不再成立,命令已在 Web 实现,见 commands/provider-commands.ts。)
2407
2501
  ["security", "Redaction status and toggles are terminal-only for now; /status shows the current profile."]
2408
2502
  ]);
2409
2503
  var webCommandHandlers = {
@@ -2411,6 +2505,7 @@ var webCommandHandlers = {
2411
2505
  model: handleModel,
2412
2506
  think: handleThink,
2413
2507
  plan: handlePlan,
2508
+ route: handleRoute,
2414
2509
  clear: handleClear,
2415
2510
  compact: handleCompact,
2416
2511
  status: handleStatus,
@@ -2583,9 +2678,19 @@ var SessionHandler = class {
2583
2678
  }
2584
2679
  runLifecycleHooks(hooks, "SessionStart", { source: "web" }, { configDir: this.config.getConfigDir() });
2585
2680
  this.sendStatus();
2586
- askUserContext.rl = null;
2681
+ askUserContext.rl = void 0;
2587
2682
  askUserContext.prompting = false;
2588
2683
  }
2684
+ /**
2685
+ * P3-03:本方法与 `WebCommandContext` 列出的其余 36 个成员一并由 private 放开为
2686
+ * public——它们本就经由 ctx 门面暴露给每一个 web 命令 handler,`private` 只是名义上的。
2687
+ *
2688
+ * `web-command-context.ts` 的文件注释明明白白写着「`ctx: WebCommandContext = this`
2689
+ * 这个赋值保证 handler 只能碰到这些成员」,而 `handleCommand` 实际写的是
2690
+ * `this as unknown as WebCommandContext`——那道保证被这一次 cast 整个绕过了,
2691
+ * 唯一拦着真赋值的就是这些名义上的 private。去掉 cast 之后,SessionHandler 与门面
2692
+ * 接口之间的任何漂移(少一个成员、签名改了)都会当场编译失败,而不是等到运行时。
2693
+ */
2589
2694
  send(msg) {
2590
2695
  if (this.ws.readyState === this.ws.OPEN) {
2591
2696
  this.ws.send(JSON.stringify(msg));
@@ -2954,10 +3059,10 @@ var SessionHandler = class {
2954
3059
  this.processing = false;
2955
3060
  return;
2956
3061
  }
2957
- const hasToolSupport = typeof provider.chatWithTools === "function";
2958
- const { toolDefs, mcpBudgetNote } = hasToolSupport ? this.getFilteredToolDefs() : { toolDefs: [], mcpBudgetNote: null };
2959
- if (hasToolSupport && toolDefs.length > 0) {
2960
- await this.handleChatWithTools(provider, session.messages, toolDefs, mcpBudgetNote, routingDecision.model);
3062
+ const toolCapable = isToolCapableProvider(provider) ? provider : null;
3063
+ const { toolDefs, mcpBudgetNote } = toolCapable ? this.getFilteredToolDefs() : { toolDefs: [], mcpBudgetNote: null };
3064
+ if (toolCapable && toolDefs.length > 0) {
3065
+ await this.handleChatWithTools(toolCapable, session.messages, toolDefs, mcpBudgetNote, routingDecision.model);
2961
3066
  } else {
2962
3067
  await this.handleChatSimple(provider, session.messages, routingDecision.model);
2963
3068
  }
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-NXNXWM6H.js";
4
+ } from "./chunk-WOXIKQRI.js";
5
5
  import "./chunk-GHWZVPUV.js";
6
- import "./chunk-KWSGSSWN.js";
7
- import "./chunk-GLSR2NR3.js";
6
+ import "./chunk-RFSKPCYC.js";
7
+ import "./chunk-4DEMGCK4.js";
8
8
  import "./chunk-UUSRWSSX.js";
9
9
  import "./chunk-CKH4KQ4E.js";
10
10
  import "./chunk-BXP6YZ2P.js";
@@ -14,7 +14,7 @@ import "./chunk-NYNSYLFY.js";
14
14
  import "./chunk-3FEZSLGI.js";
15
15
  import {
16
16
  runTool
17
- } from "./chunk-AOISQVXS.js";
17
+ } from "./chunk-L3CPM472.js";
18
18
  import {
19
19
  getDangerLevel,
20
20
  schemaToJsonSchema
@@ -23,10 +23,10 @@ import "./chunk-TU3L3PW7.js";
23
23
  import "./chunk-HOSJZMQS.js";
24
24
  import "./chunk-IW3Q7AE5.js";
25
25
  import "./chunk-4BKXL7SM.js";
26
- import "./chunk-OMBKLWLJ.js";
26
+ import "./chunk-SB4XONS4.js";
27
27
  import {
28
28
  VERSION
29
- } from "./chunk-FLDYAXJR.js";
29
+ } from "./chunk-X3722RFA.js";
30
30
 
31
31
  // src/mcp/server.ts
32
32
  import { createInterface } from "readline";
@@ -2,11 +2,12 @@
2
2
  import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
+ isToolCapableProvider,
5
6
  truncateOutput
6
- } from "./chunk-NXNXWM6H.js";
7
+ } from "./chunk-WOXIKQRI.js";
7
8
  import "./chunk-GHWZVPUV.js";
8
- import "./chunk-KWSGSSWN.js";
9
- import "./chunk-GLSR2NR3.js";
9
+ import "./chunk-RFSKPCYC.js";
10
+ import "./chunk-4DEMGCK4.js";
10
11
  import "./chunk-UUSRWSSX.js";
11
12
  import "./chunk-CKH4KQ4E.js";
12
13
  import "./chunk-BXP6YZ2P.js";
@@ -16,7 +17,7 @@ import "./chunk-NYNSYLFY.js";
16
17
  import "./chunk-3FEZSLGI.js";
17
18
  import {
18
19
  runTool
19
- } from "./chunk-AOISQVXS.js";
20
+ } from "./chunk-L3CPM472.js";
20
21
  import {
21
22
  getDangerLevel,
22
23
  runLeanAgentLoop
@@ -27,10 +28,10 @@ import {
27
28
  atomicWriteFileSync
28
29
  } from "./chunk-IW3Q7AE5.js";
29
30
  import "./chunk-4BKXL7SM.js";
30
- import "./chunk-OMBKLWLJ.js";
31
+ import "./chunk-SB4XONS4.js";
31
32
  import {
32
33
  SUBAGENT_ALLOWED_TOOLS
33
- } from "./chunk-FLDYAXJR.js";
34
+ } from "./chunk-X3722RFA.js";
34
35
 
35
36
  // src/hub/task-orchestrator.ts
36
37
  import { createInterface } from "readline";
@@ -193,8 +194,7 @@ var TaskToolExecutor = class {
193
194
  // src/hub/task-orchestrator.ts
194
195
  var TASK_STATE_FILE = ".aicli-task.json";
195
196
  function asToolCapable(p) {
196
- const maybe = p;
197
- if (typeof maybe.chatWithTools !== "function") {
197
+ if (!isToolCapableProvider(p)) {
198
198
  throw new Error(
199
199
  `Provider '${p.info?.id ?? "unknown"}' does not support tool calls. Hub task orchestration requires a tool-capable provider (e.g. claude, openai, deepseek).`
200
200
  );
@@ -8,10 +8,10 @@ import {
8
8
  } from "./chunk-DPTEC6AQ.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-VF7DMSKF.js";
11
+ } from "./chunk-2BYQP6JX.js";
12
12
  import "./chunk-TU3L3PW7.js";
13
13
  import "./chunk-IW3Q7AE5.js";
14
- import "./chunk-FLDYAXJR.js";
14
+ import "./chunk-X3722RFA.js";
15
15
 
16
16
  // src/cli/usage.ts
17
17
  function classifyRowCost(row) {
@@ -994,7 +994,10 @@ btnThink.addEventListener('click', () => {
994
994
  });
995
995
 
996
996
  btnPlan.addEventListener('click', () => {
997
- send({ type: 'command', name: 'plan', args: [] });
997
+ // 显式发 toggle:裸 /plan 的语义两端相反(REPL 是「进入」,Web 是切换),已统一为
998
+ // 「进入」,按钮则改用明写的 toggle 由**服务端**按自己的状态翻转——不能拿客户端的
999
+ // active class 当真相,它来自 status 帧,多标签页/换会话时会过期(实测撞到过)。
1000
+ send({ type: 'command', name: 'plan', args: ['toggle'] });
998
1001
  });
999
1002
 
1000
1003
  providerSelect.addEventListener('change', () => {
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.276",
3
+ "version": "0.4.278",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",