Skip to content

chore: release - merge dev into main#1162

Merged
zbigniewsobiecki merged 14 commits intomainfrom
dev
Apr 22, 2026
Merged

chore: release - merge dev into main#1162
zbigniewsobiecki merged 14 commits intomainfrom
dev

Conversation

@zbigniewsobiecki
Copy link
Copy Markdown
Member

Summary

Release dev to main.

Included commits:

161d2f4c fix: harden jira env handling in cascade-tools (#1161)
479a7497 fix(webhook-logs): add Linear and Sentry to webhook logs filter UI and CLI (#1156)
cba87c31 refactor(inline-checklist): extract ID helpers to shared module (#1155)
d6306ee9 fix(router): scope trigger dedup by work item (#1159)
48b5bf3d feat(cli): accept manual run work item metadata (#1158)
2ccc4286 fix: parse linear comment webhooks (#1157)
70f703c2 feat(pm-wizard): redesign Labels step — Combobox + bulk-create banner (#1154)
fddda841 fix(pm-wizard): support stored credentials in edit mode (#1153)
0245daf6 fix(web): restore PM wizard styling regression from specs 010-012 (#1152)
9a6329d9 fix: web build + dev deploy failing on tsc strict checks (#1151)
12220cc6 chore: remove unused API_URL import from pm-wizard-hooks.ts (#1150)
3b374eef feat(pm): webhook UX manifest migration + legacy WebhookStep retirement (spec 012) (#1149)
229a77df feat(pm): integration hardening follow-ups + wizard shared-component migration (specs 010 + 011/1-2) (#1148)
27a31fe0 docs: add Linear integration to all user-facing and architecture docs (#1147)

Validation

Post-merge, I will watch the main production deploy workflow through completion.

aaight and others added 14 commits April 18, 2026 15:47
…migration (specs 010 + 011/1-2) (#1148)

* docs(010): add spec + plans for PM integration hardening followups

* chore(010/1): lock plan 1 as .wip

* feat(010/1): manifest createCustomField hook + pm.discovery mutations

* chore(010/1): mutations complete, plan done

* chore(010/2): lock plan 2 as .wip

* feat(010/2): currentUser discovery capability + provider implementations

* chore(010/2): read cleanup done, currentUser UX restored

* chore(010/3): lock plan 3 with narrowed scope (option B)

* feat(010/3): wizard-components done — shared step components + generator dispatch

Upgrades the wizard generator from spec-010/1 placeholders to real shared
React components for every StandardStepKind. Six new components at
web/src/components/projects/pm-providers/steps/*.tsx: credentials,
container-pick, status-mapping, label-mapping, webhook-url-display,
project-scope. Generator exports STANDARD_STEP_COMPONENTS registry and
dispatches through it; unknown kinds still warn-once and render a
placeholder.

Trello/JIRA/Linear wizards keep their per-provider step adapters from
the spec-006 era — a future plan migrates them. The shared path is
live for new providers today.

new-provider-surface snapshot is tightened to pin the six new files;
wizard-generator + per-provider manifest-wizardSpec tests now assert
element.type identity against the registry instead of placeholder DOM
shapes. 55 new/updated tests, all green.

Docs updated: src/integrations/README.md (post-spec-010 additions),
root CLAUDE.md (PM-integration summary), spec 009 forward-references
spec 010, CHANGELOG entries for specs 009 + 010.

Closes plan 010/3 of spec 010.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(010): spec done — all plans complete

All three plans of spec 010 (PM integration hardening follow-ups)
shipped. Mutations (010/1) added generic pm.discovery.createLabel /
createCustomField endpoints. Read cleanup (010/2) added currentUser
discovery capability. Wizard components (010/3) landed real shared
React components for every StandardStepKind. Spec marked .done.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* docs(011): spec + plan decomposition for wizard shared migration

Spec 011 (PM Wizard Shared Migration) and its 5-plan decomposition.
Migrates Trello/JIRA/Linear wizards onto the shared StandardStepKind
components landed by spec 010 — closes the "zero per-provider step
code" promise across all three production providers, not just new
providers.

Plans: 1-shared-components (widen container-pick/project-scope with
searchable mode + widen webhook-url-display with optional signing-
secret + add 7th StandardStepKind: custom-field-mapping), 2-trello
(first consumer; OAuth stays kind:'custom'), 3-jira (issue-type stays
kind:'custom'; free-text label mode), 4-linear (retire LinearWebhook-
InfoPanel in favor of widened shared component), 5-cleanup (delete
pm-wizard-{trello,jira,linear}-steps.tsx + final docs rewrite).

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011/1): lock plan 1 (shared-components)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(011/1): shared-components done — widen 3 steps + add custom-field-mapping kind

Foundation plan for the wizard migration. Three additive widenings +
one new StandardStepKind. All changes dormant until plan 2 activates
them; the 31 spec-010 step tests pass unchanged as the backward-compat
proof.

- container-pick gains optional searchable?: boolean → dispatches to
  the existing shared Combobox (cmdk + radix) when true.
- project-scope gains the same searchable? prop; empty value still
  means "no scope" in both render paths.
- webhook-url-display gains optional secretFieldRole / secretLabel /
  secretValue / onSecretChange → renders an inline <input type="password">
  below the URL when both role + callback are supplied. Defensive: omits
  the input if role is set but callback is not (avoids uncontrolled
  secret inputs silently dropping user input).
- 7th StandardStepKind: 'custom-field-mapping'. New shared component at
  web/src/components/projects/pm-providers/steps/custom-field-mapping.tsx
  renders one row per CASCADE slot with a dropdown of discovered provider
  custom fields + optional inline "Create…" affordance wired to
  manifest.createCustomField (spec 010/1). Visual idiom matches
  status-mapping.
- STANDARD_STEP_COMPONENTS registers the new kind; generator dispatch
  falls through the existing switch path.
- new-provider-surface snapshot pins the 7th file.

Tests use element-tree identity checks where SSR would hit the React
instance mismatch (radix lives in web/node_modules and pulls its own
React). 17 new/updated test assertions across 4 files. Full suite
8153/8153, lint 0/0, typecheck + build green.

Closes plan 011/1 of spec 011.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011/2): lock plan 2 (trello)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(011/2): trello done — wizard migrated to shared step components

First real consumer of the shared wizard components. Trello's legacy
per-provider step file (pm-wizard-trello-steps.tsx) has no live importers
outside itself; deletion deferred to plan 011/5.

- TrelloOAuthStep: new custom step at pm-providers/trello/oauth-step.tsx.
  Lifts the window.open popup + manual-token fallback verbatim from the
  legacy TrelloCredentialsStep. Registered as kind:'custom' with
  component:'TrelloOAuthStep' in trelloManifest.wizardSpec.
- trelloManifest.wizardSpec.steps: now [custom(TrelloOAuthStep),
  container-pick, status-mapping, label-mapping, custom-field-mapping,
  webhook-url-display] — 6 steps, one of them custom.
- trelloProviderWizard.steps: rewritten to consume shared components via
  thin per-step adapters. useProviderHooks returns the flat shape each
  adapter slices (boardOptions, providerStates, providerLabels,
  providerCustomFields, onCreate* callbacks). Adapters call shared
  components directly with Trello-specific props.
- Adapters file (trello/adapters.tsx): deleted — orphaned after the
  wizard rewrite.
- useTrelloCustomFieldCreation: now accepts { name: string } argument
  (was hard-coded "Cost"). Enables the shared Create-form UX.

Forward-edit to plan 011/1 (additive, existing tests unchanged):
- label-mapping widened with optional labelDefaults?: Record<slot,
  {name, color?}> — pre-populates Create input, threads color to
  onCreateLabel. Trello uses it for cascade-ready/processing/etc.
- custom-field-mapping widened with optional fieldDefaults?: Record<slot,
  {name}> — pre-populates Create input. Trello uses it for cost field.

Normalize-upward UX changes (user-approved in behavior inventory):
- Dropped retry button on board-picker error (shared component shows
  error text; operator refreshes page).
- Dropped "Create All Missing Labels" batch button (per-slot Create
  covers the same ground, one click at a time).

AC #9 (no operator regression) marked **deferred** — browser smoke test
pending reviewer verification. Unit tests + conformance harness cover
wire-level invariants; no runtime behavior change in adapters
(discovery / label-creation / custom-field-creation hooks reused
unchanged).

19 Trello tests: 5 wizardSpec + 7 oauth-step + 7 wizard-generator. Plus
2 forward-edit tests on the widened shared steps. Full suite 8169/8169,
lint + typecheck + build all green.

Closes plan 011/2 of spec 011.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011/3): lock plan 3 (jira)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(011/3): jira done — wizard migrated to shared step components

Second real consumer of the shared wizard components. JIRA's legacy
per-provider step file (pm-wizard-jira-steps.tsx) has no live importers
outside itself; deletion deferred to plan 011/5.

- IssueTypeMappingStep: new JIRA-specific custom step at
  pm-providers/jira/issue-type-step.tsx. Maps CASCADE task/subtask
  roles to JIRA issue types (filtered by the `subtask` flag). Stays
  kind:'custom' rather than becoming an 8th StandardStepKind because
  JIRA is the sole consumer today — speculative abstraction avoided.
- jiraManifest.wizardSpec.steps: now [credentials, container-pick,
  status-mapping, label-mapping, custom-field-mapping,
  custom(IssueTypeMappingStep), webhook-url-display] — 7 steps, one
  custom.
- jiraProviderWizard.steps: rewritten to consume shared components via
  thin per-step adapters. Credentials step uses the shared
  `CredentialsStep` with a synthetic `base_url` role alongside email +
  api_token — no OAuth popup needed for JIRA (unlike Trello). Label
  mapping passes providerLabels: [] so the shared step renders in
  free-text mode (JIRA labels are free-form).
- Adapters file (jira/adapters.tsx): deleted — orphaned after rewrite.
- useJiraCustomFieldCreation: now accepts { name: string } argument
  (was hard-coded "Cost") so the shared Create affordance works.

Task 1 behavior inventory found the same 4 gap classes Trello
surfaced; all four were already closed by plan 011/2's forward-edit to
plan 011/1 (labelDefaults + fieldDefaults additive widenings). No
additional shared-component changes were required for JIRA.

AC #10 (no operator regression) marked **deferred** — browser smoke
test pending reviewer verification on the deployed branch. Unit tests
+ conformance harness cover wire-level invariants; legacy discovery +
custom-field hooks reused unchanged (only the name-arg tweak on the
custom-field mutation).

17 JIRA tests: 6 manifest + 7 issue-type + 4 wizard-generator. JIRA
had zero dedicated wizard-step tests before this plan — this is the
first JIRA wizard coverage landing. Full suite 8185/8185, lint +
typecheck + build all green.

Closes plan 011/3 of spec 011.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011/4): lock plan 4 (linear)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(011/4): linear done — + parent-wizard fix for plans 2+3 regression

Third real consumer of the shared wizard components. Plan 011/4 also
ships a critical fix for a regression plans 011/2 and 011/3 introduced:
pm-wizard.tsx hardcoded 3 manifest step slots (stepIndex 0/1/2) from
the spec-006 era. Trello/JIRA wizardSpecs grew to 6+ steps; only the
first 3 rendered on the deploy — label-mapping, custom-field-mapping,
and issue-type-mapping steps were INVISIBLE in production.

Fix: pm-wizard.tsx now iterates over `manifestDef.steps`, rendering
one WizardStep slot per entry. Webhook steps (id ends with `-webhook`)
are filtered out — the legacy WebhookStep still owns programmatic
webhook registration (Trello/JIRA API calls) and Linear's signing-secret
UX. The shared `webhook-url-display` component (widened in plan 011/1)
remains dormant for the three existing providers until a follow-up plan
migrates webhook-creation UX into the manifest path.

Linear wizard migration:

- linearProviderWizard.steps: rewritten to consume shared components
  via 6 thin per-step adapters. No kind:'custom' steps — Linear has no
  OAuth popup (like Trello) and no issue-type mapping (like JIRA).
- LinearWebhookDisplayAdapter: Fragment composing shared
  WebhookUrlDisplayStep + ProjectSecretField (LINEAR_WEBHOOK_SECRET).
  Currently dormant; activates after legacy WebhookStep migration.
- project-scope step (spec 005): uses the shared ProjectScopeStep with
  `searchable: true`.
- label-mapping: uses shared component with LINEAR_LABEL_DEFAULTS
  (plan 011/1 forward-edit) pre-populating the Create input with
  cascade-ready/processing/etc. and threading hex colors.
- Adapters file (linear/adapters.tsx): deleted — orphaned after
  rewrite.
- Legacy step tests deleted: linear-field-mapping-step.test.ts,
  linear-team-step.test.ts, linear-webhook-info-panel.test.ts
  (-450 lines). Replaced by 8-test linear-wizard-generator.test.ts
  covering the wizard wiring + manifest↔definition parity.

AC #3 (inline webhook secret), #6 (LinearWebhookInfoPanel retired),
and #11 (no operator regression) marked **partial/deferred** — see
Progress section for details. All other ACs green.

Full suite 8167/8167, lint + typecheck + build all green.

Closes plan 011/4 of spec 011.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011/5): lock plan 5 (cleanup)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(011/5): cleanup done — deleted 3 legacy step files + docs rewrite

Closes spec 011 per user-approved option (a) — tight scope: deletions
+ docs. Scope-clipped items (full LinearWebhookInfoPanel retirement,
Linear inline-secret via shared component) carry over as follow-up
work; rationale is captured in the plan's Progress section.

Deletions:
- web/src/components/projects/pm-wizard-trello-steps.tsx (retired
  since plan 011/2; no live importers)
- web/src/components/projects/pm-wizard-jira-steps.tsx (since 011/3)
- web/src/components/projects/pm-wizard-linear-steps.tsx (since 011/4)
- pm-wizard.tsx dead comments about transitive imports of the above

Audits:
- pm-wizard-common-steps.tsx — all three remaining exports
  (LinearWebhookInfoPanel, WebhookStep, SaveStep) still have live
  consumers via pm-wizard.tsx. File retained.
- Dead-code grep: only doc-comment references to the deleted files
  remain; no live imports.

Docs:
- src/integrations/README.md — four-specs preamble (006/009/010/011);
  "seven kinds" in "Adding a new PM provider" step 3;
  Post-spec-011 additions table alongside the Post-spec-010 one.
- CLAUDE.md (project root) — PM-integration summary references
  spec 011.
- CHANGELOG.md — Internal entry for spec 011 alongside 009/010.
- docs/specs/010-pm-integration-hardening-followups.md.done —
  forward-reference blockquote to spec 011.

Verification:
- npm test: 8167 passed, 23 skipped
- npm run lint: clean
- npm run typecheck: green
- npm run build: green
- Conformance harness: all three providers pass
- new-provider-surface guard: 7 step files pinned

Closes plan 011/5 of spec 011.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(011): spec done — all plans complete

Five plans of spec 011 (PM Wizard Shared Migration) shipped. Shared
components widened (plan 1), Trello migrated (plan 2), JIRA migrated
(plan 3), Linear migrated + pm-wizard.tsx parent refactor (plan 4),
legacy per-provider step files deleted + docs closed (plan 5). Spec
marked .done.

Deferred to follow-up spec:
- Full migration of webhook-creation UX (Trello/JIRA programmatic
  webhook registration + Linear signing-secret persistence) into the
  manifest path. Legacy WebhookStep + LinearWebhookInfoPanel still
  render for this.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
…nt (spec 012) (#1149)

* docs(012): spec + plan decomposition for webhook manifest migration

Spec 012 (PM Webhook Manifest Migration) and its 4-plan decomposition.
Closes the final gap from spec 011 — moves each provider's webhook-
creation UX from the legacy WebhookStep + LinearWebhookInfoPanel into
manifest-path webhook adapters in each provider's folder.

Plans: 1-trello-webhook (programmatic create + active list + delete +
curl fallback composed with shared WebhookUrlDisplayStep), 2-jira-webhook
(JIRA equivalent + jiraEnsureLabels preserved), 3-linear-webhook
(signing-secret via ProjectSecretField + 5-step instructions; removes
the -webhook filter from pm-wizard.tsx), 4-cleanup (delete legacy
WebhookStep + LinearWebhookInfoPanel + 2 hooks + legacy test file +
empty legacy slot; rewrite docs + close spec 011 coverage-map).

Strategic decisions (composition over widening; keep flag-based webhooks.*
tRPC endpoints as-is; linear migration sequence) documented in spec.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(012/1): lock plan 1 (trello-webhook)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(012/1): trello-webhook done — migrate Trello webhook UX to manifest path

First of three per-provider webhook migrations. Moves Trello's
webhook-creation UX from the legacy `WebhookStep` into a new manifest-
path adapter `TrelloWebhookAdapter`. All `webhooks.*` tRPC endpoints
reused verbatim (no backend change); only the render path moves.

- web/src/components/projects/pm-providers/trello/webhook-step.tsx:
  new file. Fragment composing the shared `WebhookUrlDisplayStep` (URL
  + copy) with Trello-specific UX — active-webhooks list with status
  dots + delete buttons, "Create Webhook" button wired to
  `webhooks.create({ trelloOnly: true })`, curl fallback template with
  `trelloBoardId` interpolated.
- trello/wizard.ts: extend `TrelloProviderHooks` with webhook
  plumbing (callbackBaseUrl, activeTrelloWebhooks, createTrelloWebhook,
  deleteTrelloWebhook, loading/error states). Inline the
  `useWebhookManagement` formula in `useProviderHooks` (legacy hook
  gets deleted in plan 012/4). Replace old `TrelloWebhookDisplayAdapter`
  (URL-only) with `TrelloWebhookAdapter`.
- pm-wizard.tsx: adjust filter from `.endsWith('-webhook')` to
  `id !== 'jira-webhook' && id !== 'linear-webhook'`. Trello's webhook
  step now passes through the manifest iteration; JIRA + Linear still
  route through legacy `WebhookStep` until plans 012/2-3.

10 new tests in `tests/unit/web/trello-webhook-step.test.ts` covering
URL display, active-list rendering, Create button disabled/enabled
states, curl interpolation, delete button count, Linear-secret
regression guard.

Full suite 8177/8177, lint + typecheck + build all green.

Closes plan 012/1 of spec 012.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(012/2): lock plan 2 (jira-webhook)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(012/2): jira-webhook done — migrate JIRA webhook UX to manifest path

Second of three per-provider webhook migrations. Same Fragment-
composition pattern as plan 012/1's Trello adapter.

- web/src/components/projects/pm-providers/jira/webhook-step.tsx:
  new file. Fragment composing shared `WebhookUrlDisplayStep` + active
  list + Create button + curl fallback (JIRA REST API v1 endpoint
  preserved verbatim — legacy used `/rest/webhooks/1.0/webhook`; v3
  migration is out of scope) + per-webhook delete buttons.
- jira/wizard.ts: extend `JiraProviderHooks` with webhook plumbing;
  inline `webhooks.list/create/delete({jiraOnly:true})` in
  `useProviderHooks`. Replace old `JiraWebhookDisplayAdapter`
  (URL-only) with `JiraWebhookAdapter`. jiraEnsureLabels side-effect
  runs server-side inside webhooks.create — no frontend change needed
  to preserve it.
- pm-wizard.tsx: adjust filter to `id !== 'linear-webhook'`. JIRA's
  webhook step now passes through manifest iteration; only Linear
  still routes through legacy `WebhookStep`.

10 new tests in `tests/unit/web/jira-webhook-step.test.ts`.
Full suite 8187/8187, lint + typecheck + build all green.

Closes plan 012/2 of spec 012.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(012/3): lock plan 3 (linear-webhook)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(012/3): linear-webhook done — migrate Linear webhook UX to manifest path

Third and final per-provider webhook migration. Linear has no
programmatic registration (Linear's API forbids it), so the adapter
is a Fragment of shared WebhookUrlDisplayStep + info banner +
ProjectSecretField + 5-step setup instructions. No Create/delete/curl.

- web/src/components/projects/pm-providers/linear/webhook-step.tsx:
  new file. Extracts the inlined `LinearWebhookDisplayAdapter` from
  `linear/wizard.ts` and extends it with the 5-step setup instructions
  that previously lived in the retiring `LinearWebhookInfoPanel` (plan
  012/4 deletes the panel). Fragment composition; the secret field is
  NOT a controlled input — `ProjectSecretField` self-manages its
  server round-trip via project-credentials tRPC endpoints.
- linear/wizard.ts: delete the inlined `LinearWebhookDisplayAdapter`,
  import + use the new component. No `useProviderHooks` changes —
  plan 011/4 already exposed `projectIdForSecret` +
  `webhookSecretCredential`.
- pm-wizard.tsx: remove the `-webhook` id-skip filter entirely.
  `renderedManifestSteps = manifestDef.steps.map(...)` with no filter.
  All three providers now route through the manifest path. The legacy
  `WebhookStep` slot still renders but no provider's state matches its
  Trello/JIRA/Linear branch conditions — it's a no-op until plan 012/4
  deletes the slot entirely.

7 new tests in `tests/unit/web/linear-webhook-step.test.ts`. Same
`ProjectSecretField` mock pattern as plan 011/1 (React-instance
mismatch from web/node_modules). Full suite 8194/8194, lint +
typecheck + build all green; `regression-2026-04.test.ts` still
passes (adapter untouched).

Closes plan 012/3 of spec 012.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(012/4): lock plan 4 (cleanup)

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(012/4): cleanup done — delete legacy WebhookStep + 2 hooks + legacy test + docs close

Closes spec 012 and the final gap from spec 011. Every PM wizard step,
without exception, now renders via the manifest path.

Deletions:
- `WebhookStep` export from pm-wizard-common-steps.tsx (file kept —
  `SaveStep` still live; the provider-agnostic step patterns going
  forward live inside each provider's folder).
- `LinearWebhookInfoPanel` export from the same file.
- `useWebhookManagement` + `useLinearWebhookInfo` from
  pm-wizard-hooks.ts (each provider's `useProviderHooks` now inlines
  the `webhooks.*` tRPC + callbackBaseUrl formula).
- pm-wizard.tsx: legacy webhook `<WizardStep>` slot + the
  `webhookStepNumber` / `activeWebhooks` / `linearWebhookUrl` /
  `linearWebhookSecretCredential` / `webhooksQuery` / `webhookManagement`
  derivations; imports of deleted symbols. Parent wizard now owns only
  the provider picker (step 1) and the Save step.
- tests/unit/web/pm-wizard-webhooks-step.test.ts (-181 lines, 8 tests —
  assertions now live in the three per-provider adapter tests).

Docs:
- src/integrations/README.md — five-specs preamble; Post-spec-012
  additions section; step-3 guidance updated (Fragment composition
  pattern for webhook-step extension, alongside `kind: 'custom'` for
  fully provider-specific steps).
- CLAUDE.md (project root) — PM-integration summary references
  spec 012.
- CHANGELOG.md — Internal entry summarizing spec 012 alongside 009/
  010/011.
- docs/specs/011-pm-wizard-shared-migration.md.done — forward-
  reference blockquote to spec 012.
- docs/plans/011-pm-wizard-shared-migration/_coverage.md — spec 011
  AC #3 marked "closed by spec 012" downstream.
- docs/plans/011-pm-wizard-shared-migration/4-linear.md.done — plan
  011/4 ACs #3 + #6 marked closed downstream (originally partial).

Dead-code grep: only doc-comment references to the retired symbols
remain; no live imports. Full suite 8186/8186, lint + typecheck +
build all green.

Closes plan 012/4 of spec 012.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* chore(012): spec done — all plans complete

Four plans of spec 012 (PM Webhook Manifest Migration) shipped. Trello
+ JIRA + Linear webhook steps migrated to manifest path (plans 1-3);
legacy WebhookStep + LinearWebhookInfoPanel + supporting hooks + legacy
test file deleted, docs closed (plan 4). Spec marked .done.

Every PM wizard step, without exception, renders via the manifest
path. Plan 011/4 ACs #3 + #6 fully close.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
Adhoc cleanup. Leftover from plan 012/4 — deleted useWebhookManagement
and useLinearWebhookInfo (the two consumers of API_URL); each
provider's wizard now imports API_URL directly inside its own
useProviderHooks. Biome flagged it as a warning, which CI did not
fail on.

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
The dev deploy + CI `Build frontend` step have been failing since PR
#1148 (spec 011 merge). Root cause: `cd web && npm run build` runs
`tsc -b` which is stricter than the root `npm run typecheck` I've
been using for local verification. Three classes of errors surfaced:

1. `steps/webhook-url-display.tsx` + `steps/container-pick.tsx` had
   a `readonly /** jsdoc */ fieldName: string` pattern (pre-existing
   from spec 010/3). Stricter tsc parses this as `readonly: any` on
   its own + bare `fieldName: string` without the readonly modifier
   (TS7008). Downstream callers couldn't satisfy the broken interface
   (TS2345). Fixed by moving the JSDoc comment above the `readonly`
   keyword.

2. `pm-wizard-hooks.ts` verify-button flow passes `capability:
   'currentUser'` to `pm.discovery.discover`, but the Zod enum at
   the tRPC input schema was missing `'currentUser'` (pre-existing
   from spec 010/2 — type union was updated but the enum wasn't).
   Every wizard Verify-button call failed at runtime Zod validation.
   Fixed by promoting the enum to `src/pm/types.ts` as
   `DISCOVERY_CAPABILITIES` (const array) and deriving both the
   `DiscoveryCapability` type union and the tRPC Zod enum from it —
   the two can no longer drift.

3. `jira/wizard.ts` mapped `details?.fields` directly to
   `providerCustomFields`, but JIRA's discovery shape is
   `{id, name, custom}` while the shared prop contract expects
   `{id, name, type}` (introduced by me in plan 011/3 / 012/2).
   Fixed by mapping `custom: boolean` → `type: 'custom' | 'standard'`.

Tests:
- New regression in `tests/unit/api/pm-discovery.test.ts`:
  `accepts currentUser capability (closes Zod-enum / type-union drift)`
  pins the root-cause invariant.
- Existing 13 pm-discovery tests continue to pass.
- Full suite: 8187/8187 (+1 vs pre-fix).

Verified: `npm test`, `npm run lint`, `npm run typecheck`,
`npm run build`, `cd web && npm run build` — all green.

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
)

* feat(ui): add NativeSelect primitive + DataProps helper

SSR-safe `<select>` wrapper matching shadcn SelectTrigger's utility
classes — shadcn's radix-based Select breaks renderToStaticMarkup,
so the PM wizards need a plain styled select they can use in
createElement paths.

DataProps is a tiny index-signature widener restoring the
`[key: \`data-\${string}\`]: unknown` shape that @types/react 19.1
dropped from HTMLAttributes — it's needed so createElement(Button,
{ 'data-action': 'x' }) typechecks under strict mode.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* refactor(ui): extract shared CopyButton to ui/copy-button.tsx

Moved the previously cross-file-imported CopyButton from
integration-scm-tab.tsx into its own primitive under ui/copy-button.tsx.
The alerting tab and PM webhook adapters now import from the canonical
location instead of reaching into a sibling tab module.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* fix(pm-wizard): apply shadcn primitives to shared step components

Swap raw <input>, <button>, <select>, <label> elements — all of which
shipped with pm-wizard-* BEM class names that have zero CSS definitions
anywhere — to shadcn Input/Button/NativeSelect/Label + Tailwind utility
classes across the seven shared StandardStepKind components.

The Linear API-key password field was invisible on the dark theme
because the raw <input> had no border, no padding, and browser-default
transparent background. Status/label/custom-field selects were
borderless. Credentials verify button and Create-label button were
unstyled. This commit brings them back to the legacy pre-spec-010/3
visual baseline without touching SSR-level behavior.

SSR tests in tests/unit/web/steps/ were loosened to match shadcn's
attribute-order-agnostic output and to walk by prop id rather than
raw element tag.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* fix(pm-wizard): apply shadcn primitives to provider webhook adapters

Swap raw <button>, <select>, <label>, <input> elements to shadcn
primitives + Tailwind utility classes across the Trello, JIRA, and
Linear webhook-step adapters plus the JIRA issue-type step.

Visible fix: active-webhooks list now has bordered rows, delete button
is a real ghost-icon Button with a Trash2 icon, Create Webhook is a
primary Button with a spinner during creation, the curl fallback sits
inside a styled <details>/<summary> block, and the Linear info banner
uses the themed blue surface from the legacy component instead of raw
divs.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* test(pm-wizard): guard against raw HTML interactive elements

New regression test walks every .tsx under pm-providers/** and fails
CI if any file contains createElement('input'|'button'|'select'|'label')
or <input/<button/<select/<label in JSX. Comments are stripped before
matching to avoid false positives on JSDoc prose.

This is the structural guard that was missing when specs 010/3, 011,
and 012 silently stripped the PM wizard styling — root tsc and SSR
tests passed because neither asserts visual output.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
* fix(pm-wizard): route edit-mode mutations through projectId

buildEditState intentionally leaves raw API credentials blank when
re-opening an existing integration (security), but the verify,
create-label, and create-custom-field hooks required form-state
credentials and threw "Missing credentials or team selection"
client-side before reaching the backend. The discovery hooks already
had the projectId fallback — now the mutation hooks do too.

Introduces shouldUseStoredCredentials(state) in pm-wizard-state.ts
as the single source of truth for "send projectId vs send credentials".
Each hook (useVerification, useTrello/LinearLabelCreation,
useTrello/JiraCustomFieldCreation) now picks the correct path.

Team / board / project-key checks stay — those come from config
state, not credentials, so their error messages are split out.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* fix(pm-wizard): always render Verify Connection button

The gate `(!state.isEditing || !state.hasStoredCredentials || credsReady)`
hid the button precisely when it was most useful — editing an existing
integration with stored credentials but an empty API-key field. User
had no way to test that the stored key still works.

Drop the gate. Enable the button whenever credentials are ready OR the
user is editing with stored credentials (backend resolves them via
projectId path). Add a muted "Using stored credentials" hint when
taking the stored-creds path so it's obvious what's happening.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* test(pm-wizard): cover shouldUseStoredCredentials edit-mode paths

Eight new tests, one per (provider × scenario) combo. Fresh setup →
false; edit with stored creds + empty API-key → true; edit with
re-typed API-key → false; edit without stored creds → false. Locks in
the #1152-follow-up contract that stored-creds-aware mutations route
through projectId instead of throwing "Missing credentials".

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
…#1154)

* feat(ui): add color swatch to ComboboxOption

Optional `swatch` field on ComboboxOption. When set, the Combobox
renders a 12×12 rounded dot before the label in both the trigger
(selected value) and every option row in the dropdown. Accepts any
CSS color value — hex/rgb/named. Additive; existing callers that
don't set `swatch` are unchanged.

PM wizard label picker (next commit) uses this so operators can
distinguish `cascade-*` labels at a glance.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* feat(pm-wizard): redesign label-mapping step UX

The Labels step shipped with three controls per row — a dropdown, a
text input pre-filled with the SAME value as the dropdown, and a
Create button — repeated for every slot whether mapped or not.
Confusing, noisy, and makes fresh setup a 5-click chore.

This rewrite:

- **Searchable Combobox** replaces the plain <select> for enum-mode
  rows (Linear + Trello). Each label shows a color swatch so
  `cascade-*` labels are visually distinguishable.
- **Bulk-create banner** at the top: when ≥1 slot has a default but
  no mapping, one click creates every missing label with canonical
  defaults (5 clicks → 1). Hidden when every slot is mapped or when
  the provider doesn't declare `createLabel`. Wires the existing but
  previously unused `createMissingLabelsMutation` hook.
- **Per-row Create form** now renders only when the slot is unmapped.
  Mapped rows show a single clean Combobox. Cuts visual clutter ~50%.

Free-text mode (JIRA) is unchanged — plain Input per slot.

The Trello and Linear `useProviderHooks` expose the new
`onCreateMissingLabels` + `creatingMissingLabels` values; the
adapters pass them through. JIRA doesn't declare `createLabel` so
the banner stays hidden automatically.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

* test(pm-wizard): cover redesigned label-mapping step

Migrates the test strategy: enum mode uses element-tree traversal
(same pattern as container-pick.test.ts) because the new Combobox-
based rendering can't SSR through radix Popover. Free-text mode stays
on renderToStaticMarkup.

Adds coverage for the new UX contracts:
- Each slot renders a Combobox with `swatch` mapped from label.color.
- Mapped rows get `data-mapped="true"` and `data-has-create-form="false"`.
- Bulk banner renders when missing-with-defaults ≥ 1 and both
  onCreateLabel + onCreateMissingLabels are supplied; hides otherwise.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
* feat(cli): accept manual run work item metadata

* test(api): cover queued manual run metadata
…d CLI (#1156)

Co-authored-by: Cascade Bot <bot@cascade.dev>
@zbigniewsobiecki zbigniewsobiecki merged commit 795f38c into main Apr 22, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants