universal-dev-standards 6.13.1 → 6.14.0-beta.2
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/bin/uds.js +37 -0
- package/bundled/ai/standards/open-work-tracking.ai.yaml +71 -4
- package/bundled/ai/standards/turn-completion-integrity.ai.yaml +14 -7
- package/bundled/core/open-work-tracking.md +111 -8
- package/bundled/core/turn-completion-integrity.md +58 -11
- package/bundled/hooks/check-turn-completion-agy.mjs +147 -0
- package/bundled/hooks/turn-completion/locales/en.mjs +54 -5
- package/bundled/hooks/turn-completion/locales/zh-TW.mjs +37 -6
- package/bundled/locales/zh-CN/CHANGELOG.md +33 -3
- package/bundled/locales/zh-CN/README.md +2 -2
- package/bundled/locales/zh-CN/SECURITY.md +1 -0
- package/bundled/locales/zh-CN/core/turn-completion-integrity.md +46 -13
- package/bundled/locales/zh-CN/docs/CHEATSHEET.md +6 -1
- package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +33 -8
- package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +17 -7
- package/bundled/locales/zh-TW/CHANGELOG.md +33 -3
- package/bundled/locales/zh-TW/README.md +2 -2
- package/bundled/locales/zh-TW/SECURITY.md +1 -0
- package/bundled/locales/zh-TW/core/open-work-tracking.md +88 -9
- package/bundled/locales/zh-TW/core/turn-completion-integrity.md +46 -13
- package/bundled/locales/zh-TW/docs/CHEATSHEET.md +6 -1
- package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +33 -8
- package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +17 -7
- package/package.json +1 -1
- package/src/commands/init.js +17 -2
- package/src/commands/open-work.js +60 -0
- package/src/commands/uninstall.js +1 -1
- package/src/commands/update.js +91 -0
- package/src/i18n/messages.js +3 -0
- package/src/installers/hooks-installer.js +276 -11
- package/src/uninstallers/hook-uninstaller.js +107 -4
- package/src/utils/detector.js +46 -1
- package/src/utils/open-work-tracking.mjs +693 -0
- package/standards-registry.json +8 -8
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* UDS Hook: Turn Completion Integrity — Antigravity CLI (agy) adapter
|
|
4
|
+
*
|
|
5
|
+
* Runs when the agent is about to stop. Blocks when the agent's final message
|
|
6
|
+
* states a first-person commitment to a next action that the turn then ended
|
|
7
|
+
* without taking.
|
|
8
|
+
*
|
|
9
|
+
* Contract (Antigravity CLI Stop hook — https://antigravity.google/docs/hooks/,
|
|
10
|
+
* fetched 2026-09-29, and OBSERVED against a real session the same day: agy
|
|
11
|
+
* 1.2.12 on PC15, `agy -p`, evidence kept in dev-platform
|
|
12
|
+
* cross-project/ops/evidence/agy-stop-hook-2026-09-29/):
|
|
13
|
+
* config — <repo>/.agents/hooks.json (or ~/.gemini/config/hooks.json). The
|
|
14
|
+
* file maps a hook NAME to its events:
|
|
15
|
+
* {"<name>": {"Stop": [{"type":"command","command":"...","timeout":N}]}}
|
|
16
|
+
* There is no `hooks` wrapper key and no `hooks[]` nesting around the
|
|
17
|
+
* handler, unlike Claude Code / Codex. `timeout` is in seconds.
|
|
18
|
+
* stdin — JSON with artifactDirectoryPath, conversationId, error,
|
|
19
|
+
* executionNum (from 0), fullyIdle, modelName, terminationReason,
|
|
20
|
+
* transcriptPath, workspacePaths. 🔴 It carries NEITHER the final
|
|
21
|
+
* message NOR the human's message: both come from the transcript.
|
|
22
|
+
* transcript — JSONL, one record per line with source / type / content:
|
|
23
|
+
* the human's message = source USER_EXPLICIT, type USER_INPUT,
|
|
24
|
+
* content wrapped in <USER_REQUEST>…</USER_REQUEST>
|
|
25
|
+
* and followed by <ADDITIONAL_METADATA> etc.
|
|
26
|
+
* the model's reply = source MODEL, type PLANNER_RESPONSE
|
|
27
|
+
* a `continue` reason = source SYSTEM, type SYSTEM_MESSAGE
|
|
28
|
+
* output — {"decision":"continue","reason":"..."} restarts the loop (the
|
|
29
|
+
* reason reaches the model); anything else lets it stop. This
|
|
30
|
+
* adapter writes "{}" on every allow path so stdout is always
|
|
31
|
+
* valid JSON.
|
|
32
|
+
*
|
|
33
|
+
* 🔴 The human's last message is taken from USER_EXPLICIT/USER_INPUT ONLY.
|
|
34
|
+
* This hook's own `continue` reason is written back into the transcript as a
|
|
35
|
+
* SYSTEM_MESSAGE; reading "any non-MODEL record" as the human would take the
|
|
36
|
+
* hook's own text for the human's words (R11, same family as the Claude Code
|
|
37
|
+
* block-message echo). Filtering by `source` is the guard; the SELF_ECHO check
|
|
38
|
+
* below is a second, weaker one.
|
|
39
|
+
*
|
|
40
|
+
* 🔴 agy runs the hook with the working directory set to `.agents/`, not the
|
|
41
|
+
* project root (measured 2026-09-29, agy 1.2.12), and silently lets a hook that
|
|
42
|
+
* fails to start through — hence the installed command `node ../scripts/hooks/...`.
|
|
43
|
+
* Nothing here or in the engine reads process.cwd(): packs load relative to the
|
|
44
|
+
* module, state lives under ~/.uds (or UDS_TURN_COMPLETION_STATE_DIR), and the
|
|
45
|
+
* transcript path from stdin is absolute. Tests run the adapter from `.agents/`.
|
|
46
|
+
*
|
|
47
|
+
* At the moment the hook runs, the transcript ALREADY holds the model's final
|
|
48
|
+
* reply (observed, single turn, no tool calls). This is the opposite of Claude
|
|
49
|
+
* Code, where it does not (see check-turn-completion.mjs). Not verified: multi-
|
|
50
|
+
* turn, turns with tool calls, fullyIdle:false, a non-empty `error`, interactive
|
|
51
|
+
* mode. If the final reply is not yet in the transcript in one of those cases,
|
|
52
|
+
* this adapter would judge the previous reply — see the standard's Supported
|
|
53
|
+
* harnesses section.
|
|
54
|
+
*
|
|
55
|
+
* No `executionNum > 0` loop guard is used (unlike stop_hook_active on the
|
|
56
|
+
* other adapters): whether executionNum resets between turns in a long
|
|
57
|
+
* interactive session is unverified, and a guard that never resets is a delayed
|
|
58
|
+
* off switch. The engine's cooldown and rolling window (R6) bound the loop.
|
|
59
|
+
*
|
|
60
|
+
* Judgement (packs, cooldown, rolling window, self-echo) lives in
|
|
61
|
+
* turn-completion/engine.mjs and is shared with every other adapter.
|
|
62
|
+
*
|
|
63
|
+
* Usage: node check-turn-completion-agy.mjs (reads stdin)
|
|
64
|
+
* node check-turn-completion-agy.mjs --self-test
|
|
65
|
+
* node check-turn-completion-agy.mjs --languages
|
|
66
|
+
*
|
|
67
|
+
* @see core/turn-completion-integrity.md
|
|
68
|
+
*/
|
|
69
|
+
import { readFileSync } from 'node:fs';
|
|
70
|
+
import { decide, isSelfEcho, runSelfTest, printLanguages } from './turn-completion/engine.mjs';
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The human's words inside a USER_INPUT record: the text between
|
|
74
|
+
* <USER_REQUEST> and </USER_REQUEST>. Everything after the closing tag
|
|
75
|
+
* (<ADDITIONAL_METADATA>, <USER_SETTINGS_CHANGE>, ...) is system-added and is
|
|
76
|
+
* dropped. A record with no tag is taken whole (defensive: a different agy
|
|
77
|
+
* version may not wrap it).
|
|
78
|
+
*/
|
|
79
|
+
export function unwrapUserRequest(content) {
|
|
80
|
+
if (typeof content !== 'string') return '';
|
|
81
|
+
const m = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
82
|
+
if (m) return m[1].trim();
|
|
83
|
+
const open = content.indexOf('<USER_REQUEST>');
|
|
84
|
+
if (open !== -1) {
|
|
85
|
+
// opening tag without a close: take what follows, up to the next system block
|
|
86
|
+
const rest = content.slice(open + '<USER_REQUEST>'.length);
|
|
87
|
+
const next = rest.search(/<(ADDITIONAL_METADATA|USER_SETTINGS_CHANGE|SYSTEM_MESSAGE)>/);
|
|
88
|
+
return (next === -1 ? rest : rest.slice(0, next)).trim();
|
|
89
|
+
}
|
|
90
|
+
return content.trim();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Last model reply and last human message in an agy transcript_full.jsonl.
|
|
95
|
+
* Unparseable lines are skipped; a read failure throws to the caller.
|
|
96
|
+
*/
|
|
97
|
+
export function lastMessages(transcriptPath) {
|
|
98
|
+
let assistant = '';
|
|
99
|
+
let user = '';
|
|
100
|
+
for (const line of readFileSync(transcriptPath, 'utf8').split('\n')) {
|
|
101
|
+
if (!line.trim()) continue;
|
|
102
|
+
let ev;
|
|
103
|
+
try { ev = JSON.parse(line); } catch { continue; }
|
|
104
|
+
if (!ev || typeof ev.content !== 'string') continue;
|
|
105
|
+
if (ev.source === 'MODEL' && ev.type === 'PLANNER_RESPONSE') {
|
|
106
|
+
if (ev.content.trim()) assistant = ev.content;
|
|
107
|
+
} else if (ev.source === 'USER_EXPLICIT' && ev.type === 'USER_INPUT') {
|
|
108
|
+
const text = unwrapUserRequest(ev.content);
|
|
109
|
+
if (text && !isSelfEcho(text)) user = text;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { assistant, user };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function main() {
|
|
116
|
+
let out = {};
|
|
117
|
+
try {
|
|
118
|
+
const raw = readFileSync(0, 'utf8');
|
|
119
|
+
const data = JSON.parse(raw);
|
|
120
|
+
if (data && typeof data === 'object' && typeof data.transcriptPath === 'string' && data.transcriptPath) {
|
|
121
|
+
const { assistant, user } = lastMessages(data.transcriptPath);
|
|
122
|
+
const verdict = await decide({
|
|
123
|
+
sessionId: data.conversationId,
|
|
124
|
+
assistantText: assistant,
|
|
125
|
+
userText: user,
|
|
126
|
+
});
|
|
127
|
+
if (verdict.fire) out = { decision: 'continue', reason: verdict.reason };
|
|
128
|
+
}
|
|
129
|
+
} catch {
|
|
130
|
+
/* R5: fail open — stdout stays valid JSON, the agent stops */
|
|
131
|
+
}
|
|
132
|
+
process.stdout.write(JSON.stringify(out));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const arg = process.argv[2];
|
|
136
|
+
if (arg === '--self-test') {
|
|
137
|
+
process.exit((await runSelfTest('turn-completion-agy')) ? 0 : 1);
|
|
138
|
+
} else if (arg === '--languages') {
|
|
139
|
+
await printLanguages();
|
|
140
|
+
} else {
|
|
141
|
+
try {
|
|
142
|
+
await main();
|
|
143
|
+
} catch {
|
|
144
|
+
// R5, belt and braces — see check-turn-completion-codex.mjs.
|
|
145
|
+
process.stdout.write('{}');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -50,11 +50,34 @@ const ASKING =
|
|
|
50
50
|
// request for information, so ASKING above never caught it (measured: the
|
|
51
51
|
// zh-TW mirror of this shape fired as an unkept commitment). Grammar-based, not
|
|
52
52
|
// a verb list, to match this pack's own design note above: "once/after/as soon
|
|
53
|
-
// as you", up to
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
// the
|
|
57
|
-
|
|
53
|
+
// as you", then everything up to the CLAUSE BOUNDARY, a comma, then "I".
|
|
54
|
+
//
|
|
55
|
+
// 🔴 The clause used to be capped at 20 characters, chosen by feel. Measured
|
|
56
|
+
// 2026-09-29 on the published 6.14.0-beta.1: "Once you choose, I will apply it."
|
|
57
|
+
// passed and "Once you choose option A or B, I will apply it." (21 characters)
|
|
58
|
+
// blocked — the cap, not the grammar, decided. A human's precondition is often a
|
|
59
|
+
// long clause ("Once you've reviewed the three options above and picked one,
|
|
60
|
+
// …"), so no count is the right count. The clause ends where the class stops:
|
|
61
|
+
// a comma, sentence punctuation, or a line break. A precondition cannot be
|
|
62
|
+
// longer than the sentence it sits in, and it cannot cross a sentence.
|
|
63
|
+
//
|
|
64
|
+
// What the boundary keeps out, and why the comma stays required: "I will apply
|
|
65
|
+
// it once the build finishes." is not conditional on the human (no "you"), and
|
|
66
|
+
// "After you merged it I will …" (no comma) still fires — see the corpus.
|
|
67
|
+
//
|
|
68
|
+
// A widened clause must not swallow a commitment of mine, so the clause may not
|
|
69
|
+
// contain "I will / I am going to / I am about to". Without that,
|
|
70
|
+
// "After you merged it I will follow up, I will …" — the no-comma shape above,
|
|
71
|
+
// then a comma and a second "I" — would match, where the 20-character cap used
|
|
72
|
+
// to stop it. The subject of the precondition is the human's; a clause that
|
|
73
|
+
// makes a promise of its own is not one. (Contractions are already expanded by
|
|
74
|
+
// normalize() before this runs.)
|
|
75
|
+
const CONDITIONAL_ON_YOU = new RegExp(
|
|
76
|
+
'\\b(once|after|as soon as) you\\b' +
|
|
77
|
+
'(?:(?!\\bI\\s+(?:will|am going to|am about to|going to|about to)\\b)[^,.;:!?\\n])*' +
|
|
78
|
+
',\\s*I\\b',
|
|
79
|
+
'i'
|
|
80
|
+
);
|
|
58
81
|
|
|
59
82
|
/**
|
|
60
83
|
* Expand contractions so the patterns below never have to fight an apostrophe.
|
|
@@ -171,6 +194,32 @@ export const corpus = [
|
|
|
171
194
|
'After you confirm the plan, I will kick off the deploy.'],
|
|
172
195
|
[false, 'conditional: once you decide, I will',
|
|
173
196
|
'Once you decide, I will draft the ADR and file the tickets.'],
|
|
197
|
+
// 🔴 Measured 2026-09-29 on 6.14.0-beta.1 (published): the SAME sentence
|
|
198
|
+
// blocked or passed depending on how many characters sat between "you" and the
|
|
199
|
+
// comma — the 20-character cap, not the grammar. Each of these is one of the
|
|
200
|
+
// sentences that was measured, and the last three are the long clauses real
|
|
201
|
+
// agents write.
|
|
202
|
+
[false, 'conditional: once you choose (short, always passed)',
|
|
203
|
+
'Once you choose, I will apply it.'],
|
|
204
|
+
[false, 'conditional: once you choose A (short, always passed)',
|
|
205
|
+
'Once you choose A, I will apply it.'],
|
|
206
|
+
[false, 'conditional: as soon as you choose A or B',
|
|
207
|
+
'As soon as you choose A or B, I will apply it.'],
|
|
208
|
+
[false, 'conditional: after you choose option A or B (was blocked: 21 chars)',
|
|
209
|
+
'After you choose option A or B, I will apply it.'],
|
|
210
|
+
[false, 'conditional: once you choose option A or B (was blocked: 21 chars)',
|
|
211
|
+
'Once you choose option A or B, I will apply it.'],
|
|
212
|
+
[false, 'conditional: a long precondition clause',
|
|
213
|
+
"Once you've reviewed the three options above and picked one, I will apply it."],
|
|
214
|
+
[false, 'conditional: a long precondition clause, no contraction',
|
|
215
|
+
'After you have read the summary and decided which of the two migrations to keep, I will start the rollout.'],
|
|
216
|
+
// The widening must not turn the clause into a place to hide a commitment.
|
|
217
|
+
[true, 'not conditional on the human: the condition is a build, not you',
|
|
218
|
+
'I will apply it once the build finishes.'],
|
|
219
|
+
[true, 'not conditional on the human: "you" appears only after the commitment',
|
|
220
|
+
'I will apply the fix now, and you can review it later.'],
|
|
221
|
+
[true, 'a promise of my own inside the clause is not the human\'s precondition',
|
|
222
|
+
'After you merged it I will follow up, I will push the tag.'],
|
|
174
223
|
[true, 'subject is not you, still commits',
|
|
175
224
|
"After I fix this, I'll push it up."],
|
|
176
225
|
// Known limit, not fixed here: no comma between the precondition and "I"
|
|
@@ -47,12 +47,26 @@ const ASKING = new RegExp(
|
|
|
47
47
|
'|(跟我說|告訴我|回報我|讓我知道)(一聲)?[,,]\\s*我' +
|
|
48
48
|
// 「你選定後,我會…」— the precondition is the human's decision, not a request
|
|
49
49
|
// for information or a report-back, so neither branch above caught it. Measured:
|
|
50
|
-
// fired as an unkept commitment.
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
'
|
|
50
|
+
// fired as an unkept commitment. Grammar, not a length: literal 你 as the SUBJECT
|
|
51
|
+
// of the clause, then everything up to the clause boundary that is not another
|
|
52
|
+
// 我/你, then 後 (or 之後), then a comma and 我.
|
|
53
|
+
//
|
|
54
|
+
// 🔴 The clause used to be capped at 1–6 characters "so it stays a short
|
|
55
|
+
// decision verb". That is the same mistake the en pack made with 20: a human's
|
|
56
|
+
// precondition is often a whole clause (「你看完上面三個選項並選好一個之後,我會…」),
|
|
57
|
+
// and a count decided it instead of the grammar. Measured 2026-09-29 (en side,
|
|
58
|
+
// 6.14.0-beta.1); this side had the identical cap and the identical miss.
|
|
59
|
+
// The clause ends at 逗號/句號/驚嘆/問號/分號/冒號/換行, and may not contain 我
|
|
60
|
+
// (a precondition that carries my own act is not the human's).
|
|
61
|
+
//
|
|
62
|
+
// What replaces the count as the thing keeping real commitments out:
|
|
63
|
+
// - 你 must OPEN the clause (line/clause start, or after 等/待/當/若/一旦/
|
|
64
|
+
// 如果/只要), and must not be 你的. 「我看了你的設定檔並判斷需要重構之後,
|
|
65
|
+
// 我會接著改」 has 你 in the middle as a possessive inside MY sentence; with
|
|
66
|
+
// the cap gone it would have been exempted, and it is my commitment.
|
|
67
|
+
// - no 後 right after 你…: 「你選定的那份我會接著處理」 falls through.
|
|
68
|
+
// - no 你 before it: 「改好後我接著合併」, 「他確認後,我會…」 fall through.
|
|
69
|
+
'|(?:^|[,,。!?;;::\\n]|等到|等|待|當|若|一旦|如果|只要)\\s*你(?!的)[^,,。!?;;::\\n我你]+(之)?後[,,]\\s*我)'
|
|
56
70
|
);
|
|
57
71
|
|
|
58
72
|
// First person + future marker + action verb, within one sentence.
|
|
@@ -185,6 +199,23 @@ export const corpus = [
|
|
|
185
199
|
'你選好後,我會接著跑一次測試。'],
|
|
186
200
|
[false, '條件式承諾:你點頭後',
|
|
187
201
|
'你點頭後,我會接著把這份規格送出。'],
|
|
202
|
+
// 🔴 2026-09-29 實測(6.14.0-beta.1):en 側同一句話因為「你」到逗號之間差一個字而擋或放,
|
|
203
|
+
// 是字數上限決定的,不是語法。本側原本的 1–6 字上限是同一個缺陷。下面三句是真實會出現的長前提子句。
|
|
204
|
+
[false, '條件式承諾:你選好方案 A 或 B 後(原本被擋:超過 6 字)',
|
|
205
|
+
'你選好方案 A 或 B 後,我會接著套用。'],
|
|
206
|
+
[false, '條件式承諾:長前提子句',
|
|
207
|
+
'你看完上面三個選項並選好一個之後,我會接著套用。'],
|
|
208
|
+
[false, '條件式承諾:長前提子句,含頓號',
|
|
209
|
+
'你把上面三個選項都看過、挑好一個後,我會接著套用。'],
|
|
210
|
+
[false, '條件式承諾:等你……後',
|
|
211
|
+
'等你把上面三個選項看完並選好後,我會接著套用。'],
|
|
212
|
+
// 放寬之後,子句不能變成藏承諾的地方。
|
|
213
|
+
[true, '「你的」是所有格,句子的主詞是我,仍必須擋',
|
|
214
|
+
'我看了你的設定檔並判斷需要重構之後,我會接著改。'],
|
|
215
|
+
[true, '「你」在受詞位置(我把你貼的…整理完),仍必須擋',
|
|
216
|
+
'我把你貼的那一段整理完之後,我會接著改。'],
|
|
217
|
+
[true, '前提不是你,是建置——沒有在等使用者,仍必須擋',
|
|
218
|
+
'建置跑完之後,我會接著套用修正。'],
|
|
188
219
|
[true, '主詞不是你,仍必須擋——「後」在,但前面不是你',
|
|
189
220
|
'改好後我接著合併。'],
|
|
190
221
|
[true, '主詞不是你,仍必須擋——第三人稱的「後」',
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../CHANGELOG.md
|
|
3
|
-
source_version: 6.
|
|
4
|
-
translation_version: 6.
|
|
5
|
-
last_synced: 2026-09-
|
|
3
|
+
source_version: 6.14.0-beta.2
|
|
4
|
+
translation_version: 6.14.0-beta.2
|
|
5
|
+
last_synced: 2026-09-30
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -17,6 +17,36 @@ status: current
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [6.14.0-beta.2] - 2026-09-30
|
|
21
|
+
|
|
22
|
+
> **测试版**——以 `npm install -g universal-dev-standards@beta` 安装。要测什么、如何退回正式版:[docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。
|
|
23
|
+
>
|
|
24
|
+
> **修正 6.14.0-beta.1 的已知限制:**既有项目现在可以用 `uds update --with-hooks` 补装 Antigravity CLI 关卡(以及缺少的 Claude Code / Codex / Gemini CLI 关卡)。
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **`uds open-work next-action | revision | separation | self-test` —— `open-work-tracking` 1.1.0 的参考检查(OWT-017/018/019)现在随 npm 安装包出货。** 6.14.0-beta.1 的这些检查只在 repo 的 `scripts/` 里,而 npm 安装包不含该目录,采用者不 clone UDS 就跑不了。规则现在只住在一个地方,`cli/src/utils/open-work-tracking.mjs`(在安装包内);`uds open-work` 与旧的 `node scripts/check-open-work-tracking.mjs`(现在是一个不含规则、只重新导出该模块的薄壳)跑的是同一份,并有测试要求两者输出完全相同。检查本身没有任何改变:退出码相同(0 没有违反、1 有违反、2 判定不了——2 不是通过),检查器仍先跑自己的自测臂,每次运行仍声明覆盖率未知(OWT-011)、词汇未校准(OWT-016)。它仍是作为证据提供的参考判定程序,不是闸门。**每次测试都观察到会红:**新测试复制 CLI,让命令吞掉退出码(永远 0)或让共用规则永远通过,并要求违反的样本对副本变绿;并断言 `npm pack --dry-run` 的清单包含该模块。标准的“什么在执行本标准”一节改为指向该命令,而不是只在 repo 里的路径。
|
|
29
|
+
|
|
30
|
+
- **`uds update --with-hooks`——为已初始化的项目补装强制执行 hooks,并放宽 Antigravity 的检测规则。** Hooks 过去只有 `uds init --with-hooks` 会接线,而 `uds init` 不能跑第二次,所以既有采用者永远拿不到 UDS 在他们初始化之后才开始支持的工具的 hook(这是把 6.14.0-beta.1 安装包装进全新项目时发现的,已记为那一版的已知限制)。`uds update --with-hooks` 会重新检测工具(manifest 里的工具,加上项目文件现在看得出来的)并补装缺少的 hooks;`--ai-tool <列表>`(`claude-code`、`codex`、`gemini-cli`、`antigravity`)可改为直接指定,找不到任何工具时它会说明如何指定并以 1 退出,而不是猜。已经装好的 hook 不会被重写(重跑一次不会有任何变化),采用者自己的 hooks 绝不会被移除或重排(Claude/Codex/Gemini 是合并进去;agy 的 `.agents/hooks.json` 只写在 UDS 自己的 `uds-turn-completion-integrity` 键下面,不是合法 JSON 的文件原样保留),采用者改过的 hook 脚本会被保留、除非加 `--force`,`--plan` 则什么都不写。它与 `--claude-target`、`--sync-refs` 一样是独立模式;在已初始化的项目执行 `uds init --with-hooks`,现在会指向它,而不是默默什么都没做。**Antigravity 检测:**原本要求 `.agents/AGENTS.md`,而一个项目可以长期使用 agy 却从不创建这个文件。现在也接受 `.agents/rules/`、`.agents/workflows/`、`.agents/plugins/` 与 `.agents/hooks.json`——这些是 agy 自己的可执行文件带着、且 antigravity.google 有文档记载的名称——并且刻意**不**把 `.agents/skills/` 算进去,因为 Codex 也读它(根目录 `AGENTS.md` 加 `.agents/skills/` 的 repo 仍是 Codex;有测试)。检测只看项目目录:agy 记录已打开项目的 `~/.gemini/projects.json` 有被考虑,但因为它是机器本地的而不采用。`.agents/hooks.json` 是标记,但它同时也是 UDS 自己写的文件,所以安装之后它证明的是“装过”,不是“采用者在用 agy”。**每次测试都观察到会红:**测试把真的 CLI 当子进程对一个已初始化的项目跑,并要求把补装拿掉的 CLI 副本——删掉该分支、一个报告成功却什么都没写的安装器、检测退回只看 `.agents/AGENTS.md`——对真 CLI 会通过的同一组断言失败。agy 关卡仍然只验证过 `agy -p` 模式下没有用工具的单一回合。
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **`turn-completion-integrity` 在用户的前提子句超过固定字数时,会把“正在等用户”的一轮拦下——自 6.13 起就存在。** 条件式承诺(“你选好后,我会套用”)的豁免,在英文语言包是 `you` 到逗号之间最多 20 个字符,在 zh-TW 语言包是 `你` 到 `後` 之间 1–6 个字;两个数字都是凭感觉定的。以已发布的 6.14.0-beta.1、真实的 Claude Code Stop hook 输入实测:“Once you choose A, I will apply it.”放行,“Once you choose option A or B, I will apply it.”(21 个字符)被拦,“After you choose option A or B, I will apply it.”同样被拦——决定结果的是子句长度,不是 `once`/`after`。此 hook 只看一轮的**最后**一条消息,所以采用者看到的是:代理明明已经正确地停下来问人,却被逼着继续说话。修正:豁免改为延伸到子句边界(逗号、句末标点或换行),不再是字数,因此“Once you've reviewed the three options above and picked one, I will apply it.”与“你看完上面三個選項並選好一個之後,我會接著套用。”都放行。放宽上限就是让真承诺漏过的方向,所以改用两道规则取代字数:英文的子句内不得含有我自己的承诺(“After you merged it I will follow up, I will push the tag.”仍被拦);zh-TW 的 `你` 必须是子句的开头、且不能是“你的”(“我看了你的設定檔並判斷需要重構之後,我會接著改。”仍被拦——那里的 `你` 是我自己那句话里的所有格)。“I will apply it once the build finishes.”不是在等用户,仍被拦。**每次测试都观察到会红:**新测试复制 hook 目录、把两个旧上限各自放回去,要求同样那几句话对副本重新被拦(且 `--self-test` 失败)。**已知限制,没有改变:**豁免以段落为单位,含有一个这种条件子句的段落,会连带豁免旁边不相干的无条件承诺(原本就如此);没有逗号的条件句(“After you merged it I will follow up”)仍会被拦。
|
|
35
|
+
|
|
36
|
+
- **运行 `scripts/pre-release-check.sh`——以及在这个 repo 里 `git commit`——会把 UDS 技能写进执行者真实的家目录。** 2026-09-29,维护者在自己的机器上跑发版前检查,54 个技能文件夹与一个 `.manifest.json` 被写进真实的 `~/.claude/skills/`。用户层技能会遮蔽项目层技能,于是一个使用繁中技能的项目静默地跑起了英文测试版。每一步都是绿的:做这件事的那些步骤是在 `mkdtemp` 目录里跑 CLI,而那隔离的是**项目**,不是**用户**——`uds init -y` 与 `uds update` 不论在哪里跑,都会写用户层文件(`~/.claude/skills`、`~/.uds`)。用一次性 `HOME` 重现并实测,不是推测:`scripts/check-upgrade-fidelity.sh` 写入 115 个文件(它的 `uds update` 与上一版的 `npx … init` 都继承了真实 `HOME`);一开始被怀疑的 `check-adopter-instruction-files.ts` 什么也没写。另外两处写入者是逐文件二分单元测试找到的:`tests/commands/update-language-fidelity.test.js` 与 `update-agents-md-generator-fidelity.test.js` 调用真的 `updateCommand`(115 个文件进 `~/.claude/skills`),`tests/commands/check.test.js` 写了 `~/.uds/update-check.json`——而 pre-commit hook 会跑单元测试,所以**这个 repo 的每一次 commit 都会这样**;修正者自己在修正落地前的下一次 commit 就又对真实家目录做了一次。修正分三层:每一个会跑 CLI 的脚本现在都在一次性 `HOME` 下跑,且统一出自 `scripts/lib/isolated-home.{mjs,sh}`(`HOME`、`USERPROFILE`、`XDG_*`、`APPDATA`、`CODEX_HOME`;变量清单只有一份,bash 端执行 mjs 来读它),涵盖 `pre-release-check.sh` 的自我采用步骤、`check-upgrade-fidelity.sh`、`check-prompt-footprint.mjs`、`check-adopter-instruction-files.ts`、`check-skills-install-paths.ts`、`generate-usage-docs.mjs`、`cli/scripts/check-command-existence.mjs`、`cli/scripts/test-upgrade-path.mjs` 与 `cli/scripts/test-refactoring.sh`;测试套件在 `cli/tests/setup.js` 为每个测试文件换掉 `HOME`;`pre-release-check.sh` 开始前先对 `HOME` 底下 UDS 会写的位置拍快照,结束时若有任何新增或修改就在摘要失败(`scripts/check-home-untouched.mjs`)。被监看的位置不是手列的:从安装器的路径表与 `cli/src` 里以 `homedir()` 为根的路径遍历得出,并打印数量,所以缩成空集合的守卫不可能通过。**每次测试都观察到会红,且是端到端:**不隔离地对一个代表真实家目录的目录跑 CLI,守卫 exit 1 并点名 `~/.claude/skills`;有隔离则 exit 0;一个测试遍历每一个会 spawn CLI 的脚本,某个调用点的隔离被拿掉就红;一个探针测试在没有 `tests/setup.js` 时会失败。**如果你在这个修正之前跑过 `pre-release-check.sh`,或在这个 repo 里 commit 过,**请检查 `~/.claude/skills/`:若有 `installedDate` 是当天的 `.manifest.json` 与旁边的 UDS 技能文件夹,而那不是你自己装的,就移除它们(用户层技能会遮蔽项目层)。**刻意不监看:**`~/.claude/skills/synced/`——Claude Code 自己在运行时会把账号的 claude.ai 技能同步进去(在真实家目录上的第一次完整运行就因它失败,写入者正是运行检查的那个 Claude Code 会话);它是守卫排除清单里唯一一项、附有理由,每次比对都会打印,且排除被拿掉或放宽成整个 `~/.claude/skills` 时测试会失败。**未涵盖:**没有任何安装器点名的路径上的写入;以及端到端(`tests/e2e`)测试——已逐文件二分过,没有写入。
|
|
37
|
+
|
|
38
|
+
## [6.14.0-beta.1] - 2026-09-29
|
|
39
|
+
|
|
40
|
+
> **测试版**——以 `npm install -g universal-dev-standards@beta` 安装。要测什么、如何退回正式版:[docs/PRE-RELEASE.md](../../docs/PRE-RELEASE.md)。
|
|
41
|
+
>
|
|
42
|
+
> **已知限制(2026-09-29 把安装包装进全新项目实测发现):** Antigravity CLI 的关卡**只有**在“**全新**项目、且已经有 `.agents/AGENTS.md`”时,由 `uds init --with-hooks` 装上(init 靠这个文件判断项目在用 Antigravity)。既有项目执行 `uds update` **不会**补装,而 `uds init` 不能对同一个项目跑第二次。因此这个测试版里,既有项目拿不到 agy 关卡;预计下一版修正。
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **`open-work-tracking` 1.1.0:在 OWT-016 之后新增三条要求——意图与进度分开存放、意图被修改要留痕、下一步要点名对象。** OWT-017(warning):承载一件工作之目标、验收条件或限制的载体,不同时承载它的进度或下一步,以遍历各载体的结构判定、绝不看文件名,所以更新进度不必碰目标。OWT-018(error):对该意图的每次修改都留下改了什么、谁核可、为什么的记录;没有核可者的修改在 OWT-007 交回点被列出、不得静默,且列出永不阻断(OWT-008)。OWT-019(warning):「下一步」字段点名文件路径、测试名称、命令或需求编号之一,只有动词不算;这个检查判断有没有点名对象,不判断句子写得好不好。严重度的理由写在标准里。标准也记下对促成本次修改之提示词刻意**不**采纳的部分——那是用户转贴、作者不明、没有实现的文字,只借了设计形状:以手写状态文件当状态真相(会过期,而戳比过期内容新是隐形的)、固定的开工仪式(由各代理工具设置,且会变成没有任何 artefact 检查判定得了的要求)。新增 `scripts/check-open-work-tracking.mjs`,是这三条要求的参考判定程序,作为 OWT-015 证据而非闸门提供(UDS 仍不设闸门,也没有接进 `pre-release-check.sh`):`next-action` 报告「点名且已找到/点名但未找到/未点名」,`revision` 比对两个版本(或一个文件对 `--base <git rev>`)的验收/目标/限制区段并要求一条新增且完整的记录、把没有核可者的修改列给交回点,`separation` 检查没有任何载体同时装着两者。它判定前先跑自己的自测臂、判定不了时 exit 2(不是 0),并写明自己判定不了的事——记录是否诚实描述了修改、被点名的对象是否正确。**每次跑测试都被观察到会红:**测试套件复制该脚本、改它的源码文字,要求对真脚本通过的断言对 17 个突变版失败(每条要求的永远通过与永远失败、每个辨认分支逐一关掉、旧记录被当成新记录、不完整的记录被接受)。**未校准(OWT-016):标题词汇、命令清单、扩展名清单与编号样式都是初始判断,不是量测**——例如 `已知限制` 会被读成限制区段;采用者应传入自己的编号样式。在真实历史上重放,它报告 XSPEC-436 的验收条件有变动而没有修订记录,以及 dev-platform 工作记录里一条未点名的下一步。
|
|
47
|
+
|
|
48
|
+
- **`turn-completion-integrity` 1.5.0:Antigravity CLI(`agy`)现已支持,依据是真实会话观察到的契约。** 这份标准过去写 agy「尚未支持」,因为它的 Stop hook 契约还没被观察过(R3:不对未经观察的契约出适配层)。2026-09-29 已观察(agy 1.2.12、`agy -p`、单轮、无工具调用),适配层 `scripts/hooks/check-turn-completion-agy.mjs` 建立在那次实跑的产出上,而不只是文档:hook 传入数据只有 `transcriptPath`,所以最后一条回复取最后一条 `MODEL`/`PLANNER_RESPONSE`,人的消息取最后一条 `USER_EXPLICIT`/`USER_INPUT`(从 `<USER_REQUEST>` 内取出,后面的系统区块丢掉)。`SYSTEM_MESSAGE` 记录绝不当成人说的话——agy 会把这个 hook 自己的 `continue` 理由写回成这种记录,读成人的话会让 R9 叫停豁免失效。拦截是 `{"decision":"continue","reason":...}`,放行是 `{}`,所有失败路径都放行。`uds init --with-hooks` 在选了 Google Antigravity 时写入 `.agents/hooks.json`(遇到无法解析的 `hooks.json` 不覆盖),`uds uninstall` 只移除 UDS 自己的 handler、保留用户其他 hook。**已验证范围:单轮、无工具调用、`agy -p`。未验证:多轮、含工具调用的回合、交互模式、`fullyIdle: false`、`error` 非空、`.agents/hooks.json` 是否需要已登记的 Antigravity 项目、以及工作目录是否永远是 `.agents/`**——标准、适配层与安装输出都写明了这一点。**同日实测:agy 执行 hook 时的工作目录是 `.agents/`(不是项目根目录),且对启动失败的 hook 静默放行,所以安装的命令是 `node ../scripts/hooks/check-turn-completion-agy.mjs`。**
|
|
49
|
+
|
|
20
50
|
## [6.13.1] - 2026-09-28
|
|
21
51
|
|
|
22
52
|
> **修补版**:修复 6.13.0 暴露的两个“以 `uds update` 升级既有项目”的缺陷(繁中的提交消息语言段落变成英文;AGENTS.md 被改写成另一种格式且少了“这是索引”提醒),并新增一道发版前检查,实际从上一个正式版升级一次。**若你已用 `uds update` 升到 6.13.0,请在升级至 6.13.1 后再执行一次 `uds update`**,以还原那些段落。
|
|
@@ -15,7 +15,7 @@ status: current
|
|
|
15
15
|
|
|
16
16
|
> **语言**: [English](../../README.md) | [繁體中文](../zh-TW/README.md) | 简体中文
|
|
17
17
|
|
|
18
|
-
**版本**: 6.
|
|
18
|
+
**版本**: 6.14.0-beta.2 (Pre-release) | **发布日期**: 2026-09-30 | **授权**: [双重授权](../../LICENSE) (CC BY 4.0 + MIT)
|
|
19
19
|
|
|
20
20
|
语言无关、框架无关的软件项目文档标准。通过 AI 原生工作流,确保不同技术栈之间的一致性、质量和可维护性。
|
|
21
21
|
|
|
@@ -79,7 +79,7 @@ npx universal-dev-standards init
|
|
|
79
79
|
| **核心标准** | 153 | 通用开发准则 |
|
|
80
80
|
| **AI Skills** | 55 | 互动式技能 |
|
|
81
81
|
| **斜线命令** | 51 | 快速操作 |
|
|
82
|
-
| **CLI 命令** |
|
|
82
|
+
| **CLI 命令** | 24 | 项目设置与维护 |
|
|
83
83
|
<!-- UDS_STATS_TABLE_END -->
|
|
84
84
|
|
|
85
85
|
> **5.0 新功能?** 请参阅[预发布说明](../../docs/PRE-RELEASE.md)了解新功能详情。
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../../core/turn-completion-integrity.md
|
|
3
|
-
source_version: 1.
|
|
4
|
-
translation_version: 1.
|
|
5
|
-
last_synced: 2026-09-
|
|
6
|
-
source_hash:
|
|
3
|
+
source_version: 1.5.0
|
|
4
|
+
translation_version: 1.5.0
|
|
5
|
+
last_synced: 2026-09-29
|
|
6
|
+
source_hash: 08579653d9a4
|
|
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.
|
|
15
|
-
**最后更新**: 2026-09-
|
|
14
|
+
**版本**: 1.5.0
|
|
15
|
+
**最后更新**: 2026-09-29
|
|
16
16
|
**适用范围**: 任何由 agent 结束回合、把控制权交还给人的执行环境
|
|
17
17
|
**Scope**: universal
|
|
18
18
|
**行业标准**: 不声称任何来源——由实际观察到的失败归纳,见「证据」
|
|
@@ -144,13 +144,14 @@ agent 写下「我接着做 X」,然后结束回合,而 X 没有做。
|
|
|
144
144
|
## 支持的执行环境
|
|
145
145
|
|
|
146
146
|
这个检查只在「适配层存在,且 hook 真的被接入该执行环境自己的配置」时才生效。
|
|
147
|
-
截至 v1.
|
|
147
|
+
截至 v1.5.0:
|
|
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
153
|
| Gemini CLI(过时) | AfterAgent | `.gemini/settings.json` | stdout 输出 `{"decision":"deny","reason":...}`,exit 0——官方文档标记为优先于 exit code 2 的做法 |
|
|
154
|
+
| Antigravity CLI(`agy`) | Stop | `.agents/hooks.json` | stdout 输出 `{"decision":"continue","reason":...}`,exit 0;`{}` 即放行 |
|
|
154
155
|
|
|
155
156
|
在 Codex 上,接上了不等于会执行。Codex 会跳过项目级的 hook,直到项目被信任、**而且**
|
|
156
157
|
这一支 hook 的定义在交互式 Codex 会话里通过 `/hooks` 被信任为止;信任记录绑定在定义的
|
|
@@ -173,12 +174,42 @@ agent 的最后一条消息,却不给出用户的;要拿到用户那一侧
|
|
|
173
174
|
|
|
174
175
|
Gemini CLI 已过时。Google 于 2026-06-18 对个人账号停用 Gemini CLI,
|
|
175
176
|
改由 Antigravity CLI(`agy`)取代;企业账号两者都还能用。这个适配层为那些用户保留,
|
|
176
|
-
但它从未在真实的 Gemini CLI 会话中验证过;使用 Google
|
|
177
|
-
Antigravity CLI
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
但它从未在真实的 Gemini CLI 会话中验证过;使用 Google 工具的新采用者应使用下面的
|
|
178
|
+
Antigravity CLI 适配层。
|
|
179
|
+
|
|
180
|
+
Antigravity CLI 已支持,依据是真实会话观察到的契约(2026-09-29,agy 1.2.12),
|
|
181
|
+
而不只是它的文档。这份契约在关键之处与上表每一个适配层都不同:
|
|
182
|
+
|
|
183
|
+
- **配置**在 `.agents/hooks.json`,以 hook 名称为键——
|
|
184
|
+
`{"<名称>": {"Stop": [{"type":"command","command":"...","timeout":N}]}}`,
|
|
185
|
+
`timeout` 单位为秒。没有 `hooks` 外层,handler 也不嵌套在 `hooks[]` 里。
|
|
186
|
+
- **stdin 既没有最后一条回复、也没有人的消息**,只有 `transcriptPath` 与元数据,所以两者
|
|
187
|
+
都要从转录读(JSONL,每条有 `source`、`type`、`content`)。最后一条回复是最后一条
|
|
188
|
+
`source: MODEL`、`type: PLANNER_RESPONSE`。人的消息是最后一条
|
|
189
|
+
`source: USER_EXPLICIT`、`type: USER_INPUT`,取 `<USER_REQUEST>…</USER_REQUEST>` 之内的文字——
|
|
190
|
+
后面接着的系统区块(`<ADDITIONAL_METADATA>` 等)不是人说的话。
|
|
191
|
+
- **`SYSTEM_MESSAGE` 记录绝不可当成人的消息读。** agy 会把这个 hook 自己的 `continue` 理由
|
|
192
|
+
写回转录,成为这种记录(`source: SYSTEM`、`type: SYSTEM_MESSAGE`,内容为
|
|
193
|
+
「Stop hook blocked termination: …」)。若把「不是模型的任何记录」都当成人,就会把 hook
|
|
194
|
+
自己的话当成人说的,R9 豁免随之失效——也就是 R11 的失败,换成这份转录的形状重演。
|
|
195
|
+
- **拦截是 `{"decision":"continue","reason":...}`**,不是 `block` 或 `deny`;`{}` 即放行。
|
|
196
|
+
- **hook 执行时的工作目录是 `.agents/`,不是项目根目录**(2026-09-29 实测,agy 1.2.12)。
|
|
197
|
+
因此安装的命令是 `node ../scripts/hooks/check-turn-completion-agy.mjs`;以项目根目录为准的
|
|
198
|
+
`node scripts/hooks/...` 会解析成 `<项目>/.agents/scripts/hooks/...`,出现
|
|
199
|
+
「Cannot find module」,而且**agy 对执行失败的 hook 静默放行**——没有任何消息、stdout 照常,
|
|
200
|
+
回合就这样结束。路径刻意用相对路径(这个文件本来就是要提交并共用的,绝对路径只属于某一台机器),
|
|
201
|
+
也不用任何 shell 语法(`sh -c`、`$(...)`),因为 agy 是否经过 shell 执行 `command` 没有证据。
|
|
202
|
+
- **与 Claude Code 相反,hook 被调用时转录已经写到最后一条回复。**
|
|
203
|
+
|
|
204
|
+
已验证:agy 1.2.12、非交互的 `agy -p`、**单轮且没有工具调用**——hook 被调用时最后一条回复
|
|
205
|
+
已在转录里,`continue` 确实生效(模型又回了一轮),且没有遇到信任提示(与 Codex 不同)。
|
|
206
|
+
**未验证**:多轮对话、含工具调用的回合(此时最后一条 `PLANNER_RESPONSE` 是不是最后回复、
|
|
207
|
+
hook 执行时是否已写入)、`fullyIdle: false`、`error` 非空、交互模式、项目级
|
|
208
|
+
`.agents/hooks.json` 是否像 `.agents/skills/` 一样只对已登记的 Antigravity 项目生效,
|
|
209
|
+
以及工作目录是否永远是 `.agents/`(只对项目级文件量测过;`uds init` 不会写用户级的
|
|
210
|
+
`~/.gemini/config/hooks.json`)。在未验证的情境下,适配层可能判断的是
|
|
211
|
+
较早的一条回复而不是最后一条;读取失败时仍一律放行(R5)。`uds init --with-hooks` 会在安装
|
|
212
|
+
那一行旁边打印已验证的范围。
|
|
182
213
|
|
|
183
214
|
Cursor 已评估但不支持:截至撰写本文时,Cursor 的 stop hook 能不能真的
|
|
184
215
|
拦下一个回合仍未确定,若对着一个没人验证过的契约交付一份适配层,
|
|
@@ -240,3 +271,5 @@ Cursor 已评估但不支持:截至撰写本文时,Cursor 的 stop hook 能
|
|
|
240
271
|
- [ ] 归属词的搜索排除检查自己的标题与结构
|
|
241
272
|
- [ ] 每个支持的执行环境的拦截契约都对照该环境自己的官方文档验证过,不是照搬另一个环境
|
|
242
273
|
- [ ] 安装器只为采用者实际选择的执行环境写入该环境的 hook 配置
|
|
274
|
+
- [ ] 转录里会出现系统代写消息的执行环境,只从「人的记录」读人的消息,绝不从「不是模型写的任何东西」读
|
|
275
|
+
- [ ] 一份执行环境契约只对「真实会话观察过的范围」交付,并注明没观察到的范围
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UDS 速查表
|
|
2
2
|
|
|
3
|
-
> Quick reference for all UDS features | Last updated: 2026-09-
|
|
3
|
+
> Quick reference for all UDS features | Last updated: 2026-09-29
|
|
4
4
|
|
|
5
5
|
**Language**: [English](../../../docs/user/CHEATSHEET.md) | [繁體中文](../../zh-TW/docs/CHEATSHEET.md) | 简体中文
|
|
6
6
|
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
| `uds agent` | Manage UDS agents for AI tools |
|
|
33
33
|
| `uds ai-context` | Manage .ai-context.yaml configuration for AI-friendly architecture |
|
|
34
34
|
| `uds mcp` | MCP server commands for AI tool integration |
|
|
35
|
+
| `uds open-work` | Reference checks for open-work-tracking (OWT-017/018/019). Exit 0 no violation, 1 violation, 2 cannot decide (not a pass) |
|
|
35
36
|
| `uds run` | Run a project command by intent (test/lint/build/security) via uds.project.yaml |
|
|
36
37
|
|
|
37
38
|
## 💬 斜线命令
|
|
@@ -352,8 +353,11 @@
|
|
|
352
353
|
| `check-docs-sync.sh` | Documentation Sync Checker |
|
|
353
354
|
| `check-error-exit.mjs` | 🔴 沒填就是沒設定,而沒設定會 exit 2, |
|
|
354
355
|
| `check-external-references.mjs` | External Reference Checker (SPEC-SELFDIAG-001 REQ- |
|
|
356
|
+
| `check-home-untouched.mjs` | check-home-untouched — did this run write anywhere |
|
|
357
|
+
| `check-open-work-tracking.mjs` | Open-work-tracking reference checks for OWT-017 / |
|
|
355
358
|
| `check-orphan-specs.ps1` | Check Orphan Specs |
|
|
356
359
|
| `check-orphan-specs.sh` | Orphan Spec Detection Script |
|
|
360
|
+
| `check-prompt-footprint.mjs` | Prompt Footprint Ratchet — DEC-117 D2/L2 |
|
|
357
361
|
| `check-scope-sync.ps1` | Check Scope Sync |
|
|
358
362
|
| `check-scope-sync.sh` | Scope Consistency Check Script |
|
|
359
363
|
| `check-skill-next-steps-sync.ps1` | Check Skill Next Steps Sync |
|
|
@@ -367,6 +371,7 @@
|
|
|
367
371
|
| `check-translation-hash-ratchet.sh` | XSPEC-392 R6 棘輪:新的翻譯必須帶 source_hash,既有的欠債冷凍為基線。 |
|
|
368
372
|
| `check-translation-sync.ps1` | Check Translation Sync |
|
|
369
373
|
| `check-translation-sync.sh` | Translation Sync Checker |
|
|
374
|
+
| `check-upgrade-fidelity.sh` | Upgrade Fidelity Checker |
|
|
370
375
|
| `check-usage-docs-sync.ps1` | Check if usage documentation needs to be regenerat |
|
|
371
376
|
| `check-usage-docs-sync.sh` | check-usage-docs-sync.sh |
|
|
372
377
|
| `check-version-sync.ps1` | Check Version Sync |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../../docs/CLI-INIT-OPTIONS.md
|
|
3
|
-
source_version: 3.7.
|
|
4
|
-
translation_version: 3.7.
|
|
5
|
-
last_synced: 2026-09-
|
|
3
|
+
source_version: 3.7.1
|
|
4
|
+
translation_version: 3.7.1
|
|
5
|
+
last_synced: 2026-09-29
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -10,8 +10,8 @@ status: current
|
|
|
10
10
|
|
|
11
11
|
> **语言**: [English](../../../docs/CLI-INIT-OPTIONS.md) | [简体中文](../../zh-TW/docs/CLI-INIT-OPTIONS.md) | 简体中文
|
|
12
12
|
>
|
|
13
|
-
> **版本**: 3.7.
|
|
14
|
-
> **最后更新**: 2026-09-
|
|
13
|
+
> **版本**: 3.7.1
|
|
14
|
+
> **最后更新**: 2026-09-29
|
|
15
15
|
|
|
16
16
|
本文档详细说明 `uds init` 命令的每一个选项,包含使用情境、影响范围和建议选择。
|
|
17
17
|
|
|
@@ -870,21 +870,46 @@ UDS 的项目——并在 `[pre-commit]` 下回报同样的修复方式;此警
|
|
|
870
870
|
|
|
871
871
|
`--with-hooks` 一定会安装进 `.claude/settings.json`。四个有 hook 支持的标准
|
|
872
872
|
之一——`turn-completion-integrity`(见 CHANGELOG,Unreleased)——也会装进
|
|
873
|
-
**Codex
|
|
873
|
+
**Codex**、**Gemini CLI**(过时)与 **Antigravity CLI**(`agy`),门槛是你有没有在 [AI 工具选择](#1-ai-工具选择)
|
|
874
874
|
里选了那个工具(或用非交互模式的工具标志带入):
|
|
875
875
|
|
|
876
876
|
| 工具 | 写入的配置文件 | 触发条件 |
|
|
877
877
|
|------|---------------|---------|
|
|
878
878
|
| Codex | `.codex/hooks.json` | 选了 **OpenAI Codex** |
|
|
879
879
|
| Gemini CLI | `.gemini/settings.json` | 选了 **Gemini CLI** |
|
|
880
|
+
| Antigravity CLI | `.agents/hooks.json` | 选了 **Google Antigravity** |
|
|
880
881
|
|
|
881
|
-
没选的工具不会写入任何东西——`uds init` 不会在没用到 Codex 或
|
|
882
|
-
的项目里创建 `.codex/` 或 `.
|
|
882
|
+
没选的工具不会写入任何东西——`uds init` 不会在没用到 Codex、Gemini CLI 或 Antigravity
|
|
883
|
+
的项目里创建 `.codex/`、`.gemini/` 或 `.agents/` 目录。其余三个有 hook 支持的标准
|
|
883
884
|
(commit message 校验、logging、security)目前仍只支持 Claude Code;
|
|
884
885
|
为什么目前只推广 turn-completion-integrity,以及 Cursor 的现状
|
|
885
886
|
(已评估、不支持),见
|
|
886
887
|
[支持的执行环境](../../../core/turn-completion-integrity.md#supported-harnesses)。
|
|
887
888
|
|
|
889
|
+
### 为已初始化的项目补装 Hooks(`uds update --with-hooks`)
|
|
890
|
+
|
|
891
|
+
`uds init` 不能跑第二次,所以 `--with-hooks` 到不了已经初始化的项目——包括在 UDS 支持某个工具**之前**
|
|
892
|
+
(或在检测认得它之前)就初始化的项目。`uds update --with-hooks` 就是那扇门:
|
|
893
|
+
|
|
894
|
+
```bash
|
|
895
|
+
uds update --with-hooks --plan # 列出会装什么;不写任何文件
|
|
896
|
+
uds update --with-hooks # 补装缺少的 hooks
|
|
897
|
+
uds update --with-hooks --ai-tool antigravity # 直接指定工具,不做检测
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
- **装给哪些工具。** `.standards/manifest.json` 里的工具,加上项目文件现在看得出来的(Claude Code:
|
|
901
|
+
`.claude/` 或 `CLAUDE.md`;Codex:根目录 `AGENTS.md`;Gemini CLI:`GEMINI.md`;Antigravity:
|
|
902
|
+
`.agents/AGENTS.md`、`.agents/rules/`、`.agents/workflows/`、`.agents/plugins/` 或
|
|
903
|
+
`.agents/hooks.json`)。**`.agents/skills/` 不算 Antigravity 的标记**——Codex 也从同一个目录读项目技能,
|
|
904
|
+
所以它分不出是哪个工具。`--ai-tool <列表>`(`claude-code`、`codex`、`gemini-cli`、`antigravity`,
|
|
905
|
+
以逗号分隔)会取代检测。找不到任何工具时,它会说明、打印出如何指定,并以 1 退出。
|
|
906
|
+
- **不会动什么。** 已经装好的 hook 不会被重写。你自己的 hooks 不会被移除或重排:Claude、Codex、Gemini 的
|
|
907
|
+
条目是合并进去;Antigravity 的 `.agents/hooks.json` 只写在 `uds-turn-completion-integrity` 这个键下面
|
|
908
|
+
(不是合法 JSON 的 `hooks.json` 会原样保留并报告)。`scripts/hooks/` 里与随附版本不同的 hook 脚本会被保留并报告;
|
|
909
|
+
加上 `--force` 才会覆盖。
|
|
910
|
+
- **它不做什么。** 不更新标准、技能或集成文件(那是一般的 `uds update`),也不会把工具加进 manifest。
|
|
911
|
+
它不能与 `--skills`、`--commands` 等其他 update 模式合用,合用时会明说。
|
|
912
|
+
|
|
888
913
|
### Claude Code 集成目标文件(`--claude-target`)
|
|
889
914
|
|
|
890
915
|
UDS 默认把 Claude Code 内容写进 `CLAUDE.md`——团队共用、会进版本控制的那个文件。
|