@intentic/registry 1.224.0 → 1.225.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/README.md +16 -16
- package/package.json +2 -2
- package/src/registry.test.ts +2 -2
- package/src/source.test.ts +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @intentic/registry
|
|
2
2
|
|
|
3
|
-
The **extension-registry file format
|
|
3
|
+
The **extension-registry file format**: what a registry repo contains, how its two files join, and the order
|
|
4
4
|
the result is shown in. Published to npm, and depended on by three otherwise-unrelated consumers, which is the
|
|
5
5
|
whole reason it is a package: the daemon that clones a registry, the site that builds the public gallery, and
|
|
6
6
|
the [scanner](../../_tools/registry-scan) that writes the files. One zod schema instead of three that drift.
|
|
@@ -10,7 +10,7 @@ below, and [Verification & trust](https://intentic.dev/developers/verify/) for w
|
|
|
10
10
|
|
|
11
11
|
## The shape of it
|
|
12
12
|
|
|
13
|
-
intentic hosts no extension code, builds none, and signs none. **A registry is a git repo of pointers
|
|
13
|
+
intentic hosts no extension code, builds none, and signs none. **A registry is a git repo of pointers**:
|
|
14
14
|
each entry names somebody else's repository at a commit, and installing follows that pointer from the owner's
|
|
15
15
|
sandbox straight to the author's git host. Listing costs a pull request; delisting removes a pointer and
|
|
16
16
|
deletes nothing.
|
|
@@ -23,13 +23,13 @@ lists a team's agent plugins and its intentic extensions together.
|
|
|
23
23
|
|
|
24
24
|
| File | Written by | Holds |
|
|
25
25
|
| --- | --- | --- |
|
|
26
|
-
| `.claude-plugin/marketplace.json` | humans + protected admission workflow | every decision
|
|
26
|
+
| `.claude-plugin/marketplace.json` | humans + protected admission workflow | every decision: what is listed, the exact source, trust level, and source-bound security record |
|
|
27
27
|
| `.claude-plugin/registry.generated.json` | the nightly scanner | only facts read back off the source host: stars, last push |
|
|
28
28
|
|
|
29
29
|
Keeping the derived data out of the curated file is load-bearing, not tidiness. Star counts in the hand-edited
|
|
30
30
|
file would make every nightly refresh a merge conflict against every open listing pull request, and would bury
|
|
31
31
|
the decision under churn in the review diff. A registry with no generated file is a registry with no stars,
|
|
32
|
-
which renders fine
|
|
32
|
+
which renders fine: most registries are a dozen internal extensions in a private repo and run no scanner.
|
|
33
33
|
|
|
34
34
|
[`resolveRegistry`](src/registry.ts) joins them by entry name into `RegistryEntry`, which is also the daemon's
|
|
35
35
|
browse wire shape, so the app's list and the website's gallery are the same rows in the same order.
|
|
@@ -48,7 +48,7 @@ with install disabled and is omitted from the public gallery; it cannot become a
|
|
|
48
48
|
the runtime backstop behind the registry's required PR check.
|
|
49
49
|
|
|
50
50
|
A blocked entry stays in the file. Deleting the row hides it from people browsing and tells the people who
|
|
51
|
-
already installed it nothing, which is backwards
|
|
51
|
+
already installed it nothing, which is backwards: they are the ones at risk. Absent on a third-party registry
|
|
52
52
|
resolves to `listed`, because a registry that doesn't use the field hasn't asserted anything.
|
|
53
53
|
Third-party registries are their own admission boundary: their non-blocked rows remain installable without
|
|
54
54
|
adopting intentic's gate or policy, and the app states when they carry no audit record.
|
|
@@ -56,40 +56,40 @@ adopting intentic's gate or policy, and the app states when they carry no audit
|
|
|
56
56
|
Installed sandboxes read these states back on a daily comparison, so trust reaches the people past the browse
|
|
57
57
|
moment too: a row turned `blocked` raises an advisory on the installed extension (and, by default, switches it
|
|
58
58
|
off), and `securityFix: true` on an entry marks its pinned commit as fixing a security problem in earlier ones
|
|
59
|
-
|
|
59
|
+
- the installed side promotes its update badge from ambient to loud, because there the OLD version is the
|
|
60
60
|
dangerous one. Both are asserted by pull request, like `trust`, and are worth exactly that review.
|
|
61
61
|
|
|
62
62
|
## Tier, and what premium buys into
|
|
63
63
|
|
|
64
|
-
`tier` is the listing's price: `free` (the default, and the whole story for most rows) or `premium
|
|
64
|
+
`tier` is the listing's price: `free` (the default, and the whole story for most rows) or `premium`, the
|
|
65
65
|
listing opts into the **creator pool**. A premium row needs an intentic membership, both surfaces badge it
|
|
66
66
|
before the click, and installing it **donates a published number of the member's credits to the publisher**
|
|
67
|
-
(once, deduped monthly
|
|
67
|
+
(once, deduped monthly: updates donate again at most monthly). No usage is metered or reported anywhere;
|
|
68
68
|
the deliberate install is the whole signal. The economics live in
|
|
69
69
|
[The creator pool](https://intentic.dev/earn/).
|
|
70
70
|
|
|
71
71
|
## The mark
|
|
72
72
|
|
|
73
|
-
A row carries the two display tiers the manifest declares
|
|
74
|
-
from the app's own set)
|
|
73
|
+
A row carries the two display tiers the manifest declares: `logo` (a simple-icons slug) and `icon` (a glyph
|
|
74
|
+
from the app's own set): and the [scanner](../../_tools/registry-scan) copies whichever is set into the listing it
|
|
75
75
|
proposes, exactly as it copies the version. A row with neither is drawn as the extension's initials.
|
|
76
76
|
|
|
77
77
|
They ride the **curated** file, which looks wrong for a copied value until you ask what the two files are for:
|
|
78
78
|
the mark is part of how a listing presents itself, so it belongs in the row a human reviews and can correct.
|
|
79
|
-
It also has to be here to be worth anything
|
|
79
|
+
It also has to be here to be worth anything: the gallery and the app's browse list render this row and have
|
|
80
80
|
no access to the manifest, because the whole point of browsing is that the code has not been cloned yet.
|
|
81
81
|
|
|
82
82
|
## The order
|
|
83
83
|
|
|
84
84
|
[`compareEntries`](src/registry.ts): verified first, then stars, then most-recently-pushed, then name. Stars
|
|
85
|
-
are the obvious sort and the wrong one alone
|
|
85
|
+
are the obvious sort and the wrong one alone: every listing sits at nought to three of them for months, so a
|
|
86
86
|
pure star sort is a random order wearing a merit badge, and it is the most purchasable number on GitHub.
|
|
87
87
|
Recency is what actually does the ordering early on. Stars stay visible; they just don't get to be the
|
|
88
88
|
ranking.
|
|
89
89
|
|
|
90
90
|
## Identity
|
|
91
91
|
|
|
92
|
-
An entry's `name` is `publisher.name` from the manifest
|
|
92
|
+
An entry's `name` is `publisher.name` from the manifest: [`extensionIdOf`](../extension-api/src/manifest.ts),
|
|
93
93
|
the same identity the app installs under. It is derived, never declared by the registry, so a registry entry
|
|
94
94
|
cannot rename or spoof an extension, and a repo that copies somebody else's manifest collides with their
|
|
95
95
|
listing instead of shadowing it.
|
|
@@ -107,6 +107,6 @@ exists because neither those signatures nor manifest validation can answer malic
|
|
|
107
107
|
|
|
108
108
|
## Key files
|
|
109
109
|
|
|
110
|
-
- [src/registry.ts](src/registry.ts)
|
|
111
|
-
- [src/source.ts](src/source.ts)
|
|
112
|
-
- [src/index.ts](src/index.ts)
|
|
110
|
+
- [src/registry.ts](src/registry.ts), the file format: what a registry repo contains.
|
|
111
|
+
- [src/source.ts](src/source.ts): how a sha-pinned pointer names an extension.
|
|
112
|
+
- [src/index.ts](src/index.ts): the public surface.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentic/registry",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "The extension-registry file format
|
|
3
|
+
"version": "1.225.0",
|
|
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",
|
|
7
7
|
"repository": {
|
package/src/registry.test.ts
CHANGED
|
@@ -113,9 +113,9 @@ describe(`resolveRegistry`, () => {
|
|
|
113
113
|
expect(resolveRegistry(premium, undefined, REGISTRY)[0]?.tier).toBe(`premium`);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
-
// Blocked rows must survive the resolve
|
|
116
|
+
// Blocked rows must survive the resolve: deleting them is what hides a warning from the people who
|
|
117
117
|
/* The staleness rule the checks ride on: a fact is bound to the sha it was derived from, and a listing
|
|
118
|
-
* repointed since the last scan renders no checks at all
|
|
118
|
+
* repointed since the last scan renders no checks at all (the honest gap) rather than yesterday's verdict
|
|
119
119
|
* describing today's pointer. */
|
|
120
120
|
it(`joins checks only when they were derived from the sha the listing still pins`, () => {
|
|
121
121
|
const facts = RegistryFactsSchema.parse({
|
package/src/source.test.ts
CHANGED
|
@@ -31,7 +31,7 @@ describe(`resolveSource`, () => {
|
|
|
31
31
|
});
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
// An unclonable source is a row we still show
|
|
34
|
+
// An unclonable source is a row we still show: undefined here becomes "not installable", not a dropped entry.
|
|
35
35
|
it(`gives up on shapes it cannot clone rather than throwing`, () => {
|
|
36
36
|
expect(resolveSource({ source: `npm`, package: `@acme/incidents` }, REGISTRY, undefined)).toBeUndefined();
|
|
37
37
|
expect(resolveSource({ source: `github` }, REGISTRY, undefined)).toBeUndefined();
|