@michengai/dsh-codex-pet 0.1.6 → 0.1.8

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.8] - 2026-09-22
4
+
5
+ - Add compatibility with DSH `0.1.7-alpha.1` without dropping the existing supported hosts. Pin development types and the default end-to-end host to this release. The model fixture answers the Messages API on this host.
6
+
7
+ ## [0.1.7] - 2026-09-18
8
+
9
+ - 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.
10
+ - Use a bilingual package description matching the GitHub repository.
11
+
3
12
  ## [0.1.6] - 2026-09-16
4
13
 
5
14
  - 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.
@@ -1,5 +1,14 @@
1
1
  # 更新日志
2
2
 
3
+ ## [0.1.8] - 2026-09-22
4
+
5
+ - 新增 DSH `0.1.7-alpha.1` 兼容,不移除已支持的旧宿主。开发类型检查和默认端到端宿主固定到该版本。该宿主的模型夹具改为应答 Messages API。
6
+
7
+ ## [0.1.7] - 2026-09-18
8
+
9
+ - 新增 DSH `0.1.6-alpha.2` 兼容,不移除已支持的旧宿主。旧宿主继续使用 `sessions.open`、`pendingInteractions` 和会话快照里的旧请求;仅在这些接口消失后改走 `uiWorkspace.openSession` 和 `uiSession.sessionStatus`。开发类型检查和默认端到端宿主固定到该版本。
10
+ - 软件包描述改为与 GitHub 仓库一致的中英文双语。
11
+
3
12
  ## [0.1.6] - 2026-09-16
4
13
 
5
14
  - 新增 DSH `0.1.6-alpha.1` 兼容,不移除已支持的旧宿主。开发类型检查和默认端到端宿主固定到该版本。
package/README.md CHANGED
@@ -74,7 +74,7 @@ For a desktop workbench, download [DSH Codex Desktop](https://github.com/Micheng
74
74
 
75
75
  ## Installation
76
76
 
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`, and `0.1.6-alpha.1`**. 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`, `0.1.6-alpha.2`, and `0.1.7-alpha.1`**. 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.
78
78
 
79
79
  ```powershell
80
80
  [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
package/README.zh-CN.md CHANGED
@@ -74,7 +74,7 @@
74
74
 
75
75
  ## 安装
76
76
 
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`**,需要可使用 `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`、`0.1.7-alpha.1`**。新增兼容不移除这些旧版。需要可用的 `dsh` 命令。以下示例使用 `web` profile,请按实际环境替换。
78
78
 
79
79
  ```powershell
80
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.6"
951
+ "0.1.8"
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.6",
3
+ "version": "0.1.8",
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 || 0.1.6-alpha.1",
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 || 0.1.7-alpha.1",
63
63
  "react": "^18.2.0",
64
64
  "react-dom": "^18.2.0"
65
65
  },
@@ -69,14 +69,15 @@
69
69
  }
70
70
  },
71
71
  "devDependencies": {
72
- "@deepseek-ai/cordis": "4.0.2",
73
- "@deepseek-ai/dsh": "0.1.6-alpha.1",
74
- "@deepseek-ai/dsh-api-session-controller": "0.1.6-alpha.1",
75
- "@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
76
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
77
- "@deepseek-ai/dsh-client-ui-session": "0.1.6-alpha.1",
78
- "@deepseek-ai/dsh-client-ui-slots": "0.1.6-alpha.1",
79
- "@deepseek-ai/dsh-host-webserver": "0.1.6-alpha.1",
72
+ "@deepseek-ai/cordis": "4.0.3",
73
+ "@deepseek-ai/dsh": "0.1.7-alpha.1",
74
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-alpha.1",
75
+ "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.1",
76
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.1",
77
+ "@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.1",
78
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.1",
79
+ "@deepseek-ai/dsh-client-ui-workspace": "0.1.7-alpha.1",
80
+ "@deepseek-ai/dsh-host-webserver": "0.1.7-alpha.1",
80
81
  "@electron/asar": "^3.4.1",
81
82
  "@radix-ui/react-icons": "^1.3.2",
82
83
  "@types/node": "^24.0.0",