Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
2072471
feat: add app lock password verifier
Ryanisgood Jun 17, 2026
b0fafed
feat: persist app lock settings
Ryanisgood Jun 17, 2026
e2c2550
feat: add app lock lifecycle state
Ryanisgood Jun 17, 2026
4d54b12
feat: add app lock overlay
Ryanisgood Jun 17, 2026
b284774
feat: add app lock settings UI
Ryanisgood Jun 17, 2026
6d26227
fix: reschedule app lock idle checks
Ryanisgood Jun 17, 2026
34d3d7b
fix: lock app when main window reopens
Ryanisgood Jun 17, 2026
02388f0
fix: gate app routes before startup unlock
Ryanisgood Jun 17, 2026
2afefa5
fix: delay renderer ready until app lock unlocks
Ryanisgood Jun 17, 2026
faa683c
fix: route app lock bridge through state hook
Ryanisgood Jun 17, 2026
4089080
feat: unify app lock runtime ownership
Ryanisgood Jun 23, 2026
15b729e
fix: recreate crashed window on app lock reopen
Ryanisgood Jun 23, 2026
091ea93
test: cover app lock renderer runtime flows
Ryanisgood Jun 23, 2026
984328b
test: extend app lock renderer recovery coverage
Ryanisgood Jun 23, 2026
ad90aa9
test: harden app lock recovery regressions
Ryanisgood Jun 23, 2026
fad39c0
test: cover app lock password change authority
Ryanisgood Jun 23, 2026
8f35fe4
test: cover shared app lock idle activity
Ryanisgood Jun 23, 2026
a0581b5
test: tighten app lock idle activity timing
Ryanisgood Jun 23, 2026
a4e8958
test: cover app lock minimize preservation
Ryanisgood Jun 23, 2026
8528ec9
test: tighten app lock minimize preservation
Ryanisgood Jun 23, 2026
cc20ca0
fix: cancel tray reveal stale app lock hide
Ryanisgood Jun 23, 2026
6571c78
feat: clarify app lock setup flow
Ryanisgood Jun 23, 2026
559f2a4
fix: clarify app lock password lifecycle
Ryanisgood Jun 23, 2026
43f8a39
chore: simplify app lock setup copy
Ryanisgood Jun 23, 2026
86df78e
feat: allow disabling idle app lock
Ryanisgood Jun 23, 2026
c186258
feat: add app lock reset easter egg
Ryanisgood Jun 24, 2026
5be97aa
merge: sync upstream main
Ryanisgood Jun 24, 2026
564095d
fix: stabilize app lock ci checks
Ryanisgood Jun 24, 2026
38f318b
feat: persist app lock system unlock setting
Ryanisgood Jun 24, 2026
8a49c56
feat: add windows hello helper packaging
Ryanisgood Jun 24, 2026
4dcb06d
feat: add app lock system auth bridge
Ryanisgood Jun 24, 2026
41d3000
feat: wire app lock system unlock ipc
Ryanisgood Jun 24, 2026
751aee0
feat: expose app lock system unlock state
Ryanisgood Jun 24, 2026
ba3e76e
test: cover app lock system unlock overlay
Ryanisgood Jun 24, 2026
f6a49db
feat: add app lock system unlock setting
Ryanisgood Jun 24, 2026
0ea707f
fix: harden app lock system unlock flow
Ryanisgood Jun 24, 2026
08032b0
fix: package windows hello helper per arch
Ryanisgood Jun 24, 2026
1d3484f
fix: validate windows hello helper architecture
Ryanisgood Jun 24, 2026
a4b8388
fix: initialize msvc for windows hello helper
Ryanisgood Jun 24, 2026
41f8924
fix: streamline app lock system unlock
Ryanisgood Jun 24, 2026
46716f1
fix: refine app lock biometric unlock
Ryanisgood Jun 24, 2026
6c49baf
feat: add app lock system unlock auto prompt setting
Ryanisgood Jun 24, 2026
90db33c
Fix system app-lock availability handling
Ryanisgood Jun 29, 2026
b8bb91e
Initialize MSVC for Windows package builds
Ryanisgood Jun 29, 2026
61ef47b
Fix Windows Hello helper MSVC invocation
Ryanisgood Jun 29, 2026
e3b1547
Silence MSVC coroutine deprecation for Windows Hello helper
Ryanisgood Jun 29, 2026
17b6130
Respect Windows package arch in builder config
Ryanisgood Jun 29, 2026
54b30ba
chore: trigger CI for app lock PR
Ryanisgood Jun 30, 2026
5a3ffe1
Merge upstream/main into feature/app-lock-screen
Ryanisgood Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ jobs:
node-version: 22
cache: npm

- name: Set up MSVC developer command prompt
if: matrix.name == 'windows'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64

- name: Install deps
run: npm ci

Expand Down
52 changes: 9 additions & 43 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useAutoSync } from './application/state/useAutoSync';
import { useManagedSourceSync } from './application/state/useManagedSourceSync';
import { usePortForwardingState } from './application/state/usePortForwardingState';
import { useSessionState } from './application/state/useSessionState';
import { useSettingsState } from './application/state/useSettingsState';
import type { useSettingsState } from './application/state/useSettingsState';
import type { useAppLockState } from './application/state/useAppLockState';
import { useUpdateCheck } from './application/state/useUpdateCheck';
import { useVaultState } from './application/state/useVaultState';
import { useVaultAgentBridge } from './application/state/useVaultAgentBridge';
Expand All @@ -20,7 +21,7 @@ import {
} from './application/defaultKeyPassphrases';
import { initializeFonts } from './application/state/fontStore';
import { initializeUIFonts } from './application/state/uiFontStore';
import { I18nProvider, useI18n } from './application/i18n/I18nProvider';
import { useI18n } from './application/i18n/I18nProvider';
import { matchesKeyBinding } from './domain/models';
import { resolveGroupDefaults, applyGroupDefaults } from './domain/groupConfig';
import { upsertKnownHost } from './domain/knownHosts';
Expand Down Expand Up @@ -54,10 +55,8 @@ import {
STORAGE_KEY_DEBUG_HOTKEYS,
STORAGE_KEY_PORT_FORWARDING,
} from './infrastructure/config/storageKeys';
import { getEffectiveKnownHosts } from './infrastructure/syncHelpers';
import { ToastProvider, toast } from './components/ui/toast';
import { TooltipProvider } from './components/ui/tooltip';
import { PortForwardHostKeyDialog } from './components/port-forwarding';
import { toast } from './components/ui/toast';
import { VaultSection } from './components/VaultView';
import { KeyboardInteractiveRequest } from './components/KeyboardInteractiveModal';
import { PassphraseRequest } from './components/PassphraseModal';
Expand All @@ -79,6 +78,7 @@ initializeFonts();
initializeUIFonts();

type SettingsState = ReturnType<typeof useSettingsState>;
type AppLockState = ReturnType<typeof useAppLockState>;
type OpenSessionInNewWindowPayload = {
title?: string;
sourceSession?: TerminalSession;
Expand All @@ -89,7 +89,7 @@ const IS_DEV = import.meta.env.DEV;
const HOTKEY_DEBUG =
IS_DEV && localStorageAdapter.readString(STORAGE_KEY_DEBUG_HOTKEYS) === '1';

function App({ settings }: { settings: SettingsState }) {
function App({ settings, appLock }: { settings: SettingsState; appLock: AppLockState }) {
const { t } = useI18n();

const [isQuickSwitcherOpen, setIsQuickSwitcherOpen] = useState(false);
Expand Down Expand Up @@ -1195,44 +1195,10 @@ function App({ settings }: { settings: SettingsState }) {
resolveSessionAppearance={themeRuntime.resolveFocusedAppearance}
t={t}
/>
<AppView ctx={{ accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace, clearAndRemoveSource, clearAndRemoveSources, clearUnsavedConnectionLogs, clearSessionFontSizeOverride, closeLogView, closeSession, closeTabsBatch, copySessionWithCurrentShell, copySessionToNewWindowWithCurrentShell, closeWorkspace, connectionLogs, convertKnownHostToHost, createWorkspaceFromSessions, createWorkspaceFromTargets, createWorkspaceWithHosts, customAccent, customGroups, currentTerminalTheme, deepLinkHostDraft, deleteConnectionLog, draggingSessionId, effectiveKnownHosts, editorTabs, editorWordWrap, emptyVaultConflict, followAppTerminalTheme, clearThemeIntent: themeRuntime.clearIntent, settleManualThemeIntent: themeRuntime.settleManualIntent, pickTerminalTheme: themeRuntime.pickTheme, resolveSessionAppearance: themeRuntime.resolveFocusedAppearance, groupConfigs, handleAddKnownHost, handleConnectSerial, handleConnectToHost, handleCreateLocalTerminal, handleDefaultTerminalThemeChange, handleDeleteHost, handleEndSessionDrag, handleFollowAppTerminalThemeChange, handleHostConnectWithProtocolCheck, handleHotkeyAction, handleOpenHostFromVaultNote, handleOpenVaultHostFromChat, handleOpenVaultNoteFromChat, handleOpenVaultSectionFromChat, handleOpenVaultSnippetFromChat, handleKeyboardInteractiveCancel, handleKeyboardInteractiveSubmit, handleOpenQuickSwitcher, handleOpenSettings, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect, handleRequestCloseEditorTabRef, handleSessionStatusChange, handleSyncNowManual, handleTerminalDataCapture, handleToggleTheme, handleUpdateHostFromTerminal, hostById, hosts, hotkeyScheme, identities, importOrReuseKey, isBroadcastEnabled, isCreateWorkspaceOpen, isMacClient, isQuickSwitcherOpen, keyBindings, keyboardInteractiveQueue, keys, logViews, managedSources, navigateToSection, noteGroups, notes, openLogView, openNoteRequest, orderedTabsWithEditors, orphanSessions, passphraseQueue, protocolSelectHost, proxyProfiles, portForwardingRules, quickResults, quickSearch, removeSessionFromWorkspace, reorderWorkTabs, reorderWorkspaceSessions, resetSessionRename, resetWorkspaceRename, resolveEmptyVaultConflict, resolvedTheme, runSnippet: handleRunSnippet, sessionLogsDir, sessionLogsEnabled, sessionLogsFormat, sessionLogsTimestampsEnabled, sessionRenameTarget, sessionRenameValue, sessions, setActiveTabId, setAddToWorkspaceDialog, setDeepLinkHostDraft, setDraggingSessionId, setEditorWordWrap, setIsCreateWorkspaceOpen, setIsQuickSwitcherOpen, setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setVaultFocusRequest, setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior, sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, sshDebugLogsEnabled: settings.sshDebugLogsEnabled, startSessionRename, renameSessionInline, startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId, themeById, toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog, updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources, updateNoteGroups, updateNotes, updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateSessionFontSize, updateSessionRestoreCwd, updateSessionDynamicTitle, updateSessionCodingCliProvider, updateTerminalSetting, vaultFocusRequest, workspaceRenameTarget, workspaceRenameValue, workspaces, VaultViewContainer, SftpViewMount, TerminalLayerMount, LogViewWrapper }} />
<ScriptAutomationRoot />
<AppView ctx={{ accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace, appLockEnabled: settings.appLockSettings.enabled, clearAndRemoveSource, clearAndRemoveSources, clearUnsavedConnectionLogs, clearSessionFontSizeOverride, closeLogView, closeSession, closeTabsBatch, copySessionWithCurrentShell, copySessionToNewWindowWithCurrentShell, closeWorkspace, connectionLogs, convertKnownHostToHost, createWorkspaceFromSessions, createWorkspaceFromTargets, createWorkspaceWithHosts, customAccent, customGroups, currentTerminalTheme, deepLinkHostDraft, deleteConnectionLog, draggingSessionId, effectiveKnownHosts, editorTabs, editorWordWrap, emptyVaultConflict, followAppTerminalTheme, clearThemeIntent: themeRuntime.clearIntent, settleManualThemeIntent: themeRuntime.settleManualIntent, pickTerminalTheme: themeRuntime.pickTheme, resolveSessionAppearance: themeRuntime.resolveFocusedAppearance, groupConfigs, handleAddKnownHost, handleConnectSerial, handleConnectToHost, handleCreateLocalTerminal, handleDefaultTerminalThemeChange, handleDeleteHost, handleEndSessionDrag, handleFollowAppTerminalThemeChange, handleHostConnectWithProtocolCheck, handleHotkeyAction, handleOpenHostFromVaultNote, handleOpenVaultHostFromChat, handleOpenVaultNoteFromChat, handleOpenVaultSectionFromChat, handleOpenVaultSnippetFromChat, handleKeyboardInteractiveCancel, handleKeyboardInteractiveSubmit, handleLockApp: () => appLock.lockNow('manual'), handleOpenQuickSwitcher, handleOpenSettings, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect, handleRequestCloseEditorTabRef, handleSessionStatusChange, handleSyncNowManual, handleTerminalDataCapture, handleToggleTheme, handleUpdateHostFromTerminal, hostById, hosts, hotkeyScheme, identities, importOrReuseKey, isBroadcastEnabled, isCreateWorkspaceOpen, isMacClient, isQuickSwitcherOpen, keyBindings, keyboardInteractiveQueue, keys, logViews, managedSources, navigateToSection, noteGroups, notes, openLogView, openNoteRequest, orderedTabsWithEditors, orphanSessions, passphraseQueue, protocolSelectHost, proxyProfiles, portForwardingRules, quickResults, quickSearch, removeSessionFromWorkspace, reorderWorkTabs, reorderWorkspaceSessions, resetSessionRename, resetWorkspaceRename, resolveEmptyVaultConflict, resolvedTheme, runSnippet: handleRunSnippet, sessionLogsDir, sessionLogsEnabled, sessionLogsFormat, sessionLogsTimestampsEnabled, sessionRenameTarget, sessionRenameValue, sessions, setActiveTabId, setAddToWorkspaceDialog, setDeepLinkHostDraft, setDraggingSessionId, setEditorWordWrap, setIsCreateWorkspaceOpen, setIsQuickSwitcherOpen, setNavigateToSection, setProtocolSelectHost, setQuickSearch, setSessionRenameValue, setTerminalFontFamilyId, setTerminalFontSize, setVaultFocusRequest, setWorkspaceFocusedSession, setWorkspaceRenameValue, settings, sftpAutoOpenSidebar, sftpFollowTerminalCwd, setSftpFollowTerminalCwd, sftpAutoSync, sftpDefaultViewMode, sftpDoubleClickBehavior, sftpShowHiddenFiles, sftpUseCompressedUpload, shellHistory, snippetPackages, snippets, splitSessionWithCurrentShell, sshDebugLogsEnabled: settings.sshDebugLogsEnabled, startSessionRename, renameSessionInline, startWorkspaceRename, submitSessionRename, submitWorkspaceRename, t, terminalFontFamilyId, terminalFontSize, terminalSettings, terminalThemeId, themeById, toggleBroadcast, toggleConnectionLogSaved, toggleScriptsSidePanelRef, toggleSidePanelRef, toggleWorkspaceViewMode, unmanageSource, updateConnectionLog, updateCustomGroups, updateGroupConfigs, updateHostDistro, updateHosts, updateIdentities, updateKeys, updateKnownHosts, updateManagedSources, updateNoteGroups, updateNotes, updateProxyProfiles, updateSnippetPackages, updateSnippets, updateSplitSizes, updateSessionFontSize, updateSessionRestoreCwd, updateSessionDynamicTitle, updateSessionCodingCliProvider, updateTerminalSetting, vaultFocusRequest, workspaceRenameTarget, workspaceRenameValue, workspaces, VaultViewContainer, SftpViewMount, TerminalLayerMount, LogViewWrapper }} />
</>
);
}

function AppWithProviders() {
const isPeerSessionWindow = typeof window !== 'undefined' && window.location.hash.startsWith('#/session-window');
const settings = useSettingsState({
enableSettingsSync: !isPeerSessionWindow,
enableSystemEffects: !isPeerSessionWindow,
});

useEffect(() => {
try {
// Hide splash screen with a fade-out animation
const splash = document.getElementById('splash');
if (splash) {
splash.classList.add('fade-out');
// Remove from DOM after animation completes
setTimeout(() => splash.remove(), 200);
}
// Notify main process that renderer is ready
netcattyBridge.get()?.rendererReady?.();
} catch {
// ignore
}
}, []);

return (
<I18nProvider locale={settings.uiLanguage}>
<ToastProvider>
<TooltipProvider delayDuration={300}>
<ScriptAutomationRoot />
<App settings={settings} />
</TooltipProvider>
</ToastProvider>
</I18nProvider>
);
}

export default AppWithProviders;
export default App;
6 changes: 4 additions & 2 deletions application/app/AppView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ export function AppView({ ctx }: { ctx: AppViewContext }) {
useMainWindowInputFocusRecovery({ onPageHidden: dismissTransientOverlays });

const {
accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace,
accentMode, addShellHistoryEntry, addSessionToWorkspace, addToWorkspaceDialog, appendHostToWorkspace, appendLocalTerminalToWorkspace, appLockEnabled,
clearAndRemoveSource, clearAndRemoveSources, clearUnsavedConnectionLogs, closeLogView, closeSession, closeTabsBatch, closeWorkspace, copySessionToNewWindowWithCurrentShell, copySessionWithCurrentShell,
connectionLogs, convertKnownHostToHost, createWorkspaceFromSessions, createWorkspaceFromTargets, createWorkspaceWithHosts, customAccent,
customGroups, currentTerminalTheme, deepLinkHostDraft, deleteConnectionLog, draggingSessionId, effectiveKnownHosts, editorTabs, editorWordWrap, emptyVaultConflict,
followAppTerminalTheme,
groupConfigs, handleAddKnownHost, handleConnectSerial, handleConnectToHost, handleCreateLocalTerminal, handleDefaultTerminalThemeChange, handleDeleteHost,
handleEndSessionDrag, handleFollowAppTerminalThemeChange, handleHostConnectWithProtocolCheck, handleHotkeyAction, handleKeyboardInteractiveCancel, handleKeyboardInteractiveSubmit,
handleOpenHostFromVaultNote, handleOpenQuickSwitcher, handleOpenSettings, handleOpenVaultHostFromChat, handleOpenVaultNoteFromChat, handleOpenVaultSectionFromChat, handleOpenVaultSnippetFromChat, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect,
handleLockApp, handleOpenHostFromVaultNote, handleOpenQuickSwitcher, handleOpenSettings, handleOpenVaultHostFromChat, handleOpenVaultNoteFromChat, handleOpenVaultSectionFromChat, handleOpenVaultSnippetFromChat, handleRootContextMenu, handlePassphraseCancel, handlePassphraseSkip, handlePassphraseSubmit, handleProtocolSelect,
handleRequestCloseEditorTabRef, handleSessionStatusChange, handleSyncNowManual, handleTerminalDataCapture, handleToggleTheme, handleUpdateHostFromTerminal,
hostById, hosts, hotkeyScheme, identities, importOrReuseKey, isBroadcastEnabled, isCreateWorkspaceOpen, isMacClient, isQuickSwitcherOpen,
keyBindings, keyboardInteractiveQueue, keys, logViews, managedSources, navigateToSection, noteGroups, notes, openLogView, openNoteRequest, orderedTabsWithEditors, orphanSessions,
Expand Down Expand Up @@ -194,6 +194,8 @@ export function AppView({ ctx }: { ctx: AppViewContext }) {
onOpenQuickSwitcher={handleOpenQuickSwitcher}
onToggleTheme={handleToggleTheme}
onOpenSettings={handleOpenSettings}
onLockApp={handleLockApp}
appLockEnabled={appLockEnabled}
windowOpacity={settings.windowOpacity}
setWindowOpacity={settings.setWindowOpacity}
onSyncNow={handleSyncNowManual}
Expand Down
Loading
Loading