Skip to content

Commit c1cc45e

Browse files
authored
refactor(core): change folder structure to be by command/resource (#8)
* refactor core/ to structured by resource * remove usage of @core from inside core/ * some more changes * lint issues * small eslint rule * no name for resource
1 parent c65b74c commit c1cc45e

36 files changed

Lines changed: 237 additions & 315 deletions

AGENTS.md

Lines changed: 83 additions & 233 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
This document provides essential context and guidelines for AI agents working on the Base44 CLI project.
44

5+
**Important**: Keep this file updated when making significant architectural changes.
6+
57
## Project Overview
68

79
The Base44 CLI is a TypeScript-based command-line tool built with:
@@ -12,263 +14,111 @@ The Base44 CLI is a TypeScript-based command-line tool built with:
1214

1315
### Project Structure
1416
- **Package**: `base44` - Single package published to npm
15-
- **Core Module**: `src/core/` - Shared utilities, API clients, schemas, config
17+
- **Core Module**: `src/core/` - Resources, utilities, errors, and config
1618
- **CLI Module**: `src/cli/` - CLI commands and entry point
1719

18-
## Key Technologies & Patterns
19-
20-
### CLI Framework
21-
- Use **Commander.js** for all command definitions
22-
- CLI name is **`base44`**
23-
- Commands follow the pattern: `base44 <command> [subcommand] [options]`
24-
25-
### User Interaction
26-
- Always use **@clack/prompts** for interactive prompts
27-
- Use `@clack/prompts` for:
28-
- User input collection
29-
- Progress indicators
30-
- Spinners for async operations (via `runTask` utility)
31-
- Confirmation dialogs
32-
- Selection menus
33-
34-
### Schema Validation
35-
- **Zod is mandatory** for all validation:
36-
- API response validation
37-
- Configuration file validation
38-
- User input validation
39-
- File schema validation
40-
- Create Zod schemas before implementing features
41-
- Use Zod-inferred types for TypeScript type safety
42-
- Always validate external data before processing
43-
44-
### Code Style & Structure
20+
## Folder Structure
4521

46-
#### Code Comments
47-
- **Minimal commenting approach**: Only add comments for:
48-
- Complex algorithms or non-obvious logic
49-
- Unclear design decisions that need explanation
50-
- Workarounds or non-standard patterns
51-
- **Avoid commenting**:
52-
- Self-explanatory code
53-
- Simple function signatures (TypeScript types provide documentation)
54-
- Obvious operations (e.g., "// Read the file" when the function is `readFile`)
55-
- **JSDoc comments**: Only use for public APIs that need documentation for external consumers
56-
- Let the code speak for itself - prefer clear naming over comments
57-
58-
#### Project Folder Structure
5922
```
6023
cli/
6124
├── src/
62-
│ ├── core/ # Core module (shared code)
63-
│ │ ├── api/ # API client code
64-
│ │ ├── config/ # Configuration management
65-
│ │ ├── errors/ # Custom error classes
66-
│ │ ├── schemas/ # Zod schemas
67-
│ │ ├── utils/ # Utility functions
68-
│ │ └── index.ts # Core module exports
69-
│ └── cli/ # CLI module (main CLI)
70-
│ ├── commands/ # Command implementations (grouped by feature)
71-
│ │ ├── auth/ # Authentication commands (login, logout, whoami)
72-
│ │ └── project/ # Project commands (show-project)
73-
│ ├── utils/ # CLI-specific utilities (runCommand, runTask)
74-
│ └── index.ts # Main CLI entry point (with shebang)
75-
├── dist/ # Build output
76-
├── package.json # Package configuration
77-
└── tsconfig.json # TypeScript configuration
25+
│ ├── core/
26+
│ │ ├── auth/ # Auth (user authentication, not a project resource)
27+
│ │ │ ├── api.ts
28+
│ │ │ ├── schema.ts
29+
│ │ │ ├── config.ts
30+
│ │ │ └── index.ts
31+
│ │ ├── resources/ # Project resources (entity, function, etc.)
32+
│ │ │ ├── entity/
33+
│ │ │ │ ├── schema.ts
34+
│ │ │ │ ├── config.ts
35+
│ │ │ │ ├── resource.ts
36+
│ │ │ │ └── index.ts
37+
│ │ │ ├── function/
38+
│ │ │ │ ├── schema.ts
39+
│ │ │ │ ├── config.ts
40+
│ │ │ │ ├── resource.ts
41+
│ │ │ │ └── index.ts
42+
│ │ │ └── index.ts
43+
│ │ ├── config/ # Project/app configuration
44+
│ │ │ ├── resource.ts # Resource<T> interface
45+
│ │ │ ├── project.ts # Project loading logic
46+
│ │ │ ├── app.ts
47+
│ │ │ └── index.ts
48+
│ │ ├── utils/
49+
│ │ ├── consts.ts
50+
│ │ ├── errors.ts
51+
│ │ └── index.ts
52+
│ └── cli/
53+
│ ├── commands/
54+
│ │ ├── auth/
55+
│ │ └── project/
56+
│ ├── utils/
57+
│ └── index.ts
58+
├── dist/
59+
├── package.json
60+
└── tsconfig.json
7861
```
7962

80-
#### Path Aliases
81-
82-
The project uses TypeScript path aliases for cleaner imports. These are defined in `tsconfig.json` and resolved at build time using `tsc-alias`:
63+
## Resource Pattern
8364

84-
- `@api/*``./src/core/api/*`
85-
- `@schemas/*``./src/core/schemas/*`
86-
- `@config/*``./src/core/config/*`
87-
- `@core/*``./src/core/*`
65+
Resources are project-specific collections (entities, functions) that can be loaded from the filesystem.
8866

89-
**Example usage:**
67+
### Resource Interface (`config/resource.ts`)
9068
```typescript
91-
import { writeAuth } from "@config/auth.js";
92-
import { generateDeviceCode } from "@api/auth/index.js";
93-
import { AuthApiError } from "@core/errors/index.js";
69+
export interface Resource<T> {
70+
readAll(dir: string): Promise<T[]>;
71+
}
9472
```
9573

96-
#### Command Implementation Pattern
74+
### Resource Implementation (`resources/<name>/resource.ts`)
9775
```typescript
98-
import { Command } from "commander";
99-
import { log } from "@clack/prompts";
100-
import { runCommand, runTask } from "../../utils/index.js";
101-
import { someConfig } from "@config/some.js";
102-
import { someApiCall } from "@api/some/index.js";
103-
104-
async function commandFunction(): Promise<void> {
105-
const result = await runTask(
106-
"Loading data...",
107-
async () => {
108-
return await someApiCall();
109-
},
110-
{
111-
successMessage: "Data loaded",
112-
errorMessage: "Failed to load data",
113-
}
114-
);
115-
116-
log.info(`Result: ${result}`);
117-
}
118-
119-
export const commandName = new Command("command-name")
120-
.description("Command description")
121-
.action(async () => {
122-
await runCommand(commandFunction);
123-
});
76+
export const entityResource: Resource<Entity> = {
77+
readAll: readAllEntities,
78+
};
12479
```
12580

126-
**Important**:
127-
- All commands must use `runCommand()` wrapper for consistent Base44 branding
128-
- Use `runTask()` for async operations that need spinner feedback
129-
- Use path aliases for imports from core module
130-
- Use relative imports for CLI-specific utilities
81+
### Adding a New Resource
82+
1. Create folder in `src/core/resources/<name>/`
83+
2. Add `schema.ts` with Zod schemas
84+
3. Add `config.ts` with file reading logic
85+
4. Add `resource.ts` implementing `Resource<T>`
86+
5. Add `index.ts` barrel exports
87+
6. Register in `config/project.ts` resources list
88+
7. Add typed field to `ProjectData` interface
13189

132-
#### CLI Utilities
90+
## Path Aliases
13391

134-
**`runCommand(commandFn)`** - Wraps command execution with:
135-
- Base44 intro banner
136-
- Consistent error handling for `AuthApiError`, `AuthValidationError`, and generic errors
137-
- Process exit on error
138-
139-
**`runTask(message, operation, options)`** - Wraps async operations with:
140-
- Automatic spinner management
141-
- Success/error message customization
142-
- Returns the operation result
92+
Single alias defined in `tsconfig.json`:
93+
- `@core/*``./src/core/*`
14394

144-
#### Schema Definition Pattern
14595
```typescript
146-
import { z } from "zod";
147-
148-
export const UserSchema = z.object({
149-
id: z.string(),
150-
email: z.string().email(),
151-
name: z.string(),
152-
});
153-
154-
export type User = z.infer<typeof UserSchema>;
96+
import { readProjectConfig } from "@core/config/project.js";
97+
import { entityResource } from "@core/resources/entity/index.js";
15598
```
15699

157-
## Development Workflow
158-
159-
### Package Manager
160-
- **Use npm** for all package management operations
161-
- Install dependencies: `npm install`
162-
- Add dependencies: `npm install <package>`
163-
- Add dev dependencies: `npm install -D <package>`
164-
165-
### Build Process
166-
- **Build**: Use `npm run build` to compile TypeScript to JavaScript (runs `tsc && tsc-alias`)
167-
- **Development**: Use `npm run dev` for development mode (uses `tsx` to run TypeScript directly)
168-
- Always build before testing
169-
- **ES Modules**: Package uses `"type": "module"` - use `.js` extensions in imports
170-
- **CLI Entry Point**: Main entry point (`src/cli/index.ts`) includes shebang for direct execution
171-
- **Output**: Compiled JavaScript output goes to `dist/` directory
172-
- **Path Alias Resolution**: `tsc-alias` resolves path aliases in compiled output
173-
174-
### Command Testing
175-
- Test commands by running the compiled CLI or using development mode
176-
- Verify help text: `base44 <command> --help`
177-
178100
## Important Rules
179101

180-
1. **Use npm** for all package management - never yarn
181-
2. **Project structure** - Core module (`src/core/`) contains shared code, CLI module (`src/cli/`) contains commands
182-
3. **Path aliases** - Use `@api/*`, `@config/*`, `@schemas/*`, `@core/*` for imports from core module
183-
4. **CLI utilities** - Use relative imports for CLI-specific utilities (`../../utils/index.js`)
184-
5. **Zod validation is required** for all external data
185-
6. **@clack/prompts for all user interaction** - no raw `readline` or `inquirer`
186-
7. **TypeScript strict mode** - maintain type safety
187-
8. **Commander.js for commands** - follow the established pattern
188-
9. **TypeScript compiler for builds** - use `tsc && tsc-alias` for production builds, `tsx` for development
189-
10. **Test commands** after implementation to ensure they're registered
190-
11. **Cross-platform support** - The CLI must work on both Windows and Unix-like systems. Always use `path.join()`, `path.dirname()`, and other `path` module utilities for path operations. Never use string concatenation or hardcoded path separators.
191-
12. **Command wrapper** - All commands must use `runCommand()` utility for consistent Base44 branding
192-
13. **Task wrapper** - Use `runTask()` for async operations that need spinner feedback
193-
14. **ES Modules** - Package uses `"type": "module"` - always use `.js` extensions in import statements
194-
15. **Shared utilities** - Use cross-platform file utilities and config management from `src/core/`
195-
196-
## Common Patterns
197-
198-
### Adding a New Command
199-
1. Create command file in `src/cli/commands/<feature>/` directory
200-
2. Import and register in main CLI entry point (`src/cli/index.ts`)
201-
3. Use Commander.js Command class
202-
4. Add Zod validation for inputs (schemas in `src/core/schemas/`)
203-
5. Use @clack/prompts for user interaction
204-
6. Use path aliases for imports from core module (`@api/*`, `@config/*`, etc.)
205-
7. Use relative imports for CLI utilities (`../../utils/index.js`)
206-
8. Wrap command function with `runCommand()` utility
207-
9. Use `runTask()` for async operations with spinners
208-
209-
### API Integration
210-
1. Define Zod schema in `src/core/schemas/` directory
211-
2. Create API client function in `src/core/api/` directory
212-
3. Export from `src/core/api/index.ts`
213-
4. Import in CLI commands using path alias (`@api/*`)
214-
5. Validate response with Zod schema
215-
6. Handle errors gracefully
216-
7. Use `runTask()` for loading states
217-
218-
### Configuration Management
219-
1. Define Zod schema in `src/core/schemas/` directory
220-
2. Create config management functions in `src/core/config/` directory
221-
3. Export from `src/core/config/index.ts`
222-
4. Import in CLI commands using path alias (`@config/*`)
223-
5. Read config file
224-
6. Validate with Zod schema
225-
7. Provide type-safe access via inferred types
226-
227-
## Dependencies Reference
228-
229-
### Core (Required)
230-
- `commander` - CLI framework
231-
- `@clack/prompts` - User prompts and UI components
232-
- `chalk` - Terminal colors
233-
- `zod` - Schema validation
234-
- `p-wait-for` - Polling utility for async operations
235-
236-
### Development
237-
- `typescript` - Language
238-
- `tsx` - TypeScript execution for development mode
239-
- `tsc-alias` - Path alias resolution for compiled output
102+
1. **npm only** - Never use yarn
103+
2. **Zod validation** - Required for all external data
104+
3. **@clack/prompts** - For all user interaction
105+
4. **ES Modules** - Use `.js` extensions in imports
106+
5. **Cross-platform** - Use `path` module utilities, never hardcode separators
107+
6. **Command wrapper** - All commands use `runCommand()` utility
108+
7. **Task wrapper** - Use `runTask()` for async operations with spinners
109+
8. **Keep AGENTS.md updated** - Update this file when architecture changes
110+
111+
## Development
112+
113+
```bash
114+
npm run build # tsc && tsc-alias
115+
npm run dev # tsx for development
116+
npm test # vitest
117+
```
240118

241119
## File Locations
242120

243-
- **Main plan**: `cli/plan.md` - Full implementation plan
244-
- **This file**: `cli/AGENTS.md` - AI agent guidelines
245-
- **Core module**: `cli/src/core/` - Shared utilities, API, schemas, config
246-
- **CLI module**: `cli/src/cli/` - CLI commands and entry point
247-
248-
## Questions to Ask
249-
250-
If uncertain about implementation:
251-
1. Check `plan.md` for feature requirements
252-
2. Verify command name matches `base44 <command>` pattern
253-
3. Ensure Zod validation is included
254-
4. Confirm @clack/prompts is used for user interaction
255-
5. Check if feature is in current phase scope
256-
257-
## Notes from Development
258-
259-
- **Project structure**: Single package with core and cli modules
260-
- CLI uses TypeScript with strict type checking
261-
- All commands must be registered in main CLI entry point (`src/cli/index.ts`)
262-
- Build process compiles TypeScript to JavaScript in `dist/` folder and resolves path aliases
263-
- Commands should be testable independently
264-
- Shared code (API, schemas, config, utils, errors) goes in `src/core/`
265-
- CLI-specific code (commands, runCommand, runTask) goes in `src/cli/`
266-
- Use path aliases (`@api/*`, `@config/*`, `@schemas/*`, `@core/*`) for imports from core
267-
- Use relative imports for CLI-specific utilities
268-
- Error handling should be user-friendly with clear messages
269-
- Use @clack/prompts for all user-facing interactions (no console.log for prompts)
270-
- All commands use `runCommand()` utility for consistent branding
271-
- Use `runTask()` for async operations with spinner feedback
272-
- Package uses ES modules - imports must use `.js` extensions
273-
- Use cross-platform file utilities from `src/core/utils/` for file operations
274-
- All data validation uses Zod schemas with type inference
121+
- `cli/plan.md` - Implementation plan
122+
- `cli/AGENTS.md` - This file
123+
- `cli/src/core/` - Core module
124+
- `cli/src/cli/` - CLI commands

eslint.config.mjs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import tseslint from "typescript-eslint";
22
import importPlugin from "eslint-plugin-import";
33
import unicornPlugin from "eslint-plugin-unicorn";
4+
import stylistic from "@stylistic/eslint-plugin";
45

56
export default tseslint.config(
67
{
@@ -21,6 +22,7 @@ export default tseslint.config(
2122
"@typescript-eslint": tseslint.plugin,
2223
import: importPlugin,
2324
unicorn: unicornPlugin,
25+
"@stylistic": stylistic,
2426
},
2527
rules: {
2628
//
@@ -109,6 +111,12 @@ export default tseslint.config(
109111
"unicorn/no-lonely-if": "error",
110112
"unicorn/no-typeof-undefined": "error",
111113
"unicorn/prefer-array-some": "error",
114+
115+
//
116+
// Stylistic
117+
//
118+
119+
"@stylistic/no-trailing-spaces": "error",
112120
},
113121
}
114122
);

0 commit comments

Comments
 (0)