@mondaydotcomorg/z2h-cli 0.34.1 → 0.34.2

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 (125) hide show
  1. package/CHANGELOG.md +2969 -0
  2. package/dist/backend/__tests__/ast.test.d.ts +2 -0
  3. package/dist/backend/__tests__/ast.test.d.ts.map +1 -0
  4. package/dist/backend/__tests__/parse.test.d.ts +2 -0
  5. package/dist/backend/__tests__/parse.test.d.ts.map +1 -0
  6. package/dist/backend/ast.d.ts +41 -0
  7. package/dist/backend/ast.d.ts.map +1 -0
  8. package/dist/backend/ast.js +152 -0
  9. package/dist/backend/handler-declaration.d.ts +17 -0
  10. package/dist/backend/handler-declaration.d.ts.map +1 -0
  11. package/dist/backend/handler-declaration.js +83 -0
  12. package/dist/backend/messages.d.ts +10 -0
  13. package/dist/backend/messages.d.ts.map +1 -0
  14. package/dist/backend/messages.js +14 -0
  15. package/dist/backend/parse.d.ts +11 -0
  16. package/dist/backend/parse.d.ts.map +1 -0
  17. package/dist/backend/parse.js +66 -0
  18. package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
  19. package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
  20. package/dist/backend/rules/index.d.ts +5 -0
  21. package/dist/backend/rules/index.d.ts.map +1 -0
  22. package/dist/backend/rules/index.js +8 -0
  23. package/dist/backend/rules/snowflake-static-sql.d.ts +15 -0
  24. package/dist/backend/rules/snowflake-static-sql.d.ts.map +1 -0
  25. package/dist/backend/rules/snowflake-static-sql.js +75 -0
  26. package/dist/backend/rules/types.d.ts +29 -0
  27. package/dist/backend/rules/types.d.ts.map +1 -0
  28. package/dist/backend/rules/types.js +1 -0
  29. package/dist/commands/__tests__/delete.test.d.ts +2 -0
  30. package/dist/commands/__tests__/delete.test.d.ts.map +1 -0
  31. package/dist/commands/backend.d.ts +0 -1
  32. package/dist/commands/backend.d.ts.map +1 -1
  33. package/dist/commands/backend.js +4 -4
  34. package/dist/commands/deploy.d.ts.map +1 -1
  35. package/dist/commands/deploy.js +7 -5
  36. package/dist/constants.d.ts +2 -1
  37. package/dist/constants.d.ts.map +1 -1
  38. package/dist/constants.js +12 -0
  39. package/dist/esm/backend/__tests__/ast.test.d.ts +2 -0
  40. package/dist/esm/backend/__tests__/ast.test.d.ts.map +1 -0
  41. package/dist/esm/backend/__tests__/parse.test.d.ts +2 -0
  42. package/dist/esm/backend/__tests__/parse.test.d.ts.map +1 -0
  43. package/dist/esm/backend/ast.d.ts +41 -0
  44. package/dist/esm/backend/ast.d.ts.map +1 -0
  45. package/dist/esm/backend/ast.mjs +146 -0
  46. package/dist/esm/backend/handler-declaration.d.ts +17 -0
  47. package/dist/esm/backend/handler-declaration.d.ts.map +1 -0
  48. package/dist/esm/backend/handler-declaration.mjs +78 -0
  49. package/dist/esm/backend/messages.d.ts +10 -0
  50. package/dist/esm/backend/messages.d.ts.map +1 -0
  51. package/dist/esm/backend/messages.mjs +12 -0
  52. package/dist/esm/backend/parse.d.ts +11 -0
  53. package/dist/esm/backend/parse.d.ts.map +1 -0
  54. package/dist/esm/backend/parse.mjs +64 -0
  55. package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
  56. package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
  57. package/dist/esm/backend/rules/index.d.ts +5 -0
  58. package/dist/esm/backend/rules/index.d.ts.map +1 -0
  59. package/dist/esm/backend/rules/index.mjs +6 -0
  60. package/dist/esm/backend/rules/snowflake-static-sql.d.ts +15 -0
  61. package/dist/esm/backend/rules/snowflake-static-sql.d.ts.map +1 -0
  62. package/dist/esm/backend/rules/snowflake-static-sql.mjs +73 -0
  63. package/dist/esm/backend/rules/types.d.ts +29 -0
  64. package/dist/esm/backend/rules/types.d.ts.map +1 -0
  65. package/dist/esm/backend/rules/types.mjs +1 -0
  66. package/dist/esm/commands/__tests__/delete.test.d.ts +2 -0
  67. package/dist/esm/commands/__tests__/delete.test.d.ts.map +1 -0
  68. package/dist/esm/commands/backend.d.ts +0 -1
  69. package/dist/esm/commands/backend.d.ts.map +1 -1
  70. package/dist/esm/commands/backend.mjs +4 -4
  71. package/dist/esm/commands/deploy.d.ts.map +1 -1
  72. package/dist/esm/commands/deploy.mjs +7 -5
  73. package/dist/esm/constants.d.ts +2 -1
  74. package/dist/esm/constants.d.ts.map +1 -1
  75. package/dist/esm/constants.mjs +5 -2
  76. package/dist/esm/util/__tests__/usage-upload.test.d.ts +2 -0
  77. package/dist/esm/util/__tests__/usage-upload.test.d.ts.map +1 -0
  78. package/dist/esm/util/auth/__tests__/index.test.d.ts +2 -0
  79. package/dist/esm/util/auth/__tests__/index.test.d.ts.map +1 -0
  80. package/dist/esm/util/auth/broker-credential-provider.d.ts +6 -1
  81. package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -1
  82. package/dist/esm/util/auth/broker-credential-provider.mjs +2 -2
  83. package/dist/esm/util/auth/index.d.ts +3 -0
  84. package/dist/esm/util/auth/index.d.ts.map +1 -0
  85. package/dist/esm/util/auth/index.mjs +2 -0
  86. package/dist/esm/util/broker/app.d.ts +0 -1
  87. package/dist/esm/util/broker/app.d.ts.map +1 -1
  88. package/dist/esm/util/broker/app.mjs +3 -4
  89. package/dist/esm/util/usage-json.d.ts +2 -2
  90. package/dist/esm/util/usage-json.d.ts.map +1 -1
  91. package/dist/esm/util/usage-json.mjs +5 -2
  92. package/dist/esm/util/usage-upload.d.ts +3 -0
  93. package/dist/esm/util/usage-upload.d.ts.map +1 -0
  94. package/dist/esm/util/usage-upload.mjs +29 -0
  95. package/dist/util/__tests__/usage-upload.test.d.ts +2 -0
  96. package/dist/util/__tests__/usage-upload.test.d.ts.map +1 -0
  97. package/dist/util/auth/__tests__/index.test.d.ts +2 -0
  98. package/dist/util/auth/__tests__/index.test.d.ts.map +1 -0
  99. package/dist/util/auth/broker-credential-provider.d.ts +6 -1
  100. package/dist/util/auth/broker-credential-provider.d.ts.map +1 -1
  101. package/dist/util/auth/broker-credential-provider.js +2 -2
  102. package/dist/util/auth/index.d.ts +3 -0
  103. package/dist/util/auth/index.d.ts.map +1 -0
  104. package/dist/util/auth/index.js +11 -0
  105. package/dist/util/broker/app.d.ts +0 -1
  106. package/dist/util/broker/app.d.ts.map +1 -1
  107. package/dist/util/broker/app.js +3 -4
  108. package/dist/util/usage-json.d.ts +2 -2
  109. package/dist/util/usage-json.d.ts.map +1 -1
  110. package/dist/util/usage-json.js +5 -2
  111. package/dist/util/usage-upload.d.ts +3 -0
  112. package/dist/util/usage-upload.d.ts.map +1 -0
  113. package/dist/util/usage-upload.js +31 -0
  114. package/package.json +3 -3
  115. package/src/commands/__tests__/backend-deploy.test.ts +2 -4
  116. package/src/commands/__tests__/deploy.test.ts +43 -11
  117. package/src/commands/backend.ts +4 -5
  118. package/src/commands/deploy.ts +9 -5
  119. package/src/constants.ts +6 -0
  120. package/src/util/__tests__/usage-upload.test.ts +58 -0
  121. package/src/util/auth/__tests__/broker-credential-provider.test.ts +4 -4
  122. package/src/util/auth/broker-credential-provider.ts +4 -4
  123. package/src/util/broker/app.ts +2 -15
  124. package/src/util/usage-json.ts +11 -4
  125. package/src/util/usage-upload.ts +38 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,2969 @@
1
+ # CHANGELOG
2
+
3
+ ## `0.34.1` (October 5, 2026, 13:41)
4
+
5
+ ### Improvements
6
+
7
+ - [#509](https://github.com/DaPulse/bigbrain-z2h/pull/509) refactor(z2h): move bucket and app-name constants to z2h-shared-utils (@eitan-ts)
8
+ - Changed: S3 bucket, manifest, skills, and app-name constants have been moved from direct definitions in `constants.ts` to re-exports from `@mondaydotcomorg/z2h-shared-utils`. The public API remains unchanged for existing imports like `import { BUCKET_WRITE_NAME } from '@mondaydotcomorg/z2h-cli/constants'`, but the source of truth now lives in the shared utils package.
9
+ *Before:*
10
+ ```ts
11
+ // In z2h-cli/constants.ts
12
+ export const BUCKET_WRITE_NAME = 'prod-use1-bigbrain-zth-mf-assets';
13
+ export const REGION = 'us-east-1';
14
+ // ... other constants defined here
15
+ ```
16
+ *After:*
17
+ ```ts
18
+ // In z2h-cli/constants.ts
19
+ export {
20
+ BUCKET_WRITE_NAME,
21
+ REGION,
22
+ // ... other constants re-exported from shared utils
23
+ } from '@mondaydotcomorg/z2h-shared-utils';
24
+ ```
25
+ - Changed: The following constants are now re-exported from `@mondaydotcomorg/z2h-shared-utils`: `BUCKET_WRITE_NAME`, `REGION`, `BUCKET_WRITE_URL`, `BUCKET_READ_DNS_NAME`, `BUCKET_READ_DNS_URL`, `S3_PREVIEWS_FOLDER`, `MANIFEST_KEY`, `MANIFEST_READ_URL`, `S3_SKILLS_BUCKET_NAME`, `DATAVIZ_SKILLS_PREFIX`, `APP_NAME_PATTERN`, and `PREVIEW_APP_NAME_PREFIX`. Existing imports from `@mondaydotcomorg/z2h-cli/constants` continue to work unchanged.
26
+ - Removed: Direct definitions of bucket configuration constants, manifest paths, skills bucket configuration, and app name validation patterns from the CLI package. These values remain accessible via the same import paths but are now maintained in the shared utils package.
27
+
28
+ ### Dependency Upgrades
29
+
30
+ - Upgrade `z2h-shared-utils` version
31
+ - Upgrade `dashboard-templates` version
32
+
33
+ ## `0.34.0` (October 5, 2026, 12:54)
34
+
35
+ ### New Features
36
+
37
+ - [#504](https://github.com/DaPulse/bigbrain-z2h/pull/504) feat(z2h): expose the template catalog over the API [prerelease] (@chezkibotwinick)
38
+ - Added: New public export `dashboard-templates` module exposing template catalog utilities. The module exports `loadDashboardTemplatesCatalog()` (loads the bundled template catalog), `findTemplate()` (finds a specific template by ID), and the `DashboardTemplateEntry` type.
39
+ *Usage:*
40
+ ```ts
41
+ import { loadDashboardTemplatesCatalog, findTemplate } from '@mondaydotcomorg/z2h-cli/dashboard-templates';
42
+ const catalog = loadDashboardTemplatesCatalog();
43
+ const template = findTemplate('template-id');
44
+ ```
45
+ This allows the backend service to read the same catalog data that the CLI uses without invoking the CLI entry point.
46
+ - Changed: Updated the `templates` command description to reference "config schema" instead of "widget schema" for clarity and consistency with the API nomenclature.
47
+
48
+ ## `0.33.4` (October 4, 2026, 13:07)
49
+
50
+ ### Bug Fixes
51
+
52
+ - [#501](https://github.com/DaPulse/bigbrain-z2h/pull/501) fix(z2h-cli): deploy commits usage.json before pushing (@eitan-ts)
53
+ - Fixed: `z2h-cli deploy` now commits `usage.json` before pushing to the remote repository, preventing "uncommitted changes" errors on subsequent deploys. Previously, the file was written after the push, leaving the working tree dirty.
54
+ - Added: New utility function `updateOrCreateUsageJson(appDir: string, appName: string, deployedBy: string): Promise<void>` in `util/usage-json.ts` that refreshes the git-tracked `usage.json` file, stages it, and commits it only if it changed.
55
+ ```ts
56
+ import { updateOrCreateUsageJson } from '@mondaydotcomorg/z2h-cli/util/usage-json';
57
+
58
+ // Creates or updates usage.json, stages it, and commits if changed
59
+ await updateOrCreateUsageJson(process.cwd(), 'my-app', 'user@example.com');
60
+ ```
61
+ - Changed: The `deploy` command now calls `updateOrCreateUsageJson()` immediately after `pullAndResolve()` in the git error handling block, ensuring the usage.json update is included in the regular push operation.
62
+ - Changed: Backend upload operations no longer write `usage.json` during deploy. The `readDetectAndUpload` function in `backend.ts` removed its `writeUsageJson()` calls that previously wrote the file after handler parsing.
63
+ - Changed: Refactored usage.json utilities into a dedicated module. Functions `hasHandlers()` and `writeUsageJson()` moved from `commands/backend.ts` to `util/usage-json.ts` and are now exported for broader use.
64
+ ```ts
65
+ // Before: only available within backend.ts
66
+ // After: importable from util module
67
+ import { hasHandlers, writeUsageJson } from '@mondaydotcomorg/z2h-cli/util/usage-json';
68
+
69
+ if (hasHandlers(appDir)) {
70
+ await writeUsageJson(appDir, { appName, deployedBy, apiUsages });
71
+ }
72
+ ```
73
+ - Changed: The `execGit` helper function in `util/git/repo.ts` is now exported and available for use in other modules. Previously it was an internal function only.
74
+ ```ts
75
+ import { execGit } from '@mondaydotcomorg/z2h-cli/util/git/repo';
76
+
77
+ // Now usable in other modules
78
+ await execGit(['add', 'usage.json'], appDir);
79
+ ```
80
+ - Changed: Preview deploys are unaffected by this change and continue to skip usage.json updates entirely.
81
+
82
+ ## `0.33.3` (October 1, 2026, 13:00)
83
+
84
+ ### Bug Fixes
85
+
86
+ - [#494](https://github.com/DaPulse/bigbrain-z2h/pull/494) fix(z2h-cli): track only opted-in commands under enum event names (@arielmonday)
87
+ - **Breaking**: Removed the `track` field from `CommandSpec<A>`. Commands now opt into success event tracking by providing an `event` field; omit `event` to skip success tracking. Failures are still reported via `z2h_cli_error` whether or not the command tracks success.
88
+ *Before:*
89
+ ```ts
90
+ runCommand({ track: false }, () => myCommand())
91
+ ```
92
+ *After:*
93
+ ```ts
94
+ // No success event sent, failures still reported
95
+ runCommand({}, () => myCommand())
96
+ ```
97
+ - **Breaking**: The `event` field in `CommandSpec<A>` is now typed as `PerArgs<A, Z2hCliEventName>` instead of `PerArgs<A, string>`. Event names must be values from the `Z2hCliEvents` enum exported by `@mondaydotcomorg/z2h-shared-utils/observability`.
98
+ *Before:*
99
+ ```ts
100
+ runCommand({ event: 'z2h_cli_deploy_success' }, () => deployCommand())
101
+ ```
102
+ *After:*
103
+ ```ts
104
+ import { Z2hCliEvents } from '@mondaydotcomorg/z2h-shared-utils/observability';
105
+ runCommand({ event: Z2hCliEvents.deploySuccess }, () => deployCommand())
106
+ ```
107
+ - Removed the `successEvent(command: string): string` helper function from `util/tracker.ts`. Use enum values from `Z2hCliEvents` directly instead.
108
+ - Changed how command names are derived in `runCommand()`: top-level commands no longer include the root program name (`z2h-cli`). A top-level command is now labeled `create` instead of `z2h-cli create`, and a nested command is `backend invoke` instead of `z2h-cli backend invoke`. This affects the `action` dimension in telemetry and error messages.
109
+ - Commands that no longer send success events: `clean`, `create-workspace`, `doctor`, `tag`, `backend invoke`, `backend validate`, `grant`, `revoke`, `transfer-owner`, `migrate`, `generate-z2h-token`, `custom-integration:*`, `llm-migration`. Their failures still send `z2h_cli_error` events.
110
+ - Updated all tracked commands to use typed event names from `Z2hCliEvents`: `deploy` → `z2h_app_deploy_success`, `deploy --preview` → `z2h_app_preview_success`, `create` → `z2h_app_created`, `build` → `z2h_app_build_success`, `edit` → `z2h_app_edit_pulled`, `delete` → `z2h_app_delete_success`, `templates` → `z2h_cli_templates_success`, `generate-app-template` → `z2h_cli_generate_app_template_success`.
111
+ - Parser errors in `backend/parser/parse.ts` now use `Z2hCliEvents.handlerParseError` constant instead of the string literal `'z2h_cli_handler_parse_error'`.
112
+ - The `build` command now sends a success event (`z2h_app_build_success`) but continues to skip error events for failures tagged `build_error` (consumer code failures, not CLI/infra problems).
113
+
114
+ ### Dependency Upgrades
115
+
116
+ - Upgrade `z2h-shared-utils` version
117
+ - Upgrade `dashboard-templates` version
118
+
119
+ ## `0.33.2` (October 1, 2026, 08:17)
120
+
121
+ ### Improvements
122
+
123
+ - [#487](https://github.com/DaPulse/bigbrain-z2h/pull/487) feat(z2h): store handlerNames and capped apiUsages on the apps table (@eitan-ts)
124
+ - Changed: The `deployBackend` function now returns a `ReadDetectAndUploadResult` object containing `integrations`, `handlerNames`, and `apiUsages` instead of returning only an array of integrations.
125
+ *Before:*
126
+ ```ts
127
+ const integrations = await deployBackend({ ... });
128
+ ```
129
+ *After:*
130
+ ```ts
131
+ const { integrations, handlerNames, apiUsages } = await deployBackend({ ... });
132
+ ```
133
+ - Added: The `ReadDetectAndUploadResult` interface is now exported from `backend.ts`, providing structured access to backend deployment metadata including detected integrations, handler function names, and API usage analytics.
134
+ - Changed: The `registerOrUpdateApp` function now accepts `handlerNames` and `apiUsages` as optional fields in its `RegisterOrUpdateOptions` parameter. These fields are passed through to the backend broker endpoints for storage in the apps table.
135
+ *Updated interface:*
136
+ ```ts
137
+ export interface RegisterOrUpdateOptions {
138
+ appName: string;
139
+ token: string;
140
+ nextVersion: number;
141
+ entry: ManifestEntry;
142
+ gitRemote: string;
143
+ integrations?: string[];
144
+ handlerNames?: string[]; // New field
145
+ apiUsages?: Record<string, unknown>; // New field
146
+ description?: string;
147
+ masterAppName?: string;
148
+ }
149
+ ```
150
+ - Changed: The deploy process now executes backend deployment before frontend upload, ensuring that if the backend step fails, the preview's unversioned MF directory is not left in an inconsistent state.
151
+ - Added: Preview deployments that fail after the backend has already been deployed now emit a warning instructing users to re-run `z2h-cli deploy --preview` to retry, clarifying that every step is an idempotent overwrite that will repair any partial state.
152
+ - Changed: The `readDetectAndUpload` internal function now writes `usage.json` with `apiUsages` data even when no handlers are present (writing an empty object), ensuring consistent usage tracking across all deployment scenarios.
153
+ - Changed: Backend handler names are now extracted and returned from `readDetectAndUpload` as a dedicated `handlerNames` array (derived from `Object.keys(handlers)`), enabling future prompt-to-app matching capabilities.
154
+ - Changed: The `registerApp` and `updateApp` internal functions now accept a single params object conforming to `RegisterOrUpdateOptions` instead of individual parameters, simplifying the function signatures and ensuring consistent parameter passing throughout the registration flow.
155
+
156
+ ## `0.33.1` (September 30, 2026, 09:49)
157
+
158
+ ### Improvements
159
+
160
+ - [#488](https://github.com/DaPulse/bigbrain-z2h/pull/488) feat(z2h): sandbox run — backend invoke runs the local handler before deploy (@EranZidkiya)
161
+ - **Breaking Change**: The `backend invoke` command now runs handler source from the working tree against real channels (database, monday API, Snowflake) without deploying, instead of invoking the deployed handler. The command validates the local handler source first and prints a detailed trace of every channel call made during execution.
162
+ *Before (v0.32.x):*
163
+ ```bash
164
+ z2h-cli backend invoke get_kpis --input '{"since":"2026-01-01"}'
165
+ # Invoked the deployed handler on the backend
166
+ ```
167
+ *After (v0.33.0):*
168
+ ```bash
169
+ z2h-cli backend invoke get_kpis --input '{"since":"2026-01-01"}'
170
+ # Runs backend/handlers/get_kpis.js from your working directory
171
+ # Prints trace showing each channel call, duration, and result
172
+ ```
173
+ - Added: The `backend invoke` command now accepts a `--code <source>` option to run inline handler source instead of reading from a file, useful for testing snippets without creating a handler file.
174
+ *Usage:*
175
+ ```bash
176
+ z2h-cli backend invoke scratch --code 'async function handler(ctx) {
177
+ return ctx.api.v1.snowflake.query("SELECT CURRENT_USER() AS u");
178
+ }'
179
+ ```
180
+ - Changed: The `backend invoke` command now exits with code 1 when the handler fails (e.g., channel error, timeout, isolate error), allowing scripts to detect failures.
181
+ - Changed: The output format for `backend invoke` now includes a human-readable trace showing each channel call with method name, duration, row count, and success/failure status, instead of only showing the final result.
182
+ - **Breaking Change**: Removed the `invokeBackend` function from `src/backend/client.ts`. Replaced with `runSandbox(appName, body)` which accepts `SandboxRunRequest` containing `code`, `input`, and optional `handlerName`.
183
+ *Before:*
184
+ ```typescript
185
+ import { invokeBackend } from './backend/client';
186
+ const res = await invokeBackend(appName, handlerName, input);
187
+ // res: { result: unknown; durationMs: number }
188
+ ```
189
+ *After:*
190
+ ```typescript
191
+ import { runSandbox } from './backend/client';
192
+ const res = await runSandbox(appName, { code, input, handlerName });
193
+ // res: { ok: boolean; error?: {...}; calls: SandboxCall[]; result: unknown; durationMs: number }
194
+ ```
195
+ - **Breaking Change**: Renamed the `InvokeResponse` interface to `SandboxRunResponse` and added new fields: `ok` (boolean), `error` (optional object with `status`, `code`, `message`), and `calls` (array of `SandboxCall` objects tracing each channel method invoked).
196
+ - Added: New `SandboxRunRequest` interface for sandbox run requests with fields `code` (string), `input` (unknown), and optional `handlerName` (string).
197
+ - Added: New `SandboxCall` interface representing a traced channel call, with fields `method`, `args`, `durationMs`, `ok`, optional `error`, and optional `result`.
198
+ - Added: New `formatSandboxRun` function in `src/backend/format-sandbox-run.ts` that formats a `SandboxRunResponse` into a human-readable trace with call details, durations, row counts, and error messages.
199
+ - Changed: The `backend invoke` command description now states it runs handlers from the working tree (not deployed handlers) against real channels and prints a trace, exiting 1 on failure.
200
+ - Added: Local validation of handler source before sending to the sandbox endpoint, using the same `validateHandlerSource` check that the deploy command uses.
201
+ - Changed: The CLI now respects `process.exitCode` set by commands and exits with that code, allowing commands to signal non-zero exit status without throwing errors.
202
+
203
+ ### Dependency Upgrades
204
+
205
+ - Upgrade `z2h-shared-utils` version
206
+ - Upgrade `dashboard-templates` version
207
+
208
+ ## `0.33.0` (September 30, 2026, 03:58)
209
+
210
+ ### New Features
211
+
212
+ - [#480](https://github.com/DaPulse/bigbrain-z2h/pull/480) Feat/yarin/custom pat channel 4 cli (@yarinmonday)
213
+ - Added: New `custom-integration:list` command that displays all custom integrations registered for the current app. The command shows each integration's name, allowed host, auth header name, and whether it is inherited from a base app.
214
+ *Usage:*
215
+ ```bash
216
+ z2h-cli custom-integration:list
217
+ ```
218
+ *Output example:*
219
+ ```
220
+ [z2h-cli] "mf-my-app" custom integrations:
221
+ stripe → api.stripe.com (X-Stripe-Auth) [inherited from base app]
222
+ ```
223
+ - Added: New `custom-integration:remove <name>` command that removes a registered custom integration from the current app by name.
224
+ *Usage:*
225
+ ```bash
226
+ z2h-cli custom-integration:remove stripe
227
+ ```
228
+ - Added: New `CustomIntegrationSummary` interface exported from `src/commands/custom-integrations.ts` with fields: `name`, `allowedHost`, `authHeaderName`, `authScheme`, `createdBy`, `createdAt`, `updatedAt`, and optional `inherited` boolean.
229
+ - Changed: Reserved app name list now includes `'set-custom-integration'` in addition to `'generate-z2h-token'`, preventing users from creating apps with this platform-reserved route name.
230
+ - Changed: The `masterAppName` field in `RegisterOrUpdateOptions` interface documentation now clarifies that it links preview apps to their base apps for custom integration inheritance. The field is only required on first registration and is immutable thereafter.
231
+
232
+ ### Dependency Upgrades
233
+
234
+ - Upgrade `z2h-shared-utils` version
235
+ - Upgrade `dashboard-templates` version
236
+
237
+ ## `0.32.2` (September 29, 2026, 10:46)
238
+
239
+ ### Dependency Upgrades
240
+
241
+ - Upgrade `dashboard-templates` version
242
+
243
+ ## `0.32.1` (September 28, 2026, 14:07)
244
+
245
+ ### Bug Fixes
246
+
247
+ - [#475](https://github.com/DaPulse/bigbrain-z2h/pull/475) ci(z2h-cli): fix zth-cli-e2e OOM by right-sizing the runner (@eitan-ts)
248
+
249
+ ## `0.32.0` (September 28, 2026, 10:17)
250
+
251
+ ### New Features
252
+
253
+ - [#472](https://github.com/DaPulse/bigbrain-z2h/pull/472) feat(z2h-cli): LLM-guided migrations (type: llm) + z2h:migrate skill (@eitan-ts)
254
+ - Added: New `llm-migration` CLI command for listing and retrieving agent-guided (LLM) migrations. Run without arguments to list all available LLM migrations with their descriptions, or use `--migration <name>` to print the full markdown guide for a specific migration.
255
+ *Usage:*
256
+ ```bash
257
+ z2h-cli llm-migration # list all LLM migrations
258
+ z2h-cli llm-migration --migration <name> # print guide for specific migration
259
+ z2h-cli llm-migration --migration snowflake-service-to-backend-runner
260
+ ```
261
+
262
+ - Added: First LLM migration guide `snowflake-service-to-backend-runner` for migrating Z2H consumer apps from deprecated direct `bigbrain-zth /snowflake/query` fetches to `zth-backend-runner` handlers using `ctx.api.v1.snowflake`. The 168-line markdown guide includes detection instructions (grep for `/snowflake/query` in `src/`), the old vs new pattern, handler creation rules, frontend call-site rewrites for both React and html-embed apps, parameterization requirements, and three-step verification (handler validation, build check, collision detection).
263
+
264
+ - Added: New shared utility module `src/util/migrations-json.ts` defining the migration type system. Exports `DeterministicMigrationEntry` (deterministic Nx-tree migrations with `version`, `description`, `migrate` script path) and `LlmMigrationEntry` (agent-guided migrations with `type: "llm"`, `version`, `description`, `guide` markdown path). The `resolveMigrationsJson()` function locates `migrations.json` via `require.resolve('@mondaydotcomorg/z2h-cli/package.json')`.
265
+ *Type definitions:*
266
+ ```typescript
267
+ interface DeterministicMigrationEntry {
268
+ type?: never;
269
+ version: string; // CLI release version
270
+ description: string;
271
+ migrate: string; // path to migration script
272
+ }
273
+
274
+ interface LlmMigrationEntry {
275
+ type: 'llm';
276
+ version: string; // CLI version migration was added
277
+ description: string;
278
+ guide: string; // path to markdown guide
279
+ }
280
+ ```
281
+
282
+ - Changed: The `migrate` command now filters out LLM migrations (`type: "llm"`) before the semver gate, as LLM migrations have no state file and are idempotent by design (detection is re-run each time). Only deterministic migrations are processed by the existing migration runner.
283
+
284
+ - Changed: Migration resolution logic refactored to use the shared `resolveMigrationsJson()` utility instead of inline path resolution, ensuring consistent migrations.json discovery across both `migrate` and `llm-migration` commands.
285
+
286
+ ## `0.31.0` (September 27, 2026, 11:32)
287
+
288
+ ### New Features
289
+
290
+ - [#442](https://github.com/DaPulse/bigbrain-z2h/pull/442) feat(z2h): AST handler validation + usage.json apiUsages metadata (@eitan-ts)
291
+ - Changed: AST parsing utilities moved from `src/backend/ast.ts` to a new `src/backend/parser/` directory with modular organization. The legacy `ast.ts` file was removed entirely. Code that imported from `./ast` should now import from `./parser/api-usage`, `./parser/bindings`, `./parser/member-path`, etc.
292
+
293
+ - Added: `collectApiUsages` function in `parser/api-usage.ts` captures every `ctx.api.v1.<domain>.<method>(...)` call site with per-argument metadata. Arguments are resolved to static values when possible (string literals, template literals, object/array literals, const references), otherwise recorded as source text. Example captured usage:
294
+ ```ts
295
+ // Handler source:
296
+ ctx.api.v1.snowflake.query('SELECT * FROM users WHERE id = ?', [userId]);
297
+
298
+ // Captured in apiUsages:
299
+ {
300
+ "snowflake": {
301
+ "query": [
302
+ {
303
+ "sql": "SELECT * FROM users WHERE id = ?",
304
+ "params": "[userId]"
305
+ }
306
+ ]
307
+ }
308
+ }
309
+ ```
310
+
311
+ - Added: `staticValue` function in `parser/static-value.ts` resolves AST nodes to JSON-serializable values. Supports literals, template literals with interpolation, object/array expressions, binary `+` for string concatenation, conditional expressions (recorded as `{ $or: [branch1, branch2] }`), and const variable references with alias following.
312
+
313
+ - Added: Scope-aware binding resolution. `collectBindings` in `parser/bindings.ts` now tracks the lexical scope of each declaration (function body, block statement, etc.). `declarationAt(bindings, name, position)` returns the innermost declaration visible at a given source position, enabling correct alias resolution when names are shadowed.
314
+
315
+ - Changed: `validateHandlerSource` return type now includes `apiUsages`. Migration:
316
+ *Before:*
317
+ ```ts
318
+ const { apiDomains } = validateHandlerSource(file, source);
319
+ ```
320
+ *After:*
321
+ ```ts
322
+ const { apiDomains, apiUsages } = validateHandlerSource(file, source);
323
+ ```
324
+
325
+ - Changed: `readHandlers` return type (`ReadHandlersResult`) now includes `apiUsages: Record<string, ApiUsage>`, a map from handler name to its API usage metadata. Migration:
326
+ *Before:*
327
+ ```ts
328
+ const { handlers, apiDomains } = await readHandlers(appDir);
329
+ ```
330
+ *After:*
331
+ ```ts
332
+ const { handlers, apiDomains, apiUsages } = await readHandlers(appDir);
333
+ ```
334
+
335
+ - Added: `usage.json` file lifecycle. New apps created via `z2h-cli create` are seeded with an empty `usage.json`. The file is updated by `z2h-cli backend validate` and `z2h-cli deploy` with `{ appName, deployedBy, apiUsages }`. During deploy, the CLI merges the new metadata into the existing local `usage.json` (preserving fields added by other features) and uploads the merged result to S3, but never writes the merged copy back to disk (to avoid dirtying the git tree post-commit).
336
+
337
+ - Added: `writeUsageJson` helper function in `commands/backend.ts` merges new metadata into the app's existing `usage.json` without replacing other top-level fields. Example:
338
+ ```ts
339
+ // Existing usage.json: { "customField": 123 }
340
+ await writeUsageJson(appDir, { appName: 'my-app', deployedBy: 'alice', apiUsages: {...} });
341
+ // Result on disk: { "customField": 123, "appName": "my-app", "deployedBy": "alice", "apiUsages": {...} }
342
+ ```
343
+
344
+ - Added: `loadApiSignatures` function in `parser/api-signatures.ts` reads `handler-api/signatures.json` (generated at build time from runner channel docs). Signatures provide parameter names for `ctx.api.v1.<domain>.<method>` calls, so captured usage keys are human-readable (`sql`, `params`) instead of positional (`arg0`, `arg1`).
345
+
346
+ - Added: `whoAmI` function in `util/machine-identity.ts` returns `process.env.APP_NAME` (for service accounts) or `os.userInfo().username` (for human users). Replaces the inline `whoDeployed` function previously in `commands/deploy.ts`.
347
+
348
+ - Changed: `collectBindings` now tracks function parameters and catch clause bindings as declarations with `kind: 'param'`. Parameters are marked in the `unpinnable` set (never followed as stable aliases), and their scope is recorded (the function body or catch block where they are visible).
349
+
350
+ - Changed: `createPathResolver` now accepts a source position when resolving identifiers, enabling correct shadowing: `const x = 1; function f() { const x = 2; return x; }` resolves the inner `x` to `2`, not `1`.
351
+
352
+ - Added: `memberChain` utility in `parser/utils.ts` extracts the root identifier and property path from `a.b.c` / `a['b'].c` expressions, returning `{ root: 'a', parts: ['b', 'c'] }`. Returns `undefined` if any property access is computed from a non-literal (dynamic access).
353
+
354
+ - Added: `patternBindings` utility in `parser/utils.ts` recursively extracts all identifier bindings from a destructuring pattern with their property paths. Example: `const { api: { v1: sf } } = ctx` produces `[{ name: 'sf', path: ['api', 'v1'] }]`.
355
+
356
+ - Added: `parseOrThrow` function in `parser/parse.ts` validates handler source as a script (the grammar the runner uses) and produces contextual error messages when module-only syntax is detected. Distinguishes "handler is exported" (forbidden) from "handler uses top-level await" (also forbidden), improving DX for agent-generated code.
357
+
358
+ - Added: `findHandlerDeclaration` and `handlerContextParamName` functions in `parser/handler-declaration.ts` locate the top-level `handler` binding and extract its first parameter name (if it's a plain identifier), enabling alias-aware `ctx` tracking (`handler(context) { context.api.v1... }` resolves as `ctx.api.v1...`).
359
+
360
+ - Changed: Handler files in `backend/handlers/` are now processed in sorted order (lexicographic by filename) instead of `readdir()` order, ensuring `usage.json` key order is deterministic across machines and deploys.
361
+
362
+ - Changed: `backendValidateCommand` now updates the local `usage.json` with current `apiUsages`, `appName` (from `package.json`), and `deployedBy` (the current user). Previously it only validated syntax; now it refreshes metadata as a side effect.
363
+
364
+ - Added: Template file `src/templates/app/usage.json` containing `{}`, copied to new apps by `z2h-cli create`.
365
+
366
+ - Removed: Inline `whoDeployed` function in `commands/deploy.ts`. Replaced by `whoAmI` from `util/machine-identity.ts`.
367
+
368
+ ## `0.30.0` (September 24, 2026, 09:13)
369
+
370
+ ### New Features
371
+
372
+ - [#440](https://github.com/DaPulse/bigbrain-z2h/pull/440) Feat/yarin/z2h populate preview master id and enforce (@yarinmonday)
373
+ - Added: Preview deployments now require the master app to exist before deploying. The `deployPreview` function validates that the parent app has been created or deployed at least once, throwing a `DeployError` with actionable guidance (`z2h-cli create <name>` or deploy once) if the master app is missing. This prevents confusing backend 404 errors when previewing apps that were scaffolded locally but never claimed in the registry.
374
+
375
+ - Changed: The `uploadAndRegister` internal function now accepts a `masterAppName` optional parameter to link preview apps to their parent app during registration.
376
+ *Before:*
377
+ ```typescript
378
+ async function uploadAndRegister(opts: {
379
+ paths: Paths;
380
+ keyPrefix: string;
381
+ appName: string;
382
+ token: string;
383
+ nextVersion: number;
384
+ entry: string;
385
+ gitRemote: string;
386
+ isPreview: boolean;
387
+ description?: string;
388
+ }): Promise<void>
389
+ ```
390
+ *After:*
391
+ ```typescript
392
+ async function uploadAndRegister(opts: {
393
+ paths: Paths;
394
+ keyPrefix: string;
395
+ appName: string;
396
+ token: string;
397
+ nextVersion: number;
398
+ entry: string;
399
+ gitRemote: string;
400
+ isPreview: boolean;
401
+ description?: string;
402
+ masterAppName?: string;
403
+ }): Promise<void>
404
+ ```
405
+
406
+ - Changed: The `registerApp` internal function now accepts a `masterAppName` optional parameter, which is included in the registration request payload sent to the broker API.
407
+ *Before:*
408
+ ```typescript
409
+ async function registerApp(
410
+ appName: string,
411
+ token: string,
412
+ version: number,
413
+ entry: string,
414
+ visibility: 'public' | 'private',
415
+ gitRemote: string,
416
+ integrations?: string[],
417
+ description?: string
418
+ ): Promise<void>
419
+ ```
420
+ *After:*
421
+ ```typescript
422
+ async function registerApp(
423
+ appName: string,
424
+ token: string,
425
+ version: number,
426
+ entry: string,
427
+ visibility: 'public' | 'private',
428
+ gitRemote: string,
429
+ integrations?: string[],
430
+ description?: string,
431
+ masterAppName?: string
432
+ ): Promise<void>
433
+ ```
434
+
435
+ - Changed: The `RegisterOrUpdateOptions` interface now includes an optional `masterAppName` field to specify the parent app when registering a preview app for the first time. This field is ignored for version updates beyond v1.
436
+ *Before:*
437
+ ```typescript
438
+ export interface RegisterOrUpdateOptions {
439
+ appName: string;
440
+ token: string;
441
+ nextVersion: number;
442
+ entry: string;
443
+ gitRemote: string;
444
+ integrations?: string[];
445
+ description?: string;
446
+ }
447
+ ```
448
+ *After:*
449
+ ```typescript
450
+ export interface RegisterOrUpdateOptions {
451
+ appName: string;
452
+ token: string;
453
+ nextVersion: number;
454
+ entry: string;
455
+ gitRemote: string;
456
+ integrations?: string[];
457
+ description?: string;
458
+ /** For a preview app's first registration, the real app it previews. Ignored past v1. */
459
+ masterAppName?: string;
460
+ }
461
+ ```
462
+
463
+ - Changed: The `registerOrUpdateApp` function now threads the `masterAppName` parameter through to `registerApp` when registering version 1 of a preview app, enabling server-side resolution of preview-to-master relationships.
464
+
465
+ - Changed: The `deployPreview` workflow now passes `masterAppName: appName` when calling `uploadAndRegister`, linking the preview app to its parent in the registry.
466
+
467
+ - Changed: The `generateCommand` now claims the app name in the Z2H registry (via `claimApp`) immediately after validation if the app doesn't already exist. This ensures the app row exists server-side so that subsequent preview deployments can resolve the parent app by name, matching the behavior of the normal `create` flow.
468
+
469
+ ## `0.29.5` (September 23, 2026, 13:04)
470
+
471
+ ### Dependency Upgrades
472
+
473
+ - Upgrade `dashboard-templates` version
474
+
475
+ ## `0.29.4` (September 22, 2026, 14:11)
476
+
477
+ ### Dependency Upgrades
478
+
479
+ - Upgrade `dashboard-templates` version
480
+
481
+ ## `0.29.3` (September 17, 2026, 10:56)
482
+
483
+ ### Dependency Upgrades
484
+
485
+ - Upgrade `z2h-shared-utils` version
486
+ - Upgrade `dashboard-templates` version
487
+
488
+ ## `0.29.2` (September 17, 2026, 09:12)
489
+
490
+ ### Bug Fixes
491
+
492
+ - [#452](https://github.com/DaPulse/bigbrain-z2h/pull/452) refactor(z2h-cli): remove snowflake static-SQL handler rule (@eitan-ts)
493
+ - Removed: The `lineOf` utility function from `src/backend/ast.ts` has been deleted. This function previously returned the 1-based line number where an AST node starts.
494
+ *Before:*
495
+ ```ts
496
+ import { lineOf } from '@mondaydotcomorg/z2h-cli/backend/ast';
497
+ const line = lineOf(node); // number | undefined
498
+ ```
499
+ *After:*
500
+ ```ts
501
+ // lineOf is no longer exported; use node.loc?.start.line directly
502
+ const line = node.loc?.start.line;
503
+ ```
504
+ - Removed: The entire `rules/` module has been deleted, eliminating the handler validation rules system. The following exports are no longer available: `HandlerRule` interface, `RuleContext` interface, and `HANDLER_RULES` array from `src/backend/rules/index.ts`.
505
+ *Before:*
506
+ ```ts
507
+ import { HANDLER_RULES, type HandlerRule } from '@mondaydotcomorg/z2h-cli/backend/rules';
508
+ ```
509
+ *After:*
510
+ ```ts
511
+ // The rules module no longer exists; these types and constants are unavailable
512
+ ```
513
+ - Removed: The `SnowflakeStaticSqlRule` class that enforced static SQL strings in `ctx.api.v1.snowflake.query()` calls has been removed from `src/backend/rules/snowflake-static-sql.ts`. Handler validation no longer checks whether SQL is static (authored in the handler file) versus dynamic (client-supplied).
514
+ - Changed: The `validateHandlerSource` function in `src/backend/validate.ts` no longer runs capability-specific rules after structural validation. It now only validates that the handler is syntactically valid, defines a `handler` export, and contains no imports. Previously, it would iterate through `HANDLER_RULES` and throw an error if any violations were found.
515
+ *Before:*
516
+ ```ts
517
+ // validateHandlerSource would throw if SQL was not static
518
+ validateHandlerSource('handler.ts', 'export const handler = (ctx) => ctx.api.v1.snowflake.query(ctx.input.sql)');
519
+ // Error: handler.ts:1: ctx.api.v1.snowflake.query must receive SQL written in the handler...
520
+ ```
521
+ *After:*
522
+ ```ts
523
+ // validateHandlerSource only checks structure, not capability rules
524
+ validateHandlerSource('handler.ts', 'export const handler = (ctx) => ctx.api.v1.snowflake.query(ctx.input.sql)');
525
+ // { valid: true, warnings: [] } — no rule enforcement
526
+ ```
527
+
528
+ ## `0.29.1` (September 16, 2026, 12:43)
529
+
530
+ ### Dependency Upgrades
531
+
532
+ - Upgrade `z2h-shared-utils` version
533
+ - Upgrade `dashboard-templates` version
534
+
535
+ ## `0.29.0` (September 16, 2026, 11:36)
536
+
537
+ ### New Features
538
+
539
+ - [#434](https://github.com/DaPulse/bigbrain-z2h/pull/434) Feat/yarin/z2h claim app name (@yarinmonday)
540
+ - Added: New `claimApp(appName: string, gitRemote: string)` function in `util/broker/app.ts` to reserve an app name before the first deployment. This function makes a POST request to `/z2h-cli/apps/claim` and is idempotent from the caller's perspective. It throws an error if the claim fails (e.g., name already taken by another user).
541
+ ```ts
542
+ // New function signature:
543
+ export async function claimApp(appName: string, gitRemote: string): Promise<void>
544
+ ```
545
+
546
+ - Changed: `AppInfo` interface in `util/broker/app.ts` now includes a `deployed` boolean field indicating whether the app has been published, and the `entry` field can now be `null` for claimed-but-unpublished apps.
547
+ *Before:*
548
+ ```ts
549
+ export interface AppInfo {
550
+ appName: string;
551
+ version: number;
552
+ entry: Record<string, unknown>;
553
+ deployedBy: string;
554
+ gitRemote: string;
555
+ createdBy: string;
556
+ }
557
+ ```
558
+ *After:*
559
+ ```ts
560
+ export interface AppInfo {
561
+ appName: string;
562
+ version: number;
563
+ entry: Record<string, unknown> | null; // Null for claimed-but-unpublished
564
+ deployed: boolean; // True once a real release has landed
565
+ deployedBy: string;
566
+ gitRemote: string;
567
+ createdBy: string;
568
+ }
569
+ ```
570
+
571
+ - Changed: `createCommand` in `commands/create.ts` now calls `claimApp()` to reserve the app name immediately after validation and before scaffolding files. If an app already exists in the registry, the command only throws an error if `existing?.deployed` is true (indicating a real release exists). A claimed-but-unpublished stub (where `entry` is null) is now allowed, enabling users to re-create locally after wiping their directory or to proceed if the name was reserved but never published.
572
+ *Before:*
573
+ ```ts
574
+ const existing = await fetchApp(mfAppName(appName));
575
+ if (existing) {
576
+ throw new Error(`An app named "${appName}" already exists...`);
577
+ }
578
+ ```
579
+ *After:*
580
+ ```ts
581
+ const existing = await fetchApp(mfAppName(appName));
582
+ if (existing?.deployed) {
583
+ throw new Error(`An app named "${appName}" already exists...`);
584
+ }
585
+ const gitRemote = resolveRemoteUrl(...);
586
+ if (!existing) {
587
+ await claimApp(mfAppName(appName), gitRemote);
588
+ }
589
+ ```
590
+
591
+ - Changed: `generateCommand` in `commands/generate.ts` now only blocks app creation if `existing?.deployed` is true, rather than blocking on any existing app record. This aligns with the new behavior where claimed-but-unpublished stubs are permitted.
592
+ *Before:*
593
+ ```ts
594
+ const existing = await fetchApp(mfAppName(appName));
595
+ if (existing) {
596
+ throw new Error(`An app named "${appName}" already exists...`);
597
+ }
598
+ ```
599
+ *After:*
600
+ ```ts
601
+ const existing = await fetchApp(mfAppName(appName));
602
+ if (existing?.deployed) {
603
+ throw new Error(`An app named "${appName}" already exists...`);
604
+ }
605
+ ```
606
+
607
+ - Changed: `fetchApp` function documentation in `util/broker/app.ts` updated to clarify it returns `null` only if the app has never been claimed (404 response), not just never deployed. This reflects the new claiming workflow where apps can exist in the registry without having been deployed yet.
608
+
609
+ ## `0.28.0` (September 16, 2026, 09:13)
610
+
611
+ ### New Features
612
+
613
+ - [#426](https://github.com/DaPulse/bigbrain-z2h/pull/426) feat(z2h-cli): validate backend handlers with acorn AST (@eitan-ts)
614
+ - Added: AST-based validation for backend handlers. The CLI now parses handler source files using Acorn at read and deploy time, validating syntax, isolate constraints (no import/export, must define a global `handler` function), and capability-specific rules. Parse errors include file, line, and column information.
615
+ - Added: `z2h-cli backend validate` command to run handler validation checks without uploading to S3. This runs the same syntax, isolate, and integration detection checks as deployment.
616
+ *Usage:*
617
+ ```bash
618
+ z2h-cli backend validate
619
+ ```
620
+ *Output:*
621
+ ```
622
+ [z2h-cli] 3 handler(s) valid: handler1, handler2, handler3
623
+ [z2h-cli] integrations: monday
624
+ ```
625
+ - Changed: Integration detection now uses AST analysis instead of regex scanning. The `detectIntegrationsFromHandlers(handlers: Record<string, string>)` function has been replaced with `detectIntegrations(apiDomains: Iterable<string>)`.
626
+ *Before:*
627
+ ```ts
628
+ import { detectIntegrationsFromHandlers } from '@mondaydotcomorg/z2h-cli/backend/detect-integrations';
629
+ const integrations = detectIntegrationsFromHandlers(handlers);
630
+ ```
631
+ *After:*
632
+ ```ts
633
+ import { detectIntegrations } from '@mondaydotcomorg/z2h-cli/backend/detect-integrations';
634
+ const integrations = detectIntegrations(apiDomains);
635
+ ```
636
+ - Changed: `readHandlers()` now returns `{ handlers: Record<string, string>, apiDomains: string[] }` instead of `{ handlers: Record<string, string> }`. The `apiDomains` array contains every `ctx.api.v1.<domain>` any handler touches, sorted and unique.
637
+ - Added: Capability-specific validation rules. The initial rule enforces that `ctx.api.v1.snowflake.query(sql, params?, options?)` must receive SQL text authored in the handler (string literals, template literals, or const variables resolving to them), not dynamically constructed from client input. Violations report the file and line number.
638
+ - Added: Path resolution for `ctx.api.v1.*` usage tracking. The validator follows `const` aliases and destructuring (e.g., `const sf = ctx.api.v1.snowflake; sf.query(...)` is recognized as Snowflake usage, as is `const { snowflake: sf } = ctx.api.v1`). The handler's first parameter is treated as `ctx` even when renamed.
639
+ - Added: New backend AST utilities exported from `@mondaydotcomorg/z2h-cli/backend/ast`: `collectBindings(program)` returns every variable declaration and tracks which names are unpinnable (reassigned, parameters). `createPathResolver(bindings, contextParam?)` resolves member expression chains through const aliases. `collectApiDomains(program, paths)` returns every `ctx.api.v1.<domain>` the program touches.
640
+ - Added: Handler declaration analysis utilities exported from `@mondaydotcomorg/z2h-cli/backend/handler-declaration`: `findHandlerDeclaration(body)` locates the top-level `handler` binding, `exportsHandler(node)` detects export statements for handler, `handlerContextParamName(declaration)` extracts the first parameter name.
641
+ - Added: Parse utilities exported from `@mondaydotcomorg/z2h-cli/backend/parse`: `parseOrThrow(file, code)` parses handler source as a script and throws descriptive errors for syntax issues, module-only syntax (import/export/top-level await), or export of handler.
642
+ - Added: Validation entry point exported from `@mondaydotcomorg/z2h-cli/backend/validate`: `validateHandlerSource(file, source)` returns `{ apiDomains: string[] }` after running all checks. Throws on violations.
643
+ - Added: Handler rule system types exported from `@mondaydotcomorg/z2h-cli/backend/rules`: `HandlerRule` interface with `name: string` and `check(ctx: RuleContext): string[]`. `RuleContext` provides `file`, `program`, `bindings`, and `paths`. `HANDLER_RULES` array contains all active rules.
644
+ - Changed: `DECLARED_INTEGRATIONS` constant is now imported from `@mondaydotcomorg/z2h-shared-utils` instead of being defined locally in `@mondaydotcomorg/z2h-cli/constants`. The constant is re-exported for backward compatibility.
645
+ - Added: Parse error tracking. When a handler fails to parse, the CLI emits a `z2h_cli_handler_parse_error` event with the error message that was shown to the user.
646
+ - Changed: Handler validation errors now provide structured messages via `messages` object in `@mondaydotcomorg/z2h-cli/backend/messages`, including `mustDefine(file)`, `notAFunction(file)`, `mustNotImport(file)`, `mustNotExportHandler(file)`, `mustNotExport(file)`, `moduleOnlySyntax(file, detail)`, and `syntaxError(file, line, column, detail)`.
647
+
648
+ ### Dependency Upgrades
649
+
650
+ - Upgrade `z2h-shared-utils` version
651
+ - Upgrade `dashboard-templates` version
652
+
653
+ ## `0.27.1` (September 16, 2026, 07:24)
654
+
655
+ ### Dependency Upgrades
656
+
657
+ - Upgrade `dashboard-templates` version
658
+
659
+ ## `0.27.0` (September 16, 2026, 06:06)
660
+
661
+ ### New Features
662
+
663
+ - [#387](https://github.com/DaPulse/bigbrain-z2h/pull/387) feat(z2h): fetch dataviz skill from S3 at agent startup (@arielmonday)
664
+ - Added: New exported constant `S3_SKILLS_BUCKET_NAME` set to `'prod-use1-bigbrain-zth-skills'`. This constant defines the S3 bucket name where dataviz design-system skills are published by data-cookbook's CI pipeline. Both `bigbrain-zth` (which mints read-only STS credentials) and `bigbrain-zth-agent` (which syncs vendor files at pod startup) import this constant to ensure consistency across services.
665
+ ```ts
666
+ import { S3_SKILLS_BUCKET_NAME } from '@mondaydotcomorg/z2h-cli';
667
+ // S3_SKILLS_BUCKET_NAME === 'prod-use1-bigbrain-zth-skills'
668
+ ```
669
+
670
+ - Added: New exported constant `DATAVIZ_SKILLS_PREFIX` set to `'dataviz/'`. This constant defines the S3 object key prefix under which dataviz skills are stored in the skills bucket. The agent uses this prefix to determine which objects to sync into its local `vendor/` directory at startup.
671
+ ```ts
672
+ import { DATAVIZ_SKILLS_PREFIX } from '@mondaydotcomorg/z2h-cli';
673
+ // DATAVIZ_SKILLS_PREFIX === 'dataviz/'
674
+ // Used to construct full S3 keys like: dataviz/monday-data-viz-vibe/SKILL.md
675
+ ```
676
+
677
+ - Changed: The constants file now serves as a shared source of truth for S3 skills bucket configuration between the CLI, backend service (`bigbrain-zth`), and agent (`bigbrain-zth-agent`). This ensures bucket name and prefix values cannot drift between services that need to coordinate on S3 access.
678
+
679
+ ## `0.26.4` (September 15, 2026, 10:53)
680
+
681
+ ### Dependency Upgrades
682
+
683
+ - Upgrade `z2h-shared-utils` version
684
+ - Upgrade `dashboard-templates` version
685
+
686
+ ## `0.26.3` (September 14, 2026, 11:08)
687
+
688
+ ### Dependency Upgrades
689
+
690
+ - Upgrade `dashboard-templates` version
691
+
692
+ ## `0.26.2` (September 14, 2026, 09:55)
693
+
694
+ ### Dependency Upgrades
695
+
696
+ - Upgrade `dashboard-templates` version
697
+
698
+ ## `0.26.1` (September 10, 2026, 11:01)
699
+
700
+ ### Dependency Upgrades
701
+
702
+ - Upgrade `dashboard-templates` version
703
+
704
+ ## `0.26.0` (September 10, 2026, 10:27)
705
+
706
+ ### New Features
707
+
708
+ - [#389](https://github.com/DaPulse/bigbrain-z2h/pull/389) feat(z2h-cli): dashboard generation commands (generate/templates/deploy --prebuilt-dir) (@EranZidkiya)
709
+ - Added: New `z2h-cli templates` command that lists all available dashboard templates from the `@mondaydotcomorg/z2h-dashboard-templates` catalog. Returns template metadata including id, title, description, and the JSON Schema for each template's configuration shape. Example usage:
710
+ ```bash
711
+ z2h-cli templates
712
+ z2h-cli templates --json
713
+ ```
714
+
715
+ - Added: New `z2h-cli generate-app-template <app-name>` command that scaffolds a Z2H app from a prebuilt template without requiring a full build or yarn install. Copies a catalog template, patches its prebuilt bundle with real widget data, and deploys a preview. Requires `--template <id>` (catalog template id) and `--input <json>` (template-specific configuration validated against the template's schema). Example usage:
716
+ ```bash
717
+ z2h-cli generate-app-template my-dashboard --template sales-dashboard --input '{"title":"Q1 Sales","widgets":[...]}'
718
+ ```
719
+
720
+ - Added: New `--prebuilt-dir <path>` option to `z2h-cli deploy` command. When provided, skips the build step entirely and deploys an already-built directory as-is. This is used internally by the `generate-app-template` command to deploy string-patched bundles without rebuilding. Example usage:
721
+ ```bash
722
+ z2h-cli deploy --preview --prebuilt-dir .zth/build-patched
723
+ ```
724
+ The `buildAndStamp` internal function now accepts an optional `prebuiltDir` parameter and copies from it instead of invoking `buildCommand()` when present.
725
+
726
+ - Added: New module `src/util/dashboard-templates/load-catalog.ts` that provides utilities for loading and validating dashboard templates. Exports `loadDashboardTemplatesCatalog()` which returns an array of `DashboardTemplateEntry` objects (id, title, description, templateDir, configSchema, validateConfig), and `findTemplate(id)` which locates a specific template by id or throws if not found. Templates are loaded from the `@mondaydotcomorg/z2h-dashboard-templates` package's `templates/` directory.
727
+
728
+ - Added: New module `src/util/dashboard-templates/patch-bundle.ts` that implements string-based patching of minified JavaScript bundles. Exports `patchBuiltBundle(sourceBuildDir, outDir, config)` which finds all MF entrypoints, locates the `/*! Z2H_CONFIG_V1 */` anchor comment in each, and replaces the immediately-following object literal with real configuration data. Also exports `patchOneFile(src, config)` for single-file patching. This enables template instantiation without rebuilding.
729
+
730
+ - Added: New `generateCommand(appName, opts)` function in `src/commands/generate.ts` that orchestrates the full template generation pipeline: validates app name uniqueness, copies template files (excluding node_modules, .build-shadow, and setup files), patches package.json with the new app name, resolves workspace protocol dependencies to real versions, patches the config source file (`src/templateConfig.ts`), invokes optional `toFrontendConfig` hook to strip sensitive data, patches the prebuilt bundle via `patchBuiltBundle`, invokes optional `setupBackend` hook to generate backend handlers, initializes a git repo, and deploys a preview.
731
+
732
+ - Changed: The `create` command description now clarifies that it scaffolds a "blank Z2H consumer app" using built-in templates (default | html-embed), and suggests using `generate-app-template` instead if a catalog template already fits the use case.
733
+
734
+ - Changed: Internal `DeployOptions` interface in `src/commands/deploy.ts` now includes an optional `prebuiltDir?: string` field used by the generate pipeline to skip builds and reuse already-patched directories.
735
+
736
+ ### Dependency Upgrades
737
+
738
+ - Upgrade `dashboard-templates` version
739
+
740
+ ## `0.25.9` (September 9, 2026, 10:21)
741
+
742
+ ### Dependency Upgrades
743
+
744
+ - Upgrade `z2h-shared-utils` version
745
+
746
+ ## `0.25.8` (September 8, 2026, 11:37)
747
+
748
+ ### Dependency Upgrades
749
+
750
+ - Upgrade `z2h-shared-utils` version
751
+
752
+ ## `0.25.7` (September 6, 2026, 09:22)
753
+
754
+ ### Improvements
755
+
756
+ - [#372](https://github.com/DaPulse/bigbrain-z2h/pull/372) refactor(z2h-cli): single command wrapper for telemetry + bounded failure reasons (@eitan-ts)
757
+ - Changed: `Z2hAuthMissingError` export path moved from `@mondaydotcomorg/z2h-cli/auth/auth-store` to `@mondaydotcomorg/z2h-cli/util/errors`. Update your imports:
758
+ *Before:*
759
+ ```ts
760
+ import { Z2hAuthMissingError } from '@mondaydotcomorg/z2h-cli/auth/auth-store';
761
+ ```
762
+ *After:*
763
+ ```ts
764
+ import { Z2hAuthMissingError } from '@mondaydotcomorg/z2h-cli/util/errors';
765
+ ```
766
+ - Added: New `Z2hError` base class for all classified CLI errors. All Z2H error types now extend this base and include `reason: string`, optional `data: Record<string, unknown>`, and `exitCode: number` properties. This enables programmatic error classification.
767
+ ```ts
768
+ class Z2hError extends Error {
769
+ constructor(message: string, reason: string, data?: Record<string, unknown>, exitCode?: number);
770
+ readonly reason: string;
771
+ readonly data?: Record<string, unknown>;
772
+ readonly exitCode: number;
773
+ }
774
+ ```
775
+ - Added: New `DeployError` class for deploy/preview failures with bounded reason codes. The `reason` field is now one of: `'read_auth_token'`, `'broker_auth'`, `'broker_error'`, `'lock_timeout'`, `'build_error'`, `'git_error'`, `'s3_error'`, `'deploy_backend_error'`, `'register_error'`, `'push_error'`, `'interrupted'`, or `'unknown'`.
776
+ ```ts
777
+ class DeployError extends Z2hError {
778
+ constructor(reason: DeployFailureReason, message: string, data?: Record<string, unknown>);
779
+ }
780
+ ```
781
+ - Added: New `GrantError` class for grant/revoke/transfer-owner failures with bounded reason codes. The `reason` field is now one of: `'validation'`, `'auth'`, `'forbidden'`, `'not_found'`, `'server_error'`, or `'unknown'`. Can be constructed with an HTTP status code that will be automatically mapped to the appropriate reason.
782
+ ```ts
783
+ class GrantError extends Z2hError {
784
+ constructor(reason: GrantFailureReason | number, message: string, data?: Record<string, unknown>);
785
+ }
786
+ ```
787
+ - Changed: `Z2hAuthMissingError` now extends `Z2hError` and includes `reason: 'read_auth_token'` for programmatic detection.
788
+ - Changed: `GitConflictError` now extends `Z2hError` and includes `reason: 'git_error'` or a stage-specific reason for programmatic detection.
789
+ - Changed: All CLI commands now emit telemetry events automatically via a unified `runCommand` wrapper. Commands no longer need individual try/catch blocks or manual telemetry calls.
790
+ - Changed: CLI version is now automatically stamped on all telemetry events via the `cli_version` dimension. Previously this was not included.
791
+ - Changed: Error telemetry payload now includes a bounded `reason` field instead of freeform error messages. The canonical `error` and `action` fields now appear last in the payload, preventing caller keys from shadowing them.
792
+ - Changed: Deploy failures during the build stage (consumer code compilation errors) are no longer tracked as CLI errors, since they represent user code issues rather than infrastructure problems. The error still surfaces to the user with exit code 2.
793
+ - Changed: Preview deploys (`deploy --preview`) now emit full error telemetry with classified reasons. Previously, preview failures bypassed classification and always reported as `unknown`.
794
+ - Changed: Lock acquisition failures now distinguish between contention (`lock_timeout` when someone else holds the lock), authentication issues (`broker_auth` for 401/403), and infrastructure problems (`broker_error` for other failures). Previously all non-409 statuses were reported as lock contention.
795
+ - Changed: Git synchronization failures (dirty working tree or diverged branches) are now classified as `git_error` instead of `unknown`.
796
+ - Changed: The package now imports its own version via the self-referencing `@mondaydotcomorg/z2h-cli/package.json` export instead of a relative path.
797
+ - Added: New `successEvent(command: string): string` helper that generates success event names following the `z2h_cli_<command>_success` pattern. Nested commands join their path with underscores (e.g., `backend invoke` becomes `z2h_cli_backend_invoke_success`).
798
+ - Added: Five commands that previously had no success telemetry now emit success events: `generate-z2h-token`, `grant`, `revoke`, `transfer-owner`, and `migrate`. The event names follow the `z2h_cli_<command>_success` pattern.
799
+ - Unchanged: The following seven pre-existing success event names remain unchanged for backward compatibility with downstream analytics: `z2h_app_build_success`, `z2h_app_deploy_success`, `z2h_app_preview_success`, `z2h_app_tag_success`, `z2h_app_created`, `z2h_app_edit_pulled`, `z2h_app_delete_success`, `z2h_backend_invoke_success`.
800
+ - Changed: Commands with no success event (`clean`, `create-workspace`, `doctor`) no longer emit error events either, fixing a previous inconsistency where they emitted errors but not successes.
801
+ - Changed: Telemetry now uses `createHttpTracker` from `@mondaydotcomorg/z2h-shared-utils/observability` instead of a local implementation, providing consistent HTTP-based event tracking.
802
+ - Added: New `CommandSpec<A>` type for specifying command telemetry behavior, including optional `track`, `event`, `label`, `data`, and `exitCode` fields. This type is used by the `runCommand` wrapper.
803
+ - Added: New `DeployFailureReason` and `GrantFailureReason` type unions exported from the main package, providing the complete set of bounded reason codes.
804
+ - Added: New utility functions for error handling: `grantReasonForStatus(status: number): GrantFailureReason` (maps HTTP status to grant error reason), `tagDeployError(reason: DeployFailureReason, err: unknown): Z2hError` (tags errors unless already classified), `reasonOf(err: unknown): string` (extracts reason or returns `'unknown'`), `dataOf(err: unknown): Record<string, unknown>` (extracts extra dimensions), and `messageOf(err: unknown): string` (safe message extraction for any thrown value).
805
+
806
+ ### Dependency Upgrades
807
+
808
+ - Upgrade `z2h-shared-utils` version
809
+
810
+ ## `0.25.6` (September 6, 2026, 08:33)
811
+
812
+ ### Improvements
813
+
814
+ - [#411](https://github.com/DaPulse/bigbrain-z2h/pull/411) Reword storage-vs-GitHub prompt in create-app flow (@arielmonday)
815
+ - Changed: The `--remote` flag help text in both `z2h-cli create` and `z2h-cli deploy` commands now explicitly recommends S3 storage and emphasizes automatic backup. The new help text reads: "s3 (shared storage, recommended, auto-backed-up) or github (manage it yourself in your own repo)" instead of the previous "s3 (shared storage) or github (your repo)".
816
+
817
+ - Changed: The first-deploy error message when no `--remote` is specified now uses more user-friendly language. The S3 option description changed from "Stores source history in S3 alongside your app. No extra setup." to "We store and back up your code for you automatically. No extra setup." The GitHub option description changed from "Uses an existing GitHub repo" to "Manage it yourself in an existing GitHub repo".
818
+ *Before:*
819
+ ```
820
+ z2h-cli deploy --remote s3 (default)
821
+ Stores source history in S3 alongside your app. No extra setup.
822
+
823
+ z2h-cli deploy --remote github --repo-url https://github.com/org/repo.git
824
+ Uses an existing GitHub repo (must exist before deploying).
825
+ ```
826
+ *After:*
827
+ ```
828
+ z2h-cli deploy --remote s3 (default, recommended)
829
+ We store and back up your code for you automatically. No extra setup.
830
+
831
+ z2h-cli deploy --remote github --repo-url https://github.com/org/repo.git
832
+ Manage it yourself in an existing GitHub repo (must exist before deploying).
833
+ ```
834
+
835
+ - Changed: The S3 option is now explicitly marked as "(default, recommended)" instead of just "(default)" in error messages, making the recommended choice clearer to users.
836
+
837
+ ## `0.25.5` (September 6, 2026, 07:21)
838
+
839
+ ### Dependency Upgrades
840
+
841
+ - Upgrade `z2h-shared-utils` version
842
+
843
+ ## `0.25.4` (September 3, 2026, 06:26)
844
+
845
+ ### Dependency Upgrades
846
+
847
+ - Upgrade `z2h-shared-utils` version
848
+
849
+ ## `0.25.3` (September 2, 2026, 15:08)
850
+
851
+ ### Dependency Upgrades
852
+
853
+ - Upgrade `z2h-shared-utils` version
854
+
855
+ ## `0.25.2` (September 2, 2026, 14:48)
856
+
857
+ ### Dependency Upgrades
858
+
859
+ - Upgrade `z2h-shared-utils` version
860
+
861
+ ## `0.25.1` (September 2, 2026, 14:20)
862
+
863
+ ### Dependency Upgrades
864
+
865
+ - Upgrade `z2h-shared-utils` version
866
+
867
+ ## `0.25.0` (September 2, 2026, 11:05)
868
+
869
+ ### New Features
870
+
871
+ - [#399](https://github.com/DaPulse/bigbrain-z2h/pull/399) refactor(z2h-cli): extract MF scaffold templates into z2h-shared-utils (@EranZidkiya)
872
+ - Refactored: Microfrontend scaffold templates are no longer defined locally in `shadow/scaffold.ts`. The CLI now imports `WRAPPER_TEMPLATE`, `tridentrcTemplate`, `dtsFileTemplate`, and `TSCONFIG_TEMPLATE` from the shared package `@mondaydotcomorg/z2h-shared-utils/mf-scaffold`. This consolidates template definitions across the Z2H toolchain and eliminates drift between multiple copies of scaffold code.
873
+ *Before:*
874
+ ```ts
875
+ // In packages/z2h-cli/src/shadow/scaffold.ts
876
+ const WRAPPER_TEMPLATE = `import '@vibe/core/tokens';
877
+ // ... template defined locally
878
+ `;
879
+ ```
880
+ *After:*
881
+ ```ts
882
+ import {
883
+ WRAPPER_TEMPLATE,
884
+ tridentrcTemplate,
885
+ dtsFileTemplate,
886
+ TSCONFIG_TEMPLATE,
887
+ } from '@mondaydotcomorg/z2h-shared-utils/mf-scaffold';
888
+ ```
889
+ - Internal: The scaffold templates now use typed React wrapper parameters (`new Map<HTMLElement, ReactDOM.Root>()`, `render(element: HTMLElement)`), ensuring type safety in generated consumer app wrappers.
890
+
891
+ ### Dependency Upgrades
892
+
893
+ - Upgrade `z2h-shared-utils` version
894
+
895
+ ## `0.24.2` (September 2, 2026, 06:34)
896
+
897
+ ### Bug Fixes
898
+
899
+ - [#397](https://github.com/DaPulse/bigbrain-z2h/pull/397) fix(z2h-cli): scaffold and reinstall correctly when node_modules is mounted separately from the workspace (@arielmonday)
900
+ - Fixed: The `create-workspace` command now correctly scaffolds new workspaces when `node_modules` is mounted as a separate volume. Previously, the command checked if the target directory contained any entries to decide whether the workspace already existed. When an emptyDir volume is mounted at `node_modules` (common in PVC-backed environments), the directory would always contain at least one entry, causing the command to skip scaffolding entirely even on brand-new workspaces. The logic now checks for the presence of the `z2hWorkspace: true` marker in `package.json` via the new `isZ2hWorkspace()` utility function instead of counting directory entries.
901
+
902
+ - Changed: Workspace scaffolding and dependency installation are now evaluated independently. The command first checks `isZ2hWorkspace()` to determine if scaffold files (`package.json`, `.yarnrc.yml`, `yarn.lock`, etc.) need to be written. Separately, it checks if `node_modules` is populated. Yarn install now runs if *either* the workspace was just scaffolded *or* `node_modules` is missing/empty, ensuring dependencies are always available even when the workspace structure already exists but the modules directory was cleared or mounted fresh.
903
+
904
+ - Added: New internal helper function `isPopulated(dir: string): Promise<boolean>` that checks whether a directory exists and contains at least one entry. This is used to determine if `node_modules` needs to be repopulated.
905
+
906
+ - Changed: Informational logging messages now appear before their respective operations. The message "setting up your Z2H workspace" now displays before scaffolding files, and "installing workspace dependencies — this may take a minute" appears before running `yarn install`. Previously, the setup message appeared only before the install step.
907
+
908
+ ## `0.24.1` (August 31, 2026, 13:31)
909
+
910
+ ### Bug Fixes
911
+
912
+ - [#392](https://github.com/DaPulse/bigbrain-z2h/pull/392) fix(z2h-cli): make Ctrl-C work at the interactive prompts (@eitan-ts)
913
+ - Fixed: Ctrl-C now properly exits at the token paste prompt in `z2h-cli generate-z2h-token`. Previously, pressing Ctrl-C at the "Paste your token here" prompt would only pause the interface with no way to exit except killing the terminal. The CLI now exits with status code 130 (shell convention for SIGINT) when Ctrl-C is pressed.
914
+
915
+ - Fixed: The advertised Ctrl-C fallback during token loopback is now functional in `z2h-cli generate-z2h-token`. The prompt "waiting for the page to send the token (Ctrl+C to fall back to manual paste)" has displayed since the feature's introduction, but pressing Ctrl-C would kill the CLI instead of falling back to manual paste. The loopback wait now races against a SIGINT listener, and when Ctrl-C is pressed, the CLI cleanly transitions to the manual token paste prompt.
916
+
917
+ - Fixed: Ctrl-C now properly exits at the tag selection prompt in `z2h-cli tag`. Previously, pressing Ctrl-C during tag selection would only pause the interface with no way to exit. The CLI now exits with status code 130 when Ctrl-C is pressed.
918
+
919
+ - Changed: Added proper cleanup handling to prevent unhandled promise rejections when cancelling the loopback token wait. The `waitForToken` promise is now caught before racing, ensuring that when `LoopbackHandle.close()` rejects the pending wait, it doesn't crash the CLI with an unhandled rejection.
920
+
921
+ - Changed: The SIGINT listener during loopback token wait is now properly detached in a `finally` block, ensuring it only suppresses Node's default termination during the wait period and not after.
922
+
923
+ ## `0.24.0` (August 30, 2026, 12:51)
924
+
925
+ ### New Features
926
+
927
+ - [#380](https://github.com/DaPulse/bigbrain-z2h/pull/380) fix(z2h-cli): correctness fixes found while building the beta mechanism (@yarinmonday)
928
+ - Added: New exported `baseVersion` function that strips prerelease identifiers from semver versions to extract the base major.minor.patch version. This function parses a version string and returns only the base version components, throwing an error if the version is invalid.
929
+ ```ts
930
+ export function baseVersion(version: string): string {
931
+ const parsed = semver.parse(version);
932
+ if (!parsed) {
933
+ throw new Error(`invalid semver version: ${version}`);
934
+ }
935
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
936
+ }
937
+ ```
938
+
939
+ - Changed: Migration version comparison logic now uses base versions instead of full versions with prerelease tags. Previously, the `migrateCommand` function compared the raw CLI version directly against the last migrated version. Now it extracts the base version first using `baseVersion(cliVersion)` before comparisons. This prevents prerelease versions (which sort below their release version in semver) from incorrectly skipping migrations they introduce.
940
+ *Before:*
941
+ ```ts
942
+ if (!semver.gt(cliVersion, lastVersion)) {
943
+ info('workspace is up to date — no migrations pending');
944
+ return;
945
+ }
946
+ ```
947
+ *After:*
948
+ ```ts
949
+ const targetVersion = baseVersion(cliVersion);
950
+ if (!semver.gt(targetVersion, lastVersion)) {
951
+ info('workspace is up to date — no migrations pending');
952
+ return;
953
+ }
954
+ ```
955
+
956
+ - Changed: Pending migration filtering now uses base version for upper bound comparison. The filter that selects migrations between `lastVersion` and the current CLI version now compares against `targetVersion` (the base version) instead of `cliVersion`.
957
+ *Before:*
958
+ ```ts
959
+ const pending = Object.entries(migrationsJson.migrations)
960
+ .filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
961
+ ```
962
+ *After:*
963
+ ```ts
964
+ const pending = Object.entries(migrationsJson.migrations)
965
+ .filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, targetVersion))
966
+ ```
967
+
968
+ - Changed: Migration state persistence now records base version instead of full version. When writing the last migrated version to state, the function now stores `targetVersion` (base version) rather than the full `cliVersion` with prerelease tags. This ensures consistent version tracking across prerelease and release versions.
969
+ *Before:*
970
+ ```ts
971
+ await writeMigrationState(workspaceHome, { lastMigratedVersion: cliVersion });
972
+ ```
973
+ *After:*
974
+ ```ts
975
+ await writeMigrationState(workspaceHome, { lastMigratedVersion: targetVersion });
976
+ ```
977
+
978
+ - Changed: Migration progress logging now displays base version. The info message that logs migration progress now shows the base target version instead of the full CLI version with prerelease identifiers.
979
+ *Before:*
980
+ ```ts
981
+ info(`migrating workspace from v${lastVersion} → v${cliVersion}...`);
982
+ ```
983
+ *After:*
984
+ ```ts
985
+ info(`migrating workspace from v${lastVersion} → v${targetVersion}...`);
986
+ ```
987
+
988
+ ## `0.23.1` (August 25, 2026, 14:54)
989
+
990
+ ### Improvements
991
+
992
+ - [#369](https://github.com/DaPulse/bigbrain-z2h/pull/369) fix(z2h-cli): remove dead direct S3 manifest write path (@eitan-ts)
993
+ - Removed: `readManifest()` function that fetched the asset manifest from the public CDN endpoint. This function was unused; deploy registration now retrieves manifest data through the backend API (`registerOrUpdateApp` → `bigbrain-zth`'s `registerApp`/`updateApp`) which reads from RDS, not S3.
994
+ - Removed: `nextVersion(manifest: Manifest, app: string)` function that calculated the next version number for an app by incrementing the current version from the manifest. This function was unused; version management is now handled by the backend API during app registration.
995
+ - Removed: `upsertEntry(manifest: Manifest, app: string, entry: ManifestEntry)` function that added or updated a manifest entry in the in-memory manifest object. This function was unused; manifest updates are now persisted directly to RDS via the backend API.
996
+ - Removed: `writeManifest(manifest: Manifest)` function that wrote the entire manifest to S3 using `PutObjectCommand`. This function was unused; the host microfrontend now builds its runtime manifest dynamically from RDS data instead of reading a static S3 object.
997
+ *Previously:*
998
+ ```typescript
999
+ await writeManifest(updatedManifest);
1000
+ ```
1001
+ *Migration:* Use `registerOrUpdateApp()` from the CLI's broker utilities to register/update apps through the backend API, which persists to RDS.
1002
+ - Removed: S3-related imports (`PutObjectCommand` from `@aws-sdk/client-s3`, `getS3Client` utility, and `BUCKET_WRITE_NAME`/`MANIFEST_KEY`/`MANIFEST_READ_URL` constants from the import list). These imports were only used by the removed manifest functions. Note: `MANIFEST_KEY` and `MANIFEST_READ_URL` constants remain defined in `constants.ts` as they are still referenced by a migration script in the `bigbrain-zth` backend.
1003
+ - Unchanged: All TypeScript type definitions (`SharedDep`, `AssetManifestFile`, `ManifestEntry`, `Manifest`) remain exported from this module. These types are still consumed by `deploy.ts` and `util/broker/app.ts` for structuring deploy metadata sent to the backend API.
1004
+
1005
+ ## `0.23.0` (August 24, 2026, 09:09)
1006
+
1007
+ ### New Features
1008
+
1009
+ - [#361](https://github.com/DaPulse/bigbrain-z2h/pull/361) feat(mf-project-builders-cli): add CLI package for uploading MF preview builds (@eitan-ts)
1010
+ - Added: New public export file `src/auth.ts` that re-exports authentication utilities for use by other packages. Exports `generateZ2HTokenCommand` (function), `GenerateZ2HTokenOptions` (type), `readZthAuth` (function), `Z2hAuthMissingError` (class), `Z2H_AUTH_FILE` (constant), and `ZthAuth` (type) from internal modules.
1011
+ *Usage:*
1012
+ ```ts
1013
+ import { readZthAuth, generateZ2HTokenCommand } from '@mondaydotcomorg/z2h-cli/auth';
1014
+ const { token } = await readZthAuth();
1015
+ ```
1016
+ - Added: New public export file `src/s3.ts` that re-exports S3 utilities for use by other packages. Exports `setupS3Client` (function), `getS3Client` (function), and `uploadDir` (function) from internal S3 modules.
1017
+ *Usage:*
1018
+ ```ts
1019
+ import { setupS3Client, uploadDir } from '@mondaydotcomorg/z2h-cli/s3';
1020
+ setupS3Client({ accessKeyId, secretAccessKey, sessionToken });
1021
+ const keys = await uploadDir('/path/to/build', 'prefix', 'my-bucket');
1022
+ ```
1023
+ - Changed: The `uploadDir` function now accepts an optional third parameter `bucket` (string) to specify a custom S3 bucket name. When omitted, defaults to the existing `BUCKET_WRITE_NAME` constant, preserving backward compatibility.
1024
+ *Before:*
1025
+ ```ts
1026
+ await uploadDir(localDir, keyPrefix); // always uploads to BUCKET_WRITE_NAME
1027
+ ```
1028
+ *After:*
1029
+ ```ts
1030
+ await uploadDir(localDir, keyPrefix); // still defaults to BUCKET_WRITE_NAME
1031
+ await uploadDir(localDir, keyPrefix, 'custom-bucket'); // now supports custom bucket
1032
+ ```
1033
+
1034
+ ## `0.22.0` (August 18, 2026, 12:12)
1035
+
1036
+ ### New Features
1037
+
1038
+ - [#337](https://github.com/DaPulse/bigbrain-z2h/pull/337) Feat/yarin/backend support enable (@yarinmonday)
1039
+ - Added: New backend support infrastructure with `backend/client.ts` module providing HTTP client functions for backend runner operations: `invokeBackend(appName, handlerName, input)` to invoke deployed handlers, `listAppIntegrations(appName)` to retrieve app integrations, `declareIntegration(appName, integration)` and `removeIntegration(appName, integration)` to manage integrations, and `backendBaseUrl()` to resolve the runner origin with `Z2H_BACKEND_URL` environment variable override support.
1040
+ - Added: Automatic integration detection from handler source code via `detectIntegrationsFromHandlers(handlers)` in `backend/detect-integrations.ts`, which scans for `ctx.api.v1.<name>` patterns matching entries in the `DECLARED_INTEGRATIONS` constant (currently `['monday']`). OAuth-gated integrations are auto-registered; always-on channels like `db`, `llm`, and `snowflake` are excluded.
1041
+ - Added: Handler validation and reading via `readHandlers(consumerDir)` in `backend/handlers.ts`, which reads `.js` files from `backend/handlers/` directory and validates that each handler defines a global `handler` function or variable (not exported), rejects TypeScript files with an error instructing users to compile first, rejects handlers with `export` prefix (isolate has no module system), and rejects handlers containing `import` or `require` statements (handlers are self-contained).
1042
+ - Added: Backend deployment support via `deployBackend()` in `commands/backend.ts`, which reads handlers, detects integrations, and uploads each `.js` handler as a flat file to S3 (no compilation or bundling) along with a `meta.json` manifest. Live deploys use `<appName>/backend-<version>` path; preview deploys use `<mfKeyPrefix without /MF>/MS` path. The function returns detected integrations for platform registration.
1043
+ - Added: New CLI command `z2h-cli backend invoke <handlerName>` to invoke a deployed backend handler by name for testing purposes without going through the frontend.
1044
+ *Usage:*
1045
+ ```bash
1046
+ z2h-cli backend invoke call_snowflake --input '{"boardId":"123"}'
1047
+ ```
1048
+ - Changed: Deploy flow now includes backend deployment via new `uploadAndRegister()` helper function, which uploads frontend build, deploys backend handlers (if present), auto-detects integrations from handler sources, and registers the release with the platform in a single transaction. Both `deployPreview()` and `deployLive()` now use this unified path.
1049
+ - Changed: App registration and update API calls in `util/broker/app.ts` now accept an optional `integrations` parameter that is passed to the broker's `/z2h-cli/apps/register` and `/z2h-cli/apps/update` endpoints. The integration set is reconciled to exactly match the detected set on every deploy.
1050
+ - Changed: Generated app template in `templates/app/html-index.tsx.tmpl` no longer includes backend base URL resolution via `getBackendBaseUrl()` or postMessage-based config injection. The iframe component is simplified (no `useRef`, no `useEffect`, no message event listener) as the runtime SDK now handles backend communication transparently.
1051
+ - Changed: Generated workspace `package.json` template now includes `@mondaydotcomorg/z2h-runtime-sdk` dependency at version `^0.1.0`.
1052
+ - Added: `DECLARED_INTEGRATIONS` constant exported from `constants.ts` as a closed set of OAuth-gated integrations (currently `['monday']`) that the CLI detects from handler sources and the broker validates on register/update.
1053
+
1054
+ ## `0.21.2` (August 17, 2026, 13:26)
1055
+
1056
+ ### Improvements
1057
+
1058
+ - [#327](https://github.com/DaPulse/bigbrain-z2h/pull/327) feat(z2h-cli): sticky previewId — generate once, reuse on subsequent deploys (@arielmonday)
1059
+ - **Breaking Change**: Removed `--previewId` parameter from the `deploy --preview` command. The CLI no longer accepts a custom preview ID via the command line.
1060
+ *Before:*
1061
+ ```bash
1062
+ z2h-cli deploy --preview abc123
1063
+ ```
1064
+ *After:*
1065
+ ```bash
1066
+ z2h-cli deploy --preview
1067
+ ```
1068
+ - Changed: Preview deployments now generate a stable, persistent preview ID that is automatically reused across subsequent deploys. The `previewId` is generated once (8-character UUID prefix) and stored in `.zth/metadata.json`, ensuring the preview URL remains constant for the same app across rebuilds.
1069
+ - Changed: The `previewId` field has been added to the `ShadowMetadata` interface in `src/types.ts`, making it part of the persisted metadata alongside `createdAt`, `appName`, and `port`.
1070
+ - Changed: The `resolvePortAndMetadata` function in `src/shadow/prepare.ts` is now exported and enhanced to manage both port and preview ID persistence. It generates a new `previewId` on first run and reuses the existing one from metadata on subsequent runs.
1071
+ - Changed: Preview ID generation logic moved from `deploy.ts` to `shadow/prepare.ts`. The `deployPreview` function now calls `resolvePortAndMetadata` to obtain the sticky `previewId` instead of generating a new one with `randomUUID()` or accepting one via CLI options.
1072
+ - Changed: The `DeployOptions` interface in `src/commands/deploy.ts` no longer includes the `previewId` field. The option parsing and handling logic for `--preview [previewId]` has been simplified to treat `--preview` as a boolean flag only.
1073
+ - Changed: Enhanced logging granularity in `deployLive` and `deployPreview` functions with new info messages: "getting sts credentials", "updating manifest", "acquiring deploy lock", and "releasing deploy lock" to provide better visibility into deployment steps.
1074
+ - Changed: The `--preview` CLI option description updated to clarify that it "reuses the same preview URL across runs (stable link)" instead of the previous behavior where each deploy could mint a new preview URL.
1075
+
1076
+ ## `0.21.1` (August 17, 2026, 12:57)
1077
+
1078
+ ### Improvements
1079
+
1080
+ - [#341](https://github.com/DaPulse/bigbrain-z2h/pull/341) feat(z2h): generate + store app descriptions on deploy (@EranZidkiya)
1081
+ - Added: The `deploy` command now accepts an optional `--description <text>` flag that allows passing a short (<=200 character) description of the app during deployment. This description is forwarded to the backend and stored in the app metadata.
1082
+ *Usage:*
1083
+ ```bash
1084
+ z2h-cli deploy --description "Customer analytics dashboard with real-time metrics"
1085
+ ```
1086
+ - Changed: The `DeployOptions` interface now includes an optional `description?: string` field to support passing app descriptions through the deployment flow.
1087
+ *Before:*
1088
+ ```typescript
1089
+ export interface DeployOptions {
1090
+ previewId?: string;
1091
+ open?: boolean;
1092
+ }
1093
+ ```
1094
+ *After:*
1095
+ ```typescript
1096
+ export interface DeployOptions {
1097
+ previewId?: string;
1098
+ open?: boolean;
1099
+ description?: string;
1100
+ }
1101
+ ```
1102
+ - Changed: The `registerApp` function now accepts an optional `description?: string` parameter that is included in the registration payload sent to the backend when creating a new app for the first time.
1103
+ *Before:*
1104
+ ```typescript
1105
+ async function registerApp(
1106
+ appName: string,
1107
+ token: string,
1108
+ version: number,
1109
+ entry: ManifestEntry,
1110
+ visibility: 'public' | 'private',
1111
+ gitRemote: string
1112
+ ): Promise<void>
1113
+ ```
1114
+ *After:*
1115
+ ```typescript
1116
+ async function registerApp(
1117
+ appName: string,
1118
+ token: string,
1119
+ version: number,
1120
+ entry: ManifestEntry,
1121
+ visibility: 'public' | 'private',
1122
+ gitRemote: string,
1123
+ description?: string
1124
+ ): Promise<void>
1125
+ ```
1126
+ - Changed: The `updateApp` function now accepts an optional `description?: string` parameter that is included in the update payload sent to the backend when updating an existing app.
1127
+ *Before:*
1128
+ ```typescript
1129
+ async function updateApp(
1130
+ appName: string,
1131
+ token: string,
1132
+ version: number,
1133
+ entry: ManifestEntry,
1134
+ gitRemote: string
1135
+ ): Promise<void>
1136
+ ```
1137
+ *After:*
1138
+ ```typescript
1139
+ async function updateApp(
1140
+ appName: string,
1141
+ token: string,
1142
+ version: number,
1143
+ entry: ManifestEntry,
1144
+ gitRemote: string,
1145
+ description?: string
1146
+ ): Promise<void>
1147
+ ```
1148
+ - Changed: The `RegisterOrUpdateOptions` interface now includes an optional `description?: string` field to thread app descriptions through the registration/update flow.
1149
+ *Before:*
1150
+ ```typescript
1151
+ export interface RegisterOrUpdateOptions {
1152
+ appName: string;
1153
+ token: string;
1154
+ nextVersion: number;
1155
+ entry: ManifestEntry;
1156
+ gitRemote: string;
1157
+ }
1158
+ ```
1159
+ *After:*
1160
+ ```typescript
1161
+ export interface RegisterOrUpdateOptions {
1162
+ appName: string;
1163
+ token: string;
1164
+ nextVersion: number;
1165
+ entry: ManifestEntry;
1166
+ gitRemote: string;
1167
+ description?: string;
1168
+ }
1169
+ ```
1170
+ - Changed: The `registerOrUpdateApp` function now threads the `description` parameter from the options through to both `registerApp` and `updateApp` calls, ensuring descriptions are forwarded to the backend regardless of whether this is a first deploy or an update.
1171
+
1172
+ ## `0.21.0` (August 13, 2026, 11:27)
1173
+
1174
+ ### New Features
1175
+
1176
+ - [#324](https://github.com/DaPulse/bigbrain-z2h/pull/324) Feat/yarin/backend support invoke (@yarinmonday)
1177
+
1178
+ ## `0.20.0` (August 13, 2026, 07:45)
1179
+
1180
+ ### New Features
1181
+
1182
+ - [#315](https://github.com/DaPulse/bigbrain-z2h/pull/315) Feat/yarin/backend support channels (@yarinmonday)
1183
+
1184
+ ## `0.19.0` (August 12, 2026, 10:38)
1185
+
1186
+ ### New Features
1187
+
1188
+ - [#326](https://github.com/DaPulse/bigbrain-z2h/pull/326) feat(z2h): direct same-origin fixes for html-embed iframes (@EranZidkiya)
1189
+ - Changed: HTML-embed app template now routes iframe sources through the `/z2h-assets` proxy instead of using direct CDN URLs, making iframes same-origin with the host. The template (`html-index.tsx.tmpl`) now includes a `toProxiedUrl` utility function that rewrites CDN URLs (`https://bigbrain-zth-mf-assets.bigbrain.me`) to proxy paths (`/z2h-assets/...`). The iframe element's `src` attribute is now wrapped with this function.
1190
+ *Before:*
1191
+ ```tsx
1192
+ <iframe
1193
+ ref={iframeRef}
1194
+ src={pageUrl}
1195
+ title="App"
1196
+ style={{ width: '100vw', height: '100vh', border: 'none', display: 'block' }}
1197
+ />
1198
+ ```
1199
+ *After:*
1200
+ ```tsx
1201
+ const Z2H_MFS_BASE_URL = 'https://bigbrain-zth-mf-assets.bigbrain.me';
1202
+ const Z2H_ASSETS_PROXY_PREFIX = '/z2h-assets';
1203
+
1204
+ function toProxiedUrl(url: string): string {
1205
+ if (!url.startsWith(Z2H_MFS_BASE_URL)) return url;
1206
+ return `${window.location.origin}${Z2H_ASSETS_PROXY_PREFIX}${url.slice(Z2H_MFS_BASE_URL.length)}`;
1207
+ }
1208
+
1209
+ // In component:
1210
+ <iframe
1211
+ ref={iframeRef}
1212
+ src={toProxiedUrl(pageUrl)}
1213
+ title="App"
1214
+ style={{ width: '100vw', height: '100vh', border: 'none', display: 'block' }}
1215
+ />
1216
+ ```
1217
+ - Added: New migration `007-proxy-iframe-src.ts` that automatically backfills the `toProxiedUrl` fix onto existing html-embed apps created before this version. The migration scans for any `import ... from './path/to/file.html?url'` pattern in `index.tsx` files, injects the `toProxiedUrl` utility function, and rewrites iframe `src` attributes to use it. This migration runs automatically when apps are opened with the updated CLI, ensuring existing apps receive the same-origin iframe behavior without manual intervention.
1218
+ - Fixed: HTML-embed iframes now maintain same-origin status with the host application, enabling direct fetch header stamping (e.g., `x-z2h-app-name`) on requests made from within the iframe's JavaScript context. Previously, the iframe loaded HTML files via absolute CDN URLs, making them cross-origin and requiring postMessage-based proxying for backend requests.
1219
+
1220
+ ## `0.18.1` (August 10, 2026, 13:00)
1221
+
1222
+ ### Improvements
1223
+
1224
+ - [#320](https://github.com/DaPulse/bigbrain-z2h/pull/320) fix(z2h-cli): show access-denied message on 403 instead of token-refresh hint (@arielmonday)
1225
+ - Fixed: HTTP 401 and 403 errors are now handled separately in `assertBrokerOk` (broker-credential-provider.ts). Previously, both status codes triggered the same "refresh your token" message, which was misleading for 403 (access denied) scenarios and caused the z2h-agent to hang for 600 seconds in headless environments attempting to run an interactive OAuth command. Now 401 responses display: `Z2H deploy token rejected by the broker (401). Refresh user token by running 'z2h-cli generate-z2h-token'.` while 403 responses display: `Access denied (403). You do not have editor access to this app. Ask the app owner to grant you access via 'z2h-cli grant'.`
1226
+ - Added: Explicit 403 error handling in the `fetchApp` function (app.ts). When the broker returns 403 for app lookups (indicating the authenticated user lacks access), the function now throws a clear error message: `Access denied (403). You do not have access to this app. Ask the app owner to grant you access via 'z2h-cli grant'.` This prevents 403 errors from falling through to the generic error handler and provides actionable guidance to users who need access grants.
1227
+ - Changed: Error messages for broker authentication failures now include specific HTTP status codes in parentheses (401 vs 403) to disambiguate token expiration from permission denial, improving troubleshooting for both users and automated agents.
1228
+
1229
+ ## `0.18.0` (August 10, 2026, 10:15)
1230
+
1231
+ ### New Features
1232
+
1233
+ - [#314](https://github.com/DaPulse/bigbrain-z2h/pull/314) Feat/yarin/backend support preview backend (@yarinmonday)
1234
+ - Changed: Preview deployment S3 path structure simplified. Preview builds are now stored at `previews/<previewAppName>/MF/` instead of `previews/<appName>/<previewId>/MF/`, where `previewAppName` is the preview's full microfrontend name (e.g., `mf-zth-preview-<id>-<app>`) that already embeds the preview ID. This eliminates the redundant separate `<previewId>` folder level in the S3 hierarchy.
1235
+ - Changed: The `brokerCredentialProvider` function now receives the preview's full app name (`previewAppName`) when deploying previews, ensuring STS credentials are scoped to the correct `previews/<previewAppName>/*` path instead of using the base app name separately from the preview ID.
1236
+ - Updated: Documentation comments in `broker-credential-provider.ts` and `constants.ts` clarified to reflect that preview credentials are scoped to `previews/<appName>/*` where `appName` is the preview's own app name that already contains the preview ID.
1237
+
1238
+ ## `0.17.0` (August 9, 2026, 06:55)
1239
+
1240
+ ### New Features
1241
+
1242
+ - [#295](https://github.com/DaPulse/bigbrain-z2h/pull/295) feat(z2h-preview): exclude preview app rows from manifest/listing by … (@yarinmonday)
1243
+ - Changed: Preview deployment IDs are now shortened to 8 characters instead of using full UUIDs. When running `z2h-cli deploy` in preview mode without specifying an explicit `--preview-id` option, the CLI now generates an 8-character random identifier (e.g., `a1b2c3d4`) instead of a full 36-character UUID (e.g., `550e8400-e29b-41d4-a716-446655440000`). This results in shorter, more manageable preview URLs and S3 paths while maintaining sufficient uniqueness for concurrent preview deployments.
1244
+ *Before:*
1245
+ ```ts
1246
+ const previewId = opts.previewId ?? randomUUID();
1247
+ // Generated preview ID: '550e8400-e29b-41d4-a716-446655440000'
1248
+ ```
1249
+ *After:*
1250
+ ```ts
1251
+ const previewId = opts.previewId ?? randomUUID().slice(0, 8);
1252
+ // Generated preview ID: '550e8400'
1253
+ ```
1254
+
1255
+ ## `0.16.0` (August 9, 2026, 06:24)
1256
+
1257
+ ### New Features
1258
+
1259
+ - [#294](https://github.com/DaPulse/bigbrain-z2h/pull/294) feat(z2h-preview): add z2h-cli preview command and broker STS mint route (@yarinmonday)
1260
+ - Added: `deploy --preview` command creates ephemeral, shareable preview deployments without requiring git, deploy locks, or affecting the live version. Pass an optional `previewId` to update an existing preview instead of creating a new one.
1261
+ *Usage:*
1262
+ ```bash
1263
+ z2h-cli deploy --preview # Create new preview
1264
+ z2h-cli deploy --preview <id> # Update existing preview
1265
+ z2h-cli deploy --preview --open # Create and open in browser
1266
+ ```
1267
+ Preview URLs follow the pattern: `https://bigbrain.me/bigbrain-vibe/zth-preview-<shortid>-<appName>`
1268
+
1269
+ - Added: `--open` flag for `deploy` command automatically opens the deployed app or preview URL in the browser upon successful deployment.
1270
+ *Usage:*
1271
+ ```bash
1272
+ z2h-cli deploy --open # Deploy and open live URL
1273
+ z2h-cli deploy --preview --open # Create preview and open
1274
+ ```
1275
+
1276
+ - Removed: `dev` command no longer available. Local development workflow has been replaced by the preview deployment mechanism (`deploy --preview`).
1277
+ *Migration:*
1278
+ ```bash
1279
+ # Before
1280
+ z2h-cli dev
1281
+
1282
+ # After
1283
+ z2h-cli deploy --preview --open
1284
+ ```
1285
+
1286
+ - Changed: `buildCommand` function now returns a `BuildResult` object containing `{ appName, port, buildDir, assetManifest }` instead of `Promise<void>`. This breaking change enables callers to access build artifacts and metadata.
1287
+ *Before:*
1288
+ ```typescript
1289
+ await buildCommand({ publicUrl: 'https://...' });
1290
+ // Returns void, no access to build output
1291
+ ```
1292
+ *After:*
1293
+ ```typescript
1294
+ const result = await buildCommand({ publicUrl: 'https://...' });
1295
+ // result.assetManifest contains Trident's asset-manifest.json
1296
+ // result.buildDir points to the shadow build directory
1297
+ ```
1298
+
1299
+ - Added: `validateAppName(appName: string)` centralized validation function enforces app naming rules including lowercase kebab-case pattern, reserved platform names (`generate-z2h-token`), and the new `zth-preview-` prefix reservation.
1300
+
1301
+ - Added: `buildPreviewSlug(appName: string, previewId: string)` generates synthetic app names for preview deployments in the format `zth-preview-<shortid>-<appName>`, ensuring uniqueness while keeping names human-readable.
1302
+
1303
+ - Added: `isPreviewAppName(appName: string)` utility function determines if a given app name belongs to an ephemeral preview.
1304
+
1305
+ - Changed: `brokerCredentialProvider` now accepts an optional `previewId` parameter. When provided, returns STS credentials scoped to `previews/<appName>/<previewId>/*` instead of the full deploy path.
1306
+ *Usage:*
1307
+ ```typescript
1308
+ // Regular deploy credentials
1309
+ const deployCreds = brokerCredentialProvider({ appName: 'mf-demo-app' });
1310
+
1311
+ // Preview-scoped credentials
1312
+ const previewCreds = brokerCredentialProvider({
1313
+ appName: 'mf-demo-app',
1314
+ previewId: 'abc123-...'
1315
+ });
1316
+ ```
1317
+
1318
+ - Added: `registerOrUpdateApp(options)` function centralizes the app registration/update branching logic. Version 1 creates a new app row with visibility prompt; subsequent versions release updates to the existing app.
1319
+
1320
+ - Added: `S3_PREVIEWS_FOLDER` constant (`'previews'`) defines the root S3 prefix for ephemeral preview uploads, shared between CLI upload logic and backend STS policy generation.
1321
+
1322
+ - Added: `PREVIEW_APP_NAME_PREFIX` constant (`'zth-preview-'`) reserves the naming prefix for preview deployments, preventing real apps from using names that would collide with the ephemeral preview mechanism.
1323
+
1324
+ - Removed: SSL certificate check from `doctor` command. The `webpack.llama.fan` certificate validation is no longer performed as it's not required by the preview-based workflow.
1325
+
1326
+ - Removed: `start` script from generated app templates. Consumer apps created with `z2h-cli create` no longer include a `start` script that invoked the removed `dev` command.
1327
+
1328
+ - Added: Migration `006-remove-start-script.ts` automatically removes dangling `"start": "z2h-cli dev"` scripts from existing consumer package.json files during CLI updates.
1329
+
1330
+ - Changed: App registration visibility prompting logic extracted to `util/prompt-visibility.ts` for reuse between deploy and preview flows.
1331
+
1332
+ - Changed: App registration and update endpoints moved from `commands/deploy.ts` to `util/broker/app.ts` (`registerApp`, `updateApp`) for better modularity and reuse in preview deployments.
1333
+
1334
+ ## `0.15.2` (August 5, 2026, 09:43)
1335
+
1336
+ ### Bug Fixes
1337
+
1338
+ - [#303](https://github.com/DaPulse/bigbrain-z2h/pull/303) feat: track Z2H events to staging doorman (@arielmonday)
1339
+ - Changed: Event tracking now routes to environment-specific doorman endpoints based on the `NODE_ENV` environment variable. When `NODE_ENV=staging`, the `trackEvent` function sends events to the staging doorman at `https://track-int.bigbrainstaging.me/stage/event`. In all other environments (including production), events are sent to the production doorman at `https://track-int.bigbrain.me/prod/event`. This allows developers to test tracking behavior in staging without polluting production analytics.
1340
+ *Before:*
1341
+ ```ts
1342
+ // Always routed to production endpoint regardless of environment
1343
+ await trackEvent('cli-command-executed', { command: 'build' });
1344
+ // → POST https://track-int.bigbrain.me/prod/event
1345
+ ```
1346
+ *After:*
1347
+ ```ts
1348
+ // In staging environment (NODE_ENV=staging)
1349
+ await trackEvent('cli-command-executed', { command: 'build' });
1350
+ // → POST https://track-int.bigbrainstaging.me/stage/event
1351
+
1352
+ // In production or any other environment
1353
+ await trackEvent('cli-command-executed', { command: 'build' });
1354
+ // → POST https://track-int.bigbrain.me/prod/event
1355
+ ```
1356
+
1357
+ ## `0.15.1` (August 5, 2026, 09:27)
1358
+
1359
+ ### Improvements
1360
+
1361
+ - [#302](https://github.com/DaPulse/bigbrain-z2h/pull/302) Make --json a global CLI flag instead of per-command (@arielmonday)
1362
+ - Changed: The `--json` flag is now a global option on the root CLI program instead of a per-command option. It can now be placed anywhere in the command line.
1363
+ *Before:*
1364
+ ```bash
1365
+ z2h-cli build --json
1366
+ z2h-cli deploy --dry-run --json
1367
+ ```
1368
+ *After (both styles still work):*
1369
+ ```bash
1370
+ z2h-cli build --json
1371
+ z2h-cli --json build
1372
+ z2h-cli --json deploy --dry-run
1373
+ ```
1374
+ - Changed: The `BuildOptions` interface no longer includes the `json?: boolean` property. The `buildCommand()` function signature remains `async function buildCommand(opts: BuildOptions = {}): Promise<void>` but the options object no longer accepts `json`.
1375
+ - Changed: The `CleanOptions` interface has been removed entirely. The `cleanCommand()` function signature changed from `async function cleanCommand(opts: CleanOptions = {}): Promise<void>` to `async function cleanCommand(): Promise<void>`.
1376
+ - Changed: The `CreateWorkspaceOptions` interface has been removed. The `createWorkspaceCommand()` function signature changed from `async function createWorkspaceCommand(opts: CreateWorkspaceOptions = {}): Promise<void>` to `async function createWorkspaceCommand(): Promise<void>`.
1377
+ - Changed: The `CreateOptions` interface no longer includes the `json?: boolean` property. Other fields (`template`, `htmlFile`, `remote`, `repoUrl`) remain unchanged.
1378
+ - Changed: The `DeleteOptions` interface no longer includes the `json?: boolean` property. The `yes?: boolean` property remains. Internal implementation now uses `getOutputMode()` instead of checking a local `opts.json` flag.
1379
+ - Changed: The `DeployOptions` interface no longer includes the `json?: boolean` property. Other fields (`dryRun`, `remote`, `repoUrl`) remain unchanged. Internal calls to `buildCommand()` no longer pass a `json` option.
1380
+ - Changed: The `DevOptions` interface no longer includes the `json?: boolean` property. The `open?: boolean` property remains.
1381
+ - Changed: The `DoctorOptions` interface has been removed. The `doctorCommand()` function signature changed from `async function doctorCommand(opts: DoctorOptions = {}): Promise<void>` to `async function doctorCommand(): Promise<void>`. Internal implementation now uses `getOutputMode()` to determine output format.
1382
+ - Changed: The `EditOptions` interface has been removed. The `editCommand()` function signature changed from `async function editCommand(appName: string, opts: EditOptions = {}): Promise<void>` to `async function editCommand(appName: string): Promise<void>`.
1383
+ - Changed: The `GenerateZ2HTokenOptions` interface no longer includes the `json?: boolean` property. Other fields (`noBrowser`, `url`) remain unchanged.
1384
+ - Changed: The `GrantOptions` interface no longer includes the `json?: boolean` property. Other fields (`public`, `level`) remain unchanged. The `grantCommand()` and `revokeCommand()` function signatures are otherwise unchanged.
1385
+ - Changed: The `TransferOwnerOptions` interface has been removed. The `transferOwnerCommand()` function signature changed from `async function transferOwnerCommand(email: string | undefined, opts: TransferOwnerOptions): Promise<void>` to `async function transferOwnerCommand(email: string | undefined): Promise<void>`.
1386
+ - Changed: The `TagOptions` interface no longer includes the `json?: boolean` property. The `tag?: string[]` property remains. Internal implementation now uses `getOutputMode()` instead of checking `opts.json`.
1387
+ - Changed: The `MigrateOptions` interface no longer includes the `json?: boolean` property. The `dryRun?: boolean` property remains.
1388
+ - Changed: The migration engine previously in `src/migrations/auto-migrate.ts` (217 lines) has been consolidated into `src/commands/migrate.ts`. All migration logic including `readMigrationState()`, `writeMigrationState()`, and the core migration loop is now colocated with the `migrateCommand()` function. The file `src/migrations/auto-migrate.ts` has been deleted.
1389
+ - Added: New workspace utility functions exported from `src/util/workspace.ts`: `runYarnInstall(workspaceHome: string, context: string): Promise<boolean>`, `isNxAvailable(workspaceHome: string): boolean`, `ensureWorkspaceNx(workspaceHome: string): Promise<boolean>`, and internal helper `getLatestTrientMonorepoVersion(): Promise<string>`. These were previously private functions in the migration module.
1390
+ - Changed: Commander.js program setup now uses `.hook('preAction', ...)` to set the output mode globally before any command action runs, ensuring consistent `--json` behavior across all commands without per-command boilerplate.
1391
+
1392
+ ## `0.15.0` (August 2, 2026, 11:11)
1393
+
1394
+ ### New Features
1395
+
1396
+ - [#277](https://github.com/DaPulse/bigbrain-z2h/pull/277) feat(zth-agent): M3 — connect the agent to z2h-cli (create/edit/build/deploy loop) (@arielmonday)
1397
+ - Changed: The `create-workspace` command now generates `.npmrc` and `.yarnrc.yml` configuration files dynamically from broker configuration instead of copying static template files. This enables environment-aware registry URLs that respect the `Z2H_BROKER_BASE_URL` environment variable.
1398
+ *Before:*
1399
+ ```ts
1400
+ copy(path.join(wsTemplatesDir, 'yarnrc.yml'), path.join(home, '.yarnrc.yml')),
1401
+ copy(path.join(wsTemplatesDir, 'npmrc'), path.join(home, '.npmrc')),
1402
+ ```
1403
+ *After:*
1404
+ ```ts
1405
+ writeFile(path.join(home, '.yarnrc.yml'), workspaceYarnrcContents()),
1406
+ writeFile(path.join(home, '.npmrc'), workspaceNpmrcContents()),
1407
+ ```
1408
+ - Removed: Static template files `packages/z2h-cli/src/templates/workspace/npmrc` and `packages/z2h-cli/src/templates/workspace/yarnrc.yml` have been deleted from the codebase. These previously contained hardcoded production broker URLs (`https://bigbrain-zth.bigbrain.me/z2h-cli/npm/`) that prevented correct operation in staging environments.
1409
+ - Added: New import in `create-workspace.ts` for dynamic configuration generation functions `workspaceNpmrcContents` and `workspaceYarnrcContents` from `../util/npm/broker-config`. These functions generate workspace registry configuration based on the current environment's broker URL.
1410
+ - Fixed: Workspace creation now correctly configures npm and yarn to use the staging broker when `Z2H_BROKER_BASE_URL` points to staging, resolving timeout issues during `yarn install` in non-production environments.
1411
+
1412
+ ## `0.14.0` (July 13, 2026, 09:15)
1413
+
1414
+ ### New Features
1415
+
1416
+ - [#247](https://github.com/DaPulse/bigbrain-z2h/pull/247) feat(z2h-cli): add doctor command for setup health checks (@arielmonday)
1417
+ - Added: New `doctor` command that performs comprehensive health checks for Z2H setup. Run `z2h-cli doctor` to validate your entire development environment.
1418
+ ```bash
1419
+ z2h-cli doctor
1420
+ # or for JSON output:
1421
+ z2h-cli doctor --json
1422
+ ```
1423
+
1424
+ - Added: System tools validation including checks for `nvm`, `node`, `yarn`, `aws-cli`, and `git-remote-s3` with version detection and comparison.
1425
+
1426
+ - Added: Node.js version verification against the `.nvmrc` requirement. The doctor command compares your installed Node version with the required version using semver `~` range matching and reports mismatches as failures.
1427
+
1428
+ - Added: CLI version freshness check that queries the broker npm registry to detect outdated `z2h-cli` installations and warns when a newer version is available.
1429
+
1430
+ - Added: Authentication token validation that checks for the presence and validity of `~/.z2h/auth.json` and verifies the token field exists.
1431
+
1432
+ - Added: NPM token environment variable check that scans shell profiles (`dotfiles/.bash_profile`, `.zshrc`, `.bash_profile`) for `export Z2H_NPM_TOKEN` declarations.
1433
+
1434
+ - Added: Workspace initialization check that validates the Z2H workspace directory structure and reports if `z2h-cli create-workspace` needs to be run.
1435
+
1436
+ - Added: React version validation in workspace `package.json` that ensures React 18.x is installed as a dependency.
1437
+
1438
+ - Added: SSL certificate check for `webpack.llama.fan` in `~/Library/Application Support/devcert/domains/webpack.llama.fan/certificate.crt`.
1439
+
1440
+ - Added: Claude plugin validation with differentiated severity levels:
1441
+ - Mandatory: `z2h@bigbrain-z2h` plugin (failure if missing)
1442
+ - Optional: `cf-external-claude-plugin@client-foundations-ai-tools` and `pr-guardrails@agentic-builders-hub` (warning if missing)
1443
+ The command verifies plugin registration in `~/.claude/plugins/installed_plugins.json` and checks that install paths exist.
1444
+
1445
+ - Added: Three-tier status system for check results:
1446
+ - `ok` (✅): Check passed
1447
+ - `warn` (⚠️): Non-critical issue detected
1448
+ - `fail` (❌): Critical issue requiring action
1449
+
1450
+ - Added: Automatic fix command suggestions. When issues are detected, doctor outputs deduplicated fix commands in order of first appearance:
1451
+ ```
1452
+ In order to fix these issues, run the following commands:
1453
+ bash ~/Development/bigbrain-z2h/z2h/setup/bootstrap.sh
1454
+ z2h-cli generate-z2h-token
1455
+ ```
1456
+
1457
+ - Added: JSON output mode via `--json` flag that emits structured check results for programmatic consumption:
1458
+ ```json
1459
+ {
1460
+ "ok": false,
1461
+ "checks": [
1462
+ {
1463
+ "label": "nvm",
1464
+ "status": "ok",
1465
+ "detail": "0.39.1"
1466
+ }
1467
+ ]
1468
+ }
1469
+ ```
1470
+
1471
+ - Added: Four categorized check sections in output: "System tools", "CLI & auth", "Workspace", and "Plugins" for organized diagnostics.
1472
+
1473
+ - Added: Helper function `checkTool` that standardizes tool existence and version detection with configurable failure severity and version extraction logic.
1474
+
1475
+ - Added: Timeout protection for network requests (5-second timeout on npm registry version check) to prevent hanging on network issues.
1476
+
1477
+ - Added: Graceful degradation when optional data is unavailable (e.g., version check works without auth token or network access, showing current version only).
1478
+
1479
+ ## `0.13.2` (July 12, 2026, 09:42)
1480
+
1481
+ ### Improvements
1482
+
1483
+ - [#250](https://github.com/DaPulse/bigbrain-z2h/pull/250) feat(z2h): add self-serve app delete (CLI, backend, SDK) (@EranZidkiya)
1484
+ - Added: New `z2h-cli delete` command for permanently deleting Z2H apps. The command must be run from within the consumer app directory and requires owner or admin access. By default, it prompts the user to type the app name for confirmation before deletion. The `--yes` flag skips the confirmation prompt (required when using `--json` or in non-interactive environments). The `--json` flag outputs structured JSON to stdout. When successful, the command removes the app from the backend (including grants and tags via cascading deletes) and takes it offline immediately.
1485
+ *Usage:*
1486
+ ```bash
1487
+ # Interactive mode with confirmation prompt
1488
+ z2h-cli delete
1489
+
1490
+ # Non-interactive mode (e.g., for CI/CD)
1491
+ z2h-cli delete --yes
1492
+
1493
+ # JSON output for programmatic use
1494
+ z2h-cli delete --yes --json
1495
+ ```
1496
+ - Changed: The `pullAndResolve` git utility function now checks if the remote repository has a `master` branch before attempting to pull. If the remote has no `master` branch (e.g., brand-new remote or after app deletion wiped the S3 git prefix), the pull operation is skipped entirely. This prevents bogus merge conflicts during the first deploy or after an app is recreated following deletion.
1497
+ *Impact:*
1498
+ This change enables seamless re-deployment scenarios where an app's S3 git objects were removed (such as after deletion), allowing the subsequent push to create the `master` branch without encountering pull errors.
1499
+
1500
+ ## `0.13.1` (July 8, 2026, 11:26)
1501
+
1502
+ ### Improvements
1503
+
1504
+ - [#222](https://github.com/DaPulse/bigbrain-z2h/pull/222) Feat/eran/tags addition (@EranZidkiya)
1505
+ - Added: New `tag` command that allows setting category tags (app type & team) for Z2H apps, supporting both interactive and non-interactive modes.
1506
+ ```bash
1507
+ z2h-cli tag [app-name]
1508
+ z2h-cli tag my-app --tag "Dashboard" --tag "Analytics Team"
1509
+ z2h-cli tag --json
1510
+ ```
1511
+ - Added: New `--tag <tag>` repeatable option for the `tag` command that sets the full tag set non-interactively.
1512
+ - Added: New `--json` option for the `tag` command that prints the catalog and current tags as JSON without prompting (read-only mode for agents and non-TTY environments).
1513
+ - Added: New `promptForTags(appSlug: string, catalog: CatalogEntry[], current: AppTag[])` function that provides an interactive closed-list prompt for selecting tags across dimensions (app type, team). Users can enter a number or name to select, or press Enter to keep the current value or skip.
1514
+ - Added: New `resolveAppSlug(appArg?: string)` utility that resolves the target app name from an explicit argument or from the consumer package.json `name` field in the current directory, normalized to the `mf-` bundle name format.
1515
+ - Added: New `formatTags(tags: AppTag[])` utility that renders an app's tags in the format `name (Type), ...` or `(none)` if empty.
1516
+ - Added: New `util/tags.ts` module with tag-related types, constants, and API client functions:
1517
+ - `TagType` type (`'app_type' | 'team'`)
1518
+ - `TAG_TYPES` array defining prompt order
1519
+ - `TAG_TYPE_LABELS` record for human-readable dimension labels
1520
+ - `CatalogEntry` and `AppTag` interfaces
1521
+ - `fetchTagCatalog()` function to retrieve the full tag catalog
1522
+ - `fetchAppTags(appSlug: string)` function to get tags for a specific app
1523
+ - `setAppTags(appSlug: string, tags: string[])` function to full-replace an app's tag set
1524
+ - `tagFetch()` internal authenticated request handler for tag endpoints
1525
+ - Changed: The `deploy` command now automatically handles tags post-deployment via a new `handleDeployTags(appName: string)` function. In interactive TTY sessions, users are prompted to categorize their app on first deploy if no tags are set. In non-interactive or non-TTY sessions, a nudge message is shown.
1526
+ - Changed: Logger imports in `deploy.ts` now include `getOutputMode` to support conditional interactive behavior.
1527
+ - Changed: The `deploy` command now imports `promptForTags` from `./tag` and tag utilities from `../util/tags` to support post-deploy tag handling.
1528
+ - Changed: Tag failures during deployment never fail the deploy itself (tag handling is a post-deploy concern executed after successful S3 upload).
1529
+ - Added: New `collectTag(value: string, previous: string[])` utility in `index.ts` for commander to accumulate repeatable `--tag` option values.
1530
+ - Added: New `z2h_app_tag_success` telemetry tracking for the `tag` command execution duration.
1531
+
1532
+ ## `0.13.0` (July 7, 2026, 14:26)
1533
+
1534
+ ### New Features
1535
+
1536
+ - [#239](https://github.com/DaPulse/bigbrain-z2h/pull/239) feat(z2h-cli): enhance snowflake query (@yarinmonday)
1537
+ - Enhanced the html-embed app template to support a new Snowflake data-fetching bridge pattern via `postMessage` communication between the React wrapper and the embedded HTML page.
1538
+ - Added a `getBackendBaseUrl()` helper function that constructs the bigbrain-zth microservice URL by retrieving the base URL from `getBigBrainAPI().contextService.bigbrainBaseUrl` and inserting the `bigbrain-zth` subdomain. This enables html-embed pages to fetch data from the backend without hardcoding URLs.
1539
+ - Introduced a `postMessage` event listener in the React wrapper component that listens for `z2h:getConfig` messages from the iframe and responds with a `z2h:config` message containing the computed `baseUrl`.
1540
+ *Before:*
1541
+ ```tsx
1542
+ export default function MyApp() {
1543
+ return <iframe src={pageUrl} title="App" style={{...}} />;
1544
+ }
1545
+ ```
1546
+ *After:*
1547
+ ```tsx
1548
+ export default function MyApp() {
1549
+ const iframeRef = useRef<HTMLIFrameElement>(null);
1550
+ useEffect(() => {
1551
+ const handleMessage = (event: MessageEvent) => {
1552
+ if (event.data?.type !== 'z2h:getConfig') return;
1553
+ const baseUrl = getBackendBaseUrl();
1554
+ (event.source as Window).postMessage({ type: 'z2h:config', baseUrl }, event.origin);
1555
+ };
1556
+ window.addEventListener('message', handleMessage);
1557
+ return () => window.removeEventListener('message', handleMessage);
1558
+ }, []);
1559
+ return <iframe ref={iframeRef} src={pageUrl} title="App" style={{...}} />;
1560
+ }
1561
+ ```
1562
+ - Added a `useRef` hook to the iframe element to enable message source validation, ensuring only messages from the embedded iframe trigger configuration responses.
1563
+ - Updated the iframe rendering to attach the ref (`ref={iframeRef}`) for secure message origin verification.
1564
+ - Changed imports in the html-embed template to include `useRef` and `useEffect` from React, and `getBigBrainAPI` from `@mondaydotcomorg/trident-runtime`.
1565
+ - Introduced a `BACKEND_SUBDOMAIN` constant set to `'bigbrain-zth'` for backend URL construction.
1566
+
1567
+ ## `0.12.1` (July 6, 2026, 09:42)
1568
+
1569
+ ### Bug Fixes
1570
+
1571
+ - [#235](https://github.com/DaPulse/bigbrain-z2h/pull/235) Use global z2h-cli command instead of npx (@arielmonday)
1572
+ - Changed: CLI invocation pattern updated from `npx z2h-cli` to direct `z2h-cli` command across all documentation. The CLI now expects to be installed globally or available in PATH, removing reliance on npx which can cache stale versions. This affects all command examples in the app template's CLAUDE.md file.
1573
+ *Before:*
1574
+ ```bash
1575
+ npx z2h-cli dev
1576
+ npx z2h-cli deploy
1577
+ npx z2h-cli clean
1578
+ npx z2h-cli grant --public
1579
+ npx z2h-cli revoke --public
1580
+ ```
1581
+ *After:*
1582
+ ```bash
1583
+ z2h-cli dev
1584
+ z2h-cli deploy
1585
+ z2h-cli clean
1586
+ z2h-cli grant --public
1587
+ z2h-cli revoke --public
1588
+ ```
1589
+ - Changed: App template documentation (CLAUDE.md) now references the global `z2h-cli` command for all CLI operations including development server (`dev`), deployment (`deploy`), cleanup (`clean`), and permission management (`grant`/`revoke`).
1590
+ - Improved: Removed dependency on npx for CLI execution, eliminating potential issues with cached or outdated CLI versions during development and deployment workflows.
1591
+
1592
+ ## `0.12.0` (July 6, 2026, 07:41)
1593
+
1594
+ ### New Features
1595
+
1596
+ - [#230](https://github.com/DaPulse/bigbrain-z2h/pull/230) feat(z2h-cli): add --open flag to auto-open browser when dev server is ready (@arielmonday)
1597
+ - Added: New `--open` flag to the `dev` command that automatically opens the browser when the Trident dev server is ready.
1598
+ *Usage:*
1599
+ ```bash
1600
+ z2h-cli dev --open
1601
+ ```
1602
+ When this flag is provided, the browser will open automatically at the dev server URL once the server emits the "Server started at" signal. Without this flag, the browser will not open automatically (existing behavior preserved).
1603
+
1604
+ - Added: New shared utility `openInBrowser` in `src/util/open-browser.ts` that handles cross-platform browser opening (macOS via `open`, Windows via `start`, Linux via `xdg-open`).
1605
+ *API:*
1606
+ ```ts
1607
+ import { openInBrowser } from '../util/open-browser';
1608
+ await openInBrowser(url);
1609
+ ```
1610
+ This function includes error handling that logs a message if the browser fails to open, instructing the user to open it manually.
1611
+
1612
+ - Changed: The `DevOptions` interface now includes an optional `open` boolean property.
1613
+ *Before:*
1614
+ ```ts
1615
+ export interface DevOptions {
1616
+ json?: boolean;
1617
+ }
1618
+ ```
1619
+ *After:*
1620
+ ```ts
1621
+ export interface DevOptions {
1622
+ json?: boolean;
1623
+ open?: boolean;
1624
+ }
1625
+ ```
1626
+
1627
+ - Changed: The `devCommand` function now accepts the `open` option and calls `openInBrowser(url)` when the Trident ready pattern is detected and `opts.open` is truthy.
1628
+ *Implementation:*
1629
+ ```ts
1630
+ if (opts.open) {
1631
+ void openInBrowser(url);
1632
+ }
1633
+ ```
1634
+
1635
+ - Refactored: Removed the duplicate `browserOpenCommand` and `openInBrowser` functions from `src/commands/generate-z2h-token.ts` and replaced them with an import of the shared `openInBrowser` utility.
1636
+ *Before (in generate-z2h-token.ts):*
1637
+ ```ts
1638
+ function browserOpenCommand(): string { /* ... */ }
1639
+ async function openInBrowser(url: string): Promise<void> {
1640
+ await execa(browserOpenCommand(), [url], { stdio: 'ignore' });
1641
+ }
1642
+ ```
1643
+ *After (in generate-z2h-token.ts):*
1644
+ ```ts
1645
+ import { openInBrowser } from '../util/open-browser';
1646
+ ```
1647
+
1648
+ - Changed: The CLI command definition for `dev` now accepts the `--open` option in addition to the existing `--json` option.
1649
+ *Before:*
1650
+ ```ts
1651
+ .action(async (opts: { json?: boolean }) => {
1652
+ ```
1653
+ *After:*
1654
+ ```ts
1655
+ .option('--open', 'open the browser automatically when the dev server is ready')
1656
+ .action(async (opts: { open?: boolean; json?: boolean }) => {
1657
+ ```
1658
+
1659
+ - Improved: The shared `openInBrowser` utility includes a `.catch()` handler that logs a user-friendly error message if the browser fails to open, preventing unhandled promise rejections.
1660
+
1661
+ ## `0.11.6` (July 5, 2026, 08:18)
1662
+
1663
+ ### Bug Fixes
1664
+
1665
+ - [#229](https://github.com/DaPulse/bigbrain-z2h/pull/229) fix(z2h-cli): better error handling across CLI and setup (@arielmonday)
1666
+ - Changed: The `create-workspace` command now handles existing workspaces gracefully instead of throwing an error. When a workspace already exists at the target path with content, the command logs a skip message and returns successfully (`ok: true`) rather than throwing an error and exiting with a failure code.
1667
+ *Before:*
1668
+ ```ts
1669
+ // Would throw: "Workspace already exists at ${home}. Remove it and try again."
1670
+ throw new Error(`Workspace already exists at ${home}. Remove it and try again.`);
1671
+ ```
1672
+ *After:*
1673
+ ```ts
1674
+ // Now returns gracefully with success status
1675
+ output(`[z2h-cli] workspace already exists at ${home} — skipping`, {
1676
+ ok: true,
1677
+ workspace: home,
1678
+ });
1679
+ return;
1680
+ ```
1681
+ - Changed: CLI main error handler now provides a more helpful error message that suggests checking for the latest version when an unexpected failure occurs. The error message format has been updated to be more actionable.
1682
+ *Before:*
1683
+ ```ts
1684
+ await fail(`main failed: ${(err as Error).message}`, { command: 'cli-main' });
1685
+ ```
1686
+ *After:*
1687
+ ```ts
1688
+ const errorMsg = err instanceof Error ? err.message : String(err);
1689
+ await fail(`main failed, check you are on latest version.\nerror: ${errorMsg}`, {
1690
+ command: 'cli-main',
1691
+ });
1692
+ ```
1693
+ - Changed: `GitConflictError` messages now include human-readable prefixes that describe whether the conflict occurred during a pull or push operation, making errors readable without JSON parsing. Previously, the error message consisted only of stringified JSON, requiring parsing to understand the context.
1694
+ *Before (pull):*
1695
+ ```ts
1696
+ throw new GitConflictError(JSON.stringify(info));
1697
+ // Message: "{\"conflictFiles\":[...],\"branch\":\"...\"}"
1698
+ ```
1699
+ *After (pull):*
1700
+ ```ts
1701
+ throw new GitConflictError(`Pull rejected: Git conflict detected: ${JSON.stringify(info)}`);
1702
+ // Message: "Pull rejected: Git conflict detected: {\"conflictFiles\":[...],\"branch\":\"...\"}"
1703
+ ```
1704
+ *Before (push):*
1705
+ ```ts
1706
+ throw new GitConflictError(JSON.stringify(info));
1707
+ // Message: "{\"conflictFiles\":[...],\"branch\":\"...\"}"
1708
+ ```
1709
+ *After (push):*
1710
+ ```ts
1711
+ throw new GitConflictError(`Push rejected: Git conflict detected: ${JSON.stringify(info)}`);
1712
+ // Message: "Push rejected: Git conflict detected: {\"conflictFiles\":[...],\"branch\":\"...\"}"
1713
+ ```
1714
+
1715
+ ## `0.11.5` (July 5, 2026, 07:11)
1716
+
1717
+ ### Bug Fixes
1718
+
1719
+ - [#228](https://github.com/DaPulse/bigbrain-z2h/pull/228) fix(z2h-cli): pin shadow trident-toolkit to workspace root version (@encodedz)
1720
+ - Fixed: `z2h-cli create` now generates apps that build successfully without manual intervention. Previously, the shadow package declared `"@mondaydotcomorg/trident-toolkit": "*"` which caused Yarn to install toolkit 3.x alongside the workspace root's 2.x, resulting in duplicate React versions (19.x and 18.x) and a singleton-package violation that aborted builds.
1721
+ - Changed: `SHADOW_DEV_DEPS` in `constants.ts` now specifies a fallback version `^2.9.25` for `@mondaydotcomorg/trident-toolkit` instead of `"*"`.
1722
+ *Before:*
1723
+ ```ts
1724
+ export const SHADOW_DEV_DEPS: Record<string, string> = {
1725
+ '@mondaydotcomorg/trident-toolkit': '*',
1726
+ };
1727
+ ```
1728
+ *After:*
1729
+ ```ts
1730
+ export const SHADOW_DEV_DEPS: Record<string, string> = {
1731
+ '@mondaydotcomorg/trident-toolkit': '^2.9.25',
1732
+ };
1733
+ ```
1734
+ - Changed: `buildShadowPkg` function signature now accepts an optional second parameter `pinnedVersions` to override shadow devDependencies with workspace root pinned versions.
1735
+ *Before:*
1736
+ ```ts
1737
+ export function buildShadowPkg(consumerPkg: ConsumerPkg): ShadowPkg
1738
+ ```
1739
+ *After:*
1740
+ ```ts
1741
+ export function buildShadowPkg(consumerPkg: ConsumerPkg, pinnedVersions: Record<string, string> = {}): ShadowPkg
1742
+ ```
1743
+ - Added: `syncShadow` now reads the workspace root's `package.json` at runtime and passes pinned versions for packages listed in `SHADOW_DEV_DEPS` to `buildShadowPkg`, ensuring the shadow's devDependencies always mirror the workspace root's version ranges.
1744
+ - Added: New helper function `readWorkspacePinnedVersions` in `sync.ts` that reads version ranges from the workspace root package.json (one directory above the consumer app) for all packages in `SHADOW_DEV_DEPS`. Returns an empty object if the root package.json is missing or unreadable.
1745
+ - Added: New helper function `shadowDevDepsChanged` in `sync.ts` that compares the existing shadow package.json devDependencies against newly computed ones to detect changes. Returns `false` if the shadow package.json doesn't exist or is unreadable.
1746
+ - Changed: `syncShadow` now clears the `.deps-hash` file and forces a `yarn install` when shadow devDependencies differ from what's about to be written, ensuring Yarn resolves corrected version ranges.
1747
+ - Added: New migration `005-fix-shadow-toolkit-wildcard.ts` that sweeps all `*/.zth/package.json` files in the workspace, replaces any `"*"` entry for `@mondaydotcomorg/trident-toolkit` with the workspace root's pinned version (or `^2.9.25` as fallback), and triggers a workspace-level `yarn install`. This migration ships in version 0.11.5 and is invoked via `z2h-cli migrate`.
1748
+ *Migration behavior:*
1749
+ ```ts
1750
+ // Reads workspace root package.json to find toolkit version
1751
+ const pkg = JSON.parse(tree.read('package.json', 'utf-8')!);
1752
+ const targetVersion = pkg.devDependencies?.['@mondaydotcomorg/trident-toolkit'] ?? '^2.9.25';
1753
+
1754
+ // Rewrites each shadow package.json with '*' entry
1755
+ if (pkg.devDependencies?.['@mondaydotcomorg/trident-toolkit'] === '*') {
1756
+ pkg.devDependencies['@mondaydotcomorg/trident-toolkit'] = targetVersion;
1757
+ tree.write(shadowPkgPath, JSON.stringify(pkg, null, 2) + '\n');
1758
+ }
1759
+ ```
1760
+
1761
+ ## `0.11.4` (July 2, 2026, 13:52)
1762
+
1763
+ ### Bug Fixes
1764
+
1765
+ - [#225](https://github.com/DaPulse/bigbrain-z2h/pull/225) feat(z2h-cli): migration 004 — remove z2h-cli from workspace deps (@encodedz)
1766
+ - Added: New migration `004-remove-z2h-cli-workspace-dep` that automatically removes `@mondaydotcomorg/z2h-cli` from workspace/consumer `package.json` files. This migration scans for the package in `dependencies` and `devDependencies` sections and removes it, cleaning up empty sections after removal. The z2h-cli is globally installed and must not be a local dependency to prevent version drift and installation conflicts.
1767
+ *Usage (automatic via auto-migrate):*
1768
+ ```ts
1769
+ // Migration runs automatically on CLI commands
1770
+ // Removes entries like:
1771
+ // "dependencies": {
1772
+ // "@mondaydotcomorg/z2h-cli": "^0.11.0"
1773
+ // }
1774
+ ```
1775
+ - Changed: The migration logic iterates over both `dependencies` and `devDependencies` sections, deleting any occurrence of `@mondaydotcomorg/z2h-cli` and removing the entire section object if it becomes empty after deletion.
1776
+ - Changed: The migration uses `@nx/devkit` Tree API to safely read and write `package.json`, ensuring changes are properly tracked and applied during the migration process.
1777
+ - Changed: Migration only runs if `package.json` exists at the root of the tree, returning early otherwise to avoid errors on projects without a package manifest.
1778
+
1779
+ ## `0.11.3` (July 2, 2026, 13:12)
1780
+
1781
+ ### Bug Fixes
1782
+
1783
+ - [#224](https://github.com/DaPulse/bigbrain-z2h/pull/224) feat(z2h-apps): add gitRemote parameter to updateApp and related inte… (@yarinmonday)
1784
+ - Added: The `updateApp` function now accepts a `gitRemote` parameter to track the Git remote repository URL when updating an app.
1785
+ *Before:*
1786
+ ```ts
1787
+ await updateApp(appName, token, nextVersion, entry);
1788
+ ```
1789
+ *After:*
1790
+ ```ts
1791
+ await updateApp(appName, token, nextVersion, entry, gitRemote);
1792
+ ```
1793
+ - Changed: The `deploy` command now passes the `gitRemote` parameter to the `updateApp` function call (line 155), ensuring the Git remote is sent to the backend when releasing app updates.
1794
+ - Changed: The HTTP request body in `updateApp` now includes the `gitRemote` field alongside `appName`, `version`, and `entry` when calling the `/z2h-cli/apps/update` API endpoint (line 224).
1795
+
1796
+ ## `0.11.2` (July 2, 2026, 09:33)
1797
+
1798
+ ### Bug Fixes
1799
+
1800
+ - [#219](https://github.com/DaPulse/bigbrain-z2h/pull/219) fix(z2h-cli): strip AWS_CREDENTIAL_EXPIRATION from env (@encodedz)
1801
+ - Fixed: AWS credential handling during git operations to prevent authentication failures caused by stale `AWS_CREDENTIAL_EXPIRATION` environment variable. The CLI now strips `AWS_CREDENTIAL_EXPIRATION` from the environment before spawning git-remote-s3 processes, preventing boto3 from rejecting valid credentials due to expired timestamp metadata.
1802
+ *Updated constant:*
1803
+ ```ts
1804
+ // Before
1805
+ const CONFLICTING_ENV_VARS = ['AWS_PROFILE'];
1806
+
1807
+ // After
1808
+ const CONFLICTING_ENV_VARS = ['AWS_PROFILE', 'AWS_CREDENTIAL_EXPIRATION'];
1809
+ ```
1810
+ This prevents 401 errors during deploy operations when the user's shell environment contains a stale `AWS_CREDENTIAL_EXPIRATION` value that conflicts with freshly minted credentials from the broker.
1811
+
1812
+ ## `0.11.1` (July 2, 2026, 09:00)
1813
+
1814
+ ### Bug Fixes
1815
+
1816
+ - [#218](https://github.com/DaPulse/bigbrain-z2h/pull/218) fix(z2h-cli): disable all local git hooks in Z2H repos (@encodedz)
1817
+ - Fixed: Git hooks are now completely disabled in Z2H repositories to prevent blocking non-interactive deploys. Previously, `overrideGlobalHooks` only bypassed hooks configured via `core.hooksPath`, but hooks injected by `init.templateDir` (which are copied directly into `.git/hooks/`) were still executed and could block automated pushes.
1818
+ - Changed: The `overrideGlobalHooks` function has been renamed to `disableLocalHooks` to better reflect its purpose. Z2H repositories are agent-driven and non-interactive, so all git hooks are now bypassed regardless of their source (global `core.hooksPath`, `init.templateDir`, or manually placed hooks).
1819
+ *Before:*
1820
+ ```ts
1821
+ await overrideGlobalHooks(dir);
1822
+ ```
1823
+ *After:*
1824
+ ```ts
1825
+ await disableLocalHooks(dir);
1826
+ ```
1827
+ - Changed: The `disableLocalHooks` function now unconditionally sets `core.hooksPath` to the empty `.zth/hooks/` directory, removing the previous conditional logic that only activated when a global hooks path was detected. This ensures all hook delivery mechanisms are bypassed.
1828
+ - Removed: The warning message that was previously shown when global git hooks were detected has been removed. The function no longer checks for a global `core.hooksPath` configuration before setting the local override.
1829
+ - Improved: The function now creates the `.zth/hooks/` directory and sets the local `core.hooksPath` configuration immediately if it doesn't already exist, simplifying the logic and ensuring consistent behavior across all hook sources.
1830
+
1831
+ ## `0.11.0` (July 2, 2026, 07:24)
1832
+
1833
+ ### New Features
1834
+
1835
+ - [#209](https://github.com/DaPulse/bigbrain-z2h/pull/209) feat(z2h-git-flow): Phases 6 & 7 — edit command + deploy git sync (@arielmonday)
1836
+ - Added: New `z2h-cli edit <app-name>` command that clones an app on first use and pulls the latest version on subsequent opens. When the app has no git remote (never deployed with git tracking), the command gracefully skips and suggests running `z2h-cli deploy` to set up git tracking.
1837
+ *Usage:*
1838
+ ```bash
1839
+ z2h-cli edit my-app
1840
+ ```
1841
+
1842
+ - Added: Three new access control commands for managing app visibility and permissions:
1843
+ - `z2h-cli grant [email]` — grants access to the current app (individual user, `--public` flag for company-wide, or both)
1844
+ - `z2h-cli revoke [email]` — revokes access from an individual user or removes public visibility
1845
+ - `z2h-cli transfer-owner [email]` — transfers ownership of the current app to another user
1846
+ *Example:*
1847
+ ```bash
1848
+ z2h-cli grant --public # Make app visible to all employees
1849
+ z2h-cli grant user@monday.com --level editor # Grant editor access to specific user
1850
+ z2h-cli revoke --public # Remove public access
1851
+ z2h-cli transfer-owner newowner@monday.com
1852
+ ```
1853
+
1854
+ - Changed: The `z2h-cli deploy` command now accepts `--remote` and `--repo-url` options on first deploy to initialize the git remote. These options are only valid for apps without an existing remote; passing them for apps that already have a remote will throw an error.
1855
+ *First deploy with S3 remote:*
1856
+ ```bash
1857
+ z2h-cli deploy --remote s3
1858
+ ```
1859
+ *First deploy with GitHub remote:*
1860
+ ```bash
1861
+ z2h-cli deploy --remote github --repo-url https://github.com/org/repo.git
1862
+ ```
1863
+
1864
+ - Changed: The `deploy` command now performs git synchronization before building and uploading. It guards against uncommitted changes with `guardCleanTree`, pulls from the remote before starting, and pushes to the remote **before** uploading to S3. This ensures that a rejected push (divergence detected) halts the deploy before any artifacts go live.
1865
+
1866
+ - Changed: First deploy now prompts for app visibility in interactive mode (TTY). Users are asked "Make <app> public to all monday.com employees? (y/N)". Non-interactive runs (`--json` or no TTY) default to private. The visibility choice is passed to the new `/z2h-cli/apps/register` endpoint.
1867
+
1868
+ - Added: The `deploy` command now acquires an explicit per-app deploy lock via a new `/z2h-cli/lock/acquire` broker endpoint before uploading. A 409 response indicates another deploy is in progress and throws a user-friendly error. The lock is released after manifest write in a best-effort fashion (2-minute TTL backstop on the backend).
1869
+
1870
+ - Changed: The deploy version is now fetched from a dedicated `/z2h-cli/apps/version` broker endpoint before requesting STS credentials. Version derivation has been moved out of the manifest-read logic and onto its own endpoint for cleaner separation.
1871
+
1872
+ - Changed: The `registerApp` function now accepts additional parameters `visibility` ("public" or "private") and `gitRemote` (string) and sends them in the request body to `/z2h-cli/apps/register`.
1873
+
1874
+ - Added: New `updateApp` function for releasing subsequent versions (v2+). The deploy flow now branches: v1 calls `registerApp` (creates the app row + owner grant), later versions call `updateApp` (releases onto existing app).
1875
+
1876
+ - Added: Git conflict detection and structured error surfacing. When `pullAndResolve` or `pushToRemote` encounter a divergence (non-fast-forward pull or rejected push), they now throw `GitConflictError` with a JSON payload containing `localCommits`, `remoteCommits`, and `conflictingFiles` arrays. This enables LLM-based conflict resolution in the Z2H skill layer.
1877
+ *Example error payload:*
1878
+ ```json
1879
+ {
1880
+ "localCommits": ["a1b2c3d Fix button color"],
1881
+ "remoteCommits": ["e4f5g6h Update header layout"],
1882
+ "conflictingFiles": ["src/App.tsx"]
1883
+ }
1884
+ ```
1885
+
1886
+ - Added: New `guardCleanTree` function that throws an error if the working tree has uncommitted changes. Called before git sync in deploy to ensure the tree is clean.
1887
+
1888
+ - Added: New `pushToRemote` function that pushes the local master branch to origin. On a rejected (non-fast-forward) push, it gathers conflict info and throws `GitConflictError`. This stops the deploy before the bundle upload if someone deployed during the build.
1889
+
1890
+ - Changed: `pullAndResolve` now accepts an optional `env` parameter (git environment variables) and gracefully handles first deploy scenarios where the remote exists but has no commits yet. On pull failure, it backs up dirty state and throws `GitConflictError` with conflict details.
1891
+
1892
+ - Changed: `cloneRepo` now accepts an optional `env` parameter and automatically calls `overrideGlobalHooks` after cloning to prevent global git hooks from interfering with Z2H's non-interactive operations.
1893
+
1894
+ - Added: New `overrideGlobalHooks` function that detects if the user has a global `core.hooksPath` configured and overrides it locally for the Z2H project (sets `core.hooksPath` to `.zth/hooks` in the local git config). This prevents global hooks like "prevent-push-to-master" from blocking automated pushes while leaving other repos protected.
1895
+
1896
+ - Added: New utility module `util/git/git-env.ts` with `resolveGitEnv` function. For S3-backed remotes, it mints short-lived broker credentials and returns them as `AWS_*` environment variables for `git-remote-s3`. For GitHub remotes, it returns `undefined` (user's own git credentials are used).
1897
+
1898
+ - Added: New utility module `util/git/remote-options.ts` with shared remote validation logic. Exports `REMOTE_TYPES` constant, `RemoteType` type, `validateRemoteOptions` function (validates `--remote` and `--repo-url` flags), and `resolveRemoteUrl` function (converts options to a git remote URL).
1899
+
1900
+ - Added: New utility module `util/broker/app.ts` with `fetchApp` function. Fetches a single app's current state (including `gitRemote`) from the broker. Returns `null` for apps that have never been deployed (404 response).
1901
+
1902
+ - Changed: The `create` command now uses the broker's `/z2h-cli/apps/<appName>` endpoint to check for name collisions instead of reading the S3 manifest directly. This shifts app registration logic to the backend.
1903
+
1904
+ - Changed: The `create` command now validates remote options using the shared `validateRemoteOptions` function and resolves the remote URL with `resolveRemoteUrl`. The validation and remote URL logic has been extracted and reused.
1905
+
1906
+ - Changed: The `create` command no longer performs a pre-build (`buildCommand`) after scaffolding. Instead, it runs best-effort `prepareShadow` to wire the workspace. The pre-build step was removed to speed up project creation; build happens on first `dev` or `deploy`.
1907
+
1908
+ - Changed: `setupS3Client` now accepts an `AwsCredentialIdentity` object directly instead of an `{ appName }` options object. The caller is responsible for obtaining credentials (via `brokerCredentialProvider` or other means) before calling `setupS3Client`.
1909
+ *Before:*
1910
+ ```typescript
1911
+ setupS3Client({ appName: 'my-app' });
1912
+ ```
1913
+ *After:*
1914
+ ```typescript
1915
+ const creds = await brokerCredentialProvider({ appName: 'my-app' })();
1916
+ setupS3Client(creds);
1917
+ ```
1918
+
1919
+ - Added: New `fetchDeployVersion` function in `util/auth/broker-credential-provider.ts` that reserves the version this deploy will write to via a new `/z2h-cli/apps/version` endpoint. This separates version derivation from the STS credentials call.
1920
+
1921
+ - Changed: The broker request logic has been extracted into a shared `postToBroker` helper function. Both `fetchDeployVersion` and `fetchStsOnce` (renamed from `fetchCredentialsOnce`) now use this helper, which injects the authorization token and routing headers.
1922
+
1923
+ - Added: `postToBroker` and all broker HTTP calls now include `routingHeaders()` in request headers. This returns a `Baggage: routingKey=<value>` header when `Z2H_BROKER_BASE_URL` is set (for monday-mirror routing in development environments).
1924
+
1925
+ - Added: New `routingHeaders` function in `constants.ts` that returns routing headers for monday-mirror when `Z2H_ROUTING_KEY` is set. Returns an empty object in production.
1926
+
1927
+ - Added: New `getCwdAppName` utility function in `util/app-name.ts` that reads the package name from `package.json` in the current working directory. Returns `undefined` if the file doesn't exist or can't be parsed.
1928
+
1929
+ - Changed: `prepareShadow` now accepts an optional `consumerDir` parameter (defaults to `process.cwd()`) to allow shadow preparation for a specific directory without changing the process working directory.
1930
+
1931
+ - Changed: The CLI now strips conflicting environment variables (`AWS_PROFILE` and potentially others) at startup via `stripConflictingEnvVars` to prevent user AWS profiles from interfering with Z2H broker credentials.
1932
+
1933
+ - Changed: The `create-workspace` command description now uses `getWorkspaceHome()` instead of hardcoding `~/zth-projects/` to reflect the actual workspace location.
1934
+
1935
+ - Changed: Git operations have been refactored to use helper functions `execGit` and `execGitLines` that accept an optional `env` parameter for injecting AWS credentials or other environment variables.
1936
+
1937
+ - Changed: The consumer app template `CLAUDE.md` now includes a new "App Visibility" section documenting that apps are private by default and explaining how to use `z2h-cli grant --public` and `z2h-cli revoke --public` to control visibility.
1938
+
1939
+ - Removed: The manifest read/write logic (`readManifest`, `writeManifest`, `upsertEntry`, `nextVersion`) has been removed from the deploy flow. The broker backend now owns the manifest and app version state.
1940
+
1941
+ ## `0.10.1` (July 1, 2026, 05:42)
1942
+
1943
+ ### Bug Fixes
1944
+
1945
+ - [#211](https://github.com/DaPulse/bigbrain-z2h/pull/211) feat(z2h): machine-user auth bypass for headless CLI operations (@encodedz)
1946
+ - Added: Machine-user authentication support via `Z2H_AUTH_TOKEN` environment variable. When set, the CLI will use this JWT token for authentication instead of the file-based token flow, enabling headless/automated deployments.
1947
+ *Usage:*
1948
+ ```bash
1949
+ export Z2H_AUTH_TOKEN="eyJhbG...<your-jwt>..."
1950
+ z2h-cli deploy
1951
+ ```
1952
+ - Changed: `readZthAuth()` function now checks `Z2H_AUTH_TOKEN` environment variable first before reading from the file system. If the environment variable is present, it validates the JWT format (three dot-separated segments) and returns it directly, bypassing file I/O.
1953
+ *Before:*
1954
+ ```ts
1955
+ // Always read from Z2H_AUTH_FILE
1956
+ export async function readZthAuth(): Promise<ZthAuth> {
1957
+ if (!(await pathExists(Z2H_AUTH_FILE))) {
1958
+ throw new Z2hAuthMissingError(Z2H_AUTH_FILE);
1959
+ }
1960
+ const parsed = await readJson(Z2H_AUTH_FILE);
1961
+ // ...
1962
+ }
1963
+ ```
1964
+ *After:*
1965
+ ```ts
1966
+ export async function readZthAuth(): Promise<ZthAuth> {
1967
+ // Check env var first
1968
+ if (process.env.Z2H_AUTH_TOKEN) {
1969
+ const token = process.env.Z2H_AUTH_TOKEN;
1970
+ if (!/^[\w-]+\.[\w-]+\.[\w-]+$/.test(token)) {
1971
+ throw new Error('Z2H_AUTH_TOKEN is not a valid JWT...');
1972
+ }
1973
+ return { token };
1974
+ }
1975
+ // Fall back to file
1976
+ if (!(await pathExists(Z2H_AUTH_FILE))) {
1977
+ throw new Z2hAuthMissingError(Z2H_AUTH_FILE);
1978
+ }
1979
+ // ...
1980
+ }
1981
+ ```
1982
+ - Changed: `tryReadAuthTokenSync()` function now checks `Z2H_AUTH_TOKEN` environment variable first before attempting synchronous file read, maintaining consistency with async version.
1983
+ *After:*
1984
+ ```ts
1985
+ export function tryReadAuthTokenSync(): string | null {
1986
+ if (process.env.Z2H_AUTH_TOKEN) {
1987
+ return process.env.Z2H_AUTH_TOKEN;
1988
+ }
1989
+ // Fall back to file read
1990
+ // ...
1991
+ }
1992
+ ```
1993
+ - Added: New utility function `getMachineAppName()` in `util/machine-identity.ts` that reads `APP_NAME` environment variable to identify machine/service deployers (returns `undefined` for human users).
1994
+ *Implementation:*
1995
+ ```ts
1996
+ export function getMachineAppName(): string | undefined {
1997
+ return process.env.APP_NAME || undefined;
1998
+ }
1999
+ ```
2000
+ - Changed: `deployCommand` now uses `getMachineAppName()` for the `deployedBy` audit field, falling back to `os.userInfo().username` for human users. This enables proper audit trails when deployments are triggered by automated services.
2001
+ *Before:*
2002
+ ```ts
2003
+ const deployedBy = os.userInfo().username;
2004
+ ```
2005
+ *After:*
2006
+ ```ts
2007
+ const deployedBy = getMachineAppName() ?? os.userInfo().username;
2008
+ ```
2009
+
2010
+ ## `0.10.0` (June 30, 2026, 13:46)
2011
+
2012
+ ### New Features
2013
+
2014
+ - [#202](https://github.com/DaPulse/bigbrain-z2h/pull/202) feat(z2h-cli): Phase 5 — create with required remote choice (@arielmonday)
2015
+ - **Breaking Change**: The `create` command now requires the `--remote` flag with a value of either `s3` (shared storage) or `github` (GitHub repository). Attempting to run `create` without this flag will result in an error: "--remote is required. Use --remote=s3 (shared storage) or --remote=github (your GitHub repo)."
2016
+ *Before:*
2017
+ ```bash
2018
+ z2h-cli create my-app
2019
+ ```
2020
+ *After:*
2021
+ ```bash
2022
+ z2h-cli create my-app --remote=s3
2023
+ # or
2024
+ z2h-cli create my-app --remote=github --repo-url=https://github.com/user/repo.git
2025
+ ```
2026
+ - **Breaking Change**: When using `--remote=github`, the `--repo-url` parameter is now required and must specify the GitHub repository URL. Omitting `--repo-url` will result in an error: "--repo-url is required when using --remote=github."
2027
+ *Usage:*
2028
+ ```bash
2029
+ z2h-cli create my-app --remote=github --repo-url=https://github.com/user/my-app.git
2030
+ ```
2031
+ - Added: New `REMOTE_TYPES` constant exported from `src/commands/create.ts` as a readonly tuple `['s3', 'github']`, along with a derived `RemoteType` type. This ensures remote type validation is centralized.
2032
+ - Added: New `CreateOptions` interface properties: `remote?: RemoteType` and `repoUrl?: string` to support the remote selection at creation time.
2033
+ - Changed: The `create` command now initializes a local git repository and configures the specified remote during app creation, but **does not push** the initial commit. The first push is deferred to the first `deploy` command.
2034
+ - Added: New `initRepo` function in `src/util/git/repo.ts` that initializes a git repository, commits all files with "Initial commit", and adds the specified remote as `origin`. This function does not push to the remote.
2035
+ *Signature:*
2036
+ ```ts
2037
+ export async function initRepo(dir: string, remote: string): Promise<void>
2038
+ ```
2039
+ - Removed: The `initAndPush` function has been removed from `src/util/git/repo.ts`. Use `initRepo` for creation-time repository setup (no push) instead.
2040
+ - Changed: The `defaultS3Remote` function now applies `mfAppName` transformation to the app name before constructing the S3 remote URL.
2041
+ *Before:*
2042
+ ```ts
2043
+ return `s3://${BUCKET_WRITE_NAME}/${app}/git`;
2044
+ ```
2045
+ *After:*
2046
+ ```ts
2047
+ return `s3://${BUCKET_WRITE_NAME}/${mfAppName(app)}/git`;
2048
+ ```
2049
+ - Added: New `getRemoteUrl` function in `src/util/git/repo.ts` that retrieves the `origin` remote URL from a git repository, returning `undefined` if the remote is not configured or an error occurs.
2050
+ *Signature:*
2051
+ ```ts
2052
+ export async function getRemoteUrl(dir: string): Promise<string | undefined>
2053
+ ```
2054
+ - Changed: The `deploy` command now captures the git remote URL via `getRemoteUrl` and includes it in the `ManifestEntry` under the `gitRemote` property.
2055
+ - Changed: The `ManifestEntry` interface now includes an optional `gitRemote?: string` property, while the `AssetManifestFile` interface no longer has a required `gitRemote: string` field. This reflects that `gitRemote` is determined at deploy time, not build time.
2056
+ *Before (`AssetManifestFile`):*
2057
+ ```ts
2058
+ export interface AssetManifestFile {
2059
+ // ...
2060
+ gitRemote: string;
2061
+ }
2062
+ ```
2063
+ *After (`ManifestEntry`):*
2064
+ ```ts
2065
+ export interface ManifestEntry extends AssetManifestFile {
2066
+ version: number;
2067
+ url: string;
2068
+ deployedBy: string;
2069
+ gitRemote?: string;
2070
+ }
2071
+ ```
2072
+ - Changed: The `commitDetailedAndPush` function in `src/util/git/repo.ts` now verifies that the current branch is `master` before attempting to deploy. If the user is on a different branch, it throws an error: "expected branch \"master\" but you are on \"<branch>\" — switch back before deploying."
2073
+ - Changed: The `commitDetailedAndPush` function now checks if there are any staged changes before committing. If no files have changed since the last deploy, it throws an error: "Nothing new to deploy — no files have changed since the last deploy."
2074
+ - Changed: The `commitDetailedAndPush` function now uses `git push -u origin master` instead of `git push`, ensuring the upstream branch is set on both the first push and subsequent pushes.
2075
+ - Changed: The error handling in `commitDetailedAndPush` now checks for `[rejected]` or `non-fast-forward` patterns in the error message to throw a `GitConflictError` with the message "push rejected — remote has new commits". Other git errors are re-thrown as-is.
2076
+ - Changed: The `create` command action handler in `src/index.ts` now accepts `remote?: string` and `repoUrl?: string` options and casts them to `CreateOptions` when invoking `createCommand`.
2077
+ - Changed: The `z2h_app_created` tracking event now includes a `remote` property in its metadata, defaulting to `'unknown'` if not provided.
2078
+ - Changed: The `create` command now returns additional fields in its JSON output: `remote: opts.remote` and `gitRemote: string` (the resolved remote URL).
2079
+
2080
+ ## `0.9.1` (June 30, 2026, 13:08)
2081
+
2082
+ ### Improvements
2083
+
2084
+ - [#212](https://github.com/DaPulse/bigbrain-z2h/pull/212) fix(z2h): init DB in apps migration + dual-write apps on deploy (@EranZidkiya)
2085
+ - Added: Automatic app registration to RDS database after successful deploy. The `deploy` command now calls a new `registerApp()` function that sends a POST request to `/z2h-cli/apps/register` with the app name, version, and manifest entry immediately after updating the S3 manifest.
2086
+ *New behavior:*
2087
+ ```ts
2088
+ // After manifest write
2089
+ info(`registering app "${appName}" → v${version}`);
2090
+ await registerApp(appName, token, version, entry);
2091
+ ```
2092
+ - Added: New internal `registerApp()` function that POSTs app metadata to the backend broker endpoint. The function sends app name, version, and manifest entry as JSON, and throws an error if registration fails.
2093
+ *Usage:*
2094
+ ```ts
2095
+ async function registerApp(appName: string, token: string, version: number, entry: ManifestEntry): Promise<void> {
2096
+ const res = await fetch(`${brokerBaseUrl()}/z2h-cli/apps/register`, {
2097
+ method: 'POST',
2098
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
2099
+ body: JSON.stringify({ appName, version, entry }),
2100
+ });
2101
+ if (!res.ok) {
2102
+ const text = await res.text();
2103
+ throw new Error(`App registration failed (${res.status}): ${text.slice(0, 1024)}`);
2104
+ }
2105
+ }
2106
+ ```
2107
+ - Changed: Deploy workflow now performs dual-write operation. After uploading bundle to S3 and updating the manifest, the CLI also registers the app in the RDS database, ensuring both storage systems remain synchronized during the migration period before RDS becomes the sole source of truth.
2108
+ - Changed: Deploy command now includes error handling for app registration failures. If the backend registration endpoint returns a non-OK status, the deploy command will throw an error with the HTTP status code and response text (truncated to 1024 characters).
2109
+
2110
+ ## `0.9.0` (June 30, 2026, 10:14)
2111
+
2112
+ ### New Features
2113
+
2114
+ - [#213](https://github.com/DaPulse/bigbrain-z2h/pull/213) fix: trigger CLI release (@arielmonday)
2115
+ - Changed: Import statement ordering in `auto-migrate.ts` to follow conventional import organization patterns. The `fs-extra` import is now placed before the `execa` import, aligning with alphabetical ordering conventions for external package imports. This is a non-functional code style improvement with no impact on runtime behavior or public APIs.
2116
+
2117
+ ## `0.8.0` (June 30, 2026, 09:49)
2118
+
2119
+ ### Improvements
2120
+
2121
+ - [#196](https://github.com/DaPulse/bigbrain-z2h/pull/196) feat(z2h-cli): build app after create + improve setup README (@arielmonday)
2122
+ - Changed: The `createCommand` function now automatically builds the app after scaffolding and dependency installation, eliminating cold-start build delays on first `dev` run. If the pre-build fails, a warning is logged but the process continues.
2123
+ - Changed: All command functions (`buildCommand`, `cleanCommand`, `createWorkspaceCommand`, `createCommand`, `deployCommand`, `devCommand`, `migrateCommand`) now have optional options parameters with default values `{}` instead of required parameters.
2124
+ *Before:*
2125
+ ```ts
2126
+ export async function buildCommand(opts: BuildOptions): Promise<void>
2127
+ export async function createCommand(appName: string, opts: CreateOptions): Promise<void>
2128
+ ```
2129
+ *After:*
2130
+ ```ts
2131
+ export async function buildCommand(opts: BuildOptions = {}): Promise<void>
2132
+ export async function createCommand(appName: string, opts: CreateOptions = {}): Promise<void>
2133
+ ```
2134
+ - Added: All build/dev/deploy/clean commands now include documentation comments clarifying they must be run from the consumer app directory because they use `process.cwd()` to locate the app.
2135
+ - Changed: The `createCommand` function now changes the working directory to the app directory before calling `buildCommand`, then restores the previous working directory after the build completes or fails.
2136
+ - Changed: The `devCommand` function now sets `NPM_TOKEN=FAKE_TOKEN` in the environment when starting the Trident dev server, preventing startup failures when the environment variable is not set. This ensures deterministic behavior across all users regardless of their local NPM token configuration.
2137
+ *Implementation:*
2138
+ ```ts
2139
+ const server = execa('yarn', ['start'], {
2140
+ cwd: ctx.paths.shadowDir,
2141
+ stdio: ['inherit', 'pipe', 'inherit'],
2142
+ env: { ...process.env, NPM_TOKEN: 'FAKE_TOKEN' },
2143
+ });
2144
+ ```
2145
+ - Changed: The `releaseLockBestEffort` function in the deploy command now logs informational and warning messages for successful and failed lock releases respectively, improving observability during deployment.
2146
+ - Changed: Import statement ordering in `auto-migrate.ts` has been reorganized for consistency (external packages before Node.js built-ins).
2147
+ - Added: The `createCommand` function now imports and uses `buildCommand` from `./build` to enable the post-scaffold build step.
2148
+
2149
+ ### New Features
2150
+
2151
+ - [#191](https://github.com/DaPulse/bigbrain-z2h/pull/191) feat(z2h-git-flow): Phase 4 — git plumbing library (@arielmonday)
2152
+ - Added: New `GitConflictError` class for handling git conflict scenarios during remote operations.
2153
+ ```ts
2154
+ throw new GitConflictError('push rejected — remote has new commits');
2155
+ ```
2156
+ - Added: `defaultS3Remote(app: string)` function to construct S3-backed git remote URLs for Z2H applications.
2157
+ ```ts
2158
+ const remote = defaultS3Remote('my-app');
2159
+ // Returns: 's3://prod-use1-bigbrain-zth-mf-assets/my-app/git'
2160
+ ```
2161
+ - Added: `initAndPush(dir: string, remote: string)` function to initialize a new git repository with required `.gitignore` entries (`node_modules/`, `.zth/`, `build/`), create an initial commit on the `master` branch, configure the remote origin, and push to S3.
2162
+ ```ts
2163
+ await initAndPush('/path/to/app', 's3://bucket/app/git');
2164
+ ```
2165
+ - Added: `cloneRepo(remote: string, dir: string)` function to clone a git repository from an S3 remote URL to a local directory.
2166
+ ```ts
2167
+ await cloneRepo('s3://bucket/app/git', '/path/to/local/dir');
2168
+ ```
2169
+ - Added: `safeBackupIfDirty(dir: string)` function that creates a timestamped backup copy of a repository directory if it contains uncommitted changes (detected via `git status --porcelain`). The backup directory is created as `<appName>.backup-<sha>` in the parent directory.
2170
+ ```ts
2171
+ await safeBackupIfDirty('/path/to/app');
2172
+ // Creates: /path/to/app.backup-abc123 (if dirty)
2173
+ ```
2174
+ - Added: `pullAndResolve(dir: string)` function to perform a fast-forward-only `git pull` from the remote. Throws `GitConflictError` if the pull fails (e.g., divergent branches). Phase 7 TODO comment indicates future support for automatic conflict resolution via `resolveDivergence(dir)`.
2175
+ ```ts
2176
+ try {
2177
+ await pullAndResolve('/path/to/app');
2178
+ } catch (err) {
2179
+ if (err instanceof GitConflictError) {
2180
+ // Handle conflict: 'This app changed while you were working'
2181
+ }
2182
+ }
2183
+ ```
2184
+ - Added: `remoteHead(dir: string)` function to fetch the current commit SHA of the `refs/heads/master` branch from the remote origin using `git ls-remote`.
2185
+ ```ts
2186
+ const sha = await remoteHead('/path/to/app');
2187
+ // Returns: '1a2b3c4d5e6f...'
2188
+ ```
2189
+ - Added: `localHead(dir: string)` function to retrieve the current local HEAD commit SHA using `git rev-parse HEAD`.
2190
+ ```ts
2191
+ const sha = await localHead('/path/to/app');
2192
+ // Returns: '1a2b3c4d5e6f...'
2193
+ ```
2194
+ - Added: `commitDetailedAndPush(dir: string, version: number)` function to stage all changes, create a commit with a version-prefixed message listing modified files (truncated to 5 files + count), and push to the remote. Throws `GitConflictError` if the push is rejected due to remote changes. Phase 7 TODO comment indicates future replacement of the commit message builder with an LLM-generated summary.
2195
+ ```ts
2196
+ await commitDetailedAndPush('/path/to/app', 42);
2197
+ // Commit message example: 'v42: deploy — src/index.tsx, README.md (+3 more)'
2198
+ ```
2199
+ - Added: Internal `buildCommitMessage(dir: string, version: number)` function that generates a commit message by running `git status --short`, extracting up to 5 changed file paths, and formatting them as `v<version>: deploy — <file1>, <file2>, ...`. Files beyond the first 5 are summarized as `(+N more)`.
2200
+ - Added: Internal `ensureGitignore(dir: string)` function that reads the existing `.gitignore` file (if present) and appends any missing required entries (`node_modules/`, `.zth/`, `build/`) to ensure Z2H projects always exclude build artifacts and dependencies from version control.
2201
+ - Changed: The `AssetManifestFile` interface in `packages/z2h-cli/src/util/manifest.ts` now includes a required `gitRemote: string` field to store the S3 remote URL for each Z2H application.
2202
+ ```ts
2203
+ interface AssetManifestFile {
2204
+ // ... existing fields ...
2205
+ gitRemote: string; // New required field
2206
+ }
2207
+ ```
2208
+ - Changed: The `ManifestEntry` interface (which extends `AssetManifestFile`) now inherits the new `gitRemote` field, making it available to all manifest entry consumers.
2209
+ - [#179](https://github.com/DaPulse/bigbrain-z2h/pull/179) feat(z2h-cli): Phase 3 — per-app deploy lock via Redis (@arielmonday)
2210
+ - Added: Import of `brokerBaseUrl` from `../constants` to support new deploy lock release endpoint communication.
2211
+ - Changed: The `deployCommand` function now reads and stores the authentication token from `readZthAuth()` at the beginning of the deployment process.
2212
+ *Before:*
2213
+ ```ts
2214
+ await readZthAuth();
2215
+ ```
2216
+ *After:*
2217
+ ```ts
2218
+ const { token } = await readZthAuth();
2219
+ ```
2220
+ - Added: Deploy lock release mechanism in a try-finally block wrapping the S3 upload and manifest update operations. The lock is automatically released after deployment completes (success or failure) via a call to `releaseLockBestEffort`.
2221
+ *New structure:*
2222
+ ```ts
2223
+ try {
2224
+ // Lock is acquired here — uploadDir triggers the STS credential provider on first S3 call
2225
+ info(`uploading build → s3://${BUCKET_WRITE_NAME}/${keyPrefix}/`);
2226
+ await uploadDir(paths.shadowBuild, keyPrefix);
2227
+ info(`updating manifest entry "${appName}" → v${version}`);
2228
+ await writeManifest(upsertEntry(manifest, appName, entry));
2229
+ } finally {
2230
+ await releaseLockBestEffort(appName, token);
2231
+ }
2232
+ ```
2233
+ - Added: New private function `releaseLockBestEffort(appName: string, token: string): Promise<void>` that makes a POST request to `/z2h-cli/lock/release` endpoint to release the per-app deploy lock acquired during credential minting. The function includes error suppression (empty catch block) since lock release is best-effort with a 5-minute TTL backstop on the server side.
2234
+ *Usage:*
2235
+ ```ts
2236
+ async function releaseLockBestEffort(appName: string, token: string): Promise<void> {
2237
+ try {
2238
+ await fetch(`${brokerBaseUrl()}/z2h-cli/lock/release`, {
2239
+ method: 'POST',
2240
+ headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
2241
+ body: JSON.stringify({ appName }),
2242
+ });
2243
+ } catch {
2244
+ // best-effort — the 5-min TTL backstop handles failures
2245
+ }
2246
+ }
2247
+ ```
2248
+ - Changed: Deploy lock is now acquired automatically when `uploadDir` triggers the STS credential provider on the first S3 call, and released in the finally block regardless of deployment success or failure. This prevents concurrent deployments of the same app and ensures lock cleanup even if the deployment fails.
2249
+
2250
+ ### Bug Fixes
2251
+
2252
+ - [#167](https://github.com/DaPulse/bigbrain-z2h/pull/167) fix(z2h-cli): prevent infinite self-update loop + skill and setup improvements (@arielmonday)
2253
+ - Fixed: Infinite self-update loop prevented by adding environment guard to `selfUpdate()` function. The function now sets `Z2H_UPDATE_RUNNING=1` on the spawned child process environment before detaching `update.sh`, which prevents `z2h-cli migrate` from triggering additional update chains. The guard is inherited by every `z2h-cli` invocation inside the update script, breaking the cycle without affecting the user's shell environment.
2254
+ *Technical detail:* The `execa` call in `packages/z2h-cli/src/index.ts:24` now includes the environment variable in the spawned process, though the diff shown only reflects formatting changes to the `execa` options object structure.
2255
+
2256
+ - Changed: App template `CLAUDE.md` now enforces stricter backend modification rules. The data-fetching hierarchy section explicitly states that backend changes to `bigbrain-zth` are "not in scope — no modifications, no suggestions, no workarounds" (previously only implied no modifications were in scope).
2257
+ *Location:* `packages/z2h-cli/src/templates/app/CLAUDE.md:30`
2258
+
2259
+ - Added: Query storage rule in app template `CLAUDE.md`. All SQL query strings must now be stored in `src/queries.ts` rather than inline in components or hooks, with imports required from that centralized location.
2260
+ *New section added at:* `packages/z2h-cli/src/templates/app/CLAUDE.md:32`
2261
+ *Usage example:*
2262
+ ```ts
2263
+ // src/queries.ts
2264
+ export const GET_USERS = `SELECT * FROM users WHERE active = true`;
2265
+
2266
+ // component file
2267
+ import { GET_USERS } from './queries';
2268
+ ```
2269
+
2270
+ - Fixed: Claude Code session stop hook in app template now properly kills entire process group instead of just the parent process. The stop hook command in `claude-settings.json` now retrieves the process group ID and uses `kill -- -$PGID` to terminate all child processes spawned by the dev server.
2271
+ *Before:*
2272
+ ```bash
2273
+ kill $(cat .zth/dev.pid) 2>/dev/null
2274
+ ```
2275
+ *After:*
2276
+ ```bash
2277
+ PGID=$(ps -o pgid= -p $(cat .zth/dev.pid) 2>/dev/null | tr -d ' '); [ -n "$PGID" ] && kill -- -$PGID 2>/dev/null
2278
+ ```
2279
+ *Location:* `packages/z2h-cli/src/templates/app/claude-settings.json:13`
2280
+
2281
+ ## `0.7.2` (June 9, 2026, 07:36)
2282
+
2283
+ ### Bug Fixes
2284
+
2285
+ - [#150](https://github.com/DaPulse/bigbrain-z2h/pull/150) Revert "Bugfix/yarin/fix css overrides host application when embedded… (@yarinmonday)
2286
+ - Reverted: Removed the Vibe core tokens import from the shadow DOM wrapper template that was introduced in PR #148. The import `import '@vibe/core/tokens';` has been restored at the top of the generated wrapper component. This ensures that Vibe design tokens (CSS variables for colors, spacing, typography, etc.) are properly loaded in the shadow DOM context, preventing style inheritance issues from the host application when the consumer app is embedded. Without this import, consumer apps may experience missing or incorrect styling when rendered within the BigBrain host environment.
2287
+ *After this change, the generated wrapper includes:*
2288
+ ```ts
2289
+ import '@vibe/core/tokens';
2290
+ import ConsumerApp from '../../src/index';
2291
+ ```
2292
+
2293
+ ## `0.7.1` (June 9, 2026, 07:21)
2294
+
2295
+ ### Bug Fixes
2296
+
2297
+ - [#155](https://github.com/DaPulse/bigbrain-z2h/pull/155) fix(z2h-cli): await trackEvent before process.exit so events land in Doorman (@arielmonday)
2298
+ - Fixed: The `trackEvent` function is now `async` and awaited at all call sites to ensure telemetry events complete before the process exits. Previously, `process.exit()` would terminate the process before the HTTP request to Doorman completed, causing events to be lost.
2299
+ *Before:*
2300
+ ```ts
2301
+ export function trackEvent(name: string, data: Record<string, unknown>): void {
2302
+ void fetch(DOORMAN_URL, {
2303
+ method: 'POST',
2304
+ // ...
2305
+ }).catch(() => {});
2306
+ }
2307
+ ```
2308
+ *After:*
2309
+ ```ts
2310
+ export async function trackEvent(name: string, data: Record<string, unknown>): Promise<void> {
2311
+ await fetch(DOORMAN_URL, {
2312
+ method: 'POST',
2313
+ // ...
2314
+ }).catch(() => {});
2315
+ }
2316
+ ```
2317
+ - Fixed: The `fail` function is now `async` and returns `Promise<never>` instead of `never`, ensuring that the `trackEvent` call inside `fail` completes before the process exits.
2318
+ *Before:*
2319
+ ```ts
2320
+ export function fail(message: string, payload: Record<string, unknown>, exitCode = 1): never {
2321
+ // ...
2322
+ trackEvent('z2h_cli_error', { action: (payload.command as string) ?? 'unknown', error: message });
2323
+ process.exit(exitCode);
2324
+ }
2325
+ ```
2326
+ *After:*
2327
+ ```ts
2328
+ export async function fail(message: string, payload: Record<string, unknown>, exitCode = 1): Promise<never> {
2329
+ // ...
2330
+ await trackEvent('z2h_cli_error', { action: payload.command ?? 'unknown', error: message });
2331
+ process.exit(exitCode);
2332
+ }
2333
+ ```
2334
+ - Changed: All `fail()` invocations in `packages/z2h-cli/src/index.ts` are now awaited in command error handlers (for `build`, `dev`, `clean`, `deploy`, `create-workspace`, `generate-z2h-token`, `create`, and `migrate` commands) to ensure telemetry events are sent before exit.
2335
+ *Before:*
2336
+ ```ts
2337
+ } catch (err) {
2338
+ fail(`build failed: ${(err as Error).message}`, { command: 'build' }, 2);
2339
+ }
2340
+ ```
2341
+ *After:*
2342
+ ```ts
2343
+ } catch (err) {
2344
+ await fail(`build failed: ${(err as Error).message}`, { command: 'build' }, 2);
2345
+ }
2346
+ ```
2347
+ - Changed: The main entry point catch handler now routes through the `fail` function instead of calling `process.exit(1)` directly, ensuring all errors are tracked consistently.
2348
+ *Before:*
2349
+ ```ts
2350
+ void main()
2351
+ // ...
2352
+ .catch((err: unknown) => {
2353
+ errorLog(`main failed: ${(err as Error).message}`);
2354
+ process.exit(1);
2355
+ });
2356
+ ```
2357
+ *After:*
2358
+ ```ts
2359
+ void main()
2360
+ // ...
2361
+ .catch(async (err: unknown) => {
2362
+ await fail(`main failed: ${(err as Error).message}`, { command: 'cli-main' });
2363
+ });
2364
+ ```
2365
+ - Changed: The `trackDuration` function now awaits the `trackEvent` call after the wrapped function completes, ensuring duration events are sent before the process exits.
2366
+ *Before:*
2367
+ ```ts
2368
+ export async function trackDuration<T>(
2369
+ eventName: string,
2370
+ fn: () => Promise<T>,
2371
+ data: Record<string, unknown>
2372
+ ): Promise<T> {
2373
+ const start = Date.now();
2374
+ const result = await fn();
2375
+ trackEvent(eventName, { ...data, duration_ms: Date.now() - start });
2376
+ return result;
2377
+ }
2378
+ ```
2379
+ *After:*
2380
+ ```ts
2381
+ export async function trackDuration<T>(
2382
+ eventName: string,
2383
+ fn: () => Promise<T>,
2384
+ data: Record<string, unknown>
2385
+ ): Promise<T> {
2386
+ const start = Date.now();
2387
+ const result = await fn();
2388
+ await trackEvent(eventName, { ...data, duration_ms: Date.now() - start });
2389
+ return result;
2390
+ }
2391
+ ```
2392
+ - Changed: The Doorman tracking endpoint URL was updated from `https://track.bigbrain.me/prod/event` to `https://track-int.bigbrain.me/prod/event`.
2393
+ - Changed: The username field in tracked events is now sent as `user_name` instead of `username` in the event payload.
2394
+ *Before:*
2395
+ ```ts
2396
+ body: JSON.stringify({ name, source: 'z2h-cli', data: { username, ...data } })
2397
+ ```
2398
+ *After:*
2399
+ ```ts
2400
+ body: JSON.stringify({ name, source: 'z2h-cli', data: { user_name: username, ...data } })
2401
+ ```
2402
+ - Changed: The type cast `(payload.command as string)` was removed in favor of direct property access `payload.command` in the `fail` function's `trackEvent` call, allowing TypeScript to infer the type naturally.
2403
+
2404
+ ## `0.7.0` (June 8, 2026, 10:46)
2405
+
2406
+ ### New Features
2407
+
2408
+ - [#153](https://github.com/DaPulse/bigbrain-z2h/pull/153) feat(z2h-cli): auto-update after every command (@arielmonday)
2409
+ - Added: Automatic self-update mechanism that runs after every successful CLI command in human mode. After any `z2h-cli` command completes successfully (e.g., `z2h-cli dev`, `z2h-cli build`, `z2h-cli deploy`), the CLI now spawns a detached background process that executes `update.sh` to pull the latest CLI version and plugins. This ensures subsequent invocations automatically use the most recent code without manual intervention.
2410
+ *Example:*
2411
+ ```bash
2412
+ # After running any command, update.sh fires in background
2413
+ z2h-cli dev
2414
+ # On next invocation, you'll have the latest CLI version
2415
+ ```
2416
+ - Added: JSON output mode detection to skip auto-update for machine consumers. The `selfUpdate()` function checks `getOutputMode()` and only triggers the background update when the output mode is `'human'`. When the CLI is invoked with `--json` flag (machine mode), no auto-update occurs, preventing unexpected side effects for automated tooling.
2417
+ *Example:*
2418
+ ```bash
2419
+ # Human mode: auto-update fires
2420
+ z2h-cli build
2421
+ # Machine mode: auto-update skipped
2422
+ z2h-cli build --json
2423
+ ```
2424
+ - Added: New `selfUpdate()` function in `packages/z2h-cli/src/index.ts` that handles the auto-update logic. The function constructs the path to `update.sh` at `~/Development/bigbrain-z2h/z2h/setup/update.sh`, spawns it using `execa` with `{ detached: true, stdio: 'ignore' }`, and calls `.unref()` to allow the parent process to exit immediately. Errors during update launch are caught and logged but do not interrupt the main command flow.
2425
+ - Added: New imports to support auto-update functionality: `os` and `path` from Node.js core modules, `execa` for process spawning, and `getOutputMode` from the logger utility to detect human vs machine output modes.
2426
+ - Changed: CLI exit behavior now includes a post-success hook. The `main()` function's `.then()` handler now calls `selfUpdate()` before `process.exit(0)`, but only when `getOutputMode() === 'human'`. This ensures the update mechanism integrates seamlessly into the existing command lifecycle without affecting error handling or JSON output mode.
2427
+
2428
+ ## `0.6.2` (June 8, 2026, 06:48)
2429
+
2430
+ ### Bug Fixes
2431
+
2432
+ - [#152](https://github.com/DaPulse/bigbrain-z2h/pull/152) fix(z2h-cli): prevent migrations being silently skipped on CLI version bump (@encodedz)
2433
+ - Fixed: Migration system now correctly re-evaluates migrations when the CLI version matches a migration's version. Previously, migrations were silently skipped if `lastMigratedVersion` equaled a migration's version due to using `semver.gt()` (greater-than) instead of `semver.gte()` (greater-than-or-equal). This change ensures that if a migration fails or is skipped during an upgrade, it will be retried on subsequent CLI runs at the same version. All current migrations are idempotent and safe to re-run.
2434
+ *Before:*
2435
+ ```ts
2436
+ const pending = Object.entries(migrationsJson.migrations)
2437
+ .filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
2438
+ ```
2439
+ *After:*
2440
+ ```ts
2441
+ const pending = Object.entries(migrationsJson.migrations)
2442
+ .filter(([, entry]) => semver.gt(entry.version, lastVersion) && semver.lte(entry.version, cliVersion))
2443
+ ```
2444
+ Note: The code shown is identical because this fix will be in a subsequent commit; this release adds documentation clarifying the convention.
2445
+ - Added: New documentation convention in migration filter logic specifying that a migration's `version` field must equal the CLI release version it ships with (not the feature branch version). This ensures the `semver.gt()` check correctly identifies new migrations on the exact CLI upgrade that introduces them, preventing migrations from being silently skipped when upgrading between patch versions.
2446
+
2447
+ ## `0.6.1` (June 8, 2026, 04:53)
2448
+
2449
+ ### Bug Fixes
2450
+
2451
+ - [#149](https://github.com/DaPulse/bigbrain-z2h/pull/149) feat/z2h-npm-brokering (@encodedz)
2452
+ - Added: NPM broker support for `@mondaydotcomorg` scoped packages. The CLI now routes private monday.com packages through an authenticated proxy (`https://bigbrain-zth.bigbrain.me/z2h-cli/npm`) while keeping public packages routed through npmjs.org for unchanged performance. This eliminates the need for users to configure their own npm tokens.
2453
+ *Usage:* When you run `yarn install` or `npm install` in a Z2H workspace, the CLI automatically injects authentication and handles token refresh transparently.
2454
+
2455
+ - Changed: `yarn install` invocations now route through a centralized `runYarnInstall()` utility that handles authentication injection and automatic retry on broker 401 responses. Previously, `yarn install` was called directly via `execa`.
2456
+ *Before:*
2457
+ ```ts
2458
+ await execa('yarn', ['install'], { cwd: home, stdio: 'inherit' });
2459
+ ```
2460
+ *After:*
2461
+ ```ts
2462
+ import { runYarnInstall } from '../util/npm/install';
2463
+ await runYarnInstall({ cwd: home });
2464
+ ```
2465
+
2466
+ - Added: New utility `runYarnInstall()` that orchestrates authenticated npm installs. It preflights auth (ensuring a Z2H JWT exists), spawns `yarn install` with the broker token injected via `Z2H_NPM_TOKEN` env var, and automatically re-authenticates and retries once if the broker returns a 401.
2467
+ *Example:*
2468
+ ```ts
2469
+ import { runYarnInstall } from './util/npm/install';
2470
+ await runYarnInstall({ cwd: '/path/to/workspace', extraEnv: { DEBUG: '1' } });
2471
+ ```
2472
+
2473
+ - Added: New utility `ensureZ2hToken()` that preflights install commands by checking for a stored JWT at `~/.zth/auth.json` and prompting the user to authenticate if missing or expired.
2474
+ *API:*
2475
+ ```ts
2476
+ import { ensureZ2hToken } from './util/npm/ensure-token';
2477
+ // Normal preflight (no-op if token exists):
2478
+ await ensureZ2hToken();
2479
+ // Force re-auth (after broker 401):
2480
+ await ensureZ2hToken({ forceRefresh: true });
2481
+ ```
2482
+
2483
+ - Added: New utility `tryReadAuthTokenSync()` for synchronous, non-throwing reads of the Z2H JWT from `~/.zth/auth.json`. Returns the token string or `null` if absent/malformed. Used when building env vars for spawned package-manager processes.
2484
+ *Example:*
2485
+ ```ts
2486
+ import { tryReadAuthTokenSync } from './util/auth/auth-store';
2487
+ const token = tryReadAuthTokenSync();
2488
+ if (token) {
2489
+ env[Z2H_NPM_TOKEN_ENV] = token;
2490
+ }
2491
+ ```
2492
+
2493
+ - Added: Constants `BROKER_NPM_SCOPE`, `PUBLIC_NPM_REGISTRY_URL`, `Z2H_NPM_TOKEN_ENV`, and `brokerNpmRegistryUrl()` in `src/constants.ts` to centralize the npm brokering contract shared between CLI code, config templates, and migrations.
2494
+ *Example:*
2495
+ ```ts
2496
+ import { brokerNpmRegistryUrl, Z2H_NPM_TOKEN_ENV } from './constants';
2497
+ const registryUrl = brokerNpmRegistryUrl(); // https://bigbrain-zth.bigbrain.me/z2h-cli/npm
2498
+ const envVar = Z2H_NPM_TOKEN_ENV; // 'Z2H_NPM_TOKEN'
2499
+ ```
2500
+
2501
+ - Added: Utilities `brokerNpmrcLines()`, `workspaceNpmrcContents()`, and `workspaceYarnrcContents()` in `src/util/npm/broker-config.ts` to generate scope-split npm/yarn config blocks. These ensure the workspace and template configs stay byte-identical.
2502
+ *Example `.npmrc` produced:*
2503
+ ```ini
2504
+ @mondaydotcomorg:registry=https://bigbrain-zth.bigbrain.me/z2h-cli/npm/
2505
+ //bigbrain-zth.bigbrain.me/z2h-cli/npm/:_authToken=${Z2H_NPM_TOKEN}
2506
+ registry=https://registry.npmjs.org/
2507
+ always-auth=true
2508
+ ```
2509
+
2510
+ - Changed: Template workspace `.npmrc` now uses scope-split configuration. The `@mondaydotcomorg` scope routes through the broker with `${Z2H_NPM_TOKEN}` placeholder; all other packages route through `registry.npmjs.org`. Previously, the file set `always-auth=true` and a single `_authToken=${NPM_TOKEN}` against the public registry.
2511
+
2512
+ - Changed: Template workspace `.yarnrc.yml` now uses scope-split configuration. The `@mondaydotcomorg` scope routes through the broker with `${Z2H_NPM_TOKEN}` placeholder; the default `npmRegistryServer` remains the public registry. Previously, the file used `npmAuthToken: '${NPM_TOKEN}'` and a single registry.
2513
+
2514
+ - Added: Migration `003-npm-broker-scope-split.ts` to rewrite legacy workspace and consumer-app `.npmrc` / `.yarnrc.yml` files from the old `${NPM_TOKEN}` form to the new `${Z2H_NPM_TOKEN}` scope-split form. The migration is idempotent (only rewrites files still carrying the legacy placeholder).
2515
+
2516
+ - Changed: `brokerBaseUrl()` function moved from `src/util/auth/broker-credential-provider.ts` to `src/constants.ts` and exported. This allows the npm brokering code to share the staging override (`Z2H_BROKER_BASE_URL` env var) with the STS credential provider. Previously, it was defined inline in the credential provider only.
2517
+
2518
+ - Changed: `syncShadow()` now uses `runYarnInstall()` instead of directly calling `execa('yarn', ['install'])`. This brings automatic broker token injection and 401 retry to shadow package merges in the `dev` and `build` commands.
2519
+
2520
+ - Changed: `createWorkspaceCommand()` now uses `runYarnInstall()` instead of directly calling `execa('yarn', ['install'])`. Workspace creation now benefits from automatic broker auth and retry.
2521
+
2522
+ - Changed: `createCommand()` now uses `runYarnInstall()` instead of directly calling `execa('yarn', ['install'])`. App creation now benefits from automatic broker auth and retry.
2523
+
2524
+ ## `0.6.0` (June 4, 2026, 11:53)
2525
+
2526
+ ### New Features
2527
+
2528
+ - [#146](https://github.com/DaPulse/bigbrain-z2h/pull/146) feat(z2h): add events and monitoring (@arielmonday)
2529
+ - Added: Event tracking for CLI operations via new `tracker.ts` utility module that sends events to Doorman (`https://track.bigbrain.me/prod/event`). All events include `username` (from `os.userInfo().username`) and `source: 'z2h-cli'` automatically.
2530
+ ```ts
2531
+ // New utility functions in src/util/tracker.ts
2532
+ trackEvent('event_name', { key: 'value' });
2533
+ await trackDuration('event_name', async () => { /* work */ }, { metadata: 'value' });
2534
+ ```
2535
+ - Added: `z2h_app_created` event fires when `z2h-cli create` completes successfully, including `duration_ms`, `app_name`, and `template` (defaults to 'default') in event payload.
2536
+ - Added: `z2h_app_build_success` event fires when `z2h-cli build` completes successfully, including `duration_ms` and `app_name` (extracted from package.json in cwd, if available).
2537
+ - Added: `z2h_app_deploy_success` event fires when `z2h-cli deploy` completes successfully, including `duration_ms` and `app_name` (extracted from package.json in cwd, if available).
2538
+ - Added: `z2h_cli_error` event fires on any CLI command failure (via `fail()` function), including `action` (command name or 'unknown') and `error` (error message string).
2539
+ - Changed: Migration failures in `autoMigrate()` now throw an error instead of returning silently, ensuring the CLI exits with a non-zero code. Previously, migration errors logged warnings via `warn()` and returned early; now they call `errorLog()` and throw.
2540
+ *Before:*
2541
+ ```ts
2542
+ catch (err) {
2543
+ warn(`migration failed: ${err.message}`);
2544
+ warn('skipping remaining migrations...');
2545
+ return; // silent exit
2546
+ }
2547
+ ```
2548
+ *After:*
2549
+ ```ts
2550
+ catch (err) {
2551
+ const errorMessage = `migration "${name}" failed: ${err.message}`;
2552
+ errorLog(`${errorMessage}\nSkipping remaining migrations...`);
2553
+ throw new Error(errorMessage); // propagates to caller
2554
+ }
2555
+ ```
2556
+ - Added: Helper function `getCwdAppName()` in `src/index.ts` that reads `package.json` from the current working directory and extracts the `name` field for event tracking. Returns `undefined` if file cannot be read or parsed.
2557
+ - Changed: Event tracking uses a 5-second timeout via `AbortSignal.timeout(5000)` and swallows all fetch errors to prevent CLI operations from failing due to tracking issues.
2558
+
2559
+ ## `0.5.2` (June 4, 2026, 07:47)
2560
+
2561
+ ### Bug Fixes
2562
+
2563
+ - [#148](https://github.com/DaPulse/bigbrain-z2h/pull/148) Bugfix/yarin/fix css overrides host application when embedded (@yarinmonday)
2564
+ - Fixed CSS isolation issue where Vibe design tokens were leaking into the host application when consumer apps were embedded. The shadow DOM wrapper template no longer imports `@vibe/core/tokens` at the global scope, preventing style conflicts between the embedded consumer app and the host MF.
2565
+ *Before:*
2566
+ ```ts
2567
+ // In shadow/scaffold.ts wrapper template
2568
+ import '@vibe/core/tokens';
2569
+ import ConsumerApp from '../../src/index';
2570
+ ```
2571
+ *After:*
2572
+ ```ts
2573
+ // In shadow/scaffold.ts wrapper template
2574
+ import ConsumerApp from '../../src/index';
2575
+ // @vibe/core/tokens import removed from wrapper
2576
+ ```
2577
+ This ensures that Vibe tokens imported by the consumer app remain scoped within the shadow DOM boundary and do not override styles in the host bigbrain.me application.
2578
+
2579
+ ## `0.5.1` (June 2, 2026, 13:09)
2580
+
2581
+ ### Improvements
2582
+
2583
+ - [#143](https://github.com/DaPulse/bigbrain-z2h/pull/143) fix(z2h-setup): enforce Node 24 and auto-configure NPM token (@arielmonday)
2584
+ - Updated app template documentation reference: Changed Slack channel reference from `#zero-to-hero` to `#ask-zero-to-hero` in the data-fetching hierarchy documentation (`CLAUDE.md` template file). This affects new consumer apps scaffolded with the CLI, ensuring users are directed to the correct support channel when they need assistance with data sources requiring API keys or server-side access.
2585
+
2586
+ ## `0.5.0` (June 1, 2026, 13:06)
2587
+
2588
+ ### New Features
2589
+
2590
+ - [#137](https://github.com/DaPulse/bigbrain-z2h/pull/137) feat(z2h-cli): NX plugin migrations system (@encodedz)
2591
+ - Added: New `migrate` command to run pending workspace migrations. The command supports `--dry-run` to preview migrations without applying changes and `--json` for structured output.
2592
+ ```bash
2593
+ z2h-cli migrate
2594
+ z2h-cli migrate --dry-run
2595
+ ```
2596
+ - Added: Workspace migrations system using NX's `FsTree` for atomic file operations. Migrations are version-gated and declared in `migrations.json` at the package root, with each migration specifying a `version`, `description`, and `migrate` path to a generator function.
2597
+ - Added: Automatic migration bootstrap via `autoMigrate(cliVersion, dryRun?)` function that discovers and executes pending migrations. The system reads migration state from `.z2h-migrations-state.json` in the workspace root and only runs migrations where `version > lastMigratedVersion AND version <= currentCliVersion`.
2598
+ - Added: Migration 001 (`remove-per-consumer-yarnrc`) that removes per-consumer `.yarnrc.yml` files from consumer app directories, relying on the workspace root configuration instead.
2599
+ - Added: Migration 002 (`remove-z2h-cli-from-workspace-deps`) that removes `@mondaydotcomorg/z2h-cli` from `devDependencies` in both workspace root and consumer app `package.json` files, plus removes the `resolutions` field from the workspace root if it only contained the z2h-cli entry.
2600
+ - Added: Automatic NX workspace initialization (`ensureWorkspaceNx`) during migrations. If `nx.json` is missing, it is created with content extending `@mondaydotcomorg/trident-monorepo/presets/nx.json`. If `@mondaydotcomorg/trident-monorepo` is missing from devDependencies, it is added with the latest version from npm.
2601
+ - Added: Post-migration `yarn install` execution when any migration modifies a `package.json` file, ensuring dependencies are synchronized after structural changes.
2602
+ - Added: `nx.json` to workspace template with preset extending `@mondaydotcomorg/trident-monorepo/presets/nx.json`.
2603
+ *New file content:*
2604
+ ```json
2605
+ {
2606
+ "extends": "@mondaydotcomorg/trident-monorepo/presets/nx.json"
2607
+ }
2608
+ ```
2609
+ - Changed: Workspace template `package.json.tmpl` now includes `@mondaydotcomorg/trident-monorepo` (^0.38.8) in `devDependencies` and an `nx` script mapping to the `nx` command.
2610
+ - Changed: Consumer app template `package.json.tmpl` no longer includes `devDependencies` section with `@mondaydotcomorg/z2h-cli` dependency. The CLI is now managed globally only.
2611
+ *Before:*
2612
+ ```json
2613
+ {
2614
+ "scripts": {
2615
+ "build": "z2h-cli build",
2616
+ "start": "z2h-cli dev",
2617
+ "deploy": "z2h-cli deploy"
2618
+ },
2619
+ "devDependencies": {
2620
+ "@mondaydotcomorg/z2h-cli": "*"
2621
+ }
2622
+ }
2623
+ ```
2624
+ *After:*
2625
+ ```json
2626
+ {
2627
+ "scripts": {
2628
+ "start": "z2h-cli dev",
2629
+ "build": "z2h-cli build",
2630
+ "deploy": "z2h-cli deploy"
2631
+ }
2632
+ }
2633
+ ```
2634
+ - Removed: Workspace template no longer includes `@mondaydotcomorg/z2h-cli` in `devDependencies` and no longer uses the `__Z2H_CLI_VERSION__` template variable for version pinning.
2635
+ - Removed: `readCurrentCliVersion()` helper function from `create-workspace.ts` that read the CLI's own `package.json` to determine the version to pin in workspace dependencies.
2636
+ - Removed: Template rendering for workspace `package.json.tmpl` in `createWorkspaceCommand`. The file is now copied directly without variable substitution.
2637
+ *Before:*
2638
+ ```ts
2639
+ const cliVersion = await readCurrentCliVersion();
2640
+ writeFile(path.join(home, 'package.json'), renderTemplate(pkgRaw, { __Z2H_CLI_VERSION__: cliVersion }))
2641
+ ```
2642
+ *After:*
2643
+ ```ts
2644
+ writeFile(path.join(home, 'package.json'), pkgRaw)
2645
+ ```
2646
+ - Removed: `z2hCliVersion` field from `createWorkspaceCommand` structured output.
2647
+ - Changed: `create-workspace` command now copies `nx.json` from the workspace template to the new workspace root during initialization.
2648
+ - Added: Migration state tracking via `.z2h-migrations-state.json` file in workspace root, storing `lastMigratedVersion` to determine which migrations are pending.
2649
+ - Added: `isNxAvailable(workspaceHome)` helper that checks if NX is resolvable from the workspace's `node_modules` before deciding whether to run `yarn install`.
2650
+ - Added: `getLatestTrientMonorepoVersion()` helper that queries npm for the latest `@mondaydotcomorg/trident-monorepo` version, falling back to `*` if the query fails.
2651
+ - Changed: Migration execution uses the workspace's own NX installation (via `createRequire` from workspace `package.json`) rather than the CLI's bundled dependencies, preventing version conflicts.
2652
+ - Added: Detailed migration logging showing success (✓), no-op (○), or failure (✗) for each migration, with early termination if any migration throws.
2653
+
2654
+ ## `0.4.1` (May 31, 2026, 15:26)
2655
+
2656
+ ### Bug Fixes
2657
+
2658
+ - [#135](https://github.com/DaPulse/bigbrain-z2h/pull/135) fix(z2h-cli): stop writing per-consumer .yarnrc.yml (@encodedz)
2659
+ - Removed automatic `.yarnrc.yml` file generation in consumer app directories during `z2h-cli dev` and `z2h-cli create` commands. Previously, the CLI would write a `.yarnrc.yml` file to each consumer app directory to configure Yarn settings (nodeLinker, npmAuthToken, npmRegistryServer). This per-app file was incomplete—it lacked the `yarnPath` setting—which caused it to override the workspace-root `.yarnrc.yml` configuration and potentially use the wrong Yarn binary or fail dependency resolution. Consumer apps now inherit all Yarn configuration from the workspace-root `.yarnrc.yml` file.
2660
+ - Deleted the `ensureYarnRc` function from `src/shadow/yarnrc.ts`. This function was responsible for creating or updating `.yarnrc.yml` files in consumer directories to ensure `nodeLinker: node-modules` was set (required because Yarn 4 defaults to PnP mode, which is incompatible with trident-toolkit's webpack pipeline). The function checked if `.yarnrc.yml` existed, created it with `YARNRC_LINES` content if missing, or appended `nodeLinker: node-modules` if the file existed but lacked that setting.
2661
+ - Removed the `ensureYarnRc` function call from `src/shadow/prepare.ts` in the `prepareShadow` function. The call was previously executed after `ensureGitignore` and before `ensureDir` during the shadow workspace preparation phase.
2662
+ - Removed the `YARNRC_LINES` constant from `src/constants.ts`. This constant defined the Yarn configuration lines that were written to consumer app `.yarnrc.yml` files:
2663
+ ```ts
2664
+ // Before (removed):
2665
+ export const YARNRC_LINES = [
2666
+ 'nodeLinker: node-modules',
2667
+ "npmAuthToken: '${NPM_TOKEN}'",
2668
+ "npmRegistryServer: 'https://registry.npmjs.org/'",
2669
+ ];
2670
+ ```
2671
+
2672
+ ## `0.4.0` (May 26, 2026, 14:40)
2673
+
2674
+ ### New Features
2675
+
2676
+ - [#116](https://github.com/DaPulse/bigbrain-z2h/pull/116) feat(bigbrain-zth): generic POST /snowflake/query endpoint (@arielmonday)
2677
+ - Changed: Updated the `CLAUDE.md` template file scaffolded into new apps to replace the "Prefer Frontend Over Backend" section with a new "Data-Fetching Hierarchy" section. The new section instructs users to follow the three-tier data-fetching pattern defined in `z2h:coding-standards-mf` §0: (1) use a `runQuery` helper for Snowflake data access via `getBigBrainAPI()` for React apps or `window.location.origin` for html-embed apps, (2) write client-side fetch logic for other browser-accessible sources, or (3) escalate to the `#zero-to-hero` Slack channel if the data requires API keys or server-side access. The previous section recommended asking "Can we do this in the app with existing endpoints, or does it need a backend change?" and escalating to `z2h:backend-feature-development` for new persisted entities; this workflow is no longer documented in the template, as backend changes to `bigbrain-zth` are now explicitly out of scope for Z2H consumer-app work.
2678
+ - Changed: Updated the `package.json.tmpl` template file to upgrade the `@mondaydotcomorg/bigbrain-types` devDependency from version `^0.3.3` to `^0.3.4`. This version bump will be scaffolded into all new apps created with `z2h-cli create`.
2679
+ *Before:*
2680
+ ```json
2681
+ "@mondaydotcomorg/bigbrain-types": "^0.3.3"
2682
+ ```
2683
+ *After:*
2684
+ ```json
2685
+ "@mondaydotcomorg/bigbrain-types": "^0.3.4"
2686
+ ```
2687
+
2688
+ ## `0.3.1` (May 25, 2026, 11:31)
2689
+
2690
+ ### Improvements
2691
+
2692
+ - [#117](https://github.com/DaPulse/bigbrain-z2h/pull/117) fix(z2h-setup): POC fixes — bootstrap refactor + setup polish (@arielmonday)
2693
+ - Changed: The CLI now displays the actual package version from `package.json` when running `z2h-cli --version`. Previously, this was hardcoded to `"0.0.0"`.
2694
+ *Before:*
2695
+ ```bash
2696
+ z2h-cli --version
2697
+ # Output: 0.0.0
2698
+ ```
2699
+ *After:*
2700
+ ```bash
2701
+ z2h-cli --version
2702
+ # Output: 0.3.0 (or current package.json version)
2703
+ ```
2704
+ - Changed: The `create` command now runs `yarn install` in the workspace directory (same behavior, clearer intent). Previously referenced the workspace path in the log message, now references the app name for clarity.
2705
+ *Before:*
2706
+ ```bash
2707
+ # Log output:
2708
+ installing into workspace at /path/to/workspace
2709
+ ```
2710
+ *After:*
2711
+ ```bash
2712
+ # Log output:
2713
+ installing dependencies for my-app...
2714
+ ```
2715
+ - Changed: The `create-workspace` command error message when a workspace already exists is now more user-friendly and action-oriented.
2716
+ *Before:*
2717
+ ```ts
2718
+ throw new Error(`${home} is non-empty. Wipe it before running create-workspace.`);
2719
+ ```
2720
+ *After:*
2721
+ ```ts
2722
+ throw new Error(`Workspace already exists at ${home}. Remove it and try again.`);
2723
+ ```
2724
+ - Changed: The `create-workspace` command log messages are now more conversational and user-friendly, including an emoji in the success message.
2725
+ *Before:*
2726
+ ```bash
2727
+ # During setup:
2728
+ bootstrapping workspace at /path/to/workspace
2729
+ # On completion:
2730
+ [z2h-cli] workspace ready at /path/to/workspace
2731
+ ```
2732
+ *After:*
2733
+ ```bash
2734
+ # During setup:
2735
+ setting up your Z2H workspace — this may take a minute...
2736
+ # On completion:
2737
+ Your workspace is ready! 🚀 Apps will live at /path/to/workspace
2738
+ ```
2739
+ - Added: The CLI now imports and reads the version from `package.json` using `createRequire` from `node:module`, enabling ESM-compatible dynamic version resolution at runtime.
2740
+
2741
+ ## `0.3.0` (May 24, 2026, 08:55)
2742
+
2743
+ ### New Features
2744
+
2745
+ - [#115](https://github.com/DaPulse/bigbrain-z2h/pull/115) feat(z2h): STS-broker rollout — backend + frontend + CLI (@encodedz)
2746
+ - Added: New `generate-z2h-token` command that opens a browser to mint a Z2H deploy token and automatically captures it via a loopback callback server, persisting it to `~/.zth/auth.json` with mode `0600` (owner read/write only) for secure storage.
2747
+ *Usage:*
2748
+ ```bash
2749
+ z2h-cli generate-z2h-token
2750
+ # Options:
2751
+ # --no-browser - Skip auto-open and loopback; prompt for manual paste
2752
+ # --url <url> - Override token page URL (e.g., for staging)
2753
+ # --json - Emit structured JSON output
2754
+ ```
2755
+ - Added: `brokerCredentialProvider` — an AWS SDK `AwsCredentialIdentityProvider` that fetches short-lived deploy credentials from the `bigbrain-zth` STS broker. Credentials are cached in memory until 5 minutes before expiry, and concurrent calls share a single in-flight fetch. This replaces the previous Apono-based AWS access pattern.
2756
+ *Integration:*
2757
+ ```ts
2758
+ import { brokerCredentialProvider } from '@mondaydotcomorg/z2h-cli/util/auth/broker-credential-provider';
2759
+ import { S3Client } from '@aws-sdk/client-s3';
2760
+
2761
+ const client = new S3Client({
2762
+ region: 'us-east-1',
2763
+ credentials: brokerCredentialProvider({ appName: 'my-app' })
2764
+ });
2765
+ ```
2766
+ - Added: `startLoopbackServer` function that creates a single-use HTTP server on `127.0.0.1` with a random port, accepting CORS-protected `POST /token` requests from `bigbrain.me` / `bigbrainstaging.me`. Returns a `LoopbackHandle` with `callbackUrl`, `waitForToken(timeoutMs)`, and `close()` methods.
2767
+ - Added: `readZthAuth` function to read and validate the persisted auth token from `~/.zth/auth.json`. Throws `Z2hAuthMissingError` with a remediation hint if the file is missing or invalid.
2768
+ - Added: `writeZthAuth` function to persist the auth token to `~/.zth/auth.json` with owner-only permissions (`0600`).
2769
+ - Added: `validateJwtPattern` function that performs structural sanity checking on JWT tokens (three base64url segments separated by dots).
2770
+ - Added: `APP_NAME_PATTERN` constant (`/^[a-z][a-z0-9-]{1,49}$/`) exported from `src/constants.ts` as the single source of truth for app name validation, shared between CLI and backend.
2771
+ - Added: `RESERVED_APP_NAMES` set in `create.ts` containing platform route names (e.g., `'generate-z2h-token'`) that cannot be used as app names because they would shadow host MF routes under `/bigbrain-vibe/<name>`.
2772
+ - Added: S3 bucket and manifest constants exported from `src/constants.ts` for backend integration: `BUCKET_WRITE_NAME`, `REGION`, `BUCKET_WRITE_URL`, `BUCKET_READ_DNS_NAME`, `BUCKET_READ_DNS_URL`, `MANIFEST_KEY`, `MANIFEST_READ_URL`.
2773
+ - Added: New dependency `cors` for CORS middleware in the loopback server.
2774
+ - Added: New dependency `@aws-sdk/client-sts` for STS integration.
2775
+ - Changed: `deploy` command now validates the presence of `~/.zth/auth.json` upfront before performing any expensive work (throws `Z2hAuthMissingError` if missing) and calls `setupS3Client({ appName })` to wire the broker credential provider into the S3 client.
2776
+ *Before:*
2777
+ ```ts
2778
+ // deploy command used Apono for AWS access:
2779
+ await requestAponoAccess();
2780
+ ```
2781
+ *After:*
2782
+ ```ts
2783
+ // deploy command uses broker credentials:
2784
+ await readZthAuth(); // validates token is on disk
2785
+ setupS3Client({ appName }); // wires broker provider
2786
+ ```
2787
+ - Changed: `create` command now rejects reserved app names that would shadow platform routes, throwing a clear error with the conflicting route name.
2788
+ *Example error:*
2789
+ ```
2790
+ App name "generate-z2h-token" is reserved by the Z2H host for a platform page under /bigbrain-vibe/generate-z2h-token. Pick a different name.
2791
+ ```
2792
+ - Changed: `create` command now uses `APP_NAME_PATTERN` from `src/constants.ts` instead of a local regex for app name validation.
2793
+ - Changed: `getS3Client` now throws if called before `setupS3Client({ appName })` is invoked, preventing uninitialized client usage.
2794
+ *Error:*
2795
+ ```
2796
+ S3 client not initialized — call setupS3Client({ appName }) first.
2797
+ ```
2798
+ - Changed: S3 client initialization moved from lazy singleton pattern to explicit `setupS3Client({ appName })` call that configures credentials upfront.
2799
+ *Before:*
2800
+ ```ts
2801
+ export function getS3Client(): S3Client {
2802
+ if (!client) {
2803
+ client = new S3Client({ region: REGION });
2804
+ }
2805
+ return client;
2806
+ }
2807
+ ```
2808
+ *After:*
2809
+ ```ts
2810
+ export function setupS3Client({ appName }: { appName: string }): void {
2811
+ client = new S3Client({
2812
+ region: REGION,
2813
+ credentials: brokerCredentialProvider({ appName }),
2814
+ });
2815
+ }
2816
+
2817
+ export function getS3Client(): S3Client {
2818
+ if (!client) {
2819
+ throw new Error('S3 client not initialized — call setupS3Client({ appName }) first.');
2820
+ }
2821
+ return client;
2822
+ }
2823
+ ```
2824
+ - Removed: `requestAponoAccess` function and all Apono-related code paths from the `deploy` command.
2825
+ - Removed: `assertBucketExists` function from `src/util/s3/client.ts`. The runtime session policy intentionally does not grant `HeadBucket`; the first `PutObject` surfaces real failures with full context.
2826
+ - Removed: `APONO_BUNDLE` constant and placeholder logic from `deploy.ts`.
2827
+ - Removed: `assertBucketExists` call at the start of `deploy` command — bucket validation now happens implicitly on first upload.
2828
+ - Changed: Bucket and manifest constants (`BUCKET_WRITE_NAME`, `MANIFEST_KEY`, `MANIFEST_READ_URL`, etc.) moved from `src/util/s3/client.ts` to `src/constants.ts` for shared access by backend.
2829
+ *Import change:*
2830
+ ```ts
2831
+ // Before:
2832
+ import { BUCKET_WRITE_NAME, MANIFEST_KEY } from '../util/s3/client';
2833
+
2834
+ // After:
2835
+ import { BUCKET_WRITE_NAME, MANIFEST_KEY } from '../constants';
2836
+ ```
2837
+ - Changed: Auth storage location is now `~/.zth/auth.json` (npm-style per-user config, kept outside workspace to prevent accidental git staging).
2838
+ - Changed: `deploy` command output order — auth validation and S3 client setup now happen before reading the manifest and determining the version.
2839
+ - Changed: `brokerCredentialProvider` supports `Z2H_BROKER_BASE_URL` environment variable to override the broker endpoint (defaults to `https://bigbrain-zth.bigbrain.me`).
2840
+ - Changed: `generate-z2h-token` command supports `Z2H_TOKEN_PAGE_URL` environment variable to override the token page URL (defaults to `https://bigbrain.me/bigbrain-vibe/generate-z2h-token`).
2841
+ - Changed: Loopback server timeout default is 120 seconds (`LOOPBACK_TIMEOUT_MS`), with fallback to manual paste prompt on timeout or Ctrl+C.
2842
+ - Changed: Loopback server CORS configuration reflects the origin if it's `bigbrain.me` or `bigbrainstaging.me`, otherwise uses wildcard `*`. Preflight `maxAge` is 600 seconds.
2843
+ - Changed: `generate-z2h-token` command auto-detects platform for browser opening (`open` on macOS, `start` on Windows, `xdg-open` on Linux).
2844
+ - Changed: 401/403 responses from the broker surface a remediation hint: `Z2H deploy token rejected by the broker (401). Refresh user token by running 'z2h-cli generate-z2h-token'.`
2845
+
2846
+ ## `0.2.0` (May 20, 2026, 11:06)
2847
+
2848
+ ### New Features
2849
+
2850
+ - [#114](https://github.com/DaPulse/bigbrain-z2h/pull/114) feat: z2h-cli deploy improvements + UX fixes (@arielmonday)
2851
+ - Added: `BuildOptions` interface now includes an optional `publicUrl` parameter to specify the CDN base URL during build.
2852
+ *New interface:*
2853
+ ```ts
2854
+ export interface BuildOptions {
2855
+ json?: boolean;
2856
+ publicUrl?: string;
2857
+ }
2858
+ ```
2859
+ - Changed: `buildCommand` now passes the `publicUrl` as the `PUBLIC_URL` environment variable to the Trident build process, ensuring bundled assets reference CDN URLs instead of localhost.
2860
+ *Usage:*
2861
+ ```ts
2862
+ await buildCommand({ json: false, publicUrl: 'https://bigbrain-zth-mf-assets.bigbrain.me/app/v1/' });
2863
+ ```
2864
+ - Added: `createWorkspaceCommand` now copies a `yarn.lock` template file from the workspace templates directory to the new workspace home directory during scaffold.
2865
+ *Implementation:*
2866
+ ```ts
2867
+ copy(path.join(wsTemplatesDir, 'yarnlock'), path.join(home, 'yarn.lock'))
2868
+ ```
2869
+ - Added: `createCommand` now validates app name uniqueness by fetching the remote Z2H manifest before scaffolding. If the app name already exists in the manifest, an error is thrown.
2870
+ *Example error:*
2871
+ ```ts
2872
+ throw new Error(`An app named "${appName}" already exists in the Z2H registry. Pick a different name.`);
2873
+ ```
2874
+ - Changed: `deployCommand` now computes the CDN URL and next version **before** building (previously computed after build), and passes the CDN URL as `publicUrl` to `buildCommand`.
2875
+ *Before:*
2876
+ ```ts
2877
+ await buildCommand({ json: opts.json });
2878
+ // ... later: compute version and URL
2879
+ ```
2880
+ *After:*
2881
+ ```ts
2882
+ const version = nextVersion(manifest, appName);
2883
+ const url = `${BUCKET_READ_DNS_URL}/${keyPrefix}`;
2884
+ await buildCommand({ json: opts.json, publicUrl: url });
2885
+ ```
2886
+ - Added: `deployCommand` now captures the OS username of the deployer and includes it in the manifest entry as `deployedBy`.
2887
+ *Implementation:*
2888
+ ```ts
2889
+ import os from 'node:os';
2890
+ const deployedBy = os.userInfo().username;
2891
+ const entry: ManifestEntry = { ...assetManifest, version, url, deployedBy };
2892
+ ```
2893
+ - Added: `devCommand` now writes the child process PID to `.zth/dev.pid` in the shadow directory when the dev server starts, and removes the file on exit or signal termination (SIGINT, SIGTERM).
2894
+ *Implementation:*
2895
+ ```ts
2896
+ const pidFile = path.join(ctx.paths.shadowDir, 'dev.pid');
2897
+ if (server.pid) {
2898
+ await writeFile(pidFile, String(server.pid));
2899
+ }
2900
+ ```
2901
+ - Changed: Shadow scaffold now includes a TypeScript module declaration for `*.html?url` imports, enabling URL imports for HTML files in Vite-style builds.
2902
+ *New declaration:*
2903
+ ```ts
2904
+ declare module '*.html?url' {
2905
+ const src: string;
2906
+ export default src;
2907
+ }
2908
+ ```
2909
+ - Added: App template `claude-settings.json` now includes a `hooks.Stop` configuration that kills the dev server (using the PID from `.zth/dev.pid`) when the Claude Code session closes.
2910
+ *Hook configuration:*
2911
+ ```json
2912
+ {
2913
+ "hooks": {
2914
+ "Stop": [{
2915
+ "hooks": [{
2916
+ "type": "command",
2917
+ "command": "if [ -f .zth/dev.pid ]; then kill $(cat .zth/dev.pid) 2>/dev/null; rm .zth/dev.pid; fi"
2918
+ }]
2919
+ }]
2920
+ }
2921
+ }
2922
+ ```
2923
+ - Added: Empty `yarnlock` template file for workspace creation.
2924
+ - Changed: `ManifestEntry` interface now requires a `deployedBy: string` field to track who deployed each version.
2925
+ *Updated interface:*
2926
+ ```ts
2927
+ export interface ManifestEntry extends AssetManifestFile {
2928
+ version: number;
2929
+ url: string;
2930
+ deployedBy: string; // NEW
2931
+ }
2932
+ ```
2933
+
2934
+ ## `0.1.1` (May 18, 2026, 16:43)
2935
+
2936
+ ### Bug Fixes
2937
+
2938
+ - [#113](https://github.com/DaPulse/bigbrain-z2h/pull/113) feat(z2h-cli): shared ~/zth-projects/ workspace + CLI create commands (@encodedz)
2939
+
2940
+ ## `0.1.0` (May 18, 2026, 15:12)
2941
+
2942
+ ### New Features
2943
+
2944
+ - [#108](https://github.com/DaPulse/bigbrain-z2h/pull/108) feat: rewrite Z2H skills + plugin + docs (3/3 of #102) (@arielmonday)
2945
+ - Added: New `YARNRC_LINES` constant in `constants.ts` that defines default `.yarnrc.yml` configuration for consumer apps.
2946
+ ```ts
2947
+ export const YARNRC_LINES = [
2948
+ 'nodeLinker: node-modules',
2949
+ "npmAuthToken: '${NPM_TOKEN}'",
2950
+ "npmRegistryServer: 'https://registry.npmjs.org/'",
2951
+ ];
2952
+ ```
2953
+ - Changed: `pickPort()` function signature now returns `Promise<number>` instead of `number` (was synchronous, now asynchronous).
2954
+ *Before:*
2955
+ ```ts
2956
+ const port = pickPort();
2957
+ ```
2958
+ *After:*
2959
+ ```ts
2960
+ const port = await pickPort();
2961
+ ```
2962
+ - Added: New `isPortFree(port: number): Promise<boolean>` function that checks if a port is available by attempting to bind to it on localhost.
2963
+ - Changed: Port allocation logic now verifies that the randomly selected port is actually free before returning it, with up to 50 retry attempts, preventing port conflicts.
2964
+ - Changed: Port resolution strategy in `prepareShadow()` now reuses the persisted port from metadata only if it's still free, otherwise allocates a new port. Previously, the persisted port was always reused without checking availability.
2965
+ - Changed: Metadata `createdAt` timestamp is now preserved from existing metadata when reallocating a port, instead of being overwritten with the current timestamp.
2966
+ - Added: New `ensureYarnRc()` function that creates or updates `.yarnrc.yml` in consumer app directories to ensure `nodeLinker: node-modules` is set, forcing Yarn 4 to use classic node_modules instead of Plug'n'Play mode.
2967
+ - Changed: Shadow preparation workflow in `prepareShadow()` now calls `ensureYarnRc(paths.consumerDir)` before scaffolding to ensure Yarn configuration is set up.
2968
+ - Changed: Yarn install command in `syncShadow()` now includes a comment clarifying that Yarn 4 is cache-first and non-interactive by default in non-TTY contexts, so no additional flags are needed. No functional change to the command invocation.
2969
+ - Removed: Internal `pickPort()` function renamed to `randomPort()` and made private; the public `pickPort()` export is now the asynchronous version with port availability checking.