feat(tui): add Claude Code-style --fork flag to duplicate sessions before continuing (resolves #11137) (#11340)
This commit is contained in:
@@ -250,7 +250,8 @@ function App() {
|
||||
})
|
||||
local.model.set({ providerID, modelID }, { recent: true })
|
||||
}
|
||||
if (args.sessionID) {
|
||||
// Handle --session without --fork immediately (fork is handled in createEffect below)
|
||||
if (args.sessionID && !args.fork) {
|
||||
route.navigate({
|
||||
type: "session",
|
||||
sessionID: args.sessionID,
|
||||
@@ -268,10 +269,36 @@ function App() {
|
||||
.find((x) => x.parentID === undefined)?.id
|
||||
if (match) {
|
||||
continued = true
|
||||
route.navigate({ type: "session", sessionID: match })
|
||||
if (args.fork) {
|
||||
sdk.client.session.fork({ sessionID: match }).then((result) => {
|
||||
if (result.data?.id) {
|
||||
route.navigate({ type: "session", sessionID: result.data.id })
|
||||
} else {
|
||||
toast.show({ message: "Failed to fork session", variant: "error" })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
route.navigate({ type: "session", sessionID: match })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Handle --session with --fork: wait for sync to be fully complete before forking
|
||||
// (session list loads in non-blocking phase for --session, so we must wait for "complete"
|
||||
// to avoid a race where reconcile overwrites the newly forked session)
|
||||
let forked = false
|
||||
createEffect(() => {
|
||||
if (forked || sync.status !== "complete" || !args.sessionID || !args.fork) return
|
||||
forked = true
|
||||
sdk.client.session.fork({ sessionID: args.sessionID }).then((result) => {
|
||||
if (result.data?.id) {
|
||||
route.navigate({ type: "session", sessionID: result.data.id })
|
||||
} else {
|
||||
toast.show({ message: "Failed to fork session", variant: "error" })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
createEffect(
|
||||
on(
|
||||
() => sync.status === "complete" && sync.data.provider.length === 0,
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface Args {
|
||||
prompt?: string
|
||||
continue?: boolean
|
||||
sessionID?: string
|
||||
fork?: boolean
|
||||
}
|
||||
|
||||
export const { use: useArgs, provider: ArgsProvider } = createSimpleContext({
|
||||
|
||||
@@ -64,6 +64,10 @@ export const TuiThreadCommand = cmd({
|
||||
type: "string",
|
||||
describe: "session id to continue",
|
||||
})
|
||||
.option("fork", {
|
||||
type: "boolean",
|
||||
describe: "fork the session when continuing (use with --continue or --session)",
|
||||
})
|
||||
.option("prompt", {
|
||||
type: "string",
|
||||
describe: "prompt to use",
|
||||
@@ -73,6 +77,11 @@ export const TuiThreadCommand = cmd({
|
||||
describe: "agent to use",
|
||||
}),
|
||||
handler: async (args) => {
|
||||
if (args.fork && !args.continue && !args.session) {
|
||||
UI.error("--fork requires --continue or --session")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Resolve relative paths against PWD to preserve behavior when using --cwd flag
|
||||
const baseCwd = process.env.PWD ?? process.cwd()
|
||||
const cwd = args.project ? path.resolve(baseCwd, args.project) : process.cwd()
|
||||
@@ -150,6 +159,7 @@ export const TuiThreadCommand = cmd({
|
||||
agent: args.agent,
|
||||
model: args.model,
|
||||
prompt,
|
||||
fork: args.fork,
|
||||
},
|
||||
onExit: async () => {
|
||||
await client.call("shutdown", undefined)
|
||||
|
||||
Reference in New Issue
Block a user