dsh-plugin-tool-management 0.8.5 → 0.9.1

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 (59) hide show
  1. package/CHANGELOG.md +275 -206
  2. package/README.md +71 -69
  3. package/README_EN.md +65 -65
  4. package/docs/images/1-EN.png +0 -0
  5. package/docs/images/1.png +0 -0
  6. package/docs/images/2-EN.png +0 -0
  7. package/docs/images/2.png +0 -0
  8. package/docs/images/3-EN.png +0 -0
  9. package/docs/images/3.png +0 -0
  10. package/docs/images/4-EN.png +0 -0
  11. package/docs/images/4.png +0 -0
  12. package/docs/images/5-EN.png +0 -0
  13. package/docs/images/5.png +0 -0
  14. package/docs/images/6-EN.png +0 -0
  15. package/docs/images/6.png +0 -0
  16. package/docs/images/7-EN.png +0 -0
  17. package/docs/images/7.png +0 -0
  18. package/docs/images/8-EN.png +0 -0
  19. package/docs/images/8.png +0 -0
  20. package/docs/update.md +132 -86
  21. package/lib/agents-md/preset-id.js +1 -1
  22. package/lib/agents-md/service.js +46 -9
  23. package/lib/approval-policy.js +1 -1
  24. package/lib/client.js +867 -146
  25. package/lib/compat/preset-reach.js +155 -93
  26. package/lib/context-inject.js +401 -0
  27. package/lib/hub.js +155 -13
  28. package/lib/imports/upload.js +34 -14
  29. package/lib/index.js +1072 -243
  30. package/lib/mcp/state-section.js +46 -15
  31. package/lib/rules/archive-engine.js +158 -64
  32. package/lib/rules/archive.js +41 -1
  33. package/lib/rules/service.js +424 -162
  34. package/lib/scene-prompt-sync.js +93 -12
  35. package/lib/skills/catalog.js +125 -0
  36. package/lib/skills/core.js +6 -4
  37. package/lib/skills/service.js +56 -2
  38. package/lib/subagents/catalog.js +15 -6
  39. package/lib/subagents/service.js +25 -12
  40. package/lib/subagents/tools.js +18 -13
  41. package/package.json +11 -6
  42. package/screenshots.json +8 -8
  43. package/docs/images/1/345/234/272/346/231/257.png +0 -0
  44. package/docs/images/1/345/234/272/346/231/257_en.png +0 -0
  45. package/docs/images/2MCP.png +0 -0
  46. package/docs/images/2MCP_en.png +0 -0
  47. package/docs/images/3/346/212/200/350/203/275.png +0 -0
  48. package/docs/images/3/346/212/200/350/203/275_en.png +0 -0
  49. package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223.png +0 -0
  50. package/docs/images/4/345/255/220/346/231/272/350/203/275/344/275/223_en.png +0 -0
  51. package/docs/images/5/346/217/220/347/244/272/350/257/215.png +0 -0
  52. package/docs/images/5/346/217/220/347/244/272/350/257/215_en.png +0 -0
  53. package/docs/images/6/350/256/260/345/277/206.png +0 -0
  54. package/docs/images/6/350/256/260/345/277/206_en.png +0 -0
  55. package/docs/images/7/344/274/232/350/257/235.png +0 -0
  56. package/docs/images/7/344/274/232/350/257/235_en.png +0 -0
  57. package/docs/images/8/345/205/274/345/256/271.png +0 -0
  58. package/docs/images/8/345/205/274/345/256/271_en.png +0 -0
  59. package/lib/prompt-sections.js +0 -148
@@ -166,8 +166,9 @@ const MAX_BUNDLE_ATTACH_TOTAL = 16 * 1024 * 1024;
166
166
  /**
167
167
  * 记忆落点:
168
168
  * - 裸 `.md` → 落到 defaultScene(空串 = 全局:任何对话都注入);zip 内带目录 → 目录路径即场景/分组。
169
- * - zip 内 `<场景路径>/<名>/SKILL.md` → bundle 记忆(目录末段是记忆名,其余前缀是场景);同层非 `.md`
170
- * 文件作为附件一并带入(`.md` 不带——bundle 是叶子,塞进去不会被发现,静默降级反而误导)。
169
+ * - zip 内 `<场景路径>/<名>/<名>.md` → bundle 记忆(目录末段是记忆名,正文文件名与目录名一致,
170
+ * 其余前缀是场景);同层非 `.md` 文件作为附件一并带入(`.md` 不带——bundle 是叶子,塞进去不会被发现,
171
+ * 静默降级反而误导)。旧导出包里正文可能仍叫 `SKILL.md`,也认(只读兼容)。
171
172
  * - zip 根层的裸 `SKILL.md` 没有目录名可当记忆名 → 跳过并回报;`SKILL.md` 的大小写变体也跳过
172
173
  * (发现层只认精确 `SKILL.md`,NTFS 大小写不敏感下两者不能共存)。
173
174
  */
@@ -180,18 +181,39 @@ export function planMemoryImport(entries, defaultScene) {
180
181
  const idx = path.lastIndexOf('/');
181
182
  return { dir: idx >= 0 ? path.slice(0, idx) : '', base: path.slice(idx + 1) };
182
183
  };
183
- // pass 1:认 bundle 目录(精确 SKILL.md;大小写变体只报跳过,不当 bundle 也不当 flat)。
184
+ // pass 1:认 bundle 目录(`<目录名>.md` 是正文;旧导出包的 `SKILL.md` 也认,只读兼容)。
184
185
  const bundleDocs = new Map();
186
+ const consumed = new Set(); // 已被 pass 1 认领(或已回报)的条目路径,pass 3 不再当 flat 处理
185
187
  for (const entry of entries) {
186
188
  const { dir, base } = split(entry.path);
187
- if (base !== 'SKILL.md' && base.toLowerCase() !== 'skill.md')
188
- continue;
189
- if (base !== 'SKILL.md') {
189
+ const dirName = dir === '' ? '' : dir.slice(dir.lastIndexOf('/') + 1);
190
+ const isLegacyCaseVariant = base.toLowerCase() === 'skill.md' && base !== 'SKILL.md';
191
+ if (isLegacyCaseVariant) {
190
192
  problems.push({ name: entry.path, reason: 'SKILL.md 大小写变体不导入(发现层只认精确 SKILL.md,且与 NTFS 大小写不敏感冲突),已跳过' });
193
+ consumed.add(entry.path);
191
194
  continue;
192
195
  }
193
- if (dir === '') {
196
+ // 一级目录恒为场景(与发现层 `discover`/`probeSceneFilesSync` 同口径):`1/1.md` 是
197
+ // 「场景 1 的记忆 1」的 flat 正文,**不是**根层 bundle「1」——bundle 只认目录至少两段
198
+ // (`<场景>/<名>/<名>.md`)。认错会写出发现层根本读不到、且会把整个场景目录吃成叶子的形态。
199
+ const isRootSkill = base === 'SKILL.md' && dir === '';
200
+ if (isRootSkill) {
201
+ // zip 根层的裸 SKILL.md:没有目录名可作记忆名。
194
202
  problems.push({ name: entry.path, reason: 'SKILL.md 在 zip 根层,没有目录名可作记忆名,已跳过' });
203
+ consumed.add(entry.path);
204
+ continue;
205
+ }
206
+ const isLegacyDoc = base === 'SKILL.md' && dir.includes('/');
207
+ const isNamedDoc = dir.includes('/') && base === `${dirName}.md`;
208
+ if (!isLegacyDoc && !isNamedDoc)
209
+ continue;
210
+ consumed.add(entry.path);
211
+ const existing = bundleDocs.get(dir);
212
+ if (existing) {
213
+ // 同一目录里同时出现 `<目录名>.md` 与旧的 `SKILL.md`(少见):`<目录名>.md` 优先。
214
+ const { base: existingBase } = split(existing.path);
215
+ if (isNamedDoc && existingBase !== `${dirName}.md`)
216
+ bundleDocs.set(dir, entry);
195
217
  continue;
196
218
  }
197
219
  bundleDocs.set(dir, entry);
@@ -206,7 +228,7 @@ export function planMemoryImport(entries, defaultScene) {
206
228
  if (!bundleDir)
207
229
  continue;
208
230
  if (dir !== bundleDir) {
209
- problems.push({ name: entry.path, reason: 'bundle 只支持一层附件(SKILL.md 同层),子目录条目已跳过' });
231
+ problems.push({ name: entry.path, reason: 'bundle 只支持一层附件(正文同层),子目录条目已跳过' });
210
232
  continue;
211
233
  }
212
234
  if (!entry.bytes.length) {
@@ -231,7 +253,7 @@ export function planMemoryImport(entries, defaultScene) {
231
253
  list.push({ name, bytes: entry.bytes });
232
254
  attachments.set(bundleDir, list);
233
255
  }
234
- // pass 3:先规划 bundle 目标(含 SKILL.md 同层 .md 的明确跳过),再走 flat。
256
+ // pass 3:先规划 bundle 目标(含正文同层 .md 的明确跳过),再走 flat。
235
257
  for (const [dir, doc] of bundleDocs) {
236
258
  const segs = dir.split('/');
237
259
  const name = segs[segs.length - 1];
@@ -256,12 +278,10 @@ export function planMemoryImport(entries, defaultScene) {
256
278
  const { dir, base } = split(entry.path);
257
279
  if (!base.toLowerCase().endsWith('.md'))
258
280
  continue;
259
- if (base === 'SKILL.md')
260
- continue;
261
- if (base.toLowerCase() === 'skill.md')
262
- continue; // pass 1 已回报
281
+ if (consumed.has(entry.path))
282
+ continue; // pass 1 已认领为 bundle 正文,或已回报为大小写变体/根层裸 SKILL.md
263
283
  if ([...bundleDocs.keys()].some((d) => dir === d || dir.startsWith(d + '/'))) {
264
- problems.push({ name: entry.path, reason: 'bundle 目录内的非 SKILL.md 的 .md 不导入(bundle 是叶子,放进去不会被发现),已跳过' });
284
+ problems.push({ name: entry.path, reason: 'bundle 目录内的非正文 .md 不导入(bundle 是叶子,放进去不会被发现),已跳过' });
265
285
  continue;
266
286
  }
267
287
  const name = base.slice(0, -3); // 去掉 .md