@deepseek-ai/dsh-client-test-runtime 0.0.1-rc.2 → 0.1.0-rc.2

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 CHANGED
@@ -1,28 +1,21 @@
1
- BSD 3-Clause License
1
+ MIT License
2
2
 
3
- Copyright (c) 2026, DeepSeek
3
+ Copyright (c) 2026 DeepSeek
4
4
 
5
- Redistribution and use in source and binary forms, with or without
6
- modification, are permitted provided that the following conditions are met:
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:
7
11
 
8
- 1. Redistributions of source code must retain the above copyright notice, this
9
- list of conditions and the following disclaimer.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
10
14
 
11
- 2. Redistributions in binary form must reproduce the above copyright notice,
12
- this list of conditions and the following disclaimer in the documentation
13
- and/or other materials provided with the distribution.
14
-
15
- 3. Neither the name of the copyright holder nor the names of its
16
- contributors may be used to endorse or promote products derived from
17
- this software without specific prior written permission.
18
-
19
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
- # pnpm run verify-translation-pairing --write packages/client/test-runtime/README.md
5
- README.md: d5c0797c37168578f08a08f3d5d57670d7973db0
6
- README.zh.md: 57854213c3a9ea28850665eb26d07bc824c017e8
4
+ # pnpm run verify-translation-pairing --write packages/test-support/client-runtime/README.md
5
+ README.md: 15646d05daae0a39a36639f335a71d6d208da13b
6
+ README.zh.md: 9624bc8ffc997ba786f3cb1bba670344d44ac60d
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  English | [中文](README.zh.md)
4
4
 
5
- jsdom slot test runtime for client feature specs: a real Cordis `Context`, the production `SlotsService` and web-react renderer, assembled around typed session/workspace doubles. Feature suites exercise declaration, registration, scope, store, inject, rendering, updates, and disposal without hand-building the machinery per suite — and without a second implementation of any production logic.
5
+ jsdom slot test runtime for client feature specs: a real Cordis `Context`, the production `SlotRegistry` and web-react renderer, assembled around typed session/workspace doubles. Feature suites exercise declaration, registration, scope, store, inject, rendering, updates, and disposal without hand-building the machinery per suite — and without a second implementation of any production logic.
6
6
 
7
- The doubles implement the same outward faces features receive through ctx (`TestSessions implements ISessions`, `TestWorkspaces implements IWorkspaces`; each fixture session is a `FixtureSession implements SessionFace`; `stubSettingsScope` is a `SettingsScope` with test-driven publications and a write spy), so a production face change breaks the bench at compile time instead of silently drifting. Provide-bundle materialization runs the production `SessionProvideChannel` — the one implementation shared with `SessionsService`. Fixtures feed plain data: list rows, conversation snapshots (immer-patched via `updateSnapshot`), projection values, and `ISession`-typed behavior stubs that fail loud when a spec calls an unstubbed verb. The typed `provide()` constrains fakes for declared service names to `Partial` of that service's outward face.
7
+ The doubles implement the same outward faces features receive through ctx (`TestSessions implements ISessions`, `TestWorkspaces implements IWorkspaces`; each fixture session is a `FixtureSession implements SessionFace`; `stubSettingsScope` is a `SettingsScope` with test-driven publications and a write spy), so a production face change breaks the bench at compile time instead of silently drifting. Provide-bundle materialization runs the production `SessionProvideChannel` — the one implementation shared with `SessionRuntime`. Fixtures feed plain data: list rows, conversation snapshots (immer-patched via `updateSnapshot`), projection values, and `ISession`-typed behavior stubs that fail loud when a spec calls an unstubbed verb. The typed `provide()` constrains fakes for declared service names to `Partial` of that service's outward face.
8
8
 
9
9
  Local DOM snapshots: `declare(children)` registers an auto frame whose per-key `<div data-slot>` wrappers are snapshot roots; `renderSlot(key, owner)` returns the slot-local view (container, scoped Testing Library queries, in-place `update(owner)`); a registered snapshot serializer folds CSS-module class hashes (`_frame_a1b2c3` → `frame`) to keep `.snap` files structural and collapses `<svg>` internals to a `data-content` fingerprint. Suites needing a custom page frame use `root.declare(children, Frame)` instead; `mount(plugin)` runs a real fiber with fail-loud service prechecks, and `dispose()` tears down views, feature fibers, minted scopes, and persisted store state on one axis.
10
10
 
package/README.zh.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [English](README.md) | 中文
4
4
 
5
- 面向客户端功能测试的 jsdom slot 测试运行时:真实 Cordis `Context`、生产 `SlotsService` 与 web-react 渲染器,围绕带类型的 session/workspace 测试替身组装。功能套件无需逐套件手搭机器即可测遍声明、注册、scope、store、inject、渲染、更新与销毁——且不存在任何生产逻辑的第二份实现。
5
+ 面向客户端功能测试的 jsdom slot 测试运行时:真实 Cordis `Context`、生产 `SlotRegistry` 与 web-react 渲染器,围绕带类型的 session/workspace 测试替身组装。功能套件无需逐套件手搭机器即可测遍声明、注册、scope、store、inject、渲染、更新与销毁——且不存在任何生产逻辑的第二份实现。
6
6
 
7
- 替身实现的正是功能通过 ctx 获得的对外接口(`TestSessions implements ISessions`、`TestWorkspaces implements IWorkspaces`;每个 fixture session 是 `FixtureSession implements SessionFace`;`stubSettingsScope` 是发布由测试驱动、带写入 spy 的 `SettingsScope`),生产面一旦改形,测试台在编译期即断,而非静默漂移。provide bundle 材料化直接运行生产 `SessionProvideChannel`——与 `SessionsService` 共用同一份实现。fixture 灌入的是普通数据:列表行、会话快照(经 `updateSnapshot` 以 immer 补丁改写)、projection 值,以及按 `ISession` 取型的行为桩——spec 调用未打桩的动词时报错自明。带类型的 `provide()` 将已声明服务名的 fake 约束为该服务对外面的 `Partial` 子集。
7
+ 替身实现的正是功能通过 ctx 获得的对外接口(`TestSessions implements ISessions`、`TestWorkspaces implements IWorkspaces`;每个 fixture session 是 `FixtureSession implements SessionFace`;`stubSettingsScope` 是发布由测试驱动、带写入 spy 的 `SettingsScope`),生产面一旦改形,测试台在编译期即断,而非静默漂移。provide bundle 材料化直接运行生产 `SessionProvideChannel`——与 `SessionRuntime` 共用同一份实现。fixture 灌入的是普通数据:列表行、会话快照(经 `updateSnapshot` 以 immer 补丁改写)、projection 值,以及按 `ISession` 取型的行为桩——spec 调用未打桩的动词时报错自明。带类型的 `provide()` 将已声明服务名的 fake 约束为该服务对外面的 `Partial` 子集。
8
8
 
9
9
  局部 DOM 快照:`declare(children)` 注册自动 frame,逐 key 的 `<div data-slot>` 包裹层即快照根;`renderSlot(key, owner)` 返回该 slot 的局部视图(container、限定范围的 Testing Library 查询、原位 `update(owner)`);注册的快照序列化器把 CSS-module 哈希类名折回语义名(`_frame_a1b2c3` → `frame`)保持 `.snap` 只含结构,并把 `<svg>` 内部折叠为 `data-content` 指纹。需要自定义页面 frame 的套件改用 `root.declare(children, Frame)`;`mount(plugin)` 在真实 fiber 上运行并对缺失服务先行报错;`dispose()` 沿单一轴拆除视图、feature fiber、已铸 scope 与持久化 store 状态。
10
10
 
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Context, Inject } from "@deepseek-ai/cordis";
2
2
  import { Fragment, createElement, useSyncExternalStore } from "react";
3
3
  import { act, render, within } from "@testing-library/react";
4
- import { ConversationEventRegistry, ConversationViewRegistry, EMPTY_CHAT_SNAPSHOT, EMPTY_CONVERSATION_VIEWS, SessionProvideChannel, SlotsService, createScope, createSnapshotStore, scopeOf } from "@deepseek-ai/dsh-client-runtime/client";
4
+ import { ConversationEventRegistry, ConversationViewRegistry, EMPTY_CHAT_SNAPSHOT, EMPTY_CONVERSATION_VIEWS, SessionProvideChannel, SlotRegistry, createScope, createSnapshotStore, scopeOf } from "@deepseek-ai/dsh-client-runtime/client";
5
5
  import { createSlotRenderer } from "@deepseek-ai/dsh-client-web-react";
6
6
  import { afterEach, beforeEach, expect, vi } from "vitest";
7
7
  import { SESSION_SEARCH_RESULT_LIMIT } from "@deepseek-ai/dsh-host-apiproxy/api";
@@ -113,7 +113,7 @@ function conversationSnapshot(sessionId) {
113
113
  };
114
114
  }
115
115
  /**
116
- * A ready workspace list with no workspaces (the shape WorkspacesService
116
+ * A ready workspace list with no workspaces (the shape WorkspaceRuntime
117
117
  * projects after both baselines land).
118
118
  * @returns the initial state of the test workspaces store.
119
119
  */
@@ -262,9 +262,9 @@ var TestSessions = class {
262
262
  /** The useSessions standard feed (list rows + current selection). */
263
263
  list;
264
264
  /**
265
- * Atomic current-session provide projection (production SessionsService
265
+ * Atomic current-session provide projection (production SessionRuntime
266
266
  * mirror): selection changes and provider-roster changes publish through
267
- * this one source — the member the SlotsService host face hands the
267
+ * this one source — the member the SlotRegistry host face hands the
268
268
  * renderer's SessionProvider.
269
269
  */
270
270
  currentProvideInfo;
@@ -290,7 +290,7 @@ var TestSessions = class {
290
290
  current: void 0,
291
291
  phase: "ready",
292
292
  subagentsByParent: {},
293
- tasksBySession: {},
293
+ jobsBySession: {},
294
294
  currentAddress: void 0
295
295
  });
296
296
  this.channel = new SessionProvideChannel({
@@ -387,7 +387,7 @@ var TestSessions = class {
387
387
  /**
388
388
  * Remove a session: list row, scope fiber, and per-session store instances
389
389
  * (with persisted state) die together — the same single lifecycle axis the
390
- * production SessionsService drives on session death, minus staging.
390
+ * production SessionRuntime drives on session death, minus staging.
391
391
  * @param id - session id.
392
392
  */
393
393
  async remove(id) {
@@ -822,6 +822,18 @@ var TestWorkspaces = class {
822
822
  await this.stubs.get("delete")?.(workspaceId);
823
823
  }
824
824
  /**
825
+ * Move a Workspace in display order (recorded; default no-op).
826
+ * @param workspaceId - Workspace to move.
827
+ * @param beforeWorkspaceId - Anchor; omitted appends.
828
+ */
829
+ async insertBefore(workspaceId, beforeWorkspaceId) {
830
+ this.calls.push({
831
+ method: "insertBefore",
832
+ args: [workspaceId, beforeWorkspaceId]
833
+ });
834
+ await this.stubs.get("insertBefore")?.(workspaceId, beforeWorkspaceId);
835
+ }
836
+ /**
825
837
  * Move an accounted session (recorded). The default echoes a minimal view.
826
838
  * @param workspaceId - target workspace.
827
839
  * @param sessionId - session to move.
@@ -978,7 +990,7 @@ var TestRemote = class {
978
990
  //#region lib/types/translate.js
979
991
  /**
980
992
  * Test double of the locale lookup chain: a translate stub over plain
981
- * dictionaries, mirroring LocaleService's resolution order (first dictionary
993
+ * dictionaries, mirroring LocaleRuntime's resolution order (first dictionary
982
994
  * that owns the key wins, then the key itself stays visible) and its
983
995
  * `{name}` template interpolation. Specs stub the framework-injected `t`
984
996
  * seat with `makeTranslate(zh, commonZh)` instead of re-implementing the
@@ -1008,7 +1020,7 @@ function makeTranslate(...dicts) {
1008
1020
  //#region lib/types/locale-env.js
1009
1021
  /**
1010
1022
  * Browser-language pin for specs that assert localized copy. A fresh
1011
- * LocaleService with no stored preference opens in the language `navigator`
1023
+ * LocaleRuntime with no stored preference opens in the language `navigator`
1012
1024
  * asks for, and jsdom reports the runner's own (`en-US`) — so a spec asserting
1013
1025
  * the product's Chinese copy states the browser it assumes instead of
1014
1026
  * inheriting the machine's.
@@ -1041,7 +1053,7 @@ function usePinnedBrowserLanguages(primary, ...rest) {
1041
1053
  //#region lib/types/index.js
1042
1054
  /**
1043
1055
  * jsdom slot test runtime: a real small runtime — Cordis `Context`, the
1044
- * runtime `SlotsService`, and the web-react renderer — assembled around
1056
+ * runtime `SlotRegistry`, and the web-react renderer — assembled around
1045
1057
  * test-owned session/workspace doubles, so feature specs exercise
1046
1058
  * declaration, registration, scope, store, inject, rendering, updates, and
1047
1059
  * disposal without hand-building the machinery per suite.
@@ -1099,7 +1111,7 @@ var TestRoot = class {
1099
1111
  stabilize;
1100
1112
  disposeEntry;
1101
1113
  /**
1102
- * @param slots - the runtime SlotsService.
1114
+ * @param slots - the runtime SlotRegistry.
1103
1115
  * @param stabilize - the owning runtime's act wrapper.
1104
1116
  */
1105
1117
  constructor(slots, stabilize) {
@@ -1137,7 +1149,7 @@ var TestRoot = class {
1137
1149
  var SlotTestRuntime = class SlotTestRuntime {
1138
1150
  /** The runtime's Cordis root (escape hatch: extra services via `ctx.provide`, raw `ctx.plugin` mounts). */
1139
1151
  ctx;
1140
- /** The production SlotsService mounted on {@link SlotTestRuntime.ctx}. */
1152
+ /** The production SlotRegistry mounted on {@link SlotTestRuntime.ctx}. */
1141
1153
  slots;
1142
1154
  /** The test-owned 'root' occupant. */
1143
1155
  root;
@@ -1173,14 +1185,14 @@ var SlotTestRuntime = class SlotTestRuntime {
1173
1185
  } });
1174
1186
  }
1175
1187
  /**
1176
- * Assemble a runtime: real Context, mounted SlotsService, installed
1188
+ * Assemble a runtime: real Context, mounted SlotRegistry, installed
1177
1189
  * renderer, and the session/workspace doubles provided as services.
1178
1190
  * @returns the ready runtime.
1179
1191
  */
1180
1192
  static async create() {
1181
1193
  registerDomSnapshotSerializer();
1182
1194
  const ctx = new Context();
1183
- await ctx.plugin(SlotsService).await();
1195
+ await ctx.plugin(SlotRegistry).await();
1184
1196
  await ctx.plugin(ConversationEventRegistry).await();
1185
1197
  await ctx.plugin(ConversationViewRegistry).await();
1186
1198
  return new SlotTestRuntime(ctx, ctx.get("slots"));
@@ -1237,10 +1249,10 @@ var SlotTestRuntime = class SlotTestRuntime {
1237
1249
  /**
1238
1250
  * Declare child slots under an auto-generated root frame — the single-slot
1239
1251
  * mounting path for local DOM snapshots. Each key later supplied through
1240
- * {@link SlotTestRuntime.renderSlot} renders inside its own
1241
- * `<div data-slot="<key>">` wrapper (the snapshot root). Mutually exclusive
1242
- * with {@link TestRoot.declare} ('root' is a single slot); one call per
1243
- * runtime.
1252
+ * {@link SlotTestRuntime.renderSlot} renders inside the renderer's own
1253
+ * `<div data-slot="<key>">` outlet anchor (the snapshot root the frame
1254
+ * adds no wrapper of its own). Mutually exclusive with
1255
+ * {@link TestRoot.declare} ('root' is a single slot); one call per runtime.
1244
1256
  * @param children - child-slot declaration table (same contract as TestRoot.declare).
1245
1257
  * @returns completion of the act-wrapped registration.
1246
1258
  */
@@ -1249,10 +1261,7 @@ var SlotTestRuntime = class SlotTestRuntime {
1249
1261
  const cell = this.ownerCell;
1250
1262
  const AutoFrame = (props) => {
1251
1263
  useSyncExternalStore(cell.subscribe, cell.getVersion);
1252
- return createElement(Fragment, null, cell.entries().map(([key, owner]) => createElement("div", {
1253
- "data-slot": key,
1254
- key
1255
- }, props.renderSlot(key, owner))));
1264
+ return createElement(Fragment, null, cell.entries().map(([key, owner]) => createElement(Fragment, { key }, props.renderSlot(key, owner))));
1256
1265
  };
1257
1266
  await this.root.declare(children, AutoFrame);
1258
1267
  }
package/lib/invariant.js CHANGED
@@ -10,7 +10,7 @@ const name = "client-test-runtime-invariant";
10
10
  const inject = ["invariants"];
11
11
  /**
12
12
  * No runtime invariant: this test-support package owns no production event
13
- * stream or mutable data — it assembles the runtime SlotsService and renderer
13
+ * stream or mutable data — it assembles the runtime SlotRegistry and renderer
14
14
  * (whose packages own their invariants) around test doubles; its own behavior
15
15
  * is exercised by its package tests.
16
16
  */
@@ -38,7 +38,7 @@ export interface SessionFixture {
38
38
  */
39
39
  export declare function conversationSnapshot(sessionId: SessionId): ConversationSnapshot;
40
40
  /**
41
- * A ready workspace list with no workspaces (the shape WorkspacesService
41
+ * A ready workspace list with no workspaces (the shape WorkspaceRuntime
42
42
  * projects after both baselines land).
43
43
  * @returns the initial state of the test workspaces store.
44
44
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * jsdom slot test runtime: a real small runtime — Cordis `Context`, the
3
- * runtime `SlotsService`, and the web-react renderer — assembled around
3
+ * runtime `SlotRegistry`, and the web-react renderer — assembled around
4
4
  * test-owned session/workspace doubles, so feature specs exercise
5
5
  * declaration, registration, scope, store, inject, rendering, updates, and
6
6
  * disposal without hand-building the machinery per suite.
@@ -15,7 +15,7 @@ import type { Fiber, Plugin } from '@deepseek-ai/cordis';
15
15
  import type { RenderResult } from '@testing-library/react';
16
16
  import type { queries } from '@testing-library/dom';
17
17
  import type { BoundFunctions } from '@testing-library/dom';
18
- import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client';
18
+ import { SlotRegistry } from '@deepseek-ai/dsh-client-runtime/client';
19
19
  import type { ChildrenDecl, ComposedProps, OwnerOf, SlotComponent, SlotMap, StoreInstanceLike } from '@deepseek-ai/dsh-client-ui-slots';
20
20
  import { TestSessions } from './sessions.ts';
21
21
  import { TestWorkspaces } from './workspaces.ts';
@@ -32,12 +32,13 @@ export { makeTranslate } from './translate.ts';
32
32
  export { usePinnedBrowserLanguages } from './locale-env.ts';
33
33
  /**
34
34
  * One rendered slot's local view, from {@link SlotTestRuntime.renderSlot}:
35
- * the `data-slot` wrapper is the snapshot root (`expect(view.container)
36
- * .toMatchSnapshot()` captures exactly this slot's output), Testing Library
37
- * queries are bound inside it, and `update` re-renders with new owner props.
35
+ * the renderer's own `[data-slot]` outlet anchor is the snapshot root
36
+ * (`expect(view.container).toMatchSnapshot()` captures exactly this slot's
37
+ * output), Testing Library queries are bound inside it, and `update`
38
+ * re-renders with new owner props.
38
39
  */
39
40
  export interface SlotView<K extends keyof SlotMap & string> {
40
- /** The `<div data-slot="<key>">` wrapper around the slot's rendered output. */
41
+ /** The renderer's `<div data-slot="<key>">` anchor around the slot's rendered output. */
41
42
  readonly container: HTMLElement;
42
43
  /** Testing Library queries scoped to {@link SlotView.container}. */
43
44
  readonly view: BoundFunctions<typeof queries>;
@@ -72,10 +73,10 @@ export declare class TestRoot {
72
73
  private readonly stabilize;
73
74
  private disposeEntry;
74
75
  /**
75
- * @param slots - the runtime SlotsService.
76
+ * @param slots - the runtime SlotRegistry.
76
77
  * @param stabilize - the owning runtime's act wrapper.
77
78
  */
78
- constructor(slots: SlotsService, stabilize: Stabilizer);
79
+ constructor(slots: SlotRegistry, stabilize: Stabilizer);
79
80
  /**
80
81
  * Register the root frame, declaring (and thereby claiming) the child
81
82
  * slots. One declaration per runtime — a second call fails loud in the
@@ -97,8 +98,8 @@ export declare class TestRoot {
97
98
  export declare class SlotTestRuntime {
98
99
  /** The runtime's Cordis root (escape hatch: extra services via `ctx.provide`, raw `ctx.plugin` mounts). */
99
100
  readonly ctx: Context;
100
- /** The production SlotsService mounted on {@link SlotTestRuntime.ctx}. */
101
- readonly slots: SlotsService;
101
+ /** The production SlotRegistry mounted on {@link SlotTestRuntime.ctx}. */
102
+ readonly slots: SlotRegistry;
102
103
  /** The test-owned 'root' occupant. */
103
104
  readonly root: TestRoot;
104
105
  /** Sessions double (list/current observable, cells, scopes, behavior faces). */
@@ -116,7 +117,7 @@ export declare class SlotTestRuntime {
116
117
  private autoRootView;
117
118
  private constructor();
118
119
  /**
119
- * Assemble a runtime: real Context, mounted SlotsService, installed
120
+ * Assemble a runtime: real Context, mounted SlotRegistry, installed
120
121
  * renderer, and the session/workspace doubles provided as services.
121
122
  * @returns the ready runtime.
122
123
  */
@@ -149,10 +150,10 @@ export declare class SlotTestRuntime {
149
150
  /**
150
151
  * Declare child slots under an auto-generated root frame — the single-slot
151
152
  * mounting path for local DOM snapshots. Each key later supplied through
152
- * {@link SlotTestRuntime.renderSlot} renders inside its own
153
- * `<div data-slot="<key>">` wrapper (the snapshot root). Mutually exclusive
154
- * with {@link TestRoot.declare} ('root' is a single slot); one call per
155
- * runtime.
153
+ * {@link SlotTestRuntime.renderSlot} renders inside the renderer's own
154
+ * `<div data-slot="<key>">` outlet anchor (the snapshot root the frame
155
+ * adds no wrapper of its own). Mutually exclusive with
156
+ * {@link TestRoot.declare} ('root' is a single slot); one call per runtime.
156
157
  * @param children - child-slot declaration table (same contract as TestRoot.declare).
157
158
  * @returns completion of the act-wrapped registration.
158
159
  */
@@ -1,4 +1,4 @@
1
- /** Test-owned sessions face: the SlotsService host contract over declarative fixtures. */
1
+ /** Test-owned sessions face: the SlotRegistry host contract over declarative fixtures. */
2
2
  import type { Context } from '@deepseek-ai/cordis';
3
3
  import type { AttachmentIdType } from '@deepseek-ai/dsh-attachment';
4
4
  import type { AgentContext, ConversationSnapshot, ISessions, ProjectionsFace, SessionFace, SessionId, SessionListState, SessionProvideDescriptor, SessionSearchResultItem, SessionSummary, SnapshotStore, SubagentAddress } from '@deepseek-ai/dsh-client-runtime/client';
@@ -95,9 +95,9 @@ export declare class TestSessions implements ISessions {
95
95
  /** The useSessions standard feed (list rows + current selection). */
96
96
  readonly list: SnapshotStore<SessionListState>;
97
97
  /**
98
- * Atomic current-session provide projection (production SessionsService
98
+ * Atomic current-session provide projection (production SessionRuntime
99
99
  * mirror): selection changes and provider-roster changes publish through
100
- * this one source — the member the SlotsService host face hands the
100
+ * this one source — the member the SlotRegistry host face hands the
101
101
  * renderer's SessionProvider.
102
102
  */
103
103
  readonly currentProvideInfo: HostObservable<SessionMaybeProvideInfo>;
@@ -149,7 +149,7 @@ export declare class TestSessions implements ISessions {
149
149
  /**
150
150
  * Remove a session: list row, scope fiber, and per-session store instances
151
151
  * (with persisted state) die together — the same single lifecycle axis the
152
- * production SessionsService drives on session death, minus staging.
152
+ * production SessionRuntime drives on session death, minus staging.
153
153
  * @param id - session id.
154
154
  */
155
155
  remove(id: string): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Test double of the locale lookup chain: a translate stub over plain
3
- * dictionaries, mirroring LocaleService's resolution order (first dictionary
3
+ * dictionaries, mirroring LocaleRuntime's resolution order (first dictionary
4
4
  * that owns the key wins, then the key itself stays visible) and its
5
5
  * `{name}` template interpolation. Specs stub the framework-injected `t`
6
6
  * seat with `makeTranslate(zh, commonZh)` instead of re-implementing the
@@ -91,6 +91,12 @@ export declare class TestWorkspaces implements IWorkspaces {
91
91
  * @param workspaceId - target workspace.
92
92
  */
93
93
  delete(workspaceId: WorkspaceId): Promise<void>;
94
+ /**
95
+ * Move a Workspace in display order (recorded; default no-op).
96
+ * @param workspaceId - Workspace to move.
97
+ * @param beforeWorkspaceId - Anchor; omitted appends.
98
+ */
99
+ insertBefore(workspaceId: WorkspaceId, beforeWorkspaceId?: WorkspaceId): Promise<void>;
94
100
  /**
95
101
  * Move an accounted session (recorded). The default echoes a minimal view.
96
102
  * @param workspaceId - target workspace.
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-test-runtime",
3
- "description": "jsdom slot test runtime: real Cordis Context + SlotsService + web-react renderer with test-owned session/workspace doubles for feature specs",
4
- "version": "0.0.1-rc.2",
3
+ "description": "jsdom slot test runtime: real Cordis Context + SlotRegistry + web-react renderer with test-owned session/workspace doubles for feature specs",
4
+ "version": "0.1.0-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
11
- "directory": "packages/client/test-runtime"
11
+ "directory": "packages/test-support/client-runtime"
12
12
  },
13
13
  "type": "module",
14
14
  "main": "lib/index.js",
@@ -25,7 +25,7 @@
25
25
  "./src/*": "./src/*",
26
26
  "./package.json": "./package.json"
27
27
  },
28
- "license": "BSD-3-Clause",
28
+ "license": "MIT",
29
29
  "dependencies": {
30
30
  "@testing-library/dom": "^10.4.1",
31
31
  "@testing-library/react": "^16.3.2",
@@ -34,24 +34,24 @@
34
34
  "peerDependencies": {
35
35
  "react": "^18.2.0",
36
36
  "react-dom": "^18.2.0",
37
- "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.2",
38
- "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.2",
39
- "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.2",
40
- "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.2",
41
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
42
- "@deepseek-ai/cordis": "^4.0.1-rc.1"
37
+ "@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.2",
38
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.2",
39
+ "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.2",
40
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.2",
41
+ "@deepseek-ai/cordis": "^4.0.1",
42
+ "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.2"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/react": "~18.3.1",
46
46
  "@types/react-dom": "~18.3.0",
47
47
  "react": "^18.2.0",
48
48
  "react-dom": "^18.2.0",
49
- "@deepseek-ai/dsh-client-runtime": "^0.0.1-rc.2",
50
- "@deepseek-ai/dsh-client-ui-slots": "^0.0.1-rc.2",
51
- "@deepseek-ai/dsh-host-apiproxy": "^0.0.1-rc.2",
52
- "@deepseek-ai/dsh-client-web-react": "^0.0.1-rc.2",
53
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
54
- "@deepseek-ai/cordis": "^4.0.1-rc.1"
49
+ "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.2",
50
+ "@deepseek-ai/dsh-client-web-react": "^0.1.0-rc.2",
51
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.2",
52
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.2",
53
+ "@deepseek-ai/cordis": "^4.0.1",
54
+ "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.2"
55
55
  },
56
56
  "files": [
57
57
  "lib/index.js",