universal-dev-standards 5.13.3 → 5.15.1
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 -0
- package/bundled/ai/standards/ai-instruction-standards.ai.yaml +190 -3
- package/bundled/ai/standards/knowledge-graph-memory.ai.yaml +83 -0
- package/bundled/core/ai-instruction-standards.md +136 -11
- package/bundled/core/knowledge-graph-memory.md +119 -0
- package/bundled/locales/COVERAGE.md +226 -0
- package/bundled/locales/zh-CN/CHANGELOG.md +43 -3
- package/bundled/locales/zh-CN/README.md +1 -1
- package/bundled/locales/zh-CN/SECURITY.md +1 -1
- package/bundled/locales/zh-CN/core/ai-instruction-standards.md +111 -5
- package/bundled/locales/zh-TW/CHANGELOG.md +47 -3
- package/bundled/locales/zh-TW/README.md +1 -1
- package/bundled/locales/zh-TW/SECURITY.md +1 -1
- package/bundled/locales/zh-TW/core/ai-instruction-standards.md +130 -5
- package/bundled/locales/zh-TW/core/knowledge-graph-memory.md +127 -0
- package/bundled/locales/zh-TW/core/self-review-protocol.md +9 -1
- package/bundled/locales/zh-TW/skills/ac-coverage/SKILL.md +192 -0
- package/bundled/locales/zh-TW/skills/ai-collaboration-standards/SKILL.md +5 -1
- package/bundled/locales/zh-TW/skills/deploy-assistant/SKILL.md +187 -0
- package/bundled/locales/zh-TW/skills/dev-methodology/SKILL.md +108 -0
- package/bundled/locales/zh-TW/skills/journey-test-assistant/SKILL.md +222 -0
- package/bundled/locales/zh-TW/skills/knowledge-graph/SKILL.md +56 -0
- package/bundled/locales/zh-TW/skills/orchestrate/SKILL.md +172 -0
- package/bundled/locales/zh-TW/skills/plan/SKILL.md +239 -0
- package/bundled/locales/zh-TW/skills/project-structure-guide/SKILL.md +5 -1
- package/bundled/locales/zh-TW/skills/push/SKILL.md +241 -0
- package/bundled/locales/zh-TW/skills/skill-builder/SKILL.md +165 -0
- package/bundled/locales/zh-TW/skills/spec-derivation/SKILL.md +83 -0
- package/bundled/locales/zh-TW/skills/sweep/SKILL.md +149 -0
- package/bundled/skills/adr-assistant/SKILL.md +1 -1
- package/bundled/skills/ai-collaboration-standards/SKILL.md +1 -1
- package/bundled/skills/ai-friendly-architecture/SKILL.md +1 -1
- package/bundled/skills/ai-instruction-standards/SKILL.md +1 -1
- package/bundled/skills/api-design-assistant/SKILL.md +1 -1
- package/bundled/skills/audit-assistant/SKILL.md +1 -1
- package/bundled/skills/ci-cd-assistant/SKILL.md +1 -1
- package/bundled/skills/contract-test-assistant/SKILL.md +1 -1
- package/bundled/skills/database-assistant/SKILL.md +1 -1
- package/bundled/skills/deploy-assistant/SKILL.md +1 -1
- package/bundled/skills/documentation-guide/SKILL.md +1 -1
- package/bundled/skills/error-code-guide/SKILL.md +1 -1
- package/bundled/skills/git-workflow-guide/SKILL.md +1 -1
- package/bundled/skills/incident-response-assistant/SKILL.md +1 -1
- package/bundled/skills/journey-test-assistant/SKILL.md +1 -1
- package/bundled/skills/knowledge-graph/SKILL.md +58 -0
- package/bundled/skills/knowledge-graph/guide.md +69 -0
- package/bundled/skills/logging-guide/SKILL.md +1 -1
- package/bundled/skills/observability-assistant/SKILL.md +1 -1
- package/bundled/skills/orchestrate/SKILL.md +1 -1
- package/bundled/skills/plan/SKILL.md +1 -1
- package/bundled/skills/pr-automation-assistant/SKILL.md +1 -1
- package/bundled/skills/project-structure-guide/SKILL.md +1 -1
- package/bundled/skills/push/SKILL.md +1 -1
- package/bundled/skills/retrospective-assistant/SKILL.md +1 -1
- package/bundled/skills/reverse-engineer/SKILL.md +1 -1
- package/bundled/skills/runbook-assistant/SKILL.md +1 -1
- package/bundled/skills/security-assistant/SKILL.md +1 -1
- package/bundled/skills/security-scan-assistant/SKILL.md +1 -1
- package/bundled/skills/slo-assistant/SKILL.md +1 -1
- package/bundled/skills/sweep/SKILL.md +1 -1
- package/bundled/skills/testing-guide/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/commands/check.js +91 -1
- package/src/commands/init.js +8 -1
- package/src/commands/update.js +49 -14
- package/src/i18n/messages.js +32 -5
- package/src/installers/skills-installer.js +49 -0
- package/src/lint/i18n.js +338 -0
- package/src/utils/config-manager.js +39 -0
- package/src/utils/skills-installer.js +39 -7
- package/standards-registry.json +16 -4
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Knowledge Graph — Detailed Guide | 詳細指南
|
|
2
|
+
|
|
3
|
+
Companion to [SKILL.md](SKILL.md). Worked examples of both operating modes and the engine API.
|
|
4
|
+
|
|
5
|
+
[SKILL.md](SKILL.md) 的配套說明。兩種運作模式的範例與引擎 API。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Service Mode (graph engine) | 服務模式
|
|
10
|
+
|
|
11
|
+
When a CodeSage-compatible engine is reachable, a single query returns the full chain.
|
|
12
|
+
|
|
13
|
+
### Impact analysis | 影響分析
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
curl -s -X POST "$CODESAGE_URL/graph/impact-analysis" \
|
|
17
|
+
-H 'content-type: application/json' \
|
|
18
|
+
-d '{"nodeId":"XSPEC-205","maxHops":3}'
|
|
19
|
+
# => { "nodeId": "XSPEC-205",
|
|
20
|
+
# "decisions": [ {"id":"DEC-062","title":"...","via":"direct"},
|
|
21
|
+
# {"id":"DEC-069","title":"...","via":"supersedes"} ] }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`via: "direct"` means the decision IMPACTS the spec directly; `via: "supersedes"` means it reaches the spec through a SUPERSEDES chain (≤ `maxHops`).
|
|
25
|
+
|
|
26
|
+
### Confidence feedback (SAGE) | 信心回饋
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
curl -s -X POST "$CODESAGE_URL/graph/ingest" \
|
|
30
|
+
-H 'content-type: application/json' \
|
|
31
|
+
-d '{"type":"test_fail","functionId":"src/a.ts#execute"}'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Lowers the node's confidence; reads then surface higher-confidence nodes first.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. Degraded Mode (Markdown only) | 降級模式
|
|
39
|
+
|
|
40
|
+
No engine required. Reconstruct the chain by reading files:
|
|
41
|
+
|
|
42
|
+
1. Read the target document (e.g. `XSPEC-205`).
|
|
43
|
+
2. Collect ids from its front-matter (`impacts`, `impacted_by`, `supersedes`, `related`) and inline `[[ref]]` links.
|
|
44
|
+
3. For each id, read that document and repeat up to the desired hop depth.
|
|
45
|
+
4. Classify each id by prefix (`XSPEC-*`/`SPEC-*` → Spec; `DEC-*`/`ADR-*` → Decision) and report the edges.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# find the documents
|
|
49
|
+
grep -rl "id: XSPEC-205" --include='*.md' .
|
|
50
|
+
# discover outbound references
|
|
51
|
+
grep -nE "(impacts|impacted_by|supersedes|related):|\[\[(XSPEC|DEC|ADR)-" path/to/XSPEC-205.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Degraded mode is always correct but bounded by how many files you read; cross-domain code links (function → spec) are usually only available in service mode.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. Equivalence | 等價性
|
|
59
|
+
|
|
60
|
+
Both modes produce the **same answer shape** (a list of connected Specs/Decisions with edge types). Service mode is faster and more complete (it can include code→spec→decision hops); degraded mode is the universal fallback. Always tell the user which mode produced the answer.
|
|
61
|
+
|
|
62
|
+
兩種模式產生**相同形狀的答案**。服務模式更快更完整;降級模式為通用後備。務必告知使用者答案來自哪種模式。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Reference | 參考
|
|
67
|
+
|
|
68
|
+
- [core/knowledge-graph-memory.md](../../core/knowledge-graph-memory.md)
|
|
69
|
+
- [CodeSage](https://github.com/AsiaOstrich/CodeSage)
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Implement structured logging with proper log levels and sensitive data handling.
|
|
6
6
|
Use when: adding logging, debugging, setting up observability.
|
|
7
|
-
Keywords: logging, log level, structured logging, observability
|
|
7
|
+
Keywords: logging, log level, structured logging, observability.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Logging Guide
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide observability setup, metrics design, and alerting configuration.
|
|
6
6
|
Use when: new service instrumentation, SLO definition, alert design, maturity assessment.
|
|
7
|
-
Keywords: observability, metrics, traces, golden signals, alerting, SLO
|
|
7
|
+
Keywords: observability, metrics, traces, golden signals, alerting, SLO.
|
|
8
8
|
allowed-tools: Read, Write, Grep, Glob
|
|
9
9
|
argument-hint: "[service name or observability topic | 服務名稱或可觀測性主題]"
|
|
10
10
|
---
|
|
@@ -5,7 +5,7 @@ scope: universal
|
|
|
5
5
|
description: |
|
|
6
6
|
Orchestrate multi-task execution plans using Claude's native Agent tool (DAG-based, no external engine).
|
|
7
7
|
Use when: executing a plan.json file with parallel/sequential task dependencies.
|
|
8
|
-
Keywords: orchestrate, plan, execute, DAG, task plan
|
|
8
|
+
Keywords: orchestrate, plan, execute, DAG, task plan.
|
|
9
9
|
argument-hint: "<plan.json> [--dry-run]"
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ scope: universal
|
|
|
5
5
|
description: |
|
|
6
6
|
Generate plan.json from Spec documents, OpenSpec changes, or free-text requirements.
|
|
7
7
|
Use when: converting specifications into executable task plans for /orchestrate.
|
|
8
|
-
Keywords: plan, spec, task plan,
|
|
8
|
+
Keywords: plan, spec, task plan, plan.json, DAG.
|
|
9
9
|
argument-hint: "[spec-file.md | openspec-dir/ | \"requirement text\" | (interactive)]"
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide pull request creation, review automation, and merge strategies.
|
|
6
6
|
Use when: creating PRs, automating reviews, configuring merge policies.
|
|
7
|
-
Keywords: pull request, PR, merge, review, GitHub, GitLab
|
|
7
|
+
Keywords: pull request, PR, merge, review, GitHub, GitLab.
|
|
8
8
|
allowed-tools: Read, Grep, Glob, Bash(git:*, gh:*)
|
|
9
9
|
argument-hint: "[branch name or PR number | 分支名稱或 PR 編號]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide for organizing project directories following language-specific best practices.
|
|
6
6
|
Use when: creating projects, reorganizing structure, adding modules, setting up builds, deciding file placement.
|
|
7
|
-
Keywords: project, structure, directory, layout, gitignore, scaffold,
|
|
7
|
+
Keywords: project, structure, directory, layout, gitignore, scaffold, file placement, utils, helpers, shared, where to put.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Project Structure Guide
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
AI-assisted safety layer for git push operations with quality gates and collaboration guardrails.
|
|
6
6
|
Use when: pushing commits, force pushing, pushing to protected branches, pushing feature branches.
|
|
7
|
-
Keywords: git push, force push, protected branch, quality gate, push receipt, PR automation
|
|
7
|
+
Keywords: git push, force push, protected branch, quality gate, push receipt, PR automation.
|
|
8
8
|
allowed-tools: Read, Bash(git:*), Bash(npm:*), Bash(pnpm:*), Bash(yarn:*), Bash(bun:*)
|
|
9
9
|
argument-hint: "[--force] [--target <branch>] [--skip-gates] [--no-pr]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
[UDS] Guide structured team retrospectives for Sprint and Release cycles.
|
|
6
6
|
Use when: sprint end, release post-mortem, iteration review, process improvement.
|
|
7
|
-
Keywords: retrospective, retro, sprint review, lessons learned, action items
|
|
7
|
+
Keywords: retrospective, retro, sprint review, lessons learned, action items.
|
|
8
8
|
allowed-tools: Read, Write, Glob, Grep
|
|
9
9
|
argument-hint: "[sprint | release | actions | --technique starfish]"
|
|
10
10
|
---
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reverse
|
|
3
3
|
scope: partial
|
|
4
|
-
description: "[UDS] System archeology
|
|
4
|
+
description: "[UDS] System archeology - reverse engineer code across Logic, Data, and Runtime dimensions"
|
|
5
5
|
allowed-tools: Read, Grep, Glob, Bash(pg_dump:*), Bash(mysql:*), Bash(sqlite3:*), Bash(npm run:*), Bash(cat:*), Bash(docker:*)
|
|
6
6
|
argument-hint: "[spec|data|runtime|bdd|tdd] <input>"
|
|
7
7
|
disable-model-invocation: true
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide runbook creation, maintenance, and drill exercises.
|
|
6
6
|
Use when: writing runbooks, planning drills, auditing runbook coverage, post-incident runbook updates.
|
|
7
|
-
Keywords: runbook, operations, drill, on-call, procedure
|
|
7
|
+
Keywords: runbook, operations, drill, on-call, procedure.
|
|
8
8
|
allowed-tools: Read, Write, Grep, Glob
|
|
9
9
|
argument-hint: "[create|drill|coverage] [alert name or type | 告警名稱或類型]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide security review and vulnerability assessment following OWASP standards.
|
|
6
6
|
Use when: security audit, vulnerability check, secure coding review, threat modeling.
|
|
7
|
-
Keywords: security, OWASP, vulnerability, authentication, authorization
|
|
7
|
+
Keywords: security, OWASP, vulnerability, authentication, authorization.
|
|
8
8
|
allowed-tools: Read, Grep, Glob
|
|
9
9
|
argument-hint: "[module or file to audit | 要審計的模組或檔案]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide automated security scanning, dependency auditing, and secret detection.
|
|
6
6
|
Use when: dependency audit, CVE scanning, secret detection, license compliance.
|
|
7
|
-
Keywords: scan, audit, CVE, dependency, secret, SBOM, vulnerability
|
|
7
|
+
Keywords: scan, audit, CVE, dependency, secret, SBOM, vulnerability.
|
|
8
8
|
allowed-tools: Read, Grep, Glob, Bash(npm:audit, npx:*)
|
|
9
9
|
argument-hint: "[scan type or target | 掃描類型或目標]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Guide SLI selection, SLO setting, and Error Budget management.
|
|
6
6
|
Use when: defining service quality targets, setting up SLO-based alerting, Error Budget policy.
|
|
7
|
-
Keywords: SLI, SLO, SLA, Error Budget, burn rate, service level
|
|
7
|
+
Keywords: SLI, SLO, SLA, Error Budget, burn rate, service level.
|
|
8
8
|
allowed-tools: Read, Write, Grep, Glob
|
|
9
9
|
argument-hint: "[create|review|budget] [service name | 服務名稱]"
|
|
10
10
|
---
|
|
@@ -4,7 +4,7 @@ scope: universal
|
|
|
4
4
|
description: |
|
|
5
5
|
Scan codebase for debug artifacts and code quality issues; optionally auto-fix safe patterns.
|
|
6
6
|
Use when: before committing, during PR review, or periodic codebase cleanup.
|
|
7
|
-
Keywords: sweep, debug cleanup, console.log, debugger, TODO, ts-any, code quality
|
|
7
|
+
Keywords: sweep, debug cleanup, console.log, debugger, TODO, ts-any, code quality.
|
|
8
8
|
allowed-tools: Read, Grep, Glob, Bash(find:*), Edit, Write
|
|
9
9
|
argument-hint: "[--fix] [--report] [--path <dir>] [--exclude <pattern>]"
|
|
10
10
|
---
|
|
@@ -5,7 +5,7 @@ description: |
|
|
|
5
5
|
Testing pyramid and test writing standards for UT/IT/ST/E2E.
|
|
6
6
|
Supports ISTQB and Industry Pyramid frameworks.
|
|
7
7
|
Use when: writing tests, discussing test coverage, test strategy, or test naming.
|
|
8
|
-
Keywords: test, unit, integration, e2e, coverage, mock, ISTQB, SIT
|
|
8
|
+
Keywords: test, unit, integration, e2e, coverage, mock, ISTQB, SIT.
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Testing Guide
|
package/package.json
CHANGED
package/src/commands/check.js
CHANGED
|
@@ -38,6 +38,7 @@ import { StandardValidator } from '../utils/standard-validator.js';
|
|
|
38
38
|
import { WorkflowGate } from '../utils/workflow-gate.js';
|
|
39
39
|
import { t, setLanguage, isLanguageExplicitlySet } from '../i18n/messages.js';
|
|
40
40
|
import { guardAgainstSelfAdoption } from '../utils/detect-self-adoption.js';
|
|
41
|
+
import { lintAll as lintI18nAll, partitionFindings as partitionI18nFindings } from '../lint/i18n.js';
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
* Display the summary of file integrity status
|
|
@@ -243,6 +244,15 @@ function displayAdoptionStatus(manifest, msg, common, repoInfo) {
|
|
|
243
244
|
export async function checkCommand(options = {}) {
|
|
244
245
|
const projectPath = process.cwd();
|
|
245
246
|
|
|
247
|
+
// Handle --i18n option early — i18n lint is meant to be runnable both
|
|
248
|
+
// inside UDS source (lint canonical + locale variants) and inside
|
|
249
|
+
// adopter projects (lint installed locale variants). It does not require
|
|
250
|
+
// adoption-drift checks, so we short-circuit before guardAgainstSelfAdoption.
|
|
251
|
+
if (options.i18n) {
|
|
252
|
+
await runI18nLint(projectPath, options);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
246
256
|
// Refuse to run inside the UDS source repo itself.
|
|
247
257
|
// See DEC-044 / XSPEC-071 — adoption-drift check makes no sense for the
|
|
248
258
|
// source repo. `--force` bypasses (e.g. private forks of UDS).
|
|
@@ -1054,6 +1064,19 @@ function checkIntegrationFiles(manifest, projectPath, msg) {
|
|
|
1054
1064
|
console.log(chalk.cyan(msg.aiToolIntegration));
|
|
1055
1065
|
|
|
1056
1066
|
const standardsFiles = manifest.standards?.map(s => basename(s)) || [];
|
|
1067
|
+
|
|
1068
|
+
// Build a lookup map: registry ID → actual AI filename
|
|
1069
|
+
// Needed because some standards have IDs that differ from their .ai.yaml basename
|
|
1070
|
+
// (e.g. ID "error-code-standards" → file "error-codes.ai.yaml").
|
|
1071
|
+
// After migrateStandardsPathsToIds(), manifest.standards contains IDs, so a plain
|
|
1072
|
+
// content.includes(id) check would fail for these mismatched entries.
|
|
1073
|
+
const allRegistryStds = getAllStandards();
|
|
1074
|
+
const idToAiFilename = new Map(
|
|
1075
|
+
allRegistryStds
|
|
1076
|
+
.filter(s => s.source?.ai)
|
|
1077
|
+
.map(s => [s.id, basename(s.source.ai)])
|
|
1078
|
+
);
|
|
1079
|
+
|
|
1057
1080
|
let hasIssues = false;
|
|
1058
1081
|
let checkedCount = 0;
|
|
1059
1082
|
|
|
@@ -1093,8 +1116,14 @@ function checkIntegrationFiles(manifest, projectPath, msg) {
|
|
|
1093
1116
|
const missingStandards = [];
|
|
1094
1117
|
|
|
1095
1118
|
for (const stdFile of standardsFiles) {
|
|
1096
|
-
// Check if standard is referenced in the file
|
|
1119
|
+
// Check if standard is referenced in the file.
|
|
1120
|
+
// stdFile is a registry ID (e.g. "error-code-standards") after manifest
|
|
1121
|
+
// migration. For standards where the ID doesn't match the .ai.yaml basename
|
|
1122
|
+
// (e.g. ID "error-code-standards" → file "error-codes.ai.yaml"), we must
|
|
1123
|
+
// also check the actual filename so those aren't falsely reported as missing.
|
|
1124
|
+
const aiFilename = idToAiFilename.get(stdFile);
|
|
1097
1125
|
const isReferenced = content.includes(stdFile) ||
|
|
1126
|
+
(aiFilename !== undefined && aiFilename !== stdFile && content.includes(aiFilename)) ||
|
|
1098
1127
|
content.includes(`.standards/${stdFile}`) ||
|
|
1099
1128
|
content.includes(`standards/${stdFile}`);
|
|
1100
1129
|
|
|
@@ -1818,3 +1847,64 @@ function displayWorkflowStatus(projectPath) {
|
|
|
1818
1847
|
// Silently skip if workflow gate not available
|
|
1819
1848
|
}
|
|
1820
1849
|
}
|
|
1850
|
+
|
|
1851
|
+
// ============================================================
|
|
1852
|
+
// i18n Lint (XSPEC-239 — P1-CLI-5)
|
|
1853
|
+
// ============================================================
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* Run i18n lint across canonical + locale variants and print findings.
|
|
1857
|
+
* Exits 1 if any error-level findings are detected.
|
|
1858
|
+
*
|
|
1859
|
+
* @param {string} projectPath
|
|
1860
|
+
* @param {object} options - CLI options (currently honors options.json)
|
|
1861
|
+
*/
|
|
1862
|
+
async function runI18nLint(projectPath, options = {}) {
|
|
1863
|
+
const findings = lintI18nAll({ projectPath });
|
|
1864
|
+
const { errors, warnings } = partitionI18nFindings(findings);
|
|
1865
|
+
|
|
1866
|
+
if (options.json) {
|
|
1867
|
+
console.log(JSON.stringify({
|
|
1868
|
+
summary: {
|
|
1869
|
+
errors: errors.length,
|
|
1870
|
+
warnings: warnings.length,
|
|
1871
|
+
},
|
|
1872
|
+
findings,
|
|
1873
|
+
}, null, 2));
|
|
1874
|
+
if (errors.length > 0) process.exitCode = 1;
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
console.log();
|
|
1879
|
+
console.log(chalk.bold('UDS i18n Lint (XSPEC-239)'));
|
|
1880
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1881
|
+
console.log();
|
|
1882
|
+
|
|
1883
|
+
if (findings.length === 0) {
|
|
1884
|
+
console.log(chalk.green(' ✓ No i18n violations found.'));
|
|
1885
|
+
console.log();
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
// Display errors first
|
|
1890
|
+
for (const f of errors) {
|
|
1891
|
+
console.log(chalk.red(` ✗ [${f.rule}]`));
|
|
1892
|
+
console.log(chalk.red(` ${f.file}:${f.line}`));
|
|
1893
|
+
console.log(chalk.gray(` ${f.message}`));
|
|
1894
|
+
console.log();
|
|
1895
|
+
}
|
|
1896
|
+
for (const f of warnings) {
|
|
1897
|
+
console.log(chalk.yellow(` ⚠ [${f.rule}]`));
|
|
1898
|
+
console.log(chalk.yellow(` ${f.file}:${f.line}`));
|
|
1899
|
+
console.log(chalk.gray(` ${f.message}`));
|
|
1900
|
+
console.log();
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
1904
|
+
console.log(` ${chalk.red('Errors:')} ${errors.length} ${chalk.yellow('Warnings:')} ${warnings.length}`);
|
|
1905
|
+
console.log();
|
|
1906
|
+
|
|
1907
|
+
if (errors.length > 0) {
|
|
1908
|
+
process.exitCode = 1;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { displayLanguageToLocale } from '../utils/locale.js';
|
|
24
24
|
import { generateReleaseConfig, RELEASE_MODE_LABELS } from '../utils/release-config.js';
|
|
25
25
|
import { guardAgainstSelfAdoption } from '../utils/detect-self-adoption.js';
|
|
26
|
+
import { readInstallYaml } from '../utils/config-manager.js';
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Init command - initialize standards in current project
|
|
@@ -308,7 +309,13 @@ echo "Pre-commit checks passed"
|
|
|
308
309
|
* Build configuration for non-interactive mode
|
|
309
310
|
*/
|
|
310
311
|
function buildNonInteractiveConfig(options, detected, projectPath) {
|
|
311
|
-
|
|
312
|
+
// Locale resolution order (XSPEC-239 §Req-3):
|
|
313
|
+
// CLI --locale > .uds/install.yaml locale: > UDS_LOCALE env > LANG > 'en'
|
|
314
|
+
// detectLanguage() handles UDS_LOCALE + LANG fallback internally (P1-CLI-3).
|
|
315
|
+
const installYaml = readInstallYaml(projectPath);
|
|
316
|
+
const displayLanguage = options.locale
|
|
317
|
+
|| installYaml.locale
|
|
318
|
+
|| detectLanguage(null);
|
|
312
319
|
|
|
313
320
|
// Determine AI tools
|
|
314
321
|
const detectedAiTools = Object.keys(detected.aiTools).filter(k => detected.aiTools[k]);
|
package/src/commands/update.js
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
cleanupLegacyCommands
|
|
31
31
|
} from '../utils/skills-installer.js';
|
|
32
32
|
import { displayLanguageToLocale, isLocalizedLocale, detectLocaleFromStandards } from '../utils/locale.js';
|
|
33
|
+
import { readInstallYaml } from '../utils/config-manager.js';
|
|
33
34
|
import {
|
|
34
35
|
getAgentDisplayName,
|
|
35
36
|
getAgentConfig,
|
|
@@ -237,17 +238,49 @@ function checkNewStandards(manifest) {
|
|
|
237
238
|
}
|
|
238
239
|
|
|
239
240
|
/**
|
|
240
|
-
* Resolve locale
|
|
241
|
-
*
|
|
241
|
+
* Resolve locale for skill / command installation.
|
|
242
|
+
*
|
|
243
|
+
* Resolution order (XSPEC-239 §Req-3 / P1-CLI-2 + P1-CLI-3):
|
|
244
|
+
* 1. CLI `--locale` (passed via `options.locale`)
|
|
245
|
+
* 2. `.uds/install.yaml` `locale:`
|
|
246
|
+
* 3. `UDS_LOCALE` env var
|
|
247
|
+
* 4. manifest `options.display_language` (existing behaviour)
|
|
248
|
+
* 5. `.standards/` file-based detection (existing behaviour)
|
|
249
|
+
* 6. `'en'`
|
|
250
|
+
*
|
|
242
251
|
* @param {Object} manifest - Project manifest
|
|
243
252
|
* @param {string} projectPath - Project root path
|
|
253
|
+
* @param {Object} [options] - CLI options object (optional, for `--locale`)
|
|
244
254
|
* @returns {string} Locale directory name (e.g., 'zh-TW', 'en')
|
|
245
255
|
*/
|
|
246
|
-
function resolveLocale(manifest, projectPath) {
|
|
256
|
+
function resolveLocale(manifest, projectPath, options) {
|
|
257
|
+
// 1. CLI flag wins
|
|
258
|
+
const cliLocale = options?.locale && displayLanguageToLocale(options.locale);
|
|
259
|
+
if (cliLocale && isLocalizedLocale(cliLocale)) return cliLocale;
|
|
260
|
+
if (cliLocale === 'en') return 'en';
|
|
261
|
+
|
|
262
|
+
// 2. .uds/install.yaml
|
|
263
|
+
const installYaml = readInstallYaml(projectPath);
|
|
264
|
+
if (installYaml.locale) {
|
|
265
|
+
const fromYaml = displayLanguageToLocale(installYaml.locale);
|
|
266
|
+
if (isLocalizedLocale(fromYaml)) return fromYaml;
|
|
267
|
+
if (fromYaml === 'en') return 'en';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 3. UDS_LOCALE env
|
|
271
|
+
if (process.env.UDS_LOCALE) {
|
|
272
|
+
const fromEnv = displayLanguageToLocale(process.env.UDS_LOCALE);
|
|
273
|
+
if (isLocalizedLocale(fromEnv)) return fromEnv;
|
|
274
|
+
if (fromEnv === 'en') return 'en';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// 4. Manifest
|
|
247
278
|
const fromManifest = displayLanguageToLocale(manifest.options?.display_language);
|
|
248
279
|
if (isLocalizedLocale(fromManifest)) {
|
|
249
280
|
return fromManifest;
|
|
250
281
|
}
|
|
282
|
+
|
|
283
|
+
// 5. .standards/ detection → 6. 'en'
|
|
251
284
|
return detectLocaleFromStandards(projectPath) || 'en';
|
|
252
285
|
}
|
|
253
286
|
|
|
@@ -309,13 +342,13 @@ export async function updateCommand(options) {
|
|
|
309
342
|
|
|
310
343
|
// Handle --skills option
|
|
311
344
|
if (options.skills) {
|
|
312
|
-
await updateSkillsOnly(projectPath, manifest);
|
|
345
|
+
await updateSkillsOnly(projectPath, manifest, options);
|
|
313
346
|
return;
|
|
314
347
|
}
|
|
315
348
|
|
|
316
349
|
// Handle --commands option
|
|
317
350
|
if (options.commands) {
|
|
318
|
-
await updateCommandsOnly(projectPath, manifest);
|
|
351
|
+
await updateCommandsOnly(projectPath, manifest, options);
|
|
319
352
|
return;
|
|
320
353
|
}
|
|
321
354
|
|
|
@@ -892,7 +925,7 @@ export async function updateCommand(options) {
|
|
|
892
925
|
// Install Skills if user agreed
|
|
893
926
|
if (installSkills.length > 0) {
|
|
894
927
|
const skillSpinner = ora(msg.installingNewSkills || 'Installing Skills...').start();
|
|
895
|
-
const skillsLocale = resolveLocale(manifest, projectPath);
|
|
928
|
+
const skillsLocale = resolveLocale(manifest, projectPath, options);
|
|
896
929
|
const skillResult = await installSkillsToMultipleAgents(installSkills, null, projectPath, skillsLocale);
|
|
897
930
|
|
|
898
931
|
// Update manifest
|
|
@@ -933,7 +966,7 @@ export async function updateCommand(options) {
|
|
|
933
966
|
// Update outdated Skills if user agreed
|
|
934
967
|
if (updateSkills.length > 0) {
|
|
935
968
|
const updateSpinner = ora(msg.updatingSkills || 'Updating Skills...').start();
|
|
936
|
-
const updateLocale = resolveLocale(manifest, projectPath);
|
|
969
|
+
const updateLocale = resolveLocale(manifest, projectPath, options);
|
|
937
970
|
const updateResult = await installSkillsToMultipleAgents(updateSkills, null, projectPath, updateLocale);
|
|
938
971
|
|
|
939
972
|
// Update manifest version
|
|
@@ -969,7 +1002,7 @@ export async function updateCommand(options) {
|
|
|
969
1002
|
// Install Commands if user agreed
|
|
970
1003
|
if (installCommands.length > 0) {
|
|
971
1004
|
const cmdSpinner = ora(msg.installingNewCommands || 'Installing commands...').start();
|
|
972
|
-
const cmdLocale = resolveLocale(manifest, projectPath);
|
|
1005
|
+
const cmdLocale = resolveLocale(manifest, projectPath, options);
|
|
973
1006
|
const cmdResult = await installCommandsToMultipleAgents(installCommands, null, projectPath, cmdLocale);
|
|
974
1007
|
|
|
975
1008
|
// Update manifest
|
|
@@ -999,7 +1032,7 @@ export async function updateCommand(options) {
|
|
|
999
1032
|
// Update outdated Commands if user agreed
|
|
1000
1033
|
if (updateCommands.length > 0) {
|
|
1001
1034
|
const updateCmdSpinner = ora(msg.updatingCommands || 'Updating Commands...').start();
|
|
1002
|
-
const updateCmdLocale = resolveLocale(manifest, projectPath);
|
|
1035
|
+
const updateCmdLocale = resolveLocale(manifest, projectPath, options);
|
|
1003
1036
|
const updateCmdResult = await installCommandsToMultipleAgents(updateCommands, null, projectPath, updateCmdLocale);
|
|
1004
1037
|
|
|
1005
1038
|
// Update manifest version
|
|
@@ -1069,7 +1102,7 @@ export async function updateCommand(options) {
|
|
|
1069
1102
|
}
|
|
1070
1103
|
} else {
|
|
1071
1104
|
// --yes mode: auto-install/update Skills and Commands (treat -y as confirming all prompts)
|
|
1072
|
-
const skillsLocale = resolveLocale(manifest, projectPath);
|
|
1105
|
+
const skillsLocale = resolveLocale(manifest, projectPath, options);
|
|
1073
1106
|
let hasChanges = false;
|
|
1074
1107
|
|
|
1075
1108
|
if (missingSkills.length > 0) {
|
|
@@ -1551,8 +1584,9 @@ async function syncIntegrationReferences(projectPath, manifest) {
|
|
|
1551
1584
|
* Update Skills for all AI agents (--skills option)
|
|
1552
1585
|
* @param {string} projectPath - Project path
|
|
1553
1586
|
* @param {Object} manifest - Manifest object
|
|
1587
|
+
* @param {Object} [options] - CLI options (forwarded for locale resolution)
|
|
1554
1588
|
*/
|
|
1555
|
-
async function updateSkillsOnly(projectPath, manifest) {
|
|
1589
|
+
async function updateSkillsOnly(projectPath, manifest, options) {
|
|
1556
1590
|
const msg = t().commands.update;
|
|
1557
1591
|
const repoInfo = getRepositoryInfo();
|
|
1558
1592
|
const latestVersion = repoInfo.skills.version;
|
|
@@ -1621,7 +1655,7 @@ async function updateSkillsOnly(projectPath, manifest) {
|
|
|
1621
1655
|
|
|
1622
1656
|
const spinner = ora(msg.installingSkills || 'Installing Skills...').start();
|
|
1623
1657
|
|
|
1624
|
-
const skillsLocaleForUpdate = resolveLocale(manifest, projectPath);
|
|
1658
|
+
const skillsLocaleForUpdate = resolveLocale(manifest, projectPath, options);
|
|
1625
1659
|
const result = await installSkillsToMultipleAgents(
|
|
1626
1660
|
fileBasedInstallations,
|
|
1627
1661
|
null, // Install all skills
|
|
@@ -1665,8 +1699,9 @@ async function updateSkillsOnly(projectPath, manifest) {
|
|
|
1665
1699
|
* Update slash commands for all AI agents (--commands option)
|
|
1666
1700
|
* @param {string} projectPath - Project path
|
|
1667
1701
|
* @param {Object} manifest - Manifest object
|
|
1702
|
+
* @param {Object} [options] - CLI options (forwarded for locale resolution)
|
|
1668
1703
|
*/
|
|
1669
|
-
async function updateCommandsOnly(projectPath, manifest) {
|
|
1704
|
+
async function updateCommandsOnly(projectPath, manifest, options) {
|
|
1670
1705
|
const msg = t().commands.update;
|
|
1671
1706
|
|
|
1672
1707
|
console.log(chalk.cyan(msg.updatingCommandsOnly || 'Updating slash commands for all AI Agents...'));
|
|
@@ -1715,7 +1750,7 @@ async function updateCommandsOnly(projectPath, manifest) {
|
|
|
1715
1750
|
|
|
1716
1751
|
const spinner = ora(msg.installingCommands || 'Installing commands...').start();
|
|
1717
1752
|
|
|
1718
|
-
const commandsLocale = resolveLocale(manifest, projectPath);
|
|
1753
|
+
const commandsLocale = resolveLocale(manifest, projectPath, options);
|
|
1719
1754
|
const result = await installCommandsToMultipleAgents(
|
|
1720
1755
|
commandsInstallations,
|
|
1721
1756
|
null, // Install all commands
|
package/src/i18n/messages.js
CHANGED
|
@@ -1003,6 +1003,10 @@ export const messages = {
|
|
|
1003
1003
|
installingSkills: 'Installing Claude Code Skills...',
|
|
1004
1004
|
installedSkills: 'Installed {count} Skills to {locations}',
|
|
1005
1005
|
installedSkillsWithErrors: 'Installed {count} Skills with {errors} errors',
|
|
1006
|
+
// P1-CLI-1: locale fallback summary (printed after install when some
|
|
1007
|
+
// skills lack a localized variant and fell back to English source)
|
|
1008
|
+
localeFallbackTitle: 'Locale fallback: {count} skill(s) fell back to English because no {locale} variant exists:',
|
|
1009
|
+
localeFallbackHint: 'See locales/COVERAGE.md for full coverage status.',
|
|
1006
1010
|
// Success
|
|
1007
1011
|
initializedSuccess: '✓ Standards initialized successfully!',
|
|
1008
1012
|
filesCopied: '{count} files copied to project',
|
|
@@ -2264,6 +2268,9 @@ export const messages = {
|
|
|
2264
2268
|
installingSkills: '安裝 Claude Code Skills 中...',
|
|
2265
2269
|
installedSkills: '已安裝 {count} 個 Skills 到 {locations}',
|
|
2266
2270
|
installedSkillsWithErrors: '已安裝 {count} 個 Skills,有 {errors} 個錯誤',
|
|
2271
|
+
// P1-CLI-1:locale fallback 摘要(安裝結束後顯示,列出沒有對應語系變體而退回英文來源的 skill)
|
|
2272
|
+
localeFallbackTitle: 'Locale fallback:{count} 個 skill 因為沒有 {locale} 變體而退回英文版本:',
|
|
2273
|
+
localeFallbackHint: '完整覆蓋率請參閱 locales/COVERAGE.md。',
|
|
2267
2274
|
// Success
|
|
2268
2275
|
initializedSuccess: '✓ 標準初始化成功!',
|
|
2269
2276
|
filesCopied: '已複製 {count} 個檔案到專案',
|
|
@@ -3270,6 +3277,9 @@ export const messages = {
|
|
|
3270
3277
|
installingSkills: '正在安装 Claude Code Skills...',
|
|
3271
3278
|
installedSkills: '已安装 {count} 个 Skills 到 {locations}',
|
|
3272
3279
|
installedSkillsWithErrors: '已安装 {count} 个 Skills,有 {errors} 个错误',
|
|
3280
|
+
// P1-CLI-1:locale fallback 摘要(安装结束后显示,列出没有对应语种变体而退回英文来源的 skill)
|
|
3281
|
+
localeFallbackTitle: 'Locale fallback:{count} 个 skill 因为没有 {locale} 变体而退回英文版本:',
|
|
3282
|
+
localeFallbackHint: '完整覆盖率请参阅 locales/COVERAGE.md。',
|
|
3273
3283
|
// Success
|
|
3274
3284
|
initializedSuccess: '✓ 标准初始化成功!',
|
|
3275
3285
|
filesCopied: '已复制 {count} 个文件到项目',
|
|
@@ -3792,12 +3802,19 @@ export function msg(path) {
|
|
|
3792
3802
|
}
|
|
3793
3803
|
|
|
3794
3804
|
/**
|
|
3795
|
-
* Detect language from environment or locale setting
|
|
3805
|
+
* Detect language from environment or locale setting.
|
|
3806
|
+
*
|
|
3807
|
+
* Resolution order (XSPEC-239 §Req-3 / P1-CLI-3):
|
|
3808
|
+
* 1. explicit `locale` arg (from CLI `--locale`)
|
|
3809
|
+
* 2. `UDS_LOCALE` env var (UDS-specific override; takes precedence over LANG)
|
|
3810
|
+
* 3. POSIX locale env vars (`LANG` / `LC_ALL` / `LC_MESSAGES`)
|
|
3811
|
+
* 4. `'en'`
|
|
3812
|
+
*
|
|
3796
3813
|
* @param {string|null} locale - Locale setting from CLI options
|
|
3797
|
-
* @returns {string} Detected language code
|
|
3814
|
+
* @returns {string} Detected language code ('zh-tw' | 'zh-cn' | 'en')
|
|
3798
3815
|
*/
|
|
3799
3816
|
export function detectLanguage(locale) {
|
|
3800
|
-
// If locale is explicitly set, use it
|
|
3817
|
+
// 1. If locale is explicitly set, use it
|
|
3801
3818
|
if (locale === 'zh-tw') {
|
|
3802
3819
|
return 'zh-tw';
|
|
3803
3820
|
}
|
|
@@ -3805,7 +3822,17 @@ export function detectLanguage(locale) {
|
|
|
3805
3822
|
return 'zh-cn';
|
|
3806
3823
|
}
|
|
3807
3824
|
|
|
3808
|
-
//
|
|
3825
|
+
// 2. UDS-specific env var (P1-CLI-3): preferred over generic POSIX LANG so
|
|
3826
|
+
// adopters can opt into a specific UDS locale in CI without touching LANG.
|
|
3827
|
+
if (process.env.UDS_LOCALE) {
|
|
3828
|
+
const v = process.env.UDS_LOCALE.toLowerCase();
|
|
3829
|
+
if (v === 'zh-tw' || v === 'zh_tw') return 'zh-tw';
|
|
3830
|
+
if (v === 'zh-cn' || v === 'zh_cn') return 'zh-cn';
|
|
3831
|
+
if (v === 'en') return 'en';
|
|
3832
|
+
// Unknown UDS_LOCALE values fall through to LANG detection below
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
// 3. Check POSIX environment variables
|
|
3809
3836
|
const envLang = process.env.LANG || process.env.LC_ALL || process.env.LC_MESSAGES || '';
|
|
3810
3837
|
if (envLang.toLowerCase().includes('zh_tw') || envLang.toLowerCase().includes('zh-tw')) {
|
|
3811
3838
|
return 'zh-tw';
|
|
@@ -3814,6 +3841,6 @@ export function detectLanguage(locale) {
|
|
|
3814
3841
|
return 'zh-cn';
|
|
3815
3842
|
}
|
|
3816
3843
|
|
|
3817
|
-
// Default to English
|
|
3844
|
+
// 4. Default to English
|
|
3818
3845
|
return 'en';
|
|
3819
3846
|
}
|