Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Test

on:
push:
branches: ["*"]
pull_request:
branches: ["*"]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install

- name: Type check
run: bun run type-check

- name: Run tests
run: bun test

- name: Build
run: bun run build
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ The auth file contains credentials for all configured OpenCode providers:
- `google` - Gemini (OAuth)
- API key providers

## Development

### Running Tests

```bash
bun test
```

### Type Checking

```bash
bun run type-check
```

### Building

```bash
bun run build
```

## License

MIT
96 changes: 12 additions & 84 deletions cli.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,25 @@
#!/usr/bin/env bun
import * as p from "@clack/prompts"
import color from "picocolors"
import { execSync } from "child_process"
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"
import { homedir } from "os"
import { join } from "path"
import { writeFileSync, mkdirSync } from "fs"
import { loadPluginConfigSync, mergeConfig } from "./lib/config"

const OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode")
const OPENCODE_CONFIG_PATH = join(OPENCODE_CONFIG_DIR, "opencode.json")
const PLUGIN_CONFIG_PATH = join(OPENCODE_CONFIG_DIR, "opencode-auth-sync.json")
const PLUGIN_NAME = "@activade/opencode-auth-sync"

interface GhRepo {
nameWithOwner: string
isPrivate: boolean
description: string | null
}

function checkGhCli(): boolean {
try {
execSync("gh --version", { stdio: "ignore" })
return true
} catch {
return false
}
}

function checkGhAuth(): boolean {
try {
execSync("gh auth status", { stdio: "ignore" })
return true
} catch {
return false
}
}

function getGhRepos(): GhRepo[] {
try {
const output = execSync(
'gh repo list --limit 100 --json nameWithOwner,isPrivate,description',
{ encoding: "utf-8" }
)
return JSON.parse(output)
} catch {
return []
}
}

function loadOpencodeConfig(): Record<string, unknown> {
if (!existsSync(OPENCODE_CONFIG_PATH)) {
return {}
}
try {
return JSON.parse(readFileSync(OPENCODE_CONFIG_PATH, "utf-8"))
} catch {
return {}
}
}

function saveOpencodeConfig(config: Record<string, unknown>): void {
mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true })
writeFileSync(OPENCODE_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n")
}

function isPluginInstalled(config: Record<string, unknown>): boolean {
const plugins = (config.plugin as string[]) || []
return plugins.some((p) => p.includes("opencode-auth-sync"))
}

function addPluginToConfig(config: Record<string, unknown>): Record<string, unknown> {
const plugins = (config.plugin as string[]) || []
if (!isPluginInstalled(config)) {
plugins.push(PLUGIN_NAME)
}
return { ...config, plugin: plugins }
}


import {
OPENCODE_CONFIG_DIR,
PLUGIN_CONFIG_PATH,
checkGhCli,
checkGhAuth,
getGhRepos,
loadOpencodeConfig,
saveOpencodeConfig,
isPluginInstalled,
addPluginToConfig,
} from "./lib/cli-utils"

async function main() {
console.clear()

p.intro(color.bgCyan(color.black(" opencode-auth-sync setup ")))

// Check prerequisites
const s = p.spinner()

s.start("Checking prerequisites")
Expand All @@ -105,15 +40,13 @@ async function main() {

s.stop("Prerequisites OK")

// Check existing installation
const opencodeConfig = loadOpencodeConfig()
const alreadyInstalled = isPluginInstalled(opencodeConfig)

if (alreadyInstalled) {
p.log.info("Plugin already installed in opencode.json")
}

// Fetch repositories
s.start("Fetching your GitHub repositories")
const repos = getGhRepos()
s.stop(`Found ${repos.length} repositories`)
Expand All @@ -126,7 +59,6 @@ async function main() {
const existingConfig = loadPluginConfigSync(PLUGIN_CONFIG_PATH)
const existingRepos = existingConfig.repositories || []

// Repository selection
const repoOptions = repos.map((repo) => ({
value: repo.nameWithOwner,
label: repo.nameWithOwner,
Expand Down Expand Up @@ -162,7 +94,6 @@ async function main() {
process.exit(0)
}

// Confirm
const confirmed = await p.confirm({
message: `Install plugin and sync to ${(selectedRepos as string[]).length} repositories?`,
initialValue: true,
Expand All @@ -173,7 +104,6 @@ async function main() {
process.exit(0)
}

// Execute setup
s.start("Configuring plugin")

mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true })
Expand All @@ -189,15 +119,13 @@ async function main() {
}
writeFileSync(PLUGIN_CONFIG_PATH, JSON.stringify(pluginConfig, null, 2) + "\n")

// Add plugin to opencode.json
if (!alreadyInstalled) {
const updatedConfig = addPluginToConfig(opencodeConfig)
saveOpencodeConfig(updatedConfig)
}

s.stop("Configuration saved")

// Summary
p.note(
[
`${color.dim("Plugin config:")} ~/.config/opencode/opencode-auth-sync.json`,
Expand Down
Loading