opencode-subagent-magazine 1.6.0-beta.3 → 1.6.0-beta.4

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 CHANGED
@@ -56,7 +56,8 @@
56
56
  - **TTL 自动清理**:可配置数据保留期限(3/7/14/30 天/无期限),每次访问自动续期,过期自动清除
57
57
  - **手动清除条目**:`/subagent-clear-entries` 清除当前会话所有记录,防止历史条目扫描重建
58
58
  - **语言适配**:支持 `/subagent-lang` 运行时切换中/英文,偏好持久化
59
- - **斜杠命令**:`/subagent-lang` `/subagent-max` `/subagent-order` `/subagent-scroll` `/subagent-ttl` `/subagent-clear-entries` `/subagent-session` `/subagent-version` `/subagent-clear-running` 动态配置
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>
@@ -1 +1 @@
1
- export declare const PLUGIN_VERSION = "1.6.0-beta.3";
1
+ export declare const PLUGIN_VERSION = "1.6.0-beta.4";
package/dist/_version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // auto-generated
2
- export const PLUGIN_VERSION = "1.6.0-beta.3";
2
+ export const PLUGIN_VERSION = "1.6.0-beta.4";
package/dist/core/kv.d.ts CHANGED
@@ -14,6 +14,7 @@ export declare const SETTING_KEYS: {
14
14
  readonly scrollMode: "subagent_magazine.scroll_mode";
15
15
  readonly open: "subagent_magazine.open";
16
16
  readonly ttlDays: "subagent_magazine.ttl_days";
17
+ readonly border: "subagent_magazine.border";
17
18
  };
18
19
  export declare function loadSessionData(kv: KVApi): Record<string, SessionRecord>;
19
20
  export declare function saveSessionData(kv: KVApi, data: Record<string, SessionRecord>): void;
package/dist/core/kv.js CHANGED
@@ -8,6 +8,7 @@ export const SETTING_KEYS = {
8
8
  scrollMode: `${KV_PREFIX}.scroll_mode`,
9
9
  open: `${KV_PREFIX}.open`,
10
10
  ttlDays: `${KV_PREFIX}.ttl_days`,
11
+ border: `${KV_PREFIX}.border`,
11
12
  };
12
13
  export function loadSessionData(kv) {
13
14
  try {
@@ -47,5 +47,7 @@ export interface SharedSignals {
47
47
  setSortOrder: (o: SortOrder) => void;
48
48
  scrollMode: () => ScrollMode;
49
49
  setScrollMode: (m: ScrollMode) => void;
50
+ borderVisible: () => boolean;
51
+ setBorderVisible: (v: boolean) => void;
50
52
  sessionId: string;
51
53
  }
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
@@ -13,7 +13,7 @@ function createSidebarSlot(api, panelApi, sig) {
13
13
  slots: {
14
14
  sidebar_content(ctx, input) {
15
15
  sig.sessionId = input.session_id;
16
- return (_jsx(SubAgentPanel, { api: panelApi, theme: ctx.theme.current, lang: sig.lang, maxEntries: sig.maxEntries, sortOrder: sig.sortOrder, scrollMode: sig.scrollMode, sessionId: input.session_id }));
16
+ return (_jsx(SubAgentPanel, { api: panelApi, theme: ctx.theme.current, lang: sig.lang, maxEntries: sig.maxEntries, sortOrder: sig.sortOrder, scrollMode: sig.scrollMode, borderVisible: sig.borderVisible, sessionId: input.session_id }));
17
17
  },
18
18
  },
19
19
  };
@@ -26,7 +26,8 @@ const tui = async (api) => {
26
26
  const [maxEntries, setMaxEntries] = createSignal(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
27
27
  const [sortOrder, setSortOrder] = createSignal(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
28
28
  const [scrollMode, setScrollMode] = createSignal(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
29
- const signals = { lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, sessionId: "" };
29
+ const [borderVisible, setBorderVisible] = createSignal(api.kv.get(`${KV_PREFIX}.border`, false) === true);
30
+ const signals = { lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, borderVisible, setBorderVisible, sessionId: "" };
30
31
  // ── V1 PanelApi adapter: wraps the V1 host API into the shared panel contract ──
31
32
  const v1Api = {
32
33
  kv: api.kv,
@@ -416,6 +417,20 @@ const tui = async (api) => {
416
417
  } })));
417
418
  },
418
419
  },
420
+ {
421
+ title: "SubAgent Magazine: Border",
422
+ value: "subagent-border",
423
+ description: "Show or hide the panel border",
424
+ slash: { name: "subagent-border" },
425
+ onSelect: (dialog) => {
426
+ const t = createT(() => signals.lang());
427
+ const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, false));
428
+ api.kv.set(`${KV_PREFIX}.border`, !cur);
429
+ signals.setBorderVisible(!cur);
430
+ api.ui.toast({ message: !cur ? t("borderShown") : t("borderHidden") });
431
+ dialog?.clear();
432
+ },
433
+ },
419
434
  ]);
420
435
  };
421
436
  const mod = {
@@ -9,5 +9,6 @@ export declare function SubAgentPanel(props: {
9
9
  maxEntries: () => number;
10
10
  sortOrder: () => SortOrder;
11
11
  scrollMode: () => ScrollMode;
12
+ borderVisible: () => boolean;
12
13
  sessionId: string;
13
14
  }): JSX.Element;
@@ -1017,7 +1017,19 @@ export function SubAgentPanel(props) {
1017
1017
  return next;
1018
1018
  });
1019
1019
  };
1020
- const sep = () => "\u2500".repeat(Math.max(1, panelWidth()));
1020
+ /** Horizontal space eaten by the panel border (1+1) and its padding (2+2). */
1021
+ const gutter = createMemo(() => (props.borderVisible() ? 6 : 0));
1022
+ const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - gutter()));
1023
+ // The border toggling shifts the box dimensions, which may not reliably
1024
+ // re-fire onSizeChange across (re)mount cycles; re-sync panelWidth with the
1025
+ // live box so the content width stays correct.
1026
+ createEffect(() => {
1027
+ props.borderVisible();
1028
+ if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
1029
+ const w = Math.max(20, boxEl.width);
1030
+ setPanelWidth((prev) => (prev === w ? prev : w));
1031
+ }
1032
+ });
1021
1033
  // ── expanded detail right-align ──
1022
1034
  const expandedMaxLabelW = createMemo(() => {
1023
1035
  const labels = [
@@ -1027,7 +1039,7 @@ export function SubAgentPanel(props) {
1027
1039
  return Math.max(...labels.map(l => visualWidth(l + ": ")));
1028
1040
  });
1029
1041
  const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
1030
- const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
1042
+ const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
1031
1043
  // ── header parts for colored spans ──
1032
1044
  const summaryParts = createMemo(() => {
1033
1045
  if (!anyEntry())
@@ -1062,7 +1074,7 @@ export function SubAgentPanel(props) {
1062
1074
  return false;
1063
1075
  const icon = "\u25bc";
1064
1076
  const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
1065
- return need <= panelWidth();
1077
+ return need <= panelWidth() - gutter();
1066
1078
  });
1067
1079
  const leftCols = createMemo(() => {
1068
1080
  const icon = open() ? "\u25bc" : "\u25b6";
@@ -1074,11 +1086,11 @@ export function SubAgentPanel(props) {
1074
1086
  const spacerCols = createMemo(() => {
1075
1087
  if (!anyEntry())
1076
1088
  return 0;
1077
- return Math.max(0, panelWidth() - leftCols() - summaryCols());
1089
+ return Math.max(0, panelWidth() - gutter() - leftCols() - summaryCols());
1078
1090
  });
1079
- const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
1091
+ const valueCols = (label) => Math.max(4, panelWidth() - gutter() - INDENT - visualWidth(label + ": "));
1080
1092
  // ── render ──
1081
- return (_jsxs("box", { border: false, paddingTop: 0, paddingBottom: 0, paddingLeft: 0, paddingRight: 0, flexDirection: "column", gap: 0, ref: boxEl, onSizeChange: () => {
1093
+ 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: () => {
1082
1094
  const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
1083
1095
  setPanelWidth((prev) => (prev === w ? prev : w));
1084
1096
  }, children: [_jsxs("text", { onMouseUp: () => {
@@ -1170,7 +1182,7 @@ export function SubAgentPanel(props) {
1170
1182
  w += visualWidth(tk);
1171
1183
  return w;
1172
1184
  };
1173
- const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
1185
+ const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW());
1174
1186
  const labelText = () => {
1175
1187
  const max = labelAvail();
1176
1188
  const text = entry.title || entry.agent;
@@ -1206,7 +1218,7 @@ export function SubAgentPanel(props) {
1206
1218
  const cancelLabel = () => ` ${t("cancel.label")}`;
1207
1219
  const dismissLabel = () => ` ${t("dismiss.label")}`;
1208
1220
  const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
1209
- const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
1221
+ const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2);
1210
1222
  return (_jsxs("box", { flexDirection: "row", children: [_jsx(Show, { when: entry.sessionId, children: _jsxs("text", { onMouseOver: () => setHoveredOpen(entry.id), onMouseOut: () => setHoveredOpen(undefined), onMouseUp: () => {
1211
1223
  if (entry.sessionId) {
1212
1224
  props.api.route.navigateSession(entry.sessionId);
@@ -1224,7 +1236,7 @@ export function SubAgentPanel(props) {
1224
1236
  const right = props.sortOrder() === "desc"
1225
1237
  ? `\u2191 ${t("scroll.top")}`
1226
1238
  : `\u2193 ${t("scroll.bottom")}`;
1227
- const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
1239
+ const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0;
1228
1240
  return (_jsxs("box", { flexDirection: "row", children: [_jsx("text", { onMouseOver: () => showMore && setHoveredMoreBelow(true), onMouseOut: () => setHoveredMoreBelow(false), onMouseUp: () => {
1229
1241
  if (!showMore)
1230
1242
  return;
package/dist/tui.js CHANGED
@@ -6,7 +6,7 @@ import { createComponent as _$createComponent2 } from "@opentui/solid";
6
6
  import { createSignal as createSignal3 } from "solid-js";
7
7
 
8
8
  // src/_version.ts
9
- var PLUGIN_VERSION = "1.6.0-beta.3";
9
+ var PLUGIN_VERSION = "1.6.0-beta.4";
10
10
 
11
11
  // src/i18n.ts
12
12
  var ZH_T = {
@@ -58,7 +58,9 @@ var ZH_T = {
58
58
  "cancel.already_ended": "\u4F1A\u8BDD\u5DF2\u7ED3\u675F\uFF0C\u65E0\u9700\u53D6\u6D88",
59
59
  "cancel.status_error": "\u65E0\u6CD5\u67E5\u8BE2\u4F1A\u8BDD\u72B6\u6001",
60
60
  "cancel.sent": "\u5DF2\u53D1\u9001\u53D6\u6D88\u6307\u4EE4",
61
- "cancel.failed": "\u53D6\u6D88\u5931\u8D25"
61
+ "cancel.failed": "\u53D6\u6D88\u5931\u8D25",
62
+ "borderShown": "\u9762\u677F\u8FB9\u6846 \u5DF2\u663E\u793A",
63
+ "borderHidden": "\u9762\u677F\u8FB9\u6846 \u5DF2\u9690\u85CF"
62
64
  };
63
65
  var EN_T = {
64
66
  "panel.title": "SubAgent",
@@ -109,7 +111,9 @@ var EN_T = {
109
111
  "cancel.already_ended": "Session already ended, no need to cancel",
110
112
  "cancel.status_error": "Cannot query session status",
111
113
  "cancel.sent": "Cancel instruction sent",
112
- "cancel.failed": "Cancellation failed"
114
+ "cancel.failed": "Cancellation failed",
115
+ "borderShown": "Panel border shown",
116
+ "borderHidden": "Panel border hidden"
113
117
  };
114
118
  var JA_T = {
115
119
  "panel.title": "\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8",
@@ -160,7 +164,9 @@ var JA_T = {
160
164
  "cancel.already_ended": "\u30BB\u30C3\u30B7\u30E7\u30F3\u306F\u65E2\u306B\u7D42\u4E86\u3057\u3066\u3044\u307E\u3059",
161
165
  "cancel.status_error": "\u30BB\u30C3\u30B7\u30E7\u30F3\u72B6\u614B\u3092\u7167\u4F1A\u3067\u304D\u307E\u305B\u3093",
162
166
  "cancel.sent": "\u30AD\u30E3\u30F3\u30BB\u30EB\u6307\u793A\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F",
163
- "cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
167
+ "cancel.failed": "\u30AD\u30E3\u30F3\u30BB\u30EB\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
168
+ "borderShown": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u8868\u793A",
169
+ "borderHidden": "\u30D1\u30CD\u30EB\u67A0\u7DDA \u975E\u8868\u793A"
164
170
  };
165
171
  var KO_T = {
166
172
  "panel.title": "\uC11C\uBE0C \uC5D0\uC774\uC804\uD2B8",
@@ -211,7 +217,9 @@ var KO_T = {
211
217
  "cancel.already_ended": "\uC138\uC158\uC774 \uC774\uBBF8 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4",
212
218
  "cancel.status_error": "\uC138\uC158 \uC0C1\uD0DC\uB97C \uC870\uD68C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4",
213
219
  "cancel.sent": "\uCDE8\uC18C \uC9C0\uC2DC\uB97C \uBCF4\uB0C8\uC2B5\uB2C8\uB2E4",
214
- "cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4"
220
+ "cancel.failed": "\uCDE8\uC18C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4",
221
+ "borderShown": "\uD328\uB110 \uD14C\uB450\uB9AC \uD45C\uC2DC",
222
+ "borderHidden": "\uD328\uB110 \uD14C\uB450\uB9AC \uC228\uAE40"
215
223
  };
216
224
  var LANGS = { zh: ZH_T, en: EN_T, ja: JA_T, ko: KO_T };
217
225
  var LANG_META = [
@@ -251,7 +259,8 @@ var SETTING_KEYS = {
251
259
  order: `${KV_PREFIX}.order`,
252
260
  scrollMode: `${KV_PREFIX}.scroll_mode`,
253
261
  open: `${KV_PREFIX}.open`,
254
- ttlDays: `${KV_PREFIX}.ttl_days`
262
+ ttlDays: `${KV_PREFIX}.ttl_days`,
263
+ border: `${KV_PREFIX}.border`
255
264
  };
256
265
 
257
266
  // src/panel/SubAgentPanel.tsx
@@ -260,9 +269,11 @@ import { insertNode as _$insertNode } from "@opentui/solid";
260
269
  import { createComponent as _$createComponent } from "@opentui/solid";
261
270
  import { effect as _$effect } from "@opentui/solid";
262
271
  import { insert as _$insert } from "@opentui/solid";
263
- import { memo as _$memo } from "@opentui/solid";
264
- import { use as _$use } from "@opentui/solid";
265
272
  import { setProp as _$setProp } from "@opentui/solid";
273
+ import { use as _$use } from "@opentui/solid";
274
+ import { spread as _$spread } from "@opentui/solid";
275
+ import { mergeProps as _$mergeProps } from "@opentui/solid";
276
+ import { memo as _$memo } from "@opentui/solid";
266
277
  import { createElement as _$createElement } from "@opentui/solid";
267
278
  import { createMemo, createSignal as createSignal2, createEffect, onMount, onCleanup, untrack, Show, For } from "solid-js";
268
279
 
@@ -1550,13 +1561,21 @@ function SubAgentPanel(props) {
1550
1561
  return next;
1551
1562
  });
1552
1563
  };
1553
- const sep = () => "\u2500".repeat(Math.max(1, panelWidth()));
1564
+ const gutter = createMemo(() => props.borderVisible() ? 6 : 0);
1565
+ const sep = () => "\u2500".repeat(Math.max(1, panelWidth() - gutter()));
1566
+ createEffect(() => {
1567
+ props.borderVisible();
1568
+ if (boxEl && typeof boxEl.width === "number" && boxEl.width > 0) {
1569
+ const w = Math.max(20, boxEl.width);
1570
+ setPanelWidth((prev) => prev === w ? prev : w);
1571
+ }
1572
+ });
1554
1573
  const expandedMaxLabelW = createMemo(() => {
1555
1574
  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")];
1556
1575
  return Math.max(...labels.map((l) => visualWidth(l + ": ")));
1557
1576
  });
1558
1577
  const expandedPad = (label) => Math.max(0, expandedMaxLabelW() - visualWidth(label + ": "));
1559
- const expandedValAvail = () => Math.max(6, panelWidth() - INDENT - expandedMaxLabelW());
1578
+ const expandedValAvail = () => Math.max(6, panelWidth() - gutter() - INDENT - expandedMaxLabelW());
1560
1579
  const summaryParts = createMemo(() => {
1561
1580
  if (!anyEntry()) return null;
1562
1581
  const dot = "\u25CF";
@@ -1585,7 +1604,7 @@ function SubAgentPanel(props) {
1585
1604
  if (!open()) return false;
1586
1605
  const icon = "\u25BC";
1587
1606
  const need = visualWidth(icon) + 1 + visualWidth(t("panel.title")) + versionW + summaryCols();
1588
- return need <= panelWidth();
1607
+ return need <= panelWidth() - gutter();
1589
1608
  });
1590
1609
  const leftCols = createMemo(() => {
1591
1610
  const icon = open() ? "\u25BC" : "\u25B6";
@@ -1595,25 +1614,36 @@ function SubAgentPanel(props) {
1595
1614
  });
1596
1615
  const spacerCols = createMemo(() => {
1597
1616
  if (!anyEntry()) return 0;
1598
- return Math.max(0, panelWidth() - leftCols() - summaryCols());
1617
+ return Math.max(0, panelWidth() - gutter() - leftCols() - summaryCols());
1599
1618
  });
1600
- const valueCols = (label) => Math.max(4, panelWidth() - INDENT - visualWidth(label + ": "));
1619
+ const valueCols = (label) => Math.max(4, panelWidth() - gutter() - INDENT - visualWidth(label + ": "));
1601
1620
  return (() => {
1602
1621
  var _el$ = _$createElement("box"), _el$2 = _$createElement("text"), _el$3 = _$createElement("span"), _el$4 = _$createElement("span");
1603
1622
  _$insertNode(_el$, _el$2);
1604
1623
  var _ref$ = boxEl;
1605
1624
  typeof _ref$ === "function" ? _$use(_ref$, _el$) : boxEl = _el$;
1606
- _$setProp(_el$, "border", false);
1607
- _$setProp(_el$, "paddingTop", 0);
1608
- _$setProp(_el$, "paddingBottom", 0);
1609
- _$setProp(_el$, "paddingLeft", 0);
1610
- _$setProp(_el$, "paddingRight", 0);
1611
- _$setProp(_el$, "flexDirection", "column");
1612
- _$setProp(_el$, "gap", 0);
1613
- _$setProp(_el$, "onSizeChange", () => {
1614
- const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
1615
- setPanelWidth((prev) => prev === w ? prev : w);
1616
- });
1625
+ _$spread(_el$, _$mergeProps({
1626
+ get border() {
1627
+ return props.borderVisible();
1628
+ }
1629
+ }, () => props.borderVisible() ? {
1630
+ borderColor: pal().border
1631
+ } : {}, {
1632
+ "paddingTop": 0,
1633
+ "paddingBottom": 0,
1634
+ get paddingLeft() {
1635
+ return props.borderVisible() ? 2 : 0;
1636
+ },
1637
+ get paddingRight() {
1638
+ return props.borderVisible() ? 2 : 0;
1639
+ },
1640
+ "flexDirection": "column",
1641
+ "gap": 0,
1642
+ "onSizeChange": () => {
1643
+ const w = boxEl ? Math.max(20, boxEl.width ?? 0) : 28;
1644
+ setPanelWidth((prev) => prev === w ? prev : w);
1645
+ }
1646
+ }), true);
1617
1647
  _$insertNode(_el$2, _el$3);
1618
1648
  _$insertNode(_el$2, _el$4);
1619
1649
  _$setProp(_el$2, "onMouseUp", () => {
@@ -1810,7 +1840,7 @@ function SubAgentPanel(props) {
1810
1840
  if (tk) w += visualWidth(tk);
1811
1841
  return w;
1812
1842
  };
1813
- const labelAvail = () => Math.max(6, panelWidth() - LEFT_PAD - suffixW());
1843
+ const labelAvail = () => Math.max(6, panelWidth() - gutter() - LEFT_PAD - suffixW());
1814
1844
  const labelText = () => {
1815
1845
  const max2 = labelAvail();
1816
1846
  const text = entry.title || entry.agent;
@@ -2207,7 +2237,7 @@ ${t("session.toast.copy_failed")}`, {
2207
2237
  const cancelLabel = () => ` ${t("cancel.label")}`;
2208
2238
  const dismissLabel = () => ` ${t("dismiss.label")}`;
2209
2239
  const rightW = (isRunning ? visualWidth(dismissLabel()) : 0) + (isRunning && entry.sessionId ? visualWidth(cancelLabel()) : 0);
2210
- const spacerW = () => Math.max(1, panelWidth() - openW() - rightW - 2);
2240
+ const spacerW = () => Math.max(1, panelWidth() - gutter() - openW() - rightW - 2);
2211
2241
  return (() => {
2212
2242
  var _el$91 = _$createElement("box"), _el$95 = _$createElement("text");
2213
2243
  _$insertNode(_el$91, _el$95);
@@ -2308,7 +2338,7 @@ ${t("session.toast.copy_failed")}`, {
2308
2338
  const showTop = props.sortOrder() === "desc" ? scrollOffset() > 0 : entryList().length > max() && clampedOffset() < entryList().length - max();
2309
2339
  const left = showMore ? ` \u2193 ${hiddenBelow()} ${t("scroll.more")}` : " ";
2310
2340
  const right = props.sortOrder() === "desc" ? `\u2191 ${t("scroll.top")}` : `\u2193 ${t("scroll.bottom")}`;
2311
- const pad = showTop ? Math.max(1, panelWidth() - visualWidth(left) - visualWidth(right)) : 0;
2341
+ const pad = showTop ? Math.max(1, panelWidth() - gutter() - visualWidth(left) - visualWidth(right)) : 0;
2312
2342
  return (() => {
2313
2343
  var _el$100 = _$createElement("box"), _el$101 = _$createElement("text"), _el$102 = _$createElement("span");
2314
2344
  _$insertNode(_el$100, _el$101);
@@ -2411,6 +2441,9 @@ function createSidebarSlot(api, panelApi, sig) {
2411
2441
  get scrollMode() {
2412
2442
  return sig.scrollMode;
2413
2443
  },
2444
+ get borderVisible() {
2445
+ return sig.borderVisible;
2446
+ },
2414
2447
  get sessionId() {
2415
2448
  return input.session_id;
2416
2449
  }
@@ -2426,6 +2459,7 @@ var tui = async (api) => {
2426
2459
  const [maxEntries, setMaxEntries] = createSignal3(parseInt(String(api.kv.get(`${KV_PREFIX}.max_entries`, "10")), 10) || 10);
2427
2460
  const [sortOrder, setSortOrder] = createSignal3(String(api.kv.get(`${KV_PREFIX}.order`, "desc")) === "asc" ? "asc" : "desc");
2428
2461
  const [scrollMode, setScrollMode] = createSignal3(String(api.kv.get(`${KV_PREFIX}.scroll_mode`, "wheel")) === "click" ? "click" : "wheel");
2462
+ const [borderVisible, setBorderVisible] = createSignal3(api.kv.get(`${KV_PREFIX}.border`, false) === true);
2429
2463
  const signals = {
2430
2464
  lang,
2431
2465
  setLang,
@@ -2435,6 +2469,8 @@ var tui = async (api) => {
2435
2469
  setSortOrder,
2436
2470
  scrollMode,
2437
2471
  setScrollMode,
2472
+ borderVisible,
2473
+ setBorderVisible,
2438
2474
  sessionId: ""
2439
2475
  };
2440
2476
  const v1Api = {
@@ -2918,6 +2954,23 @@ var tui = async (api) => {
2918
2954
  }
2919
2955
  }));
2920
2956
  }
2957
+ }, {
2958
+ title: "SubAgent Magazine: Border",
2959
+ value: "subagent-border",
2960
+ description: "Show or hide the panel border",
2961
+ slash: {
2962
+ name: "subagent-border"
2963
+ },
2964
+ onSelect: (dialog) => {
2965
+ const t = createT(() => signals.lang());
2966
+ const cur = Boolean(api.kv.get(`${KV_PREFIX}.border`, false));
2967
+ api.kv.set(`${KV_PREFIX}.border`, !cur);
2968
+ signals.setBorderVisible(!cur);
2969
+ api.ui.toast({
2970
+ message: !cur ? t("borderShown") : t("borderHidden")
2971
+ });
2972
+ dialog?.clear();
2973
+ }
2921
2974
  }]);
2922
2975
  };
2923
2976
  var mod = {
@@ -258,6 +258,19 @@ export function makeCommands(context, api, signals) {
258
258
  catch { }
259
259
  },
260
260
  },
261
+ {
262
+ id: "opencode-subagent-magazine.subagent.border",
263
+ title: "SubAgent Magazine: Border",
264
+ description: "Show or hide the panel border",
265
+ slash: { name: "subagent-border" },
266
+ palette: true,
267
+ run: () => {
268
+ const cur = Boolean(kv.get(SETTING_KEYS.border, false));
269
+ kv.set(SETTING_KEYS.border, !cur);
270
+ signals.setBorderVisible(!cur);
271
+ api.ui.toast(!cur ? t("borderShown") : t("borderHidden"));
272
+ },
273
+ },
261
274
  ];
262
275
  }
263
276
  export { KV_PREFIX };
package/dist/v2/index.js CHANGED
@@ -14,7 +14,7 @@ function PluginRoot(props) {
14
14
  mode: "global",
15
15
  commands: makeCommands(props.context, props.api, props.signals),
16
16
  }));
17
- return (_jsx(SubAgentPanel, { api: props.api, theme: mapTheme(props.context.theme), lang: props.signals.lang, maxEntries: props.signals.maxEntries, sortOrder: props.signals.sortOrder, scrollMode: props.signals.scrollMode, sessionId: props.sessionID }));
17
+ return (_jsx(SubAgentPanel, { api: props.api, theme: mapTheme(props.context.theme), lang: props.signals.lang, maxEntries: props.signals.maxEntries, sortOrder: props.signals.sortOrder, scrollMode: props.signals.scrollMode, borderVisible: props.signals.borderVisible, sessionId: props.sessionID }));
18
18
  }
19
19
  /** V2 入口:setup 创建共享信号 + PanelApi + 命令 layer + 侧边栏槽位。
20
20
  * 行为对齐 V1 tui()(信号初始值从 KV 恢复;侧边栏渲染共享 SubAgentPanel)。 */
@@ -39,12 +39,13 @@ const mod = {
39
39
  const [maxSignal, setMaxEntries] = createSignal(Number(api.kv.get(SETTING_KEYS.maxEntries, "10")) || 10);
40
40
  const [orderSignal, setSortOrder] = createSignal(String(api.kv.get(SETTING_KEYS.order, "desc")) === "asc" ? "asc" : "desc");
41
41
  const [scrollSignal, setScrollMode] = createSignal(String(api.kv.get(SETTING_KEYS.scrollMode, "wheel")) === "click" ? "click" : "wheel");
42
+ const [borderSignal, setBorderVisible] = createSignal(api.kv.get(SETTING_KEYS.border, false) === true);
42
43
  lang = langSignal;
43
44
  maxEntries = maxSignal;
44
45
  sortOrder = orderSignal;
45
46
  scrollMode = scrollSignal;
46
47
  const signals = {
47
- lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, sessionId: "",
48
+ lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, borderVisible: borderSignal, setBorderVisible, sessionId: "",
48
49
  };
49
50
  // 命令 layer(组件内注册——见 PluginRoot)
50
51
  // 侧边栏面板(共享 SubAgentPanel——V1/V2 同一组件)