Resolves merge conflicts: - apps/server/src/routes/terminal/common.ts: Keep randomBytes import, use @automaker/utils for createLogger - apps/ui/eslint.config.mjs: Use main's explicit globals list with XMLHttpRequest and MediaQueryListEvent additions - apps/ui/src/components/views/terminal-view.tsx: Keep our terminal improvements (killAllSessions, beforeunload, better error handling) - apps/ui/src/config/terminal-themes.ts: Keep our search highlight colors for all themes - apps/ui/src/store/app-store.ts: Keep our terminal settings persistence improvements (merge function) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
AutoMaker Shared Packages - LLM Guide
This guide helps AI assistants understand how to use AutoMaker's shared packages effectively.
Package Overview
AutoMaker uses a monorepo structure with shared packages in libs/:
libs/
├── types/ # Type definitions (no dependencies)
├── utils/ # Utility functions
├── prompts/ # AI prompt templates
├── platform/ # Platform utilities
├── model-resolver/ # Claude model resolution
├── dependency-resolver/# Feature dependency resolution
└── git-utils/ # Git operations
When to Use Each Package
@automaker/types
Use when: You need type definitions for any AutoMaker concept.
Import for:
Feature- Feature interface with all propertiesExecuteOptions- Claude agent execution optionsConversationMessage- Chat message formatErrorType,ErrorInfo- Error handling typesCLAUDE_MODEL_MAP- Model alias to ID mappingDEFAULT_MODELS- Default model configurations
Example:
import type { Feature, ExecuteOptions } from '@automaker/types';
Never import from: services/feature-loader, providers/types
@automaker/utils
Use when: You need common utilities like logging, error handling, or image processing.
Import for:
createLogger(context)- Structured loggingisAbortError(error)- Error type checkingclassifyError(error)- Error classificationbuildPromptWithImages()- Prompt building with imagesreadImageAsBase64()- Image handlingextractTextFromContent()- Message parsing
Example:
import { createLogger, classifyError } from '@automaker/utils';
Never import from: lib/logger, lib/error-handler, lib/prompt-builder, lib/image-handler
@automaker/prompts
Use when: You need AI prompt templates for text enhancement or other AI-powered features.
Import for:
getEnhancementPrompt(mode)- Get complete prompt for enhancement modegetSystemPrompt(mode)- Get system prompt for specific modegetExamples(mode)- Get few-shot examples for a modebuildUserPrompt(description, mode)- Build user prompt with examplesisValidEnhancementMode(mode)- Check if mode is validIMPROVE_SYSTEM_PROMPT- System prompt for improving vague descriptionsTECHNICAL_SYSTEM_PROMPT- System prompt for adding technical detailsSIMPLIFY_SYSTEM_PROMPT- System prompt for simplifying verbose textACCEPTANCE_SYSTEM_PROMPT- System prompt for adding acceptance criteria
Example:
import { getEnhancementPrompt, isValidEnhancementMode } from '@automaker/prompts';
if (isValidEnhancementMode('improve')) {
const { systemPrompt, userPrompt } = getEnhancementPrompt('improve', description);
const result = await callClaude(systemPrompt, userPrompt);
}
Never import from: lib/enhancement-prompts
Enhancement modes:
improve- Transform vague requests into clear, actionable taskstechnical- Add implementation details and technical specificationssimplify- Make verbose descriptions concise and focusedacceptance- Add testable acceptance criteria
@automaker/platform
Use when: You need to work with AutoMaker's directory structure or spawn processes.
Import for:
getAutomakerDir(projectPath)- Get .automaker directorygetFeaturesDir(projectPath)- Get features directorygetFeatureDir(projectPath, featureId)- Get specific feature directoryensureAutomakerDir(projectPath)- Create .automaker if neededspawnJSONLProcess()- Spawn process with JSONL outputinitAllowedPaths()- Security path validation
Example:
import { getFeatureDir, ensureAutomakerDir } from '@automaker/platform';
Never import from: lib/automaker-paths, lib/subprocess-manager, lib/security
@automaker/model-resolver
Use when: You need to convert model aliases to full model IDs.
Import for:
resolveModelString(modelOrAlias)- Convert alias to full IDDEFAULT_MODELS- Access default models
Example:
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
// Convert user input to model ID
const modelId = resolveModelString('sonnet'); // → 'claude-sonnet-4-20250514'
Never import from: lib/model-resolver
Model aliases:
haiku→claude-haiku-4-5(fast, simple tasks)sonnet→claude-sonnet-4-20250514(balanced, recommended)opus→claude-opus-4-5-20251101(maximum capability)
@automaker/dependency-resolver
Use when: You need to order features by dependencies or check if dependencies are satisfied.
Import for:
resolveDependencies(features)- Topological sort with priorityareDependenciesSatisfied(feature, allFeatures)- Check if ready to executegetBlockingDependencies(feature, allFeatures)- Get incomplete dependencies
Example:
import { resolveDependencies, areDependenciesSatisfied } from '@automaker/dependency-resolver';
const { orderedFeatures, hasCycle } = resolveDependencies(features);
if (!hasCycle) {
for (const feature of orderedFeatures) {
if (areDependenciesSatisfied(feature, features)) {
await execute(feature);
}
}
}
Never import from: lib/dependency-resolver
Used in:
- Auto-mode feature execution (server)
- Board view feature ordering (UI)
@automaker/git-utils
Use when: You need git operations, status parsing, or diff generation.
Import for:
isGitRepo(path)- Check if path is a git repositoryparseGitStatus(output)- Parsegit status --porcelainoutputgetGitRepositoryDiffs(path)- Get complete diffs (tracked + untracked)generateSyntheticDiffForNewFile()- Create diff for untracked filelistAllFilesInDirectory()- List files excluding build artifacts
Example:
import { isGitRepo, getGitRepositoryDiffs } from '@automaker/git-utils';
if (await isGitRepo(projectPath)) {
const { diff, files, hasChanges } = await getGitRepositoryDiffs(projectPath);
console.log(`Found ${files.length} changed files`);
}
Never import from: routes/common
Handles:
- Binary file detection
- Large file handling (>1MB)
- Untracked file diffs
- Non-git directory support
Common Patterns
Creating a Feature Executor
import type { Feature, ExecuteOptions } from '@automaker/types';
import { createLogger, classifyError } from '@automaker/utils';
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
import { areDependenciesSatisfied } from '@automaker/dependency-resolver';
import { getFeatureDir } from '@automaker/platform';
const logger = createLogger('FeatureExecutor');
async function executeFeature(feature: Feature, allFeatures: Feature[], projectPath: string) {
// Check dependencies
if (!areDependenciesSatisfied(feature, allFeatures)) {
logger.warn(`Dependencies not satisfied for ${feature.id}`);
return;
}
// Resolve model
const model = resolveModelString(feature.model, DEFAULT_MODELS.autoMode);
// Get feature directory
const featureDir = getFeatureDir(projectPath, feature.id);
try {
// Execute with Claude
const options: ExecuteOptions = {
model,
temperature: 0.7,
};
await runAgent(featureDir, options);
logger.info(`Feature ${feature.id} completed`);
} catch (error) {
const errorInfo = classifyError(error);
logger.error(`Feature ${feature.id} failed:`, errorInfo.message);
}
}
Analyzing Git Changes
import { getGitRepositoryDiffs, parseGitStatus } from '@automaker/git-utils';
import { createLogger } from '@automaker/utils';
const logger = createLogger('GitAnalyzer');
async function analyzeChanges(projectPath: string) {
const { diff, files, hasChanges } = await getGitRepositoryDiffs(projectPath);
if (!hasChanges) {
logger.info('No changes detected');
return;
}
// Group by status
const modified = files.filter((f) => f.status === 'M');
const added = files.filter((f) => f.status === 'A');
const deleted = files.filter((f) => f.status === 'D');
const untracked = files.filter((f) => f.status === '?');
logger.info(
`Changes: ${modified.length}M ${added.length}A ${deleted.length}D ${untracked.length}U`
);
return diff;
}
Ordering Features for Execution
import type { Feature } from '@automaker/types';
import { resolveDependencies, getBlockingDependencies } from '@automaker/dependency-resolver';
import { createLogger } from '@automaker/utils';
const logger = createLogger('FeatureOrdering');
function orderAndFilterFeatures(features: Feature[]): Feature[] {
const { orderedFeatures, hasCycle, cyclicFeatures } = resolveDependencies(features);
if (hasCycle) {
logger.error(`Circular dependency detected: ${cyclicFeatures.join(' → ')}`);
throw new Error('Cannot execute features with circular dependencies');
}
// Filter to only ready features
const readyFeatures = orderedFeatures.filter((feature) => {
const blocking = getBlockingDependencies(feature, features);
if (blocking.length > 0) {
logger.debug(`${feature.id} blocked by: ${blocking.join(', ')}`);
return false;
}
return true;
});
logger.info(`${readyFeatures.length} of ${features.length} features ready`);
return readyFeatures;
}
Import Rules for LLMs
✅ DO
// Import types from @automaker/types
import type { Feature, ExecuteOptions } from '@automaker/types';
// Import constants from @automaker/types
import { CLAUDE_MODEL_MAP, DEFAULT_MODELS } from '@automaker/types';
// Import utilities from @automaker/utils
import { createLogger, classifyError } from '@automaker/utils';
// Import prompts from @automaker/prompts
import { getEnhancementPrompt, isValidEnhancementMode } from '@automaker/prompts';
// Import platform utils from @automaker/platform
import { getFeatureDir, ensureAutomakerDir } from '@automaker/platform';
// Import model resolution from @automaker/model-resolver
import { resolveModelString } from '@automaker/model-resolver';
// Import dependency resolution from @automaker/dependency-resolver
import { resolveDependencies } from '@automaker/dependency-resolver';
// Import git utils from @automaker/git-utils
import { getGitRepositoryDiffs } from '@automaker/git-utils';
❌ DON'T
// DON'T import from old paths
import { Feature } from '../services/feature-loader'; // ❌
import { ExecuteOptions } from '../providers/types'; // ❌
import { createLogger } from '../lib/logger'; // ❌
import { resolveModelString } from '../lib/model-resolver'; // ❌
import { isGitRepo } from '../routes/common'; // ❌
import { resolveDependencies } from '../lib/dependency-resolver'; // ❌
import { getEnhancementPrompt } from '../lib/enhancement-prompts'; // ❌
// DON'T import from old lib/ paths
import { getFeatureDir } from '../lib/automaker-paths'; // ❌
import { classifyError } from '../lib/error-handler'; // ❌
// DON'T define types that exist in @automaker/types
interface Feature { ... } // ❌ Use: import type { Feature } from '@automaker/types';
Migration Checklist
When refactoring server code, check:
- All
Featureimports use@automaker/types - All
ExecuteOptionsimports use@automaker/types - All logger usage uses
@automaker/utils - All prompt templates use
@automaker/prompts - All path operations use
@automaker/platform - All model resolution uses
@automaker/model-resolver - All dependency checks use
@automaker/dependency-resolver - All git operations use
@automaker/git-utils - No imports from old
lib/paths - No imports from
services/feature-loaderfor types - No imports from
providers/types
Package Dependencies
Understanding the dependency chain helps prevent circular dependencies:
@automaker/types (no dependencies)
↓
@automaker/utils
@automaker/prompts
@automaker/platform
@automaker/model-resolver
@automaker/dependency-resolver
↓
@automaker/git-utils
↓
@automaker/server
@automaker/ui
Rule: Packages can only depend on packages above them in the chain.
Building Packages
All packages must be built before use:
# Build all packages from workspace
npm run build:packages
# Or from root
npm install # Installs and links workspace packages
Module Format
All packages use ES modules (type: "module") with NodeNext module resolution:
- Requires explicit
.jsextensions in import statements - Compatible with both Node.js (server) and Vite (UI)
- Centralized ESM configuration in
libs/tsconfig.base.json
Testing
When writing tests:
// ✅ Import from packages
import type { Feature } from '@automaker/types';
import { createLogger } from '@automaker/utils';
// ❌ Don't import from src
import { Feature } from '../../../src/services/feature-loader';
Summary for LLMs
Quick reference:
- Types →
@automaker/types - Logging/Errors/Utils →
@automaker/utils - AI Prompts →
@automaker/prompts - Paths/Security →
@automaker/platform - Model Resolution →
@automaker/model-resolver - Dependency Ordering →
@automaker/dependency-resolver - Git Operations →
@automaker/git-utils
Never import from: lib/*, services/feature-loader (for types), providers/types, routes/common
Always: Use the shared packages instead of local implementations.