dsh-code-ui 1.6.0 → 1.6.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.
Files changed (3) hide show
  1. package/lib/client.js +14 -6
  2. package/lib/index.js +54 -10
  3. package/package.json +94 -94
package/lib/client.js CHANGED
@@ -2414,10 +2414,6 @@ window.__ModuleLoader__.load({
2414
2414
  const snap = shell && shell.snapshot
2415
2415
  if (!snap || typeof snap.draftRev !== 'number' || typeof snap.draft !== 'string') return false
2416
2416
  if (snap.phase && snap.phase !== 'plain' && snap.phase !== 'claimed') return false
2417
- const inputTriggers = store.inputTriggers
2418
- if (!inputTriggers || !inputTriggers.live || !inputTriggers.live.controllers) return false
2419
- const controller = inputTriggers.live.controllers.get(sid)
2420
- if (!controller || typeof controller.execute !== 'function') return false
2421
2417
  let detectLen = snap.draft.length
2422
2418
  const occs = Array.isArray(snap.occurrences) ? snap.occurrences : []
2423
2419
  for (const o of occs) {
@@ -2425,8 +2421,20 @@ window.__ModuleLoader__.load({
2425
2421
  }
2426
2422
  if (detectLen < 0) detectLen = 0
2427
2423
  const label = chipLabelFor(r)
2428
- const outcome = { insert: { source: 'code-ui', ref: JSON.stringify({ id: r.id, path: r.path, lineStart: r.lineStart, lineEnd: r.lineEnd, kind: r.kind }), label: label, appearance: 'file', clipboardText: label } }
2429
- return controller.execute(outcome, { start: detectLen, end: detectLen, draftRev: snap.draftRev }) === true
2424
+ const span = { start: detectLen, end: detectLen, draftRev: snap.draftRev }
2425
+ const insert = { source: 'code-ui', ref: JSON.stringify({ id: r.id, path: r.path, lineStart: r.lineStart, lineEnd: r.lineEnd, kind: r.kind }), label: label, appearance: 'file', clipboardText: label }
2426
+ // 0.2.0-rc.x:优先走 shell.insertReference 公共契约(span-CAS,Lexical 离散更新,
2427
+ // 立即渲染)。旧路径(inputTriggers.live.controllers.get(sid))在 0.2.0 上失效——
2428
+ // controllers 改按 SessionBinding 对象键控,字符串 sid 取不到 controller,
2429
+ // chip 插不进去,发送时才由 submit 补丁附带指针(表现为「引用回车才出现」)。
2430
+ if (typeof shell.insertReference === 'function') {
2431
+ return shell.insertReference(insert, span) === true
2432
+ }
2433
+ const inputTriggers = store.inputTriggers
2434
+ if (!inputTriggers || !inputTriggers.live || !inputTriggers.live.controllers) return false
2435
+ const controller = inputTriggers.live.controllers.get(sid)
2436
+ if (!controller || typeof controller.execute !== 'function') return false
2437
+ return controller.execute({ insert: insert }, span) === true
2430
2438
  } catch (e) { return false }
2431
2439
  }
2432
2440
  // chip ref(JSON 串)→ 引用数据;解析失败返回 null
package/lib/index.js CHANGED
@@ -8,7 +8,7 @@ import { Remote, bindTypertRemote } from "@deepseek-ai/dsh-typert-protocol";
8
8
  import { defineTool } from "@deepseek-ai/dsh-tools";
9
9
  import z from "@deepseek-ai/schemastery";
10
10
  import { spawn } from "node:child_process";
11
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, watch, writeFileSync } from "node:fs";
11
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
12
12
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
13
13
  import { fileURLToPath } from "node:url";
14
14
 
@@ -696,7 +696,48 @@ function unwatchAllFiles() {
696
696
  }
697
697
 
698
698
  function rpcHandler(ctx) {
699
- const fs = ctx.get("fs");
699
+ // fs 服务延迟获取:插件 apply 可能早于 base bundle 的 fs-sandbox 行挂载,
700
+ // apply 时一次性 ctx.get("fs") 会永久取到 undefined(0.2.0-rc.2 实测:
701
+ // list-dir/stat-path/read-file 全部抛 "Cannot read properties of
702
+ // undefined (reading 'resolve')")。改为 inject 等待 + 调用时解析。
703
+ let fsSvc = null;
704
+ try { fsSvc = ctx.get("fs") || null; } catch (_) {}
705
+ try {
706
+ ctx.inject(["fs"], (c) => { fsSvc = c.fs || fsSvc; });
707
+ } catch (_) {}
708
+ // 宿主组合始终无 fs 服务时的原生兜底:与 fs-mkdir/write-file 等磁盘端点
709
+ // 同一权限模型(编辑器是用户显式操作面,本就读写真实磁盘)。
710
+ const nativeFsShim = {
711
+ resolve: async (p) => p,
712
+ stat: async (p) => {
713
+ try {
714
+ const s = statSync(p);
715
+ return { type: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other" };
716
+ } catch (_) { return null; }
717
+ },
718
+ listDir: async (p) => {
719
+ const sep = String(p).includes("\\") ? "\\" : "/";
720
+ return readdirSync(p, { withFileTypes: true }).map((d) => ({
721
+ name: d.name,
722
+ path: String(p).replace(/[\\/]+$/, "") + sep + d.name,
723
+ isDir: d.isDirectory(),
724
+ }));
725
+ },
726
+ readBytes: async (p, _signal, maxBytes) => {
727
+ const b = readFileSync(p);
728
+ if (b.length > maxBytes) {
729
+ const e = new Error("file too large");
730
+ e.code = "FS_TOO_LARGE";
731
+ throw e;
732
+ }
733
+ return new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
734
+ },
735
+ readByteRange: async (p, range) => {
736
+ const b = readFileSync(p);
737
+ return new Uint8Array(b.buffer, b.byteOffset, b.byteLength).slice(range.offset, range.offset + range.length);
738
+ },
739
+ };
740
+ const getFs = () => fsSvc || nativeFsShim;
700
741
  let currentRootRef = detectWorkspaceRoot(ctx); // 最近一次解析的根:list-dir 的兜底
701
742
  // 每会话根目录记忆:sessionId -> 手动设置的根(「以此文件夹为根」)。
702
743
  // 按会话隔离——手动根只影响设置它的那个会话,不再全局污染其它会话的自动解析;
@@ -792,8 +833,9 @@ function rpcHandler(ctx) {
792
833
  if (endpoint === "list-dir") {
793
834
  const path = args.path || currentRootRef;
794
835
  if (!path) return ok({ error: "no-root" });
795
- const target = await fs.resolve(path);
796
- const entries = await fs.listDir(target);
836
+ const fsvc = getFs();
837
+ const target = await fsvc.resolve(path);
838
+ const entries = await fsvc.listDir(target);
797
839
  const sep = String(path).includes("\\") ? "\\" : "/";
798
840
  const list = entries.map((e) => {
799
841
  let name = null;
@@ -820,8 +862,9 @@ function rpcHandler(ctx) {
820
862
 
821
863
  if (endpoint === "stat-path") {
822
864
  if (!args.path) return ok({ error: "no-path" });
823
- const target = await fs.resolve(args.path);
824
- const info = await fs.stat(target);
865
+ const fsvc = getFs();
866
+ const target = await fsvc.resolve(args.path);
867
+ const info = await fsvc.stat(target);
825
868
  // DSH fs.stat 返回 FsInfo { type: 'file' | 'directory' | 'other' },
826
869
  // 没有 isDirectory/isFile 布尔字段;必须按 type 判定(原实现恒为 false,
827
870
  // 导致目录路径被误报为「不存在」)。保留遗留字段兼容。
@@ -833,19 +876,20 @@ function rpcHandler(ctx) {
833
876
 
834
877
  if (endpoint === "read-file") {
835
878
  if (!args.path) return ok({ error: "no-path" });
836
- const target = await fs.resolve(args.path);
879
+ const fsvc = getFs();
880
+ const target = await fsvc.resolve(args.path);
837
881
  // 对齐 dsh ≥ 0.1.7-rc.1 的二进制 Remote 结果契约:字节经 Uint8Array 字段返回,
838
882
  // gateway 自动投影为 multipart 附件下发;0.1.5/0.1.6 老宿主无投影则走 JSON
839
883
  // (Uint8Array 落成下标对象,客户端负责重建),同一份代码两端兼容。
840
884
  // 取代旧的 60 万字符文本截断——截断内容若被 Ctrl+S 原样写回会写坏大文件。
841
885
  const MAX = 4 * 1024 * 1024; // 单次读取上限 4MB
842
886
  try {
843
- const bytes = await fs.readBytes(target, undefined, MAX);
887
+ const bytes = await fsvc.readBytes(target, undefined, MAX);
844
888
  return ok({ path: args.path, bytes, truncated: false, size: bytes.length });
845
889
  } catch (err) {
846
- if (!err || err.code !== "FS_TOO_LARGE" || typeof fs.readByteRange !== "function") throw err;
890
+ if (!err || err.code !== "FS_TOO_LARGE" || typeof fsvc.readByteRange !== "function") throw err;
847
891
  // 超限文件读前 4MB,标记 truncated;客户端据此禁写并提示
848
- const bytes = await fs.readByteRange(target, { offset: 0, length: MAX });
892
+ const bytes = await fsvc.readByteRange(target, { offset: 0, length: MAX });
849
893
  return ok({ path: args.path, bytes, truncated: true });
850
894
  }
851
895
  }
package/package.json CHANGED
@@ -1,94 +1,94 @@
1
- {
2
- "name": "dsh-code-ui",
3
- "version": "1.6.0",
4
- "description": "Cursor 风格的 AI 代码编辑器工作台插件(DSH):文件树、多标签页编辑、语法高亮、引用/翻译行内标签给 AI、右侧停靠/悬浮窗口双布局",
5
- "type": "module",
6
- "main": "lib/index.js",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/soGoodayo/dsh-code-ui.git"
10
- },
11
- "homepage": "https://github.com/soGoodayo/dsh-code-ui#readme",
12
- "bugs": {
13
- "url": "https://github.com/soGoodayo/dsh-code-ui/issues"
14
- },
15
- "exports": {
16
- ".": {
17
- "default": "./lib/index.js"
18
- },
19
- "./client": {
20
- "default": "./lib/client.js"
21
- },
22
- "./cordis.patch.yml": "./cordis.patch.yml",
23
- "./icon": "./icon.svg",
24
- "./package.json": "./package.json"
25
- },
26
- "files": [
27
- "lib",
28
- "cordis.patch.yml",
29
- "icon.svg",
30
- "README.md",
31
- "LICENSE"
32
- ],
33
- "engines": {
34
- "dsh": ">=0.1.5-rc.1 <0.3.0"
35
- },
36
- "dsh": {
37
- "bundle": {
38
- "patch": "./cordis.patch.yml"
39
- },
40
- "client": {
41
- "inject": [
42
- "@deepseek-ai/dsh-client-ui-slots",
43
- "@deepseek-ai/dsh-client-ui-conversation",
44
- "@deepseek-ai/dsh-client-ui-settings",
45
- "@deepseek-ai/dsh-client-ui-theme"
46
- ],
47
- "platform": "web"
48
- }
49
- },
50
- "peerDependencies": {
51
- "@deepseek-ai/cordis": "^4.0.1",
52
- "@deepseek-ai/dsh": ">=0.1.5-rc.1 <0.3.0",
53
- "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.3.0",
54
- "@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.3.0",
55
- "@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.3.0",
56
- "react": "^18.2.0"
57
- },
58
- "peerDependenciesMeta": {
59
- "@deepseek-ai/dsh-typert-protocol": {
60
- "optional": true
61
- },
62
- "@deepseek-ai/dsh-tools": {
63
- "optional": true
64
- },
65
- "@deepseek-ai/dsh-settings": {
66
- "optional": true
67
- }
68
- },
69
- "dependencies": {
70
- "@deepseek-ai/schemastery": "^3.18.1"
71
- },
72
- "devDependencies": {
73
- "@deepseek-ai/dsh-typert-protocol": "^0.2.0-rc.2",
74
- "@types/node": "^26.2.0",
75
- "@types/react": "~18.3.1",
76
- "react": "^18.3.1",
77
- "tsdown": "^0.22.14",
78
- "typescript": "^7.0.2"
79
- },
80
- "scripts": {},
81
- "publishConfig": {
82
- "registry": "https://registry.npmjs.org/"
83
- },
84
- "license": "MIT",
85
- "keywords": [
86
- "dsh",
87
- "deepseek-harness",
88
- "cursor",
89
- "editor",
90
- "code-ui",
91
- "plugin"
92
- ],
93
- "packageManager": "pnpm@11.23.0+sha512.f00082e5b283a199b74e079da28d155c008fe232f44c8a06ea7ddfa014ecf719fc362f790ecc67b28106ddac2afb24c49a9a079159da560b2ce7d1e98efd11af"
94
- }
1
+ {
2
+ "name": "dsh-code-ui",
3
+ "version": "1.6.2",
4
+ "description": "Cursor 风格的 AI 代码编辑器工作台插件(DSH):文件树、多标签页编辑、语法高亮、引用/翻译行内标签给 AI、右侧停靠/悬浮窗口双布局",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/soGoodayo/dsh-code-ui.git"
10
+ },
11
+ "homepage": "https://github.com/soGoodayo/dsh-code-ui#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/soGoodayo/dsh-code-ui/issues"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "default": "./lib/index.js"
18
+ },
19
+ "./client": {
20
+ "default": "./lib/client.js"
21
+ },
22
+ "./cordis.patch.yml": "./cordis.patch.yml",
23
+ "./icon": "./icon.svg",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "lib",
28
+ "cordis.patch.yml",
29
+ "icon.svg",
30
+ "README.md",
31
+ "LICENSE"
32
+ ],
33
+ "engines": {
34
+ "dsh": ">=0.1.5-rc.1 <0.3.0"
35
+ },
36
+ "dsh": {
37
+ "bundle": {
38
+ "patch": "./cordis.patch.yml"
39
+ },
40
+ "client": {
41
+ "inject": [
42
+ "@deepseek-ai/dsh-client-ui-slots",
43
+ "@deepseek-ai/dsh-client-ui-conversation",
44
+ "@deepseek-ai/dsh-client-ui-settings",
45
+ "@deepseek-ai/dsh-client-ui-theme"
46
+ ],
47
+ "platform": "web"
48
+ }
49
+ },
50
+ "peerDependencies": {
51
+ "@deepseek-ai/cordis": "^4.0.1",
52
+ "@deepseek-ai/dsh": ">=0.1.5-rc.1 <0.3.0",
53
+ "@deepseek-ai/dsh-typert-protocol": ">=0.1.5-rc.1 <0.3.0",
54
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.1 <0.3.0",
55
+ "@deepseek-ai/dsh-settings": ">=0.1.0-rc.7 <0.3.0",
56
+ "react": "^18.2.0"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@deepseek-ai/dsh-typert-protocol": {
60
+ "optional": true
61
+ },
62
+ "@deepseek-ai/dsh-tools": {
63
+ "optional": true
64
+ },
65
+ "@deepseek-ai/dsh-settings": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "dependencies": {
70
+ "@deepseek-ai/schemastery": "^3.18.1"
71
+ },
72
+ "devDependencies": {
73
+ "@deepseek-ai/dsh-typert-protocol": "^0.2.0-rc.2",
74
+ "@types/node": "^26.2.0",
75
+ "@types/react": "~18.3.1",
76
+ "react": "^18.3.1",
77
+ "tsdown": "^0.22.14",
78
+ "typescript": "^7.0.2"
79
+ },
80
+ "scripts": {},
81
+ "publishConfig": {
82
+ "registry": "https://registry.npmjs.org/"
83
+ },
84
+ "license": "MIT",
85
+ "keywords": [
86
+ "dsh",
87
+ "deepseek-harness",
88
+ "cursor",
89
+ "editor",
90
+ "code-ui",
91
+ "plugin"
92
+ ],
93
+ "packageManager": "pnpm@11.23.0+sha512.f00082e5b283a199b74e079da28d155c008fe232f44c8a06ea7ddfa014ecf719fc362f790ecc67b28106ddac2afb24c49a9a079159da560b2ce7d1e98efd11af"
94
+ }