@oh-my-pi/pi-wire 18.2.10 → 18.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/CHANGELOG.md +6 -0
- package/dist/types/skillshare.d.ts +293 -0
- package/package.json +1 -1
- package/src/skillshare.ts +323 -0
package/CHANGELOG.md
CHANGED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for Skillshare (`skills.omp.sh`): an npm-style registry for
|
|
3
|
+
* omp skills. Shared by the omp CLI (`omp skill …`), the Go server
|
|
4
|
+
* (`stencil/apps/skills`), and its web UI (which mirrors this file).
|
|
5
|
+
*
|
|
6
|
+
* Packages are scoped: `@scope/name`. A scope is a Stencil username claimed on
|
|
7
|
+
* first publish and bound to the account's immutable `sub` forever (usernames
|
|
8
|
+
* can be renamed and recycled; scopes cannot). `name` is the SKILL.md
|
|
9
|
+
* frontmatter `name`. Published versions are immutable.
|
|
10
|
+
*
|
|
11
|
+
* Registry fields ride in SKILL.md `metadata` (the Agent Skills frontmatter is
|
|
12
|
+
* closed to name/description/license/compatibility/metadata/allowed-tools):
|
|
13
|
+
* `metadata.version` (semver, required to publish), `metadata.keywords`
|
|
14
|
+
* (comma-separated), `metadata.repository`, `metadata.homepage`.
|
|
15
|
+
*/
|
|
16
|
+
/** Default registry; `skills.registryUrl` overrides it. */
|
|
17
|
+
export declare const DEFAULT_SKILLS_URL = "https://skills.omp.sh";
|
|
18
|
+
/** Scopes are Stencil usernames (or registry orgs): lowercase letters, digits, underscores; 3–32 chars. */
|
|
19
|
+
export declare const SKILL_SCOPE_RE: RegExp;
|
|
20
|
+
/** Registry skill names: ASCII kebab-case, 1–64 chars, no leading/trailing/double hyphens. */
|
|
21
|
+
export declare const SKILL_NAME_RE: RegExp;
|
|
22
|
+
export declare const SKILL_NAME_MAX = 64;
|
|
23
|
+
/** `@scope/name`, optionally `@version-or-range-or-tag`. */
|
|
24
|
+
export declare const SKILL_SPEC_RE: RegExp;
|
|
25
|
+
/** Publish limits, enforced by both the CLI and the server. */
|
|
26
|
+
export declare const SKILL_LIMITS: {
|
|
27
|
+
/** Compressed `.tgz` upload. */
|
|
28
|
+
readonly tarballBytes: number;
|
|
29
|
+
/** Sum of all file sizes after unpacking. */
|
|
30
|
+
readonly unpackedBytes: number;
|
|
31
|
+
readonly files: 1000;
|
|
32
|
+
/** Longest path inside the package. */
|
|
33
|
+
readonly pathLength: 255;
|
|
34
|
+
readonly descriptionLength: 1024;
|
|
35
|
+
readonly keywords: 20;
|
|
36
|
+
readonly keywordLength: 50;
|
|
37
|
+
readonly deprecationLength: 500;
|
|
38
|
+
};
|
|
39
|
+
/** Paths excluded from packs in addition to `.skillignore` entries. */
|
|
40
|
+
export declare const SKILL_DEFAULT_IGNORES: readonly [".git", ".DS_Store", "node_modules", "__pycache__", "*.pyc", "evals", ".skillignore"];
|
|
41
|
+
/**
|
|
42
|
+
* Publish request: `PUT SKILLS_ROUTES.publish(scope, name, version)`, body is
|
|
43
|
+
* the `.tgz` (gzip tar; entries are paths relative to the skill root, regular
|
|
44
|
+
* files only, sorted, mtime 0, mode 0644 or 0755). Auth: `Authorization:
|
|
45
|
+
* Bearer <Stencil access token | registry publish token>`.
|
|
46
|
+
*/
|
|
47
|
+
export declare const SKILL_HEADERS: {
|
|
48
|
+
/** Required: SRI `sha512-<base64>` of the body. */
|
|
49
|
+
readonly integrity: "X-Skill-Integrity";
|
|
50
|
+
/** Optional dist-tag to point at the new version (default `latest` for stable, none for prereleases). */
|
|
51
|
+
readonly tag: "X-Skill-Tag";
|
|
52
|
+
/** Optional base64(JSON {@link SkillReportedProvenance}); shown as "reported". */
|
|
53
|
+
readonly provenance: "X-Skill-Provenance";
|
|
54
|
+
/** Optional GitHub Actions OIDC token (audience {@link SKILLS_OIDC_AUDIENCE}); verified server-side. */
|
|
55
|
+
readonly githubOidc: "X-Skill-GitHub-OIDC";
|
|
56
|
+
};
|
|
57
|
+
/** Audience CI must request for GitHub Actions OIDC tokens. */
|
|
58
|
+
export declare const SKILLS_OIDC_AUDIENCE = "skills.omp.sh";
|
|
59
|
+
/** Env var holding a registry publish token for CI (`sks_…`); wins over the Stencil login. */
|
|
60
|
+
export declare const SKILLS_TOKEN_ENV = "SKILLS_TOKEN";
|
|
61
|
+
/** Public identity of an account: current username + avatar seed (hash of the immutable sub). */
|
|
62
|
+
export interface SkillUser {
|
|
63
|
+
username: string;
|
|
64
|
+
/** Hex seed for the generated dither avatar; never the raw sub. */
|
|
65
|
+
avatar: string;
|
|
66
|
+
}
|
|
67
|
+
export interface SkillReportedProvenance {
|
|
68
|
+
ompVersion: string;
|
|
69
|
+
gitRemote?: string;
|
|
70
|
+
gitCommit?: string;
|
|
71
|
+
}
|
|
72
|
+
/** Provenance proven by a verified GitHub Actions OIDC token. */
|
|
73
|
+
export interface SkillVerifiedProvenance {
|
|
74
|
+
kind: "github-actions";
|
|
75
|
+
repository: string;
|
|
76
|
+
workflow: string;
|
|
77
|
+
ref: string;
|
|
78
|
+
sha: string;
|
|
79
|
+
runUrl: string;
|
|
80
|
+
}
|
|
81
|
+
export interface SkillProvenance {
|
|
82
|
+
publisher: SkillUser;
|
|
83
|
+
/** Publish came from a registry token rather than an interactive login. */
|
|
84
|
+
viaToken: boolean;
|
|
85
|
+
reported?: SkillReportedProvenance;
|
|
86
|
+
verified?: SkillVerifiedProvenance;
|
|
87
|
+
}
|
|
88
|
+
export interface SkillFile {
|
|
89
|
+
/** POSIX path relative to the skill root. */
|
|
90
|
+
path: string;
|
|
91
|
+
size: number;
|
|
92
|
+
/** Hex SHA-256 of the content. */
|
|
93
|
+
sha256: string;
|
|
94
|
+
executable: boolean;
|
|
95
|
+
}
|
|
96
|
+
/** One version as listed in a packument. */
|
|
97
|
+
export interface SkillVersionSummary {
|
|
98
|
+
version: string;
|
|
99
|
+
publishedAt: number;
|
|
100
|
+
publisher: SkillUser;
|
|
101
|
+
integrity: string;
|
|
102
|
+
size: number;
|
|
103
|
+
unpackedSize: number;
|
|
104
|
+
fileCount: number;
|
|
105
|
+
/** Ships executables or anything under `scripts/`. */
|
|
106
|
+
hasScripts: boolean;
|
|
107
|
+
yanked: boolean;
|
|
108
|
+
deprecated?: string;
|
|
109
|
+
}
|
|
110
|
+
/** Daily download counts, oldest first: `[YYYY-MM-DD, count]`. */
|
|
111
|
+
export type SkillDownloadSeries = [day: string, count: number][];
|
|
112
|
+
/** `GET SKILLS_ROUTES.packument`: everything about a package. */
|
|
113
|
+
export interface SkillPackument {
|
|
114
|
+
scope: string;
|
|
115
|
+
name: string;
|
|
116
|
+
/** From the `latest` version. */
|
|
117
|
+
description: string;
|
|
118
|
+
keywords: string[];
|
|
119
|
+
license?: string;
|
|
120
|
+
repository?: string;
|
|
121
|
+
homepage?: string;
|
|
122
|
+
owners: SkillUser[];
|
|
123
|
+
/** e.g. `{ latest: "1.2.0", next: "2.0.0-beta.1" }`. */
|
|
124
|
+
distTags: Record<string, string>;
|
|
125
|
+
versions: Record<string, SkillVersionSummary>;
|
|
126
|
+
createdAt: number;
|
|
127
|
+
updatedAt: number;
|
|
128
|
+
downloads: {
|
|
129
|
+
weekly: number;
|
|
130
|
+
total: number;
|
|
131
|
+
daily: SkillDownloadSeries;
|
|
132
|
+
};
|
|
133
|
+
/** Signed-in viewer may publish, tag, yank, deprecate, and manage owners. */
|
|
134
|
+
canManage: boolean;
|
|
135
|
+
}
|
|
136
|
+
/** `GET SKILLS_ROUTES.version`: one immutable version. `:version` may be a dist-tag. */
|
|
137
|
+
export interface SkillVersionManifest extends SkillVersionSummary {
|
|
138
|
+
scope: string;
|
|
139
|
+
name: string;
|
|
140
|
+
description: string;
|
|
141
|
+
license?: string;
|
|
142
|
+
compatibility?: string;
|
|
143
|
+
allowedTools?: string;
|
|
144
|
+
/** SKILL.md `metadata` verbatim. */
|
|
145
|
+
metadata: Record<string, string>;
|
|
146
|
+
keywords: string[];
|
|
147
|
+
repository?: string;
|
|
148
|
+
homepage?: string;
|
|
149
|
+
files: SkillFile[];
|
|
150
|
+
/** Package path rendered as the README (`README.md` if present, else `SKILL.md`). */
|
|
151
|
+
readmePath: string;
|
|
152
|
+
provenance: SkillProvenance;
|
|
153
|
+
}
|
|
154
|
+
/** `GET SKILLS_ROUTES.readme`: sanitized HTML rendered at publish time. */
|
|
155
|
+
export interface SkillReadme {
|
|
156
|
+
html: string;
|
|
157
|
+
}
|
|
158
|
+
/** `GET SKILLS_ROUTES.source`: one file for the code viewer. */
|
|
159
|
+
export interface SkillSource {
|
|
160
|
+
path: string;
|
|
161
|
+
size: number;
|
|
162
|
+
/** Binary or over the view limit: no `html`, offer `SKILLS_ROUTES.file` instead. */
|
|
163
|
+
binary: boolean;
|
|
164
|
+
tooLarge: boolean;
|
|
165
|
+
/** Server-highlighted, sanitized HTML: one `<span class="line">` per line. */
|
|
166
|
+
html?: string;
|
|
167
|
+
lines?: number;
|
|
168
|
+
}
|
|
169
|
+
export interface SkillSearchHit {
|
|
170
|
+
scope: string;
|
|
171
|
+
name: string;
|
|
172
|
+
description: string;
|
|
173
|
+
keywords: string[];
|
|
174
|
+
version: string;
|
|
175
|
+
publisher: SkillUser;
|
|
176
|
+
updatedAt: number;
|
|
177
|
+
weeklyDownloads: number;
|
|
178
|
+
deprecated?: string;
|
|
179
|
+
}
|
|
180
|
+
export type SkillSearchSort = "relevance" | "downloads" | "recent";
|
|
181
|
+
/** `GET SKILLS_ROUTES.search?q=&sort=&page=`. `q` accepts `owner:<scope>` and `keyword:<kw>` filters. */
|
|
182
|
+
export interface SkillSearchResponse {
|
|
183
|
+
total: number;
|
|
184
|
+
page: number;
|
|
185
|
+
perPage: number;
|
|
186
|
+
hits: SkillSearchHit[];
|
|
187
|
+
}
|
|
188
|
+
/** `GET SKILLS_ROUTES.home`. */
|
|
189
|
+
export interface SkillHome {
|
|
190
|
+
stats: {
|
|
191
|
+
packages: number;
|
|
192
|
+
versions: number;
|
|
193
|
+
publishers: number;
|
|
194
|
+
weeklyDownloads: number;
|
|
195
|
+
};
|
|
196
|
+
recent: SkillSearchHit[];
|
|
197
|
+
popular: SkillSearchHit[];
|
|
198
|
+
trending: SkillSearchHit[];
|
|
199
|
+
keywords: [keyword: string, count: number][];
|
|
200
|
+
}
|
|
201
|
+
/** `GET SKILLS_ROUTES.user`: a user or org scope page. */
|
|
202
|
+
export interface SkillProfile {
|
|
203
|
+
user: SkillUser;
|
|
204
|
+
kind: "user" | "org";
|
|
205
|
+
scopes: string[];
|
|
206
|
+
packages: SkillSearchHit[];
|
|
207
|
+
/** Orgs only. */
|
|
208
|
+
members?: {
|
|
209
|
+
user: SkillUser;
|
|
210
|
+
role: SkillOrgRole;
|
|
211
|
+
}[];
|
|
212
|
+
}
|
|
213
|
+
export type SkillOrgRole = "owner" | "member";
|
|
214
|
+
export interface SkillPublishResponse {
|
|
215
|
+
scope: string;
|
|
216
|
+
name: string;
|
|
217
|
+
version: string;
|
|
218
|
+
integrity: string;
|
|
219
|
+
/** Package page. */
|
|
220
|
+
url: string;
|
|
221
|
+
/** Dist-tags now pointing at this version. */
|
|
222
|
+
tags: string[];
|
|
223
|
+
}
|
|
224
|
+
/** Registry publish token (CI). The secret is shown once, at creation. */
|
|
225
|
+
export interface SkillToken {
|
|
226
|
+
id: string;
|
|
227
|
+
name: string;
|
|
228
|
+
/** `@scope/name` packages the token may publish; empty = all packages the creator manages. */
|
|
229
|
+
packages: string[];
|
|
230
|
+
createdAt: number;
|
|
231
|
+
expiresAt?: number;
|
|
232
|
+
lastUsedAt?: number;
|
|
233
|
+
}
|
|
234
|
+
export interface SkillTokenCreated extends SkillToken {
|
|
235
|
+
/** `sks_…`; never retrievable again. */
|
|
236
|
+
token: string;
|
|
237
|
+
}
|
|
238
|
+
/** `GET SKILLS_ROUTES.me`. */
|
|
239
|
+
export interface SkillSession {
|
|
240
|
+
user: SkillUser | null;
|
|
241
|
+
/** Sign-in is configured on this server. */
|
|
242
|
+
login: boolean;
|
|
243
|
+
admin: boolean;
|
|
244
|
+
}
|
|
245
|
+
/** Error body of every non-2xx JSON response. */
|
|
246
|
+
export interface SkillError {
|
|
247
|
+
error: string;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* HTTP routes, relative to the registry base URL. Mutations with a JSON body
|
|
251
|
+
* use the documented request shapes:
|
|
252
|
+
* - `tag` PUT `{ version }`, DELETE to remove (never `latest`)
|
|
253
|
+
* - `yank` POST `{ yanked: boolean }`
|
|
254
|
+
* - `deprecate` POST `{ message: string | null }`
|
|
255
|
+
* - `owner` PUT / DELETE (no body)
|
|
256
|
+
* - `tokens` POST `{ name, packages?: string[], expiresInDays?: number }`
|
|
257
|
+
* - `report` POST `{ reason: string }`
|
|
258
|
+
* - `takedown` POST `{ reason: string }` (admins)
|
|
259
|
+
* - `orgs` POST `{ name }`; `orgMember` PUT `{ role }` / DELETE
|
|
260
|
+
* - `importSkill` POST body = Claude `.skill` zip (bearer) → {@link SkillPublishResponse}
|
|
261
|
+
*/
|
|
262
|
+
export declare const SKILLS_ROUTES: {
|
|
263
|
+
readonly home: "/api/v1/home";
|
|
264
|
+
readonly search: "/api/v1/search";
|
|
265
|
+
readonly packument: (scope: string, name: string) => string;
|
|
266
|
+
readonly version: (scope: string, name: string, version: string) => string;
|
|
267
|
+
readonly readme: (scope: string, name: string, version: string) => string;
|
|
268
|
+
/** 302 to a signed R2 link; counts one download. */
|
|
269
|
+
readonly tarball: (scope: string, name: string, version: string) => string;
|
|
270
|
+
/** Raw file, same-origin: text as text/plain, sniffed raster images inline, everything else as an attachment. */
|
|
271
|
+
readonly file: (scope: string, name: string, version: string, path: string) => string;
|
|
272
|
+
readonly source: (scope: string, name: string, version: string, path: string) => string;
|
|
273
|
+
readonly publish: (scope: string, name: string, version: string) => string;
|
|
274
|
+
readonly tag: (scope: string, name: string, tag: string) => string;
|
|
275
|
+
readonly yank: (scope: string, name: string, version: string) => string;
|
|
276
|
+
readonly deprecate: (scope: string, name: string, version: string) => string;
|
|
277
|
+
readonly owner: (scope: string, name: string, username: string) => string;
|
|
278
|
+
readonly report: (scope: string, name: string) => string;
|
|
279
|
+
readonly takedown: (scope: string, name: string) => string;
|
|
280
|
+
readonly user: (username: string) => string;
|
|
281
|
+
readonly tokens: "/api/v1/tokens";
|
|
282
|
+
readonly token: (id: string) => string;
|
|
283
|
+
readonly orgs: "/api/v1/orgs";
|
|
284
|
+
readonly orgMember: (org: string, username: string) => string;
|
|
285
|
+
readonly importSkill: "/api/v1/import";
|
|
286
|
+
readonly me: "/api/me";
|
|
287
|
+
/** Web pages. */
|
|
288
|
+
readonly pages: {
|
|
289
|
+
readonly package: (scope: string, name: string) => string;
|
|
290
|
+
readonly user: (username: string) => string;
|
|
291
|
+
readonly search: (query: string) => string;
|
|
292
|
+
};
|
|
293
|
+
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for Skillshare (`skills.omp.sh`): an npm-style registry for
|
|
3
|
+
* omp skills. Shared by the omp CLI (`omp skill …`), the Go server
|
|
4
|
+
* (`stencil/apps/skills`), and its web UI (which mirrors this file).
|
|
5
|
+
*
|
|
6
|
+
* Packages are scoped: `@scope/name`. A scope is a Stencil username claimed on
|
|
7
|
+
* first publish and bound to the account's immutable `sub` forever (usernames
|
|
8
|
+
* can be renamed and recycled; scopes cannot). `name` is the SKILL.md
|
|
9
|
+
* frontmatter `name`. Published versions are immutable.
|
|
10
|
+
*
|
|
11
|
+
* Registry fields ride in SKILL.md `metadata` (the Agent Skills frontmatter is
|
|
12
|
+
* closed to name/description/license/compatibility/metadata/allowed-tools):
|
|
13
|
+
* `metadata.version` (semver, required to publish), `metadata.keywords`
|
|
14
|
+
* (comma-separated), `metadata.repository`, `metadata.homepage`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Default registry; `skills.registryUrl` overrides it. */
|
|
18
|
+
export const DEFAULT_SKILLS_URL = "https://skills.omp.sh";
|
|
19
|
+
|
|
20
|
+
/** Scopes are Stencil usernames (or registry orgs): lowercase letters, digits, underscores; 3–32 chars. */
|
|
21
|
+
export const SKILL_SCOPE_RE = /^[a-z0-9][a-z0-9_]{2,31}$/;
|
|
22
|
+
/** Registry skill names: ASCII kebab-case, 1–64 chars, no leading/trailing/double hyphens. */
|
|
23
|
+
export const SKILL_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
24
|
+
export const SKILL_NAME_MAX = 64;
|
|
25
|
+
/** `@scope/name`, optionally `@version-or-range-or-tag`. */
|
|
26
|
+
export const SKILL_SPEC_RE = /^@([a-z0-9][a-z0-9_]{2,31})\/([a-z0-9]+(?:-[a-z0-9]+)*)(?:@(.+))?$/;
|
|
27
|
+
|
|
28
|
+
/** Publish limits, enforced by both the CLI and the server. */
|
|
29
|
+
export const SKILL_LIMITS = {
|
|
30
|
+
/** Compressed `.tgz` upload. */
|
|
31
|
+
tarballBytes: 5 * 1024 * 1024,
|
|
32
|
+
/** Sum of all file sizes after unpacking. */
|
|
33
|
+
unpackedBytes: 20 * 1024 * 1024,
|
|
34
|
+
files: 1000,
|
|
35
|
+
/** Longest path inside the package. */
|
|
36
|
+
pathLength: 255,
|
|
37
|
+
descriptionLength: 1024,
|
|
38
|
+
keywords: 20,
|
|
39
|
+
keywordLength: 50,
|
|
40
|
+
deprecationLength: 500,
|
|
41
|
+
} as const;
|
|
42
|
+
|
|
43
|
+
/** Paths excluded from packs in addition to `.skillignore` entries. */
|
|
44
|
+
export const SKILL_DEFAULT_IGNORES = [
|
|
45
|
+
".git",
|
|
46
|
+
".DS_Store",
|
|
47
|
+
"node_modules",
|
|
48
|
+
"__pycache__",
|
|
49
|
+
"*.pyc",
|
|
50
|
+
"evals",
|
|
51
|
+
".skillignore",
|
|
52
|
+
] as const;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Publish request: `PUT SKILLS_ROUTES.publish(scope, name, version)`, body is
|
|
56
|
+
* the `.tgz` (gzip tar; entries are paths relative to the skill root, regular
|
|
57
|
+
* files only, sorted, mtime 0, mode 0644 or 0755). Auth: `Authorization:
|
|
58
|
+
* Bearer <Stencil access token | registry publish token>`.
|
|
59
|
+
*/
|
|
60
|
+
export const SKILL_HEADERS = {
|
|
61
|
+
/** Required: SRI `sha512-<base64>` of the body. */
|
|
62
|
+
integrity: "X-Skill-Integrity",
|
|
63
|
+
/** Optional dist-tag to point at the new version (default `latest` for stable, none for prereleases). */
|
|
64
|
+
tag: "X-Skill-Tag",
|
|
65
|
+
/** Optional base64(JSON {@link SkillReportedProvenance}); shown as "reported". */
|
|
66
|
+
provenance: "X-Skill-Provenance",
|
|
67
|
+
/** Optional GitHub Actions OIDC token (audience {@link SKILLS_OIDC_AUDIENCE}); verified server-side. */
|
|
68
|
+
githubOidc: "X-Skill-GitHub-OIDC",
|
|
69
|
+
} as const;
|
|
70
|
+
|
|
71
|
+
/** Audience CI must request for GitHub Actions OIDC tokens. */
|
|
72
|
+
export const SKILLS_OIDC_AUDIENCE = "skills.omp.sh";
|
|
73
|
+
|
|
74
|
+
/** Env var holding a registry publish token for CI (`sks_…`); wins over the Stencil login. */
|
|
75
|
+
export const SKILLS_TOKEN_ENV = "SKILLS_TOKEN";
|
|
76
|
+
|
|
77
|
+
/** Public identity of an account: current username + avatar seed (hash of the immutable sub). */
|
|
78
|
+
export interface SkillUser {
|
|
79
|
+
username: string;
|
|
80
|
+
/** Hex seed for the generated dither avatar; never the raw sub. */
|
|
81
|
+
avatar: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface SkillReportedProvenance {
|
|
85
|
+
ompVersion: string;
|
|
86
|
+
gitRemote?: string;
|
|
87
|
+
gitCommit?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Provenance proven by a verified GitHub Actions OIDC token. */
|
|
91
|
+
export interface SkillVerifiedProvenance {
|
|
92
|
+
kind: "github-actions";
|
|
93
|
+
repository: string;
|
|
94
|
+
workflow: string;
|
|
95
|
+
ref: string;
|
|
96
|
+
sha: string;
|
|
97
|
+
runUrl: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface SkillProvenance {
|
|
101
|
+
publisher: SkillUser;
|
|
102
|
+
/** Publish came from a registry token rather than an interactive login. */
|
|
103
|
+
viaToken: boolean;
|
|
104
|
+
reported?: SkillReportedProvenance;
|
|
105
|
+
verified?: SkillVerifiedProvenance;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface SkillFile {
|
|
109
|
+
/** POSIX path relative to the skill root. */
|
|
110
|
+
path: string;
|
|
111
|
+
size: number;
|
|
112
|
+
/** Hex SHA-256 of the content. */
|
|
113
|
+
sha256: string;
|
|
114
|
+
executable: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** One version as listed in a packument. */
|
|
118
|
+
export interface SkillVersionSummary {
|
|
119
|
+
version: string;
|
|
120
|
+
publishedAt: number;
|
|
121
|
+
publisher: SkillUser;
|
|
122
|
+
integrity: string;
|
|
123
|
+
size: number;
|
|
124
|
+
unpackedSize: number;
|
|
125
|
+
fileCount: number;
|
|
126
|
+
/** Ships executables or anything under `scripts/`. */
|
|
127
|
+
hasScripts: boolean;
|
|
128
|
+
yanked: boolean;
|
|
129
|
+
deprecated?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Daily download counts, oldest first: `[YYYY-MM-DD, count]`. */
|
|
133
|
+
export type SkillDownloadSeries = [day: string, count: number][];
|
|
134
|
+
|
|
135
|
+
/** `GET SKILLS_ROUTES.packument`: everything about a package. */
|
|
136
|
+
export interface SkillPackument {
|
|
137
|
+
scope: string;
|
|
138
|
+
name: string;
|
|
139
|
+
/** From the `latest` version. */
|
|
140
|
+
description: string;
|
|
141
|
+
keywords: string[];
|
|
142
|
+
license?: string;
|
|
143
|
+
repository?: string;
|
|
144
|
+
homepage?: string;
|
|
145
|
+
owners: SkillUser[];
|
|
146
|
+
/** e.g. `{ latest: "1.2.0", next: "2.0.0-beta.1" }`. */
|
|
147
|
+
distTags: Record<string, string>;
|
|
148
|
+
versions: Record<string, SkillVersionSummary>;
|
|
149
|
+
createdAt: number;
|
|
150
|
+
updatedAt: number;
|
|
151
|
+
downloads: { weekly: number; total: number; daily: SkillDownloadSeries };
|
|
152
|
+
/** Signed-in viewer may publish, tag, yank, deprecate, and manage owners. */
|
|
153
|
+
canManage: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** `GET SKILLS_ROUTES.version`: one immutable version. `:version` may be a dist-tag. */
|
|
157
|
+
export interface SkillVersionManifest extends SkillVersionSummary {
|
|
158
|
+
scope: string;
|
|
159
|
+
name: string;
|
|
160
|
+
description: string;
|
|
161
|
+
license?: string;
|
|
162
|
+
compatibility?: string;
|
|
163
|
+
allowedTools?: string;
|
|
164
|
+
/** SKILL.md `metadata` verbatim. */
|
|
165
|
+
metadata: Record<string, string>;
|
|
166
|
+
keywords: string[];
|
|
167
|
+
repository?: string;
|
|
168
|
+
homepage?: string;
|
|
169
|
+
files: SkillFile[];
|
|
170
|
+
/** Package path rendered as the README (`README.md` if present, else `SKILL.md`). */
|
|
171
|
+
readmePath: string;
|
|
172
|
+
provenance: SkillProvenance;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** `GET SKILLS_ROUTES.readme`: sanitized HTML rendered at publish time. */
|
|
176
|
+
export interface SkillReadme {
|
|
177
|
+
html: string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** `GET SKILLS_ROUTES.source`: one file for the code viewer. */
|
|
181
|
+
export interface SkillSource {
|
|
182
|
+
path: string;
|
|
183
|
+
size: number;
|
|
184
|
+
/** Binary or over the view limit: no `html`, offer `SKILLS_ROUTES.file` instead. */
|
|
185
|
+
binary: boolean;
|
|
186
|
+
tooLarge: boolean;
|
|
187
|
+
/** Server-highlighted, sanitized HTML: one `<span class="line">` per line. */
|
|
188
|
+
html?: string;
|
|
189
|
+
lines?: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface SkillSearchHit {
|
|
193
|
+
scope: string;
|
|
194
|
+
name: string;
|
|
195
|
+
description: string;
|
|
196
|
+
keywords: string[];
|
|
197
|
+
version: string;
|
|
198
|
+
publisher: SkillUser;
|
|
199
|
+
updatedAt: number;
|
|
200
|
+
weeklyDownloads: number;
|
|
201
|
+
deprecated?: string;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export type SkillSearchSort = "relevance" | "downloads" | "recent";
|
|
205
|
+
|
|
206
|
+
/** `GET SKILLS_ROUTES.search?q=&sort=&page=`. `q` accepts `owner:<scope>` and `keyword:<kw>` filters. */
|
|
207
|
+
export interface SkillSearchResponse {
|
|
208
|
+
total: number;
|
|
209
|
+
page: number;
|
|
210
|
+
perPage: number;
|
|
211
|
+
hits: SkillSearchHit[];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** `GET SKILLS_ROUTES.home`. */
|
|
215
|
+
export interface SkillHome {
|
|
216
|
+
stats: { packages: number; versions: number; publishers: number; weeklyDownloads: number };
|
|
217
|
+
recent: SkillSearchHit[];
|
|
218
|
+
popular: SkillSearchHit[];
|
|
219
|
+
trending: SkillSearchHit[];
|
|
220
|
+
keywords: [keyword: string, count: number][];
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** `GET SKILLS_ROUTES.user`: a user or org scope page. */
|
|
224
|
+
export interface SkillProfile {
|
|
225
|
+
user: SkillUser;
|
|
226
|
+
kind: "user" | "org";
|
|
227
|
+
scopes: string[];
|
|
228
|
+
packages: SkillSearchHit[];
|
|
229
|
+
/** Orgs only. */
|
|
230
|
+
members?: { user: SkillUser; role: SkillOrgRole }[];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export type SkillOrgRole = "owner" | "member";
|
|
234
|
+
|
|
235
|
+
export interface SkillPublishResponse {
|
|
236
|
+
scope: string;
|
|
237
|
+
name: string;
|
|
238
|
+
version: string;
|
|
239
|
+
integrity: string;
|
|
240
|
+
/** Package page. */
|
|
241
|
+
url: string;
|
|
242
|
+
/** Dist-tags now pointing at this version. */
|
|
243
|
+
tags: string[];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** Registry publish token (CI). The secret is shown once, at creation. */
|
|
247
|
+
export interface SkillToken {
|
|
248
|
+
id: string;
|
|
249
|
+
name: string;
|
|
250
|
+
/** `@scope/name` packages the token may publish; empty = all packages the creator manages. */
|
|
251
|
+
packages: string[];
|
|
252
|
+
createdAt: number;
|
|
253
|
+
expiresAt?: number;
|
|
254
|
+
lastUsedAt?: number;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export interface SkillTokenCreated extends SkillToken {
|
|
258
|
+
/** `sks_…`; never retrievable again. */
|
|
259
|
+
token: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** `GET SKILLS_ROUTES.me`. */
|
|
263
|
+
export interface SkillSession {
|
|
264
|
+
user: SkillUser | null;
|
|
265
|
+
/** Sign-in is configured on this server. */
|
|
266
|
+
login: boolean;
|
|
267
|
+
admin: boolean;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/** Error body of every non-2xx JSON response. */
|
|
271
|
+
export interface SkillError {
|
|
272
|
+
error: string;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const pkg = (scope: string, name: string) => `/api/v1/skills/@${scope}/${name}`;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* HTTP routes, relative to the registry base URL. Mutations with a JSON body
|
|
279
|
+
* use the documented request shapes:
|
|
280
|
+
* - `tag` PUT `{ version }`, DELETE to remove (never `latest`)
|
|
281
|
+
* - `yank` POST `{ yanked: boolean }`
|
|
282
|
+
* - `deprecate` POST `{ message: string | null }`
|
|
283
|
+
* - `owner` PUT / DELETE (no body)
|
|
284
|
+
* - `tokens` POST `{ name, packages?: string[], expiresInDays?: number }`
|
|
285
|
+
* - `report` POST `{ reason: string }`
|
|
286
|
+
* - `takedown` POST `{ reason: string }` (admins)
|
|
287
|
+
* - `orgs` POST `{ name }`; `orgMember` PUT `{ role }` / DELETE
|
|
288
|
+
* - `importSkill` POST body = Claude `.skill` zip (bearer) → {@link SkillPublishResponse}
|
|
289
|
+
*/
|
|
290
|
+
export const SKILLS_ROUTES = {
|
|
291
|
+
home: "/api/v1/home",
|
|
292
|
+
search: "/api/v1/search",
|
|
293
|
+
packument: (scope: string, name: string) => pkg(scope, name),
|
|
294
|
+
version: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}`,
|
|
295
|
+
readme: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}/readme`,
|
|
296
|
+
/** 302 to a signed R2 link; counts one download. */
|
|
297
|
+
tarball: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}/tarball`,
|
|
298
|
+
/** Raw file, same-origin: text as text/plain, sniffed raster images inline, everything else as an attachment. */
|
|
299
|
+
file: (scope: string, name: string, version: string, path: string) =>
|
|
300
|
+
`${pkg(scope, name)}/versions/${version}/files/${path}`,
|
|
301
|
+
source: (scope: string, name: string, version: string, path: string) =>
|
|
302
|
+
`${pkg(scope, name)}/versions/${version}/source/${path}`,
|
|
303
|
+
publish: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}`,
|
|
304
|
+
tag: (scope: string, name: string, tag: string) => `${pkg(scope, name)}/tags/${tag}`,
|
|
305
|
+
yank: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}/yank`,
|
|
306
|
+
deprecate: (scope: string, name: string, version: string) => `${pkg(scope, name)}/versions/${version}/deprecate`,
|
|
307
|
+
owner: (scope: string, name: string, username: string) => `${pkg(scope, name)}/owners/${username}`,
|
|
308
|
+
report: (scope: string, name: string) => `${pkg(scope, name)}/report`,
|
|
309
|
+
takedown: (scope: string, name: string) => `/api/v1/admin/skills/@${scope}/${name}/takedown`,
|
|
310
|
+
user: (username: string) => `/api/v1/users/${username}`,
|
|
311
|
+
tokens: "/api/v1/tokens",
|
|
312
|
+
token: (id: string) => `/api/v1/tokens/${id}`,
|
|
313
|
+
orgs: "/api/v1/orgs",
|
|
314
|
+
orgMember: (org: string, username: string) => `/api/v1/orgs/${org}/members/${username}`,
|
|
315
|
+
importSkill: "/api/v1/import",
|
|
316
|
+
me: "/api/me",
|
|
317
|
+
/** Web pages. */
|
|
318
|
+
pages: {
|
|
319
|
+
package: (scope: string, name: string) => `/@${scope}/${name}`,
|
|
320
|
+
user: (username: string) => `/~${username}`,
|
|
321
|
+
search: (query: string) => `/search?q=${encodeURIComponent(query)}`,
|
|
322
|
+
},
|
|
323
|
+
} as const;
|