├── .configs └── tsconfig.base.json ├── .env.example ├── .eslintignore ├── .github └── workflows │ ├── build-docker-image.yml │ └── submit.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── SECURITY.md ├── apps ├── init │ ├── .gitignore │ ├── Dockerfile │ ├── README.md │ ├── entrypoint.sh │ ├── package.json │ ├── src │ │ ├── cli │ │ │ ├── index.ts │ │ │ └── version.ts │ │ ├── commands │ │ │ └── init.ts │ │ ├── index.ts │ │ └── utils │ │ │ ├── ascii.ts │ │ │ ├── env.ts │ │ │ └── trigger.ts │ ├── trigger.dump │ ├── tsconfig.json │ └── vite.config.ts └── webapp │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── app │ ├── components │ │ ├── ErrorDisplay.tsx │ │ ├── activity │ │ │ └── contribution-graph.tsx │ │ ├── api │ │ │ ├── api-table.tsx │ │ │ ├── columns.tsx │ │ │ └── index.ts │ │ ├── common │ │ │ └── page-header.tsx │ │ ├── conversation │ │ │ ├── conversation-item.client.tsx │ │ │ ├── conversation-list.tsx │ │ │ ├── conversation-textarea.client.tsx │ │ │ ├── conversation.client.tsx │ │ │ ├── editor-extensions.tsx │ │ │ ├── index.ts │ │ │ ├── streaming-conversation.client.tsx │ │ │ └── use-trigger-stream.tsx │ │ ├── editor │ │ │ ├── conversation-context.tsx │ │ │ └── skill-extension │ │ │ │ ├── index.ts │ │ │ │ ├── skill-component.tsx │ │ │ │ └── skill-extension.ts │ │ ├── graph │ │ │ ├── graph-client.tsx │ │ │ ├── graph-clustering-visualization.tsx │ │ │ ├── graph-clustering.tsx │ │ │ ├── graph-filters.tsx │ │ │ ├── graph-popover.tsx │ │ │ ├── graph-visualization.tsx │ │ │ ├── graph.tsx │ │ │ ├── node-colors.ts │ │ │ ├── space-search.tsx │ │ │ ├── type.ts │ │ │ └── utils.ts │ │ ├── icon-picker │ │ │ ├── emoji-data.ts │ │ │ ├── icon-picker.tsx │ │ │ ├── index.ts │ │ │ └── utils.tsx │ │ ├── icon-utils.tsx │ │ ├── icons │ │ │ ├── arrows.tsx │ │ │ ├── claude.tsx │ │ │ ├── cline.tsx │ │ │ ├── cursor.tsx │ │ │ ├── index.ts │ │ │ ├── linear-icon.tsx │ │ │ ├── project.tsx │ │ │ ├── slack-icon.tsx │ │ │ ├── types.tsx │ │ │ └── vscode.tsx │ │ ├── ingestion │ │ │ └── floating-ingestion-status.tsx │ │ ├── integrations │ │ │ ├── api-key-auth-section.tsx │ │ │ ├── connected-account-section.tsx │ │ │ ├── ingestion-rule-section.tsx │ │ │ ├── integration-card.tsx │ │ │ ├── integration-grid.tsx │ │ │ ├── mcp-auth-section.tsx │ │ │ ├── oauth-auth-section.tsx │ │ │ ├── section.tsx │ │ │ └── utils.tsx │ │ ├── layout │ │ │ ├── app-layout.tsx │ │ │ ├── login-page-layout.tsx │ │ │ └── onboarding-layout.tsx │ │ ├── logo │ │ │ ├── core.svg │ │ │ ├── index.ts │ │ │ └── logo.tsx │ │ ├── logs │ │ │ ├── index.ts │ │ │ ├── log-details.tsx │ │ │ ├── log-options.tsx │ │ │ ├── log-text-collapse.tsx │ │ │ ├── logs-filters.tsx │ │ │ └── virtual-logs-list.tsx │ │ ├── nav-main.tsx │ │ ├── nav-projects.tsx │ │ ├── nav-secondary.tsx │ │ ├── nav-user.tsx │ │ ├── setting-section.tsx │ │ ├── sidebar │ │ │ ├── app-sidebar.tsx │ │ │ ├── nav-main.tsx │ │ │ └── nav-user.tsx │ │ ├── spaces │ │ │ ├── edit-space-dialog.client.tsx │ │ │ ├── new-space-dialog.client.tsx │ │ │ ├── space-card.tsx │ │ │ ├── space-fact-card.tsx │ │ │ ├── space-facts-filters.tsx │ │ │ ├── space-facts-list.tsx │ │ │ ├── space-graph.tsx │ │ │ ├── space-options.tsx │ │ │ ├── space-properties.tsx │ │ │ ├── space-summary.client.tsx │ │ │ └── spaces-grid.tsx │ │ ├── ui │ │ │ ├── Fieldset.tsx │ │ │ ├── FormButtons.tsx │ │ │ ├── Headers.tsx │ │ │ ├── Icon.tsx │ │ │ ├── Paragraph.tsx │ │ │ ├── TextLink.tsx │ │ │ ├── alert-dialog.tsx │ │ │ ├── alert.tsx │ │ │ ├── avatar.tsx │ │ │ ├── badge.tsx │ │ │ ├── breadcrumb.tsx │ │ │ ├── button.tsx │ │ │ ├── card.tsx │ │ │ ├── checkbox.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── color-utils.ts │ │ │ ├── command.tsx │ │ │ ├── dialog.tsx │ │ │ ├── dropdown-menu.tsx │ │ │ ├── index.ts │ │ │ ├── input.tsx │ │ │ ├── label.tsx │ │ │ ├── multi-select.tsx │ │ │ ├── pagination.tsx │ │ │ ├── popover.tsx │ │ │ ├── resizable.tsx │ │ │ ├── scrollarea.tsx │ │ │ ├── select.tsx │ │ │ ├── separator.tsx │ │ │ ├── sheet.tsx │ │ │ ├── sidebar.tsx │ │ │ ├── skeleton.tsx │ │ │ ├── slider.tsx │ │ │ ├── table.tsx │ │ │ ├── tabs.tsx │ │ │ ├── textarea.tsx │ │ │ └── tooltip.tsx │ │ ├── use-auto-scroll.tsx │ │ └── virtualized-list │ │ │ ├── index.ts │ │ │ └── scroll-managed-list.tsx │ ├── db.server.ts │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── env.server.ts │ ├── hooks │ │ ├── use-autosize-textarea.tsx │ │ ├── use-debounce.ts │ │ ├── use-ingestion-status.tsx │ │ ├── use-local-state.tsx │ │ ├── use-logs.tsx │ │ ├── use-mobile.ts │ │ ├── use-mobile.tsx │ │ ├── useChanged.ts │ │ ├── usePostHog.ts │ │ ├── useTypedMatchData.ts │ │ ├── useUser.ts │ │ └── useWorkspace.ts │ ├── lib │ │ ├── batch.server.ts │ │ ├── batch │ │ │ ├── base-provider.ts │ │ │ ├── providers │ │ │ │ ├── anthropic.ts │ │ │ │ └── openai.ts │ │ │ └── types.ts │ │ ├── ingest.server.ts │ │ ├── model.server.ts │ │ ├── neo4j.server.ts │ │ ├── usePersistentState.ts │ │ └── utils.ts │ ├── models │ │ ├── message.server.ts │ │ ├── personal-token.server.ts │ │ ├── user.server.ts │ │ └── workspace.server.ts │ ├── root.tsx │ ├── routes │ │ ├── _index.tsx │ │ ├── action.set-theme.ts │ │ ├── api.oauth.clients.$clientId.tsx │ │ ├── api.oauth.clients.tsx │ │ ├── api.profile.tsx │ │ ├── api.v1.activity.contribution.tsx │ │ ├── api.v1.activity.tsx │ │ ├── api.v1.add.tsx │ │ ├── api.v1.conversation.$conversationId.read.tsx │ │ ├── api.v1.conversation.$conversationId.run.tsx │ │ ├── api.v1.conversation.$conversationId.stop.tsx │ │ ├── api.v1.conversation.$conversationId.tsx │ │ ├── api.v1.conversation._index.tsx │ │ ├── api.v1.conversations.tsx │ │ ├── api.v1.episodes.$episodeId.facts.tsx │ │ ├── api.v1.extension-search.tsx │ │ ├── api.v1.extension-summary.tsx │ │ ├── api.v1.graph.clustered.tsx │ │ ├── api.v1.ingestion-queue.status.tsx │ │ ├── api.v1.ingestion-rules.$id.tsx │ │ ├── api.v1.ingestion-rules.tsx │ │ ├── api.v1.ingestion_queue.delete.tsx │ │ ├── api.v1.integration_account.$id.credentials.tsx │ │ ├── api.v1.integration_account.disconnect.tsx │ │ ├── api.v1.integration_account.disconnect_mcp.tsx │ │ ├── api.v1.integration_account.tsx │ │ ├── api.v1.integrations.tsx │ │ ├── api.v1.logs.tsx │ │ ├── api.v1.mcp.$slug.tsx │ │ ├── api.v1.mcp.memory.tsx │ │ ├── api.v1.oauth._index.tsx │ │ ├── api.v1.oauth.callback.mcp.tsx │ │ ├── api.v1.oauth.callback.tsx │ │ ├── api.v1.search.tsx │ │ ├── api.v1.spaces.$spaceId.reset.ts │ │ ├── api.v1.spaces.$spaceId.statements.ts │ │ ├── api.v1.spaces.$spaceId.ts │ │ ├── api.v1.spaces.assignments.ts │ │ ├── api.v1.spaces.ts │ │ ├── api.v1.webhooks.$id.tsx │ │ ├── api.v1.webhooks.tsx │ │ ├── auth.google.callback.tsx │ │ ├── auth.google.tsx │ │ ├── confirm-basic-details.tsx │ │ ├── home.conversation.$conversationId.tsx │ │ ├── home.conversation._index.tsx │ │ ├── home.dashboard.tsx │ │ ├── home.integration.$slug.tsx │ │ ├── home.integrations.tsx │ │ ├── home.logs.tsx │ │ ├── home.space.$spaceId.facts.tsx │ │ ├── home.space.$spaceId.overview.tsx │ │ ├── home.space.$spaceId.tsx │ │ ├── home.space._index.tsx │ │ ├── home.tsx │ │ ├── login._index.tsx │ │ ├── login.magic.tsx │ │ ├── logout.tsx │ │ ├── magic.tsx │ │ ├── oauth.authorize.tsx │ │ ├── oauth.register.tsx │ │ ├── oauth.token.tsx │ │ ├── oauth.tokeninfo.tsx │ │ ├── oauth.userinfo.tsx │ │ ├── onboarding.tsx │ │ ├── settings.api.tsx │ │ ├── settings.tsx │ │ ├── settings.webhooks.tsx │ │ └── webhook.$sourceName.tsx │ ├── services │ │ ├── apiAuth.server.ts │ │ ├── auth.server.ts │ │ ├── authUser.ts │ │ ├── authorization.server.ts │ │ ├── clustering.server.ts │ │ ├── conversation.server.ts │ │ ├── email.server.ts │ │ ├── emailAuth.server.tsx │ │ ├── episodeFacts.server.ts │ │ ├── googleAuth.server.ts │ │ ├── graphModels │ │ │ ├── entity.ts │ │ │ ├── episode.ts │ │ │ ├── space.ts │ │ │ └── statement.ts │ │ ├── httpAsyncStorage.server.ts │ │ ├── impersonation.server.ts │ │ ├── ingestionLogs.server.ts │ │ ├── ingestionRule.server.ts │ │ ├── integration.server.ts │ │ ├── integrationAccount.server.ts │ │ ├── integrationDefinition.server.ts │ │ ├── knowledgeGraph.server.ts │ │ ├── logger.service.ts │ │ ├── oauth │ │ │ ├── oauth-utils.server.ts │ │ │ └── oauth.server.ts │ │ ├── oauth2.server.ts │ │ ├── oauthIntegration.server.ts │ │ ├── personalAccessToken.server.ts │ │ ├── postAuth.server.ts │ │ ├── prompts │ │ │ ├── index.ts │ │ │ ├── nodes.ts │ │ │ ├── normalize.ts │ │ │ └── statements.ts │ │ ├── redirectTo.server.ts │ │ ├── routeBuilders │ │ │ └── apiBuilder.server.ts │ │ ├── search.server.ts │ │ ├── search │ │ │ ├── rerank.ts │ │ │ └── utils.ts │ │ ├── sensitiveDataReplacer.ts │ │ ├── session.server.ts │ │ ├── sessionStorage.server.ts │ │ ├── space.server.ts │ │ └── webhook.server.ts │ ├── tailwind.css │ ├── trigger │ │ ├── .gitkeep │ │ ├── chat │ │ │ ├── chat-utils.ts │ │ │ ├── chat.ts │ │ │ ├── memory-utils.ts │ │ │ ├── prompt.ts │ │ │ ├── stream-utils.ts │ │ │ └── types.ts │ │ ├── cluster │ │ │ └── index.ts │ │ ├── conversation │ │ │ ├── create-conversation-title.ts │ │ │ └── prompt.ts │ │ ├── ingest │ │ │ └── ingest.ts │ │ ├── integrations │ │ │ ├── integration-run-schedule.ts │ │ │ ├── integration-run.ts │ │ │ └── scheduler.ts │ │ ├── spaces │ │ │ ├── space-assignment.ts │ │ │ ├── space-pattern.ts │ │ │ └── space-summary.ts │ │ ├── temp.ts │ │ ├── utils │ │ │ ├── cli-message-handler.ts │ │ │ ├── mcp.ts │ │ │ ├── message-utils.ts │ │ │ ├── prisma.ts │ │ │ ├── queue.ts │ │ │ ├── space-status.ts │ │ │ ├── space-utils.ts │ │ │ ├── stdio.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ └── webhooks │ │ │ ├── integration-webhook-delivery.ts │ │ │ ├── webhook-delivery-utils.ts │ │ │ └── webhook-delivery.ts │ ├── utils.ts │ └── utils │ │ ├── apiCors.ts │ │ ├── auth-helper.ts │ │ ├── boolEnv.ts │ │ ├── db.ts │ │ ├── httpErrors.ts │ │ ├── json.ts │ │ ├── mcp.ts │ │ ├── oauth2-middleware.ts │ │ ├── pathBuilder.ts │ │ ├── presets │ │ └── nodes.ts │ │ ├── proxy.server.ts │ │ ├── regex.ts │ │ ├── requestUrl.server.ts │ │ ├── singleton.ts │ │ └── startup.ts │ ├── components.json │ ├── integrations │ └── slack │ │ └── main │ ├── openapi-docs.yaml │ ├── openapi.yaml │ ├── package.json │ ├── prisma │ └── schema.prisma │ ├── public │ ├── favicon.ico │ ├── login.png │ ├── logo-dark.png │ ├── logo-dark.svg │ ├── logo-light.png │ ├── logo-light.svg │ └── logo.png │ ├── remix.env.d.ts │ ├── server.mjs │ ├── tailwind.config.ts │ ├── trigger.config.ts │ ├── tsconfig.json │ └── vite.config.ts ├── benchmarks ├── .env.example ├── evaluate_qa.js ├── evaluation_results.json ├── ingest_conversations.js ├── ingest_sessions.js ├── ingestion_status.json ├── locomo10.json ├── package-lock.json └── package.json ├── docker-compose.aws.yaml ├── docker ├── Dockerfile └── scripts │ ├── entrypoint.sh │ └── wait-for-it.sh ├── hosting └── docker │ ├── .env │ ├── .gitignore │ ├── core │ └── docker-compose.yaml │ └── docker-compose.yaml ├── integrations ├── github │ ├── .gitignore │ ├── .prettierrc │ ├── eslint.config.js │ ├── package.json │ ├── pnpm-lock.yaml │ ├── rollup.config.mjs │ ├── spec.json │ ├── src │ │ ├── account-create.ts │ │ ├── index.ts │ │ ├── schedule.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── linear │ ├── .gitignore │ ├── .prettierrc │ ├── eslint.config.js │ ├── package.json │ ├── pnpm-lock.yaml │ ├── spec.json │ ├── src │ │ ├── account-create.ts │ │ ├── index.ts │ │ └── schedule.ts │ ├── tsconfig.json │ └── tsup.config.ts └── slack │ ├── .gitignore │ ├── .prettierrc │ ├── eslint.config.js │ ├── package.json │ ├── pnpm-lock.yaml │ ├── spec.json │ ├── src │ ├── account-create.ts │ ├── create-activity.ts │ ├── index.ts │ └── utils.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── package.json ├── packages ├── database │ ├── .env │ ├── .gitignore │ ├── package.json │ ├── prisma │ │ ├── migrations │ │ │ ├── 20250527101713_init │ │ │ │ └── migration.sql │ │ │ ├── 20250527174127_add_space_queue │ │ │ │ └── migration.sql │ │ │ ├── 20250603140024_add_workspace │ │ │ │ └── migration.sql │ │ │ ├── 20250604101446_space_optional_in_queue │ │ │ │ └── migration.sql │ │ │ ├── 20250605181456_add_integrations │ │ │ │ └── migration.sql │ │ │ ├── 20250611151414_add_workspace_output_to_ingestion │ │ │ │ └── migration.sql │ │ │ ├── 20250611173339_add_magic_link │ │ │ │ └── migration.sql │ │ │ ├── 20250706093221_add_activity │ │ │ │ └── migration.sql │ │ │ ├── 20250707105400_add_preferences │ │ │ │ └── migration.sql │ │ │ ├── 20250708000247_add_conversation │ │ │ │ └── migration.sql │ │ │ ├── 20250712032515_add_ingestion_rule_model │ │ │ │ └── migration.sql │ │ │ ├── 20250715055759_add_activity_to_ingestion │ │ │ │ └── migration.sql │ │ │ ├── 20250716103033_add_oauth_models │ │ │ │ └── migration.sql │ │ │ ├── 20250722045404_add_integration_grant_model │ │ │ │ └── migration.sql │ │ │ ├── 20250722185955_add_oauth_installation_model │ │ │ │ └── migration.sql │ │ │ ├── 20250723034312_add_userusage │ │ │ │ └── migration.sql │ │ │ ├── 20250723162344_modify_client_for_dymanic_creation │ │ │ │ └── migration.sql │ │ │ ├── 20250724124717_add_onboarding │ │ │ │ └── migration.sql │ │ │ ├── 20250804053927_add_recall_log_model │ │ │ │ └── migration.sql │ │ │ ├── 20250814134924_modify_relation_in_space │ │ │ │ └── migration.sql │ │ │ ├── 20250816034949_add_summary_to_space │ │ │ │ └── migration.sql │ │ │ ├── 20250818041710_add_space_pattern │ │ │ │ └── migration.sql │ │ │ ├── 20250818052148_add_name_to_space_pattern │ │ │ │ └── migration.sql │ │ │ ├── 20250818062920_modify_type_space_pattern │ │ │ │ └── migration.sql │ │ │ ├── 20250818071238_add_pattern_tracker_in_space │ │ │ │ └── migration.sql │ │ │ ├── 20250820104832_add_icon_to_space │ │ │ │ └── migration.sql │ │ │ ├── 20250821054728_add_status_to_space │ │ │ │ └── migration.sql │ │ │ └── migration_lock.toml │ │ └── schema.prisma │ ├── src │ │ ├── index.ts │ │ └── transaction.ts │ └── tsconfig.json ├── emails │ ├── .gitignore │ ├── README.md │ ├── emails │ │ ├── components │ │ │ ├── BasePath.tsx │ │ │ ├── Footer.tsx │ │ │ ├── Image.tsx │ │ │ └── styles.ts │ │ ├── invite.tsx │ │ ├── magic-link.tsx │ │ └── welcome.tsx │ ├── package.json │ ├── src │ │ ├── index.tsx │ │ └── transports │ │ │ ├── aws-ses.ts │ │ │ ├── index.ts │ │ │ ├── null.ts │ │ │ ├── resend.ts │ │ │ └── smtp.ts │ └── tsconfig.json ├── mcp-proxy │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── src │ │ ├── core │ │ │ └── mcp-remote-client.ts │ │ ├── index.ts │ │ ├── lib │ │ │ ├── coordination.ts │ │ │ ├── in-memory-auth-storage.ts │ │ │ ├── node-oauth-client-provider.ts │ │ │ └── utils.ts │ │ ├── types │ │ │ ├── index.ts │ │ │ └── remote-client.ts │ │ └── utils │ │ │ ├── auth-provider-factory.ts │ │ │ ├── errors.ts │ │ │ ├── index.ts │ │ │ ├── mcp-transport-bridge.ts │ │ │ └── mcp-transport.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── sdk │ ├── .eslintrc.js │ ├── .prettierrc.json │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── integrations │ │ │ ├── index.ts │ │ │ └── integration-cli.ts │ ├── tsconfig.json │ └── tsup.config.ts └── types │ ├── .gitignore │ ├── package.json │ ├── src │ ├── conversation-execution-step │ │ ├── conversation-execution.entity.ts │ │ └── index.ts │ ├── graph │ │ ├── graph.entity.ts │ │ └── index.ts │ ├── index.ts │ ├── integration.ts │ ├── llm │ │ ├── index.ts │ │ └── llm.entity.ts │ ├── oauth │ │ ├── index.ts │ │ └── params.ts │ ├── pattern.ts │ ├── space.ts │ └── user │ │ └── index.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── prettier.config.js └── turbo.json /.configs/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2022", 4 | "lib": ["ES2022", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], 5 | "module": "NodeNext", 6 | "moduleResolution": "NodeNext", 7 | "moduleDetection": "force", 8 | "verbatimModuleSyntax": false, 9 | "jsx": "react", 10 | 11 | "strict": true, 12 | "alwaysStrict": true, 13 | "strictPropertyInitialization": false, 14 | "skipLibCheck": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "noUnusedLocals": false, 17 | "noUnusedParameters": false, 18 | "noImplicitAny": true, 19 | "noImplicitReturns": true, 20 | "noImplicitThis": true, 21 | 22 | "noFallthroughCasesInSwitch": true, 23 | "resolveJsonModule": true, 24 | 25 | "removeComments": false, 26 | "esModuleInterop": true, 27 | "emitDecoratorMetadata": false, 28 | "experimentalDecorators": false, 29 | "downlevelIteration": true, 30 | "isolatedModules": true, 31 | "noUncheckedIndexedAccess": true, 32 | 33 | "pretty": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | VERSION=0.1.16 2 | 3 | # Nest run in docker, change host to database container name 4 | DB_HOST=localhost 5 | DB_PORT=5432 6 | 7 | # POSTGRES 8 | POSTGRES_USER=docker 9 | POSTGRES_PASSWORD=docker 10 | POSTGRES_DB=core 11 | 12 | LOGIN_ORIGIN=http://localhost:3033 13 | DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?schema=core 14 | 15 | # This sets the URL used for direct connections to the database and should only be needed in limited circumstances 16 | # See: https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#fields:~:text=the%20shadow%20database.-,directUrl,-No 17 | DIRECT_URL=${DATABASE_URL} 18 | 19 | REMIX_APP_PORT=3033 20 | APP_ENV=production 21 | NODE_ENV=${APP_ENV} 22 | APP_ORIGIN=http://localhost:3033 23 | API_BASE_URL=${APP_ORIGIN} 24 | 25 | 26 | SESSION_SECRET=27192e6432564f4788d55c15131bd5ac 27 | ENCRYPTION_KEY=27192e6432564f4788d55c15131bd5ac 28 | 29 | ########### Sign.in with google ############ 30 | AUTH_GOOGLE_CLIENT_ID= 31 | AUTH_GOOGLE_CLIENT_SECRET= 32 | 33 | REDIS_HOST=redis 34 | REDIS_PORT=6379 35 | REDIS_TLS_DISABLED=true 36 | 37 | ENABLE_EMAIL_LOGIN=true 38 | 39 | NEO4J_URI=bolt://neo4j:7687 40 | NEO4J_USERNAME=neo4j 41 | NEO4J_PASSWORD=27192e6432564f4788d55c15131bd5ac 42 | OPENAI_API_KEY= 43 | 44 | 45 | MAGIC_LINK_SECRET=27192e6432564f4788d55c15131bd5ac 46 | 47 | 48 | NEO4J_AUTH=neo4j/27192e6432564f4788d55c15131bd5ac 49 | OLLAMA_URL=http://ollama:11434 50 | 51 | EMBEDDING_MODEL=text-embedding-3-small 52 | MODEL=gpt-4.1-2025-04-14 53 | 54 | ## Trigger ## 55 | TRIGGER_PROJECT_ID= 56 | TRIGGER_SECRET_KEY= 57 | TRIGGER_API_URL=http://host.docker.internal:8030 58 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | */**.js 2 | */**.d.ts 3 | packages/*/dist 4 | packages/*/lib 5 | 6 | build/ -------------------------------------------------------------------------------- /.github/workflows/submit.yml: -------------------------------------------------------------------------------- 1 | name: "Submit to Web Store" 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | defaults: 9 | run: 10 | working-directory: apps/extension 11 | steps: 12 | - uses: actions/checkout@v3 13 | - name: Cache pnpm modules 14 | uses: actions/cache@v3 15 | with: 16 | path: ~/.pnpm-store 17 | key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} 18 | restore-keys: | 19 | ${{ runner.os }}- 20 | - uses: pnpm/action-setup@v2.2.4 21 | with: 22 | version: latest 23 | run_install: true 24 | - name: Use Node.js 16.x 25 | uses: actions/setup-node@v3.4.1 26 | with: 27 | node-version: 16.x 28 | cache: "pnpm" 29 | - name: Build the extension 30 | run: pnpm build 31 | - name: Package the extension into a zip artifact 32 | run: pnpm package 33 | - name: Browser Platform Publish 34 | uses: PlasmoHQ/bpp@v3 35 | with: 36 | keys: ${{ secrets.SUBMIT_KEYS }} 37 | artifact: build/chrome-mv3-prod.zip 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | .tshy/ 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | 40 | docker-compose.dev.yaml 41 | 42 | clickhouse/ 43 | .vscode/ 44 | registry/ 45 | 46 | .cursor 47 | CLAUDE.md 48 | 49 | .claude 50 | 51 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPlanetHQ/core/60948933307334e8f5ead581776789242abb83f0/.npmrc -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .env.local 4 | pnpm-lock.yaml 5 | tailwind.css 6 | .babelrc.json 7 | **/.react-email/ 8 | **/storybook-static/ 9 | **/.changeset/ 10 | **/dist/ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [ 3 | { 4 | "mode": "auto" 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /apps/init/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | .tshy/ 30 | .tshy-build/ 31 | 32 | # Debug 33 | npm-debug.log* 34 | yarn-debug.log* 35 | yarn-error.log* 36 | 37 | # Misc 38 | .DS_Store 39 | *.pem 40 | 41 | docker-compose.dev.yaml 42 | 43 | clickhouse/ 44 | .vscode/ 45 | registry/ 46 | 47 | .cursor 48 | CLAUDE.md 49 | 50 | .claude 51 | 52 | -------------------------------------------------------------------------------- /apps/init/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Exit on any error 4 | set -e 5 | 6 | echo "Starting init CLI..." 7 | 8 | # Wait for database to be ready 9 | echo "Waiting for database connection..." 10 | until pg_isready -h "${DB_HOST:-localhost}" -p "${DB_PORT:-5432}" -U "${POSTGRES_USER:-docker}"; do 11 | echo "Database is unavailable - sleeping" 12 | sleep 2 13 | done 14 | 15 | echo "Database is ready!" 16 | 17 | # Run the init command 18 | echo "Running init command..." 19 | node ./dist/esm/index.js init 20 | 21 | echo "Init completed successfully!" 22 | exit 0 -------------------------------------------------------------------------------- /apps/init/src/cli/index.ts: -------------------------------------------------------------------------------- 1 | import { Command } from "commander"; 2 | import { initCommand } from "../commands/init.js"; 3 | import { VERSION } from "./version.js"; 4 | 5 | const program = new Command(); 6 | 7 | program.name("core").description("Core CLI - A Command-Line Interface for Core").version(VERSION); 8 | 9 | program 10 | .command("init") 11 | .description("Initialize Core development environment (run once)") 12 | .action(initCommand); 13 | 14 | program.parse(process.argv); 15 | -------------------------------------------------------------------------------- /apps/init/src/cli/version.ts: -------------------------------------------------------------------------------- 1 | import { env } from "../utils/env.js"; 2 | 3 | export const VERSION = env.VERSION; 4 | -------------------------------------------------------------------------------- /apps/init/src/commands/init.ts: -------------------------------------------------------------------------------- 1 | import { intro, outro, note } from "@clack/prompts"; 2 | import { printCoreBrainLogo } from "../utils/ascii.js"; 3 | import { initTriggerDatabase, updateWorkerImage } from "../utils/trigger.js"; 4 | 5 | export async function initCommand() { 6 | // Display the CORE brain logo 7 | printCoreBrainLogo(); 8 | 9 | intro("🚀 Core Development Environment Setup"); 10 | 11 | try { 12 | await initTriggerDatabase(); 13 | await updateWorkerImage(); 14 | 15 | note( 16 | [ 17 | "Your services will start running:", 18 | "", 19 | "• Core Application: http://localhost:3033", 20 | "• Trigger.dev: http://localhost:8030", 21 | "• PostgreSQL: localhost:5432", 22 | "", 23 | "You can now start developing with Core!", 24 | "", 25 | "ℹ️ When logging in to the Core Application, you can find the login URL in the Docker container logs:", 26 | " docker logs core-app --tail 50", 27 | ].join("\n"), 28 | "🚀 Services Running" 29 | ); 30 | outro("🎉 Setup Complete!"); 31 | process.exit(0); 32 | } catch (error: any) { 33 | outro(`❌ Setup failed: ${error.message}`); 34 | process.exit(1); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /apps/init/src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import "./cli/index.js"; 4 | -------------------------------------------------------------------------------- /apps/init/src/utils/ascii.ts: -------------------------------------------------------------------------------- 1 | import chalk from "chalk"; 2 | import { VERSION } from "../cli/version.js"; 3 | 4 | export function printCoreBrainLogo(): void { 5 | const brain = ` 6 | ██████╗ ██████╗ ██████╗ ███████╗ 7 | ██╔════╝██╔═══██╗██╔══██╗██╔════╝ 8 | ██║ ██║ ██║██████╔╝█████╗ 9 | ██║ ██║ ██║██╔══██╗██╔══╝ 10 | ╚██████╗╚██████╔╝██║ ██║███████╗ 11 | ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ 12 | 13 | o o o 14 | o o---o---o o 15 | o---o o o---o---o 16 | o o---o---o---o o 17 | o---o o o---o---o 18 | o o---o---o o 19 | o o o 20 | 21 | `; 22 | 23 | console.log(chalk.cyan(brain)); 24 | console.log( 25 | chalk.bold.white( 26 | ` 🧠 CORE - Contextual Observation & Recall Engine ${VERSION ? chalk.gray(`(${VERSION})`) : ""}\n` 27 | ) 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /apps/init/src/utils/env.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | 3 | const EnvironmentSchema = z.object({ 4 | // Version 5 | VERSION: z.string().default("0.1.14"), 6 | 7 | // Database 8 | DB_HOST: z.string().default("localhost"), 9 | DB_PORT: z.string().default("5432"), 10 | TRIGGER_DB: z.string().default("trigger"), 11 | POSTGRES_USER: z.string().default("docker"), 12 | POSTGRES_PASSWORD: z.string().default("docker"), 13 | 14 | // Trigger database 15 | TRIGGER_TASKS_IMAGE: z.string().default("redplanethq/proj_core:latest"), 16 | 17 | // Node environment 18 | NODE_ENV: z 19 | .union([z.literal("development"), z.literal("production"), z.literal("test")]) 20 | .default("development"), 21 | }); 22 | 23 | export type Environment = z.infer; 24 | export const env = EnvironmentSchema.parse(process.env); 25 | -------------------------------------------------------------------------------- /apps/init/trigger.dump: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPlanetHQ/core/60948933307334e8f5ead581776789242abb83f0/apps/init/trigger.dump -------------------------------------------------------------------------------- /apps/init/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*.ts"], 3 | "exclude": ["./src/**/*.test.ts"], 4 | "compilerOptions": { 5 | "target": "es2022", 6 | "lib": ["ES2022", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], 7 | "module": "NodeNext", 8 | "moduleResolution": "NodeNext", 9 | "moduleDetection": "force", 10 | "verbatimModuleSyntax": false, 11 | "jsx": "react", 12 | 13 | "strict": true, 14 | "alwaysStrict": true, 15 | "strictPropertyInitialization": true, 16 | "skipLibCheck": true, 17 | "forceConsistentCasingInFileNames": true, 18 | "noUnusedLocals": false, 19 | "noUnusedParameters": false, 20 | "noImplicitAny": true, 21 | "noImplicitReturns": true, 22 | "noImplicitThis": true, 23 | 24 | "noFallthroughCasesInSwitch": true, 25 | "resolveJsonModule": true, 26 | 27 | "removeComments": false, 28 | "esModuleInterop": true, 29 | "emitDecoratorMetadata": false, 30 | "experimentalDecorators": false, 31 | "downlevelIteration": true, 32 | "isolatedModules": true, 33 | "noUncheckedIndexedAccess": true, 34 | 35 | "pretty": true, 36 | "isolatedDeclarations": false, 37 | "composite": true, 38 | "sourceMap": true 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /apps/init/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { configDefaults, defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig({ 4 | test: { 5 | globals: true, 6 | exclude: [...configDefaults.exclude, "e2e/**/*"], 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /apps/webapp/.eslintignore: -------------------------------------------------------------------------------- 1 | public/ -------------------------------------------------------------------------------- /apps/webapp/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["react-hooks", "@typescript-eslint/eslint-plugin", "import"], 3 | "parser": "@typescript-eslint/parser", 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx"], 7 | "rules": { 8 | "@typescript-eslint/consistent-type-imports": [ 9 | "warn", 10 | { 11 | // the "type" annotation can get tangled and cause syntax errors 12 | // during some autofixes, so easier to just turn it off 13 | "prefer": "type-imports", 14 | "disallowTypeAnnotations": true, 15 | "fixStyle": "inline-type-imports", 16 | }, 17 | ], 18 | 19 | "import/no-duplicates": ["warn", { "prefer-inline": true }], 20 | // lots of undeclared vars, enable this rule if you want to clean them up 21 | "turbo/no-undeclared-env-vars": "off", 22 | }, 23 | }, 24 | ], 25 | "ignorePatterns": ["public/"], 26 | } 27 | -------------------------------------------------------------------------------- /apps/webapp/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | .env 6 | 7 | .trigger -------------------------------------------------------------------------------- /apps/webapp/.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /build 4 | /public/build 5 | .env 6 | 7 | /cypress/screenshots 8 | /cypress/videos 9 | /postgres-data 10 | 11 | /app/styles/tailwind.css -------------------------------------------------------------------------------- /apps/webapp/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tailwindConfig": "./tailwind.config.ts", 3 | "plugins": [ "prettier-plugin-tailwindcss" ] 4 | } -------------------------------------------------------------------------------- /apps/webapp/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedPlanetHQ/core/60948933307334e8f5ead581776789242abb83f0/apps/webapp/README.md -------------------------------------------------------------------------------- /apps/webapp/app/components/api/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./api-table"; 2 | -------------------------------------------------------------------------------- /apps/webapp/app/components/conversation/conversation-item.client.tsx: -------------------------------------------------------------------------------- 1 | import { EditorContent, useEditor } from "@tiptap/react"; 2 | 3 | import { useEffect } from "react"; 4 | import { UserTypeEnum } from "@core/types"; 5 | import { type ConversationHistory } from "@core/database"; 6 | import { cn } from "~/lib/utils"; 7 | import { extensionsForConversation } from "./editor-extensions"; 8 | import { skillExtension } from "../editor/skill-extension"; 9 | 10 | interface AIConversationItemProps { 11 | conversationHistory: ConversationHistory; 12 | } 13 | 14 | export const ConversationItem = ({ 15 | conversationHistory, 16 | }: AIConversationItemProps) => { 17 | const isUser = 18 | conversationHistory.userType === UserTypeEnum.User || 19 | conversationHistory.userType === UserTypeEnum.System; 20 | 21 | const id = `a${conversationHistory.id.replace(/-/g, "")}`; 22 | 23 | const editor = useEditor({ 24 | extensions: [...extensionsForConversation, skillExtension], 25 | editable: false, 26 | content: conversationHistory.message, 27 | }); 28 | 29 | useEffect(() => { 30 | editor?.commands.setContent(conversationHistory.message); 31 | 32 | // eslint-disable-next-line react-hooks/exhaustive-deps 33 | }, [id, conversationHistory.message]); 34 | 35 | if (!conversationHistory.message) { 36 | return null; 37 | } 38 | 39 | return ( 40 |
41 |
47 | 48 |
49 |
50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /apps/webapp/app/components/conversation/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./conversation.client"; 2 | export * from "./conversation-item.client"; 3 | export * from "./streaming-conversation.client"; 4 | export * from "./conversation-textarea.client"; 5 | export * from "./conversation-list"; 6 | -------------------------------------------------------------------------------- /apps/webapp/app/components/editor/conversation-context.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | interface ConversationContextInterface { 4 | conversationHistoryId: string; 5 | 6 | // Used just in streaming 7 | streaming?: boolean; 8 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 9 | actionMessages?: Record; 10 | } 11 | 12 | export const ConversationContext = React.createContext< 13 | ConversationContextInterface | undefined 14 | >(undefined); 15 | -------------------------------------------------------------------------------- /apps/webapp/app/components/editor/skill-extension/index.ts: -------------------------------------------------------------------------------- 1 | export * from './skill-extension'; 2 | -------------------------------------------------------------------------------- /apps/webapp/app/components/editor/skill-extension/skill-extension.ts: -------------------------------------------------------------------------------- 1 | import { ReactNodeViewRenderer, Node, mergeAttributes } from "@tiptap/react"; 2 | 3 | import { SkillComponent } from "./skill-component"; 4 | 5 | export const skillExtension = Node.create({ 6 | name: "skill", 7 | group: "block", 8 | atom: true, 9 | selectable: false, 10 | 11 | addAttributes() { 12 | return { 13 | id: { 14 | default: undefined, 15 | }, 16 | name: { 17 | default: undefined, 18 | }, 19 | agent: { 20 | default: undefined, 21 | }, 22 | }; 23 | }, 24 | 25 | parseHTML() { 26 | return [ 27 | { 28 | tag: "skill", 29 | getAttrs: (element) => { 30 | return { 31 | id: element.getAttribute("id"), 32 | name: element.getAttribute("name"), 33 | agent: element.getAttribute("agent"), 34 | }; 35 | }, 36 | }, 37 | ]; 38 | }, 39 | 40 | renderHTML({ HTMLAttributes }) { 41 | return ["skill", mergeAttributes(HTMLAttributes)]; 42 | }, 43 | 44 | addNodeView() { 45 | return ReactNodeViewRenderer(SkillComponent); 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /apps/webapp/app/components/graph/graph-client.tsx: -------------------------------------------------------------------------------- 1 | import { type GraphClusteringVisualizationProps } from "./graph-clustering-visualization"; 2 | import { useState, useEffect } from "react"; 3 | 4 | export function GraphVisualizationClient( 5 | props: GraphClusteringVisualizationProps, 6 | ) { 7 | const [Component, setComponent] = useState(undefined); 8 | 9 | useEffect(() => { 10 | if (typeof window === "undefined") return; 11 | 12 | import("./graph-clustering-visualization").then( 13 | ({ GraphClusteringVisualization }) => { 14 | setComponent(GraphClusteringVisualization); 15 | }, 16 | ); 17 | }, []); 18 | 19 | if (!Component) { 20 | return null; 21 | } 22 | 23 | return ; 24 | } 25 | -------------------------------------------------------------------------------- /apps/webapp/app/components/graph/type.ts: -------------------------------------------------------------------------------- 1 | export interface Node { 2 | uuid: string; 3 | name: string; 4 | summary?: string; 5 | labels?: string[]; 6 | attributes?: Record; 7 | createdAt: string; 8 | clusterId?: string; 9 | } 10 | 11 | export interface Edge { 12 | uuid: string; 13 | source_node_uuid: string; 14 | target_node_uuid: string; 15 | type: string; 16 | createdAt: string; 17 | } 18 | 19 | export interface RawTriplet { 20 | sourceNode: Node; 21 | edge: Edge; 22 | targetNode: Node; 23 | } 24 | 25 | export interface GraphNode extends Node { 26 | id: string; 27 | value: string; 28 | primaryLabel?: string; 29 | clusterId?: string; // Add cluster information 30 | } 31 | 32 | export interface GraphEdge extends Edge { 33 | id: string; 34 | value: string; 35 | } 36 | 37 | export interface GraphTriplet { 38 | source: GraphNode; 39 | relation: GraphEdge; 40 | target: GraphNode; 41 | } 42 | 43 | export interface IdValue { 44 | id: string; 45 | value: string; 46 | } 47 | 48 | // Graph visualization types 49 | export interface GraphNode extends Node { 50 | id: string; 51 | value: string; 52 | } 53 | 54 | export interface GraphEdge extends Edge { 55 | id: string; 56 | value: string; 57 | } 58 | 59 | export interface GraphTriplet { 60 | source: GraphNode; 61 | relation: GraphEdge; 62 | target: GraphNode; 63 | } 64 | 65 | // Popup content types for UI 66 | export interface NodePopupContent { 67 | id: string; 68 | node: Node; 69 | } 70 | 71 | export interface EdgePopupContent { 72 | id: string; 73 | source: Node; 74 | relation: Edge; 75 | target: Node; 76 | } 77 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icon-picker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './icon-picker'; 2 | export * from './utils'; 3 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icon-picker/utils.tsx: -------------------------------------------------------------------------------- 1 | import * as LucideIcons from "lucide-react"; 2 | 3 | import { emojiData } from "./emoji-data"; 4 | import { cn } from "~/lib/utils"; 5 | import { Project } from "../icons/project"; 6 | 7 | export function getEmojiFromId(id: number) { 8 | return emojiData.find((em) => em.id === id); 9 | } 10 | 11 | export const getIcon = ( 12 | icon?: string | null, 13 | size?: number, 14 | className?: string, 15 | ) => { 16 | if (icon) { 17 | const iconData = JSON.parse(icon); 18 | 19 | if (iconData.icon) { 20 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 21 | const IconComponent = (LucideIcons as any)[iconData.icon]; 22 | 23 | return ( 24 | 29 | ); 30 | } 31 | 32 | if (iconData.emoji) { 33 | return ( 34 |
38 | {iconData.emoji} 39 |
40 | ); 41 | } 42 | } 43 | 44 | return ; 45 | }; 46 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icon-utils.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | RiDiscordFill, 3 | RiGithubFill, 4 | RiMailFill, 5 | RiSlackFill, 6 | } from "@remixicon/react"; 7 | import { LayoutGrid } from "lucide-react"; 8 | import { LinearIcon, SlackIcon } from "./icons"; 9 | import { Cursor } from "./icons/cursor"; 10 | import { Claude } from "./icons/claude"; 11 | import { Cline } from "./icons/cline"; 12 | import { VSCode } from "./icons/vscode"; 13 | 14 | export const ICON_MAPPING = { 15 | slack: SlackIcon, 16 | email: RiMailFill, 17 | discord: RiDiscordFill, 18 | github: RiGithubFill, 19 | 20 | gmail: RiMailFill, 21 | linear: LinearIcon, 22 | cursor: Cursor, 23 | claude: Claude, 24 | cline: Cline, 25 | vscode: VSCode, 26 | 27 | // Default icon 28 | integration: LayoutGrid, 29 | }; 30 | 31 | export type IconType = keyof typeof ICON_MAPPING; 32 | 33 | export function getIcon(icon: IconType) { 34 | if (icon in ICON_MAPPING) { 35 | return ICON_MAPPING[icon]; 36 | } 37 | 38 | return ICON_MAPPING["integration"]; 39 | } 40 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/arrows.tsx: -------------------------------------------------------------------------------- 1 | import type { IconProps } from "./types"; 2 | 3 | export function Arrows({ size = 18, className }: IconProps) { 4 | return ( 5 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/cline.tsx: -------------------------------------------------------------------------------- 1 | import type { IconProps } from "./types"; 2 | 3 | export function Cline({ size = 18, className }: IconProps) { 4 | return ( 5 | 14 | Cline 15 | 16 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./slack-icon"; 2 | export * from "./linear-icon"; 3 | export * from "./arrows"; 4 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/slack-icon.tsx: -------------------------------------------------------------------------------- 1 | import type { IconProps } from "./types"; 2 | 3 | export function SlackIcon({ size = 18, className }: IconProps) { 4 | return ( 5 | 12 | 16 | 20 | 24 | 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/types.tsx: -------------------------------------------------------------------------------- 1 | export interface IconProps { 2 | size?: number; 3 | className?: string; 4 | color?: string; 5 | onClick?: (event: MouseEvent) => void; 6 | } 7 | -------------------------------------------------------------------------------- /apps/webapp/app/components/icons/vscode.tsx: -------------------------------------------------------------------------------- 1 | import type { IconProps } from "./types"; 2 | 3 | export function VSCode({ size = 18, className }: IconProps) { 4 | return ( 5 | 12 | 16 | 20 | 24 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ingestion/floating-ingestion-status.tsx: -------------------------------------------------------------------------------- 1 | import { LoaderCircle } from "lucide-react"; 2 | import { Card, CardContent } from "~/components/ui/card"; 3 | import { useIngestionStatus } from "~/hooks/use-ingestion-status"; 4 | 5 | export function FloatingIngestionStatus() { 6 | const { data } = useIngestionStatus(); 7 | 8 | if (!data || data.count === 0) { 9 | return null; 10 | } 11 | 12 | const processingCount = data.queue.filter( 13 | (item) => item.status === "PROCESSING", 14 | ).length; 15 | const pendingCount = data.queue.filter( 16 | (item) => item.status === "PENDING", 17 | ).length; 18 | 19 | return ( 20 |
21 | 22 | 23 | 24 | {processingCount + pendingCount} ingesting 25 | 26 | 27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /apps/webapp/app/components/integrations/integration-grid.tsx: -------------------------------------------------------------------------------- 1 | import { LayoutGrid } from "lucide-react"; 2 | import { IntegrationCard } from "./integration-card"; 3 | 4 | interface IntegrationGridProps { 5 | integrations: Array<{ 6 | id: string; 7 | name: string; 8 | description?: string; 9 | icon: string; 10 | slug?: string; 11 | spec: any; 12 | }>; 13 | activeAccountIds: Set; 14 | showDetail?: boolean; 15 | } 16 | 17 | export function IntegrationGrid({ 18 | integrations, 19 | activeAccountIds, 20 | }: IntegrationGridProps) { 21 | const hasActiveAccount = (integrationDefinitionId: string) => 22 | activeAccountIds.has(integrationDefinitionId); 23 | 24 | if (integrations.length === 0) { 25 | return ( 26 |
27 | 28 |

No integrations found

29 |
30 | ); 31 | } 32 | 33 | return ( 34 |
35 | {integrations.map((integration) => { 36 | const isConnected = hasActiveAccount(integration.id); 37 | 38 | return ( 39 | 43 | ); 44 | })} 45 |
46 | ); 47 | } 48 | -------------------------------------------------------------------------------- /apps/webapp/app/components/integrations/section.tsx: -------------------------------------------------------------------------------- 1 | interface SectionProps { 2 | icon?: React.ReactNode; 3 | title: string; 4 | description: string; 5 | metadata?: React.ReactNode; 6 | children: React.ReactNode; 7 | } 8 | 9 | export function Section({ 10 | icon, 11 | title, 12 | description, 13 | metadata, 14 | children, 15 | }: SectionProps) { 16 | return ( 17 |
18 |
19 | {icon && <>{icon}} 20 |

{title}

21 |

{description}

22 | {metadata ? metadata : null} 23 |
24 |
25 |
26 |
27 | {children} 28 |
29 |
30 |
31 |
32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /apps/webapp/app/components/integrations/utils.tsx: -------------------------------------------------------------------------------- 1 | export const FIXED_INTEGRATIONS = [ 2 | { 3 | id: "claude", 4 | name: "Claude", 5 | description: "AI assistant for coding, writing, and analysis", 6 | icon: "claude", 7 | slug: "claude", 8 | spec: {}, 9 | }, 10 | { 11 | id: "cursor", 12 | name: "Cursor", 13 | description: "AI-powered code editor", 14 | icon: "cursor", 15 | slug: "cursor", 16 | spec: {}, 17 | }, 18 | { 19 | id: "cline", 20 | name: "Cline", 21 | description: "AI coding assistant for terminal and command line", 22 | icon: "cline", 23 | slug: "cline", 24 | spec: {}, 25 | }, 26 | { 27 | id: "vscode", 28 | name: "Visual Studio Code", 29 | description: "Popular code editor with extensive extensions", 30 | icon: "vscode", 31 | slug: "vscode", 32 | spec: {}, 33 | }, 34 | ]; 35 | -------------------------------------------------------------------------------- /apps/webapp/app/components/layout/login-page-layout.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "../ui"; 2 | import Logo from "../logo/logo"; 3 | import { Theme, useTheme } from "remix-themes"; 4 | import { GalleryVerticalEnd } from "lucide-react"; 5 | 6 | export function LoginPageLayout({ children }: { children: React.ReactNode }) { 7 | return ( 8 |
9 |
10 | 18 |
19 |
{children}
20 |
21 |
22 |
23 | Image 28 |
29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /apps/webapp/app/components/layout/onboarding-layout.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from "../ui"; 2 | import Logo from "../logo/logo"; 3 | import { Theme, useTheme } from "remix-themes"; 4 | 5 | export function LoginPageLayout({ children }: { children: React.ReactNode }) { 6 | return ( 7 |
15 |
16 |
17 | 18 |
19 | 20 |
C.O.R.E.
21 |
22 | {children} 23 |
24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /apps/webapp/app/components/logo/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./logo"; 2 | -------------------------------------------------------------------------------- /apps/webapp/app/components/logs/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ingestion-logs-table"; 2 | -------------------------------------------------------------------------------- /apps/webapp/app/components/nav-secondary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | import { type LucideIcon } from "lucide-react" 3 | 4 | import { 5 | SidebarGroup, 6 | SidebarGroupContent, 7 | SidebarMenu, 8 | SidebarMenuButton, 9 | SidebarMenuItem, 10 | } from "~/components/ui/sidebar" 11 | 12 | export function NavSecondary({ 13 | items, 14 | ...props 15 | }: { 16 | items: { 17 | title: string 18 | url: string 19 | icon: LucideIcon 20 | }[] 21 | } & React.ComponentPropsWithoutRef) { 22 | return ( 23 | 24 | 25 | 26 | {items.map((item) => ( 27 | 28 | 29 | 30 | 31 | {item.title} 32 | 33 | 34 | 35 | ))} 36 | 37 | 38 | 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /apps/webapp/app/components/setting-section.tsx: -------------------------------------------------------------------------------- 1 | interface SettingSectionProps { 2 | title: React.ReactNode | string; 3 | description: React.ReactNode | string; 4 | metadata?: React.ReactNode; 5 | actions?: React.ReactNode; 6 | children: React.ReactNode; 7 | } 8 | 9 | export function SettingSection({ 10 | title, 11 | description, 12 | metadata, 13 | children, 14 | actions, 15 | }: SettingSectionProps) { 16 | return ( 17 |
18 |
19 |
20 |

{title}

21 |

{description}

22 | {metadata ? metadata : null} 23 |
24 | 25 |
{actions}
26 |
27 |
28 |
29 |
{children}
30 |
31 |
32 |
33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /apps/webapp/app/components/sidebar/nav-main.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "~/lib/utils"; 2 | import { 3 | SidebarGroup, 4 | SidebarGroupContent, 5 | SidebarMenu, 6 | SidebarMenuItem, 7 | } from "../ui/sidebar"; 8 | import { useLocation, useNavigate } from "@remix-run/react"; 9 | import { Button } from "../ui"; 10 | 11 | export const NavMain = ({ 12 | items, 13 | }: { 14 | items: { 15 | title: string; 16 | url: string; 17 | icon?: any; 18 | }[]; 19 | }) => { 20 | const location = useLocation(); 21 | const navigate = useNavigate(); 22 | 23 | return ( 24 | 25 | 26 | 27 | {items.map((item) => ( 28 | 29 | 42 | 43 | ))} 44 | 45 | 46 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /apps/webapp/app/components/spaces/space-properties.tsx: -------------------------------------------------------------------------------- 1 | export const SpaceProperties = () => { 2 | return ( 3 |
4 |

Properties

5 |
6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /apps/webapp/app/components/spaces/space-summary.client.tsx: -------------------------------------------------------------------------------- 1 | import { EditorContent, useEditor } from "@tiptap/react"; 2 | 3 | import { useEffect } from "react"; 4 | 5 | import { skillExtension } from "../editor/skill-extension"; 6 | import { extensionsForConversation } from "../conversation/editor-extensions"; 7 | 8 | export const SpaceSummary = ({ summary }: { summary?: string | null }) => { 9 | const editor = useEditor({ 10 | extensions: [...extensionsForConversation, skillExtension], 11 | editable: false, 12 | content: summary, 13 | }); 14 | 15 | useEffect(() => { 16 | if (summary) { 17 | editor?.commands.setContent(summary); 18 | } 19 | 20 | // eslint-disable-next-line react-hooks/exhaustive-deps 21 | }, [summary]); 22 | 23 | if (!summary) { 24 | return null; 25 | } 26 | 27 | return ; 28 | }; 29 | -------------------------------------------------------------------------------- /apps/webapp/app/components/spaces/spaces-grid.tsx: -------------------------------------------------------------------------------- 1 | import { LayoutGrid } from "lucide-react"; 2 | import { SpaceCard } from "./space-card"; 3 | 4 | interface SpacesGridProps { 5 | spaces: Array<{ 6 | id: string; 7 | name: string; 8 | description: string | null; 9 | createdAt: string; 10 | updatedAt: string; 11 | autoMode: boolean; 12 | statementCount: number | null; 13 | summary: string | null; 14 | themes?: string[]; 15 | }>; 16 | } 17 | 18 | export function SpacesGrid({ spaces }: SpacesGridProps) { 19 | if (spaces.length === 0) { 20 | return ( 21 |
22 | 23 |

No spaces found

24 |
25 | ); 26 | } 27 | 28 | return ( 29 |
30 | {spaces.map((space) => ( 31 | 32 | ))} 33 |
34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/Fieldset.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "~/lib/utils"; 2 | 3 | export function Fieldset({ 4 | children, 5 | className, 6 | }: { 7 | children: React.ReactNode; 8 | className?: string; 9 | }) { 10 | return ( 11 |
{children}
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/FormButtons.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "~/lib/utils"; 2 | 3 | export function FormButtons({ 4 | cancelButton, 5 | confirmButton, 6 | className, 7 | }: { 8 | cancelButton?: React.ReactNode; 9 | confirmButton: React.ReactNode; 10 | className?: string; 11 | }) { 12 | return ( 13 |
16 | {cancelButton ? cancelButton :
} {confirmButton} 17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/Icon.tsx: -------------------------------------------------------------------------------- 1 | import React, { type FunctionComponent, createElement } from "react"; 2 | import { cn } from "~/lib/utils"; 3 | 4 | export type RenderIcon = 5 | | FunctionComponent<{ className?: string }> 6 | | React.ReactNode; 7 | 8 | export type IconProps = { 9 | icon?: RenderIcon; 10 | className?: string; 11 | }; 12 | 13 | /** Use this icon to either render a passed in React component, or a NamedIcon/CompanyIcon */ 14 | export function Icon(props: IconProps) { 15 | if (!props.icon) return null; 16 | 17 | if (typeof props.icon === "function") { 18 | const Icon = props.icon; 19 | return ; 20 | } 21 | 22 | if (React.isValidElement(props.icon)) { 23 | return <>{props.icon}; 24 | } 25 | 26 | if ( 27 | props.icon && 28 | typeof props.icon === "object" && 29 | ("type" in props.icon || "$$typeof" in props.icon) 30 | ) { 31 | return createElement>( 32 | props.icon as any, 33 | { className: props.className } as any, 34 | ); 35 | } 36 | 37 | return null; 38 | } 39 | 40 | export function IconInBox({ 41 | boxClassName, 42 | ...props 43 | }: IconProps & { boxClassName?: string }) { 44 | return ( 45 |
51 | 52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/TextLink.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "@remix-run/react"; 2 | 3 | import { Icon, type RenderIcon } from "./Icon"; 4 | import { cn } from "~/lib/utils"; 5 | 6 | const variations = { 7 | primary: 8 | "text-indigo-500 transition hover:text-indigo-400 inline-flex gap-0.5 items-center group focus-visible:focus-custom", 9 | secondary: 10 | "text-text-dimmed transition hover:text-text-bright inline-flex gap-0.5 items-center group focus-visible:focus-custom", 11 | } as const; 12 | 13 | type TextLinkProps = { 14 | href?: string; 15 | to?: string; 16 | className?: string; 17 | trailingIcon?: RenderIcon; 18 | trailingIconClassName?: string; 19 | variant?: keyof typeof variations; 20 | children: React.ReactNode; 21 | } & React.AnchorHTMLAttributes; 22 | 23 | export function TextLink({ 24 | href, 25 | to, 26 | children, 27 | className, 28 | trailingIcon, 29 | trailingIconClassName, 30 | variant = "primary", 31 | ...props 32 | }: TextLinkProps) { 33 | const classes = variations[variant]; 34 | return to ? ( 35 | 36 | {children}{" "} 37 | {trailingIcon && ( 38 | 42 | )} 43 | 44 | ) : href ? ( 45 | 46 | {children}{" "} 47 | {trailingIcon && ( 48 | 52 | )} 53 | 54 | ) : ( 55 | Need to define a path or href 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/badge.tsx: -------------------------------------------------------------------------------- 1 | import { cva, type VariantProps } from "class-variance-authority"; 2 | import React from "react"; 3 | import { cn } from "~/lib/utils"; 4 | 5 | const badgeVariants = cva( 6 | "flex items-center h-5 gap-2 rounded-sm border px-1.5 py-0.5 text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", 7 | { 8 | variants: { 9 | variant: { 10 | default: 11 | "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", 12 | secondary: "border-none bg-grayAlpha-100", 13 | destructive: 14 | "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", 15 | outline: "text-foreground bg-background", 16 | }, 17 | }, 18 | defaultVariants: { 19 | variant: "default", 20 | }, 21 | }, 22 | ); 23 | 24 | export interface BadgeProps 25 | extends React.HTMLAttributes, 26 | VariantProps {} 27 | 28 | function Badge({ className, variant, ...props }: BadgeProps) { 29 | return ( 30 |
31 | ); 32 | } 33 | 34 | interface BadgeColorProps extends React.HTMLAttributes { 35 | className?: string; 36 | } 37 | 38 | function BadgeColor({ className, ...otherProps }: BadgeColorProps) { 39 | return ( 40 | 44 | ); 45 | } 46 | 47 | export { Badge, badgeVariants, BadgeColor }; 48 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 2 | import { CheckIcon } from "@radix-ui/react-icons"; 3 | import React from "react"; 4 | 5 | import { cn } from "../../lib/utils"; 6 | 7 | const Checkbox = React.forwardRef< 8 | React.ElementRef, 9 | React.ComponentPropsWithoutRef 10 | >(({ className, ...props }, ref) => ( 11 | 19 | 22 | 23 | 24 | 25 | )); 26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName; 27 | 28 | export { Checkbox }; 29 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/collapsible.tsx: -------------------------------------------------------------------------------- 1 | import * as CollapsiblePrimitive from "@radix-ui/react-collapsible" 2 | 3 | function Collapsible({ 4 | ...props 5 | }: React.ComponentProps) { 6 | return 7 | } 8 | 9 | function CollapsibleTrigger({ 10 | ...props 11 | }: React.ComponentProps) { 12 | return ( 13 | 17 | ) 18 | } 19 | 20 | function CollapsibleContent({ 21 | ...props 22 | }: React.ComponentProps) { 23 | return ( 24 | 28 | ) 29 | } 30 | 31 | export { Collapsible, CollapsibleTrigger, CollapsibleContent } 32 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/color-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates an OKLCH color string with fixed lightness, chroma, and a random hue. 3 | * @returns {string} - The generated OKLCH color string. 4 | */ 5 | export function generateOklchColor(): string { 6 | // Generate a random number between 30 and 360 for the hue 7 | const hue = Math.floor(Math.random() * (360 - 30 + 1)) + 30; 8 | 9 | // Fixed lightness and chroma values 10 | const lightness = 66; 11 | const chroma = 0.1835; 12 | 13 | // Construct the OKLCH color string 14 | const oklchColor = `oklch(${lightness}% ${chroma} ${hue})`; 15 | 16 | return oklchColor; 17 | } 18 | 19 | export function getTailwindColor(name: string): string { 20 | // Generate a hash value for the input name 21 | let hash = 0; 22 | for (let i = 0; i < name.length; i++) { 23 | hash = name.charCodeAt(i) + ((hash << 5) - hash); 24 | } 25 | 26 | // Ensure hash value is within the range of colors array 27 | const index = Math.abs(hash) % 12; 28 | 29 | return `var(--custom-color-${index + 1})`; 30 | } 31 | 32 | export function getTeamColor(name: string): string { 33 | // Generate a hash value for the input name 34 | let hash = 0; 35 | for (let i = 0; i < name.length; i++) { 36 | hash = name.charCodeAt(i) + ((hash << 5) - hash); 37 | } 38 | 39 | // Ensure hash value is within the range of colors array 40 | const index = Math.abs(hash) % 3; 41 | 42 | return `var(--team-color-${index + 1})`; 43 | } 44 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./button"; 2 | export * from "./tabs"; 3 | export * from "./input"; 4 | export * from "./scrollarea"; 5 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { cn } from "../../lib/utils"; 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ); 21 | }, 22 | ); 23 | Input.displayName = "Input"; 24 | 25 | export { Input }; 26 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | import * as LabelPrimitive from "@radix-ui/react-label"; 2 | import { cva, type VariantProps } from "class-variance-authority"; 3 | import React from "react"; 4 | 5 | import { cn } from "../../lib/utils"; 6 | 7 | const labelVariants = cva( 8 | "font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", 9 | ); 10 | 11 | const Label = React.forwardRef< 12 | React.ElementRef, 13 | React.ComponentPropsWithoutRef & 14 | VariantProps 15 | >(({ className, ...props }, ref) => ( 16 | 21 | )); 22 | Label.displayName = LabelPrimitive.Root.displayName; 23 | 24 | export { Label }; 25 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/popover.tsx: -------------------------------------------------------------------------------- 1 | import * as PopoverPrimitive from "@radix-ui/react-popover"; 2 | import React from "react"; 3 | 4 | import { cn } from "../../lib/utils"; 5 | 6 | const Popover = PopoverPrimitive.Root; 7 | 8 | const PopoverTrigger = PopoverPrimitive.Trigger; 9 | 10 | const PopoverAnchor = PopoverPrimitive.Anchor; 11 | const PopoverPortal = PopoverPrimitive.Portal; 12 | 13 | const PopoverContent = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef 16 | >(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( 17 | <> 18 | 28 | 29 | )); 30 | PopoverContent.displayName = PopoverPrimitive.Content.displayName; 31 | 32 | export { 33 | Popover, 34 | PopoverTrigger, 35 | PopoverContent, 36 | PopoverAnchor, 37 | PopoverPortal, 38 | }; 39 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/separator.tsx: -------------------------------------------------------------------------------- 1 | import * as SeparatorPrimitive from "@radix-ui/react-separator"; 2 | import React from "react"; 3 | 4 | import { cn } from "../../lib/utils"; 5 | 6 | const Separator = React.forwardRef< 7 | React.ElementRef, 8 | React.ComponentPropsWithoutRef 9 | >( 10 | ( 11 | { className, orientation = "horizontal", decorative = true, ...props }, 12 | ref, 13 | ) => ( 14 | 25 | ), 26 | ); 27 | Separator.displayName = SeparatorPrimitive.Root.displayName; 28 | 29 | export { Separator }; 30 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { cn } from "../../lib/utils"; 4 | 5 | function Skeleton({ 6 | className, 7 | ...props 8 | }: React.HTMLAttributes) { 9 | return ( 10 |
14 | ); 15 | } 16 | 17 | export { Skeleton }; 18 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/slider.tsx: -------------------------------------------------------------------------------- 1 | import * as SliderPrimitive from "@radix-ui/react-slider"; 2 | import * as React from "react"; 3 | import { cn } from "~/lib/utils"; 4 | 5 | const Slider = React.forwardRef< 6 | React.ElementRef, 7 | React.ComponentPropsWithoutRef 8 | >(({ className, ...props }, ref) => ( 9 | 17 | 18 | 19 | 20 | 21 | 22 | )); 23 | Slider.displayName = SliderPrimitive.Root.displayName; 24 | 25 | export { Slider }; 26 | -------------------------------------------------------------------------------- /apps/webapp/app/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import { useAutoSizeTextArea } from "../../hooks/use-autosize-textarea"; 4 | import { cn } from "../../lib/utils"; 5 | 6 | export interface TextareaProps 7 | extends React.TextareaHTMLAttributes {} 8 | 9 | const Textarea = React.forwardRef( 10 | ({ className, value, ...props }, ref) => { 11 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 12 | const textAreaRef = React.useRef(ref); 13 | const id = React.useMemo(() => { 14 | return `id${Math.random().toString(16).slice(2)}`; 15 | }, []); 16 | 17 | useAutoSizeTextArea(id, textAreaRef.current, value); 18 | 19 | return ( 20 |