hub-launch 1.23.0 → 1.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.25.0] - 2026-08-23
11
+
12
+ ### Added
13
+
14
+ - New `hula error-watcher` command to manage production **Error Watchers** — inbound error webhooks that deduplicate reported errors and auto-launch a fix (PR, plan, or feedback run). Seven modes: `--create`, `--list`, `--show`, `--events`, `--update`, `--delete`, and `--print-setup`. `--create` and `--print-setup` print the steps to mint a project ingest key, a paste-ready `.env` block, and a hard-coded signed-request snippet that signs the exact `` `${timestamp}.${body}` `` payload the server verifies. Credentials resolve flags → `.hublaunch/hublaunch.config.js` → env, identical to `hula schedule`, and are never written to any file. `--events` shows each error's disposition (`deduped`, `skipped_environment`, `skipped_budget`, `skipped_credits`, `skipped_open_pr`, `launched`, `failed`) so "why was there no PR?" is answerable from the terminal; with no watcher id it covers every watcher on the project. Requires a hula-server with Error Watcher support; older servers return a clear "not supported yet" message. See [docs/error-watcher.md](./docs/error-watcher.md).
15
+ - `--instructions`, `--error-env KEY=VALUE`, and `--secret <literal>` flags on `--create`/`--update` for the three watcher fields that shape what the fix agent sees: trusted guidance rendered into the agent's brief, environment variables injected into the fix sandbox, and extra literal values redacted from every payload. Each replaces the stored value wholesale, with matching `--clear-instructions` / `--clear-error-env` / `--clear-secrets` flags. Values are write-only — the server never echoes them back, and the CLI never prints them.
16
+ - Optional `errorWebhookUrl` config key to override the Error Watcher ingest URL for self-hosted servers whose webhook host differs from `hulaProjectUrl`.
17
+
18
+ ### Changed
19
+
20
+ - **Error Watcher ingest now authenticates on a project ingest key.** Matching the server, the credential a reporting app presents moved from the per-watcher `hew_` token to a project-level `hik_` key signing with its own `his_` secret. The generated `.env` block emits `HULA_INGEST_KEY` / `HULA_INGEST_SECRET` (was `HULA_ERROR_WATCHER_TOKEN` / `HULA_ERROR_WATCHER_SECRET`) and the snippet sends `X-Hula-Api-Key` (was `X-Hula-Watcher`). The watcher now holds configuration only; `--create` prints no credential of its own and instead directs you to **Projects → gear icon → Error reporting API keys**, the only place a key can be minted. **Any reporter wired up against an earlier build of this command must be updated or it will 401.**
21
+ - The printed snippet now sends `errorName` and `errorCode` alongside `key`. The server's dedupe fingerprint is built from those three identity fields and nothing else, so a report carrying none of them shares a single bucket with every other such report — one fix per watcher per dedupe window.
22
+ - `--events` with no watcher id lists the project's watchers and queries each one, merging the results newest-first. It previously requested a project-wide events route that does not exist on the server and always returned 404.
23
+ - `--update` now rejects `--container-cpu`, `--container-memory`, `--container-disk`, `--update-notification-url`, and `--update-notification-name-tag` up front. The update endpoint ignores those fields, so sending them reported success while changing nothing; they remain settable at `--create`.
24
+ - `--delete` no longer claims reports will start returning 401. Deleting a watcher revokes no credential — ingest keys keep authenticating, and the webhook answers 409 once the project has no enabled watcher left.
25
+ - `--show` displays the watcher's `instructions` and no longer prints the vestigial watcher token prefix.
26
+ - A `409` from the ingest webhook now maps to a specific message naming the cause ("no enabled error watcher is configured for this project") and the commands that fix it, instead of falling through to a generic status line.
27
+
28
+ ### Removed
29
+
30
+ - `hula error-watcher --rotate`. It rotated the watcher's signing secret, which the ingest webhook no longer verifies, and its response handling did not match the server's shape. The signing secret that matters belongs to the project ingest key and is rotated from the dashboard settings page, which has no REST route for the CLI to call.
31
+
32
+ ## [1.24.0] - 2026-08-18
33
+
34
+ ### Fixed
35
+
36
+ - Entitlement is now verified with the server on every launch instead of being cached indefinitely in local config. A cancelled subscription, an expired free trial, or exhausted PR credits no longer slips past the local gate only to fail later against the server. `usageTier` is now treated as a refreshable cache of the last server answer, consulted only when the server is unreachable.
37
+ - Access-denied messages now reflect the account's actual subscription status — never subscribed (offers the free trial), cancelled, payment failed, or the server's status verbatim — instead of always claiming the user is on the free tier.
38
+ - Billing and upgrade links point at the configured server's own dashboard rather than a hardcoded hublaunch.site, so preview and self-hosted deployments send users to their own billing page.
39
+ - Chained hula skills (`/hula-plan` → confirm → launch) now execute inline explicitly, fixing the "blocked by disable-model-invocation" break under newer Claude Code versions that enforce that flag on model-initiated Skill-tool calls.
40
+
41
+ ### Changed
42
+
43
+ - Prefer the server's own 402 response message and its `upgradeUrl` / `buyCreditsUrl` over anything the CLI infers, in both the single-repo and `--folder` launch paths.
44
+
10
45
  ## [1.23.0] - 2026-08-13
11
46
 
12
47
  ### Added
package/README.md CHANGED
@@ -128,6 +128,7 @@ they're there when you want them:
128
128
  | `/hula-confirm` | Re-validate a plan you've edited by hand |
129
129
  | `/hula-upload` | Sync a plan to `origin/main` (normally automatic during launch) |
130
130
  | `/hula-schedule` | Run or schedule autonomous actions (e.g. a nightly `harden` security audit) |
131
+ | `hula error-watcher` | Manage production Error Watchers — inbound error webhooks that auto-launch fix PRs |
131
132
  | `/hula-help` | Interactive onboarding and reference — walks through setup, the workflow, or any command/skill |
132
133
  | `/hula-create` | Legacy: create an issue without launching (the modern flow is `/hula-plan` → launch) |
133
134
 
@@ -135,6 +136,64 @@ Full details: [Commands Reference](./docs/commands.md) ·
135
136
  [Advanced Usage](./docs/advanced.md) (launch pipeline internals, resume,
136
137
  test mode, env forwarding, scheduling).
137
138
 
139
+ ## Error Watchers
140
+
141
+ An **Error Watcher** is an inbound webhook: your production app reports an error
142
+ to HubLaunch, HubLaunch deduplicates it, and — when the error is new — auto-launches
143
+ a fix (a PR, a plan, or a feedback run). Manage watchers from the CLI:
144
+
145
+ Reporting an error needs **two** pieces, created in different places:
146
+
147
+ - the **watcher** — the configuration (dedupe window, environments, PR policy,
148
+ agent instructions), managed from the CLI;
149
+ - a **project ingest key** — the credential your app presents (`hik_…` plus its
150
+ own signing secret `his_…`), created in the dashboard under **Projects → gear
151
+ icon → Error reporting API keys**.
152
+
153
+ ```bash
154
+ # Create a watcher; prints where to mint the ingest key, a .env block, and a
155
+ # ready-to-paste signed-request snippet.
156
+ hula error-watcher --create --name api-prod
157
+
158
+ # See what your watchers have been doing, and why each error did or didn't
159
+ # launch a fix (omit the id to cover every watcher on the project)
160
+ hula error-watcher --events
161
+
162
+ # List, inspect, patch tuning, or delete
163
+ hula error-watcher --list
164
+ hula error-watcher --show <watcherId>
165
+ hula error-watcher --update <watcherId> --max-fixes-per-day 10
166
+ hula error-watcher --update <watcherId> --instructions "Never touch billing/"
167
+ hula error-watcher --delete <watcherId>
168
+
169
+ # Re-print the setup snippet at any time (placeholders only — no secrets, works offline)
170
+ hula error-watcher --print-setup
171
+ ```
172
+
173
+ Add the printed block to your production environment, filling in the key and
174
+ secret from the dashboard:
175
+
176
+ ```bash
177
+ HULA_ERROR_WEBHOOK_URL=https://www.hublaunch.site/api/v1/webhooks/error
178
+ HULA_INGEST_KEY=hik_…
179
+ HULA_INGEST_SECRET=his_…
180
+ ```
181
+
182
+ The **key and secret are shown only once** and are never handled by the CLI —
183
+ copy them into your deployment's secret store immediately. Every report is signed
184
+ with `HMAC-SHA256` over `` `${timestamp}.${body}` `` (the exact payload the printed
185
+ snippet produces) and sent as `X-Hula-Api-Key` + `X-Hula-Signature`. Rotate the
186
+ secret from the same settings page; the previous one keeps verifying for 24 hours.
187
+
188
+ Send at least a `key`, `errorName`, or `errorCode` with every report — the dedupe
189
+ fingerprint is built from those three fields alone, and a report carrying none of
190
+ them shares one bucket with every other such report.
191
+
192
+ A `409` means the key is valid but the project has no enabled watcher; create one
193
+ with `--create`. Requires a hula-server with Error Watcher support; older servers
194
+ return a clear "not supported yet" message. Full reference:
195
+ [docs/error-watcher.md](./docs/error-watcher.md).
196
+
138
197
  ## Multi-repo feature groups
139
198
 
140
199
  A feature that spans several repositories — say a mobile app plus its backend
@@ -0,0 +1,147 @@
1
+ import type { Command } from 'commander';
2
+ import type { Config } from '../types/index.js';
3
+ export interface ErrorWatcherOptions {
4
+ create?: boolean;
5
+ list?: boolean;
6
+ show?: string;
7
+ /** `--events [watcherId]`: `true` (all watchers) or a specific watcher id. */
8
+ events?: string | boolean;
9
+ update?: string;
10
+ delete?: string;
11
+ /** `--print-setup [watcherId]`: the id is informational only. */
12
+ printSetup?: string | boolean;
13
+ name?: string;
14
+ dedupeWindow?: number;
15
+ maxFixesPerDay?: number;
16
+ environments?: string;
17
+ outcomeType?: string;
18
+ prPolicy?: string;
19
+ enabled?: string;
20
+ /** Trusted guidance rendered into the fix agent's brief. */
21
+ instructions?: string;
22
+ /** Clear the stored instructions (sends `instructions: null`). */
23
+ clearInstructions?: boolean;
24
+ /** Repeatable `KEY=VALUE` env vars injected into the fix sandbox. */
25
+ errorEnv?: string[];
26
+ /** Clear all errorEnvVars (sends an empty map). */
27
+ clearErrorEnv?: boolean;
28
+ /** Repeatable literal values redacted from every payload for this watcher. */
29
+ secret?: string[];
30
+ /** Clear the extra redaction list (sends an empty array). */
31
+ clearSecrets?: boolean;
32
+ status?: string;
33
+ limit?: number;
34
+ provider?: string;
35
+ providerKey?: string;
36
+ containerCpu?: number;
37
+ containerMemory?: number;
38
+ containerDisk?: number;
39
+ updateNotificationUrl?: string;
40
+ updateNotificationNameTag?: string;
41
+ project?: string;
42
+ url?: string;
43
+ apiKey?: string;
44
+ json?: boolean;
45
+ yes?: boolean;
46
+ }
47
+ /** The mutually-exclusive command modes, in dispatch order. */
48
+ export type WatcherMode = 'create' | 'list' | 'show' | 'events' | 'update' | 'delete' | 'print-setup';
49
+ /**
50
+ * Manage production Error Watchers — thin REST client over
51
+ * `/api/v1/error-watchers`, structured like `hula schedule`.
52
+ */
53
+ export declare function errorWatcherCommand(program: Command, config: Config): void;
54
+ /**
55
+ * Commander collector for a repeatable flag. `previous` is undefined on the
56
+ * first occurrence, which is what lets a caller distinguish "flag omitted"
57
+ * (undefined) from "flag given" — the distinction PATCH relies on to leave a
58
+ * field untouched rather than clearing it.
59
+ */
60
+ export declare function collectRepeatable(value: string, previous?: string[]): string[];
61
+ /**
62
+ * Which mode flags are active. `--events` and `--print-setup` count when
63
+ * present even without a value (`true`); every other flag counts when truthy.
64
+ */
65
+ export declare function selectModes(options: ErrorWatcherOptions): WatcherMode[];
66
+ /**
67
+ * Dispatch a single mode. Enforces mutual exclusion BEFORE any network call, so
68
+ * two mode flags fail without issuing a request. With no mode flag, prints help.
69
+ */
70
+ export declare function runErrorWatcher(config: Config, options: ErrorWatcherOptions, showHelp?: () => void): Promise<void>;
71
+ /**
72
+ * The ingest webhook URL the customer's production app POSTs to. Defaults to
73
+ * `<serverUrl>/api/v1/webhooks/error`, overridable via `config.errorWebhookUrl`
74
+ * for self-hosted servers whose webhook host differs from `hulaProjectUrl`.
75
+ */
76
+ export declare function resolveWebhookUrl(serverUrl: string, config: Config): string;
77
+ /**
78
+ * Where a project ingest key (`hik_…`) is minted. Key CRUD is exposed over
79
+ * tRPC only — there is no REST route for the CLI to call — so every setup path
80
+ * points the user at this page rather than pretending to issue a credential.
81
+ */
82
+ export declare function resolveProjectSettingsUrl(serverUrl: string): string;
83
+ /**
84
+ * Validate tuning flags client-side so the common mistakes are caught without a
85
+ * network round trip. Returns a list of error strings (empty when all valid).
86
+ * The server validates independently; this is a convenience, not the boundary.
87
+ */
88
+ export declare function validateTuningOptions(options: ErrorWatcherOptions): string[];
89
+ /**
90
+ * Validate the repeatable `--error-env KEY=VALUE` pairs. Reserved names are
91
+ * rejected here because the server returns a 400 for them, and the platform
92
+ * owns those variables inside the fix sandbox.
93
+ */
94
+ export declare function validateErrorEnv(entries: string[] | undefined): string[];
95
+ /**
96
+ * Validate the repeatable `--secret` values. The minimum length is the server's
97
+ * floor: a very short literal would match everywhere and shred the very error
98
+ * text the fix agent needs.
99
+ */
100
+ export declare function validateSecrets(entries: string[] | undefined): string[];
101
+ /** Parse validated `KEY=VALUE` entries into the map the server expects. */
102
+ export declare function parseErrorEnv(entries: string[]): Record<string, string>;
103
+ /**
104
+ * The signed-request snippet. HARD-CODED (never fetched) so `--print-setup`
105
+ * works with the server unreachable. Built line-by-line from single/double
106
+ * quoted strings so the literal `${timestamp}.${body}` signing payload survives
107
+ * verbatim into the printed output (it must NOT be interpolated here).
108
+ */
109
+ export declare function buildSigningSnippet(): string;
110
+ /**
111
+ * The `.env` block for the customer's production environment.
112
+ *
113
+ * The credential is the PROJECT ingest key (`hik_…`) and its own signing secret
114
+ * (`his_…`), minted in the dashboard settings page — not the watcher. The CLI
115
+ * never holds either value, so both are always placeholders.
116
+ */
117
+ export declare function buildEnvBlock(webhookUrl: string): string;
118
+ /**
119
+ * Print the wiring steps for a watcher: mint the project ingest key, set the
120
+ * env vars, paste the signed-request snippet.
121
+ *
122
+ * The CLI deliberately prints no credential of its own. Ingest keys are created
123
+ * over tRPC from the dashboard and have no REST route, so the only honest thing
124
+ * the CLI can do is say where to get one. The watcher `hew_`/`hes_` values the
125
+ * create endpoint still returns authenticate nothing and are never shown.
126
+ */
127
+ export declare function printSetupInstructions(serverUrl: string, webhookUrl: string): void;
128
+ /**
129
+ * One-line rendering of the watcher's `instructions`. Long guidance is elided
130
+ * rather than wrapped so the field stays one row in the detail block.
131
+ */
132
+ export declare function summarizeInstructions(instructions: string | null | undefined, maxLen?: number): string;
133
+ /** Humanize a duration in seconds: 300 → 5m, 3600 → 1h, 86400 → 24h, 604800 → 7d. */
134
+ export declare function humanizeDuration(seconds: number): string;
135
+ /** Relative time such as "12m ago" for an ISO timestamp. */
136
+ export declare function relativeTime(iso: string): string;
137
+ /**
138
+ * Map server responses to actionable messages. NEVER echoes the Authorization
139
+ * header, the watcher token, or the secret — none of those are read from the
140
+ * error object, so no redaction pass is needed. Re-throws non-axios errors for
141
+ * the caller's outer handler.
142
+ */
143
+ export declare function handleWatcherApiError(error: unknown, serverUrl: string, ctx?: {
144
+ project?: string;
145
+ watcherId?: string;
146
+ }): void;
147
+ //# sourceMappingURL=errorWatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorWatcher.d.ts","sourceRoot":"","sources":["../../src/commands/errorWatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Signing fixture for the reporter snippet the CLI prints.
3
+ *
4
+ * The CLI does not sign anything itself — it prints a snippet the customer
5
+ * pastes into their app. This fixture pins the algorithm that snippet
6
+ * documents, so a careless edit to `buildSigningSnippet()` fails here rather
7
+ * than surfacing as an unexplained production `401`.
8
+ *
9
+ * Signing payload: `${timestamp}.${body}` — the request timestamp, a literal
10
+ * `.`, then the raw JSON body. Signing the body alone (dropping the timestamp
11
+ * prefix) removes replay protection and is the exact mistake the snippet and
12
+ * this fixture guard against.
13
+ *
14
+ * The secret is the PROJECT ingest key's signing secret (`his_…`), minted with
15
+ * the key in the dashboard settings page. The per-watcher `hes_…` secret this
16
+ * fixture used to model no longer authenticates anything.
17
+ */
18
+ export declare const WATCHER_SIGNATURE_FIXTURE: {
19
+ /** Test signing secret. NEVER a real credential. */
20
+ readonly secret: "his_test_secret_do_not_use_in_production";
21
+ /** Unix seconds, as sent in the `X-Hula-Timestamp` header. */
22
+ readonly timestamp: "1734556800";
23
+ /**
24
+ * The exact raw request body that was signed. Carries all three dedupe
25
+ * identity fields (`key`, `errorName`, `errorCode`) because those — and only
26
+ * those — build the server's fingerprint.
27
+ */
28
+ readonly body: "{\"errorDescription\":\"Payment gateway timed out\",\"key\":\"orders.checkout.timeout\",\"errorName\":\"TimeoutError\",\"errorCode\":\"ETIMEDOUT\",\"environment\":\"production\"}";
29
+ /** HMAC-SHA256(secret, `${timestamp}.${body}`) as lowercase hex. */
30
+ readonly signatureHex: "fe747ddcc36a1405b9ecc417328fbfdb0459d5c7d4d3b0528b47eed0c0b17045";
31
+ };
32
+ //# sourceMappingURL=errorWatcher.fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorWatcher.fixture.d.ts","sourceRoot":"","sources":["../../src/commands/errorWatcher.fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB;IACpC,oDAAoD;;IAEpD,8DAA8D;;IAE9D;;;;OAIG;;IAEH,oEAAoE;;CAG5D,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Signing fixture for the reporter snippet the CLI prints.
3
+ *
4
+ * The CLI does not sign anything itself — it prints a snippet the customer
5
+ * pastes into their app. This fixture pins the algorithm that snippet
6
+ * documents, so a careless edit to `buildSigningSnippet()` fails here rather
7
+ * than surfacing as an unexplained production `401`.
8
+ *
9
+ * Signing payload: `${timestamp}.${body}` — the request timestamp, a literal
10
+ * `.`, then the raw JSON body. Signing the body alone (dropping the timestamp
11
+ * prefix) removes replay protection and is the exact mistake the snippet and
12
+ * this fixture guard against.
13
+ *
14
+ * The secret is the PROJECT ingest key's signing secret (`his_…`), minted with
15
+ * the key in the dashboard settings page. The per-watcher `hes_…` secret this
16
+ * fixture used to model no longer authenticates anything.
17
+ */
18
+ export const WATCHER_SIGNATURE_FIXTURE = {
19
+ /** Test signing secret. NEVER a real credential. */
20
+ secret: 'his_test_secret_do_not_use_in_production',
21
+ /** Unix seconds, as sent in the `X-Hula-Timestamp` header. */
22
+ timestamp: '1734556800',
23
+ /**
24
+ * The exact raw request body that was signed. Carries all three dedupe
25
+ * identity fields (`key`, `errorName`, `errorCode`) because those — and only
26
+ * those — build the server's fingerprint.
27
+ */
28
+ body: '{"errorDescription":"Payment gateway timed out","key":"orders.checkout.timeout","errorName":"TimeoutError","errorCode":"ETIMEDOUT","environment":"production"}',
29
+ /** HMAC-SHA256(secret, `${timestamp}.${body}`) as lowercase hex. */
30
+ signatureHex: 'fe747ddcc36a1405b9ecc417328fbfdb0459d5c7d4d3b0528b47eed0c0b17045',
31
+ };
32
+ //# sourceMappingURL=errorWatcher.fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorWatcher.fixture.js","sourceRoot":"","sources":["../../src/commands/errorWatcher.fixture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,oDAAoD;IACpD,MAAM,EAAE,0CAA0C;IAClD,8DAA8D;IAC9D,SAAS,EAAE,YAAY;IACvB;;;;OAIG;IACH,IAAI,EAAE,gKAAgK;IACtK,oEAAoE;IACpE,YAAY,EACV,kEAAkE;CAC5D,CAAC"}