diff --git a/.github/workflows/doc-sync.yml b/.github/workflows/doc-sync.yml index a3ed43b..c2cd497 100644 --- a/.github/workflows/doc-sync.yml +++ b/.github/workflows/doc-sync.yml @@ -16,12 +16,6 @@ jobs: ref: ${{ github.head_ref }} fetch-depth: 0 - - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth- - restore-keys: opencode-auth- - - uses: activadee/open-workflows/actions/doc-sync@main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/issue-label.yml b/.github/workflows/issue-label.yml index 0458bc7..ad621a3 100644 --- a/.github/workflows/issue-label.yml +++ b/.github/workflows/issue-label.yml @@ -12,12 +12,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth- - restore-keys: opencode-auth- - - uses: activadee/open-workflows/actions/issue-label@main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/opencode-auth.yml b/.github/workflows/opencode-auth.yml deleted file mode 100644 index 29ab827..0000000 --- a/.github/workflows/opencode-auth.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: OpenCode Auth - -on: - schedule: - - cron: '0 3 * * *' - workflow_dispatch: - -jobs: - refresh: - runs-on: ubuntu-latest - steps: - - id: cache - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth-${{ github.run_id }} - restore-keys: opencode-auth- - - - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p ~/.local/share/opencode - echo '${{ secrets.OPENCODE_AUTH }}' > ~/.local/share/opencode/auth.json - - - run: curl -fsSL https://opencode.ai/install | bash - - - run: opencode models - - - uses: actions/cache/save@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth-${{ github.run_id }} diff --git a/.github/workflows/pr-review.yml b/.github/workflows/pr-review.yml index 48c9f24..57a235d 100644 --- a/.github/workflows/pr-review.yml +++ b/.github/workflows/pr-review.yml @@ -13,12 +13,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth- - restore-keys: opencode-auth- - - uses: activadee/open-workflows/actions/pr-review@main env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 2df8404..70b8b07 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,14 @@ gh secret set ANTHROPIC_API_KEY ``` **Option 2: Claude Max (OAuth)** + +Use the [opencode-auth-sync](https://github.com/activadee/opencode-auth-sync) plugin to automatically sync your OAuth tokens: + +```bash +bunx @activade/opencode-auth-sync +``` + +Or manually set the secret: ```bash gh secret set OPENCODE_AUTH < ~/.local/share/opencode/auth.json ``` diff --git a/bun.lock b/bun.lock index 2e66dc8..9a743a4 100644 --- a/bun.lock +++ b/bun.lock @@ -6,12 +6,11 @@ "name": "@activade/open-workflows", "dependencies": { "@clack/prompts": "^0.10.0", - "@types/bun": "^1.3.5", "picocolors": "^1.1.1", }, "devDependencies": { + "@types/bun": "^1.3.5", "@types/node": "^22.0.0", - "bun-types": "latest", "typescript": "^5.6.0", }, }, diff --git a/examples/README.md b/examples/README.md index 46fe20a..e0dce2f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -10,7 +10,13 @@ For AI-powered actions (pr-review, issue-label, doc-sync), add your API key: gh secret set ANTHROPIC_API_KEY ``` -Or if using Claude Max subscription: +Or if using Claude Max subscription, use the [opencode-auth-sync](https://github.com/activadee/opencode-auth-sync) plugin to automatically sync your OAuth tokens: + +```bash +bunx @activade/opencode-auth-sync +``` + +Or manually set the secret: ```bash gh secret set OPENCODE_AUTH < ~/.local/share/opencode/auth.json diff --git a/src/cli/index.ts b/src/cli/index.ts index f0d33a8..cc0a092 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -42,11 +42,10 @@ WHAT GETS INSTALLED .github/workflows/issue-label.yml .github/workflows/doc-sync.yml .github/workflows/release.yml - .github/workflows/opencode-auth.yml (OAuth only) REQUIRED SECRETS For Claude Max (OAuth): - OPENCODE_AUTH - Your auth.json from ~/.local/share/opencode/auth.json + OPENCODE_AUTH - Your auth.json (use opencode-auth-sync plugin to keep it updated) For API Key: ANTHROPIC_API_KEY - Your Anthropic API key @@ -85,11 +84,22 @@ const promptResults = await p.group( } ); -let selectedWorkflows = (promptResults.workflows || []) as WorkflowType[]; +const selectedWorkflows = (promptResults.workflows || []) as WorkflowType[]; const useOAuth = Boolean(promptResults.useOAuth); -if (useOAuth && !selectedWorkflows.includes('opencode-auth')) { - selectedWorkflows = [...selectedWorkflows, 'opencode-auth']; +let installPlugin = false; +if (useOAuth) { + const pluginPrompt = await p.confirm({ + message: 'Install opencode-auth-sync plugin? (keeps OAuth tokens synced)', + initialValue: true, + }); + + if (p.isCancel(pluginPrompt)) { + p.cancel('Installation cancelled.'); + process.exit(0); + } + + installPlugin = Boolean(pluginPrompt); } const workflowOverrides = new Set(); @@ -165,10 +175,23 @@ if (errors.length > 0) { } if (useOAuth) { - p.note( - `${color.cyan('1.')} Export your OpenCode auth as a secret:\n ${color.dim('gh secret set OPENCODE_AUTH < ~/.local/share/opencode/auth.json')}\n\n${color.cyan('2.')} Commit and push the workflow files\n\n${color.cyan('3.')} Run the opencode-auth workflow manually to initialize the cache:\n ${color.dim('gh workflow run opencode-auth.yml')}`, - 'Next steps (OAuth)' - ); + if (installPlugin) { + p.log.info('Launching opencode-auth-sync setup...'); + const proc = Bun.spawn(['bunx', '@activade/opencode-auth-sync'], { + stdio: ['inherit', 'inherit', 'inherit'], + }); + await proc.exited; + + p.note( + `Commit and push the workflow files`, + 'Next steps' + ); + } else { + p.note( + `${color.cyan('1.')} Export your OpenCode auth as a secret:\n ${color.dim('gh secret set OPENCODE_AUTH < ~/.local/share/opencode/auth.json')}\n\n${color.cyan('2.')} Commit and push the workflow files`, + 'Next steps (OAuth)' + ); + } } else { p.note( `${color.cyan('1.')} Add your Anthropic API key:\n ${color.dim('gh secret set ANTHROPIC_API_KEY')}\n\n${color.cyan('2.')} Commit and push the workflow files`, diff --git a/src/cli/installer.ts b/src/cli/installer.ts index a11628a..dbd93ff 100644 --- a/src/cli/installer.ts +++ b/src/cli/installer.ts @@ -5,7 +5,6 @@ import { ISSUE_LABEL, DOC_SYNC, RELEASE, - OPENCODE_AUTH, WORKFLOW_FILE_MAP, type WorkflowType, } from './templates'; @@ -15,7 +14,6 @@ const WORKFLOW_GENERATORS: Record string> = { 'issue-label': ISSUE_LABEL, 'doc-sync': DOC_SYNC, release: RELEASE, - 'opencode-auth': OPENCODE_AUTH, }; export interface ExistingFile { diff --git a/src/cli/templates/doc-sync.ts b/src/cli/templates/doc-sync.ts index a06d716..8cfe6c4 100644 --- a/src/cli/templates/doc-sync.ts +++ b/src/cli/templates/doc-sync.ts @@ -1,4 +1,4 @@ -import { ENV_OPENCODE_AUTH, ENV_API_KEY, CACHE_RESTORE_STEP } from './shared'; +import { ENV_OPENCODE_AUTH, ENV_API_KEY } from './shared'; export const DOC_SYNC = (useOAuth: boolean) => `name: Doc Sync @@ -17,7 +17,7 @@ jobs: with: ref: \${{ github.head_ref }} fetch-depth: 0 -${useOAuth ? CACHE_RESTORE_STEP : ''} + - uses: activadee/open-workflows/actions/doc-sync@main env: GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}${useOAuth ? ENV_OPENCODE_AUTH : ENV_API_KEY} diff --git a/src/cli/templates/index.ts b/src/cli/templates/index.ts index 4b11d8a..a29299b 100644 --- a/src/cli/templates/index.ts +++ b/src/cli/templates/index.ts @@ -2,14 +2,12 @@ export { PR_REVIEW } from './pr-review'; export { ISSUE_LABEL } from './issue-label'; export { DOC_SYNC } from './doc-sync'; export { RELEASE } from './release'; -export { OPENCODE_AUTH } from './opencode-auth'; -export type WorkflowType = 'review' | 'label' | 'doc-sync' | 'release' | 'opencode-auth'; +export type WorkflowType = 'review' | 'label' | 'doc-sync' | 'release'; export const WORKFLOW_FILE_MAP: Record = { review: 'pr-review', label: 'issue-label', 'doc-sync': 'doc-sync', release: 'release', - 'opencode-auth': 'opencode-auth', }; diff --git a/src/cli/templates/issue-label.ts b/src/cli/templates/issue-label.ts index 24071e5..914006f 100644 --- a/src/cli/templates/issue-label.ts +++ b/src/cli/templates/issue-label.ts @@ -1,4 +1,4 @@ -import { ENV_OPENCODE_AUTH, ENV_API_KEY, CACHE_RESTORE_STEP } from './shared'; +import { ENV_OPENCODE_AUTH, ENV_API_KEY } from './shared'; export const ISSUE_LABEL = (useOAuth: boolean) => `name: Issue Label @@ -13,7 +13,7 @@ jobs: issues: write steps: - uses: actions/checkout@v4 -${useOAuth ? CACHE_RESTORE_STEP : ''} + - uses: activadee/open-workflows/actions/issue-label@main env: GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}${useOAuth ? ENV_OPENCODE_AUTH : ENV_API_KEY} diff --git a/src/cli/templates/opencode-auth.ts b/src/cli/templates/opencode-auth.ts deleted file mode 100644 index 6606895..0000000 --- a/src/cli/templates/opencode-auth.ts +++ /dev/null @@ -1,32 +0,0 @@ -export const OPENCODE_AUTH = (_useOAuth: boolean = true) => `name: OpenCode Auth - -on: - schedule: - - cron: '0 3 * * *' - workflow_dispatch: - -jobs: - refresh: - runs-on: ubuntu-latest - steps: - - id: cache - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth-\${{ github.run_id }} - restore-keys: opencode-auth- - - - if: steps.cache.outputs.cache-hit != 'true' - run: | - mkdir -p ~/.local/share/opencode - echo '\${{ secrets.OPENCODE_AUTH }}' > ~/.local/share/opencode/auth.json - - - run: curl -fsSL https://opencode.ai/install | bash - - - run: opencode models - - - uses: actions/cache/save@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth-\${{ github.run_id }} -`; diff --git a/src/cli/templates/pr-review.ts b/src/cli/templates/pr-review.ts index 0b5fef9..ecb191f 100644 --- a/src/cli/templates/pr-review.ts +++ b/src/cli/templates/pr-review.ts @@ -1,4 +1,4 @@ -import { ENV_OPENCODE_AUTH, ENV_API_KEY, CACHE_RESTORE_STEP } from './shared'; +import { ENV_OPENCODE_AUTH, ENV_API_KEY } from './shared'; export const PR_REVIEW = (useOAuth: boolean) => `name: PR Review @@ -14,7 +14,7 @@ jobs: pull-requests: write steps: - uses: actions/checkout@v4 -${useOAuth ? CACHE_RESTORE_STEP : ''} + - uses: activadee/open-workflows/actions/pr-review@main env: GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}${useOAuth ? ENV_OPENCODE_AUTH : ENV_API_KEY} diff --git a/src/cli/templates/shared.ts b/src/cli/templates/shared.ts index b86c7cc..56fdafb 100644 --- a/src/cli/templates/shared.ts +++ b/src/cli/templates/shared.ts @@ -3,11 +3,3 @@ export const ENV_OPENCODE_AUTH = ` export const ENV_API_KEY = ` ANTHROPIC_API_KEY: \${{ secrets.ANTHROPIC_API_KEY }}`; - -export const CACHE_RESTORE_STEP = ` - - uses: actions/cache/restore@v4 - with: - path: ~/.local/share/opencode/auth.json - key: opencode-auth- - restore-keys: opencode-auth- -`; diff --git a/test/installer.test.js b/test/installer.test.js index a92afde..a6c0f1c 100644 --- a/test/installer.test.js +++ b/test/installer.test.js @@ -76,6 +76,39 @@ describe('installer workflow functionality', () => { expect(content).not.toContain('ANTHROPIC_API_KEY'); }); + it('does NOT include cache restore step for OAuth', () => { + installWorkflows({ + workflows: ['review'], + cwd: tempDir, + useOAuth: true, + }); + + const content = fs.readFileSync( + path.join(tempDir, '.github', 'workflows', 'pr-review.yml'), + 'utf-8' + ); + expect(content).not.toContain('actions/cache/restore'); + expect(content).not.toContain('opencode-auth-'); + }); + + it('creates all AI workflow types without cache steps', () => { + installWorkflows({ + workflows: ['review', 'label', 'doc-sync'], + cwd: tempDir, + useOAuth: true, + }); + + const files = ['pr-review.yml', 'issue-label.yml', 'doc-sync.yml']; + for (const file of files) { + const content = fs.readFileSync( + path.join(tempDir, '.github', 'workflows', file), + 'utf-8' + ); + expect(content).toContain('OPENCODE_AUTH'); + expect(content).not.toContain('actions/cache/restore'); + } + }); + it('skips existing files without override', () => { const workflowDir = path.join(tempDir, '.github', 'workflows'); fs.mkdirSync(workflowDir, { recursive: true });