@deerdesign/deertools 1.2.13 → 1.2.17
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/README.md +5 -4
- package/package.json +1 -1
- package/src/agent-detector.js +127 -15
- package/src/cli.js +2 -0
- package/src/commands.js +97 -6
- package/src/skill-commands.js +346 -45
package/README.md
CHANGED
|
@@ -185,11 +185,12 @@ deertools profile list
|
|
|
185
185
|
deertools profile use staging
|
|
186
186
|
|
|
187
187
|
# 12. AI Agent Skills (DeerSkills Hub):
|
|
188
|
-
deertools skill list # Wyświetl
|
|
189
|
-
deertools skill
|
|
190
|
-
deertools skill install
|
|
188
|
+
deertools skill list # Wyświetl listę skilli ze statusem zainstalowania w projekcie
|
|
189
|
+
deertools skill sync # Jedna komenda: instaluje brakujące i aktualizuje obecne skille zespołu
|
|
190
|
+
deertools skill install --all # To samo co skill sync (pełna synchronizacja zespołu)
|
|
191
|
+
deertools skill install deer-kosztorys # Zainstaluj konkretny skill w ~/.gemini/antigravity/skills lub .agents
|
|
191
192
|
deertools skill install deer-kosztorys --version 1.0.0
|
|
192
|
-
deertools skill
|
|
193
|
+
deertools skill search "kosztorys" # Wyszukaj skille po nazwie, tagu lub opisie
|
|
193
194
|
deertools skill push ./my-skill # Opublikuj nową wersję z automatycznym skanerem sekretów
|
|
194
195
|
deertools skill push ./my-skill --bump minor # Automatyczne podbicie wersji SemVer
|
|
195
196
|
deertools skill update deer-kosztorys # Zaktualizuj zainstalowany skill do najnowszej wersji
|
package/package.json
CHANGED
package/src/agent-detector.js
CHANGED
|
@@ -3,6 +3,27 @@ const fs = require('fs');
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
const readline = require('readline');
|
|
8
|
+
const { readConfig, writeConfig } = require('./profiles');
|
|
9
|
+
|
|
10
|
+
function isBinaryInPath(cmd) {
|
|
11
|
+
try {
|
|
12
|
+
const check = process.platform === 'win32' ? `where ${cmd} 2>nul` : `which ${cmd} 2>/dev/null`;
|
|
13
|
+
execSync(check, { stdio: 'ignore', timeout: 800 });
|
|
14
|
+
return true;
|
|
15
|
+
} catch (_) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isAppInstalled(appName) {
|
|
21
|
+
if (process.platform === 'darwin') {
|
|
22
|
+
return fs.existsSync(`/Applications/${appName}.app`) || fs.existsSync(path.join(os.homedir(), `Applications/${appName}.app`));
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
6
27
|
/**
|
|
7
28
|
* Rejestr obsługiwanych platform agentów AI.
|
|
8
29
|
* Obsługuje: Google Antigravity / Gemini, Claude Code, OpenAI Codex, Hermes AI,
|
|
@@ -19,35 +40,35 @@ const KNOWN_AGENTS = [
|
|
|
19
40
|
{
|
|
20
41
|
id: 'claude',
|
|
21
42
|
name: 'Claude Code',
|
|
22
|
-
detect: (home) => fs.existsSync(path.join(home, '.claude')),
|
|
43
|
+
detect: (home) => fs.existsSync(path.join(home, '.claude')) || isBinaryInPath('claude'),
|
|
23
44
|
getTarget: (home) => path.join(home, '.claude', 'skills'),
|
|
24
45
|
format: 'skill_md',
|
|
25
46
|
},
|
|
26
47
|
{
|
|
27
48
|
id: 'codex',
|
|
28
49
|
name: 'OpenAI Codex',
|
|
29
|
-
detect: (home) => fs.existsSync(path.join(home, '.codex')),
|
|
50
|
+
detect: (home) => fs.existsSync(path.join(home, '.codex')) || isBinaryInPath('codex'),
|
|
30
51
|
getTarget: (home) => path.join(home, '.codex', 'skills'),
|
|
31
52
|
format: 'skill_md',
|
|
32
53
|
},
|
|
33
54
|
{
|
|
34
55
|
id: 'hermes',
|
|
35
56
|
name: 'Hermes AI',
|
|
36
|
-
detect: (home) => fs.existsSync(path.join(home, '.hermes')) || fs.existsSync(path.join(home, '.config', 'hermes')) || Boolean(process.env.HERMES_HOME),
|
|
57
|
+
detect: (home) => fs.existsSync(path.join(home, '.hermes')) || fs.existsSync(path.join(home, '.config', 'hermes')) || Boolean(process.env.HERMES_HOME) || isBinaryInPath('hermes'),
|
|
37
58
|
getTarget: (home) => process.env.HERMES_SKILLS_DIR || path.join(home, '.hermes', 'skills'),
|
|
38
59
|
format: 'skill_md',
|
|
39
60
|
},
|
|
40
61
|
{
|
|
41
62
|
id: 'cursor',
|
|
42
63
|
name: 'Cursor IDE',
|
|
43
|
-
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(home, '.cursor')),
|
|
64
|
+
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(home, '.cursor')) || isAppInstalled('Cursor'),
|
|
44
65
|
getTarget: (home, cwd) => fs.existsSync(path.join(cwd, '.cursor')) ? path.join(cwd, '.cursor', 'rules') : path.join(home, '.cursor', 'rules'),
|
|
45
66
|
format: 'cursor_mdc',
|
|
46
67
|
},
|
|
47
68
|
{
|
|
48
69
|
id: 'windsurf',
|
|
49
70
|
name: 'Windsurf / Codeium',
|
|
50
|
-
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.windsurfrules')) || fs.existsSync(path.join(cwd, '.windsurf')) || fs.existsSync(path.join(home, '.codeium')),
|
|
71
|
+
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.windsurfrules')) || fs.existsSync(path.join(cwd, '.windsurf')) || fs.existsSync(path.join(home, '.codeium')) || isAppInstalled('Windsurf'),
|
|
51
72
|
getTarget: (home, cwd) => path.join(cwd, '.windsurf', 'rules'),
|
|
52
73
|
format: 'skill_md',
|
|
53
74
|
},
|
|
@@ -61,7 +82,40 @@ const KNOWN_AGENTS = [
|
|
|
61
82
|
];
|
|
62
83
|
|
|
63
84
|
/**
|
|
64
|
-
*
|
|
85
|
+
* Zwraca listę skonfigurowanych agentów użytkownika na tym PC.
|
|
86
|
+
*/
|
|
87
|
+
function getSelectedAgents() {
|
|
88
|
+
if (process.env.DEERTOOLS_AGENTS) {
|
|
89
|
+
const fromEnv = process.env.DEERTOOLS_AGENTS.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
90
|
+
if (fromEnv.length > 0) return fromEnv;
|
|
91
|
+
}
|
|
92
|
+
const cfg = readConfig();
|
|
93
|
+
if (cfg.selectedAgents && Array.isArray(cfg.selectedAgents) && cfg.selectedAgents.length > 0) {
|
|
94
|
+
return cfg.selectedAgents.map((s) => String(s).trim().toLowerCase());
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Zapisuje listę wybranych agentów użytkownika w konfiguracji ~/.deertools/config.json.
|
|
101
|
+
*/
|
|
102
|
+
function setSelectedAgents(agentIds) {
|
|
103
|
+
const cfg = readConfig();
|
|
104
|
+
cfg.selectedAgents = agentIds.map((s) => String(s).trim().toLowerCase());
|
|
105
|
+
writeConfig(cfg);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Czyści zapisaną listę agentów (przywraca auto-detekcję wszystkich obecnych na PC).
|
|
110
|
+
*/
|
|
111
|
+
function clearSelectedAgents() {
|
|
112
|
+
const cfg = readConfig();
|
|
113
|
+
delete cfg.selectedAgents;
|
|
114
|
+
writeConfig(cfg);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Wykrywa zainstalowane środowiska agentów lub filtruje według flagi --agent / konfiguracji.
|
|
65
119
|
*/
|
|
66
120
|
function detectAgents(options = {}) {
|
|
67
121
|
const home = os.homedir();
|
|
@@ -77,7 +131,7 @@ function detectAgents(options = {}) {
|
|
|
77
131
|
}];
|
|
78
132
|
}
|
|
79
133
|
|
|
80
|
-
// Wymuszenie instalacji do WSZYSTKICH
|
|
134
|
+
// Wymuszenie instalacji do WSZYSTKICH znanych platform (--all-agents)
|
|
81
135
|
if (options['all-agents']) {
|
|
82
136
|
return KNOWN_AGENTS.map((spec) => ({
|
|
83
137
|
id: spec.id,
|
|
@@ -87,21 +141,35 @@ function detectAgents(options = {}) {
|
|
|
87
141
|
}));
|
|
88
142
|
}
|
|
89
143
|
|
|
90
|
-
// Wskazanie konkretnego agenta
|
|
144
|
+
// Wskazanie konkretnego agenta lub listy po przecinku (--agent claude,antigravity)
|
|
91
145
|
if (options.agent && options.agent !== 'all' && options.agent !== 'auto') {
|
|
92
|
-
const requested = options.agent.
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
return
|
|
146
|
+
const requested = options.agent.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
147
|
+
const matched = KNOWN_AGENTS.filter((spec) => requested.includes(spec.id));
|
|
148
|
+
if (matched.length > 0) {
|
|
149
|
+
return matched.map((spec) => ({
|
|
150
|
+
id: spec.id,
|
|
151
|
+
name: spec.name,
|
|
152
|
+
targetDir: spec.getTarget(home, cwd),
|
|
153
|
+
format: spec.format,
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Jeśli użytkownik ma zapisaną konfigurację wybranych agentów na tym PC:
|
|
159
|
+
const configured = getSelectedAgents();
|
|
160
|
+
if (configured && configured.length > 0 && !options['ignore-selected']) {
|
|
161
|
+
const matched = KNOWN_AGENTS.filter((spec) => configured.includes(spec.id));
|
|
162
|
+
if (matched.length > 0) {
|
|
163
|
+
return matched.map((spec) => ({
|
|
96
164
|
id: spec.id,
|
|
97
165
|
name: spec.name,
|
|
98
166
|
targetDir: spec.getTarget(home, cwd),
|
|
99
167
|
format: spec.format,
|
|
100
|
-
}
|
|
168
|
+
}));
|
|
101
169
|
}
|
|
102
170
|
}
|
|
103
171
|
|
|
104
|
-
// Automatyczne wykrywanie obecnych agentów
|
|
172
|
+
// Automatyczne wykrywanie obecnych agentów na PC
|
|
105
173
|
const matched = [];
|
|
106
174
|
for (const spec of KNOWN_AGENTS) {
|
|
107
175
|
try {
|
|
@@ -157,4 +225,48 @@ function installSkillContent(agent, skillName, rawMarkdown) {
|
|
|
157
225
|
return filePath;
|
|
158
226
|
}
|
|
159
227
|
|
|
160
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Interaktywny prompt pytający użytkownika o wybór platform agentów w terminalu.
|
|
230
|
+
*/
|
|
231
|
+
async function promptSelectAgents(availableAgents) {
|
|
232
|
+
if (!process.stdin.isTTY) return availableAgents;
|
|
233
|
+
return new Promise((resolve) => {
|
|
234
|
+
const rl = readline.createInterface({
|
|
235
|
+
input: process.stdin,
|
|
236
|
+
output: process.stdout,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
process.stdout.write(`\nWykryto platformy agentów AI na tym komputerze:\n`);
|
|
240
|
+
availableAgents.forEach((a, i) => {
|
|
241
|
+
process.stdout.write(` [${i + 1}] ${a.name} (${a.id})\n`);
|
|
242
|
+
});
|
|
243
|
+
process.stdout.write(`\nWybierz platformy (np. 1, 3 lub 'all') [domyślnie: wszystkie wykryte]: `);
|
|
244
|
+
|
|
245
|
+
rl.question('', (answer) => {
|
|
246
|
+
rl.close();
|
|
247
|
+
const trimmed = (answer || '').trim().toLowerCase();
|
|
248
|
+
if (!trimmed || trimmed === 'all') {
|
|
249
|
+
resolve(availableAgents);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const parts = trimmed.split(/[\s,]+/).map((p) => parseInt(p, 10)).filter((n) => !isNaN(n) && n >= 1 && n <= availableAgents.length);
|
|
253
|
+
if (parts.length === 0) {
|
|
254
|
+
resolve(availableAgents);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const selected = parts.map((n) => availableAgents[n - 1]);
|
|
258
|
+
resolve(selected);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
module.exports = {
|
|
264
|
+
KNOWN_AGENTS,
|
|
265
|
+
detectAgents,
|
|
266
|
+
installSkillContent,
|
|
267
|
+
getSelectedAgents,
|
|
268
|
+
setSelectedAgents,
|
|
269
|
+
clearSelectedAgents,
|
|
270
|
+
promptSelectAgents,
|
|
271
|
+
isBinaryInPath,
|
|
272
|
+
};
|
package/src/cli.js
CHANGED
|
@@ -32,6 +32,8 @@ async function main(argv) {
|
|
|
32
32
|
const table = {
|
|
33
33
|
login: c.cmdLogin, logout: c.cmdLogout, whoami: c.cmdWhoami, docs: c.cmdDocs,
|
|
34
34
|
endpoints: c.cmdEndpoints, api: c.cmdApi, estimate: c.cmdEstimate, skill: c.cmdSkill,
|
|
35
|
+
sync: (pos, flags) => c.cmdSkill(['sync', ...pos], flags),
|
|
36
|
+
agent: c.cmdAgent, agents: c.cmdAgent,
|
|
35
37
|
mcp: c.cmdMcp, doctor: c.cmdDoctor, audit: c.cmdAudit, profile: c.cmdProfile,
|
|
36
38
|
completion: c.cmdCompletion, catalog: c.cmdCatalog, deliveries: c.cmdDeliveries,
|
|
37
39
|
supplier: c.cmdSupplier, rendermind: c.cmdRendermind, baselinker: c.cmdBaseLinker,
|
package/src/commands.js
CHANGED
|
@@ -379,6 +379,9 @@ async function cmdSkill(pos, flags) {
|
|
|
379
379
|
if (sub === 'bundle') {
|
|
380
380
|
return cmdSkillBundle(pos[1], flags);
|
|
381
381
|
}
|
|
382
|
+
if (sub === 'sync') {
|
|
383
|
+
return skillCommands.cmdSkillSync(flags, out, err);
|
|
384
|
+
}
|
|
382
385
|
if (sub === 'list') {
|
|
383
386
|
return skillCommands.cmdSkillList(flags, out, err);
|
|
384
387
|
}
|
|
@@ -404,9 +407,10 @@ async function cmdSkill(pos, flags) {
|
|
|
404
407
|
return skillCommands.cmdSkillPromote(pos[1], flags, out, err);
|
|
405
408
|
}
|
|
406
409
|
if (sub === 'install') {
|
|
407
|
-
|
|
410
|
+
const target = pos[1] || (flags.all ? '--all' : null);
|
|
411
|
+
return skillCommands.cmdSkillInstall(target, flags, out, err);
|
|
408
412
|
}
|
|
409
|
-
fail('Użycie:\n deertools skill login [token]\n deertools skill bundle <architekci|kosztorysy|logistyka|sprzedaz|it>\n deertools skill list [--tag <tag>]\n deertools skill search <fraza>\n deertools skill install
|
|
413
|
+
fail('Użycie:\n deertools skill login [token]\n deertools skill sync [--force]\n deertools skill bundle <architekci|kosztorysy|logistyka|sprzedaz|it>\n deertools skill list [--tag <tag>]\n deertools skill search <fraza>\n deertools skill install [--all|<slug[@version]>]\n deertools skill check\n deertools skill update [slug]\n deertools skill versions <slug>\n deertools skill diff <slug> [wersjaA] [wersjaB]\n deertools skill push [katalog] [--bump patch|minor|major] [--changelog "opis"]\n deertools skill promote <slug>', 2);
|
|
410
414
|
}
|
|
411
415
|
|
|
412
416
|
|
|
@@ -508,6 +512,91 @@ async function cmdMcp(pos, flags) {
|
|
|
508
512
|
fail('Użycie: deertools mcp [config|install|serve] [produkt|all] [--json]', 2);
|
|
509
513
|
}
|
|
510
514
|
|
|
515
|
+
async function cmdAgent(pos, flags) {
|
|
516
|
+
const {
|
|
517
|
+
KNOWN_AGENTS,
|
|
518
|
+
detectAgents,
|
|
519
|
+
getSelectedAgents,
|
|
520
|
+
setSelectedAgents,
|
|
521
|
+
clearSelectedAgents,
|
|
522
|
+
promptSelectAgents,
|
|
523
|
+
} = require('./agent-detector');
|
|
524
|
+
const action = pos[0] || 'list';
|
|
525
|
+
|
|
526
|
+
if (action === 'list') {
|
|
527
|
+
const selected = getSelectedAgents();
|
|
528
|
+
const detected = detectAgents({ 'ignore-selected': true });
|
|
529
|
+
const detectedIds = new Set(detected.map((a) => a.id));
|
|
530
|
+
|
|
531
|
+
out(`\n=== Platformy Agentów AI (DeerTools) ===\n`);
|
|
532
|
+
for (const a of KNOWN_AGENTS) {
|
|
533
|
+
const isDetected = detectedIds.has(a.id);
|
|
534
|
+
const isActive = selected ? selected.includes(a.id) : isDetected;
|
|
535
|
+
|
|
536
|
+
let statusBadge = '\x1b[90m[○ Niewykryty na PC]\x1b[0m';
|
|
537
|
+
if (isDetected) statusBadge = '\x1b[32m[✓ Wykryty na PC]\x1b[0m';
|
|
538
|
+
|
|
539
|
+
let activeBadge = '';
|
|
540
|
+
if (isActive) {
|
|
541
|
+
activeBadge = ' \x1b[36m(AKTYWNY DLA SKILLI)\x1b[0m';
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
out(` • ${a.id.padEnd(16)} ${(a.name).padEnd(32)} ${statusBadge}${activeBadge}`);
|
|
545
|
+
out(` Ścieżka: ${a.getTarget(os.homedir(), process.cwd())}`);
|
|
546
|
+
out('');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
out('─'.repeat(72));
|
|
550
|
+
if (selected && selected.length > 0) {
|
|
551
|
+
out(`📌 Wybrane platformy na tym PC: \x1b[36m${selected.join(', ')}\x1b[0m (zapisane w ~/.deertools/config.json)`);
|
|
552
|
+
out(` Skille instalują się tylko u wybranych agentów.`);
|
|
553
|
+
out(` Aby przywrócić auto-wykrywanie wszystkich: \x1b[33mdeertools agent reset\x1b[0m`);
|
|
554
|
+
} else {
|
|
555
|
+
out(`⚡ Tryb: \x1b[32mAutomatyczne wykrywanie wszystkich platform obecnych na komputerze\x1b[0m`);
|
|
556
|
+
out(` Aby ograniczyć synchronizację do wybranych agentów:`);
|
|
557
|
+
out(` \x1b[36mdeertools agent select antigravity,cursor\x1b[0m`);
|
|
558
|
+
}
|
|
559
|
+
out('─'.repeat(72) + '\n');
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (action === 'select' || action === 'set') {
|
|
564
|
+
let targets = pos.slice(1).join(',').split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
565
|
+
if (targets.length === 0) {
|
|
566
|
+
const detected = detectAgents({ 'ignore-selected': true });
|
|
567
|
+
const picked = await promptSelectAgents(detected);
|
|
568
|
+
targets = picked.map((a) => a.id);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
const validIds = KNOWN_AGENTS.map((a) => a.id);
|
|
572
|
+
const validTargets = targets.filter((id) => validIds.includes(id));
|
|
573
|
+
|
|
574
|
+
if (validTargets.length === 0) {
|
|
575
|
+
fail(`Błąd: Podaj poprawne identyfikatory agentów: ${validIds.join(', ')}`, 2);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
setSelectedAgents(validTargets);
|
|
579
|
+
out(`✓ Zapisano aktywnych agentów na tym komputerze: \x1b[36m${validTargets.join(', ')}\x1b[0m`);
|
|
580
|
+
out(`Od teraz deertools skill sync i skill install instalują skille tylko dla tych platform.`);
|
|
581
|
+
out(`Aby przywrócić instalację u wszystkich wykrytych: deertools agent reset\n`);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (action === 'reset' || action === 'clear') {
|
|
586
|
+
clearSelectedAgents();
|
|
587
|
+
out(`✓ Zresetowano konfigurację agentów. Przywrócono automatyczne wykrywanie obecnych na PC.\n`);
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (action === 'current') {
|
|
592
|
+
const active = detectAgents({});
|
|
593
|
+
out(active.map((a) => a.id).join(','));
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
fail(`Nieznana podkomenda „agent ${action}”. Użyj: deertools agent [list|select <agenty>|reset|current]`, 2);
|
|
598
|
+
}
|
|
599
|
+
|
|
511
600
|
const { cmdDoctor } = require('./doctor');
|
|
512
601
|
const { cmdAudit } = require('./audit');
|
|
513
602
|
const { cmdProfile } = require('./profiles');
|
|
@@ -544,9 +633,11 @@ BaseLinker MCP Proxy & Hub:
|
|
|
544
633
|
deertools baselinker catalog <search|get> Operacje katalogowe z poziomu terminala.
|
|
545
634
|
|
|
546
635
|
Integracje MCP i Agenci AI (DeerSkills Hub):
|
|
547
|
-
deertools
|
|
636
|
+
deertools agent [list|select <agenty>|reset] Wykrywanie i konfiguracja platform agentów AI na PC.
|
|
637
|
+
deertools skill list [--tag <tag>] Przegląda skille w Hubie wraz ze statusem zainstalowania.
|
|
638
|
+
deertools skill sync [--agent <id>|-i|--force] Instaluje brakujące i aktualizuje obecne skille zespołu.
|
|
639
|
+
deertools skill install [--all|<slug[@wersja]>] Instaluje wszystkie skille (--all) lub wskazany skill.
|
|
548
640
|
deertools skill search <fraza> Wyszukuje umiejętności po słowach kluczowych.
|
|
549
|
-
deertools skill install <slug[@wersja]> Instaluje skill w ~/.gemini/antigravity/skills lub .agents.
|
|
550
641
|
deertools skill versions <slug> Historia wydań z changelogami z commitów i datami.
|
|
551
642
|
deertools skill diff <slug> [wersjaA] [wersjaB] Porównanie zmian w plikach paczki i treści SKILL.md.
|
|
552
643
|
deertools skill push [katalog] [--bump patch|minor] Publikuje nową wersję z automatycznym skanerem sekretów.
|
|
@@ -566,13 +657,13 @@ Narzędzia systemowe:
|
|
|
566
657
|
deertools audit [--limit 25] [--clear] [--json] Historia operacji i wywołań API.
|
|
567
658
|
deertools completion [install|zsh|bash] Autouzupełnianie w powłoce po wciśnięciu Tab.
|
|
568
659
|
|
|
569
|
-
Zmienne środowiskowe: DEERTOOLS_<PRODUKT>_KEY, BASELINKER_TOKEN, DEERTOOLS_HOME, DEERTOOLS_PROFILE.
|
|
660
|
+
Zmienne środowiskowe: DEERTOOLS_<PRODUKT>_KEY, BASELINKER_TOKEN, DEERTOOLS_HOME, DEERTOOLS_PROFILE, DEERTOOLS_AGENTS.
|
|
570
661
|
`;
|
|
571
662
|
|
|
572
663
|
module.exports = {
|
|
573
664
|
cmdLogin, cmdLogout, cmdWhoami, cmdDocs, cmdEndpoints, cmdApi, cmdEstimate, cmdSkill, cmdMcp,
|
|
574
665
|
cmdDoctor, cmdAudit, cmdProfile, cmdCompletion, cmdCatalog, cmdDeliveries, cmdSupplier, cmdRendermind,
|
|
575
|
-
cmdBaseLinker,
|
|
666
|
+
cmdBaseLinker, cmdAgent,
|
|
576
667
|
HELP, parseQuery,
|
|
577
668
|
};
|
|
578
669
|
|
package/src/skill-commands.js
CHANGED
|
@@ -7,6 +7,8 @@ const { parseFrontmatterName } = require('./openapi');
|
|
|
7
7
|
const { resolveProducts } = require('./registry');
|
|
8
8
|
const { fetchText } = require('./http');
|
|
9
9
|
|
|
10
|
+
const { compareSemver } = require('./updater');
|
|
11
|
+
|
|
10
12
|
const LOCK_FILE = '.deertools-lock.json';
|
|
11
13
|
|
|
12
14
|
function getLockFilePath(cwd = process.cwd()) {
|
|
@@ -38,14 +40,149 @@ function writeLock(data, cwd = process.cwd()) {
|
|
|
38
40
|
} catch (_) {}
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Szuka pliku skilla na dysku dla danego agenta.
|
|
45
|
+
*/
|
|
46
|
+
function findSkillFileForAgent(agent, skill) {
|
|
47
|
+
const slug = skill.slug;
|
|
48
|
+
const fullSlug = skill.full_slug || slug;
|
|
49
|
+
const shortSlug = slug.replace(/^@[^/]+\//, '');
|
|
50
|
+
|
|
51
|
+
if (agent.format === 'cursor_mdc') {
|
|
52
|
+
const candidates = [
|
|
53
|
+
path.join(agent.targetDir, `${slug}.mdc`),
|
|
54
|
+
path.join(agent.targetDir, `${shortSlug}.mdc`),
|
|
55
|
+
path.join(agent.targetDir, `${fullSlug.replace(/\//g, '-')}.mdc`),
|
|
56
|
+
];
|
|
57
|
+
for (const c of candidates) {
|
|
58
|
+
if (fs.existsSync(c)) return c;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const candidates = [
|
|
64
|
+
path.join(agent.targetDir, slug, 'SKILL.md'),
|
|
65
|
+
path.join(agent.targetDir, shortSlug, 'SKILL.md'),
|
|
66
|
+
path.join(agent.targetDir, fullSlug, 'SKILL.md'),
|
|
67
|
+
];
|
|
68
|
+
for (const c of candidates) {
|
|
69
|
+
if (fs.existsSync(c)) return c;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Wyciąga wersję z pliku SKILL.md lub .mdc z fallbackiem na lockfile.
|
|
76
|
+
*/
|
|
77
|
+
function readSkillVersion(filePath, lock, skill) {
|
|
78
|
+
if (!filePath || !fs.existsSync(filePath)) return null;
|
|
79
|
+
try {
|
|
80
|
+
const head = fs.readFileSync(filePath, 'utf8').slice(0, 2048);
|
|
81
|
+
const m = head.match(/[\r\n]version:\s*['"]?([0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z0-9.]+)?)/i)
|
|
82
|
+
|| head.match(/^version:\s*['"]?([0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z0-9.]+)?)/im);
|
|
83
|
+
if (m && m[1]) return m[1];
|
|
84
|
+
const vMatch = head.match(/v([0-9]+\.[0-9]+(\.[0-9]+)?)/i);
|
|
85
|
+
if (vMatch && vMatch[1]) return vMatch[1];
|
|
86
|
+
} catch (_) {}
|
|
87
|
+
|
|
88
|
+
if (lock?.skills) {
|
|
89
|
+
const lockEntry = lock.skills[skill.slug] || lock.skills[skill.full_slug];
|
|
90
|
+
if (lockEntry && lockEntry.version) return lockEntry.version;
|
|
91
|
+
}
|
|
92
|
+
return '1.0.0';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Bada stan instalacji i wersję skilla u wszystkich zadanych agentów.
|
|
97
|
+
*/
|
|
98
|
+
function inspectSkillForAgents(agents, skill, lock) {
|
|
99
|
+
const agentStatuses = {};
|
|
100
|
+
let installedCount = 0;
|
|
101
|
+
let upToDateCount = 0;
|
|
102
|
+
let outdatedCount = 0;
|
|
103
|
+
let missingCount = 0;
|
|
104
|
+
|
|
105
|
+
for (const agent of agents) {
|
|
106
|
+
const filePath = findSkillFileForAgent(agent, skill);
|
|
107
|
+
if (!filePath) {
|
|
108
|
+
agentStatuses[agent.id] = {
|
|
109
|
+
agentId: agent.id,
|
|
110
|
+
agentName: agent.name,
|
|
111
|
+
installed: false,
|
|
112
|
+
version: null,
|
|
113
|
+
status: 'missing',
|
|
114
|
+
filePath: null,
|
|
115
|
+
badge: `\x1b[90m[○ ${agent.id}: brak]\x1b[0m`,
|
|
116
|
+
};
|
|
117
|
+
missingCount += 1;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
installedCount += 1;
|
|
122
|
+
const installedVer = readSkillVersion(filePath, lock, skill);
|
|
123
|
+
const cmp = compareSemver(installedVer, skill.latest_version);
|
|
124
|
+
|
|
125
|
+
if (cmp >= 0) {
|
|
126
|
+
agentStatuses[agent.id] = {
|
|
127
|
+
agentId: agent.id,
|
|
128
|
+
agentName: agent.name,
|
|
129
|
+
installed: true,
|
|
130
|
+
version: installedVer,
|
|
131
|
+
status: 'up_to_date',
|
|
132
|
+
filePath,
|
|
133
|
+
badge: `\x1b[32m[✓ ${agent.id}: v${installedVer}]\x1b[0m`,
|
|
134
|
+
};
|
|
135
|
+
upToDateCount += 1;
|
|
136
|
+
} else {
|
|
137
|
+
agentStatuses[agent.id] = {
|
|
138
|
+
agentId: agent.id,
|
|
139
|
+
agentName: agent.name,
|
|
140
|
+
installed: true,
|
|
141
|
+
version: installedVer,
|
|
142
|
+
status: 'outdated',
|
|
143
|
+
target_version: skill.latest_version,
|
|
144
|
+
filePath,
|
|
145
|
+
badge: `\x1b[33m[↑ ${agent.id}: v${installedVer} → v${skill.latest_version}]\x1b[0m`,
|
|
146
|
+
};
|
|
147
|
+
outdatedCount += 1;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let overallStatus = 'missing';
|
|
152
|
+
let overallBadge = '\x1b[90m[○ Niezainstalowany]\x1b[0m';
|
|
153
|
+
|
|
154
|
+
if (installedCount > 0) {
|
|
155
|
+
if (installedCount === agents.length && outdatedCount === 0) {
|
|
156
|
+
overallStatus = 'up_to_date';
|
|
157
|
+
overallBadge = `\x1b[32m[✓ Aktualny (${installedCount}/${agents.length})]\x1b[0m`;
|
|
158
|
+
} else if (outdatedCount > 0) {
|
|
159
|
+
overallStatus = 'outdated';
|
|
160
|
+
overallBadge = `\x1b[33m[↑ Wymaga aktualizacji (${outdatedCount})]\x1b[0m`;
|
|
161
|
+
} else {
|
|
162
|
+
overallStatus = 'partial';
|
|
163
|
+
overallBadge = `\x1b[36m[◐ Częściowy (${installedCount}/${agents.length})]\x1b[0m`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
agents: agentStatuses,
|
|
169
|
+
installedCount,
|
|
170
|
+
upToDateCount,
|
|
171
|
+
outdatedCount,
|
|
172
|
+
missingCount,
|
|
173
|
+
overallStatus,
|
|
174
|
+
overallBadge,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
41
178
|
async function cmdSkillList(flags, out, err) {
|
|
42
|
-
out('Pobieram listę skilli z DeerSkills Hub...');
|
|
179
|
+
if (!flags.json) out('Pobieram listę skilli z DeerSkills Hub...');
|
|
43
180
|
const res = await skillsHub.listSkills({
|
|
44
181
|
query: flags.query,
|
|
45
182
|
tag: flags.tag,
|
|
46
183
|
category: flags.category,
|
|
47
184
|
scope: flags.scope,
|
|
48
|
-
limit: flags.limit ||
|
|
185
|
+
limit: flags.limit || 100,
|
|
49
186
|
});
|
|
50
187
|
|
|
51
188
|
if (!res.ok) {
|
|
@@ -54,66 +191,133 @@ async function cmdSkillList(flags, out, err) {
|
|
|
54
191
|
}
|
|
55
192
|
|
|
56
193
|
const items = Array.isArray(res.data) ? res.data : (res.data?.skills || []);
|
|
194
|
+
const agents = detectAgents({
|
|
195
|
+
dir: flags.dir,
|
|
196
|
+
agent: flags.agent,
|
|
197
|
+
'all-agents': flags['all-agents'],
|
|
198
|
+
});
|
|
199
|
+
const lock = readLock(flags.dir);
|
|
200
|
+
|
|
57
201
|
if (flags.json) {
|
|
58
|
-
|
|
202
|
+
const enriched = items.map((s) => {
|
|
203
|
+
const insp = inspectSkillForAgents(agents, s, lock);
|
|
204
|
+
return {
|
|
205
|
+
...s,
|
|
206
|
+
overall_status: insp.overallStatus,
|
|
207
|
+
agents: Object.fromEntries(
|
|
208
|
+
Object.entries(insp.agents).map(([id, data]) => [
|
|
209
|
+
id,
|
|
210
|
+
{
|
|
211
|
+
installed: data.installed,
|
|
212
|
+
version: data.version,
|
|
213
|
+
status: data.status,
|
|
214
|
+
target_version: data.target_version || null,
|
|
215
|
+
file_path: data.filePath,
|
|
216
|
+
},
|
|
217
|
+
])
|
|
218
|
+
),
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
out(JSON.stringify(enriched, null, 2));
|
|
59
222
|
return;
|
|
60
223
|
}
|
|
61
224
|
|
|
225
|
+
const agentSummary = {};
|
|
226
|
+
for (const a of agents) {
|
|
227
|
+
agentSummary[a.id] = {
|
|
228
|
+
name: a.name,
|
|
229
|
+
targetDir: a.targetDir,
|
|
230
|
+
total: items.length,
|
|
231
|
+
upToDate: 0,
|
|
232
|
+
outdated: 0,
|
|
233
|
+
missing: 0,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
62
237
|
out(`\n=== Dostępne Skille w DeerSkills Hub (${items.length}) ===\n`);
|
|
63
238
|
for (const s of items) {
|
|
64
239
|
const badge = s.scope === 'global' ? '★ GLOBAL' : `@${s.namespace}`;
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
240
|
+
const latestVer = s.latest_version ? `v${s.latest_version}` : 'v1.0.0';
|
|
241
|
+
const insp = inspectSkillForAgents(agents, s, lock);
|
|
242
|
+
|
|
243
|
+
for (const a of agents) {
|
|
244
|
+
const st = insp.agents[a.id];
|
|
245
|
+
if (st.status === 'up_to_date') agentSummary[a.id].upToDate += 1;
|
|
246
|
+
else if (st.status === 'outdated') agentSummary[a.id].outdated += 1;
|
|
247
|
+
else agentSummary[a.id].missing += 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const agentBadges = agents.map((a) => insp.agents[a.id].badge).join(' ');
|
|
251
|
+
|
|
252
|
+
out(` • ${s.full_slug.padEnd(36)} ${latestVer.padEnd(10)} ${badge.padEnd(14)} ${insp.overallBadge}`);
|
|
253
|
+
out(` Agenci: ${agentBadges}`);
|
|
254
|
+
if (s.summary) out(` ${s.summary.slice(0, 95)}...`);
|
|
68
255
|
if (s.tags && s.tags.length) out(` Tagi: ${s.tags.join(', ')}`);
|
|
69
256
|
out('');
|
|
70
257
|
}
|
|
258
|
+
|
|
259
|
+
out('─'.repeat(78));
|
|
260
|
+
out(`📊 Stan platform agentów AI / lokalnego środowiska agenta:`);
|
|
261
|
+
let anyOutdated = false;
|
|
262
|
+
let anyMissing = false;
|
|
263
|
+
|
|
264
|
+
for (const a of agents) {
|
|
265
|
+
const sum = agentSummary[a.id];
|
|
266
|
+
if (sum.outdated > 0) anyOutdated = true;
|
|
267
|
+
if (sum.missing > 0) anyMissing = true;
|
|
268
|
+
|
|
269
|
+
let badgeText = '';
|
|
270
|
+
if (sum.upToDate === sum.total) {
|
|
271
|
+
badgeText = `\x1b[32m${sum.upToDate}/${sum.total} aktualne\x1b[0m`;
|
|
272
|
+
} else {
|
|
273
|
+
const parts = [];
|
|
274
|
+
if (sum.upToDate > 0) parts.push(`\x1b[32m${sum.upToDate} aktualne\x1b[0m`);
|
|
275
|
+
if (sum.outdated > 0) parts.push(`\x1b[33m${sum.outdated} do aktualizacji\x1b[0m`);
|
|
276
|
+
if (sum.missing > 0) parts.push(`\x1b[90m${sum.missing} brak\x1b[0m`);
|
|
277
|
+
badgeText = parts.join(', ');
|
|
278
|
+
}
|
|
279
|
+
out(` • ${(a.name + ' (' + a.id + '):').padEnd(36)} ${badgeText}`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (anyOutdated || anyMissing) {
|
|
283
|
+
out(`\n💡 Aby zainstalować brakujące i zaktualizować wszystkie skille u agentów:`);
|
|
284
|
+
out(` \x1b[36mdeertools skill sync\x1b[0m (lub: \x1b[36mdeertools sync\x1b[0m)`);
|
|
285
|
+
} else {
|
|
286
|
+
out(`\n✓ Wszystkie skille zespołu (${items.length}) są zainstalowane i aktualne u wszystkich wykrytych agentów.`);
|
|
287
|
+
}
|
|
288
|
+
out('─'.repeat(78) + '\n');
|
|
71
289
|
}
|
|
72
290
|
|
|
73
291
|
async function cmdSkillSearch(query, flags, out, err) {
|
|
74
292
|
return cmdSkillList({ ...flags, query }, out, err);
|
|
75
293
|
}
|
|
76
294
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (!r.ok) continue;
|
|
90
|
-
const skillName = parseFrontmatterName(r.text) || `deer-${product.id}`;
|
|
91
|
-
for (const agent of agents) {
|
|
92
|
-
try {
|
|
93
|
-
const dest = installSkillContent(agent, skillName, r.text);
|
|
94
|
-
out(`✓ [${agent.id}] ${product.name}: ${dest}`);
|
|
95
|
-
installed += 1;
|
|
96
|
-
} catch (e) {
|
|
97
|
-
err(`✗ [${agent.id}] ${product.name}: ${e.message}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (!installed) throw new Error('Nie zainstalowano żadnego skilla produktowego.');
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
295
|
+
/**
|
|
296
|
+
* Instaluje pojedynczy skill z DeerSkills Hub.
|
|
297
|
+
*/
|
|
298
|
+
async function installSingleSkill(slug, requestedVersion, flags, out, err, { silentSummary = false } = {}) {
|
|
299
|
+
const legacyMap = {
|
|
300
|
+
estimate: 'deer-kosztorys',
|
|
301
|
+
catalog: 'deer-catalog',
|
|
302
|
+
deliveries: 'deertools-dostawy',
|
|
303
|
+
supplier: 'deertools-supplier-hub',
|
|
304
|
+
rendermind: 'rendermind',
|
|
305
|
+
};
|
|
306
|
+
const resolvedSlug = legacyMap[slug] || slug;
|
|
104
307
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
308
|
+
if (!silentSummary) {
|
|
309
|
+
out(`Pobieram skill „${resolvedSlug}”${requestedVersion ? ` w wersji ${requestedVersion}` : ''} z DeerSkills Hub...`);
|
|
310
|
+
}
|
|
311
|
+
const res = await skillsHub.getSkill(resolvedSlug, requestedVersion);
|
|
108
312
|
|
|
109
313
|
if (!res.ok || !res.data?.skill) {
|
|
110
|
-
throw new Error(`Nie znaleziono skilla „${
|
|
314
|
+
throw new Error(`Nie znaleziono skilla „${resolvedSlug}” w DeerSkills Hub (${res.status}): ${res.data?.error || 'Błąd'}`);
|
|
111
315
|
}
|
|
112
316
|
|
|
113
317
|
const skill = res.data.skill;
|
|
114
318
|
const versionData = res.data.selected_version || res.data.version || (res.data.versions && res.data.versions[0]);
|
|
115
319
|
if (!versionData) {
|
|
116
|
-
throw new Error(`Brak opublikowanej wersji dla skilla „${
|
|
320
|
+
throw new Error(`Brak opublikowanej wersji dla skilla „${resolvedSlug}”.`);
|
|
117
321
|
}
|
|
118
322
|
const agents = detectAgents({ dir: flags.dir, agent: flags.agent });
|
|
119
323
|
|
|
@@ -125,12 +329,14 @@ async function cmdSkillInstall(target, flags, out, err) {
|
|
|
125
329
|
for (const agent of agents) {
|
|
126
330
|
try {
|
|
127
331
|
const dest = installSkillContent(agent, skill.slug, versionData.skill_md_content);
|
|
128
|
-
|
|
332
|
+
if (!silentSummary) {
|
|
333
|
+
out(`✓ [${agent.id}] Zainstalowano ${skill.full_slug} (${versionData.version}) → ${dest}`);
|
|
334
|
+
}
|
|
129
335
|
count += 1;
|
|
130
336
|
|
|
131
337
|
// Jeśli są dodatkowe pliki w manifeście, zapisz je obok SKILL.md
|
|
132
338
|
if (versionData.files_manifest && Array.isArray(versionData.files_manifest)) {
|
|
133
|
-
const baseDir = path.dirname(dest);
|
|
339
|
+
const baseDir = agent.format === 'cursor_mdc' ? path.join(agent.targetDir, skill.slug) : path.dirname(dest);
|
|
134
340
|
for (const file of versionData.files_manifest) {
|
|
135
341
|
const targetFile = path.join(baseDir, file.path);
|
|
136
342
|
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
@@ -147,18 +353,112 @@ async function cmdSkillInstall(target, flags, out, err) {
|
|
|
147
353
|
}
|
|
148
354
|
|
|
149
355
|
// Zapis do .deertools-lock.json
|
|
150
|
-
const lock = readLock();
|
|
356
|
+
const lock = readLock(flags.dir);
|
|
151
357
|
lock.skills[skill.slug] = {
|
|
152
358
|
fullSlug: skill.full_slug,
|
|
153
359
|
version: versionData.version,
|
|
154
360
|
installedAt: new Date().toISOString(),
|
|
155
361
|
sha256: versionData.sha256_checksum,
|
|
156
362
|
};
|
|
157
|
-
writeLock(lock);
|
|
158
|
-
|
|
363
|
+
writeLock(lock, flags.dir);
|
|
364
|
+
|
|
365
|
+
if (!silentSummary) {
|
|
366
|
+
out(`✓ Zaktualizowano ${LOCK_FILE} (wersja ${versionData.version}).`);
|
|
367
|
+
printSkillSummary(skill, versionData, out);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return { skill, versionData, count };
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Instaluje lub synchronizuje wszystkie skille zespołu z DeerSkills Hub.
|
|
375
|
+
*/
|
|
376
|
+
async function cmdSkillSync(flags, out, err) {
|
|
377
|
+
out('Pobieram pełną listę skilli zespołu z DeerSkills Hub...');
|
|
378
|
+
const res = await skillsHub.listSkills({ limit: 100 });
|
|
379
|
+
if (!res.ok) {
|
|
380
|
+
err(`✗ Błąd pobierania katalogu skilli (${res.status}): ${res.data?.error || 'Brak dostępu'}`);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const items = Array.isArray(res.data) ? res.data : (res.data?.skills || []);
|
|
384
|
+
if (items.length === 0) {
|
|
385
|
+
out('Brak skilli w DeerSkills Hub.');
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let agents = detectAgents({ dir: flags.dir, agent: flags.agent });
|
|
390
|
+
if (flags.i || flags.interactive || flags.select) {
|
|
391
|
+
const { promptSelectAgents } = require('./agent-detector');
|
|
392
|
+
const available = detectAgents({ dir: flags.dir, 'ignore-selected': true });
|
|
393
|
+
agents = await promptSelectAgents(available);
|
|
394
|
+
flags = { ...flags, agent: agents.map((a) => a.id).join(',') };
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (agents.length === 0) {
|
|
398
|
+
err('✗ Nie wybrano ani nie wykryto żadnego środowiska agenta AI.');
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const lock = readLock(flags.dir);
|
|
403
|
+
out(`Platformy docelowe: \x1b[36m${agents.map((a) => a.name || a.id).join(', ')}\x1b[0m`);
|
|
404
|
+
out(`Rozpoczynam synchronizację ${items.length} skilli zespołu...\n`);
|
|
405
|
+
|
|
406
|
+
let installedCount = 0;
|
|
407
|
+
let updatedCount = 0;
|
|
408
|
+
let unchangedCount = 0;
|
|
409
|
+
let failedCount = 0;
|
|
410
|
+
|
|
411
|
+
for (const s of items) {
|
|
412
|
+
const slug = s.slug;
|
|
413
|
+
const fullSlug = s.full_slug;
|
|
414
|
+
const current = lock.skills?.[slug] || lock.skills?.[fullSlug];
|
|
415
|
+
const currentVer = current?.version;
|
|
416
|
+
const latestVer = s.latest_version || '1.0.0';
|
|
417
|
+
|
|
418
|
+
if (currentVer && currentVer === latestVer && !flags.force) {
|
|
419
|
+
out(` \x1b[32m✓\x1b[0m ${s.full_slug.padEnd(38)} v${currentVer.padEnd(8)} [Aktualny]`);
|
|
420
|
+
unchangedCount += 1;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
await installSingleSkill(s.full_slug || s.slug, latestVer, flags, out, err, { silentSummary: true });
|
|
426
|
+
if (currentVer) {
|
|
427
|
+
out(` \x1b[33m↑\x1b[0m ${s.full_slug.padEnd(38)} v${latestVer.padEnd(8)} [Zaktualizowano z v${currentVer}]`);
|
|
428
|
+
updatedCount += 1;
|
|
429
|
+
} else {
|
|
430
|
+
out(` \x1b[36m+\x1b[0m ${s.full_slug.padEnd(38)} v${latestVer.padEnd(8)} [Zainstalowano]`);
|
|
431
|
+
installedCount += 1;
|
|
432
|
+
}
|
|
433
|
+
} catch (e) {
|
|
434
|
+
out(` \x1b[31m✗\x1b[0m ${s.full_slug.padEnd(38)} Błąd: ${e.message}`);
|
|
435
|
+
failedCount += 1;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
out('\n' + '─'.repeat(72));
|
|
440
|
+
out(`\x1b[1m✓ Podsumowanie synchronizacji ekosystemu Deer Design:\x1b[0m`);
|
|
441
|
+
out(` • Nowo zainstalowane: \x1b[36m${installedCount}\x1b[0m`);
|
|
442
|
+
out(` • Zaktualizowane: \x1b[33m${updatedCount}\x1b[0m`);
|
|
443
|
+
out(` • Aktualne bez zmian: \x1b[32m${unchangedCount}\x1b[0m`);
|
|
444
|
+
if (failedCount > 0) {
|
|
445
|
+
out(` • Błędy instalacji: \x1b[31m${failedCount}\x1b[0m`);
|
|
446
|
+
}
|
|
447
|
+
out(` • Agenci docelowi: ${agents.map((a) => a.id).join(', ')}`);
|
|
448
|
+
out(` • Zapisano w rejestrze: ${LOCK_FILE}`);
|
|
449
|
+
out('─'.repeat(72) + '\n');
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
async function cmdSkillInstall(target, flags, out, err) {
|
|
453
|
+
let [slug, requestedVersion] = String(target || '').split('@');
|
|
454
|
+
slug = (slug || '').trim();
|
|
455
|
+
|
|
456
|
+
// Jeśli brak argumentu lub "all" / "--all" / "team" / "*" lub flaga --all, synchronizuj wszystkie
|
|
457
|
+
if (!slug || slug === 'all' || slug === '--all' || slug === 'team' || slug === '*' || flags.all) {
|
|
458
|
+
return cmdSkillSync(flags, out, err);
|
|
459
|
+
}
|
|
159
460
|
|
|
160
|
-
|
|
161
|
-
printSkillSummary(skill, versionData, out);
|
|
461
|
+
await installSingleSkill(slug, requestedVersion, flags, out, err);
|
|
162
462
|
}
|
|
163
463
|
|
|
164
464
|
function extractCapabilities(content, summary = '') {
|
|
@@ -479,6 +779,7 @@ module.exports = {
|
|
|
479
779
|
cmdSkillList,
|
|
480
780
|
cmdSkillSearch,
|
|
481
781
|
cmdSkillInstall,
|
|
782
|
+
cmdSkillSync,
|
|
482
783
|
cmdSkillPush,
|
|
483
784
|
cmdSkillCheck,
|
|
484
785
|
cmdSkillUpdate,
|