@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.
@@ -0,0 +1,196 @@
1
+ // @ts-check
2
+
3
+ import {
4
+ loadPackageManifest,
5
+ packageInstallCommand,
6
+ packageInstallHint,
7
+ resolvePackageManifestPath
8
+ } from "../package-adapters/index.js";
9
+ import { BUILTIN_EXTRACTOR_PACKS } from "../import/core/registry.js";
10
+
11
+ export const EXTRACTOR_TRACKS = ["db", "api", "ui", "cli", "workflows", "verification"];
12
+
13
+ /**
14
+ * @typedef {Object} ExtractorManifest
15
+ * @property {string} id
16
+ * @property {string} version
17
+ * @property {string[]} tracks
18
+ * @property {"bundled"|"package"} source
19
+ * @property {string[]} extractors
20
+ * @property {Record<string, string>} stack
21
+ * @property {Record<string, boolean>} capabilities
22
+ * @property {string[]} candidateKinds
23
+ * @property {string[]} evidenceTypes
24
+ * @property {string} [package]
25
+ * @property {string} [export]
26
+ */
27
+
28
+ /**
29
+ * @typedef {Object} ExtractorBinding
30
+ * @property {string} id
31
+ * @property {string} track
32
+ * @property {string} packageName
33
+ * @property {string} version
34
+ */
35
+
36
+ /**
37
+ * @typedef {Object} ResolvedExtractorManifest
38
+ * @property {ExtractorManifest|null} manifest
39
+ * @property {string[]} errors
40
+ * @property {"bundled"|"package"|null} source
41
+ * @property {string|null} manifestPath
42
+ * @property {string|null} packageRoot
43
+ */
44
+
45
+ /** @type {ExtractorManifest[]} */
46
+ export const EXTRACTOR_MANIFESTS = BUILTIN_EXTRACTOR_PACKS.map((pack) => pack.manifest);
47
+
48
+ const EXTRACTOR_MANIFEST_BY_ID = new Map(EXTRACTOR_MANIFESTS.map((manifest) => [manifest.id, manifest]));
49
+
50
+ /**
51
+ * @param {any} value
52
+ * @param {boolean} [nonEmpty]
53
+ * @returns {boolean}
54
+ */
55
+ function isStringArray(value, nonEmpty = false) {
56
+ return Array.isArray(value) &&
57
+ (!nonEmpty || value.length > 0) &&
58
+ value.every((entry) => typeof entry === "string" && entry.length > 0);
59
+ }
60
+
61
+ /**
62
+ * @param {any} value
63
+ * @returns {value is Record<string, string>}
64
+ */
65
+ function isStringRecord(value) {
66
+ return Boolean(value) &&
67
+ typeof value === "object" &&
68
+ !Array.isArray(value) &&
69
+ Object.values(value).every((entry) => typeof entry === "string");
70
+ }
71
+
72
+ /**
73
+ * @param {any} value
74
+ * @returns {value is Record<string, boolean>}
75
+ */
76
+ function isBooleanRecord(value) {
77
+ return Boolean(value) &&
78
+ typeof value === "object" &&
79
+ !Array.isArray(value) &&
80
+ Object.values(value).every((entry) => typeof entry === "boolean");
81
+ }
82
+
83
+ /**
84
+ * @param {any} manifest
85
+ * @returns {{ ok: boolean, errors: string[] }}
86
+ */
87
+ export function validateExtractorManifest(manifest) {
88
+ const errors = [];
89
+ if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
90
+ return { ok: false, errors: ["Extractor manifest must be an object."] };
91
+ }
92
+ if (typeof manifest.id !== "string" || manifest.id.length === 0) {
93
+ errors.push("Extractor manifest id must be a non-empty string.");
94
+ }
95
+ if (typeof manifest.version !== "string" || manifest.version.length === 0) {
96
+ errors.push("Extractor manifest version must be a non-empty string.");
97
+ }
98
+ if (!isStringArray(manifest.tracks, true)) {
99
+ errors.push("Extractor manifest tracks must be a non-empty array of strings.");
100
+ } else {
101
+ for (const track of manifest.tracks) {
102
+ if (!EXTRACTOR_TRACKS.includes(track)) {
103
+ errors.push(`Extractor manifest track '${track}' is not supported.`);
104
+ }
105
+ }
106
+ }
107
+ if (manifest.source !== "bundled" && manifest.source !== "package") {
108
+ errors.push("Extractor manifest source must be 'bundled' or 'package'.");
109
+ }
110
+ if (!isStringArray(manifest.extractors, true)) {
111
+ errors.push("Extractor manifest extractors must be a non-empty array of strings.");
112
+ }
113
+ if (!isStringRecord(manifest.stack)) {
114
+ errors.push("Extractor manifest stack must be an object of string values.");
115
+ }
116
+ if (!isBooleanRecord(manifest.capabilities)) {
117
+ errors.push("Extractor manifest capabilities must be an object of boolean values.");
118
+ }
119
+ if (!isStringArray(manifest.candidateKinds)) {
120
+ errors.push("Extractor manifest candidateKinds must be an array of strings.");
121
+ }
122
+ if (!isStringArray(manifest.evidenceTypes)) {
123
+ errors.push("Extractor manifest evidenceTypes must be an array of strings.");
124
+ }
125
+ if (manifest.package != null && (typeof manifest.package !== "string" || manifest.package.length === 0)) {
126
+ errors.push("Extractor manifest package must be a non-empty string when present.");
127
+ }
128
+ if (manifest.export != null && (typeof manifest.export !== "string" || manifest.export.length === 0)) {
129
+ errors.push("Extractor manifest export must be a non-empty string when present.");
130
+ }
131
+ return { ok: errors.length === 0, errors };
132
+ }
133
+
134
+ /**
135
+ * @param {string} extractorId
136
+ * @returns {ExtractorManifest|null}
137
+ */
138
+ export function getExtractorManifest(extractorId) {
139
+ return EXTRACTOR_MANIFEST_BY_ID.get(extractorId) || null;
140
+ }
141
+
142
+ /**
143
+ * @param {string|null|undefined} packageName
144
+ * @returns {string|null}
145
+ */
146
+ export function packageExtractorInstallCommand(packageName) {
147
+ return packageInstallCommand(packageName);
148
+ }
149
+
150
+ /**
151
+ * @param {string|null|undefined} packageName
152
+ * @returns {string|null}
153
+ */
154
+ export function packageExtractorInstallHint(packageName) {
155
+ return packageInstallHint(packageName);
156
+ }
157
+
158
+ /**
159
+ * @param {string} packageName
160
+ * @param {string|null|undefined} rootDir
161
+ * @returns {{ manifestPath: string|null, packageRoot: string|null, error: string|null }}
162
+ */
163
+ export function resolvePackageExtractorManifestPath(packageName, rootDir = process.cwd()) {
164
+ return resolvePackageManifestPath(packageName, "topogram-extractor.json", rootDir, "Extractor package");
165
+ }
166
+
167
+ /**
168
+ * @param {string} packageName
169
+ * @param {string|null|undefined} rootDir
170
+ * @returns {{ manifest: ExtractorManifest|null, errors: string[], manifestPath: string|null, packageRoot: string|null }}
171
+ */
172
+ export function loadPackageExtractorManifest(packageName, rootDir = process.cwd()) {
173
+ return loadPackageManifest({
174
+ packageName,
175
+ rootDir,
176
+ manifestFile: "topogram-extractor.json",
177
+ packageLabel: "Extractor package",
178
+ validateManifest: validateExtractorManifest
179
+ });
180
+ }
181
+
182
+ /**
183
+ * @param {Record<string, any>|null|undefined} manifest
184
+ * @returns {ExtractorBinding[]}
185
+ */
186
+ export function extractorBindingsForManifest(manifest) {
187
+ if (!manifest || manifest.source !== "package" || typeof manifest.package !== "string") {
188
+ return [];
189
+ }
190
+ return (manifest.extractors || []).map((/** @type {any} */ extractorId) => ({
191
+ id: String(extractorId),
192
+ track: Array.isArray(manifest.tracks) && manifest.tracks.length === 1 ? String(manifest.tracks[0]) : "multiple",
193
+ packageName: String(manifest.package),
194
+ version: String(manifest.version || "unknown")
195
+ }));
196
+ }
@@ -0,0 +1,249 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ import { stableStringify } from "./format.js";
7
+ import {
8
+ optionalStringArray,
9
+ optionalStringRecord,
10
+ packageAllowedByPolicy,
11
+ packageScopeFromName as sharedPackageScopeFromName
12
+ } from "./package-adapters/index.js";
13
+
14
+ export const EXTRACTOR_POLICY_FILE = "topogram.extractor-policy.json";
15
+
16
+ /**
17
+ * @typedef {Object} ExtractorPolicy
18
+ * @property {string} version
19
+ * @property {string[]} allowedPackageScopes
20
+ * @property {string[]} allowedPackages
21
+ * @property {Record<string, string>} pinnedVersions
22
+ * @property {string[]} enabledPackages
23
+ */
24
+
25
+ /**
26
+ * @typedef {Object} PackageExtractorBinding
27
+ * @property {string} packageName
28
+ * @property {string} version
29
+ */
30
+
31
+ /**
32
+ * @typedef {Object} ExtractorPolicyInfo
33
+ * @property {string} path
34
+ * @property {ExtractorPolicy|null} policy
35
+ * @property {boolean} exists
36
+ * @property {ExtractorPolicyDiagnostic[]} diagnostics
37
+ */
38
+
39
+ /**
40
+ * @typedef {Object} ExtractorPolicyDiagnostic
41
+ * @property {string} code
42
+ * @property {"error"|"warning"} severity
43
+ * @property {string} message
44
+ * @property {string|null} path
45
+ * @property {string|null} suggestedFix
46
+ * @property {string|null} step
47
+ * @property {string|null} [packageName]
48
+ * @property {string|null} [version]
49
+ */
50
+
51
+ /**
52
+ * @param {Record<string, any>} input
53
+ * @returns {ExtractorPolicyDiagnostic}
54
+ */
55
+ function extractorPolicyDiagnostic(input) {
56
+ return {
57
+ code: String(input.code || "extractor_policy_failed"),
58
+ severity: input.severity === "warning" ? "warning" : "error",
59
+ message: String(input.message || "Extractor policy check failed."),
60
+ path: typeof input.path === "string" ? input.path : null,
61
+ suggestedFix: typeof input.suggestedFix === "string" ? input.suggestedFix : null,
62
+ step: typeof input.step === "string" ? input.step : null,
63
+ packageName: typeof input.packageName === "string" ? input.packageName : null,
64
+ version: typeof input.version === "string" ? input.version : null
65
+ };
66
+ }
67
+
68
+ /**
69
+ * @returns {ExtractorPolicy}
70
+ */
71
+ export function defaultExtractorPolicy() {
72
+ return {
73
+ version: "0.1",
74
+ allowedPackageScopes: [],
75
+ allowedPackages: [],
76
+ pinnedVersions: {},
77
+ enabledPackages: []
78
+ };
79
+ }
80
+
81
+ /**
82
+ * @param {unknown} value
83
+ * @param {string} policyPath
84
+ * @returns {ExtractorPolicy}
85
+ */
86
+ export function validateExtractorPolicy(value, policyPath) {
87
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
88
+ throw new Error(`${EXTRACTOR_POLICY_FILE} must contain a JSON object.`);
89
+ }
90
+ const raw = /** @type {Record<string, unknown>} */ (value);
91
+ const defaults = defaultExtractorPolicy();
92
+ return {
93
+ version: typeof raw.version === "string" && raw.version ? raw.version : defaults.version,
94
+ allowedPackageScopes: raw.allowedPackageScopes == null
95
+ ? defaults.allowedPackageScopes
96
+ : optionalStringArray(raw.allowedPackageScopes, "allowedPackageScopes", policyPath),
97
+ allowedPackages: optionalStringArray(raw.allowedPackages, "allowedPackages", policyPath),
98
+ pinnedVersions: optionalStringRecord(raw.pinnedVersions, policyPath, "package-or-extractor ids"),
99
+ enabledPackages: optionalStringArray(raw.enabledPackages, "enabledPackages", policyPath)
100
+ };
101
+ }
102
+
103
+ /**
104
+ * @param {string} packageName
105
+ * @returns {string|null}
106
+ */
107
+ export function packageScopeFromName(packageName) {
108
+ return sharedPackageScopeFromName(packageName);
109
+ }
110
+
111
+ /**
112
+ * @param {ExtractorPolicy} policy
113
+ * @param {string} packageName
114
+ * @returns {boolean}
115
+ */
116
+ export function extractorPackageAllowed(policy, packageName) {
117
+ return packageName.startsWith("@topogram/extractor-") || packageAllowedByPolicy(policy, packageName);
118
+ }
119
+
120
+ /**
121
+ * @param {string} projectRoot
122
+ * @param {string|null|undefined} policyPath
123
+ * @returns {string}
124
+ */
125
+ function resolvePolicyPath(projectRoot, policyPath) {
126
+ if (policyPath) {
127
+ const resolved = path.resolve(projectRoot, policyPath);
128
+ if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
129
+ return path.join(resolved, EXTRACTOR_POLICY_FILE);
130
+ }
131
+ return resolved;
132
+ }
133
+ return path.join(projectRoot, EXTRACTOR_POLICY_FILE);
134
+ }
135
+
136
+ /**
137
+ * @param {string} projectRoot
138
+ * @param {string|null|undefined} [policyPath]
139
+ * @returns {ExtractorPolicyInfo}
140
+ */
141
+ export function loadExtractorPolicy(projectRoot, policyPath = null) {
142
+ const resolvedPolicyPath = resolvePolicyPath(projectRoot, policyPath);
143
+ if (!fs.existsSync(resolvedPolicyPath)) {
144
+ return {
145
+ path: resolvedPolicyPath,
146
+ policy: null,
147
+ exists: false,
148
+ diagnostics: []
149
+ };
150
+ }
151
+ try {
152
+ return {
153
+ path: resolvedPolicyPath,
154
+ policy: validateExtractorPolicy(JSON.parse(fs.readFileSync(resolvedPolicyPath, "utf8")), resolvedPolicyPath),
155
+ exists: true,
156
+ diagnostics: []
157
+ };
158
+ } catch (error) {
159
+ return {
160
+ path: resolvedPolicyPath,
161
+ policy: null,
162
+ exists: true,
163
+ diagnostics: [extractorPolicyDiagnostic({
164
+ code: "extractor_policy_invalid",
165
+ message: error instanceof Error ? error.message : String(error),
166
+ path: resolvedPolicyPath,
167
+ suggestedFix: `Fix ${EXTRACTOR_POLICY_FILE} or regenerate it with \`topogram extractor policy init\`.`,
168
+ step: "extractor-policy"
169
+ })]
170
+ };
171
+ }
172
+ }
173
+
174
+ /**
175
+ * @param {ExtractorPolicyInfo} policyInfo
176
+ * @returns {ExtractorPolicy}
177
+ */
178
+ export function effectiveExtractorPolicy(policyInfo) {
179
+ return policyInfo.policy || defaultExtractorPolicy();
180
+ }
181
+
182
+ /**
183
+ * @param {string} projectRoot
184
+ * @param {ExtractorPolicy} policy
185
+ * @param {string|null|undefined} [policyPath]
186
+ * @returns {ExtractorPolicy}
187
+ */
188
+ export function writeExtractorPolicy(projectRoot, policy, policyPath = null) {
189
+ const resolvedPolicyPath = resolvePolicyPath(projectRoot, policyPath);
190
+ fs.writeFileSync(resolvedPolicyPath, `${stableStringify(policy)}\n`, "utf8");
191
+ return policy;
192
+ }
193
+
194
+ /**
195
+ * @param {ExtractorPolicyInfo} policyInfo
196
+ * @param {PackageExtractorBinding[]} bindings
197
+ * @param {string} [step]
198
+ * @returns {ExtractorPolicyDiagnostic[]}
199
+ */
200
+ export function extractorPolicyDiagnosticsForPackages(policyInfo, bindings, step = "extractor-policy") {
201
+ if (policyInfo.diagnostics.length > 0) {
202
+ return policyInfo.diagnostics;
203
+ }
204
+ const policy = effectiveExtractorPolicy(policyInfo);
205
+ /** @type {ExtractorPolicyDiagnostic[]} */
206
+ const diagnostics = [];
207
+ for (const binding of bindings) {
208
+ if (!extractorPackageAllowed(policy, binding.packageName)) {
209
+ const scope = packageScopeFromName(binding.packageName);
210
+ diagnostics.push(extractorPolicyDiagnostic({
211
+ code: "extractor_package_denied",
212
+ message: `Extractor package '${binding.packageName}' is not allowed by ${EXTRACTOR_POLICY_FILE}.`,
213
+ path: policyInfo.path,
214
+ suggestedFix: `Review '${binding.packageName}', then run \`topogram extractor policy pin ${binding.packageName}@${binding.version}\` or add '${scope || binding.packageName}' to ${EXTRACTOR_POLICY_FILE}.`,
215
+ step,
216
+ packageName: binding.packageName,
217
+ version: binding.version
218
+ }));
219
+ }
220
+ const pinnedVersion = policy.pinnedVersions[binding.packageName] || null;
221
+ if (pinnedVersion && pinnedVersion !== binding.version) {
222
+ diagnostics.push(extractorPolicyDiagnostic({
223
+ code: "extractor_version_mismatch",
224
+ message: `Extractor package '${binding.packageName}' uses version '${binding.version}', but ${EXTRACTOR_POLICY_FILE} pins it to '${pinnedVersion}'.`,
225
+ path: policyInfo.path,
226
+ suggestedFix: `Use extractor version '${pinnedVersion}', or run \`topogram extractor policy pin ${binding.packageName}@${binding.version}\` after review.`,
227
+ step,
228
+ packageName: binding.packageName,
229
+ version: binding.version
230
+ }));
231
+ }
232
+ }
233
+ return diagnostics;
234
+ }
235
+
236
+ /**
237
+ * @param {string} spec
238
+ * @returns {{ packageName: string, version: string }}
239
+ */
240
+ export function parseExtractorPolicyPin(spec) {
241
+ const separator = spec.lastIndexOf("@");
242
+ if (separator <= 0 || separator === spec.length - 1) {
243
+ throw new Error("Extractor policy pin requires a package name and extractor version, for example @topogram/extractor-node-cli@1.");
244
+ }
245
+ return {
246
+ packageName: spec.slice(0, separator),
247
+ version: spec.slice(separator + 1)
248
+ };
249
+ }
@@ -2,12 +2,18 @@
2
2
 
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
- import { createRequire } from "node:module";
6
5
 
7
6
  import {
8
7
  loadPackageGeneratorManifest,
9
8
  validateGeneratorManifest
10
9
  } from "./registry.js";
10
+ import {
11
+ isPathSpec,
12
+ loadInstalledPackageAdapter,
13
+ loadLocalPackageAdapter,
14
+ packageNameFromSpec,
15
+ validateRelativeStringFileMap
16
+ } from "../package-adapters/index.js";
11
17
 
12
18
  /**
13
19
  * @typedef {import("./registry.js").GeneratorManifest} GeneratorManifest
@@ -28,82 +34,6 @@ import {
28
34
  * @property {boolean} executesPackageCode
29
35
  */
30
36
 
31
- /**
32
- * @param {string} spec
33
- * @param {string} cwd
34
- * @returns {boolean}
35
- */
36
- function isPathSpec(spec, cwd) {
37
- return spec.startsWith(".") || spec.startsWith("/") || fs.existsSync(path.resolve(cwd, spec));
38
- }
39
-
40
- /**
41
- * @param {string} spec
42
- * @returns {string}
43
- */
44
- function packageNameFromSpec(spec) {
45
- if (spec.startsWith("@")) {
46
- const versionIndex = spec.indexOf("@", 1);
47
- return versionIndex > 0 ? spec.slice(0, versionIndex) : spec;
48
- }
49
- const versionIndex = spec.indexOf("@");
50
- return versionIndex > 0 ? spec.slice(0, versionIndex) : spec;
51
- }
52
-
53
- /**
54
- * @param {any} moduleValue
55
- * @param {string|null|undefined} exportName
56
- * @returns {any}
57
- */
58
- function selectPackageExport(moduleValue, exportName) {
59
- if (exportName) {
60
- return moduleValue?.[exportName] || moduleValue?.default?.[exportName] || null;
61
- }
62
- return moduleValue?.default || moduleValue;
63
- }
64
-
65
- /**
66
- * @param {string} root
67
- * @param {GeneratorManifest} manifest
68
- * @returns {{ adapter: any|null, error: string|null }}
69
- */
70
- function loadLocalAdapter(root, manifest) {
71
- try {
72
- const packageJsonPath = path.join(root, "package.json");
73
- const requireFromPackage = createRequire(packageJsonPath);
74
- return {
75
- adapter: selectPackageExport(requireFromPackage(root), manifest.export),
76
- error: null
77
- };
78
- } catch (error) {
79
- return {
80
- adapter: null,
81
- error: `Generator package export could not be loaded from '${root}': ${error instanceof Error ? error.message : String(error)}`
82
- };
83
- }
84
- }
85
-
86
- /**
87
- * @param {string} packageName
88
- * @param {string} rootDir
89
- * @param {GeneratorManifest} manifest
90
- * @returns {{ adapter: any|null, error: string|null }}
91
- */
92
- function loadInstalledAdapter(packageName, rootDir, manifest) {
93
- try {
94
- const requireFromRoot = createRequire(path.join(rootDir, "package.json"));
95
- return {
96
- adapter: selectPackageExport(requireFromRoot(packageName), manifest.export),
97
- error: null
98
- };
99
- } catch (error) {
100
- return {
101
- adapter: null,
102
- error: `Generator package '${packageName}' export could not be loaded from '${rootDir}': ${error instanceof Error ? error.message : String(error)}`
103
- };
104
- }
105
- }
106
-
107
37
  /**
108
38
  * @param {GeneratorManifest} manifest
109
39
  * @returns {Record<string, any>}
@@ -208,14 +138,12 @@ function validateSmokeResult(result) {
208
138
  if (!result.files || typeof result.files !== "object" || Array.isArray(result.files)) {
209
139
  return { ok: false, message: "generate(context) result must include a files object", smoke: null };
210
140
  }
211
- for (const [filePath, content] of Object.entries(result.files)) {
212
- const normalizedPath = typeof filePath === "string" ? path.normalize(filePath) : "";
213
- if (typeof filePath !== "string" || filePath.length === 0 || path.isAbsolute(filePath) || normalizedPath === ".." || normalizedPath.startsWith(`..${path.sep}`)) {
214
- return { ok: false, message: "generated file paths must be non-empty relative paths", smoke: null };
215
- }
216
- if (typeof content !== "string") {
217
- return { ok: false, message: `generated file '${filePath}' content must be a string`, smoke: null };
218
- }
141
+ const fileMapValidation = validateRelativeStringFileMap(result.files, {
142
+ filePathMessage: "generated file paths must be non-empty relative paths",
143
+ contentMessage: (filePath) => `generated file '${filePath}' content must be a string`
144
+ });
145
+ if (!fileMapValidation.ok) {
146
+ return { ok: false, message: fileMapValidation.message, smoke: null };
219
147
  }
220
148
  return {
221
149
  ok: true,
@@ -304,7 +232,11 @@ export function checkGeneratorPack(sourceSpec, options = {}) {
304
232
  }
305
233
 
306
234
  if (payload.source === "path") {
307
- const loaded = loadLocalAdapter(payload.packageRoot || cwd, payload.manifest);
235
+ const loaded = loadLocalPackageAdapter({
236
+ packageRoot: payload.packageRoot || cwd,
237
+ exportName: payload.manifest.export,
238
+ packageLabel: "Generator package"
239
+ });
308
240
  adapter = loaded.adapter;
309
241
  if (loaded.error) {
310
242
  payload.errors.push(loaded.error);
@@ -312,7 +244,12 @@ export function checkGeneratorPack(sourceSpec, options = {}) {
312
244
  return payload;
313
245
  }
314
246
  } else if (payload.packageName) {
315
- const loaded = loadInstalledAdapter(payload.packageName, cwd, payload.manifest);
247
+ const loaded = loadInstalledPackageAdapter({
248
+ packageName: payload.packageName,
249
+ rootDir: cwd,
250
+ exportName: payload.manifest.export,
251
+ packageLabel: "Generator package"
252
+ });
316
253
  adapter = loaded.adapter;
317
254
  if (loaded.error) {
318
255
  payload.errors.push(loaded.error);