@deerdesign/deertools 1.2.7 → 1.2.8
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/package.json +1 -1
- package/src/commands.js +9 -1
- package/src/skill-commands.js +142 -9
- package/src/skills-hub.js +152 -29
package/package.json
CHANGED
package/src/commands.js
CHANGED
|
@@ -384,13 +384,19 @@ async function cmdSkill(pos, flags) {
|
|
|
384
384
|
if (sub === 'update') {
|
|
385
385
|
return skillCommands.cmdSkillUpdate(flags, out, err);
|
|
386
386
|
}
|
|
387
|
+
if (sub === 'versions' || sub === 'history') {
|
|
388
|
+
return skillCommands.cmdSkillVersions(pos[1], flags, out, err);
|
|
389
|
+
}
|
|
390
|
+
if (sub === 'diff' || sub === 'compare') {
|
|
391
|
+
return skillCommands.cmdSkillDiff(pos.slice(1), flags, out, err);
|
|
392
|
+
}
|
|
387
393
|
if (sub === 'promote') {
|
|
388
394
|
return skillCommands.cmdSkillPromote(pos[1], flags, out, err);
|
|
389
395
|
}
|
|
390
396
|
if (sub === 'install') {
|
|
391
397
|
return skillCommands.cmdSkillInstall(pos[1], flags, out, err);
|
|
392
398
|
}
|
|
393
|
-
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 push [katalog] [--
|
|
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);
|
|
394
400
|
}
|
|
395
401
|
|
|
396
402
|
|
|
@@ -531,6 +537,8 @@ Integracje MCP i Agenci AI (DeerSkills Hub):
|
|
|
531
537
|
deertools skill list [--tag <tag>] Przegląda skille globalne i użytkownika w DeerSkills Hub.
|
|
532
538
|
deertools skill search <fraza> Wyszukuje umiejętności po słowach kluczowych.
|
|
533
539
|
deertools skill install <slug[@wersja]> Instaluje skill w ~/.gemini/antigravity/skills lub .agents.
|
|
540
|
+
deertools skill versions <slug> Historia wydań z changelogami z commitów i datami.
|
|
541
|
+
deertools skill diff <slug> [wersjaA] [wersjaB] Porównanie zmian w plikach paczki i treści SKILL.md.
|
|
534
542
|
deertools skill push [katalog] [--bump patch|minor] Publikuje nową wersję z automatycznym skanerem sekretów.
|
|
535
543
|
deertools skill update [slug] Aktualizuje zainstalowane skille do najnowszej wersji.
|
|
536
544
|
deertools skill promote <slug> Zgłasza nominację skilla do oficjalnego katalogu globalnego.
|
package/src/skill-commands.js
CHANGED
|
@@ -120,7 +120,11 @@ async function cmdSkillInstall(target, flags, out, err) {
|
|
|
120
120
|
for (const file of versionData.files_manifest) {
|
|
121
121
|
const targetFile = path.join(baseDir, file.path);
|
|
122
122
|
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
123
|
-
|
|
123
|
+
if (file.encoding === 'base64') {
|
|
124
|
+
fs.writeFileSync(targetFile, Buffer.from(file.content, 'base64'));
|
|
125
|
+
} else {
|
|
126
|
+
fs.writeFileSync(targetFile, file.content, 'utf8');
|
|
127
|
+
}
|
|
124
128
|
}
|
|
125
129
|
}
|
|
126
130
|
} catch (e) {
|
|
@@ -145,8 +149,9 @@ async function cmdSkillPush(dir, flags, out, err) {
|
|
|
145
149
|
out(`Analizuję folder skilla: ${targetDir}...`);
|
|
146
150
|
|
|
147
151
|
const res = await skillsHub.pushSkill(targetDir, {
|
|
148
|
-
version: flags.version ||
|
|
149
|
-
|
|
152
|
+
version: flags.version || null,
|
|
153
|
+
bump: flags.bump || (flags.major ? 'major' : flags.minor ? 'minor' : 'patch'),
|
|
154
|
+
changelog: flags.changelog || flags.message || flags.m || null,
|
|
150
155
|
visibility: flags.private ? 'private' : 'shared',
|
|
151
156
|
});
|
|
152
157
|
|
|
@@ -154,12 +159,138 @@ async function cmdSkillPush(dir, flags, out, err) {
|
|
|
154
159
|
throw new Error(`Nie udało się opublikować skilla (${res.status}): ${res.data?.error || 'Błąd serwera'}`);
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
out(
|
|
161
|
-
out(` •
|
|
162
|
-
out(`
|
|
162
|
+
const skill = res.data.skill || {};
|
|
163
|
+
const version = res.data.version || res.data.selected_version || {};
|
|
164
|
+
const manifest = version.files_manifest || [];
|
|
165
|
+
out(`\n✓ Pomyślnie opublikowano skill w DeerSkills Hub:`);
|
|
166
|
+
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`);
|
|
170
|
+
}
|
|
171
|
+
out(` • Paczka: ${manifest.length + 1} plików (SKILL.md + ${manifest.length} plików w podkatalogach)`);
|
|
172
|
+
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`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function cmdSkillVersions(slug, flags, out, err) {
|
|
177
|
+
if (!slug) throw new Error('Podaj slug skilla, np. deertools skill versions deer-technical-documentation');
|
|
178
|
+
out(`Pobieram historię wydań dla skilla „${slug}”...`);
|
|
179
|
+
const res = await skillsHub.getSkill(slug);
|
|
180
|
+
if (!res.ok || !res.data?.skill) {
|
|
181
|
+
throw new Error(`Nie znaleziono skilla „${slug}” (${res.status}): ${res.data?.error || 'Błąd'}`);
|
|
182
|
+
}
|
|
183
|
+
const { skill, versions = [] } = res.data;
|
|
184
|
+
out(`\n=== Historia wydań: ${skill.full_slug || skill.slug} (${skill.title || skill.slug}) ===\n`);
|
|
185
|
+
if (versions.length === 0) {
|
|
186
|
+
out('Brak opublikowanych wersji w rejestrze.');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const lock = readLock();
|
|
190
|
+
const installedVer = lock.skills?.[skill.slug]?.version;
|
|
191
|
+
|
|
192
|
+
for (let i = 0; i < versions.length; i++) {
|
|
193
|
+
const v = versions[i];
|
|
194
|
+
const isLatest = v.version === skill.latest_version;
|
|
195
|
+
const isInstalled = installedVer && v.version === installedVer;
|
|
196
|
+
const bullet = isLatest ? '\x1b[32m●\x1b[0m' : '○';
|
|
197
|
+
const tag = [
|
|
198
|
+
isLatest ? '\x1b[32m(najnowsza)\x1b[0m' : null,
|
|
199
|
+
isInstalled ? '\x1b[36m[zainstalowana]\x1b[0m' : null,
|
|
200
|
+
].filter(Boolean).join(' ');
|
|
201
|
+
|
|
202
|
+
const dateStr = v.created_at ? new Date(v.created_at).toLocaleDateString('pl-PL') : '—';
|
|
203
|
+
const fileCount = (v.files_manifest && Array.isArray(v.files_manifest) ? v.files_manifest.length : 0) + 1;
|
|
204
|
+
out(`${bullet} \x1b[1mv${v.version}\x1b[0m ${tag} — ${dateStr}`);
|
|
205
|
+
if (v.changelog) {
|
|
206
|
+
out(` Changelog: \x1b[33m${v.changelog}\x1b[0m`);
|
|
207
|
+
}
|
|
208
|
+
out(` Paczka: ${fileCount} ${fileCount === 1 ? 'plik' : 'plików'} • SHA-256: ${(v.sha256_checksum || '').slice(0, 16)}...`);
|
|
209
|
+
out(` Komenda: deertools skill install ${skill.slug}@${v.version}\n`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function cmdSkillDiff(args, flags, out, err) {
|
|
214
|
+
const slug = Array.isArray(args) ? args[0] : args;
|
|
215
|
+
if (!slug) throw new Error('Podaj slug skilla, np. deertools skill diff deer-technical-documentation [wersjaA] [wersjaB]');
|
|
216
|
+
const verA = Array.isArray(args) ? args[1] : null;
|
|
217
|
+
const verB = Array.isArray(args) ? args[2] : null;
|
|
218
|
+
|
|
219
|
+
out(`Pobieram dane do porównania dla „${slug}”...`);
|
|
220
|
+
const res = await skillsHub.getSkill(slug);
|
|
221
|
+
if (!res.ok || !res.data?.skill) {
|
|
222
|
+
throw new Error(`Nie znaleziono skilla „${slug}”: ${res.data?.error || 'Błąd'}`);
|
|
223
|
+
}
|
|
224
|
+
const { skill, versions = [] } = res.data;
|
|
225
|
+
if (versions.length < 1) {
|
|
226
|
+
out('Brak wystarczającej liczby wersji do porównania.');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let objA = null;
|
|
231
|
+
let objB = null;
|
|
232
|
+
|
|
233
|
+
if (verA && verB) {
|
|
234
|
+
objA = versions.find((v) => v.version === verA);
|
|
235
|
+
objB = versions.find((v) => v.version === verB);
|
|
236
|
+
if (!objA) throw new Error(`Nie znaleziono wersji ${verA}.`);
|
|
237
|
+
if (!objB) throw new Error(`Nie znaleziono wersji ${verB}.`);
|
|
238
|
+
} else if (verA) {
|
|
239
|
+
objA = versions.find((v) => v.version === verA);
|
|
240
|
+
objB = versions.find((v) => v.version === skill.latest_version) || versions[0];
|
|
241
|
+
if (!objA) throw new Error(`Nie znaleziono wersji ${verA}.`);
|
|
242
|
+
} else {
|
|
243
|
+
const lock = readLock();
|
|
244
|
+
const installed = lock.skills?.[skill.slug]?.version;
|
|
245
|
+
if (installed && installed !== skill.latest_version) {
|
|
246
|
+
objA = versions.find((v) => v.version === installed);
|
|
247
|
+
objB = versions.find((v) => v.version === skill.latest_version);
|
|
248
|
+
} else if (versions.length >= 2) {
|
|
249
|
+
objA = versions[1];
|
|
250
|
+
objB = versions[0];
|
|
251
|
+
} else {
|
|
252
|
+
out(`Dostępna jest tylko jedna wersja (v${versions[0].version}). Brak wcześniejszych wydań do porównania.`);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
out(`\n=== Porównanie: ${skill.slug} v${objA.version} → v${objB.version} ===\n`);
|
|
258
|
+
if (objB.changelog) {
|
|
259
|
+
out(`Opis zmian (v${objB.version}): \x1b[33m${objB.changelog}\x1b[0m\n`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 1. Zmiany w strukturze plików paczki
|
|
263
|
+
const manA = objA.files_manifest || [];
|
|
264
|
+
const manB = objB.files_manifest || [];
|
|
265
|
+
const comp = skillsHub.compareManifests(manA, manB);
|
|
266
|
+
|
|
267
|
+
out(`Pliki w paczce:`);
|
|
268
|
+
if (comp.added.length === 0 && comp.removed.length === 0 && comp.modified.length === 0) {
|
|
269
|
+
out(` (brak zmian w strukturze plików paczki)`);
|
|
270
|
+
} else {
|
|
271
|
+
for (const f of comp.added) out(` \x1b[32m+ ${f.path}\x1b[0m (nowy plik, ${Math.round((f.size || 0) / 1024 * 10) / 10 || '<1'} KB)`);
|
|
272
|
+
for (const f of comp.removed) out(` \x1b[31m- ${f.path}\x1b[0m (usunięty plik)`);
|
|
273
|
+
for (const f of comp.modified) out(` \x1b[33m~ ${f.path}\x1b[0m (zmodyfikowany plik)`);
|
|
274
|
+
}
|
|
275
|
+
out('');
|
|
276
|
+
|
|
277
|
+
// 2. Diff tekstu SKILL.md
|
|
278
|
+
out(`Różnice w SKILL.md (v${objA.version} → v${objB.version}):`);
|
|
279
|
+
const diff = skillsHub.diffLines(objA.skill_md_content, objB.skill_md_content);
|
|
280
|
+
let hasDiff = false;
|
|
281
|
+
for (const p of diff) {
|
|
282
|
+
if (p.type === 'added') {
|
|
283
|
+
out(`\x1b[32m+ ${p.line}\x1b[0m`);
|
|
284
|
+
hasDiff = true;
|
|
285
|
+
} else if (p.type === 'removed') {
|
|
286
|
+
out(`\x1b[31m- ${p.line}\x1b[0m`);
|
|
287
|
+
hasDiff = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (!hasDiff) {
|
|
291
|
+
out(` (brak zmian w pliku SKILL.md)`);
|
|
292
|
+
}
|
|
293
|
+
out('');
|
|
163
294
|
}
|
|
164
295
|
|
|
165
296
|
async function cmdSkillUpdate(flags, out, err) {
|
|
@@ -223,4 +354,6 @@ module.exports = {
|
|
|
223
354
|
cmdSkillPush,
|
|
224
355
|
cmdSkillUpdate,
|
|
225
356
|
cmdSkillPromote,
|
|
357
|
+
cmdSkillVersions,
|
|
358
|
+
cmdSkillDiff,
|
|
226
359
|
};
|
package/src/skills-hub.js
CHANGED
|
@@ -91,15 +91,127 @@ async function getSkill(slug, version = null) {
|
|
|
91
91
|
return hubRequest(`/skills/${encodeURIComponent(slug)}${qs}`);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
function bumpVersion(currentVersion = '1.0.0', type = 'patch') {
|
|
95
|
+
const parts = String(currentVersion || '1.0.0').replace(/^v/, '').split('.').map((n) => parseInt(n, 10) || 0);
|
|
96
|
+
let [major = 1, minor = 0, patch = 0] = parts;
|
|
97
|
+
if (type === 'major') {
|
|
98
|
+
major += 1;
|
|
99
|
+
minor = 0;
|
|
100
|
+
patch = 0;
|
|
101
|
+
} else if (type === 'minor') {
|
|
102
|
+
minor += 1;
|
|
103
|
+
patch = 0;
|
|
104
|
+
} else {
|
|
105
|
+
patch += 1;
|
|
106
|
+
}
|
|
107
|
+
return `${major}.${minor}.${patch}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function getGitCommitMessage(dir) {
|
|
111
|
+
try {
|
|
112
|
+
const { execSync } = require('child_process');
|
|
113
|
+
const msg = execSync('git log -1 --pretty=%B', { cwd: dir, stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000 })
|
|
114
|
+
.toString('utf8')
|
|
115
|
+
.trim();
|
|
116
|
+
return msg || null;
|
|
117
|
+
} catch (_) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isTextBuffer(buf) {
|
|
123
|
+
const max = Math.min(buf.length, 512);
|
|
124
|
+
for (let i = 0; i < max; i++) {
|
|
125
|
+
if (buf[i] === 0) return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function gatherSkillBundle(skillDir) {
|
|
131
|
+
const isFile = fs.existsSync(skillDir) && fs.statSync(skillDir).isFile();
|
|
132
|
+
const mdPath = isFile ? skillDir : path.join(skillDir, 'SKILL.md');
|
|
98
133
|
|
|
99
134
|
if (!fs.existsSync(mdPath)) {
|
|
100
135
|
throw new Error(`Nie znaleziono pliku SKILL.md w ścieżce: ${skillDir}`);
|
|
101
136
|
}
|
|
102
137
|
|
|
138
|
+
const baseDir = isFile ? path.dirname(skillDir) : skillDir;
|
|
139
|
+
const manifest = [];
|
|
140
|
+
const ignored = new Set(['.git', 'node_modules', '.DS_Store', '__pycache__', '.pytest_cache', '.turbo']);
|
|
141
|
+
|
|
142
|
+
function walk(currentDir, relPrefix = '') {
|
|
143
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
144
|
+
for (const ent of entries) {
|
|
145
|
+
if (ignored.has(ent.name) || ent.name.startsWith('.')) continue;
|
|
146
|
+
const fullPath = path.join(currentDir, ent.name);
|
|
147
|
+
const relPath = relPrefix ? `${relPrefix}/${ent.name}` : ent.name;
|
|
148
|
+
|
|
149
|
+
if (ent.isDirectory()) {
|
|
150
|
+
walk(fullPath, relPath);
|
|
151
|
+
} else if (ent.isFile() && relPath !== 'SKILL.md') {
|
|
152
|
+
const buf = fs.readFileSync(fullPath);
|
|
153
|
+
const isText = isTextBuffer(buf);
|
|
154
|
+
const content = isText ? buf.toString('utf8') : buf.toString('base64');
|
|
155
|
+
const encoding = isText ? 'utf8' : 'base64';
|
|
156
|
+
const sha = crypto.createHash('sha256').update(buf).digest('hex');
|
|
157
|
+
|
|
158
|
+
manifest.push({
|
|
159
|
+
path: relPath,
|
|
160
|
+
content,
|
|
161
|
+
encoding,
|
|
162
|
+
size: buf.length,
|
|
163
|
+
sha256: sha,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
walk(baseDir);
|
|
170
|
+
return { mdPath, baseDir, manifest };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function diffLines(textA, textB) {
|
|
174
|
+
const linesA = String(textA || '').split('\n');
|
|
175
|
+
const linesB = String(textB || '').split('\n');
|
|
176
|
+
const diff = [];
|
|
177
|
+
let i = 0, j = 0;
|
|
178
|
+
while (i < linesA.length || j < linesB.length) {
|
|
179
|
+
if (i < linesA.length && j < linesB.length && linesA[i] === linesB[j]) {
|
|
180
|
+
diff.push({ type: 'same', line: linesA[i] });
|
|
181
|
+
i++; j++;
|
|
182
|
+
} else if (j < linesB.length && (!linesA.includes(linesB[j]) || linesB.indexOf(linesA[i]) > j)) {
|
|
183
|
+
diff.push({ type: 'added', line: linesB[j] });
|
|
184
|
+
j++;
|
|
185
|
+
} else if (i < linesA.length) {
|
|
186
|
+
diff.push({ type: 'removed', line: linesA[i] });
|
|
187
|
+
i++;
|
|
188
|
+
} else {
|
|
189
|
+
diff.push({ type: 'added', line: linesB[j] });
|
|
190
|
+
j++;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return diff;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function compareManifests(manifestA = [], manifestB = []) {
|
|
197
|
+
const mapA = new Map((manifestA || []).map((f) => [f.path, f]));
|
|
198
|
+
const mapB = new Map((manifestB || []).map((f) => [f.path, f]));
|
|
199
|
+
const added = [];
|
|
200
|
+
const removed = [];
|
|
201
|
+
const modified = [];
|
|
202
|
+
|
|
203
|
+
for (const [p, f] of mapB) {
|
|
204
|
+
if (!mapA.has(p)) added.push(f);
|
|
205
|
+
else if (mapA.get(p).sha256 !== f.sha256) modified.push({ path: p, old: mapA.get(p), new: f });
|
|
206
|
+
}
|
|
207
|
+
for (const [p, f] of mapA) {
|
|
208
|
+
if (!mapB.has(p)) removed.push(f);
|
|
209
|
+
}
|
|
210
|
+
return { added, removed, modified };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function pushSkill(skillDir, { version = null, bump = 'patch', changelog = null, visibility = 'shared' } = {}) {
|
|
214
|
+
const { mdPath, baseDir, manifest } = gatherSkillBundle(skillDir);
|
|
103
215
|
const skillContent = fs.readFileSync(mdPath, 'utf8');
|
|
104
216
|
|
|
105
217
|
// 1. Skanowanie sekretów
|
|
@@ -109,8 +221,18 @@ async function pushSkill(skillDir, { version = '1.0.0', changelog = 'Publikacja
|
|
|
109
221
|
throw new Error(`BLOKADA BEZPIECZEŃSTWA: Wykryto potencjalne klucze API w treści SKILL.md [${list}]. Usuń sekrety przed publikacją!`);
|
|
110
222
|
}
|
|
111
223
|
|
|
224
|
+
for (const file of manifest) {
|
|
225
|
+
if (file.encoding === 'utf8') {
|
|
226
|
+
const fScan = scanForSecrets(file.content);
|
|
227
|
+
if (!fScan.safe) {
|
|
228
|
+
const list = fScan.matches.map((m) => `${m.name} (${m.count})`).join(', ');
|
|
229
|
+
throw new Error(`BLOKADA BEZPIECZEŃSTWA: Wykryto potencjalne klucze w ${file.path} [${list}]. Usuń sekrety przed publikacją!`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
112
234
|
// 2. Parsowanie frontmatter
|
|
113
|
-
let slug = path.basename(
|
|
235
|
+
let slug = path.basename(baseDir);
|
|
114
236
|
let title = slug;
|
|
115
237
|
let description = '';
|
|
116
238
|
if (skillContent.startsWith('---')) {
|
|
@@ -126,39 +248,35 @@ async function pushSkill(skillDir, { version = '1.0.0', changelog = 'Publikacja
|
|
|
126
248
|
}
|
|
127
249
|
}
|
|
128
250
|
|
|
129
|
-
// 3.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
for (const f of files) {
|
|
139
|
-
const fullF = path.join(subPath, f);
|
|
140
|
-
if (fs.statSync(fullF).isFile() && !f.startsWith('.')) {
|
|
141
|
-
try {
|
|
142
|
-
const rel = path.join(sub, f);
|
|
143
|
-
const content = fs.readFileSync(fullF, 'utf8');
|
|
144
|
-
filesManifest.push({ path: rel, content });
|
|
145
|
-
} catch (_) {
|
|
146
|
-
// binarne pomijamy w manifeście tekstowym
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
251
|
+
// 3. Automatyczne ustalenie wersji, jeśli nie podano
|
|
252
|
+
let targetVersion = version;
|
|
253
|
+
if (!targetVersion) {
|
|
254
|
+
try {
|
|
255
|
+
const existing = await getSkill(slug);
|
|
256
|
+
const latestVer = existing?.data?.skill?.latest_version;
|
|
257
|
+
targetVersion = latestVer ? bumpVersion(latestVer, bump) : '1.0.0';
|
|
258
|
+
} catch (_) {
|
|
259
|
+
targetVersion = '1.0.0';
|
|
150
260
|
}
|
|
151
261
|
}
|
|
152
262
|
|
|
263
|
+
// 4. Automatyczny opis z ostatniego commita git, jeśli nie podano changelog
|
|
264
|
+
let finalChangelog = changelog;
|
|
265
|
+
if (!finalChangelog) {
|
|
266
|
+
const gitMsg = getGitCommitMessage(baseDir);
|
|
267
|
+
finalChangelog = gitMsg || 'Aktualizacja paczki przez DeerTools CLI';
|
|
268
|
+
}
|
|
269
|
+
|
|
153
270
|
const body = {
|
|
154
271
|
slug,
|
|
155
272
|
title,
|
|
156
273
|
summary: description,
|
|
157
|
-
version,
|
|
158
|
-
changelog,
|
|
274
|
+
version: targetVersion,
|
|
275
|
+
changelog: finalChangelog,
|
|
159
276
|
visibility,
|
|
277
|
+
skill_md: skillContent,
|
|
160
278
|
skill_md_content: skillContent,
|
|
161
|
-
files_manifest:
|
|
279
|
+
files_manifest: manifest,
|
|
162
280
|
};
|
|
163
281
|
|
|
164
282
|
return hubRequest('/skills/push', { method: 'POST', body });
|
|
@@ -194,6 +312,11 @@ module.exports = {
|
|
|
194
312
|
listSkills,
|
|
195
313
|
getSkill,
|
|
196
314
|
pushSkill,
|
|
315
|
+
bumpVersion,
|
|
316
|
+
gatherSkillBundle,
|
|
317
|
+
diffLines,
|
|
318
|
+
compareManifests,
|
|
319
|
+
getGitCommitMessage,
|
|
197
320
|
listMcpServers,
|
|
198
321
|
getProducts,
|
|
199
322
|
getDocs,
|