dsh-claude-move 0.2.2 → 0.2.4

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/client/client.js CHANGED
@@ -17,6 +17,8 @@
17
17
  name: 'claude-move-panel',
18
18
  inject: [],
19
19
  apply: function (ctx) { installPanel(ctx) },
20
+ // 纯函数测试面(U3):面板仅此三个无 I/O/时钟/随机的纯函数。
21
+ helpers: { panelText, esc, safeService, strings: PANEL_STRINGS },
20
22
  }
21
23
  },
22
24
  })
@@ -155,6 +157,11 @@ function panelText(key, ...args) {
155
157
  return text
156
158
  }
157
159
 
160
+ /** HTML 转义(纯函数;面板渲染所有外部文本前调用)。 */
161
+ function esc(text) {
162
+ return String(text ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]))
163
+ }
164
+
158
165
  function installPanel(ctx) {
159
166
  if (document.getElementById('claude-move-panel')) return
160
167
 
@@ -443,9 +450,6 @@ function installPanel(ctx) {
443
450
 
444
451
  function setBar(pct) { bar.style.width = Math.max(0, Math.min(100, pct)) + '%' }
445
452
  function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)) }
446
- function esc(text) {
447
- return String(text ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]))
448
- }
449
453
 
450
454
  // 默认收起:只显示悬浮按钮,用户点击才展开抽屉(不抢占每次页面加载的注意力)。
451
455
  }
package/index.mjs CHANGED
@@ -2085,11 +2085,16 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2085
2085
  const claudeHome = () => config.claudeHome ? path.resolve(config.claudeHome) : locateClaudeHome()
2086
2086
  const jobs = new Map()
2087
2087
  const JOB_RETENTION = 20
2088
+ // webServer.register 返回的 disposer 是唯一注销途径(重复 exact 路由会抛
2089
+ // duplicate route),不随 fiber 自动撤销:逐个收集,函数末尾挂进一个
2090
+ // ctx.effect,fiber 卸载时逆序摘除全部路由。
2091
+ /** @type {Array<(() => void) | undefined>} */
2092
+ const routeDisposers = []
2088
2093
 
2089
2094
  // 官方后台任务服务(B5):特性探测,缺失回退自有 job Map(rc.6 兼容)。
2090
2095
  const hostJobs = typeof ctx.get === 'function' ? ctx.get('jobs') : undefined
2091
2096
 
2092
- webServer.register({
2097
+ routeDisposers.push(webServer.register({
2093
2098
  kind: 'exact',
2094
2099
  path: '/api/claude-move/index',
2095
2100
  handler: async (req, res) => {
@@ -2101,9 +2106,9 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2101
2106
  sendJson(res, 500, { error: String((err && err.message) || err) })
2102
2107
  }
2103
2108
  },
2104
- })
2109
+ }))
2105
2110
 
2106
- webServer.register({
2111
+ routeDisposers.push(webServer.register({
2107
2112
  kind: 'exact',
2108
2113
  path: '/api/claude-move/import',
2109
2114
  handler: async (req, res) => {
@@ -2196,9 +2201,9 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2196
2201
  }
2197
2202
  })()
2198
2203
  },
2199
- })
2204
+ }))
2200
2205
 
2201
- webServer.register({
2206
+ routeDisposers.push(webServer.register({
2202
2207
  kind: 'exact',
2203
2208
  path: '/api/claude-move/progress',
2204
2209
  handler: (req, res) => {
@@ -2213,9 +2218,9 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2213
2218
  const { controller: _controller, hostJobId: _hostJobId, ...publicJob } = job
2214
2219
  sendJson(res, 200, publicJob)
2215
2220
  },
2216
- })
2221
+ }))
2217
2222
 
2218
- webServer.register({
2223
+ routeDisposers.push(webServer.register({
2219
2224
  kind: 'exact',
2220
2225
  path: '/api/claude-move/job',
2221
2226
  handler: (req, res) => {
@@ -2245,9 +2250,9 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2245
2250
  }
2246
2251
  sendJson(res, 200, { cancelled: true })
2247
2252
  },
2248
- })
2253
+ }))
2249
2254
 
2250
- webServer.register({
2255
+ routeDisposers.push(webServer.register({
2251
2256
  kind: 'exact',
2252
2257
  path: '/api/claude-move/reset',
2253
2258
  handler: async (req, res) => {
@@ -2267,7 +2272,12 @@ function registerRouteDefinitions(ctx, config, state, webServer) {
2267
2272
  sendJson(res, 500, { error: String((err && err.message) || err) })
2268
2273
  }
2269
2274
  },
2270
- })
2275
+ }))
2276
+
2277
+ // 路由随本插件生命周期撤销:fiber 卸载时逆序执行全部 disposer。
2278
+ ctx.effect(() => () => {
2279
+ for (const dispose of routeDisposers.splice(0).reverse()) dispose?.()
2280
+ }, 'claude-move: web panel routes')
2271
2281
  }
2272
2282
 
2273
2283
  // ── 四合一迁移向导:move_detect / move_preview / move_run + /move ──────────────
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-claude-move",
3
- "description": "Copy Claude Code transcripts, memories, skills and CLAUDE.md into DeepSeek Harness as resumable sessions 閳?one workspace per project, copy-only, seamlessly resumable",
4
- "version": "0.2.2",
3
+ "description": "Four-source migration wizard: copy Claude Code, Codex, OpenCode and Hermes sessions, memories, skills, instructions and slash commands into DeepSeek Harness as resumable sessions copy-only, approval-gated, idempotent",
4
+ "version": "0.2.4",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
7
7
  "exports": {
@@ -43,13 +43,57 @@
43
43
  "immediately": true
44
44
  }
45
45
  },
46
+ "dshWorkshop": {
47
+ "schema": "omdsh-workshop-package/v1",
48
+ "type": "plugin",
49
+ "integration": {
50
+ "protocol": "harness-profile",
51
+ "artifact": "cordis.patch.yml"
52
+ },
53
+ "install": {
54
+ "mode": "transactional",
55
+ "adapter": "profile-bundle",
56
+ "failurePolicy": "generation-rollback",
57
+ "touchesCurrentBeforeActivation": false
58
+ },
59
+ "lifecycle": {
60
+ "activation": "hot-reload",
61
+ "dispose": "supported"
62
+ },
63
+ "permissions": [
64
+ "filesystem:read",
65
+ "filesystem:write"
66
+ ],
67
+ "compatibility": {
68
+ "dshVersions": [
69
+ "0.1.0-rc.6"
70
+ ]
71
+ },
72
+ "capability": {
73
+ "id": "move-wizard",
74
+ "kind": "command",
75
+ "invocation": "/move",
76
+ "expected": "detects the four sources, renders the migration preview, and with approval applies the plans and records them in move.json (re-runs skip unchanged items)"
77
+ },
78
+ "evidence": {
79
+ "install": null,
80
+ "failureIsolation": null,
81
+ "hotReload": null,
82
+ "remove": null
83
+ }
84
+ },
46
85
  "peerDependencies": {
47
86
  "@deepseek-ai/cordis": "^4.0.1",
48
87
  "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
49
88
  "@deepseek-ai/schemastery": ">=3.0.0"
50
89
  },
51
90
  "scripts": {
52
- "test": "node --test \"test/*.test.mjs\""
91
+ "test": "node --test \"test/*.test.mjs\"",
92
+ "coverage": "node --test --experimental-test-coverage \"test/*.test.mjs\"",
93
+ "lint": "oxlint",
94
+ "check:readmes": "node scripts/check-readme-sync.mjs",
95
+ "verify:self-contained": "node scripts/verify-self-contained.mjs",
96
+ "verify:artifacts": "node scripts/verify-artifacts.mjs"
53
97
  },
54
98
  "keywords": [
55
99
  "deepseek-harness",
@@ -62,5 +106,25 @@
62
106
  "engines": {
63
107
  "node": "^22.19.0 || >=24.0.0"
64
108
  },
65
- "license": "Apache-2.0"
109
+ "license": "Apache-2.0",
110
+ "devDependencies": {
111
+ "@deepseek-ai/cordis": "^4.0.1",
112
+ "@deepseek-ai/cordis-plugin-include": "^1.0.6",
113
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
114
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.6",
115
+ "@deepseek-ai/dsh-attachment": "^0.1.0-rc.6",
116
+ "@deepseek-ai/dsh-brand": "^0.1.0-rc.6",
117
+ "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.6",
118
+ "@deepseek-ai/dsh-commands": "^0.1.0-rc.6",
119
+ "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
120
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
121
+ "@deepseek-ai/dsh-scope": "^0.1.0-rc.6",
122
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
123
+ "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.6",
124
+ "@deepseek-ai/dsh-timeout": "^0.1.0-rc.6",
125
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
126
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6",
127
+ "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.6",
128
+ "oxlint": "^0.18.1"
129
+ }
66
130
  }