diff --git a/cockpit/langgraph/streaming/angular/project.json b/cockpit/langgraph/streaming/angular/project.json index c72120c6e..9664fc7d7 100644 --- a/cockpit/langgraph/streaming/angular/project.json +++ b/cockpit/langgraph/streaming/angular/project.json @@ -2,16 +2,51 @@ "name": "cockpit-langgraph-streaming-angular", "$schema": "../../../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "cockpit/langgraph/streaming/angular/src", - "projectType": "library", + "projectType": "application", "targets": { "build": { - "executor": "@nx/js:tsc", - "outputs": ["{workspaceRoot}/dist/cockpit/langgraph/streaming/angular"], + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], "options": { "outputPath": "dist/cockpit/langgraph/streaming/angular", - "main": "cockpit/langgraph/streaming/angular/src/index.ts", - "tsConfig": "cockpit/langgraph/streaming/angular/tsconfig.json" - } + "index": "cockpit/langgraph/streaming/angular/src/index.html", + "browser": "cockpit/langgraph/streaming/angular/src/main.ts", + "tsConfig": "cockpit/langgraph/streaming/angular/tsconfig.app.json", + "styles": ["cockpit/langgraph/streaming/angular/src/styles.css"] + }, + "configurations": { + "production": { + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "fileReplacements": [ + { + "replace": "cockpit/langgraph/streaming/angular/src/environments/environment.ts", + "with": "cockpit/langgraph/streaming/angular/src/environments/environment.development.ts" + } + ] + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "port": 4300, + "proxyConfig": "cockpit/langgraph/streaming/angular/proxy.conf.json" + }, + "configurations": { + "production": { + "buildTarget": "cockpit-langgraph-streaming-angular:build:production" + }, + "development": { + "buildTarget": "cockpit-langgraph-streaming-angular:build:development" + } + }, + "defaultConfiguration": "development" }, "smoke": { "executor": "nx:run-commands", diff --git a/cockpit/langgraph/streaming/angular/src/app.component.ts b/cockpit/langgraph/streaming/angular/src/app.component.ts deleted file mode 100644 index 51879bf97..000000000 --- a/cockpit/langgraph/streaming/angular/src/app.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, inject, Injector, OnInit } from '@angular/core'; -import { runInInjectionContext } from '@angular/core'; -import { - ChatComponent, - ChatMessagesComponent, - ChatInputComponent, - ChatTypingIndicatorComponent, -} from '@cacheplane/chat'; -import { streamResource, StreamResourceRef } from '@cacheplane/stream-resource'; - -@Component({ - selector: 'app-streaming', - standalone: true, - imports: [ - ChatComponent, - ChatMessagesComponent, - ChatInputComponent, - ChatTypingIndicatorComponent, - ], - template: ` -
- - - - - -
- `, -}) -export class StreamingAppComponent implements OnInit { - private readonly injector = inject(Injector); - chat!: StreamResourceRef; - - ngOnInit(): void { - runInInjectionContext(this.injector, () => { - this.chat = streamResource({ assistantId: 'chat_agent' }); - }); - } -} diff --git a/cockpit/langgraph/streaming/angular/src/app.config.ts b/cockpit/langgraph/streaming/angular/src/app.config.ts deleted file mode 100644 index 6ac3b924c..000000000 --- a/cockpit/langgraph/streaming/angular/src/app.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 -import { ApplicationConfig } from '@angular/core'; -import { provideStreamResource } from '@cacheplane/stream-resource'; -import { provideChat } from '@cacheplane/chat'; - -export const appConfig: ApplicationConfig = { - providers: [ - provideStreamResource({ - apiUrl: 'http://localhost:2024', - }), - provideChat({}), - ], -}; diff --git a/cockpit/langgraph/streaming/angular/src/app/app.config.ts b/cockpit/langgraph/streaming/angular/src/app/app.config.ts index 8eb40c712..b52a916ac 100644 --- a/cockpit/langgraph/streaming/angular/src/app/app.config.ts +++ b/cockpit/langgraph/streaming/angular/src/app/app.config.ts @@ -1,18 +1,12 @@ +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { ApplicationConfig } from '@angular/core'; import { provideStreamResource } from '@cacheplane/stream-resource'; +import { provideChat } from '@cacheplane/chat'; import { environment } from '../environments/environment'; -/** - * Application configuration for the LangGraph Streaming demo. - * - * Uses `provideStreamResource()` to set the global LangGraph API URL. - * All `streamResource()` calls in this app inherit this URL unless - * overridden at the call site. - */ export const appConfig: ApplicationConfig = { providers: [ - provideStreamResource({ - apiUrl: environment.langGraphApiUrl, - }), + provideStreamResource({ apiUrl: environment.langGraphApiUrl }), + provideChat({}), ], }; diff --git a/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts b/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts index 5d4b8bd06..4de25f813 100644 --- a/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts +++ b/cockpit/langgraph/streaming/angular/src/app/streaming.component.ts @@ -1,47 +1,25 @@ +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { Component } from '@angular/core'; import { ChatComponent } from '@cacheplane/chat'; import { streamResource } from '@cacheplane/stream-resource'; import { environment } from '../environments/environment'; /** - * StreamingComponent demonstrates real-time LLM streaming with `streamResource()`. + * Streaming demo — simplest possible @cacheplane/chat integration. * - * Uses the shared `@cacheplane/chat` component for the chat UI. - * This is the simplest example — just streaming messages with no - * additional capability features (no threads, interrupts, etc.). - * - * Key integration points: - * - `streamResource()` creates a Signal-based streaming ref - * - `stream.messages()` provides reactive access to the conversation - * - `stream.submit()` fires a message to the LangGraph backend - * - `stream.isLoading()` tracks whether a response is in progress + * Creates a streamResource ref and passes it to the prebuilt + * composition. The composition handles message rendering, input, typing + * indicator, and error display internally. */ @Component({ selector: 'app-streaming', standalone: true, imports: [ChatComponent], - template: ` - - `, + template: ``, }) export class StreamingComponent { - /** - * The streaming resource ref — connects to the LangGraph Cloud backend. - */ protected readonly stream = streamResource({ apiUrl: environment.langGraphApiUrl, assistantId: environment.streamingAssistantId, }); - - /** - * Submits the user's message to the LangGraph streaming endpoint. - */ - send(text: string): void { - this.stream.submit({ messages: [{ role: 'human', content: text }] }); - } } diff --git a/cockpit/langgraph/streaming/angular/src/environments/environment.development.ts b/cockpit/langgraph/streaming/angular/src/environments/environment.development.ts index 41e02a946..fa1459bf2 100644 --- a/cockpit/langgraph/streaming/angular/src/environments/environment.development.ts +++ b/cockpit/langgraph/streaming/angular/src/environments/environment.development.ts @@ -6,6 +6,6 @@ */ export const environment = { production: false, - langGraphApiUrl: 'http://localhost:4300/api', + langGraphApiUrl: '/api', streamingAssistantId: 'streaming', }; diff --git a/cockpit/langgraph/streaming/angular/src/index.html b/cockpit/langgraph/streaming/angular/src/index.html index 0d8fdfa2c..968fea49d 100644 --- a/cockpit/langgraph/streaming/angular/src/index.html +++ b/cockpit/langgraph/streaming/angular/src/index.html @@ -2,11 +2,12 @@ - Streaming - LangGraph Angular Example + LangGraph Streaming — Angular + - + diff --git a/cockpit/langgraph/streaming/angular/src/main.ts b/cockpit/langgraph/streaming/angular/src/main.ts index 1bc6a1a3d..aed8e4d3e 100644 --- a/cockpit/langgraph/streaming/angular/src/main.ts +++ b/cockpit/langgraph/streaming/angular/src/main.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 import { bootstrapApplication } from '@angular/platform-browser'; -import { appConfig } from './app.config'; -import { StreamingAppComponent } from './app.component'; +import { appConfig } from './app/app.config'; +import { StreamingComponent } from './app/streaming.component'; -bootstrapApplication(StreamingAppComponent, appConfig).catch(console.error); +bootstrapApplication(StreamingComponent, appConfig).catch(console.error); diff --git a/cockpit/langgraph/streaming/angular/tsconfig.app.json b/cockpit/langgraph/streaming/angular/tsconfig.app.json index 5d05a9e61..64731b107 100644 --- a/cockpit/langgraph/streaming/angular/tsconfig.app.json +++ b/cockpit/langgraph/streaming/angular/tsconfig.app.json @@ -2,7 +2,9 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../../../dist/out-tsc", - "types": [] + "lib": ["es2022", "dom"], + "types": [], + "emitDeclarationOnly": false }, "files": ["src/main.ts"], "include": ["src/**/*.ts"] diff --git a/docs/superpowers/plans/2026-04-05-chat-ui-redesign.md b/docs/superpowers/plans/2026-04-05-chat-ui-redesign.md new file mode 100644 index 000000000..31dff712e --- /dev/null +++ b/docs/superpowers/plans/2026-04-05-chat-ui-redesign.md @@ -0,0 +1,849 @@ +# Chat UI Redesign Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Redesign @cacheplane/chat compositions with Apple-clean aesthetics, neutral gray palette, CSS custom property theming, light/dark mode support, and responsive layout. + +**Architecture:** New `chat-theme.css` defines all CSS custom properties with dark defaults and light mode overrides via `prefers-color-scheme`. All compositions reference theme vars instead of hardcoded Tailwind colors. The `` selector replaces `chat-ui`. Template override mechanism lets developers project `chatMessageTemplate` directives to replace defaults. + +**Tech Stack:** Angular 21, Tailwind CSS (utility classes referencing CSS vars), CSS custom properties + +**Spec:** `docs/superpowers/specs/2026-04-05-chat-ui-redesign.md` + +--- + +## File Structure + +``` +libs/chat/src/lib/ + styles/ + chat-theme.css # NEW — CSS custom properties + dark/light + compositions/ + chat/chat.component.ts # REWRITE — new template, selector chat → chat + chat-interrupt-panel/...component.ts # RESTYLE — theme vars + chat-tool-call-card/...component.ts # RESTYLE — theme vars + chat-subagent-card/...component.ts # RESTYLE — theme vars + chat-debug/chat-debug.component.ts # RESTYLE — theme vars + primitives/ + chat-input/chat-input.component.ts # RESTYLE — pill input + chat-typing-indicator/...component.ts # RESTYLE — dot animation + chat-error/...component.ts # RESTYLE — themed banner +cockpit/langgraph/streaming/angular/ + src/app/streaming.component.ts # UPDATE — chat-ui → chat +``` + +--- + +### Task 1: Create Theme CSS File + +**Files:** +- Create: `libs/chat/src/lib/styles/chat-theme.css` + +- [ ] **Step 1: Create the theme CSS file** + +Create `libs/chat/src/lib/styles/chat-theme.css`: + +```css +/* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 */ + +/* + * @cacheplane/chat theme system + * + * All visual properties are exposed as CSS custom properties. + * Override any property at your app level to customize. + * + * Dark mode is the default. Light mode activates via: + * - prefers-color-scheme: light (automatic) + * - [data-chat-theme="light"] attribute (manual) + */ + +:host { + /* Surfaces */ + --chat-bg: #171717; + --chat-bg-alt: #222222; + --chat-bg-hover: #2a2a2a; + + /* Text */ + --chat-text: #e0e0e0; + --chat-text-muted: #777777; + --chat-text-placeholder: #666666; + + /* Borders */ + --chat-border: #333333; + --chat-border-light: #2a2a2a; + + /* User messages */ + --chat-user-bg: #2a2a2a; + --chat-user-text: #f5f5f5; + --chat-user-border: #333333; + + /* Avatar */ + --chat-avatar-bg: #333333; + --chat-avatar-text: #aaaaaa; + + /* Input */ + --chat-input-bg: #222222; + --chat-input-border: #333333; + --chat-input-focus-border: #555555; + --chat-send-bg: #444444; + --chat-send-text: #aaaaaa; + + /* Status */ + --chat-error-bg: #2d1515; + --chat-error-text: #f87171; + --chat-warning-bg: #2d2315; + --chat-warning-text: #fbbf24; + --chat-success: #4ade80; + + /* Geometry */ + --chat-radius-message: 20px; + --chat-radius-input: 24px; + --chat-radius-card: 12px; + --chat-radius-avatar: 8px; + --chat-max-width: 720px; + + /* Typography */ + --chat-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif; + --chat-font-size: 15px; + --chat-line-height: 1.6; + + font-family: var(--chat-font-family); + font-size: var(--chat-font-size); + line-height: var(--chat-line-height); + color: var(--chat-text); + background: var(--chat-bg); +} + +/* Light mode — automatic via system preference */ +@media (prefers-color-scheme: light) { + :host:not([data-chat-theme="dark"]) { + --chat-bg: #ffffff; + --chat-bg-alt: #f5f5f5; + --chat-bg-hover: #ebebeb; + + --chat-text: #1a1a1a; + --chat-text-muted: #999999; + --chat-text-placeholder: #999999; + + --chat-border: #e5e5e5; + --chat-border-light: #f0f0f0; + + --chat-user-bg: #f0f0f0; + --chat-user-text: #1a1a1a; + --chat-user-border: transparent; + + --chat-avatar-bg: #f0f0f0; + --chat-avatar-text: #666666; + + --chat-input-bg: #f5f5f5; + --chat-input-border: #e5e5e5; + --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; + --chat-send-text: #999999; + + --chat-error-bg: #fef2f2; + --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; + --chat-warning-text: #d97706; + --chat-success: #16a34a; + } +} + +/* Light mode — manual override */ +:host([data-chat-theme="light"]) { + --chat-bg: #ffffff; + --chat-bg-alt: #f5f5f5; + --chat-bg-hover: #ebebeb; + + --chat-text: #1a1a1a; + --chat-text-muted: #999999; + --chat-text-placeholder: #999999; + + --chat-border: #e5e5e5; + --chat-border-light: #f0f0f0; + + --chat-user-bg: #f0f0f0; + --chat-user-text: #1a1a1a; + --chat-user-border: transparent; + + --chat-avatar-bg: #f0f0f0; + --chat-avatar-text: #666666; + + --chat-input-bg: #f5f5f5; + --chat-input-border: #e5e5e5; + --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; + --chat-send-text: #999999; + + --chat-error-bg: #fef2f2; + --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; + --chat-warning-text: #d97706; + --chat-success: #16a34a; +} + +/* Typing indicator animation */ +@keyframes chat-dot-pulse { + 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } + 40% { opacity: 1; transform: scale(1); } +} +``` + +- [ ] **Step 2: Commit** + +```bash +git add libs/chat/src/lib/styles/chat-theme.css +git commit -m "feat(chat): add CSS custom property theme system with dark/light modes" +``` + +--- + +### Task 2: Redesign `` Composition (selector `chat-ui` → `chat`) + +**Files:** +- Modify: `libs/chat/src/lib/compositions/chat/chat.component.ts` + +- [ ] **Step 1: Rewrite the component** + +Replace the full contents of `libs/chat/src/lib/compositions/chat/chat.component.ts`: + +```typescript +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import { + Component, + contentChildren, + input, + output, + ChangeDetectionStrategy, +} from '@angular/core'; +import type { StreamResourceRef } from '@cacheplane/stream-resource'; +import { ChatMessagesComponent } from '../../primitives/chat-messages/chat-messages.component'; +import { MessageTemplateDirective } from '../../primitives/chat-messages/message-template.directive'; +import { ChatInputComponent } from '../../primitives/chat-input/chat-input.component'; +import { ChatTypingIndicatorComponent } from '../../primitives/chat-typing-indicator/chat-typing-indicator.component'; +import { ChatErrorComponent } from '../../primitives/chat-error/chat-error.component'; +import { ChatInterruptComponent } from '../../primitives/chat-interrupt/chat-interrupt.component'; +import { ChatThreadListComponent, Thread } from '../../primitives/chat-thread-list/chat-thread-list.component'; +import { messageContent } from '../shared/message-utils'; + +@Component({ + selector: 'chat', + standalone: true, + imports: [ + ChatMessagesComponent, + MessageTemplateDirective, + ChatInputComponent, + ChatTypingIndicatorComponent, + ChatErrorComponent, + ChatInterruptComponent, + ChatThreadListComponent, + ], + changeDetection: ChangeDetectionStrategy.OnPush, + styleUrls: ['../../styles/chat-theme.css'], + styles: [` + :host { + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; + } + `], + template: ` +
+ + @if (threads().length > 0) { +
+
+

Threads

+
+ + + + + +
+ } + + +
+ +
+
+
+ + + +
+
{{ messageContent(message) }}
+
+
+ + + +
+
+
+
A
+ Assistant +
+
{{ messageContent(message) }}
+
+
+
+ + + +
+
{{ messageContent(message) }}
+
+
+ + + +
+
{{ messageContent(message) }}
+
+
+
+ + + +
+
+
+ + + + +
+

Agent paused: {{ interrupt.value }}

+
+
+
+ + + + + +
+
+ +
+
+
+
+ `, +}) +export class ChatComponent { + readonly ref = input.required>(); + readonly threads = input([]); + readonly activeThreadId = input(''); + readonly threadSelected = output(); + + // Message templates are intentionally co-located (shadcn copy-paste model) + readonly messageContent = messageContent; +} +``` + +- [ ] **Step 2: Run tests** + +Run: `npx nx test chat` + +Expected: All tests pass (no logic changes, only template/style changes). + +- [ ] **Step 3: Run build** + +Run: `npx nx build chat` + +Expected: Build succeeds. + +- [ ] **Step 4: Commit** + +```bash +git add libs/chat/src/lib/compositions/chat/chat.component.ts +git commit -m "feat(chat): redesign composition — Apple-clean aesthetic with theme vars" +``` + +--- + +### Task 3: Restyle ChatInput Primitive (Pill Input) + +**Files:** +- Modify: `libs/chat/src/lib/primitives/chat-input/chat-input.component.ts` + +- [ ] **Step 1: Update the template** + +Replace the template in `chat-input.component.ts` with the pill-shaped input design. Keep all logic (`onSubmit`, `onKeydown`, signals) unchanged — only modify the `template` string: + +```typescript + template: ` +
+ + +
+ `, +``` + +Also add a `focused` field to the class: + +```typescript + focused = false; +``` + +- [ ] **Step 2: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 3: Commit** + +```bash +git add libs/chat/src/lib/primitives/chat-input/chat-input.component.ts +git commit -m "feat(chat): restyle ChatInput as pill-shaped with theme vars" +``` + +--- + +### Task 4: Restyle ChatTypingIndicator (Dot Animation) + +**Files:** +- Modify: `libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts` + +- [ ] **Step 1: Update the template and add styles** + +Replace the template with the themed dot animation. Add `styleUrls` pointing to the theme CSS and inline the animation. Keep all logic unchanged. + +```typescript + template: ` + @if (visible()) { +
+
+
+
A
+ Assistant +
+
+ + + +
+
+
+ } + `, + styles: [` + .chat-dot { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--chat-text-muted, #777); + animation: chat-dot-pulse 1.4s ease-in-out infinite; + } + @keyframes chat-dot-pulse { + 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } + 40% { opacity: 1; transform: scale(1); } + } + `], +``` + +- [ ] **Step 2: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 3: Commit** + +```bash +git add libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts +git commit -m "feat(chat): restyle ChatTypingIndicator with dot animation and theme vars" +``` + +--- + +### Task 5: Restyle ChatError (Themed Banner) + +**Files:** +- Modify: `libs/chat/src/lib/primitives/chat-error/chat-error.component.ts` + +- [ ] **Step 1: Update the template** + +```typescript + template: ` + @if (errorMessage(); as msg) { + + } + `, +``` + +- [ ] **Step 2: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 3: Commit** + +```bash +git add libs/chat/src/lib/primitives/chat-error/chat-error.component.ts +git commit -m "feat(chat): restyle ChatError with theme vars" +``` + +--- + +### Task 6: Restyle ChatInterruptPanel + +**Files:** +- Modify: `libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts` + +- [ ] **Step 1: Replace the template with themed version** + +Replace the template. All logic (`interrupt`, `interruptPayload`, `action` output) stays unchanged. + +```typescript + template: ` + @if (interrupt()) { +
+
+ +
+

Agent Interrupt

+

{{ interruptPayload() }}

+
+
+
+ + + + +
+
+ } + `, +``` + +- [ ] **Step 2: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 3: Commit** + +```bash +git add libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts +git commit -m "feat(chat): restyle ChatInterruptPanel with neutral theme vars" +``` + +--- + +### Task 7: Restyle ChatToolCallCard and ChatSubagentCard + +**Files:** +- Modify: `libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts` +- Modify: `libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts` + +- [ ] **Step 1: Update ChatToolCallCard template** + +Replace all hardcoded Tailwind color classes with theme var equivalents. Key changes: +- `border-gray-200 bg-gray-50` → `style="border: 1px solid var(--chat-border); background: var(--chat-bg-alt); border-radius: var(--chat-radius-card);"` +- `text-gray-700` → `style="color: var(--chat-text);"` +- `text-gray-400` → `style="color: var(--chat-text-muted);"` +- `text-gray-500` → `style="color: var(--chat-text-muted);"` +- `hover:bg-gray-100` → `onmouseover` or CSS `:hover` with var +- `text-green-600` → `style="color: var(--chat-success);"` + +- [ ] **Step 2: Update ChatSubagentCard template** + +Same pattern. Replace all hardcoded colors with theme vars. Status badge colors: +- pending: `background: var(--chat-bg-alt); color: var(--chat-text-muted);` +- running: `background: var(--chat-warning-bg); color: var(--chat-warning-text);` +- complete: `background: transparent; color: var(--chat-success);` +- error: `background: var(--chat-error-bg); color: var(--chat-error-text);` + +- [ ] **Step 3: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 4: Commit** + +```bash +git add libs/chat/src/lib/compositions/chat-tool-call-card/ libs/chat/src/lib/compositions/chat-subagent-card/ +git commit -m "feat(chat): restyle ToolCallCard and SubagentCard with theme vars" +``` + +--- + +### Task 8: Restyle ChatDebug Composition + +**Files:** +- Modify: `libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts` + +- [ ] **Step 1: Update the template** + +Apply the same patterns as ``: centered column for messages, theme vars for all colors, avatar + label for AI messages, pill input. The debug panel sidebar also uses theme vars: + +Key changes: +- Message templates: identical to `` (asymmetric bubble for human, plain text + avatar for AI) +- Debug panel: `background: var(--chat-bg); border-color: var(--chat-border);` +- Headers, labels: `color: var(--chat-text-muted);` +- Cards, sections: `border-color: var(--chat-border); background: var(--chat-bg-alt);` +- Add `styleUrls: ['../../styles/chat-theme.css']` + +- [ ] **Step 2: Run tests and build** + +Run: `npx nx test chat && npx nx build chat` + +- [ ] **Step 3: Commit** + +```bash +git add libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts +git commit -m "feat(chat): restyle ChatDebug with theme vars" +``` + +--- + +### Task 9: Update Streaming Example Selector + +**Files:** +- Modify: `cockpit/langgraph/streaming/angular/src/app/streaming.component.ts` + +- [ ] **Step 1: Update selector from `chat-ui` to `chat`** + +Change: +```typescript + template: ``, +``` +To: +```typescript + template: ``, +``` + +Also update the JSDoc comment to reference `` instead of ``. + +- [ ] **Step 2: Build the streaming example** + +Run: `npx nx build cockpit-langgraph-streaming-angular` + +- [ ] **Step 3: Commit** + +```bash +git add cockpit/langgraph/streaming/angular/src/app/streaming.component.ts +git commit -m "fix(cockpit): update streaming example selector chat-ui → chat" +``` + +--- + +### Task 10: Full Verification + +- [ ] **Step 1: Run all library tests** + +Run: `npx nx test render && npx nx test chat && npx nx test stream-resource` + +Expected: All pass. + +- [ ] **Step 2: Run lint** + +Run: `npx nx lint chat` + +Expected: Clean (or only pre-existing warnings). + +- [ ] **Step 3: Build both libraries** + +Run: `npx nx build render && npx nx build chat` + +Expected: Both succeed. + +- [ ] **Step 4: Build streaming example** + +Run: `npx nx build cockpit-langgraph-streaming-angular` + +Expected: Succeeds. + +- [ ] **Step 5: Serve and visually verify** + +Run: `npx nx serve cockpit-langgraph-streaming-angular` + +Open in browser. Verify: +- Dark mode renders (dark bg, neutral gray messages, pill input) +- Toggle system preference to light → light mode renders +- Messages use asymmetric border-radius for human, no bubble for AI +- Input is pill-shaped with circular send button +- Content column is centered at 720px max-width +- Mobile: resize browser narrow — full-bleed, larger message width % + +--- + +## Summary + +| Task | Description | Files | +|------|-------------|-------| +| 1 | Theme CSS file | 1 new file | +| 2 | Redesign `` composition | 1 file rewrite | +| 3 | Pill-shaped ChatInput | 1 file template update | +| 4 | Dot animation ChatTypingIndicator | 1 file template + styles | +| 5 | Themed ChatError | 1 file template update | +| 6 | Themed ChatInterruptPanel | 1 file template update | +| 7 | Themed ToolCallCard + SubagentCard | 2 files template update | +| 8 | Themed ChatDebug | 1 file template update | +| 9 | Streaming example selector fix | 1 file | +| 10 | Full verification | Tests + build + visual | diff --git a/docs/superpowers/plans/2026-04-05-streaming-example-chat-integration.md b/docs/superpowers/plans/2026-04-05-streaming-example-chat-integration.md new file mode 100644 index 000000000..58d1d665e --- /dev/null +++ b/docs/superpowers/plans/2026-04-05-streaming-example-chat-integration.md @@ -0,0 +1,366 @@ +# Streaming Example — Chat UI Integration Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Wire the cockpit `langgraph/streaming/angular` example to correctly consume `@cacheplane/chat` and `@cacheplane/stream-resource`, making it buildable and serveable as a standalone Angular app against a real LangGraph backend. + +**Architecture:** Standalone Angular app bootstrapped with `bootstrapApplication()`. Uses `provideStreamResource()` for global API URL, `provideChat()` for chat config. `StreamingComponent` creates a `streamResource()` ref and passes it to ``. Proxied to LangGraph dev server on port 8123 via `/api`. + +**Tech Stack:** Angular 21, `@cacheplane/chat`, `@cacheplane/stream-resource`, `@angular-devkit/build-angular`, Tailwind CSS + +--- + +## Context + +The streaming example has two problems: + +1. **Wrong API usage:** `StreamingComponent` uses `` — none of these exist. The actual `ChatComponent` has selector `chat-ui` and accepts `[ref]` (a `StreamResourceRef`). + +2. **Duplicate entry points:** Two app components exist (`src/app.component.ts` and `src/app/streaming.component.ts`) from different branches being merged. Need to consolidate to one. + +3. **No Angular CLI build target:** `project.json` uses `@nx/js:tsc` (library build) instead of `@angular-devkit/build-angular:application` (app build). Can't serve the app. + +## File Structure + +``` +cockpit/langgraph/streaming/angular/ +├── src/ +│ ├── app/ +│ │ ├── streaming.component.ts # REWRITE — use chat-ui with [ref] +│ │ └── app.config.ts # UPDATE — add provideChat +│ ├── environments/ +│ │ ├── environment.ts # VERIFY — production config +│ │ └── environment.development.ts # UPDATE — use /api proxy +│ ├── main.ts # REWRITE — bootstrap StreamingComponent +│ ├── index.html # UPDATE — proper Angular app HTML +│ ├── styles.css # VERIFY — Tailwind setup +│ ├── index.ts # KEEP — module descriptor for cockpit +│ ├── app.component.ts # DELETE — duplicate +│ └── app.config.ts # DELETE — duplicate +├── project.json # REWRITE — Angular CLI build/serve targets +├── tsconfig.app.json # UPDATE — Angular CLI compatible +├── proxy.conf.json # KEEP — proxies /api to localhost:8123 +├── package.json # KEEP +└── prompts/streaming.md # KEEP +``` + +--- + +### Task 1: Clean Up Duplicate Files + +**Files:** +- Delete: `cockpit/langgraph/streaming/angular/src/app.component.ts` +- Delete: `cockpit/langgraph/streaming/angular/src/app.config.ts` + +- [ ] **Step 1: Delete duplicate entry point** + +```bash +rm cockpit/langgraph/streaming/angular/src/app.component.ts +rm cockpit/langgraph/streaming/angular/src/app.config.ts +``` + +- [ ] **Step 2: Commit** + +```bash +git add -A cockpit/langgraph/streaming/angular/src/ +git commit -m "chore(cockpit): remove duplicate streaming entry points" +``` + +--- + +### Task 2: Rewrite StreamingComponent with Correct Chat API + +**Files:** +- Modify: `cockpit/langgraph/streaming/angular/src/app/streaming.component.ts` + +- [ ] **Step 1: Rewrite the component** + +The component must use `chat-ui` selector (the actual ChatComponent selector) with `[ref]` input. Call `streamResource()` as a field initializer (valid injection context — no need for `runInInjectionContext`). + +```typescript +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import { Component } from '@angular/core'; +import { ChatComponent } from '@cacheplane/chat'; +import { streamResource } from '@cacheplane/stream-resource'; +import { environment } from '../environments/environment'; + +/** + * Streaming demo — simplest possible @cacheplane/chat integration. + * + * Creates a streamResource ref and passes it to the prebuilt + * composition. The composition handles message rendering, input, typing + * indicator, and error display internally. + */ +@Component({ + selector: 'app-streaming', + standalone: true, + imports: [ChatComponent], + template: ``, +}) +export class StreamingComponent { + protected readonly stream = streamResource({ + assistantId: environment.streamingAssistantId, + }); +} +``` + +- [ ] **Step 2: Verify the import resolves** + +Run: `npx nx build cockpit-langgraph-streaming-angular --dry-run` (or just check TypeScript compilation) + +- [ ] **Step 3: Commit** + +```bash +git add cockpit/langgraph/streaming/angular/src/app/streaming.component.ts +git commit -m "feat(cockpit): rewrite streaming component with correct chat-ui API" +``` + +--- + +### Task 3: Update App Config and Bootstrap + +**Files:** +- Modify: `cockpit/langgraph/streaming/angular/src/app/app.config.ts` +- Modify: `cockpit/langgraph/streaming/angular/src/main.ts` +- Modify: `cockpit/langgraph/streaming/angular/src/environments/environment.development.ts` + +- [ ] **Step 1: Update app.config.ts to include provideChat** + +```typescript +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import { ApplicationConfig } from '@angular/core'; +import { provideStreamResource } from '@cacheplane/stream-resource'; +import { provideChat } from '@cacheplane/chat'; +import { environment } from '../environments/environment'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideStreamResource({ apiUrl: environment.langGraphApiUrl }), + provideChat({}), + ], +}; +``` + +- [ ] **Step 2: Update main.ts to bootstrap StreamingComponent** + +```typescript +// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { StreamingComponent } from './app/streaming.component'; + +bootstrapApplication(StreamingComponent, appConfig).catch(console.error); +``` + +- [ ] **Step 3: Update development environment to use proxy** + +```typescript +export const environment = { + production: false, + langGraphApiUrl: '/api', + streamingAssistantId: 'streaming', +}; +``` + +The `/api` path is rewritten to `http://localhost:8123` by `proxy.conf.json`. + +- [ ] **Step 4: Commit** + +```bash +git add cockpit/langgraph/streaming/angular/src/ +git commit -m "feat(cockpit): update streaming app config and bootstrap" +``` + +--- + +### Task 4: Add Angular CLI Build and Serve Targets + +**Files:** +- Modify: `cockpit/langgraph/streaming/angular/project.json` +- Modify: `cockpit/langgraph/streaming/angular/tsconfig.app.json` +- Modify: `cockpit/langgraph/streaming/angular/src/index.html` +- Verify: `cockpit/langgraph/streaming/angular/src/styles.css` + +- [ ] **Step 1: Rewrite project.json with Angular CLI targets** + +Replace the `@nx/js:tsc` build target with `@angular-devkit/build-angular:application` and add a `serve` target: + +```json +{ + "name": "cockpit-langgraph-streaming-angular", + "$schema": "../../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "cockpit/langgraph/streaming/angular/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/cockpit/langgraph/streaming/angular", + "index": "cockpit/langgraph/streaming/angular/src/index.html", + "browser": "cockpit/langgraph/streaming/angular/src/main.ts", + "tsConfig": "cockpit/langgraph/streaming/angular/tsconfig.app.json", + "styles": ["cockpit/langgraph/streaming/angular/src/styles.css"] + }, + "configurations": { + "production": { + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "options": { + "port": 4300, + "proxyConfig": "cockpit/langgraph/streaming/angular/proxy.conf.json" + }, + "configurations": { + "production": { + "buildTarget": "cockpit-langgraph-streaming-angular:build:production" + }, + "development": { + "buildTarget": "cockpit-langgraph-streaming-angular:build:development" + } + }, + "defaultConfiguration": "development" + }, + "smoke": { + "executor": "nx:run-commands", + "options": { + "cwd": "cockpit/langgraph/streaming/angular", + "command": "npx tsx -e \"import { langgraphStreamingAngularModule } from './src/index.ts'; const module = langgraphStreamingAngularModule; if (module.id !== 'langgraph-streaming-angular' || module.title !== 'LangGraph Streaming (Angular)') { throw new Error('Unexpected module shape for ' + module.id); }\"" + } + } + } +} +``` + +- [ ] **Step 2: Update tsconfig.app.json for Angular CLI** + +```json +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"] +} +``` + +- [ ] **Step 3: Update index.html** + +```html + + + + + LangGraph Streaming — Angular + + + + + + + +``` + +- [ ] **Step 4: Verify styles.css has Tailwind** + +Check that `src/styles.css` contains Tailwind directives. If not, add them: + +```css +@tailwind base; +@tailwind components; +@tailwind utilities; +``` + +Also verify that a `tailwind.config.js` or equivalent exists at the example root, or that Tailwind is configured at the workspace level. If Tailwind isn't set up for this project, use the CDN script in `index.html` as a fallback: + +```html + +``` + +- [ ] **Step 5: Build the app** + +Run: `npx nx build cockpit-langgraph-streaming-angular` + +Expected: Build succeeds, output in `dist/cockpit/langgraph/streaming/angular/`. + +- [ ] **Step 6: Serve the app** + +Run: `npx nx serve cockpit-langgraph-streaming-angular` + +Expected: Dev server starts on `http://localhost:4300`. + +- [ ] **Step 7: Commit** + +```bash +git add cockpit/langgraph/streaming/angular/ +git commit -m "feat(cockpit): add Angular CLI build and serve targets for streaming example" +``` + +--- + +### Task 5: End-to-End Verification + +- [ ] **Step 1: Start the LangGraph backend** + +In a separate terminal: +```bash +cd cockpit/langgraph/streaming/python +langgraph dev +``` + +Expected: LangGraph dev server starts on `http://localhost:8123`. + +- [ ] **Step 2: Serve the Angular app** + +```bash +npx nx serve cockpit-langgraph-streaming-angular +``` + +Expected: Dev server on `http://localhost:4300`. + +- [ ] **Step 3: Test in browser** + +Open `http://localhost:4300`: +- Chat UI renders (message list, input, typing indicator) +- Type a message and submit +- Verify streaming response renders token by token +- Verify typing indicator shows during streaming +- Verify human messages appear right-aligned (blue) +- Verify AI messages appear left-aligned (gray) + +- [ ] **Step 4: Test error handling** + +Stop the LangGraph backend and submit a message. Verify the error component renders. + +- [ ] **Step 5: Run library tests to verify no regressions** + +```bash +npx nx test render && npx nx test chat && npx nx test stream-resource +``` + +- [ ] **Step 6: Document any issues found** + +If the chat or render libraries have bugs discovered during integration testing, document them for follow-up fixes. + +--- + +## Summary + +| Task | Description | Files | +|------|-------------|-------| +| 1 | Clean up duplicate files | Delete 2 files | +| 2 | Rewrite StreamingComponent | 1 file | +| 3 | Update config and bootstrap | 3 files | +| 4 | Add Angular CLI build/serve targets | 4 files | +| 5 | End-to-end verification | Manual testing | diff --git a/docs/superpowers/specs/2026-04-05-chat-ui-redesign.md b/docs/superpowers/specs/2026-04-05-chat-ui-redesign.md new file mode 100644 index 000000000..ec1930761 --- /dev/null +++ b/docs/superpowers/specs/2026-04-05-chat-ui-redesign.md @@ -0,0 +1,230 @@ +# Chat UI Redesign — Apple-Clean Aesthetic + +**Date:** 2026-04-05 +**Status:** Draft +**Scope:** Visual redesign of `@cacheplane/chat` composition layer. No changes to headless primitives, types, DI, or test utilities. + +--- + +## Overview + +Redesign the `@cacheplane/chat` prebuilt compositions with an Apple-clean aesthetic: neutral grays, generous whitespace, SF Pro typography, pill-shaped input, asymmetric rounded corners. Fully responsive (desktop → mobile). Fully themeable via CSS custom properties. Light and dark mode support via `prefers-color-scheme`. + +### Design Principles + +1. **Neutral by default** — Grays only. No brand color in shipped defaults. Developers add their brand via CSS vars. +2. **AI = text, Human = bubble** — AI responses render as plain text with avatar badge (ChatGPT pattern). Human messages get a subtle surface bubble. Clear visual hierarchy. +3. **Centered column** — 720px max-width centered content. Optimal reading width. Full-bleed on mobile with 16px edge padding. +4. **Template overrides for extensibility** — Developers content-project `chatMessageTemplate` directives into `` to replace any message type's rendering. The composition detects overrides and uses them instead of defaults. + +--- + +## Theming Architecture + +### CSS Custom Properties + +All visual properties are exposed as CSS custom properties on the host element. Two built-in themes (dark/light) ship as defaults. Developers override any property at their app level. + +#### Surfaces + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-bg` | `#171717` | `#ffffff` | Main background | +| `--chat-bg-alt` | `#222222` | `#f5f5f5` | Input, cards, elevated surfaces | +| `--chat-bg-hover` | `#2a2a2a` | `#ebebeb` | Hover state for interactive elements | + +#### Text + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-text` | `#e0e0e0` | `#1a1a1a` | Primary text | +| `--chat-text-muted` | `#777777` | `#999999` | Secondary/label text | +| `--chat-text-placeholder` | `#666666` | `#999999` | Input placeholder | + +#### Borders + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-border` | `#333333` | `#e5e5e5` | Standard border | +| `--chat-border-light` | `#2a2a2a` | `#f0f0f0` | Subtle dividers | + +#### User Messages + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-user-bg` | `#2a2a2a` | `#f0f0f0` | Human message bubble | +| `--chat-user-text` | `#f5f5f5` | `#1a1a1a` | Human message text | +| `--chat-user-border` | `#333333` | `transparent` | Human message border | + +#### Avatar + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-avatar-bg` | `#333333` | `#f0f0f0` | Agent avatar background | +| `--chat-avatar-text` | `#aaaaaa` | `#666666` | Agent avatar letter | + +#### Input + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-input-bg` | `#222222` | `#f5f5f5` | Input container | +| `--chat-input-border` | `#333333` | `#e5e5e5` | Input border | +| `--chat-input-focus-border` | `#555555` | `#cccccc` | Input border on focus | +| `--chat-send-bg` | `#444444` | `#e5e5e5` | Send button background | +| `--chat-send-text` | `#aaaaaa` | `#999999` | Send button icon | + +#### Status + +| Property | Dark Default | Light Default | Purpose | +|----------|-------------|---------------|---------| +| `--chat-error-bg` | `#2d1515` | `#fef2f2` | Error banner background | +| `--chat-error-text` | `#f87171` | `#dc2626` | Error text | +| `--chat-warning-bg` | `#2d2315` | `#fffbeb` | Interrupt/warning background | +| `--chat-warning-text` | `#fbbf24` | `#d97706` | Interrupt text | +| `--chat-success` | `#4ade80` | `#16a34a` | Success indicators | + +#### Geometry + +| Property | Default | Purpose | +|----------|---------|---------| +| `--chat-radius-message` | `20px` | Message bubble radius | +| `--chat-radius-input` | `24px` | Input pill radius | +| `--chat-radius-card` | `12px` | Card/panel radius | +| `--chat-radius-avatar` | `8px` | Avatar radius | +| `--chat-max-width` | `720px` | Content column max-width | + +#### Typography + +| Property | Default | Purpose | +|----------|---------|---------| +| `--chat-font-family` | `-apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif` | System font stack | +| `--chat-font-size` | `15px` | Base font size | +| `--chat-line-height` | `1.6` | Base line height | + +### Dark/Light Mode Activation + +- Default: dark theme +- Light mode: `@media (prefers-color-scheme: light)` overrides all properties +- Manual control: set `data-chat-theme="light"` or `data-chat-theme="dark"` on a parent element to force a mode regardless of system preference + +### Theme File + +New file: `libs/chat/src/lib/styles/chat-theme.css` + +Imported by composition components via Angular's `styles` or `styleUrls`. Defines `:host` defaults (dark) and `@media (prefers-color-scheme: light)` block. Also supports `[data-chat-theme="light"]` and `[data-chat-theme="dark"]` attribute selectors. + +--- + +## Responsive Design + +| Breakpoint | Content Width | Edge Padding | Message Max Width | Font Size | +|------------|--------------|-------------|-------------------|-----------| +| ≥1024px (desktop) | `var(--chat-max-width)` centered | 20px | 75% | 15px | +| 768–1023px (tablet) | 100% (max `var(--chat-max-width)`) | 20px | 80% | 15px | +| <768px (mobile) | 100% full-bleed | 16px | 85% | 14–15px | + +- Input: minimum 44px touch target height on mobile +- Send button: 32px desktop, 36px mobile +- Thread sidebar: hidden on mobile (collapses behind a toggle or removed entirely) + +--- + +## Component Changes + +### `` (selector change: `chat-ui` → `chat`) + +The main prebuilt composition. Renders the full chat experience. + +**Message rendering:** +- Human messages: right-aligned bubble with `var(--chat-user-bg)`, asymmetric radius (`--chat-radius-message` top-left/top-right/bottom-right, 6px bottom-left for "tail" effect), `var(--chat-user-border)` border +- AI messages: no bubble — plain text, left-aligned, with an avatar badge (24px square, `var(--chat-radius-avatar)` corners, `var(--chat-avatar-bg)`) and an "Assistant" label in `var(--chat-text-muted)` +- Tool messages: monospace, subtle `var(--chat-bg-alt)` background, `var(--chat-radius-card)` corners +- System messages: centered, `var(--chat-text-muted)`, italic, small font + +**Template override mechanism:** +- `` uses `contentChildren(MessageTemplateDirective)` to detect developer-provided templates +- If a `chatMessageTemplate` for a given type (human/ai/tool/system) is projected, it replaces the default +- If no override is projected, the built-in default template renders +- This means `` works zero-config, but developers can override any or all templates + +**Layout:** +- Flex column, full height of parent +- Messages area: scrollable, centered column +- Input area: fixed at bottom, centered column matching messages width +- Optional thread sidebar: rendered when `threads` input is non-empty + +### `` (primitive — styled template update) + +- Pill-shaped container: `var(--chat-input-bg)`, `var(--chat-radius-input)` border-radius +- Auto-expanding textarea (CSS `field-sizing: content` or JS fallback) +- Circular send button on the right: `var(--chat-send-bg)`, fully round +- Focus state: `var(--chat-input-focus-border)` with `transition: border-color 0.2s` +- Disabled state: `opacity: 0.5` when `ref.isLoading()` + +### `` + +- Three-dot pulse animation: 5px dots, staggered 0.2s delay +- Rendered below last AI message, with avatar badge matching AI message style +- Dot color: `var(--chat-text-muted)` + +### `` + +- Inline banner above input area +- `var(--chat-error-bg)` background, `var(--chat-error-text)` text +- `var(--chat-radius-card)` corners +- Subtle, non-intrusive + +### `` + +- Warning banner: `var(--chat-warning-bg)` with `var(--chat-warning-text)` +- Action buttons: neutral `var(--chat-bg-alt)` with `var(--chat-border)` — not colored per-action +- `var(--chat-radius-card)` corners + +### `` and `` + +- Cards: `var(--chat-bg-alt)` background, `var(--chat-border)` border, `var(--chat-radius-card)` corners +- Collapsible with smooth height transition +- Monospace font for JSON content +- Status badges use `var(--chat-text-muted)` with colored dot indicators + +### `` + +- Same theme variables throughout — inherits the full system +- Debug panel: `var(--chat-bg)` background, `var(--chat-border)` left border +- Checkpoint cards, state inspector, diff: all use `var(--chat-bg-alt)`, `var(--chat-border)`, `var(--chat-radius-card)` + +--- + +## Files Changed + +| File | Change | Type | +|------|--------|------| +| `libs/chat/src/lib/styles/chat-theme.css` | New | CSS custom properties + dark/light defaults | +| `libs/chat/src/lib/compositions/chat/chat.component.ts` | Rewrite template + add theme import | Composition | +| `libs/chat/src/lib/primitives/chat-input/chat-input.component.ts` | Style the template | Primitive | +| `libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts` | Dot animation + themed | Primitive | +| `libs/chat/src/lib/primitives/chat-error/chat-error.component.ts` | Styled error banner | Primitive | +| `libs/chat/src/lib/compositions/chat-interrupt-panel/chat-interrupt-panel.component.ts` | Restyle with theme vars | Composition | +| `libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts` | Restyle with theme vars | Composition | +| `libs/chat/src/lib/compositions/chat-subagent-card/chat-subagent-card.component.ts` | Restyle with theme vars | Composition | +| `libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts` | Restyle with theme vars | Composition | +| `cockpit/langgraph/streaming/angular/src/app/streaming.component.ts` | Update selector `chat-ui` → `chat` | Cockpit example | + +**No changes to:** headless primitive logic, types, DI providers, public-api.ts exports, tests. + +--- + +## Key Decisions Log + +| Decision | Choice | Rationale | +|----------|--------|-----------| +| Design direction | Apple-clean (Option A) | Industry-standard ChatGPT-like pattern, clean and modern | +| Color palette | Neutral grays, no brand color | Works in any application, developers add brand via CSS vars | +| AI message style | No bubble, plain text + avatar | ChatGPT pattern, reduces visual noise, focuses on content | +| Human message style | Subtle surface bubble, asymmetric radius | Clear visual distinction without strong brand color | +| Theming | CSS custom properties | Most flexible, no runtime overhead, works with any CSS framework | +| Dark/light mode | `prefers-color-scheme` + `data-chat-theme` attribute | Automatic system detection + manual override for app control | +| Extensibility | Template overrides via `chatMessageTemplate` | Full rendering control per message type, Angular-idiomatic | +| Responsive | 720px centered → full-bleed mobile | Optimal reading width desktop, maximum space mobile | +| Selector | `chat` (not `chat-ui`) | Simple, memorable | +| Input shape | Pill (24px radius) | Apple/ChatGPT convention, modern feel | diff --git a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts index 8906066ab..df44d5719 100644 --- a/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts +++ b/libs/chat/src/lib/compositions/chat-debug/chat-debug.component.ts @@ -35,63 +35,150 @@ import { messageContent } from '../shared/message-utils'; DebugSummaryComponent, ], changeDetection: ChangeDetectionStrategy.OnPush, + styles: [ + `:host { + --chat-bg: #171717; --chat-bg-alt: #222222; --chat-bg-hover: #2a2a2a; + --chat-text: #e0e0e0; --chat-text-muted: #777777; --chat-text-placeholder: #666666; + --chat-border: #333333; --chat-border-light: #2a2a2a; + --chat-user-bg: #2a2a2a; --chat-user-text: #f5f5f5; --chat-user-border: #333333; + --chat-avatar-bg: #333333; --chat-avatar-text: #aaaaaa; + --chat-input-bg: #222222; --chat-input-border: #333333; --chat-input-focus-border: #555555; + --chat-send-bg: #444444; --chat-send-text: #aaaaaa; + --chat-error-bg: #2d1515; --chat-error-text: #f87171; + --chat-warning-bg: #2d2315; --chat-warning-text: #fbbf24; --chat-success: #4ade80; + --chat-radius-message: 20px; --chat-radius-input: 24px; --chat-radius-card: 12px; + --chat-radius-avatar: 8px; --chat-max-width: 720px; + --chat-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif; + --chat-font-size: 15px; --chat-line-height: 1.6; + font-family: var(--chat-font-family); font-size: var(--chat-font-size); + line-height: var(--chat-line-height); color: var(--chat-text); background: var(--chat-bg); + display: flex; flex-direction: column; height: 100%; overflow: hidden; + } + @media (prefers-color-scheme: light) { + :host:not([data-chat-theme="dark"]) { + --chat-bg: #ffffff; --chat-bg-alt: #f5f5f5; --chat-bg-hover: #ebebeb; + --chat-text: #1a1a1a; --chat-text-muted: #999999; --chat-text-placeholder: #999999; + --chat-border: #e5e5e5; --chat-border-light: #f0f0f0; + --chat-user-bg: #f0f0f0; --chat-user-text: #1a1a1a; --chat-user-border: transparent; + --chat-avatar-bg: #f0f0f0; --chat-avatar-text: #666666; + --chat-input-bg: #f5f5f5; --chat-input-border: #e5e5e5; --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; --chat-send-text: #999999; + --chat-error-bg: #fef2f2; --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; --chat-warning-text: #d97706; --chat-success: #16a34a; + } + } + :host([data-chat-theme="light"]) { + --chat-bg: #ffffff; --chat-bg-alt: #f5f5f5; --chat-bg-hover: #ebebeb; + --chat-text: #1a1a1a; --chat-text-muted: #999999; --chat-text-placeholder: #999999; + --chat-border: #e5e5e5; --chat-border-light: #f0f0f0; + --chat-user-bg: #f0f0f0; --chat-user-text: #1a1a1a; --chat-user-border: transparent; + --chat-avatar-bg: #f0f0f0; --chat-avatar-text: #666666; + --chat-input-bg: #f5f5f5; --chat-input-border: #e5e5e5; --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; --chat-send-text: #999999; + --chat-error-bg: #fef2f2; --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; --chat-warning-text: #d97706; --chat-success: #16a34a; + }`, + ], template: ` -
+
-
-
- - -
-
- {{ messageContent(message) }} +
+
+
+ + + +
+
{{ messageContent(message) }}
-
- + - -
-
- {{ messageContent(message) }} + + +
+
+
A
+ Assistant +
+
{{ messageContent(message) }}
-
- + - -
-
- {{ messageContent(message) }} -
-
-
+ + +
{{ messageContent(message) }}
+
- -
-
- {{ messageContent(message) }} + + +
+ + {{ messageContent(message) }} +
-
- - + + - + +
-
- + +
+
+ +
@if (!debugOpen()) {
-
+
-
+
-
+
@if (selectedCheckpointIndex() >= 0) { -
+
+
-
- -
-

Agent Interrupt

-

{{ interruptPayload() }}

+
+ +
+

Agent Interrupt

+

{{ interruptPayload() }}

-
+
@if (expanded()) { -
+
-
+
{{ subagent().messages().length }} message(s)
@if (subagent().messages().length > 0) {
-

Latest Message

-
+

Latest Message

+
{{ latestMessageContent() }}
diff --git a/libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts b/libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts index d5a748c75..81eed5e66 100644 --- a/libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts +++ b/libs/chat/src/lib/compositions/chat-tool-call-card/chat-tool-call-card.component.ts @@ -18,34 +18,34 @@ export interface ToolCallInfo { standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ` -
+
@if (expanded()) { -
-
-

Inputs

-
{{ formatJson(toolCall().args) }}
+
+
+

Inputs

+
{{ formatJson(toolCall().args) }}
@if (toolCall().result !== undefined) { -
-

Output

-
{{ formatJson(toolCall().result) }}
+
+

Output

+
{{ formatJson(toolCall().result) }}
}
diff --git a/libs/chat/src/lib/compositions/chat/chat.component.ts b/libs/chat/src/lib/compositions/chat/chat.component.ts index 8d24d4289..ba56dbd3a 100644 --- a/libs/chat/src/lib/compositions/chat/chat.component.ts +++ b/libs/chat/src/lib/compositions/chat/chat.component.ts @@ -16,7 +16,7 @@ import { ChatThreadListComponent, Thread } from '../../primitives/chat-thread-li import { messageContent } from '../shared/message-utils'; @Component({ - selector: 'chat-ui', + selector: 'chat', standalone: true, imports: [ ChatMessagesComponent, @@ -28,13 +28,58 @@ import { messageContent } from '../shared/message-utils'; ChatThreadListComponent, ], changeDetection: ChangeDetectionStrategy.OnPush, + styles: [ + // Theme CSS custom properties (sourced from libs/chat/src/lib/styles/chat-theme.css) + `:host { + --chat-bg: #171717; --chat-bg-alt: #222222; --chat-bg-hover: #2a2a2a; + --chat-text: #e0e0e0; --chat-text-muted: #777777; --chat-text-placeholder: #666666; + --chat-border: #333333; --chat-border-light: #2a2a2a; + --chat-user-bg: #2a2a2a; --chat-user-text: #f5f5f5; --chat-user-border: #333333; + --chat-avatar-bg: #333333; --chat-avatar-text: #aaaaaa; + --chat-input-bg: #222222; --chat-input-border: #333333; --chat-input-focus-border: #555555; + --chat-send-bg: #444444; --chat-send-text: #aaaaaa; + --chat-error-bg: #2d1515; --chat-error-text: #f87171; + --chat-warning-bg: #2d2315; --chat-warning-text: #fbbf24; --chat-success: #4ade80; + --chat-radius-message: 20px; --chat-radius-input: 24px; --chat-radius-card: 12px; + --chat-radius-avatar: 8px; --chat-max-width: 720px; + --chat-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif; + --chat-font-size: 15px; --chat-line-height: 1.6; + font-family: var(--chat-font-family); font-size: var(--chat-font-size); + line-height: var(--chat-line-height); color: var(--chat-text); background: var(--chat-bg); + display: flex; flex-direction: column; height: 100%; overflow: hidden; + } + @media (prefers-color-scheme: light) { + :host:not([data-chat-theme="dark"]) { + --chat-bg: #ffffff; --chat-bg-alt: #f5f5f5; --chat-bg-hover: #ebebeb; + --chat-text: #1a1a1a; --chat-text-muted: #999999; --chat-text-placeholder: #999999; + --chat-border: #e5e5e5; --chat-border-light: #f0f0f0; + --chat-user-bg: #f0f0f0; --chat-user-text: #1a1a1a; --chat-user-border: transparent; + --chat-avatar-bg: #f0f0f0; --chat-avatar-text: #666666; + --chat-input-bg: #f5f5f5; --chat-input-border: #e5e5e5; --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; --chat-send-text: #999999; + --chat-error-bg: #fef2f2; --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; --chat-warning-text: #d97706; --chat-success: #16a34a; + } + } + :host([data-chat-theme="light"]) { + --chat-bg: #ffffff; --chat-bg-alt: #f5f5f5; --chat-bg-hover: #ebebeb; + --chat-text: #1a1a1a; --chat-text-muted: #999999; --chat-text-placeholder: #999999; + --chat-border: #e5e5e5; --chat-border-light: #f0f0f0; + --chat-user-bg: #f0f0f0; --chat-user-text: #1a1a1a; --chat-user-border: transparent; + --chat-avatar-bg: #f0f0f0; --chat-avatar-text: #666666; + --chat-input-bg: #f5f5f5; --chat-input-border: #e5e5e5; --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; --chat-send-text: #999999; + --chat-error-bg: #fef2f2; --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; --chat-warning-text: #d97706; --chat-success: #16a34a; + }`, + ], template: ` -
+
@if (threads().length > 0) { -
-
-

Threads

+
+
+

Threads

+ `, }) @@ -55,6 +105,8 @@ export class ChatInputComponent { readonly isDisabled = computed(() => this.ref().isLoading()); + focused = false; + onSubmit(): void { const submitted = submitMessage(this.ref(), this.messageText()); if (submitted !== null) { diff --git a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts index 05c5f88b1..caaf2088d 100644 --- a/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts +++ b/libs/chat/src/lib/primitives/chat-typing-indicator/chat-typing-indicator.component.ts @@ -19,10 +19,46 @@ export function isTyping(ref: StreamResourceRef): boolean { selector: 'chat-typing-indicator', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, + styles: [` + .chat-dot { + display: inline-block; + width: 5px; + height: 5px; + border-radius: 50%; + background: var(--chat-text-muted, #777); + animation: chat-dot-pulse 1.4s ease-in-out infinite; + } + .chat-dot:nth-child(2) { animation-delay: 0.2s; } + .chat-dot:nth-child(3) { animation-delay: 0.4s; } + @keyframes chat-dot-pulse { + 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } + 40% { opacity: 1; transform: scale(1); } + } + `], template: ` @if (visible()) { -
- ... +
+
+
A
+ Assistant +
+ + + +
+
} `, diff --git a/libs/chat/src/lib/styles/chat-theme.css b/libs/chat/src/lib/styles/chat-theme.css new file mode 100644 index 000000000..2f2ca7318 --- /dev/null +++ b/libs/chat/src/lib/styles/chat-theme.css @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 */ + +/* ── Dark defaults ─────────────────────────────────────────────────────────── */ +:host { + /* Surfaces */ + --chat-bg: #171717; + --chat-bg-alt: #222222; + --chat-bg-hover: #2a2a2a; + + /* Text */ + --chat-text: #e0e0e0; + --chat-text-muted: #777777; + --chat-text-placeholder: #666666; + + /* Borders */ + --chat-border: #333333; + --chat-border-light: #2a2a2a; + + /* User messages */ + --chat-user-bg: #2a2a2a; + --chat-user-text: #f5f5f5; + --chat-user-border: #333333; + + /* Avatar */ + --chat-avatar-bg: #333333; + --chat-avatar-text: #aaaaaa; + + /* Input */ + --chat-input-bg: #222222; + --chat-input-border: #333333; + --chat-input-focus-border: #555555; + --chat-send-bg: #444444; + --chat-send-text: #aaaaaa; + + /* Status */ + --chat-error-bg: #2d1515; + --chat-error-text: #f87171; + --chat-warning-bg: #2d2315; + --chat-warning-text: #fbbf24; + --chat-success: #4ade80; + + /* Geometry */ + --chat-radius-message: 20px; + --chat-radius-input: 24px; + --chat-radius-card: 12px; + --chat-radius-avatar: 8px; + --chat-max-width: 720px; + + /* Typography */ + --chat-font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif; + --chat-font-size: 15px; + --chat-line-height: 1.6; + + font-family: var(--chat-font-family); + font-size: var(--chat-font-size); + line-height: var(--chat-line-height); + color: var(--chat-text); + background: var(--chat-bg); +} + +/* ── Light mode via OS preference (unless forced dark) ─────────────────────── */ +@media (prefers-color-scheme: light) { + :host:not([data-chat-theme="dark"]) { + /* Surfaces */ + --chat-bg: #ffffff; + --chat-bg-alt: #f5f5f5; + --chat-bg-hover: #ebebeb; + + /* Text */ + --chat-text: #1a1a1a; + --chat-text-muted: #999999; + --chat-text-placeholder: #999999; + + /* Borders */ + --chat-border: #e5e5e5; + --chat-border-light: #f0f0f0; + + /* User messages */ + --chat-user-bg: #f0f0f0; + --chat-user-text: #1a1a1a; + --chat-user-border: transparent; + + /* Avatar */ + --chat-avatar-bg: #f0f0f0; + --chat-avatar-text: #666666; + + /* Input */ + --chat-input-bg: #f5f5f5; + --chat-input-border: #e5e5e5; + --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; + --chat-send-text: #999999; + + /* Status */ + --chat-error-bg: #fef2f2; + --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; + --chat-warning-text: #d97706; + --chat-success: #16a34a; + } +} + +/* ── Manual light override ─────────────────────────────────────────────────── */ +:host([data-chat-theme="light"]) { + /* Surfaces */ + --chat-bg: #ffffff; + --chat-bg-alt: #f5f5f5; + --chat-bg-hover: #ebebeb; + + /* Text */ + --chat-text: #1a1a1a; + --chat-text-muted: #999999; + --chat-text-placeholder: #999999; + + /* Borders */ + --chat-border: #e5e5e5; + --chat-border-light: #f0f0f0; + + /* User messages */ + --chat-user-bg: #f0f0f0; + --chat-user-text: #1a1a1a; + --chat-user-border: transparent; + + /* Avatar */ + --chat-avatar-bg: #f0f0f0; + --chat-avatar-text: #666666; + + /* Input */ + --chat-input-bg: #f5f5f5; + --chat-input-border: #e5e5e5; + --chat-input-focus-border: #cccccc; + --chat-send-bg: #e5e5e5; + --chat-send-text: #999999; + + /* Status */ + --chat-error-bg: #fef2f2; + --chat-error-text: #dc2626; + --chat-warning-bg: #fffbeb; + --chat-warning-text: #d97706; + --chat-success: #16a34a; +} + +/* ── Dot pulse animation (used by ChatTypingIndicator) ─────────────────────── */ +@keyframes chat-dot-pulse { + 0%, 80%, 100% { + opacity: 0.3; + transform: scale(0.8); + } + 40% { + opacity: 1; + transform: scale(1); + } +} diff --git a/package-lock.json b/package-lock.json index ed4a8fbea..913defd38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "shiki": "^4.0.2" }, "devDependencies": { + "@angular-devkit/build-angular": "^21.2.6", "@angular-devkit/core": "~21.1.0", "@angular-devkit/schematics": "~21.1.0", "@angular/build": "~21.1.0", @@ -367,6 +368,2287 @@ "yarn": ">= 1.13.0" } }, + "node_modules/@angular-devkit/build-angular": { + "version": "21.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-21.2.6.tgz", + "integrity": "sha512-eUWcWiMOUg01QyJkaO/csyTy8ZecW2HrMvOlgM+IWLagDyqFQVcSwcx9/NJy/42YA+EtpBcCnXPK3vk5NVob7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.6", + "@angular-devkit/build-webpack": "0.2102.6", + "@angular-devkit/core": "21.2.6", + "@angular/build": "21.2.6", + "@babel/core": "7.29.0", + "@babel/generator": "7.29.1", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.29.0", + "@babel/plugin-transform-async-to-generator": "7.28.6", + "@babel/plugin-transform-runtime": "7.29.0", + "@babel/preset-env": "7.29.0", + "@babel/runtime": "7.28.6", + "@discoveryjs/json-ext": "0.6.3", + "@ngtools/webpack": "21.2.6", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.27", + "babel-loader": "10.0.0", + "browserslist": "^4.26.0", + "copy-webpack-plugin": "14.0.0", + "css-loader": "7.1.3", + "esbuild-wasm": "0.27.3", + "http-proxy-middleware": "3.0.5", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "karma-source-map-support": "1.4.0", + "less": "4.4.2", + "less-loader": "12.3.1", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.3.1", + "mini-css-extract-plugin": "2.10.0", + "open": "11.0.0", + "ora": "9.3.0", + "picomatch": "4.0.4", + "piscina": "5.1.4", + "postcss": "8.5.6", + "postcss-loader": "8.2.0", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.2", + "sass": "1.97.3", + "sass-loader": "16.0.7", + "semver": "7.7.4", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.46.0", + "tinyglobby": "0.2.15", + "tree-kill": "1.2.2", + "tslib": "2.8.1", + "webpack": "5.105.2", + "webpack-dev-middleware": "7.4.5", + "webpack-dev-server": "5.2.3", + "webpack-merge": "6.0.1", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.27.3" + }, + "peerDependencies": { + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.6", + "@web/test-runner": "^0.20.0", + "browser-sync": "^3.0.2", + "jest": "^30.2.0", + "jest-environment-jsdom": "^30.2.0", + "karma": "^6.3.0", + "ng-packagr": "^21.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "typescript": ">=5.9 <6.0" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { + "version": "0.2102.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.6.tgz", + "integrity": "sha512-h4qybKypR7OuwcTHPQI1zRm7abXgmPiV49vI2UeMtVVY/GKzru9gMexcYmWabzEyBY8w6VSfWjV2X+eit2EhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.6", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { + "version": "21.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.6.tgz", + "integrity": "sha512-u5gPTAY7MC02uACQE39xxiFcm1hslF+ih/f2borMWnhER0JNTpHjLiLRXFkq7or7+VVHU30zfhK4XNAuO4WTIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "version": "21.2.6", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.6.tgz", + "integrity": "sha512-PJltYl9/INfz8nZ/KHf39nqlmt3c9PR0jJaZt6hhCPENyAf4PwQpm28erkJmbOYO864goIuws41lduYXyDqQ0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.6", + "@babel/core": "7.29.0", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "5.1.21", + "@vitejs/plugin-basic-ssl": "2.1.4", + "beasties": "0.4.1", + "browserslist": "^4.26.0", + "esbuild": "0.27.3", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "magic-string": "0.30.21", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "8.0.0", + "picomatch": "4.0.4", + "piscina": "5.1.4", + "rolldown": "1.0.0-rc.4", + "sass": "1.97.3", + "semver": "7.7.4", + "source-map-support": "0.5.21", + "tinyglobby": "0.2.15", + "undici": "7.24.4", + "vite": "7.3.1", + "watchpack": "2.5.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "lmdb": "3.5.1" + }, + "peerDependencies": { + "@angular/compiler": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.6", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^21.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.9 <6.0", + "vitest": "^4.0.8" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/preset-env": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.0.tgz", + "integrity": "sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/runtime": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", + "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", + "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", + "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", + "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", + "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", + "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", + "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular-devkit/build-angular/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", + "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@oxc-project/types": { + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", + "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", + "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", + "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", + "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/babel-loader": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", + "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": "^18.20.0 || ^20.10.0 || >=22.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5.61.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/beasties": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", + "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3", + "postcss-safe-parser": "^7.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/copy-webpack-plugin": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-14.0.0.tgz", + "integrity": "sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-parent": "^6.0.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^7.0.3", + "tinyglobby": "^0.2.12" + }, + "engines": { + "node": ">= 20.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/css-loader": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.3.tgz", + "integrity": "sha512-frbERmjT0UC5lMheWpJmMilnt9GEhbZJN/heUb7/zaJYeIzj5St9HvDcfshzzOqbsS+rYpMk++2SD3vGETDSyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.40", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-angular/node_modules/less": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz", + "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/less-loader": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.3.1.tgz", + "integrity": "sha512-JZZmG7gMzoDP3VGeEG8Sh6FW5wygB5jYL7Wp29FFihuRTsIBacqO3LbRPr2yStYD11riVf13selLm/CPFRDBRQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/lmdb": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", + "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@harperfast/extended-iterable": "^1.0.3", + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.5.1", + "@lmdb/lmdb-darwin-x64": "3.5.1", + "@lmdb/lmdb-linux-arm": "3.5.1", + "@lmdb/lmdb-linux-arm64": "3.5.1", + "@lmdb/lmdb-linux-x64": "3.5.1", + "@lmdb/lmdb-win32-arm64": "3.5.1", + "@lmdb/lmdb-win32-x64": "3.5.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/mini-css-extract-plugin": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", + "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@angular-devkit/build-angular/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ora": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", + "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss-loader": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.2.0.tgz", + "integrity": "sha512-tHX+RkpsXVcc7st4dSdDGliI+r4aAQDuv+v3vFYHixb6YgjreG5AG4SEB0kDK8u2s6htqEEpKlkhSBUTvWKYnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^2.5.1", + "semver": "^7.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rolldown": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", + "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.113.0", + "@rolldown/pluginutils": "1.0.0-rc.4" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-x64": "1.0.0-rc.4", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/stdin-discarder": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz", + "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/string-width": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack": { + "version": "5.105.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", + "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.2102.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2102.6.tgz", + "integrity": "sha512-IN0xUlFTOmDt+UrW1X7ymYgp94Y/HfMj4zNahplBEbBl72WmqQdJGiDMThGgFY+RzJJMyAbqD7RDyiimsVkfOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.2102.6", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { + "version": "0.2102.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.6.tgz", + "integrity": "sha512-h4qybKypR7OuwcTHPQI1zRm7abXgmPiV49vI2UeMtVVY/GKzru9gMexcYmWabzEyBY8w6VSfWjV2X+eit2EhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.6", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { + "version": "21.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.6.tgz", + "integrity": "sha512-u5gPTAY7MC02uACQE39xxiFcm1hslF+ih/f2borMWnhER0JNTpHjLiLRXFkq7or7+VVHU30zfhK4XNAuO4WTIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/build-webpack/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/@angular-devkit/core": { "version": "21.1.5", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.1.5.tgz", @@ -4636,6 +6918,16 @@ "node": ">= 6" } }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17.0" + } + }, "node_modules/@emnapi/core": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", @@ -5407,6 +7699,14 @@ "@types/hast": "^3.0.4" } }, + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, "node_modules/@hono/node-server": { "version": "1.19.11", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", @@ -8878,6 +11178,23 @@ "node": ">= 10" } }, + "node_modules/@ngtools/webpack": { + "version": "21.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-21.2.6.tgz", + "integrity": "sha512-SU6aMvFz/0uM2WhIGrZ/QexEIqT/VdLfcmy7OYAxOd3w7u2wqQao/1uSOEJo+BR+B48QYf7Z5LLpS8t1mWZYKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^21.0.0", + "typescript": ">=5.9 <6.0", + "webpack": "^5.54.0" + } + }, "node_modules/@noble/hashes": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", @@ -18302,6 +20619,20 @@ "node": ">= 10.0.0" } }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, "node_modules/adm-zip": { "version": "0.5.16", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", @@ -21572,6 +23903,19 @@ "@esbuild/win32-x64": "0.27.4" } }, + "node_modules/esbuild-wasm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.27.3.tgz", + "integrity": "sha512-AUXuOxZ145/5Az+lIqk6TdJbxKTyDGkXMJpTExmBdbnHR6n6qAFx+F4oG9ORpVYJ9dQYeQAqzv51TO4DFKsbXw==", + "dev": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -24605,6 +26949,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -25537,6 +27894,16 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map-support": "^0.5.5" + } + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", @@ -30670,6 +33037,33 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, "node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -30806,6 +33200,19 @@ "dev": true, "license": "MIT" }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -31329,6 +33736,13 @@ "regex-utilities": "^2.3.0" } }, + "node_modules/regex-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", + "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/regex-recursion": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", @@ -31584,6 +33998,30 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve.exports": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", diff --git a/package.json b/package.json index b9680e157..6de2106fa 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "private": true, "devDependencies": { + "@angular-devkit/build-angular": "^21.2.6", "@angular-devkit/core": "~21.1.0", "@angular-devkit/schematics": "~21.1.0", "@angular/build": "~21.1.0",