@grimoire-rs/indexer 0.1.8 → 0.2.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 +38 -0
- package/dist/cli/init.js +1 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/config.d.ts +21 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -2
- package/dist/config.js.map +1 -1
- package/dist/enrich/index.d.ts.map +1 -1
- package/dist/enrich/index.js +62 -0
- package/dist/enrich/index.js.map +1 -1
- package/dist/renderer/astro/components/BrandMark.d.ts +14 -0
- package/dist/renderer/astro/components/BrandMark.d.ts.map +1 -0
- package/dist/renderer/astro/components/BrandMark.js +16 -0
- package/dist/renderer/astro/components/BrandMark.js.map +1 -0
- package/dist/renderer/astro/components/BrandMark.tsx +19 -0
- package/dist/renderer/astro/components/Catalog.d.ts.map +1 -1
- package/dist/renderer/astro/components/Catalog.js +310 -18
- package/dist/renderer/astro/components/Catalog.js.map +1 -1
- package/dist/renderer/astro/components/Catalog.tsx +445 -63
- package/dist/renderer/astro/components/CommandField.astro +43 -0
- package/dist/renderer/astro/components/PickerMenu.astro +68 -0
- package/dist/renderer/astro/components/VersionMenu.astro +6 -2
- package/dist/renderer/astro/content.config.ts +23 -5
- package/dist/renderer/astro/layouts/Base.astro +794 -66
- package/dist/renderer/astro/lib/catalog.d.ts +24 -0
- package/dist/renderer/astro/lib/catalog.d.ts.map +1 -1
- package/dist/renderer/astro/lib/catalog.js +62 -0
- package/dist/renderer/astro/lib/catalog.js.map +1 -1
- package/dist/renderer/astro/lib/catalog.ts +62 -0
- package/dist/renderer/astro/lib/code.d.ts +22 -0
- package/dist/renderer/astro/lib/code.d.ts.map +1 -0
- package/dist/renderer/astro/lib/code.js +21 -0
- package/dist/renderer/astro/lib/code.js.map +1 -0
- package/dist/renderer/astro/lib/code.ts +21 -0
- package/dist/renderer/astro/pages/index.astro +144 -36
- package/dist/renderer/astro/pages/p/[...slug].astro +403 -55
- package/dist/renderer/index.d.ts +23 -0
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +117 -30
- package/dist/renderer/index.js.map +1 -1
- package/package.json +5 -1
- package/dist/renderer/astro/components/CopyButton.astro +0 -24
|
@@ -4,4 +4,28 @@ export declare function compareVersions(a: string, b: string): number;
|
|
|
4
4
|
export declare function timeAgo(iso: string): string;
|
|
5
5
|
/** `vscode://<publisher.extension>/open?repo=<ref>`, or null when disabled. */
|
|
6
6
|
export declare function vscodeUrl(extension: string | null, ref: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* `vscode://<publisher.extension>/add-registry?index=<url>&alias=<name>` — the
|
|
9
|
+
* one-click counterpart of the `grim config registry add` line beside it.
|
|
10
|
+
*
|
|
11
|
+
* Null unless the link would actually work: the handler takes https only (an
|
|
12
|
+
* index locator is fetched with whatever credentials the user configures for
|
|
13
|
+
* it), refuses embedded credentials, and caps the URL at 2048 characters.
|
|
14
|
+
* Checking here keeps a broken button off the page rather than putting the
|
|
15
|
+
* failure in the user's hands.
|
|
16
|
+
*/
|
|
17
|
+
export declare function addRegistryUrl(extension: string | null, registry: {
|
|
18
|
+
alias: string;
|
|
19
|
+
index: string;
|
|
20
|
+
} | null): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* A bundle member's `id` resolved to the reference the index stores.
|
|
23
|
+
*
|
|
24
|
+
* grim writes members relative to the bundle itself — `../skills/grim-usage:0`
|
|
25
|
+
* — so a member published alongside its bundle stays correct wherever the
|
|
26
|
+
* whole namespace is mirrored. The catalog keys on absolute, untagged refs,
|
|
27
|
+
* which is what this returns; an id that is already absolute passes through
|
|
28
|
+
* with only its tag or digest removed.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveMemberRef(bundleRef: string, id: string): string;
|
|
7
31
|
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAWpF;AAID,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5D;AAcD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS3C;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E"}
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAWpF;AAID,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5D;AAcD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS3C;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E;AAUD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAChD,MAAM,GAAG,IAAI,CAYf;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAgBtE"}
|
|
@@ -58,4 +58,66 @@ export function timeAgo(iso) {
|
|
|
58
58
|
export function vscodeUrl(extension, ref) {
|
|
59
59
|
return extension ? `vscode://${extension}/open?repo=${encodeURIComponent(ref)}` : null;
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Alias charset the extension's `/add-registry` handler accepts. It has to be
|
|
63
|
+
* a TOML bare key and safe as a CLI argument, so it refuses a link rather
|
|
64
|
+
* than escaping one. Mirrored here so a config that cannot produce a working
|
|
65
|
+
* link renders no button at all, instead of one that silently does nothing.
|
|
66
|
+
*/
|
|
67
|
+
const REGISTRY_ALIAS = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
|
|
68
|
+
/**
|
|
69
|
+
* `vscode://<publisher.extension>/add-registry?index=<url>&alias=<name>` — the
|
|
70
|
+
* one-click counterpart of the `grim config registry add` line beside it.
|
|
71
|
+
*
|
|
72
|
+
* Null unless the link would actually work: the handler takes https only (an
|
|
73
|
+
* index locator is fetched with whatever credentials the user configures for
|
|
74
|
+
* it), refuses embedded credentials, and caps the URL at 2048 characters.
|
|
75
|
+
* Checking here keeps a broken button off the page rather than putting the
|
|
76
|
+
* failure in the user's hands.
|
|
77
|
+
*/
|
|
78
|
+
export function addRegistryUrl(extension, registry) {
|
|
79
|
+
if (!extension || !registry || !REGISTRY_ALIAS.test(registry.alias))
|
|
80
|
+
return null;
|
|
81
|
+
let url;
|
|
82
|
+
try {
|
|
83
|
+
url = new URL(registry.index);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "")
|
|
89
|
+
return null;
|
|
90
|
+
if (url.href.length > 2048)
|
|
91
|
+
return null;
|
|
92
|
+
const query = new URLSearchParams({ index: url.href, alias: registry.alias });
|
|
93
|
+
return `vscode://${extension}/add-registry?${query.toString()}`;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A bundle member's `id` resolved to the reference the index stores.
|
|
97
|
+
*
|
|
98
|
+
* grim writes members relative to the bundle itself — `../skills/grim-usage:0`
|
|
99
|
+
* — so a member published alongside its bundle stays correct wherever the
|
|
100
|
+
* whole namespace is mirrored. The catalog keys on absolute, untagged refs,
|
|
101
|
+
* which is what this returns; an id that is already absolute passes through
|
|
102
|
+
* with only its tag or digest removed.
|
|
103
|
+
*/
|
|
104
|
+
export function resolveMemberRef(bundleRef, id) {
|
|
105
|
+
const pinned = id.split("@")[0] ?? id;
|
|
106
|
+
// A tag is a colon *after* the last slash — `localhost:5000/x` is a host,
|
|
107
|
+
// not a tag.
|
|
108
|
+
const slash = pinned.lastIndexOf("/");
|
|
109
|
+
const colon = pinned.lastIndexOf(":");
|
|
110
|
+
const ref = colon > slash ? pinned.slice(0, colon) : pinned;
|
|
111
|
+
if (!ref.startsWith("."))
|
|
112
|
+
return ref;
|
|
113
|
+
// Relative: resolve against the directory the bundle itself lives in.
|
|
114
|
+
const segments = bundleRef.split("/").slice(0, -1);
|
|
115
|
+
for (const segment of ref.split("/")) {
|
|
116
|
+
if (segment === "..")
|
|
117
|
+
segments.pop();
|
|
118
|
+
else if (segment !== "." && segment !== "")
|
|
119
|
+
segments.push(segment);
|
|
120
|
+
}
|
|
121
|
+
return segments.join("/");
|
|
122
|
+
}
|
|
61
123
|
//# sourceMappingURL=catalog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAQtC,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,MAAM,UAAU,cAAc,CAAC,OAA2B,EAAE,IAAc;IACxE,MAAM,MAAM,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,yEAAyE;IACzE,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAC/E,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAC5C,CAAC;IACF,2EAA2E;IAC3E,qDAAqD;IACrD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,yEAAyE;AACzE,8CAA8C;AAC9C,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,CAAS;IAClD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAChE,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,EAAE,KAAK,EAAE;gBAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAChC,CAAC;aAAM,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iEAAiE;AACjE,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACnE,MAAM,cAAc,GAA4C;IAC9D,CAAC,EAAE,EAAE,SAAS,CAAC;IACf,CAAC,EAAE,EAAE,SAAS,CAAC;IACf,CAAC,EAAE,EAAE,OAAO,CAAC;IACb,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,OAAO,EAAE,OAAO,CAAC;IAClB,CAAC,EAAE,EAAE,QAAQ,CAAC;IACd,CAAC,QAAQ,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC,CAAC,wCAAwC;IAC7E,IAAI,QAAQ,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;IACxC,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,cAAc,EAAE,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,MAAM;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QAC/E,QAAQ,IAAI,MAAM,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC;AACnD,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,SAAwB,EAAE,GAAW;IAC7D,OAAO,SAAS,CAAC,CAAC,CAAC,YAAY,SAAS,cAAc,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACzF,CAAC;AAED;;;;;GAKG;AACH,MAAM,cAAc,GAAG,kCAAkC,CAAC;AAE1D;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,SAAwB,EACxB,QAAiD;IAEjD,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjF,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACzF,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9E,OAAO,YAAY,SAAS,iBAAiB,KAAK,CAAC,QAAQ,EAAE,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,EAAU;IAC5D,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,0EAA0E;IAC1E,aAAa;IACb,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5D,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC;IAErC,sEAAsE;IACtE,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACnD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,IAAI,OAAO,KAAK,IAAI;YAAE,QAAQ,CAAC,GAAG,EAAE,CAAC;aAChC,IAAI,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,EAAE;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -67,3 +67,65 @@ export function timeAgo(iso: string): string {
|
|
|
67
67
|
export function vscodeUrl(extension: string | null, ref: string): string | null {
|
|
68
68
|
return extension ? `vscode://${extension}/open?repo=${encodeURIComponent(ref)}` : null;
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Alias charset the extension's `/add-registry` handler accepts. It has to be
|
|
73
|
+
* a TOML bare key and safe as a CLI argument, so it refuses a link rather
|
|
74
|
+
* than escaping one. Mirrored here so a config that cannot produce a working
|
|
75
|
+
* link renders no button at all, instead of one that silently does nothing.
|
|
76
|
+
*/
|
|
77
|
+
const REGISTRY_ALIAS = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* `vscode://<publisher.extension>/add-registry?index=<url>&alias=<name>` — the
|
|
81
|
+
* one-click counterpart of the `grim config registry add` line beside it.
|
|
82
|
+
*
|
|
83
|
+
* Null unless the link would actually work: the handler takes https only (an
|
|
84
|
+
* index locator is fetched with whatever credentials the user configures for
|
|
85
|
+
* it), refuses embedded credentials, and caps the URL at 2048 characters.
|
|
86
|
+
* Checking here keeps a broken button off the page rather than putting the
|
|
87
|
+
* failure in the user's hands.
|
|
88
|
+
*/
|
|
89
|
+
export function addRegistryUrl(
|
|
90
|
+
extension: string | null,
|
|
91
|
+
registry: { alias: string; index: string } | null,
|
|
92
|
+
): string | null {
|
|
93
|
+
if (!extension || !registry || !REGISTRY_ALIAS.test(registry.alias)) return null;
|
|
94
|
+
let url: URL;
|
|
95
|
+
try {
|
|
96
|
+
url = new URL(registry.index);
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "") return null;
|
|
101
|
+
if (url.href.length > 2048) return null;
|
|
102
|
+
const query = new URLSearchParams({ index: url.href, alias: registry.alias });
|
|
103
|
+
return `vscode://${extension}/add-registry?${query.toString()}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* A bundle member's `id` resolved to the reference the index stores.
|
|
108
|
+
*
|
|
109
|
+
* grim writes members relative to the bundle itself — `../skills/grim-usage:0`
|
|
110
|
+
* — so a member published alongside its bundle stays correct wherever the
|
|
111
|
+
* whole namespace is mirrored. The catalog keys on absolute, untagged refs,
|
|
112
|
+
* which is what this returns; an id that is already absolute passes through
|
|
113
|
+
* with only its tag or digest removed.
|
|
114
|
+
*/
|
|
115
|
+
export function resolveMemberRef(bundleRef: string, id: string): string {
|
|
116
|
+
const pinned = id.split("@")[0] ?? id;
|
|
117
|
+
// A tag is a colon *after* the last slash — `localhost:5000/x` is a host,
|
|
118
|
+
// not a tag.
|
|
119
|
+
const slash = pinned.lastIndexOf("/");
|
|
120
|
+
const colon = pinned.lastIndexOf(":");
|
|
121
|
+
const ref = colon > slash ? pinned.slice(0, colon) : pinned;
|
|
122
|
+
if (!ref.startsWith(".")) return ref;
|
|
123
|
+
|
|
124
|
+
// Relative: resolve against the directory the bundle itself lives in.
|
|
125
|
+
const segments = bundleRef.split("/").slice(0, -1);
|
|
126
|
+
for (const segment of ref.split("/")) {
|
|
127
|
+
if (segment === "..") segments.pop();
|
|
128
|
+
else if (segment !== "." && segment !== "") segments.push(segment);
|
|
129
|
+
}
|
|
130
|
+
return segments.join("/");
|
|
131
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Light and dark code themes.
|
|
3
|
+
*
|
|
4
|
+
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
5
|
+
* with — so nothing here adds a library; this only stops the two consumers
|
|
6
|
+
* drifting onto different themes. The markdown pipeline reads it through
|
|
7
|
+
* `astro.config`'s `shikiConfig`, and the `<Code>` component on the package
|
|
8
|
+
* page takes it as a prop.
|
|
9
|
+
*
|
|
10
|
+
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
11
|
+
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
12
|
+
* dark one as a `--shiki-dark` custom property on the same token, and
|
|
13
|
+
* `Base.astro` swaps between them with the rest of the palette.
|
|
14
|
+
*
|
|
15
|
+
* GitHub's pair, deliberately boring: Shiki's best-tested themes, and neutral
|
|
16
|
+
* enough to sit on this page without fighting the accent.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SHIKI_THEMES: {
|
|
19
|
+
readonly light: "github-light";
|
|
20
|
+
readonly dark: "github-dark";
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/code.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY;;;CAA0D,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 The Grimoire Authors
|
|
3
|
+
/**
|
|
4
|
+
* Light and dark code themes.
|
|
5
|
+
*
|
|
6
|
+
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
7
|
+
* with — so nothing here adds a library; this only stops the two consumers
|
|
8
|
+
* drifting onto different themes. The markdown pipeline reads it through
|
|
9
|
+
* `astro.config`'s `shikiConfig`, and the `<Code>` component on the package
|
|
10
|
+
* page takes it as a prop.
|
|
11
|
+
*
|
|
12
|
+
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
13
|
+
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
14
|
+
* dark one as a `--shiki-dark` custom property on the same token, and
|
|
15
|
+
* `Base.astro` swaps between them with the rest of the palette.
|
|
16
|
+
*
|
|
17
|
+
* GitHub's pair, deliberately boring: Shiki's best-tested themes, and neutral
|
|
18
|
+
* enough to sit on this page without fighting the accent.
|
|
19
|
+
*/
|
|
20
|
+
export const SHIKI_THEMES = { light: "github-light", dark: "github-dark" };
|
|
21
|
+
//# sourceMappingURL=code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code.js","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/code.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAEtC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAW,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 The Grimoire Authors
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Light and dark code themes.
|
|
6
|
+
*
|
|
7
|
+
* Shiki is what Astro already ships — the same highlighter VS Code renders
|
|
8
|
+
* with — so nothing here adds a library; this only stops the two consumers
|
|
9
|
+
* drifting onto different themes. The markdown pipeline reads it through
|
|
10
|
+
* `astro.config`'s `shikiConfig`, and the `<Code>` component on the package
|
|
11
|
+
* page takes it as a prop.
|
|
12
|
+
*
|
|
13
|
+
* A *pair*, not one theme: with a single theme a block stays dark on a light
|
|
14
|
+
* page. Given two, Shiki writes the light colour as an inline style and the
|
|
15
|
+
* dark one as a `--shiki-dark` custom property on the same token, and
|
|
16
|
+
* `Base.astro` swaps between them with the rest of the palette.
|
|
17
|
+
*
|
|
18
|
+
* GitHub's pair, deliberately boring: Shiki's best-tested themes, and neutral
|
|
19
|
+
* enough to sit on this page without fighting the accent.
|
|
20
|
+
*/
|
|
21
|
+
export const SHIKI_THEMES = { light: "github-light", dark: "github-dark" } as const;
|
|
@@ -1,29 +1,75 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Base from "../layouts/Base.astro";
|
|
3
3
|
import Catalog from "../components/Catalog.tsx";
|
|
4
|
-
import
|
|
4
|
+
import CommandField from "../components/CommandField.astro";
|
|
5
|
+
import PickerMenu from "../components/PickerMenu.astro";
|
|
6
|
+
import { BrandMark } from "../components/BrandMark.tsx";
|
|
7
|
+
import { FolderRoot, Globe } from "lucide-preact";
|
|
8
|
+
import { addRegistryUrl } from "../lib/catalog";
|
|
5
9
|
import { data } from "../lib/data";
|
|
10
|
+
import {
|
|
11
|
+
mdiApple,
|
|
12
|
+
mdiConsole,
|
|
13
|
+
mdiMicrosoftVisualStudioCode,
|
|
14
|
+
mdiMicrosoftWindows,
|
|
15
|
+
mdiPenguin,
|
|
16
|
+
} from "@mdi/js";
|
|
6
17
|
|
|
7
18
|
const { config, packages } = data;
|
|
8
19
|
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
// One-click counterpart of the `grim config registry add` line: the VS Code
|
|
21
|
+
// extension registers a URI handler that writes the registry after a modal
|
|
22
|
+
// confirmation. Null whenever the link would not work — see `addRegistryUrl`.
|
|
23
|
+
const addRegistry = addRegistryUrl(config.vscodeExtension, config.registry);
|
|
24
|
+
|
|
25
|
+
// The extension's own marketplace page — the one thing on this page that
|
|
26
|
+
// helps a visitor who does not have it installed yet.
|
|
27
|
+
const marketplace = config.vscodeExtension
|
|
28
|
+
? `https://marketplace.visualstudio.com/items?itemName=${config.vscodeExtension}`
|
|
29
|
+
: null;
|
|
30
|
+
|
|
31
|
+
// The "add this index" ergonomic (`helm repo add`): the one command a
|
|
32
|
+
// visitor needs to point their own grim at *this* index. Absent `registry`
|
|
33
|
+
// config means the index has no public URL to hand out, so the block is
|
|
34
|
+
// omitted rather than guessed.
|
|
35
|
+
const addCommand = config.registry
|
|
36
|
+
? `grim config registry add ${config.registry.alias} --index ${config.registry.index}`
|
|
37
|
+
: null;
|
|
38
|
+
|
|
39
|
+
// One installer row usually covers several platforms ("Linux / macOS"), and
|
|
40
|
+
// the toggle reads better as the platforms themselves than as the config's
|
|
41
|
+
// row labels — so a row expands into one button per platform it names, all
|
|
42
|
+
// pointing at the same command. A row naming none (a custom label) keeps a
|
|
43
|
+
// single generic button, so an unrecognized platform is never dropped.
|
|
44
|
+
//
|
|
45
|
+
// `mdiPenguin`, not `mdiLinux`: Tux's own silhouette is a solid mass that
|
|
46
|
+
// reads as an indistinct blob at 16px, where the plainer penguin keeps its
|
|
47
|
+
// outline. Still a brand mark from the same set, so it sits beside Apple
|
|
48
|
+
// and Windows without a weight change.
|
|
49
|
+
const PLATFORMS = [
|
|
50
|
+
{ match: /linux/i, name: "Linux", path: mdiPenguin },
|
|
51
|
+
{ match: /mac|darwin|osx|apple/i, name: "macOS", path: mdiApple },
|
|
52
|
+
{ match: /win/i, name: "Windows", path: mdiMicrosoftWindows },
|
|
53
|
+
];
|
|
54
|
+
const installChoices = config.install.flatMap((row) => {
|
|
55
|
+
const hits = PLATFORMS.filter((p) => p.match.test(row.os));
|
|
56
|
+
return hits.length > 0
|
|
57
|
+
? hits.map((p) => ({ name: p.name, path: p.path, command: row.command }))
|
|
58
|
+
: [{ name: row.os, path: mdiConsole, command: row.command }];
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Registry scope, the same two-way choice the package cards offer and drawn
|
|
62
|
+
// with the same two Lucide glyphs. Global leads: someone arriving from an
|
|
63
|
+
// index website wants this index available everywhere, not wired into
|
|
64
|
+
// whichever directory happens to be open — and it is also the scope that
|
|
65
|
+
// works with no project at all.
|
|
66
|
+
// `--global` leads rather than trails: it is a top-level flag, and appended
|
|
67
|
+
// after a long `--index <url>` it fell off the end of the line, so switching
|
|
68
|
+
// scope looked like it changed nothing at all.
|
|
69
|
+
const scopeChoices = addCommand
|
|
14
70
|
? [
|
|
15
|
-
{
|
|
16
|
-
|
|
17
|
-
command: `grim config registry add ${config.registry.alias} --index ${config.registry.index}`,
|
|
18
|
-
block: false,
|
|
19
|
-
label: "Copy the registry add command",
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
os: "grimoire.toml",
|
|
23
|
-
command: `[[registries]]\nalias = "${config.registry.alias}"\nindex = "${config.registry.index}"`,
|
|
24
|
-
block: true,
|
|
25
|
-
label: "Copy the registries TOML entry",
|
|
26
|
-
},
|
|
71
|
+
{ name: "Global", command: `grim --global ${addCommand.slice("grim ".length)}`, Icon: Globe },
|
|
72
|
+
{ name: "Project", command: addCommand, Icon: FolderRoot },
|
|
27
73
|
]
|
|
28
74
|
: [];
|
|
29
75
|
---
|
|
@@ -37,33 +83,95 @@ const registryRows = config.registry
|
|
|
37
83
|
config.installDocsUrl && (
|
|
38
84
|
<Fragment>
|
|
39
85
|
{" "}
|
|
40
|
-
|
|
41
|
-
<
|
|
86
|
+
<a href={config.installDocsUrl}>Install grim</a>, add this index,
|
|
87
|
+
then <code>grim add</code> anything below.
|
|
42
88
|
</Fragment>
|
|
43
89
|
)
|
|
44
90
|
}
|
|
45
91
|
</p>
|
|
92
|
+
{/* Beside the description, not under it: getting set up is a sidebar to
|
|
93
|
+
reading what this index is. Two labelled rows of one shape — the
|
|
94
|
+
command, then the ways to act on it, inside a single border. */}
|
|
46
95
|
{
|
|
47
|
-
(
|
|
48
|
-
<div class="
|
|
49
|
-
{
|
|
50
|
-
<
|
|
51
|
-
<span class="
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
96
|
+
(installChoices.length > 0 || addCommand || addRegistry) && (
|
|
97
|
+
<div class="hero-side">
|
|
98
|
+
{installChoices.length > 0 && (
|
|
99
|
+
<Fragment>
|
|
100
|
+
<span class="side-label">install grim</span>
|
|
101
|
+
<div class="cmd-bar" data-os-switch data-os-detect data-os-noun="install command">
|
|
102
|
+
{installChoices.length > 1 && (
|
|
103
|
+
<PickerMenu
|
|
104
|
+
choices={installChoices}
|
|
105
|
+
title="Platform"
|
|
106
|
+
label="Choose your platform"
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
<CommandField
|
|
110
|
+
value={installChoices[0].command}
|
|
111
|
+
name={`${installChoices[0].name} install command`}
|
|
112
|
+
label="Copy the install command"
|
|
113
|
+
/>
|
|
114
|
+
{marketplace && (
|
|
115
|
+
<a
|
|
116
|
+
class="seg brand-link"
|
|
117
|
+
href={marketplace}
|
|
118
|
+
target="_blank"
|
|
119
|
+
rel="noopener noreferrer"
|
|
120
|
+
title="Get the VS Code extension"
|
|
121
|
+
aria-label="Get the VS Code extension from the marketplace"
|
|
122
|
+
>
|
|
123
|
+
<BrandMark path={mdiMicrosoftVisualStudioCode} />
|
|
124
|
+
</a>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</Fragment>
|
|
128
|
+
)}
|
|
129
|
+
{(addCommand || addRegistry) && (
|
|
130
|
+
<Fragment>
|
|
131
|
+
<span class="side-label">add registry</span>
|
|
132
|
+
<div class="cmd-bar" data-os-switch data-os-noun="registry add command">
|
|
133
|
+
{scopeChoices.length > 0 && (
|
|
134
|
+
<PickerMenu choices={scopeChoices} title="Scope" label="Choose the scope" />
|
|
135
|
+
)}
|
|
136
|
+
{scopeChoices.length > 0 && (
|
|
137
|
+
<CommandField
|
|
138
|
+
value={scopeChoices[0].command}
|
|
139
|
+
name={`${scopeChoices[0].name} registry add command`}
|
|
140
|
+
label="Copy the registry add command"
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
{addRegistry && (
|
|
144
|
+
<a
|
|
145
|
+
class="seg brand-link"
|
|
146
|
+
href={addRegistry}
|
|
147
|
+
title="Add this index via VS Code"
|
|
148
|
+
aria-label="Add this index via VS Code"
|
|
149
|
+
>
|
|
150
|
+
<BrandMark path={mdiMicrosoftVisualStudioCode} />
|
|
151
|
+
</a>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
</Fragment>
|
|
155
|
+
)}
|
|
63
156
|
</div>
|
|
64
157
|
)
|
|
65
158
|
}
|
|
66
159
|
</div>
|
|
67
160
|
|
|
161
|
+
{/* Right after the bar, on purpose: the layout's picker script sits at the
|
|
162
|
+
end of the document, past the whole catalog, and the browser can paint
|
|
163
|
+
before it runs — long enough to show a Linux command to someone on
|
|
164
|
+
Windows. Here it lands in the same parse as the hero. A platform the
|
|
165
|
+
bar does not offer leaves the configured first choice alone. */}
|
|
166
|
+
<script is:inline>
|
|
167
|
+
for (const bar of document.querySelectorAll("[data-os-detect]")) {
|
|
168
|
+
const host = window.__grimHostOs();
|
|
169
|
+
const match = [...bar.querySelectorAll("[data-os-pick]")].find(
|
|
170
|
+
(p) => p.dataset.osName === host,
|
|
171
|
+
);
|
|
172
|
+
if (match) window.__grimPick(bar, match);
|
|
173
|
+
}
|
|
174
|
+
</script>
|
|
175
|
+
|
|
68
176
|
<Catalog client:load packages={packages} vscodeExtension={config.vscodeExtension} />
|
|
69
177
|
</Base>
|