@deerdesign/deertools 1.2.13 → 1.2.21

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 CHANGED
@@ -185,18 +185,30 @@ 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 skille (oficjalne globalne i Twoje)
189
- deertools skill search "kosztorys" # Wyszukaj skille po nazwie, tagu lub opisie
190
- deertools skill install deer-kosztorys # Zainstaluj skill w ~/.gemini/antigravity/skills lub .agents
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 install all # Zainstaluj wszystkie oficjalne skille Deer Design
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
- deertools skill push ./my-skill --bump minor # Automatyczne podbicie wersji SemVer
195
+ deertools skill push ./my-skill --tags "wycena, kosztorys, marże" # Dodaj tagi przy publikacji
196
+ deertools skill push ./my-skill --team architekci # Publikacja bezpośrednio do zespołu
197
+ deertools skill share my-skill --team architekci # Udostępnij skill dla wskazanego zespołu
198
+ deertools skill share my-skill --private # Cofnij udostępnienie (tylko dla autora)
195
199
  deertools skill update deer-kosztorys # Zaktualizuj zainstalowany skill do najnowszej wersji
196
200
  deertools skill update # Zaktualizuj wszystkie zainstalowane skille
197
201
  deertools skill promote my-skill # Zgłoś wniosek do admina o nominację do globalnego katalogu
198
202
 
199
- # 13. AI Agent MCP Registry & Configuration:
203
+ # 13. Team Management (Konfiguracja Zespołów):
204
+ deertools team list # Lista zespołów, liczba członków i skilli
205
+ deertools team members architekci # Członkowie i role w zespole architekci
206
+ deertools team add architekci jan@deer.pl # Dodaj członka do zespołu (rola member)
207
+ deertools team add architekci ewa@deer.pl --role lead # Dodaj lidera zespołu
208
+ deertools team remove architekci jan@deer.pl # Usuń członka z zespołu
209
+ deertools team create "Projektanci Wnętrz" --slug projektanci # Utwórz nowy zespół
210
+
211
+ # 14. AI Agent MCP Registry & Configuration:
200
212
  deertools mcp list # Lista dostępnych serwerów MCP w ekosystemie
201
213
  deertools mcp config # Wygeneruj konfigurację JSON dla Cursor, Claude, Antigravity
202
214
  deertools mcp install # Automatycznie dopisz konfigurację do narzędzi AI
@@ -233,10 +245,10 @@ deertools mcp install # Automatycznie dopisz konfiguracj
233
245
 
234
246
  **DeerSkills Hub** (`https://skills.deergroup.pl`) to centralna platforma dystrybucji, wersjonowania i zarządzania umiejętnościami agentów AI (Skills) oraz serwerami MCP w ekosystemie Deer Design:
235
247
 
236
- 1. **Struktura i Uprawnienia**:
237
- - **Oficjalne Skille (`global`)**: Zweryfikowane, wersjonowane semantycznie (`v1.0.0`) narzędzia firmowe, zarządzane wyłącznie przez Administratorów.
238
- - **Skille Użytkowników (`user`)**: Każdy pracownik może tworzyć i wersjonować własne skille pod przestrzenią `@uzytkownik/nazwa-skilla`.
239
- - **Widoczność**: `shared` (dostępne wewnątrz firmy dla zalogowanych) lub `private` (widoczne tylko dla autora).
248
+ 1. **Trzypoziomowa Struktura Uprawnień i Widoczności**:
249
+ - **Oficjalne Skille Firmowe (`global`)**: Zweryfikowane narzędzia firmowe, widoczne dla wszystkich pracowników w organizacji, instalowane domyślnie.
250
+ - **Skille Zespołowe (`team`)**: Dedykowane dla konkretnego zespołu (np. Architekci, Doradcy Klienta, Kosztorysy, Logistyka, IT-Dev). Widoczne i instalowalne **wyłącznie** przez członków danego zespołu. Zespoły i role są w pełni konfigurowalne przez `deertools team` oraz portal Web.
251
+ - **Prywatne Skille Użytkownika (`user`)**: Każdy pracownik publikuje pod własną przestrzenią `@uzytkownik/nazwa-skilla`. Są w 100% prywatne (niewidoczne dla innych), dopóki autor nie zdecyduje się ich udostępnić swojemu zespołowi (`deertools skill share --team <slug>`) lub zgłosić do publikacji globalnej (`deertools skill promote`).
240
252
  2. **Automatyczny Skaner Sekretów**:
241
253
  - Każde wywołanie `deertools skill push` automatycznie skanuje pliki skilla w poszukiwaniu niebezpiecznych tokenów (`deer_*_live_`, `ghp_`, `sk-`, `X-BLToken`, haseł).
242
254
  - Próba wysłania niezanominizowanych kluczy kończy się natychmiastową blokadą z kodem błędu i listą wykrytych linii.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deerdesign/deertools",
3
- "version": "1.2.13",
3
+ "version": "1.2.21",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
@@ -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
- * Wykrywa zainstalowane środowiska agentów lub filtruje według flagi --agent.
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 obsługiwanych platform (--all-agents)
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 (--agent claude / --agent codex / --agent hermes / etc.)
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.toLowerCase().trim();
93
- const spec = KNOWN_AGENTS.find((a) => a.id === requested);
94
- if (spec) {
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
- module.exports = { KNOWN_AGENTS, detectAgents, installSkillContent };
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,9 @@ 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,
37
+ team: c.cmdTeam, teams: c.cmdTeam,
35
38
  mcp: c.cmdMcp, doctor: c.cmdDoctor, audit: c.cmdAudit, profile: c.cmdProfile,
36
39
  completion: c.cmdCompletion, catalog: c.cmdCatalog, deliveries: c.cmdDeliveries,
37
40
  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
  }
@@ -403,10 +406,27 @@ async function cmdSkill(pos, flags) {
403
406
  if (sub === 'promote') {
404
407
  return skillCommands.cmdSkillPromote(pos[1], flags, out, err);
405
408
  }
409
+ if (sub === 'review' || sub === 'reviews') {
410
+ return skillCommands.cmdSkillReview(pos.slice(1), flags, out, err);
411
+ }
412
+ if (sub === 'approve') {
413
+ return skillCommands.cmdSkillReview(['approve', ...pos.slice(1)], flags, out, err);
414
+ }
415
+ if (sub === 'reject') {
416
+ return skillCommands.cmdSkillReview(['reject', ...pos.slice(1)], flags, out, err);
417
+ }
418
+ if (sub === 'share') {
419
+ return skillCommands.cmdSkillShare(pos[1], flags, out, err);
420
+ }
421
+ if (sub === 'team' || sub === 'teams') {
422
+ const { cmdTeam: runTeam } = require('./team-commands');
423
+ return runTeam(pos.slice(1), flags, out, err);
424
+ }
406
425
  if (sub === 'install') {
407
- return skillCommands.cmdSkillInstall(pos[1], flags, out, err);
426
+ const target = pos[1] || (flags.all ? '--all' : null);
427
+ return skillCommands.cmdSkillInstall(target, flags, out, err);
408
428
  }
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 <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);
429
+ 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] [--team <zespół>] [--own|--global] [--bump patch|minor|major]\n deertools skill share <slug> --team <zespół>\n deertools skill review [list|approve|reject|submit]\n deertools skill promote <slug>', 2);
410
430
  }
411
431
 
412
432
 
@@ -508,6 +528,96 @@ async function cmdMcp(pos, flags) {
508
528
  fail('Użycie: deertools mcp [config|install|serve] [produkt|all] [--json]', 2);
509
529
  }
510
530
 
531
+ async function cmdAgent(pos, flags) {
532
+ const {
533
+ KNOWN_AGENTS,
534
+ detectAgents,
535
+ getSelectedAgents,
536
+ setSelectedAgents,
537
+ clearSelectedAgents,
538
+ promptSelectAgents,
539
+ } = require('./agent-detector');
540
+ const action = pos[0] || 'list';
541
+
542
+ if (action === 'list') {
543
+ const selected = getSelectedAgents();
544
+ const detected = detectAgents({ 'ignore-selected': true });
545
+ const detectedIds = new Set(detected.map((a) => a.id));
546
+
547
+ out(`\n=== Platformy Agentów AI (DeerTools) ===\n`);
548
+ for (const a of KNOWN_AGENTS) {
549
+ const isDetected = detectedIds.has(a.id);
550
+ const isActive = selected ? selected.includes(a.id) : isDetected;
551
+
552
+ let statusBadge = '\x1b[90m[○ Niewykryty na PC]\x1b[0m';
553
+ if (isDetected) statusBadge = '\x1b[32m[✓ Wykryty na PC]\x1b[0m';
554
+
555
+ let activeBadge = '';
556
+ if (isActive) {
557
+ activeBadge = ' \x1b[36m(AKTYWNY DLA SKILLI)\x1b[0m';
558
+ }
559
+
560
+ out(` • ${a.id.padEnd(16)} ${(a.name).padEnd(32)} ${statusBadge}${activeBadge}`);
561
+ out(` Ścieżka: ${a.getTarget(os.homedir(), process.cwd())}`);
562
+ out('');
563
+ }
564
+
565
+ out('─'.repeat(72));
566
+ if (selected && selected.length > 0) {
567
+ out(`📌 Wybrane platformy na tym PC: \x1b[36m${selected.join(', ')}\x1b[0m (zapisane w ~/.deertools/config.json)`);
568
+ out(` Skille instalują się tylko u wybranych agentów.`);
569
+ out(` Aby przywrócić auto-wykrywanie wszystkich: \x1b[33mdeertools agent reset\x1b[0m`);
570
+ } else {
571
+ out(`⚡ Tryb: \x1b[32mAutomatyczne wykrywanie wszystkich platform obecnych na komputerze\x1b[0m`);
572
+ out(` Aby ograniczyć synchronizację do wybranych agentów:`);
573
+ out(` \x1b[36mdeertools agent select antigravity,cursor\x1b[0m`);
574
+ }
575
+ out('─'.repeat(72) + '\n');
576
+ return;
577
+ }
578
+
579
+ if (action === 'select' || action === 'set') {
580
+ let targets = pos.slice(1).join(',').split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
581
+ if (targets.length === 0) {
582
+ const detected = detectAgents({ 'ignore-selected': true });
583
+ const picked = await promptSelectAgents(detected);
584
+ targets = picked.map((a) => a.id);
585
+ }
586
+
587
+ const validIds = KNOWN_AGENTS.map((a) => a.id);
588
+ const validTargets = targets.filter((id) => validIds.includes(id));
589
+
590
+ if (validTargets.length === 0) {
591
+ fail(`Błąd: Podaj poprawne identyfikatory agentów: ${validIds.join(', ')}`, 2);
592
+ }
593
+
594
+ setSelectedAgents(validTargets);
595
+ out(`✓ Zapisano aktywnych agentów na tym komputerze: \x1b[36m${validTargets.join(', ')}\x1b[0m`);
596
+ out(`Od teraz deertools skill sync i skill install instalują skille tylko dla tych platform.`);
597
+ out(`Aby przywrócić instalację u wszystkich wykrytych: deertools agent reset\n`);
598
+ return;
599
+ }
600
+
601
+ if (action === 'reset' || action === 'clear') {
602
+ clearSelectedAgents();
603
+ out(`✓ Zresetowano konfigurację agentów. Przywrócono automatyczne wykrywanie obecnych na PC.\n`);
604
+ return;
605
+ }
606
+
607
+ if (action === 'current') {
608
+ const active = detectAgents({});
609
+ out(active.map((a) => a.id).join(','));
610
+ return;
611
+ }
612
+
613
+ fail(`Nieznana podkomenda „agent ${action}”. Użyj: deertools agent [list|select <agenty>|reset|current]`, 2);
614
+ }
615
+
616
+ async function cmdTeam(pos, flags) {
617
+ const { cmdTeam: runTeam } = require('./team-commands');
618
+ return runTeam(pos, flags, out, err);
619
+ }
620
+
511
621
  const { cmdDoctor } = require('./doctor');
512
622
  const { cmdAudit } = require('./audit');
513
623
  const { cmdProfile } = require('./profiles');
@@ -544,12 +654,16 @@ BaseLinker MCP Proxy & Hub:
544
654
  deertools baselinker catalog <search|get> Operacje katalogowe z poziomu terminala.
545
655
 
546
656
  Integracje MCP i Agenci AI (DeerSkills Hub):
547
- deertools skill list [--tag <tag>] Przegląda skille globalne i użytkownika w DeerSkills Hub.
657
+ deertools agent [list|select <agenty>|reset] Wykrywanie i konfiguracja platform agentów AI na PC.
658
+ deertools skill list [--tag <tag>] Przegląda skille w Hubie wraz ze statusem zainstalowania.
659
+ deertools skill sync [--agent <id>|-i|--force] Instaluje brakujące i aktualizuje obecne skille zespołu.
660
+ deertools skill install [--all|<slug[@wersja]>] Instaluje wszystkie skille (--all) lub wskazany skill.
548
661
  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
662
  deertools skill versions <slug> Historia wydań z changelogami z commitów i datami.
551
663
  deertools skill diff <slug> [wersjaA] [wersjaB] Porównanie zmian w plikach paczki i treści SKILL.md.
552
- deertools skill push [katalog] [--bump patch|minor] Publikuje nową wersję z automatycznym skanerem sekretów.
664
+ deertools skill push [katalog] [--team <zespół>] Publikuje do własnej przestrzeni, zespołu lub globalnie.
665
+ deertools skill share <slug> --team <zespół> Udostępnia skill prywatny wskazanemu zespołowi.
666
+ deertools skill review [list|approve|reject|submit] Zarządzanie procesem Peer Review i weryfikacją skilli zespołu.
553
667
  deertools skill update [slug] Aktualizuje zainstalowane skille do najnowszej wersji.
554
668
  deertools skill promote <slug> Zgłasza nominację skilla do oficjalnego katalogu globalnego.
555
669
  deertools mcp list Lista dostępnych serwerów MCP w chmurze.
@@ -560,19 +674,26 @@ Integracje MCP i Agenci AI (DeerSkills Hub):
560
674
  deertools endpoints <produkt> [--json] Lista endpointów REST z openapi.json.
561
675
  deertools api <produkt> <METODA> </ścieżka> Wywołuje bezpośrednio API produktu.
562
676
 
677
+ Zarządzanie zespołami (DeerSkills Hub Teams):
678
+ deertools team [list] Przegląda listę zespołów, liczbę członków i przypisanych skilli.
679
+ deertools team members [zespół] Lista członków zespołów i ich ról (Lider / Członek).
680
+ deertools team add <zespół> <email> [--role lead] Dodaje lub aktualizuje rolę pracownika w zespole.
681
+ deertools team remove <zespół> <email> Usuwa pracownika ze wskazanego zespołu.
682
+ deertools team create <nazwa> [--slug <s>] [--desc] Tworzy nowy zespół w organizacji Deer Design.
683
+
563
684
  Narzędzia systemowe:
564
685
  deertools update Sprawdza i podpowiada aktualizację CLI.
565
686
  deertools doctor [--json] Pełna diagnostyka połączeń, portów i kluczy.
566
687
  deertools audit [--limit 25] [--clear] [--json] Historia operacji i wywołań API.
567
688
  deertools completion [install|zsh|bash] Autouzupełnianie w powłoce po wciśnięciu Tab.
568
689
 
569
- Zmienne środowiskowe: DEERTOOLS_<PRODUKT>_KEY, BASELINKER_TOKEN, DEERTOOLS_HOME, DEERTOOLS_PROFILE.
690
+ Zmienne środowiskowe: DEERTOOLS_<PRODUKT>_KEY, BASELINKER_TOKEN, DEERTOOLS_HOME, DEERTOOLS_PROFILE, DEERTOOLS_AGENTS.
570
691
  `;
571
692
 
572
693
  module.exports = {
573
694
  cmdLogin, cmdLogout, cmdWhoami, cmdDocs, cmdEndpoints, cmdApi, cmdEstimate, cmdSkill, cmdMcp,
574
695
  cmdDoctor, cmdAudit, cmdProfile, cmdCompletion, cmdCatalog, cmdDeliveries, cmdSupplier, cmdRendermind,
575
- cmdBaseLinker,
696
+ cmdBaseLinker, cmdAgent, cmdTeam,
576
697
  HELP, parseQuery,
577
698
  };
578
699
 
package/src/mcp-stdio.js CHANGED
@@ -4,6 +4,7 @@ const credentials = require('./credentials');
4
4
  const { ALL_PRODUCTS, getProduct } = require('./registry');
5
5
  const { apiRequest } = require('./http');
6
6
  const { checkSkillUpdates, updateSkills } = require('./skill-commands');
7
+ const skillsHub = require('./skills-hub');
7
8
 
8
9
  const PROTOCOL_VERSION = '2024-11-05';
9
10
  const SERVER_INFO = { name: 'deertools-stdio-bridge', version: '1.0.5' };
@@ -113,6 +114,40 @@ async function cmdMcpServe(pos, flags) {
113
114
  required: ['confirmed'],
114
115
  },
115
116
  },
117
+ {
118
+ name: 'deer_list_skill_reviews',
119
+ description: 'Pobiera kolejkę zgłoszeń skilli do Peer Review z DeerSkills Hub (zgłoszenia oczekujące, zatwierdzone lub odesłane do poprawek).',
120
+ inputSchema: {
121
+ type: 'object',
122
+ properties: {
123
+ status: { type: 'string', enum: ['pending', 'approved', 'changes_requested', 'all'], description: 'Status zgłoszenia (domyślnie pending - oczekujące)' },
124
+ },
125
+ },
126
+ },
127
+ {
128
+ name: 'deer_decide_skill_review',
129
+ description: 'Rozpatrzenie zgłoszonego skilla w Peer Review (zatwierdzenie do katalogu globalnego lub odesłanie do poprawek z uwagami) przez leada/admina.',
130
+ inputSchema: {
131
+ type: 'object',
132
+ properties: {
133
+ slug: { type: 'string', description: 'Identyfikator (slug) zgłoszonego skilla, np. deer-technical-documentation' },
134
+ approve: { type: 'boolean', description: 'true = zatwierdź (Approve) i przenieś do katalogu globalnego, false = odeślij do poprawek (Request Changes)' },
135
+ notes: { type: 'string', description: 'Uwagi i wytyczne dla autora (obowiązkowe przy odrzuceniu/poprawkach)' },
136
+ },
137
+ required: ['slug', 'approve'],
138
+ },
139
+ },
140
+ {
141
+ name: 'deer_submit_skill_review',
142
+ description: 'Zgłoszenie własnego opublikowanego skilla do weryfikacji zespołu / Peer Review w DeerSkills Hub.',
143
+ inputSchema: {
144
+ type: 'object',
145
+ properties: {
146
+ slug: { type: 'string', description: 'Identyfikator (slug) skilla do zgłoszenia, np. @mariusz.szostak/moj-skill' },
147
+ },
148
+ required: ['slug'],
149
+ },
150
+ },
116
151
  ];
117
152
 
118
153
  send({ jsonrpc: '2.0', id, result: { tools } });
@@ -269,6 +304,77 @@ async function cmdMcpServe(pos, flags) {
269
304
  return;
270
305
  }
271
306
 
307
+ if (toolName === 'deer_list_skill_reviews') {
308
+ const res = await skillsHub.listReviews({ status: args.status || 'pending' });
309
+ if (!res.ok) {
310
+ send({ jsonrpc: '2.0', id, error: { code: -32000, message: res.data?.error || `Błąd pobierania (${res.status})` } });
311
+ return;
312
+ }
313
+ send({
314
+ jsonrpc: '2.0',
315
+ id,
316
+ result: { content: [{ type: 'text', text: JSON.stringify(res.data, null, 2) }] },
317
+ });
318
+ return;
319
+ }
320
+
321
+ if (toolName === 'deer_decide_skill_review') {
322
+ const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(args.slug);
323
+ const res = await skillsHub.decideReview({
324
+ slug: isUuid ? null : args.slug,
325
+ reviewId: isUuid ? args.slug : null,
326
+ approve: Boolean(args.approve),
327
+ notes: args.notes || '',
328
+ });
329
+ if (!res.ok) {
330
+ send({ jsonrpc: '2.0', id, error: { code: -32000, message: res.data?.error || `Błąd rozpatrywania (${res.status})` } });
331
+ return;
332
+ }
333
+ send({
334
+ jsonrpc: '2.0',
335
+ id,
336
+ result: {
337
+ content: [{
338
+ type: 'text',
339
+ text: JSON.stringify({
340
+ success: true,
341
+ decision: args.approve ? 'approved' : 'changes_requested',
342
+ skill: res.data?.skill || res.data,
343
+ notes: args.notes || null,
344
+ message: args.approve
345
+ ? `Skill został pomyślnie zatwierdzony i opublikowany w katalogu globalnym zespołu.`
346
+ : `Zgłoszenie zostało odesłane do poprawek z uwagami dla autora.`,
347
+ }, null, 2),
348
+ }],
349
+ },
350
+ });
351
+ return;
352
+ }
353
+
354
+ if (toolName === 'deer_submit_skill_review') {
355
+ const res = await skillsHub.submitReview(args.slug);
356
+ if (!res.ok) {
357
+ send({ jsonrpc: '2.0', id, error: { code: -32000, message: res.data?.error || `Błąd zgłaszania (${res.status})` } });
358
+ return;
359
+ }
360
+ send({
361
+ jsonrpc: '2.0',
362
+ id,
363
+ result: {
364
+ content: [{
365
+ type: 'text',
366
+ text: JSON.stringify({
367
+ success: true,
368
+ status: 'in_review',
369
+ skill: args.slug,
370
+ message: `Skill ${args.slug} został pomyślnie zgłoszony do Peer Review zespołu.`,
371
+ }, null, 2),
372
+ }],
373
+ },
374
+ });
375
+ return;
376
+ }
377
+
272
378
  send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Tool not found: ${toolName}` } });
273
379
  } catch (e) {
274
380
  send({ jsonrpc: '2.0', id, error: { code: -32000, message: e.message } });