universal-dev-standards 4.1.0 → 4.2.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 +75 -0
- package/bundled/core/ai-friendly-architecture.md +542 -0
- package/bundled/locales/zh-CN/README.md +210 -509
- package/bundled/locales/zh-CN/core/ai-friendly-architecture.md +306 -0
- package/bundled/locales/zh-CN/docs/AI-AGENT-ROADMAP.md +82 -22
- package/bundled/locales/zh-CN/integrations/gemini-cli/GEMINI.md +35 -3
- package/bundled/locales/zh-CN/integrations/github-copilot/COPILOT-CHAT-REFERENCE.md +89 -3
- package/bundled/locales/zh-CN/integrations/github-copilot/skills-mapping.md +8 -4
- package/bundled/locales/zh-TW/README.md +211 -490
- package/bundled/locales/zh-TW/core/ai-friendly-architecture.md +306 -0
- package/bundled/locales/zh-TW/docs/AI-AGENT-ROADMAP.md +82 -22
- package/bundled/locales/zh-TW/integrations/gemini-cli/GEMINI.md +35 -3
- package/bundled/locales/zh-TW/integrations/github-copilot/COPILOT-CHAT-REFERENCE.md +89 -3
- package/bundled/locales/zh-TW/integrations/github-copilot/skills-mapping.md +8 -4
- package/bundled/skills/claude-code/README.md +8 -0
- package/bundled/skills/claude-code/agents/README.md +305 -0
- package/bundled/skills/claude-code/agents/code-architect.md +259 -0
- package/bundled/skills/claude-code/agents/doc-writer.md +406 -0
- package/bundled/skills/claude-code/agents/reviewer.md +353 -0
- package/bundled/skills/claude-code/agents/spec-analyst.md +374 -0
- package/bundled/skills/claude-code/agents/test-specialist.md +364 -0
- package/bundled/skills/claude-code/workflows/README.md +303 -0
- package/bundled/skills/claude-code/workflows/code-review.workflow.yaml +186 -0
- package/bundled/skills/claude-code/workflows/feature-dev.workflow.yaml +174 -0
- package/bundled/skills/claude-code/workflows/integrated-flow.workflow.yaml +238 -0
- package/bundled/skills/claude-code/workflows/large-codebase-analysis.workflow.yaml +226 -0
- package/package.json +11 -1
- package/src/commands/agent.js +417 -0
- package/src/commands/ai-context.js +552 -0
- package/src/commands/check.js +3 -3
- package/src/commands/init.js +6 -3
- package/src/commands/workflow.js +425 -0
- package/src/config/ai-agent-paths.js +217 -13
- package/src/core/constants.js +514 -0
- package/src/core/errors.js +398 -0
- package/src/core/manifest.js +473 -0
- package/src/core/paths.js +398 -0
- package/src/prompts/init.js +7 -5
- package/src/utils/agent-adapter.js +320 -0
- package/src/utils/agents-installer.js +393 -0
- package/src/utils/context-chunker.js +467 -0
- package/src/utils/copier.js +59 -99
- package/src/utils/hasher.js +2 -16
- package/src/utils/integration-generator.js +28 -52
- package/src/utils/workflows-installer.js +545 -0
- package/standards-registry.json +166 -20
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join, basename, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import {
|
|
5
|
+
DIRECTORIES,
|
|
6
|
+
FILE_PATTERNS,
|
|
7
|
+
FILE_EXTENSIONS as EXTENSIONS
|
|
8
|
+
} from './constants.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* UDS Path Resolution System
|
|
12
|
+
* Centralized path management for all UDS operations
|
|
13
|
+
*
|
|
14
|
+
* Note: DIRECTORIES, FILE_PATTERNS, and EXTENSIONS are imported from constants.js
|
|
15
|
+
* to maintain a single source of truth for these values.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = dirname(__filename);
|
|
20
|
+
|
|
21
|
+
// CLI package root (where package.json is located)
|
|
22
|
+
const CLI_ROOT = join(__dirname, '../..');
|
|
23
|
+
|
|
24
|
+
// Bundled files directory (for npm-installed CLI)
|
|
25
|
+
const BUNDLED_ROOT = join(CLI_ROOT, 'bundled');
|
|
26
|
+
|
|
27
|
+
// Root of universal-dev-standards repository (for local development)
|
|
28
|
+
const REPO_ROOT = join(CLI_ROOT, '..');
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Path priority order for source files
|
|
32
|
+
*/
|
|
33
|
+
export const PATH_PRIORITY = {
|
|
34
|
+
BUNDLED: 1, // npm-installed bundled files
|
|
35
|
+
REPO: 2, // local development repository
|
|
36
|
+
GITHUB: 3 // fallback download from GitHub
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Re-export DIRECTORIES and FILE_PATTERNS for backward compatibility
|
|
40
|
+
export { DIRECTORIES, FILE_PATTERNS, EXTENSIONS };
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* PathResolver class for centralized path management
|
|
44
|
+
*/
|
|
45
|
+
export class PathResolver {
|
|
46
|
+
/**
|
|
47
|
+
* Get CLI root directory
|
|
48
|
+
* @returns {string} CLI root path
|
|
49
|
+
*/
|
|
50
|
+
static getCliRoot() {
|
|
51
|
+
return CLI_ROOT;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get repository root directory
|
|
56
|
+
* @returns {string} Repository root path
|
|
57
|
+
*/
|
|
58
|
+
static getRepoRoot() {
|
|
59
|
+
return REPO_ROOT;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get bundled files directory
|
|
64
|
+
* @returns {string} Bundled root path
|
|
65
|
+
*/
|
|
66
|
+
static getBundledRoot() {
|
|
67
|
+
return BUNDLED_ROOT;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get standard source file path with priority resolution
|
|
72
|
+
* @param {string} relativePath - Relative path from repo root (e.g., 'core/anti-hallucination.md')
|
|
73
|
+
* @returns {string|null} Absolute path to source file, or null if not found locally
|
|
74
|
+
*/
|
|
75
|
+
static getStandardSource(relativePath) {
|
|
76
|
+
// Priority 1: Bundled files (for npm-installed CLI)
|
|
77
|
+
const bundledPath = join(BUNDLED_ROOT, relativePath);
|
|
78
|
+
if (existsSync(bundledPath)) {
|
|
79
|
+
return bundledPath;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Priority 2: Repository root (for local development)
|
|
83
|
+
const repoPath = join(REPO_ROOT, relativePath);
|
|
84
|
+
if (existsSync(repoPath)) {
|
|
85
|
+
return repoPath;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return null; // Not found locally, will need to download
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get integration source file path
|
|
93
|
+
* @param {string} tool - AI tool name (e.g., 'claude-code')
|
|
94
|
+
* @param {string} relativePath - Relative path within tool directory
|
|
95
|
+
* @returns {string|null} Absolute path to integration file, or null if not found
|
|
96
|
+
*/
|
|
97
|
+
static getIntegrationSource(tool, relativePath) {
|
|
98
|
+
const toolPath = join(DIRECTORIES.INTEGRATIONS, tool, relativePath);
|
|
99
|
+
return this.getStandardSource(toolPath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get skill source file path
|
|
104
|
+
* @param {string} agent - AI agent name (e.g., 'claude-code')
|
|
105
|
+
* @param {string} category - Skill category (e.g., 'agents', 'workflows')
|
|
106
|
+
* @param {string} fileName - File name
|
|
107
|
+
* @returns {string|null} Absolute path to skill file, or null if not found
|
|
108
|
+
*/
|
|
109
|
+
static getSkillSource(agent, category, fileName) {
|
|
110
|
+
const skillPath = join(DIRECTORIES.SKILLS, agent, category, fileName);
|
|
111
|
+
return this.getStandardSource(skillPath);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get locale source file path
|
|
116
|
+
* @param {string} locale - Locale code (e.g., 'zh-TW', 'zh-CN')
|
|
117
|
+
* @param {string} relativePath - Relative path within locale directory
|
|
118
|
+
* @returns {string|null} Absolute path to locale file, or null if not found
|
|
119
|
+
*/
|
|
120
|
+
static getLocaleSource(locale, relativePath) {
|
|
121
|
+
const localePath = join(DIRECTORIES.LOCALES, locale, relativePath);
|
|
122
|
+
return this.getStandardSource(localePath);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get target path for standard file in project
|
|
127
|
+
* @param {string} projectPath - Project root path
|
|
128
|
+
* @param {string} relativePath - Relative path from standards directory
|
|
129
|
+
* @returns {string} Absolute target path
|
|
130
|
+
*/
|
|
131
|
+
static getStandardTarget(projectPath, relativePath) {
|
|
132
|
+
return join(projectPath, DIRECTORIES.STANDARDS, relativePath);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get target path for integration file
|
|
137
|
+
* @param {string} projectPath - Project root path
|
|
138
|
+
* @param {string} tool - AI tool name
|
|
139
|
+
* @param {string} fileName - File name
|
|
140
|
+
* @returns {string} Absolute target path
|
|
141
|
+
*/
|
|
142
|
+
static getIntegrationTarget(projectPath, tool, fileName) {
|
|
143
|
+
// Different tools use different target locations
|
|
144
|
+
const toolTargets = {
|
|
145
|
+
'claude-code': 'CLAUDE.md',
|
|
146
|
+
'cursor': '.cursorrules',
|
|
147
|
+
'cline': '.clinerules',
|
|
148
|
+
'windsurf': '.windsurfrules',
|
|
149
|
+
'copilot': 'copilot-instructions.md',
|
|
150
|
+
'aider': '.aider.conf.yml',
|
|
151
|
+
'opencode': 'AGENTS.md',
|
|
152
|
+
'roo': 'ROO.md',
|
|
153
|
+
'antigravity': 'INSTRUCTIONS.md'
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const targetFile = toolTargets[tool] || fileName;
|
|
157
|
+
return join(projectPath, targetFile);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get target path for skill installation
|
|
162
|
+
* @param {string} projectPath - Project root path
|
|
163
|
+
* @param {string} agent - AI agent name
|
|
164
|
+
* @param {string} level - Installation level ('project' or 'user')
|
|
165
|
+
* @param {string} skillPath - Skill relative path
|
|
166
|
+
* @returns {string} Absolute target path
|
|
167
|
+
*/
|
|
168
|
+
static getSkillTarget(projectPath, agent, level, skillPath) {
|
|
169
|
+
if (level === 'project') {
|
|
170
|
+
return join(projectPath, '.uds', 'skills', agent, skillPath);
|
|
171
|
+
} else {
|
|
172
|
+
// User-level installation (home directory)
|
|
173
|
+
const userHome = require('os').homedir();
|
|
174
|
+
return join(userHome, '.uds', 'skills', agent, skillPath);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get manifest file path for project
|
|
180
|
+
* @param {string} projectPath - Project root path
|
|
181
|
+
* @returns {string} Absolute path to manifest.json
|
|
182
|
+
*/
|
|
183
|
+
static getManifestPath(projectPath) {
|
|
184
|
+
return join(projectPath, DIRECTORIES.STANDARDS, 'manifest.json');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get standards directory path for project
|
|
189
|
+
* @param {string} projectPath - Project root path
|
|
190
|
+
* @returns {string} Absolute path to standards directory
|
|
191
|
+
*/
|
|
192
|
+
static getStandardsDir(projectPath) {
|
|
193
|
+
return join(projectPath, DIRECTORIES.STANDARDS);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Get UDS working directory for project
|
|
198
|
+
* @param {string} projectPath - Project root path
|
|
199
|
+
* @returns {string} Absolute path to .uds directory
|
|
200
|
+
*/
|
|
201
|
+
static getUDSDir(projectPath) {
|
|
202
|
+
return join(projectPath, '.uds');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Check if path exists locally (not counting GitHub downloads)
|
|
207
|
+
* @param {string} relativePath - Relative path to check
|
|
208
|
+
* @returns {boolean} True if file exists locally
|
|
209
|
+
*/
|
|
210
|
+
static existsLocally(relativePath) {
|
|
211
|
+
return this.getStandardSource(relativePath) !== null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get relative path from project root
|
|
216
|
+
* @param {string} projectPath - Project root path
|
|
217
|
+
* @param {string} fullPath - Full path
|
|
218
|
+
* @returns {string} Relative path
|
|
219
|
+
*/
|
|
220
|
+
static getRelativePath(projectPath, fullPath) {
|
|
221
|
+
return fullPath.replace(projectPath + '/', '');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Normalize path separators for current platform
|
|
226
|
+
* @param {string} path - Path to normalize
|
|
227
|
+
* @returns {string} Normalized path
|
|
228
|
+
*/
|
|
229
|
+
static normalizePath(path) {
|
|
230
|
+
return path.replace(/\\/g, '/');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Join path segments safely
|
|
235
|
+
* @param {...string} segments - Path segments
|
|
236
|
+
* @returns {string} Joined path
|
|
237
|
+
*/
|
|
238
|
+
static join(...segments) {
|
|
239
|
+
return join(...segments);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get file extension from path
|
|
244
|
+
* @param {string} filePath - File path
|
|
245
|
+
* @returns {string} File extension (with dot)
|
|
246
|
+
*/
|
|
247
|
+
static getExtension(filePath) {
|
|
248
|
+
return filePath.substring(filePath.lastIndexOf('.'));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get file name without extension
|
|
253
|
+
* @param {string} filePath - File path
|
|
254
|
+
* @returns {string} File name without extension
|
|
255
|
+
*/
|
|
256
|
+
static getBaseName(filePath) {
|
|
257
|
+
const name = basename(filePath);
|
|
258
|
+
const ext = this.getExtension(name);
|
|
259
|
+
return name.slice(0, -ext.length);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Check if file path indicates a standard file
|
|
264
|
+
* @param {string} filePath - File path
|
|
265
|
+
* @returns {boolean} True if it's a standard file
|
|
266
|
+
*/
|
|
267
|
+
static isStandardFile(filePath) {
|
|
268
|
+
return filePath.includes(DIRECTORIES.CORE) ||
|
|
269
|
+
filePath.includes(DIRECTORIES.AI + '/standards');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Check if file path indicates a skill file
|
|
274
|
+
* @param {string} filePath - File path
|
|
275
|
+
* @returns {boolean} True if it's a skill file
|
|
276
|
+
*/
|
|
277
|
+
static isSkillFile(filePath) {
|
|
278
|
+
return filePath.includes(DIRECTORIES.SKILLS);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Check if file path indicates an integration file
|
|
283
|
+
* @param {string} filePath - File path
|
|
284
|
+
* @returns {boolean} True if it's an integration file
|
|
285
|
+
*/
|
|
286
|
+
static isIntegrationFile(filePath) {
|
|
287
|
+
return filePath.includes(DIRECTORIES.INTEGRATIONS);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Check if file path indicates a locale file
|
|
292
|
+
* @param {string} filePath - File path
|
|
293
|
+
* @returns {boolean} True if it's a locale file
|
|
294
|
+
*/
|
|
295
|
+
static isLocaleFile(filePath) {
|
|
296
|
+
return filePath.includes(DIRECTORIES.LOCALES);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get file type from path
|
|
301
|
+
* @param {string} filePath - File path
|
|
302
|
+
* @returns {string} File type: 'standard', 'skill', 'integration', 'locale', or 'unknown'
|
|
303
|
+
*/
|
|
304
|
+
static getFileType(filePath) {
|
|
305
|
+
if (this.isStandardFile(filePath)) return 'standard';
|
|
306
|
+
if (this.isSkillFile(filePath)) return 'skill';
|
|
307
|
+
if (this.isIntegrationFile(filePath)) return 'integration';
|
|
308
|
+
if (this.isLocaleFile(filePath)) return 'locale';
|
|
309
|
+
return 'unknown';
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Convert relative path to canonical form
|
|
314
|
+
* @param {string} relativePath - Relative path from repo root
|
|
315
|
+
* @returns {string} Canonical path
|
|
316
|
+
*/
|
|
317
|
+
static canonicalizePath(relativePath) {
|
|
318
|
+
// Remove leading ./ if present
|
|
319
|
+
let canonical = relativePath.replace(/^\.\//, '');
|
|
320
|
+
|
|
321
|
+
// Ensure forward slashes
|
|
322
|
+
canonical = canonical.replace(/\\/g, '/');
|
|
323
|
+
|
|
324
|
+
// Remove trailing slash
|
|
325
|
+
canonical = canonical.replace(/\/$/, '');
|
|
326
|
+
|
|
327
|
+
return canonical;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Get all possible source locations for a file
|
|
332
|
+
* @param {string} relativePath - Relative path
|
|
333
|
+
* @returns {Array} Array of possible locations with priorities
|
|
334
|
+
*/
|
|
335
|
+
static getAllPossibleLocations(relativePath) {
|
|
336
|
+
return [
|
|
337
|
+
{
|
|
338
|
+
path: join(BUNDLED_ROOT, relativePath),
|
|
339
|
+
priority: PATH_PRIORITY.BUNDLED,
|
|
340
|
+
type: 'bundled'
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
path: join(REPO_ROOT, relativePath),
|
|
344
|
+
priority: PATH_PRIORITY.REPO,
|
|
345
|
+
type: 'repo'
|
|
346
|
+
}
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Find first existing local file for a relative path
|
|
352
|
+
* @param {string} relativePath - Relative path
|
|
353
|
+
* @returns {Object|null} First existing location or null
|
|
354
|
+
*/
|
|
355
|
+
static findFirstExisting(relativePath) {
|
|
356
|
+
const locations = this.getAllPossibleLocations(relativePath);
|
|
357
|
+
|
|
358
|
+
for (const location of locations) {
|
|
359
|
+
if (existsSync(location.path)) {
|
|
360
|
+
return location;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Legacy compatibility functions
|
|
370
|
+
* These maintain compatibility with existing code
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get source file path (legacy compatibility)
|
|
375
|
+
* @param {string} sourcePath - Relative path
|
|
376
|
+
* @returns {string|null} Absolute path or null
|
|
377
|
+
*/
|
|
378
|
+
export function getSourcePath(sourcePath) {
|
|
379
|
+
return PathResolver.getStandardSource(sourcePath);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Get repository root path (legacy compatibility)
|
|
384
|
+
* @returns {string} Repository root path
|
|
385
|
+
*/
|
|
386
|
+
export function getRepoRoot() {
|
|
387
|
+
return PathResolver.getRepoRoot();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get bundled files directory path (legacy compatibility)
|
|
392
|
+
* @returns {string} Bundled root path
|
|
393
|
+
*/
|
|
394
|
+
export function getBundledRoot() {
|
|
395
|
+
return PathResolver.getBundledRoot();
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export default PathResolver;
|
package/src/prompts/init.js
CHANGED
|
@@ -237,11 +237,13 @@ export async function promptCommandsInstallation(selectedTools = []) {
|
|
|
237
237
|
const config = getAgentConfig(tool);
|
|
238
238
|
const displayName = getAgentDisplayName(tool);
|
|
239
239
|
|
|
240
|
-
// User level option
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
240
|
+
// User level option (skip if user path is null - e.g., Copilot only supports VS Code IDE)
|
|
241
|
+
if (config.commands.user) {
|
|
242
|
+
choices.push({
|
|
243
|
+
name: `${chalk.blue(displayName)} - ${msg.choices.userLevel} ${chalk.gray(`(${config.commands.user.replace(os.homedir(), '~')})`)}`,
|
|
244
|
+
value: `${tool}:user`
|
|
245
|
+
});
|
|
246
|
+
}
|
|
245
247
|
|
|
246
248
|
// Project level option
|
|
247
249
|
choices.push({
|