From c940b08b7a3a1639d2ae237b8f261a096c401128 Mon Sep 17 00:00:00 2001 From: Kam Date: Sun, 20 Sep 2026 18:29:55 +0300 Subject: [PATCH 1/2] fix: repair devtools build, CLI entry, and test suite - use .ts import specifiers in devframe.ts; the package has no build step and Node's type stripping does not remap .js to .ts - enable allowImportingTsExtensions and rewriteRelativeImportExtensions in tsconfig.app.json so ng build still compiles src/server.ts - declare cac, an optional peer of devframe that nothing installs but both bin.mjs call through createCac - provide Router in app.spec.ts and drop the assertion on an h1 that app.html no longer renders --- packages/ng-devtools/package.json | 1 + packages/ng-devtools/src/devframe.ts | 12 ++++++------ pnpm-lock.yaml | 20 +++++++++++++++----- src/app/app.spec.ts | 7 +++++-- tsconfig.app.json | 4 +++- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/packages/ng-devtools/package.json b/packages/ng-devtools/package.json index a80394f..a851130 100644 --- a/packages/ng-devtools/package.json +++ b/packages/ng-devtools/package.json @@ -25,6 +25,7 @@ "mcp" ], "dependencies": { + "cac": "^7.0.0", "devframe": "^1.0.0", "valibot": "^1.5.0" }, diff --git a/packages/ng-devtools/src/devframe.ts b/packages/ng-devtools/src/devframe.ts index 412cf7f..0eaab82 100644 --- a/packages/ng-devtools/src/devframe.ts +++ b/packages/ng-devtools/src/devframe.ts @@ -1,11 +1,11 @@ import type { RemoteAssets } from 'devframe' import { defineDevframe } from 'devframe' -import { getRoutes } from './rpc/get-routes.js' -import { getComponents } from './rpc/get-components.js' -import { getBuildMeta } from './rpc/build-meta.js' -import { getSignals } from './rpc/get-signals.js' -import { getProviders } from './rpc/get-providers.js' -import type {} from './types.js' +import { getRoutes } from './rpc/get-routes.ts' +import { getComponents } from './rpc/get-components.ts' +import { getBuildMeta } from './rpc/build-meta.ts' +import { getSignals } from './rpc/get-signals.ts' +import { getProviders } from './rpc/get-providers.ts' +import type {} from './types.ts' import pkg from '../package.json' with { type: 'json' } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89fd42b..4f5bf58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: link:packages/ng-devtools devframe: specifier: ^1.0.0 - version: 1.0.0(@devframes/agentic@1.0.0)(srvx@1.0.5) + version: 1.0.0(@devframes/agentic@1.0.0)(cac@7.0.0)(srvx@1.0.5) express: specifier: ^5.1.0 version: 5.2.1 @@ -99,9 +99,12 @@ importers: '@devframes/agentic': specifier: ^1.0.0 version: 1.0.0(crossws@0.4.12(srvx@1.0.5))(devframe@1.0.0) + cac: + specifier: ^7.0.0 + version: 7.0.0 devframe: specifier: ^1.0.0 - version: 1.0.0(@devframes/agentic@1.0.0)(srvx@1.0.5) + version: 1.0.0(@devframes/agentic@1.0.0)(cac@7.0.0)(srvx@1.0.5) valibot: specifier: ^1.5.0 version: 1.5.0(typescript@6.0.3) @@ -1813,6 +1816,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -3376,7 +3383,7 @@ snapshots: dependencies: '@modelcontextprotocol/client': 2.0.0 '@modelcontextprotocol/server': 2.0.0 - devframe: 1.0.0(@devframes/agentic@1.0.0)(srvx@1.0.5) + devframe: 1.0.0(@devframes/agentic@1.0.0)(cac@7.0.0)(srvx@1.0.5) h3: 2.0.1-rc.32(crossws@0.4.12(srvx@1.0.5)) pathe: 2.0.3 transitivePeerDependencies: @@ -3385,7 +3392,7 @@ snapshots: '@devframes/vite@1.0.0(devframe@1.0.0)(vite@8.3.0(@types/node@20.19.43)(esbuild@0.28.2)(sass@1.101.0))': dependencies: - devframe: 1.0.0(@devframes/agentic@1.0.0)(srvx@1.0.5) + devframe: 1.0.0(@devframes/agentic@1.0.0)(cac@7.0.0)(srvx@1.0.5) pathe: 2.0.3 optionalDependencies: vite: 8.3.0(@types/node@20.19.43)(esbuild@0.28.2)(sass@1.101.0) @@ -4367,6 +4374,8 @@ snapshots: bytes@3.1.2: {} + cac@7.0.0: {} + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -4476,7 +4485,7 @@ snapshots: detect-libc@2.1.2: {} - devframe@1.0.0(@devframes/agentic@1.0.0)(srvx@1.0.5): + devframe@1.0.0(@devframes/agentic@1.0.0)(cac@7.0.0)(srvx@1.0.5): dependencies: crossws: 0.4.12(srvx@1.0.5) h3: 2.0.1-rc.32(crossws@0.4.12(srvx@1.0.5)) @@ -4484,6 +4493,7 @@ snapshots: pathe: 2.0.3 optionalDependencies: '@devframes/agentic': 1.0.0(crossws@0.4.12(srvx@1.0.5))(devframe@1.0.0) + cac: 7.0.0 transitivePeerDependencies: - ocache - srvx diff --git a/src/app/app.spec.ts b/src/app/app.spec.ts index bb1b59a..526f3bf 100644 --- a/src/app/app.spec.ts +++ b/src/app/app.spec.ts @@ -1,10 +1,12 @@ import { TestBed } from '@angular/core/testing'; +import { provideRouter } from '@angular/router'; import { App } from './app'; describe('App', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [App], + providers: [provideRouter([])], }) .compileComponents(); }); @@ -15,10 +17,11 @@ describe('App', () => { expect(app).toBeTruthy(); }); - it('should render title', async () => { + it('should render the nav links', async () => { const fixture = TestBed.createComponent(App); await fixture.whenStable(); const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Hello, angular-devtools'); + const hrefs = Array.from(compiled.querySelectorAll('nav a')).map((a) => a.getAttribute('href')); + expect(hrefs).toEqual(['/', '/about']); }); }); diff --git a/tsconfig.app.json b/tsconfig.app.json index 11c10da..e7e0a12 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -5,7 +5,9 @@ "compilerOptions": { "types": [ "node" - ] + ], + "allowImportingTsExtensions": true, + "rewriteRelativeImportExtensions": true }, "include": [ "src/**/*.ts" From 08477a4fb8796988042b2abbbb2465bc35a846c3 Mon Sep 17 00:00:00 2001 From: Kam Date: Sun, 20 Sep 2026 19:15:19 +0300 Subject: [PATCH 2/2] feat: declare input schemas for the selector-taking agent tools highlight, inspect-signals and inspect-providers each advertised `inputSchema: { type: 'object', properties: {} }` while their handlers read `args.selector`, so an MCP client had no way to discover the argument and a wrong guess failed silently. --- packages/ng-devtools/src/devframe.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/ng-devtools/src/devframe.ts b/packages/ng-devtools/src/devframe.ts index 0eaab82..4437a34 100644 --- a/packages/ng-devtools/src/devframe.ts +++ b/packages/ng-devtools/src/devframe.ts @@ -137,6 +137,13 @@ const ngDevtools = defineDevframe({ id: 'ng-devtools:highlight', description: 'Highlight a component in the running Angular app by its selector.', safety: 'action', + inputSchema: { + type: 'object', + properties: { + selector: { type: 'string', description: 'CSS selector of the component to highlight, e.g. app-root.' }, + }, + required: ['selector'], + }, handler: async (args: { selector: string }) => { await ctx.rpc.invokeLocal('ng-devtools:select-component' as any, args.selector) void my.rpc.broadcast({ method: 'highlight-in-page', args: [args.selector], optional: true }) @@ -148,6 +155,13 @@ const ngDevtools = defineDevframe({ id: 'ng-devtools:inspect-signals', description: 'Get the signal graph for a specific component by CSS selector. Returns signal nodes (signal, computed, linkedSignal, effect) and their dependency edges. Call this to understand reactive data flow before suggesting state changes.', safety: 'read', + inputSchema: { + type: 'object', + properties: { + selector: { type: 'string', description: 'CSS selector of the component to inspect, e.g. app-root.' }, + }, + required: ['selector'], + }, handler: async (args: { selector: string }) => { try { const result = await my.rpc.broadcast({ method: 'get-signal-graph-for', args: [args.selector] }) @@ -163,6 +177,13 @@ const ngDevtools = defineDevframe({ id: 'ng-devtools:inspect-providers', description: 'Get DI providers and the injector resolution path for a component by CSS selector. Call this to understand dependency injection before suggesting provider changes.', safety: 'read', + inputSchema: { + type: 'object', + properties: { + selector: { type: 'string', description: 'CSS selector of the component to inspect, e.g. app-root.' }, + }, + required: ['selector'], + }, handler: async (args: { selector: string }) => { try { const result = await my.rpc.broadcast({ method: 'get-providers-for', args: [args.selector] })