diff --git a/README.md b/README.md
index 74e6388..05f363a 100644
--- a/README.md
+++ b/README.md
@@ -3,468 +3,216 @@
-
Squadron
-
-
- Autonomous Agent Orchestration for your local machine.
-
- Explore the docs »
-
-
- Report Bug
- ·
- Request Feature
+
Squadron
+
+
+ The AI Agent Command Center for Your Desktop
+
+
+
+ Run Claude, Gemini, Codex, and more — all in one native app.
+ 6 terminals. Any AI Provider. Complete control.
+
+
+
+
+
+ ⬇️ Download Now
+ •
+ Features
+ •
+ Quick Start
+ •
+ Architecture
-
+
+
-
-
-
-
-
-
- Quick Start •
- Dashboard •
- Commands •
- Architecture •
- Skills •
- Testing •
- Roadmap
+
---
-## 🔥 New in v0.5.1
+## 🔥 What's New in v2.0
| Feature | Description |
|:---|:---|
-| **🧪 Comprehensive Test Suite** | Full pytest coverage with mocked dependencies |
-| **🔄 GitHub Actions CI/CD** | Automated testing on Python 3.10, 3.11, 3.12 |
-| **🐛 Bug Fixes** | Resolved merge conflicts and duplicate dependencies |
-| **📊 README Badges** | Tests, Coverage, Downloads, Last Commit, Issues |
-
----
-
-
-
-
-
-## ⚡ Install
-
-```bash
-pip install squadron-agents
-```
-
-That's it. You're ready.
+| **🖥️ Native Desktop App** | Download and run — no terminal required |
+| **🤖 Multi-Provider Support** | Claude, Gemini, Codex, OpenCode, Cursor |
+| **📺 6-Terminal Grid** | Run 6 AI agents simultaneously |
+| **🔐 Secure API Keys** | Encrypted storage with OS-level security |
+| **🌳 Git Worktrees** | Safe parallel execution per task |
+| **📋 Kanban Board** | Drag-and-drop task management |
+| **🚀 Onboarding Wizard** | Get started in under a minute |
---
-## 🎮 Squadron Desktop (v2.0)
-
-Squadron is evolving into a native **Desktop Application**.
-The web-based Control Plane is being deprecated in favor of a high-performance Electron + React application.
-
-### Roadmap for v2.0
-- **Native Experience**: One-click installer (no terminal required).
-- **Kanban Board**: Drag-and-drop task management.
-- **Agent Terminals**: Watch your agents work in real-time.
-- **Git Worktrees**: Safety and parallelism for agent tasks.
-
-> _Work in Progress: The new desktop app is currently under active development._
-
----
-
-## 🐝 Swarm 2.0 — Multi-Agent Orchestration
-
-Squadron's Swarm system enables intelligent, autonomous agent coordination.
-
-
-
-> **Screenshot needed:** Dashboard showing a task being routed from user → Overseer → Agent
-
-### Key Features
-
-- **🧠 LLM-Powered Routing** — Gemini decides which agent handles each task
-- **🤝 Agent Handoffs** — Agents can delegate tasks to each other with context
-- **📋 Task Queue** — Priority-based task management
-- **🔗 Delegation Chain** — Full tracking of task ownership
-
-```python
-# Example: Intelligent task routing
-from squadron.swarm import route_task
-
-result = route_task("Analyze the API performance and deploy the fix")
-# Swarm routes to the best agent for each subtask
-```
-
----
-
-## 💬 Agent Communication
-
-Agents can now communicate with each other through your ticket system.
-
-
-
-> **Screenshot needed:** Jira/Linear ticket with agent comments showing @mentions
+## ⬇️ Download
-### Features
+Download the latest release for your platform:
-- **@Mention Support** — Tag agents in ticket comments to request help
-- **`reply_to_ticket()`** — Agents post updates directly on tickets
-- **`tag_agent()`** — Request help from specific agents
-- **Auto-Wake** — Overseer wakes agents when tickets are assigned
+| Platform | Download | Architecture |
+|----------|----------|--------------|
+| **Windows** | [Squadron-Setup.exe](https://github.com/MikeeBuilds/Squadron/releases/latest) | x64 |
+| **macOS** | [Squadron.dmg](https://github.com/MikeeBuilds/Squadron/releases/latest) | Intel & Apple Silicon |
+| **Linux** | [Squadron.AppImage](https://github.com/MikeeBuilds/Squadron/releases/latest) | x64 |
-```bash
-# Overseer monitors and auto-wakes agents
-squadron overseer --auto-wake
-
-# Example ticket comment that triggers an agent:
-# "@YourAgent please review the authentication changes"
-```
+> **Windows users**: You may see a SmartScreen warning. Click "More info" → "Run anyway". We're working on code signing.
---
-## 🧠 Persistent Memory (Hippocampus)
-
-Agents now have long-term memory powered by ChromaDB semantic search.
-
-
-
-> **Screenshot needed:** Console showing agent recalling relevant past conversations
-
-### Memory Types
-
-| Type | Description |
-|------|-------------|
-| **Conversation** | Past chat history with context |
-| **Task** | Completed tasks and their outcomes |
-| **Learning** | Insights and knowledge gained |
-| **General** | Miscellaneous memories |
-
-### API
-
-```python
-from squadron.memory import remember, recall, get_context_for_task
+## ✨ Features
-# Store a memory
-remember("User prefers TypeScript over JavaScript", agent="Atlas")
+### 🤖 Multi-Provider AI Terminal
-# Recall relevant memories
-memories = recall("coding preferences", agent="Atlas")
+Run any AI coding assistant directly in Squadron:
-# Get context for a new task
-context = get_context_for_task("Set up the new frontend", agent="Atlas")
-```
-
----
+| Provider | Models | Status |
+|----------|--------|--------|
+| **Claude** | Sonnet 4, Opus 4, Haiku | ✅ Auto-install |
+| **Gemini** | 2.5 Pro, 2.5 Flash | ✅ Auto-install |
+| **OpenAI Codex** | GPT-4o, o1, o3-mini | ✅ Auto-install |
+| **OpenCode** | Multi-model | ✅ Auto-install |
+| **Cursor** | Any model | ✅ Auto-install |
-## 🧬 Evolution Layer
+> **Auto-Install**: CLIs download automatically when you select a provider. No manual setup.
-Squadron agents can evolve and improve their skills over time.
+### 📺 6-Terminal Grid
-
-
-> **Screenshot needed:** Dashboard showing skill registry with versions and quality scores
-
-### Features
+
+
+
-- **Skill Registry** — Track all skills with version history
-- **Quality Scoring** — Success/failure rate tracking
-- **Version Control** — Rollback to previous skill versions
-- **Skill Creation** — Agents can propose new skills
+- **3x2 Grid Layout** — See all agents at once
+- **Per-Terminal Provider** — Run Claude in one, Gemini in another
+- **Task Linking** — Connect terminals to Kanban tasks
+- **Context Injection** — Task details auto-sent to AI
----
+### 📋 Kanban Board
-## ⏰ Wake Protocol
+
+
+
-The Wake Protocol orchestrates autonomous agent execution.
+Visual task management:
+- **Columns**: Backlog → Planning → In Progress → Review → Done
+- **Real-time Updates** via Server-Sent Events
+- **Task Wizard** for quick task creation
+- **Agent Assignment** per task
-
-
-> **Recording needed:** Full flow of Overseer detecting ticket → waking agent → executing → reporting back
+### 🌳 Git Worktree Isolation
-```bash
-# Manually trigger the Wake Protocol
-squadron wake --summary "Deploy the hotfix to production"
+Each agent task gets its own isolated workspace:
-# Auto-wake runs automatically with overseer
-squadron overseer --auto-wake --interval 30
```
-
-### Flow
-
-1. **Trigger** — New ticket detected or manual wake command
-2. **Route** — Swarm selects the best agent for the task
-3. **Execute** — Agent completes the work
-4. **Report** — Results posted back to the ticket
-
----
-
-## 🎬 See It In Action
-
-```bash
-$ squadron report --msg "Refactored the auth module." --ticket "KAN-1"
-
-🚀 Squadron Bridge Activated...
-✅ Slack: Message sent to #general
-✅ Jira: Comment added to KAN-1
+Task Started → .worktrees/task-XXX created → Agent works in isolation
+ ↓
+ Merge or Discard via Dashboard
```
-**One command. Multiple integrations. Zero context switching.**
+**Benefits:**
+- ✅ Agents work in parallel without conflicts
+- ✅ Main branch stays protected
+- ✅ Easy to discard failed work
+- ✅ Each task gets its own branch for review
-
-
-> **Recording needed:** Terminal showing `squadron report`, `squadron broadcast`, and `squadron pr` commands
-
----
-
-## 😤 The Problem
-
-You're building with AI agents. They're powerful. They can write code, refactor systems, and solve complex problems.
-
-But here's the frustrating reality:
-
-| What You Want | What Actually Happens |
-|--------------|----------------------|
-| Agent finishes a task | You don't know unless you check the terminal |
-| Jira ticket should update | It stays in "To Do" forever |
-| Team needs visibility | They have no idea what the AI is building |
-| Agent A needs Agent B's help | They can't communicate |
-| Agent worked on this before | It doesn't remember |
-
-**Your agents are trapped in a chat window.** They can think, but they can't *act* in your team's workflow.
-
----
+### 🔐 Secure Settings
-## ✨ The Solution
-
-Squadron is a **bridge** that connects your local AI agents to your team's real tools.
-
-```
-┌─────────────────┐ ┌─────────────────┐
-│ AI AGENTS │ │ YOUR TEAM │
-│ (Your Agents) │ │ │
-│ │ │ 📋 Jira/Linear │
-│ "Task done!" │────────▶│ 💬 Slack │
-│ │Squadron │ 🔔 Discord │
-│ 🧠 Memory │ Bridge │ 🐙 GitHub │
-│ 🔄 Handoffs │ │ 🎮 Dashboard │
-└─────────────────┘ └─────────────────┘
-```
+
+
+
-**Squadron gives your agents:**
-- 🗣️ **A Voice** — Post updates to Slack/Discord
-- ✋ **Hands** — Update Jira tickets, create GitHub PRs
-- 👀 **Awareness** — Overseer watches for new assignments
-- 🧠 **Memory** — Remember past work and context
-- 🤝 **Collaboration** — Hand off tasks to each other
-- 🎮 **Control** — Real-time dashboard for management
+- **Encrypted at Rest** using OS-level security (Windows DPAPI / macOS Keychain)
+- **11 Integrations**: Slack, Discord, Jira, Linear, GitHub + AI providers
+- **Export to .env** for Python backend
+- **Never Transmitted** — keys stay local
---
## 🚀 Quick Start
-### 1. Install
-
-```bash
-pip install squadron-agents
-```
-
-### 2. Configure
-
-Create a `.env` file in your project root:
-
-```env
-# Required: LLM Provider
-GEMINI_API_KEY=your-gemini-key
-
-# Jira
-JIRA_SERVER=https://your-domain.atlassian.net
-JIRA_EMAIL=your-email@example.com
-JIRA_TOKEN=your-api-token
-
-# Slack
-SLACK_BOT_TOKEN=xoxb-your-bot-token
-
-# Discord (optional)
-DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
-DISCORD_BOT_TOKEN=your-bot-token
-
-# GitHub (optional)
-GITHUB_TOKEN=ghp_your-token
-
-# Linear (optional)
-LINEAR_API_KEY=lin_api_...
-```
-
-### 3. Initialize
-
-```bash
-squadron init
-```
-This creates a `squadron/knowledge/` folder in your project. Customize `TEAM.md` and `ROLES.md` here.
-
-### 4. Learn
-
-```bash
-squadron learn
-```
-This scans your code and builds a map for the agent to use.
-
-### 5. Test
+### 1. Download & Install
-```bash
-squadron report --msg "Hello from Squadron!" --channel "#general"
-```
-
-If you see `✅ Slack: Message sent` — you're live! 🎉
-
----
+Download from [Releases](https://github.com/MikeeBuilds/Squadron/releases/latest) and install for your platform.
-## 📖 Commands
+### 2. Complete Onboarding
-### Core Commands
-
-| Command | Description |
-|---------|-------------|
-| `squadron init` | Initialize Squadron in your project |
-| `squadron learn` | Scan codebase and update knowledge |
-| `squadron server` | Start the Control Plane API |
-| `squadron listen` | Listen for @mentions in Slack |
-| `squadron listen --discord` | Listen for @mentions in Discord |
-| `squadron overseer` | Watch for new ticket assignments |
-| `squadron wake` | Manually trigger the Wake Protocol |
+
+
+
-### Communication Commands
+The wizard guides you through:
+- Choosing your AI provider
+- Entering your API key
+- Selecting your project folder
-| Command | Description |
-|---------|-------------|
-| `squadron report` | Send updates to Slack + update tickets |
-| `squadron broadcast` | Announce to Discord |
-| `squadron pr` | Create GitHub Pull Request |
-| `squadron issue` | Create GitHub Issue |
+### 3. Start Coding
-See [COMMANDS.md](COMMANDS.md) for full documentation.
+- Click the provider dropdown in any terminal
+- Select your AI (Claude, Gemini, etc.)
+- CLI auto-downloads if needed
+- Start prompting!
---
## 🏗️ Architecture
-Squadron uses a **Skill-Based Architecture** inspired by the [Model Context Protocol (MCP)](https://modelcontextprotocol.io).
+Squadron is a **hybrid desktop application**:
```
-squadron/
-├── cli.py # 🎯 The Router (entry point)
-├── server.py # 🎮 Control Plane API
-├── overseer.py # 👀 Background ticket watcher
-├── brain.py # 🧠 Intelligence router (LLM decisions)
-│
-├── swarm/ # 🐝 ORCHESTRATION LAYER
-│ ├── agent.py # Base agent class
-│ ├── delegator.py # Task handoff logic
-│ └── overseer.py # LLM-powered routing
-│
-├── memory/ # 🧠 MEMORY LAYER
-│ └── hippocampus.py # Semantic memory (ChromaDB)
-│
-├── evolution/ # 🧬 EVOLUTION LAYER
-│ ├── skill_registry.py # Skill tracking & versioning
-│ ├── improver.py # Self-improvement engine
-│ └── watcher.py # Performance monitoring
-│
-├── skills/ # 🛠️ ACTION LAYER (The Hands)
-│ ├── jira_bridge/ # Jira API integration
-│ ├── slack_bridge/ # Slack API integration
-│ ├── discord_bridge/ # Discord webhooks + bot
-│ ├── github_bridge/ # GitHub API integration
-│ ├── linear_bridge/ # Linear API integration
-│ ├── ssh_skill/ # Remote command execution
-│ └── browser_skill/ # Web navigation & screenshots
-│
-├── services/ # 🔧 SERVICE LAYER
-│ └── llm/ # LLM providers (Gemini)
-│
-└── knowledge/ # 📚 CONTEXT LAYER (The Brain)
- ├── TEAM.md # Who is on the team?
- ├── WORKFLOW.md # How does work flow?
- └── ROLES.md # What does each agent do?
+┌─────────────────────────────────────────────────────────┐
+│ ELECTRON SHELL │
+│ ┌─────────────────┐ ┌────────────────────────────────┐│
+│ │ React + Vite │ │ Main Process ││
+│ │ ───────────── │ │ ──────────────── ││
+│ │ • 6-Terminal │ │ • PTY Management ││
+│ │ • Kanban UI │◄─┤ • API Key Storage ││
+│ │ • Settings │ │ • CLI Auto-Install ││
+│ │ • Onboarding │ │ • Process Manager ││
+│ └─────────────────┘ └────────────────────────────────┘│
+│ ▲ ▲ │
+│ │ IPC │ Spawn │
+│ ▼ ▼ │
+│ ┌─────────────────────────────────────────────────────┐│
+│ │ TERMINAL SESSIONS (node-pty + xterm.js) ││
+│ └─────────────────────────────────────────────────────┘│
+└─────────────────────────────────────────────────────────┘
+ │
+ │ HTTP API (Port 8000)
+ ▼
+┌─────────────────────────────────────────────────────────┐
+│ PYTHON BACKEND │
+│ • Swarm Orchestration • Git Worktrees │
+│ • Task Queue • Integrations │
+└─────────────────────────────────────────────────────────┘
```
-### Why This Structure?
-
-| Layer | Purpose | Example |
-|-------|---------|---------|
-| **Swarm** | Task routing & handoffs | Route task to best agent |
-| **Memory** | Long-term context | Remember past conversations |
-| **Evolution** | Self-improvement | Track skill performance |
-| **Skills** | Executable actions | `JiraTool.update_ticket()` |
-| **Knowledge** | Context for decisions | "Move to Done only after tests pass" |
-
----
-
-## 🔌 Skills
-
-| Skill | Status | What It Does |
-|-------|--------|--------------|
-| **Jira Bridge** | ✅ Live | Update tickets, add comments, transition status |
-| **Slack Bridge** | ✅ Live | Send formatted messages to channels |
-| **Discord Bridge** | ✅ Live | Broadcast via webhooks & Reply via Bot |
-| **GitHub Bridge** | ✅ Live | Create PRs and Issues |
-| **Linear Bridge** | ✅ Live | Update Linear issues |
-| **Overseer** | ✅ Live | Watch Jira/Linear for new assignments |
-| **SSH Skill** | ✅ Live | Execute remote commands |
-| **Browser Skill** | ✅ Live | Navigate & Screenshot Web |
-
---
-## 📝 Customizing for Your Team
+## 🛠️ Build from Source
-After running `squadron init`, you'll have example templates to customize:
-
-| File | What to Customize |
-|------|-------------------|
-| `squadron/agents.yaml` | Define your agent personas (names, roles, avatars) |
-| `squadron/knowledge/TEAM.md` | Your team members (human and AI) |
-| `squadron/knowledge/ROLES.md` | Agent specializations for task routing |
-| `squadron/knowledge/WORKFLOW.md` | Your team's development process |
-
-The templates include example agents (**Atlas** and **Sage**) — replace them with your own!
+For developers who want to run from source:
```bash
-# Customize your agents
-code squadron/agents.yaml
-code squadron/knowledge/ROLES.md
-```
-
----
-
-## 🤖 Teaching Your Agents
-
-Add this to your agent's system prompt:
+# Clone the repo
+git clone https://github.com/MikeeBuilds/Squadron.git
+cd Squadron/desktop
-```markdown
-## Tool: Squadron
-
-You have access to the `squadron` CLI for team communication.
+# Install dependencies
+npm install
-### When to use:
-- After completing a coding task
-- When you hit a blocker and need help
-- To update ticket status
-- To hand off work to another agent
+# Run in development mode
+npm run electron:dev
-### Commands:
-- Start task: `squadron report --msg "Starting auth work" --ticket "KAN-1" --status "In Progress"`
-- Complete task: `squadron report --msg "Auth complete" --ticket "KAN-1" --status "Done"`
-- Announce: `squadron broadcast --msg "Shipped new feature!"`
-- Hand off: Tag another agent in the ticket comment with @AgentName
+# Build for production
+npm run electron:build
```
---
@@ -473,83 +221,35 @@ You have access to the `squadron` CLI for team communication.
### Completed ✅
-- [x] **Core CLI** — `squadron report` command
-- [x] **Jira Integration** — Comments + status transitions
-- [x] **Slack Integration** — Rich block messages
-- [x] **Discord Integration** — Webhook broadcasts + Bot
-- [x] **GitHub Integration** — PRs and Issues
-- [x] **Linear Integration** — Issue management
-- [x] **Overseer Mode** — Background ticket watcher
-- [x] **PyPI Release** — `pip install squadron-agents`
-- [x] **Control Plane Dashboard** — Real-time web UI
-- [x] **Swarm 2.0** — LLM-powered intelligent routing
-- [x] **Agent Communication** — @mentions and ticket comments
-- [x] **Persistent Memory** — Hippocampus with ChromaDB
-- [x] **Evolution Layer** — Skill versioning and quality tracking
-- [x] **Wake Protocol** — Autonomous agent execution
+- [x] **Native Desktop App** — Electron cross-platform
+- [x] **6-Terminal Grid** — Multi-agent workspace
+- [x] **Multi-Provider Support** — Claude, Gemini, Codex, OpenCode, Cursor
+- [x] **Auto-Install CLIs** — Zero setup for users
+- [x] **Secure API Keys** — Encrypted local storage
+- [x] **Git Worktree Isolation** — Safe parallel execution
+- [x] **Kanban Board** — Visual task management
+- [x] **Task Wizard** — Easy task creation
+- [x] **Onboarding Wizard** — First-launch setup
+- [x] **Integration Settings** — Slack, Discord, Jira, Linear, GitHub
### Coming Soon 🚧
-- [ ] **Active Inference** — Predictive agent behavior
-- [ ] **Hive Mind** — Collective intelligence layer
-- [ ] **Multi-LLM Support** — OpenAI, Anthropic, local models
-- [ ] **Email Notifications** — SMTP integration
-- [ ] **Calendar Integration** — Scheduling and reminders
-
----
-
-## 🌟 The Origin Story
-
-Squadron was born out of necessity.
-
-We're building [BlackCircleTerminal](https://blackcircleterminal.com), a quantitative trading platform managed by AI agents. Our virtual developers — **Marcus** (Strategy) and **Caleb** (Data) — needed a way to communicate with us when we weren't at the keyboard.
-
-We realized that for agents to be truly useful, they need to be part of the **workflow**, not just the **code editor**.
-
-Squadron is the nervous system that connects our AI workforce to our human tools.
-
----
-
-## 🧪 Testing
-
-Squadron has a comprehensive test suite with mocked dependencies for fast, reliable tests.
-
-```bash
-# Install dependencies
-pip install -r requirements.txt
-pip install -e .
-
-# Run all tests
-python -m pytest tests/ -v
-
-# Run with coverage
-python -m pytest tests/ --cov=squadron --cov-report=html
-
-# Run only unit tests (fast)
-python -m pytest tests/unit/ -v
-
-# Run integration tests
-python -m pytest tests/integration/ -v
-```
-
-Tests run automatically on push/PR via GitHub Actions. See `tests/README.md` for details on fixtures and writing new tests.
+- [ ] **AI Merge Resolution** — Automatic conflict resolution
+- [ ] **Insights Panel** — ChatGPT-style project Q&A
+- [ ] **Changelog Generator** — Auto-generate from tasks
+- [ ] **Auto-Updates** — In-app updates
---
## 🤝 Contributing
-We're building the future of **Agent-First Development**. Want to add a new skill?
+We welcome contributions!
1. Fork the repo
-2. Create a skill in `squadron/skills/your_skill/`
-3. Add `tool.py` (logic) and `SKILL.md` (instructions)
-4. Open a PR!
-
-**Ideas for new skills:**
-- Trello / Asana integrations
-- Email notifications
-- CI/CD triggers
-- Calendar scheduling
+2. Create a feature branch: `git checkout -b feature/amazing-feature`
+3. Commit your changes: `git commit -m 'Add amazing feature'`
+4. Push to the branch: `git push origin feature/amazing-feature`
+5. Open a Pull Request
---
@@ -560,11 +260,11 @@ AGPL-3.0 © [MikeeBuilds](https://github.com/MikeeBuilds)
---
- Don't just build agents. Give them a job.
+ Command your AI agents. Ship faster.
⭐ Star this repo •
- 📦 PyPI •
+ 📦 Download •
🐛 Report Bug
diff --git a/desktop/electron/main.ts b/desktop/electron/main.ts
index 29cfa72..07f6296 100644
--- a/desktop/electron/main.ts
+++ b/desktop/electron/main.ts
@@ -135,6 +135,38 @@ function setupTerminalIPC(mainWindow: BrowserWindow) {
});
});
});
+
+ // Onboarding & Project IPC Handlers
+ ipcMain.handle('settings-onboarding-complete', async () => {
+ return settingsStore.isOnboardingComplete();
+ });
+
+ ipcMain.handle('settings-set-onboarding', async (_, { complete }) => {
+ settingsStore.setOnboardingComplete(complete);
+ return true;
+ });
+
+ ipcMain.handle('settings-set-project', async (_, { projectPath }) => {
+ settingsStore.setProjectPath(projectPath);
+ return true;
+ });
+
+ ipcMain.handle('settings-get-integrations', async () => {
+ return settingsStore.getIntegrationConfig();
+ });
+
+ ipcMain.handle('settings-export-env', async (_, { targetPath }) => {
+ return settingsStore.exportToEnvFile(targetPath);
+ });
+
+ ipcMain.handle('dialog-select-folder', async () => {
+ const { dialog } = require('electron');
+ const result = await dialog.showOpenDialog({
+ properties: ['openDirectory'],
+ title: 'Select Project Folder'
+ });
+ return result.canceled ? null : result.filePaths[0];
+ });
}
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
diff --git a/desktop/electron/preload.ts b/desktop/electron/preload.ts
index b50f779..3a860c6 100644
--- a/desktop/electron/preload.ts
+++ b/desktop/electron/preload.ts
@@ -32,6 +32,13 @@ contextBridge.exposeInMainWorld('electronAPI', {
getSettings: () => ipcRenderer.invoke('settings-get-all'),
getEnabledProviders: () => ipcRenderer.invoke('settings-get-providers'),
hasApiKey: (provider: string) => ipcRenderer.invoke('settings-has-key', { provider }),
+ // Onboarding & Project IPC
+ isOnboardingComplete: () => ipcRenderer.invoke('settings-onboarding-complete'),
+ setOnboardingComplete: (complete: boolean) => ipcRenderer.invoke('settings-set-onboarding', { complete }),
+ setProjectPath: (projectPath: string) => ipcRenderer.invoke('settings-set-project', { projectPath }),
+ getIntegrationConfig: () => ipcRenderer.invoke('settings-get-integrations'),
+ exportEnvFile: (targetPath: string) => ipcRenderer.invoke('settings-export-env', { targetPath }),
+ selectFolder: () => ipcRenderer.invoke('dialog-select-folder'),
// CLI Installation IPC
checkCliInstalled: (cli: string) => ipcRenderer.invoke('cli-check-installed', { cli }),
installCli: (installCommand: string) => ipcRenderer.invoke('cli-install', { installCommand }),
diff --git a/desktop/electron/settings-store.ts b/desktop/electron/settings-store.ts
index b9318c3..66cb0e3 100644
--- a/desktop/electron/settings-store.ts
+++ b/desktop/electron/settings-store.ts
@@ -5,11 +5,37 @@ import { app } from 'electron'
const SETTINGS_FILE = 'squadron-settings.json'
+// All configurable integration keys
+export const INTEGRATION_KEYS = {
+ // AI Providers
+ anthropic: { label: 'Claude (Anthropic)', envKey: 'ANTHROPIC_API_KEY', category: 'ai' },
+ google: { label: 'Gemini (Google)', envKey: 'GOOGLE_API_KEY', category: 'ai' },
+ openai: { label: 'OpenAI (Codex)', envKey: 'OPENAI_API_KEY', category: 'ai' },
+
+ // Communication
+ slack_token: { label: 'Slack Bot Token', envKey: 'SLACK_BOT_TOKEN', category: 'communication' },
+ discord_webhook: { label: 'Discord Webhook URL', envKey: 'DISCORD_WEBHOOK_URL', category: 'communication' },
+ discord_token: { label: 'Discord Bot Token', envKey: 'DISCORD_BOT_TOKEN', category: 'communication' },
+
+ // Project Management
+ jira_server: { label: 'Jira Server URL', envKey: 'JIRA_SERVER', category: 'project', placeholder: 'https://your-domain.atlassian.net' },
+ jira_email: { label: 'Jira Email', envKey: 'JIRA_EMAIL', category: 'project', placeholder: 'your-email@example.com' },
+ jira_token: { label: 'Jira API Token', envKey: 'JIRA_TOKEN', category: 'project' },
+ linear: { label: 'Linear API Key', envKey: 'LINEAR_API_KEY', category: 'project' },
+
+ // Development
+ github: { label: 'GitHub Token', envKey: 'GITHUB_TOKEN', category: 'development', placeholder: 'ghp_...' },
+} as const
+
+export type IntegrationKey = keyof typeof INTEGRATION_KEYS
+
interface Settings {
apiKeys: Record // encrypted keys
enabledProviders: string[]
defaultProvider: string
defaultModel: string
+ onboardingComplete: boolean
+ projectPath: string | null
}
const getSettingsPath = (): string => {
@@ -30,7 +56,9 @@ const loadSettings = (): Settings => {
apiKeys: {},
enabledProviders: ['shell'],
defaultProvider: 'shell',
- defaultModel: 'default'
+ defaultModel: 'default',
+ onboardingComplete: false,
+ projectPath: null
}
}
@@ -50,7 +78,7 @@ export const saveApiKey = (provider: string, key: string): boolean => {
console.warn('[Settings] Encryption not available, storing in plain text')
const settings = loadSettings()
settings.apiKeys[provider] = key
- if (!settings.enabledProviders.includes(provider)) {
+ if (!settings.enabledProviders.includes(provider) && ['anthropic', 'google', 'openai'].includes(provider)) {
settings.enabledProviders.push(provider)
}
saveSettings(settings)
@@ -60,7 +88,7 @@ export const saveApiKey = (provider: string, key: string): boolean => {
const encrypted = safeStorage.encryptString(key).toString('base64')
const settings = loadSettings()
settings.apiKeys[provider] = encrypted
- if (!settings.enabledProviders.includes(provider)) {
+ if (!settings.enabledProviders.includes(provider) && ['anthropic', 'google', 'openai'].includes(provider)) {
settings.enabledProviders.push(provider)
}
saveSettings(settings)
@@ -118,6 +146,8 @@ export const getAllSettings = (): Omit & { hasKeys: Record<
enabledProviders: settings.enabledProviders,
defaultProvider: settings.defaultProvider,
defaultModel: settings.defaultModel,
+ onboardingComplete: settings.onboardingComplete,
+ projectPath: settings.projectPath,
hasKeys: Object.fromEntries(
Object.keys(settings.apiKeys).map(k => [k, true])
)
@@ -130,3 +160,54 @@ export const setDefaultProvider = (provider: string, model: string): void => {
settings.defaultModel = model
saveSettings(settings)
}
+
+export const setOnboardingComplete = (complete: boolean): void => {
+ const settings = loadSettings()
+ settings.onboardingComplete = complete
+ saveSettings(settings)
+}
+
+export const setProjectPath = (projectPath: string | null): void => {
+ const settings = loadSettings()
+ settings.projectPath = projectPath
+ saveSettings(settings)
+}
+
+export const isOnboardingComplete = (): boolean => {
+ const settings = loadSettings()
+ return settings.onboardingComplete
+}
+
+// Export settings to .env file for Python backend
+export const exportToEnvFile = (targetPath: string): boolean => {
+ try {
+ const settings = loadSettings()
+ const envLines: string[] = ['# Generated by Squadron Desktop App', '']
+
+ for (const [key, config] of Object.entries(INTEGRATION_KEYS)) {
+ const stored = settings.apiKeys[key]
+ if (stored) {
+ let value = stored
+ // Decrypt if encrypted
+ if (safeStorage.isEncryptionAvailable()) {
+ try {
+ const buffer = Buffer.from(stored, 'base64')
+ value = safeStorage.decryptString(buffer)
+ } catch { /* use as-is */ }
+ }
+ envLines.push(`${config.envKey}=${value}`)
+ }
+ }
+
+ const envPath = path.join(targetPath, '.env')
+ fs.writeFileSync(envPath, envLines.join('\n'))
+ console.log(`[Settings] Exported .env to ${envPath}`)
+ return true
+ } catch (err) {
+ console.error('[Settings] Failed to export .env:', err)
+ return false
+ }
+}
+
+// Get integration config for UI
+export const getIntegrationConfig = () => INTEGRATION_KEYS
diff --git a/desktop/package.json b/desktop/package.json
index 12fa742..b1e0d9f 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -1,11 +1,15 @@
{
- "name": "desktop",
+ "name": "squadron-desktop",
"productName": "Squadron",
- "description": "The Operating System for Autonomous Software Teams",
+ "description": "The AI Agent Command Center for Your Desktop",
"author": "MikeeBuilds",
"private": true,
- "version": "0.0.0",
+ "version": "2.0.0",
"main": "dist-electron/main.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/MikeeBuilds/Squadron"
+ },
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
@@ -13,8 +17,64 @@
"preview": "vite preview",
"electron:dev": "concurrently -k \"cross-env BROWSER=none npm run dev\" \"npm run build:main && wait-on http://localhost:5173 && cross-env VITE_DEV_SERVER_URL=http://localhost:5173 electron .\"",
"electron:build": "npm run build && npm run build:main && electron-builder",
+ "electron:build:mac": "npm run build && npm run build:main && electron-builder --mac",
+ "electron:build:win": "npm run build && npm run build:main && electron-builder --win",
+ "electron:build:linux": "npm run build && npm run build:main && electron-builder --linux",
"build:main": "tsc -p electron/tsconfig.json"
},
+ "build": {
+ "appId": "com.squadron.desktop",
+ "productName": "Squadron",
+ "directories": {
+ "output": "release"
+ },
+ "files": [
+ "dist/**/*",
+ "dist-electron/**/*"
+ ],
+ "mac": {
+ "category": "public.app-category.developer-tools",
+ "target": [
+ {
+ "target": "dmg",
+ "arch": [
+ "x64",
+ "arm64"
+ ]
+ }
+ ],
+ "icon": "public/icon.icns",
+ "hardenedRuntime": true,
+ "gatekeeperAssess": false
+ },
+ "win": {
+ "target": [
+ {
+ "target": "nsis",
+ "arch": [
+ "x64"
+ ]
+ }
+ ],
+ "icon": "public/icon.ico"
+ },
+ "linux": {
+ "target": [
+ {
+ "target": "AppImage",
+ "arch": [
+ "x64"
+ ]
+ }
+ ],
+ "category": "Development",
+ "icon": "public/icon.png"
+ },
+ "nsis": {
+ "oneClick": false,
+ "allowToChangeInstallationDirectory": true
+ }
+ },
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
@@ -41,7 +101,7 @@
"@eslint/js": "^9.39.1",
"@tailwindcss/postcss": "^4.1.18",
"@types/node": "^24.10.1",
- "@types/react": "^19.2.5",
+ "@types/react": "^19.2.0",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"autoprefixer": "^10.4.23",
@@ -63,4 +123,4 @@
"vite": "^7.2.4",
"wait-on": "^9.0.3"
}
-}
+}
\ No newline at end of file
diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx
index 3b50f0c..b3d0221 100644
--- a/desktop/src/App.tsx
+++ b/desktop/src/App.tsx
@@ -17,6 +17,7 @@ import { TaskWizard } from '@/components/TaskWizard'
import { AgentCard } from '@/components/AgentCard'
import { TerminalHub } from '@/components/TerminalHub'
import { SettingsPanel } from '@/components/SettingsPanel'
+import { OnboardingWizard } from '@/components/OnboardingWizard'
// Shadcn Sidebar Imports
import {
@@ -41,6 +42,25 @@ export default function App() {
const [isWizardOpen, setIsWizardOpen] = useState(false)
const [isSettingsOpen, setIsSettingsOpen] = useState(false)
const [kanbanKey, setKanbanKey] = useState(0)
+ const [showOnboarding, setShowOnboarding] = useState(false)
+ const [loading, setLoading] = useState(true)
+
+ const api = (window as any).electronAPI
+
+ // Check if onboarding is needed
+ useEffect(() => {
+ const checkOnboarding = async () => {
+ try {
+ const isComplete = await api.isOnboardingComplete()
+ setShowOnboarding(!isComplete)
+ } catch (err) {
+ console.error('Failed to check onboarding:', err)
+ } finally {
+ setLoading(false)
+ }
+ }
+ checkOnboarding()
+ }, [])
useEffect(() => {
const fetchStatus = async () => {
@@ -53,6 +73,19 @@ export default function App() {
return () => clearInterval(interval)
}, [])
+ // Show loading or onboarding
+ if (loading) {
+ return (
+
+ )
+ }
+
+ if (showOnboarding) {
+ return setShowOnboarding(false)} />
+ }
+
const navItems = [
{ id: 'kanban', label: 'Operations', icon: LayoutDashboard },
{ id: 'terminals', label: 'Terminal Hub', icon: Terminal },
diff --git a/desktop/src/components/OnboardingWizard.tsx b/desktop/src/components/OnboardingWizard.tsx
new file mode 100644
index 0000000..d18b7b8
--- /dev/null
+++ b/desktop/src/components/OnboardingWizard.tsx
@@ -0,0 +1,224 @@
+import { useState } from 'react'
+import { Rocket, Key, FolderOpen, ChevronRight, ChevronLeft, Check, SkipForward } from 'lucide-react'
+import { cn } from '@/lib/utils'
+
+interface OnboardingWizardProps {
+ onComplete: () => void
+}
+
+const AI_PROVIDERS = [
+ { id: 'anthropic', name: 'Claude', description: 'Anthropic Claude 4 Sonnet/Opus', color: 'from-orange-600 to-orange-400', envKey: 'ANTHROPIC_API_KEY' },
+ { id: 'google', name: 'Gemini', description: 'Google Gemini 2.5 Pro/Flash', color: 'from-blue-600 to-blue-400', envKey: 'GOOGLE_API_KEY' },
+ { id: 'openai', name: 'Codex', description: 'OpenAI GPT-4o / o1 / o3', color: 'from-green-600 to-green-400', envKey: 'OPENAI_API_KEY' },
+]
+
+export function OnboardingWizard({ onComplete }: OnboardingWizardProps) {
+ const [step, setStep] = useState(1)
+ const [selectedProvider, setSelectedProvider] = useState(null)
+ const [apiKey, setApiKey] = useState('')
+ const [saving, setSaving] = useState(false)
+ const [projectPath, setProjectPath] = useState(null)
+
+ const api = (window as any).electronAPI
+
+ const totalSteps = 3
+
+ const handleNext = async () => {
+ if (step === 2 && apiKey && selectedProvider) {
+ setSaving(true)
+ await api.saveApiKey(selectedProvider, apiKey)
+ setSaving(false)
+ }
+
+ if (step === 3 && projectPath) {
+ await api.setProjectPath(projectPath)
+ await api.exportEnvFile(projectPath)
+ }
+
+ if (step < totalSteps) {
+ setStep(step + 1)
+ } else {
+ await api.setOnboardingComplete(true)
+ onComplete()
+ }
+ }
+
+ const handleSkip = async () => {
+ await api.setOnboardingComplete(true)
+ onComplete()
+ }
+
+ const handleSelectFolder = async () => {
+ const folder = await api.selectFolder()
+ if (folder) {
+ setProjectPath(folder)
+ }
+ }
+
+ const canProceed = () => {
+ if (step === 1) return !!selectedProvider
+ if (step === 2) return !!apiKey.trim()
+ return true // Step 3 is optional
+ }
+
+ return (
+
+
+ {/* Logo & Title */}
+
+
+
+
+
Welcome to Squadron
+
Let's get you set up in under a minute
+
+
+ {/* Progress */}
+
+ {[1, 2, 3].map(i => (
+
+ ))}
+
+
+ {/* Card */}
+
+
+ {/* Step 1: Choose Provider */}
+ {step === 1 && (
+
+
+
+ Step 1: Choose Your AI Provider
+
+
+
+ {AI_PROVIDERS.map(provider => (
+
setSelectedProvider(provider.id)}
+ className={cn(
+ "w-full p-4 rounded-xl border-2 text-left transition-all",
+ selectedProvider === provider.id
+ ? "border-yellow-400 bg-yellow-400/5"
+ : "border-zinc-800 hover:border-zinc-700 bg-zinc-950"
+ )}
+ >
+
+
+ {provider.name[0]}
+
+
+
{provider.name}
+
{provider.description}
+
+ {selectedProvider === provider.id && (
+
+ )}
+
+
+ ))}
+
+
+ )}
+
+ {/* Step 2: Enter API Key */}
+ {step === 2 && (
+
+
+
+ Step 2: Enter Your API Key
+
+
+
+
+ {AI_PROVIDERS.find(p => p.id === selectedProvider)?.name} API Key
+
+ setApiKey(e.target.value)}
+ className="w-full bg-transparent border-0 text-white text-lg focus:outline-none placeholder:text-zinc-600"
+ autoFocus
+ />
+
+
+
+ Your key is encrypted and stored securely on your device. It never leaves your machine.
+
+
+ )}
+
+ {/* Step 3: Project Folder (Optional) */}
+ {step === 3 && (
+
+
+
+ Step 3: Select Project Folder (Optional)
+
+
+
+ Choose a project folder to export your settings as a .env file for the Python backend.
+
+
+
+
+ {projectPath || 'No folder selected'}
+
+
+ Browse
+
+
+
+ )}
+
+
+ {/* Footer */}
+
+
+
+ Skip Setup
+
+
+
+ {step > 1 && (
+ setStep(step - 1)}
+ className="px-4 py-2 bg-zinc-800 hover:bg-zinc-700 text-white rounded-xl font-medium text-sm flex items-center gap-1 transition-colors"
+ >
+
+ Back
+
+ )}
+
+ {saving ? 'Saving...' : step === totalSteps ? 'Finish' : 'Continue'}
+ {!saving && }
+
+
+
+
+
+ {/* Step indicator */}
+
+ Step {step} of {totalSteps}
+
+
+
+ )
+}
diff --git a/desktop/src/components/SettingsPanel.tsx b/desktop/src/components/SettingsPanel.tsx
index f6f8ec3..46aaa86 100644
--- a/desktop/src/components/SettingsPanel.tsx
+++ b/desktop/src/components/SettingsPanel.tsx
@@ -1,7 +1,45 @@
import { useState, useEffect } from 'react'
-import { X, Key, Check, AlertCircle, Eye, EyeOff, Trash2 } from 'lucide-react'
+import { X, Key, Check, AlertCircle, Eye, EyeOff, Trash2, Folder, FolderOpen, Download } from 'lucide-react'
import { cn } from '@/lib/utils'
-import { PROVIDERS } from '@/lib/providers'
+
+// Integration configuration matching settings-store.ts
+const INTEGRATIONS = {
+ ai: {
+ label: 'AI Providers',
+ icon: '🤖',
+ items: [
+ { id: 'anthropic', label: 'Claude (Anthropic)', envKey: 'ANTHROPIC_API_KEY', color: 'text-orange-400' },
+ { id: 'google', label: 'Gemini (Google)', envKey: 'GOOGLE_API_KEY', color: 'text-blue-400' },
+ { id: 'openai', label: 'OpenAI (Codex)', envKey: 'OPENAI_API_KEY', color: 'text-green-400' },
+ ]
+ },
+ communication: {
+ label: 'Communication',
+ icon: '💬',
+ items: [
+ { id: 'slack_token', label: 'Slack Bot Token', envKey: 'SLACK_BOT_TOKEN', color: 'text-purple-400', placeholder: 'xoxb-...' },
+ { id: 'discord_webhook', label: 'Discord Webhook', envKey: 'DISCORD_WEBHOOK_URL', color: 'text-indigo-400', placeholder: 'https://discord.com/api/webhooks/...' },
+ { id: 'discord_token', label: 'Discord Bot Token', envKey: 'DISCORD_BOT_TOKEN', color: 'text-indigo-400' },
+ ]
+ },
+ project: {
+ label: 'Project Management',
+ icon: '📋',
+ items: [
+ { id: 'jira_server', label: 'Jira Server URL', envKey: 'JIRA_SERVER', color: 'text-blue-500', placeholder: 'https://your-domain.atlassian.net' },
+ { id: 'jira_email', label: 'Jira Email', envKey: 'JIRA_EMAIL', color: 'text-blue-500', placeholder: 'your-email@example.com' },
+ { id: 'jira_token', label: 'Jira API Token', envKey: 'JIRA_TOKEN', color: 'text-blue-500' },
+ { id: 'linear', label: 'Linear API Key', envKey: 'LINEAR_API_KEY', color: 'text-violet-400', placeholder: 'lin_api_...' },
+ ]
+ },
+ development: {
+ label: 'Development',
+ icon: '🔧',
+ items: [
+ { id: 'github', label: 'GitHub Token', envKey: 'GITHUB_TOKEN', color: 'text-gray-300', placeholder: 'ghp_...' },
+ ]
+ }
+}
interface SettingsPanelProps {
isOpen: boolean
@@ -14,6 +52,8 @@ export function SettingsPanel({ isOpen, onClose }: SettingsPanelProps) {
const [showKey, setShowKey] = useState>({})
const [saving, setSaving] = useState(null)
const [saved, setSaved] = useState(null)
+ const [projectPath, setProjectPath] = useState(null)
+ const [activeSection, setActiveSection] = useState('ai')
const api = (window as any).electronAPI
@@ -22,138 +62,230 @@ export function SettingsPanel({ isOpen, onClose }: SettingsPanelProps) {
if (!isOpen) return
const loadKeyStatus = async () => {
- const status: Record = {}
- for (const providerId of Object.keys(PROVIDERS)) {
- if (providerId === 'shell') continue
- try {
- status[providerId] = await api.hasApiKey(providerId)
- } catch {
- status[providerId] = false
- }
- }
- setHasKeys(status)
+ const settings = await api.getSettings()
+ setHasKeys(settings.hasKeys || {})
+ setProjectPath(settings.projectPath)
}
loadKeyStatus()
}, [isOpen])
- const handleSaveKey = async (providerId: string) => {
- const key = apiKeys[providerId]
+ const handleSaveKey = async (integrationId: string) => {
+ const key = apiKeys[integrationId]
if (!key?.trim()) return
- setSaving(providerId)
+ setSaving(integrationId)
try {
- await api.saveApiKey(providerId, key.trim())
- setHasKeys(prev => ({ ...prev, [providerId]: true }))
- setApiKeys(prev => ({ ...prev, [providerId]: '' }))
- setSaved(providerId)
+ await api.saveApiKey(integrationId, key.trim())
+ setHasKeys(prev => ({ ...prev, [integrationId]: true }))
+ setApiKeys(prev => ({ ...prev, [integrationId]: '' }))
+ setSaved(integrationId)
setTimeout(() => setSaved(null), 2000)
} catch (err) {
- console.error(`Failed to save API key for ${providerId}:`, err)
+ console.error(`Failed to save key for ${integrationId}:`, err)
} finally {
setSaving(null)
}
}
- const handleDeleteKey = async (providerId: string) => {
+ const handleDeleteKey = async (integrationId: string) => {
try {
- await api.deleteApiKey(providerId)
- setHasKeys(prev => ({ ...prev, [providerId]: false }))
+ await api.deleteApiKey(integrationId)
+ setHasKeys(prev => ({ ...prev, [integrationId]: false }))
} catch (err) {
- console.error(`Failed to delete API key for ${providerId}:`, err)
+ console.error(`Failed to delete key for ${integrationId}:`, err)
+ }
+ }
+
+ const handleSelectFolder = async () => {
+ const folder = await api.selectFolder()
+ if (folder) {
+ await api.setProjectPath(folder)
+ setProjectPath(folder)
+ }
+ }
+
+ const handleExportEnv = async () => {
+ if (!projectPath) return
+ const success = await api.exportEnvFile(projectPath)
+ if (success) {
+ setSaved('env-export')
+ setTimeout(() => setSaved(null), 2000)
}
}
if (!isOpen) return null
- const providerList = Object.values(PROVIDERS).filter(p => p.id !== 'shell')
+ const sections = Object.entries(INTEGRATIONS)
return (
-
+
{/* Header */}
- API Configuration
+ Settings & Integrations
- {/* Content */}
-
-
- Configure API keys for AI providers. Keys are encrypted and stored securely on your device.
-
-
- {providerList.map(provider => (
-
-
-
- {provider.name}
-
- {hasKeys[provider.id] && (
-
-
- Configured
-
+
+ {/* Sidebar */}
+
+ {sections.map(([key, section]) => (
+ setActiveSection(key)}
+ className={cn(
+ "w-full text-left px-3 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2",
+ activeSection === key
+ ? "bg-yellow-400/10 text-yellow-400"
+ : "text-zinc-400 hover:bg-zinc-800 hover:text-white"
)}
-
+ >
+
{section.icon}
+ {section.label}
+
+ ))}
+
+
setActiveSection('project-folder')}
+ className={cn(
+ "w-full text-left px-3 py-2 rounded-lg text-sm font-medium transition-all flex items-center gap-2",
+ activeSection === 'project-folder'
+ ? "bg-yellow-400/10 text-yellow-400"
+ : "text-zinc-400 hover:bg-zinc-800 hover:text-white"
+ )}
+ >
+
+ Project
+
+
+
+ {/* Content */}
+
+ {activeSection === 'project-folder' ? (
+
+
Project Folder
+
+ Select your Squadron project folder. Integration keys will be exported to a .env file here.
+
-
-
-
setApiKeys(prev => ({ ...prev, [provider.id]: e.target.value }))}
- className="w-full bg-zinc-950 border border-zinc-800 rounded-xl px-4 py-2.5 text-sm text-zinc-100 placeholder:text-zinc-600 focus:outline-none focus:border-yellow-400/50 transition-colors pr-10"
- />
+
+
+ {projectPath || 'No project folder selected'}
+
setShowKey(prev => ({ ...prev, [provider.id]: !prev[provider.id] }))}
- className="absolute right-3 top-1/2 -translate-y-1/2 text-zinc-600 hover:text-zinc-400 transition-colors"
+ onClick={handleSelectFolder}
+ className="px-4 py-2.5 bg-zinc-800 hover:bg-zinc-700 text-white rounded-xl font-medium text-sm flex items-center gap-2 transition-colors"
>
- {showKey[provider.id] ? : }
+
+ Browse
-
handleSaveKey(provider.id)}
- disabled={!apiKeys[provider.id]?.trim() || saving === provider.id}
- className={cn(
- "px-4 py-2.5 rounded-xl font-bold text-sm transition-all flex items-center gap-2",
- saved === provider.id
- ? "bg-green-500 text-black"
- : "bg-yellow-400 hover:bg-yellow-500 disabled:opacity-50 disabled:cursor-not-allowed text-black"
- )}
- >
- {saving === provider.id ? '...' : saved === provider.id ? : 'Save'}
-
-
- {hasKeys[provider.id] && (
+ {projectPath && (
handleDeleteKey(provider.id)}
- className="px-3 py-2.5 rounded-xl border border-red-500/30 text-red-500 hover:bg-red-500/10 transition-all"
- title="Delete API key"
+ onClick={handleExportEnv}
+ className={cn(
+ "w-full py-2.5 rounded-xl font-bold text-sm transition-all flex items-center justify-center gap-2",
+ saved === 'env-export'
+ ? "bg-green-500 text-black"
+ : "bg-yellow-400 hover:bg-yellow-500 text-black"
+ )}
>
-
+ {saved === 'env-export' ? (
+ <>
+
+ Exported!
+ >
+ ) : (
+ <>
+
+ Export .env File
+ >
+ )}
)}
+ ) : (
+
+
+ {INTEGRATIONS[activeSection as keyof typeof INTEGRATIONS]?.label}
+
-
- Environment variable: {provider.envKey}
-
-
- ))}
+ {INTEGRATIONS[activeSection as keyof typeof INTEGRATIONS]?.items.map(item => (
+
+
+
+ {item.label}
+
+ {hasKeys[item.id] && (
+
+
+ Set
+
+ )}
+
+
+
+
+ setApiKeys(prev => ({ ...prev, [item.id]: e.target.value }))}
+ className="w-full bg-zinc-950 border border-zinc-800 rounded-lg px-3 py-2 text-xs text-zinc-100 placeholder:text-zinc-600 focus:outline-none focus:border-yellow-400/50 transition-colors pr-8"
+ />
+ setShowKey(prev => ({ ...prev, [item.id]: !prev[item.id] }))}
+ className="absolute right-2 top-1/2 -translate-y-1/2 text-zinc-600 hover:text-zinc-400 transition-colors"
+ >
+ {showKey[item.id] ? : }
+
+
- {/* Security notice */}
-
-
-
- Security: API keys are encrypted using your operating system's secure storage (Windows DPAPI / macOS Keychain) and never leave your device.
+ handleSaveKey(item.id)}
+ disabled={!apiKeys[item.id]?.trim() || saving === item.id}
+ className={cn(
+ "px-3 py-2 rounded-lg font-bold text-xs transition-all",
+ saved === item.id
+ ? "bg-green-500 text-black"
+ : "bg-yellow-400 hover:bg-yellow-500 disabled:opacity-50 disabled:cursor-not-allowed text-black"
+ )}
+ >
+ {saving === item.id ? '...' : saved === item.id ? : 'Save'}
+
+
+ {hasKeys[item.id] && (
+ handleDeleteKey(item.id)}
+ className="px-2 py-2 rounded-lg border border-red-500/30 text-red-500 hover:bg-red-500/10 transition-all"
+ title="Delete"
+ >
+
+
+ )}
+
+
+
+ {item.envKey}
+
+
+ ))}
+
+ )}
+
+ {/* Security notice */}
+
+
+
+ Security: Keys are encrypted using your OS secure storage.
+
diff --git a/setup.py b/setup.py
index c3985fa..7938dca 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@
setup(
name="squadron-agents",
- version="0.6.0",
+ version="2.0.0",
author="MikeeBuilds",
author_email="mludlow000@icloud.com",
description="The Operating System for Autonomous Software Teams",