#
tokens: 49599/50000 30/473 files (page 4/7)
lines: off (toggle) GitHub
raw markdown copy
This is page 4 of 7. Use http://codebase.md/push-based/angular-toolkit-mcp?page={x} to view the full context.

# Directory Structure

```
├── .aiignore
├── .cursor
│   ├── flows
│   │   ├── component-refactoring
│   │   │   ├── 01-review-component.mdc
│   │   │   ├── 02-refactor-component.mdc
│   │   │   ├── 03-validate-component.mdc
│   │   │   └── angular-20.md
│   │   ├── ds-refactoring-flow
│   │   │   ├── 01-find-violations.mdc
│   │   │   ├── 01b-find-all-violations.mdc
│   │   │   ├── 02-plan-refactoring.mdc
│   │   │   ├── 02b-plan-refactoring-for-all-violations.mdc
│   │   │   ├── 03-fix-violations.mdc
│   │   │   ├── 03-non-viable-cases.mdc
│   │   │   ├── 04-validate-changes.mdc
│   │   │   ├── 05-prepare-report.mdc
│   │   │   └── clean-global-styles.mdc
│   │   └── README.md
│   └── mcp.json.example
├── .github
│   └── workflows
│       └── ci.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── assets
│   ├── entain-logo.png
│   └── entain.png
├── CONTRIBUTING.MD
├── docs
│   ├── architecture-internal-design.md
│   ├── component-refactoring-flow.md
│   ├── contracts.md
│   ├── ds-refactoring-flow.md
│   ├── getting-started.md
│   ├── README.md
│   ├── tools.md
│   └── writing-custom-tools.md
├── eslint.config.mjs
├── jest.config.ts
├── jest.preset.mjs
├── LICENSE
├── nx.json
├── package-lock.json
├── package.json
├── packages
│   ├── .gitkeep
│   ├── angular-mcp
│   │   ├── eslint.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── assets
│   │   │   │   └── .gitkeep
│   │   │   └── main.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   ├── vitest.config.mts
│   │   └── webpack.config.cjs
│   ├── angular-mcp-server
│   │   ├── eslint.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── lib
│   │   │       ├── angular-mcp-server.ts
│   │   │       ├── prompts
│   │   │       │   └── prompt-registry.ts
│   │   │       ├── tools
│   │   │       │   ├── ds
│   │   │       │   │   ├── component
│   │   │       │   │   │   ├── get-deprecated-css-classes.tool.ts
│   │   │       │   │   │   ├── get-ds-component-data.tool.ts
│   │   │       │   │   │   ├── list-ds-components.tool.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── deprecated-css-helpers.ts
│   │   │       │   │   │       ├── doc-helpers.ts
│   │   │       │   │   │       ├── metadata-helpers.ts
│   │   │       │   │   │       └── paths-helpers.ts
│   │   │       │   │   ├── component-contract
│   │   │       │   │   │   ├── builder
│   │   │       │   │   │   │   ├── build-component-contract.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   │   └── types.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   ├── css-match.spec.ts
│   │   │       │   │   │   │   │   ├── dom-slots.extractor.spec.ts
│   │   │       │   │   │   │   │   ├── element-helpers.spec.ts
│   │   │       │   │   │   │   │   ├── inline-styles.collector.spec.ts
│   │   │       │   │   │   │   │   ├── meta.generator.spec.ts
│   │   │       │   │   │   │   │   ├── public-api.extractor.spec.ts
│   │   │       │   │   │   │   │   ├── styles.collector.spec.ts
│   │   │       │   │   │   │   │   └── typescript-analyzer.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       ├── build-contract.ts
│   │   │       │   │   │   │       ├── css-match.ts
│   │   │       │   │   │   │       ├── dom-slots.extractor.ts
│   │   │       │   │   │   │       ├── element-helpers.ts
│   │   │       │   │   │   │       ├── inline-styles.collector.ts
│   │   │       │   │   │   │       ├── meta.generator.ts
│   │   │       │   │   │   │       ├── public-api.extractor.ts
│   │   │       │   │   │   │       ├── styles.collector.ts
│   │   │       │   │   │   │       └── typescript-analyzer.ts
│   │   │       │   │   │   ├── diff
│   │   │       │   │   │   │   ├── diff-component-contract.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   └── schema.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   ├── diff-utils.spec.ts
│   │   │       │   │   │   │   │   └── dom-path-utils.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       ├── diff-utils.ts
│   │   │       │   │   │   │       └── dom-path-utils.ts
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── list
│   │   │       │   │   │   │   ├── list-component-contracts.tool.ts
│   │   │       │   │   │   │   ├── models
│   │   │       │   │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   │   └── types.ts
│   │   │       │   │   │   │   ├── spec
│   │   │       │   │   │   │   │   └── contract-list-utils.spec.ts
│   │   │       │   │   │   │   └── utils
│   │   │       │   │   │   │       └── contract-list-utils.ts
│   │   │       │   │   │   └── shared
│   │   │       │   │   │       ├── models
│   │   │       │   │   │       │   └── types.ts
│   │   │       │   │   │       ├── spec
│   │   │       │   │   │       │   └── contract-file-ops.spec.ts
│   │   │       │   │   │       └── utils
│   │   │       │   │   │           └── contract-file-ops.ts
│   │   │       │   │   ├── component-usage-graph
│   │   │       │   │   │   ├── build-component-usage-graph.tool.ts
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── config.ts
│   │   │       │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   └── types.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── angular-parser.ts
│   │   │       │   │   │       ├── component-helpers.ts
│   │   │       │   │   │       ├── component-usage-graph-builder.ts
│   │   │       │   │   │       ├── path-resolver.ts
│   │   │       │   │   │       └── unified-ast-analyzer.ts
│   │   │       │   │   ├── ds.tools.ts
│   │   │       │   │   ├── project
│   │   │       │   │   │   ├── get-project-dependencies.tool.ts
│   │   │       │   │   │   ├── report-deprecated-css.tool.ts
│   │   │       │   │   │   └── utils
│   │   │       │   │   │       ├── dependencies-helpers.ts
│   │   │       │   │   │       └── styles-report-helpers.ts
│   │   │       │   │   ├── report-violations
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── schema.ts
│   │   │       │   │   │   │   └── types.ts
│   │   │       │   │   │   ├── report-all-violations.tool.ts
│   │   │       │   │   │   └── report-violations.tool.ts
│   │   │       │   │   ├── shared
│   │   │       │   │   │   ├── index.ts
│   │   │       │   │   │   ├── models
│   │   │       │   │   │   │   ├── input-schemas.model.ts
│   │   │       │   │   │   │   └── schema-helpers.ts
│   │   │       │   │   │   ├── utils
│   │   │       │   │   │   │   ├── component-validation.ts
│   │   │       │   │   │   │   ├── cross-platform-path.ts
│   │   │       │   │   │   │   ├── handler-helpers.ts
│   │   │       │   │   │   │   ├── output.utils.ts
│   │   │       │   │   │   │   └── regex-helpers.ts
│   │   │       │   │   │   └── violation-analysis
│   │   │       │   │   │       ├── base-analyzer.ts
│   │   │       │   │   │       ├── coverage-analyzer.ts
│   │   │       │   │   │       ├── formatters.ts
│   │   │       │   │   │       ├── index.ts
│   │   │       │   │   │       └── types.ts
│   │   │       │   │   └── tools.ts
│   │   │       │   ├── schema.ts
│   │   │       │   ├── tools.ts
│   │   │       │   ├── types.ts
│   │   │       │   └── utils.ts
│   │   │       └── validation
│   │   │           ├── angular-mcp-server-options.schema.ts
│   │   │           ├── ds-components-file-loader.validation.ts
│   │   │           ├── ds-components-file.validation.ts
│   │   │           ├── ds-components.schema.ts
│   │   │           └── file-existence.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.tsbuildinfo
│   │   └── vitest.config.mts
│   ├── minimal-repo
│   │   └── packages
│   │       ├── application
│   │       │   ├── angular.json
│   │       │   ├── code-pushup.config.ts
│   │       │   ├── src
│   │       │   │   ├── app
│   │       │   │   │   ├── app.component.ts
│   │       │   │   │   ├── app.config.ts
│   │       │   │   │   ├── app.routes.ts
│   │       │   │   │   ├── components
│   │       │   │   │   │   ├── refactoring-tests
│   │       │   │   │   │   │   ├── bad-alert-tooltip-input.component.ts
│   │       │   │   │   │   │   ├── bad-alert.component.ts
│   │       │   │   │   │   │   ├── bad-button-dropdown.component.ts
│   │       │   │   │   │   │   ├── bad-document.component.ts
│   │       │   │   │   │   │   ├── bad-global-this.component.ts
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.css
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.html
│   │       │   │   │   │   │   ├── bad-mixed-external-assets.component.ts
│   │       │   │   │   │   │   ├── bad-mixed-not-standalone.component.ts
│   │       │   │   │   │   │   ├── bad-mixed.component.ts
│   │       │   │   │   │   │   ├── bad-mixed.module.ts
│   │       │   │   │   │   │   ├── bad-modal-progress.component.ts
│   │       │   │   │   │   │   ├── bad-this-window-document.component.ts
│   │       │   │   │   │   │   ├── bad-window.component.ts
│   │       │   │   │   │   │   ├── complex-components
│   │       │   │   │   │   │   │   ├── first-case
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.html
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.scss
│   │       │   │   │   │   │   │   │   ├── dashboard-demo.component.ts
│   │       │   │   │   │   │   │   │   ├── dashboard-header.component.html
│   │       │   │   │   │   │   │   │   ├── dashboard-header.component.scss
│   │       │   │   │   │   │   │   │   └── dashboard-header.component.ts
│   │       │   │   │   │   │   │   ├── second-case
│   │       │   │   │   │   │   │   │   ├── complex-badge-widget.component.scss
│   │       │   │   │   │   │   │   │   ├── complex-badge-widget.component.ts
│   │       │   │   │   │   │   │   │   └── complex-widget-demo.component.ts
│   │       │   │   │   │   │   │   └── third-case
│   │       │   │   │   │   │   │       ├── product-card.component.scss
│   │       │   │   │   │   │   │       ├── product-card.component.ts
│   │       │   │   │   │   │   │       └── product-showcase.component.ts
│   │       │   │   │   │   │   ├── group-1
│   │       │   │   │   │   │   │   ├── bad-mixed-1.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-1.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-1.component.ts
│   │       │   │   │   │   │   │   └── bad-mixed-not-standalone-1.component.ts
│   │       │   │   │   │   │   ├── group-2
│   │       │   │   │   │   │   │   ├── bad-mixed-2.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-2.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-2.component.ts
│   │       │   │   │   │   │   │   └── bad-mixed-not-standalone-2.component.ts
│   │       │   │   │   │   │   ├── group-3
│   │       │   │   │   │   │   │   ├── bad-mixed-3.component.spec.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-3.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-3.module.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.css
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.html
│   │       │   │   │   │   │   │   ├── bad-mixed-external-assets-3.component.ts
│   │       │   │   │   │   │   │   ├── bad-mixed-not-standalone-3.component.ts
│   │       │   │   │   │   │   │   └── lazy-loader-3.component.ts
│   │       │   │   │   │   │   └── group-4
│   │       │   │   │   │   │       ├── multi-violation-test.component.html
│   │       │   │   │   │   │       ├── multi-violation-test.component.scss
│   │       │   │   │   │   │       └── multi-violation-test.component.ts
│   │       │   │   │   │   └── validation-tests
│   │       │   │   │   │       ├── circular-dependency.component.ts
│   │       │   │   │   │       ├── external-files-missing.component.ts
│   │       │   │   │   │       ├── invalid-lifecycle.component.ts
│   │       │   │   │   │       ├── invalid-pipe-usage.component.ts
│   │       │   │   │   │       ├── invalid-template-syntax.component.ts
│   │       │   │   │   │       ├── missing-imports.component.ts
│   │       │   │   │   │       ├── missing-method.component.ts
│   │       │   │   │   │       ├── README.md
│   │       │   │   │   │       ├── standalone-module-conflict.component.ts
│   │       │   │   │   │       ├── standalone-module-conflict.module.ts
│   │       │   │   │   │       ├── template-reference-error.component.ts
│   │       │   │   │   │       ├── type-mismatch.component.ts
│   │       │   │   │   │       ├── valid.component.ts
│   │       │   │   │   │       ├── wrong-decorator-usage.component.ts
│   │       │   │   │   │       └── wrong-property-binding.component.ts
│   │       │   │   │   └── styles
│   │       │   │   │       ├── bad-global-styles.scss
│   │       │   │   │       ├── base
│   │       │   │   │       │   ├── _reset.scss
│   │       │   │   │       │   └── base.scss
│   │       │   │   │       ├── components
│   │       │   │   │       │   └── components.scss
│   │       │   │   │       ├── extended-deprecated-styles.scss
│   │       │   │   │       ├── layout
│   │       │   │   │       │   └── layout.scss
│   │       │   │   │       ├── new-styles-1.scss
│   │       │   │   │       ├── new-styles-10.scss
│   │       │   │   │       ├── new-styles-2.scss
│   │       │   │   │       ├── new-styles-3.scss
│   │       │   │   │       ├── new-styles-4.scss
│   │       │   │   │       ├── new-styles-5.scss
│   │       │   │   │       ├── new-styles-6.scss
│   │       │   │   │       ├── new-styles-7.scss
│   │       │   │   │       ├── new-styles-8.scss
│   │       │   │   │       ├── new-styles-9.scss
│   │       │   │   │       ├── themes
│   │       │   │   │       │   └── themes.scss
│   │       │   │   │       └── utilities
│   │       │   │   │           └── utilities.scss
│   │       │   │   ├── index.html
│   │       │   │   ├── main.ts
│   │       │   │   └── styles.css
│   │       │   ├── tsconfig.app.json
│   │       │   ├── tsconfig.json
│   │       │   └── tsconfig.spec.json
│   │       └── design-system
│   │           ├── component-options.mjs
│   │           ├── storybook
│   │           │   └── card
│   │           │       └── card-tabs
│   │           │           └── overview.mdx
│   │           ├── storybook-host-app
│   │           │   └── src
│   │           │       └── components
│   │           │           ├── badge
│   │           │           │   ├── badge-tabs
│   │           │           │   │   ├── api.mdx
│   │           │           │   │   ├── examples.mdx
│   │           │           │   │   └── overview.mdx
│   │           │           │   ├── badge.component.mdx
│   │           │           │   └── badge.component.stories.ts
│   │           │           ├── modal
│   │           │           │   ├── demo-cdk-dialog-cmp.component.ts
│   │           │           │   ├── demo-modal-cmp.component.ts
│   │           │           │   ├── modal-tabs
│   │           │           │   │   ├── api.mdx
│   │           │           │   │   ├── examples.mdx
│   │           │           │   │   └── overview.mdx
│   │           │           │   ├── modal.component.mdx
│   │           │           │   └── modal.component.stories.ts
│   │           │           └── segmented-control
│   │           │               ├── segmented-control-tabs
│   │           │               │   ├── api.mdx
│   │           │               │   ├── examples.mdx
│   │           │               │   └── overview.mdx
│   │           │               ├── segmented-control.component.mdx
│   │           │               └── segmented-control.component.stories.ts
│   │           └── ui
│   │               ├── badge
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       └── badge.component.ts
│   │               ├── modal
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       ├── modal-content.component.ts
│   │               │       ├── modal-header
│   │               │       │   └── modal-header.component.ts
│   │               │       ├── modal-header-drag
│   │               │       │   └── modal-header-drag.component.ts
│   │               │       └── modal.component.ts
│   │               ├── rx-host-listener
│   │               │   ├── package.json
│   │               │   ├── project.json
│   │               │   └── src
│   │               │       └── rx-host-listener.ts
│   │               └── segmented-control
│   │                   ├── package.json
│   │                   ├── project.json
│   │                   └── src
│   │                       ├── segmented-control.component.html
│   │                       ├── segmented-control.component.ts
│   │                       ├── segmented-control.token.ts
│   │                       └── segmented-option.component.ts
│   └── shared
│       ├── angular-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── docs
│       │   │   └── angular-component-tree.md
│       │   ├── eslint.config.mjs
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       ├── decorator-config.visitor.inline-styles.spec.ts
│       │   │       ├── decorator-config.visitor.spec.ts
│       │   │       ├── decorator-config.visitor.ts
│       │   │       ├── parse-component.ts
│       │   │       ├── schema.ts
│       │   │       ├── styles
│       │   │       │   └── utils.ts
│       │   │       ├── template
│       │   │       │   ├── noop-tmpl-visitor.ts
│       │   │       │   ├── template.walk.ts
│       │   │       │   ├── utils.spec.ts
│       │   │       │   ├── utils.ts
│       │   │       │   └── utils.unit.test.ts
│       │   │       ├── ts.walk.ts
│       │   │       ├── types.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── DEPENDENCIES.md
│       ├── ds-component-coverage
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── docs
│       │   │   ├── examples
│       │   │   │   ├── report.json
│       │   │   │   └── report.md
│       │   │   ├── images
│       │   │   │   └── report-overview.png
│       │   │   └── README.md
│       │   ├── jest.config.ts
│       │   ├── mocks
│       │   │   └── fixtures
│       │   │       └── e2e
│       │   │           ├── asset-location
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-styl-inl-tmpl
│       │   │           │   │   └── inl-styl-inl-tmpl.component.ts
│       │   │           │   ├── inl-styl-url-tmpl
│       │   │           │   │   ├── inl-styl-url-tmpl.component.html
│       │   │           │   │   └── inl-styl-url-tmpl.component.ts
│       │   │           │   ├── multi-url-styl-inl-tmpl
│       │   │           │   │   ├── multi-url-styl-inl-tmpl-1.component.css
│       │   │           │   │   ├── multi-url-styl-inl-tmpl-2.component.css
│       │   │           │   │   └── multi-url-styl-inl-tmpl.component.ts
│       │   │           │   ├── url-styl-inl-tmpl
│       │   │           │   │   ├── url-styl-inl-tmpl.component.css
│       │   │           │   │   └── url-styl-inl-tmpl.component.ts
│       │   │           │   ├── url-styl-single-inl-tmpl
│       │   │           │   │   ├── url-styl-inl-tmpl.component.ts
│       │   │           │   │   └── url-styl-single-inl-tmpl.component.css
│       │   │           │   └── url-styl-url-tmpl
│       │   │           │       ├── inl-styl-url-tmpl.component.css
│       │   │           │       ├── inl-styl-url-tmpl.component.html
│       │   │           │       └── inl-styl-url-tmpl.component.ts
│       │   │           ├── demo
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── prompt.md
│       │   │           │   └── src
│       │   │           │       ├── bad-button-dropdown.component.ts
│       │   │           │       ├── bad-modal-progress.component.ts
│       │   │           │       ├── mixed-external-assets.component.css
│       │   │           │       ├── mixed-external-assets.component.html
│       │   │           │       ├── mixed-external-assets.component.ts
│       │   │           │       └── sub-folder-1
│       │   │           │           ├── bad-alert.component.ts
│       │   │           │           ├── button.component.ts
│       │   │           │           └── sub-folder-2
│       │   │           │               ├── bad-alert-tooltip-input.component.ts
│       │   │           │               └── bad-mixed.component.ts
│       │   │           ├── line-number
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-styl-single.component.ts
│       │   │           │   ├── inl-styl-span.component.ts
│       │   │           │   ├── inl-tmpl-single.component.ts
│       │   │           │   ├── inl-tmpl-span.component.ts
│       │   │           │   ├── url-style
│       │   │           │   │   ├── url-styl-single.component.css
│       │   │           │   │   ├── url-styl-single.component.ts
│       │   │           │   │   ├── url-styl-span.component.css
│       │   │           │   │   └── url-styl-span.component.ts
│       │   │           │   └── url-tmpl
│       │   │           │       ├── url-tmpl-single.component.html
│       │   │           │       ├── url-tmpl-single.component.ts
│       │   │           │       ├── url-tmpl-span.component.html
│       │   │           │       └── url-tmpl-span.component.ts
│       │   │           ├── style-format
│       │   │           │   ├── code-pushup.config.ts
│       │   │           │   ├── inl-css.component.ts
│       │   │           │   ├── inl-scss.component.ts
│       │   │           │   ├── styles.css
│       │   │           │   ├── styles.scss
│       │   │           │   ├── url-css.component.ts
│       │   │           │   └── url-scss.component.ts
│       │   │           └── template-syntax
│       │   │               ├── class-attribute.component.ts
│       │   │               ├── class-binding.component.ts
│       │   │               ├── code-pushup.config.ts
│       │   │               └── ng-class-binding.component.ts
│       │   ├── package.json
│       │   ├── src
│       │   │   ├── core.config.ts
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       ├── ds-component-coverage.plugin.ts
│       │   │       ├── runner
│       │   │       │   ├── audits
│       │   │       │   │   └── ds-coverage
│       │   │       │   │       ├── class-definition.utils.ts
│       │   │       │   │       ├── class-definition.visitor.ts
│       │   │       │   │       ├── class-definition.visitor.unit.test.ts
│       │   │       │   │       ├── class-usage.utils.ts
│       │   │       │   │       ├── class-usage.visitor.spec.ts
│       │   │       │   │       ├── class-usage.visitor.ts
│       │   │       │   │       ├── constants.ts
│       │   │       │   │       ├── ds-coverage.audit.ts
│       │   │       │   │       ├── schema.ts
│       │   │       │   │       └── utils.ts
│       │   │       │   ├── create-runner.ts
│       │   │       │   └── schema.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── LLMS.md
│       ├── models
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── cli.ts
│       │   │       ├── diagnostics.ts
│       │   │       └── mcp.ts
│       │   ├── tsconfig.json
│       │   └── tsconfig.lib.json
│       ├── styles-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── postcss-safe-parser.d.ts
│       │   │       ├── styles-ast-utils.spec.ts
│       │   │       ├── styles-ast-utils.ts
│       │   │       ├── stylesheet.parse.ts
│       │   │       ├── stylesheet.parse.unit.test.ts
│       │   │       ├── stylesheet.visitor.ts
│       │   │       ├── stylesheet.walk.ts
│       │   │       ├── types.ts
│       │   │       ├── utils.ts
│       │   │       └── utils.unit.test.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       ├── typescript-ast-utils
│       │   ├── .spec.swcrc
│       │   ├── ai
│       │   │   ├── API.md
│       │   │   ├── EXAMPLES.md
│       │   │   └── FUNCTIONS.md
│       │   ├── jest.config.ts
│       │   ├── package.json
│       │   ├── README.md
│       │   ├── src
│       │   │   ├── index.ts
│       │   │   └── lib
│       │   │       ├── constants.ts
│       │   │       └── utils.ts
│       │   ├── tsconfig.json
│       │   ├── tsconfig.lib.json
│       │   ├── tsconfig.spec.json
│       │   └── vitest.config.mts
│       └── utils
│           ├── .spec.swcrc
│           ├── ai
│           │   ├── API.md
│           │   ├── EXAMPLES.md
│           │   └── FUNCTIONS.md
│           ├── package.json
│           ├── README.md
│           ├── src
│           │   ├── index.ts
│           │   └── lib
│           │       ├── execute-process.ts
│           │       ├── execute-process.unit.test.ts
│           │       ├── file
│           │       │   ├── default-export-loader.spec.ts
│           │       │   ├── default-export-loader.ts
│           │       │   ├── file.resolver.ts
│           │       │   └── find-in-file.ts
│           │       ├── format-command-log.integration.test.ts
│           │       ├── format-command-log.ts
│           │       ├── logging.ts
│           │       └── utils.ts
│           ├── tsconfig.json
│           ├── tsconfig.lib.json
│           ├── tsconfig.spec.json
│           ├── vite.config.ts
│           └── vitest.config.mts
├── README.md
├── testing
│   ├── setup
│   │   ├── eslint.config.mjs
│   │   ├── eslint.next.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.d.ts
│   │   │   ├── index.mjs
│   │   │   └── memfs.constants.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.spec.json
│   │   ├── vitest.config.mts
│   │   └── vitest.integration.config.mts
│   ├── utils
│   │   ├── eslint.config.mjs
│   │   ├── eslint.next.config.mjs
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── lib
│   │   │       ├── constants.ts
│   │   │       ├── e2e-setup.ts
│   │   │       ├── execute-process-helper.mock.ts
│   │   │       ├── execute-process.mock.mjs
│   │   │       ├── os-agnostic-paths.ts
│   │   │       ├── os-agnostic-paths.unit.test.ts
│   │   │       ├── source-file-from.code.ts
│   │   │       └── string.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.lib.json
│   │   ├── tsconfig.spec.json
│   │   ├── vite.config.ts
│   │   ├── vitest.config.mts
│   │   └── vitest.integration.config.mts
│   └── vitest-setup
│       ├── eslint.config.mjs
│       ├── eslint.next.config.mjs
│       ├── package.json
│       ├── README.md
│       ├── src
│       │   ├── index.ts
│       │   └── lib
│       │       ├── configuration.ts
│       │       └── fs-memfs.setup-file.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       ├── tsconfig.spec.json
│       ├── vite.config.ts
│       ├── vitest.config.mts
│       └── vitest.integration.config.mts
├── tools
│   ├── nx-advanced-profile.bin.js
│   ├── nx-advanced-profile.js
│   ├── nx-advanced-profile.postinstall.js
│   └── perf_hooks.patch.js
├── tsconfig.base.json
├── tsconfig.json
└── vitest.workspace.ts
```

# Files

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/first-case/dashboard-demo.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component, signal } from '@angular/core';
import { DashboardHeaderComponent, UserProfile, NotificationItem } from '../dashboard-header.component';

@Component({
  selector: 'app-dashboard-demo',
  standalone: true,
  imports: [DashboardHeaderComponent],
  templateUrl: './dashboard-demo.component.html',
  styleUrls: ['./dashboard-demo.component.scss']
})
export class DashboardDemoComponent {
  darkMode = signal(false);
  eventLog = signal<string[]>([]);
  
  userProfile = signal<UserProfile>({
    id: '1',
    name: 'John Doe',
    email: '[email protected]',
    role: 'Administrator',
    lastLogin: new Date(),
    avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face'
  });

  private users: UserProfile[] = [
    {
      id: '1',
      name: 'John Doe',
      email: '[email protected]',
      role: 'Administrator',
      lastLogin: new Date(),
      avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face'
    },
    {
      id: '2',
      name: 'Jane Smith',
      email: '[email protected]',
      role: 'Manager',
      lastLogin: new Date(Date.now() - 1000 * 60 * 30), // 30 minutes ago
    },
    {
      id: '3',
      name: 'Mike Johnson',
      email: '[email protected]',
      role: 'Developer',
      lastLogin: new Date(Date.now() - 1000 * 60 * 60 * 2), // 2 hours ago
      avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face'
    }
  ];

  private currentUserIndex = 0;

  onSearchPerformed(query: string) {
    this.addLogEntry(`Search performed: "${query}"`);
  }

  onBadgeDismissed() {
    this.addLogEntry('Offer badge dismissed');
  }

  onNotificationClicked(notification: NotificationItem) {
    this.addLogEntry(`Notification clicked: ${notification.title}`);
  }

  onUserActionClicked(action: string) {
    this.addLogEntry(`User action: ${action}`);
    
    if (action === 'logout') {
      this.addLogEntry('User logged out');
      // In a real app, you would handle logout logic here
    }
  }

  onThemeToggled(isDark: boolean) {
    this.darkMode.set(isDark);
    this.addLogEntry(`Theme toggled to: ${isDark ? 'dark' : 'light'}`);
    
    // Apply theme to demo container
    const container = document.querySelector('.demo-container');
    if (container) {
      container.classList.toggle('dark', isDark);
    }
  }

  toggleTheme() {
    const newTheme = !this.darkMode();
    this.onThemeToggled(newTheme);
  }

  changeUser() {
    this.currentUserIndex = (this.currentUserIndex + 1) % this.users.length;
    const newUser = this.users[this.currentUserIndex];
    this.userProfile.set(newUser);
    this.addLogEntry(`User changed to: ${newUser.name}`);
  }

  addNotification() {
    const notifications = [
      {
        id: Date.now().toString(),
        title: 'New Message',
        message: 'You have received a new message from a colleague',
        timestamp: new Date(),
        read: false,
        type: 'info' as const
      },
      {
        id: Date.now().toString(),
        title: 'Task Completed',
        message: 'Your background task has finished successfully',
        timestamp: new Date(),
        read: false,
        type: 'success' as const
      },
      {
        id: Date.now().toString(),
        title: 'Warning',
        message: 'Your session will expire in 10 minutes',
        timestamp: new Date(),
        read: false,
        type: 'warning' as const
      }
    ];
    
    const randomNotification = notifications[Math.floor(Math.random() * notifications.length)];
    this.addLogEntry(`Added notification: ${randomNotification.title}`);
  }

  private addLogEntry(message: string) {
    const timestamp = new Date().toLocaleTimeString();
    const entry = `[${timestamp}] ${message}`;
    this.eventLog.update(log => [entry, ...log.slice(0, 49)]); // Keep last 50 entries
  }
} 
```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/spec/css-match.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi } from 'vitest';

vi.mock('@push-based/angular-ast-utils', () => {
  return {
    parseClassNames: (classStr: string) => classStr.trim().split(/\s+/),
    ngClassesIncludeClassName: (expr: string, className: string) =>
      expr.includes(className),
  };
});

import { selectorMatches } from '../utils/css-match.js';

import type {
  DomElement,
  Attribute,
  Binding,
} from '../../shared/models/types.js';

function createElement(overrides: Partial<DomElement> = {}): DomElement {
  return {
    tag: 'div',
    parent: null,
    children: [],
    attributes: [],
    bindings: [],
    events: [],
    ...overrides,
  } as DomElement;
}

function attr(name: string, source: string): Attribute {
  return { type: 'attribute', name, source };
}

function classBinding(name: string, source = ''): Binding {
  return { type: 'class', name, source } as Binding;
}

describe('selectorMatches', () => {
  const domKey = '';

  describe('class selectors', () => {
    it('matches static class attribute', () => {
      const el = createElement({
        attributes: [attr('class', 'foo bar')],
      });
      expect(selectorMatches('.foo', domKey, el)).toBe(true);
      expect(selectorMatches('.bar', domKey, el)).toBe(true);
      expect(selectorMatches('.baz', domKey, el)).toBe(false);
    });

    it('matches Angular [class.foo] binding', () => {
      const el = createElement({
        bindings: [classBinding('class.foo')],
      });
      expect(selectorMatches('.foo', domKey, el)).toBe(true);
    });

    it('matches ngClass expression', () => {
      const el = createElement({
        bindings: [classBinding('ngClass', "{ 'foo': cond }")],
      });
      expect(selectorMatches('.foo', domKey, el)).toBe(true);
    });
  });

  describe('id selectors', () => {
    it('matches id attribute', () => {
      const el = createElement({ attributes: [attr('id', 'my-id')] });
      expect(selectorMatches('#my-id', domKey, el)).toBe(true);
      expect(selectorMatches('#other', domKey, el)).toBe(false);
    });
  });

  describe('tag selectors', () => {
    it('matches element tag', () => {
      const spanEl = createElement({ tag: 'span' });
      expect(selectorMatches('span', domKey, spanEl)).toBe(true);
      expect(selectorMatches('div', domKey, spanEl)).toBe(false);
    });
  });

  describe('attribute selectors', () => {
    it('matches existence selector', () => {
      const el = createElement({ attributes: [attr('disabled', '')] });
      expect(selectorMatches('[disabled]', domKey, el)).toBe(true);
    });

    it('matches equality selector', () => {
      const el = createElement({ attributes: [attr('type', 'button')] });
      expect(selectorMatches('[type="button"]', domKey, el)).toBe(true);
      expect(selectorMatches('[type="text"]', domKey, el)).toBe(false);
    });

    it('matches *= selector', () => {
      const el = createElement({
        attributes: [attr('data-role', 'dialog-box')],
      });
      expect(selectorMatches('[data-role*="dialog"]', domKey, el)).toBe(true);
      expect(selectorMatches('[data-role*="modal"]', domKey, el)).toBe(false);
    });

    it('matches ^= and $= selectors', () => {
      const el = createElement({
        attributes: [attr('data-role', 'dialog-box')],
      });
      expect(selectorMatches('[data-role^="dialog"]', domKey, el)).toBe(true);
      expect(selectorMatches('[data-role$="box"]', domKey, el)).toBe(true);
    });
  });

  describe('composite selectors', () => {
    it('matches when any comma-separated selector matches', () => {
      const el = createElement({ attributes: [attr('class', 'foo')] });
      expect(selectorMatches('.foo, #bar', domKey, el)).toBe(true);
      expect(selectorMatches('.baz, #bar', domKey, el)).toBe(false);
    });

    it('matches last part of descendant selector', () => {
      const el = createElement({ attributes: [attr('class', 'foo')] });
      expect(selectorMatches('div .foo', domKey, el)).toBe(true);
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/file/default-export-loader.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, expect, it, beforeEach, afterEach } from 'vitest';
import { writeFileSync, rmSync, mkdirSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { loadDefaultExport } from './default-export-loader.js';

describe('loadDefaultExport', () => {
  let testDir: string;

  beforeEach(() => {
    testDir = join(
      tmpdir(),
      `test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
    );
    mkdirSync(testDir, { recursive: true });
  });

  afterEach(() => {
    rmSync(testDir, { recursive: true, force: true });
  });

  const createFile = (name: string, content: string) => {
    const path = join(testDir, name);
    writeFileSync(path, content, 'utf-8');
    return path;
  };

  describe('Success Cases', () => {
    it.each([
      {
        type: 'array',
        content: '[{name: "test"}]',
        expected: [{ name: 'test' }],
      },
      {
        type: 'object',
        content: '{version: "1.0"}',
        expected: { version: '1.0' },
      },
      { type: 'string', content: '"test"', expected: 'test' },
      { type: 'null', content: 'null', expected: null },
      { type: 'boolean', content: 'false', expected: false },
      { type: 'undefined', content: 'undefined', expected: undefined },
    ])('should load $type default export', async ({ content, expected }) => {
      const path = createFile('test.mjs', `export default ${content};`);
      expect(await loadDefaultExport(path)).toEqual(expected);
    });
  });

  describe('Error Cases - No Default Export', () => {
    it.each([
      {
        desc: 'named exports only',
        content: 'export const a = 1; export const b = 2;',
        exports: 'a, b',
      },
      { desc: 'empty module', content: '', exports: 'none' },
      { desc: 'comments only', content: '// comment', exports: 'none' },
      {
        desc: 'function exports',
        content: 'export function fn() {}',
        exports: 'fn',
      },
    ])('should throw error for $desc', async ({ content, exports }) => {
      const path = createFile('test.mjs', content);
      await expect(loadDefaultExport(path)).rejects.toThrow(
        `No default export found in module. Expected ES Module format:\nexport default [...]\n\nAvailable exports: ${exports}`,
      );
    });
  });

  describe('Error Cases - File System', () => {
    it('should throw error when file does not exist', async () => {
      const path = join(testDir, 'missing.mjs');
      await expect(loadDefaultExport(path)).rejects.toThrow(
        `Failed to load module from ${path}`,
      );
    });

    it('should throw error when file has syntax errors', async () => {
      const path = createFile(
        'syntax.mjs',
        'export default { invalid: syntax }',
      );
      await expect(loadDefaultExport(path)).rejects.toThrow(
        `Failed to load module from ${path}`,
      );
    });
  });

  describe('Edge Cases', () => {
    it('should work with TypeScript generics', async () => {
      interface Config {
        name: string;
      }
      const path = createFile('typed.mjs', 'export default [{name: "test"}];');
      const result = await loadDefaultExport<Config[]>(path);
      expect(result).toEqual([{ name: 'test' }]);
    });

    it('should handle mixed exports (prefers default)', async () => {
      const path = createFile(
        'mixed.mjs',
        'export const named = "n"; export default "d";',
      );
      expect(await loadDefaultExport<string>(path)).toBe('d');
    });

    it('should handle complex nested structures', async () => {
      const path = createFile(
        'complex.mjs',
        `
        export default {
          data: [{ name: 'test', meta: { date: new Date('2024-01-01') } }],
          version: '1.0'
        };
      `,
      );
      const result = await loadDefaultExport(path);
      expect(result).toMatchObject({
        data: [{ name: 'test', meta: { date: expect.any(Date) } }],
        version: '1.0',
      });
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/ds.tools.ts:
--------------------------------------------------------------------------------

```typescript
import {
  createHandler,
  BaseHandlerOptions,
} from './shared/utils/handler-helpers.js';
import { ToolSchemaOptions } from '@push-based/models';
import { dsComponentCoveragePlugin } from '@push-based/ds-component-coverage';
import { baseToolsSchema } from '../schema.js';
import { join } from 'node:path';
import {
  reportViolationsTools,
  reportAllViolationsTools,
} from './report-violations/index.js';

export const componentCoverageToolsSchema: ToolSchemaOptions = {
  name: 'ds_component-coverage',
  description:
    'Migration report. Search for deprecated CSS classes in a component. List available options with the tool `ds_list-options',
  inputSchema: {
    type: 'object',
    properties: {
      ...baseToolsSchema.inputSchema.properties,
      directory: {
        type: 'string',
        description:
          'The relative path the directory (starting with "./path/to/dir" avoid big folders.)  to run the task in starting from CWD. Respect the OS specifics.',
      },
      dsComponents: {
        type: 'array',
        items: {
          type: 'object',
          required: ['componentName', 'deprecatedCssClasses'],
          properties: {
            componentName: {
              type: 'string',
              description: 'The class name of the component to search for',
            },
            deprecatedCssClasses: {
              type: 'array',
              items: {
                type: 'string',
              },
              description: 'List of deprecated CSS classes for this component',
            },
            docsUrl: {
              type: 'string',
              description: 'URL to the component documentation',
            },
          },
        },
        description: 'Array of components and their deprecated CSS classes',
      },
    },
    required: [
      ...(baseToolsSchema.inputSchema.required as string[]),
      'directory',
      'dsComponents',
    ],
  },
  annotations: {
    title: 'Design System Component Coverage',
    readOnlyHint: true,
    openWorldHint: true,
    idempotentHint: false,
  },
};

interface ComponentCoverageOptions extends BaseHandlerOptions {
  directory: string;
  dsComponents: Array<{
    componentName: string;
    deprecatedCssClasses: string[];
    docsUrl?: string;
  }>;
}

export const componentCoverageHandler = createHandler<
  ComponentCoverageOptions,
  any
>(
  componentCoverageToolsSchema.name,
  async (params, { cwd }) => {
    const { directory, dsComponents, ...pluginOptions } = params;

    const pluginConfig = await dsComponentCoveragePlugin({
      ...pluginOptions,
      directory: join(cwd, directory),
      dsComponents,
    });

    const { executePlugin } = await import('@code-pushup/core');
    const result = await executePlugin(pluginConfig as any, {
      cache: { read: false, write: false },
      persist: { outputDir: '' },
    });
    const reducedResult = {
      ...result,
      audits: result.audits.filter(({ score }) => score < 1),
    };

    return {
      directory,
      reducedResult,
    };
  },
  (result) => {
    const output = [`List of missing DS components:`];

    output.push(`Result:\n\nBase directory: ${result.directory}`);

    result.reducedResult.audits.forEach(({ details, title }: any) => {
      const auditOutput = [`\n${title}`];
      (details?.issues ?? []).forEach(
        ({ message, source }: any, index: number) => {
          if (index === 0) {
            auditOutput.push(message.replace(result.directory + '/', ''));
          }
          auditOutput.push(
            `  - ${source?.file.replace(result.directory + '/', '')}#L${source?.position?.startLine}`,
          );
        },
      );
      output.push(auditOutput.join('\n'));
    });

    return [output.join('\n')];
  },
);

export const componentCoverageTools = [
  {
    schema: componentCoverageToolsSchema,
    handler: componentCoverageHandler,
  },
];

export const dsTools = [
  ...componentCoverageTools,
  ...reportViolationsTools,
  ...reportAllViolationsTools,
];

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/third-case/product-card.component.scss:
--------------------------------------------------------------------------------

```scss
// Product Card Component Styles
.product-card {
  background: white;
  border-radius: 0.75rem;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  transition: all 0.3s ease;
  position: relative;
  
  &:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  }
  
  &.product-card-selected {
    border: 2px solid #3b82f6;
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
  }
}

// Product Image Section
.product-image-container {
  position: relative;
  width: 100%;
  height: 200px;
  overflow: hidden;
}

.product-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
  
  .product-card:hover & {
    transform: scale(1.05);
  }
}

// Badge Overlay - Moderate complexity offer-badge
.badge-overlay {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 2;
}

// DsBadge replaces the custom offer-badge implementation
// The badge styling is now handled by the design system component

// Stock Overlay
.stock-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3;
}

.stock-badge {
  background: #ef4444;
  color: white;
  padding: 0.5rem 1rem;
  border-radius: 0.375rem;
  font-weight: 600;
  text-transform: uppercase;
  font-size: 0.875rem;
}

// Product Content
.product-content {
  padding: 1rem;
}

.product-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 0.5rem;
}

.product-name {
  margin: 0;
  font-size: 1.125rem;
  font-weight: 600;
  color: #1f2937;
  line-height: 1.4;
  flex: 1;
  margin-right: 0.5rem;
}

.favorite-button {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0.25rem;
  border-radius: 0.25rem;
  transition: all 0.2s ease;
  color: #6b7280;
  
  &:hover {
    background: #f3f4f6;
    color: #ef4444;
  }
  
  &.favorite-active {
    color: #ef4444;
  }
}

.product-category {
  font-size: 0.875rem;
  color: #6b7280;
  margin-bottom: 0.75rem;
  text-transform: capitalize;
}

.product-pricing {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.original-price {
  font-size: 0.875rem;
  color: #6b7280;
  text-decoration: line-through;
}

.current-price {
  font-size: 1.125rem;
  font-weight: 700;
  color: #ef4444;
}

.product-rating {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.rating-stars {
  display: flex;
  gap: 0.125rem;
}

.star {
  color: #d1d5db;
  font-size: 1rem;
  
  &.star-filled {
    color: #f59e0b;
  }
}

.rating-text {
  font-size: 0.875rem;
  color: #6b7280;
}

.product-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin-bottom: 1rem;
}

.product-tag {
  background: #f3f4f6;
  color: #374151;
  padding: 0.25rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.75rem;
  font-weight: 500;
}

.tag-more {
  color: #6b7280;
  font-size: 0.75rem;
  font-style: italic;
}

// Product Actions
.product-actions {
  padding: 0 1rem 1rem;
  display: flex;
  gap: 0.5rem;
}

.action-button {
  flex: 1;
  padding: 0.75rem;
  border: none;
  border-radius: 0.375rem;
  font-weight: 600;
  font-size: 0.875rem;
  cursor: pointer;
  transition: all 0.2s ease;
  
  &.add-to-cart {
    background: #3b82f6;
    color: white;
    
    &:hover:not(:disabled) {
      background: #2563eb;
    }
    
    &:disabled {
      background: #9ca3af;
      cursor: not-allowed;
    }
  }
  
  &.quick-view {
    background: #f3f4f6;
    color: #374151;
    border: 1px solid #d1d5db;
    
    &:hover {
      background: #e5e7eb;
      border-color: #9ca3af;
    }
  }
}

// Custom badge animations removed - DsBadge handles its own styling

// Responsive design
@media (max-width: 768px) {
  .product-card {
    margin: 0.5rem;
  }
  
  // DsBadge responsive styles are handled by the design system
  
  .product-name {
    font-size: 1rem;
  }
  
  .product-actions {
    flex-direction: column;
    
    .action-button {
      flex: none;
    }
  }
} 
```

--------------------------------------------------------------------------------
/packages/shared/angular-ast-utils/ai/FUNCTIONS.md:
--------------------------------------------------------------------------------

```markdown
# Public API — Quick Reference

| Symbol                              | Kind     | Signature                                                                     | Summary                                                |
| ----------------------------------- | -------- | ----------------------------------------------------------------------------- | ------------------------------------------------------ |
| `ANGULAR_COMPONENT_DECORATOR`       | function | `const ANGULAR_COMP...`                                                       | Constant for Angular component decorator string        |
| `AngularUnit`                       | function | `type AngularUnit = z.infer<…>`                                               | Union type for Angular unit types                      |
| `AngularUnitSchema`                 | function | `const AngularUnitSchema = z.enum…`                                           | Zod schema for Angular unit types                      |
| `Asset<T>`                          | function | `interface Asset<T>`                                                          | Typed asset wrapper                                    |
| `assetFromPropertyArrayInitializer` | function | `assetFromPropertyArrayInitializer(prop, sourceFile, textParser): Asset<T>[]` | Create assets from array property initializers         |
| `assetFromPropertyValueInitializer` | function | `assetFromPropertyValueInitializer(opts): Asset<T>`                           | Create asset from property value initializer           |
| `classDecoratorVisitor`             | function | `classDecoratorVisitor(opts): Visitor`                                        | Iterate class decorators in a SourceFile               |
| `findAngularUnits`                  | function | `findAngularUnits(directory, unit): Promise<string[]>`                        | Find Angular unit files by type in directory           |
| `ngClassesIncludeClassName`         | function | `ngClassesIncludeClassName(src, name): boolean`                               | Check if class name exists inside `[ngClass]` bindings |
| `parseAngularUnit`                  | function | `parseAngularUnit(directory, unit): Promise<ParsedComponent[]>`               | Parse Angular units in a directory                     |
| `parseClassNames`                   | function | `parseClassNames(str): string[]`                                              | Split string into individual CSS class names           |
| `parseComponents`                   | function | `parseComponents(files): Promise<ParsedComponent[]>`                          | Parse TS/TSX components into AST descriptors           |
| `ParsedComponent`                   | function | `type ParsedComponent`                                                        | Type for parsed Angular component data                 |
| `SourceLink`                        | function | `type SourceLink`                                                             | Type for source file location reference                |
| `tmplAstElementToSource`            | function | `tmplAstElementToSource(el): Source`                                          | Convert template AST elements to source map location   |
| `visitAngularDecoratorProperties`   | function | `visitAngularDecoratorProperties(opts)`                                       | Visit properties of Angular decorators                 |
| `visitAngularDecorators`            | function | `visitAngularDecorators(opts)`                                                | Traverse decorators & return matches                   |
| `visitComponentStyles`              | function | `visitComponentStyles(comp, arg, cb): Promise<Issue[]>`                       | Visit component styles with callback                   |
| `visitComponentTemplate`            | function | `visitComponentTemplate(comp, arg, cb)`                                       | Run visitor against a component's template             |
| `visitEachTmplChild`                | function | `visitEachTmplChild(nodes, visitor)`                                          | Visit each template AST child node                     |

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-usage-graph/utils/component-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import * as path from 'path';
import { toUnixPath } from '@code-pushup/utils';
import { buildText } from '../../shared/utils/output.utils.js';
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
import {
  DependencyGraphResult,
  DependencyInfo,
  ComponentGroup,
  FileExtension,
} from '../models/types.js';
import { DEPENDENCY_ANALYSIS_CONFIG } from '../models/config.js';

// Consolidated utilities
const NAME_RE =
  /^(.*?)(?:\.(?:component|directive|pipe|service|module|spec))?\.(?:ts|js|html?|s?css|less)$/i;

const baseName = (filePath: string): string => {
  const fileName = path.basename(filePath);
  const match = fileName.match(NAME_RE);
  return match ? match[1] : fileName;
};

const rel = (root: string, p: string) =>
  toUnixPath(path.isAbsolute(p) ? path.relative(root, p) : p);

type Index = Map<string, string[]>; // baseName → related files

const buildIndex = (graph: DependencyGraphResult): Index => {
  const index: Index = new Map();
  for (const fp of Object.keys(graph)) {
    const bn = baseName(fp);
    (index.get(bn) ?? index.set(bn, []).get(bn)!).push(fp);
  }
  return index;
};

const expandViolations = (seeds: string[], index: Index): string[] => [
  ...new Set(seeds.flatMap((s) => index.get(baseName(s)) ?? [])),
];

export const assetToComponentTs = (p: string): string =>
  path.join(path.dirname(p), baseName(p) + '.component.ts');

export const filterGraph = (
  graph: DependencyGraphResult,
  violationFiles: string[],
  root: string,
  index: Index = buildIndex(graph),
): DependencyGraphResult => {
  const seeds = violationFiles.flatMap((f) =>
    /\.(html?|s?css|sass|less)$/i.test(f) ? [f, assetToComponentTs(f)] : [f],
  );

  const bad = new Set(expandViolations(seeds, index).map((f) => rel(root, f)));
  const badNames = new Set([...bad].map(baseName));

  return Object.fromEntries(
    Object.entries(graph).filter(
      ([fp, info]) =>
        bad.has(fp) ||
        badNames.has(baseName(fp)) ||
        info.dependencies.some(
          (d) => d.type === 'reverse-dependency' && bad.has(d.path),
        ),
    ),
  );
};

const buildGroups = (
  result: DependencyGraphResult,
): Map<string, ComponentGroup> => {
  const componentGroups = new Map<string, ComponentGroup>();

  for (const [filePath, fileInfo] of Object.entries(result)) {
    const bn = baseName(filePath);

    if (!componentGroups.has(bn)) {
      componentGroups.set(bn, {
        relatedFiles: [],
        hasReverseDeps: false,
      });
    }

    const group = componentGroups.get(bn);
    if (group) {
      if (fileInfo.isAngularComponent) {
        group.componentFile = [filePath, fileInfo];
        group.hasReverseDeps = fileInfo.dependencies.some(
          (dep: DependencyInfo) => dep.type === 'reverse-dependency',
        );
      } else {
        group.relatedFiles.push([filePath, fileInfo]);
      }
    }
  }

  return componentGroups;
};

const getFileType = (filePath: string): string => {
  const extension = path.extname(filePath).toLowerCase() as FileExtension;
  return DEPENDENCY_ANALYSIS_CONFIG.fileTypeMap[extension] || 'file';
};

type Mode = 'inline' | 'entity';

export const printComponents = (
  graph: DependencyGraphResult,
  mode: Mode = 'inline',
): string | CallToolResult['content'] => {
  const groups = buildGroups(graph);
  const comps = [...groups.values()].filter((g) => g.componentFile);

  if (!comps.length)
    return mode === 'inline'
      ? 'No Angular components found with violations.'
      : [buildText('No Angular components found with violations.')];

  const toLines = (g: ComponentGroup) => {
    if (!g.componentFile) return '';
    const [cp, ci] = g.componentFile;
    return [
      `Component: ${ci.componentName ?? 'Unknown'}`,
      '',
      `- ${ci.type}: ${cp}`,
      ...g.relatedFiles.map(([p, i]) => `- ${i.type}: ${p}`),
      ...ci.dependencies
        .filter((d) => d.type === 'reverse-dependency')
        .map(
          (d) =>
            `- ${getFileType(d.resolvedPath ?? d.path)}: ${d.resolvedPath ?? d.path}`,
        ),
    ].join('\n');
  };

  if (mode === 'inline') {
    return comps.map(toLines).join('\n\n');
  }
  return comps.map((g) => buildText(toLines(g)));
};

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/design-system/storybook-host-app/src/components/modal/demo-modal-cmp.component.ts:
--------------------------------------------------------------------------------

```typescript
import {
  ChangeDetectionStrategy,
  Component,
  booleanAttribute,
  inject,
  input,
} from '@angular/core';
import {
  MAT_BOTTOM_SHEET_DATA,
  MatBottomSheet,
  MatBottomSheetModule,
  MatBottomSheetRef,
} from '@angular/material/bottom-sheet';
import {
  MAT_DIALOG_DATA,
  MatDialog,
  MatDialogModule,
  MatDialogRef,
} from '@angular/material/dialog';

import { DemoCloseIconComponent } from '@design-system/storybook-demo-cmp-lib';
import { DsButton } from '@frontend/ui/button';
import { DsButtonIcon } from '@frontend/ui/button-icon';
import {
  DsModal,
  DsModalContent,
  DsModalHeader,
  DsModalHeaderVariant,
  DsModalVariant,
} from '@frontend/ui/modal';

@Component({
  selector: 'ds-demo-dialog-cmp',
  imports: [
    MatDialogModule,
    DsButton,
    DsModalHeader,
    DsButtonIcon,
    DemoCloseIconComponent,
    DsModal,
    DsModalContent,
  ],
  standalone: true,
  template: `
    <ds-modal
      [inverse]="data.inverse"
      [bottomSheet]="data.bottomSheet"
      [variant]="data.variant"
    >
      <ds-modal-header [variant]="data.headerVariant">
        <div slot="start">
          <div slot="title">Hello start</div>
          <div slot="subtitle">Header subtitle</div>
        </div>

        <button slot="end" ds-button-icon size="small" (click)="close()">
          Close
        </button>
      </ds-modal-header>
      <ds-modal-content>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam,
        ducimus, sequi! Ab consequatur earum expedita fugit illo illum in
        maiores nihil nostrum officiis ratione repellendus temporibus, vel!
        <br />
        <br />
        <b>Lorem ipsum dolor sit amet</b>, consectetur adipisicing elit.
        Aliquam, ducimus, sequi! Ab consequatur earum expedita fugit illo illum
        in maiores nihil nostrum officiis ratione repellendus temporibus, vel!
        <br />
        <br />
        <div class="footer-buttons">
          <button
            ds-button
            [inverse]="data.inverse"
            kind="secondary"
            variant="outline"
            mat-dialog-close
          >
            Outline Button
          </button>
          <button
            ds-button
            [inverse]="data.inverse"
            kind="primary"
            variant="filled"
            mat-dialog-close
          >
            Filled Button
          </button>
        </div>
      </ds-modal-content>
    </ds-modal>
  `,
  styles: `
    ds-modal {
      width: 400px;
      min-height: 300px;
      margin-left: auto;
      margin-right: auto;
    }

    .footer-buttons {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 10px;
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DemoModalCmp {
  dialogRef = inject(MatDialogRef<DemoModalCmp>, { optional: true });
  bottomSheetRef = inject(MatBottomSheetRef<DemoModalCmp>, { optional: true });
  dialogData = inject(MAT_DIALOG_DATA, { optional: true });
  bottomSheetData = inject(MAT_BOTTOM_SHEET_DATA, { optional: true });

  data = this.dialogData ?? this.bottomSheetData ?? {}; // fallback to empty {}

  close() {
    this.dialogRef?.close();
    this.bottomSheetRef?.dismiss();
  }
}

@Component({
  selector: 'ds-demo-dialog-container',
  standalone: true,
  imports: [MatDialogModule, MatBottomSheetModule, DsButton],
  template: `
    <button ds-button (click)="openDialog()">Open with Material Dialog</button>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DemoModalContainer {
  dialog = inject(MatDialog);
  bottomSheet = inject(MatBottomSheet);

  headerVariant = input<DsModalHeaderVariant>();
  variant = input<DsModalVariant>();
  inverse = input(false, { transform: booleanAttribute });
  bottomSheetInput = input(false, { transform: booleanAttribute });

  openDialog() {
    const data = {
      headerVariant: this.headerVariant(),
      inverse: this.inverse(),
      variant: this.variant(),
      bottomSheet: this.bottomSheetInput(),
    };

    if (data.bottomSheet) {
      this.bottomSheet.open(DemoModalCmp, {
        data,
        panelClass: 'ds-bottom-sheet-panel',
      });
    } else {
      this.dialog.open(DemoModalCmp, {
        data,
        panelClass: 'ds-dialog-panel',
      });
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/shared/violation-analysis/coverage-analyzer.ts:
--------------------------------------------------------------------------------

```typescript
import { dsComponentCoveragePlugin } from '@push-based/ds-component-coverage';
import * as process from 'node:process';
import { validateDsComponentsArray } from '../../../../validation/ds-components-file-loader.validation.js';
import {
  ReportCoverageParams,
  BaseViolationResult,
  FormattedCoverageResult,
  BaseViolationAudit,
} from './types.js';
import { groupIssuesByFile } from './formatters.js';
import { resolveCrossPlatformPath } from '../utils/cross-platform-path.js';

/**
 * Validates the input parameters for the report coverage tool
 */
export function validateReportInput(params: ReportCoverageParams): void {
  if (!params.directory || typeof params.directory !== 'string') {
    throw new Error('Directory parameter is required and must be a string');
  }

  try {
    validateDsComponentsArray(params.dsComponents);
  } catch (ctx) {
    throw new Error(
      `Invalid dsComponents parameter: ${(ctx as Error).message}`,
    );
  }
}

/**
 * Executes the coverage plugin and returns the result
 */
export async function executeCoveragePlugin(
  params: ReportCoverageParams,
): Promise<BaseViolationResult> {
  const pluginConfig = await dsComponentCoveragePlugin({
    dsComponents: params.dsComponents,
    directory: resolveCrossPlatformPath(
      params.cwd || process.cwd(),
      params.directory,
    ),
  });

  const { executePlugin } = await import('@code-pushup/core');
  return (await executePlugin(pluginConfig as any, {
    cache: { read: false, write: false },
    persist: { outputDir: '' },
  })) as BaseViolationResult;
}

/**
 * Extracts component name from audit title - performance optimized with caching
 */
const componentNameCache = new Map<string, string>();

export function extractComponentName(title: string): string {
  if (componentNameCache.has(title)) {
    return componentNameCache.get(title)!;
  }

  const componentMatch = title.match(/Usage coverage for (\w+) component/);
  const componentName = componentMatch ? componentMatch[1] : 'Unknown';

  componentNameCache.set(title, componentName);
  return componentName;
}

/**
 * Formats the coverage result as text output - performance optimized
 */
export function formatCoverageResult(
  result: BaseViolationResult,
  params: ReportCoverageParams,
): string {
  // Pre-filter failed audits to avoid repeated filtering
  const failedAudits = result.audits.filter(
    ({ score }: BaseViolationAudit) => score < 1,
  );

  if (failedAudits.length === 0) {
    return '';
  }

  const output: string[] = [];
  output.push(''); // Pre-allocate with expected size for better performance

  for (const { details, title } of failedAudits) {
    const componentName = extractComponentName(title);

    output.push(`- design system component: ${componentName}`);
    output.push(`- base directory: ${params.directory}`);
    output.push('');

    // Use shared, optimized groupIssuesByFile function
    const fileGroups = groupIssuesByFile(
      details?.issues ?? [],
      params.directory,
    );

    // Add first message
    const firstFile = Object.keys(fileGroups)[0];
    if (firstFile && fileGroups[firstFile]) {
      output.push(fileGroups[firstFile].message);
      output.push('');
    }

    // Add files and lines - optimize sorting
    for (const [fileName, { lines }] of Object.entries(fileGroups)) {
      output.push(`- ${fileName}`);
      // Sort once and cache the result
      const sortedLines =
        lines.length > 1 ? lines.sort((a, b) => a - b) : lines;
      output.push(` - lines: ${sortedLines.join(',')}`);
    }

    output.push('');
  }

  return output.join('\n');
}

/**
 * Main implementation function for reporting project coverage
 */
export async function analyzeProjectCoverage(
  params: ReportCoverageParams,
): Promise<FormattedCoverageResult> {
  validateReportInput(params);

  if (params.cwd) {
    process.chdir(params.cwd);
  }

  const result = await executeCoveragePlugin(params);

  const textOutput = formatCoverageResult(result, params);

  const formattedResult: FormattedCoverageResult = {
    textOutput,
  };

  if (params.returnRawData) {
    formattedResult.rawData = {
      rawPluginResult: result,
      pluginOptions: {
        directory: params.directory,
        dsComponents: params.dsComponents,
      },
    };
  }

  return formattedResult;
}

```

--------------------------------------------------------------------------------
/tools/perf_hooks.patch.js:
--------------------------------------------------------------------------------

```javascript
import { Performance, performance } from 'node:perf_hooks';
import { basename } from 'node:path';

// Global array to store complete events.
const trace = [];

// Metadata events.

const processMetadata = {
  name: 'process_name', // Used to label the main process
  ph: 'M',
  pid: 0,
  tid: process.pid,
  ts: 0,
  args: { name: 'Measure Process' },
};

const threadMetadata = {
  name: 'thread_name', // Used to label the child processes
  ph: 'M',
  pid: 0,
  tid: process.pid,
  ts: 0,
  args: {
    name: `Child Process: ${basename(process.argv.at(0))} ${basename(
      process.argv.at(1),
    )} ${process.argv.slice(2).join(' ')}`,
  },
};

const originalMark = Performance.prototype.mark;
const originalMeasure = Performance.prototype.measure;

let correlationIdCounter = 0;
function generateCorrelationId() {
  return ++correlationIdCounter;
}

/**
 * Parse an error stack into an array of frames.
 */
function parseStack(stack) {
  const frames = [];
  const lines = stack.split('\n').slice(2); // Skip error message & current function.
  for (const line of lines) {
    const trimmed = line.trim();
    const regex1 = /^at\s+(.*?)\s+\((.*):(\d+):(\d+)\)$/;
    const regex2 = /^at\s+(.*):(\d+):(\d+)$/;
    let match = trimmed.match(regex1);
    if (match) {
      frames.push({
        functionName: match[1],
        file: match[2].replace(process.cwd(), ''),
        line: Number(match[3]),
        column: Number(match[4]),
      });
    } else {
      match = trimmed.match(regex2);
      if (match) {
        frames.push({
          functionName: null,
          file: match[1],
          line: Number(match[2]),
          column: Number(match[3]),
        });
      } else {
        frames.push({ raw: trimmed });
      }
    }
  }
  return frames;
}

Performance.prototype.mark = function (name, options) {
  const err = new Error();
  const callStack = parseStack(err.stack);
  const opt = Object.assign({}, options, {
    detail: Object.assign({}, (options && options.detail) || {}, { callStack }),
  });
  return originalMark.call(this, name, opt);
};

// Override measure to create complete events.
Performance.prototype.measure = function (name, start, end, options) {
  const startEntry = performance.getEntriesByName(start, 'mark')[0];
  const endEntry = performance.getEntriesByName(end, 'mark')[0];
  let event = null;
  if (startEntry && endEntry) {
    const ts = startEntry.startTime * 1000; // Convert ms to microseconds.
    const dur = (endEntry.startTime - startEntry.startTime) * 1000;

    // Enrich event further if needed (here keeping it minimal to match your profile).
    event = {
      name,
      cat: 'measure', // Keeping the same category as in your uploaded trace.
      ph: 'X',
      ts,
      dur,
      pid: 0,
      tid: process.pid,
      args: {
        startDetail: startEntry.detail || {},
        endDetail: endEntry.detail || {},
        // Optionally: add correlation and extra labels.
        uiLabel: name,
      },
    };

    // Push metadata events once.
    if (trace.length < 1) {
      trace.push(threadMetadata);
      console.log(`traceEvent:JSON:${JSON.stringify(threadMetadata)}`);
      trace.push(processMetadata);
      console.log(`traceEvent:JSON:${JSON.stringify(processMetadata)}`);
    }
    trace.push(event);
    console.log(`traceEvent:JSON:${JSON.stringify(event)}`);

    // console.log('Measure Event:', JSON.stringify(event));
  } else {
    console.warn('Missing start or end mark for measure', name);
  }
  return originalMeasure.call(this, name, start, end, options);
};

// Return the complete Chrome Trace profile object.
performance.profile = function () {
  return {
    metadata: {
      source: 'Nx Advanced Profiling',
      startTime: Date.now() / 1000,
      hardwareConcurrency: 12,
      dataOrigin: 'TraceEvents',
      modifications: {
        entriesModifications: {
          hiddenEntries: [],
          expandableEntries: [],
        },
        initialBreadcrumb: {
          window: {
            min: 269106047711,
            max: 269107913714,
            range: 1866003,
          },
          child: null,
        },
        annotations: {
          entryLabels: [],
          labelledTimeRanges: [],
          linksBetweenEntries: [],
        },
      },
    },
    traceEvents: trace,
  };
};
performance.trace = trace;

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/utils/css-match.ts:
--------------------------------------------------------------------------------

```typescript
import {
  parseClassNames,
  ngClassesIncludeClassName,
} from '@push-based/angular-ast-utils';
import type {
  DomElement,
  Attribute,
  Binding,
} from '../../shared/models/types.js';

/**
 * Check if a CSS selector matches a DOM element with improved accuracy
 */
export function selectorMatches(
  cssSelector: string,
  domKey: string,
  element: DomElement,
): boolean {
  const normalizedSelector = cssSelector.trim();

  // Handle multiple selectors separated by commas
  if (normalizedSelector.includes(',')) {
    return normalizedSelector
      .split(',')
      .some((selector) => selectorMatches(selector, domKey, element));
  }

  // Handle descendant selectors (space-separated)
  if (normalizedSelector.includes(' ')) {
    const parts = normalizedSelector.split(/\s+/);
    const lastPart = parts[parts.length - 1];
    // Check if the element matches the last part - simplified check as full implementation
    // would need to traverse the DOM tree to check ancestors
    return matchSelector(lastPart, element);
  }

  // Handle single selector
  return matchSelector(normalizedSelector, element);
}

/**
 * Match a single CSS selector (class, id, tag, or attribute)
 */
function matchSelector(selector: string, element: DomElement): boolean {
  // Class selector (.class-name)
  if (selector.startsWith('.')) {
    return matchAttribute('class', selector.substring(1), '=', element);
  }

  // ID selector (#id-name)
  if (selector.startsWith('#')) {
    return matchAttribute('id', selector.substring(1), '=', element);
  }

  // Attribute selector ([attr], [attr=value], [attr*=value], etc.)
  if (selector.startsWith('[') && selector.endsWith(']')) {
    const content = selector.slice(1, -1);

    // Simple attribute existence check [attr]
    if (!content.includes('=')) {
      return (
        element.attributes?.some((attr: Attribute) => attr.name === content) ||
        false
      );
    }

    // Parse attribute selector with value using non-greedy split before the operator
    // This correctly captures operators like *=, ^=, $=
    const match = content.match(/^(.+?)([*^$]?=)(.+)$/);
    if (!match) return false;

    const [, attrNameRaw, operator, value] = match;
    const attrName = attrNameRaw.trim();
    return matchAttribute(attrName, stripQuotes(value), operator, element);
  }

  // Tag selector (div, span, etc.)
  return element.tag === selector;
}

/**
 * Unified attribute matching with support for classes, IDs, and general attributes
 */
function matchAttribute(
  attrName: string,
  expectedValue: string,
  operator: string,
  element: DomElement,
): boolean {
  // Special handling for class attributes
  if (attrName === 'class') {
    // Check static class attribute
    const classAttr = element.attributes?.find(
      (attr: Attribute) => attr.name === 'class',
    );
    if (classAttr) {
      const classes = parseClassNames(classAttr.source);
      if (classes.includes(expectedValue)) {
        return true;
      }
    }

    // Check class bindings [class.foo]
    const classBindings = element.bindings?.filter(
      (binding: Binding) =>
        binding.type === 'class' && binding.name === `class.${expectedValue}`,
    );

    // Check ngClass bindings
    const ngClassBindings = element.bindings?.filter(
      (binding: Binding) => binding.name === 'ngClass',
    );

    for (const binding of ngClassBindings || []) {
      if (ngClassesIncludeClassName(binding.source, expectedValue)) {
        return true;
      }
    }

    return classBindings && classBindings.length > 0;
  }

  // General attribute matching
  const attr = element.attributes?.find(
    (attr: Attribute) => attr.name === attrName,
  );
  if (!attr) return false;

  const attrValue = attr.source;
  return OPERATORS[operator]?.(attrValue, expectedValue) || false;
}

// Operator lookup table
const OPERATORS: Record<
  string,
  (attrValue: string, expectedValue: string) => boolean
> = {
  '=': (attrValue, expectedValue) => attrValue === expectedValue,
  '*=': (attrValue, expectedValue) => attrValue.includes(expectedValue),
  '^=': (attrValue, expectedValue) => attrValue.startsWith(expectedValue),
  '$=': (attrValue, expectedValue) => attrValue.endsWith(expectedValue),
};

/**
 * Remove surrounding quotes from a string
 */
function stripQuotes(str: string): string {
  return str.startsWith('"') || str.startsWith("'") ? str.slice(1, -1) : str;
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/shared/spec/contract-file-ops.spec.ts:
--------------------------------------------------------------------------------

```typescript
/* eslint-disable prefer-const */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

let readFileMock: any;
let mkdirMock: any;
let writeFileMock: any;
let existsSyncMock: any;
let resolveCrossPlatformPathMock: any;

vi.mock('node:fs/promises', () => ({
  get readFile() {
    return readFileMock;
  },
  get mkdir() {
    return mkdirMock;
  },
  get writeFile() {
    return writeFileMock;
  },
}));

vi.mock('node:fs', () => ({
  get existsSync() {
    return existsSyncMock;
  },
}));

vi.mock('node:crypto', () => ({
  createHash: () => ({
    update: () => ({
      digest: () => 'deadbeefdeadbeef',
    }),
  }),
}));

vi.mock('../../../shared/utils/cross-platform-path.js', () => ({
  get resolveCrossPlatformPath() {
    return resolveCrossPlatformPathMock;
  },
}));

import {
  loadContract,
  saveContract,
  generateContractSummary,
  generateDiffFileName,
} from '../utils/contract-file-ops.js';

import type { ComponentContract } from '../models/types.js';

function fixedDate(dateStr = '2024-02-10T12:00:00Z') {
  vi.useFakeTimers();
  vi.setSystemTime(new Date(dateStr));
}

function restoreTime() {
  vi.useRealTimers();
}

const minimalContract: ComponentContract = {
  meta: {
    name: 'FooComponent',
    selector: 'app-foo',
    sourceFile: '/src/app/foo.component.ts',
    templateType: 'external',
    generatedAt: new Date().toISOString(),
    hash: 'hash',
  },
  publicApi: {
    properties: { foo: { type: 'string', isInput: true, required: true } },
    events: { done: { type: 'void' } },
    methods: {
      do: {
        name: 'do',
        parameters: [],
        returnType: 'void',
        isPublic: true,
        isStatic: false,
        isAsync: false,
      },
    },
    lifecycle: ['ngOnInit'],
    imports: [],
  },
  slots: { default: { selector: 'ng-content' } },
  dom: {
    div: {
      tag: 'div',
      parent: null,
      children: [],
      bindings: [],
      attributes: [],
      events: [],
    },
  },
  styles: {
    sourceFile: '/src/app/foo.component.scss',
    rules: { div: { appliesTo: ['div'], properties: { color: 'red' } } },
  },
};

describe('contract-file-ops', () => {
  beforeEach(() => {
    readFileMock = vi.fn();
    mkdirMock = vi.fn();
    writeFileMock = vi.fn();
    existsSyncMock = vi.fn();
    resolveCrossPlatformPathMock = vi.fn(
      (_root: string, p: string) => `${_root}/${p}`,
    );
  });

  afterEach(() => {
    restoreTime();
  });

  describe('loadContract', () => {
    it('loads wrapped contract files', async () => {
      const filePath = '/tmp/contract.json';

      existsSyncMock.mockReturnValue(true);
      readFileMock.mockResolvedValue(
        JSON.stringify({ contract: minimalContract }),
      );

      const contract = await loadContract(filePath);

      expect(readFileMock).toHaveBeenCalledWith(filePath, 'utf-8');
      expect(contract).toEqual(minimalContract);
    });

    it('throws when file is missing', async () => {
      existsSyncMock.mockReturnValue(false);

      await expect(loadContract('/missing.json')).rejects.toThrow(
        'Contract file not found',
      );
    });
  });

  describe('saveContract', () => {
    it('writes contract with metadata and returns path & hash', async () => {
      fixedDate();

      const workspaceRoot = '/workspace';
      const templatePath = 'src/app/foo.component.html';
      const scssPath = 'src/app/foo.component.scss';
      const cwd = '/cwd';

      writeFileMock.mockResolvedValue(undefined);
      mkdirMock.mockResolvedValue(undefined);

      const { contractFilePath, hash } = await saveContract(
        minimalContract,
        workspaceRoot,
        templatePath,
        scssPath,
        cwd,
      );

      // mkdir called for .cursor/tmp directory
      expect(mkdirMock).toHaveBeenCalled();
      expect(contractFilePath).toMatch(/foo\.component.*\.contract\.json$/i);
      expect(hash.startsWith('sha256-')).toBe(true);
      expect(writeFileMock).toHaveBeenCalled();
    });
  });

  describe('generateContractSummary', () => {
    it('generates human-readable summary lines', () => {
      const lines = generateContractSummary(minimalContract);
      expect(lines).toEqual(
        expect.arrayContaining([
          expect.stringMatching(/^🎯 DOM Elements: 1/),
          expect.stringMatching(/^🎨 Style Rules: 1/),
          expect.stringMatching(/^📥 Properties: 1/),
          expect.stringMatching(/^📤 Events: 1/),
        ]),
      );
    });
  });

  describe('generateDiffFileName', () => {
    it('creates timestamped diff filename', () => {
      fixedDate();
      const before = '/contracts/foo.contract.json';
      const after = '/contracts/bar.contract.json';
      const fname = generateDiffFileName(before, after);
      expect(fname).toMatch(/^diff-foo-vs-bar-.*\.json$/);
    });
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/spec/public-api.extractor.spec.ts:
--------------------------------------------------------------------------------

```typescript
/* eslint-disable prefer-const */
import { describe, it, expect, beforeEach, vi } from 'vitest';

let createProgramMock: any;
vi.mock('typescript', () => {
  return {
    get createProgram() {
      return createProgramMock;
    },
    ScriptTarget: { Latest: 99 },
    ModuleKind: { ESNext: 99 },
  };
});

createProgramMock = vi.fn();

let extractClassDeclaration: any;
let extractPublicMethods: any;
let extractLifecycleHooks: any;
let extractImports: any;
let extractInputsAndOutputs: any;

extractClassDeclaration = vi.fn();
extractPublicMethods = vi.fn();
extractLifecycleHooks = vi.fn();
extractImports = vi.fn();
extractInputsAndOutputs = vi.fn();

vi.mock('../utils/typescript-analyzer.js', () => ({
  get extractClassDeclaration() {
    return extractClassDeclaration;
  },
  get extractPublicMethods() {
    return extractPublicMethods;
  },
  get extractLifecycleHooks() {
    return extractLifecycleHooks;
  },
  get extractImports() {
    return extractImports;
  },
  get extractInputsAndOutputs() {
    return extractInputsAndOutputs;
  },
}));

import { extractPublicApi } from '../utils/public-api.extractor.js';

type ParsedComponentStub = {
  fileName: string;
  inputs?: Record<string, any>;
  outputs?: Record<string, any>;
};

function makeParsedComponent(
  partial: Partial<ParsedComponentStub> = {},
): ParsedComponentStub {
  return {
    fileName: '/comp.ts',
    ...partial,
  } as ParsedComponentStub;
}

function resetHelperMocks() {
  extractClassDeclaration.mockReset();
  extractPublicMethods.mockReset();
  extractLifecycleHooks.mockReset();
  extractImports.mockReset();
  extractInputsAndOutputs.mockReset();
  createProgramMock.mockReset();
}

describe('extractPublicApi', () => {
  beforeEach(() => {
    resetHelperMocks();
  });

  it('maps basic inputs and outputs when no class declaration', () => {
    const parsed = makeParsedComponent({
      inputs: { foo: { type: 'string', required: true } },
      outputs: { done: { type: 'void' } },
    });

    extractClassDeclaration.mockReturnValue(undefined);

    const api = extractPublicApi(parsed as any);

    expect(api.properties.foo).toEqual({
      type: 'string',
      isInput: true,
      required: true,
    });
    expect(api.events.done).toEqual({ type: 'void' });
    expect(api.methods).toEqual({});
    expect(api.lifecycle).toEqual([]);
    expect(api.imports).toEqual([]);
  });

  it('merges TypeScript analysis results', () => {
    const parsed = makeParsedComponent();

    const classDeclStub = {};
    extractClassDeclaration.mockReturnValue(classDeclStub);

    createProgramMock.mockReturnValue({
      getSourceFile: () => ({}),
    });

    extractInputsAndOutputs.mockReturnValue({
      inputs: {
        bar: { type: 'number', required: false, alias: 'baz' },
      },
      outputs: {
        submitted: { type: 'CustomEvt', alias: 'submittedAlias' },
      },
    });

    extractPublicMethods.mockReturnValue({
      doStuff: { parameters: [], returnType: 'void' },
    });

    extractLifecycleHooks.mockReturnValue(['ngOnInit']);
    extractImports.mockReturnValue([
      { name: 'HttpClient', path: '@angular/common/http' },
    ]);

    const api = extractPublicApi(parsed as any);

    expect(api.properties.bar).toEqual(
      expect.objectContaining({
        type: 'number',
        isInput: true,
        alias: 'baz',
      }),
    );

    expect(api.events.submitted).toEqual(
      expect.objectContaining({ type: 'CustomEvt', alias: 'submittedAlias' }),
    );

    expect(api.methods).toHaveProperty('doStuff');
    expect(api.lifecycle).toEqual(['ngOnInit']);
    expect(api.imports[0]).toEqual({
      name: 'HttpClient',
      path: '@angular/common/http',
    });
  });

  it('coerces booleanAttribute transform to boolean type', () => {
    const parsed = makeParsedComponent();
    extractClassDeclaration.mockReturnValue({});
    createProgramMock.mockReturnValue({ getSourceFile: () => ({}) });
    extractInputsAndOutputs.mockReturnValue({
      inputs: {
        flag: { type: 'any', transform: 'booleanAttribute' },
      },
      outputs: {},
    });

    const api = extractPublicApi(parsed as any);
    expect(api.properties.flag.type).toBe('boolean');
  });

  it('handles signal input with defaultValue and transform', () => {
    const parsed = makeParsedComponent();
    extractClassDeclaration.mockReturnValue({});
    createProgramMock.mockReturnValue({ getSourceFile: () => ({}) });
    extractInputsAndOutputs.mockReturnValue({
      inputs: {
        count: { type: 'number', defaultValue: 0, transform: 'identity' },
      },
      outputs: {},
    });

    const api = extractPublicApi(parsed as any);

    const countProp = api.properties.count as any;
    expect(countProp.isInput).toBe(true);
    expect(countProp.defaultValue).toBe(0);
    expect(countProp.transform).toBe('identity');
    expect(countProp).not.toHaveProperty('alias');
  });
});

```

--------------------------------------------------------------------------------
/docs/architecture-internal-design.md:
--------------------------------------------------------------------------------

```markdown
# Angular MCP Server – Architecture & Internal Design

> **Audience:** Backend & tool authors who need to understand how the MCP server is wired together so they can extend it with new tools, prompts, or transports.

---

## 1. High-level Overview

The Angular MCP Server is a **Node.js** process that wraps the generic **[Model Context Protocol SDK](https://github.com/modelcontextprotocol/sdk)** and exposes Angular-specific analysis & refactoring tools.  
It follows a clean, layered design:

1. **Transport & Core (MCP SDK)** – HTTP/SSE transport, request routing, JSON-schema validation.  
2. **Server Wrapper (`AngularMcpServerWrapper`)** – registers prompts, tools, and resources; injects workspace-specific paths.  
3. **Tools Layer (`src/lib/tools/**`)** – thin adapters delegating to shared analysis libraries.  
4. **Shared Libraries (`packages/shared/**`)** – AST utilities, DS coverage, generic helpers.

---

## 2. Runtime Flow

```mermaid
graph TD
    subgraph Editor / LLM Client
      A[CallTool / ListTools] -->|HTTP + SSE| B(McpServer Core)
    end

    B --> C{Request Router}
    C -->|tools| D[Tools Registry]
    C -->|prompts| E[Prompts Registry]
    C -->|resources| F[Resources Provider]

    D --> G[Individual Tool Handler]
    G --> H[Shared Libs & Workspace FS]
```

1. The client sends a **`CallTool`** request.  
2. `McpServer` validates the request against JSON Schema.  
3. `AngularMcpServerWrapper` routes it to the correct handler inside **Tools Registry**.  
4. The handler performs analysis (often via shared libs) and returns structured content.  
5. The response streams back.

---

## 3. Bootstrap Sequence

1. **CLI Invocation** (see `.cursor/mcp.json`):
   ```bash
   node packages/angular-mcp/dist/main.js --workspaceRoot=/abs/path ...
   ```
2. `main.ts` → `AngularMcpServerWrapper.create()`
3. **Config Validation** (`AngularMcpServerOptionsSchema`) – checks absolute/relative paths.
4. **File Existence Validation** – ensures Storybook docs & DS mapping files are present.
5. **Server Setup** – registers capabilities & calls:
   - `registerPrompts()`
   - `registerTools()`
   - `registerResources()`
6. Server starts listening.

---

## 4. Directory Layout (server package)

```
packages/angular-mcp-server/
  src/
    lib/
      angular-mcp-server.ts   # Wrapper class (core of the server)
      tools/
        ds/                  # DS-specific tool categories
        shared/              # Internal helpers
      prompts/               # Prompt schemas & impls
      validation/            # Zod schemas & file checks
    index.ts                 # Re-export of wrapper
```

---

## 5. Tools & Extension Points

| Extension | Where to Add | Boilerplate |
|-----------|-------------|-------------|
| **Tool** | `src/lib/tools/**` | 1. Create `my-awesome.tool.ts` exporting `ToolsConfig[]`.  <br>2. Add it to the export list in `tools/ds/tools.ts` (or another category). |
| **Prompt** | `prompts/prompt-registry.ts` | 1. Append schema to `PROMPTS`. <br>2. Provide implementation in `PROMPTS_IMPL`. |
| **Resource Provider** | `registerResources()` | Extend logic to aggregate custom docs or design-system assets. |

All tools share the `ToolsConfig` interface (`@push-based/models`) that bundles:
- `schema` (name, description, arguments, return type)
- `handler(request)` async function.

The MCP SDK auto-validates every call against the schema – no manual parsing required.

---

## 6. Configuration Options

| Option | Type | Description |
|--------|------|-------------|
| `workspaceRoot` | absolute path | Root of the Nx/Angular workspace. |
| `ds.storybookDocsRoot` | relative path | Path (from root) to Storybook MDX/Docs for DS components. |
| `ds.deprecatedCssClassesPath` | relative path | JS file mapping components → deprecated CSS classes. |
| `ds.uiRoot` | relative path | Folder containing raw design-system component source. |

Validation is handled via **Zod** in `angular-mcp-server-options.schema.ts`.

---

## 7. Shared Libraries in Play

```
models  (types & schemas)
├─ utils
├─ styles-ast-utils
└─ angular-ast-utils
    └─ ds-component-coverage  (top-level plugin)
```

These libraries provide AST parsing, file operations, and DS analysis. Tools import them directly; they are **framework-agnostic** and can be unit-tested in isolation.

---

## 8. Testing & Examples

`packages/minimal-repo/**` contains miniature Angular apps used by unit/integration tests. They are **not** part of production code but useful when debugging a new tool.

---

## 9. Adding a New Tool – Checklist

1. Identify functionality and pick/create an appropriate shared library function.  
2. Generate a JSON-schema with arguments & result shape (can use Zod helper).  
3. Implement handler logic (avoid heavy FS operations in main thread; prefer async).  
4. Export via `ToolsConfig[]` and append to category list.  
5. Write unit tests.
6. Update `docs/tools.md` once published.

---
```

--------------------------------------------------------------------------------
/packages/shared/DEPENDENCIES.md:
--------------------------------------------------------------------------------

```markdown
# Shared Libraries Dependencies

This document provides an AI-friendly overview of the shared libraries in the `/packages/shared` directory, their purposes, and cross-dependencies.

## Library Overview

### Foundation Layer (No Internal Dependencies)

#### `@push-based/models`

- **Purpose**: Core types and interfaces for CLI and MCP tooling
- **Key Exports**: CliArgsObject, ArgumentValue, ToolSchemaOptions, ToolsConfig, ToolHandlerContentResult, DiagnosticsAware
- **Dependencies**: None (foundation library)
- **Used By**: All other shared libraries

#### `@push-based/typescript-ast-utils`

- **Purpose**: TypeScript AST parsing and manipulation utilities
- **Key Exports**: isComponentDecorator, removeQuotes, getDecorators, isDecorator
- **Dependencies**: None (foundation library)
- **Used By**: angular-ast-utils

### Intermediate Layer (Single Foundation Dependency)

#### `@push-based/utils`

- **Purpose**: General utility functions and file system operations
- **Key Exports**: findFilesWithPattern, resolveFile
- **Dependencies**: models
- **Used By**: angular-ast-utils, ds-component-coverage

#### `@push-based/styles-ast-utils`

- **Purpose**: CSS/SCSS AST parsing and manipulation utilities
- **Key Exports**: parseStylesheet, CssAstVisitor, visitStyleSheet, styleAstRuleToSource
- **Dependencies**: models
- **Used By**: angular-ast-utils, ds-component-coverage

### Advanced Layer (Multiple Dependencies)

#### `@push-based/angular-ast-utils`

- **Purpose**: Angular component parsing and template/style analysis
- **Key Exports**: parseComponents, visitComponentTemplate, visitComponentStyles, findAngularUnits
- **Dependencies**:
  - models (types and schemas)
  - utils (file operations)
  - typescript-ast-utils (TS AST utilities)
  - styles-ast-utils (CSS AST utilities)
- **Used By**: ds-component-coverage

#### `@push-based/ds-component-coverage`

- **Purpose**: Design System component usage analysis and coverage reporting
- **Key Exports**: dsComponentCoveragePlugin, runnerFunction, getAngularDsUsageCategoryRefs
- **Dependencies**:
  - models (audit types)
  - utils (utilities)
  - styles-ast-utils (CSS analysis)
  - angular-ast-utils (component parsing)
- **Used By**: None (top-level plugin)

## Dependency Graph

```
@code-pushup/models (foundation)
├── @code-pushup/utils
├── styles-ast-utils
└── angular-ast-utils
    ├── @code-pushup/models
    ├── @code-pushup/utils
    ├── typescript-ast-utils
    └── styles-ast-utils

ds-component-coverage (most complex)
├── @code-pushup/models
├── @code-pushup/utils
├── styles-ast-utils
└── angular-ast-utils
```

## Build Order

Based on dependencies, the correct build order is:

1. **Foundation**: `models`, `typescript-ast-utils`
2. **Intermediate**: `utils`, `styles-ast-utils`
3. **Advanced**: `angular-ast-utils`
4. **Top-level**: `ds-component-coverage`

## Key Patterns

### Dependency Injection Pattern

- Libraries accept dependencies through imports rather than direct instantiation
- Enables testing and modularity

### Layered Architecture

- Clear separation between foundation, intermediate, and advanced layers
- Each layer builds upon the previous one

### Single Responsibility

- Each library has a focused purpose
- Cross-cutting concerns are handled by foundation libraries

### No Circular Dependencies

- Clean acyclic dependency graph
- Ensures predictable build order and runtime behavior

## Usage Guidelines for AI

### When to Use Each Library

- **models**: When you need CLI argument types or MCP tooling interfaces
- **utils**: For file operations, string manipulation, or general utilities
- **typescript-ast-utils**: For TypeScript code analysis and manipulation
- **styles-ast-utils**: For CSS/SCSS parsing and analysis
- **angular-ast-utils**: For Angular component analysis and template/style processing
- **ds-component-coverage**: For Design System migration analysis and reporting

### Common Import Patterns

```typescript
// Foundation types
import { CliArgsObject, ToolSchemaOptions, DiagnosticsAware } from '@push-based/models';

// File operations
import { resolveFile, findFilesWithPattern } from '@code-pushup/utils';

// Angular component parsing
import {
  parseComponents,
  visitComponentTemplate,
} from '@push-based/angular-ast-utils';

// CSS analysis
import { parseStylesheet, visitStyleSheet } from '@push-based/styles-ast-utils';

// TypeScript utilities
import {
  isComponentDecorator,
  removeQuotes,
} from '@push-based/typescript-ast-utils';
```

### Integration Points

- All libraries use `models` for CLI and MCP tooling type definitions
- File operations flow through `utils`
- AST operations are specialized by language (TS, CSS, Angular)
- Complex analysis combines multiple AST utilities through `angular-ast-utils`

## Maintenance Notes

- Changes to `models` affect all other libraries
- `angular-ast-utils` is the most integration-heavy library
- `ds-component-coverage` represents the full stack integration
- Foundation libraries should remain stable and focused
- New features should follow the established layering pattern

```

--------------------------------------------------------------------------------
/packages/shared/utils/src/lib/execute-process.ts:
--------------------------------------------------------------------------------

```typescript
import {
  type ChildProcess,
  type ChildProcessByStdio,
  type SpawnOptionsWithStdioTuple,
  type StdioPipe,
  spawn,
} from 'node:child_process';
import type { Readable, Writable } from 'node:stream';
import { formatCommandLog } from './format-command-log.js';
import { isVerbose } from './logging.js';
import { calcDuration } from './utils.js';

/**
 * Represents the process result.
 * @category Types
 * @public
 * @property {string} stdout - The stdout of the process.
 * @property {string} stderr - The stderr of the process.
 * @property {number | null} code - The exit code of the process.
 */
export type ProcessResult = {
  stdout: string;
  stderr: string;
  code: number | null;
  date: string;
  duration: number;
};

/**
 * Error class for process errors.
 * Contains additional information about the process result.
 * @category Error
 * @public
 * @class
 * @extends Error
 * @example
 * const result = await executeProcess({})
 * .catch((error) => {
 *   if (error instanceof ProcessError) {
 *   console.error(error.code);
 *   console.error(error.stderr);
 *   console.error(error.stdout);
 *   }
 * });
 *
 */
export class ProcessError extends Error {
  code: number | null;
  stderr: string;
  stdout: string;

  constructor(result: ProcessResult) {
    super(result.stderr);
    this.code = result.code;
    this.stderr = result.stderr;
    this.stdout = result.stdout;
  }
}

/**
 * Process config object. Contains the command, args and observer.
 * @param cfg - process config object with command, args and observer (optional)
 * @category Types
 * @public
 * @property {string} command - The command to execute.
 * @property {string[]} args - The arguments for the command.
 * @property {ProcessObserver} observer - The observer for the process.
 *
 * @example
 *
 * // bash command
 * const cfg = {
 *   command: 'bash',
 *   args: ['-c', 'echo "hello world"']
 * };
 *
 * // node command
 * const cfg = {
 * command: 'node',
 * args: ['--version']
 * };
 *
 * // npx command
 * const cfg = {
 * command: 'npx',
 * args: ['--version']
 *
 */
export type ProcessConfig = Omit<
  SpawnOptionsWithStdioTuple<StdioPipe, StdioPipe, StdioPipe>,
  'stdio'
> & {
  command: string;
  args?: string[];
  observer?: ProcessObserver;
  ignoreExitCode?: boolean;
};

/**
 * Process observer object. Contains the onStdout, error and complete function.
 * @category Types
 * @public
 * @property {function} onStdout - The onStdout function of the observer (optional).
 * @property {function} onError - The error function of the observer (optional).
 * @property {function} onComplete - The complete function of the observer (optional).
 *
 * @example
 * const observer = {
 *  onStdout: (stdout) => console.info(stdout)
 *  }
 */
export type ProcessObserver = {
  onStdout?: (stdout: string, sourceProcess?: ChildProcess) => void;
  onStderr?: (stderr: string, sourceProcess?: ChildProcess) => void;
  onError?: (error: ProcessError) => void;
  onComplete?: () => void;
};

/**
 * Executes a process and returns a promise with the result as `ProcessResult`.
 *
 * @example
 *
 * // sync process execution
 * const result = await executeProcess({
 *  command: 'node',
 *  args: ['--version']
 * });
 *
 * console.info(result);
 *
 * // async process execution
 * const result = await executeProcess({
 *    command: 'node',
 *    args: ['download-data.js'],
 *    observer: {
 *      onStdout: updateProgress,
 *      error: handleError,
 *      complete: cleanLogs,
 *    }
 * });
 *
 * console.info(result);
 *
 * @param cfg - see {@link ProcessConfig}
 */
export function executeProcess(cfg: ProcessConfig): Promise<ProcessResult> {
  const { command, args, observer, ignoreExitCode = false, ...options } = cfg;
  const { onStdout, onStderr, onError, onComplete } = observer ?? {};
  const date = new Date().toISOString();
  const start = performance.now();

  if (isVerbose()) {
    console.log(formatCommandLog(command, args, `${cfg.cwd ?? process.cwd()}`));
  }

  return new Promise((resolve, reject) => {
    // shell:true tells Windows to use shell command for spawning a child process
    const spawnedProcess = spawn(command, args ?? [], {
      shell: true,
      windowsHide: true,
      ...options,
    }) as ChildProcessByStdio<Writable, Readable, Readable>;

    let stdout = '';
    let stderr = '';

    spawnedProcess.stdout.on('data', (data) => {
      stdout += String(data);
      onStdout?.(String(data), spawnedProcess);
    });

    spawnedProcess.stderr.on('data', (data) => {
      stderr += String(data);
      onStderr?.(String(data), spawnedProcess);
    });

    spawnedProcess.on('error', (err) => {
      stderr += err.toString();
    });

    spawnedProcess.on('close', (code) => {
      const timings = { date, duration: calcDuration(start) };
      if (code === 0 || ignoreExitCode) {
        onComplete?.();
        resolve({ code, stdout, stderr, ...timings });
      } else {
        const errorMsg = new ProcessError({ code, stdout, stderr, ...timings });
        onError?.(errorMsg);
        reject(errorMsg);
      }
    });
  });
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/builder/spec/dom-slots.extractor.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { describe, it, expect, vi } from 'vitest';

// -----------------------------------------------------------------------------
// Mocking angular-ast-utils functions relied upon by extractSlotsAndDom
// -----------------------------------------------------------------------------

// Helper used by extractSlotsAndDom to traverse template
function visitEachTmplChild(nodes: any[], visitor: any): void {
  nodes.forEach((node) => {
    if (typeof node.visit === 'function') {
      node.visit(visitor);
    }
  });
}

// Mock implementation of visitComponentTemplate – supplies template nodes
async function visitComponentTemplate(
  parsedComponent: any,
  _options: any,
  cb: any,
) {
  const templateAsset = {
    parse: async () => ({ nodes: parsedComponent.templateNodes }),
  };
  return cb(parsedComponent, templateAsset);
}

/* eslint-disable prefer-const */

vi.mock('@push-based/angular-ast-utils', () => {
  // Define a lightweight NoopTmplVisitor inside the mock factory to avoid
  // reference-before-initialization issues caused by hoisting.
  class NoopTmplVisitor {}

  return {
    visitComponentTemplate,
    visitEachTmplChild,
    NoopTmplVisitor,
    parseClassNames: (classStr: string) => classStr.trim().split(/\s+/),
  };
});

// -----------------------------------------------------------------------------
// Imports (after mocks)
// -----------------------------------------------------------------------------
import { extractSlotsAndDom } from '../utils/dom-slots.extractor.js';

// -----------------------------------------------------------------------------
// Minimal AST node builders
// -----------------------------------------------------------------------------

type AttributeNode = { name: string; value: string };
type InputNode = { name: string; value?: any };
type OutputNode = { name: string; handler: { source: string } };

type ElementNode = {
  name: string;
  attributes: AttributeNode[];
  inputs: InputNode[];
  outputs: OutputNode[];
  children: any[];
  visit: (v: any) => void;
};

function createElement(
  params: Partial<ElementNode> & { name: string },
): ElementNode {
  const node: ElementNode = {
    name: params.name,
    attributes: params.attributes ?? [],
    inputs: params.inputs ?? [],
    outputs: params.outputs ?? [],
    children: params.children ?? [],
    visit(visitor: any) {
      // Call the appropriate visitor method
      if (typeof visitor.visitElement === 'function') {
        visitor.visitElement(this as any);
      }
    },
  } as ElementNode;
  return node;
}

function createContent(selector: string | undefined): any {
  return {
    selector,
    visit(visitor: any) {
      if (typeof visitor.visitContent === 'function') {
        visitor.visitContent(this);
      }
    },
  };
}

function createForLoopBlock(
  children: any[],
  expressionSrc = 'item of items',
  alias = 'item',
): any {
  return {
    children,
    expression: { source: expressionSrc },
    item: { name: alias },
    visit(visitor: any) {
      if (typeof visitor.visitForLoopBlock === 'function') {
        visitor.visitForLoopBlock(this);
      }
    },
  };
}

// -----------------------------------------------------------------------------
// Test suites
// -----------------------------------------------------------------------------

describe('extractSlotsAndDom', () => {
  it('extracts default and named slots', async () => {
    const defaultSlot = createContent(undefined);
    const namedSlot = createContent('[slot=header]');

    const parsedComponent = {
      templateNodes: [defaultSlot, namedSlot],
    };

    const { slots } = await extractSlotsAndDom(parsedComponent as any);

    expect(slots).toHaveProperty('default');
    expect(slots.default.selector).toBe('ng-content');

    expect(slots).toHaveProperty('header');
    expect(slots.header.selector).toBe('ng-content[select="[slot=header]"]');
  });

  it('builds DOM structure with parent-child links', async () => {
    const span = createElement({
      name: 'span',
      attributes: [{ name: 'class', value: 'foo' }],
    });

    const div = createElement({
      name: 'div',
      attributes: [{ name: 'id', value: 'root' }],
      children: [span],
    });

    const parsedComponent = { templateNodes: [div] };

    const { dom } = await extractSlotsAndDom(parsedComponent as any);

    const parentKey = 'div#root';
    const childKey = 'div#root > span.foo';

    expect(Object.keys(dom)).toEqual([parentKey, childKey]);

    const parent = dom[parentKey] as any;
    const child = dom[childKey] as any;

    expect(parent.children).toEqual([childKey]);
    expect(child.parent).toBe(parentKey);
  });

  it('captures structural directive context (for loop)', async () => {
    const li = createElement({ name: 'li' });
    const forBlock = createForLoopBlock([li]);

    const parsedComponent = { templateNodes: [forBlock] };

    const { dom } = await extractSlotsAndDom(parsedComponent as any);

    const liNode = dom['li'] as any;
    expect(liNode).toBeTruthy();
    expect(liNode.structural?.[0]).toEqual(
      expect.objectContaining({ kind: 'for', alias: 'item' }),
    );
  });
});

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component-contract/diff/utils/diff-utils.ts:
--------------------------------------------------------------------------------

```typescript
import type { Difference } from 'microdiff';
import type { DomPathDictionary } from '../../shared/models/types.js';
import { createDomPathDictionary, processDomPaths } from './dom-path-utils.js';

/**
 * Enhanced version of consolidateAndPruneRemoveOperations with DOM path deduplication
 */
export function consolidateAndPruneRemoveOperationsWithDeduplication(
  diffResult: Difference[],
): {
  processedResult: Difference[];
  domPathDict: DomPathDictionary;
} {
  const consolidatedResult = consolidateAndPruneRemoveOperations(diffResult);

  const domPathDict = createDomPathDictionary(),
    processedResult = consolidatedResult.map((c) =>
      processDomPaths(c, domPathDict),
    );

  return {
    processedResult,
    domPathDict,
  };
}

/**
 * Consolidates REMOVE operations for CSS rules in styles section and
 * prunes redundant child REMOVE operations from a microdiff result.
 */
export function consolidateAndPruneRemoveOperations(
  diffResult: Difference[],
): Difference[] {
  const { removeOperations, nonRemoveOperations } = diffResult.reduce(
    (acc, change) => {
      (change.type === 'REMOVE'
        ? acc.removeOperations
        : acc.nonRemoveOperations
      ).push(change);
      return acc;
    },
    {
      removeOperations: [] as Difference[],
      nonRemoveOperations: [] as Difference[],
    },
  );

  if (removeOperations.length === 0) {
    return diffResult;
  }

  const cssRuleRemoves = new Map<string, Difference[]>();
  const otherRemoves: Difference[] = [];

  const isCssRuleRemove = (d: Difference) =>
    d.type === 'REMOVE' &&
    d.path.length === 3 &&
    d.path[0] === 'styles' &&
    d.path[1] === 'rules' &&
    typeof d.path[2] === 'string';

  for (const remove of removeOperations) {
    if (isCssRuleRemove(remove)) {
      const key = 'styles.rules';
      const group = cssRuleRemoves.get(key) ?? [];
      group.push(remove);
      cssRuleRemoves.set(key, group);
    } else {
      otherRemoves.push(remove);
    }
  }

  const consolidatedCssRuleChanges: Difference[] = [
    ...[...cssRuleRemoves.values()].flatMap((removes) =>
      removes.length > 1
        ? [
            {
              type: 'REMOVE',
              path: ['styles', 'rules'],
              oldValue: removes.map((r) => r.path[2]),
            } as Difference,
          ]
        : removes,
    ),
  ];

  otherRemoves.sort((a, b) => a.path.length - b.path.length);

  const prunedOtherRemoves: Difference[] = [];

  for (const currentRemove of otherRemoves) {
    let isRedundant = false;

    for (const existingRemove of prunedOtherRemoves) {
      if (isChildPath(currentRemove.path, existingRemove.path)) {
        isRedundant = true;
        break;
      }
    }

    if (!isRedundant) {
      prunedOtherRemoves.push(currentRemove);
    }
  }

  return [
    ...nonRemoveOperations,
    ...consolidatedCssRuleChanges,
    ...prunedOtherRemoves,
  ];
}

/**
 * Checks if childPath is a descendant of parentPath.
 * For example, ['a', 'b', 'c'] is a child of ['a', 'b']
 */
export function isChildPath(
  childPath: (string | number)[],
  parentPath: (string | number)[],
): boolean {
  return (
    childPath.length > parentPath.length &&
    parentPath.every((seg, i) => childPath[i] === seg)
  );
}

/**
 * Groups diff changes by domain first, then by type within each domain.
 * Removes the domain from the path since it's captured in the grouping structure.
 */
export function groupChangesByDomainAndType(
  changes: Difference[],
): Record<string, Record<string, any[]>> {
  return changes.reduce(
    (acc: Record<string, Record<string, any[]>>, change: Difference) => {
      const { type, path, ...changeWithoutTypeAndPath } = change;
      const domain = path[0] as string;
      if (!acc[domain]) acc[domain] = {};
      if (!acc[domain][type]) acc[domain][type] = [];
      acc[domain][type].push({
        ...changeWithoutTypeAndPath,
        path: path.slice(1),
      });
      return acc;
    },
    {} as Record<string, Record<string, any[]>>,
  );
}

/**
 * Generates a comprehensive summary of diff changes including totals and breakdowns by type and domain.
 */
export function generateDiffSummary(
  processedResult: Difference[],
  groupedChanges: Record<string, Record<string, any[]>>,
): {
  totalChanges: number;
  changeTypes: Record<string, number>;
  changesByDomain: Record<string, Record<string, number>>;
} {
  return {
    totalChanges: processedResult.length,
    changeTypes: processedResult.reduce(
      (acc: Record<string, number>, change: Difference) => {
        acc[change.type] = (acc[change.type] ?? 0) + 1;
        return acc;
      },
      {} as Record<string, number>,
    ),
    changesByDomain: Object.entries(groupedChanges).reduce(
      (acc: Record<string, Record<string, number>>, [domain, types]) => {
        acc[domain] = Object.entries(types).reduce(
          (domainAcc: Record<string, number>, [type, changes]) => {
            domainAcc[type] = changes.length;
            return domainAcc;
          },
          {} as Record<string, number>,
        );
        return acc;
      },
      {} as Record<string, Record<string, number>>,
    ),
  };
}

```

--------------------------------------------------------------------------------
/packages/shared/LLMS.md:
--------------------------------------------------------------------------------

```markdown
# LLM Documentation Index

<a id="top"></a>
**Contents:**

- [Structure](#documentation-structure)
- [Foundation](#foundation-layer)
- [Intermediate](#intermediate-layer)
- [Advanced](#advanced-layer)
- [Navigation](#quick-navigation)
- [Related](#related-docs)
- [Tips](#tips)
- [Status](#doc-status)

This document provides quick access to all AI-friendly documentation across the shared libraries. Each library includes comprehensive API documentation, practical examples, and function references.

## 📚 Documentation Structure <a id="documentation-structure"></a>

Each library provides three types of AI documentation:

- **FUNCTIONS.md**: A-Z quick reference for every public symbol
- **API.md**: Overview, key features, and minimal usage examples
- **EXAMPLES.md**: Practical, runnable code scenarios with expected outputs

## 🏗️ Foundation Layer <a id="foundation-layer"></a>

### @code-pushup/models <a id="models"></a>

Core types, interfaces, and Zod schemas for the entire ecosystem.

- [🔍 Functions Reference](./models/ai/FUNCTIONS.md)
- [📖 API Overview](./models/ai/API.md)
- [💡 Examples](./models/ai/EXAMPLES.md)

### @push-based/typescript-ast-utils <a id="typescript-ast-utils"></a>

TypeScript AST parsing and manipulation utilities.

- [🔍 Functions Reference](./typescript-ast-utils/ai/FUNCTIONS.md)
- [📖 API Overview](./typescript-ast-utils/ai/API.md)
- [💡 Examples](./typescript-ast-utils/ai/EXAMPLES.md)

## 🔧 Intermediate Layer <a id="intermediate-layer"></a>

### @code-pushup/utils <a id="utils"></a>

General utility functions and file system operations.

- [🔍 Functions Reference](./utils/ai/FUNCTIONS.md)
- [📖 API Overview](./utils/ai/API.md)
- [💡 Examples](./utils/ai/EXAMPLES.md)

### @push-based/styles-ast-utils <a id="styles-ast-utils"></a>

CSS/SCSS AST parsing and manipulation utilities.

- [🔍 Functions Reference](./styles-ast-utils/ai/FUNCTIONS.md)
- [📖 API Overview](./styles-ast-utils/ai/API.md)
- [💡 Examples](./styles-ast-utils/ai/EXAMPLES.md)

## 🚀 Advanced Layer <a id="advanced-layer"></a>

### @push-based/angular-ast-utils <a id="angular-ast-utils"></a>

Angular component parsing and template/style analysis.

- [🔍 Functions Reference](./angular-ast-utils/ai/FUNCTIONS.md)
- [📖 API Overview](./angular-ast-utils/ai/API.md)
- [💡 Examples](./angular-ast-utils/ai/EXAMPLES.md)

### @push-based/ds-component-coverage <a id="ds-component-coverage"></a>

Design System component usage analysis and coverage reporting.

- [🔍 Functions Reference](./ds-component-coverage/ai/FUNCTIONS.md)
- [📖 API Overview](./ds-component-coverage/ai/API.md)
- [💡 Examples](./ds-component-coverage/ai/EXAMPLES.md)

## 🎯 Quick Navigation by Use Case <a id="quick-navigation"></a>

### Type Definitions & Schemas

- [models/FUNCTIONS.md](./models/ai/FUNCTIONS.md) - All available types and interfaces
- [models/API.md](./models/ai/API.md) - Core types and Zod schemas

### File & String Operations

- [utils/FUNCTIONS.md](./utils/ai/FUNCTIONS.md) - Complete function reference
- [utils/API.md](./utils/ai/API.md) - File system and utility functions
- [utils/EXAMPLES.md](./utils/ai/EXAMPLES.md) - File operations and string manipulation

### AST Analysis & Manipulation

- [typescript-ast-utils/FUNCTIONS.md](./typescript-ast-utils/ai/FUNCTIONS.md) - TS AST function reference
- [styles-ast-utils/FUNCTIONS.md](./styles-ast-utils/ai/FUNCTIONS.md) - CSS AST function reference
- [angular-ast-utils/FUNCTIONS.md](./angular-ast-utils/ai/FUNCTIONS.md) - Angular AST function reference

### Angular Development

- [angular-ast-utils/EXAMPLES.md](./angular-ast-utils/ai/EXAMPLES.md) - Component parsing and analysis

### Design System Analysis

- [ds-component-coverage/FUNCTIONS.md](./ds-component-coverage/ai/FUNCTIONS.md) - DS analysis functions
- [ds-component-coverage/API.md](./ds-component-coverage/ai/API.md) - DS migration and coverage analysis
- [ds-component-coverage/EXAMPLES.md](./ds-component-coverage/ai/EXAMPLES.md) - Real-world DS analysis scenarios

## 🔗 Related Documentation <a id="related-docs"></a>

- [DEPENDENCIES.md](./DEPENDENCIES.md) - Cross-dependencies and architecture overview
- [Individual README files](./*/README.md) - Library-specific setup and build instructions

## 💡 Tips for LLMs <a id="tips"></a>

1. **Start with FUNCTIONS.md** for quick function lookup and signatures
2. **Use API.md** for understanding library capabilities and minimal usage
3. **Reference EXAMPLES.md** for practical implementation patterns
4. **Check DEPENDENCIES.md** to understand library relationships
5. **Follow the layered architecture** when combining multiple libraries

## 📋 Documentation Status <a id="doc-status"></a>

All shared libraries have complete AI documentation:

| Library               | Functions | API | Examples | Status   |
| --------------------- | --------- | --- | -------- | -------- |
| models                | ✅        | ✅  | ✅       | Complete |
| typescript-ast-utils  | ✅        | ✅  | ✅       | Complete |
| utils                 | ✅        | ✅  | ✅       | Complete |
| styles-ast-utils      | ✅        | ✅  | ✅       | Complete |
| angular-ast-utils     | ✅        | ✅  | ✅       | Complete |
| ds-component-coverage | ✅        | ✅  | ✅       | Complete |

_Last updated: 2025-06-13_

```

--------------------------------------------------------------------------------
/packages/shared/models/ai/EXAMPLES.md:
--------------------------------------------------------------------------------

```markdown
# Examples

## 1 — Working with CLI arguments

> Type-safe handling of command line arguments.

```ts
import { type CliArgsObject, type ArgumentValue } from '@push-based/models';

// Basic CLI arguments
const args: CliArgsObject = {
  directory: './src/components',
  componentName: 'DsButton',
  groupBy: 'file',
  _: ['report-violations'],
};

console.log(args.directory); // → './src/components'
console.log(args._); // → ['report-violations']

// Typed CLI arguments with specific structure
interface MyToolArgs {
  directory: string;
  componentName: string;
  groupBy?: 'file' | 'folder';
  verbose?: boolean;
}

const typedArgs: CliArgsObject<MyToolArgs> = {
  directory: './packages/shared/models',
  componentName: 'DsCard',
  groupBy: 'folder',
  verbose: true,
  _: ['analyze'],
};

console.log(`Analyzing ${typedArgs.componentName} in ${typedArgs.directory}`);
// → 'Analyzing DsCard in ./packages/shared/models'
```

---

## 2 — Creating MCP tools

> Build Model Context Protocol tools with proper typing.

```ts
import { type ToolsConfig, type ToolSchemaOptions } from '@push-based/models';

// Define a simple MCP tool
const reportViolationsTool: ToolsConfig = {
  schema: {
    name: 'report-violations',
    description: 'Report deprecated DS CSS usage in a directory',
    inputSchema: {
      type: 'object',
      properties: {
        directory: {
          type: 'string',
          description: 'The relative path to the directory to scan',
        },
        componentName: {
          type: 'string',
          description: 'The class name of the component (e.g., DsButton)',
        },
        groupBy: {
          type: 'string',
          enum: ['file', 'folder'],
          default: 'file',
          description: 'How to group the results',
        },
      },
      required: ['directory', 'componentName'],
    },
  },
  handler: async (request) => {
    const { directory, componentName, groupBy = 'file' } = request.params.arguments as {
      directory: string;
      componentName: string;
      groupBy?: 'file' | 'folder';
    };

    // Tool implementation logic here
    const violations = await analyzeViolations(directory, componentName, groupBy);

    return {
      content: [
        {
          type: 'text',
          text: `Found ${violations.length} violations in ${directory}`,
        },
      ],
    };
  },
};

// Use the tool configuration
console.log(`Tool: ${reportViolationsTool.schema.name}`);
// → 'Tool: report-violations'
```

---

## 3 — Implementing diagnostics

> Create objects that can report issues and diagnostics.

```ts
import { type DiagnosticsAware } from '@push-based/models';

class ComponentAnalyzer implements DiagnosticsAware {
  private issues: Array<{ code?: number; message: string; severity: string }> = [];

  analyze(componentPath: string): void {
    // Simulate analysis
    if (!componentPath.endsWith('.ts')) {
      this.issues.push({
        code: 1001,
        message: 'Component file should have .ts extension',
        severity: 'error',
      });
    }

    if (componentPath.includes('deprecated')) {
      this.issues.push({
        code: 2001,
        message: 'Component uses deprecated patterns',
        severity: 'warning',
      });
    }
  }

  getIssues() {
    return this.issues;
  }

  clear(): void {
    this.issues = [];
  }
}

// Usage
const analyzer = new ComponentAnalyzer();
analyzer.analyze('src/components/deprecated-button.js');

const issues = analyzer.getIssues();
console.log(`Found ${issues.length} issues:`);
issues.forEach((issue) => {
  console.log(`  ${issue.severity}: ${issue.message} (code: ${issue.code})`);
});
// → Found 2 issues:
// →   error: Component file should have .ts extension (code: 1001)
// →   warning: Component uses deprecated patterns (code: 2001)

analyzer.clear();
console.log(`Issues after clear: ${analyzer.getIssues().length}`); // → 0
```

---

## 4 — Advanced MCP tool with content results

> Create sophisticated MCP tools that return structured content.

```ts
import {
  type ToolsConfig,
  type ToolHandlerContentResult,
} from '@push-based/models';

const buildComponentContractTool: ToolsConfig = {
  schema: {
    name: 'build-component-contract',
    description: 'Generate a static surface contract for a component',
    inputSchema: {
      type: 'object',
      properties: {
        directory: { type: 'string' },
        templateFile: { type: 'string' },
        styleFile: { type: 'string' },
        typescriptFile: { type: 'string' },
        dsComponentName: { type: 'string' },
      },
      required: ['directory', 'templateFile', 'styleFile', 'typescriptFile', 'dsComponentName'],
    },
  },
  handler: async (request) => {
    const params = request.params.arguments as {
      directory: string;
      templateFile: string;
      styleFile: string;
      typescriptFile: string;
      dsComponentName: string;
    };

    // Generate contract
    const contract = await generateContract(params);

    const content: ToolHandlerContentResult[] = [
      {
        type: 'text',
        text: `Generated contract for ${params.dsComponentName}`,
      },
      {
        type: 'text',
        text: `Template inputs: ${contract.templateInputs.length}`,
      },
      {
        type: 'text',
        text: `Style classes: ${contract.styleClasses.length}`,
      },
    ];

    return { content };
  },
};

// Mock contract generation function
async function generateContract(params: any) {
  return {
    templateInputs: ['@Input() label: string', '@Input() disabled: boolean'],
    styleClasses: ['.ds-button', '.ds-button--primary'],
  };
}
```

These examples demonstrate the practical usage patterns of the `@push-based/models` library for building type-safe CLI tools, MCP integrations, and diagnostic utilities in the Angular MCP toolkit.

```

--------------------------------------------------------------------------------
/.cursor/flows/component-refactoring/angular-20.md:
--------------------------------------------------------------------------------

```markdown
# Angular Best Practices

This project adheres to modern Angular best practices, emphasizing maintainability, performance, accessibility, and scalability.

## TypeScript Best Practices

- **Strict Type Checking:** Always enable and adhere to strict type checking. This helps catch errors early and improves code quality.
- **Prefer Type Inference:** Allow TypeScript to infer types when they are obvious from the context. This reduces verbosity while maintaining type safety.
  - **Bad:**
    ```typescript
    let name: string = 'Angular';
    ```
  - **Good:**
    ```typescript
    let name = 'Angular';
    ```
- **Avoid `any`:** Do not use the `any` type unless absolutely necessary as it bypasses type checking. Prefer `unknown` when a type is uncertain and you need to handle it safely.

## Angular Best Practices

- **Standalone Components:** Always use standalone components, directives, and pipes. Avoid using `NgModules` for new features or refactoring existing ones.
- **Implicit Standalone:** When creating standalone components, you do not need to explicitly set `standalone: true` as it is implied by default when generating a standalone component.
  - **Bad:**
    ```typescript
    @Component({
      standalone: true,
      // ...
    })
    export class MyComponent {}
    ```
  - **Good:**
    ```typescript
    @Component({
      // `standalone: true` is implied
      // ...
    })
    export class MyComponent {}
    ```
- **Signals for State Management:** Utilize Angular Signals for reactive state management within components and services.
- **Lazy Loading:** Implement lazy loading for feature routes to improve initial load times of your application.
- **NgOptimizedImage:** Use `NgOptimizedImage` for all static images to automatically optimize image loading and performance.

## Components

- **Single Responsibility:** Keep components small, focused, and responsible for a single piece of functionality.
- **`input()` and `output()` Functions:** Prefer `input()` and `output()` functions over the `@Input()` and `@Output()` decorators for defining component inputs and outputs.
  - **Old Decorator Syntax:**
    ```typescript
    @Input() userId!: string;
    @Output() userSelected = new EventEmitter<string>();
    ```
  - **New Function Syntax:**

    ```typescript
    import { input, output } from '@angular/core';

    // ...
    userId = input<string>('');
    userSelected = output<string>();
    ```

- **`computed()` for Derived State:** Use the `computed()` function from `@angular/core` for derived state based on signals.
- **`ChangeDetectionStrategy.OnPush`:** Always set `changeDetection: ChangeDetectionStrategy.OnPush` in the `@Component` decorator for performance benefits by reducing unnecessary change detection cycles.
- **Inline Templates:** Prefer inline templates (template: `...`) for small components to keep related code together. For larger templates, use external HTML files.
- **Reactive Forms:** Prefer Reactive forms over Template-driven forms for complex forms, validation, and dynamic controls due to their explicit, immutable, and synchronous nature.
- **No `ngClass` / `NgClass`:** Do not use the `ngClass` directive. Instead, use native `class` bindings for conditional styling.
  - **Bad:**
    ```html
    <section [ngClass]="{'active': isActive}"></section>
    ```
  - **Good:**
    ```html
    <section [class.active]="isActive"></section>
    <section [class]="{'active': isActive}"></section>
    <section [class]="myClasses"></section>
    ```
- **No `ngStyle` / `NgStyle`:** Do not use the `ngStyle` directive. Instead, use native `style` bindings for conditional inline styles.
  - **Bad:**
    ```html
    <section [ngStyle]="{'font-size': fontSize + 'px'}"></section>
    ```
  - **Good:**
    ```html
    <section [style.font-size.px]="fontSize"></section>
    <section [style]="myStyles"></section>
    ```

## State Management

- **Signals for Local State:** Use signals for managing local component state.
- **`computed()` for Derived State:** Leverage `computed()` for any state that can be derived from other signals.
- **Pure and Predictable Transformations:** Ensure state transformations are pure functions (no side effects) and predictable.

## Templates

- **Simple Templates:** Keep templates as simple as possible, avoiding complex logic directly in the template. Delegate complex logic to the component's TypeScript code.
- **Native Control Flow:** Use the new built-in control flow syntax (`@if`, `@for`, `@switch`) instead of the older structural directives (`*ngIf`, `*ngFor`, `*ngSwitch`).
  - **Old Syntax:**
    ```html
    <section *ngIf="isVisible">Content</section>
    <section *ngFor="let item of items">{{ item }}</section>
    ```
  - **New Syntax:**
    ```html
    @if (isVisible) {
    <section>Content</section>
    } @for (item of items; track item.id) {
    <section>{{ item }}</section>
    }
    ```
- **Async Pipe:** Use the `async` pipe to handle observables in templates. This automatically subscribes and unsubscribes, preventing memory leaks.

## Services

- **Single Responsibility:** Design services around a single, well-defined responsibility.
- **`providedIn: 'root'`:** Use the `providedIn: 'root'` option when declaring injectable services to ensure they are singletons and tree-shakable.
- **`inject()` Function:** Prefer the `inject()` function over constructor injection when injecting dependencies, especially within `provide` functions, `computed` properties, or outside of constructor context.
  - **Old Constructor Injection:**
    ```typescript
    constructor(private myService: MyService) {}
    ```
  - **New `inject()` Function:**

    ```typescript
    import { inject } from '@angular/core';

    export class MyComponent {
      private myService = inject(MyService);
      // ...
    }
    ```

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/components/refactoring-tests/complex-components/third-case/product-showcase.component.ts:
--------------------------------------------------------------------------------

```typescript
import { Component, signal } from '@angular/core';
import { ProductCardComponent, Product, ProductBadgeType } from './product-card.component';

@Component({
  selector: 'app-product-showcase',
  standalone: true,
  imports: [ProductCardComponent],
  template: `
    <div class="showcase-container">
      <h2>Product Card Showcase - Moderate Badge Complexity</h2>
      <p>This demonstrates a moderate level of badge complexity that should be more manageable to refactor to DsBadge.</p>
      
      <div class="showcase-grid">
        @for (product of products(); track product.id) {
          <app-product-card
            [product]="product"
            [badgeType]="getBadgeType(product)"
            [showBadge]="shouldShowBadge(product)"
            [animated]="true"
            [compact]="false"
            (productSelected)="onProductSelected($event)"
            (favoriteToggled)="onFavoriteToggled($event)"
            (addToCartClicked)="onAddToCart($event)"
            (quickViewClicked)="onQuickView($event)">
          </app-product-card>
        }
      </div>
      
      <div class="showcase-log">
        <h3>Event Log:</h3>
        <div class="log-entries">
          @for (entry of eventLog(); track $index) {
            <div class="log-entry">{{ entry }}</div>
          }
        </div>
      </div>
    </div>
  `,
  styles: [`
    .showcase-container {
      padding: 2rem;
      max-width: 1200px;
      margin: 0 auto;
    }
    
    .showcase-container h2 {
      color: #1f2937;
      margin-bottom: 1rem;
    }
    
    .showcase-container p {
      color: #6b7280;
      margin-bottom: 2rem;
    }
    
    .showcase-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
      gap: 1.5rem;
      margin-bottom: 2rem;
    }
    
    .showcase-log {
      background: white;
      border-radius: 0.5rem;
      padding: 1.5rem;
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
    }
    
    .showcase-log h3 {
      margin: 0 0 1rem 0;
      color: #1f2937;
      font-size: 1.125rem;
    }
    
    .log-entries {
      max-height: 200px;
      overflow-y: auto;
    }
    
    .log-entry {
      padding: 0.5rem;
      border-bottom: 1px solid #f3f4f6;
      font-size: 0.875rem;
      color: #374151;
      font-family: monospace;
    }
    
    .log-entry:last-child {
      border-bottom: none;
    }
  `]
})
export class ProductShowcaseComponent {
  eventLog = signal<string[]>([]);
  
  products = signal<Product[]>([
    {
      id: 'prod-1',
      name: 'Premium Wireless Headphones',
      price: 199.99,
      originalPrice: 249.99,
      category: 'Electronics',
      rating: 4.5,
      reviewCount: 128,
      inStock: true,
      imageUrl: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=300&h=200&fit=crop',
      tags: ['wireless', 'premium', 'noise-canceling']
    },
    {
      id: 'prod-2',
      name: 'Smart Fitness Watch',
      price: 299.99,
      category: 'Wearables',
      rating: 4.8,
      reviewCount: 256,
      inStock: true,
      imageUrl: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=300&h=200&fit=crop',
      tags: ['fitness', 'smart', 'waterproof', 'gps']
    },
    {
      id: 'prod-3',
      name: 'Professional Camera Lens',
      price: 899.99,
      category: 'Photography',
      rating: 4.9,
      reviewCount: 89,
      inStock: true,
      imageUrl: 'https://images.unsplash.com/photo-1606983340126-99ab4feaa64a?w=300&h=200&fit=crop',
      tags: ['professional', 'telephoto', 'canon']
    },
    {
      id: 'prod-4',
      name: 'Gaming Mechanical Keyboard',
      price: 149.99,
      originalPrice: 179.99,
      category: 'Gaming',
      rating: 4.6,
      reviewCount: 342,
      inStock: false,
      imageUrl: 'https://images.unsplash.com/photo-1541140532154-b024d705b90a?w=300&h=200&fit=crop',
      tags: ['mechanical', 'rgb', 'gaming', 'cherry-mx']
    },
    {
      id: 'prod-5',
      name: 'Eco-Friendly Water Bottle',
      price: 24.99,
      category: 'Lifestyle',
      rating: 4.3,
      reviewCount: 67,
      inStock: true,
      imageUrl: 'https://images.unsplash.com/photo-1602143407151-7111542de6e8?w=300&h=200&fit=crop',
      tags: ['eco-friendly', 'stainless-steel', 'insulated']
    },
    {
      id: 'prod-6',
      name: 'Designer Laptop Backpack',
      price: 79.99,
      originalPrice: 99.99,
      category: 'Accessories',
      rating: 4.4,
      reviewCount: 156,
      inStock: true,
      imageUrl: 'https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=300&h=200&fit=crop',
      tags: ['designer', 'laptop', 'travel', 'waterproof']
    }
  ]);

  getBadgeType(product: Product): ProductBadgeType {
    // Logic to determine badge type based on product characteristics
    if (product.originalPrice && product.originalPrice > product.price) {
      return 'sale';
    }
    if (product.rating >= 4.8) {
      return 'bestseller';
    }
    if (!product.inStock) {
      return 'limited';
    }
    if (product.tags.includes('new') || Date.now() % 2 === 0) { // Simulate new products
      return 'new';
    }
    return 'sale';
  }

  shouldShowBadge(product: Product): boolean {
    // Show badge for sale items, high-rated items, or out of stock
    return !!(product.originalPrice && product.originalPrice > product.price) ||
           product.rating >= 4.7 ||
           !product.inStock;
  }

  onProductSelected(product: Product) {
    this.addLogEntry(`Product selected: ${product.name}`);
  }

  onFavoriteToggled(event: {product: Product, favorited: boolean}) {
    this.addLogEntry(`${event.product.name} ${event.favorited ? 'added to' : 'removed from'} favorites`);
  }

  onAddToCart(product: Product) {
    this.addLogEntry(`Added to cart: ${product.name} - $${product.price.toFixed(2)}`);
  }

  onQuickView(product: Product) {
    this.addLogEntry(`Quick view opened: ${product.name}`);
  }

  private addLogEntry(message: string) {
    const timestamp = new Date().toLocaleTimeString();
    const entry = `[${timestamp}] ${message}`;
    this.eventLog.update(log => [entry, ...log.slice(0, 49)]);
  }
} 
```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/bad-global-styles.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/base/base.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/components/components.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/layout/layout.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/themes/themes.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/minimal-repo/packages/application/src/app/styles/utilities/utilities.scss:
--------------------------------------------------------------------------------

```scss
// Extended and more meaningful classes
.pill-with-badge {
  color: red;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 15px;
  display: inline-block;
}

.pill-with-badge-v2 {
  color: blue;
  border: 2px solid #aaa;
  padding: 6px 12px;
  border-radius: 20px;
  display: inline-block;
}

.sports-pill {
  color: green;
  background-color: #f0f0f0;
  padding: 8px 16px;
  border-radius: 25px;
  display: inline-block;
}

.offer-badge {
  color: yellow;
  background-color: #333;
  padding: 4px 8px;
  border-radius: 10px;
  display: inline-block;
}

.tab-nav {
  color: orange;
  background-color: #fff;
  padding: 10px;
  border-bottom: 2px solid #ddd;
}

.nav-tabs {
  color: purple;
  background-color: #eee;
  padding: 10px;
  border-bottom: 2px solid #ccc;
}

.tab-nav-item {
  color: pink;
  padding: 10px 15px;
  border-radius: 5px;
  display: inline-block;
  cursor: pointer;
}

.btn {
  color: brown;
  background-color: #f5f5f5;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.btn-primary {
  color: cyan;
  background-color: #007bff;
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}

.legacy-button {
  color: magenta;
  background-color: #f8f9fa;
  padding: 10px 20px;
  border: 1px solid #ccc;
  border-radius: 5px;
  cursor: pointer;
}

.modal {
  color: lime;
  background-color: #fff;
  padding: 20px;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

.card {
  color: olive;
  background-color: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.loading {
  color: teal;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v2 {
  color: navy;
  font-size: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-v3 {
  color: maroon;
  font-size: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.collapsible-container {
  color: silver;
  background-color: #f0f0f0;
  padding: 10px;
  border-radius: 5px;
  overflow: hidden;
}

.divider {
  color: gray;
  border-top: 1px solid #ccc;
  margin: 10px 0;
}

.count {
  color: gold;
  background-color: #333;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.badge-circle {
  color: coral;
  background-color: #f0f0f0;
  padding: 5px 10px;
  border-radius: 50%;
  display: inline-block;
}

.custom-control-checkbox {
  color: khaki;
  display: flex;
  align-items: center;
}

.custom-control-radio {
  color: lavender;
  display: flex;
  align-items: center;
}

.form-control-tabs-segmented-v2 {
  color: salmon;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-flex {
  color: sienna;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v2-dark {
  color: tan;
  background-color: #333;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v3 {
  color: turquoise;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented-v4 {
  color: violet;
  background-color: #f8f9fa;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.form-control-tabs-segmented {
  color: wheat;
  background-color: #fff;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  justify-content: space-between;
}

.custom-control-switcher {
  color: azure;
  display: flex;
  align-items: center;
}

// 50 more random classes
.random-class-1 {
  background-color: #f0f0f0;
}
.random-class-2 {
  background-color: #e0e0e0;
}
.random-class-3 {
  background-color: #d0d0d0;
}
.random-class-4 {
  background-color: #c0c0c0;
}
.random-class-5 {
  background-color: #b0b0b0;
}
.random-class-6 {
  background-color: #a0a0a0;
}
.random-class-7 {
  background-color: #909090;
}
.random-class-8 {
  background-color: #808080;
}
.random-class-9 {
  background-color: #707070;
}
.random-class-10 {
  background-color: #606060;
}
.random-class-11 {
  background-color: #505050;
}
.random-class-12 {
  background-color: #404040;
}
.random-class-13 {
  background-color: #303030;
}
.random-class-14 {
  background-color: #202020;
}
.random-class-15 {
  background-color: #101010;
}
.random-class-16 {
  background-color: #f8f8f8;
}
.random-class-17 {
  background-color: #e8e8e8;
}
.random-class-18 {
  background-color: #d8d8d8;
}
.random-class-19 {
  background-color: #c8c8c8;
}
.random-class-20 {
  background-color: #b8b8b8;
}
.random-class-21 {
  background-color: #a8a8a8;
}
.random-class-22 {
  background-color: #989898;
}
.random-class-23 {
  background-color: #888888;
}
.random-class-24 {
  background-color: #787878;
}
.random-class-25 {
  background-color: #686868;
}
.random-class-26 {
  background-color: #585858;
}
.random-class-27 {
  background-color: #484848;
}
.random-class-28 {
  background-color: #383838;
}
.random-class-29 {
  background-color: #282828;
}
.random-class-30 {
  background-color: #181818;
}
.random-class-31 {
  background-color: #080808;
}
.random-class-32 {
  background-color: #fefefe;
}
.random-class-33 {
  background-color: #ededed;
}
.random-class-34 {
  background-color: #dcdcdc;
}
.random-class-35 {
  background-color: #cbcbcb;
}
.random-class-36 {
  background-color: #bababa;
}
.random-class-37 {
  background-color: #a9a9a9;
}
.random-class-38 {
  background-color: #989898;
}
.random-class-39 {
  background-color: #878787;
}
.random-class-40 {
  background-color: #767676;
}
.random-class-41 {
  background-color: #656565;
}
.random-class-42 {
  background-color: #545454;
}
.random-class-43 {
  background-color: #434343;
}
.random-class-44 {
  background-color: #323232;
}
.random-class-45 {
  background-color: #212121;
}
.random-class-46 {
  background-color: #101010;
}
.random-class-47 {
  background-color: #f7f7f7;
}
.random-class-48 {
  background-color: #e6e6e6;
}
.random-class-49 {
  background-color: #d5d5d5;
}
.random-class-50 {
  background-color: #c4c4c4;
}

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/component/get-ds-component-data.tool.ts:
--------------------------------------------------------------------------------

```typescript
import { ToolSchemaOptions } from '@push-based/models';
import {
  createHandler,
  BaseHandlerOptions,
} from '../shared/utils/handler-helpers.js';
import { COMMON_ANNOTATIONS } from '../shared/models/schema-helpers.js';
import { getComponentPathsInfo } from './utils/paths-helpers.js';
import { getComponentDocPathsForName } from './utils/doc-helpers.js';
import {
  validateComponentName,
  componentNameToKebabCase,
} from '../shared/utils/component-validation.js';
import { resolveCrossPlatformPath } from '../shared/utils/cross-platform-path.js';
import * as fs from 'fs';
import * as path from 'path';

interface DsComponentDataOptions extends BaseHandlerOptions {
  componentName: string;
  sections?: string[];
}

interface DsComponentData {
  componentName: string;
  implementation: string[];
  documentation: string[];
  stories: string[];
  importPath: string;
}

export const getDsComponentDataToolSchema: ToolSchemaOptions = {
  name: 'get-ds-component-data',
  description: `Return comprehensive data for a DS component including implementation files, documentation files, stories files, and import path.`,
  inputSchema: {
    type: 'object',
    properties: {
      componentName: {
        type: 'string',
        description:
          'The class name of the component to get data for (e.g., DsBadge)',
      },
      sections: {
        type: 'array',
        items: {
          type: 'string',
          enum: ['implementation', 'documentation', 'stories', 'all'],
        },
        description:
          'Sections to include in the response. Options: "implementation", "documentation", "stories", "all". Defaults to ["all"] if not specified.',
        default: ['all'],
      },
    },
    required: ['componentName'],
  },
  annotations: {
    title: 'Get Design System Component Data',
    ...COMMON_ANNOTATIONS.readOnly,
  },
};

function getAllFilesInDirectory(dirPath: string): string[] {
  const files: string[] = [];

  function walkDirectory(currentPath: string) {
    try {
      const items = fs.readdirSync(currentPath);

      for (const item of items) {
        const fullPath = path.join(currentPath, item);
        const stat = fs.statSync(fullPath);

        if (stat.isDirectory()) {
          walkDirectory(fullPath);
        } else {
          files.push(fullPath);
        }
      }
    } catch {
      return;
    }
  }

  if (fs.existsSync(dirPath)) {
    walkDirectory(dirPath);
  }

  return files;
}

function findStoriesFiles(componentPath: string): string[] {
  const storiesFiles: string[] = [];

  try {
    if (fs.existsSync(componentPath)) {
      const items = fs.readdirSync(componentPath);

      for (const item of items) {
        const fullPath = path.join(componentPath, item);
        const stat = fs.statSync(fullPath);

        if (stat.isFile() && item.endsWith('.stories.ts')) {
          storiesFiles.push(fullPath);
        }
      }
    }
  } catch {
    return storiesFiles;
  }

  return storiesFiles;
}

export const getDsComponentDataHandler = createHandler<
  DsComponentDataOptions,
  DsComponentData
>(
  getDsComponentDataToolSchema.name,
  async (
    { componentName, sections = ['all'] },
    { cwd, uiRoot, storybookDocsRoot },
  ) => {
    try {
      validateComponentName(componentName);

      const includeAll = sections.includes('all');
      const includeImplementation =
        includeAll || sections.includes('implementation');
      const includeDocumentation =
        includeAll || sections.includes('documentation');
      const includeStories = includeAll || sections.includes('stories');

      const pathsInfo = getComponentPathsInfo(componentName, uiRoot, cwd);

      let implementationFiles: string[] = [];
      if (includeImplementation) {
        const srcFiles = getAllFilesInDirectory(pathsInfo.srcPath);
        implementationFiles = srcFiles.map((file) => `file://${file}`);
      }

      const documentationFiles: string[] = [];

      let storiesFilePaths: string[] = [];
      if (storybookDocsRoot) {
        const docsBasePath = resolveCrossPlatformPath(cwd, storybookDocsRoot);

        if (includeDocumentation) {
          const docPaths = getComponentDocPathsForName(
            docsBasePath,
            componentName,
          );

          if (fs.existsSync(docPaths.paths.api)) {
            documentationFiles.push(`file://${docPaths.paths.api}`);
          }
          if (fs.existsSync(docPaths.paths.overview)) {
            documentationFiles.push(`file://${docPaths.paths.overview}`);
          }
        }

        if (includeStories) {
          const componentFolderName = componentNameToKebabCase(componentName);
          const storiesComponentFolderPath = path.join(
            docsBasePath,
            componentFolderName,
          );
          const storiesFiles = findStoriesFiles(storiesComponentFolderPath);
          storiesFilePaths = storiesFiles.map((file) => `file://${file}`);
        }
      }

      return {
        componentName,
        implementation: implementationFiles,
        documentation: documentationFiles,
        stories: storiesFilePaths,
        importPath: pathsInfo.importPath,
      };
    } catch (ctx) {
      throw new Error(
        `Error retrieving component data: ${(ctx as Error).message}`,
      );
    }
  },
  (result) => {
    const messages: string[] = [];

    if (result.implementation && result.implementation.length > 0) {
      messages.push('Implementation');
      messages.push('');
      result.implementation.forEach((file: string) => {
        messages.push(file);
      });
      messages.push('');
    }

    if (result.documentation && result.documentation.length > 0) {
      messages.push('Documentation');
      messages.push('');
      result.documentation.forEach((file: string) => {
        messages.push(file);
      });
      messages.push('');
    }

    if (result.stories && result.stories.length > 0) {
      messages.push('Stories');
      messages.push('');
      result.stories.forEach((file: string) => {
        messages.push(file);
      });
      messages.push('');
    }

    if (result.importPath) {
      messages.push('Import path');
      messages.push('');
      messages.push(result.importPath);
    }

    return messages;
  },
);

export const getDsComponentDataTools = [
  {
    schema: getDsComponentDataToolSchema,
    handler: getDsComponentDataHandler,
  },
];

```

--------------------------------------------------------------------------------
/packages/angular-mcp-server/src/lib/tools/ds/project/utils/dependencies-helpers.ts:
--------------------------------------------------------------------------------

```typescript
import * as fs from 'fs';
import * as path from 'path';
import process from 'node:process';
import { getComponentPathsInfo } from '../../component/utils/paths-helpers.js';
import { resolveCrossPlatformPathAndValidateWithContext } from '../../shared/utils/cross-platform-path.js';

// Type definitions
export interface PackageJsonPeerDependencies {
  [packageName: string]: string;
}

export interface PackageJson {
  name?: string;
  version?: string;
  peerDependencies?: PackageJsonPeerDependencies;
  dependencies?: Record<string, string>;
  devDependencies?: Record<string, string>;
  [key: string]: unknown;
}

export interface ProjectAnalysisResult {
  packageJsonFound: true;
  packageJsonPath: string;
  projectJsonPath: string | null;
  isPublishable: boolean;
  peerDependencies: PackageJsonPeerDependencies;
  peerDependencyMissing: boolean;
  importPath?: string;
  message?: string;
  suggestedChange?: {
    importPath: string;
    message: string;
  };
}

export interface ProjectAnalysisNotFoundResult {
  packageJsonFound: false;
  searchedPath: string;
  message: string;
}

export type ProjectAnalysisResponse =
  | ProjectAnalysisResult
  | ProjectAnalysisNotFoundResult;

export interface ComponentMetadata {
  importPath?: string;
  [key: string]: unknown;
}

/**
 * Finds package.json by traversing up the directory tree
 */
export function findPackageJson(startPath: string): string | null {
  let currentPath = path.resolve(startPath);
  const rootPath = path.parse(currentPath).root;

  while (currentPath !== rootPath) {
    const packageJsonPath = path.join(currentPath, 'package.json');

    if (fs.existsSync(packageJsonPath)) {
      return packageJsonPath;
    }

    currentPath = path.dirname(currentPath);
  }

  return null;
}

/**
 * Finds project.json in the same directory as package.json or nearby
 */
export function findProjectJson(packageJsonDir: string): string | null {
  const projectJsonPath = path.join(packageJsonDir, 'project.json');

  if (fs.existsSync(projectJsonPath)) {
    return projectJsonPath;
  }

  return null;
}

/**
 * Reads and parses package.json file
 */
export function readPackageJson(packageJsonPath: string): PackageJson {
  try {
    const content = fs.readFileSync(packageJsonPath, 'utf-8');
    return JSON.parse(content) as PackageJson;
  } catch (ctx) {
    throw new Error(
      `Failed to read or parse package.json at ${packageJsonPath}: ${
        (ctx as Error).message
      }`,
    );
  }
}

/**
 * Checks if the library has peer dependencies (indicating it's buildable/publishable)
 */
export function hasPeerDependencies(packageJson: PackageJson): boolean {
  return (
    packageJson.peerDependencies !== undefined &&
    typeof packageJson.peerDependencies === 'object' &&
    Object.keys(packageJson.peerDependencies).length > 0
  );
}

/**
 * Gets import path from component metadata
 */
export async function getComponentImportPath(
  componentName: string,
  cwd: string,
  uiRoot: string,
): Promise<string | null> {
  try {
    const pathsInfo = getComponentPathsInfo(componentName, uiRoot, cwd);
    return pathsInfo.importPath || null;
  } catch {
    return null;
  }
}

/**
 * Builds the base project analysis result from package.json and project.json
 */
export function buildProjectAnalysisResult(
  cwd: string,
  packageJsonPath: string,
  packageJson: PackageJson,
): ProjectAnalysisResult {
  const packageJsonDir = path.dirname(packageJsonPath);
  const hasPackagePeerDeps = hasPeerDependencies(packageJson);
  const projectJsonPath = findProjectJson(packageJsonDir);

  return {
    packageJsonFound: true,
    packageJsonPath: path.relative(cwd, packageJsonPath),
    projectJsonPath: projectJsonPath
      ? path.relative(cwd, projectJsonPath)
      : null,
    isPublishable: hasPackagePeerDeps,
    peerDependencies: packageJson.peerDependencies || {},
    peerDependencyMissing: false,
  };
}

/**
 * Handles peer dependencies analysis and component import path validation
 */
export async function handlePeerDependenciesAnalysis(
  result: ProjectAnalysisResult,
  componentName?: string,
  cwd?: string,
  uiRoot?: string,
): Promise<void> {
  if (!result.isPublishable) {
    result.message =
      'Library has no peer dependencies - appears to be a normal library';
    return;
  }

  if (!componentName) {
    result.message =
      'Library has peer dependencies (publishable/buildable). Provide componentName to validate import path.';
    return;
  }

  if (!cwd) {
    result.message = 'CWD is required for component import path validation.';
    return;
  }

  if (!uiRoot) {
    result.message =
      'UI root is required for component import path validation.';
    return;
  }

  // Try to get import path for the component
  const importPath = await getComponentImportPath(componentName, cwd, uiRoot);

  if (!importPath || importPath.trim() === '') {
    result.peerDependencyMissing = true;
    result.suggestedChange = {
      importPath: '*',
      message:
        'Component import path is missing or empty. This is required for publishable libraries.',
    };
  } else {
    result.importPath = importPath;
    result.message =
      'Component import path found - library appears properly configured';
  }
}

/**
 * Analyzes project dependencies and determines if library is buildable/publishable
 */
export async function analyzeProjectDependencies(
  cwd: string,
  directory: string,
  componentName?: string,
  workspaceRoot?: string,
  uiRoot?: string,
): Promise<ProjectAnalysisResponse> {
  // Parameter validation
  if (!directory || typeof directory !== 'string') {
    throw new Error('Directory parameter is required and must be a string');
  }

  // Set working directory
  process.chdir(cwd);

  // Validate target path exists
  const targetPath = resolveCrossPlatformPathAndValidateWithContext(
    cwd,
    directory,
    workspaceRoot,
  );

  // Find package.json
  const packageJsonPath = findPackageJson(targetPath);

  if (!packageJsonPath) {
    return {
      packageJsonFound: false,
      searchedPath: targetPath,
      message: 'No package.json found in the directory tree',
    };
  }

  // Read and parse package.json
  const packageJson = readPackageJson(packageJsonPath);

  // Build base result
  const result = buildProjectAnalysisResult(cwd, packageJsonPath, packageJson);

  // Handle peer dependencies analysis
  await handlePeerDependenciesAnalysis(result, componentName, cwd, uiRoot);

  return result;
}

```
Page 4/7FirstPrevNextLast