dsh-plugin-guide 0.3.29 → 0.3.30

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.md CHANGED
@@ -60,7 +60,7 @@ content counts as stated in the README (What you get)
60
60
 
61
61
  | Surface | Status |
62
62
  |---|---|
63
- | Harness | DeepSeek Harness `dsh-v0.2.1-alpha.2` (`d743267388641bc76f17c45ce8b4c231aed1d32c`, the newest master tag **and** master HEAD, 2026-10-09); npm `latest` = `next` = `0.2.0-rc.2`, `alpha` = `0.2.1-alpha.2`. **There is no stable line** — all 31 npm versions and all 26 GitHub Releases are prereleases. The official-docs mirror and `guide/migration-0.2.md` are pinned one release back, at `dsh-v0.2.1-alpha.1` (`5badb15009`, 2026-10-03); the 20 breaking-change guides added since are captured in [guide/version-matrix.md](guide/version-matrix.md) §3. |
63
+ | Harness | DeepSeek Harness `dsh-v0.2.1-alpha.2` (`d743267388641bc76f17c45ce8b4c231aed1d32c`, the newest master tag **and** master HEAD, 2026-10-09); npm `latest` = `next` = `0.2.0-rc.2`, `alpha` = `0.2.1-alpha.2`. **There is no stable line** — all 31 npm versions and all 26 GitHub Releases are prereleases. The official-docs mirror is pinned to that same commit (429 md pages, re-synced 2026-10-13; see [references/official-docs/SNAPSHOT.md](references/official-docs/SNAPSHOT.md)). `guide/migration-0.2.md` covers `0.1.6-alpha.2` → `0.2.1-alpha.1` in §0–§12 and `0.2.1-alpha.1` → `0.2.1-alpha.2` as 19 citable seams in §13; the 20 breaking-change guides added since the previous baseline (19 under `v0.2.1-alpha.1` plus one backfilled into `v0.2.0-rc.2`) are all in the mirror. |
64
64
  | Node | `^22.19.0 || >=24.0.0` (DeepSeek Harness runtime) |
65
65
  | Platforms | All (plain ESM bundle; no native code, no network) |
66
66
  | Model | Any (no model interaction) |
package/SKILL.md CHANGED
@@ -19,7 +19,14 @@ description: Use when developing, reviewing, packaging, debugging, or answering
19
19
 
20
20
  ## 开发前置(第一步必做)
21
21
 
22
- 0. **先认版本**:`dsh --version`,然后读 `guide/version-matrix.md`(**版本适配矩阵**:五个"最新"的区分、子包 `latest` 冻结陷阱、破坏性变更断层、peer 区间选择、会话格式谱系)。要点:`0.1.7-alpha.1`(2026-09-22)起包含本世代全部破坏性变更(会话格式 V4、settings 重写、`readBytes`、Messages-only 适配器);**npm `latest`=`0.2.0-rc.2`、`next`=`0.2.0-rc.2`、`alpha`=`0.2.1-alpha.2`,而 master 最新 tag 是 `dsh-v0.2.1-alpha.2`——这四个"最新"不是同一个东西**。**不存在稳定版**:全部 31 个 npm 版本都是 prerelease。目标宿主不是 matrix 基线时,按 `guide/migration-0.2.md` 逐条对照;目标宿主**更新**(如 `0.2.1-alpha.2`)时另见 `guide/version-matrix.md` §3 的 19 条新破坏性变更。
22
+ 0. **先认版本**:跑 `dsh --version`,然后按下表决定读什么。**不要跳过这一步**——本库 17 篇文档里对当前宿主不适用的部分不会自己标注。
23
+ | 你的 `dsh --version` | 含义 | 读什么 |
24
+ |---|---|---|
25
+ | `< 0.1.7-alpha.1` | 旧基线 | 本世代破坏性变更**全部适用** → `guide/migration-0.2.md` §0–§12 逐条改 |
26
+ | `0.1.7-alpha.1` – `0.2.1-alpha.1` | 中间线 | 会话格式 V4 已生效;§13 的 19 条**不适用** |
27
+ | `0.2.1-alpha.2` 或更新 | 最新线 | §13 的 19 条**适用** → `guide/version-matrix.md` §3 |
28
+ | **npm `latest`(= `0.2.0-rc.2`)** | **默认安装拿到的就是这一版** | ⚠️ 它**早于** master 一版:§13 不适用,但 `version-matrix.md` §1.1 的"不存在稳定版"警告适用 |
29
+ **四个"最新"不是同一个东西**:npm `latest`=`next`=`0.2.0-rc.2`、npm `alpha`=`0.2.1-alpha.2`、master 最新 tag = `dsh-v0.2.1-alpha.2`。**不存在稳定版**(全部 31 个 npm 版本都是 prerelease)。完整谱系、子包 `latest` 冻结陷阱与 peer 区间选择见 `guide/version-matrix.md`。
23
30
  1. 若未读过 Cordis 概念:读 `references/official-docs/docs/cordis-primer.md`(5 个概念,5 分钟);需要动手跟练时跑 `references/official-docs/docs/cordis-tutorial/` 01-07(无 API key 可跑)。
24
31
  2. 打开 `guide/quick-reference.md`(契约速查)+ `guide/plugin-dev-guide.md`(完整路径)。官方/社区文档 URL 对照见 `guide/links.md`。排查官方运行时行为/未修复 bug 时查 `guide/unfixed-issues.md`(master 基线源码核实的问题清单 + 已修复提交号 + 设计行为对照 + 本世代新核实的 T1–T11)。决定一个插件**该不该继续维护**(官方已进内核 / 第三方采用度显著更高)时查 `guide/when-to-retire-a-plugin.md`(判据 + 实测倍数表);判断某个能力面谁领先时查 `guide/choosing-a-plugin.md`。
25
32
  2b. **要判断"该改哪一行 / 该找哪个工具"时**,读 `guide/family-toolchain.md`(家族工具链路由:问题→所有者→可引用产物;`dsh-plugin-doctor` 33 项检查全表与裁定语义;本库 16 项检查与 doctor 的交叉对照)。发布流水线(多插件组合的持续可安装/可发布/可升级)见 `guide/release-engineering.md`。
@@ -55,7 +62,7 @@ description: Use when developing, reviewing, packaging, debugging, or answering
55
62
  - **新服务/能力**:`docs/user/develop/framework/service.md` + `docs/user/develop/practice/`(三层拆分完整代码)。
56
63
  - **拦截/策略/hook**:`docs/cookbook/extension-cookbook.md`(permission-gate 范例)+ `docs/event-producer-consumer.md`(全事件矩阵)。
57
64
  - **新 LLM 提供商**:`docs/user/develop/practice/llm-adapter.md`(StreamChunk 协议)。
58
- - **UI 插件(Web)**:`references/official-plugin-dev-skill.md` §3.2 + `docs/subsystems/slots.md`、`sidebar-right.md`、`client-modules.md`、`web-client.md`、`ui-radius.md`;Chat 行业务节点用 `ctx.uiConversation.events.register()` + `conversation.chat.node` slot。
65
+ - **UI 插件(Web)**:`references/official-plugin-dev-skill.md` §3.2 + `docs/subsystems/slots.md`、`sidebar-right.md`、`client-modules.md`、`web-client.md`、**`docs/ui-radius.md`**(注意 `ui-radius` 在 `docs/` 顶层,**不在** `docs/subsystems/` 下);Chat 行业务节点用 `ctx.uiConversation.events.register()` + `conversation.chat.node` slot。
59
66
  - **插件配置表单**:`docs/subsystems/settings.md`(已改名 "Plugin Configuration Forms")+ `docs/cookbook/adding-a-settings-card.md`(已重写)。
60
67
  - **打包/发布**:`docs/user/develop/basic/publish.md`(bundle/profile、层顺序、多 patch 数组、peer 解析、git 安装坑)。
61
68
  - **升级/迁移**:`guide/version-matrix.md`(**版本适配矩阵:先读这个**——五个"最新"、子包 `latest` 冻结、破坏性变更断层、peer 区间选择、会话格式 V0→V4)→ `guide/migration-0.2.md`(本库综述,0.1.6→0.2.1-alpha.1)→ `docs/upgrade-guide/**`(官方逐版本迁移指南)+ `docs/persistence-changes/**`(持久化类型变更记录)+ `docs/session-format-status.md`(会话格式版本权威)。⚠️ **目标宿主是 `0.2.1-alpha.2` 或更新时**:`version-matrix.md` §3 列了该版落的 **19 条破坏性变更**(`webRuntime`→`webStartup`、`mode: both` 被拒、`backgroundMode`/`run_in_background` 移除、`{{cwd}}` 移除、`BundleInfo` 新增必填字段、`dsh plugin --profile` 位置强制等),`migration-0.2.md` **尚未并入**。
@@ -82,11 +89,16 @@ description: Use when developing, reviewing, packaging, debugging, or answering
82
89
 
83
90
  ## CLI 工具链(dsh-plugin-dev)
84
91
 
85
- 本仓库随 bundle 附带零依赖 CLI `dsh-plugin-dev`,把机械检查自动化(知识库仍是认知层,CLI 是机械层):
92
+ 本仓库随 bundle 附带零依赖 CLI `dsh-plugin-dev`,把机械检查自动化(知识库仍是认知层,CLI 是机械层)。
86
93
 
87
- - `dsh-plugin-dev new <name>`:参数化脚手架,生成 TS 或 JS 插件仓库骨架(`src/index.ts` 契约模板、Schemastery Config、tests、tsdown/vitest、注释齐全的 `cordis.patch.yml`、五语 README),模板与 `references/official-docs` 同步更新。
88
- - `dsh-plugin-dev check [--json] [--strict]`:静态检查(`cordis.patch.yml` 合法性、`package.json` 元数据(`dsh.bundle.patch` 指向/peer 依赖/engines/files 白名单)、五语 README 一致性、工程红线模式),输出 CI 可消费的结构化 JSON;每个检查项在输出里引用本知识库对应章节(skill 联动),agent 可继续人工审计。
89
- - `dsh-plugin-dev verify`:`pnpm pack` 后装入干净临时 `DSH_HOME` profile 做安装+启动+卸载冒烟(对齐官方 verify:self-contained);失败给出日志尾部与建议。
94
+ > ⚠️ **调用方式**:`dsh-plugin-dev` **通常不在 PATH 上**(bundle 安装只登记技能,不安装二进制)。
95
+ > 用本 SKILL.md 所在目录下的入口调用:`node "<resourceBase>/bin/dsh-plugin-dev.js" <子命令>`。
96
+ > bundle 安装的包已带 `dist/`;从源码副本用则先跑一次 `pnpm run build`。
97
+ > 只有全局 `npm i -g dsh-plugin-guide` 之后才可以直接敲 `dsh-plugin-dev`。
98
+
99
+ - `new <name>`:参数化脚手架,生成 TS 或 JS 插件仓库骨架(`src/index.ts` 契约模板、Schemastery Config、tests、tsdown/vitest、注释齐全的 `cordis.patch.yml`、五语 README),模板与 `references/official-docs` 同步更新。标志:`--lang <ts|js>`、`--dir <path>`、`--force`、`--git`。
100
+ - `check [--json] [--strict] [--cwd <dir>]`:静态检查(`cordis.patch.yml` 合法性、`package.json` 元数据(`dsh.bundle.patch` 指向/peer 依赖/engines/files 白名单)、五语 README 一致性、工程红线模式),输出 CI 可消费的结构化 JSON;每个检查项在输出里引用本知识库对应章节(skill 联动),agent 可继续人工审计。**这 16 项是同族 `dsh-plugin-doctor` 33 项的子集**(逐项对照见 `guide/family-toolchain.md` §3);发布前建议两个都跑。
101
+ - `verify [--cwd <dir>] [--base <spec>] [--headless <spec>] [--profile <name>]`:`pnpm pack` 后装入干净临时 `DSH_HOME` profile 做安装+启动+卸载冒烟(对齐官方 verify:self-contained);失败给出日志尾部与建议。
90
102
 
91
103
  三个子命令均可逆/幂等;网络/子进程尊重超时与 AbortSignal;只清理自己 mkdtemp 的目录。CLI 零运行时依赖,构建产物经 tsdown 打包为单文件 `dist/dsh-plugin-dev.js`。
92
104
 
@@ -9,14 +9,31 @@ const LONG_ALIASES = {
9
9
  help: "help",
10
10
  version: "version"
11
11
  };
12
+ /** Raised for a malformed or unrecognised argument. */
13
+ var UsageError = class extends Error {};
12
14
  /**
13
15
  * Parse an argv slice (without the node/script prefix) into positionals and flags.
16
+ *
17
+ * `allowed` is the set of long flag names the caller accepts (aliases included).
18
+ * Passing it turns an unrecognised flag into a `UsageError` instead of a silently
19
+ * ignored one: `dsh-plugin-dev check --stirct` used to parse the typo, check
20
+ * nothing extra, and exit 0 — a gate that can be disabled by a spelling mistake
21
+ * is worse than no gate, because CI stays green and everyone believes it ran.
22
+ *
14
23
  * @param argv - process.argv.slice(2) style input.
24
+ * @param allowed - optional allowlist of accepted long flag names.
15
25
  * @returns the parsed structure.
16
26
  */
17
- function parseArgs(argv) {
27
+ function parseArgs(argv, allowed) {
18
28
  const positionals = [];
19
29
  const flags = {};
30
+ const permitted = allowed ? new Set(allowed) : void 0;
31
+ const assertAllowed = (key) => {
32
+ if (permitted && !permitted.has(key)) {
33
+ const known = [...permitted].sort().join(", ");
34
+ throw new UsageError(`unknown option "--${key}" (accepted: ${known})`);
35
+ }
36
+ };
20
37
  for (let i = 0; i < argv.length; i++) {
21
38
  const arg = argv[i];
22
39
  if (arg === "--") {
@@ -27,10 +44,13 @@ function parseArgs(argv) {
27
44
  const body = arg.slice(2);
28
45
  const eq = body.indexOf("=");
29
46
  if (eq >= 0) {
30
- setFlag(flags, body.slice(0, eq), body.slice(eq + 1));
47
+ const key = body.slice(0, eq);
48
+ assertAllowed(LONG_ALIASES[key] ?? key);
49
+ setFlag(flags, key, body.slice(eq + 1));
31
50
  continue;
32
51
  }
33
52
  const key = body;
53
+ assertAllowed(LONG_ALIASES[key] ?? key);
34
54
  const next = argv[i + 1];
35
55
  if (next !== void 0 && !next.startsWith("-")) {
36
56
  setFlag(flags, key, next);
@@ -39,7 +59,10 @@ function parseArgs(argv) {
39
59
  continue;
40
60
  }
41
61
  if (arg.startsWith("-") && arg.length > 1) {
42
- for (const ch of arg.slice(1)) flags[ch] = true;
62
+ for (const ch of arg.slice(1)) {
63
+ assertAllowed(ch);
64
+ flags[ch] = true;
65
+ }
43
66
  continue;
44
67
  }
45
68
  positionals.push(arg);
@@ -909,7 +932,8 @@ function checkManifestFiles(_root, pkg) {
909
932
  const problems = [];
910
933
  for (const patchFile of patchFiles) if (!files.includes(patchFile)) problems.push(`files whitelist is missing the patch file "${patchFile}"`);
911
934
  if (main && !files.includes(main) && !files.some((f) => main.startsWith(`${f.replace(/\/$/, "")}/`))) problems.push(`files whitelist is missing the main entry "${main}"`);
912
- if (!files.some((f) => f === "lib" || f === "dist")) problems.push("files whitelist has no built-artifact directory (`lib` or `dist`)");
935
+ const entryDir = main?.includes("/") ? main.slice(0, main.indexOf("/")) : void 0;
936
+ if (entryDir && (entryDir === "lib" || entryDir === "dist") && !files.includes(entryDir)) problems.push(`files whitelist has no built-artifact directory ("${entryDir}"), but main points into it`);
913
937
  if (problems.length > 0) return {
914
938
  id: "manifest-files",
915
939
  severity: "error",
@@ -1104,14 +1128,26 @@ function checkReadmeConsistency(root) {
1104
1128
  skillRef: ref
1105
1129
  };
1106
1130
  }
1107
- /** Body of SKILL.md after its YAML frontmatter, or undefined. */
1131
+ /**
1132
+ * Body of SKILL.md after its YAML frontmatter, or undefined when the file is
1133
+ * absent. Falls back to the whole text when there is no well-formed block.
1134
+ *
1135
+ * CRLF tolerance is load-bearing: without `.gitattributes`, a Windows checkout
1136
+ * (`core.autocrlf=true`) delivers CRLF while CI and the published tarball
1137
+ * deliver LF. An exact `startsWith('---\n')` guard therefore failed locally,
1138
+ * leaving the frontmatter in the "body" — so `redline-persona-role` judged the
1139
+ * `name:` line as the opening paragraph and emitted a false warning on every
1140
+ * local run while CI stayed green. Keep this in step with `index.js`.
1141
+ */
1108
1142
  function skillBody(root) {
1109
1143
  const text = readText(join(root, "SKILL.md"));
1110
1144
  if (!text) return void 0;
1111
- if (!text.startsWith("---\n")) return text;
1112
- const end = text.indexOf("\n---", 4);
1113
- if (end < 0) return text;
1114
- return text.slice(end + 4).replace(/^\n+/, "");
1145
+ const open = /^---\r?\n/.exec(text);
1146
+ if (!open) return text;
1147
+ const rest = text.slice(open[0].length);
1148
+ const close = /\r?\n---[ \t]*(?:\r?\n|$)/.exec(rest);
1149
+ if (!close) return text;
1150
+ return rest.slice(close.index + close[0].length).replace(/^(?:[ \t]*\r?\n)+/, "");
1115
1151
  }
1116
1152
  function checkRedlinePersonaRole(root) {
1117
1153
  const ref = skillRefFor("redline-persona-role");
@@ -1921,7 +1957,37 @@ function timeoutMs(flags, key, envKey, fallback) {
1921
1957
  * @param cwd - working directory (injectable for tests).
1922
1958
  */
1923
1959
  async function main(argv, cwd = process.cwd()) {
1924
- const { positionals, flags } = parseArgs(argv);
1960
+ const KNOWN_FLAGS = [
1961
+ "help",
1962
+ "h",
1963
+ "version",
1964
+ "V",
1965
+ "lang",
1966
+ "dir",
1967
+ "force",
1968
+ "git",
1969
+ "cwd",
1970
+ "json",
1971
+ "strict",
1972
+ "dsh",
1973
+ "pnpm",
1974
+ "profile",
1975
+ "base",
1976
+ "headless",
1977
+ "timeout",
1978
+ "smoke-timeout"
1979
+ ];
1980
+ let parsed;
1981
+ try {
1982
+ parsed = parseArgs(argv, KNOWN_FLAGS);
1983
+ } catch (err) {
1984
+ if (err instanceof UsageError) {
1985
+ process.stderr.write(`dsh-plugin-dev: ${err.message}\n`);
1986
+ return 2;
1987
+ }
1988
+ throw err;
1989
+ }
1990
+ const { positionals, flags } = parsed;
1925
1991
  if (flagBool(flags, "version") || flags.V === true) {
1926
1992
  process.stdout.write(`${readCliVersion()}\n`);
1927
1993
  return 0;
package/index.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ // Type declarations for the bundle entry point (`index.js`).
2
+ //
3
+ // `index.js` is plain ESM JavaScript and is intentionally not part of the
4
+ // TypeScript program (`tsconfig.json` includes only `src`, `tests` and the build
5
+ // configs, with `allowJs` off). `tests/entry.test.ts` imports it, so without this
6
+ // file `noImplicitAny` rejects the import as an untyped module.
7
+ //
8
+ // The declaration is deliberately loose: this module exists to be loaded by the
9
+ // host's Cordis loader, not consumed as a typed library, and the shapes it
10
+ // touches (`ctx.effect`, `ctx.skills.register`) belong to the harness rather
11
+ // than to this package. Pinning them here would create a second, drifting copy
12
+ // of the host contract — the exact failure mode `guide/family-toolchain.md`
13
+ // warns about. The test asserts the runtime shape instead.
14
+
15
+ /** Cordis plugin name contributed by this bundle. */
16
+ export declare const name: string
17
+
18
+ /** Services this plugin requires before `apply` runs. */
19
+ export declare const inject: string[]
20
+
21
+ /**
22
+ * Split a SKILL.md document into its frontmatter description and instruction
23
+ * body. Falls back to `{ description: undefined, body: text }` when there is no
24
+ * well-formed frontmatter block. Tolerates both LF and CRLF line endings.
25
+ */
26
+ export declare function splitFrontmatter(text: string): {
27
+ description: string | undefined
28
+ body: string
29
+ }
30
+
31
+ /** Register the knowledge-base skill. Registration is an effect. */
32
+ export declare function apply(ctx: any): void
package/index.js CHANGED
@@ -21,18 +21,33 @@ const packageRoot = dirname(fileURLToPath(import.meta.url))
21
21
 
22
22
  /**
23
23
  * Strip the YAML frontmatter block from SKILL.md and return the description
24
- * plus the instruction body. A malformed or missing block fails loud through
25
- * the read itself or falls back to the full text as the body.
24
+ * plus the instruction body. A malformed or missing block falls back to the
25
+ * full text as the body.
26
+ *
27
+ * CRLF tolerance is deliberate and load-bearing, not cosmetic. Without
28
+ * `.gitattributes`, git's `core.autocrlf=true` checks this repository out with
29
+ * CRLF while the published tarball and every CI checkout use LF. An exact
30
+ * `startsWith('---\n')` guard therefore took a different branch on a Windows
31
+ * working tree and the skill silently registered its generic fallback
32
+ * description instead of the trigger-phrase description from the frontmatter —
33
+ * the text that decides when the host loads the skill at all. `.gitattributes`
34
+ * now pins LF; this function no longer depends on that being true.
35
+ *
26
36
  * @param text - raw SKILL.md content.
27
37
  * @returns parsed description (when the frontmatter carries one) and body.
28
38
  */
29
- function splitFrontmatter(text) {
30
- if (!text.startsWith('---\n')) return { description: undefined, body: text }
31
- const end = text.indexOf('\n---', 4)
32
- if (end < 0) return { description: undefined, body: text }
33
- const meta = text.slice(4, end)
34
- const body = text.slice(end + 4).replace(/^\n+/, '')
35
- const match = /^description:\s*(.+)$/m.exec(meta)
39
+ export function splitFrontmatter(text) {
40
+ // Match the opening fence with either ending, then find the closing fence.
41
+ const open = /^---\r?\n/.exec(text)
42
+ if (!open) return { description: undefined, body: text }
43
+ const rest = text.slice(open[0].length)
44
+ const close = /\r?\n---[ \t]*(?:\r?\n|$)/.exec(rest)
45
+ if (!close) return { description: undefined, body: text }
46
+ const meta = rest.slice(0, close.index)
47
+ // Trim the separating blank lines so the body starts at the first heading,
48
+ // matching the host provider's own body trimming.
49
+ const body = rest.slice(close.index + close[0].length).replace(/^(?:[ \t]*\r?\n)+/, '')
50
+ const match = /^description:[ \t]*(.+?)[ \t]*$/m.exec(meta)
36
51
  return { description: match?.[1]?.trim(), body }
37
52
  }
38
53
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-plugin-guide",
3
- "version": "0.3.29",
4
- "description": "The dsh-plugin-guide knowledge base plus the dsh-plugin-dev CLI toolchain: official docs, Cordis primer, community deep-dives, and battle-tested pitfalls registered as an on-demand agent skill, with a scaffolder, static checker, and pack verifier for building DSH plugins.",
3
+ "version": "0.3.30",
4
+ "description": "DSH plugin development as an on-demand agent skill: official docs mirror, version-compatibility matrix, migration seams, measured pitfalls, plus a scaffolder, checker and pack verifier CLI.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "files": [
17
17
  "index.js",
18
+ "index.d.ts",
18
19
  "bin",
19
20
  "dist",
20
21
  "templates",
@@ -35,15 +36,21 @@
35
36
  ],
36
37
  "keywords": [
37
38
  "dsh",
38
- "deepseek-harness",
39
39
  "dsh-plugin",
40
+ "dsh-plugin-development",
41
+ "dsh-skill",
42
+ "deepseek",
43
+ "deepseek-harness",
40
44
  "cordis",
41
- "agent-skill",
42
45
  "plugin-development",
46
+ "agent-skill",
47
+ "agent-skills",
43
48
  "knowledge-base",
49
+ "documentation",
44
50
  "cli",
45
51
  "scaffold",
46
- "checker"
52
+ "checker",
53
+ "typescript"
47
54
  ],
48
55
  "license": "Apache-2.0",
49
56
  "repository": {
@@ -57,6 +64,7 @@
57
64
  "typecheck:checkout": "tsc -p tsconfig.checkout.json --noEmit",
58
65
  "test": "vitest run",
59
66
  "check:readmes": "node scripts/check-readme-sync.mjs",
67
+ "check:ps1-bom": "node scripts/check-ps1-bom.mjs",
60
68
  "build:llms": "node scripts/build-llms-full.mjs",
61
69
  "check:kit": "pwsh -File scripts/verify-kit.ps1",
62
70
  "verify:artifacts": "node scripts/verify-artifacts.mjs",
@@ -64,15 +72,14 @@
64
72
  "prepare": "tsdown",
65
73
  "prepack": "tsdown"
66
74
  },
67
- "dependencies": {
68
- "tsdown": "^0.22.14",
69
- "typescript": "^5.9.3"
70
- },
75
+ "dependencies": {},
71
76
  "devDependencies": {
72
77
  "@deepseek-ai/dsh-attachment": "0.2.1-alpha.2",
73
78
  "@types/node": "^22.20.1",
74
79
  "@types/semver": "^7.8.0",
75
80
  "semver": "^7.8.5",
81
+ "tsdown": "^0.22.14",
82
+ "typescript": "^5.9.3",
76
83
  "vitest": "^3.2.7"
77
84
  },
78
85
  "peerDependencies": {
@@ -122,6 +122,7 @@
122
122
  - 重跑:脚本均幂等,可随时刷新;`sync-official-docs.ps1` 同步官方文档副本(本次扩展了根文件范围与 `:(top)` pathspec/修剪)。
123
123
  - **08-14 晚环境限制记录**:`gh` CLI token 失效(401)后,GitHub 全部查询改走 git 协议(ls-remote/clone)与 codeload;api.github.com 匿名配额 60/h 仅用于 Discussions 评论精选抓取;本机网络直连 github.com 网页与 raw.githubusercontent.com 失败(curl 000),git https 与 codeload 正常。
124
124
  - **编码约定(重要)**:Windows PowerShell 5.1 无 BOM 的 UTF-8 脚本会按 ANSI 解析,中文注释尾字节可能吞换行导致代码行并入注释(本次真实踩坑);`scripts/*.ps1` 必须保持 **UTF-8 with BOM**,编辑后务必复核 BOM。
125
+ - **2026-10-13 复核(约定被违反的实例)**:实测 `scripts/` 下 9 个 `.ps1`,**8 个带 BOM 且 5.1 解析 0 错**;唯一无 BOM 的 `verify-kit.ps1` 有 **1644 个非 ASCII 字节**、在 5.1 下报 **5–6 个解析错误**(`Missing ')' in method call`)——**而它正是发布门禁**(`release.yml` 用 `shell: pwsh` 调它,所以 CI 从没发现;本机没有 pwsh 时才暴露)。已补回 BOM 并实测 `VERIFY-OK` / exit 0(82 项关键路径全在)。**根因不是约定错,而是这一个文件丢了 BOM**——另加 `.gitattributes` 固定行尾,避免同类问题复现。
125
126
  - 时间戳:下载会话 2026-08-14 22:45–23:59(+08:00);dsh-plugin topic 快照共三期(2026-08-13T15:15Z/08-13T18:36Z/08-14T08:16Z)+ 08-14 晚扫描(total_count 2034,见 §D.2)。
126
127
  - 官网 deepseek.com 页面受 Cloudflare 保护时可能失败——以 manifest 记录为准,正文内容以 GitHub Pages 同源文档为准。
127
128
  - **备注**:用户清单中 `ess-plugin-mcp` 经 GitHub 搜索无精确匹配(最接近者为 Skyrim .ess 插件工具的 MCP,与 DSH 无关);按 DSH 生态语义定位到 `bobleer/deepseek-harness-plugin-mcp`(让任意 agent 经 MCP 发现/安装/运行 DSH 插件)并归档,如用户所指另有其仓,请告知后补充。