diff options
| author | Adam Malczewski <[email protected]> | 2026-05-20 15:43:07 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-20 15:43:07 +0900 |
| commit | 971a8f775d5e89e484e56a575e8ae2706fe2b53f (patch) | |
| tree | d11f6cbbf230d73e53dee0db09e535dea9717599 | |
| parent | adc8bd185b54935e7a31aae04da3175b7989927a (diff) | |
| download | dispatch-971a8f775d5e89e484e56a575e8ae2706fe2b53f.tar.gz dispatch-971a8f775d5e89e484e56a575e8ae2706fe2b53f.zip | |
fix: sidebar layout, copilot auth script, config setup
- Sidebar uses absolute inset-0 with overflow-y-auto for proper scrolling
- Border moved to inner div so it hides with sidebar
- Copilot auth script uses portable sed instead of grep -P (macOS compat)
- dispatch.toml with 3 keys, 4 models, fallback order
- .env.dispatch with key placeholders and script reference
- docker-compose loads .env.dispatch via env_file
| -rw-r--r-- | .gitignore | 1 | ||||
| -rwxr-xr-x | bin/copilot-auth | 84 | ||||
| -rw-r--r-- | dispatch.toml | 86 | ||||
| -rw-r--r-- | docker-compose.yml | 4 | ||||
| -rw-r--r-- | packages/frontend/src/App.svelte | 4 |
5 files changed, 175 insertions, 4 deletions
@@ -2,6 +2,7 @@ node_modules/ dist/ build/ .env +.env.dispatch *.db *.sqlite .DS_Store diff --git a/bin/copilot-auth b/bin/copilot-auth new file mode 100755 index 0000000..28d08a1 --- /dev/null +++ b/bin/copilot-auth @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +CLIENT_ID="Ov23li8tweQw6odWQebz" +ENV_FILE="$(cd "$(dirname "$0")/.." && pwd)/.env.dispatch" + +# Parse form-encoded key=value pairs +parse() { + local key="$1" data="$2" + local val + val=$(echo "$data" | sed -n "s/.*${key}=\([^&]*\).*/\1/p") + python3 -c "import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read().strip()))" <<< "$val" +} + +echo "=== GitHub Copilot OAuth ===" +echo "" + +# Step 1: Request device code +echo "Requesting device code..." +RESP=$(curl -s https://github.com/login/device/code \ + -d "client_id=$CLIENT_ID" \ + -d "scope=read:user") + +DEVICE_CODE=$(parse "device_code" "$RESP") + +if [ -z "$DEVICE_CODE" ]; then + echo "Failed to get device code: $RESP" + exit 1 +fi + +USER_CODE=$(parse "user_code" "$RESP") +VERIF_URI=$(parse "verification_uri" "$RESP") +INTERVAL=$(parse "interval" "$RESP") +INTERVAL=${INTERVAL:-5} + +echo "" +echo "Open this URL and enter the code:" +echo " $VERIF_URI" +echo " Code: $USER_CODE" +echo "" +echo "Waiting for you to authorize..." + +# Step 2: Poll for access token +TOKEN="" +ATTEMPTS=0 +while [ -z "$TOKEN" ] && [ $ATTEMPTS -lt 60 ]; do + sleep "$INTERVAL" + ATTEMPTS=$((ATTEMPTS + 1)) + + TOKEN_RESP=$(curl -s https://github.com/login/oauth/access_token \ + -d "client_id=$CLIENT_ID" \ + -d "device_code=$DEVICE_CODE" \ + -d "grant_type=urn:ietf:params:oauth:grant-type:device_code") + + TOKEN=$(parse "access_token" "$TOKEN_RESP" || true) + ERROR=$(parse "error" "$TOKEN_RESP" || true) + + if [ "$ERROR" = "authorization_pending" ]; then + continue + elif [ "$ERROR" = "slow_down" ]; then + INTERVAL=$((INTERVAL + 5)) + continue + elif [ -n "$ERROR" ]; then + echo "Error: $ERROR" + exit 1 + fi +done + +if [ -z "$TOKEN" ]; then + echo "Timed out waiting for authorization." + exit 1 +fi + +# Step 3: Write to .env.dispatch +mkdir -p "$(dirname "$ENV_FILE")" +if [ -f "$ENV_FILE" ] && grep -q "^COPILOT_TOKEN=" "$ENV_FILE" 2>/dev/null; then + sed -i "s/^COPILOT_TOKEN=.*/COPILOT_TOKEN=$TOKEN/" "$ENV_FILE" +else + echo "COPILOT_TOKEN=$TOKEN" >> "$ENV_FILE" +fi + +echo "" +echo "Token saved to .env.dispatch" +echo "Ready — run: docker compose up" diff --git a/dispatch.toml b/dispatch.toml new file mode 100644 index 0000000..1559578 --- /dev/null +++ b/dispatch.toml @@ -0,0 +1,86 @@ +# Dispatch — Model & Key Configuration +# Keys reference env var names in .env.dispatch + +# ─── Fallback Order (highest priority first) ──────────────────── +# Exhaust opencode-1 first, then opencode-2, then copilot. +# When all keys are exhausted the agent enters wait-for-refresh. +# Must be declared BEFORE any [[keys]] / [[models]] blocks. + +fallback = ["opencode-1", "opencode-2", "copilot"] + +# ─── API Keys ─────────────────────────────────────────────────── + +[[keys]] +id = "opencode-1" +provider = "opencode-go" +env = "OPENCODE_KEY_1" +base_url = "https://opencode.ai/zen/go/v1" + +[[keys]] +id = "opencode-2" +provider = "opencode-go" +env = "OPENCODE_KEY_2" +base_url = "https://opencode.ai/zen/go/v1" + +[[keys]] +id = "copilot" +provider = "github-copilot" +env = "COPILOT_TOKEN" +base_url = "https://api.githubcopilot.com" + +# ─── Models ───────────────────────────────────────────────────── + +[[models]] +id = "deepseek-v4-pro" +provider = "opencode-go" +tags = ["heavy", "coding"] + +[[models]] +id = "deepseek-v4-flash" +provider = "opencode-go" +tags = ["light", "quick"] + +[[models]] +id = "gpt-4o" +provider = "github-copilot" +tags = ["heavy", "coding"] + +[[models]] +id = "claude-3.5-sonnet" +provider = "github-copilot" +tags = ["heavy", "coding", "review"] + +# ─── Agent Templates ───────────────────────────────────────────── + +[agents.default] +name = "Dispatch" +description = "Default coding assistant" +system_prompt = "You are a helpful AI coding assistant." +tools = ["read_file", "write_file", "list_files", "run_shell", "task_list"] +model_tag = "heavy" + +# ─── Permissions ───────────────────────────────────────────────── + +[permissions] +read = "allow" + +[permissions.edit] +"*" = "ask" +"src/**" = "allow" + +[permissions.bash] +"npm test" = "allow" +"npm run *" = "allow" +"git status" = "allow" +"git diff" = "allow" +"git log *" = "allow" +"git branch *" = "allow" +"git add *" = "allow" +"git commit *" = "allow" +"git push *" = "allow" +"ls *" = "allow" +"*" = "ask" + +[permissions.external_directory] +"~/*" = "ask" +"/tmp/*" = "allow" diff --git a/docker-compose.yml b/docker-compose.yml index e52d3f2..f669705 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,9 +8,9 @@ services: - "3000:3000" volumes: - .:/app + env_file: + - .env.dispatch environment: - OPENCODE_API_KEY: ${OPENCODE_API_KEY:-} - DISPATCH_MODEL: ${DISPATCH_MODEL:-deepseek-v4-flash} DISPATCH_WORKING_DIR: /app frontend: diff --git a/packages/frontend/src/App.svelte b/packages/frontend/src/App.svelte index 02a80ba..43fcc5d 100644 --- a/packages/frontend/src/App.svelte +++ b/packages/frontend/src/App.svelte @@ -92,12 +92,12 @@ onMount(() => { <!-- Right sidebar — slides in/out while chat smoothly resizes --> <div - class="shrink-0 overflow-hidden border-l border-base-300 transition-[width] duration-300 ease-out" + class="shrink-0 overflow-x-hidden transition-[width] duration-300 ease-out relative" class:w-80={sidebarOpen} class:w-0={!sidebarOpen} > <div - class="w-80 overflow-y-auto bg-base-100 px-2 py-2 flex flex-col gap-2 h-full transition-transform duration-300 ease-out" + class="w-80 absolute inset-0 overflow-y-auto bg-base-100 border-l border-base-300 px-2 py-2 flex flex-col gap-2 transition-transform duration-300 ease-out" style="transform: translateX({sidebarOpen ? '0' : '100%'})" > <div class="collapse collapse-arrow bg-base-200"> |
