Merge branch 'v0.9.0rc' into remove-sandbox-as-it-is-broken

This commit is contained in:
webdevcody
2026-01-07 15:01:31 -05:00
115 changed files with 8734 additions and 401 deletions

View File

@@ -9,8 +9,11 @@ import type {
FeatureTextFilePath,
ModelAlias,
PlanningMode,
ThinkingLevel,
ModelProvider,
AIProfile,
CursorModelId,
CodexModelId,
PhaseModelConfig,
PhaseModelKey,
PhaseModelEntry,
@@ -20,12 +23,20 @@ import type {
PipelineStep,
PromptCustomization,
} from '@automaker/types';
import { getAllCursorModelIds, DEFAULT_PHASE_MODELS } from '@automaker/types';
import { getAllCursorModelIds, getAllCodexModelIds, DEFAULT_PHASE_MODELS } from '@automaker/types';
const logger = createLogger('AppStore');
// Re-export types for convenience
export type { ModelAlias };
export type {
ModelAlias,
PlanningMode,
ThinkingLevel,
ModelProvider,
AIProfile,
FeatureTextFilePath,
FeatureImagePath,
};
export type ViewMode =
| 'welcome'
@@ -533,6 +544,15 @@ export interface AppState {
enabledCursorModels: CursorModelId[]; // Which Cursor models are available in feature modal
cursorDefaultModel: CursorModelId; // Default Cursor model selection
// Codex CLI Settings (global)
enabledCodexModels: CodexModelId[]; // Which Codex models are available in feature modal
codexDefaultModel: CodexModelId; // Default Codex model selection
codexAutoLoadAgents: boolean; // Auto-load .codex/AGENTS.md files
codexSandboxMode: 'read-only' | 'workspace-write' | 'danger-full-access'; // Sandbox policy
codexApprovalPolicy: 'untrusted' | 'on-failure' | 'on-request' | 'never'; // Approval policy
codexEnableWebSearch: boolean; // Enable web search capability
codexEnableImages: boolean; // Enable image processing
// Claude Agent SDK Settings
autoLoadClaudeMd: boolean; // Auto-load CLAUDE.md files using SDK's settingSources option
skipSandboxWarning: boolean; // Skip the sandbox environment warning dialog on startup
@@ -595,6 +615,10 @@ export interface AppState {
claudeUsage: ClaudeUsage | null;
claudeUsageLastUpdated: number | null;
// Codex Usage Tracking
codexUsage: CodexUsage | null;
codexUsageLastUpdated: number | null;
// Pipeline Configuration (per-project, keyed by project path)
pipelineConfigByProject: Record<string, PipelineConfig>;
@@ -636,6 +660,41 @@ export type ClaudeUsage = {
// Response type for Claude usage API (can be success or error)
export type ClaudeUsageResponse = ClaudeUsage | { error: string; message?: string };
// Codex Usage types
export type CodexPlanType =
| 'free'
| 'plus'
| 'pro'
| 'team'
| 'business'
| 'enterprise'
| 'edu'
| 'unknown';
export interface CodexCreditsSnapshot {
balance?: string;
unlimited?: boolean;
hasCredits?: boolean;
}
export interface CodexRateLimitWindow {
limit: number;
used: number;
remaining: number;
window: number; // Duration in minutes
resetsAt: number; // Unix timestamp in seconds
}
export interface CodexUsage {
planType: CodexPlanType | null;
credits: CodexCreditsSnapshot | null;
rateLimits: {
session?: CodexRateLimitWindow;
weekly?: CodexRateLimitWindow;
} | null;
lastUpdated: string;
}
/**
* Check if Claude usage is at its limit (any of: session >= 100%, weekly >= 100%, OR cost >= limit)
* Returns true if any limit is reached, meaning auto mode should pause feature pickup.
@@ -839,6 +898,20 @@ export interface AppActions {
setCursorDefaultModel: (model: CursorModelId) => void;
toggleCursorModel: (model: CursorModelId, enabled: boolean) => void;
// Codex CLI Settings actions
setEnabledCodexModels: (models: CodexModelId[]) => void;
setCodexDefaultModel: (model: CodexModelId) => void;
toggleCodexModel: (model: CodexModelId, enabled: boolean) => void;
setCodexAutoLoadAgents: (enabled: boolean) => Promise<void>;
setCodexSandboxMode: (
mode: 'read-only' | 'workspace-write' | 'danger-full-access'
) => Promise<void>;
setCodexApprovalPolicy: (
policy: 'untrusted' | 'on-failure' | 'on-request' | 'never'
) => Promise<void>;
setCodexEnableWebSearch: (enabled: boolean) => Promise<void>;
setCodexEnableImages: (enabled: boolean) => Promise<void>;
// Claude Agent SDK Settings actions
setAutoLoadClaudeMd: (enabled: boolean) => Promise<void>;
setSkipSandboxWarning: (skip: boolean) => Promise<void>;
@@ -970,6 +1043,14 @@ export interface AppActions {
setRecentFolders: (folders: string[]) => void;
addRecentFolder: (folder: string) => void;
// Claude Usage Tracking actions
setClaudeRefreshInterval: (interval: number) => void;
setClaudeUsageLastUpdated: (timestamp: number) => void;
setClaudeUsage: (usage: ClaudeUsage | null) => void;
// Codex Usage Tracking actions
setCodexUsage: (usage: CodexUsage | null) => void;
// Reset
reset: () => void;
}
@@ -1061,6 +1142,13 @@ const initialState: AppState = {
favoriteModels: [],
enabledCursorModels: getAllCursorModelIds(), // All Cursor models enabled by default
cursorDefaultModel: 'auto', // Default to auto selection
enabledCodexModels: getAllCodexModelIds(), // All Codex models enabled by default
codexDefaultModel: 'gpt-5.2-codex', // Default to GPT-5.2-Codex
codexAutoLoadAgents: false, // Default to disabled (user must opt-in)
codexSandboxMode: 'workspace-write', // Default to workspace-write for safety
codexApprovalPolicy: 'on-request', // Default to on-request for balanced safety
codexEnableWebSearch: false, // Default to disabled
codexEnableImages: false, // Default to disabled
autoLoadClaudeMd: false, // Default to disabled (user must opt-in)
skipSandboxWarning: false, // Default to disabled (show sandbox warning dialog)
mcpServers: [], // No MCP servers configured by default
@@ -1095,6 +1183,8 @@ const initialState: AppState = {
claudeRefreshInterval: 60,
claudeUsage: null,
claudeUsageLastUpdated: null,
codexUsage: null,
codexUsageLastUpdated: null,
pipelineConfigByProject: {},
// UI State (previously in localStorage, now synced via API)
worktreePanelCollapsed: false,
@@ -1753,6 +1843,41 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
: state.enabledCursorModels.filter((m) => m !== model),
})),
// Codex CLI Settings actions
setEnabledCodexModels: (models) => set({ enabledCodexModels: models }),
setCodexDefaultModel: (model) => set({ codexDefaultModel: model }),
toggleCodexModel: (model, enabled) =>
set((state) => ({
enabledCodexModels: enabled
? [...state.enabledCodexModels, model]
: state.enabledCodexModels.filter((m) => m !== model),
})),
setCodexAutoLoadAgents: async (enabled) => {
set({ codexAutoLoadAgents: enabled });
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setCodexSandboxMode: async (mode) => {
set({ codexSandboxMode: mode });
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setCodexApprovalPolicy: async (policy) => {
set({ codexApprovalPolicy: policy });
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setCodexEnableWebSearch: async (enabled) => {
set({ codexEnableWebSearch: enabled });
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
setCodexEnableImages: async (enabled) => {
set({ codexEnableImages: enabled });
const { syncSettingsToServer } = await import('@/hooks/use-settings-migration');
await syncSettingsToServer();
},
// Claude Agent SDK Settings actions
setAutoLoadClaudeMd: async (enabled) => {
const previous = get().autoLoadClaudeMd;
@@ -2826,6 +2951,13 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
claudeUsageLastUpdated: usage ? Date.now() : null,
}),
// Codex Usage Tracking actions
setCodexUsage: (usage: CodexUsage | null) =>
set({
codexUsage: usage,
codexUsageLastUpdated: usage ? Date.now() : null,
}),
// Pipeline actions
setPipelineConfig: (projectPath, config) => {
set({

View File

@@ -34,6 +34,37 @@ export interface CursorCliStatus {
error?: string;
}
// Codex CLI Status
export interface CodexCliStatus {
installed: boolean;
version?: string | null;
path?: string | null;
auth?: {
authenticated: boolean;
method: string;
};
installCommand?: string;
loginCommand?: string;
error?: string;
}
// Codex Auth Method
export type CodexAuthMethod =
| 'api_key_env' // OPENAI_API_KEY environment variable
| 'api_key' // Manually stored API key
| 'cli_authenticated' // Codex CLI is installed and authenticated
| 'none';
// Codex Auth Status
export interface CodexAuthStatus {
authenticated: boolean;
method: CodexAuthMethod;
hasAuthFile?: boolean;
hasApiKey?: boolean;
hasEnvApiKey?: boolean;
error?: string;
}
// Claude Auth Method - all possible authentication sources
export type ClaudeAuthMethod =
| 'oauth_token_env'
@@ -71,6 +102,7 @@ export type SetupStep =
| 'claude_detect'
| 'claude_auth'
| 'cursor'
| 'codex'
| 'github'
| 'complete';
@@ -91,6 +123,11 @@ export interface SetupState {
// Cursor CLI state
cursorCliStatus: CursorCliStatus | null;
// Codex CLI state
codexCliStatus: CliStatus | null;
codexAuthStatus: CodexAuthStatus | null;
codexInstallProgress: InstallProgress;
// Setup preferences
skipClaudeSetup: boolean;
}
@@ -115,6 +152,12 @@ export interface SetupActions {
// Cursor CLI
setCursorCliStatus: (status: CursorCliStatus | null) => void;
// Codex CLI
setCodexCliStatus: (status: CliStatus | null) => void;
setCodexAuthStatus: (status: CodexAuthStatus | null) => void;
setCodexInstallProgress: (progress: Partial<InstallProgress>) => void;
resetCodexInstallProgress: () => void;
// Preferences
setSkipClaudeSetup: (skip: boolean) => void;
}
@@ -141,6 +184,10 @@ const initialState: SetupState = {
ghCliStatus: null,
cursorCliStatus: null,
codexCliStatus: null,
codexAuthStatus: null,
codexInstallProgress: { ...initialInstallProgress },
skipClaudeSetup: shouldSkipSetup,
};
@@ -190,6 +237,24 @@ export const useSetupStore = create<SetupState & SetupActions>()((set, get) => (
// Cursor CLI
setCursorCliStatus: (status) => set({ cursorCliStatus: status }),
// Codex CLI
setCodexCliStatus: (status) => set({ codexCliStatus: status }),
setCodexAuthStatus: (status) => set({ codexAuthStatus: status }),
setCodexInstallProgress: (progress) =>
set({
codexInstallProgress: {
...get().codexInstallProgress,
...progress,
},
}),
resetCodexInstallProgress: () =>
set({
codexInstallProgress: { ...initialInstallProgress },
}),
// Preferences
setSkipClaudeSetup: (skip) => set({ skipClaudeSetup: skip }),
}));