dsh-m 0.9.48 → 0.9.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/docs/DESIGN.md +1 -1
- package/lib/client.js +10 -3
- package/lib/core/installed.js +4 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,13 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
8
8
|
|
|
9
9
|
## 中文
|
|
10
10
|
|
|
11
|
+
### 0.9.49 变更:已装 README 基址贯通 + 链接归一三件(0.9.48 深入分析跟进)
|
|
12
|
+
|
|
13
|
+
- **已装视图基址贯通(P0,主缺口)**:0.9.48 已装详情挂载点误传不存在的 `it.github`,而已装插件走本地读取路径(`repo` 字段只在 npm 兜底路径附带)→ 已装 README 相对链接全部归 `#`。现改传 `vm.githubRepo`——installed-view 视图模型现成的三级兜底(registry 匹配 `registryGithub` → 已装包 package.json `repository` 解析 → 安装 spec `github:o/r` 解析),图标与 LinksRow 早就在用。装机浏览场景的相对链接/图片自此全部可锚定。
|
|
14
|
+
- **链接归一(P1)**:①协议相对 `//host/x` 补 `https:`——此前有基址时被错剥成仓库内路径、无基址时跳 DSH 站内;②`git@github.com:o/r(.git)` 内联链接归一 https 形态(README 的 clone 指引段落);③有基址时 `#anchor` 锚 `github.com/<o>/<r>#anchor`(仓库首页 README 同名锚,裸 `#` 与图片 kind 不参与)。
|
|
15
|
+
- **host 侧解析口径统一(P2)**:`githubRepoFromRepository` 尾部从 `$` 放宽到 `[/?#]`——`github.com/o/r/`(尾斜杠)与 `…/tree/main` 等更深路径此前解析不出;与 versions.ts `extractGithubRepo` 同口径。
|
|
16
|
+
- **测试**:client-markdown 净增 4 例(协议相对两态、git@ 两形态、锚点四断言含 img kind 不锚)、installed 净增 1 例(repository 五形态含尾斜杠与子路径);锚点断言随新行为更新;全量 1185/1185、typecheck 零错误。纯客户端+host 只读字段透传变更,刷新页面即生效。
|
|
17
|
+
|
|
11
18
|
### 0.9.48 变更:README 实体解码 + 相对路径仓库基址锚定(0.9.47 实装反馈两连修)
|
|
12
19
|
|
|
13
20
|
- **HTML 实体解码**:0.9.47 解析了标签但未解码实体——dsh-task-board 类 README 徽章间独立成行的 ` ` 按字面漏出。现命名实体(nbsp/amp/lt/gt/quot/copy/mdash/箭头/分数等 60+ 高频集)与数字实体(十进制/十六进制)均解码;文本段与 HTML 属性值都解(徽章 src 里 `&labelColor` → `&labelColor`,shields 参数不再丢失);`code`/`pre` 内不解码;未知实体与裸 `&` 原样保留;单趟解码不回炉(`&lt;` → `<` 文本,与浏览器一致),解码结果只作为文本节点、绝不重新参与标签解析,无注入面。
|
|
@@ -364,6 +371,13 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
364
371
|
|
|
365
372
|
## English
|
|
366
373
|
|
|
374
|
+
### Added in 0.9.49 — installed-view repo base + three link normalizations (follow-up to the 0.9.48 deep-dive)
|
|
375
|
+
|
|
376
|
+
- **Installed-view base wired through (P0, the main gap)**: the 0.9.48 installed-detail mount passed a non-existent `it.github`, and installed plugins take the local-read path (the `repo` field only rides on the npm fallback) → every relative link in installed READMEs collapsed to `#`. Now passes `vm.githubRepo` — the ready three-level fallback in the installed view model (registry match `registryGithub` → installed package.json `repository` parse → install spec `github:o/r` parse), which the icon and LinksRow already consumed. Relative links and images now anchor in the installed-browsing scenario too.
|
|
377
|
+
- **Link normalizations (P1)**: ① protocol-relative `//host/x` gains `https:` — previously mangled into a repo path with a base, or pointed at the DSH origin without; ② inline `git@github.com:o/r(.git)` links normalize to https form (clone-instruction paragraphs); ③ with a base, `#anchor` anchors to `github.com/<o>/<r>#anchor` (same-name anchor on the repo home README; bare `#` and the img kind do not participate).
|
|
378
|
+
- **Host-side parse alignment (P2)**: `githubRepoFromRepository` tail relaxed from `$` to `[/?#]` — `github.com/o/r/` (trailing slash) and deeper paths like `…/tree/main` previously failed to parse; now aligned with versions.ts `extractGithubRepo`.
|
|
379
|
+
- **Testing**: 4 new cases in client-markdown (protocol-relative both modes, git@ two shapes, four anchor assertions incl. img kind), 1 new installed case (five repository shapes incl. trailing slash and subpath); the anchor assertion updated to the new behavior; full suite 1185/1185, typecheck clean. Client-only plus a read-only host passthrough — a page refresh takes effect.
|
|
380
|
+
|
|
367
381
|
### Added in 0.9.48 — README entity decoding + repo-base anchoring for relative paths (two fixes from 0.9.47 field feedback)
|
|
368
382
|
|
|
369
383
|
- **HTML entity decoding**: 0.9.47 parsed tags but left entities raw — standalone ` ` lines between badges (dsh-task-board-style READMEs) leaked literally. Named entities (nbsp/amp/lt/gt/quot/copy/mdash/arrows/fractions — 60+ common set) and numeric entities (decimal/hex) now decode; both text runs and HTML attribute values decode (badge src `&labelColor` → `&labelColor`, shields params no longer dropped); `code`/`pre` content stays literal; unknown entities and bare `&` are preserved; single-pass decoding without re-processing (`&lt;` → `<` as text, matching browsers). Decoded output only ever becomes text nodes — never re-parsed as tags, no injection surface.
|
package/docs/DESIGN.md
CHANGED
|
@@ -182,7 +182,7 @@ npm 安装 / GitHub 安装 / 升级 / 自升级 / 卸载是**同一个事务模
|
|
|
182
182
|
技术:`src/client.js` 经 **esbuild** 打包为 `lib/client.js`;`window.__ModuleLoader__.load({ id: "dsh-m", factory })` 注册;**React 从 module loader require**(零额外运行时依赖);manifest 注入 `@deepseek-ai/dsh-client-runtime`、`@deepseek-ai/dsh-client-ui-slots`、`@deepseek-ai/dsh-client-ui-settings`。
|
|
183
183
|
图标:GitHub 来源自动用 `https://github.com/<owner>.png?size=64`;`icon` 字段可覆盖;npm-only 条目首字母色块回退。
|
|
184
184
|
|
|
185
|
-
**README 预览渲染(`src/client/markdown.js`,0.9.47 起)**:自研轻量渲染器,安全模型 = 「白名单标签 + 白名单属性 + safeUrl 闸门 → 全部经 `h()` 构造 React 元素」,**绝不注入原始 HTML 字符串**(无 `dangerouslySetInnerHTML`,文本节点 React 转义兜底)。markdown 侧支持标题/列表/表格/围栏/引用/徽章链接等;HTML 侧支持 GitHub 风 README 常见内嵌子集——块级包裹标签(`p/div/center/details/table/tr/td/li/ul/ol/h1-6` 等)剥壳后渲染:内容纯行内(无空行分段/无 markdown 块结构/行首均为行内标签)时整块行走内 token 流(徽章 + ` ` 连排一行,GitHub 语义,0.9.48),否则按 markdown 递归(保内部结构);行内标签(`a/img/strong/em/code/kbd/mark/br/sub/sup` 等)token 化渲染,`align` 属性映射 `textAlign`、`<img width/height>` 映射显式尺寸(放开徽章 20px 高度帽);未知标签剥壳留文本,`script/style/svg/iframe` 等容器连同内容丢弃,`javascript:` 等危险 URL 归 `#`。**HTML 实体解码(0.9.48)**:命名(60+ 高频集)+ 数字(十/十六进制),文本段与属性值都解、`code/pre` 不解、单趟不回炉、解码结果仅作文本节点。**仓库基址锚定(0.9.48)**:`renderMarkdown(src, { repo: "owner/repo" })` 后相对链接锚 `github.com/<o>/<r>/blob/HEAD/`、相对图片锚 `raw.githubusercontent.com/<o>/<r>/HEAD/`;基址来源 = npm packument `repository`(host-api readme 结果 `repo` 字段,仅 GitHub 归一)> 卡片 `github` 字段;无基址时相对路径归 `#`(0.9.47
|
|
185
|
+
**README 预览渲染(`src/client/markdown.js`,0.9.47 起)**:自研轻量渲染器,安全模型 = 「白名单标签 + 白名单属性 + safeUrl 闸门 → 全部经 `h()` 构造 React 元素」,**绝不注入原始 HTML 字符串**(无 `dangerouslySetInnerHTML`,文本节点 React 转义兜底)。markdown 侧支持标题/列表/表格/围栏/引用/徽章链接等;HTML 侧支持 GitHub 风 README 常见内嵌子集——块级包裹标签(`p/div/center/details/table/tr/td/li/ul/ol/h1-6` 等)剥壳后渲染:内容纯行内(无空行分段/无 markdown 块结构/行首均为行内标签)时整块行走内 token 流(徽章 + ` ` 连排一行,GitHub 语义,0.9.48),否则按 markdown 递归(保内部结构);行内标签(`a/img/strong/em/code/kbd/mark/br/sub/sup` 等)token 化渲染,`align` 属性映射 `textAlign`、`<img width/height>` 映射显式尺寸(放开徽章 20px 高度帽);未知标签剥壳留文本,`script/style/svg/iframe` 等容器连同内容丢弃,`javascript:` 等危险 URL 归 `#`。**HTML 实体解码(0.9.48)**:命名(60+ 高频集)+ 数字(十/十六进制),文本段与属性值都解、`code/pre` 不解、单趟不回炉、解码结果仅作文本节点。**仓库基址锚定(0.9.48)**:`renderMarkdown(src, { repo: "owner/repo" })` 后相对链接锚 `github.com/<o>/<r>/blob/HEAD/`、相对图片锚 `raw.githubusercontent.com/<o>/<r>/HEAD/`;基址来源 = npm packument `repository`(host-api readme 结果 `repo` 字段,仅 GitHub 归一)> 卡片 `github` 字段;无基址时相对路径归 `#`(0.9.47 前行为)。**链接归一(0.9.49)**:协议相对 `//host/x` 补 `https:`;`git@github.com:o/r(.git)` 内联归一 https 形态;有基址时 `#anchor` 锚 `github.com/<o>/<r>#anchor`(裸 `#` 与 img kind 不锚);已装视图挂载点改传 `vm.githubRepo`(installed-view 三级兜底:registryGithub → 已装包 repository 解析 → spec 解析;0.9.48 曾误传不存在的 `it.github` 致已装 README 相对链接全归 `#`);host 侧 `githubRepoFromRepository` 尾部放宽到 `[/?#]`(与 versions.ts `extractGithubRepo` 同口径)。已知边界:monorepo 子目录 README 的相对路径锚到仓库根(packument 不携带子目录信息);绝对 URL 不受锚定影响。数据源:已装条目读 profile 本地 `README.md`(≤64KB 截断);未装条目回源 npm packument 顶层 `readme` 字段(0.9.45 U10b)。
|
|
186
186
|
|
|
187
187
|
## 5. Agent 工具(host)与 CLI
|
|
188
188
|
|
package/lib/client.js
CHANGED
|
@@ -410,9 +410,16 @@ function normalizeRepoInput(v) {
|
|
|
410
410
|
return m ? `${m[1]}/${m[2]}` : "";
|
|
411
411
|
}
|
|
412
412
|
function safeUrl(u, kind) {
|
|
413
|
-
|
|
413
|
+
let t = String(u || "").trim();
|
|
414
|
+
if (!t) return "#";
|
|
415
|
+
if (t.startsWith("//")) t = `https:${t}`;
|
|
416
|
+
const ghm = /^git@github\.com:([^/\s]+)\/([^\s]+?)(?:\.git)?$/i.exec(t);
|
|
417
|
+
if (ghm) t = `https://github.com/${ghm[1]}/${ghm[2]}`;
|
|
414
418
|
if (/^(https?:\/\/|mailto:)/i.test(t)) return t;
|
|
415
|
-
if (t.startsWith("#"))
|
|
419
|
+
if (t.startsWith("#")) {
|
|
420
|
+
if (t.length > 1 && RENDER_REPO && kind === "link") return `https://github.com/${RENDER_REPO}#${t.slice(1)}`;
|
|
421
|
+
return t;
|
|
422
|
+
}
|
|
416
423
|
if (RENDER_REPO && (kind === "img" || kind === "link")) {
|
|
417
424
|
const path = t.replace(/^(?:\.\/|\.\.\/|\/)+/, "");
|
|
418
425
|
return kind === "img" ? `https://raw.githubusercontent.com/${RENDER_REPO}/HEAD/${path}` : `https://github.com/${RENDER_REPO}/blob/HEAD/${path}`;
|
|
@@ -3560,7 +3567,7 @@ function InstalledTab({ notify, installed, updates, onMutation, ops }) {
|
|
|
3560
3567
|
}),
|
|
3561
3568
|
open: openPkg === it.pkg,
|
|
3562
3569
|
onToggle: () => setOpenPkg(openPkg === it.pkg ? null : it.pkg),
|
|
3563
|
-
detail: readmePkg === it.pkg ? h(ReadmeBlock, { pkg: it.pkg, repo:
|
|
3570
|
+
detail: readmePkg === it.pkg ? h(ReadmeBlock, { pkg: it.pkg, repo: vm.githubRepo }) : DetailRows([
|
|
3564
3571
|
[lookup("detail.pkg"), it.pkg],
|
|
3565
3572
|
[lookup("detail.spec"), it.spec],
|
|
3566
3573
|
[lookup("detail.latest"), vm.latestLabelDetail],
|
package/lib/core/installed.js
CHANGED
|
@@ -52,7 +52,9 @@ export function resolvePluginDir(profileDir, pkg, spec) {
|
|
|
52
52
|
}
|
|
53
53
|
return join(resolve(profileDir), 'node_modules', pkg);
|
|
54
54
|
}
|
|
55
|
-
/** 从 repository 字段(字符串或 {url},git+/ssh/https 形态)提取 github owner/repo。
|
|
55
|
+
/** 从 repository 字段(字符串或 {url},git+/ssh/https 形态)提取 github owner/repo。
|
|
56
|
+
* 0.9.49:尾部放宽到 [/?#] 或结尾(与 versions.ts extractGithubRepo 同口径)——
|
|
57
|
+
* 此前 github.com/o/r/(尾斜杠)与更深路径解析不出。 */
|
|
56
58
|
export function githubRepoFromRepository(raw) {
|
|
57
59
|
let url = '';
|
|
58
60
|
if (typeof raw === 'string')
|
|
@@ -62,7 +64,7 @@ export function githubRepoFromRepository(raw) {
|
|
|
62
64
|
if (typeof u === 'string')
|
|
63
65
|
url = u;
|
|
64
66
|
}
|
|
65
|
-
const m = /github\.com[/:]([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+?)(?:\.git)
|
|
67
|
+
const m = /github\.com[/:]([A-Za-z0-9._-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?(?:[/?#]|$)/i.exec(url.trim());
|
|
66
68
|
return m ? `${m[1]}/${m[2]}` : null;
|
|
67
69
|
}
|
|
68
70
|
/** JSON 合法根:非 null、非数组的对象(typeof [] === 'object',数组必须显式排除)。 */
|