From e2abd592225086e045f10f391e4b70104cbdd970 Mon Sep 17 00:00:00 2001
From: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
Date: Wed, 5 Aug 2026 00:30:02 -0700
Subject: [PATCH] Derive composer hooks by host context for React Doctor
Key loaded hooks and issue commands by execution-host context so
repo/host switches no longer reset derived state in effects (the
static-analysis gate). Also wire SSH-aware workspace targets and
cancel-safe submit settlement for workspace creation.
---
.../components/NewWorkspaceComposerModal.tsx | 52 +-
...k-page-workspace-composer-boundary.test.ts | 6 +-
...poserState-host-context-boundaries.test.ts | 9 +-
.../useComposerState-host-retarget.test.ts | 62 +++
src/renderer/src/hooks/useComposerState.ts | 484 +++++++++++++-----
.../lib/composer-submit-cancellation.test.ts | 44 ++
.../src/lib/composer-submit-cancellation.ts | 18 +
.../src/lib/ensure-hooks-confirmed.test.ts | 98 +++-
.../src/lib/ensure-hooks-confirmed.ts | 173 +++++--
.../src/lib/pending-worktree-creation.test.ts | 99 ++++
.../src/lib/pending-worktree-creation.ts | 23 +
.../lib/project-host-workspace-target.test.ts | 55 ++
.../src/lib/project-host-workspace-target.ts | 49 +-
.../lib/worktree-creation-flow-dedupe.test.ts | 110 ++++
.../src/lib/worktree-creation-flow-startup.ts | 50 ++
.../src/lib/worktree-creation-flow.ts | 73 +--
16 files changed, 1155 insertions(+), 250 deletions(-)
create mode 100644 src/renderer/src/hooks/useComposerState-host-retarget.test.ts
create mode 100644 src/renderer/src/lib/composer-submit-cancellation.test.ts
create mode 100644 src/renderer/src/lib/composer-submit-cancellation.ts
create mode 100644 src/renderer/src/lib/pending-worktree-creation.test.ts
create mode 100644 src/renderer/src/lib/worktree-creation-flow-dedupe.test.ts
create mode 100644 src/renderer/src/lib/worktree-creation-flow-startup.ts
diff --git a/src/renderer/src/components/NewWorkspaceComposerModal.tsx b/src/renderer/src/components/NewWorkspaceComposerModal.tsx
index 1631d39a355..aa46a10f7bf 100644
--- a/src/renderer/src/components/NewWorkspaceComposerModal.tsx
+++ b/src/renderer/src/components/NewWorkspaceComposerModal.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense, useCallback, useEffect, useMemo, useState } from 'react'
+import React, { Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useAppStore } from '@/store'
import { lazyWithRetry } from '@/lib/lazy-with-retry'
import {
@@ -61,42 +61,29 @@ export default function NewWorkspaceComposerModal(): React.JSX.Element | null {
const modalData = useAppStore((s) => s.modalData as ComposerModalData | undefined)
const closeModal = useAppStore((s) => s.closeModal)
- // Why: Dialog open-state transitions must be driven by the store, not a
- // mirror useState, so palette/open-modal calls feel instantaneous and the
- // modal doesn't linger with stale data after close.
- const handleOpenChange = useCallback(
- (open: boolean) => {
- if (!open) {
- closeModal()
- }
- },
- [closeModal]
- )
-
if (!visible) {
return null
}
- return (
-
- )
+ return
}
function ComposerModalBody({
modalData,
- onClose,
- onOpenChange
+ onClose
}: {
modalData: ComposerModalData
onClose: () => void
- onOpenChange: (open: boolean) => void
}): React.JSX.Element {
+ const submitCancelledRef = useRef(false)
+ const handleDismiss = useCallback(() => {
+ submitCancelledRef.current = true
+ onClose()
+ }, [onClose])
+ const isSubmissionCancelled = useCallback(() => submitCancelledRef.current, [])
+
return (
-