prompt-skill-armory 0.9.2 → 0.9.7
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.en.md +3 -3
- package/README.md +3 -3
- package/package.json +1 -1
- package/packages/client-ui-switchblade/lib/client.js +221 -60
- package/packages/client-ui-switchblade/lib/client.js.map +1 -1
- package/packages/client-ui-switchblade/package.json +1 -1
- package/packages/client-ui-switchblade/src/client/SwitchbladeSection.tsx +133 -28
- package/packages/client-ui-switchblade/src/client/conversations.ts +20 -13
- package/packages/switchblade/lib/index.js +296 -37
- package/packages/switchblade/lib/switchblade.js +296 -37
- package/packages/switchblade/package.json +1 -1
- package/packages/switchblade/src/conversations.ts +293 -31
package/README.en.md
CHANGED
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
|--|--|--|--|
|
|
13
13
|
| <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
|
|
14
14
|
|
|
15
|
-

|
|
16
16
|

|
|
17
17
|

|
|
18
18
|

|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
✦ Armory v0.9.
|
|
21
|
+
✦ Armory v0.9.7
|
|
22
22
|
┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
|
|
23
23
|
│ Prompts │ Skills │ MCP │ Wallpaper │ Chat │ Stats│
|
|
24
24
|
│ global │ merged │ hub │ wallpaper │ sync │ usage│
|
|
@@ -111,7 +111,7 @@ Achieved via profile composition (the installer mounts the panel into each profi
|
|
|
111
111
|
|
|
112
112
|
Every time the panel opens it queries npm for the latest `prompt-skill-armory` version; when a newer version exists a banner appears:
|
|
113
113
|
|
|
114
|
-
> New version vX.Y.Z (current v0.9.
|
|
114
|
+
> New version vX.Y.Z (current v0.9.7) [Update now]
|
|
115
115
|
|
|
116
116
|
Clicking "Update now" makes the Host re-run the official installer in place → "Update complete, please restart the client".
|
|
117
117
|
|
package/README.md
CHANGED
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
|--|--|--|--|
|
|
13
13
|
| <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
|
|
14
14
|
|
|
15
|
-

|
|
16
16
|

|
|
17
17
|

|
|
18
18
|

|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
✦ Armory v0.9.
|
|
21
|
+
✦ Armory v0.9.7
|
|
22
22
|
┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
|
|
23
23
|
│ 提示词 │ 技能 │ MCP │ Wallpaper │ 对话 │ 统计 │
|
|
24
24
|
│ 全局注入 │ 合并管理 │ 连接 │ 壁纸·特效 │ 导入 │ 用量 │
|
|
@@ -114,7 +114,7 @@ pnpm dsh web
|
|
|
114
114
|
|
|
115
115
|
插件面板每次打开会自动查询 npm 上 `prompt-skill-armory` 的最新版本;发现新版本时顶部显示横幅:
|
|
116
116
|
|
|
117
|
-
> 有新版本 vX.Y.Z(当前 v0.9.
|
|
117
|
+
> 有新版本 vX.Y.Z(当前 v0.9.7) [一键更新]
|
|
118
118
|
|
|
119
119
|
点击「一键更新」→ Host 端运行官方安装器原地重装 → 提示「更新完成,请重启客户端生效」。
|
|
120
120
|
|
package/package.json
CHANGED
|
@@ -521,13 +521,14 @@ window.__ModuleLoader__.load({
|
|
|
521
521
|
return [];
|
|
522
522
|
}
|
|
523
523
|
}
|
|
524
|
-
async function exportConversations(ids) {
|
|
524
|
+
async function exportConversations(ids, projectKey) {
|
|
525
525
|
try {
|
|
526
526
|
const b = await (await fetch("/api/armory/export", {
|
|
527
527
|
method: "POST",
|
|
528
528
|
headers: { "content-type": "application/json" },
|
|
529
529
|
body: JSON.stringify({
|
|
530
530
|
sessionIds: ids,
|
|
531
|
+
projectKey,
|
|
531
532
|
includeAttachments: false,
|
|
532
533
|
includeWorkspace: false
|
|
533
534
|
})
|
|
@@ -538,15 +539,22 @@ window.__ModuleLoader__.load({
|
|
|
538
539
|
}
|
|
539
540
|
}
|
|
540
541
|
async function downloadExport(name) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
542
|
+
try {
|
|
543
|
+
const r = await fetch(`/api/armory/export/${name}`);
|
|
544
|
+
if (!r.ok) return false;
|
|
545
|
+
const blob = await r.blob();
|
|
546
|
+
const url = URL.createObjectURL(blob);
|
|
547
|
+
const a = document.createElement("a");
|
|
548
|
+
a.href = url;
|
|
549
|
+
a.download = name;
|
|
550
|
+
document.body.appendChild(a);
|
|
551
|
+
a.click();
|
|
552
|
+
a.remove();
|
|
553
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e3);
|
|
554
|
+
return true;
|
|
555
|
+
} catch {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
550
558
|
}
|
|
551
559
|
async function deleteConversations(ids) {
|
|
552
560
|
try {
|
|
@@ -555,7 +563,11 @@ window.__ModuleLoader__.load({
|
|
|
555
563
|
headers: { "content-type": "application/json" },
|
|
556
564
|
body: JSON.stringify({ sessionIds: ids })
|
|
557
565
|
})).json();
|
|
558
|
-
|
|
566
|
+
if (!b.ok) return null;
|
|
567
|
+
return {
|
|
568
|
+
deleted: b.deleted ?? 0,
|
|
569
|
+
failed: Array.isArray(b.failed) ? b.failed : []
|
|
570
|
+
};
|
|
559
571
|
} catch {
|
|
560
572
|
return null;
|
|
561
573
|
}
|
|
@@ -946,7 +958,7 @@ window.__ModuleLoader__.load({
|
|
|
946
958
|
});
|
|
947
959
|
}
|
|
948
960
|
/** Bump with every release; keep in sync with package.json version + CHANGELOG. */
|
|
949
|
-
const ARMORY_VERSION = "0.9.
|
|
961
|
+
const ARMORY_VERSION = "0.9.7";
|
|
950
962
|
/** Compact duration: 45.2s / 2m42s / 1h05m. */
|
|
951
963
|
function fmtDuration(ms) {
|
|
952
964
|
const s = ms / 1e3;
|
|
@@ -990,13 +1002,29 @@ window.__ModuleLoader__.load({
|
|
|
990
1002
|
children: "暂无趋势数据"
|
|
991
1003
|
});
|
|
992
1004
|
const maxSteps = Math.max(...byDay.map((d) => d.steps), 1);
|
|
993
|
-
const maxTokens = Math.max(...byDay.map((d) => d.outputTokens), 1);
|
|
1005
|
+
const maxTokens = Math.max(...byDay.map((d) => d.outputTokens), ...byDay.map((d) => d.inputTokens), ...byDay.map((d) => d.cacheReadTokens), ...byDay.map((d) => d.cacheWriteTokens), 1);
|
|
1006
|
+
const logBase = Math.max(Math.log10(maxTokens), 1);
|
|
994
1007
|
const x = (i) => PAD.l + (n === 1 ? iw / 2 : i / (n - 1) * iw);
|
|
995
1008
|
const ySteps = (v) => PAD.t + ih - v / maxSteps * ih;
|
|
996
|
-
const yTok = (v) =>
|
|
1009
|
+
const yTok = (v) => {
|
|
1010
|
+
const vv = Math.max(v, 1);
|
|
1011
|
+
return PAD.t + ih - Math.log10(vv) / logBase * ih;
|
|
1012
|
+
};
|
|
997
1013
|
const pathSteps = byDay.map((d, i) => `${i === 0 ? "M" : "L"}${x(i).toFixed(1)},${ySteps(d.steps).toFixed(1)}`).join(" ");
|
|
998
1014
|
const pathOut = byDay.map((d, i) => `${i === 0 ? "M" : "L"}${x(i).toFixed(1)},${yTok(d.outputTokens).toFixed(1)}`).join(" ");
|
|
999
1015
|
const pathIn = byDay.map((d, i) => `${i === 0 ? "M" : "L"}${x(i).toFixed(1)},${yTok(d.inputTokens).toFixed(1)}`).join(" ");
|
|
1016
|
+
const tokTicks = [
|
|
1017
|
+
0,
|
|
1018
|
+
.25,
|
|
1019
|
+
.5,
|
|
1020
|
+
.75,
|
|
1021
|
+
1
|
|
1022
|
+
].map((f) => Math.pow(10, f * logBase));
|
|
1023
|
+
const niceToken = (v) => {
|
|
1024
|
+
if (v >= 1e6) return `${(v / 1e6).toFixed(v % 1e6 === 0 ? 0 : 1)}M`;
|
|
1025
|
+
if (v >= 1e3) return `${(v / 1e3).toFixed(v % 1e3 === 0 ? 0 : 1)}k`;
|
|
1026
|
+
return String(Math.round(v));
|
|
1027
|
+
};
|
|
1000
1028
|
const grid = [
|
|
1001
1029
|
0,
|
|
1002
1030
|
1,
|
|
@@ -1038,12 +1066,15 @@ window.__ModuleLoader__.load({
|
|
|
1038
1066
|
fill: "#8b949e",
|
|
1039
1067
|
children: g.label
|
|
1040
1068
|
})] }, i)),
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1069
|
+
tokTicks.map((v, i) => {
|
|
1070
|
+
const yy = yTok(v);
|
|
1071
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
1072
|
+
x: W - PAD.r + 6,
|
|
1073
|
+
y: yy + 3,
|
|
1074
|
+
fontSize: "9",
|
|
1075
|
+
fill: i === 4 ? "#3fb950" : "#8b949e",
|
|
1076
|
+
children: niceToken(v)
|
|
1077
|
+
}, i);
|
|
1047
1078
|
}),
|
|
1048
1079
|
byDay.map((d, i) => {
|
|
1049
1080
|
if (n > 7 && i % Math.ceil(n / 7) !== 0 && i !== n - 1) return null;
|
|
@@ -1110,21 +1141,40 @@ window.__ModuleLoader__.load({
|
|
|
1110
1141
|
stroke: "#0d1117",
|
|
1111
1142
|
strokeWidth: "1"
|
|
1112
1143
|
}),
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
}),
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1144
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1145
|
+
cx: x(i),
|
|
1146
|
+
cy: yTok(d.inputTokens),
|
|
1147
|
+
r: hover === i ? 4 : 3,
|
|
1148
|
+
fill: "#58a6ff",
|
|
1149
|
+
stroke: "#0d1117",
|
|
1150
|
+
strokeWidth: "1"
|
|
1151
|
+
}),
|
|
1152
|
+
n <= 4 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1153
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
1154
|
+
x: x(i),
|
|
1155
|
+
y: ySteps(d.steps) - 6,
|
|
1156
|
+
textAnchor: "middle",
|
|
1157
|
+
fontSize: "8.5",
|
|
1158
|
+
fill: "#d29922",
|
|
1159
|
+
children: d.steps
|
|
1160
|
+
}),
|
|
1161
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
1162
|
+
x: x(i),
|
|
1163
|
+
y: yTok(d.outputTokens) - 6,
|
|
1164
|
+
textAnchor: "middle",
|
|
1165
|
+
fontSize: "8.5",
|
|
1166
|
+
fill: "#3fb950",
|
|
1167
|
+
children: fmtTokens(d.outputTokens)
|
|
1168
|
+
}),
|
|
1169
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
1170
|
+
x: x(i),
|
|
1171
|
+
y: yTok(d.inputTokens) - 6,
|
|
1172
|
+
textAnchor: "middle",
|
|
1173
|
+
fontSize: "8.5",
|
|
1174
|
+
fill: "#58a6ff",
|
|
1175
|
+
children: fmtTokens(d.inputTokens)
|
|
1176
|
+
})
|
|
1177
|
+
] })
|
|
1128
1178
|
] }, i))
|
|
1129
1179
|
]
|
|
1130
1180
|
}),
|
|
@@ -1278,6 +1328,7 @@ window.__ModuleLoader__.load({
|
|
|
1278
1328
|
const [chatRows, setChatRows] = (0, react.useState)([]);
|
|
1279
1329
|
const [chatSelected, setChatSelected] = (0, react.useState)(/* @__PURE__ */ new Set());
|
|
1280
1330
|
const [chatTarget, setChatTarget] = (0, react.useState)("");
|
|
1331
|
+
const [chatProject, setChatProject] = (0, react.useState)("");
|
|
1281
1332
|
const [chatBusy, setChatBusy] = (0, react.useState)(false);
|
|
1282
1333
|
const [chatMsg, setChatMsg] = (0, react.useState)("");
|
|
1283
1334
|
const [latestVer, setLatestVer] = (0, react.useState)("");
|
|
@@ -1285,13 +1336,30 @@ window.__ModuleLoader__.load({
|
|
|
1285
1336
|
const [updateMsg, setUpdateMsg] = (0, react.useState)("");
|
|
1286
1337
|
const [stats, setStats] = (0, react.useState)(null);
|
|
1287
1338
|
const [statsRange, setStatsRange] = (0, react.useState)("all");
|
|
1339
|
+
const [statsUpdatedAt, setStatsUpdatedAt] = (0, react.useState)(0);
|
|
1288
1340
|
const reloadStats = async () => {
|
|
1289
|
-
|
|
1341
|
+
const s = await fetchStats(statsRange);
|
|
1342
|
+
if (s !== null) {
|
|
1343
|
+
setStats(s);
|
|
1344
|
+
setStatsUpdatedAt(Date.now());
|
|
1345
|
+
}
|
|
1290
1346
|
};
|
|
1291
1347
|
const changeStatsRange = (r) => {
|
|
1292
1348
|
setStatsRange(r);
|
|
1293
|
-
fetchStats(r).then(
|
|
1349
|
+
fetchStats(r).then((s) => {
|
|
1350
|
+
if (s !== null) {
|
|
1351
|
+
setStats(s);
|
|
1352
|
+
setStatsUpdatedAt(Date.now());
|
|
1353
|
+
}
|
|
1354
|
+
});
|
|
1294
1355
|
};
|
|
1356
|
+
(0, react.useEffect)(() => {
|
|
1357
|
+
if (activeTab !== "stats") return;
|
|
1358
|
+
const timer = setInterval(() => {
|
|
1359
|
+
reloadStats();
|
|
1360
|
+
}, 3e4);
|
|
1361
|
+
return () => clearInterval(timer);
|
|
1362
|
+
}, [activeTab, statsRange]);
|
|
1295
1363
|
(0, react.useEffect)(() => {
|
|
1296
1364
|
checkLatestVersion().then((v) => {
|
|
1297
1365
|
if (v !== "") setLatestVer(v);
|
|
@@ -1311,18 +1379,59 @@ window.__ModuleLoader__.load({
|
|
|
1311
1379
|
return n;
|
|
1312
1380
|
});
|
|
1313
1381
|
};
|
|
1382
|
+
const chatProjects = (0, react.useMemo)(() => {
|
|
1383
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1384
|
+
for (const row of chatRows) {
|
|
1385
|
+
const name = row.cwd ? row.cwd.split(/[\\/]/).filter(Boolean).pop() ?? row.projectKey : row.projectKey;
|
|
1386
|
+
if (!byKey.has(row.projectKey)) byKey.set(row.projectKey, name);
|
|
1387
|
+
}
|
|
1388
|
+
return [...byKey.entries()].map(([key, name]) => ({
|
|
1389
|
+
key,
|
|
1390
|
+
name
|
|
1391
|
+
})).sort((a, b) => a.name.localeCompare(b.name));
|
|
1392
|
+
}, [chatRows]);
|
|
1393
|
+
(0, react.useEffect)(() => {
|
|
1394
|
+
if (chatProject === "" && chatProjects.length > 0) setChatProject(chatProjects[0].key);
|
|
1395
|
+
else if (chatProject !== "" && !chatProjects.some((p) => p.key === chatProject)) setChatProject(chatProjects[0]?.key ?? "");
|
|
1396
|
+
}, [chatProjects, chatProject]);
|
|
1314
1397
|
const doExportChat = async () => {
|
|
1315
1398
|
setChatBusy(true);
|
|
1316
1399
|
setChatMsg("");
|
|
1317
|
-
|
|
1318
|
-
|
|
1400
|
+
try {
|
|
1401
|
+
const name = await exportConversations([...chatSelected]);
|
|
1402
|
+
if (name === null) {
|
|
1403
|
+
setChatMsg("导出失败");
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
const ok = await downloadExport(name);
|
|
1407
|
+
setChatMsg(ok ? `已导出 ${name}` : "导出失败:下载未完成");
|
|
1408
|
+
} catch {
|
|
1319
1409
|
setChatMsg("导出失败");
|
|
1410
|
+
} finally {
|
|
1320
1411
|
setChatBusy(false);
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
const doExportProject = async () => {
|
|
1415
|
+
const key = chatProject.trim();
|
|
1416
|
+
if (key === "") {
|
|
1417
|
+
setChatMsg("请先选择项目工作区");
|
|
1321
1418
|
return;
|
|
1322
1419
|
}
|
|
1323
|
-
|
|
1324
|
-
setChatMsg(
|
|
1325
|
-
|
|
1420
|
+
setChatBusy(true);
|
|
1421
|
+
setChatMsg("");
|
|
1422
|
+
try {
|
|
1423
|
+
const name = await exportConversations([], key);
|
|
1424
|
+
if (name === null) {
|
|
1425
|
+
setChatMsg("导出失败");
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
const ok = await downloadExport(name);
|
|
1429
|
+
setChatMsg(ok ? `已导出整个项目 ${key} → ${name}` : "导出失败:下载未完成");
|
|
1430
|
+
} catch {
|
|
1431
|
+
setChatMsg("导出失败");
|
|
1432
|
+
} finally {
|
|
1433
|
+
setChatBusy(false);
|
|
1434
|
+
}
|
|
1326
1435
|
};
|
|
1327
1436
|
const doUpdate = async () => {
|
|
1328
1437
|
setUpdating(true);
|
|
@@ -1335,13 +1444,18 @@ window.__ModuleLoader__.load({
|
|
|
1335
1444
|
if (file === void 0) return;
|
|
1336
1445
|
setChatBusy(true);
|
|
1337
1446
|
setChatMsg("");
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1447
|
+
try {
|
|
1448
|
+
const n = await importConversations(file, chatTarget.trim() || void 0);
|
|
1449
|
+
setChatMsg(n === null ? "导入失败" : `已导入 ${n} 个对话,重启客户端后生效`);
|
|
1450
|
+
if (n !== null) {
|
|
1451
|
+
refreshSessions();
|
|
1452
|
+
await reloadChat();
|
|
1453
|
+
}
|
|
1454
|
+
} catch {
|
|
1455
|
+
setChatMsg("导入失败");
|
|
1456
|
+
} finally {
|
|
1457
|
+
setChatBusy(false);
|
|
1343
1458
|
}
|
|
1344
|
-
setChatBusy(false);
|
|
1345
1459
|
};
|
|
1346
1460
|
const doDeleteChat = async () => {
|
|
1347
1461
|
const ids = [...chatSelected];
|
|
@@ -1349,17 +1463,22 @@ window.__ModuleLoader__.load({
|
|
|
1349
1463
|
if (!window.confirm(`确定删除选中的 ${ids.length} 个对话吗?此操作不可恢复。`)) return;
|
|
1350
1464
|
setChatBusy(true);
|
|
1351
1465
|
setChatMsg("");
|
|
1352
|
-
|
|
1353
|
-
|
|
1466
|
+
try {
|
|
1467
|
+
const r = await deleteConversations(ids);
|
|
1468
|
+
if (r === null) {
|
|
1469
|
+
setChatMsg("删除失败");
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
setChatSelected(/* @__PURE__ */ new Set());
|
|
1473
|
+
const failMsg = r.failed.length > 0 ? `;${r.failed.length} 个删除失败(文件可能被占用,可稍后重试)` : "";
|
|
1474
|
+
setChatMsg(`已删除 ${r.deleted} 个对话${failMsg}`);
|
|
1475
|
+
refreshSessions();
|
|
1476
|
+
await reloadChat();
|
|
1477
|
+
} catch {
|
|
1354
1478
|
setChatMsg("删除失败");
|
|
1479
|
+
} finally {
|
|
1355
1480
|
setChatBusy(false);
|
|
1356
|
-
return;
|
|
1357
1481
|
}
|
|
1358
|
-
setChatSelected(/* @__PURE__ */ new Set());
|
|
1359
|
-
setChatMsg(`已删除 ${n} 个对话`);
|
|
1360
|
-
refreshSessions();
|
|
1361
|
-
await reloadChat();
|
|
1362
|
-
setChatBusy(false);
|
|
1363
1482
|
};
|
|
1364
1483
|
(0, react.useEffect)(() => {
|
|
1365
1484
|
const snap = backgroundClient.getSnapshot();
|
|
@@ -2468,7 +2587,7 @@ window.__ModuleLoader__.load({
|
|
|
2468
2587
|
...CSS.desc,
|
|
2469
2588
|
lineHeight: "1.5"
|
|
2470
2589
|
},
|
|
2471
|
-
children: "
|
|
2590
|
+
children: "可导出选中的对话,也可下拉选择某个项目工作区整体导出;导入后项目工作区名会尽量与导出端保持一致。"
|
|
2472
2591
|
}),
|
|
2473
2592
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2474
2593
|
style: CSS.actions,
|
|
@@ -2483,6 +2602,36 @@ window.__ModuleLoader__.load({
|
|
|
2483
2602
|
")"
|
|
2484
2603
|
]
|
|
2485
2604
|
}),
|
|
2605
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2606
|
+
style: CSS.actionBtn,
|
|
2607
|
+
disabled: chatBusy || chatProject === "",
|
|
2608
|
+
onClick: () => void doExportProject(),
|
|
2609
|
+
title: "导出该项目工作区下的全部对话,导入后可保留项目名",
|
|
2610
|
+
children: "导出整个项目"
|
|
2611
|
+
}),
|
|
2612
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2613
|
+
style: {
|
|
2614
|
+
...CSS.input,
|
|
2615
|
+
maxWidth: "220px",
|
|
2616
|
+
textOverflow: "ellipsis"
|
|
2617
|
+
},
|
|
2618
|
+
value: chatProject,
|
|
2619
|
+
onChange: (e) => setChatProject(e.target.value),
|
|
2620
|
+
disabled: chatProjects.length === 0,
|
|
2621
|
+
title: "选择要整体导出的项目工作区",
|
|
2622
|
+
children: [chatProjects.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2623
|
+
value: "",
|
|
2624
|
+
children: "(无项目)"
|
|
2625
|
+
}), chatProjects.map((p) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
2626
|
+
value: p.key,
|
|
2627
|
+
children: [
|
|
2628
|
+
p.name,
|
|
2629
|
+
"(",
|
|
2630
|
+
chatRows.filter((r) => r.projectKey === p.key).length,
|
|
2631
|
+
" 个对话)"
|
|
2632
|
+
]
|
|
2633
|
+
}, p.key))]
|
|
2634
|
+
}),
|
|
2486
2635
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2487
2636
|
style: {
|
|
2488
2637
|
...CSS.actionBtn,
|
|
@@ -2559,8 +2708,13 @@ window.__ModuleLoader__.load({
|
|
|
2559
2708
|
style: {
|
|
2560
2709
|
...CSS.badge,
|
|
2561
2710
|
...CSS.badgeDisabled,
|
|
2562
|
-
flex: "none"
|
|
2711
|
+
flex: "none",
|
|
2712
|
+
maxWidth: "150px",
|
|
2713
|
+
overflow: "hidden",
|
|
2714
|
+
textOverflow: "ellipsis",
|
|
2715
|
+
whiteSpace: "nowrap"
|
|
2563
2716
|
},
|
|
2717
|
+
title: row.cwd || row.projectKey,
|
|
2564
2718
|
children: row.cwd ? row.cwd.split(/[\\/]/).filter(Boolean).pop() : row.projectKey
|
|
2565
2719
|
})]
|
|
2566
2720
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2592,12 +2746,19 @@ window.__ModuleLoader__.load({
|
|
|
2592
2746
|
gap: "8px",
|
|
2593
2747
|
flexWrap: "wrap"
|
|
2594
2748
|
},
|
|
2595
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
2749
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2596
2750
|
style: {
|
|
2597
2751
|
fontSize: "13px",
|
|
2598
2752
|
fontWeight: 600
|
|
2599
2753
|
},
|
|
2600
|
-
children: "使用统计"
|
|
2754
|
+
children: ["使用统计", statsUpdatedAt > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2755
|
+
style: {
|
|
2756
|
+
...CSS.hint,
|
|
2757
|
+
marginLeft: "8px",
|
|
2758
|
+
fontWeight: 400
|
|
2759
|
+
},
|
|
2760
|
+
children: ["自动刷新 · 上次更新 ", new Date(statsUpdatedAt).toLocaleTimeString()]
|
|
2761
|
+
})]
|
|
2601
2762
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2602
2763
|
style: {
|
|
2603
2764
|
display: "flex",
|