@deerdesign/deertools 1.2.8 → 1.2.11

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
@@ -34,7 +34,7 @@ Requires **Node.js ≥ 18**. Zero runtime dependencies.
34
34
  ### Option 1: Run instantly with `npx` (No installation needed)
35
35
 
36
36
  ```bash
37
- npx @deerdesign/deertools login catalog
37
+ npx -y @deerdesign/deertools@latest login catalog
38
38
  ```
39
39
 
40
40
  ### Option 2: Install globally
@@ -54,7 +54,7 @@ deer whoami # skrócony alias
54
54
 
55
55
  ### 2. Uruchomienie ad-hoc bez instalacji:
56
56
  ```bash
57
- npx @deerdesign/deertools doctor
57
+ npx -y @deerdesign/deertools@latest doctor
58
58
  ```
59
59
 
60
60
  ### 3. Klonowanie repozytorium (wersja deweloperska):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deerdesign/deertools",
3
- "version": "1.2.8",
3
+ "version": "1.2.11",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"
package/src/commands.js CHANGED
@@ -381,6 +381,9 @@ async function cmdSkill(pos, flags) {
381
381
  if (sub === 'push') {
382
382
  return skillCommands.cmdSkillPush(pos[1], flags, out, err);
383
383
  }
384
+ if (sub === 'check' || sub === 'status') {
385
+ return skillCommands.cmdSkillCheck(flags, out, err);
386
+ }
384
387
  if (sub === 'update') {
385
388
  return skillCommands.cmdSkillUpdate(flags, out, err);
386
389
  }
@@ -396,7 +399,7 @@ async function cmdSkill(pos, flags) {
396
399
  if (sub === 'install') {
397
400
  return skillCommands.cmdSkillInstall(pos[1], flags, out, err);
398
401
  }
399
- 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 versions <slug>\n deertools skill diff <slug> [wersjaA] [wersjaB]\n deertools skill push [katalog] [--bump patch|minor|major] [--changelog "opis"]\n deertools skill update\n deertools skill promote <slug>', 2);
402
+ 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);
400
403
  }
401
404
 
402
405
 
package/src/mcp-stdio.js CHANGED
@@ -1,8 +1,9 @@
1
1
  'use strict';
2
2
  const readline = require('readline');
3
3
  const credentials = require('./credentials');
4
- const { ALL_PRODUCTS } = require('./registry');
4
+ const { ALL_PRODUCTS, getProduct } = require('./registry');
5
5
  const { apiRequest } = require('./http');
6
+ const { checkSkillUpdates, updateSkills } = require('./skill-commands');
6
7
 
7
8
  const PROTOCOL_VERSION = '2024-11-05';
8
9
  const SERVER_INFO = { name: 'deertools-stdio-bridge', version: '1.0.5' };
@@ -92,6 +93,24 @@ async function cmdMcpServe(pos, flags) {
92
93
  required: ['catalog_price_net'],
93
94
  },
94
95
  },
96
+ {
97
+ name: 'deer_check_skill_updates',
98
+ description: 'Sprawdza czy zainstalowane lokalnie skille AI DeerTools posiadają nowsze wersje w DeerSkills Hub. Zwraca listę skilli z dostępnymi aktualizacjami i ich changelogami.',
99
+ inputSchema: {
100
+ type: 'object',
101
+ properties: {},
102
+ },
103
+ },
104
+ {
105
+ name: 'deer_update_skills',
106
+ description: 'Autonomiczna aktualizacja skilli Deer Design — pobiera najnowsze wersje paczek z DeerSkills Hub i odświeża plik blokady.',
107
+ inputSchema: {
108
+ type: 'object',
109
+ properties: {
110
+ slug: { type: 'string', description: 'Opcjonalny slug konkretnego skilla do zaktualizowania (np. deer-kosztorys). Domyślnie aktualizuje wszystkie przestarzałe skille.' },
111
+ },
112
+ },
113
+ },
95
114
  ];
96
115
 
97
116
  send({ jsonrpc: '2.0', id, result: { tools } });
@@ -183,6 +202,52 @@ async function cmdMcpServe(pos, flags) {
183
202
  return;
184
203
  }
185
204
 
205
+ if (toolName === 'deer_check_skill_updates') {
206
+ const updates = await checkSkillUpdates();
207
+ const outdated = updates.filter((u) => u.hasUpdate);
208
+ send({
209
+ jsonrpc: '2.0',
210
+ id,
211
+ result: {
212
+ content: [{
213
+ type: 'text',
214
+ text: JSON.stringify({
215
+ has_updates: outdated.length > 0,
216
+ outdated_count: outdated.length,
217
+ total_checked: updates.length,
218
+ skills: updates,
219
+ agent_recommendation: outdated.length > 0
220
+ ? `Znaleziono ${outdated.length} przestarzałych skilli. Zapytaj użytkownika: „Czy chcesz, abym zaktualizował skille [${outdated.map((o) => o.slug).join(', ')}] do najnowszych wydań?” i wywołaj deer_update_skills.`
221
+ : 'Wszystkie zainstalowane skille są w najnowszych wersjach.',
222
+ }, null, 2),
223
+ }],
224
+ },
225
+ });
226
+ return;
227
+ }
228
+
229
+ if (toolName === 'deer_update_skills') {
230
+ const res = await updateSkills(args.slug || null);
231
+ send({
232
+ jsonrpc: '2.0',
233
+ id,
234
+ result: {
235
+ content: [{
236
+ type: 'text',
237
+ text: JSON.stringify({
238
+ status: 'success',
239
+ updated_count: res.updated.length,
240
+ updated_skills: res.updated,
241
+ message: res.updated.length > 0
242
+ ? `Pomyślnie zaktualizowano ${res.updated.length} skilli do najnowszych wydań.`
243
+ : 'Wszystkie skille były już w najnowszych wersjach.',
244
+ }, null, 2),
245
+ }],
246
+ },
247
+ });
248
+ return;
249
+ }
250
+
186
251
  send({ jsonrpc: '2.0', id, error: { code: -32601, message: `Tool not found: ${toolName}` } });
187
252
  } catch (e) {
188
253
  send({ jsonrpc: '2.0', id, error: { code: -32000, message: e.message } });
@@ -1,6 +1,6 @@
1
- 'use strict';
2
1
  const fs = require('fs');
3
2
  const path = require('path');
3
+ const os = require('os');
4
4
  const { detectAgents, installSkillContent } = require('./agent-detector');
5
5
  const skillsHub = require('./skills-hub');
6
6
  const { parseFrontmatterName } = require('./openapi');
@@ -9,8 +9,17 @@ const { fetchText } = require('./http');
9
9
 
10
10
  const LOCK_FILE = '.deertools-lock.json';
11
11
 
12
+ function getLockFilePath(cwd = process.cwd()) {
13
+ const local = path.join(cwd, LOCK_FILE);
14
+ if (fs.existsSync(local)) return local;
15
+ const globalDir = path.join(os.homedir(), '.deertools');
16
+ const globalPath = path.join(globalDir, LOCK_FILE);
17
+ if (fs.existsSync(globalPath)) return globalPath;
18
+ return local;
19
+ }
20
+
12
21
  function readLock(cwd = process.cwd()) {
13
- const p = path.join(cwd, LOCK_FILE);
22
+ const p = getLockFilePath(cwd);
14
23
  if (fs.existsSync(p)) {
15
24
  try {
16
25
  return JSON.parse(fs.readFileSync(p, 'utf8'));
@@ -22,6 +31,11 @@ function readLock(cwd = process.cwd()) {
22
31
  function writeLock(data, cwd = process.cwd()) {
23
32
  const p = path.join(cwd, LOCK_FILE);
24
33
  fs.writeFileSync(p, JSON.stringify(data, null, 2) + '\n', 'utf8');
34
+ try {
35
+ const globalDir = path.join(os.homedir(), '.deertools');
36
+ if (!fs.existsSync(globalDir)) fs.mkdirSync(globalDir, { recursive: true });
37
+ fs.writeFileSync(path.join(globalDir, LOCK_FILE), JSON.stringify(data, null, 2) + '\n', 'utf8');
38
+ } catch (_) {}
25
39
  }
26
40
 
27
41
  async function cmdSkillList(flags, out, err) {
@@ -159,18 +173,22 @@ async function cmdSkillPush(dir, flags, out, err) {
159
173
  throw new Error(`Nie udało się opublikować skilla (${res.status}): ${res.data?.error || 'Błąd serwera'}`);
160
174
  }
161
175
 
162
- const skill = res.data.skill || {};
163
- const version = res.data.version || res.data.selected_version || {};
164
- const manifest = version.files_manifest || [];
176
+ const skill = res.data.skill || res.data || {};
177
+ const versionNum = res.data.pushed_version || res.data.version?.version || skill.latest_version;
178
+ const changelog = res.data.pushed_changelog || res.data.version?.changelog || versionNum;
179
+ const manifestCount = res.data.pushed_manifest_count !== undefined
180
+ ? res.data.pushed_manifest_count
181
+ : (res.data.version?.files_manifest?.length || 0);
182
+
165
183
  out(`\n✓ Pomyślnie opublikowano skill w DeerSkills Hub:`);
166
184
  out(` • Identyfikator: \x1b[1m${skill.full_slug || skill.slug}\x1b[0m`);
167
- out(` • Wersja: \x1b[32mv${version.version || skill.latest_version}\x1b[0m`);
168
- if (version.changelog) {
169
- out(` • Changelog: \x1b[33m${version.changelog}\x1b[0m`);
185
+ out(` • Wersja: \x1b[32mv${versionNum}\x1b[0m`);
186
+ if (changelog && changelog !== versionNum) {
187
+ out(` • Changelog: \x1b[33m${changelog}\x1b[0m`);
170
188
  }
171
- out(` • Paczka: ${manifest.length + 1} plików (SKILL.md + ${manifest.length} plików w podkatalogach)`);
189
+ out(` • Paczka: ${manifestCount + 1} plików (SKILL.md + ${manifestCount} plików w podkatalogach)`);
172
190
  out(` • Widoczność: ${skill.visibility || 'shared'}`);
173
- out(`\nAby zainstalować tę wersję w projekcie:\n \x1b[36mdeertools skill install ${skill.full_slug || skill.slug}@${version.version || skill.latest_version}\x1b[0m\n`);
191
+ out(`\nAby zainstalować tę wersję w projekcie:\n \x1b[36mdeertools skill install ${skill.full_slug || skill.slug}@${versionNum}\x1b[0m\n`);
174
192
  }
175
193
 
176
194
  async function cmdSkillVersions(slug, flags, out, err) {
@@ -293,39 +311,88 @@ async function cmdSkillDiff(args, flags, out, err) {
293
311
  out('');
294
312
  }
295
313
 
296
- async function cmdSkillUpdate(flags, out, err) {
297
- const lock = readLock();
314
+ async function checkSkillUpdates(cwd = process.cwd()) {
315
+ const lock = readLock(cwd);
298
316
  const installedSkills = Object.keys(lock.skills || {});
299
-
300
- if (installedSkills.length === 0) {
301
- out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
302
- return;
303
- }
304
-
305
- out(`Sprawdzam aktualizacje dla ${installedSkills.length} skilli...`);
306
- let updatedCount = 0;
317
+ const results = [];
307
318
 
308
319
  for (const slug of installedSkills) {
309
320
  const current = lock.skills[slug];
310
321
  try {
311
322
  const res = await skillsHub.getSkill(slug);
312
- if (res.ok && res.data?.version) {
313
- const latestVer = res.data.version.version;
314
- if (latestVer !== current.version) {
315
- out(`Aktualizacja ${slug}: ${current.version} → ${latestVer}...`);
316
- await cmdSkillInstall(`${slug}@${latestVer}`, flags, out, err);
317
- updatedCount += 1;
318
- } else {
319
- out(` • ${slug} (${current.version}) — aktualny.`);
320
- }
323
+ if (res.ok) {
324
+ const latestVer = res.data?.skill?.latest_version || res.data?.version?.version || res.data?.latest_version;
325
+ const changelog = res.data?.selected_version?.changelog || res.data?.skill?.changelog || '';
326
+ const title = res.data?.skill?.title || slug;
327
+ const hasUpdate = latestVer && latestVer !== current.version;
328
+ results.push({
329
+ slug,
330
+ title,
331
+ currentVersion: current.version,
332
+ latestVersion: latestVer,
333
+ hasUpdate: !!hasUpdate,
334
+ changelog,
335
+ installedAt: current.installedAt,
336
+ });
321
337
  }
338
+ } catch (_) {}
339
+ }
340
+ return results;
341
+ }
342
+
343
+ async function updateSkills(slugFilter = null, flags = {}, out = () => {}, err = () => {}) {
344
+ const updates = await checkSkillUpdates();
345
+ const toUpdate = slugFilter
346
+ ? updates.filter((u) => u.slug === slugFilter && u.hasUpdate)
347
+ : updates.filter((u) => u.hasUpdate);
348
+
349
+ const updated = [];
350
+ for (const item of toUpdate) {
351
+ try {
352
+ out(`Aktualizacja ${item.slug}: ${item.currentVersion} → ${item.latestVersion}...`);
353
+ await cmdSkillInstall(`${item.slug}@${item.latestVersion}`, flags, out, err);
354
+ updated.push({ slug: item.slug, from: item.currentVersion, to: item.latestVersion });
322
355
  } catch (e) {
323
- err(`✗ Błąd sprawdzania ${slug}: ${e.message}`);
356
+ err(`✗ Błąd aktualizacji ${item.slug}: ${e.message}`);
324
357
  }
325
358
  }
359
+ return { updated, checked: updates.length, totalOutdated: updates.filter((u) => u.hasUpdate).length };
360
+ }
361
+
362
+ async function cmdSkillCheck(flags, out, err) {
363
+ out('Sprawdzam wersje zainstalowanych skilli w DeerSkills Hub...');
364
+ const updates = await checkSkillUpdates();
365
+ if (updates.length === 0) {
366
+ out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
367
+ return;
368
+ }
369
+
370
+ const outdated = updates.filter((u) => u.hasUpdate);
371
+ if (outdated.length === 0) {
372
+ out(`✓ Wszystkie zainstalowane skille (${updates.length}) są w najnowszych wersjach.`);
373
+ return;
374
+ }
375
+
376
+ out(`\nZnaleziono aktualizacje dla ${outdated.length} z ${updates.length} skilli:\n`);
377
+ for (const item of outdated) {
378
+ out(` • \x1b[1m${item.slug}\x1b[0m: ${item.currentVersion} → \x1b[32mv${item.latestVersion}\x1b[0m`);
379
+ if (item.changelog) out(` Changelog: \x1b[33m${item.changelog}\x1b[0m`);
380
+ }
381
+ out(`\nAby zaktualizować wszystkie, uruchom: \x1b[36mdeertools skill update\x1b[0m\n`);
382
+ }
383
+
384
+ async function cmdSkillUpdate(flags, out, err) {
385
+ const targetSlug = typeof flags === 'string' ? flags : (flags.slug || null);
386
+ out('Sprawdzam aktualizacje w DeerSkills Hub...');
387
+ const res = await updateSkills(targetSlug, flags, out, err);
388
+
389
+ if (res.checked === 0) {
390
+ out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
391
+ return;
392
+ }
326
393
 
327
- if (updatedCount > 0) {
328
- out(`\n✓ Zaktualizowano pomyślnie ${updatedCount} skilli.`);
394
+ if (res.updated.length > 0) {
395
+ out(`\n✓ Zaktualizowano pomyślnie ${res.updated.length} skilli.`);
329
396
  } else {
330
397
  out('\nWszystkie zainstalowane skille są w najnowszych wersjach.');
331
398
  }
@@ -352,8 +419,11 @@ module.exports = {
352
419
  cmdSkillSearch,
353
420
  cmdSkillInstall,
354
421
  cmdSkillPush,
422
+ cmdSkillCheck,
355
423
  cmdSkillUpdate,
356
424
  cmdSkillPromote,
357
425
  cmdSkillVersions,
358
426
  cmdSkillDiff,
427
+ checkSkillUpdates,
428
+ updateSkills,
359
429
  };
package/src/skills-hub.js CHANGED
@@ -87,7 +87,8 @@ async function listSkills(params = {}) {
87
87
  }
88
88
 
89
89
  async function getSkill(slug, version = null) {
90
- const qs = version ? `?version=${encodeURIComponent(version)}` : '';
90
+ const ver = typeof version === 'object' && version !== null ? version.version : version;
91
+ const qs = ver ? `?version=${encodeURIComponent(ver)}` : '';
91
92
  return hubRequest(`/skills/${encodeURIComponent(slug)}${qs}`);
92
93
  }
93
94
 
@@ -279,7 +280,13 @@ async function pushSkill(skillDir, { version = null, bump = 'patch', changelog =
279
280
  files_manifest: manifest,
280
281
  };
281
282
 
282
- return hubRequest('/skills/push', { method: 'POST', body });
283
+ const res = await hubRequest('/skills/push', { method: 'POST', body });
284
+ if (res.ok && res.data) {
285
+ res.data.pushed_version = targetVersion;
286
+ res.data.pushed_manifest_count = manifest.length;
287
+ res.data.pushed_changelog = finalChangelog;
288
+ }
289
+ return res;
283
290
  }
284
291
 
285
292
  async function listMcpServers() {
package/src/updater.js CHANGED
@@ -95,7 +95,8 @@ function printUpdateNotice(updateInfo) {
95
95
  process.stderr.write(`\x1b[33m└${border}┘\x1b[0m\n\n`);
96
96
  }
97
97
 
98
- async function cmdUpdate(pos, flags) {
98
+ async function cmdUpdate(pos, flags = {}) {
99
+ const shouldInstall = flags.install || flags.i || flags.yes || flags.y;
99
100
  process.stdout.write(`Sprawdzam aktualizacje w rejestrze npm...\n`);
100
101
  const latest = await fetchLatestVersion();
101
102
  if (!latest) {
@@ -104,13 +105,35 @@ async function cmdUpdate(pos, flags) {
104
105
  }
105
106
 
106
107
  const cmp = compareSemver(latest, PKG.version);
107
- if (cmp <= 0) {
108
+ if (cmp <= 0 && !flags.force) {
108
109
  process.stdout.write(`✓ DeerTools CLI jest w najnowszej wersji (${PKG.version}).\n`);
109
110
  return 0;
110
111
  }
111
112
 
112
- process.stdout.write(`\nZnaleziono nowszą wersję: ${PKG.version} → \x1b[32m${latest}\x1b[0m\n\n`);
113
- process.stdout.write(`Aby zaktualizować instalację globalną, uruchom:\n`);
113
+ if (cmp > 0) {
114
+ process.stdout.write(`\nZnaleziono nowszą wersję: ${PKG.version} → \x1b[32m${latest}\x1b[0m\n\n`);
115
+ } else if (flags.force) {
116
+ process.stdout.write(`\nWymuszam ponowną instalację wersji: \x1b[32m${latest}\x1b[0m\n\n`);
117
+ }
118
+
119
+ if (shouldInstall) {
120
+ process.stdout.write(`Uruchamiam: npm install -g @deerdesign/deertools@latest...\n`);
121
+ const { spawnSync } = require('child_process');
122
+ const res = spawnSync('npm', ['install', '-g', '@deerdesign/deertools@latest'], {
123
+ stdio: 'inherit',
124
+ });
125
+ if (res.status === 0) {
126
+ process.stdout.write(`\n✓ Pomyślnie zaktualizowano DeerTools CLI do wersji v${latest}!\n`);
127
+ return 0;
128
+ } else {
129
+ process.stdout.write(`\n✗ Błąd instalacji (kod wyjścia: ${res.status}).\nJeśli instalacja wymaga uprawnień roota, uruchom:\n sudo npm install -g @deerdesign/deertools@latest\n\n`);
130
+ return res.status || 1;
131
+ }
132
+ }
133
+
134
+ process.stdout.write(`Aby zaktualizować instalację globalną automatycznie, uruchom:\n`);
135
+ process.stdout.write(` \x1b[36mdeertools update --install\x1b[0m (lub \x1b[36mdeertools update -y\x1b[0m)\n\n`);
136
+ process.stdout.write(`Lub bezpośrednio przez npm:\n`);
114
137
  process.stdout.write(` \x1b[36mnpm install -g @deerdesign/deertools@latest\x1b[0m\n\n`);
115
138
  process.stdout.write(`Jeśli instalacja wymaga uprawnień administratora:\n`);
116
139
  process.stdout.write(` \x1b[36msudo npm install -g @deerdesign/deertools@latest\x1b[0m\n\n`);