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.
- package/bin/uds.js +12 -2
- package/bundled/ai/standards/acceptance-criteria-traceability.ai.yaml +14 -2
- package/bundled/ai/standards/adr-standards.ai.yaml +14 -2
- package/bundled/ai/standards/code-review.ai.yaml +13 -3
- package/bundled/ai/standards/commit-message.ai.yaml +8 -4
- package/bundled/ai/standards/deferred-item-exit.ai.yaml +225 -0
- package/bundled/ai/standards/feature-discovery-standards.ai.yaml +14 -2
- package/bundled/ai/standards/governance-layer.ai.yaml +128 -2
- package/bundled/ai/standards/logging.ai.yaml +2 -2
- package/bundled/ai/standards/retrospective-standards.ai.yaml +14 -2
- package/bundled/ai/standards/reverse-engineering-standards.ai.yaml +73 -2
- package/bundled/ai/standards/security-standards.ai.yaml +2 -2
- package/bundled/ai/standards/spec-driven-development.ai.yaml +14 -2
- package/bundled/ai/standards/tech-debt-standards.ai.yaml +87 -3
- package/bundled/ai/standards/turn-completion-integrity.ai.yaml +131 -0
- package/bundled/core/acceptance-criteria-traceability.md +5 -2
- package/bundled/core/adr-standards.md +26 -2
- package/bundled/core/agent-communication-protocol.md +8 -0
- package/bundled/core/branch-completion.md +8 -0
- package/bundled/core/change-batching-standards.md +8 -0
- package/bundled/core/code-review-checklist.md +5 -2
- package/bundled/core/context-aware-loading.md +1 -1
- package/bundled/core/deferred-item-exit.md +254 -0
- package/bundled/core/execution-history.md +8 -0
- package/bundled/core/feature-discovery-standards.md +5 -1
- package/bundled/core/governance-layer.md +114 -2
- package/bundled/core/pipeline-integration-standards.md +8 -0
- package/bundled/core/retrospective-standards.md +4 -2
- package/bundled/core/reverse-engineering-standards.md +81 -2
- package/bundled/core/spec-driven-development.md +8 -2
- package/bundled/core/tech-debt-standards.md +67 -8
- package/bundled/core/turn-completion-integrity.md +196 -0
- package/bundled/core/workflow-enforcement.md +8 -0
- package/bundled/core/workflow-state-protocol.md +8 -0
- package/bundled/hooks/check-dangerous-cmd.mjs +60 -0
- package/bundled/hooks/check-logging-standard.mjs +59 -0
- package/bundled/hooks/check-turn-completion.mjs +233 -0
- package/bundled/hooks/inject-standards.mjs +183 -0
- package/bundled/hooks/telemetry-wrapper.mjs +77 -0
- package/bundled/hooks/turn-completion/detect.mjs +99 -0
- package/bundled/hooks/turn-completion/locales/en.mjs +159 -0
- package/bundled/hooks/turn-completion/locales/zh-TW.mjs +166 -0
- package/bundled/hooks/validate-commit-msg.mjs +104 -0
- package/bundled/locales/zh-CN/CHANGELOG.md +73 -3
- package/bundled/locales/zh-CN/CLAUDE.md +1 -1
- package/bundled/locales/zh-CN/README.md +2 -2
- package/bundled/locales/zh-CN/SECURITY.md +1 -1
- package/bundled/locales/zh-CN/core/adr-standards.md +1 -1
- package/bundled/locales/zh-CN/core/agent-communication-protocol.md +7 -0
- package/bundled/locales/zh-CN/core/branch-completion.md +7 -0
- package/bundled/locales/zh-CN/core/change-batching-standards.md +7 -0
- package/bundled/locales/zh-CN/core/execution-history.md +7 -0
- package/bundled/locales/zh-CN/core/governance-layer.md +118 -6
- package/bundled/locales/zh-CN/core/pipeline-integration-standards.md +7 -0
- package/bundled/locales/zh-CN/core/retrospective-standards.md +1 -1
- package/bundled/locales/zh-CN/core/tech-debt-standards.md +71 -4
- package/bundled/locales/zh-CN/core/turn-completion-integrity.md +190 -0
- package/bundled/locales/zh-CN/core/workflow-enforcement.md +7 -0
- package/bundled/locales/zh-CN/core/workflow-state-protocol.md +7 -0
- package/bundled/locales/zh-CN/docs/CHEATSHEET.md +8 -1
- package/bundled/locales/zh-CN/docs/CLI-INIT-OPTIONS.md +29 -68
- package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +25 -15
- package/bundled/locales/zh-CN/docs/MIGRATION-v6.md +8 -4
- package/bundled/locales/zh-CN/docs/USAGE-MODES-COMPARISON.md +1 -2
- package/bundled/locales/zh-CN/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
- package/bundled/locales/zh-CN/integrations/google-antigravity/README.md +3 -3
- package/bundled/locales/zh-CN/skills/atdd-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-CN/skills/bdd-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-CN/skills/brainstorm-assistant/SKILL.md +22 -12
- package/bundled/locales/zh-CN/skills/brainstorm-assistant/guide.md +12 -9
- package/bundled/locales/zh-CN/skills/code-review-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/commands/brainstorm.md +17 -13
- package/bundled/locales/zh-CN/skills/commands/config.md +0 -1
- package/bundled/locales/zh-CN/skills/commands/init.md +1 -2
- package/bundled/locales/zh-CN/skills/commit-standards/SKILL.md +2 -0
- package/bundled/locales/zh-CN/skills/contract-test-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/dev-methodology/SKILL.md +2 -0
- package/bundled/locales/zh-CN/skills/observability-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/project-structure-guide/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/release-standards/SKILL.md +3 -0
- package/bundled/locales/zh-CN/skills/requirement-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-CN/skills/reverse-engineer/SKILL.md +3 -0
- package/bundled/locales/zh-CN/skills/runbook-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/slo-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-CN/skills/tdd-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-TW/CHANGELOG.md +74 -3
- package/bundled/locales/zh-TW/CLAUDE.md +1 -1
- package/bundled/locales/zh-TW/README.md +2 -2
- package/bundled/locales/zh-TW/SECURITY.md +1 -1
- package/bundled/locales/zh-TW/core/acceptance-criteria-traceability.md +2 -0
- package/bundled/locales/zh-TW/core/adr-standards.md +26 -5
- package/bundled/locales/zh-TW/core/agent-communication-protocol.md +7 -0
- package/bundled/locales/zh-TW/core/branch-completion.md +7 -0
- package/bundled/locales/zh-TW/core/change-batching-standards.md +7 -0
- package/bundled/locales/zh-TW/core/code-review-checklist.md +2 -0
- package/bundled/locales/zh-TW/core/container-image-standards.md +2 -2
- package/bundled/locales/zh-TW/core/contract-testing-standards.md +2 -2
- package/bundled/locales/zh-TW/core/cross-flow-regression.md +8 -7
- package/bundled/locales/zh-TW/core/data-contract.md +2 -2
- package/bundled/locales/zh-TW/core/data-migration-testing.md +2 -2
- package/bundled/locales/zh-TW/core/data-pipeline.md +2 -2
- package/bundled/locales/zh-TW/core/deferred-item-exit.md +251 -0
- package/bundled/locales/zh-TW/core/documentation-writing-standards.md +228 -3
- package/bundled/locales/zh-TW/core/execution-history.md +7 -0
- package/bundled/locales/zh-TW/core/full-coverage-testing.md +15 -2
- package/bundled/locales/zh-TW/core/governance-layer.md +118 -5
- package/bundled/locales/zh-TW/core/iac-design-principles.md +2 -2
- package/bundled/locales/zh-TW/core/incident-response.md +2 -2
- package/bundled/locales/zh-TW/core/model-provenance.md +4 -2
- package/bundled/locales/zh-TW/core/pii-classification.md +42 -6
- package/bundled/locales/zh-TW/core/pipeline-integration-standards.md +7 -0
- package/bundled/locales/zh-TW/core/prd-standards.md +4 -2
- package/bundled/locales/zh-TW/core/product-metrics-standards.md +4 -2
- package/bundled/locales/zh-TW/core/release-readiness-gate.md +2 -2
- package/bundled/locales/zh-TW/core/resource-cost-boundary.md +2 -2
- package/bundled/locales/zh-TW/core/retrospective-standards.md +5 -3
- package/bundled/locales/zh-TW/core/reverse-engineering-standards.md +83 -5
- package/bundled/locales/zh-TW/core/runbook.md +2 -2
- package/bundled/locales/zh-TW/core/schema-evolution.md +2 -2
- package/bundled/locales/zh-TW/core/secret-management-standards.md +2 -2
- package/bundled/locales/zh-TW/core/slo-sli.md +2 -2
- package/bundled/locales/zh-TW/core/spec-driven-development.md +2 -0
- package/bundled/locales/zh-TW/core/tech-debt-standards.md +71 -4
- package/bundled/locales/zh-TW/core/turn-completion-integrity.md +190 -0
- package/bundled/locales/zh-TW/core/user-journey-testing.md +2 -2
- package/bundled/locales/zh-TW/core/user-story-mapping.md +2 -2
- package/bundled/locales/zh-TW/core/verification-oracle.md +2 -2
- package/bundled/locales/zh-TW/core/workflow-enforcement.md +7 -0
- package/bundled/locales/zh-TW/core/workflow-state-protocol.md +7 -0
- package/bundled/locales/zh-TW/docs/CHEATSHEET.md +8 -1
- package/bundled/locales/zh-TW/docs/CLI-INIT-OPTIONS.md +29 -68
- package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +25 -15
- package/bundled/locales/zh-TW/docs/MIGRATION-v6.md +8 -4
- package/bundled/locales/zh-TW/docs/USAGE-MODES-COMPARISON.md +1 -2
- package/bundled/locales/zh-TW/integrations/google-antigravity/{INSTRUCTIONS.md → AGENTS.md} +1 -1
- package/bundled/locales/zh-TW/integrations/google-antigravity/README.md +3 -3
- package/bundled/locales/zh-TW/skills/adr-assistant/SKILL.md +1 -1
- package/bundled/locales/zh-TW/skills/atdd-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-TW/skills/bdd-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-TW/skills/brainstorm-assistant/SKILL.md +22 -12
- package/bundled/locales/zh-TW/skills/brainstorm-assistant/guide.md +12 -9
- package/bundled/locales/zh-TW/skills/code-review-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/commands/brainstorm.md +17 -13
- package/bundled/locales/zh-TW/skills/commands/config.md +0 -1
- package/bundled/locales/zh-TW/skills/commands/init.md +1 -2
- package/bundled/locales/zh-TW/skills/commit-standards/SKILL.md +2 -0
- package/bundled/locales/zh-TW/skills/contract-test-assistant/SKILL.md +2 -1
- package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +2 -0
- package/bundled/locales/zh-TW/skills/dev-workflow-guide/SKILL.md +1 -1
- package/bundled/locales/zh-TW/skills/knowledge-graph/guide.md +2 -2
- package/bundled/locales/zh-TW/skills/migration-assistant/SKILL.md +1 -1
- package/bundled/locales/zh-TW/skills/observability-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/project-discovery/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/release-standards/SKILL.md +3 -0
- package/bundled/locales/zh-TW/skills/requirement-assistant/SKILL.md +2 -0
- package/bundled/locales/zh-TW/skills/reverse-engineer/SKILL.md +3 -0
- package/bundled/locales/zh-TW/skills/runbook-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/slo-assistant/SKILL.md +1 -0
- package/bundled/locales/zh-TW/skills/tdd-assistant/SKILL.md +2 -0
- package/bundled/skills/atdd-assistant/SKILL.md +2 -0
- package/bundled/skills/bdd-assistant/SKILL.md +2 -0
- package/bundled/skills/brainstorm-assistant/SKILL.md +31 -13
- package/bundled/skills/brainstorm-assistant/guide.md +9 -6
- package/bundled/skills/code-review-assistant/SKILL.md +1 -0
- package/bundled/skills/commands/brainstorm.md +12 -9
- package/bundled/skills/commands/config.md +0 -1
- package/bundled/skills/commands/init.md +2 -3
- package/bundled/skills/commit-standards/SKILL.md +2 -0
- package/bundled/skills/contract-test-assistant/SKILL.md +1 -0
- package/bundled/skills/dev-methodology/SKILL.md +4 -0
- package/bundled/skills/observability-assistant/SKILL.md +1 -0
- package/bundled/skills/project-discovery/SKILL.md +1 -0
- package/bundled/skills/project-structure-guide/SKILL.md +1 -0
- package/bundled/skills/release-standards/SKILL.md +3 -0
- package/bundled/skills/requirement-assistant/SKILL.md +2 -0
- package/bundled/skills/reverse-engineer/SKILL.md +3 -0
- package/bundled/skills/runbook-assistant/SKILL.md +1 -0
- package/bundled/skills/slo-assistant/SKILL.md +1 -0
- package/bundled/skills/tdd-assistant/SKILL.md +2 -0
- package/bundled/templates/.ai-context.yaml.template +194 -0
- package/bundled/templates/CLAUDE.md.template +145 -0
- package/bundled/templates/DESIGN.md +237 -0
- package/bundled/templates/SKILL-BRIEF-TEMPLATE.md +57 -0
- package/bundled/templates/SKILL-CANDIDATES.md +39 -0
- package/bundled/templates/gates/check-error-exit.mjs +309 -0
- package/bundled/templates/mcp-config.json +10 -0
- package/bundled/templates/methodology-template.yaml +209 -0
- package/bundled/templates/migration-template.md +408 -0
- package/bundled/templates/requirement-checklist.md +410 -0
- package/bundled/templates/requirement-document-template.md +591 -0
- package/bundled/templates/requirement-template.md +881 -0
- package/bundled/templates/reverse-spec-template.md +409 -0
- package/bundled/templates/test-case-template.md +74 -0
- package/bundled/templates/test-plan-template.md +74 -0
- package/package.json +12 -9
- package/src/commands/audit.js +82 -0
- package/src/commands/check.js +227 -34
- package/src/commands/config.js +19 -19
- package/src/commands/init.js +174 -20
- package/src/commands/spec.js +2 -2
- package/src/commands/update.js +537 -43
- package/src/compilers/claude-code-compiler.js +4 -1
- package/src/config/ai-agent-paths.js +62 -17
- package/src/core/constants.js +42 -11
- package/src/core/manifest.js +201 -3
- package/src/core/paths.js +2 -2
- package/src/i18n/messages.js +42 -29
- package/src/installers/hooks-installer.js +167 -75
- package/src/installers/integration-installer.js +13 -9
- package/src/installers/skills-installer.js +4 -4
- package/src/installers/standards-installer.js +3 -3
- package/src/prompts/init.js +47 -18
- package/src/reconciler/diff-engine.js +57 -2
- package/src/reconciler/plan-executor.js +31 -11
- package/src/utils/detector.js +21 -1
- package/src/utils/effect-boundary.js +1093 -0
- package/src/utils/hasher.js +166 -1
- package/src/utils/hook-stats.js +1 -1
- package/src/utils/integration-generator.js +288 -82
- package/src/utils/reference-sync.js +107 -8
- package/src/utils/registry.js +57 -0
- package/src/utils/spinner.js +31 -0
- package/src/utils/yaml-generator.js +51 -9
- 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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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(
|
|
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
|
-
|
|
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'
|
package/src/utils/registry.js
CHANGED
|
@@ -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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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) {
|
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.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.
|
|
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.
|
|
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
|
|
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/
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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"
|