@rayul/kordis 0.9.3 → 0.10.1
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/assets/kordis-publishing/SKILL.md +45 -1
- package/assets/kordis-using/SKILL.md +26 -1
- package/dist/index.js +249 -31
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kordis-publishing
|
|
3
|
-
description: Use whenever the user wants to publish, share, or push a package to Kordis — phrases like "publish this", "share this skill to Kordis", "push this rule", "release a new version of <slug>", "bump the version", "semver", "버전 올리기". Covers dry-run flow, frontmatter requirements, version bump strategies, semver rules, and the AI review pipeline.
|
|
3
|
+
description: Use whenever the user wants to publish, share, or push a package to Kordis — phrases like "publish this", "share this skill to Kordis", "push this rule", "release a new version of <slug>", "bump the version", "semver", "버전 올리기". Also covers retracting a bad or compromised release — "yank", "withdraw a version", "unpublish a release", "kill a release", "nuke a version", "take down a version", "recall a release", "we leaked a key in <version>", "compromised", "철회", "내리기". Covers dry-run flow, frontmatter requirements, version bump strategies, semver rules, yank/unyank for retracting bad releases, and the AI review pipeline.
|
|
4
4
|
type: skill
|
|
5
5
|
allowed-tools: ["Bash(kordis:*)", "Read", "Edit"]
|
|
6
6
|
---
|
|
@@ -36,6 +36,50 @@ single `.md` file that doesn't match the SKILL.md filename pattern.
|
|
|
36
36
|
use only `--bump patch|minor|major` to control versioning. Having both
|
|
37
37
|
is the most common push failure.
|
|
38
38
|
|
|
39
|
+
## Yanking a bad version (0.10.0+)
|
|
40
|
+
|
|
41
|
+
When a single release goes wrong — leaked secret, broken on platform X,
|
|
42
|
+
superseded by an urgent fix — use **yank**, not delete.
|
|
43
|
+
|
|
44
|
+
### `kordis yank <full_slug>[@<version>] [--reason <text>] [--force]`
|
|
45
|
+
Soft-marks the specific version as "unrecommended". Author-only.
|
|
46
|
+
|
|
47
|
+
**0.10.1+ — omit `@<version>` to yank the package's current version.**
|
|
48
|
+
Panic-mode shortcut: `kordis yank user/slug --reason "leaked AWS key"
|
|
49
|
+
--force` yanks whichever version is currently installed by bare-slug pulls
|
|
50
|
+
without needing a prior `kordis versions <slug>` round-trip. The CLI
|
|
51
|
+
displays `(current)` next to the resolved version in the confirmation
|
|
52
|
+
banner so you know what got picked. Explicit pins (`@1.2.3`) still
|
|
53
|
+
override.
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
Versions yanked this way:
|
|
57
|
+
- Disappear from `kordis pull <slug>` (bare slug) and from `@^X.Y` /
|
|
58
|
+
`@X.x` / `@*` range resolution
|
|
59
|
+
- **Still install** when explicitly pinned to that exact version
|
|
60
|
+
(`kordis pull <slug>@1.2.3`) — but the consumer's CLI prints a
|
|
61
|
+
stderr warning naming the reason. This preserves reproducibility of
|
|
62
|
+
prior pinned installs.
|
|
63
|
+
- Reversible at any time with `kordis unyank`
|
|
64
|
+
|
|
65
|
+
`--reason` is plain text capped at 280 chars — shown verbatim to
|
|
66
|
+
consumers in `info` / `versions` / pull warning. Examples that work
|
|
67
|
+
well: `"leaked AWS key"`, `"broken on Node 18"`, `"superseded by
|
|
68
|
+
0.5.0 — security fix"`.
|
|
69
|
+
|
|
70
|
+
### `kordis unyank <full_slug>@<version>`
|
|
71
|
+
Reverses a yank. Idempotent. After unyank, the version re-enters
|
|
72
|
+
range resolution and `current_version` recomputes if appropriate.
|
|
73
|
+
|
|
74
|
+
### Yank vs delete — pick the right one
|
|
75
|
+
- **`kordis yank <slug>@<version>`** — one bad release. Reversible.
|
|
76
|
+
Per-version. Preserves pinned-install reproducibility.
|
|
77
|
+
- **`kordis delete <slug>`** — the whole package should disappear.
|
|
78
|
+
Permanent + slug reservation forever (no successor can republish
|
|
79
|
+
under the same name). Last-resort.
|
|
80
|
+
|
|
81
|
+
If you just pushed a wrong version, the answer is almost always yank.
|
|
82
|
+
|
|
39
83
|
## Deleting a package
|
|
40
84
|
|
|
41
85
|
### `kordis delete <full_slug> [--force]`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kordis-using
|
|
3
|
-
description: Use whenever the user wants to consult or install a Kordis package — including any `<username>/<slug>` reference, "install this skill", "use the X skill", "fetch the Y rule", "set this repo up with…", "pin to version", "specific version", "버전 고정", "전이 의존성", "transitive dependency". Covers JIT read vs pull, the five Kordis package types, dependencies, version pinning, range syntax, and attribution. Load eagerly when in doubt.
|
|
3
|
+
description: Use whenever the user wants to consult or install a Kordis package — including any `<username>/<slug>` reference, "install this skill", "use the X skill", "fetch the Y rule", "set this repo up with…", "pin to version", "specific version", "버전 고정", "전이 의존성", "transitive dependency", "yanked", "version withdrawn", "철회", "unrecommended version". Covers JIT read vs pull, the five Kordis package types, dependencies, version pinning, range syntax, yank semantics, and attribution. Load eagerly when in doubt.
|
|
4
4
|
type: skill
|
|
5
5
|
allowed-tools: ["Bash(kordis:*)"]
|
|
6
6
|
---
|
|
@@ -132,6 +132,31 @@ transitive deps — read is a one-shot context inject, no install plan.
|
|
|
132
132
|
`kordis info user/foo@^1` shows a `Requested: 1.4.2 (current: 2.0.0)`
|
|
133
133
|
line above `Type` when the pin differs from the registry default.
|
|
134
134
|
|
|
135
|
+
## When a version is yanked (0.10.0+)
|
|
136
|
+
|
|
137
|
+
Authors can soft-mark a specific release as "yanked" via `kordis yank
|
|
138
|
+
<slug>@<version>` — usually to discourage installs of a broken or
|
|
139
|
+
unsafe version. Yank is reversible (`kordis unyank`), per-version (NOT
|
|
140
|
+
whole-package), and preserves reproducibility of prior pinned
|
|
141
|
+
installs.
|
|
142
|
+
|
|
143
|
+
Three install behaviours:
|
|
144
|
+
|
|
145
|
+
| Input | Behaviour |
|
|
146
|
+
| ---------------------------------- | ---------------------------------------------------------------- |
|
|
147
|
+
| `kordis pull <slug>` | Always picks the highest **non-yanked** version. Yanked versions are silently skipped — user sees the next-best release. |
|
|
148
|
+
| `kordis pull <slug>@^X.Y` | Range resolution skips yanked. If every match is yanked, server returns `not_found` with hint "every version satisfying X has been yanked". |
|
|
149
|
+
| `kordis pull <slug>@<exact>` (pinned to a yanked version) | Succeeds (exit 0) with a stderr warning: `⚠ pulled yanked version X of slug (reason: …) — author marked this as unrecommended on YYYY-MM-DD`. Stays installable so old lockfiles keep working. |
|
|
150
|
+
|
|
151
|
+
`kordis info <slug>` shows a red `⚠ Yanked YYYY-MM-DD` banner with the
|
|
152
|
+
reason when the resolved version is yanked. `kordis versions <slug>`
|
|
153
|
+
greys out yanked rows and suffixes their status with ` (yanked)`.
|
|
154
|
+
|
|
155
|
+
Transitive yank: if `A → B@^1` and the only `B@^1` is yanked, server
|
|
156
|
+
returns `dependency_conflict` (exit 35) with a chain link naming the
|
|
157
|
+
parent. Surface that chain to the user — fixing usually means pinning
|
|
158
|
+
A's requirement to a non-yanked range, or contacting B's author.
|
|
159
|
+
|
|
135
160
|
## Dependencies
|
|
136
161
|
`kordis pull` reports `depends` and `recommends` from the package metadata.
|
|
137
162
|
Surface the dependency tree to the user FIRST. If they accept,
|
package/dist/index.js
CHANGED
|
@@ -334,7 +334,14 @@ var init_package = __esm({
|
|
|
334
334
|
* concrete resolved version. Absent for bare-slug calls (where the
|
|
335
335
|
* response reflects `current_version`).
|
|
336
336
|
*/
|
|
337
|
-
requested_version: SemverSchema.optional()
|
|
337
|
+
requested_version: SemverSchema.optional(),
|
|
338
|
+
/**
|
|
339
|
+
* 0.10.0+ — yank status of the *displayed* version (requested_version
|
|
340
|
+
* if pinned, else current_version). Absent for non-yanked versions
|
|
341
|
+
* so pre-0.10 clients keep ignoring unknown fields.
|
|
342
|
+
*/
|
|
343
|
+
yanked_at: IsoDateTimeSchema.nullable().optional(),
|
|
344
|
+
yank_reason: z6.string().max(280).nullable().optional()
|
|
338
345
|
});
|
|
339
346
|
PackageVersionSchema = z6.object({
|
|
340
347
|
id: UuidSchema,
|
|
@@ -347,7 +354,15 @@ var init_package = __esm({
|
|
|
347
354
|
review_status: ReviewStatusSchema,
|
|
348
355
|
review_score: z6.number().nullable(),
|
|
349
356
|
review_flags: z6.array(ReviewFlagSchema),
|
|
350
|
-
published_at: IsoDateTimeSchema
|
|
357
|
+
published_at: IsoDateTimeSchema,
|
|
358
|
+
/**
|
|
359
|
+
* 0.10.0+ — when set, this version was soft-marked as yanked by the
|
|
360
|
+
* author (or an admin override). Excluded from range/`*` resolution
|
|
361
|
+
* but still installable when explicitly pinned (`@<exact>`). Null
|
|
362
|
+
* for active versions.
|
|
363
|
+
*/
|
|
364
|
+
yanked_at: IsoDateTimeSchema.nullable().optional(),
|
|
365
|
+
yank_reason: z6.string().max(280).nullable().optional()
|
|
351
366
|
});
|
|
352
367
|
PackageVersionSummarySchema = PackageVersionSchema.omit({ content: true });
|
|
353
368
|
VersionDiffSchema = z6.object({
|
|
@@ -500,7 +515,7 @@ var init_auth = __esm({
|
|
|
500
515
|
|
|
501
516
|
// ../../packages/contracts/src/api.ts
|
|
502
517
|
import { z as z9 } from "zod";
|
|
503
|
-
var SearchQuerySchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, AssetSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageRequestSchema, PullPackageResponseSchema, ResolveVersionQuerySchema, ResolveVersionResponseSchema, GetPackageQuerySchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema, ListUserPackagesResponseSchema, ListUserStarsResponseSchema, FollowResponseSchema, ListFollowersQuerySchema, ListFollowersResponseSchema;
|
|
518
|
+
var SearchQuerySchema, SearchResponseSchema, TrendingQuerySchema, RisingQuerySchema, StarResponseSchema, AssetSchema, PublishPackageRequestSchema, PublishWaitQuerySchema, PublishPackageResponseSchema, PackagePathParamsSchema, ContentQuerySchema, PackageContentResponseSchema, JitReadRequestSchema, JitReadResponseSchema, PullPackageRequestSchema, PullPackageResponseSchema, YankRequestSchema, YankResponseSchema, ResolveVersionQuerySchema, ResolveVersionResponseSchema, GetPackageQuerySchema, ListVersionsResponseSchema, VersionDiffQuerySchema, ListCommentsQuerySchema, ListCommentsResponseSchema, UserProfileResponseSchema, UserPackagesQuerySchema, ListUserPackagesResponseSchema, ListUserStarsResponseSchema, FollowResponseSchema, ListFollowersQuerySchema, ListFollowersResponseSchema;
|
|
504
519
|
var init_api = __esm({
|
|
505
520
|
"../../packages/contracts/src/api.ts"() {
|
|
506
521
|
"use strict";
|
|
@@ -692,6 +707,17 @@ var init_api = __esm({
|
|
|
692
707
|
installed_paths: z9.array(z9.string()),
|
|
693
708
|
tool_detected: ToolSlugSchema.nullable(),
|
|
694
709
|
format: z9.string(),
|
|
710
|
+
/**
|
|
711
|
+
* 0.10.0+ — true when the version being pulled was explicitly
|
|
712
|
+
* pinned (@version) AND has been yanked by its author. CLI uses this
|
|
713
|
+
* to print the stderr warning. Bare-slug / range pulls never set
|
|
714
|
+
* this flag (those paths silently skip yanked versions). Field is
|
|
715
|
+
* omitted entirely (not false) when not relevant, so pre-0.10
|
|
716
|
+
* clients ignore it cleanly.
|
|
717
|
+
*/
|
|
718
|
+
yanked: z9.boolean().optional(),
|
|
719
|
+
yank_reason: z9.string().max(280).nullable().optional(),
|
|
720
|
+
yanked_at: IsoDateTimeSchema.nullable().optional(),
|
|
695
721
|
dependencies: z9.object({
|
|
696
722
|
required: z9.array(
|
|
697
723
|
z9.object({
|
|
@@ -718,6 +744,16 @@ var init_api = __esm({
|
|
|
718
744
|
}),
|
|
719
745
|
recommends_hint: z9.string().nullable()
|
|
720
746
|
});
|
|
747
|
+
YankRequestSchema = z9.object({
|
|
748
|
+
reason: z9.string().max(280).optional()
|
|
749
|
+
});
|
|
750
|
+
YankResponseSchema = z9.object({
|
|
751
|
+
full_slug: FullSlugSchema,
|
|
752
|
+
version: SemverSchema,
|
|
753
|
+
yanked_at: IsoDateTimeSchema.nullable(),
|
|
754
|
+
yank_reason: z9.string().max(280).nullable(),
|
|
755
|
+
effective_current_version: SemverSchema
|
|
756
|
+
});
|
|
721
757
|
ResolveVersionQuerySchema = z9.object({
|
|
722
758
|
range: SemverRangeSchema
|
|
723
759
|
});
|
|
@@ -1302,6 +1338,25 @@ var init_client = __esm({
|
|
|
1302
1338
|
`/api/packages/${username}/${slug}/versions`
|
|
1303
1339
|
);
|
|
1304
1340
|
}
|
|
1341
|
+
/**
|
|
1342
|
+
* 0.10.0+ — soft-yank a specific version. Author-only by default;
|
|
1343
|
+
* pass `asAdmin: true` to use the admin override (server validates
|
|
1344
|
+
* the caller's role). Reason is plain text, 280 chars max.
|
|
1345
|
+
*/
|
|
1346
|
+
yankVersion(username, slug, version, body = {}, opts = {}) {
|
|
1347
|
+
const query = opts.asAdmin ? { as: "admin" } : void 0;
|
|
1348
|
+
return this.request(
|
|
1349
|
+
`/api/packages/${username}/${slug}/versions/${version}/yank`,
|
|
1350
|
+
{ method: "POST", body, ...query ? { query } : {} }
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
unyankVersion(username, slug, version, opts = {}) {
|
|
1354
|
+
const query = opts.asAdmin ? { as: "admin" } : void 0;
|
|
1355
|
+
return this.request(
|
|
1356
|
+
`/api/packages/${username}/${slug}/versions/${version}/yank`,
|
|
1357
|
+
{ method: "DELETE", ...query ? { query } : {} }
|
|
1358
|
+
);
|
|
1359
|
+
}
|
|
1305
1360
|
diff(username, slug, from, to) {
|
|
1306
1361
|
return this.request(`/api/packages/${username}/${slug}/diff`, {
|
|
1307
1362
|
query: { from, to }
|
|
@@ -1430,7 +1485,7 @@ var init_src2 = __esm({
|
|
|
1430
1485
|
|
|
1431
1486
|
// src/index.ts
|
|
1432
1487
|
init_src2();
|
|
1433
|
-
import { Command as
|
|
1488
|
+
import { Command as Command25 } from "commander";
|
|
1434
1489
|
|
|
1435
1490
|
// src/commands/login.ts
|
|
1436
1491
|
import { Command } from "commander";
|
|
@@ -3859,7 +3914,12 @@ async function doPullInstall(fullSlug, tool, installRoot, opts = {}) {
|
|
|
3859
3914
|
installRoot,
|
|
3860
3915
|
written,
|
|
3861
3916
|
notes,
|
|
3862
|
-
plan: pullRes.dependencies
|
|
3917
|
+
plan: pullRes.dependencies,
|
|
3918
|
+
...pullRes.yanked ? {
|
|
3919
|
+
yanked: true,
|
|
3920
|
+
yankReason: pullRes.yank_reason ?? null,
|
|
3921
|
+
yankedAt: pullRes.yanked_at ?? null
|
|
3922
|
+
} : {}
|
|
3863
3923
|
};
|
|
3864
3924
|
}
|
|
3865
3925
|
function pullCommand() {
|
|
@@ -3928,6 +3988,11 @@ function pullCommand() {
|
|
|
3928
3988
|
tool_detected: result.tool,
|
|
3929
3989
|
installed_paths: result.written,
|
|
3930
3990
|
notes: result.notes,
|
|
3991
|
+
...result.yanked ? {
|
|
3992
|
+
yanked: true,
|
|
3993
|
+
yank_reason: result.yankReason,
|
|
3994
|
+
yanked_at: result.yankedAt
|
|
3995
|
+
} : {},
|
|
3931
3996
|
dependencies: dependencyInstalls.map((d) => ({
|
|
3932
3997
|
full_slug: d.fullSlug,
|
|
3933
3998
|
version: d.result.version,
|
|
@@ -3938,6 +4003,16 @@ function pullCommand() {
|
|
|
3938
4003
|
printHuman(
|
|
3939
4004
|
c.green(`\u2713 Installed ${c.bold(parsed.fullSlug)} v${result.version}`)
|
|
3940
4005
|
);
|
|
4006
|
+
if (result.yanked) {
|
|
4007
|
+
const reasonSuffix = result.yankReason ? ` (reason: ${result.yankReason})` : "";
|
|
4008
|
+
const dateSuffix = result.yankedAt ? ` on ${new Date(result.yankedAt).toISOString().slice(0, 10)}` : "";
|
|
4009
|
+
process.stderr.write(
|
|
4010
|
+
c.yellow(
|
|
4011
|
+
`\u26A0 pulled yanked version ${result.version} of ${parsed.fullSlug}${reasonSuffix} \u2014 author marked this as unrecommended${dateSuffix}
|
|
4012
|
+
`
|
|
4013
|
+
)
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
3941
4016
|
for (const w of result.written) printHuman(` ${c.gray("wrote")} ${w}`);
|
|
3942
4017
|
for (const n of result.notes) printHuman(c.yellow(` ! ${n}`));
|
|
3943
4018
|
for (const dep of dependencyInstalls) {
|
|
@@ -4060,6 +4135,15 @@ function infoCommand() {
|
|
|
4060
4135
|
printHuman(c.bold(detail.full_slug) + " " + c.gray(`v${headerVersion}`));
|
|
4061
4136
|
printHuman(" " + detail.description);
|
|
4062
4137
|
printHuman("");
|
|
4138
|
+
if (detail.yanked_at) {
|
|
4139
|
+
printHuman(
|
|
4140
|
+
c.red(" \u26A0 Yanked") + " " + c.gray(new Date(detail.yanked_at).toISOString().slice(0, 10))
|
|
4141
|
+
);
|
|
4142
|
+
if (detail.yank_reason) {
|
|
4143
|
+
printHuman(c.gray(` reason: ${detail.yank_reason}`));
|
|
4144
|
+
}
|
|
4145
|
+
printHuman("");
|
|
4146
|
+
}
|
|
4063
4147
|
if (detail.requested_version && detail.requested_version !== detail.current_version) {
|
|
4064
4148
|
printHuman(
|
|
4065
4149
|
` ${c.cyan("Requested")}: ${detail.requested_version} ${c.gray(`(current: ${detail.current_version})`)}`
|
|
@@ -4630,10 +4714,137 @@ function deleteCommand() {
|
|
|
4630
4714
|
});
|
|
4631
4715
|
}
|
|
4632
4716
|
|
|
4633
|
-
// src/commands/
|
|
4717
|
+
// src/commands/yank.ts
|
|
4634
4718
|
import { Command as Command13 } from "commander";
|
|
4719
|
+
import prompts3 from "prompts";
|
|
4720
|
+
function yankCommand() {
|
|
4721
|
+
return new Command13("yank").description("soft-mark a specific version of your package as yanked").argument(
|
|
4722
|
+
"<full_slug>",
|
|
4723
|
+
'package identifier; omit @version to yank the current version, or pin like "user/slug@1.2.3"'
|
|
4724
|
+
).option("--reason <text>", "optional reason shown to consumers (\u2264280 chars)").option("--force", "skip the confirmation prompt").action(
|
|
4725
|
+
async (fullSlugArg, opts) => {
|
|
4726
|
+
const parsed = parseSlugAtVersion(fullSlugArg);
|
|
4727
|
+
if (parsed.range) {
|
|
4728
|
+
throw new Error(
|
|
4729
|
+
"yank requires either no version (yanks current) or an explicit pin \u2014 range syntax not allowed"
|
|
4730
|
+
);
|
|
4731
|
+
}
|
|
4732
|
+
const bundle = await useClient();
|
|
4733
|
+
const detail = await bundle.api.getPackage(parsed.username, parsed.slug);
|
|
4734
|
+
const targetVersion = parsed.version ?? detail.current_version;
|
|
4735
|
+
const isImplicitCurrent = !parsed.version;
|
|
4736
|
+
if (!opts.force) {
|
|
4737
|
+
printHuman(c.yellow(" \u26A0 You are about to yank:"));
|
|
4738
|
+
printHuman(
|
|
4739
|
+
` ${c.bold(detail.full_slug)} v${targetVersion}${isImplicitCurrent ? c.gray(" (current)") : ""}`
|
|
4740
|
+
);
|
|
4741
|
+
if (opts.reason) {
|
|
4742
|
+
printHuman(` reason: ${opts.reason}`);
|
|
4743
|
+
}
|
|
4744
|
+
printHuman(
|
|
4745
|
+
c.gray(
|
|
4746
|
+
" Yanked versions disappear from range/`*` resolution. Pinned installs (`@" + targetVersion + "`) still work. Reversible with `kordis unyank`."
|
|
4747
|
+
)
|
|
4748
|
+
);
|
|
4749
|
+
printHuman("");
|
|
4750
|
+
const { confirmed } = await prompts3({
|
|
4751
|
+
type: "confirm",
|
|
4752
|
+
name: "confirmed",
|
|
4753
|
+
message: `Yank ${c.bold(`${parsed.fullSlug}@${targetVersion}`)}?`,
|
|
4754
|
+
initial: false
|
|
4755
|
+
});
|
|
4756
|
+
if (!confirmed) {
|
|
4757
|
+
printHuman(c.gray("Aborted."));
|
|
4758
|
+
process.exit(0);
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
const res = await bundle.authedRequest(
|
|
4762
|
+
(api) => api.yankVersion(parsed.username, parsed.slug, targetVersion, {
|
|
4763
|
+
...opts.reason ? { reason: opts.reason } : {}
|
|
4764
|
+
})
|
|
4765
|
+
);
|
|
4766
|
+
printDual({
|
|
4767
|
+
json: res,
|
|
4768
|
+
human: () => {
|
|
4769
|
+
printHuman(
|
|
4770
|
+
c.green(
|
|
4771
|
+
`\u2713 Yanked ${c.bold(parsed.fullSlug)}@${targetVersion}`
|
|
4772
|
+
)
|
|
4773
|
+
);
|
|
4774
|
+
if (res.yank_reason) {
|
|
4775
|
+
printHuman(c.gray(` reason: ${res.yank_reason}`));
|
|
4776
|
+
}
|
|
4777
|
+
if (res.effective_current_version !== targetVersion) {
|
|
4778
|
+
printHuman(
|
|
4779
|
+
c.gray(
|
|
4780
|
+
` current_version is now ${c.bold(res.effective_current_version)} (was ${targetVersion})`
|
|
4781
|
+
)
|
|
4782
|
+
);
|
|
4783
|
+
} else {
|
|
4784
|
+
printHuman(
|
|
4785
|
+
c.gray(
|
|
4786
|
+
` current_version unchanged at ${c.bold(res.effective_current_version)} (no higher non-yanked version exists)`
|
|
4787
|
+
)
|
|
4788
|
+
);
|
|
4789
|
+
}
|
|
4790
|
+
printHuman(
|
|
4791
|
+
c.gray(
|
|
4792
|
+
` \u2192 Reverse with: kordis unyank ${parsed.fullSlug}@${targetVersion}`
|
|
4793
|
+
)
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
});
|
|
4797
|
+
}
|
|
4798
|
+
);
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4801
|
+
// src/commands/unyank.ts
|
|
4802
|
+
import { Command as Command14 } from "commander";
|
|
4803
|
+
function unyankCommand() {
|
|
4804
|
+
return new Command14("unyank").description("reverse a yank on a specific version").argument(
|
|
4805
|
+
"<full_slug>",
|
|
4806
|
+
'package identifier with explicit version, e.g. "user/slug@1.2.3"'
|
|
4807
|
+
).action(async (fullSlugArg) => {
|
|
4808
|
+
const parsed = parseSlugAtVersion(fullSlugArg);
|
|
4809
|
+
if (!parsed.version) {
|
|
4810
|
+
throw new Error(
|
|
4811
|
+
'unyank requires an explicit version pin \u2014 use "user/slug@1.2.3"'
|
|
4812
|
+
);
|
|
4813
|
+
}
|
|
4814
|
+
const bundle = await useClient();
|
|
4815
|
+
const res = await bundle.authedRequest(
|
|
4816
|
+
(api) => api.unyankVersion(parsed.username, parsed.slug, parsed.version)
|
|
4817
|
+
);
|
|
4818
|
+
printDual({
|
|
4819
|
+
json: res,
|
|
4820
|
+
human: () => {
|
|
4821
|
+
printHuman(
|
|
4822
|
+
c.green(
|
|
4823
|
+
`\u2713 Unyanked ${c.bold(parsed.fullSlug)}@${parsed.version}`
|
|
4824
|
+
)
|
|
4825
|
+
);
|
|
4826
|
+
if (res.effective_current_version !== parsed.version) {
|
|
4827
|
+
printHuman(
|
|
4828
|
+
c.gray(
|
|
4829
|
+
` current_version is ${c.bold(res.effective_current_version)} (highest non-yanked)`
|
|
4830
|
+
)
|
|
4831
|
+
);
|
|
4832
|
+
} else {
|
|
4833
|
+
printHuman(
|
|
4834
|
+
c.gray(
|
|
4835
|
+
` current_version is now ${c.bold(res.effective_current_version)}`
|
|
4836
|
+
)
|
|
4837
|
+
);
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
});
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
// src/commands/list.ts
|
|
4845
|
+
import { Command as Command15 } from "commander";
|
|
4635
4846
|
function listCommand() {
|
|
4636
|
-
return new
|
|
4847
|
+
return new Command15("list").description("list packages \u2014 your own (no arg) or a public user\u2019s (with <username>)").argument("[username]", "kordis username to list (omit for self)").option("--limit <n>", "max results per page", (v) => parseInt(v, 10), 20).option("--page <n>", "self-mode page number (1-based)", (v) => parseInt(v, 10), 1).option("--cursor <token>", "public-mode pagination cursor").option("--sort <mode>", "sort: latest|popular (self) or stars|downloads|recent|updated (public)", "latest").action(async (rawUsername, opts) => {
|
|
4637
4848
|
const bundle = await useClient();
|
|
4638
4849
|
if (rawUsername === void 0) {
|
|
4639
4850
|
requireAuth(bundle);
|
|
@@ -4704,9 +4915,9 @@ function listCommand() {
|
|
|
4704
4915
|
}
|
|
4705
4916
|
|
|
4706
4917
|
// src/commands/versions.ts
|
|
4707
|
-
import { Command as
|
|
4918
|
+
import { Command as Command16 } from "commander";
|
|
4708
4919
|
function versionsCommand() {
|
|
4709
|
-
return new
|
|
4920
|
+
return new Command16("versions").description("list all versions of a package").argument("<full_slug>", "package identifier {username}/{slug}").action(async (fullSlug) => {
|
|
4710
4921
|
const [username, slug] = fullSlug.split("/");
|
|
4711
4922
|
if (!username || !slug) {
|
|
4712
4923
|
throw new Error('full_slug must be "{username}/{slug}"');
|
|
@@ -4723,12 +4934,17 @@ function versionsCommand() {
|
|
|
4723
4934
|
);
|
|
4724
4935
|
printHuman("");
|
|
4725
4936
|
for (const v of res.versions) {
|
|
4726
|
-
const
|
|
4937
|
+
const isYanked = Boolean(v.yanked_at);
|
|
4938
|
+
const reviewLabel = isYanked ? c.gray(`${v.review_status} (yanked)`) : v.review_status === "passed" ? c.green(v.review_status) : v.review_status === "rejected" ? c.red(v.review_status) : c.yellow(v.review_status);
|
|
4727
4939
|
const age = relativeTime(v.published_at);
|
|
4728
4940
|
const isCurrent = v.version === res.current_version;
|
|
4941
|
+
const versionLabel = isYanked ? c.gray(v.version) : c.bold(v.version);
|
|
4729
4942
|
printHuman(
|
|
4730
|
-
` ${
|
|
4943
|
+
` ${versionLabel}${isCurrent ? c.cyan(" (current)") : ""} ${reviewLabel} ${c.gray(age)}`
|
|
4731
4944
|
);
|
|
4945
|
+
if (isYanked && v.yank_reason) {
|
|
4946
|
+
printHuman(` ${c.gray(`reason: ${v.yank_reason}`)}`);
|
|
4947
|
+
}
|
|
4732
4948
|
}
|
|
4733
4949
|
}
|
|
4734
4950
|
});
|
|
@@ -4760,13 +4976,13 @@ function relativeTime(isoString) {
|
|
|
4760
4976
|
}
|
|
4761
4977
|
|
|
4762
4978
|
// src/commands/outdated.ts
|
|
4763
|
-
import { Command as
|
|
4979
|
+
import { Command as Command17 } from "commander";
|
|
4764
4980
|
import semver from "semver";
|
|
4765
4981
|
function effectiveRange(entry) {
|
|
4766
4982
|
return entry.requestedRange ?? `^${entry.version}`;
|
|
4767
4983
|
}
|
|
4768
4984
|
function outdatedCommand() {
|
|
4769
|
-
return new
|
|
4985
|
+
return new Command17("outdated").description("check installed packages for available updates").action(async () => {
|
|
4770
4986
|
const lf = await readLockfile();
|
|
4771
4987
|
const slugs = Object.keys(lf.packages);
|
|
4772
4988
|
if (slugs.length === 0) {
|
|
@@ -4864,13 +5080,13 @@ function outdatedCommand() {
|
|
|
4864
5080
|
}
|
|
4865
5081
|
|
|
4866
5082
|
// src/commands/update.ts
|
|
4867
|
-
import { Command as
|
|
5083
|
+
import { Command as Command18 } from "commander";
|
|
4868
5084
|
import semver2 from "semver";
|
|
4869
5085
|
function effectiveRange2(entry) {
|
|
4870
5086
|
return entry.requestedRange ?? `^${entry.version}`;
|
|
4871
5087
|
}
|
|
4872
5088
|
function updateCommand() {
|
|
4873
|
-
return new
|
|
5089
|
+
return new Command18("update").description("update installed packages to their latest versions").argument("[full_slug]", "package identifier {username}/{slug} (omit to update all)").option("--dry-run", "show what would be updated without doing it", false).action(async (fullSlugArg, opts) => {
|
|
4874
5090
|
const lf = await readLockfile();
|
|
4875
5091
|
let slugs = Object.keys(lf.packages);
|
|
4876
5092
|
if (slugs.length === 0) {
|
|
@@ -5004,9 +5220,9 @@ function updateCommand() {
|
|
|
5004
5220
|
}
|
|
5005
5221
|
|
|
5006
5222
|
// src/commands/diff.ts
|
|
5007
|
-
import { Command as
|
|
5223
|
+
import { Command as Command19 } from "commander";
|
|
5008
5224
|
function diffCommand() {
|
|
5009
|
-
return new
|
|
5225
|
+
return new Command19("diff").description("show changes between two versions of a package").argument("<full_slug>", "package identifier: {username}/{slug}, or {username}/{slug}@{from}..{to}").argument("[from]", "older version (omit to use second-latest)").argument("[to]", "newer version (omit to use latest)").action(async (fullSlugArg, fromArg, toArg) => {
|
|
5010
5226
|
let fullSlug = fullSlugArg;
|
|
5011
5227
|
let from = fromArg;
|
|
5012
5228
|
let to = toArg;
|
|
@@ -5077,13 +5293,13 @@ function diffCommand() {
|
|
|
5077
5293
|
}
|
|
5078
5294
|
|
|
5079
5295
|
// src/commands/recommend.ts
|
|
5080
|
-
import { Command as
|
|
5081
|
-
import
|
|
5296
|
+
import { Command as Command20 } from "commander";
|
|
5297
|
+
import prompts4 from "prompts";
|
|
5082
5298
|
function recommendCommand() {
|
|
5083
|
-
return new
|
|
5299
|
+
return new Command20("recommend").description("show personalized package recommendations").option("--limit <n>", "max items to return (1-50)", (v) => parseInt(v, 10), 10).option("--verbose", "include score_breakdown per item", false).option("--no-context", "skip the X-Kordis-Context header for this call").action(async (opts) => {
|
|
5084
5300
|
const cfg = await loadCliConfig();
|
|
5085
5301
|
if (cfg.personalization === "undecided" && process.stdin.isTTY && !isJsonMode() && opts.context !== false) {
|
|
5086
|
-
const { enable } = await
|
|
5302
|
+
const { enable } = await prompts4({
|
|
5087
5303
|
type: "confirm",
|
|
5088
5304
|
name: "enable",
|
|
5089
5305
|
message: "Personalize recommendations using anonymous local signals (installed agent tools, language stats, frameworks)? Server never stores them \u2014 only re-ranks results in-flight.",
|
|
@@ -5188,9 +5404,9 @@ function renderItem(idx, it, verbose) {
|
|
|
5188
5404
|
}
|
|
5189
5405
|
|
|
5190
5406
|
// src/commands/profile.ts
|
|
5191
|
-
import { Command as
|
|
5407
|
+
import { Command as Command21 } from "commander";
|
|
5192
5408
|
function profileCommand() {
|
|
5193
|
-
return new
|
|
5409
|
+
return new Command21("profile").description("inspect a user\u2019s public profile").argument("<username>", "kordis username").action(async (raw) => {
|
|
5194
5410
|
const username = parseUsername(raw);
|
|
5195
5411
|
const bundle = await useClient();
|
|
5196
5412
|
const profile = await bundle.api.getUserProfile(username);
|
|
@@ -5225,9 +5441,9 @@ function profileCommand() {
|
|
|
5225
5441
|
}
|
|
5226
5442
|
|
|
5227
5443
|
// src/commands/stars.ts
|
|
5228
|
-
import { Command as
|
|
5444
|
+
import { Command as Command22 } from "commander";
|
|
5229
5445
|
function starsCommand() {
|
|
5230
|
-
return new
|
|
5446
|
+
return new Command22("stars").description("list packages a user has starred").argument("<username>", "kordis username").option("--limit <n>", "max results per page (1-100, default 50)", (v) => parseInt(v, 10), 50).option("--cursor <token>", "pagination cursor returned by a prior response").action(async (raw, opts) => {
|
|
5231
5447
|
const username = parseUsername(raw);
|
|
5232
5448
|
const bundle = await useClient();
|
|
5233
5449
|
const res = await bundle.api.listUserStars(username, {
|
|
@@ -5259,9 +5475,9 @@ function starsCommand() {
|
|
|
5259
5475
|
}
|
|
5260
5476
|
|
|
5261
5477
|
// src/commands/follow.ts
|
|
5262
|
-
import { Command as
|
|
5478
|
+
import { Command as Command23 } from "commander";
|
|
5263
5479
|
function followCommand() {
|
|
5264
|
-
return new
|
|
5480
|
+
return new Command23("follow").description("follow a kordis user").argument("<username>", "kordis username").action(async (raw) => {
|
|
5265
5481
|
const username = parseUsername(raw);
|
|
5266
5482
|
const bundle = await useClient();
|
|
5267
5483
|
requireAuth(bundle);
|
|
@@ -5276,7 +5492,7 @@ function followCommand() {
|
|
|
5276
5492
|
});
|
|
5277
5493
|
}
|
|
5278
5494
|
function unfollowCommand() {
|
|
5279
|
-
return new
|
|
5495
|
+
return new Command23("unfollow").description("stop following a kordis user").argument("<username>", "kordis username").action(async (raw) => {
|
|
5280
5496
|
const username = parseUsername(raw);
|
|
5281
5497
|
const bundle = await useClient();
|
|
5282
5498
|
requireAuth(bundle);
|
|
@@ -5292,9 +5508,9 @@ function unfollowCommand() {
|
|
|
5292
5508
|
}
|
|
5293
5509
|
|
|
5294
5510
|
// src/commands/followers.ts
|
|
5295
|
-
import { Command as
|
|
5511
|
+
import { Command as Command24 } from "commander";
|
|
5296
5512
|
function makeListing(name) {
|
|
5297
|
-
return new
|
|
5513
|
+
return new Command24(name).description(
|
|
5298
5514
|
name === "followers" ? "list users following <username>" : "list users that <username> follows"
|
|
5299
5515
|
).argument("<username>", "kordis username").option("--limit <n>", "max results per page (1-100, default 50)", (v) => parseInt(v, 10), 50).option("--cursor <token>", "pagination cursor returned by a prior response").action(async (raw, opts) => {
|
|
5300
5516
|
const username = parseUsername(raw);
|
|
@@ -5339,7 +5555,7 @@ function followingCommand() {
|
|
|
5339
5555
|
|
|
5340
5556
|
// src/index.ts
|
|
5341
5557
|
function buildProgram() {
|
|
5342
|
-
const program = new
|
|
5558
|
+
const program = new Command25("kordis").version(VERSION).description("Kordis \u2014 registry for agentic-coding packages").option("--json", "emit JSON output to stdout (default: human)", false).hook("preAction", (thisCommand) => {
|
|
5343
5559
|
const opts = thisCommand.optsWithGlobals();
|
|
5344
5560
|
if (opts.json) setJsonMode(true);
|
|
5345
5561
|
}).addHelpText("after", `
|
|
@@ -5372,6 +5588,8 @@ Environment variables (see README.md "Privacy & environment variables"):
|
|
|
5372
5588
|
program.addCommand(followersCommand());
|
|
5373
5589
|
program.addCommand(followingCommand());
|
|
5374
5590
|
program.addCommand(deleteCommand());
|
|
5591
|
+
program.addCommand(yankCommand());
|
|
5592
|
+
program.addCommand(unyankCommand());
|
|
5375
5593
|
program.addCommand(listCommand());
|
|
5376
5594
|
program.addCommand(versionsCommand());
|
|
5377
5595
|
program.addCommand(outdatedCommand());
|