jinzd-ai-cli 0.4.219 → 0.4.221
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/README.md +101 -99
- package/README.zh-CN.md +40 -38
- package/dist/{batch-CHAPYRVM.js → batch-LSWWSINO.js} +3 -3
- package/dist/{chunk-GEN4O5QH.js → chunk-4AX2MEJA.js} +4 -4
- package/dist/{chunk-64NUW3WL.js → chunk-4MOBTDS6.js} +1 -1
- package/dist/{chunk-4ZN6L6K5.js → chunk-5BY4XICU.js} +6 -5
- package/dist/{chunk-MC34ISJU.js → chunk-5GTWZ4QF.js} +30 -6
- package/dist/{chunk-TZQHYZKT.js → chunk-5ULLIOVC.js} +1 -0
- package/dist/{chunk-3I4RZYYO.js → chunk-6SKMGONY.js} +6 -5
- package/dist/{chunk-QUFYBR6Q.js → chunk-BYQEWWA4.js} +2 -2
- package/dist/{chunk-VADHBW7T.js → chunk-OULVIHCT.js} +1 -1
- package/dist/{chunk-KIEZBTVD.js → chunk-PMTEZTXP.js} +2 -2
- package/dist/{chunk-QMXC327F.js → chunk-PUBCJF7E.js} +213 -175
- package/dist/{chunk-U7KVU25H.js → chunk-QDN5G7JN.js} +1 -1
- package/dist/{chunk-GGKQHPB3.js → chunk-QKJ3MAP7.js} +1 -1
- package/dist/{chunk-A4GUGWEY.js → chunk-QT5FA2ZY.js} +1 -1
- package/dist/{chunk-EGMORH5W.js → chunk-S5EEKS4P.js} +1 -1
- package/dist/{ci-QPP66T53.js → ci-OIFTAJKR.js} +6 -6
- package/dist/{ci-format-5S3EEYRK.js → ci-format-H6BLMWQ5.js} +2 -2
- package/dist/{constants-FJOLBABC.js → constants-EJRLT7DM.js} +1 -1
- package/dist/{doctor-cli-KB2LUDF3.js → doctor-cli-EXC7YU5D.js} +6 -6
- package/dist/electron-server.js +558 -466
- package/dist/{hub-DIM7SKKY.js → hub-HQDRQBNM.js} +2 -2
- package/dist/index.js +376 -45
- package/dist/{persist-L54DPLI7.js → persist-GTBEKVFL.js} +2 -2
- package/dist/{pr-YQGH72N6.js → pr-VSZNVKBS.js} +8 -7
- package/dist/{run-tests-O76JIBCW.js → run-tests-55JGEZYL.js} +1 -1
- package/dist/{run-tests-GEZSSNJM.js → run-tests-OYXK27XH.js} +2 -2
- package/dist/{server-5E2AIXVX.js → server-JKNIZ5CB.js} +54 -22
- package/dist/{server-Z6O3G2LY.js → server-XX6UM4ZQ.js} +5 -5
- package/dist/{task-orchestrator-5HBW4O64.js → task-orchestrator-F3DUIACA.js} +5 -5
- package/dist/{usage-BMK6M5U3.js → usage-4KFX3HTK.js} +3 -3
- package/package.json +1 -1
|
@@ -139,7 +139,7 @@ ${content}`);
|
|
|
139
139
|
const state = await runDiscussion(config, providers, options.topic);
|
|
140
140
|
if (options.save !== false && state.messages.length > 0) {
|
|
141
141
|
try {
|
|
142
|
-
const { persistDiscussion } = await import("./persist-
|
|
142
|
+
const { persistDiscussion } = await import("./persist-GTBEKVFL.js");
|
|
143
143
|
const { path } = await persistDiscussion(state, configManager, defaultProvider, defaultModel);
|
|
144
144
|
console.log(chalk.dim(`
|
|
145
145
|
\u{1F4BE} Saved to history \u2014 open it in the Web UI and hit \u{1F3AC} to replay.
|
|
@@ -154,7 +154,7 @@ ${content}`);
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
157
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
157
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-F3DUIACA.js");
|
|
158
158
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
159
159
|
let interrupted = false;
|
|
160
160
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
scanProject,
|
|
15
15
|
sessionHasMeaningfulContent,
|
|
16
16
|
setupProxy
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-BYQEWWA4.js";
|
|
18
18
|
import {
|
|
19
19
|
buildReviewPrompt,
|
|
20
20
|
buildSecurityReviewPrompt
|
|
@@ -51,15 +51,15 @@ import {
|
|
|
51
51
|
theme,
|
|
52
52
|
undoStack,
|
|
53
53
|
updateMemoryApproval
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-4AX2MEJA.js";
|
|
55
55
|
import "./chunk-K3CF65QH.js";
|
|
56
56
|
import "./chunk-T2NL5ZIA.js";
|
|
57
57
|
import "./chunk-BXP6YZ2P.js";
|
|
58
|
-
import "./chunk-
|
|
58
|
+
import "./chunk-4MOBTDS6.js";
|
|
59
59
|
import {
|
|
60
60
|
SessionManager,
|
|
61
61
|
getContentText
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-5GTWZ4QF.js";
|
|
63
63
|
import {
|
|
64
64
|
CostTracker
|
|
65
65
|
} from "./chunk-CITDVXXM.js";
|
|
@@ -87,10 +87,10 @@ import {
|
|
|
87
87
|
formatDoctorReport,
|
|
88
88
|
loadContextFiles,
|
|
89
89
|
writeCrashLog
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-6SKMGONY.js";
|
|
91
91
|
import {
|
|
92
92
|
ProviderRegistry
|
|
93
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-PUBCJF7E.js";
|
|
94
94
|
import {
|
|
95
95
|
describePlugin,
|
|
96
96
|
getActivePluginAssets,
|
|
@@ -107,7 +107,7 @@ import {
|
|
|
107
107
|
trustHook,
|
|
108
108
|
trustPlugin,
|
|
109
109
|
untrustHook
|
|
110
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-QKJ3MAP7.js";
|
|
111
111
|
import {
|
|
112
112
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
113
113
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -129,12 +129,12 @@ import {
|
|
|
129
129
|
} from "./chunk-XPBEJB27.js";
|
|
130
130
|
import {
|
|
131
131
|
ConfigManager
|
|
132
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-PMTEZTXP.js";
|
|
133
133
|
import {
|
|
134
134
|
AuthError,
|
|
135
135
|
ProviderError,
|
|
136
136
|
RateLimitError
|
|
137
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-5ULLIOVC.js";
|
|
138
138
|
import {
|
|
139
139
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
140
140
|
AUTHOR,
|
|
@@ -153,7 +153,7 @@ import {
|
|
|
153
153
|
SKILLS_DIR_NAME,
|
|
154
154
|
VERSION,
|
|
155
155
|
buildUserIdentityPrompt
|
|
156
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-QDN5G7JN.js";
|
|
157
157
|
import {
|
|
158
158
|
formatGitContextForPrompt,
|
|
159
159
|
getGitContext,
|
|
@@ -780,6 +780,117 @@ function oneLinePreview(s, max) {
|
|
|
780
780
|
const flat = s.replace(/\s+/g, " ").trim();
|
|
781
781
|
return flat.length > max ? flat.slice(0, max - 1) + "\u2026" : flat;
|
|
782
782
|
}
|
|
783
|
+
var DEFAULT_SESSION_LIST_LIMIT = 50;
|
|
784
|
+
var MAX_TITLE_WIDTH = 40;
|
|
785
|
+
function formatFileSize(bytes) {
|
|
786
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
787
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
788
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
789
|
+
}
|
|
790
|
+
function visualWidth(s) {
|
|
791
|
+
const clean = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
792
|
+
let w = 0;
|
|
793
|
+
for (const ch of clean) {
|
|
794
|
+
const cp = ch.codePointAt(0);
|
|
795
|
+
if (cp >= 4352 && cp <= 4447 || // Hangul Jamo
|
|
796
|
+
cp >= 11904 && cp <= 42191 || // CJK Radicals … Yi
|
|
797
|
+
cp >= 44032 && cp <= 55203 || // Hangul Syllables
|
|
798
|
+
cp >= 63744 && cp <= 64255 || // CJK Compatibility Ideographs
|
|
799
|
+
cp >= 65072 && cp <= 65135 || // CJK Compatibility Forms
|
|
800
|
+
cp >= 65281 && cp <= 65376 || // Fullwidth Forms
|
|
801
|
+
cp >= 65504 && cp <= 65510 || // Fullwidth Signs
|
|
802
|
+
cp >= 126976 && cp <= 129791 || // Mahjong / Domino / …
|
|
803
|
+
cp >= 131072 && cp <= 196605 || // CJK Extension B+
|
|
804
|
+
cp >= 196608 && cp <= 262141) {
|
|
805
|
+
w += 2;
|
|
806
|
+
} else {
|
|
807
|
+
w += 1;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return w;
|
|
811
|
+
}
|
|
812
|
+
function truncateTitle(title, maxWidth) {
|
|
813
|
+
if (visualWidth(title) <= maxWidth) return title;
|
|
814
|
+
let w = 0;
|
|
815
|
+
let end = 0;
|
|
816
|
+
for (const ch of title) {
|
|
817
|
+
const chW = visualWidth(ch);
|
|
818
|
+
if (w + chW > maxWidth - 1) break;
|
|
819
|
+
w += chW;
|
|
820
|
+
end++;
|
|
821
|
+
}
|
|
822
|
+
return title.slice(0, end) + "\u2026";
|
|
823
|
+
}
|
|
824
|
+
function formatSessionDate(date) {
|
|
825
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
826
|
+
const ymd = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
827
|
+
const hm = `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
828
|
+
const abs = `${ymd} ${hm}`;
|
|
829
|
+
const now = /* @__PURE__ */ new Date();
|
|
830
|
+
const diffMs = now.getTime() - date.getTime();
|
|
831
|
+
const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
|
|
832
|
+
if (diffDays === 0) return `${abs} (today)`;
|
|
833
|
+
if (diffDays === 1) return `${abs} (yesterday)`;
|
|
834
|
+
if (diffDays < 7) return `${abs} (${diffDays} days ago)`;
|
|
835
|
+
return abs;
|
|
836
|
+
}
|
|
837
|
+
function parseSessionListArgs(args) {
|
|
838
|
+
let limit = DEFAULT_SESSION_LIST_LIMIT;
|
|
839
|
+
let all = false;
|
|
840
|
+
const filter = {};
|
|
841
|
+
let search = null;
|
|
842
|
+
let days = null;
|
|
843
|
+
let since = null;
|
|
844
|
+
let sort = { field: "updated", order: "desc" };
|
|
845
|
+
let json = false;
|
|
846
|
+
let stale = null;
|
|
847
|
+
let verbose = false;
|
|
848
|
+
for (let i = 1; i < args.length; i++) {
|
|
849
|
+
const a = args[i];
|
|
850
|
+
if (a === "--all" || a === "-a") {
|
|
851
|
+
all = true;
|
|
852
|
+
} else if ((a === "--limit" || a === "-n") && i + 1 < args.length) {
|
|
853
|
+
const n = Number(args[i + 1]);
|
|
854
|
+
if (Number.isFinite(n) && n > 0) {
|
|
855
|
+
limit = n;
|
|
856
|
+
i++;
|
|
857
|
+
}
|
|
858
|
+
} else if (a === "--filter" && i + 1 < args.length) {
|
|
859
|
+
const val = args[++i];
|
|
860
|
+
const eq = val.indexOf("=");
|
|
861
|
+
if (eq > 0) {
|
|
862
|
+
const key = val.slice(0, eq);
|
|
863
|
+
const vals = val.slice(eq + 1).split(",").map((s) => s.trim().toLowerCase());
|
|
864
|
+
if (key === "provider") filter.provider = vals;
|
|
865
|
+
else if (key === "model") filter.model = vals;
|
|
866
|
+
}
|
|
867
|
+
} else if ((a === "--search" || a === "-s") && i + 1 < args.length) {
|
|
868
|
+
search = args[++i];
|
|
869
|
+
} else if (a === "--days" && i + 1 < args.length) {
|
|
870
|
+
const n = Number(args[++i]);
|
|
871
|
+
if (Number.isFinite(n) && n > 0) days = n;
|
|
872
|
+
} else if (a === "--since" && i + 1 < args.length) {
|
|
873
|
+
since = args[++i];
|
|
874
|
+
} else if (a === "--sort" && i + 1 < args.length) {
|
|
875
|
+
const sv = args[++i];
|
|
876
|
+
const colon = sv.indexOf(":");
|
|
877
|
+
const field = colon > 0 ? sv.slice(0, colon) : sv;
|
|
878
|
+
const order = colon > 0 ? sv.slice(colon + 1) : "desc";
|
|
879
|
+
if (field === "updated" || field === "created" || field === "messages" || field === "size") {
|
|
880
|
+
sort = { field, order: order === "asc" ? "asc" : "desc" };
|
|
881
|
+
}
|
|
882
|
+
} else if (a === "--json") {
|
|
883
|
+
json = true;
|
|
884
|
+
} else if (a === "--verbose" || a === "-v") {
|
|
885
|
+
verbose = true;
|
|
886
|
+
} else if (a === "--stale" && i + 1 < args.length) {
|
|
887
|
+
const n = Number(args[++i]);
|
|
888
|
+
if (Number.isFinite(n) && n > 0) stale = n;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (all) limit = -1;
|
|
892
|
+
return { limit, all, filter, search, days, since, sort, json, stale, verbose };
|
|
893
|
+
}
|
|
783
894
|
function renderTranscriptMessage(msg, renderer) {
|
|
784
895
|
if (msg.role === "user") {
|
|
785
896
|
const text = getContentText(msg.content);
|
|
@@ -891,7 +1002,7 @@ function createDefaultCommands() {
|
|
|
891
1002
|
title: "Chat & model",
|
|
892
1003
|
rows: [
|
|
893
1004
|
["/provider <name>", "Switch AI provider"],
|
|
894
|
-
["/model
|
|
1005
|
+
["/model [name|refresh|cache]", "Switch model or refresh live model cache"],
|
|
895
1006
|
["/route [on|off|show|test <msg>]", "Smart model routing rules"],
|
|
896
1007
|
["/think [on|off|status]", "Toggle Extended Thinking (deep reasoning)"],
|
|
897
1008
|
["/plan [execute|exit|status]", "Enter/manage Plan Mode (read-only)"],
|
|
@@ -1059,13 +1170,46 @@ No commands match "${filter}".
|
|
|
1059
1170
|
},
|
|
1060
1171
|
{
|
|
1061
1172
|
name: "model",
|
|
1062
|
-
description: "Switch model
|
|
1063
|
-
usage: "/model [name]",
|
|
1173
|
+
description: "Switch model, refresh live model list, or inspect model cache",
|
|
1174
|
+
usage: "/model [name|refresh [provider]|cache [clear [provider]]]",
|
|
1064
1175
|
async execute(args, ctx) {
|
|
1176
|
+
const sub = (args[0] ?? "").toLowerCase();
|
|
1177
|
+
if (sub === "refresh") {
|
|
1178
|
+
const providerId = args[1] ?? ctx.getCurrentProvider();
|
|
1179
|
+
if (!ctx.providers.has(providerId)) {
|
|
1180
|
+
ctx.renderer.printInfo(`Provider is not configured: ${providerId}`);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
ctx.renderer.printInfo(`Refreshing models for ${providerId}...`);
|
|
1184
|
+
try {
|
|
1185
|
+
const models = await ctx.providers.refreshModels(providerId);
|
|
1186
|
+
ctx.renderer.printSuccess(`Refreshed ${models.length} model(s) for ${providerId}.`);
|
|
1187
|
+
} catch (err) {
|
|
1188
|
+
ctx.renderer.printInfo(`Model refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1189
|
+
}
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
if (sub === "cache") {
|
|
1193
|
+
if ((args[1] ?? "").toLowerCase() === "clear") {
|
|
1194
|
+
const providerId = args[2];
|
|
1195
|
+
ctx.providers.clearModelCache(providerId);
|
|
1196
|
+
ctx.renderer.printSuccess(providerId ? `Cleared model cache for ${providerId}.` : "Cleared model cache.");
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
const rows = ctx.providers.getModelCacheStatus();
|
|
1200
|
+
if (rows.length === 0) {
|
|
1201
|
+
ctx.renderer.printInfo("Model cache is empty. Use /model refresh to populate it.");
|
|
1202
|
+
return;
|
|
1203
|
+
}
|
|
1204
|
+
ctx.renderer.printTable(
|
|
1205
|
+
["Provider", "Models", "Fetched"],
|
|
1206
|
+
rows.map((row) => [row.providerId, row.count, row.fetchedAt])
|
|
1207
|
+
);
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1065
1210
|
let targetModel;
|
|
1066
1211
|
if (!args[0]) {
|
|
1067
|
-
const
|
|
1068
|
-
const models = await provider.listModels();
|
|
1212
|
+
const models = await ctx.providers.listModels(ctx.getCurrentProvider());
|
|
1069
1213
|
const currentModel = ctx.getCurrentModel();
|
|
1070
1214
|
const items = models.map((m) => ({
|
|
1071
1215
|
value: m.id,
|
|
@@ -1073,7 +1217,9 @@ No commands match "${filter}".
|
|
|
1073
1217
|
hint: [
|
|
1074
1218
|
m.displayName,
|
|
1075
1219
|
`ctx:${fmtCtx(m.contextWindow)}`,
|
|
1076
|
-
m.supportsThinking ? "
|
|
1220
|
+
m.supportsThinking ? "thinking" : "",
|
|
1221
|
+
m.metadataUnknown ? "metadata?" : "",
|
|
1222
|
+
m.source && m.source !== "curated" ? m.source : "",
|
|
1077
1223
|
m.id === currentModel ? "(current)" : ""
|
|
1078
1224
|
].filter(Boolean).join(" ")
|
|
1079
1225
|
}));
|
|
@@ -1187,7 +1333,7 @@ No commands match "${filter}".
|
|
|
1187
1333
|
{
|
|
1188
1334
|
name: "session",
|
|
1189
1335
|
description: "Session management",
|
|
1190
|
-
usage: "/session new|list|load <id>|show <id> [page]|page <n>|remove <id
|
|
1336
|
+
usage: "/session new|list [--limit N|--all] [--filter k=v] [--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]",
|
|
1191
1337
|
async execute(args, ctx) {
|
|
1192
1338
|
const sub = args[0];
|
|
1193
1339
|
if (sub === "new") {
|
|
@@ -1198,23 +1344,137 @@ No commands match "${filter}".
|
|
|
1198
1344
|
ctx.clearDevState();
|
|
1199
1345
|
ctx.renderer.printSuccess("New session started.");
|
|
1200
1346
|
} else if (sub === "list") {
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1347
|
+
const opts = parseSessionListArgs(args);
|
|
1348
|
+
const needFileSize = opts.verbose || opts.sort.field === "size";
|
|
1349
|
+
let allSessions = ctx.sessions.listSessions({ includeFileSize: needFileSize });
|
|
1350
|
+
if (allSessions.length === 0) {
|
|
1203
1351
|
ctx.renderer.printInfo("No saved sessions.");
|
|
1204
1352
|
return;
|
|
1205
1353
|
}
|
|
1354
|
+
const hasFilters = opts.filter.provider || opts.filter.model;
|
|
1355
|
+
const hasSearch = !!opts.search;
|
|
1356
|
+
const hasTimeFilter = opts.days !== null || opts.since !== null;
|
|
1357
|
+
const hasStale = opts.stale !== null;
|
|
1358
|
+
if (hasFilters) {
|
|
1359
|
+
const p = opts.filter.provider;
|
|
1360
|
+
const m = opts.filter.model;
|
|
1361
|
+
allSessions = allSessions.filter((s) => {
|
|
1362
|
+
if (p && !p.includes(s.provider.toLowerCase())) return false;
|
|
1363
|
+
if (m && !m.some((kw) => s.model.toLowerCase().includes(kw))) return false;
|
|
1364
|
+
return true;
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
if (hasSearch) {
|
|
1368
|
+
const q = opts.search.toLowerCase();
|
|
1369
|
+
allSessions = allSessions.filter(
|
|
1370
|
+
(s) => (s.title ?? "").toLowerCase().includes(q) || s.id.toLowerCase().includes(q)
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
if (hasTimeFilter) {
|
|
1374
|
+
const now = Date.now();
|
|
1375
|
+
let cutoff = 0;
|
|
1376
|
+
if (opts.since) {
|
|
1377
|
+
cutoff = new Date(opts.since).getTime();
|
|
1378
|
+
} else if (opts.days !== null) {
|
|
1379
|
+
cutoff = now - opts.days * 24 * 60 * 60 * 1e3;
|
|
1380
|
+
}
|
|
1381
|
+
if (!isNaN(cutoff)) {
|
|
1382
|
+
allSessions = allSessions.filter((s) => s.updated.getTime() >= cutoff);
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
const staleCutoff = hasStale ? Date.now() - opts.stale * 24 * 60 * 60 * 1e3 : 0;
|
|
1386
|
+
if (hasStale) {
|
|
1387
|
+
allSessions = allSessions.filter((s) => s.updated.getTime() < staleCutoff);
|
|
1388
|
+
}
|
|
1389
|
+
const defaultSort = opts.sort.field === "updated" && opts.sort.order === "desc";
|
|
1390
|
+
if (!defaultSort) {
|
|
1391
|
+
const mul = opts.sort.order === "asc" ? 1 : -1;
|
|
1392
|
+
allSessions = [...allSessions].sort((a, b) => {
|
|
1393
|
+
switch (opts.sort.field) {
|
|
1394
|
+
case "created":
|
|
1395
|
+
return (a.created.getTime() - b.created.getTime()) * mul;
|
|
1396
|
+
case "messages":
|
|
1397
|
+
return (a.messageCount - b.messageCount) * mul;
|
|
1398
|
+
case "size":
|
|
1399
|
+
return ((a.fileSize ?? 0) - (b.fileSize ?? 0)) * mul;
|
|
1400
|
+
default:
|
|
1401
|
+
return (a.updated.getTime() - b.updated.getTime()) * mul;
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
const totalCount = allSessions.length;
|
|
1406
|
+
if (totalCount === 0) {
|
|
1407
|
+
ctx.renderer.printInfo("No sessions match the filter criteria.");
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
if (opts.json) {
|
|
1411
|
+
const sliced2 = opts.limit > 0 ? allSessions.slice(0, opts.limit) : allSessions;
|
|
1412
|
+
const payload = sliced2.map((s) => ({
|
|
1413
|
+
id: s.id,
|
|
1414
|
+
title: s.title ?? null,
|
|
1415
|
+
provider: s.provider,
|
|
1416
|
+
model: s.model,
|
|
1417
|
+
messageCount: s.messageCount,
|
|
1418
|
+
created: s.created.toISOString(),
|
|
1419
|
+
updated: s.updated.toISOString(),
|
|
1420
|
+
...needFileSize ? { fileSize: s.fileSize } : {},
|
|
1421
|
+
...s.branchCount !== void 0 ? { branchCount: s.branchCount, activeBranch: s.activeBranch } : {}
|
|
1422
|
+
}));
|
|
1423
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
1424
|
+
if (opts.limit > 0 && totalCount > opts.limit) {
|
|
1425
|
+
console.error(
|
|
1426
|
+
`
|
|
1427
|
+
(truncated: ${opts.limit} of ${totalCount} sessions shown; use --all for full list)`
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const sliced = opts.limit > 0 ? allSessions.slice(0, opts.limit) : allSessions;
|
|
1433
|
+
const headers = ["ID (short)", "Provider", "Model", "Messages"];
|
|
1434
|
+
if (opts.verbose) {
|
|
1435
|
+
headers.push("Size");
|
|
1436
|
+
headers.push("Br");
|
|
1437
|
+
}
|
|
1438
|
+
headers.push("Date", "Title");
|
|
1439
|
+
const rows = sliced.map((s) => {
|
|
1440
|
+
const isStale = hasStale ? s.updated.getTime() < staleCutoff : false;
|
|
1441
|
+
const dim = isStale ? theme.dim : (x) => String(x);
|
|
1442
|
+
const row = [
|
|
1443
|
+
dim(s.id.slice(0, 8)),
|
|
1444
|
+
dim(s.provider),
|
|
1445
|
+
dim(s.model),
|
|
1446
|
+
s.messageCount
|
|
1447
|
+
];
|
|
1448
|
+
if (opts.verbose) {
|
|
1449
|
+
row.push(
|
|
1450
|
+
s.fileSize !== void 0 ? formatFileSize(s.fileSize) : "\u2014",
|
|
1451
|
+
s.branchCount ?? 1
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
row.push(
|
|
1455
|
+
formatSessionDate(s.updated),
|
|
1456
|
+
dim(truncateTitle(s.title ?? "(untitled)", MAX_TITLE_WIDTH))
|
|
1457
|
+
);
|
|
1458
|
+
return row;
|
|
1459
|
+
});
|
|
1206
1460
|
console.log();
|
|
1207
|
-
ctx.renderer.printTable(
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1461
|
+
ctx.renderer.printTable(headers, rows);
|
|
1462
|
+
const totalMessages = allSessions.reduce((sum, s) => sum + s.messageCount, 0);
|
|
1463
|
+
const shown = sliced.length;
|
|
1464
|
+
const filterHints = [];
|
|
1465
|
+
if (hasFilters) filterHints.push("filtered");
|
|
1466
|
+
if (hasSearch) filterHints.push("searched");
|
|
1467
|
+
if (hasTimeFilter) filterHints.push("time-limited");
|
|
1468
|
+
if (hasStale) filterHints.push(`stale >${opts.stale}d`);
|
|
1469
|
+
const filterTag = filterHints.length > 0 ? ` (${filterHints.join(", ")})` : "";
|
|
1470
|
+
console.log(
|
|
1471
|
+
theme.dim(
|
|
1472
|
+
` \u2500\u2500 ${shown} of ${totalCount} sessions${filterTag} \xB7 ${totalMessages} messages total`
|
|
1473
|
+
)
|
|
1217
1474
|
);
|
|
1475
|
+
if (shown < totalCount) {
|
|
1476
|
+
console.log(theme.dim(` Use --all to show all, or --limit N to change count.`));
|
|
1477
|
+
}
|
|
1218
1478
|
} else if (sub === "load" || sub === "show") {
|
|
1219
1479
|
const id = args[1];
|
|
1220
1480
|
if (!id) {
|
|
@@ -1302,6 +1562,71 @@ No commands match "${filter}".
|
|
|
1302
1562
|
ctx.clearDevState();
|
|
1303
1563
|
ctx.renderer.printInfo("Current session was deleted \u2014 started a fresh session.");
|
|
1304
1564
|
}
|
|
1565
|
+
} else if (sub === "clean") {
|
|
1566
|
+
let staleDays = 90;
|
|
1567
|
+
let dryRun = false;
|
|
1568
|
+
for (let i = 1; i < args.length; i++) {
|
|
1569
|
+
if (args[i] === "--stale" && i + 1 < args.length) {
|
|
1570
|
+
const n = Number(args[++i]);
|
|
1571
|
+
if (Number.isFinite(n) && n > 0) staleDays = n;
|
|
1572
|
+
} else if (args[i] === "--dry-run") {
|
|
1573
|
+
dryRun = true;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
const cutoff = Date.now() - staleDays * 24 * 60 * 60 * 1e3;
|
|
1577
|
+
const allSessions = ctx.sessions.listSessions();
|
|
1578
|
+
const stale = allSessions.filter((s) => s.updated.getTime() < cutoff);
|
|
1579
|
+
if (stale.length === 0) {
|
|
1580
|
+
ctx.renderer.printInfo(`No sessions older than ${staleDays} days found.`);
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
console.log();
|
|
1584
|
+
console.log(
|
|
1585
|
+
theme.warning(
|
|
1586
|
+
` Found ${stale.length} session(s) not updated in ${staleDays}+ days:`
|
|
1587
|
+
)
|
|
1588
|
+
);
|
|
1589
|
+
for (const s of stale.slice(0, 20)) {
|
|
1590
|
+
console.log(
|
|
1591
|
+
theme.dim(
|
|
1592
|
+
` ${s.id.slice(0, 12)} ${String(s.messageCount).padStart(4)} msgs ${s.updated.toISOString().slice(0, 10)} ${truncateTitle(s.title ?? "(untitled)", 60)}`
|
|
1593
|
+
)
|
|
1594
|
+
);
|
|
1595
|
+
}
|
|
1596
|
+
if (stale.length > 20) {
|
|
1597
|
+
console.log(theme.dim(` ... and ${stale.length - 20} more`));
|
|
1598
|
+
}
|
|
1599
|
+
if (dryRun) {
|
|
1600
|
+
console.log(
|
|
1601
|
+
theme.info(`
|
|
1602
|
+
--dry-run: no sessions were deleted. Remove --dry-run to actually delete.`)
|
|
1603
|
+
);
|
|
1604
|
+
return;
|
|
1605
|
+
}
|
|
1606
|
+
console.log();
|
|
1607
|
+
const choice = await ctx.select(
|
|
1608
|
+
`Delete all ${stale.length} stale sessions?`,
|
|
1609
|
+
[
|
|
1610
|
+
{ label: "No \u2014 keep them", value: "no" },
|
|
1611
|
+
{ label: "Yes \u2014 delete permanently", value: "yes", hint: "unlinks all stale history files" }
|
|
1612
|
+
]
|
|
1613
|
+
);
|
|
1614
|
+
if (choice !== "yes") {
|
|
1615
|
+
ctx.renderer.printInfo("Cancelled \u2014 no sessions deleted.");
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
let deleted = 0;
|
|
1619
|
+
let failed = 0;
|
|
1620
|
+
for (const s of stale) {
|
|
1621
|
+
if (ctx.sessions.deleteSession(s.id)) {
|
|
1622
|
+
deleted++;
|
|
1623
|
+
} else {
|
|
1624
|
+
failed++;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
ctx.renderer.printSuccess(
|
|
1628
|
+
`Cleaned up: ${deleted} deleted${failed > 0 ? `, ${failed} failed` : ""}.`
|
|
1629
|
+
);
|
|
1305
1630
|
} else {
|
|
1306
1631
|
ctx.renderer.renderError("Usage: /session new|list|load <id>|show <id> [page]|page <n>|remove <id>");
|
|
1307
1632
|
}
|
|
@@ -1761,7 +2086,7 @@ No tools match "${filter}".
|
|
|
1761
2086
|
const { join: join5 } = await import("path");
|
|
1762
2087
|
const { existsSync: existsSync5 } = await import("fs");
|
|
1763
2088
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1764
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
2089
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-EJRLT7DM.js");
|
|
1765
2090
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1766
2091
|
const cwd = process.cwd();
|
|
1767
2092
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2820,7 +3145,7 @@ ${hint}` : "")
|
|
|
2820
3145
|
usage: "/test [command|filter]",
|
|
2821
3146
|
async execute(args, ctx) {
|
|
2822
3147
|
try {
|
|
2823
|
-
const { executeTests } = await import("./run-tests-
|
|
3148
|
+
const { executeTests } = await import("./run-tests-OYXK27XH.js");
|
|
2824
3149
|
const argStr = args.join(" ").trim();
|
|
2825
3150
|
let testArgs = {};
|
|
2826
3151
|
if (argStr) {
|
|
@@ -3786,6 +4111,7 @@ var PROVIDERS = [
|
|
|
3786
4111
|
{ value: "zhipu", name: "Zhipu (GLM)" },
|
|
3787
4112
|
{ value: "kimi", name: "Kimi (Moonshot AI)" },
|
|
3788
4113
|
{ value: "minimax", name: "MiniMax (\u6D77\u87BA)" },
|
|
4114
|
+
{ value: "qwen", name: "Qwen (Alibaba Cloud)" },
|
|
3789
4115
|
{ value: "openai", name: "OpenAI" },
|
|
3790
4116
|
{ value: "openrouter", name: "OpenRouter" },
|
|
3791
4117
|
{ value: "ollama", name: "Ollama (Local)" }
|
|
@@ -7231,7 +7557,8 @@ program.command("providers").description("List all AI providers and their config
|
|
|
7231
7557
|
baseUrl: config.get("customBaseUrls")[id],
|
|
7232
7558
|
timeout: config.get("timeouts")[id]
|
|
7233
7559
|
}),
|
|
7234
|
-
config.get("customProviders")
|
|
7560
|
+
config.get("customProviders"),
|
|
7561
|
+
config.getConfigDir()
|
|
7235
7562
|
);
|
|
7236
7563
|
const all = registry.listAll();
|
|
7237
7564
|
console.log("\nAvailable providers:\n");
|
|
@@ -7255,7 +7582,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7255
7582
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7256
7583
|
process.exit(1);
|
|
7257
7584
|
}
|
|
7258
|
-
const { startWebServer } = await import("./server-
|
|
7585
|
+
const { startWebServer } = await import("./server-JKNIZ5CB.js");
|
|
7259
7586
|
await startWebServer({ port, host: options.host });
|
|
7260
7587
|
});
|
|
7261
7588
|
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) => {
|
|
@@ -7422,11 +7749,11 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7422
7749
|
console.log(footer + "\n");
|
|
7423
7750
|
});
|
|
7424
7751
|
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) => {
|
|
7425
|
-
const { runUsageCli } = await import("./usage-
|
|
7752
|
+
const { runUsageCli } = await import("./usage-4KFX3HTK.js");
|
|
7426
7753
|
await runUsageCli(options);
|
|
7427
7754
|
});
|
|
7428
7755
|
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) => {
|
|
7429
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7756
|
+
const { runDoctorCli } = await import("./doctor-cli-EXC7YU5D.js");
|
|
7430
7757
|
const argv = process.argv.slice(2);
|
|
7431
7758
|
await runDoctorCli({
|
|
7432
7759
|
json: !!options.json || argv.includes("--json"),
|
|
@@ -7435,7 +7762,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
|
|
|
7435
7762
|
});
|
|
7436
7763
|
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) => {
|
|
7437
7764
|
try {
|
|
7438
|
-
const batch = await import("./batch-
|
|
7765
|
+
const batch = await import("./batch-LSWWSINO.js");
|
|
7439
7766
|
switch (action) {
|
|
7440
7767
|
case "submit":
|
|
7441
7768
|
if (!arg) {
|
|
@@ -7478,7 +7805,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7478
7805
|
}
|
|
7479
7806
|
});
|
|
7480
7807
|
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) => {
|
|
7481
|
-
const { startMcpServer } = await import("./server-
|
|
7808
|
+
const { startMcpServer } = await import("./server-XX6UM4ZQ.js");
|
|
7482
7809
|
await startMcpServer({
|
|
7483
7810
|
allowDestructive: !!options.allowDestructive,
|
|
7484
7811
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7491,7 +7818,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
7491
7818
|
console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
|
|
7492
7819
|
process.exit(1);
|
|
7493
7820
|
}
|
|
7494
|
-
const { runPrCli } = await import("./pr-
|
|
7821
|
+
const { runPrCli } = await import("./pr-VSZNVKBS.js");
|
|
7495
7822
|
const result = await runPrCli({
|
|
7496
7823
|
action,
|
|
7497
7824
|
target,
|
|
@@ -7511,8 +7838,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
7511
7838
|
process.exit(result.exitCode);
|
|
7512
7839
|
});
|
|
7513
7840
|
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) => {
|
|
7514
|
-
const { runCi } = await import("./ci-
|
|
7515
|
-
const { formatCiResult } = await import("./ci-format-
|
|
7841
|
+
const { runCi } = await import("./ci-OIFTAJKR.js");
|
|
7842
|
+
const { formatCiResult } = await import("./ci-format-H6BLMWQ5.js");
|
|
7516
7843
|
const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
|
|
7517
7844
|
if (formats > 1) {
|
|
7518
7845
|
console.error("Choose only one output format: --json, --markdown, or --sarif.");
|
|
@@ -7667,9 +7994,10 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7667
7994
|
baseUrl: config.get("customBaseUrls")[id],
|
|
7668
7995
|
timeout: config.get("timeouts")[id]
|
|
7669
7996
|
}),
|
|
7670
|
-
config.get("customProviders")
|
|
7997
|
+
config.get("customProviders"),
|
|
7998
|
+
config.getConfigDir()
|
|
7671
7999
|
);
|
|
7672
|
-
const { startHub } = await import("./hub-
|
|
8000
|
+
const { startHub } = await import("./hub-HQDRQBNM.js");
|
|
7673
8001
|
await startHub(
|
|
7674
8002
|
{
|
|
7675
8003
|
topic: topic ?? "",
|
|
@@ -7702,7 +8030,8 @@ program.command("join").description("Join a running hub as a remote AI agent").o
|
|
|
7702
8030
|
baseUrl: config.get("customBaseUrls")[id],
|
|
7703
8031
|
timeout: config.get("timeouts")[id]
|
|
7704
8032
|
}),
|
|
7705
|
-
config.get("customProviders")
|
|
8033
|
+
config.get("customProviders"),
|
|
8034
|
+
config.getConfigDir()
|
|
7706
8035
|
);
|
|
7707
8036
|
const { joinHub } = await import("./agent-client-6GX6QQDU.js");
|
|
7708
8037
|
await joinHub(
|
|
@@ -7743,7 +8072,8 @@ async function runHeadless(options) {
|
|
|
7743
8072
|
timeout: config.get("timeouts")[id],
|
|
7744
8073
|
proxy: config.get("proxy")
|
|
7745
8074
|
}),
|
|
7746
|
-
config.get("customProviders")
|
|
8075
|
+
config.get("customProviders"),
|
|
8076
|
+
config.getConfigDir()
|
|
7747
8077
|
);
|
|
7748
8078
|
const providerId = options.provider ?? config.getDefaultProvider();
|
|
7749
8079
|
if (!providers.has(providerId)) {
|
|
@@ -7902,7 +8232,8 @@ async function startRepl(options) {
|
|
|
7902
8232
|
timeout: config.get("timeouts")[id],
|
|
7903
8233
|
proxy: config.get("proxy")
|
|
7904
8234
|
}),
|
|
7905
|
-
config.get("customProviders")
|
|
8235
|
+
config.get("customProviders"),
|
|
8236
|
+
config.getConfigDir()
|
|
7906
8237
|
);
|
|
7907
8238
|
if (providers.listAvailable().length === 0) {
|
|
7908
8239
|
console.error(
|