From a3c4b28e88633c01d2e1b11e2ee6e5e7c839b06c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 15:24:05 +0000 Subject: [PATCH] feat: auto-run quick project scan on first session so agent has immediate project context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously autoInit skipped the scan entirely — users had to run `ua scan` manually before the agent knew anything about the project. Now autoInit performs a fast, local-only scan (no LLM call) that generates docs/scan.md with directory tree, dependencies, scripts, key files, test files, API routes and git info. The agent picks this up automatically via the existing scan.md injection in agent-factory. Full AI-powered architecture analysis remains available via `ua scan --force` or the new `ua scan --quick` flag for explicit quick scans. --- src/cli.ts | 1 + src/commands/init.ts | 39 +++++++++++++++++++++++++++++++++------ src/commands/scan.ts | 43 ++++++++++++++++++++++++------------------- 3 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index f326506..32e9f85 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -100,6 +100,7 @@ program .description("Scan project and create docs/scan.md (auto-included in every LLM request)") .option("-d, --dir ", "Project directory", ".") .option("-f, --force", "Force re-scan even if scan.md exists") + .option("-q, --quick", "Skip AI analysis (fast, no LLM call — same as autoInit)") .action(scanCommand); // ── Create Project (Legacy) ─────────────────────────────────── diff --git a/src/commands/init.ts b/src/commands/init.ts index 0a75c94..8fa4359 100644 --- a/src/commands/init.ts +++ b/src/commands/init.ts @@ -22,6 +22,8 @@ interface InitOptions { dir?: string; quiet?: boolean; skipScan?: boolean; + /** Run a quick scan (no AI analysis) — fast, gives agent immediate project knowledge */ + quickScan?: boolean; } /** @@ -151,10 +153,12 @@ export default { } // 7. Run project scan (creates docs/scan.md) + // Quick scan = local analysis only (fast, no LLM call) — gives agent immediate project knowledge. + // Full scan (no quickScan flag) = quick scan + AI-powered architecture analysis. if (!options.skipScan) { if (!quiet) console.log(); try { - await scanProject(dir, false); + await scanProject(dir, false, options.quickScan); } catch { if (!quiet) console.log(` ${colors.warning(icons.warning)} ${colors.dim("Scan skipped (can be run later with 'ua scan')")}`); } @@ -178,12 +182,35 @@ export default { /** * Auto-init: Run silently on first chat session if .ultraagent/ doesn't exist. - * Only creates the directory structure — skips the scan (too slow for auto-init). + * Creates the directory structure AND a quick scan (no AI analysis) so the + * agent has immediate project knowledge (tree, deps, scripts, key files, ...). + * Run `ua scan --force` later for the full AI-powered architecture analysis. */ export async function autoInit(projectDir: string): Promise { - if (isInitialized(projectDir)) return; + const scanPath = path.join(projectDir, "docs", "scan.md"); + const hasStructure = isInitialized(projectDir); + const hasScan = fs.existsSync(scanPath); - console.log(colors.dim(`\n ${icons.info} First time in this project — setting up UltraAgent...`)); - await initProject({ dir: projectDir, quiet: true, skipScan: true }); - console.log(colors.dim(` ${icons.success} .ultraagent/ created. Use 'ua scan' for full project context.\n`)); + if (hasStructure && hasScan) return; + + if (!hasStructure) { + console.log(colors.dim(`\n ${icons.info} First time in this project — setting up UltraAgent...`)); + } + if (!hasScan) { + console.log(colors.dim(` ${icons.info} Scanning project for immediate context (quick scan, no LLM)...`)); + } + + await initProject({ + dir: projectDir, + quiet: true, + // Only run the quick scan if scan.md doesn't exist yet + skipScan: hasScan, + quickScan: true, + }); + + if (!hasScan) { + console.log(colors.dim(` ${icons.success} docs/scan.md created — agent has project context. Run 'ua scan --force' for deep AI analysis.\n`)); + } else if (!hasStructure) { + console.log(colors.dim(` ${icons.success} .ultraagent/ created.\n`)); + } } diff --git a/src/commands/scan.ts b/src/commands/scan.ts index ef8000a..9b8919b 100644 --- a/src/commands/scan.ts +++ b/src/commands/scan.ts @@ -19,6 +19,8 @@ import { getConfig } from "../utils/config.js"; interface ScanOptions { dir?: string; force?: boolean; + /** Skip the AI analysis phase — much faster, used by autoInit */ + quick?: boolean; } /** @@ -30,13 +32,14 @@ export async function scanCommand(options: ScanOptions): Promise { heading("Project Scan"); - await scanProject(dir, options.force); + await scanProject(dir, options.force, options.quick); } /** * Core scan logic — can be called from other commands (e.g., /new). + * Pass `quick: true` to skip the AI analysis phase (much faster, no LLM needed). */ -export async function scanProject(dir: string, force?: boolean): Promise { +export async function scanProject(dir: string, force?: boolean, quick?: boolean): Promise { const scanPath = path.join(dir, "docs", "scan.md"); // Check if scan already exists @@ -65,25 +68,27 @@ export async function scanProject(dir: string, force?: boolean): Promise const details = await gatherProjectDetails(dir); detailSpinner.succeed(colors.success("Details gathered")); - // Phase 3: AI-powered deep analysis - console.log(); - statusLine("🤖", "AI analysis", "Generating comprehensive documentation..."); + // Phase 3: AI-powered deep analysis (skipped in quick mode) + let aiAnalysis = ""; + if (!quick) { + console.log(); + statusLine("🤖", "AI analysis", "Generating comprehensive documentation..."); - const config = getConfig(); - const analysisPrompt = buildScanPrompt(dir, info, tree, details); + const config = getConfig(); + const analysisPrompt = buildScanPrompt(dir, info, tree, details); - let aiAnalysis = ""; - try { - aiAnalysis = await runAgent( - { mode: "analyze", config, projectDir: dir, skipScanInjection: true }, - analysisPrompt, - { - onToken: (token) => process.stdout.write(colors.dim(token)), - } - ); - } catch (err: unknown) { - const detail = err instanceof Error ? err.message : String(err); - console.log(colors.warning(` ${icons.warning} AI analysis skipped: ${detail}`)); + try { + aiAnalysis = await runAgent( + { mode: "analyze", config, projectDir: dir, skipScanInjection: true }, + analysisPrompt, + { + onToken: (token) => process.stdout.write(colors.dim(token)), + } + ); + } catch (err: unknown) { + const detail = err instanceof Error ? err.message : String(err); + console.log(colors.warning(` ${icons.warning} AI analysis skipped: ${detail}`)); + } } // Phase 4: Generate scan.md