jinzd-ai-cli 0.4.277 → 0.4.279
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{batch-2I5TPZA2.js → batch-6QZSWCBL.js} +2 -2
- package/dist/{chunk-ZP3RCZKM.js → chunk-2BKRWTEQ.js} +1 -1
- package/dist/{chunk-Z752LDYF.js → chunk-5XHEXRMN.js} +1 -1
- package/dist/{chunk-7BO5H2QI.js → chunk-6WMT7OQG.js} +1 -1
- package/dist/{chunk-HJVKCOAG.js → chunk-7L4TEK7Q.js} +419 -3
- package/dist/{chunk-7YYUITED.js → chunk-CMNXAJLH.js} +1 -1
- package/dist/{chunk-KIGKL3PZ.js → chunk-FQJFGGKN.js} +4 -4
- package/dist/{chunk-UWQCTTP4.js → chunk-IIXZ7IPN.js} +1 -1
- package/dist/{chunk-7IPMONKZ.js → chunk-JLOQBYU4.js} +3 -3
- package/dist/{chunk-I3PYD2YN.js → chunk-JS6VAPWM.js} +3 -3
- package/dist/{chunk-3VFOXEIL.js → chunk-NZPHEUJM.js} +1 -1
- package/dist/{chunk-HCF442WL.js → chunk-RJY3HJS4.js} +1 -1
- package/dist/{chunk-BYNNKJUC.js → chunk-SIVM2YQQ.js} +1 -1
- package/dist/{chunk-OCOGYIRY.js → chunk-UD3BVNC5.js} +1 -1
- package/dist/{ci-JFC45LIS.js → ci-F4ESOYI5.js} +4 -4
- package/dist/{ci-format-P3LIZHUR.js → ci-format-AIRW3TVQ.js} +2 -2
- package/dist/{constants-N3CHKZJY.js → constants-3VMMZJDS.js} +1 -1
- package/dist/{doctor-cli-Z3TGHTSX.js → doctor-cli-WVMEWMYE.js} +4 -4
- package/dist/electron-server.js +699 -101
- package/dist/{hub-NEWIFMQ3.js → hub-JJCCCU3O.js} +1 -1
- package/dist/index.js +243 -466
- package/dist/{persistent-memory-6Q5FDFJ7.js → persistent-memory-KSZKM4JG.js} +2 -2
- package/dist/{persistent-memory-ZFR5GI7D.js → persistent-memory-QZN4Q3W4.js} +2 -2
- package/dist/{pr-ZUGSWQ5R.js → pr-GFB5JC26.js} +4 -4
- package/dist/{run-tests-76M6AC3G.js → run-tests-EL54INOI.js} +2 -2
- package/dist/{run-tests-USV7IJ7X.js → run-tests-HMHHIG7Y.js} +2 -2
- package/dist/{server-R7D5RR36.js → server-6C7GITHY.js} +5 -5
- package/dist/{server-C523CIGN.js → server-WUSJWC3A.js} +324 -106
- package/dist/{task-orchestrator-G2MQDNGQ.js → task-orchestrator-C7RUUA2Q.js} +5 -5
- package/dist/{usage-EFHXXMYX.js → usage-CW6BT2UV.js} +2 -2
- package/dist/web/client/app.js +18 -3
- package/dist/web/client/app.js.br +0 -0
- package/dist/web/client/app.js.gz +0 -0
- package/package.json +1 -1
|
@@ -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,36 @@ import {
|
|
|
25
26
|
costSourceNote,
|
|
26
27
|
decideDeferredSave,
|
|
27
28
|
decideModel,
|
|
29
|
+
describeRouting,
|
|
28
30
|
estimateConversationTokens,
|
|
29
31
|
evaluateContextPressure,
|
|
30
32
|
filterMemoryEntries,
|
|
33
|
+
formatSessionSummaryLine,
|
|
31
34
|
loadDevState,
|
|
35
|
+
parseBatchDeleteArgs,
|
|
36
|
+
parseCleanArgs,
|
|
32
37
|
parseMemoryShowFilters,
|
|
38
|
+
parseModelCommand,
|
|
39
|
+
parseRouteCommand,
|
|
40
|
+
parseSessionListArgs,
|
|
33
41
|
persistToolRound,
|
|
34
42
|
readGitDiff,
|
|
43
|
+
resolveModelSwitch,
|
|
44
|
+
resolveProviderSwitch,
|
|
45
|
+
resolveSessionRef,
|
|
46
|
+
routeDecisionRows,
|
|
47
|
+
routingEmptyRulesNote,
|
|
35
48
|
scanDirTree,
|
|
36
49
|
scanProject,
|
|
50
|
+
selectSessions,
|
|
51
|
+
selectStaleSessions,
|
|
52
|
+
sessionListJsonRow,
|
|
53
|
+
sessionListNeedsFileSize,
|
|
54
|
+
sessionListSummary,
|
|
37
55
|
setupProxy,
|
|
38
56
|
snapshotFile,
|
|
39
57
|
stripRoutingTags
|
|
40
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-7L4TEK7Q.js";
|
|
41
59
|
import {
|
|
42
60
|
CNY_PER_USD,
|
|
43
61
|
CostTracker,
|
|
@@ -79,7 +97,7 @@ import {
|
|
|
79
97
|
spawnAgentContext,
|
|
80
98
|
truncateOutput,
|
|
81
99
|
undoStack
|
|
82
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-FQJFGGKN.js";
|
|
83
101
|
import {
|
|
84
102
|
buildReviewPrompt,
|
|
85
103
|
buildSecurityReviewPrompt
|
|
@@ -106,7 +124,7 @@ import {
|
|
|
106
124
|
restoreMemoryEntries,
|
|
107
125
|
updateMemoryApproval,
|
|
108
126
|
updateMemoryEntry
|
|
109
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-6WMT7OQG.js";
|
|
110
128
|
import "./chunk-4DEMGCK4.js";
|
|
111
129
|
import "./chunk-UUSRWSSX.js";
|
|
112
130
|
import "./chunk-CKH4KQ4E.js";
|
|
@@ -125,7 +143,7 @@ import {
|
|
|
125
143
|
buildDoctorReport,
|
|
126
144
|
formatDoctorReport,
|
|
127
145
|
loadContextFiles
|
|
128
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-JLOQBYU4.js";
|
|
129
147
|
import {
|
|
130
148
|
describePlugin,
|
|
131
149
|
getActivePluginAssets,
|
|
@@ -140,13 +158,13 @@ import {
|
|
|
140
158
|
runTool,
|
|
141
159
|
setPluginEnabled,
|
|
142
160
|
trustPlugin
|
|
143
|
-
} from "./chunk-
|
|
161
|
+
} from "./chunk-IIXZ7IPN.js";
|
|
144
162
|
import {
|
|
145
163
|
ProviderRegistry
|
|
146
164
|
} from "./chunk-UGY5SVNX.js";
|
|
147
165
|
import {
|
|
148
166
|
ConfigManager
|
|
149
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-UD3BVNC5.js";
|
|
150
168
|
import {
|
|
151
169
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
152
170
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -176,7 +194,7 @@ import {
|
|
|
176
194
|
maskConfigSecrets
|
|
177
195
|
} from "./chunk-XNFIYS7G.js";
|
|
178
196
|
import "./chunk-4BKXL7SM.js";
|
|
179
|
-
import "./chunk-
|
|
197
|
+
import "./chunk-NZPHEUJM.js";
|
|
180
198
|
import {
|
|
181
199
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
182
200
|
AUTHOR,
|
|
@@ -192,7 +210,7 @@ import {
|
|
|
192
210
|
SKILLS_DIR_NAME,
|
|
193
211
|
VERSION,
|
|
194
212
|
buildUserIdentityPrompt
|
|
195
|
-
} from "./chunk-
|
|
213
|
+
} from "./chunk-2BKRWTEQ.js";
|
|
196
214
|
|
|
197
215
|
// src/web/server.ts
|
|
198
216
|
import express from "express";
|
|
@@ -721,47 +739,86 @@ import { mkdirSync as mkdirSync2, createWriteStream as createWriteStream2 } from
|
|
|
721
739
|
import { dirname as dirname2 } from "path";
|
|
722
740
|
|
|
723
741
|
// src/web/commands/provider-commands.ts
|
|
742
|
+
function syncSessionProvider(ctx) {
|
|
743
|
+
const session = ctx.sessions.current;
|
|
744
|
+
if (!session) return;
|
|
745
|
+
session.updateProvider(ctx.currentProvider, ctx.currentModel);
|
|
746
|
+
ctx.saveIfNeeded();
|
|
747
|
+
}
|
|
724
748
|
async function handleProvider(args, ctx) {
|
|
725
749
|
const id = args[0];
|
|
726
750
|
if (!id) {
|
|
727
751
|
ctx.send({ type: "error", message: "Usage: /provider <id>" });
|
|
728
752
|
return;
|
|
729
753
|
}
|
|
730
|
-
const
|
|
731
|
-
|
|
732
|
-
|
|
754
|
+
const configured = ctx.providers.has(id);
|
|
755
|
+
let availableModels = [];
|
|
756
|
+
let providerDefaultModel = "";
|
|
757
|
+
if (configured) {
|
|
758
|
+
const target = ctx.providers.get(id);
|
|
759
|
+
providerDefaultModel = target.info.defaultModel;
|
|
760
|
+
availableModels = target.info.models.map((m) => m.id);
|
|
761
|
+
if (availableModels.length === 0) {
|
|
762
|
+
try {
|
|
763
|
+
availableModels = (await target.listModels()).map((m) => m.id);
|
|
764
|
+
} catch {
|
|
765
|
+
availableModels = [];
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
const outcome = resolveProviderSwitch({
|
|
770
|
+
targetId: id,
|
|
771
|
+
currentProvider: ctx.currentProvider,
|
|
772
|
+
configured,
|
|
773
|
+
availableModels,
|
|
774
|
+
configuredDefaultModel: ctx.config.get("defaultModels")[id],
|
|
775
|
+
providerDefaultModel,
|
|
776
|
+
messageCount: ctx.sessions.current?.messages.length ?? 0
|
|
777
|
+
});
|
|
778
|
+
if (outcome.status === "not-configured" || outcome.status === "no-models") {
|
|
779
|
+
ctx.send({ type: "error", message: outcome.message });
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (outcome.status === "unchanged") {
|
|
783
|
+
ctx.send({ type: "info", message: outcome.message });
|
|
733
784
|
return;
|
|
734
785
|
}
|
|
735
|
-
ctx.currentProvider =
|
|
736
|
-
ctx.currentModel =
|
|
786
|
+
ctx.currentProvider = outcome.providerId;
|
|
787
|
+
ctx.currentModel = outcome.model;
|
|
737
788
|
ctx.updateContextWindow();
|
|
738
|
-
|
|
789
|
+
syncSessionProvider(ctx);
|
|
790
|
+
ctx.send({ type: "info", message: outcome.message });
|
|
739
791
|
ctx.sendStatus();
|
|
740
792
|
}
|
|
741
793
|
async function handleModel(args, ctx) {
|
|
742
|
-
const
|
|
743
|
-
if (
|
|
794
|
+
const intent = parseModelCommand(args, ctx.currentProvider);
|
|
795
|
+
if (intent.kind === "select") {
|
|
744
796
|
ctx.send({ type: "error", message: "Usage: /model <id>|refresh [provider]|cache [clear [provider]]" });
|
|
745
797
|
return;
|
|
746
798
|
}
|
|
747
|
-
if (
|
|
748
|
-
|
|
799
|
+
if (intent.kind === "refresh") {
|
|
800
|
+
if (!ctx.providers.has(intent.providerId)) {
|
|
801
|
+
ctx.send({ type: "error", message: `Provider is not configured: ${intent.providerId}` });
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
749
804
|
try {
|
|
750
|
-
const models2 = await ctx.providers.refreshModels(providerId);
|
|
751
|
-
ctx.send({ type: "info", message: `Refreshed ${models2.length} model(s) for ${providerId}.` });
|
|
805
|
+
const models2 = await ctx.providers.refreshModels(intent.providerId);
|
|
806
|
+
ctx.send({ type: "info", message: `Refreshed ${models2.length} model(s) for ${intent.providerId}.` });
|
|
752
807
|
ctx.sendStatus();
|
|
753
808
|
} catch (err) {
|
|
754
809
|
ctx.send({ type: "error", message: `Model refresh failed: ${err instanceof Error ? err.message : String(err)}` });
|
|
755
810
|
}
|
|
756
811
|
return;
|
|
757
812
|
}
|
|
758
|
-
if (
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
813
|
+
if (intent.kind === "cache-clear") {
|
|
814
|
+
ctx.providers.clearModelCache(intent.providerId);
|
|
815
|
+
ctx.send({
|
|
816
|
+
type: "info",
|
|
817
|
+
message: intent.providerId ? `Cleared model cache for ${intent.providerId}.` : "Cleared model cache."
|
|
818
|
+
});
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
if (intent.kind === "cache-show") {
|
|
765
822
|
const rows = ctx.providers.getModelCacheStatus();
|
|
766
823
|
ctx.send({
|
|
767
824
|
type: "info",
|
|
@@ -769,16 +826,25 @@ async function handleModel(args, ctx) {
|
|
|
769
826
|
});
|
|
770
827
|
return;
|
|
771
828
|
}
|
|
772
|
-
const modelId = sub;
|
|
773
829
|
const models = await ctx.providers.listModels(ctx.currentProvider);
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
ctx.
|
|
830
|
+
const outcome = resolveModelSwitch({
|
|
831
|
+
targetModel: intent.modelId,
|
|
832
|
+
currentModel: ctx.currentModel,
|
|
833
|
+
provider: ctx.currentProvider,
|
|
834
|
+
knownModels: models.map((m) => m.id),
|
|
835
|
+
messageCount: ctx.sessions.current?.messages.length ?? 0
|
|
836
|
+
});
|
|
837
|
+
if (outcome.status === "unchanged") {
|
|
838
|
+
ctx.send({ type: "info", message: outcome.message });
|
|
777
839
|
return;
|
|
778
840
|
}
|
|
779
|
-
ctx.currentModel =
|
|
841
|
+
ctx.currentModel = outcome.model;
|
|
780
842
|
ctx.updateContextWindow();
|
|
781
|
-
ctx
|
|
843
|
+
syncSessionProvider(ctx);
|
|
844
|
+
ctx.send({
|
|
845
|
+
type: "info",
|
|
846
|
+
message: outcome.warning ? `${outcome.message} \u2014 ${outcome.warning}` : outcome.message
|
|
847
|
+
});
|
|
782
848
|
ctx.sendStatus();
|
|
783
849
|
}
|
|
784
850
|
async function handleThink(args, ctx) {
|
|
@@ -788,7 +854,7 @@ async function handleThink(args, ctx) {
|
|
|
788
854
|
runtimeEffort: ctx.runtimeThinkingEffort,
|
|
789
855
|
configuredThinking: modelParams?.thinking,
|
|
790
856
|
configuredEffort: modelParams?.thinkingEffort,
|
|
791
|
-
supportsEffort: ctx.providers.get(ctx.currentProvider)
|
|
857
|
+
supportsEffort: ctx.providers.has(ctx.currentProvider) ? ctx.providers.get(ctx.currentProvider).supportsReasoningEffort : false,
|
|
792
858
|
provider: ctx.currentProvider
|
|
793
859
|
});
|
|
794
860
|
if (outcome.changed) {
|
|
@@ -802,24 +868,59 @@ async function handleThink(args, ctx) {
|
|
|
802
868
|
if (outcome.changed) ctx.sendStatus();
|
|
803
869
|
}
|
|
804
870
|
async function handlePlan(args, ctx) {
|
|
805
|
-
const
|
|
806
|
-
if (
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
871
|
+
const outcome = applyPlanCommand(args[0], ctx.planMode);
|
|
872
|
+
if (outcome.changed) ctx.planMode = outcome.planMode;
|
|
873
|
+
ctx.send({
|
|
874
|
+
type: outcome.status === "unknown" ? "error" : "info",
|
|
875
|
+
message: [outcome.summary, ...outcome.details].join(" \u2014 ")
|
|
876
|
+
});
|
|
877
|
+
if (outcome.changed) ctx.sendStatus();
|
|
878
|
+
}
|
|
879
|
+
async function handleRoute(args, ctx) {
|
|
880
|
+
const intent = parseRouteCommand(args);
|
|
881
|
+
const routing = ctx.config.get("routing");
|
|
882
|
+
if (intent.kind === "enable" || intent.kind === "disable") {
|
|
883
|
+
const on = intent.kind === "enable";
|
|
884
|
+
ctx.config.setByPath("routing.enabled", on ? "true" : "false");
|
|
885
|
+
const note = on ? routingEmptyRulesNote(routing) : null;
|
|
886
|
+
ctx.send({
|
|
887
|
+
type: "info",
|
|
888
|
+
message: `Smart model routing ${on ? "enabled" : "disabled"}.` + (note ? `
|
|
889
|
+
${note}` : "")
|
|
890
|
+
});
|
|
891
|
+
ctx.sendStatus();
|
|
814
892
|
return;
|
|
815
|
-
}
|
|
816
|
-
|
|
893
|
+
}
|
|
894
|
+
if (intent.kind === "usage" || intent.kind === "unknown") {
|
|
895
|
+
ctx.send({ type: "error", message: intent.message });
|
|
817
896
|
return;
|
|
897
|
+
}
|
|
898
|
+
if (intent.kind === "test") {
|
|
899
|
+
const decision = ctx.computeRoutingDecision(intent.message);
|
|
900
|
+
ctx.send({
|
|
901
|
+
type: "info",
|
|
902
|
+
message: routeDecisionRows(intent.message, ctx.currentModel, decision).map((row) => `${row.label}: ${row.value}`).join("\n")
|
|
903
|
+
});
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
const view = describeRouting({ routing, provider: ctx.currentProvider, currentModel: ctx.currentModel });
|
|
907
|
+
const lines = [
|
|
908
|
+
"Smart Model Routing",
|
|
909
|
+
`Status: ${view.enabled ? "enabled" : "disabled"}`,
|
|
910
|
+
`Provider: ${view.provider}`,
|
|
911
|
+
`Current: ${view.currentModel}`
|
|
912
|
+
];
|
|
913
|
+
if (view.fallback) lines.push(`Fallback: ${view.fallback}`);
|
|
914
|
+
if (view.noRulesNote) {
|
|
915
|
+
lines.push(view.noRulesNote);
|
|
818
916
|
} else {
|
|
819
|
-
|
|
820
|
-
|
|
917
|
+
lines.push("Rules (evaluated top-to-bottom):");
|
|
918
|
+
for (const rule of view.rules) {
|
|
919
|
+
lines.push(` #${rule.index} ${rule.name ? `${rule.name} ` : ""}${rule.condition} \u2192 ${rule.model}`);
|
|
920
|
+
}
|
|
821
921
|
}
|
|
822
|
-
|
|
922
|
+
lines.push(view.hint);
|
|
923
|
+
ctx.send({ type: "info", message: lines.join("\n") });
|
|
823
924
|
}
|
|
824
925
|
|
|
825
926
|
// src/web/commands/_shared.ts
|
|
@@ -863,7 +964,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
863
964
|
Cost: ${formatCost(cost)}` : "";
|
|
864
965
|
let memoryLine = "";
|
|
865
966
|
try {
|
|
866
|
-
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-
|
|
967
|
+
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-KSZKM4JG.js");
|
|
867
968
|
const pending = countPendingMemories2(ctx.config.getConfigDir());
|
|
868
969
|
if (pending > 0) memoryLine = `
|
|
869
970
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -906,11 +1007,17 @@ async function handleSession(args, ctx) {
|
|
|
906
1007
|
ctx.sendSessionList();
|
|
907
1008
|
return;
|
|
908
1009
|
}
|
|
909
|
-
const
|
|
910
|
-
|
|
911
|
-
|
|
1010
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "most-recent");
|
|
1011
|
+
if (ref.status === "ok") {
|
|
1012
|
+
const found = ref.match;
|
|
912
1013
|
ctx.sessions.loadSession(found.id);
|
|
913
1014
|
ctx.resetWebSessionUsage();
|
|
1015
|
+
if (ref.message) {
|
|
1016
|
+
ctx.send({
|
|
1017
|
+
type: "info",
|
|
1018
|
+
message: [ref.message, ...ref.ambiguousWith.slice(0, 5).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
914
1021
|
ctx.send({ type: "info", message: `Loaded session: ${found.id.slice(0, 8)} "${found.title ?? ""}" (${found.messageCount} messages)` });
|
|
915
1022
|
const loadedSession = ctx.sessions.current;
|
|
916
1023
|
if (loadedSession && loadedSession.messages.length > 0) {
|
|
@@ -940,52 +1047,81 @@ async function handleSession(args, ctx) {
|
|
|
940
1047
|
return;
|
|
941
1048
|
}
|
|
942
1049
|
if (sub === "list") {
|
|
943
|
-
|
|
1050
|
+
if (args.length <= 1) {
|
|
1051
|
+
ctx.sendSessionList();
|
|
1052
|
+
return;
|
|
1053
|
+
}
|
|
1054
|
+
const opts = parseSessionListArgs(args);
|
|
1055
|
+
const all = ctx.sessions.listSessions({ includeFileSize: sessionListNeedsFileSize(opts) });
|
|
1056
|
+
if (all.length === 0) {
|
|
1057
|
+
ctx.send({ type: "info", message: "No saved sessions." });
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
const view = selectSessions(all, opts);
|
|
1061
|
+
if (view.totalCount === 0) {
|
|
1062
|
+
ctx.send({
|
|
1063
|
+
type: "info",
|
|
1064
|
+
message: [...opts.warnings.map((w) => `\u26A0 ${w}`), "No sessions match the filter criteria."].join("\n")
|
|
1065
|
+
});
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
1068
|
+
if (opts.json) {
|
|
1069
|
+
ctx.send({
|
|
1070
|
+
type: "info",
|
|
1071
|
+
message: JSON.stringify(view.shown.map((s) => sessionListJsonRow(s, view.needsFileSize)), null, 2)
|
|
1072
|
+
});
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const lines = [
|
|
1076
|
+
...opts.warnings.map((w) => `\u26A0 ${w}`),
|
|
1077
|
+
...view.shown.map((s) => formatSessionSummaryLine(s)),
|
|
1078
|
+
`\u2500\u2500 ${sessionListSummary(view)}`
|
|
1079
|
+
];
|
|
1080
|
+
if (view.shown.length < view.totalCount) lines.push("Use --all to show all, or --limit N to change count.");
|
|
1081
|
+
ctx.send({ type: "info", message: lines.join("\n") });
|
|
944
1082
|
return;
|
|
945
1083
|
}
|
|
946
1084
|
if (sub === "delete" && args[1]) {
|
|
947
1085
|
const targetId = args[1];
|
|
948
1086
|
if (targetId === "--filter") {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const val = args[i + 1];
|
|
953
|
-
i++;
|
|
954
|
-
const eq = val.indexOf("=");
|
|
955
|
-
if (eq > 0) {
|
|
956
|
-
const key = val.slice(0, eq);
|
|
957
|
-
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
958
|
-
if (key === "messages") {
|
|
959
|
-
const n = Number(vals[0]);
|
|
960
|
-
if (Number.isFinite(n) && n >= 0) filterMessages = n;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
}
|
|
965
|
-
if (filterMessages === void 0) {
|
|
966
|
-
ctx.send({ type: "error", message: "Usage: /session delete --filter messages=N" });
|
|
1087
|
+
const opts = parseBatchDeleteArgs(args);
|
|
1088
|
+
if (opts.error) {
|
|
1089
|
+
ctx.send({ type: "error", message: opts.error });
|
|
967
1090
|
return;
|
|
968
1091
|
}
|
|
969
|
-
const
|
|
970
|
-
const matches = list2.filter((s) => s.messageCount === filterMessages);
|
|
1092
|
+
const matches = ctx.sessions.listSessions().filter((s) => s.messageCount === opts.messages);
|
|
971
1093
|
if (matches.length === 0) {
|
|
972
|
-
ctx.send({ type: "info", message: `No sessions with ${
|
|
1094
|
+
ctx.send({ type: "info", message: `No sessions with ${opts.messages} message(s) found.` });
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
const preview = [
|
|
1098
|
+
`Found ${matches.length} session(s) with ${opts.messages} message(s):`,
|
|
1099
|
+
...matches.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
|
|
1100
|
+
...matches.length > 20 ? [` ... and ${matches.length - 20} more`] : []
|
|
1101
|
+
];
|
|
1102
|
+
if (opts.dryRun) {
|
|
1103
|
+
ctx.send({
|
|
1104
|
+
type: "info",
|
|
1105
|
+
message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
|
|
1106
|
+
});
|
|
973
1107
|
return;
|
|
974
1108
|
}
|
|
975
1109
|
let deleted = 0;
|
|
976
1110
|
let failed = 0;
|
|
977
1111
|
for (const s of matches) {
|
|
978
|
-
if (ctx.sessions.deleteSession(s.id))
|
|
979
|
-
|
|
980
|
-
} else {
|
|
981
|
-
failed++;
|
|
982
|
-
}
|
|
1112
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
1113
|
+
else failed++;
|
|
983
1114
|
}
|
|
984
1115
|
if (!ctx.sessions.current) {
|
|
985
|
-
ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1116
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1117
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
986
1118
|
ctx.resetWebSessionUsage();
|
|
987
1119
|
}
|
|
988
|
-
ctx.send({
|
|
1120
|
+
ctx.send({
|
|
1121
|
+
type: "info",
|
|
1122
|
+
message: [...preview, `Deleted ${deleted} session(s)${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
|
|
1123
|
+
});
|
|
1124
|
+
ctx.sendStatus();
|
|
989
1125
|
ctx.sendSessionList();
|
|
990
1126
|
return;
|
|
991
1127
|
}
|
|
@@ -994,20 +1130,79 @@ async function handleSession(args, ctx) {
|
|
|
994
1130
|
ctx.unsavedSessions.delete(cachedKey);
|
|
995
1131
|
if (ctx.sessions.current?.id === cachedKey) {
|
|
996
1132
|
ctx.sessions.clearCurrent();
|
|
1133
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1134
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
1135
|
+
ctx.resetWebSessionUsage();
|
|
1136
|
+
ctx.sendStatus();
|
|
997
1137
|
}
|
|
998
1138
|
ctx.send({ type: "info", message: `Deleted session: ${cachedKey.slice(0, 8)}` });
|
|
999
1139
|
ctx.sendSessionList();
|
|
1000
1140
|
return;
|
|
1001
1141
|
}
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
if (found) {
|
|
1005
|
-
ctx.sessions.deleteSession(found.id);
|
|
1006
|
-
ctx.send({ type: "info", message: `Deleted session: ${found.id.slice(0, 8)}` });
|
|
1007
|
-
ctx.sendSessionList();
|
|
1008
|
-
} else {
|
|
1142
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
|
|
1143
|
+
if (ref.status === "not-found") {
|
|
1009
1144
|
ctx.send({ type: "error", message: `Session not found: ${targetId}` });
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
if (ref.status === "ambiguous") {
|
|
1148
|
+
ctx.send({
|
|
1149
|
+
type: "error",
|
|
1150
|
+
message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
1151
|
+
});
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
const wasCurrent = ctx.sessions.current?.id === ref.match.id;
|
|
1155
|
+
if (!ctx.sessions.deleteSession(ref.match.id)) {
|
|
1156
|
+
ctx.send({ type: "error", message: "Delete failed \u2014 session file not found on disk." });
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
ctx.send({ type: "info", message: `Deleted session: ${ref.match.id.slice(0, 8)}` });
|
|
1160
|
+
if (wasCurrent) {
|
|
1161
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1162
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
1163
|
+
ctx.resetWebSessionUsage();
|
|
1164
|
+
ctx.send({ type: "info", message: "Current session was deleted \u2014 started a fresh session." });
|
|
1165
|
+
ctx.sendStatus();
|
|
1166
|
+
}
|
|
1167
|
+
ctx.sendSessionList();
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
if (sub === "clean") {
|
|
1171
|
+
const opts = parseCleanArgs(args);
|
|
1172
|
+
const stale = selectStaleSessions(ctx.sessions.listSessions(), opts.staleDays);
|
|
1173
|
+
if (stale.length === 0) {
|
|
1174
|
+
ctx.send({ type: "info", message: `No sessions older than ${opts.staleDays} days found.` });
|
|
1175
|
+
return;
|
|
1010
1176
|
}
|
|
1177
|
+
const preview = [
|
|
1178
|
+
`Found ${stale.length} session(s) not updated in ${opts.staleDays}+ days:`,
|
|
1179
|
+
...stale.slice(0, 20).map((s) => ` ${formatSessionSummaryLine(s)}`),
|
|
1180
|
+
...stale.length > 20 ? [` ... and ${stale.length - 20} more`] : []
|
|
1181
|
+
];
|
|
1182
|
+
if (opts.dryRun) {
|
|
1183
|
+
ctx.send({
|
|
1184
|
+
type: "info",
|
|
1185
|
+
message: [...preview, "--dry-run: no sessions were deleted. Remove --dry-run to actually delete."].join("\n")
|
|
1186
|
+
});
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
let deleted = 0;
|
|
1190
|
+
let failed = 0;
|
|
1191
|
+
for (const s of stale) {
|
|
1192
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
1193
|
+
else failed++;
|
|
1194
|
+
}
|
|
1195
|
+
if (!ctx.sessions.current) {
|
|
1196
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1197
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
1198
|
+
ctx.resetWebSessionUsage();
|
|
1199
|
+
ctx.sendStatus();
|
|
1200
|
+
}
|
|
1201
|
+
ctx.send({
|
|
1202
|
+
type: "info",
|
|
1203
|
+
message: [...preview, `Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`].join("\n")
|
|
1204
|
+
});
|
|
1205
|
+
ctx.sendSessionList();
|
|
1011
1206
|
return;
|
|
1012
1207
|
}
|
|
1013
1208
|
if (sub === "batch-delete") {
|
|
@@ -1031,6 +1226,12 @@ async function handleSession(args, ctx) {
|
|
|
1031
1226
|
deleted++;
|
|
1032
1227
|
}
|
|
1033
1228
|
}
|
|
1229
|
+
if (!ctx.sessions.current) {
|
|
1230
|
+
const created = ctx.sessions.createSession(ctx.currentProvider, ctx.currentModel);
|
|
1231
|
+
ctx.unsavedSessions.set(created.id, created);
|
|
1232
|
+
ctx.resetWebSessionUsage();
|
|
1233
|
+
ctx.sendStatus();
|
|
1234
|
+
}
|
|
1034
1235
|
ctx.send({ type: "info", message: `Deleted ${deleted} session(s).` });
|
|
1035
1236
|
ctx.sendSessionList();
|
|
1036
1237
|
return;
|
|
@@ -1044,26 +1245,40 @@ async function handleSession(args, ctx) {
|
|
|
1044
1245
|
}
|
|
1045
1246
|
const cachedKey = ctx.unsavedSessions.has(targetId) ? targetId : [...ctx.unsavedSessions.keys()].find((k) => k.startsWith(targetId));
|
|
1046
1247
|
if (cachedKey) {
|
|
1047
|
-
const
|
|
1048
|
-
|
|
1248
|
+
const session2 = ctx.unsavedSessions.get(cachedKey);
|
|
1249
|
+
session2.title = newTitle;
|
|
1049
1250
|
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
1050
1251
|
ctx.sendSessionList();
|
|
1051
1252
|
return;
|
|
1052
1253
|
}
|
|
1053
|
-
const
|
|
1054
|
-
|
|
1055
|
-
if (found) {
|
|
1056
|
-
const session = ctx.sessions.loadSession(found.id);
|
|
1057
|
-
session.title = newTitle;
|
|
1058
|
-
ctx.sessions.save();
|
|
1059
|
-
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
1060
|
-
ctx.sendSessionList();
|
|
1061
|
-
} else {
|
|
1254
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), targetId, "strict");
|
|
1255
|
+
if (ref.status === "not-found") {
|
|
1062
1256
|
ctx.send({ type: "error", message: `Session not found: ${targetId}` });
|
|
1257
|
+
return;
|
|
1063
1258
|
}
|
|
1259
|
+
if (ref.status === "ambiguous") {
|
|
1260
|
+
ctx.send({
|
|
1261
|
+
type: "error",
|
|
1262
|
+
message: [ref.message, ...ref.matches.slice(0, 10).map((m) => ` ${formatSessionSummaryLine(m)}`)].join("\n")
|
|
1263
|
+
});
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
const priorId = ctx.sessions.current?.id ?? null;
|
|
1267
|
+
const isCurrent = priorId === ref.match.id;
|
|
1268
|
+
const session = isCurrent ? ctx.sessions.current : ctx.sessions.loadSession(ref.match.id);
|
|
1269
|
+
session.title = newTitle;
|
|
1270
|
+
ctx.sessions.save();
|
|
1271
|
+
if (!isCurrent && priorId) {
|
|
1272
|
+
ctx.sessions.loadSession(priorId);
|
|
1273
|
+
}
|
|
1274
|
+
ctx.send({ type: "info", message: `Renamed session: "${newTitle}"` });
|
|
1275
|
+
ctx.sendSessionList();
|
|
1064
1276
|
return;
|
|
1065
1277
|
}
|
|
1066
|
-
ctx.send({
|
|
1278
|
+
ctx.send({
|
|
1279
|
+
type: "info",
|
|
1280
|
+
message: "Usage: /session new | list [--filter k=v] [--search kw] [--limit N|--all] [--sort f[:o]] [--json] | load <id> | delete <id> | delete --filter messages=N [--dry-run] | clean --stale N [--dry-run] | rename <id> <title>"
|
|
1281
|
+
});
|
|
1067
1282
|
}
|
|
1068
1283
|
async function handleExport(args, ctx) {
|
|
1069
1284
|
const format = args[0] === "json" ? "json" : "md";
|
|
@@ -1676,7 +1891,7 @@ async function handleTest(args, ctx) {
|
|
|
1676
1891
|
const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
|
|
1677
1892
|
testArgs = isCommand ? { command: argStr } : { filter: argStr };
|
|
1678
1893
|
}
|
|
1679
|
-
const runTests = ctx.runTests ?? (await import("./run-tests-
|
|
1894
|
+
const runTests = ctx.runTests ?? (await import("./run-tests-EL54INOI.js")).executeTests;
|
|
1680
1895
|
const report = await runTests(testArgs);
|
|
1681
1896
|
ctx.send({ type: "info", message: report });
|
|
1682
1897
|
} catch (err) {
|
|
@@ -2012,7 +2227,7 @@ async function handleMemory(args, ctx) {
|
|
|
2012
2227
|
ctx.handleMemoryManage(sub, args[1], sub === "expire" ? args[2] : void 0);
|
|
2013
2228
|
} else if (sub === "export") {
|
|
2014
2229
|
if (args[1] === "md") {
|
|
2015
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
2230
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-KSZKM4JG.js");
|
|
2016
2231
|
ctx.send({
|
|
2017
2232
|
type: "export_data",
|
|
2018
2233
|
format: "md",
|
|
@@ -2266,8 +2481,9 @@ async function handleHelp(_args, ctx) {
|
|
|
2266
2481
|
" /clear \u2014 Clear conversation & start new session",
|
|
2267
2482
|
" /compact [hint] \u2014 Compress conversation history",
|
|
2268
2483
|
" /think [on|off] \u2014 Toggle extended thinking mode",
|
|
2269
|
-
" /plan [
|
|
2270
|
-
" /
|
|
2484
|
+
" /plan [execute|exit|status] \u2014 Read-only planning mode (bare /plan enters it)",
|
|
2485
|
+
" /route [on|off|show|test <msg>] \u2014 Smart model routing",
|
|
2486
|
+
" /session new|list [filters]|load <id>|delete <id>|delete --filter messages=N [--dry-run]|clean --stale N [--dry-run]|rename <id> <title> \u2014 Session management",
|
|
2271
2487
|
" /system [prompt|clear] \u2014 Set/view/reset system prompt",
|
|
2272
2488
|
" /context [status|reload] \u2014 Show/reload context layers",
|
|
2273
2489
|
" /status \u2014 Show session info & token usage",
|
|
@@ -2403,8 +2619,9 @@ var CLI_ONLY_WEB_COMMANDS = /* @__PURE__ */ new Map([
|
|
|
2403
2619
|
["snapshot", "Dev-state snapshots are written when the terminal REPL exits."],
|
|
2404
2620
|
["hooks", "Hook trust is granted per machine from the terminal."],
|
|
2405
2621
|
["hook", "Hook trust is granted per machine from the terminal."],
|
|
2406
|
-
//
|
|
2407
|
-
|
|
2622
|
+
// 以下一条并非「终端才有意义」,而是 Web 侧尚未实现——如实说明,别假装是设计。
|
|
2623
|
+
// (`route` 曾在这里,理由写的是「Web 尚未应用智能路由」;v0.4.269 让 routing 在 Web
|
|
2624
|
+
// 上真正生效之后那句话就不再成立,命令已在 Web 实现,见 commands/provider-commands.ts。)
|
|
2408
2625
|
["security", "Redaction status and toggles are terminal-only for now; /status shows the current profile."]
|
|
2409
2626
|
]);
|
|
2410
2627
|
var webCommandHandlers = {
|
|
@@ -2412,6 +2629,7 @@ var webCommandHandlers = {
|
|
|
2412
2629
|
model: handleModel,
|
|
2413
2630
|
think: handleThink,
|
|
2414
2631
|
plan: handlePlan,
|
|
2632
|
+
route: handleRoute,
|
|
2415
2633
|
clear: handleClear,
|
|
2416
2634
|
compact: handleCompact,
|
|
2417
2635
|
status: handleStatus,
|