@intentic/registry 1.222.0 → 1.224.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/registry",
3
- "version": "1.222.0",
3
+ "version": "1.224.0",
4
4
  "description": "The extension-registry file format — a git repo of sha-pinned pointers, shared by the daemon, the site gallery and the scanner",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/registry.ts CHANGED
@@ -4,15 +4,15 @@ import { type RegistryInstall, RegistryInstallSchema, resolveSource } from "./so
4
4
  /* THE EXTENSION REGISTRY: a git repo of pointers, and the two files in it.
5
5
  *
6
6
  * intentic hosts no extension code, builds none, and signs none. A registry is a repository whose
7
- * `.claude-plugin/marketplace.json` lists pointers to other people's repositories at a commit — so listing
7
+ * `.claude-plugin/marketplace.json` lists pointers to other people's repositories at a commit, so listing
8
8
  * costs a pull request, delisting deletes nothing, and anybody can run their own registry against a private
9
9
  * one. That file is Claude Code's plugin-marketplace format deliberately: `kind` and `trust` are intentic's
10
10
  * own fields and Claude Code ignores what it doesn't know, so one repo serves both consumers.
11
11
  *
12
- * The split into TWO files is the load-bearing part. `marketplace.json` is hand-edited and is the only place a
12
+ * The split into TWO files is the part that matters. `marketplace.json` is hand-edited and is the only place a
13
13
  * curated decision and source-bound admission are recorded; `registry.generated.json` is bot-written and holds
14
14
  * nothing but facts read back off the source host. Keeping star counts out of the curated file is what stops every nightly refresh from
15
- * being a merge conflict against an open pull request — and it keeps the review diff to the thing being
15
+ * being a merge conflict against an open pull request, and it keeps the review diff to the thing being
16
16
  * decided. A registry that carries no generated file is a registry with no stars, which renders fine. */
17
17
 
18
18
  // Repo-relative, and the same two strings for the daemon (which clones), the scanner (which commits) and the
@@ -24,7 +24,7 @@ export const REGISTRY_FACTS_FILE = ".claude-plugin/registry.generated.json";
24
24
  // field stays editable, so a company points it at an internal registry and never touches this one.
25
25
  export const OFFICIAL_REGISTRY_URL = "https://github.com/intentic/registry";
26
26
 
27
- // The GitHub topic an author adds to be found. This is discovery only — appearing in the scan gets you a pull
27
+ // The GitHub topic an author adds to be found. This is discovery only, appearing in the scan gets you a pull
28
28
  // request against the registry, never a listing.
29
29
  export const REGISTRY_TOPIC = "intentic-extension";
30
30
 
@@ -65,7 +65,7 @@ export type RegistrySecurityReview = z.infer<typeof RegistrySecurityReviewSchema
65
65
  * - `verified` both automated checks passed and a human also read the source at that sha. Sorted first and badged.
66
66
  * - `blocked` known-malicious or known-broken. It STAYS in the file with a reason rather than being deleted:
67
67
  * removing the row hides it from people browsing and tells the people who already installed it
68
- * nothing, which is backwards — they are the ones at risk.
68
+ * nothing, which is backwards, they are the ones at risk.
69
69
  *
70
70
  * Absent on a third-party registry ⇒ `listed`, because a registry that doesn't use the field hasn't asserted
71
71
  * anything and shouldn't be read as if it had. */
@@ -74,10 +74,10 @@ export type RegistryTrust = z.infer<typeof RegistryTrustSchema>;
74
74
 
75
75
  /* WHAT A LISTING COSTS. `free` is the default and the whole story for most rows. `premium` opts the listing
76
76
  * into the creator pool: installing it requires an intentic membership and donates a published number of the
77
- * member's credits to the publisher (once, deduped monthly — an update in a later month donates again), and
77
+ * member's credits to the publisher (once, deduped monthly, an update in a later month donates again), and
78
78
  * both surfaces badge it so the price is visible before the click. No usage is ever metered or reported for
79
79
  * this; the deliberate act of installing is the whole signal. On a third-party registry the field still
80
- * parses but means nothing — the pool only pays listings the platform's members actually install. */
80
+ * parses but means nothing, the pool only pays listings the platform's members actually install. */
81
81
  export const RegistryTierSchema = z.enum(["free", "premium"]);
82
82
  export type RegistryTier = z.infer<typeof RegistryTierSchema>;
83
83
 
@@ -89,27 +89,27 @@ const RegistryFileEntrySchema = z
89
89
  // "extension" installs as the sha-pinned `extension` capability; absent/"plugin" is a Claude Code plugin.
90
90
  kind: z.enum(["plugin", "extension"]).optional(),
91
91
  trust: RegistryTrustSchema.optional(),
92
- // Why it is blocked, or what was checked to verify it — shown verbatim wherever the badge is, because a
92
+ // Why it is blocked, or what was checked to verify it, shown verbatim wherever the badge is, because a
93
93
  // trust state with no stated reason is an opinion the reader can't weigh.
94
94
  trustReason: z.string().optional(),
95
95
  // Both automated checks' evidence, bound to the complete source identity below. It is deliberately
96
96
  // distinct from `trust: verified`: passing admission admits code; verified additionally says a human
97
97
  // read it. Keeping those claims apart stops automated verdicts being presented as human review.
98
98
  securityReview: RegistrySecurityReviewSchema.optional(),
99
- // This listing's pinned commit fixes a security problem in earlier commits — the fast lane: an installed
99
+ // This listing's pinned commit fixes a security problem in earlier commits, the fast lane: an installed
100
100
  // sandbox promotes its "update available" badge from ambient to attention-demanding, because there the OLD
101
101
  // version is the dangerous one. Asserted by the pull request like trust, and worth exactly that review.
102
102
  securityFix: z.boolean().optional(),
103
103
  tier: RegistryTierSchema.optional(),
104
104
  category: z.string().optional(),
105
105
  /* The mark the row is drawn with, copied off the extension's manifest exactly like the description and
106
- * the version — the same three tiers the manifest declares (the author's own inline drawing, then a
106
+ * the version, the same three tiers the manifest declares (the author's own inline drawing, then a
107
107
  * simple-icons slug, then a name from the app's icon set), and none is required.
108
108
  *
109
109
  * It rides the CURATED file rather than the generated one, which looks wrong for a derived value until you
110
110
  * ask what a registry is for: a listing is what a human decided to publish, and the mark is part of how it
111
111
  * presents itself, so it belongs in the row a reviewer reads and can strike out. The generated file holds
112
- * only what a bot re-reads nightly and nobody reviews. It also has to be here to be of any use at all —
112
+ * only what a bot re-reads nightly and nobody reviews. It also has to be here to be of any use at all,
113
113
  * this is what the gallery and the in-app browse list render, and neither of them has the manifest: the
114
114
  * whole point of the row is that the code has NOT been cloned yet.
115
115
  *
@@ -166,15 +166,15 @@ export type RegistryFile = z.infer<typeof RegistryFileSchema>;
166
166
  /* Facts read off the source host, keyed by the curated entry's name. Deliberately NOT the upstream head sha:
167
167
  * the approved sha is the one that runs, updating is a pull request, and a file that advertised "there's a
168
168
  * newer commit over there" would be inviting a click that skips the review the whole model rests on. */
169
- /* What the scan re-derived COLD at the listing's pinned sha — the same questions the daemon's readiness check
169
+ /* What the scan re-derived COLD at the listing's pinned sha, the same questions the daemon's readiness check
170
170
  * answers for an author before publishing, asked again by a stranger with nothing but the pointer. That
171
171
  * re-derivation is the whole value: an author's own checks describe the directory they ran them in, and these
172
172
  * describe what an installer actually gets. `sha` binds the answers to the commit they were read from, so a
173
- * listing repointed since the last scan renders no stale verdicts — the join drops checks whose sha no longer
173
+ * listing repointed since the last scan renders no stale verdicts, the join drops checks whose sha no longer
174
174
  * matches rather than letting yesterday's answer describe today's pointer. */
175
175
  const RegistryChecksSchema = z.object({
176
176
  sha: z.string(),
177
- // "ok", or the reason it is not, verbatim — a verdict with no stated reason is an opinion.
177
+ // "ok", or the reason it is not, verbatim, a verdict with no stated reason is an opinion.
178
178
  manifest: z.string(),
179
179
  // "ok" / "none" (no UI bundle) / the reason the bundle cannot load where it is installed.
180
180
  bundle: z.string(),
@@ -187,7 +187,7 @@ export type RegistryChecks = z.infer<typeof RegistryChecksSchema>;
187
187
  const RegistryFactsEntrySchema = z.object({
188
188
  name: z.string(),
189
189
  stars: z.number().int().nonnegative().optional(),
190
- // ISO-8601, last push to the source repo's default branch — the tiebreaker that does the real work while
190
+ // ISO-8601, last push to the source repo's default branch, the tiebreaker that does the real work while
191
191
  // every listing still has single-digit stars.
192
192
  pushedAt: z.string().optional(),
193
193
  checks: RegistryChecksSchema.optional(),
@@ -200,7 +200,7 @@ export const RegistryFactsSchema = z.object({
200
200
  export type RegistryFacts = z.infer<typeof RegistryFactsSchema>;
201
201
 
202
202
  // One row as every surface consumes it: the curated decision, the resolved pointer, and the upstream facts,
203
- // already joined. This is also the daemon's browse wire shape — the app renders what the site renders.
203
+ // already joined. This is also the daemon's browse wire shape, the app renders what the site renders.
204
204
  export const RegistryEntrySchema = z.object({
205
205
  name: z.string(),
206
206
  description: z.string().optional(),
@@ -217,7 +217,7 @@ export const RegistryEntrySchema = z.object({
217
217
  securityFix: z.boolean().optional(),
218
218
  tier: RegistryTierSchema,
219
219
  category: z.string().optional(),
220
- // The mark, as the gallery and the app's browse list draw it — see the curated file's fields above.
220
+ // The mark, as the gallery and the app's browse list draw it, see the curated file's fields above.
221
221
  art: z.string().optional(),
222
222
  logo: z.string().optional(),
223
223
  icon: z.string().optional(),
@@ -265,7 +265,7 @@ export const isCurrentSecurityReview = (review: RegistrySecurityReview | undefin
265
265
  review.deterministic.version === OFFICIAL_DETERMINISTIC_SCANNER_VERSION;
266
266
 
267
267
  /* Join the curated file to the generated facts. `facts` is undefined for any registry that runs no scanner,
268
- * which is most of them — a private registry of six internal extensions wants the pointers and nothing else. */
268
+ * which is most of them, a private registry of six internal extensions wants the pointers and nothing else. */
269
269
  export const resolveRegistry = (file: RegistryFile, facts: RegistryFacts | undefined, registryUrl: string): RegistryEntry[] => {
270
270
  const byName = new Map(facts?.entries.map((entry) => [entry.name, entry]) ?? []);
271
271
  const official = isOfficialRegistryUrl(registryUrl);
@@ -295,7 +295,7 @@ export const resolveRegistry = (file: RegistryFile, facts: RegistryFacts | undef
295
295
  ...(install !== undefined ? { install } : {}),
296
296
  ...(upstream?.stars !== undefined ? { stars: upstream.stars } : {}),
297
297
  ...(upstream?.pushedAt !== undefined ? { pushedAt: upstream.pushedAt } : {}),
298
- // Only when derived from the sha this row still points at — a repointed listing renders no checks
298
+ // Only when derived from the sha this row still points at, a repointed listing renders no checks
299
299
  // until the next scan, which is the honest gap rather than yesterday's verdict on today's pointer.
300
300
  ...(upstream?.checks !== undefined && upstream.checks.sha === install?.ref ? { checks: upstream.checks } : {}),
301
301
  };
@@ -305,7 +305,7 @@ export const resolveRegistry = (file: RegistryFile, facts: RegistryFacts | undef
305
305
  /* THE ORDER, and why it isn't just stars.
306
306
  *
307
307
  * Stars are the obvious sort and the wrong one on day one: every listing will sit at nought to three of them
308
- * for months, so a pure star sort is a random order wearing a merit badge — and it is the single most
308
+ * for months, so a pure star sort is a random order wearing a merit badge, and it is the single most
309
309
  * purchasable number on GitHub. So: the one field a human actually asserted leads, stars rank within that,
310
310
  * and recency breaks the ties that will be the overwhelmingly common case early on. Stars stay VISIBLE
311
311
  * either way; a reader can weigh them, they just don't get to be the whole ranking. */
package/src/source.ts CHANGED
@@ -2,10 +2,10 @@ import { z } from "zod";
2
2
 
3
3
  /* WHERE A REGISTRY ENTRY'S CODE LIVES, and how that resolves to something cloneable.
4
4
  *
5
- * A registry never hosts code — an entry is a pointer to somebody else's repository at a commit. `source` is
5
+ * A registry never hosts code, an entry is a pointer to somebody else's repository at a commit. `source` is
6
6
  * that pointer in the shapes Claude Code's plugin-marketplace format already defines, so one registry repo
7
7
  * serves both consumers; `resolveSource` maps the shapes we can clone onto the url/ref/path a capability
8
- * install takes, and returns undefined for the ones we can't (npm, say) rather than dropping the entry —
8
+ * install takes, and returns undefined for the ones we can't (npm, say) rather than dropping the entry,
9
9
  * an entry that exists but can't be installed in a click is information, a missing row is a bug report. */
10
10
 
11
11
  // The resolved pointer: exactly the fields a plugin- or extension-capability install needs.
@@ -46,14 +46,14 @@ export const resolveSource = (source: unknown, registryUrl: string, pluginRoot:
46
46
 
47
47
  const FULL_SHA = /^[0-9a-f]{40}$/;
48
48
 
49
- /* Whether this pointer names one immutable commit. An EXTENSION install requires it — extension code runs
49
+ /* Whether this pointer names one immutable commit. An EXTENSION install requires it, extension code runs
50
50
  * trusted in the owner's browser, so the approved code and the running code have to be the same object, and a
51
51
  * branch name is a promise the upstream can break with a force-push. A registry entry that gives only a branch
52
52
  * is still listed and still readable; it just can't be a one-click install, which is the pressure that makes
53
53
  * authors pin. Plugins are laxer by design: they load into the agent, not the browser. */
54
54
  export const isShaPinned = (install: RegistryInstall | undefined): boolean => install?.ref !== undefined && FULL_SHA.test(install.ref);
55
55
 
56
- // `owner/repo` for a GitHub pointer — what the scanner keys upstream facts by, and what the gallery links to.
56
+ // `owner/repo` for a GitHub pointer, what the scanner keys upstream facts by, and what the gallery links to.
57
57
  // Undefined for any host that isn't GitHub, which is a listing we simply carry no stars for.
58
58
  export const githubRepoOf = (install: RegistryInstall | undefined): string | undefined => {
59
59
  if (install === undefined) {