universal-dev-standards 3.5.0-beta.12 → 3.5.0-beta.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-dev-standards",
3
- "version": "3.5.0-beta.12",
3
+ "version": "3.5.0-beta.14",
4
4
  "description": "CLI tool for adopting Universal Development Standards",
5
5
  "keywords": [
6
6
  "documentation",
@@ -13,7 +13,7 @@ import {
13
13
  compareFileHash,
14
14
  hasFileHashes
15
15
  } from '../utils/hasher.js';
16
- import { downloadFromGitHub } from '../utils/github.js';
16
+ import { downloadFromGitHub, getMarketplaceSkillsInfo } from '../utils/github.js';
17
17
  import {
18
18
  parseReferences,
19
19
  compareStandardsWithReferences
@@ -619,6 +619,11 @@ async function migrateToHashBasedTracking(projectPath, manifest) {
619
619
  */
620
620
  function displaySkillsStatus(manifest, projectPath) {
621
621
  console.log(chalk.cyan('Skills Status:'));
622
+
623
+ // Check which skills-compatible tools are configured
624
+ const hasClaudeCode = manifest.aiTools?.includes('claude-code');
625
+ const hasOpenCode = manifest.aiTools?.includes('opencode');
626
+
622
627
  if (manifest.skills.installed) {
623
628
  const location = manifest.skills.location || '';
624
629
  // Check if skills are installed via Plugin Marketplace
@@ -629,8 +634,20 @@ function displaySkillsStatus(manifest, projectPath) {
629
634
 
630
635
  if (isMarketplace) {
631
636
  console.log(chalk.green(' ✓ Skills installed via Plugin Marketplace'));
637
+
638
+ // Try to get actual version from marketplace
639
+ const marketplaceInfo = getMarketplaceSkillsInfo();
640
+ if (marketplaceInfo && marketplaceInfo.version && marketplaceInfo.version !== 'unknown') {
641
+ console.log(chalk.gray(` Version: ${marketplaceInfo.version}`));
642
+ if (marketplaceInfo.lastUpdated) {
643
+ const updateDate = marketplaceInfo.lastUpdated.split('T')[0];
644
+ console.log(chalk.gray(` Last updated: ${updateDate}`));
645
+ }
646
+ } else {
647
+ console.log(chalk.gray(' Version: (run /plugin list to check)'));
648
+ }
649
+
632
650
  console.log(chalk.gray(' Managed by Claude Code plugin system'));
633
- console.log(chalk.gray(' To verify: /plugin list'));
634
651
  console.log(chalk.gray(' Note: Marketplace skills are not file-based'));
635
652
  } else {
636
653
  const skillsDir = join(process.env.HOME || '', '.claude', 'skills');
@@ -638,9 +655,23 @@ function displaySkillsStatus(manifest, projectPath) {
638
655
  const hasProjectSkills = existsSync(join(projectPath, '.claude', 'skills'));
639
656
 
640
657
  if (hasGlobalSkills || hasProjectSkills) {
641
- console.log(chalk.green(' ✓ Claude Code Skills installed'));
658
+ console.log(chalk.green(' ✓ Skills installed'));
642
659
  if (hasGlobalSkills) console.log(chalk.gray(' Global: ~/.claude/skills/'));
643
660
  if (hasProjectSkills) console.log(chalk.gray(' Project: .claude/skills/'));
661
+
662
+ // Show compatible tools
663
+ const compatibleTools = [];
664
+ if (hasClaudeCode) compatibleTools.push('Claude Code');
665
+ if (hasOpenCode) compatibleTools.push('OpenCode');
666
+ if (compatibleTools.length > 0) {
667
+ console.log(chalk.gray(` Compatible: ${compatibleTools.join(', ')}`));
668
+ }
669
+
670
+ // OpenCode auto-detection note (only if OpenCode is configured without Claude Code)
671
+ if (hasOpenCode && !hasClaudeCode) {
672
+ console.log(chalk.gray(' Note: OpenCode auto-detects .claude/skills/'));
673
+ }
674
+
644
675
  // Migration suggestion
645
676
  console.log(chalk.yellow(' ⚠ Consider migrating to Plugin Marketplace'));
646
677
  console.log(chalk.gray(' Marketplace provides automatic updates and easier management.'));
@@ -655,6 +686,14 @@ function displaySkillsStatus(manifest, projectPath) {
655
686
  console.log(chalk.gray(' Then reinitialize: uds init --yes'));
656
687
  }
657
688
  }
689
+
690
+ // Show compatible tools for marketplace installation too
691
+ if (isMarketplace && (hasClaudeCode || hasOpenCode)) {
692
+ const compatibleTools = [];
693
+ if (hasClaudeCode) compatibleTools.push('Claude Code');
694
+ if (hasOpenCode) compatibleTools.push('OpenCode');
695
+ console.log(chalk.gray(` Compatible: ${compatibleTools.join(', ')}`));
696
+ }
658
697
  } else {
659
698
  console.log(chalk.gray(' Skills not installed (using reference documents only)'));
660
699
  }
@@ -178,12 +178,17 @@ export async function initCommand(options) {
178
178
  aiTools = handleAgentsMdSharing(aiTools);
179
179
 
180
180
  const useClaudeCode = aiTools.includes('claude-code');
181
- const onlyClaudeCode = aiTools.length === 1 && useClaudeCode;
182
-
183
- // STEP 4: Skills handling (only if Claude Code is the ONLY selected tool)
184
- // When other AI tools are also selected, they need full standards,
181
+ const useOpenCode = aiTools.includes('opencode');
182
+ const supportsSkills = useClaudeCode || useOpenCode;
183
+ // Skills-compatible tools: Claude Code and OpenCode (both auto-detect .claude/skills/)
184
+ const onlySkillsTools = aiTools.every(tool =>
185
+ tool === 'claude-code' || tool === 'opencode'
186
+ );
187
+
188
+ // STEP 4: Skills handling (only if ALL selected tools support Skills)
189
+ // When other AI tools (Cursor, Cline, etc.) are also selected, they need full standards,
185
190
  // so we skip the Skills prompt to avoid minimal installation affecting them
186
- if (onlyClaudeCode) {
191
+ if (supportsSkills && onlySkillsTools) {
187
192
  const projectSkillsInfo = getProjectInstalledSkillsInfo(projectPath);
188
193
  const userSkillsInfo = getInstalledSkillsInfo();
189
194
  const repoInfo = getRepositoryInfo();
@@ -240,7 +245,7 @@ export async function initCommand(options) {
240
245
  console.log(chalk.cyan('Skills Status:'));
241
246
  console.log(chalk.gray(' No Skills installation detected'));
242
247
 
243
- const location = await promptSkillsInstallLocation();
248
+ const location = await promptSkillsInstallLocation(aiTools);
244
249
  if (location !== 'none') {
245
250
  skillsConfig = {
246
251
  installed: true,
@@ -356,8 +361,26 @@ export async function initCommand(options) {
356
361
  test_levels: options.testLevels ? options.testLevels.split(',') : ['unit-testing', 'integration-testing']
357
362
  };
358
363
 
359
- // Handle Skills configuration based on CLI flag (default: marketplace)
360
- const skillsLocationFlag = options.skillsLocation || 'marketplace';
364
+ // Determine AI tools from detection for skills compatibility check
365
+ const detectedAiTools = Object.keys(detected.aiTools).filter(k => detected.aiTools[k]);
366
+ // Map detected keys to standard tool names
367
+ const aiToolsNormalized = detectedAiTools.map(k => {
368
+ if (k === 'claudeCode') return 'claude-code';
369
+ if (k === 'geminiCli') return 'gemini-cli';
370
+ return k;
371
+ });
372
+
373
+ // Check if only skills-compatible tools are detected
374
+ const hasSkillsCompatibleTool = aiToolsNormalized.some(t => t === 'claude-code' || t === 'opencode');
375
+ const onlySkillsCompatibleTools = aiToolsNormalized.every(t => t === 'claude-code' || t === 'opencode');
376
+
377
+ // Handle Skills configuration based on CLI flag
378
+ // Default: marketplace only if all detected tools support skills
379
+ // If non-skills tools are detected, default to 'none' (full standards)
380
+ let skillsLocationFlag = options.skillsLocation;
381
+ if (!skillsLocationFlag) {
382
+ skillsLocationFlag = (hasSkillsCompatibleTool && onlySkillsCompatibleTools) ? 'marketplace' : 'none';
383
+ }
361
384
 
362
385
  // Content mode from CLI flag (default: index for best balance)
363
386
  const contentModeFlag = options.contentMode || 'index';
@@ -83,12 +83,27 @@ export async function promptAITools(detected = {}) {
83
83
 
84
84
  /**
85
85
  * Prompt for Skills installation location
86
+ * @param {string[]} selectedTools - Selected AI tools (for displaying compatibility info)
86
87
  * @returns {Promise<string>} 'user', 'project', or 'none'
87
88
  */
88
- export async function promptSkillsInstallLocation() {
89
+ export async function promptSkillsInstallLocation(selectedTools = []) {
90
+ const hasClaudeCode = selectedTools.includes('claude-code');
91
+ const hasOpenCode = selectedTools.includes('opencode');
92
+
93
+ // Build compatible tools list
94
+ const compatibleTools = [];
95
+ if (hasClaudeCode) compatibleTools.push('Claude Code');
96
+ if (hasOpenCode) compatibleTools.push('OpenCode');
97
+
89
98
  console.log();
90
99
  console.log(chalk.cyan('Skills Installation:'));
91
- console.log(chalk.gray(' Choose where to install Claude Code Skills'));
100
+ if (compatibleTools.length > 1) {
101
+ console.log(chalk.gray(` Skills will work with: ${compatibleTools.join(' and ')}`));
102
+ } else if (compatibleTools.length === 1) {
103
+ console.log(chalk.gray(` Choose where to install ${compatibleTools[0]} Skills`));
104
+ } else {
105
+ console.log(chalk.gray(' Choose where to install Skills'));
106
+ }
92
107
  console.log();
93
108
 
94
109
  const { location } = await inquirer.prompt([
@@ -453,6 +453,54 @@ export function installSkillToDir(skillName, targetBaseDir) {
453
453
  };
454
454
  }
455
455
 
456
+ /**
457
+ * Get Plugin Marketplace installed skills info
458
+ * Reads from ~/.claude/plugins/installed_plugins.json
459
+ * @returns {Object|null} Marketplace skills info or null
460
+ */
461
+ export function getMarketplaceSkillsInfo() {
462
+ const pluginsFile = join(homedir(), '.claude', 'plugins', 'installed_plugins.json');
463
+
464
+ if (!existsSync(pluginsFile)) {
465
+ return null;
466
+ }
467
+
468
+ try {
469
+ const data = JSON.parse(readFileSync(pluginsFile, 'utf-8'));
470
+ const plugins = data.plugins || {};
471
+
472
+ // Look for universal-dev-standards plugin (various marketplace keys)
473
+ const udsKeys = Object.keys(plugins).filter(key =>
474
+ key.includes('universal-dev-standards')
475
+ );
476
+
477
+ if (udsKeys.length === 0) {
478
+ return null;
479
+ }
480
+
481
+ // Get the first matching plugin info
482
+ const pluginKey = udsKeys[0];
483
+ const pluginInfo = plugins[pluginKey];
484
+
485
+ if (!pluginInfo || pluginInfo.length === 0) {
486
+ return null;
487
+ }
488
+
489
+ const info = pluginInfo[0];
490
+ return {
491
+ installed: true,
492
+ version: info.version || 'unknown',
493
+ installPath: info.installPath || null,
494
+ installedAt: info.installedAt || null,
495
+ lastUpdated: info.lastUpdated || null,
496
+ source: 'marketplace',
497
+ pluginKey
498
+ };
499
+ } catch {
500
+ return null;
501
+ }
502
+ }
503
+
456
504
  /**
457
505
  * Download and install a single Skill to a specific target directory
458
506
  * @param {string} skillName - Skill name
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "3.5.0-beta.12",
4
- "lastUpdated": "2026-01-12",
3
+ "version": "3.5.0-beta.14",
4
+ "lastUpdated": "2026-01-14",
5
5
  "description": "Standards registry for universal-dev-standards with integrated skills and AI-optimized formats",
6
6
  "formats": {
7
7
  "ai": {
@@ -48,14 +48,14 @@
48
48
  "standards": {
49
49
  "name": "universal-dev-standards",
50
50
  "url": "https://github.com/AsiaOstrich/universal-dev-standards",
51
- "version": "3.5.0-beta.12"
51
+ "version": "3.5.0-beta.14"
52
52
  },
53
53
  "skills": {
54
54
  "name": "universal-dev-standards",
55
55
  "url": "https://github.com/AsiaOstrich/universal-dev-standards",
56
56
  "localPath": "skills/claude-code",
57
57
  "rawUrl": "https://raw.githubusercontent.com/AsiaOstrich/universal-dev-standards/main/skills/claude-code",
58
- "version": "3.5.0-beta.12",
58
+ "version": "3.5.0-beta.14",
59
59
  "note": "Skills are now included in the main repository under skills/"
60
60
  }
61
61
  },