@helix3/helix-cli 0.1.18-helix3.268 → 0.1.18-helix3.269
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/bridge-plugins/helix.bridge.unreal/bin/unreal-skeletal-mesh-extract.js +103 -5
- package/bridge-plugins/helix.bridge.unreal/test/handler.test.js +54 -0
- package/dist/bridge/execute.js +11 -2
- package/dist/bridge/execute.js.map +1 -1
- package/dist/bridge/types.d.ts +9 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_abs.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_expression.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_jbeam.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_materials.cpython-312.pyc +0 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const { spawn, spawnSync } = require('node:child_process');
|
|
5
5
|
const { createHash } = require('node:crypto');
|
|
6
6
|
const {
|
|
7
|
+
chmodSync,
|
|
7
8
|
closeSync,
|
|
8
9
|
existsSync,
|
|
9
10
|
lstatSync,
|
|
@@ -13,8 +14,9 @@ const {
|
|
|
13
14
|
readdirSync,
|
|
14
15
|
realpathSync,
|
|
15
16
|
statSync,
|
|
17
|
+
writeFileSync,
|
|
16
18
|
} = require('node:fs');
|
|
17
|
-
const { basename, extname, isAbsolute, join, relative, resolve, sep } = require('node:path');
|
|
19
|
+
const { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } = require('node:path');
|
|
18
20
|
|
|
19
21
|
const REQUEST_SCHEMA = 'helix.bridge-plugin-request/1';
|
|
20
22
|
const PROFILE_SCHEMA = 'helix.bridge.unreal-asset/1';
|
|
@@ -251,6 +253,60 @@ function findProject(sourcePath) {
|
|
|
251
253
|
return projects[0];
|
|
252
254
|
}
|
|
253
255
|
|
|
256
|
+
/**
|
|
257
|
+
* A "Game Features" category plugin marked `"ExplicitlyLoaded": true` in its
|
|
258
|
+
* .uplugin (HELIX's character-content plugins all are) is deliberately
|
|
259
|
+
* excluded from Unreal's built-in game-feature startup scan
|
|
260
|
+
* (`UGameFeaturesSubsystem::LoadBuiltInGameFeaturePlugins` filters
|
|
261
|
+
* `IPluginManager::GetEnabledPlugins()` down to `GetPluginsEnabledAtStartup()`,
|
|
262
|
+
* which explicit-load plugins are not part of). Its C++ modules still load
|
|
263
|
+
* from being listed in the .uproject's `Plugins` array, but its Content
|
|
264
|
+
* folder is never mounted as a package path root — so any package path under
|
|
265
|
+
* it (e.g. `/HelixCharacterCreator/...`) fails to resolve with Unreal's own
|
|
266
|
+
* "does not map to a root" error. Normal interactive/gameplay sessions
|
|
267
|
+
* activate it through a runtime Game Feature request that a bare
|
|
268
|
+
* `-ExecutePythonScript` extraction session never makes, and no amount of
|
|
269
|
+
* waiting resolves it (measured: 6 minutes of polling every 10s never
|
|
270
|
+
* mounted it).
|
|
271
|
+
*
|
|
272
|
+
* The extract capability only reads content — it has no use for Game
|
|
273
|
+
* Feature runtime state — so on this capability's own already-immutable
|
|
274
|
+
* project snapshot (never the caller's real source), flip
|
|
275
|
+
* `ExplicitlyLoaded` to `false` for every such plugin before invoking the
|
|
276
|
+
* editor. That makes Unreal mount its Content like any ordinary enabled
|
|
277
|
+
* plugin, deterministically, with no dependency on Game Feature activation
|
|
278
|
+
* or timing.
|
|
279
|
+
*/
|
|
280
|
+
function mountExplicitlyLoadedGameFeaturePlugins(uprojectPath) {
|
|
281
|
+
const pluginsDir = join(dirname(uprojectPath), 'Plugins');
|
|
282
|
+
if (!existsSync(pluginsDir)) return;
|
|
283
|
+
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
284
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
285
|
+
const pluginDir = join(pluginsDir, entry.name);
|
|
286
|
+
for (const file of readdirSync(pluginDir, { withFileTypes: true })) {
|
|
287
|
+
if (!file.isFile() || file.isSymbolicLink() || extname(file.name).toLowerCase() !== '.uplugin') continue;
|
|
288
|
+
const upluginPath = join(pluginDir, file.name);
|
|
289
|
+
let descriptor;
|
|
290
|
+
try {
|
|
291
|
+
descriptor = JSON.parse(readFileSync(upluginPath, 'utf8'));
|
|
292
|
+
} catch {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (descriptor.ExplicitlyLoaded !== true) continue;
|
|
296
|
+
descriptor.ExplicitlyLoaded = false;
|
|
297
|
+
try {
|
|
298
|
+
chmodSync(upluginPath, 0o644);
|
|
299
|
+
writeFileSync(upluginPath, `${JSON.stringify(descriptor, null, '\t')}\n`);
|
|
300
|
+
} catch (error) {
|
|
301
|
+
process.stderr.write(
|
|
302
|
+
`HELIX Unreal Bridge warning: could not mount explicitly-loaded plugin '${entry.name}' ` +
|
|
303
|
+
`for extraction (left as-is; its content will not resolve): ${error.message}\n`,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
254
310
|
function runningInWsl() {
|
|
255
311
|
if (process.platform !== 'linux') return false;
|
|
256
312
|
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) return true;
|
|
@@ -274,14 +330,15 @@ function wslPath(mode, path) {
|
|
|
274
330
|
return result.stdout.trim();
|
|
275
331
|
}
|
|
276
332
|
|
|
277
|
-
function editorInvocationPaths(editor, project, script, outputs) {
|
|
333
|
+
function editorInvocationPaths(editor, project, script, outputs, log) {
|
|
278
334
|
const wsl = runningInWsl();
|
|
279
|
-
if (!wsl) return { editor, project, script, outputs, wsl };
|
|
335
|
+
if (!wsl) return { editor, project, script, outputs, log, wsl };
|
|
280
336
|
return {
|
|
281
337
|
editor: WINDOWS_ABSOLUTE_PATH.test(editor) ? wslPath('-u', editor) : editor,
|
|
282
338
|
project: wslPath('-w', project),
|
|
283
339
|
script: wslPath('-w', script),
|
|
284
340
|
outputs: outputs.map((output) => wslPath('-w', output)),
|
|
341
|
+
log: wslPath('-w', log),
|
|
285
342
|
wsl,
|
|
286
343
|
};
|
|
287
344
|
}
|
|
@@ -359,6 +416,39 @@ async function runEditor(editor, args, environment, wsl) {
|
|
|
359
416
|
});
|
|
360
417
|
}
|
|
361
418
|
|
|
419
|
+
const ENGINE_LOG_TAIL_BYTES = 64 * 1024;
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Read the trailing bytes of the real Unreal Editor engine log (written via
|
|
423
|
+
* `-abslog`), not the captured stdout/stderr tail, which is capped at
|
|
424
|
+
* LOG_TAIL_BYTES and can lose the actual Python traceback under the noise UE
|
|
425
|
+
* prints on the way to a clean `-unattended` shutdown. Returns null when the
|
|
426
|
+
* log was never written (e.g. the editor failed to start at all).
|
|
427
|
+
*/
|
|
428
|
+
function readEngineLogTail(path, maxBytes) {
|
|
429
|
+
let info;
|
|
430
|
+
try {
|
|
431
|
+
info = statSync(path);
|
|
432
|
+
} catch {
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
if (!info.isFile()) return null;
|
|
436
|
+
const length = Math.min(maxBytes, info.size);
|
|
437
|
+
const start = info.size - length;
|
|
438
|
+
const buffer = Buffer.alloc(length);
|
|
439
|
+
let descriptor;
|
|
440
|
+
try {
|
|
441
|
+
descriptor = openSync(path, 'r');
|
|
442
|
+
readSync(descriptor, buffer, 0, length, start);
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return `(could not read '${path}': ${error.message})`;
|
|
445
|
+
} finally {
|
|
446
|
+
if (descriptor !== undefined) closeSync(descriptor);
|
|
447
|
+
}
|
|
448
|
+
const text = buffer.toString('utf8').trim();
|
|
449
|
+
return start > 0 ? `…(truncated, showing last ${length} of ${info.size} bytes)…\n${text}` : text;
|
|
450
|
+
}
|
|
451
|
+
|
|
362
452
|
function editorFailure(outcome) {
|
|
363
453
|
return `Unreal Editor failed${outcome.signal ? ` with signal ${outcome.signal}` : ` with exit ${outcome.code}`}` +
|
|
364
454
|
`${outcome.tail ? `: ${outcome.tail}` : ''}`;
|
|
@@ -575,6 +665,7 @@ async function main() {
|
|
|
575
665
|
const { sourcePath, outputDir, profilePath } = validateRequest(request);
|
|
576
666
|
const profiles = validateProfile(readJsonFile(profilePath, 'Unreal asset profile'));
|
|
577
667
|
const project = findProject(sourcePath);
|
|
668
|
+
mountExplicitlyLoadedGameFeaturePlugins(project);
|
|
578
669
|
const outputs = profiles.map((profile) => join(outputDir, `${profile.slug}.fbx`));
|
|
579
670
|
const script = resolve(__dirname, '..', 'unreal', 'export_skeletal_mesh.py');
|
|
580
671
|
if (!existsSync(script)) fail(`Packaged Unreal Python exporter is missing: ${script}`);
|
|
@@ -586,7 +677,8 @@ async function main() {
|
|
|
586
677
|
}
|
|
587
678
|
|
|
588
679
|
const editorValue = nonEmptyString(process.env.HELIX_UNREAL_EDITOR, 'HELIX_UNREAL_EDITOR');
|
|
589
|
-
const
|
|
680
|
+
const engineLogPath = join(outputDir, 'unreal-editor-full.log');
|
|
681
|
+
const paths = editorInvocationPaths(editorValue, project, script, outputs, engineLogPath);
|
|
590
682
|
const environment = {
|
|
591
683
|
...process.env,
|
|
592
684
|
HELIX_UNREAL_ASSET_PATH: profiles[0].assetPath,
|
|
@@ -609,12 +701,18 @@ async function main() {
|
|
|
609
701
|
'-nop4',
|
|
610
702
|
'-nosplash',
|
|
611
703
|
'-nosound',
|
|
704
|
+
'-log',
|
|
705
|
+
`-abslog=${paths.log}`,
|
|
612
706
|
], editorEnvironment(environment, paths.wsl), paths.wsl);
|
|
613
707
|
|
|
614
708
|
const invalidOutputs = outputs.map(validateFbxOutput).filter(Boolean);
|
|
615
709
|
if (invalidOutputs.length > 0) {
|
|
616
710
|
const suffix = editorOutcome.code === 0 && !editorOutcome.signal ? '' : `; ${editorFailure(editorOutcome)}`;
|
|
617
|
-
|
|
711
|
+
const engineLogTail = readEngineLogTail(engineLogPath, ENGINE_LOG_TAIL_BYTES);
|
|
712
|
+
const logSuffix = engineLogTail
|
|
713
|
+
? `\nUnreal Editor engine log (${engineLogPath}):\n${engineLogTail}`
|
|
714
|
+
: `\n(Unreal Editor engine log not found at ${engineLogPath})`;
|
|
715
|
+
fail(`Unreal Editor did not produce the complete reviewed export set (${invalidOutputs.join(', ')})${suffix}${logSuffix}`);
|
|
618
716
|
}
|
|
619
717
|
const materialSidecars = profiles.map((profile) => validateMaterialSidecar(
|
|
620
718
|
join(outputDir, `${profile.slug}.materials.json`),
|
|
@@ -70,6 +70,10 @@ function fixture(profileOverrides = {}) {
|
|
|
70
70
|
" else writeFileSync(sidecarPath, JSON.stringify(sidecar));",
|
|
71
71
|
"}",
|
|
72
72
|
"if (process.env.HELIX_TEST_EDITOR_LOG) process.stderr.write(process.env.HELIX_TEST_EDITOR_LOG);",
|
|
73
|
+
"if (process.env.HELIX_TEST_ABSLOG_CONTENT) {",
|
|
74
|
+
" const abslogArg = process.argv.slice(2).find((arg) => arg.startsWith('-abslog='));",
|
|
75
|
+
" if (abslogArg) writeFileSync(abslogArg.slice('-abslog='.length), process.env.HELIX_TEST_ABSLOG_CONTENT);",
|
|
76
|
+
"}",
|
|
73
77
|
"if (process.env.HELIX_TEST_EDITOR_SIGNAL) process.kill(process.pid, process.env.HELIX_TEST_EDITOR_SIGNAL);",
|
|
74
78
|
"if (process.env.HELIX_TEST_EDITOR_EXIT) process.exit(Number(process.env.HELIX_TEST_EDITOR_EXIT));",
|
|
75
79
|
].join('\n'));
|
|
@@ -121,12 +125,50 @@ test('exports one configured skeletal mesh with the full Unreal editor script',
|
|
|
121
125
|
assert.match(invocation.args[1], /^-ExecutePythonScript=.*export_skeletal_mesh\.py$/);
|
|
122
126
|
assert.ok(invocation.args.includes('-stdout'));
|
|
123
127
|
assert.ok(invocation.args.includes('-FullStdOutLogOutput'));
|
|
128
|
+
assert.ok(invocation.args.includes('-log'));
|
|
129
|
+
assert.ok(invocation.args.some((arg) => arg.startsWith('-abslog=')));
|
|
124
130
|
assert.match(readFileSync(join(entry.output, 'base-male.fbx'), 'binary'), /^Kaydara FBX Binary/);
|
|
125
131
|
const sidecar = JSON.parse(readFileSync(join(entry.output, 'base-male.materials.json'), 'utf8'));
|
|
126
132
|
assert.equal(sidecar.materials[0].parameters.scalars.Roughness, 0.5);
|
|
127
133
|
assert.deepEqual(sidecar.materials[0].parameters.vectors.Tint, { r: 1, g: 0.5, b: 0.25, a: 1 });
|
|
128
134
|
});
|
|
129
135
|
|
|
136
|
+
test('mounts an ExplicitlyLoaded Game Features plugin before extraction, and leaves other plugins alone', () => {
|
|
137
|
+
const entry = fixture();
|
|
138
|
+
const explicitPluginDir = join(entry.project, 'Plugins', 'HelixCharacterCreator');
|
|
139
|
+
mkdirSync(join(explicitPluginDir, 'Content'), { recursive: true });
|
|
140
|
+
const explicitPluginPath = join(explicitPluginDir, 'HelixCharacterCreator.uplugin');
|
|
141
|
+
writeFileSync(explicitPluginPath, JSON.stringify({
|
|
142
|
+
FileVersion: 3,
|
|
143
|
+
FriendlyName: 'HelixCharacterCreator',
|
|
144
|
+
Category: 'Game Features',
|
|
145
|
+
CanContainContent: true,
|
|
146
|
+
ExplicitlyLoaded: true,
|
|
147
|
+
BuiltInInitialFeatureState: 'Registered',
|
|
148
|
+
}));
|
|
149
|
+
chmodSync(explicitPluginPath, 0o444); // Perforce-style read-only, like the real content.
|
|
150
|
+
|
|
151
|
+
const implicitPluginDir = join(entry.project, 'Plugins', 'SomeOrdinaryPlugin');
|
|
152
|
+
mkdirSync(join(implicitPluginDir, 'Content'), { recursive: true });
|
|
153
|
+
const implicitPluginPath = join(implicitPluginDir, 'SomeOrdinaryPlugin.uplugin');
|
|
154
|
+
writeFileSync(implicitPluginPath, JSON.stringify({
|
|
155
|
+
FileVersion: 3,
|
|
156
|
+
FriendlyName: 'SomeOrdinaryPlugin',
|
|
157
|
+
CanContainContent: true,
|
|
158
|
+
ExplicitlyLoaded: false,
|
|
159
|
+
}));
|
|
160
|
+
|
|
161
|
+
const result = run(entry);
|
|
162
|
+
assert.equal(result.status, 0, result.stderr);
|
|
163
|
+
|
|
164
|
+
const patched = JSON.parse(readFileSync(explicitPluginPath, 'utf8'));
|
|
165
|
+
assert.equal(patched.ExplicitlyLoaded, false);
|
|
166
|
+
assert.equal(patched.Category, 'Game Features', 'only the loading gate changes, not the plugin identity');
|
|
167
|
+
|
|
168
|
+
const untouched = JSON.parse(readFileSync(implicitPluginPath, 'utf8'));
|
|
169
|
+
assert.equal(untouched.ExplicitlyLoaded, false);
|
|
170
|
+
});
|
|
171
|
+
|
|
130
172
|
test('accepts a structurally valid ASCII FBX export', () => {
|
|
131
173
|
const entry = fixture();
|
|
132
174
|
const result = run(entry, { HELIX_TEST_OUTPUT_KIND: 'ascii' });
|
|
@@ -173,6 +215,18 @@ test('rejects a corrupt file even when Unreal exits successfully', () => {
|
|
|
173
215
|
assert.match(result.stderr, /not a structurally valid FBX/);
|
|
174
216
|
});
|
|
175
217
|
|
|
218
|
+
test('surfaces the real engine log tail, not just the truncated stdout tail, when the export set is incomplete', () => {
|
|
219
|
+
const entry = fixture();
|
|
220
|
+
const result = run(entry, {
|
|
221
|
+
HELIX_TEST_OUTPUT_KIND: 'missing',
|
|
222
|
+
HELIX_TEST_ABSLOG_CONTENT: 'LogPython: Error: Unable to load Unreal asset — this is the real engine log, not stdout',
|
|
223
|
+
});
|
|
224
|
+
assert.equal(result.status, 1);
|
|
225
|
+
assert.match(result.stderr, /did not produce the complete reviewed export set/);
|
|
226
|
+
assert.match(result.stderr, /Unreal Editor engine log/);
|
|
227
|
+
assert.match(result.stderr, /Unable to load Unreal asset — this is the real engine log, not stdout/);
|
|
228
|
+
});
|
|
229
|
+
|
|
176
230
|
test('rejects missing and empty export files', async (t) => {
|
|
177
231
|
for (const outputKind of ['missing', 'empty']) {
|
|
178
232
|
await t.test(outputKind, () => {
|
package/dist/bridge/execute.js
CHANGED
|
@@ -89,10 +89,13 @@ async function importWithBridge(source, options = {}) {
|
|
|
89
89
|
let removeSignalCleanup = () => undefined;
|
|
90
90
|
let published = false;
|
|
91
91
|
let outputs = [];
|
|
92
|
+
const keepStage = options.keepStage === true || process.env.HELIX_BRIDGE_KEEP_STAGE === '1';
|
|
92
93
|
try {
|
|
93
94
|
reservation = await (0, outputReservation_1.acquireOutputReservation)(reservationPath, reservationRecord);
|
|
94
95
|
removeSignalCleanup = (0, outputReservation_1.installSignalCleanup)(reservationRecord, reservationPath, reservation, (signal) => (0, externalExecution_1.terminateActiveExternalProcesses)(`Bridge import interrupted by ${signal}`));
|
|
95
96
|
await (0, promises_1.mkdir)(transactionDir);
|
|
97
|
+
if (keepStage)
|
|
98
|
+
options.onProgress?.(`debug: bridge stage will be kept at ${transactionDir} if this import fails`);
|
|
96
99
|
const packageDir = (0, node_path_1.join)(transactionDir, 'package');
|
|
97
100
|
const workingDir = (0, node_path_1.join)(transactionDir, 'work');
|
|
98
101
|
await (0, promises_1.mkdir)(packageDir, { recursive: true });
|
|
@@ -187,8 +190,14 @@ async function importWithBridge(source, options = {}) {
|
|
|
187
190
|
}
|
|
188
191
|
finally {
|
|
189
192
|
removeSignalCleanup();
|
|
190
|
-
if (!published)
|
|
191
|
-
|
|
193
|
+
if (!published) {
|
|
194
|
+
if (keepStage) {
|
|
195
|
+
options.onProgress?.(`debug: bridge stage kept for inspection: ${transactionDir}`);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
await (0, promises_1.rm)(transactionDir, { recursive: true, force: true });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
192
201
|
if (reservation)
|
|
193
202
|
await reservation.close().catch(() => undefined);
|
|
194
203
|
await (0, outputReservation_1.removeOwnedReservation)(reservationPath, reservationRecord.reservationId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/bridge/execute.ts"],"names":[],"mappings":";;;AAwEA,
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/bridge/execute.ts"],"names":[],"mappings":"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"}
|
package/dist/bridge/types.d.ts
CHANGED
|
@@ -222,6 +222,15 @@ export interface BridgeImportOptions extends BridgePlanOptions {
|
|
|
222
222
|
expectedPlanKey?: string;
|
|
223
223
|
approvedPermissions?: BridgePermission[];
|
|
224
224
|
onProgress?: (message: string) => void;
|
|
225
|
+
/**
|
|
226
|
+
* Preserve the `.{output}.bridge-stage-<uuid>/` transaction directory (raw
|
|
227
|
+
* step outputs, snapshots, and any external-tool working files) after a
|
|
228
|
+
* failed import instead of deleting it. Also honored via the
|
|
229
|
+
* `HELIX_BRIDGE_KEEP_STAGE=1` environment variable. Debug-only: never set
|
|
230
|
+
* this for a normal import, since a kept stage is not cleaned up by Bridge
|
|
231
|
+
* and accumulates on disk across retries.
|
|
232
|
+
*/
|
|
233
|
+
keepStage?: boolean;
|
|
225
234
|
}
|
|
226
235
|
export interface BridgeImportResult {
|
|
227
236
|
plan: BridgePlan;
|
package/dist/index.js
CHANGED
|
@@ -262,6 +262,7 @@ bridge
|
|
|
262
262
|
.option('--expect-plan-key <sha256>', 'execute only if the freshly resolved plan has this exact key')
|
|
263
263
|
.option('--allow-permission <permissions...>', 'permissions approved for community/local plugins; repeat or comma-separate')
|
|
264
264
|
.option('--dry-run', 'plan only; write and execute nothing')
|
|
265
|
+
.option('--keep-stage', 'debug only: preserve the .bridge-stage-<uuid> transaction directory on failure instead of deleting it (also HELIX_BRIDGE_KEEP_STAGE=1)')
|
|
265
266
|
.option('--json', 'print the machine-readable result')
|
|
266
267
|
.action(async (source, opts) => {
|
|
267
268
|
try {
|
|
@@ -280,6 +281,7 @@ bridge
|
|
|
280
281
|
expectedPlanKey: opts.expectPlanKey,
|
|
281
282
|
approvedPermissions: bridgePermissions(opts.allowPermission),
|
|
282
283
|
dryRun: opts.dryRun,
|
|
284
|
+
keepStage: opts.keepStage,
|
|
283
285
|
onProgress: (message) => console.error(` ${message}`),
|
|
284
286
|
});
|
|
285
287
|
if (opts.json)
|