mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-11-11 17:00:22 +00:00
* feat(ctrl-w): add ps-node + windows-process-tree + tsx deps for close-priority feature * fix(ctrl-w): drop ps-node dep and add windows-process-tree to asarUnpack Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): add ptyProcessTree bridge with per-platform child-process enumeration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): ptyProcessTree uses args= for full command + warns on pid overwrite - Replace `comm=` with `args=` in defaultListPosix so the full command line is captured on both macOS (BSD ps) and Linux (GNU ps), avoiding the 15-char TASK_COMM_LEN truncation. - Add console.warn in registerPid when the same sessionId is overwritten with a different pid, making the race condition visible in logs. - Add test: registerPid warns exactly once on a pid change, not on a same-pid re-registration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): register local PTY pid with ptyProcessTree on spawn/exit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): unregister pids in cleanupAllSessions to match per-delete invariant Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): add IPC handlers for pty child processes and confirm-close dialog Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): guard BrowserWindow.fromWebContents null and document dialog dismiss contract Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): expose ptyGetChildProcesses and confirmCloseBusy on window.netcatty Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): add i18n strings for close-busy-terminal dialog Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): add resolveCloseIntent pure function with 8 unit tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): expose handleCloseSidePanel via ref to App.tsx Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): wire resolveCloseIntent + local-shell busy confirmation into closeTab hotkey Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(ctrl-w): add re-entrancy guard, aggregate busy count, sync sidebar ref, dedupe intent branches Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ctrl-w): auto-close workspace when its last session is closed Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): sidebar close wins over focused terminal in priority chain Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): sidebar priority applies to single-session tabs too, not just workspaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ctrl-w): compute empty-workspace auto-close outside setSessions updater Addresses Codex P2 on #739: React 18+ does not guarantee updater execution timing under concurrent scheduling. Moving the decision outside the updater makes the microtask queue deterministic. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
export type CloseIntent =
|
|
| { kind: 'closeTerminal'; sessionId: string }
|
|
| { kind: 'closeSidePanel' }
|
|
| { kind: 'closeWorkspace'; workspaceId: string }
|
|
| { kind: 'closeSingleTab'; sessionId: string }
|
|
| { kind: 'noop' };
|
|
|
|
export interface ResolveCloseInput {
|
|
activeTabId: string | null;
|
|
workspace: { id: string; focusedSessionId?: string } | null;
|
|
sessionForTab: { id: string } | null;
|
|
activeSidePanelTab: string | null;
|
|
focusIsInsideTerminal: boolean;
|
|
}
|
|
|
|
export function resolveCloseIntent(input: ResolveCloseInput): CloseIntent {
|
|
const { activeTabId, workspace, sessionForTab, activeSidePanelTab, focusIsInsideTerminal } = input;
|
|
|
|
if (!activeTabId) return { kind: 'noop' };
|
|
|
|
// Sidebar always wins — applies to any tab type (workspace, single-session, etc.).
|
|
// Modals take priority over this but are intercepted upstream in App.tsx before the
|
|
// hotkey reaches resolveCloseIntent.
|
|
if (activeSidePanelTab !== null) {
|
|
return { kind: 'closeSidePanel' };
|
|
}
|
|
|
|
if (sessionForTab && !workspace) {
|
|
return { kind: 'closeSingleTab', sessionId: sessionForTab.id };
|
|
}
|
|
|
|
if (!workspace) {
|
|
// e.g. 'vault', 'sftp', or any non-closable pinned tab
|
|
return { kind: 'noop' };
|
|
}
|
|
|
|
const focusedSessionId = workspace.focusedSessionId;
|
|
if (focusedSessionId && focusIsInsideTerminal) {
|
|
return { kind: 'closeTerminal', sessionId: focusedSessionId };
|
|
}
|
|
|
|
return { kind: 'closeWorkspace', workspaceId: workspace.id };
|
|
}
|