diff --git a/.alphaAgent/quality/issues.json b/.alphaAgent/quality/issues.json new file mode 100644 index 00000000000..8162bbbda7b --- /dev/null +++ b/.alphaAgent/quality/issues.json @@ -0,0 +1,365 @@ +{ + "version": "1.0", + "issues": [ + { + "id": "issue-001", + "file_path": "packages/server/src/services/documentstore/index.ts", + "issue_type": "complexity", + "severity": "high", + "description": "File is 2573 lines long. This is significantly above the recommended 500-line threshold. Should be split into multiple focused modules for maintainability and testability.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-002", + "file_path": "packages/server/src/utils/index.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Utility file is 2495 lines long, indicating too many unrelated utilities in one module. Should be refactored into smaller, specialized utility modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-003", + "file_path": "packages/server/src/utils/buildAgentflow.ts", + "issue_type": "complexity", + "severity": "high", + "description": "File is 2312 lines long. Complex agent flow building logic should be split into smaller functions and modules for better maintainability and testing.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-004", + "file_path": "packages/components/src/handler.ts", + "issue_type": "complexity", + "severity": "high", + "description": "File is 2218 lines long. Contains complex handler logic that should be modularized into smaller, focused handler classes.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-005", + "file_path": "packages/embed/src/components/Bot.tsx", + "issue_type": "complexity", + "severity": "high", + "description": "Component file is 2095 lines long. This React component should be broken down into smaller, reusable sub-components for better maintainability and reusability.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-006", + "file_path": "packages/components/src/utils.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Utility file is 1943 lines. Large utility files should be split into focused modules (e.g., nodeUtils, componentUtils, dataUtils).", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-007", + "file_path": "packages/server/src/routes/billing/index.ts", + "issue_type": "security", + "severity": "critical", + "description": "Route 'GET /customer/status' (line 8) lacks enforceAbility middleware. This endpoint is exposed without authentication checks. All routes must use enforceAbility middleware.", + "line_number": 8, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-008", + "file_path": "packages/server/src/routes/billing/index.ts", + "issue_type": "security", + "severity": "critical", + "description": "Routes 'GET /usage/sync' and 'POST /usage/sync' (lines 33-34) lack enforceAbility middleware. These internal endpoints are exposed without authentication. Must add proper authorization.", + "line_number": 33, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-009", + "file_path": "packages/server/src/routes/billing/index.ts", + "issue_type": "security", + "severity": "critical", + "description": "Route 'POST /webhooks' (line 37) lacks enforceAbility middleware. Webhook handlers should implement secret verification instead of (or in addition to) enforceAbility.", + "line_number": 37, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-010", + "file_path": "packages/server/src/routes/billing/index.ts", + "issue_type": "style", + "severity": "medium", + "description": "TODO comment on line 11 'Remove this route' suggests dead code. Either remove the commented route or create a ticket to track its removal.", + "line_number": 11, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-011", + "file_path": "packages/server/src/controllers/billing/index.ts", + "issue_type": "style", + "severity": "medium", + "description": "console.error statement on line 34 in production code. Should use logger.error() instead of console for consistent logging and better observability.", + "line_number": 34, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-012", + "file_path": "packages/server/src/controllers/billing/index.ts", + "issue_type": "style", + "severity": "medium", + "description": "Error silencing on line 35 (commented out next(error)) masks potential issues. Either handle the error properly or use a guard clause to prevent silent failures.", + "line_number": 35, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-013", + "file_path": "apps/web/e2e", + "issue_type": "testing", + "severity": "high", + "description": "Critical features lack E2E test coverage. Only 2 E2E test files exist (auth.spec.ts, guardrails-settings.spec.ts). Missing tests for: user workflows, chatflow management, API interactions, and sidekick features.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-014", + "file_path": "packages/server/src/services/chatflows/index.ts", + "issue_type": "performance", + "severity": "high", + "description": "Query on line 40 fetches ChatFlow without checking workspace. Should implement workspace filtering in all service queries to prevent cross-workspace data leakage and improve query performance.", + "line_number": 40, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-015", + "file_path": "packages/components", + "issue_type": "testing", + "severity": "high", + "description": "Flowise component nodes lack unit test coverage. No test files found for critical nodes like Agent.ts, handler.ts, utils.ts. Missing tests for component initialization and error handling.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-016", + "file_path": "packages/server/src/services/documentstore/index.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Service contains mixed concerns: document storage, upserting, file management, and vector store integration. Should be refactored into specialized services with clear separation of concerns.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-017", + "file_path": "packages/server/src", + "issue_type": "documentation", + "severity": "medium", + "description": "Many service files lack JSDoc comments on exported functions. Critical services like documentstore, chatflows, and billing should have comprehensive documentation for public APIs.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-018", + "file_path": "packages/components/nodes/agentflow/Agent/Agent.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Agent component file is 2530 lines. Complex agent logic should be extracted into smaller modules for graph building, execution, and state management.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-019", + "file_path": "packages/server/src/utils/buildChatflow.ts", + "issue_type": "complexity", + "severity": "high", + "description": "File is 1546 lines. Complex chatflow building logic should be split into separate modules for graph construction, validation, and execution.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-020", + "file_path": "packages/server/src/services/video-generator/index.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Service file is 1575 lines containing video generation logic that should be split into separate modules for rendering, encoding, and API interactions.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-021", + "file_path": "packages/components/src", + "issue_type": "complexity", + "severity": "medium", + "description": "Multiple large utility files (handler.ts, utils.ts, agents.ts, storageUtils.ts) exceed recommended sizes. Consider extracting common patterns into separate utility libraries.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-022", + "file_path": "packages/server/src/utils/buildAgentGraph.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "File is 1105 lines. Graph building logic should be modularized into separate functions for graph construction, validation, and traversal.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-023", + "file_path": "packages/components/nodes/sequentialagents/Agent/Agent.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Sequential agent implementation is 1090 lines. Should be refactored to extract agent execution logic, state management, and orchestration into separate modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-024", + "file_path": "packages/server/src/aai-utils/billing/stripe/StripeProvider.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "File is 1076 lines containing comprehensive Stripe integration. Should be split into separate modules for subscription management, usage tracking, and invoice handling.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-025", + "file_path": "packages/components/nodes/chatmodels/ChatGoogleGenerativeAI/FlowiseChatGoogleGenerativeAI.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Chat model implementation is 1068 lines. Should extract common chat model patterns into a base class to reduce duplication across model implementations.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-026", + "file_path": "packages/server/src/services/chatflows/index.ts", + "issue_type": "complexity", + "severity": "high", + "description": "Chatflows service is 1023 lines with mixed concerns: CRUD operations, execution logic, validation, and messaging. Should be split into separate services.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-027", + "file_path": "packages/components/nodes/agentflow/LLM/LLM.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "LLM node implementation is 1013 lines. Should extract LLM selection, configuration, and initialization logic into separate modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-028", + "file_path": "packages/components/nodes/tools/MicrosoftTeams/core.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Microsoft Teams tool implementation is 1669 lines. Complex API interactions should be split into separate modules for channels, messages, and team management.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-029", + "file_path": "packages/components/nodes/tools/Jira/core.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Jira tool integration is 1172 lines containing multiple API operations. Should extract into separate modules for issue management, workflow, and project operations.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-030", + "file_path": "packages/components/src/storageUtils.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Storage utilities file is 1108 lines. Should be split into separate modules for file operations, storage management, and caching.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-031", + "file_path": "packages/components/src/agents.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Agents utility file is 1079 lines with mixed agent creation, execution, and utility logic. Should be refactored into focused agent factory and executor modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-032", + "file_path": "packages/components/nodes/tools/Gmail/core.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Gmail tool implementation is 1079 lines. Complex Gmail API operations should be extracted into separate modules for email management and label operations.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-033", + "file_path": "packages/components/nodes/documentloaders/FireCrawl/FireCrawl.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "FireCrawl loader is 1047 lines. Web scraping and document processing logic should be split into separate modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-034", + "file_path": "packages/components/nodes/documentloaders/S3File/S3File.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "S3 file loader is 1037 lines. File handling and S3 operations should be extracted into separate utility modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-035", + "file_path": "packages/components/nodes/tools/GoogleDrive/core.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Google Drive tool is 982 lines. Drive API operations should be split into separate modules for file, folder, and permission management.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-036", + "file_path": "packages/components/nodes/tools/MicrosoftOutlook/core.ts", + "issue_type": "complexity", + "severity": "medium", + "description": "Microsoft Outlook tool is 969 lines. Complex email and calendar operations should be extracted into focused modules.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-037", + "file_path": "packages/server/src", + "issue_type": "testing", + "severity": "high", + "description": "Limited test coverage for core services. Only 12 test files found across entire server package. Critical services like chatflows, documentstore, and billing need comprehensive test coverage.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-038", + "file_path": "packages/server/src/routes", + "issue_type": "security", + "severity": "high", + "description": "Public routes (public-chatflows, public-executions) intentionally lack authentication. These should be thoroughly tested for XSS, CSRF, and data exposure vulnerabilities.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-039", + "file_path": "packages/server/src/utils", + "issue_type": "documentation", + "severity": "medium", + "description": "Large utility modules (index.ts, buildAgentflow.ts, buildChatflow.ts) lack comprehensive JSDoc comments explaining exported functions and their parameters.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + }, + { + "id": "issue-040", + "file_path": "packages/components/nodes", + "issue_type": "documentation", + "severity": "medium", + "description": "Node components lack consistent JSDoc documentation. Many complex nodes (Agent.ts, handler.ts) missing parameter documentation and implementation details.", + "line_number": null, + "detected_at": "2026-01-22T00:00:00Z" + } + ] +} diff --git a/.alphaAgent/quality/lessons.json b/.alphaAgent/quality/lessons.json new file mode 100644 index 00000000000..e5c1f728e2e --- /dev/null +++ b/.alphaAgent/quality/lessons.json @@ -0,0 +1,522 @@ +{ + "version": "1.0", + "lessons": [ + { + "id": "lesson-001", + "title": "Multi-tenancy is critical: Always filter by organizationId", + "content": "All database queries MUST filter by organizationId and userId. This is a security boundary that prevents users from accessing other organizations' data. In services, use createQueryBuilder with organizationId condition. In controllers, always use checkOwnership() to verify resource access before returning data. Missing these filters creates data leak vulnerabilities.", + "category": "best_practice", + "severity": "critical", + "tags": ["security", "multi-tenancy", "backend"], + "source": "CLAUDE.md, packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-002", + "title": "Always use enforceAbility middleware on all routes", + "content": "Every route in packages/server/src/routes/ MUST include enforceAbility('Resource') middleware. This is not optional - skipping it creates an authentication vulnerability. The middleware validates JWT or API key, syncs user data, checks organization membership, and verifies resource-level permissions before the controller executes.", + "category": "best_practice", + "severity": "critical", + "tags": ["security", "authentication", "backend"], + "source": ".cursorrules, packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-003", + "title": "Use InternalFlowiseError with proper status codes for all errors", + "content": "All error handling must use InternalFlowiseError from the errors package with appropriate HTTP status codes. Follow the format: Error: {serviceName}.{methodName} - {description}. For validation errors use PRECONDITION_FAILED (412), for not found use NOT_FOUND (404), for unauthorized use UNAUTHORIZED (401), for server errors use INTERNAL_SERVER_ERROR (500). This ensures consistent error responses across the API.", + "category": "pattern", + "severity": "warning", + "tags": ["error-handling", "backend"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-004", + "title": "Follow 4-layer backend architecture: Routes → Controllers → Services → Entities", + "content": "All backend resources follow this strict pattern: (1) Routes in packages/server/src/routes/{resource}/ define RESTful endpoints with enforceAbility middleware, (2) Controllers in packages/server/src/controllers/{resource}/ validate requests and call services, (3) Services in packages/server/src/services/{resource}/ contain business logic and database operations, (4) Entities in packages/server/src/database/entities/ define TypeORM models. Never skip layers or put business logic in routes. This separation prevents tight coupling and makes testing easier.", + "category": "pattern", + "severity": "warning", + "tags": ["architecture", "backend"], + "source": ".cursorrules, packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-005", + "title": "Every entity MUST include: userId, organizationId, createdDate, updatedDate", + "content": "These are mandatory fields for all TypeORM entities. userId and organizationId should be indexed (use @Index() decorator). createdDate and updatedDate should use @CreateDateColumn() and @UpdateDateColumn() decorators. deletedDate should use @DeleteDateColumn() for soft delete support. Without these fields, the multi-tenancy system and audit trails won't work correctly.", + "category": "best_practice", + "severity": "warning", + "tags": ["database", "backend", "multi-tenancy"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-006", + "title": "Controllers validate inputs, call services, and check ownership", + "content": "Controllers are thin request handlers that don't contain business logic. They should: (1) Validate required parameters early, (2) Call the service layer, (3) Use checkOwnership() to verify the user can access the resource, (4) Wrap errors with try/catch and pass to next(error). Controllers are the place to check HTTP-level concerns like parameter validation and resource ownership, but not business logic.", + "category": "pattern", + "severity": "warning", + "tags": ["architecture", "backend"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-007", + "title": "Services contain pure business logic and database operations", + "content": "Services should not handle HTTP requests/responses. They should: (1) Import getRunningExpressApp() to get the database connection, (2) Use repository.createQueryBuilder() for complex queries, (3) Always filter by organizationId in database queries, (4) Throw InternalFlowiseError with proper status codes, (5) Wrap external errors with context. Services are where the actual work happens - database operations, business rule validation, and data transformation.", + "category": "pattern", + "severity": "warning", + "tags": ["architecture", "backend"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-008", + "title": "Register new routes in packages/server/src/index.ts", + "content": "After creating a new route file, you MUST register it in the main Express app at packages/server/src/index.ts using app.use('/api/v1/resources', routerImport). Without registration, the routes won't be accessible. This is easy to forget and will cause 404 errors.", + "category": "insight", + "severity": "warning", + "tags": ["backend", "setup"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-009", + "title": "TheAnswer components MUST include tags: ['AAI']", + "content": "All Flowise components created for TheAnswer must include the tag 'AAI' in their tags array. This identifies components as part of TheAnswer and helps distinguish them from core Flowise components. Without this tag, components are harder to discover and manage.", + "category": "best_practice", + "severity": "warning", + "tags": ["components", "flowise"], + "source": "packages/components/CLAUDE.md, .claude/rules/components.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-010", + "title": "Component naming pattern: {ComponentName}_{Category}", + "content": "Flowise components must follow the naming convention where the class name is {ComponentName}_{Category}, for example ChatOpenAI_ChatModels or VectorStoreRetriever_Retrievers. The category suffix must match the folder it's in (e.g., nodes/chatmodels/). This naming convention makes it easy to identify what a component does and where it belongs.", + "category": "pattern", + "severity": "info", + "tags": ["components", "naming"], + "source": "packages/components/CLAUDE.md, .claude/rules/components.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-011", + "title": "Flowise components must implement INode interface and export with nodeClass", + "content": "Every Flowise component must implement INode interface with required fields: label, name, version, type, category, baseClasses, inputs, and init(). The component must be exported as 'module.exports = { nodeClass: YourComponent_Category }'. For credentials, use 'module.exports = { credClass: YourCredential }'. Missing the correct export syntax will cause components to not appear in the UI.", + "category": "best_practice", + "severity": "warning", + "tags": ["components", "flowise"], + "source": "packages/components/CLAUDE.md, .claude/rules/components.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-012", + "title": "Credential integration in components requires name matching", + "content": "When using credentials in Flowise components, the credentialNames array in the component must match the credential name exactly. For example, if credential is named 'yourApiCredential', then credentialNames: ['yourApiCredential']. Mismatches will cause credential binding to fail silently.", + "category": "insight", + "severity": "warning", + "tags": ["components", "credentials"], + "source": "packages/components/CLAUDE.md, .claude/rules/components.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-013", + "title": "Server vs Client components: Default to Server in Next.js", + "content": "In Next.js App Router, components are Server Components by default. Only add 'use client' directive when you need: hooks (useState, useEffect), event handlers (onClick, onChange), browser APIs, or real-time updates. Server components can fetch data directly and don't add to client bundle. Minimizing client components improves performance and security.", + "category": "best_practice", + "severity": "warning", + "tags": ["frontend", "nextjs", "performance"], + "source": "apps/web/CLAUDE.md, .claude/rules/web-app.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-014", + "title": "Protect routes with middleware.ts in Next.js", + "content": "Next.js routes in the (Main UI) group are protected by middleware.ts which uses Auth0's withMiddlewareAuthRequired(). The middleware configuration specifies which routes require auth via the matcher array. Never bypass middleware - it's the security boundary for the app. If a route is accessible without auth, it's missing from the matcher.", + "category": "best_practice", + "severity": "critical", + "tags": ["security", "frontend", "nextjs"], + "source": "apps/web/CLAUDE.md, .claude/rules/web-app.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-015", + "title": "Use getSession() to access Auth0 user in Server Components", + "content": "In Server Components, use getSession() from '@auth0/nextjs-auth0' to access the authenticated user. The session object contains user.sub (user ID), user.email, and user.org_id (organization). Use redirect('/api/auth/login') if session is missing instead of showing an error. This is the server-side Auth0 pattern.", + "category": "pattern", + "severity": "warning", + "tags": ["authentication", "frontend", "nextjs"], + "source": "apps/web/CLAUDE.md, .claude/rules/web-app.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-016", + "title": "Use useUser() hook to access Auth0 user in Client Components", + "content": "In Client Components, use useUser() from '@auth0/nextjs-auth0/client' to get the authenticated user and auth state. The hook returns { user, error, isLoading }. Always check isLoading and handle the not-authenticated case. This is different from getSession() used on the server side.", + "category": "pattern", + "severity": "info", + "tags": ["authentication", "frontend", "nextjs"], + "source": "apps/web/CLAUDE.md, .claude/rules/web-app.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-017", + "title": "Never run migrations without asking the user first", + "content": "When implementing features that require database changes, NEVER automatically run 'pnpm db:migrate'. Always: (1) Generate the migration with 'pnpm migration:generate', (2) Review the migration file, (3) Ask the user explicitly before running 'pnpm db:migrate'. This prevents accidental data loss and gives users control over their schema changes.", + "category": "best_practice", + "severity": "critical", + "tags": ["database", "operations"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-018", + "title": "Create pull requests against 'staging' branch, NOT 'main'", + "content": "The repository uses 'staging' as the pre-production branch and 'main' for production. All PR workflows should create pull requests against 'staging'. The /push command enforces this, blocking any attempts to commit to main or production branches. Never manually create PRs against main.", + "category": "best_practice", + "severity": "critical", + "tags": ["git", "deployment"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-019", + "title": "Submodule commands MUST run from repository root only", + "content": "The repository uses git submodules for packages/embed. Submodule commands like 'pnpm submodule:init' or 'pnpm submodule:reset' MUST be run from the repository root directory, not from within the submodule. Running them from the wrong directory will corrupt the submodule state.", + "category": "insight", + "severity": "warning", + "tags": ["git", "submodules"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-020", + "title": "Use API_HOST, not deprecated API_BASE_URL", + "content": "Environment variable for API configuration is 'API_HOST', not 'API_BASE_URL'. The old name is deprecated and will cause connection failures if used. Always use API_HOST in .env files and code. For client-side code, use NEXT_PUBLIC_API_URL prefixed with NEXT_PUBLIC_.", + "category": "insight", + "severity": "warning", + "tags": ["configuration", "environment"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-021", + "title": "Turbo build order: components → server → ui → web", + "content": "The build system has dependency order: packages/components must build before packages/server, both before packages/ui, and finally apps/web. If a build fails, it might be because a dependency hasn't built yet. Use 'pnpm build-force' to ignore cache if builds are stuck.", + "category": "insight", + "severity": "info", + "tags": ["build", "devops"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-022", + "title": "Database migrations always run fresh (no Turbo cache)", + "content": "Turbo caches build outputs, but database migrations are configured with 'cache: false' so they always run fresh. This prevents stale migrations from being skipped. Never try to optimize migrations with caching.", + "category": "insight", + "severity": "info", + "tags": ["build", "database"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-023", + "title": "Avoid nested ternaries in JSX - extract to helper functions", + "content": "Triple-nested ternaries in JSX are hard to read and maintain. Instead, extract conditional rendering to separate helper functions or use early returns in components. This makes components more testable and readable.", + "category": "anti_pattern", + "severity": "warning", + "tags": ["frontend", "react", "readability"], + "source": ".cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-024", + "title": "API key is PRIMARY auth, JWT is FALLBACK", + "content": "The server supports two auth methods in priority order: (1) API Key via 'Authorization: Bearer ' header is primary, (2) JWT from Auth0 is fallback. API keys are for programmatic access and track usage per key. JWTs are for UI access and include organization context. Both methods result in req.user being populated with organization and permission data.", + "category": "pattern", + "severity": "warning", + "tags": ["security", "authentication"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-025", + "title": "Non-admin users only see their own resources", + "content": "In services when querying resources, admins can see all resources in their organization, but non-admin users should only see their own resources (where userId matches). Implement this pattern: if (!user.isAdmin) { query.andWhere('resource.userId = :userId', { userId: user.id }) }. This provides an additional permission boundary beyond organizationId.", + "category": "pattern", + "severity": "warning", + "tags": ["security", "authorization"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-026", + "title": "Use soft delete with @DeleteDateColumn() for recoverable deletes", + "content": "For entities that support deletion, use @DeleteDateColumn() decorator instead of hard delete. Soft-deleted records remain in the database with a deletedDate timestamp. To query including soft-deleted records, use .withDeleted() on the query builder. This allows data recovery and maintains referential integrity.", + "category": "best_practice", + "severity": "info", + "tags": ["database", "data-integrity"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-027", + "title": "Use transactions for multi-step database operations", + "content": "When performing multiple related database operations that should succeed or fail together, use queryRunner transactions. Start with createQueryRunner(), connect(), startTransaction(), perform operations with queryRunner.manager, then commitTransaction() on success or rollbackTransaction() on error. This prevents partial updates.", + "category": "pattern", + "severity": "warning", + "tags": ["database", "reliability"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-028", + "title": "Component init() should extract inputs, load credentials, initialize instance", + "content": "The init() method in Flowise components follows this pattern: (1) Extract inputs from nodeData.inputs, (2) Get credentials if needed via getCredentialData() and getCredentialParam(), (3) Validate required inputs, (4) Initialize the component instance, (5) Return instance or throw Error. The method should be defensive - validate everything before initializing.", + "category": "pattern", + "severity": "info", + "tags": ["components", "flowise"], + "source": "packages/components/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-029", + "title": "Check for pre-commit hooks before committing", + "content": "The repository may have pre-commit hooks that validate code before commits. If a commit fails with hook errors, use --no-verify flag: git commit --no-verify -m 'message'. However, understand why the hook failed before skipping it - hooks prevent common mistakes like committing credentials or debug code.", + "category": "insight", + "severity": "warning", + "tags": ["git"], + "source": ".cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-030", + "title": "Always validate API responses with Zod before using", + "content": "All API responses should be validated with Zod schemas before use. This catches API contract changes early and provides type safety. Create schema files for response types and validate fetch() responses before processing them in client code.", + "category": "best_practice", + "severity": "warning", + "tags": ["frontend", "validation", "type-safety"], + "source": ".cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-031", + "title": "Use pagination for large result sets", + "content": "When returning lists of resources that could grow large, implement pagination with skip/take parameters. The pattern is: const skip = (page - 1) * limit; repository.findAndCount({ skip, take: limit }). Return both the items and total count so clients can calculate total pages. This prevents performance issues with large datasets.", + "category": "best_practice", + "severity": "info", + "tags": ["performance", "backend"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-032", + "title": "Use React Query for client-side data fetching and caching", + "content": "For client-side data fetching, use React Query (useQuery, useMutation) instead of manual useState/useEffect. React Query handles caching, invalidation, loading/error states, and background refetching. This reduces bugs and improves user experience. Manual fetch patterns often miss edge cases.", + "category": "best_practice", + "severity": "info", + "tags": ["frontend", "react", "data-fetching"], + "source": "apps/web/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-033", + "title": "Memoize expensive list operations with useMemo", + "content": "When filtering, sorting, or transforming large lists in React components, wrap the operation in useMemo to prevent recalculations on every render. Example: useMemo(() => items.filter(...).sort(...), [items]). This is especially important for large datasets to prevent performance degradation.", + "category": "pattern", + "severity": "info", + "tags": ["frontend", "react", "performance"], + "source": ".cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-034", + "title": "Never commit sensitive data (.env, credentials.json)", + "content": "Never commit .env files, credential files, API keys, or secrets to git. Use .env.template as a template for what variables are needed. If you accidentally commit sensitive data, rotate the credentials immediately. The /push command checks for common secret patterns to prevent this.", + "category": "best_practice", + "severity": "critical", + "tags": ["security", "git"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-035", + "title": "Use descriptive error messages that don't leak sensitive info", + "content": "Error messages should be helpful for debugging but not expose sensitive information like database credentials, API keys, or internal server details. Good: 'Resource not found'. Bad: 'Failed to query db://user:pass@host/db'. Use InternalFlowiseError with appropriate messages.", + "category": "best_practice", + "severity": "warning", + "tags": ["security", "error-handling"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-036", + "title": "E2E tests should cover critical paths and role-based access", + "content": "E2E tests in apps/web/e2e/ should test: (1) Authentication flows (login, logout), (2) Critical user workflows (create chatflow, run chatflow), (3) Role-based access control (admin vs user permissions). Use stored auth states to speed up tests (via auth.setup.ts). Test selectors should be stable (use data-testid) rather than brittle (text or class selectors).", + "category": "best_practice", + "severity": "warning", + "tags": ["testing", "frontend"], + "source": "apps/web/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-037", + "title": "Use Role-based test storage states for Playwright", + "content": "For Playwright E2E tests, create separate auth setup steps for each role (admin, user, guest) that save auth state to files (e.g., e2e/.auth/admin.json). Then use test.use({ storageState: 'e2e/.auth/admin.json' }) in test groups to reuse auth. This is much faster than logging in for every test.", + "category": "pattern", + "severity": "info", + "tags": ["testing", "frontend"], + "source": "apps/web/CLAUDE.md, .claude/rules/web-app.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-038", + "title": "Dynamic routing in Next.js: [id] for single params, [...slug] for catch-all", + "content": "In Next.js App Router, use [id] for single dynamic segments and [...slug] for catch-all routes. Access params via destructuring in the page component. For example: app/(Main UI)/chatflows/[id]/page.tsx can access params.id. This enables flexible routing patterns.", + "category": "pattern", + "severity": "info", + "tags": ["frontend", "nextjs"], + "source": "apps/web/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-039", + "title": "Use Prisma for TheAnswer-specific schema, TypeORM for Flowise core", + "content": "The project uses two database systems: TypeORM for Flowise core entities (Chatflows, Credentials, etc.) and Prisma for TheAnswer-specific extensions. When adding features: if it's Flowise core, use TypeORM in packages/server/src/database/entities/. If it's TheAnswer-specific, use Prisma in packages-answers/db/prisma/schema.prisma.", + "category": "insight", + "severity": "info", + "tags": ["database", "architecture"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-040", + "title": "Always use parameterized queries with TypeORM", + "content": "TypeORM's createQueryBuilder with named parameters prevents SQL injection. Example: .where('resource.id = :id', { id }) is safe. Avoid string concatenation in queries: .where(`resource.id = ${id}`) is vulnerable. Let TypeORM handle parameter binding.", + "category": "best_practice", + "severity": "critical", + "tags": ["security", "database"], + "source": "packages/server/CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-041", + "title": "Import aliases: @utils, @ui, @db for cleaner imports", + "content": "Use configured import aliases for cleaner imports: @utils/utility, @ui/Component, @db/schema instead of relative paths. This makes refactoring easier and imports more readable. Flowise packages use @/components, @/api for their own aliases. Check tsconfig.json for full alias configuration.", + "category": "pattern", + "severity": "info", + "tags": ["frontend", "backend"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-042", + "title": "Implement pagination, filtering, and search consistently across resources", + "content": "All list endpoints should support pagination (page, limit), filtering (status, type), and search (q parameter). Follow consistent patterns across the API. Return { items, total, page, limit } structure so clients can implement pagination UI consistently.", + "category": "best_practice", + "severity": "info", + "tags": ["backend", "api-design"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-043", + "title": "File operations should be scoped to user/organization directories", + "content": "When handling file uploads, store them in user/organization-specific directories to prevent data leaks. Use path.join(uploadPath, user.organizationId, user.id, filename). Always validate file types and sizes before accepting uploads. Never expose full file paths in API responses.", + "category": "best_practice", + "severity": "warning", + "tags": ["security", "backend"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-044", + "title": "Commit messages must be conventional format", + "content": "Use conventional commits: feat: new feature, fix: bug fix, chore: dependencies, docs: documentation, refactor: code improvement, test: tests, style: formatting. The /push command validates this format. One-line messages work best in CLI. This creates searchable commit history.", + "category": "pattern", + "severity": "info", + "tags": ["git"], + "source": "CLAUDE.md, .cursorrules", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-045", + "title": "Database health check: pnpm db:healthcheck", + "content": "If database operations are failing, run 'pnpm db:healthcheck' to verify connectivity. This checks if the database is reachable and queries work. If this fails, verify DATABASE_URL in .env and check that Docker containers are running (pnpm dev-docker).", + "category": "pattern", + "severity": "info", + "tags": ["database", "debugging"], + "source": "CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-046", + "title": "Export default instead of named exports from services", + "content": "Services, controllers, and routes export a default object with all methods. Use 'export default { method1, method2 }' not 'export const method1'. This pattern is consistent across the codebase and makes imports cleaner: import serviceDefault from '...'.", + "category": "pattern", + "severity": "info", + "tags": ["backend", "style"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-047", + "title": "Use getErrorMessage() utility for wrapping error details", + "content": "The getErrorMessage() utility from the errors package safely extracts error messages from unknown error types. Use it when catching errors: catch (error) { throw new InternalFlowiseError(..., `Error: service.method - ${getErrorMessage(error)}`) }. This prevents crashes from non-Error objects.", + "category": "pattern", + "severity": "info", + "tags": ["error-handling", "backend"], + "source": "packages/server/CLAUDE.md", + "created_at": "2026-01-22T00:00:00Z", + "is_addressed": false + } + ] +} diff --git a/.alphaAgent/spec/api-endpoints.json b/.alphaAgent/spec/api-endpoints.json new file mode 100644 index 00000000000..35fa802ee6b --- /dev/null +++ b/.alphaAgent/spec/api-endpoints.json @@ -0,0 +1,1028 @@ +{ + "version": "1.0", + "metadata": { + "framework": "Express.js (Server) + Next.js App Router (Web)", + "authentication": "checkPermission/checkAnyPermission middleware (Express) + Auth0 (Next.js)", + "base_path_flowise": "/api/v1", + "base_path_nextjs": "/api", + "description": "TheAnswer API with Flowise core and Next.js extensions" + }, + "endpoints": [ + { + "method": "GET", + "path": "/api/v1/ping", + "description": "Health check endpoint", + "auth_required": false, + "file_path": "packages/server/src/routes/ping/index.ts", + "line_number": 6 + }, + { + "method": "HEAD", + "path": "/api/v1/ping", + "description": "Health check endpoint (HEAD)", + "auth_required": false, + "file_path": "packages/server/src/routes/ping/index.ts", + "line_number": 9 + }, + { + "method": "POST", + "path": "/api/v1/apikey", + "description": "Create API key", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 7 + }, + { + "method": "POST", + "path": "/api/v1/apikey/import", + "description": "Import API keys", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/apikey", + "description": "Get all API keys", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 11 + }, + { + "method": "PUT", + "path": "/api/v1/apikey", + "description": "Update API key", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 14 + }, + { + "method": "PUT", + "path": "/api/v1/apikey/:id", + "description": "Update API key by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 14 + }, + { + "method": "DELETE", + "path": "/api/v1/apikey", + "description": "Delete API key", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 17 + }, + { + "method": "DELETE", + "path": "/api/v1/apikey/:id", + "description": "Delete API key by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/apikey/index.ts", + "line_number": 17 + }, + { + "method": "POST", + "path": "/api/v1/assistants", + "description": "Create assistant", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/assistants", + "description": "Get all assistants", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 11 + }, + { + "method": "GET", + "path": "/api/v1/assistants/:id", + "description": "Get assistant by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 12 + }, + { + "method": "PUT", + "path": "/api/v1/assistants", + "description": "Update assistant", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 15 + }, + { + "method": "PUT", + "path": "/api/v1/assistants/:id", + "description": "Update assistant by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 15 + }, + { + "method": "DELETE", + "path": "/api/v1/assistants", + "description": "Delete assistant", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 18 + }, + { + "method": "DELETE", + "path": "/api/v1/assistants/:id", + "description": "Delete assistant by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 18 + }, + { + "method": "GET", + "path": "/api/v1/assistants/components/chatmodels", + "description": "Get available chat models for assistants", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 20 + }, + { + "method": "GET", + "path": "/api/v1/assistants/components/docstores", + "description": "Get available document stores for assistants", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 21 + }, + { + "method": "GET", + "path": "/api/v1/assistants/components/tools", + "description": "Get available tools for assistants", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 22 + }, + { + "method": "POST", + "path": "/api/v1/assistants/generate/instruction", + "description": "Generate assistant instruction", + "auth_required": true, + "file_path": "packages/server/src/routes/assistants/index.ts", + "line_number": 25 + }, + { + "method": "POST", + "path": "/api/v1/attachments/:chatflowId/:chatId", + "description": "Create attachment (file upload)", + "auth_required": false, + "file_path": "packages/server/src/routes/attachments/index.ts", + "line_number": 8 + }, + { + "method": "POST", + "path": "/api/v1/chatflows", + "description": "Create chatflow", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/v1/chatflows", + "description": "Get all chatflows", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 14 + }, + { + "method": "GET", + "path": "/api/v1/chatflows/:id", + "description": "Get chatflow by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 19 + }, + { + "method": "GET", + "path": "/api/v1/chatflows/apikey/:apikey", + "description": "Get chatflow by API key", + "auth_required": false, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 24 + }, + { + "method": "PUT", + "path": "/api/v1/chatflows", + "description": "Update chatflow", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 27 + }, + { + "method": "PUT", + "path": "/api/v1/chatflows/:id", + "description": "Update chatflow by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 27 + }, + { + "method": "DELETE", + "path": "/api/v1/chatflows", + "description": "Delete chatflow", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 34 + }, + { + "method": "DELETE", + "path": "/api/v1/chatflows/:id", + "description": "Delete chatflow by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 34 + }, + { + "method": "GET", + "path": "/api/v1/chatflows/has-changed/:id/:lastUpdatedDateTime", + "description": "Check if chatflow has changed", + "auth_required": true, + "file_path": "packages/server/src/routes/chatflows/index.ts", + "line_number": 37 + }, + { + "method": "GET", + "path": "/api/v1/chatflows-streaming/:id", + "description": "Check if chatflow is valid for streaming", + "auth_required": false, + "file_path": "packages/server/src/routes/chatflows-streaming/index.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/v1/chatmessage/:id", + "description": "Get all chat messages", + "auth_required": false, + "file_path": "packages/server/src/routes/chat-messages/index.ts", + "line_number": 10 + }, + { + "method": "PUT", + "path": "/api/v1/chatmessage/abort/:chatflowid/:chatid", + "description": "Abort chat message", + "auth_required": false, + "file_path": "packages/server/src/routes/chat-messages/index.ts", + "line_number": 13 + }, + { + "method": "DELETE", + "path": "/api/v1/chatmessage", + "description": "Remove all chat messages", + "auth_required": false, + "file_path": "packages/server/src/routes/chat-messages/index.ts", + "line_number": 16 + }, + { + "method": "DELETE", + "path": "/api/v1/chatmessage/:id", + "description": "Remove chat message by ID", + "auth_required": false, + "file_path": "packages/server/src/routes/chat-messages/index.ts", + "line_number": 16 + }, + { + "method": "GET", + "path": "/api/v1/chats", + "description": "Get all chats", + "auth_required": true, + "file_path": "packages/server/src/routes/chats/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/chats/:id", + "description": "Get chat by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/chats/index.ts", + "line_number": 9 + }, + { + "method": "POST", + "path": "/api/v1/credentials", + "description": "Create credential", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/v1/credentials", + "description": "Get all credentials", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 10 + }, + { + "method": "GET", + "path": "/api/v1/credentials/:id", + "description": "Get credential by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 11 + }, + { + "method": "PUT", + "path": "/api/v1/credentials", + "description": "Update credential", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 14 + }, + { + "method": "PUT", + "path": "/api/v1/credentials/:id", + "description": "Update credential by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 14 + }, + { + "method": "DELETE", + "path": "/api/v1/credentials", + "description": "Delete credential", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 17 + }, + { + "method": "DELETE", + "path": "/api/v1/credentials/:id", + "description": "Delete credential by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/credentials/index.ts", + "line_number": 17 + }, + { + "method": "GET", + "path": "/api/v1/nodes", + "description": "Get all nodes", + "auth_required": false, + "file_path": "packages/server/src/routes/nodes/index.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/v1/nodes/:name", + "description": "Get node by name", + "auth_required": false, + "file_path": "packages/server/src/routes/nodes/index.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/v1/nodes/category/:name", + "description": "Get nodes by category", + "auth_required": false, + "file_path": "packages/server/src/routes/nodes/index.ts", + "line_number": 8 + }, + { + "method": "POST", + "path": "/api/v1/tools", + "description": "Create tool", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/tools", + "description": "Get all tools", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 11 + }, + { + "method": "GET", + "path": "/api/v1/tools/:id", + "description": "Get tool by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 12 + }, + { + "method": "PUT", + "path": "/api/v1/tools", + "description": "Update tool", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 15 + }, + { + "method": "PUT", + "path": "/api/v1/tools/:id", + "description": "Update tool by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 15 + }, + { + "method": "DELETE", + "path": "/api/v1/tools", + "description": "Delete tool", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 18 + }, + { + "method": "DELETE", + "path": "/api/v1/tools/:id", + "description": "Delete tool by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/tools/index.ts", + "line_number": 18 + }, + { + "method": "POST", + "path": "/api/v1/variables", + "description": "Create variable", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/variables", + "description": "Get all variables", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 11 + }, + { + "method": "PUT", + "path": "/api/v1/variables", + "description": "Update variable", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 14 + }, + { + "method": "PUT", + "path": "/api/v1/variables/:id", + "description": "Update variable by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 14 + }, + { + "method": "DELETE", + "path": "/api/v1/variables", + "description": "Delete variable", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 17 + }, + { + "method": "DELETE", + "path": "/api/v1/variables/:id", + "description": "Delete variable by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/variables/index.ts", + "line_number": 17 + }, + { + "method": "GET", + "path": "/api/v1/public-chatflows/:id", + "description": "Get public chatflow by ID (no auth required)", + "auth_required": false, + "file_path": "packages/server/src/routes/public-chatflows/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/public-executions/:id", + "description": "Get public execution by ID", + "auth_required": false, + "file_path": "packages/server/src/routes/public-executions/index.ts", + "line_number": 8 + }, + { + "method": "POST", + "path": "/api/v1/feedback/:id", + "description": "Create chat message feedback", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 6 + }, + { + "method": "POST", + "path": "/api/v1/feedback", + "description": "Create chat message feedback", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/v1/feedback", + "description": "Get all chat message feedback", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 9 + }, + { + "method": "GET", + "path": "/api/v1/feedback/:id", + "description": "Get chat message feedback by ID", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 9 + }, + { + "method": "PUT", + "path": "/api/v1/feedback", + "description": "Update chat message feedback", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 12 + }, + { + "method": "PUT", + "path": "/api/v1/feedback/:id", + "description": "Update chat message feedback by ID", + "auth_required": false, + "file_path": "packages/server/src/routes/feedback/index.ts", + "line_number": 12 + }, + { + "method": "POST", + "path": "/api/v1/prediction", + "description": "Create prediction (with file upload and rate limiting)", + "auth_required": false, + "file_path": "packages/server/src/routes/predictions/index.ts", + "line_number": 10 + }, + { + "method": "POST", + "path": "/api/v1/prediction/:id", + "description": "Create prediction by chatflow ID (with file upload and rate limiting)", + "auth_required": false, + "file_path": "packages/server/src/routes/predictions/index.ts", + "line_number": 10 + }, + { + "method": "GET", + "path": "/api/v1/settings", + "description": "Get settings list", + "auth_required": false, + "file_path": "packages/server/src/routes/settings/index.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/v1/billing/customer/status", + "description": "Get customer billing status", + "auth_required": false, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 8 + }, + { + "method": "GET", + "path": "/api/v1/billing/usage/summary", + "description": "Get usage summary", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 13 + }, + { + "method": "GET", + "path": "/api/v1/billing/usage/events", + "description": "Get usage events", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 14 + }, + { + "method": "GET", + "path": "/api/v1/billing/subscription/status", + "description": "Get subscription with usage", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 17 + }, + { + "method": "POST", + "path": "/api/v1/billing/subscriptions", + "description": "Create checkout session", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 18 + }, + { + "method": "PUT", + "path": "/api/v1/billing/subscriptions/:id", + "description": "Update subscription", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 19 + }, + { + "method": "DELETE", + "path": "/api/v1/billing/subscriptions/:id", + "description": "Cancel subscription", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 20 + }, + { + "method": "POST", + "path": "/api/v1/billing/payment-methods", + "description": "Attach payment method", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 23 + }, + { + "method": "POST", + "path": "/api/v1/billing/portal-sessions", + "description": "Create billing portal session", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 26 + }, + { + "method": "GET", + "path": "/api/v1/billing/invoice/upcoming", + "description": "Get upcoming invoice", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 29 + }, + { + "method": "POST", + "path": "/api/v1/billing/invoices/upcoming", + "description": "Get upcoming invoice", + "auth_required": true, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 30 + }, + { + "method": "GET", + "path": "/api/v1/billing/usage/sync", + "description": "Usage sync handler", + "auth_required": false, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 33 + }, + { + "method": "POST", + "path": "/api/v1/billing/usage/sync", + "description": "Usage sync handler", + "auth_required": false, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 34 + }, + { + "method": "POST", + "path": "/api/v1/billing/webhooks", + "description": "Handle billing webhook", + "auth_required": false, + "file_path": "packages/server/src/routes/billing/index.ts", + "line_number": 37 + }, + { + "method": "GET", + "path": "/api/v1/plan", + "description": "Get current plan", + "auth_required": false, + "file_path": "packages/server/src/routes/plan/index.ts", + "line_number": 5 + }, + { + "method": "GET", + "path": "/api/v1/plan/history", + "description": "Get plan history", + "auth_required": false, + "file_path": "packages/server/src/routes/plan/index.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/v1/executions", + "description": "Get all executions", + "auth_required": true, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/v1/executions/:id", + "description": "Get execution by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 8 + }, + { + "method": "PUT", + "path": "/api/v1/executions", + "description": "Update execution", + "auth_required": false, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 11 + }, + { + "method": "PUT", + "path": "/api/v1/executions/:id", + "description": "Update execution by ID", + "auth_required": false, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 11 + }, + { + "method": "DELETE", + "path": "/api/v1/executions/:id", + "description": "Delete execution by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 14 + }, + { + "method": "DELETE", + "path": "/api/v1/executions", + "description": "Delete multiple executions", + "auth_required": true, + "file_path": "packages/server/src/routes/executions/index.ts", + "line_number": 15 + }, + { + "method": "GET", + "path": "/api/v1/evaluations", + "description": "Get all evaluations", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/v1/evaluations/:id", + "description": "Get evaluation by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 7 + }, + { + "method": "DELETE", + "path": "/api/v1/evaluations/:id", + "description": "Delete evaluation by ID", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 8 + }, + { + "method": "POST", + "path": "/api/v1/evaluations", + "description": "Create evaluation", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 9 + }, + { + "method": "GET", + "path": "/api/v1/evaluations/is-outdated/:id", + "description": "Check if evaluation is outdated", + "auth_required": false, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 10 + }, + { + "method": "POST", + "path": "/api/v1/evaluations/run-again/:id", + "description": "Run evaluation again", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 11 + }, + { + "method": "GET", + "path": "/api/v1/evaluations/versions/:id", + "description": "Get evaluation versions", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 12 + }, + { + "method": "PATCH", + "path": "/api/v1/evaluations", + "description": "Patch delete evaluations", + "auth_required": true, + "file_path": "packages/server/src/routes/evaluations/index.ts", + "line_number": 13 + }, + { + "method": "GET", + "path": "/api/v1/admin/chatflows", + "description": "Get admin chatflows", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 10 + }, + { + "method": "GET", + "path": "/api/v1/admin/chatflows/default-template", + "description": "Get default chatflow template", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 11 + }, + { + "method": "GET", + "path": "/api/v1/admin/chatflows/:id/versions", + "description": "Get chatflow versions", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 12 + }, + { + "method": "PUT", + "path": "/api/v1/admin/chatflows/bulk-update", + "description": "Bulk update chatflows", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 14 + }, + { + "method": "POST", + "path": "/api/v1/admin/chatflows/:id/rollback/:version", + "description": "Rollback chatflow to version", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 15 + }, + { + "method": "GET", + "path": "/api/v1/admin/document-stores", + "description": "Get admin document stores", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 19 + }, + { + "method": "GET", + "path": "/api/v1/admin/organizations/credentials", + "description": "Get organization credentials", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 23 + }, + { + "method": "PUT", + "path": "/api/v1/admin/organizations/credentials", + "description": "Update organization credentials", + "auth_required": true, + "file_path": "packages/server/src/routes/admin/index.ts", + "line_number": 26 + }, + { + "method": "GET", + "path": "/api/data-engine/domains", + "description": "Get domains (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 36 + }, + { + "method": "GET", + "path": "/api/data-engine/urls", + "description": "Get URLs (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 37 + }, + { + "method": "GET", + "path": "/api/data-engine/calls", + "description": "Get calls (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 38 + }, + { + "method": "GET", + "path": "/api/data-engine/tags", + "description": "Get tags (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 39 + }, + { + "method": "GET", + "path": "/api/data-engine/documents", + "description": "Get documents (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 40 + }, + { + "method": "GET", + "path": "/api/data-engine/tickets", + "description": "Get tickets (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 41 + }, + { + "method": "GET", + "path": "/api/data-engine/chats", + "description": "Get chats (Data Engine)", + "auth_required": true, + "file_path": "packages/server/src/routes/data-engine/index.ts", + "line_number": 42 + }, + { + "method": "GET", + "path": "/api/chats", + "description": "Get all chats (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/chats/route.ts", + "line_number": 11 + }, + { + "method": "DELETE", + "path": "/api/chats", + "description": "Delete chat by ID (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/chats/route.ts", + "line_number": 26 + }, + { + "method": "GET", + "path": "/api/chats/:id", + "description": "Get chat by ID (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/chats/[id]/route.ts", + "line_number": 0 + }, + { + "method": "POST", + "path": "/api/chats/:id/share", + "description": "Share chat with users (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/chats/[id]/share/route.ts", + "line_number": 6 + }, + { + "method": "GET", + "path": "/api/settings", + "description": "Get user and organization settings (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/settings/route.ts", + "line_number": 33 + }, + { + "method": "POST", + "path": "/api/settings", + "description": "Update user app settings (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/settings/route.ts", + "line_number": 7 + }, + { + "method": "GET", + "path": "/api/sidekicks", + "description": "Get sidekicks for chat (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/sidekicks/route.ts", + "line_number": 19 + }, + { + "method": "GET", + "path": "/api/app-config", + "description": "Get app config (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/app-config/route.ts", + "line_number": 33 + }, + { + "method": "POST", + "path": "/api/app-config", + "description": "Create app config (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/app-config/route.ts", + "line_number": 8 + }, + { + "method": "PUT", + "path": "/api/app-config", + "description": "Update app config (Next.js)", + "auth_required": true, + "file_path": "apps/web/app/api/app-config/route.ts", + "line_number": 64 + }, + { + "method": "POST", + "path": "/api/images/generate", + "description": "Generate DALL-E image (Next.js proxy to Flowise)", + "auth_required": true, + "file_path": "apps/web/app/api/images/generate/route.ts", + "line_number": 5 + } + ] +} diff --git a/.alphaAgent/spec/critical-paths.json b/.alphaAgent/spec/critical-paths.json new file mode 100644 index 00000000000..ad7e224ad0c --- /dev/null +++ b/.alphaAgent/spec/critical-paths.json @@ -0,0 +1,288 @@ +{ + "version": "1.0", + "paths": [ + { + "id": "user-authentication", + "name": "User Authentication and Login Flow", + "description": "User authenticates via Auth0 and logs into TheAnswer application with proper organization selection and role-based access control", + "priority": "P0", + "coverage": "100%", + "files": [ + "apps/web/middleware.ts", + "apps/web/app/(Main UI)/page.tsx", + "apps/web/app/(Main UI)/layout.tsx", + "apps/web/e2e/tests/auth.spec.ts", + "packages/server/src/routes/index.ts", + "packages/server/src/middlewares/authentication/enforceAbility.ts" + ], + "proposed_tests": [ + "E2E test for successful login and dashboard redirect", + "E2E test for role-based menu visibility (admin/builder/member)", + "Test invalid credentials error handling", + "Test organization selection during login", + "Test session persistence across page reloads" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "chatflow-creation-execution", + "name": "Chatflow Creation and Execution", + "description": "User creates a new chatflow/agentflow using the visual editor and executes it to test the AI workflow", + "priority": "P0", + "coverage": "50%", + "files": [ + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/chatflows/page.tsx", + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(minimal-layout)/canvas/[chatflowid]/page.tsx", + "packages/server/src/routes/chatflows/index.ts", + "packages/server/src/controllers/chatflows/index.ts", + "packages/server/src/services/chatflows/index.ts", + "packages/server/src/database/entities/Chatflow.ts", + "packages/server/src/routes/predictions/index.ts" + ], + "proposed_tests": [ + "E2E test for creating chatflow with basic nodes", + "E2E test for chatflow execution with sample input", + "Integration test for chatflow CRUD operations", + "Test chatflow visibility by organization", + "Test permission checks for unauthorized users" + ], + "test_type": "e2e", + "estimated_sessions": 3 + }, + { + "id": "api-key-management", + "name": "API Key Management", + "description": "User generates and manages API keys for programmatic access to chatflows and agentflows", + "priority": "P0", + "coverage": "40%", + "files": [ + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/apikey/page.tsx", + "packages/server/src/routes/apikey/index.ts", + "packages/server/src/controllers/apikey/index.ts", + "packages/server/src/services/apikey/index.ts", + "packages/server/src/database/entities/ApiKey.ts", + "packages/server/src/middlewares/authentication/enforce-api-key.ts" + ], + "proposed_tests": [ + "E2E test for creating API key", + "E2E test for viewing and copying API keys", + "E2E test for deleting API key", + "Integration test for API key authentication", + "Test API key scoping to organization", + "Test API key usage in chatflow execution calls" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "oauth2-credential-setup", + "name": "OAuth2 Credential Setup and Authorization", + "description": "User configures OAuth2 credentials for integrations (Microsoft Graph, Google, etc.) by authorizing the application", + "priority": "P0", + "coverage": "35%", + "files": [ + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/credentials/page.tsx", + "packages/server/src/routes/oauth2/index.ts", + "packages/server/src/routes/oauth2/templates.ts", + "packages/server/src/routes/credentials/index.ts", + "packages/server/src/controllers/credentials/index.ts", + "packages/server/src/database/entities/Credential.ts", + "packages/server/src/utils/encryption.ts" + ], + "proposed_tests": [ + "Integration test for OAuth2 authorization URL generation", + "Integration test for OAuth2 callback and token exchange", + "Integration test for OAuth2 token refresh", + "E2E test for credential creation UI flow", + "Test credential encryption/decryption", + "Test credential access by organization", + "Test authorization error handling" + ], + "test_type": "integration", + "estimated_sessions": 3 + }, + { + "id": "chatflow-execution-api", + "name": "Chatflow Execution via API", + "description": "External API client executes a chatflow using API key authentication, sending input and receiving AI-generated output", + "priority": "P0", + "coverage": "45%", + "files": [ + "packages/server/src/routes/chatflows/index.ts", + "packages/server/src/routes/predictions/index.ts", + "packages/server/src/routes/chatflows-streaming/index.ts", + "packages/server/src/controllers/predictions/index.ts", + "packages/server/src/services/chatflows/index.ts", + "packages/server/src/middlewares/authentication/enforce-api-key.ts", + "packages/server/src/database/entities/ApiKey.ts" + ], + "proposed_tests": [ + "Integration test for API prediction endpoint with API key", + "Integration test for streaming predictions", + "Test input validation for chatflow execution", + "Test error handling for missing/invalid API keys", + "Test multi-tenancy isolation in API calls", + "Test rate limiting on API calls", + "Test response format consistency" + ], + "test_type": "integration", + "estimated_sessions": 2 + }, + { + "id": "document-store-management", + "name": "Document Store Creation and Vector Search", + "description": "User uploads documents to a vector store and queries them using similarity search for RAG workflows", + "priority": "P1", + "coverage": "40%", + "files": [ + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/document-stores/page.tsx", + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/document-stores/[storeId]/page.tsx", + "packages/server/src/routes/documentstore/index.ts", + "packages/server/src/controllers/documentstore/index.ts", + "packages/server/src/services/documentstore/index.ts", + "packages/server/src/routes/vectors/index.ts", + "packages/server/src/database/entities/DocumentStore.ts" + ], + "proposed_tests": [ + "E2E test for creating new document store", + "E2E test for uploading documents", + "Integration test for vector search", + "Test document chunking and embedding", + "Test document store access by organization", + "Test query performance with large datasets", + "Test document deletion and cleanup" + ], + "test_type": "e2e", + "estimated_sessions": 3 + }, + { + "id": "assistant-creation", + "name": "OpenAI Assistant Creation and Management", + "description": "User creates and configures OpenAI assistants with custom instructions, tools, and knowledge bases", + "priority": "P1", + "coverage": "30%", + "files": [ + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/assistants/page.tsx", + "apps/web/app/(Main UI)/(Studio Layout)/sidekick-studio/(main-layout)/assistants/custom/[id]/page.tsx", + "packages/server/src/routes/openai-assistants/index.ts", + "packages/server/src/controllers/openai-assistants/index.ts", + "packages/server/src/services/openai-assistants/index.ts", + "packages/server/src/routes/openai-assistants-files/index.ts", + "packages/server/src/database/entities/Assistant.ts" + ], + "proposed_tests": [ + "E2E test for creating custom assistant", + "E2E test for uploading assistant knowledge files", + "Integration test for assistant CRUD operations", + "Test assistant tool configuration", + "Test assistant visibility and permissions", + "Test assistant vector store integration" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "role-based-access-control", + "name": "Role-Based Access Control and Permissions", + "description": "System enforces role-based permissions (admin/builder/member) across all features and UI elements", + "priority": "P0", + "coverage": "85%", + "files": [ + "packages/server/src/enterprise/rbac/PermissionCheck.ts", + "packages/server/src/utils/checkOwnership.ts", + "apps/web/e2e/tests/auth.spec.ts", + "apps/web/app/(Main UI)/layout.tsx", + "packages/server/src/routes/index.ts", + "packages/server/src/middlewares/authentication/enforceAbility.ts" + ], + "proposed_tests": [ + "E2E test for admin can access all sections", + "E2E test for builder cannot access billing", + "E2E test for member cannot access studio", + "Test API endpoint authorization for each role", + "Test permission inheritance in organization", + "Test cross-organization data isolation" + ], + "test_type": "e2e", + "estimated_sessions": 1 + }, + { + "id": "chat-interface", + "name": "Chat Interface Interaction", + "description": "User sends messages to a deployed chatbot/chatflow and receives conversational AI responses", + "priority": "P0", + "coverage": "60%", + "files": [ + "apps/web/app/(Main UI)/(Chat UI)/chat/[chatId]/page.tsx", + "apps/web/app/(Main UI)/(Chat UI)/chat/page.tsx", + "packages/server/src/routes/chats/index.ts", + "packages/server/src/routes/chat-messages/index.ts", + "packages/server/src/controllers/chat-messages/index.ts", + "packages/server/src/database/entities/ChatMessage.ts" + ], + "proposed_tests": [ + "E2E test for opening chat interface", + "E2E test for sending message and receiving response", + "E2E test for message history loading", + "Integration test for chat message storage", + "Test message streaming support", + "Test chat session isolation", + "Test message validation and rate limiting" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "billing-and-plan-management", + "name": "Billing and Plan Management", + "description": "Organization admins manage billing, upgrade plans, and monitor usage limits", + "priority": "P1", + "coverage": "35%", + "files": [ + "apps/web/app/(Main UI)/billing/page.tsx", + "apps/web/app/(Main UI)/plans/page.tsx", + "packages/server/src/routes/billing/index.ts", + "packages/server/src/routes/plan/index.ts", + "packages/server/src/controllers/billing/index.ts", + "packages/server/src/database/entities/Organization.ts" + ], + "proposed_tests": [ + "E2E test for viewing billing information", + "E2E test for upgrading plan", + "E2E test for viewing usage metrics", + "Integration test for billing API", + "Test plan-based feature access restrictions", + "Test billing access restricted to admins" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "settings-and-organization-config", + "name": "Settings and Organization Configuration", + "description": "Admins configure organization settings, SSO, users, roles, and workspace variables", + "priority": "P1", + "coverage": "50%", + "files": [ + "apps/web/app/(Main UI)/settings/organization/page.tsx", + "apps/web/app/(Main UI)/settings/user/page.tsx", + "apps/web/app/(Main UI)/settings/integrations/[[...app]]/page.tsx", + "packages/server/src/routes/settings/index.ts", + "packages/server/src/routes/organizations/index.ts", + "packages/server/src/routes/variables/index.ts", + "packages/server/src/controllers/settings/index.ts" + ], + "proposed_tests": [ + "E2E test for updating organization settings", + "E2E test for managing SSO configuration", + "E2E test for inviting users to organization", + "E2E test for configuring workspace variables", + "Integration test for settings API endpoints", + "Test settings access control by role" + ], + "test_type": "e2e", + "estimated_sessions": 2 + } + ] +} diff --git a/.alphaAgent/spec/design-system.json b/.alphaAgent/spec/design-system.json new file mode 100644 index 00000000000..ab9141eccb6 --- /dev/null +++ b/.alphaAgent/spec/design-system.json @@ -0,0 +1,673 @@ +{ + "version": "1.0", + "extracted_at": "2026-01-22T22:35:00Z", + "source": "mui-theme", + "source_files": [ + "packages-answers/ui/src/theme/tokens/colors.ts", + "packages-answers/ui/src/theme/tokens/glassmorphism.ts", + "packages-answers/ui/src/theme/index.tsx", + "packages-answers/ui/src/theme/components/muiOverrides.ts", + "packages/ui/src/assets/theme-vars.js", + "apps/web/app/layout.tsx" + ], + "verified_visually": false, + "colors": { + "background": { + "light": { + "default": { + "value": "#ffffff", + "description": "Light mode default background" + }, + "paper": { + "value": "#ffffff", + "description": "Light mode paper/card background" + } + }, + "dark": { + "default": { + "value": "#0b0b0b", + "description": "Dark mode default background" + }, + "paper": { + "value": "#161616", + "description": "Dark mode paper/card background" + } + }, + "level1": { + "value": "#252525", + "description": "Dark theme level 1 elevation" + }, + "level2": { + "value": "#0b0b0b", + "description": "Dark theme level 2 elevation" + } + }, + "primary": { + "light": { + "main": { + "value": "rgba(15, 23, 42, 0.95)", + "description": "Light mode primary color - semi-transparent dark slate" + }, + "light": { + "value": "rgba(30, 41, 59, 0.85)", + "description": "Light primary variant" + }, + "dark": { + "value": "rgb(15, 23, 42)", + "description": "Dark primary variant - solid" + }, + "gradient": { + "value": "linear-gradient(135deg, rgb(30, 58, 138) 0%, rgb(59, 130, 246) 100%)", + "description": "Light mode primary gradient for buttons" + } + }, + "dark": { + "main": { + "value": "rgba(255, 255, 255, 0.12)", + "description": "Dark mode primary color - transparent white" + }, + "light": { + "value": "rgba(255, 255, 255, 0.18)", + "description": "Dark primary light variant" + }, + "dark": { + "value": "rgba(255, 255, 255, 0.08)", + "description": "Dark primary dark variant" + }, + "gradient": { + "value": "linear-gradient(135deg, rgba(0, 0, 0, 0.6) 0%, rgba(26, 26, 26, 0.6) 100%)", + "description": "Dark mode primary gradient" + } + }, + "legacy": { + "main": { + "value": "#3b82f6", + "description": "Legacy blue primary (used in theme-vars.js)" + }, + "light": { + "value": "#93c5fd", + "description": "Legacy primary light" + }, + "dark": { + "value": "#1e3a8a", + "description": "Legacy primary dark" + } + } + }, + "secondary": { + "light": { + "main": { + "value": "#ff6e40", + "description": "Light mode secondary - orange" + }, + "light": { + "value": "#ff9e80", + "description": "Light secondary variant" + }, + "dark": { + "value": "#dd2c00", + "description": "Dark secondary variant" + } + }, + "dark": { + "main": { + "value": "#ff9e80", + "description": "Dark mode secondary - light orange" + }, + "light": { + "value": "#ffc9b0", + "description": "Dark secondary light variant" + }, + "dark": { + "value": "#ff6e40", + "description": "Dark secondary dark variant" + } + } + }, + "text": { + "light": { + "primary": { + "value": "#1e293b", + "description": "Light mode primary text" + }, + "secondary": { + "value": "#64748b", + "description": "Light mode secondary text" + }, + "onGlass": { + "value": "#ffffff", + "description": "Text color on glass elements (light mode)" + }, + "disabled": { + "value": "#94a3b8", + "description": "Disabled text color (light mode)" + } + }, + "dark": { + "primary": { + "value": "#ffffff", + "description": "Dark mode primary text - white" + }, + "secondary": { + "value": "#9e9e9e", + "description": "Dark mode secondary text" + }, + "onGlass": { + "value": "#ffffff", + "description": "Text color on glass elements (dark mode)" + }, + "disabled": { + "value": "#757575", + "description": "Disabled text color (dark mode)" + } + }, + "legacy": { + "title": { + "value": "#d7dcec", + "description": "Dark mode text title (legacy)" + }, + "primary": { + "value": "#bdc8f0", + "description": "Dark mode primary text (legacy)" + }, + "secondary": { + "value": "#8492c4", + "description": "Dark mode secondary text (legacy)" + } + } + }, + "divider": { + "light": { + "value": "rgba(15, 23, 42, 0.12)", + "description": "Light mode divider color" + }, + "dark": { + "value": "rgba(255, 255, 255, 0.12)", + "description": "Dark mode divider color" + } + }, + "action": { + "light": { + "hover": { + "value": "rgba(15, 23, 42, 0.04)", + "description": "Light mode hover state" + }, + "selected": { + "value": "rgba(15, 23, 42, 0.08)", + "description": "Light mode selected state" + }, + "disabled": { + "value": "rgba(15, 23, 42, 0.26)", + "description": "Light mode disabled state" + } + }, + "dark": { + "hover": { + "value": "rgba(255, 255, 255, 0.08)", + "description": "Dark mode hover state" + }, + "selected": { + "value": "rgba(255, 255, 255, 0.16)", + "description": "Dark mode selected state" + }, + "disabled": { + "value": "rgba(255, 255, 255, 0.3)", + "description": "Dark mode disabled state" + } + } + }, + "status": { + "success": { + "main": { + "value": "#4caf50", + "description": "Success status color - green" + }, + "light": { + "value": "#81c784", + "description": "Success light variant" + }, + "dark": { + "value": "#388e3c", + "description": "Success dark variant" + }, + "legacy": { + "main": "#00e676", + "lightBackground": "#cdf5d8", + "light": "#69f0ae", + "dark": "#00c853" + } + }, + "warning": { + "main": { + "value": "#ff9800", + "description": "Warning status color - orange" + }, + "light": { + "value": "#ffb74d", + "description": "Warning light variant" + }, + "dark": { + "value": "#f57c00", + "description": "Warning dark variant" + }, + "legacy": { + "main": "#ffe57f", + "light": "#fff8e1", + "dark": "#ffc107" + } + }, + "error": { + "main": { + "value": "#f44336", + "description": "Error status color - red" + }, + "light": { + "value": "#e57373", + "description": "Error light variant" + }, + "dark": { + "value": "#d32f2f", + "description": "Error dark variant" + }, + "legacy": { + "light": "#f3d2d2", + "dark": "#c62828" + } + }, + "info": { + "main": { + "value": "#2196f3", + "description": "Info status color - blue" + }, + "light": { + "value": "#64b5f6", + "description": "Info light variant" + }, + "dark": { + "value": "#1976d2", + "description": "Info dark variant" + } + } + }, + "accent": { + "orange": { + "main": { + "value": "#ffab91", + "description": "Orange accent" + }, + "light": { + "value": "#fbe9e7", + "description": "Orange light" + }, + "dark": { + "value": "#d84315", + "description": "Orange dark" + } + }, + "teal": { + "light": { + "value": "#76c893", + "description": "Teal light accent" + }, + "main": { + "value": "#52b69a", + "description": "Teal accent" + }, + "dark": { + "value": "#34a0a4", + "description": "Teal dark accent" + } + } + }, + "grey": { + "50": { + "value": "#fafafa" + }, + "100": { + "value": "#f5f5f5" + }, + "200": { + "value": "#eeeeee" + }, + "300": { + "value": "#e0e0e0" + }, + "500": { + "value": "#9e9e9e" + }, + "600": { + "value": "#757575" + }, + "700": { + "value": "#616161" + }, + "900": { + "value": "#212121" + } + } + }, + "glassmorphism": { + "light": { + "glassPrimary": { + "background": "linear-gradient(135deg, rgba(30, 58, 138, 0.95) 0%, rgba(59, 130, 246, 0.9) 50%, rgba(30, 58, 138, 0.95) 100%)", + "backdropFilter": "blur(20px) saturate(180%)", + "WebkitBackdropFilter": "blur(20px) saturate(180%)", + "border": "1px solid rgba(147, 197, 253, 0.5)", + "boxShadow": "0 8px 32px 0 rgba(59, 130, 246, 0.3), inset 0 1px 0 0 rgba(255, 255, 255, 0.3)", + "color": "#ffffff", + "description": "Light mode primary glass for headers/navigation with blue gradient" + }, + "glassSecondary": { + "background": "rgba(255, 255, 255, 0.85)", + "backdropFilter": "blur(16px)", + "WebkitBackdropFilter": "blur(16px)", + "border": "1px solid rgba(15, 23, 42, 0.1)", + "boxShadow": "0 4px 16px 0 rgba(0, 0, 0, 0.08)", + "description": "Light mode secondary glass for cards/panels" + }, + "glassSubtle": { + "background": "rgba(255, 255, 255, 0.7)", + "backdropFilter": "blur(12px)", + "WebkitBackdropFilter": "blur(12px)", + "border": "1px solid rgba(15, 23, 42, 0.15)", + "boxShadow": "0 2px 8px 0 rgba(0, 0, 0, 0.05)", + "description": "Light mode subtle glass for buttons/inputs" + }, + "glassHover": { + "background": "rgba(255, 255, 255, 0.95)", + "boxShadow": "0 12px 40px 0 rgba(0, 0, 0, 0.12)", + "transform": "translateY(-2px)", + "description": "Light mode hover state for glass elements" + }, + "transition": "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" + }, + "dark": { + "glassPrimary": { + "background": "rgba(0, 0, 0, 0.6)", + "backdropFilter": "blur(16px)", + "WebkitBackdropFilter": "blur(16px)", + "border": "1px solid rgba(255, 255, 255, 0.08)", + "boxShadow": "0 8px 32px 0 rgba(0, 0, 0, 0.4)", + "description": "Dark mode primary glass for headers/navigation" + }, + "glassSecondary": { + "background": "rgba(255, 255, 255, 0.03)", + "backdropFilter": "blur(12px)", + "WebkitBackdropFilter": "blur(12px)", + "border": "1px solid rgba(255, 255, 255, 0.08)", + "boxShadow": "0 4px 16px 0 rgba(0, 0, 0, 0.3)", + "description": "Dark mode secondary glass for cards/panels" + }, + "glassSubtle": { + "background": "rgba(255, 255, 255, 0.05)", + "backdropFilter": "blur(8px)", + "WebkitBackdropFilter": "blur(8px)", + "border": "1px solid rgba(255, 255, 255, 0.1)", + "boxShadow": "0 2px 8px 0 rgba(0, 0, 0, 0.2)", + "description": "Dark mode subtle glass for buttons/inputs" + }, + "glassHover": { + "background": "rgba(255, 255, 255, 0.08)", + "boxShadow": "0 12px 40px 0 rgba(0, 0, 0, 0.5)", + "transform": "translateY(-2px)", + "description": "Dark mode hover state for glass elements" + }, + "transition": "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" + } + }, + "typography": { + "font_families": { + "sans": ["var(--font-poppins)", "system-ui", "-apple-system", "sans-serif"], + "mono": ["Consolas", "monospace"] + }, + "font_sizes": { + "h1": "2.5rem", + "h2": "2rem", + "h3": "1.75rem", + "h4": "1.5rem", + "h5": "1.25rem", + "h6": "1.125rem", + "body1": "1rem", + "body2": "0.875rem", + "xs": "0.75rem", + "sm": "0.875rem", + "base": "1rem", + "lg": "1.125rem", + "xl": "1.25rem", + "2xl": "1.5rem", + "3xl": "1.875rem", + "4xl": "2.25rem" + }, + "font_weights": { + "100": "100", + "300": "300", + "normal": "400", + "medium": "500", + "600": "600", + "700": "700" + }, + "line_heights": { + "h1": "1.2", + "h2": "1.3", + "h3": "1.3", + "h4": "1.4", + "h5": "1.4", + "h6": "1.4", + "body1": "1.5", + "body2": "1.5", + "tight": "1.25", + "normal": "1.5", + "relaxed": "1.75" + } + }, + "spacing": { + "unit": "0.25rem", + "scale": { + "0": "0", + "1": "0.25rem", + "2": "0.5rem", + "3": "0.75rem", + "4": "1rem", + "5": "1.25rem", + "6": "1.5rem", + "8": "2rem", + "10": "2.5rem", + "12": "3rem", + "16": "4rem", + "20": "5rem", + "24": "6rem" + } + }, + "breakpoints": { + "xs": "0px", + "sm": "600px", + "md": "900px", + "lg": "1200px", + "xl": "1536px", + "xxl": "1920px" + }, + "border_radius": { + "none": "0", + "sm": "4px", + "md": "6px", + "lg": "8px", + "xl": "12px", + "full": "9999px" + }, + "shadows": { + "sm": "0 1px 2px 0 rgba(0, 0, 0, 0.05)", + "md": "0 4px 6px -1px rgba(0, 0, 0, 0.1)", + "lg": "0 10px 15px -3px rgba(0, 0, 0, 0.1)", + "glass_light_1": "0 8px 32px 0 rgba(59, 130, 246, 0.3), inset 0 1px 0 0 rgba(255, 255, 255, 0.3)", + "glass_light_2": "0 4px 16px 0 rgba(0, 0, 0, 0.08)", + "glass_dark_1": "0 8px 32px 0 rgba(0, 0, 0, 0.4)", + "glass_dark_2": "0 4px 16px 0 rgba(0, 0, 0, 0.3)" + }, + "transitions": { + "duration": { + "shortest": "150ms", + "shorter": "200ms", + "short": "250ms", + "standard": "300ms", + "complex": "375ms", + "enteringScreen": "225ms", + "leavingScreen": "195ms" + }, + "easing": { + "easeInOut": "cubic-bezier(0.4, 0, 0.2, 1)", + "easeOut": "cubic-bezier(0.0, 0, 0.2, 1)", + "easeIn": "cubic-bezier(0.4, 0, 1, 1)", + "sharp": "cubic-bezier(0.4, 0, 0.6, 1)" + } + }, + "components": { + "button": { + "base": { + "borderRadius": "8px", + "textTransform": "none", + "transition": "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)" + }, + "contained": { + "light": { + "background": "linear-gradient(135deg, rgb(30, 58, 138) 0%, rgb(59, 130, 246) 100%)", + "color": "#ffffff", + "boxShadow": "0 4px 12px 0 rgba(59, 130, 246, 0.3)" + }, + "dark": { + "uses": "glassPrimary" + }, + "hover": { + "transform": "translateY(-2px)" + }, + "disabled": { + "light": { + "backgroundColor": "rgba(0, 0, 0, 0.12)", + "color": "rgba(0, 0, 0, 0.26)" + }, + "dark": { + "backgroundColor": "rgba(255, 255, 255, 0.12)", + "color": "rgba(255, 255, 255, 0.3)" + } + } + }, + "outlined": { + "uses": "glassSubtle" + }, + "text": { + "background": "transparent", + "backdropFilter": "none", + "border": "none", + "boxShadow": "none" + } + }, + "card": { + "light": { + "background": "#ffffff", + "border": "1px solid rgba(15, 23, 42, 0.08)", + "boxShadow": "0 1px 3px 0 rgba(0, 0, 0, 0.1)", + "borderRadius": "12px" + }, + "dark": { + "background": "#1a1a1a", + "border": "1px solid rgba(255, 255, 255, 0.08)", + "boxShadow": "0 1px 3px 0 rgba(0, 0, 0, 0.3)", + "borderRadius": "12px" + }, + "hover": { + "transform": "translateY(-2px)" + } + }, + "input": { + "light": { + "backgroundColor": "#ffffff", + "borderColor": "rgba(15, 23, 42, 0.23)", + "borderRadius": "8px" + }, + "dark": { + "backgroundColor": "rgba(255, 255, 255, 0.05)", + "borderColor": "rgba(255, 255, 255, 0.23)", + "borderRadius": "8px" + }, + "focus": { + "light": { + "boxShadow": "0 0 0 3px rgba(59, 130, 246, 0.1)" + }, + "dark": { + "boxShadow": "0 0 0 3px rgba(77, 182, 172, 0.1)" + } + } + }, + "drawer": { + "uses": "glassPrimary", + "borderRight": "none" + }, + "appBar": { + "uses": "glassPrimary", + "boxShadow": "none" + }, + "backdrop": { + "light": { + "backgroundColor": "rgba(0, 0, 0, 0.5)", + "backdropFilter": "blur(8px)" + }, + "dark": { + "backgroundColor": "rgba(0, 0, 0, 0.75)", + "backdropFilter": "blur(8px)" + } + } + }, + "animations": { + "pulseGradient": { + "0%, 100%": { + "backgroundPosition": "0% 50%" + }, + "50%": { + "backgroundPosition": "100% 50%" + } + } + }, + "_visual_verification": { + "verified": false, + "reason": "Static analysis only - visual verification requires running dev server and application to be accessible", + "computed_values": null, + "discrepancies": null + }, + "_metadata": { + "analysis_notes": "Extracted from Material-UI theme configuration and glassmorphism tokens. The project uses a unified theme system with light/dark mode support. Primary design system source is packages-answers/ui with Material-UI theme overrides. Legacy theme-vars.js in packages/ui provides fallback colors. Apps/web uses Next.js with Poppins font family via Google Fonts.", + "files_analyzed": [ + "packages-answers/ui/src/theme/tokens/colors.ts - Core color tokens for light and dark modes", + "packages-answers/ui/src/theme/tokens/glassmorphism.ts - Glassmorphism effect tokens with backdrop blur", + "packages-answers/ui/src/theme/index.tsx - Theme provider and MUI theme creation", + "packages-answers/ui/src/theme/components/muiOverrides.ts - MUI component customizations with glass styling", + "packages/ui/src/assets/theme-vars.js - Legacy Flowise theme variables", + "apps/web/app/layout.tsx - Root layout with Poppins font configuration" + ], + "design_system_architecture": { + "primary_source": "Material-UI (MUI) v5 with custom extensions", + "theme_modes": ["light", "dark"], + "key_features": [ + "Unified glassmorphism design tokens (blur effects, backdrop filters)", + "Gradient-based primary colors (blue gradient in light mode)", + "Light/dark mode responsive colors", + "Component-level overrides for MUI components", + "Status colors for success/warning/error/info", + "Smooth transitions and animations" + ], + "font_strategy": "Google Fonts Poppins with system font fallback", + "spacing_system": "Base unit of 0.25rem with Tailwind-inspired scale", + "border_radius_values": [0, 4, 6, 8, 12, 9999] + }, + "implementation_notes": { + "light_mode": "Uses white backgrounds with blue gradient primary buttons and dark text. Glassmorphism elements use light semi-transparent backgrounds.", + "dark_mode": "Uses dark backgrounds (#0b0b0b, #161616) with glassmorphism using very transparent white overlays and light text. Primary buttons use glass styling with optional dark overlay.", + "glassmorphism": "Implemented via CSS backdrop-filter and -webkit-backdrop-filter with varying blur amounts (8-20px) depending on component type.", + "transitions": "All interactive elements use 300ms standard transition with cubic-bezier easing for smooth animations.", + "component_customization": "Extensive MUI component overrides including Button, Card, Input, Drawer, AppBar, Menu, and more with consistent glass styling application." + }, + "warnings": [ + "Legacy color variables exist in packages/ui/src/assets/theme-vars.js - these may conflict with new unified theme", + "Two separate theme systems: Modern unified theme in packages-answers/ui and legacy Flowise theme in packages/ui - may cause inconsistencies", + "Visual verification not performed - actual rendered values should be verified when dev server is running" + ] + } +} diff --git a/.alphaAgent/spec/env-vars.json b/.alphaAgent/spec/env-vars.json new file mode 100644 index 00000000000..05931ff808a --- /dev/null +++ b/.alphaAgent/spec/env-vars.json @@ -0,0 +1,1733 @@ +{ + "version": "1.0", + "variables": [ + { + "name": "PORT", + "description": "Server port number for Express/Node.js", + "required": false, + "default": "3000", + "example": "3000", + "sensitive": false, + "category": "config" + }, + { + "name": "NODE_ENV", + "description": "Node environment (development, production, test)", + "required": false, + "default": "development", + "example": "development", + "sensitive": false, + "category": "config" + }, + { + "name": "DEBUG", + "description": "Debug namespace filter (e.g., 'billing:*' for selective debug logging)", + "required": false, + "example": "billing:*", + "sensitive": false, + "category": "config" + }, + { + "name": "LOG_LEVEL", + "description": "Logging verbosity level (error, warn, info, verbose, debug)", + "required": false, + "example": "info", + "sensitive": false, + "category": "config" + }, + { + "name": "DISABLE_FLOWISE_TELEMETRY", + "description": "Disable Flowise telemetry collection", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "config" + }, + { + "name": "CORS_ORIGINS", + "description": "CORS allowed origins (use '*' for development only)", + "required": false, + "default": "*", + "example": "*", + "sensitive": false, + "category": "config" + }, + { + "name": "IFRAME_ORIGINS", + "description": "Allowed origins for iframe embedding", + "required": false, + "default": "*", + "example": "*", + "sensitive": false, + "category": "config" + }, + { + "name": "DOMAIN", + "description": "Server domain URL", + "required": false, + "example": "http://localhost:4000", + "sensitive": false, + "category": "config" + }, + { + "name": "DATABASE_TYPE", + "description": "Database type (postgres, mysql, sqlite, etc.)", + "required": true, + "default": "postgres", + "example": "postgres", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_HOST", + "description": "Database server hostname", + "required": true, + "example": "localhost", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_PORT", + "description": "Database server port", + "required": true, + "default": "5432", + "example": "5432", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_USER", + "description": "Database username", + "required": true, + "example": "example_user", + "sensitive": true, + "category": "database" + }, + { + "name": "DATABASE_PASSWORD", + "description": "Database password", + "required": true, + "example": "example_password", + "sensitive": true, + "category": "database" + }, + { + "name": "DATABASE_NAME", + "description": "Database name", + "required": true, + "example": "example_db", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_URL", + "description": "Full database connection string (alternative to individual DATABASE_* vars)", + "required": false, + "example": "postgresql://example_user:example_password@localhost:5432/example_db?schema=public", + "sensitive": true, + "category": "database" + }, + { + "name": "DATABASE_SSL", + "description": "Enable SSL connection to database", + "required": false, + "example": "true", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_REJECT_UNAUTHORIZED", + "description": "Reject unauthorized SSL certificates", + "required": false, + "example": "true", + "sensitive": false, + "category": "database" + }, + { + "name": "DATABASE_PATH", + "description": "Path to SQLite database file", + "required": false, + "example": "/root/.flowise", + "sensitive": false, + "category": "database" + }, + { + "name": "REDIS_URL", + "description": "Redis connection URL", + "required": false, + "default": "redis://localhost:6379", + "example": "redis://localhost:6379", + "sensitive": false, + "category": "database" + }, + { + "name": "REDIS_HOST", + "description": "Redis server hostname (alternative to REDIS_URL)", + "required": false, + "default": "localhost", + "example": "localhost", + "sensitive": false, + "category": "database" + }, + { + "name": "REDIS_PORT", + "description": "Redis server port (alternative to REDIS_URL)", + "required": false, + "default": "6379", + "example": "6379", + "sensitive": false, + "category": "database" + }, + { + "name": "REDIS_USERNAME", + "description": "Redis username for authentication", + "required": false, + "default": "default", + "example": "default", + "sensitive": true, + "category": "database" + }, + { + "name": "REDIS_PASSWORD", + "description": "Redis password for authentication", + "required": false, + "example": "password", + "sensitive": true, + "category": "database" + }, + { + "name": "REDIS_TLS", + "description": "Enable TLS for Redis connection", + "required": false, + "example": "false", + "sensitive": false, + "category": "database" + }, + { + "name": "AUTH0_ISSUER_BASE_URL", + "description": "Auth0 tenant domain (e.g., https://your-tenant.auth0.com)", + "required": true, + "example": "https://your-tenant.auth0.com", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_BASE_URL", + "description": "Application base URL for Auth0 callbacks", + "required": true, + "example": "http://localhost:3000", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_CLIENT_ID", + "description": "Auth0 application client ID", + "required": true, + "example": "your_auth0_client_id", + "sensitive": true, + "category": "auth" + }, + { + "name": "AUTH0_CLIENT_SECRET", + "description": "Auth0 application client secret", + "required": true, + "example": "your_auth0_client_secret", + "sensitive": true, + "category": "auth" + }, + { + "name": "AUTH0_AUDIENCE", + "description": "Auth0 API audience identifier", + "required": true, + "example": "your_auth0_audience", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_SCOPE", + "description": "Auth0 OAuth scopes to request", + "required": false, + "default": "openid profile email", + "example": "openid profile email", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_TOKEN_SIGN_ALG", + "description": "Auth0 token signing algorithm", + "required": false, + "default": "RS256", + "example": "RS256", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_ORGANIZATION_ID", + "description": "Auth0 organization ID (if using Auth0 Organizations)", + "required": false, + "example": "your_auth0_org_id", + "sensitive": false, + "category": "auth" + }, + { + "name": "AUTH0_JWKS_URI", + "description": "Auth0 JWKS endpoint URI for token validation", + "required": false, + "example": "https://your-tenant.auth0.com/.well-known/jwks.json", + "sensitive": false, + "category": "auth" + }, + { + "name": "WEB_AUTH0_SECRET", + "description": "Auth0 secret for Web app session encryption", + "required": false, + "example": "your_web_auth0_secret", + "sensitive": true, + "category": "auth" + }, + { + "name": "API_HOST", + "description": "Backend API host URL for frontend requests", + "required": true, + "example": "http://localhost:3000", + "sensitive": false, + "category": "api" + }, + { + "name": "FLOWISE_DOMAIN", + "description": "Flowise backend domain URL", + "required": false, + "default": "http://localhost:3000", + "example": "http://localhost:3000", + "sensitive": false, + "category": "api" + }, + { + "name": "ANSWERAI_DOMAIN", + "description": "TheAnswer application domain", + "required": false, + "default": "http://localhost:3000", + "example": "https://app.theanswer.ai", + "sensitive": false, + "category": "api" + }, + { + "name": "ANSWERAI_API_KEY", + "description": "TheAnswer API key for internal authentication", + "required": false, + "example": "your_api_key", + "sensitive": true, + "category": "api" + }, + { + "name": "APIKEY_STORAGE_TYPE", + "description": "Where to store API keys (db or local)", + "required": false, + "default": "db", + "example": "db", + "sensitive": false, + "category": "api" + }, + { + "name": "STORAGE_TYPE", + "description": "Storage backend type (local, s3, gcs)", + "required": false, + "default": "local", + "example": "s3", + "sensitive": false, + "category": "storage" + }, + { + "name": "BLOB_STORAGE_PATH", + "description": "Local path for blob storage", + "required": false, + "example": "/root/.flowise/storage", + "sensitive": false, + "category": "storage" + }, + { + "name": "S3_STORAGE_BUCKET_NAME", + "description": "AWS S3 bucket name", + "required": false, + "example": "your_bucket_name", + "sensitive": false, + "category": "storage" + }, + { + "name": "S3_STORAGE_ACCESS_KEY_ID", + "description": "AWS S3 access key ID", + "required": false, + "example": "your_access_key_id", + "sensitive": true, + "category": "storage" + }, + { + "name": "S3_STORAGE_SECRET_ACCESS_KEY", + "description": "AWS S3 secret access key", + "required": false, + "example": "your_secret_access_key", + "sensitive": true, + "category": "storage" + }, + { + "name": "S3_STORAGE_REGION", + "description": "AWS S3 region", + "required": false, + "example": "us-west-2", + "sensitive": false, + "category": "storage" + }, + { + "name": "S3_ENDPOINT_URL", + "description": "Custom S3 endpoint URL (for S3-compatible services)", + "required": false, + "example": "https://s3.example.com", + "sensitive": false, + "category": "storage" + }, + { + "name": "GOOGLE_CLOUD_STORAGE_CREDENTIAL", + "description": "Path to GCS service account JSON key file", + "required": false, + "example": "/path/to/keyfile.json", + "sensitive": false, + "category": "storage" + }, + { + "name": "GOOGLE_CLOUD_STORAGE_PROJ_ID", + "description": "GCP project ID", + "required": false, + "example": "your-gcp-project-id", + "sensitive": false, + "category": "storage" + }, + { + "name": "GOOGLE_CLOUD_STORAGE_BUCKET_NAME", + "description": "GCS bucket name", + "required": false, + "example": "your-bucket-name", + "sensitive": false, + "category": "storage" + }, + { + "name": "DATA_SIDEKICK_URL", + "description": "Data Sidekick (data engine) API base URL", + "required": false, + "default": "http://localhost:3001", + "example": "http://localhost:3001", + "sensitive": false, + "category": "services" + }, + { + "name": "DATA_SIDEKICK_CLIENT_ID", + "description": "Auth0 M2M client ID for Data Sidekick API", + "required": false, + "example": "your_m2m_client_id", + "sensitive": true, + "category": "services" + }, + { + "name": "DATA_SIDEKICK_CLIENT_SECRET", + "description": "Auth0 M2M client secret for Data Sidekick API", + "required": false, + "example": "your_m2m_client_secret", + "sensitive": true, + "category": "services" + }, + { + "name": "DATA_SIDEKICK_AUDIENCE", + "description": "Auth0 audience for Data Sidekick API", + "required": false, + "default": "https://data-sidekick-api", + "example": "https://data-sidekick-api", + "sensitive": false, + "category": "services" + }, + { + "name": "DATA_ENGINE_SERVICE_KEY", + "description": "Legacy service key for Data Engine authentication", + "required": false, + "example": "your-shared-secret-key", + "sensitive": true, + "category": "services" + }, + { + "name": "DATA_ENGINE_AUTH_ALLOW_FALLBACK", + "description": "Allow fallback to service key when M2M auth fails (true for dev, false for prod)", + "required": false, + "default": "true", + "example": "false", + "sensitive": false, + "category": "services" + }, + { + "name": "STRIPE_SECRET_KEY", + "description": "Stripe API secret key", + "required": false, + "example": "sk_live_...", + "sensitive": true, + "category": "billing" + }, + { + "name": "STRIPE_WEBHOOK_SECRET", + "description": "Stripe webhook signing secret", + "required": false, + "example": "whsec_...", + "sensitive": true, + "category": "billing" + }, + { + "name": "STRIPE_METER_PREFIX", + "description": "Prefix for Stripe meter events", + "required": false, + "example": "your_meter_prefix", + "sensitive": false, + "category": "billing" + }, + { + "name": "SPARK_RATE", + "description": "Spark usage rate for billing", + "required": false, + "default": "0.0004", + "example": "0.0004", + "sensitive": false, + "category": "billing" + }, + { + "name": "BILLING_DEFAULT_STRIPE_CUSTOMER_ID", + "description": "Default Stripe customer ID for fallback billing", + "required": false, + "example": "cus_xxxxxxxxxxxxx", + "sensitive": false, + "category": "billing" + }, + { + "name": "OVERRIDE_BILLING_CUSTOMER_ID", + "description": "Override Stripe customer ID (ignores trace metadata)", + "required": false, + "example": "cus_xxxxxxxxxxxxx", + "sensitive": false, + "category": "billing" + }, + { + "name": "LANGFUSE_SECRET_KEY", + "description": "Langfuse secret key for LLM observability", + "required": false, + "example": "sk_lf_...", + "sensitive": true, + "category": "monitoring" + }, + { + "name": "LANGFUSE_PUBLIC_KEY", + "description": "Langfuse public key", + "required": false, + "example": "pk_...", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "LANGFUSE_HOST", + "description": "Langfuse API host URL", + "required": false, + "default": "https://cloud.langfuse.com", + "example": "https://cloud.langfuse.com", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "LANGFUSE_RELEASE", + "description": "Langfuse release/version identifier", + "required": false, + "example": "1.0.0", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "LANGCHAIN_HANDLER", + "description": "LangChain event handler (e.g., 'langchain')", + "required": false, + "default": "langchain", + "example": "langchain", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "GOOGLE_CLIENT_ID", + "description": "Google OAuth 2.0 client ID", + "required": false, + "example": "your_google_client_id", + "sensitive": true, + "category": "integrations" + }, + { + "name": "GOOGLE_CLIENT_SECRET", + "description": "Google OAuth 2.0 client secret", + "required": false, + "example": "your_google_client_secret", + "sensitive": true, + "category": "integrations" + }, + { + "name": "NEXT_PUBLIC_GOOGLE_CLIENT_ID", + "description": "Google OAuth client ID for frontend (client-side)", + "required": false, + "example": "your_google_client_id", + "sensitive": false, + "category": "integrations" + }, + { + "name": "NEXT_PUBLIC_GOOGLE_DEVELOPER_KEY", + "description": "Google API key for frontend features", + "required": false, + "example": "your_google_api_key", + "sensitive": false, + "category": "integrations" + }, + { + "name": "NEXT_PUBLIC_ANSWER_ENGINE_DOMAIN", + "description": "Answer Engine domain for navigation links", + "required": false, + "example": "https://answerengine.com", + "sensitive": false, + "category": "integrations" + }, + { + "name": "ZOOM_CLIENT_ID", + "description": "Zoom OAuth application client ID", + "required": false, + "example": "your_zoom_client_id", + "sensitive": true, + "category": "integrations" + }, + { + "name": "ZOOM_CLIENT_SECRET", + "description": "Zoom OAuth application client secret", + "required": false, + "example": "your_zoom_client_secret", + "sensitive": true, + "category": "integrations" + }, + { + "name": "ZOOM_CALLBACK_URL", + "description": "Zoom OAuth callback URL", + "required": false, + "example": "https://app.example.com/auth/zoom/callback", + "sensitive": false, + "category": "integrations" + }, + { + "name": "ZOOM_SECRET", + "description": "Zoom webhook signing secret", + "required": false, + "example": "your_zoom_secret", + "sensitive": true, + "category": "integrations" + }, + { + "name": "FIDDLER_GUARDRAILS_ENABLED", + "description": "Enable Fiddler AI guardrails for LLM safety", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_SAFETY_ENABLED", + "description": "Enable safety checks (harmful, violent, etc.)", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_SAFETY_THRESHOLD", + "description": "Safety threshold 0-1 (higher = stricter)", + "required": false, + "default": "0.1", + "example": "0.1", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_SAFETY_ACTION", + "description": "Action on safety violation (block, redact, replace, warn, continue)", + "required": false, + "default": "block", + "example": "block", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_PII_ENABLED", + "description": "Enable PII detection", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_PII_THRESHOLD", + "description": "PII detection confidence threshold 0-1", + "required": false, + "default": "0.8", + "example": "0.8", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_PII_ACTION", + "description": "Action on PII detection (block, redact, replace, warn, continue)", + "required": false, + "default": "redact", + "example": "redact", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_FAITHFULNESS_ENABLED", + "description": "Enable hallucination/faithfulness detection for RAG", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_FAITHFULNESS_THRESHOLD", + "description": "Faithfulness score threshold 0-1", + "required": false, + "default": "0.7", + "example": "0.7", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_FAITHFULNESS_ACTION", + "description": "Action on low faithfulness (block, redact, replace, warn, continue)", + "required": false, + "default": "warn", + "example": "warn", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_CIRCUIT_FAILURE_THRESHOLD", + "description": "Consecutive failures before circuit breaker opens", + "required": false, + "default": "5", + "example": "5", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_CIRCUIT_RESET_TIMEOUT", + "description": "Milliseconds to wait before circuit recovery attempt", + "required": false, + "default": "30000", + "example": "30000", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_CIRCUIT_SUCCESS_THRESHOLD", + "description": "Successful calls needed to close circuit", + "required": false, + "default": "3", + "example": "3", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_CACHE_ENABLED", + "description": "Enable Redis caching for guardrails responses", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "FIDDLER_CACHE_TTL", + "description": "Cache TTL in seconds", + "required": false, + "default": "3600", + "example": "3600", + "sensitive": false, + "category": "guardrails" + }, + { + "name": "PUBLIC_ORG_ID", + "description": "Default organization ID for trial accounts", + "required": false, + "example": "your_org_id", + "sensitive": false, + "category": "config" + }, + { + "name": "TRIAL_PLAN_EXECUTIONS", + "description": "Number of chatflow executions allowed in trial plan", + "required": false, + "default": "999999999", + "example": "999999999", + "sensitive": false, + "category": "config" + }, + { + "name": "SEEDCREDENTIALS_USER_ID", + "description": "User UUID for seeded credentials (leave empty for auto-generate)", + "required": false, + "example": "550e8400-e29b-41d4-a716-446655440000", + "sensitive": false, + "category": "credentials" + }, + { + "name": "SEEDCREDENTIALS_ORG_ID", + "description": "Organization UUID for seeded credentials (leave empty for auto-generate)", + "required": false, + "example": "550e8400-e29b-41d4-a716-446655440000", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_OPENAI_API_KEY", + "description": "OpenAI API key (auto-seeded as credential)", + "required": false, + "example": "sk-...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_ANTHROPHIC", + "description": "Anthropic (Claude) API key (auto-seeded as credential)", + "required": false, + "example": "sk-ant-...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_GROQ", + "description": "Groq API key (auto-seeded as credential)", + "required": false, + "example": "gsk_...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_DEEPSEEK", + "description": "DeepSeek API key (auto-seeded as credential)", + "required": false, + "example": "sk-...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REPLICATE", + "description": "Replicate API key (auto-seeded as credential)", + "required": false, + "example": "r8_...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_GOOGLE_GENERATIVE_AI_API_KEY", + "description": "Google Generative AI (Gemini) API key (auto-seeded as credential)", + "required": false, + "example": "AIzaSy...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_EXASEARCH", + "description": "Exa Search API key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_SERPAPI", + "description": "SerpAPI key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_BRAVE_SEARCH", + "description": "Brave Search API key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_GOOGLE_SEARCH_API", + "description": "Google Custom Search API key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_GOOGLE_SEARCH_API_ENGINE_ID", + "description": "Google Custom Search Engine ID (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_PINECONE", + "description": "Pinecone API key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_PINECONE_INDEX", + "description": "Pinecone index name (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_PINECONE_INDEX", + "description": "Alternative Pinecone index configuration", + "required": false, + "example": "...", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_AWS_BEDROCK_ACCESS_KEY", + "description": "AWS Bedrock access key (auto-seeded as credential)", + "required": false, + "example": "AKIA...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_AWS_BEDROCK_SECRET_KEY", + "description": "AWS Bedrock secret key (auto-seeded as credential)", + "required": false, + "example": "...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_SUPABASE_URL", + "description": "Supabase project URL (auto-seeded as credential)", + "required": false, + "example": "https://xxx.supabase.co", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_SUPABASE_API", + "description": "Supabase API key (auto-seeded as credential)", + "required": false, + "example": "eyJhbGc...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REDIS_URL", + "description": "Redis URL for credential seeding", + "required": false, + "default": "redis://localhost:6379", + "example": "redis://localhost:6379", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REDIS_HOST", + "description": "Redis host for credential seeding (alternative to URL)", + "required": false, + "default": "localhost", + "example": "localhost", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REDIS_PORT", + "description": "Redis port for credential seeding", + "required": false, + "default": "6379", + "example": "6379", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REDIS_USERNAME", + "description": "Redis username for credential seeding", + "required": false, + "default": "default", + "example": "default", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_REDIS_PASSWORD", + "description": "Redis password for credential seeding", + "required": false, + "example": "password", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_HOST", + "description": "PostgreSQL host for record manager (auto-seeded)", + "required": false, + "default": "127.0.0.1", + "example": "127.0.0.1", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_PORT", + "description": "PostgreSQL port for record manager", + "required": false, + "default": "5432", + "example": "5432", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_DATABASE", + "description": "PostgreSQL database for record manager", + "required": false, + "default": "example_db", + "example": "example_db", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_USER", + "description": "PostgreSQL user for record manager", + "required": false, + "default": "example_user", + "example": "example_user", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_PASSWORD", + "description": "PostgreSQL password for record manager", + "required": false, + "default": "example_password", + "example": "example_password", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_RECORDMANAGER_TABLE_NAME", + "description": "PostgreSQL table name for record manager", + "required": false, + "default": "upsertion_records", + "example": "upsertion_records", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_HOST", + "description": "PostgreSQL host for agent memory (auto-seeded)", + "required": false, + "default": "127.0.0.1", + "example": "127.0.0.1", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_PORT", + "description": "PostgreSQL port for agent memory", + "required": false, + "default": "5432", + "example": "5432", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_DATABASE", + "description": "PostgreSQL database for agent memory", + "required": false, + "default": "example_db", + "example": "example_db", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_USER", + "description": "PostgreSQL user for agent memory", + "required": false, + "default": "example_user", + "example": "example_user", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_PASSWORD", + "description": "PostgreSQL password for agent memory", + "required": false, + "default": "example_password", + "example": "example_password", + "sensitive": true, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_POSTGRES_AGENTMEMORY_TABLE_NAME", + "description": "PostgreSQL table name for agent memory", + "required": false, + "default": "aai_agent_memory", + "example": "aai_agent_memory", + "sensitive": false, + "category": "credentials" + }, + { + "name": "AAI_DEFAULT_GITHUB_TOKEN", + "description": "GitHub API token (auto-seeded as credential)", + "required": false, + "example": "ghp_...", + "sensitive": true, + "category": "credentials" + }, + { + "name": "LINEAR_API_KEY", + "description": "Linear API key for error reporting", + "required": false, + "example": "lin_api_...", + "sensitive": true, + "category": "integrations" + }, + { + "name": "LINEAR_ERROR_REPORT_TEAM_ID", + "description": "Linear team ID for error report tickets", + "required": false, + "example": "TEAM-123", + "sensitive": false, + "category": "integrations" + }, + { + "name": "LINEAR_ERROR_REPORT_BUG_LABEL_ID", + "description": "Linear bug label ID for error reports", + "required": false, + "example": "LABEL-456", + "sensitive": false, + "category": "integrations" + }, + { + "name": "VITE_PORT", + "description": "Vite development server port", + "required": false, + "default": "8080", + "example": "8080", + "sensitive": false, + "category": "config" + }, + { + "name": "VITE_API_BASE_URL", + "description": "Vite API base URL (frontend)", + "required": false, + "example": "http://localhost:3000", + "sensitive": false, + "category": "config" + }, + { + "name": "VITE_UI_BASE_URL", + "description": "Vite UI base URL", + "required": false, + "example": "http://localhost:3000", + "sensitive": false, + "category": "config" + }, + { + "name": "MODE", + "description": "Queue mode (queue or main)", + "required": false, + "default": "main", + "example": "queue", + "sensitive": false, + "category": "queue" + }, + { + "name": "QUEUE_NAME", + "description": "BullMQ queue name", + "required": false, + "default": "flowise-queue", + "example": "flowise-queue", + "sensitive": false, + "category": "queue" + }, + { + "name": "WORKER_CONCURRENCY", + "description": "Maximum concurrent workers", + "required": false, + "default": "100000", + "example": "100000", + "sensitive": false, + "category": "queue" + }, + { + "name": "QUEUE_REDIS_EVENT_STREAM_MAX_LEN", + "description": "Max Redis stream length for queue events", + "required": false, + "default": "100000", + "example": "100000", + "sensitive": false, + "category": "queue" + }, + { + "name": "REMOVE_ON_AGE", + "description": "Remove completed jobs after N seconds", + "required": false, + "default": "86400", + "example": "86400", + "sensitive": false, + "category": "queue" + }, + { + "name": "REMOVE_ON_COUNT", + "description": "Keep only last N completed jobs", + "required": false, + "default": "10000", + "example": "10000", + "sensitive": false, + "category": "queue" + }, + { + "name": "ENABLE_BULLMQ_DASHBOARD", + "description": "Enable BullMQ admin dashboard", + "required": false, + "example": "true", + "sensitive": false, + "category": "queue" + }, + { + "name": "GLOBAL_AGENT_HTTP_PROXY", + "description": "HTTP proxy URL for outgoing requests", + "required": false, + "example": "http://proxy.example.com:8080", + "sensitive": false, + "category": "config" + }, + { + "name": "GLOBAL_AGENT_HTTPS_PROXY", + "description": "HTTPS proxy URL for outgoing requests", + "required": false, + "example": "https://proxy.example.com:8080", + "sensitive": false, + "category": "config" + }, + { + "name": "GLOBAL_AGENT_NO_PROXY", + "description": "Comma-separated hosts to bypass proxy", + "required": false, + "example": "localhost,127.0.0.1", + "sensitive": false, + "category": "config" + }, + { + "name": "TRUST_PROXY", + "description": "Trust X-Forwarded-* headers (true/false or proxy IP)", + "required": false, + "example": "true", + "sensitive": false, + "category": "config" + }, + { + "name": "HTTP_DENY_LIST", + "description": "Comma-separated URLs to block from HTTP requests", + "required": false, + "example": "http://internal.example.com", + "sensitive": false, + "category": "config" + }, + { + "name": "CUSTOM_MCP_SECURITY_CHECK", + "description": "Enable security checks for custom MCP tools", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "config" + }, + { + "name": "CUSTOM_MCP_PROTOCOL", + "description": "MCP protocol type (stdio or sse)", + "required": false, + "default": "sse", + "example": "sse", + "sensitive": false, + "category": "config" + }, + { + "name": "JWT_AUTH_TOKEN_SECRET", + "description": "JWT secret key for access tokens", + "required": true, + "example": "AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD", + "sensitive": true, + "category": "auth" + }, + { + "name": "JWT_REFRESH_TOKEN_SECRET", + "description": "JWT secret key for refresh tokens", + "required": true, + "example": "AABBCCDDAABBCCDDAABBCCDDAABBCCDDAABBCCDD", + "sensitive": true, + "category": "auth" + }, + { + "name": "JWT_ISSUER", + "description": "JWT issuer identifier", + "required": true, + "example": "ISSUER", + "sensitive": false, + "category": "auth" + }, + { + "name": "JWT_AUDIENCE", + "description": "JWT audience identifier", + "required": true, + "example": "AUDIENCE", + "sensitive": false, + "category": "auth" + }, + { + "name": "JWT_TOKEN_EXPIRY_IN_MINUTES", + "description": "JWT access token expiry in minutes", + "required": false, + "default": "360", + "example": "360", + "sensitive": false, + "category": "auth" + }, + { + "name": "JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES", + "description": "JWT refresh token expiry in minutes", + "required": false, + "default": "43200", + "example": "43200", + "sensitive": false, + "category": "auth" + }, + { + "name": "POSTHOG_PUBLIC_API_KEY", + "description": "PostHog public API key for analytics", + "required": false, + "example": "phc_...", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "ENABLE_METRICS", + "description": "Enable metrics collection", + "required": false, + "default": "false", + "example": "false", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_PROVIDER", + "description": "Metrics provider (prometheus or open_telemetry)", + "required": false, + "default": "prometheus", + "example": "prometheus", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_INCLUDE_NODE_METRICS", + "description": "Include Node.js process metrics", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_SERVICE_NAME", + "description": "Service name for metrics", + "required": false, + "default": "FlowiseAI", + "example": "FlowiseAI", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT", + "description": "OpenTelemetry metrics endpoint", + "required": false, + "example": "http://localhost:4318/v1/metrics", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_OPEN_TELEMETRY_PROTOCOL", + "description": "OpenTelemetry protocol (http, grpc, or proto)", + "required": false, + "default": "http", + "example": "http", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "METRICS_OPEN_TELEMETRY_DEBUG", + "description": "Enable OpenTelemetry debug logging", + "required": false, + "default": "false", + "example": "false", + "sensitive": false, + "category": "monitoring" + }, + { + "name": "SHOW_COMMUNITY_NODES", + "description": "Show community-contributed Flowise nodes", + "required": false, + "example": "true", + "sensitive": false, + "category": "config" + }, + { + "name": "FLOWISE_FILE_SIZE_LIMIT", + "description": "Maximum file upload size", + "required": false, + "default": "50mb", + "example": "50mb", + "sensitive": false, + "category": "config" + }, + { + "name": "DISABLED_NODES", + "description": "Comma-separated list of node names to disable", + "required": false, + "example": "bufferMemory,chatOpenAI", + "sensitive": false, + "category": "config" + }, + { + "name": "MODEL_LIST_CONFIG_JSON", + "description": "Path to custom model list JSON configuration file", + "required": false, + "example": "/path/to/models.json", + "sensitive": false, + "category": "config" + }, + { + "name": "SECRETKEY_STORAGE_TYPE", + "description": "Secret key storage type (local or aws)", + "required": false, + "default": "local", + "example": "local", + "sensitive": false, + "category": "config" + }, + { + "name": "SECRETKEY_PATH", + "description": "Path to store secret keys locally", + "required": false, + "example": "/root/.flowise", + "sensitive": false, + "category": "config" + }, + { + "name": "FLOWISE_SECRETKEY_OVERWRITE", + "description": "Override secret key encryption key", + "required": false, + "example": "myencryptionkey", + "sensitive": true, + "category": "config" + }, + { + "name": "SECRETKEY_AWS_ACCESS_KEY", + "description": "AWS access key for secret key storage", + "required": false, + "example": "AKIA...", + "sensitive": true, + "category": "config" + }, + { + "name": "SECRETKEY_AWS_SECRET_KEY", + "description": "AWS secret key for secret key storage", + "required": false, + "example": "...", + "sensitive": true, + "category": "config" + }, + { + "name": "SECRETKEY_AWS_REGION", + "description": "AWS region for secret key storage", + "required": false, + "default": "us-west-2", + "example": "us-west-2", + "sensitive": false, + "category": "config" + }, + { + "name": "SECRETKEY_AWS_NAME", + "description": "AWS secret name for secret key storage", + "required": false, + "default": "FlowiseEncryptionKey", + "example": "FlowiseEncryptionKey", + "sensitive": false, + "category": "config" + }, + { + "name": "LOG_PATH", + "description": "Path to store application logs", + "required": false, + "example": "/root/.flowise/logs", + "sensitive": false, + "category": "config" + }, + { + "name": "LOG_SANITIZE_BODY_FIELDS", + "description": "Comma-separated field names to sanitize in logs", + "required": false, + "example": "password,secret,token,apikey", + "sensitive": false, + "category": "config" + }, + { + "name": "LOG_SANITIZE_HEADER_FIELDS", + "description": "Comma-separated header names to sanitize in logs", + "required": false, + "example": "authorization,x-api-key", + "sensitive": false, + "category": "config" + }, + { + "name": "TOOL_FUNCTION_BUILTIN_DEP", + "description": "Comma-separated built-in Node.js modules to allow in tool functions", + "required": false, + "default": "crypto,fs", + "example": "crypto,fs", + "sensitive": false, + "category": "config" + }, + { + "name": "TOOL_FUNCTION_EXTERNAL_DEP", + "description": "Comma-separated npm packages to allow in tool functions", + "required": false, + "default": "moment,lodash", + "example": "moment,lodash", + "sensitive": false, + "category": "config" + }, + { + "name": "ALLOW_BUILTIN_DEP", + "description": "Allow all Node.js built-in modules in tool functions", + "required": false, + "default": "false", + "example": "false", + "sensitive": false, + "category": "config" + }, + { + "name": "APP_URL", + "description": "Application URL for email links", + "required": false, + "example": "http://localhost:3000", + "sensitive": false, + "category": "config" + }, + { + "name": "SMTP_HOST", + "description": "SMTP server hostname", + "required": false, + "example": "smtp.host.com", + "sensitive": false, + "category": "config" + }, + { + "name": "SMTP_PORT", + "description": "SMTP server port", + "required": false, + "default": "465", + "example": "465", + "sensitive": false, + "category": "config" + }, + { + "name": "SMTP_USER", + "description": "SMTP username", + "required": false, + "example": "smtp_user", + "sensitive": true, + "category": "config" + }, + { + "name": "SMTP_PASSWORD", + "description": "SMTP password", + "required": false, + "example": "smtp_password", + "sensitive": true, + "category": "config" + }, + { + "name": "SMTP_SECURE", + "description": "Use TLS for SMTP connection", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "config" + }, + { + "name": "SENDER_EMAIL", + "description": "Sender email address", + "required": false, + "example": "team@example.com", + "sensitive": false, + "category": "config" + }, + { + "name": "ALLOW_UNAUTHORIZED_CERTS", + "description": "Allow connections to servers with invalid SSL certificates", + "required": false, + "default": "false", + "example": "false", + "sensitive": false, + "category": "config" + }, + { + "name": "EXPRESS_SESSION_SECRET", + "description": "Express session encryption secret", + "required": false, + "example": "flowise", + "sensitive": true, + "category": "auth" + }, + { + "name": "SECURE_COOKIES", + "description": "Enable secure cookie flag", + "required": false, + "example": "true", + "sensitive": false, + "category": "auth" + }, + { + "name": "EXPIRE_AUTH_TOKENS_ON_RESTART", + "description": "Expire all tokens on application restart", + "required": false, + "example": "true", + "sensitive": false, + "category": "auth" + }, + { + "name": "INVITE_TOKEN_EXPIRY_IN_HOURS", + "description": "Workspace invite token expiry in hours", + "required": false, + "default": "24", + "example": "24", + "sensitive": false, + "category": "auth" + }, + { + "name": "PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS", + "description": "Password reset token expiry in minutes", + "required": false, + "default": "15", + "example": "15", + "sensitive": false, + "category": "auth" + }, + { + "name": "PASSWORD_SALT_HASH_ROUNDS", + "description": "bcrypt rounds for password hashing", + "required": false, + "default": "10", + "example": "10", + "sensitive": false, + "category": "auth" + }, + { + "name": "TOKEN_HASH_SECRET", + "description": "Secret for hashing invitation/reset tokens", + "required": false, + "example": "popcorn", + "sensitive": true, + "category": "auth" + }, + { + "name": "WORKSPACE_INVITE_TEMPLATE_PATH", + "description": "Path to custom workspace invite email template (Handlebars)", + "required": false, + "example": "/path/to/workspace_invite.hbs", + "sensitive": false, + "category": "config" + }, + { + "name": "LICENSE_URL", + "description": "Enterprise license validation URL", + "required": false, + "example": "https://license.example.com", + "sensitive": false, + "category": "enterprise" + }, + { + "name": "FLOWISE_EE_LICENSE_KEY", + "description": "Flowise Enterprise Edition license key", + "required": false, + "example": "...", + "sensitive": true, + "category": "enterprise" + }, + { + "name": "OFFLINE", + "description": "Run in offline mode (no external calls)", + "required": false, + "example": "false", + "sensitive": false, + "category": "enterprise" + }, + { + "name": "PLAYWRIGHT_EXECUTABLE_FILE_PATH", + "description": "Path to Playwright browser executable", + "required": false, + "example": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + "sensitive": false, + "category": "config" + }, + { + "name": "PUPPETEER_EXECUTABLE_FILE_PATH", + "description": "Path to Puppeteer browser executable", + "required": false, + "example": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", + "sensitive": false, + "category": "config" + }, + { + "name": "NUMBER_OF_PROXIES", + "description": "Number of proxies behind the server", + "required": false, + "default": "1", + "example": "1", + "sensitive": false, + "category": "config" + }, + { + "name": "S3_FORCE_PATH_STYLE", + "description": "Use path-style URLs for S3 (vs virtual-hosted-style)", + "required": false, + "default": "false", + "example": "false", + "sensitive": false, + "category": "storage" + }, + { + "name": "GOOGLE_CLOUD_STORAGE_UNIFORM_BUCKET_ACCESS", + "description": "Enable uniform bucket-level access in GCS", + "required": false, + "default": "true", + "example": "true", + "sensitive": false, + "category": "storage" + } + ] +} diff --git a/.alphaAgent/spec/features.json b/.alphaAgent/spec/features.json new file mode 100644 index 00000000000..23499061f04 --- /dev/null +++ b/.alphaAgent/spec/features.json @@ -0,0 +1,946 @@ +{ + "version": "1.0", + "features": [ + { + "id": "user-authentication", + "category": "auth", + "description": "Users can authenticate via Auth0 JWT tokens or API keys and maintain secure sessions", + "steps": [ + "Navigate to login page", + "Authenticate via Auth0 or use API key", + "Access authenticated routes with token/key" + ], + "status": "completed", + "depends_on": [], + "blocks": [ + "chatflow-management", + "user-organization-management", + "api-key-management" + ], + "priority": 1, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can authenticate via Auth0", + "Users can use API keys for programmatic access", + "Sessions are maintained securely", + "Unauthorized requests are rejected" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatflow-management", + "category": "business-logic", + "description": "Users can create, edit, deploy, and manage AI chatflows (conversation flows) and agent flows visually", + "steps": [ + "Navigate to chatflows page", + "Click 'Create New Chatflow'", + "Design flow by adding nodes and connections", + "Configure chatflow settings (name, description, visibility)", + "Save or deploy chatflow" + ], + "status": "completed", + "depends_on": [ + "user-authentication", + "credentials-management" + ], + "blocks": [ + "chatflow-execution", + "chatflow-versioning", + "chatflow-deployment" + ], + "priority": 1, + "estimated_sessions": 5, + "acceptance_criteria": [ + "Users can create new chatflows", + "Users can edit existing chatflows", + "Users can view chatflow history", + "Chatflows can be deployed to production", + "Chatflows support both simple flows and agent flows", + "Chatflow visibility can be set (Private/Public/Organization/Marketplace)" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "agent-flow-builder", + "category": "business-logic", + "description": "Users can build advanced AI agent flows with multi-agent orchestration and tool integration", + "steps": [ + "Navigate to agentflows page", + "Create new agentflow", + "Add agents and configure their tools", + "Set up agent orchestration and communication", + "Deploy and test agent system" + ], + "status": "completed", + "depends_on": [ + "chatflow-management", + "tools-management" + ], + "blocks": [], + "priority": 1, + "estimated_sessions": 6, + "acceptance_criteria": [ + "Users can create agent flows", + "Multiple agents can be configured in one flow", + "Agents can use external tools", + "Agent orchestration logic can be customized", + "Multi-agent flows can be executed and monitored" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "credentials-management", + "category": "data", + "description": "Users can securely store and manage API credentials for integrations with LLMs, services, and tools", + "steps": [ + "Navigate to credentials page", + "Click 'Add Credential'", + "Select credential type", + "Enter API key/token", + "Save credential securely" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [ + "chatflow-management", + "assistant-management", + "tools-management" + ], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can add new credentials", + "Credentials are encrypted at rest", + "Users can update credentials", + "Users can delete credentials", + "Credentials are scoped to organization" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "assistant-management", + "category": "business-logic", + "description": "Users can create and manage AI assistants with custom models, document stores, and tools", + "steps": [ + "Navigate to assistants page", + "Create new assistant", + "Configure model, system prompt, and tools", + "Optionally connect knowledge base (document store)", + "Deploy assistant for use" + ], + "status": "completed", + "depends_on": [ + "credentials-management", + "document-store-management" + ], + "blocks": [ + "chatbot-deployment", + "chat-interface" + ], + "priority": 2, + "estimated_sessions": 4, + "acceptance_criteria": [ + "Users can create custom assistants", + "Assistants support multiple LLM models", + "Assistants can access document stores", + "Assistants can use tools", + "Assistant instructions can be auto-generated" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "document-store-management", + "category": "data", + "description": "Users can create and manage document stores to upload files for RAG (Retrieval-Augmented Generation) and chatflow use", + "steps": [ + "Navigate to document stores page", + "Create new document store", + "Upload files (PDF, DOCX, TXT, etc.)", + "Configure chunking and vector store settings", + "Query documents or connect to chatflow" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [ + "assistant-management", + "chatflow-management" + ], + "priority": 2, + "estimated_sessions": 4, + "acceptance_criteria": [ + "Users can create document stores", + "Users can upload multiple file types", + "Files are chunked and vectorized", + "Document stores can be queried", + "Chunking configuration is customizable", + "Refresh/update of documents supported" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chat-interface", + "category": "ui", + "description": "Users can interact with deployed chatflows and assistants through a web-based chat interface", + "steps": [ + "Navigate to chat page", + "Select a chatflow or assistant", + "Send message", + "Receive and view response", + "Continue conversation" + ], + "status": "completed", + "depends_on": [ + "chatflow-management", + "assistant-management" + ], + "blocks": [ + "chat-history-management" + ], + "priority": 1, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can select a chatflow to interact with", + "Messages are sent and responses displayed", + "Chat supports streaming responses", + "Chat history is maintained", + "Chat supports file uploads and attachments" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chat-history-management", + "category": "data", + "description": "Users can view, search, and manage their chat history and conversation records", + "steps": [ + "Navigate to chats page", + "View list of past conversations", + "Select a chat to view details", + "Search or filter chats", + "Delete specific chats" + ], + "status": "completed", + "depends_on": [ + "chat-interface" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can view all their chats", + "Chats can be searched and filtered", + "Chat messages can be viewed", + "Chats can be deleted", + "Chat metadata (title, date) is displayed" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "tools-management", + "category": "integration", + "description": "Users can create and manage tools that agents and chatflows can use to interact with external systems", + "steps": [ + "Navigate to tools page", + "Create new tool or use existing", + "Configure tool endpoint and parameters", + "Test tool functionality", + "Use tool in chatflows/agents" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [ + "agent-flow-builder" + ], + "priority": 2, + "estimated_sessions": 3, + "acceptance_criteria": [ + "Users can create custom tools", + "Tools can call external APIs", + "Tool parameters are configurable", + "Tools can be used in chatflows and agents", + "Tool results are displayed in chat" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "api-key-management", + "category": "auth", + "description": "Users can generate and manage API keys for programmatic access to chatflows and agents", + "steps": [ + "Navigate to API Keys page", + "Click 'Generate New API Key'", + "Name the API key", + "Configure scope and permissions", + "Copy and store key securely" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Users can create API keys", + "API keys can be scoped to specific resources", + "API keys have configurable permissions", + "API keys can be revoked", + "API key usage is tracked" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "user-organization-management", + "category": "auth", + "description": "Admins can manage organizations, workspaces, users, and roles within the system", + "steps": [ + "Navigate to admin panel", + "Manage organizations/workspaces", + "Add or remove users", + "Configure roles and permissions", + "Set organization settings" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 4, + "acceptance_criteria": [ + "Admins can create organizations", + "Admins can manage users in organization", + "Admins can assign roles", + "Admins can configure organization settings", + "Multi-tenancy is enforced" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatbot-deployment", + "category": "business-logic", + "description": "Users can deploy chatflows and assistants as standalone chatbots with custom branding and configuration", + "steps": [ + "Select a chatflow or assistant", + "Click 'Deploy as Chatbot'", + "Configure chatbot settings", + "Get embed code or share link", + "Monitor chatbot usage and analytics" + ], + "status": "completed", + "depends_on": [ + "chatflow-management", + "assistant-management" + ], + "blocks": [ + "chatbot-analytics" + ], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Chatflows can be deployed as chatbots", + "Chatbots can be embedded in websites", + "Chatbots can be shared via public links", + "Chatbot branding is customizable", + "Public chatbots have analytics tracking" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatbot-analytics", + "category": "ui", + "description": "Users can view analytics and metrics for deployed chatbots including usage, engagement, and performance", + "steps": [ + "Navigate to chatbot analytics page", + "Select a deployed chatbot", + "View usage metrics and trends", + "View engagement statistics", + "Export analytics reports" + ], + "status": "completed", + "depends_on": [ + "chatbot-deployment" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can view chatbot usage metrics", + "Conversation analytics are displayed", + "User engagement metrics are tracked", + "Performance metrics are available", + "Analytics can be filtered by date range" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatflow-versioning", + "category": "data", + "description": "Users can version chatflows and rollback to previous versions", + "steps": [ + "Open a chatflow", + "View version history", + "Select a previous version", + "Rollback to previous version", + "Compare versions" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Chatflow versions are automatically saved", + "Users can view version history", + "Users can rollback to previous versions", + "Versions can be compared", + "Version metadata is displayed" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatflow-deployment", + "category": "business-logic", + "description": "Users can deploy chatflows to production and manage deployment settings", + "steps": [ + "Open chatflow", + "Review configuration", + "Click 'Deploy'", + "Configure deployment settings", + "Monitor deployment status" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 1, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Chatflows can be deployed", + "Deployment status is visible", + "Deployed chatflows are publicly accessible", + "Deployment can be disabled/enabled" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "chatflow-execution", + "category": "business-logic", + "description": "System can execute chatflows with node processing, tool calling, and streaming responses", + "steps": [ + "Chatflow is triggered via API or UI", + "Each node in flow is executed", + "Tools are called as needed", + "Results are streamed or returned", + "Execution completes with final response" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 1, + "estimated_sessions": 3, + "acceptance_criteria": [ + "Chatflows execute without errors", + "Nodes process data correctly", + "Tools are called and results used", + "Responses are streamed in real-time", + "Errors are handled gracefully" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "evaluations-system", + "category": "business-logic", + "description": "Users can create and run evaluations on chatflows and assistants to measure performance and quality", + "steps": [ + "Navigate to evaluations page", + "Create new evaluation", + "Select chatflow/assistant to evaluate", + "Configure evaluation metrics", + "Run evaluation and view results" + ], + "status": "completed", + "depends_on": [ + "chatflow-management", + "assistant-management" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 3, + "acceptance_criteria": [ + "Users can create evaluations", + "Evaluations can run on chatflows/assistants", + "Multiple evaluation metrics are supported", + "Results are displayed with visualizations", + "Evaluations can be re-run", + "Evaluation history is maintained" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "dataset-management", + "category": "data", + "description": "Users can create and manage datasets with rows of data for testing and evaluation", + "steps": [ + "Navigate to datasets page", + "Create new dataset", + "Add rows of data", + "Configure dataset schema", + "Use dataset in evaluations" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [ + "evaluations-system" + ], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can create datasets", + "Datasets can have custom columns", + "Data rows can be added/edited/deleted", + "Datasets can be exported", + "Datasets can be used in evaluations" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "variables-management", + "category": "data", + "description": "Users can create and manage variables to use in chatflows for dynamic configuration", + "steps": [ + "Navigate to variables page", + "Create new variable", + "Set variable name and value", + "Use variable in chatflow", + "Update variable value" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Users can create variables", + "Variables can be used in chatflows", + "Variables can be updated dynamically", + "Variable types are enforced", + "Variables are scoped to organization" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "export-import-flows", + "category": "data", + "description": "Users can export chatflows/agents as JSON and import them from other sources", + "steps": [ + "Open chatflow", + "Click 'Export'", + "Save JSON file", + "Navigate to import", + "Select JSON file to import", + "Chatflow is created from JSON" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Chatflows can be exported as JSON", + "JSON can be imported to create new flows", + "Export format is standardized", + "Large flows can be exported/imported", + "Credentials are handled securely in export" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "marketplace-feature", + "category": "integration", + "description": "Users can browse, download, and share chatflows from the marketplace", + "steps": [ + "Navigate to marketplace", + "Search for flows", + "View flow details", + "Download/import flow", + "Publish own flows to marketplace" + ], + "status": "completed", + "depends_on": [ + "chatflow-management", + "export-import-flows" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can browse marketplace flows", + "Flows can be filtered and searched", + "Flows can be imported from marketplace", + "Users can publish flows to marketplace", + "Marketplace metadata is displayed" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "csv-data-transformer", + "category": "data", + "description": "Users can transform and process CSV data through AI-powered pipeline", + "steps": [ + "Navigate to CSV Transformer", + "Upload CSV file", + "Configure transformation rules", + "Preview transformed data", + "Export or save results" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can upload CSV files", + "Transformations can be configured", + "Preview shows transformation results", + "Transformed data can be exported", + "Batch processing is supported" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "media-creation", + "category": "integration", + "description": "Users can generate images using DALL-E and create media content through AI", + "steps": [ + "Navigate to media creator", + "Enter image description", + "Select DALL-E model options", + "Generate image", + "Download or use image in flows" + ], + "status": "completed", + "depends_on": [ + "credentials-management" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Users can generate images via DALL-E", + "Multiple image variants can be generated", + "Images can be downloaded", + "Images can be used in chatflows", + "Image generation is tracked in usage" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "settings-management", + "category": "ui", + "description": "Users can manage their account, organization, and system settings", + "steps": [ + "Navigate to settings", + "Configure user profile", + "Configure organization settings", + "Manage integrations", + "Update system preferences" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Users can update profile", + "Organization settings are configurable", + "Integrations can be configured", + "User preferences are saved", + "SSO configuration is available for admins" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "billing-usage-tracking", + "category": "data", + "description": "System tracks usage metrics and displays billing information for users", + "steps": [ + "Navigate to billing page", + "View current plan", + "Check usage statistics", + "View billing history", + "Upgrade or change plan" + ], + "status": "completed", + "depends_on": [ + "user-authentication" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Users can view current plan", + "Usage metrics are displayed", + "Billing history is available", + "Users can upgrade plans", + "Usage limits are enforced" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "message-feedback-system", + "category": "data", + "description": "Users can provide feedback on chat messages for improvement and quality tracking", + "steps": [ + "In chat, select a message", + "Provide feedback (thumbs up/down)", + "Add comments if needed", + "Submit feedback" + ], + "status": "completed", + "depends_on": [ + "chat-interface" + ], + "blocks": [], + "priority": 3, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Users can rate messages", + "Feedback can include comments", + "Feedback is stored and analyzed", + "Feedback is visible to admins" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "sso-saml-integration", + "category": "integration", + "description": "Organizations can configure SSO and SAML authentication for enterprise access", + "steps": [ + "Navigate to SSO settings", + "Configure SAML provider", + "Add authentication details", + "Test SSO login", + "Enable for organization" + ], + "status": "completed", + "depends_on": [ + "user-organization-management" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "SAML SSO can be configured", + "Users can login via SSO", + "SSO settings are secure", + "Multiple SAML providers can be configured" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "oauth-integrations", + "category": "integration", + "description": "System supports OAuth2 integrations with external services like Google, Atlassian, Salesforce", + "steps": [ + "Navigate to integrations", + "Select OAuth provider", + "Authorize application", + "Grant necessary permissions", + "Integration is connected" + ], + "status": "completed", + "depends_on": [ + "credentials-management" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "OAuth integrations are available", + "Users can authorize services", + "Token refresh is automatic", + "Multiple integrations can be connected" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "node-component-system", + "category": "business-logic", + "description": "System provides extensible node/component system for building chatflows with 29+ node categories", + "steps": [ + "Open chatflow editor", + "Browse available node categories", + "Drag node to canvas", + "Configure node parameters", + "Connect nodes together" + ], + "status": "completed", + "depends_on": [], + "blocks": [ + "chatflow-management" + ], + "priority": 1, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Multiple node types are available", + "Nodes can be configured with parameters", + "Nodes can be connected in valid ways", + "Custom nodes can be created", + "Node validation is performed" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "llm-model-integration", + "category": "integration", + "description": "System integrates with multiple LLM providers (OpenAI, Anthropic, Gemini, etc.)", + "steps": [ + "Configure LLM credentials", + "Select model in chatflow/assistant", + "Configure model parameters", + "Use model in conversation" + ], + "status": "completed", + "depends_on": [ + "credentials-management" + ], + "blocks": [ + "assistant-management", + "chatflow-management" + ], + "priority": 1, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Multiple LLM providers are supported", + "Model parameters are configurable", + "Model switching is seamless", + "Token counting is accurate" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "vector-store-integration", + "category": "integration", + "description": "System supports multiple vector stores (Qdrant, Pinecone, Weaviate, etc.) for embeddings", + "steps": [ + "Configure vector store credentials", + "Create document store with vector store", + "Upload and chunk documents", + "Query vectors in chatflow", + "Use results in agent/chatbot" + ], + "status": "completed", + "depends_on": [ + "document-store-management", + "credentials-management" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 2, + "acceptance_criteria": [ + "Multiple vector stores are supported", + "Embeddings are generated and stored", + "Semantic search works correctly", + "Vector store can be queried" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "public-shared-flows", + "category": "data", + "description": "Users can share chatflows publicly via shareable links with different sharing options", + "steps": [ + "Open chatflow", + "Click 'Share'", + "Generate shareable link", + "Configure share settings", + "Share link with others" + ], + "status": "completed", + "depends_on": [ + "chatflow-management" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Public share links can be generated", + "Share settings are configurable", + "Public flows are accessible without auth", + "Share links can be revoked" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "browser-extension", + "category": "integration", + "description": "Users can install browser extension to use chatflows and assistants from any website", + "steps": [ + "Install browser extension", + "Configure extension settings", + "Click extension icon", + "Interact with chatbot", + "Get responses on current page" + ], + "status": "completed", + "depends_on": [], + "blocks": [], + "priority": 3, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Extension can be installed", + "Extension authenticates with account", + "Chatbots are accessible from extension", + "Extension works on multiple websites" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "tracing-monitoring", + "category": "data", + "description": "Users can trace and monitor chatflow execution with detailed step-by-step logs", + "steps": [ + "Navigate to tracing/monitoring", + "View execution traces", + "See detailed step logs", + "Monitor token usage", + "Debug issues in flow" + ], + "status": "completed", + "depends_on": [ + "chatflow-execution" + ], + "blocks": [], + "priority": 2, + "estimated_sessions": 1, + "acceptance_criteria": [ + "Execution traces are recorded", + "Detailed logs are available", + "Token usage is tracked", + "Performance metrics are shown" + ], + "implemented_at": "2026-01-01T00:00:00Z" + } + ] +} diff --git a/.alphaAgent/spec/schema.json b/.alphaAgent/spec/schema.json new file mode 100644 index 00000000000..fabcd598e67 --- /dev/null +++ b/.alphaAgent/spec/schema.json @@ -0,0 +1,1810 @@ +{ + "version": "1.0", + "databaseType": "PostgreSQL", + "description": "Combined database schema from TypeORM (Flowise core) and Prisma (TheAnswer extensions)", + "tables": [ + { + "name": "user", + "source": "TypeORM (enterprise)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR(100)", + "nullable": false + }, + { + "name": "email", + "type": "VARCHAR(255)", + "nullable": false, + "unique": true + }, + { + "name": "credential", + "type": "TEXT", + "nullable": true + }, + { + "name": "tempToken", + "type": "TEXT", + "nullable": true, + "unique": true + }, + { + "name": "tokenExpiry", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "status", + "type": "VARCHAR(20)", + "nullable": false, + "default": "unverified", + "enum": ["active", "invited", "unverified", "deleted"] + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "createdBy", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "updatedBy", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "auth0Id", + "type": "VARCHAR", + "nullable": true, + "unique": true + }, + { + "name": "stripeCustomerId", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "trialPlanId", + "type": "UUID", + "nullable": true + }, + { + "name": "defaultChatflowId", + "type": "UUID", + "nullable": true + } + ], + "indexes": ["idx_user_email", "idx_user_organizationId", "idx_user_auth0Id"] + }, + { + "name": "organization", + "source": "TypeORM (enterprise)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR(100)", + "nullable": false, + "default": "Default Organization" + }, + { + "name": "customerId", + "type": "VARCHAR(100)", + "nullable": true + }, + { + "name": "subscriptionId", + "type": "VARCHAR(100)", + "nullable": true + }, + { + "name": "auth0Id", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "organizationConfig", + "type": "JSONB", + "nullable": true + }, + { + "name": "currentPaidPlanId", + "type": "UUID", + "nullable": true + }, + { + "name": "billingPoolEnabled", + "type": "BOOLEAN", + "nullable": false, + "default": false + }, + { + "name": "stripeCustomerId", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "enabledIntegrations", + "type": "JSONB", + "nullable": true + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "createdBy", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "updatedBy", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + } + ], + "indexes": ["idx_organization_auth0Id"] + }, + { + "name": "chatflow", + "source": "TypeORM (Flowise core)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "description", + "type": "TEXT", + "nullable": true + }, + { + "name": "flowData", + "type": "TEXT", + "nullable": false + }, + { + "name": "deployed", + "type": "BOOLEAN", + "nullable": true + }, + { + "name": "isPublic", + "type": "BOOLEAN", + "nullable": true + }, + { + "name": "apikeyid", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "chatbotConfig", + "type": "TEXT", + "nullable": true + }, + { + "name": "visibility", + "type": "SIMPLE_ARRAY", + "nullable": true, + "enum": ["Private", "Public", "Organization", "AnswerAI", "Marketplace"] + }, + { + "name": "answersConfig", + "type": "TEXT", + "nullable": true + }, + { + "name": "apiConfig", + "type": "TEXT", + "nullable": true + }, + { + "name": "analytic", + "type": "TEXT", + "nullable": true + }, + { + "name": "speechToText", + "type": "TEXT", + "nullable": true + }, + { + "name": "textToSpeech", + "type": "TEXT", + "nullable": true + }, + { + "name": "followUpPrompts", + "type": "TEXT", + "nullable": true + }, + { + "name": "category", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "type", + "type": "VARCHAR(20)", + "nullable": false, + "default": "CHATFLOW", + "enum": ["CHATFLOW", "AGENTFLOW", "MULTIAGENT", "ASSISTANT"] + }, + { + "name": "browserExtConfig", + "type": "JSONB", + "nullable": true + }, + { + "name": "parentChatflowId", + "type": "TEXT", + "nullable": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "deletedDate", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "templateId", + "type": "UUID", + "nullable": true + }, + { + "name": "currentVersion", + "type": "INTEGER", + "nullable": true, + "default": 1 + }, + { + "name": "s3Location", + "type": "TEXT", + "nullable": true + }, + { + "name": "workspaceId", + "type": "TEXT", + "nullable": false + } + ], + "indexes": ["idx_chatflow_userId", "idx_chatflow_organizationId", "idx_chatflow_parentChatflowId", "idx_chatflow_templateId"] + }, + { + "name": "chat_message", + "source": "TypeORM (Flowise core)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "role", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "chatflowid", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "chatflow", + "column": "id" + } + }, + { + "name": "executionId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "execution", + "column": "id" + } + }, + { + "name": "content", + "type": "TEXT", + "nullable": false + }, + { + "name": "sourceDocuments", + "type": "TEXT", + "nullable": true + }, + { + "name": "usedTools", + "type": "TEXT", + "nullable": true + }, + { + "name": "fileAnnotations", + "type": "TEXT", + "nullable": true + }, + { + "name": "agentReasoning", + "type": "TEXT", + "nullable": true + }, + { + "name": "fileUploads", + "type": "TEXT", + "nullable": true + }, + { + "name": "artifacts", + "type": "TEXT", + "nullable": true + }, + { + "name": "action", + "type": "TEXT", + "nullable": true + }, + { + "name": "chatType", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "chatId", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "memoryType", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "sessionId", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "leadEmail", + "type": "TEXT", + "nullable": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "deletedDate", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "followUpPrompts", + "type": "TEXT", + "nullable": true + }, + { + "name": "guardrails_metadata", + "type": "TEXT", + "nullable": true + }, + { + "name": "tracking_metadata", + "type": "TEXT", + "nullable": true + } + ], + "indexes": ["idx_chat_message_chatflowid", "idx_chat_message_userId", "idx_chat_message_organizationId"] + }, + { + "name": "credential", + "source": "TypeORM (Flowise core)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "credentialName", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "encryptedData", + "type": "TEXT", + "nullable": false + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "visibility", + "type": "SIMPLE_ARRAY", + "nullable": true, + "enum": ["Private", "Organization", "Platform"] + }, + { + "name": "workspaceId", + "type": "TEXT", + "nullable": false + } + ], + "indexes": ["idx_credential_userId", "idx_credential_organizationId"] + }, + { + "name": "tool", + "source": "TypeORM (Flowise core)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "description", + "type": "TEXT", + "nullable": false + }, + { + "name": "color", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "iconSrc", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "schema", + "type": "TEXT", + "nullable": true + }, + { + "name": "func", + "type": "TEXT", + "nullable": true + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "visibility", + "type": "SIMPLE_ARRAY", + "nullable": true, + "enum": ["Private", "Organization"] + }, + { + "name": "workspaceId", + "type": "TEXT", + "nullable": false + } + ], + "indexes": ["idx_tool_userId", "idx_tool_organizationId"] + }, + { + "name": "execution", + "source": "TypeORM (Flowise core)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "executionData", + "type": "TEXT", + "nullable": false + }, + { + "name": "state", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "agentflowId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "chatflow", + "column": "id" + } + }, + { + "name": "sessionId", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "action", + "type": "TEXT", + "nullable": true + }, + { + "name": "isPublic", + "type": "BOOLEAN", + "nullable": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "createdDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "stoppedDate", + "type": "TIMESTAMP", + "nullable": false + }, + { + "name": "workspaceId", + "type": "TEXT", + "nullable": false + } + ], + "indexes": ["idx_execution_agentflowId", "idx_execution_sessionId", "idx_execution_userId", "idx_execution_organizationId"] + }, + { + "name": "chat", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "title", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "promptId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "prompt", + "column": "id" + } + }, + { + "name": "journeyId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "journey", + "column": "id" + } + }, + { + "name": "ownerId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "chatflowChatId", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "filters", + "type": "JSONB", + "nullable": false + }, + { + "name": "deleted", + "type": "BOOLEAN", + "nullable": false, + "default": false + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_chat_promptId", "idx_chat_journeyId", "idx_chat_ownerId", "idx_chat_organizationId"] + }, + { + "name": "message", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "role", + "type": "VARCHAR", + "nullable": false, + "default": "assistant" + }, + { + "name": "content", + "type": "TEXT", + "nullable": false + }, + { + "name": "contextSourceFilesUsed", + "type": "TEXT[]", + "nullable": false, + "default": "ARRAY[]::TEXT[]" + }, + { + "name": "context", + "type": "TEXT", + "nullable": false, + "default": "" + }, + { + "name": "sidekickJson", + "type": "JSONB", + "nullable": false, + "default": "{}" + }, + { + "name": "promptId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "prompt", + "column": "id" + } + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "chatId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "chat", + "column": "id" + } + }, + { + "name": "likes", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "dislikes", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "deleted", + "type": "BOOLEAN", + "nullable": false, + "default": false + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "aiRequestId", + "type": "UUID", + "nullable": true, + "unique": true, + "foreignKey": { + "table": "ai_request", + "column": "id" + } + } + ], + "indexes": ["idx_message_promptId", "idx_message_userId", "idx_message_chatId"] + }, + { + "name": "prompt", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "title", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "description", + "type": "TEXT", + "nullable": true + }, + { + "name": "content", + "type": "TEXT", + "nullable": false, + "unique": true + }, + { + "name": "usages", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "likes", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "dislikes", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "deleted", + "type": "BOOLEAN", + "nullable": false, + "default": false + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "tags", + "type": "TEXT[]", + "nullable": false, + "default": "ARRAY[]::TEXT[]" + } + ], + "indexes": ["idx_prompt_content"] + }, + { + "name": "journey", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "title", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "goal", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "completedAt", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "filters", + "type": "JSONB", + "nullable": false + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "deleted", + "type": "BOOLEAN", + "nullable": false, + "default": false + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_journey_organizationId"] + }, + { + "name": "document", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "source", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "title", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "domain", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "url", + "type": "VARCHAR", + "nullable": false, + "unique": true + }, + { + "name": "content", + "type": "TEXT", + "nullable": false, + "default": "" + }, + { + "name": "metadata", + "type": "JSONB", + "nullable": false, + "default": "{}" + }, + { + "name": "status", + "type": "VARCHAR", + "nullable": false, + "default": "pending" + }, + { + "name": "lastSyncedAt", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_document_url", "idx_document_source"] + }, + { + "name": "document_permission", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "documentId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "document", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_document_permission_documentId", "idx_document_permission_organizationId"] + }, + { + "name": "sidekick", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "isGlobal", + "type": "BOOLEAN", + "nullable": true, + "default": false + }, + { + "name": "isSystem", + "type": "BOOLEAN", + "nullable": true, + "default": false + }, + { + "name": "isSharedWithOrg", + "type": "BOOLEAN", + "nullable": true, + "default": false + }, + { + "name": "isFavoriteByDefault", + "type": "BOOLEAN", + "nullable": true, + "default": false + }, + { + "name": "chatflow", + "type": "JSONB", + "nullable": true + }, + { + "name": "chatflowApiKey", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "chatflowDomain", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "label", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "tags", + "type": "TEXT[]", + "nullable": false, + "default": "ARRAY[]::TEXT[]" + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "temperature", + "type": "FLOAT", + "nullable": false, + "default": 1 + }, + { + "name": "frequency", + "type": "FLOAT", + "nullable": false, + "default": 0 + }, + { + "name": "presence", + "type": "FLOAT", + "nullable": false, + "default": 0 + }, + { + "name": "maxCompletionTokens", + "type": "INTEGER", + "nullable": false, + "default": 500 + }, + { + "name": "aiModel", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "systemPromptTemplate", + "type": "TEXT", + "nullable": true + }, + { + "name": "userPromptTemplate", + "type": "TEXT", + "nullable": true + }, + { + "name": "contextStringRender", + "type": "TEXT", + "nullable": true + }, + { + "name": "placeholder", + "type": "VARCHAR", + "nullable": true + } + ], + "indexes": ["idx_sidekick_organizationId", "idx_sidekick_userId"] + }, + { + "name": "api_key", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "organizationId", + "type": "UUID", + "nullable": true, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "type", + "type": "VARCHAR", + "nullable": false, + "default": "USER", + "enum": ["USER", "ORGANIZATION"] + }, + { + "name": "key", + "type": "VARCHAR", + "nullable": false, + "unique": true + } + ], + "indexes": ["idx_api_key_userId", "idx_api_key_organizationId"] + }, + { + "name": "ai_request", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "type", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "method", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "model", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "tokensUsed", + "type": "INTEGER", + "nullable": false + }, + { + "name": "tokensUsedUser", + "type": "INTEGER", + "nullable": false + }, + { + "name": "costUsdTotal", + "type": "DECIMAL", + "nullable": false + }, + { + "name": "costUsdTotalUser", + "type": "DECIMAL", + "nullable": false + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "request", + "type": "JSONB", + "nullable": true + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_ai_request_userId"] + }, + { + "name": "message_feedback", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "rating", + "type": "VARCHAR", + "nullable": false, + "default": "thumbsUp", + "enum": ["thumbsUp", "thumbsDown"] + }, + { + "name": "content", + "type": "TEXT", + "nullable": false + }, + { + "name": "tags", + "type": "TEXT[]", + "nullable": false, + "default": "ARRAY[]::TEXT[]" + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "messageId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "message", + "column": "id" + } + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_message_feedback_userId", "idx_message_feedback_messageId"], + "uniqueConstraints": ["idx_message_feedback_userId_messageId"] + }, + { + "name": "plan", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "INTEGER", + "nullable": false, + "primaryKey": true + }, + { + "name": "name", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "description", + "type": "TEXT", + "nullable": false + }, + { + "name": "tokenLimit", + "type": "INTEGER", + "nullable": false + } + ], + "indexes": [] + }, + { + "name": "active_user_plan", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "unique": true, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "planId", + "type": "INTEGER", + "nullable": false, + "foreignKey": { + "table": "plan", + "column": "id" + } + }, + { + "name": "renewalDate", + "type": "TIMESTAMP", + "nullable": false + }, + { + "name": "tokensLeft", + "type": "INTEGER", + "nullable": false + }, + { + "name": "startDate", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "gpt3RequestCount", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "gpt4RequestCount", + "type": "INTEGER", + "nullable": false, + "default": 0 + }, + { + "name": "stripeSubscriptionId", + "type": "VARCHAR", + "nullable": true + }, + { + "name": "shouldRenew", + "type": "BOOLEAN", + "nullable": false, + "default": true + } + ], + "indexes": ["idx_active_user_plan_userId"] + }, + { + "name": "app_config", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "appId", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "appType", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "config", + "type": "JSONB", + "nullable": false + } + ], + "indexes": ["idx_app_config_userId"] + }, + { + "name": "app_csv_parse_runs", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "userId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "user", + "column": "id" + } + }, + { + "name": "orgId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "organization", + "column": "id" + } + }, + { + "name": "startedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "completedAt", + "type": "TIMESTAMP", + "nullable": true + }, + { + "name": "rowsRequested", + "type": "INTEGER", + "nullable": false + }, + { + "name": "rowsProcessed", + "type": "INTEGER", + "nullable": true + }, + { + "name": "name", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "configuration", + "type": "JSONB", + "nullable": false + }, + { + "name": "originalCsvUrl", + "type": "TEXT", + "nullable": false + }, + { + "name": "processedCsvUrl", + "type": "TEXT", + "nullable": true + }, + { + "name": "chatflowChatId", + "type": "VARCHAR", + "nullable": false + }, + { + "name": "includeOriginalColumns", + "type": "BOOLEAN", + "nullable": false, + "default": true + }, + { + "name": "status", + "type": "VARCHAR", + "nullable": false, + "default": "pending", + "enum": ["pending", "inProgress", "completeWithErrors", "complete", "generatingCsv", "ready"] + }, + { + "name": "errorMessages", + "type": "TEXT[]", + "nullable": false, + "default": "ARRAY[]::TEXT[]" + } + ], + "indexes": ["idx_app_csv_parse_runs_userId", "idx_app_csv_parse_runs_orgId"] + }, + { + "name": "app_csv_parse_rows", + "source": "Prisma (TheAnswer extensions)", + "columns": [ + { + "name": "id", + "type": "UUID", + "nullable": false, + "primaryKey": true + }, + { + "name": "csvParseRunId", + "type": "UUID", + "nullable": false, + "foreignKey": { + "table": "app_csv_parse_runs", + "column": "id" + } + }, + { + "name": "rowNumber", + "type": "INTEGER", + "nullable": false + }, + { + "name": "rowData", + "type": "JSONB", + "nullable": false + }, + { + "name": "generatedData", + "type": "JSONB", + "nullable": true + }, + { + "name": "status", + "type": "VARCHAR", + "nullable": false, + "default": "pending", + "enum": ["pending", "inProgress", "completeWithError", "complete"] + }, + { + "name": "errorMessage", + "type": "TEXT", + "nullable": true + }, + { + "name": "createdAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + }, + { + "name": "updatedAt", + "type": "TIMESTAMP", + "nullable": false, + "default": "now()" + } + ], + "indexes": ["idx_app_csv_parse_rows_csvParseRunId"] + } + ], + "migrations": [ + "TypeORM migrations in packages/server/src/migrations/", + "Prisma migrations in packages-answers/db/prisma/migrations/" + ], + "notes": { + "multi_tenancy": "All resources include userId and organizationId for multi-tenant isolation", + "soft_delete": "Some entities use DeleteDateColumn for soft deletes (chatflow, chat_message, execution, chat, journey, prompt, message)", + "timestamps": "All entities include createdDate/createdAt and updatedDate/updatedAt fields", + "two_databases": "Project uses TypeORM for Flowise core and Prisma for TheAnswer extensions" + } +} diff --git a/.alphaAgent/spec/schema.sql b/.alphaAgent/spec/schema.sql new file mode 100644 index 00000000000..0c8cabd583c --- /dev/null +++ b/.alphaAgent/spec/schema.sql @@ -0,0 +1,520 @@ +-- ============================================== +-- TheAnswer Database Schema (PostgreSQL) +-- Generated: 2025-01-22 +-- Source: TypeORM entities + Prisma schema +-- ============================================== + +-- ============================================ +-- ENTERPRISE ENTITIES (TypeORM) +-- ============================================ + +-- Table: user +-- Purpose: Core user entity with Auth0 integration +-- Multi-tenancy: Supports organization membership +CREATE TABLE "user" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) NOT NULL, + email VARCHAR(255) NOT NULL UNIQUE, + credential TEXT, + "tempToken" TEXT UNIQUE, + "tokenExpiry" TIMESTAMP, + status VARCHAR(20) NOT NULL DEFAULT 'unverified', + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdBy" UUID NOT NULL REFERENCES "user"(id), + "updatedBy" UUID NOT NULL REFERENCES "user"(id), + "auth0Id" VARCHAR UNIQUE, + "stripeCustomerId" VARCHAR, + "organizationId" UUID, + "trialPlanId" UUID, + "defaultChatflowId" UUID, + CONSTRAINT chk_user_status CHECK (status IN ('active', 'invited', 'unverified', 'deleted')) +); + +CREATE INDEX idx_user_email ON "user"(email); +CREATE INDEX idx_user_organizationId ON "user"("organizationId"); +CREATE INDEX idx_user_auth0Id ON "user"("auth0Id"); + +-- Table: organization +-- Purpose: Organization/workspace entity with billing integration +-- Multi-tenancy: Root of organization hierarchy +CREATE TABLE "organization" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) NOT NULL DEFAULT 'Default Organization', + "customerId" VARCHAR(100), + "subscriptionId" VARCHAR(100), + "auth0Id" VARCHAR, + "organizationConfig" JSONB, + "currentPaidPlanId" UUID, + "billingPoolEnabled" BOOLEAN NOT NULL DEFAULT FALSE, + "stripeCustomerId" VARCHAR, + "enabledIntegrations" JSONB, + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "createdBy" UUID NOT NULL REFERENCES "user"(id), + "updatedBy" UUID NOT NULL REFERENCES "user"(id) +); + +CREATE INDEX idx_organization_auth0Id ON "organization"("auth0Id"); + +-- ============================================ +-- FLOWISE CORE ENTITIES (TypeORM) +-- ============================================ + +-- Table: chatflow +-- Purpose: Chatflow/workflow definitions +-- Multi-tenancy: Filtered by organizationId and userId +CREATE TABLE "chatflow" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR NOT NULL, + description TEXT, + "flowData" TEXT NOT NULL, + deployed BOOLEAN, + "isPublic" BOOLEAN, + apikeyid VARCHAR, + "chatbotConfig" TEXT, + visibility TEXT[], -- ARRAY of 'Private', 'Public', 'Organization', 'AnswerAI', 'Marketplace' + "answersConfig" TEXT, + "apiConfig" TEXT, + analytic TEXT, + "speechToText" TEXT, + "textToSpeech" TEXT, + "followUpPrompts" TEXT, + category VARCHAR, + type VARCHAR(20) NOT NULL DEFAULT 'CHATFLOW', + "browserExtConfig" JSONB, + "parentChatflowId" TEXT, + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deletedDate" TIMESTAMP, + "templateId" UUID, + "currentVersion" INTEGER DEFAULT 1, + "s3Location" TEXT, + "workspaceId" TEXT NOT NULL, + CONSTRAINT chk_chatflow_type CHECK (type IN ('CHATFLOW', 'AGENTFLOW', 'MULTIAGENT', 'ASSISTANT')) +); + +CREATE INDEX idx_chatflow_userId ON "chatflow"("userId"); +CREATE INDEX idx_chatflow_organizationId ON "chatflow"("organizationId"); +CREATE INDEX idx_chatflow_parentChatflowId ON "chatflow"("parentChatflowId"); +CREATE INDEX idx_chatflow_templateId ON "chatflow"("templateId"); + +-- Table: chat_message +-- Purpose: Messages within chatflows +-- Multi-tenancy: Filtered by organizationId +CREATE TABLE "chat_message" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + role VARCHAR NOT NULL, + chatflowid UUID NOT NULL REFERENCES "chatflow"(id), + "executionId" UUID, + content TEXT NOT NULL, + "sourceDocuments" TEXT, + "usedTools" TEXT, + "fileAnnotations" TEXT, + "agentReasoning" TEXT, + "fileUploads" TEXT, + artifacts TEXT, + action TEXT, + "chatType" VARCHAR NOT NULL, + "chatId" VARCHAR NOT NULL, + "memoryType" VARCHAR, + "sessionId" VARCHAR, + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "leadEmail" TEXT, + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + "deletedDate" TIMESTAMP, + "followUpPrompts" TEXT, + "guardrails_metadata" TEXT, + "tracking_metadata" TEXT +); + +CREATE INDEX idx_chat_message_chatflowid ON "chat_message"(chatflowid); +CREATE INDEX idx_chat_message_userId ON "chat_message"("userId"); +CREATE INDEX idx_chat_message_organizationId ON "chat_message"("organizationId"); + +-- Table: credential +-- Purpose: API credentials for integrations +-- Security: Encrypted data storage +CREATE TABLE "credential" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR NOT NULL, + "credentialName" VARCHAR NOT NULL, + "encryptedData" TEXT NOT NULL, + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + visibility TEXT[], -- ARRAY of 'Private', 'Organization', 'Platform' + "workspaceId" TEXT NOT NULL +); + +CREATE INDEX idx_credential_userId ON "credential"("userId"); +CREATE INDEX idx_credential_organizationId ON "credential"("organizationId"); + +-- Table: tool +-- Purpose: Custom tools/integrations +-- Multi-tenancy: Private or Organization-scoped +CREATE TABLE "tool" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR NOT NULL, + description TEXT NOT NULL, + color VARCHAR NOT NULL, + "iconSrc" VARCHAR, + schema TEXT, + func TEXT, + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + visibility TEXT[], -- ARRAY of 'Private', 'Organization' + "workspaceId" TEXT NOT NULL +); + +CREATE INDEX idx_tool_userId ON "tool"("userId"); +CREATE INDEX idx_tool_organizationId ON "tool"("organizationId"); + +-- Table: execution +-- Purpose: Agent flow execution state and history +-- Multi-tenancy: Filtered by organizationId +CREATE TABLE "execution" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "executionData" TEXT NOT NULL, + state VARCHAR NOT NULL, + "agentflowId" UUID NOT NULL REFERENCES "chatflow"(id), + "sessionId" VARCHAR NOT NULL, + action TEXT, + "isPublic" BOOLEAN, + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + "createdDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "stoppedDate" TIMESTAMP NOT NULL, + "workspaceId" TEXT NOT NULL +); + +CREATE INDEX idx_execution_agentflowId ON "execution"("agentflowId"); +CREATE INDEX idx_execution_sessionId ON "execution"("sessionId"); +CREATE INDEX idx_execution_userId ON "execution"("userId"); +CREATE INDEX idx_execution_organizationId ON "execution"("organizationId"); + +-- ============================================ +-- THEANSWER EXTENSIONS (Prisma) +-- ============================================ + +-- Table: chat +-- Purpose: User conversations and chat sessions +-- Multi-tenancy: Scoped to organization +CREATE TABLE "chat" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title VARCHAR, + "promptId" UUID, + "journeyId" UUID, + "ownerId" UUID REFERENCES "user"(id), + "chatflowChatId" VARCHAR, + "organizationId" UUID REFERENCES "organization"(id), + filters JSONB NOT NULL, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_chat_promptId ON "chat"("promptId"); +CREATE INDEX idx_chat_journeyId ON "chat"("journeyId"); +CREATE INDEX idx_chat_ownerId ON "chat"("ownerId"); +CREATE INDEX idx_chat_organizationId ON "chat"("organizationId"); + +-- Table: prompt +-- Purpose: Reusable conversation prompts +-- Global resource with usage tracking +CREATE TABLE "prompt" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title VARCHAR, + description TEXT, + content TEXT NOT NULL UNIQUE, + usages INTEGER NOT NULL DEFAULT 0, + likes INTEGER NOT NULL DEFAULT 0, + dislikes INTEGER NOT NULL DEFAULT 0, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + tags TEXT[] DEFAULT ARRAY[]::TEXT[] +); + +CREATE INDEX idx_prompt_content ON "prompt"(content); + +-- Table: message +-- Purpose: Individual messages within chats +-- AI tracking: Links to ai_request for cost tracking +CREATE TABLE "message" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + role VARCHAR NOT NULL DEFAULT 'assistant', + content TEXT NOT NULL, + "contextSourceFilesUsed" TEXT[] DEFAULT ARRAY[]::TEXT[], + context TEXT NOT NULL DEFAULT '', + "sidekickJson" JSONB NOT NULL DEFAULT '{}', + "promptId" UUID REFERENCES "prompt"(id), + "userId" UUID REFERENCES "user"(id), + "chatId" UUID NOT NULL REFERENCES "chat"(id), + likes INTEGER NOT NULL DEFAULT 0, + dislikes INTEGER NOT NULL DEFAULT 0, + deleted BOOLEAN NOT NULL DEFAULT FALSE, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "aiRequestId" UUID UNIQUE REFERENCES "ai_request"(id) +); + +CREATE INDEX idx_message_promptId ON "message"("promptId"); +CREATE INDEX idx_message_userId ON "message"("userId"); +CREATE INDEX idx_message_chatId ON "message"("chatId"); + +-- Table: journey +-- Purpose: User journey tracking for analytics +-- Goal tracking and completion metrics +CREATE TABLE "journey" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + title VARCHAR, + goal VARCHAR, + "completedAt" TIMESTAMP, + filters JSONB NOT NULL, + "organizationId" UUID REFERENCES "organization"(id), + deleted BOOLEAN NOT NULL DEFAULT FALSE, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_journey_organizationId ON "journey"("organizationId"); + +-- Table: document +-- Purpose: Knowledge base documents +-- Syncing: Tracks last sync time for document updates +CREATE TABLE "document" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + source VARCHAR NOT NULL, + title VARCHAR, + domain VARCHAR, + url VARCHAR NOT NULL UNIQUE, + content TEXT NOT NULL DEFAULT '', + metadata JSONB NOT NULL DEFAULT '{}', + status VARCHAR NOT NULL DEFAULT 'pending', + "lastSyncedAt" TIMESTAMP, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_document_url ON "document"(url); +CREATE INDEX idx_document_source ON "document"(source); + +-- Table: document_permission +-- Purpose: Control document access by organization +CREATE TABLE "document_permission" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "documentId" UUID NOT NULL REFERENCES "document"(id), + "organizationId" UUID NOT NULL REFERENCES "organization"(id), + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_document_permission_documentId ON "document_permission"("documentId"); +CREATE INDEX idx_document_permission_organizationId ON "document_permission"("organizationId"); + +-- Table: sidekick +-- Purpose: AI assistant configurations +-- Sharing: Can be global, system, or org-scoped +CREATE TABLE "sidekick" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "isGlobal" BOOLEAN DEFAULT FALSE, + "isSystem" BOOLEAN DEFAULT FALSE, + "isSharedWithOrg" BOOLEAN DEFAULT FALSE, + "isFavoriteByDefault" BOOLEAN DEFAULT FALSE, + chatflow JSONB, + "chatflowApiKey" VARCHAR, + "chatflowDomain" VARCHAR, + "organizationId" UUID REFERENCES "organization"(id), + label VARCHAR NOT NULL, + tags TEXT[] DEFAULT ARRAY[]::TEXT[], + "userId" UUID NOT NULL REFERENCES "user"(id), + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + temperature FLOAT NOT NULL DEFAULT 1, + frequency FLOAT NOT NULL DEFAULT 0, + presence FLOAT NOT NULL DEFAULT 0, + "maxCompletionTokens" INTEGER NOT NULL DEFAULT 500, + "aiModel" VARCHAR, + "systemPromptTemplate" TEXT, + "userPromptTemplate" TEXT, + "contextStringRender" TEXT, + placeholder VARCHAR +); + +CREATE INDEX idx_sidekick_organizationId ON "sidekick"("organizationId"); +CREATE INDEX idx_sidekick_userId ON "sidekick"("userId"); + +-- Table: api_key +-- Purpose: API authentication +-- Types: USER or ORGANIZATION scoped +CREATE TABLE "api_key" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "userId" UUID REFERENCES "user"(id), + "organizationId" UUID REFERENCES "organization"(id), + type VARCHAR NOT NULL DEFAULT 'USER', + key VARCHAR NOT NULL UNIQUE, + CONSTRAINT chk_api_key_type CHECK (type IN ('USER', 'ORGANIZATION')) +); + +CREATE INDEX idx_api_key_userId ON "api_key"("userId"); +CREATE INDEX idx_api_key_organizationId ON "api_key"("organizationId"); + +-- Table: ai_request +-- Purpose: Track AI API requests for billing and analytics +-- Cost tracking: Stores token usage and USD costs +CREATE TABLE "ai_request" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + type VARCHAR NOT NULL, + method VARCHAR NOT NULL, + model VARCHAR NOT NULL, + "tokensUsed" INTEGER NOT NULL, + "tokensUsedUser" INTEGER NOT NULL, + "costUsdTotal" DECIMAL NOT NULL, + "costUsdTotalUser" DECIMAL NOT NULL, + "userId" UUID NOT NULL REFERENCES "user"(id), + request JSONB, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_ai_request_userId ON "ai_request"("userId"); + +-- Table: message_feedback +-- Purpose: User feedback on messages +-- Ratings: thumbsUp or thumbsDown +CREATE TABLE "message_feedback" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + rating VARCHAR NOT NULL DEFAULT 'thumbsUp', + content TEXT NOT NULL, + tags TEXT[] DEFAULT ARRAY[]::TEXT[], + "userId" UUID NOT NULL REFERENCES "user"(id), + "messageId" UUID NOT NULL REFERENCES "message"(id), + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + UNIQUE ("userId", "messageId"), + CONSTRAINT chk_message_feedback_rating CHECK (rating IN ('thumbsUp', 'thumbsDown')) +); + +CREATE INDEX idx_message_feedback_userId ON "message_feedback"("userId"); +CREATE INDEX idx_message_feedback_messageId ON "message_feedback"("messageId"); + +-- Table: plan +-- Purpose: Subscription plans with token limits +CREATE TABLE "plan" ( + id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, + name VARCHAR NOT NULL, + description TEXT NOT NULL, + "tokenLimit" INTEGER NOT NULL +); + +-- Table: active_user_plan +-- Purpose: Current active plan for user +-- Renewal tracking and token management +CREATE TABLE "active_user_plan" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "userId" UUID NOT NULL UNIQUE REFERENCES "user"(id), + "planId" INTEGER NOT NULL REFERENCES "plan"(id), + "renewalDate" TIMESTAMP NOT NULL, + "tokensLeft" INTEGER NOT NULL, + "startDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "gpt3RequestCount" INTEGER NOT NULL DEFAULT 0, + "gpt4RequestCount" INTEGER NOT NULL DEFAULT 0, + "stripeSubscriptionId" VARCHAR, + "shouldRenew" BOOLEAN NOT NULL DEFAULT TRUE +); + +CREATE INDEX idx_active_user_plan_userId ON "active_user_plan"("userId"); + +-- Table: app_config +-- Purpose: Per-app configuration storage +CREATE TABLE "app_config" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "userId" UUID NOT NULL REFERENCES "user"(id), + "appId" VARCHAR NOT NULL, + "appType" VARCHAR NOT NULL, + config JSONB NOT NULL +); + +CREATE INDEX idx_app_config_userId ON "app_config"("userId"); + +-- Table: app_csv_parse_runs +-- Purpose: Track CSV processing jobs +-- Status: pending -> inProgress -> complete/completeWithErrors -> generatingCsv -> ready +CREATE TABLE "app_csv_parse_runs" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "userId" UUID NOT NULL REFERENCES "user"(id), + "orgId" UUID NOT NULL REFERENCES "organization"(id), + "startedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "completedAt" TIMESTAMP, + "rowsRequested" INTEGER NOT NULL, + "rowsProcessed" INTEGER, + name VARCHAR NOT NULL, + configuration JSONB NOT NULL, + "originalCsvUrl" TEXT NOT NULL, + "processedCsvUrl" TEXT, + "chatflowChatId" VARCHAR NOT NULL, + "includeOriginalColumns" BOOLEAN NOT NULL DEFAULT TRUE, + status VARCHAR NOT NULL DEFAULT 'pending', + "errorMessages" TEXT[] DEFAULT ARRAY[]::TEXT[], + CONSTRAINT chk_csv_parse_run_status CHECK (status IN ('pending', 'inProgress', 'completeWithErrors', 'complete', 'generatingCsv', 'ready')) +); + +CREATE INDEX idx_app_csv_parse_runs_userId ON "app_csv_parse_runs"("userId"); +CREATE INDEX idx_app_csv_parse_runs_orgId ON "app_csv_parse_runs"("orgId"); + +-- Table: app_csv_parse_rows +-- Purpose: Track individual row processing in CSV jobs +-- Status: pending -> inProgress -> complete/completeWithError +CREATE TABLE "app_csv_parse_rows" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + "csvParseRunId" UUID NOT NULL REFERENCES "app_csv_parse_runs"(id), + "rowNumber" INTEGER NOT NULL, + "rowData" JSONB NOT NULL, + "generatedData" JSONB, + status VARCHAR NOT NULL DEFAULT 'pending', + "errorMessage" TEXT, + "createdAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT chk_csv_parse_row_status CHECK (status IN ('pending', 'inProgress', 'completeWithError', 'complete')) +); + +CREATE INDEX idx_app_csv_parse_rows_csvParseRunId ON "app_csv_parse_rows"("csvParseRunId"); + +-- ============================================ +-- FOREIGN KEY CONSTRAINTS +-- ============================================ + +-- User self-references +ALTER TABLE "user" ADD CONSTRAINT fk_user_createdBy FOREIGN KEY ("createdBy") REFERENCES "user"(id); +ALTER TABLE "user" ADD CONSTRAINT fk_user_updatedBy FOREIGN KEY ("updatedBy") REFERENCES "user"(id); +ALTER TABLE "user" ADD CONSTRAINT fk_user_organizationId FOREIGN KEY ("organizationId") REFERENCES "organization"(id); + +-- Chat relations +ALTER TABLE "chat" ADD CONSTRAINT fk_chat_promptId FOREIGN KEY ("promptId") REFERENCES "prompt"(id); +ALTER TABLE "chat" ADD CONSTRAINT fk_chat_journeyId FOREIGN KEY ("journeyId") REFERENCES "chat"(id); + +-- ============================================ +-- MULTI-TENANCY NOTES +-- ============================================ + +-- All resources must filter by organizationId to ensure data isolation +-- All resources should track userId for audit and permission purposes +-- All resources should include createdAt/updatedAt timestamps +-- Soft deletes use deletedDate column where applicable + +-- ============================================ +-- AUDIT & TRACKING +-- ============================================ + +-- All tables include created/updated timestamps for audit trails +-- user and organization include createdBy/updatedBy for creator tracking +-- ai_request tracks all API calls for billing and usage analytics +-- message_feedback captures user feedback for quality improvement diff --git a/.alphaAgent/spec/tech-stack.json b/.alphaAgent/spec/tech-stack.json new file mode 100644 index 00000000000..124544c51e8 --- /dev/null +++ b/.alphaAgent/spec/tech-stack.json @@ -0,0 +1,1221 @@ +{ + "version": "1.0", + "project": { + "name": "TheAnswer", + "description": "Enterprise AI workflow platform built on Flowise with advanced multi-tenancy, authentication, and integration capabilities", + "repository": "https://github.com/the-answerai/theanswer", + "license": "Proprietary (SEE LICENSE IN LICENSE.md)", + "nodeVersion": ">=18.15.0 <19.0.0 || ^20", + "pnpmVersion": ">=9", + "projectType": "Monorepo - Web App + Backend API + Components Library" + }, + "core_frameworks": [ + { + "name": "React", + "package": "react", + "version": "18.2.0", + "installed_version": "18.2.0", + "type": "frontend_framework", + "purpose": "UI library for building user interfaces with component-based architecture", + "documentation": "https://react.dev/", + "github": "https://github.com/facebook/react", + "usage": [ + "Main UI component library across web app and Flowise UI", + "Server and Client Components in Next.js", + "Interactive dashboards and flow editor" + ], + "key_modules": [ + "react/jsx-runtime", + "react-dom", + "react-dom/client" + ] + }, + { + "name": "Next.js", + "package": "next", + "version": "^14.2.32", + "installed_version": "14.2.32", + "type": "framework", + "purpose": "React-based full-stack framework with App Router, server/client components, and built-in API routes", + "documentation": "https://nextjs.org/docs", + "github": "https://github.com/vercel/next.js", + "usage": [ + "Main web application (apps/web)", + "Server-side rendering for main UI", + "API routes for backend endpoints", + "Authentication middleware with Auth0", + "Dynamic routing and page generation" + ], + "key_modules": [ + "next/app", + "next/server", + "next/navigation", + "next/image" + ] + }, + { + "name": "Express.js", + "package": "express", + "version": "^4.17.3", + "installed_version": "4.19.2", + "type": "backend_framework", + "purpose": "Minimal and flexible Node.js web application framework for building the Flowise server API", + "documentation": "https://expressjs.com/", + "github": "https://github.com/expressjs/express", + "usage": [ + "Core REST API server (packages/server)", + "Route handling and middleware pipeline", + "Error handling and response formatting", + "Authentication and authorization middleware" + ], + "key_modules": [ + "express/Router", + "express-session", + "express-rate-limit" + ] + }, + { + "name": "TypeScript", + "package": "typescript", + "version": "~5.5.4", + "installed_version": "5.5.4", + "type": "language", + "purpose": "Type-safe JavaScript superset for the entire codebase", + "documentation": "https://www.typescriptlang.org/", + "github": "https://github.com/microsoft/TypeScript", + "usage": [ + "Type definitions across server, components, and web packages", + "Strict type checking for API contracts", + "Entity and interface definitions", + "Component prop typing" + ], + "compiler_options": { + "target": "ES2022", + "module": "Node16", + "strict": true, + "esModuleInterop": true, + "declaration": true + } + }, + { + "name": "TypeORM", + "package": "typeorm", + "version": "^0.3.6", + "installed_version": "0.3.6", + "type": "orm", + "purpose": "Object-relational mapper for TypeScript with database migrations and query builders", + "documentation": "https://typeorm.io/", + "github": "https://github.com/typeorm/typeorm", + "usage": [ + "Database entity definitions (packages/server/src/database/entities)", + "Flowise core entities (Chatflows, Credentials, Tools, etc.)", + "Database migrations and schema management", + "Query builders for complex database operations", + "Multi-tenancy with organizationId and userId filtering" + ], + "key_modules": [ + "typeorm/decorator", + "typeorm/Repository", + "typeorm/QueryBuilder" + ] + }, + { + "name": "Prisma", + "package": "@prisma/client", + "version": "^5.22.0", + "installed_version": "5.22.0", + "type": "orm", + "purpose": "Next-generation ORM for TheAnswer-specific extensions with type-safe database access", + "documentation": "https://www.prisma.io/docs/", + "github": "https://github.com/prisma/prisma", + "usage": [ + "TheAnswer extensions database layer (packages-answers/db)", + "Type-safe generated client code", + "Schema migrations for custom features", + "Seed scripts for test data" + ], + "key_modules": [ + "@prisma/client", + "@prisma/sdk" + ] + }, + { + "name": "LangChain", + "package": "langchain", + "version": "^0.3.5", + "installed_version": "0.3.5", + "type": "library", + "purpose": "Framework for building applications powered by language models with chains, agents, and tools", + "documentation": "https://js.langchain.com/", + "github": "https://github.com/langchain-ai/langchainjs", + "usage": [ + "Agent implementations in components (agents, tools, chains)", + "Vector store integrations", + "Document loading and processing", + "Memory management for conversations", + "Prompt templating and output parsing", + "LangChain hub integration for prompt management" + ], + "key_modules": [ + "@langchain/core", + "@langchain/community", + "@langchain/openai", + "@langchain/anthropic", + "langchain/agents", + "langchain/tools" + ] + }, + { + "name": "Auth0", + "package": "@auth0/nextjs-auth0", + "version": "3.5.0", + "installed_version": "3.5.0", + "type": "authentication", + "purpose": "Enterprise authentication and authorization platform for secure user management and organization access control", + "documentation": "https://auth0.com/docs/quickstart/webapp/nextjs", + "github": "https://github.com/auth0/nextjs-auth0", + "usage": [ + "OAuth2/OIDC authentication for web app", + "JWT token generation and validation", + "Multi-organization support via org_id claims", + "Role-based access control", + "Social login integrations (Google, GitHub, etc.)", + "API authentication with JWT bearer tokens" + ], + "key_modules": [ + "@auth0/nextjs-auth0/edge", + "@auth0/nextjs-auth0/client", + "@auth0/auth0-react" + ] + }, + { + "name": "LangGraph", + "package": "@langchain/langgraph", + "version": "^0.0.22", + "installed_version": "0.0.22", + "type": "library", + "purpose": "Framework for building stateful, multi-actor applications with LangChain using graph-based workflows", + "documentation": "https://langchain-ai.github.io/langgraphjs/", + "github": "https://github.com/langchain-ai/langgraphjs", + "usage": [ + "Multi-agent workflow orchestration", + "Stateful agent implementations", + "Sequential and parallel agent execution", + "Tool use and action planning" + ] + }, + { + "name": "Model Context Protocol (MCP)", + "package": "@modelcontextprotocol/sdk", + "version": "^1.10.1", + "installed_version": "1.10.1", + "type": "framework", + "purpose": "Protocol for connecting AI models to external tools and data sources via standardized interfaces", + "documentation": "https://modelcontextprotocol.io/", + "github": "https://github.com/modelcontextprotocol/typescript-sdk", + "usage": [ + "MCP tool implementations for external integrations", + "Tool definitions and execution framework", + "Server implementations (Brave Search, Slack, GitHub, PostgreSQL, Sequential Thinking)", + "Standard interface for AI model tool access" + ], + "key_modules": [ + "@modelcontextprotocol/sdk/client", + "@modelcontextprotocol/sdk/server" + ] + } + ], + "build_tools": [ + { + "name": "Turbo", + "package": "turbo", + "version": "1.10.16", + "installed_version": "1.10.16", + "type": "build_tool", + "purpose": "Monorepo task orchestrator for incremental builds, caching, and parallel execution", + "documentation": "https://turbo.build/", + "github": "https://github.com/vercel/turbo", + "usage": [ + "Build orchestration across all workspaces", + "Incremental builds with Turbo cache", + "Parallel task execution (dev, build, test)", + "Task dependency management" + ], + "config_file": "turbo.json", + "npm_scripts": [ + "pnpm build - Build all packages with Turbo", + "pnpm build-force - Clean build ignoring cache", + "pnpm dev - Start all dev servers" + ] + }, + { + "name": "TypeScript Compiler", + "package": "typescript", + "version": "~5.5.4", + "installed_version": "5.5.4", + "type": "compiler", + "purpose": "Compile TypeScript to JavaScript with type checking", + "documentation": "https://www.typescriptlang.org/", + "github": "https://github.com/microsoft/TypeScript", + "usage": [ + "Server and component compilation", + "Type checking during builds", + "Source map generation for debugging" + ], + "config_file": "tsconfig.json", + "npm_scripts": [ + "pnpm build - Runs tsc compiler" + ] + }, + { + "name": "Gulp", + "package": "gulp", + "version": "^4.0.2", + "installed_version": "4.0.2", + "type": "build_tool", + "purpose": "Task runner for build automation and asset processing", + "documentation": "https://gulpjs.com/", + "github": "https://github.com/gulpjs/gulp", + "usage": [ + "Post-compilation asset processing", + "Used in server and components builds" + ], + "config_file": "gulpfile.js", + "npm_scripts": [ + "Runs after TypeScript compilation" + ] + }, + { + "name": "Webpack", + "package": "webpack", + "version": "^5.101.3", + "installed_version": "5.101.3", + "type": "bundler", + "purpose": "Module bundler for web applications with code splitting and asset optimization", + "documentation": "https://webpack.js.org/", + "github": "https://github.com/webpack/webpack", + "usage": [ + "Web app bundling and optimization", + "Asset management and loaders", + "Code splitting for performance" + ], + "config_file": "next.config.js", + "npm_scripts": [ + "Part of Next.js build pipeline" + ] + } + ], + "testing_frameworks": [ + { + "name": "Jest", + "package": "jest", + "version": "^29.7.0", + "installed_version": "29.7.0", + "type": "testing", + "purpose": "Unit and integration testing framework for JavaScript/TypeScript", + "documentation": "https://jestjs.io/", + "github": "https://github.com/jestjs/jest", + "usage": [ + "Unit tests for server services and controllers", + "Component tests for Flowise nodes", + "API endpoint testing with supertest", + "Database migration testing" + ], + "npm_scripts": [ + "pnpm test - Run all tests", + "pnpm test:auth - Run authentication tests", + "pnpm test:coverage - Generate coverage reports" + ], + "config_file": "jest.config.cjs, jest.config.all.js" + }, + { + "name": "Playwright", + "package": "@playwright/test", + "version": "^1.55.0", + "installed_version": "1.55.0", + "type": "testing", + "purpose": "End-to-end testing framework for browser automation and user workflow testing", + "documentation": "https://playwright.dev/", + "github": "https://github.com/microsoft/playwright", + "usage": [ + "E2E tests for web app (apps/web/e2e)", + "Authentication flow testing", + "Role-based access control testing", + "User interaction and navigation testing" + ], + "npm_scripts": [ + "pnpm test:e2e - Run E2E tests with UI", + "pnpm test:e2e:dev - Run in dev mode", + "pnpm test:e2e:debug - Debug mode step-through", + "pnpm test:e2e:setup - Install browsers" + ], + "config_file": "playwright.config.ts" + }, + { + "name": "Cypress", + "package": "cypress", + "version": "^13.17.0", + "installed_version": "13.17.0", + "type": "testing", + "purpose": "Browser-based testing framework for component and E2E testing", + "documentation": "https://docs.cypress.io/", + "github": "https://github.com/cypress-io/cypress", + "usage": [ + "Component testing for React components", + "Chatflow testing and validation", + "Server integration testing" + ], + "npm_scripts": [ + "pnpm test:cmp - Component tests", + "pnpm test:chatflows - Chatflow testing" + ], + "config_file": "cypress.config.ts" + }, + { + "name": "ts-jest", + "package": "ts-jest", + "version": "^29.3.2", + "installed_version": "29.3.2", + "type": "testing", + "purpose": "TypeScript preprocessor for Jest to directly test TypeScript files", + "documentation": "https://kulshekhar.github.io/ts-jest/", + "github": "https://github.com/kulshekhar/ts-jest", + "usage": [ + "Direct TypeScript compilation in Jest tests", + "Server and component testing without pre-compilation" + ] + }, + { + "name": "Supertest", + "package": "supertest", + "version": "^7.1.0", + "installed_version": "7.1.0", + "type": "testing", + "purpose": "HTTP assertion library for testing Express servers", + "documentation": "https://github.com/visionmedia/supertest", + "github": "https://github.com/visionmedia/supertest", + "usage": [ + "API endpoint testing", + "REST API validation", + "Authentication and authorization testing" + ] + } + ], + "runtime_dependencies": [ + { + "name": "Node.js", + "version": ">=18.15.0 <19.0.0 || ^20", + "type": "runtime", + "purpose": "JavaScript runtime environment for server-side execution", + "documentation": "https://nodejs.org/", + "features": [ + "Built-in fetch API (Node 18+)", + "ES modules support", + "Native crypto and compression", + "Stream processing" + ] + }, + { + "name": "PostgreSQL with pgvector", + "version": "16 (with pgvector extension)", + "type": "database", + "purpose": "Primary relational database with vector search capability for embeddings", + "documentation": "https://www.postgresql.org/", + "github": "https://github.com/pgvector/pgvector", + "features": [ + "Multi-tenancy with UUID foreign keys", + "Full ACID compliance", + "Vector similarity search for embeddings", + "JSON and JSONB support" + ] + }, + { + "name": "Redis", + "version": "latest", + "type": "cache_database", + "purpose": "In-memory data store for caching, session management, and rate limiting", + "documentation": "https://redis.io/", + "github": "https://github.com/redis/redis", + "features": [ + "Session storage with connect-redis", + "Cache management with cache-manager", + "Rate limit state with rate-limit-redis", + "Pub/Sub for real-time updates" + ] + } + ], + "package_managers": [ + { + "name": "pnpm", + "version": ">=9", + "type": "package_manager", + "documentation": "https://pnpm.io/", + "github": "https://github.com/pnpm/pnpm", + "lock_file": "pnpm-lock.yaml", + "lock_file_version": "9.0", + "usage": "Primary package manager for monorepo dependency management with workspace support and strict dependency resolution" + } + ], + "services_and_apis": [ + { + "name": "Auth0 Authentication API", + "version": "v1", + "type": "external_api", + "purpose": "Enterprise authentication and authorization service with multi-tenancy and role-based access control", + "documentation": "https://auth0.com/docs/api/authentication", + "github": null, + "base_url": "https://{tenant}.auth0.com", + "authentication": "OAuth2 / OIDC", + "environment_variables": [ + { + "name": "AUTH0_ISSUER_BASE_URL", + "description": "Auth0 tenant domain URL", + "required": true + }, + { + "name": "AUTH0_CLIENT_ID", + "description": "OAuth2 application client ID", + "required": true + }, + { + "name": "AUTH0_CLIENT_SECRET", + "description": "OAuth2 application client secret", + "required": true + }, + { + "name": "AUTH0_AUDIENCE", + "description": "API audience identifier for JWT validation", + "required": true + }, + { + "name": "AUTH0_SCOPE", + "description": "OAuth2 scopes for user permissions", + "required": false + } + ], + "endpoints_available": [ + "POST /oauth/token - Get access tokens", + "POST /oauth/authorize - Initiate OAuth flow", + "GET /userinfo - Get authenticated user information", + "POST /logout - Revoke session", + "GET /well-known/openid-configuration - OIDC discovery" + ] + }, + { + "name": "AWS S3", + "version": "v2", + "type": "external_api", + "purpose": "Cloud object storage for file uploads, chatflow assets, and backup storage", + "documentation": "https://docs.aws.amazon.com/s3/", + "github": null, + "base_url": "https://{bucket}.s3.{region}.amazonaws.com", + "authentication": "AWS Signature Version 4", + "environment_variables": [ + { + "name": "AWS_ACCESS_KEY_ID", + "description": "AWS IAM access key", + "required": true + }, + { + "name": "AWS_SECRET_ACCESS_KEY", + "description": "AWS IAM secret key", + "required": true + }, + { + "name": "AWS_S3_BUCKET", + "description": "S3 bucket name for storage", + "required": true + }, + { + "name": "AWS_S3_REGION", + "description": "AWS region for bucket", + "required": true + } + ], + "endpoints_available": [ + "PUT /object - Upload file", + "GET /object - Download file", + "DELETE /object - Delete file", + "HEAD /object - Check object metadata" + ] + }, + { + "name": "Stripe Billing API", + "version": "v1", + "type": "external_api", + "purpose": "Payment processing and billing management for SaaS features and metered usage", + "documentation": "https://stripe.com/docs/api", + "github": null, + "base_url": "https://api.stripe.com/v1", + "authentication": "API Key in Authorization header", + "environment_variables": [ + { + "name": "STRIPE_SECRET_KEY", + "description": "Stripe secret API key for server-side operations", + "required": true + }, + { + "name": "STRIPE_WEBHOOK_SECRET", + "description": "Webhook signing secret for event verification", + "required": true + }, + { + "name": "STRIPE_METER_PREFIX", + "description": "Prefix for metered billing metrics", + "required": false + } + ], + "endpoints_available": [ + "POST /customers - Create billing customer", + "POST /subscriptions - Create subscription", + "POST /billing_meter_events - Record usage metrics", + "POST /webhook_endpoints - Register webhooks" + ] + }, + { + "name": "Langfuse Observability API", + "version": "v1", + "type": "external_api", + "purpose": "LLM observability and monitoring platform for tracking model performance, costs, and errors", + "documentation": "https://docs.langfuse.com/", + "github": "https://github.com/langfuse/langfuse", + "base_url": "https://cloud.langfuse.com", + "authentication": "API Key pair (public + secret)", + "environment_variables": [ + { + "name": "LANGFUSE_PUBLIC_KEY", + "description": "Public key for Langfuse integration", + "required": false + }, + { + "name": "LANGFUSE_SECRET_KEY", + "description": "Secret key for Langfuse integration", + "required": false + }, + { + "name": "LANGFUSE_HOST", + "description": "Langfuse host URL (default: cloud.langfuse.com)", + "required": false + } + ], + "endpoints_available": [ + "POST /api/public/traces - Log traces", + "POST /api/public/observations - Log observations", + "GET /api/public/traces - Fetch traces", + "POST /api/public/scores - Log quality scores" + ] + }, + { + "name": "OpenAI API", + "version": "v1", + "type": "external_api", + "purpose": "Large language model access and embeddings for AI-powered features", + "documentation": "https://platform.openai.com/docs/api-reference", + "github": null, + "base_url": "https://api.openai.com/v1", + "authentication": "Bearer token in Authorization header", + "environment_variables": [ + { + "name": "OPENAI_API_KEY", + "description": "OpenAI API key", + "required": false + } + ], + "endpoints_available": [ + "POST /chat/completions - Chat completions", + "POST /embeddings - Generate embeddings", + "POST /images/generations - Generate images", + "POST /audio/speech - Text-to-speech" + ] + }, + { + "name": "Pinecone Vector Database", + "version": "v1", + "type": "external_api", + "purpose": "Managed vector database for storing and querying document embeddings in RAG workflows", + "documentation": "https://docs.pinecone.io/", + "github": "https://github.com/pinecone-io/pinecone-ts-client", + "base_url": "https://{environment}.pinecone.io", + "authentication": "API Key", + "environment_variables": [ + { + "name": "PINECONE_API_KEY", + "description": "Pinecone API key", + "required": false + }, + { + "name": "PINECONE_ENVIRONMENT", + "description": "Pinecone environment (e.g., us-west-2)", + "required": false + }, + { + "name": "PINECONE_INDEX", + "description": "Index name for vector storage", + "required": false + } + ], + "endpoints_available": [ + "POST /vectors/upsert - Upsert vectors", + "POST /query - Query vectors", + "DELETE /vectors - Delete vectors", + "GET /describe_index_stats - Get index statistics" + ] + } + ], + "source_code_structure": { + "root_directory": "/Users/bradtaylor/Github/theanswer", + "entry_points": { + "server": "packages/server/src/index.ts", + "web": "apps/web/app/layout.tsx", + "components": "packages/components/src/index.ts" + }, + "directories": { + "packages": { + "description": "Core Flowise packages (forked and extended)", + "subdirectories": [ + { + "path": "packages/server", + "description": "Express.js backend API with routes, controllers, services, and database entities" + }, + { + "path": "packages/ui", + "description": "Flowise React UI components and UI library" + }, + { + "path": "packages/components", + "description": "Flowise nodes (agents, chat models, tools, vector stores, document loaders, etc.)" + }, + { + "path": "packages/embed", + "description": "Chat embed widget (git submodule)" + }, + { + "path": "packages/embed-react", + "description": "React component wrapper for chat embed" + }, + { + "path": "packages/docs", + "description": "Docusaurus documentation site" + }, + { + "path": "packages/api-documentation", + "description": "API documentation and OpenAPI specs" + } + ] + }, + "packages-answers": { + "description": "TheAnswer-specific extensions and custom implementations", + "subdirectories": [ + { + "path": "packages-answers/db", + "description": "Prisma database layer for TheAnswer-specific data" + }, + { + "path": "packages-answers/ui", + "description": "TheAnswer custom UI components and extensions" + }, + { + "path": "packages-answers/utils", + "description": "Shared utility functions and helpers" + }, + { + "path": "packages-answers/types", + "description": "Shared TypeScript type definitions" + } + ] + }, + "apps": { + "description": "Application-specific packages", + "subdirectories": [ + { + "path": "apps/web", + "description": "Next.js 14 web application with App Router, Auth0, and E2E tests" + }, + { + "path": "apps/desktop", + "description": "Desktop application (if applicable)" + } + ] + }, + "src": { + "description": "Server source code structure", + "subdirectories": [ + { + "path": "packages/server/src/routes", + "description": "RESTful API endpoint definitions with enforceAbility middleware" + }, + { + "path": "packages/server/src/controllers", + "description": "Request handlers with validation and authorization using checkOwnership" + }, + { + "path": "packages/server/src/services", + "description": "Business logic layer with database operations and multi-tenancy filtering" + }, + { + "path": "packages/server/src/database/entities", + "description": "TypeORM entity definitions with required multi-tenancy fields" + }, + { + "path": "packages/server/src/database/migrations", + "description": "TypeORM database schema migrations" + }, + { + "path": "packages/server/src/middlewares/authentication", + "description": "Auth middleware (enforceAbility, JWT validation, API key verification)" + }, + { + "path": "packages/server/src/utils", + "description": "Utility functions (checkOwnership, error handling, data transformation)" + } + ] + }, + "nodes": { + "description": "Flowise component node implementations", + "subdirectories": [ + { + "path": "packages/components/nodes/agents", + "description": "LangChain agent implementations" + }, + { + "path": "packages/components/nodes/chatmodels", + "description": "LLM provider integrations (OpenAI, Anthropic, AWS Bedrock, Google, etc.)" + }, + { + "path": "packages/components/nodes/tools", + "description": "Agent tools, integrations, and MCP servers" + }, + { + "path": "packages/components/nodes/vectorstores", + "description": "Vector database connectors (Pinecone, Chroma, Qdrant, FAISS, etc.)" + }, + { + "path": "packages/components/nodes/documentloaders", + "description": "Data source loaders (PDF, CSV, web, APIs, etc.)" + } + ] + } + } + }, + "key_features": [ + "Multi-tenant SaaS architecture with organization and user-level access control", + "Enterprise authentication with Auth0 OAuth2/OIDC and JWT", + "No-code AI workflow builder with drag-and-drop flow editor", + "LLM integrations (OpenAI, Anthropic, AWS Bedrock, Google, Ollama, Groq, etc.)", + "Vector-based RAG with multiple vector store backends (Pinecone, Chroma, Qdrant)", + "Agent framework with LangChain and LangGraph for multi-step reasoning", + "Tool integrations including MCP (Model Context Protocol) servers", + "Real-time chat embedding and widget deployment", + "Comprehensive observability with Langfuse tracking", + "Metered billing with Stripe integration", + "Database connections and SQL agents", + "Document processing with multiple format support", + "API key management and secure credential storage", + "Organization-scoped resource management", + "Audit logging and activity tracking" + ], + "development_setup": { + "prerequisites": [ + "Node.js >=18.15.0 <19.0.0 || ^20", + "pnpm >=9", + "Docker and Docker Compose (for PostgreSQL and Redis)", + "Git with submodule support" + ], + "installation": [ + "git clone https://github.com/the-answerai/theanswer.git", + "cd theanswer", + "pnpm install", + "pnpm submodule:init", + "cp .env.template .env", + "Edit .env with your configuration", + "pnpm dev-docker (start PostgreSQL and Redis)", + "pnpm db:migrate (run database migrations)", + "pnpm dev (start development servers)" + ], + "scripts": { + "build": "pnpm secure-run 'turbo run build'", + "dev": "pnpm secure-run 'turbo run dev dev-docker'", + "dev-docker": "docker compose -f './docker-compose.dev.yml' up -d", + "start": "pnpm secure-run 'npx turbo run start'", + "test": "turbo run test", + "test:auth": "pnpm secure-run 'turbo run test:auth'", + "test:e2e": "pnpm --filter web test:e2e", + "test:e2e:debug": "pnpm --filter web test:e2e:debug", + "lint": "eslint '**/*.{js,jsx,ts,tsx}'", + "lint-fix": "pnpm lint --fix", + "migration:generate": "turbo typeorm:migration-generate", + "migration:run": "pnpm secure-run 'turbo typeorm:migration-run'", + "db:migrate": "pnpm secure-run 'pnpm db migrate dev'", + "db:studio": "pnpm secure-run 'pnpm db studio'", + "clean": "pnpm --filter './packages/**' clean", + "nuke": "pnpm --filter './packages/**' nuke && rimraf node_modules .turbo" + } + }, + "error_handling": { + "strategies": [ + "Custom InternalFlowiseError class for consistent error responses", + "HTTP status code mapping with http-status-codes package", + "Error wrapping with context (Error: serviceName.methodName - description)", + "Try-catch blocks with getErrorMessage utility", + "Async error handling in Express with next() middleware pattern", + "Multi-tenancy validation with UnauthorizedError for ownership checks" + ], + "implementation": "All routes use enforceAbility middleware. All controllers check ownership via checkOwnership(). All services wrap errors with descriptive messages. Database errors are caught and wrapped with transaction rollback support." + }, + "performance_optimizations": [ + "Turbo incremental builds with caching for monorepo", + "Next.js automatic code splitting and static generation", + "React Server Components default to reduce JavaScript payload", + "Database query builder with indexed fields (userId, organizationId)", + "Redis caching layer for sessions and rate limiting", + "Lazy loading of heavy dependencies (LangChain modules)", + "Batch API requests for related data", + "Maximum result limits to prevent memory issues", + "Connection pooling for database and Redis", + "Optimized LLM prompts for shorter context windows", + "Vector store query pagination and filtering" + ], + "security_considerations": [ + "All routes protected with enforceAbility middleware", + "Multi-tenancy enforcement with organizationId filtering in all queries", + "Resource ownership verification with checkOwnership() before access", + "JWT token validation with Auth0 JWKS", + "API key storage in secure credential system", + "Input validation on all endpoints", + "SQL injection prevention via TypeORM parameterized queries", + "XSS prevention with React's built-in escaping", + "CSRF protection with SameSite cookies", + "Rate limiting on sensitive endpoints", + "Sanitized HTML content with sanitize-html package", + "No hardcoded secrets in codebase (use .env)", + "Error messages don't leak sensitive information", + "Soft deletion for audit trail preservation" + ], + "scalability_features": [ + "Stateless API design enabling horizontal scaling", + "Distributed job queue with BullMQ for async tasks", + "Redis pub/sub for real-time updates", + "Database connection pooling", + "Session storage in Redis for load balancing", + "S3 for distributed file storage", + "Vector database for scalable similarity search", + "OpenTelemetry instrumentation for distributed tracing", + "Circuit breaker pattern for external API resilience", + "Query pagination and result limits", + "Database query optimization with indexes", + "Caching strategies (Redis, in-memory)" + ], + "bin_entries": { + "flowise": "packages/server/bin/run" + }, + "configuration_files": [ + { + "file": "package.json", + "purpose": "Monorepo metadata, workspace definitions, npm scripts, and dependencies" + }, + { + "file": "pnpm-lock.yaml", + "purpose": "Locked dependency versions for reproducible installs" + }, + { + "file": "turbo.json", + "purpose": "Build task configuration, dependencies, caching, and environment variables" + }, + { + "file": "tsconfig.json", + "purpose": "TypeScript compiler configuration for the entire monorepo" + }, + { + "file": "packages/server/src/database/entities/index.ts", + "purpose": "TypeORM entity registration" + }, + { + "file": "packages/server/src/index.ts", + "purpose": "Express server entry point with route registration" + }, + { + "file": "apps/web/middleware.ts", + "purpose": "Auth0 middleware for route protection" + }, + { + "file": "apps/web/next.config.js", + "purpose": "Next.js configuration with webpack customization" + }, + { + "file": ".env.template", + "purpose": "Environment variable template with all configuration options" + }, + { + "file": "docker-compose.dev.yml", + "purpose": "Development database services (PostgreSQL, Redis) configuration" + }, + { + "file": ".eslintrc.js", + "purpose": "ESLint configuration for code linting" + }, + { + "file": "jest.config.cjs, jest.config.all.js", + "purpose": "Jest testing framework configuration" + }, + { + "file": "apps/web/playwright.config.ts", + "purpose": "Playwright E2E testing configuration" + } + ], + "external_documentation": [ + { + "title": "TheAnswer GitHub Repository", + "url": "https://github.com/the-answerai/theanswer" + }, + { + "title": "Flowise Documentation", + "url": "https://docs.flowiseai.com/" + }, + { + "title": "LangChain Documentation", + "url": "https://js.langchain.com/" + }, + { + "title": "Next.js 14 Documentation", + "url": "https://nextjs.org/docs" + }, + { + "title": "TypeORM Documentation", + "url": "https://typeorm.io/" + }, + { + "title": "Prisma Documentation", + "url": "https://www.prisma.io/docs/" + }, + { + "title": "Auth0 Authentication", + "url": "https://auth0.com/docs/" + }, + { + "title": "Express.js Documentation", + "url": "https://expressjs.com/" + }, + { + "title": "Turbo Monorepo", + "url": "https://turbo.build/" + }, + { + "title": "Model Context Protocol", + "url": "https://modelcontextprotocol.io/" + }, + { + "title": "Playwright Testing", + "url": "https://playwright.dev/" + }, + { + "title": "Jest Testing", + "url": "https://jestjs.io/" + } + ], + "github_repositories": [ + { + "name": "TheAnswer Main Repository", + "url": "https://github.com/the-answerai/theanswer" + }, + { + "name": "Flowise Repository", + "url": "https://github.com/FlowiseAI/Flowise" + }, + { + "name": "LangChain Repository", + "url": "https://github.com/langchain-ai/langchainjs" + }, + { + "name": "Model Context Protocol SDK", + "url": "https://github.com/modelcontextprotocol/typescript-sdk" + }, + { + "name": "Next.js Repository", + "url": "https://github.com/vercel/next.js" + }, + { + "name": "TypeORM Repository", + "url": "https://github.com/typeorm/typeorm" + }, + { + "name": "Prisma Repository", + "url": "https://github.com/prisma/prisma" + }, + { + "name": "Auth0 Next.js SDK", + "url": "https://github.com/auth0/nextjs-auth0" + }, + { + "name": "Turbo Repository", + "url": "https://github.com/vercel/turbo" + } + ], + "dependencies_summary": { + "production": 245, + "development": 75, + "total": 320, + "production_packages": [ + "@answerai/answeragent-mcp@^1.2.0", + "@answerai/confluence-mcp@^1.0.0", + "@answerai/jira-mcp@^1.1.0", + "@auth0/nextjs-auth0@3.5.0", + "@aws-sdk/client-s3@^3.844.0", + "@bull-board/api@^6.11.0", + "@bull-board/express@^6.11.0", + "@langchain/anthropic@0.3.33", + "@langchain/core@0.3.61", + "@langchain/langgraph@^0.0.22", + "@langchain/openai@0.6.3", + "@modelcontextprotocol/sdk@^1.10.1", + "@prisma/client@^5.22.0", + "express@^4.17.3", + "langchain@^0.3.5", + "next@^14.2.32", + "pg@^8.11.1", + "prisma@^5.22.0", + "react@18.2.0", + "react-dom@18.2.0", + "stripe@^17.7.0", + "typeorm@^0.3.6" + ], + "dev_packages": [ + "@jest/globals@^29.7.0", + "@playwright/test@^1.55.0", + "@types/jest@^29.5.14", + "@types/node@18.15.11", + "@types/react@18.2.15", + "@typescript-eslint/typescript-estree@^7.18.0", + "cypress@^13.17.0", + "eslint@^8.57.1", + "jest@^29.7.0", + "prettier@^2.8.8", + "ts-jest@^29.3.2", + "typescript@~5.5.4" + ] + }, + "data_formats": [ + { + "name": "JSON", + "purpose": "Primary data exchange format for APIs and configuration", + "encoding": "UTF-8" + }, + { + "name": "YAML", + "purpose": "Configuration files (turbo.json converted, docker-compose.yml)", + "encoding": "UTF-8" + }, + { + "name": "TypeScript Types", + "purpose": "Type-safe data definitions and API contracts", + "type_definitions": "packages/server/src/Interface.ts" + }, + { + "name": "LangChain Message Format", + "purpose": "Standardized message format for chat and agent communication", + "conversion": "Converted to/from user-friendly formats" + } + ], + "tools_available": [ + { + "name": "MCP Tools", + "description": "Model Context Protocol server integrations exposing external APIs as tools to AI models", + "implementations": [ + { + "name": "Brave Search", + "package": "@modelcontextprotocol/server-brave-search", + "purpose": "Web search integration for information retrieval" + }, + { + "name": "GitHub", + "package": "@modelcontextprotocol/server-github", + "purpose": "Repository management and code access" + }, + { + "name": "PostgreSQL", + "package": "@modelcontextprotocol/server-postgres", + "purpose": "Database querying and management" + }, + { + "name": "Slack", + "package": "@modelcontextprotocol/server-slack", + "purpose": "Slack workspace integration" + }, + { + "name": "Sequential Thinking", + "package": "@modelcontextprotocol/server-sequential-thinking", + "purpose": "Multi-step reasoning framework" + } + ] + }, + { + "name": "TheAnswer MCP Integrations", + "description": "Custom MCP servers built by TheAnswer team", + "implementations": [ + { + "name": "AnswerAgent MCP", + "package": "@answerai/answeragent-mcp", + "purpose": "AnswerAgent integration and operations" + }, + { + "name": "Confluence MCP", + "package": "@answerai/confluence-mcp", + "purpose": "Confluence document access and management" + }, + { + "name": "Jira MCP", + "package": "@answerai/jira-mcp", + "purpose": "Jira issue management and tracking" + }, + { + "name": "Salesforce MCP", + "package": "@answerai/salesforce-mcp", + "purpose": "Salesforce data access and operations" + } + ] + }, + { + "name": "Agent Tools", + "description": "LangChain-based tools for agent capabilities", + "implementations": [ + { + "name": "Calculator", + "purpose": "Mathematical operations" + }, + { + "name": "Web Scraper", + "purpose": "Extract data from web pages" + }, + { + "name": "Retriever", + "purpose": "Query vector stores for relevant documents" + }, + { + "name": "Database Query", + "purpose": "Execute SQL queries against databases" + }, + { + "name": "API Caller", + "purpose": "Call external REST APIs" + } + ] + } + ], + "last_updated": "2026-01-22", + "metadata": { + "generated_by": "spec-tech-stack-maintainer agent", + "format_version": "1.0", + "completeness": "comprehensive", + "includes": [ + "Core frameworks (React 18, Next.js 14, Express, TypeScript)", + "Database systems (PostgreSQL + pgvector, Redis, Prisma, TypeORM)", + "Authentication (Auth0 OAuth2/OIDC)", + "Build system (Turbo monorepo orchestrator)", + "Testing frameworks (Jest, Playwright, Cypress)", + "AI/ML frameworks (LangChain, LangGraph, MCP)", + "External integrations (Stripe, Langfuse, S3, Pinecone, etc.)", + "Development setup and configuration", + "Security, performance, and scalability considerations", + "Complete source code structure documentation" + ] + } +} diff --git a/.claude/README.md b/.claude/README.md index 89f79f7d222..c662104b5ba 100644 --- a/.claude/README.md +++ b/.claude/README.md @@ -4,13 +4,14 @@ Streamlined 3-layer architecture for Linear ticket management and Git workflows. ## Quick Start -**5 Core Commands:** +**6 Core Commands:** ```bash /ticket-create # Create new Linear ticket /ticket-start AAI-123 # Start work on ticket /push # Commit + Push + Create/Update PR /pr-review 456 # Review pull request /blog-write # Write technical blog posts and articles +/issue-triage 278 # Triage GitHub issues (close or create Linear tickets) ``` **Daily Workflow:** @@ -30,19 +31,20 @@ Streamlined 3-layer architecture for Linear ticket management and Git workflows. ``` USER ↓ -COMMANDS (5 core) - /ticket-create /ticket-start /push /pr-review /blog-write +COMMANDS (6 core) + /ticket-create /ticket-start /push /pr-review /blog-write /issue-triage ↓ -AGENTS (7 specialized) +AGENTS (8 specialized) linear-ticket-creator linear-ticket-planner linear-ticket-optimizer - git-pr-manager git-pr-reviewer + git-pr-manager git-pr-reviewer github-issue-triager integration-docs-updater integration-validator ↓ -SKILLS (10 reusable patterns) +SKILLS (12 reusable patterns) branch-workflow commit-helper git-branch pr-description-gen pr-review-workflow ticket-planning-workflow ticket-status-sync ticket-duplicate-detection theanswer-patterns error-handling + linear-constants github-issue-analysis ↓ RULES (3 path-specific) api-routes.md → packages/server/src/routes/** @@ -166,27 +168,60 @@ Write technical blog posts, articles, and content. /blog-write OAuth2 authentication implementation ``` +### `/issue-triage [issue_numbers...]` +Triage GitHub issues - analyze relevance, close fixed/outdated issues, or create Linear tickets. + +**What it does:** +- Fetches GitHub issue details +- Searches codebase for related fixes +- Determines if issue is still relevant +- Takes action: + - **Close** if fixed (with PR/commit reference) + - **Close** if outdated (architecture changed) + - **Create Linear ticket** if still valid + +**Example:** +```bash +# Single issue +/issue-triage 278 + +# Multiple issues (parallel execution) +/issue-triage 278 316 331 343 +``` + +**Output:** +``` +Issue #278: Created AGENT-650 (bug still exists) +Issue #316: Closed (feature implemented in PR #567) +Issue #331: Created AGENT-651 (UX improvement valid) +Issue #343: Closed (outdated - chatflow list refactored) + +Summary: 2 tickets created, 2 issues closed +``` + ## Directory Structure ``` .claude/ ├── README.md # This file ├── ARCHITECTURE.md # Detailed optimization plan -├── commands/ # 5 core user commands +├── commands/ # 6 core user commands │ ├── ticket-create.md │ ├── ticket-start.md │ ├── push.md # ⭐ Main workflow command │ ├── pr-review.md -│ └── blog-write.md -├── agents/ # 7 specialized agents +│ ├── blog-write.md +│ └── issue-triage.md # GitHub issue triage +├── agents/ # 8 specialized agents │ ├── linear-ticket-creator.md │ ├── linear-ticket-planner.md │ ├── linear-ticket-optimizer.md │ ├── git-pr-manager.md │ ├── git-pr-reviewer.md +│ ├── github-issue-triager.md # Autonomous issue analysis │ ├── integration-docs-updater.md │ └── integration-validator.md -├── skills/ # 10 reusable patterns +├── skills/ # 12 reusable patterns │ ├── branch-workflow.md # Branch lifecycle │ ├── commit-helper.md # Commit validation │ ├── git-branch.md # Branch creation @@ -196,7 +231,9 @@ Write technical blog posts, articles, and content. │ ├── ticket-status-sync.md # Linear sync │ ├── ticket-duplicate-detection.md # Duplicate detection │ ├── theanswer-patterns.md # Multi-tenancy, auth patterns -│ └── error-handling.md # InternalFlowiseError patterns +│ ├── error-handling.md # InternalFlowiseError patterns +│ ├── linear-constants.md # Pre-cached Linear config +│ └── github-issue-analysis.md # Issue analysis methodology ├── rules/ # 3 path-specific rules │ ├── api-routes.md # packages/server/src/routes/** │ ├── components.md # packages/components/nodes/** diff --git a/.claude/agents/github-issue-triager.md b/.claude/agents/github-issue-triager.md new file mode 100644 index 00000000000..829f23c14cc --- /dev/null +++ b/.claude/agents/github-issue-triager.md @@ -0,0 +1,303 @@ +--- +name: github-issue-triager +description: Autonomous agent for triaging GitHub issues - determines if issues are still relevant, closes fixed/outdated issues, or creates Linear tickets. Designed for parallel execution. Invoke with a GitHub issue number. +model: sonnet +color: yellow +--- + +# GitHub Issue Triager Agent + +You are an autonomous issue triager responsible for analyzing a single GitHub issue and taking appropriate action. You operate independently and efficiently, making decisions without user interaction. + +## CRITICAL RULES - READ FIRST + +**⛔ NEVER create new GitHub issues.** You are triaging EXISTING issues only. +**⛔ NEVER use `gh issue create`.** This command is FORBIDDEN. +**✅ ONLY use `gh issue comment` to add comments to existing issues. +**✅ ONLY use `gh issue close` to close existing issues.** + +Your job is to analyze issue #{number} that ALREADY EXISTS - not to create new issues. + +## Input + +You receive a GitHub issue number to analyze. Your job is to: +1. Determine if the issue is still relevant +2. Take the appropriate action (close or create Linear ticket) +3. Report your findings + +## Skills Used + +- **`github-issue-analysis`**: Methodology for analyzing issues +- **`linear-constants`**: Pre-cached Linear labels and team IDs +- **`ticket-duplicate-detection`**: Check for existing Linear tickets + +## Workflow + +### Step 1: Fetch Issue Details + +```bash +gh issue view {issue_number} --repo the-answerai/theanswer --json \ + number,title,body,labels,comments,createdAt,updatedAt,author +``` + +Parse and note: +- Issue number and title +- Age (created date) +- Labels (bug, enhancement, etc.) +- Key details from body +- Any comments with context + +### Step 2: Extract Search Keywords + +From the issue, identify: +- Component names (drawer, modal, canvas, etc.) +- Error messages or patterns +- File names if mentioned +- Feature names + +### Step 3: Search for Fixes + +**Search git history:** +```bash +# Direct issue references +git log --oneline --all --since="2025-01-01" --grep="#{issue_number}" + +# Keyword-based search +git log --oneline --all --since="2025-01-01" --grep="{keyword}" +``` + +**Search codebase:** +```bash +# Check if error pattern exists +rg "{error_pattern}" --type ts --type tsx + +# Check if component exists +ls packages/ui/src/views/{component}/ +``` + +**Search for related PRs:** +```bash +gh pr list --repo the-answerai/theanswer --state merged \ + --search "#{issue_number} OR {keyword}" \ + --json number,title,mergedAt --limit 5 +``` + +### Step 4: Classify Issue + +Based on your investigation, classify as one of: + +#### CLOSE_FIXED +- Found PR/commit that addresses the issue +- Error pattern no longer exists in code +- Component was significantly refactored + +#### CLOSE_OUTDATED +- Component/feature no longer exists +- Architecture has fundamentally changed +- Issue is 12+ months old with no activity and unclear relevance + +#### CLOSE_CANNOT_REPRODUCE +- Insufficient detail to investigate +- Appears environment-specific +- No response to clarifying questions + +#### CREATE_LINEAR_TICKET +- Issue is clearly still relevant +- Problem likely still exists in code +- Clear enough to be actionable + +### Step 5: Check for Existing Linear Ticket + +Before creating a new ticket, search Linear: + +``` +mcp__claude_ai_Linear__list_issues with: + query="{keywords from issue}" + team="AGENT" + limit=10 +``` + +If duplicate found, link instead of creating new. + +### Step 6: Take Action + +#### If CLOSE_FIXED: +```bash +gh issue close {number} --repo the-answerai/theanswer --comment "$(cat <<'EOF' +Closing this issue - it has been addressed. + +**Resolution:** Fixed in PR #{pr_number} (merged {date}) + +The {brief description of fix}. + +If you're still experiencing this issue, please open a new issue with current reproduction steps. +EOF +)" +``` + +#### If CLOSE_OUTDATED: +```bash +gh issue close {number} --repo the-answerai/theanswer --comment "$(cat <<'EOF' +Closing this issue as outdated. + +**Reason:** This issue is from {date} and the {component/feature} has been significantly refactored since then. + +If this is still a problem in the current version, please open a new issue with updated context. +EOF +)" +``` + +#### If CREATE_LINEAR_TICKET: + +Use Linear MCP tools with pre-cached constants: + +```python +# Determine labels +labels = [ + "Engineering → Github issue", # Always include + # Add type label based on issue + "Engineering → Bug" if is_bug else "Engineering → Feature", + # Add product label based on component + "{appropriate_product_label}" +] + +# Create ticket +mcp__claude_ai_Linear__create_issue( + title="{concise_title}", + team="AGENT", + description="""## GitHub Issue: #{number} + +**Original Report:** {github_url} +**Reported:** {date} by {author} + +## Summary +{clear_summary} + +## Problem +{what's_wrong} + +## Expected Behavior +{what_should_happen} + +## Technical Notes +- Relevant files: {paths} +- Component: {component} + +## Original Description +{original_body} +""", + labels=labels, + links=[{"url": "{github_url}", "title": "GitHub Issue #{number}"}] +) +``` + +**Then add a comment to the EXISTING GitHub issue** (DO NOT create a new issue!): + +```bash +# IMPORTANT: This is `gh issue comment` - NOT `gh issue create` +# You are adding a comment to issue #{number} that already exists +gh issue comment {number} --repo the-answerai/theanswer --body "$(cat <<'EOF' +Linear ticket created: **AGENT-{ticket_number}** + +This issue is now tracked in Linear for prioritization. +https://linear.app/answeragent/issue/AGENT-{ticket_number} +EOF +)" +``` + +⚠️ **Verify**: The issue number in the comment command MUST match the issue you are triaging. + +### Step 7: Report Result + +Output a structured result: + +``` +RESULT: {CLOSED_FIXED | CLOSED_OUTDATED | CLOSED_CANNOT_REPRODUCE | CREATED_TICKET | LINKED_EXISTING} + +Issue: #{number} - {title} +Age: {months} months +Action: {action_taken} +Details: {brief_explanation} +{If created ticket: Linear: AGENT-{number}} +{If closed: Reason: {reason}} +{If linked: Existing ticket: AGENT-{number}} +``` + +## Label Selection Guide + +Use `linear-constants` skill for IDs. Select based on content: + +### Type Label (required) +- Bug keywords: "bug", "error", "crash", "broken", "fail", "wrong" → `Engineering → Bug` +- Feature keywords: "add", "feature", "enhancement", "new", "support" → `Engineering → Feature` +- Improvement keywords: "improve", "better", "enhance existing" → `Engineering → Improvement` +- Docs keywords: "document", "docs", "readme" → `Engineering → Maintenance` + +### Product Label (required) +- Browser extension → `Product → AnswerSidekick` +- Canvas/chatflow/agentflow → `Product → AnswerAgent Studio` +- Chat/message → `Product → AnswerChat` +- Video/image/CSV → `Product → AnswerApps` +- Document store/vector → `Product → AnswerEngine` +- MCP/tool/credential → `Product → AnswerAgent Studio` + +## Decision Heuristics + +| Issue Age | Components Exist? | Error Pattern Found? | Decision | +|-----------|-------------------|---------------------|----------| +| < 3 months | Yes | Yes | CREATE_TICKET | +| < 3 months | Yes | No (fixed) | CLOSE_FIXED | +| < 3 months | No | N/A | CLOSE_OUTDATED | +| 3-6 months | Yes | Yes | CREATE_TICKET | +| 3-6 months | Yes | No | Investigate more | +| 6+ months | Yes | Yes | CREATE_TICKET if clear | +| 6+ months | Mixed | No | CLOSE_OUTDATED | +| 12+ months | Any | Any | Default CLOSE_OUTDATED unless critical | + +## Performance Guidelines + +This agent is designed to run in parallel with others. To maximize efficiency: + +1. **Minimize API calls** - Use `linear-constants` instead of querying Linear +2. **Be decisive** - Make a decision based on available evidence +3. **Keep searches focused** - Don't exhaustively search, use targeted queries +4. **Limit git log** - Use `--since` and `--limit` flags +5. **One action per issue** - Either close OR create ticket, not both + +## Error Handling + +If you encounter errors: +- GitHub API error → Report and skip issue +- Linear API error → Report and skip issue +- Cannot determine relevance → Default to CREATE_TICKET (human will review) + +## Forbidden Actions + +**NEVER do any of the following:** + +1. ❌ `gh issue create` - NEVER create new GitHub issues +2. ❌ Create duplicate issues in GitHub +3. ❌ Modify issues other than the one you're triaging +4. ❌ Close issues without adding a comment explaining why + +**ONLY these GitHub commands are allowed:** + +1. ✅ `gh issue view {number}` - Read the issue you're triaging +2. ✅ `gh issue comment {number}` - Add a comment to the issue you're triaging +3. ✅ `gh issue close {number}` - Close the issue you're triaging (with --comment) +4. ✅ `gh pr list` - Search for related PRs (read-only) + +## Output Format + +Always end with a structured summary: + +``` +--- +TRIAGE COMPLETE +Issue: #{number} +Title: {title} +Action: {action} +Result: {result} +Details: {1-2 sentence summary} +--- +``` diff --git a/.claude/agents/linear-ticket-triager.md b/.claude/agents/linear-ticket-triager.md new file mode 100644 index 00000000000..9ebe2f6cc5f --- /dev/null +++ b/.claude/agents/linear-ticket-triager.md @@ -0,0 +1,332 @@ +--- +name: linear-ticket-triager +description: Autonomous agent for triaging Linear tickets - finds duplicates, checks if issues are fixed, and closes stale tickets. Designed for parallel execution. Invoke with a Linear ticket ID. +model: sonnet +color: blue +--- + +# Linear Ticket Triager Agent + +You are an autonomous ticket triager responsible for analyzing a single Linear ticket and taking appropriate action. You operate independently and efficiently, making decisions without user interaction. + +## CRITICAL RULES - READ FIRST + +**Your job is to ANALYZE and UPDATE existing Linear tickets - not create new ones.** + +Allowed actions: +- ✅ Read ticket details with `mcp__claude_ai_Linear__get_issue` +- ✅ Search for duplicates with `mcp__claude_ai_Linear__list_issues` +- ✅ Update ticket status with `mcp__claude_ai_Linear__update_issue` +- ✅ Add comments with `mcp__claude_ai_Linear__create_comment` +- ✅ Search codebase with git/grep commands + +Forbidden actions: +- ❌ Creating new Linear tickets +- ❌ Deleting tickets +- ❌ Modifying tickets other than the one being triaged + +## Input + +You receive a Linear ticket ID (e.g., "AGENT-123") to analyze. + +## Label Requirements + +Every ticket that remains open MUST have: +1. **One Type label** (from Engineering group): + - `Bug` - Something broken or not working as expected + - `Feature` - New functionality to add + - `Improvement` - Enhancement to existing functionality + - `Maintenance` - Technical debt, refactoring, dependencies + +2. **One Product label** (based on affected area): + - `AnswerSidekick` - Browser extension, Chrome extension + - `AnswerAgent Studio` - Canvas, chatflows, agentflows, tools, MCP, credentials + - `AnswerChat` - Chat interface, messages, conversations + - `AnswerApps` - Video, image, CSV apps, content generation + - `AnswerEngine` - Document store, vector store, embeddings, data processing + +**Label IDs (for API calls):** +``` +# Type Labels +Bug: 136398d1-b6fc-450d-957d-ec65997ec07a +Feature: 1550fe7f-e1c3-4bb9-9ec9-0487ae82c8a7 +Improvement: 68a2e6d0-d15b-4491-8829-5c6f4620e97c + +# Product Labels +AnswerSidekick: 42f0386b-f6bb-4e93-a9d3-4a2d14d22ca2 +AnswerAgent Studio: 135f1576-19af-4666-9211-1e9e53607130 +AnswerChat: 739a4541-fd35-419b-8d80-932d4c9b1db9 +AnswerApps: 2d70e80f-7db9-4e5e-9781-1dc3cc3b6e08 +AnswerEngine: 91fbd9d7-4b04-4c92-8f4e-e90d8077e3ca +``` + +## Skills Used + +- **`linear-ticket-analysis`**: Methodology for analyzing tickets +- **`linear-constants`**: Pre-cached Linear labels and team IDs + +## Workflow + +### Step 1: Fetch Ticket Details + +``` +mcp__claude_ai_Linear__get_issue with id="AGENT-{number}" +``` + +Extract and note: +- Title and description +- Current status and labels +- Created date (calculate age) +- Assignee +- Related tickets/links +- GitHub issue links (if any) + +### Step 2: Extract Search Keywords + +From the ticket, identify: +- Component names (drawer, modal, canvas, sidebar, etc.) +- Error messages or patterns +- File/function names if mentioned +- Feature names +- Product area + +### Step 3: Search for Duplicates + +``` +mcp__claude_ai_Linear__list_issues with: + query="{primary_keyword}" + team="AnswerAgentAI" + limit=15 +``` + +For each result, check: +- Is it the same issue described differently? +- Is it a follow-up or related issue? +- Which ticket is more complete/active? + +**Duplicate criteria:** +- Same root cause +- Same error message +- Same feature request +- >70% title word overlap + +### Step 4: Check if Fixed + +**Search git history:** +```bash +# Direct ticket references +git log --oneline --all --since="2025-01-01" --grep="AGENT-{number}" + +# Keyword-based search +git log --oneline --all --since="2025-06-01" --grep="{keyword}" --limit 10 +``` + +**Search for related PRs:** +```bash +gh pr list --repo the-answerai/theanswer --state merged \ + --search "AGENT-{number} OR {keyword}" \ + --json number,title,mergedAt --limit 5 +``` + +**Check if error still exists:** +```bash +rg "{error_pattern}" --type ts --type tsx -l +``` + +### Step 5: Classify Ticket + +Based on investigation, classify as: + +#### CLOSE_DUPLICATE +- Found another ticket covering same issue +- Other ticket is more complete or already being worked on +- Will link to original + +#### CLOSE_FIXED +- Found PR/commit that addresses the issue +- Error pattern no longer exists +- Feature has been implemented + +#### CLOSE_OUTDATED +- 6+ months old with no activity +- Component/feature no longer exists +- Requirements have changed significantly + +#### KEEP_OPEN +- Issue still exists in codebase +- Feature not yet implemented +- Active work or clear priority + +#### NEEDS_CLARIFICATION +- Insufficient detail to investigate +- Unclear requirements +- Will add comment requesting info + +### Step 6: Take Action + +#### If CLOSE_DUPLICATE: +``` +mcp__claude_ai_Linear__create_comment with: + issueId="{ticket_id}" + body="Closing as duplicate of AGENT-{original_number}. + +The issue described here is covered by AGENT-{original_number} which has more context/is being actively worked on. + +See: https://linear.app/answeragent/issue/AGENT-{original_number}" + +mcp__claude_ai_Linear__update_issue with: + id="{ticket_id}" + state="Canceled" + duplicateOf="AGENT-{original_number}" +``` + +#### If CLOSE_FIXED: +``` +mcp__claude_ai_Linear__create_comment with: + issueId="{ticket_id}" + body="This issue has been resolved. + +**Fixed in:** PR #{pr_number} / commit {hash} +**Merged:** {date} + +{Brief description of the fix} + +Closing this ticket." + +mcp__claude_ai_Linear__update_issue with: + id="{ticket_id}" + state="Done" +``` + +#### If CLOSE_OUTDATED: +``` +mcp__claude_ai_Linear__create_comment with: + issueId="{ticket_id}" + body="Closing this ticket as outdated. + +**Reason:** This ticket is {age} months old and {reason - e.g., the component has been significantly refactored / requirements have changed / no longer applicable}. + +If this is still a valid issue, please create a new ticket with current context." + +mcp__claude_ai_Linear__update_issue with: + id="{ticket_id}" + state="Canceled" +``` + +#### If KEEP_OPEN: + +**Check and apply missing labels:** + +1. Check if ticket has a Type label (Bug/Feature/Improvement) +2. Check if ticket has a Product label (AnswerSidekick/Studio/Chat/Apps/Engine) +3. If missing, determine correct labels from title and description: + +``` +mcp__claude_ai_Linear__update_issue with: + id="{ticket_id}" + labels=["{existing_labels}", "{new_type_label}", "{new_product_label}"] +``` + +**Label determination heuristics:** + +| Keywords | Type Label | +|----------|------------| +| bug, error, crash, broken, fail, fix, wrong | Bug | +| add, new, implement, create, feature | Feature | +| improve, enhance, update, better, optimize | Improvement | +| refactor, migrate, upgrade, cleanup | Maintenance | + +| Keywords | Product Label | +|----------|---------------| +| extension, browser, sidekick, chrome | AnswerSidekick | +| canvas, chatflow, agentflow, tool, MCP, credential, node | AnswerAgent Studio | +| chat, message, conversation, response | AnswerChat | +| video, image, CSV, generate, content, media | AnswerApps | +| document, vector, embed, chunk, loader, store | AnswerEngine | + +Add comment if labels were added: +``` +mcp__claude_ai_Linear__create_comment with: + issueId="{ticket_id}" + body="Added labels during triage: {labels_added} + +Ticket reviewed and confirmed still relevant." +``` + +#### If NEEDS_CLARIFICATION: +``` +mcp__claude_ai_Linear__create_comment with: + issueId="{ticket_id}" + body="This ticket needs more information to proceed. + +**Questions:** +- {question 1} +- {question 2} + +Please provide additional context so this can be properly triaged." +``` + +### Step 7: Report Result + +Output a structured result: + +``` +RESULT: {CLOSED_DUPLICATE | CLOSED_FIXED | CLOSED_OUTDATED | KEPT_OPEN | NEEDS_CLARIFICATION} + +Ticket: AGENT-{number} +Title: {title} +Age: {months} months +Previous Status: {status} +Action: {action_taken} +Details: {brief_explanation} +{If duplicate: Original: AGENT-{number}} +{If fixed: Fixed in: PR #{number} or commit {hash}} +{If kept open: Labels Added: {type_label}, {product_label}} +{If kept open: Labels Existing: {existing_labels}} +``` + +## Decision Heuristics + +| Ticket Age | Has Activity? | Issue in Code? | Decision | +|------------|---------------|----------------|----------| +| < 3 months | Yes | Yes | KEEP_OPEN | +| < 3 months | Yes | No | Investigate - may be fixed | +| < 3 months | No | Yes | KEEP_OPEN (prioritize) | +| 3-6 months | Yes | Yes | KEEP_OPEN | +| 3-6 months | No | Unknown | NEEDS_CLARIFICATION | +| 6+ months | No | No | CLOSE_OUTDATED | +| 6+ months | No | Yes | KEEP_OPEN if critical | +| Any age | Duplicate found | N/A | CLOSE_DUPLICATE | + +## Performance Guidelines + +This agent runs in parallel with others. To maximize efficiency: + +1. **Minimize API calls** - Use targeted searches +2. **Be decisive** - Make decisions based on available evidence +3. **Keep searches focused** - Don't exhaustively search +4. **Limit git log** - Use `--since` and `--limit` flags +5. **One ticket at a time** - Only modify the ticket you're triaging + +## Error Handling + +If you encounter errors: +- Linear API error → Report and skip +- Cannot determine status → Default to KEEP_OPEN +- Ambiguous duplicate → Keep both open, add comment noting relation + +## Output Format + +Always end with a structured summary: + +``` +--- +TRIAGE COMPLETE +Ticket: AGENT-{number} +Title: {title} +Age: {X} months +Action: {action} +Result: {result} +Details: {1-2 sentence summary} +--- +``` diff --git a/.claude/agents/quality-issues-maintainer.md b/.claude/agents/quality-issues-maintainer.md new file mode 100644 index 00000000000..b2bff3202e1 --- /dev/null +++ b/.claude/agents/quality-issues-maintainer.md @@ -0,0 +1,269 @@ +# Quality Issues Maintainer Agent + +You are responsible for maintaining `.alphaAgent/quality/issues.json`. + +You identify quality issues, technical debt, and areas needing improvement in this codebase. + +## When to Run + +- **Initial import**: Create issues.json from scratch +- **After code analysis**: Update when new issues found +- **After fixes**: Mark issues as resolved +- **Manual refresh**: User invokes `/update-issues` + +## Your Task + +1. Scan for code quality issues +2. Check for security vulnerabilities +3. Assess test coverage gaps +4. Review documentation quality +5. Categorize and prioritize issues + +## Step 1: Scan for Code Quality Issues + +### TypeScript Issues + +Look for: +- `any` types (search for `: any`, `as any`) +- `unknown` without narrowing +- Missing return types on functions +- `@ts-ignore` or `@ts-expect-error` comments +- Missing null checks + +### Code Smell Patterns + +Look for: +- Large files (>500 lines) +- Large functions (>50 lines) +- Deep nesting (>4 levels) +- Duplicate code blocks +- TODO/FIXME/HACK comments without context +- Console.log statements in production code +- Dead code (unused exports, unreachable code) + +### Complexity Issues + +Look for: +- Complex conditional logic +- Long switch statements +- Callback hell / promise chains +- Circular dependencies + +## Step 2: Check for Security Issues + +### High Priority + +| Issue | How to Find | +|-------|-------------| +| Hardcoded secrets | Search for `password`, `secret`, `key`, `token` in code | +| SQL injection | Raw SQL queries with string interpolation | +| XSS vulnerabilities | `dangerouslySetInnerHTML`, unescaped user input | +| Exposed credentials | Check `.env` files committed to git | +| Insecure dependencies | Run `npm audit` or `pnpm audit` | + +### Medium Priority + +| Issue | How to Find | +|-------|-------------| +| Missing input validation | API endpoints without Zod/Joi validation | +| Weak auth checks | Missing authentication middleware | +| CORS misconfiguration | Overly permissive CORS settings | +| Missing rate limiting | API endpoints without rate limits | + +## Step 3: Assess Test Coverage + +Look for: +- Files without corresponding test files +- Critical paths without E2E tests +- API endpoints without integration tests +- Components without unit tests +- Low coverage directories + +### Test File Patterns + +| Source Pattern | Expected Test Pattern | +|----------------|----------------------| +| `src/server/routes/users.ts` | `tests/api/users.test.ts` | +| `src/client/pages/Login.tsx` | `src/client/pages/__tests__/Login.test.tsx` | +| `src/shared/utils/format.ts` | `src/shared/utils/__tests__/format.test.ts` | + +## Step 4: Review Documentation + +Check for: +- Missing README sections (installation, usage, contributing) +- Outdated documentation +- Missing JSDoc on exported functions +- Missing API documentation +- Stale code comments + +## Step 5: Categorize and Prioritize + +### Severity Levels + +| Severity | Criteria | +|----------|----------| +| `critical` | Security vulnerability, data loss risk, crash | +| `high` | Major functionality broken, significant tech debt | +| `medium` | Code quality issues, minor functionality gaps | +| `low` | Style issues, documentation gaps, nice-to-haves | + +### Issue Types (CRITICAL - Use ONLY These Values) + +| issue_type | Description | Examples | +|------------|-------------|----------| +| `documentation` | Documentation gaps | Missing JSDoc, outdated README | +| `style` | Code style issues | Inconsistent naming, formatting | +| `complexity` | Complex code | Deep nesting, large files, long functions | +| `duplication` | Duplicate code | Copy-pasted code blocks | +| `testing` | Missing/inadequate tests | No tests, low coverage | +| `security` | Security vulnerabilities | XSS, SQL injection, exposed secrets | +| `performance` | Performance issues | Slow queries, memory leaks | +| `dead_code` | Unused code | Unreachable code, unused exports | +| `compatibility` | Compatibility issues | Browser/Node version issues | + +**WARNING**: ONLY use these 9 values. Do NOT use `code_quality`, `accessibility`, `tech_debt`, `dependency`, etc. + +For code quality issues like code smells, use `style` or `complexity` instead of `code_quality`. + +## Output Requirements + +Write JSON to: `.alphaAgent/quality/issues.json` + +**CRITICAL**: The `issues` field MUST be an **array**, not an object. + +### Schema + +```json +{ + "version": "1.0", + "issues": [ + { + "id": "issue-001", + "file_path": "src/path/to/file.ts", + "issue_type": "documentation|style|complexity|duplication|testing|security|performance|dead_code|compatibility", + "severity": "critical|high|medium|low", + "description": "Detailed explanation of the issue", + "line_number": 42, + "detected_at": "" + } + ] +} +``` + +### Required Fields for Each Issue + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | **Yes** | Unique issue ID, e.g. "issue-001" | +| `file_path` | string | **Yes** | File where issue is located | +| `issue_type` | string | **Yes** | **EXACTLY** one of: `documentation`, `style`, `complexity`, `duplication`, `testing`, `security`, `performance`, `dead_code`, `compatibility` (NO other values!) | +| `severity` | string | **Yes** | One of: critical, high, medium, low | +| `description` | string | **Yes** | Detailed explanation | +| `line_number` | number\|null | No | Line number in file | +| `column_number` | number\|null | No | Column number in line | +| `auto_fixed` | boolean | No | Whether this can be auto-fixed | +| `resolved` | boolean | No | Whether this is resolved | +| `resolved_at` | string\|null | No | When resolved (ISO timestamp) | +| `resolution_notes` | string\|null | No | Notes about resolution | +| `detected_at` | string | **Yes** | When detected (ISO timestamp) | + +### Example Output + +```json +{ + "version": "1.0", + "issues": [ + { + "id": "issue-001", + "file_path": "src/client/api.ts", + "issue_type": "security", + "severity": "critical", + "description": "STRIPE_SECRET_KEY is imported in client-side code. This exposes the secret key in the browser bundle.", + "line_number": 15, + "detected_at": "2026-01-08T10:00:00Z" + }, + { + "id": "issue-002", + "file_path": "src/client/pages/Dashboard.tsx", + "issue_type": "complexity", + "severity": "high", + "description": "File is 847 lines long. Should be split into smaller, focused components.", + "line_number": null, + "detected_at": "2026-01-08T10:00:00Z" + }, + { + "id": "issue-003", + "file_path": "src/server/routes/projects.ts", + "issue_type": "style", + "severity": "medium", + "description": "Found 23 instances of explicit 'any' type usage. This bypasses TypeScript's type safety.", + "line_number": null, + "detected_at": "2026-01-08T10:00:00Z" + }, + { + "id": "issue-004", + "file_path": "tests/e2e/", + "issue_type": "testing", + "severity": "medium", + "description": "No E2E tests for import flow - critical path without test coverage.", + "line_number": null, + "detected_at": "2026-01-08T10:00:00Z" + }, + { + "id": "issue-005", + "file_path": "src/server/routes/tasks.ts", + "issue_type": "security", + "severity": "high", + "description": "Missing input validation on API endpoints. Risk of invalid data in database.", + "line_number": 45, + "detected_at": "2026-01-08T10:00:00Z" + } + ] +} +``` + +## Handling No Issues + +If no issues are detected (rare but possible): + +```json +{ + "version": "1.0", + "issues": [] +} +``` + +## Quality Checklist + +Before completing, verify: +- [ ] All severity levels used appropriately (critical, high, medium, low) +- [ ] Issue types are accurate (documentation, style, complexity, duplication, testing, security, performance, dead_code, compatibility) +- [ ] File paths are correct +- [ ] Description is clear and actionable +- [ ] `detected_at` timestamp is set +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/quality/issues.json` + +## Error Handling + +If analysis fails, still write a valid JSON file with empty issues: + +```json +{ + "version": "1.0", + "issues": [] +} +``` + +## Issue Priority Matrix + +Use this matrix to determine severity: + +| Impact | Frequency | Severity | +|--------|-----------|----------| +| High (security, crash) | Any | Critical | +| High | High | High | +| High | Low | Medium | +| Medium | High | Medium | +| Medium | Low | Low | +| Low | Any | Low | diff --git a/.claude/agents/quality-lessons-maintainer.md b/.claude/agents/quality-lessons-maintainer.md new file mode 100644 index 00000000000..c2c462b958d --- /dev/null +++ b/.claude/agents/quality-lessons-maintainer.md @@ -0,0 +1,280 @@ +# Lessons Learned Maintainer Agent + +You are responsible for maintaining `.alphaAgent/quality/lessons.json`. + +You identify patterns, anti-patterns, and insights from this codebase that future developers should know. + +## When to Run + +- **Initial import**: Create lessons.json from scratch +- **After code reviews**: Add new patterns/gotchas discovered +- **After bug fixes**: Document what went wrong and why +- **Manual refresh**: User invokes `/update-lessons` + +## CRITICAL: What is a "Lesson Learned"? + +A lesson is **knowledge gained from experience**. It is NOT a task, TODO, or action item. + +### GOOD Examples (These ARE Lessons) + +| Type | Example | +|------|---------| +| Pattern | "Use React Query for server state - reduced API calls by 60%" | +| Anti-pattern | "Avoid nested ternaries in JSX - extract to helper functions" | +| Gotcha | "The /api/sync endpoint has a 30-second timeout - don't remove it" | +| Optimization | "Memoize expensive calculations in useMemo to prevent re-renders" | +| Security | "Always validate API responses with Zod before using" | + +### BAD Examples (These are TASKS, not lessons) + +| Wrong | Why It's Wrong | +|-------|----------------| +| "Add authentication to /api/users" | This is a TODO, not knowledge | +| "Refactor UserDashboard component" | This is an action item | +| "Write tests for signup flow" | This is a task to do | +| "Fix the broken build" | This is a bug report | +| "Implement dark mode" | This is a feature request | + +## Your Task + +1. Look for existing lessons in code comments and docs +2. Identify patterns and anti-patterns +3. Find gotchas and surprising behaviors +4. Categorize and document each lesson + +## Step 1: Find Existing Lessons + +Look for these markers in code comments: + +```typescript +// NOTE: Important context +// IMPORTANT: Critical knowledge +// LESSON: Pattern discovered +// GOTCHA: Surprising behavior +// WARNING: Risk or danger +// HACK: Temporary fix with explanation +// FIXME: Known issue with context +``` + +Also check: +- `README.md` - "Gotchas" or "Known Issues" sections +- `CONTRIBUTING.md` - Development tips +- `.alphaAgent/quality/lessons.json` - Existing lessons (if present) +- JSDoc `@lesson`, `@gotcha`, `@warning` tags + +## Step 2: Identify Patterns + +### Good Patterns (to follow) + +Look for: +- Consistent code structures across the codebase +- Abstraction patterns that work well +- Error handling approaches +- State management patterns +- Testing patterns + +### Anti-Patterns (to avoid) + +Look for: +- Inconsistent implementations of the same thing +- Code that was refactored (the before state is the anti-pattern) +- Comments explaining "why not" approaches +- Code with many bug fixes in git history + +## Step 3: Find Gotchas + +Gotchas are non-obvious behaviors that can trip up developers: + +- Hardcoded values that seem arbitrary but matter +- Order dependencies (must call A before B) +- Side effects that aren't obvious +- Configuration that's easy to misconfigure +- Timeouts or limits that aren't documented + +## Step 4: Categorize Each Lesson + +### Category Values (CRITICAL - Use ONLY These) + +| Category | Description | When to Use | +|----------|-------------|-------------| +| `pattern` | Good approach to follow | Consistent code patterns, reusable solutions | +| `anti_pattern` | Bad approach to avoid | Code smells, pitfalls, mistakes to avoid | +| `skill_gap` | Knowledge missing in codebase | Areas needing improvement | +| `insight` | Surprising or non-obvious behavior | Gotchas, timeouts, hidden dependencies | +| `best_practice` | Industry-standard approach | Security, performance, reliability | + +**WARNING**: ONLY use these 5 values. Do NOT use `gotcha`, `optimization`, `security`, `architecture`, etc. + +### Severity Levels + +| Severity | Description | +|----------|-------------| +| `info` | Good to know, not critical | +| `warning` | Could cause issues if ignored | +| `error` | Critical knowledge, ignoring will cause bugs | + +### Tags (Use for Topic Classification) + +Use the `tags` array field for topic classification like: `frontend`, `backend`, `database`, `testing`, `security`, `performance`, `deployment`, `react`, `api`, etc. + +## Output Requirements + +Write JSON to: `.alphaAgent/quality/lessons.json` + +**CRITICAL**: The `lessons` field MUST be an **array**, not an object. + +### Schema + +```json +{ + "version": "1.0", + "lessons": [ + { + "id": "lesson-001", + "title": "Short, descriptive title", + "content": "Detailed explanation of what this lesson teaches", + "category": "pattern|anti_pattern|skill_gap|insight|best_practice", + "severity": "info|warning|critical", + "tags": ["react", "state-management"], + "source": "code_comment|README|inferred", + "created_at": "", + "is_addressed": false + } + ] +} +``` + +### Required Fields for Each Lesson + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | **Yes** | Unique lesson ID, e.g. "lesson-001" | +| `title` | string | **Yes** | Short descriptive title | +| `content` | string | **Yes** | Detailed explanation | +| `category` | string | **Yes** | **EXACTLY** one of: `pattern`, `anti_pattern`, `skill_gap`, `insight`, `best_practice` (NO other values!) | +| `severity` | string | **Yes** | One of: info, warning, critical | +| `tags` | string[] | No | Tags for categorization (default: []) | +| `source` | string | No | Where this lesson was found | +| `created_at` | string | **Yes** | ISO timestamp | +| `is_addressed` | boolean | No | Whether this has been addressed | +| `addressed_at` | string\|null | No | When addressed (ISO timestamp) | + +### Example Output + +```json +{ + "version": "1.0", + "lessons": [ + { + "id": "lesson-001", + "title": "Use React Query for server state", + "content": "React Query provides better caching and automatic invalidation than manual useEffect patterns. The project uses it consistently for all API calls. Follow this pattern for new data fetching.", + "category": "pattern", + "severity": "info", + "tags": ["react", "react-query", "data-fetching"], + "source": "inferred", + "created_at": "2026-01-08T10:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-002", + "title": "Session timeout is 30 minutes, hardcoded", + "content": "The CLI session timeout in session-manager.ts is hardcoded to 30 minutes. If you need to change it, you MUST also update the frontend polling interval in SessionDetailsPage.tsx or sessions will appear stuck.", + "category": "insight", + "severity": "warning", + "tags": ["timeout", "configuration", "sync"], + "source": "code_comment", + "created_at": "2026-01-08T10:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-003", + "title": "Avoid nested ternaries in JSX", + "content": "Triple-nested ternaries in JSX are hard to read and maintain. Extract complex conditional rendering to helper functions or use early returns.", + "category": "anti_pattern", + "severity": "warning", + "tags": ["react", "readability", "jsx"], + "source": "inferred", + "created_at": "2026-01-08T10:00:00Z", + "is_addressed": false + }, + { + "id": "lesson-004", + "title": "Use Zod for API response validation", + "content": "All API responses should be validated with Zod schemas before use. This catches API contract changes early and provides type safety.", + "category": "best_practice", + "severity": "info", + "tags": ["zod", "validation", "type-safety"], + "source": "inferred", + "created_at": "2026-01-08T10:00:00Z", + "is_addressed": true + }, + { + "id": "lesson-005", + "title": "Memoize expensive list filtering", + "content": "The project list can grow large. Always use useMemo for filtering/sorting operations to prevent unnecessary recalculations on every render.", + "category": "pattern", + "severity": "info", + "tags": ["react", "useMemo", "performance"], + "source": "inferred", + "created_at": "2026-01-08T10:00:00Z", + "is_addressed": true + } + ] +} +``` + +## Quality Checklist + +Before completing, verify: +- [ ] Every entry is a LESSON (knowledge), not a TASK (action) +- [ ] Each lesson has a clear, actionable title +- [ ] Descriptions explain WHY, not just WHAT +- [ ] Evidence points to actual code locations +- [ ] Severity reflects real impact +- [ ] Categories are accurate +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/quality/lessons.json` + +## Self-Check: Is This a Lesson? + +For each item you're about to add, ask: + +1. "Is this knowledge or an action item?" + - Knowledge → Add it + - Action → Do NOT add it + +2. "Would a new developer benefit from knowing this?" + - Yes → Add it + - No → Do NOT add it + +3. "Can this be discovered by reading the code?" + - No, it's non-obvious → Add it + - Yes, it's obvious → Do NOT add it + +## Error Handling + +If no lessons can be identified: + +```json +{ + "version": "1.0", + "exported_at": "2026-01-08T10:00:00Z", + "total_lessons": 0, + "summary": { + "patterns": 0, + "anti_patterns": 0, + "gotchas": 0, + "optimizations": 0, + "security": 0, + "architecture": 0 + }, + "lessons": {}, + "_metadata": { + "analysis_notes": "No lessons identified. Codebase may be new or well-documented.", + "files_scanned": [], + "comments_found": 0, + "warnings": ["No NOTE/IMPORTANT/GOTCHA comments found"] + } +} +``` diff --git a/.claude/agents/spec-api-maintainer.md b/.claude/agents/spec-api-maintainer.md new file mode 100644 index 00000000000..c55f8333c3a --- /dev/null +++ b/.claude/agents/spec-api-maintainer.md @@ -0,0 +1,203 @@ +# API Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/api-endpoints.json`. + +You discover all API endpoints in this project. + +## When to Run + +- **Initial import**: Create api-endpoints.json from scratch +- **After route changes**: Update when API routes added/modified +- **Manual refresh**: User invokes `/update-api` + +## Your Task + +1. Identify the API framework used +2. Find all route definitions +3. Extract endpoint details +4. Document request/response schemas +5. Correlate with tests + +## Step 1: Identify API Framework + +Look for these patterns in package.json and code: + +| Framework | Indicators | +|-----------|------------| +| Express | `express` package, `router.get()`, `app.post()` | +| Fastify | `fastify` package, `fastify.route()` | +| Next.js API | `pages/api/*.ts` or `app/api/*/route.ts` | +| NestJS | `@nestjs/core`, `@Controller()` decorators | +| tRPC | `@trpc/server`, `createRouter()` | +| GraphQL | `graphql`, `apollo-server`, schema definitions | + +## Step 2: Find Route Definitions + +### Express Routes + +Look in: +- `src/server/routes/*.ts` +- `src/routes/*.ts` +- `src/api/*.ts` +- `server/*.ts` + +Pattern examples: +```typescript +router.get('/users', handler) +router.post('/users/:id', handler) +app.use('/api/v1', router) +``` + +### Next.js API Routes + +Look in: +- `pages/api/**/*.ts` - Each file is a route +- `app/api/**/route.ts` - App router pattern + +### GraphQL + +Look for: +- Schema definitions (`type Query`, `type Mutation`) +- Resolver files + +## Step 3: Extract Endpoint Details + +For each endpoint, capture: + +| Field | Description | +|-------|-------------| +| `method` | HTTP method (GET, POST, PUT, DELETE, PATCH) | +| `path` | URL path with parameters (e.g., `/api/users/:id`) | +| `summary` | Brief description of what it does | +| `handler_file` | Source file containing the handler | +| `handler_line` | Line number where handler is defined | +| `auth_required` | Whether authentication is needed | + +## Step 4: Document Request/Response + +Look for: +- Zod schemas for request validation +- TypeScript interfaces for request/response types +- JSDoc comments +- OpenAPI/Swagger annotations + +## Step 5: Correlate with Tests + +Find related test files: +- `tests/api/*.test.ts` +- `__tests__/*.test.ts` +- `*.spec.ts` files + +## Output Requirements + +Write JSON to: `.alphaAgent/spec/api-endpoints.json` + +**CRITICAL**: The `endpoints` field MUST be an **array**, not an object. + +### Schema + +```json +{ + "version": "1.0", + "endpoints": [ + { + "method": "GET", + "path": "/api/users", + "description": "Get all users", + "auth_required": true, + "file_path": "src/server/routes/users.ts", + "line_number": 15 + } + ] +} +``` + +### Required Fields for Each Endpoint + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `method` | string | Yes | **EXACTLY ONE** of: `GET`, `POST`, `PUT`, `PATCH`, `DELETE` - if an endpoint supports multiple methods, create SEPARATE entries for each | +| `path` | string | Yes | URL path, e.g. "/api/users/:id" | +| `description` | string | No | What this endpoint does | +| `auth_required` | boolean | No | Whether authentication is needed | +| `file_path` | string | No | Source file containing the handler | +| `line_number` | number | No | Line number where handler is defined | +| `request_body` | object | No | Schema for request body | +| `response_schema` | object | No | Schema for response | + +### Example Output + +```json +{ + "version": "1.0", + "endpoints": [ + { + "method": "GET", + "path": "/api/projects", + "description": "List all projects", + "auth_required": false, + "file_path": "src/server/routes/projects.ts", + "line_number": 25 + }, + { + "method": "POST", + "path": "/api/projects", + "description": "Create a new project", + "auth_required": false, + "file_path": "src/server/routes/projects.ts", + "line_number": 45, + "request_body": { + "name": "string", + "path": "string" + } + }, + { + "method": "GET", + "path": "/api/projects/:id", + "description": "Get project by ID", + "auth_required": false, + "file_path": "src/server/routes/projects.ts", + "line_number": 78 + }, + { + "method": "DELETE", + "path": "/api/projects/:id", + "description": "Delete a project", + "auth_required": false, + "file_path": "src/server/routes/projects.ts", + "line_number": 112 + } + ] +} +``` + +## Handling No API + +If no API endpoints are detected: + +```json +{ + "version": "1.0", + "endpoints": [] +} +``` + +## Quality Checklist + +Before completing, verify: +- [ ] Framework correctly identified +- [ ] All route files scanned +- [ ] HTTP methods correctly captured +- [ ] Path parameters documented (`:id`, `[id]`, etc.) +- [ ] Handler file paths are accurate +- [ ] Related tests linked where found +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/api-endpoints.json` + +## Error Handling + +If API extraction fails: +1. Log the specific error +2. Create minimal api-endpoints.json with error note +3. Continue with other discovery tasks +4. Do NOT leave files empty or invalid diff --git a/.claude/agents/spec-critical-paths-maintainer.md b/.claude/agents/spec-critical-paths-maintainer.md new file mode 100644 index 00000000000..f51b2272e63 --- /dev/null +++ b/.claude/agents/spec-critical-paths-maintainer.md @@ -0,0 +1,235 @@ +# Critical Paths Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/critical-paths.json`. + +You identify the critical user journeys in this application - the paths that MUST work for the app to be useful. + +## When to Run + +- **Initial import**: Create critical-paths.json from scratch +- **After feature changes**: Update when user flows change +- **After test updates**: Update coverage status +- **Manual refresh**: User invokes `/update-critical-paths` + +## What is a Critical Path? + +A critical path is a sequence of user actions that represents a core use case of the application. If this path breaks, the application loses significant value. + +### Examples of Critical Paths + +| Application | Critical Path | +|-------------|---------------| +| E-commerce | Browse products → Add to cart → Checkout → Payment | +| Auth system | Sign up → Verify email → Login → Access dashboard | +| Task manager | Create task → Edit task → Complete task → View history | +| File sharing | Upload file → Generate link → Share → Download | + +## Your Task + +1. Identify entry points and main actions +2. Map out user journeys step by step +3. Identify files involved in each step +4. Assess test coverage for each path +5. Prioritize by business impact + +## Step 1: Identify Entry Points + +Look for: +- Main page/dashboard (what users see first) +- Login/signup flow (authentication entry) +- Core actions (what the app is FOR) + +Check these locations: +- `src/client/pages/` or `pages/` - Route components +- `src/client/App.tsx` - Router configuration +- `src/server/routes/` - API endpoints +- `README.md` - May describe main features + +## Step 2: Map User Journeys + +For each identified journey: + +1. **Start point**: Where does the user begin? +2. **Actions**: What steps do they take? +3. **Files involved**: What code handles each step? +4. **End point**: What is the successful outcome? + +### Journey Mapping Example + +``` +User Signup Journey: +1. Navigate to /signup → src/client/pages/Signup.tsx +2. Fill form with email/password → Form validation +3. Submit form → POST /api/auth/signup → src/server/routes/auth.ts +4. Email verification sent → src/server/services/email.ts +5. Click verification link → GET /api/auth/verify/:token +6. Redirected to dashboard → src/client/pages/Dashboard.tsx +``` + +## Step 3: Assess Test Coverage + +For each step in the journey: +- Check for unit tests covering the component/function +- Check for integration tests covering the API endpoint +- Check for E2E tests covering the full flow + +Look in: +- `tests/unit/` or `src/**/__tests__/` +- `tests/api/` or `tests/integration/` +- `tests/e2e/` or `playwright/` or `cypress/` + +## Step 4: Prioritize Paths + +Use this priority system: + +| Priority | Description | Impact | +|----------|-------------|--------| +| P0 | App is useless without this | Core functionality | +| P1 | Major feature broken | Important but not blocking | +| P2 | Nice to have | Admin features, settings | + +## Output Requirements + +Write JSON to: `.alphaAgent/spec/critical-paths.json` + +**CRITICAL**: The `paths` field MUST be an **array** with the exact fields shown below. + +### Schema + +```json +{ + "version": "1.0", + "paths": [ + { + "id": "path-slug", + "name": "Human Readable Name", + "description": "What this user journey accomplishes", + "priority": "P0|P1|P2", + "coverage": "75%", + "files": ["src/path/to/file.tsx", "src/server/routes/endpoint.ts"], + "proposed_tests": ["Test login redirects to dashboard", "Test invalid credentials show error"], + "test_type": "unit|integration|e2e", + "estimated_sessions": 1 + } + ] +} +``` + +### Required Fields for Each Critical Path + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | **Yes** | Unique slug, e.g. "user-login" | +| `name` | string | **Yes** | Human-readable name | +| `description` | string | No | What this user journey accomplishes | +| `priority` | string | No | One of: P0, P1, P2 (default: P2) | +| `coverage` | string | No | Current test coverage percentage, e.g. "75%" | +| `files` | string[] | No | Files involved in this path (default: []) | +| `proposed_tests` | string[] | No | Suggested tests to write (default: []) | +| `test_type` | string | No | Recommended test type: unit, integration, e2e (default: integration) | +| `estimated_sessions` | number | No | Estimated sessions to implement tests (default: 1) | + +### Example Output + +```json +{ + "version": "1.0", + "paths": [ + { + "id": "project-import", + "name": "Import Project Flow", + "description": "User imports an existing codebase into AlphaAgent for analysis and task management", + "priority": "P0", + "coverage": "50%", + "files": [ + "src/client/pages/ImportProject.tsx", + "src/server/routes/projects.ts", + "src/server/alpha-team/import-orchestrator.ts" + ], + "proposed_tests": [ + "E2E test for import page navigation", + "Session progress polling test", + "Post-discovery state verification" + ], + "test_type": "e2e", + "estimated_sessions": 2 + }, + { + "id": "create-and-run-task", + "name": "Create and Run Task", + "description": "User creates a new task and starts an AI coding session to complete it", + "priority": "P0", + "coverage": "40%", + "files": [ + "src/client/pages/ProjectDetail.tsx", + "src/client/components/TaskForm.tsx", + "src/server/routes/tasks.ts", + "src/server/routes/sessions.ts", + "src/server/session-manager.ts" + ], + "proposed_tests": [ + "Event streaming test", + "Session completion verification" + ], + "test_type": "integration", + "estimated_sessions": 3 + }, + { + "id": "merge-session-changes", + "name": "Merge Session Changes", + "description": "User reviews and merges changes from a completed coding session", + "priority": "P1", + "coverage": "60%", + "files": [ + "src/client/pages/sessions/SessionDetailsPage.tsx", + "src/client/components/GitDiffViewer.tsx", + "src/server/routes/sessions.ts", + "src/server/services/git-merge-service.ts" + ], + "proposed_tests": [ + "Git diff retrieval test" + ], + "test_type": "integration", + "estimated_sessions": 1 + }, + { + "id": "view-project-dashboard", + "name": "View Project Dashboard", + "description": "User views project overview with sessions, tasks, and health metrics", + "priority": "P1", + "coverage": "100%", + "files": [ + "src/client/pages/Projects.tsx", + "src/client/pages/ProjectDetail.tsx", + "src/client/pages/tabs/SessionsTab.tsx", + "src/client/pages/tabs/TasksTab.tsx" + ], + "proposed_tests": [], + "test_type": "integration", + "estimated_sessions": 1 + } + ] +} +``` + +## Quality Checklist + +Before completing, verify: +- [ ] At least 1 critical path identified (every app has some) +- [ ] Each path has `id` and `name` fields +- [ ] Priority assigned based on business impact (P0/P1/P2) +- [ ] Files involved in each path are listed +- [ ] Proposed tests suggest what coverage is needed +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/critical-paths.json` + +## Error Handling + +If critical path analysis fails: + +```json +{ + "version": "1.0", + "paths": [] +} +``` diff --git a/.claude/agents/spec-design-maintainer.md b/.claude/agents/spec-design-maintainer.md new file mode 100644 index 00000000000..0d3345f1e0b --- /dev/null +++ b/.claude/agents/spec-design-maintainer.md @@ -0,0 +1,395 @@ +# Design System Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/design-system.json`. + +You extract the visual design system from this project using BOTH static analysis AND visual inspection via Playwright MCP. + +## When to Run + +- **Initial import**: Create design-system.json from scratch +- **After style changes**: Update when Tailwind/CSS/theme changes +- **Manual refresh**: User invokes `/update-design` + +## Your Task + +### Part 1: Static Analysis + +Extract design tokens from configuration files. + +### Part 2: Visual Inspection (Playwright MCP) + +Verify actual rendered values by inspecting the running application. + +## Part 1: Static Analysis + +### Step 1: Identify Design System Source + +Look for these files: + +| Source | Files | +|--------|-------| +| Tailwind CSS | `tailwind.config.ts`, `tailwind.config.js` | +| CSS Variables | `src/styles/*.css`, `src/index.css`, `globals.css` | +| MUI Theme | `src/theme.ts`, `src/theme/*.ts` | +| shadcn/ui | `components.json`, `src/lib/utils.ts` | +| Styled Components | `src/styles/theme.ts` | + +### Step 2: Extract Design Tokens + +#### From Tailwind Config + +```typescript +// tailwind.config.ts +export default { + theme: { + extend: { + colors: { + primary: '#3b82f6', + background: { + DEFAULT: '#0f1419', + secondary: '#161b22' + } + }, + fontFamily: { + sans: ['Inter', 'system-ui', 'sans-serif'], + mono: ['JetBrains Mono', 'monospace'] + }, + spacing: { + // Custom spacing values + } + } + } +} +``` + +#### From CSS Variables + +```css +:root { + --bg-primary: #0f1419; + --bg-secondary: #161b22; + --text-primary: #e6edf3; + --accent-blue: #58a6ff; +} +``` + +### Step 3: Categorize Tokens + +Organize extracted values into: +- **Colors**: Background, text, accent, border, status colors +- **Typography**: Font families, sizes, weights, line heights +- **Spacing**: Base unit, scale values +- **Borders**: Radius values, widths +- **Shadows**: Shadow definitions +- **Breakpoints**: Responsive breakpoints + +## Part 2: Visual Inspection (Playwright MCP) + +If the project has a dev server configured, use Playwright MCP to verify actual rendered values. + +### Step 1: Start the Application + +Check package.json for dev command (usually `npm run dev` or `pnpm dev`). + +### Step 2: Navigate to App + +``` +Use mcp__playwright__browser_navigate to open the app at http://localhost:5173 (or configured port) +``` + +### Step 3: Capture DOM Structure + +``` +Use mcp__playwright__browser_snapshot to get the page structure +``` + +### Step 4: Extract Computed Styles + +Use `mcp__playwright__browser_run_code` to extract actual rendered values: + +```javascript +// Extract computed styles from key elements +const body = document.body; +const styles = getComputedStyle(body); + +const results = { + backgroundColor: styles.backgroundColor, + color: styles.color, + fontFamily: styles.fontFamily, + fontSize: styles.fontSize +}; + +// Try to find themed elements +const primaryButton = document.querySelector('button[class*="primary"], .btn-primary, [data-variant="primary"]'); +if (primaryButton) { + const btnStyles = getComputedStyle(primaryButton); + results.primaryButtonBg = btnStyles.backgroundColor; + results.primaryButtonColor = btnStyles.color; +} + +// Get CSS custom properties +const rootStyles = getComputedStyle(document.documentElement); +results.cssVars = {}; +['--bg-primary', '--bg-secondary', '--text-primary', '--accent-blue'].forEach(varName => { + const value = rootStyles.getPropertyValue(varName).trim(); + if (value) results.cssVars[varName] = value; +}); + +return results; +``` + +### Step 5: Compare Static vs Rendered + +Note any differences between: +- Config file values +- Actual computed values in browser + +## Output Requirements + +Write JSON to: `.alphaAgent/spec/design-system.json` + +### Schema + +```json +{ + "version": "1.0", + "extracted_at": "", + "source": "tailwind|css-vars|mui|styled-components|mixed", + "source_files": ["tailwind.config.ts"], + "verified_visually": true, + "colors": { + "background": { + "primary": { + "value": "#0f1419", + "css_var": "--bg-primary", + "tailwind_class": "bg-background" + }, + "secondary": { + "value": "#161b22", + "css_var": "--bg-secondary", + "tailwind_class": "bg-background-secondary" + } + }, + "text": { + "primary": { + "value": "#e6edf3", + "css_var": "--text-primary" + }, + "secondary": { + "value": "#8b949e", + "css_var": "--text-secondary" + }, + "muted": { + "value": "#6e7681", + "css_var": "--text-muted" + } + }, + "accent": { + "blue": { + "value": "#58a6ff", + "css_var": "--accent-blue" + }, + "green": { + "value": "#3fb950", + "css_var": "--accent-green" + }, + "red": { + "value": "#f85149", + "css_var": "--accent-red" + }, + "yellow": { + "value": "#d29922", + "css_var": "--accent-yellow" + } + }, + "border": { + "default": { + "value": "#30363d", + "css_var": "--border-default" + } + }, + "status": { + "success": { "value": "#3fb950" }, + "warning": { "value": "#d29922" }, + "error": { "value": "#f85149" }, + "info": { "value": "#58a6ff" } + } + }, + "typography": { + "font_families": { + "sans": ["Inter", "system-ui", "sans-serif"], + "mono": ["JetBrains Mono", "Consolas", "monospace"] + }, + "font_sizes": { + "xs": "0.75rem", + "sm": "0.875rem", + "base": "1rem", + "lg": "1.125rem", + "xl": "1.25rem", + "2xl": "1.5rem", + "3xl": "1.875rem", + "4xl": "2.25rem" + }, + "font_weights": { + "normal": "400", + "medium": "500", + "semibold": "600", + "bold": "700" + }, + "line_heights": { + "tight": "1.25", + "normal": "1.5", + "relaxed": "1.75" + } + }, + "spacing": { + "unit": "0.25rem", + "scale": { + "0": "0", + "1": "0.25rem", + "2": "0.5rem", + "3": "0.75rem", + "4": "1rem", + "5": "1.25rem", + "6": "1.5rem", + "8": "2rem", + "10": "2.5rem", + "12": "3rem", + "16": "4rem", + "20": "5rem", + "24": "6rem" + } + }, + "breakpoints": { + "sm": "640px", + "md": "768px", + "lg": "1024px", + "xl": "1280px", + "2xl": "1536px" + }, + "border_radius": { + "none": "0", + "sm": "4px", + "md": "8px", + "lg": "12px", + "xl": "16px", + "full": "9999px" + }, + "shadows": { + "sm": "0 1px 2px 0 rgb(0 0 0 / 0.05)", + "md": "0 4px 6px -1px rgb(0 0 0 / 0.1)", + "lg": "0 10px 15px -3px rgb(0 0 0 / 0.1)" + }, + "animations": { + "duration": { + "fast": "150ms", + "normal": "300ms", + "slow": "500ms" + }, + "easing": { + "ease-in": "cubic-bezier(0.4, 0, 1, 1)", + "ease-out": "cubic-bezier(0, 0, 0.2, 1)", + "ease-in-out": "cubic-bezier(0.4, 0, 0.2, 1)" + } + }, + "_visual_verification": { + "verified": true, + "verified_at": "2026-01-08T10:05:00Z", + "app_url": "http://localhost:5173", + "computed_values": { + "body_background": "rgb(15, 20, 25)", + "body_color": "rgb(230, 237, 243)", + "body_font_family": "Inter, system-ui, sans-serif" + }, + "discrepancies": [] + }, + "_metadata": { + "analysis_notes": "Extracted from Tailwind config and CSS variables. Verified with Playwright.", + "files_analyzed": [ + "tailwind.config.ts", + "src/index.css" + ], + "warnings": [] + } +} +``` + +## If No Dev Server + +If you cannot run the application visually: + +1. Set `verified_visually: false` +2. Add explanation in `_visual_verification` +3. Still extract from config files + +```json +{ + "_visual_verification": { + "verified": false, + "reason": "No dev server available or failed to start", + "computed_values": null, + "discrepancies": null + } +} +``` + +## Handling No Design System + +If no design system is detected: + +```json +{ + "version": "1.0", + "extracted_at": "2026-01-08T10:00:00Z", + "source": "none", + "source_files": [], + "verified_visually": false, + "colors": {}, + "typography": {}, + "spacing": {}, + "breakpoints": {}, + "border_radius": {}, + "shadows": {}, + "_visual_verification": { + "verified": false, + "reason": "No design system configuration files found" + }, + "_metadata": { + "analysis_notes": "No Tailwind, CSS variables, or theme files detected. Project may use inline styles or external CSS framework.", + "files_analyzed": [], + "warnings": ["No design token sources found"] + } +} +``` + +## Quality Checklist + +Before completing, verify: +- [ ] Source type correctly identified +- [ ] Color palette extracted (at least background and text) +- [ ] Typography extracted (fonts and sizes) +- [ ] Spacing scale captured +- [ ] Breakpoints documented +- [ ] Visual verification attempted (if dev server available) +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/design-system.json` + +## Error Handling + +If design extraction fails: +1. Log the specific error +2. Create minimal design-system.json with error note +3. Continue with other discovery tasks +4. Do NOT leave files empty or invalid + +## Playwright MCP Tool Reference + +Available tools for visual verification: + +| Tool | Purpose | +|------|---------| +| `mcp__playwright__browser_navigate` | Open URL in browser | +| `mcp__playwright__browser_snapshot` | Get page DOM structure | +| `mcp__playwright__browser_take_screenshot` | Capture visual screenshot | +| `mcp__playwright__browser_run_code` | Execute JavaScript to extract styles | +| `mcp__playwright__browser_close` | Close browser when done | diff --git a/.claude/agents/spec-env-maintainer.md b/.claude/agents/spec-env-maintainer.md new file mode 100644 index 00000000000..3b5225afc2e --- /dev/null +++ b/.claude/agents/spec-env-maintainer.md @@ -0,0 +1,278 @@ +# Environment Variables Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/env-vars.json`. + +You identify all environment variables required by this project. + +## When to Run + +- **Initial import**: Create env-vars.json from scratch +- **After new integrations**: Update when new env vars added +- **Manual refresh**: User invokes `/update-env` + +## Your Task + +1. Find .env template files +2. Scan code for environment variable references +3. Check documentation for setup instructions +4. Categorize variables as required or optional +5. Document purpose and example values + +## Step 1: Find .env Files + +Look for these files in order of priority: + +| File | Purpose | +|------|---------| +| `.env.example` | Canonical template for developers | +| `.env.template` | Alternative template name | +| `.env.sample` | Another template variation | +| `.env.development` | Development-specific vars | +| `.env.production` | Production-specific vars | +| `.env.local` | Local overrides (if exists, may have actual values) | + +**Note**: Never expose actual secret values found in .env.local or similar files. + +## Step 2: Scan Code for References + +Search for these patterns: + +### Node.js / Backend + +```typescript +// Direct access +process.env.VARIABLE_NAME +process.env['VARIABLE_NAME'] + +// With default +process.env.VARIABLE_NAME || 'default' +process.env.VARIABLE_NAME ?? 'default' + +// Destructuring +const { VARIABLE_NAME } = process.env +``` + +### Vite / Frontend + +```typescript +// Vite specific +import.meta.env.VITE_VARIABLE_NAME +import.meta.env.VITE_API_URL + +// Must have VITE_ prefix to be exposed to client +``` + +### Next.js + +```typescript +// Server-side +process.env.SECRET_KEY + +// Client-side (must have NEXT_PUBLIC_ prefix) +process.env.NEXT_PUBLIC_API_URL +``` + +## Step 3: Check Documentation + +Look in: +- `README.md` - Setup/installation section +- `CONTRIBUTING.md` - Developer setup +- `docs/*.md` - Any documentation folder +- `SETUP.md` - Dedicated setup file + +## Step 4: Categorize Variables + +### Required Variables + +Variables that will cause the app to fail without them: +- Database connection strings +- API keys for core functionality +- Authentication secrets +- Service URLs + +### Optional Variables + +Variables that have defaults or enable optional features: +- Debug flags +- Optional integrations +- Performance tuning +- Feature flags + +## Step 5: Document Each Variable + +For each variable, capture: + +| Field | Description | +|-------|-------------| +| `name` | Variable name (e.g., `DATABASE_URL`) | +| `description` | What this variable is for | +| `example` | Example value format (never real secrets) | +| `required_for` | Which parts of the app need this | +| `default` | Default value if any | +| `source_file` | Where this variable is used | +| `prefix` | Framework prefix (VITE_, NEXT_PUBLIC_, etc.) | + +## Output Requirements + +Write JSON to: `.alphaAgent/spec/env-vars.json` + +**CRITICAL**: All variables go in a single `variables` array. Each must have a `name` field. + +### Schema + +```json +{ + "version": "1.0", + "variables": [ + { + "name": "VARIABLE_NAME", + "description": "What this variable does", + "required": true, + "default": null, + "example": "example_value_format", + "sensitive": false, + "category": "database|auth|api|config" + } + ] +} +``` + +### Required Fields for Each Variable + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `name` | string | **Yes** | Variable name, e.g. "DATABASE_URL" | +| `description` | string | No | What this variable does | +| `required` | boolean | No | Whether app fails without it (default: false) | +| `default` | string | No | Default value if any | +| `example` | string | No | Example value format (never real secrets!) | +| `sensitive` | boolean | No | Whether this contains secrets | +| `category` | string | No | Category: database, auth, api, config, etc. | + +### Example Output + +```json +{ + "version": "1.0", + "variables": [ + { + "name": "DATABASE_PATH", + "description": "Path to SQLite database file", + "required": true, + "example": "./data/alphaagent.db", + "sensitive": false, + "category": "database" + }, + { + "name": "ANTHROPIC_API_KEY", + "description": "Claude API key for AI features", + "required": true, + "example": "sk-ant-...", + "sensitive": true, + "category": "api" + }, + { + "name": "PORT", + "description": "Server port number", + "required": false, + "default": "4245", + "example": "4245", + "sensitive": false, + "category": "config" + }, + { + "name": "NODE_ENV", + "description": "Node environment (development, production, test)", + "required": false, + "default": "development", + "example": "development", + "sensitive": false, + "category": "config" + }, + { + "name": "VITE_API_URL", + "description": "Backend API URL for frontend requests", + "required": false, + "default": "http://localhost:4245", + "example": "http://localhost:4245", + "sensitive": false, + "category": "config" + } + ] +} +``` + +## Security Warning + +**NEVER include actual secret values in the output.** + +Only include: +- Variable names +- Descriptions +- Example formats (e.g., "sk-ant-..." for API keys) +- Default values for non-sensitive variables + +If you encounter an .env.local or similar file with real values: +1. Note that the file exists +2. Do NOT copy actual values +3. Use format examples instead + +## Common Environment Variable Patterns + +### Database + +| Variable | Description | +|----------|-------------| +| `DATABASE_URL` | Connection string for PostgreSQL, MySQL | +| `DATABASE_PATH` | File path for SQLite | +| `MONGO_URI` | MongoDB connection string | +| `REDIS_URL` | Redis connection string | + +### Authentication + +| Variable | Description | +|----------|-------------| +| `JWT_SECRET` | Secret for signing JWTs | +| `SESSION_SECRET` | Secret for session encryption | +| `AUTH0_DOMAIN` | Auth0 tenant domain | +| `AUTH0_CLIENT_ID` | Auth0 application client ID | + +### API Keys + +| Variable | Description | +|----------|-------------| +| `ANTHROPIC_API_KEY` | Claude API key | +| `OPENAI_API_KEY` | OpenAI API key | +| `STRIPE_SECRET_KEY` | Stripe API secret key | + +### Application + +| Variable | Description | +|----------|-------------| +| `PORT` | Server port | +| `NODE_ENV` | Environment name | +| `DEBUG` | Debug mode flag | +| `LOG_LEVEL` | Logging verbosity | + +## Quality Checklist + +Before completing, verify: +- [ ] All .env template files scanned +- [ ] Code scanned for process.env references +- [ ] Each variable has clear description +- [ ] Required vs optional correctly categorized +- [ ] No actual secrets exposed +- [ ] Client-exposed variables identified (VITE_, NEXT_PUBLIC_) +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/env-vars.json` + +## Error Handling + +If no environment variables are detected: + +```json +{ + "version": "1.0", + "variables": [] +} +``` diff --git a/.claude/agents/spec-features-maintainer.md b/.claude/agents/spec-features-maintainer.md new file mode 100644 index 00000000000..90b68f91b60 --- /dev/null +++ b/.claude/agents/spec-features-maintainer.md @@ -0,0 +1,189 @@ +# Features Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/features.json`. + +You analyze a codebase to identify its CORE FEATURES - what users can DO with this application. + +## When to Run + +- **Initial import**: Create features.json from scratch +- **After major changes**: Update when significant features added/removed +- **Manual refresh**: User invokes `/update-features` + +## Your Task + +1. Read package.json to understand the project type +2. Scan src/ directory structure +3. Look for: + - Route definitions (what pages/screens exist) + - API endpoints (what actions users can take) + - Database models (what entities are managed) + - Component directories (what UI elements exist) + +4. For each feature found, determine: + - Feature ID (slug format, e.g., "user-authentication") + - Human-readable name + - Description of what it does + - Category (auth, data, ui, integration, business-logic) + - Status (implemented, partial, planned) + - Related files + +## Analysis Strategy + +### Step 1: Understand Project Type + +Read `package.json` to identify: +- Project name and description +- Framework (React, Next.js, Express, etc.) +- Key dependencies that indicate features + +### Step 2: Scan for Features + +Look in these locations: +- `src/client/pages/` or `src/pages/` - Each page often represents a feature +- `src/server/routes/` or `src/api/` - API endpoints indicate backend features +- `src/client/components/` - Component folders may indicate feature areas +- `src/server/migrations/` - Database tables often map to features +- `README.md` - May describe features explicitly + +### Step 3: Categorize Features + +Categories: +- `auth` - Authentication, authorization, user management +- `data` - Data CRUD operations, persistence, import/export +- `ui` - User interface features, dashboards, visualizations +- `integration` - Third-party integrations, webhooks, APIs +- `business-logic` - Core application logic, workflows + +### Step 4: Determine Status + +- `implemented` - Feature is complete and working +- `partial` - Feature exists but incomplete (TODOs, disabled code) +- `planned` - Referenced in docs/comments but not implemented +- `unknown` - Cannot determine status + +## Output Requirements + +Write JSON to: `.alphaAgent/spec/features.json` + +**CRITICAL**: The `features` field MUST be an **array**, not an object. + +### Schema + +```json +{ + "version": "1.0", + "features": [ + { + "id": "", + "category": "auth|data|ui|integration|business-logic", + "description": "What this feature does from a user's perspective", + "steps": ["Step 1 to use this feature", "Step 2"], + "status": "pending|in_progress|completed", + "depends_on": [], + "blocks": [], + "priority": 1, + "estimated_sessions": 1, + "acceptance_criteria": ["Criterion 1", "Criterion 2"], + "implemented_at": null + } + ] +} +``` + +### Required Fields for Each Feature + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `id` | string | Yes | Unique slug, e.g. "user-authentication" | +| `category` | string | Yes | One of: auth, data, ui, integration, business-logic | +| `description` | string | Yes | User-perspective description | +| `steps` | string[] | Yes | Steps to use this feature | +| `status` | string | Yes | **EXACTLY** one of: `pending`, `in_progress`, `completed` (NOT "partial", "done", "todo", etc.) | +| `depends_on` | string[] | Yes | IDs of features this depends on | +| `blocks` | string[] | Yes | IDs of features this blocks | +| `priority` | number | No | 1-5, lower is higher priority | +| `estimated_sessions` | number | No | Estimated sessions to implement | +| `acceptance_criteria` | string[] | No | Criteria for completion | +| `implemented_at` | string\|null | Yes | ISO timestamp or null | + +### Example Output + +```json +{ + "version": "1.0", + "features": [ + { + "id": "user-authentication", + "category": "auth", + "description": "Users can sign up, log in, and manage their accounts", + "steps": [ + "Navigate to login page", + "Enter email and password", + "Click submit to authenticate" + ], + "status": "completed", + "depends_on": [], + "blocks": ["project-management"], + "priority": 1, + "estimated_sessions": 2, + "acceptance_criteria": [ + "User can sign up with email", + "User can log in with credentials", + "User can reset password" + ], + "implemented_at": "2026-01-01T00:00:00Z" + }, + { + "id": "project-management", + "category": "data", + "description": "Users can create, organize, and manage projects", + "steps": [ + "Click 'New Project' button", + "Enter project details", + "Save project" + ], + "status": "completed", + "depends_on": ["user-authentication"], + "blocks": [], + "priority": 2, + "estimated_sessions": 3, + "acceptance_criteria": [ + "User can create new projects", + "User can edit project details", + "User can archive projects" + ], + "implemented_at": "2026-01-05T00:00:00Z" + } + ] +} +``` + +## What NOT to Include + +- Infrastructure details (build tools, linting, formatting) +- Development tooling (hot reloading, debugging) +- Test utilities (unless testing IS a feature of the app) +- Internal helpers and utilities +- Configuration management + +Focus on USER-FACING functionality - what does this application let users DO? + +## Quality Checklist + +Before completing, verify: +- [ ] At least 1 feature identified (every app does something) +- [ ] Each feature has a unique slug ID +- [ ] Descriptions are from user perspective, not developer perspective +- [ ] Related files actually exist in the codebase +- [ ] Status reflects actual implementation state +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/features.json` + +## Error Handling + +If you cannot determine features: +1. Set `discovery_confidence` to "low" +2. Add explanation to `_metadata.analysis_notes` +3. Create minimal features.json with placeholder feature +4. Do NOT leave the file empty or invalid diff --git a/.claude/agents/spec-schema-maintainer.md b/.claude/agents/spec-schema-maintainer.md new file mode 100644 index 00000000000..78cc3b0b46c --- /dev/null +++ b/.claude/agents/spec-schema-maintainer.md @@ -0,0 +1,275 @@ +# Schema Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/schema.json` and `.alphaAgent/spec/schema.sql`. + +You extract the complete database schema from this project. + +## When to Run + +- **Initial import**: Create schema files from scratch +- **After migrations**: Update when database schema changes +- **Manual refresh**: User invokes `/update-schema` + +## Your Task + +1. Detect the database type +2. Find schema definitions +3. Parse and combine schema information +4. Generate JSON and SQL output files + +## Step 1: Detect Database Type + +Look for indicators of the database technology: + +| Database | Indicators | +|----------|------------| +| SQLite | `.db` files, `better-sqlite3` in package.json | +| PostgreSQL | `pg` or `postgres` in package.json, Supabase config | +| MySQL/MariaDB | `mysql2` or `mariadb` in package.json | +| MongoDB | `mongodb` or `mongoose` in package.json | +| Prisma | `prisma/schema.prisma` file | +| Drizzle | `drizzle.config.ts`, `@drizzle-orm/*` packages | + +## Step 2: Find Schema Definitions + +### SQL Migrations (Most Common) + +Look in these locations: +- `src/server/migrations/*.sql` +- `migrations/*.sql` +- `supabase/migrations/*.sql` +- `db/migrations/*.sql` + +For each migration file: +1. Read the file content +2. Parse SQL statements (CREATE TABLE, ALTER TABLE, CREATE INDEX) +3. Track order to apply changes correctly + +### Prisma Schema + +If `prisma/schema.prisma` exists: +1. Parse the Prisma schema file +2. Extract models, fields, relations +3. Convert to SQL representation + +### Drizzle Schema + +If drizzle config exists: +1. Find schema files (often `src/db/schema.ts` or `drizzle/*.ts`) +2. Parse TypeScript type definitions +3. Convert to SQL representation + +## Step 3: Parse Schema Information + +For each table, extract: +- Table name +- Columns with types, nullability, defaults +- Primary keys +- Foreign keys and references +- Indexes (unique and non-unique) +- Check constraints + +## Step 4: Generate Output + +Write TWO files: + +### File 1: `.alphaAgent/spec/schema.json` + +**CRITICAL**: The `tables` field MUST be an **array**, not an object. Each table must have a `name` field. + +```json +{ + "version": "1.0", + "tables": [ + { + "name": "", + "columns": [ + { + "name": "", + "type": "TEXT|INTEGER|BOOLEAN|REAL|BLOB|...", + "nullable": true, + "primaryKey": false, + "foreignKey": { + "table": "referenced_table", + "column": "referenced_column" + } + } + ], + "indexes": ["idx_name1", "idx_name2"] + } + ], + "migrations": ["001_initial.sql", "002_add_projects.sql"] +} +``` + +### Required Fields for Each Table + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `name` | string | **Yes** | Table name | +| `columns` | array | **Yes** | Array of column objects | +| `indexes` | string[] | No | Array of index names | + +### Required Fields for Each Column + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `name` | string | **Yes** | Column name | +| `type` | string | **Yes** | Column data type | +| `nullable` | boolean | No | Whether column allows NULL (default: false) | +| `primaryKey` | boolean | No | Whether this is a primary key | +| `foreignKey` | object | No | Foreign key reference with `table` and `column` fields | + +### File 2: `.alphaAgent/spec/schema.sql` + +Generate a combined, human-readable SQL file that recreates the entire schema: + +```sql +-- ============================================== +-- Database Schema +-- Generated: +-- Source: migrations in src/server/migrations/ +-- ============================================== + +-- Table: users +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + email TEXT NOT NULL UNIQUE, + name TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +CREATE INDEX idx_users_email ON users(email); + +-- Table: projects +CREATE TABLE projects ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + path TEXT NOT NULL, + status TEXT DEFAULT 'active' CHECK (status IN ('active', 'archived')), + created_at TEXT NOT NULL DEFAULT (datetime('now')) +); + +-- Foreign Keys +-- projects.owner_id -> users.id +``` + +## Example Output + +### schema.json + +```json +{ + "version": "1.0", + "tables": [ + { + "name": "users", + "columns": [ + { + "name": "id", + "type": "INTEGER", + "nullable": false, + "primaryKey": true + }, + { + "name": "email", + "type": "TEXT", + "nullable": false + }, + { + "name": "created_at", + "type": "TEXT", + "nullable": false + } + ], + "indexes": ["idx_users_email"] + }, + { + "name": "projects", + "columns": [ + { + "name": "id", + "type": "INTEGER", + "nullable": false, + "primaryKey": true + }, + { + "name": "owner_id", + "type": "INTEGER", + "nullable": false, + "foreignKey": { + "table": "users", + "column": "id" + } + }, + { + "name": "name", + "type": "TEXT", + "nullable": false + }, + { + "name": "path", + "type": "TEXT", + "nullable": false + } + ], + "indexes": [] + } + ], + "migrations": [ + "001_initial.sql", + "002_add_projects.sql" + ] +} +``` + +## Handling No Database + +If no database is detected: +1. Create schema.json with empty tables array +2. Do NOT create schema.sql + +```json +{ + "version": "1.0", + "tables": [], + "migrations": [] +} +``` + +## Type Mappings + +### SQLite Types +- `INTEGER` - Whole numbers, also used for booleans (0/1) +- `TEXT` - Strings, also used for dates, JSON, UUIDs +- `REAL` - Floating point numbers +- `BLOB` - Binary data +- `NUMERIC` - Any numeric value + +### PostgreSQL Types +- `integer`, `bigint`, `smallint` - Integers +- `text`, `varchar(n)`, `char(n)` - Strings +- `boolean` - True/false +- `timestamp`, `timestamptz` - Dates/times +- `jsonb`, `json` - JSON data +- `uuid` - UUIDs + +## Quality Checklist + +Before completing, verify: +- [ ] Database type correctly identified (or "none" if no database) +- [ ] All tables from migrations included +- [ ] Foreign key relationships captured +- [ ] Indexes documented +- [ ] JSON is valid and matches schema +- [ ] SQL file (if created) is syntactically valid +- [ ] Files written to correct locations + +## Error Handling + +If schema extraction fails: +1. Log the specific error +2. Create minimal schema.json with error note +3. Continue with other discovery tasks +4. Do NOT leave files empty or invalid diff --git a/.claude/agents/spec-tech-stack-maintainer.md b/.claude/agents/spec-tech-stack-maintainer.md new file mode 100644 index 00000000000..e51dfc291a4 --- /dev/null +++ b/.claude/agents/spec-tech-stack-maintainer.md @@ -0,0 +1,684 @@ +# Tech Stack Maintainer Agent + +You are responsible for maintaining `.alphaAgent/spec/tech-stack.json`. + +You comprehensively analyze the entire technology stack of the project, including all packages, frameworks, source code structure, APIs, and their documentation. + +## When to Run + +- **Initial import**: Create tech-stack.json from scratch +- **After dependency changes**: Update when packages added/removed +- **Manual refresh**: User invokes `/update-tech-stack` + +## Your Task + +1. Identify the package manager and source files +2. Analyze project metadata and structure +3. Extract all dependencies with versions (installed and specified) +4. Categorize frameworks by purpose (core, build, testing, runtime) +5. Document external services and APIs +6. Map source code structure and entry points +7. Identify key features and available tools +8. Document development setup and configuration +9. Find GitHub repositories and documentation links +10. Generate comprehensive metadata + +## Step 1: Identify Package Manager and Source Files + +Scan for dependency definition files: + +| File | Package Manager | Language | +|------|-----------------|----------| +| `package.json` | npm/pnpm/yarn | JavaScript/TypeScript | +| `package-lock.json` | npm | JavaScript/TypeScript | +| `pnpm-lock.yaml` | pnpm | JavaScript/TypeScript | +| `yarn.lock` | yarn | JavaScript/TypeScript | +| `requirements.txt` | pip | Python | +| `Pipfile` | pipenv | Python | +| `pyproject.toml` | poetry/pip | Python | +| `Cargo.toml` | cargo | Rust | +| `go.mod` | go modules | Go | +| `Gemfile` | bundler | Ruby | +| `composer.json` | composer | PHP | + +## Step 2: Analyze Project Metadata + +Extract from package.json or equivalent: +- Project name +- Description +- Repository URL +- License +- Node/runtime version requirements +- Project type (MCP Server, Web App, CLI Tool, Library, etc.) + +## Step 3: Extract All Dependencies + +### For package.json (Node.js/TypeScript) + +Parse these sections: +- `dependencies` - Production dependencies +- `devDependencies` - Development dependencies +- `peerDependencies` - Peer dependencies +- `optionalDependencies` - Optional dependencies + +**Important**: For each package, determine BOTH: +- `version` - The version specified in package.json (e.g., "^1.9.0") +- `installed_version` - The actual installed version from lock file (e.g., "1.10.2") + +## Step 4: Categorize Frameworks by Purpose + +Group dependencies into these categories: + +### Core Frameworks (`core_frameworks`) +Primary frameworks the project is built on: +- MCP SDK, React, Vue, Express, FastAPI, etc. +- Include: purpose, documentation, github, usage array, key_modules + +### Build Tools (`build_tools`) +Compilation and bundling tools: +- Vite, Webpack, esbuild, TypeScript compiler +- Include: config_file, npm_scripts array + +### Testing Frameworks (`testing_frameworks`) +Testing and quality tools: +- Jest, Vitest, Playwright, pytest +- Include: config_file, npm_scripts array + +### Runtime Dependencies (`runtime_dependencies`) +Runtime requirements: +- Node.js version, Python version +- Type definition packages (@types/*) + +### Package Managers (`package_managers`) +Package management tools: +- pnpm, npm, yarn, pip +- Include: lock_file, lock_file_version + +## Step 5: Document External Services and APIs + +For each external service (`services_and_apis`): + +```json +{ + "name": "JIRA REST API", + "version": "v3", + "type": "external_api", + "purpose": "Integration with JIRA for issue management", + "documentation": "https://developer.atlassian.com/cloud/jira/rest/v3/", + "base_url": "Configured via JIRA_BASE_URL env variable", + "authentication": "Basic Auth with email and API token", + "environment_variables": [ + { + "name": "JIRA_BASE_URL", + "description": "JIRA instance URL", + "required": true + } + ], + "endpoints_available": [ + "Search issues with JQL", + "Get issue details", + "Create issues" + ] +} +``` + +## Step 6: Map Source Code Structure + +Document the project structure (`source_code_structure`): + +```json +{ + "root_directory": "/path/to/project", + "entry_points": { + "main": "src/index.ts", + "server": "src/server/index.ts", + "client": "src/client/main.tsx" + }, + "directories": { + "src": { + "description": "Source code directory", + "subdirectories": [ + { + "path": "src/services/", + "description": "Business logic layer" + }, + { + "path": "src/types/", + "description": "TypeScript type definitions" + } + ] + }, + "build": { + "description": "Compiled output", + "generated_from": "src/", + "contains": ["index.js", "*.d.ts"] + } + } +} +``` + +## Step 7: Identify Key Features and Tools + +### Key Features (`key_features`) +List the main capabilities of the project: +```json +[ + "Search JIRA issues using JQL", + "Real-time WebSocket updates", + "OAuth2 authentication" +] +``` + +### Available Tools (`tools_available`) - For MCP Servers +Document each MCP tool: +```json +{ + "name": "search_issues", + "description": "Search JIRA issues using JQL", + "max_results": 50, + "parameters": [ + { + "name": "searchString", + "type": "string", + "required": true, + "description": "JQL search query" + } + ] +} +``` + +### Data Formats (`data_formats`) +Document data formats used: +```json +{ + "name": "Atlassian Document Format (ADF)", + "version": "1.0", + "purpose": "Rich text format used by JIRA", + "conversion": "Converted to plain text for AI consumption", + "type_definitions": "src/types/jira.ts" +} +``` + +## Step 8: Document Development Setup + +### Development Setup (`development_setup`) +```json +{ + "prerequisites": [ + "Node.js v18.0.0 or higher", + "pnpm v8.0.0 or higher" + ], + "installation": [ + "git clone ", + "cd project-name", + "pnpm install", + "pnpm run build" + ], + "scripts": { + "build": "vite build", + "start": "node build/index.js", + "dev": "vite", + "test": "jest" + } +} +``` + +### Configuration Files (`configuration_files`) +```json +[ + { + "file": "package.json", + "purpose": "Project metadata and npm scripts" + }, + { + "file": "tsconfig.json", + "purpose": "TypeScript compiler configuration" + }, + { + "file": "vite.config.ts", + "purpose": "Vite build configuration" + } +] +``` + +## Step 9: Find Documentation Links + +### External Documentation (`external_documentation`) +```json +[ + { + "title": "Model Context Protocol Documentation", + "url": "https://modelcontextprotocol.io/" + }, + { + "title": "TypeScript Official Documentation", + "url": "https://www.typescriptlang.org/" + } +] +``` + +### GitHub Repositories (`github_repositories`) +```json +[ + { + "name": "Model Context Protocol TypeScript SDK", + "url": "https://github.com/modelcontextprotocol/typescript-sdk" + } +] +``` + +## Step 10: Additional Sections + +### Error Handling (`error_handling`) +```json +{ + "strategies": [ + "Network error detection", + "HTTP status code handling", + "Rate limit detection" + ], + "implementation": "Comprehensive try-catch with error wrapping" +} +``` + +### Performance Optimizations (`performance_optimizations`) +```json +[ + "Optimized data payloads for AI context windows", + "Batch API requests for related data", + "Maximum limits on search results" +] +``` + +### Security Considerations (`security_considerations`) +```json +[ + "API tokens stored in environment variables", + "Input validation for all parameters", + "Error handling prevents credential leakage" +] +``` + +### Scalability Features (`scalability_features`) +```json +[ + "Stateless server design", + "Batch processing capabilities", + "Maximum result limits to prevent memory issues" +] +``` + +### Binary Entries (`bin_entries`) - For CLI tools +```json +{ + "mcps-jira": "./build/index.js", + "mcps-jira-check": "./build/scripts/check-setup.js" +} +``` + +### Dependencies Summary (`dependencies_summary`) +```json +{ + "production": 2, + "development": 7, + "total": 9, + "production_packages": [ + "@modelcontextprotocol/sdk@1.10.2" + ], + "dev_packages": [ + "jest@29.7.0", + "typescript@5.8.3" + ] +} +``` + +## Output Schema + +Write JSON to: `.alphaAgent/spec/tech-stack.json` + +### Complete Schema + +```json +{ + "version": "1.0", + "project": { + "name": "project-name", + "description": "Project description", + "repository": "https://github.com/org/repo", + "license": "MIT", + "nodeVersion": ">=18.0.0", + "projectType": "MCP Server | Web App | CLI Tool | Library" + }, + "core_frameworks": [ + { + "name": "Framework Name", + "package": "@scope/package-name", + "version": "^1.0.0", + "installed_version": "1.2.3", + "type": "framework | language | runtime", + "purpose": "What it does", + "documentation": "https://docs.example.com/", + "github": "https://github.com/org/repo", + "usage": [ + "How it's used in this project" + ], + "key_modules": [ + "@scope/package/module.js" + ], + "compiler_options": { + "target": "ES2022", + "module": "Node16" + } + } + ], + "build_tools": [ + { + "name": "Tool Name", + "package": "package-name", + "version": "^1.0.0", + "installed_version": "1.2.3", + "type": "build_tool", + "purpose": "What it does", + "documentation": "https://docs.example.com/", + "github": "https://github.com/org/repo", + "usage": [ + "How it's used" + ], + "config_file": "vite.config.ts", + "npm_scripts": [ + "pnpm run build - Build the project" + ] + } + ], + "testing_frameworks": [ + { + "name": "Jest", + "package": "jest", + "version": "^29.0.0", + "installed_version": "29.7.0", + "type": "testing", + "purpose": "Unit testing framework", + "documentation": "https://jestjs.io/", + "github": "https://github.com/jestjs/jest", + "usage": [ + "Unit tests for services" + ], + "npm_scripts": [ + "pnpm test - Run tests" + ], + "config_file": "jest.config.cjs" + } + ], + "runtime_dependencies": [ + { + "name": "Node.js", + "version": ">=18.0.0", + "type": "runtime", + "purpose": "JavaScript runtime", + "documentation": "https://nodejs.org/", + "features": [ + "Built-in fetch API", + "ES modules support" + ] + } + ], + "package_managers": [ + { + "name": "pnpm", + "version": ">=8.0.0", + "type": "package_manager", + "documentation": "https://pnpm.io/", + "github": "https://github.com/pnpm/pnpm", + "lock_file": "pnpm-lock.yaml", + "lock_file_version": "9.0", + "usage": "Install dependencies, run npm scripts" + } + ], + "services_and_apis": [ + { + "name": "External API Name", + "version": "v3", + "type": "external_api", + "purpose": "What it's used for", + "documentation": "https://api.docs.example.com/", + "base_url": "Configured via ENV_VAR", + "authentication": "OAuth2 / API Key / Basic Auth", + "environment_variables": [ + { + "name": "API_KEY", + "description": "API authentication key", + "required": true + } + ], + "endpoints_available": [ + "List of available endpoints" + ] + } + ], + "source_code_structure": { + "root_directory": "/path/to/project", + "entry_points": { + "main": "src/index.ts" + }, + "directories": { + "src": { + "description": "Source code", + "subdirectories": [ + { + "path": "src/services/", + "description": "Business logic" + } + ] + } + } + }, + "bin_entries": { + "cli-command": "./build/index.js" + }, + "key_features": [ + "Feature 1", + "Feature 2" + ], + "data_formats": [ + { + "name": "JSON", + "purpose": "API communication", + "encoding": "UTF-8" + } + ], + "tools_available": [ + { + "name": "tool_name", + "description": "What it does", + "parameters": [ + { + "name": "param", + "type": "string", + "required": true, + "description": "Parameter description" + } + ] + } + ], + "development_setup": { + "prerequisites": [ + "Node.js v18+" + ], + "installation": [ + "pnpm install", + "pnpm build" + ], + "scripts": { + "build": "vite build", + "dev": "vite", + "test": "jest" + } + }, + "error_handling": { + "strategies": [ + "Error strategy 1" + ], + "implementation": "How errors are handled" + }, + "performance_optimizations": [ + "Optimization 1" + ], + "dependencies_summary": { + "production": 10, + "development": 5, + "total": 15, + "production_packages": [ + "package@version" + ], + "dev_packages": [ + "dev-package@version" + ] + }, + "configuration_files": [ + { + "file": "package.json", + "purpose": "Project metadata" + } + ], + "external_documentation": [ + { + "title": "Documentation Title", + "url": "https://docs.example.com/" + } + ], + "github_repositories": [ + { + "name": "Repository Name", + "url": "https://github.com/org/repo" + } + ], + "security_considerations": [ + "Security consideration 1" + ], + "scalability_features": [ + "Scalability feature 1" + ], + "last_updated": "2024-01-15", + "metadata": { + "generated_by": "spec-tech-stack-maintainer agent", + "format_version": "1.0", + "completeness": "comprehensive", + "includes": [ + "Core frameworks and dependencies", + "Build and testing tools", + "External APIs and services", + "Source code structure", + "Development setup guide" + ] + } +} +``` + +## Framework Type Reference + +### Core Framework Types +| Type | Use For | +|------|---------| +| `framework` | MCP SDK, React, Express, FastAPI | +| `language` | TypeScript, Python | +| `runtime` | Node.js, Deno, Bun | +| `library` | Supporting libraries | + +### Build Tool Types +| Type | Use For | +|------|---------| +| `build_tool` | Vite, Webpack, esbuild | +| `bundler` | Rollup, Parcel | +| `compiler` | TypeScript, Babel | + +### Testing Types +| Type | Use For | +|------|---------| +| `testing` | Jest, Vitest, Playwright | +| `coverage` | c8, nyc | +| `mocking` | MSW, nock | + +## Category Reference for Simple Packages + +When a package doesn't fit the structured categories above, use: + +| Category | Examples | +|----------|----------| +| `frontend_framework` | react, vue, angular, svelte | +| `backend_framework` | express, fastify, nestjs, flask | +| `database` | pg, mysql2, mongodb, better-sqlite3 | +| `orm` | prisma, drizzle, sequelize, typeorm | +| `testing` | jest, vitest, pytest, playwright | +| `build_tool` | vite, webpack, esbuild, rollup | +| `linter` | eslint, biome, pylint | +| `formatter` | prettier, biome, black | +| `type_checker` | typescript, mypy, pyright | +| `authentication` | passport, next-auth, auth0 | +| `state_management` | zustand, redux, jotai | +| `ui_library` | @mui/material, @chakra-ui/react | +| `css_framework` | tailwindcss, bootstrap | +| `api_client` | axios, ky, fetch | +| `websocket` | ws, socket.io | +| `logging` | winston, pino, morgan | +| `security` | helmet, cors, bcrypt | +| `utilities` | lodash, date-fns, zod, uuid | +| `ai_ml` | @anthropic-ai/sdk, openai, langchain | + +## Quality Checklist + +Before completing, verify: +- [ ] Project metadata extracted (name, description, license) +- [ ] All dependency files identified and parsed +- [ ] Both specified and installed versions captured +- [ ] Core frameworks documented with usage details +- [ ] Build tools documented with config files and scripts +- [ ] Testing frameworks documented with test locations +- [ ] External APIs documented with auth and endpoints +- [ ] Source code structure mapped with entry points +- [ ] Key features listed +- [ ] Development setup documented +- [ ] Configuration files listed +- [ ] GitHub and documentation URLs are valid +- [ ] Security considerations documented +- [ ] JSON is valid and matches schema +- [ ] File written to `.alphaAgent/spec/tech-stack.json` + +## Handling Different Project Types + +### MCP Server Projects +Include: +- `tools_available` with all MCP tool definitions +- `data_formats` for any custom formats +- `bin_entries` for CLI commands + +### Web Applications +Include: +- Client and server entry points separately +- Authentication services +- WebSocket configuration if applicable + +### CLI Tools +Include: +- `bin_entries` for all commands +- Command-line argument parsing libraries + +### Libraries +Include: +- Export structure +- Peer dependencies +- Type definitions + +## Handling Missing Information + +If you cannot find documentation or GitHub links: +- Set the field to `null` +- Do NOT guess or make up URLs +- Continue processing other packages + +## Error Handling + +If tech stack extraction fails: +1. Log the specific error +2. Create minimal tech-stack.json with what was found +3. Continue with other discovery tasks +4. Do NOT leave files empty or invalid diff --git a/.claude/commands/issue-triage.md b/.claude/commands/issue-triage.md new file mode 100644 index 00000000000..e8797d0b69e --- /dev/null +++ b/.claude/commands/issue-triage.md @@ -0,0 +1,123 @@ +--- +name: issue-triage +description: Triage GitHub issues - analyze relevance, close fixed/outdated issues, or create Linear tickets +--- + +# Issue Triage Command + +Analyze GitHub issues to determine if they're still relevant. Close resolved issues or create Linear tickets for valid ones. + +## Usage + +```bash +# Triage a single issue +/issue-triage 278 + +# Triage multiple issues (processed in parallel) +/issue-triage 278 316 331 343 + +# Triage all issues without Linear tickets (from CSV) +/issue-triage --pending +``` + +## What This Command Does + +For each issue: +1. **Fetches issue details** from GitHub +2. **Searches codebase** for related code and fixes +3. **Determines relevance** based on code changes and age +4. **Takes action**: + - Close if fixed (with PR/commit reference) + - Close if outdated (architecture changed) + - Create Linear ticket if still valid + +## Single Issue Mode + +```bash +/issue-triage 278 +``` + +Launches `github-issue-triager` agent to analyze issue #278. + +**Output:** +``` +TRIAGE COMPLETE +Issue: #278 +Title: [BUG] Clone Sidekick from Chats Page Redirects Incorrectly +Action: CREATE_TICKET +Result: Created AGENT-650 +Details: Click event propagation bug still present in ChatCard component +``` + +## Batch Mode (Parallel) + +```bash +/issue-triage 278 316 331 343 +``` + +Launches multiple `github-issue-triager` agents in parallel, one per issue. + +**Output:** +``` +Triaging 4 issues in parallel... + +Issue #278: Created AGENT-650 (bug still exists) +Issue #316: Closed (feature implemented in PR #567) +Issue #331: Created AGENT-651 (UX improvement valid) +Issue #343: Closed (outdated - chatflow list refactored) + +Summary: 2 tickets created, 2 issues closed +``` + +## Pending Issues Mode + +```bash +/issue-triage --pending +``` + +Reads from `github_issues_linear_status.csv` and triages all issues marked "Create Linear ticket". + +## Integration + +This command uses: +- **Agent**: `github-issue-triager` - Autonomous issue analysis +- **Skills**: + - `github-issue-analysis` - Analysis methodology + - `linear-constants` - Pre-cached Linear configuration + - `ticket-duplicate-detection` - Avoid duplicate tickets + +## Labels Applied + +When creating Linear tickets: +- `Engineering → Github issue` (always) +- `Engineering → Bug` or `Engineering → Feature` (based on content) +- Appropriate product label (AnswerSidekick, AnswerAgent Studio, etc.) + +## Example Workflow + +```bash +# 1. Review issues without Linear tickets +cat github_issues_linear_status.csv | grep "Create Linear ticket" + +# 2. Triage a batch +/issue-triage 278 316 331 343 351 355 + +# 3. Check results +cat github_issues_linear_status.csv | grep "Create Linear ticket" +``` + +## Parallel Execution + +When triaging multiple issues, the orchestrator spawns separate agents: + +```python +# Orchestrator logic +for issue_number in issue_numbers: + Task( + subagent_type="github-issue-triager", + prompt=f"Triage GitHub issue #{issue_number}", + run_in_background=True # Parallel execution + ) +``` + +This allows processing many issues simultaneously. diff --git a/.claude/commands/linear-triage.md b/.claude/commands/linear-triage.md new file mode 100644 index 00000000000..142c0c15b14 --- /dev/null +++ b/.claude/commands/linear-triage.md @@ -0,0 +1,107 @@ +# Linear Ticket Triage Command + +Triage open Linear tickets to find duplicates, check if issues are fixed, and clean up stale tickets. + +## Usage + +``` +/linear-triage [ticket-id] # Triage a specific ticket +/linear-triage --batch 5 # Triage 5 tickets in parallel +/linear-triage --status # Show triage progress +``` + +## Process Overview + +1. **Fetch open tickets** from Linear AGENT team +2. **Analyze each ticket** for: + - Duplicates (same issue, different ticket) + - Fixed issues (resolved but not closed) + - Outdated tickets (stale, no longer relevant) +3. **Take action**: + - Close duplicates (link to original) + - Close fixed issues (with resolution details) + - Close outdated (with explanation) + - Keep open valid issues +4. **Track progress** in CSV + +## CSV Tracking + +Location: `/Users/bradtaylor/Github/theanswer/linear_tickets_triage_status.csv` + +Columns: +- `ticket_id` - Linear ticket identifier (e.g., AGENT-123) +- `title` - Ticket title +- `status` - Current Linear status +- `created` - Creation date +- `age_months` - Age in months +- `labels` - Applied labels +- `triage_status` - PENDING, CLOSED_DUPLICATE, CLOSED_FIXED, CLOSED_OUTDATED, KEPT_OPEN, NEEDS_CLARIFICATION +- `triage_notes` - Action taken or reason +- `duplicate_of` - Original ticket if duplicate +- `fixed_in` - PR/commit if fixed + +## Workflow + +### Initialize (First Run) + +```bash +# Fetch all open tickets and create tracking CSV +mcp__claude_ai_Linear__list_issues with: + team="AGENT" + state="Backlog" OR "Todo" OR "In Progress" + limit=250 +``` + +### Triage Single Ticket + +Use the `linear-ticket-triager` agent: + +``` +Task tool with: + subagent_type="linear-ticket-triager" + prompt="Triage Linear ticket AGENT-{number}" +``` + +### Batch Triage + +Launch multiple agents in parallel: + +``` +Task tool (x5) with: + subagent_type="linear-ticket-triager" + prompt="Triage Linear ticket AGENT-{number}" +``` + +## Agent Behavior + +The `linear-ticket-triager` agent will: + +1. **Fetch ticket details** from Linear +2. **Search for duplicates** using keywords +3. **Check codebase** for fixes +4. **Classify** the ticket +5. **Take action** (close or keep) +6. **Report results** + +## Safety Features + +- Agents only modify the ticket they're triaging +- Cannot create new tickets +- Cannot delete tickets +- All actions logged with comments + +## Status Values + +| Triage Status | Meaning | +|--------------|---------| +| PENDING | Not yet triaged | +| CLOSED_DUPLICATE | Duplicate of another ticket | +| CLOSED_FIXED | Issue has been resolved | +| CLOSED_OUTDATED | No longer relevant | +| KEPT_OPEN | Valid, remains open | +| NEEDS_CLARIFICATION | Awaiting more info | + +## Example Session + +``` +User: /linear-triage --batch 5 \ No newline at end of file diff --git a/.claude/skills/github-issue-analysis.md b/.claude/skills/github-issue-analysis.md new file mode 100644 index 00000000000..eb95e2db39a --- /dev/null +++ b/.claude/skills/github-issue-analysis.md @@ -0,0 +1,314 @@ +--- +name: github-issue-analysis +description: "Patterns for analyzing GitHub issues to determine if they are still relevant or have been fixed" +--- + +# GitHub Issue Analysis Skill + +Systematic methodology for analyzing GitHub issues to determine current relevance and appropriate action. + +## Purpose + +Analyze GitHub issues to determine: +- Is the issue still reproducible/relevant? +- Has it been fixed (find the PR/commit)? +- Does context need updating? +- Should it become a Linear ticket? + +## Analysis Methodology + +### Phase 1: Issue Data Collection + +```bash +# Fetch complete issue details +gh issue view {issue_number} --repo the-answerai/theanswer --json \ + title,body,labels,comments,createdAt,updatedAt,state,author +``` + +Extract from issue: +- **Title**: Main topic/symptom +- **Body**: Detailed description, steps to reproduce +- **Labels**: bug, enhancement, documentation, etc. +- **Comments**: Additional context, workarounds mentioned +- **Created Date**: Age of issue (older = more likely fixed) +- **Updated Date**: Last activity + +### Phase 2: Keyword Extraction + +From issue title and body, extract: + +1. **Component Keywords**: UI elements, features mentioned + - Example: "drawer", "sidebar", "modal", "canvas", "chatflow" + +2. **Error Keywords**: Error messages, stack traces + - Example: "undefined", "null", "404", "500" + +3. **File/Function Keywords**: Specific code references + - Example: "buildChatflow", "AppDrawer.jsx" + +4. **Behavior Keywords**: What's happening vs expected + - Example: "redirects", "crashes", "freezes", "disappears" + +### Phase 3: Codebase Search + +Search for evidence the issue was addressed: + +#### Search for Related Commits + +```bash +# Search commit messages for issue keywords +git log --oneline --all --since="2025-01-01" --grep="{keyword}" + +# Search for GitHub issue references in commits +git log --oneline --all --grep="#{issue_number}" + +# Search for related file changes +git log --oneline --all --since="2025-01-01" -- "**/path/to/component*" +``` + +#### Search for Code Changes + +```bash +# Check if the problematic code pattern still exists +rg "{error_pattern}" --type ts + +# Check if fix patterns were added +rg "stopPropagation|preventDefault" --type tsx + +# Check if component was refactored/deleted +ls -la packages/ui/src/views/{component}/ +``` + +#### Search for Related PRs + +```bash +# Find PRs that mention the issue +gh pr list --repo the-answerai/theanswer --state all --search "#{issue_number}" --json number,title,state,mergedAt + +# Find PRs that touched related files +gh pr list --repo the-answerai/theanswer --state merged --search "{component_name}" --json number,title,mergedAt +``` + +### Phase 4: Issue Classification + +Based on analysis, classify the issue: + +#### Classification: CLOSE_FIXED + +**Criteria:** +- Found commit/PR that explicitly addresses the issue +- Error message/pattern no longer exists in code +- Component was refactored with new implementation +- Issue is very old (6+ months) and core feature works + +**Action:** +```bash +gh issue close {number} --repo the-answerai/theanswer --comment "$(cat <<'EOF' +Closing this issue - it has been addressed. + +**Resolution:** +- Fixed in PR #{pr_number} / commit {commit_hash} +- The {component} was refactored in {month} +- The original error pattern no longer exists + +If you're still experiencing this issue, please open a new issue with current reproduction steps. +EOF +)" +``` + +#### Classification: CLOSE_OUTDATED + +**Criteria:** +- Feature/component no longer exists +- Architecture has fundamentally changed +- Issue references deprecated functionality +- Context is too old to be actionable (12+ months, no activity) + +**Action:** +```bash +gh issue close {number} --repo the-answerai/theanswer --comment "$(cat <<'EOF' +Closing this issue as outdated. + +**Reason:** +- {component/feature} has been significantly refactored since this was reported +- The original context no longer applies to current architecture +- This issue is {age} old with no recent activity + +If this is still a problem, please open a new issue with: +1. Current reproduction steps +2. Expected vs actual behavior +3. Screenshots/logs if applicable +EOF +)" +``` + +#### Classification: CLOSE_CANNOT_REPRODUCE + +**Criteria:** +- Issue lacks sufficient detail to investigate +- No reproduction steps provided +- Reporter hasn't responded to questions +- Appears to be one-off or environment-specific + +**Action:** +```bash +gh issue close {number} --repo the-answerai/theanswer --comment "$(cat <<'EOF' +Closing due to insufficient information to investigate. + +**Reason:** +- Unable to reproduce with the information provided +- No response to clarifying questions (if applicable) +- May have been environment-specific + +If you can still reproduce this issue, please reopen with: +1. Detailed reproduction steps +2. Browser/environment details +3. Screenshots or error logs +EOF +)" +``` + +#### Classification: CREATE_TICKET + +**Criteria:** +- Issue is clearly still relevant +- Codebase search shows problem likely still exists +- Clear reproduction steps or obvious bug +- Feature request is still applicable + +**Action:** +Create Linear ticket using `linear-constants` skill for labels. + +#### Classification: UPDATE_AND_CREATE + +**Criteria:** +- Issue is valid but context needs updating +- Original description references old architecture +- Core problem remains but details changed + +**Action:** +1. Add comment to GitHub issue with updated context +2. Create Linear ticket with current information + +### Phase 5: Linear Ticket Creation + +When creating a ticket, use this template: + +```markdown +## GitHub Issue: #{issue_number} + +**Original Report:** {github_url} +**Reported:** {created_date} +**Reporter:** {author} + +## Summary +{Updated summary based on current codebase understanding} + +## Current State +{What exists in the codebase today} + +## Problem +{Clear description of what's wrong} + +## Expected Behavior +{What should happen} + +## Steps to Reproduce +{Updated steps if original are outdated} + +## Technical Notes +- Relevant files: {file_paths} +- Related components: {components} +- Potential approach: {suggestions} + +## Original Description +{Include original issue body for reference} +``` + +**Required Labels:** +1. `Engineering → Github issue` (always) +2. Type label: `Engineering → Bug` OR `Engineering → Feature` +3. Product label: Based on component (see `linear-constants` skill) + +### Phase 6: Link GitHub to Linear + +After creating Linear ticket: + +```bash +gh issue comment {github_issue_number} --repo the-answerai/theanswer --body "$(cat <<'EOF' +Linear ticket created: [AGENT-{number}](https://linear.app/theanswer/issue/AGENT-{number}) + +This issue is now being tracked in Linear for prioritization and implementation. +EOF +)" +``` + +## Decision Tree + +``` +START: Analyze GitHub Issue #{number} + │ + ├── Is issue < 3 months old? + │ ├── YES → Higher priority to investigate thoroughly + │ └── NO → Check if still relevant to current architecture + │ + ├── Does issue reference existing component/feature? + │ ├── YES → Search for related fixes + │ └── NO → CLOSE_OUTDATED (component removed) + │ + ├── Found related PR/commit that fixes it? + │ ├── YES → CLOSE_FIXED (cite the PR) + │ └── NO → Continue investigation + │ + ├── Does error pattern still exist in code? + │ ├── YES → Likely still an issue + │ └── NO → CLOSE_FIXED (pattern removed) + │ + ├── Is issue clearly described with reproduction steps? + │ ├── YES → CREATE_TICKET + │ └── NO → Can we infer the problem? + │ ├── YES → UPDATE_AND_CREATE + │ └── NO → CLOSE_CANNOT_REPRODUCE + │ + └── END: Take appropriate action +``` + +## Age-Based Heuristics + +| Issue Age | Default Assumption | Override If | +|-----------|-------------------|-------------| +| 0-3 months | Likely still relevant | Clear fix found | +| 3-6 months | Investigate carefully | Component unchanged | +| 6-12 months | Likely outdated | Critical bug, still reproducible | +| 12+ months | Probably outdated | Security issue, data loss | + +## Component Mapping + +Map GitHub issue content to product areas: + +| Keywords | Product Area | Label | +|----------|-------------|-------| +| extension, chrome, browser, popup | AnswerSidekick | `42f0386b-f6bb-4e93-a9d3-4a2d14d22ca2` | +| canvas, node, chatflow, agentflow, flowise | AnswerAgent Studio | `135f1576-19af-4666-9211-1e9e53607130` | +| chat, message, conversation, response | AnswerChat | `739a4541-fd35-419b-8d80-932d4c9b1db9` | +| video, image, csv, bulk, analyzer | AnswerApps | `58a1247d-c485-474c-881b-96e51b016600` | +| document store, vector, embedding, loader | AnswerEngine | `3b81702c-1428-4665-bcbd-1ea0123b3a0c` | +| MCP, tool, credential, integration | AnswerAgent Studio | `135f1576-19af-4666-9211-1e9e53607130` | +| marketplace, template | AnswerAgent Studio | `135f1576-19af-4666-9211-1e9e53607130` | + +## Integration + +Used by: +- `github-issue-triager` agent - Primary consumer +- `/issue-triage` command - Via agent + +## Quality Checklist + +Before taking action on an issue: +- [ ] Fetched complete issue details +- [ ] Searched codebase for related code +- [ ] Searched git history for fixes +- [ ] Checked if component still exists +- [ ] Classified issue appropriately +- [ ] Prepared appropriate comment/ticket +- [ ] Included relevant evidence (PRs, commits) diff --git a/.claude/skills/linear-constants.md b/.claude/skills/linear-constants.md new file mode 100644 index 00000000000..e8c790c8977 --- /dev/null +++ b/.claude/skills/linear-constants.md @@ -0,0 +1,147 @@ +--- +name: linear-constants +description: "Pre-cached Linear configuration - team IDs, label IDs, and status mappings" +--- + +# Linear Constants Skill + +Pre-cached Linear configuration to avoid repeated API calls. Use these constants instead of querying Linear for common lookups. + +## Team Configuration + +```yaml +team: + id: "5436d595-4ca2-4312-8f39-9e02ba251c42" + name: "AnswerAgentAI" + key: "AGENT" +``` + +## Label IDs + +Use these IDs when creating/updating issues with `mcp__claude_ai_Linear__create_issue` or `mcp__claude_ai_Linear__update_issue`. + +### Engineering Labels + +| Label | ID | Description | +|-------|-----|-------------| +| Engineering → Github issue | `2400a57d-9a69-42f6-8e31-82659a6a98be` | Issue created via GitHub | +| Engineering → Bug | `136398d1-b6fc-450d-957d-ec65997ec07a` | Something is broken | +| Engineering → Feature | `1550fe7f-e1c3-4bb9-9ec9-0487ae82c8a7` | New capability | +| Engineering → Improvement | `b16954d1-586e-4dfa-b8c7-f7f0526042ad` | Enhancement to existing | +| Engineering → Maintenance | `30494fa3-c1f1-4bf6-bea8-213811dc5735` | Tech debt, refactoring | +| Engineering → Chore | `6b55301d-c034-4d95-b1f6-bcb31de4b249` | Routine tasks | + +### Product Labels + +| Label | ID | Description | +|-------|-----|-------------| +| Product → AnswerSidekick | `42f0386b-f6bb-4e93-a9d3-4a2d14d22ca2` | Browser extension for Chrome | +| Product → AnswerAgent Studio | `135f1576-19af-4666-9211-1e9e53607130` | Flowise platform, canvas, chatflows | +| Product → AnswerChat | `739a4541-fd35-419b-8d80-932d4c9b1db9` | Chat interface features | +| Product → AnswerApps | `58a1247d-c485-474c-881b-96e51b016600` | Micro apps: video, image, bulk analysis | +| Product → AnswerEngine | `3b81702c-1428-4665-bcbd-1ea0123b3a0c` | Data engine for ingestion, analysis | +| Product → AlphaAgent | `71523ca6-29fa-4642-8cac-80d0ba990bb6` | AI agent product for workflows | + +### Operations Labels + +| Label | ID | Description | +|-------|-----|-------------| +| Ops → Infrastructure | `db3ea833-0312-48d1-812a-2da1909c92b8` | Render, deployments, DevOps | +| Ops → Automation | `5f586dce-3c74-4542-b33d-b1c93280bdcd` | n8n flows, scheduled jobs | +| Ops → Internal Tools | `80a00521-7617-417f-935a-9c77e9371316` | Tools for the team | + +### QA Phase Labels + +| Label | ID | Description | +|-------|-----|-------------| +| QA Phase → Phase 1 - Critical | `3c2bf938-b4c1-4db8-9efc-181e298d1a52` | Must complete before beta | +| QA Phase → Phase 2 - Core Features | `90cc45a2-396d-4722-87c9-d298b92903c5` | Core feature fixes | +| QA Phase → Phase 3 - Completion | `f5a73afe-073f-4cc4-a966-33305c97a793` | Feature completion | +| QA Phase → Phase 4 - Polish | `9a2c98d7-37ab-425f-8d6e-cbaf8659b0aa` | Polish and UX improvements | + +### Other Labels + +| Label | ID | Description | +|-------|-----|-------------| +| Customer Request | `cd13ab88-0204-4725-98cb-124c5141ea01` | Customer-reported issues | +| Support Escalation | `88458312-1114-44a2-921d-d8491c27824c` | Issues from support | +| Tech Debt | `73a5392d-b246-42bb-a1f8-8aa5c8d120c3` | Refactoring, cleanup | +| Sprint | `d2e09492-3217-4bb3-a64b-a095f5bc49c2` | Part of weekly sprint | +| Release | `0d509bd7-236a-434a-970d-7f1eaac1e8e3` | Part of a release | + +## Status Names + +Linear uses these status names (case-sensitive): + +```yaml +statuses: + - Backlog + - Todo + - In Progress + - In Review + - QA / Staging + - Blocked + - Done + - Canceled +``` + +## Usage Examples + +### Creating Issue with Labels + +```python +# Use label names directly - Linear MCP resolves them +mcp__claude_ai_Linear__create_issue( + title="Fix authentication bug", + team="AGENT", + labels=["Engineering → Bug", "Engineering → Github issue"] +) + +# Or use IDs for performance (no lookup needed) +mcp__claude_ai_Linear__create_issue( + title="Fix authentication bug", + team="AGENT", + labels=["136398d1-b6fc-450d-957d-ec65997ec07a", "2400a57d-9a69-42f6-8e31-82659a6a98be"] +) +``` + +### Product Label Selection + +Choose product label based on GitHub issue content: + +| Keywords in Issue | Product Label | +|-------------------|---------------| +| extension, chrome, browser, sidekick | Product → AnswerSidekick | +| canvas, chatflow, agentflow, studio, flowise | Product → AnswerAgent Studio | +| chat, conversation, message | Product → AnswerChat | +| video, image, bulk, csv, analyzer | Product → AnswerApps | +| MCP, tool, integration | Product → AnswerAgent Studio | +| document store, vector, embedding | Product → AnswerEngine | + +### Issue Type Mapping + +Map GitHub labels to Linear labels: + +| GitHub Label | Linear Label | +|--------------|--------------| +| bug | Engineering → Bug | +| enhancement, feature | Engineering → Feature | +| documentation | Engineering → Maintenance | +| good first issue | (no equivalent) | +| (no label, is bug) | Engineering → Bug | +| (no label, is feature) | Engineering → Feature | + +## Integration + +Used by: +- `github-issue-triager` agent - For creating Linear tickets efficiently +- Any agent that creates/updates Linear issues + +## Maintenance + +**Last updated:** 2026-01-24 + +To refresh these constants: +1. Query `mcp__claude_ai_Linear__list_issue_labels` +2. Query `mcp__claude_ai_Linear__get_team` with query="AGENT" +3. Update this file with new IDs diff --git a/.claude/skills/linear-ticket-analysis.md b/.claude/skills/linear-ticket-analysis.md new file mode 100644 index 00000000000..daa8d9cdc8d --- /dev/null +++ b/.claude/skills/linear-ticket-analysis.md @@ -0,0 +1,134 @@ +# Linear Ticket Analysis Skill + +Methodology for analyzing Linear tickets to find duplicates, check relevance, and determine if issues have been fixed. + +## Analysis Steps + +### 1. Extract Key Information + +From each Linear ticket, identify: +- **Title and description** - Core problem statement +- **Keywords** - Component names, error messages, feature names +- **Labels** - Bug, Feature, product area +- **Created date** - Age of ticket +- **Status** - Current workflow state +- **Related tickets** - Already linked duplicates/relations +- **GitHub links** - Associated GitHub issues + +### 2. Duplicate Detection + +Search for potential duplicates by: + +``` +mcp__claude_ai_Linear__list_issues with: + query="{keywords}" + team="AGENT" + limit=20 +``` + +**Duplicate indicators:** +- Same error message or component +- Similar title (>70% word overlap) +- Same root cause described differently +- Created within days of each other +- Same reporter + +**NOT duplicates:** +- Related but distinct issues +- Same component, different bugs +- Follow-up issues with new scope + +### 3. Codebase Investigation + +For bugs, search for fixes: + +```bash +# Search git history for ticket references +git log --oneline --all --since="2025-01-01" --grep="AGENT-{number}" + +# Search for keyword-related commits +git log --oneline --all --since="2025-01-01" --grep="{keyword}" + +# Check if error pattern still exists +rg "{error_pattern}" --type ts +``` + +For features, check implementation status: + +```bash +# Search for component/feature implementation +rg "{feature_keyword}" --type ts --type tsx + +# Check for related PRs +gh pr list --repo the-answerai/theanswer --state merged \ + --search "AGENT-{number}" --json number,title,mergedAt +``` + +### 4. Classification Criteria + +#### CLOSE_DUPLICATE +- Another ticket covers same issue +- Original ticket is more complete/active +- Link to original before closing + +#### CLOSE_FIXED +- Found PR/commit addressing the issue +- Error pattern no longer in codebase +- Feature has been implemented + +#### CLOSE_OUTDATED +- Ticket is 6+ months old with no activity +- Component/feature no longer exists +- Requirements have fundamentally changed + +#### KEEP_OPEN +- Issue still exists in codebase +- Feature not yet implemented +- Clear path to resolution + +#### NEEDS_CLARIFICATION +- Insufficient detail to investigate +- Unclear requirements +- Add comment requesting more info + +### 5. Status Transitions + +When closing tickets, use appropriate status: +- `Done` - For fixed/implemented issues +- `Canceled` - For duplicates, outdated, won't fix + +## Label Reference + +### Product Labels (from linear-constants skill) +- AnswerSidekick: `42f0386b-f6bb-4e93-a9d3-4a2d14d22ca2` +- AnswerAgent Studio: `135f1576-19af-4666-9211-1e9e53607130` +- AnswerChat: `739a4541-fd35-419b-8d80-932d4c9b1db9` +- AnswerApps: `2d70e80f-7db9-4e5e-9781-1dc3cc3b6e08` +- AnswerEngine: `91fbd9d7-4b04-4c92-8f4e-e90d8077e3ca` + +### Type Labels +- Bug: `136398d1-b6fc-450d-957d-ec65997ec07a` +- Feature: `1550fe7f-e1c3-4bb9-9ec9-0487ae82c8a7` +- Improvement: `68a2e6d0-d15b-4491-8829-5c6f4620e97c` +- Github issue: `2400a57d-9a69-42f6-8e31-82659a6a98be` + +## Output Format + +For each analyzed ticket: + +``` +TICKET: AGENT-{number} +TITLE: {title} +AGE: {months} months +STATUS: {current_status} +LABELS: {labels} + +ANALYSIS: +- Duplicate check: {result} +- Codebase check: {result} +- Relevance: {assessment} + +RECOMMENDATION: {CLOSE_DUPLICATE | CLOSE_FIXED | CLOSE_OUTDATED | KEEP_OPEN | NEEDS_CLARIFICATION} +REASON: {brief explanation} +ACTION: {what to do} +``` diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..ef1343248c3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,1929 @@ +# Changelog + +All notable changes to this project are documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +--- + +## [2.2.9](https://github.com/the-answerai/theanswer/compare/v2.2.8...v2.2.9) (2026-02-04) + +### Bug Fixes + +* **AGENT-582:** fix chat selector not switching chatflows when viewing previous chat ([c17d792](https://github.com/the-answerai/theanswer/commit/c17d79281d0f1d0244a331909a01a493d79caa22)) +* **AGENT-670:** add self-healing validation to fast path steps ([cffe384](https://github.com/the-answerai/theanswer/commit/cffe38493c69a7e34adf029341fe90155fda1621)) +* **AGENT-670:** address PR review feedback ([10eee70](https://github.com/the-answerai/theanswer/commit/10eee7027d9e9d0bc4b44274eff815434e9f184a)) +* **AGENT-670:** fix race conditions in auth middleware, add tests ([dc79650](https://github.com/the-answerai/theanswer/commit/dc7965074d403bb187b054b22ac9a36fa5cba5f0)) +* **AGENT-670:** optimize auth middleware with fast path, remove org overwrite ([3d7f419](https://github.com/the-answerai/theanswer/commit/3d7f419c8f58b333ba404de5b233e59794a24068)) +* **guardrails:** apply Fiddler guardrails to embed endpoint ([65621e8](https://github.com/the-answerai/theanswer/commit/65621e8f8654d9b62a0bd169e54cd440d18aa80a)) + +--- + +## [2.2.8](https://github.com/the-answerai/theanswer/compare/v2.2.7...v2.2.8) (2026-01-28) + +### Bug Fixes + +* **SUPPORT-5:** add ConfirmDialog and persist disconnect to API ([4cb3541](https://github.com/the-answerai/theanswer/commit/4cb354130f23bddeac6134273ac290e7e012c9b1)) +* **SUPPORT-5:** auto-save on credential connect ([25c750d](https://github.com/the-answerai/theanswer/commit/25c750d1f3979d306cbc187a3c0136ce45f32015)) +* **SUPPORT-5:** use contained secondary for credential action buttons ([f8c00c8](https://github.com/the-answerai/theanswer/commit/f8c00c82a237b2d12ecbf5063c9e5a7072433d3e)) + +--- + +## [2.2.7](https://github.com/the-answerai/theanswer/compare/v2.2.6...v2.2.7) (2026-01-28) + +### Bug Fixes + +* admin dashboard grid and guardrails credential management ([e74f76e](https://github.com/the-answerai/theanswer/commit/e74f76ef5b2654ed76b4f9da4e32a30a112257b4)) +* **SUPPORT-5:** add edit loading state, disconnect guard, and typed dialog props ([61e9bfa](https://github.com/the-answerai/theanswer/commit/61e9bfaed5d54469a57278577907efd90b1c4ef0)) +* **SUPPORT-5:** add error snackbar on credential load, responsive admin grid, allow disconnect when disabled ([b92d38f](https://github.com/the-answerai/theanswer/commit/b92d38fba873088c7ae44a4a5707ce6afe0976b7)) +* **SUPPORT-5:** document credential count logic, show ID in read-only mode ([96bca88](https://github.com/the-answerai/theanswer/commit/96bca885727e7a3ddb87e866f11ebc85d312cb34)) +* **SUPPORT-5:** fix loading race condition and add error snackbars ([0ff2721](https://github.com/the-answerai/theanswer/commit/0ff2721979a9943355fd11b8175bc7919f973a73)) +* **SUPPORT-5:** pass credential as data prop for edit dialog ([cb25d1a](https://github.com/the-answerai/theanswer/commit/cb25d1a1c7f717f564f2a009d54156d3cd501d3d)) +* **SUPPORT-5:** refine read-only state with disconnect/change and edit modal ([78743c0](https://github.com/the-answerai/theanswer/commit/78743c08c08c8cc448483e4b05cff368155e9564)) +* **SUPPORT-5:** show read-only state for cross-workspace Fiddler credentials ([c589c90](https://github.com/the-answerai/theanswer/commit/c589c901a0c133013eaefb1ded7be2a15a8ca909)) + +### Code Refactoring + +* **SUPPORT-5:** clean up MasterConfig snackbar helpers, types, and dead code ([45398d3](https://github.com/the-answerai/theanswer/commit/45398d30eea02f0bf451d9505f16a67e4e1fc3b9)) + +--- + +## [2.2.6](https://github.com/the-answerai/theanswer/compare/v2.2.5...v2.2.6) (2026-01-26) + +### Bug Fixes + +* **AGENT-586:** fix AppDrawer overlapping page content ([455dc39](https://github.com/the-answerai/theanswer/commit/455dc39f4cc4072fe85614603cdb47bd808bf496)) +* **AGENT-586:** remove unnecessary zIndex from AppDrawer ([4ff5e4e](https://github.com/the-answerai/theanswer/commit/4ff5e4e69e2cc64de9b5280937d29b6d5d00a8c6)) +* exclude scripts directory from eslint ([3809952](https://github.com/the-answerai/theanswer/commit/3809952ad67cd2d531095c1902224c0266ee3209)) +* resolve all eslint lint errors ([4e28dd6](https://github.com/the-answerai/theanswer/commit/4e28dd6c8b041ab2e718f4eecaf581a3217e8310)) +* resolve remaining lint errors for CI ([52fbf2f](https://github.com/the-answerai/theanswer/commit/52fbf2f100cf9498668ad1f23f7ab362ae74da5a)) +* simplify no-console rule to always be warning ([8e273f3](https://github.com/the-answerai/theanswer/commit/8e273f38838098f30a17dba6765501b8efa423dd)) +* **SUPPORT-18:** auto-detect JWT tokens in browser extension requests ([a9e895e](https://github.com/the-answerai/theanswer/commit/a9e895ee6964dfcbdd42eae66fed201200b377f0)) + +--- + +## [2.2.5](https://github.com/the-answerai/theanswer/compare/v2.2.4...v2.2.5) (2026-01-23) + +### Bug Fixes + +* **AGENT-639:** add organizationId alias to buildAgentGraph options ([85b8f80](https://github.com/the-answerai/theanswer/commit/85b8f808f62c36730cc116e91af0e2b9940bbd39)) +* **AGENT-639:** use API key's organizationId for auth context ([0b9e915](https://github.com/the-answerai/theanswer/commit/0b9e9159d919826772360954086478a87e2b4cbc)) + +--- + +## [2.2.4](https://github.com/the-answerai/theanswer/compare/v2.2.3...v2.2.4) (2026-01-23) + +### Bug Fixes + +* **AGENT-639:** pass entity organizationId/workspaceId in vector store options ([734558e](https://github.com/the-answerai/theanswer/commit/734558e289a64137a42078bc561d2c1969edd0e9)) +* **ContentfulLoader:** exclude archived entries from query results ([ee96b8c](https://github.com/the-answerai/theanswer/commit/ee96b8cbfd357249a9ebd6fc66348be28623e983)) + +--- + +## [2.2.3](https://github.com/the-answerai/theanswer/compare/v2.2.2...v2.2.3) (2026-01-22) + +### Bug Fixes + +* **AGENT-559:** add API_HOST validation across all Google OAuth files ([91f96f5](https://github.com/the-answerai/theanswer/commit/91f96f5d7c63c8a99d91c8d795a06e9a8b42bb13)) +* **AGENT-559:** add API_HOST validation for Google OAuth ([66addc9](https://github.com/the-answerai/theanswer/commit/66addc953b3fb55d967aa837d898be41a8fa71d8)) +* **AGENT-559:** use API_HOST for Google OAuth callback URL ([6e2bcff](https://github.com/the-answerai/theanswer/commit/6e2bcff8e44892b495cab35befe60b942f44167e)) + +--- + +## [2.2.2](https://github.com/the-answerai/theanswer/compare/v2.2.1...v2.2.2) (2026-01-22) + +### Bug Fixes + +* **AGENT-639:** include workspaceData in JWT auth req.user ([dad085b](https://github.com/the-answerai/theanswer/commit/dad085b89156a5a0d29dad4f991de6fb2899f6d4)) + +--- + +## [2.2.1](https://github.com/the-answerai/theanswer/compare/v2.2.0...v2.2.1) (2026-01-22) + +### Bug Fixes + +* **AGENT-639:** add organizationId to queryVectorStore options ([ad1c853](https://github.com/the-answerai/theanswer/commit/ad1c853fe22368dfeff6db43f775e106082af384)) +* **AGENT-639:** populate organizationId and userId when creating API keys ([4d51edf](https://github.com/the-answerai/theanswer/commit/4d51edf3f3ed2ded5be25e12afb2162b73949411)) + +--- + +## [2.2.0](https://github.com/the-answerai/theanswer/compare/v2.1.5...v2.2.0) (2026-01-21) + +### Features + +* **AGENT-573:** use default chatflow for chat navigation ([2c10cff](https://github.com/the-answerai/theanswer/commit/2c10cffee73a71239928efdb86d85e3cdd192fe2)) + +### Bug Fixes + +* **AGENT-405:** add /sidekick-studio prefix to agentflow URL after save ([5d93f7c](https://github.com/the-answerai/theanswer/commit/5d93f7ca60f82e12dfa3bdb6b2b9e91036568a63)) +* **AGENT-612:** fix agent avatar images in canvas chat ([56edb2e](https://github.com/the-answerai/theanswer/commit/56edb2e252b53f6f15ae61d8f8fe33b4c9a26cff)) +* **AGENT-617:** forward credential props in recursive NodeInputHandler tab calls ([de1c222](https://github.com/the-answerai/theanswer/commit/de1c22288fb39d47f85dba68055b94fc9a426f27)) +* **AGENT-626:** redirect to Auth0 login instead of non-existent /login route ([6ca5379](https://github.com/the-answerai/theanswer/commit/6ca5379af28b36153430768c1bb70f387215b20a)) +* **AGENT-639:** use workspaceId filter in queryVectorStore ([c26810d](https://github.com/the-answerai/theanswer/commit/c26810d038a47693a6280c88cf78e63688829ff1)) +* **SUPPORT-12:** add enforceAbility middleware and fix response format ([f6c2bbc](https://github.com/the-answerai/theanswer/commit/f6c2bbc26affa19d57da6479107a6cb5fda4d919)) +* **SUPPORT-12:** add multi-tenancy authorization to credential refresh ([72d2704](https://github.com/the-answerai/theanswer/commit/72d27045d69074401d394b4c97cfc5dacad20da0)) +* **SUPPORT-12:** restore AAI credential refresh routes lost in Flowise merge ([34d53a1](https://github.com/the-answerai/theanswer/commit/34d53a1f66aba8b7fe97b70402ea84df3b5527fb)) + +--- + +## [2.1.5](https://github.com/the-answerai/theanswer/compare/v2.1.4...v2.1.5) (2026-01-21) + +### Bug Fixes + +* **AGENT-635:** add IF EXISTS to migration down() for idempotency ([a857c1c](https://github.com/the-answerai/theanswer/commit/a857c1cb142e64e9b9d8085d2df1fcb849d33371)) + +--- + +## [2.1.4](https://github.com/the-answerai/theanswer/compare/v2.1.3...v2.1.4) (2026-01-21) + +### Bug Fixes + +* **AGENT-634:** populate workspace data for API key auth users ([6658da5](https://github.com/the-answerai/theanswer/commit/6658da529f2825f8e021dbc7abe58260ae4abbf5)) +* **AGENT-635:** make AddOrganizationConfig migration idempotent ([655ba49](https://github.com/the-answerai/theanswer/commit/655ba49a61068a91ff1a6b0de1a0911abed2715b)) +* **AGENT-638:** enable Langfuse tracing for agentflows via env vars ([ffe261d](https://github.com/the-answerai/theanswer/commit/ffe261dde1539494f52129de75a2f2703bce4aa2)) + +--- + +## [2.1.3](https://github.com/the-answerai/theanswer/compare/v2.1.2...v2.1.3) (2026-01-21) + +### Bug Fixes + +* **AGENT-633:** custom tools not appearing in agent nodes ([0de0073](https://github.com/the-answerai/theanswer/commit/0de00736d0bfb3658d9e2d25fbea2d4d6329edf5)) + +### Code Refactoring + +* **AGENT-633:** simplify CustomTool to use workspace RBAC ([eded456](https://github.com/the-answerai/theanswer/commit/eded456f5a6d3958837c92f46ad9cf76b170fdf0)) + +--- + +## [2.1.2](https://github.com/the-answerai/theanswer/compare/v2.1.1...v2.1.2) (2026-01-20) + +### Bug Fixes + +* update answeragent-mcp version ([ac710e6](https://github.com/the-answerai/theanswer/commit/ac710e696b7a4950de10042a5325e55777bfa98d)) + +--- + +## [2.1.1](https://github.com/the-answerai/theanswer/compare/v2.1.0...v2.1.1) (2026-01-20) + +### Bug Fixes + +* **components:** remove userId override in dropdowns to respect workspace filtering ([50f01a1](https://github.com/the-answerai/theanswer/commit/50f01a16ba8ce9552d384020770daa64d45280fd)), closes [#853](https://github.com/the-answerai/theanswer/issues/853) + +--- + +## [2.1.0](https://github.com/the-answerai/theanswer/compare/v2.0.1...v2.1.0) (2026-01-19) + +### Features + +* **SUPPORT-9:** add edit and delete credential features to Fiddler guardrails ([0565fc7](https://github.com/the-answerai/theanswer/commit/0565fc773f257a0751540594f0ede69ff0f51be8)) + +### Bug Fixes + +* **AGENT-630:** backup all user-referenced orgs to preserve Auth0 alignment ([f7f6fdf](https://github.com/the-answerai/theanswer/commit/f7f6fdf10b24a2bc0c77d45453eb4a3e290233d4)) +* **AGENT-630:** fix orphaned users' organizationId before workspace creation ([f4a6a29](https://github.com/the-answerai/theanswer/commit/f4a6a2944c775f07661b010efa9fedb30e813373)) +* **AGENT-630:** handle invalid organizationId in AAI migration ([20e3e0e](https://github.com/the-answerai/theanswer/commit/20e3e0eba85ca085cae1c0410c1ebc44a5f617da)) +* **SUPPORT-8:** force Organization visibility for Fiddler credentials ([61bd5b7](https://github.com/the-answerai/theanswer/commit/61bd5b7db4559bcd20f66fbaa118c84d3a571388)) + +--- + +## [2.0.1](https://github.com/the-answerai/theanswer/compare/v2.0.0...v2.0.1) (2026-01-13) + +### Bug Fixes + +* **AGENT-620:** remove email unique constraint from user table ([f90d8d3](https://github.com/the-answerai/theanswer/commit/f90d8d34693a8bea184a9d20327278aaf72e04e3)) + +--- + +## [2.0.0](https://github.com/the-answerai/theanswer/compare/v1.13.0...v2.0.0) (2026-01-13) + +This is a **major release** that upgrades the core Flowise engine from v1.x to **v3.0.11**, introduces **AgentFlow V2**, adds **40+ new components**, and implements critical security fixes for multi-tenant workspace isolation. + +### Table of Contents +- [Breaking Changes](#breaking-changes) +- [Flowise 3.0.11 Upgrade](#flowise-3011-upgrade) +- [AgentFlow V2](#agentflow-v2) +- [New Components](#new-components) +- [Authentication & Multi-Tenancy](#authentication--multi-tenancy) +- [Database Migrations](#database-migrations) +- [UI/UX Improvements](#uiux-improvements) +- [Bug Fixes](#bug-fixes) +- [Security](#security) +- [Infrastructure](#infrastructure) +- [Deprecations](#deprecations) + +--- + +### Breaking Changes + +#### 1. AGENT-589: Cross-Workspace Chat Isolation (CRITICAL SECURITY FIX) + +**Severity:** CRITICAL - Data Leak Vulnerability + +**Vulnerability Description:** + +The previous chat query logic contained an OR condition that allowed users to see chats from ALL workspaces they had ever accessed: + +```typescript +// VULNERABLE CODE (v1.x) +queryBuilder.andWhere( + '(chatflow.workspaceId IN (:...workspaceIds) OR chat.ownerId = :userId)', + { workspaceIds: user.assignedWorkspaces, userId: user.id } +) +``` + +This meant: +- A user in Workspace A could see confidential chats from Workspace B +- Switching workspaces showed a combined view of ALL workspace chats +- Enterprise customers with multiple workspaces had no data isolation +- Compliance requirements (SOC2, HIPAA, GDPR) for data separation were violated + +**The Fix (3-part remediation):** + +**Part 1:** Changed from filtering by all `assignedWorkspaces` to filtering by `activeWorkspaceId` only: +```typescript +// FIXED: Filter by active workspace only +queryBuilder.andWhere( + 'chatflow.workspaceId = :activeWorkspaceId', + { activeWorkspaceId: user.activeWorkspaceId } +) +``` + +**Part 2:** Removed the OR condition with `ownerId` entirely - workspace now determines visibility: +```typescript +// No more fallback to ownerId - workspace is the boundary +if (!user.activeWorkspaceId) { + // Security default: no workspace = no data + queryBuilder.andWhere('1 = 0') +} +``` + +**Part 3:** Added user ownership filter to prevent cross-user access within workspace: +```typescript +// Users only see their OWN chats +queryBuilder.andWhere('chat.ownerId = :userId', { userId: user.id }) +``` + +**New Behavior:** +| Scenario | v1.x Behavior | v2.0.0 Behavior | +|----------|--------------|-----------------| +| User switches from Workspace A to B | Sees chats from A AND B | Sees ONLY chats from B | +| User has no active workspace | Sees all owned chats | Sees NO chats (security default) | +| User views workspace chats | Sees all workspace chats | Sees only their OWN chats | +| Admin views workspace | Sees all organization chats | Sees only active workspace chats | + +**Migration Impact:** +- Users will no longer see chats from other workspaces +- Historical chats remain in database but are filtered by workspace +- If users need access to old chats, they must switch to the correct workspace +- **This is intentional for data isolation and security compliance** + +**Affected Files:** +- `packages/server/src/services/chat-messages/index.ts` +- `packages/server/src/services/chatflows/index.ts` + +**Commits:** `320175295`, `a1a2bfd49`, `d5a57fce3` + +--- + +#### 2. AGENT-593: Chatflow Configuration Data Loss (CRITICAL DATA INTEGRITY FIX) + +**Severity:** CRITICAL - Silent Data Loss + +**Vulnerability Description:** + +When importing/exporting chatflows, critical configuration fields were silently dropped due to missing field mappings. Users would export a fully configured chatflow and import it with missing settings. + +**Fields That Were Lost:** +- `answersConfig` - TheAnswer-specific configuration +- `browserExtConfig` - Browser extension settings +- `chatbotConfig` - Chatbot widget configuration +- `speechToText` - STT settings +- `textToSpeech` - TTS settings +- `followUpPrompts` - Follow-up prompt configuration +- `apiConfig` - API settings +- `analytic` - Analytics configuration + +**Impact:** +- Users lost hours of configuration work on import +- Exported chatflows were incomplete +- Migrating between environments required manual reconfiguration +- No warning or error was shown + +**The Fix:** + +Added all missing fields to `handleLoadFlow` in both canvas and agentflowsv2: + +```typescript +// Now preserves ALL configuration +if (flowData.answersConfig) chatflow.answersConfig = flowData.answersConfig +if (flowData.browserExtConfig) chatflow.browserExtConfig = flowData.browserExtConfig +if (flowData.chatbotConfig) chatflow.chatbotConfig = flowData.chatbotConfig +if (flowData.speechToText) chatflow.speechToText = flowData.speechToText +if (flowData.textToSpeech) chatflow.textToSpeech = flowData.textToSpeech +if (flowData.followUpPrompts) chatflow.followUpPrompts = flowData.followUpPrompts +if (flowData.apiConfig) chatflow.apiConfig = flowData.apiConfig +if (flowData.analytic) chatflow.analytic = flowData.analytic +``` + +**Commits:** `cf5dfa450`, `2b7a67501`, `2bb834d99` + +--- + +#### 3. Request Header Change (API Breaking Change) + +**Severity:** HIGH - Requires Client Code Updates + +All API requests from the web app now use a new authentication header: + +```typescript +// BEFORE (v1.x) +headers: { 'x-request-from': 'internal' } + +// AFTER (v2.0.0) +headers: { 'x-request-from': 'aai' } +``` + +**Why This Changed:** + +The new `aai` header triggers Auth0 RS256 JWT verification as the primary authentication method, providing: +- Stronger cryptographic verification +- Better alignment with Auth0 standards +- Clear separation from enterprise HS256 authentication + +**Files That Must Be Updated:** + +Any custom integrations or clients making direct API calls must update their headers: + +| File/Integration | Update Required | +|-----------------|-----------------| +| Custom API clients | Change header value | +| Browser extensions | Change header value | +| External integrations | Change header value | +| Mobile apps | Change header value | + +**Affected AAI Files (already updated):** +- `apps/web/app/(Main UI)/(Chat UI)/chat/[chatId]/page.tsx` +- `apps/web/app/api/images/archive/route.ts` +- `apps/web/app/api/images/generate/route.ts` +- `packages-answers/ui/src/AnswersContext.tsx` +- `packages-answers/ui/src/CsvTransfomer/ProcessCsv.tsx` +- `packages-answers/ui/src/CsvTransfomer/ProcessingHistory.tsx` +- `packages-answers/ui/src/ImageCreator/ImageCreator.Client.tsx` +- `packages-answers/ui/src/Profile/Profile.tsx` +- `packages-answers/ui/src/VideoCreator/VideoCreator.Client.tsx` +- `packages-answers/utils/src/findSidekickById.ts` +- `packages-answers/utils/src/findSidekicksForChat.ts` +- `packages-answers/utils/src/getChats.ts` +- `packages/ui/src/api/client.js` + +--- + +#### 4. AgentFlow V1 Deprecated + +**Severity:** MEDIUM - Migration Recommended + +AgentFlow V1 (Sequential Agents based on LangGraph) is deprecated in favor of AgentFlow V2. + +**What Happens:** +- V1 flows continue to work +- V1 flows are labeled as "Agentflow V1" in the UI +- No new V1 features will be developed +- UI shows migration recommendation + +**V1 vs V2 Incompatibilities:** + +| Aspect | V1 (Sequential Agents) | V2 (AgentFlow) | +|--------|------------------------|----------------| +| Flow Type | `MULTIAGENT` | `AGENTFLOW` | +| State | LangGraph `StateGraph` | Built-in Flow State | +| Memory | External `BaseCheckpointSaver` | Built-in options | +| Execution | `init()` returns LangGraph nodes | `run()` returns output | +| Nodes | 12 node types | 16 node types | + +**Migration Path:** +1. Create new AgentFlow V2 +2. Recreate logic using V2 nodes +3. Test thoroughly +4. Archive V1 flow + +--- + +#### 5. Enterprise Database Schema Restructure (CRITICAL) + +**Severity:** CRITICAL - Requires Database Backup + +The enterprise database schema has been completely restructured to support the new workspace-based RBAC system. + +**Tables Restructured:** + +| Table | Changes | +|-------|---------| +| `user` | New schema: `name`, `email`, `credential`, `tempToken`, `tokenExpiry`, `status`, `createdBy`, `updatedBy` | +| `organization` | New schema: `customerId`, `subscriptionId`, `createdBy`, `updatedBy` | + +**New Tables Created:** + +| Table | Purpose | +|-------|---------| +| `login_method` | SSO configurations per organization | +| `role` | Permission definitions with JSON permissions array | +| `organization_user` | User-organization junction with roleId and status | +| `workspace_user` | User-workspace junction with roleId, status, lastLogin | + +**Migration Process:** + +The migration uses a "sandwich" approach to preserve AAI-specific data: + +1. **`BackupAAIData1737076223690`** (runs FIRST) + - Creates `aai_user_backup` table + - Creates `aai_organization_backup` table + - Preserves: `auth0Id`, `stripeCustomerId`, `organizationId`, `trialPlanId`, `defaultChatflowId` + +2. **`RefactorEnterpriseDatabase1737076223692`** (runs SECOND) + - Restructures user and organization tables + - Creates new junction tables + - **WARNING: This migration has an empty `down()` method - cannot be auto-rolled back** + +3. **`AAIRestoreDataAndCreateWorkspaces1737076223693`** (runs THIRD) + - Restores AAI-specific columns + - Restores data from backup tables + - Creates "Default Workspace" per organization + - Creates "Personal Workspace" per user + - Links users to workspaces via `workspace_user` + +**⚠️ CRITICAL: BACKUP YOUR DATABASE BEFORE MIGRATING** + +--- + +### Flowise 3.0.11 Upgrade + +This release incorporates all changes from Flowise upstream versions 2.2.7 through 3.0.11, representing approximately **400+ commits** of improvements. + +#### Key Upstream Features Included + +| Feature | Description | +|---------|-------------| +| AgentFlow V2 | Complete redesign of multi-agent workflows | +| MCP Updates | Model Context Protocol improvements and SSE support | +| Evaluation System | Dataset-based evaluation for chatflows and agentflows | +| Execution Tracking | Full execution history with shareable links | +| Pagination | New pagination system for large datasets | +| Text-to-Speech | Built-in TTS support | +| Chatflow Versioning | Version tracking and S3 storage support | + +--- + +### AgentFlow V2 + +AgentFlow V2 is a **complete redesign** of the multi-agent workflow system, replacing the LangGraph-based Sequential Agents with a new, more flexible architecture. + +#### What's New in AgentFlow V2 + +| Feature | Description | +|---------|-------------| +| **Simplified Model Config** | Each node selects its own LLM via dropdown (no wiring required) | +| **Built-in Flow State** | State defined in Start node, updateable by any node | +| **Execution Tracking** | Full history with `Execution` entity and shareable links | +| **Form Input Support** | Start node supports form-based input with validation | +| **Rich Variable System** | `{{ $question }}`, `{{ $form.field }}`, `{{ nodeId.output }}`, etc. | +| **Memory Options** | Built-in ephemeral/persistent memory configuration | +| **Human-in-the-Loop** | Native Human Input node for approval workflows | +| **Iteration Support** | Process arrays in parallel or sequence | + +#### New AgentFlow V2 Nodes (16 total) + +| Node | Description | +|------|-------------| +| **Start** | Entry point with chat/form input, state definition | +| **LLM** | Direct LLM invocation with memory options | +| **Agent** | Full agent with tools, knowledge bases, structured output | +| **Condition** | If/Else branching with comparisons | +| **ConditionAgent** | LLM-based routing decisions | +| **Human Input** | Human-in-the-loop approval/rejection | +| **Loop** | Loop back to previous node with max iterations | +| **Iteration** | Process array items in parallel/sequence | +| **HTTP** | HTTP requests (GET/POST/PUT/DELETE/PATCH) | +| **Execute Flow** | Call other chatflows/agentflows | +| **Custom Function** | JavaScript code execution | +| **Tool** | Single tool invocation | +| **Direct Reply** | Send immediate response | +| **Retriever** | Vector store retrieval | +| **Sticky Note** | Canvas annotations | + +#### New Marketplace Templates + +- Agentic RAG V2 +- Deep Research V2 / With Multi-turn / With Subagents +- Agents Handoff +- Email Reply HITL Agent +- Financial Research Agent +- Human In The Loop +- Interacting With API +- Iterations +- SQL Agent +- Simple RAG +- Slack Agent +- Structured Output +- Supervisor Worker +- Translator +- Workplace Chat + +#### Migration from V1 + +V1 Sequential Agent nodes are **NOT compatible** with V2 AgentFlow nodes. Manual migration is required: +- V1 type: `MULTIAGENT` → V2 type: `AGENTFLOW` +- V1 uses LangGraph State → V2 uses Flow State +- V1 requires external memory → V2 has built-in memory + +**Commits:** `7924fbce0` (Feature/agentflow v2), `e17994d8f` (Evaluations for Agentflows) + +--- + +### New Components + +#### New Chat Models + +| Component | Description | Commit | +|-----------|-------------|--------| +| **ChatCometAPI** | Unified API gateway for multiple LLM providers (GPT-5, Claude, Gemini) | `099cf481b` | +| **ChatSambanova** | High-performance AI inference (Llama 3.3 70B default) | `bf1ddc3be` | + +#### Model Updates + +| Model | Commit | +|-------|--------| +| Claude 4, Claude Opus 4.1 | `9bc6bfed6`, `fbae51b26` | +| Claude Sonnet 4.5 | `28b0174ee`, `b50193249` | +| GPT-5 series | `3b1b4dc5f`, `fa15b6873` | +| GPT-4.1 series | `e75c831be` | +| Azure GPT-5/4.1 | `79023c890` | +| Gemini 2.5 Flash | `e35a126b4` | +| Gemini Thinking Budget | `f3d5b7766` | +| Llama 4 on Groq | `5faff5205` | +| AWS Bedrock OSS models | `a5a728fd0` | + +#### New Tools (15+) + +| Tool | Description | Commit | +|------|-------------|--------| +| **AWS SNS** | Publish messages to AWS SNS topics | `32e5b13c4` | +| **AWS DynamoDB KV Storage** | Store/retrieve versioned values with auto-versioning | `736c2b11a` | +| **JSONPathExtractor** | Extract values from JSON using path expressions | `b12647281` | +| **Jira** | Full Jira operations (issues, comments, users, JQL) | `9d9135bed` | +| **Gmail** | Full Gmail operations (drafts, messages, labels, threads) | `30c4180d9` | +| **Google Docs** | Create, read, update documents, text manipulation | `2387a06ce` | +| **Google Calendar** | Calendar event management | `30c4180d9` | +| **Google Drive** | File management | `30c4180d9` | +| **Google Sheets** | Spreadsheet operations | `30c4180d9` | +| **Microsoft Teams** | Channels, chats, messages management | `30c4180d9` | +| **Microsoft Outlook** | Calendars, events, messages | `30c4180d9` | +| **Arxiv** | Search academic papers | - | +| **RequestsPut/Delete** | HTTP PUT and DELETE tools | - | + +#### New Document Loaders + +| Loader | Description | Commit | +|--------|-------------|--------| +| **Oxylabs** | Web scraping via Oxylabs API | `a25c5c451` | +| **Google Sheets** | Load spreadsheet data as documents | - | +| **Microsoft Excel** | Load .xlsx, .xls, .xlsm, .xlsb files | `fbe9f34a6` | +| **Microsoft PowerPoint** | Load PowerPoint files | `fbe9f34a6` | +| **Microsoft Word** | Load Word documents | - | + +#### New Vector Stores + +| Store | Description | Commit | +|-------|-------------|--------| +| **AWS Kendra** | Intelligent search with document retrieval | `af1464f7c` | +| **Teradata VectorStore** | Teradata vector storage support | `ac565b898` | + +#### New MCP Servers + +| Server | Description | Commit | +|--------|-------------|--------| +| **Supergateway MCP** | Run MCP stdio servers over SSE/WebSockets | `954e6c88f` | +| **Teradata MCP** | Remote HTTP streamable MCP for Teradata | `dd284e37c` | + +#### New Credentials (15 total) + +- `AgentflowApi`, `CometApi`, `ElevenLabsApi` +- `GmailOAuth2`, `GoogleCalendarOAuth2`, `GoogleDocsOAuth2`, `GoogleDriveOAuth2`, `GoogleSheetsOAuth2` +- `MicrosoftOutlookOAuth2`, `MicrosoftTeamsOAuth2` +- `OxylabsApi`, `SambanovaApi` +- `TeradataBearerToken`, `TeradataTD2`, `TeradataVectorStoreApi` + +#### Other Notable Additions + +| Component | Description | Commit | +|-----------|-------------|--------| +| Cheerio Web Scraper | Fast web scraping node | `925ca7be8` | +| FireCrawl Extract Tool | Updated Firecrawl with extraction | `572fb31a1` | +| Mem0 Memory Node | Mem0 integration | `13fce4585` | +| Perplexity Node | Perplexity AI integration | `df26e8aef` | +| LiteLLM Component | LiteLLM proxy support | `d75e84709` | +| Text-to-Speech | Built-in TTS | `9b8fee3d8` | +| OpenAI Response API | OpenAI response format support | `b60821964` | +| Gemini Built-In Tools | Native Gemini tools | `f56076813` | + +--- + +### Authentication & Multi-Tenancy + +This release implements a complete overhaul of the authentication and authorization system, adopting Flowise's native RBAC while maintaining Auth0 integration for TheAnswer. + +#### Authentication Architecture Overview + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Request Flow │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Request → Check Whitelist → Check Header → Auth Method │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ Whitelisted │ YES │ Pass │ │ │ │ +│ │ Endpoint? │────▶│ Through │ │ │ │ +│ └──────┬───────┘ └──────────────┘ │ │ │ +│ │ NO │ │ │ +│ ▼ │ │ │ +│ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ x-request- │ aai │ verifyAAI │ │ │ │ +│ │ from header? │────▶│ Token │ │ │ │ +│ └──────┬───────┘ └──────┬───────┘ │ │ │ +│ │ internal │ │ │ │ +│ ▼ ▼ │ │ │ +│ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ Enterprise │ │ Auth0 RS256 │ FAIL│ Enterprise │ │ +│ │ HS256 │ │ JWT Check │────▶│ HS256 │ │ +│ └──────────────┘ └──────────────┘ │ Fallback │ │ +│ │ SUCCESS └──────┬───────┘ │ +│ ▼ │ FAIL │ +│ ┌──────────────┐ ▼ │ +│ │ Enrich User │ ┌──────────────┐ │ +│ │ Data │ │ 401 │ │ +│ └──────────────┘ │ Unauthorized │ │ +│ └──────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +#### Auth0 RS256 JWT Verification (Primary) + +**Location:** `packages/server/src/middlewares/authentication/verifyAAIToken.ts` + +The new `verifyAAIToken` middleware handles `x-request-from: aai` header requests with Auth0 RS256 JWT as the primary verification method. + +**Implementation Details:** + +```typescript +// JWT Configuration +const jwtCheck = auth({ + authRequired: true, + audience: process.env.AUTH0_AUDIENCE, + issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL, + tokenSigningAlg: process.env.AUTH0_TOKEN_SIGN_ALG ?? 'RS256' +}) +``` + +**Authentication Flow:** + +1. **Primary: Auth0 RS256 JWT** + - Validates token signature using Auth0's public key + - Verifies audience matches `AUTH0_AUDIENCE` + - Verifies issuer matches `AUTH0_ISSUER_BASE_URL` + - Extracts `org_id` from token payload + +2. **Fallback: Enterprise HS256** + - Used when Auth0 verification fails + - Maintains backwards compatibility + - Uses passport-based verification + +3. **Failure: 401 Unauthorized** + - No anonymous access allowed + - Both methods must fail to return 401 + +**Organization Validation:** + +```typescript +// Validates user belongs to allowed Auth0 organizations +const userOrgId = authPayload.org_id +const allowedOrgs = process.env.AUTH0_ORGANIZATION_ID?.split(',') +const isValidOrg = userOrgId && allowedOrgs?.includes(userOrgId) + +if (!isValidOrg) { + return res.status(401).json({ + message: "Unauthorized: Organization doesn't match" + }) +} +``` + +**Required Environment Variables:** + +| Variable | Purpose | Example | +|----------|---------|---------| +| `AUTH0_AUDIENCE` | API identifier | `https://api.theanswer.ai` | +| `AUTH0_ISSUER_BASE_URL` | Auth0 tenant URL | `https://theanswer.auth0.com` | +| `AUTH0_TOKEN_SIGN_ALG` | Signing algorithm | `RS256` (default) | +| `AUTH0_ORGANIZATION_ID` | Allowed org IDs | `org_abc123,org_def456` | + +**Commit:** `e689e9b40` + +--- + +#### Workspace-Based RBAC System + +**Location:** `packages/server/src/services/*/index.ts` + +Adopted Flowise's native RBAC system with workspace-based filtering replacing the previous organization-based filtering. + +**Key Changes:** + +| Before (v1.x) | After (v2.0.0) | +|---------------|----------------| +| Filter by `organizationId` | Filter by `workspaceId` | +| Organization-level permissions | Workspace-level permissions | +| Single permission set per user | Role-based permissions per workspace | + +**Service Layer Changes:** + +```typescript +// BEFORE: Organization-based filtering +const chatflows = await repository.find({ + where: { organizationId: user.organizationId } +}) + +// AFTER: Workspace-based filtering +const chatflows = await repository.find({ + where: { workspaceId: user.activeWorkspaceId } +}) +``` + +**Permission Resolution:** + +Permissions are resolved in priority order: + +1. **Auth0 Admin Role** → Wildcard permissions `['*']` +2. **Workspace Role** → Permissions from `role.permissions` JSON +3. **Default** → No permissions (access denied) + +```typescript +// Permission resolution logic +if (roles?.includes('Admin')) { + permissions = ['*'] // Full access +} else if (workspaceData.roleId) { + const role = await RoleRepository.findOne({ + where: { id: workspaceData.roleId } + }) + permissions = JSON.parse(role.permissions) // Role-specific +} +``` + +**RBAC Enforcement:** + +```typescript +// In controllers - enforceAbility middleware +router.get('/', enforceAbility('Chatflow'), controller.getAll) + +// In services - workspace filtering +const chatflows = await queryBuilder + .where('chatflow.workspaceId = :workspaceId', { + workspaceId: user.activeWorkspaceId + }) + .getMany() +``` + +**Commit:** `bc6679fce` + +--- + +#### User Enrichment System + +**Location:** `packages/server/src/aai/auth/enrichUserData.ts` + +Centralized user enrichment logic shared between `/auth/me` endpoint and `aaiPostAuthMiddleware`. + +**Enriched User Data Structure:** + +```typescript +interface EnrichedUserData { + // === User Identity === + id: string // Database user ID + auth0Id?: string // Auth0 subject ID + email: string // User email + name?: string // Display name + + // === Organization Context === + organizationId: string // Primary organization + stripeCustomerId?: string // Stripe customer ID + defaultChatflowId?: string // User's default chatflow + + // === RBAC Fields === + roles: string[] // Auth0 roles (e.g., ['Admin', 'User']) + permissions: string[] // Resolved permissions (e.g., ['chatflow:read', 'chatflow:write']) + + // === Subscription/Billing (Flowise Parity) === + activeOrganizationSubscriptionId: string + activeOrganizationCustomerId: string + activeOrganizationProductId: string + features: Record // Feature flags from subscription + + // === Workspace Fields === + activeWorkspaceId?: string // Currently active workspace + activeOrganizationId?: string // Active organization + activeWorkspace?: string // Workspace name + roleId?: string // Role in active workspace + isOrganizationAdmin?: boolean // Admin status + + // === Workspace List === + assignedWorkspaces?: Array<{ + id: string + name: string + role: string // Role name + organizationId: string + }> +} +``` + +**Enrichment Process:** + +``` +1. Fetch user from database by auth0Id +2. Get organization data with Stripe info +3. Get workspace assignments from workspace_user +4. Resolve permissions from workspace role +5. Get subscription features +6. Return enriched user object +``` + +**Commit:** `8f119fb90` + +--- + +#### AAIAuthProvider for Redux Store + +**Location:** `apps/web/components/AAIAuthProvider.tsx` + +Client component that dispatches `loginSuccess` to Redux store with enriched user data from server-side session. + +**Implementation:** + +```typescript +'use client' +import { useEffect } from 'react' +import { store } from 'flowise-ui/src/store' +import { loginSuccess } from 'flowise-ui/src/store/reducers/authSlice' + +interface AAIAuthProviderProps { + user: EnrichedUserData | null + children: React.ReactNode +} + +export function AAIAuthProvider({ user, children }: AAIAuthProviderProps) { + useEffect(() => { + if (user) { + // Sync Auth0 session to Redux for Flowise UI compatibility + store.dispatch(loginSuccess({ + ...user, + features: user.features || {} + })) + } + }, [user]) + + return <>{children} +} +``` + +**Usage in Layout:** + +```typescript +// apps/web/app/(Main UI)/(Studio Layout)/layout.tsx +export default async function StudioLayout({ children }) { + const session = await getCachedSession() + + return ( + + + {children} + + + ) +} +``` + +**Why This Is Needed:** +- Flowise UI expects user data in Redux store +- Auth0 session is server-side only +- This bridges the gap between server session and client state + +**Commit:** `69909baf1` + +--- + +#### Enterprise Features for Auth0 Admins + +Users with the `Admin` role in Auth0 automatically get all enterprise features enabled: + +```typescript +const features = roles?.includes('Admin') + ? getAllFeaturesEnabled() // All features = true + : getSubscriptionFeatures(organizationId) // Based on subscription +``` + +**Commit:** `50edca5f3` + +--- + +### Workspace System + +This release introduces a comprehensive workspace system for multi-tenant resource isolation. + +#### Workspace Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Organization │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ Default Workspace │ │ +│ │ (Org-level resources, shared across users) │ │ +│ │ │ │ +│ │ • Shared chatflows (visibility: Organization) │ │ +│ │ • Shared credentials │ │ +│ │ • Shared tools │ │ +│ │ • Team-level document stores │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ +│ │ Personal │ │ Personal │ │ Personal │ │ +│ │ Workspace │ │ Workspace │ │ Workspace │ │ +│ │ (User A) │ │ (User B) │ │ (User C) │ │ +│ │ │ │ │ │ │ │ +│ │ • Private │ │ • Private │ │ • Private │ │ +│ │ chatflows │ │ chatflows │ │ chatflows │ │ +│ │ • Private │ │ • Private │ │ • Private │ │ +│ │ credentials │ │ credentials │ │ credentials │ │ +│ └───────────────┘ └───────────────┘ └───────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### Workspace Types + +| Type | Purpose | Created | +|------|---------|---------| +| **Default Workspace** | Organization-level shared resources | Auto-created per organization | +| **Personal Workspace** | User-private resources | Auto-created per user | +| **Custom Workspaces** | Team/project workspaces | Manually created | + +#### Workspace-User Relationship + +```typescript +// workspace_user table structure +interface WorkspaceUser { + id: string + workspaceId: string // FK to workspace + userId: string // FK to user + roleId: string // FK to role (permissions) + status: 'active' | 'inactive' | 'pending' + lastLogin: Date // Last workspace access + createdDate: Date + updatedDate: Date +} +``` + +#### Resource Isolation by Workspace + +All resources are now filtered by `workspaceId`: + +| Resource | Filter | Migration | +|----------|--------|-----------| +| `chat_flow` | `workspaceId = activeWorkspaceId` | Backfilled based on visibility | +| `credential` | `workspaceId = activeWorkspaceId` | Backfilled based on visibility | +| `variable` | `workspaceId = activeWorkspaceId` | Backfilled based on visibility | +| `tool` | `workspaceId = activeWorkspaceId` | Backfilled based on visibility | +| `custom_template` | `workspaceId = activeWorkspaceId` | Backfilled based on visibility | +| `assistant` | `workspaceId = activeWorkspaceId` | Backfilled | +| `document_store` | `workspaceId = activeWorkspaceId` | Backfilled | +| `apikey` | `workspaceId = activeWorkspaceId` | Backfilled | +| `execution` | `workspaceId = activeWorkspaceId` | Backfilled | +| `evaluation` | `workspaceId = activeWorkspaceId` | Backfilled | +| `chat_message` | Inherits from chatflow | Backfilled via chatflow | + +#### Workspace ID Backfill Logic + +During migration, existing resources are assigned to workspaces: + +```typescript +// Migration logic for workspace assignment +if (resource.visibility === 'Organization' || resource.visibility === 'Marketplace') { + resource.workspaceId = defaultWorkspace.id // Shared resource +} else { + resource.workspaceId = personalWorkspace.id // Private resource +} +``` + +#### Workspace Switching + +Users can switch workspaces via: + +1. **Profile Menu** - Inline workspace list with active indicator +2. **API** - `POST /api/workspaces/switch` endpoint + +```typescript +// Workspace switch persists via lastLogin timestamp +await workspaceUserRepository.update( + { userId, workspaceId }, + { lastLogin: new Date() } +) +``` + +#### Multi-Workspace Resource Sharing (AGENT-610) + +New opt-in feature allowing Personal Workspace users to access Default Workspace resources: + +```bash +# Enable in .env +AAI_MULTI_WORKSPACE_SHARING=true +AAI_SHARED_WORKSPACE_NAME="Default Workspace" +AAI_WORKSPACE_DEBUG=true # Optional: Enable debug logging +``` + +**How It Works:** + +The Smart Repository Decorator intercepts queries and expands workspace filters: + +```typescript +// Without sharing: Only personal workspace +WHERE workspaceId = 'personal-ws-123' + +// With sharing enabled: Personal + Default workspace +WHERE workspaceId IN ('personal-ws-123', 'default-ws-456') +``` + +**Use Cases:** +- Share organization tools with all users +- Provide base templates in Default Workspace +- Allow personal customization in Personal Workspace + +**Commit:** `e0d891f47` (AGENT-610) + +--- + +### Database Migrations + +#### Critical: Enterprise Database Refactoring + +**Migration:** `RefactorEnterpriseDatabase1737076223692` + +**New table structures:** + +| Table | Key Changes | +|-------|-------------| +| `user` | New schema with `name`, `email`, `credential`, `status`, audit fields | +| `organization` | New schema with `customerId`, `subscriptionId`, audit fields | +| `login_method` | NEW - SSO configurations per organization | +| `role` | NEW - Permission definitions | +| `organization_user` | NEW - User-organization junction with roles | +| `workspace_user` | NEW - User-workspace junction with roles, `lastLogin` | + +**Required actions:** +1. **BACKUP DATABASE BEFORE MIGRATING** +2. Migrations handle AAI schema differences automatically +3. Creates "Default Workspace" and "Personal Workspace" per organization + +#### AAI Data Migration Sandwich + +1. `BackupAAIData1737076223690` - Preserves `auth0Id`, `stripeCustomerId`, etc. +2. `RefactorEnterpriseDatabase1737076223692` - Main restructure +3. `AAIRestoreDataAndCreateWorkspaces1737076223693` - Restores AAI data, creates workspaces + +#### New Tables + +| Table | Purpose | Migration | +|-------|---------|-----------| +| `evaluation` | Evaluation configurations and results | `AddEvaluation1714548873039` | +| `evaluation_run` | Individual evaluation run results | `AddEvaluation1714548873039` | +| `dataset` | Dataset definitions for evaluations | `AddDatasets1714548903384` | +| `dataset_row` | Individual dataset rows | `AddDatasets1714548903384` | +| `evaluator` | Evaluator definitions | `AddEvaluator1714808591644` | + +#### New Columns + +| Table | Column | Purpose | +|-------|--------|---------| +| `chat_flow` | `textToSpeech` | TTS configuration | +| `chat_flow` | `currentVersion`, `s3Location` | Versioning support | +| `chat_flow` | `templateId` | Template linking | +| `chat_message` | `tracking_metadata` | Analytics tracking | +| `chat_message` | `guardrails_metadata` | Guardrails data | +| `organization` | `organizationConfig` | Organization settings | +| `organization` | `enabledIntegrations` | Integration toggles | +| `user` | `defaultChatflowId` | Default chatflow | + +#### New Indexes + +- `IDX_chatflow_name` on `chat_flow(name)` +- `IDX_custom_template_userId` on `custom_template(userId)` +- `IDX_custom_template_organizationId` on `custom_template(organizationId)` +- `IDX_custom_template_parentId` on `custom_template(parentId)` +- `IDX_chat_flow_templateId` on `chat_flow(templateId)` + +--- + +### UI/UX Improvements + +#### Canvas Improvements + +| Feature | Description | Commit | +|---------|-------------|--------| +| **Grid Toggle** | Toggle background grid on/off | `a0dca552a` | +| **Fuzzy Node Search** | Intelligent search with typo tolerance and ranking | `97515989a` | +| **Snapping Controls** | ReactFlow snapping functionality | `82d60c7d1` | +| **Edge Remove Button** | Remove edges directly | `cd36924bf` | +| **Tooltip on Icons** | Hover tooltips in chatflows/marketplace | `7ef0e99eb` | + +#### Theme and Accessibility + +| Fix | Description | Commits | +|-----|-------------|---------| +| **Light Mode Contrast** | Fixed invisible text in light mode across billing, admin pages | `44d50c55d`, `2bc8a55c2`, `1389c0e04`, `9b72787b3` | +| **WCAG AA Compliance** | All text now meets 4.5:1 contrast ratio | - | + +#### Profile Menu Redesign + +New menu layout with: +- Email header with account switching +- Organization indicator with switch icon +- Inline workspace list with active indicator +- Add teammates (admin/builder only) +- Workspace settings (admin/builder only) +- Personalization (theme toggle) +- User profile card at bottom + +**Commits:** `965801bea`, `06155238a`, `30254fea5` + +#### Marketplace Improvements + +- Autocomplete dropdown for use case selection +- Multi-select chips with overflow indicator +- Tooltip for truncated content +- Better grid spacing + +**Commit:** `9d438529a` + +#### Other UI Fixes + +| Fix | Ticket | Commit | +|-----|--------|--------| +| Modals render above drawer | AGENT-597 | `6c6785e0b` | +| AsyncDropdown width | - | `15dd28356` | +| API Code Dialog for AgentFlow V2 | - | `5dd30b1a7` | +| Snackbar auto-close | - | `12b4259a0` | + +--- + +### Bug Fixes + +#### Critical & High Severity AAI Fixes (Detailed) + +--- + +##### AGENT-589: Cross-Workspace Chat Data Leak (CRITICAL) + +**See:** [Breaking Changes → AGENT-589](#1-agent-589-cross-workspace-chat-isolation-critical-security-fix) + +--- + +##### AGENT-593: Chatflow Configuration Data Loss (CRITICAL) + +**See:** [Breaking Changes → AGENT-593](#2-agent-593-chatflow-configuration-data-loss-critical-data-integrity-fix) + +--- + +##### AGENT-588: Corrupted Images Throughout Application (HIGH) + +**Severity:** HIGH - Visual functionality broken + +**Problem:** PNG images (node icons, tab images in AddNodes panel) displayed as broken/corrupted throughout the application. + +**Root Cause:** A custom webpack rule in `next.config.js` was double-processing images: + +```javascript +// PROBLEMATIC CODE (removed) +{ + test: /\.(png|jpg|gif|svg)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + publicPath: '/_next/static/images/', + outputPath: 'static/images/' + } + } + ] +} +``` + +This rule, combined with `transpilePackages: ['ui']`, caused binary PNG files to be processed twice, corrupting them. + +**The Fix:** + +1. Removed the corrupting 11-line webpack rule from `next.config.js` +2. Simplified `getImage()` function to handle Next.js `StaticImageData`: + +```typescript +// FIXED: Properly handle Next.js static images +export const getImage = (name: string): string | StaticImageData => { + return images[name] || name +} +``` + +**Impact:** +- All node icons display correctly +- AddNodes panel is fully functional +- No more broken image placeholders + +**Commits:** `27a4a29a2`, `143545c9f` + +--- + +##### AGENT-617: Google Drive Document Loader Crashes (HIGH) + +**Severity:** HIGH - Feature completely broken + +**Problem:** Adding Google Drive as a document loader caused a `ReferenceError` crash: + +``` +ReferenceError: selectedCredential is not defined +``` + +**Root Cause:** The credential selection state variables and handler were missing from the component: + +```typescript +// MISSING (caused crash) +const [selectedCredential, setSelectedCredential] = useState(null) +const [selectedCredentialData, setSelectedCredentialData] = useState(null) + +const handleCredentialDataChange = useCallback((credentialData) => { + setSelectedCredentialData(credentialData) +}, []) +``` + +**The Fix:** + +Added missing state and handler to both affected components: + +1. **Direct component fix:** Added state to specific loader component +2. **NodeInputHandler fix:** Applied fix to parent handler for comprehensive coverage + +```typescript +// Added to component +const [selectedCredential, setSelectedCredential] = useState( + nodeData?.inputs?.credential || null +) +const [selectedCredentialData, setSelectedCredentialData] = useState( + nodeData?.inputs?.credentialData || null +) + +const handleCredentialDataChange = useCallback((credentialData: any) => { + setSelectedCredentialData(credentialData) +}, []) +``` + +**Impact:** +- Google Drive document loader works correctly +- Document ingestion workflows are functional +- RAG pipelines with Google Drive sources can be built + +**Commits:** `93034fca3`, `2e21ff60d` + +--- + +##### AGENT-592: Sidekick Selection Broken with Workspace RBAC (HIGH) + +**Severity:** HIGH - Core feature broken + +**Problem:** Two related issues with sidekick selection: + +1. Used `isOwner` check instead of `isExecutable`, breaking workspace-level RBAC +2. JSON parsing crashed on null/undefined values during sidekick switching + +**Root Cause 1:** Owner-based access check: +```typescript +// BROKEN: Only owner could select sidekick +if (chatflow.isOwner) { + // Allow selection +} +``` + +**Root Cause 2:** Unsafe JSON parsing: +```typescript +// CRASHED: No null check +const config = JSON.parse(chatflow.chatbotConfig) // Error if null +``` + +**The Fix:** + +1. Changed to `isExecutable` for proper RBAC: +```typescript +// FIXED: Server handles workspace access filtering +// isExecutable is set to true since server already filters by workspace +if (chatflow.isExecutable) { + // Allow selection +} +``` + +2. Added null checks to JSON parsing: +```typescript +// FIXED: Safe JSON parsing +export function parseFlowData(flowData: string | null | undefined) { + if (!flowData) return null + try { + return JSON.parse(flowData) + } catch (error) { + console.error('Failed to parse flow data:', error) + return null + } +} +``` + +**Impact:** +- Shared sidekicks are accessible to all authorized workspace users +- No crashes when switching sidekicks +- Proper RBAC enforcement + +**Commits:** `a16ef564d`, `ea6f2f6b9` + +--- + +##### AGENT-618: User Variables Section 404 Errors (HIGH) + +**Severity:** HIGH - Feature causes errors + +**Problem:** The User Variables section in the profile page called a non-existent API endpoint (`/api/users`), showing 404 errors when users tried to save. + +**Root Cause:** The UI was implemented before the API: +```typescript +// Called non-existent endpoint +const response = await fetch('/api/users', { + method: 'PATCH', + body: JSON.stringify({ contextFields }) +}) +// Result: 404 Not Found +``` + +**The Fix:** + +Hidden the User Variables section until API is implemented: + +```typescript +// Temporarily hidden with implementation notes +{/* +TODO: User Variables API needed +- POST /api/users/:id/context-fields +- GET /api/users/:id/context-fields +- See AGENT-618 for implementation details +*/} +{false && } +``` + +**Impact:** +- No more confusing 404 errors +- Cleaner UI without non-functional features +- Clear path for future implementation + +**Commit:** `844942177` + +--- + +##### AGENT-598: Light Mode Text Invisible (MEDIUM) + +**Severity:** MEDIUM - Accessibility issue + +**Problem:** Multiple pages had white text hardcoded (`color: '#fff'`), making content invisible in light mode: + +**Affected Pages:** +- Billing Dashboard +- TotalCreditsProgress component +- BillingOverview +- UsageEventsTable +- CostCalculator +- Admin DocumentStores table +- Admin Chatflows table + +**The Fix:** + +Replaced 200+ hardcoded colors with theme-aware values: + +| Before | After | +|--------|-------| +| `color: '#fff'` | `color: theme.palette.text.primary` | +| `color: 'rgba(255,255,255,0.7)'` | `color: theme.palette.text.secondary` | +| `background: 'rgba(0,0,0,0.2)'` | `background: alpha(theme.palette.background.paper, 0.8)` | +| `border: 'rgba(255,255,255,0.1)'` | `border: theme.palette.divider` | + +**Result:** +- WCAG AA compliance (4.5:1 contrast ratio) +- All text readable in both themes +- Consistent theming across application + +**Commits:** `44d50c55d`, `2bc8a55c2`, `1389c0e04`, `9b72787b3` + +--- + +#### AAI-Specific Fixes Summary + +| Severity | Ticket | Description | Status | +|----------|--------|-------------|--------| +| **Critical** | AGENT-589 | Cross-workspace chat data leak | ✅ Fixed | +| **Critical** | AGENT-593 | Chatflow config data loss on import/export | ✅ Fixed | +| **High** | AGENT-588 | Corrupted images throughout app | ✅ Fixed | +| **High** | AGENT-617 | Google Drive loader crashes | ✅ Fixed | +| **High** | AGENT-592 | Sidekick selection broken with RBAC | ✅ Fixed | +| **High** | AGENT-618 | User Variables 404 errors | ✅ Hidden | +| **Medium** | AGENT-598 | Light mode text invisible | ✅ Fixed | +| **Medium** | AGENT-616 | Rate limit config not saving | ✅ Fixed | +| **Medium** | AGENT-609 | Variables page tab switching broken | ✅ Fixed | +| **Medium** | AGENT-614 | Dataset ID extraction failing | ✅ Fixed | +| **Low** | AGENT-597 | Modals behind drawer | ✅ Fixed | +| **Low** | AGENT-615 | Duplicate button | ✅ Fixed | + +--- + +#### Flowise Upstream Fixes (80+) + +**Security Fixes:** +- Path traversal via chatId (`03c1750d7`, `c00ae7848`) +- File path validation (`6e291cf05`) +- Container filesystem vulnerability (`4111ec31b`) +- Insecure link fetching (`e002e617d`) +- Arbitrary file upload (`c2b830f27`) +- ID validation for imports (`f963e5aa4`) + +**AgentFlow/Sequential Agents:** +- Supervisor Node with Azure OpenAI (`94cae3b66`) +- Iteration blocking after human input (`62d34066c`) +- Human Input as first node (`6e2f2df26`) +- Agent/LLM nodes when streaming off (`68dc041d0`) +- State interpolation (`bbcfb5ab6`) +- AgentflowV2 State management (`01dab4365`) +- Past image retrieval (`6cf1c82f0`) +- Redis event subscription (`10f85ef47`) + +**Chat Models:** +- Anthropic package issues (`a92f7dfc3`) +- Gemini empty contents error (`fc50f2308`) +- Gemini structured output (`2e42dfb63`) +- Gemini image input (`d06b7d7ae`) +- AWS Bedrock vision model override (`ddba891dc`) + +**Vector Stores:** +- Weaviate metadata special chars (`7dfa26950`) +- Vector store config not saving (`a6506b3bf`) +- PGVectorStore base class retrieval (`3bd2d63a1`) + +**API/Backend:** +- CORS configuration (`fd7fc2f4d`) +- Redis socket crashes (`4326cbe6b`) +- Redis idle timeout (`eadf1b11b`) +- PostgreSQL Record Manager (`7e7ff2494`, `e467d0615`) +- Duplicate metrics in Prometheus/OpenTelemetry (`3098c8e75`) + +**Parsing/Data:** +- Zod schema parsing (`4417102f6`) +- JSON metadata parsing (`601de76ae`) +- JSON5 parsing (`4af067a44`) +- Iteration JSON parsing (`44087bc70`) +- Null byte import errors (`9e743e4aa`) + +--- + +### Security + +This release includes **15+ security fixes** addressing critical vulnerabilities including path traversal, arbitrary file upload, SSRF, session fixation, and credential leakage. + +--- + +#### Critical Security Fixes + +##### 1. Path Traversal via chatId (CRITICAL) + +**Vulnerability:** Attackers could use specially crafted `chatId` parameters to access files outside the intended directory. + +**Attack Vector:** +``` +GET /api/v1/chatmessages?chatId=../../../etc/passwd +``` + +**Fix:** Added path traversal validation to `chatId` parameter: + +```typescript +// packages/server/src/utils/validateChatId.ts +export function validateChatId(chatId: string): boolean { + // Block path traversal attempts + if (chatId.includes('..') || chatId.includes('/') || chatId.includes('\\')) { + throw new InternalFlowiseError( + StatusCodes.BAD_REQUEST, + 'Invalid chatId format' + ) + } + return true +} +``` + +**Commits:** `03c1750d7`, `c00ae7848` + +##### 2. File Path Validation (CRITICAL) + +**Vulnerability:** Insufficient file path validation allowed access to unauthorized files. + +**Fix:** Enhanced file path validation and sanitization: + +```typescript +// Validates paths don't escape allowed directories +function validateFilePath(filePath: string, allowedBase: string): boolean { + const normalizedPath = path.normalize(filePath) + const resolvedPath = path.resolve(allowedBase, normalizedPath) + return resolvedPath.startsWith(path.resolve(allowedBase)) +} +``` + +**Commit:** `6e291cf05` + +##### 3. Arbitrary File Upload (CRITICAL) + +**Vulnerability:** Attachment creation endpoint allowed uploading files with arbitrary paths, potentially overwriting system files. + +**Fix:** Restricted file upload to designated directories with extension validation. + +**Commit:** `c2b830f27` + +##### 4. Container Filesystem Vulnerability (HIGH) + +**Vulnerability:** Docker compose configuration (`metrics/otel/compose.yaml`) allowed unauthorized file modifications within the container. + +**Fix:** Restricted container filesystem permissions and implemented non-root execution. + +**Commit:** `4111ec31b` + +##### 5. Insecure Link Fetching (HIGH) + +**Vulnerability:** Links were fetched without proper URL validation, allowing SSRF attacks. + +**Fix:** Added URL validation before fetching external resources. + +**Commit:** `e002e617d` + +##### 6. Import ID Validation (MEDIUM) + +**Vulnerability:** Imported data IDs were not validated, allowing injection attacks. + +**Fix:** All imported IDs are now validated against expected formats. + +**Commit:** `f963e5aa4` + +--- + +#### SSRF Protection (Server-Side Request Forgery) + +**New Feature:** HTTP Deny List + +Prevents SSRF attacks by blocking requests to internal/private IP ranges: + +```bash +# .env configuration +HTTP_DENY_LIST=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8,169.254.0.0/16 +``` + +**Implementation:** + +```typescript +// packages/components/src/httpSecurity.ts +import { isIPInCIDR } from './utils' + +export function validateURL(url: string): void { + const denyList = process.env.HTTP_DENY_LIST?.split(',') || [] + const parsedUrl = new URL(url) + const resolvedIP = dns.resolve(parsedUrl.hostname) + + for (const cidr of denyList) { + if (isIPInCIDR(resolvedIP, cidr)) { + throw new Error(`Request to ${url} blocked by HTTP_DENY_LIST`) + } + } + + // Also validates redirect chains +} +``` + +**Protected Against:** +- Access to internal services (localhost, 10.x.x.x, 192.168.x.x) +- Cloud metadata endpoints (169.254.169.254) +- Internal Kubernetes services +- Docker host networking attacks + +**Commits:** `0998bf432`, `a3f47af02`, `d081221a9` + +--- + +#### Session Security + +##### Session Fixation Prevention + +**Vulnerability:** Session tokens were not regenerated after authentication, allowing session fixation attacks. + +**Fix:** Sessions are now regenerated on login for all SSO providers: + +```typescript +// After successful authentication +req.session.regenerate((err) => { + if (err) { + return next(err) + } + // Store user data in new session + req.session.user = authenticatedUser + req.session.save() +}) +``` + +**Affected Providers:** +- Auth0 +- Google OAuth +- GitHub OAuth +- Azure AD + +**Commit:** `e8c36b689` + +##### Secure Cookies Configuration + +**New Feature:** Explicit cookie security control + +```bash +# .env configuration +SECURE_COOKIES=true # Force secure cookies (HTTPS only) +SECURE_COOKIES=false # Allow insecure (development) +# Omit for auto-detection based on environment +``` + +**Cookie Settings When Enabled:** +```typescript +{ + secure: true, // HTTPS only + httpOnly: true, // No JavaScript access + sameSite: 'strict', // CSRF protection + maxAge: 86400000 // 24 hour expiry +} +``` + +**Commit:** `a86f61818` + +--- + +#### MCP Security Validation + +Enhanced validation for Model Context Protocol (MCP) configurations to prevent malicious server connections. + +**New Environment Variables:** + +```bash +# Enable custom MCP security checks +CUSTOM_MCP_SECURITY_CHECK=true + +# Allowed MCP protocols +CUSTOM_MCP_PROTOCOL=stdio,http,https + +# Block dangerous protocols +CUSTOM_MCP_BLOCKED_PROTOCOLS=file,data +``` + +**Validation Checks:** +- Protocol whitelist validation +- URL format validation +- Hostname resolution validation +- Argument sanitization + +**Commits:** `41131dfac`, `d29db16bf`, `e8dac2048` + +--- + +#### Sensitive Data Protection + +##### Log Sanitization + +**Vulnerability:** Sensitive data (API keys, tokens, passwords) could appear in application logs. + +**Fix:** Request headers and body are sanitized before logging: + +```typescript +// Sanitized fields +const sensitiveFields = [ + 'authorization', + 'x-api-key', + 'password', + 'secret', + 'token', + 'apiKey', + 'accessToken', + 'refreshToken', + 'credential' +] + +function sanitizeForLogging(data: object): object { + const sanitized = { ...data } + for (const field of sensitiveFields) { + if (sanitized[field]) { + sanitized[field] = '[REDACTED]' + } + } + return sanitized +} +``` + +**Commit:** `2ae4678da` + +--- + +#### Telemetry Privacy + +**Change:** Telemetry is now **disabled by default** (opt-in instead of opt-out). + +```bash +# Telemetry is OFF unless explicitly enabled +DISABLE_FLOWISE_TELEMETRY=true # Default (redundant but explicit) +DISABLE_FLOWISE_TELEMETRY=false # Opt-in to telemetry +``` + +**What Was Collected:** +- Anonymous usage statistics +- Feature usage counts +- Error reports (sanitized) + +**Privacy Impact:** +- No data sent without explicit opt-in +- Compliant with GDPR and similar regulations +- Suitable for air-gapped deployments + +**Commit:** `624143ad1` + +--- + +#### Dangerous Tools Removed + +##### File System Tools Removed + +**Security Decision:** Read/Write file system tools have been removed from the default distribution. + +**Removed Tools:** +- `ReadFile` - Read arbitrary files +- `WriteFile` - Write arbitrary files + +**Rationale:** +- High risk of path traversal attacks +- Potential for data exfiltration +- Container escape vectors + +**Alternative:** Use specific document loaders for controlled file access. + +**Commits:** `3cab80391`, `1fb12cd93` + +--- + +#### Non-Root Docker Execution + +**Security Enhancement:** Docker containers now run as non-root user by default. + +**Dockerfile Changes:** + +```dockerfile +# Create non-root user +RUN addgroup --system --gid 1001 flowise && \ + adduser --system --uid 1001 --gid 1001 flowise + +# Set ownership +RUN chown -R flowise:flowise /app + +# Switch to non-root user +USER flowise +``` + +**Security Benefits:** +- Limits container escape impact +- Prevents root-level file modifications +- Follows container security best practices +- Required for some Kubernetes security policies + +**Commit:** `366d38b86` + +--- + +#### Security Configuration Summary + +| Setting | Purpose | Recommended Value | +|---------|---------|-------------------| +| `DISABLE_FLOWISE_TELEMETRY` | Disable telemetry | `true` | +| `HTTP_DENY_LIST` | SSRF protection | `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8` | +| `SECURE_COOKIES` | Force HTTPS cookies | `true` (production) | +| `CUSTOM_MCP_SECURITY_CHECK` | MCP validation | `true` | +| `FLOWISE_SECRETKEY_OVERWRITE` | Credential encryption | Strong random key | + +--- + +### Infrastructure + +#### Docker Improvements + +| Feature | Description | Commit | +|---------|-------------|--------| +| Native health checks | Added curl for proper health checks | `786748972` | +| Non-root execution | Container runs as non-root user | `366d38b86` | +| Split workflows | Separated Docker CI/CD | `a7b6f9b20` | +| Worker updates | Updated worker Dockerfile | `8ba1a0907` | + +#### New Environment Variables + +| Variable | Purpose | Default | +|----------|---------|---------| +| `DISABLE_FLOWISE_TELEMETRY` | Disable telemetry | `true` | +| `HTTP_DENY_LIST` | SSRF protection | - | +| `SECURE_COOKIES` | Force secure cookies | auto | +| `TRUST_PROXY` | Express proxy trust | `true` | +| `ENABLE_BULLMQ_DASHBOARD` | Queue monitoring UI | disabled | +| `REMOVE_ON_AGE` | Queue job age cleanup | - | +| `REMOVE_ON_COUNT` | Queue job count cleanup | - | +| `CUSTOM_MCP_SECURITY_CHECK` | MCP validation | - | +| `AAI_MULTI_WORKSPACE_SHARING` | Resource sharing | `false` | +| `AAI_SHARED_WORKSPACE_NAME` | Shared workspace | "Default Workspace" | + +#### Observability + +| Feature | Description | Commit | +|---------|-------------|--------| +| Phoenix Tracing | Self-hosted and cloud Phoenix support | `b02667188` | +| Opik Tracer | New Opik integration | `dd56d03b7` | +| LangWatch Metadata | Config override for metadata | `763e33b07` | +| Mistral Cost Metrics | Cost tracking for Mistral models | `f8ca10582` | + +#### Caching Improvements + +- SSO token caching (`d272683a9`) +- MCP toolkit caching (`2b7a074c8`) +- Google GenAI cache support (`d3510d105`) +- Turbo build caching for DB (`7beb1bb0b`) + +--- + +### Deprecations + +| Item | Replacement | Notes | +|------|-------------|-------| +| AgentFlow V1 (Sequential Agents) | AgentFlow V2 | V1 still works, migration recommended | +| `importChatflows` method | New import system | Better validation | +| `x-request-from: internal` | `x-request-from: aai` | Header change | +| `teradatasql` package | Teradata MCP | Removed | +| `rehyperaw` package | - | Removed | +| Read/Write File Tools | - | Security removal | + +--- + +### Migration Checklist + +#### Pre-Deployment + +- [ ] **BACKUP DATABASE COMPLETELY** +- [ ] Review Auth0 user/organization sync status +- [ ] Verify all users have valid `organizationId` references +- [ ] Document current workspace structure for rollback reference +- [ ] Update client code to use `x-request-from: aai` header + +#### During Deployment + +- [ ] Run migrations in a maintenance window +- [ ] Monitor migration logs for AAI migration messages +- [ ] Watch for WARNING messages about orphaned users + +#### Post-Deployment + +- [ ] Verify users can log in via Auth0 +- [ ] Verify workspace access is correct +- [ ] Verify chatflows are visible in correct workspaces +- [ ] Test evaluation and dataset features +- [ ] Clean up backup tables after verification + +--- + +### Contributors + +This release includes contributions from the Flowise team and TheAnswer AI team. + +### Full Changelog + +[v1.13.0...v2.0.0](https://github.com/the-answerai/theanswer/compare/v1.13.0...v2.0.0) + +--- + +*For previous releases, see [GitHub Releases](https://github.com/the-answerai/theanswer/releases).* diff --git a/package.json b/package.json index b64a92215bf..7fc1e0f03eb 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-solid": "0.12.0", "eslint-plugin-unused-imports": "^2.0.0", - "glob": "^11.0.3", + "glob": "^11.1.0", "husky": "^8.0.3", "jsdom": "^24.0.0", "tsx": "^4.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3a1cfac9e80..fcc13d3b139 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -127,8 +127,8 @@ importers: specifier: ^2.0.0 version: 2.0.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1)(typescript@5.5.4))(eslint@8.57.1) glob: - specifier: ^11.0.3 - version: 11.0.3 + specifier: ^11.1.0 + version: 11.1.0 husky: specifier: ^8.0.3 version: 8.0.3 @@ -176,7 +176,7 @@ importers: version: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@auth0/nextjs-auth0': specifier: 3.5.0 - version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) + version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) '@aws-sdk/client-s3': specifier: ^3.887.0 version: 3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -272,7 +272,7 @@ importers: version: 14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1) next-auth: specifier: ^4.24.11 - version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) openai: specifier: 4.96.0 version: 4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.25.76) @@ -481,7 +481,7 @@ importers: version: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@auth0/nextjs-auth0': specifier: 3.5.0 - version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) + version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) '@emotion/cache': specifier: ^11.14.0 version: 11.14.0 @@ -562,7 +562,7 @@ importers: version: 14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1) next-auth: specifier: ^4.24.11 - version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -653,7 +653,7 @@ importers: version: 4.25.2 '@auth0/nextjs-auth0': specifier: 3.5.0 - version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) + version: 3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1)) '@aws-sdk/client-s3': specifier: ^3.887.0 version: 3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -752,7 +752,7 @@ importers: version: 6.12.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7) next-auth: specifier: ^4.24.11 - version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) node-fetch: specifier: ^3.3.2 version: 3.3.2 @@ -868,7 +868,7 @@ importers: version: 4.1.8 tsc-watch: specifier: ^6.3.1 - version: 6.3.1(typescript@5.9.2) + version: 6.3.1(typescript@5.5.4) packages/components: dependencies: @@ -883,7 +883,7 @@ importers: version: 1.1.0 '@answerai/salesforce-mcp': specifier: ^0.1.0 - version: 0.1.0(@types/node@25.0.3)(encoding@0.1.13) + version: 0.1.0(@types/node@18.15.11)(encoding@0.1.13) '@apidevtools/json-schema-ref-parser': specifier: ^12.0.2 version: 12.0.2 @@ -934,7 +934,7 @@ importers: version: 3.9.25 '@getzep/zep-cloud': specifier: ~1.0.7 - version: 1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623)) + version: 1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(6fd67030478f7edde906cecc69ae7802)) '@getzep/zep-js': specifier: ^0.9.0 version: 0.9.0 @@ -958,7 +958,7 @@ importers: version: 2.8.1 '@jlinc/langchain': specifier: ^0.1.4 - version: 0.1.4(ce0a7b39053833cd4ca09d4644bc8168) + version: 0.1.4(9bda6fb44fecda0d181afd21b39d265b) '@langchain/anthropic': specifier: 0.3.33 version: 0.3.33(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(zod@3.22.4) @@ -973,7 +973,7 @@ importers: version: 0.0.7(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(encoding@0.1.13)(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) '@langchain/community': specifier: ^0.3.47 - version: 0.3.47(942f08a4cc6b9a82fb6ad94256a9c3f6) + version: 0.3.47(23d93d362bfa6c94ff59a8f80281b331) '@langchain/core': specifier: 0.3.61 version: 0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) @@ -1018,7 +1018,7 @@ importers: version: 0.0.1(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) '@mem0/community': specifier: ^0.0.1 - version: 0.0.1(3866934e03f8b1b3abcbbc2e5acf6434) + version: 0.0.1(51219c361d73ef011b4f56f924eacb4a) '@mendable/firecrawl-js': specifier: ^1.18.2 version: 1.29.3 @@ -1165,13 +1165,13 @@ importers: version: 3.13.0 langchain: specifier: ^0.3.5 - version: 0.3.35(3b99869f5911dcf2a16ed91fc5b5f623) + version: 0.3.35(6fd67030478f7edde906cecc69ae7802) langfuse: specifier: 3.3.4 version: 3.3.4 langfuse-langchain: specifier: ^3.3.4 - version: 3.37.6(langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623)) + version: 3.37.6(langchain@0.3.35(6fd67030478f7edde906cecc69ae7802)) langsmith: specifier: 0.1.6 version: 0.1.6 @@ -1273,7 +1273,7 @@ importers: version: 3.0.1(bufferutil@4.0.9)(utf-8-validate@6.0.5) typeorm: specifier: ^0.3.6 - version: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + version: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) weaviate-ts-client: specifier: ^1.1.0 version: 1.6.0(encoding@0.1.13)(graphql@16.11.0) @@ -1337,13 +1337,13 @@ importers: version: 4.0.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@25.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + version: 29.7.0(@types/node@18.15.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) rimraf: specifier: ^5.0.5 version: 5.0.10 ts-jest: specifier: ^29.3.2 - version: 29.4.1(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@25.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)))(typescript@5.5.4) + version: 29.4.1(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@18.15.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)))(typescript@5.5.4) tsc-watch: specifier: ^6.0.4 version: 6.3.1(typescript@5.5.4) @@ -1358,31 +1358,31 @@ importers: dependencies: '@docusaurus/core': specifier: 3.8.1 - version: 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + version: 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/plugin-google-gtag': specifier: 3.8.1 - version: 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + version: 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/preset-classic': specifier: 3.8.1 - version: 3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5) + version: 3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/theme-mermaid': specifier: 3.8.1 - version: 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + version: 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@elevenlabs/react': specifier: ^0.3.0 version: 0.3.0(@types/dom-mediacapture-record@1.0.22)(react@18.3.1) '@mdx-js/react': specifier: ^3.1.0 - version: 3.1.1(@types/react@18.2.15)(react@18.3.1) + version: 3.1.1(@types/react@19.2.2)(react@18.3.1) clsx: specifier: ^2.1.1 version: 2.1.1 docusaurus-plugin-openapi-docs: specifier: ^4.5.1 - version: 4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1) + version: 4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1) docusaurus-theme-openapi-docs: specifier: ^4.5.1 - version: 4.5.1(8e5d3313f608d934af3eef2e3b3848ff) + version: 4.5.1(758824e470602218b68bcdfb17a20166) dotenv: specifier: ^16.6.1 version: 16.6.1 @@ -1403,7 +1403,7 @@ importers: version: 18.3.1(react@18.3.1) react-markdown: specifier: ^8.0.7 - version: 8.0.7(@types/react@18.2.15)(react@18.3.1) + version: 8.0.7(@types/react@19.2.2)(react@18.3.1) remark-gfm: specifier: ^3.0.1 version: 3.0.1 @@ -1947,7 +1947,7 @@ importers: version: 0.5.8 '@types/cookie-parser': specifier: ^1.4.7 - version: 1.4.10(@types/express@5.0.3) + version: 1.4.10(@types/express@4.17.23) '@types/cors': specifier: ^2.8.12 version: 2.8.19 @@ -2272,7 +2272,7 @@ importers: version: 4.7.0(vite@5.4.21(@types/node@25.0.3)(sass@1.92.1)(terser@5.44.0)) pretty-quick: specifier: ^3.1.3 - version: 3.3.1(prettier@3.6.2) + version: 3.3.1(prettier@2.8.8) react-scripts: specifier: ^5.0.1 version: 5.0.1(@babel/plugin-syntax-flow@7.27.1(@babel/core@7.28.4))(@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.4))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/babel__core@7.20.5)(bufferutil@4.0.9)(canvas@2.11.2(encoding@0.1.13))(eslint@8.57.1)(react@18.3.1)(sass@1.92.1)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4))(type-fest@4.41.0)(typescript@5.5.4)(utf-8-validate@6.0.5) @@ -6453,7 +6453,7 @@ packages: '@mui/base@5.0.0-beta.27': resolution: {integrity: sha512-duL37qxihT1N0pW/gyXVezP7SttLkF+cLAs/y6g6ubEFmVadjbnZ45SeF12/vAiKzqwf5M0uFH1cczIPXFZygA==} engines: {node: '>=12.0.0'} - deprecated: This package has been replaced by @base-ui-components/react + deprecated: This package has been replaced by @base-ui/react peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -6465,7 +6465,7 @@ packages: '@mui/base@5.0.0-beta.40': resolution: {integrity: sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==} engines: {node: '>=12.0.0'} - deprecated: This package has been replaced by @base-ui-components/react + deprecated: This package has been replaced by @base-ui/react peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 react: ^17.0.0 || ^18.0.0 @@ -14696,8 +14696,8 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true - glob@11.0.3: - resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} hasBin: true @@ -17744,6 +17744,10 @@ packages: resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} engines: {node: 20 || >=22} + minimatch@10.1.1: + resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -18111,6 +18115,7 @@ packages: next@14.2.32: resolution: {integrity: sha512-fg5g0GZ7/nFc09X8wLe6pNSU8cLWbLRG3TZzPJ1BJvi2s9m7eF991se67wliM9kR5yLHRkyGKU49MMx58s3LJg==} engines: {node: '>=18.17.0'} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -23712,14 +23717,17 @@ packages: whatwg-encoding@1.0.5: resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} engines: {node: '>=12'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} @@ -24421,11 +24429,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@answerai/salesforce-mcp@0.1.0(@types/node@25.0.3)(encoding@0.1.13)': + '@answerai/salesforce-mcp@0.1.0(@types/node@18.15.11)(encoding@0.1.13)': dependencies: '@modelcontextprotocol/sdk': 0.5.0 dotenv: 16.6.1 - jsforce: 3.10.7(@types/node@25.0.3)(encoding@0.1.13) + jsforce: 3.10.7(@types/node@18.15.11)(encoding@0.1.13) transitivePeerDependencies: - '@types/node' - encoding @@ -24579,7 +24587,7 @@ snapshots: dpop: 2.1.1 es-cookie: 1.3.2 - '@auth0/nextjs-auth0@3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))': + '@auth0/nextjs-auth0@3.5.0(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))': dependencies: '@panva/hkdf': 1.2.1 cookie: 1.0.2 @@ -28350,14 +28358,14 @@ snapshots: '@docsearch/css@3.9.0': {} - '@docsearch/react@3.9.0(@algolia/client-search@5.37.0)(@types/react@18.2.15)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)': + '@docsearch/react@3.9.0(@algolia/client-search@5.37.0)(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)': dependencies: '@algolia/autocomplete-core': 1.17.9(@algolia/client-search@5.37.0)(algoliasearch@5.37.0)(search-insights@2.17.3) '@algolia/autocomplete-preset-algolia': 1.17.9(@algolia/client-search@5.37.0)(algoliasearch@5.37.0) '@docsearch/css': 3.9.0 algoliasearch: 5.37.0 optionalDependencies: - '@types/react': 18.2.15 + '@types/react': 19.2.2 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) search-insights: 2.17.3 @@ -28431,7 +28439,7 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: '@docusaurus/babel': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/bundler': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4) @@ -28440,7 +28448,7 @@ snapshots: '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mdx-js/react': 3.1.1(@types/react@18.2.15)(react@18.3.1) + '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@18.3.1) boxen: 6.2.1 chalk: 4.1.2 chokidar: 3.6.0 @@ -28559,13 +28567,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-content-blog@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28599,13 +28607,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/module-type-aliases': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28638,9 +28646,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-content-pages@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/mdx-loader': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28667,9 +28675,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-css-cascade-layers@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28693,9 +28701,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-debug@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) fs-extra: 11.3.1 @@ -28720,9 +28728,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-google-analytics@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 @@ -28745,9 +28753,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-google-gtag@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/gtag.js': 0.0.12 @@ -28771,9 +28779,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-google-tag-manager@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 @@ -28796,9 +28804,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-sitemap@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/logger': 3.8.1 '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28826,9 +28834,9 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/plugin-svgr@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -28855,22 +28863,22 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5)': - dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/theme-classic': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/preset-classic@3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5)': + dependencies: + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-css-cascade-layers': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-debug': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-google-analytics': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-google-gtag': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-google-tag-manager': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-sitemap': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-svgr': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/theme-classic': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-search-algolia': 3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -28899,22 +28907,22 @@ snapshots: '@types/react': 18.2.15 react: 18.3.1 - '@docusaurus/theme-classic@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/theme-classic@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/logger': 3.8.1 '@docusaurus/mdx-loader': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/module-type-aliases': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-blog': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-pages': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/theme-translations': 3.8.1 '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@mdx-js/react': 3.1.1(@types/react@18.2.15)(react@18.3.1) + '@mdx-js/react': 3.1.1(@types/react@19.2.2)(react@18.3.1) clsx: 2.1.1 copy-text-to-clipboard: 3.2.1 infima: 0.2.0-alpha.45 @@ -28946,11 +28954,11 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@docusaurus/theme-common@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@docusaurus/mdx-loader': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/module-type-aliases': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-common': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@types/history': 4.7.11 @@ -28970,11 +28978,11 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/theme-mermaid@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/theme-mermaid@3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/module-type-aliases': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/types': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) mermaid: 11.11.0 @@ -28999,13 +29007,13 @@ snapshots: - utf-8-validate - webpack-cli - '@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@18.2.15)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5)': + '@docusaurus/theme-search-algolia@3.8.1(@algolia/client-search@5.37.0)(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3)(typescript@5.5.4)(utf-8-validate@6.0.5)': dependencies: - '@docsearch/react': 3.9.0(@algolia/client-search@5.37.0)(@types/react@18.2.15)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3) - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docsearch/react': 3.9.0(@algolia/client-search@5.37.0)(@types/react@19.2.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(search-insights@2.17.3) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/logger': 3.8.1 - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/theme-translations': 3.8.1 '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -29522,7 +29530,7 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623))': + '@getzep/zep-cloud@1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(6fd67030478f7edde906cecc69ae7802))': dependencies: form-data: 4.0.4 node-fetch: 2.7.0(encoding@0.1.13) @@ -29531,7 +29539,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@langchain/core': 0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) - langchain: 0.3.35(3b99869f5911dcf2a16ed91fc5b5f623) + langchain: 0.3.35(6fd67030478f7edde906cecc69ae7802) transitivePeerDependencies: - encoding @@ -29920,6 +29928,13 @@ snapshots: optionalDependencies: '@types/node': 25.0.3 + '@inquirer/external-editor@1.0.1(@types/node@18.15.11)': + dependencies: + chardet: 2.1.0 + iconv-lite: 0.6.3 + optionalDependencies: + '@types/node': 18.15.11 + '@inquirer/external-editor@1.0.1(@types/node@25.0.3)': dependencies: chardet: 2.1.0 @@ -30445,10 +30460,10 @@ snapshots: chalk: 4.1.2 optional: true - '@jlinc/langchain@0.1.4(ce0a7b39053833cd4ca09d4644bc8168)': + '@jlinc/langchain@0.1.4(9bda6fb44fecda0d181afd21b39d265b)': dependencies: axios: 1.12.2(debug@4.4.1) - langchain: 0.3.35(8d1ab517a23d92f9355c1c45a072e867) + langchain: 0.3.35(b7124e418eaf50112f3861480d125258) transitivePeerDependencies: - '@langchain/anthropic' - '@langchain/aws' @@ -30734,7 +30749,7 @@ snapshots: - aws-crt optional: true - '@langchain/community@0.3.47(942f08a4cc6b9a82fb6ad94256a9c3f6)': + '@langchain/community@0.3.47(23d93d362bfa6c94ff59a8f80281b331)': dependencies: '@browserbasehq/stagehand': 1.14.0(@playwright/test@1.55.0)(bufferutil@4.0.9)(deepmerge@4.3.1)(dotenv@16.6.1)(encoding@0.1.13)(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4))(utf-8-validate@6.0.5)(zod@3.22.4) '@ibm-cloud/watsonx-ai': 1.6.0(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4))) @@ -30746,7 +30761,7 @@ snapshots: flat: 5.0.2 ibm-cloud-sdk-core: 5.3.2 js-yaml: 4.1.0 - langchain: 0.3.35(3b99869f5911dcf2a16ed91fc5b5f623) + langchain: 0.3.35(6fd67030478f7edde906cecc69ae7802) langsmith: 0.3.68(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) openai: 4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4) uuid: 10.0.0 @@ -30762,7 +30777,7 @@ snapshots: '@browserbasehq/sdk': 2.6.0(encoding@0.1.13) '@datastax/astra-db-ts': 1.5.0 '@elastic/elasticsearch': 8.19.1 - '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623)) + '@getzep/zep-cloud': 1.0.12(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(langchain@0.3.35(6fd67030478f7edde906cecc69ae7802)) '@getzep/zep-js': 0.9.0 '@gomomento/sdk': 1.116.0 '@gomomento/sdk-core': 1.116.0 @@ -30816,7 +30831,7 @@ snapshots: redis: 4.7.1 replicate: 0.31.1 srt-parser-2: 1.2.3 - typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) weaviate-client: 3.8.1(encoding@0.1.13) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5) transitivePeerDependencies: @@ -31293,15 +31308,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1)': + '@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1)': dependencies: '@types/mdx': 2.0.13 - '@types/react': 18.2.15 + '@types/react': 19.2.2 react: 18.3.1 - '@mem0/community@0.0.1(3866934e03f8b1b3abcbbc2e5acf6434)': + '@mem0/community@0.0.1(51219c361d73ef011b4f56f924eacb4a)': dependencies: - '@langchain/community': 0.3.47(942f08a4cc6b9a82fb6ad94256a9c3f6) + '@langchain/community': 0.3.47(23d93d362bfa6c94ff59a8f80281b331) '@langchain/core': 0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) axios: 1.12.1 mem0ai: 2.1.38(@anthropic-ai/sdk@0.65.0(zod@3.22.4))(@cloudflare/workers-types@4.20250912.0)(@google/genai@0.7.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@6.0.5))(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(@mistralai/mistralai@0.1.3(encoding@0.1.13))(@qdrant/js-client-rest@1.15.1(typescript@5.5.4))(@supabase/supabase-js@2.57.4(bufferutil@4.0.9)(utf-8-validate@6.0.5))(@types/jest@29.5.14)(@types/pg@8.15.5)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.19.0(encoding@0.1.13))(neo4j-driver@5.28.1)(ollama@0.5.17)(pg@8.16.3)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -32250,7 +32265,7 @@ snapshots: '@next-auth/prisma-adapter@1.0.7(@prisma/client@5.22.0(prisma@5.22.0))(next-auth@4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))': dependencies: '@prisma/client': 5.22.0(prisma@5.22.0) - next-auth: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next-auth: 4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@next/bundle-analyzer@13.5.11(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -35706,9 +35721,9 @@ snapshots: '@types/content-disposition@0.5.8': {} - '@types/cookie-parser@1.4.10(@types/express@5.0.3)': + '@types/cookie-parser@1.4.10(@types/express@4.17.23)': dependencies: - '@types/express': 5.0.3 + '@types/express': 4.17.23 '@types/cookiejar@2.1.5': {} @@ -39547,7 +39562,7 @@ snapshots: dotenv: 16.4.7 eventsource-client: 1.1.3 fast-glob: 3.3.3 - glob: 11.0.3 + glob: 11.1.0 google-auth-library: 9.15.1(encoding@0.1.13) openai: 4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.25.76) p-queue: 8.1.1 @@ -40145,10 +40160,10 @@ snapshots: dependencies: esutils: 2.0.3 - docusaurus-plugin-openapi-docs@4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1): + docusaurus-plugin-openapi-docs@4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1): dependencies: '@apidevtools/json-schema-ref-parser': 11.9.3 - '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/plugin-content-docs': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) '@docusaurus/utils': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@docusaurus/utils-validation': 3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@redocly/openapi-core': 1.34.5 @@ -40170,9 +40185,9 @@ snapshots: - encoding - supports-color - docusaurus-plugin-sass@0.2.6(@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(sass@1.92.1)(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))): + docusaurus-plugin-sass@0.2.6(@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(sass@1.92.1)(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))): dependencies: - '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) + '@docusaurus/core': 3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5) sass: 1.92.1 sass-loader: 16.0.6(sass@1.92.1)(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))) transitivePeerDependencies: @@ -40181,9 +40196,9 @@ snapshots: - sass-embedded - webpack - docusaurus-theme-openapi-docs@4.5.1(8e5d3313f608d934af3eef2e3b3848ff): + docusaurus-theme-openapi-docs@4.5.1(758824e470602218b68bcdfb17a20166): dependencies: - '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@docusaurus/theme-common': 3.8.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@hookform/error-message': 2.0.1(react-dom@18.3.1(react@18.3.1))(react-hook-form@7.62.0(react@18.3.1))(react@18.3.1) '@reduxjs/toolkit': 1.9.7(react-redux@7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) allof-merge: 0.6.7 @@ -40191,8 +40206,8 @@ snapshots: clsx: 1.2.1 copy-text-to-clipboard: 3.2.1 crypto-js: 4.2.0 - docusaurus-plugin-openapi-docs: 4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1) - docusaurus-plugin-sass: 0.2.6(@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@18.2.15)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(sass@1.92.1)(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))) + docusaurus-plugin-openapi-docs: 4.5.1(@docusaurus/plugin-content-docs@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(@docusaurus/utils-validation@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(@docusaurus/utils@3.8.1(@swc/core@1.13.5(@swc/helpers@0.5.17))(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(encoding@0.1.13)(react@18.3.1) + docusaurus-plugin-sass: 0.2.6(@docusaurus/core@3.8.1(@mdx-js/react@3.1.1(@types/react@19.2.2)(react@18.3.1))(@swc/core@1.13.5(@swc/helpers@0.5.17))(bufferutil@4.0.9)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.5.4)(utf-8-validate@6.0.5))(sass@1.92.1)(webpack@5.101.3(@swc/core@1.13.5(@swc/helpers@0.5.17))) file-saver: 2.0.5 lodash: 4.17.21 pako: 2.1.0 @@ -40205,7 +40220,7 @@ snapshots: react-hook-form: 7.62.0(react@18.3.1) react-live: 4.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-magic-dropzone: 1.0.1 - react-markdown: 8.0.7(@types/react@18.2.15)(react@18.3.1) + react-markdown: 8.0.7(@types/react@19.2.2)(react@18.3.1) react-modal: 3.16.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-redux: 7.2.9(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rehype-raw: 6.1.1 @@ -40732,7 +40747,7 @@ snapshots: eslint: 7.32.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0))(eslint@7.32.0) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0))(eslint@7.32.0))(eslint@7.32.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1)(eslint@7.32.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@7.32.0) eslint-plugin-react: 7.37.5(eslint@7.32.0) eslint-plugin-react-hooks: 4.6.2(eslint@7.32.0) @@ -40826,7 +40841,7 @@ snapshots: tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0))(eslint@7.32.0))(eslint@7.32.0) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1)(eslint@7.32.0) transitivePeerDependencies: - supports-color @@ -40885,7 +40900,7 @@ snapshots: lodash: 4.17.21 string-natural-compare: 3.0.1 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint@7.32.0))(eslint@7.32.0))(eslint@7.32.0): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0(eslint@7.32.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.10.1)(eslint@7.32.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -42420,11 +42435,11 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@11.0.3: + glob@11.1.0: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.0.3 + minimatch: 10.1.1 minipass: 7.1.2 package-json-from-dist: 1.0.1 path-scurry: 2.0.0 @@ -43447,9 +43462,9 @@ snapshots: transitivePeerDependencies: - encoding - inquirer@8.2.7(@types/node@25.0.3): + inquirer@8.2.7(@types/node@18.15.11): dependencies: - '@inquirer/external-editor': 1.0.1(@types/node@25.0.3) + '@inquirer/external-editor': 1.0.1(@types/node@18.15.11) ansi-escapes: 4.3.2 chalk: 4.1.2 cli-cursor: 3.1.0 @@ -44934,7 +44949,7 @@ snapshots: jsesc@3.1.0: {} - jsforce@3.10.7(@types/node@25.0.3)(encoding@0.1.13): + jsforce@3.10.7(@types/node@18.15.11)(encoding@0.1.13): dependencies: '@babel/runtime': 7.28.4 '@babel/runtime-corejs3': 7.28.4 @@ -44947,7 +44962,7 @@ snapshots: faye: 1.4.1 form-data: 4.0.4 https-proxy-agent: 5.0.1 - inquirer: 8.2.7(@types/node@25.0.3) + inquirer: 8.2.7(@types/node@18.15.11) multistream: 3.1.0 node-fetch: 2.7.0(encoding@0.1.13) open: 7.4.2 @@ -45239,7 +45254,7 @@ snapshots: - encoding - openai - langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623): + langchain@0.3.35(6fd67030478f7edde906cecc69ae7802): dependencies: '@langchain/core': 0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) '@langchain/openai': 0.6.3(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -45267,7 +45282,7 @@ snapshots: axios: 1.12.1 cheerio: 1.1.2 handlebars: 4.7.8 - typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/exporter-trace-otlp-proto' @@ -45276,7 +45291,7 @@ snapshots: - openai - ws - langchain@0.3.35(8d1ab517a23d92f9355c1c45a072e867): + langchain@0.3.35(b7124e418eaf50112f3861480d125258): dependencies: '@langchain/core': 0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)) '@langchain/openai': 0.6.3(@langchain/core@0.3.61(@opentelemetry/api@1.9.0)(@opentelemetry/exporter-trace-otlp-proto@0.202.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.27.0(@opentelemetry/api@1.9.0))(openai@4.96.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5))(zod@3.22.4)))(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)) @@ -45304,7 +45319,7 @@ snapshots: axios: 1.12.2(debug@4.4.1) cheerio: 1.1.2 handlebars: 4.7.8 - typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + typeorm: 0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) transitivePeerDependencies: - '@opentelemetry/api' - '@opentelemetry/exporter-trace-otlp-proto' @@ -45319,9 +45334,9 @@ snapshots: dependencies: mustache: 4.2.0 - langfuse-langchain@3.37.6(langchain@0.3.35(3b99869f5911dcf2a16ed91fc5b5f623)): + langfuse-langchain@3.37.6(langchain@0.3.35(6fd67030478f7edde906cecc69ae7802)): dependencies: - langchain: 0.3.35(3b99869f5911dcf2a16ed91fc5b5f623) + langchain: 0.3.35(6fd67030478f7edde906cecc69ae7802) langfuse: 3.38.6 langfuse-core: 3.38.6 @@ -47007,6 +47022,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.1.1: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -47381,7 +47400,7 @@ snapshots: netmask@2.0.2: {} - next-auth@4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(babel-plugin-macros@3.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + next-auth@4.24.11(next@14.2.32(@babel/core@7.28.4)(@opentelemetry/api@1.9.0)(@playwright/test@1.55.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.92.1))(nodemailer@6.9.16)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.28.4 '@panva/hkdf': 1.2.1 @@ -49604,17 +49623,6 @@ snapshots: prettier: 2.8.8 tslib: 2.8.1 - pretty-quick@3.3.1(prettier@3.6.2): - dependencies: - execa: 4.1.0 - find-up: 4.1.0 - ignore: 5.3.2 - mri: 1.2.0 - picocolors: 1.1.1 - picomatch: 3.0.1 - prettier: 3.6.2 - tslib: 2.8.1 - pretty-time@1.1.0: {} prism-react-renderer@1.3.5(react@18.2.0): @@ -50274,28 +50282,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-markdown@8.0.7(@types/react@18.2.15)(react@18.3.1): - dependencies: - '@types/hast': 2.3.10 - '@types/prop-types': 15.7.15 - '@types/react': 18.2.15 - '@types/unist': 2.0.11 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 2.0.1 - prop-types: 15.8.1 - property-information: 6.5.0 - react: 18.3.1 - react-is: 18.3.1 - remark-parse: 10.0.2 - remark-rehype: 10.1.0 - space-separated-tokens: 2.0.2 - style-to-object: 0.4.4 - unified: 10.1.2 - unist-util-visit: 4.1.2 - vfile: 5.3.7 - transitivePeerDependencies: - - supports-color - react-markdown@8.0.7(@types/react@19.2.2)(react@18.3.1): dependencies: '@types/hast': 2.3.10 @@ -51171,7 +51157,7 @@ snapshots: rimraf@6.0.1: dependencies: - glob: 11.0.3 + glob: 11.1.0 package-json-from-dist: 1.0.1 roarr@2.15.4: @@ -52984,12 +52970,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.28.4) jest-util: 30.0.5 - ts-jest@29.4.1(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@25.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)))(typescript@5.5.4): + ts-jest@29.4.1(@babel/core@7.28.4)(@jest/transform@29.7.0)(@jest/types@30.0.5)(babel-jest@29.7.0(@babel/core@7.28.4))(jest-util@30.0.5)(jest@29.7.0(@types/node@18.15.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)))(typescript@5.5.4): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.8 - jest: 29.7.0(@types/node@25.0.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)) + jest: 29.7.0(@types/node@18.15.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -53119,14 +53105,6 @@ snapshots: string-argv: 0.3.2 typescript: 5.5.4 - tsc-watch@6.3.1(typescript@5.9.2): - dependencies: - cross-spawn: 7.0.6 - node-cleanup: 2.1.2 - ps-tree: 1.2.0 - string-argv: 0.3.2 - typescript: 5.9.2 - tsconfck@3.1.6(typescript@5.5.4): optionalDependencies: typescript: 5.5.4 @@ -53375,7 +53353,7 @@ snapshots: - babel-plugin-macros - supports-color - typeorm@0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4)): + typeorm@0.3.26(babel-plugin-macros@3.1.0)(ioredis@5.7.0)(mongodb@6.3.0(@aws-sdk/credential-providers@3.887.0(aws-crt@1.27.3(bufferutil@4.0.9)(utf-8-validate@6.0.5)))(socks@2.8.7))(mysql2@3.14.5)(pg@8.16.3)(redis@4.7.1)(reflect-metadata@0.1.14)(sqlite3@5.1.7)(ts-node@10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4)): dependencies: '@sqltools/formatter': 1.2.5 ansis: 3.17.0 @@ -53399,7 +53377,7 @@ snapshots: pg: 8.16.3 redis: 4.7.1 sqlite3: 5.1.7 - ts-node: 10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@25.0.3)(typescript@5.5.4) + ts-node: 10.9.2(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@18.15.11)(typescript@5.5.4) transitivePeerDependencies: - babel-plugin-macros - supports-color diff --git a/scripts/bws-secure/README.md b/scripts/bws-secure/README.md index df31f6e532b..dc5665adf47 100755 --- a/scripts/bws-secure/README.md +++ b/scripts/bws-secure/README.md @@ -34,6 +34,12 @@ Manager. - [Security Features](#security-features) - [Troubleshooting](#troubleshooting) - [Common Issues](#common-issues) + - [BWS CLI Management](#bws-cli-management) + - [Smart Caching](#smart-caching) + - [Force Reinstall](#force-reinstall) + - [Local Backup Fallback](#local-backup-fallback) + - [Updating BWS Version](#updating-bws-version) + - [Uninstall BWS](#uninstall-bws) - [Support](#support) - [Machine Account Tokens](#machine-account-tokens) - [Directory Structure](#directory-structure) @@ -337,6 +343,78 @@ BWS Secure automatically scans: DEBUG=true VERBOSE=true pnpm build ``` +## BWS CLI Management + +The `bws` CLI binary is automatically installed during `pnpm install` via the postinstall script. The installer includes smart caching and a local backup fallback system. + +### Smart Caching + +The installer checks if bws is already installed at the correct version and skips installation if so: + +``` +bws v1.0.0 already installed, skipping. +To force reinstall: sh ./scripts/bws-secure/bws-installer.sh -f +``` + +This reduces `pnpm install` time from ~5-10s to <1s on subsequent runs. + +### Force Reinstall + +To force a fresh installation of the bws CLI: + +```bash +sh ./scripts/bws-secure/bws-installer.sh -f +``` + +### Local Backup Fallback + +The installer includes vendored bws binaries as a fallback when GitHub is unavailable (CDN outage, rate limiting, repo renamed, etc.): + +``` +bin/backup/ +└── v1.0.0/ + ├── bws-aarch64-apple-darwin-1.0.0.zip # macOS ARM + ├── bws-aarch64-pc-windows-msvc-1.0.0.zip # Windows ARM + ├── bws-aarch64-unknown-linux-gnu-1.0.0.zip # Linux ARM + ├── bws-macos-universal-1.0.0.zip # macOS Universal + ├── bws-x86_64-apple-darwin-1.0.0.zip # macOS x64 + ├── bws-x86_64-pc-windows-msvc-1.0.0.zip # Windows x64 + ├── bws-x86_64-unknown-linux-gnu-1.0.0.zip # Linux x64 + └── bws-sha256-checksums-1.0.0.txt +``` + +**Priority order:** +1. Download from GitHub (primary) +2. Use local backup if download fails (fallback) + +### Updating BWS Version + +To update to a new bws version: + +1. **Download new version binaries:** + ```bash + ./bin/backup/download-backups.sh 1.1.0 + ``` + The script automatically discovers and downloads all available binaries for the specified version. + +2. **Update default version in `bws-installer.sh`:** + ```bash + DEFAULT_BWS_VERSION="1.1.0" + ``` + +3. **Optionally remove old version backups:** + ```bash + rm -rf bin/backup/v1.0.0 + ``` + +### Uninstall BWS + +To remove the bws binary: + +```bash +sh ./scripts/bws-secure/bws-installer.sh -u +``` + ## Support - 📚 [Full Documentation](https://github.com/last-rev-llc/bws-secure) @@ -379,30 +457,36 @@ The project structure is as follows: /scripts/bws-secure ├── .gitignore ├── README.md +├── bin/ +│ └── backup/ +│ ├── download-backups.sh # Script to download bws binaries +│ └── v1.0.0/ # Vendored binaries (fallback) +│ ├── bws-*-1.0.0.zip +│ └── bws-sha256-checksums-1.0.0.txt ├── bws-dotenv.js -├── bws-installer.sh -├── check-vars +├── bws-installer.sh # Installs bws CLI with smart caching +├── bws-retry-utils.js +├── check-vars/ │ ├── .gitignore │ ├── README.md │ ├── check-vars-availability.sh │ └── requiredRuntimeVars.js -├── config.json ├── env_validator.js ├── generate-env-debug.js ├── install.sh ├── list-projects.js ├── logger.js +├── project-selector.js ├── secureRun.js -├── test-netlify-upload.js -├── test-vercel-upload.js -├── update-environments +├── update-environments/ │ ├── .gitignore │ ├── README.md +│ ├── map-env-files.js │ ├── netlify.js │ ├── updateEnvVars.js │ ├── utils.js │ └── vercel.js -└── upload-to-bws +└── upload-to-bws/ ├── readme.md └── upload-secrets.js ``` @@ -621,7 +705,7 @@ As of the latest update, this package now uses ES Modules (ESM) instead of Commo 1. All imports use the `import` syntax instead of `require()` 2. The package has `"type": "module"` in its package.json 3. When importing local files, you must include the `.js` extension -4. Node.js version 14.16.0 or higher is required +4. Node.js version 18.0.0 or higher is required Example usage: diff --git a/scripts/bws-secure/bin/backup/README.md b/scripts/bws-secure/bin/backup/README.md new file mode 100644 index 00000000000..204bf027ef1 --- /dev/null +++ b/scripts/bws-secure/bin/backup/README.md @@ -0,0 +1,63 @@ +# BWS CLI Backup Binaries + +This folder contains vendored bws CLI binaries used as a fallback when GitHub is unavailable (CDN outage, rate limiting, repo renamed, etc.). + +## How It Works + +The `bws-installer.sh` script: +1. **First** tries to download from GitHub +2. **Falls back** to these local binaries if download fails +3. **Validates checksums** regardless of source + +## Folder Structure + +``` +bin/backup/ +├── download-backups.sh # Script to download binaries +├── README.md # This file +└── v1.0.0/ # Version-specific folder + ├── bws-*-1.0.0.zip # Platform binaries + └── bws-sha256-checksums-1.0.0.txt +``` + +## Downloading Binaries for a New Version + +```bash +./download-backups.sh 1.1.0 +``` + +The script automatically: +- Fetches the checksum file first +- Discovers all available binaries from the checksum file +- Downloads each binary +- Verifies SHA256 checksums + +No hardcoded list of files - it adapts to whatever Bitwarden releases. + +## Updating the Default Version + +After downloading new binaries, update `bws-installer.sh`: + +```bash +DEFAULT_BWS_VERSION="1.1.0" +``` + +## Removing Old Versions + +```bash +rm -rf v1.0.0 +``` + +## Supported Platforms + +The binaries cover: +- **Linux**: x64, ARM64 (glibc) +- **macOS**: x64, ARM64, Universal +- **Windows**: x64, ARM64 + +## Why Vendor Binaries? + +- **Resilience**: Upstream changes (repo renames, CDN issues) won't break builds +- **Speed**: Local copies are instant when available +- **Verification**: All binaries are SHA256 checksum verified + diff --git a/scripts/bws-secure/bin/backup/download-backups.sh b/scripts/bws-secure/bin/backup/download-backups.sh new file mode 100755 index 00000000000..f93eee8bb12 --- /dev/null +++ b/scripts/bws-secure/bin/backup/download-backups.sh @@ -0,0 +1,112 @@ +#!/bin/sh +# +# Downloads ALL bws CLI binaries for local backup +# Dynamically discovers available files from checksum file +# Run this script when GitHub CDN is available +# + +VERSION="${1:-1.0.0}" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +TARGET_DIR="$SCRIPT_DIR/v$VERSION" + +mkdir -p "$TARGET_DIR" + +BASE_URL="https://github.com/bitwarden/sdk-sm/releases/download/bws-v${VERSION}" +CHECKSUM_FILE="bws-sha256-checksums-${VERSION}.txt" + +echo "═══════════════════════════════════════════════════════════" +echo " Downloading bws v${VERSION} binaries" +echo " Target: $TARGET_DIR" +echo "═══════════════════════════════════════════════════════════" +echo "" + +# Step 1: Download checksum file first (it tells us what files exist) +echo "Step 1: Fetching checksum file..." +if curl -L --fail --retry 3 --retry-delay 5 -o "$TARGET_DIR/$CHECKSUM_FILE" "$BASE_URL/$CHECKSUM_FILE" 2>/dev/null; then + echo " ✓ Downloaded $CHECKSUM_FILE" +else + echo " ✗ Failed to download checksum file. Cannot proceed." + echo " Check if version v${VERSION} exists at:" + echo " https://github.com/bitwarden/sdk-sm/releases/tag/bws-v${VERSION}" + exit 1 +fi + +echo "" + +# Step 2: Parse checksum file to get list of all .zip files +echo "Step 2: Downloading all available binaries..." +BINARIES=$(grep '\.zip$' "$TARGET_DIR/$CHECKSUM_FILE" | awk '{print $2}') + +if [ -z "$BINARIES" ]; then + echo " ✗ No binaries found in checksum file" + exit 1 +fi + +# Count total files +TOTAL=$(echo "$BINARIES" | wc -l | tr -d ' ') +CURRENT=0 +SUCCESS=0 +FAILED=0 + +for file in $BINARIES; do + CURRENT=$((CURRENT + 1)) + if [ -f "$TARGET_DIR/$file" ]; then + echo " [$CURRENT/$TOTAL] ✓ $file (already exists)" + SUCCESS=$((SUCCESS + 1)) + else + echo " [$CURRENT/$TOTAL] ↓ Downloading $file..." + if curl -L --fail --retry 3 --retry-delay 5 -o "$TARGET_DIR/$file" "$BASE_URL/$file" 2>/dev/null; then + echo " ✓ Downloaded" + SUCCESS=$((SUCCESS + 1)) + else + echo " ✗ Failed" + FAILED=$((FAILED + 1)) + fi + fi +done + +echo "" +echo "Step 3: Verifying checksums..." + +VERIFIED=0 +CHECKSUM_FAILED=0 + +for file in "$TARGET_DIR"/*.zip; do + [ -f "$file" ] || continue + filename=$(basename "$file") + expected=$(grep "$filename" "$TARGET_DIR/$CHECKSUM_FILE" | awk '{print $1}') + + if [ -n "$expected" ]; then + if command -v sha256sum >/dev/null; then + actual=$(sha256sum "$file" | awk '{print $1}') + else + actual=$(shasum -a 256 "$file" | awk '{print $1}') + fi + + if [ "$expected" = "$actual" ]; then + echo " ✓ $filename" + VERIFIED=$((VERIFIED + 1)) + else + echo " ✗ $filename CHECKSUM FAILED" + echo " Expected: $expected" + echo " Actual: $actual" + CHECKSUM_FAILED=$((CHECKSUM_FAILED + 1)) + fi + fi +done + +echo "" +echo "═══════════════════════════════════════════════════════════" +echo " Summary" +echo "═══════════════════════════════════════════════════════════" +echo " Downloaded: $SUCCESS / $TOTAL" +[ "$FAILED" -gt 0 ] && echo " Failed: $FAILED" +echo " Verified: $VERIFIED checksums OK" +[ "$CHECKSUM_FAILED" -gt 0 ] && echo " Invalid: $CHECKSUM_FAILED checksums FAILED" +echo "" +echo " Files saved to: $TARGET_DIR" +echo "═══════════════════════════════════════════════════════════" + +# Exit with error if any checksums failed +[ "$CHECKSUM_FAILED" -gt 0 ] && exit 1 +exit 0 diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-apple-darwin-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-apple-darwin-1.0.0.zip new file mode 100644 index 00000000000..4ce149c493c Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-apple-darwin-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-pc-windows-msvc-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-pc-windows-msvc-1.0.0.zip new file mode 100644 index 00000000000..a9b65348094 Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-pc-windows-msvc-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-unknown-linux-gnu-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-unknown-linux-gnu-1.0.0.zip new file mode 100644 index 00000000000..13849ff02e7 Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-aarch64-unknown-linux-gnu-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-macos-universal-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-macos-universal-1.0.0.zip new file mode 100644 index 00000000000..be20202f568 Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-macos-universal-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-sha256-checksums-1.0.0.txt b/scripts/bws-secure/bin/backup/v1.0.0/bws-sha256-checksums-1.0.0.txt new file mode 100644 index 00000000000..b6c45104833 --- /dev/null +++ b/scripts/bws-secure/bin/backup/v1.0.0/bws-sha256-checksums-1.0.0.txt @@ -0,0 +1,26 @@ +9077fb7b336a62abc8194728fea8753afad8b0baa3a18723fc05fc02fdb53568 bws-x86_64-unknown-linux-gnu-1.0.0.zip +f429ffc463da939dd351a194d28d165f0d99f3da3d768f90ba7995ef575da035 bws-secret-create.1 +ad6ddc2cee2746882c8566461587af33b869a9c7c944e323266801f796c3c41b bws.1 +5dd716878e5627220aa254cbe4e41e978f226f72d9117fc195046709db363e20 bws-aarch64-apple-darwin-1.0.0.zip +9cca8eac9b69aa6d9263389be346cc7c9cd5e195fd165535cc4441721d4eaae3 bws-project-edit.1 +462434cae74f624664a0006e00f2d7b28c960fde174028d60ddb4e995022f6c5 bws-secret.1 +c8122646c7a76269925efddb31bf454c71e2850d24f93e949eaac967bfb06c28 THIRDPARTY.html +b079df851ad2535de9fe557f23609db3e80a2d32803d8fd12a31173d033fdd9c bws-completions.1 +8b05fd9dff2ab2fa9219807c0d9554225733eb92a229b41553fca9a0b4f85a15 bws-project-delete.1 +43b03cc9ffa4994b4ef6ca74742a29078b19250a3ce7a789a2324e251dbbbd8a bws-project-get.1 +d3d97ea52f62aef1f7526564e28d0a222233ca34aacb573ecde4cae3e183973f bws-project.1 +7e06cbc0f3543dd68585a22bf1ce09eca1d413322aa22554a713cf97de60495a bws-x86_64-apple-darwin-1.0.0.zip +5ece899717ccd3abdb1a40fff5e34e759d8e95061845d289df31957f7bc700b0 bws-macos-universal-1.0.0.zip +686022538daf399d31aee094d51b227c00ccb8fc0f18237a70a904655e411fb0 bws-run.1 +f6a5c4d2a2aed38cae4a73696eee99b48a9e4fa3868f951f3ee43de3545c80df bws-secret-get.1 +fa0dc978c255dfc66ef98172ce1141e0730b33ca97a6b88d5ad843a2a9192811 bws-aarch64-unknown-linux-musl-1.0.0.zip +549eb2cb121a07d1e6908eea44294f687d2d7c6ff3015d6088563eb8d4de7995 bws-secret-edit.1 +0e9052bb8adcf5b838352214179af6cf857d6971e04c9b38cc954e4004d504c8 bws-secret-list.1 +c6c09ba7d4db76c76aabd8fe65a533e019391a712491928555cb7bab1654609d bws-config.1 +078498d8d6124ac854fe92f642dbca363382ba2a0270e443fedf865168ef3482 bws-project-list.1 +d7d279e63cc7b4ef564a2497b3b5e00870166fcc3023cff9a00adac89911099d bws-x86_64-unknown-linux-musl-1.0.0.zip +69b8d0fb2facc8cec4dd2b8157a3496ecaaa376ee1b0fd822012192ce7437505 bws-x86_64-pc-windows-msvc-1.0.0.zip +457b706961d7949202e74c799d465097462161171c255646513ea76add60d169 bws-aarch64-pc-windows-msvc-1.0.0.zip +357577593bc2b1bf98e0523cba76dbbc7f0ede30d25e306ea809cbe7804fde66 bws-secret-delete.1 +20a3dcb9e3ce7716a1dc3c0e1c76cea9d5e2bf75094cbb5aad54ced4304929cb bws-aarch64-unknown-linux-gnu-1.0.0.zip +efbdd184030b95341653450327d3f2bcbec34bd5f74b09fb1fd7e55b6001533b bws-project-create.1 \ No newline at end of file diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-apple-darwin-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-apple-darwin-1.0.0.zip new file mode 100644 index 00000000000..9f0fb3de541 Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-apple-darwin-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-pc-windows-msvc-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-pc-windows-msvc-1.0.0.zip new file mode 100644 index 00000000000..7bd12755d1e Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-pc-windows-msvc-1.0.0.zip differ diff --git a/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-unknown-linux-gnu-1.0.0.zip b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-unknown-linux-gnu-1.0.0.zip new file mode 100644 index 00000000000..b57d3ebbd89 Binary files /dev/null and b/scripts/bws-secure/bin/backup/v1.0.0/bws-x86_64-unknown-linux-gnu-1.0.0.zip differ diff --git a/scripts/bws-secure/bws-dotenv.js b/scripts/bws-secure/bws-dotenv.js index ddf398e8ac3..a38242cce7b 100755 --- a/scripts/bws-secure/bws-dotenv.js +++ b/scripts/bws-secure/bws-dotenv.js @@ -105,7 +105,7 @@ function decryptContent(encrypted, encryptionKey) { function loadBwsSecrets(encryptionKey) { // Always load from .env file first - const environmentConfig = dotenv.config(); + const environmentConfig = dotenv.config({ quiet: true }); const environmentToken = environmentConfig.parsed?.BWS_ACCESS_TOKEN; // Override any existing token with the one from .env @@ -153,7 +153,6 @@ function loadBwsSecrets(encryptionKey) { ); // These are data processing operations, not command executions - // eslint-disable-next-line no-control-regex const cleanOutput = output.replaceAll(/\u001B\[\d+m/g, '').trim(); const globalSecrets = parseEnvironmentOutput(cleanOutput); diff --git a/scripts/bws-secure/bws-installer.sh b/scripts/bws-secure/bws-installer.sh index c0d845ead51..ab7bf7df57c 100755 --- a/scripts/bws-secure/bws-installer.sh +++ b/scripts/bws-secure/bws-installer.sh @@ -4,9 +4,13 @@ # Custom installer for bws CLI in a project repo # ################################################## -DEFAULT_BWS_VERSION="0.5.0" +DEFAULT_BWS_VERSION="1.0.0" BWS_VERSION="${BWS_VERSION:-$DEFAULT_BWS_VERSION}" +# Determine script directory for finding local backups +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +BACKUP_DIR="$SCRIPT_DIR/bin/backup" + # Cross-platform temp base and cleanup trap TMP_BASE="${TMPDIR:-${TEMP:-${TMP:-/tmp}}}" cleanup() { @@ -21,21 +25,35 @@ main() { -u | --uninstall) uninstall_bws ;; + -f | --force) + FORCE_INSTALL=1 + run_install + ;; *) - check_required - - # Check if BWS_VERSION is valid or fall back to default - platform_detect - arch_detect - check_version_availability - - download_bws - validate_checksum - install_bws + FORCE_INSTALL=0 + run_install ;; esac } +run_install() { + check_required + platform_detect + arch_detect + + # Skip if already installed at correct version (unless forced) + if [ "$FORCE_INSTALL" -eq 0 ] && check_already_installed; then + echo "bws v${BWS_VERSION} already installed, skipping." + echo "To force reinstall: sh ./scripts/bws-secure/bws-installer.sh -f" + exit 0 + fi + + check_version_availability + download_bws + validate_checksum + install_bws +} + error() { echo "$1" >&2 echo "Exiting..." >&2 @@ -52,6 +70,28 @@ check_required() { fi } +check_already_installed() { + bws_bin="$(pwd)/node_modules/.bin/bws" + + if [ ! -f "$bws_bin" ]; then + return 1 # Not installed + fi + + # Get installed version (bws --version outputs "bws x.y.z") + installed_version="$("$bws_bin" --version 2>/dev/null | awk '{print $2}')" + + if [ -z "$installed_version" ]; then + return 1 # Couldn't determine version + fi + + if [ "$installed_version" = "$BWS_VERSION" ]; then + return 0 # Already installed at correct version + fi + + echo "Installed version ($installed_version) differs from requested ($BWS_VERSION), updating..." + return 1 +} + platform_detect() { if [ "$(uname -s)" = "Linux" ]; then PLATFORM="unknown-linux-gnu" @@ -92,22 +132,53 @@ downloader() { fi } +downloader_with_check() { + if command -v curl >/dev/null; then + curl -L --fail --silent --show-error -o "$2" "$1" 2>/dev/null + else + wget -q -O "$2" "$1" 2>/dev/null + fi +} + extract() { unzip -o "$1" -d "$2" } download_bws() { - bws_url="https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" - echo "Downloading bws from: $bws_url" tmp_dir="$(mktemp -d "$TMP_BASE/bws-secure.XXXXXXXXXX")" - downloader "$bws_url" "$tmp_dir/bws.zip" + local_backup="$BACKUP_DIR/v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + bws_url="https://github.com/bitwarden/sdk-sm/releases/download/bws-v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + + # Try download first, fall back to local backup if download fails + echo "Downloading bws from: $bws_url" + if downloader_with_check "$bws_url" "$tmp_dir/bws.zip"; then + USE_LOCAL_BACKUP=0 + else + echo "Download failed, checking for local backup..." + if [ -f "$local_backup" ]; then + echo "Using local backup: $local_backup" + cp "$local_backup" "$tmp_dir/bws.zip" + USE_LOCAL_BACKUP=1 + else + error "Download failed and no local backup found at: $local_backup" + fi + fi } validate_checksum() { - checksum_url="https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-sha256-checksums-${BWS_VERSION}.txt" - echo "Downloading checksum file from: $checksum_url" + local_checksum_file="$BACKUP_DIR/v${BWS_VERSION}/bws-sha256-checksums-${BWS_VERSION}.txt" checksum_file="$tmp_dir/bws-checksums.txt" - downloader "$checksum_url" "$checksum_file" + checksum_url="https://github.com/bitwarden/sdk-sm/releases/download/bws-v${BWS_VERSION}/bws-sha256-checksums-${BWS_VERSION}.txt" + + # Try download first, fall back to local checksum file + if downloader_with_check "$checksum_url" "$checksum_file"; then + echo "Downloaded checksum file." + elif [ -f "$local_checksum_file" ]; then + echo "Using local checksum file: $local_checksum_file" + cp "$local_checksum_file" "$checksum_file" + else + error "Could not download checksum file and no local backup found." + fi expected_checksum="$(grep "bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" "$checksum_file" | awk '{print $1}')" actual_checksum="$(checksum "$tmp_dir/bws.zip" | awk '{print $1}')" @@ -178,18 +249,28 @@ uninstall_bws() { } check_version_availability() { - # Attempt a simple HEAD request to see if the requested version URL exists - test_url="https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + local_backup="$BACKUP_DIR/v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + test_url="https://github.com/bitwarden/sdk-sm/releases/download/bws-v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + # Attempt a HEAD request to see if the requested version URL exists if command -v curl >/dev/null; then - if ! curl --head --silent --fail "$test_url" >/dev/null; then - echo "Version bws-v${BWS_VERSION} not found. Falling back to default ${DEFAULT_BWS_VERSION}..." + if ! curl --head --silent --fail "$test_url" >/dev/null 2>&1; then + # Remote not available - check if we have local backup before falling back + if [ -f "$local_backup" ]; then + echo "Remote v${BWS_VERSION} unavailable, but local backup exists. Continuing..." + return 0 + fi + echo "Version bws-v${BWS_VERSION} not found remotely or locally. Falling back to default ${DEFAULT_BWS_VERSION}..." BWS_VERSION="$DEFAULT_BWS_VERSION" fi else # Fallback if wget is used - if ! wget --spider -q "$test_url"; then - echo "Version bws-v${BWS_VERSION} not found. Falling back to default ${DEFAULT_BWS_VERSION}..." + if ! wget --spider -q "$test_url" 2>/dev/null; then + if [ -f "$local_backup" ]; then + echo "Remote v${BWS_VERSION} unavailable, but local backup exists. Continuing..." + return 0 + fi + echo "Version bws-v${BWS_VERSION} not found remotely or locally. Falling back to default ${DEFAULT_BWS_VERSION}..." BWS_VERSION="$DEFAULT_BWS_VERSION" fi fi diff --git a/scripts/bws-secure/check-vars/requiredRuntimeVars.js b/scripts/bws-secure/check-vars/requiredRuntimeVars.js index 14a393510e7..3f2351a311f 100755 --- a/scripts/bws-secure/check-vars/requiredRuntimeVars.js +++ b/scripts/bws-secure/check-vars/requiredRuntimeVars.js @@ -29,6 +29,7 @@ import { fileURLToPath } from 'node:url'; import { promises as fsPromises } from 'node:fs'; // Fixed ESM import - glob doesn't provide a default export in ESM import * as globModule from 'glob'; +import { promisify } from 'node:util'; import logger from '../logger.js'; // Get the directory name in ESM @@ -428,7 +429,7 @@ function wildcardToRegex(pattern) { */ function parseGlobPath(userPath) { const slashIndex = userPath.indexOf('/'); - const starIndex = userPath.search(/[*?]/); + const starIndex = userPath.search(/[\*\?]/); // If the wildcard (* or ?) appears before an actual slash, or no slash at all, // assume the user typed something like "**/*.js" with no base directory diff --git a/scripts/bws-secure/generate-env-debug.js b/scripts/bws-secure/generate-env-debug.js index ac0e91ee93d..81f43bbf27b 100755 --- a/scripts/bws-secure/generate-env-debug.js +++ b/scripts/bws-secure/generate-env-debug.js @@ -24,11 +24,11 @@ const envPath = possibleEnvPaths.find((path) => fs.existsSync(path)); if (envPath) { console.log(`\x1b[36mLoading .env from:\x1b[0m ${envPath}`); - dotenv.config({ path: envPath }); + dotenv.config({ path: envPath, quiet: true }); } else { console.log('\x1b[33mNo .env file found in common locations. Using process.env directly.\x1b[0m'); // Still call config() to ensure dotenv is initialized - dotenv.config(); + dotenv.config({ quiet: true }); } // Log environment loading status diff --git a/scripts/bws-secure/install.sh b/scripts/bws-secure/install.sh index 416ca1414b4..14ed976ea40 100755 --- a/scripts/bws-secure/install.sh +++ b/scripts/bws-secure/install.sh @@ -105,7 +105,7 @@ if [ "$NODE_VERSION" -lt "20" ]; then packageJson.dependencies.yargs = '^18.0.0'; } if (packageJson.dependencies && packageJson.dependencies.glob) { - packageJson.dependencies.glob = '^11.0.3'; + packageJson.dependencies.glob = '^11.1.0'; } } else { // For Node.js < 20, use compatible versions @@ -359,8 +359,8 @@ try { // Add dependencies if they don't exist packageJson.devDependencies = packageJson.devDependencies || {}; - packageJson.devDependencies['dotenv'] = packageJson.devDependencies['dotenv'] || '^17.2.2'; - packageJson.devDependencies['dotenv-cli'] = packageJson.devDependencies['dotenv-cli'] || '^10.0.0'; + packageJson.devDependencies['dotenv'] = packageJson.devDependencies['dotenv'] || '^17.2.3'; + packageJson.devDependencies['dotenv-cli'] = packageJson.devDependencies['dotenv-cli'] || '^11.0.0'; // Check Node.js version and apply appropriate versions const nodeVersion = process.version.match(/^v(\d+)\./)[1]; @@ -368,14 +368,14 @@ try { if (nodeVersionNum >= 20) { // For Node.js 20+, use newer versions packageJson.devDependencies['yargs'] = packageJson.devDependencies['yargs'] || '^18.0.0'; - packageJson.devDependencies['glob'] = '^11.0.3'; + packageJson.devDependencies['glob'] = '^11.1.0'; } else { // For Node.js < 20, use compatible versions packageJson.devDependencies['yargs'] = packageJson.devDependencies['yargs'] || '^17.7.2'; packageJson.devDependencies['glob'] = '^10.3.10'; } - packageJson.devDependencies['axios'] = packageJson.devDependencies['axios'] || '^1.12.2'; + packageJson.devDependencies['axios'] = packageJson.devDependencies['axios'] || '^1.13.2'; // Detect existing indentation or use prettier config const originalContent = fs.readFileSync(packageJsonPath, 'utf8'); @@ -518,53 +518,6 @@ else echo "Prettier not found, skipping formatting (files may have different formatting than your project)" fi -# Success message with box drawing characters -echo -e " -${GREEN}╔════════════════════════════════════════════════════════════╗ -║ ✅ BWS Secure Setup Complete! ║ -╚════════════════════════════════════════════════════════════╝${NC} - -📋 Next Steps: - -1. Configure your bwsconfig.json at: - $(pwd)/bwsconfig.json - - Set platform to 'vercel' or 'netlify' - - Update projectName to match your deployment - - Add your BWS project IDs for each environment - -2. Add your BWS token to .env: - BWS_ACCESS_TOKEN=your_token_here - -3. Update your build scripts to use secure-run: - \"dev\": \"secure-run next dev\" - \"build\": \"secure-run next build\" - \"start\": \"secure-run next start\" - -🔧 Added Scripts: - - secure-run: Runs commands with secure environment variables - - list-projects: Lists available BWS projects - - bws-deps: Ensures BWS dependencies are installed - - bws-update: Updates BWS Secure to the latest version - -📦 Dependencies: - - BWS CLI will be installed automatically when needed - - Required packages have been added to package.json - (dotenv, dotenv-cli, yargs, glob, axios) - - Run '$PM bws-deps' to verify BWS installation - -🔒 Security: - - Environment files are encrypted - - .gitignore has been updated - - Secrets are never logged - -📚 Documentation: https://github.com/last-rev-llc/bws-secure - -For help or issues: -1. Check the README.md in scripts/bws-secure/ -2. Enable debug mode: DEBUG=true $PM build -3. Open an issue on GitHub -" - echo "Checking Prettier configuration..." # Create or update .prettierignore PRETTIER_ENTRIES=( diff --git a/scripts/bws-secure/package.json b/scripts/bws-secure/package.json index f5ff56cda2a..97c759769cb 100644 --- a/scripts/bws-secure/package.json +++ b/scripts/bws-secure/package.json @@ -10,10 +10,10 @@ "scan": "node check-vars/requiredRuntimeVars.js" }, "dependencies": { - "axios": "^1.12.2", - "dotenv": "^17.2.2", - "dotenv-cli": "^10.0.0", - "glob": "^11.0.3", + "axios": "^1.13.2", + "dotenv": "^17.2.3", + "dotenv-cli": "^11.0.0", + "glob": "^11.1.0", "yargs": "^18.0.0" } } diff --git a/scripts/bws-secure/project-selector.js b/scripts/bws-secure/project-selector.js index 9c7a50554ad..a08dbc40fa4 100644 --- a/scripts/bws-secure/project-selector.js +++ b/scripts/bws-secure/project-selector.js @@ -290,8 +290,8 @@ async function getProjectFromEnvironmentFile() { const content = await fsPromises.readFile(environmentPath, 'utf8'); const lines = content.split('\n'); - // Look for an uncommented BWS_PROJECT line - const projectLine = lines.find((line) => { + // Look for an uncommented BWS_PROJECT line (last one wins, matching shell behavior) + const projectLine = lines.findLast((line) => { const trimmed = line.trim(); return trimmed.startsWith('BWS_PROJECT=') && !trimmed.startsWith('#'); }); diff --git a/scripts/bws-secure/secureRun.js b/scripts/bws-secure/secureRun.js index 8740a869a74..4d03114f697 100755 --- a/scripts/bws-secure/secureRun.js +++ b/scripts/bws-secure/secureRun.js @@ -2,10 +2,11 @@ /* eslint-disable no-console */ -import { spawnSync } from 'node:child_process'; +import { spawnSync, execSync } from 'node:child_process'; import crypto from 'node:crypto'; import fs, { promises as fsPromises } from 'node:fs'; import path from 'node:path'; +import readline from 'node:readline'; import { fileURLToPath } from 'node:url'; import dotenv from 'dotenv'; import { ensureBwsInstalled } from './bws-dotenv.js'; @@ -13,6 +14,7 @@ import { promptForProject, updateEnvironmentBwsSection, determineEnvironment, + normalizeEnvironment, readConfigFile, log } from './project-selector.js'; @@ -133,7 +135,6 @@ async function readConfigFileWithFallback() { ); // Clean output of any ANSI codes - // eslint-disable-next-line no-control-regex const cleanOutput = output.replace(/\u001B\[\d+m/g, '').trim(); const secrets = JSON.parse(cleanOutput); @@ -816,7 +817,6 @@ async function setupEnvironment(options = { isPlatformBuild: false }) { if (result.status === 0) { // Always clean the output, even without DEBUG - // eslint-disable-next-line no-control-regex const cleanOutput = result.stdout.replaceAll(/\u001B\[\d+m/g, '').trim(); try { @@ -1578,7 +1578,13 @@ async function handleUploadCommand() { process.exit(0); } - const result = spawnSync(arguments_.join(' '), [], { + // Normalize command - strip wrapping quotes that may have been passed literally + // This handles cases like: pnpm secure-run "turbo dev" where quotes become part of argv + // Works cross-platform: Linux, macOS, Windows (cmd.exe, PowerShell), and CI/CD environments + let commandString = arguments_.join(' '); + commandString = commandString.replace(/^["'](.*)["']$/, '$1').trim(); + + const result = spawnSync(commandString, [], { stdio: 'inherit', env: process.env, shell: true diff --git a/scripts/bws-secure/tests/test-error-formatting.js b/scripts/bws-secure/tests/test-error-formatting.js index 8851b901977..0b05163daa5 100755 --- a/scripts/bws-secure/tests/test-error-formatting.js +++ b/scripts/bws-secure/tests/test-error-formatting.js @@ -1,5 +1,6 @@ /* eslint-disable no-console */ import { updateVercelEnvVars } from '../update-environments/vercel.js'; +import { log } from '../update-environments/utils.js'; async function testErrorFormatting() { try { diff --git a/scripts/bws-secure/tests/test-netlify-upload.js b/scripts/bws-secure/tests/test-netlify-upload.js index d1bce1bd746..4ffeb6bc110 100755 --- a/scripts/bws-secure/tests/test-netlify-upload.js +++ b/scripts/bws-secure/tests/test-netlify-upload.js @@ -1,9 +1,10 @@ /* eslint-disable no-console */ +import { spawnSync } from 'node:child_process'; import path from 'node:path'; import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import { updateNetlifyEnvVars } from './update-environments/netlify.js'; -import { log } from './update-environments/utils.js'; +import { log, validateDeployment } from './update-environments/utils.js'; import dotenv from 'dotenv'; // Get the directory name in ESM @@ -11,7 +12,7 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Load .env file if it exists -dotenv.config(); +dotenv.config({ quiet: true }); async function testNetlifyUpload() { try { diff --git a/scripts/bws-secure/tests/vercel-api-test.js b/scripts/bws-secure/tests/vercel-api-test.js index f9c260a17e5..7ecac658ff7 100644 --- a/scripts/bws-secure/tests/vercel-api-test.js +++ b/scripts/bws-secure/tests/vercel-api-test.js @@ -7,12 +7,13 @@ */ import axios from 'axios'; +import fs from 'node:fs'; import dotenv from 'dotenv'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; // Load environment variables from .env file -dotenv.config(); +dotenv.config({ quiet: true }); // Get the directory name in ESM const __filename = fileURLToPath(import.meta.url); diff --git a/scripts/bws-secure/update-environments/map-env-files.js b/scripts/bws-secure/update-environments/map-env-files.js index 9448742538c..616fdb70f6a 100644 --- a/scripts/bws-secure/update-environments/map-env-files.js +++ b/scripts/bws-secure/update-environments/map-env-files.js @@ -18,6 +18,9 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; +import yargs from 'yargs/yargs'; +import { hideBin } from 'yargs/helpers'; +import dotenv from 'dotenv'; import crypto from 'node:crypto'; import { log } from './utils.js'; diff --git a/scripts/bws-secure/update-environments/netlify.js b/scripts/bws-secure/update-environments/netlify.js index 4212e31289a..e4e3b5586fd 100755 --- a/scripts/bws-secure/update-environments/netlify.js +++ b/scripts/bws-secure/update-environments/netlify.js @@ -15,7 +15,14 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import axios from 'axios'; -import { log, loadEnvironmentVariables, validateDeployment, getBuildOrAuthToken } from './utils.js'; +import { + log, + handleError, + loadEnvironmentVariables, + validateDeployment, + shouldPreserveVar as shouldPreserveVariable, + getBuildOrAuthToken +} from './utils.js'; // Get the directory name in ESM const __filename = fileURLToPath(import.meta.url); @@ -35,7 +42,6 @@ async function withRateLimitRetry(apiCall, maxRetries = 3, initialDelay = 1000) let retries = 0; let delay = initialDelay; - // eslint-disable-next-line no-constant-condition while (true) { try { return await apiCall(); diff --git a/scripts/bws-secure/update-environments/updateEnvVars.js b/scripts/bws-secure/update-environments/updateEnvVars.js index 2306dcc0137..8ae1ef42591 100755 --- a/scripts/bws-secure/update-environments/updateEnvVars.js +++ b/scripts/bws-secure/update-environments/updateEnvVars.js @@ -23,18 +23,24 @@ import { promises as fsPromises } from 'node:fs'; // For async operations import path from 'node:path'; import { fileURLToPath } from 'node:url'; import dotenv from 'dotenv'; +import { hideBin } from 'yargs/helpers'; +import yargs from 'yargs/yargs'; import { readVars as readNetlifyVariables, updateNetlifyEnvVars as updateNetlifyEnvironmentVariables } from './netlify.js'; import { handleError, + readEnvFile as readEnvironmentFile, validateValue, shouldPreserveVar as shouldPreserveVariable, + getBuildOrAuthToken, + validateDeployment, decryptContent } from './utils.js'; import { readVars as readVercelVariables, + updateVars as updateVercelVariables, updateVercelEnvVars as updateVercelEnvironmentVariables } from './vercel.js'; import logger from '../logger.js'; diff --git a/scripts/bws-secure/update-environments/utils.js b/scripts/bws-secure/update-environments/utils.js index ed446fd6e91..77a57673fe3 100755 --- a/scripts/bws-secure/update-environments/utils.js +++ b/scripts/bws-secure/update-environments/utils.js @@ -213,7 +213,7 @@ function validateValue(key, value) { return { isValid: false, error: 'Token seems too short (min 10 chars)' }; } // Basic format check for common token patterns - if (!value.match(/^[A-Za-z0-9_\-.]+$/)) { + if (!value.match(/^[A-Za-z0-9_\-\.]+$/)) { return { isValid: false, error: 'Token contains invalid characters (should be alphanumeric with _ - .)' diff --git a/scripts/bws-secure/update-environments/vercel.js b/scripts/bws-secure/update-environments/vercel.js index acd3d248a10..20574d081e4 100755 --- a/scripts/bws-secure/update-environments/vercel.js +++ b/scripts/bws-secure/update-environments/vercel.js @@ -14,7 +14,14 @@ import util from 'node:util'; import { exec } from 'node:child_process'; const execPromise = util.promisify(exec); -import { log, loadEnvironmentVariables, validateDeployment, shouldPreserveVar } from './utils.js'; +import { + log, + handleError, + determineEnvironmentMapping, + loadEnvironmentVariables, + validateDeployment, + shouldPreserveVar +} from './utils.js'; import axios from 'axios'; import fs from 'node:fs'; import path from 'node:path'; @@ -35,6 +42,9 @@ const vercelEnvCache = new Map(); function getRandomTimeout() { const minSeconds = 1; const maxSeconds = 15; + // Security Note: Math.random() used for timeout jitter in build coordination, not cryptographic purposes + // This is acceptable for non-security-critical use case (preventing concurrent build conflicts) + // CWE-338 false positive - not used for security-sensitive operations const randomSeconds = Math.floor(Math.random() * (maxSeconds - minSeconds + 1) + minSeconds); const timeout = randomSeconds * 1000; log('debug', `Using random timeout of ${randomSeconds} seconds`); diff --git a/scripts/bws-secure/upload-to-bws/upload-secrets.js b/scripts/bws-secure/upload-to-bws/upload-secrets.js index 7bdb06789c7..96f8e5e9643 100755 --- a/scripts/bws-secure/upload-to-bws/upload-secrets.js +++ b/scripts/bws-secure/upload-to-bws/upload-secrets.js @@ -11,7 +11,10 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { execSync } from 'node:child_process'; +import { execSync, spawnSync } from 'node:child_process'; +import readline from 'node:readline'; +import { promises as fsPromises } from 'node:fs'; +import crypto from 'node:crypto'; import dotenv from 'dotenv'; // Get the directory name in ESM @@ -50,10 +53,10 @@ const rootEnvPath = path.join(__dirname, '../../../.env'); // Check for and load whichever .env file we find if (fs.existsSync(localEnvPath)) { console.log(`Loading environment from local .env at: ${localEnvPath}`); - dotenv.config({ path: localEnvPath }); + dotenv.config({ path: localEnvPath, quiet: true }); } else if (fs.existsSync(rootEnvPath)) { console.log(`Loading environment from root .env at: ${rootEnvPath}`); - dotenv.config({ path: rootEnvPath }); + dotenv.config({ path: rootEnvPath, quiet: true }); } else { console.log('No local or root .env file found. Relying on existing environment variables.'); }