@deepseek-ai/dsh-client-ui-goal 0.1.6-alpha.2 → 0.1.7-alpha.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/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
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
4
  # pnpm run verify-translation-pairing --write packages/client/ui-goal/README.md
5
- README.md: 4a2c0c18f41cd4965ee8170ec7a93843d7427769
6
- README.zh.md: 1d3d6dd7aef4a2b37c273a7a43e09bed05d33f9d
5
+ README.md: ac23ac87c5b1bfe3eb849679c30a2ed283f33455
6
+ README.zh.md: bc9971a5e8917bf636de34a742530b113e4e4453
package/README.md CHANGED
@@ -25,7 +25,7 @@ The Web GUI goal surface shows both the durable goal state and its current proce
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
- Mount this plugin alongside `ui-conversation` and the goal domain package; the strip then appears as the second card in the composer-context stack (after Todo, before Queue) whenever the session has a goal. An armed active goal offers pause; an active-but-disarmed or paused goal offers resume; edit rewrites the objective; clear removes the goal and suppresses the strip until the projection catches up.
28
+ Mount this plugin alongside `ui-conversation` and the goal domain package; the strip then appears as the second card in the composer-context stack (after Todo, before Queue) whenever the session has a goal. Todo and Goal use the same panel elevation above the composer. An armed active goal offers pause; an active-but-disarmed or paused goal offers resume; edit rewrites the objective; clear removes the goal and suppresses the strip until the projection catches up.
29
29
 
30
30
  ### The command-input bubble
31
31
 
@@ -45,6 +45,8 @@ A rejected mutation surfaces the Remote error inline on the strip; loading, abse
45
45
 
46
46
  The durable goal arrives through `useProjection('goal')` (seeded by the history tail page and updated by `session/projection` frames). The inject face carries a registrant-private activation hook source plus the four mutation verbs. That source starts only while the framework hook observes it, reads `ctx.remote.goals.get`, subscribes to `goal/activation-changed`, and refreshes on running-state or connection resets. Live-event epochs invalidate in-flight reads, so a stale HTTP result cannot overwrite a newer activation edge; running refreshes retain the last known activation until the read resolves. The strip owns no domain store or cross-plugin cache. Each mutation reads the CAS ref from the session's current projected value at call time, and the RPC's compare-and-set is the staleness guard. The strip single-flights mutations synchronously because a pending render cannot fence same-frame clicks. The command-input projection is a separate Conversation Definition that builds a `command-input` Chat Node before the generic command result Node; it never creates `user/message` or a model turn.
47
47
 
48
+ Activation reads hold a temporary `goalActivation` Client reference and send `goals.get` only after that Session's initial history open succeeds. A stale binding or failed open sends no RPC. Rejected reads are logged without changing the projected goal or last known activation; the temporary reference is released when the read settles.
49
+
48
50
  </details>
49
51
 
50
52
  -----
package/README.zh.md CHANGED
@@ -25,7 +25,7 @@ Web GUI 的 goal 界面同时显示持久 goal 状态及当前的进程本地激
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
- 与 `ui-conversation` 及 goal 领域包一起挂载本插件;只要会话存在目标,条带就会作为 composer 上下文堆栈的第二张卡片出现(位于 Todo 之后、Queue 之前)。已 armed 的 active goal 提供暂停动作;active-but-disarmed 或 paused 的 goal 提供恢复;编辑重写目标文本;清除移除目标,并在投影追上之前抑制条带。
28
+ 与 `ui-conversation` 及 goal 领域包一起挂载本插件;只要会话存在目标,条带就会作为 composer 上下文堆栈的第二张卡片出现(位于 Todo 之后、Queue 之前)。Todo 与 Goal 使用相同的面板 elevation,使其位于 composer 层级之上。已 armed 的 active goal 提供暂停动作;active-but-disarmed 或 paused 的 goal 提供恢复;编辑重写目标文本;清除移除目标,并在投影追上之前抑制条带。
29
29
 
30
30
  ### 指令输入气泡
31
31
 
@@ -45,6 +45,8 @@ Web GUI 的 goal 界面同时显示持久 goal 状态及当前的进程本地激
45
45
 
46
46
  持久 goal 经 `useProjection('goal')` 到达(由历史尾页播种、`session/projection` 帧更新)。注入面携带注册方私有的激活钩子源与四个变更动词。该源仅在框架钩子观察它时启动;启动后会读取 `ctx.remote.goals.get`、订阅 `goal/activation-changed`,并在 running 状态或连接重置时刷新。实时事件 epoch 会让在途读取失效,因此较旧的 HTTP 响应不能覆盖较新的 activation 变化;running 刷新会保留最后一次已知 activation,直到读取完成。条带不持有领域存储或跨插件缓存。每个变更在调用时从会话当前投影值读取 CAS ref,比较并交换(RPC 的 CAS)就是陈旧性护栏。由于 React 的 pending 渲染无法拦住同一帧内的点击,条带会同步为变更建立 single-flight 防护。指令输入投影是独立的 Conversation Definition,在通用命令结果 Node 之前构建 `command-input` Chat Node;它绝不创建 `user/message` 或模型轮次。
47
47
 
48
+ 激活状态读取持有临时的 `goalActivation` 客户端引用,仅在该会话首次历史打开成功后发送 `goals.get`。binding 已失效或打开失败时不发送 RPC。读取被拒绝时记录错误,不改变投影中的目标或最后一次已知激活状态;读取结束时释放临时引用。
49
+
48
50
  </details>
49
51
 
50
52
  -----
package/lib/client.js CHANGED
@@ -57,6 +57,8 @@ window.__ModuleLoader__.load({
57
57
  revision: goal.revision,
58
58
  activation: goal.activation
59
59
  });
60
+ }, (error) => {
61
+ console.warn("[ui-goal] goal activation read failed:", error);
60
62
  });
61
63
  };
62
64
  const refreshProjection = () => {
@@ -124,7 +126,7 @@ window.__ModuleLoader__.load({
124
126
  }
125
127
  //#endregion
126
128
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-goal/src/client/GoalBar.module.css.mjs
127
- const css$1 = ".nLMEza_dock{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));margin:0 auto}.nLMEza_bar{box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) - 4 * var(--dsh-composer-dock-inset));border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-tip);border-radius:12px;align-items:center;gap:10px;height:36px;margin:0 auto;padding:4px 5px 4px 12px;display:flex}.nLMEza_goalGlyph{color:var(--dsw-alias-label-tertiary);flex:none;display:inline-flex}.nLMEza_label{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.nLMEza_objective{min-width:0;color:var(--dsw-alias-label-primary-dimmed);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:20px;overflow:hidden}.nLMEza_error{min-width:0;color:var(--dsw-alias-state-error-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;line-height:20px;overflow:hidden}.nLMEza_objectiveInput{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:13px;line-height:20px}.nLMEza_objectiveInput:focus{border-color:var(--dsw-alias-state-business-primary)}.nLMEza_objectiveInput::placeholder{color:var(--dsw-alias-label-caption)}.nLMEza_actions{flex:none;align-items:center;gap:10px;display:flex}.nLMEza_iconBtn{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;justify-content:center;align-items:center;padding:0;display:inline-flex}.nLMEza_iconBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.nLMEza_iconBtn:disabled{opacity:.4;cursor:default}";
129
+ const css$1 = ".nLMEza_dock{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));margin:0 auto}.nLMEza_bar{isolation:isolate;box-sizing:border-box;width:100%;max-width:calc(var(--dsh-composer-card-max-width) - 4 * var(--dsh-composer-dock-inset));--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);height:36px;box-shadow:var(--dsw-elevation-panel);border:0;border-radius:12px;align-items:center;gap:10px;margin:0 auto;padding:4px 5px 4px 12px;display:flex;position:relative}.nLMEza_bar:before{z-index:-1;border-radius:inherit;background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);content:\"\";pointer-events:none;position:absolute;inset:0}.nLMEza_goalGlyph{color:var(--dsw-alias-label-tertiary);flex:none;display:inline-flex}.nLMEza_label{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.nLMEza_objective{min-width:0;color:var(--dsw-alias-label-primary-dimmed);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:20px;overflow:hidden}.nLMEza_error{min-width:0;color:var(--dsw-alias-state-error-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;line-height:20px;overflow:hidden}.nLMEza_objectiveInput{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-base);min-width:0;height:26px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:13px;line-height:20px}.nLMEza_objectiveInput:focus{border-color:var(--dsw-alias-state-business-primary)}.nLMEza_objectiveInput::placeholder{color:var(--dsw-alias-label-caption)}.nLMEza_actions{flex:none;align-items:center;gap:10px;display:flex}.nLMEza_iconBtn{corner-shape:round;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;justify-content:center;align-items:center;padding:0;display:inline-flex}.nLMEza_iconBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.nLMEza_iconBtn:disabled{opacity:.4;cursor:default}";
128
130
  const tagId$1 = "@deepseek-ai/dsh-client-ui-goal/GoalBar.module.css";
129
131
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
130
132
  const tag = document.createElement("style");
@@ -242,7 +244,7 @@ window.__ModuleLoader__.load({
242
244
  },
243
245
  disabled: pending || draft.trim() === "",
244
246
  "aria-label": t("action.save"),
245
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 14 })
247
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 })
246
248
  })
247
249
  }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
248
250
  label: t("action.cancel"),
@@ -256,7 +258,7 @@ window.__ModuleLoader__.load({
256
258
  },
257
259
  disabled: pending,
258
260
  "aria-label": t("action.cancel"),
259
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
261
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 })
260
262
  })
261
263
  })]
262
264
  })
@@ -275,7 +277,7 @@ window.__ModuleLoader__.load({
275
277
  children: [
276
278
  (0, react_jsx_runtime.jsx)("span", {
277
279
  className: GoalBar_module_css_default.goalGlyph,
278
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutline16, { size: 14 })
280
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutlineRegular, { size: 14 })
279
281
  }),
280
282
  (0, react_jsx_runtime.jsx)("span", {
281
283
  className: GoalBar_module_css_default.label,
@@ -305,7 +307,7 @@ window.__ModuleLoader__.load({
305
307
  runAction(onPause);
306
308
  },
307
309
  "aria-label": t("action.pause"),
308
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPauseOutline16, { size: 14 })
310
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPauseOutlineRegular, { size: 14 })
309
311
  })
310
312
  }),
311
313
  showResume && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -320,7 +322,7 @@ window.__ModuleLoader__.load({
320
322
  runAction(onResume);
321
323
  },
322
324
  "aria-label": t("action.resume"),
323
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, { size: 14 })
325
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutlineRegular, { size: 14 })
324
326
  })
325
327
  }),
326
328
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -336,7 +338,7 @@ window.__ModuleLoader__.load({
336
338
  setEditing(true);
337
339
  },
338
340
  "aria-label": t("action.edit"),
339
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 14 })
341
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, { size: 14 })
340
342
  })
341
343
  }),
342
344
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
@@ -351,7 +353,7 @@ window.__ModuleLoader__.load({
351
353
  handleClear(goal.id);
352
354
  },
353
355
  "aria-label": t("action.clear"),
354
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
356
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
355
357
  })
356
358
  })
357
359
  ]
@@ -558,7 +560,14 @@ window.__ModuleLoader__.load({
558
560
  hooks: { goalActivation: createGoalActivationSource({
559
561
  projection: binding.session.projections.faceOf("goal"),
560
562
  session: binding.session,
561
- getGoal: () => ctx.remote.goals.get(sessionId),
563
+ getGoal: async () => {
564
+ if (sessions.binding(sessionId) !== binding) throw new Error(`ui-goal: session "${sessionId}" is unavailable`);
565
+ return sessions.using(sessionId, { source: "goalActivation" }, async (reference) => {
566
+ const state = reference.binding.session.getSnapshot();
567
+ if (state.openState !== "open") throw state.openError ?? /* @__PURE__ */ new Error(`session "${sessionId}" is not open`);
568
+ return ctx.remote.goals.get(sessionId);
569
+ });
570
+ },
562
571
  subscribeActivation: (listener) => ctx.remote.$on("goal/activation-changed", (event) => {
563
572
  if (event.sessionId === sessionId) listener(event.goal);
564
573
  }),
@@ -11,7 +11,7 @@ export interface GoalActivationDeps {
11
11
  readonly session: HostObservable<{
12
12
  readonly running: boolean;
13
13
  }>;
14
- /** Read the current live goal at call time. */
14
+ /** Read live activation after initial history; rejected reads leave the current snapshot unchanged. */
15
15
  readonly getGoal: () => Promise<RemoteResult<GoalView | undefined>>;
16
16
  /** Subscribe to activation edges after the transport delivers them. */
17
17
  readonly subscribeActivation: (listener: (goal: GoalActivationChanged['goal']) => void) => () => void;
@@ -4,6 +4,8 @@
4
4
  * `useProjection('goal')`. A registrant-private activation hook source owns
5
5
  * the live Remote read and event subscription; the inject face carries that
6
6
  * hook plus the four mutation verbs through the generated Goal Remote API.
7
+ * Activation reads retain the Client Session through completion and wait
8
+ * for its initial history open to succeed before contacting the Host.
7
9
  * This plugin does not create goals; deployments may expose /goal separately.
8
10
  */
9
11
  import type { Context as ClientContext } from '@deepseek-ai/cordis';
@@ -11,6 +13,12 @@ import { type GoalKey } from './locales.ts';
11
13
  export { GoalBar, GoalDock } from './GoalBar.tsx';
12
14
  export type { GoalActionResult, GoalBarActions, } from './slots.ts';
13
15
  export type { GoalKey } from './locales.ts';
16
+ declare module '@deepseek-ai/dsh-api-session-controller/client' {
17
+ interface SessionReferenceSourceMap {
18
+ /** A live goal read waiting for initial history and its RPC result. */
19
+ goalActivation: unknown;
20
+ }
21
+ }
14
22
  declare module '@deepseek-ai/dsh-client-ui-slots' {
15
23
  interface LocaleNamespaceMap {
16
24
  /** The goal strip's copy. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-goal",
3
3
  "description": "Session goal surface: GoalBar docked above the composer, read from the goal session projection",
4
- "version": "0.1.6-alpha.2",
4
+ "version": "0.1.7-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -41,28 +41,28 @@
41
41
  },
42
42
  "license": "MIT",
43
43
  "peerDependencies": {
44
- "@deepseek-ai/cordis": "^4.0.2"
44
+ "@deepseek-ai/cordis": "~4.0.4"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@testing-library/react": "^16.1.0",
48
48
  "@types/react": "~18.3.1",
49
49
  "react": "^18.2.0",
50
50
  "react-dom": "^18.2.0",
51
- "@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
52
- "@deepseek-ai/dsh-api-session-controller": "^0.1.6-alpha.2",
53
- "@deepseek-ai/dsh-client-locale": "^0.1.6-alpha.2",
54
- "@deepseek-ai/dsh-client-ui-chat": "^0.1.6-alpha.2",
55
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.6-alpha.2",
56
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.6-alpha.2",
57
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.6-alpha.2",
58
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.6-alpha.2",
59
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.6-alpha.2",
60
- "@deepseek-ai/dsh-client-ui-session": "^0.1.6-alpha.2",
61
- "@deepseek-ai/dsh-goal": "^0.1.6-alpha.2",
62
- "@deepseek-ai/dsh-session": "^0.1.6-alpha.2",
63
- "@deepseek-ai/dsh-commands": "^0.1.6-alpha.2",
64
- "@deepseek-ai/cordis": "^4.0.2",
65
- "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2"
51
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-alpha.2",
52
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-alpha.2",
53
+ "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
54
+ "@deepseek-ai/dsh-client-ui-chat": "0.1.7-alpha.2",
55
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-alpha.2",
56
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
57
+ "@deepseek-ai/dsh-client-test-runtime": "0.1.7-alpha.2",
58
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
59
+ "@deepseek-ai/dsh-commands": "0.1.7-alpha.2",
60
+ "@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.2",
61
+ "@deepseek-ai/dsh-goal": "0.1.7-alpha.2",
62
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
63
+ "@deepseek-ai/dsh-session": "0.1.7-alpha.2",
64
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-alpha.2",
65
+ "@deepseek-ai/cordis": "~4.0.4"
66
66
  },
67
67
  "files": [
68
68
  "lib/index.js",