@tantawowa/hosanna-tools 2.19.0 → 2.20.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 (40) hide show
  1. package/README.md +61 -8
  2. package/dist/build-info.json +3 -3
  3. package/dist/cli.js +70 -71
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.d.ts +148 -0
  6. package/dist/index.js +293 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/lib/cli.configure-hosanna-url.d.ts +11 -1
  9. package/dist/lib/cli.configure-hosanna-url.js +17 -10
  10. package/dist/lib/cli.configure-hosanna-url.js.map +1 -1
  11. package/dist/lib/env-cloud-agent-setup-help.js +3 -6
  12. package/dist/lib/env-cloud-agent-setup-help.js.map +1 -1
  13. package/dist/support-tools/build-config-secrets.d.ts +17 -0
  14. package/dist/support-tools/build-config-secrets.js +114 -0
  15. package/dist/support-tools/build-config-secrets.js.map +1 -0
  16. package/dist/support-tools/cloud-agent-setup.d.ts +7 -3
  17. package/dist/support-tools/cloud-agent-setup.js +20 -27
  18. package/dist/support-tools/cloud-agent-setup.js.map +1 -1
  19. package/dist/support-tools/dev-runner.d.ts +2 -0
  20. package/dist/support-tools/dev-runner.js +17 -5
  21. package/dist/support-tools/dev-runner.js.map +1 -1
  22. package/dist/support-tools/mcp-server/cli-test-runner.d.ts +12 -1
  23. package/dist/support-tools/mcp-server/cli-test-runner.js +24 -19
  24. package/dist/support-tools/mcp-server/cli-test-runner.js.map +1 -1
  25. package/dist/support-tools/mcp-server/index.d.ts +10 -1
  26. package/dist/support-tools/mcp-server/index.js +12 -3
  27. package/dist/support-tools/mcp-server/index.js.map +1 -1
  28. package/dist/support-tools/roku-map-stack.d.ts +7 -0
  29. package/dist/support-tools/roku-map-stack.js +79 -0
  30. package/dist/support-tools/roku-map-stack.js.map +1 -0
  31. package/dist/support-tools/roku-stack-resolver.d.ts +1 -0
  32. package/dist/support-tools/roku-stack-resolver.js +53 -1
  33. package/dist/support-tools/roku-stack-resolver.js.map +1 -1
  34. package/package.json +42 -3
  35. package/dist/support-tools/extract-ci-config.d.ts +0 -5
  36. package/dist/support-tools/extract-ci-config.js +0 -70
  37. package/dist/support-tools/extract-ci-config.js.map +0 -1
  38. package/dist/support-tools/restore-debug-flags.d.ts +0 -26
  39. package/dist/support-tools/restore-debug-flags.js +0 -172
  40. 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-04T12:18:05+01:00",
3
+ "buildDateISO": "2026-06-04T11:18:05.597Z",
4
4
  "timeZone": "Europe/London",
5
- "gitHash": "de31d2c"
5
+ "gitHash": "4ea6b0e"
6
6
  }
package/dist/cli.js CHANGED
@@ -87,7 +87,7 @@ 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,
@@ -144,6 +144,38 @@ catch (err) {
144
144
  console.error('❌ Failed to resolve build config:', err);
145
145
  process.exit(1);
146
146
  }
147
+ })
148
+ .command('build-config:restore-secrets', 'Restore ignored build config secret overlays from BUILD_CONFIG_SECRETS_*_BASE64 environment variables', yargs => yargs
149
+ .option('out-dir', { type: 'string', describe: 'Output directory for secret overlays (default: secrets)' })
150
+ .option('env', { type: 'string', describe: 'Restore only one environment overlay, e.g. dev or prod' })
151
+ .option('profile', { type: 'string', describe: 'Restore only one profile overlay, e.g. george' })
152
+ .option('quiet', { type: 'boolean', default: false, describe: 'Reduce output' })
153
+ .example('$0 build-config:restore-secrets', 'Restore all build config secret overlays from the environment')
154
+ .example('$0 build-config:restore-secrets --env prod', 'Restore only BUILD_CONFIG_SECRETS_PROD_BASE64')
155
+ .epilog([
156
+ 'Environment variables:',
157
+ ' BUILD_CONFIG_SECRETS_<ENV>_BASE64 -> secrets/<env>.json',
158
+ ' BUILD_CONFIG_PROFILE_SECRETS_<PROFILE>_BASE64 -> secrets/profiles/<profile>.json',
159
+ 'Values must be base64-encoded JSON objects. Secret values are never printed.',
160
+ ].join('\n')), async (args) => {
161
+ if (args.verbose) {
162
+ process.env.HOSANNA_VERBOSE = '1';
163
+ process.env.HOSANNA_UPDATER_VERBOSE = '1';
164
+ }
165
+ try {
166
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/build-config-secrets.js')));
167
+ mod.restoreBuildConfigSecrets({
168
+ outDir: args['out-dir'],
169
+ env: args.env,
170
+ profile: args.profile,
171
+ quiet: Boolean(args.quiet),
172
+ });
173
+ process.exit(0);
174
+ }
175
+ catch (err) {
176
+ console.error('❌ Failed to restore build config secret overlays:', err);
177
+ process.exit(1);
178
+ }
147
179
  })
148
180
  .command(['version', 'v'], 'Print the version number', yargs => yargs, () => {
149
181
  console.log(buildVersion);
@@ -216,6 +248,41 @@ catch (err) {
216
248
  console.error('❌ Failed to publish Roku package:', err);
217
249
  process.exit(1);
218
250
  }
251
+ })
252
+ .command('roku:map-stack', 'Resolve Roku BrightScript stack traces or compile errors to original TypeScript locations using .brs.map files', yargs => yargs
253
+ .option('source-map-root', {
254
+ type: 'string',
255
+ default: 'platforms/roku/src',
256
+ describe: 'Path to packaged Roku source root containing .brs.map files, e.g. platforms/roku/src'
257
+ })
258
+ .option('file', {
259
+ type: 'string',
260
+ describe: 'Read stack trace text from a file instead of stdin'
261
+ })
262
+ .option('text', {
263
+ type: 'string',
264
+ describe: 'Resolve this stack trace text directly instead of stdin'
265
+ })
266
+ .example('pbpaste | $0 roku:map-stack --source-map-root platforms/roku/src', 'Resolve a pasted Roku crash or compiler log')
267
+ .example('$0 roku:map-stack --file crash.txt --source-map-root platforms/roku/src', 'Resolve stack trace text from a file')
268
+ .example('$0 roku:map-stack --text "file/line: pkg:/components/source_0.brs(7475)"', 'Resolve a single Roku backtrace line'), async (args) => {
269
+ if (args.verbose) {
270
+ process.env.HOSANNA_VERBOSE = '1';
271
+ }
272
+ try {
273
+ const mod = await Promise.resolve().then(() => __importStar(require('./support-tools/roku-map-stack.js')));
274
+ await mod.runRokuMapStackCommand({
275
+ sourceMapRoot: args['source-map-root'],
276
+ file: args.file,
277
+ text: args.text,
278
+ });
279
+ process.exit(0);
280
+ }
281
+ catch (err) {
282
+ const msg = err instanceof Error ? err.message : String(err);
283
+ console.error(`❌ Failed to map Roku stack trace: ${msg}`);
284
+ process.exit(1);
285
+ }
219
286
  })
220
287
  .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
288
  .option('ip', { type: 'string', describe: 'Roku device IP (env: ROKU_IP)' })
@@ -309,74 +376,6 @@ catch (err) {
309
376
  console.error('❌ Failed to create CI package:', err);
310
377
  process.exit(1);
311
378
  }
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
379
  })
381
380
  .command('secrets:list', 'Print secret key names from .secrets (values hidden). Use --template for .secrets.example', yargs => yargs
382
381
  .option('file', { type: 'string', describe: 'Path to .secrets (default: .secrets in cwd or git root)' })
@@ -532,7 +531,7 @@ catch (err) {
532
531
  }
533
532
  })
534
533
  .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)' })
534
+ .option('output-dir', { type: 'string', describe: 'Directory for cloud-agent.json build config profile (default: build-config/profiles)' })
536
535
  .option('start-debugger', { type: 'boolean', default: false, describe: 'Start command debugger in-process (non-blocking)' })
537
536
  .option('start-app', { type: 'boolean', default: false, describe: 'Spawn npm run dev detached and wait for Vite port' })
538
537
  .option('vite-port', { type: 'number', default: 5173, describe: 'Port to wait on when --start-app is set' })
@@ -1077,7 +1076,7 @@ catch (err) {
1077
1076
  process.env.HOSANNA_VERBOSE = '1';
1078
1077
  process.env.HOSANNA_UPDATER_VERBOSE = '1';
1079
1078
  }
1080
- return (0, cli_configure_hosanna_url_js_1.runConfigureHosannaUrl)(typeof args.gitUrl === 'string' ? args.gitUrl : undefined);
1079
+ (0, cli_configure_hosanna_url_js_1.runConfigureHosannaUrl)(typeof args.gitUrl === 'string' ? args.gitUrl : undefined);
1081
1080
  })
1082
1081
  .command('test:ui [recordings..]', 'Replay UI test recordings against a running Hosanna app and exit with pass/fail. ' +
1083
1082
  'Requires a running debug proxy (hst run:debugger) and a connected app.', yargs => yargs