universal-dev-standards 6.13.0-beta.4 → 6.13.0
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/bundled/ai/standards/turn-completion-integrity.ai.yaml +8 -2
- package/bundled/core/turn-completion-integrity.md +25 -4
- package/bundled/hooks/check-turn-completion.mjs +22 -6
- package/bundled/locales/zh-CN/CHANGELOG.md +19 -2
- package/bundled/locales/zh-CN/README.md +1 -1
- package/bundled/locales/zh-CN/SECURITY.md +1 -2
- package/bundled/locales/zh-CN/core/turn-completion-integrity.md +23 -8
- package/bundled/locales/zh-TW/CHANGELOG.md +19 -2
- package/bundled/locales/zh-TW/README.md +1 -1
- package/bundled/locales/zh-TW/SECURITY.md +1 -2
- package/bundled/locales/zh-TW/core/turn-completion-integrity.md +23 -8
- package/package.json +1 -1
- package/src/commands/init.js +6 -1
- package/standards-registry.json +7 -7
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
id: turn-completion-integrity
|
|
5
5
|
meta:
|
|
6
|
-
version: "1.4.
|
|
7
|
-
updated: "2026-09-
|
|
6
|
+
version: "1.4.1"
|
|
7
|
+
updated: "2026-09-28"
|
|
8
8
|
source: core/turn-completion-integrity.md
|
|
9
9
|
description: An agent must not end a turn having stated a next action it did not take; enforced at turn end, not by instruction
|
|
10
10
|
related:
|
|
@@ -134,12 +134,18 @@ supported_harnesses:
|
|
|
134
134
|
config_file: ".codex/hooks.json"
|
|
135
135
|
block_shape: '{"decision":"block","reason":...}, exit 0 — plain text or empty stdout documented as invalid for this event'
|
|
136
136
|
script: scripts/hooks/check-turn-completion-codex.mjs
|
|
137
|
+
activation: "Codex skips a project hook until the project is trusted AND the exact hook definition is trusted via /hooks (trust keyed to the definition's hash). Under codex exec an untrusted hook is skipped silently. Measured 2026-09-28, codex-cli 0.155.1"
|
|
137
138
|
known_limit: "R9 (human-directed stop exemption) is best-effort — Codex gives the assistant's last message directly but not the human's; a failed transcript read leaves the human side empty rather than skipping detection"
|
|
138
139
|
- harness: gemini-cli
|
|
139
140
|
event: AfterAgent
|
|
140
141
|
config_file: ".gemini/settings.json"
|
|
141
142
|
block_shape: '{"decision":"deny","reason":...}, exit 0 — the documented preferred path over exit code 2'
|
|
142
143
|
script: scripts/hooks/check-turn-completion-gemini.mjs
|
|
144
|
+
status: legacy
|
|
145
|
+
reason: "Google retired Gemini CLI for personal accounts on 2026-06-18 in favour of Antigravity CLI; enterprise accounts keep both. Adapter kept for them; never confirmed against a real Gemini CLI session"
|
|
146
|
+
- harness: antigravity-cli
|
|
147
|
+
status: not-yet-supported
|
|
148
|
+
reason: "Documented Stop contract differs: config .agents/hooks.json, payload has only transcriptPath (no final or human message), block is {\"decision\":\"continue\",\"reason\":...}. Adapter waits until that contract is observed against a real session (R3)"
|
|
143
149
|
- harness: cursor
|
|
144
150
|
status: evaluated-not-supported
|
|
145
151
|
reason: "Whether Cursor's stop hook can actually block a turn was unresolved as of writing; shipping an adapter against an unverified contract repeats the exact failure R3 exists to prevent"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> **Language**: English | [繁體中文](../locales/zh-TW/core/turn-completion-integrity.md)
|
|
4
4
|
|
|
5
|
-
**Version**: 1.4.
|
|
6
|
-
**Last Updated**: 2026-09-
|
|
5
|
+
**Version**: 1.4.1
|
|
6
|
+
**Last Updated**: 2026-09-28
|
|
7
7
|
**Applicability**: Any harness where an agent ends a turn and hands control back to a human
|
|
8
8
|
**Scope**: universal
|
|
9
9
|
**Industry Standards**: none claimed — derived from observed failures, see Evidence
|
|
@@ -149,13 +149,22 @@ prevent, one level up.
|
|
|
149
149
|
## Supported harnesses
|
|
150
150
|
|
|
151
151
|
The check is enforced only where a harness adapter exists and a hook is
|
|
152
|
-
actually wired into that harness's own config. As of v1.4.
|
|
152
|
+
actually wired into that harness's own config. As of v1.4.1:
|
|
153
153
|
|
|
154
154
|
| Harness | Event | Config file | Block contract |
|
|
155
155
|
|---|---|---|---|
|
|
156
156
|
| Claude Code | Stop | `.claude/settings.json` | stdout `{"decision":"block","reason":...}`, exit 0; silence allows |
|
|
157
157
|
| Codex | Stop | `.codex/hooks.json` | stdout `{"decision":"block","reason":...}`, exit 0 — plain text or empty stdout is documented as invalid for this event |
|
|
158
|
-
| Gemini CLI | AfterAgent | `.gemini/settings.json` | stdout `{"decision":"deny","reason":...}`, exit 0 — the documented preferred path over exit code 2 |
|
|
158
|
+
| Gemini CLI (legacy) | AfterAgent | `.gemini/settings.json` | stdout `{"decision":"deny","reason":...}`, exit 0 — the documented preferred path over exit code 2 |
|
|
159
|
+
|
|
160
|
+
Wired is not running on Codex. Codex skips a project hook until the project
|
|
161
|
+
is trusted **and** that exact hook definition has been trusted through `/hooks`
|
|
162
|
+
in an interactive Codex session; trust is recorded against the definition's
|
|
163
|
+
hash, so a changed definition needs trusting again. Under `codex exec` an
|
|
164
|
+
untrusted hook is skipped with no message at all (measured 2026-09-28,
|
|
165
|
+
codex-cli 0.155.1: the adapter was never invoked until the hook was trusted,
|
|
166
|
+
then blocked and allowed exactly as its tests say). `uds init --with-hooks`
|
|
167
|
+
prints this next to the install line.
|
|
159
168
|
|
|
160
169
|
Codex's R9 exemption is best-effort, not silent failure: Codex's Stop payload
|
|
161
170
|
gives the assistant's final message directly but not the human's, so reading
|
|
@@ -172,6 +181,18 @@ shape) still leaves the human side empty rather than throwing — detection
|
|
|
172
181
|
still runs on the assistant's message, only the R9 exemption for that one
|
|
173
182
|
turn may be missed.
|
|
174
183
|
|
|
184
|
+
Gemini CLI is legacy. Google retired it for personal accounts on
|
|
185
|
+
2026-06-18 in favour of Antigravity CLI (`agy`); enterprise accounts keep
|
|
186
|
+
access to both. The adapter stays for those users, but it has never been
|
|
187
|
+
confirmed against a real Gemini CLI session, and new adopters on Google's
|
|
188
|
+
tooling should expect Antigravity CLI, which is **not yet supported**. Its
|
|
189
|
+
documented Stop hook contract differs from every adapter above in the ways
|
|
190
|
+
that matter: the hook is configured in `.agents/hooks.json`, the payload
|
|
191
|
+
carries only a `transcriptPath` (no final message, no human message), and a
|
|
192
|
+
block is `{"decision":"continue","reason":...}`, not `block` or `deny`. An
|
|
193
|
+
adapter will be added once that contract has been observed against a real
|
|
194
|
+
session — the same reason Cursor below has none.
|
|
195
|
+
|
|
175
196
|
Cursor was evaluated and is not supported: whether its stop hook can actually
|
|
176
197
|
block a turn in the way this standard requires was unresolved as of this
|
|
177
198
|
writing, and shipping an adapter against an unverified contract would repeat
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* commitment to a next action that the turn then ended without taking.
|
|
7
7
|
*
|
|
8
8
|
* Contract (Claude Code Stop hook):
|
|
9
|
-
* stdin — JSON with session_id, transcript_path, stop_hook_active
|
|
9
|
+
* stdin — JSON with session_id, transcript_path, stop_hook_active, and
|
|
10
|
+
* (current Claude Code) last_assistant_message
|
|
10
11
|
* block — print {"decision":"block","reason":"..."} on stdout, exit 0
|
|
11
12
|
* allow — print nothing, exit 0
|
|
12
13
|
*
|
|
@@ -21,6 +22,17 @@
|
|
|
21
22
|
* is reading Claude Code's stdin/transcript shape and writing Claude Code's
|
|
22
23
|
* output shape.
|
|
23
24
|
*
|
|
25
|
+
* The agent's final message is taken from stdin's `last_assistant_message`
|
|
26
|
+
* when present, NOT from the transcript. Measured 2026-09-28 against Claude
|
|
27
|
+
* Code 2.1.283 in a live `claude -p` session: at the moment the Stop hook runs,
|
|
28
|
+
* the transcript does not yet contain the final assistant message — the
|
|
29
|
+
* adapter read "" and allowed 5 of 5 turns that should have blocked. (In a
|
|
30
|
+
* longer session it would have read the PREVIOUS turn's message instead.)
|
|
31
|
+
* Every self-test and unit test passed throughout, because they all hand the
|
|
32
|
+
* adapter a transcript that is already complete. The transcript is still read
|
|
33
|
+
* for the human's side (R9), which is written at the start of the turn, and
|
|
34
|
+
* as the fallback for Claude Code versions that do not send the field.
|
|
35
|
+
*
|
|
24
36
|
* Usage: node check-turn-completion.mjs (reads stdin)
|
|
25
37
|
* node check-turn-completion.mjs --self-test
|
|
26
38
|
* node check-turn-completion.mjs --languages
|
|
@@ -82,15 +94,19 @@ async function main() {
|
|
|
82
94
|
if (!data || typeof data !== 'object') return;
|
|
83
95
|
if (data.stop_hook_active === true) return;
|
|
84
96
|
|
|
85
|
-
const
|
|
86
|
-
if (!tp || !existsSync(tp)) return; // cannot tell is not the same as should block
|
|
97
|
+
const fromStdin = typeof data.last_assistant_message === 'string' ? data.last_assistant_message : null;
|
|
87
98
|
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
const tp = data.transcript_path;
|
|
100
|
+
let msgs = { assistant: '', user: '' };
|
|
101
|
+
if (tp && existsSync(tp)) {
|
|
102
|
+
try { msgs = lastMessages(tp); } catch { /* human side unknown; see below */ }
|
|
103
|
+
} else if (fromStdin === null) {
|
|
104
|
+
return; // no message from either source: cannot tell is not the same as should block
|
|
105
|
+
}
|
|
90
106
|
|
|
91
107
|
const verdict = await decide({
|
|
92
108
|
sessionId: data.session_id,
|
|
93
|
-
assistantText: msgs.assistant,
|
|
109
|
+
assistantText: fromStdin !== null ? fromStdin : msgs.assistant,
|
|
94
110
|
userText: msgs.user,
|
|
95
111
|
});
|
|
96
112
|
if (!verdict.fire) return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../CHANGELOG.md
|
|
3
|
-
source_version: 6.13.0
|
|
4
|
-
translation_version: 6.13.0
|
|
3
|
+
source_version: 6.13.0
|
|
4
|
+
translation_version: 6.13.0
|
|
5
5
|
last_synced: 2026-09-27
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
@@ -17,6 +17,23 @@ status: current
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [6.13.0] - 2026-09-28
|
|
21
|
+
|
|
22
|
+
> **正式版**:包含下方 6.13.0-beta.1 至 beta.5 的全部内容,beta.5 之后没有任何变更。重点:回合收尾关卡(agent 说了下一步却没做就不得结束回合)现在覆盖 **Claude Code 与 Codex**,两者都以从 npm 安装的版本在真实会话中验证过(Codex 要先用 `/hooks` 信任才会执行);Claude Code 关卡真的会拦(到 beta.4 为止每个回合都放行);Windows 上可用;`uds uninstall` 会移除它;`uds init` 让提交前检查真的执行;`developer-memory` 1.2.0。Gemini CLI 标为过时(Google 已对个人账号停用,改由 Antigravity CLI 取代,后者尚未支持)。
|
|
23
|
+
|
|
24
|
+
## [6.13.0-beta.5] - 2026-09-28
|
|
25
|
+
|
|
26
|
+
> **测试版** — 以 `npm install -g universal-dev-standards@beta` 安装。要测什么、已知限制、如何退回正式版:见 [docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。**装过 6.13.0-beta.1~beta.4 的请升级:那几版的 Claude Code 回合收尾关卡从未拦下过。**
|
|
27
|
+
|
|
28
|
+
### 修复
|
|
29
|
+
|
|
30
|
+
- **Claude Code 的回合收尾关卡在真实的 Claude Code 会话里从未拦下过任何回合——6.13.0-beta.1 到 beta.4 的每个采用者都接上了、也在执行,而它放行了每一个回合。** 2026-09-28 以 Claude Code 2.1.283 在真实 `claude -p` 会话实测:Stop hook 执行的那一刻,对话记录里还没有最后一条 AI 回复,因此只读对话记录的适配层看到空消息,应拦的 5 次全部放行;在较长的对话里,它判断的会是上一轮的回复。自我测试与单元测试从头到尾都通过,因为每一个都喂给适配层一份已经写完的对话记录。适配层现在改从 stdin 的 `last_assistant_message`(Claude Code 会发送)取得最后一条回复,对话记录只用来读人的那一侧(R9),以及在不发送这个字段的版本上作为备援。修复后已再次实测。新测试重现关卡当下实际看到的形状,在旧适配层上会失败。
|
|
31
|
+
- **Codex 的关卡装上了却从未执行,而且没有任何提示。** Codex 会跳过项目级的 hook,直到项目被信任、且这一支 hook 通过 `/hooks` 被信任为止——在 `codex exec` 下完全无声。`uds init --with-hooks` 现在会在 Codex 安装那一行旁边说明这件事,标准的〈支持的执行环境〉与 `docs/PRE-RELEASE.md` 也补上这个步骤。信任之后,Codex 适配层的拦截与放行与它的测试完全一致(2026-09-28 实测,codex-cli 0.155.1)。
|
|
32
|
+
|
|
33
|
+
### 变更
|
|
34
|
+
|
|
35
|
+
- **`turn-completion-integrity` 1.4.1:Gemini CLI 适配层标为过时,并明列 Antigravity CLI 尚未支持。** Google 于 2026-06-18 对个人账号停用 Gemini CLI,改由 Antigravity CLI(`agy`)取代;企业账号两者都还能用。适配层为他们保留,但从未在真实的 Gemini CLI 会话中验证过,因此不再与 Claude Code、Codex 适配层并列。Antigravity CLI 文档记载的 Stop hook 契约与所有已发布的适配层都不同(配置在 `.agents/hooks.json`;传入数据只有 `transcriptPath`,没有最后一条回复或人的消息;拦截是 `{"decision":"continue"}`),因此在真实会话中观察到这份契约之前不发布适配层——与 Cursor 不支持是同一条规则。行为不变:选了 Gemini CLI 时,`uds init --with-hooks` 仍会接上它的关卡。
|
|
36
|
+
|
|
20
37
|
## [6.13.0-beta.4] - 2026-09-28
|
|
21
38
|
|
|
22
39
|
> **测试版** — 以 `npm install -g universal-dev-standards@beta` 安装。要测什么、已知限制、如何退回正式版:见 [docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。注意:6.13.0-beta.3 从未上架 npm,其内容随本版发布。
|
|
@@ -15,7 +15,7 @@ status: current
|
|
|
15
15
|
|
|
16
16
|
> **语言**: [English](../../README.md) | [繁體中文](../zh-TW/README.md) | 简体中文
|
|
17
17
|
|
|
18
|
-
**版本**: 6.13.0
|
|
18
|
+
**版本**: 6.13.0 | **发布日期**: 2026-09-28 | **授权**: [双重授权](../../LICENSE) (CC BY 4.0 + MIT)
|
|
19
19
|
|
|
20
20
|
语言无关、框架无关的软件项目文档标准。通过 AI 原生工作流,确保不同技术栈之间的一致性、质量和可维护性。
|
|
21
21
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../../core/turn-completion-integrity.md
|
|
3
|
-
source_version: 1.4.
|
|
4
|
-
translation_version: 1.4.
|
|
5
|
-
last_synced: 2026-09-
|
|
6
|
-
source_hash:
|
|
3
|
+
source_version: 1.4.1
|
|
4
|
+
translation_version: 1.4.1
|
|
5
|
+
last_synced: 2026-09-28
|
|
6
|
+
source_hash: 0c04676006c0
|
|
7
7
|
status: current
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -11,8 +11,8 @@ status: current
|
|
|
11
11
|
|
|
12
12
|
> **语言**: [English](../../../core/turn-completion-integrity.md) | [繁體中文](../../zh-TW/core/turn-completion-integrity.md) | 简体中文
|
|
13
13
|
|
|
14
|
-
**版本**: 1.4.
|
|
15
|
-
**最后更新**: 2026-09-
|
|
14
|
+
**版本**: 1.4.1
|
|
15
|
+
**最后更新**: 2026-09-28
|
|
16
16
|
**适用范围**: 任何由 agent 结束回合、把控制权交还给人的执行环境
|
|
17
17
|
**Scope**: universal
|
|
18
18
|
**行业标准**: 不声称任何来源——由实际观察到的失败归纳,见「证据」
|
|
@@ -144,13 +144,19 @@ agent 写下「我接着做 X」,然后结束回合,而 X 没有做。
|
|
|
144
144
|
## 支持的执行环境
|
|
145
145
|
|
|
146
146
|
这个检查只在「适配层存在,且 hook 真的被接入该执行环境自己的配置」时才生效。
|
|
147
|
-
截至 v1.4.
|
|
147
|
+
截至 v1.4.1:
|
|
148
148
|
|
|
149
149
|
| 执行环境 | 事件 | 配置文件 | 拦截契约 |
|
|
150
150
|
|---|---|---|---|
|
|
151
151
|
| Claude Code | Stop | `.claude/settings.json` | stdout 输出 `{"decision":"block","reason":...}`,exit 0;沉默即放行 |
|
|
152
152
|
| Codex | Stop | `.codex/hooks.json` | stdout 输出 `{"decision":"block","reason":...}`,exit 0——官方文档写明这个事件纯文本或空输出无效 |
|
|
153
|
-
| Gemini CLI | AfterAgent | `.gemini/settings.json` | stdout 输出 `{"decision":"deny","reason":...}`,exit 0——官方文档标记为优先于 exit code 2 的做法 |
|
|
153
|
+
| Gemini CLI(过时) | AfterAgent | `.gemini/settings.json` | stdout 输出 `{"decision":"deny","reason":...}`,exit 0——官方文档标记为优先于 exit code 2 的做法 |
|
|
154
|
+
|
|
155
|
+
在 Codex 上,接上了不等于会执行。Codex 会跳过项目级的 hook,直到项目被信任、**而且**
|
|
156
|
+
这一支 hook 的定义在交互式 Codex 会话里通过 `/hooks` 被信任为止;信任记录绑定在定义的
|
|
157
|
+
哈希值上,定义一改就要重新信任。在 `codex exec` 下,未被信任的 hook 会被跳过,而且完全
|
|
158
|
+
没有任何消息(2026-09-28 实测,codex-cli 0.155.1:hook 被信任之前适配层一次都没被调用;
|
|
159
|
+
信任之后,拦截与放行都与它的测试完全一致)。`uds init --with-hooks` 会在安装那一行旁边打印这件事。
|
|
154
160
|
|
|
155
161
|
Codex 的 R9 豁免是尽力而为,不是静默失效:Codex 的 Stop payload 直接给出
|
|
156
162
|
agent 的最后一条消息,却不给出用户的;要拿到用户那一侧必须解析一份
|
|
@@ -165,6 +171,15 @@ agent 的最后一条消息,却不给出用户的;要拿到用户那一侧
|
|
|
165
171
|
用户那一侧变空、不会抛出异常——检测仍照样运行在 agent 消息上,只有那一轮
|
|
166
172
|
的 R9 豁免可能漏掉。
|
|
167
173
|
|
|
174
|
+
Gemini CLI 已过时。Google 于 2026-06-18 对个人账号停用 Gemini CLI,
|
|
175
|
+
改由 Antigravity CLI(`agy`)取代;企业账号两者都还能用。这个适配层为那些用户保留,
|
|
176
|
+
但它从未在真实的 Gemini CLI 会话中验证过;使用 Google 工具的新采用者应预期的是
|
|
177
|
+
Antigravity CLI,而它**尚未支持**。它文档记载的 Stop hook 契约,在关键之处与上表每一个
|
|
178
|
+
适配层都不同:hook 配置在 `.agents/hooks.json`、传入数据只有 `transcriptPath`
|
|
179
|
+
(没有最后一条回复、也没有人的消息)、拦截是 `{"decision":"continue","reason":...}`
|
|
180
|
+
而不是 `block` 或 `deny`。等这份契约在真实会话中观察到之后才会加入适配层——
|
|
181
|
+
与下方 Cursor 没有适配层是同一个理由。
|
|
182
|
+
|
|
168
183
|
Cursor 已评估但不支持:截至撰写本文时,Cursor 的 stop hook 能不能真的
|
|
169
184
|
拦下一个回合仍未确定,若对着一个没人验证过的契约交付一份适配层,
|
|
170
185
|
等于重演 R3 要防的那个失败——一个没人确认过真的在执法的执法机制。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../CHANGELOG.md
|
|
3
|
-
source_version: 6.13.0
|
|
4
|
-
translation_version: 6.13.0
|
|
3
|
+
source_version: 6.13.0
|
|
4
|
+
translation_version: 6.13.0
|
|
5
5
|
last_synced: 2026-09-27
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
@@ -17,6 +17,23 @@ status: current
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [6.13.0] - 2026-09-28
|
|
21
|
+
|
|
22
|
+
> **正式版**:包含下方 6.13.0-beta.1 至 beta.5 的全部內容,beta.5 之後沒有任何變更。重點:回合收尾關卡(agent 說了下一步卻沒做就不得結束回合)現在涵蓋 **Claude Code 與 Codex**,兩者都以從 npm 安裝的版本在真實工作階段驗證過(Codex 要先用 `/hooks` 信任才會執行);Claude Code 關卡真的會擋(到 beta.4 為止每個回合都放行);Windows 上可用;`uds uninstall` 會移除它;`uds init` 讓提交前檢查真的執行;`developer-memory` 1.2.0。Gemini CLI 標為過時(Google 已對個人帳號停用,改由 Antigravity CLI 取代,後者尚未支援)。
|
|
23
|
+
|
|
24
|
+
## [6.13.0-beta.5] - 2026-09-28
|
|
25
|
+
|
|
26
|
+
> **測試版** — 以 `npm install -g universal-dev-standards@beta` 安裝。要測什麼、已知限制、如何退回正式版:見 [docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。**裝過 6.13.0-beta.1~beta.4 的請升級:那幾版的 Claude Code 回合收尾關卡從未擋下過。**
|
|
27
|
+
|
|
28
|
+
### 修正
|
|
29
|
+
|
|
30
|
+
- **Claude Code 的回合收尾關卡在真實的 Claude Code 工作階段裡從未擋下過任何回合——6.13.0-beta.1 到 beta.4 的每個採用者都接上了、也在執行,而它放行了每一個回合。** 2026-09-28 以 Claude Code 2.1.283 在真實 `claude -p` 工作階段實測:Stop hook 執行的那一刻,逐字稿裡還沒有最後一則 AI 回覆,因此只讀逐字稿的適配層看到空訊息,應擋的 5 次全部放行;在較長的對話裡,它判斷的會是上一輪的回覆。自我測試與單元測試從頭到尾都通過,因為每一支都餵給適配層一份已經寫完的逐字稿。適配層現在改從 stdin 的 `last_assistant_message`(Claude Code 會送)取得最後一則回覆,逐字稿只用來讀人的那一側(R9),以及在不送這個欄位的版本上當備援。修正後已再次實測。新測試重現關卡當下實際看到的形狀,在舊適配層上會失敗。
|
|
31
|
+
- **Codex 的關卡裝上了卻從未執行,而且沒有任何提示。** Codex 會略過專案層級的 hook,直到專案被信任、且這一支 hook 透過 `/hooks` 被信任為止——在 `codex exec` 底下完全無聲。`uds init --with-hooks` 現在會在 Codex 安裝那一行旁邊說明這件事,標準的〈支援的執行環境〉與 `docs/PRE-RELEASE.md` 也補上這個步驟。信任之後,Codex 適配層的擋與放行與它的測試完全一致(2026-09-28 實測,codex-cli 0.155.1)。
|
|
32
|
+
|
|
33
|
+
### 變更
|
|
34
|
+
|
|
35
|
+
- **`turn-completion-integrity` 1.4.1:Gemini CLI 適配層標為過時,並明列 Antigravity CLI 尚未支援。** Google 於 2026-06-18 對個人帳號停用 Gemini CLI,改由 Antigravity CLI(`agy`)取代;企業帳號兩者都還能用。適配層為他們保留,但從未在真實的 Gemini CLI 工作階段中驗證過,因此不再與 Claude Code、Codex 適配層並列。Antigravity CLI 文件記載的 Stop hook 契約與所有已出貨的適配層都不同(設定在 `.agents/hooks.json`;傳入資料只有 `transcriptPath`,沒有最後一則回覆或人的訊息;攔截是 `{"decision":"continue"}`),因此在真實工作階段中觀察到這份契約之前不出貨適配層——與 Cursor 不支援是同一條規則。行為不變:選了 Gemini CLI 時,`uds init --with-hooks` 仍會接上它的關卡。
|
|
36
|
+
|
|
20
37
|
## [6.13.0-beta.4] - 2026-09-28
|
|
21
38
|
|
|
22
39
|
> **測試版** — 以 `npm install -g universal-dev-standards@beta` 安裝。要測什麼、已知限制、如何退回正式版:見 [docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。注意:6.13.0-beta.3 從未上架 npm,其內容隨本版出貨。
|
|
@@ -15,7 +15,7 @@ status: current
|
|
|
15
15
|
|
|
16
16
|
> **語言**: [English](../../README.md) | 繁體中文 | [简体中文](../zh-CN/README.md)
|
|
17
17
|
|
|
18
|
-
**版本**: 6.13.0
|
|
18
|
+
**版本**: 6.13.0 | **發布日期**: 2026-09-28 | **授權**: [雙重授權](../../LICENSE) (CC BY 4.0 + MIT)
|
|
19
19
|
|
|
20
20
|
語言無關、框架無關的軟體專案文件標準。透過 AI 原生工作流,確保不同技術堆疊之間的一致性、品質和可維護性。
|
|
21
21
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../../core/turn-completion-integrity.md
|
|
3
|
-
source_version: 1.4.
|
|
4
|
-
translation_version: 1.4.
|
|
5
|
-
last_synced: 2026-09-
|
|
6
|
-
source_hash:
|
|
3
|
+
source_version: 1.4.1
|
|
4
|
+
translation_version: 1.4.1
|
|
5
|
+
last_synced: 2026-09-28
|
|
6
|
+
source_hash: 0c04676006c0
|
|
7
7
|
status: current
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -11,8 +11,8 @@ status: current
|
|
|
11
11
|
|
|
12
12
|
> **Language**: [English](../../../core/turn-completion-integrity.md) | 繁體中文
|
|
13
13
|
|
|
14
|
-
**版本**: 1.4.
|
|
15
|
-
**最後更新**: 2026-09-
|
|
14
|
+
**版本**: 1.4.1
|
|
15
|
+
**最後更新**: 2026-09-28
|
|
16
16
|
**適用範圍**: 任何由 agent 結束回合、把控制權交還給人的執行環境
|
|
17
17
|
**Scope**: universal
|
|
18
18
|
**產業標準**: 不宣稱任何來源——由實際觀察到的失敗歸納,見「證據」
|
|
@@ -144,13 +144,19 @@ agent 寫下「我接著做 X」,然後結束回合,而 X 沒有做。
|
|
|
144
144
|
## 支援的執行環境
|
|
145
145
|
|
|
146
146
|
這個檢查只在「轉接層存在,且 hook 真的被接進該執行環境自己的設定」時才生效。
|
|
147
|
-
截至 v1.4.
|
|
147
|
+
截至 v1.4.1:
|
|
148
148
|
|
|
149
149
|
| 執行環境 | 事件 | 設定檔 | 阻擋契約 |
|
|
150
150
|
|---|---|---|---|
|
|
151
151
|
| Claude Code | Stop | `.claude/settings.json` | stdout 印 `{"decision":"block","reason":...}`,exit 0;沉默即放行 |
|
|
152
152
|
| Codex | Stop | `.codex/hooks.json` | stdout 印 `{"decision":"block","reason":...}`,exit 0——官方文件寫明這個事件純文字或空輸出無效 |
|
|
153
|
-
| Gemini CLI | AfterAgent | `.gemini/settings.json` | stdout 印 `{"decision":"deny","reason":...}`,exit 0——官方文件標記為優先於 exit code 2 的做法 |
|
|
153
|
+
| Gemini CLI(過時) | AfterAgent | `.gemini/settings.json` | stdout 印 `{"decision":"deny","reason":...}`,exit 0——官方文件標記為優先於 exit code 2 的做法 |
|
|
154
|
+
|
|
155
|
+
在 Codex 上,接上了不等於會執行。Codex 會略過專案層級的 hook,直到專案被信任、**而且**
|
|
156
|
+
這一支 hook 的定義在互動式 Codex 工作階段裡透過 `/hooks` 被信任為止;信任紀錄綁在定義的
|
|
157
|
+
雜湊值上,定義一改就要重新信任。在 `codex exec` 底下,未被信任的 hook 會被略過,而且完全
|
|
158
|
+
沒有任何訊息(2026-09-28 實測,codex-cli 0.155.1:hook 被信任之前適配層一次都沒被呼叫;
|
|
159
|
+
信任之後,擋與放行都與它的測試完全一致)。`uds init --with-hooks` 會在安裝那一行旁邊印出這件事。
|
|
154
160
|
|
|
155
161
|
Codex 的 R9 豁免是盡力而為,不是靜默失效:Codex 的 Stop payload 直接給
|
|
156
162
|
agent 的最後一則訊息,卻不給使用者的;要拿到使用者那一側必須解析一份
|
|
@@ -165,6 +171,15 @@ agent 的最後一則訊息,卻不給使用者的;要拿到使用者那一
|
|
|
165
171
|
使用者那一側變空、不會拋出例外——偵測仍照樣跑在 agent 訊息上,只有那一輪
|
|
166
172
|
的 R9 豁免可能漏掉。
|
|
167
173
|
|
|
174
|
+
Gemini CLI 已過時。Google 於 2026-06-18 對個人帳號停用 Gemini CLI,
|
|
175
|
+
改由 Antigravity CLI(`agy`)取代;企業帳號兩者都還能用。這個適配層為那些使用者保留,
|
|
176
|
+
但它從未在真實的 Gemini CLI 工作階段中驗證過;使用 Google 工具的新採用者該預期的是
|
|
177
|
+
Antigravity CLI,而它**尚未支援**。它文件記載的 Stop hook 契約,在關鍵之處與上表每一個
|
|
178
|
+
適配層都不同:hook 設定在 `.agents/hooks.json`、傳入資料只有 `transcriptPath`
|
|
179
|
+
(沒有最後一則回覆、也沒有人的訊息)、攔截是 `{"decision":"continue","reason":...}`
|
|
180
|
+
而不是 `block` 或 `deny`。等這份契約在真實工作階段中觀察到之後才會加入適配層——
|
|
181
|
+
與下方 Cursor 沒有適配層是同一個理由。
|
|
182
|
+
|
|
168
183
|
Cursor 已評估但不支援:截至撰寫本文時,Cursor 的 stop hook 能不能真的
|
|
169
184
|
擋下一個回合仍未確定,若對著一個沒人驗證過的契約出一份轉接層,
|
|
170
185
|
等於重演 R3 要防的那個失敗——一個沒人確認過真的在執法的執法機制。
|
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -293,6 +293,11 @@ export async function initCommand(options) {
|
|
|
293
293
|
const codexResult = installCodexHooks(projectPath);
|
|
294
294
|
if (codexResult.installed) {
|
|
295
295
|
console.log(chalk.green(' ✓ Codex Stop hook installed (turn-completion-integrity)'));
|
|
296
|
+
// Measured 2026-09-28 (codex-cli 0.155.1): Codex skips a project hook
|
|
297
|
+
// until the project is trusted AND that exact hook definition is
|
|
298
|
+
// trusted via /hooks — silently under `codex exec`. Installed is not
|
|
299
|
+
// running; say so here, where the adopter believes it now works.
|
|
300
|
+
console.log(chalk.yellow(' ⚠ Codex will not run it until you trust it: open Codex in this project, trust the project, then run /hooks and trust this hook. Until then it is skipped (silently under `codex exec`).'));
|
|
296
301
|
} else {
|
|
297
302
|
console.log(chalk.yellow(` ⚠ Codex hook not installed — ${codexResult.reason}`));
|
|
298
303
|
}
|
|
@@ -301,7 +306,7 @@ export async function initCommand(options) {
|
|
|
301
306
|
const { installGeminiHooks } = await import('../installers/hooks-installer.js');
|
|
302
307
|
const geminiResult = installGeminiHooks(projectPath);
|
|
303
308
|
if (geminiResult.installed) {
|
|
304
|
-
console.log(chalk.green(' ✓ Gemini CLI AfterAgent hook installed (turn-completion-integrity)'));
|
|
309
|
+
console.log(chalk.green(' ✓ Gemini CLI AfterAgent hook installed (turn-completion-integrity; Gemini CLI is legacy — see the standard)'));
|
|
305
310
|
} else {
|
|
306
311
|
console.log(chalk.yellow(` ⚠ Gemini CLI hook not installed — ${geminiResult.reason}`));
|
|
307
312
|
}
|
package/standards-registry.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"version": "6.13.0
|
|
3
|
+
"version": "6.13.0",
|
|
4
4
|
"lastUpdated": "2026-05-13",
|
|
5
5
|
"description": "Standards registry for universal-dev-standards with integrated skills and AI-optimized formats",
|
|
6
6
|
"formats": {
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"standards": {
|
|
59
59
|
"name": "universal-dev-standards",
|
|
60
60
|
"url": "https://github.com/AsiaOstrich/universal-dev-standards",
|
|
61
|
-
"version": "6.13.0
|
|
61
|
+
"version": "6.13.0"
|
|
62
62
|
},
|
|
63
63
|
"skills": {
|
|
64
64
|
"name": "universal-dev-standards",
|
|
65
65
|
"url": "https://github.com/AsiaOstrich/universal-dev-standards",
|
|
66
66
|
"localPath": "skills",
|
|
67
67
|
"rawUrl": "https://raw.githubusercontent.com/AsiaOstrich/universal-dev-standards/main/skills",
|
|
68
|
-
"version": "6.13.0
|
|
68
|
+
"version": "6.13.0",
|
|
69
69
|
"note": "Skills are now included in the main repository under skills/"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
@@ -2295,7 +2295,7 @@
|
|
|
2295
2295
|
"id": "license-compliance",
|
|
2296
2296
|
"name": "License Compliance Standards",
|
|
2297
2297
|
"nameZh": "授權合規標準",
|
|
2298
|
-
"version": "6.13.0
|
|
2298
|
+
"version": "6.13.0",
|
|
2299
2299
|
"source": {
|
|
2300
2300
|
"human": "core/license-compliance.md",
|
|
2301
2301
|
"ai": "ai/standards/license-compliance.ai.yaml"
|
|
@@ -2307,7 +2307,7 @@
|
|
|
2307
2307
|
"id": "verification-oracle",
|
|
2308
2308
|
"name": "Verification Oracle Standards",
|
|
2309
2309
|
"nameZh": "驗證 Oracle 標準",
|
|
2310
|
-
"version": "6.13.0
|
|
2310
|
+
"version": "6.13.0",
|
|
2311
2311
|
"source": {
|
|
2312
2312
|
"human": "core/verification-oracle.md",
|
|
2313
2313
|
"ai": "ai/standards/verification-oracle.ai.yaml"
|
|
@@ -2319,7 +2319,7 @@
|
|
|
2319
2319
|
"id": "model-provenance",
|
|
2320
2320
|
"name": "Model Provenance Policy Standards",
|
|
2321
2321
|
"nameZh": "模型來源政策標準",
|
|
2322
|
-
"version": "6.13.0
|
|
2322
|
+
"version": "6.13.0",
|
|
2323
2323
|
"source": {
|
|
2324
2324
|
"human": "core/model-provenance.md",
|
|
2325
2325
|
"ai": "ai/standards/model-provenance.ai.yaml"
|
|
@@ -2331,7 +2331,7 @@
|
|
|
2331
2331
|
"id": "resource-cost-boundary",
|
|
2332
2332
|
"name": "Resource / Cost Boundary Declaration Standards",
|
|
2333
2333
|
"nameZh": "資源/成本邊界宣告標準",
|
|
2334
|
-
"version": "6.13.0
|
|
2334
|
+
"version": "6.13.0",
|
|
2335
2335
|
"source": {
|
|
2336
2336
|
"human": "core/resource-cost-boundary.md",
|
|
2337
2337
|
"ai": "ai/standards/resource-cost-boundary.ai.yaml"
|