universal-dev-standards 6.3.9 → 6.4.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/bin/uds.js +2 -2
- package/bundled/ai/standards/class-level-fix.ai.yaml +143 -0
- package/bundled/core/class-level-fix.md +161 -0
- package/bundled/locales/zh-CN/CHANGELOG.md +26 -3
- package/bundled/locales/zh-CN/CLAUDE.md +1 -1
- package/bundled/locales/zh-CN/README.md +3 -3
- package/bundled/locales/zh-CN/SECURITY.md +1 -1
- package/bundled/locales/zh-CN/docs/CHEATSHEET.md +3 -1
- package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +9 -7
- package/bundled/locales/zh-TW/CHANGELOG.md +26 -3
- package/bundled/locales/zh-TW/CLAUDE.md +1 -1
- package/bundled/locales/zh-TW/README.md +3 -3
- package/bundled/locales/zh-TW/SECURITY.md +1 -1
- package/bundled/locales/zh-TW/core/class-level-fix.md +148 -0
- package/bundled/locales/zh-TW/docs/CHEATSHEET.md +3 -1
- package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +9 -7
- package/package.json +1 -1
- package/src/commands/update.js +187 -39
- package/standards-registry.json +19 -7
package/bin/uds.js
CHANGED
|
@@ -213,8 +213,8 @@ program
|
|
|
213
213
|
.option('--skills', 'Install/update Skills for configured AI tools')
|
|
214
214
|
.option('--commands', 'Install/update slash commands for configured AI tools')
|
|
215
215
|
.option('--debug', 'Show debug output for Skills/Commands detection')
|
|
216
|
-
.option('--plan', 'Show reconciliation plan without executing (like terraform plan)')
|
|
217
|
-
.option('--apply', 'Apply exactly the plan --plan prints (plain `uds update` does not)')
|
|
216
|
+
.option('--plan', 'Show reconciliation plan without executing (like terraform plan); combines with --skills/--commands to plan just that scope, still writing nothing')
|
|
217
|
+
.option('--apply', 'Apply exactly the plan --plan prints (plain `uds update` does not); with --skills/--commands it does the reconciliation AND that scope, not only the scope')
|
|
218
218
|
.option('--force', 'Force update all files, ignoring hash comparison')
|
|
219
219
|
.option('--rollback', 'Rollback to the most recent backup')
|
|
220
220
|
.option('--locale <locale>', 'Override locale for skills install (zh-tw, zh-cn, en); also reads .uds/install.yaml + UDS_LOCALE env')
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Class-Level Fix Standard - AI Optimized
|
|
2
|
+
# Source: core/class-level-fix.md
|
|
3
|
+
|
|
4
|
+
standard:
|
|
5
|
+
id: class-level-fix
|
|
6
|
+
name: Class-Level Fix Standard
|
|
7
|
+
description: 類別層修正標準——修正瞄準集合,不是瞄準成員
|
|
8
|
+
|
|
9
|
+
meta:
|
|
10
|
+
version: "1.0.0"
|
|
11
|
+
updated: "2026-08-10"
|
|
12
|
+
source: core/class-level-fix.md
|
|
13
|
+
description: >
|
|
14
|
+
一個缺陷幾乎從不孤單,它是某個集合的一員。修掉被指出的那一員,
|
|
15
|
+
集合裡其餘的原封不動,而沒有東西會通知你下一個在哪。
|
|
16
|
+
本標準要求修正瞄準集合:指出可窮舉集合,並加上一個「走訪」而非「列舉」該集合的檢查。
|
|
17
|
+
|
|
18
|
+
iron_law: >
|
|
19
|
+
修一個缺陷之前,先指出它所屬的可窮舉集合,並加上一個走訪該集合的檢查。
|
|
20
|
+
若該集合無法被走訪,寫下為什麼——沉默不算答案。
|
|
21
|
+
|
|
22
|
+
guidelines:
|
|
23
|
+
- "修正瞄準集合,不是瞄準成員"
|
|
24
|
+
- "**走訪並排除,絕不列舉**——列舉正確到有人新增第四個成員為止,而沒有東西會告訴你"
|
|
25
|
+
- "走訪必須從系統自己讀的那個來源讀(CLI 定義/目錄/manifest),**不從手打的清單讀**"
|
|
26
|
+
- "檢查要印出分母**與被排除的數量**,不是只印「全部通過」"
|
|
27
|
+
- "類別層檢查在被信任之前,先以合成成員證明它不是空跑——**逐子集做,不要整體做**"
|
|
28
|
+
- "集合無法走訪是合法答案,但要寫下理由與解除條件"
|
|
29
|
+
- "**註解描述了類別,不等於有檢查涵蓋類別**——散文不會執行"
|
|
30
|
+
|
|
31
|
+
# 依序回答,第 3 題決定這道檢查活不活得下去
|
|
32
|
+
three_questions:
|
|
33
|
+
- order: 1
|
|
34
|
+
question: "這個缺陷是哪個集合的一員?"
|
|
35
|
+
examples: ["分派鏈裡的旗標", "manifest 的條目", "agents/ 底下的目錄", "目錄樹裡的設定檔"]
|
|
36
|
+
- order: 2
|
|
37
|
+
question: "那個集合能不能被走訪而不是被列舉?"
|
|
38
|
+
- order: 3
|
|
39
|
+
question: "走訪從哪裡讀出成員?"
|
|
40
|
+
note: >
|
|
41
|
+
必須從系統自己讀的那個來源讀。從手打的清單讀,等於把同一個缺陷
|
|
42
|
+
換一個位置重新製造一次。
|
|
43
|
+
|
|
44
|
+
walk_vs_enumerate:
|
|
45
|
+
enumerate:
|
|
46
|
+
shape: "for (const x of ['a','b','c'])"
|
|
47
|
+
new_member: "靜默地不被涵蓋"
|
|
48
|
+
failure_mode: "對一部分表面回報綠燈"
|
|
49
|
+
walk_and_exclude:
|
|
50
|
+
shape: "for (const x of readAll()) if (!EXCLUDED.has(x))"
|
|
51
|
+
new_member: "**預設被涵蓋**"
|
|
52
|
+
failure_mode: "吵——而吵是看得見的"
|
|
53
|
+
why: >
|
|
54
|
+
不對稱正是重點。列舉失敗時是靜默的;排除清單失敗時是吵的,
|
|
55
|
+
因為那條排除必須由一個人寫下來,而他得說明理由。
|
|
56
|
+
|
|
57
|
+
# 一道類別層檢查在被信任之前必須先被證明非空跑
|
|
58
|
+
evidence_requirement:
|
|
59
|
+
steps:
|
|
60
|
+
- "塞一個違反規則的合成成員"
|
|
61
|
+
- "確認檢查失敗**且指名該成員**"
|
|
62
|
+
- "移除後確認回到綠燈"
|
|
63
|
+
granularity: per_subset
|
|
64
|
+
why_per_subset: >
|
|
65
|
+
一道涵蓋五份清單、卻只對第一份測過的檢查,是一道涵蓋一份清單的檢查。
|
|
66
|
+
|
|
67
|
+
output_requirement:
|
|
68
|
+
must_print: ["實際檢查的數量(分母)", "被排除的數量"]
|
|
69
|
+
rationale: >
|
|
70
|
+
只印分母不夠。「檢查了 4,012 條宣告」讀起來像涵蓋率,
|
|
71
|
+
而篩選器悄悄跳過了每一條目錄條目。
|
|
72
|
+
|
|
73
|
+
# 集合無法走訪時的合法出口
|
|
74
|
+
when_not_walkable:
|
|
75
|
+
legitimate: true
|
|
76
|
+
must_record: ["理由", "什麼條件下會改變"]
|
|
77
|
+
common_cause: >
|
|
78
|
+
成員只能相對於某個基準目錄才知道,而那個基準沒有記在任何機器讀得到的地方
|
|
79
|
+
(例如 manifest 的路徑基準只活在讀取它的程式裡)。對這種宣告做通用掃描,
|
|
80
|
+
假陽性率高到讓檢查在第一週就被關掉。
|
|
81
|
+
workable_form: >
|
|
82
|
+
逐份清冊——一種宣告一道檢查,各自知道自己的基準與條目形狀。
|
|
83
|
+
說出清冊有幾份,並確認每一份都有檢查。
|
|
84
|
+
|
|
85
|
+
anti_patterns:
|
|
86
|
+
- pattern: "修掉被回報的那一員就結案"
|
|
87
|
+
why: "集合沒有變;下一個成員會以新事故的形式抵達"
|
|
88
|
+
- pattern: "寫一段註解說明通則"
|
|
89
|
+
why: "散文不會執行"
|
|
90
|
+
- pattern: "檢查自行列舉它的範圍"
|
|
91
|
+
why: "正確到有人新增第四個成員為止"
|
|
92
|
+
- pattern: "類別層檢查只對一個成員測過"
|
|
93
|
+
why: "證明的是那一個成員,不是那個類別"
|
|
94
|
+
- pattern: "`✓ all pass` 而沒有分母"
|
|
95
|
+
why: "掃了全部與什麼都沒掃,輸出一模一樣"
|
|
96
|
+
|
|
97
|
+
rules:
|
|
98
|
+
- id: CLF-001
|
|
99
|
+
rule: "修正前必須指出缺陷所屬的可窮舉集合"
|
|
100
|
+
severity: error
|
|
101
|
+
- id: CLF-002
|
|
102
|
+
rule: "類別層檢查必須走訪集合並排除例外,不得列舉成員"
|
|
103
|
+
severity: error
|
|
104
|
+
- id: CLF-003
|
|
105
|
+
rule: "走訪的成員來源必須是系統自己讀的來源,不得是手寫清單"
|
|
106
|
+
severity: error
|
|
107
|
+
- id: CLF-004
|
|
108
|
+
rule: "檢查輸出必須包含分母與被排除的數量"
|
|
109
|
+
severity: error
|
|
110
|
+
- id: CLF-005
|
|
111
|
+
rule: "類別層檢查須以合成成員逐子集證明非空跑"
|
|
112
|
+
severity: error
|
|
113
|
+
- id: CLF-006
|
|
114
|
+
rule: "集合無法走訪時,須記錄理由與解除條件"
|
|
115
|
+
severity: warning
|
|
116
|
+
|
|
117
|
+
# 本標準自己沒有自動閘門——依它自己的規則,這件事必須寫下來而不是暗示強制力存在
|
|
118
|
+
enforcement:
|
|
119
|
+
automated_gate: false
|
|
120
|
+
why_not: >
|
|
121
|
+
沒有任何檢查能走訪「現在正在被修的所有缺陷」。套用本標準是修的當下所做的判斷。
|
|
122
|
+
enforced_by: review
|
|
123
|
+
review_question: "這是哪個集合的一員?"
|
|
124
|
+
reopen_condition: >
|
|
125
|
+
若 repo 取得「能把一次缺陷修正落地看成離散事件」的機制(有標記的 commit 型別、
|
|
126
|
+
issue↔commit 連結),即可斷言這類 commit 要嘛動到一個走訪集合的測試,
|
|
127
|
+
要嘛帶著寫下來的理由。
|
|
128
|
+
note: >
|
|
129
|
+
一份陳述了規則而沒有東西執行它的標準,正是「寫下來的風險沒有東西在執行」那個形狀。
|
|
130
|
+
不承認這一點的標準比承認的更糟,因為讀的人會以為有東西在盯。
|
|
131
|
+
|
|
132
|
+
related:
|
|
133
|
+
- id: verification-evidence
|
|
134
|
+
relation: "同一族:工具靜默失敗時,其輸出與真結果無從分辨。本標準是同一件事套用在**範圍**而非**執行**上"
|
|
135
|
+
- id: anti-hallucination
|
|
136
|
+
relation: "那個防「沒查」;這個防「查了其中一個,卻對全部下結論」"
|
|
137
|
+
|
|
138
|
+
physical_spec:
|
|
139
|
+
applies_to:
|
|
140
|
+
- "任何缺陷修正(程式碼或設定)"
|
|
141
|
+
deliverables:
|
|
142
|
+
- "一道走訪集合的檢查,或一份「為何無法走訪」的紀錄"
|
|
143
|
+
- "該檢查的逐子集對照組證據"
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Class-Level Fix Standard
|
|
2
|
+
|
|
3
|
+
> **Language**: English | [繁體中文](../locales/zh-TW/core/class-level-fix.md)
|
|
4
|
+
|
|
5
|
+
**Version**: 1.0.0
|
|
6
|
+
**Last Updated**: 2026-08-10
|
|
7
|
+
**Applicability**: Any defect fix, in code or in configuration
|
|
8
|
+
**Scope**: universal
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
A defect is almost never alone. It is one member of a set — one flag in a dispatch chain, one entry in a manifest, one directory under `agents/`, one config file in a tree. Fixing the member you were shown leaves the rest of the set exactly as it was, and **nothing announces the next one**. It surfaces months later as a fresh incident, and the work feels endless because the same shape keeps arriving under different names.
|
|
15
|
+
|
|
16
|
+
This standard requires that a fix be aimed at the **set**, not at the member.
|
|
17
|
+
|
|
18
|
+
一個缺陷幾乎從不孤單。它是某個集合的一員——分派鏈裡的一個旗標、manifest 裡的一條宣告、`agents/` 底下的一個目錄、目錄樹裡的一份設定檔。修掉被指出的那一員,集合裡其餘的原封不動,**而沒有任何東西會通知你下一個在哪**。它會在幾個月後以一則新事故的形式出現,於是工作感覺沒完沒了——因為同一個形狀不斷換名字回來。
|
|
19
|
+
|
|
20
|
+
本標準要求:**修正瞄準集合,不是瞄準成員。**
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## The Rule
|
|
25
|
+
|
|
26
|
+
**Before fixing a defect, name the enumerable set it belongs to, and add a check that walks that set.** If the set cannot be walked, write down why. Silence is not an answer.
|
|
27
|
+
|
|
28
|
+
**修一個缺陷之前,先指出它所屬的可窮舉集合,並加上一個走訪該集合的檢查。** 若該集合無法被走訪,寫下為什麼。沉默不算答案。
|
|
29
|
+
|
|
30
|
+
### Three questions, in order
|
|
31
|
+
|
|
32
|
+
| # | Question | 問題 |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| 1 | What set is this defect a member of? | 這個缺陷是哪個集合的一員? |
|
|
35
|
+
| 2 | Can that set be **walked** rather than **listed**? | 那個集合能不能被**走訪**而不是**列舉**? |
|
|
36
|
+
| 3 | Where does the walk read its members from? | 走訪從哪裡讀出成員? |
|
|
37
|
+
|
|
38
|
+
Question 3 decides whether the check survives. **The walk must read from the same source the system reads from** — the CLI definition, the directory, the manifest — never from a list you typed. A typed list is correct until someone adds the fourth member, and nothing will tell you.
|
|
39
|
+
|
|
40
|
+
第 3 題決定這道檢查活不活得下去。**走訪必須從系統自己讀的那個來源讀**——CLI 定義、目錄、manifest——**絕不從你手打的清單讀**。手打的清單正確到有人新增第四個成員為止,而不會有東西告訴你。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Walk and exclude, never enumerate
|
|
45
|
+
|
|
46
|
+
| | Enumerate(列舉)| Walk and exclude(走訪並排除)|
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| Shape | `for (const x of ['a','b','c'])` | `for (const x of readAll()) if (!EXCLUDED.has(x))` |
|
|
49
|
+
| A new member is | silently uncovered | **covered by default** |
|
|
50
|
+
| Wrong when | someone adds the fourth | someone adds an exclusion without cause |
|
|
51
|
+
| Failure mode | reports green over a fraction | noisy — which is visible |
|
|
52
|
+
|
|
53
|
+
**The asymmetry is the point.** An enumeration fails silently; an exclusion list fails loudly, because the exclusion has to be written down by a person who has to justify it.
|
|
54
|
+
|
|
55
|
+
**不對稱正是重點。** 列舉失敗時是靜默的;排除清單失敗時是吵的,因為那條排除必須由一個人寫下來,而他得說明理由。
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## The check must print what it excluded
|
|
60
|
+
|
|
61
|
+
A denominator alone is not enough. `checked 4,012 declarations` reads like coverage while the filter silently skipped every directory entry.
|
|
62
|
+
|
|
63
|
+
只印分母不夠。「檢查了 4,012 條宣告」讀起來像涵蓋率,而篩選器悄悄跳過了每一條目錄條目。
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
✓ 91 entries across 5 lists all resolve # denominator
|
|
67
|
+
(0 excluded) # and what was left out
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See [verification-evidence](verification-evidence.md) — this is the same family: an output whose shape is identical whether the tool worked or not.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Evidence requirement
|
|
75
|
+
|
|
76
|
+
A class-level check must be proven non-vacuous **before** it is trusted:
|
|
77
|
+
|
|
78
|
+
1. Add a synthetic member that violates the rule.
|
|
79
|
+
2. Confirm the check fails **and names that member**.
|
|
80
|
+
3. Remove it and confirm the check returns to green.
|
|
81
|
+
|
|
82
|
+
Do this **per sub-set**, not in aggregate. A check over five lists that was only ever tested against the first is a check over one list.
|
|
83
|
+
|
|
84
|
+
一道類別層檢查在被信任之前,必須先被證明不是空跑:塞一個違反規則的合成成員 → 確認檢查失敗**且指名該成員** → 移除後確認回到綠燈。**逐子集做,不要整體做**——一道涵蓋五份清單、卻只對第一份測過的檢查,是一道涵蓋一份清單的檢查。
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Worked examples (measured, 2026-08-10)
|
|
89
|
+
|
|
90
|
+
### It works: the flag dispatch
|
|
91
|
+
|
|
92
|
+
A CLI's `--plan` flag (documented as "show the plan without executing") was being silently discarded when combined with `--skills`, because scope flags sat ahead of mode flags in a first-match-wins chain. The instance-level fix was two branches.
|
|
93
|
+
|
|
94
|
+
The class-level fix was a test that **reads the flag list off the CLI definition**, excludes the mode flags and the few that are not scopes, and asserts `--plan` writes nothing whatever it is combined with.
|
|
95
|
+
|
|
96
|
+
**It found a fourth instance the moment it first ran** — `--sync-refs`, which nobody had looked at, and which was rewriting integration files and the manifest under a flag documented as not executing.
|
|
97
|
+
|
|
98
|
+
### It fails: the same defect, fixed once, eleven days earlier
|
|
99
|
+
|
|
100
|
+
The same codebase had already fixed exactly this for `--integrations-only`, eleven days before, **with a comment explaining the general problem**. The other three branches were left untouched. The knowledge was in the file; it had not reached its siblings.
|
|
101
|
+
|
|
102
|
+
> **A comment describing the class is not a check over the class.** This is the failure this standard exists to prevent.
|
|
103
|
+
|
|
104
|
+
### It fails: a gate that listed its own scope
|
|
105
|
+
|
|
106
|
+
A parsing gate hardcoded three directories instead of walking the tree. It reported "423 files all pass" while the shipping surface was 287 files, and ten broken ones reached the registry.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## When the set cannot be walked
|
|
111
|
+
|
|
112
|
+
Legitimate. Write it down, with the reason and what would change it.
|
|
113
|
+
|
|
114
|
+
The common cause is that **the set's members are only knowable from a base directory that is not recorded anywhere machine-readable** — for example, a manifest whose paths are relative to a root stated only inside the program that reads it. A generic walk over such declarations produces false positives at a rate that gets the check switched off in its first week.
|
|
115
|
+
|
|
116
|
+
In that case the workable form is **per-inventory**: one check per declaration kind, each knowing its own base and entry shape. Say how many inventories there are, and confirm each has a check.
|
|
117
|
+
|
|
118
|
+
集合無法被走訪是合法的答案,但要寫下來,連同理由與「什麼條件下會改變」。
|
|
119
|
+
|
|
120
|
+
最常見的成因是**成員只能相對於某個基準目錄才知道,而那個基準沒有記在任何機器讀得到的地方**——例如一份 manifest,它的路徑基準只活在讀取它的那支程式裡。對這種宣告做通用掃描,假陽性率高到讓檢查在第一週就被關掉。這時可行的形狀是**逐份清冊**:一種宣告一道檢查,各自知道自己的基準與條目形狀。**說出清冊有幾份,並確認每一份都有檢查。**
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Anti-patterns
|
|
125
|
+
|
|
126
|
+
| Anti-pattern | Why it fails |
|
|
127
|
+
|---|---|
|
|
128
|
+
| Fixing the reported member and moving on | The set is unchanged; the next member arrives as a new incident |
|
|
129
|
+
| A comment explaining the general problem | Prose does not execute |
|
|
130
|
+
| A check that lists its own scope | Correct until someone adds the fourth member |
|
|
131
|
+
| Testing the class check against one member | Proves that member, not the class |
|
|
132
|
+
| `✓ all pass` with no denominator | Identical output whether it scanned everything or nothing |
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## This standard has no automated gate — and that is recorded, not hidden
|
|
137
|
+
|
|
138
|
+
Applying this standard is a judgement made at the moment of fixing. There is no check that can walk "all defects being fixed right now", so by its own rule the honest answer is to write down why not, rather than to imply enforcement that does not exist.
|
|
139
|
+
|
|
140
|
+
**What this means in practice**: the only place it can bite is review — human or agent. A fix that changes one member of a set and adds no check over that set should be sent back with one question: *what set is this a member of?*
|
|
141
|
+
|
|
142
|
+
**Reopen condition**: if a repository gains a mechanism that can see "a defect fix landed" as a discrete event (a labelled commit type, an issue-to-commit link), a check becomes possible — assert that such a commit either touches a test that walks a set, or carries a written reason. Until that exists, this standard is enforced by reading.
|
|
143
|
+
|
|
144
|
+
> Recording this is not a formality. A standard that states a rule while nothing executes it is the exact shape of a documented risk with no enforcement — and a standard that does not admit it is worse than one that does, because the reader assumes something is watching.
|
|
145
|
+
|
|
146
|
+
**本標準沒有自動閘門,而這件事是被記錄下來的,不是被藏起來的。**
|
|
147
|
+
|
|
148
|
+
套用本標準是「修的當下」所做的判斷。沒有任何檢查能走訪「現在正在被修的所有缺陷」,所以依照它自己的規則,誠實的答案是寫下為什麼不能,而不是暗示一個不存在的強制力。
|
|
149
|
+
|
|
150
|
+
**實務上唯一會咬到的地方是 review**(人或 agent):一個只改了集合中某一員、而沒有加上涵蓋該集合之檢查的修正,應該被退回並問一句——**這是哪個集合的一員?**
|
|
151
|
+
|
|
152
|
+
**重啟條件**:若某個 repo 取得了「能把『一次缺陷修正落地』看成一個離散事件」的機制(有標記的 commit 型別、issue↔commit 連結),檢查就變得可能——斷言這類 commit 要嘛動到一個走訪集合的測試,要嘛帶著一段寫下來的理由。在那之前,本標準靠閱讀執行。
|
|
153
|
+
|
|
154
|
+
> 記下這件事不是形式。**一份陳述了規則而沒有東西執行它的標準,正是「寫下來的風險沒有東西在執行」那個形狀**——而一份不承認這一點的標準,比承認的更糟,因為讀的人會以為有東西在盯。
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Relationship to other standards
|
|
159
|
+
|
|
160
|
+
- [verification-evidence](verification-evidence.md) — evidence validity: a tool can fail silently and its output is indistinguishable from a real result. This standard is the same concern applied to *scope* rather than to *execution*.
|
|
161
|
+
- [anti-hallucination](anti-hallucination.md) — that one guards "did not check"; this one guards "checked one of many and reported on all".
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../CHANGELOG.md
|
|
3
|
-
source_version: 6.
|
|
4
|
-
translation_version: 6.
|
|
5
|
-
last_synced: 2026-08-
|
|
3
|
+
source_version: 6.4.0
|
|
4
|
+
translation_version: 6.4.0
|
|
5
|
+
last_synced: 2026-08-10
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -17,6 +17,29 @@ status: current
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [6.4.0] - 2026-08-10
|
|
21
|
+
|
|
22
|
+
### 新增
|
|
23
|
+
|
|
24
|
+
- **`class-level-fix` 标准——修正瞄准集合,不是瞄准成员。** 一个缺陷几乎从不孤单:它是分派链里的一个标志、manifest 里的一条声明、`agents/` 底下的一个目录。修掉被指出的那一员,集合里其余的原封不动,**而没有东西会通知你下一个在哪**——它会在几个月后以新事故的形式回来,那正是这类工作感觉没完没了的原因。规则:修之前先指出缺陷所属的可穷举集合,并加上一个**走访**该集合的检查。第三个问题决定这道检查活不活得下去——走访从哪里读出成员?必须是系统自己读的那个来源(CLI 定义、目录、manifest),**绝不是谁手打的清单**,因为手打的清单正确到第四个成员出现为止,而不会有东西告诉你。枚举失败时是静默的;走访配排除清单失败时是吵的,因为那条排除必须由一个人写下来、而他得说明理由。检查必须打印分母**与被排除的数量**——「检查了 4,012 条声明」读起来像覆盖率,而筛选器悄悄跳过了每一条目录条目。而且它在被信任之前要**逐子集**证明非空跑,因为一道覆盖五份清单却只对第一份测过的检查,是一道覆盖一份清单的检查。
|
|
25
|
+
|
|
26
|
+
标准里每一个实例都是 2026-08-10 量出来的。最有分量的是那个反例:本 repo **十一天前已经为 `--integrations-only` 修过完全相同的缺陷,还留了一段说明通则的注释**,而另外三个分支原封不动。知识就在那个文件里,只是没有到达它的兄弟。**一段描述类别的注释,不等于一道覆盖类别的检查。**
|
|
27
|
+
|
|
28
|
+
标准明白写出**它没有自动闸门**——没有东西能走访「现在正在被修的所有缺陷」——并记下理由、由什么执行(review,只问一句:*这是哪个集合的一员?*)、以及什么条件下闸门会变得可能。不写那一段,它就会变成它所要防止的那件事的下一个实例。
|
|
29
|
+
|
|
30
|
+
### 修复
|
|
31
|
+
|
|
32
|
+
- **`--plan` 与 `--apply` 的组合行为现在也到得了 `--help`。** 6.3.10 记录该行为的方式是编辑 `docs/reference/FEATURE-REFERENCE.md`——一份**生成的文件**。那次编辑活到有人重新生成为止。文本现在住在 `cli/bin/uds.js` 的 `.option()` 字符串里,于是它也会出现在 `uds update --help`,而手改的那一份从来不会。
|
|
33
|
+
|
|
34
|
+
## [6.3.10] - 2026-08-10
|
|
35
|
+
|
|
36
|
+
### 修复
|
|
37
|
+
|
|
38
|
+
- **`--plan` 会被另外四个标志吃掉,而唯一能防止破坏的正是被忽略的那一个。** `uds update --plan --skills` 会安装 Skills;`--plan --sync-refs` 会改写集成文件与 manifest。那个文档写着「Show reconciliation plan without executing (like terraform plan)」的标志被静默丢弃——因为范围标志(`--skills`、`--commands`、`--integrations-only`、`--sync-refs`)在一条先到先得、每个分支都 return 的链里,排在模式标志(`--plan`、`--apply`、`--force`、`--rollback`)之前。`--integrations-only` 早在 2026-07-30 就为了同一件事修过;另外三个没有被碰,十一天后它们仍在写文件。现在模式先于范围决定,而测试改为**从 CLI 定义读出标志清单**而非人工列举——之后新增的标志不需要有人记得就会被覆盖。第四个实例正是那个测试找出来的。
|
|
39
|
+
- **`--apply --skills` 只升级 Skills、安静地把标准留在原地,并报告成功。** 同一条链:`--skills` 在协调器执行之前就 return 了。以此方式升级一个真实项目,结果它停在旧的标准版本,而屏幕上没有任何一行说明。现在 `--apply` 与 `--force` 会执行协调**并且**执行所要求的范围。
|
|
40
|
+
- **没有人能回答的确认提示,返回 exit 0。** 非交互 shell 下 `@inquirer/prompts` 会抛出 `ExitPromptError`,该异常从未被捕获而进程仍以 exit code 0 结束——于是在 CI 里「什么都没写」与「更新成功」返回同一个值。现在它会说明没有任何东西被写入、指向 `--yes`,并以 exit 2 结束。检测方式是**提示真的失败了**,而不是探测 `process.stdin.isTTY`——后者在两个方向上都会答错。
|
|
41
|
+
- **`--rollback` 现在会说明 `--skills`/`--commands` 无法缩小它的范围**,而不是接受它们却照样还原全部。
|
|
42
|
+
|
|
20
43
|
## [6.3.9] - 2026-08-09
|
|
21
44
|
|
|
22
45
|
### 修复
|
|
@@ -14,7 +14,7 @@ status: current
|
|
|
14
14
|
|
|
15
15
|
Universal Development Standards 是一个语言无关、框架无关的文件化标准框架。它提供:
|
|
16
16
|
|
|
17
|
-
- **核心规范** (`core/`):
|
|
17
|
+
- **核心规范** (`core/`):150 个基础开发标准
|
|
18
18
|
- **AI 技能** (`skills/`):用于 AI 辅助开发的 Claude Code 技能
|
|
19
19
|
- **CLI 工具** (`cli/`):用于采用标准的 Node.js CLI
|
|
20
20
|
- **整合** (`integrations/`):各种 AI 工具的配置
|
|
@@ -15,7 +15,7 @@ status: current
|
|
|
15
15
|
|
|
16
16
|
> **语言**: [English](../../README.md) | [繁體中文](../zh-TW/README.md) | 简体中文
|
|
17
17
|
|
|
18
|
-
**版本**: 6.
|
|
18
|
+
**版本**: 6.4.0 | **发布日期**: 2026-08-10 | **授权**: [双重授权](../../LICENSE) (CC BY 4.0 + MIT)
|
|
19
19
|
|
|
20
20
|
语言无关、框架无关的软件项目文档标准。通过 AI 原生工作流,确保不同技术栈之间的一致性、质量和可维护性。
|
|
21
21
|
|
|
@@ -76,10 +76,10 @@ npx universal-dev-standards init
|
|
|
76
76
|
<!-- UDS_STATS_TABLE_START -->
|
|
77
77
|
| 类别 | 数量 | 说明 |
|
|
78
78
|
|----------|-------|-------------|
|
|
79
|
-
| **核心标准** |
|
|
79
|
+
| **核心标准** | 150 | 通用开发准则 |
|
|
80
80
|
| **AI Skills** | 55 | 互动式技能 |
|
|
81
81
|
| **斜线命令** | 51 | 快速操作 |
|
|
82
|
-
| **CLI 命令** |
|
|
82
|
+
| **CLI 命令** | 22 | 项目设置与维护 |
|
|
83
83
|
<!-- UDS_STATS_TABLE_END -->
|
|
84
84
|
|
|
85
85
|
> **5.0 新功能?** 请参阅[预发布说明](../../docs/PRE-RELEASE.md)了解新功能详情。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UDS 速查表
|
|
2
2
|
|
|
3
|
-
> Quick reference for all UDS features | Last updated: 2026-
|
|
3
|
+
> Quick reference for all UDS features | Last updated: 2026-08-10
|
|
4
4
|
|
|
5
5
|
**Language**: [English](../../../docs/user/CHEATSHEET.md) | [繁體中文](../../zh-TW/docs/CHEATSHEET.md) | 简体中文
|
|
6
6
|
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
| `chaos-injection-tests` | Chaos Injection Tests |
|
|
191
191
|
| `checkin-standards` | This standard defines quality gates that MUST be p |
|
|
192
192
|
| `circuit-breaker` | Circuit Breaker Standard |
|
|
193
|
+
| `class-level-fix` | A defect is almost never alone. It is one member o |
|
|
193
194
|
| `code-review-checklist` | This standard provides a comprehensive checklist f |
|
|
194
195
|
| `commit-message-guide` | Standardized commit messages improve code review e |
|
|
195
196
|
| `container-image-standards` | Container Image Build and Security Standards |
|
|
@@ -322,6 +323,7 @@
|
|
|
322
323
|
| `check-ai-agent-sync.ps1` | Check Ai Agent Sync |
|
|
323
324
|
| `check-ai-agent-sync.sh` | AI Agent Sync Checker |
|
|
324
325
|
| `check-ai-behavior-sync.sh` | DEPRECATED: Use 'npx tsx scripts/check-ai-behavior |
|
|
326
|
+
| `check-ai-yaml-parses.mjs` | Every shipped .ai.yaml must parse, and must parse |
|
|
325
327
|
| `check-cli-docs-sync.ps1` | Check Cli Docs Sync |
|
|
326
328
|
| `check-cli-docs-sync.sh` | CLI-to-Documentation Sync Checker |
|
|
327
329
|
| `check-commands-sync.ps1` | Check Commands Sync |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UDS 功能参考手册
|
|
2
2
|
|
|
3
3
|
> Universal Development Standards - 完整功能文档
|
|
4
|
-
> Auto-generated | Last updated: 2026-
|
|
4
|
+
> Auto-generated | Last updated: 2026-08-10
|
|
5
5
|
|
|
6
6
|
**Language**: [English](../../../docs/reference/FEATURE-REFERENCE.md) | [繁體中文](../../zh-TW/docs/FEATURE-REFERENCE.md) | 简体中文
|
|
7
7
|
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
3. [技能](#skills) (55)
|
|
15
15
|
4. [代理](#agents) (5)
|
|
16
16
|
5. [工作流程](#workflows) (5)
|
|
17
|
-
6. [核心规范](#core-standards) (
|
|
18
|
-
7. [脚本](#scripts) (
|
|
17
|
+
6. [核心规范](#core-standards) (150)
|
|
18
|
+
7. [脚本](#scripts) (59)
|
|
19
19
|
|
|
20
|
-
**Total Features:
|
|
20
|
+
**Total Features: 334**
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
| `--skills` | Install/update Skills for configured AI tools |
|
|
108
108
|
| `--commands` | Install/update slash commands for configured AI tools |
|
|
109
109
|
| `--debug` | Show debug output for Skills/Commands detection |
|
|
110
|
-
| `--plan` | Show reconciliation plan without executing (like terraform plan) |
|
|
111
|
-
| `--apply` | Apply exactly the plan --plan prints (plain `uds update` does not) |
|
|
110
|
+
| `--plan` | Show reconciliation plan without executing (like terraform plan); combines with --skills/--commands to plan just that scope, still writing nothing |
|
|
111
|
+
| `--apply` | Apply exactly the plan --plan prints (plain `uds update` does not); with --skills/--commands it does the reconciliation AND that scope, not only the scope |
|
|
112
112
|
| `--force` | Force update all files, ignoring hash comparison |
|
|
113
113
|
| `--rollback` | Rollback to the most recent backup |
|
|
114
114
|
| `--locale` | Override locale for skills install (zh-tw, zh-cn, en); also reads .uds/install.yaml + UDS_LOCALE env |
|
|
@@ -317,6 +317,7 @@
|
|
|
317
317
|
| `chaos-injection-tests` | - | |
|
|
318
318
|
| `checkin-standards` | 1.8.0 | This standard defines quality gates that MUST be passed before committing code t |
|
|
319
319
|
| `circuit-breaker` | - | |
|
|
320
|
+
| `class-level-fix` | 1.0.0 | A defect is almost never alone. It is one member of a set — one flag in a dispat |
|
|
320
321
|
| `code-review-checklist` | 1.4.0 | This standard provides a comprehensive checklist for reviewing code changes, ens |
|
|
321
322
|
| `commit-message-guide` | 1.3.0 | Standardized commit messages improve code review efficiency, facilitate automate |
|
|
322
323
|
| `container-image-standards` | 1.0.0 | **Status**: Active | **Updated**: 2026-06-17 | |
|
|
@@ -417,7 +418,7 @@
|
|
|
417
418
|
| `standard-lifecycle-management` | - | |
|
|
418
419
|
| `structured-task-definition` | 1.0.0 | |
|
|
419
420
|
| `supply-chain-attestation` | - | |
|
|
420
|
-
| `supply-chain-security-standards` | 1.
|
|
421
|
+
| `supply-chain-security-standards` | 1.1.0 | |
|
|
421
422
|
| `systematic-debugging` | 1.0.0 | Define a structured, four-phase debugging workflow that prevents the common anti |
|
|
422
423
|
| `tech-debt-standards` | 1.0.0 | |
|
|
423
424
|
| `test-completeness-dimensions` | 1.1.0 | This document defines a systematic framework for evaluating test completeness. I |
|
|
@@ -451,6 +452,7 @@
|
|
|
451
452
|
| `check-ai-agent-sync.ps1` | Check Ai Agent Sync |
|
|
452
453
|
| `check-ai-agent-sync.sh` | AI Agent Sync Checker |
|
|
453
454
|
| `check-ai-behavior-sync.sh` | DEPRECATED: Use 'npx tsx scripts/check-ai-behavior-sync.ts' instead (cross-platform). |
|
|
455
|
+
| `check-ai-yaml-parses.mjs` | Every shipped .ai.yaml must parse, and must parse into what it says. |
|
|
454
456
|
| `check-cli-docs-sync.ps1` | Check Cli Docs Sync |
|
|
455
457
|
| `check-cli-docs-sync.sh` | CLI-to-Documentation Sync Checker |
|
|
456
458
|
| `check-commands-sync.ps1` | Check Commands Sync |
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: ../../CHANGELOG.md
|
|
3
|
-
source_version: 6.
|
|
4
|
-
translation_version: 6.
|
|
5
|
-
last_synced: 2026-08-
|
|
3
|
+
source_version: 6.4.0
|
|
4
|
+
translation_version: 6.4.0
|
|
5
|
+
last_synced: 2026-08-10
|
|
6
6
|
status: current
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -17,6 +17,29 @@ status: current
|
|
|
17
17
|
|
|
18
18
|
## [Unreleased]
|
|
19
19
|
|
|
20
|
+
## [6.4.0] - 2026-08-10
|
|
21
|
+
|
|
22
|
+
### 新增
|
|
23
|
+
|
|
24
|
+
- **`class-level-fix` 標準——修正瞄準集合,不是瞄準成員。** 一個缺陷幾乎從不孤單:它是分派鏈裡的一個旗標、manifest 裡的一條宣告、`agents/` 底下的一個目錄。修掉被指出的那一員,集合裡其餘的原封不動,**而沒有東西會通知你下一個在哪**——它會在幾個月後以新事故的形式回來,那正是這類工作感覺沒完沒了的原因。規則:修之前先指出缺陷所屬的可窮舉集合,並加上一個**走訪**該集合的檢查。第三個問題決定這道檢查活不活得下去——走訪從哪裡讀出成員?必須是系統自己讀的那個來源(CLI 定義、目錄、manifest),**絕不是誰手打的清單**,因為手打的清單正確到第四個成員出現為止,而不會有東西告訴你。列舉失敗時是靜默的;走訪配排除清單失敗時是吵的,因為那條排除必須由一個人寫下來、而他得說明理由。檢查必須印出分母**與被排除的數量**——「檢查了 4,012 條宣告」讀起來像涵蓋率,而篩選器悄悄跳過了每一條目錄條目。而且它在被信任之前要**逐子集**證明非空跑,因為一道涵蓋五份清單卻只對第一份測過的檢查,是一道涵蓋一份清單的檢查。
|
|
25
|
+
|
|
26
|
+
標準裡每一個實例都是 2026-08-10 量出來的。最有份量的是那個反例:本 repo **十一天前已經為 `--integrations-only` 修過完全相同的缺陷,還留了一段說明通則的註解**,而另外三個分支原封不動。知識就在那個檔案裡,只是沒有到達它的兄弟。**一段描述類別的註解,不等於一道涵蓋類別的檢查。**
|
|
27
|
+
|
|
28
|
+
標準明白寫出**它沒有自動閘門**——沒有東西能走訪「現在正在被修的所有缺陷」——並記下理由、由什麼執行(review,只問一句:*這是哪個集合的一員?*)、以及什麼條件下閘門會變得可能。不寫那一段,它就會變成它所要防止的那件事的下一個實例。
|
|
29
|
+
|
|
30
|
+
### 修正
|
|
31
|
+
|
|
32
|
+
- **`--plan` 與 `--apply` 的組合行為現在也到得了 `--help`。** 6.3.10 記錄該行為的方式是編輯 `docs/reference/FEATURE-REFERENCE.md`——一份**產生的檔案**。那次編輯活到有人重新產生為止。文字現在住在 `cli/bin/uds.js` 的 `.option()` 字串裡,於是它也會出現在 `uds update --help`,而手改的那一份從來不會。
|
|
33
|
+
|
|
34
|
+
## [6.3.10] - 2026-08-10
|
|
35
|
+
|
|
36
|
+
### 修正
|
|
37
|
+
|
|
38
|
+
- **`--plan` 會被另外四個旗標吃掉,而唯一能防止破壞的正是被忽略的那一個。** `uds update --plan --skills` 會安裝 Skills;`--plan --sync-refs` 會改寫整合檔與 manifest。那個文件寫著「Show reconciliation plan without executing (like terraform plan)」的旗標被靜默丟棄——因為範圍旗標(`--skills`、`--commands`、`--integrations-only`、`--sync-refs`)在一條先到先得、每個分支都 return 的鏈裡,排在模式旗標(`--plan`、`--apply`、`--force`、`--rollback`)之前。`--integrations-only` 早在 2026-07-30 就為了同一件事修過;另外三個沒有被碰,十一天後它們仍在寫檔。現在模式先於範圍決定,而測試改為**從 CLI 定義讀出旗標清單**而非人工列舉——之後新增的旗標不需要有人記得就會被涵蓋。第四個實例正是那個測試找出來的。
|
|
39
|
+
- **`--apply --skills` 只升級 Skills、安靜地把標準留在原地,並回報成功。** 同一條鏈:`--skills` 在調和器執行之前就 return 了。以此方式升級一個真實專案,結果它停在舊的標準版本,而畫面上沒有任何一行說明。現在 `--apply` 與 `--force` 會執行調和**並且**執行所要求的範圍。
|
|
40
|
+
- **沒有人能回答的確認提示,回傳 exit 0。** 非互動 shell 下 `@inquirer/prompts` 會擲 `ExitPromptError`,該例外從未被攔截而程序仍以 exit code 0 結束——於是在 CI 裡「什麼都沒寫」與「更新成功」回傳同一個值。現在它會說明沒有任何東西被寫入、指向 `--yes`,並以 exit 2 結束。偵測方式是**提示真的失敗了**,而不是探測 `process.stdin.isTTY`——後者在兩個方向上都會答錯。
|
|
41
|
+
- **`--rollback` 現在會說明 `--skills`/`--commands` 無法縮小它的範圍**,而不是接受它們卻照樣還原全部。
|
|
42
|
+
|
|
20
43
|
## [6.3.9] - 2026-08-09
|
|
21
44
|
|
|
22
45
|
### 修正
|
|
@@ -14,7 +14,7 @@ status: current
|
|
|
14
14
|
|
|
15
15
|
Universal Development Standards 是一個語言無關、框架無關的文件化標準框架。它提供:
|
|
16
16
|
|
|
17
|
-
- **核心規範** (`core/`):
|
|
17
|
+
- **核心規範** (`core/`):150 個基礎開發標準
|
|
18
18
|
- **AI 技能** (`skills/`):用於 AI 輔助開發的 Claude Code 技能
|
|
19
19
|
- **CLI 工具** (`cli/`):用於採用標準的 Node.js CLI
|
|
20
20
|
- **整合** (`integrations/`):各種 AI 工具的配置
|
|
@@ -15,7 +15,7 @@ status: current
|
|
|
15
15
|
|
|
16
16
|
> **語言**: [English](../../README.md) | 繁體中文 | [简体中文](../zh-CN/README.md)
|
|
17
17
|
|
|
18
|
-
**版本**: 6.
|
|
18
|
+
**版本**: 6.4.0 | **發布日期**: 2026-08-10 | **授權**: [雙重授權](../../LICENSE) (CC BY 4.0 + MIT)
|
|
19
19
|
|
|
20
20
|
語言無關、框架無關的軟體專案文件標準。透過 AI 原生工作流,確保不同技術堆疊之間的一致性、品質和可維護性。
|
|
21
21
|
|
|
@@ -76,10 +76,10 @@ npx universal-dev-standards init
|
|
|
76
76
|
<!-- UDS_STATS_TABLE_START -->
|
|
77
77
|
| 類別 | 數量 | 說明 |
|
|
78
78
|
|----------|-------|-------------|
|
|
79
|
-
| **核心標準** |
|
|
79
|
+
| **核心標準** | 150 | 通用開發準則 |
|
|
80
80
|
| **AI Skills** | 55 | 互動式技能 |
|
|
81
81
|
| **斜線命令** | 51 | 快速操作 |
|
|
82
|
-
| **CLI 指令** |
|
|
82
|
+
| **CLI 指令** | 22 | 專案設定與維護 |
|
|
83
83
|
<!-- UDS_STATS_TABLE_END -->
|
|
84
84
|
|
|
85
85
|
> **5.0 新功能?** 請參閱[預發布說明](../../docs/PRE-RELEASE.md)了解新功能詳情。
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
source: ../../../core/class-level-fix.md
|
|
3
|
+
source_version: 1.0.0
|
|
4
|
+
translation_version: 1.0.0
|
|
5
|
+
last_synced: 2026-08-10
|
|
6
|
+
source_hash: 1a2b451bae6d
|
|
7
|
+
status: current
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# 類別層修正標準
|
|
11
|
+
|
|
12
|
+
> **Language**: [English](../../../core/class-level-fix.md) | 繁體中文
|
|
13
|
+
|
|
14
|
+
**版本**: 1.0.0
|
|
15
|
+
**最後更新**: 2026-08-10
|
|
16
|
+
**適用**: 任何缺陷修正(程式碼或設定)
|
|
17
|
+
**範圍**: universal
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 目的
|
|
22
|
+
|
|
23
|
+
一個缺陷幾乎從不孤單。它是某個集合的一員——分派鏈裡的一個旗標、manifest 裡的一條宣告、`agents/` 底下的一個目錄、目錄樹裡的一份設定檔。修掉被指出的那一員,集合裡其餘的原封不動,**而沒有任何東西會通知你下一個在哪**。它會在幾個月後以一則新事故的形式出現,於是工作感覺沒完沒了——因為同一個形狀不斷換名字回來。
|
|
24
|
+
|
|
25
|
+
本標準要求:**修正瞄準集合,不是瞄準成員。**
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 規則
|
|
30
|
+
|
|
31
|
+
**修一個缺陷之前,先指出它所屬的可窮舉集合,並加上一個走訪該集合的檢查。** 若該集合無法被走訪,寫下為什麼。沉默不算答案。
|
|
32
|
+
|
|
33
|
+
### 三個問題,依序回答
|
|
34
|
+
|
|
35
|
+
| # | 問題 |
|
|
36
|
+
|---|---|
|
|
37
|
+
| 1 | 這個缺陷是哪個集合的一員? |
|
|
38
|
+
| 2 | 那個集合能不能被**走訪**而不是被**列舉**? |
|
|
39
|
+
| 3 | 走訪從哪裡讀出成員? |
|
|
40
|
+
|
|
41
|
+
第 3 題決定這道檢查活不活得下去。**走訪必須從系統自己讀的那個來源讀**——CLI 定義、目錄、manifest——**絕不從你手打的清單讀**。手打的清單正確到有人新增第四個成員為止,而不會有東西告訴你。
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 走訪並排除,絕不列舉
|
|
46
|
+
|
|
47
|
+
| | 列舉 | 走訪並排除 |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| 形狀 | `for (const x of ['a','b','c'])` | `for (const x of readAll()) if (!EXCLUDED.has(x))` |
|
|
50
|
+
| 新成員 | 靜默地不被涵蓋 | **預設被涵蓋** |
|
|
51
|
+
| 何時會錯 | 有人新增第四個 | 有人在沒有理由下加了排除 |
|
|
52
|
+
| 失效方式 | 對一部分表面回報綠燈 | 吵——而吵是看得見的 |
|
|
53
|
+
|
|
54
|
+
**不對稱正是重點。** 列舉失敗時是靜默的;排除清單失敗時是吵的,因為那條排除必須由一個人寫下來,而他得說明理由。
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 檢查必須印出被排除的數量
|
|
59
|
+
|
|
60
|
+
只印分母不夠。「檢查了 4,012 條宣告」讀起來像涵蓋率,而篩選器悄悄跳過了每一條目錄條目。
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
✓ 91 entries across 5 lists all resolve # 分母
|
|
64
|
+
(0 excluded) # 以及被排除的
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
見 [verification-evidence](verification-evidence.md)——這是同一族:**輸出的形狀在工具壞掉時與正常時無從分辨**。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 證據要求
|
|
72
|
+
|
|
73
|
+
一道類別層檢查在被信任之前,必須先被證明不是空跑:
|
|
74
|
+
|
|
75
|
+
1. 塞一個違反規則的合成成員。
|
|
76
|
+
2. 確認檢查失敗**且指名該成員**。
|
|
77
|
+
3. 移除後確認檢查回到綠燈。
|
|
78
|
+
|
|
79
|
+
**逐子集做,不要整體做。** 一道涵蓋五份清單、卻只對第一份測過的檢查,是一道涵蓋一份清單的檢查。
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 實例(皆為實測,2026-08-10)
|
|
84
|
+
|
|
85
|
+
### 有效:旗標分派
|
|
86
|
+
|
|
87
|
+
某 CLI 的 `--plan` 旗標(文件寫著「印出計畫但不執行」)在與 `--skills` 併用時被靜默丟棄,因為範圍旗標在一條先到先得的鏈裡排在模式旗標之前。實例層的修法是兩個分支。
|
|
88
|
+
|
|
89
|
+
類別層的修法是一個**從 CLI 定義讀出旗標清單**的測試,排除模式旗標與少數非範圍的旗標,然後斷言 `--plan` 在任何組合下都不寫檔。
|
|
90
|
+
|
|
91
|
+
**它第一次跑起來就找到第四個實例**——`--sync-refs`,那個從來沒有人看過、而且正在一個文件宣稱「不執行」的旗標底下改寫整合檔與 manifest。
|
|
92
|
+
|
|
93
|
+
### 失效:同一個缺陷,十一天前修過一次
|
|
94
|
+
|
|
95
|
+
同一份程式碼**十一天前已經為 `--integrations-only` 修過完全相同的問題,還留了一段註解說明通則**。另外三個分支沒有被碰。**知識就在那個檔案裡,只是沒有到達它的兄弟。**
|
|
96
|
+
|
|
97
|
+
> **一段描述類別的註解,不等於一道涵蓋類別的檢查。** 這正是本標準存在的理由。
|
|
98
|
+
|
|
99
|
+
### 失效:自行列舉範圍的閘門
|
|
100
|
+
|
|
101
|
+
一道解析閘門硬編碼三個目錄而不走訪整棵樹。它回報「423 個檔案全部通過」,而實際出貨面是 287 個檔案,其中十個壞的到達了 registry。
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 集合無法走訪時
|
|
106
|
+
|
|
107
|
+
這是合法的答案,但要寫下來,連同理由與「什麼條件下會改變」。
|
|
108
|
+
|
|
109
|
+
最常見的成因是**成員只能相對於某個基準目錄才知道,而那個基準沒有記在任何機器讀得到的地方**——例如一份 manifest,它的路徑基準只活在讀取它的那支程式裡。對這種宣告做通用掃描,假陽性率高到讓檢查在第一週就被關掉。
|
|
110
|
+
|
|
111
|
+
這時可行的形狀是**逐份清冊**:一種宣告一道檢查,各自知道自己的基準與條目形狀。**說出清冊有幾份,並確認每一份都有檢查。**
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 反模式
|
|
116
|
+
|
|
117
|
+
| 反模式 | 為何失效 |
|
|
118
|
+
|---|---|
|
|
119
|
+
| 修掉被回報的那一員就結案 | 集合沒有變;下一個成員會以新事故的形式抵達 |
|
|
120
|
+
| 寫一段註解說明通則 | 散文不會執行 |
|
|
121
|
+
| 檢查自行列舉它的範圍 | 正確到有人新增第四個成員為止 |
|
|
122
|
+
| 類別層檢查只對一個成員測過 | 證明的是那一個成員,不是那個類別 |
|
|
123
|
+
| `✓ all pass` 而沒有分母 | 掃了全部與什麼都沒掃,輸出一模一樣 |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 本標準沒有自動閘門,而這件事是被記錄下來的,不是被藏起來的
|
|
128
|
+
|
|
129
|
+
套用本標準是「修的當下」所做的判斷。沒有任何檢查能走訪「現在正在被修的所有缺陷」,
|
|
130
|
+
所以依照它自己的規則,誠實的答案是寫下為什麼不能,而不是暗示一個不存在的強制力。
|
|
131
|
+
|
|
132
|
+
**實務上唯一會咬到的地方是 review**(人或 agent):一個只改了集合中某一員、
|
|
133
|
+
而沒有加上涵蓋該集合之檢查的修正,應該被退回並問一句——**這是哪個集合的一員?**
|
|
134
|
+
|
|
135
|
+
**重啟條件**:若某個 repo 取得了「能把『一次缺陷修正落地』看成一個離散事件」的機制
|
|
136
|
+
(有標記的 commit 型別、issue↔commit 連結),檢查就變得可能——斷言這類 commit
|
|
137
|
+
要嘛動到一個走訪集合的測試,要嘛帶著一段寫下來的理由。在那之前,本標準靠閱讀執行。
|
|
138
|
+
|
|
139
|
+
> 記下這件事不是形式。**一份陳述了規則而沒有東西執行它的標準,正是「寫下來的風險
|
|
140
|
+
> 沒有東西在執行」那個形狀**——而一份不承認這一點的標準,比承認的更糟,
|
|
141
|
+
> 因為讀的人會以為有東西在盯。
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 與其他標準的關係
|
|
146
|
+
|
|
147
|
+
- [verification-evidence](verification-evidence.md) — 證據有效性:工具可以靜默失敗,而其輸出與真結果無從分辨。本標準是同一件事套用在**範圍**而非**執行**上。
|
|
148
|
+
- [anti-hallucination](anti-hallucination.md) — 那個防「沒查」;這個防「查了其中一個,卻對全部下結論」。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UDS 速查表
|
|
2
2
|
|
|
3
|
-
> Quick reference for all UDS features | Last updated: 2026-
|
|
3
|
+
> Quick reference for all UDS features | Last updated: 2026-08-10
|
|
4
4
|
|
|
5
5
|
**Language**: [English](../../../docs/user/CHEATSHEET.md) | 繁體中文 | [简体中文](../../zh-CN/docs/CHEATSHEET.md)
|
|
6
6
|
|
|
@@ -190,6 +190,7 @@
|
|
|
190
190
|
| `chaos-injection-tests` | Chaos Injection Tests |
|
|
191
191
|
| `checkin-standards` | This standard defines quality gates that MUST be p |
|
|
192
192
|
| `circuit-breaker` | Circuit Breaker Standard |
|
|
193
|
+
| `class-level-fix` | A defect is almost never alone. It is one member o |
|
|
193
194
|
| `code-review-checklist` | This standard provides a comprehensive checklist f |
|
|
194
195
|
| `commit-message-guide` | Standardized commit messages improve code review e |
|
|
195
196
|
| `container-image-standards` | Container Image Build and Security Standards |
|
|
@@ -322,6 +323,7 @@
|
|
|
322
323
|
| `check-ai-agent-sync.ps1` | Check Ai Agent Sync |
|
|
323
324
|
| `check-ai-agent-sync.sh` | AI Agent Sync Checker |
|
|
324
325
|
| `check-ai-behavior-sync.sh` | DEPRECATED: Use 'npx tsx scripts/check-ai-behavior |
|
|
326
|
+
| `check-ai-yaml-parses.mjs` | Every shipped .ai.yaml must parse, and must parse |
|
|
325
327
|
| `check-cli-docs-sync.ps1` | Check Cli Docs Sync |
|
|
326
328
|
| `check-cli-docs-sync.sh` | CLI-to-Documentation Sync Checker |
|
|
327
329
|
| `check-commands-sync.ps1` | Check Commands Sync |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UDS 功能參考手冊
|
|
2
2
|
|
|
3
3
|
> Universal Development Standards - 完整功能文件
|
|
4
|
-
> Auto-generated | Last updated: 2026-
|
|
4
|
+
> Auto-generated | Last updated: 2026-08-10
|
|
5
5
|
|
|
6
6
|
**Language**: [English](../../../docs/reference/FEATURE-REFERENCE.md) | 繁體中文 | [简体中文](../../zh-CN/docs/FEATURE-REFERENCE.md)
|
|
7
7
|
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
3. [技能](#skills) (55)
|
|
15
15
|
4. [代理](#agents) (5)
|
|
16
16
|
5. [工作流程](#workflows) (5)
|
|
17
|
-
6. [核心規範](#core-standards) (
|
|
18
|
-
7. [腳本](#scripts) (
|
|
17
|
+
6. [核心規範](#core-standards) (150)
|
|
18
|
+
7. [腳本](#scripts) (59)
|
|
19
19
|
|
|
20
|
-
**Total Features:
|
|
20
|
+
**Total Features: 334**
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
| `--skills` | Install/update Skills for configured AI tools |
|
|
108
108
|
| `--commands` | Install/update slash commands for configured AI tools |
|
|
109
109
|
| `--debug` | Show debug output for Skills/Commands detection |
|
|
110
|
-
| `--plan` | Show reconciliation plan without executing (like terraform plan) |
|
|
111
|
-
| `--apply` | Apply exactly the plan --plan prints (plain `uds update` does not) |
|
|
110
|
+
| `--plan` | Show reconciliation plan without executing (like terraform plan); combines with --skills/--commands to plan just that scope, still writing nothing |
|
|
111
|
+
| `--apply` | Apply exactly the plan --plan prints (plain `uds update` does not); with --skills/--commands it does the reconciliation AND that scope, not only the scope |
|
|
112
112
|
| `--force` | Force update all files, ignoring hash comparison |
|
|
113
113
|
| `--rollback` | Rollback to the most recent backup |
|
|
114
114
|
| `--locale` | Override locale for skills install (zh-tw, zh-cn, en); also reads .uds/install.yaml + UDS_LOCALE env |
|
|
@@ -317,6 +317,7 @@
|
|
|
317
317
|
| `chaos-injection-tests` | - | |
|
|
318
318
|
| `checkin-standards` | 1.8.0 | This standard defines quality gates that MUST be passed before committing code t |
|
|
319
319
|
| `circuit-breaker` | - | |
|
|
320
|
+
| `class-level-fix` | 1.0.0 | A defect is almost never alone. It is one member of a set — one flag in a dispat |
|
|
320
321
|
| `code-review-checklist` | 1.4.0 | This standard provides a comprehensive checklist for reviewing code changes, ens |
|
|
321
322
|
| `commit-message-guide` | 1.3.0 | Standardized commit messages improve code review efficiency, facilitate automate |
|
|
322
323
|
| `container-image-standards` | 1.0.0 | **Status**: Active | **Updated**: 2026-06-17 | |
|
|
@@ -417,7 +418,7 @@
|
|
|
417
418
|
| `standard-lifecycle-management` | - | |
|
|
418
419
|
| `structured-task-definition` | 1.0.0 | |
|
|
419
420
|
| `supply-chain-attestation` | - | |
|
|
420
|
-
| `supply-chain-security-standards` | 1.
|
|
421
|
+
| `supply-chain-security-standards` | 1.1.0 | |
|
|
421
422
|
| `systematic-debugging` | 1.0.0 | Define a structured, four-phase debugging workflow that prevents the common anti |
|
|
422
423
|
| `tech-debt-standards` | 1.0.0 | |
|
|
423
424
|
| `test-completeness-dimensions` | 1.1.0 | This document defines a systematic framework for evaluating test completeness. I |
|
|
@@ -451,6 +452,7 @@
|
|
|
451
452
|
| `check-ai-agent-sync.ps1` | Check Ai Agent Sync |
|
|
452
453
|
| `check-ai-agent-sync.sh` | AI Agent Sync Checker |
|
|
453
454
|
| `check-ai-behavior-sync.sh` | DEPRECATED: Use 'npx tsx scripts/check-ai-behavior-sync.ts' instead (cross-platform). |
|
|
455
|
+
| `check-ai-yaml-parses.mjs` | Every shipped .ai.yaml must parse, and must parse into what it says. |
|
|
454
456
|
| `check-cli-docs-sync.ps1` | Check Cli Docs Sync |
|
|
455
457
|
| `check-cli-docs-sync.sh` | CLI-to-Documentation Sync Checker |
|
|
456
458
|
| `check-commands-sync.ps1` | Check Commands Sync |
|
package/package.json
CHANGED
package/src/commands/update.js
CHANGED
|
@@ -334,9 +334,13 @@ export async function updateCommand(options) {
|
|
|
334
334
|
console.log(chalk.bold(msg.title));
|
|
335
335
|
console.log(chalk.gray('─'.repeat(50)));
|
|
336
336
|
|
|
337
|
-
// Handle --sync-refs option
|
|
337
|
+
// Handle --sync-refs option.
|
|
338
|
+
// `--plan` is honoured here too. This branch is above the mode dispatch
|
|
339
|
+
// because sync-refs is its own operation rather than a scope of the
|
|
340
|
+
// reconciler — but "above the dispatch" is exactly how --plan got dropped by
|
|
341
|
+
// three other branches, so it passes the flag down instead of assuming.
|
|
338
342
|
if (options.syncRefs) {
|
|
339
|
-
await syncIntegrationReferences(projectPath, manifest);
|
|
343
|
+
await syncIntegrationReferences(projectPath, manifest, { plan: !!options.plan });
|
|
340
344
|
return;
|
|
341
345
|
}
|
|
342
346
|
|
|
@@ -350,39 +354,68 @@ export async function updateCommand(options) {
|
|
|
350
354
|
return;
|
|
351
355
|
}
|
|
352
356
|
|
|
353
|
-
//
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
//
|
|
357
|
+
// ── Flags come in two axes, and they must not eat each other ──────────
|
|
358
|
+
// // implements XSPEC-372 R1/R2
|
|
359
|
+
//
|
|
360
|
+
// mode : --plan / --apply / --force / --rollback (what to do)
|
|
361
|
+
// scope : --skills / --commands / --integrations-only / --standards-only
|
|
362
|
+
//
|
|
363
|
+
// These used to sit in one first-match-wins if/return chain with the scope
|
|
364
|
+
// flags first. `--plan --skills` therefore *installed* Skills — the flag
|
|
365
|
+
// documented as "without executing" was dropped with nothing said — and
|
|
366
|
+
// `--apply --skills` upgraded Skills while silently leaving the standards
|
|
367
|
+
// behind, reporting success either way. Both measured 2026-08-10 while
|
|
368
|
+
// upgrading four repos to 6.3.9.
|
|
369
|
+
//
|
|
370
|
+
// Mode is now decided first, and scope narrows it instead of replacing it.
|
|
371
|
+
const scopedToSkills = !!options.skills;
|
|
372
|
+
const scopedToCommands = !!options.commands;
|
|
373
|
+
|
|
374
|
+
// Handle --rollback option (DSR). It restores a whole backup, so a scope
|
|
375
|
+
// flag cannot narrow it — say so rather than appearing to honour it.
|
|
366
376
|
if (options.rollback) {
|
|
377
|
+
if (scopedToSkills || scopedToCommands) {
|
|
378
|
+
console.log(chalk.yellow(' ! --rollback restores a complete backup; --skills/--commands cannot narrow it and are ignored.'));
|
|
379
|
+
console.log();
|
|
380
|
+
}
|
|
367
381
|
await handleRollback(projectPath);
|
|
368
382
|
return;
|
|
369
383
|
}
|
|
370
384
|
|
|
371
|
-
// Handle --plan option (DSR dry-run)
|
|
385
|
+
// Handle --plan option (DSR dry-run). Nothing below this line writes.
|
|
372
386
|
if (options.plan) {
|
|
373
|
-
|
|
387
|
+
if (!scopedToSkills && !scopedToCommands) {
|
|
388
|
+
await handlePlan(projectPath, options);
|
|
389
|
+
}
|
|
390
|
+
if (scopedToSkills) await planSkills(projectPath, manifest, options);
|
|
391
|
+
if (scopedToCommands) await planCommands(projectPath, manifest, options);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Handle --apply / --force (DSR reconciliation), composing with scope.
|
|
396
|
+
// A scope flag alone still means "only that scope"; combined with a mode it
|
|
397
|
+
// means "that mode, and also that scope" — the reconciler tracks Skills
|
|
398
|
+
// files only when the manifest records them, so `--skills` is not redundant.
|
|
399
|
+
if (options.apply || options.force) {
|
|
400
|
+
if (!scopedToSkills && !scopedToCommands) {
|
|
401
|
+
await handleReconcile(projectPath, options, { force: !!options.force });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
await handleReconcile(projectPath, options, { force: !!options.force });
|
|
405
|
+
// These exit the process on completion, so run Skills last.
|
|
406
|
+
if (scopedToCommands) await updateCommandsOnly(projectPath, manifest, options);
|
|
407
|
+
if (scopedToSkills) await updateSkillsOnly(projectPath, manifest, options);
|
|
374
408
|
return;
|
|
375
409
|
}
|
|
376
410
|
|
|
377
|
-
//
|
|
378
|
-
if (
|
|
379
|
-
await
|
|
411
|
+
// Scope without a mode: the original shortcuts.
|
|
412
|
+
if (scopedToSkills) {
|
|
413
|
+
await updateSkillsOnly(projectPath, manifest, options);
|
|
380
414
|
return;
|
|
381
415
|
}
|
|
382
416
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
await handleReconcile(projectPath, options, { force: true });
|
|
417
|
+
if (scopedToCommands) {
|
|
418
|
+
await updateCommandsOnly(projectPath, manifest, options);
|
|
386
419
|
return;
|
|
387
420
|
}
|
|
388
421
|
|
|
@@ -494,11 +527,8 @@ export async function updateCommand(options) {
|
|
|
494
527
|
console.log();
|
|
495
528
|
|
|
496
529
|
// Confirm
|
|
497
|
-
|
|
498
|
-
const confirmed = await
|
|
499
|
-
message: msg.confirmUpdate,
|
|
500
|
-
default: true
|
|
501
|
-
});
|
|
530
|
+
{
|
|
531
|
+
const confirmed = await confirmOrFail({ message: msg.confirmUpdate, options });
|
|
502
532
|
|
|
503
533
|
if (!confirmed) {
|
|
504
534
|
console.log(chalk.yellow(msg.updateCancelled));
|
|
@@ -558,10 +588,7 @@ export async function updateCommand(options) {
|
|
|
558
588
|
shouldInstallNew = true;
|
|
559
589
|
} else {
|
|
560
590
|
// Interactive mode: ask user
|
|
561
|
-
const installNew = await
|
|
562
|
-
message: msg.installNewStandards,
|
|
563
|
-
default: true
|
|
564
|
-
});
|
|
591
|
+
const installNew = await confirmOrFail({ message: msg.installNewStandards, options });
|
|
565
592
|
shouldInstallNew = installNew;
|
|
566
593
|
}
|
|
567
594
|
|
|
@@ -886,9 +913,9 @@ export async function updateCommand(options) {
|
|
|
886
913
|
if (options.yes) {
|
|
887
914
|
shouldRestore = true;
|
|
888
915
|
} else {
|
|
889
|
-
const restoreMissing = await
|
|
916
|
+
const restoreMissing = await confirmOrFail({
|
|
890
917
|
message: (msg.restoreMissingPrompt || 'Restore {count} missing file(s)?').replace('{count}', missingFiles.length),
|
|
891
|
-
|
|
918
|
+
options
|
|
892
919
|
});
|
|
893
920
|
shouldRestore = restoreMissing;
|
|
894
921
|
}
|
|
@@ -1440,6 +1467,40 @@ export function regenerateIntegrations(projectPath, manifest) {
|
|
|
1440
1467
|
* @param {string} projectPath - Project path
|
|
1441
1468
|
* @param {Object} manifest - Manifest object
|
|
1442
1469
|
*/
|
|
1470
|
+
/**
|
|
1471
|
+
* Ask for confirmation, or fail loudly when there is nobody to ask.
|
|
1472
|
+
* // implements XSPEC-372 R3
|
|
1473
|
+
*
|
|
1474
|
+
* `@inquirer/prompts` throws `ExitPromptError` when stdin is not a TTY. That
|
|
1475
|
+
* exception was never caught, and the process still ended with **exit code 0**
|
|
1476
|
+
* — so in CI a run that wrote nothing was indistinguishable from a successful
|
|
1477
|
+
* update. Measured 2026-08-10 on `uds update --apply` and reproduced with
|
|
1478
|
+
* `--force --apply`: zero files written, `echo $?` printed 0.
|
|
1479
|
+
*
|
|
1480
|
+
* Not auto-confirming: that would give an unattended environment broader
|
|
1481
|
+
* permission than an interactive one. Exit 2 rather than 1 keeps "could not
|
|
1482
|
+
* run" distinct from "ran and found a problem".
|
|
1483
|
+
*/
|
|
1484
|
+
async function confirmOrFail({ message, defaultValue = true, options }) {
|
|
1485
|
+
if (options?.yes) return true;
|
|
1486
|
+
try {
|
|
1487
|
+
return await inquirerConfirm({ message, default: defaultValue });
|
|
1488
|
+
} catch (err) {
|
|
1489
|
+
// Detect by what the prompt does, not by probing `process.stdin.isTTY`.
|
|
1490
|
+
// isTTY is a proxy for "somebody can answer", and it is wrong in both
|
|
1491
|
+
// directions — a mocked or wrapped stdin answers fine with isTTY unset.
|
|
1492
|
+
// The prompt failing IS the condition; anything else is a guess about it.
|
|
1493
|
+
const closed = err?.name === 'ExitPromptError' || /force closed the prompt/i.test(err?.message || '');
|
|
1494
|
+
if (!closed) throw err;
|
|
1495
|
+
console.log();
|
|
1496
|
+
console.log(chalk.red('Cannot ask for confirmation: there is nothing attached to answer the prompt (non-interactive shell, CI, or a pipe).'));
|
|
1497
|
+
console.log(chalk.gray(` Pending question: ${message}`));
|
|
1498
|
+
console.log(chalk.gray(' Re-run with --yes to confirm up front. Nothing has been written.'));
|
|
1499
|
+
console.log();
|
|
1500
|
+
process.exit(2);
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1443
1504
|
async function updateIntegrationsOnly(projectPath, manifest, options = {}) {
|
|
1444
1505
|
const msg = t().commands.update;
|
|
1445
1506
|
|
|
@@ -1548,7 +1609,7 @@ async function updateIntegrationsOnly(projectPath, manifest, options = {}) {
|
|
|
1548
1609
|
* @param {string} projectPath - Project path
|
|
1549
1610
|
* @param {Object} manifest - Manifest object
|
|
1550
1611
|
*/
|
|
1551
|
-
async function syncIntegrationReferences(projectPath, manifest) {
|
|
1612
|
+
async function syncIntegrationReferences(projectPath, manifest, { plan = false } = {}) {
|
|
1552
1613
|
const msg = t().commands.update;
|
|
1553
1614
|
|
|
1554
1615
|
console.log(chalk.cyan(msg.syncingRefs));
|
|
@@ -1615,6 +1676,12 @@ async function syncIntegrationReferences(projectPath, manifest) {
|
|
|
1615
1676
|
outputLanguage: manifest.options?.output_language || manifest.options?.commit_language || config.outputLanguage || config.commitLanguage || 'english'
|
|
1616
1677
|
};
|
|
1617
1678
|
|
|
1679
|
+
if (plan) {
|
|
1680
|
+
console.log(chalk.yellow(` ~ ${integrationPath}: categories would change to ${expectedCategories.join(', ') || '(none)'} (dry run — nothing is written)`));
|
|
1681
|
+
updatedCount++;
|
|
1682
|
+
continue;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1618
1685
|
const result = writeIntegrationFile(toolName, newConfig, projectPath);
|
|
1619
1686
|
|
|
1620
1687
|
if (result.success) {
|
|
@@ -1657,7 +1724,11 @@ async function syncIntegrationReferences(projectPath, manifest) {
|
|
|
1657
1724
|
if (updatedCount > 0) {
|
|
1658
1725
|
manifest.version = '3.3.0';
|
|
1659
1726
|
refreshIntegrationBlockHashes(manifest, projectPath);
|
|
1660
|
-
|
|
1727
|
+
if (plan) {
|
|
1728
|
+
console.log(chalk.gray(' (dry run — the manifest was not written)'));
|
|
1729
|
+
} else {
|
|
1730
|
+
writeManifest(manifest, projectPath);
|
|
1731
|
+
}
|
|
1661
1732
|
}
|
|
1662
1733
|
|
|
1663
1734
|
// Summary
|
|
@@ -1680,6 +1751,83 @@ async function syncIntegrationReferences(projectPath, manifest) {
|
|
|
1680
1751
|
* @param {Object} manifest - Manifest object
|
|
1681
1752
|
* @param {Object} [options] - CLI options (forwarded for locale resolution)
|
|
1682
1753
|
*/
|
|
1754
|
+
/**
|
|
1755
|
+
* `--plan --skills`: say what a Skills update would do, and write nothing.
|
|
1756
|
+
* // implements XSPEC-372 R1
|
|
1757
|
+
*
|
|
1758
|
+
* Deliberately does not call installSkillsToMultipleAgents and roll back.
|
|
1759
|
+
* "Write then restore" leaves a broken tree if it dies halfway, which is worse
|
|
1760
|
+
* than having no dry run at all — the same reasoning as the integrations plan.
|
|
1761
|
+
*/
|
|
1762
|
+
async function planSkills(projectPath, manifest, options) {
|
|
1763
|
+
const repoInfo = getRepositoryInfo();
|
|
1764
|
+
const latestVersion = repoInfo.skills.version;
|
|
1765
|
+
const installations = (manifest.skills?.installations || []).filter(i => i.level !== 'marketplace');
|
|
1766
|
+
|
|
1767
|
+
console.log(chalk.bold('=== Skills Plan (dry run — nothing is written) ==='));
|
|
1768
|
+
|
|
1769
|
+
if (installations.length === 0) {
|
|
1770
|
+
// Not "up to date". The manifest records no installation, so a Skills
|
|
1771
|
+
// update has nothing to act on — which is a different answer, and the one
|
|
1772
|
+
// that explains why `--skills` appears to do nothing here.
|
|
1773
|
+
console.log(chalk.yellow(' No Skills installations recorded in the manifest — nothing for --skills to update.'));
|
|
1774
|
+
if (manifest.skills?.installed) {
|
|
1775
|
+
console.log(chalk.gray(' (manifest.skills.installed is true but installations[] is empty; run `uds skills` to re-register)'));
|
|
1776
|
+
}
|
|
1777
|
+
console.log();
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
let changed = 0;
|
|
1782
|
+
for (const inst of installations) {
|
|
1783
|
+
const info = getInstalledSkillsInfoForAgent(inst.agent, inst.level, projectPath);
|
|
1784
|
+
const current = info?.version || 'unknown';
|
|
1785
|
+
const dir = getSkillsDirForAgent(inst.agent, inst.level, projectPath);
|
|
1786
|
+
if (current === latestVersion) {
|
|
1787
|
+
console.log(chalk.gray(` = ${getAgentDisplayName(inst.agent)} (${inst.level}): v${current} — unchanged`));
|
|
1788
|
+
} else {
|
|
1789
|
+
changed++;
|
|
1790
|
+
console.log(chalk.yellow(` ~ ${getAgentDisplayName(inst.agent)} (${inst.level}): v${current} → v${latestVersion} ${dir}`));
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
console.log();
|
|
1795
|
+
console.log(`Summary: ${changed} installation(s) would be updated, ${installations.length - changed} unchanged.`);
|
|
1796
|
+
console.log(chalk.gray(` Locale that would be used: ${resolveLocale(manifest, projectPath, options)}`));
|
|
1797
|
+
console.log(chalk.gray(' Run `uds update --apply --yes --skills` to apply.'));
|
|
1798
|
+
console.log();
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1801
|
+
/**
|
|
1802
|
+
* `--plan --commands`: same contract as planSkills.
|
|
1803
|
+
* // implements XSPEC-372 R1
|
|
1804
|
+
*/
|
|
1805
|
+
async function planCommands(projectPath, manifest, options) {
|
|
1806
|
+
const installations = manifest.commands?.installations || [];
|
|
1807
|
+
|
|
1808
|
+
console.log(chalk.bold('=== Commands Plan (dry run — nothing is written) ==='));
|
|
1809
|
+
|
|
1810
|
+
if (installations.length === 0) {
|
|
1811
|
+
console.log(chalk.yellow(' No slash-command installations recorded in the manifest — nothing for --commands to update.'));
|
|
1812
|
+
console.log();
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
for (const inst of installations) {
|
|
1817
|
+
const agent = typeof inst === 'string' ? inst : inst.agent;
|
|
1818
|
+
const level = typeof inst === 'string' ? 'project' : (inst.level || 'project');
|
|
1819
|
+
const info = getInstalledCommandsForAgent(agent, level, projectPath);
|
|
1820
|
+
const dir = getCommandsDirForAgent(agent, level, projectPath);
|
|
1821
|
+
console.log(chalk.yellow(` ~ ${getAgentDisplayName(agent)} (${level}): ${info?.count || 0} command(s) would be reinstalled ${dir}`));
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
console.log();
|
|
1825
|
+
console.log(`Summary: ${installations.length} installation(s) would be reinstalled.`);
|
|
1826
|
+
console.log(chalk.gray(` Locale that would be used: ${resolveLocale(manifest, projectPath, options)}`));
|
|
1827
|
+
console.log(chalk.gray(' Run `uds update --apply --yes --commands` to apply.'));
|
|
1828
|
+
console.log();
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1683
1831
|
async function updateSkillsOnly(projectPath, manifest, options) {
|
|
1684
1832
|
const msg = t().commands.update;
|
|
1685
1833
|
const repoInfo = getRepositoryInfo();
|
|
@@ -2382,10 +2530,10 @@ async function handleReconcile(projectPath, options, { force }) {
|
|
|
2382
2530
|
console.log();
|
|
2383
2531
|
|
|
2384
2532
|
// Confirm unless --yes
|
|
2385
|
-
|
|
2386
|
-
const confirmed = await
|
|
2533
|
+
{
|
|
2534
|
+
const confirmed = await confirmOrFail({
|
|
2387
2535
|
message: `Apply ${planResult.plan.actions.length} changes?`,
|
|
2388
|
-
|
|
2536
|
+
options
|
|
2389
2537
|
});
|
|
2390
2538
|
|
|
2391
2539
|
if (!confirmed) {
|
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.
|
|
3
|
+
"version": "6.4.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.
|
|
61
|
+
"version": "6.4.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.
|
|
68
|
+
"version": "6.4.0",
|
|
69
69
|
"note": "Skills are now included in the main repository under skills/"
|
|
70
70
|
}
|
|
71
71
|
},
|
|
@@ -1742,6 +1742,18 @@
|
|
|
1742
1742
|
"skillName": null,
|
|
1743
1743
|
"description": "Git worktree lifecycle management: setup → baseline → execute → merge → cleanup"
|
|
1744
1744
|
},
|
|
1745
|
+
{
|
|
1746
|
+
"id": "class-level-fix",
|
|
1747
|
+
"name": "Class-Level Fix Standard",
|
|
1748
|
+
"nameZh": "類別層修正標準",
|
|
1749
|
+
"source": {
|
|
1750
|
+
"human": "core/class-level-fix.md",
|
|
1751
|
+
"ai": "ai/standards/class-level-fix.ai.yaml"
|
|
1752
|
+
},
|
|
1753
|
+
"category": "skill",
|
|
1754
|
+
"skillName": null,
|
|
1755
|
+
"description": "Aim a fix at the set, not the member. Walk the set from the source the system reads, never from a typed list; print the denominator and what was excluded; prove the check non-vacuous per sub-set"
|
|
1756
|
+
},
|
|
1745
1757
|
{
|
|
1746
1758
|
"id": "verification-evidence",
|
|
1747
1759
|
"name": "Verification Evidence Standard",
|
|
@@ -2236,7 +2248,7 @@
|
|
|
2236
2248
|
"id": "license-compliance",
|
|
2237
2249
|
"name": "License Compliance Standards",
|
|
2238
2250
|
"nameZh": "授權合規標準",
|
|
2239
|
-
"version": "6.
|
|
2251
|
+
"version": "6.4.0",
|
|
2240
2252
|
"source": {
|
|
2241
2253
|
"human": "core/license-compliance.md",
|
|
2242
2254
|
"ai": "ai/standards/license-compliance.ai.yaml"
|
|
@@ -2248,7 +2260,7 @@
|
|
|
2248
2260
|
"id": "verification-oracle",
|
|
2249
2261
|
"name": "Verification Oracle Standards",
|
|
2250
2262
|
"nameZh": "驗證 Oracle 標準",
|
|
2251
|
-
"version": "6.
|
|
2263
|
+
"version": "6.4.0",
|
|
2252
2264
|
"source": {
|
|
2253
2265
|
"human": "core/verification-oracle.md",
|
|
2254
2266
|
"ai": "ai/standards/verification-oracle.ai.yaml"
|
|
@@ -2260,7 +2272,7 @@
|
|
|
2260
2272
|
"id": "model-provenance",
|
|
2261
2273
|
"name": "Model Provenance Policy Standards",
|
|
2262
2274
|
"nameZh": "模型來源政策標準",
|
|
2263
|
-
"version": "6.
|
|
2275
|
+
"version": "6.4.0",
|
|
2264
2276
|
"source": {
|
|
2265
2277
|
"human": "core/model-provenance.md",
|
|
2266
2278
|
"ai": "ai/standards/model-provenance.ai.yaml"
|
|
@@ -2272,7 +2284,7 @@
|
|
|
2272
2284
|
"id": "resource-cost-boundary",
|
|
2273
2285
|
"name": "Resource / Cost Boundary Declaration Standards",
|
|
2274
2286
|
"nameZh": "資源/成本邊界宣告標準",
|
|
2275
|
-
"version": "6.
|
|
2287
|
+
"version": "6.4.0",
|
|
2276
2288
|
"source": {
|
|
2277
2289
|
"human": "core/resource-cost-boundary.md",
|
|
2278
2290
|
"ai": "ai/standards/resource-cost-boundary.ai.yaml"
|