@tantawowa/hosanna-tools 2.19.0 → 2.21.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.
Files changed (59) hide show
  1. package/README.md +61 -8
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +133 -71
  4. package/dist/cli.js.map +1 -1
  5. package/dist/generation/generation-utils.js +4 -0
  6. package/dist/generation/generation-utils.js.map +1 -1
  7. package/dist/generation/node-library-generator.d.ts +1 -0
  8. package/dist/generation/node-library-generator.js +479 -0
  9. package/dist/generation/node-library-generator.js.map +1 -0
  10. package/dist/index.d.ts +148 -0
  11. package/dist/index.js +293 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/lib/cli.configure-hosanna-url.d.ts +11 -1
  14. package/dist/lib/cli.configure-hosanna-url.js +17 -10
  15. package/dist/lib/cli.configure-hosanna-url.js.map +1 -1
  16. package/dist/lib/env-cloud-agent-setup-help.js +3 -6
  17. package/dist/lib/env-cloud-agent-setup-help.js.map +1 -1
  18. package/dist/support-tools/build-config-secrets.d.ts +17 -0
  19. package/dist/support-tools/build-config-secrets.js +114 -0
  20. package/dist/support-tools/build-config-secrets.js.map +1 -0
  21. package/dist/support-tools/cloud-agent-setup.d.ts +7 -3
  22. package/dist/support-tools/cloud-agent-setup.js +20 -27
  23. package/dist/support-tools/cloud-agent-setup.js.map +1 -1
  24. package/dist/support-tools/complib.d.ts +26 -0
  25. package/dist/support-tools/complib.js +102 -0
  26. package/dist/support-tools/complib.js.map +1 -0
  27. package/dist/support-tools/dev-runner.d.ts +2 -0
  28. package/dist/support-tools/dev-runner.js +17 -5
  29. package/dist/support-tools/dev-runner.js.map +1 -1
  30. package/dist/support-tools/mcp-server/cli-test-runner.d.ts +12 -1
  31. package/dist/support-tools/mcp-server/cli-test-runner.js +24 -19
  32. package/dist/support-tools/mcp-server/cli-test-runner.js.map +1 -1
  33. package/dist/support-tools/mcp-server/game-tools.d.ts +47 -0
  34. package/dist/support-tools/mcp-server/game-tools.js +428 -0
  35. package/dist/support-tools/mcp-server/game-tools.js.map +1 -0
  36. package/dist/support-tools/mcp-server/index.d.ts +10 -1
  37. package/dist/support-tools/mcp-server/index.js +12 -3
  38. package/dist/support-tools/mcp-server/index.js.map +1 -1
  39. package/dist/support-tools/mcp-server/tools.js +2 -0
  40. package/dist/support-tools/mcp-server/tools.js.map +1 -1
  41. package/dist/support-tools/mcp-server/types.d.ts +54 -0
  42. package/dist/support-tools/mcp-server/types.js +2 -0
  43. package/dist/support-tools/mcp-server/types.js.map +1 -1
  44. package/dist/support-tools/roku-map-stack.d.ts +7 -0
  45. package/dist/support-tools/roku-map-stack.js +79 -0
  46. package/dist/support-tools/roku-map-stack.js.map +1 -0
  47. package/dist/support-tools/roku-stack-resolver.d.ts +1 -0
  48. package/dist/support-tools/roku-stack-resolver.js +53 -1
  49. package/dist/support-tools/roku-stack-resolver.js.map +1 -1
  50. package/dist/support-tools/tiled-prep.d.ts +15 -0
  51. package/dist/support-tools/tiled-prep.js +277 -0
  52. package/dist/support-tools/tiled-prep.js.map +1 -0
  53. package/package.json +42 -3
  54. package/dist/support-tools/extract-ci-config.d.ts +0 -5
  55. package/dist/support-tools/extract-ci-config.js +0 -70
  56. package/dist/support-tools/extract-ci-config.js.map +0 -1
  57. package/dist/support-tools/restore-debug-flags.d.ts +0 -26
  58. package/dist/support-tools/restore-debug-flags.js +0 -172
  59. package/dist/support-tools/restore-debug-flags.js.map +0 -1
package/README.md CHANGED
@@ -18,6 +18,43 @@ Note, if you are developing hosanna-tools, you will install the package locally.
18
18
  npm install . -g # path to the hosanna-tools directory
19
19
  ```
20
20
 
21
+ ## Embedding as a library
22
+
23
+ Hosanna Tools can also be imported by app build chains. The CLI remains available as `hst`, but package imports are library-safe and do not parse CLI arguments or call `process.exit` during import. Public wrappers for process-oriented commands use no-exit mode where supported, so API callers receive structured results or thrown errors instead of forced process termination.
24
+
25
+ ```ts
26
+ import { buildConfig, env, generate, install, roku, secrets } from '@tantawowa/hosanna-tools';
27
+
28
+ await generate.all({
29
+ rootFolder: './src',
30
+ generatedFolder: './src-generated',
31
+ mode: 'runtime',
32
+ });
33
+
34
+ await buildConfig.resolve({
35
+ env: 'dev',
36
+ platform: 'roku',
37
+ out: 'assets/meta/build-config.json',
38
+ });
39
+
40
+ await install.compiler({ version: '0.33.7' });
41
+ await roku.package({ env: 'prod', prebuild: 'npm run roku:build:prod' });
42
+ ```
43
+
44
+ Common build-script replacements:
45
+
46
+ | CLI command | Programmatic API |
47
+ | --- | --- |
48
+ | `npx hst generate --rootFolder ./src` | `await generate.all({ rootFolder: './src' })` |
49
+ | `npx hst generate:clean` | `await generate.clean()` |
50
+ | `npx hst build-config resolve --env dev --platform roku --out assets/meta/build-config.json` | `await buildConfig.resolve({ env: 'dev', platform: 'roku', out: 'assets/meta/build-config.json' })` |
51
+ | `npx hst install:compiler 0.33.7` | `await install.compiler({ version: '0.33.7' })` |
52
+ | `npx hst roku:package --env prod --prebuild 'npm run roku:build:prod'` | `await roku.package({ env: 'prod', prebuild: 'npm run roku:build:prod' })` |
53
+ | `npx hst secrets:check` | `await secrets.check({ cwd: process.cwd() })` |
54
+ | `npx hst env` | `await env.check({ cwd: process.cwd() })` |
55
+
56
+ Long-running APIs such as `dev.run`, `debugger.start`, `mcp.start`, `test.record`, and RASP capture-style workflows keep the same operational behavior as the corresponding CLI commands: they start services, attach to debuggers, or wait for user/session activity. `mcp.start`, `dev.run`, and `test.ui` are wired for programmatic no-exit behavior through the top-level API.
57
+
21
58
  # Getting started
22
59
 
23
60
  Ensure you have Node.js 20 or higher.
@@ -113,6 +150,22 @@ The CLI commands are organized into logical groups using colon-separated namespa
113
150
  ### Roku Commands (`roku:*`) - Roku Deployment & Packaging
114
151
  - `roku:run` - Deploy a Roku app to a device (supports .zip file or folder)
115
152
  - `roku:package` - Package and sign a Roku channel using roku-deploy
153
+ - `roku:map-stack` - Resolve Roku `.brs` stack traces, compile errors, and crash snippets to original TypeScript locations using `.brs.map` files
154
+
155
+ Resolve pasted Roku output:
156
+
157
+ ```bash
158
+ pbpaste | hst roku:map-stack --source-map-root platforms/roku/src
159
+ ```
160
+
161
+ Resolve a saved crash report or a single line:
162
+
163
+ ```bash
164
+ hst roku:map-stack --file crash.txt --source-map-root platforms/roku/src
165
+ hst roku:map-stack --text "file/line: pkg:/components/source_0.brs(7475)"
166
+ ```
167
+
168
+ Supported inputs include `file/line: pkg:/components/source_0.brs(7475)`, `at ... (pkg:/components/source_1.brs:6636)`, `in pkg:/components/source_3.brs(4710)`, and bare generated references such as `source_10.brs:8211`. See [docs/roku-map-stack.md](docs/roku-map-stack.md).
116
169
 
117
170
  ### Generate Commands (`generate:*`) - Code Generation
118
171
  - `generate` - Generate structs and command handler maps
@@ -142,11 +195,12 @@ npm run apple:build-code
142
195
 
143
196
  ### CI Commands (`ci:*`) - Continuous Integration
144
197
  - `ci:extract-pkg-key` - Extract signing key from an existing signed Roku package as base64
145
- - `ci:extract-config` - Extract debug-flags JSON files as base64 environment variables
146
- - `ci:restore-flags` - Restore debug-flags JSON files from base64 environment variables
147
- - `ci:prepare-debug-flags` - Prepare one runtime `debug-flags.json` from `DEBUG_FLAGS_<ENV>_BASE64` or a local source file
148
198
  - `ci:configure-hosanna-url` - Configure hosanna.json git-url from argument or environment
149
199
 
200
+ ### Build Config Commands (`build-config:*`) - Build/runtime config
201
+ - `build-config resolve` - Merge build config overlays into `assets/meta/build-config.json`
202
+ - `build-config:restore-secrets` - Restore ignored `secrets/*.json` overlays from `BUILD_CONFIG_SECRETS_*_BASE64`
203
+
150
204
  ### Secrets Commands (`secrets:*`) - Portable `.secrets` files
151
205
  - `secrets:list` - Print key names from `.secrets` (or `--template` for `.secrets.example`); `--format json`
152
206
  - `secrets:check` - Compare `.secrets` to the template; report missing, empty, and extra keys; `--strict` fails on extras
@@ -158,13 +212,13 @@ Shared options: `--file` (secrets path), `--template` (template path for `check`
158
212
  ### Environment Commands (`env:*`) - Environment Management
159
213
  - `env` - Print environment information and run checks with auto-fix option
160
214
  - `env:prepare-gitignore` - Ensure .gitignore contains required entries
161
- - `env:cloud-agent-setup` - Restore debug flags, patch `remoteDebug` for cloud agents, optionally start debugger and `npm run dev`
215
+ - `env:cloud-agent-setup` - Write `build-config/profiles/cloud-agent.json`, patch `remoteDebug` for cloud agents, optionally start debugger and `npm run dev` with `HS_BUILD_PROFILE=cloud-agent`
162
216
 
163
217
  ### MCP Debugging Commands (`run:mcp`, `stop:mcp`) - AI Agent Debugging
164
218
  - `run:mcp` - Start the Hosanna MCP server for AI agent debugging
165
219
  - `stop:mcp` - Stop the Hosanna MCP server
166
220
 
167
- **Cursor agents and MCP:** Cursor does not magically attach to a terminal `hst run:mcp`. You add Hosanna as an MCP server (project **`.cursor/mcp.json`** or **Cursor Settings → MCP → Add Custom MCP**) so Cursor spawns **`hosanna-mcp`** (stdio transport). That process talks to the **command debugger** on HTTP **59150** and extension WebSocket **59153** by default. In **Cursor Cloud Agents**, run **`npx hst env:cloud-agent-setup --start-debugger --start-app`** (and set **`DEBUG_FLAGS_DEV_BASE64`** in agent secrets) so those services and `debug-flags.dev.json` exist before the agent uses MCP tools. See [Cursor MCP settings](#cursor-settings--mcp-hosanna-debugger) below.
221
+ **Cursor agents and MCP:** Cursor does not magically attach to a terminal `hst run:mcp`. You add Hosanna as an MCP server (project **`.cursor/mcp.json`** or **Cursor Settings → MCP → Add Custom MCP**) so Cursor spawns **`hosanna-mcp`** (stdio transport). That process talks to the **command debugger** on HTTP **59150** and extension WebSocket **59153** by default. In **Cursor Cloud Agents**, run **`npx hst env:cloud-agent-setup --start-debugger --start-app`** so those services are up before the agent uses MCP tools. See [Cursor MCP settings](#cursor-settings--mcp-hosanna-debugger) below.
168
222
 
169
223
  ### UI Test Commands (`test:*`) - UI Test Automation
170
224
  - `test:ui` - Replay UI test recordings against a running Hosanna app
@@ -189,9 +243,8 @@ hst install:template # Create new template app
189
243
 
190
244
  # CI/CD operations
191
245
  hst ci:extract-pkg-key myapp.pkg # Extract signing key for CI
192
- hst ci:extract-config # Extract debug config for CI
193
- hst ci:restore-flags # Restore config from CI variables
194
- hst ci:prepare-debug-flags --env prod --source assets/meta/debug-flags.prod.json --output-file build/debug-flags/prod/debug-flags.json
246
+ hst build-config:restore-secrets
247
+ hst build-config resolve --env prod --platform roku --out assets/meta/build-config.json
195
248
 
196
249
  # Secrets (.secrets / .secrets.example)
197
250
  hst secrets:list
@@ -1,6 +1,6 @@
1
1
  {
2
- "buildDate": "2026-06-02T15:26:13+01:00",
3
- "buildDateISO": "2026-06-02T14:26:13.016Z",
2
+ "buildDate": "2026-06-10T19:58:46+01:00",
3
+ "buildDateISO": "2026-06-10T18:58:46.578Z",
4
4
  "timeZone": "Europe/London",
5
- "gitHash": "de31d2c"
5
+ "gitHash": "411594a"
6
6
  }
package/dist/cli.js CHANGED
@@ -87,12 +87,46 @@ catch (err) {
87
87
  // Let yargs handle all commands including env
88
88
  (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
89
89
  .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 run:* Development execution (dev, roku, debugger, mcp)\n stop:mcp Stop the Hosanna MCP server (PID lock; alias: run:stop)\n roku:* Roku deployment & packaging (run, package)\n generate:* Code generation (structs, clean)\n install:* Setup & installation (compiler, template)\n build-config Build/runtime configuration resolution\n ci:* Continuous integration (extract-pkg-key, extract-config, restore-flags)\n secrets:* Portable .secrets (list, check, exec, init)\n test:* UI testing (replay recordings, visual regression)\n rasp:* RASP cert scripts (capture, export, validate)\n env:* Environment management (prepare-gitignore, cloud-agent-setup)`)
90
+ .usage('$0 [command] [options]', `Hosanna Tools CLI\nVersion: ${buildVersion}\nBuild Date: ${buildDate}\n\nCommand Groups:\n run:* Development execution (dev, roku, debugger, mcp)\n stop:mcp Stop the Hosanna MCP server (PID lock; alias: run:stop)\n roku:* Roku deployment & packaging (run, package)\n generate:* Code generation (structs, clean)\n install:* Setup & installation (compiler, template)\n build-config Build/runtime configuration resolution\n ci:* Continuous integration (extract-pkg-key)\n secrets:* Portable .secrets (list, check, exec, init)\n test:* UI testing (replay recordings, visual regression)\n rasp:* RASP cert scripts (capture, export, validate)\n env:* Environment management (prepare-gitignore, cloud-agent-setup)`)
91
91
  .option('verbose', {
92
92
  type: 'boolean',
93
93
  default: false,
94
94
  describe: 'Enable verbose logging for all operations',
95
95
  global: true
96
+ })
97
+ .command('game prep-level <input>', 'Normalize a Tiled JSON map into the Hs2d canonical runtime subset', yargs => yargs
98
+ .positional('input', { type: 'string', demandOption: true, describe: 'Path to a Tiled .json/.tmj map export' })
99
+ .option('out', { alias: 'o', type: 'string', describe: 'Output path (defaults to overwriting the input file)' })
100
+ .option('pretty', { type: 'boolean', default: false, describe: 'Pretty-print the output JSON (device payloads default to compact)' })
101
+ .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
+ .epilog([
103
+ 'Converts what Tiled produces into what the Hs2d device parser reads:',
104
+ ' - decodes base64 (+zlib/gzip) tile data into plain arrays',
105
+ ' - inlines external JSON tilesets and drops unused ones',
106
+ ' - strips editor-only fields',
107
+ 'Fails with guidance on infinite maps, flip flags, TSX tilesets,',
108
+ 'zstd compression, and maps that use more than one tileset.',
109
+ ].join('\n')), async (args) => {
110
+ var _a;
111
+ try {
112
+ const fsMod = await Promise.resolve().then(() => __importStar(require('fs')));
113
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/tiled-prep.js')));
114
+ const inputPath = args.input;
115
+ const outPath = (_a = args.out) !== null && _a !== void 0 ? _a : inputPath;
116
+ const result = mod.prepTiledMapFile(inputPath);
117
+ const json = args.pretty ? JSON.stringify(result.map, null, 2) : JSON.stringify(result.map);
118
+ fsMod.writeFileSync(outPath, json);
119
+ for (const warning of result.warnings) {
120
+ console.info(` - ${warning}`);
121
+ }
122
+ console.info(`✅ Prepped Tiled map ${inputPath} -> ${outPath} (${json.length} bytes)`);
123
+ process.exit(0);
124
+ }
125
+ catch (err) {
126
+ const message = err instanceof Error ? err.message : String(err);
127
+ console.error(`❌ prep-level failed: ${message}`);
128
+ process.exit(1);
129
+ }
96
130
  })
97
131
  .command('build-config resolve', 'Resolve Hosanna build config overlays into the canonical runtime build-config.json', yargs => yargs
98
132
  .option('env', { type: 'string', describe: 'Environment, e.g. dev, qa, or prod (or HS_ENV / HOSANNA_BUILD_ENV)' })
@@ -144,6 +178,38 @@ catch (err) {
144
178
  console.error('❌ Failed to resolve build config:', err);
145
179
  process.exit(1);
146
180
  }
181
+ })
182
+ .command('build-config:restore-secrets', 'Restore ignored build config secret overlays from BUILD_CONFIG_SECRETS_*_BASE64 environment variables', yargs => yargs
183
+ .option('out-dir', { type: 'string', describe: 'Output directory for secret overlays (default: secrets)' })
184
+ .option('env', { type: 'string', describe: 'Restore only one environment overlay, e.g. dev or prod' })
185
+ .option('profile', { type: 'string', describe: 'Restore only one profile overlay, e.g. george' })
186
+ .option('quiet', { type: 'boolean', default: false, describe: 'Reduce output' })
187
+ .example('$0 build-config:restore-secrets', 'Restore all build config secret overlays from the environment')
188
+ .example('$0 build-config:restore-secrets --env prod', 'Restore only BUILD_CONFIG_SECRETS_PROD_BASE64')
189
+ .epilog([
190
+ 'Environment variables:',
191
+ ' BUILD_CONFIG_SECRETS_<ENV>_BASE64 -> secrets/<env>.json',
192
+ ' BUILD_CONFIG_PROFILE_SECRETS_<PROFILE>_BASE64 -> secrets/profiles/<profile>.json',
193
+ 'Values must be base64-encoded JSON objects. Secret values are never printed.',
194
+ ].join('\n')), async (args) => {
195
+ if (args.verbose) {
196
+ process.env.HOSANNA_VERBOSE = '1';
197
+ process.env.HOSANNA_UPDATER_VERBOSE = '1';
198
+ }
199
+ try {
200
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/build-config-secrets.js')));
201
+ mod.restoreBuildConfigSecrets({
202
+ outDir: args['out-dir'],
203
+ env: args.env,
204
+ profile: args.profile,
205
+ quiet: Boolean(args.quiet),
206
+ });
207
+ process.exit(0);
208
+ }
209
+ catch (err) {
210
+ console.error('❌ Failed to restore build config secret overlays:', err);
211
+ process.exit(1);
212
+ }
147
213
  })
148
214
  .command(['version', 'v'], 'Print the version number', yargs => yargs, () => {
149
215
  console.log(buildVersion);
@@ -216,6 +282,41 @@ catch (err) {
216
282
  console.error('❌ Failed to publish Roku package:', err);
217
283
  process.exit(1);
218
284
  }
285
+ })
286
+ .command('roku:map-stack', 'Resolve Roku BrightScript stack traces or compile errors to original TypeScript locations using .brs.map files', yargs => yargs
287
+ .option('source-map-root', {
288
+ type: 'string',
289
+ default: 'platforms/roku/src',
290
+ describe: 'Path to packaged Roku source root containing .brs.map files, e.g. platforms/roku/src'
291
+ })
292
+ .option('file', {
293
+ type: 'string',
294
+ describe: 'Read stack trace text from a file instead of stdin'
295
+ })
296
+ .option('text', {
297
+ type: 'string',
298
+ describe: 'Resolve this stack trace text directly instead of stdin'
299
+ })
300
+ .example('pbpaste | $0 roku:map-stack --source-map-root platforms/roku/src', 'Resolve a pasted Roku crash or compiler log')
301
+ .example('$0 roku:map-stack --file crash.txt --source-map-root platforms/roku/src', 'Resolve stack trace text from a file')
302
+ .example('$0 roku:map-stack --text "file/line: pkg:/components/source_0.brs(7475)"', 'Resolve a single Roku backtrace line'), async (args) => {
303
+ if (args.verbose) {
304
+ process.env.HOSANNA_VERBOSE = '1';
305
+ }
306
+ try {
307
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/roku-map-stack.js')));
308
+ await mod.runRokuMapStackCommand({
309
+ sourceMapRoot: args['source-map-root'],
310
+ file: args.file,
311
+ text: args.text,
312
+ });
313
+ process.exit(0);
314
+ }
315
+ catch (err) {
316
+ const msg = err instanceof Error ? err.message : String(err);
317
+ console.error(`❌ Failed to map Roku stack trace: ${msg}`);
318
+ process.exit(1);
319
+ }
219
320
  })
220
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
221
322
  .option('ip', { type: 'string', describe: 'Roku device IP (env: ROKU_IP)' })
@@ -309,74 +410,6 @@ catch (err) {
309
410
  console.error('❌ Failed to create CI package:', err);
310
411
  process.exit(1);
311
412
  }
312
- })
313
- .command('ci:extract-config', 'Extract debug-flags JSON files as base64 environment variables for CI', yargs => yargs
314
- .option('output-dir', { type: 'string', describe: 'Directory containing debug-flags files (default: assets/meta)' })
315
- .option('root-keys', { type: 'string', describe: 'Comma-separated list of root keys to include (default: env,remoteDebug,services,appController,config,remoteStyleFile)' })
316
- .example('$0 ci:extract-config', 'Extract all debug-flags.*.json files as base64 environment variables')
317
- .example('$0 ci:extract-config --output-dir ./config', 'Extract from custom directory')
318
- .example('$0 ci:extract-config --root-keys env,remoteDebug', 'Extract only specific root keys'), async (args) => {
319
- if (args.verbose) {
320
- process.env.HOSANNA_VERBOSE = '1';
321
- process.env.HOSANNA_UPDATER_VERBOSE = '1';
322
- }
323
- try {
324
- const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/extract-ci-config.js')));
325
- await mod.extractCiConfig({
326
- outputDir: args['output-dir'],
327
- rootKeys: args['root-keys'],
328
- });
329
- process.exit(0);
330
- }
331
- catch (err) {
332
- console.error('❌ Failed to extract CI config:', err);
333
- process.exit(1);
334
- }
335
- })
336
- .command('ci:restore-flags', 'Restore debug-flags JSON files from DEBUG_FLAGS_*_BASE64 environment variables', yargs => yargs
337
- .option('output-dir', { type: 'string', describe: 'Directory to restore debug-flags files (default: assets/meta)' })
338
- .example('$0 ci:restore-flags', 'Restore debug-flags files from environment variables')
339
- .example('$0 ci:restore-flags --output-dir ./config', 'Restore to custom directory'), async (args) => {
340
- if (args.verbose) {
341
- process.env.HOSANNA_VERBOSE = '1';
342
- process.env.HOSANNA_UPDATER_VERBOSE = '1';
343
- }
344
- try {
345
- const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/restore-debug-flags.js')));
346
- await mod.restoreDebugFlags({
347
- outputDir: args['output-dir'],
348
- });
349
- process.exit(0);
350
- }
351
- catch (err) {
352
- console.error('❌ Failed to restore debug flags:', err);
353
- process.exit(1);
354
- }
355
- })
356
- .command('ci:prepare-debug-flags', 'Prepare one runtime debug-flags.json file from DEBUG_FLAGS_<ENV>_BASE64 or a local source file', yargs => yargs
357
- .option('env', { type: 'string', demandOption: true, describe: 'Environment to prepare, e.g. dev or prod' })
358
- .option('source', { type: 'string', demandOption: true, describe: 'Local debug-flags source file to use when the env var is absent' })
359
- .option('output-file', { type: 'string', demandOption: true, describe: 'Runtime debug-flags.json output path' })
360
- .option('quiet', { type: 'boolean', default: false, describe: 'Reduce output' })
361
- .example('$0 ci:prepare-debug-flags --env prod --source assets/meta/debug-flags.prod.json --output-file build/debug-flags/prod/debug-flags.json', 'Prepare prod runtime debug flags without overwriting the local source file'), async (args) => {
362
- if (args.verbose) {
363
- process.env.HOSANNA_VERBOSE = '1';
364
- process.env.HOSANNA_UPDATER_VERBOSE = '1';
365
- }
366
- try {
367
- const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/restore-debug-flags.js')));
368
- await mod.prepareDebugFlags({
369
- env: args.env,
370
- source: args.source,
371
- outputFile: args['output-file'],
372
- quiet: Boolean(args.quiet),
373
- });
374
- process.exit(0);
375
- }
376
- catch (err) {
377
- console.error('❌ Failed to prepare debug flags:', err);
378
- process.exit(1);
379
- }
380
413
  })
381
414
  .command('secrets:list', 'Print secret key names from .secrets (values hidden). Use --template for .secrets.example', yargs => yargs
382
415
  .option('file', { type: 'string', describe: 'Path to .secrets (default: .secrets in cwd or git root)' })
@@ -532,7 +565,7 @@ catch (err) {
532
565
  }
533
566
  })
534
567
  .command('env:cloud-agent-setup', 'Restore debug flags, patch remoteDebug for agents, optionally start debugger and npm dev (see --help for Cursor Cloud Agents)', yargs => yargs
535
- .option('output-dir', { type: 'string', describe: 'Directory for debug-flags.dev.json (default: assets/meta)' })
568
+ .option('output-dir', { type: 'string', describe: 'Directory for cloud-agent.json build config profile (default: build-config/profiles)' })
536
569
  .option('start-debugger', { type: 'boolean', default: false, describe: 'Start command debugger in-process (non-blocking)' })
537
570
  .option('start-app', { type: 'boolean', default: false, describe: 'Spawn npm run dev detached and wait for Vite port' })
538
571
  .option('vite-port', { type: 'number', default: 5173, describe: 'Port to wait on when --start-app is set' })
@@ -913,6 +946,35 @@ catch (err) {
913
946
  console.error('An error occurred during the install template process:', err);
914
947
  process.exit(1);
915
948
  }
949
+ })
950
+ .command('complib:package', 'Zip a built Roku component library (libraryMode "standalone" output) into a distributable archive', yargs => yargs
951
+ .option('src', { type: 'string', demandOption: true, describe: 'Built package root containing manifest and components/' })
952
+ .option('out', { type: 'string', describe: 'Output zip path (default: <src>/../<folder>.zip)' })
953
+ .example('$0 complib:package --src platforms/roku-complib/pkg --out dist/vendor-lib.zip', 'Package a built library'), async (args) => {
954
+ try {
955
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/complib.js')));
956
+ const out = mod.packageComponentLibrary({ src: args.src, out: args.out });
957
+ console.info(`✅ Component library packaged: ${out}`);
958
+ process.exit(0);
959
+ }
960
+ catch (err) {
961
+ console.error('❌ complib:package failed:', err instanceof Error ? err.message : err);
962
+ process.exit(1);
963
+ }
964
+ })
965
+ .command('complib:serve', 'Serve component library zips over HTTP for the on-device dev loop', yargs => yargs
966
+ .option('dir', { type: 'string', demandOption: true, describe: 'Directory containing library zip(s)' })
967
+ .option('port', { type: 'number', default: 8061, describe: 'HTTP port' })
968
+ .example('$0 complib:serve --dir dist --port 8061', 'Serve dist/*.zip to ComponentLibrary.uri consumers'), async (args) => {
969
+ try {
970
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/complib.js')));
971
+ mod.serveComponentLibrary({ dir: args.dir, port: args.port });
972
+ // keep the process alive while serving
973
+ }
974
+ catch (err) {
975
+ console.error('❌ complib:serve failed:', err instanceof Error ? err.message : err);
976
+ process.exit(1);
977
+ }
916
978
  })
917
979
  .command('roku:run', 'Deploy a Roku app to a device (supports .zip file or folder)', yargs => yargs
918
980
  .option('ip', { type: 'string', describe: 'Roku device IP (env: ROKU_IP)' })
@@ -1077,7 +1139,7 @@ catch (err) {
1077
1139
  process.env.HOSANNA_VERBOSE = '1';
1078
1140
  process.env.HOSANNA_UPDATER_VERBOSE = '1';
1079
1141
  }
1080
- return (0, cli_configure_hosanna_url_js_1.runConfigureHosannaUrl)(typeof args.gitUrl === 'string' ? args.gitUrl : undefined);
1142
+ (0, cli_configure_hosanna_url_js_1.runConfigureHosannaUrl)(typeof args.gitUrl === 'string' ? args.gitUrl : undefined);
1081
1143
  })
1082
1144
  .command('test:ui [recordings..]', 'Replay UI test recordings against a running Hosanna app and exit with pass/fail. ' +
1083
1145
  'Requires a running debug proxy (hst run:debugger) and a connected app.', yargs => yargs