@jayyuen66/dsh-quality-gate 0.1.3 → 0.1.4
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 +12 -0
- package/README.md +7 -6
- package/README.zh-CN.md +6 -5
- package/THIRD_PARTY_NOTICES.md +4 -1
- package/client.js +501 -254
- package/docs/DETAIL.md +24 -0
- package/docs/DETAIL.zh.md +24 -0
- package/host.js +171 -20
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +40 -32
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
格式遵循 [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),版本号遵循
|
|
4
4
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html)。最新版本在最上。
|
|
5
5
|
|
|
6
|
+
## 0.1.4
|
|
7
|
+
|
|
8
|
+
这一版收窄回合门禁的作用域:子包自己的 workspace 门禁不再被外层伞工作区顶掉,改单仓的回合不再跑整棵树。
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **单仓安装态下两份 zod 的 `ZodType` 不兼容**:宿主投影包自带 zod 4.4.3,本包 catalog 是
|
|
13
|
+
4.6.7;`editLedgerProjection.stateSchema` 经宿主声明的类型做一次窄桥接,运行期仍交给宿主
|
|
14
|
+
`safeParse`,不改依赖版本。
|
|
15
|
+
- **子包自己的 workspace 门禁被外层伞工作区顶掉。** 编辑一个自带 `pnpm-workspace.yaml` 且声明了 `check` 的子包时,根探测会继续上溯到外层伞工作区,把「改一个仓」放大成「整棵树跑一遍 `pnpm check`」:回合收口的预算被单条命令吃光,改本仓的回合反而反复超时。现在子包自己产得出 `pnpm check` 时就地执行、不再上溯;外层升级只在子包自己产不出门禁时发生。`test/host-integrity.test.ts` 新增一条伞工作区用例钉住这一面。
|
|
16
|
+
- **脚本内部的 exit 126/127 被误报成「门禁工具缺失」。** 126/127 是整条命令的退出码,不是「工具没装」的充分证据:`pnpm check` 的 check 脚本里缺命令时 pnpm 同样以 127 退出(实测 `pnpm run check` 对不存在的脚本命令回 `[ELIFECYCLE] Command failed with exit code 127`),tsc 的脚本也可能因缺 devDependency 回 127。原先这两档一律按 not-run 注入「command not found (tool not installed) — the gate did not run」,项目自己的坏脚本被当成环境问题放掉。现在只有 stderr **点名门禁命令自己的首 token**(`sh: pnpm: command not found`、`command not found: tsc`、Windows 的 `'pnpm' is not recognized`)才判工具不可用,其余 126/127 按代码失败上报并附证据;126 同理只在点名「不可执行」时判 not-run。`test/host.test.ts` 与 `test/host-integrity.test.ts` 的 126/127 用例补上点名证据,并新增一条「脚本内 127 仍报代码失败」的用例。
|
|
17
|
+
|
|
6
18
|
## 0.1.3
|
|
7
19
|
|
|
8
20
|
这一版把判定面与构建/CI 面一起收口:ruff 不再对只写了 `pyproject.toml` 的工程发门禁,卡片保存期间的编辑不再被静默丢弃,记忆反馈的文案与来源一致,Windows 与发布链的静默降级补上判据。宿主线抬到 `0.2.1-rc.3`。
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/v/@jayyuen66/dsh-quality-gate?style=flat-square&logo=npm&logoColor=white" alt="npm version" /></a>
|
|
11
|
-
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/
|
|
11
|
+
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/d18m/@jayyuen66/dsh-quality-gate?style=flat-square" alt="npm downloads (total)" /></a>
|
|
12
12
|
<a href="https://github.com/JayYuen666/dsh-quality-gate/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/JayYuen666/dsh-quality-gate/ci.yml?branch=main&style=flat-square&label=ci" alt="ci" /></a>
|
|
13
13
|
<img src="https://img.shields.io/badge/license-MIT-4c1?style=flat-square" alt="MIT" />
|
|
14
14
|
<img src="https://img.shields.io/badge/node-%3E%3D22.12-4c1?style=flat-square&logo=nodedotjs&logoColor=white" alt="node" />
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
- **Turn-end, not in-flight.** The hook is the host event `agent/turn-stopping`: read this session's **successful** edits → walk each file up to the nearest manifest root → detect the gate → run it. A failure is injected back via `agent.followup`; the host still checks the inbox after turn-stopping, so a repair instruction opens a new turn.
|
|
51
51
|
- **One run has exactly three outcomes**: `pass` (it really finished with exit 0), `code-failure` (it ran and reported code errors), `not-run` (it never ran). A check that did not truly complete is never recorded as passed; and "could not run" is never conflated with "code error" — the former injects "please confirm manually", writes no memory and never reaches the lesson bus as `gate-failure`.
|
|
52
52
|
- **Only commands the project itself declares.** One of four whitelist commands per root; without a declaration the gate is simply not issued — better no gate than an invented command that fails deterministically (see "The four gate commands").
|
|
53
|
-
- **Runaway protection.** Repair injections are quota'd per session across turns; once spent, one user-visible release note is injected and auto-repair stops. The total gate time is budget-capped; a timeout
|
|
53
|
+
- **Runaway protection.** Repair injections are quota'd per session across turns; once spent, one user-visible release note is injected and auto-repair stops. The total gate time is budget-capped; a timeout is injected as "could not run" instead of passing silently.
|
|
54
54
|
- **It does not edit code, does not block dangerous commands (that is danger-guard's job) and does not write any file.**
|
|
55
55
|
|
|
56
56
|
## <img src="https://api.iconify.design/lucide/package.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> Install
|
|
@@ -62,9 +62,10 @@ dsh plugin --profile web add @jayyuen66/dsh-quality-gate
|
|
|
62
62
|
Remove with `dsh plugin --profile web remove @jayyuen66/dsh-quality-gate`. The package is on the public npm registry, so installation needs no credentials.
|
|
63
63
|
|
|
64
64
|
- **Requires Node.js `>= 22.12`.** The artifacts use newer runtime faces such as `AbortSignal.any`.
|
|
65
|
-
- **Requires a host `dsh` on the `0.2.1-rc.3` line.** The requirement the host reads is `engines.dsh` (`^0.2.1-rc.3`), and it **decides alone**; pre-release versions participate in range comparison, and `0.3.0` and later need the explicit, risk-accepting grant `dsh plugin --profile <p> allow-version <pkg>@<ver> --dsh-version <exact> --accept-risk`.
|
|
65
|
+
- **Requires a host `dsh` on the `0.2.1-rc.3` line.** The requirement the host reads is `engines.dsh` (`^0.2.1-rc.3`), and it **decides alone**; pre-release versions participate in range comparison, and `0.3.0` and later need the explicit, risk-accepting grant `dsh plugin --profile <p> allow-version <pkg>@<ver> --dsh-version <exact> --accept-risk`.The support window rolls: this package is verified against the three most recently released host versions at publish time and re-verified once the window moves, so the version number in this bullet is not a standing promise.
|
|
66
66
|
- **The runtime dependency `@jayyuen66/dsh-plugin-shared` must already be on the same registry**, otherwise the whole set 404s.
|
|
67
67
|
- **`typescript` is a real `dependencies` entry**: the fallback entry for the `tsc` gate — the project's own install wins, then the copy shipped with this package; no network action at runtime, never an `npx` auto-download.
|
|
68
|
+
- **`zod` is also a real `dependencies` entry**: the edit-ledger projection state and the settings card's value/draft faces use it for shape validation, versioned through the umbrella catalog. The client artifact keeps `require("zod")` externalized via the host's `PLATFORM_MODULES`.
|
|
68
69
|
- **`@deepseek-ai/schemastery` is resolved from the host, not installed by this package**: only the host's fork resolves `.volatile()` fields into live references; a public schemastery turns "edit a setting" into "restart to apply". Two validator functions of `@deepseek-ai/dsh-credentials` are value imports, so that package sits in `peerDependencies` — no `@deepseek-ai/*` under `dependencies` is a publishing contract (`test/publish-manifest.test.ts` enforces it: a host package there materializes a second copy in the consumer's profile, next to the running host).
|
|
69
70
|
- Installing a local directory needs pnpm ≥ 12.3.0 (12.0.0 has a known bug in that path).
|
|
70
71
|
|
|
@@ -108,7 +109,7 @@ The whitelist is locked at type level (the `GateCommand` union in `lib/gate-dete
|
|
|
108
109
|
| `tsc --noEmit` | The root has both `package.json` and `tsconfig.json`; without `tsconfig.json` it is not a TS project |
|
|
109
110
|
|
|
110
111
|
- `tsc` is only a logical name in the command: the entry is resolved at runtime — the project's own `typescript` first, then the copy shipped with this package, finally `tsc` on PATH (reported as not-run by the "tool unavailable" exit); never an `npx` auto-download.
|
|
111
|
-
- Root detection: from each edited file, up to `maxRootDepth` (default 10) levels to the nearest manifest root; a monorepo package is upgraded to the workspace root holding `pnpm-workspace.yaml` — but only when that root **yields a gate**; otherwise the package keeps its own root (an outer workspace without a `check` script must not swallow the package's `tsc`/`ruff` gate).
|
|
112
|
+
- Root detection: from each edited file, up to `maxRootDepth` (default 10) levels to the nearest manifest root; a package that is **itself** a workspace root yielding `pnpm check` keeps its own root (a change in one package must not fan out into the whole umbrella workspace), and otherwise a monorepo package is upgraded to the workspace root holding `pnpm-workspace.yaml` — but only when that root **yields a gate**; otherwise the package keeps its own root (an outer workspace without a `check` script must not swallow the package's `tsc`/`ruff` gate).
|
|
112
113
|
- Budget and concurrency: total budget `gateBudgetMs`; each root gets the smaller of `max(10s, budget / root count)` and the time actually left; a tail with under 5s left does not start and is injected as "did not run". Gates run sequentially and only one failure is injected at a time.
|
|
113
114
|
- Evidence caps: 64 KiB per stream stays in memory (the tail is kept; the first error is the root cause), and when truncated a bounded 4 KiB head excerpt is read back from the spill file; the per-session edit accumulator holds 500 files, evicting oldest-first with a warning.
|
|
114
115
|
|
|
@@ -120,7 +121,7 @@ The namespace `quality-gate` is the settings entry id; the fields projected into
|
|
|
120
121
|
| --- | --- | --- | --- |
|
|
121
122
|
| `enabled` | boolean | `true` | Master switch; off means no turn-end verification at all |
|
|
122
123
|
| `maxInjectsPerTurn` | natural, 1–5 | `2` | Repair-injection quota, accumulated per session across turns |
|
|
123
|
-
| `gateBudgetMs` | natural, 10000–600000 | `300000` | Total gate budget; a timeout
|
|
124
|
+
| `gateBudgetMs` | natural, 10000–600000 | `300000` | Total gate budget; a timeout is injected as "could not run" instead of passing silently |
|
|
124
125
|
| `memoryFeedback` | boolean | `false` | Additionally persist code-level failures to the memory gateway |
|
|
125
126
|
| `memoryGatewayUrl` | string | `""` (unset) | Gateway base URL; the setting wins, empty falls back to the env `TDAI_GATEWAY_URL` |
|
|
126
127
|
| `memoryGatewayKeyRef` | string (credential ref name) | `TDAI_GATEWAY_KEY` | Ref name of the gateway key; the value lives in the host credential service, never in settings |
|
|
@@ -166,7 +167,7 @@ Settings persist in the host's settings file under the dsh data directory; the c
|
|
|
166
167
|
| Question | Answer |
|
|
167
168
|
| --- | --- |
|
|
168
169
|
| Why did my pnpm project not run `pnpm check`? | Its root `package.json` declares no non-empty `check` script — a deliberate trade: a false failure costs more than a missed check |
|
|
169
|
-
| The gate said "could not run" — is my code broken? | No. Sandbox policy denial, a runner that will not start, a timeout, a cancellation, exit 126/127
|
|
170
|
+
| The gate said "could not run" — is my code broken? | No. Sandbox policy denial, a runner that will not start, a timeout, a cancellation, an exhausted budget, and exit 126/127 **whose stderr names the gate command itself** (tool not installed) all land here. The injected text explicitly says **do not change code because of it**, and it is reported separately as `gate-not-run`. A 126/127 raised *inside* your own `check` script is a code failure and is reported as such |
|
|
170
171
|
| Can it loop forever? | Once the quota is spent it injects one user-visible release note, stops auto-repair, and only counts again after a fully clean pass |
|
|
171
172
|
| Stop it temporarily? | Turn off `enabled` on the card, or run `dsh plugin --profile web remove @jayyuen66/dsh-quality-gate` |
|
|
172
173
|
| Which `tsc` is used? | The project's own install first, then the `typescript` shipped with this package, and PATH only as the last resort — never an `npx` download |
|
package/README.zh-CN.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/v/@jayyuen66/dsh-quality-gate?style=flat-square&logo=npm&logoColor=white" alt="npm version" /></a>
|
|
11
|
-
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/
|
|
11
|
+
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-quality-gate"><img src="https://img.shields.io/npm/d18m/@jayyuen66/dsh-quality-gate?style=flat-square" alt="npm downloads (total)" /></a>
|
|
12
12
|
<a href="https://github.com/JayYuen666/dsh-quality-gate/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/JayYuen666/dsh-quality-gate/ci.yml?branch=main&style=flat-square&label=ci" alt="ci" /></a>
|
|
13
13
|
<img src="https://img.shields.io/badge/license-MIT-4c1?style=flat-square" alt="MIT" />
|
|
14
14
|
<img src="https://img.shields.io/badge/node-%3E%3D22.12-4c1?style=flat-square&logo=nodedotjs&logoColor=white" alt="node" />
|
|
@@ -62,9 +62,10 @@ dsh plugin --profile web add @jayyuen66/dsh-quality-gate
|
|
|
62
62
|
卸载:`dsh plugin --profile web remove @jayyuen66/dsh-quality-gate`。包在公共 npm 上,安装不需要凭据,也不需要配作用域源。
|
|
63
63
|
|
|
64
64
|
- **要求 Node.js `>= 22.12`。** 产物用到 `AbortSignal.any` 这类较新的运行面。
|
|
65
|
-
- **要求宿主 `dsh` 在 `0.2.1-rc.3` 这条线上。** 宿主读取的版本要求是 `engines.dsh`(`^0.2.1-rc.3`),它**单独决定**兼容性;预发布版本参与范围比较,`0.3.0` 及以后要走显式担责的授权 `dsh plugin --profile <p> allow-version <pkg>@<ver> --dsh-version <exact> --accept-risk
|
|
65
|
+
- **要求宿主 `dsh` 在 `0.2.1-rc.3` 这条线上。** 宿主读取的版本要求是 `engines.dsh`(`^0.2.1-rc.3`),它**单独决定**兼容性;预发布版本参与范围比较,`0.3.0` 及以后要走显式担责的授权 `dsh plugin --profile <p> allow-version <pkg>@<ver> --dsh-version <exact> --accept-risk`。支持窗口是滚动的:本包在发布时最近的三个已发布宿主版本上逐版取证,窗口滚动后重新取证,不把这一句里的版本号当长期承诺。
|
|
66
66
|
- **运行时依赖 `@jayyuen66/dsh-plugin-shared` 必须已在同一 registry 上**,否则整组 404。
|
|
67
67
|
- **`typescript` 是真实的 `dependencies`**:`tsc` 门禁的兜底入口——工程自己装的那份优先,其次随包安装的这份,运行期无网络动作,从不走 `npx` 的自动下载。
|
|
68
|
+
- **`zod` 也是真实的 `dependencies`**:编辑台账投影状态与设置卡的值面/草稿面用它校验形状;版本走伞根 catalog。client 产物按宿主 `PLATFORM_MODULES` 保持 `require("zod")` 外部化。
|
|
68
69
|
- **`@deepseek-ai/schemastery` 由宿主解析、不由本包安装**:只有宿主 fork 的那一枚能把 `.volatile()` 字段解析成活引用,换成公共 schemastery 就变成改设置要重启才生效。`@deepseek-ai/dsh-credentials` 的两枚校验函数是值导入,因此落在 `peerDependencies`——`dependencies` 里不放任何 `@deepseek-ai/*` 是发布契约(`test/publish-manifest.test.ts` 钉着:写在 `dependencies` 里的宿主包会在消费方 profile 里物化出第二份,与运行中的宿主并存)。
|
|
69
70
|
- 本地目录形态安装需 pnpm ≥ 12.3.0(12.0.0 的本地目录 `add` 有已知缺陷)。
|
|
70
71
|
|
|
@@ -110,7 +111,7 @@ dsh plugin --profile web add @jayyuen66/dsh-quality-gate
|
|
|
110
111
|
| `tsc --noEmit` | 根同时有 `package.json` 与 `tsconfig.json`;缺 `tsconfig.json` 不算 TS 项目 |
|
|
111
112
|
|
|
112
113
|
- `tsc` 在命令里只是逻辑名:入口在运行期解析——工程自己装的 `typescript` 优先,其次随包那份,最后 PATH 上的 `tsc`(由「工具不可用」出口报成未执行);绝不走 `npx` 的自动下载。
|
|
113
|
-
- 根探测:从编辑文件向上最多 `maxRootDepth`(默认 10
|
|
114
|
+
- 根探测:从编辑文件向上最多 `maxRootDepth`(默认 10)层找最近清单根;子包**自己就是** workspace 根且能产出 `pnpm check` 时就地执行(改一个包不得把整棵伞工作区拖进来);否则 monorepo 子包升到 `pnpm-workspace.yaml` 所在的工作区根——但只在该根**产得出门禁**时升级,再否则保留子包自己的根(外层没有 `check` 脚本的 workspace 不得吃掉子包的 `tsc` / `ruff` 门禁)。
|
|
114
115
|
- 预算与并发:总预算 `gateBudgetMs`;每根取 `max(10s, 预算/根数)` 与实际剩余的较小值;剩余不足 5s 的尾段不再起跑,按「未执行」注入清单。门禁顺序执行,一次只注入一个失败。
|
|
115
116
|
- 证据上限:每条流内存留存 64 KiB(截断保尾部,首条错误才是根因),被截断时从落盘文件有界读回 4 KiB 头部;单会话编辑记账 500 个文件,超出按插入序淘汰并 warn。
|
|
116
117
|
|
|
@@ -122,7 +123,7 @@ dsh plugin --profile web add @jayyuen66/dsh-quality-gate
|
|
|
122
123
|
| --- | --- | --- | --- |
|
|
123
124
|
| `enabled` | boolean | `true` | 总开关;关掉即收口不再核验 |
|
|
124
125
|
| `maxInjectsPerTurn` | natural,1–5 | `2` | 修复指令注入配额,按会话跨回合累计 |
|
|
125
|
-
| `gateBudgetMs` | natural,10000–600000 | `300000` |
|
|
126
|
+
| `gateBudgetMs` | natural,10000–600000 | `300000` | 门禁总预算;超时按「未执行」注入,不静默放行 |
|
|
126
127
|
| `memoryFeedback` | boolean | `false` | 是否把代码型失败额外沉淀到记忆网关 |
|
|
127
128
|
| `memoryGatewayUrl` | string | `""`(未配置) | 网关基址;设置值优先,留空回落 env `TDAI_GATEWAY_URL` |
|
|
128
129
|
| `memoryGatewayKeyRef` | string(凭据引用名) | `TDAI_GATEWAY_KEY` | 网关密钥的引用名;值走宿主凭据服务,不落设置 |
|
|
@@ -168,7 +169,7 @@ dsh plugin --profile web add @jayyuen66/dsh-quality-gate
|
|
|
168
169
|
| 问题 | 回答 |
|
|
169
170
|
| --- | --- |
|
|
170
171
|
| pnpm 工程为什么没跑 `pnpm check`? | 根 `package.json` 没声明非空 `check` 脚本。刻意取舍:假失败比漏检查更贵 |
|
|
171
|
-
| 门禁说「未能执行」,是代码错了吗? | 不是。沙箱策略拒绝、runner
|
|
172
|
+
| 门禁说「未能执行」,是代码错了吗? | 不是。沙箱策略拒绝、runner 起不来、超时、取消、预算不足,以及 stderr **点名门禁命令自身**(工具没装)的 exit 126/127 都属此类。注入文案明确要求**不要为此修改代码**,并以 `gate-not-run` 单独上报总线。若 126/127 来自你自己的 `check` 脚本内部,那是代码失败,按代码失败上报 |
|
|
172
173
|
| 会不会无限修下去? | 配额耗尽后注入一次用户可见的放行说明并停止自动修复,直到某次全部干净通过才重新计数 |
|
|
173
174
|
| 临时停掉? | 设置卡关 `enabled`,或 `dsh plugin --profile web remove @jayyuen66/dsh-quality-gate` |
|
|
174
175
|
| `tsc` 用哪个版本? | 工程自己装的那份优先,其次随包安装的 `typescript`,都不在才回落 PATH——从不经 `npx` 下载 |
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -45,8 +45,11 @@
|
|
|
45
45
|
profile 里那一份实例,因此不存在"把第三方源码打进发布物"的情形,本文件也就不需要附各包的
|
|
46
46
|
许可证全文。
|
|
47
47
|
|
|
48
|
-
- `@jayyuen66/dsh-plugin-shared`(MIT
|
|
48
|
+
- `@jayyuen66/dsh-plugin-shared`(MIT)——普通依赖。`lib/locale`、`lib/tool-events`、
|
|
49
49
|
`lib/lesson-bus`、`lib/record`、`lib/project-key` 五个子路径来自它。
|
|
50
|
+
- `zod`(MIT)——普通依赖。`lib/edit-ledger.ts` 的投影状态与 `src/client-entry.ts` 的设置卡
|
|
51
|
+
值面/草稿面用它做形状校验;client 产物按宿主 `PLATFORM_MODULES` 保持 `require("zod")` 外部化。
|
|
52
|
+
- `typescript`(Apache-2.0)——普通依赖,`tsc` 门禁的兜底入口。
|
|
50
53
|
- `@deepseek-ai/*`(一律 MIT,由宿主提供,声明为 peer / devDependency,**不进** `dependencies`)
|
|
51
54
|
——`dsh`、`cordis`、`schemastery`、`dsh-settings`、`dsh-shell`、`dsh-sandbox`、
|
|
52
55
|
`dsh-sandbox-policy`、`dsh-session`、`dsh-session-query`、`dsh-session-projection`、
|