@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 +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 +102 -32
- package/src/skills-hub.js +9 -2
- 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) {
|
|
@@ -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
|
|
164
|
-
const
|
|
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${
|
|
168
|
-
if (
|
|
169
|
-
out(` • Changelog: \x1b[33m${
|
|
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: ${
|
|
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}@${
|
|
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
|
|
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
|
|
313
|
-
const latestVer = res.data.version.
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
|
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 (
|
|
328
|
-
out(`\n✓ Zaktualizowano pomyślnie ${
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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`);
|