mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
Merge main into massive-terminal-upgrade
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>
This commit is contained in:
66
docs/docker-isolation.md
Normal file
66
docs/docker-isolation.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Docker Isolation Guide
|
||||
|
||||
This guide covers running Automaker in a fully isolated Docker container. For background on why isolation matters, see the [Security Disclaimer](../DISCLAIMER.md).
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Set your API key** (create a `.env` file in the project root):
|
||||
|
||||
```bash
|
||||
# Linux/Mac
|
||||
echo "ANTHROPIC_API_KEY=your-api-key-here" > .env
|
||||
|
||||
# Windows PowerShell
|
||||
Set-Content -Path .env -Value "ANTHROPIC_API_KEY=your-api-key-here" -Encoding UTF8
|
||||
```
|
||||
|
||||
2. **Build and run**:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
3. **Access Automaker** at `http://localhost:3007`
|
||||
|
||||
4. **Stop**:
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
## How Isolation Works
|
||||
|
||||
The default `docker-compose.yml` configuration:
|
||||
|
||||
- Uses only Docker-managed volumes (no host filesystem access)
|
||||
- Server runs as a non-root user
|
||||
- Has no privileged access to your system
|
||||
|
||||
Projects created in the UI are stored inside the container at `/projects` and persist across restarts via Docker volumes.
|
||||
|
||||
## Mounting a Specific Project
|
||||
|
||||
If you need to work on a host project, create `docker-compose.project.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
server:
|
||||
volumes:
|
||||
- ./my-project:/projects/my-project:ro # :ro = read-only
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.yml -f docker-compose.project.yml up -d
|
||||
```
|
||||
|
||||
**Tip**: Use `:ro` (read-only) when possible for extra safety.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
| --------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| Container won't start | Check `.env` has `ANTHROPIC_API_KEY` set. Run `docker-compose logs` for errors. |
|
||||
| Can't access web UI | Verify container is running with `docker ps \| grep automaker` |
|
||||
| Need a fresh start | Run `docker-compose down && docker volume rm automaker-data && docker-compose up -d --build` |
|
||||
450
docs/llm-shared-packages.md
Normal file
450
docs/llm-shared-packages.md
Normal file
@@ -0,0 +1,450 @@
|
||||
# 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 properties
|
||||
- `ExecuteOptions` - Claude agent execution options
|
||||
- `ConversationMessage` - Chat message format
|
||||
- `ErrorType`, `ErrorInfo` - Error handling types
|
||||
- `CLAUDE_MODEL_MAP` - Model alias to ID mapping
|
||||
- `DEFAULT_MODELS` - Default model configurations
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 logging
|
||||
- `isAbortError(error)` - Error type checking
|
||||
- `classifyError(error)` - Error classification
|
||||
- `buildPromptWithImages()` - Prompt building with images
|
||||
- `readImageAsBase64()` - Image handling
|
||||
- `extractTextFromContent()` - Message parsing
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 mode
|
||||
- `getSystemPrompt(mode)` - Get system prompt for specific mode
|
||||
- `getExamples(mode)` - Get few-shot examples for a mode
|
||||
- `buildUserPrompt(description, mode)` - Build user prompt with examples
|
||||
- `isValidEnhancementMode(mode)` - Check if mode is valid
|
||||
- `IMPROVE_SYSTEM_PROMPT` - System prompt for improving vague descriptions
|
||||
- `TECHNICAL_SYSTEM_PROMPT` - System prompt for adding technical details
|
||||
- `SIMPLIFY_SYSTEM_PROMPT` - System prompt for simplifying verbose text
|
||||
- `ACCEPTANCE_SYSTEM_PROMPT` - System prompt for adding acceptance criteria
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 tasks
|
||||
- `technical` - Add implementation details and technical specifications
|
||||
- `simplify` - Make verbose descriptions concise and focused
|
||||
- `acceptance` - 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 directory
|
||||
- `getFeaturesDir(projectPath)` - Get features directory
|
||||
- `getFeatureDir(projectPath, featureId)` - Get specific feature directory
|
||||
- `ensureAutomakerDir(projectPath)` - Create .automaker if needed
|
||||
- `spawnJSONLProcess()` - Spawn process with JSONL output
|
||||
- `initAllowedPaths()` - Security path validation
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 ID
|
||||
- `DEFAULT_MODELS` - Access default models
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 priority
|
||||
- `areDependenciesSatisfied(feature, allFeatures)` - Check if ready to execute
|
||||
- `getBlockingDependencies(feature, allFeatures)` - Get incomplete dependencies
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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 repository
|
||||
- `parseGitStatus(output)` - Parse `git status --porcelain` output
|
||||
- `getGitRepositoryDiffs(path)` - Get complete diffs (tracked + untracked)
|
||||
- `generateSyntheticDiffForNewFile()` - Create diff for untracked file
|
||||
- `listAllFilesInDirectory()` - List files excluding build artifacts
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
// 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
|
||||
|
||||
```typescript
|
||||
// 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 `Feature` imports use `@automaker/types`
|
||||
- [ ] All `ExecuteOptions` imports 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-loader` for 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:
|
||||
|
||||
```bash
|
||||
# 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 `.js` extensions in import statements
|
||||
- Compatible with both Node.js (server) and Vite (UI)
|
||||
- Centralized ESM configuration in `libs/tsconfig.base.json`
|
||||
|
||||
## Testing
|
||||
|
||||
When writing tests:
|
||||
|
||||
```typescript
|
||||
// ✅ 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.
|
||||
Reference in New Issue
Block a user