@qilin-agent/client-test-runtime 3.1.7 → 3.1.9

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/README.i18n.yaml CHANGED
@@ -6,8 +6,8 @@
6
6
  en: 6fd77b7a27000bf1
7
7
  zh: 4a9606aa75285111
8
8
  /qilin-agent-client-test-runtime:
9
- en: 98930800a1b3f9df
10
- zh: 40284d89485f924e
9
+ en: d67e576407527114
10
+ zh: ff4b26a96adb4c5d
11
11
  /qilin-agent-client-test-runtime/summary:
12
12
  en: 7f54f8cd8f6bce97
13
13
  zh: 90527ba60f855dc2
@@ -30,8 +30,8 @@
30
30
  en: f089ab96a088895d
31
31
  zh: 31852d191de6604d
32
32
  /qilin-agent-client-test-runtime/use-this-package/roster-and-startup-behavior:
33
- en: bb3ec77a5fb158e7
34
- zh: e2251ec69a305feb
33
+ en: 15466d568bd44194
34
+ zh: 86f0b47679a0c2dd
35
35
  /qilin-agent-client-test-runtime/use-this-package/when-to-use-it:
36
36
  en: eb2f9bc90acb7a62
37
37
  zh: cb59a2134bc83106
@@ -45,7 +45,7 @@
45
45
  en: d9d7e2f11d3dfbc9
46
46
  zh: bfddde279a836900
47
47
  /qilin-agent-client-test-runtime/understand-the-implementation/source-map:
48
- en: bf31d10735c9a3b3
48
+ en: 20e3be303554ead3
49
49
  zh: 095ac3e7a8361383
50
50
  /qilin-agent-client-test-runtime/understand-the-implementation/lifecycle:
51
51
  en: b42779f364504719
package/README.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-library"
7
7
 
8
8
  English | [中文](README.zh.md)
9
9
 
10
+ Direct component fixtures use `contextMenuHook(open)` to supply the global menu hook with production gesture handling. An unstubbed activation throws; Slot composition tests mount the menu plugin itself.
11
+
10
12
  ## Summary
11
13
 
12
14
  `SlotTestRuntime.create()` lets Vitest suites drive production slots, stores, typed Session and Workspace fixtures, and local DOM assertions in jsdom. For plugin activation, reload, reconnect, and cleanup tests, `createClientTest` starts the web profile's bundle roster with endpoint-named Remote mocks, without a business Host. Missing services and unstubbed calls fail explicitly. The whole-client fixture owns startup and disposal; the local runtime provides idempotent disposal. Use this package through `devDependencies` for client tests; it is not a product plugin.
@@ -87,7 +89,7 @@ The [generic Remote proxy](../remote-mock/README.md#remote-proxy) supports every
87
89
 
88
90
  ### Roster and startup behavior
89
91
 
90
- `webApp` is the `web` profile's browser roster, read when the assembly entry is first imported from its bundles (`qilin-base`, then `qilin-web-app`) as the launcher composes them, except that a patch matching nothing throws here where the launcher warns: each bundle's `qilin.bundle.patch` list is parsed with the include plugin's YAML dialect and composed by its `applyEntryPatches`, and every enabled row whose package declares `qilin.client.platform === 'web'` becomes a row carrying that declaration's `inject` and `immediately`; `bundleRoster(bundles)` does the same for any bundle list. Nothing is copied from the bundles, so a bundle change is visible at the next test run. `webApp.closure(names)` keeps the named rows plus everything they inject, transitively (the rows a spec needs to boot those plugins as the bundle composes them), `webApp.pick(names)` and `webApp.without(names)` cut it down by hand, all three throw on unknown names, and `ClientRoster.of(rows)` builds one inline. `remoteDefaultResponses` holds default responses for exactly the Remote endpoints the roster calls while booting with no sessions, no workspaces, and default settings; a spec layers its own `RemoteTable` on top with `mock.load(table)`, and any call without a rule fails the test at `dispose()` through `mock.assertNoUnmatched()`. `mount` requires a roster that provides `uiRenderer`; `start` fails loud otherwise instead of returning an empty container. `client.connection` is the roster's Connection service (no `Context` augmentation declares it), and `connectTimeoutMs` bounds the readiness wait, whose failure message lists the mock log. `reload(name)` rebuilds one Loader entry through the shared Client Modules helper (registry-first teardown, then `entry.refresh()`); each client retains its own module system and instance-bound Connection replacement, so starts and reloads can overlap without changing a page global. `unload(name)` removes an entry and waits for plugin cleanup; `flush()` settles React inside `act`. jsdom implements neither `EventSource` (client-hmr opens one at apply) nor `ResizeObserver` (layout components observe size at mount), so `start` reference-counts inert stubs for whichever global is absent and `dispose` removes exactly those — a jsdom gap, not a client identity channel. The `@qilin-agent/api-remotes` row is dropped from every roster: its generated Remote clients exist only in built `lib/`, and `remote.<ns>` is what the tier replaces anyway. `start` instead provides one contract-free proxy per `remote.<ns>` service the roster injects (plus the namespaces the mock has rules for at that point; a namespace first registered later has no proxy); `ctx.remote.<ns>.<method>(...args)` becomes a call on the endpoint `<ns>/<method>` carrying the positional args, a stream when the mock registered a `stream()` script and a unary call otherwise, with the generated client's outcome folding (`gateway/internal` for carrier throws, `gateway/cancelled` on abort). An endpoint without a rule is still dispatched, so the mock logs it and `dispose()` fails the test.
92
+ `webApp` is the `web` profile's browser roster, read when the assembly entry is first imported from its bundles (`qilin-base`, then `qilin-web-app`) as the launcher composes them, except that a patch matching nothing throws here where the launcher warns: each bundle's `qilin.bundle.patch` list is parsed with the include plugin's YAML dialect and composed by its `applyEntryPatches`, and every enabled row whose package declares `qilin.client.platform === 'web'` becomes a row carrying that declaration's `inject` and `immediately`; `bundleRoster(bundles)` does the same for any bundle list. Nothing is copied from the bundles, so a bundle change is visible at the next test run. `webApp.closure(names)` keeps the named rows plus everything they inject, transitively (the rows a spec needs to boot those plugins as the bundle composes them), `webApp.pick(names)` and `webApp.without(names)` cut it down by hand, all three throw on unknown names, and `ClientRoster.of(rows)` builds one inline. `remoteDefaultResponses` holds default responses for exactly the Remote endpoints the roster calls while booting with no sessions, no workspaces, and default settings; a spec layers its own `RemoteTable` on top with `mock.load(table)`, and any call without a rule fails the test at `dispose()` through `mock.assertNoUnmatched()`. `mount` requires a roster that provides `uiRenderer`; `start` fails loud otherwise instead of returning an empty container. `client.connection` is the roster's Connection service (no `Context` augmentation declares it), and `connectTimeoutMs` bounds the readiness wait, whose failure message lists the mock log. `reload(name)` rebuilds one Loader entry through the shared Client Modules helper (registry-first teardown, then `entry.refresh()`); each client retains its own module system and instance-bound Connection replacement, so starts and reloads can overlap without changing a page global. `unload(name)` removes an entry and waits for plugin cleanup; `flush()` settles React inside `act`. jsdom implements neither `EventSource` (client-hmr opens one at apply) nor `ResizeObserver` or `matchMedia` (layout components observe size and media queries at mount), so `start` reference-counts inert stubs for whichever global is absent and `dispose` removes exactly those — a jsdom gap, not a client identity channel. The `@qilin-agent/api-remotes` row is dropped from every roster: its generated Remote clients exist only in built `lib/`, and `remote.<ns>` is what the tier replaces anyway. `start` instead provides one contract-free proxy per `remote.<ns>` service the roster injects (plus the namespaces the mock has rules for at that point; a namespace first registered later has no proxy); `ctx.remote.<ns>.<method>(...args)` becomes a call on the endpoint `<ns>/<method>` carrying the positional args, a stream when the mock registered a `stream()` script and a unary call otherwise, with the generated client's outcome folding (`gateway/internal` for carrier throws, `gateway/cancelled` on abort). An endpoint without a rule is still dispatched, so the mock logs it and `dispose()` fails the test.
91
93
 
92
94
  ### When to use it
93
95
 
@@ -124,7 +126,7 @@ The bench copies no production logic: it mounts the production `SlotRegistry`, p
124
126
  | [`src/remote.ts`](src/remote.ts) | `TestRemote` double for host RPC, `RemoteError` value re-export |
125
127
  | [`src/translate.ts`](src/translate.ts) + [`src/locale-env.ts`](src/locale-env.ts) | Translation and pinned-browser-language test helpers |
126
128
  | [`src/config-form.ts`](src/config-form.ts) | `stubConfigForm` with test-driven publications and write spies |
127
- | [`src/access.ts`](src/access.ts) | `allowAllAccess`: the access-Hook share hand-built component props spread |
129
+ | [`src/access.ts`](src/access.ts) | `allowAllAccess`: the root and Session access-Hook share hand-built component props spread |
128
130
  | [`src/assembly/roster.ts`](src/assembly/roster.ts) | `ClientRosterRow`, `ClientRoster` (`of`/`closure`/`pick`/`without`), the `AssemblyPlan` it annotates, and `graphFromRoster` |
129
131
  | [`src/assembly/modules.ts`](src/assembly/modules.ts) | Source `/client` imports and replacements, registered through the production module facade's pending factory queue |
130
132
  | [`src/assembly/test-client.ts`](src/assembly/test-client.ts) | `TestClient`: instance-bound Connection, shared jsdom shims, `bootClient`, mount, readiness wait, `reload`/`unload`/`dispose` |
package/README.zh.md CHANGED
@@ -7,6 +7,8 @@ kind: "package-library"
7
7
 
8
8
  [English](README.md) | 中文
9
9
 
10
+ 直接挂载组件的夹具使用 `contextMenuHook(open)` 提供全局菜单 hook,并复用生产手势处理。未提供行为的触发会抛错;Slot 组合测试挂载菜单插件本身。
11
+
10
12
  ## 概述
11
13
 
12
14
  `SlotTestRuntime.create()` 让 Vitest 套件在 jsdom 中驱动生产 slot、store、带类型的 Session 与 Workspace fixture,并对局部 DOM 断言。面向插件激活、重载、重连与清理的测试,`createClientTest` 使用具名端点 Remote mock 启动 web profile 的 bundle roster,无需业务 Host。缺失服务与未打桩调用会明确失败。整机 fixture 拥有启动和销毁,局部 runtime 提供幂等销毁。通过 `devDependencies` 将本包用于客户端测试;它不是产品插件。
@@ -87,7 +89,7 @@ test('registers into the sidebar', async ({ remote, start }) => {
87
89
 
88
90
  ### Roster 与启动行为
89
91
 
90
- `webApp` 是 `web` profile 的浏览器 roster,首次 import 装配入口时从它的 bundle(先 `qilin-base`、再 `qilin-web-app`)按启动器的方式现读,只是匹配不到任何行的补丁在这里抛错、启动器只警告:每个 bundle 的 `qilin.bundle.patch` 列表用 include 插件的 YAML 方言解析、用它的 `applyEntryPatches` 合成,每个未禁用且其包声明 `qilin.client.platform === 'web'` 的行成为一行,带上该声明的 `inject` 与 `immediately`;`bundleRoster(bundles)` 对任意 bundle 列表做同样的事。没有任何东西从 bundle 拷贝出来,bundle 一改下次跑测试就能看见。`webApp.closure(names)` 保留点名的行及其传递注入的全部行(即按 bundle 组合方式起这些插件所需的行),`webApp.pick(names)` 与 `webApp.without(names)` 手工裁剪,三者都对未知名字抛错,`ClientRoster.of(rows)` 内联构造一份。`remoteDefaultResponses` 是 roster 在没有 session、没有 workspace、默认设置下启动时恰好会打的那些 Remote 端点的默认响应;测试用 `mock.load(table)` 在其上叠加自己的 `RemoteTable`,任何没有规则的调用都会在 `dispose()` 时经 `mock.assertNoUnmatched()` 让测试失败。`mount` 要求 roster 提供 `uiRenderer`;否则 `start` 响亮失败而不是返回一个空容器。`client.connection` 是 roster 的 Connection 服务(没有任何 `Context` 增强声明它),`connectTimeoutMs` 限定等就绪的时长,超时消息列出 mock log。`reload(name)` 通过共享的 Client Modules 辅助函数重建一个 Loader entry(先拆 registry,再 `entry.refresh()`);每个客户端都保留自己的模块系统和绑定实例的 Connection 替换,因此启动与重载可以重叠而无需改写页面全局变量。`unload(name)` 移除 entry 并等待插件清理完成,`flush()` 在 `act` 内让 React 落定。jsdom 既没有 `EventSource`(client-hmr 在 apply 时打开一个)也没有 `ResizeObserver`(布局组件挂载时观察尺寸),所以 `start` 对缺失的全局惰性桩做引用计数,`dispose` 只移除它装的那些——这是 jsdom 的缺口,不是客户端身份通道。每个 roster 里的 `@qilin-agent/api-remotes` 行都会被去掉:它生成的 Remote 客户端只存在于构建后的 `lib/`,而 `remote.<ns>` 正是本档要替掉的东西。`start` 改为给 roster 注入的每个 `remote.<ns>` 服务(加上此刻 mock 登记过规则的命名空间;之后才首次登记的命名空间没有代理)提供一个无契约代理;`ctx.remote.<ns>.<method>(...args)` 变成对端点 `<ns>/<method>` 的调用,携带位置参数,mock 登记了 `stream()` 脚本的走流、否则走一元,并沿用生成客户端的结果折叠(载体抛错折成 `gateway/internal`,中止折成 `gateway/cancelled`)。没有规则的端点照样发出,所以 mock 会记下它、`dispose()` 让测试失败。
92
+ `webApp` 是 `web` profile 的浏览器 roster,首次 import 装配入口时从它的 bundle(先 `qilin-base`、再 `qilin-web-app`)按启动器的方式现读,只是匹配不到任何行的补丁在这里抛错、启动器只警告:每个 bundle 的 `qilin.bundle.patch` 列表用 include 插件的 YAML 方言解析、用它的 `applyEntryPatches` 合成,每个未禁用且其包声明 `qilin.client.platform === 'web'` 的行成为一行,带上该声明的 `inject` 与 `immediately`;`bundleRoster(bundles)` 对任意 bundle 列表做同样的事。没有任何东西从 bundle 拷贝出来,bundle 一改下次跑测试就能看见。`webApp.closure(names)` 保留点名的行及其传递注入的全部行(即按 bundle 组合方式起这些插件所需的行),`webApp.pick(names)` 与 `webApp.without(names)` 手工裁剪,三者都对未知名字抛错,`ClientRoster.of(rows)` 内联构造一份。`remoteDefaultResponses` 是 roster 在没有 session、没有 workspace、默认设置下启动时恰好会打的那些 Remote 端点的默认响应;测试用 `mock.load(table)` 在其上叠加自己的 `RemoteTable`,任何没有规则的调用都会在 `dispose()` 时经 `mock.assertNoUnmatched()` 让测试失败。`mount` 要求 roster 提供 `uiRenderer`;否则 `start` 响亮失败而不是返回一个空容器。`client.connection` 是 roster 的 Connection 服务(没有任何 `Context` 增强声明它),`connectTimeoutMs` 限定等就绪的时长,超时消息列出 mock log。`reload(name)` 通过共享的 Client Modules 辅助函数重建一个 Loader entry(先拆 registry,再 `entry.refresh()`);每个客户端都保留自己的模块系统和绑定实例的 Connection 替换,因此启动与重载可以重叠而无需改写页面全局变量。`unload(name)` 移除 entry 并等待插件清理完成,`flush()` 在 `act` 内让 React 落定。jsdom 既没有 `EventSource`(client-hmr 在 apply 时打开一个)也没有 `ResizeObserver` 和 `matchMedia`(布局组件挂载时观察尺寸与媒体查询),所以 `start` 对缺失的全局惰性桩做引用计数,`dispose` 只移除它装的那些——这是 jsdom 的缺口,不是客户端身份通道。每个 roster 里的 `@qilin-agent/api-remotes` 行都会被去掉:它生成的 Remote 客户端只存在于构建后的 `lib/`,而 `remote.<ns>` 正是本档要替掉的东西。`start` 改为给 roster 注入的每个 `remote.<ns>` 服务(加上此刻 mock 登记过规则的命名空间;之后才首次登记的命名空间没有代理)提供一个无契约代理;`ctx.remote.<ns>.<method>(...args)` 变成对端点 `<ns>/<method>` 的调用,携带位置参数,mock 登记了 `stream()` 脚本的走流、否则走一元,并沿用生成客户端的结果折叠(载体抛错折成 `gateway/internal`,中止折成 `gateway/cancelled`)。没有规则的端点照样发出,所以 mock 会记下它、`dispose()` 让测试失败。
91
93
 
92
94
  ### 何时使用
93
95
 
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Context, Inject } from "@qilin-agent/kylin";
1
+ import { Context, Inject, Service } from "@qilin-agent/kylin";
2
2
  import { Fragment, createElement, useSyncExternalStore } from "react";
3
3
  import { act, render, within } from "@testing-library/react";
4
4
  import { SlotRegistry } from "@qilin-agent/client-ui-renderer/client";
@@ -12,6 +12,7 @@ import { MutableSessionEventSource, SESSION_SEARCH_RESULT_LIMIT, createScope, sc
12
12
  import { scopeIdentityOf } from "@qilin-agent/api-session-controller/src/client/scope.ts";
13
13
  import { EMPTY_CONVERSATION_SNAPSHOT } from "@qilin-agent/client-ui-conversation/client";
14
14
  import { EMPTY_CHAT_SNAPSHOT } from "@qilin-agent/client-ui-chat/client";
15
+ import { createContextMenuBindings } from "@qilin-agent/client-ui-context-menu/src/client/trigger.ts";
15
16
  //#region lib/types/snapshot.js
16
17
  /**
17
18
  * DOM snapshot hygiene: a vitest snapshot serializer that keeps `.snap`
@@ -1272,6 +1273,19 @@ function scriptedSettingsRemote(namespaces = [], options = {}) {
1272
1273
  };
1273
1274
  }
1274
1275
  //#endregion
1276
+ //#region lib/types/context-menu.js
1277
+ /**
1278
+ * Supply the global hook to a component mounted outside the Slot renderer.
1279
+ * @param open - Observe captured targets; an unstubbed activation throws.
1280
+ * @returns Stable hook using the production pointer and keyboard handlers.
1281
+ */
1282
+ function contextMenuHook(open = () => {
1283
+ throw new Error("Unexpected context menu");
1284
+ }) {
1285
+ const bindings = createContextMenuBindings(open, () => true);
1286
+ return () => bindings;
1287
+ }
1288
+ //#endregion
1275
1289
  //#region lib/types/translate.js
1276
1290
  /**
1277
1291
  * Test double of the locale lookup chain: a translate stub over plain
@@ -1305,13 +1319,57 @@ function makeTranslate(...dicts) {
1305
1319
  //#region lib/types/access.js
1306
1320
  /**
1307
1321
  * Allow-all access for client specs. Production pages receive the
1308
- * `remoteAccess` Client service and the global-resource `useRemoteAccess` Hook
1309
- * from the remote-access Client plugin. Hand-built component props spread
1322
+ * `remoteAccess` Client service, the global-resource `useRemoteAccess` Hook
1323
+ * from the remote-access Client plugin, the Session list `useSessionAccess`
1324
+ * Hook from the session Client plugin, and the bound Session's `useAccess`
1325
+ * Hook as a standard prop. Hand-built component props spread
1310
1326
  * {@link allowAllAccess}; a spec of a refused path overrides the Hook.
1311
1327
  * @module @qilin-agent/client-test-runtime/src/access
1312
1328
  */
1313
1329
  /** Access Hooks that allow every action on every resource, for hand-built component props. */
1314
- const allowAllAccess = { useRemoteAccess: () => true };
1330
+ const allowAllAccess = {
1331
+ useRemoteAccess: () => true,
1332
+ useSessionAccess: () => true,
1333
+ useAccess: () => true
1334
+ };
1335
+ const ALLOWED = {
1336
+ getSnapshot: () => true,
1337
+ subscribe: () => () => {}
1338
+ };
1339
+ const REFUSED = {
1340
+ getSnapshot: () => false,
1341
+ subscribe: () => () => {}
1342
+ };
1343
+ /**
1344
+ * A `remoteAccess` Client service whose answers never change: `allows`
1345
+ * decides each action on every resource once. `whenAccess` installs an
1346
+ * allowed action's effects in the caller's fiber at once and never installs a
1347
+ * refused action's effects.
1348
+ */
1349
+ var StaticRemoteAccess = class extends Service {
1350
+ allows;
1351
+ /**
1352
+ * @param ctx - Context the service is provided on.
1353
+ * @param allows - the fixed answer for each action; allows everything when omitted.
1354
+ */
1355
+ constructor(ctx, allows = () => true) {
1356
+ super(ctx, "remoteAccess");
1357
+ this.allows = allows;
1358
+ }
1359
+ source(_kind, _id, action) {
1360
+ return this.allows(action) ? ALLOWED : REFUSED;
1361
+ }
1362
+ whenAccess(action, callback) {
1363
+ if (!this.allows(action)) return () => {};
1364
+ const dispose = this.ctx.effect(callback, `remoteAccess.whenAccess(${JSON.stringify(action)})`);
1365
+ return () => {
1366
+ dispose();
1367
+ };
1368
+ }
1369
+ whenResourceAccess(_kind, _id, action, callback) {
1370
+ return this.whenAccess(action, callback);
1371
+ }
1372
+ };
1315
1373
  //#endregion
1316
1374
  //#region lib/types/locale-env.js
1317
1375
  /**
@@ -1730,4 +1788,4 @@ var SlotTestRuntime = class SlotTestRuntime {
1730
1788
  }
1731
1789
  };
1732
1790
  //#endregion
1733
- export { FixtureSession, RemoteError, SlotTestRuntime, TestRemote, TestRoot, TestSessions, TestWorkspaces, allowAllAccess, bindSnapshotSelector, chatSnapshot, conversationSnapshot, createSlotRenderer, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, scriptedSettingsRemote, sessionSnapshot, stubConfigForm, usePinnedBrowserLanguages, workspaceSnapshot };
1791
+ export { FixtureSession, RemoteError, SlotTestRuntime, StaticRemoteAccess, TestRemote, TestRoot, TestSessions, TestWorkspaces, allowAllAccess, bindSnapshotSelector, chatSnapshot, contextMenuHook, conversationSnapshot, createSlotRenderer, domSnapshotSerializer, makeTranslate, registerDomSnapshotSerializer, scriptedSettingsRemote, sessionSnapshot, stubConfigForm, usePinnedBrowserLanguages, workspaceSnapshot };
@@ -1,13 +1,40 @@
1
1
  /**
2
2
  * Allow-all access for client specs. Production pages receive the
3
- * `remoteAccess` Client service and the global-resource `useRemoteAccess` Hook
4
- * from the remote-access Client plugin. Hand-built component props spread
3
+ * `remoteAccess` Client service, the global-resource `useRemoteAccess` Hook
4
+ * from the remote-access Client plugin, the Session list `useSessionAccess`
5
+ * Hook from the session Client plugin, and the bound Session's `useAccess`
6
+ * Hook as a standard prop. Hand-built component props spread
5
7
  * {@link allowAllAccess}; a spec of a refused path overrides the Hook.
6
8
  * @module @qilin-agent/client-test-runtime/src/access
7
9
  */
8
- import type { GlobalStandardProps } from '@qilin-agent/client-ui-slots';
9
- /** The access Hooks every Slot component receives. */
10
- export type AccessStandardProps = Pick<GlobalStandardProps, 'useRemoteAccess'>;
10
+ import { Service, type Context } from '@qilin-agent/kylin';
11
+ import type { AccessEffect, ClientRemoteAccess, RemoteEndpoint } from '@qilin-agent/api-remote-access/client/types';
12
+ import type { GlobalStandardProps, HostObservable, SessionStandardProps } from '@qilin-agent/client-ui-slots';
13
+ import type { TypertResourceKind } from '@qilin-agent/typert-protocol';
14
+ /**
15
+ * The access Hooks a root- or session-scoped Slot component receives: the two
16
+ * GlobalStandardProps Hooks plus the SessionStandardProps `useAccess`, whose
17
+ * `boolean` result also satisfies the `session-maybe` seat's
18
+ * `boolean | undefined` result.
19
+ */
20
+ export type AccessStandardProps = Pick<GlobalStandardProps, 'useRemoteAccess' | 'useSessionAccess'> & Pick<SessionStandardProps, 'useAccess'>;
11
21
  /** Access Hooks that allow every action on every resource, for hand-built component props. */
12
22
  export declare const allowAllAccess: AccessStandardProps;
23
+ /**
24
+ * A `remoteAccess` Client service whose answers never change: `allows`
25
+ * decides each action on every resource once. `whenAccess` installs an
26
+ * allowed action's effects in the caller's fiber at once and never installs a
27
+ * refused action's effects.
28
+ */
29
+ export declare class StaticRemoteAccess extends Service implements ClientRemoteAccess {
30
+ private readonly allows;
31
+ /**
32
+ * @param ctx - Context the service is provided on.
33
+ * @param allows - the fixed answer for each action; allows everything when omitted.
34
+ */
35
+ constructor(ctx: Context, allows?: (action: string) => boolean);
36
+ source(_kind: TypertResourceKind, _id: string, action: string): HostObservable<boolean>;
37
+ whenAccess(action: RemoteEndpoint, callback: () => AccessEffect): () => void;
38
+ whenResourceAccess(_kind: TypertResourceKind, _id: string, action: RemoteEndpoint, callback: () => AccessEffect): () => void;
39
+ }
13
40
  //# sourceMappingURL=access.d.ts.map
@@ -0,0 +1,11 @@
1
+ /** Gesture bindings for direct component fixtures, using the production adapter. */
2
+ import type { ContextMenuTriggerProps, MenuPoint, ContextMenuTarget } from '@qilin-agent/client-ui-context-menu/client';
3
+ /**
4
+ * Supply the global hook to a component mounted outside the Slot renderer.
5
+ * @param open - Observe captured targets; an unstubbed activation throws.
6
+ * @returns Stable hook using the production pointer and keyboard handlers.
7
+ */
8
+ export declare function contextMenuHook<Target extends object = ContextMenuTarget>(open?: (target: Target, point: MenuPoint) => void): () => {
9
+ getTriggerProps: (target: Target | (() => Target) | undefined, handlers?: ContextMenuTriggerProps) => ContextMenuTriggerProps;
10
+ };
11
+ //# sourceMappingURL=context-menu.d.ts.map
@@ -35,8 +35,9 @@ export { TestWorkspaces } from './workspaces.ts';
35
35
  export { RemoteError, TestRemote } from './remote.ts';
36
36
  export { chatSnapshot, conversationSnapshot, sessionSnapshot, workspaceSnapshot, } from './fixtures.ts';
37
37
  export type { FixtureSnapshot, SessionBehaviorOverrides, SessionFixture, SessionFixtureSnapshot, Stabilizer, } from './fixtures.ts';
38
+ export { contextMenuHook } from './context-menu.ts';
38
39
  export { makeTranslate } from './translate.ts';
39
- export { allowAllAccess } from './access.ts';
40
+ export { allowAllAccess, StaticRemoteAccess } from './access.ts';
40
41
  export type { AccessStandardProps } from './access.ts';
41
42
  export { usePinnedBrowserLanguages } from './locale-env.ts';
42
43
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-test-runtime",
3
3
  "description": "Browser test runtimes: a jsdom slot bench with test-owned Session and Workspace doubles, and a whole-client tier that boots the web roster through the production bootClient over an endpoint-named Remote mock",
4
- "version": "3.1.7",
4
+ "version": "3.1.9",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -26,123 +26,124 @@
26
26
  },
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
+ "@qilin-agent/dsh-compat": "3.1.9",
29
30
  "@testing-library/dom": "^10.4.1",
30
31
  "@testing-library/react": "^16.3.2",
31
32
  "js-yaml": "^4.3.2",
32
- "vitest": "^4.1.8",
33
- "@qilin-agent/dsh-compat": "3.1.7"
33
+ "vitest": "^4.1.8"
34
34
  },
35
35
  "peerDependencies": {
36
+ "@qilin-agent/kylin": "~4.0.7",
37
+ "@qilin-agent/kylin-plugin-include": "~1.0.12",
38
+ "@qilin-agent/kylin-plugin-loader": "~1.0.8",
39
+ "@qilin-agent/api-gateway": "3.1.9",
40
+ "@qilin-agent/api-session-controller": "3.1.9",
41
+ "@qilin-agent/api-workspace-controller": "3.1.9",
42
+ "@qilin-agent/attachment": "3.1.9",
43
+ "@qilin-agent/client-connection": "3.1.9",
44
+ "@qilin-agent/client-hmr": "3.1.9",
45
+ "@qilin-agent/client-modules": "3.1.9",
46
+ "@qilin-agent/client-store": "3.1.9",
47
+ "@qilin-agent/client-ui-chat": "3.1.9",
48
+ "@qilin-agent/client-ui-context-menu": "3.1.9",
49
+ "@qilin-agent/client-ui-conversation": "3.1.9",
50
+ "@qilin-agent/client-ui-renderer": "3.1.9",
51
+ "@qilin-agent/client-ui-session": "3.1.9",
52
+ "@qilin-agent/client-ui-settings": "3.1.9",
53
+ "@qilin-agent/client-ui-slots": "3.1.9",
54
+ "@qilin-agent/client-web": "3.1.9",
55
+ "@qilin-agent/remote-mock": "3.1.9",
56
+ "@qilin-agent/session": "3.1.9",
57
+ "@qilin-agent/subagent": "3.1.9",
58
+ "@qilin-agent/typert-protocol": "3.1.9",
36
59
  "react": "^18.2.0",
37
- "react-dom": "^18.2.0",
38
- "@qilin-agent/kylin": "~4.0.5",
39
- "@qilin-agent/kylin-plugin-loader": "~1.0.6",
40
- "@qilin-agent/kylin-plugin-include": "~1.0.10",
41
- "@qilin-agent/api-gateway": "3.1.7",
42
- "@qilin-agent/api-session-controller": "3.1.7",
43
- "@qilin-agent/api-workspace-controller": "3.1.7",
44
- "@qilin-agent/attachment": "3.1.7",
45
- "@qilin-agent/client-connection": "3.1.7",
46
- "@qilin-agent/client-hmr": "3.1.7",
47
- "@qilin-agent/client-store": "3.1.7",
48
- "@qilin-agent/client-ui-chat": "3.1.7",
49
- "@qilin-agent/client-ui-conversation": "3.1.7",
50
- "@qilin-agent/client-modules": "3.1.7",
51
- "@qilin-agent/client-ui-renderer": "3.1.7",
52
- "@qilin-agent/client-ui-session": "3.1.7",
53
- "@qilin-agent/client-ui-slots": "3.1.7",
54
- "@qilin-agent/client-web": "3.1.7",
55
- "@qilin-agent/remote-mock": "3.1.7",
56
- "@qilin-agent/client-ui-settings": "3.1.7",
57
- "@qilin-agent/session": "3.1.7",
58
- "@qilin-agent/typert-protocol": "3.1.7",
59
- "@qilin-agent/subagent": "3.1.7"
60
+ "react-dom": "^18.2.0"
60
61
  },
61
62
  "devDependencies": {
63
+ "@qilin-agent/api-gateway": "3.1.9",
64
+ "@qilin-agent/api-remote-access": "3.1.9",
65
+ "@qilin-agent/api-remotes": "3.1.9",
66
+ "@qilin-agent/api-session-controller": "3.1.9",
67
+ "@qilin-agent/api-terminal-controller": "3.1.9",
68
+ "@qilin-agent/api-workspace-controller": "3.1.9",
69
+ "@qilin-agent/api-workspace-files": "3.1.9",
70
+ "@qilin-agent/attachment": "3.1.9",
71
+ "@qilin-agent/base": "3.1.9",
72
+ "@qilin-agent/client-connection": "3.1.9",
73
+ "@qilin-agent/client-file-upload": "3.1.9",
74
+ "@qilin-agent/client-hmr": "3.1.9",
75
+ "@qilin-agent/client-locale": "3.1.9",
76
+ "@qilin-agent/client-modules": "3.1.9",
77
+ "@qilin-agent/client-resources": "3.1.9",
78
+ "@qilin-agent/client-store": "3.1.9",
79
+ "@qilin-agent/client-ui-account": "3.1.9",
80
+ "@qilin-agent/client-ui-agent-preset": "3.1.9",
81
+ "@qilin-agent/client-ui-approval": "3.1.9",
82
+ "@qilin-agent/client-ui-attachment": "3.1.9",
83
+ "@qilin-agent/client-ui-brand": "3.1.9",
84
+ "@qilin-agent/client-ui-chat": "3.1.9",
85
+ "@qilin-agent/client-ui-commands": "3.1.9",
86
+ "@qilin-agent/client-ui-context-menu": "3.1.9",
87
+ "@qilin-agent/client-ui-conversation": "3.1.9",
88
+ "@qilin-agent/client-ui-deliverables": "3.1.9",
89
+ "@qilin-agent/client-ui-goal": "3.1.9",
90
+ "@qilin-agent/client-ui-input-trigger": "3.1.9",
91
+ "@qilin-agent/client-ui-jobs": "3.1.9",
92
+ "@qilin-agent/client-ui-kylin": "3.1.9",
93
+ "@qilin-agent/client-ui-layout": "3.1.9",
94
+ "@qilin-agent/client-ui-message-feedback": "3.1.9",
95
+ "@qilin-agent/client-ui-model-selection": "3.1.9",
96
+ "@qilin-agent/client-ui-open-in-app": "3.1.9",
97
+ "@qilin-agent/client-ui-permission-presets": "3.1.9",
98
+ "@qilin-agent/client-ui-plan": "3.1.9",
99
+ "@qilin-agent/client-ui-plugin-manager": "3.1.9",
100
+ "@qilin-agent/client-ui-reference": "3.1.9",
101
+ "@qilin-agent/client-ui-renderer": "3.1.9",
102
+ "@qilin-agent/client-ui-schedule": "3.1.9",
103
+ "@qilin-agent/client-ui-session": "3.1.9",
104
+ "@qilin-agent/client-ui-settings": "3.1.9",
105
+ "@qilin-agent/client-ui-settings-general": "3.1.9",
106
+ "@qilin-agent/client-ui-settings-mcp": "3.1.9",
107
+ "@qilin-agent/client-ui-settings-models": "3.1.9",
108
+ "@qilin-agent/client-ui-settings-plugins": "3.1.9",
109
+ "@qilin-agent/client-ui-settings-skills": "3.1.9",
110
+ "@qilin-agent/client-ui-settings-unarchive-sessions": "3.1.9",
111
+ "@qilin-agent/client-ui-sidebar": "3.1.9",
112
+ "@qilin-agent/client-ui-sidebar-browser": "3.1.9",
113
+ "@qilin-agent/client-ui-sidebar-documentpreview": "3.1.9",
114
+ "@qilin-agent/client-ui-sidebar-files": "3.1.9",
115
+ "@qilin-agent/client-ui-sidebar-plans": "3.1.9",
116
+ "@qilin-agent/client-ui-sidebar-right": "3.1.9",
117
+ "@qilin-agent/client-ui-sidebar-tasks": "3.1.9",
118
+ "@qilin-agent/client-ui-sidebar-terminal": "3.1.9",
119
+ "@qilin-agent/client-ui-skill": "3.1.9",
120
+ "@qilin-agent/client-ui-slots": "3.1.9",
121
+ "@qilin-agent/client-ui-subagent": "3.1.9",
122
+ "@qilin-agent/client-ui-theme": "3.1.9",
123
+ "@qilin-agent/client-ui-theme-brand": "3.1.9",
124
+ "@qilin-agent/client-ui-tool": "3.1.9",
125
+ "@qilin-agent/client-ui-trajectory": "3.1.9",
126
+ "@qilin-agent/client-ui-user-questions": "3.1.9",
127
+ "@qilin-agent/client-ui-workflow-run": "3.1.9",
128
+ "@qilin-agent/client-ui-workspace": "3.1.9",
129
+ "@qilin-agent/client-web": "3.1.9",
130
+ "@qilin-agent/kylin": "~4.0.7",
131
+ "@qilin-agent/kylin-client-runner": "3.1.9",
132
+ "@qilin-agent/kylin-plugin-include": "~1.0.12",
133
+ "@qilin-agent/kylin-plugin-loader": "~1.0.8",
134
+ "@qilin-agent/remote-mock": "3.1.9",
135
+ "@qilin-agent/session": "3.1.9",
136
+ "@qilin-agent/session-log-export": "3.1.9",
137
+ "@qilin-agent/settings": "3.1.9",
138
+ "@qilin-agent/subagent": "3.1.9",
139
+ "@qilin-agent/typert-protocol": "3.1.9",
140
+ "@qilin-agent/typert-registry": "3.1.9",
141
+ "@qilin-agent/web-app": "3.1.9",
62
142
  "@types/js-yaml": "^4.0.9",
63
143
  "@types/react": "~18.3.1",
64
144
  "@types/react-dom": "~18.3.0",
65
145
  "react": "^18.2.0",
66
- "react-dom": "^18.2.0",
67
- "@qilin-agent/api-remote-access": "3.1.7",
68
- "@qilin-agent/api-terminal-controller": "3.1.7",
69
- "@qilin-agent/api-gateway": "3.1.7",
70
- "@qilin-agent/api-session-controller": "3.1.7",
71
- "@qilin-agent/api-remotes": "3.1.7",
72
- "@qilin-agent/api-workspace-controller": "3.1.7",
73
- "@qilin-agent/attachment": "3.1.7",
74
- "@qilin-agent/client-connection": "3.1.7",
75
- "@qilin-agent/api-workspace-files": "3.1.7",
76
- "@qilin-agent/client-file-upload": "3.1.7",
77
- "@qilin-agent/client-hmr": "3.1.7",
78
- "@qilin-agent/client-locale": "3.1.7",
79
- "@qilin-agent/client-modules": "3.1.7",
80
- "@qilin-agent/client-resources": "3.1.7",
81
- "@qilin-agent/base": "3.1.7",
82
- "@qilin-agent/client-store": "3.1.7",
83
- "@qilin-agent/client-ui-agent-preset": "3.1.7",
84
- "@qilin-agent/client-ui-account": "3.1.7",
85
- "@qilin-agent/client-ui-attachment": "3.1.7",
86
- "@qilin-agent/client-ui-brand": "3.1.7",
87
- "@qilin-agent/client-ui-approval": "3.1.7",
88
- "@qilin-agent/client-ui-chat": "3.1.7",
89
- "@qilin-agent/client-ui-conversation": "3.1.7",
90
- "@qilin-agent/client-ui-commands": "3.1.7",
91
- "@qilin-agent/client-ui-deliverables": "3.1.7",
92
- "@qilin-agent/client-ui-goal": "3.1.7",
93
- "@qilin-agent/client-ui-input-trigger": "3.1.7",
94
- "@qilin-agent/client-ui-kylin": "3.1.7",
95
- "@qilin-agent/client-ui-model-selection": "3.1.7",
96
- "@qilin-agent/client-ui-layout": "3.1.7",
97
- "@qilin-agent/client-ui-open-in-app": "3.1.7",
98
- "@qilin-agent/client-ui-permission-presets": "3.1.7",
99
- "@qilin-agent/client-ui-message-feedback": "3.1.7",
100
- "@qilin-agent/client-ui-plugin-manager": "3.1.7",
101
- "@qilin-agent/client-ui-plan": "3.1.7",
102
- "@qilin-agent/client-ui-reference": "3.1.7",
103
- "@qilin-agent/client-ui-renderer": "3.1.7",
104
- "@qilin-agent/client-ui-jobs": "3.1.7",
105
- "@qilin-agent/client-ui-session": "3.1.7",
106
- "@qilin-agent/client-ui-settings": "3.1.7",
107
- "@qilin-agent/client-ui-settings-general": "3.1.7",
108
- "@qilin-agent/client-ui-settings-models": "3.1.7",
109
- "@qilin-agent/client-ui-settings-mcp": "3.1.7",
110
- "@qilin-agent/client-ui-settings-unarchive-sessions": "3.1.7",
111
- "@qilin-agent/client-ui-settings-plugin-inventory": "3.1.7",
112
- "@qilin-agent/client-ui-sidebar": "3.1.7",
113
- "@qilin-agent/client-ui-sidebar-browser": "3.1.7",
114
- "@qilin-agent/client-ui-sidebar-documentpreview": "3.1.7",
115
- "@qilin-agent/client-ui-settings-skills": "3.1.7",
116
- "@qilin-agent/client-ui-schedule": "3.1.7",
117
- "@qilin-agent/client-ui-sidebar-plans": "3.1.7",
118
- "@qilin-agent/client-ui-sidebar-files": "3.1.7",
119
- "@qilin-agent/client-ui-sidebar-right": "3.1.7",
120
- "@qilin-agent/client-ui-sidebar-tasks": "3.1.7",
121
- "@qilin-agent/client-ui-sidebar-terminal": "3.1.7",
122
- "@qilin-agent/client-ui-skill": "3.1.7",
123
- "@qilin-agent/client-ui-slots": "3.1.7",
124
- "@qilin-agent/client-ui-theme-brand": "3.1.7",
125
- "@qilin-agent/client-ui-settings-plugins": "3.1.7",
126
- "@qilin-agent/client-ui-subagent": "3.1.7",
127
- "@qilin-agent/client-ui-theme": "3.1.7",
128
- "@qilin-agent/client-ui-tool": "3.1.7",
129
- "@qilin-agent/client-ui-trajectory": "3.1.7",
130
- "@qilin-agent/client-ui-user-questions": "3.1.7",
131
- "@qilin-agent/client-ui-workflow-run": "3.1.7",
132
- "@qilin-agent/client-ui-workspace": "3.1.7",
133
- "@qilin-agent/client-web": "3.1.7",
134
- "@qilin-agent/kylin": "~4.0.5",
135
- "@qilin-agent/kylin-client-runner": "3.1.7",
136
- "@qilin-agent/kylin-plugin-include": "~1.0.10",
137
- "@qilin-agent/kylin-plugin-loader": "~1.0.6",
138
- "@qilin-agent/session": "3.1.7",
139
- "@qilin-agent/session-log-export": "3.1.7",
140
- "@qilin-agent/remote-mock": "3.1.7",
141
- "@qilin-agent/subagent": "3.1.7",
142
- "@qilin-agent/typert-protocol": "3.1.7",
143
- "@qilin-agent/settings": "3.1.7",
144
- "@qilin-agent/web-app": "3.1.7",
145
- "@qilin-agent/typert-registry": "3.1.7"
146
+ "react-dom": "^18.2.0"
146
147
  },
147
148
  "files": [
148
149
  "lib/index.js",