@skillcdn/core 0.0.0-stage → 0.1.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/LICENSE.md +105 -0
- package/README.md +59 -2
- package/dist/access.d.ts +7 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/access.js +8 -0
- package/dist/access.js.map +1 -0
- package/dist/address.d.ts +55 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +162 -0
- package/dist/address.js.map +1 -0
- package/dist/brand.d.ts +20 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +18 -0
- package/dist/brand.js.map +1 -0
- package/dist/browse-tree.d.ts +25 -0
- package/dist/browse-tree.d.ts.map +1 -0
- package/dist/browse-tree.js +99 -0
- package/dist/browse-tree.js.map +1 -0
- package/dist/bytes.d.ts +6 -0
- package/dist/bytes.d.ts.map +1 -0
- package/dist/bytes.js +17 -0
- package/dist/bytes.js.map +1 -0
- package/dist/context-page.d.ts +7 -0
- package/dist/context-page.d.ts.map +1 -0
- package/dist/context-page.js +17 -0
- package/dist/context-page.js.map +1 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/front-matter.d.ts +29 -0
- package/dist/front-matter.d.ts.map +1 -0
- package/dist/front-matter.js +106 -0
- package/dist/front-matter.js.map +1 -0
- package/dist/git-ref.d.ts +9 -0
- package/dist/git-ref.d.ts.map +1 -0
- package/dist/git-ref.js +34 -0
- package/dist/git-ref.js.map +1 -0
- package/dist/host-urls.d.ts +16 -0
- package/dist/host-urls.d.ts.map +1 -0
- package/dist/host-urls.js +31 -0
- package/dist/host-urls.js.map +1 -0
- package/dist/image-source.d.ts +5 -0
- package/dist/image-source.d.ts.map +1 -0
- package/dist/image-source.js +20 -0
- package/dist/image-source.js.map +1 -0
- package/dist/index-entry.d.ts +111 -0
- package/dist/index-entry.d.ts.map +1 -0
- package/dist/index-entry.js +2 -0
- package/dist/index-entry.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/license.d.ts +89 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +304 -0
- package/dist/license.js.map +1 -0
- package/dist/manifest-fields.d.ts +33 -0
- package/dist/manifest-fields.d.ts.map +1 -0
- package/dist/manifest-fields.js +169 -0
- package/dist/manifest-fields.js.map +1 -0
- package/dist/markdown-links.d.ts +26 -0
- package/dist/markdown-links.d.ts.map +1 -0
- package/dist/markdown-links.js +220 -0
- package/dist/markdown-links.js.map +1 -0
- package/dist/markdown.d.ts +14 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +133 -0
- package/dist/markdown.js.map +1 -0
- package/dist/ports/blob-store.d.ts +19 -0
- package/dist/ports/blob-store.d.ts.map +1 -0
- package/dist/ports/blob-store.js +2 -0
- package/dist/ports/blob-store.js.map +1 -0
- package/dist/ports/clock.d.ts +5 -0
- package/dist/ports/clock.d.ts.map +1 -0
- package/dist/ports/clock.js +2 -0
- package/dist/ports/clock.js.map +1 -0
- package/dist/ports/entitlements.d.ts +59 -0
- package/dist/ports/entitlements.d.ts.map +1 -0
- package/dist/ports/entitlements.js +4 -0
- package/dist/ports/entitlements.js.map +1 -0
- package/dist/ports/git-host-directory.d.ts +44 -0
- package/dist/ports/git-host-directory.d.ts.map +1 -0
- package/dist/ports/git-host-directory.js +2 -0
- package/dist/ports/git-host-directory.js.map +1 -0
- package/dist/ports/git-host-events.d.ts +88 -0
- package/dist/ports/git-host-events.d.ts.map +1 -0
- package/dist/ports/git-host-events.js +9 -0
- package/dist/ports/git-host-events.js.map +1 -0
- package/dist/ports/git-host-login.d.ts +84 -0
- package/dist/ports/git-host-login.d.ts.map +1 -0
- package/dist/ports/git-host-login.js +2 -0
- package/dist/ports/git-host-login.js.map +1 -0
- package/dist/ports/git-host.d.ts +117 -0
- package/dist/ports/git-host.d.ts.map +1 -0
- package/dist/ports/git-host.js +12 -0
- package/dist/ports/git-host.js.map +1 -0
- package/dist/ports/usage-sink.d.ts +21 -0
- package/dist/ports/usage-sink.d.ts.map +1 -0
- package/dist/ports/usage-sink.js +4 -0
- package/dist/ports/usage-sink.js.map +1 -0
- package/dist/repo-layout.d.ts +71 -0
- package/dist/repo-layout.d.ts.map +1 -0
- package/dist/repo-layout.js +158 -0
- package/dist/repo-layout.js.map +1 -0
- package/dist/repo-manifest.d.ts +68 -0
- package/dist/repo-manifest.d.ts.map +1 -0
- package/dist/repo-manifest.js +176 -0
- package/dist/repo-manifest.js.map +1 -0
- package/dist/repo-path.d.ts +32 -0
- package/dist/repo-path.d.ts.map +1 -0
- package/dist/repo-path.js +81 -0
- package/dist/repo-path.js.map +1 -0
- package/dist/rest/account.d.ts +265 -0
- package/dist/rest/account.d.ts.map +1 -0
- package/dist/rest/account.js +227 -0
- package/dist/rest/account.js.map +1 -0
- package/dist/rest/contracts.d.ts +599 -0
- package/dist/rest/contracts.d.ts.map +1 -0
- package/dist/rest/contracts.js +321 -0
- package/dist/rest/contracts.js.map +1 -0
- package/dist/rest/legal.d.ts +38 -0
- package/dist/rest/legal.d.ts.map +1 -0
- package/dist/rest/legal.js +46 -0
- package/dist/rest/legal.js.map +1 -0
- package/dist/rest/showcase.d.ts +268 -0
- package/dist/rest/showcase.d.ts.map +1 -0
- package/dist/rest/showcase.js +179 -0
- package/dist/rest/showcase.js.map +1 -0
- package/dist/rest/social.d.ts +31 -0
- package/dist/rest/social.d.ts.map +1 -0
- package/dist/rest/social.js +17 -0
- package/dist/rest/social.js.map +1 -0
- package/dist/result.d.ts +17 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +7 -0
- package/dist/result.js.map +1 -0
- package/dist/skill-document-sources.d.ts +30 -0
- package/dist/skill-document-sources.d.ts.map +1 -0
- package/dist/skill-document-sources.js +31 -0
- package/dist/skill-document-sources.js.map +1 -0
- package/dist/skill-document.d.ts +74 -0
- package/dist/skill-document.d.ts.map +1 -0
- package/dist/skill-document.js +117 -0
- package/dist/skill-document.js.map +1 -0
- package/dist/skill-listing.d.ts +48 -0
- package/dist/skill-listing.d.ts.map +1 -0
- package/dist/skill-listing.js +55 -0
- package/dist/skill-listing.js.map +1 -0
- package/dist/skill-manifest.d.ts +64 -0
- package/dist/skill-manifest.d.ts.map +1 -0
- package/dist/skill-manifest.js +135 -0
- package/dist/skill-manifest.js.map +1 -0
- package/dist/skill-uri.d.ts +25 -0
- package/dist/skill-uri.d.ts.map +1 -0
- package/dist/skill-uri.js +33 -0
- package/dist/skill-uri.js.map +1 -0
- package/dist/text-safety.d.ts +3 -0
- package/dist/text-safety.d.ts.map +1 -0
- package/dist/text-safety.js +26 -0
- package/dist/text-safety.js.map +1 -0
- package/dist/tools/catalog.d.ts +43 -0
- package/dist/tools/catalog.d.ts.map +1 -0
- package/dist/tools/catalog.js +77 -0
- package/dist/tools/catalog.js.map +1 -0
- package/dist/tools/contracts.d.ts +50 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +98 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/render.d.ts +22 -0
- package/dist/tools/render.d.ts.map +1 -0
- package/dist/tools/render.js +271 -0
- package/dist/tools/render.js.map +1 -0
- package/dist/tools/response-budget.d.ts +9 -0
- package/dist/tools/response-budget.d.ts.map +1 -0
- package/dist/tools/response-budget.js +28 -0
- package/dist/tools/response-budget.js.map +1 -0
- package/dist/tools/results.d.ts +206 -0
- package/dist/tools/results.d.ts.map +1 -0
- package/dist/tools/results.js +26 -0
- package/dist/tools/results.js.map +1 -0
- package/package.json +48 -3
package/LICENSE.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 KDX Labs Corp.
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @skillcdn/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The contracts of [SkillCDN](https://skillcdn.ai), which turns any git repository into an MCP server: the address scheme, the skill-repo convention, the tool contracts, the REST schemas, the types of an index, and the ports the rest of the system implements. Pure TypeScript with no I/O and no Node.js APIs: it runs unchanged in the server, in tests, in a browser, and in whatever else reads or writes a SkillCDN address.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install @skillcdn/core
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What belongs here
|
|
10
|
+
|
|
11
|
+
| Area | Spec |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Address parser and formatter | [address.md](https://github.com/skillcdn/skillcdn/blob/main/docs/specs/address.md) |
|
|
14
|
+
| Skill-repo convention parser (front-matter, layouts, manifests) | [skill-repo.md](https://github.com/skillcdn/skillcdn/blob/main/docs/specs/skill-repo.md) |
|
|
15
|
+
| Tool contracts: names, input and output schemas | [tools.md](https://github.com/skillcdn/skillcdn/blob/main/docs/specs/tools.md) |
|
|
16
|
+
| Permission rules: the decision logic, given facts fetched elsewhere | [permissions.md](https://github.com/skillcdn/skillcdn/blob/main/docs/specs/permissions.md) |
|
|
17
|
+
| REST contracts: the schemas of the public API, and of what a signed-in person has (`rest/account.ts`) | [rest.md](https://github.com/skillcdn/skillcdn/blob/main/docs/specs/rest.md) |
|
|
18
|
+
| The types of an index: what the reading rules produce for a commit and what the store keeps (`IndexEntry`, `SnapshotIndex`, `SkillFrontMatter`, `SnapshotDiagnostic`, `StoredTranslation`) | [ADR-0045](https://github.com/skillcdn/skillcdn/blob/main/docs/adr/0045-the-indexer-is-a-package-and-check-is-a-command.md) |
|
|
19
|
+
| Ports: git host (`GitHost` for content, `GitHostLogin` for signing in and what a person can see, `GitHostDirectory` for an account's public listing, `GitHostEventSource` for what the host says happened, as the events that end what is remembered), blob store, clock and ids, `Entitlements`, `UsageSink` | [architecture.md](https://github.com/skillcdn/skillcdn/blob/main/docs/architecture.md#extension-points) |
|
|
20
|
+
| The mark of the site as path data, so that the pages, the favicon and the social previews the server draws show one shape | [apps/web/README.md](https://github.com/skillcdn/skillcdn/blob/main/apps/web/README.md) |
|
|
21
|
+
|
|
22
|
+
## What does not
|
|
23
|
+
|
|
24
|
+
Network calls, SQL, file access, environment variables, logging setup, HTTP types. Those live in adapters that implement the ports defined here. The reading rules that turn a commit into an index are [`@skillcdn/indexer`](https://www.npmjs.com/package/@skillcdn/indexer).
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { formatAddress, parseAddress } from "@skillcdn/core";
|
|
30
|
+
|
|
31
|
+
const parsed = parseAddress("/gh/acme/skills@v1.2.0/marketing");
|
|
32
|
+
if (parsed.ok) {
|
|
33
|
+
parsed.value.ref; // { kind: "name", name: "v1.2.0" }
|
|
34
|
+
formatAddress(parsed.value); // the canonical spelling
|
|
35
|
+
} else {
|
|
36
|
+
parsed.error.code; // a stable, typed reason
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Parsers return a `Result` and never throw. A `RepoPath` can only come from `parseRepoPath`, so a function that takes one does not need to think about traversal.
|
|
41
|
+
|
|
42
|
+
`extractMarkdownReferences(sourcePath, markdown)` recognizes local `.md` links in prose and resolves them to repository-root paths. It ignores code and external URLs and bounds input size and reference count. `resolveMarkdownReference` exposes the same path resolution for a single destination. These helpers identify references; the indexer decides whether their destinations may be served.
|
|
43
|
+
|
|
44
|
+
`inspectMarkdownReferences` also reports when those inspection bounds are reached. `browseCatalogFiles` builds immediate folder entries and descendant counts from already published files; both the server and the working-tree check use it.
|
|
45
|
+
|
|
46
|
+
`isServedPath` combines skill declarations, the nearest repository manifest's document directories, and explicit includes. A valid `SKILL.md` can declare a skill anywhere, including a hidden directory. A declaration permits ordinary descendants; further hidden descendants need their own declaration or a Markdown link.
|
|
47
|
+
|
|
48
|
+
`isSharedIncludePath` says whether a skill may include a document from outside its directory: a page served under a document directory that a manifest at or above the skill declares ([ADR-0044](https://github.com/skillcdn/skillcdn/blob/main/docs/adr/0044-a-skill-may-include-a-page-of-a-shared-document-set.md)). `resolveRepoPath` resolves a path written as a link destination is, from the repository root with a leading `/` or relative to a directory; links and include lists share it.
|
|
49
|
+
|
|
50
|
+
Ancestor `exclude` paths and unreadable manifest scopes take precedence over publication. `selectReadmePaths` and `folderOverview` supply optional original-language introductions without loading their bodies or adding search results. MCP discovery summaries and serialized response budgets keep selection separate from full context loading; REST retains full metadata.
|
|
51
|
+
|
|
52
|
+
For the MCP skills extension: `skillDocumentInput` and `assembleSkillDocument` turn a skill's sources into the one document it is served as, so that the indexer's digest and the reader's bytes agree; `renderSkillSections` gives the tools the same sections; `skillListingProblem` says why a skill cannot be listed; `formatSkillUri` and `parseSkillUri` implement the URI grammar; `decodeText` is the one UTF-8 decoder every adapter uses.
|
|
53
|
+
|
|
54
|
+
`parseOwnerPath` and `formatOwnerPath` read and write `/gh/<owner>`, the path of the page of an account, with the owner rules of the address grammar. `rest/account.ts` also holds the paths the pages and the server share for signing in (`AUTH_ROUTES`, `loginPath`, and `SIGN_IN_PARAM` with `signInPath`, by which the server asks a page to open the sign-in dialog and tells it why a sign-in did not complete), the account pages and the consent page, so that neither side spells them on its own.
|
|
55
|
+
|
|
56
|
+
Everything public is exported from `src/index.ts`. There are no deep imports.
|
|
57
|
+
|
|
58
|
+
## Status
|
|
59
|
+
|
|
60
|
+
Pre-1.0: the surface may change between minor versions, and the changelog says what changed. The specifications linked above describe the contracts; the code follows them.
|
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HostRepository } from "./ports/git-host.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a repository may be served to a caller who has not authenticated. Fails closed: only a
|
|
4
|
+
* repository the host reports as public qualifies, whatever credentials fetched the answer.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isAnonymouslyReadable(repository: HostRepository): boolean;
|
|
7
|
+
//# sourceMappingURL=access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAEzE"}
|
package/dist/access.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a repository may be served to a caller who has not authenticated. Fails closed: only a
|
|
3
|
+
* repository the host reports as public qualifies, whatever credentials fetched the answer.
|
|
4
|
+
*/
|
|
5
|
+
export function isAnonymouslyReadable(repository) {
|
|
6
|
+
return repository.visibility === "public";
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,UAA0B;IAC9D,OAAO,UAAU,CAAC,UAAU,KAAK,QAAQ,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type RepoPath } from "./repo-path.js";
|
|
2
|
+
import { type Result } from "./result.js";
|
|
3
|
+
export declare const MAX_ADDRESS_LENGTH = 2048;
|
|
4
|
+
/** Git hosts an address can name. `gh` is GitHub. */
|
|
5
|
+
export declare const GIT_HOST_KEYS: readonly ["gh"];
|
|
6
|
+
export type GitHostKey = (typeof GIT_HOST_KEYS)[number];
|
|
7
|
+
export type AddressRef =
|
|
8
|
+
/** A full commit hash, lowercase. The address is pinned: its content never changes. */
|
|
9
|
+
{
|
|
10
|
+
readonly kind: "commit";
|
|
11
|
+
readonly hash: string;
|
|
12
|
+
}
|
|
13
|
+
/** A branch, a tag or anything else the host resolves. The address is moving. */
|
|
14
|
+
| {
|
|
15
|
+
readonly kind: "name";
|
|
16
|
+
readonly name: string;
|
|
17
|
+
};
|
|
18
|
+
export interface Address {
|
|
19
|
+
readonly host: GitHostKey;
|
|
20
|
+
/** Canonical spelling: lowercase on hosts that match names case-insensitively. */
|
|
21
|
+
readonly owner: string;
|
|
22
|
+
readonly repo: string;
|
|
23
|
+
/** `undefined` means the default branch. */
|
|
24
|
+
readonly ref: AddressRef | undefined;
|
|
25
|
+
/** Directory the address mounts; the root path mounts the whole repository. */
|
|
26
|
+
readonly path: RepoPath;
|
|
27
|
+
}
|
|
28
|
+
export type AddressErrorCode = "not_absolute" | "too_long" | "bad_encoding" | "forbidden_character" | "empty_segment" | "dot_segment" | "unknown_host" | "missing_repo" | "invalid_owner" | "invalid_repo" | "empty_ref" | "invalid_ref" | "invalid_path";
|
|
29
|
+
export interface AddressError {
|
|
30
|
+
readonly code: AddressErrorCode;
|
|
31
|
+
readonly message: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parses the path of an endpoint URL, for example `/gh/acme/skills@v1.2.0/marketing`.
|
|
35
|
+
* Total: every input yields an address or a typed error, and nothing here touches the network.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseAddress(input: string): Result<Address, AddressError>;
|
|
38
|
+
/** The canonical spelling of an address. `formatAddress(parseAddress(x).value)` is the canonical form of `x`. */
|
|
39
|
+
export declare function formatAddress(address: Address): string;
|
|
40
|
+
/** An account on a git host, as the path of its page names it. */
|
|
41
|
+
export interface OwnerPath {
|
|
42
|
+
readonly host: GitHostKey;
|
|
43
|
+
/** Canonical spelling: lowercase on hosts that match names case-insensitively. */
|
|
44
|
+
readonly owner: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parses `/gh/<owner>`: the path of the page of an account. It is one segment short of an
|
|
48
|
+
* address, serves people and never MCP. `undefined` for anything else; an owner is written with
|
|
49
|
+
* unreserved characters only, so nothing is percent-decoded.
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseOwnerPath(input: string): OwnerPath | undefined;
|
|
52
|
+
export declare function formatOwnerPath(owner: OwnerPath): string;
|
|
53
|
+
/** Pinned addresses name a full commit hash and may be cached indefinitely; everything else moves. */
|
|
54
|
+
export declare function isPinnedAddress(address: Address): boolean;
|
|
55
|
+
//# sourceMappingURL=address.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAKnD,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAEvC,qDAAqD;AACrD,eAAO,MAAM,aAAa,YAAI,IAAI,CAAU,CAAC;AAC7C,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,MAAM,UAAU;AACpB,uFAAuF;AACrF;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACpD,iFAAiF;GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,CAAC;IACrC,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,UAAU,GACV,cAAc,GACd,qBAAqB,GACrB,eAAe,GACf,aAAa,GACb,cAAc,GACd,cAAc,GACd,eAAe,GACf,cAAc,GACd,WAAW,GACX,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAiCD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,YAAY,CAAC,CAmFzE;AASD,iHAAiH;AACjH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAatD;AAED,kEAAkE;AAClE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAenE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAExD;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEzD"}
|
package/dist/address.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { isFullCommitHash, isValidRefName } from "./git-ref.js";
|
|
2
|
+
import { parseRepoPath } from "./repo-path.js";
|
|
3
|
+
import { err, ok } from "./result.js";
|
|
4
|
+
import { hasForbiddenCodePoint } from "./text-safety.js";
|
|
5
|
+
// Grammar and semantics: docs/specs/address.md.
|
|
6
|
+
export const MAX_ADDRESS_LENGTH = 2048;
|
|
7
|
+
/** Git hosts an address can name. `gh` is GitHub. */
|
|
8
|
+
export const GIT_HOST_KEYS = ["gh"];
|
|
9
|
+
const HOST_NAMING_RULES = {
|
|
10
|
+
gh: {
|
|
11
|
+
// Managed-user accounts carry an underscore suffix, so "_" is allowed after the first character.
|
|
12
|
+
owner: /^[a-z0-9][a-z0-9_-]{0,38}$/i,
|
|
13
|
+
repo: /^[a-z0-9._-]{1,100}$/i,
|
|
14
|
+
caseInsensitive: true,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
function fail(code, message) {
|
|
18
|
+
return err({ code, message });
|
|
19
|
+
}
|
|
20
|
+
function isGitHostKey(value) {
|
|
21
|
+
return GIT_HOST_KEYS.includes(value);
|
|
22
|
+
}
|
|
23
|
+
function decodeSegment(raw) {
|
|
24
|
+
try {
|
|
25
|
+
return decodeURIComponent(raw);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parses the path of an endpoint URL, for example `/gh/acme/skills@v1.2.0/marketing`.
|
|
33
|
+
* Total: every input yields an address or a typed error, and nothing here touches the network.
|
|
34
|
+
*/
|
|
35
|
+
export function parseAddress(input) {
|
|
36
|
+
if (!input.startsWith("/")) {
|
|
37
|
+
return fail("not_absolute", 'an address starts with "/"');
|
|
38
|
+
}
|
|
39
|
+
if (input.length > MAX_ADDRESS_LENGTH) {
|
|
40
|
+
return fail("too_long", `an address is at most ${MAX_ADDRESS_LENGTH} characters`);
|
|
41
|
+
}
|
|
42
|
+
const segments = [];
|
|
43
|
+
for (const raw of input.slice(1).split("/")) {
|
|
44
|
+
if (raw.length === 0) {
|
|
45
|
+
return fail("empty_segment", "an address has no empty segments and no trailing slash");
|
|
46
|
+
}
|
|
47
|
+
const segment = decodeSegment(raw);
|
|
48
|
+
if (segment === undefined) {
|
|
49
|
+
return fail("bad_encoding", "an address must be valid percent-encoded UTF-8");
|
|
50
|
+
}
|
|
51
|
+
// An encoded slash would mean different things before and after a proxy decodes it.
|
|
52
|
+
if (segment.includes("/") || segment.includes("\\") || hasForbiddenCodePoint(segment)) {
|
|
53
|
+
return fail("forbidden_character", "an address has no encoded slashes, backslashes or control characters");
|
|
54
|
+
}
|
|
55
|
+
if (segment === "." || segment === "..") {
|
|
56
|
+
return fail("dot_segment", 'an address has no "." or ".." segments');
|
|
57
|
+
}
|
|
58
|
+
segments.push(segment);
|
|
59
|
+
}
|
|
60
|
+
const [host, owner, repoSegment, ...rest] = segments;
|
|
61
|
+
if (host === undefined || !isGitHostKey(host)) {
|
|
62
|
+
return fail("unknown_host", `unknown git host; expected one of: ${GIT_HOST_KEYS.join(", ")}`);
|
|
63
|
+
}
|
|
64
|
+
if (owner === undefined || repoSegment === undefined) {
|
|
65
|
+
return fail("missing_repo", "an address names an owner and a repository");
|
|
66
|
+
}
|
|
67
|
+
const rules = HOST_NAMING_RULES[host];
|
|
68
|
+
if (!rules.owner.test(owner)) {
|
|
69
|
+
return fail("invalid_owner", "the owner is not a valid account name on this git host");
|
|
70
|
+
}
|
|
71
|
+
const at = repoSegment.indexOf("@");
|
|
72
|
+
const repo = at < 0 ? repoSegment : repoSegment.slice(0, at);
|
|
73
|
+
if (!rules.repo.test(repo) || repo === "." || repo === ".." || /\.git$/i.test(repo)) {
|
|
74
|
+
return fail("invalid_repo", "the repository is not a valid repository name on this git host");
|
|
75
|
+
}
|
|
76
|
+
let ref;
|
|
77
|
+
let pathInput;
|
|
78
|
+
if (at < 0) {
|
|
79
|
+
pathInput = rest.join("/");
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// The ref ends at the first ":" if there is one, otherwise at the first "/".
|
|
83
|
+
const tail = [repoSegment.slice(at + 1), ...rest].join("/");
|
|
84
|
+
const colon = tail.indexOf(":");
|
|
85
|
+
const end = colon >= 0 ? colon : tail.indexOf("/");
|
|
86
|
+
const refText = end < 0 ? tail : tail.slice(0, end);
|
|
87
|
+
pathInput = end < 0 ? "" : tail.slice(end + 1);
|
|
88
|
+
if (refText.length === 0) {
|
|
89
|
+
return fail("empty_ref", 'a ref follows "@"');
|
|
90
|
+
}
|
|
91
|
+
if (isFullCommitHash(refText)) {
|
|
92
|
+
ref = { kind: "commit", hash: refText.toLowerCase() };
|
|
93
|
+
}
|
|
94
|
+
else if (isValidRefName(refText)) {
|
|
95
|
+
ref = { kind: "name", name: refText };
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
return fail("invalid_ref", "the ref is not a valid git ref name");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const path = parseRepoPath(pathInput);
|
|
102
|
+
if (!path.ok) {
|
|
103
|
+
return fail("invalid_path", path.error.message);
|
|
104
|
+
}
|
|
105
|
+
return ok({
|
|
106
|
+
host,
|
|
107
|
+
owner: rules.caseInsensitive ? owner.toLowerCase() : owner,
|
|
108
|
+
repo: rules.caseInsensitive ? repo.toLowerCase() : repo,
|
|
109
|
+
ref,
|
|
110
|
+
path: path.value,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function encodeSlashSeparated(value) {
|
|
114
|
+
return value
|
|
115
|
+
.split("/")
|
|
116
|
+
.map((segment) => encodeURIComponent(segment).replaceAll("%40", "@").replaceAll("%3A", ":"))
|
|
117
|
+
.join("/");
|
|
118
|
+
}
|
|
119
|
+
/** The canonical spelling of an address. `formatAddress(parseAddress(x).value)` is the canonical form of `x`. */
|
|
120
|
+
export function formatAddress(address) {
|
|
121
|
+
const repo = `/${address.host}/${address.owner}/${address.repo}`;
|
|
122
|
+
const path = encodeSlashSeparated(address.path);
|
|
123
|
+
if (address.ref === undefined) {
|
|
124
|
+
return path.length === 0 ? repo : `${repo}/${path}`;
|
|
125
|
+
}
|
|
126
|
+
const refText = address.ref.kind === "commit" ? address.ref.hash : address.ref.name;
|
|
127
|
+
const mounted = `${repo}@${encodeSlashSeparated(refText)}`;
|
|
128
|
+
// Without the explicit terminator, a "/" in the ref or a ":" in the path would be read back differently.
|
|
129
|
+
if (refText.includes("/") || address.path.includes(":")) {
|
|
130
|
+
return `${mounted}:${path}`;
|
|
131
|
+
}
|
|
132
|
+
return path.length === 0 ? mounted : `${mounted}/${path}`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Parses `/gh/<owner>`: the path of the page of an account. It is one segment short of an
|
|
136
|
+
* address, serves people and never MCP. `undefined` for anything else; an owner is written with
|
|
137
|
+
* unreserved characters only, so nothing is percent-decoded.
|
|
138
|
+
*/
|
|
139
|
+
export function parseOwnerPath(input) {
|
|
140
|
+
if (input.length > MAX_ADDRESS_LENGTH) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
const [empty, host, owner, ...rest] = input.split("/");
|
|
144
|
+
if (empty !== "" || host === undefined || owner === undefined || rest.length > 0) {
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
if (!isGitHostKey(host)) {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
const rules = HOST_NAMING_RULES[host];
|
|
151
|
+
return rules.owner.test(owner)
|
|
152
|
+
? { host, owner: rules.caseInsensitive ? owner.toLowerCase() : owner }
|
|
153
|
+
: undefined;
|
|
154
|
+
}
|
|
155
|
+
export function formatOwnerPath(owner) {
|
|
156
|
+
return `/${owner.host}/${owner.owner}`;
|
|
157
|
+
}
|
|
158
|
+
/** Pinned addresses name a full commit hash and may be cached indefinitely; everything else moves. */
|
|
159
|
+
export function isPinnedAddress(address) {
|
|
160
|
+
return address.ref?.kind === "commit";
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"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"}
|
package/dist/brand.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The symbol: two interlocking halves of an S, centred in a 100 by 100 box. */
|
|
2
|
+
export declare const BRAND_SYMBOL_PATH = "M97.39 67.65C96.39 51.77 83.22 39.18 67.08 39.18C66.71 39.18 66.35 39.23 65.98 39.24C71.37 41.43 75.17 46.72 75.17 52.9C75.17 61.05 68.57 67.65 60.42 67.65L36.77 67.65L34.86 67.65C16.99 67.65 2.51 82.13 2.51 100L61.04 100L67.08 100C83.88 100 97.49 86.39 97.49 69.59C97.49 68.94 97.44 68.3 97.39 67.65Z M2.61 32.35C3.61 48.23 16.78 60.82 32.92 60.82C33.29 60.82 33.65 60.77 34.02 60.76C28.63 58.57 24.83 53.28 24.83 47.1C24.83 38.95 31.43 32.35 39.58 32.35L63.23 32.35L65.14 32.35C83.01 32.35 97.49 17.87 97.49 0L38.96 0L32.92 0C16.12 0 2.51 13.61 2.51 30.41C2.51 31.06 2.56 31.7 2.61 32.35Z";
|
|
3
|
+
/** The symbol's own blue. It is the symbol's colour and not an interface colour: the symbol is drawn in it everywhere, on light and on dark alike. */
|
|
4
|
+
export declare const BRAND_SYMBOL_COLOR = "#3a6dd4";
|
|
5
|
+
/**
|
|
6
|
+
* The wordmark, in the coordinates of the lockup: the symbol's 100 by 100 box at the left, the
|
|
7
|
+
* word at the distance the brand file sets. It is drawn in black on light grounds and in white on
|
|
8
|
+
* dark ones, and in no other colour.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BRAND_WORDMARK_PATH = "M187.74 34.15L187.74 33.73C187.74 30.09 184.72 27.07 181.08 27.07L151.54 27.07C147.89 27.07 144.88 30.09 144.88 33.73L144.88 34.15C144.88 37.78 147.89 40.8 151.54 40.8L177.75 40.8C184.51 40.8 190.55 43.71 194.71 48.29C195.02 48.6 195.23 48.92 195.54 49.23C198.76 53.18 200.74 58.28 200.74 63.79C200.74 76.48 190.44 86.78 177.75 86.78L154.97 86.78C142.28 86.78 131.98 76.48 131.98 63.79L144.98 63.79C144.98 69.3 149.45 73.78 154.97 73.78L177.75 73.78C183.26 73.78 187.84 69.3 187.84 63.79C187.84 58.28 183.26 53.8 177.75 53.8L151.54 53.8C146.23 53.8 141.44 51.72 137.91 48.29C136.97 47.36 136.14 46.32 135.41 45.17C133.23 42.05 131.98 38.2 131.98 34.04L131.98 33.62C131.98 22.8 140.72 13.96 151.54 13.96L181.08 13.96C191.9 13.96 200.74 22.8 200.74 33.62L200.74 34.04L187.74 34.15Z M252.12 43.19L283.64 86.78L267.62 86.78L242.45 52.04L224.04 68.79L224.04 86.78L211.03 86.78L211.03 13.96L224.04 13.96L224.04 51.2L234.75 41.43L244.43 32.58L264.71 13.96L283.95 13.96L252.12 43.19Z M294.35 33.75L307.36 33.75L307.36 86.78L294.35 86.78ZZ M294.35 13.11L307.36 13.11L307.36 26.12L294.35 26.12ZZ M317.76 13.96L330.76 13.96L330.76 86.78L317.76 86.78ZZ M341.16 13.96L354.17 13.96L354.17 86.78L341.16 86.78ZZ M377.57 50.37C377.57 63.27 388.08 73.78 400.98 73.78L437.39 73.78L437.39 86.78L400.98 86.78C380.9 86.78 364.57 70.45 364.57 50.37C364.57 30.29 380.9 13.96 400.98 13.96L437.39 13.96L437.39 26.97L400.98 26.97C388.08 26.97 377.57 37.47 377.57 50.37Z M460.68 73.88L484.09 73.88C496.99 73.88 507.49 63.38 507.49 50.48C507.49 37.58 496.99 27.07 484.09 27.07L460.68 27.07L460.68 73.88ZM484.09 14.07C504.17 14.07 520.5 30.29 520.5 50.37C520.5 59.32 517.27 67.54 511.86 73.88C511.24 74.61 510.51 75.34 509.78 76.07C503.23 82.72 494.18 86.78 484.19 86.78L447.78 86.78L447.78 13.96L484.09 14.07Z M603.82 14.07L603.82 86.89L590.81 76.9L544 40.8L544 86.89L531 86.89L531 14.27L544 24.26L590.81 60.36L590.81 13.96L603.82 14.07Z";
|
|
11
|
+
/** The lockup, symbol and wordmark together: its width for a height of 100. */
|
|
12
|
+
export declare const BRAND_LOCKUP_WIDTH = 603.82;
|
|
13
|
+
/** The box the wordmark alone occupies within the lockup: x, y, width, height. */
|
|
14
|
+
export declare const BRAND_WORDMARK_BOX: {
|
|
15
|
+
readonly x: 131.98;
|
|
16
|
+
readonly y: 13.11;
|
|
17
|
+
readonly width: 471.84;
|
|
18
|
+
readonly height: 73.77;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../src/brand.ts"],"names":[],"mappings":"AAIA,gFAAgF;AAChF,eAAO,MAAM,iBAAiB,mlBACojB,CAAC;AAEnlB,sJAAsJ;AACtJ,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,y3DACw1D,CAAC;AAEz3D,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,SAAS,CAAC;AAEzC,kFAAkF;AAClF,eAAO,MAAM,kBAAkB;aAAK,CAAC,EAAE,MAAM;aAAE,CAAC,EAAE,KAAK;aAAE,KAAK,EAAE,MAAM;aAAE,MAAM,EAAE,KAAK;CAAW,CAAC"}
|
package/dist/brand.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// The mark of the site, as path data, so that every place that draws it (the pages, the
|
|
2
|
+
// favicon, the social previews the server draws) draws the same shape. The files under
|
|
3
|
+
// apps/web/public/brand/ carry the same paths for whoever needs a picture; a test keeps them equal.
|
|
4
|
+
/** The symbol: two interlocking halves of an S, centred in a 100 by 100 box. */
|
|
5
|
+
export const BRAND_SYMBOL_PATH = "M97.39 67.65C96.39 51.77 83.22 39.18 67.08 39.18C66.71 39.18 66.35 39.23 65.98 39.24C71.37 41.43 75.17 46.72 75.17 52.9C75.17 61.05 68.57 67.65 60.42 67.65L36.77 67.65L34.86 67.65C16.99 67.65 2.51 82.13 2.51 100L61.04 100L67.08 100C83.88 100 97.49 86.39 97.49 69.59C97.49 68.94 97.44 68.3 97.39 67.65Z M2.61 32.35C3.61 48.23 16.78 60.82 32.92 60.82C33.29 60.82 33.65 60.77 34.02 60.76C28.63 58.57 24.83 53.28 24.83 47.1C24.83 38.95 31.43 32.35 39.58 32.35L63.23 32.35L65.14 32.35C83.01 32.35 97.49 17.87 97.49 0L38.96 0L32.92 0C16.12 0 2.51 13.61 2.51 30.41C2.51 31.06 2.56 31.7 2.61 32.35Z";
|
|
6
|
+
/** The symbol's own blue. It is the symbol's colour and not an interface colour: the symbol is drawn in it everywhere, on light and on dark alike. */
|
|
7
|
+
export const BRAND_SYMBOL_COLOR = "#3a6dd4";
|
|
8
|
+
/**
|
|
9
|
+
* The wordmark, in the coordinates of the lockup: the symbol's 100 by 100 box at the left, the
|
|
10
|
+
* word at the distance the brand file sets. It is drawn in black on light grounds and in white on
|
|
11
|
+
* dark ones, and in no other colour.
|
|
12
|
+
*/
|
|
13
|
+
export const BRAND_WORDMARK_PATH = "M187.74 34.15L187.74 33.73C187.74 30.09 184.72 27.07 181.08 27.07L151.54 27.07C147.89 27.07 144.88 30.09 144.88 33.73L144.88 34.15C144.88 37.78 147.89 40.8 151.54 40.8L177.75 40.8C184.51 40.8 190.55 43.71 194.71 48.29C195.02 48.6 195.23 48.92 195.54 49.23C198.76 53.18 200.74 58.28 200.74 63.79C200.74 76.48 190.44 86.78 177.75 86.78L154.97 86.78C142.28 86.78 131.98 76.48 131.98 63.79L144.98 63.79C144.98 69.3 149.45 73.78 154.97 73.78L177.75 73.78C183.26 73.78 187.84 69.3 187.84 63.79C187.84 58.28 183.26 53.8 177.75 53.8L151.54 53.8C146.23 53.8 141.44 51.72 137.91 48.29C136.97 47.36 136.14 46.32 135.41 45.17C133.23 42.05 131.98 38.2 131.98 34.04L131.98 33.62C131.98 22.8 140.72 13.96 151.54 13.96L181.08 13.96C191.9 13.96 200.74 22.8 200.74 33.62L200.74 34.04L187.74 34.15Z M252.12 43.19L283.64 86.78L267.62 86.78L242.45 52.04L224.04 68.79L224.04 86.78L211.03 86.78L211.03 13.96L224.04 13.96L224.04 51.2L234.75 41.43L244.43 32.58L264.71 13.96L283.95 13.96L252.12 43.19Z M294.35 33.75L307.36 33.75L307.36 86.78L294.35 86.78ZZ M294.35 13.11L307.36 13.11L307.36 26.12L294.35 26.12ZZ M317.76 13.96L330.76 13.96L330.76 86.78L317.76 86.78ZZ M341.16 13.96L354.17 13.96L354.17 86.78L341.16 86.78ZZ M377.57 50.37C377.57 63.27 388.08 73.78 400.98 73.78L437.39 73.78L437.39 86.78L400.98 86.78C380.9 86.78 364.57 70.45 364.57 50.37C364.57 30.29 380.9 13.96 400.98 13.96L437.39 13.96L437.39 26.97L400.98 26.97C388.08 26.97 377.57 37.47 377.57 50.37Z M460.68 73.88L484.09 73.88C496.99 73.88 507.49 63.38 507.49 50.48C507.49 37.58 496.99 27.07 484.09 27.07L460.68 27.07L460.68 73.88ZM484.09 14.07C504.17 14.07 520.5 30.29 520.5 50.37C520.5 59.32 517.27 67.54 511.86 73.88C511.24 74.61 510.51 75.34 509.78 76.07C503.23 82.72 494.18 86.78 484.19 86.78L447.78 86.78L447.78 13.96L484.09 14.07Z M603.82 14.07L603.82 86.89L590.81 76.9L544 40.8L544 86.89L531 86.89L531 14.27L544 24.26L590.81 60.36L590.81 13.96L603.82 14.07Z";
|
|
14
|
+
/** The lockup, symbol and wordmark together: its width for a height of 100. */
|
|
15
|
+
export const BRAND_LOCKUP_WIDTH = 603.82;
|
|
16
|
+
/** The box the wordmark alone occupies within the lockup: x, y, width, height. */
|
|
17
|
+
export const BRAND_WORDMARK_BOX = { x: 131.98, y: 13.11, width: 471.84, height: 73.77 };
|
|
18
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","sourceRoot":"","sources":["../src/brand.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,uFAAuF;AACvF,oGAAoG;AAEpG,gFAAgF;AAChF,MAAM,CAAC,MAAM,iBAAiB,GAC5B,glBAAglB,CAAC;AAEnlB,sJAAsJ;AACtJ,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC9B,s3DAAs3D,CAAC;AAEz3D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAEzC,kFAAkF;AAClF,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAW,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { LicenseFact } from "./license.js";
|
|
2
|
+
import { type RepoFileKind } from "./repo-layout.js";
|
|
3
|
+
import { type RepoPath } from "./repo-path.js";
|
|
4
|
+
import type { BrowseEntry, FolderOverview } from "./tools/results.js";
|
|
5
|
+
/** One already-published file, independent of storage or transport representation. */
|
|
6
|
+
export interface CatalogFile {
|
|
7
|
+
/** A skill's license (ADR-0026). */
|
|
8
|
+
readonly license?: LicenseFact | undefined;
|
|
9
|
+
readonly path: RepoPath;
|
|
10
|
+
readonly kind: RepoFileKind;
|
|
11
|
+
readonly name?: string | undefined;
|
|
12
|
+
readonly title?: string | undefined;
|
|
13
|
+
readonly description?: string | undefined;
|
|
14
|
+
readonly skillDir?: RepoPath | undefined;
|
|
15
|
+
readonly searchable: boolean;
|
|
16
|
+
readonly size: number;
|
|
17
|
+
readonly linkedOnly?: boolean | undefined;
|
|
18
|
+
readonly overviewOnly?: boolean | undefined;
|
|
19
|
+
readonly language?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Returns only overview metadata; its body is read explicitly through read_file. */
|
|
22
|
+
export declare function folderOverview(files: readonly CatalogFile[], path: RepoPath): FolderOverview | undefined;
|
|
23
|
+
/** Immediate canonical children, with descendant counts and inherited manifest language. */
|
|
24
|
+
export declare function browseCatalogFiles(files: readonly CatalogFile[], path: RepoPath): BrowseEntry[];
|
|
25
|
+
//# sourceMappingURL=browse-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browse-tree.d.ts","sourceRoot":"","sources":["../src/browse-tree.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAEL,KAAK,YAAY,EAGlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,QAAQ,EAAa,MAAM,gBAAgB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEtE,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,qFAAqF;AACrF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,IAAI,EAAE,QAAQ,GACb,cAAc,GAAG,SAAS,CAS5B;AASD,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,WAAW,EAAE,CAsF/F"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { parentDirectory, SKILL_MANIFEST_FILE, selectReadmePaths, } from "./repo-layout.js";
|
|
2
|
+
import { ROOT_PATH } from "./repo-path.js";
|
|
3
|
+
/** Returns only overview metadata; its body is read explicitly through read_file. */
|
|
4
|
+
export function folderOverview(files, path) {
|
|
5
|
+
const selected = selectReadmePaths(files.map((file) => file.path), new Set([path]));
|
|
6
|
+
const file = files.find((file) => selected.has(file.path));
|
|
7
|
+
return file === undefined
|
|
8
|
+
? undefined
|
|
9
|
+
: { path: file.path, title: file.title, description: file.description };
|
|
10
|
+
}
|
|
11
|
+
/** Immediate canonical children, with descendant counts and inherited manifest language. */
|
|
12
|
+
export function browseCatalogFiles(files, path) {
|
|
13
|
+
const manifests = new Map();
|
|
14
|
+
const overviews = new Map();
|
|
15
|
+
const directories = new Set(files.map((file) => parentDirectory(file.path)));
|
|
16
|
+
const overviewPaths = selectReadmePaths(files.map((file) => file.path), directories);
|
|
17
|
+
const children = new Map();
|
|
18
|
+
const prefix = path.length === 0 ? "" : `${path}/`;
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
if (overviewPaths.has(file.path))
|
|
21
|
+
overviews.set(parentDirectory(file.path), file);
|
|
22
|
+
if (file.overviewOnly === true)
|
|
23
|
+
continue;
|
|
24
|
+
if (file.linkedOnly === true)
|
|
25
|
+
continue;
|
|
26
|
+
if (file.kind === "manifest")
|
|
27
|
+
manifests.set(parentDirectory(file.path), file);
|
|
28
|
+
if (!file.path.startsWith(prefix))
|
|
29
|
+
continue;
|
|
30
|
+
const relative = file.path.slice(prefix.length);
|
|
31
|
+
if (relative.length === 0)
|
|
32
|
+
continue;
|
|
33
|
+
const slash = relative.indexOf("/");
|
|
34
|
+
// This is a whole-segment prefix of an already validated canonical path.
|
|
35
|
+
const childPath = `${prefix}${slash < 0 ? relative : relative.slice(0, slash)}`;
|
|
36
|
+
let child = children.get(childPath);
|
|
37
|
+
if (child === undefined) {
|
|
38
|
+
child = { direct: undefined, skill: undefined, skillCount: 0, documentCount: 0 };
|
|
39
|
+
children.set(childPath, child);
|
|
40
|
+
}
|
|
41
|
+
if (file.path === childPath)
|
|
42
|
+
child.direct = file;
|
|
43
|
+
if (file.kind === "skill") {
|
|
44
|
+
// Counts cover what can be discovered: a hidden copy of a visible skill, or a copy that
|
|
45
|
+
// repeats one, is found by browsing its folder but is not counted (ADR-0024).
|
|
46
|
+
if (file.searchable)
|
|
47
|
+
child.skillCount += 1;
|
|
48
|
+
if (file.path === childPath || file.path === `${childPath}/${SKILL_MANIFEST_FILE}`) {
|
|
49
|
+
child.skill = file;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (file.searchable &&
|
|
53
|
+
file.skillDir === undefined &&
|
|
54
|
+
(file.kind === "markdown" || file.kind === "json")) {
|
|
55
|
+
child.documentCount += 1;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const result = [];
|
|
59
|
+
for (const [childPath, child] of children) {
|
|
60
|
+
const { direct, skill } = child;
|
|
61
|
+
if (direct?.kind === "manifest")
|
|
62
|
+
continue;
|
|
63
|
+
const ownManifest = manifests.get(childPath);
|
|
64
|
+
const overview = overviews.get(skill === undefined ? childPath : parentDirectory(skill.path));
|
|
65
|
+
let ancestor = childPath;
|
|
66
|
+
let language = null;
|
|
67
|
+
while (true) {
|
|
68
|
+
const declared = manifests.get(ancestor)?.language;
|
|
69
|
+
if (declared !== undefined) {
|
|
70
|
+
language = declared;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
if (ancestor === ROOT_PATH)
|
|
74
|
+
break;
|
|
75
|
+
ancestor = parentDirectory(ancestor);
|
|
76
|
+
}
|
|
77
|
+
result.push({
|
|
78
|
+
...(skill === undefined ? {} : { browsePath: parentDirectory(skill.path) }),
|
|
79
|
+
...(overview === undefined ? {} : { overviewPath: overview.path }),
|
|
80
|
+
...(skill?.license === undefined ? {} : { license: skill.license }),
|
|
81
|
+
kind: skill !== undefined ? "skill" : direct === undefined ? "directory" : "file",
|
|
82
|
+
path: skill?.path ?? childPath,
|
|
83
|
+
name: skill?.name ?? ownManifest?.name ?? direct?.title ?? overview?.title ?? null,
|
|
84
|
+
description: skill?.description ??
|
|
85
|
+
ownManifest?.description ??
|
|
86
|
+
direct?.description ??
|
|
87
|
+
overview?.description ??
|
|
88
|
+
null,
|
|
89
|
+
skillCount: child.skillCount,
|
|
90
|
+
documentCount: child.documentCount,
|
|
91
|
+
size: (skill ?? direct)?.size ?? null,
|
|
92
|
+
manifestPath: ownManifest?.path ?? null,
|
|
93
|
+
language,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return result.sort((a, b) => Number(a.kind === "file") - Number(b.kind === "file") ||
|
|
97
|
+
(a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=browse-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browse-tree.js","sourceRoot":"","sources":["../src/browse-tree.ts"],"names":[],"mappings":"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"}
|