File size: 8,322 Bytes
92c4ae6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
"""
Atom CLI - Init command for Personal Edition setup.

Creates initial configuration for Personal Edition:
- .env file with Personal defaults (SQLite)
- data/ directory for local storage
- Database initialization
- First run wizard
"""

import os
import sys
import click
import logging
from pathlib import Path
from datetime import datetime

# Add backend to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

logger = logging.getLogger(__name__)


@click.command()
@click.option('--force', is_flag=True, help='Overwrite existing configuration')
@click.option('--edition', type=click.Choice(['personal', 'enterprise']), default='personal',
              help='Edition to initialize (default: personal)')
@click.option('--database-url', help='Custom database URL (default: SQLite for personal)')
@click.option('--no-input', is_flag=True, help='Run non-interactively')
def init(force: bool, edition: str, database_url: str, no_input: bool):
    """
    Initialize Atom Personal Edition configuration.

    Creates .env file with Personal Edition defaults:
    - SQLite database (./data/atom.db)
    - Local filesystem storage
    - Minimal feature set

    **Examples:**
        atom init                          # Interactive setup
        atom init --edition personal        # Personal Edition
        atom init --edition enterprise      # Enterprise Edition
        atom init --force                  # Overwrite existing
        atom init --no-input               # Use all defaults

    **Enterprise Edition:**
        atom init --edition enterprise \\
            --database-url "postgresql://user:pass@localhost/atom"
    """
    click.echo(click.style("Atom Initialization", bold=True))
    click.echo("=" * 50)

    # Check if already initialized
    env_file = Path(".env")
    if env_file.exists() and not force:
        click.echo(click.style("Configuration already exists!", fg="yellow"))
        click.echo("Use --force to overwrite")

        # Show current status
        from core.package_feature_service import get_package_feature_service
        service = get_package_feature_service()

        click.echo("")
        click.echo(f"Current Edition: {service.edition.value}")
        click.echo(f"Database: {os.getenv('DATABASE_URL', 'Not configured')}")

        raise SystemExit(1)

    # Edition-specific defaults
    if edition == "personal":
        _init_personal_edition(database_url, no_input)
    else:
        _init_enterprise_edition(database_url, no_input, force)

    # Success message
    click.echo("")
    click.echo(click.style("Initialization complete!", fg="green", bold=True))
    click.echo("")
    click.echo("Next steps:")
    click.echo("  1. Edit .env and add your API keys:")
    click.echo("     OPENAI_API_KEY=sk-...")
    click.echo("     ANTHROPIC_API_KEY=sk-ant-...")
    click.echo("")
    click.echo("  2. Start Atom:")
    click.echo("     atom start")
    click.echo("")
    click.echo(f"  3. Open dashboard:")
    click.echo("     http://localhost:8000")


def _init_personal_edition(database_url: str, no_input: bool) -> None:
    """Initialize Personal Edition configuration."""
    click.echo("")
    click.echo(click.style("Setting up Personal Edition...", fg="blue"))

    # Create data directory
    data_dir = Path("data")
    data_dir.mkdir(exist_ok=True)
    click.echo(f"  Created data directory: {data_dir}")

    # Generate encryption keys
    import secrets
    encryption_key = secrets.token_urlsafe(32)
    jwt_secret = secrets.token_urlsafe(32)

    # Set Personal Edition defaults
    env_content = f"""# Atom Personal Edition Configuration
# Generated: {datetime.now().isoformat()}

# Edition
ATOM_EDITION=personal

# Server
PORT=8000
HOST=0.0.0.0
WORKERS=1

# Database (SQLite - Personal Edition default)
DATABASE_URL=sqlite:///./data/atom.db

# Encryption Keys (auto-generated)
BYOK_ENCRYPTION_KEY={encryption_key}
JWT_SECRET_KEY={jwt_secret}

# LLM Providers (add your keys)
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
DEEPSEEK_API_KEY=

# Vector Embeddings (local - Personal Edition)
EMBEDDING_PROVIDER=fastembed
FASTEMBED_MODEL=BAAI/bge-small-en-v1.5
LANCEDB_PATH=./data/lancedb

# Agent Governance
AGENT_MATURITY_DEFAULT=STUDENT
MAX_CONCURRENT_AGENTS=3

# Logging
LOG_LEVEL=INFO
STRUCTLOG_LEVEL=INFO

# Feature Flags (Personal Edition)
ATOM_MULTI_USER_ENABLED=false
ATOM_MONITORING_ENABLED=false
ATOM_SSO_ENABLED=false
"""

    # Use custom database URL if provided
    if database_url:
        env_content = env_content.replace(
            "DATABASE_URL=sqlite:///./data/atom.db",
            f"DATABASE_URL={database_url}"
        )

    # Write .env file
    env_file = Path(".env")
    env_file.write_text(env_content)
    click.echo(f"  Created .env file (Personal Edition)")

    # Create subdirectories
    (data_dir / "lancedb").mkdir(exist_ok=True)
    (data_dir / "uploads").mkdir(exist_ok=True)
    click.echo(f"  Created storage directories")

    # Show database info
    db_url = database_url or "sqlite:///./data/atom.db"
    click.echo(f"  Database: {db_url}")


def _init_enterprise_edition(database_url: str, no_input: bool, force: bool) -> None:
    """Initialize Enterprise Edition configuration."""
    click.echo("")
    click.echo(click.style("Setting up Enterprise Edition...", fg="blue"))

    # Prompt for database URL if not provided
    if not database_url and not no_input:
        click.echo("")
        click.echo("Enterprise Edition requires PostgreSQL.")
        database_url = click.prompt(
            "Enter PostgreSQL database URL",
            default="postgresql://atom:atom@localhost:5432/atom"
        )

    if not database_url:
        click.echo(click.style("Error: Database URL required for Enterprise", fg="red"), err=True)
        raise SystemExit(1)

    # Create data directory
    data_dir = Path("data")
    data_dir.mkdir(exist_ok=True)
    click.echo(f"  Created data directory: {data_dir}")

    # Generate encryption keys
    import secrets
    encryption_key = secrets.token_urlsafe(32)
    jwt_secret = secrets.token_urlsafe(32)

    # Set Enterprise Edition defaults
    env_content = f"""# Atom Enterprise Edition Configuration
# Generated: {datetime.now().isoformat()}

# Edition
ATOM_EDITION=enterprise

# Server
PORT=8000
HOST=0.0.0.0
WORKERS=4

# Database (PostgreSQL - Enterprise Edition required)
DATABASE_URL={database_url}

# Encryption Keys (auto-generated)
BYOK_ENCRYPTION_KEY={encryption_key}
JWT_SECRET_KEY={jwt_secret}

# LLM Providers
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
DEEPSEEK_API_KEY=

# Vector Embeddings (OpenAI for Enterprise)
EMBEDDING_PROVIDER=openai
OPENAI_EMBEDDING_MODEL=text-embedding-3-small
LANCEDB_PATH=./data/lancedb

# Agent Governance
AGENT_MATURITY_DEFAULT=STUDENT
MAX_CONCURRENT_AGENTS=10

# Multi-User (Enterprise)
ATOM_MULTI_USER_ENABLED=true
ATOM_WORKSPACE_ISOLATION=true

# SSO (Enterprise)
ATOM_SSO_ENABLED=false
# SSO_PROVIDER=okta|auth0|saml
# OKTA_DOMAIN=
# OKTA_CLIENT_ID=
# AUTH0_DOMAIN=
# AUTH0_CLIENT_ID=

# Monitoring (Enterprise)
ATOM_MONITORING_ENABLED=true
PROMETHEUS_ENABLED=true
PROMETHEUS_PORT=9090

# Logging
LOG_LEVEL=INFO
STRUCTLOG_LEVEL=INFO
STRUCTLOG_JSON=true

# Redis (Enterprise - for multi-user pub/sub)
REDIS_URL=redis://localhost:6379/0

# Audit Trail (Enterprise)
ATOM_AUDIT_TRAIL_ENABLED=true
AUDIT_LOG_RETENTION_DAYS=90

# Rate Limiting (Enterprise)
ATOM_RATE_LIMITING_ENABLED=true
RATE_LIMIT_PER_MINUTE=60
"""

    # Write .env file
    env_file = Path(".env")
    env_file.write_text(env_content)
    click.echo(f"  Created .env file (Enterprise Edition)")

    # Create subdirectories
    (data_dir / "lancedb").mkdir(exist_ok=True)
    (data_dir / "uploads").mkdir(exist_ok=True)
    (data_dir / "audit").mkdir(exist_ok=True)
    click.echo(f"  Created storage directories")

    # Warning about PostgreSQL
    click.echo("")
    click.echo(click.style("PostgreSQL Setup Required:", fg="yellow"))
    click.echo("  1. Ensure PostgreSQL is installed and running")
    click.echo("  2. Create database: createdb atom")
    click.echo("  3. Or use connection string to existing database")
    click.echo("")
    click.echo("Current DATABASE_URL:")
    click.echo(f"  {database_url}")


def register_init_command(cli_group):
    """Register init command with CLI group."""
    cli_group.add_command(init)