opencode-subagent-magazine 1.5.1 → 1.5.3
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 +3 -1
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +8 -0
- package/dist/index.js +47 -16
- package/dist/tui.js +80 -29
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/i18n.ts +8 -0
- package/src/index.tsx +58 -16
package/README.md
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
- **TTL 自动清理**:可配置数据保留期限(3/7/14/30 天/无期限),每次访问自动续期,过期自动清除
|
|
57
57
|
- **手动清除条目**:`/subagent-clear-entries` 清除当前会话所有记录,防止历史条目扫描重建
|
|
58
58
|
- **语言适配**:支持 `/subagent-lang` 运行时切换中/英文,偏好持久化
|
|
59
|
-
-
|
|
59
|
+
- **可切换边框**:`/subagent-border` 控制面板外边框显隐(默认隐藏),开启后与缓存统计面板风格统一
|
|
60
|
+
- **斜杠命令**:`/subagent-lang` `/subagent-max` `/subagent-order` `/subagent-scroll` `/subagent-ttl` `/subagent-clear-entries` `/subagent-session` `/subagent-version` `/subagent-clear-running` `/subagent-border` 动态配置
|
|
60
61
|
|
|
61
62
|
---
|
|
62
63
|
|
|
@@ -114,6 +115,7 @@ npm install -g opencode-subagent-magazine@latest
|
|
|
114
115
|
| `/subagent-session` | 查看当前会话 ID | 弹出当前 OpenCode 会话 ID |
|
|
115
116
|
| `/subagent-version` | 查看插件版本 | 弹出当前插件版本号 |
|
|
116
117
|
| `/subagent-clear-running` | 批量清理僵尸条目 | 一键将所有运行中的条目标记为完成,清理卡住的旧数据 |
|
|
118
|
+
| `/subagent-border` | 开关面板边框 | 切换面板外边框显隐(默认隐藏),即时生效并持久化 |
|
|
117
119
|
|
|
118
120
|
<div align="center">
|
|
119
121
|
<img src="https://raw.githubusercontent.com/Hotakus/opencode-subagent-magazine/master/assets/slash_cmds.png" alt="斜杠命令" width="49%"></img>
|
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "1.5.
|
|
1
|
+
export declare const PLUGIN_VERSION = "1.5.3";
|
package/dist/_version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION = "1.5.
|
|
2
|
+
export const PLUGIN_VERSION = "1.5.3";
|
package/dist/i18n.d.ts
CHANGED
|
@@ -49,6 +49,8 @@ declare const ZH_T: {
|
|
|
49
49
|
readonly "cancel.status_error": "无法查询会话状态";
|
|
50
50
|
readonly "cancel.sent": "已发送取消指令";
|
|
51
51
|
readonly "cancel.failed": "取消失败";
|
|
52
|
+
readonly borderShown: "面板边框 已显示";
|
|
53
|
+
readonly borderHidden: "面板边框 已隐藏";
|
|
52
54
|
};
|
|
53
55
|
/** 结构约束:值放宽为 string,键集合来自中文表(新增语言缺 key 会编译报错)。 */
|
|
54
56
|
export type Translation = {
|
package/dist/i18n.js
CHANGED
|
@@ -53,6 +53,8 @@ const ZH_T = {
|
|
|
53
53
|
"cancel.status_error": "无法查询会话状态",
|
|
54
54
|
"cancel.sent": "已发送取消指令",
|
|
55
55
|
"cancel.failed": "取消失败",
|
|
56
|
+
"borderShown": "面板边框 已显示",
|
|
57
|
+
"borderHidden": "面板边框 已隐藏",
|
|
56
58
|
};
|
|
57
59
|
const EN_T = {
|
|
58
60
|
"panel.title": "SubAgent",
|
|
@@ -104,6 +106,8 @@ const EN_T = {
|
|
|
104
106
|
"cancel.status_error": "Cannot query session status",
|
|
105
107
|
"cancel.sent": "Cancel instruction sent",
|
|
106
108
|
"cancel.failed": "Cancellation failed",
|
|
109
|
+
"borderShown": "Panel border shown",
|
|
110
|
+
"borderHidden": "Panel border hidden",
|
|
107
111
|
};
|
|
108
112
|
const JA_T = {
|
|
109
113
|
"panel.title": "サブエージェント",
|
|
@@ -155,6 +159,8 @@ const JA_T = {
|
|
|
155
159
|
"cancel.status_error": "セッション状態を照会できません",
|
|
156
160
|
"cancel.sent": "キャンセル指示を送信しました",
|
|
157
161
|
"cancel.failed": "キャンセルに失敗しました",
|
|
162
|
+
"borderShown": "パネル枠線 表示",
|
|
163
|
+
"borderHidden": "パネル枠線 非表示",
|
|
158
164
|
};
|
|
159
165
|
const KO_T = {
|
|
160
166
|
"panel.title": "서브 에이전트",
|
|
@@ -206,6 +212,8 @@ const KO_T = {
|
|
|
206
212
|
"cancel.status_error": "세션 상태를 조회할 수 없습니다",
|
|
207
213
|
"cancel.sent": "취소 지시를 보냈습니다",
|
|
208
214
|
"cancel.failed": "취소에 실패했습니다",
|
|
215
|
+
"borderShown": "패널 테두리 표시",
|
|
216
|
+
"borderHidden": "패널 테두리 숨김",
|
|
209
217
|
};
|
|
210
218
|
export const LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
|
|
211
219
|
/** 语言元数据:/subagent-lang 选项与自动检测共用。 */
|
package/dist/index.js
CHANGED
|
@@ -369,8 +369,9 @@ function SubAgentPanel(props) {
|
|
|
369
369
|
const [renderTick, setRenderTick] = createSignal(0);
|
|
370
370
|
let boxEl;
|
|
371
371
|
let disposed = false;
|
|
372
|
-
/** Total
|
|
373
|
-
* Matches opencode
|
|
372
|
+
/** Total usage tokens for a sub-agent session.
|
|
373
|
+
* Matches opencode's bottom status bar usage: last assistant message with
|
|
374
|
+
* output > 0, summing input + output + reasoning + cache read/write. */
|
|
374
375
|
const readSessionTokens = (sid) => {
|
|
375
376
|
if (!sid)
|
|
376
377
|
return undefined;
|
|
@@ -382,10 +383,13 @@ function SubAgentPanel(props) {
|
|
|
382
383
|
if (m.role !== "assistant")
|
|
383
384
|
continue;
|
|
384
385
|
const t = m.tokens;
|
|
385
|
-
if (!t)
|
|
386
|
+
if (!t || !(Number(t.output) > 0))
|
|
386
387
|
continue;
|
|
387
|
-
const
|
|
388
|
-
|
|
388
|
+
const ctx = (Number(t.input) || 0) +
|
|
389
|
+
(Number(t.output) || 0) +
|
|
390
|
+
(Number(t.reasoning) || 0) +
|
|
391
|
+
(Number(t.cache?.read) || 0) +
|
|
392
|
+
(Number(t.cache?.write) || 0);
|
|
389
393
|
if (ctx > 0)
|
|
390
394
|
return ctx;
|
|
391
395
|
}
|
|
@@ -1248,7 +1252,19 @@ function SubAgentPanel(props) {
|
|
|
1248
1252
|
return next;
|
|
1249
1253
|
});
|
|
1250
1254
|
};
|
|
1251
|
-
|
|
1255
|
+
/** Horizontal space eaten by the panel border (1+1) and its padding (2+2). */
|
|
1256
|
+
const gutter = createMemo(() => (props.borderVisible() ? 6 : 0));
|
|
1257
|
+
const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - gutter()));
|
|
1258
|
+
// The border toggling shifts the box dimensions, which may not reliably
|
|
1259
|
+
// re-fire onSizeChange across (re)mount cycles; re-sync panelWidth with the
|
|
1260
|
+
// live box so the content width stays correct.
|
|
1261
|
+
createEffect(() => {
|
|
1262
|
+
props.borderVisible();
|
|
1263
|
+
if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
|
|
1264
|
+
const w = Math.max(20, boxEl.width);
|
|
1265
|
+
setPanelWidth((prev) => (prev === w ? prev : w));
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1252
1268
|
// ── expanded detail right-align ──
|
|
1253
1269
|
const expandedMaxLabelW = createMemo(() => {
|
|
1254
1270
|
const labels = [
|
|
@@ -1258,7 +1274,7 @@ function SubAgentPanel(props) {
|
|
|
1258
1274
|
return Math.max(...labels.map(l => visualWidth(l + ": ")));
|
|
1259
1275
|
});
|
|
1260
1276
|
const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
|
|
1261
|
-
const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
|
|
1277
|
+
const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
|
|
1262
1278
|
// ── header parts for colored spans ──
|
|
1263
1279
|
const summaryParts = createMemo(() => {
|
|
1264
1280
|
if (!anyEntry())
|
|
@@ -1293,7 +1309,7 @@ function SubAgentPanel(props) {
|
|
|
1293
1309
|
return false;
|
|
1294
1310
|
const icon = "\u25bc";
|
|
1295
1311
|
const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
|
|
1296
|
-
return need <= panelWidth();
|
|
1312
|
+
return need <= panelWidth() - gutter();
|
|
1297
1313
|
});
|
|
1298
1314
|
const leftCols = createMemo(() => {
|
|
1299
1315
|
const icon = open() ? "\u25bc" : "\u25b6";
|
|
@@ -1305,11 +1321,11 @@ function SubAgentPanel(props) {
|
|
|
1305
1321
|
const spacerCols = createMemo(() => {
|
|
1306
1322
|
if (!anyEntry())
|
|
1307
1323
|
return 0;
|
|
1308
|
-
return Math.max(0, panelWidth() - leftCols() - summaryCols());
|
|
1324
|
+
return Math.max(0, panelWidth() - gutter() - leftCols() - summaryCols());
|
|
1309
1325
|
});
|
|
1310
|
-
const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
|
|
1326
|
+
const valueCols = (label) => Math.max(4, panelWidth() - gutter() - INDENT - visualWidth(label + ": "));
|
|
1311
1327
|
// ── render ──
|
|
1312
|
-
return (_jsxs("box", { border:
|
|
1328
|
+
return (_jsxs("box", { border: props.borderVisible(), ...(props.borderVisible() ? { borderColor: pal().border } : {}), paddingTop: 0, paddingBottom: 0, paddingLeft: props.borderVisible() ? 2 : 0, paddingRight: props.borderVisible() ? 2 : 0, flexDirection: "column", gap: 0, ref: boxEl, onSizeChange: () => {
|
|
1313
1329
|
const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
|
|
1314
1330
|
setPanelWidth((prev) => (prev === w ? prev : w));
|
|
1315
1331
|
}, children: [_jsxs("text", { onMouseUp: () => {
|
|
@@ -1401,7 +1417,7 @@ function SubAgentPanel(props) {
|
|
|
1401
1417
|
w += visualWidth(tk);
|
|
1402
1418
|
return w;
|
|
1403
1419
|
};
|
|
1404
|
-
const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
|
|
1420
|
+
const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW());
|
|
1405
1421
|
const labelText = () => {
|
|
1406
1422
|
const max = labelAvail();
|
|
1407
1423
|
const text = entry.title || entry.agent;
|
|
@@ -1439,7 +1455,7 @@ function SubAgentPanel(props) {
|
|
|
1439
1455
|
const cancelLabel = () => ` ${t("cancel.label")}`;
|
|
1440
1456
|
const dismissLabel = () => ` ${t("dismiss.label")}`;
|
|
1441
1457
|
const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
|
|
1442
|
-
const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
|
|
1458
|
+
const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2);
|
|
1443
1459
|
return (_jsxs("box", { flexDirection: "row", children: [_jsx(Show, { when: entry.sessionId, children: _jsxs("text", { onMouseOver: () => setHoveredOpen(entry.id), onMouseOut: () => setHoveredOpen(undefined), onMouseUp: () => {
|
|
1444
1460
|
if (entry.sessionId) {
|
|
1445
1461
|
props.api.route.navigate("session", { sessionID: entry.sessionId });
|
|
@@ -1457,7 +1473,7 @@ function SubAgentPanel(props) {
|
|
|
1457
1473
|
const right = props.sortOrder() === "desc"
|
|
1458
1474
|
? `\u2191 ${t("scroll.top")}`
|
|
1459
1475
|
: `\u2193 ${t("scroll.bottom")}`;
|
|
1460
|
-
const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
|
|
1476
|
+
const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0;
|
|
1461
1477
|
return (_jsxs("box", { flexDirection: "row", children: [_jsx("text", { onMouseOver: () => showMore && setHoveredMoreBelow(true), onMouseOut: () => setHoveredMoreBelow(false), onMouseUp: () => {
|
|
1462
1478
|
if (!showMore)
|
|
1463
1479
|
return;
|
|
@@ -1490,7 +1506,7 @@ function createSidebarSlot(api, sig) {
|
|
|
1490
1506
|
slots: {
|
|
1491
1507
|
sidebar_content(ctx, input) {
|
|
1492
1508
|
sig.sessionId = input.session_id;
|
|
1493
|
-
return (_jsx(SubAgentPanel, { theme: ctx.theme.current, api: api, lang: sig.lang, maxEntries: sig.maxEntries, sortOrder: sig.sortOrder, scrollMode: sig.scrollMode, sessionId: input.session_id }));
|
|
1509
|
+
return (_jsx(SubAgentPanel, { theme: ctx.theme.current, api: api, lang: sig.lang, maxEntries: sig.maxEntries, sortOrder: sig.sortOrder, scrollMode: sig.scrollMode, borderVisible: sig.borderVisible, sessionId: input.session_id }));
|
|
1494
1510
|
},
|
|
1495
1511
|
},
|
|
1496
1512
|
};
|
|
@@ -1504,7 +1520,8 @@ const tui = async (api) => {
|
|
|
1504
1520
|
const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
|
|
1505
1521
|
const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
|
|
1506
1522
|
const [scrollMode, setScrollMode] = createSignal(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
|
|
1507
|
-
const
|
|
1523
|
+
const [borderVisible, setBorderVisible] = createSignal(api.kv.get(`${KV_PREFIX}.border`, false) === true);
|
|
1524
|
+
const signals = { lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, borderVisible, setBorderVisible, sessionId: "" };
|
|
1508
1525
|
api.slots.register(createSidebarSlot(api, signals));
|
|
1509
1526
|
// ── slash command: /subagent-lang ──
|
|
1510
1527
|
api.command?.register(() => [
|
|
@@ -1748,6 +1765,20 @@ const tui = async (api) => {
|
|
|
1748
1765
|
} })));
|
|
1749
1766
|
},
|
|
1750
1767
|
},
|
|
1768
|
+
{
|
|
1769
|
+
title: "SubAgent Magazine: Border",
|
|
1770
|
+
value: "subagent-border",
|
|
1771
|
+
description: "Show or hide the panel border",
|
|
1772
|
+
slash: { name: "subagent-border" },
|
|
1773
|
+
onSelect: (dialog) => {
|
|
1774
|
+
const t = createT(() => signals.lang());
|
|
1775
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, false));
|
|
1776
|
+
api.kv.set(`${KV_PREFIX}.border`, !cur);
|
|
1777
|
+
signals.setBorderVisible(!cur);
|
|
1778
|
+
api.ui.toast({ message: !cur ? t("borderShown") : t("borderHidden") });
|
|
1779
|
+
dialog?.clear();
|
|
1780
|
+
},
|
|
1781
|
+
},
|
|
1751
1782
|
]);
|
|
1752
1783
|
};
|
|
1753
1784
|
const mod = {
|
package/dist/tui.js
CHANGED
|
@@ -4,14 +4,16 @@ import { insertNode as _$insertNode } from "@opentui/solid";
|
|
|
4
4
|
import { createComponent as _$createComponent } from "@opentui/solid";
|
|
5
5
|
import { effect as _$effect } from "@opentui/solid";
|
|
6
6
|
import { insert as _$insert } from "@opentui/solid";
|
|
7
|
-
import { memo as _$memo } from "@opentui/solid";
|
|
8
|
-
import { use as _$use } from "@opentui/solid";
|
|
9
7
|
import { setProp as _$setProp } from "@opentui/solid";
|
|
8
|
+
import { use as _$use } from "@opentui/solid";
|
|
9
|
+
import { spread as _$spread } from "@opentui/solid";
|
|
10
|
+
import { mergeProps as _$mergeProps } from "@opentui/solid";
|
|
11
|
+
import { memo as _$memo } from "@opentui/solid";
|
|
10
12
|
import { createElement as _$createElement } from "@opentui/solid";
|
|
11
13
|
import { createMemo, createSignal, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
|
|
12
14
|
|
|
13
15
|
// src/_version.ts
|
|
14
|
-
var PLUGIN_VERSION = "1.5.
|
|
16
|
+
var PLUGIN_VERSION = "1.5.3";
|
|
15
17
|
|
|
16
18
|
// src/clipboard.ts
|
|
17
19
|
import { spawn } from "node:child_process";
|
|
@@ -159,7 +161,9 @@ var ZH_T = {
|
|
|
159
161
|
"cancel.already_ended": "\u4F1A\u8BDD\u5DF2\u7ED3\u675F\uFF0C\u65E0\u9700\u53D6\u6D88",
|
|
160
162
|
"cancel.status_error": "\u65E0\u6CD5\u67E5\u8BE2\u4F1A\u8BDD\u72B6\u6001",
|
|
161
163
|
"cancel.sent": "\u5DF2\u53D1\u9001\u53D6\u6D88\u6307\u4EE4",
|
|
162
|
-
"cancel.failed": "\u53D6\u6D88\u5931\u8D25"
|
|
164
|
+
"cancel.failed": "\u53D6\u6D88\u5931\u8D25",
|
|
165
|
+
"borderShown": "\u9762\u677F\u8FB9\u6846 \u5DF2\u663E\u793A",
|
|
166
|
+
"borderHidden": "\u9762\u677F\u8FB9\u6846 \u5DF2\u9690\u85CF"
|
|
163
167
|
};
|
|
164
168
|
var EN_T = {
|
|
165
169
|
"panel.title": "SubAgent",
|
|
@@ -210,7 +214,9 @@ var EN_T = {
|
|
|
210
214
|
"cancel.already_ended": "Session already ended, no need to cancel",
|
|
211
215
|
"cancel.status_error": "Cannot query session status",
|
|
212
216
|
"cancel.sent": "Cancel instruction sent",
|
|
213
|
-
"cancel.failed": "Cancellation failed"
|
|
217
|
+
"cancel.failed": "Cancellation failed",
|
|
218
|
+
"borderShown": "Panel border shown",
|
|
219
|
+
"borderHidden": "Panel border hidden"
|
|
214
220
|
};
|
|
215
221
|
var JA_T = {
|
|
216
222
|
"panel.title": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
|
|
@@ -261,7 +267,9 @@ var JA_T = {
|
|
|
261
267
|
"cancel.already_ended": "\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059",
|
|
262
268
|
"cancel.status_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u72B6\u614B\u3092\u7167\u4F1A\u3067\u304D\u307E\u305B\u3093",
|
|
263
269
|
"cancel.sent": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6307\u793A\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F",
|
|
264
|
-
"cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
270
|
+
"cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
271
|
+
"borderShown": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u8868\u793A",
|
|
272
|
+
"borderHidden": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u975E\u8868\u793A"
|
|
265
273
|
};
|
|
266
274
|
var KO_T = {
|
|
267
275
|
"panel.title": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8",
|
|
@@ -312,7 +320,9 @@ var KO_T = {
|
|
|
312
320
|
"cancel.already_ended": "\uC138\uC158\uC774 \uC774\uBBF8 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
|
|
313
321
|
"cancel.status_error": "\uC138\uC158 \uC0C1\uD0DC\uB97C \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
314
322
|
"cancel.sent": "\uCDE8\uC18C \uC9C0\uC2DC\uB97C \uBCF4\uB0C8\uC2B5\uB2C8\uB2E4",
|
|
315
|
-
"cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4"
|
|
323
|
+
"cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
|
|
324
|
+
"borderShown": "\uD328\uB110 \uD14C\uB450\uB9AC \uD45C\uC2DC",
|
|
325
|
+
"borderHidden": "\uD328\uB110 \uD14C\uB450\uB9AC \uC228\uAE40"
|
|
316
326
|
};
|
|
317
327
|
var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
|
|
318
328
|
var LANG_META = [
|
|
@@ -755,9 +765,8 @@ function SubAgentPanel(props) {
|
|
|
755
765
|
const m = msgs[i];
|
|
756
766
|
if (m.role !== "assistant") continue;
|
|
757
767
|
const t2 = m.tokens;
|
|
758
|
-
if (!t2) continue;
|
|
759
|
-
const
|
|
760
|
-
const ctx = (Number(t2.input) || 0) + (cache?.read ?? 0);
|
|
768
|
+
if (!t2 || !(Number(t2.output) > 0)) continue;
|
|
769
|
+
const ctx = (Number(t2.input) || 0) + (Number(t2.output) || 0) + (Number(t2.reasoning) || 0) + (Number(t2.cache?.read) || 0) + (Number(t2.cache?.write) || 0);
|
|
761
770
|
if (ctx > 0) return ctx;
|
|
762
771
|
}
|
|
763
772
|
}
|
|
@@ -1569,13 +1578,21 @@ function SubAgentPanel(props) {
|
|
|
1569
1578
|
return next;
|
|
1570
1579
|
});
|
|
1571
1580
|
};
|
|
1572
|
-
const
|
|
1581
|
+
const gutter = createMemo(() => props.borderVisible() ? 6 : 0);
|
|
1582
|
+
const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - gutter()));
|
|
1583
|
+
createEffect(() => {
|
|
1584
|
+
props.borderVisible();
|
|
1585
|
+
if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
|
|
1586
|
+
const w = Math.max(20, boxEl.width);
|
|
1587
|
+
setPanelWidth((prev) => prev === w ? prev : w);
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1573
1590
|
const expandedMaxLabelW = createMemo(() => {
|
|
1574
1591
|
const labels = [t("agent.label"), t("status.label"), t("time.label"), t("tokens.label"), t("error.label"), t("cost.label"), t("model.label"), t("todo.label"), t("session.label")];
|
|
1575
1592
|
return Math.max(...labels.map((l) => visualWidth(l + ": ")));
|
|
1576
1593
|
});
|
|
1577
1594
|
const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
|
|
1578
|
-
const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
|
|
1595
|
+
const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
|
|
1579
1596
|
const summaryParts = createMemo(() => {
|
|
1580
1597
|
if (!anyEntry()) return null;
|
|
1581
1598
|
const dot = "\u25CF";
|
|
@@ -1604,7 +1621,7 @@ function SubAgentPanel(props) {
|
|
|
1604
1621
|
if (!open()) return false;
|
|
1605
1622
|
const icon = "\u25BC";
|
|
1606
1623
|
const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
|
|
1607
|
-
return need <= panelWidth();
|
|
1624
|
+
return need <= panelWidth() - gutter();
|
|
1608
1625
|
});
|
|
1609
1626
|
const leftCols = createMemo(() => {
|
|
1610
1627
|
const icon = open() ? "\u25BC" : "\u25B6";
|
|
@@ -1614,25 +1631,36 @@ function SubAgentPanel(props) {
|
|
|
1614
1631
|
});
|
|
1615
1632
|
const spacerCols = createMemo(() => {
|
|
1616
1633
|
if (!anyEntry()) return 0;
|
|
1617
|
-
return Math.max(0, panelWidth() - leftCols() - summaryCols());
|
|
1634
|
+
return Math.max(0, panelWidth() - gutter() - leftCols() - summaryCols());
|
|
1618
1635
|
});
|
|
1619
|
-
const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
|
|
1636
|
+
const valueCols = (label) => Math.max(4, panelWidth() - gutter() - INDENT - visualWidth(label + ": "));
|
|
1620
1637
|
return (() => {
|
|
1621
1638
|
var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span");
|
|
1622
1639
|
_$insertNode(_el$, _el$2);
|
|
1623
1640
|
var _ref$ = boxEl;
|
|
1624
1641
|
typeof _ref$ === "function" ? _$use(_ref$, _el$) : boxEl = _el$;
|
|
1625
|
-
_$
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1642
|
+
_$spread(_el$, _$mergeProps({
|
|
1643
|
+
get border() {
|
|
1644
|
+
return props.borderVisible();
|
|
1645
|
+
}
|
|
1646
|
+
}, () => props.borderVisible() ? {
|
|
1647
|
+
borderColor: pal().border
|
|
1648
|
+
} : {}, {
|
|
1649
|
+
"paddingTop": 0,
|
|
1650
|
+
"paddingBottom": 0,
|
|
1651
|
+
get paddingLeft() {
|
|
1652
|
+
return props.borderVisible() ? 2 : 0;
|
|
1653
|
+
},
|
|
1654
|
+
get paddingRight() {
|
|
1655
|
+
return props.borderVisible() ? 2 : 0;
|
|
1656
|
+
},
|
|
1657
|
+
"flexDirection": "column",
|
|
1658
|
+
"gap": 0,
|
|
1659
|
+
"onSizeChange": () => {
|
|
1660
|
+
const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
|
|
1661
|
+
setPanelWidth((prev) => prev === w ? prev : w);
|
|
1662
|
+
}
|
|
1663
|
+
}), true);
|
|
1636
1664
|
_$insertNode(_el$2, _el$3);
|
|
1637
1665
|
_$insertNode(_el$2, _el$4);
|
|
1638
1666
|
_$setProp(_el$2, "onMouseUp", () => {
|
|
@@ -1829,7 +1857,7 @@ function SubAgentPanel(props) {
|
|
|
1829
1857
|
if (tk) w += visualWidth(tk);
|
|
1830
1858
|
return w;
|
|
1831
1859
|
};
|
|
1832
|
-
const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
|
|
1860
|
+
const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW());
|
|
1833
1861
|
const labelText = () => {
|
|
1834
1862
|
const max2 = labelAvail();
|
|
1835
1863
|
const text = entry.title || entry.agent;
|
|
@@ -2228,7 +2256,7 @@ ${t("session.toast.copy_failed")}`,
|
|
|
2228
2256
|
const cancelLabel = () => ` ${t("cancel.label")}`;
|
|
2229
2257
|
const dismissLabel = () => ` ${t("dismiss.label")}`;
|
|
2230
2258
|
const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
|
|
2231
|
-
const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
|
|
2259
|
+
const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2);
|
|
2232
2260
|
return (() => {
|
|
2233
2261
|
var _el$91 = _$createElement("box"), _el$95 = _$createElement("text");
|
|
2234
2262
|
_$insertNode(_el$91, _el$95);
|
|
@@ -2331,7 +2359,7 @@ ${t("session.toast.copy_failed")}`,
|
|
|
2331
2359
|
const showTop = props.sortOrder() === "desc" ? scrollOffset() > 0 : entryList().length > max() && clampedOffset() < entryList().length - max();
|
|
2332
2360
|
const left = showMore ? ` \u2193 ${hiddenBelow()} ${t("scroll.more")}` : " ";
|
|
2333
2361
|
const right = props.sortOrder() === "desc" ? `\u2191 ${t("scroll.top")}` : `\u2193 ${t("scroll.bottom")}`;
|
|
2334
|
-
const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
|
|
2362
|
+
const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0;
|
|
2335
2363
|
return (() => {
|
|
2336
2364
|
var _el$100 = _$createElement("box"), _el$101 = _$createElement("text"), _el$102 = _$createElement("span");
|
|
2337
2365
|
_$insertNode(_el$100, _el$101);
|
|
@@ -2432,6 +2460,9 @@ function createSidebarSlot(api, sig) {
|
|
|
2432
2460
|
get scrollMode() {
|
|
2433
2461
|
return sig.scrollMode;
|
|
2434
2462
|
},
|
|
2463
|
+
get borderVisible() {
|
|
2464
|
+
return sig.borderVisible;
|
|
2465
|
+
},
|
|
2435
2466
|
get sessionId() {
|
|
2436
2467
|
return input.session_id;
|
|
2437
2468
|
}
|
|
@@ -2448,6 +2479,7 @@ var tui = async (api) => {
|
|
|
2448
2479
|
const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
|
|
2449
2480
|
const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
|
|
2450
2481
|
const [scrollMode, setScrollMode] = createSignal(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
|
|
2482
|
+
const [borderVisible, setBorderVisible] = createSignal(api.kv.get(`${KV_PREFIX}.border`, false) === true);
|
|
2451
2483
|
const signals = {
|
|
2452
2484
|
lang,
|
|
2453
2485
|
setLang,
|
|
@@ -2457,6 +2489,8 @@ var tui = async (api) => {
|
|
|
2457
2489
|
setSortOrder,
|
|
2458
2490
|
scrollMode,
|
|
2459
2491
|
setScrollMode,
|
|
2492
|
+
borderVisible,
|
|
2493
|
+
setBorderVisible,
|
|
2460
2494
|
sessionId: ""
|
|
2461
2495
|
};
|
|
2462
2496
|
api.slots.register(createSidebarSlot(api, signals));
|
|
@@ -2790,6 +2824,23 @@ var tui = async (api) => {
|
|
|
2790
2824
|
}
|
|
2791
2825
|
}));
|
|
2792
2826
|
}
|
|
2827
|
+
}, {
|
|
2828
|
+
title: "SubAgent Magazine: Border",
|
|
2829
|
+
value: "subagent-border",
|
|
2830
|
+
description: "Show or hide the panel border",
|
|
2831
|
+
slash: {
|
|
2832
|
+
name: "subagent-border"
|
|
2833
|
+
},
|
|
2834
|
+
onSelect: (dialog) => {
|
|
2835
|
+
const t = createT(() => signals.lang());
|
|
2836
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, false));
|
|
2837
|
+
api.kv.set(`${KV_PREFIX}.border`, !cur);
|
|
2838
|
+
signals.setBorderVisible(!cur);
|
|
2839
|
+
api.ui.toast({
|
|
2840
|
+
message: !cur ? t("borderShown") : t("borderHidden")
|
|
2841
|
+
});
|
|
2842
|
+
dialog?.clear();
|
|
2843
|
+
}
|
|
2793
2844
|
}]);
|
|
2794
2845
|
};
|
|
2795
2846
|
var mod = {
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// auto-generated
|
|
2
|
-
export const PLUGIN_VERSION="1.5.
|
|
2
|
+
export const PLUGIN_VERSION="1.5.3";
|
package/src/i18n.ts
CHANGED
|
@@ -56,6 +56,8 @@ const ZH_T = {
|
|
|
56
56
|
"cancel.status_error": "无法查询会话状态",
|
|
57
57
|
"cancel.sent": "已发送取消指令",
|
|
58
58
|
"cancel.failed": "取消失败",
|
|
59
|
+
"borderShown": "面板边框 已显示",
|
|
60
|
+
"borderHidden": "面板边框 已隐藏",
|
|
59
61
|
} as const
|
|
60
62
|
|
|
61
63
|
/** 结构约束:值放宽为 string,键集合来自中文表(新增语言缺 key 会编译报错)。 */
|
|
@@ -111,6 +113,8 @@ const EN_T: Translation = {
|
|
|
111
113
|
"cancel.status_error": "Cannot query session status",
|
|
112
114
|
"cancel.sent": "Cancel instruction sent",
|
|
113
115
|
"cancel.failed": "Cancellation failed",
|
|
116
|
+
"borderShown": "Panel border shown",
|
|
117
|
+
"borderHidden": "Panel border hidden",
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
const JA_T: Translation = {
|
|
@@ -163,6 +167,8 @@ const JA_T: Translation = {
|
|
|
163
167
|
"cancel.status_error": "セッション状態を照会できません",
|
|
164
168
|
"cancel.sent": "キャンセル指示を送信しました",
|
|
165
169
|
"cancel.failed": "キャンセルに失敗しました",
|
|
170
|
+
"borderShown": "パネル枠線 表示",
|
|
171
|
+
"borderHidden": "パネル枠線 非表示",
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
const KO_T: Translation = {
|
|
@@ -215,6 +221,8 @@ const KO_T: Translation = {
|
|
|
215
221
|
"cancel.status_error": "세션 상태를 조회할 수 없습니다",
|
|
216
222
|
"cancel.sent": "취소 지시를 보냈습니다",
|
|
217
223
|
"cancel.failed": "취소에 실패했습니다",
|
|
224
|
+
"borderShown": "패널 테두리 표시",
|
|
225
|
+
"borderHidden": "패널 테두리 숨김",
|
|
218
226
|
}
|
|
219
227
|
|
|
220
228
|
export const LANGS: Record<LangCode, Translation> = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T }
|
package/src/index.tsx
CHANGED
|
@@ -214,6 +214,7 @@ function SubAgentPanel(props: {
|
|
|
214
214
|
maxEntries: () => number
|
|
215
215
|
sortOrder: () => SortOrder
|
|
216
216
|
scrollMode: () => ScrollMode
|
|
217
|
+
borderVisible: () => boolean
|
|
217
218
|
sessionId: string
|
|
218
219
|
}): JSX.Element {
|
|
219
220
|
const t = createT(() => props.lang())
|
|
@@ -428,8 +429,9 @@ function SubAgentPanel(props: {
|
|
|
428
429
|
let boxEl: any
|
|
429
430
|
let disposed = false
|
|
430
431
|
|
|
431
|
-
/** Total
|
|
432
|
-
* Matches opencode
|
|
432
|
+
/** Total usage tokens for a sub-agent session.
|
|
433
|
+
* Matches opencode's bottom status bar usage: last assistant message with
|
|
434
|
+
* output > 0, summing input + output + reasoning + cache read/write. */
|
|
433
435
|
const readSessionTokens = (sid: string): number | undefined => {
|
|
434
436
|
if (!sid) return undefined
|
|
435
437
|
try {
|
|
@@ -439,9 +441,13 @@ function SubAgentPanel(props: {
|
|
|
439
441
|
const m = (msgs as any[])[i]
|
|
440
442
|
if (m.role !== "assistant") continue
|
|
441
443
|
const t = m.tokens
|
|
442
|
-
if (!t) continue
|
|
443
|
-
const
|
|
444
|
-
|
|
444
|
+
if (!t || !(Number(t.output) > 0)) continue
|
|
445
|
+
const ctx =
|
|
446
|
+
(Number(t.input) || 0) +
|
|
447
|
+
(Number(t.output) || 0) +
|
|
448
|
+
(Number(t.reasoning) || 0) +
|
|
449
|
+
(Number(t.cache?.read) || 0) +
|
|
450
|
+
(Number(t.cache?.write) || 0)
|
|
445
451
|
if (ctx > 0) return ctx
|
|
446
452
|
}
|
|
447
453
|
}
|
|
@@ -1276,7 +1282,21 @@ function SubAgentPanel(props: {
|
|
|
1276
1282
|
})
|
|
1277
1283
|
}
|
|
1278
1284
|
|
|
1279
|
-
|
|
1285
|
+
/** Horizontal space eaten by the panel border (1+1) and its padding (2+2). */
|
|
1286
|
+
const gutter = createMemo(() => (props.borderVisible() ? 6 : 0))
|
|
1287
|
+
|
|
1288
|
+
const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - gutter()))
|
|
1289
|
+
|
|
1290
|
+
// The border toggling shifts the box dimensions, which may not reliably
|
|
1291
|
+
// re-fire onSizeChange across (re)mount cycles; re-sync panelWidth with the
|
|
1292
|
+
// live box so the content width stays correct.
|
|
1293
|
+
createEffect(() => {
|
|
1294
|
+
props.borderVisible()
|
|
1295
|
+
if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
|
|
1296
|
+
const w = Math.max(20, boxEl.width)
|
|
1297
|
+
setPanelWidth((prev) => (prev === w ? prev : w))
|
|
1298
|
+
}
|
|
1299
|
+
})
|
|
1280
1300
|
|
|
1281
1301
|
// ── expanded detail right-align ──
|
|
1282
1302
|
const expandedMaxLabelW = createMemo(() => {
|
|
@@ -1289,7 +1309,7 @@ function SubAgentPanel(props: {
|
|
|
1289
1309
|
|
|
1290
1310
|
const expandedPad = (label: string) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "))
|
|
1291
1311
|
|
|
1292
|
-
const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW())
|
|
1312
|
+
const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW())
|
|
1293
1313
|
|
|
1294
1314
|
// ── header parts for colored spans ──
|
|
1295
1315
|
const summaryParts = createMemo(() => {
|
|
@@ -1323,7 +1343,7 @@ function SubAgentPanel(props: {
|
|
|
1323
1343
|
if (!open()) return false
|
|
1324
1344
|
const icon = "\u25bc"
|
|
1325
1345
|
const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols()
|
|
1326
|
-
return need <= panelWidth()
|
|
1346
|
+
return need <= panelWidth() - gutter()
|
|
1327
1347
|
})
|
|
1328
1348
|
|
|
1329
1349
|
const leftCols = createMemo(() => {
|
|
@@ -1335,17 +1355,19 @@ function SubAgentPanel(props: {
|
|
|
1335
1355
|
|
|
1336
1356
|
const spacerCols = createMemo(() => {
|
|
1337
1357
|
if (!anyEntry()) return 0
|
|
1338
|
-
return Math.max(0, panelWidth() - leftCols() - summaryCols())
|
|
1358
|
+
return Math.max(0, panelWidth() - gutter() - leftCols() - summaryCols())
|
|
1339
1359
|
})
|
|
1340
1360
|
|
|
1341
1361
|
const valueCols = (label: string) =>
|
|
1342
|
-
Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "))
|
|
1362
|
+
Math.max(4, panelWidth() - gutter() - INDENT - visualWidth(label + ": "))
|
|
1343
1363
|
|
|
1344
1364
|
// ── render ──
|
|
1345
1365
|
return (
|
|
1346
1366
|
<box
|
|
1347
|
-
border={
|
|
1348
|
-
|
|
1367
|
+
border={props.borderVisible()}
|
|
1368
|
+
{...(props.borderVisible() ? { borderColor: pal().border } : {})}
|
|
1369
|
+
paddingTop={0} paddingBottom={0}
|
|
1370
|
+
paddingLeft={props.borderVisible() ? 2 : 0} paddingRight={props.borderVisible() ? 2 : 0}
|
|
1349
1371
|
flexDirection="column" gap={0}
|
|
1350
1372
|
ref={boxEl}
|
|
1351
1373
|
onSizeChange={() => {
|
|
@@ -1482,7 +1504,7 @@ function SubAgentPanel(props: {
|
|
|
1482
1504
|
if (tk) w += visualWidth(tk)
|
|
1483
1505
|
return w
|
|
1484
1506
|
}
|
|
1485
|
-
const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW())
|
|
1507
|
+
const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW())
|
|
1486
1508
|
const labelText = () => {
|
|
1487
1509
|
const max = labelAvail()
|
|
1488
1510
|
const text = entry.title || entry.agent
|
|
@@ -1626,7 +1648,7 @@ function SubAgentPanel(props: {
|
|
|
1626
1648
|
const cancelLabel = () => ` ${t("cancel.label")}`
|
|
1627
1649
|
const dismissLabel = () => ` ${t("dismiss.label")}`
|
|
1628
1650
|
const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0)
|
|
1629
|
-
const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2)
|
|
1651
|
+
const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2)
|
|
1630
1652
|
return (
|
|
1631
1653
|
<box flexDirection="row">
|
|
1632
1654
|
<Show when={entry.sessionId}>
|
|
@@ -1683,7 +1705,7 @@ function SubAgentPanel(props: {
|
|
|
1683
1705
|
const right = props.sortOrder() === "desc"
|
|
1684
1706
|
? `\u2191 ${t("scroll.top")}`
|
|
1685
1707
|
: `\u2193 ${t("scroll.bottom")}`
|
|
1686
|
-
const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0
|
|
1708
|
+
const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0
|
|
1687
1709
|
return (
|
|
1688
1710
|
<box flexDirection="row">
|
|
1689
1711
|
<text
|
|
@@ -1748,6 +1770,8 @@ interface SharedSignals {
|
|
|
1748
1770
|
setSortOrder: (o: SortOrder) => void
|
|
1749
1771
|
scrollMode: () => ScrollMode
|
|
1750
1772
|
setScrollMode: (m: ScrollMode) => void
|
|
1773
|
+
borderVisible: () => boolean
|
|
1774
|
+
setBorderVisible: (v: boolean) => void
|
|
1751
1775
|
sessionId: string
|
|
1752
1776
|
}
|
|
1753
1777
|
|
|
@@ -1765,6 +1789,7 @@ function createSidebarSlot(api: TuiPluginApi, sig: SharedSignals): TuiSlotPlugin
|
|
|
1765
1789
|
maxEntries={sig.maxEntries}
|
|
1766
1790
|
sortOrder={sig.sortOrder}
|
|
1767
1791
|
scrollMode={sig.scrollMode}
|
|
1792
|
+
borderVisible={sig.borderVisible}
|
|
1768
1793
|
sessionId={input.session_id}
|
|
1769
1794
|
/>
|
|
1770
1795
|
)
|
|
@@ -1790,8 +1815,11 @@ const tui: TuiPlugin = async (api: TuiPluginApi) => {
|
|
|
1790
1815
|
const [scrollMode, setScrollMode] = createSignal<ScrollMode>(
|
|
1791
1816
|
String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel"
|
|
1792
1817
|
)
|
|
1818
|
+
const [borderVisible, setBorderVisible] = createSignal<boolean>(
|
|
1819
|
+
(api.kv.get(`${KV_PREFIX}.border`, false) as boolean) === true
|
|
1820
|
+
)
|
|
1793
1821
|
|
|
1794
|
-
const signals: SharedSignals = { lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, sessionId: "" }
|
|
1822
|
+
const signals: SharedSignals = { lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, borderVisible, setBorderVisible, sessionId: "" }
|
|
1795
1823
|
|
|
1796
1824
|
api.slots.register(createSidebarSlot(api, signals))
|
|
1797
1825
|
|
|
@@ -2065,6 +2093,20 @@ const tui: TuiPlugin = async (api: TuiPluginApi) => {
|
|
|
2065
2093
|
))
|
|
2066
2094
|
},
|
|
2067
2095
|
},
|
|
2096
|
+
{
|
|
2097
|
+
title: "SubAgent Magazine: Border",
|
|
2098
|
+
value: "subagent-border",
|
|
2099
|
+
description: "Show or hide the panel border",
|
|
2100
|
+
slash: { name: "subagent-border" },
|
|
2101
|
+
onSelect: (dialog) => {
|
|
2102
|
+
const t = createT(() => signals.lang())
|
|
2103
|
+
const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, false))
|
|
2104
|
+
api.kv.set(`${KV_PREFIX}.border`, !cur)
|
|
2105
|
+
signals.setBorderVisible(!cur)
|
|
2106
|
+
api.ui.toast({ message: !cur ? t("borderShown") : t("borderHidden") })
|
|
2107
|
+
dialog?.clear()
|
|
2108
|
+
},
|
|
2109
|
+
},
|
|
2068
2110
|
])
|
|
2069
2111
|
}
|
|
2070
2112
|
|