@prettier-ai/dsh-client-ui-workflow-run 0.1.2-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/LICENSE +21 -0
- package/README.i18n.yaml +6 -0
- package/README.md +100 -0
- package/README.zh.md +100 -0
- package/lib/client.js +649 -0
- package/lib/index.js +6 -0
- package/lib/invariant.js +17 -0
- package/lib/types/client/WorkflowRunPanel.d.ts +11 -0
- package/lib/types/client/index.d.ts +14 -0
- package/lib/types/client/locales.d.ts +29 -0
- package/lib/types/client/workflow-definition.d.ts +50 -0
- package/lib/types/index.d.ts +4 -0
- package/lib/types/invariant.d.ts +9 -0
- package/package.json +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/client/ui-workflow-run/README.md
|
|
5
|
+
README.md: 1cf482bb8f9d0f8c41e82a639fa6cb656f5fd563
|
|
6
|
+
README.zh.md: 2b559c666b1ea00374717b9f401ea02113459ac6
|
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Durable workflow-run Conversation Node for the dsh web client: reconstructs top-level workflow runs as independent chat nodes with nested member disclosure."
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-client-ui-workflow-run
|
|
7
|
+
|
|
8
|
+
English | [中文](README.zh.md)
|
|
9
|
+
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-client-ui-workflow-run` is the browser plugin that reconstructs durable top-level workflow runs as independent Chat nodes in the dsh web client. It consumes the four `tool-workflow/*` Session events owned by `dsh-tool-workflow`, registers one `ConversationNodeDefinition`, and renders through the keyed `conversation.chat.node` slot without changing the existing workflow tool card. The run and each phase are controlled disclosures: a mount opens running, failed, cancelled, and interrupted levels and closes fully completed levels, and users can toggle either level with the full row, Enter, or Space. A member opens a child Session only while every current fact agrees, and the node shows run, phase, member identity, and status only.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Use this package](#use-this-package)
|
|
17
|
+
- [Understand the implementation](#understand-the-implementation)
|
|
18
|
+
- [Further Exploration](#further-exploration)
|
|
19
|
+
- [Model Experience](#model-experience)
|
|
20
|
+
- [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
|
|
21
|
+
- [Dev Note](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
A top-level workflow run through `dsh-tool-workflow` appears in the conversation as its own node: expand the run to see its phases, and expand a phase to see its members. Phase groups come only from members that started, and settlement changes status without removing or reordering members.
|
|
29
|
+
|
|
30
|
+
### Navigating the node
|
|
31
|
+
|
|
32
|
+
The run uses a 32-pixel row with persistent chevrons, an inline state dot, and status text; phases use disclosure rows with title and member count in the main area and a fixed aggregate-status tail; members use a 16-pixel dot slot, a truncating name area, and a fixed status column. Opening a member's child Session requires the member to be running, the child id to be in the ordinary Session list, the row to have `origin: 'subagent'`, its `parentId` to be the current Session, and the list row to still be running — remote, addressed-only, wrong-parent, or terminal rows remain non-interactive.
|
|
33
|
+
|
|
34
|
+
### State and completion
|
|
35
|
+
|
|
36
|
+
Completion updates the visible status immediately but delays its automatic close while focus remains inside the content. A closed Turn or Step with missing terminal events presents the affected run or members as interrupted without changing the tool result.
|
|
37
|
+
|
|
38
|
+
-----
|
|
39
|
+
|
|
40
|
+
<a id="understand-the-implementation"></a>
|
|
41
|
+
## Understand the implementation
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>Implementation internals — click to expand</summary>
|
|
45
|
+
|
|
46
|
+
The node is a deterministic replay of durable session events: `tool-workflow/run-start` creates one Context keyed by `runId`, and member starts, member endings, and the run ending update that Context in log order. A history tail containing only updates remains pending until an older page supplies the unique start, after which prepend, complete replay, and live append produce the same state.
|
|
47
|
+
|
|
48
|
+
### Disclosure choices
|
|
49
|
+
|
|
50
|
+
Ordinary running updates preserve the current choice, the first abnormal edge opens once, normal completion closes once, and a completed phase plus the outer run open again when a new running member starts under the same phase key. If an entire new clean cycle arrives in one render while the run remains active, the phase finishes folded but the outer run opens once to expose its updated summary. `WorkflowRunPanel` owns the phase choices, so closing and reopening the outer run does not reset them; a renderer remount reconstructs every initial choice from durable facts.
|
|
51
|
+
|
|
52
|
+
### Composition
|
|
53
|
+
|
|
54
|
+
The package registers its Definition, locale dictionary, and `workflow-run` renderer as Cordis effects; removing the client entry retracts all three contributions. The shipped Web bundle includes the plugin after `ui-conversation` and `ui-tool`.
|
|
55
|
+
|
|
56
|
+
</details>
|
|
57
|
+
|
|
58
|
+
-----
|
|
59
|
+
|
|
60
|
+
<a id="further-exploration"></a>
|
|
61
|
+
## Further Exploration
|
|
62
|
+
|
|
63
|
+
These pages cover the tool seam, the conversation host, and the tool presentation layer.
|
|
64
|
+
|
|
65
|
+
- [tool-workflow](../../workflow/tool-workflow/README.md) — the tool that owns the four `tool-workflow/*` Session events.
|
|
66
|
+
- [ui-conversation](../ui-conversation/README.md) — the chat surface hosting the `conversation.chat.node` slot.
|
|
67
|
+
- [ui-tool](../ui-tool/README.md) — the tool-call presentation layer this node sits beside.
|
|
68
|
+
- [Conversation subsystem](../../../docs/subsystems/conversation.md) — how a business-owned feature registers a Conversation node.
|
|
69
|
+
|
|
70
|
+
-----
|
|
71
|
+
|
|
72
|
+
<a id="model-experience"></a>
|
|
73
|
+
## Model Experience
|
|
74
|
+
|
|
75
|
+
None, as the package is a browser-side UI plugin layer that renders durable workflow records without changing model context.
|
|
76
|
+
|
|
77
|
+
#### KV Cache effect
|
|
78
|
+
|
|
79
|
+
None; this package neither assembles nor sends a provider request.
|
|
80
|
+
|
|
81
|
+
## Known Limitations and Deferred Work
|
|
82
|
+
|
|
83
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
These limits define which runs produce records and what the node exposes; they are current package constraints.
|
|
87
|
+
|
|
88
|
+
- **Only top-level calls through `dsh-tool-workflow` produce these records** — nested PTC mode calls and direct `WorkflowEngine` consumers do not.
|
|
89
|
+
- **Navigation is intentionally live-only** — terminal members remain visible for review but never expose a cold-session opener from this node.
|
|
90
|
+
- **The node shows run, phase, member identity, and status only** — scripts, outputs, errors, logs, usage, static topology, and controls remain outside this surface.
|
|
91
|
+
|
|
92
|
+
<a id="dev-note"></a>
|
|
93
|
+
### Dev Note
|
|
94
|
+
|
|
95
|
+
<details>
|
|
96
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
97
|
+
|
|
98
|
+
None.
|
|
99
|
+
|
|
100
|
+
</details>
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "dsh Web 客户端的持久化工作流运行 Conversation Node:把顶层工作流运行重建为带嵌套成员折叠的独立聊天节点。"
|
|
3
|
+
kind: "package-reference"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @deepseek-ai/dsh-client-ui-workflow-run
|
|
7
|
+
|
|
8
|
+
[English](README.md) | 中文
|
|
9
|
+
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-client-ui-workflow-run` 是浏览器插件,把持久化的顶层工作流运行重建为 dsh Web 客户端中的独立 Chat 节点。它消费由 `dsh-tool-workflow` 拥有的四类 `tool-workflow/*` Session 事件,注册一个 `ConversationNodeDefinition`,并通过 keyed `conversation.chat.node` slot 渲染,不改变现有工作流工具卡。运行与每个阶段都是受控 disclosure:挂载时运行中、失败、已取消与已中断层级默认展开,全部完成的层级默认折叠,用户可以点击整行或按 Enter、Space 切换任一层级。只有当所有实时事实同时成立时,成员才可打开子 Session;节点只显示运行、阶段、成员身份与状态。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
22
|
+
|
|
23
|
+
-----
|
|
24
|
+
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
经 `dsh-tool-workflow` 发起的顶层工作流运行会在对话中显示为独立节点:展开运行查看其阶段,展开阶段查看其成员。阶段组只来自开始过的成员;成员结算只改变状态,不删除或重排成员。
|
|
29
|
+
|
|
30
|
+
### 导航节点
|
|
31
|
+
|
|
32
|
+
运行使用 32 像素行,带常驻 chevron、行内状态点与状态文字;阶段使用 disclosure 行,在主区显示标题与成员数、在固定尾部显示聚合状态;成员使用 16 像素状态点槽、可省略名称区与固定状态列。打开成员的子 Session 需要成员仍在运行、子 id 位于普通 Session 列表、列表行为 `origin: 'subagent'`、`parentId` 等于当前 Session,且列表行仍标记运行——远程、仅地址化、父级不符或终态的行都不可交互。
|
|
33
|
+
|
|
34
|
+
### 状态与完成
|
|
35
|
+
|
|
36
|
+
完成状态会立即更新,但只要焦点仍位于展开内容内,自动折叠就会等待焦点离开。若所属 Turn 或 Step 已关闭但终点事件缺失,界面把相应运行或成员显示为已中断,而不改写工具结果。
|
|
37
|
+
|
|
38
|
+
-----
|
|
39
|
+
|
|
40
|
+
<a id="understand-the-implementation"></a>
|
|
41
|
+
## 理解实现
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary>实现细节——点击展开</summary>
|
|
45
|
+
|
|
46
|
+
节点是持久化会话事件的确定性回放:`tool-workflow/run-start` 以 `runId` 创建唯一 Context,成员开始、成员结束与运行结束事件按日志顺序更新该 Context。只有 update 的历史尾页会保持 pending,直到更早页面补入唯一 start;此后 prepend、完整回放与实时 append 得到相同状态。
|
|
47
|
+
|
|
48
|
+
### 展开选择
|
|
49
|
+
|
|
50
|
+
普通运行更新保留当前选择,首次异常边沿只自动展开一次,正常完成只自动折叠一次;已完成阶段在同一 phase key 下开始新的运行成员时,该 Phase 与外层运行会再次自动展开。若一个完整的新干净周期在同一次渲染中送达且运行仍处于活动状态,Phase 保持折叠,但外层运行会自动展开一次以展示更新后的摘要。Phase 选择由 `WorkflowRunPanel` 持有,因此关闭并重新打开外层运行不会重置它们;renderer remount 会从持久事实重建每层的初始选择。
|
|
51
|
+
|
|
52
|
+
### 装配
|
|
53
|
+
|
|
54
|
+
本包把 Definition、locale 字典与 `workflow-run` renderer 都注册为 Cordis effect;移除客户端 entry 会撤销三者。shipped Web bundle 在 `ui-conversation` 与 `ui-tool` 之后装配该插件。
|
|
55
|
+
|
|
56
|
+
</details>
|
|
57
|
+
|
|
58
|
+
-----
|
|
59
|
+
|
|
60
|
+
<a id="further-exploration"></a>
|
|
61
|
+
## 进一步探索
|
|
62
|
+
|
|
63
|
+
以下页面覆盖工具 seam、对话宿主与工具展示层。
|
|
64
|
+
|
|
65
|
+
- [tool-workflow](../../workflow/tool-workflow/README.zh.md)——拥有四类 `tool-workflow/*` Session 事件的工具。
|
|
66
|
+
- [ui-conversation](../ui-conversation/README.zh.md)——承载 `conversation.chat.node` slot 的聊天界面。
|
|
67
|
+
- [ui-tool](../ui-tool/README.zh.md)——本节点相邻的工具调用展示层。
|
|
68
|
+
- [Conversation 子系统](../../../docs/subsystems/conversation.zh.md)——业务自有功能如何注册 Conversation node。
|
|
69
|
+
|
|
70
|
+
-----
|
|
71
|
+
|
|
72
|
+
<a id="model-experience"></a>
|
|
73
|
+
## 模型体验
|
|
74
|
+
|
|
75
|
+
无。该包是浏览器端 UI 插件层,只渲染持久化工作流记录,不改变模型上下文。
|
|
76
|
+
|
|
77
|
+
#### KV Cache 影响
|
|
78
|
+
|
|
79
|
+
无;该包既不组装也不发送提供方请求。
|
|
80
|
+
|
|
81
|
+
## 已知限制与延期工作
|
|
82
|
+
|
|
83
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
这些限制定义哪些运行会产生记录、节点暴露什么;它们是当前包约束。
|
|
87
|
+
|
|
88
|
+
- **只有经 `dsh-tool-workflow` 发起的顶层调用会生成这些记录**:嵌套 PTC mode 调用和直接 `WorkflowEngine` 消费方不会生成。
|
|
89
|
+
- **导航刻意只面向实时运行**:终态成员继续保留供复盘,但本节点永不为其提供冷 Session 入口。
|
|
90
|
+
- **节点只显示运行、阶段、成员身份与状态**:脚本、输出、错误、日志、用量、静态拓扑与控制操作都不属于本界面。
|
|
91
|
+
|
|
92
|
+
<a id="dev-note"></a>
|
|
93
|
+
### 开发备注
|
|
94
|
+
|
|
95
|
+
<details>
|
|
96
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
97
|
+
|
|
98
|
+
无。
|
|
99
|
+
|
|
100
|
+
</details>
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@prettier-ai/dsh-client-ui-workflow-run",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
|
+
let react = require("react");
|
|
9
|
+
let _prettier_ai_dsh_client_ui_primitives = require("@prettier-ai/dsh-client-ui-primitives");
|
|
10
|
+
let _prettier_ai_dsh_client_store = require("@prettier-ai/dsh-client-store");
|
|
11
|
+
//#region \0dsh-css:/home/runner/work/dsh-publisher/dsh-publisher/upstream/packages/client/ui-workflow-run/src/client/WorkflowRunPanel.module.css.mjs
|
|
12
|
+
const css = ".KFKxAq_root{width:100%;min-width:0}.KFKxAq_runHeader{box-sizing:border-box;background:var(--dsw-alias-bg-module-platform);border-radius:8px;align-items:center;gap:6px;width:100%;min-width:0;height:32px;padding:0 8px;display:flex}.KFKxAq_runHeader:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.KFKxAq_runLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:0;display:inline-flex}.KFKxAq_runTitle{max-width:42%;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);font-weight:510;line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:none;overflow:hidden}.KFKxAq_runSummary{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(18px + var(--dsh-content-font-delta-secondary,0px));text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.KFKxAq_statusTail{height:20px;color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none;align-items:center;gap:4px;font-size:11px;font-weight:510;line-height:16px;display:inline-flex;overflow:hidden}.KFKxAq_phaseHeader{box-sizing:border-box;align-items:center;gap:6px;width:100%;min-width:0;height:32px;display:flex}.KFKxAq_phaseHeader:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px;border-radius:4px}.KFKxAq_phaseLeading{width:calc(16px + var(--dsh-content-font-delta,0px));height:calc(16px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;margin-right:0;display:inline-flex}.KFKxAq_phaseTitle{min-width:0;max-width:42%;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:0 auto;overflow:hidden}.KFKxAq_phaseCount{min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.KFKxAq_phaseStatus{width:calc(132px + var(--dsh-content-font-delta-secondary,0px) * 10);color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));text-align:right;text-overflow:ellipsis;white-space:nowrap;flex:none;overflow:hidden}.KFKxAq_separator{background:var(--dsw-alias-label-tertiary);border-radius:50%;flex:none;width:2px;height:2px}.KFKxAq_phaseList{flex-direction:column;gap:4px;min-width:0;padding:4px 0 0 16px;display:flex}.KFKxAq_phase{min-width:0}.KFKxAq_members{flex-direction:column;gap:2px;min-width:0;padding:0 0 0 16px;display:flex}.KFKxAq_memberRow,.KFKxAq_memberButton{width:100%;min-width:0;min-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-secondary);font:inherit;text-align:left;background:0 0;border:0;border-radius:4px;align-items:center;gap:12px;padding:0;display:flex}.KFKxAq_memberButton{cursor:pointer}.KFKxAq_memberButton .KFKxAq_memberLabel{color:var(--dsw-alias-state-business-primary);text-underline-position:from-font;text-decoration:underline}.KFKxAq_dotSlot{width:16px;height:calc(24px + var(--dsh-content-font-delta,0px));flex:none;justify-content:center;align-items:center;display:inline-flex;overflow:hidden}.KFKxAq_memberButton:focus-visible{outline:none}.KFKxAq_memberButton:focus-visible .KFKxAq_memberLabelWrap{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.KFKxAq_memberLabelWrap{min-width:0;height:calc(24px + var(--dsh-content-font-delta,0px));border-radius:4px;flex:1;align-items:center;padding:0 2px;display:flex;overflow:hidden}.KFKxAq_memberLabel{min-width:0;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size,14px);line-height:calc(24px + var(--dsh-content-font-delta,0px));text-overflow:ellipsis;white-space:nowrap;flex:1;overflow:hidden}.KFKxAq_memberStatus{width:64px;color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));text-align:right;text-overflow:ellipsis;white-space:nowrap;flex:none;overflow:hidden}.KFKxAq_empty{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));padding:0}@media (width<=560px){.KFKxAq_phaseList,.KFKxAq_members{padding-left:12px}}";
|
|
13
|
+
const tagId = "@prettier-ai/dsh-client-ui-workflow-run/WorkflowRunPanel.module.css";
|
|
14
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
15
|
+
const tag = document.createElement("style");
|
|
16
|
+
tag.dataset.plugin = "@prettier-ai/dsh-client-ui-workflow-run";
|
|
17
|
+
tag.dataset.pluginCss = tagId;
|
|
18
|
+
tag.textContent = css;
|
|
19
|
+
document.head.appendChild(tag);
|
|
20
|
+
}
|
|
21
|
+
var WorkflowRunPanel_module_css_default = {
|
|
22
|
+
"dotSlot": "KFKxAq_dotSlot",
|
|
23
|
+
"empty": "KFKxAq_empty",
|
|
24
|
+
"memberButton": "KFKxAq_memberButton",
|
|
25
|
+
"memberLabel": "KFKxAq_memberLabel",
|
|
26
|
+
"memberLabelWrap": "KFKxAq_memberLabelWrap",
|
|
27
|
+
"memberRow": "KFKxAq_memberRow",
|
|
28
|
+
"memberStatus": "KFKxAq_memberStatus",
|
|
29
|
+
"members": "KFKxAq_members",
|
|
30
|
+
"phase": "KFKxAq_phase",
|
|
31
|
+
"phaseCount": "KFKxAq_phaseCount",
|
|
32
|
+
"phaseHeader": "KFKxAq_phaseHeader",
|
|
33
|
+
"phaseLeading": "KFKxAq_phaseLeading",
|
|
34
|
+
"phaseList": "KFKxAq_phaseList",
|
|
35
|
+
"phaseStatus": "KFKxAq_phaseStatus",
|
|
36
|
+
"phaseTitle": "KFKxAq_phaseTitle",
|
|
37
|
+
"root": "KFKxAq_root",
|
|
38
|
+
"runHeader": "KFKxAq_runHeader",
|
|
39
|
+
"runLeading": "KFKxAq_runLeading",
|
|
40
|
+
"runSummary": "KFKxAq_runSummary",
|
|
41
|
+
"runTitle": "KFKxAq_runTitle",
|
|
42
|
+
"separator": "KFKxAq_separator",
|
|
43
|
+
"statusTail": "KFKxAq_statusTail"
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region lib/types/client/WorkflowRunPanel.js
|
|
47
|
+
const STATUS_KEYS = {
|
|
48
|
+
running: "status.running",
|
|
49
|
+
completed: "status.completed",
|
|
50
|
+
failed: "status.failed",
|
|
51
|
+
cancelled: "status.cancelled",
|
|
52
|
+
interrupted: "status.interrupted"
|
|
53
|
+
};
|
|
54
|
+
function dotState(status) {
|
|
55
|
+
switch (status) {
|
|
56
|
+
case "running": return "ongoing";
|
|
57
|
+
case "completed": return "done";
|
|
58
|
+
case "failed": return "error";
|
|
59
|
+
case "cancelled":
|
|
60
|
+
case "interrupted": return "warning";
|
|
61
|
+
/* v8 ignore next -- WorkflowRunStatus is closed and every variant is handled above. */
|
|
62
|
+
default: return status;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function readablePhase(phase, t) {
|
|
66
|
+
if (phase === null) return t("phase.unassigned");
|
|
67
|
+
return phase === "" ? t("phase.empty") : phase;
|
|
68
|
+
}
|
|
69
|
+
function readableMember(label, t) {
|
|
70
|
+
return label === "" ? t("member.empty") : label;
|
|
71
|
+
}
|
|
72
|
+
function statusCount(status, count, t) {
|
|
73
|
+
return t(`statusCount.${status}`, { count });
|
|
74
|
+
}
|
|
75
|
+
function memberCount(count, t) {
|
|
76
|
+
return t(count === 1 ? "run.members.one" : "run.members.other", { count });
|
|
77
|
+
}
|
|
78
|
+
function StatusDisclosure(props) {
|
|
79
|
+
return (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
80
|
+
...props,
|
|
81
|
+
expandable: true
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function abnormal(status) {
|
|
85
|
+
return status === "failed" || status === "cancelled" || status === "interrupted";
|
|
86
|
+
}
|
|
87
|
+
function phaseDisclosureFacts(phase) {
|
|
88
|
+
return {
|
|
89
|
+
mode: phase.members.some((member) => abnormal(member.status)) ? "abnormal" : phase.members.some((member) => member.status === "running") ? "running" : "clean",
|
|
90
|
+
activityCount: phase.members.length
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function runDisclosureFacts(status, phases) {
|
|
94
|
+
return {
|
|
95
|
+
mode: abnormal(status) || phases.some(([, facts]) => facts.mode === "abnormal") ? "abnormal" : status === "running" || phases.some(([, facts]) => facts.mode === "running") ? "running" : "clean",
|
|
96
|
+
activityCount: phases.reduce((count, [, facts]) => count + facts.activityCount, 0)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function initialDisclosureState(facts) {
|
|
100
|
+
return {
|
|
101
|
+
...facts,
|
|
102
|
+
open: facts.mode !== "clean",
|
|
103
|
+
pendingCleanCollapse: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function advanceDisclosureState(current, facts, focusWithin) {
|
|
107
|
+
if (current.mode === facts.mode && current.activityCount === facts.activityCount) {
|
|
108
|
+
if (!current.pendingCleanCollapse || focusWithin) return current;
|
|
109
|
+
return {
|
|
110
|
+
...current,
|
|
111
|
+
open: false,
|
|
112
|
+
pendingCleanCollapse: false
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (facts.mode === "clean") {
|
|
116
|
+
const deferCollapse = current.open && focusWithin;
|
|
117
|
+
return {
|
|
118
|
+
...facts,
|
|
119
|
+
open: deferCollapse,
|
|
120
|
+
pendingCleanCollapse: deferCollapse
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
if (current.mode === "clean" || facts.mode === "abnormal" && current.mode !== "abnormal") return {
|
|
124
|
+
...facts,
|
|
125
|
+
open: true,
|
|
126
|
+
pendingCleanCollapse: false
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
...facts,
|
|
130
|
+
open: current.open,
|
|
131
|
+
pendingCleanCollapse: false
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function focusIsWithin(element) {
|
|
135
|
+
if (element === null || element === void 0) return false;
|
|
136
|
+
return element.contains(element.ownerDocument.activeElement);
|
|
137
|
+
}
|
|
138
|
+
function collapsePending(state) {
|
|
139
|
+
if (!state.pendingCleanCollapse) return state;
|
|
140
|
+
return {
|
|
141
|
+
...state,
|
|
142
|
+
open: false,
|
|
143
|
+
pendingCleanCollapse: false
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function existingPhaseState(phases, key) {
|
|
147
|
+
const phase = phases.get(key);
|
|
148
|
+
/* v8 ignore next -- mounted phase callbacks are created from this owner map. */
|
|
149
|
+
if (phase === void 0) throw new Error(`Missing disclosure state for phase ${key}`);
|
|
150
|
+
return phase;
|
|
151
|
+
}
|
|
152
|
+
function preventPendingHeaderFocus(event) {
|
|
153
|
+
const header = event.currentTarget.querySelector("[data-disclosure-row]");
|
|
154
|
+
/* v8 ignore next -- DisclosureRow always renders its header before the content. */
|
|
155
|
+
if (header === null) throw new Error("Missing disclosure header");
|
|
156
|
+
if (header.contains(event.target)) event.preventDefault();
|
|
157
|
+
}
|
|
158
|
+
function phaseStatusSummary(members, t) {
|
|
159
|
+
const counts = /* @__PURE__ */ new Map();
|
|
160
|
+
for (const member of members) counts.set(member.status, (counts.get(member.status) ?? 0) + 1);
|
|
161
|
+
const count = (status) => counts.get(status) ?? 0;
|
|
162
|
+
const active = [
|
|
163
|
+
"running",
|
|
164
|
+
"failed",
|
|
165
|
+
"cancelled",
|
|
166
|
+
"interrupted"
|
|
167
|
+
].filter((status) => count(status) > 0);
|
|
168
|
+
if (active.length === 0) return statusCount("completed", count("completed"), t);
|
|
169
|
+
return (active.includes("interrupted") && count("completed") > 0 ? ["completed", ...active] : active).map((status) => statusCount(status, count(status), t)).join(" · ");
|
|
170
|
+
}
|
|
171
|
+
function navigableMembers(sessions, phases, parentId) {
|
|
172
|
+
const ordinary = new Set(sessions.ids);
|
|
173
|
+
const result = [];
|
|
174
|
+
for (const phase of phases) for (const member of phase.members) {
|
|
175
|
+
const summary = sessions.byId[member.childId];
|
|
176
|
+
if (member.status === "running" && ordinary.has(member.childId) && summary?.origin === "subagent" && summary.parentId === parentId && summary.running) result.push(member.childId);
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
function RunHeader({ children, count, name, onToggle, open, status, t }) {
|
|
181
|
+
return (0, react_jsx_runtime.jsx)(StatusDisclosure, {
|
|
182
|
+
icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
183
|
+
title: t("run.title", { name }),
|
|
184
|
+
open,
|
|
185
|
+
onToggle,
|
|
186
|
+
expandOnRowClick: true,
|
|
187
|
+
previewChevron: false,
|
|
188
|
+
keepContentWhenOpen: true,
|
|
189
|
+
rowClassName: WorkflowRunPanel_module_css_default.runHeader,
|
|
190
|
+
leadingClassName: WorkflowRunPanel_module_css_default.runLeading,
|
|
191
|
+
titleClassName: WorkflowRunPanel_module_css_default.runTitle,
|
|
192
|
+
collapsedContent: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
193
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
194
|
+
className: WorkflowRunPanel_module_css_default.separator,
|
|
195
|
+
"aria-hidden": true
|
|
196
|
+
}),
|
|
197
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
198
|
+
className: WorkflowRunPanel_module_css_default.runSummary,
|
|
199
|
+
children: memberCount(count, t)
|
|
200
|
+
}),
|
|
201
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
202
|
+
className: WorkflowRunPanel_module_css_default.statusTail,
|
|
203
|
+
"data-status": status,
|
|
204
|
+
children: [(0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.StateDot, { state: dotState(status) }), (0, react_jsx_runtime.jsx)("span", { children: t(STATUS_KEYS[status]) })]
|
|
205
|
+
})
|
|
206
|
+
] }),
|
|
207
|
+
children
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function MemberRow({ member, navigable, openSession, t }) {
|
|
211
|
+
const name = readableMember(member.label, t);
|
|
212
|
+
const [focused, setFocused] = (0, react.useState)(false);
|
|
213
|
+
const renderButton = navigable || focused;
|
|
214
|
+
const content = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
215
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
216
|
+
className: WorkflowRunPanel_module_css_default.dotSlot,
|
|
217
|
+
children: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.StateDot, { state: dotState(member.status) })
|
|
218
|
+
}),
|
|
219
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
220
|
+
className: WorkflowRunPanel_module_css_default.memberLabelWrap,
|
|
221
|
+
"data-member-label-wrap": true,
|
|
222
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
223
|
+
className: WorkflowRunPanel_module_css_default.memberLabel,
|
|
224
|
+
"data-member-label": true,
|
|
225
|
+
children: name
|
|
226
|
+
})
|
|
227
|
+
}),
|
|
228
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
229
|
+
className: WorkflowRunPanel_module_css_default.memberStatus,
|
|
230
|
+
"data-member-status-text": true,
|
|
231
|
+
children: t(STATUS_KEYS[member.status])
|
|
232
|
+
})
|
|
233
|
+
] });
|
|
234
|
+
if (!renderButton) return (0, react_jsx_runtime.jsx)("div", {
|
|
235
|
+
className: WorkflowRunPanel_module_css_default.memberRow,
|
|
236
|
+
"data-member-status": member.status,
|
|
237
|
+
children: content
|
|
238
|
+
});
|
|
239
|
+
return (0, react_jsx_runtime.jsx)("button", {
|
|
240
|
+
type: "button",
|
|
241
|
+
className: navigable ? WorkflowRunPanel_module_css_default.memberButton : WorkflowRunPanel_module_css_default.memberRow,
|
|
242
|
+
"data-member-status": member.status,
|
|
243
|
+
"aria-disabled": navigable ? void 0 : true,
|
|
244
|
+
"aria-label": navigable ? t("member.open", { name }) : name,
|
|
245
|
+
tabIndex: navigable ? void 0 : -1,
|
|
246
|
+
onFocus: () => {
|
|
247
|
+
setFocused(true);
|
|
248
|
+
},
|
|
249
|
+
onBlur: () => {
|
|
250
|
+
setFocused(false);
|
|
251
|
+
},
|
|
252
|
+
onClick: navigable ? () => {
|
|
253
|
+
openSession(member.childId);
|
|
254
|
+
} : void 0,
|
|
255
|
+
children: content
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
function PhaseSection({ contentRef, onContentBlur, onToggle, open, pendingCleanCollapse, phase, navigable, openSession, t }) {
|
|
259
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
260
|
+
className: WorkflowRunPanel_module_css_default.phase,
|
|
261
|
+
onMouseDownCapture: pendingCleanCollapse ? preventPendingHeaderFocus : void 0,
|
|
262
|
+
children: (0, react_jsx_runtime.jsx)(StatusDisclosure, {
|
|
263
|
+
icon: (0, react_jsx_runtime.jsx)(_prettier_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {}),
|
|
264
|
+
title: readablePhase(phase.phase, t),
|
|
265
|
+
open,
|
|
266
|
+
onToggle,
|
|
267
|
+
expandOnRowClick: true,
|
|
268
|
+
previewChevron: false,
|
|
269
|
+
keepContentWhenOpen: true,
|
|
270
|
+
rowClassName: WorkflowRunPanel_module_css_default.phaseHeader,
|
|
271
|
+
leadingClassName: WorkflowRunPanel_module_css_default.phaseLeading,
|
|
272
|
+
titleClassName: WorkflowRunPanel_module_css_default.phaseTitle,
|
|
273
|
+
collapsedContent: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
274
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
275
|
+
className: WorkflowRunPanel_module_css_default.separator,
|
|
276
|
+
"aria-hidden": true
|
|
277
|
+
}),
|
|
278
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
279
|
+
className: WorkflowRunPanel_module_css_default.phaseCount,
|
|
280
|
+
"data-phase-count": true,
|
|
281
|
+
children: memberCount(phase.members.length, t)
|
|
282
|
+
}),
|
|
283
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
284
|
+
className: WorkflowRunPanel_module_css_default.phaseStatus,
|
|
285
|
+
"data-phase-status-text": true,
|
|
286
|
+
children: phaseStatusSummary(phase.members, t)
|
|
287
|
+
})
|
|
288
|
+
] }),
|
|
289
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
290
|
+
ref: contentRef,
|
|
291
|
+
className: WorkflowRunPanel_module_css_default.members,
|
|
292
|
+
onBlur: onContentBlur,
|
|
293
|
+
children: phase.members.map((member) => (0, react_jsx_runtime.jsx)(MemberRow, {
|
|
294
|
+
member,
|
|
295
|
+
navigable: navigable.includes(member.childId),
|
|
296
|
+
openSession,
|
|
297
|
+
t
|
|
298
|
+
}, member.seq))
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
/** Render one durable workflow run with status-driven run and phase disclosure. */
|
|
304
|
+
function WorkflowRunPanel({ node, sessionId, useSessions, openSession, t }) {
|
|
305
|
+
const phaseFacts = (0, react.useMemo)(() => node.data.phases.map((phase) => [phase.key, phaseDisclosureFacts(phase)]), [node.data.phases]);
|
|
306
|
+
const runFacts = (0, react.useMemo)(() => runDisclosureFacts(node.data.status, phaseFacts), [node.data.status, phaseFacts]);
|
|
307
|
+
const totalMembers = runFacts.activityCount;
|
|
308
|
+
const [disclosures, setDisclosures] = (0, react.useState)(() => ({
|
|
309
|
+
run: initialDisclosureState(runFacts),
|
|
310
|
+
phases: new Map(phaseFacts.map(([key, facts]) => [key, initialDisclosureState(facts)]))
|
|
311
|
+
}));
|
|
312
|
+
const runContentRef = (0, react.useRef)(null);
|
|
313
|
+
const phaseContentRefs = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
314
|
+
const navigable = useSessions((sessions) => navigableMembers(sessions, node.data.phases, sessionId), _prettier_ai_dsh_client_store.shallowEqual);
|
|
315
|
+
(0, react.useLayoutEffect)(() => {
|
|
316
|
+
setDisclosures((current) => {
|
|
317
|
+
const phases = /* @__PURE__ */ new Map();
|
|
318
|
+
let phasesChanged = current.phases.size !== phaseFacts.length;
|
|
319
|
+
let phaseStartedCycle = false;
|
|
320
|
+
for (const [key, facts] of phaseFacts) {
|
|
321
|
+
const previous = current.phases.get(key);
|
|
322
|
+
const next = previous === void 0 ? initialDisclosureState(facts) : advanceDisclosureState(previous, facts, focusIsWithin(phaseContentRefs.current.get(key)));
|
|
323
|
+
phases.set(key, next);
|
|
324
|
+
if (next !== previous) phasesChanged = true;
|
|
325
|
+
if (previous?.mode === "clean" && (facts.mode !== "clean" || facts.activityCount !== previous.activityCount)) phaseStartedCycle = true;
|
|
326
|
+
}
|
|
327
|
+
const advancedRun = advanceDisclosureState(current.run, runFacts, focusIsWithin(runContentRef.current));
|
|
328
|
+
const run = phaseStartedCycle && runFacts.mode !== "clean" && !advancedRun.open ? {
|
|
329
|
+
...advancedRun,
|
|
330
|
+
open: true,
|
|
331
|
+
pendingCleanCollapse: false
|
|
332
|
+
} : advancedRun;
|
|
333
|
+
return run !== current.run || phasesChanged ? {
|
|
334
|
+
run,
|
|
335
|
+
phases
|
|
336
|
+
} : current;
|
|
337
|
+
});
|
|
338
|
+
}, [
|
|
339
|
+
disclosures.run.open,
|
|
340
|
+
phaseFacts,
|
|
341
|
+
runFacts
|
|
342
|
+
]);
|
|
343
|
+
const toggleRun = () => {
|
|
344
|
+
setDisclosures((current) => ({
|
|
345
|
+
...current,
|
|
346
|
+
run: {
|
|
347
|
+
...current.run,
|
|
348
|
+
open: !current.run.open,
|
|
349
|
+
pendingCleanCollapse: false
|
|
350
|
+
}
|
|
351
|
+
}));
|
|
352
|
+
};
|
|
353
|
+
const togglePhase = (key) => {
|
|
354
|
+
setDisclosures((current) => {
|
|
355
|
+
const phases = new Map(current.phases);
|
|
356
|
+
const phase = existingPhaseState(phases, key);
|
|
357
|
+
phases.set(key, {
|
|
358
|
+
...phase,
|
|
359
|
+
open: !phase.open,
|
|
360
|
+
pendingCleanCollapse: false
|
|
361
|
+
});
|
|
362
|
+
return {
|
|
363
|
+
...current,
|
|
364
|
+
phases
|
|
365
|
+
};
|
|
366
|
+
});
|
|
367
|
+
};
|
|
368
|
+
const settleRunBlur = (event) => {
|
|
369
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
370
|
+
setDisclosures((current) => {
|
|
371
|
+
const run = collapsePending(current.run);
|
|
372
|
+
return run === current.run ? current : {
|
|
373
|
+
...current,
|
|
374
|
+
run
|
|
375
|
+
};
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
const settlePhaseBlur = (key, event) => {
|
|
379
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
380
|
+
setDisclosures((current) => {
|
|
381
|
+
const phase = existingPhaseState(current.phases, key);
|
|
382
|
+
const next = collapsePending(phase);
|
|
383
|
+
if (next === phase) return current;
|
|
384
|
+
const phases = new Map(current.phases);
|
|
385
|
+
phases.set(key, next);
|
|
386
|
+
return {
|
|
387
|
+
...current,
|
|
388
|
+
phases
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
return (0, react_jsx_runtime.jsx)("section", {
|
|
393
|
+
className: WorkflowRunPanel_module_css_default.root,
|
|
394
|
+
"data-workflow-run": true,
|
|
395
|
+
"data-run-status": node.data.status,
|
|
396
|
+
onMouseDownCapture: disclosures.run.pendingCleanCollapse ? preventPendingHeaderFocus : void 0,
|
|
397
|
+
children: (0, react_jsx_runtime.jsx)(RunHeader, {
|
|
398
|
+
count: totalMembers,
|
|
399
|
+
name: node.data.name,
|
|
400
|
+
open: disclosures.run.open,
|
|
401
|
+
onToggle: toggleRun,
|
|
402
|
+
status: node.data.status,
|
|
403
|
+
t,
|
|
404
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
405
|
+
ref: runContentRef,
|
|
406
|
+
className: WorkflowRunPanel_module_css_default.phaseList,
|
|
407
|
+
onBlur: settleRunBlur,
|
|
408
|
+
children: node.data.phases.length === 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
409
|
+
className: WorkflowRunPanel_module_css_default.empty,
|
|
410
|
+
children: t("run.empty")
|
|
411
|
+
}) : node.data.phases.map((phase) => {
|
|
412
|
+
const facts = phaseDisclosureFacts(phase);
|
|
413
|
+
const disclosure = disclosures.phases.get(phase.key) ?? initialDisclosureState(facts);
|
|
414
|
+
return (0, react_jsx_runtime.jsx)(PhaseSection, {
|
|
415
|
+
contentRef: (element) => {
|
|
416
|
+
if (element === null) phaseContentRefs.current.delete(phase.key);
|
|
417
|
+
else phaseContentRefs.current.set(phase.key, element);
|
|
418
|
+
},
|
|
419
|
+
onContentBlur: (event) => {
|
|
420
|
+
settlePhaseBlur(phase.key, event);
|
|
421
|
+
},
|
|
422
|
+
onToggle: () => {
|
|
423
|
+
togglePhase(phase.key);
|
|
424
|
+
},
|
|
425
|
+
open: disclosure.open,
|
|
426
|
+
pendingCleanCollapse: disclosure.pendingCleanCollapse,
|
|
427
|
+
phase,
|
|
428
|
+
navigable,
|
|
429
|
+
openSession,
|
|
430
|
+
t
|
|
431
|
+
}, phase.key);
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
})
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
//#endregion
|
|
438
|
+
//#region lib/types/client/locales.js
|
|
439
|
+
/** `workflowRun` namespace dictionaries. */
|
|
440
|
+
/** Dictionary namespace owned by this plugin. */
|
|
441
|
+
const NS = "workflowRun";
|
|
442
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
443
|
+
const zh = {
|
|
444
|
+
"run.title": "{name}",
|
|
445
|
+
"run.members.one": "{count} 个成员",
|
|
446
|
+
"run.members.other": "{count} 个成员",
|
|
447
|
+
"run.empty": "没有启动成员",
|
|
448
|
+
"phase.unassigned": "未分阶段",
|
|
449
|
+
"phase.empty": "空阶段名",
|
|
450
|
+
"statusCount.running": "运行中 {count}",
|
|
451
|
+
"statusCount.completed": "已完成 {count}",
|
|
452
|
+
"statusCount.failed": "失败 {count}",
|
|
453
|
+
"statusCount.cancelled": "已取消 {count}",
|
|
454
|
+
"statusCount.interrupted": "已中断 {count}",
|
|
455
|
+
"member.empty": "空成员名",
|
|
456
|
+
"member.open": "打开 {name}",
|
|
457
|
+
"status.running": "运行中",
|
|
458
|
+
"status.completed": "已完成",
|
|
459
|
+
"status.failed": "失败",
|
|
460
|
+
"status.cancelled": "已取消",
|
|
461
|
+
"status.interrupted": "已中断"
|
|
462
|
+
};
|
|
463
|
+
/** English dictionary (same key set). */
|
|
464
|
+
const en = {
|
|
465
|
+
"run.title": "{name}",
|
|
466
|
+
"run.members.one": "{count} member",
|
|
467
|
+
"run.members.other": "{count} members",
|
|
468
|
+
"run.empty": "No members started",
|
|
469
|
+
"phase.unassigned": "Unphased",
|
|
470
|
+
"phase.empty": "Empty phase name",
|
|
471
|
+
"statusCount.running": "Running {count}",
|
|
472
|
+
"statusCount.completed": "Completed {count}",
|
|
473
|
+
"statusCount.failed": "Failed {count}",
|
|
474
|
+
"statusCount.cancelled": "Cancelled {count}",
|
|
475
|
+
"statusCount.interrupted": "Interrupted {count}",
|
|
476
|
+
"member.empty": "Empty member name",
|
|
477
|
+
"member.open": "Open {name}",
|
|
478
|
+
"status.running": "Running",
|
|
479
|
+
"status.completed": "Completed",
|
|
480
|
+
"status.failed": "Failed",
|
|
481
|
+
"status.cancelled": "Cancelled",
|
|
482
|
+
"status.interrupted": "Interrupted"
|
|
483
|
+
};
|
|
484
|
+
//#endregion
|
|
485
|
+
//#region lib/types/client/workflow-definition.js
|
|
486
|
+
/**
|
|
487
|
+
* Build a collision-free phase key preserving absent versus empty identity.
|
|
488
|
+
* @param phase - exact phase string, or null for an omitted field.
|
|
489
|
+
* @returns the stable renderer key for that phase identity.
|
|
490
|
+
*/
|
|
491
|
+
function workflowPhaseKey(phase) {
|
|
492
|
+
return phase === null ? "missing" : `value:${phase.length}:${phase}`;
|
|
493
|
+
}
|
|
494
|
+
function statusFromStopReason(stopReason) {
|
|
495
|
+
switch (stopReason) {
|
|
496
|
+
case "completed": return "completed";
|
|
497
|
+
case "cancelled": return "cancelled";
|
|
498
|
+
case "error": return "failed";
|
|
499
|
+
/* v8 ignore next -- WorkflowStopReason is closed and every variant is handled above. */
|
|
500
|
+
default: return stopReason;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
function statusFromOutcome(outcome) {
|
|
504
|
+
switch (outcome) {
|
|
505
|
+
case "completed": return "completed";
|
|
506
|
+
case "cancelled": return "cancelled";
|
|
507
|
+
case "failed": return "failed";
|
|
508
|
+
/* v8 ignore next -- WorkflowAgentOutcome is closed and every variant is handled above. */
|
|
509
|
+
default: return outcome;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function locationClosed(location) {
|
|
513
|
+
if (location.kind === "step") return location.step.status === "closed" || location.turn.status === "closed";
|
|
514
|
+
return location.kind === "turn" && location.turn.status === "closed";
|
|
515
|
+
}
|
|
516
|
+
function projectWorkflow(context, location) {
|
|
517
|
+
const state = context.state;
|
|
518
|
+
const interrupted = state.stopReason === void 0 && locationClosed(location);
|
|
519
|
+
const phases = /* @__PURE__ */ new Map();
|
|
520
|
+
for (const member of state.members) {
|
|
521
|
+
const phase = member.phase === void 0 ? null : member.phase;
|
|
522
|
+
const key = workflowPhaseKey(phase);
|
|
523
|
+
let group = phases.get(key);
|
|
524
|
+
if (group === void 0) {
|
|
525
|
+
group = {
|
|
526
|
+
phase,
|
|
527
|
+
members: []
|
|
528
|
+
};
|
|
529
|
+
phases.set(key, group);
|
|
530
|
+
}
|
|
531
|
+
group.members.push({
|
|
532
|
+
seq: member.seq,
|
|
533
|
+
label: member.label,
|
|
534
|
+
childId: member.childId,
|
|
535
|
+
status: member.outcome === void 0 ? interrupted ? "interrupted" : "running" : statusFromOutcome(member.outcome)
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
const projectedPhases = [...phases].map(([key, phase]) => ({
|
|
539
|
+
key,
|
|
540
|
+
phase: phase.phase,
|
|
541
|
+
members: phase.members
|
|
542
|
+
}));
|
|
543
|
+
return {
|
|
544
|
+
name: state.name,
|
|
545
|
+
status: state.stopReason === void 0 ? interrupted ? "interrupted" : "running" : statusFromStopReason(state.stopReason),
|
|
546
|
+
phases: projectedPhases
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function updateAgentStart(state, data) {
|
|
550
|
+
const member = {
|
|
551
|
+
seq: data.seq,
|
|
552
|
+
label: data.label,
|
|
553
|
+
...data.phase === void 0 ? {} : { phase: data.phase },
|
|
554
|
+
childId: data.childId
|
|
555
|
+
};
|
|
556
|
+
return {
|
|
557
|
+
...state,
|
|
558
|
+
members: [...state.members, member]
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function updateAgentEnd(state, data) {
|
|
562
|
+
return {
|
|
563
|
+
...state,
|
|
564
|
+
members: state.members.map((member) => member.seq === data.seq ? {
|
|
565
|
+
...member,
|
|
566
|
+
outcome: data.outcome
|
|
567
|
+
} : member)
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
/** Durable workflow event family folded into one keyed Chat node. */
|
|
571
|
+
const workflowRunDefinition = {
|
|
572
|
+
kind: "workflow-run",
|
|
573
|
+
target: "chat",
|
|
574
|
+
match: (event) => {
|
|
575
|
+
if (event.type === "tool-workflow/run-start") return {
|
|
576
|
+
id: String(event.data.runId),
|
|
577
|
+
role: "start"
|
|
578
|
+
};
|
|
579
|
+
if (event.type === "tool-workflow/agent-start" || event.type === "tool-workflow/agent-end" || event.type === "tool-workflow/run-end") return {
|
|
580
|
+
id: String(event.data.runId),
|
|
581
|
+
role: "update"
|
|
582
|
+
};
|
|
583
|
+
return null;
|
|
584
|
+
},
|
|
585
|
+
start: (_context, match) => {
|
|
586
|
+
if (match.event.type !== "tool-workflow/run-start") throw new Error("workflow-run start requires tool-workflow/run-start");
|
|
587
|
+
return {
|
|
588
|
+
name: match.event.data.name,
|
|
589
|
+
members: []
|
|
590
|
+
};
|
|
591
|
+
},
|
|
592
|
+
update: (context, match) => {
|
|
593
|
+
if (match.event.type === "tool-workflow/agent-start") return updateAgentStart(context.state, match.event.data);
|
|
594
|
+
if (match.event.type === "tool-workflow/agent-end") return updateAgentEnd(context.state, match.event.data);
|
|
595
|
+
if (match.event.type === "tool-workflow/run-end") return {
|
|
596
|
+
...context.state,
|
|
597
|
+
stopReason: match.event.data.stopReason
|
|
598
|
+
};
|
|
599
|
+
return context.state;
|
|
600
|
+
},
|
|
601
|
+
buildViewNode: (context) => {
|
|
602
|
+
if (context.start === void 0) return null;
|
|
603
|
+
const data = projectWorkflow(context, context.start.location);
|
|
604
|
+
return {
|
|
605
|
+
key: context.key,
|
|
606
|
+
kind: "workflow-run",
|
|
607
|
+
id: context.id,
|
|
608
|
+
target: "chat",
|
|
609
|
+
anchorSeq: context.start.event.seq,
|
|
610
|
+
location: context.start.location,
|
|
611
|
+
visibility: "visible",
|
|
612
|
+
data
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region lib/types/client/index.js
|
|
618
|
+
/** Browser plugin for durable workflow-run Conversation Nodes. */
|
|
619
|
+
/** Required services for Definition, keyed renderer, navigation, and copy. */
|
|
620
|
+
const inject = [
|
|
621
|
+
"uiConversation",
|
|
622
|
+
"slots",
|
|
623
|
+
"sessions",
|
|
624
|
+
"locale"
|
|
625
|
+
];
|
|
626
|
+
/** Register the workflow Definition, dictionary, and keyed Chat renderer. */
|
|
627
|
+
function apply(ctx) {
|
|
628
|
+
ctx.uiConversation.events.register(workflowRunDefinition);
|
|
629
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
630
|
+
zh,
|
|
631
|
+
en
|
|
632
|
+
}), "ui-workflow-run: dictionaries");
|
|
633
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
634
|
+
name: "conversation.chat.node",
|
|
635
|
+
key: "workflow-run",
|
|
636
|
+
locale: NS,
|
|
637
|
+
inject: () => ({ openSession: (id) => {
|
|
638
|
+
ctx.sessions.open(id);
|
|
639
|
+
} })
|
|
640
|
+
}, WorkflowRunPanel));
|
|
641
|
+
}
|
|
642
|
+
//#endregion
|
|
643
|
+
exports.apply = apply;
|
|
644
|
+
exports.inject = inject;
|
|
645
|
+
return module.exports;
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
//# sourceMappingURL=client.js.map
|
package/lib/index.js
ADDED
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/** Package-owned invariant companion for the workflow-run UI plugin. */
|
|
3
|
+
const PACKAGE_NAME = "@prettier-ai/dsh-client-ui-workflow-run";
|
|
4
|
+
/** Cordis companion plugin name. */
|
|
5
|
+
const name = "client-ui-workflow-run-invariant";
|
|
6
|
+
/** Service required before the companion can reserve package ownership. */
|
|
7
|
+
const inject = ["invariants"];
|
|
8
|
+
/**
|
|
9
|
+
* No runtime invariant: the browser plugin contributes one effect-owned
|
|
10
|
+
* Conversation Definition, keyed renderer, and dictionary; tests prove their
|
|
11
|
+
* disposal and the Host tool package owns the durable event invariant.
|
|
12
|
+
*/
|
|
13
|
+
const install = () => {};
|
|
14
|
+
/** Register this package's invariant companion. */
|
|
15
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
16
|
+
//#endregion
|
|
17
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime } from '@prettier-ai/dsh-client-ui-slots';
|
|
2
|
+
import type { SessionId } from '@prettier-ai/dsh-session/types';
|
|
3
|
+
/** Navigation action injected from the plugin's own Session Controller access. */
|
|
4
|
+
export interface WorkflowRunInjected {
|
|
5
|
+
readonly openSession: (id: SessionId) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Complete keyed Chat renderer props. */
|
|
8
|
+
export type WorkflowRunPanelProps = PropsRuntime<'conversation.chat.node', 'workflow-run'> & PropsLocale<'workflowRun'> & WorkflowRunInjected;
|
|
9
|
+
/** Render one durable workflow run with status-driven run and phase disclosure. */
|
|
10
|
+
export declare function WorkflowRunPanel({ node, sessionId, useSessions, openSession, t }: WorkflowRunPanelProps): import("react").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=WorkflowRunPanel.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Browser plugin for durable workflow-run Conversation Nodes. */
|
|
2
|
+
import type { Context as ClientContext } from '@prettier-ai/cordis';
|
|
3
|
+
import { type WorkflowRunKey } from './locales.ts';
|
|
4
|
+
declare module '@prettier-ai/dsh-client-ui-slots' {
|
|
5
|
+
interface LocaleNamespaceMap {
|
|
6
|
+
/** Durable workflow-run node copy. */
|
|
7
|
+
workflowRun: WorkflowRunKey;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** Required services for Definition, keyed renderer, navigation, and copy. */
|
|
11
|
+
export declare const inject: string[];
|
|
12
|
+
/** Register the workflow Definition, dictionary, and keyed Chat renderer. */
|
|
13
|
+
export declare function apply(ctx: ClientContext): void;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** `workflowRun` namespace dictionaries. */
|
|
2
|
+
/** Dictionary namespace owned by this plugin. */
|
|
3
|
+
export declare const NS = "workflowRun";
|
|
4
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
5
|
+
export declare const zh: {
|
|
6
|
+
'run.title': string;
|
|
7
|
+
'run.members.one': string;
|
|
8
|
+
'run.members.other': string;
|
|
9
|
+
'run.empty': string;
|
|
10
|
+
'phase.unassigned': string;
|
|
11
|
+
'phase.empty': string;
|
|
12
|
+
'statusCount.running': string;
|
|
13
|
+
'statusCount.completed': string;
|
|
14
|
+
'statusCount.failed': string;
|
|
15
|
+
'statusCount.cancelled': string;
|
|
16
|
+
'statusCount.interrupted': string;
|
|
17
|
+
'member.empty': string;
|
|
18
|
+
'member.open': string;
|
|
19
|
+
'status.running': string;
|
|
20
|
+
'status.completed': string;
|
|
21
|
+
'status.failed': string;
|
|
22
|
+
'status.cancelled': string;
|
|
23
|
+
'status.interrupted': string;
|
|
24
|
+
};
|
|
25
|
+
/** English dictionary (same key set). */
|
|
26
|
+
export declare const en: Record<WorkflowRunKey, string>;
|
|
27
|
+
/** Union of this namespace's dictionary keys. */
|
|
28
|
+
export type WorkflowRunKey = keyof typeof zh;
|
|
29
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ConversationNodeDefinition } from '@prettier-ai/dsh-client-ui-conversation/client';
|
|
2
|
+
import type { SessionId } from '@prettier-ai/dsh-session/types';
|
|
3
|
+
import type { ToolWorkflowAgentStartData } from '@prettier-ai/dsh-tool-workflow/types';
|
|
4
|
+
import type { WorkflowAgentOutcome, WorkflowStopReason } from '@prettier-ai/dsh-workflow/types';
|
|
5
|
+
/** Status shown for a workflow, phase, or member. */
|
|
6
|
+
export type WorkflowRunStatus = 'running' | 'completed' | 'failed' | 'cancelled' | 'interrupted';
|
|
7
|
+
/** Final renderer data for one member. */
|
|
8
|
+
export interface WorkflowRunMemberData {
|
|
9
|
+
readonly seq: number;
|
|
10
|
+
readonly label: string;
|
|
11
|
+
readonly childId: SessionId;
|
|
12
|
+
readonly status: WorkflowRunStatus;
|
|
13
|
+
}
|
|
14
|
+
/** Final renderer data for one exact phase identity. */
|
|
15
|
+
export interface WorkflowRunPhaseData {
|
|
16
|
+
readonly key: string;
|
|
17
|
+
/** `null` is the absent field; the empty string remains a distinct identity. */
|
|
18
|
+
readonly phase: string | null;
|
|
19
|
+
readonly members: readonly WorkflowRunMemberData[];
|
|
20
|
+
}
|
|
21
|
+
/** Final keyed Chat payload for one workflow run. */
|
|
22
|
+
export interface WorkflowRunChatData {
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly status: WorkflowRunStatus;
|
|
25
|
+
readonly phases: readonly WorkflowRunPhaseData[];
|
|
26
|
+
}
|
|
27
|
+
declare module '@prettier-ai/dsh-client-ui-chat/client' {
|
|
28
|
+
interface ChatNodeDataMap {
|
|
29
|
+
/** Durable top-level workflow run and all members that actually started. */
|
|
30
|
+
'workflow-run': WorkflowRunChatData;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
interface WorkflowMemberState extends Omit<ToolWorkflowAgentStartData, 'runId'> {
|
|
34
|
+
readonly outcome?: WorkflowAgentOutcome;
|
|
35
|
+
}
|
|
36
|
+
interface WorkflowState {
|
|
37
|
+
readonly name: string;
|
|
38
|
+
readonly stopReason?: WorkflowStopReason;
|
|
39
|
+
readonly members: readonly WorkflowMemberState[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build a collision-free phase key preserving absent versus empty identity.
|
|
43
|
+
* @param phase - exact phase string, or null for an omitted field.
|
|
44
|
+
* @returns the stable renderer key for that phase identity.
|
|
45
|
+
*/
|
|
46
|
+
export declare function workflowPhaseKey(phase: string | null): string;
|
|
47
|
+
/** Durable workflow event family folded into one keyed Chat node. */
|
|
48
|
+
export declare const workflowRunDefinition: ConversationNodeDefinition<WorkflowState>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=workflow-definition.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Package-owned invariant companion for the workflow-run UI plugin. */
|
|
2
|
+
import type { Context } from '@prettier-ai/cordis';
|
|
3
|
+
/** Cordis companion plugin name. */
|
|
4
|
+
export declare const name = "client-ui-workflow-run-invariant";
|
|
5
|
+
/** Service required before the companion can reserve package ownership. */
|
|
6
|
+
export declare const inject: string[];
|
|
7
|
+
/** Register this package's invariant companion. */
|
|
8
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
9
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prettier-ai/dsh-client-ui-workflow-run",
|
|
3
|
+
"description": "Durable workflow-run Conversation Node and nested member disclosure for dsh web",
|
|
4
|
+
"version": "0.1.2-alpha.1",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
11
|
+
"directory": "packages/client/ui-workflow-run"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "lib/index.js",
|
|
15
|
+
"types": "lib/types/index.d.ts",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./lib/types/index.d.ts",
|
|
19
|
+
"default": "./lib/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./invariant": {
|
|
22
|
+
"types": "./lib/types/invariant.d.ts",
|
|
23
|
+
"default": "./lib/invariant.js"
|
|
24
|
+
},
|
|
25
|
+
"./client": {
|
|
26
|
+
"types": "./lib/types/client/index.d.ts",
|
|
27
|
+
"default": "./lib/client.js"
|
|
28
|
+
},
|
|
29
|
+
"./src/*": "./src/*",
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"dsh": {
|
|
33
|
+
"client": {
|
|
34
|
+
"inject": [
|
|
35
|
+
"@prettier-ai/dsh-api-session-controller",
|
|
36
|
+
"@prettier-ai/dsh-client-locale",
|
|
37
|
+
"@prettier-ai/dsh-client-ui-chat",
|
|
38
|
+
"@prettier-ai/dsh-client-ui-conversation",
|
|
39
|
+
"@prettier-ai/dsh-client-ui-renderer",
|
|
40
|
+
"@prettier-ai/dsh-client-ui-session"
|
|
41
|
+
],
|
|
42
|
+
"platform": "web"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"lib/index.js",
|
|
47
|
+
"lib/invariant.js",
|
|
48
|
+
"lib/client.js",
|
|
49
|
+
"lib/types/**/*.d.ts"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.1",
|
|
54
|
+
"@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.1",
|
|
55
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
56
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
57
|
+
"@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
58
|
+
"@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.1",
|
|
59
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
60
|
+
"@prettier-ai/dsh-session": "^0.1.2-alpha.1",
|
|
61
|
+
"@prettier-ai/dsh-tool-workflow": "^0.1.2-alpha.1",
|
|
62
|
+
"@prettier-ai/dsh-workflow": "^0.1.2-alpha.1",
|
|
63
|
+
"@prettier-ai/cordis": "^4.0.1"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/react": "~18.3.1",
|
|
67
|
+
"react": "^18.2.0",
|
|
68
|
+
"@prettier-ai/dsh-api-session-controller": "^0.1.2-alpha.1",
|
|
69
|
+
"@prettier-ai/dsh-client-locale": "^0.1.2-alpha.1",
|
|
70
|
+
"@prettier-ai/dsh-client-store": "^0.1.2-alpha.1",
|
|
71
|
+
"@prettier-ai/dsh-client-ui-chat": "^0.1.2-alpha.1",
|
|
72
|
+
"@prettier-ai/dsh-client-ui-conversation": "^0.1.2-alpha.1",
|
|
73
|
+
"@prettier-ai/dsh-client-test-runtime": "^0.1.2-alpha.1",
|
|
74
|
+
"@prettier-ai/dsh-client-ui-primitives": "^0.1.2-alpha.1",
|
|
75
|
+
"@prettier-ai/dsh-client-ui-renderer": "^0.1.2-alpha.1",
|
|
76
|
+
"@prettier-ai/dsh-client-ui-session": "^0.1.2-alpha.1",
|
|
77
|
+
"@prettier-ai/dsh-session": "^0.1.2-alpha.1",
|
|
78
|
+
"@prettier-ai/dsh-client-ui-slots": "^0.1.2-alpha.1",
|
|
79
|
+
"@prettier-ai/dsh-tool-workflow": "^0.1.2-alpha.1",
|
|
80
|
+
"@prettier-ai/dsh-workflow": "^0.1.2-alpha.1",
|
|
81
|
+
"@prettier-ai/dsh-invariants": "^0.1.2-alpha.1",
|
|
82
|
+
"@prettier-ai/cordis": "^4.0.1"
|
|
83
|
+
},
|
|
84
|
+
"scripts": {
|
|
85
|
+
"bundle": "tsdown",
|
|
86
|
+
"watch": "tsdown --watch"
|
|
87
|
+
}
|
|
88
|
+
}
|