Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,6 @@ chrome-debug.log
# Firebase credentials
ios/GoogleService-Info.plist
android/app/google-services.json

# Clix CLI local config
.clix/
17 changes: 17 additions & 0 deletions src/cli.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { runIosSetupCommand } from './commands/ios-setup/index';
import { loginCommand } from './commands/login';
import { logoutCommand } from './commands/logout';
import { resumeCommand } from './commands/resume';
import { setupCommand } from './commands/setup';
import { skillCommand } from './commands/skill/index';
import { uninstallCommand } from './commands/uninstall';
import { updateCommand } from './commands/update';
import { whoamiCommand } from './commands/whoami';
import { checkFirstRun, shouldRunSetup } from './lib/services/first-run-service';
import {
getValidMCPAgents,
isValidMCPAgent,
Expand Down Expand Up @@ -132,6 +134,11 @@ async function main() {
const skillTypes = getAvailableSkillTypes();

try {
// Check if first-run setup is needed
if (await shouldRunSetup(command)) {
await setupCommand();
}
Comment thread
pitzcarraldo marked this conversation as resolved.

switch (command) {
case 'help':
cli.showHelp();
Expand Down Expand Up @@ -200,6 +207,16 @@ async function main() {
await firebaseCommand();
break;

case 'setup': {
const status = await checkFirstRun();
if (status.needsSetup) {
await setupCommand();
} else {
console.log('Project already configured.');
}
break;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

case 'ios-setup':
case 'capabilities':
case 'ios-capabilities': {
Expand Down
31 changes: 31 additions & 0 deletions src/commands/setup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { SetupUI } from '@/ui/SetupUI';
import { safeRender } from '@/ui/utils/safeRender';

interface SetupCommandOptions {
/** Project path (defaults to cwd) */
projectPath?: string;
}

/**
* Run the project setup command.
* Sets up .clix/config.jsonc with org, project, and member information.
*/
export async function setupCommand(options?: SetupCommandOptions): Promise<void> {
return new Promise((resolve, reject) => {
const { waitUntilExit } = safeRender(
<SetupUI
projectPath={options?.projectPath}
onComplete={() => {
resolve();
}}
onError={(error) => {
reject(error);
}}
/>,
);

waitUntilExit().then(() => {
resolve();
});
});
}
4 changes: 2 additions & 2 deletions src/lib/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('ConfigManager', () => {
const config = await manager.load();

expect(config.selectedAgent).toBe('');
expect(config.version).toBe(4);
expect(config.version).toBe(5);
expect(config.ui).toBeDefined();
expect(config.ui.streaming).toBe(true);
});
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('ConfigManager', () => {
const config = await manager.load();

expect(config.selectedAgent).toBe('claude');
expect(config.version).toBe(4);
expect(config.version).toBe(5);
});

test('should create config directory if it does not exist', async () => {
Expand Down
1 change: 1 addition & 0 deletions src/lib/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface Project {
id: string;
name: string;
organization_id: string;
public_key?: string;
created_at?: string;
updated_at?: string;
}
Expand Down
25 changes: 21 additions & 4 deletions src/lib/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@
*/

export { ConfigManager, getConfigManager, resetConfigManager } from './manager';
// Project-local configuration
export { getProjectConfigManager, ProjectConfigManager } from './project-config-manager';
export {
CURRENT_PROJECT_CONFIG_VERSION,
PROJECT_CONFIG_DIR,
PROJECT_CONFIG_FILENAME,
type ProjectConfig,
ProjectConfigSchema,
type ProjectFramework,
type ProjectInfo,
ProjectInfoSchema,
type ProjectMember,
ProjectMemberSchema,
type ProjectOrganization,
ProjectOrganizationSchema,
type ProjectTargetPlatform,
type ProjectType,
ProjectTypeSchema,
safeValidateProjectConfig,
validateProjectConfig,
} from './project-config-schema';
export {
type AgentConfig,
AgentConfigSchema,
Expand All @@ -17,14 +38,10 @@ export {
type DeepPartial,
type ExperimentalConfig,
ExperimentalSchema,
type LinkedProject,
LinkedProjectSchema,
PartialConfigSchema,
safeValidateConfig,
type UIConfig,
UIConfigSchema,
validateConfig,
validatePartialConfig,
type WorkspaceMappings,
WorkspaceMappingsSchema,
} from './schema';
14 changes: 10 additions & 4 deletions src/lib/config/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
* Current configuration schema version.
* Increment when making breaking changes to config structure.
*/
const CURRENT_VERSION = 4;
const CURRENT_VERSION = 5;

/**
* Migration function type.
Expand Down Expand Up @@ -75,17 +75,24 @@ const MIGRATIONS: Record<number, MigrationFn> = {
return migrated;
},

// Migration from v3 to v4: Add workspace mappings
// Migration from v3 to v4: Add workspace mappings (legacy)
4: (config: RawConfig): RawConfig => {
const migrated: RawConfig = { ...config, version: 4 };

// Initialize empty workspaces if not present
// Initialize empty workspaces if not present (legacy)
if (!migrated.workspaces) {
migrated.workspaces = {};
}

return migrated;
},

// Migration from v4 to v5: Remove workspace mappings (moved to project-local .clix/config.jsonc)
5: (config: RawConfig): RawConfig => {
// Destructure to exclude workspaces field
const { workspaces: _removed, ...rest } = config;
return { ...rest, version: 5 };
},
};

/**
Expand Down Expand Up @@ -223,7 +230,6 @@ export class ConfigManager {
...config.update,
},
agents: config.agents ?? {},
workspaces: config.workspaces ?? {},
};
}

Expand Down
Loading