@morlay/ui-conversation-message-actions 0.0.19-alpha.8 → 0.0.19-alpha.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.md CHANGED
@@ -7,10 +7,10 @@
7
7
 
8
8
  ## 用法
9
9
 
10
- 装配只需在 profile 的 `dsh.profile.bundles` 里列出本包——本包自带 bundle patch
11
- ([`cordis.patch.yml`](./cordis.patch.yml))插入插件行并注册 `ctx.sessionEditor`。依赖 `ctx.sessionBranch` /
12
- `ctx.sessionPersistence`(需先装配 provider 实现,如 `@morlay/session-rdb`)与 `ctx.sessions`;`agents` 可选,缺失时
13
- 重放退化为「已 durable 的就地版本」。
10
+ 装配入口是聚合层 [`@morlay/better-session`](../../bundles/better-session/README.md):由它的 bundle patch 插入本包的行并注册
11
+ `ctx.sessionEditor`(本包自己没有 bundle patch,不作为独立 bundle 安装)。依赖 `ctx.sessionBranch` /
12
+ `ctx.sessionPersistence`(provider 由同一聚合层装配,如 `@morlay/session-rdb`)与 `ctx.sessions`;`agents` 可选,
13
+ 缺失时重放退化为「已 durable 的就地版本」。
14
14
 
15
15
  ```ts
16
16
  // host:装配后直接调服务
@@ -34,4 +34,4 @@ edit / retry / reroll 就地重写**同一会话**(session id 不变),只
34
34
  - 决策:[`.agents/adrs/`](./.agents/adrs)(接管官方 `ui-conversation` 行、client bundle 单文件与 shadow 渲染、引用解析、
35
35
  编辑入口门控…)
36
36
  - 接缝、测试落点与未覆盖:[本包规范 how-to-verify](./.agents/standards/how-to-verify.md)
37
- - 整体设计:[设计 20260917-系统设计](../../../.agents/designs/20260917-系统设计.md)
37
+ - 整体设计:[设计 20260917-会话编辑闭环装配](../../bundles/better-session/.agents/designs/20260917-会话编辑闭环装配.md)
package/dist/client.cjs CHANGED
@@ -470,7 +470,7 @@ window.__ModuleLoader__.load({
470
470
  },
471
471
  "&:hover": { color: "var(--dsw-alias-label-secondary)" },
472
472
  "&:focus-visible": {
473
- outline: "1.5px solid var(--dsw-alias-button-info-fill)",
473
+ outline: "1.5px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))",
474
474
  outlineOffset: "2px"
475
475
  }
476
476
  },
@@ -2855,16 +2855,15 @@ declare class WorkspaceRegistry extends Service {
2855
2855
  * Initialize the default Workspace only while both the registry and Session
2856
2856
  * history are empty. Repeated requests reuse its durable identity; deleting
2857
2857
  * that registration permanently disables automatic creation.
2858
- * @param resolveDirectory - resolve the absolute directory and initial title;
2859
- * called only for eligible creation, inside the registry mutation queue.
2860
- * Missing directories are created recursively before registration.
2858
+ * @param resolveDirectory - resolve the absolute directory; called only for
2859
+ * eligible creation, inside the registry mutation queue. Missing directories
2860
+ * are created recursively before registration, and the initial title is the
2861
+ * requested directory's own final segment — not the canonical one, so a
2862
+ * symlink at that path does not retitle the Workspace after its target.
2861
2863
  * After resolution, caller cancellation does not roll back creation or registration.
2862
2864
  * @returns the initialized Workspace, or undefined when automatic creation is ineligible.
2863
2865
  */
2864
- initializeDefault(resolveDirectory: () => Promise<{
2865
- path: string;
2866
- title: string;
2867
- }>): Promise<Workspace | undefined>;
2866
+ initializeDefault(resolveDirectory: () => Promise<string>): Promise<Workspace | undefined>;
2868
2867
  /**
2869
2868
  * Look up a workspace by id.
2870
2869
  * @param id - Workspace id.
@@ -2855,16 +2855,15 @@ declare class WorkspaceRegistry extends Service {
2855
2855
  * Initialize the default Workspace only while both the registry and Session
2856
2856
  * history are empty. Repeated requests reuse its durable identity; deleting
2857
2857
  * that registration permanently disables automatic creation.
2858
- * @param resolveDirectory - resolve the absolute directory and initial title;
2859
- * called only for eligible creation, inside the registry mutation queue.
2860
- * Missing directories are created recursively before registration.
2858
+ * @param resolveDirectory - resolve the absolute directory; called only for
2859
+ * eligible creation, inside the registry mutation queue. Missing directories
2860
+ * are created recursively before registration, and the initial title is the
2861
+ * requested directory's own final segment — not the canonical one, so a
2862
+ * symlink at that path does not retitle the Workspace after its target.
2861
2863
  * After resolution, caller cancellation does not roll back creation or registration.
2862
2864
  * @returns the initialized Workspace, or undefined when automatic creation is ineligible.
2863
2865
  */
2864
- initializeDefault(resolveDirectory: () => Promise<{
2865
- path: string;
2866
- title: string;
2867
- }>): Promise<Workspace | undefined>;
2866
+ initializeDefault(resolveDirectory: () => Promise<string>): Promise<Workspace | undefined>;
2868
2867
  /**
2869
2868
  * Look up a workspace by id.
2870
2869
  * @param id - Workspace id.
package/dist/testing.mjs CHANGED
@@ -35340,6 +35340,7 @@ var SessionObservationReader = class {
35340
35340
  * @param sessionId - logical Session identity.
35341
35341
  * @param options - cancellation and all-or-none projection computation for this read.
35342
35342
  * @returns one exact immutable observation.
35343
+ * @throws {@link SessionQueryError} with code `SESSION_QUERY_CORRUPT_SESSION` when live or prepared projection computation fails.
35343
35344
  */
35344
35345
  async read(sessionId, options = {}) {
35345
35346
  const { signal, projectionMode = "all" } = options;
@@ -35471,7 +35472,12 @@ var SessionObservationReader = class {
35471
35472
  live(session, projectionMode) {
35472
35473
  const seq = session.seq;
35473
35474
  let materialized;
35474
- const projections = projectionMode === "none" ? void 0 : this.ctx.get("sessionProjections")?.snapshot(session);
35475
+ let projections;
35476
+ try {
35477
+ projections = projectionMode === "none" ? void 0 : this.ctx.get("sessionProjections")?.snapshot(session);
35478
+ } catch (error) {
35479
+ throw new SessionQueryError(`failed to project session "${session.id}": ${errorMessage(error)}`, "SESSION_QUERY_CORRUPT_SESSION", { cause: error });
35480
+ }
35475
35481
  const lease = () => {
35476
35482
  let disposed = false;
35477
35483
  return {
@@ -36884,38 +36890,62 @@ var RdbSessionHandle = class RdbSessionHandle {
36884
36890
  }
36885
36891
  static LIVE_WRITE_BATCH_MAX_DELAY_MS = 200;
36886
36892
  };
36893
+ /**
36894
+ * 本地化说明:`description()` 的类型签名只声明 `string`,而 meta 本身接受 `Dict<string>`
36895
+ * (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
36896
+ */
36897
+ const localized = (text) => text;
36898
+ /** 投影 checkpoint 的写回节流:两个分支共用。 */
36899
+ const projectionCacheSchema = Schema.object({
36900
+ writeEveryEvents: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_EVERY_EVENTS).description(localized({
36901
+ zh: "每累计这么多事件写回一次投影 checkpoint。",
36902
+ en: "Write the projection checkpoint back after this many events."
36903
+ })),
36904
+ writeIntervalMs: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_INTERVAL_MS).description(localized({
36905
+ zh: "距离上次写回超过这个间隔(毫秒)时也写一次。",
36906
+ en: "Also write back when this many ms passed since the last one."
36907
+ }))
36908
+ }).default({
36909
+ writeEveryEvents: DEFAULT_PROJECTION_WRITE_EVERY_EVENTS,
36910
+ writeIntervalMs: DEFAULT_PROJECTION_WRITE_INTERVAL_MS
36911
+ });
36887
36912
  var SessionPersistenceRdb = class extends SessionPersistence {
36888
- config;
36889
36913
  static inject = ["sessions"];
36890
36914
  static Config = Schema.union([Schema.object({
36891
36915
  type: Schema.const("sqlite"),
36892
- path: Schema.string().required(),
36916
+ path: Schema.string().required().description(localized({
36917
+ zh: "SQLite 数据库文件路径;`:memory:` 是内存库(进程结束即丢)。",
36918
+ en: "SQLite database file path; `:memory:` keeps it in memory and loses it with the process."
36919
+ })),
36893
36920
  journalMode: Schema.union([
36894
36921
  "wal",
36895
36922
  "delete",
36896
36923
  "truncate",
36897
36924
  "persist"
36898
- ]).default("wal"),
36899
- busyTimeout: Schema.number().step(1).min(0).default(DEFAULT_BUSY_TIMEOUT_MS),
36900
- projectionCache: Schema.object({
36901
- writeEveryEvents: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_EVERY_EVENTS),
36902
- writeIntervalMs: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_INTERVAL_MS)
36903
- }).default({
36904
- writeEveryEvents: DEFAULT_PROJECTION_WRITE_EVERY_EVENTS,
36905
- writeIntervalMs: DEFAULT_PROJECTION_WRITE_INTERVAL_MS
36906
- })
36925
+ ]).default("wal").description(localized({
36926
+ zh: "SQLite 日志模式;默认 wal(并发读最好)。",
36927
+ en: "SQLite journal mode; `wal` by default (best concurrent reads)."
36928
+ })),
36929
+ busyTimeout: Schema.number().step(1).min(0).default(DEFAULT_BUSY_TIMEOUT_MS).description(localized({
36930
+ zh: "写锁冲突时的忙等超时(毫秒)。",
36931
+ en: "Busy timeout in ms while a write lock is contended."
36932
+ })),
36933
+ projectionCache: projectionCacheSchema
36907
36934
  }), Schema.object({
36908
36935
  type: Schema.const("postgres"),
36909
- connectionString: Schema.string().required(),
36910
- schema: Schema.string().default("public"),
36911
- projectionCache: Schema.object({
36912
- writeEveryEvents: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_EVERY_EVENTS),
36913
- writeIntervalMs: Schema.natural().min(1).default(DEFAULT_PROJECTION_WRITE_INTERVAL_MS)
36914
- }).default({
36915
- writeEveryEvents: DEFAULT_PROJECTION_WRITE_EVERY_EVENTS,
36916
- writeIntervalMs: DEFAULT_PROJECTION_WRITE_INTERVAL_MS
36917
- })
36918
- })]);
36936
+ connectionString: Schema.string().required().description(localized({
36937
+ zh: "PostgreSQL 连接串(含库名与凭证)。",
36938
+ en: "PostgreSQL connection string (database and credentials)."
36939
+ })),
36940
+ schema: Schema.string().default("public").description(localized({
36941
+ zh: "库内的 schema 名;默认 public。",
36942
+ en: "Schema name inside the database; `public` by default."
36943
+ })),
36944
+ projectionCache: projectionCacheSchema
36945
+ })]).description(localized({
36946
+ zh: "会话持久化后端:改这里的连接参数会在这一行重挂时生效(Loader 会重装被改的行)。",
36947
+ en: "Session persistence backend: edits apply when this row is remounted (the Loader re-installs changed rows)."
36948
+ })).volatile();
36919
36949
  name = "session-rdb";
36920
36950
  tracker = new RdbBackendTracker(this.name);
36921
36951
  backend;
@@ -36925,10 +36955,12 @@ var SessionPersistenceRdb = class extends SessionPersistence {
36925
36955
  reuseEventIds = /* @__PURE__ */ new Map();
36926
36956
  liveBuffers = /* @__PURE__ */ new Map();
36927
36957
  liveReady = /* @__PURE__ */ new Map();
36958
+ /** 本次装配用的配置快照(整段 Config 是 volatile,重挂会给新的)。 */
36959
+ config;
36928
36960
  constructor(ctx, config, injectedBackend) {
36929
36961
  super(ctx);
36930
- this.config = config;
36931
- this.backend = injectedBackend ?? createBackend(config);
36962
+ this.config = config.get();
36963
+ this.backend = injectedBackend ?? createBackend(this.config);
36932
36964
  this.ready = this.init();
36933
36965
  this.installLiveRouting(ctx);
36934
36966
  new SessionBranchRdb(this.ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morlay/ui-conversation-message-actions",
3
- "version": "0.0.19-alpha.8",
3
+ "version": "0.0.19-alpha.9",
4
4
  "description": "Rewind / retry / recall / fork orchestration (host) plus the browser half — replaces the conversation.chat.node user / steering rendering and overrides the conversation.composer.dock stats row.",
5
5
  "keywords": [
6
6
  "conversation-chat-node",
@@ -22,17 +22,15 @@
22
22
  "locale/*.json",
23
23
  "dist",
24
24
  "src",
25
- "cordis.patch.yml",
26
25
  "!**/__tests__"
27
26
  ],
28
27
  "type": "module",
29
28
  "exports": {
30
29
  ".": "./dist/index.mjs",
31
- "./invariant": "./dist/invariant.mjs",
32
30
  "./plan": "./dist/plan.mjs",
33
31
  "./testing": "./dist/testing.mjs",
32
+ "./invariant": "./dist/invariant.mjs",
34
33
  "./package.json": "./package.json",
35
- "./cordis.patch.yml": "./cordis.patch.yml",
36
34
  "./client": {
37
35
  "types": "./dist/client.d.cts",
38
36
  "default": "./dist/client.cjs"
@@ -40,42 +38,39 @@
40
38
  "./locale/*.json": "./locale/*.json"
41
39
  },
42
40
  "dependencies": {
43
- "@morlay/session-branch": "0.0.10-alpha.8"
41
+ "@morlay/session-branch": "0.0.10-alpha.9"
44
42
  },
45
43
  "devDependencies": {
46
- "@deepseek-ai/dsh-session-stats": "0.1.7-rc.1",
47
- "@morlay/dsh-client-ui-primitives": "0.0.2-alpha.8",
48
- "@morlay/session-rdb": "0.0.21-alpha.8",
44
+ "@deepseek-ai/dsh-session-stats": "0.1.7-rc.2",
45
+ "@morlay/dsh-client-ui-primitives": "0.0.2-alpha.9",
46
+ "@morlay/session-rdb": "0.0.21-alpha.9",
49
47
  "@types/react": "~18.3.1",
50
48
  "@types/react-dom": "~18.3.0",
51
49
  "react": "^18.2.0",
52
50
  "react-dom": "^18.2.0"
53
51
  },
54
52
  "peerDependencies": {
55
- "@deepseek-ai/cordis": "4.0.4",
56
- "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.1",
57
- "@deepseek-ai/dsh-attachment": "0.1.7-rc.1",
58
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.1",
59
- "@deepseek-ai/dsh-client-store": "0.1.7-rc.1",
60
- "@deepseek-ai/dsh-client-ui-attachment": "0.1.7-rc.1",
61
- "@deepseek-ai/dsh-client-ui-chat": "0.1.7-rc.1",
62
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
63
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.1",
64
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
65
- "@deepseek-ai/dsh-client-ui-workspace": "0.1.7-rc.1",
66
- "@deepseek-ai/dsh-invariants": "0.1.7-rc.1",
67
- "@deepseek-ai/dsh-llm": "0.1.7-rc.1",
68
- "@deepseek-ai/dsh-session": "0.1.7-rc.1",
69
- "@deepseek-ai/dsh-session-persistence": "0.1.7-rc.1",
70
- "@deepseek-ai/dsh-session-projection": "0.1.7-rc.1",
71
- "@deepseek-ai/dsh-token-meter": "0.1.7-rc.1",
72
- "@morlay/dsh-client-ui-conversation": "0.0.2-alpha.8",
73
- "@morlay/dsh-client-ui-primitives": "0.0.2-alpha.8"
53
+ "@deepseek-ai/cordis": "^4.0.4",
54
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.7-rc.2",
55
+ "@deepseek-ai/dsh-attachment": "^0.1.7-rc.2",
56
+ "@deepseek-ai/dsh-client-connection": "^0.1.7-rc.2",
57
+ "@deepseek-ai/dsh-client-store": "^0.1.7-rc.2",
58
+ "@deepseek-ai/dsh-client-ui-attachment": "^0.1.7-rc.2",
59
+ "@deepseek-ai/dsh-client-ui-chat": "^0.1.7-rc.2",
60
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-rc.2",
61
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.7-rc.2",
62
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.2",
63
+ "@deepseek-ai/dsh-client-ui-workspace": "^0.1.7-rc.2",
64
+ "@deepseek-ai/dsh-invariants": "^0.1.7-rc.2",
65
+ "@deepseek-ai/dsh-llm": "^0.1.7-rc.2",
66
+ "@deepseek-ai/dsh-session": "^0.1.7-rc.2",
67
+ "@deepseek-ai/dsh-session-persistence": "^0.1.7-rc.2",
68
+ "@deepseek-ai/dsh-session-projection": "^0.1.7-rc.2",
69
+ "@deepseek-ai/dsh-token-meter": "^0.1.7-rc.2",
70
+ "@morlay/dsh-client-ui-conversation": "0.0.2-alpha.9",
71
+ "@morlay/dsh-client-ui-primitives": "0.0.2-alpha.9"
74
72
  },
75
73
  "dsh": {
76
- "bundle": {
77
- "patch": "./cordis.patch.yml"
78
- },
79
74
  "client": {
80
75
  "platform": "web",
81
76
  "inject": [
@@ -164,7 +164,8 @@ export const styles = {
164
164
  color: "var(--dsw-alias-label-secondary)",
165
165
  },
166
166
  "&:focus-visible": {
167
- outline: "1.5px solid var(--dsw-alias-button-info-fill)",
167
+ // 上游 ui-chat 的 MessageItem 这轮把焦点环改成读官方焦点变量(`focus.css` 口径)。
168
+ outline: "1.5px solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary))",
168
169
  outlineOffset: "2px",
169
170
  },
170
171
  },
package/cordis.patch.yml DELETED
@@ -1,9 +0,0 @@
1
- # @morlay/ui-conversation-message-actions bundle patch.
2
- #
3
- # 在 profile 的 dsh.profile.bundles 中列出本包后,本 patch 插入编排层插件行,
4
- # 注册 ctx.sessionEditor。依赖 ctx.sessionBranch(由 provider 实现插件如
5
- # @morlay/session-rdb 提供),请确保其在 bundles 中排在前面。
6
-
7
- - insert:
8
- - id: ui-conversation-message-actions
9
- name: "@morlay/ui-conversation-message-actions"