dsh-milestone 0.7.0 → 0.7.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.md +19 -2
- package/lib/client.js +184 -18
- package/lib/index.js +64 -17
- package/package.json +22 -11
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ shell.overlay (root scope)
|
|
|
114
114
|
|
|
115
115
|
## 版本与兼容
|
|
116
116
|
|
|
117
|
-
- 当前官方支持线:**`0.1.5-rc.1
|
|
117
|
+
- 当前官方支持线:**`0.1.5` 线**(`0.1.5-rc.1` 是 npm `latest`、`0.1.5-rc.2` 是 `next`;peer 范围 `>=0.1.5-rc.1 <0.3.0-0` 同时覆盖两者)。
|
|
118
118
|
- peer/dev 范围为收紧的 `>=0.1.5-rc.1 <0.3.0-0`(`dsh-client-locale` / `dsh-client-store` / `dsh-client-ui-slots`):依赖解析到旧线时会得到明确的 ERESOLVE,而不是静默错配。
|
|
119
119
|
- 0.1.5 起流式时序内嵌在 `assistant/message` / `assistant/attempt` 的紧凑 `stream` 中(独立的 `assistant/chunk` 事件已移除),TTFT 由官方 `assistantStreamFirstTokenTime` 读取;`TokenUsage` 字段更名为 `inputTokens`/`outputTokens`/`totalTokens` 并拆分缓存计数,插件的 `input` 显示为三项之和(缓存计入),保持旧的「提示词 token」含义。
|
|
120
120
|
- 会话数据自 0.1.2 起改经**会话投影**提供(插件注册 `milestone.messages`,client 端 `useProjection` 读取);`defineStore` 由 `@deepseek-ai/dsh-client-store` 提供。
|
|
@@ -140,7 +140,24 @@ shell.overlay (root scope)
|
|
|
140
140
|
## 更新日志
|
|
141
141
|
|
|
142
142
|
<details>
|
|
143
|
-
<summary>v0.7.0 / v0.6.6 / v0.6.5 / v0.6.4(点击展开)</summary>
|
|
143
|
+
<summary>v0.7.2 / v0.7.1 / v0.7.0 / v0.6.6 / v0.6.5 / v0.6.4(点击展开)</summary>
|
|
144
|
+
|
|
145
|
+
**v0.7.2** · 点击旧圆点自动翻页定位(深跳鲁棒性)· 459 项测试
|
|
146
|
+
|
|
147
|
+
- **点旧圆点不再"没反应"**:里程碑条覆盖整个会话,但 DOM 只渲染已加载窗口——此前点一个很早的圆点会静默无反应。现在会自动按页载入更早历史直到定位(有界 20 页),定位期间该圆点脉冲提示,失败则安静结束。
|
|
148
|
+
- 站内搜索的"下一个匹配"跳转同样受益。
|
|
149
|
+
|
|
150
|
+
> [GitHub Release v0.7.2](https://github.com/SnowCrescenter-tech/dsh-milestone/releases/tag/v0.7.2)
|
|
151
|
+
|
|
152
|
+
**v0.7.1** · 升级不再被卡(可选 peer + 兼容边界)· 恢复模型与错误徽标 · 跟随官方 0.1.5-rc.2 · 457 项测试
|
|
153
|
+
|
|
154
|
+
- **升级不再被 ERESOLVE 卡死**:三个 DSH 客户端包 peer 改为 **optional**——官方换 rc 线时只告警、不再拒绝安装;并新增**渲染期兼容边界**:契约一旦变化,给出明确提示("与当前 DSH 版本不兼容,请升级插件"),不再静默消失或拖垮宿主 UI。
|
|
155
|
+
- **恢复悬停卡的模型**:改从 0.1.5 的 `request/context` 事件读取 provider / model(此前恒为 `null`)。
|
|
156
|
+
- **恢复错误 / 重试徽标**:由 `turn/end` 的结束原因(error / max-tokens)与 `assistant/attempt` 结算次数重建(此前徽标恒空)。
|
|
157
|
+
- **跟随官方 `0.1.5-rc.2`**(npm `latest` 仍为 rc.1;peer 范围 `>=0.1.5-rc.1 <0.3.0-0` 同时覆盖两者);上游 `dsh-client-store` 漏声明 `zustand`/`immer` 的兜底扩到整条 0.1.5 线。
|
|
158
|
+
- **CI 新增 `advisory / dsh next`**:持续对官方 `next` 线跑类型检查与测试,提前预警破坏性变更(首跑即发现 rc.2 与上述打包缺陷)。
|
|
159
|
+
|
|
160
|
+
> [GitHub Release v0.7.1](https://github.com/SnowCrescenter-tech/dsh-milestone/releases/tag/v0.7.1)
|
|
144
161
|
|
|
145
162
|
**v0.7.0** · 跟随官方 0.1.5(会话投影数据层)· 折叠为可拖动悬浮球(issue #4)· 447 项测试
|
|
146
163
|
|
package/lib/client.js
CHANGED
|
@@ -4,9 +4,31 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
-
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
7
|
let react = require("react");
|
|
8
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
10
|
+
//#region src/client/modal-tokens.ts
|
|
11
|
+
/**
|
|
12
|
+
* modal-tokens: the ONE source for the settings modal's dark-panel palette and
|
|
13
|
+
* radius scale, shared with the 0.6.5 coach-tour bubble so the two surfaces
|
|
14
|
+
* cannot drift (same dark panel on a dark host, same three text tiers, same
|
|
15
|
+
* 12px panel / 8px control radius, same border tone).
|
|
16
|
+
*
|
|
17
|
+
* The static MODAL_CSS block (hover/focus-visible/reduced-motion rules) stays
|
|
18
|
+
* in MilestoneRail.tsx because it also styles the settings modal's own chrome
|
|
19
|
+
* (`[data-support-card]`, `[data-toolbar-*]`, ...); the tour bubble carries
|
|
20
|
+
* its own small TOUR_CSS block for its controls, built from these same tokens.
|
|
21
|
+
* MilestoneRail.tsx imports these constants verbatim so a future palette
|
|
22
|
+
* change edits exactly one file.
|
|
23
|
+
*/
|
|
24
|
+
const MODAL_BG = "rgba(20, 24, 32, 0.98)";
|
|
25
|
+
const MODAL_FG = "#e6e8ee";
|
|
26
|
+
const MODAL_TITLE = "#c7cede";
|
|
27
|
+
const MODAL_TEXT = "#b9c2d4";
|
|
28
|
+
const MODAL_HINT = "#8b96ab";
|
|
29
|
+
const MODAL_BORDER = "rgba(255, 255, 255, 0.14)";
|
|
30
|
+
const MODAL_TIP_BG = "#222834";
|
|
31
|
+
//#endregion
|
|
10
32
|
//#region src/client/MilestoneOverlay.tsx
|
|
11
33
|
/**
|
|
12
34
|
* @param props - runtime share (root kit) + the narrowed renderSlot and the
|
|
@@ -129,6 +151,23 @@ window.__ModuleLoader__.load({
|
|
|
129
151
|
* @param input - the mark's snapshot signals.
|
|
130
152
|
* @returns the winning badge kind, or null when no signal applies.
|
|
131
153
|
*/
|
|
154
|
+
/**
|
|
155
|
+
* 0.1.5: durable badge kinds for one projected turn. The fold no longer sees
|
|
156
|
+
* the chat-layer `turn-error` / `turn-max-tokens` node kinds, but `turn/end`'s
|
|
157
|
+
* reason carries the same signal, and every `assistant/attempt` settlement
|
|
158
|
+
* (failed / retried / cancelled / stream error) is a retry.
|
|
159
|
+
* @param turn - the projection's turn meta (only the two fields are read).
|
|
160
|
+
* @returns the node-kind vocabulary {@link deriveBadge} consumes; empty when normal.
|
|
161
|
+
*/
|
|
162
|
+
function kindsForTurn(turn) {
|
|
163
|
+
const kinds = [];
|
|
164
|
+
if (turn.endReason === "error" || turn.endReason === "interrupted") kinds.push("turn-error");
|
|
165
|
+
if (turn.endReason === "max-tokens") kinds.push("turn-max-tokens");
|
|
166
|
+
if ((turn.attempts ?? 0) > 0) kinds.push("model-retry");
|
|
167
|
+
return kinds.length === 0 ? EMPTY_KINDS : kinds;
|
|
168
|
+
}
|
|
169
|
+
/** Stable empty result so normal turns never allocate a fresh array. */
|
|
170
|
+
const EMPTY_KINDS = Object.freeze([]);
|
|
132
171
|
function deriveBadge(input) {
|
|
133
172
|
if (input.nodeKinds.includes("turn-error")) return "error";
|
|
134
173
|
if (input.nodeKinds.includes("turn-max-tokens")) return "max-tokens";
|
|
@@ -469,12 +508,12 @@ window.__ModuleLoader__.load({
|
|
|
469
508
|
* @returns the turn's metadata, null where unknown.
|
|
470
509
|
*/
|
|
471
510
|
function deriveTurnMetaFromProjection(turn) {
|
|
472
|
-
if (turn
|
|
511
|
+
if (turn === void 0) return EMPTY_META;
|
|
473
512
|
return {
|
|
474
|
-
model: null,
|
|
513
|
+
model: turn.model ?? null,
|
|
475
514
|
purpose: null,
|
|
476
|
-
inputTokens: turn.usage
|
|
477
|
-
outputTokens: turn.usage
|
|
515
|
+
inputTokens: turn.usage?.input ?? null,
|
|
516
|
+
outputTokens: turn.usage?.output ?? null
|
|
478
517
|
};
|
|
479
518
|
}
|
|
480
519
|
//#endregion
|
|
@@ -1463,12 +1502,6 @@ window.__ModuleLoader__.load({
|
|
|
1463
1502
|
]
|
|
1464
1503
|
});
|
|
1465
1504
|
}
|
|
1466
|
-
const MODAL_FG = "#e6e8ee";
|
|
1467
|
-
const MODAL_TITLE = "#c7cede";
|
|
1468
|
-
const MODAL_TEXT = "#b9c2d4";
|
|
1469
|
-
const MODAL_HINT = "#8b96ab";
|
|
1470
|
-
const MODAL_BORDER = "rgba(255, 255, 255, 0.14)";
|
|
1471
|
-
const MODAL_TIP_BG = "#222834";
|
|
1472
1505
|
//#endregion
|
|
1473
1506
|
//#region src/client/onboarding-store.ts
|
|
1474
1507
|
/**
|
|
@@ -2832,7 +2865,7 @@ window.__ModuleLoader__.load({
|
|
|
2832
2865
|
* Installed plugin version. Injected at build time as
|
|
2833
2866
|
* `__DSH_MILESTONE_VERSION__`; falls back to `0.0.0-dev` when unbuilt.
|
|
2834
2867
|
*/
|
|
2835
|
-
const PLUGIN_VERSION = "0.7.
|
|
2868
|
+
const PLUGIN_VERSION = "0.7.2";
|
|
2836
2869
|
//#endregion
|
|
2837
2870
|
//#region src/client/MilestoneRail.tsx
|
|
2838
2871
|
/**
|
|
@@ -3104,6 +3137,18 @@ window.__ModuleLoader__.load({
|
|
|
3104
3137
|
const DEEP_LINK_MAX_POLLS = 5;
|
|
3105
3138
|
/** P3: bounded polls after `loadOlder`, then the deep link gives up silently. */
|
|
3106
3139
|
const DEEP_LINK_MAX_RETRY_POLLS = 5;
|
|
3140
|
+
/**
|
|
3141
|
+
* Jump paging: the rail's dots cover the WHOLE log while the DOM renders only
|
|
3142
|
+
* the loaded window, so activating an older dot must page history in first.
|
|
3143
|
+
* Bounded so an unreachable target gives up instead of paging forever.
|
|
3144
|
+
*/
|
|
3145
|
+
const LOCATE_MAX_PAGES = 20;
|
|
3146
|
+
/** Delay between a page fetch and the DOM-row recheck (lets React commit). */
|
|
3147
|
+
const LOCATE_POLL_DELAY = 150;
|
|
3148
|
+
/** Pulse applied to the dot whose jump is still paging history in. */
|
|
3149
|
+
const LOCATING_CSS = `@keyframes ms-locating { 0%, 100% { opacity: 1 } 50% { opacity: 0.35 } }
|
|
3150
|
+
[data-locating="true"] { animation: ms-locating 800ms ease-in-out infinite; }
|
|
3151
|
+
@media (prefers-reduced-motion: reduce) { [data-locating="true"] { animation: none } }`;
|
|
3107
3152
|
/** B4 update-check: mount-time silent check delay (ms) — give the harness
|
|
3108
3153
|
* time to settle before hitting the registry. */
|
|
3109
3154
|
const UPDATE_CHECK_MOUNT_DELAY = 1500;
|
|
@@ -3173,7 +3218,16 @@ window.__ModuleLoader__.load({
|
|
|
3173
3218
|
preview: m.preview
|
|
3174
3219
|
}));
|
|
3175
3220
|
}, [projection]);
|
|
3176
|
-
const kindsByTurn =
|
|
3221
|
+
const kindsByTurn = (0, react.useMemo)(() => {
|
|
3222
|
+
const turns = projection?.turns;
|
|
3223
|
+
if (turns === void 0 || turns.length === 0) return EMPTY_KINDS_BY_TURN;
|
|
3224
|
+
const map = /* @__PURE__ */ new Map();
|
|
3225
|
+
for (const t of turns) {
|
|
3226
|
+
const kinds = kindsForTurn(t);
|
|
3227
|
+
if (kinds.length > 0) map.set(t.turn, kinds);
|
|
3228
|
+
}
|
|
3229
|
+
return map;
|
|
3230
|
+
}, [projection]);
|
|
3177
3231
|
const running = useSession((s) => s.running);
|
|
3178
3232
|
const awaitingInput = useSession((s) => s.queue).length > 0;
|
|
3179
3233
|
const [railBox, setRailBox] = (0, react.useState)(null);
|
|
@@ -3196,6 +3250,13 @@ window.__ModuleLoader__.load({
|
|
|
3196
3250
|
const listRef = (0, react.useRef)(null);
|
|
3197
3251
|
const currentKey = useCurrentAnchor(marks.map((m) => m.key));
|
|
3198
3252
|
/**
|
|
3253
|
+
* Mark key whose jump is still paging older history in; its dot pulses so a
|
|
3254
|
+
* slow locate never looks like a dead click.
|
|
3255
|
+
*/
|
|
3256
|
+
const [locatingKey, setLocatingKey] = (0, react.useState)(null);
|
|
3257
|
+
/** Guards against overlapping locate loops (a second activation is ignored). */
|
|
3258
|
+
const locatingRef = (0, react.useRef)(false);
|
|
3259
|
+
/**
|
|
3199
3260
|
* P3: jump to the chat row with the given node key — smooth-scroll it into
|
|
3200
3261
|
* view and write the position back into the URL hash (`#msg=<key>`) so
|
|
3201
3262
|
* refresh and share preserve it. `history.replaceState` (not a
|
|
@@ -3213,6 +3274,45 @@ window.__ModuleLoader__.load({
|
|
|
3213
3274
|
});
|
|
3214
3275
|
history.replaceState(null, "", buildMessageHash(key));
|
|
3215
3276
|
};
|
|
3277
|
+
/**
|
|
3278
|
+
* Jump to a mark, paging older history in first when its row is not rendered
|
|
3279
|
+
* yet. The dots cover the whole log but the DOM holds only the loaded window,
|
|
3280
|
+
* so without this an older dot is a silent no-op (the official rail pages
|
|
3281
|
+
* unloaded turns in the same way). Bounded to LOCATE_MAX_PAGES fetches; the
|
|
3282
|
+
* dot pulses meanwhile.
|
|
3283
|
+
* @param key - the mark key (deep-link payload + exact-match anchor).
|
|
3284
|
+
* @param messageId - the user/message id (real-harness anchor suffix).
|
|
3285
|
+
*/
|
|
3286
|
+
const locateAndJump = (key, messageId) => {
|
|
3287
|
+
if (findRow(key, messageId) !== null) {
|
|
3288
|
+
jump(key, messageId);
|
|
3289
|
+
return;
|
|
3290
|
+
}
|
|
3291
|
+
if (!hasMore || locatingRef.current) return;
|
|
3292
|
+
locatingRef.current = true;
|
|
3293
|
+
setLocatingKey(key);
|
|
3294
|
+
(async () => {
|
|
3295
|
+
try {
|
|
3296
|
+
for (let page = 0; page < LOCATE_MAX_PAGES; page += 1) {
|
|
3297
|
+
try {
|
|
3298
|
+
await loadOlder();
|
|
3299
|
+
} catch {
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
await new Promise((resolve) => {
|
|
3303
|
+
window.setTimeout(resolve, LOCATE_POLL_DELAY);
|
|
3304
|
+
});
|
|
3305
|
+
if (findRow(key, messageId) !== null) {
|
|
3306
|
+
jump(key, messageId);
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
} finally {
|
|
3311
|
+
locatingRef.current = false;
|
|
3312
|
+
setLocatingKey(null);
|
|
3313
|
+
}
|
|
3314
|
+
})();
|
|
3315
|
+
};
|
|
3216
3316
|
const displayMarks = (0, react.useMemo)(() => {
|
|
3217
3317
|
if (!bookmarksOnly) return marks;
|
|
3218
3318
|
return filterByBookmarks(marks, bookmarkedKeys).visible.map((i) => marks[i]);
|
|
@@ -3582,7 +3682,7 @@ window.__ModuleLoader__.load({
|
|
|
3582
3682
|
activePos: next
|
|
3583
3683
|
}));
|
|
3584
3684
|
const mark = displayMarks[matches[next]];
|
|
3585
|
-
|
|
3685
|
+
locateAndJump(mark.key, mark.messageId);
|
|
3586
3686
|
};
|
|
3587
3687
|
const onSearchKeyDown = (e) => {
|
|
3588
3688
|
if (e.key === "Enter") advanceMatch();
|
|
@@ -4169,6 +4269,7 @@ window.__ModuleLoader__.load({
|
|
|
4169
4269
|
"data-inset": String(inset),
|
|
4170
4270
|
children: [
|
|
4171
4271
|
pulseCss !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: pulseCss }),
|
|
4272
|
+
locatingKey !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: LOCATING_CSS }),
|
|
4172
4273
|
focusActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: buildFocusCss(prefs.focus) }),
|
|
4173
4274
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: MODAL_CSS }),
|
|
4174
4275
|
showLoadOlder && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -5273,7 +5374,7 @@ window.__ModuleLoader__.load({
|
|
|
5273
5374
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5274
5375
|
style: { color: "#8b96ab" },
|
|
5275
5376
|
children: [t("update.current"), ": "]
|
|
5276
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.7.
|
|
5377
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "0.7.2" })] }),
|
|
5277
5378
|
updateCheck.phase === "ok" && updateCheck.latest !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5278
5379
|
"data-update-latest": true,
|
|
5279
5380
|
children: [
|
|
@@ -5451,8 +5552,9 @@ window.__ModuleLoader__.load({
|
|
|
5451
5552
|
top: rect.top + rect.height / 2
|
|
5452
5553
|
});
|
|
5453
5554
|
},
|
|
5454
|
-
onClick: () =>
|
|
5555
|
+
onClick: () => locateAndJump(mark.key, mark.messageId),
|
|
5455
5556
|
"data-rail-dot": true,
|
|
5557
|
+
"data-locating": locatingKey === mark.key ? "true" : void 0,
|
|
5456
5558
|
"data-turn-gap": showGroupGap ? "true" : void 0,
|
|
5457
5559
|
"data-turn": showGroupGap && mark.turn !== void 0 ? mark.turn : void 0,
|
|
5458
5560
|
"data-collapsed-summary": summaryCount !== void 0 ? "true" : void 0,
|
|
@@ -5556,6 +5658,70 @@ window.__ModuleLoader__.load({
|
|
|
5556
5658
|
});
|
|
5557
5659
|
}
|
|
5558
5660
|
//#endregion
|
|
5661
|
+
//#region src/client/CompatBoundary.tsx
|
|
5662
|
+
/**
|
|
5663
|
+
* Compatibility boundary for both plugin surfaces.
|
|
5664
|
+
*
|
|
5665
|
+
* The plugin consumes the framework's session standard kit (`useSession`,
|
|
5666
|
+
* `useProjection`, the store seat) and the slot registry, all of which a DSH
|
|
5667
|
+
* upgrade may rename or reshape. Without a boundary such a failure throws out
|
|
5668
|
+
* of the plugin's render — and when the registry silently ignores a stale
|
|
5669
|
+
* entry the rail simply vanishes with no explanation.
|
|
5670
|
+
*
|
|
5671
|
+
* The boundary converts any throw into ONE compact, honest notice instead: the
|
|
5672
|
+
* surrounding harness keeps working, and the user is told what to do (0.1.2→
|
|
5673
|
+
* 0.1.5 has already shown that these upgrades do break third-party plugins).
|
|
5674
|
+
*
|
|
5675
|
+
* A class boundary rather than a per-render capability probe is deliberate:
|
|
5676
|
+
* React exposes error boundaries only through class components, and swapping
|
|
5677
|
+
* hook implementations based on a runtime probe would break hook order.
|
|
5678
|
+
*/
|
|
5679
|
+
/** Catches a render failure anywhere below and shows the incompatibility notice. */
|
|
5680
|
+
var CompatBoundary = class extends react.Component {
|
|
5681
|
+
state = { failed: false };
|
|
5682
|
+
static getDerivedStateFromError() {
|
|
5683
|
+
return { failed: true };
|
|
5684
|
+
}
|
|
5685
|
+
componentDidCatch(error, info) {
|
|
5686
|
+
console.error("[dsh-milestone] incompatible with this DSH version — the rail is disabled. Please update dsh-milestone (or pin an older DSH).", error, info.componentStack);
|
|
5687
|
+
}
|
|
5688
|
+
render() {
|
|
5689
|
+
if (!this.state.failed) return this.props.children;
|
|
5690
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5691
|
+
"data-milestone-incompatible": true,
|
|
5692
|
+
role: "status",
|
|
5693
|
+
style: {
|
|
5694
|
+
position: "fixed",
|
|
5695
|
+
right: 14,
|
|
5696
|
+
bottom: 14,
|
|
5697
|
+
zIndex: 100,
|
|
5698
|
+
maxWidth: 300,
|
|
5699
|
+
padding: "10px 12px",
|
|
5700
|
+
background: MODAL_BG,
|
|
5701
|
+
color: MODAL_HINT,
|
|
5702
|
+
border: `1px solid ${MODAL_BORDER}`,
|
|
5703
|
+
borderRadius: 12,
|
|
5704
|
+
fontSize: 12,
|
|
5705
|
+
lineHeight: 1.5,
|
|
5706
|
+
fontFamily: "inherit"
|
|
5707
|
+
},
|
|
5708
|
+
children: [
|
|
5709
|
+
"dsh-milestone 与当前 DSH 版本不兼容,已停用。请升级插件。",
|
|
5710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {}),
|
|
5711
|
+
"Incompatible with this DSH version — please update dsh-milestone."
|
|
5712
|
+
]
|
|
5713
|
+
});
|
|
5714
|
+
}
|
|
5715
|
+
};
|
|
5716
|
+
/** The `shell.overlay` seat wrapped in the compatibility boundary. */
|
|
5717
|
+
function GuardedMilestoneOverlay(props) {
|
|
5718
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CompatBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MilestoneOverlay, { ...props }) });
|
|
5719
|
+
}
|
|
5720
|
+
/** The `milestone.rail` seat wrapped in the compatibility boundary. */
|
|
5721
|
+
function GuardedMilestoneRail(props) {
|
|
5722
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CompatBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MilestoneRail, { ...props }) });
|
|
5723
|
+
}
|
|
5724
|
+
//#endregion
|
|
5559
5725
|
//#region src/client/bookmarkStore.ts
|
|
5560
5726
|
/**
|
|
5561
5727
|
* Persisted per-session bookmarks store for the milestone rail.
|
|
@@ -5698,7 +5864,7 @@ window.__ModuleLoader__.load({
|
|
|
5698
5864
|
kind: "single",
|
|
5699
5865
|
scope: "session"
|
|
5700
5866
|
} }
|
|
5701
|
-
},
|
|
5867
|
+
}, GuardedMilestoneOverlay));
|
|
5702
5868
|
ctx.slots.inject("milestone.rail", () => ctx.slots.register({
|
|
5703
5869
|
name: "milestone.rail",
|
|
5704
5870
|
store: createBookmarksStore,
|
|
@@ -5709,7 +5875,7 @@ window.__ModuleLoader__.load({
|
|
|
5709
5875
|
searchSessions: createSessionSearch(sessions),
|
|
5710
5876
|
openSession: createOpenSession(sessions)
|
|
5711
5877
|
})
|
|
5712
|
-
},
|
|
5878
|
+
}, GuardedMilestoneRail));
|
|
5713
5879
|
}
|
|
5714
5880
|
//#endregion
|
|
5715
5881
|
exports.apply = apply;
|
package/lib/index.js
CHANGED
|
@@ -20,7 +20,10 @@ const turnMetaSchema = z.object({
|
|
|
20
20
|
input: z.number(),
|
|
21
21
|
output: z.number(),
|
|
22
22
|
total: z.number()
|
|
23
|
-
}).optional()
|
|
23
|
+
}).optional(),
|
|
24
|
+
provider: z.string().optional(),
|
|
25
|
+
model: z.string().optional(),
|
|
26
|
+
attempts: z.number().int().nonnegative().optional()
|
|
24
27
|
});
|
|
25
28
|
z.object({
|
|
26
29
|
messages: z.array(messageEntrySchema),
|
|
@@ -73,7 +76,7 @@ function initialState() {
|
|
|
73
76
|
}
|
|
74
77
|
const milestoneMessagesProjectionDefinition = {
|
|
75
78
|
key: "milestone.messages",
|
|
76
|
-
stateVersion:
|
|
79
|
+
stateVersion: 4,
|
|
77
80
|
stateSchema: z.custom(),
|
|
78
81
|
init: (_header, _inheritedEventCount) => initialState(),
|
|
79
82
|
apply(state, event) {
|
|
@@ -81,12 +84,17 @@ const milestoneMessagesProjectionDefinition = {
|
|
|
81
84
|
case "turn/start": {
|
|
82
85
|
const turn = event.data.turn;
|
|
83
86
|
if (state.turns.some((t) => t.turn === turn)) return state;
|
|
87
|
+
const route = state.route;
|
|
84
88
|
return {
|
|
85
|
-
|
|
89
|
+
...state,
|
|
86
90
|
turns: [...state.turns, {
|
|
87
91
|
turn,
|
|
88
92
|
startSeq: SessionSeq(event.seq),
|
|
89
|
-
startTime: event.time
|
|
93
|
+
startTime: event.time,
|
|
94
|
+
...route === void 0 ? {} : {
|
|
95
|
+
provider: route.provider,
|
|
96
|
+
model: route.model
|
|
97
|
+
}
|
|
90
98
|
}]
|
|
91
99
|
};
|
|
92
100
|
}
|
|
@@ -97,6 +105,7 @@ const milestoneMessagesProjectionDefinition = {
|
|
|
97
105
|
const preview = previewText(content, 80);
|
|
98
106
|
const openTurn = state.turns[state.turns.length - 1];
|
|
99
107
|
return {
|
|
108
|
+
...state,
|
|
100
109
|
messages: [...state.messages, {
|
|
101
110
|
seq: SessionSeq(event.seq),
|
|
102
111
|
messageId: typeof data.id === "string" ? data.id : "",
|
|
@@ -104,8 +113,7 @@ const milestoneMessagesProjectionDefinition = {
|
|
|
104
113
|
turn: openTurn?.turn ?? 0,
|
|
105
114
|
preview,
|
|
106
115
|
text
|
|
107
|
-
}]
|
|
108
|
-
turns: state.turns
|
|
116
|
+
}]
|
|
109
117
|
};
|
|
110
118
|
}
|
|
111
119
|
case "assistant/message": {
|
|
@@ -143,24 +151,31 @@ const milestoneMessagesProjectionDefinition = {
|
|
|
143
151
|
const turns = state.turns.slice();
|
|
144
152
|
turns[index] = next;
|
|
145
153
|
return {
|
|
146
|
-
|
|
154
|
+
...state,
|
|
147
155
|
turns
|
|
148
156
|
};
|
|
149
157
|
}
|
|
150
158
|
case "assistant/attempt": {
|
|
151
159
|
const turn = event.data.turn;
|
|
152
160
|
const index = state.turns.findIndex((t) => t.turn === turn);
|
|
153
|
-
if (index < 0
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
turns[index] = {
|
|
159
|
-
...turns[index],
|
|
160
|
-
firstChunkTime: firstToken
|
|
161
|
+
if (index < 0) return state;
|
|
162
|
+
const prior = state.turns[index];
|
|
163
|
+
let next = {
|
|
164
|
+
...prior,
|
|
165
|
+
attempts: (prior.attempts ?? 0) + 1
|
|
161
166
|
};
|
|
167
|
+
if (prior.firstChunkTime === void 0) {
|
|
168
|
+
const stream = event.data.stream;
|
|
169
|
+
const firstToken = Array.isArray(stream) ? assistantStreamFirstTokenTime(stream) : void 0;
|
|
170
|
+
if (firstToken !== void 0) next = {
|
|
171
|
+
...next,
|
|
172
|
+
firstChunkTime: firstToken
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const turns = state.turns.slice();
|
|
176
|
+
turns[index] = next;
|
|
162
177
|
return {
|
|
163
|
-
|
|
178
|
+
...state,
|
|
164
179
|
turns
|
|
165
180
|
};
|
|
166
181
|
}
|
|
@@ -175,7 +190,39 @@ const milestoneMessagesProjectionDefinition = {
|
|
|
175
190
|
endReason: event.data.reason.kind
|
|
176
191
|
};
|
|
177
192
|
return {
|
|
178
|
-
|
|
193
|
+
...state,
|
|
194
|
+
turns
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
case "request/context": {
|
|
198
|
+
const provider = typeof event.data.provider === "string" ? event.data.provider : "";
|
|
199
|
+
const model = typeof event.data.model === "string" ? event.data.model : "";
|
|
200
|
+
if (provider === "" && model === "") return state;
|
|
201
|
+
const index = state.turns.length - 1;
|
|
202
|
+
const open = index >= 0 ? state.turns[index] : void 0;
|
|
203
|
+
if (open === void 0 || open.endTime !== void 0) {
|
|
204
|
+
if (state.route?.provider === provider && state.route.model === model) return state;
|
|
205
|
+
return {
|
|
206
|
+
...state,
|
|
207
|
+
route: {
|
|
208
|
+
provider,
|
|
209
|
+
model
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (open.provider === provider && open.model === model) return state;
|
|
214
|
+
const turns = state.turns.slice();
|
|
215
|
+
turns[index] = {
|
|
216
|
+
...open,
|
|
217
|
+
provider,
|
|
218
|
+
model
|
|
219
|
+
};
|
|
220
|
+
return {
|
|
221
|
+
...state,
|
|
222
|
+
route: {
|
|
223
|
+
provider,
|
|
224
|
+
model
|
|
225
|
+
},
|
|
179
226
|
turns
|
|
180
227
|
};
|
|
181
228
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-milestone",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Git-style milestone timeline for DeepSeek Harness: hover for metadata, click to jump to any message. 会话里程碑导航条:圆点时间线,定位并跳转到每条提问。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -53,15 +53,26 @@
|
|
|
53
53
|
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1 <0.3.0-0",
|
|
54
54
|
"react": "^18.2.0"
|
|
55
55
|
},
|
|
56
|
+
"peerDependenciesMeta": {
|
|
57
|
+
"@deepseek-ai/dsh-client-locale": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@deepseek-ai/dsh-client-store": {
|
|
61
|
+
"optional": true
|
|
62
|
+
},
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-slots": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
56
67
|
"devDependencies": {
|
|
57
68
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
58
|
-
"@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.
|
|
59
|
-
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.
|
|
60
|
-
"@deepseek-ai/dsh-client-store": "0.1.5-rc.
|
|
61
|
-
"@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.
|
|
62
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-session": "0.1.5-rc.
|
|
64
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.
|
|
69
|
+
"@deepseek-ai/dsh-api-session-controller": "0.1.5-rc.2",
|
|
70
|
+
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
|
|
71
|
+
"@deepseek-ai/dsh-client-store": "0.1.5-rc.2",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.2",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-session": "0.1.5-rc.2",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.2",
|
|
65
76
|
"@playwright/test": "^1.62.1",
|
|
66
77
|
"@testing-library/jest-dom": "^7.0.1",
|
|
67
78
|
"@testing-library/react": "^16.3.2",
|
|
@@ -75,9 +86,9 @@
|
|
|
75
86
|
"vitest": "^4.1.10"
|
|
76
87
|
},
|
|
77
88
|
"dependencies": {
|
|
78
|
-
"@deepseek-ai/dsh-llm": "0.1.5-rc.
|
|
79
|
-
"@deepseek-ai/dsh-session": "0.1.5-rc.
|
|
80
|
-
"@deepseek-ai/dsh-session-projection": "0.1.5-rc.
|
|
89
|
+
"@deepseek-ai/dsh-llm": "0.1.5-rc.2",
|
|
90
|
+
"@deepseek-ai/dsh-session": "0.1.5-rc.2",
|
|
91
|
+
"@deepseek-ai/dsh-session-projection": "0.1.5-rc.2",
|
|
81
92
|
"zod": "^4.5.4"
|
|
82
93
|
}
|
|
83
94
|
}
|