relay-dsh-plugin-claude 0.1.5 → 0.2.0
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 +18 -1
- package/README.zh.md +18 -1
- package/docs/dsh-0.1.2-alpha.2.md +34 -0
- package/dsh-client-compat.d.mts +4 -0
- package/dsh-client-compat.mjs +26 -0
- package/dsh-compat.mjs +9 -0
- package/lib/client.js +70 -19
- package/lib/client.js.map +1 -1
- package/lib/host-plugin.js +12 -4
- package/lib/host-plugin.js.map +1 -1
- package/package.json +106 -19
package/README.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# Claude Code Conversations for DeepSeek Harness
|
|
2
2
|
|
|
3
|
+
> **Now supports the latest DSH `0.1.2-alpha.2`.** The same plugin release is verified on DSH `0.1.2-alpha.2` and `0.1.1-rc.2`. [Install it and try the latest DSH](https://www.npmjs.com/package/relay-dsh-plugin-claude) · [Compatibility details](docs/dsh-0.1.2-alpha.2.md).
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add relay-dsh-plugin-claude@0.2.0
|
|
7
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 web
|
|
8
|
+
```
|
|
9
|
+
|
|
3
10
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude)
|
|
4
11
|
[](https://github.com/yangbobo2021/relay-dsh-plugin-claude/actions/workflows/ci.yml)
|
|
5
12
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude)
|
|
6
13
|
[](https://github.com/yangbobo2021/relay-dsh-plugin-claude/stargazers)
|
|
7
14
|
[](LICENSE)
|
|
8
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
15
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
9
16
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude/v/0.1.5)
|
|
10
17
|
|
|
11
18
|
English | [中文](README.zh.md)
|
|
@@ -349,3 +356,13 @@ tests reject accidental runtime dependencies on Relay or another feature plugin.
|
|
|
349
356
|
|
|
350
357
|
Report bugs and feature requests in this repository's
|
|
351
358
|
[issue tracker](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues).
|
|
359
|
+
|
|
360
|
+
### New candidate installation (available only after publication)
|
|
361
|
+
|
|
362
|
+
The same candidate targets DSH `0.1.1-rc.2` and `0.1.2-alpha.2`; this version and Git tag are not published yet.
|
|
363
|
+
|
|
364
|
+
```sh
|
|
365
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add relay-dsh-plugin-claude@next
|
|
366
|
+
# Git tag alternative, after publication:
|
|
367
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add github:yangbobo2021/relay-dsh-plugin-claude#v0.2.0
|
|
368
|
+
```
|
package/README.zh.md
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
# 在 DeepSeek Harness 中使用 Claude Code 对话
|
|
2
2
|
|
|
3
|
+
> **现已支持最新 DSH `0.1.2-alpha.2`。** 同一插件版本已在 DSH `0.1.2-alpha.2` 与 `0.1.1-rc.2` 上完成兼容验证。[安装插件,立即体验最新版 DSH](https://www.npmjs.com/package/relay-dsh-plugin-claude) · [兼容性详情](docs/dsh-0.1.2-alpha.2.md)。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add relay-dsh-plugin-claude@0.2.0
|
|
7
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 web
|
|
8
|
+
```
|
|
9
|
+
|
|
3
10
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude)
|
|
4
11
|
[](https://github.com/yangbobo2021/relay-dsh-plugin-claude/actions/workflows/ci.yml)
|
|
5
12
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude)
|
|
6
13
|
[](https://github.com/yangbobo2021/relay-dsh-plugin-claude/stargazers)
|
|
7
14
|
[](LICENSE)
|
|
8
|
-
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
15
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
9
16
|
[](https://www.npmjs.com/package/relay-dsh-plugin-claude/v/0.1.5)
|
|
10
17
|
|
|
11
18
|
[English](README.md) | 中文
|
|
@@ -319,3 +326,13 @@ npm pack
|
|
|
319
326
|
请通过本仓库的
|
|
320
327
|
[Issue Tracker](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues)
|
|
321
328
|
报告错误或提出功能建议。
|
|
329
|
+
|
|
330
|
+
### 新候选版安装(发布后才可用)
|
|
331
|
+
|
|
332
|
+
同一候选面向 DSH `0.1.1-rc.2` 和 `0.1.2-alpha.2`;此版本和 Git Tag 目前尚未发布。
|
|
333
|
+
|
|
334
|
+
```sh
|
|
335
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add relay-dsh-plugin-claude@next
|
|
336
|
+
# Git tag alternative, after publication:
|
|
337
|
+
npx @deepseek-ai/dsh@0.1.2-alpha.2 plugin --profile web add github:yangbobo2021/relay-dsh-plugin-claude#v0.2.0
|
|
338
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# DSH 双版本兼容
|
|
2
|
+
|
|
3
|
+
同一个 `0.2.0` 稳定包的兼容目标:
|
|
4
|
+
|
|
5
|
+
| DSH | 官方提交 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `0.1.1-rc.2` | `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e` |
|
|
8
|
+
| `0.1.2-alpha.2` | `0a53fb55bea101816fa226bb964ae2bed71c343b` |
|
|
9
|
+
|
|
10
|
+
不按 DSH 版本分别发包;不要求旧用户先升级管理器。没有自定义精确版本白名单。
|
|
11
|
+
DSH 可选 peer 使用版本范围表达声明,不把它当成旧宿主必然执行的安装拦截。
|
|
12
|
+
稳定版通过 npm `latest` 发布;候选版 `0.2.0-rc.1` 保留在 `next` 通道。
|
|
13
|
+
|
|
14
|
+
## 本插件变更
|
|
15
|
+
|
|
16
|
+
导入历史的工具调用 ID 兼容两种 Host 导出;前端事件服务及会话预设读取兼容两种接口;模型切换保持取消和过期结果隔离。真实 Claude 图片识别与 fork 上下文继承按用户要求暂缓,没有标为通过。
|
|
17
|
+
|
|
18
|
+
## 验收方式与边界
|
|
19
|
+
|
|
20
|
+
开发类型检查及构建使用准备好的官方 `0.1.2-alpha.2` 源码。构建一次后,将相同 tarball
|
|
21
|
+
分别安装到两版官方 DSH 的独立临时 profile,检查 Host 启动、浏览器装配、功能注册及
|
|
22
|
+
适用的受控功能;不修改官方源码或日常运行环境。
|
|
23
|
+
跨插件结果在 Relay 的 `dsh-lab/dual-compatibility-20260831/` 中记录;插件独立测试命令:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npm ci --ignore-scripts
|
|
27
|
+
# 非管理器插件需要准备好的官方 DSH 源码;管理器使用锁定的 npm 开发依赖。
|
|
28
|
+
export DSH_ROOT=/path/to/prepared/official/deepseek-harness
|
|
29
|
+
npm run verify
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
两版核心回归不等于所有外部服务、平台或未来 DSH 版本均已验证。
|
|
33
|
+
Claude 真实识图/fork 仍暂缓;Codex Default 模式原生提问限制、Workbench 刷新后尺寸不保留
|
|
34
|
+
均不在本次兼容修复中关闭。所有公开 npm/GitHub 发布后的完整升级路径也需要发布后再验收。
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis'
|
|
2
|
+
import type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'
|
|
3
|
+
export function sessionPreset(session: { agentPreset?: string | null; projectionValues?: { agentPreset?: string | null } } | undefined): string | null | undefined
|
|
4
|
+
export function modelDirectory(ctx: unknown, sessionId: string): Pick<ReturnType<Context['modelDirectories']['directoryFor']>, 'load' | 'select'>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Public interface adapters shared by both supported DSH generations.
|
|
2
|
+
export function sessionPreset(session) {
|
|
3
|
+
if (session?.projectionValues && Object.hasOwn(session.projectionValues, 'agentPreset')) {
|
|
4
|
+
return session.projectionValues.agentPreset;
|
|
5
|
+
}
|
|
6
|
+
return session?.agentPreset;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const service = (ctx, name) => typeof ctx.get === 'function' ? ctx.get(name) : ctx[name];
|
|
10
|
+
export function modelDirectory(ctx, sessionId) {
|
|
11
|
+
const directories = service(ctx, 'modelDirectories');
|
|
12
|
+
if (directories) return directories.directoryFor(sessionId);
|
|
13
|
+
const sessions = service(ctx, 'connection')?.api?.sessions;
|
|
14
|
+
if (!sessions) throw new Error('DSH model selection interface is unavailable');
|
|
15
|
+
return {
|
|
16
|
+
async load() {
|
|
17
|
+
const response = await sessions.models({ sessionId });
|
|
18
|
+
if (!response.result.ok) throw new Error('DSH model discovery failed');
|
|
19
|
+
return response.result.value;
|
|
20
|
+
},
|
|
21
|
+
async select(selection) {
|
|
22
|
+
const response = await sessions.selectModel({ sessionId, ...selection });
|
|
23
|
+
if (!response.result.ok) throw new Error('DSH model selection failed');
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
package/dsh-compat.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as llm from '@deepseek-ai/dsh-llm';
|
|
2
|
+
|
|
3
|
+
// Keep namespace access: a named import fails before this adapter can run on
|
|
4
|
+
// the other official DSH generation. Both constructors have the same contract.
|
|
5
|
+
export function toolCallId(value) {
|
|
6
|
+
const create = Reflect.get(llm, 'ToolCallId') ?? Reflect.get(llm, 'CallId');
|
|
7
|
+
if (typeof create !== 'function') throw new Error('DSH does not provide a tool call ID constructor');
|
|
8
|
+
return create(value);
|
|
9
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -7,12 +7,39 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
9
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
//#region dsh-client-compat.mjs
|
|
11
|
+
function sessionPreset(session) {
|
|
12
|
+
if (session?.projectionValues && Object.hasOwn(session.projectionValues, "agentPreset")) return session.projectionValues.agentPreset;
|
|
13
|
+
return session?.agentPreset;
|
|
14
|
+
}
|
|
15
|
+
const service = (ctx, name) => typeof ctx.get === "function" ? ctx.get(name) : ctx[name];
|
|
16
|
+
function modelDirectory(ctx, sessionId) {
|
|
17
|
+
const directories = service(ctx, "modelDirectories");
|
|
18
|
+
if (directories) return directories.directoryFor(sessionId);
|
|
19
|
+
const sessions = service(ctx, "connection")?.api?.sessions;
|
|
20
|
+
if (!sessions) throw new Error("DSH model selection interface is unavailable");
|
|
21
|
+
return {
|
|
22
|
+
async load() {
|
|
23
|
+
const response = await sessions.models({ sessionId });
|
|
24
|
+
if (!response.result.ok) throw new Error("DSH model discovery failed");
|
|
25
|
+
return response.result.value;
|
|
26
|
+
},
|
|
27
|
+
async select(selection) {
|
|
28
|
+
if (!(await sessions.selectModel({
|
|
29
|
+
sessionId,
|
|
30
|
+
...selection
|
|
31
|
+
})).result.ok) throw new Error("DSH model selection failed");
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
10
36
|
//#region model-selection.mjs
|
|
11
37
|
function installModelSelection(ctx, preset, provider, otherProvider) {
|
|
12
|
-
|
|
38
|
+
let stopped = false;
|
|
13
39
|
const selecting = /* @__PURE__ */ new Set();
|
|
14
40
|
const pending = /* @__PURE__ */ new Set();
|
|
15
41
|
const sync = () => {
|
|
42
|
+
if (stopped) return;
|
|
16
43
|
const list = ctx.sessions.list.getSnapshot();
|
|
17
44
|
const id = list.current;
|
|
18
45
|
if (id === void 0 || list.byId[id]?.blank !== true) return;
|
|
@@ -20,34 +47,38 @@ window.__ModuleLoader__.load({
|
|
|
20
47
|
pending.add(id);
|
|
21
48
|
return;
|
|
22
49
|
}
|
|
23
|
-
const selectedPreset = list.byId[id]
|
|
50
|
+
const selectedPreset = sessionPreset(list.byId[id]);
|
|
24
51
|
if (selectedPreset !== preset && selectedPreset === otherProvider) return;
|
|
25
52
|
selecting.add(id);
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
53
|
+
(async () => {
|
|
54
|
+
const directory = modelDirectory(ctx, id);
|
|
55
|
+
const models = await directory.load();
|
|
56
|
+
if (stopped || !models.current) return;
|
|
29
57
|
const latest = ctx.sessions.list.getSnapshot().byId[id];
|
|
30
|
-
if (latest?.blank !== true || latest
|
|
58
|
+
if (ctx.sessions.list.getSnapshot().current !== id || latest?.blank !== true || sessionPreset(latest) !== selectedPreset) {
|
|
31
59
|
pending.add(id);
|
|
32
60
|
return;
|
|
33
61
|
}
|
|
34
|
-
|
|
62
|
+
if (selectedPreset === preset && models.current.provider === provider) return;
|
|
63
|
+
const target = selectedPreset === preset ? models.groups.find((group) => group.id === provider) : models.current.provider === provider ? models.groups.find((group) => group.id !== provider && group.id !== otherProvider) : void 0;
|
|
35
64
|
const model = target?.models[0];
|
|
36
65
|
if (!target || !model) return;
|
|
37
|
-
await
|
|
38
|
-
sessionId: id,
|
|
66
|
+
await directory.select({
|
|
39
67
|
provider: target.id,
|
|
40
68
|
model: model.id,
|
|
41
69
|
...model.reasoning?.defaultEffort ? { reasoningEffort: model.reasoning.defaultEffort } : {}
|
|
42
70
|
});
|
|
43
|
-
}).catch(() => {}).finally(() => {
|
|
71
|
+
})().catch(() => {}).finally(() => {
|
|
44
72
|
selecting.delete(id);
|
|
45
73
|
if (pending.delete(id)) sync();
|
|
46
74
|
});
|
|
47
75
|
};
|
|
48
76
|
const off = ctx.sessions.list.subscribe(sync);
|
|
49
77
|
sync();
|
|
50
|
-
return
|
|
78
|
+
return () => {
|
|
79
|
+
stopped = true;
|
|
80
|
+
off();
|
|
81
|
+
};
|
|
51
82
|
}
|
|
52
83
|
//#endregion
|
|
53
84
|
//#region claude-import-contract.mjs
|
|
@@ -760,6 +791,25 @@ window.__ModuleLoader__.load({
|
|
|
760
791
|
retry: "重试"
|
|
761
792
|
};
|
|
762
793
|
//#endregion
|
|
794
|
+
//#region src/client/compatible-runtime.ts
|
|
795
|
+
function conversationEvents(ctx) {
|
|
796
|
+
const events = ctx.get("uiConversation")?.events ?? ctx.get("conversationEvents");
|
|
797
|
+
if (!events) throw new Error("DSH conversation events service is unavailable");
|
|
798
|
+
return events;
|
|
799
|
+
}
|
|
800
|
+
/** Bind setup and disposal to the service family actually present in this DSH. */
|
|
801
|
+
function withConversationRuntime(ctx, setup) {
|
|
802
|
+
const current = ctx.inject(["uiConversation", "modelDirectories"], (inner) => setup(inner));
|
|
803
|
+
const legacy = ctx.inject(["conversationEvents"], (inner) => {
|
|
804
|
+
if (inner.get("uiConversation")) return;
|
|
805
|
+
return setup(inner);
|
|
806
|
+
});
|
|
807
|
+
return () => {
|
|
808
|
+
current.dispose();
|
|
809
|
+
legacy.dispose();
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
//#endregion
|
|
763
813
|
//#region src/client/index.ts
|
|
764
814
|
const inject = [
|
|
765
815
|
"slots",
|
|
@@ -768,21 +818,22 @@ window.__ModuleLoader__.load({
|
|
|
768
818
|
"remote",
|
|
769
819
|
"sessions",
|
|
770
820
|
"workspaces",
|
|
771
|
-
"connection"
|
|
772
|
-
"conversationEvents"
|
|
821
|
+
"connection"
|
|
773
822
|
];
|
|
774
823
|
async function apply(ctx) {
|
|
775
824
|
ctx.effect(() => ctx.locale.register("relay.claude", {
|
|
776
825
|
zh,
|
|
777
826
|
en
|
|
778
827
|
}), "relay-claude: dictionaries");
|
|
779
|
-
ctx.conversationEvents.register(claudeActivityDefinition);
|
|
780
|
-
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
781
|
-
name: "conversation.chat.node",
|
|
782
|
-
key: "relay-claude-activity"
|
|
783
|
-
}, ClaudeActivityView));
|
|
784
828
|
applySessionImport(ctx);
|
|
785
|
-
const unsubscribe =
|
|
829
|
+
const unsubscribe = withConversationRuntime(ctx, (inner) => {
|
|
830
|
+
conversationEvents(inner).register(claudeActivityDefinition);
|
|
831
|
+
inner.slots.inject("conversation.chat.node", () => inner.slots.register({
|
|
832
|
+
name: "conversation.chat.node",
|
|
833
|
+
key: "relay-claude-activity"
|
|
834
|
+
}, ClaudeActivityView));
|
|
835
|
+
return installModelSelection(inner, "relay-claude", "relay-claude", "relay-codex");
|
|
836
|
+
});
|
|
786
837
|
return async () => {
|
|
787
838
|
unsubscribe();
|
|
788
839
|
};
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["IconSparkle16","Modal","css","Button","css","DisclosureRow","IconCodeOutline16","StateDot"],"sources":["../model-selection.mjs","../claude-import-contract.mjs","../src/client/claude-session-import-client.mjs","../src/client/claude-session-import-ui-policy.mjs","../src/client/ClaudeSessionImportAction.tsx","../src/client/ClaudeActivityView.tsx","../src/client/claude-activity.ts","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["export function installModelSelection(ctx, preset, provider, otherProvider) {\n const connection = ctx.get(\"connection\");\n const selecting = new Set();\n const pending = new Set();\n\n const sync = () => {\n const list = ctx.sessions.list.getSnapshot();\n const id = list.current;\n if (id === undefined || list.byId[id]?.blank !== true) return;\n if (selecting.has(id)) {\n pending.add(id);\n return;\n }\n\n const selectedPreset = list.byId[id]?.agentPreset;\n if (selectedPreset !== preset && selectedPreset === otherProvider) return;\n selecting.add(id);\n void connection.api.sessions.models({ sessionId: id }).then(async (response) => {\n const { result } = response;\n if (!result.ok) return;\n const latest = ctx.sessions.list.getSnapshot().byId[id];\n if (latest?.blank !== true || latest.agentPreset !== selectedPreset) {\n pending.add(id);\n return;\n }\n const target = selectedPreset === preset\n ? result.value.groups.find((group) => group.id === provider)\n : result.value.current.provider === provider\n ? result.value.groups.find((group) => group.id !== provider && group.id !== otherProvider)\n : undefined;\n const model = target?.models[0];\n if (!target || !model) return;\n await connection.api.sessions.selectModel({\n sessionId: id,\n provider: target.id,\n model: model.id,\n ...(model.reasoning?.defaultEffort\n ? { reasoningEffort: model.reasoning.defaultEffort }\n : {}),\n });\n }).catch(() => {}).finally(() => {\n selecting.delete(id);\n if (pending.delete(id)) sync();\n });\n };\n\n const off = ctx.sessions.list.subscribe(sync);\n sync();\n return off;\n}\n","export const CLAUDE_IMPORT_PATH = \"/api/relay/claude/import\";\n","import { CLAUDE_IMPORT_PATH } from \"../../claude-import-contract.mjs\";\n\nexport function resolveImportWorkspace(workspaces, sessions) {\n const current = sessions?.current;\n if (current !== undefined) {\n const owner = workspaces?.items?.find(workspace => workspace.sessionIds?.includes(current));\n if (owner) return owner;\n }\n const recent = workspaces?.recentWorkspaceId;\n return workspaces?.items?.find(workspace => workspace.workspaceId === recent) ?? null;\n}\n\nexport async function scanClaudeWorkspace(cwd, fetchImpl = fetch) {\n const response = await fetchImpl(CLAUDE_IMPORT_PATH, requestInit(\"scan\", cwd));\n const body = await readJsonResponse(response);\n if (!response.ok) throw new Error(body?.message ?? `Claude import scan failed with HTTP ${response.status}`);\n return body;\n}\n\nexport async function importClaudeWorkspace(cwd, { sessionIds, onProgress } = {}, fetchImpl = fetch) {\n const response = await fetchImpl(CLAUDE_IMPORT_PATH, requestInit(\"import\", cwd, sessionIds));\n if (!response.ok) {\n const body = await readJsonResponse(response);\n throw new Error(body?.message ?? `Claude import failed with HTTP ${response.status}`);\n }\n let completed = null;\n for await (const frame of ndjsonFrames(response.body)) {\n if (frame?.type === \"progress\") onProgress?.(frame);\n if (frame?.type === \"complete\") completed = frame.result;\n if (frame?.type === \"error\") throw new Error(frame.message ?? \"Claude import failed\");\n }\n if (completed === null) throw new Error(\"Claude import response ended before completion\");\n return completed;\n}\n\nexport async function refreshImportedWorkspace(sessions, workspaces) {\n await sessions.refresh();\n await workspaces.refresh();\n}\n\nexport async function* ndjsonFrames(body) {\n if (!body || typeof body.getReader !== \"function\") throw new Error(\"Claude import response has no readable body\");\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n while (true) {\n const { done, value } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (line) yield parseFrame(line);\n newline = buffer.indexOf(\"\\n\");\n }\n if (done) break;\n }\n const finalLine = buffer.trim();\n if (finalLine) yield parseFrame(finalLine);\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction requestInit(action, cwd, sessionIds) {\n return {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n action,\n cwd,\n ...(sessionIds === undefined ? {} : { sessionIds }),\n }),\n };\n}\n\nasync function readJsonResponse(response) {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\nfunction parseFrame(line) {\n try {\n return JSON.parse(line);\n } catch {\n throw new Error(\"Claude import returned malformed progress data\");\n }\n}\n","export function claudeSessionImportUiPolicy(phase, selected = 0, failed = 0, hasWorkspace = true) {\n if (phase === \"importing\") {\n return Object.freeze({ canClose: false, primary: \"importing\", primaryDisabled: true });\n }\n if (phase === \"summary\") {\n return Object.freeze({\n canClose: true,\n secondary: \"cancel\",\n primary: \"import-selected\",\n primaryDisabled: selected === 0,\n });\n }\n if (phase === \"select-workspace\") {\n return Object.freeze({\n canClose: true,\n secondary: \"cancel\",\n primary: \"scan\",\n primaryDisabled: !hasWorkspace,\n });\n }\n if (phase === \"error\") {\n return Object.freeze({ canClose: true, secondary: \"cancel\", primary: \"retry\", primaryDisabled: false });\n }\n if (phase === \"complete\" && failed > 0) {\n return Object.freeze({ canClose: true, secondary: \"close\", primary: \"retry\", primaryDisabled: false });\n }\n return Object.freeze({ canClose: true, primary: \"close\", primaryDisabled: false });\n}\n\nexport function claudeSessionImportUpdatedAtDate(value) {\n if (value === null || value === undefined) return null;\n const milliseconds = typeof value === \"number\" && Number.isFinite(value) && Math.abs(value) < 1e12\n ? value * 1000\n : value;\n const date = new Date(milliseconds);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n","import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport {\n Button,\n IconSparkle16,\n Modal,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n InjectFace,\n PropsLocale,\n} from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionImportProviderOwnerProps } from 'relay-dsh-plugin-session-import/contracts'\nimport { resolveImportWorkspace } from './claude-session-import-client.mjs'\nimport {\n claudeSessionImportUpdatedAtDate,\n claudeSessionImportUiPolicy,\n type ClaudeSessionImportUiAction,\n} from './claude-session-import-ui-policy.mjs'\nimport css from './ClaudeSessionImportAction.module.css'\n\ninterface WorkspaceView {\n workspaceId: string\n title: string\n path: string\n sessionIds: readonly string[]\n}\n\ninterface WorkspaceState {\n items: readonly WorkspaceView[]\n recentWorkspaceId?: string\n}\n\ninterface SessionState {\n current?: string\n}\n\ninterface Summary {\n found: number\n existing: number\n recoverable: number\n ready: number\n}\n\ninterface Candidate {\n id: string\n title: string\n cwd: string\n updatedAt: number | string | null\n status: 'ready' | 'recoverable'\n}\n\ninterface ImportResult {\n found: number\n imported: number\n existing: number\n failed: number\n failures: readonly { session: string; message: string }[]\n}\n\ninterface Progress extends ImportResult {\n completed: number\n total: number\n}\n\ninterface Observable<T> {\n getSnapshot: () => T\n subscribe: (listener: () => void) => () => void\n}\n\nexport interface ClaudeSessionImportInjected {\n hooks: {\n claudeSessionImportWorkspaces: Observable<WorkspaceState>\n claudeSessionImportSessions: Observable<SessionState>\n }\n scanWorkspace: (cwd: string) => Promise<{\n workspace: { title: string; path: string }\n summary: Summary\n candidates: readonly Candidate[]\n }>\n importWorkspace: (\n cwd: string,\n sessionIds: readonly string[],\n onProgress: (progress: Progress) => void,\n ) => Promise<ImportResult>\n refreshWorkspaceState: () => Promise<void>\n}\n\ntype Props = SessionImportProviderOwnerProps\n & InjectFace<ClaudeSessionImportInjected>\n & PropsLocale<'relay.claude'>\n\ntype Phase = 'idle' | 'no-workspace' | 'select-workspace' | 'scanning' | 'summary' | 'importing' | 'complete' | 'error'\n\nexport function ClaudeSessionImportProvider({\n registerProvider,\n useClaudeSessionImportWorkspaces,\n useClaudeSessionImportSessions,\n scanWorkspace,\n importWorkspace,\n refreshWorkspaceState,\n t,\n}: Props): ReactNode {\n const workspaces = useClaudeSessionImportWorkspaces(value => value)\n const sessions = useClaudeSessionImportSessions(value => value)\n const availableTarget = resolveImportWorkspace(workspaces, sessions) as WorkspaceView | null\n const [open, setOpen] = useState(false)\n const [target, setTarget] = useState<WorkspaceView | null>(null)\n const [phase, setPhase] = useState<Phase>('idle')\n const [summary, setSummary] = useState<Summary | null>(null)\n const [candidates, setCandidates] = useState<readonly Candidate[]>([])\n const [selectedIds, setSelectedIds] = useState<ReadonlySet<string>>(new Set())\n const [progress, setProgress] = useState<Progress | null>(null)\n const [result, setResult] = useState<ImportResult | null>(null)\n const [error, setError] = useState('')\n const request = useRef(0)\n\n const close = (): void => {\n if (!claudeSessionImportUiPolicy(phase, selectedIds.size, result?.failed).canClose) return\n request.current += 1\n setOpen(false)\n }\n\n const scan = (workspace: WorkspaceView): void => {\n const generation = ++request.current\n setPhase('scanning')\n setSummary(null)\n setCandidates([])\n setSelectedIds(new Set())\n setProgress(null)\n setResult(null)\n setError('')\n void scanWorkspace(workspace.path).then(\n response => {\n if (request.current !== generation) return\n setSummary(response.summary)\n setCandidates(response.candidates)\n setSelectedIds(new Set(response.candidates.map(candidate => candidate.id)))\n setPhase('summary')\n },\n reason => {\n if (request.current !== generation) return\n setError(messageOf(reason))\n setPhase('error')\n },\n )\n }\n\n const begin = useCallback((): void => {\n const selected = availableTarget ?? workspaces.items[0] ?? null\n setTarget(selected)\n setOpen(true)\n if (selected === null) {\n setPhase('no-workspace')\n return\n }\n setPhase('select-workspace')\n }, [availableTarget, workspaces.items])\n\n useEffect(() => registerProvider({\n id: 'claude',\n label: t('importAction'),\n icon: <IconSparkle16 size={16} />,\n order: 20,\n open: begin,\n }), [begin, registerProvider, t])\n\n const scanSelected = (): void => {\n if (target !== null) scan(target)\n }\n\n const importSelected = (): void => {\n const sessionIds = candidates\n .filter(candidate => selectedIds.has(candidate.id))\n .map(candidate => candidate.id)\n if (target === null || summary === null || sessionIds.length === 0 || phase === 'importing') return\n const generation = ++request.current\n setPhase('importing')\n setProgress({\n completed: 0,\n total: sessionIds.length,\n found: sessionIds.length,\n imported: 0,\n existing: 0,\n failed: 0,\n failures: [],\n })\n setError('')\n void (async () => {\n try {\n const completed = await importWorkspace(target.path, sessionIds, update => {\n if (request.current === generation) setProgress(update)\n })\n await refreshWorkspaceState()\n if (request.current !== generation) return\n setResult(completed)\n setPhase('complete')\n } catch (reason) {\n if (request.current !== generation) return\n setError(messageOf(reason))\n setPhase('error')\n }\n })()\n }\n\n const retry = (): void => {\n if (target !== null) scan(target)\n }\n\n return (\n <>\n <Modal\n open={open}\n onClose={close}\n title={t('importTitle')}\n closeLabel={t('close')}\n description={t('importDescription')}\n className={css.dialog}\n footer={modalFooter({\n phase,\n selectedCount: selectedIds.size,\n result,\n close,\n scanSelected,\n retry,\n importSelected,\n t,\n })}\n >\n <div className={css.body} aria-live=\"polite\">\n {phase === 'select-workspace' && target !== null && (\n <div className={css.workspaceChoice}>\n <label htmlFor=\"claude-import-workspace\">{t('importWorkspaceLabel')}</label>\n <select\n id=\"claude-import-workspace\"\n value={target.workspaceId}\n aria-describedby=\"claude-import-workspace-help\"\n onChange={event => {\n const selected = workspaces.items.find(workspace => workspace.workspaceId === event.currentTarget.value)\n if (selected !== undefined) setTarget(selected)\n }}\n >\n {workspaces.items.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n <span id=\"claude-import-workspace-help\" className={css.message}>{t('importChooseWorkspace')}</span>\n <span className={css.workspacePath} title={target.path}>{target.path}</span>\n </div>\n )}\n {target !== null && phase !== 'select-workspace' && (\n <div className={css.workspace}>\n <strong>{target.title}</strong>\n <span title={target.path}>{target.path}</span>\n </div>\n )}\n {phase === 'no-workspace' && <p className={css.message}>{t('importNoWorkspace')}</p>}\n {phase === 'scanning' && <p className={css.message}>{t('importScanning')}</p>}\n {phase === 'summary' && summary !== null && (\n <SummaryView\n summary={summary}\n candidates={candidates}\n selectedIds={selectedIds}\n onSelectionChange={setSelectedIds}\n t={t}\n />\n )}\n {phase === 'importing' && progress !== null && <ProgressView progress={progress} t={t} />}\n {phase === 'complete' && result !== null && <ResultView result={result} t={t} />}\n {phase === 'error' && <p className={css.error} role=\"alert\">{error || t('importFailed')}</p>}\n </div>\n </Modal>\n </>\n )\n}\n\nfunction SummaryView({\n summary,\n candidates,\n selectedIds,\n onSelectionChange,\n t,\n}: {\n summary: Summary\n candidates: readonly Candidate[]\n selectedIds: ReadonlySet<string>\n onSelectionChange: (selected: ReadonlySet<string>) => void\n t: Props['t']\n}): ReactNode {\n const select = (id: string, checked: boolean): void => {\n const next = new Set(selectedIds)\n if (checked) next.add(id)\n else next.delete(id)\n onSelectionChange(next)\n }\n return (\n <div className={css.summary}>\n <dl className={css.metrics}>\n <Metric label={t('importFound')} value={summary.found} />\n <Metric label={t('importExisting')} value={summary.existing} />\n <Metric label={t('importRecoverable')} value={summary.recoverable} />\n <Metric label={t('importReady')} value={summary.ready} accent />\n </dl>\n {candidates.length === 0 ? (\n <p className={css.message}>{t('importEmpty')}</p>\n ) : (\n <>\n <div className={css.selectionToolbar}>\n <span>{t('importSelected')}: {selectedIds.size} / {candidates.length}</span>\n <div>\n <button type=\"button\" onClick={() => onSelectionChange(new Set(candidates.map(candidate => candidate.id)))}>\n {t('importSelectAll')}\n </button>\n <button type=\"button\" onClick={() => onSelectionChange(new Set())}>\n {t('importClearSelection')}\n </button>\n </div>\n </div>\n <ul className={css.candidates} aria-label={t('importCandidates')}>\n {candidates.map(candidate => (\n <li key={candidate.id}>\n <label>\n <input\n type=\"checkbox\"\n checked={selectedIds.has(candidate.id)}\n onChange={event => select(candidate.id, event.currentTarget.checked)}\n />\n <span className={css.candidateBody}>\n <span className={css.candidateHeading}>\n <strong>{candidate.title}</strong>\n <span>{candidate.status === 'recoverable' ? t('importStatusRecoverable') : t('importStatusReady')}</span>\n </span>\n <code>{candidate.id}</code>\n <span title={candidate.cwd}>{candidate.cwd}</span>\n <time dateTime={dateTimeValue(candidate.updatedAt)}>{formatUpdatedAt(candidate.updatedAt)}</time>\n </span>\n </label>\n </li>\n ))}\n </ul>\n </>\n )}\n </div>\n )\n}\n\nfunction ProgressView({ progress, t }: { progress: Progress; t: Props['t'] }): ReactNode {\n const maximum = Math.max(1, progress.total)\n return (\n <div className={css.progress}>\n <div className={css.progressCopy}>\n <strong>{t('importImporting')}</strong>\n <span>{progress.completed} / {progress.total}</span>\n </div>\n <progress value={progress.completed} max={maximum} aria-label={t('importImporting')} />\n </div>\n )\n}\n\nfunction ResultView({ result, t }: { result: ImportResult; t: Props['t'] }): ReactNode {\n return (\n <div>\n <p className={result.failed > 0 ? css.partial : css.success}>\n {result.failed > 0 ? t('importPartial') : t('importComplete')}\n </p>\n <dl className={css.metrics}>\n <Metric label={t('importImported')} value={result.imported} accent />\n <Metric label={t('importExisting')} value={result.existing} />\n <Metric label={t('importFailures')} value={result.failed} danger={result.failed > 0} />\n </dl>\n {result.failures.length > 0 && (\n <ul className={css.failures} aria-label={t('importFailures')}>\n {result.failures.map(failure => (\n <li key={failure.session}>\n <code>{failure.session}</code>\n <span>{failure.message}</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )\n}\n\nfunction Metric({\n label, value, accent = false, danger = false,\n}: { label: string; value: number; accent?: boolean; danger?: boolean }): ReactNode {\n return (\n <div className={css.metric}>\n <dt>{label}</dt>\n <dd className={danger ? css.dangerValue : accent ? css.accentValue : undefined}>{value}</dd>\n </div>\n )\n}\n\nfunction modalFooter({\n phase, selectedCount, result, close, scanSelected, retry, importSelected, t,\n}: {\n phase: Phase\n selectedCount: number\n result: ImportResult | null\n close: () => void\n scanSelected: () => void\n retry: () => void\n importSelected: () => void\n t: Props['t']\n}): ReactNode {\n const policy = claudeSessionImportUiPolicy(phase, selectedCount, result?.failed, phase !== 'no-workspace')\n const actions: Record<ClaudeSessionImportUiAction, (() => void) | undefined> = {\n cancel: close,\n close,\n 'import-selected': importSelected,\n importing: undefined,\n retry,\n scan: scanSelected,\n }\n const labels: Record<ClaudeSessionImportUiAction, string> = {\n cancel: t('cancel'),\n close: t('close'),\n 'import-selected': t('importSelectedAction'),\n importing: t('importImporting'),\n retry: t('retry'),\n scan: t('importScanAction'),\n }\n return (\n <>\n {policy.secondary !== undefined && (\n <Button variant=\"outline\" onClick={actions[policy.secondary]}>\n {labels[policy.secondary]}\n </Button>\n )}\n <Button\n variant={policy.primary === 'close' ? 'outline' : undefined}\n disabled={policy.primaryDisabled}\n onClick={actions[policy.primary]}\n >\n {labels[policy.primary]}\n </Button>\n </>\n )\n}\n\nfunction dateTimeValue(value: Candidate['updatedAt']): string | undefined {\n const date = claudeSessionImportUpdatedAtDate(value)\n return date?.toISOString()\n}\n\nfunction formatUpdatedAt(value: Candidate['updatedAt']): string {\n const date = claudeSessionImportUpdatedAtDate(value)\n return date === null ? '-' : new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date)\n}\n\nfunction messageOf(reason: unknown): string {\n return reason instanceof Error ? reason.message : String(reason)\n}\n","import { memo, useState } from 'react'\nimport {\n DisclosureRow,\n IconCodeOutline16,\n StateDot,\n type StateDotState,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { ClaudeActivityData } from './claude-activity.ts'\nimport css from './ClaudeActivityView.module.css'\n\ntype ClaudeActivityViewProps = PropsRuntime<'conversation.chat.node', 'relay-claude-activity'>\n\nfunction dotState(status: ClaudeActivityData['status']): StateDotState {\n if (status === 'running') return 'ongoing'\n if (status === 'error') return 'error'\n return 'done'\n}\n\nexport const ClaudeActivityView = memo(function ClaudeActivityView({ node }: ClaudeActivityViewProps) {\n const activity = node.data as ClaudeActivityData\n const [open, setOpen] = useState(false)\n const expandable = activity.input !== undefined || activity.output !== undefined || activity.provenance !== undefined\n return (\n <div className={css.activity} data-claude-activity={activity.type}>\n <DisclosureRow\n icon={<IconCodeOutline16 />}\n title={activity.title}\n open={open}\n expandable={expandable}\n onToggle={() => { setOpen(value => !value) }}\n expandOnRowClick\n collapsedContent={(\n <span className={css.summary}>\n <span>{activity.summary}</span>\n <StateDot state={dotState(activity.status)} size={8} />\n </span>\n )}\n >\n <div className={css.detail}>\n {activity.provenance !== undefined ? (\n <div\n className={css.provenance}\n title={`Claude Code · Session ${activity.provenance.claudeSessionId} · Turn ${activity.provenance.turnId}`}\n >\n Claude Code · Session {shortId(activity.provenance.claudeSessionId)} · Turn {shortId(activity.provenance.turnId)}\n </div>\n ) : null}\n {activity.input !== undefined ? <pre>{activity.input}</pre> : null}\n {activity.output !== undefined ? <pre>{activity.output}</pre> : null}\n </div>\n </DisclosureRow>\n </div>\n )\n})\n\nfunction shortId(value: string): string {\n return value.length > 15 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value\n}\n","import type { ChatConversationViewNode, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client'\nimport type { SessionEventMap } from '@deepseek-ai/dsh-session/types'\n\ntype SessionEventContractAnchor = SessionEventMap\n\nexport type ClaudeActivityStatus = 'running' | 'completed' | 'error'\n\nexport interface ClaudeActivityData {\n readonly type: string\n readonly status: ClaudeActivityStatus\n readonly title: string\n readonly summary?: string\n readonly input?: string\n readonly output?: string\n readonly provenance?: {\n readonly claudeSessionId: string\n readonly turnId: string\n }\n}\n\nexport interface ClaudeActivityEventData {\n readonly version: 1\n readonly claudeSessionId: string\n readonly turnId: string\n readonly itemId: string\n readonly phase: 'started' | 'completed'\n readonly activity: ClaudeActivityData\n}\n\ndeclare module '@deepseek-ai/dsh-session/types' {\n interface SessionEventMap {\n 'relay-claude/activity': ClaudeActivityEventData\n }\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-conversation/client' {\n interface ChatNodeDataMap {\n 'relay-claude-activity': ClaudeActivityData\n }\n}\n\nexport const claudeActivityDefinition: ConversationNodeDefinition<ClaudeActivityData> = {\n kind: 'relay-claude-activity',\n target: 'chat',\n match: event => event.type === 'relay-claude/activity'\n ? { id: event.data.itemId, role: event.data.phase === 'started' ? 'start' : 'update' }\n : null,\n start: (_context, match) => {\n if (match.event.type !== 'relay-claude/activity') {\n throw new Error('Claude activity start requires relay-claude/activity')\n }\n return {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n },\n update: (context, match) => match.event.type === 'relay-claude/activity'\n ? {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n : context.state,\n buildViewNode: (context): ChatConversationViewNode | null => {\n if (context.start === undefined || context.state === undefined) return null\n return {\n key: context.key,\n kind: 'relay-claude-activity',\n id: context.id,\n target: 'chat',\n anchorSeq: context.start.event.seq,\n location: context.start.location,\n visibility: 'visible',\n data: context.state,\n }\n },\n}\n","export const en = {\n importAction: 'Import from Claude',\n importTitle: 'Import Claude Sessions',\n importDescription: 'Select existing Claude terminal Sessions from this Workspace to continue in DSH.',\n importWorkspaceLabel: 'Target Workspace',\n importChooseWorkspace: 'Choose the Workspace whose Sessions you want to scan and import.',\n importScanAction: 'Scan Sessions',\n importNoWorkspace: 'Open or select a Workspace before importing Sessions.',\n importScanning: 'Scanning native Claude Sessions...',\n importFound: 'Found',\n importExisting: 'Already linked',\n importRecoverable: 'Recoverable',\n importReady: 'Available',\n importEmpty: 'No unlinked Claude Sessions are available in this Workspace.',\n importSelected: 'Selected',\n importSelectAll: 'Select all',\n importClearSelection: 'Clear',\n importCandidates: 'Claude Session candidates',\n importStatusReady: 'Ready',\n importStatusRecoverable: 'Retry import',\n importSelectedAction: 'Import selected',\n importImporting: 'Importing Sessions...',\n importComplete: 'Import completed.',\n importPartial: 'Some Sessions could not be imported.',\n importImported: 'Imported',\n importFailures: 'Failed',\n importFailed: 'Claude Session import failed.',\n cancel: 'Cancel',\n close: 'Close',\n retry: 'Retry',\n} as const\n\nexport const zh: Record<keyof typeof en, string> = {\n importAction: '从 Claude 导入',\n importTitle: '导入 Claude 会话',\n importDescription: '选择当前工作区中已有的 Claude 终端会话,并在 DSH 中继续。',\n importWorkspaceLabel: '目标 Workspace',\n importChooseWorkspace: '选择要扫描和导入会话的 Workspace。',\n importScanAction: '扫描会话',\n importNoWorkspace: '请先打开或选择一个工作区。',\n importScanning: '正在扫描原生 Claude 会话...',\n importFound: '发现',\n importExisting: '已绑定',\n importRecoverable: '可恢复',\n importReady: '可导入',\n importEmpty: '当前工作区没有未绑定的 Claude 会话。',\n importSelected: '已选择',\n importSelectAll: '全选',\n importClearSelection: '清空',\n importCandidates: 'Claude 会话候选列表',\n importStatusReady: '可导入',\n importStatusRecoverable: '重试导入',\n importSelectedAction: '导入所选会话',\n importImporting: '正在导入会话...',\n importComplete: '导入完成。',\n importPartial: '部分会话未能导入。',\n importImported: '已导入',\n importFailures: '失败',\n importFailed: 'Claude 会话导入失败。',\n cancel: '取消',\n close: '关闭',\n retry: '重试',\n}\n\nexport type ClaudeLocaleKey = keyof typeof en\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type { ChatNodeOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { installModelSelection, type ModelSelectionContext } from '../../model-selection.mjs'\nimport { ClaudeSessionImportProvider, type ClaudeSessionImportInjected } from './ClaudeSessionImportAction.tsx'\nimport { ClaudeActivityView } from './ClaudeActivityView.tsx'\nimport { claudeActivityDefinition } from './claude-activity.ts'\nimport { en, zh, type ClaudeLocaleKey } from './locales.ts'\nimport {\n importClaudeWorkspace,\n refreshImportedWorkspace,\n scanClaudeWorkspace,\n} from './claude-session-import-client.mjs'\nimport type { SessionImportProviderSlotDefinition } from 'relay-dsh-plugin-session-import/contracts'\n\ntype DshSlotContractAnchor = ChatNodeOwnerProps\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n 'relay.session-import.provider': SessionImportProviderSlotDefinition\n }\n interface LocaleNamespaceMap {\n 'relay.claude': ClaudeLocaleKey\n }\n}\n\nexport const inject = ['slots', 'theme', 'locale', 'remote', 'sessions', 'workspaces', 'connection', 'conversationEvents']\n\nexport async function apply(ctx: ClientContext): Promise<() => Promise<void>> {\n ctx.effect(() => ctx.locale.register('relay.claude', { zh, en }), 'relay-claude: dictionaries')\n ctx.conversationEvents.register(claudeActivityDefinition)\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\n name: 'conversation.chat.node', key: 'relay-claude-activity',\n }, ClaudeActivityView))\n applySessionImport(ctx)\n const unsubscribe = installModelSelection(ctx as ModelSelectionContext, 'relay-claude', 'relay-claude', 'relay-codex')\n return async () => { unsubscribe() }\n}\n\nfunction applySessionImport(ctx: ClientContext): void {\n const injected = (): ClaudeSessionImportInjected => ({\n hooks: {\n claudeSessionImportWorkspaces: ctx.workspaces.list,\n claudeSessionImportSessions: ctx.sessions.list,\n },\n scanWorkspace: cwd => scanClaudeWorkspace(cwd),\n importWorkspace: (cwd, sessionIds, onProgress) => importClaudeWorkspace(cwd, { sessionIds, onProgress }),\n refreshWorkspaceState: () => refreshImportedWorkspace(\n ctx.sessions as typeof ctx.sessions & { refresh(): Promise<void> },\n ctx.workspaces as typeof ctx.workspaces & { refresh(): Promise<void> },\n ),\n })\n ctx.slots.inject('relay.session-import.provider', () => ctx.slots.register({\n name: 'relay.session-import.provider',\n id: 'claude',\n order: 20,\n inject: injected,\n locale: 'relay.claude',\n }, ClaudeSessionImportProvider))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["IconSparkle16","Modal","css","Button","css","DisclosureRow","IconCodeOutline16","StateDot"],"sources":["../dsh-client-compat.mjs","../model-selection.mjs","../claude-import-contract.mjs","../src/client/claude-session-import-client.mjs","../src/client/claude-session-import-ui-policy.mjs","../src/client/ClaudeSessionImportAction.tsx","../src/client/ClaudeActivityView.tsx","../src/client/claude-activity.ts","../src/client/locales.ts","../src/client/compatible-runtime.ts","../src/client/index.ts"],"sourcesContent":["// Public interface adapters shared by both supported DSH generations.\nexport function sessionPreset(session) {\n if (session?.projectionValues && Object.hasOwn(session.projectionValues, 'agentPreset')) {\n return session.projectionValues.agentPreset;\n }\n return session?.agentPreset;\n}\n\nconst service = (ctx, name) => typeof ctx.get === 'function' ? ctx.get(name) : ctx[name];\nexport function modelDirectory(ctx, sessionId) {\n const directories = service(ctx, 'modelDirectories');\n if (directories) return directories.directoryFor(sessionId);\n const sessions = service(ctx, 'connection')?.api?.sessions;\n if (!sessions) throw new Error('DSH model selection interface is unavailable');\n return {\n async load() {\n const response = await sessions.models({ sessionId });\n if (!response.result.ok) throw new Error('DSH model discovery failed');\n return response.result.value;\n },\n async select(selection) {\n const response = await sessions.selectModel({ sessionId, ...selection });\n if (!response.result.ok) throw new Error('DSH model selection failed');\n },\n };\n}\n","import { sessionPreset, modelDirectory } from \"./dsh-client-compat.mjs\";\nexport function installModelSelection(ctx, preset, provider, otherProvider) {\n let stopped = false;\n const selecting = new Set();\n const pending = new Set();\n\n const sync = () => {\n if (stopped) return;\n const list = ctx.sessions.list.getSnapshot();\n const id = list.current;\n if (id === undefined || list.byId[id]?.blank !== true) return;\n if (selecting.has(id)) {\n pending.add(id);\n return;\n }\n\n const selectedPreset = sessionPreset(list.byId[id]);\n if (selectedPreset !== preset && selectedPreset === otherProvider) return;\n selecting.add(id);\n void (async () => {\n const directory = modelDirectory(ctx, id);\n const models = await directory.load();\n if (stopped || !models.current) return;\n const latest = ctx.sessions.list.getSnapshot().byId[id];\n if (ctx.sessions.list.getSnapshot().current !== id || latest?.blank !== true || sessionPreset(latest) !== selectedPreset) {\n pending.add(id);\n return;\n }\n // Model projection changes also update the Session list in alpha.2.\n // Do not reset a chosen model or select again on our own projection update.\n if (selectedPreset === preset && models.current.provider === provider) return;\n const target = selectedPreset === preset\n ? models.groups.find((group) => group.id === provider)\n : models.current.provider === provider\n ? models.groups.find((group) => group.id !== provider && group.id !== otherProvider)\n : undefined;\n const model = target?.models[0];\n if (!target || !model) return;\n await directory.select({\n provider: target.id,\n model: model.id,\n ...(model.reasoning?.defaultEffort\n ? { reasoningEffort: model.reasoning.defaultEffort }\n : {}),\n });\n })().catch(() => {}).finally(() => {\n selecting.delete(id);\n if (pending.delete(id)) sync();\n });\n };\n\n const off = ctx.sessions.list.subscribe(sync);\n sync();\n return () => { stopped = true; off(); };\n}\n","export const CLAUDE_IMPORT_PATH = \"/api/relay/claude/import\";\n","import { CLAUDE_IMPORT_PATH } from \"../../claude-import-contract.mjs\";\n\nexport function resolveImportWorkspace(workspaces, sessions) {\n const current = sessions?.current;\n if (current !== undefined) {\n const owner = workspaces?.items?.find(workspace => workspace.sessionIds?.includes(current));\n if (owner) return owner;\n }\n const recent = workspaces?.recentWorkspaceId;\n return workspaces?.items?.find(workspace => workspace.workspaceId === recent) ?? null;\n}\n\nexport async function scanClaudeWorkspace(cwd, fetchImpl = fetch) {\n const response = await fetchImpl(CLAUDE_IMPORT_PATH, requestInit(\"scan\", cwd));\n const body = await readJsonResponse(response);\n if (!response.ok) throw new Error(body?.message ?? `Claude import scan failed with HTTP ${response.status}`);\n return body;\n}\n\nexport async function importClaudeWorkspace(cwd, { sessionIds, onProgress } = {}, fetchImpl = fetch) {\n const response = await fetchImpl(CLAUDE_IMPORT_PATH, requestInit(\"import\", cwd, sessionIds));\n if (!response.ok) {\n const body = await readJsonResponse(response);\n throw new Error(body?.message ?? `Claude import failed with HTTP ${response.status}`);\n }\n let completed = null;\n for await (const frame of ndjsonFrames(response.body)) {\n if (frame?.type === \"progress\") onProgress?.(frame);\n if (frame?.type === \"complete\") completed = frame.result;\n if (frame?.type === \"error\") throw new Error(frame.message ?? \"Claude import failed\");\n }\n if (completed === null) throw new Error(\"Claude import response ended before completion\");\n return completed;\n}\n\nexport async function refreshImportedWorkspace(sessions, workspaces) {\n await sessions.refresh();\n await workspaces.refresh();\n}\n\nexport async function* ndjsonFrames(body) {\n if (!body || typeof body.getReader !== \"function\") throw new Error(\"Claude import response has no readable body\");\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n while (true) {\n const { done, value } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n let newline = buffer.indexOf(\"\\n\");\n while (newline !== -1) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (line) yield parseFrame(line);\n newline = buffer.indexOf(\"\\n\");\n }\n if (done) break;\n }\n const finalLine = buffer.trim();\n if (finalLine) yield parseFrame(finalLine);\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction requestInit(action, cwd, sessionIds) {\n return {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n action,\n cwd,\n ...(sessionIds === undefined ? {} : { sessionIds }),\n }),\n };\n}\n\nasync function readJsonResponse(response) {\n try {\n return await response.json();\n } catch {\n return null;\n }\n}\n\nfunction parseFrame(line) {\n try {\n return JSON.parse(line);\n } catch {\n throw new Error(\"Claude import returned malformed progress data\");\n }\n}\n","export function claudeSessionImportUiPolicy(phase, selected = 0, failed = 0, hasWorkspace = true) {\n if (phase === \"importing\") {\n return Object.freeze({ canClose: false, primary: \"importing\", primaryDisabled: true });\n }\n if (phase === \"summary\") {\n return Object.freeze({\n canClose: true,\n secondary: \"cancel\",\n primary: \"import-selected\",\n primaryDisabled: selected === 0,\n });\n }\n if (phase === \"select-workspace\") {\n return Object.freeze({\n canClose: true,\n secondary: \"cancel\",\n primary: \"scan\",\n primaryDisabled: !hasWorkspace,\n });\n }\n if (phase === \"error\") {\n return Object.freeze({ canClose: true, secondary: \"cancel\", primary: \"retry\", primaryDisabled: false });\n }\n if (phase === \"complete\" && failed > 0) {\n return Object.freeze({ canClose: true, secondary: \"close\", primary: \"retry\", primaryDisabled: false });\n }\n return Object.freeze({ canClose: true, primary: \"close\", primaryDisabled: false });\n}\n\nexport function claudeSessionImportUpdatedAtDate(value) {\n if (value === null || value === undefined) return null;\n const milliseconds = typeof value === \"number\" && Number.isFinite(value) && Math.abs(value) < 1e12\n ? value * 1000\n : value;\n const date = new Date(milliseconds);\n return Number.isNaN(date.getTime()) ? null : date;\n}\n","import { useCallback, useEffect, useRef, useState, type ReactNode } from 'react'\nimport {\n Button,\n IconSparkle16,\n Modal,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type {\n InjectFace,\n PropsLocale,\n} from '@deepseek-ai/dsh-client-ui-slots'\nimport type { SessionImportProviderOwnerProps } from 'relay-dsh-plugin-session-import/contracts'\nimport { resolveImportWorkspace } from './claude-session-import-client.mjs'\nimport {\n claudeSessionImportUpdatedAtDate,\n claudeSessionImportUiPolicy,\n type ClaudeSessionImportUiAction,\n} from './claude-session-import-ui-policy.mjs'\nimport css from './ClaudeSessionImportAction.module.css'\n\ninterface WorkspaceView {\n workspaceId: string\n title: string\n path: string\n sessionIds: readonly string[]\n}\n\ninterface WorkspaceState {\n items: readonly WorkspaceView[]\n recentWorkspaceId?: string\n}\n\ninterface SessionState {\n current?: string\n}\n\ninterface Summary {\n found: number\n existing: number\n recoverable: number\n ready: number\n}\n\ninterface Candidate {\n id: string\n title: string\n cwd: string\n updatedAt: number | string | null\n status: 'ready' | 'recoverable'\n}\n\ninterface ImportResult {\n found: number\n imported: number\n existing: number\n failed: number\n failures: readonly { session: string; message: string }[]\n}\n\ninterface Progress extends ImportResult {\n completed: number\n total: number\n}\n\ninterface Observable<T> {\n getSnapshot: () => T\n subscribe: (listener: () => void) => () => void\n}\n\nexport interface ClaudeSessionImportInjected {\n hooks: {\n claudeSessionImportWorkspaces: Observable<WorkspaceState>\n claudeSessionImportSessions: Observable<SessionState>\n }\n scanWorkspace: (cwd: string) => Promise<{\n workspace: { title: string; path: string }\n summary: Summary\n candidates: readonly Candidate[]\n }>\n importWorkspace: (\n cwd: string,\n sessionIds: readonly string[],\n onProgress: (progress: Progress) => void,\n ) => Promise<ImportResult>\n refreshWorkspaceState: () => Promise<void>\n}\n\ntype Props = SessionImportProviderOwnerProps\n & InjectFace<ClaudeSessionImportInjected>\n & PropsLocale<'relay.claude'>\n\ntype Phase = 'idle' | 'no-workspace' | 'select-workspace' | 'scanning' | 'summary' | 'importing' | 'complete' | 'error'\n\nexport function ClaudeSessionImportProvider({\n registerProvider,\n useClaudeSessionImportWorkspaces,\n useClaudeSessionImportSessions,\n scanWorkspace,\n importWorkspace,\n refreshWorkspaceState,\n t,\n}: Props): ReactNode {\n const workspaces = useClaudeSessionImportWorkspaces(value => value)\n const sessions = useClaudeSessionImportSessions(value => value)\n const availableTarget = resolveImportWorkspace(workspaces, sessions) as WorkspaceView | null\n const [open, setOpen] = useState(false)\n const [target, setTarget] = useState<WorkspaceView | null>(null)\n const [phase, setPhase] = useState<Phase>('idle')\n const [summary, setSummary] = useState<Summary | null>(null)\n const [candidates, setCandidates] = useState<readonly Candidate[]>([])\n const [selectedIds, setSelectedIds] = useState<ReadonlySet<string>>(new Set())\n const [progress, setProgress] = useState<Progress | null>(null)\n const [result, setResult] = useState<ImportResult | null>(null)\n const [error, setError] = useState('')\n const request = useRef(0)\n\n const close = (): void => {\n if (!claudeSessionImportUiPolicy(phase, selectedIds.size, result?.failed).canClose) return\n request.current += 1\n setOpen(false)\n }\n\n const scan = (workspace: WorkspaceView): void => {\n const generation = ++request.current\n setPhase('scanning')\n setSummary(null)\n setCandidates([])\n setSelectedIds(new Set())\n setProgress(null)\n setResult(null)\n setError('')\n void scanWorkspace(workspace.path).then(\n response => {\n if (request.current !== generation) return\n setSummary(response.summary)\n setCandidates(response.candidates)\n setSelectedIds(new Set(response.candidates.map(candidate => candidate.id)))\n setPhase('summary')\n },\n reason => {\n if (request.current !== generation) return\n setError(messageOf(reason))\n setPhase('error')\n },\n )\n }\n\n const begin = useCallback((): void => {\n const selected = availableTarget ?? workspaces.items[0] ?? null\n setTarget(selected)\n setOpen(true)\n if (selected === null) {\n setPhase('no-workspace')\n return\n }\n setPhase('select-workspace')\n }, [availableTarget, workspaces.items])\n\n useEffect(() => registerProvider({\n id: 'claude',\n label: t('importAction'),\n icon: <IconSparkle16 size={16} />,\n order: 20,\n open: begin,\n }), [begin, registerProvider, t])\n\n const scanSelected = (): void => {\n if (target !== null) scan(target)\n }\n\n const importSelected = (): void => {\n const sessionIds = candidates\n .filter(candidate => selectedIds.has(candidate.id))\n .map(candidate => candidate.id)\n if (target === null || summary === null || sessionIds.length === 0 || phase === 'importing') return\n const generation = ++request.current\n setPhase('importing')\n setProgress({\n completed: 0,\n total: sessionIds.length,\n found: sessionIds.length,\n imported: 0,\n existing: 0,\n failed: 0,\n failures: [],\n })\n setError('')\n void (async () => {\n try {\n const completed = await importWorkspace(target.path, sessionIds, update => {\n if (request.current === generation) setProgress(update)\n })\n await refreshWorkspaceState()\n if (request.current !== generation) return\n setResult(completed)\n setPhase('complete')\n } catch (reason) {\n if (request.current !== generation) return\n setError(messageOf(reason))\n setPhase('error')\n }\n })()\n }\n\n const retry = (): void => {\n if (target !== null) scan(target)\n }\n\n return (\n <>\n <Modal\n open={open}\n onClose={close}\n title={t('importTitle')}\n closeLabel={t('close')}\n description={t('importDescription')}\n className={css.dialog}\n footer={modalFooter({\n phase,\n selectedCount: selectedIds.size,\n result,\n close,\n scanSelected,\n retry,\n importSelected,\n t,\n })}\n >\n <div className={css.body} aria-live=\"polite\">\n {phase === 'select-workspace' && target !== null && (\n <div className={css.workspaceChoice}>\n <label htmlFor=\"claude-import-workspace\">{t('importWorkspaceLabel')}</label>\n <select\n id=\"claude-import-workspace\"\n value={target.workspaceId}\n aria-describedby=\"claude-import-workspace-help\"\n onChange={event => {\n const selected = workspaces.items.find(workspace => workspace.workspaceId === event.currentTarget.value)\n if (selected !== undefined) setTarget(selected)\n }}\n >\n {workspaces.items.map(workspace => (\n <option key={workspace.workspaceId} value={workspace.workspaceId}>{workspace.title}</option>\n ))}\n </select>\n <span id=\"claude-import-workspace-help\" className={css.message}>{t('importChooseWorkspace')}</span>\n <span className={css.workspacePath} title={target.path}>{target.path}</span>\n </div>\n )}\n {target !== null && phase !== 'select-workspace' && (\n <div className={css.workspace}>\n <strong>{target.title}</strong>\n <span title={target.path}>{target.path}</span>\n </div>\n )}\n {phase === 'no-workspace' && <p className={css.message}>{t('importNoWorkspace')}</p>}\n {phase === 'scanning' && <p className={css.message}>{t('importScanning')}</p>}\n {phase === 'summary' && summary !== null && (\n <SummaryView\n summary={summary}\n candidates={candidates}\n selectedIds={selectedIds}\n onSelectionChange={setSelectedIds}\n t={t}\n />\n )}\n {phase === 'importing' && progress !== null && <ProgressView progress={progress} t={t} />}\n {phase === 'complete' && result !== null && <ResultView result={result} t={t} />}\n {phase === 'error' && <p className={css.error} role=\"alert\">{error || t('importFailed')}</p>}\n </div>\n </Modal>\n </>\n )\n}\n\nfunction SummaryView({\n summary,\n candidates,\n selectedIds,\n onSelectionChange,\n t,\n}: {\n summary: Summary\n candidates: readonly Candidate[]\n selectedIds: ReadonlySet<string>\n onSelectionChange: (selected: ReadonlySet<string>) => void\n t: Props['t']\n}): ReactNode {\n const select = (id: string, checked: boolean): void => {\n const next = new Set(selectedIds)\n if (checked) next.add(id)\n else next.delete(id)\n onSelectionChange(next)\n }\n return (\n <div className={css.summary}>\n <dl className={css.metrics}>\n <Metric label={t('importFound')} value={summary.found} />\n <Metric label={t('importExisting')} value={summary.existing} />\n <Metric label={t('importRecoverable')} value={summary.recoverable} />\n <Metric label={t('importReady')} value={summary.ready} accent />\n </dl>\n {candidates.length === 0 ? (\n <p className={css.message}>{t('importEmpty')}</p>\n ) : (\n <>\n <div className={css.selectionToolbar}>\n <span>{t('importSelected')}: {selectedIds.size} / {candidates.length}</span>\n <div>\n <button type=\"button\" onClick={() => onSelectionChange(new Set(candidates.map(candidate => candidate.id)))}>\n {t('importSelectAll')}\n </button>\n <button type=\"button\" onClick={() => onSelectionChange(new Set())}>\n {t('importClearSelection')}\n </button>\n </div>\n </div>\n <ul className={css.candidates} aria-label={t('importCandidates')}>\n {candidates.map(candidate => (\n <li key={candidate.id}>\n <label>\n <input\n type=\"checkbox\"\n checked={selectedIds.has(candidate.id)}\n onChange={event => select(candidate.id, event.currentTarget.checked)}\n />\n <span className={css.candidateBody}>\n <span className={css.candidateHeading}>\n <strong>{candidate.title}</strong>\n <span>{candidate.status === 'recoverable' ? t('importStatusRecoverable') : t('importStatusReady')}</span>\n </span>\n <code>{candidate.id}</code>\n <span title={candidate.cwd}>{candidate.cwd}</span>\n <time dateTime={dateTimeValue(candidate.updatedAt)}>{formatUpdatedAt(candidate.updatedAt)}</time>\n </span>\n </label>\n </li>\n ))}\n </ul>\n </>\n )}\n </div>\n )\n}\n\nfunction ProgressView({ progress, t }: { progress: Progress; t: Props['t'] }): ReactNode {\n const maximum = Math.max(1, progress.total)\n return (\n <div className={css.progress}>\n <div className={css.progressCopy}>\n <strong>{t('importImporting')}</strong>\n <span>{progress.completed} / {progress.total}</span>\n </div>\n <progress value={progress.completed} max={maximum} aria-label={t('importImporting')} />\n </div>\n )\n}\n\nfunction ResultView({ result, t }: { result: ImportResult; t: Props['t'] }): ReactNode {\n return (\n <div>\n <p className={result.failed > 0 ? css.partial : css.success}>\n {result.failed > 0 ? t('importPartial') : t('importComplete')}\n </p>\n <dl className={css.metrics}>\n <Metric label={t('importImported')} value={result.imported} accent />\n <Metric label={t('importExisting')} value={result.existing} />\n <Metric label={t('importFailures')} value={result.failed} danger={result.failed > 0} />\n </dl>\n {result.failures.length > 0 && (\n <ul className={css.failures} aria-label={t('importFailures')}>\n {result.failures.map(failure => (\n <li key={failure.session}>\n <code>{failure.session}</code>\n <span>{failure.message}</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )\n}\n\nfunction Metric({\n label, value, accent = false, danger = false,\n}: { label: string; value: number; accent?: boolean; danger?: boolean }): ReactNode {\n return (\n <div className={css.metric}>\n <dt>{label}</dt>\n <dd className={danger ? css.dangerValue : accent ? css.accentValue : undefined}>{value}</dd>\n </div>\n )\n}\n\nfunction modalFooter({\n phase, selectedCount, result, close, scanSelected, retry, importSelected, t,\n}: {\n phase: Phase\n selectedCount: number\n result: ImportResult | null\n close: () => void\n scanSelected: () => void\n retry: () => void\n importSelected: () => void\n t: Props['t']\n}): ReactNode {\n const policy = claudeSessionImportUiPolicy(phase, selectedCount, result?.failed, phase !== 'no-workspace')\n const actions: Record<ClaudeSessionImportUiAction, (() => void) | undefined> = {\n cancel: close,\n close,\n 'import-selected': importSelected,\n importing: undefined,\n retry,\n scan: scanSelected,\n }\n const labels: Record<ClaudeSessionImportUiAction, string> = {\n cancel: t('cancel'),\n close: t('close'),\n 'import-selected': t('importSelectedAction'),\n importing: t('importImporting'),\n retry: t('retry'),\n scan: t('importScanAction'),\n }\n return (\n <>\n {policy.secondary !== undefined && (\n <Button variant=\"outline\" onClick={actions[policy.secondary]}>\n {labels[policy.secondary]}\n </Button>\n )}\n <Button\n variant={policy.primary === 'close' ? 'outline' : undefined}\n disabled={policy.primaryDisabled}\n onClick={actions[policy.primary]}\n >\n {labels[policy.primary]}\n </Button>\n </>\n )\n}\n\nfunction dateTimeValue(value: Candidate['updatedAt']): string | undefined {\n const date = claudeSessionImportUpdatedAtDate(value)\n return date?.toISOString()\n}\n\nfunction formatUpdatedAt(value: Candidate['updatedAt']): string {\n const date = claudeSessionImportUpdatedAtDate(value)\n return date === null ? '-' : new Intl.DateTimeFormat(undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n }).format(date)\n}\n\nfunction messageOf(reason: unknown): string {\n return reason instanceof Error ? reason.message : String(reason)\n}\n","import { memo, useState } from 'react'\nimport {\n DisclosureRow,\n IconCodeOutline16,\n StateDot,\n type StateDotState,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { ClaudeActivityData } from './claude-activity.ts'\nimport css from './ClaudeActivityView.module.css'\n\ntype ClaudeActivityViewProps = PropsRuntime<'conversation.chat.node', 'relay-claude-activity'>\n\nfunction dotState(status: ClaudeActivityData['status']): StateDotState {\n if (status === 'running') return 'ongoing'\n if (status === 'error') return 'error'\n return 'done'\n}\n\nexport const ClaudeActivityView = memo(function ClaudeActivityView({ node }: ClaudeActivityViewProps) {\n const activity = node.data as ClaudeActivityData\n const [open, setOpen] = useState(false)\n const expandable = activity.input !== undefined || activity.output !== undefined || activity.provenance !== undefined\n return (\n <div className={css.activity} data-claude-activity={activity.type}>\n <DisclosureRow\n icon={<IconCodeOutline16 />}\n title={activity.title}\n open={open}\n expandable={expandable}\n onToggle={() => { setOpen(value => !value) }}\n expandOnRowClick\n collapsedContent={(\n <span className={css.summary}>\n <span>{activity.summary}</span>\n <StateDot state={dotState(activity.status)} size={8} />\n </span>\n )}\n >\n <div className={css.detail}>\n {activity.provenance !== undefined ? (\n <div\n className={css.provenance}\n title={`Claude Code · Session ${activity.provenance.claudeSessionId} · Turn ${activity.provenance.turnId}`}\n >\n Claude Code · Session {shortId(activity.provenance.claudeSessionId)} · Turn {shortId(activity.provenance.turnId)}\n </div>\n ) : null}\n {activity.input !== undefined ? <pre>{activity.input}</pre> : null}\n {activity.output !== undefined ? <pre>{activity.output}</pre> : null}\n </div>\n </DisclosureRow>\n </div>\n )\n})\n\nfunction shortId(value: string): string {\n return value.length > 15 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value\n}\n","import type { ConversationNodeDefinition } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { ChatConversationViewNode } from '@deepseek-ai/dsh-client-ui-chat/client'\nimport type { SessionEventMap } from '@deepseek-ai/dsh-session/types'\n\ntype SessionEventContractAnchor = SessionEventMap\n\nexport type ClaudeActivityStatus = 'running' | 'completed' | 'error'\n\nexport interface ClaudeActivityData {\n readonly type: string\n readonly status: ClaudeActivityStatus\n readonly title: string\n readonly summary?: string\n readonly input?: string\n readonly output?: string\n readonly provenance?: {\n readonly claudeSessionId: string\n readonly turnId: string\n }\n}\n\nexport interface ClaudeActivityEventData {\n readonly version: 1\n readonly claudeSessionId: string\n readonly turnId: string\n readonly itemId: string\n readonly phase: 'started' | 'completed'\n readonly activity: ClaudeActivityData\n}\n\ndeclare module '@deepseek-ai/dsh-session/types' {\n interface SessionEventMap {\n 'relay-claude/activity': ClaudeActivityEventData\n }\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-chat/client' {\n interface ChatNodeDataMap {\n 'relay-claude-activity': ClaudeActivityData\n }\n}\n\nexport const claudeActivityDefinition: ConversationNodeDefinition<ClaudeActivityData> = {\n kind: 'relay-claude-activity',\n target: 'chat',\n match: event => event.type === 'relay-claude/activity'\n ? { id: event.data.itemId, role: event.data.phase === 'started' ? 'start' : 'update' }\n : null,\n start: (_context, match) => {\n if (match.event.type !== 'relay-claude/activity') {\n throw new Error('Claude activity start requires relay-claude/activity')\n }\n return {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n },\n update: (context, match) => match.event.type === 'relay-claude/activity'\n ? {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n : context.state,\n buildViewNode: (context): ChatConversationViewNode | null => {\n if (context.start === undefined || context.state === undefined) return null\n return {\n key: context.key,\n kind: 'relay-claude-activity',\n id: context.id,\n target: 'chat',\n anchorSeq: context.start.event.seq,\n location: context.start.location,\n visibility: 'visible',\n data: context.state,\n }\n },\n}\n","export const en = {\n importAction: 'Import from Claude',\n importTitle: 'Import Claude Sessions',\n importDescription: 'Select existing Claude terminal Sessions from this Workspace to continue in DSH.',\n importWorkspaceLabel: 'Target Workspace',\n importChooseWorkspace: 'Choose the Workspace whose Sessions you want to scan and import.',\n importScanAction: 'Scan Sessions',\n importNoWorkspace: 'Open or select a Workspace before importing Sessions.',\n importScanning: 'Scanning native Claude Sessions...',\n importFound: 'Found',\n importExisting: 'Already linked',\n importRecoverable: 'Recoverable',\n importReady: 'Available',\n importEmpty: 'No unlinked Claude Sessions are available in this Workspace.',\n importSelected: 'Selected',\n importSelectAll: 'Select all',\n importClearSelection: 'Clear',\n importCandidates: 'Claude Session candidates',\n importStatusReady: 'Ready',\n importStatusRecoverable: 'Retry import',\n importSelectedAction: 'Import selected',\n importImporting: 'Importing Sessions...',\n importComplete: 'Import completed.',\n importPartial: 'Some Sessions could not be imported.',\n importImported: 'Imported',\n importFailures: 'Failed',\n importFailed: 'Claude Session import failed.',\n cancel: 'Cancel',\n close: 'Close',\n retry: 'Retry',\n} as const\n\nexport const zh: Record<keyof typeof en, string> = {\n importAction: '从 Claude 导入',\n importTitle: '导入 Claude 会话',\n importDescription: '选择当前工作区中已有的 Claude 终端会话,并在 DSH 中继续。',\n importWorkspaceLabel: '目标 Workspace',\n importChooseWorkspace: '选择要扫描和导入会话的 Workspace。',\n importScanAction: '扫描会话',\n importNoWorkspace: '请先打开或选择一个工作区。',\n importScanning: '正在扫描原生 Claude 会话...',\n importFound: '发现',\n importExisting: '已绑定',\n importRecoverable: '可恢复',\n importReady: '可导入',\n importEmpty: '当前工作区没有未绑定的 Claude 会话。',\n importSelected: '已选择',\n importSelectAll: '全选',\n importClearSelection: '清空',\n importCandidates: 'Claude 会话候选列表',\n importStatusReady: '可导入',\n importStatusRecoverable: '重试导入',\n importSelectedAction: '导入所选会话',\n importImporting: '正在导入会话...',\n importComplete: '导入完成。',\n importPartial: '部分会话未能导入。',\n importImported: '已导入',\n importFailures: '失败',\n importFailed: 'Claude 会话导入失败。',\n cancel: '取消',\n close: '关闭',\n retry: '重试',\n}\n\nexport type ClaudeLocaleKey = keyof typeof en\n","import type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\n\nexport function conversationEvents(ctx: Context): Context['uiConversation']['events'] {\n const events = ctx.get('uiConversation')?.events ?? ctx.get('conversationEvents')\n if (!events) throw new Error('DSH conversation events service is unavailable')\n return events\n}\n\n/** Bind setup and disposal to the service family actually present in this DSH. */\nexport function withConversationRuntime(ctx: Context, setup: (ctx: Context) => (() => void)): () => void {\n const current = ctx.inject(['uiConversation', 'modelDirectories'], inner => setup(inner))\n const legacy = ctx.inject(['conversationEvents'], inner => {\n if (inner.get('uiConversation')) return\n return setup(inner)\n })\n return () => { void current.dispose(); void legacy.dispose() }\n}\n","import type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type { ChatNodeOwnerProps } from '@deepseek-ai/dsh-client-ui-chat/client'\nimport { installModelSelection, type ModelSelectionContext } from '../../model-selection.mjs'\nimport { ClaudeSessionImportProvider, type ClaudeSessionImportInjected } from './ClaudeSessionImportAction.tsx'\nimport { ClaudeActivityView } from './ClaudeActivityView.tsx'\nimport { claudeActivityDefinition } from './claude-activity.ts'\nimport { en, zh, type ClaudeLocaleKey } from './locales.ts'\nimport {\n importClaudeWorkspace,\n refreshImportedWorkspace,\n scanClaudeWorkspace,\n} from './claude-session-import-client.mjs'\nimport type { SessionImportProviderSlotDefinition } from 'relay-dsh-plugin-session-import/contracts'\nimport { conversationEvents, withConversationRuntime } from './compatible-runtime.ts'\n\ntype DshSlotContractAnchor = ChatNodeOwnerProps\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface SlotMap {\n 'relay.session-import.provider': SessionImportProviderSlotDefinition\n }\n interface LocaleNamespaceMap {\n 'relay.claude': ClaudeLocaleKey\n }\n}\n\nexport const inject = ['slots', 'theme', 'locale', 'remote', 'sessions', 'workspaces', 'connection']\n\nexport async function apply(ctx: ClientContext): Promise<() => Promise<void>> {\n ctx.effect(() => ctx.locale.register('relay.claude', { zh, en }), 'relay-claude: dictionaries')\n applySessionImport(ctx)\n const unsubscribe = withConversationRuntime(ctx, inner => {\n conversationEvents(inner).register(claudeActivityDefinition)\n inner.slots.inject('conversation.chat.node', () => inner.slots.register({\n name: 'conversation.chat.node', key: 'relay-claude-activity',\n }, ClaudeActivityView))\n return installModelSelection(inner as ModelSelectionContext, 'relay-claude', 'relay-claude', 'relay-codex')\n })\n return async () => { unsubscribe() }\n}\n\nfunction applySessionImport(ctx: ClientContext): void {\n const injected = (): ClaudeSessionImportInjected => ({\n hooks: {\n claudeSessionImportWorkspaces: ctx.workspaces.list,\n claudeSessionImportSessions: ctx.sessions.list,\n },\n scanWorkspace: cwd => scanClaudeWorkspace(cwd),\n importWorkspace: (cwd, sessionIds, onProgress) => importClaudeWorkspace(cwd, { sessionIds, onProgress }),\n refreshWorkspaceState: () => refreshImportedWorkspace(\n ctx.sessions as typeof ctx.sessions & { refresh(): Promise<void> },\n ctx.workspaces as typeof ctx.workspaces & { refresh(): Promise<void> },\n ),\n })\n ctx.slots.inject('relay.session-import.provider', () => ctx.slots.register({\n name: 'relay.session-import.provider',\n id: 'claude',\n order: 20,\n inject: injected,\n locale: 'relay.claude',\n }, ClaudeSessionImportProvider))\n}\n"],"mappings":"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"}
|
package/lib/host-plugin.js
CHANGED
|
@@ -8,7 +8,8 @@ import { z } from "zod";
|
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
10
10
|
import { KNOWN_SESSION_EVENT_TYPES, SessionId } from "@deepseek-ai/dsh-session";
|
|
11
|
-
import
|
|
11
|
+
import * as llm from "@deepseek-ai/dsh-llm";
|
|
12
|
+
import { LlmAdapter, MessageId, freezeMessage } from "@deepseek-ai/dsh-llm";
|
|
12
13
|
import { cp, mkdir, open, realpath, stat } from "node:fs/promises";
|
|
13
14
|
import sharp from "sharp";
|
|
14
15
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
@@ -3259,14 +3260,14 @@ function normalizeQuestions(input) {
|
|
|
3259
3260
|
header: String(question.header ?? "Claude").slice(0, 12),
|
|
3260
3261
|
options: normalizeOptions(question.options ?? []),
|
|
3261
3262
|
multiSelect: Boolean(question.multiSelect),
|
|
3262
|
-
|
|
3263
|
+
...typeof question.detail === "string" ? { detail: question.detail } : {}
|
|
3263
3264
|
}));
|
|
3264
3265
|
}
|
|
3265
3266
|
function normalizeOptions(input) {
|
|
3266
3267
|
if (!Array.isArray(input) || input.length === 0) return [{ label: "Continue" }, { label: "Cancel" }];
|
|
3267
3268
|
return input.slice(0, 4).map((option) => ({
|
|
3268
3269
|
label: requiredString(option.label ?? option, "option label"),
|
|
3269
|
-
|
|
3270
|
+
...typeof option.description === "string" ? { description: option.description } : {}
|
|
3270
3271
|
}));
|
|
3271
3272
|
}
|
|
3272
3273
|
function normalizeAnswers(answer, questions) {
|
|
@@ -3287,6 +3288,13 @@ function plainObject(value) {
|
|
|
3287
3288
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
3288
3289
|
}
|
|
3289
3290
|
//#endregion
|
|
3291
|
+
//#region dsh-compat.mjs
|
|
3292
|
+
function toolCallId(value) {
|
|
3293
|
+
const create = Reflect.get(llm, "ToolCallId") ?? Reflect.get(llm, "CallId");
|
|
3294
|
+
if (typeof create !== "function") throw new Error("DSH does not provide a tool call ID constructor");
|
|
3295
|
+
return create(value);
|
|
3296
|
+
}
|
|
3297
|
+
//#endregion
|
|
3290
3298
|
//#region dsh-import-target.js
|
|
3291
3299
|
var DshClaudeImportTarget = class {
|
|
3292
3300
|
constructor({ ctx, logger = console }) {
|
|
@@ -3413,7 +3421,7 @@ function buildClaudeHistorySeed(projection, updatedAt, config) {
|
|
|
3413
3421
|
})
|
|
3414
3422
|
}, "append");
|
|
3415
3423
|
else {
|
|
3416
|
-
const callId =
|
|
3424
|
+
const callId = toolCallId(entry.callId);
|
|
3417
3425
|
append("assistant/message", {
|
|
3418
3426
|
turn,
|
|
3419
3427
|
step,
|