@michengai/dsh-btw 0.1.22 → 0.1.24
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/CHANGELOG.md +11 -1
- package/CHANGELOG.zh-CN.md +11 -1
- package/lib/client.js +137 -19
- package/lib/index.js +79 -40
- package/lib/types/client/BubbleView.d.ts +3 -1
- package/lib/types/client/bubbles.d.ts +8 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/locales.d.ts +2 -0
- package/lib/types/server/jobs.d.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## [0.1.24] - 2026-10-15
|
|
4
|
+
|
|
5
|
+
- Side questions are no longer offered in a subagent session. Typing `/btw` there explains that you should return to the main session, instead of leaving a dialog that cannot be closed (#7).
|
|
6
|
+
- Closing a side question that the host rejects because the session is owned by subagent routing no longer deletes an answer that is still on the way or already returned. A request that never started, or was cancelled before it produced an answer, can still be dismissed locally.
|
|
7
|
+
|
|
8
|
+
## [0.1.23] - 2026-10-15
|
|
9
|
+
|
|
10
|
+
- Relax hardcoded timeout: Replace the strict 90s timer with a 30-minute watchdog, supporting long chain-of-thought and max-reasoning models while safeguarding concurrency slots against stalled connections (#6).
|
|
11
|
+
- Prominent stop button during answering: Display a dedicated stop button with alert styling during generation, allowing users to manually abort reasoning and release subagent resources immediately (#6).
|
|
12
|
+
- Smart auto-collapse for older side-question bubbles: Automatically collapse older bubbles when new side questions arrive, keeping the input area neat while preserving manual expansion controls and robust focus recovery.
|
|
13
|
+
- Seamless dual-generation host compatibility: Retain strict typings for DSH 0.2.1-alpha.3+ `startActivation` while providing a robust `subagents.start` fallback for DSH 0.2.0-rc.2 and earlier.
|
|
4
14
|
|
|
5
15
|
## [0.1.22] - 2026-10-15
|
|
6
16
|
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## [0.1.24] - 2026-10-15
|
|
4
|
+
|
|
5
|
+
- 子代理会话不再提供旁问。在那里输入 `/btw` 会提示返回主会话使用,而不是留下关不掉的弹窗 (#7)。
|
|
6
|
+
- 宿主因子代理路由拒绝关闭时,不再删掉还在返回或已经返回的答案。尚未启动,或在产生答案前被取消的请求,仍可在本地关掉。
|
|
7
|
+
|
|
8
|
+
## [0.1.23] - 2026-10-15
|
|
9
|
+
|
|
10
|
+
- 放宽硬超时限制:默认超时由写死的 90s 调整为 30 分钟兜底看门狗,支持长思维链与深度推理模型充分思考;同时保留长连接死锁自动回收机制保护并发槽位 (#6)。
|
|
11
|
+
- 回答中提供醒目的「停止回答」按钮:在旁问处于生成阶段展示独立停止图标与警示色悬浮高亮,用户可随时手动终止推理并释放子代理 (#6)。
|
|
12
|
+
- 优化旁问气泡自动折叠交互:连续提出新旁问时旧气泡自动折叠、最新气泡保持展开,避免撑大输入区;支持用户手动自由切换折叠/展开状态,新气泡到达后稳定重新夺回展开焦点。
|
|
13
|
+
- 完善双代宿主自适应兼容:主路径保留 DSH 0.2.1-alpha.3+ 的强类型 `startActivation`,并为 0.2.0-rc.2 及更早宿主恢复严谨的 `subagents.start` 传统调用回退分支。
|
|
4
14
|
|
|
5
15
|
## [0.1.22] - 2026-10-15
|
|
6
16
|
|
package/lib/client.js
CHANGED
|
@@ -467,6 +467,11 @@ var MessageCircle = createLucideIcon("MessageCircle", [
|
|
|
467
467
|
["path", { d: "M7.9 20A9 9 0 1 0 4 16.1L2 22Z", key: "vv11sd" }]
|
|
468
468
|
]);
|
|
469
469
|
|
|
470
|
+
// node_modules/lucide-react/dist/esm/icons/square.js
|
|
471
|
+
var Square = createLucideIcon("Square", [
|
|
472
|
+
["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]
|
|
473
|
+
]);
|
|
474
|
+
|
|
470
475
|
// node_modules/lucide-react/dist/esm/icons/x.js
|
|
471
476
|
var X = createLucideIcon("X", [
|
|
472
477
|
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
@@ -503,6 +508,7 @@ var zh = {
|
|
|
503
508
|
"action.collapse": "\u6298\u53E0\u56DE\u7B54",
|
|
504
509
|
"action.close": "\u5173\u95ED\u65C1\u95EE",
|
|
505
510
|
"action.retryClose": "\u91CD\u8BD5\u5173\u95ED",
|
|
511
|
+
"action.stop": "\u505C\u6B62\u56DE\u7B54",
|
|
506
512
|
"status.answering": "\u6B63\u5728\u56DE\u7B54\u2026",
|
|
507
513
|
"status.closing": "\u6B63\u5728\u5173\u95ED\u2026",
|
|
508
514
|
"command.hint": "\u65C1\u95EE\u5185\u5BB9",
|
|
@@ -513,6 +519,7 @@ var zh = {
|
|
|
513
519
|
"error.attachments": "\u65C1\u95EE\u53EA\u63A5\u53D7\u6587\u5B57\uFF0C\u56FE\u7247\u548C\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u8F93\u5165\u6846\u4E2D\u3002",
|
|
514
520
|
"error.removeAttachments": "\u65C1\u95EE\u53EA\u63A5\u53D7\u6587\u5B57\uFF0C\u8BF7\u5148\u79FB\u9664\u56FE\u7247\u548C\u6587\u4EF6\u3002",
|
|
515
521
|
"error.backend": "BTW \u540E\u7AEF\u5C1A\u672A\u542F\u7528\uFF0C\u8BF7\u68C0\u67E5\u63D2\u4EF6\u914D\u7F6E\u3002",
|
|
522
|
+
"error.subagent": "\u5B50\u4EE3\u7406\u4F1A\u8BDD\u6682\u4E0D\u652F\u6301\u65C1\u95EE\uFF0C\u8BF7\u8FD4\u56DE\u4E3B\u4F1A\u8BDD\u4F7F\u7528 /btw\u3002",
|
|
516
523
|
"error.empty": "\u8BF7\u8F93\u5165\u65C1\u95EE\u5185\u5BB9\u3002",
|
|
517
524
|
"error.length": `\u65C1\u95EE\u6700\u591A\u652F\u6301 ${MAX_QUESTION_LENGTH} \u4E2A\u5B57\u7B26\u3002`,
|
|
518
525
|
"error.capacity": "\u6B63\u5728\u5904\u7406\u7684\u65C1\u95EE\u8F83\u591A\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
@@ -555,6 +562,7 @@ var en = {
|
|
|
555
562
|
"action.collapse": "Collapse answer",
|
|
556
563
|
"action.close": "Close side question",
|
|
557
564
|
"action.retryClose": "Retry closing",
|
|
565
|
+
"action.stop": "Stop answering",
|
|
558
566
|
"status.answering": "Answering\u2026",
|
|
559
567
|
"status.closing": "Closing\u2026",
|
|
560
568
|
"command.hint": "Side question",
|
|
@@ -565,6 +573,7 @@ var en = {
|
|
|
565
573
|
"error.attachments": "Side questions accept text only. Your images and files remain in the input.",
|
|
566
574
|
"error.removeAttachments": "Side questions accept text only. Remove the images and files first.",
|
|
567
575
|
"error.backend": "The BTW backend is unavailable. Check the plugin configuration.",
|
|
576
|
+
"error.subagent": "Side questions are not supported in subagent sessions. Use /btw in the main session.",
|
|
568
577
|
"error.empty": "Enter a side question.",
|
|
569
578
|
"error.length": `Side questions are limited to ${MAX_QUESTION_LENGTH.toLocaleString("en-US")} characters.`,
|
|
570
579
|
"error.capacity": "Too many side questions are running. Try again shortly.",
|
|
@@ -597,6 +606,8 @@ var CLOSE_COMMAND = "btw-close";
|
|
|
597
606
|
|
|
598
607
|
// src/client/bubbles.ts
|
|
599
608
|
var MAX_BUBBLES_PER_SESSION = 20;
|
|
609
|
+
var SideRequestNotStartedError = class extends Error {
|
|
610
|
+
};
|
|
600
611
|
var BubbleStore = class {
|
|
601
612
|
constructor(transport, t = translate()) {
|
|
602
613
|
this.transport = transport;
|
|
@@ -606,6 +617,9 @@ var BubbleStore = class {
|
|
|
606
617
|
listeners = /* @__PURE__ */ new Set();
|
|
607
618
|
active = /* @__PURE__ */ new Map();
|
|
608
619
|
closing = /* @__PURE__ */ new Map();
|
|
620
|
+
notStarted = /* @__PURE__ */ new Set();
|
|
621
|
+
runEnd = /* @__PURE__ */ new Map();
|
|
622
|
+
closeFenced = /* @__PURE__ */ new Set();
|
|
609
623
|
admitting = /* @__PURE__ */ new Set();
|
|
610
624
|
disposed = false;
|
|
611
625
|
getSnapshot = () => this.snapshot;
|
|
@@ -642,12 +656,43 @@ var BubbleStore = class {
|
|
|
642
656
|
const id = crypto.randomUUID();
|
|
643
657
|
const controller = new AbortController();
|
|
644
658
|
this.active.set(id, controller);
|
|
659
|
+
this.runEnd.set(id, "pending");
|
|
645
660
|
this.publish([...this.snapshot, { id, sessionId, question, ...reference === void 0 ? {} : { reference }, answer: "", phase: "answering" }]);
|
|
646
661
|
void Promise.resolve().then(() => reference === void 0 ? this.transport.run(sessionId, id, question, controller.signal) : this.transport.run(sessionId, id, question, controller.signal, reference)).then((result) => {
|
|
647
|
-
if (
|
|
648
|
-
|
|
662
|
+
if (result.kind === "success") {
|
|
663
|
+
this.runEnd.set(id, "success");
|
|
664
|
+
if (!this.snapshot.some((item) => item.id === id)) return;
|
|
665
|
+
const failedClose = this.closeFenced.has(id) || Boolean(this.snapshot.find((item) => item.id === id)?.closeFailed);
|
|
666
|
+
this.update(id, { phase: failedClose ? "error" : this.closing.has(id) ? "closing" : "done", answer: result.text, ...failedClose ? {} : { error: void 0 } });
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
if (controller.signal.aborted) {
|
|
670
|
+
if (this.runEnd.get(id) === "pending") this.runEnd.set(id, "aborted");
|
|
671
|
+
this.dropIfCloseCannotFinish(id);
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
this.runEnd.set(id, "failed");
|
|
675
|
+
if (!this.closing.has(id)) this.update(id, { phase: "error", answer: "", error: result.text });
|
|
649
676
|
}).catch((error) => {
|
|
650
|
-
if (
|
|
677
|
+
if (this.runEnd.get(id) === "success") return;
|
|
678
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
679
|
+
if (error instanceof SideRequestNotStartedError && this.snapshot.some((item) => item.id === id)) {
|
|
680
|
+
this.runEnd.set(id, "not-started");
|
|
681
|
+
this.notStarted.add(id);
|
|
682
|
+
if (this.closeFenced.has(id) || this.closing.has(id)) {
|
|
683
|
+
this.remove(id);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
this.update(id, { phase: "error", error: message });
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (controller.signal.aborted) {
|
|
690
|
+
if (this.runEnd.get(id) === "pending") this.runEnd.set(id, "aborted");
|
|
691
|
+
this.dropIfCloseCannotFinish(id);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
this.runEnd.set(id, "failed");
|
|
695
|
+
if (!this.closing.has(id)) this.update(id, { phase: "error", error: message });
|
|
651
696
|
}).finally(() => {
|
|
652
697
|
this.active.delete(id);
|
|
653
698
|
});
|
|
@@ -658,12 +703,28 @@ var BubbleStore = class {
|
|
|
658
703
|
if (existing) return existing;
|
|
659
704
|
const item = this.snapshot.find((bubble) => bubble.id === id);
|
|
660
705
|
if (!item) return Promise.resolve();
|
|
706
|
+
if (this.notStarted.has(id)) {
|
|
707
|
+
this.remove(id);
|
|
708
|
+
return Promise.resolve();
|
|
709
|
+
}
|
|
661
710
|
this.update(id, { phase: "closing", error: void 0, closeFailed: false });
|
|
662
711
|
this.active.get(id)?.abort();
|
|
663
712
|
const operation = Promise.resolve().then(() => this.transport.close(item.sessionId, id)).then((result) => {
|
|
664
713
|
if (result.kind === "error") throw new Error(result.text);
|
|
665
|
-
this.
|
|
714
|
+
this.remove(id);
|
|
666
715
|
}).catch((error) => {
|
|
716
|
+
if (this.notStarted.has(id) || this.runEnd.get(id) === "not-started") {
|
|
717
|
+
this.remove(id);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
if (error instanceof SideRequestNotStartedError) {
|
|
721
|
+
this.closeFenced.add(id);
|
|
722
|
+
const end = this.runEnd.get(id);
|
|
723
|
+
if (end === "aborted" || end === "not-started") {
|
|
724
|
+
this.remove(id);
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
667
728
|
this.update(id, { phase: "error", closeFailed: true, error: error instanceof Error ? error.message : String(error) });
|
|
668
729
|
}).finally(() => {
|
|
669
730
|
this.closing.delete(id);
|
|
@@ -676,6 +737,17 @@ var BubbleStore = class {
|
|
|
676
737
|
this.disposed = true;
|
|
677
738
|
await Promise.all(this.snapshot.map((item) => this.close(item.id)));
|
|
678
739
|
}
|
|
740
|
+
dropIfCloseCannotFinish(id) {
|
|
741
|
+
if (!this.closeFenced.has(id)) return;
|
|
742
|
+
const end = this.runEnd.get(id);
|
|
743
|
+
if (end === "not-started" || end === "aborted") this.remove(id);
|
|
744
|
+
}
|
|
745
|
+
remove(id) {
|
|
746
|
+
this.notStarted.delete(id);
|
|
747
|
+
this.runEnd.delete(id);
|
|
748
|
+
this.closeFenced.delete(id);
|
|
749
|
+
this.publish(this.snapshot.filter((item) => item.id !== id));
|
|
750
|
+
}
|
|
679
751
|
update(id, patch2) {
|
|
680
752
|
this.publish(this.snapshot.map((item) => item.id === id ? { ...item, ...patch2 } : item));
|
|
681
753
|
}
|
|
@@ -13452,8 +13524,7 @@ function AnswerMarkdown({ text: text7, labels, imageLabel }) {
|
|
|
13452
13524
|
}
|
|
13453
13525
|
|
|
13454
13526
|
// src/client/BubbleView.tsx
|
|
13455
|
-
function BubbleView({ item, close, t }) {
|
|
13456
|
-
const [collapsed, setCollapsed] = (0, import_react5.useState)(false);
|
|
13527
|
+
function BubbleView({ item, close, t, collapsed, onToggleCollapse }) {
|
|
13457
13528
|
const [copied, setCopied] = (0, import_react5.useState)(false);
|
|
13458
13529
|
const [copyError, setCopyError] = (0, import_react5.useState)(false);
|
|
13459
13530
|
const busy = item.phase === "answering" || item.phase === "closing";
|
|
@@ -13470,17 +13541,48 @@ function BubbleView({ item, close, t }) {
|
|
|
13470
13541
|
setCopyError(true);
|
|
13471
13542
|
}
|
|
13472
13543
|
};
|
|
13544
|
+
const stopOrCloseTitle = item.closeFailed ? t("action.retryClose") : t(item.phase === "answering" ? "action.stop" : "action.close");
|
|
13473
13545
|
return /* @__PURE__ */ import_react5.default.createElement("article", { className: "btw-bubble", "data-phase": item.phase, "aria-label": t("bubble.label") }, /* @__PURE__ */ import_react5.default.createElement("header", { className: "btw-header" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "btw-symbol" }, /* @__PURE__ */ import_react5.default.createElement(MessageCircle, { size: 16 })), /* @__PURE__ */ import_react5.default.createElement("span", { className: "btw-question" }, item.question), /* @__PURE__ */ import_react5.default.createElement("div", { className: "btw-actions" }, item.answer && /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", title: t(copied ? "action.copied" : "action.copy"), "aria-label": t("action.copy"), onClick: () => {
|
|
13474
13546
|
void copy();
|
|
13475
|
-
} }, copied ? /* @__PURE__ */ import_react5.default.createElement(Check, { size: 16 }) : /* @__PURE__ */ import_react5.default.createElement(Copy, { size: 16 })), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", title: t(collapsed ? "action.expand" : "action.collapse"), "aria-label": t(collapsed ? "action.expand" : "action.collapse"), "aria-expanded": !collapsed, onClick:
|
|
13547
|
+
} }, copied ? /* @__PURE__ */ import_react5.default.createElement(Check, { size: 16 }) : /* @__PURE__ */ import_react5.default.createElement(Copy, { size: 16 })), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", title: t(collapsed ? "action.expand" : "action.collapse"), "aria-label": t(collapsed ? "action.expand" : "action.collapse"), "aria-expanded": !collapsed, onClick: onToggleCollapse }, collapsed ? /* @__PURE__ */ import_react5.default.createElement(ChevronUp, { size: 16 }) : /* @__PURE__ */ import_react5.default.createElement(ChevronDown, { size: 16 })), /* @__PURE__ */ import_react5.default.createElement(
|
|
13548
|
+
"button",
|
|
13549
|
+
{
|
|
13550
|
+
type: "button",
|
|
13551
|
+
className: item.phase === "answering" ? "btw-action-stop" : void 0,
|
|
13552
|
+
title: stopOrCloseTitle,
|
|
13553
|
+
"aria-label": stopOrCloseTitle,
|
|
13554
|
+
disabled: item.phase === "closing",
|
|
13555
|
+
onClick: close
|
|
13556
|
+
},
|
|
13557
|
+
item.phase === "answering" ? /* @__PURE__ */ import_react5.default.createElement(Square, { size: 14 }) : /* @__PURE__ */ import_react5.default.createElement(X, { size: 16 })
|
|
13558
|
+
))), !collapsed && item.reference && /* @__PURE__ */ import_react5.default.createElement("details", { className: "btw-reference" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, t("selection.reference")), /* @__PURE__ */ import_react5.default.createElement("blockquote", null, item.reference)), busy && /* @__PURE__ */ import_react5.default.createElement("div", { className: "btw-status", role: "status" }, /* @__PURE__ */ import_react5.default.createElement(LoaderCircle, { size: 14, className: "btw-spinner" }), t(item.phase === "closing" ? "status.closing" : "status.answering")), !collapsed && item.answer && /* @__PURE__ */ import_react5.default.createElement("div", { className: "btw-answer" }, /* @__PURE__ */ import_react5.default.createElement(AnswerMarkdown, { text: item.answer, labels, imageLabel: t("bubble.image") })), item.error && /* @__PURE__ */ import_react5.default.createElement("p", { className: "btw-error", role: "alert" }, item.closeFailed ? t("error.close", { detail: item.error }) : item.error), copyError && /* @__PURE__ */ import_react5.default.createElement("p", { className: "btw-error", role: "alert" }, t("error.copy")));
|
|
13476
13559
|
}
|
|
13477
13560
|
function BubbleDock({ store, sessionId, t }) {
|
|
13478
13561
|
const snapshot = (0, import_react5.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
13479
13562
|
const items = snapshot.filter((item) => item.sessionId === sessionId);
|
|
13563
|
+
const latestId = items.at(-1)?.id;
|
|
13564
|
+
const [manual, setManual] = (0, import_react5.useState)();
|
|
13565
|
+
const hasNewlyAddedBubble = manual !== void 0 && items.some((item) => !manual.knownIds.includes(item.id));
|
|
13566
|
+
const currentIds = items.map((item) => item.id);
|
|
13567
|
+
const isPinnedValid = manual !== void 0 && !hasNewlyAddedBubble && manual.id !== null ? items.some((item) => item.id === manual.id) : false;
|
|
13568
|
+
const effectiveExpandedId = manual === void 0 || hasNewlyAddedBubble ? latestId : manual.id === null ? null : isPinnedValid ? manual.id : latestId;
|
|
13480
13569
|
if (!items.length) return null;
|
|
13481
|
-
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "btw-dock" }, items.map((item) => /* @__PURE__ */ import_react5.default.createElement(
|
|
13482
|
-
|
|
13483
|
-
|
|
13570
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "btw-dock" }, items.map((item) => /* @__PURE__ */ import_react5.default.createElement(
|
|
13571
|
+
BubbleView,
|
|
13572
|
+
{
|
|
13573
|
+
key: item.id,
|
|
13574
|
+
item,
|
|
13575
|
+
t,
|
|
13576
|
+
collapsed: item.id !== effectiveExpandedId,
|
|
13577
|
+
onToggleCollapse: () => {
|
|
13578
|
+
if (item.id === effectiveExpandedId) setManual({ id: null, knownIds: currentIds });
|
|
13579
|
+
else setManual({ id: item.id, knownIds: currentIds });
|
|
13580
|
+
},
|
|
13581
|
+
close: () => {
|
|
13582
|
+
void store.close(item.id);
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13585
|
+
)));
|
|
13484
13586
|
}
|
|
13485
13587
|
|
|
13486
13588
|
// src/client/composer.ts
|
|
@@ -13729,6 +13831,8 @@ var CSS = `
|
|
|
13729
13831
|
.btw-actions button{display:grid;place-items:center;width:28px;height:28px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;flex:none;transition:background-color 120ms ease}
|
|
13730
13832
|
.btw-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
|
|
13731
13833
|
.btw-actions button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-alias-label-primary));outline-offset:-2px}
|
|
13834
|
+
.btw-actions button.btw-action-stop{color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-primary))}
|
|
13835
|
+
.btw-actions button.btw-action-stop:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-primary))}
|
|
13732
13836
|
.btw-actions button:disabled{cursor:wait;opacity:.5}
|
|
13733
13837
|
.btw-status{display:flex;align-items:center;gap:8px;padding:0 14px 12px;color:var(--dsw-alias-label-secondary);font-size:13px}
|
|
13734
13838
|
.btw-spinner{animation:btw-spin 1.2s linear infinite}@keyframes btw-spin{to{transform:rotate(360deg)}}
|
|
@@ -13754,7 +13858,7 @@ function sessionIdOf(session) {
|
|
|
13754
13858
|
if (session && typeof session === "object" && "sessionId" in session) return String(session.sessionId);
|
|
13755
13859
|
return String(session);
|
|
13756
13860
|
}
|
|
13757
|
-
function attachOfficialBtw(commandUi, claim, t) {
|
|
13861
|
+
function attachOfficialBtw(commandUi, claim, t, isSubagent) {
|
|
13758
13862
|
const live = commandUi;
|
|
13759
13863
|
if (!live) return () => {
|
|
13760
13864
|
};
|
|
@@ -13764,7 +13868,7 @@ function attachOfficialBtw(commandUi, claim, t) {
|
|
|
13764
13868
|
live.candidates = async (...args) => {
|
|
13765
13869
|
const rows = await original.apply(live, args);
|
|
13766
13870
|
if (!Array.isArray(rows)) return rows;
|
|
13767
|
-
return rows.map((row) => {
|
|
13871
|
+
return rows.filter((row) => !(isSubagent(sessionIdOf(args[0])) && row && typeof row === "object" && "name" in row && row.name === "btw")).map((row) => {
|
|
13768
13872
|
if (!row || typeof row !== "object" || !("name" in row) || row.name !== "btw") return row;
|
|
13769
13873
|
const item = row;
|
|
13770
13874
|
return {
|
|
@@ -13782,14 +13886,14 @@ function attachOfficialBtw(commandUi, claim, t) {
|
|
|
13782
13886
|
}
|
|
13783
13887
|
if (typeof live.dispatch === "function") {
|
|
13784
13888
|
const original = live.dispatch.bind(live);
|
|
13785
|
-
live.dispatch = (pick) => pick.candidate?.name === "btw" ? claim(sessionIdOf(pick.session)) : original(pick);
|
|
13889
|
+
live.dispatch = (pick) => pick.candidate?.name === "btw" ? isSubagent(sessionIdOf(pick.session)) ? void 0 : claim(sessionIdOf(pick.session)) : original(pick);
|
|
13786
13890
|
restore.push(() => {
|
|
13787
13891
|
live.dispatch = original;
|
|
13788
13892
|
});
|
|
13789
13893
|
}
|
|
13790
13894
|
if (typeof live.matchSpace === "function") {
|
|
13791
13895
|
const original = live.matchSpace.bind(live);
|
|
13792
|
-
live.matchSpace = (session, token) => token === "/btw" ? claim(sessionIdOf(session)) : original(session, token);
|
|
13896
|
+
live.matchSpace = (session, token) => token === "/btw" ? isSubagent(sessionIdOf(session)) ? void 0 : claim(sessionIdOf(session)) : original(session, token);
|
|
13793
13897
|
restore.push(() => {
|
|
13794
13898
|
live.matchSpace = original;
|
|
13795
13899
|
});
|
|
@@ -13798,6 +13902,7 @@ function attachOfficialBtw(commandUi, claim, t) {
|
|
|
13798
13902
|
const original = live.matchEnter.bind(live);
|
|
13799
13903
|
live.matchEnter = async (session, line, signal, envelope) => {
|
|
13800
13904
|
if (!/^\/btw(?:\s|$)/.test(line.trim())) return original(session, line, signal, envelope);
|
|
13905
|
+
if (isSubagent(sessionIdOf(session))) throw new Error(t("error.subagent"));
|
|
13801
13906
|
if (envelope?.attachments || envelope?.images) throw new Error(t("error.removeAttachments"));
|
|
13802
13907
|
return claim(sessionIdOf(session));
|
|
13803
13908
|
};
|
|
@@ -13809,6 +13914,7 @@ function attachOfficialBtw(commandUi, claim, t) {
|
|
|
13809
13914
|
const original = live.execute.bind(live);
|
|
13810
13915
|
live.execute = async (session, line, attachments) => {
|
|
13811
13916
|
if (!/^\/btw(?:\s|$)/.test(line)) return original(session, line, attachments);
|
|
13917
|
+
if (isSubagent(sessionIdOf(session))) return { kind: "error", text: t("error.subagent") };
|
|
13812
13918
|
if (Array.isArray(attachments) && attachments.length) return { kind: "error", text: t("error.attachments") };
|
|
13813
13919
|
const outcome = claim(sessionIdOf(session));
|
|
13814
13920
|
if (!outcome || typeof outcome !== "object" || !("claim" in outcome)) return { kind: "error", text: t("error.backend") };
|
|
@@ -13829,9 +13935,19 @@ function apply(ctx) {
|
|
|
13829
13935
|
const t = ctx.locale.bind(NS);
|
|
13830
13936
|
const slots = ctx.get("slots");
|
|
13831
13937
|
const remote = ctx.get("remote");
|
|
13938
|
+
const sessions = ctx.get("sessions");
|
|
13939
|
+
const isSubagent = (id) => Boolean(sessions.subagentAddress?.(id)) || sessions.list?.getSnapshot().byId[id]?.origin === "subagent";
|
|
13832
13940
|
const execute = async (session, line, signal) => {
|
|
13833
13941
|
const response = await remote.commands.execute(session, line, [], signal);
|
|
13834
|
-
if (!response.ok)
|
|
13942
|
+
if (!response.ok) {
|
|
13943
|
+
const failure = response.error;
|
|
13944
|
+
const code4 = failure.code;
|
|
13945
|
+
const details = failure.details;
|
|
13946
|
+
const reason = details && typeof details === "object" && "reason" in details && typeof details.reason === "string" ? details.reason : void 0;
|
|
13947
|
+
const ownedBySubagent = (code4 === "agent-busy" || code4 === "session/agent-busy") && (reason === "use subagent delivery for this child session" || failure.message === `session "${session}" is owned by subagent routing`);
|
|
13948
|
+
if (ownedBySubagent) throw new SideRequestNotStartedError(t("error.subagent"));
|
|
13949
|
+
throw new Error(failure.message);
|
|
13950
|
+
}
|
|
13835
13951
|
if (!response.value) throw new Error(t("error.backend"));
|
|
13836
13952
|
return { kind: response.value.result.kind, text: response.value.result.text ?? "" };
|
|
13837
13953
|
};
|
|
@@ -13841,11 +13957,12 @@ function apply(ctx) {
|
|
|
13841
13957
|
}, t);
|
|
13842
13958
|
const claim = (sessionId) => ({ claim: {
|
|
13843
13959
|
name: "btw",
|
|
13844
|
-
token: "/btw",
|
|
13960
|
+
token: "/btw ",
|
|
13845
13961
|
get hint() {
|
|
13846
13962
|
return t("command.hint");
|
|
13847
13963
|
},
|
|
13848
13964
|
submit: async (args, _actx, attachments) => {
|
|
13965
|
+
if (isSubagent(sessionId)) return { kind: "error", text: t("error.subagent") };
|
|
13849
13966
|
if (attachments.length) return { kind: "error", text: t("error.attachments") };
|
|
13850
13967
|
try {
|
|
13851
13968
|
await store.ask(sessionId, args.trim());
|
|
@@ -13855,8 +13972,8 @@ function apply(ctx) {
|
|
|
13855
13972
|
}
|
|
13856
13973
|
}
|
|
13857
13974
|
} });
|
|
13858
|
-
if (typeof ctx.inject === "function") ctx.inject(["commandUi"], (scope) => attachOfficialBtw(scope.get("commandUi"), (sessionId) => claim(sessionId), t));
|
|
13859
|
-
else ctx.effect(() => attachOfficialBtw(ctx.get("commandUi"), (sessionId) => claim(sessionId), t));
|
|
13975
|
+
if (typeof ctx.inject === "function") ctx.inject(["commandUi"], (scope) => attachOfficialBtw(scope.get("commandUi"), (sessionId) => claim(sessionId), t, isSubagent));
|
|
13976
|
+
else ctx.effect(() => attachOfficialBtw(ctx.get("commandUi"), (sessionId) => claim(sessionId), t, isSubagent));
|
|
13860
13977
|
ctx.effect(() => {
|
|
13861
13978
|
const style = document.createElement("style");
|
|
13862
13979
|
style.dataset.plugin = "@michengai/dsh-btw";
|
|
@@ -13868,7 +13985,7 @@ function apply(ctx) {
|
|
|
13868
13985
|
});
|
|
13869
13986
|
ctx.effect(() => () => store.dispose());
|
|
13870
13987
|
function Dock(props) {
|
|
13871
|
-
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(SelectionAsk, { key: props.session.sessionId, store, sessionId: props.session.sessionId, t: props.t, addToConversation: (reference) => {
|
|
13988
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, !props.session.subagent && !isSubagent(props.session.sessionId) && /* @__PURE__ */ import_react7.default.createElement(SelectionAsk, { key: props.session.sessionId, store, sessionId: props.session.sessionId, t: props.t, addToConversation: (reference) => {
|
|
13872
13989
|
const session = ctx.get("sessions").scope(props.session.sessionId);
|
|
13873
13990
|
if (!session) throw new Error(props.t("error.backend"));
|
|
13874
13991
|
addQuoteToComposer(ctx.conversation.input.for(session), reference, props.t);
|
|
@@ -13892,6 +14009,7 @@ lucide-react/dist/esm/icons/chevron-up.js:
|
|
|
13892
14009
|
lucide-react/dist/esm/icons/copy.js:
|
|
13893
14010
|
lucide-react/dist/esm/icons/loader-circle.js:
|
|
13894
14011
|
lucide-react/dist/esm/icons/message-circle.js:
|
|
14012
|
+
lucide-react/dist/esm/icons/square.js:
|
|
13895
14013
|
lucide-react/dist/esm/icons/x.js:
|
|
13896
14014
|
lucide-react/dist/esm/lucide-react.js:
|
|
13897
14015
|
(**
|
package/lib/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var zh = {
|
|
|
31
31
|
"action.collapse": "\u6298\u53E0\u56DE\u7B54",
|
|
32
32
|
"action.close": "\u5173\u95ED\u65C1\u95EE",
|
|
33
33
|
"action.retryClose": "\u91CD\u8BD5\u5173\u95ED",
|
|
34
|
+
"action.stop": "\u505C\u6B62\u56DE\u7B54",
|
|
34
35
|
"status.answering": "\u6B63\u5728\u56DE\u7B54\u2026",
|
|
35
36
|
"status.closing": "\u6B63\u5728\u5173\u95ED\u2026",
|
|
36
37
|
"command.hint": "\u65C1\u95EE\u5185\u5BB9",
|
|
@@ -41,6 +42,7 @@ var zh = {
|
|
|
41
42
|
"error.attachments": "\u65C1\u95EE\u53EA\u63A5\u53D7\u6587\u5B57\uFF0C\u56FE\u7247\u548C\u6587\u4EF6\u4ECD\u4FDD\u7559\u5728\u8F93\u5165\u6846\u4E2D\u3002",
|
|
42
43
|
"error.removeAttachments": "\u65C1\u95EE\u53EA\u63A5\u53D7\u6587\u5B57\uFF0C\u8BF7\u5148\u79FB\u9664\u56FE\u7247\u548C\u6587\u4EF6\u3002",
|
|
43
44
|
"error.backend": "BTW \u540E\u7AEF\u5C1A\u672A\u542F\u7528\uFF0C\u8BF7\u68C0\u67E5\u63D2\u4EF6\u914D\u7F6E\u3002",
|
|
45
|
+
"error.subagent": "\u5B50\u4EE3\u7406\u4F1A\u8BDD\u6682\u4E0D\u652F\u6301\u65C1\u95EE\uFF0C\u8BF7\u8FD4\u56DE\u4E3B\u4F1A\u8BDD\u4F7F\u7528 /btw\u3002",
|
|
44
46
|
"error.empty": "\u8BF7\u8F93\u5165\u65C1\u95EE\u5185\u5BB9\u3002",
|
|
45
47
|
"error.length": `\u65C1\u95EE\u6700\u591A\u652F\u6301 ${MAX_QUESTION_LENGTH} \u4E2A\u5B57\u7B26\u3002`,
|
|
46
48
|
"error.capacity": "\u6B63\u5728\u5904\u7406\u7684\u65C1\u95EE\u8F83\u591A\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
|
|
@@ -83,6 +85,7 @@ var en = {
|
|
|
83
85
|
"action.collapse": "Collapse answer",
|
|
84
86
|
"action.close": "Close side question",
|
|
85
87
|
"action.retryClose": "Retry closing",
|
|
88
|
+
"action.stop": "Stop answering",
|
|
86
89
|
"status.answering": "Answering\u2026",
|
|
87
90
|
"status.closing": "Closing\u2026",
|
|
88
91
|
"command.hint": "Side question",
|
|
@@ -93,6 +96,7 @@ var en = {
|
|
|
93
96
|
"error.attachments": "Side questions accept text only. Your images and files remain in the input.",
|
|
94
97
|
"error.removeAttachments": "Side questions accept text only. Remove the images and files first.",
|
|
95
98
|
"error.backend": "The BTW backend is unavailable. Check the plugin configuration.",
|
|
99
|
+
"error.subagent": "Side questions are not supported in subagent sessions. Use /btw in the main session.",
|
|
96
100
|
"error.empty": "Enter a side question.",
|
|
97
101
|
"error.length": `Side questions are limited to ${MAX_QUESTION_LENGTH.toLocaleString("en-US")} characters.`,
|
|
98
102
|
"error.capacity": "Too many side questions are running. Try again shortly.",
|
|
@@ -157,8 +161,9 @@ ${question}`;
|
|
|
157
161
|
|
|
158
162
|
// src/server/jobs.ts
|
|
159
163
|
var failure = (error) => ({ kind: "error", text: error instanceof Error ? error.message : String(error) });
|
|
164
|
+
var DEFAULT_TIMEOUT_MS = 18e5;
|
|
160
165
|
var SideJobs = class {
|
|
161
|
-
constructor(start, timeoutMs =
|
|
166
|
+
constructor(start, timeoutMs = DEFAULT_TIMEOUT_MS, options = {}) {
|
|
162
167
|
this.start = start;
|
|
163
168
|
this.timeoutMs = timeoutMs;
|
|
164
169
|
this.options = options;
|
|
@@ -182,10 +187,10 @@ var SideJobs = class {
|
|
|
182
187
|
const cancel = () => job.controller.abort(new Error(t("error.cancelled")));
|
|
183
188
|
signal?.addEventListener("abort", cancel, { once: true });
|
|
184
189
|
if (signal?.aborted) cancel();
|
|
185
|
-
const timer = setTimeout(() => job.controller.abort(new Error(t("error.timeout"))), this.timeoutMs);
|
|
186
|
-
timer
|
|
190
|
+
const timer = this.timeoutMs > 0 ? setTimeout(() => job.controller.abort(new Error(t("error.timeout"))), this.timeoutMs) : void 0;
|
|
191
|
+
timer?.unref?.();
|
|
187
192
|
job.finished = this.execute(job, { scope, id, question, signal: job.controller.signal, toolFilter: { allow: [] }, context, locale }).finally(() => {
|
|
188
|
-
clearTimeout(timer);
|
|
193
|
+
if (timer) clearTimeout(timer);
|
|
189
194
|
signal?.removeEventListener("abort", cancel);
|
|
190
195
|
this.release(job);
|
|
191
196
|
});
|
|
@@ -448,50 +453,84 @@ function apply(ctx) {
|
|
|
448
453
|
throw new Error(translate(request.locale)("error.provider"));
|
|
449
454
|
}
|
|
450
455
|
const label = `michengai-btw:${globalThis.crypto.randomUUID()}`;
|
|
451
|
-
const childId = SessionId(globalThis.crypto.randomUUID());
|
|
452
456
|
labels.add(label);
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
if (agent.id !== childId) return void 0;
|
|
457
|
-
childAgent = agent;
|
|
458
|
-
arm(agent);
|
|
459
|
-
const scoped = agent;
|
|
460
|
-
if (scoped.ctx?.systemPrompt) {
|
|
461
|
-
scoped.ctx.systemPrompt.section({
|
|
462
|
-
name: PERSONA_PREFIX_SECTION,
|
|
463
|
-
order: scoped.ctx.systemPrompt.getSectionOrder("DEPLOYMENT_PERSONA_PREFIX"),
|
|
464
|
-
text: PERSONA
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
if (scoped.ctx?.tools) scoped.ctx.tools.restrict(request.toolFilter);
|
|
468
|
-
return void 0;
|
|
469
|
-
});
|
|
470
|
-
let activation;
|
|
457
|
+
if (typeof ctx.subagents.startActivation === "function") {
|
|
458
|
+
const childId = SessionId(globalThis.crypto.randomUUID());
|
|
459
|
+
let childAgent;
|
|
471
460
|
try {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
461
|
+
const stopCreated = ctx.on("agent/created", ({ agent }) => {
|
|
462
|
+
if (agent.id !== childId) return void 0;
|
|
463
|
+
childAgent = agent;
|
|
464
|
+
arm(agent);
|
|
465
|
+
const scoped = agent;
|
|
466
|
+
if (scoped.ctx?.systemPrompt) {
|
|
467
|
+
scoped.ctx.systemPrompt.section({
|
|
468
|
+
name: PERSONA_PREFIX_SECTION,
|
|
469
|
+
order: scoped.ctx.systemPrompt.getSectionOrder("DEPLOYMENT_PERSONA_PREFIX"),
|
|
470
|
+
text: PERSONA
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
if (scoped.ctx?.tools) scoped.ctx.tools.restrict(request.toolFilter);
|
|
474
|
+
return void 0;
|
|
475
|
+
});
|
|
476
|
+
let activation;
|
|
477
|
+
try {
|
|
478
|
+
activation = await ctx.subagents.startActivation({
|
|
479
|
+
provider: "fork",
|
|
480
|
+
label,
|
|
481
|
+
childId,
|
|
482
|
+
request: {
|
|
483
|
+
parent: request.context,
|
|
484
|
+
prompt: [{ type: "text", text: `\u4EE5\u4E0B\u662F\u552F\u4E00\u9700\u8981\u56DE\u7B54\u7684\u65B0\u95EE\u9898\uFF1B\u5148\u524D\u5185\u5BB9\u4EC5\u4F9B\u53C2\u8003\u3002
|
|
479
485
|
|
|
480
486
|
${request.question}` }]
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
+
},
|
|
488
|
+
signal: request.signal,
|
|
489
|
+
delivery: "caller"
|
|
490
|
+
});
|
|
491
|
+
} finally {
|
|
492
|
+
stopCreated();
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
result: activation.result,
|
|
496
|
+
dispose: async () => {
|
|
497
|
+
try {
|
|
498
|
+
await activation.dispose();
|
|
499
|
+
} finally {
|
|
500
|
+
await releaseChild(childAgent);
|
|
501
|
+
labels.delete(label);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
} catch (error) {
|
|
506
|
+
labels.delete(label);
|
|
507
|
+
throw error;
|
|
487
508
|
}
|
|
509
|
+
}
|
|
510
|
+
const legacySubagents = ctx.subagents;
|
|
511
|
+
if (typeof legacySubagents.start !== "function") {
|
|
512
|
+
labels.delete(label);
|
|
513
|
+
throw new Error(translate(request.locale)("error.provider"));
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
const run = await legacySubagents.start("fork", {
|
|
517
|
+
parent: request.context,
|
|
518
|
+
label,
|
|
519
|
+
signal: request.signal,
|
|
520
|
+
toolFilter: request.toolFilter,
|
|
521
|
+
persona: PERSONA,
|
|
522
|
+
prompt: [{ type: "text", text: `\u4EE5\u4E0B\u662F\u552F\u4E00\u9700\u8981\u56DE\u7B54\u7684\u65B0\u95EE\u9898\uFF1B\u5148\u524D\u5185\u5BB9\u4EC5\u4F9B\u53C2\u8003\u3002
|
|
523
|
+
|
|
524
|
+
${request.question}` }]
|
|
525
|
+
});
|
|
526
|
+
if (run.localAgent) arm(run.localAgent);
|
|
488
527
|
return {
|
|
489
|
-
result:
|
|
528
|
+
result: run.result,
|
|
490
529
|
dispose: async () => {
|
|
491
530
|
try {
|
|
492
|
-
await
|
|
531
|
+
await run.dispose();
|
|
493
532
|
} finally {
|
|
494
|
-
await releaseChild(
|
|
533
|
+
await releaseChild(run.localAgent);
|
|
495
534
|
labels.delete(label);
|
|
496
535
|
}
|
|
497
536
|
}
|
|
@@ -500,7 +539,7 @@ ${request.question}` }]
|
|
|
500
539
|
labels.delete(label);
|
|
501
540
|
throw error;
|
|
502
541
|
}
|
|
503
|
-
},
|
|
542
|
+
}, DEFAULT_TIMEOUT_MS, {
|
|
504
543
|
onError: (error) => ctx.logger.warn(error),
|
|
505
544
|
onIdle: async () => {
|
|
506
545
|
stopWatch();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { Bubble, BubbleStore } from './bubbles';
|
|
3
3
|
import type { BtwTranslate } from '../locales';
|
|
4
|
-
export declare function BubbleView({ item, close, t }: {
|
|
4
|
+
export declare function BubbleView({ item, close, t, collapsed, onToggleCollapse }: {
|
|
5
5
|
item: Bubble;
|
|
6
6
|
close: () => void;
|
|
7
7
|
t: BtwTranslate;
|
|
8
|
+
collapsed: boolean;
|
|
9
|
+
onToggleCollapse: () => void;
|
|
8
10
|
}): React.JSX.Element;
|
|
9
11
|
export declare function BubbleDock({ store, sessionId, t }: {
|
|
10
12
|
store: BubbleStore;
|
|
@@ -14,6 +14,9 @@ export interface SideTransport {
|
|
|
14
14
|
run(session: string, id: string, question: string, signal: AbortSignal, reference?: string): Promise<SideResult>;
|
|
15
15
|
close(session: string, id: string): Promise<SideResult>;
|
|
16
16
|
}
|
|
17
|
+
/** 宿主在进入 handler 前明确拒绝启动;没有后台任务需要清理。 */
|
|
18
|
+
export declare class SideRequestNotStartedError extends Error {
|
|
19
|
+
}
|
|
17
20
|
/** 仅内存 UI 状态;关闭请求与答案返回按请求身份分别收敛。 */
|
|
18
21
|
export declare class BubbleStore {
|
|
19
22
|
private readonly transport;
|
|
@@ -22,6 +25,9 @@ export declare class BubbleStore {
|
|
|
22
25
|
private readonly listeners;
|
|
23
26
|
private readonly active;
|
|
24
27
|
private readonly closing;
|
|
28
|
+
private readonly notStarted;
|
|
29
|
+
private readonly runEnd;
|
|
30
|
+
private readonly closeFenced;
|
|
25
31
|
private readonly admitting;
|
|
26
32
|
private disposed;
|
|
27
33
|
constructor(transport: SideTransport, t?: BtwTranslate);
|
|
@@ -31,6 +37,8 @@ export declare class BubbleStore {
|
|
|
31
37
|
ask(sessionId: string, question: string, reference?: string): Promise<string>;
|
|
32
38
|
close(id: string): Promise<void>;
|
|
33
39
|
dispose(): Promise<void>;
|
|
40
|
+
private dropIfCloseCannotFinish;
|
|
41
|
+
private remove;
|
|
34
42
|
private update;
|
|
35
43
|
private publish;
|
|
36
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CSS = "\n.btw-reference-preview{display:block;margin-top:6px;max-height:3.2em;overflow:hidden;overflow-wrap:anywhere;line-height:1.6;color:var(--dsw-alias-label-primary)}\n.btw-selection-dialog,.btw-selection-menu{position:fixed;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;font:inherit;font-size:13px;max-height:calc(100dvh - 32px);overflow:auto;box-shadow:0 12px 36px #0003}\n.btw-selection-dialog{width:min(520px,calc(100vw - 32px));margin:auto}.btw-selection-menu{margin:0;width:max-content;max-width:calc(100vw - 16px);padding:0;inset:auto;border-radius:10px;overflow:hidden;border-color:var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);font-family:inherit;font-size:12px;font-weight:500;line-height:16px;box-shadow:0 2px 6px #0001}\n.btw-selection-menu::backdrop{background:transparent}.btw-selection-dialog::backdrop{background:#0004}\n.btw-selection-dialog h3{margin:0 0 12px;font-size:16px}.btw-selection-dialog label{display:flex;flex-direction:column;gap:8px;margin-top:12px}\n.btw-selection-dialog textarea{box-sizing:border-box;width:100%;min-height:96px;resize:vertical;font:inherit;padding:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-base);color:inherit}\n.btw-selection-dialog button,.btw-selection-menu button{font:inherit;color:inherit;background:var(--dsw-alias-interactive-bg-hover);border:0;border-radius:6px;padding:8px 12px;cursor:pointer;min-height:36px}\n.btw-selection-menu [role=\"toolbar\"]{display:flex;align-items:center}.btw-selection-menu button+button{border-left:1px solid var(--dsw-alias-border-l1)}\n.btw-selection-menu button{display:inline-flex;align-items:center;height:28px;min-height:28px;padding:0 8px;border-radius:0;text-align:left;white-space:nowrap;background:transparent}.btw-selection-menu button:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.btw-selection-dialog button:disabled{opacity:.5;cursor:default}.btw-selection-dialog :focus-visible,.btw-selection-menu :focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-alias-label-primary));outline-offset:2px}\n.btw-selection-menu :focus-visible{outline-width:1px;outline-offset:-2px}\n.btw-selection-actions{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px}.btw-selection-hint{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;margin:10px 4px}\n.btw-reference{padding:0 14px 10px;font-size:12px}.btw-reference summary{cursor:pointer;color:var(--dsw-alias-label-secondary)}.btw-reference blockquote{margin:8px 0 0;padding:8px;border-left:2px solid var(--dsw-alias-border-l2);white-space:pre-wrap;overflow-wrap:anywhere;max-height:150px;overflow:auto}.btw-selection-dialog .btw-reference{padding:0}\n.btw-dock{display:flex;flex:none;flex-direction:column;gap:8px;width:calc(100% - var(--dsh-composer-side-clearance,0px) - var(--dsh-composer-side-clearance,0px));max-width:var(--dsh-composer-card-max-width,100%);margin:0 auto;max-height:440px;overflow:auto;padding:4px 0 10px;box-sizing:border-box;letter-spacing:0}\n.btw-bubble{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;min-width:0;flex-shrink:0;font-size:13px;line-height:1.6;font-family:var(--dsw-font-family,inherit);letter-spacing:0}\n.btw-header{display:flex;align-items:center;gap:8px;padding:8px 10px 8px 14px;min-width:0;min-height:44px}\n.btw-symbol{display:flex;align-items:center;color:var(--dsw-alias-label-secondary);height:28px;flex-shrink:0}\n.btw-question{flex:1;min-width:0;overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px;max-height:66px;overflow:auto}\n.btw-actions{display:flex;gap:4px;flex-shrink:0}\n.btw-actions button{display:grid;place-items:center;width:28px;height:28px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;flex:none;transition:background-color 120ms ease}\n.btw-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.btw-actions button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-alias-label-primary));outline-offset:-2px}\n.btw-actions button:disabled{cursor:wait;opacity:.5}\n.btw-status{display:flex;align-items:center;gap:8px;padding:0 14px 12px;color:var(--dsw-alias-label-secondary);font-size:13px}\n.btw-spinner{animation:btw-spin 1.2s linear infinite}@keyframes btw-spin{to{transform:rotate(360deg)}}\n.btw-answer{padding:0 14px 14px;max-height:300px;overflow:auto;overflow-wrap:anywhere;font-size:13px;line-height:1.7}\n.btw-answer>*:first-child{margin-top:0}.btw-answer>*:last-child{margin-bottom:0}\n.btw-answer p{margin:8px 0}.btw-answer h1,.btw-answer h2,.btw-answer h3{font-size:15px;line-height:1.5;margin:12px 0 6px;font-weight:600}\n.btw-answer pre{max-width:100%;overflow:auto;background:var(--dsw-alias-markdown-code-block);padding:10px;border-radius:8px;white-space:pre;font-size:12px}.btw-answer .katex-display{max-width:100%;overflow:auto}\n.btw-answer code{font-family:Consolas,monospace;font-size:12px}.btw-answer :not(pre)>code{background:var(--dsw-alias-markdown-code-block);border-radius:4px;padding:1px 3px}.btw-answer a{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}\n.btw-answer table{display:block;max-width:100%;overflow:auto;border-collapse:collapse}.btw-answer th,.btw-answer td{border:1px solid var(--dsw-alias-border-l2);padding:5px 9px}\n.btw-answer ul,.btw-answer ol{padding-left:22px}.btw-answer blockquote{margin:8px 0;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-secondary)}\n.btw-error{margin:0;padding:0 14px 12px;font-size:13px;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere}\n@media(max-width:480px){.btw-dock{max-height:330px}.btw-header{padding:6px 8px 6px 12px;gap:6px}.btw-answer{padding:0 12px 12px;max-height:230px}.btw-status,.btw-error{padding-left:12px}.btw-actions{gap:0}.btw-actions button{width:36px;height:36px}}\n@media(prefers-reduced-motion:reduce){.btw-spinner{animation:none}.btw-actions button{transition:none}}\n";
|
|
1
|
+
export declare const CSS = "\n.btw-reference-preview{display:block;margin-top:6px;max-height:3.2em;overflow:hidden;overflow-wrap:anywhere;line-height:1.6;color:var(--dsw-alias-label-primary)}\n.btw-selection-dialog,.btw-selection-menu{position:fixed;box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;padding:16px;font:inherit;font-size:13px;max-height:calc(100dvh - 32px);overflow:auto;box-shadow:0 12px 36px #0003}\n.btw-selection-dialog{width:min(520px,calc(100vw - 32px));margin:auto}.btw-selection-menu{margin:0;width:max-content;max-width:calc(100vw - 16px);padding:0;inset:auto;border-radius:10px;overflow:hidden;border-color:var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);font-family:inherit;font-size:12px;font-weight:500;line-height:16px;box-shadow:0 2px 6px #0001}\n.btw-selection-menu::backdrop{background:transparent}.btw-selection-dialog::backdrop{background:#0004}\n.btw-selection-dialog h3{margin:0 0 12px;font-size:16px}.btw-selection-dialog label{display:flex;flex-direction:column;gap:8px;margin-top:12px}\n.btw-selection-dialog textarea{box-sizing:border-box;width:100%;min-height:96px;resize:vertical;font:inherit;padding:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-base);color:inherit}\n.btw-selection-dialog button,.btw-selection-menu button{font:inherit;color:inherit;background:var(--dsw-alias-interactive-bg-hover);border:0;border-radius:6px;padding:8px 12px;cursor:pointer;min-height:36px}\n.btw-selection-menu [role=\"toolbar\"]{display:flex;align-items:center}.btw-selection-menu button+button{border-left:1px solid var(--dsw-alias-border-l1)}\n.btw-selection-menu button{display:inline-flex;align-items:center;height:28px;min-height:28px;padding:0 8px;border-radius:0;text-align:left;white-space:nowrap;background:transparent}.btw-selection-menu button:hover{background:var(--dsw-alias-interactive-bg-hover)}\n.btw-selection-dialog button:disabled{opacity:.5;cursor:default}.btw-selection-dialog :focus-visible,.btw-selection-menu :focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-alias-label-primary));outline-offset:2px}\n.btw-selection-menu :focus-visible{outline-width:1px;outline-offset:-2px}\n.btw-selection-actions{display:flex;justify-content:flex-end;flex-wrap:wrap;gap:8px}.btw-selection-hint{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6;margin:10px 4px}\n.btw-reference{padding:0 14px 10px;font-size:12px}.btw-reference summary{cursor:pointer;color:var(--dsw-alias-label-secondary)}.btw-reference blockquote{margin:8px 0 0;padding:8px;border-left:2px solid var(--dsw-alias-border-l2);white-space:pre-wrap;overflow-wrap:anywhere;max-height:150px;overflow:auto}.btw-selection-dialog .btw-reference{padding:0}\n.btw-dock{display:flex;flex:none;flex-direction:column;gap:8px;width:calc(100% - var(--dsh-composer-side-clearance,0px) - var(--dsh-composer-side-clearance,0px));max-width:var(--dsh-composer-card-max-width,100%);margin:0 auto;max-height:440px;overflow:auto;padding:4px 0 10px;box-sizing:border-box;letter-spacing:0}\n.btw-bubble{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;min-width:0;flex-shrink:0;font-size:13px;line-height:1.6;font-family:var(--dsw-font-family,inherit);letter-spacing:0}\n.btw-header{display:flex;align-items:center;gap:8px;padding:8px 10px 8px 14px;min-width:0;min-height:44px}\n.btw-symbol{display:flex;align-items:center;color:var(--dsw-alias-label-secondary);height:28px;flex-shrink:0}\n.btw-question{flex:1;min-width:0;overflow-wrap:anywhere;font-size:13px;font-weight:500;line-height:22px;max-height:66px;overflow:auto}\n.btw-actions{display:flex;gap:4px;flex-shrink:0}\n.btw-actions button{display:grid;place-items:center;width:28px;height:28px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;flex:none;transition:background-color 120ms ease}\n.btw-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}\n.btw-actions button:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,var(--dsw-alias-label-primary));outline-offset:-2px}\n.btw-actions button.btw-action-stop{color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-primary))}\n.btw-actions button.btw-action-stop:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-primary))}\n.btw-actions button:disabled{cursor:wait;opacity:.5}\n.btw-status{display:flex;align-items:center;gap:8px;padding:0 14px 12px;color:var(--dsw-alias-label-secondary);font-size:13px}\n.btw-spinner{animation:btw-spin 1.2s linear infinite}@keyframes btw-spin{to{transform:rotate(360deg)}}\n.btw-answer{padding:0 14px 14px;max-height:300px;overflow:auto;overflow-wrap:anywhere;font-size:13px;line-height:1.7}\n.btw-answer>*:first-child{margin-top:0}.btw-answer>*:last-child{margin-bottom:0}\n.btw-answer p{margin:8px 0}.btw-answer h1,.btw-answer h2,.btw-answer h3{font-size:15px;line-height:1.5;margin:12px 0 6px;font-weight:600}\n.btw-answer pre{max-width:100%;overflow:auto;background:var(--dsw-alias-markdown-code-block);padding:10px;border-radius:8px;white-space:pre;font-size:12px}.btw-answer .katex-display{max-width:100%;overflow:auto}\n.btw-answer code{font-family:Consolas,monospace;font-size:12px}.btw-answer :not(pre)>code{background:var(--dsw-alias-markdown-code-block);border-radius:4px;padding:1px 3px}.btw-answer a{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-offset:2px;overflow-wrap:anywhere}\n.btw-answer table{display:block;max-width:100%;overflow:auto;border-collapse:collapse}.btw-answer th,.btw-answer td{border:1px solid var(--dsw-alias-border-l2);padding:5px 9px}\n.btw-answer ul,.btw-answer ol{padding-left:22px}.btw-answer blockquote{margin:8px 0;padding-left:10px;border-left:2px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-secondary)}\n.btw-error{margin:0;padding:0 14px 12px;font-size:13px;color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere}\n@media(max-width:480px){.btw-dock{max-height:330px}.btw-header{padding:6px 8px 6px 12px;gap:6px}.btw-answer{padding:0 12px 12px;max-height:230px}.btw-status,.btw-error{padding-left:12px}.btw-actions{gap:0}.btw-actions button{width:36px;height:36px}}\n@media(prefers-reduced-motion:reduce){.btw-spinner{animation:none}.btw-actions button{transition:none}}\n";
|
package/lib/types/locales.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export declare const zh: {
|
|
|
24
24
|
'action.collapse': string;
|
|
25
25
|
'action.close': string;
|
|
26
26
|
'action.retryClose': string;
|
|
27
|
+
'action.stop': string;
|
|
27
28
|
'status.answering': string;
|
|
28
29
|
'status.closing': string;
|
|
29
30
|
'command.hint': string;
|
|
@@ -34,6 +35,7 @@ export declare const zh: {
|
|
|
34
35
|
'error.attachments': string;
|
|
35
36
|
'error.removeAttachments': string;
|
|
36
37
|
'error.backend': string;
|
|
38
|
+
'error.subagent': string;
|
|
37
39
|
'error.empty': string;
|
|
38
40
|
'error.length': string;
|
|
39
41
|
'error.capacity': string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-btw",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.24",
|
|
4
4
|
"description": "DSH 一次性只读旁问插件:基于当前上下文回答,独立气泡,不执行工具 · One-shot read-only side-ask plugin: answers from current context in an independent bubble, no tool execution",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|