@tantawowa/hosanna-tools 3.0.0 → 3.2.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/dist/build-info.json +3 -3
- package/dist/cli.js +147 -73
- package/dist/cli.js.map +1 -1
- package/dist/run/executor.d.ts +4 -0
- package/dist/run/executor.js +52 -11
- package/dist/run/executor.js.map +1 -1
- package/dist/run/planner.d.ts +1 -0
- package/dist/run/planner.js +92 -7
- package/dist/run/planner.js.map +1 -1
- package/dist/run/run-config.d.ts +9 -0
- package/dist/run/run-config.js +16 -0
- package/dist/run/run-config.js.map +1 -1
- package/dist/support-tools/build-config-resolver.d.ts +6 -0
- package/dist/support-tools/build-config-resolver.js +66 -1
- package/dist/support-tools/build-config-resolver.js.map +1 -1
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -60,9 +60,9 @@ const env_info_js_1 = require("./lib/env-info.js");
|
|
|
60
60
|
const hosanna_tools_utils_js_1 = require("./lib/hosanna-tools-utils.js");
|
|
61
61
|
const cli_app_config_resolve_js_1 = require("./lib/cli.app-config-resolve.js");
|
|
62
62
|
const hosanna_config_js_1 = require("./lib/hosanna-config.js");
|
|
63
|
-
function formatRunPlanText(plan, explain) {
|
|
63
|
+
function formatRunPlanText(plan, explain, command = 'run') {
|
|
64
64
|
const lines = [
|
|
65
|
-
`hst
|
|
65
|
+
`hst ${command} plan: ${plan.resolved.platform} ${plan.resolved.env} ${plan.resolved.target}`,
|
|
66
66
|
'',
|
|
67
67
|
...plan.shellPreview.map(line => ` ${line}`),
|
|
68
68
|
];
|
|
@@ -91,6 +91,84 @@ function rawHasFlag(name) {
|
|
|
91
91
|
const dashName = `--${name}`;
|
|
92
92
|
return (0, helpers_1.hideBin)(process.argv).some(token => token === dashName || token.startsWith(`${dashName}=`));
|
|
93
93
|
}
|
|
94
|
+
function runPlanFlagsFromCliArgs(args, format) {
|
|
95
|
+
return {
|
|
96
|
+
platform: rawHasFlag('platform') ? args.platform : undefined,
|
|
97
|
+
env: rawHasFlag('env') ? args.env : undefined,
|
|
98
|
+
app: rawHasFlag('app') ? args.app : undefined,
|
|
99
|
+
target: rawHasFlag('target') ? args.target : undefined,
|
|
100
|
+
device: rawHasFlag('device') ? args.device : undefined,
|
|
101
|
+
profile: rawHasFlag('profile') ? args.profile : undefined,
|
|
102
|
+
appConfig: rawHasFlag('app-config') ? args['app-config'] : undefined,
|
|
103
|
+
hotReload: rawHasFlag('hot-reload') ? Boolean(args['hot-reload']) : undefined,
|
|
104
|
+
bundled: rawHasFlag('bundled') ? Boolean(args.bundled) : undefined,
|
|
105
|
+
noBuild: rawHasFlag('no-build') ? Boolean(args['no-build']) : undefined,
|
|
106
|
+
buildOnly: rawHasFlag('build-only') ? Boolean(args['build-only']) : undefined,
|
|
107
|
+
noLogs: rawHasFlag('no-logs') ? Boolean(args['no-logs']) : undefined,
|
|
108
|
+
logs: rawHasFlag('logs') ? Boolean(args.logs) : undefined,
|
|
109
|
+
sourceRoot: rawHasFlag('source-root') ? args['source-root'] : undefined,
|
|
110
|
+
appPackage: rawHasFlag('app-package') ? args['app-package'] : undefined,
|
|
111
|
+
files: rawHasFlag('files') ? args.files : undefined,
|
|
112
|
+
deployTimeoutMs: rawHasFlag('deploy-timeout-ms') ? args['deploy-timeout-ms'] : undefined,
|
|
113
|
+
config: rawHasFlag('config') ? args.config : undefined,
|
|
114
|
+
hscProject: rawHasFlag('hsc-project') ? args.hscProject : undefined,
|
|
115
|
+
vitePort: rawHasFlag('vitePort') ? args.vitePort : undefined,
|
|
116
|
+
webAppPort: rawHasFlag('webAppPort') ? args.webAppPort : undefined,
|
|
117
|
+
deviceAppPort: rawHasFlag('deviceAppPort') ? args.deviceAppPort : undefined,
|
|
118
|
+
extensionPort: rawHasFlag('extensionPort') ? args.extensionPort : undefined,
|
|
119
|
+
managementPort: rawHasFlag('managementPort') ? args.managementPort : undefined,
|
|
120
|
+
appName: rawHasFlag('appName') ? args.appName : undefined,
|
|
121
|
+
replace: rawHasFlag('replace') ? Boolean(args.replace) : undefined,
|
|
122
|
+
nonInteractive: rawHasFlag('non-interactive') ? Boolean(args['non-interactive']) : undefined,
|
|
123
|
+
dryRun: Boolean(args['dry-run']),
|
|
124
|
+
format,
|
|
125
|
+
explain: rawHasFlag('explain') ? Boolean(args.explain) : undefined,
|
|
126
|
+
allowProfileInProd: rawHasFlag('allow-profile-in-prod') ? Boolean(args['allow-profile-in-prod']) : undefined,
|
|
127
|
+
passthroughArgs: args['--'],
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function runRunPlanCommand(command, args) {
|
|
131
|
+
var _a, _b, _c;
|
|
132
|
+
try {
|
|
133
|
+
const planner = await Promise.resolve().then(() => __importStar(require('./run/planner.js')));
|
|
134
|
+
const executor = await Promise.resolve().then(() => __importStar(require('./run/executor.js')));
|
|
135
|
+
const positionalArgv = rawCommandPositionals(command);
|
|
136
|
+
const format = (args.json || args.format === 'json') ? 'json' : 'text';
|
|
137
|
+
const planInput = {
|
|
138
|
+
cwd: process.cwd(),
|
|
139
|
+
argv: positionalArgv,
|
|
140
|
+
flags: runPlanFlagsFromCliArgs(args, format),
|
|
141
|
+
env: process.env,
|
|
142
|
+
};
|
|
143
|
+
const plan = command === 'build'
|
|
144
|
+
? planner.createBuildPlan(planInput)
|
|
145
|
+
: planner.createRunPlan(planInput);
|
|
146
|
+
if (args['dry-run']) {
|
|
147
|
+
if (format === 'json') {
|
|
148
|
+
console.info(JSON.stringify(plan, null, 2));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.info(formatRunPlanText(plan, Boolean(args.explain), command));
|
|
152
|
+
}
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}
|
|
155
|
+
const result = await executor.executeRunPlan(plan);
|
|
156
|
+
if (format === 'json') {
|
|
157
|
+
console.info(JSON.stringify(result, null, 2));
|
|
158
|
+
}
|
|
159
|
+
else if (result.status === 'reused') {
|
|
160
|
+
console.info(`hst ${command}: reusing ${(_a = result.appName) !== null && _a !== void 0 ? _a : 'app'} at ${(_b = result.url) !== null && _b !== void 0 ? _b : '(unknown URL)'}`);
|
|
161
|
+
}
|
|
162
|
+
else if (result.url) {
|
|
163
|
+
console.info(`hst ${command}: ${(_c = result.appName) !== null && _c !== void 0 ? _c : 'app'} available at ${result.url}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
console.error(`❌ ${command} failed`);
|
|
168
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
94
172
|
const NATIVE_PLATFORM_CHOICES = ['apple', 'ios', 'apple-tv', 'android', 'android-tv', 'all'];
|
|
95
173
|
function nativeInputFromArgs(args) {
|
|
96
174
|
return {
|
|
@@ -154,7 +232,7 @@ catch (err) {
|
|
|
154
232
|
// Let yargs handle all commands including env
|
|
155
233
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
156
234
|
.version(`${buildVersion}\n git: ${buildGitHash}\n built: ${buildDate}`)
|
|
157
|
-
.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 native:* Native platform bootstrap and validation\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`)
|
|
235
|
+
.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 build Cross-platform build orchestration\n run Cross-platform launch orchestration\n native:* Native platform bootstrap and validation\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`)
|
|
158
236
|
.option('verbose', {
|
|
159
237
|
type: 'boolean',
|
|
160
238
|
default: false,
|
|
@@ -1384,6 +1462,71 @@ catch (err) {
|
|
|
1384
1462
|
console.error(err instanceof Error ? err.message : String(err));
|
|
1385
1463
|
process.exit(1);
|
|
1386
1464
|
}
|
|
1465
|
+
})
|
|
1466
|
+
.command('build [platform] [env] [target] [deviceSelector]', 'Build a Hosanna app for a platform target without launching, deploying, opening browsers, or streaming logs', yargs => yargs
|
|
1467
|
+
.parserConfiguration({ 'boolean-negation': false, 'populate--': true })
|
|
1468
|
+
.positional('platform', {
|
|
1469
|
+
type: 'string',
|
|
1470
|
+
describe: 'Build platform. Defaults from flags, env, .hosanna-tools/run.json, then web.',
|
|
1471
|
+
})
|
|
1472
|
+
.positional('env', {
|
|
1473
|
+
type: 'string',
|
|
1474
|
+
describe: 'Build environment, e.g. dev, qa, or prod.',
|
|
1475
|
+
})
|
|
1476
|
+
.positional('target', {
|
|
1477
|
+
type: 'string',
|
|
1478
|
+
describe: 'Target kind: browser, device, simulator, or emulator.',
|
|
1479
|
+
})
|
|
1480
|
+
.positional('deviceSelector', {
|
|
1481
|
+
type: 'string',
|
|
1482
|
+
describe: 'Device IP, serial/UDID, AVD name, simulator name, or case-insensitive name substring.',
|
|
1483
|
+
})
|
|
1484
|
+
.option('platform', {
|
|
1485
|
+
type: 'string',
|
|
1486
|
+
choices: ['web', 'roku', 'ios', 'apple-tv', 'android', 'android-tv'],
|
|
1487
|
+
describe: 'Build platform.',
|
|
1488
|
+
})
|
|
1489
|
+
.option('env', {
|
|
1490
|
+
type: 'string',
|
|
1491
|
+
describe: 'Build environment, e.g. dev, qa, or prod.',
|
|
1492
|
+
})
|
|
1493
|
+
.option('target', {
|
|
1494
|
+
type: 'string',
|
|
1495
|
+
choices: ['browser', 'web', 'device', 'simulator', 'emulator', 'simulated', 'emulated'],
|
|
1496
|
+
describe: 'Target kind. Defaults by platform.',
|
|
1497
|
+
})
|
|
1498
|
+
.option('device', {
|
|
1499
|
+
type: 'string',
|
|
1500
|
+
describe: 'Device IP, serial/UDID, case-insensitive name substring, or web preset id for --target browser',
|
|
1501
|
+
})
|
|
1502
|
+
.option('appName', {
|
|
1503
|
+
type: 'string',
|
|
1504
|
+
describe: 'App name used for debugger/session identity',
|
|
1505
|
+
})
|
|
1506
|
+
.option('app', { type: 'string', describe: 'Run config app/flavor selector (env: HOSANNA_RUN_APP)' })
|
|
1507
|
+
.option('profile', { type: 'string', describe: 'Build config profile (env: HS_BUILD_PROFILE)' })
|
|
1508
|
+
.option('allow-profile-in-prod', { type: 'boolean', default: false, describe: 'Allow applying --profile with --env prod' })
|
|
1509
|
+
.option('app-config', { type: 'string', describe: 'Runtime app config selector passed to web/native launch inputs' })
|
|
1510
|
+
.option('hot-reload', { type: 'boolean', default: false, describe: 'Use native JS dev server where supported' })
|
|
1511
|
+
.option('bundled', { type: 'boolean', default: false, describe: 'Use bundled native JS/assets where supported' })
|
|
1512
|
+
.option('vitePort', { type: 'number', description: 'Port for Vite dev server', default: 5173 })
|
|
1513
|
+
.option('webAppPort', { type: 'number', description: 'Port for web app debugger client', default: 59151 })
|
|
1514
|
+
.option('deviceAppPort', { type: 'number', description: 'Port for device app debugger client', default: 59152 })
|
|
1515
|
+
.option('extensionPort', { type: 'number', description: 'Debugger extension WebSocket port', default: 59153 })
|
|
1516
|
+
.option('managementPort', { type: 'number', description: 'Debugger management HTTP port', default: 59150 })
|
|
1517
|
+
.option('non-interactive', { type: 'boolean', default: false, describe: 'Fail instead of prompting when a decision is needed' })
|
|
1518
|
+
.option('json', { type: 'boolean', default: false, describe: 'Print build result as JSON when the command returns' })
|
|
1519
|
+
.option('dry-run', { type: 'boolean', default: false, describe: 'Print the resolved build RunPlan without executing it' })
|
|
1520
|
+
.option('format', { type: 'string', choices: ['text', 'json'], default: 'text', describe: 'Output format for --dry-run and build result' })
|
|
1521
|
+
.option('explain', { type: 'boolean', default: false, describe: 'Include resolution source details in text dry-run output' })
|
|
1522
|
+
.option('hsc-project', { type: 'string', describe: 'Explicit Roku HSC project file for hst build planning' })
|
|
1523
|
+
.option('config', { type: 'string', describe: 'Alias for --hsc-project' })
|
|
1524
|
+
.option('source-root', { type: 'string', describe: 'Roku source root to preserve in build planning output' })
|
|
1525
|
+
.example('$0 build roku dev device', 'Build the dev Roku output without deploying or streaming logs')
|
|
1526
|
+
.example('$0 build roku prod device --hsc-project platforms/hsconfig-roku.prod.json', 'Build Roku with an explicit HSC project file')
|
|
1527
|
+
.example('$0 build ios dev simulator --device "iPhone 17 Pro"', 'Build an iOS simulator target without install, launch, or logs')
|
|
1528
|
+
.example('$0 build web dev browser', 'Resolve web runtime build config without opening a browser'), async (args) => {
|
|
1529
|
+
await runRunPlanCommand('build', args);
|
|
1387
1530
|
})
|
|
1388
1531
|
.command('run [platform] [env] [target] [deviceSelector]', 'Launch a Hosanna app on a platform target (web, Roku, iOS, Apple TV, Android, and Android TV targets are supported)', yargs => yargs
|
|
1389
1532
|
.parserConfiguration({ 'boolean-negation': false, 'populate--': true })
|
|
@@ -1474,76 +1617,7 @@ catch (err) {
|
|
|
1474
1617
|
.example('$0 run --platform roku --target device --device "living room"', 'Build, deploy, launch, and stream logs on a Roku device')
|
|
1475
1618
|
.example('$0 run roku dev device --app criterion', 'Run a configured monorepo app/flavor')
|
|
1476
1619
|
.example('$0 run roku prod device --hsc-project platforms/hsconfig.criterion.prod.json', 'Override the Roku HSC project file'), async (args) => {
|
|
1477
|
-
|
|
1478
|
-
try {
|
|
1479
|
-
const planner = await Promise.resolve().then(() => __importStar(require('./run/planner.js')));
|
|
1480
|
-
const executor = await Promise.resolve().then(() => __importStar(require('./run/executor.js')));
|
|
1481
|
-
const positionalArgv = rawCommandPositionals('run');
|
|
1482
|
-
const format = (args.json || args.format === 'json') ? 'json' : 'text';
|
|
1483
|
-
const plan = planner.createRunPlan({
|
|
1484
|
-
cwd: process.cwd(),
|
|
1485
|
-
argv: positionalArgv,
|
|
1486
|
-
flags: {
|
|
1487
|
-
platform: rawHasFlag('platform') ? args.platform : undefined,
|
|
1488
|
-
env: rawHasFlag('env') ? args.env : undefined,
|
|
1489
|
-
app: rawHasFlag('app') ? args.app : undefined,
|
|
1490
|
-
target: rawHasFlag('target') ? args.target : undefined,
|
|
1491
|
-
device: rawHasFlag('device') ? args.device : undefined,
|
|
1492
|
-
profile: rawHasFlag('profile') ? args.profile : undefined,
|
|
1493
|
-
appConfig: rawHasFlag('app-config') ? args['app-config'] : undefined,
|
|
1494
|
-
hotReload: rawHasFlag('hot-reload') ? Boolean(args['hot-reload']) : undefined,
|
|
1495
|
-
bundled: rawHasFlag('bundled') ? Boolean(args.bundled) : undefined,
|
|
1496
|
-
noBuild: rawHasFlag('no-build') ? Boolean(args['no-build']) : undefined,
|
|
1497
|
-
buildOnly: rawHasFlag('build-only') ? Boolean(args['build-only']) : undefined,
|
|
1498
|
-
noLogs: rawHasFlag('no-logs') ? Boolean(args['no-logs']) : undefined,
|
|
1499
|
-
logs: rawHasFlag('logs') ? Boolean(args.logs) : undefined,
|
|
1500
|
-
sourceRoot: rawHasFlag('source-root') ? args['source-root'] : undefined,
|
|
1501
|
-
appPackage: rawHasFlag('app-package') ? args['app-package'] : undefined,
|
|
1502
|
-
files: rawHasFlag('files') ? args.files : undefined,
|
|
1503
|
-
deployTimeoutMs: rawHasFlag('deploy-timeout-ms') ? args['deploy-timeout-ms'] : undefined,
|
|
1504
|
-
config: rawHasFlag('config') ? args.config : undefined,
|
|
1505
|
-
hscProject: rawHasFlag('hsc-project') ? args.hscProject : undefined,
|
|
1506
|
-
vitePort: rawHasFlag('vitePort') ? args.vitePort : undefined,
|
|
1507
|
-
webAppPort: rawHasFlag('webAppPort') ? args.webAppPort : undefined,
|
|
1508
|
-
deviceAppPort: rawHasFlag('deviceAppPort') ? args.deviceAppPort : undefined,
|
|
1509
|
-
extensionPort: rawHasFlag('extensionPort') ? args.extensionPort : undefined,
|
|
1510
|
-
managementPort: rawHasFlag('managementPort') ? args.managementPort : undefined,
|
|
1511
|
-
appName: rawHasFlag('appName') ? args.appName : undefined,
|
|
1512
|
-
replace: rawHasFlag('replace') ? Boolean(args.replace) : undefined,
|
|
1513
|
-
nonInteractive: rawHasFlag('non-interactive') ? Boolean(args['non-interactive']) : undefined,
|
|
1514
|
-
dryRun: Boolean(args['dry-run']),
|
|
1515
|
-
format,
|
|
1516
|
-
explain: rawHasFlag('explain') ? Boolean(args.explain) : undefined,
|
|
1517
|
-
allowProfileInProd: rawHasFlag('allow-profile-in-prod') ? Boolean(args['allow-profile-in-prod']) : undefined,
|
|
1518
|
-
passthroughArgs: args['--'],
|
|
1519
|
-
},
|
|
1520
|
-
env: process.env,
|
|
1521
|
-
});
|
|
1522
|
-
if (args['dry-run']) {
|
|
1523
|
-
if (format === 'json') {
|
|
1524
|
-
console.info(JSON.stringify(plan, null, 2));
|
|
1525
|
-
}
|
|
1526
|
-
else {
|
|
1527
|
-
console.info(formatRunPlanText(plan, Boolean(args.explain)));
|
|
1528
|
-
}
|
|
1529
|
-
process.exit(0);
|
|
1530
|
-
}
|
|
1531
|
-
const result = await executor.executeRunPlan(plan);
|
|
1532
|
-
if (format === 'json') {
|
|
1533
|
-
console.info(JSON.stringify(result, null, 2));
|
|
1534
|
-
}
|
|
1535
|
-
else if (result.status === 'reused') {
|
|
1536
|
-
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)'}`);
|
|
1537
|
-
}
|
|
1538
|
-
else if (result.url) {
|
|
1539
|
-
console.info(`hst run: ${(_c = result.appName) !== null && _c !== void 0 ? _c : 'app'} available at ${result.url}`);
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
catch (err) {
|
|
1543
|
-
console.error('❌ run failed');
|
|
1544
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
1545
|
-
process.exit(1);
|
|
1546
|
-
}
|
|
1620
|
+
await runRunPlanCommand('run', args);
|
|
1547
1621
|
})
|
|
1548
1622
|
.command('device:run', 'Build, deploy, launch, and stream logs for a device', yargs => yargs
|
|
1549
1623
|
.parserConfiguration({ 'boolean-negation': false })
|