@monotykamary/dsh-client-ui-subagent 0.1.0-rc.5
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 +34 -0
- package/README.zh.md +34 -0
- package/lib/client.js +710 -0
- package/lib/index.js +11 -0
- package/lib/invariant.js +24 -0
- package/lib/types/client/SubagentCatalogAction.d.ts +18 -0
- package/lib/types/client/SubagentReadOnlyComposer.d.ts +17 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/locales.d.ts +44 -0
- package/lib/types/index.d.ts +9 -0
- package/lib/types/invariant.d.ts +16 -0
- package/package.json +84 -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-subagent/README.md
|
|
5
|
+
README.md: 0ce6b6ec3c87c0d1b77e82eab692282cd00fd03b
|
|
6
|
+
README.zh.md: a6ef89bbb5a5a68d19993a9e7ea80fa89c802799
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @monotykamary/dsh-client-ui-subagent
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Web subagent feature owner: contributes the lazily expandable catalog tree to `conversation.session.header.actions`, reason-specific read-only replacements to the conversation composer chain, and the existing `@` reference source to `ctx.inputTriggers`.
|
|
6
|
+
|
|
7
|
+
The header action reads `subagentsByParent` and session summaries through the standard `useSessions` hook. After a non-empty direct catalog arrives, its trigger counts the complete subagent-only descendant lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. The compact tree remains direct-catalog authoritative: continuable and one-shot rows display mode plus `running`/`inactive` activity and an optional log-backed title, while the trailing column stacks total durable provider usage above active-turn duration. Token totals sum the four disjoint `tokenUsage` buckets. Visual duration stays exact to the second below one day, then uses at most two adjacent units—days/hours, approximate months/days, or approximate years/months—while hover and the accessible name retain the exact day/hour/minute/second value. Duration sums completed `subagentTiming` turns, advances once per second only for an open turn on a running child, and freezes after the child becomes inactive; an interrupted open turn is bounded by its same-cut `active.through`, never by newer session metadata. An unlabeled one-shot row falls back to its session id, while corrupt, unsupported, or unavailable rows remain readable but disabled. Each healthy row's `hasChildren` hint determines disclosure before interaction, so known leaves never show an arrow; a catalog level reserves the disclosure column only when at least one healthy row is a branch, allowing branchless levels to start at the leading status marker. Expanding a branch immediately reserves one disabled loading row per known direct descendant, then lazily replaces them with that child's authoritative catalog. Every visible branch is reported to the runtime so membership frames cause a debounced refresh only where the tree is being consumed. Selecting any depth calls `SessionRuntime.openSubagent()` with the row's exact `{parentSessionId, childSessionId, mode}` address. Component-local state owns tree visibility, expanded branches, keyboard focus, and the running-duration clock. ArrowRight/ArrowLeft expand and collapse branches; ArrowUp/ArrowDown, Home, End, and Escape navigate or close the tree; closing returns focus to the trigger. Styling uses tokens only.
|
|
8
|
+
|
|
9
|
+
A one-shot child always elects a read-only composer that identifies the transcript as a completed execution record. A continuable child does so only when its exact parent is unavailable and the child is not running, with copy explaining the recovery path; while such a child still runs, the selector yields to the ordinary composer, whose input and Send action are disabled but whose independent Stop stays usable, and the takeover returns once it stops. A continuable child with a live parent keeps the ordinary input chrome, whose Session routes prompts through `subagent.prompt`: typing and Send stay available while the child runs because every follow-up joins the child's FIFO inbox, while an independent Stop routes through `subagent.interrupt`. This package never receives host context or calls a model-facing tool. The catalog and composer behavior are specified by the [Web subagent conversations Agent Note](../../../.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md) and the [current-turn interrupt Agent Note](../../../.agents/notes/implemented/feature/2026-08-06-continuable-subagent-interrupt.md).
|
|
10
|
+
|
|
11
|
+
Subagent-origin Session rows are omitted from the ordinary sidebar, so the parent header catalog is their navigation entry point. Ordinary forks remain in the sidebar.
|
|
12
|
+
|
|
13
|
+
The `@` source remains deliberately separate and inert. Candidates are zero-RPC running children from `ctx.sessions.list`; picking one inserts literal `@label ` text, and the codec projects `@label`. It has no command-adjudication hooks and does not resolve labels into continuation addresses.
|
|
14
|
+
|
|
15
|
+
## Model Experience
|
|
16
|
+
|
|
17
|
+
### Subagent label text in the user prompt
|
|
18
|
+
|
|
19
|
+
#### What the model sees
|
|
20
|
+
|
|
21
|
+
Only the legacy `@` reference source affects model input: a picked candidate reaches the ordinary user message as literal `@label`, without a dedicated block or host-side resolution. Catalog browsing, child navigation, and persisted transcript viewing add no prompt section; accepted continuation content becomes a normal FIFO user message through the host subagent adapter.
|
|
22
|
+
|
|
23
|
+
#### Token effect
|
|
24
|
+
|
|
25
|
+
Conditional and append-only: the literal `@label` or a human follow-up adds tokens only to its new user message. Catalog and transcript operations add zero model tokens.
|
|
26
|
+
|
|
27
|
+
#### KV Cache effect
|
|
28
|
+
|
|
29
|
+
Append-only. This package never edits earlier request tokens.
|
|
30
|
+
|
|
31
|
+
## Known Limitations and Deferred Work
|
|
32
|
+
|
|
33
|
+
- **The catalog has no durable outcome** — activity and timing do not distinguish completion, failure, or cancellation, and the UI exposes no Activation identity; stopping is limited to the composer's current-turn Stop for a running continuable child.
|
|
34
|
+
- **`@` references remain display-title text** — duplicate or renamed labels are ambiguous, so they intentionally do not acquire continuation semantics.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @monotykamary/dsh-client-ui-subagent
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
Web subagent 功能 owner:向 `conversation.session.header.actions` 贡献可懒加载展开的目录树,向会话编辑器链贡献按原因区分的只读替代呈现,并保留注册到 `ctx.inputTriggers` 的既有 `@` 引用 source。
|
|
6
|
+
|
|
7
|
+
页头操作通过标准 `useSessions` 钩子读取 `subagentsByParent` 与会话摘要。非空直接目录到达后,其触发器会统计仅含 subagent 的完整后代谱系,在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。紧凑树仍以直接目录为权威依据:可继续和 one-shot 行会显示 mode、`running`/`inactive` 活动状态和由日志支撑的可选 title,尾随列则在上行显示提供方的持久化 token 用量总计,在下行显示活跃轮次耗时。token 用量总计为四个互不重叠的 `tokenUsage` 桶之和。视觉耗时在不足一天时精确到秒,达到一天后则最多使用两个相邻单位——天/小时、近似月份/天或近似年份/月份——而悬停信息与无障碍名称会保留精确的天/小时/分钟/秒数值。耗时会累加已完成的 `subagentTiming` 轮次,仅在运行中 child 存在未结束轮次时每秒递增一次,并在 child 变为 inactive 后冻结;被中断的未结束轮次以其同一切面的 `active.through` 为上界,绝不使用更新的会话元数据。没有 label 的 one-shot 行会回退到其会话 id,而损坏、不受支持或不可用的行仍保持可读但禁用。每个健康行的 `hasChildren` 提示会在交互前决定是否显示展开控件,因此已知叶子节点从不显示箭头;每层目录仅在其中至少一个健康行是分支时才预留展开列,使完全不含分支的层级能从最前面的状态标记开始。展开分支时,会立即为每个已知直接后代预留一行禁用的加载行,随后再用该 child 的权威目录懒加载结果替换这些占位行。每个可见分支都会上报给运行时,使成员帧只在树正被消费的位置触发去抖动刷新。选择任意深度的条目都会使用该行的确切地址 `{parentSessionId, childSessionId, mode}` 调用 `SessionRuntime.openSubagent()`。组件局部状态负责树的可见性、已展开分支、键盘焦点与运行中耗时时钟。ArrowRight/ArrowLeft 展开和折叠分支;ArrowUp/ArrowDown、Home、End 与 Escape 用于导航或关闭树;关闭后焦点返回触发器。样式只使用 token。
|
|
8
|
+
|
|
9
|
+
one-shot child 始终选用只读编辑器,并将 transcript(文本记录)说明为已完成的执行记录。可继续 child 仅在其确切 parent 不可用且 child 未在运行时选用只读编辑器,并以文案说明恢复路径;此类 child 仍在运行期间,selector 会让位给普通编辑器——其输入区与 Send 操作被禁用,但独立的 Stop 保持可用,停止后只读替代恢复。确切 parent 存活时,可继续 child 保留普通输入 chrome,其会话通过 `subagent.prompt` 路由提示词:child 运行期间输入和 Send 保持可用,因为每条后续消息都会进入 child 的 FIFO inbox,而独立的 Stop 经由 `subagent.interrupt` 路由。本包绝不接收宿主上下文,也不调用面向模型的工具。目录与编辑器行为由 [Web subagent 对话 Agent Note](../../../.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md) 与[当前轮次中断 Agent Note](../../../.agents/notes/implemented/feature/2026-08-06-continuable-subagent-interrupt.md) 规定。
|
|
10
|
+
|
|
11
|
+
普通侧边栏会省略带 subagent origin 的会话行,因此 parent 页头目录是它们的导航入口。普通 fork 仍保留在侧边栏中。
|
|
12
|
+
|
|
13
|
+
`@` source 仍然刻意保持独立且惰性。候选是从 `ctx.sessions.list` 零 RPC 得到的运行中 child;pick 会插入字面文本 `@label `,codec 投影为 `@label`。它不参与命令裁决,也不会把 label 解析成继续执行地址。
|
|
14
|
+
|
|
15
|
+
## 模型体验
|
|
16
|
+
|
|
17
|
+
### 用户提示词中的 subagent label 文本
|
|
18
|
+
|
|
19
|
+
#### 模型看到的内容
|
|
20
|
+
|
|
21
|
+
只有旧有 `@` 引用 source 会影响模型输入:pick 的候选以字面文本 `@label` 进入普通用户消息,没有专用内容块或宿主侧解析。浏览目录、导航 child 与查看持久化 transcript 都不会添加提示词 section;已接收的继续交互内容会经宿主 subagent 适配器成为普通 FIFO 用户消息。
|
|
22
|
+
|
|
23
|
+
#### Token 影响
|
|
24
|
+
|
|
25
|
+
有条件且仅追加:字面 `@label` 或用户后续消息只会向对应的新用户消息增加 token。目录与 transcript 操作增加零模型 token。
|
|
26
|
+
|
|
27
|
+
#### KV Cache 影响
|
|
28
|
+
|
|
29
|
+
仅追加。本包绝不改写更早的请求 token。
|
|
30
|
+
|
|
31
|
+
## 已知限制与暂缓事项
|
|
32
|
+
|
|
33
|
+
- **目录没有持久化结果**:活动状态与计时无法区分完成、失败或取消,且 UI 不公开 Activation 身份;停止能力仅限编辑器上针对运行中可继续 child 的当前轮次 Stop。
|
|
34
|
+
- **`@` 引用仍是显示标题文本**:重复或改名后的 label 会有歧义,因此它们刻意不获得继续执行语义。
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "@monotykamary/dsh-client-ui-subagent",
|
|
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 _monotykamary_dsh_client_runtime_client = require("@monotykamary/dsh-client-runtime/client");
|
|
10
|
+
let _monotykamary_dsh_client_ui_primitives = require("@monotykamary/dsh-client-ui-primitives");
|
|
11
|
+
//#region \0dsh-css:/Users/monotykamary/VCS/working-remote/open-source/deepseek-harness/packages/client/ui-subagent/src/client/SubagentCatalogAction.module.css.mjs
|
|
12
|
+
const css$1 = ".F4LKcq_root{position:relative}.F4LKcq_trigger{min-height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;align-items:center;gap:3px;padding:3px 2px;font-size:12px;line-height:18px;display:inline-flex}.F4LKcq_count{margin:0 5px}.F4LKcq_activitySlot{flex:none;width:10px;height:10px;display:inline-flex}.F4LKcq_trigger:hover,.F4LKcq_trigger:focus-visible{color:var(--dsw-alias-label-secondary)}.F4LKcq_trigger svg{transition:transform .12s}.F4LKcq_triggerOpen{transform:rotate(180deg)}.F4LKcq_menu{z-index:100;box-sizing:border-box;background:var(--dsw-specific-menu);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);width:336px;max-width:min(400px,100vw - 32px);max-height:min(560px,100vh - 140px);box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;padding:4px;display:flex;position:absolute;top:calc(100% + 5px);left:0;overflow:auto}.F4LKcq_node{min-width:0;position:relative}.F4LKcq_menu>.F4LKcq_node{margin-left:-3px}.F4LKcq_row{box-sizing:border-box;width:100%;min-height:50px;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:8px;outline:none;align-items:flex-start;gap:8px;padding:7px 8px 7px 11px;font-size:13px;line-height:18px;display:flex;position:relative}.F4LKcq_row:hover>.F4LKcq_clickarea,.F4LKcq_row:focus-visible>.F4LKcq_clickarea{background:var(--dsw-alias-interactive-bg-hover)}.F4LKcq_clickarea{box-sizing:border-box;border-radius:8px;flex:1;align-self:stretch;align-items:flex-start;gap:8px;min-width:0;margin:-7px -8px;padding:7px 8px;display:flex}.F4LKcq_row>[data-state],.F4LKcq_clickarea>[data-state]{margin-top:4px}.F4LKcq_disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.F4LKcq_disabled:hover{background:0 0}.F4LKcq_loadingRow{cursor:default}.F4LKcq_disclosure,.F4LKcq_disclosureSpace{flex:none;width:14px;height:18px}.F4LKcq_disclosure{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;transition:transform .12s;display:inline-flex}.F4LKcq_disclosure:hover{color:var(--dsw-alias-label-primary)}.F4LKcq_disclosureOpen{transform:rotate(90deg)}.F4LKcq_content{flex-direction:column;flex:1;min-width:0;display:flex}.F4LKcq_label,.F4LKcq_summary{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F4LKcq_label{color:inherit;font-weight:400}.F4LKcq_summary,.F4LKcq_metrics{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.F4LKcq_metrics{font-variant-numeric:tabular-nums;text-align:right;white-space:nowrap;flex:none;grid-template-rows:18px 16px;display:grid}.F4LKcq_metricToken{grid-row:1;line-height:18px}.F4LKcq_metricDuration{grid-row:2}.F4LKcq_children{margin-left:18px;padding-left:4px;position:relative}.F4LKcq_children:before,.F4LKcq_children>.F4LKcq_node:before{content:\"\";border-left:1px solid var(--dsw-alias-border-l2);position:absolute;left:0}.F4LKcq_children:before{height:26px;top:-26px}.F4LKcq_children[aria-busy=true]:before{content:none}.F4LKcq_children>.F4LKcq_node:before{top:0;bottom:0;left:-4px}.F4LKcq_children>.F4LKcq_node:last-child:before{height:17px;bottom:auto}.F4LKcq_children>.F4LKcq_node>.F4LKcq_row:before{content:\"\";border-top:1px solid var(--dsw-alias-border-l2);width:14px;position:absolute;top:16px;left:-4px}.F4LKcq_notice,.F4LKcq_error{color:var(--dsw-alias-label-tertiary);padding:10px 12px;font-size:12px;line-height:18px}.F4LKcq_error{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;display:flex}.F4LKcq_refresh{color:inherit;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;align-items:center;gap:4px;padding:4px 6px;display:inline-flex}.F4LKcq_refresh:hover{background:var(--dsw-alias-interactive-bg-hover)}";
|
|
13
|
+
const tagId$1 = "@monotykamary/dsh-client-ui-subagent/SubagentCatalogAction.module.css";
|
|
14
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
15
|
+
const tag = document.createElement("style");
|
|
16
|
+
tag.dataset.plugin = "@monotykamary/dsh-client-ui-subagent";
|
|
17
|
+
tag.dataset.pluginCss = tagId$1;
|
|
18
|
+
tag.textContent = css$1;
|
|
19
|
+
document.head.appendChild(tag);
|
|
20
|
+
}
|
|
21
|
+
var SubagentCatalogAction_module_css_default = {
|
|
22
|
+
"disabled": "F4LKcq_disabled",
|
|
23
|
+
"summary": "F4LKcq_summary",
|
|
24
|
+
"disclosureOpen": "F4LKcq_disclosureOpen",
|
|
25
|
+
"label": "F4LKcq_label",
|
|
26
|
+
"root": "F4LKcq_root",
|
|
27
|
+
"content": "F4LKcq_content",
|
|
28
|
+
"clickarea": "F4LKcq_clickarea",
|
|
29
|
+
"refresh": "F4LKcq_refresh",
|
|
30
|
+
"triggerOpen": "F4LKcq_triggerOpen",
|
|
31
|
+
"count": "F4LKcq_count",
|
|
32
|
+
"trigger": "F4LKcq_trigger",
|
|
33
|
+
"metricToken": "F4LKcq_metricToken",
|
|
34
|
+
"children": "F4LKcq_children",
|
|
35
|
+
"notice": "F4LKcq_notice",
|
|
36
|
+
"error": "F4LKcq_error",
|
|
37
|
+
"disclosureSpace": "F4LKcq_disclosureSpace",
|
|
38
|
+
"row": "F4LKcq_row",
|
|
39
|
+
"menu": "F4LKcq_menu",
|
|
40
|
+
"disclosure": "F4LKcq_disclosure",
|
|
41
|
+
"node": "F4LKcq_node",
|
|
42
|
+
"activitySlot": "F4LKcq_activitySlot",
|
|
43
|
+
"loadingRow": "F4LKcq_loadingRow",
|
|
44
|
+
"metrics": "F4LKcq_metrics",
|
|
45
|
+
"metricDuration": "F4LKcq_metricDuration"
|
|
46
|
+
};
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region lib/types/client/SubagentCatalogAction.js
|
|
49
|
+
function diagnosticReason(entry, t) {
|
|
50
|
+
switch (entry.reason) {
|
|
51
|
+
case "corrupt": return t("diagnostic.corrupt");
|
|
52
|
+
case "unsupported": return t("diagnostic.unsupported");
|
|
53
|
+
case "unavailable": return t("diagnostic.unavailable");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function treeItems(root) {
|
|
57
|
+
return root === null ? [] : Array.from(root.querySelectorAll("[role=\"treeitem\"]:not([aria-disabled=\"true\"])"));
|
|
58
|
+
}
|
|
59
|
+
/** Compact token count shared in shape with the conversation stats strip. */
|
|
60
|
+
function formatTokens(value) {
|
|
61
|
+
const scaled = (next) => next >= 100 ? String(Math.round(next)) : String(Math.round(next * 10) / 10);
|
|
62
|
+
if (value < 1e3) return String(value);
|
|
63
|
+
if (value < 1e6) return `${scaled(value / 1e3)}K`;
|
|
64
|
+
return `${scaled(value / 1e6)}M`;
|
|
65
|
+
}
|
|
66
|
+
/** Sum the four disjoint durable provider-usage buckets. */
|
|
67
|
+
function tokenTotal(usage) {
|
|
68
|
+
return usage === void 0 ? void 0 : usage.uncachedInputTokens + usage.outputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
69
|
+
}
|
|
70
|
+
/** Exact whole-second active-turn duration for one catalog row. */
|
|
71
|
+
function activityDuration(summary, activity, now) {
|
|
72
|
+
if (summary === void 0) return void 0;
|
|
73
|
+
const timing = summary.projectionValues?.subagentTiming;
|
|
74
|
+
if (timing === void 0) return void 0;
|
|
75
|
+
if (timing.active === void 0) return timing.settledMs;
|
|
76
|
+
const end = activity === "running" ? now : timing.active.through;
|
|
77
|
+
return timing.settledMs + Math.max(0, end - timing.active.since);
|
|
78
|
+
}
|
|
79
|
+
function splitDuration(ms) {
|
|
80
|
+
const totalSeconds = Math.floor(Math.max(0, ms) / 1e3);
|
|
81
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
82
|
+
const totalHours = Math.floor(totalMinutes / 60);
|
|
83
|
+
return {
|
|
84
|
+
seconds: totalSeconds % 60,
|
|
85
|
+
minutes: totalMinutes % 60,
|
|
86
|
+
hours: totalHours % 24,
|
|
87
|
+
days: Math.floor(totalHours / 24),
|
|
88
|
+
totalMinutes,
|
|
89
|
+
totalHours
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** Format a duration with decreasing visual precision at larger scales. */
|
|
93
|
+
function formatDuration(ms, t) {
|
|
94
|
+
const { seconds, minutes, hours, days, totalMinutes, totalHours } = splitDuration(ms);
|
|
95
|
+
if (days >= 365) {
|
|
96
|
+
const years = Math.floor(days / 365);
|
|
97
|
+
const months = Math.floor(days % 365 / 30);
|
|
98
|
+
return months === 0 ? t("duration.years", { years }) : t("duration.yearsMonths", {
|
|
99
|
+
years,
|
|
100
|
+
months
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (days >= 30) {
|
|
104
|
+
const months = Math.floor(days / 30);
|
|
105
|
+
const remainingDays = days % 30;
|
|
106
|
+
return remainingDays === 0 ? t("duration.months", { months }) : t("duration.monthsDays", {
|
|
107
|
+
months,
|
|
108
|
+
days: remainingDays
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (days > 0) return hours === 0 ? t("duration.days", { days }) : t("duration.daysHours", {
|
|
112
|
+
days,
|
|
113
|
+
hours
|
|
114
|
+
});
|
|
115
|
+
if (totalHours > 0) return t("duration.hours", {
|
|
116
|
+
hours: totalHours,
|
|
117
|
+
minutes: String(minutes).padStart(2, "0"),
|
|
118
|
+
seconds: String(seconds).padStart(2, "0")
|
|
119
|
+
});
|
|
120
|
+
if (totalMinutes > 0) return t("duration.minutes", {
|
|
121
|
+
minutes: totalMinutes,
|
|
122
|
+
seconds: String(seconds).padStart(2, "0")
|
|
123
|
+
});
|
|
124
|
+
return t("duration.seconds", { seconds });
|
|
125
|
+
}
|
|
126
|
+
/** Preserve exact whole seconds for hover and accessible naming. */
|
|
127
|
+
function formatExactDuration(ms, t) {
|
|
128
|
+
const { seconds, minutes, hours, days } = splitDuration(ms);
|
|
129
|
+
return days === 0 ? formatDuration(ms, t) : t("duration.exactDays", {
|
|
130
|
+
days,
|
|
131
|
+
hours: String(hours).padStart(2, "0"),
|
|
132
|
+
minutes: String(minutes).padStart(2, "0"),
|
|
133
|
+
seconds: String(seconds).padStart(2, "0")
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const NO_DESCENDANTS = {
|
|
137
|
+
count: 0,
|
|
138
|
+
runningCount: 0
|
|
139
|
+
};
|
|
140
|
+
/** Render the known direct-child shape while its authoritative catalog hydrates. */
|
|
141
|
+
function CatalogLoadingRows({ parentSessionId, summaries, level, t }) {
|
|
142
|
+
const children = Object.values(summaries).filter((summary) => summary.origin === "subagent" && summary.parentId === parentSessionId);
|
|
143
|
+
if (children.length === 0) return (0, react_jsx_runtime.jsx)("div", {
|
|
144
|
+
className: SubagentCatalogAction_module_css_default.notice,
|
|
145
|
+
children: t("loading.label")
|
|
146
|
+
});
|
|
147
|
+
return children.map((summary) => (0, react_jsx_runtime.jsx)("div", {
|
|
148
|
+
className: SubagentCatalogAction_module_css_default.node,
|
|
149
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
150
|
+
role: "treeitem",
|
|
151
|
+
"aria-disabled": "true",
|
|
152
|
+
"aria-level": level,
|
|
153
|
+
"aria-label": t("loading.aria"),
|
|
154
|
+
className: `${SubagentCatalogAction_module_css_default.row} ${SubagentCatalogAction_module_css_default.disabled} ${SubagentCatalogAction_module_css_default.loadingRow}`,
|
|
155
|
+
children: [
|
|
156
|
+
(0, react_jsx_runtime.jsx)("span", { className: SubagentCatalogAction_module_css_default.disclosureSpace }),
|
|
157
|
+
(0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.StateDot, { state: summary.running ? "ongoing" : "done" }),
|
|
158
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
159
|
+
className: SubagentCatalogAction_module_css_default.content,
|
|
160
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
161
|
+
className: SubagentCatalogAction_module_css_default.label,
|
|
162
|
+
children: t("loading.label")
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
]
|
|
166
|
+
})
|
|
167
|
+
}, summary.id));
|
|
168
|
+
}
|
|
169
|
+
/** Render one catalog level and recurse only through explicitly expanded rows. */
|
|
170
|
+
function CatalogRows({ parentSessionId, catalog, catalogs, summaries, expanded, level, now, openChild, refresh, toggleBranch, closeCatalog, t }) {
|
|
171
|
+
const emptyLoading = catalog.state === "loading" && catalog.entries.length === 0;
|
|
172
|
+
const reserveDisclosure = catalog.entries.some((entry) => entry.kind === "child" && entry.hasChildren);
|
|
173
|
+
return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
174
|
+
emptyLoading && (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
|
|
175
|
+
parentSessionId,
|
|
176
|
+
summaries,
|
|
177
|
+
level,
|
|
178
|
+
t
|
|
179
|
+
}),
|
|
180
|
+
catalog.state === "error" && (0, react_jsx_runtime.jsxs)("div", {
|
|
181
|
+
className: SubagentCatalogAction_module_css_default.error,
|
|
182
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: catalog.error?.message ?? t("load.error") }), (0, react_jsx_runtime.jsxs)("button", {
|
|
183
|
+
type: "button",
|
|
184
|
+
className: SubagentCatalogAction_module_css_default.refresh,
|
|
185
|
+
onClick: () => {
|
|
186
|
+
refresh(parentSessionId);
|
|
187
|
+
},
|
|
188
|
+
children: [(0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.IconRefreshOutline14, {}), t("retry")]
|
|
189
|
+
})]
|
|
190
|
+
}),
|
|
191
|
+
catalog.entries.map((entry) => {
|
|
192
|
+
if (entry.kind === "diagnostic") {
|
|
193
|
+
const reason = diagnosticReason(entry, t);
|
|
194
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
195
|
+
className: SubagentCatalogAction_module_css_default.node,
|
|
196
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
197
|
+
role: "treeitem",
|
|
198
|
+
"aria-disabled": "true",
|
|
199
|
+
"aria-level": level,
|
|
200
|
+
"aria-label": `${entry.id} ${reason}`,
|
|
201
|
+
className: `${SubagentCatalogAction_module_css_default.row} ${SubagentCatalogAction_module_css_default.disabled}`,
|
|
202
|
+
title: reason,
|
|
203
|
+
children: [
|
|
204
|
+
reserveDisclosure && (0, react_jsx_runtime.jsx)("span", { className: SubagentCatalogAction_module_css_default.disclosureSpace }),
|
|
205
|
+
(0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.StateDot, { state: "error" }),
|
|
206
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
207
|
+
className: SubagentCatalogAction_module_css_default.content,
|
|
208
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
209
|
+
className: SubagentCatalogAction_module_css_default.label,
|
|
210
|
+
children: entry.id
|
|
211
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
212
|
+
className: SubagentCatalogAction_module_css_default.summary,
|
|
213
|
+
children: reason
|
|
214
|
+
})]
|
|
215
|
+
})
|
|
216
|
+
]
|
|
217
|
+
})
|
|
218
|
+
}, entry.id);
|
|
219
|
+
}
|
|
220
|
+
const childCatalog = catalogs[entry.id];
|
|
221
|
+
const isExpanded = expanded.has(entry.id);
|
|
222
|
+
const knownLeaf = !entry.hasChildren;
|
|
223
|
+
const childLoading = childCatalog === void 0 || childCatalog.state === "loading" && childCatalog.entries.length === 0;
|
|
224
|
+
const summary = summaries[entry.id];
|
|
225
|
+
const label = entry.label ?? entry.id;
|
|
226
|
+
const mode = entry.mode === "one-shot" ? t("mode.oneShot") : t("mode.continuable");
|
|
227
|
+
const activity = entry.activity === "running" ? t("activity.running") : t("activity.inactive");
|
|
228
|
+
const secondary = [
|
|
229
|
+
summary?.title,
|
|
230
|
+
mode,
|
|
231
|
+
activity
|
|
232
|
+
].filter((value) => value !== void 0).join(" · ");
|
|
233
|
+
const totalTokens = tokenTotal(summary?.projectionValues?.tokenUsage);
|
|
234
|
+
const durationMs = activityDuration(summary, entry.activity, now);
|
|
235
|
+
const tokenMetric = totalTokens === void 0 ? void 0 : `${formatTokens(totalTokens)} tok`;
|
|
236
|
+
const durationMetric = durationMs === void 0 ? void 0 : {
|
|
237
|
+
compact: formatDuration(durationMs, t),
|
|
238
|
+
exact: formatExactDuration(durationMs, t)
|
|
239
|
+
};
|
|
240
|
+
const metrics = [tokenMetric, durationMetric?.exact].filter((value) => value !== void 0).join(" · ");
|
|
241
|
+
const open = () => {
|
|
242
|
+
openChild({
|
|
243
|
+
parentSessionId,
|
|
244
|
+
childSessionId: entry.id,
|
|
245
|
+
mode: entry.mode
|
|
246
|
+
});
|
|
247
|
+
closeCatalog();
|
|
248
|
+
};
|
|
249
|
+
const handleKey = (event) => {
|
|
250
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
251
|
+
event.preventDefault();
|
|
252
|
+
event.stopPropagation();
|
|
253
|
+
open();
|
|
254
|
+
} else if (event.key === "ArrowRight" && !knownLeaf && !isExpanded || event.key === "ArrowLeft" && isExpanded) {
|
|
255
|
+
event.preventDefault();
|
|
256
|
+
event.stopPropagation();
|
|
257
|
+
toggleBranch(entry.id);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const toggle = (event) => {
|
|
261
|
+
event.preventDefault();
|
|
262
|
+
event.stopPropagation();
|
|
263
|
+
toggleBranch(entry.id);
|
|
264
|
+
};
|
|
265
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
266
|
+
className: SubagentCatalogAction_module_css_default.node,
|
|
267
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
268
|
+
role: "treeitem",
|
|
269
|
+
tabIndex: 0,
|
|
270
|
+
"aria-level": level,
|
|
271
|
+
"aria-label": [
|
|
272
|
+
label,
|
|
273
|
+
secondary,
|
|
274
|
+
metrics
|
|
275
|
+
].filter((value) => value !== "").join(" "),
|
|
276
|
+
...knownLeaf ? {} : { "aria-expanded": isExpanded },
|
|
277
|
+
className: SubagentCatalogAction_module_css_default.row,
|
|
278
|
+
onClick: open,
|
|
279
|
+
onKeyDown: handleKey,
|
|
280
|
+
children: [knownLeaf ? reserveDisclosure && (0, react_jsx_runtime.jsx)("span", { className: SubagentCatalogAction_module_css_default.disclosureSpace }) : (0, react_jsx_runtime.jsx)("button", {
|
|
281
|
+
type: "button",
|
|
282
|
+
tabIndex: -1,
|
|
283
|
+
className: `${SubagentCatalogAction_module_css_default.disclosure} ${isExpanded ? SubagentCatalogAction_module_css_default.disclosureOpen : ""}`,
|
|
284
|
+
"aria-label": t(isExpanded ? "branch.collapse" : "branch.expand", { label }),
|
|
285
|
+
onClick: toggle,
|
|
286
|
+
children: (0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.IconChevronRightOutline14, {})
|
|
287
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
288
|
+
className: SubagentCatalogAction_module_css_default.clickarea,
|
|
289
|
+
children: [
|
|
290
|
+
(0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.StateDot, { state: entry.activity === "running" ? "ongoing" : "done" }),
|
|
291
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
292
|
+
className: SubagentCatalogAction_module_css_default.content,
|
|
293
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
294
|
+
className: SubagentCatalogAction_module_css_default.label,
|
|
295
|
+
children: label
|
|
296
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
297
|
+
className: SubagentCatalogAction_module_css_default.summary,
|
|
298
|
+
children: secondary
|
|
299
|
+
})]
|
|
300
|
+
}),
|
|
301
|
+
metrics !== "" && (0, react_jsx_runtime.jsxs)("span", {
|
|
302
|
+
className: SubagentCatalogAction_module_css_default.metrics,
|
|
303
|
+
children: [tokenMetric !== void 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
304
|
+
className: SubagentCatalogAction_module_css_default.metricToken,
|
|
305
|
+
children: tokenMetric
|
|
306
|
+
}), durationMetric !== void 0 && (0, react_jsx_runtime.jsx)("span", {
|
|
307
|
+
className: SubagentCatalogAction_module_css_default.metricDuration,
|
|
308
|
+
title: t("duration.exactTitle", { duration: durationMetric.exact }),
|
|
309
|
+
children: durationMetric.compact
|
|
310
|
+
})]
|
|
311
|
+
})
|
|
312
|
+
]
|
|
313
|
+
})]
|
|
314
|
+
}), isExpanded && !knownLeaf && (0, react_jsx_runtime.jsx)("div", {
|
|
315
|
+
role: "group",
|
|
316
|
+
className: SubagentCatalogAction_module_css_default.children,
|
|
317
|
+
"aria-busy": childLoading || void 0,
|
|
318
|
+
children: childCatalog === void 0 ? (0, react_jsx_runtime.jsx)(CatalogLoadingRows, {
|
|
319
|
+
parentSessionId: entry.id,
|
|
320
|
+
summaries,
|
|
321
|
+
level: level + 1,
|
|
322
|
+
t
|
|
323
|
+
}) : (0, react_jsx_runtime.jsx)(CatalogRows, {
|
|
324
|
+
parentSessionId: entry.id,
|
|
325
|
+
catalog: childCatalog,
|
|
326
|
+
catalogs,
|
|
327
|
+
summaries,
|
|
328
|
+
expanded,
|
|
329
|
+
level: level + 1,
|
|
330
|
+
now,
|
|
331
|
+
openChild,
|
|
332
|
+
refresh,
|
|
333
|
+
toggleBranch,
|
|
334
|
+
closeCatalog,
|
|
335
|
+
t
|
|
336
|
+
})
|
|
337
|
+
})]
|
|
338
|
+
}, entry.id);
|
|
339
|
+
})
|
|
340
|
+
] });
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Render the current session's direct catalog and lazily expanded descendants.
|
|
344
|
+
* @param props - session standard props plus catalog navigation actions.
|
|
345
|
+
* @returns The action while the catalog is pending or summaries establish descendants.
|
|
346
|
+
*/
|
|
347
|
+
function SubagentCatalogAction({ sessionId, useSessions, openChild, refresh, setCatalogOpen, t }) {
|
|
348
|
+
const catalogs = useSessions((state) => state.subagentsByParent);
|
|
349
|
+
const summaries = useSessions((state) => state.byId);
|
|
350
|
+
const catalog = catalogs[sessionId];
|
|
351
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
352
|
+
const [now, setNow] = (0, react.useState)(() => Date.now());
|
|
353
|
+
const [expanded, setExpanded] = (0, react.useState)(() => /* @__PURE__ */ new Set());
|
|
354
|
+
const rootRef = (0, react.useRef)(null);
|
|
355
|
+
const triggerRef = (0, react.useRef)(null);
|
|
356
|
+
const observedCatalogs = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
357
|
+
const setCatalogOpenRef = (0, react.useRef)(setCatalogOpen);
|
|
358
|
+
setCatalogOpenRef.current = setCatalogOpen;
|
|
359
|
+
const healthy = catalog?.entries.filter((entry) => entry.kind === "child") ?? [];
|
|
360
|
+
const descendants = (0, react.useMemo)(() => (0, _monotykamary_dsh_client_runtime_client.indexSubagentDescendants)(summaries).get(sessionId) ?? NO_DESCENDANTS, [sessionId, summaries]);
|
|
361
|
+
const descendantCount = Math.max(healthy.length, descendants.count);
|
|
362
|
+
const totalCountKey = descendantCount === 1 ? "count.total.one" : "count.total.other";
|
|
363
|
+
const runningCountKey = descendants.runningCount === 1 ? "count.running.one" : "count.running.other";
|
|
364
|
+
const presentedCatalog = descendants.count > 0 && (catalog === void 0 || catalog.state === "ready" && catalog.entries.length === 0) ? {
|
|
365
|
+
entries: [],
|
|
366
|
+
parentAvailable: catalog?.parentAvailable ?? false,
|
|
367
|
+
state: "loading",
|
|
368
|
+
error: null
|
|
369
|
+
} : catalog;
|
|
370
|
+
const observeCatalog = (parentSessionId, next) => {
|
|
371
|
+
if (next) observedCatalogs.current.add(parentSessionId);
|
|
372
|
+
else observedCatalogs.current.delete(parentSessionId);
|
|
373
|
+
setCatalogOpen(parentSessionId, next);
|
|
374
|
+
};
|
|
375
|
+
const closeAllCatalogs = () => {
|
|
376
|
+
for (const parentSessionId of observedCatalogs.current) setCatalogOpen(parentSessionId, false);
|
|
377
|
+
observedCatalogs.current.clear();
|
|
378
|
+
setExpanded(/* @__PURE__ */ new Set());
|
|
379
|
+
};
|
|
380
|
+
const changeOpen = (next, restoreFocus = false) => {
|
|
381
|
+
setOpen(next);
|
|
382
|
+
if (next) {
|
|
383
|
+
setNow(Date.now());
|
|
384
|
+
observeCatalog(sessionId, true);
|
|
385
|
+
} else closeAllCatalogs();
|
|
386
|
+
if (restoreFocus) queueMicrotask(() => {
|
|
387
|
+
triggerRef.current?.focus();
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
const closeBranch = (root) => {
|
|
391
|
+
const closing = /* @__PURE__ */ new Set();
|
|
392
|
+
const visit = (parentSessionId) => {
|
|
393
|
+
if (closing.has(parentSessionId) || !expanded.has(parentSessionId)) return;
|
|
394
|
+
closing.add(parentSessionId);
|
|
395
|
+
const branch = catalogs[parentSessionId];
|
|
396
|
+
for (const entry of branch?.entries ?? []) if (entry.kind === "child") visit(entry.id);
|
|
397
|
+
};
|
|
398
|
+
visit(root);
|
|
399
|
+
for (const parentSessionId of closing) observeCatalog(parentSessionId, false);
|
|
400
|
+
setExpanded((current) => new Set([...current].filter((id) => !closing.has(id))));
|
|
401
|
+
};
|
|
402
|
+
const toggleBranch = (childSessionId) => {
|
|
403
|
+
if (expanded.has(childSessionId)) {
|
|
404
|
+
closeBranch(childSessionId);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
setExpanded((current) => new Set(current).add(childSessionId));
|
|
408
|
+
observeCatalog(childSessionId, true);
|
|
409
|
+
};
|
|
410
|
+
(0, react.useEffect)(() => {
|
|
411
|
+
if (!open) return;
|
|
412
|
+
const closeOutside = (event) => {
|
|
413
|
+
if (event.target instanceof Node && !rootRef.current?.contains(event.target)) changeOpen(false);
|
|
414
|
+
};
|
|
415
|
+
document.addEventListener("pointerdown", closeOutside);
|
|
416
|
+
return () => {
|
|
417
|
+
document.removeEventListener("pointerdown", closeOutside);
|
|
418
|
+
};
|
|
419
|
+
}, [open]);
|
|
420
|
+
(0, react.useEffect)(() => {
|
|
421
|
+
if (!open || descendants.runningCount === 0) return;
|
|
422
|
+
const timer = setInterval(() => {
|
|
423
|
+
setNow(Date.now());
|
|
424
|
+
}, 1e3);
|
|
425
|
+
return () => {
|
|
426
|
+
clearInterval(timer);
|
|
427
|
+
};
|
|
428
|
+
}, [open, descendants.runningCount]);
|
|
429
|
+
(0, react.useEffect)(() => () => {
|
|
430
|
+
for (const parentSessionId of observedCatalogs.current) setCatalogOpenRef.current(parentSessionId, false);
|
|
431
|
+
observedCatalogs.current.clear();
|
|
432
|
+
}, []);
|
|
433
|
+
const visible = presentedCatalog !== void 0 && (presentedCatalog.state === "error" || presentedCatalog.entries.length > 0 || descendantCount > 0);
|
|
434
|
+
(0, react.useEffect)(() => {
|
|
435
|
+
if (visible || !open) return;
|
|
436
|
+
setOpen(false);
|
|
437
|
+
closeAllCatalogs();
|
|
438
|
+
}, [visible, open]);
|
|
439
|
+
if (!visible) return null;
|
|
440
|
+
const focusAt = (index) => {
|
|
441
|
+
const items = treeItems(rootRef.current);
|
|
442
|
+
if (items.length === 0) return;
|
|
443
|
+
items[(index + items.length) % items.length]?.focus();
|
|
444
|
+
};
|
|
445
|
+
const navigate = (event) => {
|
|
446
|
+
const items = treeItems(rootRef.current);
|
|
447
|
+
const index = items.indexOf(document.activeElement);
|
|
448
|
+
if (event.key === "Escape") {
|
|
449
|
+
event.preventDefault();
|
|
450
|
+
changeOpen(false, true);
|
|
451
|
+
} else if (event.key === "Home") {
|
|
452
|
+
event.preventDefault();
|
|
453
|
+
focusAt(0);
|
|
454
|
+
} else if (event.key === "End") {
|
|
455
|
+
event.preventDefault();
|
|
456
|
+
focusAt(items.length - 1);
|
|
457
|
+
} else if (event.key === "ArrowDown") {
|
|
458
|
+
event.preventDefault();
|
|
459
|
+
focusAt(index + 1);
|
|
460
|
+
} else if (event.key === "ArrowUp") {
|
|
461
|
+
event.preventDefault();
|
|
462
|
+
focusAt(index < 0 ? items.length - 1 : index - 1);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
466
|
+
className: SubagentCatalogAction_module_css_default.root,
|
|
467
|
+
ref: rootRef,
|
|
468
|
+
onKeyDown: navigate,
|
|
469
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
470
|
+
ref: triggerRef,
|
|
471
|
+
type: "button",
|
|
472
|
+
className: SubagentCatalogAction_module_css_default.trigger,
|
|
473
|
+
"aria-haspopup": "tree",
|
|
474
|
+
"aria-expanded": open,
|
|
475
|
+
"aria-label": t(descendants.runningCount > 0 ? runningCountKey : totalCountKey, { count: descendants.runningCount > 0 ? descendants.runningCount : descendantCount }),
|
|
476
|
+
onClick: () => {
|
|
477
|
+
changeOpen(!open);
|
|
478
|
+
},
|
|
479
|
+
onKeyDown: (event) => {
|
|
480
|
+
if (event.key !== "ArrowDown") return;
|
|
481
|
+
event.preventDefault();
|
|
482
|
+
if (!open) changeOpen(true);
|
|
483
|
+
queueMicrotask(() => {
|
|
484
|
+
focusAt(0);
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
children: [
|
|
488
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
489
|
+
className: SubagentCatalogAction_module_css_default.activitySlot,
|
|
490
|
+
children: descendants.runningCount > 0 && (0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.StateDot, { state: "ongoing" })
|
|
491
|
+
}),
|
|
492
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
493
|
+
className: SubagentCatalogAction_module_css_default.count,
|
|
494
|
+
children: t(totalCountKey, { count: descendantCount })
|
|
495
|
+
}),
|
|
496
|
+
(0, react_jsx_runtime.jsx)(_monotykamary_dsh_client_ui_primitives.IconChevronDownOutline14, { className: open ? SubagentCatalogAction_module_css_default.triggerOpen : void 0 })
|
|
497
|
+
]
|
|
498
|
+
}), open && (0, react_jsx_runtime.jsx)("div", {
|
|
499
|
+
className: SubagentCatalogAction_module_css_default.menu,
|
|
500
|
+
role: "tree",
|
|
501
|
+
"aria-label": t("tree.aria"),
|
|
502
|
+
children: (0, react_jsx_runtime.jsx)(CatalogRows, {
|
|
503
|
+
parentSessionId: sessionId,
|
|
504
|
+
catalog: presentedCatalog,
|
|
505
|
+
catalogs,
|
|
506
|
+
summaries,
|
|
507
|
+
expanded,
|
|
508
|
+
level: 1,
|
|
509
|
+
now,
|
|
510
|
+
openChild,
|
|
511
|
+
refresh,
|
|
512
|
+
toggleBranch,
|
|
513
|
+
closeCatalog: () => {
|
|
514
|
+
changeOpen(false);
|
|
515
|
+
},
|
|
516
|
+
t
|
|
517
|
+
})
|
|
518
|
+
})]
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region \0dsh-css:/Users/monotykamary/VCS/working-remote/open-source/deepseek-harness/packages/client/ui-subagent/src/client/SubagentReadOnlyComposer.module.css.mjs
|
|
523
|
+
const css = ".t4SSma_frame{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-height:54px;color:var(--dsw-alias-label-tertiary);border-radius:14px;justify-content:center;align-items:center;gap:8px;margin:0 24px 20px;padding:10px 16px;font-size:13px;line-height:20px;display:flex}.t4SSma_frame strong{color:var(--dsw-alias-label-primary);font-weight:510}";
|
|
524
|
+
const tagId = "@monotykamary/dsh-client-ui-subagent/SubagentReadOnlyComposer.module.css";
|
|
525
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
526
|
+
const tag = document.createElement("style");
|
|
527
|
+
tag.dataset.plugin = "@monotykamary/dsh-client-ui-subagent";
|
|
528
|
+
tag.dataset.pluginCss = tagId;
|
|
529
|
+
tag.textContent = css;
|
|
530
|
+
document.head.appendChild(tag);
|
|
531
|
+
}
|
|
532
|
+
var SubagentReadOnlyComposer_module_css_default = { "frame": "t4SSma_frame" };
|
|
533
|
+
//#endregion
|
|
534
|
+
//#region lib/types/client/SubagentReadOnlyComposer.js
|
|
535
|
+
/**
|
|
536
|
+
* Explain why the normal composer is unavailable for an addressed child.
|
|
537
|
+
* @param props - selector-owned read-only reason plus standard slot props.
|
|
538
|
+
* @returns A read-only composer replacement.
|
|
539
|
+
*/
|
|
540
|
+
function SubagentReadOnlyComposer({ matched, t }) {
|
|
541
|
+
const oneShot = matched.reason === "one-shot";
|
|
542
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
543
|
+
className: SubagentReadOnlyComposer_module_css_default.frame,
|
|
544
|
+
role: "status",
|
|
545
|
+
children: [(0, react_jsx_runtime.jsx)("strong", { children: t(oneShot ? "readonly.oneShot.title" : "readonly.title") }), (0, react_jsx_runtime.jsx)("span", { children: t(oneShot ? "readonly.oneShot.body" : "readonly.body") })]
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region lib/types/client/locales.js
|
|
550
|
+
/** `subagent` namespace dictionaries. */
|
|
551
|
+
/** Dictionary namespace owned by this plugin. */
|
|
552
|
+
const NS = "subagent";
|
|
553
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
554
|
+
const zh = {
|
|
555
|
+
"diagnostic.corrupt": "会话记录损坏",
|
|
556
|
+
"diagnostic.unsupported": "子代理记录版本不受支持",
|
|
557
|
+
"diagnostic.unavailable": "会话记录暂不可用",
|
|
558
|
+
"duration.seconds": "{seconds}秒",
|
|
559
|
+
"duration.minutes": "{minutes}分{seconds}秒",
|
|
560
|
+
"duration.hours": "{hours}小时{minutes}分{seconds}秒",
|
|
561
|
+
"duration.days": "{days}天",
|
|
562
|
+
"duration.daysHours": "{days}天{hours}小时",
|
|
563
|
+
"duration.months": "约{months}个月",
|
|
564
|
+
"duration.monthsDays": "约{months}个月{days}天",
|
|
565
|
+
"duration.years": "约{years}年",
|
|
566
|
+
"duration.yearsMonths": "约{years}年{months}个月",
|
|
567
|
+
"duration.exactDays": "{days}天{hours}小时{minutes}分{seconds}秒",
|
|
568
|
+
"duration.exactTitle": "总活跃耗时:{duration}",
|
|
569
|
+
"loading.label": "正在加载子代理…",
|
|
570
|
+
"loading.aria": "正在加载子代理",
|
|
571
|
+
"load.error": "无法加载子代理",
|
|
572
|
+
"retry": "重试",
|
|
573
|
+
"mode.oneShot": "一次性",
|
|
574
|
+
"mode.continuable": "可继续",
|
|
575
|
+
"activity.running": "正在运行",
|
|
576
|
+
"activity.inactive": "当前未运行",
|
|
577
|
+
"branch.collapse": "收起 {label} 的下级子代理",
|
|
578
|
+
"branch.expand": "展开 {label} 的下级子代理",
|
|
579
|
+
"count.total.one": "{count} 个子代理",
|
|
580
|
+
"count.total.other": "{count} 个子代理",
|
|
581
|
+
"count.running.one": "{count} 个子代理,正在运行",
|
|
582
|
+
"count.running.other": "{count} 个子代理,正在运行",
|
|
583
|
+
"tree.aria": "子代理会话",
|
|
584
|
+
"readonly.oneShot.title": "一次性子代理记录",
|
|
585
|
+
"readonly.title": "此子代理暂时只读",
|
|
586
|
+
"readonly.oneShot.body": "一次性任务不支持后续消息,可在这里查看完整执行记录。",
|
|
587
|
+
"readonly.body": "父会话当前不在线,重新打开父会话后即可继续发送消息。"
|
|
588
|
+
};
|
|
589
|
+
/** English dictionary, key-identical to the Chinese source of truth. */
|
|
590
|
+
const en = {
|
|
591
|
+
"diagnostic.corrupt": "corrupted session record",
|
|
592
|
+
"diagnostic.unsupported": "unsupported subagent record version",
|
|
593
|
+
"diagnostic.unavailable": "session record temporarily unavailable",
|
|
594
|
+
"duration.seconds": "{seconds}s",
|
|
595
|
+
"duration.minutes": "{minutes}m {seconds}s",
|
|
596
|
+
"duration.hours": "{hours}h {minutes}m {seconds}s",
|
|
597
|
+
"duration.days": "{days}d",
|
|
598
|
+
"duration.daysHours": "{days}d {hours}h",
|
|
599
|
+
"duration.months": "~{months}mo",
|
|
600
|
+
"duration.monthsDays": "~{months}mo {days}d",
|
|
601
|
+
"duration.years": "~{years}y",
|
|
602
|
+
"duration.yearsMonths": "~{years}y {months}mo",
|
|
603
|
+
"duration.exactDays": "{days}d {hours}h {minutes}m {seconds}s",
|
|
604
|
+
"duration.exactTitle": "Total active duration: {duration}",
|
|
605
|
+
"loading.label": "Loading subagents…",
|
|
606
|
+
"loading.aria": "Loading subagents",
|
|
607
|
+
"load.error": "Unable to load subagents",
|
|
608
|
+
"retry": "Retry",
|
|
609
|
+
"mode.oneShot": "one-shot",
|
|
610
|
+
"mode.continuable": "continuable",
|
|
611
|
+
"activity.running": "running",
|
|
612
|
+
"activity.inactive": "not running",
|
|
613
|
+
"branch.collapse": "Collapse {label} descendants",
|
|
614
|
+
"branch.expand": "Expand {label} descendants",
|
|
615
|
+
"count.total.one": "{count} subagent",
|
|
616
|
+
"count.total.other": "{count} subagents",
|
|
617
|
+
"count.running.one": "{count} subagent running",
|
|
618
|
+
"count.running.other": "{count} subagents running",
|
|
619
|
+
"tree.aria": "Subagent sessions",
|
|
620
|
+
"readonly.oneShot.title": "One-shot subagent record",
|
|
621
|
+
"readonly.title": "This subagent is read-only for now",
|
|
622
|
+
"readonly.oneShot.body": "One-shot tasks do not accept follow-ups; review the full execution record here.",
|
|
623
|
+
"readonly.body": "The parent session is offline; reopen it to continue sending messages."
|
|
624
|
+
};
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region lib/types/client/index.js
|
|
627
|
+
/** Required services for references, conversation slots, and session navigation. */
|
|
628
|
+
const inject = [
|
|
629
|
+
"inputTriggers",
|
|
630
|
+
"sessions",
|
|
631
|
+
"slots",
|
|
632
|
+
"locale"
|
|
633
|
+
];
|
|
634
|
+
/** Claim the composer for one-shot history or an unavailable continuation owner. */
|
|
635
|
+
function selectReadOnlySubagent(owner) {
|
|
636
|
+
const subagent = owner.session?.subagent;
|
|
637
|
+
if (subagent === void 0 || subagent === null) return null;
|
|
638
|
+
if (subagent.address.mode === "one-shot") return { reason: "one-shot" };
|
|
639
|
+
if (subagent.parentAvailable) return null;
|
|
640
|
+
return owner.session?.running === true ? null : { reason: "parent-unavailable" };
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Client plugin body: register the '@' subagent source over the root session list.
|
|
644
|
+
* @param ctx - client root context.
|
|
645
|
+
*/
|
|
646
|
+
function apply(ctx) {
|
|
647
|
+
ctx.effect(() => ctx.locale.register(NS, {
|
|
648
|
+
zh,
|
|
649
|
+
en
|
|
650
|
+
}), "ui-subagent: dictionaries");
|
|
651
|
+
const sessions = ctx.sessions;
|
|
652
|
+
const childLabels = (session, query) => {
|
|
653
|
+
const { byId } = sessions.list.getSnapshot();
|
|
654
|
+
return Object.values(byId).filter((child) => child.parentId === session.sessionId && child.running && child.displayTitle.includes(query)).map((child) => child.displayTitle);
|
|
655
|
+
};
|
|
656
|
+
const source = {
|
|
657
|
+
trigger: "@",
|
|
658
|
+
name: "subagent",
|
|
659
|
+
candidates(session, { query }) {
|
|
660
|
+
return Promise.resolve(childLabels(session, query).map((name) => ({ name })));
|
|
661
|
+
},
|
|
662
|
+
lexicon(session) {
|
|
663
|
+
return childLabels(session, "");
|
|
664
|
+
},
|
|
665
|
+
subscribeLexicon(_session, listener) {
|
|
666
|
+
return sessions.list.subscribe(listener);
|
|
667
|
+
},
|
|
668
|
+
onPick({ candidate }) {
|
|
669
|
+
return { text: `@${candidate.name} ` };
|
|
670
|
+
},
|
|
671
|
+
codec: {
|
|
672
|
+
clipboardText: (ref) => `@${ref}`,
|
|
673
|
+
serialize: (ref) => Promise.resolve(`@${ref}`)
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
const inputTriggers = ctx.get("inputTriggers");
|
|
677
|
+
ctx.effect(() => inputTriggers.registerSource(source), "ui-subagent: @ source");
|
|
678
|
+
const catalogActions = (_parentSessionId) => ({
|
|
679
|
+
openChild(address) {
|
|
680
|
+
sessions.openSubagent(address);
|
|
681
|
+
},
|
|
682
|
+
refresh(parentSessionId) {
|
|
683
|
+
sessions.refreshSubagents(parentSessionId);
|
|
684
|
+
},
|
|
685
|
+
setCatalogOpen(parentSessionId, open) {
|
|
686
|
+
sessions.setSubagentCatalogOpen(parentSessionId, open);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
690
|
+
name: "conversation.session.header.actions",
|
|
691
|
+
id: "subagent-catalog",
|
|
692
|
+
order: 10,
|
|
693
|
+
locale: NS,
|
|
694
|
+
inject: catalogActions
|
|
695
|
+
}, SubagentCatalogAction));
|
|
696
|
+
ctx.slots.inject("conversation.composer", () => ctx.slots.register({
|
|
697
|
+
name: "conversation.composer",
|
|
698
|
+
priority: -10,
|
|
699
|
+
locale: NS,
|
|
700
|
+
select: selectReadOnlySubagent
|
|
701
|
+
}, SubagentReadOnlyComposer));
|
|
702
|
+
}
|
|
703
|
+
//#endregion
|
|
704
|
+
exports.apply = apply;
|
|
705
|
+
exports.inject = inject;
|
|
706
|
+
return module.exports;
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
//# sourceMappingURL=client.js.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region lib/types/index.js
|
|
2
|
+
/**
|
|
3
|
+
* Subagent reference plugin, node half. Pure UI plugin: the empty apply
|
|
4
|
+
* exists so the plugin appears in the host cordis.yml / Loader; the browser
|
|
5
|
+
* half ships via exports["./client"], discovered through the package.json
|
|
6
|
+
* dsh.client declaration.
|
|
7
|
+
*/
|
|
8
|
+
/** Host plugin body — no host-side behavior for this source plugin. */
|
|
9
|
+
function apply() {}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { apply };
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region lib/types/invariant.js
|
|
2
|
+
/**
|
|
3
|
+
* Package-owned invariant companion for `@monotykamary/dsh-client-ui-subagent`.
|
|
4
|
+
* @module @monotykamary/dsh-client-ui-subagent/invariant
|
|
5
|
+
*/
|
|
6
|
+
const PACKAGE_NAME = "@monotykamary/dsh-client-ui-subagent";
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
const name = "client-ui-subagent-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
const inject = ["invariants"];
|
|
11
|
+
/**
|
|
12
|
+
* No runtime invariant: a single slash-source registration whose disposal is
|
|
13
|
+
* proven by the HMR-safety spec — it emits no cordis events and owns no
|
|
14
|
+
* cross-plugin mutable state.
|
|
15
|
+
*/
|
|
16
|
+
const install = () => {};
|
|
17
|
+
/**
|
|
18
|
+
* Register this package's invariant companion.
|
|
19
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
20
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
21
|
+
*/
|
|
22
|
+
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
23
|
+
//#endregion
|
|
24
|
+
export { apply, inject, name };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type SessionId, type SubagentAddress } from '@monotykamary/dsh-client-runtime/client';
|
|
2
|
+
import type { PropsLocale, PropsRuntime } from '@monotykamary/dsh-client-ui-slots';
|
|
3
|
+
import { NS } from './locales.ts';
|
|
4
|
+
/** Business actions supplied by the slot registration. */
|
|
5
|
+
export interface SubagentCatalogInjected {
|
|
6
|
+
openChild: (address: SubagentAddress) => void;
|
|
7
|
+
refresh: (parentSessionId: SessionId) => void;
|
|
8
|
+
setCatalogOpen: (parentSessionId: SessionId, open: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
/** Full props for the session-header catalog action. */
|
|
11
|
+
export type SubagentCatalogActionProps = PropsRuntime<'conversation.session.header.actions'> & SubagentCatalogInjected & PropsLocale<typeof NS>;
|
|
12
|
+
/**
|
|
13
|
+
* Render the current session's direct catalog and lazily expanded descendants.
|
|
14
|
+
* @param props - session standard props plus catalog navigation actions.
|
|
15
|
+
* @returns The action while the catalog is pending or summaries establish descendants.
|
|
16
|
+
*/
|
|
17
|
+
export declare function SubagentCatalogAction({ sessionId, useSessions, openChild, refresh, setCatalogOpen, t, }: SubagentCatalogActionProps): import("react").JSX.Element | null;
|
|
18
|
+
//# sourceMappingURL=SubagentCatalogAction.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PropsLocale, PropsRuntime } from '@monotykamary/dsh-client-ui-slots';
|
|
2
|
+
import { NS } from './locales.ts';
|
|
3
|
+
/** Why a catalog-addressed conversation cannot accept human input. */
|
|
4
|
+
export interface SubagentReadOnlyMatch {
|
|
5
|
+
reason: 'one-shot' | 'parent-unavailable';
|
|
6
|
+
}
|
|
7
|
+
/** Full chain props after the read-only subagent selector accepts the owner currency. */
|
|
8
|
+
export type SubagentReadOnlyComposerProps = PropsRuntime<'conversation.composer'> & {
|
|
9
|
+
matched: SubagentReadOnlyMatch;
|
|
10
|
+
} & PropsLocale<typeof NS>;
|
|
11
|
+
/**
|
|
12
|
+
* Explain why the normal composer is unavailable for an addressed child.
|
|
13
|
+
* @param props - selector-owned read-only reason plus standard slot props.
|
|
14
|
+
* @returns A read-only composer replacement.
|
|
15
|
+
*/
|
|
16
|
+
export declare function SubagentReadOnlyComposer({ matched, t, }: Pick<SubagentReadOnlyComposerProps, 'matched' | 't'>): import("react").JSX.Element;
|
|
17
|
+
//# sourceMappingURL=SubagentReadOnlyComposer.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent reference plugin, browser half: registers the '@' source —
|
|
3
|
+
* candidates filtered from the session list snapshot's running children
|
|
4
|
+
* (zero RPC; the list rides the plugin's root-context sessions service, the
|
|
5
|
+
* scoped session comes from the per-call projection), pick inserts the
|
|
6
|
+
* literal `@label ` text (plain-text-reference decision, see
|
|
7
|
+
* .agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md:
|
|
8
|
+
* the draft carries plain text, chip
|
|
9
|
+
* visuals are derived by scanning against the source lexicon, and the
|
|
10
|
+
* prompt ships the same literal). Consumption semantics stay with future
|
|
11
|
+
* business work. No adjudication hooks: subagent
|
|
12
|
+
* references never enter command adjudication.
|
|
13
|
+
*/
|
|
14
|
+
import type { ClientContext } from '@monotykamary/dsh-client-runtime/client';
|
|
15
|
+
import { type SubagentKey } from './locales.ts';
|
|
16
|
+
declare module '@monotykamary/dsh-client-ui-slots' {
|
|
17
|
+
interface LocaleNamespaceMap {
|
|
18
|
+
/** Subagent catalog and read-only composer copy. */
|
|
19
|
+
'subagent': SubagentKey;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export type { SubagentCatalogActionProps, SubagentCatalogInjected, } from './SubagentCatalogAction.tsx';
|
|
23
|
+
export type { SubagentReadOnlyComposerProps, SubagentReadOnlyMatch, } from './SubagentReadOnlyComposer.tsx';
|
|
24
|
+
/** Required services for references, conversation slots, and session navigation. */
|
|
25
|
+
export declare const inject: string[];
|
|
26
|
+
/**
|
|
27
|
+
* Client plugin body: register the '@' subagent source over the root session list.
|
|
28
|
+
* @param ctx - client root context.
|
|
29
|
+
*/
|
|
30
|
+
export declare function apply(ctx: ClientContext): void;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** `subagent` namespace dictionaries. */
|
|
2
|
+
/** Dictionary namespace owned by this plugin. */
|
|
3
|
+
export declare const NS = "subagent";
|
|
4
|
+
/** Simplified Chinese dictionary (the key-set source of truth). */
|
|
5
|
+
export declare const zh: {
|
|
6
|
+
readonly 'diagnostic.corrupt': "会话记录损坏";
|
|
7
|
+
readonly 'diagnostic.unsupported': "子代理记录版本不受支持";
|
|
8
|
+
readonly 'diagnostic.unavailable': "会话记录暂不可用";
|
|
9
|
+
readonly 'duration.seconds': "{seconds}秒";
|
|
10
|
+
readonly 'duration.minutes': "{minutes}分{seconds}秒";
|
|
11
|
+
readonly 'duration.hours': "{hours}小时{minutes}分{seconds}秒";
|
|
12
|
+
readonly 'duration.days': "{days}天";
|
|
13
|
+
readonly 'duration.daysHours': "{days}天{hours}小时";
|
|
14
|
+
readonly 'duration.months': "约{months}个月";
|
|
15
|
+
readonly 'duration.monthsDays': "约{months}个月{days}天";
|
|
16
|
+
readonly 'duration.years': "约{years}年";
|
|
17
|
+
readonly 'duration.yearsMonths': "约{years}年{months}个月";
|
|
18
|
+
readonly 'duration.exactDays': "{days}天{hours}小时{minutes}分{seconds}秒";
|
|
19
|
+
readonly 'duration.exactTitle': "总活跃耗时:{duration}";
|
|
20
|
+
readonly 'loading.label': "正在加载子代理…";
|
|
21
|
+
readonly 'loading.aria': "正在加载子代理";
|
|
22
|
+
readonly 'load.error': "无法加载子代理";
|
|
23
|
+
readonly retry: "重试";
|
|
24
|
+
readonly 'mode.oneShot': "一次性";
|
|
25
|
+
readonly 'mode.continuable': "可继续";
|
|
26
|
+
readonly 'activity.running': "正在运行";
|
|
27
|
+
readonly 'activity.inactive': "当前未运行";
|
|
28
|
+
readonly 'branch.collapse': "收起 {label} 的下级子代理";
|
|
29
|
+
readonly 'branch.expand': "展开 {label} 的下级子代理";
|
|
30
|
+
readonly 'count.total.one': "{count} 个子代理";
|
|
31
|
+
readonly 'count.total.other': "{count} 个子代理";
|
|
32
|
+
readonly 'count.running.one': "{count} 个子代理,正在运行";
|
|
33
|
+
readonly 'count.running.other': "{count} 个子代理,正在运行";
|
|
34
|
+
readonly 'tree.aria': "子代理会话";
|
|
35
|
+
readonly 'readonly.oneShot.title': "一次性子代理记录";
|
|
36
|
+
readonly 'readonly.title': "此子代理暂时只读";
|
|
37
|
+
readonly 'readonly.oneShot.body': "一次性任务不支持后续消息,可在这里查看完整执行记录。";
|
|
38
|
+
readonly 'readonly.body': "父会话当前不在线,重新打开父会话后即可继续发送消息。";
|
|
39
|
+
};
|
|
40
|
+
/** English dictionary, key-identical to the Chinese source of truth. */
|
|
41
|
+
export declare const en: Record<SubagentKey, string>;
|
|
42
|
+
/** Key domain of the `subagent` namespace (zh is the source of truth). */
|
|
43
|
+
export type SubagentKey = keyof typeof zh;
|
|
44
|
+
//# sourceMappingURL=locales.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent reference plugin, node half. Pure UI plugin: the empty apply
|
|
3
|
+
* exists so the plugin appears in the host cordis.yml / Loader; the browser
|
|
4
|
+
* half ships via exports["./client"], discovered through the package.json
|
|
5
|
+
* dsh.client declaration.
|
|
6
|
+
*/
|
|
7
|
+
/** Host plugin body — no host-side behavior for this source plugin. */
|
|
8
|
+
export declare function apply(): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@monotykamary/dsh-client-ui-subagent`.
|
|
3
|
+
* @module @monotykamary/dsh-client-ui-subagent/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@monotykamary/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "client-ui-subagent-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@monotykamary/dsh-client-ui-subagent",
|
|
3
|
+
"description": "Subagent conversation catalog, continuation routing UI, and '@' reference source",
|
|
4
|
+
"version": "0.1.0-rc.5",
|
|
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-subagent"
|
|
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
|
+
"@monotykamary/dsh-client-locale",
|
|
36
|
+
"@monotykamary/dsh-client-runtime",
|
|
37
|
+
"@monotykamary/dsh-client-ui-conversation",
|
|
38
|
+
"@monotykamary/dsh-client-ui-primitives",
|
|
39
|
+
"@monotykamary/dsh-client-ui-input-trigger"
|
|
40
|
+
],
|
|
41
|
+
"platform": "web"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"react": "^18.2.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@monotykamary/dsh-client-locale": "^0.1.0-rc.5",
|
|
50
|
+
"@monotykamary/dsh-client-ui-conversation": "^0.1.0-rc.5",
|
|
51
|
+
"@monotykamary/dsh-client-ui-primitives": "^0.1.0-rc.5",
|
|
52
|
+
"@monotykamary/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
53
|
+
"@monotykamary/dsh-client-runtime": "^0.1.0-rc.5",
|
|
54
|
+
"@monotykamary/dsh-subagent": "^0.1.0-rc.5",
|
|
55
|
+
"@monotykamary/dsh-client-ui-input-trigger": "^0.1.0-rc.5",
|
|
56
|
+
"@monotykamary/cordis": "^4.0.1",
|
|
57
|
+
"@monotykamary/dsh-invariants": "^0.1.0-rc.5",
|
|
58
|
+
"@monotykamary/dsh-token-meter": "^0.1.0-rc.5"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/react": "~18.3.1",
|
|
62
|
+
"@monotykamary/dsh-client-ui-input-trigger": "^0.1.0-rc.5",
|
|
63
|
+
"@monotykamary/dsh-client-ui-primitives": "^0.1.0-rc.5",
|
|
64
|
+
"@monotykamary/dsh-client-locale": "^0.1.0-rc.5",
|
|
65
|
+
"@monotykamary/dsh-client-runtime": "^0.1.0-rc.5",
|
|
66
|
+
"@monotykamary/dsh-client-test-runtime": "^0.1.0-rc.5",
|
|
67
|
+
"@monotykamary/dsh-client-ui-conversation": "^0.1.0-rc.5",
|
|
68
|
+
"@monotykamary/dsh-invariants": "^0.1.0-rc.5",
|
|
69
|
+
"@monotykamary/dsh-subagent": "^0.1.0-rc.5",
|
|
70
|
+
"@monotykamary/cordis": "^4.0.1",
|
|
71
|
+
"@monotykamary/dsh-client-ui-slots": "^0.1.0-rc.5",
|
|
72
|
+
"@monotykamary/dsh-token-meter": "^0.1.0-rc.5"
|
|
73
|
+
},
|
|
74
|
+
"files": [
|
|
75
|
+
"lib/index.js",
|
|
76
|
+
"lib/invariant.js",
|
|
77
|
+
"lib/client.js",
|
|
78
|
+
"lib/types/**/*.d.ts"
|
|
79
|
+
],
|
|
80
|
+
"scripts": {
|
|
81
|
+
"bundle": "tsdown",
|
|
82
|
+
"watch": "tsdown --watch"
|
|
83
|
+
}
|
|
84
|
+
}
|