completly remove sandbox related code as the downstream libraries do not work with it on various os

This commit is contained in:
webdevcody
2026-01-07 08:54:14 -05:00
parent 4d4025ca06
commit 1316ead8c8
34 changed files with 589 additions and 1230 deletions

View File

@@ -7,6 +7,36 @@ import type { AutoModeEvent } from '@/types/electron';
const logger = createLogger('AutoMode');
const AUTO_MODE_SESSION_KEY = 'automaker:autoModeRunningByProjectPath';
function readAutoModeSession(): Record<string, boolean> {
try {
if (typeof window === 'undefined') return {};
const raw = window.sessionStorage?.getItem(AUTO_MODE_SESSION_KEY);
if (!raw) return {};
const parsed = JSON.parse(raw) as unknown;
if (!parsed || typeof parsed !== 'object') return {};
return parsed as Record<string, boolean>;
} catch {
return {};
}
}
function writeAutoModeSession(next: Record<string, boolean>): void {
try {
if (typeof window === 'undefined') return;
window.sessionStorage?.setItem(AUTO_MODE_SESSION_KEY, JSON.stringify(next));
} catch {
// ignore storage errors (private mode, disabled storage, etc.)
}
}
function setAutoModeSessionForProjectPath(projectPath: string, running: boolean): void {
const current = readAutoModeSession();
const next = { ...current, [projectPath]: running };
writeAutoModeSession(next);
}
// Type guard for plan_approval_required event
function isPlanApprovalEvent(
event: AutoModeEvent
@@ -64,6 +94,23 @@ export function useAutoMode() {
// Check if we can start a new task based on concurrency limit
const canStartNewTask = runningAutoTasks.length < maxConcurrency;
// Restore auto-mode toggle after a renderer refresh (e.g. dev HMR reload).
// This is intentionally session-scoped to avoid auto-running features after a full app restart.
useEffect(() => {
if (!currentProject) return;
const session = readAutoModeSession();
const desired = session[currentProject.path];
if (typeof desired !== 'boolean') return;
if (desired !== isAutoModeRunning) {
logger.info(
`[AutoMode] Restoring session state for ${currentProject.path}: ${desired ? 'ON' : 'OFF'}`
);
setAutoModeRunning(currentProject.id, desired);
}
}, [currentProject, isAutoModeRunning, setAutoModeRunning]);
// Handle auto mode events - listen globally for all projects
useEffect(() => {
const api = getElectronAPI();
@@ -337,6 +384,7 @@ export function useAutoMode() {
return;
}
setAutoModeSessionForProjectPath(currentProject.path, true);
setAutoModeRunning(currentProject.id, true);
logger.debug(`[AutoMode] Started with maxConcurrency: ${maxConcurrency}`);
}, [currentProject, setAutoModeRunning, maxConcurrency]);
@@ -348,6 +396,7 @@ export function useAutoMode() {
return;
}
setAutoModeSessionForProjectPath(currentProject.path, false);
setAutoModeRunning(currentProject.id, false);
// NOTE: We intentionally do NOT clear running tasks here.
// Stopping auto mode only turns off the toggle to prevent new features

View File

@@ -23,6 +23,7 @@ import { getHttpApiClient, waitForApiKeyInit } from '@/lib/http-api-client';
import { isElectron } from '@/lib/electron';
import { getItem, removeItem } from '@/lib/storage';
import { useAppStore } from '@/store/app-store';
import type { GlobalSettings } from '@automaker/types';
const logger = createLogger('SettingsMigration');
@@ -123,7 +124,63 @@ export function useSettingsMigration(): MigrationState {
// If settings files already exist, no migration needed
if (!status.needsMigration) {
logger.info('Settings files exist, no migration needed');
logger.info('Settings files exist - hydrating UI store from server');
// IMPORTANT: the server settings file is now the source of truth.
// If localStorage/Zustand get out of sync (e.g. cleared localStorage),
// the UI can show stale values even though the server will execute with
// the file-based settings. Hydrate the store from the server on startup.
try {
const global = await api.settings.getGlobal();
if (global.success && global.settings) {
const serverSettings = global.settings as unknown as GlobalSettings;
const current = useAppStore.getState();
useAppStore.setState({
theme: serverSettings.theme as unknown as import('@/store/app-store').ThemeMode,
sidebarOpen: serverSettings.sidebarOpen,
chatHistoryOpen: serverSettings.chatHistoryOpen,
kanbanCardDetailLevel: serverSettings.kanbanCardDetailLevel,
maxConcurrency: serverSettings.maxConcurrency,
defaultSkipTests: serverSettings.defaultSkipTests,
enableDependencyBlocking: serverSettings.enableDependencyBlocking,
skipVerificationInAutoMode: serverSettings.skipVerificationInAutoMode,
useWorktrees: serverSettings.useWorktrees,
showProfilesOnly: serverSettings.showProfilesOnly,
defaultPlanningMode: serverSettings.defaultPlanningMode,
defaultRequirePlanApproval: serverSettings.defaultRequirePlanApproval,
defaultAIProfileId: serverSettings.defaultAIProfileId,
muteDoneSound: serverSettings.muteDoneSound,
enhancementModel: serverSettings.enhancementModel,
validationModel: serverSettings.validationModel,
phaseModels: serverSettings.phaseModels,
enabledCursorModels: serverSettings.enabledCursorModels,
cursorDefaultModel: serverSettings.cursorDefaultModel,
autoLoadClaudeMd: serverSettings.autoLoadClaudeMd ?? false,
keyboardShortcuts: {
...current.keyboardShortcuts,
...(serverSettings.keyboardShortcuts as unknown as Partial<
typeof current.keyboardShortcuts
>),
},
aiProfiles: serverSettings.aiProfiles,
mcpServers: serverSettings.mcpServers,
promptCustomization: serverSettings.promptCustomization ?? {},
projects: serverSettings.projects,
trashedProjects: serverSettings.trashedProjects,
projectHistory: serverSettings.projectHistory,
projectHistoryIndex: serverSettings.projectHistoryIndex,
lastSelectedSessionByProject: serverSettings.lastSelectedSessionByProject,
});
logger.info('Hydrated UI settings from server settings file');
} else {
logger.warn('Failed to load global settings from server:', global);
}
} catch (error) {
logger.error('Failed to hydrate UI settings from server:', error);
}
setState({ checked: true, migrated: false, error: null });
return;
}
@@ -201,14 +258,28 @@ export function useSettingsMigration(): MigrationState {
export async function syncSettingsToServer(): Promise<boolean> {
try {
const api = getHttpApiClient();
const automakerStorage = getItem('automaker-storage');
if (!automakerStorage) {
return false;
// IMPORTANT:
// Prefer the live Zustand state over localStorage to avoid race conditions
// (Zustand persistence writes can lag behind `set(...)`, which would cause us
// to sync stale values to the server).
//
// localStorage remains as a fallback for cases where the store isn't ready.
let state: Record<string, unknown> | null = null;
try {
state = useAppStore.getState() as unknown as Record<string, unknown>;
} catch {
// Ignore and fall back to localStorage
}
const parsed = JSON.parse(automakerStorage);
const state = parsed.state || parsed;
if (!state) {
const automakerStorage = getItem('automaker-storage');
if (!automakerStorage) {
return false;
}
const parsed = JSON.parse(automakerStorage) as Record<string, unknown>;
state = (parsed.state as Record<string, unknown> | undefined) || parsed;
}
// Extract settings to sync
const updates = {
@@ -219,6 +290,7 @@ export async function syncSettingsToServer(): Promise<boolean> {
maxConcurrency: state.maxConcurrency,
defaultSkipTests: state.defaultSkipTests,
enableDependencyBlocking: state.enableDependencyBlocking,
skipVerificationInAutoMode: state.skipVerificationInAutoMode,
useWorktrees: state.useWorktrees,
showProfilesOnly: state.showProfilesOnly,
defaultPlanningMode: state.defaultPlanningMode,
@@ -229,8 +301,6 @@ export async function syncSettingsToServer(): Promise<boolean> {
validationModel: state.validationModel,
phaseModels: state.phaseModels,
autoLoadClaudeMd: state.autoLoadClaudeMd,
enableSandboxMode: state.enableSandboxMode,
skipSandboxWarning: state.skipSandboxWarning,
keyboardShortcuts: state.keyboardShortcuts,
aiProfiles: state.aiProfiles,
mcpServers: state.mcpServers,