oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
786 lines (623 loc) • 19.9 kB
Markdown
title: npx oneie agent - Safety & Compatibility System
type: plan
status: draft
created: 2025-01-08
tags:
- cli
- safety
- compatibility
- backup
- conflict-resolution
# npx oneie agent - Safety & Compatibility System
## Core Principle
**Never destroy user data. Always have an undo path.**
When installing ONE into existing projects, we must:
1. Detect what's already there
2. Backup before any changes
3. Choose safe installation strategy
4. Make everything reversible
5. Communicate clearly what happened
## Project Detection Matrix
### Detection Strategy
Run these checks in order:
```typescript
interface ProjectDetection {
isEmpty: boolean; // No files except .git
hasPackageJson: boolean; // Has package.json
framework: Framework; // What framework detected
hasONE: boolean; // ONE already installed
hasEnv: boolean; // Has .env files
hasClaude: boolean; // Has CLAUDE.md or .claude/
conflicts: string[]; // List of conflicting files
compatibilityLevel: 'perfect' | 'compatible' | 'conflict' | 'incompatible';
}
type Framework =
| 'none' // Empty directory
| 'astro' // Astro project (compatible!)
| 'nextjs' // Next.js (incompatible)
| 'react' // Create React App (incompatible)
| 'vue' // Vue (incompatible)
| 'svelte' // SvelteKit (incompatible)
| 'remix' // Remix (incompatible)
| 'nuxt' // Nuxt (incompatible)
| 'one' // ONE Platform (upgrade)
| 'unknown'; // Has package.json but unknown framework
```
### Framework Detection Logic
```typescript
async function detectFramework(): Promise<Framework> {
if (!fs.existsSync('package.json')) {
return 'none';
}
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
// Check for ONE Platform
if (pkg.name === 'oneie' || pkg.dependencies?.['@one/platform']) {
return 'one';
}
// Check dependencies and devDependencies
const allDeps = {
...pkg.dependencies,
...pkg.devDependencies,
};
// Priority order (most specific first)
if (allDeps.astro) return 'astro';
if (allDeps.next) return 'nextjs';
if (allDeps['@remix-run/react']) return 'remix';
if (allDeps['@sveltejs/kit']) return 'svelte';
if (allDeps.nuxt) return 'nuxt';
if (allDeps.vue) return 'vue';
if (allDeps['react-scripts']) return 'react';
return 'unknown';
}
```
## Compatibility Matrix
| Scenario | Framework | Strategy | Reason |
|----------|-----------|----------|--------|
| Empty directory | `none` | **Fresh Install** | No conflicts, perfect |
| Astro project | `astro` | **Merge Install** | Compatible architecture |
| ONE project | `one` | **Upgrade Install** | Update existing |
| Next.js project | `nextjs` | **Subfolder Install** | Different routing |
| React/Vue/Svelte | `react`/`vue`/`svelte` | **Subfolder Install** | Incompatible |
| Unknown project | `unknown` | **Subfolder Install** | Play it safe |
## Installation Strategies
### 1. Fresh Install (Empty Directory)
**When:** No package.json, no source files
**Action:**
```bash
# Install everything normally
./
├── web/ # Full Astro frontend
├── backend/ # Convex backend
├── one/ # Documentation
├── .claude/ # Claude Code config
├── CLAUDE.md # Root instructions
├── package.json # Root package file
└── .env # Environment variables
```
**Risk:** None - directory is empty
### 2. Merge Install (Astro Project)
**When:** Existing Astro project detected
**Action:**
```bash
# Backup first
.one-backups/
└── 2025-01-08T10-30-00/
├── package.json
├── .env
├── CLAUDE.md (if exists)
└── astro.config.mjs
# Then merge
./
├── src/
│ ├── pages/ # Keep existing + add ONE pages
│ ├── components/ # Keep existing + add ONE components
│ └── content/ # Keep existing + add ONE collections
├── one/ # Add documentation
├── backend/ # Add Convex backend
├── .claude/ # Add Claude config (or merge if exists)
├── CLAUDE.md # Add or merge
└── package.json # Merge dependencies
```
**Strategy:**
1. Backup all files that will change
2. Merge package.json dependencies (don't replace)
3. Add ONE-specific files to existing structure
4. Preserve existing pages and components
5. Add ONE documentation to /one folder
6. Merge or create .env files (never overwrite)
7. Update astro.config.mjs carefully
**Risk:** Medium - must preserve existing work
### 3. Subfolder Install (Incompatible Framework)
**When:** Next.js, React, Vue, Svelte, or unknown project
**Action:**
```bash
# Install in subfolder
./
├── [existing project files]
├── package.json # Original project
└── one-platform/ # ONE installed here
├── web/
├── backend/
├── one/
├── .claude/
├── CLAUDE.md
└── package.json
```
**Strategy:**
1. No backup needed (no files modified)
2. Ask for subfolder name (default: `one-platform`)
3. Install complete ONE structure in subfolder
4. Completely isolated from main project
5. Suggest: "Your ONE Platform is in ./one-platform/"
**Risk:** None - completely isolated
### 4. Upgrade Install (ONE Already Exists)
**When:** ONE Platform already detected
**Action:**
```bash
# Backup existing customizations
.one-backups/
└── 2025-01-08T10-30-00/
├── one/ # User's docs
├── .claude/ # User's agents
├── CLAUDE.md # User's instructions
└── [installation-folder]/ # User's customizations
# Then upgrade
- Update core files (web/, backend/, one/ templates)
- Preserve user customizations
- Merge new features
- Update dependencies
```
**Strategy:**
1. Detect existing ONE version
2. Backup all user customizations
3. Update core ONE files
4. Preserve installation folders
5. Merge new features from latest version
6. Show upgrade report
**Risk:** Low - existing ONE user, knows the system
## Backup System
### Backup Directory Structure
```bash
.one-backups/
├── 2025-01-08T10-30-00/ # Timestamp format
│ ├── metadata.json # What was backed up and why
│ ├── package.json
│ ├── .env
│ ├── .env.local
│ ├── CLAUDE.md
│ ├── .claude/
│ └── [any other conflicts]
└── 2025-01-08T11-45-00/ # Next backup
└── ...
```
### Backup Metadata
```json
{
"timestamp": "2025-01-08T10:30:00Z",
"reason": "merge-install",
"framework": "astro",
"backedUpFiles": [
"package.json",
".env",
"CLAUDE.md",
".claude/commands/custom.md"
],
"installationStrategy": "merge",
"canRestore": true,
"restoreCommand": "npx oneie restore 2025-01-08T10-30-00"
}
```
### Restore Command
```bash
# List available backups
npx oneie restore --list
# Restore specific backup
npx oneie restore 2025-01-08T10-30-00
# Interactive restore (choose what to restore)
npx oneie restore --interactive
```
## File Conflict Resolution
### Protected Files (Never Overwrite Without Backup)
**Critical files:**
- `.env`, `.env.local`, `.env.production`
- `CLAUDE.md`
- `.claude/` directory
- `package.json`, `package-lock.json`
- `tsconfig.json`
- `astro.config.mjs`
**User content:**
- `src/pages/*` (except ONE-specific)
- `src/components/*` (except ONE-specific)
- `src/content/*` (except ONE-specific)
- Installation folders (e.g., `/acme`)
### Merge Strategy for Common Files
#### package.json
```typescript
function mergePackageJson(existing: any, oneTemplate: any): any {
return {
...existing,
// Preserve user's name, version, etc.
name: existing.name,
version: existing.version,
description: existing.description || oneTemplate.description,
// Merge scripts (ONE scripts prefixed)
scripts: {
...existing.scripts,
'one:dev': oneTemplate.scripts.dev,
'one:build': oneTemplate.scripts.build,
'one:preview': oneTemplate.scripts.preview,
},
// Merge dependencies (ONE + existing)
dependencies: {
...existing.dependencies,
...oneTemplate.dependencies,
},
// Merge devDependencies
devDependencies: {
...existing.devDependencies,
...oneTemplate.devDependencies,
},
};
}
```
#### .env files
```typescript
function mergeEnvFile(existing: string, oneTemplate: string): string {
const existingVars = parseEnv(existing);
const oneVars = parseEnv(oneTemplate);
// Never overwrite existing variables
const merged = { ...oneVars, ...existingVars };
// Add comment for new ONE variables
let result = '# Existing environment variables\n';
result += formatEnv(existingVars);
result += '\n\n# ONE Platform variables\n';
result += formatEnv(oneVars);
return result;
}
```
#### CLAUDE.md
```typescript
function mergeClaude(existing: string, oneTemplate: string): string {
// Keep existing at top (user's customizations)
// Add ONE platform instructions at bottom
return `${existing}
# ONE Platform Instructions (Auto-generated)
${oneTemplate}
**Note:** Your custom instructions above take precedence over ONE defaults.
`;
}
```
## Safety Checks Before Installation
### Pre-flight Checks
```typescript
interface SafetyCheck {
name: string;
passed: boolean;
severity: 'error' | 'warning' | 'info';
message: string;
canContinue: boolean;
}
async function runSafetyChecks(): Promise<SafetyCheck[]> {
return [
// Critical checks (must pass)
{
name: 'git-initialized',
passed: await hasGit(),
severity: 'error',
message: 'Git repository not initialized. Run: git init',
canContinue: false,
},
{
name: 'git-clean',
passed: await isGitClean(),
severity: 'warning',
message: 'Uncommitted changes detected. Commit first for safety.',
canContinue: true,
},
{
name: 'node-version',
passed: await checkNodeVersion('>=18.0.0'),
severity: 'error',
message: 'Node.js 18+ required',
canContinue: false,
},
// Compatibility checks
{
name: 'framework-compatible',
passed: await isFrameworkCompatible(),
severity: 'warning',
message: 'Incompatible framework detected. Will install in subfolder.',
canContinue: true,
},
{
name: 'disk-space',
passed: await hasDiskSpace(500), // 500MB required
severity: 'error',
message: 'Insufficient disk space',
canContinue: false,
},
// Backup checks
{
name: 'can-backup',
passed: await canCreateBackup(),
severity: 'error',
message: 'Cannot create backup directory',
canContinue: false,
},
];
}
```
## Agent Command with Safety
### Enhanced Command Flags
```bash
# Safety flags
npx oneie agent --dry-run # Show plan without executing
npx oneie agent --backup-only # Just backup, don't install
npx oneie agent --force # Skip safety checks (dangerous!)
npx oneie agent --no-backup # Skip backup (not recommended)
npx oneie agent --subfolder="custom" # Force subfolder install
# Compatibility flags
npx oneie agent --merge # Force merge strategy
npx oneie agent --isolated # Force subfolder strategy
npx oneie agent --upgrade # Force upgrade strategy
# Recovery flags
npx oneie agent --restore="timestamp" # Restore from backup
npx oneie agent --undo # Undo last install
```
### Execution Flow with Safety
```typescript
async function agentInstall(options: AgentOptions) {
// 1. Detect existing project
const detection = await detectProject();
console.log('🔍 Detected:', detection.framework);
// 2. Run safety checks
const checks = await runSafetyChecks();
const errors = checks.filter(c => !c.passed && !c.canContinue);
if (errors.length > 0) {
console.log('❌ Safety checks failed:');
errors.forEach(e => console.log(` - ${e.message}`));
return { success: false, errors };
}
// 3. Choose installation strategy
const strategy = chooseStrategy(detection);
console.log('📋 Strategy:', strategy);
// 4. Show what will happen (if verbose)
if (options.verbose || options.dryRun) {
await showInstallationPlan(detection, strategy);
}
if (options.dryRun) {
console.log('\n✓ Dry run complete (no changes made)');
return { success: true, dryRun: true };
}
// 5. Create backup (unless --no-backup)
if (!options.noBackup && detection.hasConflicts) {
const backup = await createBackup(detection);
console.log('💾 Backup created:', backup.timestamp);
console.log(' Restore with: npx oneie restore', backup.timestamp);
}
// 6. Execute installation
const result = await executeStrategy(strategy, detection, options);
// 7. Verify installation
const verification = await verifyInstallation();
if (verification.success) {
console.log('✓ Installation verified');
return { success: true, ...result };
} else {
console.log('⚠️ Installation completed with warnings');
return { success: false, warnings: verification.warnings };
}
}
```
## Strategy Decision Logic
```typescript
function chooseStrategy(detection: ProjectDetection): InstallStrategy {
// Empty directory - perfect!
if (detection.isEmpty) {
return 'fresh';
}
// ONE already installed - upgrade
if (detection.framework === 'one') {
return 'upgrade';
}
// Astro project - compatible, can merge
if (detection.framework === 'astro' && !detection.hasConflicts) {
return 'merge';
}
// Astro with conflicts - ask user
if (detection.framework === 'astro' && detection.hasConflicts) {
// In agent mode, default to subfolder (safest)
return 'subfolder';
}
// Any other framework - subfolder for safety
if (detection.framework !== 'none') {
return 'subfolder';
}
// Unknown situation - play it safe
return 'subfolder';
}
```
## Output Examples
### Success: Fresh Install
```bash
$ npx oneie agent
🔍 Detected: Empty directory
📋 Strategy: Fresh installation
💾 No backup needed (directory empty)
✓ Created project structure
✓ Installed dependencies (23 packages)
✓ Generated environment files
✓ Your ONE Platform is ready!
Next steps:
/one # Show control center
bun run dev # Start development
```
### Success: Merge Install
```bash
$ npx oneie agent
🔍 Detected: Astro project
📋 Strategy: Merge installation
💾 Backup created: 2025-01-08T10-30-00
Restore with: npx oneie restore 2025-01-08T10-30-00
✓ Backed up 4 files
✓ Merged package.json (added 8 dependencies)
✓ Merged .env (preserved existing variables)
✓ Added ONE documentation to /one
✓ Added backend to /backend
✓ Added Claude config to /.claude
⚠️ Your existing pages preserved in:
src/pages/index.astro
src/pages/about.astro
✓ Installation complete!
Next steps:
/one # See ONE commands
bun run dev # Your existing dev script
bun run one:dev # ONE-specific dev script
```
### Success: Subfolder Install
```bash
$ npx oneie agent
🔍 Detected: Next.js project
📋 Strategy: Subfolder installation
💾 No backup needed (isolated install)
⚠️ Next.js and ONE use different routing systems.
Installing ONE in subfolder: ./one-platform
✓ Created ./one-platform
✓ Installed ONE Platform
✓ Completely isolated from your Next.js project
✓ Installation complete!
Your projects:
./ Next.js project (unchanged)
./one-platform ONE Platform (new)
Next steps:
cd one-platform
/one # Start using ONE
```
### Success: Upgrade Install
```bash
$ npx oneie agent
🔍 Detected: ONE Platform (v1.0.0)
📋 Strategy: Upgrade to v1.1.0
💾 Backup created: 2025-01-08T10-30-00
Your customizations backed up
✓ Backed up user customizations
✓ Updated core files
✓ Preserved installation folder: /acme
✓ Preserved custom agents: /.claude/agents/custom-agent.md
✓ Updated dependencies
✓ Merged new features
✓ Upgrade complete!
What's new in v1.1.0:
- New agent: agent-problem-solver
- Enhanced cycle workflow
- Improved documentation
Next steps:
/one # See updated commands
```
### Error: Safety Check Failed
```bash
$ npx oneie agent
🔍 Detected: React project
❌ Safety checks failed:
- Git repository not initialized. Run: git init
- Node.js 18+ required (found: v16.14.0)
Cannot continue installation.
Fix these issues first:
git init
nvm install 18
nvm use 18
Then run: npx oneie agent
```
## Restore Functionality
### List Backups
```bash
$ npx oneie restore --list
Available backups:
1. 2025-01-08T10-30-00 (2 hours ago)
- Reason: merge-install
- Files: package.json, .env, CLAUDE.md
- Size: 15 KB
2. 2025-01-08T08-15-00 (4 hours ago)
- Reason: upgrade-install
- Files: package.json, .claude/
- Size: 42 KB
Restore with: npx oneie restore <timestamp>
```
### Restore Backup
```bash
$ npx oneie restore 2025-01-08T10-30-00
🔍 Backup found: 2025-01-08T10-30-00
📋 Will restore 3 files:
- package.json
- .env
- CLAUDE.md
⚠️ Current files will be backed up first
Continue? (y/n): y
💾 Created safety backup: 2025-01-08T12-45-00
✓ Restored package.json
✓ Restored .env
✓ Restored CLAUDE.md
✓ Restore complete!
Tip: If something went wrong, restore the safety backup:
npx oneie restore 2025-01-08T12-45-00
```
## Testing Matrix
| Test Case | Framework | Has Files | Expected Strategy | Expected Outcome |
|-----------|-----------|-----------|-------------------|------------------|
| Empty dir | none | No | fresh | Full install |
| New Astro | astro | Yes | merge | Merge success |
| Astro + conflicts | astro | Yes | subfolder | Isolated install |
| Next.js | nextjs | Yes | subfolder | Isolated install |
| ONE v1.0 | one | Yes | upgrade | Upgrade success |
| Unknown | unknown | Yes | subfolder | Isolated install |
| No git | any | Any | error | Exit with error |
| No space | any | Any | error | Exit with error |
## Implementation Checklist
### Phase 1: Detection
- [ ] Implement `detectProject()`
- [ ] Implement `detectFramework()`
- [ ] Implement conflict detection
- [ ] Test with all framework types
### Phase 2: Safety System
- [ ] Implement backup system
- [ ] Implement restore command
- [ ] Implement safety checks
- [ ] Test backup/restore flow
### Phase 3: Strategies
- [ ] Implement fresh install
- [ ] Implement merge install
- [ ] Implement subfolder install
- [ ] Implement upgrade install
### Phase 4: Merge Logic
- [ ] Implement package.json merge
- [ ] Implement .env merge
- [ ] Implement CLAUDE.md merge
- [ ] Implement config file merge
### Phase 5: Testing
- [ ] Test all scenarios in matrix
- [ ] Test restore functionality
- [ ] Test error handling
- [ ] Test agent integration
## Summary
**Key Safety Features:**
1. ✅ **Never overwrites** without backup
2. ✅ **Smart detection** of existing projects
3. ✅ **Safe strategies** for each scenario
4. ✅ **Full restore** capability
5. ✅ **Clear communication** of what happens
6. ✅ **Reversible** operations
7. ✅ **Idempotent** (safe to run multiple times)
**Result:** Agents can confidently run `npx oneie agent` knowing it will:
- Detect the situation
- Choose the safest strategy
- Backup everything important
- Install without destroying work
- Provide clear next steps
**Philosophy:** "Make it safe first, then make it automatic."
**Status:** Ready for implementation
**Dependencies:** npx-agent.md (base command design)
**Estimated Completion:** 2 weeks (includes comprehensive testing)