Skip to content

Commit fdad823

Browse files
authored
feat(cli): add db migrate command for JSON to SQLite migration (#13874)
1 parent 5cc1d60 commit fdad823

1 file changed

Lines changed: 51 additions & 1 deletion

File tree

  • packages/opencode/src/cli/cmd

packages/opencode/src/cli/cmd/db.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { Database } from "../../storage/db"
44
import { Database as BunDatabase } from "bun:sqlite"
55
import { UI } from "../ui"
66
import { cmd } from "./cmd"
7+
import { JsonMigration } from "../../storage/json-migration"
8+
import { EOL } from "os"
79

810
const QueryCommand = cmd({
911
command: "$0 [query]",
@@ -58,11 +60,59 @@ const PathCommand = cmd({
5860
},
5961
})
6062

63+
const MigrateCommand = cmd({
64+
command: "migrate",
65+
describe: "migrate JSON data to SQLite (merges with existing data)",
66+
handler: async () => {
67+
const sqlite = new BunDatabase(Database.Path)
68+
const tty = process.stderr.isTTY
69+
const width = 36
70+
const orange = "\x1b[38;5;214m"
71+
const muted = "\x1b[0;2m"
72+
const reset = "\x1b[0m"
73+
let last = -1
74+
if (tty) process.stderr.write("\x1b[?25l")
75+
try {
76+
const stats = await JsonMigration.run(sqlite, {
77+
progress: (event) => {
78+
const percent = Math.floor((event.current / event.total) * 100)
79+
if (percent === last) return
80+
last = percent
81+
if (tty) {
82+
const fill = Math.round((percent / 100) * width)
83+
const bar = `${"■".repeat(fill)}${"・".repeat(width - fill)}`
84+
process.stderr.write(
85+
`\r${orange}${bar} ${percent.toString().padStart(3)}%${reset} ${muted}${event.current}/${event.total}${reset} `,
86+
)
87+
} else {
88+
process.stderr.write(`sqlite-migration:${percent}${EOL}`)
89+
}
90+
},
91+
})
92+
if (tty) process.stderr.write("\n")
93+
if (tty) process.stderr.write("\x1b[?25h")
94+
else process.stderr.write(`sqlite-migration:done${EOL}`)
95+
UI.println(
96+
`Migration complete: ${stats.projects} projects, ${stats.sessions} sessions, ${stats.messages} messages`,
97+
)
98+
if (stats.errors.length > 0) {
99+
UI.println(`${stats.errors.length} errors occurred during migration`)
100+
}
101+
} catch (err) {
102+
if (tty) process.stderr.write("\x1b[?25h")
103+
UI.error(`Migration failed: ${err instanceof Error ? err.message : String(err)}`)
104+
process.exit(1)
105+
} finally {
106+
sqlite.close()
107+
}
108+
},
109+
})
110+
61111
export const DbCommand = cmd({
62112
command: "db",
63113
describe: "database tools",
64114
builder: (yargs: Argv) => {
65-
return yargs.command(QueryCommand).command(PathCommand).demandCommand()
115+
return yargs.command(QueryCommand).command(PathCommand).command(MigrateCommand).demandCommand()
66116
},
67117
handler: () => {},
68118
})

0 commit comments

Comments
 (0)