@deepseek-ai/dsh-skill-filesystem 0.1.5-rc.2 → 0.1.6-alpha.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.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/skill/skill-filesystem/README.md
5
- README.md: 808df61c0fa248ba02b4e2993e6cbe60ede35f7c
6
- README.zh.md: 6e542dee5bb275488cea9dadba10decd6ecb6733
5
+ README.md: 55ec66938f53fc282a51f9bf140ed2c999a937b7
6
+ README.zh.md: f5ffb1f60b3fd908077038ae9479661266cdd160
package/README.md CHANGED
@@ -37,6 +37,8 @@ A skill is either a directory bundle `<name>/SKILL.md` or a flat file `<name>.md
37
37
 
38
38
  `disable-model-invocation: true` keeps the skill out of model-facing catalogs and loaders; `user-invocable: false` keeps it out of human-facing commands, and omitted fields default to permitting their surface. The two keys accept YAML booleans plus the case-insensitive `true`/`false`, `yes`/`no`, `on`/`off`, and `1`/`0` forms; a rejected spelling or a non-boolean value drops the whole skill with a warning rather than silently permitting a surface.
39
39
 
40
+ Catalog entries and loaded skills expose the resolved instruction-file path, so symlinked directories and flat files can open as regular-file previews. Reload locators and resource bases retain the discovered paths, including symlinks.
41
+
40
42
  The catalog and the body have separate lifecycles: discovery parses frontmatter into the catalog entry, and every load re-reads the current file, so editing a skill body needs no versioning or cache invalidation.
41
43
 
42
44
  ### Roots and priority
package/README.zh.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "本地文件系统 skill 提供方,供编写本地 skill、或配置项目、自定义与用户 skill 根目录如何被发现与监视的用户与维护者阅读。"
2
+ description: "本地文件系统 skill 提供方,供编写本地 skill 或配置项目、自定义与用户 skill 根目录如何被发现与监视的用户与维护者阅读。"
3
3
  kind: "package-reference"
4
4
  ---
5
5
 
@@ -37,6 +37,8 @@ skill 可以是被扫描根目录顶层的目录 bundle `<name>/SKILL.md`,也
37
37
 
38
38
  `disable-model-invocation: true` 会把 skill 从面向模型的目录和 loader 中排除;`user-invocable: false` 会把它从面向用户的命令中排除,省略的字段默认允许对应接口调用。这两个键接受 YAML 布尔值,以及不区分大小写的 `true`/`false`、`yes`/`no`、`on`/`off` 和 `1`/`0` 形式;被拒绝的拼写或非布尔值会让整个 skill 随警告一起被丢弃,而不会静默允许某个接口。
39
39
 
40
+ 目录条目和已加载 skill 提供解析后的指令文件路径,使符号链接目录和扁平文件都能作为普通文件预览。重新加载的定位信息和资源根保留发现时的路径,包括符号链接。
41
+
40
42
  目录与正文具有独立的生命周期:发现阶段把 frontmatter 解析进目录条目,每次加载都会重新读取当前文件,因此编辑 skill 正文无需版本化或缓存失效。
41
43
 
42
44
  ### 根目录与优先级
@@ -51,7 +53,7 @@ skill 可以是被扫描根目录顶层的目录 bundle `<name>/SKILL.md`,也
51
53
  | 400 | `user-dsh` | `<dshHome>/skills` |
52
54
  | 500 | `user-agents` | `<agentsHome>/skills` |
53
55
 
54
- 项目根目录是包含 `.git` 的最近祖先目录;如果不存在,则使用当前 cwd。用户 DSH 根目录会跳过其 `.system` 子目录。`includeDefaultRoots: false` 会省略项目根、用户根以及 `$DSH_BUNDLED_SKILL_DIR` 默认值,使隔离提供方只看到自身配置的根;`bundledSkillDir` 会按 rank 600 添加一个内置根目录。
56
+ 项目根目录是包含 `.git` 的最近祖先目录;如果不存在,则使用当前 cwd。用户 DSH 根目录会跳过其 `.system` 子目录。`includeDefaultRoots: false` 会省略项目根、用户根以及 `$DSH_BUNDLED_SKILL_DIR` 默认值,使隔离提供方只看到自身配置的根;`bundledSkillDir` 会按 rank 600 添加一个随包提供的根目录。
55
57
 
56
58
  ### 挂载与配置
57
59
 
@@ -70,9 +72,9 @@ skill 可以是被扫描根目录顶层的目录 bundle `<name>/SKILL.md`,也
70
72
  | `agentsHome` | `$DSH_AGENTS_HOME` 或 `~/.agents` | 为兼容 skill 扫描的共享 agent 配置根目录 |
71
73
  | `customSkillDirs` | `[]` | 其他本地 skill 根目录,位于项目根之后、用户根之前 |
72
74
  | `watch` | `true` | 监视本地根,并在目录可能变化时使提供方失效 |
73
- | `bundledSkillDir` | — | 配置后按 rank 600 扫描的内置 skill 根目录 |
75
+ | `bundledSkillDir` | — | 配置后按 rank 600 扫描的随包提供的 skill 根目录 |
74
76
 
75
- 其余 `watch*` 字段用于调节 Chokidar 行为——轮询、稳定窗口、间隔、项目上限与符号链接跟随。生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-skill-filesystem)是每个字段的穷尽式真源。
77
+ 其余 `watch*` 字段用于调节 Chokidar 行为——轮询、稳定窗口、间隔、项目上限与符号链接跟随。生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-skill-filesystem)完整列出了所有字段,是这些字段的真源。
76
78
 
77
79
  ### 变更检测
78
80
 
@@ -94,7 +96,7 @@ skill 可以是被扫描根目录顶层的目录 bundle `<name>/SKILL.md`,也
94
96
 
95
97
  ### 设计理念
96
98
 
97
- 该提供方建立在两个分离之上。第一,目录与正文分离:发现阶段把 frontmatter 解析为摘要,而每次加载都重新读取文件,因此正文编辑无需 hash、修订号或缓存失效。第二,发现与监视分离:`list()` 在存在文件系统服务时通过 `ctx.fs` 扫描根目录并解析项目根(否则回退到可中止的 Node I/O),而独立的监视管理器负责 Chokidar 句柄、缺失根探测与失效。
99
+ 该提供方采用两项职责分离。第一,目录与正文分离:发现阶段把 frontmatter 解析为摘要,而每次加载都重新读取文件,因此正文编辑无需 hash、修订号或缓存失效。第二,发现与监视分离:`list()` 在存在文件系统服务时通过 `ctx.fs` 扫描根目录并解析项目根(否则回退到可中止的 Node I/O),而独立的监视管理器负责 Chokidar 句柄、缺失根探测与失效。
98
100
 
99
101
  ### 源码地图
100
102
 
@@ -109,7 +111,7 @@ skill 可以是被扫描根目录顶层的目录 bundle `<name>/SKILL.md`,也
109
111
 
110
112
  ### 监视与失效
111
113
 
112
- 现有根目录由 Chokidar 以深度 1 监视;不存在的根会从最近的现有祖先开始,借助 `fs.watchFile` 每次沿一个缺失路径段跟踪。相关事件——直属 bundle 添加/移除、平铺 `.md` 添加/移除、直接 `SKILL.md` 添加/移除/变更——会在每个微任务批次合并为一次提供方失效,资源子树下的变更则被忽略。监视管理器受 `watchMaxProjects` 限制,会记录并重试失败的启动,并在释放时关闭所有句柄。第一方 `write`/`edit` 变更通过 `fs/observed` 事件同步失效。
114
+ 现有根目录由 Chokidar 以深度 1 监视;不存在的根会从最近的现有祖先开始,借助 `fs.watchFile` 每次沿一个缺失路径段跟踪。相关事件——直属 bundle 添加/移除、平铺 `.md` 添加/移除、直接 `SKILL.md` 添加/移除/变更——会在每个微任务批次合并为一次提供方失效,资源子树下的变更则被忽略。监视管理器受 `watchMaxProjects` 限制,会记录启动失败并重试,并在释放时关闭所有句柄。第一方 `write`/`edit` 变更通过 `fs/observed` 事件同步失效。
113
115
 
114
116
  </details>
115
117
 
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { access, lstat, readFile, readdir, stat } from "node:fs/promises";
1
+ import { access, lstat, readFile, readdir, realpath, stat } from "node:fs/promises";
2
2
  import { unwatchFile, watchFile } from "node:fs";
3
3
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
4
4
  import { homedir } from "node:os";
@@ -127,7 +127,7 @@ var FileSystemSkillProvider = class {
127
127
  kind: "directory",
128
128
  path: locator.directory
129
129
  },
130
- path: locator.path,
130
+ path: parsed.path,
131
131
  ...parsed.metadata !== void 0 ? { metadata: parsed.metadata } : {},
132
132
  content: parsed.content
133
133
  };
@@ -606,7 +606,7 @@ async function discoverRoot(root, ctx, provider) {
606
606
  kind: "directory",
607
607
  path: locator.directory
608
608
  },
609
- path: locator.path,
609
+ path: parsed.path,
610
610
  ...parsed.metadata !== void 0 ? { metadata: parsed.metadata } : {}
611
611
  });
612
612
  }
@@ -667,7 +667,7 @@ async function parseSkillFile(path, ctx, signal, trustedHost = false) {
667
667
  if (raw === void 0) return;
668
668
  let parsed;
669
669
  try {
670
- parsed = parseFrontmatter(raw);
670
+ parsed = parseFrontmatter(raw.content);
671
671
  } catch (error) {
672
672
  ctx.logger.warn(`skill file ${path} ignored: invalid YAML frontmatter: ${errorMessage(error)}`);
673
673
  return;
@@ -699,6 +699,7 @@ async function parseSkillFile(path, ctx, signal, trustedHost = false) {
699
699
  ...optionalString(parsed.data, "whenToUse"),
700
700
  invocation,
701
701
  ...optionalMetadata(parsed.data),
702
+ path: raw.path,
702
703
  content: parsed.body.trim()
703
704
  };
704
705
  }
@@ -710,10 +711,14 @@ async function readSkillText(ctx, path, signal, trustedHost = false) {
710
711
  const fs = optionalFileSystem(ctx);
711
712
  if (fs !== void 0 && !trustedHost) return await readSkillTextFromFileSystem(ctx, fs, path, signal);
712
713
  try {
713
- return await readFile(path, {
714
- encoding: "utf8",
715
- signal
716
- });
714
+ const resolvedPath = await realpath(path);
715
+ return {
716
+ path: resolvedPath,
717
+ content: await readFile(resolvedPath, {
718
+ encoding: "utf8",
719
+ signal
720
+ })
721
+ };
717
722
  } catch (error) {
718
723
  signal?.throwIfAborted();
719
724
  if (isAbsentSkillPathError(error)) return void 0;
@@ -740,7 +745,10 @@ async function readSkillTextFromFileSystem(ctx, fs, path, signal) {
740
745
  }
741
746
  if (info === void 0 || info.type !== "file") return void 0;
742
747
  try {
743
- return await fs.readText(target, signal);
748
+ return {
749
+ path: fs.processPath(target),
750
+ content: await fs.readText(target, signal)
751
+ };
744
752
  } catch (error) {
745
753
  signal?.throwIfAborted();
746
754
  if (isAbsentSkillPathError(error)) return void 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-skill-filesystem",
3
3
  "description": "Local filesystem skill provider for the DeepSeek Harness",
4
- "version": "0.1.5-rc.2",
4
+ "version": "0.1.6-alpha.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,9 +27,9 @@
27
27
  ],
28
28
  "license": "MIT",
29
29
  "peerDependencies": {
30
- "@deepseek-ai/dsh-fs": "^0.1.5-rc.2",
31
- "@deepseek-ai/dsh-home-paths": "^0.1.5-rc.2",
32
- "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
30
+ "@deepseek-ai/dsh-fs": "^0.1.6-alpha.1",
31
+ "@deepseek-ai/dsh-home-paths": "^0.1.6-alpha.1",
32
+ "@deepseek-ai/dsh-skill": "^0.1.6-alpha.1",
33
33
  "@deepseek-ai/cordis": "^4.0.2"
34
34
  },
35
35
  "dependencies": {
@@ -38,9 +38,9 @@
38
38
  "@deepseek-ai/schemastery": "^3.18.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@deepseek-ai/dsh-fs": "^0.1.5-rc.2",
42
- "@deepseek-ai/dsh-home-paths": "^0.1.5-rc.2",
43
- "@deepseek-ai/dsh-skill": "^0.1.5-rc.2",
44
- "@deepseek-ai/cordis": "^4.0.2"
41
+ "@deepseek-ai/dsh-fs": "^0.1.6-alpha.1",
42
+ "@deepseek-ai/dsh-skill": "^0.1.6-alpha.1",
43
+ "@deepseek-ai/cordis": "^4.0.2",
44
+ "@deepseek-ai/dsh-home-paths": "^0.1.6-alpha.1"
45
45
  }
46
46
  }