Skip to content

feat(config): add automatic project type detection#20

Merged
pitzcarraldo merged 5 commits into
mainfrom
feat/detect-project-type
Feb 5, 2026
Merged

feat(config): add automatic project type detection#20
pitzcarraldo merged 5 commits into
mainfrom
feat/detect-project-type

Conversation

@pitzcarraldo

@pitzcarraldo pitzcarraldo commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds automatic project type detection system to Clix CLI. The system detects mobile projects (Expo, React Native, Flutter, native iOS/Android) and their target platforms, enabling smarter setup workflows and project-specific configurations.

Details

This PR introduces three main components:

  1. Project Type Detection (): Analyzes project structure to identify framework (Expo, React Native, Flutter, native) and target platform (iOS, Android, or both).

  2. Project-Local Configuration (, ): Stores project-specific settings in .clix/config.json within each project, enabling persistent configurations without polluting user-level config.

  3. First-Run Service (): Handles initial setup workflows, including project detection and configuration initialization.

The system integrates with existing configuration management and provides an interactive setup UI for users.

Related Issues

Related to #17 (iOS APNS and Firebase setup integration) and #18-19 (UI improvements)

How to Validate

  1. Run bun run dev and test interactive mode
  2. Create test projects (Expo, React Native, Flutter)
  3. Run bun run dev setup to trigger project detection
  4. Verify .clix/config.json is created with correct project type
  5. Test bun run dev doctor command to verify project settings
  6. Run full test suite: bun run check && bun test && bun run build && bun test tests/e2e/

Pre-Merge Checklist

Code Quality

  • Code builds without errors (bun run build)
  • Types check correctly (bun run typecheck)
  • Linter passes (bun run lint)
  • Tests pass (bun test)
  • Added/updated tests for new functionality (if applicable)

Documentation

  • Updated relevant documentation (if needed)
  • Updated CLAUDE.md if architecture changed (if needed)

Commit Standards

  • Commits follow Conventional Commits format
  • No breaking changes, OR breaking changes are documented

Platform Validation

  • macOS
  • Linux

Summary by CodeRabbit

  • New Features

    • Guided first-run setup UI and setup command; saves per-project config to .clix/config.jsonc and ensures .clix is added to .gitignore
    • Automatic project-type detection used across Firebase/setup flows and UI
    • Project and user context shown in login, chat header, whoami, and setup screens
  • Bug Fixes

    • More precise home-directory path formatting
  • Chores

    • Bumped project config version and removed legacy workspace mappings
  • Style

    • Added optional public_key to project payloads

Implement .clix/config.jsonc for per-project settings:
- Add ProjectConfigManager with JSONC support
- Create SetupUI for first-run project setup flow
- Display project info in ChatHeader (name, org, ID, user)
- Store project public_key in local config
- Remove global workspaces from config schema
- Fix formatPath edge case for similar path prefixes
Add project type detection system that identifies framework (native,
react-native, expo, flutter) and target platform (ios, android, both).
Detection runs on login and saves to .clix/config.jsonc.

Refactor Firebase detection to reuse already-detected ProjectType,
eliminating redundant file system checks for platform detection.
@coderabbitai

coderabbitai Bot commented Feb 5, 2026

Copy link
Copy Markdown

Walkthrough

Adds per-project config (.clix/config.jsonc) with schema and manager, first-run/setup flow and UI, project-type detection, makes Firebase services project-type aware, bumps global config version to 5, updates UIs/commands, and appends .clix/ to .gitignore.

Changes

Cohort / File(s) Summary
CLI & Setup
src/cli.tsx, src/commands/setup.tsx
Runs setup pre-check before dispatching commands; adds exported setupCommand and explicit setup command wiring.
Setup UI & Login flow
src/ui/SetupUI.tsx, src/ui/LoginUI.tsx, src/ui/IosSetupUI.tsx, src/ui/WhoamiUI.tsx
New SetupUI and Login flow persist ProjectConfig to .clix/config.jsonc, ensure .gitignore, detect project type, and propagate ProjectConfig across UIs.
Project Config schema & manager
src/lib/config/project-config-schema.ts, src/lib/config/project-config-manager.ts, src/lib/config/index.ts
Adds zod-validated ProjectConfig types/constants, ProjectConfigManager (load/save/delete/ensureGitignore), and re-exports.
Global config migrations
src/lib/config/manager.ts, src/lib/config/schema.ts, src/lib/__tests__/config.test.ts
Bumps global config version 4→5, removes workspaces from schema/defaults, adds migration to strip workspaces, and updates tests.
Project type detection
src/lib/services/project-detector.ts
New detector exposing fileExists/directoryExists/detectProjectType/formatProjectType with framework and target inference.
Firebase services (project-type aware)
src/lib/services/firebase/...
src/lib/services/firebase/detector.ts, .../downloader.ts, .../firebase-service.ts, .../index.ts
Replaces runtime platform heuristics with ProjectType-driven mapping; FirebaseService now accepts projectType; detectPlatform removed from public exports.
First-run service & tests
src/lib/services/first-run-service.ts, tests/e2e/test-rig.ts
Adds first-run helpers (checkFirstRun, shouldRunSetup, exempt list) and sets CLIX_SKIP_SETUP in e2e test rig.
Errors & API types
src/lib/errors/types.ts, src/lib/api/types.ts
Adds ProjectConfigError and error codes (PROJECT_CONFIG_NOT_FOUND, PROJECT_CONFIG_INVALID, PROJECT_CONFIG_SAVE_FAILED); adds optional public_key to Project API type.
UI components & chat header
src/ui/chat/ChatApp.tsx, src/ui/chat/components/ChatHeader.tsx, src/ui/components/FirebaseWizard.tsx, src/ui/components/ProjectSelector.tsx, src/ui/components/PushSetupWizard.tsx
Loads and surfaces ProjectConfig in ChatApp/ChatHeader; Firebase wizards accept/derive ProjectType; ProjectSelector gains showSkip prop; FirebaseService usage updated across components.
Utilities & tests & gitignore
src/lib/utils/path.ts, src/lib/utils/__tests__/path.test.ts, .gitignore
Refines home-path formatting to avoid false replacements; adds test for similar-prefix case; appends .clix/ to .gitignore.

Possibly related PRs

Suggested reviewers

  • JeongwooYoo
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(config): add automatic project type detection' directly and accurately summarizes the main change: adding automatic project type detection to the configuration system.
Description check ✅ Passed The description is comprehensive and well-structured, covering all required template sections: summary of changes, detailed component breakdown, related issues, validation steps, and a complete pre-merge checklist with all items checked.
Docstring Coverage ✅ Passed Docstring coverage is 97.37% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/detect-project-type

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 078135a7a3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli.tsx
Comment thread src/ui/SetupUI.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@src/lib/config/project-config-manager.ts`:
- Around line 122-127: Replace the generic error code with the project-specific
one in the ConfigError throws: locate the ConfigError instantiations inside
project-config-manager.ts (where the code currently uses
ERROR_CODES.CONFIG_INVALID) and change them to use
ERROR_CODES.PROJECT_CONFIG_INVALID so project configuration errors are
categorized correctly; update both occurrences (the one near the first throw and
the second throw later in the file).

In `@src/lib/config/project-config-schema.ts`:
- Around line 60-62: The docstring and constants in project-config-schema.ts
currently point to ".clix/config.jsonc" in the repo root; update the docstring
and the config path constants (e.g., symbols like PROJECT_CONFIG_PATH,
CONFIG_FILENAME, SESSIONS_DIR or any getProjectConfigPath/getConfigPath helpers)
to resolve to the XDG locations instead: use $XDG_CONFIG_HOME/clix/config.json
for the main config filename and $XDG_STATE_HOME/clix/sessions/ for session
storage, and ensure the config manager code that resolves paths uses
process.env.XDG_CONFIG_HOME and process.env.XDG_STATE_HOME with sensible
fallbacks (~/.config and ~/.local/state) so no user data is written into
repositories.

In `@src/lib/services/first-run-service.ts`:
- Around line 20-32: SETUP_EXEMPT_COMMANDS currently omits the 'setup' command
which can cause re-entry/infinite-loop issues when setupCommand() is invoked;
update the SETUP_EXEMPT_COMMANDS array to include 'setup' (and optionally
'doctor' if you want diagnostics exempt) so first-run setup logic will skip
these commands, ensuring the first-run guard checks against 'setup' and 'doctor'
when deciding whether to run the setup flow.

In `@src/ui/LoginUI.tsx`:
- Around line 169-173: In handleProjectSelect's catch block, call the onError
prop with the caught error (or a constructed Error using the message) in
addition to setErrorMessage and setPhase('error') so failures propagate the same
way as the useEffect error path; locate the catch block inside the
handleProjectSelect function and invoke onError(error) (or onError(new
Error(message)) if error is not an Error) before or after setting state.
🧹 Nitpick comments (17)
src/lib/services/firebase/downloader.ts (1)

249-265: Consider adding a comment for the 'ios-android' case.

When framework is 'native' and target is 'ios-android', this returns 'unknown'. While this works correctly (lines 239-240 fall back to serving both platforms for 'unknown'), a brief comment would clarify this is intentional.

📝 Suggested clarification
   private projectTypeToPlatform(projectType: ProjectType): Platform {
     if (projectType.framework === 'flutter') {
       return 'flutter';
     }
     if (projectType.framework === 'react-native' || projectType.framework === 'expo') {
       return 'react-native';
     }
     if (projectType.framework === 'native') {
       if (projectType.target === 'ios') return 'ios';
       if (projectType.target === 'android') return 'android';
+      // 'ios-android' or 'unknown' target: return 'unknown' to serve both platforms
       return 'unknown';
     }
     return 'unknown';
   }
src/lib/services/project-detector.ts (1)

155-178: Minor inefficiency with redundant filesystem checks.

hasIosProject and hasAndroidProject are called here (lines 170-171), and then again in detectTargetPlatform (called from detectProjectType). For projects detected as native, this results in 4 extra filesystem operations.

This is a minor concern since detection typically runs once during setup, but if performance becomes noticeable, consider caching these results.

src/lib/config/project-config-manager.ts (3)

175-183: Inconsistent import style for unlink.

The delete() method dynamically imports unlink while readFile, writeFile, stat, and mkdir are statically imported at the top. Consider importing unlink statically for consistency and to avoid the async import overhead.

♻️ Proposed fix

At the top of the file:

-import { mkdir, readFile, stat, writeFile } from 'node:fs/promises';
+import { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';

In the delete() method:

   async delete(): Promise<void> {
-    const { unlink } = await import('node:fs/promises');
     try {
       await unlink(this.configFilePath);

91-97: Simplify directory creation logic.

The ensureConfigDir method checks if the directory exists before creating it, but mkdir with { recursive: true } already handles this gracefully and is a no-op if the directory exists.

♻️ Proposed fix
   private async ensureConfigDir(): Promise<void> {
-    try {
-      await stat(this.configDirPath);
-    } catch {
-      await mkdir(this.configDirPath, { recursive: true, mode: 0o755 });
-    }
+    await mkdir(this.configDirPath, { recursive: true, mode: 0o755 });
   }

246-248: Edge case: Escaped backslashes before quotes.

The isUnescapedQuote function only checks if the immediately preceding character is a backslash. This doesn't correctly handle sequences like \\" where the backslash itself is escaped, making the quote unescaped. For typical JSONC config files this is unlikely to be an issue, but worth noting.

♻️ Proposed fix for robustness
 /** Check if current position is an unescaped quote */
 function isUnescapedQuote(content: string, index: number): boolean {
-  return content[index] === '"' && (index === 0 || content[index - 1] !== '\\');
+  if (content[index] !== '"') return false;
+  // Count preceding backslashes
+  let backslashCount = 0;
+  let i = index - 1;
+  while (i >= 0 && content[i] === '\\') {
+    backslashCount++;
+    i--;
+  }
+  // Quote is unescaped if preceded by an even number of backslashes
+  return backslashCount % 2 === 0;
 }
src/ui/chat/ChatApp.tsx (1)

52-60: Add error handling for config loading.

The async loadProjectConfig function doesn't handle potential errors. While projectConfig remaining null is a valid fallback, unhandled promise rejections can cause issues. Consider adding a try-catch or .catch().

🛡️ Proposed fix
   // Load project config on mount
   useEffect(() => {
     const loadProjectConfig = async () => {
-      const configManager = getProjectConfigManager();
-      const config = await configManager.load();
-      setProjectConfig(config);
+      try {
+        const configManager = getProjectConfigManager();
+        const config = await configManager.load();
+        setProjectConfig(config);
+      } catch {
+        // Config load failed - leave as null, ChatHeader handles this gracefully
+      }
     };
     loadProjectConfig();
   }, []);
src/commands/setup.tsx (1)

14-30: Promise may resolve twice due to overlapping completion paths.

Both onComplete (line 19) and waitUntilExit().then() (line 28) call resolve(). While calling resolve() multiple times is harmless (the Promise ignores subsequent calls), this creates unclear control flow. Consider removing the redundant waitUntilExit().then() block since onComplete and onError already handle all completion scenarios.

♻️ Proposed simplification
 export async function setupCommand(options?: SetupCommandOptions): Promise<void> {
   return new Promise((resolve, reject) => {
-    const { waitUntilExit } = safeRender(
+    safeRender(
       <SetupUI
         projectPath={options?.projectPath}
         onComplete={() => {
           resolve();
         }}
         onError={(error) => {
           reject(error);
         }}
       />,
     );
-
-    waitUntilExit().then(() => {
-      resolve();
-    });
   });
 }
src/ui/chat/components/ChatHeader.tsx (1)

62-68: Minor: Inconsistent prefix spacing for project_id label.

The idPrefix value ' project_id:' lacks a trailing space, unlike other prefixes (e.g., ' project: ', ' user: '). This may cause slight visual misalignment if the intent was consistent column alignment.

💅 Proposed fix for consistency
-  const idPrefix = ' project_id:';
+  const idPrefix = ' project_id: ';
src/ui/SetupUI.tsx (5)

166-169: Empty handleProjectSkip callback may cause UX confusion.

The callback is passed to ProjectSelector with showSkip={false}, but if the skip behavior changes in the future or showSkip is accidentally enabled, pressing Esc would do nothing with no feedback. Consider removing the callback entirely or adding a comment explaining why it's intentionally empty.


281-311: Missing useCancelInput hook for cancellation handling.

The "waiting for auth" phase shows "Press Ctrl+C to cancel" but doesn't use the useCancelInput hook from @/ui/hooks for proper cancellation handling. This could leave the component in an inconsistent state if the user cancels.

Based on learnings: "Import and use useCancelInput hook from @/ui/hooks for ESC/Ctrl+C cancellation handling in new UI components."

♻️ Proposed fix to add cancellation handling
 import { useCallback, useEffect, useRef, useState } from 'react';
+import { useCancelInput } from '@/ui/hooks';

Then add in the component:

+  useCancelInput(() => {
+    if (phase === 'waiting_for_auth' || phase === 'starting_auth') {
+      pkceServiceRef.current?.abort();
+      if (onError) {
+        onError(new Error('Setup cancelled by user'));
+      } else {
+        exit();
+      }
+    }
+  });

50-90: Code duplication with LoginUI.tsx.

The helper functions fetchMember, fetchUserName, and fetchOrganizationsWithProjects are nearly identical to those in LoginUI.tsx. Consider extracting these into a shared utility module to reduce duplication and ensure consistent behavior.


82-85: Sequential API calls could be parallelized.

Fetching projects for each organization is done sequentially in a loop. For users with many organizations, this could be slow. Consider using Promise.all for parallel fetching.

♻️ Proposed optimization
 async function fetchOrganizationsWithProjects(): Promise<OrgWithProjects[]> {
-  const orgsWithProjects: OrgWithProjects[] = [];
   try {
     const apiClient = getInternalApiClient();
     const orgs = await apiClient.listOrganizations();
-    for (const org of orgs) {
-      const projects = await apiClient.listProjects(org.id);
-      orgsWithProjects.push({ org, projects });
-    }
+    const orgsWithProjects = await Promise.all(
+      orgs.map(async (org) => ({
+        org,
+        projects: await apiClient.listProjects(org.id),
+      }))
+    );
+    return orgsWithProjects;
   } catch {
     // Silently ignore org/project fetch errors
+    return [];
   }
-  return orgsWithProjects;
 }

147-153: Magic number 1500ms timeout should be extracted as a constant.

The 1500ms delay before exit/completion and 2000ms delay on error are magic numbers. Consider extracting these as named constants for clarity and consistency.

Also applies to: 256-257

src/lib/services/firebase/detector.ts (1)

57-70: Duplicate projectTypeToPlatform function across multiple files.

This function is duplicated in firebase-service.ts (lines 25-38) and downloader.ts (lines 251-264). Consider extracting it to a shared utility in the firebase module to maintain DRY principles.

♻️ Suggested extraction

Create a shared utility in src/lib/services/firebase/utils.ts:

import type { ProjectType } from '@/lib/config';
import type { Platform } from './types';

export function projectTypeToPlatform(projectType: ProjectType): Platform {
  if (projectType.framework === 'flutter') {
    return 'flutter';
  }
  if (projectType.framework === 'react-native' || projectType.framework === 'expo') {
    return 'react-native';
  }
  if (projectType.framework === 'native') {
    if (projectType.target === 'ios') return 'ios';
    if (projectType.target === 'android') return 'android';
    return 'unknown';
  }
  return 'unknown';
}

Then import and use it in detector.ts, firebase-service.ts, and downloader.ts.

src/ui/LoginUI.tsx (1)

48-52: Code duplication: fetchMember helper is identical to SetupUI.tsx.

This function and fetchUserName, fetchOrganizationsWithProjects are duplicated between LoginUI.tsx and SetupUI.tsx. Consider extracting to a shared module like @/lib/api/helpers.ts or @/ui/utils/auth-helpers.ts.

src/lib/services/firebase/firebase-service.ts (1)

22-38: Duplicate projectTypeToPlatform function.

As noted in the detector.ts review, this function is duplicated across three files. Extract to a shared utility.

src/lib/config/project-config-schema.ts (1)

65-66: Avoid version drift between schema literal and constant.

Use the exported constant in the schema to keep versioning single-sourced.

♻️ Suggested refactor
-export const ProjectConfigSchema = z.object({
-  /** Configuration schema version */
-  version: z.literal(1),
+export const CURRENT_PROJECT_CONFIG_VERSION = 1;
+
+export const ProjectConfigSchema = z.object({
+  /** Configuration schema version */
+  version: z.literal(CURRENT_PROJECT_CONFIG_VERSION),
@@
-export const CURRENT_PROJECT_CONFIG_VERSION = 1;

Also applies to: 89-90

Comment thread src/lib/config/project-config-manager.ts
Comment thread src/lib/config/project-config-schema.ts
Comment thread src/lib/services/first-run-service.ts
Comment thread src/ui/LoginUI.tsx
@pitzcarraldo pitzcarraldo self-assigned this Feb 5, 2026
- Add explicit 'setup' case to CLI switch statement (P1)
- Add 'setup' to SETUP_EXEMPT_COMMANDS to prevent double execution
- Persist detected project type in SetupUI (P2)
- Use PROJECT_CONFIG_INVALID error code for better categorization
- Add onError callback in LoginUI handleProjectSelect catch block

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/cli.tsx`:
- Around line 210-212: The 'setup' case in the CLI currently no-ops when
shouldRunSetup() returns false (because needsSetup is false), leaving users with
no feedback; update the case handler for 'setup' in src/cli.tsx to detect
shouldRunSetup()/needsSetup and if false print a clear user-facing message like
"Setup already complete — nothing to do" (or alternatively call the existing
setup routine unconditionally), referencing the existing shouldRunSetup and
needsSetup logic so you either invoke the setup function regardless or emit the
message before breaking out of the case.

In `@src/lib/config/project-config-manager.ts`:
- Around line 246-248: The isUnescapedQuote function incorrectly treats a quote
as escaped if the immediate previous character is a backslash; update
isUnescapedQuote to count consecutive backslashes immediately before
content[index] and treat the quote as unescaped when the count is even
(including zero) and escaped when odd; keep the check that content[index] ===
'"' and implement parity-based logic on the backslash run to decide escaping for
isUnescapedQuote.
🧹 Nitpick comments (3)
src/lib/config/project-config-manager.ts (3)

14-16: Consider using English for the config header comment.

The config header uses Korean text. For consistency and broader accessibility in an open-source CLI tool, consider using English or making it configurable/localizable.

-const CONFIG_HEADER = `// Clix CLI 프로젝트 설정
-// 자동 생성됨 - 수동 수정 시 덮어쓰기될 수 있음
+const CONFIG_HEADER = `// Clix CLI project configuration
+// Auto-generated - manual edits may be overwritten
 `;

91-97: Simplify ensureConfigDir - the stat check is redundant.

With recursive: true, mkdir silently succeeds if the directory already exists. The stat-then-mkdir pattern adds unnecessary I/O and a minor TOCTOU window.

♻️ Proposed simplification
 private async ensureConfigDir(): Promise<void> {
-  try {
-    await stat(this.configDirPath);
-  } catch {
-    await mkdir(this.configDirPath, { recursive: true, mode: 0o755 });
-  }
+  await mkdir(this.configDirPath, { recursive: true, mode: 0o755 });
 }

175-183: Inconsistent import style for unlink.

unlink is dynamically imported here, while readFile, writeFile, mkdir, and stat are statically imported at the top. This is inconsistent and adds unnecessary overhead.

♻️ Proposed fix

Add unlink to the static imports at line 1:

-import { mkdir, readFile, stat, writeFile } from 'node:fs/promises';
+import { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';

Then simplify the delete method:

 async delete(): Promise<void> {
-  const { unlink } = await import('node:fs/promises');
   try {
     await unlink(this.configFilePath);
     this.cachedConfig = null;
   } catch {
     // File doesn't exist, ignore
   }
 }

Comment thread src/cli.tsx Outdated
Comment thread src/lib/config/project-config-manager.ts
- Add user feedback when `clix setup` is run on already configured project
- Fix isUnescapedQuote to correctly handle escaped backslashes
  (count consecutive backslashes to determine parity)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/cli.tsx`:
- Around line 210-220: Replace the dynamic import of checkFirstRun with a static
import alongside shouldRunSetup from './lib/services/first-run-service' (so both
are imported at module top), then simplify the 'setup' case to call the
statically imported checkFirstRun and, if not needing setup, update the message
to correctly tell users how to reconfigure (e.g., "Project already configured.
Run `clix setup` to reconfigure." or another appropriate reconfigure command)
instead of suggesting `clix login`; keep the existing call to setupCommand when
status.needsSetup is true.

Comment thread src/cli.tsx
- Replace dynamic import with static import for consistency
- Simplify setup already configured message

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@pitzcarraldo pitzcarraldo merged commit acc35b0 into main Feb 5, 2026
5 checks passed
@pitzcarraldo pitzcarraldo deleted the feat/detect-project-type branch February 5, 2026 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant