universal-dev-standards 3.5.0 → 3.5.1-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-dev-standards",
3
- "version": "3.5.0",
3
+ "version": "3.5.1-beta.1",
4
4
  "description": "CLI tool for adopting Universal Development Standards",
5
5
  "keywords": [
6
6
  "documentation",
@@ -15,6 +15,14 @@ import {
15
15
  hasFileHashes
16
16
  } from '../utils/hasher.js';
17
17
  import { downloadFromGitHub, getMarketplaceSkillsInfo } from '../utils/github.js';
18
+ import {
19
+ getInstalledSkillsInfoForAgent,
20
+ getInstalledCommandsForAgent
21
+ } from '../utils/skills-installer.js';
22
+ import {
23
+ getAgentConfig,
24
+ getAgentDisplayName
25
+ } from '../config/ai-agent-paths.js';
18
26
  import {
19
27
  parseReferences,
20
28
  compareStandardsWithReferences
@@ -640,83 +648,110 @@ async function migrateToHashBasedTracking(projectPath, manifest) {
640
648
  function displaySkillsStatus(manifest, projectPath, msg) {
641
649
  console.log(chalk.cyan(msg.skillsStatus));
642
650
 
643
- // Check which skills-compatible tools are configured
644
- const hasClaudeCode = manifest.aiTools?.includes('claude-code');
645
- const hasOpenCode = manifest.aiTools?.includes('opencode');
646
-
647
- if (manifest.skills.installed) {
648
- const location = manifest.skills.location || '';
649
- // Check if skills are installed via Plugin Marketplace
650
- // Recognized patterns: 'marketplace', or paths containing 'plugins/cache'
651
- const isMarketplace = location === 'marketplace' ||
652
- location.includes('plugins/cache') ||
653
- location.includes('plugins\\cache');
654
-
655
- if (isMarketplace) {
656
- console.log(chalk.green(` ${msg.skillsViaMarketplace}`));
657
-
658
- // Try to get actual version from marketplace
659
- const marketplaceInfo = getMarketplaceSkillsInfo();
660
- if (marketplaceInfo && marketplaceInfo.version && marketplaceInfo.version !== 'unknown') {
661
- console.log(chalk.gray(` ${t().commands.common.version}: ${marketplaceInfo.version}`));
662
- if (marketplaceInfo.lastUpdated) {
663
- const updateDate = marketplaceInfo.lastUpdated.split('T')[0];
664
- console.log(chalk.gray(` ${msg.lastUpdated}: ${updateDate}`));
665
- }
666
- } else {
667
- console.log(chalk.gray(` ${t().commands.common.version}: (run /plugin list to check)`));
668
- }
651
+ const aiTools = manifest.aiTools || [];
652
+
653
+ // If no AI tools configured, show basic info
654
+ if (aiTools.length === 0) {
655
+ console.log(chalk.gray(` ${msg.noAiToolsConfigured || 'No AI tools configured'}`));
656
+ console.log();
657
+ return;
658
+ }
669
659
 
670
- console.log(chalk.gray(` ${msg.skillsManaged}`));
671
- console.log(chalk.gray(` ${msg.skillsNotFileBased}`));
660
+ // Check for Marketplace installation (Claude Code specific)
661
+ const hasClaudeCode = aiTools.includes('claude-code');
662
+ const location = manifest.skills?.location || '';
663
+ const isMarketplace = location === 'marketplace' ||
664
+ location.includes('plugins/cache') ||
665
+ location.includes('plugins\\cache');
666
+
667
+ if (isMarketplace && hasClaudeCode) {
668
+ console.log(chalk.green(` ${msg.skillsViaMarketplace}`));
669
+
670
+ // Try to get actual version from marketplace
671
+ const marketplaceInfo = getMarketplaceSkillsInfo();
672
+ if (marketplaceInfo && marketplaceInfo.version && marketplaceInfo.version !== 'unknown') {
673
+ console.log(chalk.gray(` ${t().commands.common.version}: ${marketplaceInfo.version}`));
674
+ if (marketplaceInfo.lastUpdated) {
675
+ const updateDate = marketplaceInfo.lastUpdated.split('T')[0];
676
+ console.log(chalk.gray(` ${msg.lastUpdated}: ${updateDate}`));
677
+ }
672
678
  } else {
673
- const skillsDir = join(process.env.HOME || '', '.claude', 'skills');
674
- const hasGlobalSkills = existsSync(skillsDir);
675
- const hasProjectSkills = existsSync(join(projectPath, '.claude', 'skills'));
676
-
677
- if (hasGlobalSkills || hasProjectSkills) {
678
- console.log(chalk.green(` ${msg.skillsInstalled}`));
679
- if (hasGlobalSkills) console.log(chalk.gray(` ${msg.skillsGlobal}`));
680
- if (hasProjectSkills) console.log(chalk.gray(` ${msg.skillsProject}`));
681
-
682
- // Show compatible tools
683
- const compatibleTools = [];
684
- if (hasClaudeCode) compatibleTools.push('Claude Code');
685
- if (hasOpenCode) compatibleTools.push('OpenCode');
686
- if (compatibleTools.length > 0) {
687
- console.log(chalk.gray(` ${msg.compatible}: ${compatibleTools.join(', ')}`));
688
- }
679
+ console.log(chalk.gray(` ${t().commands.common.version}: (run /plugin list to check)`));
680
+ }
681
+
682
+ console.log(chalk.gray(` ${msg.skillsManaged}`));
683
+ console.log(chalk.gray(` ${msg.skillsNotFileBased}`));
684
+ console.log();
685
+ }
686
+
687
+ // Check each AI agent's Skills and Commands status
688
+ for (const tool of aiTools) {
689
+ const config = getAgentConfig(tool);
690
+ if (!config) continue;
689
691
 
690
- // OpenCode auto-detection note (only if OpenCode is configured without Claude Code)
691
- if (hasOpenCode && !hasClaudeCode) {
692
- console.log(chalk.gray(` ${msg.openCodeNote}`));
692
+ const displayName = getAgentDisplayName(tool);
693
+ console.log(chalk.cyan(` ${displayName}:`));
694
+
695
+ // Check Skills installation for this agent (both user and project level)
696
+ const projectSkillsInfo = getInstalledSkillsInfoForAgent(tool, 'project', projectPath);
697
+ const userSkillsInfo = getInstalledSkillsInfoForAgent(tool, 'user', projectPath);
698
+
699
+ if (projectSkillsInfo?.installed || userSkillsInfo?.installed) {
700
+ console.log(chalk.green(` ✓ Skills ${msg.installed || 'installed'}:`));
701
+ if (userSkillsInfo?.installed) {
702
+ console.log(chalk.gray(` - ${msg.skillsGlobal || 'User level'}: ${userSkillsInfo.path}`));
703
+ if (userSkillsInfo.version) {
704
+ console.log(chalk.gray(` ${t().commands.common.version}: ${userSkillsInfo.version}`));
705
+ }
706
+ }
707
+ if (projectSkillsInfo?.installed) {
708
+ console.log(chalk.gray(` - ${msg.skillsProject || 'Project level'}: ${projectSkillsInfo.path}`));
709
+ if (projectSkillsInfo.version) {
710
+ console.log(chalk.gray(` ${t().commands.common.version}: ${projectSkillsInfo.version}`));
693
711
  }
712
+ }
713
+ } else if (config.supportsSkills) {
714
+ console.log(chalk.gray(` ○ Skills: ${msg.notInstalled || 'Not installed'}`));
715
+ if (config.fallbackSkillsPath) {
716
+ // Check if can use fallback (Claude skills path)
717
+ const fallbackPath = join(projectPath, config.fallbackSkillsPath);
718
+ if (existsSync(fallbackPath)) {
719
+ console.log(chalk.gray(` ${msg.canUseFallback || 'Can use fallback'}: ${config.fallbackSkillsPath}`));
720
+ }
721
+ }
722
+ }
694
723
 
695
- // Migration suggestion
696
- console.log(chalk.yellow(` ${msg.considerMigrating}`));
697
- console.log(chalk.gray(` ${msg.marketplaceAutoUpdates}`));
698
- console.log(chalk.gray(` ${msg.toMigrate}`));
699
- console.log(chalk.gray(' 1. Install via Marketplace: /install-skills AsiaOstrich/universal-dev-skills'));
700
- console.log(chalk.gray(' 2. Remove local skills: rm -rf ~/.claude/skills/'));
701
- console.log(chalk.gray(' 3. Reinitialize: uds init --yes'));
724
+ // Check Commands installation for this agent
725
+ if (config.commands) {
726
+ const commandsInfo = getInstalledCommandsForAgent(tool, projectPath);
727
+ if (commandsInfo?.installed) {
728
+ console.log(chalk.green(` ✓ Commands: ${commandsInfo.count} ${msg.commandsInstalled || 'installed'}`));
729
+ console.log(chalk.gray(` ${msg.path || 'Path'}: ${commandsInfo.path}`));
730
+ if (commandsInfo.version) {
731
+ console.log(chalk.gray(` ${t().commands.common.version}: ${commandsInfo.version}`));
732
+ }
702
733
  } else {
703
- console.log(chalk.yellow(` ${msg.skillsMarkedNotFound}`));
704
- console.log(chalk.gray(` ${msg.recommendedInstall}`));
705
- console.log(chalk.gray(' /install-skills AsiaOstrich/universal-dev-skills'));
706
- console.log(chalk.gray(' Then reinitialize: uds init --yes'));
734
+ console.log(chalk.gray(` ○ Commands: ${msg.notInstalled || 'Not installed'}`));
707
735
  }
708
736
  }
737
+ }
709
738
 
710
- // Show compatible tools for marketplace installation too
711
- if (isMarketplace && (hasClaudeCode || hasOpenCode)) {
712
- const compatibleTools = [];
713
- if (hasClaudeCode) compatibleTools.push('Claude Code');
714
- if (hasOpenCode) compatibleTools.push('OpenCode');
715
- console.log(chalk.gray(` ${msg.compatible}: ${compatibleTools.join(', ')}`));
739
+ // Show installations tracking from manifest (if using new format)
740
+ if (manifest.skills?.installations?.length > 0) {
741
+ console.log();
742
+ console.log(chalk.gray(` ${msg.trackedInstallations || 'Tracked installations'}:`));
743
+ for (const inst of manifest.skills.installations) {
744
+ console.log(chalk.gray(` - ${inst.agent}: ${inst.level}`));
716
745
  }
717
- } else {
718
- console.log(chalk.gray(` ${msg.skillsNotInstalled}`));
719
746
  }
747
+
748
+ if (manifest.commands?.installations?.length > 0) {
749
+ console.log(chalk.gray(` ${msg.trackedCommandInstallations || 'Tracked command installations'}:`));
750
+ for (const agent of manifest.commands.installations) {
751
+ console.log(chalk.gray(` - ${agent}`));
752
+ }
753
+ }
754
+
720
755
  console.log();
721
756
  }
722
757
 
@@ -26,8 +26,20 @@ import {
26
26
  promptAdoptionLevel,
27
27
  promptContentModeChange,
28
28
  handleAgentsMdSharing,
29
- promptMethodology
29
+ promptMethodology,
30
+ promptSkillsInstallLocation,
31
+ promptCommandsInstallation
30
32
  } from '../prompts/init.js';
33
+ import {
34
+ installSkillsToMultipleAgents,
35
+ installCommandsToMultipleAgents,
36
+ getInstalledSkillsInfoForAgent,
37
+ getInstalledCommandsForAgent
38
+ } from '../utils/skills-installer.js';
39
+ import {
40
+ getAgentConfig,
41
+ getAgentDisplayName
42
+ } from '../config/ai-agent-paths.js';
31
43
  import {
32
44
  writeIntegrationFile,
33
45
  getToolFilePath
@@ -102,6 +114,9 @@ export async function configureCommand(options) {
102
114
  { name: msg.optionTestLevels, value: 'test_levels' },
103
115
  new inquirer.default.Separator(),
104
116
  { name: chalk.cyan(msg.optionAITools), value: 'ai_tools' },
117
+ { name: chalk.cyan(msg.optionSkills || 'Manage Skills installations'), value: 'skills' },
118
+ { name: chalk.cyan(msg.optionCommands || 'Manage Commands installations'), value: 'commands' },
119
+ new inquirer.default.Separator(),
105
120
  { name: chalk.cyan(msg.optionLevel), value: 'level' },
106
121
  { name: chalk.cyan(msg.optionContentMode), value: 'content_mode' }
107
122
  ];
@@ -169,6 +184,18 @@ export async function configureCommand(options) {
169
184
  }
170
185
  }
171
186
 
187
+ // Handle Skills configuration
188
+ if (configType === 'skills') {
189
+ await handleSkillsConfiguration(manifest, projectPath, msg, common);
190
+ process.exit(0);
191
+ }
192
+
193
+ // Handle Commands configuration
194
+ if (configType === 'commands') {
195
+ await handleCommandsConfiguration(manifest, projectPath, msg, common);
196
+ process.exit(0);
197
+ }
198
+
172
199
  // Handle Level configuration
173
200
  if (configType === 'level') {
174
201
  newLevel = await promptAdoptionLevel(manifest.level || 2);
@@ -418,3 +445,167 @@ export async function configureCommand(options) {
418
445
  // Exit explicitly to prevent hanging due to inquirer's readline interface
419
446
  process.exit(0);
420
447
  }
448
+
449
+ /**
450
+ * Handle Skills configuration
451
+ */
452
+ async function handleSkillsConfiguration(manifest, projectPath, msg, common) {
453
+ const inquirer = await import('inquirer');
454
+ const aiTools = manifest.aiTools || [];
455
+
456
+ if (aiTools.length === 0) {
457
+ console.log(chalk.yellow(msg.noAiToolsConfigured || 'No AI tools configured'));
458
+ console.log(chalk.gray(` ${msg.addAiToolsFirst || 'Add AI tools first with: uds configure --type ai_tools'}`));
459
+ return;
460
+ }
461
+
462
+ // Show current Skills status
463
+ console.log(chalk.cyan(msg.currentSkillsStatus || 'Current Skills status:'));
464
+ for (const tool of aiTools) {
465
+ const config = getAgentConfig(tool);
466
+ if (!config?.supportsSkills) continue;
467
+
468
+ const displayName = getAgentDisplayName(tool);
469
+ const projectInfo = getInstalledSkillsInfoForAgent(tool, 'project', projectPath);
470
+ const userInfo = getInstalledSkillsInfoForAgent(tool, 'user', projectPath);
471
+
472
+ if (projectInfo?.installed || userInfo?.installed) {
473
+ console.log(chalk.green(` ✓ ${displayName}:`));
474
+ if (userInfo?.installed) {
475
+ console.log(chalk.gray(` - User: ${userInfo.version || 'installed'}`));
476
+ }
477
+ if (projectInfo?.installed) {
478
+ console.log(chalk.gray(` - Project: ${projectInfo.version || 'installed'}`));
479
+ }
480
+ } else {
481
+ console.log(chalk.gray(` ○ ${displayName}: ${msg.notInstalled || 'Not installed'}`));
482
+ }
483
+ }
484
+ console.log();
485
+
486
+ // Ask what action to take
487
+ const { action } = await inquirer.default.prompt([
488
+ {
489
+ type: 'list',
490
+ name: 'action',
491
+ message: msg.skillsAction || 'What would you like to do?',
492
+ choices: [
493
+ { name: msg.installSkills || 'Install/Update Skills', value: 'install' },
494
+ { name: msg.viewStatus || 'View status only', value: 'view' },
495
+ { name: common.cancel || 'Cancel', value: 'cancel' }
496
+ ]
497
+ }
498
+ ]);
499
+
500
+ if (action === 'cancel' || action === 'view') {
501
+ console.log(chalk.gray(msg.noChanges || 'No changes made'));
502
+ return;
503
+ }
504
+
505
+ // Use unified installation prompt
506
+ const installations = await promptSkillsInstallLocation(aiTools);
507
+ if (installations.length === 0) {
508
+ console.log(chalk.gray(msg.noChanges || 'No changes made'));
509
+ return;
510
+ }
511
+
512
+ // Install Skills
513
+ const spinner = ora(msg.installingSkills || 'Installing Skills...').start();
514
+ const result = await installSkillsToMultipleAgents(installations, null, projectPath);
515
+ spinner.stop();
516
+
517
+ if (result.success) {
518
+ console.log(chalk.green(msg.skillsInstallSuccess || 'Skills installed successfully'));
519
+ console.log(chalk.gray(` ${msg.totalInstalled || 'Total installed'}: ${result.totalInstalled}`));
520
+ } else {
521
+ console.log(chalk.yellow(msg.skillsInstallPartial || 'Skills installed with some issues'));
522
+ if (result.totalErrors > 0) {
523
+ console.log(chalk.red(` ${msg.errors || 'Errors'}: ${result.totalErrors}`));
524
+ }
525
+ }
526
+
527
+ // Update manifest
528
+ manifest.skills = manifest.skills || {};
529
+ manifest.skills.installations = installations;
530
+ writeManifest(manifest, projectPath);
531
+ }
532
+
533
+ /**
534
+ * Handle Commands configuration
535
+ */
536
+ async function handleCommandsConfiguration(manifest, projectPath, msg, common) {
537
+ const inquirer = await import('inquirer');
538
+ const aiTools = manifest.aiTools || [];
539
+
540
+ // Filter tools that support commands
541
+ const commandSupportedTools = aiTools.filter(tool => {
542
+ const config = getAgentConfig(tool);
543
+ return config?.commands !== null;
544
+ });
545
+
546
+ if (commandSupportedTools.length === 0) {
547
+ console.log(chalk.yellow(msg.noCommandSupportedTools || 'No AI tools with command support configured'));
548
+ console.log(chalk.gray(` ${msg.commandSupportedList || 'Tools that support commands: OpenCode, Copilot, Roo Code, Gemini CLI'}`));
549
+ return;
550
+ }
551
+
552
+ // Show current Commands status
553
+ console.log(chalk.cyan(msg.currentCommandsStatus || 'Current Commands status:'));
554
+ for (const tool of commandSupportedTools) {
555
+ const displayName = getAgentDisplayName(tool);
556
+ const commandsInfo = getInstalledCommandsForAgent(tool, projectPath);
557
+
558
+ if (commandsInfo?.installed) {
559
+ console.log(chalk.green(` ✓ ${displayName}: ${commandsInfo.count} ${msg.commandsInstalled || 'commands'}`));
560
+ } else {
561
+ console.log(chalk.gray(` ○ ${displayName}: ${msg.notInstalled || 'Not installed'}`));
562
+ }
563
+ }
564
+ console.log();
565
+
566
+ // Ask what action to take
567
+ const { action } = await inquirer.default.prompt([
568
+ {
569
+ type: 'list',
570
+ name: 'action',
571
+ message: msg.commandsAction || 'What would you like to do?',
572
+ choices: [
573
+ { name: msg.installCommands || 'Install/Update Commands', value: 'install' },
574
+ { name: msg.viewStatus || 'View status only', value: 'view' },
575
+ { name: common.cancel || 'Cancel', value: 'cancel' }
576
+ ]
577
+ }
578
+ ]);
579
+
580
+ if (action === 'cancel' || action === 'view') {
581
+ console.log(chalk.gray(msg.noChanges || 'No changes made'));
582
+ return;
583
+ }
584
+
585
+ // Use unified installation prompt
586
+ const selectedAgents = await promptCommandsInstallation(commandSupportedTools);
587
+ if (selectedAgents.length === 0) {
588
+ console.log(chalk.gray(msg.noChanges || 'No changes made'));
589
+ return;
590
+ }
591
+
592
+ // Install Commands
593
+ const spinner = ora(msg.installingCommands || 'Installing Commands...').start();
594
+ const result = await installCommandsToMultipleAgents(selectedAgents, null, projectPath);
595
+ spinner.stop();
596
+
597
+ if (result.success) {
598
+ console.log(chalk.green(msg.commandsInstallSuccess || 'Commands installed successfully'));
599
+ console.log(chalk.gray(` ${msg.totalInstalled || 'Total installed'}: ${result.totalInstalled}`));
600
+ } else {
601
+ console.log(chalk.yellow(msg.commandsInstallPartial || 'Commands installed with some issues'));
602
+ if (result.totalErrors > 0) {
603
+ console.log(chalk.red(` ${msg.errors || 'Errors'}: ${result.totalErrors}`));
604
+ }
605
+ }
606
+
607
+ // Update manifest
608
+ manifest.commands = manifest.commands || {};
609
+ manifest.commands.installations = selectedAgents;
610
+ writeManifest(manifest, projectPath);
611
+ }