@intentic/registry 1.309.0 → 1.311.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 +30 -99
- package/package.json +1 -1
- package/src/registry.test.ts +0 -1
- package/src/source.test.ts +0 -1
package/README.md
CHANGED
|
@@ -1,103 +1,34 @@
|
|
|
1
|
-
#
|
|
1
|
+
# registry
|
|
2
|
+
|
|
3
|
+
The file format of an extension registry, a git repository of sha-pinned pointers with curated trust and scanned facts, read the same way by the daemon, the site gallery and the scanner.
|
|
4
|
+
|
|
5
|
+
```mermaid
|
|
6
|
+
flowchart LR
|
|
7
|
+
curated["marketplace.json<br/>curated by review"] --> resolve(["resolveRegistry"])
|
|
8
|
+
facts["registry.generated.json<br/>facts from the source host"] --> resolve
|
|
9
|
+
scan["registry-scan"] -- "writes facts<br/>opens listing PRs" --> facts
|
|
10
|
+
resolve --> daemon["Daemon<br/>Extensions tab browse"]
|
|
11
|
+
resolve --> site["Site gallery"]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- A registry is a git repo, not a service. `marketplace.json` is Claude Code's plugin-marketplace format plus
|
|
15
|
+
intentic's `kind` and `trust` fields, edited by hand. `registry.generated.json` holds only facts the scanner read, in
|
|
16
|
+
a separate file so a nightly refresh never conflicts with a review.
|
|
17
|
+
- `resolveSource` maps an entry's `source` onto the url, ref and path an install clones. A shape it cannot clone, such
|
|
18
|
+
as npm, becomes "not installable" instead of failing the whole file.
|
|
19
|
+
- Trust is `listed`, `verified` or `blocked`. On the official registry a security review counts only for the exact
|
|
20
|
+
sha, url and path an installer clones, and bumping a policy or scanner version marks every older review stale.
|
|
21
|
+
- `RegistryEntry` is also the daemon's browse wire shape, so the app and the site render the same row.
|
|
2
22
|
|
|
3
|
-
|
|
4
|
-
the result is shown in. Published to npm, and depended on by three otherwise-unrelated consumers, which is the
|
|
5
|
-
whole reason it is a package: the daemon that clones a registry, the site that builds the public gallery, and
|
|
6
|
-
the [scanner](../../_tools/registry-scan) that writes the files. One zod schema instead of three that drift.
|
|
7
|
-
|
|
8
|
-
See [Publish & registries](https://intentic.dev/developers/publish/) for the author-facing version of everything
|
|
9
|
-
below, and [Verification & trust](https://intentic.dev/developers/verify/) for what each trust state claims.
|
|
10
|
-
|
|
11
|
-
## The shape of it
|
|
12
|
-
|
|
13
|
-
intentic hosts no extension code, builds none, and signs none. **A registry is a git repo of pointers**:
|
|
14
|
-
each entry names somebody else's repository at a commit, and installing follows that pointer from the owner's
|
|
15
|
-
sandbox straight to the author's git host. Listing costs a pull request; delisting removes a pointer and
|
|
16
|
-
deletes nothing.
|
|
17
|
-
|
|
18
|
-
The file is `.claude-plugin/marketplace.json`, Claude Code's plugin-marketplace format, deliberately.
|
|
19
|
-
`kind` and `trust` are intentic's own fields and Claude Code ignores what it doesn't recognise, so one repo
|
|
20
|
-
lists a team's agent plugins and its intentic extensions together.
|
|
21
|
-
|
|
22
|
-
## Two files, and why
|
|
23
|
-
|
|
24
|
-
| File | Written by | Holds |
|
|
25
|
-
| --- | --- | --- |
|
|
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
|
-
| `.claude-plugin/registry.generated.json` | the nightly scanner | only facts read back off the source host: stars, last push |
|
|
28
|
-
|
|
29
|
-
Keeping the derived data out of the curated file is load-bearing, not tidiness. Star counts in the hand-edited
|
|
30
|
-
file would make every nightly refresh a merge conflict against every open listing pull request, and would bury
|
|
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: most registries are a dozen internal extensions in a private repo and run no scanner.
|
|
33
|
-
|
|
34
|
-
[`resolveRegistry`](src/registry.ts) joins them by entry name into `RegistryEntry`, which is also the daemon's
|
|
35
|
-
browse wire shape, so the app's list and the website's gallery are the same rows in the same order.
|
|
36
|
-
|
|
37
|
-
## Trust, and what each state claims
|
|
38
|
-
|
|
39
|
-
In the official registry, `listed` means the exact source passed the deterministic scan and intentic agent audit,
|
|
40
|
-
but no human source review is claimed. `verified` means a human also read that same source. `blocked` means
|
|
41
|
-
known-malicious or known-broken, with the required reason alongside. A `verified` row without a
|
|
42
|
-
`securityReview`, a review copied from another repository/sha/subdirectory, or a blocked row without a reason does not parse.
|
|
43
|
-
|
|
44
|
-
`securityReview` records the repository, commit, subdirectory, both versioned policies, scanner and version,
|
|
45
|
-
timestamp, Trivy workflow run and agent-gate run. The official resolver accepts only current Trivy and Intentic
|
|
46
|
-
policies with that complete subject equal to the install pointer. A row missing either stays visible in the app
|
|
47
|
-
with install disabled and is omitted from the public gallery; it cannot become an update offer either. This is
|
|
48
|
-
the runtime backstop behind the registry's required PR check.
|
|
49
|
-
|
|
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: they are the ones at risk. Absent on a third-party registry
|
|
52
|
-
resolves to `listed`, because a registry that doesn't use the field hasn't asserted anything.
|
|
53
|
-
Third-party registries are their own admission boundary: their non-blocked rows remain installable without
|
|
54
|
-
adopting intentic's gate or policy, and the app states when they carry no audit record.
|
|
55
|
-
|
|
56
|
-
Installed sandboxes read these states back on a daily comparison, so trust reaches the people past the browse
|
|
57
|
-
moment too: a row turned `blocked` raises an advisory on the installed extension (and, by default, switches it
|
|
58
|
-
off), and `securityFix: true` on an entry marks its pinned commit as fixing a security problem in earlier ones
|
|
59
|
-
- the installed side promotes its update badge from ambient to loud, because there the OLD version is the
|
|
60
|
-
dangerous one. Both are asserted by pull request, like `trust`, and are worth exactly that review.
|
|
61
|
-
|
|
62
|
-
## The mark
|
|
63
|
-
|
|
64
|
-
A row carries the two display tiers the manifest declares: `logo` (a simple-icons slug) and `icon` (a glyph
|
|
65
|
-
from the app's own set): and the [scanner](../../_tools/registry-scan) copies whichever is set into the listing it
|
|
66
|
-
proposes, exactly as it copies the version. A row with neither is drawn as the extension's initials.
|
|
67
|
-
|
|
68
|
-
They ride the **curated** file, which looks wrong for a copied value until you ask what the two files are for:
|
|
69
|
-
the mark is part of how a listing presents itself, so it belongs in the row a human reviews and can correct.
|
|
70
|
-
It also has to be here to be worth anything: the gallery and the app's browse list render this row and have
|
|
71
|
-
no access to the manifest, because the whole point of browsing is that the code has not been cloned yet.
|
|
72
|
-
|
|
73
|
-
## The order
|
|
74
|
-
|
|
75
|
-
[`compareEntries`](src/registry.ts): verified first, then stars, then most-recently-pushed, then name. Stars
|
|
76
|
-
are the obvious sort and the wrong one alone: every listing sits at nought to three of them for months, so a
|
|
77
|
-
pure star sort is a random order wearing a merit badge, and it is the most purchasable number on GitHub.
|
|
78
|
-
Recency is what actually does the ordering early on. Stars stay visible; they just don't get to be the
|
|
79
|
-
ranking.
|
|
80
|
-
|
|
81
|
-
## Identity
|
|
82
|
-
|
|
83
|
-
An entry's `name` is `publisher.name` from the manifest: [`extensionIdOf`](../extension-manifest/src/manifest.ts),
|
|
84
|
-
the same identity the app installs under. It is derived, never declared by the registry, so a registry entry
|
|
85
|
-
cannot rename or spoof an extension, and a repo that copies somebody else's manifest collides with their
|
|
86
|
-
listing instead of shadowing it.
|
|
87
|
-
|
|
88
|
-
[`isShaPinned`](src/source.ts) is the other half: an extension install requires a full 40-character commit sha,
|
|
89
|
-
because extension code runs trusted in the owner's browser and a branch name is a promise the upstream can
|
|
90
|
-
break with a force-push. A registry entry without one still lists and still reads; it just can't be installed
|
|
91
|
-
in a click.
|
|
23
|
+
## Key files
|
|
92
24
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
exists because neither those signatures nor manifest validation can answer malicious intent.
|
|
25
|
+
- [src/registry.ts](src/registry.ts) — file schemas, trust, the admission record and `resolveRegistry`.
|
|
26
|
+
- [src/source.ts](src/source.ts) — `resolveSource`: an entry's pointer, resolved to something clonable.
|
|
27
|
+
- [src/registry.test.ts](src/registry.test.ts) — joining, trust and ordering, by example.
|
|
28
|
+
- [src/source.test.ts](src/source.test.ts) — which source shapes resolve and how.
|
|
98
29
|
|
|
99
|
-
##
|
|
30
|
+
## Commands
|
|
100
31
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
32
|
+
```sh
|
|
33
|
+
pnpm --filter @intentic/registry test
|
|
34
|
+
```
|
package/package.json
CHANGED
package/src/registry.test.ts
CHANGED
package/src/source.test.ts
CHANGED