universal-dev-standards 3.5.1-beta.3 → 3.5.1-beta.5

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.1-beta.3",
3
+ "version": "3.5.1-beta.5",
4
4
  "description": "CLI tool for adopting Universal Development Standards",
5
5
  "keywords": [
6
6
  "documentation",
@@ -26,6 +26,7 @@ import {
26
26
  } from '../utils/skills-installer.js';
27
27
  import {
28
28
  getAgentDisplayName,
29
+ getAgentConfig,
29
30
  getSkillsDirForAgent,
30
31
  getCommandsDirForAgent
31
32
  } from '../config/ai-agent-paths.js';
@@ -404,6 +405,83 @@ export async function updateCommand(options) {
404
405
  }
405
406
  }
406
407
 
408
+ // Check for new features (Skills/Commands) not yet installed
409
+ if (!options.standardsOnly) {
410
+ const { missingSkills, missingCommands } = checkNewFeatures(projectPath, manifest);
411
+
412
+ if (missingSkills.length > 0 || missingCommands.length > 0) {
413
+ if (!options.yes) {
414
+ // Interactive mode: prompt user to install
415
+ const { installSkills, installCommands } = await promptNewFeatureInstallation(
416
+ missingSkills,
417
+ missingCommands
418
+ );
419
+
420
+ // Install Skills if user agreed
421
+ if (installSkills.length > 0) {
422
+ const skillSpinner = ora(msg.installingNewSkills || 'Installing Skills...').start();
423
+ const skillResult = await installSkillsToMultipleAgents(installSkills, null, projectPath);
424
+
425
+ // Update manifest
426
+ if (!manifest.skills) manifest.skills = {};
427
+ manifest.skills.installed = true;
428
+ manifest.skills.version = repoInfo.skills.version;
429
+ manifest.skills.installations = [
430
+ ...(manifest.skills.installations || []),
431
+ ...installSkills
432
+ ];
433
+
434
+ if (skillResult.totalErrors === 0) {
435
+ skillSpinner.succeed((msg.newSkillsInstalled || 'Installed Skills for {count} AI tools')
436
+ .replace('{count}', installSkills.length));
437
+ } else {
438
+ skillSpinner.warn((msg.newSkillsInstalledWithErrors || 'Installed Skills with {errors} errors')
439
+ .replace('{errors}', skillResult.totalErrors));
440
+ }
441
+ }
442
+
443
+ // Install Commands if user agreed
444
+ if (installCommands.length > 0) {
445
+ const cmdSpinner = ora(msg.installingNewCommands || 'Installing commands...').start();
446
+ const cmdResult = await installCommandsToMultipleAgents(installCommands, null, projectPath);
447
+
448
+ // Update manifest
449
+ if (!manifest.commands) manifest.commands = {};
450
+ manifest.commands.installed = true;
451
+ manifest.commands.installations = [
452
+ ...(manifest.commands.installations || []),
453
+ ...installCommands
454
+ ];
455
+
456
+ if (cmdResult.totalErrors === 0) {
457
+ cmdSpinner.succeed((msg.newCommandsInstalled || 'Installed commands for {count} AI tools')
458
+ .replace('{count}', installCommands.length));
459
+ } else {
460
+ cmdSpinner.warn((msg.newCommandsInstalledWithErrors || 'Installed commands with {errors} errors')
461
+ .replace('{errors}', cmdResult.totalErrors));
462
+ }
463
+ }
464
+
465
+ // Write updated manifest if anything was installed
466
+ if (installSkills.length > 0 || installCommands.length > 0) {
467
+ writeManifest(manifest, projectPath);
468
+ }
469
+ } else {
470
+ // --yes mode: show hint but don't auto-install (conservative behavior)
471
+ console.log();
472
+ console.log(chalk.cyan(msg.newFeaturesAvailableHint || 'Note: New features available for your AI tools'));
473
+ if (missingSkills.length > 0) {
474
+ const toolNames = missingSkills.map(s => s.displayName).join(', ');
475
+ console.log(chalk.gray(` • Skills (${toolNames}): run "uds update --skills" or "uds init" to install`));
476
+ }
477
+ if (missingCommands.length > 0) {
478
+ const toolNames = missingCommands.map(c => c.displayName).join(', ');
479
+ console.log(chalk.gray(` • Commands (${toolNames}): run "uds update --commands" or "uds init" to install`));
480
+ }
481
+ }
482
+ }
483
+ }
484
+
407
485
  // Skills update reminder
408
486
  if (manifest.skills?.installed) {
409
487
  const skillsVersion = repoInfo.skills.version;
@@ -835,3 +913,153 @@ async function updateCommandsOnly(projectPath, manifest) {
835
913
  console.log();
836
914
  process.exit(0);
837
915
  }
916
+
917
+ /**
918
+ * Check manifest.aiTools and detect missing Skills/Commands
919
+ * @param {string} projectPath - Project path
920
+ * @param {Object} manifest - Manifest object
921
+ * @returns {{missingSkills: Array, missingCommands: Array}}
922
+ */
923
+ function checkNewFeatures(projectPath, manifest) {
924
+ const aiTools = manifest.aiTools || [];
925
+
926
+ if (aiTools.length === 0) {
927
+ return { missingSkills: [], missingCommands: [] };
928
+ }
929
+
930
+ const missingSkills = [];
931
+ const missingCommands = [];
932
+
933
+ for (const tool of aiTools) {
934
+ const config = getAgentConfig(tool);
935
+ if (!config) continue;
936
+
937
+ // Check Skills support
938
+ if (config.supportsSkills && config.skills) {
939
+ // Check if skills are installed for this agent
940
+ const projectInfo = getInstalledSkillsInfoForAgent(tool, 'project', projectPath);
941
+ const userInfo = getInstalledSkillsInfoForAgent(tool, 'user');
942
+
943
+ // Check if already in manifest.skills.installations
944
+ const existingInstallations = manifest.skills?.installations || [];
945
+ const isInManifest = existingInstallations.some(
946
+ inst => inst.agent === tool || (inst.agent === 'claude-code' && tool === 'claude-code')
947
+ );
948
+
949
+ // Check if using marketplace (Claude Code only)
950
+ const usingMarketplace = manifest.skills?.location === 'marketplace' && tool === 'claude-code';
951
+
952
+ const hasSkills = projectInfo?.installed || userInfo?.installed || isInManifest || usingMarketplace;
953
+
954
+ if (!hasSkills) {
955
+ missingSkills.push({
956
+ agent: tool,
957
+ displayName: getAgentDisplayName(tool),
958
+ paths: config.skills
959
+ });
960
+ }
961
+ }
962
+
963
+ // Check Commands support
964
+ if (config.commands !== null && config.commands) {
965
+ const cmdInfo = getInstalledCommandsForAgent(tool, projectPath);
966
+
967
+ // Check if already in manifest.commands.installations
968
+ const existingCmdInstallations = manifest.commands?.installations || [];
969
+ const isInCmdManifest = existingCmdInstallations.includes(tool);
970
+
971
+ const hasCommands = cmdInfo?.installed || isInCmdManifest;
972
+
973
+ if (!hasCommands) {
974
+ missingCommands.push({
975
+ agent: tool,
976
+ displayName: getAgentDisplayName(tool),
977
+ path: config.commands.project
978
+ });
979
+ }
980
+ }
981
+ }
982
+
983
+ return { missingSkills, missingCommands };
984
+ }
985
+
986
+ /**
987
+ * Prompt user to install new features discovered during update
988
+ * @param {Array} missingSkills - Array of {agent, displayName, paths}
989
+ * @param {Array} missingCommands - Array of {agent, displayName, path}
990
+ * @returns {Promise<{installSkills: Array, installCommands: Array}>}
991
+ */
992
+ async function promptNewFeatureInstallation(missingSkills, missingCommands) {
993
+ const msg = t().commands.update;
994
+
995
+ // If nothing missing, return empty
996
+ if (missingSkills.length === 0 && missingCommands.length === 0) {
997
+ return { installSkills: [], installCommands: [] };
998
+ }
999
+
1000
+ console.log();
1001
+ console.log(chalk.cyan('━'.repeat(50)));
1002
+ console.log(chalk.cyan.bold(msg.newFeaturesAvailable || 'New Features Available'));
1003
+ console.log(chalk.cyan('━'.repeat(50)));
1004
+ console.log();
1005
+
1006
+ const result = { installSkills: [], installCommands: [] };
1007
+
1008
+ // Handle missing Skills
1009
+ if (missingSkills.length > 0) {
1010
+ console.log(chalk.yellow(msg.skillsNotInstalledFor || 'Skills not yet installed for these AI tools:'));
1011
+ for (const skill of missingSkills) {
1012
+ console.log(chalk.gray(` • ${skill.displayName}`));
1013
+ }
1014
+ console.log();
1015
+
1016
+ const { shouldInstallSkills } = await inquirer.prompt([{
1017
+ type: 'confirm',
1018
+ name: 'shouldInstallSkills',
1019
+ message: msg.installSkillsNow || 'Would you like to install Skills for these AI tools?',
1020
+ default: true
1021
+ }]);
1022
+
1023
+ if (shouldInstallSkills) {
1024
+ // Prompt for installation level
1025
+ const { skillsLevel } = await inquirer.prompt([{
1026
+ type: 'list',
1027
+ name: 'skillsLevel',
1028
+ message: msg.skillsLevelQuestion || 'Where should Skills be installed?',
1029
+ choices: [
1030
+ { name: `${msg.projectLevel || 'Project level'} (.claude/skills/, etc.)`, value: 'project' },
1031
+ { name: `${msg.userLevel || 'User level'} (~/.claude/skills/, etc.)`, value: 'user' }
1032
+ ],
1033
+ default: 'project'
1034
+ }]);
1035
+
1036
+ result.installSkills = missingSkills.map(s => ({
1037
+ agent: s.agent,
1038
+ level: skillsLevel
1039
+ }));
1040
+ }
1041
+ console.log();
1042
+ }
1043
+
1044
+ // Handle missing Commands
1045
+ if (missingCommands.length > 0) {
1046
+ console.log(chalk.yellow(msg.commandsNotInstalledFor || 'Slash commands not yet installed for these AI tools:'));
1047
+ for (const cmd of missingCommands) {
1048
+ console.log(chalk.gray(` • ${cmd.displayName} → ${cmd.path}`));
1049
+ }
1050
+ console.log();
1051
+
1052
+ const { shouldInstallCommands } = await inquirer.prompt([{
1053
+ type: 'confirm',
1054
+ name: 'shouldInstallCommands',
1055
+ message: msg.installCommandsNow || 'Would you like to install slash commands for these AI tools?',
1056
+ default: true
1057
+ }]);
1058
+
1059
+ if (shouldInstallCommands) {
1060
+ result.installCommands = missingCommands.map(c => c.agent);
1061
+ }
1062
+ }
1063
+
1064
+ return result;
1065
+ }
@@ -744,7 +744,23 @@ export const messages = {
744
744
  categoriesChanged: 'Categories: {old} → {new}',
745
745
  failedToUpdate: '✗ Failed to update {path}: {error}',
746
746
  updatedCount: '✓ Updated {count} integration file(s)',
747
- skippedCount: 'Skipped {count} file(s) (already in sync or not found)'
747
+ skippedCount: 'Skipped {count} file(s) (already in sync or not found)',
748
+ // New features discovery
749
+ newFeaturesAvailable: 'New Features Available',
750
+ newFeaturesAvailableHint: 'Note: New features available for your AI tools',
751
+ skillsNotInstalledFor: 'Skills not yet installed for these AI tools:',
752
+ commandsNotInstalledFor: 'Slash commands not yet installed for these AI tools:',
753
+ installSkillsNow: 'Would you like to install Skills for these AI tools?',
754
+ installCommandsNow: 'Would you like to install slash commands for these AI tools?',
755
+ skillsLevelQuestion: 'Where should Skills be installed?',
756
+ projectLevel: 'Project level',
757
+ userLevel: 'User level',
758
+ installingNewSkills: 'Installing Skills...',
759
+ installingNewCommands: 'Installing commands...',
760
+ newSkillsInstalled: 'Installed Skills for {count} AI tools',
761
+ newSkillsInstalledWithErrors: 'Installed Skills with {errors} errors',
762
+ newCommandsInstalled: 'Installed commands for {count} AI tools',
763
+ newCommandsInstalledWithErrors: 'Installed commands with {errors} errors'
748
764
  },
749
765
 
750
766
  // configure command
@@ -1553,7 +1569,23 @@ export const messages = {
1553
1569
  categoriesChanged: '分類:{old} → {new}',
1554
1570
  failedToUpdate: '✗ 更新 {path} 失敗:{error}',
1555
1571
  updatedCount: '✓ 已更新 {count} 個整合檔案',
1556
- skippedCount: '已跳過 {count} 個檔案(已同步或找不到)'
1572
+ skippedCount: '已跳過 {count} 個檔案(已同步或找不到)',
1573
+ // New features discovery
1574
+ newFeaturesAvailable: '發現新功能',
1575
+ newFeaturesAvailableHint: '提示:您的 AI 工具有新功能可用',
1576
+ skillsNotInstalledFor: '以下 AI 工具尚未安裝 Skills:',
1577
+ commandsNotInstalledFor: '以下 AI 工具尚未安裝斜線命令:',
1578
+ installSkillsNow: '是否要為這些 AI 工具安裝 Skills?',
1579
+ installCommandsNow: '是否要為這些 AI 工具安裝斜線命令?',
1580
+ skillsLevelQuestion: 'Skills 要安裝到哪裡?',
1581
+ projectLevel: '專案層級',
1582
+ userLevel: '使用者層級',
1583
+ installingNewSkills: '安裝 Skills 中...',
1584
+ installingNewCommands: '安裝斜線命令中...',
1585
+ newSkillsInstalled: '已為 {count} 個 AI 工具安裝 Skills',
1586
+ newSkillsInstalledWithErrors: '安裝 Skills 時發生 {errors} 個錯誤',
1587
+ newCommandsInstalled: '已為 {count} 個 AI 工具安裝斜線命令',
1588
+ newCommandsInstalledWithErrors: '安裝斜線命令時發生 {errors} 個錯誤'
1557
1589
  },
1558
1590
 
1559
1591
  // configure command
@@ -2194,7 +2226,23 @@ export const messages = {
2194
2226
  categoriesChanged: '类别:{old} → {new}',
2195
2227
  failedToUpdate: '✗ 更新 {path} 失败:{error}',
2196
2228
  updatedCount: '✓ 已更新 {count} 个集成文件',
2197
- skippedCount: '跳过 {count} 个文件(已同步或未找到)'
2229
+ skippedCount: '跳过 {count} 个文件(已同步或未找到)',
2230
+ // New features discovery
2231
+ newFeaturesAvailable: '发现新功能',
2232
+ newFeaturesAvailableHint: '提示:您的 AI 工具有新功能可用',
2233
+ skillsNotInstalledFor: '以下 AI 工具尚未安装 Skills:',
2234
+ commandsNotInstalledFor: '以下 AI 工具尚未安装斜线命令:',
2235
+ installSkillsNow: '是否要为这些 AI 工具安装 Skills?',
2236
+ installCommandsNow: '是否要为这些 AI 工具安装斜线命令?',
2237
+ skillsLevelQuestion: 'Skills 要安装到哪里?',
2238
+ projectLevel: '项目级别',
2239
+ userLevel: '用户级别',
2240
+ installingNewSkills: '正在安装 Skills...',
2241
+ installingNewCommands: '正在安装斜线命令...',
2242
+ newSkillsInstalled: '已为 {count} 个 AI 工具安装 Skills',
2243
+ newSkillsInstalledWithErrors: '安装 Skills 时发生 {errors} 个错误',
2244
+ newCommandsInstalled: '已为 {count} 个 AI 工具安装斜线命令',
2245
+ newCommandsInstalledWithErrors: '安装斜线命令时发生 {errors} 个错误'
2198
2246
  },
2199
2247
 
2200
2248
  // configure command
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "version": "3.5.1-beta.3",
3
+ "version": "3.5.1-beta.5",
4
4
  "lastUpdated": "2026-01-15",
5
5
  "description": "Standards registry for universal-dev-standards with integrated skills and AI-optimized formats",
6
6
  "formats": {
@@ -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.1-beta.3"
51
+ "version": "3.5.1-beta.5"
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.1-beta.3",
58
+ "version": "3.5.1-beta.5",
59
59
  "note": "Skills are now included in the main repository under skills/"
60
60
  }
61
61
  },