@topogram/cli 0.3.79 → 0.3.80

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/src/cli/help.js CHANGED
@@ -38,7 +38,7 @@ export function printUsage(options = {}) {
38
38
  console.log(" or: topogram package update-cli <version|--latest> [--json]");
39
39
  console.log(" or: topogram copy <source> <target> [--version <version>] [--catalog <path-or-source>] [--json]");
40
40
  console.log(" or: topogram copy --list [--json] [--catalog <path-or-source>]");
41
- console.log(" or: topogram extract <app-path> --out <target> [--from <track[,track]>] [--json]");
41
+ console.log(" or: topogram extract <app-path> --out <target> [--from <track[,track]>] [--extractor <id-or-package-or-path>] [--json]");
42
42
  console.log(" or: topogram extract refresh [path] [--from <app-path>] [--dry-run] [--json]");
43
43
  console.log(" or: topogram extract diff [path] [--json]");
44
44
  console.log(" or: topogram extract check [path] [--json]");
@@ -67,6 +67,14 @@ export function printUsage(options = {}) {
67
67
  console.log(" or: topogram generator policy check [path] [--json]");
68
68
  console.log(" or: topogram generator policy explain [path] [--json]");
69
69
  console.log(" or: topogram generator policy pin [package@version] [path] [--json]");
70
+ console.log(" or: topogram extractor list [--json]");
71
+ console.log(" or: topogram extractor show <id-or-package> [--json]");
72
+ console.log(" or: topogram extractor check <path-or-package> [--json]");
73
+ console.log(" or: topogram extractor policy init [path] [--json]");
74
+ console.log(" or: topogram extractor policy status [path] [--json]");
75
+ console.log(" or: topogram extractor policy check [path] [--json]");
76
+ console.log(" or: topogram extractor policy explain [path] [--json]");
77
+ console.log(" or: topogram extractor policy pin [package@version] [path] [--json]");
70
78
  console.log(" or: topogram init [path] [--with-sdlc] [--json]");
71
79
  console.log("");
72
80
  console.log("Common commands:");
@@ -98,6 +106,9 @@ export function printUsage(options = {}) {
98
106
  console.log(" topogram generator show @topogram/generator-react-web");
99
107
  console.log(" topogram generator check ./generator-package");
100
108
  console.log(" topogram generator policy check");
109
+ console.log(" topogram extractor list");
110
+ console.log(" topogram extractor check ./extractor-package");
111
+ console.log(" topogram extractor policy check");
101
112
  console.log(" topogram generate");
102
113
  console.log(" topogram extract ./existing-app --out ./extracted-topogram");
103
114
  console.log(" topogram extract diff ./extracted-topogram");
@@ -22,6 +22,21 @@ export function optionValueIfPresent(args, flag) {
22
22
  return value && !value.startsWith("-") ? value : null;
23
23
  }
24
24
 
25
+ /**
26
+ * @param {string[]} args
27
+ * @param {string} flag
28
+ * @returns {string[]}
29
+ */
30
+ export function optionValues(args, flag) {
31
+ const values = [];
32
+ for (let index = 0; index < args.length; index += 1) {
33
+ if (args[index] === flag && args[index + 1] && !args[index + 1].startsWith("-")) {
34
+ values.push(args[index + 1]);
35
+ }
36
+ }
37
+ return values;
38
+ }
39
+
25
40
  /**
26
41
  * @param {string[]} args
27
42
  * @param {string} flag
@@ -51,6 +66,8 @@ export function parseCliOptions(args, commandArgs) {
51
66
  workflowName: commandArgs?.workflowName || (!generateTarget && workflowFlagValue ? workflowFlagValue : null),
52
67
  workflowId: generateTarget ? workflowFlagValue : null,
53
68
  fromValue: optionValue(args, "--from"),
69
+ extractorSpecs: optionValues(args, "--extractor"),
70
+ extractorPolicyPath: optionValueIfPresent(args, "--extractor-policy"),
54
71
  adoptValue: commandArgs?.adoptValue || optionValue(args, "--adopt"),
55
72
  reasonValue: optionValueIfPresent(args, "--reason"),
56
73
  modeId: optionValue(args, "--mode"),
@@ -0,0 +1,155 @@
1
+ // @ts-check
2
+
3
+ import {
4
+ createExtractorSmokeContext,
5
+ loadExtractorPackageAdapterForSpec,
6
+ validateExtractorAdapter
7
+ } from "./packages.js";
8
+
9
+ /**
10
+ * @typedef {import("./registry.js").ExtractorManifest} ExtractorManifest
11
+ */
12
+
13
+ /**
14
+ * @typedef {Object} ExtractorCheckResult
15
+ * @property {boolean} ok
16
+ * @property {string} sourceSpec
17
+ * @property {"path"|"package"} source
18
+ * @property {string|null} packageName
19
+ * @property {string|null} packageRoot
20
+ * @property {string|null} manifestPath
21
+ * @property {ExtractorManifest|null} manifest
22
+ * @property {Array<{ name: string, ok: boolean, message: string }>} checks
23
+ * @property {string[]} errors
24
+ * @property {{ extractors: number, findings: number, candidateKeys: number, diagnostics: number }|null} smoke
25
+ * @property {boolean} executesPackageCode
26
+ */
27
+
28
+ /**
29
+ * @param {any} result
30
+ * @returns {{ ok: boolean, message: string, smoke: { findings: number, candidateKeys: number, diagnostics: number }|null }}
31
+ */
32
+ function validateExtractResult(result) {
33
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
34
+ return { ok: false, message: "extract(context) must return an object", smoke: null };
35
+ }
36
+ if (result.findings != null && !Array.isArray(result.findings)) {
37
+ return { ok: false, message: "extract(context) findings must be an array when present", smoke: null };
38
+ }
39
+ if (result.diagnostics != null && !Array.isArray(result.diagnostics)) {
40
+ return { ok: false, message: "extract(context) diagnostics must be an array when present", smoke: null };
41
+ }
42
+ if (!result.candidates || typeof result.candidates !== "object" || Array.isArray(result.candidates)) {
43
+ return { ok: false, message: "extract(context) result must include a candidates object", smoke: null };
44
+ }
45
+ for (const [key, value] of Object.entries(result.candidates)) {
46
+ if (!Array.isArray(value)) {
47
+ return { ok: false, message: `extract(context) candidates.${key} must be an array`, smoke: null };
48
+ }
49
+ }
50
+ return {
51
+ ok: true,
52
+ message: `extract(context) returned ${Object.keys(result.candidates).length} candidate bucket(s)`,
53
+ smoke: {
54
+ findings: Array.isArray(result.findings) ? result.findings.length : 0,
55
+ candidateKeys: Object.keys(result.candidates).length,
56
+ diagnostics: Array.isArray(result.diagnostics) ? result.diagnostics.length : 0
57
+ }
58
+ };
59
+ }
60
+
61
+ /**
62
+ * @param {string} sourceSpec
63
+ * @param {{ cwd?: string }} [options]
64
+ * @returns {ExtractorCheckResult}
65
+ */
66
+ export function checkExtractorPack(sourceSpec, options = {}) {
67
+ /** @type {ExtractorCheckResult} */
68
+ const payload = {
69
+ ok: false,
70
+ sourceSpec,
71
+ source: "package",
72
+ packageName: null,
73
+ packageRoot: null,
74
+ manifestPath: null,
75
+ manifest: null,
76
+ checks: [],
77
+ errors: [],
78
+ smoke: null,
79
+ executesPackageCode: true
80
+ };
81
+ if (!sourceSpec || sourceSpec.startsWith("-")) {
82
+ payload.errors.push("Usage: topogram extractor check <path-or-package>");
83
+ payload.checks.push({ name: "source", ok: false, message: payload.errors[0] });
84
+ return payload;
85
+ }
86
+
87
+ const loaded = loadExtractorPackageAdapterForSpec(sourceSpec, options);
88
+ payload.source = loaded.source;
89
+ payload.packageName = loaded.packageName;
90
+ payload.packageRoot = loaded.packageRoot;
91
+ payload.manifestPath = loaded.manifestPath;
92
+ payload.manifest = loaded.manifest;
93
+ if (!loaded.manifest) {
94
+ payload.errors.push(...loaded.errors);
95
+ payload.checks.push({ name: "manifest-load", ok: false, message: loaded.errors.join(" ") || "Could not load extractor manifest." });
96
+ return payload;
97
+ }
98
+ payload.checks.push({ name: "manifest-load", ok: true, message: loaded.manifestPath || sourceSpec });
99
+ if (!loaded.adapter || loaded.errors.length > 0) {
100
+ payload.errors.push(...loaded.errors);
101
+ payload.checks.push({ name: "adapter-load", ok: false, message: loaded.errors.join(" ") || "Could not load extractor adapter." });
102
+ return payload;
103
+ }
104
+ payload.checks.push({ name: "adapter-load", ok: true, message: "Adapter export loaded." });
105
+
106
+ const adapterValidation = validateExtractorAdapter(loaded.adapter, loaded.manifest);
107
+ payload.checks.push({
108
+ name: "adapter-shape",
109
+ ok: adapterValidation.errors.length === 0,
110
+ message: adapterValidation.errors.length === 0 ? "Adapter shape is valid." : adapterValidation.errors.join(" ")
111
+ });
112
+ if (adapterValidation.errors.length > 0) {
113
+ payload.errors.push(...adapterValidation.errors);
114
+ return payload;
115
+ }
116
+
117
+ const context = createExtractorSmokeContext();
118
+ let totalFindings = 0;
119
+ let totalCandidateKeys = 0;
120
+ let totalDiagnostics = 0;
121
+ for (const extractor of adapterValidation.extractors) {
122
+ try {
123
+ const detection = extractor.detect(context) || { score: 0, reasons: [] };
124
+ if (!detection || typeof detection !== "object" || typeof detection.score !== "number") {
125
+ payload.errors.push(`Extractor '${extractor.id}' detect(context) must return { score, reasons }.`);
126
+ continue;
127
+ }
128
+ const result = extractor.extract(context) || { findings: [], candidates: {} };
129
+ const validation = validateExtractResult(result);
130
+ if (!validation.ok || !validation.smoke) {
131
+ payload.errors.push(`Extractor '${extractor.id}' ${validation.message}.`);
132
+ continue;
133
+ }
134
+ totalFindings += validation.smoke.findings;
135
+ totalCandidateKeys += validation.smoke.candidateKeys;
136
+ totalDiagnostics += validation.smoke.diagnostics;
137
+ } catch (error) {
138
+ payload.errors.push(`Extractor '${extractor.id}' smoke failed: ${error instanceof Error ? error.message : String(error)}`);
139
+ }
140
+ }
141
+ payload.checks.push({
142
+ name: "smoke-extract",
143
+ ok: payload.errors.length === 0,
144
+ message: payload.errors.length === 0 ? `Ran ${adapterValidation.extractors.length} extractor smoke check(s).` : payload.errors.join(" ")
145
+ });
146
+ payload.smoke = {
147
+ extractors: adapterValidation.extractors.length,
148
+ findings: totalFindings,
149
+ candidateKeys: totalCandidateKeys,
150
+ diagnostics: totalDiagnostics
151
+ };
152
+ payload.ok = payload.errors.length === 0;
153
+ return payload;
154
+ }
155
+
@@ -0,0 +1,295 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+
7
+ import {
8
+ isPathSpec,
9
+ loadInstalledPackageAdapter,
10
+ loadLocalPackageAdapter,
11
+ packageNameFromSpec
12
+ } from "../package-adapters/index.js";
13
+ import {
14
+ EXTRACTOR_MANIFESTS,
15
+ getExtractorManifest,
16
+ loadPackageExtractorManifest,
17
+ validateExtractorManifest
18
+ } from "./registry.js";
19
+ import {
20
+ effectiveExtractorPolicy,
21
+ extractorPackageAllowed,
22
+ extractorPolicyDiagnosticsForPackages,
23
+ loadExtractorPolicy
24
+ } from "../extractor-policy.js";
25
+ import { createImportContext } from "../import/core/context.js";
26
+ import { getBundledExtractorById, getBundledExtractorPack } from "../import/core/registry.js";
27
+
28
+ /**
29
+ * @typedef {import("./registry.js").ExtractorManifest} ExtractorManifest
30
+ */
31
+
32
+ /**
33
+ * @param {string} packageRoot
34
+ * @returns {string|null}
35
+ */
36
+ function packageNameForRoot(packageRoot) {
37
+ const packageJsonPath = path.join(packageRoot, "package.json");
38
+ if (!fs.existsSync(packageJsonPath)) {
39
+ return null;
40
+ }
41
+ try {
42
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
43
+ return typeof packageJson.name === "string" && packageJson.name.length > 0 ? packageJson.name : null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+
49
+ /**
50
+ * @param {any} adapter
51
+ * @param {ExtractorManifest} manifest
52
+ * @returns {{ extractors: any[], errors: string[] }}
53
+ */
54
+ export function validateExtractorAdapter(adapter, manifest) {
55
+ const errors = [];
56
+ if (!adapter || typeof adapter !== "object" || Array.isArray(adapter)) {
57
+ return { extractors: [], errors: ["Extractor adapter must export an object."] };
58
+ }
59
+ const adapterManifest = adapter.manifest;
60
+ if (!adapterManifest || adapterManifest.id !== manifest.id || adapterManifest.version !== manifest.version) {
61
+ errors.push("Extractor adapter must export manifest matching topogram-extractor.json.");
62
+ }
63
+ if (!Array.isArray(adapter.extractors) || adapter.extractors.length === 0) {
64
+ errors.push("Extractor adapter must export a non-empty extractors array.");
65
+ }
66
+ const manifestExtractorIds = new Set(manifest.extractors || []);
67
+ const manifestTracks = new Set(manifest.tracks || []);
68
+ const extractors = Array.isArray(adapter.extractors) ? adapter.extractors : [];
69
+ for (const extractor of extractors) {
70
+ if (!extractor || typeof extractor !== "object") {
71
+ errors.push("Extractor entries must be objects.");
72
+ continue;
73
+ }
74
+ if (typeof extractor.id !== "string" || extractor.id.length === 0) {
75
+ errors.push("Extractor entries must have a non-empty id.");
76
+ } else if (!manifestExtractorIds.has(extractor.id)) {
77
+ errors.push(`Extractor '${extractor.id}' is not declared by manifest extractors.`);
78
+ }
79
+ if (typeof extractor.track !== "string" || !manifestTracks.has(extractor.track)) {
80
+ errors.push(`Extractor '${extractor.id || "unknown"}' has track '${extractor.track || "unknown"}' not declared by manifest tracks.`);
81
+ }
82
+ if (typeof extractor.detect !== "function") {
83
+ errors.push(`Extractor '${extractor.id || "unknown"}' must expose detect(context).`);
84
+ }
85
+ if (typeof extractor.extract !== "function") {
86
+ errors.push(`Extractor '${extractor.id || "unknown"}' must expose extract(context).`);
87
+ }
88
+ }
89
+ return { extractors, errors };
90
+ }
91
+
92
+ /**
93
+ * @param {string} sourceSpec
94
+ * @param {{ cwd?: string }} [options]
95
+ * @returns {{ source: "path"|"package", packageName: string|null, packageRoot: string|null, manifestPath: string|null, manifest: ExtractorManifest|null, errors: string[] }}
96
+ */
97
+ export function loadExtractorPackageManifestForSpec(sourceSpec, options = {}) {
98
+ const cwd = path.resolve(options.cwd || process.cwd());
99
+ if (isPathSpec(sourceSpec, cwd)) {
100
+ const packageRoot = path.resolve(cwd, sourceSpec);
101
+ const manifestPath = path.join(packageRoot, "topogram-extractor.json");
102
+ if (!fs.existsSync(packageRoot) || !fs.statSync(packageRoot).isDirectory()) {
103
+ return { source: "path", packageName: null, packageRoot, manifestPath, manifest: null, errors: [`Extractor path '${packageRoot}' must be a directory.`] };
104
+ }
105
+ if (!fs.existsSync(manifestPath)) {
106
+ return { source: "path", packageName: packageNameForRoot(packageRoot), packageRoot, manifestPath, manifest: null, errors: [`Extractor path '${packageRoot}' is missing topogram-extractor.json.`] };
107
+ }
108
+ try {
109
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
110
+ const validation = validateExtractorManifest(manifest);
111
+ return {
112
+ source: "path",
113
+ packageName: typeof manifest.package === "string" ? manifest.package : packageNameForRoot(packageRoot),
114
+ packageRoot,
115
+ manifestPath,
116
+ manifest: validation.ok ? manifest : null,
117
+ errors: validation.errors
118
+ };
119
+ } catch (error) {
120
+ return {
121
+ source: "path",
122
+ packageName: packageNameForRoot(packageRoot),
123
+ packageRoot,
124
+ manifestPath,
125
+ manifest: null,
126
+ errors: [`Extractor manifest could not be read: ${error instanceof Error ? error.message : String(error)}`]
127
+ };
128
+ }
129
+ }
130
+
131
+ const packageName = packageNameFromSpec(sourceSpec);
132
+ const loaded = loadPackageExtractorManifest(packageName, cwd);
133
+ return {
134
+ source: "package",
135
+ packageName,
136
+ packageRoot: loaded.packageRoot,
137
+ manifestPath: loaded.manifestPath,
138
+ manifest: loaded.manifest,
139
+ errors: loaded.errors
140
+ };
141
+ }
142
+
143
+ /**
144
+ * @param {string} sourceSpec
145
+ * @param {{ cwd?: string }} [options]
146
+ * @returns {{ adapter: any|null, source: "path"|"package", packageName: string|null, packageRoot: string|null, manifestPath: string|null, manifest: ExtractorManifest|null, errors: string[] }}
147
+ */
148
+ export function loadExtractorPackageAdapterForSpec(sourceSpec, options = {}) {
149
+ const loadedManifest = loadExtractorPackageManifestForSpec(sourceSpec, options);
150
+ if (!loadedManifest.manifest) {
151
+ return { ...loadedManifest, adapter: null };
152
+ }
153
+ const loadedAdapter = loadedManifest.source === "path"
154
+ ? loadLocalPackageAdapter({
155
+ packageRoot: loadedManifest.packageRoot || path.resolve(options.cwd || process.cwd(), sourceSpec),
156
+ exportName: loadedManifest.manifest.export,
157
+ packageLabel: "Extractor package"
158
+ })
159
+ : loadInstalledPackageAdapter({
160
+ packageName: loadedManifest.packageName || packageNameFromSpec(sourceSpec),
161
+ rootDir: path.resolve(options.cwd || process.cwd()),
162
+ exportName: loadedManifest.manifest.export,
163
+ packageLabel: "Extractor package"
164
+ });
165
+ return {
166
+ ...loadedManifest,
167
+ adapter: loadedAdapter.adapter,
168
+ errors: [...loadedManifest.errors, ...(loadedAdapter.error ? [loadedAdapter.error] : [])]
169
+ };
170
+ }
171
+
172
+ /**
173
+ * @param {string} packageName
174
+ * @param {string} version
175
+ * @returns {import("../extractor-policy.js").PackageExtractorBinding}
176
+ */
177
+ function packageBinding(packageName, version) {
178
+ return {
179
+ packageName,
180
+ version
181
+ };
182
+ }
183
+
184
+ /**
185
+ * @param {any} context
186
+ * @returns {any}
187
+ */
188
+ function packageExtractorContext(context) {
189
+ return {
190
+ paths: context.paths,
191
+ options: context.options || {},
192
+ priorResults: context.priorResults || {},
193
+ scanDocsSummary: context.scanDocsSummary || null,
194
+ helpers: {
195
+ path: context.helpers?.path,
196
+ readTextIfExists: context.helpers?.readTextIfExists,
197
+ readJsonIfExists: context.helpers?.readJsonIfExists
198
+ }
199
+ };
200
+ }
201
+
202
+ /**
203
+ * @param {any} context
204
+ * @returns {{ extractors: any[], diagnostics: any[], provenance: any[] }}
205
+ */
206
+ export function packageExtractorsForContext(context) {
207
+ if (context.packageExtractorState) {
208
+ return context.packageExtractorState;
209
+ }
210
+ const cwd = path.resolve(context.options?.cwd || process.cwd());
211
+ const policyInfo = loadExtractorPolicy(cwd, context.options?.extractorPolicyPath || null);
212
+ const policy = effectiveExtractorPolicy(policyInfo);
213
+ const specs = [
214
+ ...(Array.isArray(policy.enabledPackages) ? policy.enabledPackages : []),
215
+ ...(Array.isArray(context.options?.extractorSpecs) ? context.options.extractorSpecs : [])
216
+ ].filter(Boolean);
217
+ /** @type {any[]} */
218
+ const extractors = [];
219
+ /** @type {any[]} */
220
+ const diagnostics = [...policyInfo.diagnostics];
221
+ /** @type {any[]} */
222
+ const provenance = [];
223
+ const seen = new Set();
224
+
225
+ for (const spec of specs) {
226
+ if (seen.has(spec)) continue;
227
+ seen.add(spec);
228
+ const bundledPack = getBundledExtractorPack(spec);
229
+ if (bundledPack) {
230
+ extractors.push(...bundledPack.extractors);
231
+ provenance.push({ source: "bundled", id: bundledPack.manifest.id, version: bundledPack.manifest.version, extractors: bundledPack.manifest.extractors });
232
+ continue;
233
+ }
234
+ const bundledExtractor = getBundledExtractorById(spec);
235
+ if (bundledExtractor) {
236
+ extractors.push(bundledExtractor);
237
+ provenance.push({ source: "bundled", id: bundledExtractor.id, version: "1", extractors: [bundledExtractor.id] });
238
+ continue;
239
+ }
240
+ const packageManifest = loadExtractorPackageManifestForSpec(spec, { cwd });
241
+ if (!packageManifest.manifest) {
242
+ diagnostics.push({ severity: "error", code: "extractor_package_manifest_failed", message: packageManifest.errors.join(" "), packageName: packageManifest.packageName, spec });
243
+ continue;
244
+ }
245
+ const packageName = packageManifest.packageName || packageManifest.manifest.package || spec;
246
+ const policyDiagnostics = extractorPolicyDiagnosticsForPackages(policyInfo, [packageBinding(packageName, packageManifest.manifest.version)], "extractor-policy");
247
+ const errors = policyDiagnostics.filter((diagnostic) => diagnostic.severity === "error");
248
+ diagnostics.push(...policyDiagnostics);
249
+ if (errors.length > 0 || !extractorPackageAllowed(policy, packageName)) {
250
+ continue;
251
+ }
252
+ const adapter = loadExtractorPackageAdapterForSpec(spec, { cwd });
253
+ if (!adapter.adapter || adapter.errors.length > 0) {
254
+ diagnostics.push(...adapter.errors.map((message) => ({ severity: "error", code: "extractor_package_load_failed", message, packageName, spec })));
255
+ continue;
256
+ }
257
+ const adapterValidation = validateExtractorAdapter(adapter.adapter, packageManifest.manifest);
258
+ if (adapterValidation.errors.length > 0) {
259
+ diagnostics.push(...adapterValidation.errors.map((message) => ({ severity: "error", code: "extractor_adapter_invalid", message, packageName, spec })));
260
+ continue;
261
+ }
262
+ for (const extractor of adapterValidation.extractors) {
263
+ extractors.push({
264
+ ...extractor,
265
+ source: "package",
266
+ manifestId: packageManifest.manifest.id,
267
+ packageName,
268
+ packageContext: packageExtractorContext
269
+ });
270
+ }
271
+ provenance.push({
272
+ source: "package",
273
+ id: packageManifest.manifest.id,
274
+ version: packageManifest.manifest.version,
275
+ packageName,
276
+ manifestPath: packageManifest.manifestPath,
277
+ packageRoot: packageManifest.packageRoot,
278
+ extractors: packageManifest.manifest.extractors
279
+ });
280
+ }
281
+
282
+ context.packageExtractorState = { extractors, diagnostics, provenance };
283
+ return context.packageExtractorState;
284
+ }
285
+
286
+ /**
287
+ * @returns {any}
288
+ */
289
+ export function createExtractorSmokeContext() {
290
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "topogram-extractor-check."));
291
+ fs.writeFileSync(path.join(root, "package.json"), "{\"scripts\":{\"check\":\"topogram check\"}}\n", "utf8");
292
+ return packageExtractorContext(createImportContext(root, { from: "cli" }));
293
+ }
294
+
295
+ export { EXTRACTOR_MANIFESTS, getExtractorManifest };