universal-dev-standards 3.5.1-beta.17 → 3.5.1-beta.19
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/bundled/skills/claude-code/commands/check.md +129 -53
- package/bundled/skills/claude-code/commands/config.md +105 -16
- package/bundled/skills/claude-code/commands/init.md +130 -41
- package/bundled/skills/claude-code/commands/update.md +90 -23
- package/package.json +1 -1
- package/src/commands/check.js +15 -8
- package/src/commands/configure.js +162 -10
- package/src/commands/update.js +86 -15
- package/src/i18n/messages.js +48 -6
- package/standards-registry.json +4 -4
|
@@ -77,7 +77,7 @@ Always include **Skip** option: Don't update at this time.
|
|
|
77
77
|
- Option 1: "更新至 Beta (建議)" - "更新標準至 3.5.1-beta.15 版本(🟡 功能大致完成)"
|
|
78
78
|
- Option 2: "暫時跳過" - "目前不進行更新,維持現有版本"
|
|
79
79
|
|
|
80
|
-
### Step 3: Execute | 步驟 3
|
|
80
|
+
### Step 3: Execute Update | 步驟 3:執行更新
|
|
81
81
|
|
|
82
82
|
**If Update Now selected:**
|
|
83
83
|
```bash
|
|
@@ -89,39 +89,93 @@ uds update --yes
|
|
|
89
89
|
uds update --beta --yes
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
### Step 4:
|
|
92
|
+
### Step 4: Check Skills/Commands Status | 步驟 4:檢查 Skills/Commands 狀態
|
|
93
93
|
|
|
94
|
-
After update completes,
|
|
94
|
+
After update completes, the CLI automatically detects missing or outdated Skills/Commands.
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
更新完成後,CLI 會自動偵測缺少或過時的 Skills/Commands。
|
|
97
97
|
|
|
98
|
-
**
|
|
98
|
+
**Important:** The CLI uses file-based detection (`getInstalledSkillsInfoForAgent`) to check actual installation status, not just manifest records.
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
2. Check if Skills are installed for each configured AI tool
|
|
102
|
-
3. Check if Commands are installed for tools that support them (opencode, copilot, gemini-cli, roo-code)
|
|
100
|
+
**重要:** CLI 使用檔案實際存在檢測,而非僅讀取 manifest 記錄。
|
|
103
101
|
|
|
104
|
-
|
|
102
|
+
#### Handling Missing Skills | 處理缺少的 Skills
|
|
103
|
+
|
|
104
|
+
If missing Skills are detected for configured AI tools, CLI shows checkbox selection:
|
|
105
|
+
|
|
106
|
+
如果偵測到已配置 AI 工具缺少 Skills,CLI 會顯示多選介面:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Skills not yet installed for these AI tools:
|
|
110
|
+
• Claude Code
|
|
111
|
+
• OpenCode
|
|
112
|
+
|
|
113
|
+
? Select AI tools to install Skills for: (Press <space> to select)
|
|
114
|
+
❯ ◯ Claude Code
|
|
115
|
+
◯ OpenCode
|
|
116
|
+
──────────────
|
|
117
|
+
◯ Skip Skills installation
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**After tool selection, prompt for installation level:**
|
|
105
121
|
|
|
106
122
|
| Option | Description |
|
|
107
123
|
|--------|-------------|
|
|
108
|
-
| **
|
|
109
|
-
| **
|
|
110
|
-
|
|
111
|
-
|
|
124
|
+
| **Project level** | Install to `.claude/skills/`, `.opencode/skill/`, etc. |
|
|
125
|
+
| **User level** | Install to `~/.claude/skills/`, `~/.opencode/skill/`, etc. |
|
|
126
|
+
|
|
127
|
+
#### Handling Outdated Skills | 處理過時的 Skills
|
|
128
|
+
|
|
129
|
+
If installed Skills have older version than latest, CLI shows update prompt:
|
|
130
|
+
|
|
131
|
+
如果已安裝的 Skills 版本比最新版本舊,CLI 會顯示更新提示:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
Skills updates available for these AI tools:
|
|
135
|
+
• Claude Code (project: .claude/skills/)
|
|
136
|
+
3.4.0 → 3.5.1
|
|
137
|
+
|
|
138
|
+
? Select AI tools to update Skills for: (Press <space> to select)
|
|
139
|
+
❯ ◉ Claude Code (project) 3.4.0 → 3.5.1
|
|
140
|
+
──────────────
|
|
141
|
+
◯ Skip Skills update
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Handling Missing Commands | 處理缺少的 Commands
|
|
145
|
+
|
|
146
|
+
Similar checkbox selection for Commands:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
Slash commands not yet installed for these AI tools:
|
|
150
|
+
• OpenCode → .opencode/commands/
|
|
151
|
+
• GitHub Copilot → .github/commands/
|
|
152
|
+
|
|
153
|
+
? Select AI tools to install Commands for: (Press <space> to select)
|
|
154
|
+
❯ ◉ OpenCode (.opencode/commands/)
|
|
155
|
+
◉ GitHub Copilot (.github/commands/)
|
|
156
|
+
──────────────
|
|
157
|
+
◯ Skip Commands installation
|
|
158
|
+
```
|
|
112
159
|
|
|
113
|
-
|
|
160
|
+
#### Declined Features Handling | 拒絕功能處理
|
|
114
161
|
|
|
115
|
-
|
|
116
|
-
|-----------|---------|
|
|
117
|
-
| Install All | `uds configure --type skills --ai-tool <tool>` for each tool, then `uds configure --type commands --ai-tool <tool>` |
|
|
118
|
-
| Skills Only | `uds configure --type skills --ai-tool <tool>` for each tool |
|
|
119
|
-
| Commands Only | `uds configure --type commands --ai-tool <tool>` for each tool |
|
|
120
|
-
| Skip | No action needed |
|
|
162
|
+
**Important:** The CLI tracks user's declined choices in `manifest.declinedFeatures`.
|
|
121
163
|
|
|
122
|
-
|
|
164
|
+
**重要:** CLI 會在 `manifest.declinedFeatures` 中追蹤用戶拒絕的選項。
|
|
123
165
|
|
|
124
|
-
|
|
166
|
+
- Tools that user previously declined will NOT be shown in subsequent prompts
|
|
167
|
+
- Users can reinstall declined features via `/config skills` or `/config commands`
|
|
168
|
+
- Declining is remembered per-tool (e.g., declining Skills for OpenCode doesn't affect Claude Code)
|
|
169
|
+
|
|
170
|
+
用戶之前拒絕的工具不會在後續提示中顯示。可透過 `/config skills` 或 `/config commands` 重新安裝。
|
|
171
|
+
|
|
172
|
+
### Step 5: Explain Results | 步驟 5:說明結果
|
|
173
|
+
|
|
174
|
+
After all operations complete, explain:
|
|
175
|
+
1. What was updated (standards version, file count)
|
|
176
|
+
2. Skills/Commands installation results
|
|
177
|
+
3. Any errors encountered
|
|
178
|
+
4. Next steps (restart AI tool if Skills were installed)
|
|
125
179
|
|
|
126
180
|
## Quick Mode | 快速模式
|
|
127
181
|
|
|
@@ -131,8 +185,12 @@ When invoked with `--yes` or specific options, skip interactive questions:
|
|
|
131
185
|
/update --yes # Update without confirmation
|
|
132
186
|
/update --beta --yes # Update to beta version
|
|
133
187
|
/update --offline # Skip npm registry check
|
|
188
|
+
/update --skills # Update Skills only
|
|
189
|
+
/update --commands # Update Commands only
|
|
134
190
|
```
|
|
135
191
|
|
|
192
|
+
**Note:** In `--yes` mode, CLI shows hints about available Skills/Commands but does NOT auto-install them (conservative behavior).
|
|
193
|
+
|
|
136
194
|
## Options Reference | 選項參考
|
|
137
195
|
|
|
138
196
|
| Option | Description | 說明 |
|
|
@@ -140,12 +198,17 @@ When invoked with `--yes` or specific options, skip interactive questions:
|
|
|
140
198
|
| `--yes`, `-y` | Skip confirmation prompt | 跳過確認提示 |
|
|
141
199
|
| `--offline` | Skip npm registry check | 跳過 npm registry 檢查 |
|
|
142
200
|
| `--beta` | Check for beta version updates | 檢查 beta 版本更新 |
|
|
201
|
+
| `--skills` | Update Skills only | 僅更新 Skills |
|
|
202
|
+
| `--commands` | Update Commands only | 僅更新 Commands |
|
|
203
|
+
| `--integrations-only` | Regenerate integration files only | 僅重新產生整合檔案 |
|
|
204
|
+
| `--sync-refs` | Sync integration file references | 同步整合檔案參考 |
|
|
205
|
+
| `--standards-only` | Update standards without integrations | 僅更新標準,不更新整合 |
|
|
143
206
|
|
|
144
207
|
## What Gets Updated | 更新內容
|
|
145
208
|
|
|
146
209
|
- Standard files in `.standards/` directory
|
|
147
210
|
- Extension files (language, framework, locale)
|
|
148
|
-
- Integration files (`.cursorrules`, etc.)
|
|
211
|
+
- Integration files (`.cursorrules`, `CLAUDE.md`, etc.)
|
|
149
212
|
- Version info in `manifest.json`
|
|
150
213
|
|
|
151
214
|
## Skills Update | Skills 更新
|
|
@@ -166,7 +229,11 @@ Skills are managed separately:
|
|
|
166
229
|
**"Already up to date"**
|
|
167
230
|
- No action needed; standards are current
|
|
168
231
|
|
|
232
|
+
**"Skills previously declined"**
|
|
233
|
+
- Run `/config skills` to reinstall declined Skills
|
|
234
|
+
|
|
169
235
|
## Reference | 參考
|
|
170
236
|
|
|
171
237
|
- CLI documentation: `uds update --help`
|
|
172
238
|
- Check command: [/check](./check.md)
|
|
239
|
+
- Config command: [/config](./config.md)
|
package/package.json
CHANGED
package/src/commands/check.js
CHANGED
|
@@ -693,18 +693,21 @@ function displaySkillsStatus(manifest, projectPath, msg) {
|
|
|
693
693
|
}
|
|
694
694
|
|
|
695
695
|
// Check for Marketplace installation (Claude Code specific)
|
|
696
|
+
// Dynamically detect marketplace installation regardless of manifest
|
|
696
697
|
const hasClaudeCode = aiTools.includes('claude-code');
|
|
698
|
+
const marketplaceInfo = getMarketplaceSkillsInfo();
|
|
699
|
+
const hasMarketplaceSkills = marketplaceInfo?.installed;
|
|
700
|
+
|
|
697
701
|
const location = manifest.skills?.location || '';
|
|
698
|
-
const
|
|
702
|
+
const isMarketplaceInManifest = location === 'marketplace' ||
|
|
699
703
|
location.includes('plugins/cache') ||
|
|
700
704
|
location.includes('plugins\\cache');
|
|
701
705
|
|
|
702
|
-
if (
|
|
706
|
+
// Show marketplace status if actually installed (not just manifest)
|
|
707
|
+
if (hasMarketplaceSkills && hasClaudeCode) {
|
|
703
708
|
console.log(chalk.green(` ${msg.skillsViaMarketplace}`));
|
|
704
709
|
|
|
705
|
-
|
|
706
|
-
const marketplaceInfo = getMarketplaceSkillsInfo();
|
|
707
|
-
if (marketplaceInfo && marketplaceInfo.version && marketplaceInfo.version !== 'unknown') {
|
|
710
|
+
if (marketplaceInfo.version && marketplaceInfo.version !== 'unknown') {
|
|
708
711
|
console.log(chalk.gray(` ${t().commands.common.version}: ${marketplaceInfo.version}`));
|
|
709
712
|
if (marketplaceInfo.lastUpdated) {
|
|
710
713
|
const updateDate = marketplaceInfo.lastUpdated.split('T')[0];
|
|
@@ -732,7 +735,7 @@ function displaySkillsStatus(manifest, projectPath, msg) {
|
|
|
732
735
|
const userSkillsInfo = getInstalledSkillsInfoForAgent(tool, 'user', projectPath);
|
|
733
736
|
|
|
734
737
|
// Check if using marketplace for Claude Code
|
|
735
|
-
const usingMarketplace =
|
|
738
|
+
const usingMarketplace = (hasMarketplaceSkills || isMarketplaceInManifest) && tool === 'claude-code';
|
|
736
739
|
|
|
737
740
|
if (projectSkillsInfo?.installed || userSkillsInfo?.installed || usingMarketplace) {
|
|
738
741
|
console.log(chalk.green(` ✓ Skills ${msg.installed || 'installed'}:`));
|
|
@@ -1425,8 +1428,12 @@ function getSkillsStatusSummary(manifest, projectPath) {
|
|
|
1425
1428
|
const parts = [];
|
|
1426
1429
|
|
|
1427
1430
|
// Check for Marketplace installation (Claude Code specific)
|
|
1431
|
+
// Dynamically detect marketplace installation regardless of manifest
|
|
1432
|
+
const marketplaceInfo = getMarketplaceSkillsInfo();
|
|
1433
|
+
const hasMarketplaceSkills = marketplaceInfo?.installed;
|
|
1434
|
+
|
|
1428
1435
|
const location = manifest.skills?.location || '';
|
|
1429
|
-
const
|
|
1436
|
+
const isMarketplaceInManifest = location === 'marketplace' ||
|
|
1430
1437
|
location.includes('plugins/cache') ||
|
|
1431
1438
|
location.includes('plugins\\cache');
|
|
1432
1439
|
|
|
@@ -1435,7 +1442,7 @@ function getSkillsStatusSummary(manifest, projectPath) {
|
|
|
1435
1442
|
if (!config || !config.supportsSkills) continue;
|
|
1436
1443
|
|
|
1437
1444
|
const displayName = getAgentDisplayName(tool);
|
|
1438
|
-
const usingMarketplace =
|
|
1445
|
+
const usingMarketplace = (hasMarketplaceSkills || isMarketplaceInManifest) && tool === 'claude-code';
|
|
1439
1446
|
|
|
1440
1447
|
if (usingMarketplace) {
|
|
1441
1448
|
parts.push(chalk.green(`${displayName} ✓`));
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
writeIntegrationFile,
|
|
45
45
|
getToolFilePath
|
|
46
46
|
} from '../utils/integration-generator.js';
|
|
47
|
+
import { getMarketplaceSkillsInfo } from '../utils/github.js';
|
|
47
48
|
import { t } from '../i18n/messages.js';
|
|
48
49
|
import { regenerateIntegrations } from './update.js';
|
|
49
50
|
|
|
@@ -562,8 +563,21 @@ async function handleSkillsConfiguration(manifest, projectPath, msg, common, spe
|
|
|
562
563
|
return;
|
|
563
564
|
}
|
|
564
565
|
|
|
566
|
+
// Get declined skills from manifest
|
|
567
|
+
const declinedSkills = manifest.declinedFeatures?.skills || [];
|
|
568
|
+
|
|
569
|
+
// Check if Skills are installed via marketplace (Claude Code only)
|
|
570
|
+
const marketplaceInfo = getMarketplaceSkillsInfo();
|
|
571
|
+
const hasMarketplaceSkills = marketplaceInfo?.installed;
|
|
572
|
+
|
|
565
573
|
// Show current Skills status
|
|
566
574
|
console.log(chalk.cyan(msg.currentSkillsStatus || 'Current Skills status:'));
|
|
575
|
+
|
|
576
|
+
// Show marketplace status if applicable
|
|
577
|
+
if (hasMarketplaceSkills && aiTools.includes('claude-code')) {
|
|
578
|
+
console.log(chalk.green(` ✓ ${msg.viaMarketplace || 'Via Marketplace'}: ${marketplaceInfo.version || 'installed'}`));
|
|
579
|
+
}
|
|
580
|
+
|
|
567
581
|
for (const tool of aiTools) {
|
|
568
582
|
const config = getAgentConfig(tool);
|
|
569
583
|
if (!config?.supportsSkills) continue;
|
|
@@ -580,23 +594,48 @@ async function handleSkillsConfiguration(manifest, projectPath, msg, common, spe
|
|
|
580
594
|
if (projectInfo?.installed) {
|
|
581
595
|
console.log(chalk.gray(` - Project: ${projectInfo.version || 'installed'}`));
|
|
582
596
|
}
|
|
597
|
+
} else if (declinedSkills.includes(tool)) {
|
|
598
|
+
console.log(chalk.yellow(` ⊘ ${displayName}: ${msg.previouslyDeclined || 'Previously declined'}`));
|
|
599
|
+
} else if (hasMarketplaceSkills && tool === 'claude-code') {
|
|
600
|
+
// Claude Code has marketplace skills but no file-based installation
|
|
601
|
+
console.log(chalk.cyan(` ◎ ${displayName}: ${msg.marketplaceOnly || 'Marketplace only (no local files)'}`));
|
|
583
602
|
} else {
|
|
584
603
|
console.log(chalk.gray(` ○ ${displayName}: ${msg.notInstalled || 'Not installed'}`));
|
|
585
604
|
}
|
|
586
605
|
}
|
|
606
|
+
|
|
607
|
+
// Show marketplace coexistence note if user might want to install local files
|
|
608
|
+
if (hasMarketplaceSkills && aiTools.includes('claude-code')) {
|
|
609
|
+
console.log();
|
|
610
|
+
console.log(chalk.cyan(` ℹ ${msg.marketplaceCoexistNote || 'Note: File-based installation will coexist with Marketplace version'}`));
|
|
611
|
+
}
|
|
587
612
|
console.log();
|
|
588
613
|
|
|
614
|
+
// Build menu choices
|
|
615
|
+
const menuChoices = [
|
|
616
|
+
{ name: msg.installSkills || 'Install/Update Skills', value: 'install' }
|
|
617
|
+
];
|
|
618
|
+
|
|
619
|
+
// Add reinstall declined option if there are declined skills
|
|
620
|
+
if (declinedSkills.length > 0) {
|
|
621
|
+
menuChoices.push({
|
|
622
|
+
name: msg.reinstallDeclinedSkills || 'Reinstall declined Skills',
|
|
623
|
+
value: 'reinstall_declined'
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
menuChoices.push(
|
|
628
|
+
{ name: msg.viewStatus || 'View status only', value: 'view' },
|
|
629
|
+
{ name: common.cancel || 'Cancel', value: 'cancel' }
|
|
630
|
+
);
|
|
631
|
+
|
|
589
632
|
// Ask what action to take
|
|
590
633
|
const { action } = await inquirer.default.prompt([
|
|
591
634
|
{
|
|
592
635
|
type: 'list',
|
|
593
636
|
name: 'action',
|
|
594
637
|
message: msg.skillsAction || 'What would you like to do?',
|
|
595
|
-
choices:
|
|
596
|
-
{ name: msg.installSkills || 'Install/Update Skills', value: 'install' },
|
|
597
|
-
{ name: msg.viewStatus || 'View status only', value: 'view' },
|
|
598
|
-
{ name: common.cancel || 'Cancel', value: 'cancel' }
|
|
599
|
-
]
|
|
638
|
+
choices: menuChoices
|
|
600
639
|
}
|
|
601
640
|
]);
|
|
602
641
|
|
|
@@ -605,6 +644,63 @@ async function handleSkillsConfiguration(manifest, projectPath, msg, common, spe
|
|
|
605
644
|
return;
|
|
606
645
|
}
|
|
607
646
|
|
|
647
|
+
// Handle reinstall declined action
|
|
648
|
+
if (action === 'reinstall_declined') {
|
|
649
|
+
// Get only the declined tools that support skills
|
|
650
|
+
const declinedToolsWithSupport = declinedSkills.filter(tool => {
|
|
651
|
+
const config = getAgentConfig(tool);
|
|
652
|
+
return config?.supportsSkills;
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
if (declinedToolsWithSupport.length === 0) {
|
|
656
|
+
console.log(chalk.gray(msg.noChanges || 'No changes made'));
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Prompt for installation level
|
|
661
|
+
const { skillsLevel } = await inquirer.default.prompt([{
|
|
662
|
+
type: 'list',
|
|
663
|
+
name: 'skillsLevel',
|
|
664
|
+
message: msg.skillsLevelQuestion || 'Where should Skills be installed?',
|
|
665
|
+
choices: [
|
|
666
|
+
{ name: `${msg.projectLevel || 'Project level'} (.claude/skills/, etc.)`, value: 'project' },
|
|
667
|
+
{ name: `${msg.userLevel || 'User level'} (~/.claude/skills/, etc.)`, value: 'user' }
|
|
668
|
+
],
|
|
669
|
+
default: 'project'
|
|
670
|
+
}]);
|
|
671
|
+
|
|
672
|
+
const installations = declinedToolsWithSupport.map(agent => ({
|
|
673
|
+
agent,
|
|
674
|
+
location: skillsLevel
|
|
675
|
+
}));
|
|
676
|
+
|
|
677
|
+
// Install Skills
|
|
678
|
+
const spinner = ora(msg.installingSkills || 'Installing Skills...').start();
|
|
679
|
+
const result = await installSkillsToMultipleAgents(installations, null, projectPath);
|
|
680
|
+
spinner.stop();
|
|
681
|
+
|
|
682
|
+
if (result.success) {
|
|
683
|
+
console.log(chalk.green(msg.skillsInstallSuccess || 'Skills installed successfully'));
|
|
684
|
+
console.log(chalk.gray(` ${msg.totalInstalled || 'Total installed'}: ${result.totalInstalled}`));
|
|
685
|
+
} else {
|
|
686
|
+
console.log(chalk.yellow(msg.skillsInstallPartial || 'Skills installed with some issues'));
|
|
687
|
+
if (result.totalErrors > 0) {
|
|
688
|
+
console.log(chalk.red(` ${msg.errors || 'Errors'}: ${result.totalErrors}`));
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Update manifest - clear declined status for installed tools
|
|
693
|
+
manifest.skills = manifest.skills || {};
|
|
694
|
+
manifest.skills.installations = installations;
|
|
695
|
+
if (manifest.declinedFeatures?.skills) {
|
|
696
|
+
manifest.declinedFeatures.skills = manifest.declinedFeatures.skills.filter(
|
|
697
|
+
tool => !declinedToolsWithSupport.includes(tool)
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
writeManifest(manifest, projectPath);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
|
|
608
704
|
// Use unified installation prompt
|
|
609
705
|
const installations = await promptSkillsInstallLocation(aiTools);
|
|
610
706
|
if (installations.length === 0) {
|
|
@@ -692,6 +788,9 @@ async function handleCommandsConfiguration(manifest, projectPath, msg, common, s
|
|
|
692
788
|
return;
|
|
693
789
|
}
|
|
694
790
|
|
|
791
|
+
// Get declined commands from manifest
|
|
792
|
+
const declinedCommands = manifest.declinedFeatures?.commands || [];
|
|
793
|
+
|
|
695
794
|
// Show current Commands status
|
|
696
795
|
console.log(chalk.cyan(msg.currentCommandsStatus || 'Current Commands status:'));
|
|
697
796
|
for (const tool of commandSupportedTools) {
|
|
@@ -700,23 +799,42 @@ async function handleCommandsConfiguration(manifest, projectPath, msg, common, s
|
|
|
700
799
|
|
|
701
800
|
if (commandsInfo?.installed) {
|
|
702
801
|
console.log(chalk.green(` ✓ ${displayName}: ${commandsInfo.count} ${msg.commandsInstalled || 'commands'}`));
|
|
802
|
+
} else if (declinedCommands.includes(tool)) {
|
|
803
|
+
console.log(chalk.yellow(` ⊘ ${displayName}: ${msg.previouslyDeclined || 'Previously declined'}`));
|
|
703
804
|
} else {
|
|
704
805
|
console.log(chalk.gray(` ○ ${displayName}: ${msg.notInstalled || 'Not installed'}`));
|
|
705
806
|
}
|
|
706
807
|
}
|
|
707
808
|
console.log();
|
|
708
809
|
|
|
810
|
+
// Build menu choices
|
|
811
|
+
const menuChoices = [
|
|
812
|
+
{ name: msg.installCommands || 'Install/Update Commands', value: 'install' }
|
|
813
|
+
];
|
|
814
|
+
|
|
815
|
+
// Add reinstall declined option if there are declined commands
|
|
816
|
+
const declinedCommandsWithSupport = declinedCommands.filter(tool =>
|
|
817
|
+
commandSupportedTools.includes(tool)
|
|
818
|
+
);
|
|
819
|
+
if (declinedCommandsWithSupport.length > 0) {
|
|
820
|
+
menuChoices.push({
|
|
821
|
+
name: msg.reinstallDeclinedCommands || 'Reinstall declined Commands',
|
|
822
|
+
value: 'reinstall_declined'
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
menuChoices.push(
|
|
827
|
+
{ name: msg.viewStatus || 'View status only', value: 'view' },
|
|
828
|
+
{ name: common.cancel || 'Cancel', value: 'cancel' }
|
|
829
|
+
);
|
|
830
|
+
|
|
709
831
|
// Ask what action to take
|
|
710
832
|
const { action } = await inquirer.default.prompt([
|
|
711
833
|
{
|
|
712
834
|
type: 'list',
|
|
713
835
|
name: 'action',
|
|
714
836
|
message: msg.commandsAction || 'What would you like to do?',
|
|
715
|
-
choices:
|
|
716
|
-
{ name: msg.installCommands || 'Install/Update Commands', value: 'install' },
|
|
717
|
-
{ name: msg.viewStatus || 'View status only', value: 'view' },
|
|
718
|
-
{ name: common.cancel || 'Cancel', value: 'cancel' }
|
|
719
|
-
]
|
|
837
|
+
choices: menuChoices
|
|
720
838
|
}
|
|
721
839
|
]);
|
|
722
840
|
|
|
@@ -725,6 +843,40 @@ async function handleCommandsConfiguration(manifest, projectPath, msg, common, s
|
|
|
725
843
|
return;
|
|
726
844
|
}
|
|
727
845
|
|
|
846
|
+
// Handle reinstall declined action
|
|
847
|
+
if (action === 'reinstall_declined') {
|
|
848
|
+
if (declinedCommandsWithSupport.length === 0) {
|
|
849
|
+
console.log(chalk.gray(msg.noChanges || 'No changes made'));
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// Install Commands
|
|
854
|
+
const spinner = ora(msg.installingCommands || 'Installing Commands...').start();
|
|
855
|
+
const result = await installCommandsToMultipleAgents(declinedCommandsWithSupport, null, projectPath);
|
|
856
|
+
spinner.stop();
|
|
857
|
+
|
|
858
|
+
if (result.success) {
|
|
859
|
+
console.log(chalk.green(msg.commandsInstallSuccess || 'Commands installed successfully'));
|
|
860
|
+
console.log(chalk.gray(` ${msg.totalInstalled || 'Total installed'}: ${result.totalInstalled}`));
|
|
861
|
+
} else {
|
|
862
|
+
console.log(chalk.yellow(msg.commandsInstallPartial || 'Commands installed with some issues'));
|
|
863
|
+
if (result.totalErrors > 0) {
|
|
864
|
+
console.log(chalk.red(` ${msg.errors || 'Errors'}: ${result.totalErrors}`));
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Update manifest - clear declined status for installed tools
|
|
869
|
+
manifest.commands = manifest.commands || {};
|
|
870
|
+
manifest.commands.installations = declinedCommandsWithSupport;
|
|
871
|
+
if (manifest.declinedFeatures?.commands) {
|
|
872
|
+
manifest.declinedFeatures.commands = manifest.declinedFeatures.commands.filter(
|
|
873
|
+
tool => !declinedCommandsWithSupport.includes(tool)
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
writeManifest(manifest, projectPath);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
|
|
728
880
|
// Use unified installation prompt
|
|
729
881
|
const selectedAgents = await promptCommandsInstallation(commandSupportedTools);
|
|
730
882
|
if (selectedAgents.length === 0) {
|
package/src/commands/update.js
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
getSkillsDirForAgent,
|
|
31
31
|
getCommandsDirForAgent
|
|
32
32
|
} from '../config/ai-agent-paths.js';
|
|
33
|
+
import { getMarketplaceSkillsInfo } from '../utils/github.js';
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Compare two semantic versions
|
|
@@ -422,7 +423,7 @@ export async function updateCommand(options) {
|
|
|
422
423
|
if (missingSkills.length > 0 || outdatedSkills.length > 0 || missingCommands.length > 0) {
|
|
423
424
|
if (!options.yes) {
|
|
424
425
|
// Interactive mode: prompt user to install/update
|
|
425
|
-
const { installSkills, updateSkills, installCommands } = await promptNewFeatureInstallation(
|
|
426
|
+
const { installSkills, updateSkills, installCommands, declinedSkills, declinedCommands } = await promptNewFeatureInstallation(
|
|
426
427
|
missingSkills,
|
|
427
428
|
outdatedSkills,
|
|
428
429
|
missingCommands
|
|
@@ -509,8 +510,39 @@ export async function updateCommand(options) {
|
|
|
509
510
|
}
|
|
510
511
|
}
|
|
511
512
|
|
|
512
|
-
//
|
|
513
|
-
if (
|
|
513
|
+
// Update declined features in manifest
|
|
514
|
+
if (declinedSkills.length > 0 || declinedCommands.length > 0) {
|
|
515
|
+
if (!manifest.declinedFeatures) manifest.declinedFeatures = {};
|
|
516
|
+
|
|
517
|
+
// Merge with existing declined items (avoid duplicates)
|
|
518
|
+
if (declinedSkills.length > 0) {
|
|
519
|
+
const existing = manifest.declinedFeatures.skills || [];
|
|
520
|
+
manifest.declinedFeatures.skills = [...new Set([...existing, ...declinedSkills])];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (declinedCommands.length > 0) {
|
|
524
|
+
const existing = manifest.declinedFeatures.commands || [];
|
|
525
|
+
manifest.declinedFeatures.commands = [...new Set([...existing, ...declinedCommands])];
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Remove from declined list if user decided to install this time
|
|
530
|
+
if (installSkills.length > 0 && manifest.declinedFeatures?.skills) {
|
|
531
|
+
const installedAgents = installSkills.map(s => s.agent);
|
|
532
|
+
manifest.declinedFeatures.skills = manifest.declinedFeatures.skills.filter(
|
|
533
|
+
agent => !installedAgents.includes(agent)
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
if (installCommands.length > 0 && manifest.declinedFeatures?.commands) {
|
|
537
|
+
manifest.declinedFeatures.commands = manifest.declinedFeatures.commands.filter(
|
|
538
|
+
agent => !installCommands.includes(agent)
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// Write updated manifest if anything was installed, updated, or declined
|
|
543
|
+
const hasChanges = installSkills.length > 0 || updateSkills.length > 0 ||
|
|
544
|
+
installCommands.length > 0 || declinedSkills.length > 0 || declinedCommands.length > 0;
|
|
545
|
+
if (hasChanges) {
|
|
514
546
|
writeManifest(manifest, projectPath);
|
|
515
547
|
}
|
|
516
548
|
} else {
|
|
@@ -1035,6 +1067,10 @@ function checkNewFeatures(projectPath, manifest, latestSkillsVersion) {
|
|
|
1035
1067
|
return { missingSkills: [], outdatedSkills: [], missingCommands: [] };
|
|
1036
1068
|
}
|
|
1037
1069
|
|
|
1070
|
+
// Get declined features from manifest (to exclude from prompts)
|
|
1071
|
+
const declinedSkills = manifest.declinedFeatures?.skills || [];
|
|
1072
|
+
const declinedCommands = manifest.declinedFeatures?.commands || [];
|
|
1073
|
+
|
|
1038
1074
|
const missingSkills = [];
|
|
1039
1075
|
const outdatedSkills = [];
|
|
1040
1076
|
const missingCommands = [];
|
|
@@ -1056,7 +1092,8 @@ function checkNewFeatures(projectPath, manifest, latestSkillsVersion) {
|
|
|
1056
1092
|
// (manifest records can be stale if user deleted the directory)
|
|
1057
1093
|
const hasSkills = projectInfo?.installed || userInfo?.installed || usingMarketplace;
|
|
1058
1094
|
|
|
1059
|
-
if
|
|
1095
|
+
// Skip if user previously declined this tool's skills
|
|
1096
|
+
if (!hasSkills && !declinedSkills.includes(tool)) {
|
|
1060
1097
|
missingSkills.push({
|
|
1061
1098
|
agent: tool,
|
|
1062
1099
|
displayName: getAgentDisplayName(tool),
|
|
@@ -1089,7 +1126,8 @@ function checkNewFeatures(projectPath, manifest, latestSkillsVersion) {
|
|
|
1089
1126
|
// Only trust actual file existence, not manifest records
|
|
1090
1127
|
const hasCommands = cmdInfo?.installed;
|
|
1091
1128
|
|
|
1092
|
-
if
|
|
1129
|
+
// Skip if user previously declined this tool's commands
|
|
1130
|
+
if (!hasCommands && !declinedCommands.includes(tool)) {
|
|
1093
1131
|
missingCommands.push({
|
|
1094
1132
|
agent: tool,
|
|
1095
1133
|
displayName: getAgentDisplayName(tool),
|
|
@@ -1107,14 +1145,14 @@ function checkNewFeatures(projectPath, manifest, latestSkillsVersion) {
|
|
|
1107
1145
|
* @param {Array} missingSkills - Array of {agent, displayName, paths}
|
|
1108
1146
|
* @param {Array} outdatedSkills - Array of {agent, displayName, paths, currentVersion, latestVersion, level, path}
|
|
1109
1147
|
* @param {Array} missingCommands - Array of {agent, displayName, path}
|
|
1110
|
-
* @returns {Promise<{installSkills: Array, updateSkills: Array, installCommands: Array}>}
|
|
1148
|
+
* @returns {Promise<{installSkills: Array, updateSkills: Array, installCommands: Array, declinedSkills: Array, declinedCommands: Array}>}
|
|
1111
1149
|
*/
|
|
1112
1150
|
async function promptNewFeatureInstallation(missingSkills, outdatedSkills, missingCommands) {
|
|
1113
1151
|
const msg = t().commands.update;
|
|
1114
1152
|
|
|
1115
1153
|
// If nothing to do, return empty
|
|
1116
1154
|
if (missingSkills.length === 0 && outdatedSkills.length === 0 && missingCommands.length === 0) {
|
|
1117
|
-
return { installSkills: [], updateSkills: [], installCommands: [] };
|
|
1155
|
+
return { installSkills: [], updateSkills: [], installCommands: [], declinedSkills: [], declinedCommands: [] };
|
|
1118
1156
|
}
|
|
1119
1157
|
|
|
1120
1158
|
console.log();
|
|
@@ -1123,22 +1161,42 @@ async function promptNewFeatureInstallation(missingSkills, outdatedSkills, missi
|
|
|
1123
1161
|
console.log(chalk.cyan('━'.repeat(50)));
|
|
1124
1162
|
console.log();
|
|
1125
1163
|
|
|
1126
|
-
const result = { installSkills: [], updateSkills: [], installCommands: [] };
|
|
1164
|
+
const result = { installSkills: [], updateSkills: [], installCommands: [], declinedSkills: [], declinedCommands: [] };
|
|
1127
1165
|
|
|
1128
1166
|
// Handle missing Skills with checkbox selection
|
|
1129
1167
|
if (missingSkills.length > 0) {
|
|
1168
|
+
// Check if Skills are already installed via marketplace (Claude Code only)
|
|
1169
|
+
const marketplaceInfo = getMarketplaceSkillsInfo();
|
|
1170
|
+
const hasMarketplaceSkills = marketplaceInfo?.installed;
|
|
1171
|
+
|
|
1130
1172
|
console.log(chalk.yellow(msg.skillsNotInstalledFor || 'Skills not yet installed for these AI tools:'));
|
|
1131
1173
|
for (const skill of missingSkills) {
|
|
1132
|
-
|
|
1174
|
+
// Show marketplace hint for Claude Code if applicable
|
|
1175
|
+
if (hasMarketplaceSkills && skill.agent === 'claude-code') {
|
|
1176
|
+
console.log(chalk.gray(` • ${skill.displayName} ${chalk.cyan(`(${msg.alreadyViaMarketplace || 'already via Marketplace'})`)}`));
|
|
1177
|
+
} else {
|
|
1178
|
+
console.log(chalk.gray(` • ${skill.displayName}`));
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// Show marketplace coexistence warning if applicable
|
|
1183
|
+
if (hasMarketplaceSkills && missingSkills.some(s => s.agent === 'claude-code')) {
|
|
1184
|
+
console.log();
|
|
1185
|
+
console.log(chalk.cyan(` ℹ ${msg.marketplaceCoexistNote || 'Note: File-based installation will coexist with Marketplace version'}`));
|
|
1133
1186
|
}
|
|
1134
1187
|
console.log();
|
|
1135
1188
|
|
|
1136
1189
|
// Build checkbox choices
|
|
1137
|
-
const skillChoices = missingSkills.map(skill =>
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1190
|
+
const skillChoices = missingSkills.map(skill => {
|
|
1191
|
+
const isClaudeWithMarketplace = hasMarketplaceSkills && skill.agent === 'claude-code';
|
|
1192
|
+
return {
|
|
1193
|
+
name: isClaudeWithMarketplace
|
|
1194
|
+
? `${skill.displayName} ${chalk.cyan(`(${msg.alreadyViaMarketplace || 'already via Marketplace'})`)}`
|
|
1195
|
+
: skill.displayName,
|
|
1196
|
+
value: skill.agent,
|
|
1197
|
+
checked: !isClaudeWithMarketplace // Default unchecked if already via marketplace
|
|
1198
|
+
};
|
|
1199
|
+
});
|
|
1142
1200
|
|
|
1143
1201
|
// Add skip option
|
|
1144
1202
|
skillChoices.push(new inquirer.Separator());
|
|
@@ -1164,6 +1222,12 @@ async function promptNewFeatureInstallation(missingSkills, outdatedSkills, missi
|
|
|
1164
1222
|
// Filter out skip and handle selection
|
|
1165
1223
|
const filteredSkillAgents = selectedSkillAgents.filter(a => a !== '__skip__');
|
|
1166
1224
|
|
|
1225
|
+
// Track declined skills (user explicitly skipped or deselected)
|
|
1226
|
+
const skippedSkillAgents = missingSkills
|
|
1227
|
+
.map(s => s.agent)
|
|
1228
|
+
.filter(agent => !filteredSkillAgents.includes(agent));
|
|
1229
|
+
result.declinedSkills = skippedSkillAgents;
|
|
1230
|
+
|
|
1167
1231
|
if (filteredSkillAgents.length > 0) {
|
|
1168
1232
|
// Prompt for installation level
|
|
1169
1233
|
const { skillsLevel } = await inquirer.prompt([{
|
|
@@ -1279,7 +1343,14 @@ async function promptNewFeatureInstallation(missingSkills, outdatedSkills, missi
|
|
|
1279
1343
|
}]);
|
|
1280
1344
|
|
|
1281
1345
|
// Filter out skip
|
|
1282
|
-
|
|
1346
|
+
const filteredCommandAgents = selectedCommandAgents.filter(a => a !== '__skip__');
|
|
1347
|
+
result.installCommands = filteredCommandAgents;
|
|
1348
|
+
|
|
1349
|
+
// Track declined commands (user explicitly skipped or deselected)
|
|
1350
|
+
const skippedCommandAgents = missingCommands
|
|
1351
|
+
.map(c => c.agent)
|
|
1352
|
+
.filter(agent => !filteredCommandAgents.includes(agent));
|
|
1353
|
+
result.declinedCommands = skippedCommandAgents;
|
|
1283
1354
|
}
|
|
1284
1355
|
|
|
1285
1356
|
return result;
|