Files
automaker/apps/app/src/lib/project-init.ts
Cody Seibert b52b9ba236 feat: enhance project initialization and improve logging in auto mode service
- Added a default categories.json file to the project initialization structure.
- Improved code formatting and readability in the auto-mode-service.ts file by restructuring console log statements and method calls.
- Updated feature status checks to include "backlog" in addition to "pending" and "ready".
2025-12-14 00:43:52 -05:00

198 lines
5.2 KiB
TypeScript

/**
* Project initialization utilities
*
* Handles the setup of the .automaker directory structure when opening
* new or existing projects.
*/
import { getElectronAPI } from "./electron";
export interface ProjectInitResult {
success: boolean;
isNewProject: boolean;
error?: string;
createdFiles?: string[];
existingFiles?: string[];
}
/**
* Required files and directories in the .automaker directory
* Note: app_spec.txt is NOT created automatically - user must set it up via the spec editor
*/
const REQUIRED_STRUCTURE: {
directories: string[];
files: Record<string, string>;
} = {
directories: [
".automaker",
".automaker/context",
".automaker/features",
".automaker/images",
],
files: {
".automaker/categories.json": "[]",
},
};
/**
* Initializes the .automaker directory structure for a project
*
* @param projectPath - The root path of the project
* @returns Result indicating what was created or if the project was already initialized
*/
export async function initializeProject(
projectPath: string
): Promise<ProjectInitResult> {
const api = getElectronAPI();
const createdFiles: string[] = [];
const existingFiles: string[] = [];
try {
// Create all required directories
for (const dir of REQUIRED_STRUCTURE.directories) {
const fullPath = `${projectPath}/${dir}`;
await api.mkdir(fullPath);
}
// Check and create required files
for (const [relativePath, defaultContent] of Object.entries(
REQUIRED_STRUCTURE.files
)) {
const fullPath = `${projectPath}/${relativePath}`;
const exists = await api.exists(fullPath);
if (!exists) {
await api.writeFile(fullPath, defaultContent as string);
createdFiles.push(relativePath);
} else {
existingFiles.push(relativePath);
}
}
// Determine if this is a new project (no files needed to be created since features/ is empty by default)
const isNewProject =
createdFiles.length === 0 && existingFiles.length === 0;
return {
success: true,
isNewProject,
createdFiles,
existingFiles,
};
} catch (error) {
console.error("[project-init] Failed to initialize project:", error);
return {
success: false,
isNewProject: false,
error: error instanceof Error ? error.message : "Unknown error occurred",
};
}
}
/**
* Checks if a project has the required .automaker structure
*
* @param projectPath - The root path of the project
* @returns true if all required files/directories exist
*/
export async function isProjectInitialized(
projectPath: string
): Promise<boolean> {
const api = getElectronAPI();
try {
// Check all required directories exist (no files required - features/ folder is source of truth)
for (const dir of REQUIRED_STRUCTURE.directories) {
const fullPath = `${projectPath}/${dir}`;
const exists = await api.exists(fullPath);
if (!exists) {
return false;
}
}
return true;
} catch (error) {
console.error(
"[project-init] Error checking project initialization:",
error
);
return false;
}
}
/**
* Gets a summary of what needs to be initialized for a project
*
* @param projectPath - The root path of the project
* @returns List of missing files/directories
*/
export async function getProjectInitStatus(projectPath: string): Promise<{
initialized: boolean;
missingFiles: string[];
existingFiles: string[];
}> {
const api = getElectronAPI();
const missingFiles: string[] = [];
const existingFiles: string[] = [];
try {
// Check directories (no files required - features/ folder is source of truth)
for (const dir of REQUIRED_STRUCTURE.directories) {
const fullPath = `${projectPath}/${dir}`;
const exists = await api.exists(fullPath);
if (exists) {
existingFiles.push(dir);
} else {
missingFiles.push(dir);
}
}
return {
initialized: missingFiles.length === 0,
missingFiles,
existingFiles,
};
} catch (error) {
console.error("[project-init] Error getting project status:", error);
return {
initialized: false,
missingFiles: REQUIRED_STRUCTURE.directories,
existingFiles: [],
};
}
}
/**
* Checks if the app_spec.txt file exists for a project
*
* @param projectPath - The root path of the project
* @returns true if app_spec.txt exists
*/
export async function hasAppSpec(projectPath: string): Promise<boolean> {
const api = getElectronAPI();
try {
const fullPath = `${projectPath}/.automaker/app_spec.txt`;
return await api.exists(fullPath);
} catch (error) {
console.error("[project-init] Error checking app_spec.txt:", error);
return false;
}
}
/**
* Checks if the .automaker directory exists for a project
*
* @param projectPath - The root path of the project
* @returns true if .automaker directory exists
*/
export async function hasAutomakerDir(projectPath: string): Promise<boolean> {
const api = getElectronAPI();
try {
const fullPath = `${projectPath}/.automaker`;
return await api.exists(fullPath);
} catch (error) {
console.error("[project-init] Error checking .automaker dir:", error);
return false;
}
}