@michengai/dsh-codex-pet 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.7] - 2026-09-18
4
+
5
+ - Add compatibility with DSH `0.1.6-alpha.2` without dropping the existing supported hosts. Keep `sessions.open`, `pendingInteractions`, and legacy session snapshots on older hosts; use `uiWorkspace.openSession` and `uiSession.sessionStatus` only when those APIs are gone. Pin development types and the default e2e host to this release.
6
+ - Use a bilingual package description matching the GitHub repository.
7
+
8
+ ## [0.1.6] - 2026-09-16
9
+
10
+ - Add compatibility with DSH `0.1.6-alpha.1` without dropping the existing supported hosts. Pin development types and the default e2e host to this release.
11
+
3
12
  ## [0.1.5] - 2026-09-12
4
13
 
5
14
  - Keep the pet in a global Web overlay across pages while preserving interaction and letting clicks pass through empty areas.
@@ -1,5 +1,14 @@
1
1
  # 更新日志
2
2
 
3
+ ## [0.1.7] - 2026-09-18
4
+
5
+ - 新增 DSH `0.1.6-alpha.2` 兼容,不移除已支持的旧宿主。旧宿主继续使用 `sessions.open`、`pendingInteractions` 和会话快照里的旧请求;仅在这些接口消失后改走 `uiWorkspace.openSession` 和 `uiSession.sessionStatus`。开发类型检查和默认端到端宿主固定到该版本。
6
+ - 软件包描述改为与 GitHub 仓库一致的中英文双语。
7
+
8
+ ## [0.1.6] - 2026-09-16
9
+
10
+ - 新增 DSH `0.1.6-alpha.1` 兼容,不移除已支持的旧宿主。开发类型检查和默认端到端宿主固定到该版本。
11
+
3
12
  ## [0.1.5] - 2026-09-12
4
13
 
5
14
  - 宠物改为在整个 Web 页面内悬浮,切换页面时保留显示和交互,空白区域不阻挡页面操作。
package/README.md CHANGED
@@ -56,23 +56,25 @@ Keep working in DSH while the pet and task notifications remain in the corner of
56
56
 
57
57
  ## DSH product ecosystem
58
58
 
59
- Add plugins as needed to your existing DeepSeek Harness environment.
59
+ For a desktop workbench, download [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases). Existing [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) installations can add plugins as needed by following each project's README. Below are 11 first-party plugins; consult the corresponding desktop release notes and bundled catalog for what that version includes.
60
60
 
61
61
  | Plugin | What you can do |
62
62
  | --- | --- |
63
- | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | Organize projects and conversations and navigate tasks |
64
- | [IM Connect](https://github.com/MichengAI/dsh-im-connect) | Send tasks and receive replies through messaging platforms |
65
- | [Automation](https://github.com/MichengAI/dsh-automation) | Schedule tasks and review their runs |
63
+ | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | Organize projects and conversations, search tasks, and navigate chat turns |
64
+ | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | Choose and summon specialists for your task |
66
65
  | [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | Find, enable, create, and import local skills |
67
- | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | Search, restore, and manage archived conversations |
68
- | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | Choose specialists for a task |
69
- | [BTW](https://github.com/MichengAI/dsh-btw) | Ask side questions in the current context |
70
- | [Simplify](https://github.com/MichengAI/dsh-simplify) | Improve code within your Git changes |
71
- | [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | Keep a companion nearby and handle task notifications |
66
+ | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | Search, restore, or clean up archived conversations |
67
+ | [IM Connect](https://github.com/MichengAI/dsh-im-connect) | Send tasks and receive replies through messaging platforms |
68
+ | [Automation](https://github.com/MichengAI/dsh-automation) | Schedule tasks and review each run |
69
+ | [BTW](https://github.com/MichengAI/dsh-btw) | Ask side questions without interrupting the main task |
70
+ | [Simplify](https://github.com/MichengAI/dsh-simplify) | Use `/simplify` to improve code within your Git changes |
71
+ | [PUA](https://github.com/MichengAI/dsh-pua) | Guide the Agent to try new approaches after failures, investigate causes, and verify results before completion |
72
+ | [Code Review](https://github.com/MichengAI/dsh-code-review) | Use `/review` to request an independent Agent code review and receive the report in the current conversation |
73
+ | [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | View conversation notifications and respond to tool approvals and questions through a desktop pet |
72
74
 
73
75
  ## Installation
74
76
 
75
- Supported DeepSeek Harness versions: **`0.1.0-rc.8`, `0.1.1-rc.2`, `0.1.2-rc.1`, `0.1.5-rc.1`, and `0.1.5-rc.2`**. New compatibility is added without dropping these older releases. Make sure the `dsh` command is available. The example uses the `web` profile; replace it with your target profile.
77
+ Supported DeepSeek Harness versions: **`0.1.0-rc.8`, `0.1.1-rc.2`, `0.1.2-rc.1`, `0.1.5-rc.1`, `0.1.5-rc.2`, `0.1.6-alpha.1`, and `0.1.6-alpha.2`**. New compatibility is added without dropping these older releases. Make sure the `dsh` command is available. The example uses the `web` profile; replace it with your target profile.
76
78
 
77
79
  ```powershell
78
80
  [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
package/README.zh-CN.md CHANGED
@@ -56,23 +56,25 @@
56
56
 
57
57
  ## DSH 产品生态
58
58
 
59
- 为已有 DeepSeek Harness 环境按需添加功能。
59
+ 想使用桌面工作台,可下载 [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases);已有 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 环境,可按各项目 README 按需安装。以下列出 11 个自研插件;桌面端实际随附范围以对应版本的发行说明和内置清单为准。
60
60
 
61
61
  | 插件 | 你可以用它做什么 |
62
62
  | --- | --- |
63
- | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | 整理项目与会话,导航任务 |
63
+ | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | 整理项目与会话、搜索任务、跳转对话轮次 |
64
+ | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | 按任务选择并召唤专业角色 |
65
+ | [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | 统一查找、启停、创建和导入本机技能 |
66
+ | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | 搜索、恢复或清理已归档会话 |
64
67
  | [IM Connect](https://github.com/MichengAI/dsh-im-connect) | 从消息平台下任务、收回复 |
65
- | [Automation](https://github.com/MichengAI/dsh-automation) | 按计划执行任务,查看运行结果 |
66
- | [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | 查找、启停、创建和导入本机技能 |
67
- | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | 搜索、恢复和管理已归档会话 |
68
- | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | 为任务选择专业角色 |
69
- | [BTW](https://github.com/MichengAI/dsh-btw) | 在当前上下文中临时旁问 |
70
- | [Simplify](https://github.com/MichengAI/dsh-simplify) | 整理 Git 改动范围内的代码 |
71
- | [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | 宠物陪伴,查看和处理任务通知 |
68
+ | [Automation](https://github.com/MichengAI/dsh-automation) | 按计划执行任务,查看每次运行的结果 |
69
+ | [BTW](https://github.com/MichengAI/dsh-btw) | 在当前上下文中临时旁问,不打断主任务 |
70
+ | [Simplify](https://github.com/MichengAI/dsh-simplify) | 用 `/simplify` 整理 Git 改动范围内的代码 |
71
+ | [PUA](https://github.com/MichengAI/dsh-pua) | 引导 Agent 在失败时换方法、查原因,并在完成前验证结果 |
72
+ | [Code Review](https://github.com/MichengAI/dsh-code-review) | 用 `/review` 发起独立 Agent 代码审查,在当前会话接收报告 |
73
+ | [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | 通过桌面宠物查看会话提醒、处理工具审批和问题回答 |
72
74
 
73
75
  ## 安装
74
76
 
75
- 支持 DeepSeek Harness **`0.1.0-rc.8`、`0.1.1-rc.2`、`0.1.2-rc.1`、`0.1.5-rc.1`、`0.1.5-rc.2`**,需要可使用 `dsh` 命令。新增兼容不移除这些旧版。以下示例使用 `web` profile,请按实际环境替换。
77
+ 支持的 DeepSeek Harness 版本:**`0.1.0-rc.8`、`0.1.1-rc.2`、`0.1.2-rc.1`、`0.1.5-rc.1`、`0.1.5-rc.2`、`0.1.6-alpha.1`、`0.1.6-alpha.2`**。新增兼容不移除这些旧版。需要可用的 `dsh` 命令。以下示例使用 `web` profile,请按实际环境替换。
76
78
 
77
79
  ```powershell
78
80
  [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
package/lib/client.js CHANGED
@@ -38,14 +38,44 @@ __export(client_exports, {
38
38
  module.exports = __toCommonJS(client_exports);
39
39
 
40
40
  // src/session-compat.ts
41
- function compatibleSessions(sessions) {
41
+ function compatibleSessions(sessions, navigate, status) {
42
42
  const cache = /* @__PURE__ */ new WeakMap();
43
+ const refs = /* @__PURE__ */ new Map();
44
+ const sweep = () => {
45
+ const ids = new Set(sessions.list?.getSnapshot?.()?.ids ?? []);
46
+ for (const [id, ref] of refs) if (!ids.has(id)) {
47
+ try {
48
+ ref.release();
49
+ } catch {
50
+ }
51
+ refs.delete(id);
52
+ }
53
+ };
54
+ sessions.list?.subscribe?.(sweep);
43
55
  return {
44
56
  list: sessions.list,
45
- open: (id) => sessions.open(id),
46
- create: (options) => sessions.create(options),
57
+ status: status ?? sessions.status,
58
+ using: sessions.using?.bind(sessions),
59
+ open: (id) => navigate ? navigate(id) : sessions.open?.(id),
60
+ create: (options) => {
61
+ if (!sessions.create) throw new Error("\u521B\u5EFA\u4F1A\u8BDD\u5C1A\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u8BD5");
62
+ return sessions.create(options);
63
+ },
47
64
  binding(id) {
48
- const binding = sessions.binding(id);
65
+ sweep();
66
+ let binding = sessions.binding(id);
67
+ if (!binding && sessions.retain) {
68
+ let ref = refs.get(id);
69
+ if (!ref) {
70
+ try {
71
+ ref = sessions.retain(id, { source: "controllerOperation" });
72
+ refs.set(id, ref);
73
+ } catch {
74
+ return void 0;
75
+ }
76
+ }
77
+ binding = ref.binding;
78
+ }
49
79
  if (!binding || binding.eventSource) return binding;
50
80
  const cached = cache.get(binding);
51
81
  if (cached) return cached;
@@ -73,6 +103,31 @@ function compatibleSessions(sessions) {
73
103
  };
74
104
  }
75
105
 
106
+ // src/pending-status.ts
107
+ function pendingFromSessionStatus(status) {
108
+ return {
109
+ getSnapshot() {
110
+ const next = /* @__PURE__ */ new Map();
111
+ for (const [id, row] of status.getSnapshot()) {
112
+ const wait = row.pendingInteraction;
113
+ if (!wait || typeof wait !== "object") continue;
114
+ const item = wait;
115
+ next.set(String(id), {
116
+ kind: item.kind,
117
+ key: item.key,
118
+ sessionId: item.sessionId ?? String(id),
119
+ toolName: item.toolName,
120
+ reason: item.reason,
121
+ questions: item.questions,
122
+ answer: typeof item.answer === "function" ? item.answer.bind(item) : void 0
123
+ });
124
+ }
125
+ return next;
126
+ },
127
+ subscribe: (listener) => status.subscribe(listener)
128
+ };
129
+ }
130
+
76
131
  // src/legacy-pending.ts
77
132
  function compatiblePending(sessions, resolveModern) {
78
133
  const legacy = legacyPending(sessions);
@@ -893,7 +948,7 @@ function PluginUpdateHeader({ locale }) {
893
948
  zh2 ? "\u5BA0\u7269" : "Pets",
894
949
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "dcp-version", children: [
895
950
  "v",
896
- "0.1.5"
951
+ "0.1.7"
897
952
  ] })
898
953
  ] }),
899
954
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", { className: "dcp-project-links", children: [
@@ -1880,6 +1935,12 @@ function Companion({
1880
1935
  );
1881
1936
  }
1882
1937
 
1938
+ // src/activity.ts
1939
+ function selectedSessionId(list) {
1940
+ for (const id of list.ids) if ((list.byId[id]?.retainedBy?.mainView ?? 0) > 0) return id;
1941
+ return list.current;
1942
+ }
1943
+
1883
1944
  // src/notifications.ts
1884
1945
  var priority = { waiting: 0, failed: 1, review: 2, running: 3 };
1885
1946
  var lifetime = { failed: 36e5, waiting: 864e5, review: 6048e5 };
@@ -1910,7 +1971,8 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
1910
1971
  if (publishing) return;
1911
1972
  publishing = true;
1912
1973
  try {
1913
- const list = sessions.list.getSnapshot(), requests = pending.getSnapshot();
1974
+ const list = sessions.list.getSnapshot(), requests = pending.getSnapshot(), statuses = sessions.status?.getSnapshot();
1975
+ const current = selectedSessionId(list);
1914
1976
  const ids = new Set(list.ids.filter((id) => list.byId[id] && list.byId[id].origin !== "subagent"));
1915
1977
  for (const id of records.keys()) if (!ids.has(id)) {
1916
1978
  records.delete(id);
@@ -1927,33 +1989,35 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
1927
1989
  for (const id of ids) {
1928
1990
  const row = list.byId[id];
1929
1991
  if (!row) continue;
1992
+ const status = statuses?.get(id);
1930
1993
  const binding = sessions.binding(id);
1931
1994
  let record = records.get(id);
1932
1995
  if (!record) {
1933
- record = { round: 0, running: row.running, completion: !!row.completed, error: null, revision: binding?.eventSource.getSnapshot().revision ?? -1, updatedAt: row.updatedAt ?? now(), lastPose: "" };
1996
+ record = { round: 0, running: row.running, completion: !!status?.completionUnread || !!row.completed, error: null, revision: binding?.eventSource?.getSnapshot().revision ?? -1, updatedAt: row.updatedAt ?? now(), lastPose: "" };
1934
1997
  records.set(id, record);
1935
1998
  }
1936
1999
  const previous = bindings.get(id);
1937
2000
  if (binding && (previous?.binding.session !== binding.session || previous.binding.eventSource !== binding.eventSource)) {
1938
2001
  previous?.off();
1939
- record.revision = binding.eventSource.getSnapshot().revision;
1940
- const offSession = binding.session.subscribe(publish), offEvents = binding.eventSource.subscribe(publish);
2002
+ record.revision = binding.eventSource?.getSnapshot().revision ?? record.revision;
2003
+ const offSession = binding.session.subscribe(publish), offEvents = binding.eventSource?.subscribe(publish);
1941
2004
  bindings.set(id, { binding, off: () => {
1942
2005
  offSession();
1943
- offEvents();
2006
+ offEvents?.();
1944
2007
  } });
1945
2008
  }
1946
2009
  const snapshot = binding?.session.getSnapshot();
1947
- const running = id === list.current ? snapshot?.running ?? row.running : row.running;
2010
+ const running = status?.running ?? (id === current ? snapshot?.running ?? row.running : row.running);
1948
2011
  if (running && !record.running) {
1949
2012
  record.round++;
1950
2013
  record.awaitingStart = true;
1951
2014
  record.finished = void 0;
1952
2015
  record.completion = false;
1953
2016
  record.error = null;
2017
+ record.suppressStopCompletion = false;
1954
2018
  record.updatedAt = now();
1955
2019
  }
1956
- const events = binding?.eventSource.getSnapshot();
2020
+ const events = binding?.eventSource?.getSnapshot();
1957
2021
  if (events && record.revision !== events.revision) {
1958
2022
  record.revision = events.revision;
1959
2023
  if (events.change.kind === "append") for (const entry of events.change.entries) {
@@ -1971,11 +2035,18 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
1971
2035
  record.updatedAt = now();
1972
2036
  }
1973
2037
  }
2038
+ else if (events.change.kind === "replace") record.suppressStopCompletion = true;
1974
2039
  }
2040
+ const stopped = !running && record.running;
1975
2041
  record.running = running;
1976
- if (snapshot?.lastAgentError && snapshot.lastAgentError !== record.snapshotError) record.error = snapshot.lastAgentError;
1977
- record.snapshotError = snapshot?.lastAgentError;
1978
- if (row.completed && !running && (!record.finished || record.finished === "completed")) record.completion = true;
2042
+ const agentError = snapshot?.lastAgentError ?? snapshot?.promptError?.error?.message ?? null;
2043
+ if (agentError && agentError !== record.snapshotError) record.error = agentError;
2044
+ record.snapshotError = agentError;
2045
+ if (stopped && !record.suppressStopCompletion && !record.finished && !record.error) {
2046
+ record.completion = true;
2047
+ record.updatedAt = now();
2048
+ }
2049
+ if ((status?.completionUnread || row.completed) && !running && (!record.finished || record.finished === "completed")) record.completion = true;
1979
2050
  const request2 = requests.get(id);
1980
2051
  const activity = selectActivity([{ id, title: row.title ?? row.displayTitle, running, waiting: !!request2, error: running ? null : record.error, completed: !running && record.completion }]);
1981
2052
  if (activity.pose === "idle") continue;
@@ -2002,7 +2073,7 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
2002
2073
  publishing = false;
2003
2074
  }
2004
2075
  };
2005
- const offList = sessions.list.subscribe(publish), offPending = pending.subscribe(publish);
2076
+ const offList = sessions.list.subscribe(publish), offPending = pending.subscribe(publish), offStatus = sessions.status?.subscribe(publish);
2006
2077
  publish();
2007
2078
  const timer = setInterval(publish, 1e3);
2008
2079
  return {
@@ -2025,6 +2096,7 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
2025
2096
  return;
2026
2097
  }
2027
2098
  if (command.type === "open") {
2099
+ if (!sessions.open) throw new Error("\u5BBF\u4E3B\u672A\u63D0\u4F9B\u6253\u5F00\u4F1A\u8BDD\u80FD\u529B");
2028
2100
  sessions.open(item.id);
2029
2101
  if (item.pose === "review") dismissed.set(item.id, item.token);
2030
2102
  publish();
@@ -2064,6 +2136,7 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
2064
2136
  dispose() {
2065
2137
  offList();
2066
2138
  offPending();
2139
+ offStatus?.();
2067
2140
  clearInterval(timer);
2068
2141
  for (const value of bindings.values()) value.off();
2069
2142
  bindings.clear();
@@ -2072,17 +2145,38 @@ function createNotifications(sessions, pending, notify, now = Date.now) {
2072
2145
  }
2073
2146
 
2074
2147
  // src/creation.ts
2148
+ function tryOpen(sessions, id) {
2149
+ try {
2150
+ sessions.open?.(id);
2151
+ } catch {
2152
+ }
2153
+ }
2075
2154
  async function createPetSession(sessions, description, directory, skill) {
2076
2155
  if (!description.trim() || description.length > 2e3) throw new Error("\u8BF7\u8F93\u5165 1\u20132000 \u5B57\u7684\u5BA0\u7269\u63CF\u8FF0");
2077
2156
  const id = await sessions.create({ cwd: directory });
2078
- sessions.open(id);
2079
- const binding = sessions.binding(id);
2080
- if (!binding) throw new Error("\u521B\u5EFA\u4F1A\u8BDD\u5C1A\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u8BD5");
2081
2157
  const text = `\u8BF7\u5148\u8BFB\u53D6\u5E76\u9075\u5FAA\u5BA0\u7269\u521B\u5EFA Skill\uFF1A${skill}
2082
2158
  \u5BA0\u7269\u8981\u6C42\uFF1A${description.trim()}
2083
2159
  \u6210\u54C1\u4FDD\u5B58\u5230 ${directory} \u4E0B\u7684\u65B0\u76EE\u5F55\uFF0C\u4FDD\u7559\u6240\u6709\u5DF2\u6709\u5BA0\u7269\u3002\u4F7F\u7528 DSH \u5F53\u524D\u914D\u7F6E\u7684\u56FE\u50CF\u5DE5\u5177\u3002\u7F3A\u5C11\u751F\u56FE\u5DE5\u5177\u65F6\u660E\u786E\u8BF4\u660E\uFF0C\u4E0D\u751F\u6210\u5360\u4F4D\u56FE\uFF0C\u4E0D\u865A\u62A5\u5B8C\u6210\u3002`;
2084
- const result = await binding.session.prompt([{ type: "text", text }], "queue");
2085
- if (!result.ok) throw new Error(result.error?.message ?? "DSH \u672A\u63A5\u53D7\u5BA0\u7269\u521B\u5EFA\u8BF7\u6C42");
2160
+ const send = async (session) => {
2161
+ const result = await session.prompt([{ type: "text", text }], "queue");
2162
+ if (!result.ok) throw new Error(result.error?.message ?? "DSH \u672A\u63A5\u53D7\u5BA0\u7269\u521B\u5EFA\u8BF7\u6C42");
2163
+ };
2164
+ tryOpen(sessions, id);
2165
+ const binding = sessions.binding(id);
2166
+ if (binding?.session.prompt) {
2167
+ await send(binding.session);
2168
+ tryOpen(sessions, id);
2169
+ return;
2170
+ }
2171
+ if (sessions.using) {
2172
+ await sessions.using(id, { source: "controllerOperation" }, async (reference) => {
2173
+ await reference.ready;
2174
+ await send(reference.binding.session);
2175
+ });
2176
+ tryOpen(sessions, id);
2177
+ return;
2178
+ }
2179
+ throw new Error("\u521B\u5EFA\u4F1A\u8BDD\u5C1A\u4E0D\u53EF\u7528\uFF0C\u8BF7\u91CD\u8BD5");
2086
2180
  }
2087
2181
 
2088
2182
  // src/settings-icon.ts
@@ -2227,8 +2321,7 @@ function Overlay({
2227
2321
  activity: state.activity,
2228
2322
  tray: { state, command },
2229
2323
  open: () => {
2230
- if (state.activity.sessionId)
2231
- sessions.open(state.activity.sessionId);
2324
+ if (state.activity.sessionId) sessions.open?.(state.activity.sessionId);
2232
2325
  },
2233
2326
  settings: openSettings
2234
2327
  }
@@ -2300,11 +2393,58 @@ function Page({
2300
2393
  }
2301
2394
  );
2302
2395
  }
2396
+ function probe(ctx, name2) {
2397
+ if (ctx.reflect) {
2398
+ try {
2399
+ return ctx.reflect.get(name2);
2400
+ } catch {
2401
+ return void 0;
2402
+ }
2403
+ }
2404
+ return ctx[name2];
2405
+ }
2406
+ function liveSessionStatus(ctx) {
2407
+ const resolve = () => {
2408
+ const live = probe(ctx, "uiSession");
2409
+ return live && "sessionStatus" in live ? live.sessionStatus : void 0;
2410
+ };
2411
+ return {
2412
+ getSnapshot() {
2413
+ return resolve()?.getSnapshot() ?? /* @__PURE__ */ new Map();
2414
+ },
2415
+ subscribe(listener) {
2416
+ let source = resolve();
2417
+ let off = source?.subscribe(listener);
2418
+ const timer = setInterval(() => {
2419
+ const next = resolve();
2420
+ if (next === source) return;
2421
+ off?.();
2422
+ source = next;
2423
+ off = next?.subscribe(listener);
2424
+ listener();
2425
+ }, 250);
2426
+ return () => {
2427
+ clearInterval(timer);
2428
+ off?.();
2429
+ };
2430
+ }
2431
+ };
2432
+ }
2303
2433
  function apply(ctx) {
2304
- const sessions = compatibleSessions(ctx.sessions);
2434
+ const sessions = compatibleSessions(
2435
+ ctx.sessions,
2436
+ (id) => {
2437
+ const open = ctx.sessions.open;
2438
+ if (open) return open.call(ctx.sessions, id);
2439
+ const uiWorkspace = probe(ctx, "uiWorkspace");
2440
+ if (uiWorkspace) return uiWorkspace.openSession(id);
2441
+ },
2442
+ liveSessionStatus(ctx)
2443
+ );
2305
2444
  const pending = compatiblePending(sessions, () => {
2306
- const service = ctx.reflect ? ctx.reflect.get("uiSession") : ctx.uiSession;
2307
- return service?.pendingInteractions;
2445
+ const live = probe(ctx, "uiSession");
2446
+ if (live && "sessionStatus" in live && live.sessionStatus) return pendingFromSessionStatus(live.sessionStatus);
2447
+ return live && "pendingInteractions" in live ? live.pendingInteractions : void 0;
2308
2448
  });
2309
2449
  ctx.slots.inject(
2310
2450
  "settings.section",
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@michengai/dsh-codex-pet",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "license": "Apache-2.0",
5
- "description": "独立实现的 DSH 宠物插件:Codex 原始宠物库、Skill 创建、Web 页内显示与消费者接入接口",
5
+ "description": "DSH Codex Pet — 为 DeepSeek Harness 提供宠物陪伴、多任务提醒与交互,以及 Skill 自定义宠物 · A pet companion with multi-task notifications, interactions, and Skill-based custom pets for DeepSeek Harness",
6
6
  "type": "module",
7
7
  "publishConfig": {
8
8
  "access": "public",
@@ -59,7 +59,7 @@
59
59
  "assets:import": "tsx scripts/import-codex.ts"
60
60
  },
61
61
  "peerDependencies": {
62
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
62
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1 || 0.1.6-alpha.2",
63
63
  "react": "^18.2.0",
64
64
  "react-dom": "^18.2.0"
65
65
  },
@@ -70,13 +70,14 @@
70
70
  },
71
71
  "devDependencies": {
72
72
  "@deepseek-ai/cordis": "4.0.2",
73
- "@deepseek-ai/dsh": "0.1.5-rc.2",
74
- "@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.2",
75
- "@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
76
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
77
- "@deepseek-ai/dsh-client-ui-session": "0.1.5-rc.2",
78
- "@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.2",
79
- "@deepseek-ai/dsh-host-webserver": "0.1.5-rc.2",
73
+ "@deepseek-ai/dsh": "0.1.6-alpha.2",
74
+ "@deepseek-ai/dsh-api-session-controller": "0.1.6-alpha.2",
75
+ "@deepseek-ai/dsh-client-locale": "0.1.6-alpha.2",
76
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.2",
77
+ "@deepseek-ai/dsh-client-ui-session": "0.1.6-alpha.2",
78
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.6-alpha.2",
79
+ "@deepseek-ai/dsh-client-ui-workspace": "0.1.6-alpha.2",
80
+ "@deepseek-ai/dsh-host-webserver": "0.1.6-alpha.2",
80
81
  "@electron/asar": "^3.4.1",
81
82
  "@radix-ui/react-icons": "^1.3.2",
82
83
  "@types/node": "^24.0.0",