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
2 changes: 0 additions & 2 deletions .gitguardian.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ paths-ignore:
- '**/*.spec.tsx'
- 'temp/**'
- '**/*.md'
- '**/test/**'
- '**/__tests__/**'

# Specific files to ignore
files-ignore:
Expand Down
14 changes: 14 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ COPY --chown=node:node package.json pnpm-workspace.yaml pnpm-lock.yaml ./
COPY --chown=node:node shared/package.json ./shared/
COPY --chown=node:node backend/package.json ./backend/
COPY --chown=node:node frontend/package.json ./frontend/
COPY --chown=node:node packages/memory ./packages/memory/

RUN pnpm install --frozen-lockfile

Expand All @@ -52,8 +53,10 @@ COPY backend ./backend
COPY frontend/src ./frontend/src
COPY frontend/public ./frontend/public
COPY frontend/index.html frontend/vite.config.ts frontend/tsconfig*.json frontend/components.json frontend/eslint.config.js ./frontend/
COPY packages/memory ./packages/memory

RUN pnpm --filter frontend build
RUN pnpm --filter @opencode-manager/memory build

FROM base AS runner

Expand All @@ -80,6 +83,7 @@ ENV PORT=5003
ENV OPENCODE_SERVER_PORT=5551
ENV DATABASE_PATH=/app/data/opencode.db
ENV WORKSPACE_PATH=/workspace
ENV NODE_PATH=/opt/opencode-plugins/node_modules

COPY --from=deps --chown=node:node /app/node_modules ./node_modules
COPY --from=builder /app/shared ./shared
Expand All @@ -90,6 +94,16 @@ COPY package.json pnpm-workspace.yaml ./
RUN mkdir -p /app/backend/node_modules/@opencode-manager && \
ln -s /app/shared /app/backend/node_modules/@opencode-manager/shared

COPY --from=builder /app/packages/memory /opt/opencode-plugins/src

RUN cd /opt/opencode-plugins/src && npm install

RUN mkdir -p /opt/opencode-plugins/node_modules/@opencode-manager/memory && \
cp -r /opt/opencode-plugins/src/dist/* /opt/opencode-plugins/node_modules/@opencode-manager/memory/ && \
cp /opt/opencode-plugins/src/package.json /opt/opencode-plugins/node_modules/@opencode-manager/memory/ && \
cp /opt/opencode-plugins/src/config.json /opt/opencode-plugins/node_modules/@opencode-manager/memory/config.json 2>/dev/null || true && \
cp -r /opt/opencode-plugins/src/node_modules/* /opt/opencode-plugins/node_modules/ 2>/dev/null || true

COPY scripts/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ On first launch, you'll be prompted to create an admin account. That's it!
- **OAuth Support** - Secure OAuth login for Anthropic and GitHub Copilot
- **Custom Agents** - Create agents with custom system prompts and tool permissions
- **MCP Servers** - Add local or remote MCP servers with pre-built templates
- **Memory Plugin** - Persistent project knowledge with semantic search, planning state, and compaction awareness

### Mobile & PWA
- **Mobile-First Design** - Responsive UI optimized for mobile
Expand Down
118 changes: 118 additions & 0 deletions backend/src/db/migration-runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Database } from 'bun:sqlite'
import { logger } from '../utils/logger'

export interface Migration {
version: number
name: string
up(db: Database): void
down(db: Database): void
}

interface MigrationRecord {
version: number
name: string
applied_at: number
}

function ensureMigrationsTable(db: Database): void {
db.run(`
CREATE TABLE IF NOT EXISTS schema_migrations (
version INTEGER PRIMARY KEY,
name TEXT NOT NULL,
applied_at INTEGER NOT NULL
)
`)
}

function getAppliedVersions(db: Database): Set<number> {
const rows = db.prepare('SELECT version FROM schema_migrations ORDER BY version').all() as MigrationRecord[]
return new Set(rows.map(r => r.version))
}

function markApplied(db: Database, migration: Migration): void {
db.prepare('INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)')
.run(migration.version, migration.name, Date.now())
}

function markReverted(db: Database, version: number): void {
db.prepare('DELETE FROM schema_migrations WHERE version = ?').run(version)
}

export function migrate(db: Database, migrations: Migration[]): void {
ensureMigrationsTable(db)

const applied = getAppliedVersions(db)
const sorted = [...migrations].sort((a, b) => a.version - b.version)
const pending = sorted.filter(m => !applied.has(m.version))

if (pending.length === 0) {
logger.info('Database schema is up to date')
return
}

logger.info(`Running ${pending.length} pending migration(s)`)

for (const migration of pending) {
logger.info(`Applying migration ${migration.version}: ${migration.name}`)
db.run('BEGIN TRANSACTION')
try {
migration.up(db)
markApplied(db, migration)
db.run('COMMIT')
logger.info(`Migration ${migration.version} applied successfully`)
} catch (error) {
db.run('ROLLBACK')
logger.error(`Migration ${migration.version} failed:`, error)
throw error
}
}

logger.info('All migrations applied successfully')
}

export function rollback(db: Database, migrations: Migration[], targetVersion?: number): void {
ensureMigrationsTable(db)

const applied = getAppliedVersions(db)
const sorted = [...migrations]
.filter(m => applied.has(m.version))
.sort((a, b) => b.version - a.version)

if (sorted.length === 0) {
logger.info('No migrations to rollback')
return
}

const latest = sorted[0]
if (!latest) {
logger.info('No migrations to rollback')
return
}
const target = targetVersion ?? latest.version - 1

const toRevert = sorted.filter(m => m.version > target)

if (toRevert.length === 0) {
logger.info('No migrations to rollback')
return
}

logger.info(`Rolling back ${toRevert.length} migration(s) to version ${target}`)

for (const migration of toRevert) {
logger.info(`Reverting migration ${migration.version}: ${migration.name}`)
db.run('BEGIN TRANSACTION')
try {
migration.down(db)
markReverted(db, migration.version)
db.run('COMMIT')
logger.info(`Migration ${migration.version} reverted successfully`)
} catch (error) {
db.run('ROLLBACK')
logger.error(`Rollback of migration ${migration.version} failed:`, error)
throw error
}
}

logger.info('Rollback completed successfully')
}
188 changes: 0 additions & 188 deletions backend/src/db/migrations.ts

This file was deleted.

Loading