Repository navigation
feat(clients): step a new thread to the next machine from the keyboard #15391
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9a71b74
419e383
8514668
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; | ||
| import { Alert } from "react-native"; | ||
|
|
||
| import type { | ||
| EnvironmentId, | ||
|
|
@@ -44,6 +45,7 @@ import { scopedProjectKey } from "../../lib/scopedEntities"; | |
| import { appAtomRegistry } from "../../state/atom-registry"; | ||
| import { projectEnvironment } from "../../state/projects"; | ||
| import { useEnvironmentQuery } from "../../state/query"; | ||
| import { useAtomCommand } from "../../state/use-atom-command"; | ||
| import { | ||
| appendComposerDraftAttachments, | ||
| type ComposerDraftInsertion, | ||
|
|
@@ -90,6 +92,10 @@ import { | |
| useSavedRemoteConnections, | ||
| } from "../../state/use-remote-environment-registry"; | ||
| import { availableScratchWorkspaceRoot } from "@t3tools/client-runtime/operations/projects"; | ||
| import { | ||
| isAtomCommandInterrupted, | ||
| squashAtomCommandFailure, | ||
| } from "@t3tools/client-runtime/state/runtime"; | ||
| import { isScratchProject } from "@t3tools/client-runtime/state/projects"; | ||
| import { EnvironmentProject } from "@t3tools/client-runtime/state/shell"; | ||
| import { type VcsRef } from "@t3tools/client-runtime/state/vcs"; | ||
|
|
@@ -201,6 +207,13 @@ type NewTaskFlowContextValue = { | |
| */ | ||
| readonly openDraft: (draftKey: string) => boolean; | ||
| readonly selectEnvironment: (environmentId: EnvironmentId) => void; | ||
| /** | ||
| * Moves the draft to another machine. A draft without a project resolves to | ||
| * that machine's "No project" folder first, creating it when needed. | ||
| */ | ||
| readonly switchEnvironment: (environmentId: EnvironmentId) => Promise<boolean>; | ||
| /** The machine a switch in progress is heading to. */ | ||
| readonly switchingToEnvironmentId: EnvironmentId | null; | ||
| readonly setSelectedModelKey: ( | ||
| key: string | null, | ||
| options?: ReadonlyArray<ProviderOptionSelection>, | ||
|
|
@@ -798,6 +811,53 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { | |
| [projects, selectedProject, carryDraftContentTo], | ||
| ); | ||
|
|
||
| const openScratch = useAtomCommand(projectEnvironment.openScratch, { reportFailure: false }); | ||
| const [switchingToEnvironmentId, setSwitchingToEnvironmentId] = useState<EnvironmentId | null>( | ||
| null, | ||
| ); | ||
| // The latest switch wins: a slower, earlier one must not retarget the draft. | ||
| const latestSwitchRef = useRef<object | null>(null); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 馃煛 Medium A completed 馃殌 Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| const switchEnvironment = useCallback( | ||
| async (environmentId: EnvironmentId): Promise<boolean> => { | ||
| if (environmentId === selectedEnvironmentId) { | ||
| latestSwitchRef.current = null; | ||
| setSwitchingToEnvironmentId(null); | ||
| return true; | ||
| } | ||
| if (!isScratchDraft) { | ||
| selectEnvironment(environmentId); | ||
| return true; | ||
| } | ||
| const request = {}; | ||
| latestSwitchRef.current = request; | ||
| setSwitchingToEnvironmentId(environmentId); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 馃煛 Medium Rapid 馃殌 Reply "fix it for me" or copy this AI Prompt for your agent: |
||
| try { | ||
| const result = await openScratch({ environmentId, input: {} }); | ||
| if (latestSwitchRef.current !== request) return false; | ||
| if (result._tag === "Success") { | ||
| setProject(result.value); | ||
| return true; | ||
| } | ||
| if (!isAtomCommandInterrupted(result)) { | ||
| const error = squashAtomCommandFailure(result); | ||
| Alert.alert( | ||
| "Could not switch machine", | ||
| error instanceof Error | ||
| ? error.message | ||
| : "The folder for threads without a project could not be created.", | ||
| ); | ||
| } | ||
| return false; | ||
| } finally { | ||
| if (latestSwitchRef.current === request) { | ||
| latestSwitchRef.current = null; | ||
| setSwitchingToEnvironmentId(null); | ||
| } | ||
| } | ||
| }, | ||
| [isScratchDraft, openScratch, selectEnvironment, selectedEnvironmentId, setProject], | ||
| ); | ||
|
|
||
| const setWorkspaceMode = useCallback( | ||
| (mode: WorkspaceMode) => { | ||
| if (!selectedProjectDraftKey) { | ||
|
|
@@ -1244,6 +1304,8 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { | |
| setProject, | ||
| openDraft, | ||
| selectEnvironment, | ||
| switchEnvironment, | ||
| switchingToEnvironmentId, | ||
| setSelectedModelKey, | ||
| setWorkspaceMode, | ||
| selectBranch, | ||
|
|
@@ -1310,6 +1372,8 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { | |
| openDraft, | ||
| selectBranch, | ||
| selectEnvironment, | ||
| switchEnvironment, | ||
| switchingToEnvironmentId, | ||
| setInteractionMode, | ||
| setPrompt, | ||
| setRuntimeMode, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
馃煛 Medium
t3nativecontrols/T3KeyboardCommandsModule.kt:44Ctrl+Alt+Hdoes not cycle hosts because this branch only matchesCtrl+Shift+H; the documented shortcut falls through, while the unintended shortcut is consumed. Matchevent.isAltPressedinstead of requiring Shift forcycleHost.馃殌 Reply "fix it for me" or copy this AI Prompt for your agent: