@khorsheed/dsh-room 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.i18n.yaml +6 -0
- package/README.md +48 -0
- package/README.zh.md +48 -0
- package/cordis.patch.yml +6 -0
- package/lib/client.js +11481 -0
- package/lib/index.js +3231 -0
- package/lib/invariant.js +26 -0
- package/lib/journal-CuRnWk66.js +435 -0
- package/lib/tool.js +350 -0
- package/lib/typert.host.d.ts +3 -0
- package/lib/typert.host.js +2615 -0
- package/lib/typert.remote-client.d.ts +55 -0
- package/lib/typert.remote-client.js +1711 -0
- package/lib/types/adapter.d.ts +42 -0
- package/lib/types/adapter.js +41 -0
- package/lib/types/agent-setup.d.ts +141 -0
- package/lib/types/agent-setup.js +145 -0
- package/lib/types/client/InviteAgentAction.d.ts +13 -0
- package/lib/types/client/InviteAgentAction.js +45 -0
- package/lib/types/client/InviteDialog.d.ts +90 -0
- package/lib/types/client/InviteDialog.js +216 -0
- package/lib/types/client/MemberCard.d.ts +33 -0
- package/lib/types/client/MemberCard.js +32 -0
- package/lib/types/client/MembersView.d.ts +5 -0
- package/lib/types/client/MembersView.js +168 -0
- package/lib/types/client/RoomComposer.d.ts +21 -0
- package/lib/types/client/RoomComposer.js +211 -0
- package/lib/types/client/RoomDockCapsules.d.ts +64 -0
- package/lib/types/client/RoomDockCapsules.js +277 -0
- package/lib/types/client/RoomEventView.d.ts +11 -0
- package/lib/types/client/RoomEventView.js +17 -0
- package/lib/types/client/RoomModelPicker.d.ts +18 -0
- package/lib/types/client/RoomModelPicker.js +134 -0
- package/lib/types/client/RoomPlanView.d.ts +17 -0
- package/lib/types/client/RoomPlanView.js +88 -0
- package/lib/types/client/RoomQueueStrip.d.ts +26 -0
- package/lib/types/client/RoomQueueStrip.js +28 -0
- package/lib/types/client/RoomRecoveryView.d.ts +11 -0
- package/lib/types/client/RoomRecoveryView.js +38 -0
- package/lib/types/client/RoomRelayView.d.ts +12 -0
- package/lib/types/client/RoomRelayView.js +20 -0
- package/lib/types/client/RoomRunView.d.ts +15 -0
- package/lib/types/client/RoomRunView.js +50 -0
- package/lib/types/client/RoomSpeechView.d.ts +18 -0
- package/lib/types/client/RoomSpeechView.js +62 -0
- package/lib/types/client/RoomStatsLine.d.ts +61 -0
- package/lib/types/client/RoomStatsLine.js +138 -0
- package/lib/types/client/RoomTaskLineView.d.ts +13 -0
- package/lib/types/client/RoomTaskLineView.js +21 -0
- package/lib/types/client/RoomTodoStrip.d.ts +24 -0
- package/lib/types/client/RoomTodoStrip.js +64 -0
- package/lib/types/client/format.d.ts +31 -0
- package/lib/types/client/format.js +48 -0
- package/lib/types/client/icons.d.ts +27 -0
- package/lib/types/client/icons.js +11 -0
- package/lib/types/client/index.d.ts +39 -0
- package/lib/types/client/index.js +471 -0
- package/lib/types/client/locales.d.ts +422 -0
- package/lib/types/client/locales.js +413 -0
- package/lib/types/client/member-color.d.ts +13 -0
- package/lib/types/client/member-color.js +22 -0
- package/lib/types/client/name-pool.d.ts +17 -0
- package/lib/types/client/name-pool.js +25 -0
- package/lib/types/client/nodes.d.ts +136 -0
- package/lib/types/client/nodes.js +212 -0
- package/lib/types/client/preset-visibility.d.ts +91 -0
- package/lib/types/client/preset-visibility.js +113 -0
- package/lib/types/client/request-ids.d.ts +7 -0
- package/lib/types/client/request-ids.js +21 -0
- package/lib/types/client/room-store.d.ts +137 -0
- package/lib/types/client/room-store.js +244 -0
- package/lib/types/client/slots.d.ts +319 -0
- package/lib/types/client/slots.js +1 -0
- package/lib/types/deliveries.d.ts +5 -0
- package/lib/types/deliveries.js +20 -0
- package/lib/types/dispatch.d.ts +105 -0
- package/lib/types/dispatch.js +467 -0
- package/lib/types/index.d.ts +301 -0
- package/lib/types/index.js +1200 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/invariant.js +24 -0
- package/lib/types/journal.d.ts +117 -0
- package/lib/types/journal.js +434 -0
- package/lib/types/plan-service.d.ts +34 -0
- package/lib/types/plan-service.js +266 -0
- package/lib/types/plan.d.ts +168 -0
- package/lib/types/plan.js +494 -0
- package/lib/types/tool.d.ts +56 -0
- package/lib/types/tool.js +389 -0
- package/lib/types/types.d.ts +813 -0
- package/lib/types/types.js +1 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +131 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The room session's stats row — a RoomComposer footer replicating the
|
|
4
|
+
* official StatsLine (harness ui-conversation chat/StatsLine.tsx), which
|
|
5
|
+
* lives inside the InputBar fallback the composer takeover hides. Every
|
|
6
|
+
* figure rides the durable whole-log projections through the framework's
|
|
7
|
+
* `useProjection` seat: `sessionStats` for turn/step counts and wall times,
|
|
8
|
+
* `tokenUsage` for billing. A key with no served value drops its groups;
|
|
9
|
+
* with neither projection served the row does not render at all (silent
|
|
10
|
+
* degrade). Unlike the official row there is no window-fold fallback — the
|
|
11
|
+
* takeover has no business re-deriving what the host already projects.
|
|
12
|
+
*
|
|
13
|
+
* Semantics: the figures are the ROOM SESSION's own — its main agent's
|
|
14
|
+
* turns and billing. CLI members consume in their own child sessions, so
|
|
15
|
+
* this row is never a whole-room aggregate.
|
|
16
|
+
*/
|
|
17
|
+
import { Fragment, memo, useLayoutEffect, useRef, useState } from 'react';
|
|
18
|
+
import { Tooltip } from '@deepseek-ai/dsh-client-ui-primitives';
|
|
19
|
+
import css from './RoomStatsLine.module.css';
|
|
20
|
+
/**
|
|
21
|
+
* Compact token count: 517 / 12.2K / 517K / 1.2M (one decimal under three
|
|
22
|
+
* digits). Copied from the official StatsLine.
|
|
23
|
+
* @param n - token count.
|
|
24
|
+
* @returns display string.
|
|
25
|
+
*/
|
|
26
|
+
export function formatTokens(n) {
|
|
27
|
+
const scaled = (v) => v >= 100 ? String(Math.round(v)) : String(Math.round(v * 10) / 10);
|
|
28
|
+
if (n < 1_000)
|
|
29
|
+
return String(n);
|
|
30
|
+
if (n < 1_000_000)
|
|
31
|
+
return `${scaled(n / 1_000)}K`;
|
|
32
|
+
return `${scaled(n / 1_000_000)}M`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Compact duration: 45.2s under a minute, 2m42s from there on. Copied from
|
|
36
|
+
* the official StatsLine.
|
|
37
|
+
* @param ms - duration in milliseconds.
|
|
38
|
+
* @returns display string.
|
|
39
|
+
*/
|
|
40
|
+
export function formatDuration(ms) {
|
|
41
|
+
const s = ms / 1_000;
|
|
42
|
+
if (s < 60)
|
|
43
|
+
return `${Math.round(s * 10) / 10}s`;
|
|
44
|
+
const whole = Math.round(s);
|
|
45
|
+
return `${Math.floor(whole / 60)}m${whole % 60}s`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Throughput figure: integer at 10+, one decimal below. Copied from the
|
|
49
|
+
* official message-chrome formatTokensPerSecond.
|
|
50
|
+
* @param tps - tokens per second.
|
|
51
|
+
* @returns display number without unit.
|
|
52
|
+
*/
|
|
53
|
+
export function formatTokensPerSecond(tps) {
|
|
54
|
+
const clamped = Math.max(0, tps);
|
|
55
|
+
return clamped >= 10 ? String(Math.round(clamped)) : String(Math.round(clamped * 10) / 10);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sum the three disjoint prompt-side billing buckets. Copied from the
|
|
59
|
+
* official StatsLine.
|
|
60
|
+
* @param usage - the session's token-usage projection value.
|
|
61
|
+
* @returns billed input tokens.
|
|
62
|
+
*/
|
|
63
|
+
export function billedInputTokens(usage) {
|
|
64
|
+
return usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Cache-hit share of prompt-side input over the whole durable log. Copied
|
|
68
|
+
* from the official StatsLine.
|
|
69
|
+
* @param usage - the session's token-usage projection value.
|
|
70
|
+
* @returns rounded integer percent, or null when no input was billed.
|
|
71
|
+
*/
|
|
72
|
+
export function cacheHitPercent(usage) {
|
|
73
|
+
const denominator = billedInputTokens(usage);
|
|
74
|
+
return denominator === 0
|
|
75
|
+
? null
|
|
76
|
+
: Math.round(usage.cacheReadTokens / denominator * 100);
|
|
77
|
+
}
|
|
78
|
+
export const RoomStatsLine = memo(function RoomStatsLine({ useProjection, t }) {
|
|
79
|
+
const stats = useProjection('sessionStats');
|
|
80
|
+
const usage = useProjection('tokenUsage');
|
|
81
|
+
// Pipe-separated groups, mirroring the official assembly; a group with no
|
|
82
|
+
// data drops out whole.
|
|
83
|
+
const groups = [];
|
|
84
|
+
if (stats !== undefined && stats.steps > 0) {
|
|
85
|
+
groups.push(t('stats.counts', { turns: stats.turns, steps: stats.steps }));
|
|
86
|
+
const durations = [];
|
|
87
|
+
if (stats.llmMs > 0)
|
|
88
|
+
durations.push(t('stats.llm', { duration: formatDuration(stats.llmMs) }));
|
|
89
|
+
if (stats.toolMs > 0)
|
|
90
|
+
durations.push(t('stats.toolCall', { duration: formatDuration(stats.toolMs) }));
|
|
91
|
+
if (durations.length > 0)
|
|
92
|
+
groups.push(durations.join(' · '));
|
|
93
|
+
const speeds = [];
|
|
94
|
+
if (stats.ttftSteps > 0) {
|
|
95
|
+
speeds.push(t('stats.ttftAverage', { duration: formatDuration(stats.ttftMs / stats.ttftSteps) }));
|
|
96
|
+
}
|
|
97
|
+
if (stats.decodeMs > 0) {
|
|
98
|
+
speeds.push(t('stats.tokensPerSecond', {
|
|
99
|
+
throughput: formatTokensPerSecond(stats.decodeTokens / (stats.decodeMs / 1_000)),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
if (speeds.length > 0)
|
|
103
|
+
groups.push(speeds.join(' · '));
|
|
104
|
+
}
|
|
105
|
+
// Gated on actual token activity, as upstream: a session whose steps all
|
|
106
|
+
// settled without billing shows its counts without a zero-token group.
|
|
107
|
+
if (usage !== undefined
|
|
108
|
+
&& (billedInputTokens(usage) > 0 || usage.outputTokens > 0)) {
|
|
109
|
+
const cacheHit = cacheHitPercent(usage);
|
|
110
|
+
if (cacheHit !== null)
|
|
111
|
+
groups.push(t('stats.cacheHit', { percent: cacheHit }));
|
|
112
|
+
groups.push(t('stats.tokens', {
|
|
113
|
+
input: formatTokens(billedInputTokens(usage)),
|
|
114
|
+
output: formatTokens(usage.outputTokens),
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
const line = groups.join(' | ');
|
|
118
|
+
// The row elides with ellipsis when overlong; a delayed hover tooltip
|
|
119
|
+
// carries the full line, enabled only while content is actually clipped
|
|
120
|
+
// (the official StatsLine behavior).
|
|
121
|
+
const rootRef = useRef(null);
|
|
122
|
+
const [truncated, setTruncated] = useState(false);
|
|
123
|
+
useLayoutEffect(() => {
|
|
124
|
+
const el = rootRef.current;
|
|
125
|
+
if (el === null)
|
|
126
|
+
return;
|
|
127
|
+
const measure = () => { setTruncated(el.scrollWidth > el.clientWidth); };
|
|
128
|
+
measure();
|
|
129
|
+
if (typeof ResizeObserver === 'undefined')
|
|
130
|
+
return;
|
|
131
|
+
const observer = new ResizeObserver(measure);
|
|
132
|
+
observer.observe(el);
|
|
133
|
+
return () => { observer.disconnect(); };
|
|
134
|
+
}, [line]);
|
|
135
|
+
if (groups.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
return (_jsx(Tooltip, { label: line, side: "top", delayMs: 500, disabled: !truncated, children: _jsx("div", { ref: rootRef, className: css.root, children: groups.map((group, i) => (_jsxs(Fragment, { children: [i > 0 && _jsxs(_Fragment, { children: [_jsx("span", { className: css.sep, "aria-hidden": true, children: "|" }), ' '] }), _jsx("span", { children: group })] }, group))) }) }));
|
|
138
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task-advance node ('room-task-line' keyed renderer): one dim line per task
|
|
3
|
+
* closed done — `✓ ada 完成了「API 定稿」── 目标进度 2/5`. The same dim
|
|
4
|
+
* single-line register as the boundary rows (RoomEventView); the goal
|
|
5
|
+
* progress suffix is computed live from the room store (the node's own fold
|
|
6
|
+
* only carries this task) and dropped when the store has no state for the
|
|
7
|
+
* session (a cold render before the first pull).
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
|
+
import type { RoomTaskLineViewProps } from './slots.ts';
|
|
11
|
+
/** The task-advance dim line. */
|
|
12
|
+
export declare function RoomTaskLineView({ node, sessionId, roomStore, t }: RoomTaskLineViewProps): ReactNode;
|
|
13
|
+
//# sourceMappingURL=RoomTaskLineView.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Task-advance node ('room-task-line' keyed renderer): one dim line per task
|
|
4
|
+
* closed done — `✓ ada 完成了「API 定稿」── 目标进度 2/5`. The same dim
|
|
5
|
+
* single-line register as the boundary rows (RoomEventView); the goal
|
|
6
|
+
* progress suffix is computed live from the room store (the node's own fold
|
|
7
|
+
* only carries this task) and dropped when the store has no state for the
|
|
8
|
+
* session (a cold render before the first pull).
|
|
9
|
+
*/
|
|
10
|
+
import { useSyncExternalStore } from 'react';
|
|
11
|
+
import { taskProgress } from '../journal.js';
|
|
12
|
+
import css from './RoomTaskLineView.module.css';
|
|
13
|
+
/** The task-advance dim line. */
|
|
14
|
+
export function RoomTaskLineView({ node, sessionId, roomStore, t }) {
|
|
15
|
+
const state = useSyncExternalStore(roomStore.subscribe, () => roomStore.getCached(sessionId));
|
|
16
|
+
const data = node.data;
|
|
17
|
+
const progress = state === undefined ? undefined : taskProgress(state.tasks);
|
|
18
|
+
return (_jsxs("div", { className: css.row, children: [t('advance.line', { member: data.member, title: data.title }), progress !== undefined && progress.total > 0
|
|
19
|
+
? t('advance.progress', { done: progress.done, total: progress.total })
|
|
20
|
+
: ''] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The room session's todo strip — a RoomComposer dock row replicating the
|
|
3
|
+
* official TodoPanel (harness ui-conversation skeleton/TodoPanel.tsx), which
|
|
4
|
+
* rides the `conversation.input.dock` seat inside the InputBar fallback the
|
|
5
|
+
* composer takeover hides. The data is the host-computed `todos` projection
|
|
6
|
+
* (the latest todo/write whole-list snapshot) through the framework's
|
|
7
|
+
* `useProjection` seat — no data of its own, nothing rendered while the list
|
|
8
|
+
* is absent or empty. Visuals follow the official panel: a collapsed header
|
|
9
|
+
* (checklist glyph + title + per-status counts + chevron) expanding to the
|
|
10
|
+
* status-glyph item list.
|
|
11
|
+
*
|
|
12
|
+
* Semantics: the list is the ROOM SESSION's own main agent plan. CLI members
|
|
13
|
+
* mirror theirs into their child sessions (family R3), never here.
|
|
14
|
+
*/
|
|
15
|
+
import { type ReactNode } from 'react';
|
|
16
|
+
import type { UseProjection } from '@deepseek-ai/dsh-api-session-controller/client';
|
|
17
|
+
import type { RoomComposerProps } from './slots.ts';
|
|
18
|
+
/** Props: the projection read seat plus the room locale seat. */
|
|
19
|
+
export interface RoomTodoStripProps {
|
|
20
|
+
readonly useProjection: UseProjection;
|
|
21
|
+
readonly t: RoomComposerProps['t'];
|
|
22
|
+
}
|
|
23
|
+
export declare function RoomTodoStrip({ useProjection, t }: RoomTodoStripProps): ReactNode;
|
|
24
|
+
//# sourceMappingURL=RoomTodoStrip.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The room session's todo strip — a RoomComposer dock row replicating the
|
|
4
|
+
* official TodoPanel (harness ui-conversation skeleton/TodoPanel.tsx), which
|
|
5
|
+
* rides the `conversation.input.dock` seat inside the InputBar fallback the
|
|
6
|
+
* composer takeover hides. The data is the host-computed `todos` projection
|
|
7
|
+
* (the latest todo/write whole-list snapshot) through the framework's
|
|
8
|
+
* `useProjection` seat — no data of its own, nothing rendered while the list
|
|
9
|
+
* is absent or empty. Visuals follow the official panel: a collapsed header
|
|
10
|
+
* (checklist glyph + title + per-status counts + chevron) expanding to the
|
|
11
|
+
* status-glyph item list.
|
|
12
|
+
*
|
|
13
|
+
* Semantics: the list is the ROOM SESSION's own main agent plan. CLI members
|
|
14
|
+
* mirror theirs into their child sessions (family R3), never here.
|
|
15
|
+
*/
|
|
16
|
+
import { useId, useState } from 'react';
|
|
17
|
+
import { IconChecklistOutlineMedium, IconChevronDownOutlineMedium, IconChevronUpOutlineMedium } from './icons.js';
|
|
18
|
+
import css from './RoomTodoStrip.module.css';
|
|
19
|
+
/** Local exhaustiveness helper — client packages do not depend on `dsh-llm`. */
|
|
20
|
+
function assertNever(value) {
|
|
21
|
+
throw new Error(`unreachable todo status: ${String(value)}`);
|
|
22
|
+
}
|
|
23
|
+
/** Status glyphs share the figma 14×14 artboard; copied from the official TodoPanel. */
|
|
24
|
+
function CompletedGlyph() {
|
|
25
|
+
return (_jsxs("svg", { width: 14, height: 14, viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", className: css.glyphCompleted, children: [_jsx("circle", { cx: "7", cy: "7", r: "6.4", stroke: "currentColor", strokeWidth: "1.2" }), _jsx("path", { d: "M10.9631 5.71411L7.70154 8.97571C7.48011 9.19714 7.27736 9.40099 7.09229 9.54993C6.89742 9.70669 6.66314 9.85279 6.3634 9.90027C6.2049 9.92534 6.04339 9.92534 5.88489 9.90027C5.58515 9.85279 5.35087 9.70669 5.15601 9.54993C4.97093 9.40099 4.76818 9.19714 4.54675 8.97571L3.03516 7.46411L3.96313 6.53613L5.47473 8.04773C5.7169 8.28989 5.86196 8.43389 5.97888 8.52795C6.08597 8.61409 6.10875 8.60701 6.08997 8.604C6.11259 8.60758 6.13571 8.60758 6.15833 8.604C6.13954 8.60701 6.16232 8.61409 6.26941 8.52795C6.38633 8.43389 6.53139 8.28989 6.77356 8.04773L10.0352 4.78613L10.9631 5.71411Z", fill: "currentColor" })] }));
|
|
26
|
+
}
|
|
27
|
+
/** In-progress: business-blue ring fading out; CSS spins the svg. */
|
|
28
|
+
function ProgressGlyph() {
|
|
29
|
+
const gradientId = useId();
|
|
30
|
+
return (_jsxs("svg", { width: 14, height: 14, viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", className: css.glyphProgress, children: [_jsx("defs", { children: _jsxs("linearGradient", { id: gradientId, x1: "2.5", y1: "12", x2: "10.5", y2: "3.5", gradientUnits: "userSpaceOnUse", children: [_jsx("stop", { stopColor: "currentColor" }), _jsx("stop", { offset: "1", stopColor: "currentColor", stopOpacity: "0" })] }) }), _jsx("circle", { cx: "7", cy: "7", r: "6.4", stroke: `url(#${gradientId})`, strokeWidth: "1.2" })] }));
|
|
31
|
+
}
|
|
32
|
+
/** Pending: dashed unstarted ring (figma dash 2.4 2.4). */
|
|
33
|
+
function PendingGlyph() {
|
|
34
|
+
return (_jsx("svg", { width: 14, height: 14, viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", className: css.glyphPending, children: _jsx("circle", { cx: "7", cy: "7", r: "6.4", stroke: "currentColor", strokeWidth: "1.2", strokeDasharray: "2.4 2.4" }) }));
|
|
35
|
+
}
|
|
36
|
+
function StatusGlyph({ status }) {
|
|
37
|
+
switch (status) {
|
|
38
|
+
case 'completed': return _jsx(CompletedGlyph, {});
|
|
39
|
+
case 'in_progress': return _jsx(ProgressGlyph, {});
|
|
40
|
+
case 'pending': return _jsx(PendingGlyph, {});
|
|
41
|
+
/* v8 ignore next -- closed TodoItem status union */
|
|
42
|
+
default: return assertNever(status);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Header summary: "·"-joined per-status counts; zero-count segments omitted (the official rule). */
|
|
46
|
+
function progressLabel(todos, t) {
|
|
47
|
+
const done = todos.filter(item => item.status === 'completed').length;
|
|
48
|
+
const active = todos.filter(item => item.status === 'in_progress').length;
|
|
49
|
+
const pending = todos.length - done - active;
|
|
50
|
+
// En spaces (U+2002): HTML collapses runs of ASCII spaces, so widening the
|
|
51
|
+
// separator breathing room needs a literal wide space.
|
|
52
|
+
return [
|
|
53
|
+
...done > 0 ? [t('todo.progress.done', { done })] : [],
|
|
54
|
+
...active > 0 ? [t('todo.progress.active', { active })] : [],
|
|
55
|
+
...pending > 0 ? [t('todo.progress.pending', { pending })] : [],
|
|
56
|
+
].join(' · ');
|
|
57
|
+
}
|
|
58
|
+
export function RoomTodoStrip({ useProjection, t }) {
|
|
59
|
+
const todos = useProjection('todos');
|
|
60
|
+
const [collapsed, setCollapsed] = useState(true);
|
|
61
|
+
if (todos === undefined || todos === null || todos.length === 0)
|
|
62
|
+
return null;
|
|
63
|
+
return (_jsx("section", { className: css.root, "data-testid": "room-todo-strip", "aria-label": t('todo.title'), children: _jsxs("div", { className: css.body, children: [_jsxs("button", { type: "button", className: css.header, "aria-expanded": !collapsed, onClick: () => { setCollapsed(v => !v); }, children: [_jsx("span", { className: css.lead, "aria-hidden": true, children: _jsx(IconChecklistOutlineMedium, {}) }), _jsx("span", { className: css.title, children: t('todo.title') }), _jsx("span", { className: css.progress, children: progressLabel(todos, t) }), _jsx("span", { className: css.chevron, "aria-hidden": true, children: collapsed ? _jsx(IconChevronUpOutlineMedium, {}) : _jsx(IconChevronDownOutlineMedium, {}) })] }), !collapsed && (_jsx("ul", { className: css.list, children: todos.map(item => (_jsxs("li", { className: css.item, "data-status": item.status, children: [_jsx("span", { className: css.glyph, "aria-hidden": true, children: _jsx(StatusGlyph, { status: item.status }) }), _jsx("span", { className: css.content, children: item.content })] }, item.content))) }))] }) }));
|
|
64
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Small clock/duration formatters for the room chat chrome. */
|
|
2
|
+
import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
/** The room-namespace translate the relative-time formatter reads through. */
|
|
4
|
+
type TimeTranslate = TranslateNS<'room'>;
|
|
5
|
+
/**
|
|
6
|
+
* The honest run/dispatch duration: sub-100ms as `<0.1s` (a flat `0.0s`
|
|
7
|
+
* reads as "nothing happened" on an instant failure), sub-10s as `0.x s`,
|
|
8
|
+
* then whole seconds, then `m:ss`.
|
|
9
|
+
* @param ms - the duration in milliseconds.
|
|
10
|
+
* @returns the formatted duration.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatDurationMs(ms: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* The hover-revealed message clock: HH:MM local.
|
|
15
|
+
* @param time - unix epoch ms.
|
|
16
|
+
* @returns the wall-clock label.
|
|
17
|
+
*/
|
|
18
|
+
export declare function formatClock(time: number): string;
|
|
19
|
+
/** The translate face the relative-time formatter needs (locale-owned copy). */
|
|
20
|
+
/**
|
|
21
|
+
* The dock's relative clock: 刚刚 under a minute, then minutes, hours, days.
|
|
22
|
+
* Coarse on purpose — the capsules answer "how long ago", not "when exactly"
|
|
23
|
+
* (the exact clock stays on the chat rows' hover affordance).
|
|
24
|
+
* @param time - unix epoch ms of the event.
|
|
25
|
+
* @param now - unix epoch ms of "now".
|
|
26
|
+
* @param t - the room namespace translate.
|
|
27
|
+
* @returns the localized relative label.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatRelativeTime(time: number, now: number, t: TimeTranslate): string;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The honest run/dispatch duration: sub-100ms as `<0.1s` (a flat `0.0s`
|
|
3
|
+
* reads as "nothing happened" on an instant failure), sub-10s as `0.x s`,
|
|
4
|
+
* then whole seconds, then `m:ss`.
|
|
5
|
+
* @param ms - the duration in milliseconds.
|
|
6
|
+
* @returns the formatted duration.
|
|
7
|
+
*/
|
|
8
|
+
export function formatDurationMs(ms) {
|
|
9
|
+
if (ms < 100)
|
|
10
|
+
return '<0.1s';
|
|
11
|
+
if (ms < 10_000)
|
|
12
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
13
|
+
const seconds = Math.round(ms / 1000);
|
|
14
|
+
if (seconds < 60)
|
|
15
|
+
return `${seconds}s`;
|
|
16
|
+
return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, '0')}s`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The hover-revealed message clock: HH:MM local.
|
|
20
|
+
* @param time - unix epoch ms.
|
|
21
|
+
* @returns the wall-clock label.
|
|
22
|
+
*/
|
|
23
|
+
export function formatClock(time) {
|
|
24
|
+
const date = new Date(time);
|
|
25
|
+
return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;
|
|
26
|
+
}
|
|
27
|
+
/** The translate face the relative-time formatter needs (locale-owned copy). */
|
|
28
|
+
/**
|
|
29
|
+
* The dock's relative clock: 刚刚 under a minute, then minutes, hours, days.
|
|
30
|
+
* Coarse on purpose — the capsules answer "how long ago", not "when exactly"
|
|
31
|
+
* (the exact clock stays on the chat rows' hover affordance).
|
|
32
|
+
* @param time - unix epoch ms of the event.
|
|
33
|
+
* @param now - unix epoch ms of "now".
|
|
34
|
+
* @param t - the room namespace translate.
|
|
35
|
+
* @returns the localized relative label.
|
|
36
|
+
*/
|
|
37
|
+
export function formatRelativeTime(time, now, t) {
|
|
38
|
+
const elapsed = Math.max(0, now - time);
|
|
39
|
+
if (elapsed < 60_000)
|
|
40
|
+
return t('time.justNow');
|
|
41
|
+
const minutes = Math.floor(elapsed / 60_000);
|
|
42
|
+
if (minutes < 60)
|
|
43
|
+
return t('time.minutesAgo', { count: minutes });
|
|
44
|
+
const hours = Math.floor(minutes / 60);
|
|
45
|
+
if (hours < 24)
|
|
46
|
+
return t('time.hoursAgo', { count: hours });
|
|
47
|
+
return t('time.daysAgo', { count: Math.floor(hours / 24) });
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by scripts/sync-icon-artwork.mts from @deepseek-ai/dsh-client-ui-primitives
|
|
3
|
+
* (v0.1.7-rc.1, harness 46a7f68b09) — do not edit by hand. The 0.1.5 and rc.1 host lines
|
|
4
|
+
* share no icon export name, so the rc.1 artwork is inlined here: pure SVG,
|
|
5
|
+
* no host runtime identity, identical on every line. Re-run the generator
|
|
6
|
+
* after adding an icon import or bumping the harness checkout.
|
|
7
|
+
*
|
|
8
|
+
* @module @khorsheed/dsh-room/client
|
|
9
|
+
*/
|
|
10
|
+
/** Shared props for every product icon component (mirrors the upstream IconProps). */
|
|
11
|
+
export interface IconProps {
|
|
12
|
+
/** Square edge in px; defaults to the glyph's own drawn size. */
|
|
13
|
+
size?: number | undefined;
|
|
14
|
+
/** Extra class for layout placement; color rides currentColor. */
|
|
15
|
+
className?: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare const IconAgentPresetOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
18
|
+
export declare const IconCheckOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
19
|
+
export declare const IconChecklistOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
20
|
+
export declare const IconChevronDownOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
21
|
+
export declare const IconChevronRightOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
22
|
+
export declare const IconChevronUpOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
23
|
+
export declare const IconCopyOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
24
|
+
export declare const IconLinkOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
25
|
+
export declare const IconQueueOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
26
|
+
export declare const IconStopFillMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
27
|
+
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const IconAgentPresetOutlineMedium = ({ size = 16, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M6.51867 12.3282C7.29816 12.6011 8.16475 12.6514 9.02269 12.4216C9.57879 12.2726 10.0784 12.0185 10.5087 11.6888C10.7819 12.0555 11.1606 12.3304 11.5913 12.4805C10.9688 13.029 10.2149 13.4478 9.35911 13.6771C8.13946 14.0038 6.90632 13.8971 5.82126 13.4533C6.15821 13.1562 6.4021 12.7652 6.51867 12.3282ZM9.17629 2.89409C11.1101 3.34433 12.739 4.81872 13.2889 6.87043C13.4219 7.3665 13.4811 7.8649 13.4774 8.35466C13.0924 8.13213 12.6422 8.01837 12.1741 8.05276L12.1711 8.05257C12.1539 7.77199 12.109 7.48889 12.0334 7.20684C11.6363 5.72533 10.5048 4.6372 9.13549 4.22844C9.25559 3.87667 9.29214 3.49087 9.22309 3.09892C9.2108 3.02922 9.19451 2.96108 9.17629 2.89409ZM4.7311 3.89107L4.78302 4.11879C4.87648 4.4488 5.04146 4.74263 5.25579 4.98896C3.98078 6.01355 3.35848 7.72904 3.8089 9.41059C3.81828 9.44559 3.82866 9.48025 3.83885 9.51479C3.38217 9.61268 2.98548 9.84137 2.68107 10.1556C2.63414 10.022 2.5897 9.88632 2.55244 9.74726C1.93301 7.43489 2.86717 5.07173 4.71504 3.76697L4.7311 3.89107Z", fill: "currentColor" }), _jsx("path", { d: "M7.99136 5.28105C8.87501 5.28105 9.59136 4.56471 9.59136 3.68105C9.59136 2.7974 8.87501 2.08105 7.99136 2.08105C7.1077 2.08105 6.39136 2.7974 6.39136 3.68105C6.39136 4.56471 7.1077 5.28105 7.99136 5.28105Z", stroke: "currentColor" }), _jsx("path", { d: "M3.94009 12.9417C4.82374 12.9417 5.54009 12.2254 5.54009 11.3417C5.54009 10.458 4.82374 9.7417 3.94009 9.7417C3.05643 9.7417 2.34009 10.458 2.34009 11.3417C2.34009 12.2254 3.05643 12.9417 3.94009 12.9417Z", stroke: "currentColor" }), _jsx("path", { d: "M12.0851 12.9417C12.9688 12.9417 13.6851 12.2254 13.6851 11.3417C13.6851 10.458 12.9688 9.7417 12.0851 9.7417C11.2015 9.7417 10.4851 10.458 10.4851 11.3417C10.4851 12.2254 11.2015 12.9417 12.0851 12.9417Z", stroke: "currentColor" })] }));
|
|
3
|
+
export const IconCheckOutlineMedium = ({ size = 16, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M2.25 8.5L5.49732 11.7473C5.90519 12.1552 6.57263 12.1344 6.95426 11.7018L13.75 4", stroke: "currentColor" }) }));
|
|
4
|
+
export const IconChecklistOutlineMedium = ({ size = 14, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M3.75 6.25C4.7165 6.25 5.5 5.4665 5.5 4.5C5.5 3.5335 4.7165 2.75 3.75 2.75C2.7835 2.75 2 3.5335 2 4.5C2 5.4665 2.7835 6.25 3.75 6.25Z", stroke: "currentColor" }), _jsx("path", { d: "M7.5 4.5H13.5", stroke: "currentColor" }), _jsx("path", { d: "M3.75 13.25C4.7165 13.25 5.5 12.4665 5.5 11.5C5.5 10.5335 4.7165 9.75 3.75 9.75C2.7835 9.75 2 10.5335 2 11.5C2 12.4665 2.7835 13.25 3.75 13.25Z", stroke: "currentColor" }), _jsx("path", { d: "M7.5 11.5H13.5", stroke: "currentColor" })] }));
|
|
5
|
+
export const IconChevronDownOutlineMedium = ({ size = 14, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6", stroke: "currentColor" }) }));
|
|
6
|
+
export const IconChevronRightOutlineMedium = ({ size = 14, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M6 12L9.29289 8.70711C9.68342 8.31658 9.68342 7.68342 9.29289 7.29289L6 4", stroke: "currentColor" }) }));
|
|
7
|
+
export const IconChevronUpOutlineMedium = ({ size = 14, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M12 10L8.70711 6.70711C8.31658 6.31658 7.68342 6.31658 7.29289 6.70711L4 10", stroke: "currentColor" }) }));
|
|
8
|
+
export const IconCopyOutlineMedium = ({ size = 16, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("rect", { x: "1.52075", y: "4.07373", width: "10.3932", height: "10.3932", rx: "2", stroke: "currentColor" }), _jsx("path", { d: "M11.9792 1.53296C13.36 1.53296 14.4792 2.65225 14.4792 4.03296V9.42847C14.4792 10.3756 13.9521 11.1987 13.1755 11.6228V10.3298C13.3652 10.0787 13.4792 9.7674 13.4792 9.42847V4.03296C13.4792 3.20453 12.8077 2.53296 11.9792 2.53296H6.58374C6.27966 2.53301 5.99684 2.6235 5.7605 2.77905H4.42358C4.85652 2.03463 5.66056 1.53304 6.58374 1.53296H11.9792Z", fill: "currentColor" })] }));
|
|
9
|
+
export const IconLinkOutlineMedium = ({ size = 16, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M6.59961 9.40051C6.82779 9.6334 7.10015 9.81842 7.40074 9.94472C7.70132 10.071 8.02409 10.1361 8.35013 10.1361C8.67618 10.1361 8.99894 10.071 9.29953 9.94472C9.60011 9.81842 9.87247 9.6334 10.1007 9.40051L12.9015 6.59967C13.3658 6.13541 13.6266 5.50572 13.6266 4.84915C13.6266 4.19258 13.3658 3.56289 12.9015 3.09863C12.4372 2.63436 11.8075 2.37354 11.151 2.37354C10.4944 2.37354 9.86472 2.63436 9.40045 3.09863L9.05034 3.44873", stroke: "currentColor" }), _jsx("path", { d: "M9.40051 6.59959C9.17233 6.3667 8.89997 6.18169 8.59939 6.05538C8.2988 5.92907 7.97603 5.86401 7.64999 5.86401C7.32395 5.86401 7.00118 5.92907 6.70059 6.05538C6.40001 6.18169 6.12765 6.3667 5.89946 6.59959L3.09863 9.40043C2.63436 9.8647 2.37354 10.4944 2.37354 11.151C2.37354 11.8075 2.63436 12.4372 3.09863 12.9015C3.56289 13.3657 4.19258 13.6266 4.84915 13.6266C5.50572 13.6266 6.13541 13.3657 6.59967 12.9015L6.94978 12.5514", stroke: "currentColor" })] }));
|
|
10
|
+
export const IconQueueOutlineMedium = ({ size = 14, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M5 6.75H11", stroke: "currentColor" }), _jsx("path", { d: "M5 9H8", stroke: "currentColor" }), _jsx("path", { d: "M2.37067 11.2497C1.5872 9.89252 1.32042 8.29798 1.61945 6.7597C1.91847 5.22141 2.76317 3.84293 3.99801 2.87809C5.23285 1.91325 6.7747 1.427 8.33964 1.50888C9.90458 1.59076 11.3873 2.23526 12.5147 3.32369C13.6422 4.41232 14.3384 5.8717 14.4751 7.43304C14.6118 8.99438 14.1797 10.5525 13.2585 11.8205C12.3372 13.0885 10.9889 13.9809 9.4617 14.3334C8.18666 14.6277 6.8587 14.529 5.64964 14.0601C5.17095 13.8745 4.76937 13.4929 4.26509 13.3963C3.67389 13.2832 2.95232 13.5595 2.0377 14.3334", stroke: "currentColor" })] }));
|
|
11
|
+
export const IconStopFillMedium = ({ size = 16, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M12.5 2.5H3.5C2.94772 2.5 2.5 2.94772 2.5 3.5V12.5C2.5 13.0523 2.94772 13.5 3.5 13.5H12.5C13.0523 13.5 13.5 13.0523 13.5 12.5V3.5C13.5 2.94772 13.0523 2.5 12.5 2.5Z", fill: "currentColor" }) }));
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* room client plugin, browser half. Mounts the room Remote through the
|
|
3
|
+
* official `ctx.remote.$mount` channel, feeds the client-side RoomStore, and
|
|
4
|
+
* registers the slot entries: the session-header「邀请 agent」action and the
|
|
5
|
+
* 成员 `conversation.view` tab — both self-hiding by the current session's
|
|
6
|
+
* preset composition (M3': visible exactly when the composition names the
|
|
7
|
+
* `@khorsheed/dsh-room-tool` row, fail-open on every unreadable path, and
|
|
8
|
+
* always visible inside an actual room) — plus the `conversation.composer`
|
|
9
|
+
* chain takeover (claims the composer exactly when the current session is a
|
|
10
|
+
* cached room — and renders the dock capsules plus the session stats row
|
|
11
|
+
* itself, because both of their official homes ride the fallback tree the
|
|
12
|
+
* takeover hides). Composing this
|
|
13
|
+
* plugin out of cordis.yml removes every surface it adds.
|
|
14
|
+
* @module @khorsheed/dsh-room/client
|
|
15
|
+
*/
|
|
16
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
17
|
+
import type { TypertRemoteNamespaceMap } from '@deepseek-ai/dsh-typert-protocol';
|
|
18
|
+
/** The room Remote namespace, as mounted by this plugin. */
|
|
19
|
+
export type RoomRemote = TypertRemoteNamespaceMap['room'];
|
|
20
|
+
/**
|
|
21
|
+
* Required services: slots, sessions, the remote channel, and the locale
|
|
22
|
+
* service. `remote.room` is deliberately NOT an inject: this plugin both
|
|
23
|
+
* mounts the namespace (through `$mount` below) and consumes it, and the
|
|
24
|
+
* Cordis property proxy only resolves services declared in `inject` or
|
|
25
|
+
* provided by an ancestor fiber — declaring it would deadlock the loader.
|
|
26
|
+
* The event-Definition registry (`uiConversation.events`) is likewise NOT a
|
|
27
|
+
* static inject: the deferred ctx.inject arm keeps the registration
|
|
28
|
+
* independent of ui-conversation's mount order. The native directory picker
|
|
29
|
+
* (uiWorkspace) is probed at gesture time, never injected.
|
|
30
|
+
*/
|
|
31
|
+
export declare const inject: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Client plugin body: mount the Remote, start the store, register the
|
|
34
|
+
* dictionaries, and inject the slot entries.
|
|
35
|
+
* @param ctx - client root context.
|
|
36
|
+
* @returns disposer unwinding the mounted Remote namespace.
|
|
37
|
+
*/
|
|
38
|
+
export declare function apply(ctx: Context): Promise<() => Promise<void>>;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|