@deepseek-ai/dsh-client-ui-plan 0.1.6-alpha.2 → 0.1.7-alpha.1
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.i18n.yaml +2 -2
- package/README.md +7 -5
- package/README.zh.md +8 -6
- package/lib/client.js +73 -60
- package/lib/types/client/PlanCard.d.ts +22 -3
- package/lib/types/client/PlanPreview.d.ts +3 -3
- package/lib/types/client/locales.d.ts +0 -4
- package/package.json +23 -23
package/README.i18n.yaml
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
3
|
# after editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/client/ui-plan/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: e9e38251ff69ed601e486b4c1ce351b236e7bcb7
|
|
6
|
+
README.zh.md: 91fe232d27007fea8264e98c895ca2788585710c
|
package/README.md
CHANGED
|
@@ -29,13 +29,13 @@ Mount this plugin alongside `ui-conversation` and `dsh-plan-mode`; the chip then
|
|
|
29
29
|
|
|
30
30
|
### What the chip shows
|
|
31
31
|
|
|
32
|
-
While the effective target is plan mode, the seat renders the
|
|
32
|
+
While the effective target is plan mode, the seat renders the blue "Plan" status button — the plan glyph ahead of the label, swapped for a circled cross while the enabled button is hovered or keyboard-focused — which executes `/plan off`. Otherwise the seat stays empty: a host without plan mode, or a Draft with no session, shows nothing. While plan mode is the effective target, the composer textarea's placeholder switches to the plan-task hint — "describe your task to generate plan" — unless the owning surface supplies its own placeholder.
|
|
33
33
|
|
|
34
34
|
### Reading submitted plans
|
|
35
35
|
|
|
36
|
-
When a Turn ends, each submitted plan appears in its final artifact area, using the file-delivery card treatment with a Markdown icon, title, and Open action. A pending plan opens automatically once per submission in the current browser session. Closing it stays effective across review remounts; a new submission opens its own plan. Historical cards open only when clicked. Use the card or review strip’s View full plan link to read
|
|
36
|
+
When a Turn ends, each submitted plan appears in its final artifact area, using the file-delivery card treatment with a Markdown icon, title, and Open action. A pending plan opens automatically once per submission in the current browser session. Closing it stays effective across review remounts; a new submission opens its own plan. Historical cards open only when clicked. Use the card or review strip’s View full plan link to read the complete Markdown. Plan tabs show a plain text file icon. Different submissions retain separate tabs; the review buttons alone decide whether implementation may begin.
|
|
37
37
|
|
|
38
|
-
A review without a logged invocation also opens automatically. Its complete text lives only in the tab’s navigation memory, and the pending review card can reopen it. Reloading the page loses that text; an expired preview directs the user back to a pending review.
|
|
38
|
+
A review without a logged invocation also opens automatically. Its complete text lives only in the tab’s navigation memory, and the pending review card can reopen it. Reloading the page loses that text; an expired preview directs the user back to a pending review. Plans opened from an embedded child conversation use the visible sidebar while retaining the child’s address for document reads.
|
|
39
39
|
|
|
40
40
|
### Failures
|
|
41
41
|
|
|
@@ -49,9 +49,11 @@ Admission failures (`matched: false`, business errors, transport faults) surface
|
|
|
49
49
|
<details>
|
|
50
50
|
<summary>Implementation internals — click to expand</summary>
|
|
51
51
|
|
|
52
|
-
The chip occupies the conversation-declared `conversation.input.plan` single seat; the node half is an empty apply (the roster row). Reads ride the generic projection pair through the standard-kit `useProjection`: the effective target is `pending ? !active : active` — a folded host value, not client optimism, so an arriving frame corrects the chip either way. The seat's injected face carries one verb, `exitPlanMode`, which executes `/plan off` through `ctx.remote.commands.execute` and maps admission failures to an inline error line. The placeholder and hint text live in ui-conversation's `conversation` locale namespace and are shared verbatim with the claimed `/plan` command hint.
|
|
52
|
+
The chip occupies the conversation-declared `conversation.input.plan` single seat; the node half is an empty apply (the roster row). Reads ride the generic projection pair through the standard-kit `useProjection`: the effective target is `pending ? !active : active` — a folded host value, not client optimism, so an arriving frame corrects the chip either way. The seat's injected face carries one verb, `exitPlanMode`, which executes `/plan off` through `ctx.remote.commands.execute` and maps admission failures to an inline error line. The placeholder and hint text live in ui-conversation's `conversation` locale namespace and are shared verbatim with the claimed `/plan` command hint.
|
|
53
53
|
|
|
54
|
-
Plan cards derive from native `tool/call` or PTC dispatch arguments through a Conversation Definition, with each invocation’s resolved Turn location. They contribute to the additive `conversation.chat.turnTail` list alongside file deliveries. The plan resource address identifies the invocation and its complete ordinary or direct-parent subagent Session address; its provider reads existing Session history, including older pages, without storing document text in sidebar layout. The question plugin owns the review action slot and supplies its request key, complete text, and optional invocation identity. The [decision](../../../.agents/notes/implemented/feature/2026-09-17-persistent-plan-cards.md) explains why review lifetime and document lifetime remain separate.
|
|
54
|
+
Plan cards derive from native `tool/call` or PTC dispatch arguments through a Conversation Definition, with each invocation’s resolved Turn location. They contribute to the additive `conversation.chat.turnTail` list alongside file deliveries. The plan resource address identifies the invocation and its complete ordinary or direct-parent subagent Session address; its provider reads existing Session history, including older pages, without storing document text in sidebar layout. The question plugin owns the review action slot and supplies its request key, complete text, and optional invocation identity. The automatic open reads `ctx.sidebarRight.mounted` through a bound hook and runs once a seat is on screen: a review arriving while a global panel is active mounts ahead of the returning seat in the same commit, before that seat binds. The [decision](../../../.agents/notes/implemented/feature/2026-09-17-persistent-plan-cards.md) explains why review lifetime and document lifetime remain separate. Subagent plan addresses also preserve unknown mode so history reads can resolve the child descriptor.
|
|
55
|
+
|
|
56
|
+
The framework-bound `usePlans(turn)` exposes only submitted-plan data for that Turn. Chat indexes membership on Node updates and orders this collection when read; card rendering neither scans the transcript nor subscribes to other Turns or Node kinds.
|
|
55
57
|
|
|
56
58
|
</details>
|
|
57
59
|
|
package/README.zh.md
CHANGED
|
@@ -25,17 +25,17 @@ kind: "package-reference"
|
|
|
25
25
|
<a id="use-this-package"></a>
|
|
26
26
|
## 使用本包
|
|
27
27
|
|
|
28
|
-
与 `ui-conversation` 及 `dsh-plan-mode` 一起挂载本插件;plan 模式激活时,徽章随即占据 composer 的 plan 座位(访问模式控件右侧)。经 `/plan` 命令路径进入 plan 模式——从 composer 的 `+` Command
|
|
28
|
+
与 `ui-conversation` 及 `dsh-plan-mode` 一起挂载本插件;plan 模式激活时,徽章随即占据 composer 的 plan 座位(访问模式控件右侧)。经 `/plan` 命令路径进入 plan 模式——从 composer 的 `+` Command 菜单选择「计划」,或键入 `/plan`——再用徽章将其关闭。
|
|
29
29
|
|
|
30
30
|
### 徽章显示什么
|
|
31
31
|
|
|
32
|
-
当有效目标为 plan
|
|
32
|
+
当有效目标为 plan 模式时,该座位渲染蓝色「计划」状态按钮——标签前是计划图标,按钮可用且被悬停或键盘聚焦时换成圆形 ×——点击执行 `/plan off`。否则座位保持为空:未组合 plan-mode 的宿主,或尚无会话的 Draft,都不显示任何内容。plan 模式为有效目标期间,composer 文本框的 placeholder 切换为 plan 任务提示——「describe your task to generate plan」——除非所属 surface 提供自己的 placeholder。
|
|
33
33
|
|
|
34
34
|
### 查看已提交的计划
|
|
35
35
|
|
|
36
|
-
回合结束后,每次提交的计划都会显示在该回合末尾的产物区域,并采用文件产物卡片的样式,包含 Markdown
|
|
36
|
+
回合结束后,每次提交的计划都会显示在该回合末尾的产物区域,并采用文件产物卡片的样式,包含 Markdown 图标、标题和“打开”操作。在当前浏览器会话中,每份待审计划自动打开一次;关闭后,重新挂载审批组件不会再次展开,新提交会打开其对应计划。历史卡片仅在点击后打开。通过卡片或审批条带上的“查看全文”链接可阅读完整 Markdown。计划标签页显示纯文本文件图标。不同提交保留独立标签页;是否开始实施仍由审批按钮决定。
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
没有已记录调用标识的审批也会自动打开。完整正文只保存在标签页的导航内存中,待处理审批卡片可以重新打开它。刷新页面会丢失该正文;失效的预览会提示用户返回待处理审批。在嵌入式子对话中打开计划时,预览使用当前可见的侧栏,读取文档仍保留子会话地址。
|
|
39
39
|
|
|
40
40
|
### 失败
|
|
41
41
|
|
|
@@ -49,9 +49,11 @@ kind: "package-reference"
|
|
|
49
49
|
<details>
|
|
50
50
|
<summary>实现细节——点击展开</summary>
|
|
51
51
|
|
|
52
|
-
徽章占据 conversation 声明的 `conversation.input.plan` 单实例座位;node 半部是空 apply(roster 行)。读取经 standard-kit 的 `useProjection` 走通用投影对:有效目标是 `pending ? !active : active`——折叠的宿主值而非客户端乐观态,因此到达的帧无论哪个方向都会纠正徽章。座位注入面携带一个动词 `exitPlanMode`,经 `ctx.remote.commands.execute` 执行 `/plan off`,并把准入失败映射为一行内联错误。placeholder 与提示文案位于 ui-conversation 的 `conversation` locale 命名空间,与已认领 `/plan`
|
|
52
|
+
徽章占据 conversation 声明的 `conversation.input.plan` 单实例座位;node 半部是空 apply(roster 行)。读取经 standard-kit 的 `useProjection` 走通用投影对:有效目标是 `pending ? !active : active`——折叠的宿主值而非客户端乐观态,因此到达的帧无论哪个方向都会纠正徽章。座位注入面携带一个动词 `exitPlanMode`,经 `ctx.remote.commands.execute` 执行 `/plan off`,并把准入失败映射为一行内联错误。placeholder 与提示文案位于 ui-conversation 的 `conversation` locale 命名空间,与已认领 `/plan` 命令的提示逐字共用。
|
|
53
53
|
|
|
54
|
-
计划卡片通过 Conversation Definition 从原生 `tool/call` 或 PTC dispatch 参数派生,并使用每次调用已解析的回合位置。它们与文件产物一起贡献到可追加的 `conversation.chat.turnTail` 列表。计划资源地址标识调用及完整的普通会话地址或子会话直接父级地址;provider
|
|
54
|
+
计划卡片通过 Conversation Definition 从原生 `tool/call` 或 PTC dispatch 参数派生,并使用每次调用已解析的回合位置。它们与文件产物一起贡献到可追加的 `conversation.chat.turnTail` 列表。计划资源地址标识调用及完整的普通会话地址或子会话直接父级地址;provider 读取已有会话历史及较早分页,不把正文存入侧边栏布局。提问插件拥有审批操作插槽,并提供请求键、完整正文和可选的调用标识。自动打开通过绑定的 hook 读取 `ctx.sidebarRight.mounted`,在座位出现在屏幕上后才执行:全局面板打开期间到达的审批,会在返回时与座位在同一次提交里先挂载、早于座位完成绑定。[决策记录](../../../.agents/notes/implemented/feature/2026-09-17-persistent-plan-cards.zh.md)说明审批与文档为何保持独立生命周期。 子代理计划地址也保留未知模式,以便历史读取解析子 descriptor。
|
|
55
|
+
|
|
56
|
+
框架绑定的 `usePlans(turn)` 只提供该回合的已提交计划数据。Chat 随节点更新维护成员索引,并在读取时排列该集合;卡片渲染不扫描整段对话,也不订阅其他回合或节点类型。
|
|
55
57
|
|
|
56
58
|
</details>
|
|
57
59
|
|
package/lib/client.js
CHANGED
|
@@ -7,8 +7,8 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let react = require("react");
|
|
10
|
-
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
11
10
|
require("@deepseek-ai/cordis");
|
|
11
|
+
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
12
12
|
//#region ../../util/crypto/src/index.ts
|
|
13
13
|
/**
|
|
14
14
|
* Random v4 UUID, minted from `crypto.getRandomValues`.
|
|
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
|
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-plan/src/client/PlanPreview.module.css.mjs
|
|
26
|
-
const css$1 = ".k74WwW_cards{flex-direction:column;gap:10px;display:flex}.k74WwW_card{--plan-card-fill:var(--dsw-static-neutral-50);--plan-card-hover:var(--dsw-static-neutral-100);box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l1);background:var(--plan-card-fill);width:100%;min-width:0;height:60px;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;border-radius:18px;align-items:center;gap:10px;margin:0;padding:8px 10px;transition:background-color .12s;display:flex}body[data-ds-dark-theme] .k74WwW_card{--plan-card-fill:var(--dsw-static-neutral-850);--plan-card-hover:var(--dsw-static-neutral-800)}.k74WwW_card:hover{background:var(--plan-card-hover)}.k74WwW_card:focus-visible
|
|
26
|
+
const css$1 = ".k74WwW_cards{flex-direction:column;gap:10px;display:flex}.k74WwW_card{--plan-card-fill:var(--dsw-static-neutral-50);--plan-card-hover:var(--dsw-static-neutral-100);box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l1);background:var(--plan-card-fill);width:100%;min-width:0;height:60px;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;border-radius:18px;align-items:center;gap:10px;margin:0;padding:8px 10px;transition:background-color .12s;display:flex}body[data-ds-dark-theme] .k74WwW_card{--plan-card-fill:var(--dsw-static-neutral-850);--plan-card-hover:var(--dsw-static-neutral-800)}.k74WwW_card:hover{background:var(--plan-card-hover)}.k74WwW_card:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:3px}.k74WwW_cardIcon{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l1);background:var(--plan-card-fill);border-radius:10px;flex:none;place-items:center;width:40px;height:40px;display:grid}.k74WwW_cardDetails{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.k74WwW_cardTitle{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.k74WwW_cardDescription{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px;overflow:hidden}.k74WwW_cardOpen{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-button-floating-fill);border-radius:10px;flex:none;align-items:center;height:28px;padding:4px 8px;font-size:12px;line-height:18px;display:inline-flex}.k74WwW_reviewLink{color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0;display:inline-flex}.k74WwW_reviewLink:hover{color:var(--dsw-alias-label-primary)}.k74WwW_reviewLink:focus-visible{outline:2px solid var(--dsw-alias-label-primary);outline-offset:3px}.k74WwW_preview{box-sizing:border-box;height:100%;padding:20px 24px 40px;position:relative;overflow:auto}.k74WwW_document{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;font-size:14px;line-height:1.75}.k74WwW_message{color:var(--dsw-alias-label-secondary);padding:24px;font-size:14px}.k74WwW_titleIcon{flex:none}@media (width<=767px){.k74WwW_preview{padding:16px 18px 32px}}";
|
|
27
27
|
const tagId$1 = "@deepseek-ai/dsh-client-ui-plan/PlanPreview.module.css";
|
|
28
28
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
29
29
|
const tag = document.createElement("style");
|
|
@@ -41,12 +41,10 @@ window.__ModuleLoader__.load({
|
|
|
41
41
|
"cardTitle": "k74WwW_cardTitle",
|
|
42
42
|
"cards": "k74WwW_cards",
|
|
43
43
|
"document": "k74WwW_document",
|
|
44
|
-
"iconButton": "k74WwW_iconButton",
|
|
45
44
|
"message": "k74WwW_message",
|
|
46
45
|
"preview": "k74WwW_preview",
|
|
47
46
|
"reviewLink": "k74WwW_reviewLink",
|
|
48
|
-
"titleIcon": "k74WwW_titleIcon"
|
|
49
|
-
"toolbar": "k74WwW_toolbar"
|
|
47
|
+
"titleIcon": "k74WwW_titleIcon"
|
|
50
48
|
};
|
|
51
49
|
//#endregion
|
|
52
50
|
//#region lib/types/client/PlanCard.js
|
|
@@ -56,13 +54,13 @@ window.__ModuleLoader__.load({
|
|
|
56
54
|
* @param props - Logged plan, localized copy, and Session-bound navigation.
|
|
57
55
|
* @returns keyboard-accessible plan cards, or null for a Turn without plans.
|
|
58
56
|
*/
|
|
59
|
-
function PlanCards({ turn,
|
|
60
|
-
const plans =
|
|
61
|
-
if (plans.length === 0) return null;
|
|
57
|
+
function PlanCards({ turn, usePlans, openPlan, t }) {
|
|
58
|
+
const plans = usePlans(String(turn.turn));
|
|
59
|
+
if (plans === void 0 || plans.length === 0) return null;
|
|
62
60
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
63
61
|
className: PlanPreview_module_css_default.cards,
|
|
64
62
|
"data-plan-artifacts": true,
|
|
65
|
-
children: plans.map((
|
|
63
|
+
children: plans.map((plan) => (0, react_jsx_runtime.jsxs)("button", {
|
|
66
64
|
type: "button",
|
|
67
65
|
className: PlanPreview_module_css_default.card,
|
|
68
66
|
"data-plan-card": plan.callId,
|
|
@@ -98,19 +96,26 @@ window.__ModuleLoader__.load({
|
|
|
98
96
|
}
|
|
99
97
|
/**
|
|
100
98
|
* Open each pending plan automatically and retain a manual opener without answering it.
|
|
99
|
+
*
|
|
100
|
+
* The automatic open waits for a mounted Sidebar seat: a review that arrives
|
|
101
|
+
* while the Conversation is off screen mounts in the same commit as the seat,
|
|
102
|
+
* ahead of it, and the seat binds from its own effect. Reading the bound
|
|
103
|
+
* session through the hook opens once that binding exists.
|
|
101
104
|
* @param props - Review identity, Session store, localized copy, and navigation.
|
|
102
105
|
* @returns an opener for either logged or temporary plan text.
|
|
103
106
|
*/
|
|
104
|
-
function PlanReviewOpen({ review, requestKey, openReview, t, useStore, actions }) {
|
|
107
|
+
function PlanReviewOpen({ review, requestKey, openReview, useSidebarMounted, t, useStore, actions }) {
|
|
105
108
|
const identity = review.callId === void 0 ? `review:${requestKey}` : `call:${review.callId}`;
|
|
106
109
|
const opened = useStore((state) => state.opened[identity] === true);
|
|
110
|
+
const mounted = useSidebarMounted((session) => session !== void 0);
|
|
107
111
|
(0, react.useEffect)(() => {
|
|
108
|
-
if (opened) return;
|
|
112
|
+
if (opened || !mounted) return;
|
|
109
113
|
openReview(review, requestKey);
|
|
110
114
|
actions.markOpened(identity);
|
|
111
115
|
}, [
|
|
112
116
|
identity,
|
|
113
117
|
opened,
|
|
118
|
+
mounted,
|
|
114
119
|
openReview,
|
|
115
120
|
review,
|
|
116
121
|
requestKey,
|
|
@@ -124,7 +129,7 @@ window.__ModuleLoader__.load({
|
|
|
124
129
|
onClick: () => {
|
|
125
130
|
openReview(review, requestKey);
|
|
126
131
|
},
|
|
127
|
-
children: [t("preview.full"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
132
|
+
children: [t("preview.full"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, { size: 14 })]
|
|
128
133
|
});
|
|
129
134
|
}
|
|
130
135
|
//#endregion
|
|
@@ -166,7 +171,7 @@ window.__ModuleLoader__.load({
|
|
|
166
171
|
//#region lib/types/client/PlanPreview.js
|
|
167
172
|
/** Read-only Markdown viewer for logged plans and temporary review documents. */
|
|
168
173
|
/**
|
|
169
|
-
* Render the submitted plan with its complete Markdown
|
|
174
|
+
* Render the submitted plan with its complete Markdown.
|
|
170
175
|
* @param props - Framework-bound tab identity, resource, and copy.
|
|
171
176
|
* @returns the plan document or a localized loading/failure state.
|
|
172
177
|
*/
|
|
@@ -188,44 +193,33 @@ window.__ModuleLoader__.load({
|
|
|
188
193
|
role: "status",
|
|
189
194
|
children: [temporary ? t("preview.expired") : resource.status === "none" ? t("preview.unavailable") : resource.status === "failed" ? t("preview.failed") : t("preview.loading"), !temporary && resource.failure !== void 0 && (0, react_jsx_runtime.jsx)("p", { children: planFailureLine(t, resource.failure) })]
|
|
190
195
|
});
|
|
191
|
-
return (0, react_jsx_runtime.
|
|
196
|
+
return (0, react_jsx_runtime.jsx)("section", {
|
|
192
197
|
className: PlanPreview_module_css_default.preview,
|
|
193
198
|
"data-plan-preview": "callId" in plan ? plan.callId : tab.tab.navigation.address,
|
|
194
199
|
"aria-label": plan.title,
|
|
195
|
-
children:
|
|
196
|
-
className: PlanPreview_module_css_default.toolbar,
|
|
197
|
-
children: (0, react_jsx_runtime.jsx)("button", {
|
|
198
|
-
type: "button",
|
|
199
|
-
className: PlanPreview_module_css_default.iconButton,
|
|
200
|
-
"aria-label": t("copy"),
|
|
201
|
-
onClick: () => {
|
|
202
|
-
(0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(plan.markdown);
|
|
203
|
-
},
|
|
204
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {})
|
|
205
|
-
})
|
|
206
|
-
}), (0, react_jsx_runtime.jsx)("div", {
|
|
200
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
207
201
|
className: PlanPreview_module_css_default.document,
|
|
208
202
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
209
203
|
text: plan.markdown,
|
|
210
204
|
labels
|
|
211
205
|
})
|
|
212
|
-
})
|
|
206
|
+
})
|
|
213
207
|
});
|
|
214
208
|
}
|
|
215
209
|
/**
|
|
216
|
-
* Display a
|
|
210
|
+
* Display a plain file icon and the heading in its tab after resource recovery.
|
|
217
211
|
* @param props - Framework-bound tab identity and resource reader.
|
|
218
|
-
* @returns a decorative
|
|
212
|
+
* @returns a decorative file icon followed by the recovered title or initial localized label.
|
|
219
213
|
*/
|
|
220
214
|
function PlanTitle({ useTabInfo, useResource }) {
|
|
221
215
|
const tab = useTabInfo();
|
|
222
216
|
const resource = useResource(tab.tab.navigation.address);
|
|
223
217
|
const params = tab.tab.navigation.params;
|
|
224
218
|
const plan = isReviewPreviewAddress(tab.tab.navigation.address) ? params !== void 0 && "planReview" in params ? params.planReview : void 0 : resource.value;
|
|
225
|
-
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
219
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
|
|
220
|
+
kind: "other",
|
|
221
|
+
size: 16,
|
|
222
|
+
className: PlanPreview_module_css_default.titleIcon
|
|
229
223
|
}), plan?.title ?? tab.tab.title] });
|
|
230
224
|
}
|
|
231
225
|
//#endregion
|
|
@@ -295,7 +289,7 @@ window.__ModuleLoader__.load({
|
|
|
295
289
|
},
|
|
296
290
|
callId: parts[1]
|
|
297
291
|
};
|
|
298
|
-
if (parts.length === 5 && parts[0] === "subagent" && (parts[3] === "one-shot" || parts[3] === "continuable")) return {
|
|
292
|
+
if (parts.length === 5 && parts[0] === "subagent" && (parts[3] === "one-shot" || parts[3] === "continuable" || parts[3] === "unknown")) return {
|
|
299
293
|
session: {
|
|
300
294
|
kind: "subagent",
|
|
301
295
|
parentSessionId: parts[1],
|
|
@@ -477,7 +471,7 @@ window.__ModuleLoader__.load({
|
|
|
477
471
|
}
|
|
478
472
|
//#endregion
|
|
479
473
|
//#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-plan/src/client/PlanModeControl.module.css.mjs
|
|
480
|
-
const css = ".rS3zOq_wrap{align-items:center;gap:6px;display:inline-flex}.rS3zOq_chip{
|
|
474
|
+
const css = ".rS3zOq_wrap{align-items:center;gap:6px;display:inline-flex}.rS3zOq_chip{background:var(--dsw-alias-state-business-tertiary);min-width:34px;height:28px;color:var(--dsw-alias-state-business-primary);cursor:pointer;border:none;border-radius:14px;align-items:center;gap:4px;padding:0 8px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.rS3zOq_chip:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-tertiary), var(--dsw-alias-state-business-primary) 6%)}.rS3zOq_chip:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.rS3zOq_chip:disabled{opacity:.6;cursor:default}.rS3zOq_glyph{color:currentColor;flex:none;width:14px;height:14px;display:inline-flex}.rS3zOq_hoverGlyph,.rS3zOq_chip:hover:not(:disabled) .rS3zOq_restGlyph,.rS3zOq_chip:focus-visible .rS3zOq_restGlyph{display:none}.rS3zOq_chip:hover:not(:disabled) .rS3zOq_hoverGlyph,.rS3zOq_chip:focus-visible .rS3zOq_hoverGlyph{display:block}.rS3zOq_error{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}";
|
|
481
475
|
const tagId = "@deepseek-ai/dsh-client-ui-plan/PlanModeControl.module.css";
|
|
482
476
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
483
477
|
const tag = document.createElement("style");
|
|
@@ -488,8 +482,10 @@ window.__ModuleLoader__.load({
|
|
|
488
482
|
}
|
|
489
483
|
var PlanModeControl_module_css_default = {
|
|
490
484
|
"chip": "rS3zOq_chip",
|
|
491
|
-
"close": "rS3zOq_close",
|
|
492
485
|
"error": "rS3zOq_error",
|
|
486
|
+
"glyph": "rS3zOq_glyph",
|
|
487
|
+
"hoverGlyph": "rS3zOq_hoverGlyph",
|
|
488
|
+
"restGlyph": "rS3zOq_restGlyph",
|
|
493
489
|
"wrap": "rS3zOq_wrap"
|
|
494
490
|
};
|
|
495
491
|
//#endregion
|
|
@@ -534,11 +530,17 @@ window.__ModuleLoader__.load({
|
|
|
534
530
|
title: t("chip.on.title"),
|
|
535
531
|
disabled: locked || leaving,
|
|
536
532
|
onClick: off,
|
|
537
|
-
children: [
|
|
538
|
-
className: PlanModeControl_module_css_default.
|
|
533
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
534
|
+
className: PlanModeControl_module_css_default.glyph,
|
|
539
535
|
"aria-hidden": true,
|
|
540
|
-
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
541
|
-
|
|
536
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlanOutlineRegular, {
|
|
537
|
+
className: PlanModeControl_module_css_default.restGlyph,
|
|
538
|
+
size: 14
|
|
539
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseCircleFillRegular, {
|
|
540
|
+
className: PlanModeControl_module_css_default.hoverGlyph,
|
|
541
|
+
size: 14
|
|
542
|
+
})]
|
|
543
|
+
}), t("chip.label")]
|
|
542
544
|
}), error !== null && (0, react_jsx_runtime.jsx)("span", {
|
|
543
545
|
className: PlanModeControl_module_css_default.error,
|
|
544
546
|
role: "status",
|
|
@@ -552,7 +554,7 @@ window.__ModuleLoader__.load({
|
|
|
552
554
|
/** `plan` namespace dictionaries (the composer plan chip's copy). */
|
|
553
555
|
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
554
556
|
const zh = {
|
|
555
|
-
"chip.label": "
|
|
557
|
+
"chip.label": "计划",
|
|
556
558
|
"preview.title": "计划",
|
|
557
559
|
"preview.document": "计划 · Markdown",
|
|
558
560
|
"preview.action": "打开",
|
|
@@ -566,11 +568,9 @@ window.__ModuleLoader__.load({
|
|
|
566
568
|
"preview.notFound": "未找到这份计划",
|
|
567
569
|
"preview.unavailable": "计划预览不可用",
|
|
568
570
|
"preview.expired": "临时计划预览已失效,请从仍在等待审批的卡片重新打开。",
|
|
569
|
-
"chip.on.aria": "
|
|
570
|
-
"chip.on.title": "
|
|
571
|
-
"chip.
|
|
572
|
-
"chip.off.title": "plan mode 已关闭 — 点击开启(/plan)",
|
|
573
|
-
"chip.exitFailed": "退出 plan mode 失败"
|
|
571
|
+
"chip.on.aria": "计划模式已开启,按下关闭",
|
|
572
|
+
"chip.on.title": "计划模式已开启 — 点击关闭(/plan off)",
|
|
573
|
+
"chip.exitFailed": "退出计划模式失败"
|
|
574
574
|
};
|
|
575
575
|
/** English dictionary, checked complete against the zh key set. */
|
|
576
576
|
const en = {
|
|
@@ -590,8 +590,6 @@ window.__ModuleLoader__.load({
|
|
|
590
590
|
"preview.expired": "This temporary plan preview has expired. Reopen it from the pending review card.",
|
|
591
591
|
"chip.on.aria": "Plan mode on, press to turn off",
|
|
592
592
|
"chip.on.title": "Plan mode on — click to turn off (/plan off)",
|
|
593
|
-
"chip.off.aria": "Plan mode off, press to turn on",
|
|
594
|
-
"chip.off.title": "Plan mode off — click to turn on (/plan)",
|
|
595
593
|
"chip.exitFailed": "Failed to exit plan mode"
|
|
596
594
|
};
|
|
597
595
|
//#endregion
|
|
@@ -641,7 +639,7 @@ window.__ModuleLoader__.load({
|
|
|
641
639
|
kind: "subagent",
|
|
642
640
|
...child
|
|
643
641
|
};
|
|
644
|
-
ctx.sidebarRight.
|
|
642
|
+
ctx.sidebarRight.openResource(planAddress({
|
|
645
643
|
session,
|
|
646
644
|
callId
|
|
647
645
|
}));
|
|
@@ -652,23 +650,38 @@ window.__ModuleLoader__.load({
|
|
|
652
650
|
name: "conversation.chat.turnTail",
|
|
653
651
|
id: previewId,
|
|
654
652
|
locale: NS,
|
|
655
|
-
inject:
|
|
653
|
+
inject: (sessionId) => {
|
|
654
|
+
const binding = ctx.sessions.binding(sessionId);
|
|
655
|
+
if (binding === void 0) throw new Error(`ui-plan: unknown session "${sessionId}"`);
|
|
656
|
+
const chat = ctx.uiConversation.binding(binding).target("chat");
|
|
657
|
+
return {
|
|
658
|
+
...open(sessionId),
|
|
659
|
+
keyedHooks: { plans: (turn) => {
|
|
660
|
+
const snapshot = chat.getSnapshot();
|
|
661
|
+
if (snapshot === void 0) throw new Error("ui-plan: Chat target is unavailable");
|
|
662
|
+
return snapshot.nodes.turnDataSource(Number(turn), "submitted-plan");
|
|
663
|
+
} }
|
|
664
|
+
};
|
|
665
|
+
}
|
|
656
666
|
}, PlanCards));
|
|
657
667
|
ctx.slots.inject("conversation.plan-review.actions", () => ctx.slots.register({
|
|
658
668
|
name: "conversation.plan-review.actions",
|
|
659
669
|
id: previewId,
|
|
660
670
|
locale: NS,
|
|
661
671
|
store: reviewStore,
|
|
662
|
-
inject: (sessionId) => ({
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
+
inject: (sessionId) => ({
|
|
673
|
+
openReview: (review, requestKey) => {
|
|
674
|
+
if (review.callId !== void 0) {
|
|
675
|
+
open(sessionId).openPlan(review.callId);
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
ctx.sidebarRight.openResource(reviewPreviewAddress(sessionId, `${reviewWindow}:${requestKey}`), { params: { planReview: {
|
|
679
|
+
markdown: review.plan,
|
|
680
|
+
title: (0, _deepseek_ai_dsh_client_ui_primitives.extractMarkdownPlainText)(review.plan, { mode: "first-line" })
|
|
681
|
+
} } });
|
|
682
|
+
},
|
|
683
|
+
hooks: { sidebarMounted: ctx.sidebarRight.mounted }
|
|
684
|
+
})
|
|
672
685
|
}, PlanReviewOpen));
|
|
673
686
|
ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
|
|
674
687
|
name: "sidebar.right.pane.tab",
|
|
@@ -1,26 +1,45 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store';
|
|
2
|
+
import type { SubmittedPlan } from './plan.ts';
|
|
3
|
+
import type { HostObservable, InjectFace, PropsLocale, PropsRuntime, PropsStore } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
4
|
import type { ToolCallId } from '@deepseek-ai/dsh-llm/brand';
|
|
5
|
+
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
3
6
|
import type { createPlanReviewStore } from './review-store.ts';
|
|
4
7
|
/** Session-bound navigation for logged plans. */
|
|
5
8
|
export interface PlanOpenInjected {
|
|
6
9
|
/** Open or focus the exact submitted plan. */
|
|
7
10
|
openPlan: (callId: ToolCallId) => void;
|
|
8
11
|
}
|
|
12
|
+
/** Turn-keyed submitted plans and Session-bound navigation. */
|
|
13
|
+
export interface PlanCardsInjected extends PlanOpenInjected {
|
|
14
|
+
keyedHooks: {
|
|
15
|
+
/** Resolve only this Turn's submitted plans, in invocation order. */
|
|
16
|
+
plans: (turn: string) => ObservableSnapshot<readonly SubmittedPlan[]>;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
9
19
|
/** Session-bound preview navigation for one pending review. */
|
|
10
20
|
export interface PlanReviewOpenInjected {
|
|
11
21
|
/** Open the logged plan, or the request's temporary document when no invocation exists. */
|
|
12
22
|
openReview: (review: PropsRuntime<'conversation.plan-review.actions'>['review'], requestKey: string) => void;
|
|
23
|
+
readonly hooks: {
|
|
24
|
+
/** The session whose right Sidebar seat is mounted; `undefined` while none is on screen. */
|
|
25
|
+
readonly sidebarMounted: HostObservable<SessionId | undefined>;
|
|
26
|
+
};
|
|
13
27
|
}
|
|
14
28
|
/**
|
|
15
29
|
* Render the completed Turn's submitted plans in invocation order.
|
|
16
30
|
* @param props - Logged plan, localized copy, and Session-bound navigation.
|
|
17
31
|
* @returns keyboard-accessible plan cards, or null for a Turn without plans.
|
|
18
32
|
*/
|
|
19
|
-
export declare function PlanCards({ turn,
|
|
33
|
+
export declare function PlanCards({ turn, usePlans, openPlan, t }: PropsRuntime<'conversation.chat.turnTail'> & InjectFace<PlanCardsInjected> & PropsLocale<'plan'>): import("react").JSX.Element | null;
|
|
20
34
|
/**
|
|
21
35
|
* Open each pending plan automatically and retain a manual opener without answering it.
|
|
36
|
+
*
|
|
37
|
+
* The automatic open waits for a mounted Sidebar seat: a review that arrives
|
|
38
|
+
* while the Conversation is off screen mounts in the same commit as the seat,
|
|
39
|
+
* ahead of it, and the seat binds from its own effect. Reading the bound
|
|
40
|
+
* session through the hook opens once that binding exists.
|
|
22
41
|
* @param props - Review identity, Session store, localized copy, and navigation.
|
|
23
42
|
* @returns an opener for either logged or temporary plan text.
|
|
24
43
|
*/
|
|
25
|
-
export declare function PlanReviewOpen({ review, requestKey, openReview, t, useStore, actions }: PropsRuntime<'conversation.plan-review.actions'> & InjectFace<PlanReviewOpenInjected> & PropsLocale<'plan'> & PropsStore<ReturnType<typeof createPlanReviewStore>>): import("react").JSX.Element;
|
|
44
|
+
export declare function PlanReviewOpen({ review, requestKey, openReview, useSidebarMounted, t, useStore, actions }: PropsRuntime<'conversation.plan-review.actions'> & InjectFace<PlanReviewOpenInjected> & PropsLocale<'plan'> & PropsStore<ReturnType<typeof createPlanReviewStore>>): import("react").JSX.Element;
|
|
26
45
|
//# sourceMappingURL=PlanCard.d.ts.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
2
2
|
type PlanPreviewProps = PropsRuntime<'sidebar.right.pane.tab'> & PropsLocale<'plan'>;
|
|
3
3
|
/**
|
|
4
|
-
* Render the submitted plan with its complete Markdown
|
|
4
|
+
* Render the submitted plan with its complete Markdown.
|
|
5
5
|
* @param props - Framework-bound tab identity, resource, and copy.
|
|
6
6
|
* @returns the plan document or a localized loading/failure state.
|
|
7
7
|
*/
|
|
8
8
|
export declare function PlanPreview({ useTabInfo, useResource, t }: PlanPreviewProps): import("react").JSX.Element;
|
|
9
9
|
/**
|
|
10
|
-
* Display a
|
|
10
|
+
* Display a plain file icon and the heading in its tab after resource recovery.
|
|
11
11
|
* @param props - Framework-bound tab identity and resource reader.
|
|
12
|
-
* @returns a decorative
|
|
12
|
+
* @returns a decorative file icon followed by the recovered title or initial localized label.
|
|
13
13
|
*/
|
|
14
14
|
export declare function PlanTitle({ useTabInfo, useResource }: PropsRuntime<'sidebar.right.pane.tab.title'>): import("react").JSX.Element;
|
|
15
15
|
export {};
|
|
@@ -17,8 +17,6 @@ export declare const zh: {
|
|
|
17
17
|
'preview.expired': string;
|
|
18
18
|
'chip.on.aria': string;
|
|
19
19
|
'chip.on.title': string;
|
|
20
|
-
'chip.off.aria': string;
|
|
21
|
-
'chip.off.title': string;
|
|
22
20
|
'chip.exitFailed': string;
|
|
23
21
|
};
|
|
24
22
|
/** The plan namespace key union. */
|
|
@@ -41,8 +39,6 @@ export declare const en: {
|
|
|
41
39
|
'preview.expired': string;
|
|
42
40
|
'chip.on.aria': string;
|
|
43
41
|
'chip.on.title': string;
|
|
44
|
-
'chip.off.aria': string;
|
|
45
|
-
'chip.off.title': string;
|
|
46
42
|
'chip.exitFailed': string;
|
|
47
43
|
};
|
|
48
44
|
//# sourceMappingURL=locales.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-plan",
|
|
3
3
|
"description": "Plan mode controls, persistent transcript plan cards, and sidebar Markdown previews",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.7-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -42,32 +42,32 @@
|
|
|
42
42
|
},
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
45
|
+
"@deepseek-ai/cordis": "^4.0.3"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/react": "~18.3.1",
|
|
49
49
|
"react": "^18.2.0",
|
|
50
|
-
"@deepseek-ai/dsh-
|
|
51
|
-
"@deepseek-ai/dsh-
|
|
52
|
-
"@deepseek-ai/dsh-client-
|
|
53
|
-
"@deepseek-ai/dsh-client-
|
|
54
|
-
"@deepseek-ai/dsh-client-ui-
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
-
"@deepseek-ai/dsh-client-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/
|
|
59
|
-
"@deepseek-ai/dsh-
|
|
60
|
-
"@deepseek-ai/dsh-client-ui-
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-
|
|
64
|
-
"@deepseek-ai/dsh-client-ui-
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
66
|
-
"@deepseek-ai/dsh-
|
|
67
|
-
"@deepseek-ai/dsh-
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
"@deepseek-ai/
|
|
50
|
+
"@deepseek-ai/dsh-api-remotes": "^0.1.7-alpha.1",
|
|
51
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.7-alpha.1",
|
|
52
|
+
"@deepseek-ai/dsh-client-store": "^0.1.7-alpha.1",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.7-alpha.1",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-alpha.1",
|
|
55
|
+
"@deepseek-ai/dsh-plan-mode": "^0.1.7-alpha.1",
|
|
56
|
+
"@deepseek-ai/dsh-client-test-runtime": "^0.1.7-alpha.1",
|
|
57
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.7-alpha.1",
|
|
58
|
+
"@deepseek-ai/cordis": "^4.0.3",
|
|
59
|
+
"@deepseek-ai/dsh-session": "^0.1.7-alpha.1",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-renderer": "^0.1.7-alpha.1",
|
|
61
|
+
"@deepseek-ai/dsh-client-ui-session": "^0.1.7-alpha.1",
|
|
62
|
+
"@deepseek-ai/dsh-api-session-controller": "^0.1.7-alpha.1",
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-chat": "^0.1.7-alpha.1",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.7-alpha.1",
|
|
65
|
+
"@deepseek-ai/dsh-client-ui-user-questions": "^0.1.7-alpha.1",
|
|
66
|
+
"@deepseek-ai/dsh-client-resources": "^0.1.7-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-typert-protocol": "^0.1.7-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-util-crypto": "^0.1.7-alpha.1"
|
|
71
71
|
},
|
|
72
72
|
"files": [
|
|
73
73
|
"lib/index.js",
|