Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
00582a5
feat: add 9Router provider and first-run onboarding wizard
johnnykang101 Mar 26, 2026
477e13c
fix: remove Paperclip references from 9Router dialog
johnnykang101 Mar 26, 2026
d39610c
fix: 9Router is URL-only, no API key required
johnnykang101 Mar 26, 2026
c700bfb
feat: dynamic model discovery for 9Router provider
johnnykang101 Mar 26, 2026
30f6553
ux: rename Fetch Models to Test Connection, show connection status
johnnykang101 Mar 26, 2026
ad55ab0
fix: resolve TypeScript errors in onboarding and 9Router dialog
johnnykang101 Mar 26, 2026
b7ae155
feat: add opencode onboard CLI command
johnnykang101 Mar 26, 2026
daeb5d1
chore: add onboard script for local dev testing
johnnykang101 Mar 26, 2026
f48e40a
fix: add provider to enabled_providers when onboarding
johnnykang101 Mar 26, 2026
c49c15d
ci: add CI and CD workflows for trunk-based development
johnnykang101 Mar 26, 2026
ae40cd7
ci: add weekly upstream sync workflow
johnnykang101 Mar 26, 2026
aa59bae
ci: use cb-v prefix for CoBuilder releases to avoid upstream tag coll…
johnnykang101 Mar 26, 2026
06050c6
feat: rename CLI to cobuilder + binary release pipeline + install.sh
johnnykang101 Mar 26, 2026
0986dcc
ci: generate commit-based release notes scoped to cb-v tags
johnnykang101 Mar 26, 2026
2bc6006
ci: clean release notes following Keep a Changelog best practices
johnnykang101 Mar 26, 2026
a999f54
feat: add security module inspired by OpenFang security architecture
johnnykang101 Mar 26, 2026
7bac0dc
fix: create release before build so binary upload finds existing release
johnnykang101 Mar 26, 2026
52d85ba
feat: add auto-dream crash recovery
johnnykang101 Mar 26, 2026
2c9516e
fix: use COBUILDER_RELEASE_TAG env var for binary upload
johnnykang101 Mar 26, 2026
9040c1b
feat: implement cross-session memory system
johnnykang101 Mar 26, 2026
747c9ab
docs: rewrite README for CoBuilder with enterprise features and insta…
johnnykang101 Mar 26, 2026
ad45a8a
docs: polish README with prose-first layout and detailed security exp…
johnnykang101 Mar 26, 2026
dd69fd6
assets: add CoBuilder logo SVG and fix README image path
johnnykang101 Mar 26, 2026
041f29c
docs: remove redundant CoBuilder heading below logo wordmark
johnnykang101 Mar 26, 2026
37d05a1
assets: add Jindo dog mascot SVG for CoBuilder
johnnykang101 Mar 26, 2026
d0f0f50
assets: redesign mascot as digital terminal-style holographic Jindo
johnnykang101 Mar 26, 2026
fb68e9f
assets: redesign mascot as pixel art Jindo matching CobuilderLabs org…
johnnykang101 Mar 26, 2026
2f4a532
assets: simplify mascot to Jindo headshot pixel art
johnnykang101 Mar 26, 2026
8d038d0
docs: add Jindo mascot alongside logo in README header
johnnykang101 Mar 26, 2026
d32901d
rebrand: blend Jindo mascot into logo icon
johnnykang101 Mar 26, 2026
f155577
fix: remove clipPath — GitHub SVG sanitizer strips it
johnnykang101 Mar 26, 2026
2de9351
rebrand: logo, CI/CD path filters, branch policy docs (#1)
johnnykang101 Mar 26, 2026
dfc1d79
rebrand: two-tone mascot + download section (#2)
johnnykang101 Mar 26, 2026
4dd2a3f
feat: update mascot with two-tone cream face patch
johnnykang101 Mar 26, 2026
4d45140
docs: add GitHub Copilot to AI Providers section
johnnykang101 Mar 26, 2026
5c2eecc
docs: add link and description for 9Router
johnnykang101 Mar 26, 2026
fcd049e
chore: initialize GSD project planning
johnnykang101 Mar 26, 2026
72a8784
chore: add GSD phase plans (modular security + workflow plugins)
johnnykang101 Mar 26, 2026
b7a566f
chore: fix GSD plan filenames and ROADMAP format
johnnykang101 Mar 26, 2026
3d6d05b
feat: Phase 1 — Modular Security System
johnnykang101 Mar 26, 2026
0f3fea2
feat: Phase 2 — Workflow Plugin System
johnnykang101 Mar 26, 2026
f367e27
fix: rename release assets from opencode- to cobuilder- prefix
johnnykang101 Mar 26, 2026
bb1a524
feat: Phase 3 — UI/UX Polish (13 issues fixed)
johnnykang101 Mar 26, 2026
eeeb02f
feat: Phase 4 — UI/UX Polish II
johnnykang101 Mar 26, 2026
8fd7064
fix: rename bin/opencode to bin/cobuilder and fix install.sh asset names
johnnykang101 Mar 26, 2026
f80ca55
fix: guard Config.get() against missing instance context on startup
johnnykang101 Mar 26, 2026
3fb9414
fix(build): replace pkg.name with literal "cobuilder" in Bun compile …
johnnykang101 Mar 26, 2026
16cd513
fix(install): re-attach /dev/tty so onboard works via curl | bash
johnnykang101 Mar 26, 2026
3092881
fix: rename all remaining opencode references to cobuilder
johnnykang101 Mar 26, 2026
1391a8f
fix(workflow): remove fake registry aliases pointing to non-existent …
johnnykang101 Mar 26, 2026
608a6b7
fix(workflow): restore gsd alias pointing to CobuilderLabs/gsd-workflow
johnnykang101 Mar 26, 2026
ecafcbb
feat(skills): add cobuilder skills install/list/remove command
johnnykang101 Mar 26, 2026
aad5a9e
fix(onboard): remove ralph-loop and gstack from wizard
johnnykang101 Mar 26, 2026
fc84970
feat(system-prompt): inject installed command packages into AI context
johnnykang101 Mar 26, 2026
93d707c
fix: pass OPENCODE_VERSION and OPENCODE_CHANNEL=latest to build step …
johnnykang101 Mar 26, 2026
967417e
chore: update AGENTS.md
johnnykang101 Mar 26, 2026
d3341fb
fix(install): scan recent releases for asset instead of blindly trust…
johnnykang101 Mar 26, 2026
23c8826
fix(cd): create release as draft, publish only after all binaries upl…
johnnykang101 Mar 26, 2026
afc900a
fix(install): use GitHub API asset list instead of HTTP probing to fi…
johnnykang101 Mar 26, 2026
4280c5b
fix(cd): add --publish never to electron-builder package steps
johnnykang101 Mar 26, 2026
a9b97d7
fix(install): revert to simple /releases/latest — draft-release CD fi…
johnnykang101 Mar 26, 2026
093013b
fix(deps): add react and react-dom to opencode package dependencies
johnnykang101 Mar 26, 2026
bc1b83a
fix(install): check /dev/tty is actually readable before redirecting
johnnykang101 Mar 26, 2026
3798562
fix(install): use redirect test to check /dev/tty accessibility
johnnykang101 Mar 26, 2026
c8983ba
fix(install): use stty to verify /dev/tty is a functional terminal
johnnykang101 Mar 26, 2026
9be9e21
feat: autopilot mode, Claude prefill fix, e2e tests, wizard validatio…
johnnykang101 Mar 27, 2026
5a6da70
fix: guard Config.get() in security headers middleware against missin…
johnnykang101 Mar 27, 2026
4ed3d21
feat: UX parity with Claude Code across 5 improvements
Mar 27, 2026
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
243 changes: 243 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
name: CD

on:
push:
branches: [main]
paths-ignore:
- "**.md"
- "**.txt"
- "assets/**"
- "docs/**"
- ".github/*.md"

permissions:
contents: write

jobs:
release:
name: Release
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.next_version.outputs.tag }}
semver: ${{ steps.next_version.outputs.semver }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Get latest CoBuilder tag
id: latest_tag
run: |
TAG=$(git tag --sort=-v:refname | grep -E '^cb-v[0-9]+\.[0-9]+\.[0-9]+$' | head -n1)
echo "tag=${TAG:-cb-v0.0.0}" >> "$GITHUB_OUTPUT"

- name: Determine next version and generate release notes
id: next_version
run: |
TAG="${{ steps.latest_tag.outputs.tag }}"
VERSION="${TAG#cb-v}"
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)

if git rev-parse "$TAG" >/dev/null 2>&1; then
COMMITS=$(git log "${TAG}..HEAD" --pretty=format:"%s|||%H")
else
COMMITS=$(git log --pretty=format:"%s|||%H")
fi

SUBJECTS=$(echo "$COMMITS" | cut -d'|' -f1)

# Determine version bump
if echo "$SUBJECTS" | grep -qE '^.+(\(.+\))?!:|^BREAKING CHANGE'; then
MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0
elif echo "$SUBJECTS" | grep -qE '^feat(\(.+\))?:'; then
MINOR=$((MINOR + 1)); PATCH=0
else
PATCH=$((PATCH + 1))
fi

NEXT_TAG="cb-v${MAJOR}.${MINOR}.${PATCH}"
NEXT_DISPLAY="v${MAJOR}.${MINOR}.${PATCH}"
RELEASE_DATE=$(date -u +"%Y-%m-%d")

echo "tag=${NEXT_TAG}" >> "$GITHUB_OUTPUT"
echo "display=${NEXT_DISPLAY}" >> "$GITHUB_OUTPUT"
echo "semver=${MAJOR}.${MINOR}.${PATCH}" >> "$GITHUB_OUTPUT"
echo "prev_tag=${TAG}" >> "$GITHUB_OUTPUT"

# Strip conventional commit prefix and capitalize first letter
strip_prefix() {
echo "$1" | sed -E 's/^(feat|fix|chore|ci|docs|refactor|perf|test|style|build|revert)(\([^)]+\))?!?:[[:space:]]*//' | sed 's/\(.\)/\u\1/'
}

BREAKING=""
ADDED=""
FIXED=""
CHANGED=""
SECURITY=""

while IFS='|||' read -r subject hash; do
[[ -z "$subject" ]] && continue
CLEAN=$(strip_prefix "$subject")
if echo "$subject" | grep -qE '^.+(\(.+\))?!:|^BREAKING CHANGE'; then
BREAKING="${BREAKING}"$'\n'"- ${CLEAN}"
elif echo "$subject" | grep -qE '^feat(\(.+\))?:'; then
ADDED="${ADDED}"$'\n'"- ${CLEAN}"
elif echo "$subject" | grep -qE '^fix(\(.+\))?:'; then
FIXED="${FIXED}"$'\n'"- ${CLEAN}"
elif echo "$subject" | grep -qE '^(perf|refactor)(\(.+\))?:'; then
CHANGED="${CHANGED}"$'\n'"- ${CLEAN}"
elif echo "$subject" | grep -qE '^(security|sec)(\(.+\))?:'; then
SECURITY="${SECURITY}"$'\n'"- ${CLEAN}"
else
CHANGED="${CHANGED}"$'\n'"- ${CLEAN}"
fi
done <<< "$COMMITS"

NOTES="## CoBuilder ${NEXT_DISPLAY} — ${RELEASE_DATE}"$'\n'
[[ -n "$BREAKING" ]] && NOTES+=$'\n'"### ⚠️ Breaking Changes"$'\n'"${BREAKING}"$'\n'
[[ -n "$SECURITY" ]] && NOTES+=$'\n'"### 🔒 Security"$'\n'"${SECURITY}"$'\n'
[[ -n "$ADDED" ]] && NOTES+=$'\n'"### Added"$'\n'"${ADDED}"$'\n'
[[ -n "$FIXED" ]] && NOTES+=$'\n'"### Fixed"$'\n'"${FIXED}"$'\n'
[[ -n "$CHANGED" ]] && NOTES+=$'\n'"### Changed"$'\n'"${CHANGED}"$'\n'
NOTES+=$'\n'"**Full Changelog**: https://github.com/CobuilderLabs/opencode/compare/${TAG}...${NEXT_TAG}"

echo "$NOTES" > /tmp/release-notes.md
cat /tmp/release-notes.md
echo "Next release: ${NEXT_TAG}"

- name: Update package version
run: |
cd packages/opencode
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ steps.next_version.outputs.semver }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

# Create release BEFORE build so build.ts can upload assets to it via gh release upload
- name: Create GitHub release (draft)
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ steps.next_version.outputs.tag }}" \
--title "CoBuilder ${{ steps.next_version.outputs.display }}" \
--notes-file /tmp/release-notes.md \
--draft

- name: Build and upload binaries
env:
OPENCODE_RELEASE: "1"
OPENCODE_VERSION: ${{ steps.next_version.outputs.semver }}
OPENCODE_CHANNEL: latest
COBUILDER_RELEASE_TAG: ${{ steps.next_version.outputs.tag }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: CobuilderLabs/opencode
run: |
cd packages/opencode
bun run build

- name: Publish release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release edit "${{ steps.next_version.outputs.tag }}" \
--draft=false \
--latest \
--repo CobuilderLabs/opencode

desktop-linux:
name: Desktop (Linux)
needs: release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Set desktop version
run: |
cd packages/desktop-electron
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ needs.release.outputs.semver }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

- name: Build
run: cd packages/desktop-electron && bun run build
env:
OPENCODE_CHANNEL: prod

- name: Package
run: cd packages/desktop-electron && bun run package:linux -- --publish never
env:
OPENCODE_CHANNEL: prod

- name: Upload to release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ needs.release.outputs.tag }}" \
packages/desktop-electron/dist/*.AppImage \
packages/desktop-electron/dist/*.deb \
packages/desktop-electron/dist/*.rpm \
--repo CobuilderLabs/opencode --clobber

desktop-windows:
name: Desktop (Windows)
needs: release
runs-on: windows-latest
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Set desktop version
run: |
cd packages/desktop-electron
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
pkg.version = '${{ needs.release.outputs.semver }}';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
"

- name: Build
run: cd packages/desktop-electron && bun run build
env:
OPENCODE_CHANNEL: prod

- name: Package
run: cd packages/desktop-electron && bun run package:win -- --publish never
env:
OPENCODE_CHANNEL: prod

- name: Upload to release
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "${{ needs.release.outputs.tag }}" \
packages/desktop-electron/dist/*.exe \
--repo CobuilderLabs/opencode --clobber
93 changes: 93 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
name: CI

on:
pull_request:
branches: [main]
paths-ignore:
- "**.md"
- "**.txt"
- "assets/**"
- "docs/**"
- ".github/*.md"

concurrency:
group: ci-${{ github.head_ref }}
cancel-in-progress: true

jobs:
typecheck:
name: Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"
- run: bun install --frozen-lockfile
- run: bun run typecheck

lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"
- run: bun install --frozen-lockfile
- run: bun run --if-present lint

audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"
- run: bun install --frozen-lockfile
- name: Audit dependencies
run: bun audit --audit-level moderate 2>/dev/null || npm audit --audit-level moderate
continue-on-error: true # informational until baseline established

secret-scan:
name: Secret Scanning
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.pull_request.base.sha }}
head: ${{ github.event.pull_request.head.sha }}
extra_args: --only-verified

sast:
name: SAST (CodeQL)
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

unit-test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.11"
- run: bun install --frozen-lockfile
- name: Run tests
run: bun test --timeout 30000
continue-on-error: true # informational until test suite is built out
26 changes: 26 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: E2E

on:
# Run automatically after a successful CD release
workflow_run:
workflows: [CD]
types: [completed]
branches: [main]
# Also allow manual runs
workflow_dispatch:

jobs:
e2e:
name: End-to-end tests
# Only run if CD succeeded (or on manual trigger)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install test dependencies
run: sudo apt-get update -qq && sudo apt-get install -y -qq expect git curl

- name: Run E2E test suite
run: bash test-e2e.sh
timeout-minutes: 10
Loading
Loading