universal-dev-standards 6.8.0 → 6.10.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.
Files changed (225) hide show
  1. package/bin/uds.js +12 -2
  2. package/bundled/ai/standards/acceptance-criteria-traceability.ai.yaml +14 -2
  3. package/bundled/ai/standards/adr-standards.ai.yaml +14 -2
  4. package/bundled/ai/standards/code-review.ai.yaml +13 -3
  5. package/bundled/ai/standards/commit-message.ai.yaml +8 -4
  6. package/bundled/ai/standards/deferred-item-exit.ai.yaml +225 -0
  7. package/bundled/ai/standards/feature-discovery-standards.ai.yaml +14 -2
  8. package/bundled/ai/standards/governance-layer.ai.yaml +128 -2
  9. package/bundled/ai/standards/logging.ai.yaml +2 -2
  10. package/bundled/ai/standards/retrospective-standards.ai.yaml +14 -2
  11. package/bundled/ai/standards/reverse-engineering-standards.ai.yaml +73 -2
  12. package/bundled/ai/standards/security-standards.ai.yaml +2 -2
  13. package/bundled/ai/standards/spec-driven-development.ai.yaml +14 -2
  14. package/bundled/ai/standards/tech-debt-standards.ai.yaml +87 -3
  15. package/bundled/ai/standards/turn-completion-integrity.ai.yaml +131 -0
  16. package/bundled/core/acceptance-criteria-traceability.md +5 -2
  17. package/bundled/core/adr-standards.md +26 -2
  18. package/bundled/core/agent-communication-protocol.md +8 -0
  19. package/bundled/core/branch-completion.md +8 -0
  20. package/bundled/core/change-batching-standards.md +8 -0
  21. package/bundled/core/code-review-checklist.md +5 -2
  22. package/bundled/core/context-aware-loading.md +1 -1
  23. package/bundled/core/deferred-item-exit.md +254 -0
  24. package/bundled/core/execution-history.md +8 -0
  25. package/bundled/core/feature-discovery-standards.md +5 -1
  26. package/bundled/core/governance-layer.md +114 -2
  27. package/bundled/core/pipeline-integration-standards.md +8 -0
  28. package/bundled/core/retrospective-standards.md +4 -2
  29. package/bundled/core/reverse-engineering-standards.md +81 -2
  30. package/bundled/core/spec-driven-development.md +8 -2
  31. package/bundled/core/tech-debt-standards.md +67 -8
  32. package/bundled/core/turn-completion-integrity.md +196 -0
  33. package/bundled/core/workflow-enforcement.md +8 -0
  34. package/bundled/core/workflow-state-protocol.md +8 -0
  35. package/bundled/hooks/check-dangerous-cmd.mjs +60 -0
  36. package/bundled/hooks/check-logging-standard.mjs +59 -0
  37. package/bundled/hooks/check-turn-completion.mjs +233 -0
  38. package/bundled/hooks/inject-standards.mjs +183 -0
  39. package/bundled/hooks/telemetry-wrapper.mjs +77 -0
  40. package/bundled/hooks/turn-completion/detect.mjs +99 -0
  41. package/bundled/hooks/turn-completion/locales/en.mjs +159 -0
  42. package/bundled/hooks/turn-completion/locales/zh-TW.mjs +166 -0
  43. package/bundled/hooks/validate-commit-msg.mjs +104 -0
  44. package/bundled/locales/zh-CN/CHANGELOG.md +73 -3
  45. package/bundled/locales/zh-CN/CLAUDE.md +1 -1
  46. package/bundled/locales/zh-CN/README.md +2 -2
  47. package/bundled/locales/zh-CN/SECURITY.md +1 -1
  48. package/bundled/locales/zh-CN/core/adr-standards.md +1 -1
  49. package/bundled/locales/zh-CN/core/agent-communication-protocol.md +7 -0
  50. package/bundled/locales/zh-CN/core/branch-completion.md +7 -0
  51. package/bundled/locales/zh-CN/core/change-batching-standards.md +7 -0
  52. package/bundled/locales/zh-CN/core/execution-history.md +7 -0
  53. package/bundled/locales/zh-CN/core/governance-layer.md +118 -6
  54. package/bundled/locales/zh-CN/core/pipeline-integration-standards.md +7 -0
  55. package/bundled/locales/zh-CN/core/retrospective-standards.md +1 -1
  56. package/bundled/locales/zh-CN/core/tech-debt-standards.md +71 -4
  57. package/bundled/locales/zh-CN/core/turn-completion-integrity.md +190 -0
  58. package/bundled/locales/zh-CN/core/workflow-enforcement.md +7 -0
  59. package/bundled/locales/zh-CN/core/workflow-state-protocol.md +7 -0
  60. package/bundled/locales/zh-CN/docs/CHEATSHEET.md +8 -1
  61. package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +29 -68
  62. package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +25 -15
  63. package/bundled/locales/zh-CN/docs/MIGRATION-v6.md +8 -4
  64. package/bundled/locales/zh-CN/docs/USAGE-MODES-COMPARISON.md +1 -2
  65. package/bundled/locales/zh-CN/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  66. package/bundled/locales/zh-CN/integrations/google-antigravity/README.md +3 -3
  67. package/bundled/locales/zh-CN/skills/atdd-assistant/SKILL.md +2 -0
  68. package/bundled/locales/zh-CN/skills/bdd-assistant/SKILL.md +2 -0
  69. package/bundled/locales/zh-CN/skills/brainstorm-assistant/SKILL.md +22 -12
  70. package/bundled/locales/zh-CN/skills/brainstorm-assistant/guide.md +12 -9
  71. package/bundled/locales/zh-CN/skills/code-review-assistant/SKILL.md +1 -0
  72. package/bundled/locales/zh-CN/skills/commands/brainstorm.md +17 -13
  73. package/bundled/locales/zh-CN/skills/commands/config.md +0 -1
  74. package/bundled/locales/zh-CN/skills/commands/init.md +1 -2
  75. package/bundled/locales/zh-CN/skills/commit-standards/SKILL.md +2 -0
  76. package/bundled/locales/zh-CN/skills/contract-test-assistant/SKILL.md +1 -0
  77. package/bundled/locales/zh-CN/skills/dev-methodology/SKILL.md +2 -0
  78. package/bundled/locales/zh-CN/skills/observability-assistant/SKILL.md +1 -0
  79. package/bundled/locales/zh-CN/skills/project-structure-guide/SKILL.md +1 -0
  80. package/bundled/locales/zh-CN/skills/release-standards/SKILL.md +3 -0
  81. package/bundled/locales/zh-CN/skills/requirement-assistant/SKILL.md +2 -0
  82. package/bundled/locales/zh-CN/skills/reverse-engineer/SKILL.md +3 -0
  83. package/bundled/locales/zh-CN/skills/runbook-assistant/SKILL.md +1 -0
  84. package/bundled/locales/zh-CN/skills/slo-assistant/SKILL.md +1 -0
  85. package/bundled/locales/zh-CN/skills/tdd-assistant/SKILL.md +2 -0
  86. package/bundled/locales/zh-TW/CHANGELOG.md +74 -3
  87. package/bundled/locales/zh-TW/CLAUDE.md +1 -1
  88. package/bundled/locales/zh-TW/README.md +2 -2
  89. package/bundled/locales/zh-TW/SECURITY.md +1 -1
  90. package/bundled/locales/zh-TW/core/acceptance-criteria-traceability.md +2 -0
  91. package/bundled/locales/zh-TW/core/adr-standards.md +26 -5
  92. package/bundled/locales/zh-TW/core/agent-communication-protocol.md +7 -0
  93. package/bundled/locales/zh-TW/core/branch-completion.md +7 -0
  94. package/bundled/locales/zh-TW/core/change-batching-standards.md +7 -0
  95. package/bundled/locales/zh-TW/core/code-review-checklist.md +2 -0
  96. package/bundled/locales/zh-TW/core/container-image-standards.md +2 -2
  97. package/bundled/locales/zh-TW/core/contract-testing-standards.md +2 -2
  98. package/bundled/locales/zh-TW/core/cross-flow-regression.md +8 -7
  99. package/bundled/locales/zh-TW/core/data-contract.md +2 -2
  100. package/bundled/locales/zh-TW/core/data-migration-testing.md +2 -2
  101. package/bundled/locales/zh-TW/core/data-pipeline.md +2 -2
  102. package/bundled/locales/zh-TW/core/deferred-item-exit.md +251 -0
  103. package/bundled/locales/zh-TW/core/documentation-writing-standards.md +228 -3
  104. package/bundled/locales/zh-TW/core/execution-history.md +7 -0
  105. package/bundled/locales/zh-TW/core/full-coverage-testing.md +15 -2
  106. package/bundled/locales/zh-TW/core/governance-layer.md +118 -5
  107. package/bundled/locales/zh-TW/core/iac-design-principles.md +2 -2
  108. package/bundled/locales/zh-TW/core/incident-response.md +2 -2
  109. package/bundled/locales/zh-TW/core/model-provenance.md +4 -2
  110. package/bundled/locales/zh-TW/core/pii-classification.md +42 -6
  111. package/bundled/locales/zh-TW/core/pipeline-integration-standards.md +7 -0
  112. package/bundled/locales/zh-TW/core/prd-standards.md +4 -2
  113. package/bundled/locales/zh-TW/core/product-metrics-standards.md +4 -2
  114. package/bundled/locales/zh-TW/core/release-readiness-gate.md +2 -2
  115. package/bundled/locales/zh-TW/core/resource-cost-boundary.md +2 -2
  116. package/bundled/locales/zh-TW/core/retrospective-standards.md +5 -3
  117. package/bundled/locales/zh-TW/core/reverse-engineering-standards.md +83 -5
  118. package/bundled/locales/zh-TW/core/runbook.md +2 -2
  119. package/bundled/locales/zh-TW/core/schema-evolution.md +2 -2
  120. package/bundled/locales/zh-TW/core/secret-management-standards.md +2 -2
  121. package/bundled/locales/zh-TW/core/slo-sli.md +2 -2
  122. package/bundled/locales/zh-TW/core/spec-driven-development.md +2 -0
  123. package/bundled/locales/zh-TW/core/tech-debt-standards.md +71 -4
  124. package/bundled/locales/zh-TW/core/turn-completion-integrity.md +190 -0
  125. package/bundled/locales/zh-TW/core/user-journey-testing.md +2 -2
  126. package/bundled/locales/zh-TW/core/user-story-mapping.md +2 -2
  127. package/bundled/locales/zh-TW/core/verification-oracle.md +2 -2
  128. package/bundled/locales/zh-TW/core/workflow-enforcement.md +7 -0
  129. package/bundled/locales/zh-TW/core/workflow-state-protocol.md +7 -0
  130. package/bundled/locales/zh-TW/docs/CHEATSHEET.md +8 -1
  131. package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +29 -68
  132. package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +25 -15
  133. package/bundled/locales/zh-TW/docs/MIGRATION-v6.md +8 -4
  134. package/bundled/locales/zh-TW/docs/USAGE-MODES-COMPARISON.md +1 -2
  135. package/bundled/locales/zh-TW/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
  136. package/bundled/locales/zh-TW/integrations/google-antigravity/README.md +3 -3
  137. package/bundled/locales/zh-TW/skills/adr-assistant/SKILL.md +1 -1
  138. package/bundled/locales/zh-TW/skills/atdd-assistant/SKILL.md +2 -0
  139. package/bundled/locales/zh-TW/skills/bdd-assistant/SKILL.md +2 -0
  140. package/bundled/locales/zh-TW/skills/brainstorm-assistant/SKILL.md +22 -12
  141. package/bundled/locales/zh-TW/skills/brainstorm-assistant/guide.md +12 -9
  142. package/bundled/locales/zh-TW/skills/code-review-assistant/SKILL.md +1 -0
  143. package/bundled/locales/zh-TW/skills/commands/brainstorm.md +17 -13
  144. package/bundled/locales/zh-TW/skills/commands/config.md +0 -1
  145. package/bundled/locales/zh-TW/skills/commands/init.md +1 -2
  146. package/bundled/locales/zh-TW/skills/commit-standards/SKILL.md +2 -0
  147. package/bundled/locales/zh-TW/skills/contract-test-assistant/SKILL.md +2 -1
  148. package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +2 -0
  149. package/bundled/locales/zh-TW/skills/dev-workflow-guide/SKILL.md +1 -1
  150. package/bundled/locales/zh-TW/skills/knowledge-graph/guide.md +2 -2
  151. package/bundled/locales/zh-TW/skills/migration-assistant/SKILL.md +1 -1
  152. package/bundled/locales/zh-TW/skills/observability-assistant/SKILL.md +1 -0
  153. package/bundled/locales/zh-TW/skills/project-discovery/SKILL.md +1 -0
  154. package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +1 -0
  155. package/bundled/locales/zh-TW/skills/release-standards/SKILL.md +3 -0
  156. package/bundled/locales/zh-TW/skills/requirement-assistant/SKILL.md +2 -0
  157. package/bundled/locales/zh-TW/skills/reverse-engineer/SKILL.md +3 -0
  158. package/bundled/locales/zh-TW/skills/runbook-assistant/SKILL.md +1 -0
  159. package/bundled/locales/zh-TW/skills/slo-assistant/SKILL.md +1 -0
  160. package/bundled/locales/zh-TW/skills/tdd-assistant/SKILL.md +2 -0
  161. package/bundled/skills/atdd-assistant/SKILL.md +2 -0
  162. package/bundled/skills/bdd-assistant/SKILL.md +2 -0
  163. package/bundled/skills/brainstorm-assistant/SKILL.md +31 -13
  164. package/bundled/skills/brainstorm-assistant/guide.md +9 -6
  165. package/bundled/skills/code-review-assistant/SKILL.md +1 -0
  166. package/bundled/skills/commands/brainstorm.md +12 -9
  167. package/bundled/skills/commands/config.md +0 -1
  168. package/bundled/skills/commands/init.md +2 -3
  169. package/bundled/skills/commit-standards/SKILL.md +2 -0
  170. package/bundled/skills/contract-test-assistant/SKILL.md +1 -0
  171. package/bundled/skills/dev-methodology/SKILL.md +4 -0
  172. package/bundled/skills/observability-assistant/SKILL.md +1 -0
  173. package/bundled/skills/project-discovery/SKILL.md +1 -0
  174. package/bundled/skills/project-structure-guide/SKILL.md +1 -0
  175. package/bundled/skills/release-standards/SKILL.md +3 -0
  176. package/bundled/skills/requirement-assistant/SKILL.md +2 -0
  177. package/bundled/skills/reverse-engineer/SKILL.md +3 -0
  178. package/bundled/skills/runbook-assistant/SKILL.md +1 -0
  179. package/bundled/skills/slo-assistant/SKILL.md +1 -0
  180. package/bundled/skills/tdd-assistant/SKILL.md +2 -0
  181. package/bundled/templates/.ai-context.yaml.template +194 -0
  182. package/bundled/templates/CLAUDE.md.template +145 -0
  183. package/bundled/templates/DESIGN.md +237 -0
  184. package/bundled/templates/SKILL-BRIEF-TEMPLATE.md +57 -0
  185. package/bundled/templates/SKILL-CANDIDATES.md +39 -0
  186. package/bundled/templates/gates/check-error-exit.mjs +309 -0
  187. package/bundled/templates/mcp-config.json +10 -0
  188. package/bundled/templates/methodology-template.yaml +209 -0
  189. package/bundled/templates/migration-template.md +408 -0
  190. package/bundled/templates/requirement-checklist.md +410 -0
  191. package/bundled/templates/requirement-document-template.md +591 -0
  192. package/bundled/templates/requirement-template.md +881 -0
  193. package/bundled/templates/reverse-spec-template.md +409 -0
  194. package/bundled/templates/test-case-template.md +74 -0
  195. package/bundled/templates/test-plan-template.md +74 -0
  196. package/package.json +12 -9
  197. package/src/commands/audit.js +82 -0
  198. package/src/commands/check.js +227 -34
  199. package/src/commands/config.js +19 -19
  200. package/src/commands/init.js +174 -20
  201. package/src/commands/spec.js +2 -2
  202. package/src/commands/update.js +537 -43
  203. package/src/compilers/claude-code-compiler.js +4 -1
  204. package/src/config/ai-agent-paths.js +62 -17
  205. package/src/core/constants.js +42 -11
  206. package/src/core/manifest.js +201 -3
  207. package/src/core/paths.js +2 -2
  208. package/src/i18n/messages.js +42 -29
  209. package/src/installers/hooks-installer.js +167 -75
  210. package/src/installers/integration-installer.js +13 -9
  211. package/src/installers/skills-installer.js +4 -4
  212. package/src/installers/standards-installer.js +3 -3
  213. package/src/prompts/init.js +47 -18
  214. package/src/reconciler/diff-engine.js +57 -2
  215. package/src/reconciler/plan-executor.js +31 -11
  216. package/src/utils/detector.js +21 -1
  217. package/src/utils/effect-boundary.js +1093 -0
  218. package/src/utils/hasher.js +166 -1
  219. package/src/utils/hook-stats.js +1 -1
  220. package/src/utils/integration-generator.js +288 -82
  221. package/src/utils/reference-sync.js +107 -8
  222. package/src/utils/registry.js +57 -0
  223. package/src/utils/spinner.js +31 -0
  224. package/src/utils/yaml-generator.js +51 -9
  225. package/standards-registry.json +32 -9
@@ -1,3 +1,6 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+
1
4
  /**
2
5
  * Reference Sync Utilities
3
6
  *
@@ -109,6 +112,56 @@ export function parseReferences(content) {
109
112
  return Array.from(references);
110
113
  }
111
114
 
115
+ /**
116
+ * Every `.standards/…` or `core/…` path mentioned anywhere in the file that is
117
+ * not on disk.
118
+ *
119
+ * `parseReferences` only reads `Reference:`/`參考:` lines, which is the right
120
+ * scope for reference *sync* — those lines are the ones UDS generates and owns.
121
+ * It is the wrong scope for "does this instruction point at anything": an older
122
+ * `uds init` left prose outside the marker block saying "優先讀取 core/ 中的精簡
123
+ * 規則(例如 core/testing-standards.md)", and on a `format: ai` project no
124
+ * `core/` directory is ever installed. An AI tool following that finds nothing,
125
+ * and nothing in the toolchain looked. Reported 2026-09-16.
126
+ *
127
+ * Existence-based, not shape-based, and deliberately so: a project that has its
128
+ * own `core/` directory is not doing anything wrong, and a rule about the shape
129
+ * of the path could not tell the two apart.
130
+ *
131
+ * @param {string} content - File content
132
+ * @param {string|null} projectPath - Project root; without it there is nothing
133
+ * to check against and the answer is "nothing", not a guess
134
+ * @returns {string[]} Distinct paths that do not resolve, in first-seen order
135
+ */
136
+ export function findBrokenPathMentions(content, projectPath) {
137
+ if (!projectPath || typeof content !== 'string') return [];
138
+
139
+ // Not preceded by `/` or a word character: that is what keeps
140
+ // `https://…/core/testing-standards.md` out of the results.
141
+ //
142
+ // The terminator class carries the full-width punctuation as well as the
143
+ // ASCII. These instructions are written in Chinese, and `(例如
144
+ // core/testing-standards.md)` ends in `)` — without it the path captured is
145
+ // `core/testing-standards.md)`, which exists nowhere and matches nothing, so
146
+ // the finding would be real and the path in it wrong.
147
+ const pattern = /(^|[^\w/\\])((?:\.standards|core)\/[^\s\n)\]`,;'")】」』〉》,。、;:!?]+)/g;
148
+ const seen = new Set();
149
+ const broken = [];
150
+
151
+ for (const match of content.matchAll(pattern)) {
152
+ const cleaned = match[2].replace(/[.,;:!?、,。]+$/, '');
153
+ if (!cleaned || seen.has(cleaned)) continue;
154
+ seen.add(cleaned);
155
+ try {
156
+ if (!existsSync(join(projectPath, cleaned))) broken.push(cleaned);
157
+ } catch {
158
+ // An unreadable path is not evidence of a broken reference.
159
+ }
160
+ }
161
+
162
+ return broken;
163
+ }
164
+
112
165
  /**
113
166
  * Get standard source paths for a category
114
167
  *
@@ -176,7 +229,27 @@ function categoryForStandard(pathOrName) {
176
229
  * - missingRefs: Standards in manifest but not referenced in integration file
177
230
  * - syncedRefs: Standards that are properly synced
178
231
  */
179
- export function compareStandardsWithReferences(manifestStandards, integrationReferences) {
232
+ export function compareStandardsWithReferences(manifestStandards, integrationReferences, context = {}) {
233
+ const { projectPath = null, options = {} } = context;
234
+
235
+ // 🔴 Existence is a separate question from adoption, and only one of the two
236
+ // was ever asked. `.standards/anti-hallucination.md` passed as "synced"
237
+ // because the manifest adopts `anti-hallucination` — while the project holds
238
+ // `anti-hallucination.ai.yaml` and the `.md` file is not on disk at all
239
+ // (reproduced on 6.9.0, 2026-09-16). An adopter's AI tool follows that link
240
+ // and finds nothing. Without a projectPath there is no disk to ask, so the
241
+ // list stays empty rather than guessing.
242
+ const danglingRefs = projectPath
243
+ ? integrationReferences.filter(ref => !existsSync(join(projectPath, '.standards', ref)))
244
+ : [];
245
+
246
+ // Options are adopted in `manifest.options`, not `manifest.standards`, so
247
+ // every `.standards/options/...` reference was reported as "not in manifest".
248
+ const optionStems = new Set(
249
+ Object.values(options || {})
250
+ .filter(v => typeof v === 'string')
251
+ .map(v => standardStem(v))
252
+ );
180
253
  // The manifest is the source of truth for what this project adopted, so ask
181
254
  // it directly. The category map below is a hand-written table covering a
182
255
  // small fraction of the standards UDS ships (compare its size against
@@ -207,6 +280,10 @@ export function compareStandardsWithReferences(manifestStandards, integrationRef
207
280
  // stem (extension- and directory-insensitive) or by legacy category name.
208
281
  const orphanedRefs = integrationReferences.filter(ref => {
209
282
  if (manifestStems.has(standardStem(ref))) return false;
283
+ if (optionStems.has(standardStem(ref))) return false;
284
+ // An option file that is on disk is adopted by definition — it got there
285
+ // because this project selected it.
286
+ if (ref.startsWith('options/') && projectPath && existsSync(join(projectPath, '.standards', ref))) return false;
210
287
  const category = categoryForStandard(ref);
211
288
  return !category || !manifestCategories.has(category);
212
289
  });
@@ -221,15 +298,34 @@ export function compareStandardsWithReferences(manifestStandards, integrationRef
221
298
  }
222
299
  const missingCategories = [...manifestCategories].filter(cat => !refCategories.has(cat));
223
300
  // Convert missing categories back to representative filenames for reporting
224
- const missingRefs = missingCategories.flatMap(cat => {
225
- const paths = CATEGORY_TO_STANDARDS[cat] || [];
226
- return paths.map(p => p.split('/').pop());
227
- });
301
+ // 🔴 `CATEGORY_TO_STANDARDS` is a hand-written table of pre-6.0.0 filenames,
302
+ // so this list named files UDS has not shipped for two majors
303
+ // (`git-workflow.md`, `error-code-standards.md`, `project-structure.md`).
304
+ // Report only what this project actually holds. With no projectPath there is
305
+ // no disk to ask, so the legacy names stand — callers that pass one get the
306
+ // filtered list.
307
+ const missingRefs = !projectPath
308
+ ? missingCategories.flatMap(cat => (CATEGORY_TO_STANDARDS[cat] || []).map(p => p.split('/').pop()))
309
+ : missingCategories.flatMap(cat => {
310
+ const paths = CATEGORY_TO_STANDARDS[cat] || [];
311
+ return paths
312
+ .map(p => p.split('/').pop())
313
+ .map(name => {
314
+ const stem = standardStem(name);
315
+ for (const candidate of [`${stem}.ai.yaml`, `${stem}.md`]) {
316
+ if (existsSync(join(projectPath, '.standards', candidate))) return candidate;
317
+ }
318
+ return null;
319
+ })
320
+ .filter(Boolean);
321
+ });
228
322
 
229
323
  // Properly synced references
230
- const syncedRefs = integrationReferences.filter(ref => !orphanedRefs.includes(ref));
324
+ const syncedRefs = integrationReferences.filter(
325
+ ref => !orphanedRefs.includes(ref) && !danglingRefs.includes(ref)
326
+ );
231
327
 
232
- return { orphanedRefs, missingRefs, syncedRefs };
328
+ return { orphanedRefs, missingRefs, syncedRefs, danglingRefs };
233
329
  }
234
330
 
235
331
  /**
@@ -296,7 +392,10 @@ export function getToolFromPath(integrationPath) {
296
392
  '.windsurfrules': 'windsurf',
297
393
  '.clinerules': 'cline',
298
394
  '.github/copilot-instructions.md': 'copilot',
299
- 'INSTRUCTIONS.md': 'antigravity',
395
+ // Antigravity never read INSTRUCTIONS.md.
396
+ // Measured 2026-09-08 with two positive controls in the same run: tokens planted in `AGENTS.md` and `.agents/AGENTS.md` both came back with correct attribution; the one in INSTRUCTIONS.md did not.
397
+ // `.agents/AGENTS.md` is used rather than the repo root so it does not collide with Codex/OpenCode, which both target root AGENTS.md.
398
+ '.agents/AGENTS.md': 'antigravity',
300
399
  'CLAUDE.md': 'claude-code',
301
400
  '.standards/CLAUDE.md': 'claude-code',
302
401
  'AGENTS.md': 'codex'
@@ -320,3 +320,60 @@ export function resolveStandardFilename(entry, format = 'ai') {
320
320
  const parts = source.split(/[/\\]/);
321
321
  return parts[parts.length - 1] || null;
322
322
  }
323
+
324
+ /**
325
+ * Every filename UDS can install under `.standards/`, in either format.
326
+ *
327
+ * Built by walking the registry: each standard's own source plus every option
328
+ * choice's source, `ai` and `human` alike. Spanning both formats is deliberate
329
+ * and is why this takes no format argument — a project can hold a file in a
330
+ * format it did not install (an upgrade that changed `format`, a hand-copied
331
+ * file), and calling that "no longer shipped" would be wrong in the opposite
332
+ * direction. The question here is only ever "is this name still ours".
333
+ *
334
+ * This exists so that question has one answer, derived from the registry rather
335
+ * than from the manifest. A manifest that was never cleaned and one that was
336
+ * must not disagree about it.
337
+ *
338
+ * @returns {Set<string>} Filenames (basenames, no directory)
339
+ */
340
+ let shippableCache = null;
341
+ export function getShippableFilenames() {
342
+ if (shippableCache) return shippableCache;
343
+
344
+ const out = new Set();
345
+ const addPath = (value) => {
346
+ if (typeof value !== 'string' || value.length === 0) return;
347
+ const parts = value.split(/[/\\]/);
348
+ const name = parts[parts.length - 1];
349
+ if (name) out.add(name);
350
+ };
351
+ const addSource = (source) => {
352
+ if (!source) return;
353
+ if (typeof source === 'string') {
354
+ addPath(source);
355
+ return;
356
+ }
357
+ for (const value of Object.values(source)) addPath(value);
358
+ };
359
+
360
+ for (const std of getAllStandards()) {
361
+ addSource(std.source);
362
+ for (const category of Object.values(std.options || {})) {
363
+ for (const choice of category.choices || []) addSource(choice.source);
364
+ }
365
+ }
366
+
367
+ shippableCache = out;
368
+ return out;
369
+ }
370
+
371
+ /**
372
+ * Does UDS still ship a file by this name, in either format?
373
+ * @param {string} filename - Basename, e.g. `anti-hallucination.ai.yaml`
374
+ * @returns {boolean}
375
+ */
376
+ export function isShippedFilename(filename) {
377
+ if (typeof filename !== 'string' || filename.length === 0) return false;
378
+ return getShippableFilenames().has(filename);
379
+ }
@@ -0,0 +1,31 @@
1
+ import ora from 'ora';
2
+
3
+ /**
4
+ * A spinner that reports on stdout.
5
+ *
6
+ * ora defaults to stderr. For a spinner that redraws over itself while a pipe
7
+ * consumes stdout, that default is right. It is wrong for this CLI: these lines
8
+ * are progress reporting for a human, they sit between lines the CLI already
9
+ * prints on stdout, and in a non-TTY ora emits each one exactly once, so there
10
+ * is nothing to redraw and nothing to isolate.
11
+ *
12
+ * On Windows PowerShell 5.1 the default is worse than untidy. Any stderr output
13
+ * from a native command is wrapped in a `NativeCommandError`, so a successful
14
+ * `uds update` surfaced as an error — including the line that said it had
15
+ * succeeded. Measured on a clean run before this change: 9 lines on stdout, 2 on
16
+ * stderr, both of them the spinner, one of them `✔ 已重新產生 2 個整合檔案`.
17
+ *
18
+ * A caller that genuinely wants stderr can still ask for it; the default is the
19
+ * only thing that changes.
20
+ *
21
+ * @param {string|Object} options - Spinner text, or an ora options object
22
+ * @returns {import('ora').Ora}
23
+ */
24
+ export function createSpinner(options) {
25
+ if (typeof options === 'string') {
26
+ return ora({ text: options, stream: process.stdout });
27
+ }
28
+ return ora({ stream: process.stdout, ...options });
29
+ }
30
+
31
+ export default createSpinner;
@@ -4,8 +4,44 @@
4
4
  * Generates AI-optimized YAML from parsed Markdown structure.
5
5
  */
6
6
 
7
+ import { execFileSync } from 'node:child_process';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { dirname, resolve } from 'node:path';
10
+
7
11
  import { SECTION_MAPPINGS, STANDARD_ID_MAPPING } from './conversion-rules.js';
8
12
 
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+ // cli/src/utils/yaml-generator.js -> cli/src/utils -> cli/src -> cli -> repo root
16
+ const REPO_ROOT = resolve(__dirname, '../../..');
17
+
18
+ /**
19
+ * XSPEC-392 R2: `meta.updated` must reflect when the source file's content
20
+ * actually last changed, not a hand-typed `**Last Updated**` line (which can
21
+ * go stale relative to the file it lives in), and — this is the part that is
22
+ * not negotiable — never a `new Date()` value standing in for "the day this
23
+ * script happened to run".
24
+ *
25
+ * Returns an ISO date (YYYY-MM-DD) from git history for `relativeSourcePath`,
26
+ * or `null` when git has no record for it (untracked/new file, git missing,
27
+ * or any other failure). A missing `updated` field is honest; a fabricated
28
+ * one is not — so callers must omit the field entirely rather than fall back
29
+ * to any other date source.
30
+ */
31
+ function getGitLastModifiedDate(relativeSourcePath) {
32
+ if (!relativeSourcePath) return null;
33
+ try {
34
+ const out = execFileSync(
35
+ 'git',
36
+ ['log', '-1', '--format=%ad', '--date=short', '--', relativeSourcePath],
37
+ { cwd: REPO_ROOT, encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }
38
+ ).trim();
39
+ return out || null;
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
9
45
  /**
10
46
  * Generate AI-YAML structure from parsed Markdown
11
47
  * @param {Object} parsed - Parsed Markdown structure from md-parser
@@ -18,16 +54,22 @@ export function generateAiYaml(parsed, options = {}) {
18
54
  // Generate ID
19
55
  const id = generateStandardId(filename, parsed.metadata.title);
20
56
 
21
- // Build YAML structure
22
- const yaml = {
23
- id,
24
- meta: {
25
- version: parsed.metadata.version || '1.0.0',
26
- updated: parsed.metadata.updated || new Date().toISOString().split('T')[0],
27
- source: inferSourcePath(filename, locale),
28
- description: parsed.purpose || parsed.metadata.title || ''
29
- }
57
+ const sourcePath = inferSourcePath(filename, locale);
58
+
59
+ // Build YAML structure. `updated` is set from git history below, and is
60
+ // deliberately absent (not null) when git has no record for the file —
61
+ // see getGitLastModifiedDate.
62
+ const meta = {
63
+ version: parsed.metadata.version || '1.0.0'
30
64
  };
65
+ const gitUpdated = getGitLastModifiedDate(sourcePath);
66
+ if (gitUpdated) {
67
+ meta.updated = gitUpdated;
68
+ }
69
+ meta.source = sourcePath;
70
+ meta.description = parsed.purpose || parsed.metadata.title || '';
71
+
72
+ const yaml = { id, meta };
31
73
 
32
74
  // Add language if locale specified
33
75
  if (locale) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "6.8.0",
3
+ "version": "6.10.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.8.0"
61
+ "version": "6.10.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.8.0",
68
+ "version": "6.10.0",
69
69
  "note": "Skills are now included in the main repository under skills/"
70
70
  }
71
71
  },
@@ -736,6 +736,17 @@
736
736
  "category": "core",
737
737
  "description": "Four behavioral disciplines for AI agents: Ask (surface assumptions), Simple (minimum code), Precision (scope only what's needed), Test (loop until verified)"
738
738
  },
739
+ {
740
+ "id": "turn-completion-integrity",
741
+ "name": "Turn Completion Integrity",
742
+ "nameZh": "回合收尾完整性標準",
743
+ "source": {
744
+ "human": "core/turn-completion-integrity.md",
745
+ "ai": "ai/standards/turn-completion-integrity.ai.yaml"
746
+ },
747
+ "category": "core",
748
+ "description": "An agent must not end a turn having stated a next action it did not take; enforced at turn end by a Stop hook, with a per-language corpus that runs in CI"
749
+ },
739
750
  {
740
751
  "id": "ai-friendly-architecture",
741
752
  "name": "AI-Friendly Architecture",
@@ -1080,7 +1091,7 @@
1080
1091
  "name": "Full Coverage Testing Standards",
1081
1092
  "nameZh": "全覆蓋測試標準",
1082
1093
  "source": {
1083
- "human": "core/testing-standards.md",
1094
+ "human": "core/full-coverage-testing.md",
1084
1095
  "ai": "ai/standards/full-coverage-testing.ai.yaml"
1085
1096
  },
1086
1097
  "category": "skill",
@@ -1569,7 +1580,7 @@
1569
1580
  "id": "antigravity-integration",
1570
1581
  "name": "Google Antigravity Instructions",
1571
1582
  "nameZh": "Google Antigravity 指令",
1572
- "source": "integrations/google-antigravity/INSTRUCTIONS.md",
1583
+ "source": "integrations/google-antigravity/AGENTS.md",
1573
1584
  "category": "integration",
1574
1585
  "skillName": null,
1575
1586
  "description": "System prompt snippets for Google Antigravity agent",
@@ -1766,6 +1777,18 @@
1766
1777
  "skillName": null,
1767
1778
  "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"
1768
1779
  },
1780
+ {
1781
+ "id": "deferred-item-exit",
1782
+ "name": "Deferred Item Exit Standard",
1783
+ "nameZh": "延後項目出口標準",
1784
+ "source": {
1785
+ "human": "core/deferred-item-exit.md",
1786
+ "ai": "ai/standards/deferred-item-exit.ai.yaml"
1787
+ },
1788
+ "category": "reference",
1789
+ "skillName": null,
1790
+ "description": "A deferred item must leave the document: a traceable exit outside it, identified beside the item. The carrier is deliberately unspecified. A present link is not a working link — verified and unverified links are two states, never one green. Anchor on document structure, not wording"
1791
+ },
1769
1792
  {
1770
1793
  "id": "verification-evidence",
1771
1794
  "name": "Verification Evidence Standard",
@@ -2260,7 +2283,7 @@
2260
2283
  "id": "license-compliance",
2261
2284
  "name": "License Compliance Standards",
2262
2285
  "nameZh": "授權合規標準",
2263
- "version": "6.8.0",
2286
+ "version": "6.10.0",
2264
2287
  "source": {
2265
2288
  "human": "core/license-compliance.md",
2266
2289
  "ai": "ai/standards/license-compliance.ai.yaml"
@@ -2272,7 +2295,7 @@
2272
2295
  "id": "verification-oracle",
2273
2296
  "name": "Verification Oracle Standards",
2274
2297
  "nameZh": "驗證 Oracle 標準",
2275
- "version": "6.8.0",
2298
+ "version": "6.10.0",
2276
2299
  "source": {
2277
2300
  "human": "core/verification-oracle.md",
2278
2301
  "ai": "ai/standards/verification-oracle.ai.yaml"
@@ -2284,7 +2307,7 @@
2284
2307
  "id": "model-provenance",
2285
2308
  "name": "Model Provenance Policy Standards",
2286
2309
  "nameZh": "模型來源政策標準",
2287
- "version": "6.8.0",
2310
+ "version": "6.10.0",
2288
2311
  "source": {
2289
2312
  "human": "core/model-provenance.md",
2290
2313
  "ai": "ai/standards/model-provenance.ai.yaml"
@@ -2296,7 +2319,7 @@
2296
2319
  "id": "resource-cost-boundary",
2297
2320
  "name": "Resource / Cost Boundary Declaration Standards",
2298
2321
  "nameZh": "資源/成本邊界宣告標準",
2299
- "version": "6.8.0",
2322
+ "version": "6.10.0",
2300
2323
  "source": {
2301
2324
  "human": "core/resource-cost-boundary.md",
2302
2325
  "ai": "ai/standards/resource-cost-boundary.ai.yaml"