skilld 0.9.1 → 0.9.3
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 +12 -3
- package/dist/_chunks/npm.mjs +21 -13
- package/dist/_chunks/npm.mjs.map +1 -1
- package/dist/_chunks/utils.d.mts +3 -3
- package/dist/_chunks/utils.d.mts.map +1 -1
- package/dist/cli.mjs +71 -15
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,6 +158,7 @@ skilld config
|
|
|
158
158
|
| `skilld remove` | Remove installed skills |
|
|
159
159
|
| `skilld uninstall` | Remove all skilld data |
|
|
160
160
|
| `skilld cache` | Cache management (clean expired LLM cache entries) |
|
|
161
|
+
| `skilld eject <pkg>` | Eject skill as portable directory (no symlinks) |
|
|
161
162
|
|
|
162
163
|
### Eject
|
|
163
164
|
|
|
@@ -165,10 +166,16 @@ Export a skill as a portable, self-contained directory with references copied as
|
|
|
165
166
|
|
|
166
167
|
```bash
|
|
167
168
|
# Eject to the default skill directory
|
|
168
|
-
skilld
|
|
169
|
+
skilld eject vue
|
|
170
|
+
|
|
171
|
+
# Custom skill directory name
|
|
172
|
+
skilld eject vue --name vue
|
|
169
173
|
|
|
170
174
|
# Eject to a custom path
|
|
171
|
-
skilld
|
|
175
|
+
skilld eject vue --out ./skills/vue/
|
|
176
|
+
|
|
177
|
+
# Only collect releases/issues/discussions since a date
|
|
178
|
+
skilld eject vue --from 2025-07-01
|
|
172
179
|
```
|
|
173
180
|
|
|
174
181
|
The ejected skill contains `SKILL.md` plus a `references/` directory with docs, issues, and releases as real files. Share it via `skilld add owner/repo` — consumers get fully functional skills with no LLM cost.
|
|
@@ -182,7 +189,9 @@ The ejected skill contains `SKILL.md` plus a `references/` directory with docs,
|
|
|
182
189
|
| `--yes` | `-y` | `false` | Skip prompts, use defaults |
|
|
183
190
|
| `--force` | `-f` | `false` | Ignore all caches, re-fetch docs and regenerate |
|
|
184
191
|
| `--model` | `-m` | config default | LLM model for skill generation (sonnet, haiku, opus, etc.) |
|
|
185
|
-
| `--
|
|
192
|
+
| `--name` | `-n` | | Custom skill directory name (eject only) |
|
|
193
|
+
| `--out` | `-o` | | Output directory path override (eject only) |
|
|
194
|
+
| `--from` | | | Collect releases/issues/discussions from this date (YYYY-MM-DD, eject only) |
|
|
186
195
|
| `--debug` | | `false` | Save raw LLM output to logs/ for each section |
|
|
187
196
|
|
|
188
197
|
## The Landscape
|
package/dist/_chunks/npm.mjs
CHANGED
|
@@ -162,10 +162,11 @@ function truncateBody$1(body, limit) {
|
|
|
162
162
|
if (lastParagraph > lastSafeEnd * .6) return `${slice.slice(0, lastParagraph)}\n\n...`;
|
|
163
163
|
return `${slice}...`;
|
|
164
164
|
}
|
|
165
|
-
function fetchIssuesByState(owner, repo, state, count, releasedAt) {
|
|
165
|
+
function fetchIssuesByState(owner, repo, state, count, releasedAt, fromDate) {
|
|
166
166
|
const fetchCount = Math.min(count * 3, 100);
|
|
167
167
|
let datePart = "";
|
|
168
|
-
if (state === "closed"
|
|
168
|
+
if (fromDate) datePart = state === "closed" ? `+closed:>=${fromDate}` : `+created:>=${fromDate}`;
|
|
169
|
+
else if (state === "closed") if (releasedAt) {
|
|
169
170
|
const date = new Date(releasedAt);
|
|
170
171
|
date.setMonth(date.getMonth() + 6);
|
|
171
172
|
datePart = `+closed:<=${isoDate(date.toISOString())}`;
|
|
@@ -256,13 +257,13 @@ function detectResolvedVersion(comments) {
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
|
-
async function fetchGitHubIssues(owner, repo, limit = 30, releasedAt) {
|
|
260
|
+
async function fetchGitHubIssues(owner, repo, limit = 30, releasedAt, fromDate) {
|
|
260
261
|
if (!isGhAvailable()) return [];
|
|
261
262
|
const openCount = Math.ceil(limit * .75);
|
|
262
263
|
const closedCount = limit - openCount;
|
|
263
264
|
try {
|
|
264
|
-
const open = fetchIssuesByState(owner, repo, "open", Math.min(openCount * 2, 100), releasedAt);
|
|
265
|
-
const closed = fetchIssuesByState(owner, repo, "closed", Math.min(closedCount * 2, 50), releasedAt);
|
|
265
|
+
const open = fetchIssuesByState(owner, repo, "open", Math.min(openCount * 2, 100), releasedAt, fromDate);
|
|
266
|
+
const closed = fetchIssuesByState(owner, repo, "closed", Math.min(closedCount * 2, 50), releasedAt, fromDate);
|
|
266
267
|
const selected = applyTypeQuotas([...open, ...closed], limit);
|
|
267
268
|
enrichWithComments(owner, repo, selected);
|
|
268
269
|
return selected;
|
|
@@ -473,16 +474,21 @@ async function fetchAllReleases(owner, repo) {
|
|
|
473
474
|
}
|
|
474
475
|
return fetchReleasesViaUngh(owner, repo);
|
|
475
476
|
}
|
|
476
|
-
function selectReleases(releases, packageName, installedVersion) {
|
|
477
|
+
function selectReleases(releases, packageName, installedVersion, fromDate) {
|
|
477
478
|
const hasMonorepoTags = packageName && releases.some((r) => tagMatchesPackage(r.tag, packageName));
|
|
478
479
|
const installedSv = installedVersion ? parseSemver(installedVersion) : null;
|
|
479
480
|
const installedIsPrerelease = installedVersion ? isPrerelease(installedVersion) : false;
|
|
480
|
-
|
|
481
|
+
const fromTs = fromDate ? new Date(fromDate).getTime() : null;
|
|
482
|
+
const sorted = releases.filter((r) => {
|
|
481
483
|
const ver = extractVersion(r.tag, hasMonorepoTags ? packageName : void 0);
|
|
482
484
|
if (!ver) return false;
|
|
483
485
|
const sv = parseSemver(ver);
|
|
484
486
|
if (!sv) return false;
|
|
485
487
|
if (hasMonorepoTags && packageName && !tagMatchesPackage(r.tag, packageName)) return false;
|
|
488
|
+
if (fromTs) {
|
|
489
|
+
const pubDate = r.publishedAt || r.createdAt;
|
|
490
|
+
if (pubDate && new Date(pubDate).getTime() < fromTs) return false;
|
|
491
|
+
}
|
|
486
492
|
if (r.prerelease) {
|
|
487
493
|
if (!installedIsPrerelease || !installedSv) return false;
|
|
488
494
|
return sv.major === installedSv.major && sv.minor === installedSv.minor;
|
|
@@ -494,7 +500,8 @@ function selectReleases(releases, packageName, installedVersion) {
|
|
|
494
500
|
const verB = extractVersion(b.tag, hasMonorepoTags ? packageName : void 0);
|
|
495
501
|
if (!verA || !verB) return 0;
|
|
496
502
|
return compareSemver(parseSemver(verB), parseSemver(verA));
|
|
497
|
-
})
|
|
503
|
+
});
|
|
504
|
+
return fromDate ? sorted : sorted.slice(0, 20);
|
|
498
505
|
}
|
|
499
506
|
function formatRelease(release, packageName) {
|
|
500
507
|
const date = isoDate(release.publishedAt || release.createdAt);
|
|
@@ -572,8 +579,8 @@ async function fetchChangelog(owner, repo, ref) {
|
|
|
572
579
|
}
|
|
573
580
|
return null;
|
|
574
581
|
}
|
|
575
|
-
async function fetchReleaseNotes(owner, repo, installedVersion, gitRef, packageName) {
|
|
576
|
-
const selected = selectReleases(await fetchAllReleases(owner, repo), packageName, installedVersion);
|
|
582
|
+
async function fetchReleaseNotes(owner, repo, installedVersion, gitRef, packageName, fromDate) {
|
|
583
|
+
const selected = selectReleases(await fetchAllReleases(owner, repo), packageName, installedVersion, fromDate);
|
|
577
584
|
if (selected.length > 0) {
|
|
578
585
|
if (isChangelogRedirectPattern(selected)) {
|
|
579
586
|
const changelog = await fetchChangelog(owner, repo, gitRef || selected[0].tag);
|
|
@@ -713,9 +720,9 @@ function truncateBody(body, limit) {
|
|
|
713
720
|
function scoreComment(c) {
|
|
714
721
|
return (c.isMaintainer ? 3 : 1) * (hasCodeBlock(c.body) ? 2 : 1) * (1 + c.reactions);
|
|
715
722
|
}
|
|
716
|
-
async function fetchGitHubDiscussions(owner, repo, limit = 20, releasedAt) {
|
|
723
|
+
async function fetchGitHubDiscussions(owner, repo, limit = 20, releasedAt, fromDate) {
|
|
717
724
|
if (!isGhAvailable()) return [];
|
|
718
|
-
if (releasedAt) {
|
|
725
|
+
if (!fromDate && releasedAt) {
|
|
719
726
|
const cutoff = new Date(releasedAt);
|
|
720
727
|
cutoff.setMonth(cutoff.getMonth() + 6);
|
|
721
728
|
if (cutoff < /* @__PURE__ */ new Date()) return [];
|
|
@@ -737,10 +744,11 @@ async function fetchGitHubDiscussions(owner, repo, limit = 20, releasedAt) {
|
|
|
737
744
|
if (!result) return [];
|
|
738
745
|
const nodes = JSON.parse(result)?.data?.repository?.discussions?.nodes;
|
|
739
746
|
if (!Array.isArray(nodes)) return [];
|
|
747
|
+
const fromTs = fromDate ? new Date(fromDate).getTime() : null;
|
|
740
748
|
return nodes.filter((d) => d.author && !BOT_USERS.has(d.author.login)).filter((d) => {
|
|
741
749
|
const cat = (d.category?.name || "").toLowerCase();
|
|
742
750
|
return !LOW_VALUE_CATEGORIES.has(cat);
|
|
743
|
-
}).map((d) => {
|
|
751
|
+
}).filter((d) => !fromTs || new Date(d.createdAt).getTime() >= fromTs).map((d) => {
|
|
744
752
|
let answer;
|
|
745
753
|
if (d.answer?.body) {
|
|
746
754
|
const isMaintainer = [
|