@deepseek-ai/dsh-client-ui-cordis 0.0.1-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +36 -0
- package/README.zh.md +36 -0
- package/lib/client.js +1433 -0
- package/lib/index.js +11 -0
- package/lib/invariant.js +26 -0
- package/lib/types/client/CordisActionRow.d.ts +8 -0
- package/lib/types/client/CordisDefineRow.d.ts +9 -0
- package/lib/types/client/CordisPanel.d.ts +8 -0
- package/lib/types/client/CordisRunRow.d.ts +9 -0
- package/lib/types/client/card-model.d.ts +56 -0
- package/lib/types/client/dynamic-port.d.ts +22 -0
- package/lib/types/client/events.d.ts +3 -0
- package/lib/types/client/index.d.ts +15 -0
- package/lib/types/client/inventory.d.ts +51 -0
- package/lib/types/client/locales.d.ts +115 -0
- package/lib/types/client/run-card-index.d.ts +36 -0
- package/lib/types/client/slots.d.ts +62 -0
- package/lib/types/client/status.d.ts +21 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
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/extensions/ui-cordis/README.md
|
|
5
|
+
README.md: 5f354aa95939de57a385921199848d40d4486ed4
|
|
6
|
+
README.zh.md: 7109c77c6947d80975eba7b2e2cca24bb6ef60b7
|
package/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-client-ui-cordis
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Cordis dynamic-plugin surfaces, browser half: a frame-wide panel that operates every definition the host holds, and a read-only `cordis_define` card that records what a session defined.
|
|
6
|
+
|
|
7
|
+
**The panel is global on purpose.** A model-driven `cordis_run` blocks host-side on a `cordis/request-run` round trip whose answer is a person pressing approve, and it can name a definition belonging to a session nobody is looking at — an approval reachable only inside that session's transcript would be unreachable exactly when it blocks the model. So the answering surface is a `shell.overlay` entry (a generic frame-wide floating seat this package contributed to `ui-layout`, not a React root of its own): a badge counting what runs plus what waits, opening a list of every definition with its run controls. The list is never filtered by session for the same reason; the selected session's rows are grouped first and everyone else's stay listed below. Rows come from the host's global `inventory` call, re-read rather than patched whenever an announcement changes what exists, because the announcements carry no labels. An open request whose definition that read does not cover still gets a row, rendered from the run activity's own session, label, reason and request identity: `cordis_define` broadcasts nothing, so a package defined after the last read is unknown to the page while its request already blocks the model, and a badge counting an answer the list cannot show would strand it. Such a request also triggers one registry read, which brings the row its run controls. Grouping reads one resolved field per row — the live run's session when there is one, the registry row's otherwise — rather than a different store per phase; both activity arms carry it, so answering a request cannot make its row leave the group it was answered in. Within a group the rows blocking a model come first.
|
|
8
|
+
|
|
9
|
+
**The card is a record.** It shows the name and purpose the model wrote, the source it wrote, and whether that definition is running — no switch, no approval, and a pointer to the panel. Its material comes only from the frozen call/result slice (labels from `argsRaw`, the host-minted id from the result's `meta.id`), so replay renders the same card, and one reading is the card's own to own: a successful `cordis_undefine` in this session's log is durable and terminal, and outranks the wire, where a retract announcement looks identical to a plain stop.
|
|
10
|
+
|
|
11
|
+
**A row reads two independent facts.** What the host runs comes from the inventory; what THIS page has loaded comes from the runner's live set. They diverge on every reload: the host keeps running everything while a fresh page holds nothing. A row the host runs and this page holds offers the global stop; a row the host runs and this page does NOT hold offers the load back first and that stop second — separate controls, because loading the browser half here and stopping the definition for every page are different acts. A host-only definition is exempt from all of it: with no browser half to load, "this page does not hold it" is simply what it always looks like, so its row reads plainly running and offers the stop alone. Idle, it offers a run labelled as just that — nothing is loaded here, so the control does not say it is — and the run request carries `hasClientHalf` to the runner, which is what makes it bring up the host half and fetch no browser half. Collapsing the two facts into the host's `running` alone left a reloaded page with nothing but the global stop, so the documented reload recovery (pull the inventory, load the definition back into this page) had no control to go through.
|
|
12
|
+
|
|
13
|
+
**A crash after a successful load still belongs on the row.** A browser half can load, answer `cordis_run` with ok, and only then throw when React renders it — the teaching error for a mistake like reaching for `setInterval` reaches the browser console, which neither the model nor the person watching the panel reads. So the row carries the runner's last render failure for this page inline, in the same slot as a load failure: one is "it never loaded", the other "it loaded and then threw", and a row can honestly show both. The line names the seat that crashed and answers the question that follows from it — whether anything of theirs is still on screen: a shadowing seat retires the crashed entry and the shipped UI comes back, while a chain entry keeps its place and its UI may simply be incomplete.
|
|
14
|
+
|
|
15
|
+
Neither surface keeps run state in component state — settling a define call moves its card in the chat flow, which remounts it. Facts live in observables owned by whoever can close them: the browser-side runner owns open requests, orchestration outcomes (it resolves them, including when another page answers first), this page's live set and its render failures — it is the only party watching `slots.onEntryError` and the only one that can map a crashed entry back to the package that registered it — and this package owns the inventory it read and the announcements it folded.
|
|
16
|
+
|
|
17
|
+
The `/client` export surface is the plugin body (`apply`/`inject`) plus the injected face, run-state, port and event payload types.
|
|
18
|
+
|
|
19
|
+
## Model Experience
|
|
20
|
+
|
|
21
|
+
Indirectly, through the run and stop verbs these surfaces drive — the browser-side runner's orchestration for a run, and `dynamicCordisRunner.stop` for a stop, the same host verbs the model's `cordis_run` and `cordis_stop` tools reach — so whatever a running definition then contributes is the runner's effect while nothing model-visible originates in this package, which renders logged call/result slices and a host inventory read, adds no prompt content, writes no session event, and deliberately leaves no session-log trace of a person approving, declining, running or stopping anything.
|
|
22
|
+
|
|
23
|
+
#### KV Cache effect
|
|
24
|
+
|
|
25
|
+
None: no prompt input originates here, and answering a run request neither extends nor rewrites the history tail.
|
|
26
|
+
|
|
27
|
+
## Known Limitations and Deferred Work
|
|
28
|
+
|
|
29
|
+
- **An open panel does not see registry changes that announce nothing** — `cordis_define`, and an undefine of a definition that was not running, change the registry without a dispatch announcement, so a panel left open across one of them keeps its rows until it is closed and opened again (opening re-reads). A run request is the exception, because it blocks the model: it both renders its own row and triggers a read. Acting on a row the host no longer holds is still honest: the call answers `definition-missing` and the row goes terminal. Polling while open was considered and rejected as the wrong price for it.
|
|
30
|
+
- **A request-only row is answerable but not operable** — it offers approve/decline only, because the run/stop switch needs the registry row the read has yet to deliver. Grouping and copy are unaffected (the ask carries the session, label and reason).
|
|
31
|
+
- **A row disappears for the width of one read if its orchestration outruns it** — the activity's orchestrating arm carries the session but no label, deliberately: a user-initiated run has no ask to take one from, and naming the row after its id would be worse than briefly omitting it. So an approved request whose registry read has not landed leaves no row until it does. In practice the read is triggered when the request arrives, so it has almost always landed by the time anyone answers.
|
|
32
|
+
- **A render failure is this page's own reading, and it arrives too late for the run receipt** — the panel shows the last crash the runner saw HERE, so a package that renders fine in this tab shows nothing even while it crashes in another. It also cannot appear in `cordis_run`'s answer: rendering happens after the run settles, so the model learns about it by asking (`cordis_inspect what:"temporary"`) rather than from the call it already made.
|
|
33
|
+
- **A second page's load failure is invisible to the others** — the host settles a dispatch on the first load report and records later ones without acting, so a page whose browser half failed after another page acknowledged keeps reading as running. That page sees the reason on its own row (the runner reports it); the others cannot.
|
|
34
|
+
- **Any page may answer any request** — approvals are frame-wide by design, so a person in one browser tab can approve a run the model asked for while another tab is in front of the defining session. First answer wins and the rest converge; narrowing who may answer is deferred.
|
|
35
|
+
- **A card whose call head left the event window loses its labels** — the card derives name and purpose from the call arguments, so a session long enough to truncate them leaves it naming its call id. The panel is unaffected: the host inventory carries the labels.
|
|
36
|
+
- **Window truncation degrades the unloaded reading** — the card calls a definition unloaded from a successful `cordis_undefine` in this session's log; a session long enough to push that result out of the window shows the definition as merely not running.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-client-ui-cordis
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
Cordis 动态插件的浏览器半:一个覆盖整个框架的面板,操作 host 持有的全部定义;以及一张只读的 `cordis_define` 卡片,记录某个会话定义了什么。
|
|
6
|
+
|
|
7
|
+
**面板做成全局是刻意的。** 模型发起的 `cordis_run` 会在 host 侧阻塞于一次 `cordis/request-run` 往返,而它的答案是**有人按下允许**;并且它可能指向一个当前没人在看的会话里的定义——审批入口若只存在于那个会话的对话流里,就会在它正阻塞模型的时候恰好不可达。所以应答面是一个 `shell.overlay` 条目(本包为 `ui-layout` 补的通用「框架级悬浮席位」,不是自建 React root):角标计数 = 在跑数 + 待确认数,点开后列出每个定义及其运行控件。列表**同理**从不按会话过滤;当前会话的行置顶成组,其他会话的行仍在下方列出。行来自 host 的全局 `inventory` 调用,并在公告改变「有哪些定义」时**重读而非打补丁**——因为公告不携带名字与用途。而那次读取覆盖不到的开放请求**仍然有行**:直接用运行活动自带的会话、标题、用途与请求标识渲染——`cordis_define` 不广播任何东西,所以在上一次读取之后定义的包,对本页是未知的,而它的请求已经在阻塞模型;此时角标数着一个列表给不出的答案,就等于把模型困死。这样一个请求还会额外触发一次注册表读取,把运行控件补给该行。**归组只读每行上一个已解析好的字段**——有活动的 run 用它自己的会话,其余用注册表行的——而不是按阶段去问不同的 store;活动的**两条臂都带这个字段**,所以应答一个请求不会让它的行跳出人刚刚操作的那一组。组内,阻塞着模型的行排在最前。
|
|
8
|
+
|
|
9
|
+
**卡片是一份记录。** 它显示模型写下的 name 与 purpose、它写的源码,以及那个定义是否在跑——没有开关、没有审批,只有一句指向面板的指引。素材只取自冻结的 call/result 切片(标签取自 `argsRaw`,host 铸出的 id 取自结果的 `meta.id`),因此 replay 渲染出同一张卡;而有一个读数天生属于卡片:本会话日志里成功的 `cordis_undefine` 是持久且终态的,它**压过 wire**——在 wire 上,retract 公告与一次普通 stop 长得一模一样。
|
|
10
|
+
|
|
11
|
+
**一行同时读两个互相独立的事实。** 「host 在跑什么」来自 inventory,「**本页**装载了什么」来自 runner 的 live set。每次刷新这两者必然分叉:host 照旧跑着全部,而全新页面什么都没装。host 在跑且本页已装的行,给出全局 stop;host 在跑但本页**没装**的行,先给「装回本页」、再给那个 stop——**两个独立控件**,因为「把浏览器半装到本页」与「为所有页面停掉这个定义」是两件不同的事。**只有 host 半的定义完全不参与这一套**:它没有浏览器半可装,「本页没装」就是它永远的样子,所以它的行如实读作「运行中」,并且只给 stop。未运行时它给出的是一个如实标注的「运行」——本页什么都不会装进来,控件就不这么说——而 run 请求把 `hasClientHalf` 一路带给 runner,正是这一位让它只起 host 半、不去取浏览器半。把这两个事实塌缩成 host 的 `running` 一个,会让刷新后的页面只剩全局 stop,于是文档写明的刷新恢复路径(拉 inventory、把定义装回本页)**没有任何控件可走**。
|
|
12
|
+
|
|
13
|
+
**装载成功之后的崩溃,同样属于这一行。** 浏览器半可以装载成功、让 `cordis_run` 答 ok,之后才在 React 渲染它时抛出异常——像误用 `setInterval` 这类错误的教学文案只会落到浏览器控制台,而模型和看着面板的人都不读那里。所以该行会把 runner 记下的、属于本页的最后一次渲染失败就地显示在行内,与装载失败共用同一个位置:一个是「它从来没装上」,另一个是「它装上了、然后抛了」,而一行可以如实地把两者都显示出来。这行文案会点名崩溃的那个座位,并回答随之而来的那个问题——他们的东西还有没有留在屏幕上:遮蔽式座位会让崩溃的条目退场,出厂 UI 随之回来;而 chain 条目会保住自己的位置,它的 UI 可能只是不完整。
|
|
14
|
+
|
|
15
|
+
两个面都不把运行态放进组件 state——define 调用结算时卡片会在聊天流里换位置并重挂。事实活在「谁能关闭它、就归谁」的观察量里:浏览器侧 runner 拥有开放请求、编排结果(是它发出 resolve,包括别的页面先应答的情形)与本页的 live set及其渲染失败——它是唯一在监视 `slots.onEntryError` 的一方,也是唯一能把崩溃的条目映射回注册它的那个包的一方——而本包拥有自己读来的清单与折叠过的公告。
|
|
16
|
+
|
|
17
|
+
`/client` 导出面是插件体(`apply`/`inject`)加注入面、运行态、端口与事件载荷类型。
|
|
18
|
+
|
|
19
|
+
## 模型体验
|
|
20
|
+
|
|
21
|
+
间接影响,经由这两个面驱动的 run 与 stop 动词——run 走浏览器侧 runner 的编排,stop 走 `dynamicCordisRunner.stop`,与模型的 `cordis_run` / `cordis_stop` 工具是同一批 host 动词。因此正在运行的定义随后贡献了什么是 runner 的效果,而本包不产生任何模型可见输入:它只渲染已落日志的 call/result 切片与一次 host 清单读取,不加 prompt 内容、不写会话事件,并刻意不为「有人批准 / 拒绝 / 运行 / 停止」留下会话日志痕迹。
|
|
22
|
+
|
|
23
|
+
#### KV 缓存影响
|
|
24
|
+
|
|
25
|
+
无:没有任何 prompt 输入源自这里,应答一次 run 请求既不延长也不改写历史尾部。
|
|
26
|
+
|
|
27
|
+
## 已知限制与欠账
|
|
28
|
+
|
|
29
|
+
- **已展开的面板看不到「不广播任何东西」的注册表变化** —— `cordis_define`,以及对一个并未在运行的定义执行 undefine,都会改变注册表却不发出下发公告;因此跨过这类变化时,已展开的面板会保留旧行,直到收起再展开(展开即重读)。run 请求是例外,因为它阻塞模型:它既自己渲染出行,也触发一次读取。对一个 host 已不持有的行动手仍然是诚实的:调用会答 `definition-missing`,该行随即转入终态。「展开期间轮询」评估过,代价不值,已否决。
|
|
30
|
+
- **只有请求、没有清单的行可应答但不可操作** —— 它只提供允许/拒绝,因为 run/stop 开关需要那次读取尚未送达的注册表行。归组与文案不受影响(ask 自带会话、标题与用途)。
|
|
31
|
+
- **若编排跑在读取之前,该行会消失一次读取的时长** —— 活动的 orchestrating 臂带会话但**刻意不带标题**:用户自发的 run 根本不存在可取标题的 ask,而拿 id 当名字比短暂缺行更难看。所以一个已批准、但注册表读取尚未落地的请求,在读取落地前没有行。实践中这次读取在请求**到达时**就已触发,所以等到有人应答时它几乎总已落地。
|
|
32
|
+
- **渲染失败是本页自己的读数,而且它来得太晚、赶不上 run 的回执** —— 面板显示的是 runner 在**本页**看到的最后一次崩溃,所以一个在本标签页渲染正常的包,即使正在另一个标签页里崩溃,这里也什么都不显示。它同样不可能出现在 `cordis_run` 的答复里:渲染发生在 run 结算之后,所以模型只能靠主动去问(`cordis_inspect what:"temporary"`)才知道,而不是从它已经发出的那次调用里得知。
|
|
33
|
+
- **某一页的装载失败对其他页不可见** —— host 以首个装载回报结算一次 dispatch,更晚的回报只记录不动作;因此在另一页确认之后浏览器半才失败的页面,仍会读作运行中。那一页能在自己的行上看到原因(runner 会报),其他页看不到。
|
|
34
|
+
- **任何页面都可以应答任何请求** —— 审批按设计是框架级的,所以某个标签页里的人可以批准模型为另一个标签页正在看的会话所发起的 run。首个应答生效、其余收敛;收窄「谁有权应答」延后。
|
|
35
|
+
- **call head 掉出事件窗的卡片会丢掉标签** —— 卡片的 name 与 purpose 取自调用参数,会话长到把它们截断时,卡片只能以自己的 call id 自称。面板不受影响:host 清单携带标签。
|
|
36
|
+
- **窗口截断会降级「已卸载」这个读数** —— 卡片凭本会话日志里成功的 `cordis_undefine` 判定已卸载;会话长到把那条结果挤出窗口时,该定义只会显示为未运行。
|