diff --git a/apps/ui/src/components/views/board-view/dialogs/mass-edit-dialog.tsx b/apps/ui/src/components/views/board-view/dialogs/mass-edit-dialog.tsx index 1b4b1467..6e198e63 100644 --- a/apps/ui/src/components/views/board-view/dialogs/mass-edit-dialog.tsx +++ b/apps/ui/src/components/views/board-view/dialogs/mass-edit-dialog.tsx @@ -10,18 +10,12 @@ import { import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; import { Label } from '@/components/ui/label'; -import { Settings2, AlertCircle } from 'lucide-react'; +import { AlertCircle } from 'lucide-react'; import { modelSupportsThinking } from '@/lib/utils'; import { Feature, ModelAlias, ThinkingLevel, AIProfile, PlanningMode } from '@/store/app-store'; -import { - ModelSelector, - ThinkingLevelSelector, - ProfileQuickSelect, - TestingTabContent, - PrioritySelector, - PlanningModeSelector, -} from '../shared'; -import { isCursorModel, PROVIDER_PREFIXES } from '@automaker/types'; +import { ProfileSelect, TestingTabContent, PrioritySelect, PlanningModeSelect } from '../shared'; +import { PhaseModelSelector } from '@/components/views/settings-view/model-defaults/phase-model-selector'; +import { isCursorModel, PROVIDER_PREFIXES, type PhaseModelEntry } from '@automaker/types'; import { cn } from '@/lib/utils'; interface MassEditDialogProps { @@ -113,7 +107,6 @@ export function MassEditDialog({ aiProfiles, }: MassEditDialogProps) { const [isApplying, setIsApplying] = useState(false); - const [showAdvancedOptions, setShowAdvancedOptions] = useState(false); // Track which fields to apply const [applyState, setApplyState] = useState({ @@ -153,7 +146,6 @@ export function MassEditDialog({ setRequirePlanApproval(getInitialValue(selectedFeatures, 'requirePlanApproval', false)); setPriority(getInitialValue(selectedFeatures, 'priority', 2)); setSkipTests(getInitialValue(selectedFeatures, 'skipTests', false)); - setShowAdvancedOptions(false); } }, [open, selectedFeatures]); @@ -216,27 +208,6 @@ export function MassEditDialog({
- {/* Show Advanced Options Toggle */} - {showProfilesOnly && ( -
-
-

Simple Mode Active

-

- Only showing AI profiles. Advanced model tweaking is hidden. -

-
- -
- )} - {/* Quick Select Profile Section */} {aiProfiles.length > 0 && (
@@ -244,7 +215,7 @@ export function MassEditDialog({

Selecting a profile will automatically enable model settings

- )} + {/* Model Selector */} +
+ +

+ Or select a specific model configuration +

+ { + setModel(entry.model as ModelAlias); + setThinkingLevel(entry.thinkingLevel || 'none'); + // Auto-enable model and thinking level for apply state + setApplyState((prev) => ({ + ...prev, + model: true, + thinkingLevel: true, + })); + }} + compact + /> +
+ {/* Separator */} - {aiProfiles.length > 0 && (!showProfilesOnly || showAdvancedOptions) && ( -
- )} - - {/* Model Selection */} - {(!showProfilesOnly || showAdvancedOptions) && ( - <> - setApplyState((prev) => ({ ...prev, model: apply }))} - > - - - - {modelAllowsThinking && ( - - setApplyState((prev) => ({ ...prev, thinkingLevel: apply })) - } - > - - - )} - - )} - - {/* Separator before options */} - {(!showProfilesOnly || showAdvancedOptions) &&
} +
{/* Planning Mode */} - { + setPlanningMode(newMode); + // Auto-suggest approval based on mode, but user can override + setRequirePlanApproval(newMode === 'spec' || newMode === 'full'); + }} requireApproval={requirePlanApproval} onRequireApprovalChange={setRequirePlanApproval} - featureDescription="" - testIdPrefix="mass-edit" - compact + testIdPrefix="mass-edit-planning" /> @@ -329,7 +284,7 @@ export function MassEditDialog({ willApply={applyState.priority} onApplyChange={(apply) => setApplyState((prev) => ({ ...prev, priority: apply }))} > - void; + requireApproval?: boolean; + onRequireApprovalChange?: (require: boolean) => void; + testIdPrefix?: string; + className?: string; + disabled?: boolean; +} + +const modes = [ + { + value: 'skip' as const, + label: 'Skip', + description: 'Direct implementation, no upfront planning', + icon: Zap, + color: 'text-emerald-500', + }, + { + value: 'lite' as const, + label: 'Lite', + description: 'Think through approach, create task list', + icon: ClipboardList, + color: 'text-blue-500', + }, + { + value: 'spec' as const, + label: 'Spec', + description: 'Generate spec with acceptance criteria', + icon: FileText, + color: 'text-purple-500', + }, + { + value: 'full' as const, + label: 'Full', + description: 'Comprehensive spec with phased plan', + icon: ScrollText, + color: 'text-amber-500', + }, +]; + +/** + * PlanningModeSelect - Compact dropdown selector for planning modes + * + * A lightweight alternative to PlanningModeSelector for contexts where + * spec management UI is not needed (e.g., mass edit, bulk operations). + * + * Shows icon + label in dropdown, with description text below. + * Does not include spec generation, approval, or require-approval checkbox. + * + * @example + * ```tsx + * { + * setPlanningMode(mode); + * setRequireApproval(mode === 'spec' || mode === 'full'); + * }} + * testIdPrefix="mass-edit-planning" + * /> + * ``` + */ +export function PlanningModeSelect({ + mode, + onModeChange, + requireApproval, + onRequireApprovalChange, + testIdPrefix = 'planning-mode', + className, + disabled = false, +}: PlanningModeSelectProps) { + const selectedMode = modes.find((m) => m.value === mode); + + // Disable approval checkbox for skip/lite modes since they don't use planning + const isApprovalDisabled = disabled || mode === 'skip' || mode === 'lite'; + + return ( +
+ + {selectedMode &&

{selectedMode.description}

} + {onRequireApprovalChange && ( +
+ onRequireApprovalChange(!!checked)} + disabled={isApprovalDisabled} + data-testid={`${testIdPrefix}-require-approval-checkbox`} + /> + +
+ )} +
+ ); +} diff --git a/apps/ui/src/components/views/board-view/shared/priority-select.tsx b/apps/ui/src/components/views/board-view/shared/priority-select.tsx new file mode 100644 index 00000000..834dacab --- /dev/null +++ b/apps/ui/src/components/views/board-view/shared/priority-select.tsx @@ -0,0 +1,112 @@ +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { AlertCircle, ChevronDown, ChevronUp } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +interface PrioritySelectProps { + selectedPriority: number; + onPrioritySelect: (priority: number) => void; + testIdPrefix?: string; + className?: string; + disabled?: boolean; +} + +const priorities = [ + { + value: 1, + label: 'High', + description: 'Urgent, needs immediate attention', + icon: ChevronUp, + color: 'text-red-500', + bgColor: 'bg-red-500/10', + }, + { + value: 2, + label: 'Medium', + description: 'Normal priority, standard workflow', + icon: AlertCircle, + color: 'text-yellow-500', + bgColor: 'bg-yellow-500/10', + }, + { + value: 3, + label: 'Low', + description: 'Can wait, not time-sensitive', + icon: ChevronDown, + color: 'text-blue-500', + bgColor: 'bg-blue-500/10', + }, +]; + +/** + * PrioritySelect - Compact dropdown selector for feature priority + * + * A lightweight alternative to PrioritySelector for contexts where + * space is limited (e.g., mass edit, bulk operations). + * + * Shows icon + priority level in dropdown, with description below. + * + * @example + * ```tsx + * + * ``` + */ +export function PrioritySelect({ + selectedPriority, + onPrioritySelect, + testIdPrefix = 'priority', + className, + disabled = false, +}: PrioritySelectProps) { + const selectedPriorityObj = priorities.find((p) => p.value === selectedPriority); + + return ( +
+ + {selectedPriorityObj && ( +

{selectedPriorityObj.description}

+ )} +
+ ); +} diff --git a/apps/ui/src/components/views/board-view/shared/profile-select.tsx b/apps/ui/src/components/views/board-view/shared/profile-select.tsx new file mode 100644 index 00000000..d586ff6c --- /dev/null +++ b/apps/ui/src/components/views/board-view/shared/profile-select.tsx @@ -0,0 +1,175 @@ +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Brain, Terminal } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import type { ModelAlias, ThinkingLevel, AIProfile, CursorModelId } from '@automaker/types'; +import { CURSOR_MODEL_MAP, profileHasThinking, PROVIDER_PREFIXES } from '@automaker/types'; +import { PROFILE_ICONS } from './model-constants'; + +/** + * Get display string for a profile's model configuration + */ +function getProfileModelDisplay(profile: AIProfile): string { + if (profile.provider === 'cursor') { + const cursorModel = profile.cursorModel || 'auto'; + const modelConfig = CURSOR_MODEL_MAP[cursorModel]; + return modelConfig?.label || cursorModel; + } + // Claude + return profile.model || 'sonnet'; +} + +/** + * Get display string for a profile's thinking configuration + */ +function getProfileThinkingDisplay(profile: AIProfile): string | null { + if (profile.provider === 'cursor') { + // For Cursor, thinking is embedded in the model + return profileHasThinking(profile) ? 'thinking' : null; + } + // Claude + return profile.thinkingLevel && profile.thinkingLevel !== 'none' ? profile.thinkingLevel : null; +} + +interface ProfileSelectProps { + profiles: AIProfile[]; + selectedModel: ModelAlias | CursorModelId; + selectedThinkingLevel: ThinkingLevel; + selectedCursorModel?: string; // For detecting cursor profile selection + onSelect: (profile: AIProfile) => void; + testIdPrefix?: string; + className?: string; + disabled?: boolean; +} + +/** + * ProfileSelect - Compact dropdown selector for AI profiles + * + * A lightweight alternative to ProfileQuickSelect for contexts where + * space is limited (e.g., mass edit, bulk operations). + * + * Shows icon + profile name in dropdown, with model details below. + * + * @example + * ```tsx + * + * ``` + */ +export function ProfileSelect({ + profiles, + selectedModel, + selectedThinkingLevel, + selectedCursorModel, + onSelect, + testIdPrefix = 'profile-select', + className, + disabled = false, +}: ProfileSelectProps) { + if (profiles.length === 0) { + return null; + } + + // Check if a profile is selected + const isProfileSelected = (profile: AIProfile): boolean => { + if (profile.provider === 'cursor') { + // For cursor profiles, check if cursor model matches + const profileCursorModel = `${PROVIDER_PREFIXES.cursor}${profile.cursorModel || 'auto'}`; + return selectedCursorModel === profileCursorModel; + } + // For Claude profiles + return selectedModel === profile.model && selectedThinkingLevel === profile.thinkingLevel; + }; + + const selectedProfile = profiles.find(isProfileSelected); + + return ( +
+ + {selectedProfile && ( +

+ {getProfileModelDisplay(selectedProfile)} + {getProfileThinkingDisplay(selectedProfile) && + ` + ${getProfileThinkingDisplay(selectedProfile)}`} +

+ )} +
+ ); +} diff --git a/package-lock.json b/package-lock.json index 98ca8545..c6e8e649 100644 --- a/package-lock.json +++ b/package-lock.json @@ -675,6 +675,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1258,6 +1259,7 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz", "integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==", "license": "MIT", + "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -1300,6 +1302,7 @@ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz", "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==", "license": "MIT", + "peer": true, "dependencies": { "@dnd-kit/accessibility": "^3.1.1", "@dnd-kit/utilities": "^3.2.2", @@ -2120,7 +2123,6 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, - "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -2142,7 +2144,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2159,7 +2160,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2174,7 +2174,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">= 10.0.0" } @@ -2942,7 +2941,6 @@ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">=18" } @@ -3067,7 +3065,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3084,7 +3081,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3101,7 +3097,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -3210,7 +3205,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3233,7 +3227,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3256,7 +3249,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3342,7 +3334,6 @@ ], "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/runtime": "^1.7.0" }, @@ -3365,7 +3356,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3385,7 +3375,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -3785,8 +3774,7 @@ "version": "16.0.10", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.0.10.tgz", "integrity": "sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { "version": "16.0.10", @@ -3800,7 +3788,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3817,7 +3804,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3834,7 +3820,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3851,7 +3836,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3868,7 +3852,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3885,7 +3868,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3902,7 +3884,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10" } @@ -3919,7 +3900,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 10" } @@ -4010,6 +3990,7 @@ "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "playwright": "1.57.0" }, @@ -5450,7 +5431,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.8.0" } @@ -5784,6 +5764,7 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.141.6.tgz", "integrity": "sha512-qWFxi2D6eGc1L03RzUuhyEOplZ7Q6q62YOl7Of9Y0q4YjwQwxRm4zxwDVtvUIoy4RLVCpqp5UoE+Nxv2PY9trg==", "license": "MIT", + "peer": true, "dependencies": { "@tanstack/history": "1.141.0", "@tanstack/react-store": "^0.8.0", @@ -6210,6 +6191,7 @@ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -6352,6 +6334,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6362,6 +6345,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6467,6 +6451,7 @@ "integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.50.0", "@typescript-eslint/types": "8.50.0", @@ -6960,7 +6945,8 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@xyflow/react": { "version": "12.10.0", @@ -7058,6 +7044,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7118,6 +7105,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7716,6 +7704,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -8247,8 +8236,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", @@ -8553,8 +8541,7 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/cross-env": { "version": "10.1.0", @@ -8651,6 +8638,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -8952,6 +8940,7 @@ "integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "app-builder-lib": "26.0.12", "builder-util": "26.0.11", @@ -9278,7 +9267,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -9299,7 +9287,6 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -9550,6 +9537,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9864,6 +9852,7 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", + "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -11531,7 +11520,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11553,7 +11541,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11575,7 +11562,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11597,7 +11583,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11619,7 +11604,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11641,7 +11625,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11663,7 +11646,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11685,7 +11667,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11707,7 +11688,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11729,7 +11709,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -11751,7 +11730,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -14039,7 +14017,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -14056,7 +14033,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -14074,7 +14050,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -14263,6 +14238,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -14272,6 +14248,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -14630,7 +14607,6 @@ "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -14819,6 +14795,7 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.4.0.tgz", "integrity": "sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10" } @@ -14867,7 +14844,6 @@ "hasInstallScript": true, "license": "Apache-2.0", "optional": true, - "peer": true, "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", @@ -14918,7 +14894,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -14941,7 +14916,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -14964,7 +14938,6 @@ "os": [ "darwin" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -14981,7 +14954,6 @@ "os": [ "darwin" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -14998,7 +14970,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15015,7 +14986,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15032,7 +15002,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15049,7 +15018,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15066,7 +15034,6 @@ "os": [ "linux" ], - "peer": true, "funding": { "url": "https://opencollective.com/libvips" } @@ -15083,7 +15050,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15106,7 +15072,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15129,7 +15094,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15152,7 +15116,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15175,7 +15138,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15198,7 +15160,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, @@ -15667,7 +15628,6 @@ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", - "peer": true, "dependencies": { "client-only": "0.0.1" }, @@ -15837,7 +15797,6 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -15901,7 +15860,6 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -15999,6 +15957,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -16203,6 +16162,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16574,6 +16534,7 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -16663,7 +16624,8 @@ "resolved": "https://registry.npmjs.org/vite-plugin-electron-renderer/-/vite-plugin-electron-renderer-0.14.6.tgz", "integrity": "sha512-oqkWFa7kQIkvHXG7+Mnl1RTroA4sP0yesKatmAy0gjZC4VwUqlvF9IvOpHd1fpLWsqYX/eZlVxlhULNtaQ78Jw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/vite/node_modules/fdir": { "version": "6.5.0", @@ -16689,6 +16651,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -16731,6 +16694,7 @@ "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@vitest/expect": "4.0.16", "@vitest/mocker": "4.0.16", @@ -16988,6 +16952,7 @@ "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", + "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -17056,6 +17021,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.2.1.tgz", "integrity": "sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }