@stigmer/cli 3.16.0 → 3.17.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/commands/agent-exec-flags.d.ts +2 -5
- package/commands/agent-exec-flags.d.ts.map +1 -1
- package/commands/agent-exec-flags.js +6 -13
- package/commands/agent-exec-flags.js.map +1 -1
- package/commands/connect.js +1 -1
- package/commands/connect.js.map +1 -1
- package/commands/install.d.ts +3 -0
- package/commands/install.d.ts.map +1 -0
- package/commands/install.js +68 -0
- package/commands/install.js.map +1 -0
- package/commands/marketplace.d.ts +3 -0
- package/commands/marketplace.d.ts.map +1 -0
- package/commands/marketplace.js +94 -0
- package/commands/marketplace.js.map +1 -0
- package/commands/push.js +2 -7
- package/commands/push.js.map +1 -1
- package/commands/run.js +0 -3
- package/commands/run.js.map +1 -1
- package/config/config.d.ts +19 -0
- package/config/config.d.ts.map +1 -1
- package/config/config.js +15 -0
- package/config/config.js.map +1 -1
- package/config/index.d.ts +1 -1
- package/config/index.d.ts.map +1 -1
- package/config/index.js.map +1 -1
- package/local/bootstrap.d.ts +21 -0
- package/local/bootstrap.d.ts.map +1 -0
- package/local/bootstrap.js +88 -0
- package/local/bootstrap.js.map +1 -0
- package/local/daemon/launch.d.ts +2 -2
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/daemon/launch.js +4 -34
- package/local/daemon/launch.js.map +1 -1
- package/local/daemon/process.d.ts +1 -1
- package/local/plugins/defaults.d.ts +35 -0
- package/local/plugins/defaults.d.ts.map +1 -0
- package/local/plugins/defaults.js +83 -0
- package/local/plugins/defaults.js.map +1 -0
- package/local/seedpack/content.d.ts +2 -1
- package/local/seedpack/content.d.ts.map +1 -1
- package/local/seedpack/content.js +5 -34
- package/local/seedpack/content.js.map +1 -1
- package/marketplace/config.d.ts +59 -0
- package/marketplace/config.d.ts.map +1 -0
- package/marketplace/config.js +162 -0
- package/marketplace/config.js.map +1 -0
- package/marketplace/github.d.ts +31 -0
- package/marketplace/github.d.ts.map +1 -0
- package/marketplace/github.js +203 -0
- package/marketplace/github.js.map +1 -0
- package/marketplace/index.d.ts +8 -0
- package/marketplace/index.d.ts.map +1 -0
- package/marketplace/index.js +12 -0
- package/marketplace/index.js.map +1 -0
- package/marketplace/install.d.ts +28 -0
- package/marketplace/install.d.ts.map +1 -0
- package/marketplace/install.js +109 -0
- package/marketplace/install.js.map +1 -0
- package/marketplace/materialize.d.ts +19 -0
- package/marketplace/materialize.d.ts.map +1 -0
- package/marketplace/materialize.js +53 -0
- package/marketplace/materialize.js.map +1 -0
- package/marketplace/official.d.ts +28 -0
- package/marketplace/official.d.ts.map +1 -0
- package/marketplace/official.js +86 -0
- package/marketplace/official.js.map +1 -0
- package/marketplace/read.d.ts +17 -0
- package/marketplace/read.d.ts.map +1 -0
- package/marketplace/read.js +44 -0
- package/marketplace/read.js.map +1 -0
- package/marketplace/ref.d.ts +13 -0
- package/marketplace/ref.d.ts.map +1 -0
- package/marketplace/ref.js +54 -0
- package/marketplace/ref.js.map +1 -0
- package/marketplace/render.d.ts +22 -0
- package/marketplace/render.d.ts.map +1 -0
- package/marketplace/render.js +118 -0
- package/marketplace/render.js.map +1 -0
- package/output/ndjson.js +1 -1
- package/output/ndjson.js.map +1 -1
- package/package.json +7 -6
- package/program.d.ts.map +1 -1
- package/program.js +4 -2
- package/program.js.map +1 -1
- package/resources/ignore/index.d.ts +2 -4
- package/resources/ignore/index.d.ts.map +1 -1
- package/resources/ignore/index.js +5 -5
- package/resources/ignore/index.js.map +1 -1
- package/resources/ignore/matcher.d.ts +2 -35
- package/resources/ignore/matcher.d.ts.map +1 -1
- package/resources/ignore/matcher.js +25 -109
- package/resources/ignore/matcher.js.map +1 -1
- package/resources/plugin.d.ts +50 -18
- package/resources/plugin.d.ts.map +1 -1
- package/resources/plugin.js +73 -74
- package/resources/plugin.js.map +1 -1
- package/resources/run/agent-exec.js +1 -1
- package/resources/run/agent-exec.js.map +1 -1
- package/resources/run/prepare.d.ts +8 -19
- package/resources/run/prepare.d.ts.map +1 -1
- package/resources/run/prepare.js +4 -4
- package/resources/run/prepare.js.map +1 -1
- package/resources/skill.d.ts +2 -2
- package/resources/skill.d.ts.map +1 -1
- package/resources/skill.js +6 -10
- package/resources/skill.js.map +1 -1
- package/src/commands/agent-exec-flags.ts +6 -12
- package/src/commands/connect.ts +1 -1
- package/src/commands/install.test.ts +289 -0
- package/src/commands/install.ts +108 -0
- package/src/commands/marketplace.test.ts +200 -0
- package/src/commands/marketplace.ts +131 -0
- package/src/commands/push.ts +5 -10
- package/src/commands/run.ts +0 -3
- package/src/config/config.ts +37 -0
- package/src/config/index.ts +1 -0
- package/src/local/bootstrap.test.ts +71 -0
- package/src/local/bootstrap.ts +133 -0
- package/src/local/daemon/launch.ts +5 -40
- package/src/local/daemon/process.ts +1 -1
- package/src/local/plugins/defaults.test.ts +238 -0
- package/src/local/plugins/defaults.ts +135 -0
- package/src/local/seedpack/content.ts +11 -42
- package/src/marketplace/__fixtures__/cursor-marketplace.ts +62 -0
- package/src/marketplace/config.test.ts +245 -0
- package/src/marketplace/config.ts +236 -0
- package/src/marketplace/github.test.ts +318 -0
- package/src/marketplace/github.ts +296 -0
- package/src/marketplace/index.ts +54 -0
- package/src/marketplace/install.test.ts +194 -0
- package/src/marketplace/install.ts +159 -0
- package/src/marketplace/materialize.ts +80 -0
- package/src/marketplace/official.test.ts +107 -0
- package/src/marketplace/official.ts +125 -0
- package/src/marketplace/read.test.ts +94 -0
- package/src/marketplace/read.ts +76 -0
- package/src/marketplace/ref.test.ts +179 -0
- package/src/marketplace/ref.ts +74 -0
- package/src/marketplace/render.ts +154 -0
- package/src/output/ndjson.ts +1 -1
- package/src/program.test.ts +4 -13
- package/src/program.ts +4 -2
- package/src/resources/ignore/ignore.test.ts +23 -100
- package/src/resources/ignore/index.ts +11 -8
- package/src/resources/ignore/matcher.ts +33 -136
- package/src/resources/plugin.test.ts +35 -6
- package/src/resources/plugin.ts +132 -85
- package/src/resources/run/agent-exec.ts +1 -1
- package/src/resources/run/prepare.test.ts +4 -18
- package/src/resources/run/prepare.ts +12 -24
- package/src/resources/skill.ts +6 -10
- package/commands/draft.d.ts +0 -3
- package/commands/draft.d.ts.map +0 -1
- package/commands/draft.js +0 -115
- package/commands/draft.js.map +0 -1
- package/resources/ignore/defaults.d.ts +0 -2
- package/resources/ignore/defaults.d.ts.map +0 -1
- package/resources/ignore/defaults.js +0 -140
- package/resources/ignore/defaults.js.map +0 -1
- package/resources/ignore/match.d.ts +0 -3
- package/resources/ignore/match.d.ts.map +0 -1
- package/resources/ignore/match.js +0 -166
- package/resources/ignore/match.js.map +0 -1
- package/resources/ignore/pattern.d.ts +0 -13
- package/resources/ignore/pattern.d.ts.map +0 -1
- package/resources/ignore/pattern.js +0 -118
- package/resources/ignore/pattern.js.map +0 -1
- package/src/commands/draft.ts +0 -189
- package/src/resources/ignore/defaults.ts +0 -155
- package/src/resources/ignore/match.ts +0 -158
- package/src/resources/ignore/pattern.ts +0 -131
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// The marketplaces a CLI knows: the official one, built in, and the ones a
|
|
2
|
+
// user added under the `marketplaces` key of ~/.stigmer/config.yaml.
|
|
3
|
+
//
|
|
4
|
+
// A marketplace is client-side configuration, never a server resource: the
|
|
5
|
+
// server only ever sees the plugin archive a client pushes. That is why the
|
|
6
|
+
// list lives beside the named backends and the context, and why `stigmer
|
|
7
|
+
// marketplace` is a noun group like `config` and `auth`.
|
|
8
|
+
//
|
|
9
|
+
// The config module keeps the on-disk entry loose (`MarketplaceEntryConfig`,
|
|
10
|
+
// every field optional) so a hand-edited entry this CLI cannot read survives
|
|
11
|
+
// the next save; this module is where the entry is narrowed into a
|
|
12
|
+
// `MarketplaceSource` the fetchers act on, and where an unreadable entry
|
|
13
|
+
// becomes a reason `stigmer marketplace list` prints instead of a silent gap.
|
|
14
|
+
import { load as loadConfig, save as saveConfig, } from "../config/index.js";
|
|
15
|
+
import { OFFICIAL_MARKETPLACE_NAME, describeGitHubSource, isOwnerRepo, } from "@stigmer/plugin-package/client";
|
|
16
|
+
import { UsageError } from "../errors/index.js";
|
|
17
|
+
import { isStandalone } from "../runtime.js";
|
|
18
|
+
export { OFFICIAL_MARKETPLACE_NAME, isOwnerRepo };
|
|
19
|
+
export const OFFICIAL_MARKETPLACE = {
|
|
20
|
+
name: OFFICIAL_MARKETPLACE_NAME,
|
|
21
|
+
source: { type: "official" },
|
|
22
|
+
};
|
|
23
|
+
/** Every marketplace the config names, the official one first. */
|
|
24
|
+
export function listMarketplaces(config = loadConfig()) {
|
|
25
|
+
const known = [OFFICIAL_MARKETPLACE];
|
|
26
|
+
const unreadable = [];
|
|
27
|
+
for (const [name, entry] of Object.entries(config.marketplaces ?? {})) {
|
|
28
|
+
const narrowed = narrowEntry(entry);
|
|
29
|
+
if (narrowed.ok)
|
|
30
|
+
known.push({ name, source: narrowed.source });
|
|
31
|
+
else
|
|
32
|
+
unreadable.push({ name, reason: narrowed.reason });
|
|
33
|
+
}
|
|
34
|
+
return { known, unreadable };
|
|
35
|
+
}
|
|
36
|
+
/** The marketplace called `name`, or `undefined`; an unreadable entry refuses with its reason. */
|
|
37
|
+
export function findMarketplace(name, config = loadConfig()) {
|
|
38
|
+
const listing = listMarketplaces(config);
|
|
39
|
+
const known = listing.known.find((marketplace) => marketplace.name === name);
|
|
40
|
+
if (known !== undefined)
|
|
41
|
+
return known;
|
|
42
|
+
const broken = listing.unreadable.find((marketplace) => marketplace.name === name);
|
|
43
|
+
if (broken !== undefined) {
|
|
44
|
+
throw new UsageError(`marketplace '${name}' is configured but cannot be read: ${broken.reason}\n\n` +
|
|
45
|
+
`Fix the entry under 'marketplaces.${name}' in the config file, or remove it with 'stigmer marketplace remove ${name}'.`);
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Record a marketplace under `name` and save. Refuses the reserved name, a
|
|
51
|
+
* name already taken, and a run under `--standalone` (the config file is
|
|
52
|
+
* ignored there, so there is nothing to add to; saving would write a fresh
|
|
53
|
+
* default file over the user's own).
|
|
54
|
+
*/
|
|
55
|
+
export function addMarketplace(name, source) {
|
|
56
|
+
refuseStandalone("add");
|
|
57
|
+
if (name === OFFICIAL_MARKETPLACE_NAME) {
|
|
58
|
+
throw new UsageError(`'${OFFICIAL_MARKETPLACE_NAME}' is the built-in marketplace and cannot be added or replaced\n\n` +
|
|
59
|
+
"Pass --name <other-name> to add this source under a different name.");
|
|
60
|
+
}
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
if (config.marketplaces?.[name] !== undefined) {
|
|
63
|
+
throw new UsageError(`a marketplace named '${name}' is already configured\n\n` +
|
|
64
|
+
`Remove it first with 'stigmer marketplace remove ${name}', or pass --name <other-name>.`);
|
|
65
|
+
}
|
|
66
|
+
saveConfig({
|
|
67
|
+
...config,
|
|
68
|
+
marketplaces: { ...config.marketplaces, [name]: toEntry(source) },
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Remove the marketplace called `name` and save. Refuses the reserved name and an unknown one. */
|
|
72
|
+
export function removeMarketplace(name) {
|
|
73
|
+
refuseStandalone("remove");
|
|
74
|
+
if (name === OFFICIAL_MARKETPLACE_NAME) {
|
|
75
|
+
throw new UsageError(`'${OFFICIAL_MARKETPLACE_NAME}' is the built-in marketplace and cannot be removed`);
|
|
76
|
+
}
|
|
77
|
+
const config = loadConfig();
|
|
78
|
+
if (config.marketplaces?.[name] === undefined) {
|
|
79
|
+
throw new UsageError(`no marketplace named '${name}' is configured\n\nRun 'stigmer marketplace list' to see the configured names.`);
|
|
80
|
+
}
|
|
81
|
+
const { [name]: _removed, ...rest } = config.marketplaces;
|
|
82
|
+
saveConfig({
|
|
83
|
+
...config,
|
|
84
|
+
marketplaces: Object.keys(rest).length === 0 ? undefined : rest,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function refuseStandalone(verb) {
|
|
88
|
+
if (isStandalone()) {
|
|
89
|
+
throw new UsageError(`--standalone ignores the config file, so there is no marketplace list to ${verb} to\n\n` +
|
|
90
|
+
"Run without --standalone to change the configured marketplaces.");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** The loose on-disk entry as a source, or the reason it is not one. */
|
|
94
|
+
export function narrowEntry(entry) {
|
|
95
|
+
switch (entry.type) {
|
|
96
|
+
case "github": {
|
|
97
|
+
if (typeof entry.repo !== "string" || !isOwnerRepo(entry.repo)) {
|
|
98
|
+
return { ok: false, reason: "type 'github' needs 'repo: owner/repo'" };
|
|
99
|
+
}
|
|
100
|
+
if (entry.ref !== undefined &&
|
|
101
|
+
(typeof entry.ref !== "string" || entry.ref === "")) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
reason: "'ref' must be a non-empty branch, tag or commit",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
ok: true,
|
|
109
|
+
source: {
|
|
110
|
+
type: "github",
|
|
111
|
+
repo: entry.repo,
|
|
112
|
+
...(entry.ref !== undefined && { ref: entry.ref }),
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case "local": {
|
|
117
|
+
if (typeof entry.path !== "string" || entry.path === "") {
|
|
118
|
+
return { ok: false, reason: "type 'local' needs 'path: <directory>'" };
|
|
119
|
+
}
|
|
120
|
+
return { ok: true, source: { type: "local", path: entry.path } };
|
|
121
|
+
}
|
|
122
|
+
case undefined:
|
|
123
|
+
return { ok: false, reason: "no 'type' (expected 'github' or 'local')" };
|
|
124
|
+
default:
|
|
125
|
+
return {
|
|
126
|
+
ok: false,
|
|
127
|
+
reason: `unknown type '${String(entry.type)}' (expected 'github' or 'local')`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function toEntry(source) {
|
|
132
|
+
switch (source.type) {
|
|
133
|
+
case "github":
|
|
134
|
+
return {
|
|
135
|
+
type: "github",
|
|
136
|
+
repo: source.repo,
|
|
137
|
+
...(source.ref !== undefined && { ref: source.ref }),
|
|
138
|
+
};
|
|
139
|
+
case "local":
|
|
140
|
+
return { type: "local", path: source.path };
|
|
141
|
+
default: {
|
|
142
|
+
const exhaustive = source;
|
|
143
|
+
return exhaustive;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** One sentence naming where a source comes from, for lists and sentences. */
|
|
148
|
+
export function describeSource(source) {
|
|
149
|
+
switch (source.type) {
|
|
150
|
+
case "official":
|
|
151
|
+
return "built in";
|
|
152
|
+
case "github":
|
|
153
|
+
return describeGitHubSource(source);
|
|
154
|
+
case "local":
|
|
155
|
+
return source.path;
|
|
156
|
+
default: {
|
|
157
|
+
const exhaustive = source;
|
|
158
|
+
return exhaustive;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/marketplace/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** The caps a repository zipball must fit under; each refusal names the one it hit. */
|
|
2
|
+
export declare const GITHUB_ZIPBALL_LIMITS: {
|
|
3
|
+
/** The compressed archive as downloaded. */
|
|
4
|
+
readonly downloadBytes: number;
|
|
5
|
+
/** The sum of every entry's declared uncompressed size. */
|
|
6
|
+
readonly inflatedBytes: number;
|
|
7
|
+
/** Files and directories the central directory lists. */
|
|
8
|
+
readonly entries: 20000;
|
|
9
|
+
};
|
|
10
|
+
export interface GitHubTreeSource {
|
|
11
|
+
/** `owner/repo`. */
|
|
12
|
+
readonly repo: string;
|
|
13
|
+
/** Branch, tag or commit; the default branch when absent. */
|
|
14
|
+
readonly ref?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface FetchGitHubTreeOptions {
|
|
17
|
+
/** Where the tree is written; created if missing. The caller owns its lifetime. */
|
|
18
|
+
readonly destDir: string;
|
|
19
|
+
/** The HTTP client (injectable for tests). */
|
|
20
|
+
readonly fetchImpl?: typeof globalThis.fetch;
|
|
21
|
+
}
|
|
22
|
+
/** The URL codeload answers with the zipball of `ref` (no API, no token). */
|
|
23
|
+
export declare function zipballUrl(source: GitHubTreeSource): string;
|
|
24
|
+
/**
|
|
25
|
+
* Download the zipball and extract it into `destDir` with the zipball's
|
|
26
|
+
* single top-level directory (`<repo>-<ref>/`) stripped, so `destDir` IS the
|
|
27
|
+
* repository root. Throws a `CliExitError` naming what refused: the
|
|
28
|
+
* repository, a cap, or an entry that would escape the directory.
|
|
29
|
+
*/
|
|
30
|
+
export declare function fetchGitHubTree(source: GitHubTreeSource, options: FetchGitHubTreeOptions): Promise<void>;
|
|
31
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/marketplace/github.ts"],"names":[],"mappings":"AA2CA,uFAAuF;AACvF,eAAO,MAAM,qBAAqB;IAChC,4CAA4C;;IAE5C,2DAA2D;;IAE3D,yDAAyD;;CAEjD,CAAC;AAKX,MAAM,WAAW,gBAAgB;IAC/B,oBAAoB;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CAC9C;AAED,6EAA6E;AAC7E,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAE3D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// A public GitHub repository as a marketplace tree: the zipball of one ref,
|
|
2
|
+
// downloaded from codeload and extracted into a directory the one plugin
|
|
3
|
+
// walker then reads like any other.
|
|
4
|
+
//
|
|
5
|
+
// Why a zipball and not `git`: codeload needs no API call, no token and no
|
|
6
|
+
// `git` binary, and the tree convention every vendor publishes (Cursor,
|
|
7
|
+
// Claude Code, Codex) is "the repository at a ref", which is exactly what a
|
|
8
|
+
// zipball is. Why to disk and not in memory: `install` and `push plugin`
|
|
9
|
+
// must yield one digest for one tree, and the digest is a function of the
|
|
10
|
+
// CLI's gitignore-aware, symlink-skipping walk over a directory. A second,
|
|
11
|
+
// in-memory walk with its own rules would be a second identity.
|
|
12
|
+
//
|
|
13
|
+
// The archive is untrusted input, so it is read the way the server's push
|
|
14
|
+
// gate reads one: the shape from the central directory (the shared
|
|
15
|
+
// `@stigmer/zip-structure` parser) BEFORE a byte is inflated, entry count and
|
|
16
|
+
// total declared size against the caps, every path contained; then each
|
|
17
|
+
// entry inflated with node:zlib under its declared size as a hard output cap
|
|
18
|
+
// and its CRC verified, because a declaration is a claim and the bytes are
|
|
19
|
+
// the fact. That per-entry read mirrors `archive/inflate.ts` in the server,
|
|
20
|
+
// its second consumer; when a third appears it moves to `@stigmer/zip-
|
|
21
|
+
// structure` beside `crc32`. The caps are set against the three vendors'
|
|
22
|
+
// real trees at HEAD (cursor/plugins 4.5 MiB down and 5.5 MiB inflated over
|
|
23
|
+
// 1,169 entries; anthropics/claude-code 11.7 / 13.6 / 1,595; openai/codex
|
|
24
|
+
// 18.6 / 76.8 / 9,188, its marketplace file at the repository root so the
|
|
25
|
+
// whole repository is the tree), with room above the largest.
|
|
26
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
27
|
+
import { dirname, join } from "node:path";
|
|
28
|
+
import { inflateRawSync } from "node:zlib";
|
|
29
|
+
import { isContainedPath } from "@stigmer/plugin-package";
|
|
30
|
+
import { crc32, parseZipStructure, } from "@stigmer/zip-structure";
|
|
31
|
+
import { CliExitError } from "../errors/cli-exit-error.js";
|
|
32
|
+
import { ExitCode } from "../errors/exit-codes.js";
|
|
33
|
+
import { log } from "../logger.js";
|
|
34
|
+
/** ZIP compression methods this reader opens, the two the platform's gates register. */
|
|
35
|
+
const METHOD_STORED = 0;
|
|
36
|
+
const METHOD_DEFLATED = 8;
|
|
37
|
+
/** The caps a repository zipball must fit under; each refusal names the one it hit. */
|
|
38
|
+
export const GITHUB_ZIPBALL_LIMITS = {
|
|
39
|
+
/** The compressed archive as downloaded. */
|
|
40
|
+
downloadBytes: 64 * 1024 * 1024,
|
|
41
|
+
/** The sum of every entry's declared uncompressed size. */
|
|
42
|
+
inflatedBytes: 256 * 1024 * 1024,
|
|
43
|
+
/** Files and directories the central directory lists. */
|
|
44
|
+
entries: 20_000,
|
|
45
|
+
};
|
|
46
|
+
/** The ref codeload serves when none is named: the repository's default branch. */
|
|
47
|
+
const DEFAULT_REF = "HEAD";
|
|
48
|
+
/** The URL codeload answers with the zipball of `ref` (no API, no token). */
|
|
49
|
+
export function zipballUrl(source) {
|
|
50
|
+
return `https://codeload.github.com/${source.repo}/zip/${source.ref ?? DEFAULT_REF}`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Download the zipball and extract it into `destDir` with the zipball's
|
|
54
|
+
* single top-level directory (`<repo>-<ref>/`) stripped, so `destDir` IS the
|
|
55
|
+
* repository root. Throws a `CliExitError` naming what refused: the
|
|
56
|
+
* repository, a cap, or an entry that would escape the directory.
|
|
57
|
+
*/
|
|
58
|
+
export async function fetchGitHubTree(source, options) {
|
|
59
|
+
const bytes = await download(source, options.fetchImpl ?? globalThis.fetch);
|
|
60
|
+
const entries = inspect(bytes, source);
|
|
61
|
+
mkdirSync(options.destDir, { recursive: true });
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
const content = inflate(entry, source);
|
|
64
|
+
const target = join(options.destDir, ...entry.relative.split("/"));
|
|
65
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
66
|
+
writeFileSync(target, content);
|
|
67
|
+
}
|
|
68
|
+
log.debug("github tree extracted", {
|
|
69
|
+
repo: source.repo,
|
|
70
|
+
ref: source.ref ?? DEFAULT_REF,
|
|
71
|
+
files: entries.length,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* One entry's bytes, inflated under its declared size as the output cap
|
|
76
|
+
* and checked against its CRC. An entry that inflates past what it declared
|
|
77
|
+
* lied about its budget; one whose bytes do not match its CRC is corrupt or
|
|
78
|
+
* tampered; a method neither the server nor Go registers is not opened.
|
|
79
|
+
*/
|
|
80
|
+
function inflate(entry, source) {
|
|
81
|
+
let content;
|
|
82
|
+
switch (entry.zip.compressionMethod) {
|
|
83
|
+
case METHOD_STORED:
|
|
84
|
+
content = entry.zip.compressedData;
|
|
85
|
+
break;
|
|
86
|
+
case METHOD_DEFLATED:
|
|
87
|
+
try {
|
|
88
|
+
content = new Uint8Array(inflateRawSync(entry.zip.compressedData, {
|
|
89
|
+
maxOutputLength: entry.declaredSize + 1,
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (isOutputLengthError(error)) {
|
|
94
|
+
throw refusal(source, `entry '${entry.relative}' inflated past its declared size`);
|
|
95
|
+
}
|
|
96
|
+
throw refusal(source, `entry '${entry.relative}' could not be inflated (${error instanceof Error ? error.message : String(error)})`);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
throw refusal(source, `entry '${entry.relative}' uses compression method ${entry.zip.compressionMethod}, which is not supported`);
|
|
101
|
+
}
|
|
102
|
+
if (content.length > entry.declaredSize) {
|
|
103
|
+
throw refusal(source, `entry '${entry.relative}' inflated past its declared size`);
|
|
104
|
+
}
|
|
105
|
+
if (crc32(content) !== entry.zip.crc32) {
|
|
106
|
+
throw refusal(source, `entry '${entry.relative}' failed its checksum`);
|
|
107
|
+
}
|
|
108
|
+
return content;
|
|
109
|
+
}
|
|
110
|
+
async function download(source, fetchImpl) {
|
|
111
|
+
const url = zipballUrl(source);
|
|
112
|
+
let response;
|
|
113
|
+
try {
|
|
114
|
+
response = await fetchImpl(url, { redirect: "follow" });
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
throw new CliExitError(`could not reach GitHub for ${source.repo}`, ExitCode.Connection, [
|
|
118
|
+
`URL: ${url}`,
|
|
119
|
+
"Check the network connection and retry.",
|
|
120
|
+
error instanceof Error ? error.message : String(error),
|
|
121
|
+
]);
|
|
122
|
+
}
|
|
123
|
+
if (response.status === 404) {
|
|
124
|
+
throw new CliExitError(`GitHub has no public repository '${source.repo}'${source.ref === undefined ? "" : ` at ref '${source.ref}'`}`, ExitCode.NotFound, [
|
|
125
|
+
"Check the owner, the repository name and the ref.",
|
|
126
|
+
"Private repositories are not supported; a marketplace is public content.",
|
|
127
|
+
]);
|
|
128
|
+
}
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
throw new CliExitError(`GitHub answered ${response.status} for ${source.repo}`, ExitCode.General, [`URL: ${url}`]);
|
|
131
|
+
}
|
|
132
|
+
const declaredLength = Number(response.headers.get("content-length") ?? "0");
|
|
133
|
+
if (declaredLength > GITHUB_ZIPBALL_LIMITS.downloadBytes) {
|
|
134
|
+
throw refusal(source, `the archive is ${mib(declaredLength)}, over the ${mib(GITHUB_ZIPBALL_LIMITS.downloadBytes)} download cap`);
|
|
135
|
+
}
|
|
136
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
137
|
+
if (bytes.length > GITHUB_ZIPBALL_LIMITS.downloadBytes) {
|
|
138
|
+
throw refusal(source, `the archive is ${mib(bytes.length)}, over the ${mib(GITHUB_ZIPBALL_LIMITS.downloadBytes)} download cap`);
|
|
139
|
+
}
|
|
140
|
+
return bytes;
|
|
141
|
+
}
|
|
142
|
+
// node:zlib's maxOutputLength violation: the output-cap arm.
|
|
143
|
+
function isOutputLengthError(error) {
|
|
144
|
+
return (error instanceof Error &&
|
|
145
|
+
(("code" in error &&
|
|
146
|
+
error.code === "ERR_BUFFER_TOO_LARGE") ||
|
|
147
|
+
error.message.includes("maxOutputLength")));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* The files to extract, in archive order, decided from the central directory
|
|
151
|
+
* alone. Refuses the caps, an entry outside the one top directory, and a
|
|
152
|
+
* path that would escape the destination.
|
|
153
|
+
*/
|
|
154
|
+
function inspect(bytes, source) {
|
|
155
|
+
let structure;
|
|
156
|
+
try {
|
|
157
|
+
structure = parseZipStructure(bytes);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
throw refusal(source, `the archive is not a readable zip (${error instanceof Error ? error.message : String(error)})`);
|
|
161
|
+
}
|
|
162
|
+
if (structure.length > GITHUB_ZIPBALL_LIMITS.entries) {
|
|
163
|
+
throw refusal(source, `the archive lists ${structure.length} entries, over the ${GITHUB_ZIPBALL_LIMITS.entries} cap`);
|
|
164
|
+
}
|
|
165
|
+
let inflated = 0;
|
|
166
|
+
for (const entry of structure)
|
|
167
|
+
inflated += entry.uncompressedSize;
|
|
168
|
+
if (inflated > GITHUB_ZIPBALL_LIMITS.inflatedBytes) {
|
|
169
|
+
throw refusal(source, `the archive inflates to ${mib(inflated)}, over the ${mib(GITHUB_ZIPBALL_LIMITS.inflatedBytes)} cap`);
|
|
170
|
+
}
|
|
171
|
+
const entries = [];
|
|
172
|
+
let top;
|
|
173
|
+
for (const entry of structure) {
|
|
174
|
+
const slash = entry.name.indexOf("/");
|
|
175
|
+
const head = slash === -1 ? entry.name : entry.name.slice(0, slash);
|
|
176
|
+
if (top === undefined)
|
|
177
|
+
top = head;
|
|
178
|
+
if (head !== top) {
|
|
179
|
+
throw refusal(source, `the archive holds more than one top-level directory ('${top}' and '${head}')`);
|
|
180
|
+
}
|
|
181
|
+
const relative = slash === -1 ? "" : entry.name.slice(slash + 1).replace(/\/+$/, "");
|
|
182
|
+
if (relative === "")
|
|
183
|
+
continue; // the top directory itself
|
|
184
|
+
if (!isContainedPath(relative)) {
|
|
185
|
+
throw refusal(source, `entry '${entry.name}' would escape the destination directory`);
|
|
186
|
+
}
|
|
187
|
+
if (entry.isDirectory)
|
|
188
|
+
continue;
|
|
189
|
+
entries.push({
|
|
190
|
+
relative,
|
|
191
|
+
declaredSize: entry.uncompressedSize,
|
|
192
|
+
zip: entry,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return entries;
|
|
196
|
+
}
|
|
197
|
+
function refusal(source, reason) {
|
|
198
|
+
return new CliExitError(`cannot read ${source.repo} as a marketplace: ${reason}`, ExitCode.Usage, ["A marketplace is a repository tree with a marketplace file at its root."]);
|
|
199
|
+
}
|
|
200
|
+
function mib(bytes) {
|
|
201
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/marketplace/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { OFFICIAL_MARKETPLACE, OFFICIAL_MARKETPLACE_NAME, type KnownMarketplace, type MarketplaceListing, type MarketplaceSource, type UnreadableMarketplace, addMarketplace, describeSource, findMarketplace, listMarketplaces, removeMarketplace, } from "./config.js";
|
|
2
|
+
export { type LocatedEntry, assertVersion, locateEntry, prepareEntry, } from "./install.js";
|
|
3
|
+
export { type OpenMarketplace, type OpenMarketplaceOptions, openMarketplace, withMarketplace, } from "./materialize.js";
|
|
4
|
+
export { type OfficialMarketplaceDir, type ResolveOfficialOptions, resolveOfficialMarketplace, } from "./official.js";
|
|
5
|
+
export { type ReadMarketplaceTree, entryDirectory, findEntry, marketplaceRefusal, readMarketplaceTree, } from "./read.js";
|
|
6
|
+
export { type InstallRef, formatInstallRef, parseAddSource, parseInstallRef, } from "./ref.js";
|
|
7
|
+
export { type ShownEntry, inspectEntries, renderMarketplaceList, renderMarketplaceShow, } from "./render.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/marketplace/index.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,YAAY,EACjB,aAAa,EACb,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,mBAAmB,EACxB,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,KAAK,UAAU,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,UAAU,EACf,cAAc,EACd,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Public surface of the marketplace module: the sources a CLI knows, the two
|
|
2
|
+
// grammars a user types, one way to get a tree on disk, one way to read it,
|
|
3
|
+
// one way to turn an entry into a push, and the two renderers. Commands
|
|
4
|
+
// lazy-import this barrel inside their actions so `--help` stays fast.
|
|
5
|
+
export { OFFICIAL_MARKETPLACE, OFFICIAL_MARKETPLACE_NAME, addMarketplace, describeSource, findMarketplace, listMarketplaces, removeMarketplace, } from "./config.js";
|
|
6
|
+
export { assertVersion, locateEntry, prepareEntry, } from "./install.js";
|
|
7
|
+
export { openMarketplace, withMarketplace, } from "./materialize.js";
|
|
8
|
+
export { resolveOfficialMarketplace, } from "./official.js";
|
|
9
|
+
export { entryDirectory, findEntry, marketplaceRefusal, readMarketplaceTree, } from "./read.js";
|
|
10
|
+
export { formatInstallRef, parseAddSource, parseInstallRef, } from "./ref.js";
|
|
11
|
+
export { inspectEntries, renderMarketplaceList, renderMarketplaceShow, } from "./render.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/marketplace/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,4EAA4E;AAC5E,wEAAwE;AACxE,uEAAuE;AAEvE,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EAKzB,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,aAAa,EACb,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAGL,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAGL,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,cAAc,EACd,SAAS,EACT,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AACnB,OAAO,EAEL,gBAAgB,EAChB,cAAc,EACd,eAAe,GAChB,MAAM,UAAU,CAAC;AAClB,OAAO,EAEL,cAAc,EACd,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type PreparedPluginPush } from "../resources/plugin.js";
|
|
2
|
+
import { type KnownMarketplace, type MarketplaceListing } from "./config.js";
|
|
3
|
+
import { type OpenMarketplace, type OpenMarketplaceOptions } from "./materialize.js";
|
|
4
|
+
import { type ReadMarketplaceTree } from "./read.js";
|
|
5
|
+
import { type InstallRef } from "./ref.js";
|
|
6
|
+
/** A ref resolved to the one marketplace that offers it, with that marketplace open on disk. */
|
|
7
|
+
export interface LocatedEntry {
|
|
8
|
+
readonly marketplace: KnownMarketplace;
|
|
9
|
+
readonly open: OpenMarketplace;
|
|
10
|
+
readonly tree: ReadMarketplaceTree;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Find the marketplace a ref names. A prefixed ref names it outright; a bare
|
|
14
|
+
* name is searched across every configured marketplace in listing order
|
|
15
|
+
* (the official one first), and exactly one must offer it: none refuses
|
|
16
|
+
* toward `marketplace show`, more than one refuses by naming each holder,
|
|
17
|
+
* because "the first one wins" would make the answer depend on the order
|
|
18
|
+
* the user added marketplaces in. The caller owns `open` and disposes it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function locateEntry(ref: InstallRef, listing: MarketplaceListing, options?: OpenMarketplaceOptions): Promise<LocatedEntry>;
|
|
21
|
+
/** Read, validate and zip the entry called `name`; refuses an entry the marketplace does not offer. */
|
|
22
|
+
export declare function prepareEntry(tree: ReadMarketplaceTree, name: string): Promise<PreparedPluginPush>;
|
|
23
|
+
/**
|
|
24
|
+
* `@version` in a ref is an assertion, not a selector: a marketplace tree
|
|
25
|
+
* holds one version of each plugin, so the ref either names it or is wrong.
|
|
26
|
+
*/
|
|
27
|
+
export declare function assertVersion(prepared: PreparedPluginPush, wanted: string | undefined, ref: string): void;
|
|
28
|
+
//# sourceMappingURL=install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/marketplace/install.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EAExB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE5B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,mBAAmB,EAIzB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,UAAU,CAAC;AAE7D,gGAAgG;AAChG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,kBAAkB,EAC3B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,YAAY,CAAC,CA4DvB;AAED,uGAAuG;AACvG,wBAAsB,YAAY,CAChC,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,kBAAkB,CAAC,CAI7B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,GAAG,EAAE,MAAM,GACV,IAAI,CASN"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// An entry of an open marketplace becomes a prepared push. This is the one
|
|
2
|
+
// place that happens, for both callers: `stigmer install <ref>` and the
|
|
3
|
+
// `stigmer up` default-set step. Neither re-derives the entry's directory or
|
|
4
|
+
// the archive's digest; both hand the prepared value to `pushPrepared` (or,
|
|
5
|
+
// for `up`, compare its digest first). The entry's directory goes through the
|
|
6
|
+
// same walker `push plugin <dir>` uses, so a marketplace install and a push
|
|
7
|
+
// of the same checked-out folder yield one digest for one tree.
|
|
8
|
+
import { UsageError } from "../errors/index.js";
|
|
9
|
+
import { preparePluginPush, } from "../resources/plugin.js";
|
|
10
|
+
import { describeSource, } from "./config.js";
|
|
11
|
+
import { openMarketplace, } from "./materialize.js";
|
|
12
|
+
import { entryDirectory, findEntry, readMarketplaceTree, } from "./read.js";
|
|
13
|
+
import { formatInstallRef } from "./ref.js";
|
|
14
|
+
/**
|
|
15
|
+
* Find the marketplace a ref names. A prefixed ref names it outright; a bare
|
|
16
|
+
* name is searched across every configured marketplace in listing order
|
|
17
|
+
* (the official one first), and exactly one must offer it: none refuses
|
|
18
|
+
* toward `marketplace show`, more than one refuses by naming each holder,
|
|
19
|
+
* because "the first one wins" would make the answer depend on the order
|
|
20
|
+
* the user added marketplaces in. The caller owns `open` and disposes it.
|
|
21
|
+
*/
|
|
22
|
+
export async function locateEntry(ref, listing, options = {}) {
|
|
23
|
+
if (ref.marketplace !== undefined) {
|
|
24
|
+
const marketplace = listing.known.find((known) => known.name === ref.marketplace);
|
|
25
|
+
if (marketplace === undefined) {
|
|
26
|
+
throw new UsageError(`no marketplace named '${ref.marketplace}' is configured\n\n` +
|
|
27
|
+
"Run 'stigmer marketplace list' to see the configured names, or add one with 'stigmer marketplace add <source>'.");
|
|
28
|
+
}
|
|
29
|
+
const open = await openMarketplace(marketplace.source, options);
|
|
30
|
+
try {
|
|
31
|
+
const tree = readMarketplaceTree(open.root, describeSource(marketplace.source));
|
|
32
|
+
if (findEntry(tree.marketplace, ref.name) === undefined)
|
|
33
|
+
throw entryNotOffered(tree, ref.name);
|
|
34
|
+
return { marketplace, open, tree };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
open.dispose();
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const holders = [];
|
|
42
|
+
for (const marketplace of listing.known) {
|
|
43
|
+
const open = await openMarketplace(marketplace.source, options);
|
|
44
|
+
let tree;
|
|
45
|
+
try {
|
|
46
|
+
tree = readMarketplaceTree(open.root, describeSource(marketplace.source));
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
open.dispose();
|
|
50
|
+
for (const holder of holders)
|
|
51
|
+
holder.open.dispose();
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
if (findEntry(tree.marketplace, ref.name) === undefined) {
|
|
55
|
+
open.dispose();
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
holders.push({ marketplace, open, tree });
|
|
59
|
+
}
|
|
60
|
+
if (holders.length === 1)
|
|
61
|
+
return holders[0];
|
|
62
|
+
for (const holder of holders)
|
|
63
|
+
holder.open.dispose();
|
|
64
|
+
if (holders.length === 0) {
|
|
65
|
+
const skipped = listing.unreadable.length === 0
|
|
66
|
+
? ""
|
|
67
|
+
: ` Not searched, because its entry cannot be read: ${listing.unreadable.map((entry) => entry.name).join(", ")} (see 'stigmer marketplace list').`;
|
|
68
|
+
throw new UsageError(`no configured marketplace offers a plugin named '${ref.name}'\n\n` +
|
|
69
|
+
`Searched: ${listing.known.map((known) => known.name).join(", ")}.${skipped} ` +
|
|
70
|
+
"Run 'stigmer marketplace show <name>' to see what each offers, or add the marketplace that has it.");
|
|
71
|
+
}
|
|
72
|
+
throw new UsageError(`'${ref.name}' is offered by more than one marketplace: ${holders.map((holder) => holder.marketplace.name).join(", ")}\n\n` +
|
|
73
|
+
`Name the one you mean: ${holders.map((holder) => formatInstallRef({ ...ref, marketplace: holder.marketplace.name })).join(" or ")}.`);
|
|
74
|
+
}
|
|
75
|
+
/** Read, validate and zip the entry called `name`; refuses an entry the marketplace does not offer. */
|
|
76
|
+
export async function prepareEntry(tree, name) {
|
|
77
|
+
const entry = findEntry(tree.marketplace, name);
|
|
78
|
+
if (entry === undefined)
|
|
79
|
+
throw entryNotOffered(tree, name);
|
|
80
|
+
return preparePluginPush(entryDirectory(tree, entry));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* `@version` in a ref is an assertion, not a selector: a marketplace tree
|
|
84
|
+
* holds one version of each plugin, so the ref either names it or is wrong.
|
|
85
|
+
*/
|
|
86
|
+
export function assertVersion(prepared, wanted, ref) {
|
|
87
|
+
if (wanted === undefined)
|
|
88
|
+
return;
|
|
89
|
+
const offered = prepared.plugin.version;
|
|
90
|
+
if (offered === wanted)
|
|
91
|
+
return;
|
|
92
|
+
throw new UsageError(offered === undefined
|
|
93
|
+
? `'${ref}' pins version ${wanted}, but the marketplace's '${prepared.plugin.name}' declares no version\n\nInstall it without '@${wanted}'.`
|
|
94
|
+
: `'${ref}' pins version ${wanted}, but the marketplace offers '${prepared.plugin.name}' at ${offered}\n\nInstall it as '${ref.slice(0, ref.lastIndexOf("@"))}@${offered}', or without a version.`);
|
|
95
|
+
}
|
|
96
|
+
function entryNotOffered(tree, name) {
|
|
97
|
+
const dropped = tree.warnings.find((warning) => warning.subject === name);
|
|
98
|
+
const offered = tree.marketplace.plugins.map((entry) => entry.name);
|
|
99
|
+
const lines = [
|
|
100
|
+
`marketplace '${tree.marketplace.name}' does not offer a plugin named '${name}'`,
|
|
101
|
+
];
|
|
102
|
+
if (dropped !== undefined)
|
|
103
|
+
lines.push("", dropped.message);
|
|
104
|
+
lines.push("", offered.length === 0
|
|
105
|
+
? "It offers no plugins this CLI can install."
|
|
106
|
+
: `Run 'stigmer marketplace show ${tree.marketplace.name}' to see the ${offered.length} it offers.`);
|
|
107
|
+
return new UsageError(lines.join("\n"));
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/marketplace/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MarketplaceSource } from "./config.js";
|
|
2
|
+
import { type ResolveOfficialOptions } from "./official.js";
|
|
3
|
+
/** A marketplace tree on disk, for as long as the caller holds it. */
|
|
4
|
+
export interface OpenMarketplace {
|
|
5
|
+
/** Absolute path to the tree root: the directory the marketplace file sits in. */
|
|
6
|
+
readonly root: string;
|
|
7
|
+
/** Release whatever the open created (a temp directory); a no-op for a tree that was already there. */
|
|
8
|
+
dispose(): void;
|
|
9
|
+
}
|
|
10
|
+
export interface OpenMarketplaceOptions {
|
|
11
|
+
/** The HTTP client for GitHub sources (injectable for tests). */
|
|
12
|
+
readonly fetchImpl?: typeof globalThis.fetch;
|
|
13
|
+
/** How the official tree is found (injectable for tests). */
|
|
14
|
+
readonly official?: ResolveOfficialOptions;
|
|
15
|
+
}
|
|
16
|
+
export declare function openMarketplace(source: MarketplaceSource, options?: OpenMarketplaceOptions): Promise<OpenMarketplace>;
|
|
17
|
+
/** Open, hand the tree to `use`, and dispose whatever the outcome. */
|
|
18
|
+
export declare function withMarketplace<T>(source: MarketplaceSource, use: (open: OpenMarketplace) => Promise<T> | T, options?: OpenMarketplaceOptions): Promise<T>;
|
|
19
|
+
//# sourceMappingURL=materialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialize.d.ts","sourceRoot":"","sources":["../../src/marketplace/materialize.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,eAAe,CAAC;AAEvB,sEAAsE;AACtE,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uGAAuG;IACvG,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAC7C,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;CAC5C;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,eAAe,CAAC,CA6B1B;AAED,sEAAsE;AACtE,wBAAsB,eAAe,CAAC,CAAC,EACrC,MAAM,EAAE,iBAAiB,EACzB,GAAG,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAC9C,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,CAAC,CAAC,CAOZ"}
|