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
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,37 @@ import {
|
|
|
14
15
|
costSourceNote,
|
|
15
16
|
decideDeferredSave,
|
|
16
17
|
decideModel,
|
|
18
|
+
describeRouting,
|
|
17
19
|
estimateConversationTokens,
|
|
18
20
|
evaluateContextPressure,
|
|
19
21
|
filterMemoryEntries,
|
|
22
|
+
formatSessionSummaryLine,
|
|
20
23
|
loadDevState,
|
|
24
|
+
parseBatchDeleteArgs,
|
|
25
|
+
parseCleanArgs,
|
|
21
26
|
parseMemoryShowFilters,
|
|
27
|
+
parseModelCommand,
|
|
28
|
+
parseRouteCommand,
|
|
29
|
+
parseSessionListArgs,
|
|
22
30
|
parseSimpleYaml,
|
|
23
31
|
persistToolRound,
|
|
24
32
|
readGitDiff,
|
|
33
|
+
resolveModelSwitch,
|
|
34
|
+
resolveProviderSwitch,
|
|
35
|
+
resolveSessionRef,
|
|
36
|
+
routeDecisionRows,
|
|
37
|
+
routingEmptyRulesNote,
|
|
25
38
|
saveDevState,
|
|
26
39
|
scanProject,
|
|
40
|
+
selectSessions,
|
|
41
|
+
selectStaleSessions,
|
|
27
42
|
sessionHasMeaningfulContent,
|
|
43
|
+
sessionListJsonRow,
|
|
44
|
+
sessionListSummary,
|
|
28
45
|
setupProxy,
|
|
29
46
|
snapshotFile,
|
|
30
47
|
stripRoutingTags
|
|
31
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-7L4TEK7Q.js";
|
|
32
49
|
import {
|
|
33
50
|
CostTracker,
|
|
34
51
|
computeCost,
|
|
@@ -58,7 +75,7 @@ import {
|
|
|
58
75
|
setMaxOutputCap,
|
|
59
76
|
spawnAgentContext,
|
|
60
77
|
undoStack
|
|
61
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-FQJFGGKN.js";
|
|
62
79
|
import {
|
|
63
80
|
buildReviewPrompt,
|
|
64
81
|
buildSecurityReviewPrompt
|
|
@@ -99,7 +116,7 @@ import {
|
|
|
99
116
|
touchMemoryReferences,
|
|
100
117
|
updateMemoryApproval,
|
|
101
118
|
updateMemoryEntry
|
|
102
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-6WMT7OQG.js";
|
|
103
120
|
import "./chunk-4DEMGCK4.js";
|
|
104
121
|
import "./chunk-UUSRWSSX.js";
|
|
105
122
|
import "./chunk-CKH4KQ4E.js";
|
|
@@ -123,7 +140,7 @@ import {
|
|
|
123
140
|
formatDoctorReport,
|
|
124
141
|
loadContextFiles,
|
|
125
142
|
writeCrashLog
|
|
126
|
-
} from "./chunk-
|
|
143
|
+
} from "./chunk-JLOQBYU4.js";
|
|
127
144
|
import {
|
|
128
145
|
describePlugin,
|
|
129
146
|
getActivePluginAssets,
|
|
@@ -140,14 +157,14 @@ import {
|
|
|
140
157
|
trustHook,
|
|
141
158
|
trustPlugin,
|
|
142
159
|
untrustHook
|
|
143
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-IIXZ7IPN.js";
|
|
144
161
|
import {
|
|
145
162
|
ProviderRegistry,
|
|
146
163
|
listBuiltInProviderMetadata
|
|
147
164
|
} from "./chunk-UGY5SVNX.js";
|
|
148
165
|
import {
|
|
149
166
|
ConfigManager
|
|
150
|
-
} from "./chunk-
|
|
167
|
+
} from "./chunk-UD3BVNC5.js";
|
|
151
168
|
import {
|
|
152
169
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
153
170
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -185,7 +202,7 @@ import {
|
|
|
185
202
|
import {
|
|
186
203
|
fileCheckpoints
|
|
187
204
|
} from "./chunk-4BKXL7SM.js";
|
|
188
|
-
import "./chunk-
|
|
205
|
+
import "./chunk-NZPHEUJM.js";
|
|
189
206
|
import {
|
|
190
207
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
191
208
|
AUTHOR,
|
|
@@ -203,7 +220,7 @@ import {
|
|
|
203
220
|
SKILLS_DIR_NAME,
|
|
204
221
|
VERSION,
|
|
205
222
|
buildUserIdentityPrompt
|
|
206
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-2BKRWTEQ.js";
|
|
207
224
|
|
|
208
225
|
// src/index.ts
|
|
209
226
|
import { program } from "commander";
|
|
@@ -722,7 +739,6 @@ import { platform } from "os";
|
|
|
722
739
|
|
|
723
740
|
// src/repl/commands/constants.ts
|
|
724
741
|
var SESSION_PAGE_SIZE = 20;
|
|
725
|
-
var DEFAULT_SESSION_LIST_LIMIT = 50;
|
|
726
742
|
var MAX_TITLE_WIDTH = 40;
|
|
727
743
|
|
|
728
744
|
// src/repl/commands/utils.ts
|
|
@@ -801,73 +817,6 @@ function formatSessionDate(date) {
|
|
|
801
817
|
if (diffDays < 7) return `${abs} (${diffDays} days ago)`;
|
|
802
818
|
return abs;
|
|
803
819
|
}
|
|
804
|
-
function parseSessionListArgs(args) {
|
|
805
|
-
let limit = DEFAULT_SESSION_LIST_LIMIT;
|
|
806
|
-
let all = false;
|
|
807
|
-
const filter = {};
|
|
808
|
-
const warnings = [];
|
|
809
|
-
let search = null;
|
|
810
|
-
let days = null;
|
|
811
|
-
let since = null;
|
|
812
|
-
let sort = { field: "updated", order: "desc" };
|
|
813
|
-
let json = false;
|
|
814
|
-
let stale = null;
|
|
815
|
-
let verbose = false;
|
|
816
|
-
for (let i = 1; i < args.length; i++) {
|
|
817
|
-
const a = args[i];
|
|
818
|
-
if (a === "--all" || a === "-a") {
|
|
819
|
-
all = true;
|
|
820
|
-
} else if ((a === "--limit" || a === "-n") && i + 1 < args.length) {
|
|
821
|
-
const n = Number(args[i + 1]);
|
|
822
|
-
if (Number.isFinite(n) && n > 0) {
|
|
823
|
-
limit = n;
|
|
824
|
-
i++;
|
|
825
|
-
}
|
|
826
|
-
} else if (a === "--filter" && i + 1 < args.length) {
|
|
827
|
-
const val = args[++i];
|
|
828
|
-
const eq = val.indexOf("=");
|
|
829
|
-
if (eq > 0) {
|
|
830
|
-
const key = val.slice(0, eq);
|
|
831
|
-
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
832
|
-
if (key === "provider") filter.provider = vals;
|
|
833
|
-
else if (key === "model") filter.model = vals;
|
|
834
|
-
else if (key === "messages") {
|
|
835
|
-
const n = Number(vals[0]);
|
|
836
|
-
if (Number.isFinite(n) && n >= 0) filter.messages = n;
|
|
837
|
-
else warnings.push(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
|
|
838
|
-
} else {
|
|
839
|
-
warnings.push(`Unknown filter key: "${key}". Supported keys: provider, model, messages`);
|
|
840
|
-
}
|
|
841
|
-
} else {
|
|
842
|
-
warnings.push(`Invalid --filter syntax: "${val}". Expected key=value`);
|
|
843
|
-
}
|
|
844
|
-
} else if ((a === "--search" || a === "-s") && i + 1 < args.length) {
|
|
845
|
-
search = args[++i];
|
|
846
|
-
} else if (a === "--days" && i + 1 < args.length) {
|
|
847
|
-
const n = Number(args[++i]);
|
|
848
|
-
if (Number.isFinite(n) && n > 0) days = n;
|
|
849
|
-
} else if (a === "--since" && i + 1 < args.length) {
|
|
850
|
-
since = args[++i];
|
|
851
|
-
} else if (a === "--sort" && i + 1 < args.length) {
|
|
852
|
-
const sv = args[++i];
|
|
853
|
-
const colon = sv.indexOf(":");
|
|
854
|
-
const field = colon > 0 ? sv.slice(0, colon) : sv;
|
|
855
|
-
const order = colon > 0 ? sv.slice(colon + 1) : "desc";
|
|
856
|
-
if (field === "updated" || field === "created" || field === "messages" || field === "size") {
|
|
857
|
-
sort = { field, order: order === "asc" ? "asc" : "desc" };
|
|
858
|
-
}
|
|
859
|
-
} else if (a === "--json") {
|
|
860
|
-
json = true;
|
|
861
|
-
} else if (a === "--verbose" || a === "-v") {
|
|
862
|
-
verbose = true;
|
|
863
|
-
} else if (a === "--stale" && i + 1 < args.length) {
|
|
864
|
-
const n = Number(args[++i]);
|
|
865
|
-
if (Number.isFinite(n) && n > 0) stale = n;
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
if (all) limit = -1;
|
|
869
|
-
return { limit, all, filter, search, days, since, sort, json, stale, verbose, warnings };
|
|
870
|
-
}
|
|
871
820
|
function renderTranscriptMessage(msg, renderer) {
|
|
872
821
|
if (msg.role === "user") {
|
|
873
822
|
const text = getContentText(msg.content);
|
|
@@ -979,34 +928,41 @@ function createProviderCommands() {
|
|
|
979
928
|
} else {
|
|
980
929
|
targetId = args[0];
|
|
981
930
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (
|
|
990
|
-
|
|
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;
|
|
931
|
+
const configured = ctx.providers.has(targetId);
|
|
932
|
+
let availableModels = [];
|
|
933
|
+
let providerDefaultModel = "";
|
|
934
|
+
if (configured) {
|
|
935
|
+
const target = ctx.providers.get(targetId);
|
|
936
|
+
providerDefaultModel = target.info.defaultModel;
|
|
937
|
+
availableModels = target.info.models.map((m) => m.id);
|
|
938
|
+
if (availableModels.length === 0) {
|
|
939
|
+
availableModels = (await target.listModels()).map((m) => m.id);
|
|
994
940
|
}
|
|
995
941
|
}
|
|
996
|
-
|
|
997
|
-
|
|
942
|
+
const session = ctx.sessions.current;
|
|
943
|
+
const outcome = resolveProviderSwitch({
|
|
944
|
+
targetId,
|
|
945
|
+
currentProvider: ctx.getCurrentProvider(),
|
|
946
|
+
configured,
|
|
947
|
+
availableModels,
|
|
948
|
+
configuredDefaultModel: ctx.config.get("defaultModels")[targetId],
|
|
949
|
+
providerDefaultModel,
|
|
950
|
+
messageCount: session?.messages.length ?? 0
|
|
951
|
+
});
|
|
952
|
+
if (outcome.status === "not-configured" || outcome.status === "no-models") {
|
|
953
|
+
ctx.renderer.renderError(outcome.message);
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
if (outcome.status === "unchanged") {
|
|
957
|
+
ctx.renderer.printInfo(outcome.message);
|
|
998
958
|
return;
|
|
999
959
|
}
|
|
1000
|
-
|
|
1001
|
-
const msgCount = session?.messages.length ?? 0;
|
|
1002
|
-
ctx.setProvider(targetId);
|
|
960
|
+
ctx.setProvider(outcome.providerId, outcome.model);
|
|
1003
961
|
if (session) {
|
|
1004
|
-
session.updateProvider(
|
|
962
|
+
session.updateProvider(outcome.providerId, outcome.model);
|
|
1005
963
|
await ctx.sessions.save();
|
|
1006
964
|
}
|
|
1007
|
-
ctx.renderer.printSuccess(
|
|
1008
|
-
`Switched to provider: ${targetId}` + (msgCount > 0 ? ` (conversation preserved: ${msgCount} messages)` : "")
|
|
1009
|
-
);
|
|
965
|
+
ctx.renderer.printSuccess(outcome.message);
|
|
1010
966
|
}
|
|
1011
967
|
},
|
|
1012
968
|
{
|
|
@@ -1014,29 +970,29 @@ function createProviderCommands() {
|
|
|
1014
970
|
description: "Switch model, refresh live model list, or inspect model cache",
|
|
1015
971
|
usage: "/model [name|refresh [provider]|cache [clear [provider]]]",
|
|
1016
972
|
async execute(args, ctx) {
|
|
1017
|
-
const
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
ctx.renderer.printInfo(`Provider is not configured: ${providerId}`);
|
|
973
|
+
const intent = parseModelCommand(args, ctx.getCurrentProvider());
|
|
974
|
+
if (intent.kind === "refresh") {
|
|
975
|
+
if (!ctx.providers.has(intent.providerId)) {
|
|
976
|
+
ctx.renderer.printInfo(`Provider is not configured: ${intent.providerId}`);
|
|
1022
977
|
return;
|
|
1023
978
|
}
|
|
1024
|
-
ctx.renderer.printInfo(`Refreshing models for ${providerId}...`);
|
|
979
|
+
ctx.renderer.printInfo(`Refreshing models for ${intent.providerId}...`);
|
|
1025
980
|
try {
|
|
1026
|
-
const models = await ctx.providers.refreshModels(providerId);
|
|
1027
|
-
ctx.renderer.printSuccess(`Refreshed ${models.length} model(s) for ${providerId}.`);
|
|
981
|
+
const models = await ctx.providers.refreshModels(intent.providerId);
|
|
982
|
+
ctx.renderer.printSuccess(`Refreshed ${models.length} model(s) for ${intent.providerId}.`);
|
|
1028
983
|
} catch (err) {
|
|
1029
984
|
ctx.renderer.printInfo(`Model refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1030
985
|
}
|
|
1031
986
|
return;
|
|
1032
987
|
}
|
|
1033
|
-
if (
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
988
|
+
if (intent.kind === "cache-clear") {
|
|
989
|
+
ctx.providers.clearModelCache(intent.providerId);
|
|
990
|
+
ctx.renderer.printSuccess(
|
|
991
|
+
intent.providerId ? `Cleared model cache for ${intent.providerId}.` : "Cleared model cache."
|
|
992
|
+
);
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (intent.kind === "cache-show") {
|
|
1040
996
|
const rows = ctx.providers.getModelCacheStatus();
|
|
1041
997
|
if (rows.length === 0) {
|
|
1042
998
|
ctx.renderer.printInfo("Model cache is empty. Use /model refresh to populate it.");
|
|
@@ -1048,9 +1004,11 @@ function createProviderCommands() {
|
|
|
1048
1004
|
);
|
|
1049
1005
|
return;
|
|
1050
1006
|
}
|
|
1007
|
+
let knownModels = ctx.providers.has(ctx.getCurrentProvider()) ? ctx.providers.get(ctx.getCurrentProvider()).info.models.map((m) => m.id) : [];
|
|
1051
1008
|
let targetModel;
|
|
1052
|
-
if (
|
|
1009
|
+
if (intent.kind === "select") {
|
|
1053
1010
|
const models = await ctx.providers.listModels(ctx.getCurrentProvider());
|
|
1011
|
+
knownModels = models.map((m) => m.id);
|
|
1054
1012
|
const currentModel = ctx.getCurrentModel();
|
|
1055
1013
|
const items = models.map((m) => ({
|
|
1056
1014
|
value: m.id,
|
|
@@ -1069,22 +1027,27 @@ function createProviderCommands() {
|
|
|
1069
1027
|
if (!chosen) return;
|
|
1070
1028
|
targetModel = chosen;
|
|
1071
1029
|
} else {
|
|
1072
|
-
targetModel =
|
|
1030
|
+
targetModel = intent.modelId;
|
|
1073
1031
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1032
|
+
const session = ctx.sessions.current;
|
|
1033
|
+
const outcome = resolveModelSwitch({
|
|
1034
|
+
targetModel,
|
|
1035
|
+
currentModel: ctx.getCurrentModel(),
|
|
1036
|
+
provider: ctx.getCurrentProvider(),
|
|
1037
|
+
knownModels,
|
|
1038
|
+
messageCount: session?.messages.length ?? 0
|
|
1039
|
+
});
|
|
1040
|
+
if (outcome.status === "unchanged") {
|
|
1041
|
+
ctx.renderer.printInfo(outcome.message);
|
|
1076
1042
|
return;
|
|
1077
1043
|
}
|
|
1078
|
-
|
|
1079
|
-
const msgCount = session?.messages.length ?? 0;
|
|
1080
|
-
ctx.setProvider(ctx.getCurrentProvider(), targetModel);
|
|
1044
|
+
ctx.setProvider(ctx.getCurrentProvider(), outcome.model);
|
|
1081
1045
|
if (session) {
|
|
1082
|
-
session.updateProvider(ctx.getCurrentProvider(),
|
|
1046
|
+
session.updateProvider(ctx.getCurrentProvider(), outcome.model);
|
|
1083
1047
|
await ctx.sessions.save();
|
|
1084
1048
|
}
|
|
1085
|
-
ctx.renderer.printSuccess(
|
|
1086
|
-
|
|
1087
|
-
);
|
|
1049
|
+
ctx.renderer.printSuccess(outcome.message);
|
|
1050
|
+
if (outcome.warning) console.log(theme.warning(` ${outcome.warning}`));
|
|
1088
1051
|
}
|
|
1089
1052
|
},
|
|
1090
1053
|
{
|
|
@@ -1092,72 +1055,61 @@ function createProviderCommands() {
|
|
|
1092
1055
|
description: "Smart model routing \u2014 enable/disable or inspect routing rules",
|
|
1093
1056
|
usage: "/route [on|off|show|test <message>]",
|
|
1094
1057
|
async execute(args, ctx) {
|
|
1095
|
-
const
|
|
1058
|
+
const intent = parseRouteCommand(args);
|
|
1096
1059
|
const routing = ctx.config.get("routing");
|
|
1097
|
-
if (
|
|
1060
|
+
if (intent.kind === "enable") {
|
|
1098
1061
|
ctx.config.setByPath("routing.enabled", "true");
|
|
1099
1062
|
ctx.renderer.printSuccess("Smart model routing enabled.");
|
|
1100
|
-
|
|
1101
|
-
|
|
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
|
-
}
|
|
1063
|
+
const note = routingEmptyRulesNote(routing);
|
|
1064
|
+
if (note) ctx.renderer.printInfo(note);
|
|
1105
1065
|
return;
|
|
1106
1066
|
}
|
|
1107
|
-
if (
|
|
1067
|
+
if (intent.kind === "disable") {
|
|
1108
1068
|
ctx.config.setByPath("routing.enabled", "false");
|
|
1109
1069
|
ctx.renderer.printSuccess("Smart model routing disabled.");
|
|
1110
1070
|
return;
|
|
1111
1071
|
}
|
|
1112
|
-
if (
|
|
1113
|
-
|
|
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();
|
|
1072
|
+
if (intent.kind === "usage" || intent.kind === "unknown") {
|
|
1073
|
+
console.log(theme.warning(` ${intent.message}`));
|
|
1129
1074
|
return;
|
|
1130
1075
|
}
|
|
1131
|
-
if (
|
|
1132
|
-
|
|
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
|
-
}
|
|
1076
|
+
if (intent.kind === "test") {
|
|
1077
|
+
const decision = ctx.computeRoutingDecision(intent.message);
|
|
1140
1078
|
console.log();
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
console.log(` ${
|
|
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
|
-
});
|
|
1079
|
+
for (const row of routeDecisionRows(intent.message, ctx.getCurrentModel(), decision)) {
|
|
1080
|
+
const pad = `${row.label}:`.padEnd(10);
|
|
1081
|
+
const value = row.label === "Input" || row.label === "Reason" || row.label === "Rule" ? theme.dim(row.value) : theme.info(row.value);
|
|
1082
|
+
console.log(` ${pad}${value}`);
|
|
1154
1083
|
}
|
|
1155
1084
|
console.log();
|
|
1156
|
-
console.log(` ${theme.dim("Commands: /route on | off | test <msg> | show")}`);
|
|
1157
|
-
console.log();
|
|
1158
1085
|
return;
|
|
1159
1086
|
}
|
|
1160
|
-
|
|
1087
|
+
const view = describeRouting({
|
|
1088
|
+
routing,
|
|
1089
|
+
provider: ctx.getCurrentProvider(),
|
|
1090
|
+
currentModel: ctx.getCurrentModel()
|
|
1091
|
+
});
|
|
1092
|
+
console.log();
|
|
1093
|
+
console.log(` ${theme.heading("Smart Model Routing")}`);
|
|
1094
|
+
console.log(` Status: ${view.enabled ? theme.success("enabled") : theme.dim("disabled")}`);
|
|
1095
|
+
console.log(` Provider: ${theme.info(view.provider)}`);
|
|
1096
|
+
console.log(` Current: ${theme.info(view.currentModel)}`);
|
|
1097
|
+
if (view.fallback) console.log(` Fallback: ${theme.info(view.fallback)}`);
|
|
1098
|
+
console.log();
|
|
1099
|
+
if (view.noRulesNote) {
|
|
1100
|
+
console.log(` ${theme.dim(view.noRulesNote)}`);
|
|
1101
|
+
} else {
|
|
1102
|
+
console.log(` ${theme.heading("Rules")} ${theme.dim(`(evaluated top-to-bottom)`)}:`);
|
|
1103
|
+
for (const rule of view.rules) {
|
|
1104
|
+
const cond = rule.empty ? theme.warning(rule.condition) : rule.condition;
|
|
1105
|
+
console.log(
|
|
1106
|
+
` ${theme.dim(`#${rule.index}`)} ${rule.name ? theme.accent(rule.name) + " " : ""}${cond} ${theme.dim("\u2192")} ${theme.info(rule.model)}`
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
console.log();
|
|
1111
|
+
console.log(` ${theme.dim(view.hint)}`);
|
|
1112
|
+
console.log();
|
|
1161
1113
|
}
|
|
1162
1114
|
},
|
|
1163
1115
|
{
|
|
@@ -1191,56 +1143,33 @@ function createProviderCommands() {
|
|
|
1191
1143
|
description: "Enter Plan Mode (read-only): AI can only read files and plan, not modify anything",
|
|
1192
1144
|
usage: "/plan [execute|exit|status]",
|
|
1193
1145
|
execute(args, ctx) {
|
|
1194
|
-
const
|
|
1195
|
-
if (
|
|
1196
|
-
|
|
1197
|
-
|
|
1146
|
+
const outcome = applyPlanCommand(args[0], ctx.getPlanMode());
|
|
1147
|
+
if (outcome.changed) ctx.setPlanMode(outcome.planMode);
|
|
1148
|
+
switch (outcome.status) {
|
|
1149
|
+
case "entered":
|
|
1150
|
+
console.log();
|
|
1151
|
+
console.log(theme.warning(` ${outcome.summary}`));
|
|
1152
|
+
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"));
|
|
1153
|
+
for (const line of outcome.details) console.log(theme.dim(` ${line}`));
|
|
1154
|
+
console.log();
|
|
1198
1155
|
return;
|
|
1199
|
-
|
|
1200
|
-
|
|
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");
|
|
1156
|
+
case "executing":
|
|
1157
|
+
ctx.renderer.printSuccess(outcome.summary);
|
|
1217
1158
|
return;
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
}
|
|
1223
|
-
if (sub === "exit" || sub === "cancel") {
|
|
1224
|
-
if (!ctx.getPlanMode()) {
|
|
1225
|
-
ctx.renderer.printInfo("Not in Plan Mode.");
|
|
1159
|
+
case "already-active":
|
|
1160
|
+
case "not-active":
|
|
1161
|
+
case "cancelled":
|
|
1162
|
+
ctx.renderer.printInfo(outcome.summary);
|
|
1226
1163
|
return;
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
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;
|
|
1164
|
+
case "status":
|
|
1165
|
+
console.log();
|
|
1166
|
+
console.log(` ${outcome.planMode ? theme.warning(outcome.summary) : theme.dim(outcome.summary)}`);
|
|
1167
|
+
for (const line of outcome.details) console.log(theme.dim(` ${line}`));
|
|
1168
|
+
console.log();
|
|
1169
|
+
return;
|
|
1170
|
+
default:
|
|
1171
|
+
ctx.renderer.renderError(outcome.summary);
|
|
1242
1172
|
}
|
|
1243
|
-
ctx.renderer.renderError("Usage: /plan [execute|exit|status]");
|
|
1244
1173
|
}
|
|
1245
1174
|
}
|
|
1246
1175
|
];
|
|
@@ -1409,7 +1338,7 @@ No tools match "${filter}".
|
|
|
1409
1338
|
const { join: join6 } = await import("path");
|
|
1410
1339
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1411
1340
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1412
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1341
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-3VMMZJDS.js");
|
|
1413
1342
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1414
1343
|
const cwd = process.cwd();
|
|
1415
1344
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2329,7 +2258,7 @@ function createReviewCommands() {
|
|
|
2329
2258
|
usage: "/test [command|filter]",
|
|
2330
2259
|
async execute(args, ctx) {
|
|
2331
2260
|
try {
|
|
2332
|
-
const { executeTests } = await import("./run-tests-
|
|
2261
|
+
const { executeTests } = await import("./run-tests-EL54INOI.js");
|
|
2333
2262
|
const argStr = args.join(" ").trim();
|
|
2334
2263
|
let testArgs = {};
|
|
2335
2264
|
if (argStr) {
|
|
@@ -3093,7 +3022,7 @@ function createSessionCommands() {
|
|
|
3093
3022
|
{
|
|
3094
3023
|
name: "session",
|
|
3095
3024
|
description: "Session management",
|
|
3096
|
-
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]",
|
|
3025
|
+
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]",
|
|
3097
3026
|
async execute(args, ctx) {
|
|
3098
3027
|
const sub = args[0];
|
|
3099
3028
|
if (sub === "new") {
|
|
@@ -3105,139 +3034,44 @@ function createSessionCommands() {
|
|
|
3105
3034
|
ctx.renderer.printSuccess("New session started.");
|
|
3106
3035
|
} else if (sub === "list") {
|
|
3107
3036
|
const opts = parseSessionListArgs(args);
|
|
3108
|
-
for (const w of opts.warnings) {
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
const needFileSize = opts.verbose || opts.sort.field === "size";
|
|
3112
|
-
let allSessions = ctx.sessions.listSessions({ includeFileSize: needFileSize });
|
|
3113
|
-
if (allSessions.length === 0) {
|
|
3037
|
+
for (const w of opts.warnings) ctx.renderer.printInfo(`\u26A0 ${w}`);
|
|
3038
|
+
const all = ctx.sessions.listSessions({ includeFileSize: opts.verbose || opts.sort.field === "size" });
|
|
3039
|
+
if (all.length === 0) {
|
|
3114
3040
|
ctx.renderer.printInfo("No saved sessions.");
|
|
3115
3041
|
return;
|
|
3116
3042
|
}
|
|
3117
|
-
const
|
|
3118
|
-
|
|
3119
|
-
const hasTimeFilter = opts.days !== null || opts.since !== null;
|
|
3120
|
-
const hasStale = opts.stale !== null;
|
|
3121
|
-
if (hasFilters) {
|
|
3122
|
-
const p = opts.filter.provider;
|
|
3123
|
-
const m = opts.filter.model;
|
|
3124
|
-
const msg = opts.filter.messages;
|
|
3125
|
-
allSessions = allSessions.filter((s) => {
|
|
3126
|
-
if (p && !p.includes(s.provider.toLowerCase())) return false;
|
|
3127
|
-
if (m && !m.some((kw) => s.model.toLowerCase().includes(kw))) return false;
|
|
3128
|
-
if (msg !== void 0 && s.messageCount !== msg) return false;
|
|
3129
|
-
return true;
|
|
3130
|
-
});
|
|
3131
|
-
}
|
|
3132
|
-
if (hasSearch) {
|
|
3133
|
-
const q = opts.search.toLowerCase();
|
|
3134
|
-
allSessions = allSessions.filter(
|
|
3135
|
-
(s) => (s.title ?? "").toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
|
|
3136
|
-
);
|
|
3137
|
-
}
|
|
3138
|
-
if (hasTimeFilter) {
|
|
3139
|
-
const now = Date.now();
|
|
3140
|
-
let cutoff = 0;
|
|
3141
|
-
if (opts.since) {
|
|
3142
|
-
cutoff = new Date(opts.since).getTime();
|
|
3143
|
-
} else if (opts.days !== null) {
|
|
3144
|
-
cutoff = now - opts.days * 24 * 60 * 60 * 1e3;
|
|
3145
|
-
}
|
|
3146
|
-
if (!isNaN(cutoff)) {
|
|
3147
|
-
allSessions = allSessions.filter((s) => s.updated.getTime() >= cutoff);
|
|
3148
|
-
}
|
|
3149
|
-
}
|
|
3150
|
-
const staleCutoff = hasStale ? Date.now() - opts.stale * 24 * 60 * 60 * 1e3 : 0;
|
|
3151
|
-
if (hasStale) {
|
|
3152
|
-
allSessions = allSessions.filter((s) => s.updated.getTime() < staleCutoff);
|
|
3153
|
-
}
|
|
3154
|
-
const defaultSort = opts.sort.field === "updated" && opts.sort.order === "desc";
|
|
3155
|
-
if (!defaultSort) {
|
|
3156
|
-
const mul = opts.sort.order === "asc" ? 1 : -1;
|
|
3157
|
-
allSessions = [...allSessions].sort((a, b) => {
|
|
3158
|
-
switch (opts.sort.field) {
|
|
3159
|
-
case "created":
|
|
3160
|
-
return (a.created.getTime() - b.created.getTime()) * mul;
|
|
3161
|
-
case "messages":
|
|
3162
|
-
return (a.messageCount - b.messageCount) * mul;
|
|
3163
|
-
case "size":
|
|
3164
|
-
return ((a.fileSize ?? 0) - (b.fileSize ?? 0)) * mul;
|
|
3165
|
-
default:
|
|
3166
|
-
return (a.updated.getTime() - b.updated.getTime()) * mul;
|
|
3167
|
-
}
|
|
3168
|
-
});
|
|
3169
|
-
}
|
|
3170
|
-
const totalCount = allSessions.length;
|
|
3171
|
-
if (totalCount === 0) {
|
|
3043
|
+
const view = selectSessions(all, opts);
|
|
3044
|
+
if (view.totalCount === 0) {
|
|
3172
3045
|
ctx.renderer.printInfo("No sessions match the filter criteria.");
|
|
3173
3046
|
return;
|
|
3174
3047
|
}
|
|
3175
3048
|
if (opts.json) {
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
id: s.id,
|
|
3179
|
-
title: s.title ?? null,
|
|
3180
|
-
provider: s.provider,
|
|
3181
|
-
model: s.model,
|
|
3182
|
-
messageCount: s.messageCount,
|
|
3183
|
-
created: s.created.toISOString(),
|
|
3184
|
-
updated: s.updated.toISOString(),
|
|
3185
|
-
...needFileSize ? { fileSize: s.fileSize } : {},
|
|
3186
|
-
...s.branchCount !== void 0 ? { branchCount: s.branchCount, activeBranch: s.activeBranch } : {}
|
|
3187
|
-
}));
|
|
3188
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
3189
|
-
if (opts.limit > 0 && totalCount > opts.limit) {
|
|
3049
|
+
console.log(JSON.stringify(view.shown.map((s) => sessionListJsonRow(s, view.needsFileSize)), null, 2));
|
|
3050
|
+
if (view.shown.length < view.totalCount) {
|
|
3190
3051
|
console.error(
|
|
3191
3052
|
`
|
|
3192
|
-
(truncated: ${
|
|
3053
|
+
(truncated: ${view.shown.length} of ${view.totalCount} sessions shown; use --all for full list)`
|
|
3193
3054
|
);
|
|
3194
3055
|
}
|
|
3195
3056
|
return;
|
|
3196
3057
|
}
|
|
3197
|
-
const sliced = opts.limit > 0 ? allSessions.slice(0, opts.limit) : allSessions;
|
|
3198
3058
|
const headers = ["ID (short)", "Provider", "Model", "Messages"];
|
|
3199
|
-
if (opts.verbose)
|
|
3200
|
-
headers.push("Size");
|
|
3201
|
-
headers.push("Br");
|
|
3202
|
-
}
|
|
3059
|
+
if (opts.verbose) headers.push("Size", "Br");
|
|
3203
3060
|
headers.push("Date", "Title");
|
|
3204
|
-
const rows =
|
|
3205
|
-
const isStale =
|
|
3061
|
+
const rows = view.shown.map((s) => {
|
|
3062
|
+
const isStale = view.staleCutoff !== null && s.updated.getTime() < view.staleCutoff;
|
|
3206
3063
|
const dim = isStale ? theme.dim : (x) => String(x);
|
|
3207
|
-
const row = [
|
|
3208
|
-
dim(s.id.slice(0, 8)),
|
|
3209
|
-
dim(s.provider),
|
|
3210
|
-
dim(s.model),
|
|
3211
|
-
s.messageCount
|
|
3212
|
-
];
|
|
3064
|
+
const row = [dim(s.id.slice(0, 8)), dim(s.provider), dim(s.model), s.messageCount];
|
|
3213
3065
|
if (opts.verbose) {
|
|
3214
|
-
row.push(
|
|
3215
|
-
s.fileSize !== void 0 ? formatFileSize(s.fileSize) : "\u2014",
|
|
3216
|
-
s.branchCount ?? 1
|
|
3217
|
-
);
|
|
3066
|
+
row.push(s.fileSize !== void 0 ? formatFileSize(s.fileSize) : "\u2014", s.branchCount ?? 1);
|
|
3218
3067
|
}
|
|
3219
|
-
row.push(
|
|
3220
|
-
formatSessionDate(s.updated),
|
|
3221
|
-
dim(truncateTitle(s.title ?? "(untitled)", MAX_TITLE_WIDTH))
|
|
3222
|
-
);
|
|
3068
|
+
row.push(formatSessionDate(s.updated), dim(truncateTitle(s.title ?? "(untitled)", MAX_TITLE_WIDTH)));
|
|
3223
3069
|
return row;
|
|
3224
3070
|
});
|
|
3225
3071
|
console.log();
|
|
3226
3072
|
ctx.renderer.printTable(headers, rows);
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
const filterHints = [];
|
|
3230
|
-
if (hasFilters) filterHints.push("filtered");
|
|
3231
|
-
if (hasSearch) filterHints.push("searched");
|
|
3232
|
-
if (hasTimeFilter) filterHints.push("time-limited");
|
|
3233
|
-
if (hasStale) filterHints.push(`stale >${opts.stale}d`);
|
|
3234
|
-
const filterTag = filterHints.length > 0 ? ` (${filterHints.join(", ")})` : "";
|
|
3235
|
-
console.log(
|
|
3236
|
-
theme.dim(
|
|
3237
|
-
` \u2500\u2500 ${shown} of ${totalCount} sessions${filterTag} \xB7 ${totalMessages} messages total`
|
|
3238
|
-
)
|
|
3239
|
-
);
|
|
3240
|
-
if (shown < totalCount) {
|
|
3073
|
+
console.log(theme.dim(` \u2500\u2500 ${sessionListSummary(view)}`));
|
|
3074
|
+
if (view.shown.length < view.totalCount) {
|
|
3241
3075
|
console.log(theme.dim(` Use --all to show all, or --limit N to change count.`));
|
|
3242
3076
|
}
|
|
3243
3077
|
} else if (sub === "load" || sub === "show") {
|
|
@@ -3246,19 +3080,18 @@ function createSessionCommands() {
|
|
|
3246
3080
|
ctx.renderer.renderError(`Usage: /session ${sub} <id>${sub === "show" ? " [page]" : ""}`);
|
|
3247
3081
|
return;
|
|
3248
3082
|
}
|
|
3249
|
-
const
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
ctx.renderer.renderError(`Session '${id}' not found.`);
|
|
3083
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "most-recent");
|
|
3084
|
+
if (ref.status !== "ok") {
|
|
3085
|
+
ctx.renderer.renderError(ref.message);
|
|
3253
3086
|
return;
|
|
3254
3087
|
}
|
|
3255
|
-
if (
|
|
3256
|
-
console.log(theme.warning(`
|
|
3257
|
-
for (const m of
|
|
3088
|
+
if (ref.message) {
|
|
3089
|
+
console.log(theme.warning(` ${ref.message}`));
|
|
3090
|
+
for (const m of ref.ambiguousWith.slice(0, 5)) {
|
|
3258
3091
|
console.log(theme.dim(` ${m.id.slice(0, 12)} ${m.title ?? "(untitled)"}`));
|
|
3259
3092
|
}
|
|
3260
3093
|
}
|
|
3261
|
-
const match =
|
|
3094
|
+
const match = ref.match;
|
|
3262
3095
|
ctx.sessions.loadSession(match.id);
|
|
3263
3096
|
ctx.setProvider(match.provider, match.model);
|
|
3264
3097
|
ctx.resetSessionTokenUsage();
|
|
@@ -3282,70 +3115,54 @@ function createSessionCommands() {
|
|
|
3282
3115
|
return;
|
|
3283
3116
|
}
|
|
3284
3117
|
renderTranscriptPage(cur.messages, ctx.renderer, n);
|
|
3118
|
+
} else if (sub === "rename") {
|
|
3119
|
+
const id = args[1];
|
|
3120
|
+
const newTitle = args.slice(2).join(" ").trim();
|
|
3121
|
+
if (!id || !newTitle) {
|
|
3122
|
+
ctx.renderer.renderError("Usage: /session rename <id> <new title>");
|
|
3123
|
+
return;
|
|
3124
|
+
}
|
|
3125
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "strict");
|
|
3126
|
+
if (ref.status !== "ok") {
|
|
3127
|
+
ctx.renderer.renderError(ref.message);
|
|
3128
|
+
if (ref.status === "ambiguous") {
|
|
3129
|
+
for (const m of ref.matches.slice(0, 10)) console.log(theme.dim(` ${formatSessionSummaryLine(m)}`));
|
|
3130
|
+
}
|
|
3131
|
+
return;
|
|
3132
|
+
}
|
|
3133
|
+
const priorId = ctx.sessions.current?.id ?? null;
|
|
3134
|
+
const isCurrent = priorId === ref.match.id;
|
|
3135
|
+
const session = isCurrent ? ctx.sessions.current : ctx.sessions.loadSession(ref.match.id);
|
|
3136
|
+
session.title = newTitle;
|
|
3137
|
+
await ctx.sessions.save();
|
|
3138
|
+
if (!isCurrent && priorId) {
|
|
3139
|
+
ctx.sessions.loadSession(priorId);
|
|
3140
|
+
}
|
|
3141
|
+
ctx.renderer.printSuccess(`Renamed session ${ref.match.id.slice(0, 8)}: "${newTitle}"`);
|
|
3285
3142
|
} else if (sub === "remove" || sub === "delete") {
|
|
3286
3143
|
if (args[1] === "--filter") {
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
if (args[i] === "--filter" && i + 1 < args.length) {
|
|
3291
|
-
const val = args[++i];
|
|
3292
|
-
const eq = val.indexOf("=");
|
|
3293
|
-
if (eq > 0) {
|
|
3294
|
-
const key = val.slice(0, eq);
|
|
3295
|
-
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
3296
|
-
if (key === "messages") {
|
|
3297
|
-
const n = Number(vals[0]);
|
|
3298
|
-
if (Number.isFinite(n) && n >= 0) filterMessages = n;
|
|
3299
|
-
else {
|
|
3300
|
-
ctx.renderer.renderError(`Invalid filter value for "messages": expected a non-negative integer, got "${vals[0]}"`);
|
|
3301
|
-
return;
|
|
3302
|
-
}
|
|
3303
|
-
} else {
|
|
3304
|
-
ctx.renderer.renderError(`Unsupported filter key for remove: "${key}". Only "messages" is supported.`);
|
|
3305
|
-
return;
|
|
3306
|
-
}
|
|
3307
|
-
} else {
|
|
3308
|
-
ctx.renderer.renderError(`Invalid --filter syntax: "${val}". Expected key=value (e.g., messages=0)`);
|
|
3309
|
-
return;
|
|
3310
|
-
}
|
|
3311
|
-
} else if (args[i] === "--dry-run") {
|
|
3312
|
-
dryRun = true;
|
|
3313
|
-
}
|
|
3314
|
-
}
|
|
3315
|
-
if (filterMessages === void 0) {
|
|
3316
|
-
ctx.renderer.renderError("Usage: /session remove --filter messages=N [--dry-run]");
|
|
3144
|
+
const opts = parseBatchDeleteArgs(args);
|
|
3145
|
+
if (opts.error) {
|
|
3146
|
+
ctx.renderer.renderError(opts.error);
|
|
3317
3147
|
return;
|
|
3318
3148
|
}
|
|
3319
|
-
const
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
ctx.renderer.printInfo(`No sessions with ${filterMessages} message(s) found.`);
|
|
3149
|
+
const matches = ctx.sessions.listSessions().filter((s) => s.messageCount === opts.messages);
|
|
3150
|
+
if (matches.length === 0) {
|
|
3151
|
+
ctx.renderer.printInfo(`No sessions with ${opts.messages} message(s) found.`);
|
|
3323
3152
|
return;
|
|
3324
3153
|
}
|
|
3325
3154
|
console.log();
|
|
3326
|
-
console.log(
|
|
3327
|
-
|
|
3328
|
-
);
|
|
3329
|
-
|
|
3330
|
-
console.log(
|
|
3331
|
-
|
|
3332
|
-
` ${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)}`
|
|
3333
|
-
)
|
|
3334
|
-
);
|
|
3335
|
-
}
|
|
3336
|
-
if (matches2.length > 20) {
|
|
3337
|
-
console.log(theme.dim(` ... and ${matches2.length - 20} more`));
|
|
3338
|
-
}
|
|
3339
|
-
if (dryRun) {
|
|
3340
|
-
console.log(
|
|
3341
|
-
theme.info(`
|
|
3342
|
-
--dry-run: no sessions were deleted. Remove --dry-run to actually delete.`)
|
|
3343
|
-
);
|
|
3155
|
+
console.log(theme.warning(` Found ${matches.length} session(s) with ${opts.messages} message(s):`));
|
|
3156
|
+
for (const s of matches.slice(0, 20)) console.log(theme.dim(` ${formatSessionSummaryLine(s)}`));
|
|
3157
|
+
if (matches.length > 20) console.log(theme.dim(` ... and ${matches.length - 20} more`));
|
|
3158
|
+
if (opts.dryRun) {
|
|
3159
|
+
console.log(theme.info(`
|
|
3160
|
+
--dry-run: no sessions were deleted. Remove --dry-run to actually delete.`));
|
|
3344
3161
|
return;
|
|
3345
3162
|
}
|
|
3346
3163
|
console.log();
|
|
3347
3164
|
const choice2 = await ctx.select(
|
|
3348
|
-
`Delete all ${
|
|
3165
|
+
`Delete all ${matches.length} matching sessions?`,
|
|
3349
3166
|
[
|
|
3350
3167
|
{ label: "No \u2014 keep them", value: "no" },
|
|
3351
3168
|
{ label: "Yes \u2014 delete permanently", value: "yes", hint: "unlinks all matching history files" }
|
|
@@ -3357,17 +3174,12 @@ function createSessionCommands() {
|
|
|
3357
3174
|
}
|
|
3358
3175
|
let deleted = 0;
|
|
3359
3176
|
let failed = 0;
|
|
3360
|
-
for (const s of
|
|
3361
|
-
if (ctx.sessions.deleteSession(s.id))
|
|
3362
|
-
|
|
3363
|
-
} else {
|
|
3364
|
-
failed++;
|
|
3365
|
-
}
|
|
3177
|
+
for (const s of matches) {
|
|
3178
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
3179
|
+
else failed++;
|
|
3366
3180
|
}
|
|
3367
3181
|
const currentStillExists = ctx.sessions.current !== null;
|
|
3368
|
-
ctx.renderer.printSuccess(
|
|
3369
|
-
`Removed: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`
|
|
3370
|
-
);
|
|
3182
|
+
ctx.renderer.printSuccess(`Removed: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`);
|
|
3371
3183
|
if (!currentStillExists) {
|
|
3372
3184
|
ctx.sessions.createSession(ctx.getCurrentProvider(), ctx.getCurrentModel());
|
|
3373
3185
|
ctx.resetSessionTokenUsage();
|
|
@@ -3381,20 +3193,15 @@ function createSessionCommands() {
|
|
|
3381
3193
|
ctx.renderer.renderError("Usage: /session remove <id> | /session remove --filter messages=N [--dry-run]");
|
|
3382
3194
|
return;
|
|
3383
3195
|
}
|
|
3384
|
-
const
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
}
|
|
3390
|
-
if (matches.length > 1) {
|
|
3391
|
-
ctx.renderer.renderError(`Ambiguous prefix '${id}' matches ${matches.length} sessions \u2014 be more specific:`);
|
|
3392
|
-
for (const m of matches.slice(0, 10)) {
|
|
3393
|
-
console.log(theme.dim(` ${m.id.slice(0, 12)} ${String(m.messageCount).padStart(4)} msgs ${m.updated.toLocaleDateString()} ${m.title ?? "(untitled)"}`));
|
|
3196
|
+
const ref = resolveSessionRef(ctx.sessions.listSessions(), id, "strict");
|
|
3197
|
+
if (ref.status !== "ok") {
|
|
3198
|
+
ctx.renderer.renderError(ref.message);
|
|
3199
|
+
if (ref.status === "ambiguous") {
|
|
3200
|
+
for (const m of ref.matches.slice(0, 10)) console.log(theme.dim(` ${formatSessionSummaryLine(m)}`));
|
|
3394
3201
|
}
|
|
3395
3202
|
return;
|
|
3396
3203
|
}
|
|
3397
|
-
const match =
|
|
3204
|
+
const match = ref.match;
|
|
3398
3205
|
const isCurrent = ctx.sessions.current?.id === match.id;
|
|
3399
3206
|
console.log();
|
|
3400
3207
|
console.log(theme.warning(" About to permanently delete session (no undo):"));
|
|
@@ -3421,44 +3228,19 @@ function createSessionCommands() {
|
|
|
3421
3228
|
ctx.renderer.printInfo("Current session was deleted \u2014 started a fresh session.");
|
|
3422
3229
|
}
|
|
3423
3230
|
} else if (sub === "clean") {
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
for (let i = 1; i < args.length; i++) {
|
|
3427
|
-
if (args[i] === "--stale" && i + 1 < args.length) {
|
|
3428
|
-
const n = Number(args[++i]);
|
|
3429
|
-
if (Number.isFinite(n) && n > 0) staleDays = n;
|
|
3430
|
-
} else if (args[i] === "--dry-run") {
|
|
3431
|
-
dryRun = true;
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
const cutoff = Date.now() - staleDays * 24 * 60 * 60 * 1e3;
|
|
3435
|
-
const allSessions = ctx.sessions.listSessions();
|
|
3436
|
-
const stale = allSessions.filter((s) => s.updated.getTime() < cutoff);
|
|
3231
|
+
const opts = parseCleanArgs(args);
|
|
3232
|
+
const stale = selectStaleSessions(ctx.sessions.listSessions(), opts.staleDays);
|
|
3437
3233
|
if (stale.length === 0) {
|
|
3438
|
-
ctx.renderer.printInfo(`No sessions older than ${staleDays} days found.`);
|
|
3234
|
+
ctx.renderer.printInfo(`No sessions older than ${opts.staleDays} days found.`);
|
|
3439
3235
|
return;
|
|
3440
3236
|
}
|
|
3441
3237
|
console.log();
|
|
3442
|
-
console.log(
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
console.log(
|
|
3449
|
-
theme.dim(
|
|
3450
|
-
` ${s.id.slice(0, 12)} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${truncateTitle(s.title ?? "(untitled)", 60)}`
|
|
3451
|
-
)
|
|
3452
|
-
);
|
|
3453
|
-
}
|
|
3454
|
-
if (stale.length > 20) {
|
|
3455
|
-
console.log(theme.dim(` ... and ${stale.length - 20} more`));
|
|
3456
|
-
}
|
|
3457
|
-
if (dryRun) {
|
|
3458
|
-
console.log(
|
|
3459
|
-
theme.info(`
|
|
3460
|
-
--dry-run: no sessions were deleted. Remove --dry-run to actually delete.`)
|
|
3461
|
-
);
|
|
3238
|
+
console.log(theme.warning(` Found ${stale.length} session(s) not updated in ${opts.staleDays}+ days:`));
|
|
3239
|
+
for (const s of stale.slice(0, 20)) console.log(theme.dim(` ${formatSessionSummaryLine(s)}`));
|
|
3240
|
+
if (stale.length > 20) console.log(theme.dim(` ... and ${stale.length - 20} more`));
|
|
3241
|
+
if (opts.dryRun) {
|
|
3242
|
+
console.log(theme.info(`
|
|
3243
|
+
--dry-run: no sessions were deleted. Remove --dry-run to actually delete.`));
|
|
3462
3244
|
return;
|
|
3463
3245
|
}
|
|
3464
3246
|
console.log();
|
|
@@ -3476,17 +3258,12 @@ function createSessionCommands() {
|
|
|
3476
3258
|
let deleted = 0;
|
|
3477
3259
|
let failed = 0;
|
|
3478
3260
|
for (const s of stale) {
|
|
3479
|
-
if (ctx.sessions.deleteSession(s.id))
|
|
3480
|
-
|
|
3481
|
-
} else {
|
|
3482
|
-
failed++;
|
|
3483
|
-
}
|
|
3261
|
+
if (ctx.sessions.deleteSession(s.id)) deleted++;
|
|
3262
|
+
else failed++;
|
|
3484
3263
|
}
|
|
3485
|
-
ctx.renderer.printSuccess(
|
|
3486
|
-
`Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`
|
|
3487
|
-
);
|
|
3264
|
+
ctx.renderer.printSuccess(`Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`);
|
|
3488
3265
|
} else {
|
|
3489
|
-
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]");
|
|
3266
|
+
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]");
|
|
3490
3267
|
}
|
|
3491
3268
|
}
|
|
3492
3269
|
},
|
|
@@ -7559,7 +7336,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7559
7336
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7560
7337
|
process.exit(1);
|
|
7561
7338
|
}
|
|
7562
|
-
const { startWebServer } = await import("./server-
|
|
7339
|
+
const { startWebServer } = await import("./server-WUSJWC3A.js");
|
|
7563
7340
|
await startWebServer({ port, host: options.host });
|
|
7564
7341
|
});
|
|
7565
7342
|
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 +7503,11 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7726
7503
|
console.log(footer + "\n");
|
|
7727
7504
|
});
|
|
7728
7505
|
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-
|
|
7506
|
+
const { runUsageCli } = await import("./usage-CW6BT2UV.js");
|
|
7730
7507
|
await runUsageCli(options);
|
|
7731
7508
|
});
|
|
7732
7509
|
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-
|
|
7510
|
+
const { runDoctorCli } = await import("./doctor-cli-WVMEWMYE.js");
|
|
7734
7511
|
const argv = process.argv.slice(2);
|
|
7735
7512
|
await runDoctorCli({
|
|
7736
7513
|
json: !!options.json || argv.includes("--json"),
|
|
@@ -7739,7 +7516,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
|
|
|
7739
7516
|
});
|
|
7740
7517
|
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
7518
|
try {
|
|
7742
|
-
const batch = await import("./batch-
|
|
7519
|
+
const batch = await import("./batch-6QZSWCBL.js");
|
|
7743
7520
|
switch (action) {
|
|
7744
7521
|
case "submit":
|
|
7745
7522
|
if (!arg) {
|
|
@@ -7782,7 +7559,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7782
7559
|
}
|
|
7783
7560
|
});
|
|
7784
7561
|
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-
|
|
7562
|
+
const { startMcpServer } = await import("./server-6C7GITHY.js");
|
|
7786
7563
|
await startMcpServer({
|
|
7787
7564
|
allowDestructive: !!options.allowDestructive,
|
|
7788
7565
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7795,7 +7572,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
7795
7572
|
console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
|
|
7796
7573
|
process.exit(1);
|
|
7797
7574
|
}
|
|
7798
|
-
const { runPrCli } = await import("./pr-
|
|
7575
|
+
const { runPrCli } = await import("./pr-GFB5JC26.js");
|
|
7799
7576
|
const result = await runPrCli({
|
|
7800
7577
|
action,
|
|
7801
7578
|
target,
|
|
@@ -7815,8 +7592,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
7815
7592
|
process.exit(result.exitCode);
|
|
7816
7593
|
});
|
|
7817
7594
|
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-
|
|
7819
|
-
const { formatCiResult } = await import("./ci-format-
|
|
7595
|
+
const { runCi } = await import("./ci-F4ESOYI5.js");
|
|
7596
|
+
const { formatCiResult } = await import("./ci-format-AIRW3TVQ.js");
|
|
7820
7597
|
const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
|
|
7821
7598
|
if (formats > 1) {
|
|
7822
7599
|
console.error("Choose only one output format: --json, --markdown, or --sarif.");
|
|
@@ -7974,7 +7751,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7974
7751
|
config.get("customProviders"),
|
|
7975
7752
|
config.getConfigDir()
|
|
7976
7753
|
);
|
|
7977
|
-
const { startHub } = await import("./hub-
|
|
7754
|
+
const { startHub } = await import("./hub-JJCCCU3O.js");
|
|
7978
7755
|
await startHub(
|
|
7979
7756
|
{
|
|
7980
7757
|
topic: topic ?? "",
|