feat: ci complexity linters (#236)
This commit is contained in:
@@ -51,6 +51,7 @@ jobs:
|
||||
version: v2.9
|
||||
args: ./...
|
||||
working-directory: apps/backend
|
||||
only-new-issues: true
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
|
||||
@@ -5,19 +5,18 @@
|
||||
## Repo Layout
|
||||
|
||||
```
|
||||
kandev-3/
|
||||
├── apps/
|
||||
│ ├── backend/ # Go backend (orchestrator, lifecycle, agentctl, WS gateway)
|
||||
│ ├── web/ # Next.js frontend (SSR + WS + Zustand)
|
||||
│ ├── packages/ # Shared packages/types
|
||||
│ └── landing/ # Marketing site (shares UI with web)
|
||||
apps/
|
||||
├── backend/ # Go backend (orchestrator, lifecycle, agentctl, WS gateway)
|
||||
├── web/ # Next.js frontend (SSR + WS + Zustand)
|
||||
├── cli/ # CLI tool (TypeScript)
|
||||
└── packages/ # Shared packages/types
|
||||
```
|
||||
|
||||
## Tooling
|
||||
|
||||
- **Package manager**: `pnpm` workspace (root)
|
||||
- **Package manager**: `pnpm` workspace (run from `apps/`, not repo root)
|
||||
- **Backend**: Go with Make (`make -C apps/backend test|lint|build`)
|
||||
- **Frontend**: Next.js (`pnpm -C apps/web dev|lint|typecheck`)
|
||||
- **Frontend**: Next.js (`cd apps && pnpm --filter @kandev/web dev|lint|typecheck`)
|
||||
- **UI**: Shadcn components via `@kandev/ui`
|
||||
|
||||
---
|
||||
@@ -30,31 +29,64 @@ kandev-3/
|
||||
apps/backend/
|
||||
├── cmd/
|
||||
│ ├── kandev/ # Main backend binary entry point
|
||||
│ └── agentctl/ # Agentctl binary (runs inside containers or standalone)
|
||||
│ ├── agentctl/ # Agentctl binary (runs inside containers or standalone)
|
||||
│ └── mock-agent/ # Mock agent for testing
|
||||
├── internal/
|
||||
│ ├── agent/
|
||||
│ │ ├── lifecycle/ # Agent instance management (see below)
|
||||
│ │ ├── agents/ # Agent type implementations
|
||||
│ │ ├── controller/ # Agent control operations
|
||||
│ │ ├── credentials/ # Agent credential management
|
||||
│ │ ├── discovery/ # Agent discovery
|
||||
│ │ ├── docker/ # Docker-specific agent logic
|
||||
│ │ ├── dto/ # Agent data transfer objects
|
||||
│ │ ├── handlers/ # Agent event handlers
|
||||
│ │ ├── registry/ # Agent type registry and defaults
|
||||
│ │ ├── runtime/ # Runtime name constants
|
||||
│ │ ├── settings/ # Agent settings
|
||||
│ │ └── mcpconfig/ # MCP server configuration
|
||||
│ ├── agentctl/
|
||||
│ │ ├── client/ # HTTP client for talking to agentctl
|
||||
│ │ └── server/ # agentctl HTTP server
|
||||
│ │ ├── api/ # HTTP endpoints
|
||||
│ │ ├── adapter/ # Protocol adapters (ACP, Codex, Copilot, Amp)
|
||||
│ │ ├── instance/ # Multi-instance management
|
||||
│ │ ├── mcp/ # MCP server integration
|
||||
│ │ ├── process/ # Agent subprocess management
|
||||
│ │ └── adapter/ # Protocol adapters (ACP, Codex, REST, MCP)
|
||||
│ │ └── shell/ # Shell session management
|
||||
│ ├── orchestrator/ # Task execution coordination
|
||||
│ │ ├── executor/ # Launches agents via lifecycle manager
|
||||
│ │ ├── scheduler/ # Task scheduling
|
||||
│ │ ├── handlers/ # Orchestrator event handlers
|
||||
│ │ ├── messagequeue/ # Message queue for agent prompts
|
||||
│ │ ├── queue/ # Task queue
|
||||
│ │ ├── scheduler/ # Task scheduling
|
||||
│ │ └── watcher/ # Event handlers
|
||||
│ ├── task/
|
||||
│ │ ├── controller/ # Task HTTP/WS controllers
|
||||
│ │ ├── dto/ # Task data transfer objects
|
||||
│ │ ├── events/ # Task event types
|
||||
│ │ ├── handlers/ # Task event handlers
|
||||
│ │ ├── models/ # Task, Session, Executor, Message models
|
||||
│ │ ├── service/ # Task business logic
|
||||
│ │ └── repository/ # Database access (SQLite)
|
||||
│ ├── worktree/ # Git worktree management for workspace isolation
|
||||
│ └── events/ # Event bus for internal pub/sub
|
||||
│ │ ├── repository/ # Database access (SQLite)
|
||||
│ │ └── service/ # Task business logic
|
||||
│ ├── analytics/ # Usage analytics
|
||||
│ ├── clarification/ # Agent clarification handling
|
||||
│ ├── common/ # Shared utilities
|
||||
│ ├── db/ # Database initialization
|
||||
│ ├── debug/ # Debug tooling
|
||||
│ ├── editors/ # Editor integration
|
||||
│ ├── events/ # Event bus for internal pub/sub
|
||||
│ ├── gateway/ # WebSocket gateway
|
||||
│ ├── integration/ # External integrations
|
||||
│ ├── lsp/ # LSP server
|
||||
│ ├── mcp/ # MCP protocol support
|
||||
│ ├── notifications/ # Notification system
|
||||
│ ├── persistence/ # Persistence layer
|
||||
│ ├── prompts/ # Prompt management
|
||||
│ ├── sysprompt/ # System prompt injection
|
||||
│ ├── user/ # User management
|
||||
│ ├── workflow/ # Workflow engine
|
||||
│ └── worktree/ # Git worktree management for workspace isolation
|
||||
```
|
||||
|
||||
### Key Concepts
|
||||
@@ -66,13 +98,15 @@ apps/backend/
|
||||
- Located in `internal/orchestrator/`
|
||||
|
||||
**Lifecycle Manager** (`internal/agent/lifecycle/`) manages agent instances:
|
||||
- `Manager` - central coordinator for agent lifecycle
|
||||
- `Runtime` interface - abstracts execution environment (Docker, Standalone)
|
||||
- `ExecutionStore` - thread-safe in-memory execution tracking
|
||||
- `SessionManager` - ACP session initialization and resume
|
||||
- `StreamManager` - WebSocket stream connections to agentctl
|
||||
- `EventPublisher` - publishes events to the event bus
|
||||
- `ContainerManager` - Docker container operations
|
||||
- `Manager` (`manager.go`) - central coordinator for agent lifecycle
|
||||
- `Runtime` interface (`runtime.go`) - abstracts execution environment (Docker, Standalone, Remote Docker)
|
||||
- `ExecutionStore` (`execution_store.go`) - thread-safe in-memory execution tracking
|
||||
- `session.go` - ACP session initialization and resume
|
||||
- `streams.go` - WebSocket stream connections to agentctl
|
||||
- `events.go` - publishes events to the event bus
|
||||
- `container.go` - Docker container operations
|
||||
- `process_runner.go` - agent process launch and management
|
||||
- `profile_resolver.go` - resolves agent profiles/settings
|
||||
|
||||
**agentctl** is an HTTP server that:
|
||||
- Runs inside Docker containers or as standalone process
|
||||
@@ -148,9 +182,12 @@ Client (WS) Orchestrator Lifecycle Manager Runtime age
|
||||
|
||||
Protocol adapters normalize different agent CLIs:
|
||||
- `AgentAdapter` interface defines `Start()`, `Stop()`, `Prompt()`, `Cancel()`
|
||||
- `ACPAdapter` - ACP JSON-RPC over stdio
|
||||
- `CodexAdapter` - Codex-style JSON-RPC
|
||||
- `ACP` - ACP JSON-RPC over stdio (Claude Code)
|
||||
- `Codex` - Codex-style JSON-RPC (OpenAI Codex)
|
||||
- `CopilotAdapter` - GitHub Copilot SDK
|
||||
- `AmpAdapter` - Sourcegraph Amp CLI
|
||||
- `process.Manager` owns subprocess, wires stdio to adapter
|
||||
- Factory pattern in `adapter/factory.go` selects adapter by agent type
|
||||
|
||||
---
|
||||
|
||||
@@ -196,19 +233,22 @@ SSR Fetch -> Hydrate Store -> Components Read Store -> Hooks Subscribe
|
||||
|
||||
```
|
||||
lib/state/
|
||||
├── store.ts (~370 lines) # Root composition
|
||||
├── store.ts # Root composition
|
||||
├── slices/ # Domain slices
|
||||
│ ├── kanban/ # boards, tasks, columns
|
||||
│ ├── session/ # sessions, messages, turns, worktrees
|
||||
│ ├── session-runtime/ # shell, processes, git, context
|
||||
│ ├── workspace/ # workspaces, repos, branches
|
||||
│ ├── settings/ # executors, agents, editors, prompts
|
||||
│ ├── diff-comments/ # code review diff comments
|
||||
│ └── ui/ # preview, connection, active state
|
||||
├── hydration/ # SSR merge strategies
|
||||
└── selectors/ # Memoized selectors (future)
|
||||
|
||||
hooks/domains/{kanban,session,workspace,settings}/ # Domain-organized hooks
|
||||
lib/api/domains/{kanban,session,workspace,settings,process}-api.ts # API clients
|
||||
lib/api/domains/ # API clients
|
||||
├── kanban-api, session-api, workspace-api, settings-api, process-api
|
||||
├── plan-api, queue-api, workflow-api, stats-api
|
||||
├── user-shell-api, debug-api
|
||||
```
|
||||
|
||||
**Key State Paths:**
|
||||
@@ -222,12 +262,31 @@ lib/api/domains/{kanban,session,workspace,settings,process}-api.ts # API client
|
||||
|
||||
### WS
|
||||
|
||||
**Format:** `{id, type, action, payload, timestamp}`. See `docs/asyncapi.yaml` for all actions.
|
||||
**Format:** `{id, type, action, payload, timestamp}`.
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Code Quality (enforced by linters)
|
||||
|
||||
Static analysis runs in CI and pre-commit. New code **must** stay within these limits:
|
||||
|
||||
**Go** (`apps/backend/.golangci.yml` — errors on new code only):
|
||||
- Functions: **≤80 lines**, **≤50 statements**
|
||||
- Cyclomatic complexity: **≤15** · Cognitive complexity: **≤30**
|
||||
- Nesting depth: **≤5** · Naked returns only in functions **≤30 lines**
|
||||
- No duplicated blocks (**≥150 tokens**) · Repeated strings → constants (**≥3 occurrences**)
|
||||
|
||||
**TypeScript** (`apps/web/eslint.config.mjs` — warnings, will become errors):
|
||||
- Files: **≤600 lines** · Functions: **≤100 lines**
|
||||
- Cyclomatic complexity: **≤15** · Cognitive complexity: **≤20**
|
||||
- Nesting depth: **≤4** · Parameters: **≤5**
|
||||
- No duplicated strings (**≥4 occurrences**) · No identical functions · No unused imports
|
||||
- No nested ternaries
|
||||
|
||||
**When you hit a limit:** extract a helper function, custom hook, or sub-component. Prefer composition over growing a single function.
|
||||
|
||||
### Backend
|
||||
- Provider pattern for DI; stderr for logs, stdout for ACP only
|
||||
- Pass context through chains; event bus for cross-component comm
|
||||
@@ -250,4 +309,10 @@ lib/api/domains/{kanban,session,workspace,settings,process}-api.ts # API client
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-01
|
||||
## Maintaining This File
|
||||
|
||||
This file is read by AI coding agents (Claude Code via `CLAUDE.md` symlink, Codex via `AGENTS.md`). If your changes make any section of this file outdated or inaccurate — e.g., you add/remove/rename packages, change architectural patterns, add new adapters, modify store slices, or change conventions — **update the relevant sections of this file as part of the same PR**. Keep descriptions concise and factual. Do not add speculative or aspirational content.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-17
|
||||
|
||||
@@ -1,2 +1,50 @@
|
||||
version: "2"
|
||||
# Default golangci-lint configuration (uses built-in defaults).
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- funlen
|
||||
- cyclop
|
||||
- gocognit
|
||||
- nestif
|
||||
- dupl
|
||||
- goconst
|
||||
- gocritic
|
||||
- misspell
|
||||
- nakedret
|
||||
- unconvert
|
||||
- dupword
|
||||
- maintidx
|
||||
|
||||
settings:
|
||||
funlen:
|
||||
lines: 80
|
||||
statements: 50
|
||||
cyclop:
|
||||
max-complexity: 15
|
||||
gocognit:
|
||||
min-complexity: 30
|
||||
nestif:
|
||||
min-complexity: 5
|
||||
dupl:
|
||||
threshold: 150
|
||||
goconst:
|
||||
min-occurrences: 3
|
||||
min-len: 3
|
||||
nakedret:
|
||||
max-func-lines: 30
|
||||
maintidx:
|
||||
under: 15
|
||||
|
||||
exclusions:
|
||||
rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- funlen
|
||||
- cyclop
|
||||
- gocognit
|
||||
- dupl
|
||||
- goconst
|
||||
- maintidx
|
||||
|
||||
issues:
|
||||
new: true
|
||||
|
||||
Generated
+171
-13
@@ -373,7 +373,7 @@ importers:
|
||||
version: 0.55.1
|
||||
next:
|
||||
specifier: 16.1.1
|
||||
version: 16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
version: 16.1.1(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
@@ -412,7 +412,7 @@ importers:
|
||||
version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
|
||||
styled-jsx:
|
||||
specifier: 5.1.6
|
||||
version: 5.1.6(react@19.2.3)
|
||||
version: 5.1.6(@babel/core@7.28.6)(react@19.2.3)
|
||||
tailwind-merge:
|
||||
specifier: ^3.4.0
|
||||
version: 3.4.0
|
||||
@@ -453,6 +453,12 @@ importers:
|
||||
eslint-config-next:
|
||||
specifier: 16.1.1
|
||||
version: 16.1.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint-plugin-sonarjs:
|
||||
specifier: ^3.0.7
|
||||
version: 3.0.7(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-unused-imports:
|
||||
specifier: ^4.4.1
|
||||
version: 4.4.1(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))
|
||||
happy-dom:
|
||||
specifier: ^20.1.0
|
||||
version: 20.1.0
|
||||
@@ -1157,89 +1163,105 @@ packages:
|
||||
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-arm@1.2.4':
|
||||
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-ppc64@1.2.4':
|
||||
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-riscv64@1.2.4':
|
||||
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-s390x@1.2.4':
|
||||
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linux-x64@1.2.4':
|
||||
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
|
||||
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
|
||||
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linux-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-arm@0.34.5':
|
||||
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-ppc64@0.34.5':
|
||||
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-riscv64@0.34.5':
|
||||
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-s390x@0.34.5':
|
||||
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linux-x64@0.34.5':
|
||||
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@img/sharp-linuxmusl-arm64@0.34.5':
|
||||
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-linuxmusl-x64@0.34.5':
|
||||
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@img/sharp-wasm32@0.34.5':
|
||||
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
|
||||
@@ -1307,6 +1329,10 @@ packages:
|
||||
resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
'@isaacs/brace-expansion@5.0.1':
|
||||
resolution: {integrity: sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@@ -1429,24 +1455,28 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-arm64-musl@16.1.1':
|
||||
resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-linux-x64-gnu@16.1.1':
|
||||
resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@next/swc-linux-x64-musl@16.1.1':
|
||||
resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@16.1.1':
|
||||
resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==}
|
||||
@@ -2278,66 +2308,79 @@ packages:
|
||||
resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.55.1':
|
||||
resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.55.1':
|
||||
resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.55.1':
|
||||
resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.55.1':
|
||||
resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==}
|
||||
@@ -2455,24 +2498,28 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.1.18':
|
||||
resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.1.18':
|
||||
resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.1.18':
|
||||
resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==}
|
||||
@@ -3061,41 +3108,49 @@ packages:
|
||||
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
|
||||
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
|
||||
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
|
||||
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
|
||||
@@ -3301,6 +3356,10 @@ packages:
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
|
||||
builtin-modules@3.3.0:
|
||||
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
bundle-name@4.1.0:
|
||||
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -3995,6 +4054,20 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
|
||||
|
||||
eslint-plugin-sonarjs@3.0.7:
|
||||
resolution: {integrity: sha512-62jB20krIPvcwBLAyG3VVKa2ce2j2lL1yCb8Y0ylMRR/dLvCCTiQx8gQbXb+G81k1alPZ2/I3muZinqWQdBbzw==}
|
||||
peerDependencies:
|
||||
eslint: ^8.0.0 || ^9.0.0
|
||||
|
||||
eslint-plugin-unused-imports@4.4.1:
|
||||
resolution: {integrity: sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ==}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0
|
||||
eslint: ^10.0.0 || ^9.0.0 || ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
optional: true
|
||||
|
||||
eslint-scope@8.4.0:
|
||||
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -4187,6 +4260,9 @@ packages:
|
||||
resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
functional-red-black-tree@1.0.1:
|
||||
resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==}
|
||||
|
||||
functions-have-names@1.2.3:
|
||||
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
||||
|
||||
@@ -4669,6 +4745,10 @@ packages:
|
||||
jsonfile@6.2.0:
|
||||
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||
|
||||
jsx-ast-utils-x@0.1.0:
|
||||
resolution: {integrity: sha512-eQQBjBnsVtGacsG9uJNB8qOr3yA8rga4wAaGG1qRcBzSIvfhERLrWxMAM1hp5fcS6Abo8M4+bUBTekYR0qTPQw==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
jsx-ast-utils@3.3.5:
|
||||
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
|
||||
engines: {node: '>=4.0'}
|
||||
@@ -4747,24 +4827,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.2:
|
||||
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.2:
|
||||
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.2:
|
||||
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
|
||||
@@ -5042,6 +5126,10 @@ packages:
|
||||
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@10.1.2:
|
||||
resolution: {integrity: sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==}
|
||||
engines: {node: 20 || >=22}
|
||||
|
||||
minimatch@3.1.2:
|
||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||
|
||||
@@ -5557,6 +5645,10 @@ packages:
|
||||
react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
refa@0.12.1:
|
||||
resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==}
|
||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5570,6 +5662,10 @@ packages:
|
||||
regex@6.1.0:
|
||||
resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==}
|
||||
|
||||
regexp-ast-analysis@0.7.1:
|
||||
resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==}
|
||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5673,6 +5769,10 @@ packages:
|
||||
scheduler@0.27.0:
|
||||
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
|
||||
|
||||
scslre@0.3.0:
|
||||
resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==}
|
||||
engines: {node: ^14.0.0 || >=16.0.0}
|
||||
|
||||
semver@6.3.1:
|
||||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
|
||||
hasBin: true
|
||||
@@ -5682,6 +5782,11 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
semver@7.7.4:
|
||||
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
send@1.2.1:
|
||||
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
||||
engines: {node: '>= 18'}
|
||||
@@ -7204,6 +7309,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@isaacs/balanced-match': 4.0.1
|
||||
|
||||
'@isaacs/brace-expansion@5.0.1':
|
||||
dependencies:
|
||||
'@isaacs/balanced-match': 4.0.1
|
||||
|
||||
'@isaacs/fs-minipass@4.0.1':
|
||||
dependencies:
|
||||
minipass: 7.1.2
|
||||
@@ -9294,6 +9403,8 @@ snapshots:
|
||||
node-releases: 2.0.27
|
||||
update-browserslist-db: 1.2.3(browserslist@4.28.1)
|
||||
|
||||
builtin-modules@3.3.0: {}
|
||||
|
||||
bundle-name@4.1.0:
|
||||
dependencies:
|
||||
run-applescript: 7.1.0
|
||||
@@ -10014,8 +10125,8 @@ snapshots:
|
||||
'@next/eslint-plugin-next': 16.1.1
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1))
|
||||
@@ -10037,7 +10148,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.3
|
||||
@@ -10048,22 +10159,22 @@ snapshots:
|
||||
tinyglobby: 0.2.15
|
||||
unrs-resolver: 1.11.1
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
|
||||
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
|
||||
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
@@ -10074,7 +10185,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
|
||||
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
@@ -10144,6 +10255,26 @@ snapshots:
|
||||
string.prototype.matchall: 4.0.12
|
||||
string.prototype.repeat: 1.0.0
|
||||
|
||||
eslint-plugin-sonarjs@3.0.7(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
builtin-modules: 3.3.0
|
||||
bytes: 3.1.2
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
functional-red-black-tree: 1.0.1
|
||||
jsx-ast-utils-x: 0.1.0
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 10.1.2
|
||||
scslre: 0.3.0
|
||||
semver: 7.7.4
|
||||
typescript: 5.9.3
|
||||
|
||||
eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)):
|
||||
dependencies:
|
||||
eslint: 9.39.2(jiti@2.6.1)
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.53.0(@typescript-eslint/parser@8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
|
||||
|
||||
eslint-scope@8.4.0:
|
||||
dependencies:
|
||||
esrecurse: 4.3.0
|
||||
@@ -10414,6 +10545,8 @@ snapshots:
|
||||
hasown: 2.0.2
|
||||
is-callable: 1.2.7
|
||||
|
||||
functional-red-black-tree@1.0.1: {}
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
fuzzysort@3.1.0: {}
|
||||
@@ -10860,6 +10993,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsx-ast-utils-x@0.1.0: {}
|
||||
|
||||
jsx-ast-utils@3.3.5:
|
||||
dependencies:
|
||||
array-includes: 3.1.9
|
||||
@@ -11431,6 +11566,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@isaacs/brace-expansion': 5.0.0
|
||||
|
||||
minimatch@10.1.2:
|
||||
dependencies:
|
||||
'@isaacs/brace-expansion': 5.0.1
|
||||
|
||||
minimatch@3.1.2:
|
||||
dependencies:
|
||||
brace-expansion: 1.1.12
|
||||
@@ -11501,7 +11640,7 @@ snapshots:
|
||||
react: 19.2.3
|
||||
react-dom: 19.2.3(react@19.2.3)
|
||||
|
||||
next@16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||
next@16.1.1(@babel/core@7.28.6)(react-dom@19.2.3(react@19.2.3))(react@19.2.3):
|
||||
dependencies:
|
||||
'@next/env': 16.1.1
|
||||
'@swc/helpers': 0.5.15
|
||||
@@ -11510,7 +11649,7 @@ snapshots:
|
||||
postcss: 8.4.31
|
||||
react: 19.2.3
|
||||
react-dom: 19.2.3(react@19.2.3)
|
||||
styled-jsx: 5.1.6(react@19.2.3)
|
||||
styled-jsx: 5.1.6(@babel/core@7.28.6)(react@19.2.3)
|
||||
optionalDependencies:
|
||||
'@next/swc-darwin-arm64': 16.1.1
|
||||
'@next/swc-darwin-x64': 16.1.1
|
||||
@@ -12088,6 +12227,10 @@ snapshots:
|
||||
tiny-invariant: 1.3.3
|
||||
victory-vendor: 36.9.2
|
||||
|
||||
refa@0.12.1:
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
@@ -12109,6 +12252,11 @@ snapshots:
|
||||
dependencies:
|
||||
regex-utilities: 2.3.0
|
||||
|
||||
regexp-ast-analysis@0.7.1:
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
refa: 0.12.1
|
||||
|
||||
regexp.prototype.flags@1.5.4:
|
||||
dependencies:
|
||||
call-bind: 1.0.8
|
||||
@@ -12272,10 +12420,18 @@ snapshots:
|
||||
|
||||
scheduler@0.27.0: {}
|
||||
|
||||
scslre@0.3.0:
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
refa: 0.12.1
|
||||
regexp-ast-analysis: 0.7.1
|
||||
|
||||
semver@6.3.1: {}
|
||||
|
||||
semver@7.7.3: {}
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
send@1.2.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
@@ -12589,10 +12745,12 @@ snapshots:
|
||||
dependencies:
|
||||
inline-style-parser: 0.2.7
|
||||
|
||||
styled-jsx@5.1.6(react@19.2.3):
|
||||
styled-jsx@5.1.6(@babel/core@7.28.6)(react@19.2.3):
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 19.2.3
|
||||
optionalDependencies:
|
||||
'@babel/core': 7.28.6
|
||||
|
||||
stylis@4.3.6: {}
|
||||
|
||||
|
||||
@@ -16,11 +16,18 @@ import { IconChevronDown, IconChevronRight, IconRefresh } from '@tabler/icons-re
|
||||
type ToolFilter = 'all' | 'tool_edit' | 'tool_read' | 'tool_execute' | 'tool_call';
|
||||
type ViewMode = 'fixtures' | 'events';
|
||||
|
||||
const TOOL_TABS: { value: ToolFilter; label: string }[] = [
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'tool_edit', label: 'Edit' },
|
||||
{ value: 'tool_read', label: 'Read' },
|
||||
{ value: 'tool_execute', label: 'Execute' },
|
||||
{ value: 'tool_call', label: 'Call' },
|
||||
];
|
||||
|
||||
function fixtureToMessage(fixture: NormalizedFixture, index: number): Message {
|
||||
const payload = fixture.payload as Record<string, unknown>;
|
||||
const toolType = fixture.tool_type as MessageType;
|
||||
|
||||
// Build content based on tool type
|
||||
let content = '';
|
||||
if (payload.file_path) {
|
||||
content = `${fixture.tool_type}: ${payload.file_path}`;
|
||||
@@ -46,6 +53,102 @@ function fixtureToMessage(fixture: NormalizedFixture, index: number): Message {
|
||||
};
|
||||
}
|
||||
|
||||
// --- Hooks ---
|
||||
|
||||
function useAgentMessages() {
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('events');
|
||||
const [fixtureFiles, setFixtureFiles] = useState<DiscoveredFile[]>([]);
|
||||
const [selectedFixtureFile, setSelectedFixtureFile] = useState<string>('');
|
||||
const [fixtures, setFixtures] = useState<NormalizedFixture[]>([]);
|
||||
const [eventFiles, setEventFiles] = useState<DiscoveredFile[]>([]);
|
||||
const [selectedEventFile, setSelectedEventFile] = useState<string>('');
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [toolFilter, setToolFilter] = useState<ToolFilter>('all');
|
||||
|
||||
useEffect(() => {
|
||||
async function loadFiles() {
|
||||
try {
|
||||
const [fixtureFilesData, eventFilesData] = await Promise.all([
|
||||
fetchFixtureFiles(),
|
||||
fetchNormalizedFiles(),
|
||||
]);
|
||||
setFixtureFiles(fixtureFilesData);
|
||||
setEventFiles(eventFilesData);
|
||||
if (eventFilesData.length > 0 && !selectedEventFile) {
|
||||
setSelectedEventFile(eventFilesData[0].path);
|
||||
}
|
||||
if (fixtureFilesData.length > 0 && !selectedFixtureFile) {
|
||||
setSelectedFixtureFile(fixtureFilesData[0].path);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load files');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadFiles();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadFixtures = useCallback(async () => {
|
||||
if (!selectedFixtureFile) return;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await fetchNormalizedMessages(selectedFixtureFile);
|
||||
setFixtures(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load fixtures');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedFixtureFile]);
|
||||
|
||||
const loadMessages = useCallback(async () => {
|
||||
if (!selectedEventFile) return;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await fetchNormalizedEventsAsMessages(selectedEventFile);
|
||||
setMessages(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load messages');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedEventFile]);
|
||||
|
||||
useEffect(() => {
|
||||
if (viewMode === 'fixtures' && selectedFixtureFile) {
|
||||
loadFixtures();
|
||||
} else if (viewMode === 'events' && selectedEventFile) {
|
||||
loadMessages();
|
||||
}
|
||||
}, [viewMode, selectedFixtureFile, selectedEventFile, loadFixtures, loadMessages]);
|
||||
|
||||
const filteredFixtures = fixtures.filter((f) => toolFilter === 'all' || f.tool_type === toolFilter);
|
||||
const currentFiles = viewMode === 'fixtures' ? fixtureFiles : eventFiles;
|
||||
const selectedFile = viewMode === 'fixtures' ? selectedFixtureFile : selectedEventFile;
|
||||
const setSelectedFile = viewMode === 'fixtures' ? setSelectedFixtureFile : setSelectedEventFile;
|
||||
const loadContent = viewMode === 'fixtures' ? loadFixtures : loadMessages;
|
||||
const itemCount = viewMode === 'fixtures' ? filteredFixtures.length : messages.length;
|
||||
const totalCount = viewMode === 'fixtures' ? fixtures.length : messages.length;
|
||||
|
||||
return {
|
||||
viewMode, setViewMode,
|
||||
loading, error,
|
||||
toolFilter, setToolFilter,
|
||||
currentFiles, selectedFile, setSelectedFile,
|
||||
loadContent,
|
||||
filteredFixtures, messages,
|
||||
itemCount, totalCount,
|
||||
};
|
||||
}
|
||||
|
||||
// --- UI Components ---
|
||||
|
||||
function JsonPanel({ title, data, defaultExpanded = false }: { title: string; data: unknown; defaultExpanded?: boolean }) {
|
||||
const [expanded, setExpanded] = useState(defaultExpanded);
|
||||
|
||||
@@ -72,7 +175,6 @@ function FixtureCard({ fixture, index }: { fixture: NormalizedFixture; index: nu
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg overflow-hidden bg-card">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-2 bg-muted/30 border-b flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs font-mono px-2 py-0.5 rounded bg-primary/10 text-primary">
|
||||
@@ -86,18 +188,10 @@ function FixtureCard({ fixture, index }: { fixture: NormalizedFixture; index: nu
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Rendered Message */}
|
||||
<div className="p-4 border-b">
|
||||
<div className="text-xs text-muted-foreground mb-2 font-medium">Rendered Output:</div>
|
||||
<MessageRenderer
|
||||
comment={message}
|
||||
isTaskDescription={false}
|
||||
taskId="demo-task"
|
||||
/>
|
||||
<MessageRenderer comment={message} isTaskDescription={false} taskId="demo-task" />
|
||||
</div>
|
||||
|
||||
{/* JSON Panels */}
|
||||
<div className="p-4 space-y-2">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<JsonPanel title="Raw Input" data={fixture.input} />
|
||||
@@ -114,7 +208,6 @@ function MessageCard({ message }: { message: Message }) {
|
||||
|
||||
return (
|
||||
<div className="border rounded-lg overflow-hidden bg-card">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-2 bg-muted/30 border-b flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xs font-mono px-2 py-0.5 rounded bg-primary/10 text-primary">
|
||||
@@ -132,8 +225,6 @@ function MessageCard({ message }: { message: Message }) {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Rendered Message */}
|
||||
<div className="p-4 border-b">
|
||||
<div className="text-xs text-muted-foreground mb-2 font-medium">Rendered Output:</div>
|
||||
<MessageRenderer
|
||||
@@ -142,8 +233,6 @@ function MessageCard({ message }: { message: Message }) {
|
||||
taskId={message.task_id || 'demo-task'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* JSON Panel */}
|
||||
<div className="p-4">
|
||||
<JsonPanel title="Message Data" data={message} />
|
||||
</div>
|
||||
@@ -151,126 +240,154 @@ function MessageCard({ message }: { message: Message }) {
|
||||
);
|
||||
}
|
||||
|
||||
function ViewModeTabs({ viewMode, setViewMode }: { viewMode: ViewMode; setViewMode: (v: ViewMode) => void }) {
|
||||
return (
|
||||
<div className="mb-6">
|
||||
<div className="flex gap-1 p-1 bg-muted/30 rounded-lg w-fit">
|
||||
{(['events', 'fixtures'] as const).map((mode) => (
|
||||
<button
|
||||
key={mode}
|
||||
onClick={() => setViewMode(mode)}
|
||||
className={`px-4 py-2 text-sm rounded-md transition-colors ${
|
||||
viewMode === mode
|
||||
? 'bg-background shadow-sm font-medium'
|
||||
: 'hover:bg-muted/50 text-muted-foreground'
|
||||
}`}
|
||||
>
|
||||
{mode === 'events' ? 'Normalized Events' : 'Test Fixtures'}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FiltersBar({
|
||||
viewMode, currentFiles, selectedFile, setSelectedFile, toolFilter, setToolFilter,
|
||||
}: {
|
||||
viewMode: ViewMode;
|
||||
currentFiles: DiscoveredFile[];
|
||||
selectedFile: string;
|
||||
setSelectedFile: (v: string) => void;
|
||||
toolFilter: ToolFilter;
|
||||
setToolFilter: (v: ToolFilter) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="mb-6 space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
{viewMode === 'events' ? 'Event File:' : 'Fixture File:'}
|
||||
</span>
|
||||
<select
|
||||
value={selectedFile}
|
||||
onChange={(e) => setSelectedFile(e.target.value)}
|
||||
className="px-3 py-1.5 text-sm rounded-md border bg-background hover:bg-muted/50 transition-colors min-w-[300px]"
|
||||
>
|
||||
{currentFiles.length === 0 && <option value="">No files found</option>}
|
||||
{currentFiles.map((file) => (
|
||||
<option key={file.path} value={file.path}>
|
||||
{file.protocol} - {file.agent || 'unknown'} ({file.message_count} messages)
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
{viewMode === 'fixtures' && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-muted-foreground">Tool Type:</span>
|
||||
<div className="flex gap-1">
|
||||
{TOOL_TABS.map((tab) => (
|
||||
<button
|
||||
key={tab.value}
|
||||
onClick={() => setToolFilter(tab.value)}
|
||||
className={`px-3 py-1.5 text-sm rounded-md transition-colors ${
|
||||
toolFilter === tab.value
|
||||
? 'bg-secondary text-secondary-foreground'
|
||||
: 'hover:bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ContentArea({
|
||||
viewMode, loading, error, itemCount, filteredFixtures, messages,
|
||||
}: {
|
||||
viewMode: ViewMode;
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
itemCount: number;
|
||||
filteredFixtures: NormalizedFixture[];
|
||||
messages: Message[];
|
||||
}) {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<IconRefresh className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-destructive">
|
||||
<div className="font-medium">Error loading {viewMode}</div>
|
||||
<div className="text-sm">{error}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (itemCount === 0) {
|
||||
return (
|
||||
<div className="text-center py-12 text-muted-foreground">
|
||||
{viewMode === 'events'
|
||||
? 'No normalized event files found. Run an agent with KANDEV_DEBUG_AGENT_MESSAGES=1 to generate event logs.'
|
||||
: 'No fixtures found. Select a fixture file from the dropdown above.'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (viewMode === 'fixtures') {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{filteredFixtures.map((fixture, index) => (
|
||||
<FixtureCard key={index} fixture={fixture} index={index} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{messages.map((message, index) => (
|
||||
<MessageCard key={message.id || index} message={message} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// --- Page ---
|
||||
|
||||
export default function AgentMessagesPage() {
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('events');
|
||||
|
||||
// Fixture mode state
|
||||
const [fixtureFiles, setFixtureFiles] = useState<DiscoveredFile[]>([]);
|
||||
const [selectedFixtureFile, setSelectedFixtureFile] = useState<string>('');
|
||||
const [fixtures, setFixtures] = useState<NormalizedFixture[]>([]);
|
||||
|
||||
// Events mode state
|
||||
const [eventFiles, setEventFiles] = useState<DiscoveredFile[]>([]);
|
||||
const [selectedEventFile, setSelectedEventFile] = useState<string>('');
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
|
||||
// Shared state
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [toolFilter, setToolFilter] = useState<ToolFilter>('all');
|
||||
|
||||
// Load available files on mount
|
||||
useEffect(() => {
|
||||
async function loadFiles() {
|
||||
try {
|
||||
// Load both fixture files and normalized event files
|
||||
const [fixtureFilesData, eventFilesData] = await Promise.all([
|
||||
fetchFixtureFiles(),
|
||||
fetchNormalizedFiles(),
|
||||
]);
|
||||
setFixtureFiles(fixtureFilesData);
|
||||
setEventFiles(eventFilesData);
|
||||
|
||||
// Auto-select first file based on current mode
|
||||
if (eventFilesData.length > 0 && !selectedEventFile) {
|
||||
setSelectedEventFile(eventFilesData[0].path);
|
||||
}
|
||||
if (fixtureFilesData.length > 0 && !selectedFixtureFile) {
|
||||
setSelectedFixtureFile(fixtureFilesData[0].path);
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load files');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
loadFiles();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const loadFixtures = useCallback(async () => {
|
||||
if (!selectedFixtureFile) return;
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await fetchNormalizedMessages(selectedFixtureFile);
|
||||
setFixtures(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load fixtures');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedFixtureFile]);
|
||||
|
||||
const loadMessages = useCallback(async () => {
|
||||
if (!selectedEventFile) return;
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await fetchNormalizedEventsAsMessages(selectedEventFile);
|
||||
setMessages(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to load messages');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [selectedEventFile]);
|
||||
|
||||
// Load content when selected file changes
|
||||
useEffect(() => {
|
||||
if (viewMode === 'fixtures' && selectedFixtureFile) {
|
||||
loadFixtures();
|
||||
} else if (viewMode === 'events' && selectedEventFile) {
|
||||
loadMessages();
|
||||
}
|
||||
}, [viewMode, selectedFixtureFile, selectedEventFile, loadFixtures, loadMessages]);
|
||||
|
||||
const filteredFixtures = fixtures.filter((f) => {
|
||||
if (toolFilter === 'all') return true;
|
||||
return f.tool_type === toolFilter;
|
||||
});
|
||||
|
||||
const currentFiles = viewMode === 'fixtures' ? fixtureFiles : eventFiles;
|
||||
const selectedFile = viewMode === 'fixtures' ? selectedFixtureFile : selectedEventFile;
|
||||
const setSelectedFile = viewMode === 'fixtures' ? setSelectedFixtureFile : setSelectedEventFile;
|
||||
const loadContent = viewMode === 'fixtures' ? loadFixtures : loadMessages;
|
||||
|
||||
const toolTabs: { value: ToolFilter; label: string }[] = [
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'tool_edit', label: 'Edit' },
|
||||
{ value: 'tool_read', label: 'Read' },
|
||||
{ value: 'tool_execute', label: 'Execute' },
|
||||
{ value: 'tool_call', label: 'Call' },
|
||||
];
|
||||
|
||||
const itemCount = viewMode === 'fixtures' ? filteredFixtures.length : messages.length;
|
||||
const totalCount = viewMode === 'fixtures' ? fixtures.length : messages.length;
|
||||
const data = useAgentMessages();
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background p-8">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h1 className="text-2xl font-bold">Agent Messages QA</h1>
|
||||
<button
|
||||
onClick={loadContent}
|
||||
disabled={loading || !selectedFile}
|
||||
onClick={data.loadContent}
|
||||
disabled={data.loading || !data.selectedFile}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm rounded-md border hover:bg-muted/50 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
<IconRefresh className={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
|
||||
<IconRefresh className={`h-4 w-4 ${data.loading ? 'animate-spin' : ''}`} />
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
@@ -278,121 +395,26 @@ export default function AgentMessagesPage() {
|
||||
Visual inspection of agent message normalization. Each card shows the rendered output alongside raw JSON.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* View Mode Tabs */}
|
||||
<div className="mb-6">
|
||||
<div className="flex gap-1 p-1 bg-muted/30 rounded-lg w-fit">
|
||||
<button
|
||||
onClick={() => setViewMode('events')}
|
||||
className={`px-4 py-2 text-sm rounded-md transition-colors ${
|
||||
viewMode === 'events'
|
||||
? 'bg-background shadow-sm font-medium'
|
||||
: 'hover:bg-muted/50 text-muted-foreground'
|
||||
}`}
|
||||
>
|
||||
Normalized Events
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setViewMode('fixtures')}
|
||||
className={`px-4 py-2 text-sm rounded-md transition-colors ${
|
||||
viewMode === 'fixtures'
|
||||
? 'bg-background shadow-sm font-medium'
|
||||
: 'hover:bg-muted/50 text-muted-foreground'
|
||||
}`}
|
||||
>
|
||||
Test Fixtures
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Filters */}
|
||||
<div className="mb-6 space-y-4">
|
||||
{/* File Selector */}
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-muted-foreground">
|
||||
{viewMode === 'events' ? 'Event File:' : 'Fixture File:'}
|
||||
</span>
|
||||
<select
|
||||
value={selectedFile}
|
||||
onChange={(e) => setSelectedFile(e.target.value)}
|
||||
className="px-3 py-1.5 text-sm rounded-md border bg-background hover:bg-muted/50 transition-colors min-w-[300px]"
|
||||
>
|
||||
{currentFiles.length === 0 && (
|
||||
<option value="">No files found</option>
|
||||
)}
|
||||
{currentFiles.map((file) => (
|
||||
<option key={file.path} value={file.path}>
|
||||
{file.protocol} - {file.agent || 'unknown'} ({file.message_count} messages)
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Tool Filter - only show for fixtures mode */}
|
||||
{viewMode === 'fixtures' && (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-muted-foreground">Tool Type:</span>
|
||||
<div className="flex gap-1">
|
||||
{toolTabs.map((tab) => (
|
||||
<button
|
||||
key={tab.value}
|
||||
onClick={() => setToolFilter(tab.value)}
|
||||
className={`px-3 py-1.5 text-sm rounded-md transition-colors ${
|
||||
toolFilter === tab.value
|
||||
? 'bg-secondary text-secondary-foreground'
|
||||
: 'hover:bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<ViewModeTabs viewMode={data.viewMode} setViewMode={data.setViewMode} />
|
||||
<FiltersBar
|
||||
viewMode={data.viewMode}
|
||||
currentFiles={data.currentFiles}
|
||||
selectedFile={data.selectedFile}
|
||||
setSelectedFile={data.setSelectedFile}
|
||||
toolFilter={data.toolFilter}
|
||||
setToolFilter={data.setToolFilter}
|
||||
/>
|
||||
<div className="mb-6 text-sm text-muted-foreground">
|
||||
Showing {itemCount} of {totalCount} {viewMode === 'events' ? 'messages' : 'fixtures'}
|
||||
Showing {data.itemCount} of {data.totalCount} {data.viewMode === 'events' ? 'messages' : 'fixtures'}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
{loading && (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<IconRefresh className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<div className="rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-destructive">
|
||||
<div className="font-medium">Error loading {viewMode}</div>
|
||||
<div className="text-sm">{error}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && itemCount === 0 && (
|
||||
<div className="text-center py-12 text-muted-foreground">
|
||||
{viewMode === 'events'
|
||||
? 'No normalized event files found. Run an agent with KANDEV_DEBUG_AGENT_MESSAGES=1 to generate event logs.'
|
||||
: 'No fixtures found. Select a fixture file from the dropdown above.'}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && viewMode === 'fixtures' && filteredFixtures.length > 0 && (
|
||||
<div className="space-y-4">
|
||||
{filteredFixtures.map((fixture, index) => (
|
||||
<FixtureCard key={index} fixture={fixture} index={index} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!loading && !error && viewMode === 'events' && messages.length > 0 && (
|
||||
<div className="space-y-4">
|
||||
{messages.map((message, index) => (
|
||||
<MessageCard key={message.id || index} message={message} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<ContentArea
|
||||
viewMode={data.viewMode}
|
||||
loading={data.loading}
|
||||
error={data.error}
|
||||
itemCount={data.itemCount}
|
||||
filteredFixtures={data.filteredFixtures}
|
||||
messages={data.messages}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { defineConfig, globalIgnores } from "eslint/config";
|
||||
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||
import nextTs from "eslint-config-next/typescript";
|
||||
import sonarjs from "eslint-plugin-sonarjs";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
|
||||
const eslintConfig = defineConfig([
|
||||
...nextVitals,
|
||||
@@ -13,6 +15,24 @@ const eslintConfig = defineConfig([
|
||||
"build/**",
|
||||
"next-env.d.ts",
|
||||
]),
|
||||
{
|
||||
plugins: {
|
||||
sonarjs,
|
||||
"unused-imports": unusedImports,
|
||||
},
|
||||
rules: {
|
||||
"max-lines": ["warn", { max: 600, skipBlankLines: true, skipComments: true }],
|
||||
"max-lines-per-function": ["warn", { max: 100, skipBlankLines: true, skipComments: true }],
|
||||
"complexity": ["warn", 15],
|
||||
"max-depth": ["warn", 4],
|
||||
"max-params": ["warn", 5],
|
||||
"no-nested-ternary": "warn",
|
||||
"sonarjs/cognitive-complexity": ["warn", 20],
|
||||
"sonarjs/no-duplicate-string": ["warn", { threshold: 4 }],
|
||||
"sonarjs/no-identical-functions": "warn",
|
||||
"unused-imports/no-unused-imports": "warn",
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export default eslintConfig;
|
||||
|
||||
@@ -107,9 +107,11 @@
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint-plugin-sonarjs": "^3.0.7",
|
||||
"eslint-plugin-unused-imports": "^4.4.1",
|
||||
"happy-dom": "^20.1.0",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5",
|
||||
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "kandev-3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
Reference in New Issue
Block a user