Skip to content

feat: integrate cdk explorer branch - #1748

Draft
megha-narayanan wants to merge 41 commits into
mainfrom
feat/cdk-explorer
Draft

feat: integrate cdk explorer branch#1748
megha-narayanan wants to merge 41 commits into
mainfrom
feat/cdk-explorer

Conversation

@megha-narayanan

@megha-narayanan megha-narayanan commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Merges the feat/cdk-explorer branch into main. The change is additive and introduces no behavior change to existing CLI commands.

Builds on the language server merged in #1681 and adds the web explorer: a new cdk explore command that serves a local, read-only web UI over a synthesized cloud assembly.

  • New cdk explore command in packages/aws-cdk. It starts a localhost web server over the cloud assembly in cdk.out, takes a single --port option (default 4200), and does not synthesize.
  • New web layer in @aws-cdk/cdk-explorer (lib/web, lib/core, and the frontend SPA): an Express backend serving a small JSON API plus an embedded single-page app, and chokidar watchers for the assembly and the source tree.
  • Uses @aws-cdk/cloud-assembly-api template-range resolution for the template viewer, and reads the synth-lock path exported from @aws-cdk/toolkit-lib to detect when source files are stale relative to the last synth.

Capabilities (folds in #1653, #1698, #1706, #1732, #1738):

  • Construct tree annotated with per-node policy-validation severity, and inherited-severity coloring on ancestor nodes.
  • Three-way navigation: double-click a construct to open its source line and its synthesized template resource, and jump from a template resource back to the source that created it.
  • Source and template viewers with Prism syntax highlighting, a YAML/JSON toggle on the template, and wavy underlines on lines that carry violations.
  • Violations panel sorted by severity, with text search and a construct-path filter.
  • Live refresh over Server-Sent Events: the tree and violations update when cdk.out changes, including an external cdk synth or cdk watch, and a banner flags a source file that has been edited since the last synth.
  • Security posture: the server binds localhost only. File and template reads are confined to the project directory, with path-escape and symlink attempts rejected, size-capped, and taken under the assembly read lock so a request never observes a mid-synth assembly. The explorer never runs the app or spawns a synth.
  • The web explorer is a pure reader over cdk.out. Synth-on-save stays with the language server.
Screenshot 2026-07-22 at 10 46 34 AM

Checklist

  • This change contains a major version upgrade for a dependency and I confirm all breaking changes are addressed
    • Release notes for the new version:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

megha-narayanan and others added 30 commits May 27, 2026 15:33
Basic scaffolding for new packages to be implemented: a core
functionality library, the lsp server, and the web explorer.

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Refactor: put LSP skeleton in a unique branch from web explorer

- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- Adds a minimal Express web server in `@aws-cdk/cdk-explorer` with a
`/api/health` endpoint
- Wires up `cdk explore` as a CLI subcommand that starts the server and
blocks until SIGINT/SIGTERM
- Port behavior: auto-increments from 4200 if default is taken; throws
if an explicit -`-port` is unavailable

Fixes #

- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…r-remerge

# Conflicts:
#	packages/aws-cdk/THIRD_PARTY_LICENSES
- Adds an assembly reader that joins `cdk.out/`'s `tree.json` with each
stack's manifest metadata into a `ConstructNode` tree carrying
`logicalId`, CFN type, and source location.
- LSP publishes CDK validation violations as `Diagnostic`s anchored to
the construct's TypeScript source line, with rule-level severity.
- LSP serves `CodeLens` entries above each construct creation site
summarising the CFN resources it produces.
- Source resolution covers `.ts` and `.js` (with sibling `.js.map`);
non-TS apps degrade gracefully (no crash, no source-linked features).

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Builds on #1592, which surfaced display-only CodeLens entries for the
CFN
resources each construct produces. This PR makes them **clickable**.
Selecting a
lens jumps to the resource's definition in the synthesized
CloudFormation template.

Features:
- **Clickable navigation** — each lens carries an `openResource` command
that opens
  the resource's template file at its logical-ID line.
- **Multi-resource picker** — constructs producing several resources
show a QuickPick;
  single-resource constructs open directly.
- **Positional `templateFile` resolution (cloud-assembly-api)** —
`buildConstructTree`
threads the owning template through the tree, switching at NestedStack
boundaries.
- **Clearer titles** — `Creates AWS::S3::Bucket`, or
`Creates 3 resources: AWS::S3::Bucket, AWS::S3::BucketPolicy,
AWS::KMS::Key`.

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…+ cloud-assembly-api core (#1592, #1617)

# Conflicts:
#	packages/@aws-cdk/cdk-explorer/lib/index.ts
- Computes character ranges for CloudFormation resource blocks in
synthesized templates and uses them for navigation in both directions:
- 
- CodeLens "go to" now selects the whole resource block (was a
zero-width cursor).
- New go-to-definition from a synthesized template back to the
construct's source.

A note on the JSON parser dependency Computing character ranges needs a
position-aware JSON parser, since JSON.parse discards offsets. The
natural choice is jsonc-parser (what the VS Code JSON language service
uses). We could not use it here: its UMD entry loads internal modules
through a parameter-shadowed require("./impl/...") that esbuild (used by
node-backpack to bundle the CLI) cannot statically trace, so the bundled
`cdk/cdk-assets` binaries fail with `Cannot find module
'./impl/format'`. Known, still-open:
[microsoft/node-jsonc-parser#57](microsoft/node-jsonc-parser#57),
[evanw/esbuild#1619](evanw/esbuild#1619). Its
ESM build bundles fine, but the esbuild mainFields workaround isn't
exposed by node-backpack, and importing the ESM build directly breaks
our CommonJS tests; marking it external isn't appropriate for a
self-contained CLI. So we use
[json-source-map](https://www.npmjs.com/package/json-source-map), a
single-file CommonJS module that bundles cleanly.


### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
The LSP currently reads `cdk.out` once at startup and never refreshes.
After this PR, any
rewrite of `cdk.out` refreshes the editor's diagnostics and CodeLenses
automatically. 

* New `lib/core/assembly-watcher.ts`: a chokidar-backed watcher with a
debounced
  200ms `onChange`, filtered to `manifest.json`, `tree.json`,
  `validation-report.json`. RWLock marker files (`synth.lock`,
`read.<pid>.<n>.lock`) are excluded. Throws from `onChange` route
through
`onError` rather than leaking from the timer. Lives in `lib/core/` so
the web
  explorer can reuse it.
* `refreshFromAssembly` is now the single fan-out for new assembly data:
rebuild `cachedIndex`, publish empty diagnostics for URIs that no longer
have
violations (clearing resolved squiggles), republish current diagnostics,
and
send `workspace/codeLens/refresh` (gated on
`workspace.codeLens.refreshSupport`).
* When the validation report fails to load, last-good diagnostics are
preserved,
  matching the existing contract for `'error'` and `'not-found'` reads.
* Watcher started in `onInitialized` after the initial refresh, closed
in
  `onShutdown`.
Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Builds the `cdk explore` web explorer UI, with a React + Cloudscape
single-page app is served by the existing
Express server, alongside file-serving API endpoints.

- **API** (`lib/web/`): `GET /api/health`, `GET /api/files?dir=`,`GET
/api/file?path=`,
- **SPA** (`frontend/`): Cloudscape `ContentLayout` with four regions.
The two center/right panes are functional server-backed file viewers
(browse + view). Header shows a "last updated" placeholder.
- **Build**: `frontend/` is compiled by esbuild (separate
`tsconfig.frontend.json`, kept off the Node `tsc` path) in
`post-compile`, then embedded into `web-assets.generated.json` and
served from memory so it travels in the
  bundled CLI. 


### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
The LSP followed source/template paths from the cloud assembly
(stack-trace
frames, source maps, template paths) with only an extension allow-list.
If
cdk.out is tampered with, a crafted path like `../../../etc/passwd.js`
could be
read or surfaced as a nav target.

Adds a symlink-aware `isWithinRoot` and gates every read: source paths
against
the project dir, `templateFile` against the assembly dir. Out-of-root
paths are
dropped as not-navigable (same as non-TS apps). No change for valid
assemblies.

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Convert the two synchronous template reads on the LSP request paths
(onDefinition and the CodeLens provider) to fs.promises, continuing the
async direction from #1631.

resourceTarget, codeLensesForFile, and commandFor are now async and read
sequentially, so the number of concurrent reads never grows with app
size. The LspHandlers interface widens onCodeLens and onDefinition to
return Promises; the connection wiring passes the Promise through
unchanged.

readAssembly and the source-map reads stay synchronous: they run at
startup and on watch events, not per request, and convert-source-map
takes a synchronous reader.

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Add utilities to source resolver to parse jsii host-language
creation-stack frames for Python, and drop the TypeScript-only
diagnostics gate. Go-to-definition (source → template, and reverse) and
policy-violation diagnostics now work for Python apps, not just
TypeScript.

Requires synthing with `JSII_HOST_STACK_TRACES=1` (opt-in; jsii 1.137+ /
aws-cdk-lib 2.260+). Auto-enabling it for LSP-triggered synth is a
follow-up. Java support separated into new PR due to FQN path parsing
complexities.

Example: 
<img width="819" height="568" alt="Screenshot 2026-06-25 at 1 30 10 PM"
src="https://github.com/user-attachments/assets/c20a136e-656f-47b2-a15f-71a585645ba0"
/>


### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Co-authored-by: Otavio Macedo <288203+otaviomacedo@users.noreply.github.com>
# Conflicts:
#	packages/@aws-cdk/integ-runner/THIRD_PARTY_LICENSES
#	packages/aws-cdk/THIRD_PARTY_LICENSES
#	packages/cdk-assets/THIRD_PARTY_LICENSES
#	yarn.lock
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Adds manual synth and auto-synth-on-save to the CDK LSP. The cdk.out
watcher (landed in #1630) handles all diagnostics/lens refreshes --
these commands just add new ways to produce a fresh assembly.

Features:
↻ Synth now CodeLens at the top of any CDK source file (only when
auto-synth is off)
▶ Enable auto-synth / ⏹ Disable auto-synth toggle
Auto-synth starts disabled
When auto-synth is on, saving any non-ignored file in the project
triggers a synth
All feedback/output goes to the Output panel, no popups

Design decisions (the important ones):

Concurrent synths are supressed: if a save fires during a slow synth,
that save is skipped. The next save picks it up.
cdk.json is read once at startup. Changing it requires an LSP restart.
The toggle/synth lenses only appear on files that already have L1
resource lenses. Files with no CDK resources see nothing.
Toggle state resets to disabled on LSP restart (not persisted).

NOTE: One thing not in this PR (but must land before prod) is a
workspace trust gate. We should verify with the user that they trust
this workspace before running any synth. I may need to set up some way
to preserve this between sessions.

Open questions / things I need some feedback on:
- Is "auto-synth" the right name? Alternatives: "synth on save", "live
synth"?
- Where should the toggle live? Line 0 of a CDK file works for LSP-only,
but it's only visible when you're in a file with constructs. Status bar
item would be better UX but needs a client extension. Is there a better
alternative?
- Should synth failures (app compile errors) be more visible than the
Output panel? A diagnostic on the first line of the failing file, for
example?
- If the app has context lookups and no cached cdk.context.json, synth
fails with an auth/context error. Should the error message detect this
and suggest running cdk synth in terminal first?

<img width="809" height="161" alt="Screenshot 2026-06-16 at 3 41 01 PM"
src="https://github.com/user-attachments/assets/b542927c-0206-462f-8464-2c43f19bbe0b"
/>
<img width="771" height="166" alt="Screenshot 2026-06-16 at 3 41 10 PM"
src="https://github.com/user-attachments/assets/52695e76-2e1d-4fc8-ada7-d1ce338512cf"
/>

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
# Conflicts:
#	packages/@aws-cdk/cdk-explorer/package.json
#	packages/aws-cdk/.projen/tasks.json
#	packages/aws-cdk/THIRD_PARTY_LICENSES
#	yarn.lock
Adds two read-only views to the `cdk explore` web UI.

- **Construct tree** (`GET /api/tree`): the synthesized construct
hierarchy. Each
node is flagged with the highest severity of any policy violation on it,
so
  problem areas are visible at a glance.
- **Policy-validation panel** (`GET /api/policy-validation`): violations
grouped
  by rule, sorted by severity, labeled with the originating plugin.

The server reads the cloud assembly in `cdk.out` and returns a
wire-stable,
app-relative view. The backend owns the full transform from core
construct node
to displayed node, including default-child collapse and the per-node
highest-severity join, so the frontend renders without re-deriving any
of it.


## Out of scope 

- Navigation between a construct, its synthesized template, and its
source. The
wire model already carries `templateFile` and `sourceLocation`, but no
  navigation UI yet.
- Frontend tests (adds deps, so future PR)

frontend:
<img width="1505" height="857" alt="Screenshot 2026-07-01 at 11 32
09 AM"
src="https://github.com/user-attachments/assets/0086cdf4-175b-49a4-917e-ebb6bdf44f9d"
/>



### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Setting JSII_HOST_STACK_TRACES=1 on the synth subprocess makes jsii
forward the host-language frames, so resolveFrames finds the .py/.java
source.

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
…1669)

- Adds LSP hover on construct creation lines showing the resolved
CloudFormation logical ID, resource type, construct path, and top-level
CFN properties with values
- Each property value links to its exact line in the synthesized
template; the logical ID header links to the resource block
- Multi-resource constructs show auxiliaries inline (≤5 listed
individually, >5 collapsed to a type histogram like "6× Subnet, 3×
RouteTable")
- Extends `template-ranges.ts` with `resolveResourceRanges` /
`indexTemplateRanges` to resolve per-property character ranges in a
single parse
- Exports `cfnProperties` from the construct tree builder so the hover
has access to resolved property values

example hover:
<img width="1128" height="645" alt="Screenshot 2026-06-24 at 12 12
52 PM"
src="https://github.com/user-attachments/assets/36451ea5-a753-43d0-a16a-293cf23ab776"
/>

<img width="1123" height="641" alt="Screenshot 2026-06-24 at 12 13
44 PM"
src="https://github.com/user-attachments/assets/8320d612-fd1d-4c84-94aa-6eed9d7caa37"
/>



Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license

---------

Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…r stdio (#1670)

Editors and AI agents start a language server by running a command over
stdio,
but the CDK Language Server (in `@aws-cdk/cdk-explorer`) has no such
entry
point. This adds one, so any LSP-capable editor or agent can get CDK
diagnostics and CodeLens by pointing at `cdk lsp`.

Wires up `cdk lsp` as a CLI subcommand that starts the server on
stdin/stdout
and runs until the client closes the channel.

- Adds `@aws-cdk/cdk-explorer` as a runtime dependency so the server
ships in the CLI bundle, version-aligned with the user's CDK toolchain.
- Writes nothing to stdout (CLI logs already go to stderr), keeping the
JSON-RPC channel clean. `applicationDir` comes from the LSP `initialize`
options, so the command takes no arguments.
- Mirrors the `cdk explore` wiring from #1598 

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
…#1711)

startServer now requires toolkitBindingsFactory (added in #1634/#1669),
but the cdk lsp command still called it with only { readable, writable
}, breaking the build. Expose startLspServer() from cdk-explorer (wires
the Toolkit bindings and starts the server) and call it from the CLI.
main.ts becomes that exported function, making cdk lsp the single LSP
entrypoint.

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Adds live refresh to the cdk explore web UI. When the cloud assembly on
disk changes, the server pushes an event and the SPA re-fetches, so the
construct tree and violations stay current without a manual reload.

- SSE stream (GET /api/events): a long-lived server-sent events channel.
SseBroadcaster tracks connected clients and pushes to all of them,
evicting any that disconnect.
- cdk.out watcher: same watcher as LSP
- SPA: subscribes on load and re-fetches the tree and violations on each
event.
- The event carries no payload. The server holds no assembly state, so
the client just re-reads /api/tree and /api/policy-validation on
receipt. Also narrows the web routes' injectable readAssembly seam to
Promise<AssemblyReadResult> to match the real reader.

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Matching LSP side of #1706. Moves the assembly read-lock acquirer out of
lib/lsp into lib/core/assembly-lock.ts so the LSP and web server build
the
read lock from one shared factory. Pure refactor, LSP behavior is
unchanged,
and server.ts re-exports AssemblyLock so existing importers keep
resolving it.

Fixes #

### Checklist
- [ ] This change contains a major version upgrade for a dependency and
I confirm all breaking changes are addressed
  - Release notes for the new version:

---
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license
Brings merged LSP work (#1697, #1669, #1670, #1711, #1715) into the explorer
branch. CLI command map now carries both 'cdk explore' and 'cdk lsp';
regenerated the user-input files from cli-config.ts. express remains a bundled
dependency of the explorer web server.
@github-actions

Copy link
Copy Markdown
Contributor

Total lines changed 3530 is greater than 1000. Please consider breaking this PR down.

@ShadowCat567 ShadowCat567 added the pr/exempt-size-check Skips PR size check label Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works better if this file lives in frontend/tsconfig.json

@mrgrain mrgrain left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance we can replace with a smaller, more modern alternative? I suspect we only need a small subset of the features express offers.

https://e18e.dev/docs/replacements/express.html#replacements-for-express

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants