@auraindustry/aurajs 0.1.1 → 0.1.5
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 +7 -0
- package/benchmarks/perf-thresholds.json +27 -0
- package/package.json +6 -1
- package/src/ai-guidance.mjs +302 -0
- package/src/asset-pack.mjs +2 -1
- package/src/authored-project.mjs +498 -2
- package/src/authored-runtime.mjs +14 -0
- package/src/bin-integrity.mjs +33 -26
- package/src/build-contract/capabilities.mjs +87 -1
- package/src/build-contract/constants.mjs +1 -0
- package/src/build-contract.mjs +2 -0
- package/src/bundler.mjs +143 -13
- package/src/cli.mjs +681 -13
- package/src/commands/packs.mjs +741 -0
- package/src/commands/project-authoring.mjs +128 -1
- package/src/conformance/cases/app-and-ui-runtime-cases.mjs +1 -2
- package/src/conformance/cases/core-runtime-cases.mjs +6 -2
- package/src/conformance/cases/scene3d-and-media-cases.mjs +238 -0
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +1126 -10
- package/src/conformance-mobile.mjs +166 -0
- package/src/conformance.mjs +89 -30
- package/src/evidence-bundle.mjs +242 -0
- package/src/external-package-surface.mjs +1 -1
- package/src/headless-test/runtime-coordinator.mjs +186 -33
- package/src/headless-test.mjs +2 -0
- package/src/helpers/2d/index.mjs +183 -0
- package/src/helpers/index.mjs +26 -0
- package/src/helpers/starter-utils/adventure-objectives.js +102 -0
- package/src/helpers/starter-utils/adventure-world-2d.js +221 -0
- package/src/helpers/starter-utils/animation-2d.js +337 -0
- package/src/helpers/starter-utils/animation-packaging-2d.js +203 -0
- package/src/helpers/starter-utils/atlas-assets-2d.js +111 -0
- package/src/helpers/starter-utils/autoplay-debug-2d.js +215 -0
- package/src/helpers/starter-utils/avatar-3d.js +404 -0
- package/src/helpers/starter-utils/combat-feedback-2d.js +320 -0
- package/src/helpers/starter-utils/combat-runtime-2d.js +290 -0
- package/src/helpers/starter-utils/core.js +150 -0
- package/src/helpers/starter-utils/dialogue-2d.js +351 -0
- package/src/helpers/starter-utils/enemy-archetypes-2d.js +68 -0
- package/src/helpers/starter-utils/index.js +26 -0
- package/src/helpers/starter-utils/inventory-2d.js +268 -0
- package/src/helpers/starter-utils/journal-2d.js +267 -0
- package/src/helpers/starter-utils/platformer-3d.js +132 -0
- package/src/helpers/starter-utils/scene-audio-2d.js +236 -0
- package/src/helpers/starter-utils/streamed-world-2d.js +378 -0
- package/src/helpers/starter-utils/tilemap-nav-2d.js +499 -0
- package/src/helpers/starter-utils/tilemap-world-2d.js +205 -0
- package/src/helpers/starter-utils/triggers.js +662 -0
- package/src/helpers/starter-utils/tween-2d.js +615 -0
- package/src/helpers/starter-utils/wave-director.js +101 -0
- package/src/helpers/starter-utils/world-compositor-2d.js +253 -0
- package/src/helpers/starter-utils/world-persistence-2d.js +180 -0
- package/src/mobile/android/build.mjs +606 -0
- package/src/mobile/android/host-artifact.mjs +280 -0
- package/src/mobile/ios/build.mjs +1323 -0
- package/src/mobile/ios/host-artifact.mjs +819 -0
- package/src/mobile/shared/capabilities.mjs +174 -0
- package/src/package-integrity.mjs +18 -4
- package/src/packs/catalog.mjs +259 -0
- package/src/perf-benchmark-runner.mjs +17 -12
- package/src/perf-benchmark.mjs +408 -4
- package/src/publish-command.mjs +434 -17
- package/src/publish-validation.mjs +22 -11
- package/src/replay-runtime.mjs +257 -0
- package/src/scaffold/config.mjs +2 -0
- package/src/scaffold/fs.mjs +8 -1
- package/src/scaffold/project-docs.mjs +101 -41
- package/src/scaffold.mjs +4 -0
- package/src/session-runtime.mjs +4 -3
- package/src/web-conformance.mjs +0 -36
- package/templates/create/2d/src/runtime/app.js +4 -0
- package/templates/create/2d-adventure/config/gameplay/adventure.config.js +9 -6
- package/templates/create/2d-adventure/content/gameplay/dialogue.js +85 -0
- package/templates/create/2d-adventure/content/gameplay/world.js +32 -36
- package/templates/create/2d-adventure/content/gameplay/world.tilemap.json +273 -0
- package/templates/create/2d-adventure/docs/design/loop.md +4 -3
- package/templates/create/2d-adventure/prefabs/relic.prefab.js +10 -10
- package/templates/create/2d-adventure/prefabs/world.prefab.js +127 -74
- package/templates/create/2d-adventure/scenes/gameplay.scene.js +603 -112
- package/templates/create/2d-adventure/src/runtime/capabilities.js +16 -0
- package/templates/create/2d-adventure/ui/hud.screen.js +187 -4
- package/templates/create/2d-adventure/ui/journal.screen.js +183 -0
- package/templates/create/2d-survivor/src/runtime/app.js +4 -0
- package/templates/create/3d/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d/src/runtime/app.js +4 -0
- package/templates/create/3d/src/runtime/capabilities.js +5 -0
- package/templates/create/3d/src/runtime/materials.js +10 -0
- package/templates/create/3d-adventure/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-adventure/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-adventure/src/runtime/materials.js +11 -0
- package/templates/create/3d-collectathon/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-collectathon/src/runtime/app.js +4 -0
- package/templates/create/3d-collectathon/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-collectathon/src/runtime/materials.js +10 -0
- package/templates/create/blank/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/blank/assets/splash/bg.webp +0 -0
- package/templates/create/blank/assets/splash/boot-loop.wav +0 -0
- package/templates/create/blank/assets/splash/boot-sting.wav +0 -0
- package/templates/create/blank/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/blank/assets/splash/logoholo.webp +0 -0
- package/templates/create/blank/src/main.js +5 -1
- package/templates/create/blank/src/runtime/splash.js +305 -0
- package/templates/create/local-multiplayer/scenes/gameplay.scene.js +186 -12
- package/templates/create/local-multiplayer/src/runtime/capabilities.js +8 -1
- package/templates/create/shared/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/shared/assets/splash/bg.webp +0 -0
- package/templates/create/shared/assets/splash/boot-loop.wav +0 -0
- package/templates/create/shared/assets/splash/boot-sting.wav +0 -0
- package/templates/create/shared/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/shared/assets/splash/logoholo.webp +0 -0
- package/templates/create/shared/src/runtime/splash.js +305 -0
- package/templates/create/shared/src/runtime/ui-forms.js +552 -0
- package/templates/create/shared/src/starter-utils/adventure-world-2d.js +221 -0
- package/templates/create/shared/src/starter-utils/animation-packaging-2d.js +203 -0
- package/templates/create/shared/src/starter-utils/atlas-assets-2d.js +111 -0
- package/templates/create/shared/src/starter-utils/autoplay-debug-2d.js +215 -0
- package/templates/create/shared/src/starter-utils/combat-runtime-2d.js +290 -0
- package/templates/create/shared/src/starter-utils/dialogue-2d.js +351 -0
- package/templates/create/shared/src/starter-utils/index.js +15 -1
- package/templates/create/shared/src/starter-utils/inventory-2d.js +268 -0
- package/templates/create/shared/src/starter-utils/journal-2d.js +267 -0
- package/templates/create/shared/src/starter-utils/scene-audio-2d.js +236 -0
- package/templates/create/shared/src/starter-utils/streamed-world-2d.js +378 -0
- package/templates/create/shared/src/starter-utils/tilemap-nav-2d.js +499 -0
- package/templates/create/shared/src/starter-utils/tilemap-world-2d.js +205 -0
- package/templates/create/shared/src/starter-utils/world-compositor-2d.js +253 -0
- package/templates/create/shared/src/starter-utils/world-persistence-2d.js +180 -0
- package/templates/create/video-cutscene/src/runtime/app.js +4 -0
- package/templates/create-bin/play.js +148 -7
- package/templates/skills/auramaxx/SKILL.md +46 -0
- package/templates/skills/auramaxx/project-requirements.md +68 -0
- package/templates/skills/auramaxx/starter-recipes.md +104 -0
- package/templates/skills/auramaxx/validation-checklist.md +49 -0
- package/templates/starter/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/starter/assets/splash/bg.webp +0 -0
- package/templates/starter/assets/splash/boot-loop.wav +0 -0
- package/templates/starter/assets/splash/boot-sting.wav +0 -0
- package/templates/starter/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/starter/assets/splash/logoholo.webp +0 -0
- package/templates/starter/src/main.js +4 -0
- package/templates/starter/src/runtime/splash.js +305 -0
- package/templates/skills/aurajs/SKILL.md +0 -96
- package/templates/skills/aurajs/api-contract-3d.md +0 -7
- package/templates/skills/aurajs/api-contract.md +0 -7
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cpSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
rmSync,
|
|
9
|
+
statSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from 'node:fs';
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { join, resolve } from 'node:path';
|
|
15
|
+
|
|
16
|
+
import { assertAuraProjectRoot } from '../authored-project.mjs';
|
|
17
|
+
import {
|
|
18
|
+
PROJECT_PACKS_MANIFEST_PATH,
|
|
19
|
+
PROJECT_PACKS_SCHEMA,
|
|
20
|
+
createPackCatalogReport,
|
|
21
|
+
expandPackSelection,
|
|
22
|
+
findPackOrBundleEntry,
|
|
23
|
+
normalizeProjectPackManifest,
|
|
24
|
+
resolvePackInstallSpec,
|
|
25
|
+
} from '../packs/catalog.mjs';
|
|
26
|
+
|
|
27
|
+
export const PACKS_USAGE = 'aura packs <list|show|add|vendor> [options]';
|
|
28
|
+
const PACK_DEFINITION_PATH = 'aurajs-pack.json';
|
|
29
|
+
|
|
30
|
+
function raiseCliError(errorHandler, message) {
|
|
31
|
+
if (typeof errorHandler === 'function') {
|
|
32
|
+
errorHandler(message);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(message);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function handlePackCommandError(errorHandler, err) {
|
|
39
|
+
raiseCliError(errorHandler, err instanceof Error ? err.message : String(err));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readJsonFile(path) {
|
|
43
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function writeJsonFile(path, payload) {
|
|
47
|
+
writeFileSync(path, `${JSON.stringify(payload, null, 2)}\n`, 'utf8');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function readProjectPackageJson(projectRoot) {
|
|
51
|
+
const packageJsonPath = resolve(projectRoot, 'package.json');
|
|
52
|
+
if (!existsSync(packageJsonPath)) {
|
|
53
|
+
throw new Error('Missing package.json in the current AuraJS project.');
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
path: packageJsonPath,
|
|
57
|
+
payload: readJsonFile(packageJsonPath),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readProjectPackManifest(projectRoot) {
|
|
62
|
+
const manifestPath = resolve(projectRoot, PROJECT_PACKS_MANIFEST_PATH);
|
|
63
|
+
if (!existsSync(manifestPath)) {
|
|
64
|
+
return {
|
|
65
|
+
path: manifestPath,
|
|
66
|
+
payload: normalizeProjectPackManifest(null),
|
|
67
|
+
existed: false,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
path: manifestPath,
|
|
72
|
+
payload: normalizeProjectPackManifest(readJsonFile(manifestPath)),
|
|
73
|
+
existed: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseListArgs(args) {
|
|
78
|
+
let json = false;
|
|
79
|
+
for (const arg of args) {
|
|
80
|
+
if (arg === '--json') {
|
|
81
|
+
json = true;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (arg.startsWith('--')) {
|
|
85
|
+
throw new Error(`Unknown option for packs list: ${arg}`);
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Unexpected extra argument "${arg}". Usage: aura packs list [--json]`);
|
|
88
|
+
}
|
|
89
|
+
return { json };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parseShowArgs(args) {
|
|
93
|
+
let id = null;
|
|
94
|
+
let json = false;
|
|
95
|
+
for (const arg of args) {
|
|
96
|
+
if (arg === '--json') {
|
|
97
|
+
json = true;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (arg.startsWith('--')) {
|
|
101
|
+
throw new Error(`Unknown option for packs show: ${arg}`);
|
|
102
|
+
}
|
|
103
|
+
if (id !== null) {
|
|
104
|
+
throw new Error(`Unexpected extra argument "${arg}". Usage: aura packs show <id> [--json]`);
|
|
105
|
+
}
|
|
106
|
+
id = arg;
|
|
107
|
+
}
|
|
108
|
+
if (!id) {
|
|
109
|
+
throw new Error('Missing pack or bundle id. Usage: aura packs show <id> [--json]');
|
|
110
|
+
}
|
|
111
|
+
return { id, json };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function parsePackSourceArgs(args, mode) {
|
|
115
|
+
const parsed = {
|
|
116
|
+
id: null,
|
|
117
|
+
json: false,
|
|
118
|
+
install: false,
|
|
119
|
+
force: false,
|
|
120
|
+
source: mode === 'vendor' ? 'auto' : 'package',
|
|
121
|
+
ref: null,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
125
|
+
const arg = args[index];
|
|
126
|
+
if (arg === '--json') {
|
|
127
|
+
parsed.json = true;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (arg === '--install') {
|
|
131
|
+
parsed.install = true;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (arg === '--force') {
|
|
135
|
+
parsed.force = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (arg === '--workspace') {
|
|
139
|
+
parsed.source = 'workspace';
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (arg === '--github') {
|
|
143
|
+
parsed.source = 'github';
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (arg === '--installed') {
|
|
147
|
+
parsed.source = 'installed';
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (arg === '--source') {
|
|
151
|
+
const value = args[index + 1];
|
|
152
|
+
if (!value || value.startsWith('--')) {
|
|
153
|
+
throw new Error(`Missing value for --source. Usage: aura packs ${mode} <id> [options]`);
|
|
154
|
+
}
|
|
155
|
+
parsed.source = value;
|
|
156
|
+
index += 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (arg.startsWith('--source=')) {
|
|
160
|
+
parsed.source = arg.slice('--source='.length);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (arg === '--ref') {
|
|
164
|
+
const value = args[index + 1];
|
|
165
|
+
if (!value || value.startsWith('--')) {
|
|
166
|
+
throw new Error(`Missing value for --ref. Usage: aura packs ${mode} <id> [options]`);
|
|
167
|
+
}
|
|
168
|
+
parsed.ref = value;
|
|
169
|
+
index += 1;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
if (arg.startsWith('--ref=')) {
|
|
173
|
+
parsed.ref = arg.slice('--ref='.length);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (arg.startsWith('--')) {
|
|
177
|
+
throw new Error(`Unknown option for packs ${mode}: ${arg}`);
|
|
178
|
+
}
|
|
179
|
+
if (parsed.id !== null) {
|
|
180
|
+
throw new Error(`Unexpected extra argument "${arg}". Usage: aura packs ${mode} <id> [options]`);
|
|
181
|
+
}
|
|
182
|
+
parsed.id = arg;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!parsed.id) {
|
|
186
|
+
throw new Error(`Missing pack or bundle id. Usage: aura packs ${mode} <id> [options]`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const validSources = mode === 'vendor'
|
|
190
|
+
? new Set(['auto', 'workspace', 'installed', 'github'])
|
|
191
|
+
: new Set(['package', 'workspace']);
|
|
192
|
+
if (!validSources.has(parsed.source)) {
|
|
193
|
+
throw new Error(`Unsupported --source "${parsed.source}" for packs ${mode}. Expected one of: ${[...validSources].join(', ')}.`);
|
|
194
|
+
}
|
|
195
|
+
if (mode !== 'vendor' && parsed.ref) {
|
|
196
|
+
throw new Error('--ref is only supported for packs vendor.');
|
|
197
|
+
}
|
|
198
|
+
if (mode !== 'vendor' && parsed.force) {
|
|
199
|
+
throw new Error('--force is only supported for packs vendor.');
|
|
200
|
+
}
|
|
201
|
+
if (mode === 'vendor' && parsed.install) {
|
|
202
|
+
throw new Error('--install is not supported for packs vendor.');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return parsed;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function resolveInstalledPackRoot(projectRoot, packageName) {
|
|
209
|
+
const packageSegments = String(packageName || '').split('/');
|
|
210
|
+
return resolve(projectRoot, 'node_modules', ...packageSegments);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function readPackDefinition(rootPath) {
|
|
214
|
+
const definitionPath = resolve(rootPath, PACK_DEFINITION_PATH);
|
|
215
|
+
if (!existsSync(definitionPath)) {
|
|
216
|
+
throw new Error(`Missing ${PACK_DEFINITION_PATH} in pack root ${rootPath}.`);
|
|
217
|
+
}
|
|
218
|
+
const definition = readJsonFile(definitionPath);
|
|
219
|
+
if (typeof definition?.id !== 'string' || definition.id.trim().length === 0) {
|
|
220
|
+
throw new Error(`Invalid ${PACK_DEFINITION_PATH} in ${rootPath}: missing pack id.`);
|
|
221
|
+
}
|
|
222
|
+
return definition;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function ensureDirectory(path) {
|
|
226
|
+
mkdirSync(path, { recursive: true });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function normalizeVendorTargets(definition) {
|
|
230
|
+
return Array.isArray(definition?.vendorTargets)
|
|
231
|
+
? definition.vendorTargets
|
|
232
|
+
.filter((entry) => entry && typeof entry === 'object' && !Array.isArray(entry))
|
|
233
|
+
.map((entry) => ({
|
|
234
|
+
source: typeof entry.source === 'string' ? entry.source : null,
|
|
235
|
+
target: typeof entry.target === 'string' ? entry.target : null,
|
|
236
|
+
}))
|
|
237
|
+
.filter((entry) => entry.source && entry.target)
|
|
238
|
+
: [];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function updateProjectPackManifest(manifest, selection, resolvedPacks) {
|
|
242
|
+
const next = normalizeProjectPackManifest(manifest);
|
|
243
|
+
const selectedKeys = new Set(next.selected.map((entry) => `${entry.kind}:${entry.id}`));
|
|
244
|
+
const packIds = new Set(next.packs.map((entry) => entry.id));
|
|
245
|
+
const bundleIds = new Set(next.bundles.map((entry) => entry.id));
|
|
246
|
+
|
|
247
|
+
if (!selectedKeys.has(`${selection.requested.kind}:${selection.requested.id}`)) {
|
|
248
|
+
next.selected.push({
|
|
249
|
+
id: selection.requested.id,
|
|
250
|
+
kind: selection.requested.kind,
|
|
251
|
+
sourceMode: selection.requested.sourceMode || 'package',
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
for (const entry of resolvedPacks) {
|
|
256
|
+
if (packIds.has(entry.id)) {
|
|
257
|
+
const target = next.packs.find((item) => item.id === entry.id);
|
|
258
|
+
target.packageName = entry.packageName;
|
|
259
|
+
target.spec = entry.spec;
|
|
260
|
+
target.installMode = entry.installMode;
|
|
261
|
+
target.sourceMode = entry.sourceMode;
|
|
262
|
+
target.vendoredPaths = [...(entry.vendoredPaths || [])];
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
next.packs.push({
|
|
266
|
+
id: entry.id,
|
|
267
|
+
kind: entry.kind,
|
|
268
|
+
packageName: entry.packageName,
|
|
269
|
+
spec: entry.spec,
|
|
270
|
+
installMode: entry.installMode,
|
|
271
|
+
sourceMode: entry.sourceMode,
|
|
272
|
+
vendoredPaths: [...(entry.vendoredPaths || [])],
|
|
273
|
+
});
|
|
274
|
+
packIds.add(entry.id);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
for (const bundle of selection.bundles) {
|
|
278
|
+
if (bundleIds.has(bundle.id)) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
next.bundles.push({
|
|
282
|
+
id: bundle.id,
|
|
283
|
+
packageName: bundle.packageName,
|
|
284
|
+
memberPackIds: [...bundle.memberPackIds],
|
|
285
|
+
});
|
|
286
|
+
bundleIds.add(bundle.id);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
schema: PROJECT_PACKS_SCHEMA,
|
|
291
|
+
selected: next.selected,
|
|
292
|
+
packs: next.packs,
|
|
293
|
+
bundles: next.bundles,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function cmdList(parsed) {
|
|
298
|
+
const report = createPackCatalogReport();
|
|
299
|
+
if (parsed.json) {
|
|
300
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
console.log('');
|
|
305
|
+
console.log(' AuraJS Packs');
|
|
306
|
+
console.log('');
|
|
307
|
+
for (const entry of report.packs) {
|
|
308
|
+
console.log(` ${entry.id}`);
|
|
309
|
+
console.log(` kind: ${entry.kind}`);
|
|
310
|
+
console.log(` package: ${entry.packageName}`);
|
|
311
|
+
console.log(` summary: ${entry.description}`);
|
|
312
|
+
}
|
|
313
|
+
console.log('');
|
|
314
|
+
console.log(' AuraJS Bundles');
|
|
315
|
+
console.log('');
|
|
316
|
+
for (const entry of report.bundles) {
|
|
317
|
+
console.log(` ${entry.id}`);
|
|
318
|
+
console.log(` package: ${entry.packageName}`);
|
|
319
|
+
console.log(` members: ${entry.memberPackIds.join(', ')}`);
|
|
320
|
+
console.log(` summary: ${entry.description}`);
|
|
321
|
+
}
|
|
322
|
+
console.log('');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function cmdShow(parsed) {
|
|
326
|
+
const entry = findPackOrBundleEntry(parsed.id);
|
|
327
|
+
if (!entry) {
|
|
328
|
+
throw new Error(`Unknown pack or bundle "${parsed.id}". Run "aura packs list" for available ids.`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const payload = {
|
|
332
|
+
schema: 'aurajs.pack-entry.v1',
|
|
333
|
+
id: entry.id,
|
|
334
|
+
kind: entry.kind,
|
|
335
|
+
title: entry.title,
|
|
336
|
+
description: entry.description,
|
|
337
|
+
packageName: entry.packageName,
|
|
338
|
+
versionRange: entry.versionRange,
|
|
339
|
+
workspaceAvailable: entry.workspaceAvailable,
|
|
340
|
+
github: entry.github ? { ...entry.github } : null,
|
|
341
|
+
recommendedFor: Array.isArray(entry.recommendedFor) ? [...entry.recommendedFor] : [],
|
|
342
|
+
surfaces: Array.isArray(entry.surfaces) ? [...entry.surfaces] : [],
|
|
343
|
+
memberPackIds: Array.isArray(entry.memberPackIds) ? [...entry.memberPackIds] : [],
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
if (parsed.json) {
|
|
347
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
console.log('');
|
|
352
|
+
console.log(` ${payload.title}`);
|
|
353
|
+
console.log('');
|
|
354
|
+
console.log(` id: ${payload.id}`);
|
|
355
|
+
console.log(` kind: ${payload.kind}`);
|
|
356
|
+
console.log(` package: ${payload.packageName}`);
|
|
357
|
+
console.log(` version: ${payload.versionRange}`);
|
|
358
|
+
console.log(` summary: ${payload.description}`);
|
|
359
|
+
if (payload.github?.repository) {
|
|
360
|
+
console.log(` github: ${payload.github.repository}#${payload.github.ref || 'main'}`);
|
|
361
|
+
}
|
|
362
|
+
if (payload.memberPackIds.length > 0) {
|
|
363
|
+
console.log(` members: ${payload.memberPackIds.join(', ')}`);
|
|
364
|
+
}
|
|
365
|
+
console.log('');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function cmdAdd(parsed) {
|
|
369
|
+
const projectRoot = process.cwd();
|
|
370
|
+
assertAuraProjectRoot(projectRoot);
|
|
371
|
+
const selection = expandPackSelection(parsed.id);
|
|
372
|
+
if (!selection) {
|
|
373
|
+
throw new Error(`Unknown pack or bundle "${parsed.id}". Run "aura packs list" for available ids.`);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const packageJson = readProjectPackageJson(projectRoot);
|
|
377
|
+
const manifest = readProjectPackManifest(projectRoot);
|
|
378
|
+
const dependencies = packageJson.payload.dependencies && typeof packageJson.payload.dependencies === 'object'
|
|
379
|
+
? { ...packageJson.payload.dependencies }
|
|
380
|
+
: {};
|
|
381
|
+
|
|
382
|
+
const resolvedPacks = selection.packs.map((entry) => {
|
|
383
|
+
const resolution = resolvePackInstallSpec(entry, {
|
|
384
|
+
projectRoot,
|
|
385
|
+
workspace: parsed.source === 'workspace',
|
|
386
|
+
});
|
|
387
|
+
dependencies[entry.packageName] = resolution.spec;
|
|
388
|
+
return {
|
|
389
|
+
id: entry.id,
|
|
390
|
+
kind: entry.kind,
|
|
391
|
+
title: entry.title,
|
|
392
|
+
packageName: entry.packageName,
|
|
393
|
+
spec: resolution.spec,
|
|
394
|
+
installMode: resolution.mode,
|
|
395
|
+
sourceMode: resolution.mode,
|
|
396
|
+
vendoredPaths: [],
|
|
397
|
+
};
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
packageJson.payload.dependencies = Object.fromEntries(
|
|
401
|
+
Object.entries(dependencies).sort(([left], [right]) => left.localeCompare(right)),
|
|
402
|
+
);
|
|
403
|
+
writeJsonFile(packageJson.path, packageJson.payload);
|
|
404
|
+
|
|
405
|
+
const nextManifest = updateProjectPackManifest(
|
|
406
|
+
manifest.payload,
|
|
407
|
+
{
|
|
408
|
+
...selection,
|
|
409
|
+
requested: {
|
|
410
|
+
...selection.requested,
|
|
411
|
+
sourceMode: parsed.source,
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
resolvedPacks,
|
|
415
|
+
);
|
|
416
|
+
writeJsonFile(manifest.path, nextManifest);
|
|
417
|
+
|
|
418
|
+
let install = null;
|
|
419
|
+
if (parsed.install) {
|
|
420
|
+
install = spawnSync('npm', ['install'], {
|
|
421
|
+
cwd: projectRoot,
|
|
422
|
+
stdio: 'pipe',
|
|
423
|
+
encoding: 'utf8',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const report = {
|
|
428
|
+
schema: 'aurajs.packs-add.v1',
|
|
429
|
+
ok: install ? install.status === 0 : true,
|
|
430
|
+
reasonCode: install
|
|
431
|
+
? (install.status === 0 ? 'project_packs_added_and_installed' : 'project_packs_added_install_failed')
|
|
432
|
+
: 'project_packs_added',
|
|
433
|
+
requestedId: selection.requested.id,
|
|
434
|
+
requestedKind: selection.requested.kind,
|
|
435
|
+
dependenciesAdded: resolvedPacks.map((entry) => ({
|
|
436
|
+
id: entry.id,
|
|
437
|
+
packageName: entry.packageName,
|
|
438
|
+
spec: entry.spec,
|
|
439
|
+
installMode: entry.installMode,
|
|
440
|
+
sourceMode: entry.sourceMode,
|
|
441
|
+
})),
|
|
442
|
+
bundles: selection.bundles.map((entry) => ({
|
|
443
|
+
id: entry.id,
|
|
444
|
+
packageName: entry.packageName,
|
|
445
|
+
memberPackIds: [...entry.memberPackIds],
|
|
446
|
+
})),
|
|
447
|
+
manifestPath: PROJECT_PACKS_MANIFEST_PATH,
|
|
448
|
+
installRequested: parsed.install,
|
|
449
|
+
installStatus: install ? install.status : null,
|
|
450
|
+
installStdout: install?.stdout || '',
|
|
451
|
+
installStderr: install?.stderr || '',
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
if (parsed.json) {
|
|
455
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
console.log('');
|
|
460
|
+
console.log(' Added optional pack selection');
|
|
461
|
+
console.log('');
|
|
462
|
+
console.log(` Requested: ${selection.requested.id}`);
|
|
463
|
+
console.log(` Packages: ${resolvedPacks.map((entry) => entry.id).join(', ')}`);
|
|
464
|
+
console.log(` Manifest: ${PROJECT_PACKS_MANIFEST_PATH}`);
|
|
465
|
+
if (parsed.install) {
|
|
466
|
+
console.log(` Install status: ${install?.status === 0 ? 'ok' : 'failed'}`);
|
|
467
|
+
} else {
|
|
468
|
+
console.log(' Next step: npm install');
|
|
469
|
+
}
|
|
470
|
+
console.log('');
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function resolveVendorSourceMode(entry, projectRoot, requestedSource) {
|
|
474
|
+
if (requestedSource === 'workspace') {
|
|
475
|
+
return 'workspace';
|
|
476
|
+
}
|
|
477
|
+
if (requestedSource === 'installed') {
|
|
478
|
+
return 'installed';
|
|
479
|
+
}
|
|
480
|
+
if (requestedSource === 'github') {
|
|
481
|
+
return 'github';
|
|
482
|
+
}
|
|
483
|
+
if (entry.workspaceAvailable) {
|
|
484
|
+
return 'workspace';
|
|
485
|
+
}
|
|
486
|
+
if (existsSync(resolveInstalledPackRoot(projectRoot, entry.packageName))) {
|
|
487
|
+
return 'installed';
|
|
488
|
+
}
|
|
489
|
+
return 'github';
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async function resolveVendorPackRoot(entry, projectRoot, requestedSource, ref) {
|
|
493
|
+
const sourceMode = resolveVendorSourceMode(entry, projectRoot, requestedSource);
|
|
494
|
+
if (sourceMode === 'workspace') {
|
|
495
|
+
if (!entry.workspaceAvailable) {
|
|
496
|
+
throw new Error(`Pack "${entry.id}" is not available in the current AuraJS workspace.`);
|
|
497
|
+
}
|
|
498
|
+
return {
|
|
499
|
+
sourceMode,
|
|
500
|
+
rootPath: entry.workspacePath,
|
|
501
|
+
ref: null,
|
|
502
|
+
archiveUrl: null,
|
|
503
|
+
cleanup() {},
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (sourceMode === 'installed') {
|
|
508
|
+
const rootPath = resolveInstalledPackRoot(projectRoot, entry.packageName);
|
|
509
|
+
if (!existsSync(rootPath)) {
|
|
510
|
+
throw new Error(`Pack "${entry.id}" is not installed in node_modules. Run "aura packs add ${entry.id} --install" first or use --source workspace/github.`);
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
sourceMode,
|
|
514
|
+
rootPath,
|
|
515
|
+
ref: null,
|
|
516
|
+
archiveUrl: null,
|
|
517
|
+
cleanup() {},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (!entry.github?.repository || !entry.github?.packPath) {
|
|
522
|
+
throw new Error(`Pack "${entry.id}" does not declare a GitHub source.`);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const tempRoot = mkdtempSync(join(tmpdir(), 'aurajs-pack-github-'));
|
|
526
|
+
const archivePath = join(tempRoot, 'pack.tar.gz');
|
|
527
|
+
const extractRoot = join(tempRoot, 'extract');
|
|
528
|
+
ensureDirectory(extractRoot);
|
|
529
|
+
const resolvedRef = ref || entry.github.ref || 'main';
|
|
530
|
+
const archiveUrl = `https://codeload.github.com/${entry.github.repository}/tar.gz/${resolvedRef}`;
|
|
531
|
+
|
|
532
|
+
const response = await fetch(archiveUrl);
|
|
533
|
+
if (!response.ok) {
|
|
534
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
535
|
+
throw new Error(`Unable to download pack archive for "${entry.id}" from ${archiveUrl} (${response.status} ${response.statusText}).`);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
writeFileSync(archivePath, Buffer.from(await response.arrayBuffer()));
|
|
539
|
+
const extract = spawnSync('tar', ['-xzf', archivePath, '-C', extractRoot], {
|
|
540
|
+
encoding: 'utf8',
|
|
541
|
+
});
|
|
542
|
+
if (extract.status !== 0) {
|
|
543
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
544
|
+
throw new Error(`Unable to extract GitHub archive for "${entry.id}": ${extract.stderr || extract.stdout}`.trim());
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const extractedRoot = readdirSync(extractRoot, { withFileTypes: true }).find((entryDir) => entryDir.isDirectory());
|
|
548
|
+
if (!extractedRoot) {
|
|
549
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
550
|
+
throw new Error(`GitHub archive for "${entry.id}" did not contain an extracted root directory.`);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const rootPath = resolve(extractRoot, extractedRoot.name, entry.github.packPath);
|
|
554
|
+
if (!existsSync(rootPath)) {
|
|
555
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
556
|
+
throw new Error(`GitHub archive for "${entry.id}" is missing pack path "${entry.github.packPath}".`);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return {
|
|
560
|
+
sourceMode,
|
|
561
|
+
rootPath,
|
|
562
|
+
ref: resolvedRef,
|
|
563
|
+
archiveUrl,
|
|
564
|
+
cleanup() {
|
|
565
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function copyVendorTarget({ projectRoot, sourceRoot, sourceRelativePath, targetRelativePath, force }) {
|
|
571
|
+
const absoluteSourcePath = resolve(sourceRoot, sourceRelativePath);
|
|
572
|
+
if (!existsSync(absoluteSourcePath)) {
|
|
573
|
+
throw new Error(`Missing pack vendor source "${sourceRelativePath}" inside ${sourceRoot}.`);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const absoluteTargetPath = resolve(projectRoot, targetRelativePath);
|
|
577
|
+
const alreadyExists = existsSync(absoluteTargetPath);
|
|
578
|
+
if (alreadyExists && !force) {
|
|
579
|
+
return {
|
|
580
|
+
created: [],
|
|
581
|
+
overwritten: [],
|
|
582
|
+
skipped: [targetRelativePath],
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
ensureDirectory(resolve(absoluteTargetPath, '..'));
|
|
587
|
+
const sourceStats = statSync(absoluteSourcePath);
|
|
588
|
+
if (sourceStats.isDirectory()) {
|
|
589
|
+
cpSync(absoluteSourcePath, absoluteTargetPath, {
|
|
590
|
+
recursive: true,
|
|
591
|
+
force: true,
|
|
592
|
+
});
|
|
593
|
+
} else {
|
|
594
|
+
ensureDirectory(resolve(absoluteTargetPath, '..'));
|
|
595
|
+
cpSync(absoluteSourcePath, absoluteTargetPath, { force: true });
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return alreadyExists
|
|
599
|
+
? { created: [], overwritten: [targetRelativePath], skipped: [] }
|
|
600
|
+
: { created: [targetRelativePath], overwritten: [], skipped: [] };
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async function cmdVendor(parsed) {
|
|
604
|
+
const projectRoot = process.cwd();
|
|
605
|
+
assertAuraProjectRoot(projectRoot);
|
|
606
|
+
const selection = expandPackSelection(parsed.id);
|
|
607
|
+
if (!selection) {
|
|
608
|
+
throw new Error(`Unknown pack or bundle "${parsed.id}". Run "aura packs list" for available ids.`);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const manifest = readProjectPackManifest(projectRoot);
|
|
612
|
+
const vendoredPacks = [];
|
|
613
|
+
const created = [];
|
|
614
|
+
const overwritten = [];
|
|
615
|
+
const skipped = [];
|
|
616
|
+
const fetchedArchives = [];
|
|
617
|
+
|
|
618
|
+
for (const entry of selection.packs) {
|
|
619
|
+
const resolved = await resolveVendorPackRoot(entry, projectRoot, parsed.source, parsed.ref);
|
|
620
|
+
try {
|
|
621
|
+
const definition = readPackDefinition(resolved.rootPath);
|
|
622
|
+
const vendorTargets = normalizeVendorTargets(definition);
|
|
623
|
+
if (vendorTargets.length === 0) {
|
|
624
|
+
throw new Error(`Pack "${entry.id}" does not define any vendorTargets in ${PACK_DEFINITION_PATH}.`);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const vendoredPaths = [];
|
|
628
|
+
for (const target of vendorTargets) {
|
|
629
|
+
const result = copyVendorTarget({
|
|
630
|
+
projectRoot,
|
|
631
|
+
sourceRoot: resolved.rootPath,
|
|
632
|
+
sourceRelativePath: target.source,
|
|
633
|
+
targetRelativePath: target.target,
|
|
634
|
+
force: parsed.force,
|
|
635
|
+
});
|
|
636
|
+
created.push(...result.created);
|
|
637
|
+
overwritten.push(...result.overwritten);
|
|
638
|
+
skipped.push(...result.skipped);
|
|
639
|
+
if (result.created.length > 0 || result.overwritten.length > 0) {
|
|
640
|
+
vendoredPaths.push(target.target);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
vendoredPacks.push({
|
|
645
|
+
id: entry.id,
|
|
646
|
+
kind: entry.kind,
|
|
647
|
+
title: entry.title,
|
|
648
|
+
packageName: entry.packageName,
|
|
649
|
+
spec: null,
|
|
650
|
+
installMode: 'package',
|
|
651
|
+
sourceMode: resolved.sourceMode === 'installed' ? 'package' : resolved.sourceMode,
|
|
652
|
+
vendoredPaths,
|
|
653
|
+
});
|
|
654
|
+
if (resolved.archiveUrl) {
|
|
655
|
+
fetchedArchives.push({
|
|
656
|
+
id: entry.id,
|
|
657
|
+
archiveUrl: resolved.archiveUrl,
|
|
658
|
+
ref: resolved.ref,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
} finally {
|
|
662
|
+
resolved.cleanup();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const nextManifest = updateProjectPackManifest(
|
|
667
|
+
manifest.payload,
|
|
668
|
+
{
|
|
669
|
+
...selection,
|
|
670
|
+
requested: {
|
|
671
|
+
...selection.requested,
|
|
672
|
+
sourceMode: parsed.source === 'auto' ? vendoredPacks[0]?.sourceMode || 'workspace' : parsed.source,
|
|
673
|
+
},
|
|
674
|
+
},
|
|
675
|
+
vendoredPacks,
|
|
676
|
+
);
|
|
677
|
+
writeJsonFile(manifest.path, nextManifest);
|
|
678
|
+
|
|
679
|
+
const report = {
|
|
680
|
+
schema: 'aurajs.packs-vendor.v1',
|
|
681
|
+
ok: true,
|
|
682
|
+
reasonCode: overwritten.length > 0 ? 'project_packs_resynced' : 'project_packs_vendored',
|
|
683
|
+
requestedId: selection.requested.id,
|
|
684
|
+
requestedKind: selection.requested.kind,
|
|
685
|
+
source: parsed.source,
|
|
686
|
+
created,
|
|
687
|
+
overwritten,
|
|
688
|
+
skipped,
|
|
689
|
+
vendoredPacks: vendoredPacks.map((entry) => ({
|
|
690
|
+
id: entry.id,
|
|
691
|
+
sourceMode: entry.sourceMode,
|
|
692
|
+
vendoredPaths: [...entry.vendoredPaths],
|
|
693
|
+
})),
|
|
694
|
+
fetchedArchives,
|
|
695
|
+
manifestPath: PROJECT_PACKS_MANIFEST_PATH,
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
if (parsed.json) {
|
|
699
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
console.log('');
|
|
704
|
+
console.log(' Vendored optional pack payload');
|
|
705
|
+
console.log('');
|
|
706
|
+
console.log(` Requested: ${selection.requested.id}`);
|
|
707
|
+
console.log(` Source: ${parsed.source}`);
|
|
708
|
+
console.log(` Created: ${created.length}`);
|
|
709
|
+
console.log(` Overwritten: ${overwritten.length}`);
|
|
710
|
+
console.log(` Skipped: ${skipped.length}`);
|
|
711
|
+
console.log('');
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
export async function cmdPacks(args, { error } = {}) {
|
|
715
|
+
try {
|
|
716
|
+
const subcommand = args[0] || 'list';
|
|
717
|
+
const rest = args.slice(1);
|
|
718
|
+
|
|
719
|
+
if (subcommand === 'list') {
|
|
720
|
+
cmdList(parseListArgs(rest));
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
if (subcommand === 'show') {
|
|
724
|
+
cmdShow(parseShowArgs(rest));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (subcommand === 'add') {
|
|
728
|
+
cmdAdd(parsePackSourceArgs(rest, 'add'));
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (subcommand === 'vendor') {
|
|
732
|
+
await cmdVendor(parsePackSourceArgs(rest, 'vendor'));
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
raiseCliError(error, `Unsupported packs subcommand "${subcommand}". Usage: ${PACKS_USAGE}`);
|
|
737
|
+
} catch (err) {
|
|
738
|
+
handlePackCommandError(error, err);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|