Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,19 @@ When embedded in Express, the MCP endpoint is also available over HTTP at `/__ng

#### Agent Tools

| Tool | Description |
| ------------------------------- | ------------------------------------ |
| `ng-devtools:get-routes` | List Angular routes from source |
| `ng-devtools:get-components` | Discover components, inputs, outputs |
| `ng-devtools:build-meta` | Angular/TS versions, SSR status |
| `ng-devtools:highlight` | Highlight a component in the page |
| `ng-devtools:inspect-signals` | Signal graph for a component |
| `ng-devtools:inspect-providers` | DI providers and resolution path |
| `ng-devtools:get-ngrx-store` | Scan source for NgRx store patterns |
MCP clients see these with an underscore, as `ng-devtools_get-routes`.

| Tool | Description |
| ------------------------------- | ----------------------------------------------------------- |
| `ng-devtools:get-routes` | List Angular routes from source |
| `ng-devtools:get-components` | Discover components and directives, with inputs and outputs |
| `ng-devtools:get-signals` | Signal declarations from source |
| `ng-devtools:get-providers` | DI providers from source |
| `ng-devtools:build-meta` | Angular/TS versions, SSR status |
| `ng-devtools:highlight` | Highlight a component in the page |
| `ng-devtools:inspect-signals` | Signal graph a connected page reported |
| `ng-devtools:inspect-providers` | Injector tree a connected page reported |
| `ng-devtools:get-ngrx-store` | Scan source for NgRx store patterns |

#### Agent Resources

Expand Down Expand Up @@ -134,12 +138,24 @@ See the [Chrome Extension](#chrome-devtools-extension-1) section below for how t

### Browser Overlay

The overlay runs inside the user's Angular page and collects live component, signal, DI, and NgRx data:
The overlay runs inside the user's Angular page and collects live component, signal, DI, and NgRx data. Importing the module starts it, so in most apps that import is all that is needed:

```ts
import '@santoshyadavdev/ng-devtools/overlay';
```

It looks for the devframe connection next to the page and then at
`/__ng-devtools/`.

`initOverlay` is exported for a devtools mounted somewhere else. Importing the
module has already started an overlay on the default URLs by then, so dispose of
that one before starting another, or the page ends up with two connections and
two polling intervals:

```ts
import { initOverlay } from '@santoshyadavdev/ng-devtools/overlay';

const dispose = await initOverlay();
const dispose = await initOverlay({ baseURL: '/__my-devtools/' });
Comment thread
erkamyaman marked this conversation as resolved.
```

### In-Page Popup
Expand Down
4 changes: 4 additions & 0 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
box-sizing: border-box;
margin: 0;
}
:root {
/* Angular brand, from the wordmark on angular.dev. */
--accent: #ff6b85;
}
body {
font-family:
system-ui,
Expand Down
55 changes: 42 additions & 13 deletions app/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,28 @@ type Tab = 'dashboard' | 'components' | 'routes' | 'signals' | 'injectors' | 'st
template: `
<header>
<div class="brand">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polygon points="12 2 22 8.5 22 15.5 12 22 2 15.5 2 8.5 12 2" />
<line x1="12" y1="22" x2="12" y2="15.5" />
<polyline points="22 8.5 12 15.5 2 8.5" />
<!-- The Angular shield, from the wordmark on angular.dev. -->
<svg width="20" height="22" viewBox="0 0 223 236" fill="url(#ng-logo)" aria-hidden="true">
<defs>
<linearGradient
id="ng-logo"
x1="49"
x2="226"
y1="214"
y2="130"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#E40035" />
<stop offset=".24" stop-color="#F60A48" />
<stop offset=".352" stop-color="#F20755" />
<stop offset=".494" stop-color="#DC087D" />
<stop offset=".745" stop-color="#9717E7" />
<stop offset="1" stop-color="#6C00F5" />
</linearGradient>
</defs>
<path
d="m222.077 39.192-8.019 125.923L137.387 0l84.69 39.192Zm-53.105 162.825-57.933 33.056-57.934-33.056 11.783-28.556h92.301l11.783 28.556ZM111.039 62.675l30.357 73.803H80.681l30.358-73.803ZM7.937 165.115 0 39.192 84.69 0 7.937 165.115Z"
/>
</svg>
<span>Angular DevTools</span>
</div>
Expand Down Expand Up @@ -80,7 +91,11 @@ type Tab = 'dashboard' | 'components' | 'routes' | 'signals' | 'injectors' | 'st
align-items: center;
gap: 8px;
font-weight: 600;
color: #a78bfa;
color: var(--accent);
}
.brand span {
color: var(--accent);
white-space: nowrap;
}
nav {
display: flex;
Expand Down Expand Up @@ -166,10 +181,24 @@ export class App implements OnInit, OnDestroy {
}

// Chrome extension passes ?baseURL=...; embedded uses /__ng-devtools/; standalone uses default
function sameOrigin(value: string): boolean {
try {
return new URL(value, location.href).origin === location.origin;
} catch {
return false;
}
}

function detectBaseURL(): string | undefined {
const params = new URLSearchParams(location.search);
const fromQuery = params.get('baseURL');
if (fromQuery) return fromQuery;
// Same origin only: any page can open this URL, and this value decides where
// the panel opens its RPC channel.
// `new URL` throws on a malformed value, and this runs before the connection
// is made, so an unhandled throw would leave the panel blank.
if (fromQuery && sameOrigin(fromQuery)) {
return fromQuery;
}

if (location.pathname.includes('__ng-devtools')) return undefined;
return '/__ng-devtools/';
Expand Down
8 changes: 4 additions & 4 deletions app/src/pages/component-tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ interface ProviderEntry {
outline: none;
}
input:focus {
border-color: #a78bfa;
border-color: var(--accent);
}
button {
padding: 8px 16px;
Expand Down Expand Up @@ -148,12 +148,12 @@ interface ProviderEntry {
transition: border-color 0.15s;
}
.component-item:hover {
border-color: #a78bfa;
border-color: var(--accent);
}
.selector {
font-family: monospace;
font-size: 15px;
color: #a78bfa;
color: var(--accent);
font-weight: 600;
}
.file {
Expand All @@ -178,7 +178,7 @@ interface ProviderEntry {
}
.detail h3 {
font-family: monospace;
color: #a78bfa;
color: var(--accent);
margin-bottom: 12px;
}
dl {
Expand Down
4 changes: 2 additions & 2 deletions app/src/pages/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import type { DevframeRpcClient } from 'devframe/client';
transition: border-color 0.15s;
}
.card.clickable:hover {
border-color: #a78bfa;
border-color: var(--accent);
}
h3 {
font-size: 13px;
Expand All @@ -87,7 +87,7 @@ import type { DevframeRpcClient } from 'devframe/client';
.big {
font-size: 36px;
font-weight: 700;
color: #a78bfa;
color: var(--accent);
}
.sub {
font-size: 13px;
Expand Down
8 changes: 4 additions & 4 deletions app/src/pages/di-inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ const TYPE_COLORS: Record<string, string> = {
outline: none;
}
input[type='text']:focus {
border-color: #a78bfa;
border-color: var(--accent);
}
.checkbox {
display: flex;
Expand Down Expand Up @@ -209,8 +209,8 @@ const TYPE_COLORS: Record<string, string> = {
background: #18181b;
}
.injector-row.selected {
background: #1e1b4b;
border-color: #a78bfa;
background: color-mix(in srgb, var(--accent) 22%, transparent);
border-color: var(--accent);
}
.type-badge {
font-size: 10px;
Expand Down Expand Up @@ -270,7 +270,7 @@ const TYPE_COLORS: Record<string, string> = {
}
.token {
font-family: monospace;
color: #a78bfa;
color: var(--accent);
}
.source-label {
font-size: 13px;
Expand Down
4 changes: 2 additions & 2 deletions app/src/pages/route-inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ interface RouteInfo {
outline: none;
}
input:focus {
border-color: #a78bfa;
border-color: var(--accent);
}
button {
padding: 8px 16px;
Expand Down Expand Up @@ -111,7 +111,7 @@ interface RouteInfo {
}
.path {
font-family: monospace;
color: #a78bfa;
color: var(--accent);
font-weight: 500;
}
.file {
Expand Down
6 changes: 3 additions & 3 deletions app/src/pages/signal-inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ const KIND_COLORS: Record<string, string> = {
outline: none;
}
input:focus {
border-color: #a78bfa;
border-color: var(--accent);
}
.label {
font-size: 13px;
Expand Down Expand Up @@ -264,7 +264,7 @@ const KIND_COLORS: Record<string, string> = {
border-color: #3f3f46;
}
.node-card.selected {
border-color: #a78bfa;
border-color: var(--accent);
}
.node-header {
display: flex;
Expand Down Expand Up @@ -318,7 +318,7 @@ const KIND_COLORS: Record<string, string> = {
}
.detail-panel h3 {
font-family: monospace;
color: #a78bfa;
color: var(--accent);
margin-bottom: 12px;
}
.detail-panel h4 {
Expand Down
6 changes: 3 additions & 3 deletions app/src/pages/store-inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ const KIND_COLORS: Record<string, string> = {
outline: none;
}
input:focus {
border-color: #a78bfa;
border-color: var(--accent);
}
.toggle-group {
display: flex;
Expand Down Expand Up @@ -371,7 +371,7 @@ const KIND_COLORS: Record<string, string> = {
border-color: #3f3f46;
}
.action-card.selected {
border-color: #a78bfa;
border-color: var(--accent);
}
.action-type {
font-family: monospace;
Expand All @@ -385,7 +385,7 @@ const KIND_COLORS: Record<string, string> = {
.detail-panel {
margin-top: 16px;
background: #18181b;
border: 1px solid #a78bfa;
border: 1px solid var(--accent);
border-radius: 10px;
padding: 16px;
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading