@tantawowa/hosanna-tools 2.22.0 → 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -52
- package/dist/build-info.json +3 -3
- package/dist/cli.js +437 -157
- package/dist/cli.js.map +1 -1
- package/dist/device/device-cli.d.ts +2 -2
- package/dist/device/device-cli.js +7 -6
- package/dist/device/device-cli.js.map +1 -1
- package/dist/device/devices-file.js +9 -1
- package/dist/device/devices-file.js.map +1 -1
- package/dist/device/drivers/roku-driver.js +1 -1
- package/dist/device/drivers/roku-driver.js.map +1 -1
- package/dist/device/log-stream.d.ts +2 -0
- package/dist/device/log-stream.js +24 -14
- package/dist/device/log-stream.js.map +1 -1
- package/dist/device/types.d.ts +4 -0
- package/dist/index.d.ts +51 -2
- package/dist/index.js +44 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/env-info.js +30 -24
- package/dist/lib/env-info.js.map +1 -1
- package/dist/lib/hosanna-config.d.ts +51 -0
- package/dist/lib/hosanna-config.js +323 -0
- package/dist/lib/hosanna-config.js.map +1 -0
- package/dist/run/android-emulator.d.ts +40 -0
- package/dist/run/android-emulator.js +590 -0
- package/dist/run/android-emulator.js.map +1 -0
- package/dist/run/apple-tv.d.ts +32 -0
- package/dist/run/apple-tv.js +367 -0
- package/dist/run/apple-tv.js.map +1 -0
- package/dist/run/ios-device.d.ts +17 -0
- package/dist/run/ios-device.js +229 -0
- package/dist/run/ios-device.js.map +1 -0
- package/dist/run/ios-simulator.d.ts +21 -0
- package/dist/run/ios-simulator.js +187 -0
- package/dist/run/ios-simulator.js.map +1 -0
- package/dist/run/process-utils.d.ts +2 -0
- package/dist/run/process-utils.js +31 -0
- package/dist/run/process-utils.js.map +1 -0
- package/dist/run/run-config.d.ts +20 -0
- package/dist/run/run-config.js +72 -0
- package/dist/run/run-config.js.map +1 -0
- package/dist/run/run-controller.d.ts +66 -0
- package/dist/run/run-controller.js +1017 -0
- package/dist/run/run-controller.js.map +1 -0
- package/dist/run/session-manager.d.ts +25 -0
- package/dist/run/session-manager.js +99 -0
- package/dist/run/session-manager.js.map +1 -0
- package/dist/run/targets.d.ts +60 -0
- package/dist/run/targets.js +210 -0
- package/dist/run/targets.js.map +1 -0
- package/dist/run/types.d.ts +60 -0
- package/dist/run/types.js +32 -0
- package/dist/run/types.js.map +1 -0
- package/dist/support-tools/framework-sync.d.ts +75 -0
- package/dist/support-tools/framework-sync.js +346 -0
- package/dist/support-tools/framework-sync.js.map +1 -0
- package/dist/support-tools/mcp-server/cli-test-recorder.js +1 -1
- package/dist/support-tools/mcp-server/cli-test-recorder.js.map +1 -1
- package/dist/support-tools/mcp-server/cli-test-runner.js +1 -1
- package/dist/support-tools/mcp-server/cli-test-runner.js.map +1 -1
- package/dist/support-tools/mcp-server/game-tools.js +1 -1
- package/dist/support-tools/mcp-server/game-tools.js.map +1 -1
- package/dist/support-tools/mcp-server/index.d.ts +1 -1
- package/dist/support-tools/mcp-server/instance-lock.js +1 -1
- package/dist/support-tools/mcp-server/tools.js +3 -3
- package/dist/support-tools/mcp-server/tools.js.map +1 -1
- package/dist/updater/compiler-installer.d.ts +17 -0
- package/dist/updater/compiler-installer.js +102 -0
- package/dist/updater/compiler-installer.js.map +1 -1
- package/dist/updater/framework-installer.d.ts +43 -0
- package/dist/updater/framework-installer.js +260 -0
- package/dist/updater/framework-installer.js.map +1 -0
- package/dist/updater/license-manager.d.ts +57 -0
- package/dist/updater/license-manager.js +265 -0
- package/dist/updater/license-manager.js.map +1 -0
- package/dist/updater/sdk-manager.d.ts +7 -1
- package/dist/updater/sdk-manager.js +15 -6
- package/dist/updater/sdk-manager.js.map +1 -1
- package/dist/updater/symlink-manager.js +25 -3
- package/dist/updater/symlink-manager.js.map +1 -1
- package/dist/updater/symlink-registry.d.ts +1 -0
- package/dist/updater/symlink-registry.js +6 -0
- package/dist/updater/symlink-registry.js.map +1 -1
- package/package.json +1 -1
- package/dist/lib/env-cloud-agent-setup-help.d.ts +0 -5
- package/dist/lib/env-cloud-agent-setup-help.js +0 -26
- package/dist/lib/env-cloud-agent-setup-help.js.map +0 -1
- package/dist/support-tools/cloud-agent-setup.d.ts +0 -41
- package/dist/support-tools/cloud-agent-setup.js +0 -132
- package/dist/support-tools/cloud-agent-setup.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -57,10 +57,9 @@ function parseGenerationMode(mode) {
|
|
|
57
57
|
const compiler_installer_js_1 = require("./updater/compiler-installer.js");
|
|
58
58
|
const generation_utils_js_2 = require("./generation/generation-utils.js");
|
|
59
59
|
const env_info_js_1 = require("./lib/env-info.js");
|
|
60
|
-
const cli_configure_hosanna_url_js_1 = require("./lib/cli.configure-hosanna-url.js");
|
|
61
60
|
const hosanna_tools_utils_js_1 = require("./lib/hosanna-tools-utils.js");
|
|
62
|
-
const env_cloud_agent_setup_help_js_1 = require("./lib/env-cloud-agent-setup-help.js");
|
|
63
61
|
const cli_app_config_resolve_js_1 = require("./lib/cli.app-config-resolve.js");
|
|
62
|
+
const hosanna_config_js_1 = require("./lib/hosanna-config.js");
|
|
64
63
|
// Read build date, version, and git hash embedded at build time
|
|
65
64
|
let buildDate = 'unknown';
|
|
66
65
|
let buildVersion = 'unknown';
|
|
@@ -87,18 +86,18 @@ catch (err) {
|
|
|
87
86
|
// Let yargs handle all commands including env
|
|
88
87
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
89
88
|
.version(`${buildVersion}\n git: ${buildGitHash}\n built: ${buildDate}`)
|
|
90
|
-
.usage('$0 [command] [options]', `Hosanna Tools CLI\nVersion: ${buildVersion}\nBuild Date: ${buildDate}\n\nCommand Groups:\n
|
|
89
|
+
.usage('$0 [command] [options]', `Hosanna Tools CLI\nVersion: ${buildVersion}\nBuild Date: ${buildDate}\n\nCommand Groups:\n compiler:* Compiler lifecycle (install, status, list)\n config hosanna.json management (wizard, show, set)\n env Environment checks and repair (check, fix, prepare-gitignore)\n dev:* Local development execution\n debugger:* Command debugger control\n mcp:* Hosanna MCP server control\n run Cross-platform launch orchestration\n target:* Run target discovery and inventory\n roku:* Roku deployment & packaging (run, package, map-stack)\n device:* Device discovery and run workflows\n generate:* Code and asset generation\n sdk:* Hosanna SDK/framework installation\n build-config:* Build/runtime configuration resolution\n ci:* Continuous integration helpers\n framework:* Framework distribution helpers\n license:* Hosanna framework licensing\n secrets:* Portable .secrets files\n test:* UI testing\n rasp:* RASP cert scripts`)
|
|
91
90
|
.option('verbose', {
|
|
92
91
|
type: 'boolean',
|
|
93
92
|
default: false,
|
|
94
93
|
describe: 'Enable verbose logging for all operations',
|
|
95
94
|
global: true
|
|
96
95
|
})
|
|
97
|
-
.command('game
|
|
96
|
+
.command('game:prep-level <input>', 'Normalize a Tiled JSON map into the Hs2d canonical runtime subset', yargs => yargs
|
|
98
97
|
.positional('input', { type: 'string', demandOption: true, describe: 'Path to a Tiled .json/.tmj map export' })
|
|
99
98
|
.option('out', { alias: 'o', type: 'string', describe: 'Output path (defaults to overwriting the input file)' })
|
|
100
99
|
.option('pretty', { type: 'boolean', default: false, describe: 'Pretty-print the output JSON (device payloads default to compact)' })
|
|
101
|
-
.example('$0 game
|
|
100
|
+
.example('$0 game:prep-level levels/level-1.json -o asset-bundles/my-game/levels/level-1.json', 'Decode/normalize a Tiled export into an asset bundle')
|
|
102
101
|
.epilog([
|
|
103
102
|
'Converts what Tiled produces into what the Hs2d device parser reads:',
|
|
104
103
|
' - decodes base64 (+zlib/gzip) tile data into plain arrays',
|
|
@@ -128,7 +127,7 @@ catch (err) {
|
|
|
128
127
|
process.exit(1);
|
|
129
128
|
}
|
|
130
129
|
})
|
|
131
|
-
.command('build-config
|
|
130
|
+
.command('build-config:resolve', 'Resolve Hosanna build config overlays into the canonical runtime build-config.json', yargs => yargs
|
|
132
131
|
.option('env', { type: 'string', describe: 'Environment, e.g. dev, qa, or prod (or HS_ENV / HOSANNA_BUILD_ENV)' })
|
|
133
132
|
.option('platform', { type: 'string', describe: 'Platform, e.g. web, roku, android, apple, or ios (or HS_PLATFORM / HOSANNA_BUILD_PLATFORM)' })
|
|
134
133
|
.option('profile', { type: 'string', describe: 'Optional explicit local developer profile (or HS_BUILD_PROFILE)' })
|
|
@@ -137,9 +136,9 @@ catch (err) {
|
|
|
137
136
|
.option('manifest-out', { type: 'string', describe: 'Write a sanitized source manifest to this file' })
|
|
138
137
|
.option('explain', { type: 'boolean', default: false, describe: 'Print source summary without secret values' })
|
|
139
138
|
.option('allow-profile-in-prod', { type: 'boolean', default: false, describe: 'Allow applying --profile with --env prod (or HS_ALLOW_PROFILE_IN_PROD=true)' })
|
|
140
|
-
.example('$0 build-config
|
|
141
|
-
.example('HS_ENV=dev HS_PLATFORM=roku $0 build-config
|
|
142
|
-
.example('$0 build-config
|
|
139
|
+
.example('$0 build-config:resolve --env dev --platform web --format json', 'Resolve dev web config to stdout')
|
|
140
|
+
.example('HS_ENV=dev HS_PLATFORM=roku $0 build-config:resolve --out assets/meta/build-config.json', 'Resolve config from env-prefixed shell arguments')
|
|
141
|
+
.example('$0 build-config:resolve --env prod --platform roku --out assets/meta/build-config.json', 'Resolve prod Roku config to a runtime file')
|
|
143
142
|
.epilog([
|
|
144
143
|
'Environment fallbacks:',
|
|
145
144
|
' --env: HS_ENV or HOSANNA_BUILD_ENV',
|
|
@@ -211,7 +210,7 @@ catch (err) {
|
|
|
211
210
|
process.exit(1);
|
|
212
211
|
}
|
|
213
212
|
})
|
|
214
|
-
.command(
|
|
213
|
+
.command('version', 'Print the version number', yargs => yargs, () => {
|
|
215
214
|
console.log(buildVersion);
|
|
216
215
|
console.log(` git: ${buildGitHash}`);
|
|
217
216
|
console.log(` built: ${buildDate}`);
|
|
@@ -317,50 +316,6 @@ catch (err) {
|
|
|
317
316
|
console.error(`❌ Failed to map Roku stack trace: ${msg}`);
|
|
318
317
|
process.exit(1);
|
|
319
318
|
}
|
|
320
|
-
})
|
|
321
|
-
.command('publish-roku', '[DEPRECATED] Use "roku:package" instead. Package and sign a Roku channel using roku-deploy. Flags fall back to env vars.', yargs => yargs
|
|
322
|
-
.option('ip', { type: 'string', describe: 'Roku device IP (env: ROKU_IP)' })
|
|
323
|
-
.option('installer-password', { type: 'string', describe: 'Dev Application Installer password (env: ROKU_DEVPASSWORD)' })
|
|
324
|
-
.option('dev-id', { type: 'string', describe: 'Signing Developer ID (env: ROKU_DEV_ID)' })
|
|
325
|
-
.option('signing-password', { type: 'string', describe: 'Signing password (env: ROKU_DEV_PASSWORD)' })
|
|
326
|
-
.option('key-pkg', { type: 'string', describe: 'Path or filename of the signed key package (.pkg) (env: ROKU_PKG_NAME)' })
|
|
327
|
-
.option('key-pkg-base64', { type: 'string', describe: 'Base64-encoded signed key package (.pkg) (env: ROKU_PKG_KEY_BASE64)' })
|
|
328
|
-
.option('env', { type: 'string', choices: ['prod', 'dev'], default: 'prod', describe: 'Used in output naming; does not modify project config' })
|
|
329
|
-
.option('rootDir', { type: 'string', describe: 'Roku project root (default: ./platforms/roku/src)' })
|
|
330
|
-
.option('outDir', { type: 'string', describe: 'Output directory (default: ./build)' })
|
|
331
|
-
.option('prebuild', { type: 'string', describe: 'Shell command to run before packaging (e.g. "npm run transpile:prod")' })
|
|
332
|
-
.option('quiet', { type: 'boolean', default: false, describe: 'Reduce output; print only errors and success' })
|
|
333
|
-
.example('$0 publish-roku --ip 192.168.1.10', '[DEPRECATED] Use "roku:package" instead'), async (args) => {
|
|
334
|
-
console.warn('⚠️ DEPRECATED: The command "publish-roku" is deprecated. Use "roku:package" instead.');
|
|
335
|
-
console.warn(' This command will be removed in a future version.');
|
|
336
|
-
if (args.verbose) {
|
|
337
|
-
process.env.HOSANNA_VERBOSE = '1';
|
|
338
|
-
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
339
|
-
}
|
|
340
|
-
try {
|
|
341
|
-
const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/publish-roku.js')));
|
|
342
|
-
const res = await mod.publishRoku({
|
|
343
|
-
ip: args.ip,
|
|
344
|
-
installerPassword: args['installer-password'],
|
|
345
|
-
devId: args['dev-id'],
|
|
346
|
-
signingPassword: args['signing-password'],
|
|
347
|
-
keyPkg: args['key-pkg'],
|
|
348
|
-
keyPkgBase64: args['key-pkg-base64'],
|
|
349
|
-
env: args.env,
|
|
350
|
-
rootDir: args.rootDir,
|
|
351
|
-
outDir: args.outDir,
|
|
352
|
-
prebuild: args.prebuild,
|
|
353
|
-
quiet: Boolean(args.quiet),
|
|
354
|
-
dotenv: true,
|
|
355
|
-
});
|
|
356
|
-
if (!args.quiet)
|
|
357
|
-
console.info(`✅ Success: ${res.outPath}`);
|
|
358
|
-
process.exit(0);
|
|
359
|
-
}
|
|
360
|
-
catch (err) {
|
|
361
|
-
console.error('❌ Failed to publish Roku package:', err);
|
|
362
|
-
process.exit(1);
|
|
363
|
-
}
|
|
364
319
|
})
|
|
365
320
|
.command('ci:extract-pkg-key <input-pkg>', 'Extract signing key from an existing signed Roku package as base64 for CI use', yargs => yargs
|
|
366
321
|
.positional('input-pkg', { type: 'string', describe: 'Path to existing signed Roku package (.pkg) file to extract key from' })
|
|
@@ -514,24 +469,46 @@ catch (err) {
|
|
|
514
469
|
}
|
|
515
470
|
})
|
|
516
471
|
// remove old --env flag; env is now a subcommand
|
|
517
|
-
.command('
|
|
518
|
-
.
|
|
472
|
+
.command('config [action]', 'Show or update hosanna.json configuration from a curated catalog', yargs => yargs
|
|
473
|
+
.positional('action', {
|
|
474
|
+
type: 'string',
|
|
475
|
+
choices: ['show', 'set', 'wizard'],
|
|
476
|
+
describe: 'show prints current config, set writes values from flags, wizard runs the interactive setup',
|
|
477
|
+
})
|
|
478
|
+
.option('git-url', { type: 'string', describe: 'Set hosanna.json git-url' })
|
|
479
|
+
.option('sdk-version', { type: 'string', describe: 'Set hosanna.json sdk-version' })
|
|
480
|
+
.option('branch', { type: 'string', describe: 'Set hosanna.json branch; use an empty string to prefer sdk-version' })
|
|
481
|
+
.option('transpiler-version', { type: 'string', describe: 'Set hosanna.json transpiler-version' })
|
|
482
|
+
.option('config-catalog-url', { type: 'string', describe: 'Persist a remote catalog URL into hosanna.json' })
|
|
483
|
+
.option('catalog-url', { type: 'string', describe: 'Use a remote catalog URL for this run without writing it' })
|
|
484
|
+
.option('fix', { type: 'boolean', default: false, describe: 'Run hst env fix after updating config' }), async (args) => {
|
|
519
485
|
if (args.verbose) {
|
|
520
486
|
process.env.HOSANNA_VERBOSE = '1';
|
|
521
487
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
522
488
|
}
|
|
523
|
-
const
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
if (args.
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
489
|
+
const actionArg = typeof args.action === 'string' ? args.action : undefined;
|
|
490
|
+
const action = actionArg === 'show' || actionArg === 'set' ? actionArg : 'wizard';
|
|
491
|
+
const updates = {};
|
|
492
|
+
if (typeof args.gitUrl === 'string')
|
|
493
|
+
updates['git-url'] = args.gitUrl;
|
|
494
|
+
if (typeof args.sdkVersion === 'string')
|
|
495
|
+
updates['sdk-version'] = args.sdkVersion;
|
|
496
|
+
if (typeof args.branch === 'string')
|
|
497
|
+
updates.branch = args.branch;
|
|
498
|
+
if (typeof args.transpilerVersion === 'string')
|
|
499
|
+
updates['transpiler-version'] = args.transpilerVersion;
|
|
500
|
+
if (typeof args.configCatalogUrl === 'string')
|
|
501
|
+
updates['config-catalog-url'] = args.configCatalogUrl;
|
|
502
|
+
try {
|
|
503
|
+
const result = await (0, hosanna_config_js_1.runHosannaConfig)({
|
|
504
|
+
action,
|
|
505
|
+
cwd: process.cwd(),
|
|
506
|
+
catalogUrl: typeof args.catalogUrl === 'string' ? args.catalogUrl : undefined,
|
|
507
|
+
updates,
|
|
508
|
+
writeStdout: text => console.info(text),
|
|
509
|
+
});
|
|
510
|
+
if ((args.fix || result.runFix) && action !== 'show') {
|
|
511
|
+
const { fixAllEnvironmentIssues } = await Promise.resolve().then(() => __importStar(require('./lib/env-info.js')));
|
|
535
512
|
const fixResult = await fixAllEnvironmentIssues(process.cwd());
|
|
536
513
|
console.info(`\n${fixResult.message}`);
|
|
537
514
|
if (fixResult.remainingIssues.length > 0) {
|
|
@@ -540,60 +517,77 @@ catch (err) {
|
|
|
540
517
|
console.info(` • ${issue}`);
|
|
541
518
|
}
|
|
542
519
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
// Fixes completed successfully - exit with 0 regardless of re-check
|
|
547
|
-
if (!process.env.VITEST) {
|
|
548
|
-
process.exit(0);
|
|
549
|
-
}
|
|
550
|
-
return; // Exit early since we handled the exit
|
|
551
|
-
}
|
|
552
|
-
// If there were remaining issues or fixes didn't complete successfully,
|
|
553
|
-
// re-check to see current state and exit accordingly
|
|
554
|
-
const updatedInfo = (0, env_info_js_1.collectEnvInfo)(process.cwd());
|
|
555
|
-
const updatedOk = (0, env_info_js_1.allEnvChecksPass)(updatedInfo);
|
|
556
|
-
if (!process.env.VITEST) {
|
|
557
|
-
process.exit(updatedOk ? 0 : 1);
|
|
558
|
-
}
|
|
559
|
-
return; // Exit early since we handled the exit
|
|
520
|
+
if (!process.env.VITEST)
|
|
521
|
+
process.exit(fixResult.success ? 0 : 1);
|
|
522
|
+
return;
|
|
560
523
|
}
|
|
524
|
+
if (!process.env.VITEST)
|
|
525
|
+
process.exit(0);
|
|
561
526
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
process.
|
|
527
|
+
catch (err) {
|
|
528
|
+
console.error('❌ Failed to configure hosanna.json:', err instanceof Error ? err.message : err);
|
|
529
|
+
if (!process.env.VITEST)
|
|
530
|
+
process.exit(1);
|
|
565
531
|
}
|
|
566
532
|
})
|
|
567
|
-
.command('env
|
|
568
|
-
.
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
.example('$0 env:cloud-agent-setup --start-debugger --start-app', 'Full bootstrap for a cloud agent')
|
|
574
|
-
.epilog(env_cloud_agent_setup_help_js_1.ENV_CLOUD_AGENT_SETUP_EPILOG), async (args) => {
|
|
533
|
+
.command('env <action>', 'Check or repair the local Hosanna environment', yargs => yargs
|
|
534
|
+
.positional('action', {
|
|
535
|
+
type: 'string',
|
|
536
|
+
choices: ['check', 'fix', 'prepare-gitignore'],
|
|
537
|
+
describe: 'check prints environment status, fix repairs version mismatches, prepare-gitignore updates .gitignore',
|
|
538
|
+
}), async (args) => {
|
|
575
539
|
if (args.verbose) {
|
|
576
540
|
process.env.HOSANNA_VERBOSE = '1';
|
|
577
541
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
578
542
|
}
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
startDebugger: Boolean(args['start-debugger']),
|
|
585
|
-
startApp: Boolean(args['start-app']),
|
|
586
|
-
vitePort: args['vite-port'],
|
|
587
|
-
format: args.format,
|
|
588
|
-
});
|
|
589
|
-
process.exit(0);
|
|
543
|
+
if (args.action === 'prepare-gitignore') {
|
|
544
|
+
console.info('Preparing .gitignore...');
|
|
545
|
+
(0, sdk_manager_js_1.prepareGitIgnore)();
|
|
546
|
+
console.info('.gitignore preparation completed.');
|
|
547
|
+
return;
|
|
590
548
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
549
|
+
const info = (0, env_info_js_1.collectEnvInfo)(process.cwd());
|
|
550
|
+
const report = (0, env_info_js_1.formatEnvReportWithChecks)(info);
|
|
551
|
+
console.info(report);
|
|
552
|
+
const ok = (0, env_info_js_1.allEnvChecksPass)(info);
|
|
553
|
+
if (args.action === 'check') {
|
|
554
|
+
if (!process.env.VITEST) {
|
|
555
|
+
process.exit(ok ? 0 : 1);
|
|
556
|
+
}
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (ok) {
|
|
560
|
+
console.info('\n✅ All environment checks passed - no fixes needed.');
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
const { fixAllEnvironmentIssues } = await Promise.resolve().then(() => __importStar(require('./lib/env-info.js')));
|
|
564
|
+
console.info('');
|
|
565
|
+
const fixResult = await fixAllEnvironmentIssues(process.cwd());
|
|
566
|
+
console.info(`\n${fixResult.message}`);
|
|
567
|
+
if (fixResult.remainingIssues.length > 0) {
|
|
568
|
+
console.info('\n❌ Remaining issues:');
|
|
569
|
+
for (const issue of fixResult.remainingIssues) {
|
|
570
|
+
console.info(` • ${issue}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (fixResult.success && fixResult.remainingIssues.length === 0) {
|
|
574
|
+
if (!process.env.VITEST) {
|
|
575
|
+
process.exit(0);
|
|
576
|
+
}
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
const updatedInfo = (0, env_info_js_1.collectEnvInfo)(process.cwd());
|
|
580
|
+
const updatedOk = (0, env_info_js_1.allEnvChecksPass)(updatedInfo);
|
|
581
|
+
if (!process.env.VITEST) {
|
|
582
|
+
process.exit(updatedOk ? 0 : 1);
|
|
583
|
+
}
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (!process.env.VITEST) {
|
|
587
|
+
process.exit(0);
|
|
594
588
|
}
|
|
595
589
|
})
|
|
596
|
-
.command('
|
|
590
|
+
.command('debugger:start', 'Start the command debugger WebSocket proxy', yargs => yargs
|
|
597
591
|
.option('webAppPort', { type: 'number', description: 'Port for web app client', default: 59151 })
|
|
598
592
|
.option('deviceAppPort', { type: 'number', description: 'Port for device app client', default: 59152 })
|
|
599
593
|
.option('extensionPort', { type: 'number', description: 'Port for extension client', default: 59153 })
|
|
@@ -611,14 +605,14 @@ catch (err) {
|
|
|
611
605
|
const { checkExistingDebugger } = await Promise.resolve().then(() => __importStar(require('./lib/debugger-probe.js')));
|
|
612
606
|
const { checkPortInUse } = await Promise.resolve().then(() => __importStar(require('./lib/port-utils.js')));
|
|
613
607
|
if (await checkExistingDebugger(managementPort)) {
|
|
614
|
-
console.log('[
|
|
615
|
-
console.log('[
|
|
608
|
+
console.log('[debugger:start] Command debugger is already running at http://localhost:' + managementPort);
|
|
609
|
+
console.log('[debugger:start] Your apps can connect via the management API (/assign-port). No need to start another debugger.');
|
|
616
610
|
process.exit(0);
|
|
617
611
|
}
|
|
618
612
|
// TCP fallback: if management port is in use (e.g. debugger still starting, HTTP not ready), assume debugger is running
|
|
619
613
|
if (await checkPortInUse(managementPort)) {
|
|
620
|
-
console.log('[
|
|
621
|
-
console.log('[
|
|
614
|
+
console.log('[debugger:start] Debugger port ' + managementPort + ' is in use — a debugger is already running.');
|
|
615
|
+
console.log('[debugger:start] Not starting a debugger server. Your apps can connect via the management API (/assign-port).');
|
|
622
616
|
process.exit(0);
|
|
623
617
|
}
|
|
624
618
|
// Check if any required ports are already in use (e.g. another process on our ports)
|
|
@@ -635,11 +629,11 @@ catch (err) {
|
|
|
635
629
|
}
|
|
636
630
|
}
|
|
637
631
|
if (portsInUse.length > 0) {
|
|
638
|
-
console.error('[
|
|
632
|
+
console.error('[debugger:start] ❌ Error: One or more ports are already in use:');
|
|
639
633
|
for (const { port, name } of portsInUse) {
|
|
640
|
-
console.error(`[
|
|
634
|
+
console.error(`[debugger:start] • Port ${port} (${name})`);
|
|
641
635
|
}
|
|
642
|
-
console.error('[
|
|
636
|
+
console.error('[debugger:start] Please free these ports or use different ports (e.g. --deviceAppPort 59156) and try again.');
|
|
643
637
|
process.exit(1);
|
|
644
638
|
}
|
|
645
639
|
const { startCommandDebugger } = await Promise.resolve().then(() => __importStar(require('./support-tools/command-debugger.js')));
|
|
@@ -651,8 +645,8 @@ catch (err) {
|
|
|
651
645
|
defaultAppName: typeof args.appName === 'string' && args.appName.trim() !== '' ? args.appName.trim() : undefined,
|
|
652
646
|
});
|
|
653
647
|
})
|
|
654
|
-
.command('install
|
|
655
|
-
.positional('
|
|
648
|
+
.command('compiler:install [compilerVersion]', 'Install or update the Hosanna compiler (hsc) locally. Downloads to /tmp cache and installs to ./bin/hsc. If [compilerVersion] is omitted, uses hosanna.json transpiler-version.', yargs => yargs
|
|
649
|
+
.positional('compilerVersion', { type: 'string', describe: 'hsc version (x.y.z). Overrides hosanna.json when provided.' })
|
|
656
650
|
.option('force', { type: 'boolean', default: false, describe: 'Force install even if version matches or compiler is npm-installed' })
|
|
657
651
|
.option('sudo', { type: 'boolean', default: false, describe: 'If needed, use sudo for file operations (legacy option, rarely needed)' }), async (args) => {
|
|
658
652
|
if (args.verbose) {
|
|
@@ -660,9 +654,9 @@ catch (err) {
|
|
|
660
654
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
661
655
|
}
|
|
662
656
|
let version;
|
|
663
|
-
const provided = args.
|
|
657
|
+
const provided = args.compilerVersion;
|
|
664
658
|
if (typeof provided === 'string') {
|
|
665
|
-
const trimmed = provided.trim();
|
|
659
|
+
const trimmed = provided.trim().replace(/^v(?=\d+\.\d+\.\d+)/, '');
|
|
666
660
|
version = trimmed.length > 0 ? trimmed : undefined;
|
|
667
661
|
}
|
|
668
662
|
try {
|
|
@@ -699,17 +693,51 @@ catch (err) {
|
|
|
699
693
|
process.exit(1);
|
|
700
694
|
}
|
|
701
695
|
})
|
|
702
|
-
.command('
|
|
696
|
+
.command('compiler:status', 'Print local Hosanna compiler status for this project', yargs => yargs.option('format', { type: 'string', choices: ['text', 'json'], default: 'text', describe: 'Output format' }), args => {
|
|
697
|
+
var _a;
|
|
698
|
+
const status = (0, compiler_installer_js_1.getCompilerStatus)(process.cwd());
|
|
699
|
+
if (args.format === 'json') {
|
|
700
|
+
console.log(JSON.stringify(status, null, 2));
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
console.info('Hosanna compiler status:');
|
|
704
|
+
console.info(` configured: ${(_a = status.configuredVersion) !== null && _a !== void 0 ? _a : '(not set)'}`);
|
|
705
|
+
console.info(` installed: ${status.installed ? status.installType : 'missing'}`);
|
|
706
|
+
if (status.installedVersion)
|
|
707
|
+
console.info(` version: ${status.installedVersion}`);
|
|
708
|
+
console.info(` path: ${status.installedPath}`);
|
|
709
|
+
console.info(` matches: ${status.matchesConfigured === undefined ? '(not applicable)' : status.matchesConfigured ? 'yes' : 'no'}`);
|
|
710
|
+
console.info(` cache: ${status.cacheDir}`);
|
|
711
|
+
console.info(` cached: ${status.cachedVersions.length ? status.cachedVersions.join(', ') : '(none)'}`);
|
|
712
|
+
}
|
|
713
|
+
process.exit(status.configuredVersion && status.matchesConfigured === false ? 1 : 0);
|
|
714
|
+
})
|
|
715
|
+
.command('compiler:list', 'List compiler versions known locally from hosanna.json, bin/hsc, and the local hsc cache', yargs => yargs.option('format', { type: 'string', choices: ['text', 'json'], default: 'text', describe: 'Output format' }), args => {
|
|
716
|
+
const entries = (0, compiler_installer_js_1.listCompilerVersions)(process.cwd());
|
|
717
|
+
if (args.format === 'json') {
|
|
718
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
719
|
+
}
|
|
720
|
+
else if (entries.length === 0) {
|
|
721
|
+
console.info('No local compiler versions found.');
|
|
722
|
+
}
|
|
723
|
+
else {
|
|
724
|
+
for (const entry of entries) {
|
|
725
|
+
console.info(`${entry.version} (${entry.sources.join(', ')})`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
process.exit(0);
|
|
729
|
+
})
|
|
730
|
+
.command('generate:all', 'Generate structs and command handler maps', yargs => yargs
|
|
703
731
|
.option('watch', { type: 'boolean', description: 'Watch for file changes' })
|
|
704
732
|
.option('rootFolder', { type: 'string', description: 'Root folder for the operation (defaults to ./src)' })
|
|
705
733
|
.option('generatedFolder', { type: 'string', description: 'Folder to output generated files (defaults to src-generated)' })
|
|
706
734
|
.option('quiet', { type: 'boolean', description: 'Reduce output; print only errors and success', default: false })
|
|
707
735
|
.option('mode', { type: 'string', choices: ['runtime', 'types', 'both'], default: 'runtime', description: 'Generate runtime .ts, types .d.ts+.map, or both' })
|
|
708
736
|
.option('fileFilter', { type: 'string', description: 'Regex pattern to filter filenames (applied to relative paths from rootFolder)' })
|
|
709
|
-
.example('$0 generate --rootFolder ./src', 'Generate structs and command handler maps for the specified root folder')
|
|
710
|
-
.example('$0 generate --watch', 'Generate structs and command handler maps and watch for file changes')
|
|
711
|
-
.example('$0 generate --generatedFolder ./gen', 'Generate structs and command handler maps in ./gen folder')
|
|
712
|
-
.example('$0 generate --fileFilter "Button"', 'Generate structs only for files containing "Button" in their path'), args => {
|
|
737
|
+
.example('$0 generate:all --rootFolder ./src', 'Generate structs and command handler maps for the specified root folder')
|
|
738
|
+
.example('$0 generate:all --watch', 'Generate structs and command handler maps and watch for file changes')
|
|
739
|
+
.example('$0 generate:all --generatedFolder ./gen', 'Generate structs and command handler maps in ./gen folder')
|
|
740
|
+
.example('$0 generate:all --fileFilter "Button"', 'Generate structs only for files containing "Button" in their path'), args => {
|
|
713
741
|
const rootFolder = args.rootFolder ? path.resolve(args.rootFolder) : path.resolve(process.cwd(), 'src');
|
|
714
742
|
const generatedFolder = args.generatedFolder ? path.resolve(args.generatedFolder) : path.resolve(process.cwd(), 'src-generated');
|
|
715
743
|
if (args.quiet) {
|
|
@@ -906,40 +934,154 @@ catch (err) {
|
|
|
906
934
|
process.exit(1);
|
|
907
935
|
}
|
|
908
936
|
})
|
|
909
|
-
.command('
|
|
937
|
+
.command('sdk:install', 'Install the SDK. Uses git (hosanna.json git-url) or license-gated keygen artifacts (hosanna.json "distribution": "keygen")', yargs => yargs
|
|
938
|
+
.option('force', { type: 'boolean', default: false, describe: 'Reinstall even if the requested version is already installed (keygen mode)' }), async (args) => {
|
|
910
939
|
if (args.verbose) {
|
|
911
940
|
process.env.HOSANNA_VERBOSE = '1';
|
|
912
941
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
913
942
|
}
|
|
914
|
-
console.info('
|
|
915
|
-
|
|
916
|
-
|
|
943
|
+
console.info('Running sdk:install command...');
|
|
944
|
+
try {
|
|
945
|
+
// Keygen-distributed projects bypass the git flow entirely.
|
|
946
|
+
const hosannaJsonPath = path.resolve(process.cwd(), 'hosanna.json');
|
|
947
|
+
let distribution;
|
|
948
|
+
if (fs.existsSync(hosannaJsonPath)) {
|
|
949
|
+
try {
|
|
950
|
+
distribution = JSON.parse(fs.readFileSync(hosannaJsonPath, 'utf-8')).distribution;
|
|
951
|
+
}
|
|
952
|
+
catch ( /* fall through to git flow which reports config errors */_a) { /* fall through to git flow which reports config errors */ }
|
|
953
|
+
}
|
|
954
|
+
if (distribution === 'keygen') {
|
|
955
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./updater/framework-installer.js')));
|
|
956
|
+
await mod.installFrameworkFromKeygen({ force: Boolean(args.force) });
|
|
957
|
+
}
|
|
958
|
+
else {
|
|
959
|
+
await (0, sdk_manager_js_1.installSdk)(); // Ensure installSdk is awaited
|
|
960
|
+
}
|
|
961
|
+
console.info('sdk:install command completed.');
|
|
962
|
+
process.exit(0); // Exit after successful completion
|
|
963
|
+
}
|
|
964
|
+
catch (err) {
|
|
965
|
+
console.error('An error occurred during the install process:', err);
|
|
966
|
+
process.exit(1); // Exit with error code on failure
|
|
967
|
+
}
|
|
917
968
|
})
|
|
918
|
-
.command('
|
|
969
|
+
.command('framework:update', 'Update the keygen-distributed hosanna-ui folder to the version in hosanna.json (no-op when already current)', yargs => yargs
|
|
970
|
+
.option('force', { type: 'boolean', default: false, describe: 'Reinstall even if the requested version is already installed' }), async (args) => {
|
|
919
971
|
if (args.verbose) {
|
|
920
972
|
process.env.HOSANNA_VERBOSE = '1';
|
|
921
973
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
922
974
|
}
|
|
923
|
-
console.info('Running install-sdk command...');
|
|
924
975
|
try {
|
|
925
|
-
await (
|
|
926
|
-
|
|
927
|
-
process.exit(0);
|
|
976
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./updater/framework-installer.js')));
|
|
977
|
+
await mod.installFrameworkFromKeygen({ force: Boolean(args.force) });
|
|
978
|
+
process.exit(0);
|
|
928
979
|
}
|
|
929
980
|
catch (err) {
|
|
930
|
-
console.error('
|
|
931
|
-
process.exit(1);
|
|
981
|
+
console.error('❌ framework:update failed:', err instanceof Error ? err.message : err);
|
|
982
|
+
process.exit(1);
|
|
983
|
+
}
|
|
984
|
+
})
|
|
985
|
+
.command('framework:sync', 'Maintainer: fast-forward tier-1 client forks (branches + tags) from upstream, driven by ~/.hosanna/sync-clients.json', yargs => yargs
|
|
986
|
+
.option('client', { type: 'string', describe: 'Sync a single named client from the registry (default: all clients)' })
|
|
987
|
+
.option('registry', { type: 'string', describe: 'Path to the sync registry (default: ~/.hosanna/sync-clients.json)' })
|
|
988
|
+
.option('dry-run', { type: 'boolean', default: false, describe: 'Show what would be pushed without pushing' })
|
|
989
|
+
.option('init', { type: 'boolean', default: false, describe: 'Create a template registry file and exit' })
|
|
990
|
+
.example('$0 framework:sync', 'Sync all registered client forks')
|
|
991
|
+
.example('$0 framework:sync --client ewtn --dry-run', 'Preview a sync for one client'), async (args) => {
|
|
992
|
+
try {
|
|
993
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/framework-sync.js')));
|
|
994
|
+
if (args.init) {
|
|
995
|
+
const filePath = mod.initRegistry(args.registry);
|
|
996
|
+
console.info(`✅ Created sync registry template: ${filePath}`);
|
|
997
|
+
console.info('Edit it to add your clients, then run: hst framework:sync');
|
|
998
|
+
process.exit(0);
|
|
999
|
+
}
|
|
1000
|
+
const results = await mod.syncFrameworkForks({
|
|
1001
|
+
registryPath: args.registry,
|
|
1002
|
+
client: args.client,
|
|
1003
|
+
dryRun: Boolean(args['dry-run']),
|
|
1004
|
+
});
|
|
1005
|
+
const ok = mod.printSyncSummary(results, Boolean(args['dry-run']));
|
|
1006
|
+
process.exit(ok ? 0 : 1);
|
|
1007
|
+
}
|
|
1008
|
+
catch (err) {
|
|
1009
|
+
console.error('❌ framework:sync failed:', err instanceof Error ? err.message : err);
|
|
1010
|
+
process.exit(1);
|
|
1011
|
+
}
|
|
1012
|
+
})
|
|
1013
|
+
.command('framework:doctor', 'Maintainer: validate tier-1 client forks (reachability, hosanna.json git-url/schema, sdk-version tags)', yargs => yargs
|
|
1014
|
+
.option('client', { type: 'string', describe: 'Check a single named client from the registry (default: all clients)' })
|
|
1015
|
+
.option('registry', { type: 'string', describe: 'Path to the sync registry (default: ~/.hosanna/sync-clients.json)' })
|
|
1016
|
+
.example('$0 framework:doctor', 'Validate all registered client forks'), async (args) => {
|
|
1017
|
+
try {
|
|
1018
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/framework-sync.js')));
|
|
1019
|
+
const issues = await mod.doctorFrameworkForks({
|
|
1020
|
+
registryPath: args.registry,
|
|
1021
|
+
client: args.client,
|
|
1022
|
+
});
|
|
1023
|
+
const ok = mod.printDoctorSummary(issues);
|
|
1024
|
+
process.exit(ok ? 0 : 1);
|
|
1025
|
+
}
|
|
1026
|
+
catch (err) {
|
|
1027
|
+
console.error('❌ framework:doctor failed:', err instanceof Error ? err.message : err);
|
|
1028
|
+
process.exit(1);
|
|
932
1029
|
}
|
|
933
1030
|
})
|
|
934
|
-
.command('
|
|
1031
|
+
.command('license:activate <key>', 'Store your Hosanna framework license key (~/.hosanna/license.key) after validating it', yargs => yargs
|
|
1032
|
+
.positional('key', { type: 'string', demandOption: true, describe: 'License key issued for your organization' }), async (args) => {
|
|
1033
|
+
try {
|
|
1034
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./updater/license-manager.js')));
|
|
1035
|
+
const key = String(args.key).trim();
|
|
1036
|
+
const validation = await mod.validateLicense(key);
|
|
1037
|
+
if (!validation.valid) {
|
|
1038
|
+
console.error(`❌ License is not valid: ${validation.code} ${validation.detail}`.trim());
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
}
|
|
1041
|
+
const filePath = mod.storeLicenseKey(key);
|
|
1042
|
+
console.info(`✅ License validated and stored at ${filePath}`);
|
|
1043
|
+
if (validation.expiry)
|
|
1044
|
+
console.info(` Expires: ${validation.expiry}`);
|
|
1045
|
+
process.exit(0);
|
|
1046
|
+
}
|
|
1047
|
+
catch (err) {
|
|
1048
|
+
console.error('❌ license:activate failed:', err instanceof Error ? err.message : err);
|
|
1049
|
+
process.exit(1);
|
|
1050
|
+
}
|
|
1051
|
+
})
|
|
1052
|
+
.command('license:status', 'Validate the stored license and print its entitlements (flavour, platforms, tier)', yargs => yargs, async () => {
|
|
1053
|
+
try {
|
|
1054
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./updater/license-manager.js')));
|
|
1055
|
+
const key = mod.requireLicenseKey();
|
|
1056
|
+
const info = await mod.getLicenseInfo(key);
|
|
1057
|
+
if (!info.validation.valid) {
|
|
1058
|
+
console.error(`❌ License is not valid: ${info.validation.code} ${info.validation.detail}`.trim());
|
|
1059
|
+
process.exit(1);
|
|
1060
|
+
}
|
|
1061
|
+
console.info('✅ License is valid');
|
|
1062
|
+
if (info.validation.expiry)
|
|
1063
|
+
console.info(` Expires: ${info.validation.expiry}`);
|
|
1064
|
+
const flavours = mod.entitledFlavours(info.entitlements);
|
|
1065
|
+
const platforms = mod.entitledPlatforms(info.entitlements);
|
|
1066
|
+
console.info(` Flavour: ${flavours.length ? flavours[flavours.length - 1] : '(none)'}`);
|
|
1067
|
+
console.info(` Platforms: ${platforms.length ? platforms.join(', ') : '(none)'}`);
|
|
1068
|
+
console.info(` Entitlements: ${info.entitlements.join(', ') || '(none)'}`);
|
|
1069
|
+
process.exit(0);
|
|
1070
|
+
}
|
|
1071
|
+
catch (err) {
|
|
1072
|
+
console.error('❌ license:status failed:', err instanceof Error ? err.message : err);
|
|
1073
|
+
process.exit(1);
|
|
1074
|
+
}
|
|
1075
|
+
})
|
|
1076
|
+
.command('template:create', 'Create a new template app with the Hosanna SDK', yargs => yargs, async (args) => {
|
|
935
1077
|
if (args.verbose) {
|
|
936
1078
|
process.env.HOSANNA_VERBOSE = '1';
|
|
937
1079
|
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
938
1080
|
}
|
|
939
|
-
console.info('Running
|
|
1081
|
+
console.info('Running template:create command...');
|
|
940
1082
|
try {
|
|
941
1083
|
await (0, sdk_manager_js_1.createTemplateApp)();
|
|
942
|
-
console.info('
|
|
1084
|
+
console.info('template:create command completed.');
|
|
943
1085
|
process.exit(0);
|
|
944
1086
|
}
|
|
945
1087
|
catch (err) {
|
|
@@ -976,7 +1118,7 @@ catch (err) {
|
|
|
976
1118
|
process.exit(1);
|
|
977
1119
|
}
|
|
978
1120
|
})
|
|
979
|
-
.command('device:list', 'List devices discovered by hst, merged with .
|
|
1121
|
+
.command('device:list', 'List devices discovered by hst, merged with .hosanna-tools/devices.json preferences', yargs => yargs
|
|
980
1122
|
.option('type', {
|
|
981
1123
|
type: 'string',
|
|
982
1124
|
choices: ['roku', 'ios', 'apple-tv', 'android', 'android-tv'],
|
|
@@ -1005,8 +1147,154 @@ catch (err) {
|
|
|
1005
1147
|
console.error(err instanceof Error ? err.message : String(err));
|
|
1006
1148
|
process.exit(1);
|
|
1007
1149
|
}
|
|
1150
|
+
})
|
|
1151
|
+
.command('target:list', 'List run targets discovered by hst, including web previews, simulators, and physical devices', yargs => yargs
|
|
1152
|
+
.option('platform', {
|
|
1153
|
+
type: 'string',
|
|
1154
|
+
choices: ['web', 'roku', 'ios', 'apple-tv', 'android', 'android-tv'],
|
|
1155
|
+
describe: 'Filter by launch platform',
|
|
1156
|
+
})
|
|
1157
|
+
.option('target', {
|
|
1158
|
+
type: 'string',
|
|
1159
|
+
choices: ['web', 'device', 'simulator', 'emulator', 'simulated', 'emulated'],
|
|
1160
|
+
describe: 'Filter by target kind',
|
|
1161
|
+
})
|
|
1162
|
+
.option('form-factor', {
|
|
1163
|
+
type: 'string',
|
|
1164
|
+
choices: ['desktop', 'mobile', 'tablet', 'tv'],
|
|
1165
|
+
describe: 'Filter by form factor for broad agent inventory queries',
|
|
1166
|
+
})
|
|
1167
|
+
.option('json', {
|
|
1168
|
+
type: 'boolean',
|
|
1169
|
+
default: false,
|
|
1170
|
+
describe: 'Print machine-readable JSON',
|
|
1171
|
+
})
|
|
1172
|
+
.example('$0 target:list --platform roku', 'List Roku web/device targets')
|
|
1173
|
+
.example('$0 target:list --platform ios --target simulator --json', 'List iOS simulator targets as JSON')
|
|
1174
|
+
.example('$0 target:list --platform ios --target device --json', 'List physical iOS device targets as JSON')
|
|
1175
|
+
.example('$0 target:list --platform android --target emulator --json', 'List Android phone emulator targets as JSON')
|
|
1176
|
+
.example('$0 target:list --platform android --target device --json', 'List physical Android device targets as JSON')
|
|
1177
|
+
.example('$0 target:list --platform android-tv --target emulator --json', 'List Android TV emulator targets as JSON')
|
|
1178
|
+
.example('$0 target:list --platform apple-tv --target simulator --json', 'List Apple TV simulator targets as JSON')
|
|
1179
|
+
.example('$0 target:list --form-factor tv --json', 'List TV-class targets as JSON'), async (args) => {
|
|
1180
|
+
try {
|
|
1181
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./run/targets.js')));
|
|
1182
|
+
const filters = mod.parseRunTargetFilters({
|
|
1183
|
+
platform: args.platform,
|
|
1184
|
+
target: args.target,
|
|
1185
|
+
formFactor: args['form-factor'],
|
|
1186
|
+
});
|
|
1187
|
+
const targets = await mod.collectRunTargets(Object.assign(Object.assign({ cwd: process.cwd() }, filters), { env: process.env }));
|
|
1188
|
+
if (args.json) {
|
|
1189
|
+
console.info(JSON.stringify(mod.formatRunTargetsJson(targets), null, 2));
|
|
1190
|
+
}
|
|
1191
|
+
else {
|
|
1192
|
+
console.info(mod.formatRunTargetsText(targets));
|
|
1193
|
+
}
|
|
1194
|
+
process.exit(0);
|
|
1195
|
+
}
|
|
1196
|
+
catch (err) {
|
|
1197
|
+
console.error('❌ target:list failed');
|
|
1198
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1199
|
+
process.exit(1);
|
|
1200
|
+
}
|
|
1201
|
+
})
|
|
1202
|
+
.command('run', 'Launch a Hosanna app on a platform target (web, Roku, iOS, Apple TV, Android, and Android TV targets are supported)', yargs => yargs
|
|
1203
|
+
.parserConfiguration({ 'boolean-negation': false })
|
|
1204
|
+
.option('platform', {
|
|
1205
|
+
type: 'string',
|
|
1206
|
+
choices: ['web', 'roku', 'ios', 'apple-tv', 'android', 'android-tv'],
|
|
1207
|
+
demandOption: true,
|
|
1208
|
+
describe: 'Launch platform. Required to keep agent runs deterministic.',
|
|
1209
|
+
})
|
|
1210
|
+
.option('target', {
|
|
1211
|
+
type: 'string',
|
|
1212
|
+
choices: ['web', 'device', 'simulator', 'emulator', 'simulated', 'emulated'],
|
|
1213
|
+
describe: 'Target kind. Defaults to web for web/roku.',
|
|
1214
|
+
})
|
|
1215
|
+
.option('device', {
|
|
1216
|
+
type: 'string',
|
|
1217
|
+
describe: 'Device IP, serial/UDID, or case-insensitive name substring for device/simulator runs',
|
|
1218
|
+
})
|
|
1219
|
+
.option('appName', {
|
|
1220
|
+
type: 'string',
|
|
1221
|
+
describe: 'App name used for debugger/session identity',
|
|
1222
|
+
})
|
|
1223
|
+
.option('vitePort', { type: 'number', description: 'Port for Vite dev server', default: 5173 })
|
|
1224
|
+
.option('webAppPort', { type: 'number', description: 'Port for web app debugger client', default: 59151 })
|
|
1225
|
+
.option('deviceAppPort', { type: 'number', description: 'Port for device app debugger client', default: 59152 })
|
|
1226
|
+
.option('extensionPort', { type: 'number', description: 'Debugger extension WebSocket port', default: 59153 })
|
|
1227
|
+
.option('managementPort', { type: 'number', description: 'Debugger management HTTP port', default: 59150 })
|
|
1228
|
+
.option('reuse', { type: 'boolean', default: false, describe: 'Explicitly allow reuse of a matching hst session' })
|
|
1229
|
+
.option('replace', { type: 'boolean', default: false, describe: 'Replace conflicting web/device sessions or occupied device log resources' })
|
|
1230
|
+
.option('non-interactive', { type: 'boolean', default: false, describe: 'Fail instead of prompting when a decision is needed' })
|
|
1231
|
+
.option('json', { type: 'boolean', default: false, describe: 'Print run result as JSON when the command returns' })
|
|
1232
|
+
.option('no-build', { type: 'boolean', default: false, describe: 'Skip the platform build step for device runs' })
|
|
1233
|
+
.option('no-logs', { type: 'boolean', default: false, describe: 'Do not stream device logs after launch where supported' })
|
|
1234
|
+
.option('build-cmd', { type: 'string', describe: 'Override the platform build command for device runs' })
|
|
1235
|
+
.option('app-package', { type: 'string', describe: 'Roku app .zip or folder to deploy for device runs' })
|
|
1236
|
+
.option('source-root', { type: 'string', describe: 'Roku source root to deploy for device runs' })
|
|
1237
|
+
.option('source-map-root', { type: 'string', describe: 'Roku source map root for log resolution' })
|
|
1238
|
+
.option('files', { type: 'array', describe: 'Roku file globs when deploying a folder' })
|
|
1239
|
+
.option('installer-password', { type: 'string', describe: 'Roku installer password (env: ROKU_DEVPASSWORD)' })
|
|
1240
|
+
.option('logs', { type: 'boolean', default: false, describe: 'Enable verbose deploy logging where supported' })
|
|
1241
|
+
.option('applySourceMapToPaths', { type: 'boolean', default: true, describe: 'Resolve Roku stack trace paths with source maps during log streaming' })
|
|
1242
|
+
.example('$0 run --platform web', 'Start/reuse web dev services for this app')
|
|
1243
|
+
.example('$0 run --platform roku --target web', 'Start/reuse the Roku TV web preview')
|
|
1244
|
+
.example('$0 run --platform ios --target simulator --device "iPhone 17 Pro"', 'Build, install, and launch on an iOS simulator')
|
|
1245
|
+
.example('$0 run --platform ios --target device --device "George iPhone" --no-logs', 'Build, install, and launch on a physical iPhone')
|
|
1246
|
+
.example('$0 run --platform android --target emulator --device "Pixel_8" --no-logs', 'Build, install, and launch on an Android phone emulator')
|
|
1247
|
+
.example('$0 run --platform android --target device --device "RF8M62694QT" --no-logs', 'Build, install, and launch on a physical Android device')
|
|
1248
|
+
.example('$0 run --platform android-tv --target emulator --device "Television_1080p" --no-logs', 'Build, install, and launch on an Android TV emulator')
|
|
1249
|
+
.example('$0 run --platform apple-tv --target simulator --device "Apple TV 4K"', 'Build, install, and launch on an Apple TV simulator')
|
|
1250
|
+
.example('$0 run --platform roku --target device --device "living room"', 'Build, deploy, launch, and stream logs on a Roku device'), async (args) => {
|
|
1251
|
+
var _a, _b, _c;
|
|
1252
|
+
try {
|
|
1253
|
+
const mod = await Promise.resolve().then(() => __importStar(require('./run/run-controller.js')));
|
|
1254
|
+
const result = await mod.runHosanna({
|
|
1255
|
+
cwd: process.cwd(),
|
|
1256
|
+
platform: args.platform,
|
|
1257
|
+
target: args.target,
|
|
1258
|
+
device: args.device,
|
|
1259
|
+
appName: args.appName,
|
|
1260
|
+
vitePort: args.vitePort,
|
|
1261
|
+
webAppPort: args.webAppPort,
|
|
1262
|
+
deviceAppPort: args.deviceAppPort,
|
|
1263
|
+
extensionPort: args.extensionPort,
|
|
1264
|
+
managementPort: args.managementPort,
|
|
1265
|
+
reuse: Boolean(args.reuse),
|
|
1266
|
+
replace: Boolean(args.replace),
|
|
1267
|
+
nonInteractive: Boolean(args['non-interactive']),
|
|
1268
|
+
noBuild: Boolean(args['no-build']),
|
|
1269
|
+
noLogs: Boolean(args['no-logs']),
|
|
1270
|
+
buildCmd: args['build-cmd'],
|
|
1271
|
+
appPackage: args['app-package'],
|
|
1272
|
+
sourceRoot: args['source-root'],
|
|
1273
|
+
sourceMapRoot: args['source-map-root'],
|
|
1274
|
+
files: args.files,
|
|
1275
|
+
installerPassword: args['installer-password'],
|
|
1276
|
+
logs: Boolean(args.logs),
|
|
1277
|
+
applySourceMapToPaths: Boolean(args.applySourceMapToPaths),
|
|
1278
|
+
env: process.env,
|
|
1279
|
+
});
|
|
1280
|
+
if (args.json) {
|
|
1281
|
+
console.info(JSON.stringify(result, null, 2));
|
|
1282
|
+
}
|
|
1283
|
+
else if (result.status === 'reused') {
|
|
1284
|
+
console.info(`hst run: reusing ${(_a = result.appName) !== null && _a !== void 0 ? _a : 'app'} at ${(_b = result.url) !== null && _b !== void 0 ? _b : '(unknown URL)'}`);
|
|
1285
|
+
}
|
|
1286
|
+
else if (result.url) {
|
|
1287
|
+
console.info(`hst run: ${(_c = result.appName) !== null && _c !== void 0 ? _c : 'app'} available at ${result.url}`);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
catch (err) {
|
|
1291
|
+
console.error('❌ run failed');
|
|
1292
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1293
|
+
process.exit(1);
|
|
1294
|
+
}
|
|
1008
1295
|
})
|
|
1009
1296
|
.command('device:run', 'Build, deploy, launch, and stream logs for a device', yargs => yargs
|
|
1297
|
+
.parserConfiguration({ 'boolean-negation': false })
|
|
1010
1298
|
.option('type', {
|
|
1011
1299
|
type: 'string',
|
|
1012
1300
|
choices: ['roku', 'ios', 'apple-tv', 'android', 'android-tv'],
|
|
@@ -1165,12 +1453,12 @@ catch (err) {
|
|
|
1165
1453
|
process.exit(1);
|
|
1166
1454
|
}
|
|
1167
1455
|
})
|
|
1168
|
-
.command('
|
|
1456
|
+
.command('mcp:start', 'Start the Hosanna MCP server for AI agent debugging', yargs => yargs
|
|
1169
1457
|
.option('managementPort', { type: 'number', description: 'Management server port', default: 59150 })
|
|
1170
1458
|
.option('managementHost', { type: 'string', description: 'Management server host', default: 'localhost' })
|
|
1171
1459
|
.option('extensionPort', {
|
|
1172
1460
|
type: 'number',
|
|
1173
|
-
description: 'Debugger extension WebSocket port (must match hst
|
|
1461
|
+
description: 'Debugger extension WebSocket port (must match hst debugger:start)',
|
|
1174
1462
|
default: 59153,
|
|
1175
1463
|
}), async (args) => {
|
|
1176
1464
|
if (args.verbose) {
|
|
@@ -1184,12 +1472,12 @@ catch (err) {
|
|
|
1184
1472
|
extensionPort: args.extensionPort,
|
|
1185
1473
|
});
|
|
1186
1474
|
})
|
|
1187
|
-
.command(
|
|
1475
|
+
.command('mcp:stop', 'Stop the Hosanna MCP server (reads PID from the same lock file as mcp:start).', yargs => {
|
|
1188
1476
|
var _a;
|
|
1189
1477
|
return yargs
|
|
1190
1478
|
.option('managementPort', {
|
|
1191
1479
|
type: 'number',
|
|
1192
|
-
description: 'Must match the running instance (same as
|
|
1480
|
+
description: 'Must match the running instance (same as mcp:start)',
|
|
1193
1481
|
default: parseInt((_a = process.env.HOSANNA_MANAGEMENT_PORT) !== null && _a !== void 0 ? _a : '59150', 10),
|
|
1194
1482
|
})
|
|
1195
1483
|
.option('force', {
|
|
@@ -1225,7 +1513,7 @@ catch (err) {
|
|
|
1225
1513
|
process.exit(1);
|
|
1226
1514
|
}
|
|
1227
1515
|
})
|
|
1228
|
-
.command('
|
|
1516
|
+
.command('dev:start', 'Run dev processes: vite, generator watch, and optional debugger', yargs => yargs
|
|
1229
1517
|
.option('vitePort', { type: 'number', description: 'Port for Vite dev server', default: 5173 })
|
|
1230
1518
|
.option('webAppPort', { type: 'number', description: 'Port for web app client', default: 59151 })
|
|
1231
1519
|
.option('deviceAppPort', { type: 'number', description: 'Port for device app client', default: 59152 })
|
|
@@ -1245,17 +1533,9 @@ catch (err) {
|
|
|
1245
1533
|
defaultClientType: args.defaultClientType || 'web',
|
|
1246
1534
|
appName: args.appName,
|
|
1247
1535
|
});
|
|
1248
|
-
})
|
|
1249
|
-
.command('ci:configure-hosanna-url [gitUrl]', 'Configure hosanna.json git-url from an argument or HOSANNA_UI_GIT_URL', yargs => yargs
|
|
1250
|
-
.positional('gitUrl', { type: 'string', describe: 'Git URL to set in hosanna.json (defaults to env HOSANNA_UI_GIT_URL)' }), args => {
|
|
1251
|
-
if (args.verbose) {
|
|
1252
|
-
process.env.HOSANNA_VERBOSE = '1';
|
|
1253
|
-
process.env.HOSANNA_UPDATER_VERBOSE = '1';
|
|
1254
|
-
}
|
|
1255
|
-
(0, cli_configure_hosanna_url_js_1.runConfigureHosannaUrl)(typeof args.gitUrl === 'string' ? args.gitUrl : undefined);
|
|
1256
1536
|
})
|
|
1257
1537
|
.command('test:ui [recordings..]', 'Replay UI test recordings against a running Hosanna app and exit with pass/fail. ' +
|
|
1258
|
-
'Requires a running debug proxy (hst
|
|
1538
|
+
'Requires a running debug proxy (hst debugger:start) and a connected app.', yargs => yargs
|
|
1259
1539
|
.positional('recordings', {
|
|
1260
1540
|
describe: 'Recording IDs to replay (omit to run all)',
|
|
1261
1541
|
type: 'string',
|
|
@@ -2020,5 +2300,5 @@ catch (err) {
|
|
|
2020
2300
|
.demandCommand(0)
|
|
2021
2301
|
.strict()
|
|
2022
2302
|
.parse();
|
|
2023
|
-
// Note: legacy --env flag removed; use `hst env`
|
|
2303
|
+
// Note: legacy --env flag removed; use `hst env check`
|
|
2024
2304
|
//# sourceMappingURL=cli.js.map
|