@michengai/dsh-skills-manager 1.2.33 → 1.2.35

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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.35] - 2026-11-06
4
+
5
+ ### Behavior Changes
6
+
7
+ - **Skill repositories are fetched on demand, and size limits apply while downloading**:
8
+ - every repository source now downloads only the skill directories, so README images and other unrelated assets no longer count; this requires Git on the machine, and adding a repository asks you to install Git when it is missing;
9
+ - size limits take effect during the transfer: free disk space is checked first, and an oversized repository stops immediately with the real limit and the actual size instead of failing after the download;
10
+ - installing reuses the already scanned checkout, so nothing is downloaded twice;
11
+ - upgrade note: the first install from a repository added before this version shows "repository cache missing or expired, refresh the repository and retry" — one refresh migrates it.
12
+
13
+ [中文文档](CHANGELOG.zh-CN.md)
14
+
15
+ ## [1.2.34] - 2026-11-06
16
+
17
+ ### Improvements
18
+
19
+ - **Load large skill repositories without size-limit errors** (Issue #79):
20
+ - GitHub repositories are now fetched on demand: only directories containing `SKILL.md` are downloaded, so README screenshots and other unrelated assets no longer count against the size limit (the reported 235 MiB repository now transfers about 20 MiB while listing all 177 skills);
21
+ - Repository scanning and installation are no longer capped by the old 32 MiB archive limit; when no usable local Git is available, the plugin falls back to the previous full-archive download;
22
+ - The snapshot version badge now shows the Git commit of GitHub repositories.
23
+
24
+ [中文文档](CHANGELOG.zh-CN.md)
25
+
3
26
  ## [1.2.33] - 2026-11-05
4
27
 
5
28
  ### Improvements
@@ -1,5 +1,28 @@
1
1
  # 更新日志
2
2
 
3
+ ## [1.2.35] - 2026-11-06
4
+
5
+ ### 行为变更
6
+
7
+ - **技能仓库统一按需检出,体积限制不再事后才报**:
8
+ - 所有仓库来源都只下载技能目录,仓库首页配图等无关内容不参与下载;这需要本机已安装 Git,未安装时添加仓库会直接提示安装;
9
+ - 体积上限在下载过程中生效:开始前先检查磁盘剩余空间,超出上限立即停止并给出实际上限与实际体积,不再等下载结束才失败;
10
+ - 已扫描的仓库在安装时直接复用本地检出结果,不再重复下载;
11
+ - 升级提示:旧仓库首次安装会提示「仓库缓存缺失或已失效,请刷新该仓库后重试」,点一次刷新即可完成迁移。
12
+
13
+ [English](CHANGELOG.md)
14
+
15
+ ## [1.2.34] - 2026-11-06
16
+
17
+ ### 体验优化
18
+
19
+ - **大体积技能仓库不再报体积超限**(Issue #79):
20
+ - GitHub 仓库改为按需检出:只下载包含 `SKILL.md` 的技能目录,仓库首页截图等无关文件不再计入体积限制(反馈中的 235 MiB 仓库现在只传输约 20 MiB,即可列出全部 177 个技能);
21
+ - 仓库扫描与安装不再受旧的 32 MiB 归档上限约束;本机没有可用 Git 时自动回落为整库下载;
22
+ - 扫描版本标识改为显示 GitHub 仓库的 Git 提交。
23
+
24
+ [English](CHANGELOG.md)
25
+
3
26
  ## [1.2.33] - 2026-11-05
4
27
 
5
28
  ### 交互体验优化
package/README.en.md CHANGED
@@ -73,7 +73,7 @@ dsh plugin --profile web add @michengai/dsh-skills-manager@latest --registry=htt
73
73
 
74
74
  Restart DSH, refresh the page, and open **Settings → Skills**. To update, select **Check for updates** or run the installation command again.
75
75
 
76
- - Plugin `1.2.33` is tested with DeepSeek Harness `0.2.0-rc.1`, `0.2.0-rc.2`, `0.2.1-rc.1`, `0.2.1-rc.2`, `0.2.1-rc.3`, `0.2.1-rc.4`, `0.2.1-rc.5`, `0.2.2-rc.1`.
76
+ - Plugin `1.2.35` is tested with DeepSeek Harness `0.2.0-rc.1`, `0.2.0-rc.2`, `0.2.1-rc.1`, `0.2.1-rc.2`, `0.2.1-rc.3`, `0.2.1-rc.4`, `0.2.1-rc.5`, `0.2.2-rc.1`.
77
77
  - Host compatibility: Full DeepSeek Harness `0.2.x` line (`>=0.2.0-rc.1 <0.3.0-0`), forwards-compatible with subsequent `0.2.x` RC releases without requiring routine plugin version bumps. Legacy versions and breaking changes in the `0.3.0` generation are rejected by the version gate. If you still use a `0.1.x` host, install plugin `1.1.23` instead of `@latest`.
78
78
  - **Reverse proxy deployment**: Supports hosting DSH behind prefix-stripping reverse proxies (e.g. `/app/dsh/`). API and update endpoints resolve against the page base URI (`document.baseURI`).
79
79
 
@@ -159,7 +159,7 @@ The DeepSeek Harness loader enforces strict identifier policies:
159
159
 
160
160
  - The header **Check for updates** updates the plugin itself; repository **Refresh** checks subscribed skill contents without replacing local files.
161
161
  - Repository installation can target user DSH skills, Shared Agent (`~/.agents/skills`, overridable via `DSH_AGENTS_HOME`), or `<project>/.dsh/skills` for registered workspaces. Unsafe paths and external agent roots (Codex, Claude) are locked against writes.
162
- - 32 MiB archive limit; downloading subdirectories still fetches the full archive.
162
+ - All repository sources are fetched through Git on demand: only directories containing `SKILL.md` are downloaded, so README images and other unrelated assets are skipped (a subdirectory narrows the scope further). Without a usable local Git, repositories cannot be added and the plugin asks you to install Git.
163
163
  - Local edits are detected and require explicit confirmation before overwriting; backup history is preserved for rollback.
164
164
 
165
165
  ## Supported Agent directories
package/README.md CHANGED
@@ -73,7 +73,7 @@ dsh plugin --profile web add @michengai/dsh-skills-manager@latest --registry=htt
73
73
 
74
74
  安装后重启 DSH 并刷新页面,打开「设置 → 技能」即可使用。更新时可点击「检查更新」,或重新执行安装命令。
75
75
 
76
- - `1.2.33` 已验证兼容 DeepSeek Harness `0.2.0-rc.1`、`0.2.0-rc.2`、`0.2.1-rc.1`、`0.2.1-rc.2`、`0.2.1-rc.3`、`0.2.1-rc.4`、`0.2.1-rc.5`、`0.2.2-rc.1`。
76
+ - `1.2.35` 已验证兼容 DeepSeek Harness `0.2.0-rc.1`、`0.2.0-rc.2`、`0.2.1-rc.1`、`0.2.1-rc.2`、`0.2.1-rc.3`、`0.2.1-rc.4`、`0.2.1-rc.5`、`0.2.2-rc.1`。
77
77
  - 宿主支持范围:DeepSeek Harness `0.2.x` 全系列(`>=0.2.0-rc.1 <0.3.0-0`),自动支持后续全部 0.2.x RC 版本,同代宿主升级无需重复等待发版。早期版本与 `0.3.0` 代际破坏性更新由版本门拦截。仍在使用 `0.1.x` 的,请安装插件 `1.1.23`,不要装 `@latest`。
78
78
  - **反向代理部署**:支持将 DSH 部署在带路径前缀的反向代理后面(如 `/app/dsh/`),插件 API 统一自动按页面基址(`document.baseURI`)相对解析。
79
79
 
@@ -159,7 +159,7 @@ DeepSeek Harness 宿主加载机制对技能标识符遵循规范命名约束:
159
159
 
160
160
  - 顶栏「检查更新」用于更新技能管理器插件自身;仓库区「刷新」仅检查技能仓库内容更新,不自动覆盖本地。
161
161
  - 仓库安装可以写入用户目录下的 DSH skills 或公共 Agent(`~/.agents/skills`,可用 `DSH_AGENTS_HOME` 覆盖),也可以写入已登记工作区的 `<项目根>/.dsh/skills`。选择器显示实际配置路径,并禁用不安全路径;缺少的目录仅在确认安装后创建。不能安装到 Codex、Claude 等其他 Agent 目录。
162
- - 归档上限 32 MiB,指定子目录也需下载整库。
162
+ - 所有仓库来源统一走 Git 按需检出:只下载包含 `SKILL.md` 的技能目录,仓库首页配图等无关内容不参与下载(指定子目录可进一步缩小范围);本机没有可用 Git 时无法添加仓库,会直接提示先安装 Git。
163
163
  - 更新前检测本地修改,覆盖必须明确确认;历史备份不自动清理,可随时恢复上一版。
164
164
 
165
165
  ## 支持的 Agent 目录
package/README.zh-CN.md CHANGED
@@ -73,7 +73,7 @@ dsh plugin --profile web add @michengai/dsh-skills-manager@latest --registry=htt
73
73
 
74
74
  安装后重启 DSH 并刷新页面,打开「设置 → 技能」即可使用。更新时可点击「检查更新」,或重新执行安装命令。
75
75
 
76
- - `1.2.33` 已验证兼容 DeepSeek Harness `0.2.0-rc.1`、`0.2.0-rc.2`、`0.2.1-rc.1`、`0.2.1-rc.2`、`0.2.1-rc.3`、`0.2.1-rc.4`、`0.2.1-rc.5`、`0.2.2-rc.1`。
76
+ - `1.2.35` 已验证兼容 DeepSeek Harness `0.2.0-rc.1`、`0.2.0-rc.2`、`0.2.1-rc.1`、`0.2.1-rc.2`、`0.2.1-rc.3`、`0.2.1-rc.4`、`0.2.1-rc.5`、`0.2.2-rc.1`。
77
77
  - 宿主支持范围:DeepSeek Harness `0.2.x` 全系列(`>=0.2.0-rc.1 <0.3.0-0`),自动支持后续全部 0.2.x RC 版本,同代宿主升级无需重复等待发版。早期版本与 `0.3.0` 代际破坏性更新由版本门拦截。仍在使用 `0.1.x` 的,请安装插件 `1.1.23`,不要装 `@latest`。
78
78
  - **反向代理部署**:支持将 DSH 部署在带路径前缀的反向代理后面(如 `/app/dsh/`),插件 API 统一自动按页面基址(`document.baseURI`)相对解析。
79
79
 
@@ -159,7 +159,7 @@ DeepSeek Harness 宿主加载机制对技能标识符遵循规范命名约束:
159
159
 
160
160
  - 顶栏「检查更新」用于更新技能管理器插件自身;仓库区「刷新」仅检查技能仓库内容更新,不自动覆盖本地。
161
161
  - 仓库安装可以写入用户目录下的 DSH skills 或公共 Agent(`~/.agents/skills`,可用 `DSH_AGENTS_HOME` 覆盖),也可以写入已登记工作区的 `<项目根>/.dsh/skills`。选择器显示实际配置路径,并禁用不安全路径;缺少的目录仅在确认安装后创建。不能安装到 Codex、Claude 等其他 Agent 目录。
162
- - 归档上限 32 MiB,指定子目录也需下载整库。
162
+ - 所有仓库来源统一走 Git 按需检出:只下载包含 `SKILL.md` 的技能目录,仓库首页配图等无关内容不参与下载(指定子目录可进一步缩小范围);本机没有可用 Git 时无法添加仓库,会直接提示先安装 Git。
163
163
  - 更新前检测本地修改,覆盖必须明确确认;历史备份不自动清理,可随时恢复上一版。
164
164
 
165
165
  ## 支持的 Agent 目录
package/lib/client.js CHANGED
@@ -1,7 +1,7 @@
1
1
  window.__ModuleLoader__.load({ id: "@michengai/dsh-skills-manager", factory: (require) => {
2
2
  var module = { exports: {} };
3
3
  var exports = module.exports;
4
- "use strict";var Fo=Object.create;var Xr=Object.defineProperty;var Vo=Object.getOwnPropertyDescriptor;var Wo=Object.getOwnPropertyNames;var Ko=Object.getPrototypeOf,qo=Object.prototype.hasOwnProperty;var Qo=(t,e,i,l)=>{if(e&&typeof e=="object"||typeof e=="function")for(let p of Wo(e))!qo.call(t,p)&&p!==i&&Xr(t,p,{get:()=>e[p],enumerable:!(l=Vo(e,p))||l.enumerable});return t};var na=(t,e,i)=>(i=t!=null?Fo(Ko(t)):{},Qo(e||!t||!t.__esModule?Xr(i,"default",{value:t,enumerable:!0}):i,t));var Fa=na(require("react"),1);var Dr={zh:{"repo.catalog.unknownLocation":"\u4F4D\u7F6E\u672A\u77E5","repo.catalog.reassociate":"\u9009\u62E9\u4F4D\u7F6E\u5E76\u91CD\u5173\u8054\u5B89\u88C5","repo.catalog.unknownHint":"\u6709\u65E7\u76EE\u5F55\u5B89\u88C5\u8BB0\u5F55\u4F4D\u7F6E\u672A\u77E5\uFF1B\u627E\u5230\u5BF9\u5E94\u6280\u80FD\u540E\u53EF\u9009\u62E9\u4F4D\u7F6E\u91CD\u5173\u8054\u5B89\u88C5\u3002","repo.catalog.loadMore":"\u518D\u52A0\u8F7D 10 \u6761","repo.catalog.installRefreshWarning":"\u6280\u80FD\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\uFF0C\u4F46\u5217\u8868\u5237\u65B0\u5931\u8D25\u3002\u8BF7\u91CD\u65B0\u6253\u5F00\u53D1\u73B0\u9875\uFF1B\u4E0D\u8981\u91CD\u590D\u5B89\u88C5\u3002","repo.catalog.uninstallRefreshWarning":"\u6280\u80FD\u5DF2\u79FB\u5165\u56DE\u6536\u7AD9\uFF0C\u4F46\u5217\u8868\u5237\u65B0\u5931\u8D25\u3002\u8BF7\u5237\u65B0\u6280\u80FD\u5217\u8868\u6216\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\uFF1B\u4E0D\u8981\u91CD\u590D\u5378\u8F7D\u3002","repo.installElsewhere":"\u5B89\u88C5\u5230\u5176\u4ED6\u4F4D\u7F6E","repo.destinationUnavailable":"\u539F\u9879\u76EE\u672A\u767B\u8BB0\u6216\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u7BA1\u7406\u6B64\u526F\u672C\u3002\u8BF7\u5728\u4FA7\u680F\u91CD\u65B0\u767B\u8BB0\u539F\u9879\u76EE\u540E\u5237\u65B0\u3002","repo.scope.user":"\u5168\u5C40","repo.scope.project":"\u9879\u76EE","repo.source.dsh":"DSH","repo.source.agents":"Shared Agent","repo.refreshing":"\u6B63\u5728\u68C0\u67E5\u66F4\u65B0\u2026","repo.refreshed":"\u5237\u65B0\u4E0E\u66F4\u65B0\u68C0\u67E5\u5B8C\u6210","repo.partialRefreshFailed":"\u90E8\u5206\u4ED3\u5E93\u68C0\u67E5\u66F4\u65B0\u5931\u8D25\uFF08{names}\uFF09\uFF0C\u5176\u4F59\u5DF2\u5B8C\u6210","repo.detailLoading":"\u6B63\u5728\u8BFB\u53D6\u6280\u80FD\u8BF4\u660E\u2026","repo.local":"\u672C\u673A","repo.source":"\u5B89\u88C5\u6765\u6E90","repo.update":"\u53EF\u66F4\u65B0","repo.review":"\u67E5\u770B\u66F4\u65B0","repo.rollback":"\u6062\u590D\u4E0A\u4E00\u7248","repo.confirmUpdate":"\u5907\u4EFD\u5E76\u66F4\u65B0","repo.confirmRollback":"\u5907\u4EFD\u5E76\u6062\u590D","repo.overwrite":"\u5907\u4EFD\u672C\u5730\u4FEE\u6539\u5E76\u66FF\u6362","repo.modified":"\u68C0\u6D4B\u5230\u672C\u5730\u4FEE\u6539\u3002\u66FF\u6362\u4F1A\u8986\u76D6\u5F53\u524D\u6587\u4EF6\uFF0C\u539F\u6587\u4EF6\u5C06\u5B8C\u6574\u5907\u4EFD\uFF0C\u53EF\u6062\u590D\u3002","repo.noChanges":"\u6587\u4EF6\u5185\u5BB9\u6CA1\u6709\u53D8\u5316\u3002","repo.added":"\u65B0\u589E","repo.removed":"\u5220\u9664","repo.modifiedFile":"\u4FEE\u6539","repo.updating":"\u66F4\u65B0\u4E2D\u2026","repo.updateProgress":"\u6B63\u5728\u6821\u9A8C\u3001\u5907\u4EFD\u5E76\u66FF\u6362\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.updateSuccess":"\u66F4\u65B0\u5B8C\u6210\uFF0C\u5DF2\u4FDD\u7559\u4E0A\u4E00\u7248\u5907\u4EFD\u3002","repo.rollbackSuccess":"\u5DF2\u6062\u590D\u4E0A\u4E00\u7248\u3002","repo.manageUpdate":"\u7BA1\u7406\u66F4\u65B0","error.repo.modified":"\u5B58\u5728\u672C\u5730\u4FEE\u6539\uFF0C\u8BF7\u9884\u89C8\u5E76\u786E\u8BA4\u5907\u4EFD\u540E\u66FF\u6362\u3002","scope.repositories":"\u53D1\u73B0\u6280\u80FD","repo.add":"\u6DFB\u52A0\u4ED3\u5E93","repo.manage":"\u7BA1\u7406\u4ED3\u5E93","repo.refresh":"\u5237\u65B0\u5E76\u68C0\u67E5\u66F4\u65B0","repo.save":"\u6DFB\u52A0\u5E76\u626B\u63CF","repo.subsource.github":"Git \u4ED3\u5E93","repo.subsource.skillsh":"skills.sh","repo.subsource.clawhub":"ClawHub","repo.subsource.popular":"\u70ED\u95E8\u4E0B\u8F7D Top 100","repo.catalog.states":"\u5168\u90E8\u72B6\u6001","repo.catalog.uninstalled":"\u672A\u5B89\u88C5","repo.catalog.searchClawhub":"\u641C\u7D22 ClawHub \u6280\u80FD","repo.catalog.searchLoading":"\u6B63\u5728\u641C\u7D22 ClawHub\u2026","repo.catalog.searchEmpty":"\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 ClawHub \u6280\u80FD\u3002","repo.catalog.searchError":"ClawHub \u641C\u7D22\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002","repo.catalog.searchSkillsh":"\u641C\u7D22 skills.sh \u6280\u80FD","repo.catalog.skillshLoading":"\u6B63\u5728\u641C\u7D22 skills.sh\u2026","repo.catalog.skillshEmpty":"\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 skills.sh \u6280\u80FD\u3002","repo.catalog.skillshError":"skills.sh \u641C\u7D22\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002","repo.sort.installs":"\u5B89\u88C5\u91CF\u4ECE\u9AD8\u5230\u4F4E","repo.sort.name":"\u540D\u79F0 A-Z","repo.subsource.catalogNote":"ClawHub \u4E0B\u8F7D\u91CF\u699C \xB7 \u6700\u591A 100 \u6761\uFF0C\u4EC5\u5BF9\u5F53\u524D\u663E\u793A\u6761\u76EE\u6392\u5E8F","repo.catalog.empty":"ClawHub \u5F53\u524D\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\u3002","repo.catalog.loading":"\u6B63\u5728\u52A0\u8F7D ClawHub \u699C\u5355\u2026","repo.catalog.loadError":"ClawHub \u699C\u5355\u52A0\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002","repo.catalog.retry":"\u91CD\u8BD5","repo.catalog.loadingMore":"\u6B63\u5728\u52A0\u8F7D\u66F4\u591A\u2026","repo.catalog.downloads":"\u4E0B\u8F7D","repo.catalog.installs":"\u5B89\u88C5","repo.catalog.stars":"\u661F\u6807","repo.hint":"\u4ECE\u5DF2\u8BA2\u9605\u7684 Git \u4ED3\u5E93\u6216\u7B2C\u4E09\u65B9\u76EE\u5F55\u53D1\u73B0\u6280\u80FD\uFF0C\u5B89\u88C5\u5230\u7528\u6237\u76EE\u5F55\u7684 DSH skills \u6216 Shared Agent\uFF0C\u6216\u5DF2\u767B\u8BB0\u9879\u76EE\u7684 .dsh/skills\u3002","repo.footer":"\u5237\u65B0\u4F1A\u68C0\u67E5\u4ED3\u5E93\u4E0E\u6280\u80FD\u66F4\u65B0\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u66FF\u6362\u672C\u5730\u6587\u4EF6\u3002\u5386\u53F2\u5907\u4EFD\u4E0D\u4F1A\u81EA\u52A8\u6E05\u7406\uFF0C\u5360\u7528\u7A7A\u95F4\u4F1A\u968F\u66F4\u65B0\u589E\u52A0\u3002","repo.search":"\u641C\u7D22\u4ED3\u5E93\u6280\u80FD","repo.all":"\u5168\u90E8\u4ED3\u5E93","repo.states":"\u5168\u90E8\u72B6\u6001","repo.available":"\u53EF\u5B89\u88C5","repo.installed":"\u5DF2\u5B89\u88C5","repo.conflict":"\u540C\u540D\u51B2\u7A81","repo.invalid":"\u683C\u5F0F\u65E0\u6548","repo.install":"\u5B89\u88C5","repo.detail":"\u8BE6\u60C5","repo.installing":"\u5B89\u88C5\u4E2D\u2026","repo.installProgress":"\u6B63\u5728\u8BFB\u53D6\u5E76\u6821\u9A8C\u6280\u80FD\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.installSuccess":"\u5B89\u88C5\u6210\u529F\u5E76\u5DF2\u542F\u7528\uFF0C\u53EF\u5728\u5BF9\u8BDD\u4E2D\u7528\u659C\u6760\u8C03\u7528\u3002","repo.installDestination":"\u5B89\u88C5\u4F4D\u7F6E","repo.rootDsh":"DSH skills","repo.rootAgents":"Shared Agent","repo.rootDshHint":"\u4EC5\u4F9B DSH \u4F7F\u7528\uFF0C\u8DEF\u5F84\u4EE5\u5F53\u524D DSH_HOME \u4E3A\u51C6\u3002","repo.rootExternalHint":"\u4F7F\u7528\u8BE5\u76EE\u5F55\u7684\u5176\u4ED6 Agent \u4E5F\u80FD\u8BFB\u53D6\u6B64\u6280\u80FD\u3002","repo.installLocationsHint":"\u7528\u6237\u76EE\u5F55\u53EF\u9009 DSH skills \u6216 Shared Agent\uFF1B\u5DF2\u767B\u8BB0\u9879\u76EE\u4EC5\u5199\u5165 .dsh/skills\u3002\u9009\u62E9\u5668\u663E\u793A\u5B9E\u9645\u8DEF\u5F84\u3002\u7F3A\u5C11\u7684\u76EE\u5F55\u4F1A\u5728\u786E\u8BA4\u5B89\u88C5\u540E\u521B\u5EFA\u3002\u4E0D\u5B89\u5168\u7684\u8DEF\u5F84\u4E0D\u53EF\u9009\u3002","repo.uninstall":"\u5378\u8F7D","repo.confirmUninstall":"\u79FB\u81F3\u56DE\u6536\u7AD9","repo.uninstallHint":"\u4EC5\u5C06\u6B64\u4ED3\u5E93\u5DF2\u8DDF\u8E2A\u7684\u5B89\u88C5\u526F\u672C\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u5305\u62EC\u672C\u5730\u4FEE\u6539\u3002\u4E4B\u540E\u53EF\u5728\u56DE\u6536\u7AD9\u6062\u590D\u3002","repo.uninstallExternalWarning":"\u5378\u8F7D\u8BE5\u6280\u80FD\u4E5F\u4F1A\u5F71\u54CD\u4F7F\u7528\u6240\u9009\u76EE\u5F55\u7684\u5176\u4ED6 Agent\u3002","repo.uninstalling":"\u5378\u8F7D\u4E2D\u2026","repo.uninstallProgress":"\u6B63\u5728\u5C06\u5DF2\u5B89\u88C5\u7684\u6280\u80FD\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.uninstallSuccess":"\u6280\u80FD\u5DF2\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u53EF\u5728\u56DE\u6536\u7AD9\u6062\u590D\u3002","repo.empty":"\u8FD8\u6CA1\u6709\u6280\u80FD\u4ED3\u5E93\uFF0C\u6DFB\u52A0\u4E00\u4E2A Git \u4ED3\u5E93\u5F00\u59CB\u3002","repo.noSkills":"\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\u3002\u53EF\u5237\u65B0\u4ED3\u5E93\u6216\u8C03\u6574\u7B5B\u9009\u3002","repo.url":"\u4ED3\u5E93\u5730\u5740","repo.urlPlaceholder":"owner/repo \u6216\u5B8C\u6574 Git \u5730\u5740","repo.ref":"\u5206\u652F\u6216\u6807\u7B7E\uFF08\u53EF\u9009\uFF09","repo.directory":"\u6280\u80FD\u5B50\u76EE\u5F55\uFF08\u53EF\u9009\uFF09","repo.defaultBranch":"\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5206\u652F","repo.defaultBranchLabel":"\u9ED8\u8BA4\u5206\u652F","repo.directoryHint":"\u4F8B\u5982 skills\uFF0C\u7559\u7A7A\u626B\u63CF\u6574\u4E2A\u4ED3\u5E93","repo.remove":"\u79FB\u9664\u4ED3\u5E93","repo.removeHint":"\u4EC5\u79FB\u9664\u4ED3\u5E93\u8BA2\u9605\uFF0C\u5DF2\u5B89\u88C5\u7684\u6280\u80FD\u4F1A\u4FDD\u7559\u3002","repo.removeConfirm":"\u786E\u8BA4\u79FB\u9664","repo.cancel":"\u53D6\u6D88","repo.close":"\u5173\u95ED","repo.loading":"\u5904\u7406\u4E2D\u2026","repo.success":"\u64CD\u4F5C\u5B8C\u6210","repo.installHint":"\u6280\u80FD\u53EF\u80FD\u5305\u542B\u811A\u672C\uFF0C\u8BF7\u5148\u67E5\u770B\u8BF4\u660E\u5E76\u786E\u8BA4\u4FE1\u4EFB\u6765\u6E90\u3002\u5B89\u88C5\u4F1A\u4FDD\u7559\u8D44\u6E90\u6587\u4EF6\uFF0C\u4E0D\u4F1A\u6267\u884C\u811A\u672C\u3002","repo.commit":"\u626B\u63CF\u7248\u672C","repo.notScanned":"\u5C1A\u672A\u626B\u63CF","repo.updated":"\u4E0A\u6B21\u5237\u65B0","repo.copyBody":"\u590D\u5236\u6B63\u6587","repo.copied":"\u5DF2\u590D\u5236","repo.copyFailed":"\u590D\u5236\u5931\u8D25","error.repo.tooLarge":"\u4ED3\u5E93\u8D85\u8FC7\u5927\u5C0F\u9650\u5236\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u6280\u80FD\u4ED3\u5E93\u3002","error.repo.transientTooLarge":"\u4ED3\u5E93\u4E34\u65F6\u4E0B\u8F7D\u4F53\u79EF\u8FC7\u5927\uFF08\u5305\u542B Git \u5386\u53F2\u5BF9\u8C61\uFF09\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u6280\u80FD\u4ED3\u5E93\u6216\u63D0\u9AD8\u4E34\u65F6\u5927\u5C0F\u9650\u5236\u3002","error.repo.noGit":"\u672A\u68C0\u6D4B\u5230 Git \u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u5148\u5B89\u88C5 Git \u540E\u91CD\u8BD5\u3002","error.repo.installState":"\u6280\u80FD\u6587\u4EF6\u5DF2\u4FDD\u7559\uFF0C\u4F46\u6765\u6E90\u72B6\u6001\u672A\u786E\u8BA4\u3002\u8BF7\u6062\u590D\u78C1\u76D8\u5199\u5165\u540E\u91CD\u65B0\u6253\u5F00\u4ED3\u5E93\u9875\uFF0C\u7CFB\u7EDF\u4F1A\u6821\u9A8C\u6587\u4EF6\u5E76\u6062\u590D\u8BB0\u5F55\u3002","error.repo.capacity":"\u5B89\u88C5\u6765\u6E90\u72B6\u6001\u8D85\u8FC7 16 MiB\u3002\u8BF7\u5148\u6E05\u7406\u4E0D\u9700\u8981\u7684\u56DE\u6536\u8BB0\u5F55\u6216\u65E7\u8EAB\u4EFD\uFF0C\u4ECD\u6709\u6548\u7684\u5B89\u88C5\u526F\u672C\u4F1A\u4FDD\u7559\u3002","error.repo.invalid":"\u4ED3\u5E93\u5730\u5740\u3001\u8DEF\u5F84\u6216\u5185\u5BB9\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u8F93\u5165\u53CA\u4ED3\u5E93\u5927\u5C0F\u3002","error.repo.network":"\u4ED3\u5E93\u8BBF\u95EE\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u7A0D\u540E\u91CD\u8BD5\u3002\u4E0A\u6B21\u5217\u8868\u5DF2\u4FDD\u7559\u3002","error.repo.state":"\u4ED3\u5E93\u72B6\u6001\u6587\u4EF6\u635F\u574F\u6216\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u8BF7\u4FDD\u7559\u6587\u4EF6\u5E76\u4FEE\u590D\u540E\u91CD\u8BD5\u3002","error.repo.conflict":"\u540C\u540D\u6280\u80FD\u5DF2\u5B58\u5728\u6216\u5B89\u88C5\u5931\u8D25\uFF0C\u672C\u5730\u6587\u4EF6\u672A\u88AB\u8986\u76D6\u3002","error.repo.enableState":"\u6280\u80FD\u6587\u4EF6\u5DF2\u64A4\u9500\uFF0C\u4F46\u542F\u7528\u72B6\u6001\u65E0\u6CD5\u5199\u5165\u3002\u8BF7\u6062\u590D\u78C1\u76D8\u5199\u5165\u540E\u91CD\u8BD5\u5B89\u88C5\u3002"},en:{"repo.catalog.unknownLocation":"Location unknown","repo.catalog.reassociate":"Choose destination and reinstall to reassociate","repo.catalog.unknownHint":"Some legacy catalog installs have unknown locations. Find the skill and choose a destination to reinstall and reassociate.","repo.catalog.loadMore":"Load 10 more","repo.catalog.installRefreshWarning":"Installed and enabled, but the list could not refresh. Reopen Discover Skills; do not install again.","repo.catalog.uninstallRefreshWarning":"Moved to trash, but the list could not refresh. Refresh the skill list or reopen Settings; do not uninstall again.","repo.installElsewhere":"Install elsewhere","repo.destinationUnavailable":"The original project is unregistered or unavailable. Re-register it in the sidebar and refresh to manage this copy.","repo.scope.user":"Global","repo.scope.project":"Project","repo.source.dsh":"DSH","repo.source.agents":"Shared Agent","repo.refreshing":"Checking updates\u2026","repo.refreshed":"Refresh and update check completed","repo.partialRefreshFailed":"Failed to check updates for some repositories ({names}); others completed.","repo.detailLoading":"Loading skill instructions\u2026","repo.local":"Local","repo.source":"Installed from","repo.update":"Update available","repo.review":"Review update","repo.rollback":"Restore previous version","repo.confirmUpdate":"Back up and update","repo.confirmRollback":"Back up and restore","repo.overwrite":"Back up local edits and replace","repo.modified":"Local edits detected. Replacement overwrites current files and keeps a complete backup for restoration.","repo.noChanges":"No file changes.","repo.added":"Added","repo.removed":"Removed","repo.modifiedFile":"Modified","repo.updating":"Updating\u2026","repo.updateProgress":"Verifying, backing up and replacing files. Please wait\u2026","repo.updateSuccess":"Updated. Previous version backed up.","repo.rollbackSuccess":"Previous version restored.","repo.manageUpdate":"Manage updates","error.repo.modified":"Local edits detected. Review and confirm replacement with a backup.","scope.repositories":"Discover Skills","repo.add":"Add repository","repo.manage":"Manage repositories","repo.refresh":"Refresh & check updates","repo.save":"Add and scan","repo.subsource.github":"Git Repos","repo.subsource.skillsh":"skills.sh","repo.subsource.clawhub":"ClawHub","repo.subsource.popular":"Top 100 by downloads","repo.catalog.states":"All statuses","repo.catalog.uninstalled":"Not installed","repo.catalog.searchClawhub":"Search ClawHub skills","repo.catalog.searchLoading":"Searching ClawHub\u2026","repo.catalog.searchEmpty":"No matching ClawHub skills were found.","repo.catalog.searchError":"ClawHub search failed. Please retry.","repo.catalog.searchSkillsh":"Search skills.sh","repo.catalog.skillshLoading":"Searching skills.sh\u2026","repo.catalog.skillshEmpty":"No matching skills.sh skills were found.","repo.catalog.skillshError":"skills.sh search failed. Please retry.","repo.sort.installs":"Installs: high to low","repo.sort.name":"Name A\u2013Z","repo.subsource.catalogNote":"ClawHub download ranking \xB7 Up to 100; sort only displayed items","repo.catalog.empty":"No matching skills were returned by ClawHub.","repo.catalog.loading":"Loading ClawHub ranking\u2026","repo.catalog.loadError":"Failed to load the ClawHub ranking. Check your connection and retry.","repo.catalog.retry":"Retry","repo.catalog.loadingMore":"Loading more\u2026","repo.catalog.downloads":"downloads","repo.catalog.installs":"installs","repo.catalog.stars":"stars","repo.hint":"Discover skills from subscribed Git repositories or community registries, and install them to user DSH skills or Shared Agent, or a registered project's .dsh/skills.","repo.footer":"Refresh checks repositories and skill updates without replacing local files. Historical backups are not cleaned automatically and use additional disk space.","repo.search":"Search repository skills","repo.all":"All repositories","repo.states":"All statuses","repo.available":"Available","repo.installed":"Installed","repo.conflict":"Name conflict","repo.invalid":"Invalid format","repo.install":"Install","repo.detail":"Details","repo.installing":"Installing\u2026","repo.installProgress":"Reading and verifying skill files. Please wait\u2026","repo.installSuccess":"Installed and enabled. Invoke it from the slash menu.","repo.installDestination":"Installation destination","repo.rootDsh":"DSH skills","repo.rootAgents":"Shared Agent","repo.rootDshHint":"For DSH only. The path uses your current DSH_HOME.","repo.rootExternalHint":"Other agents using this directory can read this skill too.","repo.installLocationsHint":"User directories offer DSH skills or Shared Agent; registered projects write only to .dsh/skills. The chooser shows actual paths. Missing directories are created after confirmation. Unsafe paths cannot be selected.","repo.uninstall":"Uninstall","repo.confirmUninstall":"Move to Trash","repo.uninstallHint":"Move only this repository\u2019s tracked installed copy, including local edits, to Trash. You can restore it from Trash later.","repo.uninstallExternalWarning":"Uninstalling this skill also affects other agents that use the selected directory.","repo.uninstalling":"Uninstalling\u2026","repo.uninstallProgress":"Moving the installed skill to Trash. Please wait\u2026","repo.uninstallSuccess":"Skill moved to Trash. You can restore it from Trash.","repo.empty":"No repositories yet. Add a Git repository to get started.","repo.noSkills":"No matching skills. Refresh the repository or adjust your filters.","repo.url":"Repository URL","repo.urlPlaceholder":"owner/repo or full Git repository URL","repo.ref":"Branch or tag (optional)","repo.directory":"Skill subdirectory (optional)","repo.defaultBranch":"Leave empty for the default branch","repo.defaultBranchLabel":"default branch","repo.directoryHint":"For example: skills. Leave empty to scan the repository.","repo.remove":"Remove repository","repo.removeHint":"This removes the subscription only. Installed skills are kept.","repo.removeConfirm":"Confirm removal","repo.cancel":"Cancel","repo.close":"Close","repo.loading":"Working\u2026","repo.success":"Completed","repo.installHint":"Skills may include scripts. Read the instructions and trust the source before installing. Resources are copied; scripts are not executed.","repo.commit":"Snapshot version","repo.notScanned":"Not scanned yet","repo.updated":"Last refreshed","repo.copyBody":"Copy body","repo.copied":"Copied","repo.copyFailed":"Copy failed","error.repo.tooLarge":"Repository exceeds size limit. Choose a smaller repository.","error.repo.transientTooLarge":"Repository transient download size exceeds limit (including Git objects). Choose a smaller repository or increase temporary limit.","error.repo.noGit":"Git command-line tool not found. Please install Git and retry.","error.repo.installState":"Skill files were preserved but source tracking could not be saved. Restore disk write access and reopen Repositories to verify files and recover the record.","error.repo.capacity":"Source tracking exceeds 16 MiB. Remove unneeded Trash records or legacy identities first. Active installation copies are kept.","error.repo.invalid":"Invalid repository URL, path or contents. Check the input and repository size.","error.repo.network":"Repository request failed. Check your connection or retry later. The previous catalog was kept.","error.repo.state":"Repository state is corrupt or unreadable. Preserve the file and repair it before retrying.","error.repo.conflict":"A skill with this name exists or installation failed. Local files were not overwritten.","error.repo.enableState":"The copied skill was removed because its enabled state could not be saved. Restore disk write access and install again."}},Zo=`
4
+ "use strict";var Fo=Object.create;var Xr=Object.defineProperty;var Vo=Object.getOwnPropertyDescriptor;var Wo=Object.getOwnPropertyNames;var Ko=Object.getPrototypeOf,qo=Object.prototype.hasOwnProperty;var Qo=(t,e,i,l)=>{if(e&&typeof e=="object"||typeof e=="function")for(let p of Wo(e))!qo.call(t,p)&&p!==i&&Xr(t,p,{get:()=>e[p],enumerable:!(l=Vo(e,p))||l.enumerable});return t};var na=(t,e,i)=>(i=t!=null?Fo(Ko(t)):{},Qo(e||!t||!t.__esModule?Xr(i,"default",{value:t,enumerable:!0}):i,t));var Fa=na(require("react"),1);var Dr={zh:{"repo.catalog.unknownLocation":"\u4F4D\u7F6E\u672A\u77E5","repo.catalog.reassociate":"\u9009\u62E9\u4F4D\u7F6E\u5E76\u91CD\u5173\u8054\u5B89\u88C5","repo.catalog.unknownHint":"\u6709\u65E7\u76EE\u5F55\u5B89\u88C5\u8BB0\u5F55\u4F4D\u7F6E\u672A\u77E5\uFF1B\u627E\u5230\u5BF9\u5E94\u6280\u80FD\u540E\u53EF\u9009\u62E9\u4F4D\u7F6E\u91CD\u5173\u8054\u5B89\u88C5\u3002","repo.catalog.loadMore":"\u518D\u52A0\u8F7D 10 \u6761","repo.catalog.installRefreshWarning":"\u6280\u80FD\u5DF2\u5B89\u88C5\u5E76\u542F\u7528\uFF0C\u4F46\u5217\u8868\u5237\u65B0\u5931\u8D25\u3002\u8BF7\u91CD\u65B0\u6253\u5F00\u53D1\u73B0\u9875\uFF1B\u4E0D\u8981\u91CD\u590D\u5B89\u88C5\u3002","repo.catalog.uninstallRefreshWarning":"\u6280\u80FD\u5DF2\u79FB\u5165\u56DE\u6536\u7AD9\uFF0C\u4F46\u5217\u8868\u5237\u65B0\u5931\u8D25\u3002\u8BF7\u5237\u65B0\u6280\u80FD\u5217\u8868\u6216\u91CD\u65B0\u6253\u5F00\u8BBE\u7F6E\u9875\uFF1B\u4E0D\u8981\u91CD\u590D\u5378\u8F7D\u3002","repo.installElsewhere":"\u5B89\u88C5\u5230\u5176\u4ED6\u4F4D\u7F6E","repo.destinationUnavailable":"\u539F\u9879\u76EE\u672A\u767B\u8BB0\u6216\u76EE\u5F55\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u7BA1\u7406\u6B64\u526F\u672C\u3002\u8BF7\u5728\u4FA7\u680F\u91CD\u65B0\u767B\u8BB0\u539F\u9879\u76EE\u540E\u5237\u65B0\u3002","repo.scope.user":"\u5168\u5C40","repo.scope.project":"\u9879\u76EE","repo.source.dsh":"DSH","repo.source.agents":"Shared Agent","repo.refreshing":"\u6B63\u5728\u68C0\u67E5\u66F4\u65B0\u2026","repo.refreshed":"\u5237\u65B0\u4E0E\u66F4\u65B0\u68C0\u67E5\u5B8C\u6210","repo.partialRefreshFailed":"\u90E8\u5206\u4ED3\u5E93\u68C0\u67E5\u66F4\u65B0\u5931\u8D25\uFF08{names}\uFF09\uFF0C\u5176\u4F59\u5DF2\u5B8C\u6210","repo.detailLoading":"\u6B63\u5728\u8BFB\u53D6\u6280\u80FD\u8BF4\u660E\u2026","repo.local":"\u672C\u673A","repo.source":"\u5B89\u88C5\u6765\u6E90","repo.update":"\u53EF\u66F4\u65B0","repo.review":"\u67E5\u770B\u66F4\u65B0","repo.rollback":"\u6062\u590D\u4E0A\u4E00\u7248","repo.confirmUpdate":"\u5907\u4EFD\u5E76\u66F4\u65B0","repo.confirmRollback":"\u5907\u4EFD\u5E76\u6062\u590D","repo.overwrite":"\u5907\u4EFD\u672C\u5730\u4FEE\u6539\u5E76\u66FF\u6362","repo.modified":"\u68C0\u6D4B\u5230\u672C\u5730\u4FEE\u6539\u3002\u66FF\u6362\u4F1A\u8986\u76D6\u5F53\u524D\u6587\u4EF6\uFF0C\u539F\u6587\u4EF6\u5C06\u5B8C\u6574\u5907\u4EFD\uFF0C\u53EF\u6062\u590D\u3002","repo.noChanges":"\u6587\u4EF6\u5185\u5BB9\u6CA1\u6709\u53D8\u5316\u3002","repo.added":"\u65B0\u589E","repo.removed":"\u5220\u9664","repo.modifiedFile":"\u4FEE\u6539","repo.updating":"\u66F4\u65B0\u4E2D\u2026","repo.updateProgress":"\u6B63\u5728\u6821\u9A8C\u3001\u5907\u4EFD\u5E76\u66FF\u6362\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.updateSuccess":"\u66F4\u65B0\u5B8C\u6210\uFF0C\u5DF2\u4FDD\u7559\u4E0A\u4E00\u7248\u5907\u4EFD\u3002","repo.rollbackSuccess":"\u5DF2\u6062\u590D\u4E0A\u4E00\u7248\u3002","repo.manageUpdate":"\u7BA1\u7406\u66F4\u65B0","error.repo.modified":"\u5B58\u5728\u672C\u5730\u4FEE\u6539\uFF0C\u8BF7\u9884\u89C8\u5E76\u786E\u8BA4\u5907\u4EFD\u540E\u66FF\u6362\u3002","scope.repositories":"\u53D1\u73B0\u6280\u80FD","repo.add":"\u6DFB\u52A0\u4ED3\u5E93","repo.manage":"\u7BA1\u7406\u4ED3\u5E93","repo.refresh":"\u5237\u65B0\u5E76\u68C0\u67E5\u66F4\u65B0","repo.save":"\u6DFB\u52A0\u5E76\u626B\u63CF","repo.subsource.github":"Git \u4ED3\u5E93","repo.subsource.skillsh":"skills.sh","repo.subsource.clawhub":"ClawHub","repo.subsource.popular":"\u70ED\u95E8\u4E0B\u8F7D Top 100","repo.catalog.states":"\u5168\u90E8\u72B6\u6001","repo.catalog.uninstalled":"\u672A\u5B89\u88C5","repo.catalog.searchClawhub":"\u641C\u7D22 ClawHub \u6280\u80FD","repo.catalog.searchLoading":"\u6B63\u5728\u641C\u7D22 ClawHub\u2026","repo.catalog.searchEmpty":"\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 ClawHub \u6280\u80FD\u3002","repo.catalog.searchError":"ClawHub \u641C\u7D22\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002","repo.catalog.searchSkillsh":"\u641C\u7D22 skills.sh \u6280\u80FD","repo.catalog.skillshLoading":"\u6B63\u5728\u641C\u7D22 skills.sh\u2026","repo.catalog.skillshEmpty":"\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684 skills.sh \u6280\u80FD\u3002","repo.catalog.skillshError":"skills.sh \u641C\u7D22\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002","repo.sort.installs":"\u5B89\u88C5\u91CF\u4ECE\u9AD8\u5230\u4F4E","repo.sort.name":"\u540D\u79F0 A-Z","repo.subsource.catalogNote":"ClawHub \u4E0B\u8F7D\u91CF\u699C \xB7 \u6700\u591A 100 \u6761\uFF0C\u4EC5\u5BF9\u5F53\u524D\u663E\u793A\u6761\u76EE\u6392\u5E8F","repo.catalog.empty":"ClawHub \u5F53\u524D\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\u3002","repo.catalog.loading":"\u6B63\u5728\u52A0\u8F7D ClawHub \u699C\u5355\u2026","repo.catalog.loadError":"ClawHub \u699C\u5355\u52A0\u8F7D\u5931\u8D25\u3002\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5\u3002","repo.catalog.retry":"\u91CD\u8BD5","repo.catalog.loadingMore":"\u6B63\u5728\u52A0\u8F7D\u66F4\u591A\u2026","repo.catalog.downloads":"\u4E0B\u8F7D","repo.catalog.installs":"\u5B89\u88C5","repo.catalog.stars":"\u661F\u6807","repo.hint":"\u4ECE\u5DF2\u8BA2\u9605\u7684 Git \u4ED3\u5E93\u6216\u7B2C\u4E09\u65B9\u76EE\u5F55\u53D1\u73B0\u6280\u80FD\uFF0C\u5B89\u88C5\u5230\u7528\u6237\u76EE\u5F55\u7684 DSH skills \u6216 Shared Agent\uFF0C\u6216\u5DF2\u767B\u8BB0\u9879\u76EE\u7684 .dsh/skills\u3002","repo.footer":"\u5237\u65B0\u4F1A\u68C0\u67E5\u4ED3\u5E93\u4E0E\u6280\u80FD\u66F4\u65B0\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u66FF\u6362\u672C\u5730\u6587\u4EF6\u3002\u5386\u53F2\u5907\u4EFD\u4E0D\u4F1A\u81EA\u52A8\u6E05\u7406\uFF0C\u5360\u7528\u7A7A\u95F4\u4F1A\u968F\u66F4\u65B0\u589E\u52A0\u3002","repo.search":"\u641C\u7D22\u4ED3\u5E93\u6280\u80FD","repo.all":"\u5168\u90E8\u4ED3\u5E93","repo.states":"\u5168\u90E8\u72B6\u6001","repo.available":"\u53EF\u5B89\u88C5","repo.installed":"\u5DF2\u5B89\u88C5","repo.conflict":"\u540C\u540D\u51B2\u7A81","repo.invalid":"\u683C\u5F0F\u65E0\u6548","repo.install":"\u5B89\u88C5","repo.detail":"\u8BE6\u60C5","repo.installing":"\u5B89\u88C5\u4E2D\u2026","repo.installProgress":"\u6B63\u5728\u8BFB\u53D6\u5E76\u6821\u9A8C\u6280\u80FD\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.installSuccess":"\u5B89\u88C5\u6210\u529F\u5E76\u5DF2\u542F\u7528\uFF0C\u53EF\u5728\u5BF9\u8BDD\u4E2D\u7528\u659C\u6760\u8C03\u7528\u3002","repo.installDestination":"\u5B89\u88C5\u4F4D\u7F6E","repo.rootDsh":"DSH skills","repo.rootAgents":"Shared Agent","repo.rootDshHint":"\u4EC5\u4F9B DSH \u4F7F\u7528\uFF0C\u8DEF\u5F84\u4EE5\u5F53\u524D DSH_HOME \u4E3A\u51C6\u3002","repo.rootExternalHint":"\u4F7F\u7528\u8BE5\u76EE\u5F55\u7684\u5176\u4ED6 Agent \u4E5F\u80FD\u8BFB\u53D6\u6B64\u6280\u80FD\u3002","repo.installLocationsHint":"\u7528\u6237\u76EE\u5F55\u53EF\u9009 DSH skills \u6216 Shared Agent\uFF1B\u5DF2\u767B\u8BB0\u9879\u76EE\u4EC5\u5199\u5165 .dsh/skills\u3002\u9009\u62E9\u5668\u663E\u793A\u5B9E\u9645\u8DEF\u5F84\u3002\u7F3A\u5C11\u7684\u76EE\u5F55\u4F1A\u5728\u786E\u8BA4\u5B89\u88C5\u540E\u521B\u5EFA\u3002\u4E0D\u5B89\u5168\u7684\u8DEF\u5F84\u4E0D\u53EF\u9009\u3002","repo.uninstall":"\u5378\u8F7D","repo.confirmUninstall":"\u79FB\u81F3\u56DE\u6536\u7AD9","repo.uninstallHint":"\u4EC5\u5C06\u6B64\u4ED3\u5E93\u5DF2\u8DDF\u8E2A\u7684\u5B89\u88C5\u526F\u672C\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u5305\u62EC\u672C\u5730\u4FEE\u6539\u3002\u4E4B\u540E\u53EF\u5728\u56DE\u6536\u7AD9\u6062\u590D\u3002","repo.uninstallExternalWarning":"\u5378\u8F7D\u8BE5\u6280\u80FD\u4E5F\u4F1A\u5F71\u54CD\u4F7F\u7528\u6240\u9009\u76EE\u5F55\u7684\u5176\u4ED6 Agent\u3002","repo.uninstalling":"\u5378\u8F7D\u4E2D\u2026","repo.uninstallProgress":"\u6B63\u5728\u5C06\u5DF2\u5B89\u88C5\u7684\u6280\u80FD\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u8BF7\u7A0D\u5019\u2026","repo.uninstallSuccess":"\u6280\u80FD\u5DF2\u79FB\u81F3\u56DE\u6536\u7AD9\uFF0C\u53EF\u5728\u56DE\u6536\u7AD9\u6062\u590D\u3002","repo.empty":"\u8FD8\u6CA1\u6709\u6280\u80FD\u4ED3\u5E93\uFF0C\u6DFB\u52A0\u4E00\u4E2A Git \u4ED3\u5E93\u5F00\u59CB\u3002","repo.noSkills":"\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD\u3002\u53EF\u5237\u65B0\u4ED3\u5E93\u6216\u8C03\u6574\u7B5B\u9009\u3002","repo.url":"\u4ED3\u5E93\u5730\u5740","repo.urlPlaceholder":"owner/repo \u6216\u5B8C\u6574 Git \u5730\u5740","repo.ref":"\u5206\u652F\u6216\u6807\u7B7E\uFF08\u53EF\u9009\uFF09","repo.directory":"\u6280\u80FD\u5B50\u76EE\u5F55\uFF08\u53EF\u9009\uFF09","repo.defaultBranch":"\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u5206\u652F","repo.defaultBranchLabel":"\u9ED8\u8BA4\u5206\u652F","repo.directoryHint":"\u4F8B\u5982 skills\uFF0C\u7559\u7A7A\u626B\u63CF\u6574\u4E2A\u4ED3\u5E93","repo.remove":"\u79FB\u9664\u4ED3\u5E93","repo.removeHint":"\u4EC5\u79FB\u9664\u4ED3\u5E93\u8BA2\u9605\uFF0C\u5DF2\u5B89\u88C5\u7684\u6280\u80FD\u4F1A\u4FDD\u7559\u3002","repo.removeConfirm":"\u786E\u8BA4\u79FB\u9664","repo.cancel":"\u53D6\u6D88","repo.close":"\u5173\u95ED","repo.loading":"\u5904\u7406\u4E2D\u2026","repo.success":"\u64CD\u4F5C\u5B8C\u6210","repo.installHint":"\u6280\u80FD\u53EF\u80FD\u5305\u542B\u811A\u672C\uFF0C\u8BF7\u5148\u67E5\u770B\u8BF4\u660E\u5E76\u786E\u8BA4\u4FE1\u4EFB\u6765\u6E90\u3002\u5B89\u88C5\u4F1A\u4FDD\u7559\u8D44\u6E90\u6587\u4EF6\uFF0C\u4E0D\u4F1A\u6267\u884C\u811A\u672C\u3002","repo.commit":"\u626B\u63CF\u7248\u672C","repo.notScanned":"\u5C1A\u672A\u626B\u63CF","repo.updated":"\u4E0A\u6B21\u5237\u65B0","repo.copyBody":"\u590D\u5236\u6B63\u6587","repo.copied":"\u5DF2\u590D\u5236","repo.copyFailed":"\u590D\u5236\u5931\u8D25","error.repo.tooLarge":"\u4ED3\u5E93\u8D85\u8FC7\u5927\u5C0F\u9650\u5236\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u6280\u80FD\u4ED3\u5E93\u3002","error.repo.transientTooLarge":"\u4ED3\u5E93\u4E34\u65F6\u4E0B\u8F7D\u4F53\u79EF\u8FC7\u5927\uFF08\u5305\u542B Git \u5386\u53F2\u5BF9\u8C61\uFF09\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u6280\u80FD\u4ED3\u5E93\u3002","error.repo.disk":"\u78C1\u76D8\u5269\u4F59\u7A7A\u95F4\u4E0D\u8DB3\uFF0C\u65E0\u6CD5\u68C0\u51FA\u8BE5\u4ED3\u5E93\u3002\u8BF7\u6E05\u7406\u78C1\u76D8\u7A7A\u95F4\u540E\u91CD\u8BD5\u3002","error.repo.noGit":"\u672A\u68C0\u6D4B\u5230 Git \u547D\u4EE4\u884C\u5DE5\u5177\uFF0C\u8BF7\u5148\u5B89\u88C5 Git \u540E\u91CD\u8BD5\u3002","error.repo.installState":"\u6280\u80FD\u6587\u4EF6\u5DF2\u4FDD\u7559\uFF0C\u4F46\u6765\u6E90\u72B6\u6001\u672A\u786E\u8BA4\u3002\u8BF7\u6062\u590D\u78C1\u76D8\u5199\u5165\u540E\u91CD\u65B0\u6253\u5F00\u4ED3\u5E93\u9875\uFF0C\u7CFB\u7EDF\u4F1A\u6821\u9A8C\u6587\u4EF6\u5E76\u6062\u590D\u8BB0\u5F55\u3002","error.repo.capacity":"\u5B89\u88C5\u6765\u6E90\u72B6\u6001\u8D85\u8FC7 16 MiB\u3002\u8BF7\u5148\u6E05\u7406\u4E0D\u9700\u8981\u7684\u56DE\u6536\u8BB0\u5F55\u6216\u65E7\u8EAB\u4EFD\uFF0C\u4ECD\u6709\u6548\u7684\u5B89\u88C5\u526F\u672C\u4F1A\u4FDD\u7559\u3002","error.repo.invalid":"\u4ED3\u5E93\u5730\u5740\u3001\u8DEF\u5F84\u6216\u5185\u5BB9\u65E0\u6548\uFF0C\u8BF7\u68C0\u67E5\u8F93\u5165\u53CA\u4ED3\u5E93\u5927\u5C0F\u3002","error.repo.network":"\u4ED3\u5E93\u8BBF\u95EE\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u7A0D\u540E\u91CD\u8BD5\u3002\u4E0A\u6B21\u5217\u8868\u5DF2\u4FDD\u7559\u3002","error.repo.state":"\u4ED3\u5E93\u72B6\u6001\u6587\u4EF6\u635F\u574F\u6216\u65E0\u6CD5\u8BFB\u53D6\uFF0C\u8BF7\u4FDD\u7559\u6587\u4EF6\u5E76\u4FEE\u590D\u540E\u91CD\u8BD5\u3002","error.repo.conflict":"\u540C\u540D\u6280\u80FD\u5DF2\u5B58\u5728\u6216\u5B89\u88C5\u5931\u8D25\uFF0C\u672C\u5730\u6587\u4EF6\u672A\u88AB\u8986\u76D6\u3002","error.repo.enableState":"\u6280\u80FD\u6587\u4EF6\u5DF2\u64A4\u9500\uFF0C\u4F46\u542F\u7528\u72B6\u6001\u65E0\u6CD5\u5199\u5165\u3002\u8BF7\u6062\u590D\u78C1\u76D8\u5199\u5165\u540E\u91CD\u8BD5\u5B89\u88C5\u3002"},en:{"repo.catalog.unknownLocation":"Location unknown","repo.catalog.reassociate":"Choose destination and reinstall to reassociate","repo.catalog.unknownHint":"Some legacy catalog installs have unknown locations. Find the skill and choose a destination to reinstall and reassociate.","repo.catalog.loadMore":"Load 10 more","repo.catalog.installRefreshWarning":"Installed and enabled, but the list could not refresh. Reopen Discover Skills; do not install again.","repo.catalog.uninstallRefreshWarning":"Moved to trash, but the list could not refresh. Refresh the skill list or reopen Settings; do not uninstall again.","repo.installElsewhere":"Install elsewhere","repo.destinationUnavailable":"The original project is unregistered or unavailable. Re-register it in the sidebar and refresh to manage this copy.","repo.scope.user":"Global","repo.scope.project":"Project","repo.source.dsh":"DSH","repo.source.agents":"Shared Agent","repo.refreshing":"Checking updates\u2026","repo.refreshed":"Refresh and update check completed","repo.partialRefreshFailed":"Failed to check updates for some repositories ({names}); others completed.","repo.detailLoading":"Loading skill instructions\u2026","repo.local":"Local","repo.source":"Installed from","repo.update":"Update available","repo.review":"Review update","repo.rollback":"Restore previous version","repo.confirmUpdate":"Back up and update","repo.confirmRollback":"Back up and restore","repo.overwrite":"Back up local edits and replace","repo.modified":"Local edits detected. Replacement overwrites current files and keeps a complete backup for restoration.","repo.noChanges":"No file changes.","repo.added":"Added","repo.removed":"Removed","repo.modifiedFile":"Modified","repo.updating":"Updating\u2026","repo.updateProgress":"Verifying, backing up and replacing files. Please wait\u2026","repo.updateSuccess":"Updated. Previous version backed up.","repo.rollbackSuccess":"Previous version restored.","repo.manageUpdate":"Manage updates","error.repo.modified":"Local edits detected. Review and confirm replacement with a backup.","scope.repositories":"Discover Skills","repo.add":"Add repository","repo.manage":"Manage repositories","repo.refresh":"Refresh & check updates","repo.save":"Add and scan","repo.subsource.github":"Git Repos","repo.subsource.skillsh":"skills.sh","repo.subsource.clawhub":"ClawHub","repo.subsource.popular":"Top 100 by downloads","repo.catalog.states":"All statuses","repo.catalog.uninstalled":"Not installed","repo.catalog.searchClawhub":"Search ClawHub skills","repo.catalog.searchLoading":"Searching ClawHub\u2026","repo.catalog.searchEmpty":"No matching ClawHub skills were found.","repo.catalog.searchError":"ClawHub search failed. Please retry.","repo.catalog.searchSkillsh":"Search skills.sh","repo.catalog.skillshLoading":"Searching skills.sh\u2026","repo.catalog.skillshEmpty":"No matching skills.sh skills were found.","repo.catalog.skillshError":"skills.sh search failed. Please retry.","repo.sort.installs":"Installs: high to low","repo.sort.name":"Name A\u2013Z","repo.subsource.catalogNote":"ClawHub download ranking \xB7 Up to 100; sort only displayed items","repo.catalog.empty":"No matching skills were returned by ClawHub.","repo.catalog.loading":"Loading ClawHub ranking\u2026","repo.catalog.loadError":"Failed to load the ClawHub ranking. Check your connection and retry.","repo.catalog.retry":"Retry","repo.catalog.loadingMore":"Loading more\u2026","repo.catalog.downloads":"downloads","repo.catalog.installs":"installs","repo.catalog.stars":"stars","repo.hint":"Discover skills from subscribed Git repositories or community registries, and install them to user DSH skills or Shared Agent, or a registered project's .dsh/skills.","repo.footer":"Refresh checks repositories and skill updates without replacing local files. Historical backups are not cleaned automatically and use additional disk space.","repo.search":"Search repository skills","repo.all":"All repositories","repo.states":"All statuses","repo.available":"Available","repo.installed":"Installed","repo.conflict":"Name conflict","repo.invalid":"Invalid format","repo.install":"Install","repo.detail":"Details","repo.installing":"Installing\u2026","repo.installProgress":"Reading and verifying skill files. Please wait\u2026","repo.installSuccess":"Installed and enabled. Invoke it from the slash menu.","repo.installDestination":"Installation destination","repo.rootDsh":"DSH skills","repo.rootAgents":"Shared Agent","repo.rootDshHint":"For DSH only. The path uses your current DSH_HOME.","repo.rootExternalHint":"Other agents using this directory can read this skill too.","repo.installLocationsHint":"User directories offer DSH skills or Shared Agent; registered projects write only to .dsh/skills. The chooser shows actual paths. Missing directories are created after confirmation. Unsafe paths cannot be selected.","repo.uninstall":"Uninstall","repo.confirmUninstall":"Move to Trash","repo.uninstallHint":"Move only this repository\u2019s tracked installed copy, including local edits, to Trash. You can restore it from Trash later.","repo.uninstallExternalWarning":"Uninstalling this skill also affects other agents that use the selected directory.","repo.uninstalling":"Uninstalling\u2026","repo.uninstallProgress":"Moving the installed skill to Trash. Please wait\u2026","repo.uninstallSuccess":"Skill moved to Trash. You can restore it from Trash.","repo.empty":"No repositories yet. Add a Git repository to get started.","repo.noSkills":"No matching skills. Refresh the repository or adjust your filters.","repo.url":"Repository URL","repo.urlPlaceholder":"owner/repo or full Git repository URL","repo.ref":"Branch or tag (optional)","repo.directory":"Skill subdirectory (optional)","repo.defaultBranch":"Leave empty for the default branch","repo.defaultBranchLabel":"default branch","repo.directoryHint":"For example: skills. Leave empty to scan the repository.","repo.remove":"Remove repository","repo.removeHint":"This removes the subscription only. Installed skills are kept.","repo.removeConfirm":"Confirm removal","repo.cancel":"Cancel","repo.close":"Close","repo.loading":"Working\u2026","repo.success":"Completed","repo.installHint":"Skills may include scripts. Read the instructions and trust the source before installing. Resources are copied; scripts are not executed.","repo.commit":"Snapshot version","repo.notScanned":"Not scanned yet","repo.updated":"Last refreshed","repo.copyBody":"Copy body","repo.copied":"Copied","repo.copyFailed":"Copy failed","error.repo.tooLarge":"Repository exceeds size limit. Choose a smaller repository.","error.repo.transientTooLarge":"Repository transient download size exceeds limit (including Git objects). Choose a smaller repository.","error.repo.disk":"Not enough free disk space to check out this repository. Free up space and retry.","error.repo.noGit":"Git command-line tool not found. Please install Git and retry.","error.repo.installState":"Skill files were preserved but source tracking could not be saved. Restore disk write access and reopen Repositories to verify files and recover the record.","error.repo.capacity":"Source tracking exceeds 16 MiB. Remove unneeded Trash records or legacy identities first. Active installation copies are kept.","error.repo.invalid":"Invalid repository URL, path or contents. Check the input and repository size.","error.repo.network":"Repository request failed. Check your connection or retry later. The previous catalog was kept.","error.repo.state":"Repository state is corrupt or unreadable. Preserve the file and repair it before retrying.","error.repo.conflict":"A skill with this name exists or installation failed. Local files were not overwritten.","error.repo.enableState":"The copied skill was removed because its enabled state could not be saved. Restore disk write access and install again."}},Zo=`
5
5
  .dssm-subsources{display:flex;align-items:center;gap:6px;margin:0;border-bottom:0.5px solid var(--dsw-alias-border-l1,#3a3a3a);padding-bottom:6px}
6
6
  .dssm-subsource-btn{padding:5px 12px;border:0.5px solid var(--dsw-alias-border-l2,#494949);background:var(--dsw-alias-bg-layer-1,var(--dsw-alias-interactive-bg-hover,transparent));color:var(--dsw-alias-label-secondary,#b9b9b9);border-radius:var(--dsw-radius-sm,8px);font-size:12px;cursor:pointer;transition:background .15s,color .15s,border-color .15s}
7
7
  .dssm-subsource-btn:hover{background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover,transparent));color:var(--dsw-alias-label-primary,#eee)}
@@ -1,11 +1,9 @@
1
1
  import { promises as fs } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
- import { unzipSync } from "fflate";
5
4
  import { managerHomePath, resolveWorkspaceTarget, repositoryDestinations, trashRootPath, listTrash, restoreTrash as restoreSkillTrash, permanentlyDeleteTrash, parseSkillDoc, importUploadedSkill, deleteSkill, setSkillEnabled, readManagerState, state, createWorkspaceIndex } from "./core.js";
6
5
  import { createRepositoryUpdater, fileIndex, signature, readSkillTree, repositoryInstallRoot, recordInstallRoot, selectInstallRecord } from "./repository-updates.js";
7
- import { parseGitUrl, fetchGitRepository, probeGitRemote, probeGitHubHttp } from "./repository-git.js";
8
- const LIMIT = 32 << 20;
6
+ import { parseGitUrl, fetchGitRepository, probeGitRemote } from "./repository-git.js";
9
7
  const STATE_LIMIT = 16 << 20;
10
8
  const STATE_READ_LIMIT = 64 << 20;
11
9
  const hash = (bytes) => createHash("sha256").update(bytes).digest("hex");
@@ -78,55 +76,7 @@ function validateStoredState(input) {
78
76
  function parseRepositoryInput(input = {}) {
79
77
  return parseGitUrl(input);
80
78
  }
81
- function decodeRepositoryArchive(bytes) {
82
- if (bytes.byteLength > LIMIT) throw failure("\u4ED3\u5E93\u5F52\u6863\u8D85\u8FC7 32 MiB", "error.repo.tooLarge");
83
- let total = 0, count = 0;
84
- const seen = /* @__PURE__ */ new Set();
85
- const archive = unzipSync(new Uint8Array(bytes), { filter(entry) {
86
- safePath(entry.name.replace(/\/$/, ""));
87
- const key = entry.name.toLowerCase().replace(/\/$/, "");
88
- if (seen.has(key)) throw failure("\u4ED3\u5E93\u5B58\u5728\u91CD\u590D\u8DEF\u5F84");
89
- seen.add(key);
90
- total += entry.originalSize;
91
- if (++count > 1e4 || entry.originalSize > LIMIT || total > 64 << 20) throw failure("\u4ED3\u5E93\u89E3\u538B\u5927\u5C0F\u6216\u6587\u4EF6\u6570\u91CF\u8D85\u9650");
92
- return !entry.name.endsWith("/");
93
- } });
94
- const result = /* @__PURE__ */ Object.create(null);
95
- let root;
96
- for (const [path, data] of Object.entries(archive)) {
97
- const slash = path.indexOf("/");
98
- if (slash < 1) throw failure("\u4ED3\u5E93\u5F52\u6863\u8DEF\u5F84\u65E0\u6548");
99
- const prefix = path.slice(0, slash);
100
- if (root && root !== prefix) throw failure("\u4ED3\u5E93\u5F52\u6863\u6839\u76EE\u5F55\u4E0D\u552F\u4E00");
101
- root = prefix;
102
- const relative = safePath(path.slice(slash + 1));
103
- if (data.byteLength > LIMIT) throw failure("\u4ED3\u5E93\u6587\u4EF6\u8FC7\u5927");
104
- result[relative] = data;
105
- }
106
- return result;
107
- }
108
- async function readResponse(response, limit) {
109
- if (!response.ok) throw Object.assign(failure(`\u4ED3\u5E93\u8BBF\u95EE\u5931\u8D25\uFF08HTTP ${response.status}\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, "error.repo.network"), { httpStatus: response.status });
110
- if (Number(response.headers.get("content-length")) > limit) throw failure("\u4ED3\u5E93\u5F52\u6863\u8D85\u8FC7 32 MiB", "error.repo.tooLarge");
111
- const reader = response.body?.getReader();
112
- if (!reader) throw failure("\u4ED3\u5E93\u54CD\u5E94\u4E3A\u7A7A", "error.repo.network");
113
- const chunks = [];
114
- let length = 0;
115
- try {
116
- for (; ; ) {
117
- const { done, value } = await reader.read();
118
- if (done) break;
119
- length += value.length;
120
- if (length > limit) throw failure("\u4ED3\u5E93\u5F52\u6863\u8D85\u8FC7 32 MiB", "error.repo.tooLarge");
121
- chunks.push(value);
122
- }
123
- } finally {
124
- await reader.cancel();
125
- }
126
- return Buffer.concat(chunks, length);
127
- }
128
79
  function createRepositoryManager({
129
- fetchImpl = globalThis.fetch,
130
80
  gitFetch,
131
81
  probeRemote,
132
82
  maxRepositoryBytes: rawMaxBytes = 2 * 1024 * 1024 * 1024,
@@ -139,8 +89,7 @@ function createRepositoryManager({
139
89
  const maxRepositoryBytes = typeof rawMaxBytes === "number" && Number.isFinite(rawMaxBytes) && rawMaxBytes > 0 ? rawMaxBytes : 2 * 1024 * 1024 * 1024;
140
90
  const maxTransientBytes = typeof rawMaxTransientBytes === "number" && Number.isFinite(rawMaxTransientBytes) && rawMaxTransientBytes > 0 ? rawMaxTransientBytes : maxRepositoryBytes * 2.5;
141
91
  const gitTimeoutMs = typeof rawTimeoutMs === "number" && Number.isFinite(rawTimeoutMs) && rawTimeoutMs > 0 ? rawTimeoutMs : 9e5;
142
- const isDefaultFetch = fetchImpl === globalThis.fetch;
143
- const defaultProbe = probeRemote ?? isDefaultFetch;
92
+ const defaultProbe = probeRemote ?? true;
144
93
  const file = join(managerHomePath(), "repositories.json");
145
94
  let queue = Promise.resolve();
146
95
  let catalogWarnings = [];
@@ -221,16 +170,6 @@ function createRepositoryManager({
221
170
  parseRepositoryInput({ url: repo.url || `${repo.owner}/${repo.name}`, ref: repo.ref, subdirectory: repo.subdirectory });
222
171
  return repo;
223
172
  }
224
- async function request(url) {
225
- try {
226
- const response = await fetchImpl(url, { redirect: "error", signal: AbortSignal.timeout(6e4), headers: { Accept: "application/zip", "User-Agent": "dsh-skills-manager" } });
227
- return await readResponse(response, LIMIT);
228
- } catch (caught) {
229
- const error = caught;
230
- if (typeof error.code === "string" && error.code.startsWith("error.repo.")) throw error;
231
- throw failure("\u4ED3\u5E93\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5", "error.repo.network");
232
- }
233
- }
234
173
  async function cacheDirectory() {
235
174
  const dir = join(managerHomePath(), "repository-cache");
236
175
  if ((await fs.lstat(managerHomePath())).isSymbolicLink()) throw failure("\u7F13\u5B58\u76EE\u5F55\u4E0D\u80FD\u662F\u94FE\u63A5");
@@ -238,24 +177,12 @@ function createRepositoryManager({
238
177
  if ((await fs.lstat(dir)).isSymbolicLink()) throw failure("\u7F13\u5B58\u76EE\u5F55\u4E0D\u80FD\u662F\u94FE\u63A5");
239
178
  return dir;
240
179
  }
241
- async function cacheArchive(repo, bytes) {
242
- const version = hash(bytes), dir = await cacheDirectory();
243
- const target = join(dir, `${repo.id}-${version}.zip`), temporary = join(dir, randomUUID() + ".tmp");
244
- try {
245
- await fs.writeFile(temporary, bytes, { flag: "wx" });
246
- await fs.rename(temporary, target);
247
- } finally {
248
- await fs.rm(temporary, { force: true });
249
- }
250
- return version;
251
- }
252
180
  async function pruneCache(repo) {
253
181
  const dir = await cacheDirectory();
254
182
  const keepDir = `${repo.id}-${repo.commit}`;
255
- const keepZip = `${repo.id}-${repo.commit}.zip`;
256
183
  const now = Date.now();
257
184
  for (const name of await fs.readdir(dir)) {
258
- if (name.startsWith(".stage-" + repo.id + "-") || name.startsWith(repo.id + "-") && name !== keepDir && name !== keepZip) {
185
+ if (name.startsWith(".stage-" + repo.id + "-") || name.startsWith(repo.id + "-") && name !== keepDir) {
259
186
  await fs.rm(join(dir, name), { recursive: true, force: true }).catch(() => void 0);
260
187
  } else if (name.startsWith(".stage-")) {
261
188
  try {
@@ -271,57 +198,28 @@ function createRepositoryManager({
271
198
  async function download(repo, path) {
272
199
  const dir = await cacheDirectory();
273
200
  const repoDir = join(dir, `${repo.id}-${repo.commit}`);
274
- const zipPath = join(dir, `${repo.id}-${repo.commit}.zip`);
275
- try {
276
- const dirInfo = await fs.lstat(repoDir);
277
- if (dirInfo.isDirectory() && !dirInfo.isSymbolicLink()) {
278
- const result = /* @__PURE__ */ Object.create(null);
279
- const targetBase = path ? join(repoDir, path) : repoDir;
280
- const prefix = path ? `${path}/` : "";
281
- async function readDir(curr, relPrefix = "") {
282
- const items = await fs.readdir(curr, { withFileTypes: true });
283
- for (const item of items) {
284
- safePath(item.name);
285
- const full = join(curr, item.name);
286
- const rel = relPrefix ? `${relPrefix}/${item.name}` : item.name;
287
- if (item.isDirectory()) {
288
- await readDir(full, rel);
289
- } else if (item.isFile()) {
290
- const fileInfo = await fs.lstat(full);
291
- if (fileInfo.isSymbolicLink() || fileInfo.size > 32 << 20) throw failure("\u4ED3\u5E93\u6587\u4EF6\u8FC7\u5927");
292
- result[prefix + rel] = await fs.readFile(full);
293
- }
294
- }
295
- }
296
- await readDir(targetBase);
297
- return result;
298
- }
299
- } catch (e) {
300
- if (e.code && e.code.startsWith("error.repo.")) throw e;
301
- if (e.code !== "ENOENT") throw e;
302
- }
303
- try {
304
- const zipInfo = await fs.lstat(zipPath);
305
- if (!zipInfo.isSymbolicLink() && zipInfo.isFile() && zipInfo.size <= LIMIT) {
306
- const bytes = await fs.readFile(zipPath);
307
- if (hash(bytes) === repo.commit) {
308
- const archive = decodeRepositoryArchive(bytes);
309
- if (!path) return archive;
310
- const prefix = `${path}/`;
311
- const filtered = /* @__PURE__ */ Object.create(null);
312
- for (const [k, v] of Object.entries(archive)) {
313
- if (k.startsWith(prefix)) filtered[k] = v;
314
- }
315
- return filtered;
201
+ const info = await fs.lstat(repoDir).catch(() => null);
202
+ if (!info || !info.isDirectory() || info.isSymbolicLink()) throw failure("\u4ED3\u5E93\u7F13\u5B58\u7F3A\u5931\u6216\u5DF2\u5931\u6548\uFF0C\u8BF7\u5237\u65B0\u8BE5\u4ED3\u5E93\u540E\u91CD\u8BD5");
203
+ const result = /* @__PURE__ */ Object.create(null);
204
+ const targetBase = path ? join(repoDir, path) : repoDir;
205
+ const prefix = path ? `${path}/` : "";
206
+ async function readDir(curr, relPrefix = "") {
207
+ const items = await fs.readdir(curr, { withFileTypes: true });
208
+ for (const item of items) {
209
+ safePath(item.name);
210
+ const full = join(curr, item.name);
211
+ const rel = relPrefix ? `${relPrefix}/${item.name}` : item.name;
212
+ if (item.isDirectory()) {
213
+ await readDir(full, rel);
214
+ } else if (item.isFile()) {
215
+ const fileInfo = await fs.lstat(full);
216
+ if (fileInfo.isSymbolicLink() || fileInfo.size > 32 << 20) throw failure("\u4ED3\u5E93\u6587\u4EF6\u8FC7\u5927");
217
+ result[prefix + rel] = await fs.readFile(full);
316
218
  }
317
219
  }
318
- } catch (e) {
319
- if (e.code && e.code.startsWith("error.repo.")) throw e;
320
- }
321
- if (/^[a-f0-9]{40}$/.test(repo.commit || "")) {
322
- return decodeRepositoryArchive(await request(`https://codeload.github.com/${repo.owner}/${repo.name}/zip/${repo.commit}`));
323
220
  }
324
- throw failure("\u626B\u63CF\u7F13\u5B58\u7F3A\u5931\u6216\u635F\u574F\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u66F4\u65B0\u540E\u64CD\u4F5C");
221
+ await readDir(targetBase);
222
+ return result;
325
223
  }
326
224
  async function scanSkillsFromDirectory(dir, subdirectory = "", repoName = "") {
327
225
  const skills = [];
@@ -379,18 +277,6 @@ function createRepositoryManager({
379
277
  }
380
278
  return skills;
381
279
  }
382
- async function fetchBranch(repo) {
383
- const refs = repo.ref && repo.ref !== "HEAD" ? [`refs/heads/${repo.ref}`, `refs/tags/${repo.ref}`] : ["HEAD", "refs/heads/main", "refs/heads/master"];
384
- for (let i = 0; i < refs.length; i++) {
385
- try {
386
- return await request(`https://codeload.github.com/${repo.owner}/${repo.name}/zip/${refs[i].split("/").map(encodeURIComponent).join("/")}`);
387
- } catch (caught) {
388
- const error = caught;
389
- if (error.httpStatus !== 404 || i === refs.length - 1) throw error;
390
- }
391
- }
392
- throw failure("\u4ED3\u5E93\u5206\u652F\u4E0D\u5B58\u5728");
393
- }
394
280
  async function matches(record, fingerprint = signature(record.files), registered = registeredWorkspaces?.(), indexed) {
395
281
  try {
396
282
  safePath(record.name);
@@ -736,11 +622,7 @@ function createRepositoryManager({
736
622
  const source = parseRepositoryInput(input);
737
623
  const shouldProbe = !gitFetch && defaultProbe && input.skipProbe !== true && process.env.DSH_SKILLS_MANAGER_SKIP_PROBE !== "1";
738
624
  if (shouldProbe) {
739
- if (source.url) {
740
- await probeGitRemote(source.url);
741
- } else {
742
- await probeGitHubHttp(source.owner, source.name, fetchImpl);
743
- }
625
+ await probeGitRemote(source.url || `https://github.com/${source.owner}/${source.name}.git`);
744
626
  }
745
627
  return serialize(async () => {
746
628
  const data = await read();
@@ -788,27 +670,10 @@ function createRepositoryManager({
788
670
  const res = await gitFetch(repo, stageDir, { maxBytes: maxRepositoryBytes, maxTransientBytes, timeoutMs: gitTimeoutMs });
789
671
  commit = res.commit;
790
672
  skills = await scanSkillsFromDirectory(stageDir, repo.subdirectory, repo.name);
791
- } else if (repo.url) {
673
+ } else {
792
674
  const res = await fetchGitRepository(repo, stageDir, { maxBytes: maxRepositoryBytes, maxTransientBytes, timeoutMs: gitTimeoutMs });
793
675
  commit = res.commit;
794
676
  skills = await scanSkillsFromDirectory(stageDir, repo.subdirectory, repo.name);
795
- } else {
796
- const bytes = await fetchBranch(repo);
797
- const entries = decodeRepositoryArchive(bytes);
798
- for (const [path, b] of Object.entries(entries)) {
799
- if (path !== "SKILL.md" && !path.endsWith("/SKILL.md")) continue;
800
- const directory = path === "SKILL.md" ? "" : path.slice(0, -9);
801
- if (repo.subdirectory && directory !== repo.subdirectory && !directory.startsWith(`${repo.subdirectory}/`)) continue;
802
- if (b.length > 256 << 10 || skills.length >= 500 || skills.reduce((n, s) => n + Buffer.byteLength(s.body, "utf8"), 0) + b.length > 4 << 20) throw failure("\u4ED3\u5E93\u6280\u80FD\u6570\u91CF\u6216\u8BF4\u660E\u957F\u5EA6\u8D85\u9650");
803
- const parsed = parseSkillDoc(Buffer.from(b).toString("utf8"));
804
- const name = String(parsed.map.name || "");
805
- const description = String(parsed.map.description || "");
806
- const prefix = directory ? directory + "/" : "";
807
- const files = fileIndex(Object.fromEntries(Object.entries(entries).filter(([p]) => p.startsWith(prefix)).map(([p, b2]) => [p.slice(prefix.length), b2])));
808
- if (files.length > 1e3) throw failure("\u6280\u80FD\u6587\u4EF6\u6570\u91CF\u8D85\u9650");
809
- skills.push({ path: directory, files, name: name || directory.split("/").pop() || repo.name, description, body: parsed.body.trim(), documentHash: hash(b), valid: parsed.hasFrontmatter && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name) && !/^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i.test(name) && name.length <= 100 && !!description });
810
- }
811
- commit = await cacheArchive(repo, bytes);
812
677
  }
813
678
  } catch (caught) {
814
679
  const error = caught;
@@ -971,6 +836,5 @@ function createRepositoryManager({
971
836
  }
972
837
  export {
973
838
  createRepositoryManager,
974
- decodeRepositoryArchive,
975
839
  parseRepositoryInput
976
840
  };
@@ -195,8 +195,14 @@ function runGit(args, cwd, optionsOrTimeout, legacyGitBinary = "git") {
195
195
  "core.symlinks=false",
196
196
  "-c",
197
197
  "core.autocrlf=false",
198
+ // 技能目录层级深时,Windows 默认 260 字符上限会让检出直接失败。
199
+ "-c",
200
+ "core.longpaths=true",
198
201
  "-c",
199
202
  "advice.detachedHead=false",
203
+ // 只支持公开仓库:禁用凭据助手,避免 Git Credential Manager 弹出账号选择窗口并卡住插件进程。
204
+ "-c",
205
+ "credential.helper=",
200
206
  "-c",
201
207
  "http.lowSpeedLimit=1000",
202
208
  "-c",
@@ -208,16 +214,41 @@ function runGit(args, cwd, optionsOrTimeout, legacyGitBinary = "git") {
208
214
  env: {
209
215
  ...process.env,
210
216
  GIT_TERMINAL_PROMPT: "0",
217
+ GCM_INTERACTIVE: "never",
218
+ GIT_ASKPASS: "echo",
211
219
  LC_ALL: "C",
212
220
  LANGUAGE: "C"
213
221
  },
214
- stdio: ["ignore", "pipe", "pipe"],
222
+ // 只在确实要写规则时才接管 stdin,其余调用保持 ignore。
223
+ stdio: options.input === void 0 ? ["ignore", "pipe", "pipe"] : ["pipe", "pipe", "pipe"],
215
224
  detached: process.platform !== "win32"
216
225
  }
217
226
  );
218
227
  let stdout = "";
219
228
  let stderr = "";
220
229
  let killed = false;
230
+ if (options.input !== void 0 && child.stdin) {
231
+ child.stdin.on("error", () => void 0);
232
+ child.stdin.end(options.input);
233
+ }
234
+ let measuring = false;
235
+ const quota = options.quota;
236
+ const watchdog = quota ? setInterval(() => {
237
+ if (measuring || killed) return;
238
+ measuring = true;
239
+ getDirectorySize(quota.dir).then((size) => {
240
+ measuring = false;
241
+ if (killed || size <= quota.limit) return;
242
+ killed = true;
243
+ killProcessTree(child);
244
+ reject(failure("\u4ED3\u5E93\u4E34\u65F6\u4E0B\u8F7D\u4F53\u79EF\u8FC7\u5927\uFF08\u5305\u542B Git \u5386\u53F2\u5BF9\u8C61\uFF09", "error.repo.transientTooLarge", { limit: quota.limit, actual: size }));
245
+ }, () => {
246
+ measuring = false;
247
+ });
248
+ }, 800) : void 0;
249
+ const stopWatchdog = () => {
250
+ if (watchdog) clearInterval(watchdog);
251
+ };
221
252
  child.stdout.on("data", (chunk) => {
222
253
  stdout += chunk;
223
254
  });
@@ -226,11 +257,13 @@ function runGit(args, cwd, optionsOrTimeout, legacyGitBinary = "git") {
226
257
  });
227
258
  const timer = setTimeout(() => {
228
259
  killed = true;
260
+ stopWatchdog();
229
261
  killProcessTree(child);
230
262
  reject(failure("Git \u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5", "error.repo.network"));
231
263
  }, timeoutMs);
232
264
  child.on("error", (err) => {
233
265
  clearTimeout(timer);
266
+ stopWatchdog();
234
267
  if (killed) return;
235
268
  const code = err?.code;
236
269
  if (code === "ENOENT") {
@@ -241,6 +274,7 @@ function runGit(args, cwd, optionsOrTimeout, legacyGitBinary = "git") {
241
274
  });
242
275
  child.on("close", (code) => {
243
276
  clearTimeout(timer);
277
+ stopWatchdog();
244
278
  if (killed) return;
245
279
  if (code === 0) resolve({ stdout, stderr });
246
280
  else reject(mapGitError(stderr || stdout));
@@ -266,27 +300,71 @@ async function probeGitRemote(repoUrl, options = {}) {
266
300
  await runGit(["ls-remote", "--heads", "-q", "--", repoUrl], process.cwd(), { timeoutMs, gitBinary });
267
301
  } catch (caught) {
268
302
  const err = caught;
303
+ if (err?.code === "error.repo.noGit") throw err;
269
304
  throw failure(err.message || "\u4ED3\u5E93\u65E0\u6CD5\u8BBF\u95EE\u6216\u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\u5730\u5740\u6216\u6743\u9650", "error.repo.network");
270
305
  }
271
306
  }
272
- async function probeGitHubHttp(owner, name, fetchImpl = globalThis.fetch, timeoutMs = 15e3) {
273
- const controller = new AbortController();
274
- const timer = setTimeout(() => controller.abort(), timeoutMs);
307
+ const SKILL_DOC_SUFFIX = "/SKILL.md";
308
+ const EMPTY_CHECKOUT_PATTERN = "/.dsh-skills-manager-empty/**";
309
+ function checkoutPatternFor(directory) {
310
+ return `/${directory.replace(/[[\]]/g, "\\$&")}/**`;
311
+ }
312
+ function skillCheckoutPatterns(paths, subdirectory = "") {
313
+ const collected = [];
314
+ for (const path of paths) {
315
+ if (typeof path !== "string" || !path) continue;
316
+ if (path === "SKILL.md") return null;
317
+ if (!path.endsWith(SKILL_DOC_SUFFIX)) continue;
318
+ const directory = path.slice(0, -SKILL_DOC_SUFFIX.length);
319
+ if (!directory) continue;
320
+ if (subdirectory && directory !== subdirectory && !directory.startsWith(`${subdirectory}/`)) continue;
321
+ safePath(directory);
322
+ collected.push(directory);
323
+ }
324
+ if (!collected.length) return [EMPTY_CHECKOUT_PATTERN];
325
+ const directories = [...new Set(collected)].sort();
326
+ return directories.filter((directory) => !directories.some((other) => other !== directory && directory.startsWith(`${other}/`))).map(checkoutPatternFor);
327
+ }
328
+ async function listTreePaths(destinationDir, revision, options) {
329
+ const { stdout } = await runGit(["ls-tree", "-r", "-z", "--name-only", "--", revision], destinationDir, options);
330
+ return stdout.split("\0").filter(Boolean);
331
+ }
332
+ async function clearSparseCheckout(destinationDir, options) {
333
+ for (const key of ["core.sparseCheckout", "core.sparseCheckoutCone"]) {
334
+ await runGit(["config", "--unset-all", key], destinationDir, options).catch(() => void 0);
335
+ }
336
+ await fs.rm(join(destinationDir, ".git", "info", "sparse-checkout"), { force: true }).catch(() => void 0);
337
+ }
338
+ const DISK_PREFLIGHT_BYTES = 256 << 20;
339
+ function formatBytes(bytes) {
340
+ if (!Number.isFinite(bytes) || bytes < 0) return String(bytes);
341
+ const units = ["B", "KiB", "MiB", "GiB"];
342
+ let value = bytes, unit = 0;
343
+ while (value >= 1024 && unit < units.length - 1) {
344
+ value /= 1024;
345
+ unit += 1;
346
+ }
347
+ return `${unit === 0 || value >= 10 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
348
+ }
349
+ async function ensureDiskSpace(dir, requiredBytes) {
350
+ let free;
275
351
  try {
276
- const res = await fetchImpl(`https://github.com/${owner}/${name}`, {
277
- method: "HEAD",
278
- redirect: "manual",
279
- signal: controller.signal,
280
- headers: { "User-Agent": "Mozilla/5.0" }
281
- });
282
- if (res.status === 404) {
283
- throw failure("\u4ED3\u5E93\u65E0\u6CD5\u8BBF\u95EE\u6216\u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\u5730\u5740\u6216\u6743\u9650", "error.repo.network");
284
- }
285
- } catch (caught) {
286
- if (caught && caught.code === "error.repo.network") throw caught;
287
- } finally {
288
- clearTimeout(timer);
352
+ const stats = await fs.statfs(dir);
353
+ free = Number(stats.bavail) * Number(stats.bsize);
354
+ } catch {
355
+ return;
356
+ }
357
+ if (!Number.isFinite(free) || free >= requiredBytes) return;
358
+ throw failure(`\u78C1\u76D8\u5269\u4F59\u7A7A\u95F4\u4E0D\u8DB3\uFF08\u5269\u4F59 ${formatBytes(free)}\uFF0C\u81F3\u5C11\u9700\u8981 ${formatBytes(requiredBytes)}\uFF09`, "error.repo.disk", { available: free, required: requiredBytes });
359
+ }
360
+ async function sumTreeBlobBytes(destinationDir, revision, options) {
361
+ const { stdout } = await runGit(["ls-tree", "-r", "-l", "-z", "--", revision], destinationDir, options);
362
+ let total = 0;
363
+ for (const record of stdout.split("\0")) {
364
+ const size = /^\d{6} blob [0-9a-f]{40,64}\s+(\d+)\t/.exec(record);
365
+ if (size) total += Number(size[1]);
289
366
  }
367
+ return total;
290
368
  }
291
369
  async function fetchGitRepository(repo, destinationDir, options = {}) {
292
370
  const maxBytes = options.maxBytes ?? 2 * 1024 * 1024 * 1024;
@@ -297,37 +375,63 @@ async function fetchGitRepository(repo, destinationDir, options = {}) {
297
375
  const remainingTimeout = () => {
298
376
  const remain = deadline - Date.now();
299
377
  if (remain <= 0) throw failure("Git \u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u540E\u91CD\u8BD5", "error.repo.network");
300
- return remain;
378
+ return { timeoutMs: remain, gitBinary, quota: { dir: destinationDir, limit: maxTransientBytes } };
301
379
  };
302
380
  const repoUrl = repo.url || `https://github.com/${repo.owner}/${repo.name}.git`;
303
381
  const ref = repo.ref && repo.ref !== "HEAD" ? repo.ref : "HEAD";
304
382
  await fs.mkdir(destinationDir, { recursive: true });
383
+ await ensureDiskSpace(destinationDir, options.diskPreflightBytes ?? Math.min(maxTransientBytes, DISK_PREFLIGHT_BYTES));
305
384
  try {
306
- await runGit(["init", "-q"], destinationDir, { timeoutMs: remainingTimeout(), gitBinary });
385
+ await runGit(["init", "-q"], destinationDir, remainingTimeout());
386
+ await runGit(["remote", "add", "origin", repoUrl], destinationDir, remainingTimeout());
307
387
  const refsToTry = ref === "HEAD" ? ["HEAD"] : [`refs/heads/${ref}`, `refs/tags/${ref}`, ref];
308
388
  let fetched = false;
389
+ let filtered = false;
309
390
  let lastError;
310
391
  for (const r of refsToTry) {
311
392
  try {
312
- await runGit(["fetch", "--progress", "--depth", "1", "--no-tags", "--", repoUrl, r], destinationDir, { timeoutMs: remainingTimeout(), gitBinary });
393
+ await runGit(["fetch", "--progress", "--depth", "1", "--no-tags", "--filter=blob:none", "--", "origin", r], destinationDir, remainingTimeout());
313
394
  fetched = true;
395
+ filtered = true;
314
396
  break;
315
397
  } catch (err) {
316
398
  lastError = err;
317
- if (r === refsToTry[refsToTry.length - 1]) {
318
- try {
319
- await runGit(["fetch", "--progress", "--no-tags", "--", repoUrl, r], destinationDir, { timeoutMs: remainingTimeout(), gitBinary });
320
- fetched = true;
321
- } catch {
322
- throw err;
399
+ try {
400
+ await runGit(["fetch", "--progress", "--depth", "1", "--no-tags", "--", "origin", r], destinationDir, remainingTimeout());
401
+ fetched = true;
402
+ break;
403
+ } catch (err2) {
404
+ lastError = err2;
405
+ if (r === refsToTry[refsToTry.length - 1]) {
406
+ try {
407
+ await runGit(["fetch", "--progress", "--no-tags", "--", "origin", r], destinationDir, remainingTimeout());
408
+ fetched = true;
409
+ } catch {
410
+ throw err2;
411
+ }
323
412
  }
324
413
  }
325
414
  }
326
415
  }
327
416
  if (!fetched) throw lastError || failure("Git \u5206\u652F\u6216\u6807\u7B7E\u4E0D\u5B58\u5728", "error.repo.network");
328
- await runGit(["checkout", "-q", "FETCH_HEAD"], destinationDir, { timeoutMs: remainingTimeout(), gitBinary });
329
- const { stdout: commitOut } = await runGit(["rev-parse", "FETCH_HEAD^{commit}"], destinationDir, { timeoutMs: remainingTimeout(), gitBinary });
417
+ const { stdout: commitOut } = await runGit(["rev-parse", "FETCH_HEAD^{commit}"], destinationDir, remainingTimeout());
330
418
  const commit = commitOut.trim();
419
+ if (!filtered) {
420
+ const bytes = await sumTreeBlobBytes(destinationDir, "FETCH_HEAD", remainingTimeout());
421
+ if (bytes > maxBytes) throw failure("\u4ED3\u5E93\u8D85\u8FC7\u5927\u5C0F\u9650\u5236", "error.repo.tooLarge", { limit: maxBytes, actual: bytes });
422
+ }
423
+ const patterns = skillCheckoutPatterns(await listTreePaths(destinationDir, "FETCH_HEAD", remainingTimeout()), repo.subdirectory);
424
+ if (patterns) {
425
+ try {
426
+ await runGit(["sparse-checkout", "set", "--no-cone", "--stdin"], destinationDir, { ...remainingTimeout(), input: `${patterns.join("\n")}
427
+ ` });
428
+ } catch (err) {
429
+ const code = err?.code;
430
+ if (code === "error.repo.noGit" || code === "error.repo.network" || code === "error.repo.transientTooLarge") throw err;
431
+ await clearSparseCheckout(destinationDir, remainingTimeout());
432
+ }
433
+ }
434
+ await runGit(["checkout", "-q", "FETCH_HEAD"], destinationDir, remainingTimeout());
331
435
  const rawSize = await getDirectorySize(destinationDir);
332
436
  if (rawSize > maxTransientBytes) {
333
437
  throw failure("\u4ED3\u5E93\u4E34\u65F6\u4E0B\u8F7D\u4F53\u79EF\u8FC7\u5927\uFF08\u5305\u542B Git \u5386\u53F2\u5BF9\u8C61\uFF09", "error.repo.transientTooLarge", { limit: maxTransientBytes, actual: rawSize });
@@ -347,6 +451,6 @@ export {
347
451
  fetchGitRepository,
348
452
  getDirectorySize,
349
453
  parseGitUrl,
350
- probeGitHubHttp,
351
- probeGitRemote
454
+ probeGitRemote,
455
+ skillCheckoutPatterns
352
456
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-skills-manager",
3
- "version": "1.2.33",
3
+ "version": "1.2.35",
4
4
  "description": "DSH Skills Manager — 在 DeepSeek Harness 中统一加载并安全管理本机 Agent Skills · Load and safely manage local Agent Skills in DSH",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {