@deerdesign/deertools 1.2.9 → 1.2.12
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 +1 -1
- package/docs/prezentacja-it-deertools.md +1 -1
- package/package.json +1 -1
- package/src/commands.js +4 -1
- package/src/mcp-stdio.js +66 -1
- package/src/skill-commands.js +151 -24
- package/src/skills-hub.js +2 -1
- package/src/updater.js +27 -4
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
|
package/package.json
CHANGED
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
|
|
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 } });
|
package/src/skill-commands.js
CHANGED
|
@@ -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 =
|
|
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) {
|
|
@@ -142,6 +156,67 @@ async function cmdSkillInstall(target, flags, out, err) {
|
|
|
142
156
|
};
|
|
143
157
|
writeLock(lock);
|
|
144
158
|
out(`✓ Zaktualizowano ${LOCK_FILE} (wersja ${versionData.version}).`);
|
|
159
|
+
|
|
160
|
+
// Podsumowanie możliwości skilla dla użytkownika i Agenta AI
|
|
161
|
+
printSkillSummary(skill, versionData, out);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function extractCapabilities(content, summary = '') {
|
|
165
|
+
const text = String(content || '');
|
|
166
|
+
const lines = text.split('\n');
|
|
167
|
+
const bullets = [];
|
|
168
|
+
let inWhen = false;
|
|
169
|
+
|
|
170
|
+
for (let i = 0; i < lines.length; i++) {
|
|
171
|
+
const line = lines[i].trim();
|
|
172
|
+
if (/^##\s+(Kiedy używać|Możliwości|Zastosowanie|Co potrafi)/i.test(line)) {
|
|
173
|
+
inWhen = true;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (inWhen) {
|
|
177
|
+
if (/^##\s+/.test(line)) break;
|
|
178
|
+
if (line.startsWith('- ') || line.startsWith('* ') || /^\d+\.\s+/.test(line)) {
|
|
179
|
+
const clean = line.replace(/^[-*]\s+|\d+\.\s+/, '').replace(/\.$/, '').trim();
|
|
180
|
+
if (clean.length > 5 && !clean.toLowerCase().startsWith('nie używaj')) {
|
|
181
|
+
bullets.push(clean);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const desc = summary || (text.match(/description:\s*["']?([^"'\n]+)/i)?.[1]) || '';
|
|
188
|
+
return { desc, bullets: bullets.slice(0, 4) };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function printSkillSummary(skill, versionData, out) {
|
|
192
|
+
const { desc, bullets } = extractCapabilities(versionData.skill_md_content, skill.summary);
|
|
193
|
+
const manifest = versionData.files_manifest || [];
|
|
194
|
+
|
|
195
|
+
out('\n\x1b[36m┌─────────────────────────────────────────────────────────────────────────────┐\x1b[0m');
|
|
196
|
+
out(`\x1b[36m│\x1b[0m \x1b[1m🚀 NOWA UMIEJĘTNOŚĆ AGENTA: ${skill.full_slug || skill.slug} (v${versionData.version})\x1b[0m`);
|
|
197
|
+
out('\x1b[36m├─────────────────────────────────────────────────────────────────────────────┤\x1b[0m');
|
|
198
|
+
|
|
199
|
+
if (desc) {
|
|
200
|
+
const shortDesc = desc.length > 180 ? `${desc.slice(0, 177)}...` : desc;
|
|
201
|
+
out(`\x1b[36m│\x1b[0m \x1b[33mOpis roli:\x1b[0m ${shortDesc}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (bullets.length > 0) {
|
|
205
|
+
out(`\x1b[36m│\x1b[0m \x1b[32mCo potrafi ten skill (Kiedy używać):\x1b[0m`);
|
|
206
|
+
for (const b of bullets) {
|
|
207
|
+
out(`\x1b[36m│\x1b[0m • ${b}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (manifest.length > 0) {
|
|
212
|
+
const fileList = manifest.map((f) => path.basename(f.path)).slice(0, 5).join(' · ');
|
|
213
|
+
const more = manifest.length > 5 ? ` (+${manifest.length - 5} więcej)` : '';
|
|
214
|
+
out(`\x1b[36m│\x1b[0m \x1b[34mDołączone referencje w paczce (${manifest.length} plików):\x1b[0m ${fileList}${more}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
out('\x1b[36m├─────────────────────────────────────────────────────────────────────────────┤\x1b[0m');
|
|
218
|
+
out('\x1b[36m│\x1b[0m \x1b[90m💡 Informacja dla Agenta AI: Twój asystent może natychmiast korzystać z tych reguł.\x1b[0m');
|
|
219
|
+
out('\x1b[36m└─────────────────────────────────────────────────────────────────────────────┘\x1b[0m\n');
|
|
145
220
|
}
|
|
146
221
|
|
|
147
222
|
async function cmdSkillPush(dir, flags, out, err) {
|
|
@@ -297,39 +372,88 @@ async function cmdSkillDiff(args, flags, out, err) {
|
|
|
297
372
|
out('');
|
|
298
373
|
}
|
|
299
374
|
|
|
300
|
-
async function
|
|
301
|
-
const lock = readLock();
|
|
375
|
+
async function checkSkillUpdates(cwd = process.cwd()) {
|
|
376
|
+
const lock = readLock(cwd);
|
|
302
377
|
const installedSkills = Object.keys(lock.skills || {});
|
|
303
|
-
|
|
304
|
-
if (installedSkills.length === 0) {
|
|
305
|
-
out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
out(`Sprawdzam aktualizacje dla ${installedSkills.length} skilli...`);
|
|
310
|
-
let updatedCount = 0;
|
|
378
|
+
const results = [];
|
|
311
379
|
|
|
312
380
|
for (const slug of installedSkills) {
|
|
313
381
|
const current = lock.skills[slug];
|
|
314
382
|
try {
|
|
315
383
|
const res = await skillsHub.getSkill(slug);
|
|
316
|
-
if (res.ok
|
|
317
|
-
const latestVer = res.data.version.
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
384
|
+
if (res.ok) {
|
|
385
|
+
const latestVer = res.data?.skill?.latest_version || res.data?.version?.version || res.data?.latest_version;
|
|
386
|
+
const changelog = res.data?.selected_version?.changelog || res.data?.skill?.changelog || '';
|
|
387
|
+
const title = res.data?.skill?.title || slug;
|
|
388
|
+
const hasUpdate = latestVer && latestVer !== current.version;
|
|
389
|
+
results.push({
|
|
390
|
+
slug,
|
|
391
|
+
title,
|
|
392
|
+
currentVersion: current.version,
|
|
393
|
+
latestVersion: latestVer,
|
|
394
|
+
hasUpdate: !!hasUpdate,
|
|
395
|
+
changelog,
|
|
396
|
+
installedAt: current.installedAt,
|
|
397
|
+
});
|
|
325
398
|
}
|
|
399
|
+
} catch (_) {}
|
|
400
|
+
}
|
|
401
|
+
return results;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async function updateSkills(slugFilter = null, flags = {}, out = () => {}, err = () => {}) {
|
|
405
|
+
const updates = await checkSkillUpdates();
|
|
406
|
+
const toUpdate = slugFilter
|
|
407
|
+
? updates.filter((u) => u.slug === slugFilter && u.hasUpdate)
|
|
408
|
+
: updates.filter((u) => u.hasUpdate);
|
|
409
|
+
|
|
410
|
+
const updated = [];
|
|
411
|
+
for (const item of toUpdate) {
|
|
412
|
+
try {
|
|
413
|
+
out(`Aktualizacja ${item.slug}: ${item.currentVersion} → ${item.latestVersion}...`);
|
|
414
|
+
await cmdSkillInstall(`${item.slug}@${item.latestVersion}`, flags, out, err);
|
|
415
|
+
updated.push({ slug: item.slug, from: item.currentVersion, to: item.latestVersion });
|
|
326
416
|
} catch (e) {
|
|
327
|
-
err(`✗ Błąd
|
|
417
|
+
err(`✗ Błąd aktualizacji ${item.slug}: ${e.message}`);
|
|
328
418
|
}
|
|
329
419
|
}
|
|
420
|
+
return { updated, checked: updates.length, totalOutdated: updates.filter((u) => u.hasUpdate).length };
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async function cmdSkillCheck(flags, out, err) {
|
|
424
|
+
out('Sprawdzam wersje zainstalowanych skilli w DeerSkills Hub...');
|
|
425
|
+
const updates = await checkSkillUpdates();
|
|
426
|
+
if (updates.length === 0) {
|
|
427
|
+
out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const outdated = updates.filter((u) => u.hasUpdate);
|
|
432
|
+
if (outdated.length === 0) {
|
|
433
|
+
out(`✓ Wszystkie zainstalowane skille (${updates.length}) są w najnowszych wersjach.`);
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
out(`\nZnaleziono aktualizacje dla ${outdated.length} z ${updates.length} skilli:\n`);
|
|
438
|
+
for (const item of outdated) {
|
|
439
|
+
out(` • \x1b[1m${item.slug}\x1b[0m: ${item.currentVersion} → \x1b[32mv${item.latestVersion}\x1b[0m`);
|
|
440
|
+
if (item.changelog) out(` Changelog: \x1b[33m${item.changelog}\x1b[0m`);
|
|
441
|
+
}
|
|
442
|
+
out(`\nAby zaktualizować wszystkie, uruchom: \x1b[36mdeertools skill update\x1b[0m\n`);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async function cmdSkillUpdate(flags, out, err) {
|
|
446
|
+
const targetSlug = typeof flags === 'string' ? flags : (flags.slug || null);
|
|
447
|
+
out('Sprawdzam aktualizacje w DeerSkills Hub...');
|
|
448
|
+
const res = await updateSkills(targetSlug, flags, out, err);
|
|
449
|
+
|
|
450
|
+
if (res.checked === 0) {
|
|
451
|
+
out('Brak zainstalowanych skilli w pliku .deertools-lock.json.');
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
330
454
|
|
|
331
|
-
if (
|
|
332
|
-
out(`\n✓ Zaktualizowano pomyślnie ${
|
|
455
|
+
if (res.updated.length > 0) {
|
|
456
|
+
out(`\n✓ Zaktualizowano pomyślnie ${res.updated.length} skilli.`);
|
|
333
457
|
} else {
|
|
334
458
|
out('\nWszystkie zainstalowane skille są w najnowszych wersjach.');
|
|
335
459
|
}
|
|
@@ -356,8 +480,11 @@ module.exports = {
|
|
|
356
480
|
cmdSkillSearch,
|
|
357
481
|
cmdSkillInstall,
|
|
358
482
|
cmdSkillPush,
|
|
483
|
+
cmdSkillCheck,
|
|
359
484
|
cmdSkillUpdate,
|
|
360
485
|
cmdSkillPromote,
|
|
361
486
|
cmdSkillVersions,
|
|
362
487
|
cmdSkillDiff,
|
|
488
|
+
checkSkillUpdates,
|
|
489
|
+
updateSkills,
|
|
363
490
|
};
|
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
|
|
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
|
|
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
|
-
|
|
113
|
-
|
|
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`);
|