/** * InitCommand - First-run project initialization wizard * DD ยง17. Routes filesystem writes through ToolRegistry (INV-3). * * @module packages/cli/src/commands/init */ import { existsSync } from 'fs' import { join } from 'path' import { randomUUID } from 'crypto' import { loadConfig } from '../bootstrap/loadConfig.js' import { ToolRegistry, createToolRegistry, register_builtin_tools } from '@aircoding/runtime' import type { ToolExecutionContext } from '@aircoding/runtime' export async function initCommand(project_path?: string, toolRegistry?: ToolRegistry): Promise { const project_root = project_path || process.cwd() console.log(`Initializing AirCoding project at ${project_root}`) // Create minimal ToolRegistry if not provided (INV-3 compliance) let registry = toolRegistry if (!registry) { registry = createToolRegistry(project_root) register_builtin_tools(registry) } const context: ToolExecutionContext = { session_id: 'init', project_id: `proj_${randomUUID()}`, project_root, agent_id: 'cli-init', agent_type: 'executor', task_scope: { allowed_paths: [project_root], denied_paths: [] }, permission_profile: 'executor' } // Create .air directory structure via fs.write tool (INV-3) const dirs = [ join(project_root, '.air', 'shared'), join(project_root, '.air', 'local'), join(project_root, '.air', 'sessions'), join(project_root, '.air', 'logs'), join(project_root, '.air', 'workspaces') ] for (const dir of dirs) { if (!existsSync(dir)) { // Use fs.write with empty content to create directory await registry.call({ name: 'fs.write', arguments: { path: join(dir, '.gitkeep'), content: '', create_dirs: true } }, context) console.log(` Created ${dir}`) } } // Generate project_id const project_id = `proj_${randomUUID()}` // Write project.json via fs.write (INV-3) const project_json = { project_id, name: project_root.split('/').pop() || 'aircoding-project', created_at: new Date().toISOString(), version: '1.0.0-alpha' } await registry.call({ name: 'fs.write', arguments: { path: join(project_root, '.air', 'shared', 'project.json'), content: JSON.stringify(project_json, null, 2), create_dirs: true } }, context) console.log(` Created .air/shared/project.json (project_id: ${project_id})`) // Write default rules via fs.write (INV-3) await registry.call({ name: 'fs.write', arguments: { path: join(project_root, '.air', 'shared', 'rules.md'), content: '# Project Rules\n\nAdd your project-specific rules here.\n', create_dirs: true } }, context) console.log('\nProject initialized successfully!') console.log(`Run 'air run' to start a session.`) }