Merge branch 'v0.11.0rc' into claude/issue-469-20260113-1744

This commit is contained in:
webdevcody
2026-01-13 14:59:14 -05:00
78 changed files with 2645 additions and 1369 deletions

View File

@@ -657,6 +657,7 @@ export interface AppState {
defaultPlanningMode: PlanningMode;
defaultRequirePlanApproval: boolean;
defaultFeatureModel: PhaseModelEntry;
// Plan Approval State
// When a plan requires user approval, this holds the pending approval details
@@ -689,6 +690,7 @@ export interface AppState {
codexModelsLoading: boolean;
codexModelsError: string | null;
codexModelsLastFetched: number | null;
codexModelsLastFailedAt: number | null;
// Pipeline Configuration (per-project, keyed by project path)
pipelineConfigByProject: Record<string, PipelineConfig>;
@@ -1106,6 +1108,7 @@ export interface AppActions {
setDefaultPlanningMode: (mode: PlanningMode) => void;
setDefaultRequirePlanApproval: (require: boolean) => void;
setDefaultFeatureModel: (entry: PhaseModelEntry) => void;
// Plan Approval actions
setPendingPlanApproval: (
@@ -1279,6 +1282,7 @@ const initialState: AppState = {
specCreatingForProject: null,
defaultPlanningMode: 'skip' as PlanningMode,
defaultRequirePlanApproval: false,
defaultFeatureModel: { model: 'opus' } as PhaseModelEntry,
pendingPlanApproval: null,
claudeRefreshInterval: 60,
claudeUsage: null,
@@ -1289,6 +1293,7 @@ const initialState: AppState = {
codexModelsLoading: false,
codexModelsError: null,
codexModelsLastFetched: null,
codexModelsLastFailedAt: null,
pipelineConfigByProject: {},
worktreePanelVisibleByProject: {},
showInitScriptIndicatorByProject: {},
@@ -3145,6 +3150,7 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
setDefaultPlanningMode: (mode) => set({ defaultPlanningMode: mode }),
setDefaultRequirePlanApproval: (require) => set({ defaultRequirePlanApproval: require }),
setDefaultFeatureModel: (entry) => set({ defaultFeatureModel: entry }),
// Plan Approval actions
setPendingPlanApproval: (approval) => set({ pendingPlanApproval: approval }),
@@ -3167,13 +3173,29 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
// Codex Models actions
fetchCodexModels: async (forceRefresh = false) => {
const { codexModelsLastFetched, codexModelsLoading } = get();
const FAILURE_COOLDOWN_MS = 30 * 1000; // 30 seconds
const SUCCESS_CACHE_MS = 5 * 60 * 1000; // 5 minutes
const { codexModelsLastFetched, codexModelsLoading, codexModelsLastFailedAt } = get();
// Skip if already loading
if (codexModelsLoading) return;
// Skip if recently fetched (< 5 minutes ago) and not forcing refresh
if (!forceRefresh && codexModelsLastFetched && Date.now() - codexModelsLastFetched < 300000) {
// Skip if recently failed and not forcing refresh
if (
!forceRefresh &&
codexModelsLastFailedAt &&
Date.now() - codexModelsLastFailedAt < FAILURE_COOLDOWN_MS
) {
return;
}
// Skip if recently fetched successfully and not forcing refresh
if (
!forceRefresh &&
codexModelsLastFetched &&
Date.now() - codexModelsLastFetched < SUCCESS_CACHE_MS
) {
return;
}
@@ -3196,12 +3218,14 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
codexModelsLastFetched: Date.now(),
codexModelsLoading: false,
codexModelsError: null,
codexModelsLastFailedAt: null, // Clear failure on success
});
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
set({
codexModelsError: errorMessage,
codexModelsLoading: false,
codexModelsLastFailedAt: Date.now(), // Record failure time for cooldown
});
}
},