Merge branch 'dev' into feat/canceled-prompts-in-history

This commit is contained in:
Ariane Emory
2026-02-17 00:09:51 -05:00
98 changed files with 1550 additions and 718 deletions
+51 -1
View File
@@ -4,6 +4,8 @@ import { Database } from "../../storage/db"
import { Database as BunDatabase } from "bun:sqlite"
import { UI } from "../ui"
import { cmd } from "./cmd"
import { JsonMigration } from "../../storage/json-migration"
import { EOL } from "os"
const QueryCommand = cmd({
command: "$0 [query]",
@@ -58,11 +60,59 @@ const PathCommand = cmd({
},
})
const MigrateCommand = cmd({
command: "migrate",
describe: "migrate JSON data to SQLite (merges with existing data)",
handler: async () => {
const sqlite = new BunDatabase(Database.Path)
const tty = process.stderr.isTTY
const width = 36
const orange = "\x1b[38;5;214m"
const muted = "\x1b[0;2m"
const reset = "\x1b[0m"
let last = -1
if (tty) process.stderr.write("\x1b[?25l")
try {
const stats = await JsonMigration.run(sqlite, {
progress: (event) => {
const percent = Math.floor((event.current / event.total) * 100)
if (percent === last) return
last = percent
if (tty) {
const fill = Math.round((percent / 100) * width)
const bar = `${"■".repeat(fill)}${"・".repeat(width - fill)}`
process.stderr.write(
`\r${orange}${bar} ${percent.toString().padStart(3)}%${reset} ${muted}${event.current}/${event.total}${reset} `,
)
} else {
process.stderr.write(`sqlite-migration:${percent}${EOL}`)
}
},
})
if (tty) process.stderr.write("\n")
if (tty) process.stderr.write("\x1b[?25h")
else process.stderr.write(`sqlite-migration:done${EOL}`)
UI.println(
`Migration complete: ${stats.projects} projects, ${stats.sessions} sessions, ${stats.messages} messages`,
)
if (stats.errors.length > 0) {
UI.println(`${stats.errors.length} errors occurred during migration`)
}
} catch (err) {
if (tty) process.stderr.write("\x1b[?25h")
UI.error(`Migration failed: ${err instanceof Error ? err.message : String(err)}`)
process.exit(1)
} finally {
sqlite.close()
}
},
})
export const DbCommand = cmd({
command: "db",
describe: "database tools",
builder: (yargs: Argv) => {
return yargs.command(QueryCommand).command(PathCommand).demandCommand()
return yargs.command(QueryCommand).command(PathCommand).command(MigrateCommand).demandCommand()
},
handler: () => {},
})
+25 -1
View File
@@ -38,10 +38,34 @@ function pagerCmd(): string[] {
export const SessionCommand = cmd({
command: "session",
describe: "manage sessions",
builder: (yargs: Argv) => yargs.command(SessionListCommand).demandCommand(),
builder: (yargs: Argv) => yargs.command(SessionListCommand).command(SessionDeleteCommand).demandCommand(),
async handler() {},
})
export const SessionDeleteCommand = cmd({
command: "delete <sessionID>",
describe: "delete a session",
builder: (yargs: Argv) => {
return yargs.positional("sessionID", {
describe: "session ID to delete",
type: "string",
demandOption: true,
})
},
handler: async (args) => {
await bootstrap(process.cwd(), async () => {
try {
await Session.get(args.sessionID)
} catch {
UI.error(`Session not found: ${args.sessionID}`)
process.exit(1)
}
await Session.remove(args.sessionID)
UI.println(UI.Style.TEXT_SUCCESS_BOLD + `Session ${args.sessionID} deleted` + UI.Style.TEXT_NORMAL)
})
},
})
export const SessionListCommand = cmd({
command: "list",
describe: "list sessions",
+21 -1
View File
@@ -1,4 +1,5 @@
import { cmd } from "../cmd"
import { UI } from "@/cli/ui"
import { tui } from "./app"
import { win32DisableProcessedInput, win32InstallCtrlCGuard } from "./win32"
@@ -16,11 +17,20 @@ export const AttachCommand = cmd({
type: "string",
description: "directory to run in",
})
.option("continue", {
alias: ["c"],
describe: "continue the last session",
type: "boolean",
})
.option("session", {
alias: ["s"],
type: "string",
describe: "session id to continue",
})
.option("fork", {
type: "boolean",
describe: "fork the session when continuing (use with --continue or --session)",
})
.option("password", {
alias: ["p"],
type: "string",
@@ -31,6 +41,12 @@ export const AttachCommand = cmd({
try {
win32DisableProcessedInput()
if (args.fork && !args.continue && !args.session) {
UI.error("--fork requires --continue or --session")
process.exitCode = 1
return
}
const directory = (() => {
if (!args.dir) return undefined
try {
@@ -49,7 +65,11 @@ export const AttachCommand = cmd({
})()
await tui({
url: args.url,
args: { sessionID: args.session },
args: {
continue: args.continue,
sessionID: args.session,
fork: args.fork,
},
directory,
headers,
})
@@ -247,7 +247,8 @@ export function Autocomplete(props: {
const width = props.anchor().width - 4
options.push(
...sortedFiles.map((item): AutocompleteOption => {
const fullPath = `${process.cwd()}/${item}`
const baseDir = (sync.data.path.directory || process.cwd()).replace(/\/+$/, "")
const fullPath = `${baseDir}/${item}`
const urlObj = pathToFileURL(fullPath)
let filename = item
if (lineRange && !item.endsWith("/")) {
@@ -2,7 +2,7 @@ import { createMemo, createSignal, For } from "solid-js"
import { DEFAULT_THEMES, useTheme } from "@tui/context/theme"
const themeCount = Object.keys(DEFAULT_THEMES).length
const themeTip = `Use {highlight}/theme{/highlight} or {highlight}Ctrl+X T{/highlight} to switch between ${themeCount} built-in themes`
const themeTip = `Use {highlight}/themes{/highlight} or {highlight}Ctrl+X T{/highlight} to switch between ${themeCount} built-in themes`
type TipPart = { text: string; highlight: boolean }
@@ -126,7 +126,7 @@ const TIPS = [
"Use {highlight}{file:path}{/highlight} to include file contents in config values",
"Use {highlight}instructions{/highlight} in config to load additional rules files",
"Set agent {highlight}temperature{/highlight} from 0.0 (focused) to 1.0 (creative)",
"Configure {highlight}maxSteps{/highlight} to limit agentic iterations per request",
"Configure {highlight}steps{/highlight} to limit agentic iterations per request",
'Set {highlight}"tools": {"bash": false}{/highlight} to disable specific tools',
'Set {highlight}"mcp_*": false{/highlight} to disable all tools from an MCP server',
"Override global tool settings per agent configuration",
@@ -147,7 +147,6 @@ const TIPS = [
"Commit your project's {highlight}AGENTS.md{/highlight} file to Git for team sharing",
"Use {highlight}/review{/highlight} to review uncommitted changes, branches, or PRs",
"Run {highlight}/help{/highlight} or {highlight}Ctrl+X H{/highlight} to show the help dialog",
"Use {highlight}/details{/highlight} to toggle tool execution details visibility",
"Use {highlight}/rename{/highlight} to rename the current session",
"Press {highlight}Ctrl+Z{/highlight} to suspend the terminal and return to your shell",
]