mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-20 23:13:07 +00:00
Feature: worktree view customization and stability fixes (#805)
* Changes from feature/worktree-view-customization * Feature: Git sync, set-tracking, and push divergence handling (#796) * Add quick-add feature with improved workflows (#802) * Changes from feature/quick-add * feat: Clarify system prompt and improve error handling across services. Address PR Feedback * feat: Improve PR description parsing and refactor event handling * feat: Add context options to pipeline orchestrator initialization * fix: Deduplicate React and handle CJS interop for use-sync-external-store Resolve "Cannot read properties of null (reading 'useState')" errors by deduplicating React/react-dom and ensuring use-sync-external-store is bundled together with React to prevent CJS packages from resolving to different React instances. * Changes from feature/worktree-view-customization * refactor: Remove unused worktree swap and highlight props * refactor: Consolidate feature completion logic and improve thinking level defaults * feat: Increase max turn limit to 10000 - Update DEFAULT_MAX_TURNS from 1000 to 10000 in settings-helpers.ts and agent-executor.ts - Update MAX_ALLOWED_TURNS from 2000 to 10000 in settings-helpers.ts - Update UI clamping logic from 2000 to 10000 in app-store.ts - Update fallback values from 1000 to 10000 in use-settings-sync.ts - Update default value from 1000 to 10000 in DEFAULT_GLOBAL_SETTINGS - Update documentation to reflect new range: 1-10000 Allows agents to perform up to 10000 turns for complex feature execution. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: Add model resolution, improve session handling, and enhance UI stability * refactor: Remove unused sync and tracking branch props from worktree components * feat: Add PR number update functionality to worktrees. Address pr feedback * feat: Optimize Gemini CLI startup and add tool result tracking * refactor: Improve error handling and simplify worktree task cleanup --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,7 @@ import {
|
||||
DEFAULT_COPILOT_MODEL,
|
||||
DEFAULT_MAX_CONCURRENCY,
|
||||
DEFAULT_GLOBAL_SETTINGS,
|
||||
getThinkingLevelsForModel,
|
||||
} from '@automaker/types';
|
||||
|
||||
// Import types from modular type files
|
||||
@@ -371,9 +372,9 @@ const initialState: AppState = {
|
||||
defaultPlanningMode: 'skip' as PlanningMode,
|
||||
defaultRequirePlanApproval: false,
|
||||
defaultFeatureModel: DEFAULT_GLOBAL_SETTINGS.defaultFeatureModel,
|
||||
defaultThinkingLevel: DEFAULT_GLOBAL_SETTINGS.defaultThinkingLevel ?? 'none',
|
||||
defaultThinkingLevel: DEFAULT_GLOBAL_SETTINGS.defaultThinkingLevel ?? 'adaptive',
|
||||
defaultReasoningEffort: DEFAULT_GLOBAL_SETTINGS.defaultReasoningEffort ?? 'none',
|
||||
defaultMaxTurns: DEFAULT_GLOBAL_SETTINGS.defaultMaxTurns ?? 1000,
|
||||
defaultMaxTurns: DEFAULT_GLOBAL_SETTINGS.defaultMaxTurns ?? 10000,
|
||||
pendingPlanApproval: null,
|
||||
claudeRefreshInterval: 60,
|
||||
claudeUsage: null,
|
||||
@@ -396,6 +397,10 @@ const initialState: AppState = {
|
||||
autoDismissInitScriptIndicatorByProject: {},
|
||||
useWorktreesByProject: {},
|
||||
worktreeCopyFilesByProject: {},
|
||||
pinnedWorktreesCountByProject: {},
|
||||
pinnedWorktreeBranchesByProject: {},
|
||||
worktreeDropdownThresholdByProject: {},
|
||||
alwaysUseWorktreeDropdownByProject: {},
|
||||
worktreePanelCollapsed: false,
|
||||
lastProjectDir: '',
|
||||
recentFolders: [],
|
||||
@@ -2453,7 +2458,20 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
setDefaultFeatureModel: (entry) => set({ defaultFeatureModel: entry }),
|
||||
|
||||
setDefaultThinkingLevel: async (level) => {
|
||||
set({ defaultThinkingLevel: level });
|
||||
const currentModel = get().defaultFeatureModel;
|
||||
const modelId = currentModel.model;
|
||||
const availableLevels = getThinkingLevelsForModel(modelId);
|
||||
|
||||
// Also update defaultFeatureModel's thinkingLevel if compatible
|
||||
if (availableLevels.includes(level)) {
|
||||
set({
|
||||
defaultThinkingLevel: level,
|
||||
defaultFeatureModel: { ...currentModel, thinkingLevel: level },
|
||||
});
|
||||
} else {
|
||||
set({ defaultThinkingLevel: level });
|
||||
}
|
||||
|
||||
// Sync to server
|
||||
try {
|
||||
const httpApi = getHttpApiClient();
|
||||
@@ -2478,7 +2496,7 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
// Guard against NaN/Infinity before flooring and clamping
|
||||
const safeValue = Number.isFinite(maxTurns) ? maxTurns : 1;
|
||||
// Clamp to valid range
|
||||
const clamped = Math.max(1, Math.min(2000, Math.floor(safeValue)));
|
||||
const clamped = Math.max(1, Math.min(10000, Math.floor(safeValue)));
|
||||
set({ defaultMaxTurns: clamped });
|
||||
// Sync to server
|
||||
try {
|
||||
@@ -2641,6 +2659,65 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
|
||||
})),
|
||||
getWorktreeCopyFiles: (projectPath) => get().worktreeCopyFilesByProject[projectPath] ?? [],
|
||||
|
||||
// Worktree Display Settings actions
|
||||
setPinnedWorktreesCount: (projectPath, count) =>
|
||||
set((state) => ({
|
||||
pinnedWorktreesCountByProject: {
|
||||
...state.pinnedWorktreesCountByProject,
|
||||
[projectPath]: count,
|
||||
},
|
||||
})),
|
||||
getPinnedWorktreesCount: (projectPath) => get().pinnedWorktreesCountByProject[projectPath] ?? 0,
|
||||
setPinnedWorktreeBranches: (projectPath, branches) =>
|
||||
set((state) => ({
|
||||
pinnedWorktreeBranchesByProject: {
|
||||
...state.pinnedWorktreeBranchesByProject,
|
||||
[projectPath]: branches,
|
||||
},
|
||||
})),
|
||||
getPinnedWorktreeBranches: (projectPath) =>
|
||||
get().pinnedWorktreeBranchesByProject[projectPath] ?? [],
|
||||
swapPinnedWorktreeBranch: (projectPath, slotIndex, newBranch) =>
|
||||
set((state) => {
|
||||
const src = state.pinnedWorktreeBranchesByProject[projectPath] ?? [];
|
||||
// Pre-fill up to slotIndex to prevent sparse holes
|
||||
const current: string[] = Array.from(
|
||||
{ length: Math.max(src.length, slotIndex + 1) },
|
||||
(_, i) => src[i] ?? ''
|
||||
);
|
||||
// If the new branch is already in another slot, swap them (only when newBranch is non-empty)
|
||||
const existingIndex = newBranch !== '' ? current.indexOf(newBranch) : -1;
|
||||
if (existingIndex !== -1 && existingIndex !== slotIndex) {
|
||||
// Swap: put the old branch from this slot into the other slot
|
||||
current[existingIndex] = current[slotIndex];
|
||||
}
|
||||
current[slotIndex] = newBranch;
|
||||
return {
|
||||
pinnedWorktreeBranchesByProject: {
|
||||
...state.pinnedWorktreeBranchesByProject,
|
||||
[projectPath]: current,
|
||||
},
|
||||
};
|
||||
}),
|
||||
setWorktreeDropdownThreshold: (projectPath, threshold) =>
|
||||
set((state) => ({
|
||||
worktreeDropdownThresholdByProject: {
|
||||
...state.worktreeDropdownThresholdByProject,
|
||||
[projectPath]: threshold,
|
||||
},
|
||||
})),
|
||||
getWorktreeDropdownThreshold: (projectPath) =>
|
||||
get().worktreeDropdownThresholdByProject[projectPath] ?? 3,
|
||||
setAlwaysUseWorktreeDropdown: (projectPath, always) =>
|
||||
set((state) => ({
|
||||
alwaysUseWorktreeDropdownByProject: {
|
||||
...state.alwaysUseWorktreeDropdownByProject,
|
||||
[projectPath]: always,
|
||||
},
|
||||
})),
|
||||
getAlwaysUseWorktreeDropdown: (projectPath) =>
|
||||
get().alwaysUseWorktreeDropdownByProject[projectPath] ?? true,
|
||||
|
||||
// UI State actions
|
||||
setWorktreePanelCollapsed: (collapsed) => set({ worktreePanelCollapsed: collapsed }),
|
||||
setLastProjectDir: (dir) => set({ lastProjectDir: dir }),
|
||||
|
||||
@@ -370,6 +370,17 @@ export interface AppState {
|
||||
// List of relative file paths to copy from project root into new worktrees
|
||||
worktreeCopyFilesByProject: Record<string, string[]>;
|
||||
|
||||
// Worktree Display Settings (per-project, keyed by project path)
|
||||
// Number of worktrees always visible (pinned) without expanding a dropdown (default: 1)
|
||||
pinnedWorktreesCountByProject: Record<string, number>;
|
||||
// Explicit list of branch names assigned to pinned slots (ordered)
|
||||
// When set, these branches are shown in the pinned slots instead of using default ordering
|
||||
pinnedWorktreeBranchesByProject: Record<string, string[]>;
|
||||
// Minimum number of worktrees before the list collapses into a dropdown (default: 3)
|
||||
worktreeDropdownThresholdByProject: Record<string, number>;
|
||||
// Always use dropdown layout regardless of worktree count (default: false)
|
||||
alwaysUseWorktreeDropdownByProject: Record<string, boolean>;
|
||||
|
||||
// UI State (previously in localStorage, now synced via API)
|
||||
/** Whether worktree panel is collapsed in board view */
|
||||
worktreePanelCollapsed: boolean;
|
||||
@@ -814,6 +825,17 @@ export interface AppActions {
|
||||
setWorktreeCopyFiles: (projectPath: string, files: string[]) => void;
|
||||
getWorktreeCopyFiles: (projectPath: string) => string[];
|
||||
|
||||
// Worktree Display Settings actions (per-project)
|
||||
setPinnedWorktreesCount: (projectPath: string, count: number) => void;
|
||||
getPinnedWorktreesCount: (projectPath: string) => number;
|
||||
setPinnedWorktreeBranches: (projectPath: string, branches: string[]) => void;
|
||||
getPinnedWorktreeBranches: (projectPath: string) => string[];
|
||||
swapPinnedWorktreeBranch: (projectPath: string, slotIndex: number, newBranch: string) => void;
|
||||
setWorktreeDropdownThreshold: (projectPath: string, threshold: number) => void;
|
||||
getWorktreeDropdownThreshold: (projectPath: string) => number;
|
||||
setAlwaysUseWorktreeDropdown: (projectPath: string, always: boolean) => void;
|
||||
getAlwaysUseWorktreeDropdown: (projectPath: string) => boolean;
|
||||
|
||||
// UI State actions (previously in localStorage, now synced via API)
|
||||
setWorktreePanelCollapsed: (collapsed: boolean) => void;
|
||||
setLastProjectDir: (dir: string) => void;
|
||||
|
||||
Reference in New Issue
Block a user