Full Code of FreeU-group/LifeTrace for AI

main 800cd27344fe cached
1003 files
14.1 MB
1.0M tokens
3969 symbols
1 requests
Download .txt
Showing preview only (4,490K chars total). Download the full file or copy to clipboard to get everything.
Repository: FreeU-group/LifeTrace
Branch: main
Commit: 800cd27344fe
Files: 1003
Total size: 14.1 MB

Directory structure:
gitextract_0o688pqc/

├── .cursor/
│   ├── commands/
│   │   ├── agno_agent.md
│   │   ├── agno_agent_CN.md
│   │   ├── backend.md
│   │   ├── backend_CN.md
│   │   ├── dynamic-island.md
│   │   ├── web.md
│   │   └── web_CN.md
│   └── plans/
│       ├── lifetrace_全面优化_76b5f86f.plan.md
│       ├── tauri_迁移方案_38d8ea4b.plan.md
│       ├── 后台持续录音方案_c7c8f0fe.plan.md
│       └── 打包与性能优化_ecd1657a.plan.md
├── .gitattributes
├── .githooks/
│   ├── post-checkout
│   └── pre-commit
├── .github/
│   ├── BACKEND_GUIDELINES.md
│   ├── BACKEND_GUIDELINES_CN.md
│   ├── CONTRIBUTING.md
│   ├── CONTRIBUTING_CN.md
│   ├── FRONTEND_GUIDELINES.md
│   ├── FRONTEND_GUIDELINES_CN.md
│   ├── GIT_FLOW.md
│   ├── GIT_FLOW_CN.md
│   ├── INSTALL.md
│   ├── INSTALL_CN.md
│   ├── PRE_COMMIT_GUIDE.md
│   ├── PRE_COMMIT_GUIDE_CN.md
│   ├── ROADMAP.md
│   ├── ROADMAP_CN.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── _disabled/
│       │   ├── dev-build-verify.yml
│       │   └── tauri-release.yml
│       ├── dependency-review.yml
│       └── pre-commit.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── AGENTS.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── README_CN.md
├── bandit.yaml
├── biome.json
├── free-todo-frontend/
│   ├── .gitignore
│   ├── app/
│   │   ├── globals.css
│   │   ├── home/
│   │   │   ├── HomePageClient.tsx
│   │   │   └── HomePageEntry.tsx
│   │   ├── island/
│   │   │   ├── island.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── apps/
│   │   ├── achievements/
│   │   │   └── AchievementsPanel.tsx
│   │   ├── activity/
│   │   │   ├── ActivityCard.tsx
│   │   │   ├── ActivityDetail.tsx
│   │   │   ├── ActivityHeader.tsx
│   │   │   ├── ActivityPanel.tsx
│   │   │   ├── ActivitySidebar.tsx
│   │   │   ├── ActivitySummary.tsx
│   │   │   └── utils/
│   │   │       └── timeUtils.ts
│   │   ├── audio/
│   │   │   ├── AudioPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── AudioExtractionPanel.tsx
│   │   │   │   ├── AudioHeader.tsx
│   │   │   │   ├── AudioList.tsx
│   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   ├── RecordingStatus.tsx
│   │   │   │   ├── StopRecordingConfirm.tsx
│   │   │   │   └── TranscriptionView.tsx
│   │   │   ├── hooks/
│   │   │   │   ├── useAudioData.ts
│   │   │   │   ├── useAudioDateSwitching.ts
│   │   │   │   ├── useAudioLink.ts
│   │   │   │   ├── useAudioPlayback.ts
│   │   │   │   ├── useAudioRecording.ts
│   │   │   │   ├── useAudioRecordingControl.ts
│   │   │   │   ├── useSegmentSync.ts
│   │   │   │   └── useStopRecordingConfirm.ts
│   │   │   └── utils/
│   │   │       ├── parseTimeToIsoWithDate.ts
│   │   │       └── timeUtils.ts
│   │   ├── calendar/
│   │   │   ├── CalendarPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── DayColumn.tsx
│   │   │   │   ├── DraggableTodo.tsx
│   │   │   │   ├── FloatingTodoCard.tsx
│   │   │   │   ├── QuickCreateBar.tsx
│   │   │   │   ├── QuickCreatePopover.tsx
│   │   │   │   ├── TimelineColumn.tsx
│   │   │   │   ├── TimelineCreatePopover.tsx
│   │   │   │   ├── TimelineSlot.tsx
│   │   │   │   └── TimelineTodoCard.tsx
│   │   │   ├── hooks/
│   │   │   │   └── useMonthScroll.ts
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   └── views/
│   │   │       ├── DayView.tsx
│   │   │       ├── MonthScroller.tsx
│   │   │       ├── MonthView.tsx
│   │   │       ├── WeekView.tsx
│   │   │       └── useWeekViewActions.ts
│   │   ├── chat/
│   │   │   ├── ChatPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── breakdown/
│   │   │   │   │   ├── BreakdownStageRenderer.tsx
│   │   │   │   │   ├── BreakdownSummary.tsx
│   │   │   │   │   └── Questionnaire.tsx
│   │   │   │   ├── input/
│   │   │   │   │   ├── ChatInputSection.tsx
│   │   │   │   │   ├── InputBox.tsx
│   │   │   │   │   ├── LinkedTodos.tsx
│   │   │   │   │   ├── PromptSuggestions.tsx
│   │   │   │   │   └── ToolSelector.tsx
│   │   │   │   ├── layout/
│   │   │   │   │   ├── HeaderBar.tsx
│   │   │   │   │   ├── HistoryDrawer.tsx
│   │   │   │   │   └── WelcomeGreetings.tsx
│   │   │   │   └── message/
│   │   │   │       ├── EditModeMessage.tsx
│   │   │   │       ├── MarkdownComponents.tsx
│   │   │   │       ├── MessageContent.tsx
│   │   │   │       ├── MessageContextMenu.tsx
│   │   │   │       ├── MessageItem.tsx
│   │   │   │       ├── MessageList.tsx
│   │   │   │       ├── MessageSources.tsx
│   │   │   │       ├── MessageTodoExtractionModal.tsx
│   │   │   │       ├── MessageTodoExtractionPanel.tsx
│   │   │   │       ├── SummaryStreaming.tsx
│   │   │   │       ├── ToolCallLoading.tsx
│   │   │   │       ├── ToolCallSteps.tsx
│   │   │   │       └── utils/
│   │   │   │           └── messageContentUtils.ts
│   │   │   ├── hooks/
│   │   │   │   ├── useBreakdownQuestionnaire.ts
│   │   │   │   ├── useBreakdownService.ts
│   │   │   │   ├── useChatController.ts
│   │   │   │   ├── useChatPrompts.ts
│   │   │   │   ├── useMessageExtraction.ts
│   │   │   │   ├── useMessageScroll.ts
│   │   │   │   ├── usePlanParser.ts
│   │   │   │   ├── useSendMessage.ts
│   │   │   │   ├── useSessionCache.ts
│   │   │   │   ├── useSessionManager.ts
│   │   │   │   ├── useStreamController.ts
│   │   │   │   └── useToolCallTracker.ts
│   │   │   ├── types.ts
│   │   │   └── utils/
│   │   │       ├── id.ts
│   │   │       ├── messageBuilder.ts
│   │   │       ├── parseEditBlocks.ts
│   │   │       ├── responseHandlers.ts
│   │   │       └── todoContext.ts
│   │   ├── cost-tracking/
│   │   │   ├── CostTrackingPanel.tsx
│   │   │   └── index.ts
│   │   ├── debug/
│   │   │   ├── DebugCapturePanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── EventCard.tsx
│   │   │   │   ├── EventSearchForm.tsx
│   │   │   │   ├── ScreenshotModal.tsx
│   │   │   │   ├── SelectedEventsBar.tsx
│   │   │   │   └── index.ts
│   │   │   ├── hooks/
│   │   │   │   ├── index.ts
│   │   │   │   ├── useEventActions.ts
│   │   │   │   └── useEventData.ts
│   │   │   └── utils.ts
│   │   ├── diary/
│   │   │   ├── DiaryEditor.tsx
│   │   │   ├── DiaryHeader.tsx
│   │   │   ├── DiaryPanel.tsx
│   │   │   ├── DiarySettings.tsx
│   │   │   ├── DiaryTabs.tsx
│   │   │   ├── JournalHistory.tsx
│   │   │   ├── index.ts
│   │   │   ├── journal-utils.ts
│   │   │   └── types.ts
│   │   ├── settings/
│   │   │   ├── SettingsPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── AudioAsrConfigSection.tsx
│   │   │   │   ├── AudioConfigSection.tsx
│   │   │   │   ├── AutoTodoDetectionSection.tsx
│   │   │   │   ├── AutomationTasksSection.tsx
│   │   │   │   ├── DifyConfigSection.tsx
│   │   │   │   ├── DockDisplayModeSection.tsx
│   │   │   │   ├── JournalSettingsSection.tsx
│   │   │   │   ├── LlmConfigSection.tsx
│   │   │   │   ├── NotificationPermissionSection.tsx
│   │   │   │   ├── OnboardingSection.tsx
│   │   │   │   ├── PanelSwitchesSection.tsx
│   │   │   │   ├── RecorderConfigSection.tsx
│   │   │   │   ├── SchedulerSection.tsx
│   │   │   │   ├── SettingsCategoryPanel.tsx
│   │   │   │   ├── SettingsSearchAction.tsx
│   │   │   │   ├── SettingsSection.tsx
│   │   │   │   ├── TavilyConfigSection.tsx
│   │   │   │   ├── ToggleSwitch.tsx
│   │   │   │   ├── VersionInfoSection.tsx
│   │   │   │   └── index.ts
│   │   │   ├── hooks/
│   │   │   │   └── useSettingsSearchMatchStats.ts
│   │   │   └── index.ts
│   │   ├── todo-detail/
│   │   │   ├── TodoDetail.tsx
│   │   │   ├── components/
│   │   │   │   ├── ArtifactsView.tsx
│   │   │   │   ├── AttachmentPreviewPanel.tsx
│   │   │   │   ├── BackgroundSection.tsx
│   │   │   │   ├── ChildTodoSection.tsx
│   │   │   │   ├── DatePickerCalendar.tsx
│   │   │   │   ├── DatePickerPopover.tsx
│   │   │   │   ├── DatePickerSidePanel.tsx
│   │   │   │   ├── DetailHeader.tsx
│   │   │   │   ├── DetailTitle.tsx
│   │   │   │   ├── MetaSection.tsx
│   │   │   │   ├── NotesEditor.tsx
│   │   │   │   └── datePickerUtils.ts
│   │   │   ├── helpers.ts
│   │   │   ├── hooks/
│   │   │   │   └── useNotesAutosize.ts
│   │   │   ├── index.ts
│   │   │   └── utils/
│   │   │       ├── date-utils.ts
│   │   │       ├── holiday-utils.ts
│   │   │       ├── index.ts
│   │   │       └── lunar-utils.ts
│   │   └── todo-list/
│   │       ├── CreateTodoForm.tsx
│   │       ├── NewTodoInlineForm.tsx
│   │       ├── TodoCard.tsx
│   │       ├── TodoExtractionModal.tsx
│   │       ├── TodoList.tsx
│   │       ├── TodoToolbar.tsx
│   │       ├── TodoTreeList.tsx
│   │       ├── components/
│   │       │   ├── TodoCardCheckbox.tsx
│   │       │   ├── TodoCardChildForm.tsx
│   │       │   ├── TodoCardDropZone.tsx
│   │       │   ├── TodoCardExpandButton.tsx
│   │       │   ├── TodoCardMetadata.tsx
│   │       │   ├── TodoCardName.tsx
│   │       │   └── TodoFilter.tsx
│   │       ├── hooks/
│   │       │   ├── useOrderedTodos.ts
│   │       │   ├── useTodoCardDrag.ts
│   │       │   ├── useTodoCardHandlers.ts
│   │       │   └── useTodoCardState.ts
│   │       ├── index.ts
│   │       └── utils/
│   │           └── todoCardUtils.ts
│   ├── components/
│   │   ├── common/
│   │   │   ├── ReminderOptions.tsx
│   │   │   ├── context-menu/
│   │   │   │   ├── BaseContextMenu.tsx
│   │   │   │   ├── MultiTodoContextMenu.tsx
│   │   │   │   └── TodoContextMenu.tsx
│   │   │   ├── layout/
│   │   │   │   ├── CollapsibleSection.tsx
│   │   │   │   ├── LayoutSelector.tsx
│   │   │   │   ├── LayoutSelectorDialogs.tsx
│   │   │   │   ├── PanelHeader.tsx
│   │   │   │   └── SectionHeader.tsx
│   │   │   ├── theme/
│   │   │   │   ├── ThemeProvider.tsx
│   │   │   │   ├── ThemeStyleSelect.tsx
│   │   │   │   └── ThemeToggle.tsx
│   │   │   └── ui/
│   │   │       ├── BackendReadyGate.tsx
│   │   │       ├── CapabilitiesSync.tsx
│   │   │       ├── DockTriggerZone.tsx
│   │   │       ├── FrontendBoot.tsx
│   │   │       ├── LanguageToggle.tsx
│   │   │       ├── LocaleSync.tsx
│   │   │       ├── ScrollbarController.tsx
│   │   │       ├── SettingsToggle.tsx
│   │   │       └── UserAvatar.tsx
│   │   ├── date-picker/
│   │   │   ├── DateOnlyPickerCalendar.tsx
│   │   │   ├── DateOnlyPickerPopover.tsx
│   │   │   └── date-picker-utils.ts
│   │   ├── island/
│   │   │   ├── DynamicIsland.tsx
│   │   │   ├── IslandContent.tsx
│   │   │   ├── IslandFullscreenContent.tsx
│   │   │   ├── IslandHeader.tsx
│   │   │   ├── IslandSidebarContent.tsx
│   │   │   └── index.ts
│   │   ├── layout/
│   │   │   ├── AppHeader.tsx
│   │   │   ├── BottomDock.tsx
│   │   │   ├── FullscreenHeader.tsx
│   │   │   ├── PanelContainer.tsx
│   │   │   ├── PanelContent.tsx
│   │   │   ├── PanelRegion.tsx
│   │   │   ├── PanelSelectorMenu.tsx
│   │   │   └── ResizeHandle.tsx
│   │   ├── notification/
│   │   │   └── HeaderIsland.tsx
│   │   └── ui/
│   │       ├── alert-dialog.tsx
│   │       ├── button.tsx
│   │       ├── dialog.tsx
│   │       └── dropdown-menu.tsx
│   ├── electron/
│   │   ├── PACKAGING_GUIDE.md
│   │   ├── PACKAGING_GUIDE_CN.md
│   │   ├── backend-server.ts
│   │   ├── bootstrap-control.ts
│   │   ├── bootstrap-status.ts
│   │   ├── bootstrap-window.ts
│   │   ├── config.ts
│   │   ├── git-info.ts
│   │   ├── global-shortcut-manager.ts
│   │   ├── ipc-handlers-todo-capture.ts
│   │   ├── ipc-handlers.ts
│   │   ├── island-window-manager.ts
│   │   ├── logger.ts
│   │   ├── main.ts
│   │   ├── next-server.ts
│   │   ├── notification.ts
│   │   ├── port-manager.ts
│   │   ├── preload.ts
│   │   ├── process-manager.ts
│   │   ├── python-runtime-command.ts
│   │   ├── python-runtime-env.ts
│   │   ├── python-runtime-installer.ts
│   │   ├── python-runtime.ts
│   │   ├── runtime-paths.ts
│   │   ├── tray-manager.ts
│   │   ├── tsconfig.json
│   │   └── window-manager.ts
│   ├── electron-builder.island.pyinstaller.yml
│   ├── electron-builder.island.script.yml
│   ├── electron-builder.island.yml
│   ├── electron-builder.web.pyinstaller.yml
│   ├── electron-builder.web.script.yml
│   ├── electron-builder.web.yml
│   ├── electron-builder.yml
│   ├── global.d.ts
│   ├── lib/
│   │   ├── api/
│   │   │   └── fetcher.ts
│   │   ├── api.ts
│   │   ├── attachments.ts
│   │   ├── config/
│   │   │   └── panel-config.ts
│   │   ├── dnd/
│   │   │   ├── context.tsx
│   │   │   ├── handlers.ts
│   │   │   ├── index.ts
│   │   │   ├── overlays.tsx
│   │   │   └── types.ts
│   │   ├── generated/
│   │   │   ├── activity/
│   │   │   │   └── activity.ts
│   │   │   ├── audio/
│   │   │   │   └── audio.ts
│   │   │   ├── case-transform.ts
│   │   │   ├── chat/
│   │   │   │   └── chat.ts
│   │   │   ├── config/
│   │   │   │   └── config.ts
│   │   │   ├── cost-tracking/
│   │   │   │   └── cost-tracking.ts
│   │   │   ├── default/
│   │   │   │   └── default.ts
│   │   │   ├── event/
│   │   │   │   └── event.ts
│   │   │   ├── floating-capture/
│   │   │   │   └── floating-capture.ts
│   │   │   ├── journals/
│   │   │   │   └── journals.ts
│   │   │   ├── logs/
│   │   │   │   └── logs.ts
│   │   │   ├── notifications/
│   │   │   │   └── notifications.ts
│   │   │   ├── ocr/
│   │   │   │   └── ocr.ts
│   │   │   ├── proactive-ocr/
│   │   │   │   └── proactive-ocr.ts
│   │   │   ├── rag/
│   │   │   │   └── rag.ts
│   │   │   ├── scheduler/
│   │   │   │   └── scheduler.ts
│   │   │   ├── schemas/
│   │   │   │   ├── activityEventsResponse.ts
│   │   │   │   ├── activityListResponse.ts
│   │   │   │   ├── activityResponse.ts
│   │   │   │   ├── activityResponseAiSummary.ts
│   │   │   │   ├── activityResponseAiTitle.ts
│   │   │   │   ├── activityResponseCreatedAt.ts
│   │   │   │   ├── activityResponseUpdatedAt.ts
│   │   │   │   ├── addMessageRequest.ts
│   │   │   │   ├── audioLinkItem.ts
│   │   │   │   ├── audioLinkRequest.ts
│   │   │   │   ├── bodyImportIcsApiTodosImportIcsPost.ts
│   │   │   │   ├── bodyUploadAttachmentsApiTodosTodoIdAttachmentsPost.ts
│   │   │   │   ├── capabilitiesResponse.ts
│   │   │   │   ├── capabilitiesResponseMissingDeps.ts
│   │   │   │   ├── chatMessage.ts
│   │   │   │   ├── chatMessageContext.ts
│   │   │   │   ├── chatMessageConversationId.ts
│   │   │   │   ├── chatMessageExternalTools.ts
│   │   │   │   ├── chatMessageMode.ts
│   │   │   │   ├── chatMessageProjectId.ts
│   │   │   │   ├── chatMessageSelectedTools.ts
│   │   │   │   ├── chatMessageSystemPrompt.ts
│   │   │   │   ├── chatMessageTaskIds.ts
│   │   │   │   ├── chatMessageUserInput.ts
│   │   │   │   ├── chatMessageWithContext.ts
│   │   │   │   ├── chatMessageWithContextConversationId.ts
│   │   │   │   ├── chatMessageWithContextEventContext.ts
│   │   │   │   ├── chatMessageWithContextEventContextAnyOfItem.ts
│   │   │   │   ├── chatMessageWorkspacePath.ts
│   │   │   │   ├── chatResponse.ts
│   │   │   │   ├── chatResponsePerformance.ts
│   │   │   │   ├── chatResponsePerformanceAnyOf.ts
│   │   │   │   ├── chatResponseQueryInfo.ts
│   │   │   │   ├── chatResponseQueryInfoAnyOf.ts
│   │   │   │   ├── chatResponseRetrievalInfo.ts
│   │   │   │   ├── chatResponseRetrievalInfoAnyOf.ts
│   │   │   │   ├── chatResponseSessionId.ts
│   │   │   │   ├── cleanupOldDataApiCleanupPostParams.ts
│   │   │   │   ├── contextListResponse.ts
│   │   │   │   ├── contextResponse.ts
│   │   │   │   ├── contextResponseAiSummary.ts
│   │   │   │   ├── contextResponseAiTitle.ts
│   │   │   │   ├── contextResponseAppName.ts
│   │   │   │   ├── contextResponseCreatedAt.ts
│   │   │   │   ├── contextResponseEndTime.ts
│   │   │   │   ├── contextResponseProjectId.ts
│   │   │   │   ├── contextResponseStartTime.ts
│   │   │   │   ├── contextResponseTaskId.ts
│   │   │   │   ├── contextResponseWindowTitle.ts
│   │   │   │   ├── contextUpdateRequest.ts
│   │   │   │   ├── contextUpdateRequestProjectId.ts
│   │   │   │   ├── contextUpdateRequestTaskId.ts
│   │   │   │   ├── countEventsApiEventsCountGetParams.ts
│   │   │   │   ├── createdTodo.ts
│   │   │   │   ├── createdTodoScheduledTime.ts
│   │   │   │   ├── eventDetailResponse.ts
│   │   │   │   ├── eventDetailResponseAiSummary.ts
│   │   │   │   ├── eventDetailResponseAiTitle.ts
│   │   │   │   ├── eventDetailResponseAppName.ts
│   │   │   │   ├── eventDetailResponseEndTime.ts
│   │   │   │   ├── eventDetailResponseWindowTitle.ts
│   │   │   │   ├── eventListResponse.ts
│   │   │   │   ├── eventResponse.ts
│   │   │   │   ├── eventResponseAiSummary.ts
│   │   │   │   ├── eventResponseAiTitle.ts
│   │   │   │   ├── eventResponseAppName.ts
│   │   │   │   ├── eventResponseEndTime.ts
│   │   │   │   ├── eventResponseFirstScreenshotId.ts
│   │   │   │   ├── eventResponseWindowTitle.ts
│   │   │   │   ├── exportIcsApiTodosExportIcsGetParams.ts
│   │   │   │   ├── extractTodosAndSchedulesApiAudioExtractPostParams.ts
│   │   │   │   ├── extractedMessageTodo.ts
│   │   │   │   ├── extractedMessageTodoDescription.ts
│   │   │   │   ├── extractedTodo.ts
│   │   │   │   ├── extractedTodoConfidence.ts
│   │   │   │   ├── extractedTodoDescription.ts
│   │   │   │   ├── extractedTodoScheduledTime.ts
│   │   │   │   ├── extractedTodoSourceText.ts
│   │   │   │   ├── extractedTodoTimeInfo.ts
│   │   │   │   ├── extractedTodoTimeInfoAnyOf.ts
│   │   │   │   ├── floatingCaptureRequest.ts
│   │   │   │   ├── floatingCaptureResponse.ts
│   │   │   │   ├── generateTasksResponse.ts
│   │   │   │   ├── generatedTaskItem.ts
│   │   │   │   ├── generatedTaskItemDescription.ts
│   │   │   │   ├── getChatHistoryApiChatHistoryGetParams.ts
│   │   │   │   ├── getChatPromptsApiGetChatPromptsGetParams.ts
│   │   │   │   ├── getContextsApiContextsGetParams.ts
│   │   │   │   ├── getCostStatsApiCostTrackingStatsGetParams.ts
│   │   │   │   ├── getLogContentApiLogsContentGetParams.ts
│   │   │   │   ├── getProjectTasksApiProjectsProjectIdTasksGetParams.ts
│   │   │   │   ├── getProjectsApiProjectsGetParams.ts
│   │   │   │   ├── getQuerySuggestionsApiChatSuggestionsGetParams.ts
│   │   │   │   ├── getRecordingsApiAudioRecordingsGetParams.ts
│   │   │   │   ├── getScreenshotsApiScreenshotsGetParams.ts
│   │   │   │   ├── getTaskProgressApiProjectsProjectIdTasksTaskIdProgressGetParams.ts
│   │   │   │   ├── getTaskProgressLatestApiProjectsProjectIdTasksTaskIdProgressLatestGet200.ts
│   │   │   │   ├── getTimeAllocationApiTimeAllocationGetParams.ts
│   │   │   │   ├── getTimelineApiAudioTimelineGetParams.ts
│   │   │   │   ├── getTranscriptionApiAudioTranscriptionRecordingIdGetParams.ts
│   │   │   │   ├── hTTPValidationError.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── jobInfo.ts
│   │   │   │   ├── jobInfoName.ts
│   │   │   │   ├── jobInfoNextRunTime.ts
│   │   │   │   ├── jobIntervalUpdateRequest.ts
│   │   │   │   ├── jobIntervalUpdateRequestHours.ts
│   │   │   │   ├── jobIntervalUpdateRequestMinutes.ts
│   │   │   │   ├── jobIntervalUpdateRequestSeconds.ts
│   │   │   │   ├── jobListResponse.ts
│   │   │   │   ├── jobOperationResponse.ts
│   │   │   │   ├── journalAutoLinkCandidate.ts
│   │   │   │   ├── journalAutoLinkRequest.ts
│   │   │   │   ├── journalAutoLinkResponse.ts
│   │   │   │   ├── journalCreate.ts
│   │   │   │   ├── journalGenerateRequest.ts
│   │   │   │   ├── journalGenerateResponse.ts
│   │   │   │   ├── journalListResponse.ts
│   │   │   │   ├── journalResponse.ts
│   │   │   │   ├── journalResponseDeletedAt.ts
│   │   │   │   ├── journalTag.ts
│   │   │   │   ├── journalUpdate.ts
│   │   │   │   ├── journalUpdateContentFormat.ts
│   │   │   │   ├── journalUpdateDate.ts
│   │   │   │   ├── journalUpdateName.ts
│   │   │   │   ├── journalUpdateTagIds.ts
│   │   │   │   ├── journalUpdateUserNotes.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodo.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoDescription.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoSourceText.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoTimeInfo.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoTimeInfoAnyOf.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodo.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoConfidence.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoDescription.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoScheduledTime.ts
│   │   │   │   ├── linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostParams.ts
│   │   │   │   ├── listActivitiesApiActivitiesGetParams.ts
│   │   │   │   ├── listEventsApiEventsGetParams.ts
│   │   │   │   ├── listJournalsApiJournalsGetParams.ts
│   │   │   │   ├── listTodosApiTodosGetParams.ts
│   │   │   │   ├── manualActivityCreateRequest.ts
│   │   │   │   ├── manualActivityCreateResponse.ts
│   │   │   │   ├── manualActivityCreateResponseAiSummary.ts
│   │   │   │   ├── manualActivityCreateResponseAiTitle.ts
│   │   │   │   ├── manualActivityCreateResponseCreatedAt.ts
│   │   │   │   ├── messageTodoExtractionRequest.ts
│   │   │   │   ├── messageTodoExtractionRequestMessagesItem.ts
│   │   │   │   ├── messageTodoExtractionRequestParentTodoId.ts
│   │   │   │   ├── messageTodoExtractionRequestTodoContext.ts
│   │   │   │   ├── messageTodoExtractionResponse.ts
│   │   │   │   ├── messageTodoExtractionResponseErrorMessage.ts
│   │   │   │   ├── newChatRequest.ts
│   │   │   │   ├── newChatRequestSessionId.ts
│   │   │   │   ├── newChatResponse.ts
│   │   │   │   ├── optimizeTranscriptionApiAudioOptimizePostParams.ts
│   │   │   │   ├── planQuestionnaireRequest.ts
│   │   │   │   ├── planQuestionnaireRequestSessionId.ts
│   │   │   │   ├── planQuestionnaireRequestTodoId.ts
│   │   │   │   ├── planSummaryRequest.ts
│   │   │   │   ├── planSummaryRequestAnswers.ts
│   │   │   │   ├── planSummaryRequestSessionId.ts
│   │   │   │   ├── processInfo.ts
│   │   │   │   ├── processOcrApiOcrProcessPostParams.ts
│   │   │   │   ├── projectCreate.ts
│   │   │   │   ├── projectCreateDefinitionOfDone.ts
│   │   │   │   ├── projectCreateDescription.ts
│   │   │   │   ├── projectListResponse.ts
│   │   │   │   ├── projectResponse.ts
│   │   │   │   ├── projectResponseDefinitionOfDone.ts
│   │   │   │   ├── projectResponseDescription.ts
│   │   │   │   ├── projectStatus.ts
│   │   │   │   ├── projectUpdate.ts
│   │   │   │   ├── projectUpdateDefinitionOfDone.ts
│   │   │   │   ├── projectUpdateDescription.ts
│   │   │   │   ├── projectUpdateName.ts
│   │   │   │   ├── projectUpdateStatus.ts
│   │   │   │   ├── saveAndInitLlmApiSaveAndInitLlmPostBody.ts
│   │   │   │   ├── saveConfigApiSaveConfigPostBody.ts
│   │   │   │   ├── screenshotResponse.ts
│   │   │   │   ├── screenshotResponseAppName.ts
│   │   │   │   ├── screenshotResponseTextContent.ts
│   │   │   │   ├── screenshotResponseWindowTitle.ts
│   │   │   │   ├── searchRequest.ts
│   │   │   │   ├── searchRequestAppName.ts
│   │   │   │   ├── searchRequestEndDate.ts
│   │   │   │   ├── searchRequestQuery.ts
│   │   │   │   ├── searchRequestStartDate.ts
│   │   │   │   ├── semanticSearchRequest.ts
│   │   │   │   ├── semanticSearchRequestFilters.ts
│   │   │   │   ├── semanticSearchRequestFiltersAnyOf.ts
│   │   │   │   ├── semanticSearchRequestRetrieveK.ts
│   │   │   │   ├── semanticSearchResult.ts
│   │   │   │   ├── semanticSearchResultMetadata.ts
│   │   │   │   ├── semanticSearchResultOcrResult.ts
│   │   │   │   ├── semanticSearchResultOcrResultAnyOf.ts
│   │   │   │   ├── semanticSearchResultScreenshot.ts
│   │   │   │   ├── semanticSearchResultScreenshotAnyOf.ts
│   │   │   │   ├── statisticsResponse.ts
│   │   │   │   ├── syncVectorDatabaseApiVectorSyncPostParams.ts
│   │   │   │   ├── systemResourcesResponse.ts
│   │   │   │   ├── systemResourcesResponseCpu.ts
│   │   │   │   ├── systemResourcesResponseDisk.ts
│   │   │   │   ├── systemResourcesResponseMemory.ts
│   │   │   │   ├── systemResourcesResponseStorage.ts
│   │   │   │   ├── systemResourcesResponseSummary.ts
│   │   │   │   ├── taskBatchDeleteRequest.ts
│   │   │   │   ├── taskBatchDeleteResponse.ts
│   │   │   │   ├── taskCreate.ts
│   │   │   │   ├── taskCreateDescription.ts
│   │   │   │   ├── taskListResponse.ts
│   │   │   │   ├── taskProgressListResponse.ts
│   │   │   │   ├── taskProgressResponse.ts
│   │   │   │   ├── taskResponse.ts
│   │   │   │   ├── taskResponseDescription.ts
│   │   │   │   ├── taskStatus.ts
│   │   │   │   ├── taskUpdate.ts
│   │   │   │   ├── taskUpdateDescription.ts
│   │   │   │   ├── taskUpdateName.ts
│   │   │   │   ├── taskUpdateStatus.ts
│   │   │   │   ├── testAsrConfigApiTestAsrConfigPostBody.ts
│   │   │   │   ├── testLlmConfigApiTestLlmConfigPostBody.ts
│   │   │   │   ├── testTavilyConfigApiTestTavilyConfigPostBody.ts
│   │   │   │   ├── timeAllocationResponse.ts
│   │   │   │   ├── timeAllocationResponseAppDetailsItem.ts
│   │   │   │   ├── timeAllocationResponseDailyDistributionItem.ts
│   │   │   │   ├── todoAttachmentResponse.ts
│   │   │   │   ├── todoAttachmentResponseFileSize.ts
│   │   │   │   ├── todoAttachmentResponseMimeType.ts
│   │   │   │   ├── todoCreate.ts
│   │   │   │   ├── todoCreateCompletedAt.ts
│   │   │   │   ├── todoCreateDeadline.ts
│   │   │   │   ├── todoCreateDescription.ts
│   │   │   │   ├── todoCreateEndTime.ts
│   │   │   │   ├── todoCreateParentTodoId.ts
│   │   │   │   ├── todoCreatePercentComplete.ts
│   │   │   │   ├── todoCreateRrule.ts
│   │   │   │   ├── todoCreateStartTime.ts
│   │   │   │   ├── todoCreateUid.ts
│   │   │   │   ├── todoCreateUserNotes.ts
│   │   │   │   ├── todoExtractionRequest.ts
│   │   │   │   ├── todoExtractionRequestScreenshotSampleRatio.ts
│   │   │   │   ├── todoExtractionResponse.ts
│   │   │   │   ├── todoExtractionResponseAppName.ts
│   │   │   │   ├── todoExtractionResponseErrorMessage.ts
│   │   │   │   ├── todoExtractionResponseEventEndTime.ts
│   │   │   │   ├── todoExtractionResponseEventStartTime.ts
│   │   │   │   ├── todoExtractionResponseWindowTitle.ts
│   │   │   │   ├── todoItemType.ts
│   │   │   │   ├── todoListResponse.ts
│   │   │   │   ├── todoPriority.ts
│   │   │   │   ├── todoReorderItem.ts
│   │   │   │   ├── todoReorderItemParentTodoId.ts
│   │   │   │   ├── todoReorderRequest.ts
│   │   │   │   ├── todoResponse.ts
│   │   │   │   ├── todoResponseCompletedAt.ts
│   │   │   │   ├── todoResponseDeadline.ts
│   │   │   │   ├── todoResponseDescription.ts
│   │   │   │   ├── todoResponseEndTime.ts
│   │   │   │   ├── todoResponseParentTodoId.ts
│   │   │   │   ├── todoResponseRrule.ts
│   │   │   │   ├── todoResponseStartTime.ts
│   │   │   │   ├── todoResponseUserNotes.ts
│   │   │   │   ├── todoStatus.ts
│   │   │   │   ├── todoTimeInfo.ts
│   │   │   │   ├── todoTimeInfoAbsoluteTime.ts
│   │   │   │   ├── todoTimeInfoRelativeDays.ts
│   │   │   │   ├── todoTimeInfoRelativeTime.ts
│   │   │   │   ├── todoTimeInfoTimeType.ts
│   │   │   │   ├── todoUpdate.ts
│   │   │   │   ├── todoUpdateCompletedAt.ts
│   │   │   │   ├── todoUpdateDeadline.ts
│   │   │   │   ├── todoUpdateDescription.ts
│   │   │   │   ├── todoUpdateEndTime.ts
│   │   │   │   ├── todoUpdateName.ts
│   │   │   │   ├── todoUpdateOrder.ts
│   │   │   │   ├── todoUpdateParentTodoId.ts
│   │   │   │   ├── todoUpdatePercentComplete.ts
│   │   │   │   ├── todoUpdatePriority.ts
│   │   │   │   ├── todoUpdateRelatedActivities.ts
│   │   │   │   ├── todoUpdateRrule.ts
│   │   │   │   ├── todoUpdateStartTime.ts
│   │   │   │   ├── todoUpdateStatus.ts
│   │   │   │   ├── todoUpdateTags.ts
│   │   │   │   ├── todoUpdateUserNotes.ts
│   │   │   │   ├── updateJournalApiJournalsJournalIdPutBody.ts
│   │   │   │   ├── validationError.ts
│   │   │   │   ├── validationErrorLocItem.ts
│   │   │   │   ├── vectorStatsResponse.ts
│   │   │   │   ├── vectorStatsResponseCollectionName.ts
│   │   │   │   ├── vectorStatsResponseDocumentCount.ts
│   │   │   │   ├── vectorStatsResponseError.ts
│   │   │   │   ├── visionChatRequest.ts
│   │   │   │   ├── visionChatRequestMaxTokens.ts
│   │   │   │   ├── visionChatRequestModel.ts
│   │   │   │   ├── visionChatRequestTemperature.ts
│   │   │   │   ├── visionChatResponse.ts
│   │   │   │   ├── visionChatResponseModel.ts
│   │   │   │   ├── visionChatResponseUsageInfo.ts
│   │   │   │   └── visionChatResponseUsageInfoAnyOf.ts
│   │   │   ├── screenshot/
│   │   │   │   └── screenshot.ts
│   │   │   ├── search/
│   │   │   │   └── search.ts
│   │   │   ├── system/
│   │   │   │   └── system.ts
│   │   │   ├── time-allocation/
│   │   │   │   └── time-allocation.ts
│   │   │   ├── todo-extraction/
│   │   │   │   └── todo-extraction.ts
│   │   │   ├── todos/
│   │   │   │   └── todos.ts
│   │   │   ├── vector/
│   │   │   │   └── vector.ts
│   │   │   └── vision/
│   │   │       └── vision.ts
│   │   ├── hooks/
│   │   │   ├── useAutoRecording.ts
│   │   │   ├── useOnboardingTour.ts
│   │   │   ├── useOpenSettings.ts
│   │   │   ├── usePanelLayout.ts
│   │   │   ├── usePanelResize.ts
│   │   │   ├── usePanelWindowResize.ts
│   │   │   ├── usePanelWindowStyles.ts
│   │   │   ├── useTodoCapture.ts
│   │   │   └── useWindowAdaptivePanels.ts
│   │   ├── i18n/
│   │   │   ├── messages/
│   │   │   │   ├── en.json
│   │   │   │   └── zh.json
│   │   │   └── request.ts
│   │   ├── island/
│   │   │   └── types.ts
│   │   ├── plugins/
│   │   │   └── registry.ts
│   │   ├── query/
│   │   │   ├── activities.ts
│   │   │   ├── automation.ts
│   │   │   ├── chat.ts
│   │   │   ├── config.ts
│   │   │   ├── cost.ts
│   │   │   ├── index.ts
│   │   │   ├── journals.ts
│   │   │   ├── keys.ts
│   │   │   ├── provider.tsx
│   │   │   └── todos.ts
│   │   ├── reminders.ts
│   │   ├── services/
│   │   │   └── notification-poller.ts
│   │   ├── store/
│   │   │   ├── activity-store.ts
│   │   │   ├── audio-recording-store.ts
│   │   │   ├── breakdown-store.ts
│   │   │   ├── chat-store.ts
│   │   │   ├── color-theme.ts
│   │   │   ├── journal-store.ts
│   │   │   ├── locale.ts
│   │   │   ├── notification-store.ts
│   │   │   ├── onboarding-store.ts
│   │   │   ├── theme.ts
│   │   │   ├── todo-store.ts
│   │   │   ├── ui-store/
│   │   │   │   ├── index.ts
│   │   │   │   ├── layout-actions.ts
│   │   │   │   ├── layout-presets.ts
│   │   │   │   ├── storage.ts
│   │   │   │   ├── store.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils.ts
│   │   │   └── ui-store.ts
│   │   ├── toast.ts
│   │   ├── types/
│   │   │   └── index.ts
│   │   ├── utils/
│   │   │   ├── electron-api.ts
│   │   │   ├── electron.ts
│   │   │   ├── platform.ts
│   │   │   └── time.ts
│   │   └── utils.ts
│   ├── next.config.ts
│   ├── orval.config.ts
│   ├── package.json
│   ├── pnpm-workspace.yaml
│   ├── postcss.config.mjs
│   ├── public/
│   │   ├── app-icons/
│   │   │   └── README.md
│   │   └── free-todo-logos/
│   │       └── favicon/
│   │           └── site.webmanifest
│   ├── scripts/
│   │   ├── build-electron.js
│   │   ├── check_code_lines.js
│   │   ├── check_rust_code_lines.js
│   │   ├── collect-tauri-artifacts.js
│   │   ├── copy-missing-deps.js
│   │   ├── dev-with-auto-port.js
│   │   ├── electron-dev-electron.ps1
│   │   ├── electron-dev.ps1
│   │   ├── resolve-symlinks.js
│   │   ├── tauri-copy-resources.js
│   │   └── tauri-prebuild.js
│   ├── src-tauri/
│   │   ├── .tauri-lint-dist/
│   │   │   └── .gitkeep
│   │   ├── Cargo.toml
│   │   ├── PACKAGING_GUIDE.md
│   │   ├── build.rs
│   │   ├── icons/
│   │   │   ├── android/
│   │   │   │   ├── mipmap-anydpi-v26/
│   │   │   │   │   └── ic_launcher.xml
│   │   │   │   └── values/
│   │   │   │       └── ic_launcher_background.xml
│   │   │   └── icon.icns
│   │   ├── rust-toolchain.toml
│   │   ├── rustfmt.toml
│   │   ├── src/
│   │   │   ├── backend.rs
│   │   │   ├── backend_log.rs
│   │   │   ├── backend_paths.rs
│   │   │   ├── backend_proxy.rs
│   │   │   ├── backend_python.rs
│   │   │   ├── backend_support.rs
│   │   │   ├── config.rs
│   │   │   ├── lib.rs
│   │   │   ├── main.rs
│   │   │   ├── nextjs.rs
│   │   │   ├── shortcut.rs
│   │   │   └── tray.rs
│   │   ├── tauri.conf.json
│   │   ├── tauri.island.pyinstaller.json
│   │   ├── tauri.island.script.json
│   │   ├── tauri.lint.json
│   │   ├── tauri.web.pyinstaller.json
│   │   └── tauri.web.script.json
│   ├── tailwind.config.ts
│   └── tsconfig.json
├── lifetrace/
│   ├── __init__.py
│   ├── alembic.ini
│   ├── config/
│   │   ├── default_config.yaml
│   │   ├── prompt.yaml
│   │   ├── prompts/
│   │   │   ├── agno_tools/
│   │   │   │   ├── en/
│   │   │   │   │   ├── breakdown.yaml
│   │   │   │   │   ├── conflict.yaml
│   │   │   │   │   ├── instructions.yaml
│   │   │   │   │   ├── stats.yaml
│   │   │   │   │   ├── tags.yaml
│   │   │   │   │   ├── time.yaml
│   │   │   │   │   └── todo.yaml
│   │   │   │   └── zh/
│   │   │   │       ├── breakdown.yaml
│   │   │   │       ├── conflict.yaml
│   │   │   │       ├── instructions.yaml
│   │   │   │       ├── stats.yaml
│   │   │   │       ├── tags.yaml
│   │   │   │       ├── time.yaml
│   │   │   │       └── todo.yaml
│   │   │   ├── audio.yaml
│   │   │   ├── chat.yaml
│   │   │   ├── llm.yaml
│   │   │   ├── plan.yaml
│   │   │   ├── rag.yaml
│   │   │   ├── search.yaml
│   │   │   ├── summary.yaml
│   │   │   └── todo.yaml
│   │   └── rapidocr_config.yaml
│   ├── core/
│   │   ├── __init__.py
│   │   ├── config_watcher.py
│   │   ├── dependencies.py
│   │   ├── lazy_services.py
│   │   └── module_registry.py
│   ├── docs/
│   │   └── MIGRATION_GUIDE.md
│   ├── jobs/
│   │   ├── activity_aggregator.py
│   │   ├── clean_data.py
│   │   ├── deadline_reminder.py
│   │   ├── job_manager.py
│   │   ├── ocr.py
│   │   ├── ocr_config.py
│   │   ├── ocr_processor.py
│   │   ├── proactive_ocr/
│   │   │   ├── __init__.py
│   │   │   ├── capture.py
│   │   │   ├── models.py
│   │   │   ├── ocr_engine.py
│   │   │   ├── priors/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── feishu.py
│   │   │   │   ├── registry.py
│   │   │   │   └── wechat.py
│   │   │   ├── roi.py
│   │   │   ├── router.py
│   │   │   └── service.py
│   │   ├── recorder.py
│   │   ├── recorder_blacklist.py
│   │   ├── recorder_capture.py
│   │   ├── recorder_config.py
│   │   ├── scheduler.py
│   │   └── todo_recorder.py
│   ├── llm/
│   │   ├── activity_summary_service.py
│   │   ├── agent_service.py
│   │   ├── agno_agent.py
│   │   ├── agno_tools/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── toolkit.py
│   │   │   └── tools/
│   │   │       ├── __init__.py
│   │   │       ├── breakdown_tools.py
│   │   │       ├── conflict_tools.py
│   │   │       ├── stats_tools.py
│   │   │       ├── tag_tools.py
│   │   │       ├── time_tools.py
│   │   │       └── todo_tools.py
│   │   ├── auto_todo_detection_service.py
│   │   ├── context_builder.py
│   │   ├── event_summary_clustering.py
│   │   ├── event_summary_config.py
│   │   ├── event_summary_ocr.py
│   │   ├── event_summary_service.py
│   │   ├── journal_generation_service.py
│   │   ├── llm_client.py
│   │   ├── llm_client_intent.py
│   │   ├── llm_client_query.py
│   │   ├── llm_client_vision.py
│   │   ├── ocr_todo_extractor.py
│   │   ├── rag_fallback.py
│   │   ├── rag_service.py
│   │   ├── rag_stream.py
│   │   ├── retrieval_service.py
│   │   ├── tavily_client.py
│   │   ├── todo_extraction_service.py
│   │   ├── tools/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── registry.py
│   │   │   └── web_search_tool.py
│   │   ├── vector_db.py
│   │   ├── vector_service.py
│   │   └── web_search_service.py
│   ├── migrations/
│   │   ├── MIGRATIONS.md
│   │   ├── README
│   │   ├── env.py
│   │   ├── re_extract_all_transcriptions.py
│   │   ├── script.py.mako
│   │   └── versions/
│   │       ├── 034079ad387f_add_segment_timestamps.py
│   │       ├── 4ca5036ec7c8_add_context_to_chats.py
│   │       ├── add_automation_tasks_001.py
│   │       ├── add_file_path_to_audio_recordings.py
│   │       ├── add_icalendar_fields_v2_001.py
│   │       ├── add_journal_panel_001.py
│   │       ├── add_optimized_extraction_fields.py
│   │       ├── add_text_hash_to_ocr_results.py
│   │       ├── add_todo_attachment_source_001.py
│   │       ├── add_todo_end_time_001.py
│   │       ├── add_todo_reminder_offsets_001.py
│   │       ├── add_todo_timezone_all_day_001.py
│   │       ├── b53d9b7c8e21_add_uid_to_journals.py
│   │       ├── cc25001eb19c_initial_schema.py
│   │       ├── cff6e6d7a3cf_merge_heads_segment_timestamps_and_.py
│   │       ├── d2f7a9c6b1a4_add_icalendar_fields_to_todos.py
│   │       ├── merge_automation_ical_001.py
│   │       ├── merge_heads_journal_todo_20260203.py
│   │       ├── merge_heads_todos_20260131.py
│   │       ├── merge_journal_uid_automation_20260204.py
│   │       └── remove_project_task_tables.py
│   ├── models/
│   │   ├── ch_PP-OCRv4_det_infer.onnx
│   │   ├── ch_PP-OCRv4_rec_infer.onnx
│   │   └── ch_ppocr_mobile_v2.0_cls_infer.onnx
│   ├── observability/
│   │   ├── __init__.py
│   │   ├── config.py
│   │   ├── exporters/
│   │   │   ├── __init__.py
│   │   │   ├── file_exporter.py
│   │   │   └── phoenix_exporter.py
│   │   └── setup.py
│   ├── pyinstaller.spec
│   ├── repositories/
│   │   ├── __init__.py
│   │   ├── interfaces.py
│   │   ├── sql_activity_repository.py
│   │   ├── sql_chat_repository.py
│   │   ├── sql_event_repository.py
│   │   ├── sql_journal_repository.py
│   │   └── sql_todo_repository.py
│   ├── routers/
│   │   ├── activity.py
│   │   ├── audio.py
│   │   ├── audio_ws.py
│   │   ├── audio_ws_handler.py
│   │   ├── audio_ws_segment.py
│   │   ├── automation.py
│   │   ├── chat/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── context.py
│   │   │   ├── core.py
│   │   │   ├── helpers.py
│   │   │   ├── message_todo_extraction.py
│   │   │   ├── misc.py
│   │   │   ├── modes/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── agent.py
│   │   │   │   ├── agno.py
│   │   │   │   ├── dify.py
│   │   │   │   └── web_search.py
│   │   │   └── plan.py
│   │   ├── chat.py
│   │   ├── config.py
│   │   ├── cost_tracking.py
│   │   ├── event.py
│   │   ├── floating_capture.py
│   │   ├── health.py
│   │   ├── journal.py
│   │   ├── logs.py
│   │   ├── notification.py
│   │   ├── ocr.py
│   │   ├── proactive_ocr.py
│   │   ├── rag.py
│   │   ├── scheduler.py
│   │   ├── screenshot.py
│   │   ├── search.py
│   │   ├── system.py
│   │   ├── time_allocation.py
│   │   ├── todo.py
│   │   ├── todo_extraction.py
│   │   ├── vector.py
│   │   └── vision.py
│   ├── schemas/
│   │   ├── __init__.py
│   │   ├── activity.py
│   │   ├── automation.py
│   │   ├── chat.py
│   │   ├── event.py
│   │   ├── floating_capture.py
│   │   ├── journal.py
│   │   ├── message_todo_extraction.py
│   │   ├── screenshot.py
│   │   ├── search.py
│   │   ├── stats.py
│   │   ├── system.py
│   │   ├── todo.py
│   │   ├── todo_extraction.py
│   │   ├── vector.py
│   │   └── vision.py
│   ├── scripts/
│   │   ├── add_file_path_column.py
│   │   ├── build-backend.ps1
│   │   ├── build-backend.sh
│   │   ├── check_code_lines.py
│   │   ├── fix_audio_recordings_table.py
│   │   ├── fix_transcriptions_table.py
│   │   └── start_backend.py
│   ├── server.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── activity_service.py
│   │   ├── asr_client.py
│   │   ├── asr_client_dashscope.py
│   │   ├── audio_extraction_service.py
│   │   ├── audio_service.py
│   │   ├── automation_task_service.py
│   │   ├── chat_service.py
│   │   ├── config_service.py
│   │   ├── dify_client.py
│   │   ├── event_service.py
│   │   ├── icalendar_service.py
│   │   ├── journal_service.py
│   │   └── todo_service.py
│   ├── storage/
│   │   ├── __init__.py
│   │   ├── activity_manager.py
│   │   ├── automation_task_manager.py
│   │   ├── chat_manager.py
│   │   ├── database.py
│   │   ├── database_base.py
│   │   ├── event_manager.py
│   │   ├── event_queries.py
│   │   ├── event_stats.py
│   │   ├── journal_manager.py
│   │   ├── migrations/
│   │   │   └── journal_migration.py
│   │   ├── models.py
│   │   ├── notification_storage.py
│   │   ├── ocr_manager.py
│   │   ├── screenshot_manager.py
│   │   ├── sql_utils.py
│   │   ├── stats_manager.py
│   │   ├── todo_manager.py
│   │   ├── todo_manager_attachments.py
│   │   ├── todo_manager_ical.py
│   │   └── todo_manager_utils.py
│   └── util/
│       ├── app_utils.py
│       ├── base_paths.py
│       ├── image_utils.py
│       ├── language.py
│       ├── logging_config.py
│       ├── path_utils.py
│       ├── prompt_loader.py
│       ├── query_parser.py
│       ├── settings.py
│       ├── time_parser.py
│       ├── time_utils.py
│       ├── token_usage_logger.py
│       └── utils.py
├── pyproject.toml
├── pyrightconfig.json
├── requirements-runtime.txt
├── scripts/
│   ├── git-hooks/
│   │   └── post-checkout
│   ├── install.ps1
│   ├── install.sh
│   ├── link_worktree_deps.ps1
│   ├── link_worktree_deps.sh
│   ├── link_worktree_deps_here.ps1
│   ├── link_worktree_deps_here.sh
│   ├── new_worktree.py
│   ├── precommit_clippy.py
│   ├── precommit_rustfmt.py
│   ├── setup_hooks_here.ps1
│   └── setup_hooks_here.sh
└── tests/
    ├── conftest.py
    ├── test_icalendar_service.py
    ├── test_todo_serialization.py
    └── test_todo_service_mapping.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .cursor/commands/agno_agent.md
================================================
# Agno Agent Development Quick Commands

## Overview

This guide covers development of **Agno Agent Tools** - the AI-powered todo management toolkit based on the [Agno framework](https://docs.agno.com/).

The FreeTodoToolkit provides a set of tools for the Agno Agent to manage todos. For the complete list of available tools, please refer to the source code in `llm/agno_tools/tools/` directory.

---

## 🏗️ Architecture

### Directory Structure

```
lifetrace/
├── config/prompts/agno_tools/     # Localized messages & prompts
│   ├── zh/                        # Chinese messages
│   └── en/                        # English messages (same structure)
│
├── llm/agno_tools/                # Python implementation
│   ├── __init__.py                # Module exports
│   ├── base.py                    # Message loader (AgnoToolsMessageLoader)
│   ├── toolkit.py                 # Main FreeTodoToolkit class
│   └── tools/                     # Individual tool implementations (organized by category)
│
└── observability/                 # Agent monitoring (Phoenix + OpenInference)
    ├── __init__.py                # Module exports
    ├── config.py                  # Observability configuration
    ├── setup.py                   # Initialization entry point
    └── exporters/
        ├── __init__.py
        └── file_exporter.py       # Local JSON file exporter
```

### Design Patterns

- **Mixin Pattern**: Each tool category is a separate mixin class
- **Composition**: FreeTodoToolkit inherits from all mixins + Agno Toolkit
- **i18n**: Messages loaded from language-specific YAML files
- **Lazy Loading**: Database and LLM clients initialized on-demand

---

## 🔧 Adding a New Tool

### Step 1: Add Messages (Both Languages)

Create or update YAML files in `config/prompts/agno_tools/zh/` and `en/`:

```yaml
# config/prompts/agno_tools/zh/my_tool.yaml
my_tool_success: "操作成功: {result}"
my_tool_failed: "操作失败: {error}"
my_tool_prompt: |
  这是给 LLM 的提示词模板。
  参数: {param}
```

```yaml
# config/prompts/agno_tools/en/my_tool.yaml
my_tool_success: "Operation successful: {result}"
my_tool_failed: "Operation failed: {error}"
my_tool_prompt: |
  This is a prompt template for LLM.
  Parameter: {param}
```

### Step 2: Create Tool Mixin

Create a new file in `llm/agno_tools/tools/`:

```python
# llm/agno_tools/tools/my_tools.py
"""My Tools - Description of what these tools do."""

from __future__ import annotations
from typing import TYPE_CHECKING

from lifetrace.llm.agno_tools.base import get_message
from lifetrace.util.logging_config import get_logger

if TYPE_CHECKING:
    from lifetrace.repositories.sql_todo_repository import SqlTodoRepository

logger = get_logger()


class MyTools:
    """My tools mixin"""

    lang: str
    todo_repo: "SqlTodoRepository"  # If needed

    def _msg(self, key: str, **kwargs) -> str:
        return get_message(self.lang, key, **kwargs)

    def my_tool_method(self, param: str) -> str:
        """Tool description for LLM to understand when to use it

        Args:
            param: Description of the parameter

        Returns:
            Result message
        """
        try:
            # Implementation
            result = f"processed {param}"
            return self._msg("my_tool_success", result=result)
        except Exception as e:
            logger.error(f"Failed: {e}")
            return self._msg("my_tool_failed", error=str(e))
```

### Step 3: Register in Toolkit

Update `llm/agno_tools/tools/__init__.py`:

```python
from lifetrace.llm.agno_tools.tools.my_tools import MyTools

__all__ = [..., "MyTools"]
```

Update `llm/agno_tools/toolkit.py`:

```python
from lifetrace.llm.agno_tools.tools import (
    ...,
    MyTools,
)

class FreeTodoToolkit(
    ...,
    MyTools,  # Add mixin
    Toolkit,
):
    def __init__(self, lang: str = "en", **kwargs):
        ...
        tools = [
            ...,
            self.my_tool_method,  # Register tool
        ]
```

---

## 📝 Message Configuration

### YAML Structure

Messages are organized by functionality in `config/prompts/agno_tools/{lang}/` directory. Each YAML file corresponds to a category of messages.

### Message Format

- Use `{placeholder}` for variable substitution
- Multi-line prompts use YAML `|` syntax
- Keep messages concise and informative

```yaml
# Simple message with placeholder
create_success: "Created todo #{id}: {name}"

# Multi-line prompt
breakdown_prompt: |
  Break down this task into subtasks.

  Task: {task_description}

  Return JSON format.
```

### Accessing Messages

```python
# In tool methods
def _msg(self, key: str, **kwargs) -> str:
    return get_message(self.lang, key, **kwargs)

# Usage
return self._msg("create_success", id=123, name="Buy groceries")
```

---

## 🌐 Internationalization

### Language Selection

Language is passed through the call chain:

```
Request Header (Accept-Language)
    ↓
Chat Router (get_request_language)
    ↓
AgnoAgentService(lang=lang)
    ↓
FreeTodoToolkit(lang=lang)
    ↓
AgnoToolsMessageLoader(lang)
```

### Adding a New Language

1. Create new directory: `config/prompts/agno_tools/{lang}/`
2. Copy all YAML files from `en/`
3. Translate all messages
4. The loader will automatically detect the new language

---

## 🧪 Testing Tools

### Quick Test Script

```python
from lifetrace.llm.agno_tools import FreeTodoToolkit

# Test Chinese
toolkit_zh = FreeTodoToolkit(lang="zh")
print(toolkit_zh.list_todos(status="active", limit=5))

# Test English
toolkit_en = FreeTodoToolkit(lang="en")
print(toolkit_en.list_todos(status="active", limit=5))
```

### Running Tests

```bash
uv run python -c "
from lifetrace.llm.agno_tools import FreeTodoToolkit
tk = FreeTodoToolkit(lang='zh')
print(tk.parse_time('明天下午3点'))
"
```

---

## 📊 Observability (Agent Monitoring)

The Agno Agent integrates with [Arize Phoenix](https://arize.com/docs/phoenix) + [OpenInference](https://github.com/arize-ai/openinference) for tracing and monitoring.

### Features

- **Local JSON Export**: Cursor-friendly trace files for AI analysis
- **Phoenix UI**: Optional web-based visualization
- **Minimal Terminal Output**: One-line summary per trace

### Configuration

In `config/config.yaml`:

```yaml
observability:
  enabled: true                    # Enable observability
  mode: both                       # local | phoenix | both
  local:
    traces_dir: traces/            # Trace file directory
    max_files: 100                 # Max files to keep
    pretty_print: true             # Format JSON for readability
  phoenix:
    endpoint: http://localhost:6006
    project_name: freetodo-agent
  terminal:
    summary_only: true             # One-line output (recommended)
```

### Trace File Format

Each agent run generates a JSON file in `data/traces/`:

```json
{
  "trace_id": "e078e147372a",
  "timestamp": "2026-01-23T08:23:48.377470+00:00",
  "duration_ms": 26910.94,
  "agent": "breakdown_task",
  "input": "{\"task_description\": \"Make a video\"}",
  "output_preview": "Task breakdown:\n1. Define topic...",
  "tool_calls": [
    {
      "name": "breakdown_task",
      "args": {"task_description": "Make a video"},
      "result_preview": "Task breakdown...",
      "duration_ms": 26910.94
    }
  ],
  "llm_calls": [],
  "status": "success",
  "span_count": 1
}
```

### Terminal Output

With `summary_only: true`:

```
[Trace] e078e147372a | 1 tools | 26.91s | traces/20260123_082348_e078e147372a.json
```

### Using Phoenix UI (Optional)

```bash
# Start Phoenix server
uv run phoenix serve

# Access http://localhost:6006
```

---

## ✅ Development Checklist

When adding new tools:

- [ ] Create YAML messages in both `zh/` and `en/` directories
- [ ] Create tool mixin class with proper type hints
- [ ] Add docstrings for LLM to understand tool usage
- [ ] Use `_msg()` for all user-facing messages
- [ ] Handle exceptions and return error messages
- [ ] Register tool in `tools/__init__.py`
- [ ] Add mixin to `FreeTodoToolkit` class
- [ ] Register method in `tools` list
- [ ] Test with both languages


================================================
FILE: .cursor/commands/agno_agent_CN.md
================================================
# Agno Agent 开发快捷命令

## 概述

本指南涵盖 **Agno Agent Tools** 的开发 - 基于 [Agno 框架](https://docs.agno.com/) 的 AI 待办管理工具包。

FreeTodoToolkit 为 Agno Agent 提供一系列工具,用于管理待办事项。具体工具列表请查阅 `llm/agno_tools/tools/` 目录下的源代码。

---

## 🏗️ 架构

### 目录结构

```
lifetrace/
├── config/prompts/agno_tools/     # 本地化消息和提示词
│   ├── zh/                        # 中文消息
│   └── en/                        # 英文消息(结构相同)
│
├── llm/agno_tools/                # Python 实现
│   ├── __init__.py                # 模块导出
│   ├── base.py                    # 消息加载器 (AgnoToolsMessageLoader)
│   ├── toolkit.py                 # 主 FreeTodoToolkit 类
│   └── tools/                     # 各工具实现(按功能分类)
│
└── observability/                 # Agent 监控(Phoenix + OpenInference)
    ├── __init__.py                # 模块导出
    ├── config.py                  # 观测配置
    ├── setup.py                   # 初始化入口
    └── exporters/
        ├── __init__.py
        └── file_exporter.py       # 本地 JSON 文件导出器
```

### 设计模式

- **Mixin 模式**:每个工具类别是独立的 mixin 类
- **组合模式**:FreeTodoToolkit 继承所有 mixin + Agno Toolkit
- **国际化**:消息从语言特定的 YAML 文件加载
- **懒加载**:数据库和 LLM 客户端按需初始化

---

## 🔧 添加新工具

### 步骤 1:添加消息(中英文)

在 `config/prompts/agno_tools/zh/` 和 `en/` 中创建或更新 YAML 文件:

```yaml
# config/prompts/agno_tools/zh/my_tool.yaml
my_tool_success: "操作成功: {result}"
my_tool_failed: "操作失败: {error}"
my_tool_prompt: |
  这是给 LLM 的提示词模板。
  参数: {param}
```

```yaml
# config/prompts/agno_tools/en/my_tool.yaml
my_tool_success: "Operation successful: {result}"
my_tool_failed: "Operation failed: {error}"
my_tool_prompt: |
  This is a prompt template for LLM.
  Parameter: {param}
```

### 步骤 2:创建工具 Mixin

在 `llm/agno_tools/tools/` 中创建新文件:

```python
# llm/agno_tools/tools/my_tools.py
"""My Tools - 这些工具的功能描述"""

from __future__ import annotations
from typing import TYPE_CHECKING

from lifetrace.llm.agno_tools.base import get_message
from lifetrace.util.logging_config import get_logger

if TYPE_CHECKING:
    from lifetrace.repositories.sql_todo_repository import SqlTodoRepository

logger = get_logger()


class MyTools:
    """My tools mixin"""

    lang: str
    todo_repo: "SqlTodoRepository"  # 如果需要

    def _msg(self, key: str, **kwargs) -> str:
        return get_message(self.lang, key, **kwargs)

    def my_tool_method(self, param: str) -> str:
        """工具描述,让 LLM 理解何时使用此工具

        Args:
            param: 参数描述

        Returns:
            结果消息
        """
        try:
            # 实现逻辑
            result = f"processed {param}"
            return self._msg("my_tool_success", result=result)
        except Exception as e:
            logger.error(f"Failed: {e}")
            return self._msg("my_tool_failed", error=str(e))
```

### 步骤 3:注册到 Toolkit

更新 `llm/agno_tools/tools/__init__.py`:

```python
from lifetrace.llm.agno_tools.tools.my_tools import MyTools

__all__ = [..., "MyTools"]
```

更新 `llm/agno_tools/toolkit.py`:

```python
from lifetrace.llm.agno_tools.tools import (
    ...,
    MyTools,
)

class FreeTodoToolkit(
    ...,
    MyTools,  # 添加 mixin
    Toolkit,
):
    def __init__(self, lang: str = "en", **kwargs):
        ...
        tools = [
            ...,
            self.my_tool_method,  # 注册工具
        ]
```

---

## 📝 消息配置

### YAML 结构

消息按功能组织在 `config/prompts/agno_tools/{lang}/` 目录下。每个 YAML 文件对应一类功能的消息。

### 消息格式

- 使用 `{placeholder}` 进行变量替换
- 多行提示词使用 YAML `|` 语法
- 保持消息简洁且信息丰富

```yaml
# 带占位符的简单消息
create_success: "成功创建待办 #{id}: {name}"

# 多行提示词
breakdown_prompt: |
  请将此任务拆解为子任务。

  任务: {task_description}

  返回 JSON 格式。
```

### 访问消息

```python
# 在工具方法中
def _msg(self, key: str, **kwargs) -> str:
    return get_message(self.lang, key, **kwargs)

# 使用
return self._msg("create_success", id=123, name="买菜")
```

---

## 🌐 国际化

### 语言选择

语言通过调用链传递:

```
请求头 (Accept-Language)
    ↓
Chat Router (get_request_language)
    ↓
AgnoAgentService(lang=lang)
    ↓
FreeTodoToolkit(lang=lang)
    ↓
AgnoToolsMessageLoader(lang)
```

### 添加新语言

1. 创建新目录:`config/prompts/agno_tools/{lang}/`
2. 从 `en/` 复制所有 YAML 文件
3. 翻译所有消息
4. 加载器会自动检测新语言

---

## 🧪 测试工具

### 快速测试脚本

```python
from lifetrace.llm.agno_tools import FreeTodoToolkit

# 测试中文
toolkit_zh = FreeTodoToolkit(lang="zh")
print(toolkit_zh.list_todos(status="active", limit=5))

# 测试英文
toolkit_en = FreeTodoToolkit(lang="en")
print(toolkit_en.list_todos(status="active", limit=5))
```

### 运行测试

```bash
uv run python -c "
from lifetrace.llm.agno_tools import FreeTodoToolkit
tk = FreeTodoToolkit(lang='zh')
print(tk.parse_time('明天下午3点'))
"
```

---

## 📊 可观测性(Agent 监控)

Agno Agent 集成了 [Arize Phoenix](https://arize.com/docs/phoenix) + [OpenInference](https://github.com/arize-ai/openinference) 进行链路追踪和监控。

### 功能特性

- **本地 JSON 导出**:Cursor 友好的 trace 文件,便于 AI 分析
- **Phoenix UI**:可选的 Web 可视化界面
- **精简终端输出**:每次 trace 仅输出一行摘要

### 配置方法

在 `config/config.yaml` 中:

```yaml
observability:
  enabled: true                    # 启用观测功能
  mode: both                       # local | phoenix | both
  local:
    traces_dir: traces/            # trace 文件目录
    max_files: 100                 # 最大保留文件数
    pretty_print: true             # 格式化 JSON 便于阅读
  phoenix:
    endpoint: http://localhost:6006
    project_name: freetodo-agent
  terminal:
    summary_only: true             # 仅输出一行摘要(推荐)
```

### Trace 文件格式

每次 Agent 运行会在 `data/traces/` 生成一个 JSON 文件:

```json
{
  "trace_id": "e078e147372a",
  "timestamp": "2026-01-23T08:23:48.377470+00:00",
  "duration_ms": 26910.94,
  "agent": "breakdown_task",
  "input": "{\"task_description\": \"做视频\"}",
  "output_preview": "任务拆解结果:\n1. 确定视频主题...",
  "tool_calls": [
    {
      "name": "breakdown_task",
      "args": {"task_description": "做视频"},
      "result_preview": "任务拆解结果...",
      "duration_ms": 26910.94
    }
  ],
  "llm_calls": [],
  "status": "success",
  "span_count": 1
}
```

### 终端输出

启用 `summary_only: true` 时:

```
[Trace] e078e147372a | 1 tools | 26.91s | traces/20260123_082348_e078e147372a.json
```

### 使用 Phoenix UI(可选)

```bash
# 启动 Phoenix 服务
uv run phoenix serve

# 访问 http://localhost:6006
```

---

## ✅ 开发检查清单

添加新工具时:

- [ ] 在 `zh/` 和 `en/` 目录中创建 YAML 消息
- [ ] 创建带有正确类型提示的工具 mixin 类
- [ ] 添加文档字符串让 LLM 理解工具用途
- [ ] 所有用户可见消息使用 `_msg()`
- [ ] 处理异常并返回错误消息
- [ ] 在 `tools/__init__.py` 中注册工具
- [ ] 将 mixin 添加到 `FreeTodoToolkit` 类
- [ ] 在 `tools` 列表中注册方法
- [ ] 使用两种语言测试


================================================
FILE: .cursor/commands/backend.md
================================================
# Backend Development Quick Commands (lifetrace version)

## Tech Stack Information

- **Framework**: FastAPI + Uvicorn (async web framework)
- **Language**: Python 3.12
- **ORM**: SQLAlchemy 2.x + SQLModel
- **Database Migration**: Alembic
- **Data Validation**: Pydantic 2.x
- **Configuration Management**: Dynaconf (supports YAML hot reload)
- **Logging**: Loguru
- **Scheduler**: APScheduler (background task scheduling)
- **OCR**: RapidOCR (local OCR recognition)
- **Vector Database**: ChromaDB (optional, for semantic search)
- **Text Embedding**: sentence-transformers (optional)
- **LLM**: OpenAI-compatible API
- **Package Manager**: uv (recommended)
- **Code Quality**: Ruff (lint/format/check)

---

## 🏗️ Project Architecture

```
lifetrace/
├── server.py                 # FastAPI application entry point
├── config/                   # Configuration files directory
│   ├── config.yaml          # User configuration
│   ├── default_config.yaml  # Default configuration
│   └── prompt.yaml          # LLM Prompt templates
├── routers/                  # API routing layer
├── services/                 # Business service layer
├── repositories/             # Data access layer (Repository pattern)
├── schemas/                  # Pydantic data models
├── storage/                  # Data storage layer (SQLAlchemy models)
├── llm/                      # LLM and AI services
├── jobs/                     # Background tasks
├── core/                     # Core dependencies and lazy-loaded services
└── util/                     # Utility functions
```

### Layered Architecture Overview

- **Router Layer**: Handles HTTP requests, parameter validation, calls Service layer
- **Service Layer**: Business logic, orchestrates multiple Repository operations
- **Repository Layer**: Data access abstraction, encapsulates database queries
- **Schema Layer**: Request/response Pydantic models
- **Storage Layer**: SQLAlchemy ORM model definitions

---

## 🔧 Route Development

### Creating New API Routes

Create new routes in the `lifetrace/routers/` directory:
- Use `APIRouter` to define route prefixes and tags
- Follow RESTful API design principles
- Use dependency injection to get database sessions
- Add complete type annotations and docstrings

### RESTful Route Conventions

- `GET /api/{resource}` - Get list
- `GET /api/{resource}/{id}` - Get single resource
- `POST /api/{resource}` - Create resource
- `PUT /api/{resource}/{id}` - Full update
- `PATCH /api/{resource}/{id}` - Partial update
- `DELETE /api/{resource}/{id}` - Delete resource

### Registering Routes

Import and register new routes in `server.py`:
- Use `app.include_router(xxx.router)` to register
- Routes organized by functional modules

---

## 📦 Data Models

### Pydantic Schema Conventions

Create data models in the `lifetrace/schemas/` directory:
- Use Pydantic v2 syntax
- Distinguish models for different scenarios: `Create`, `Update`, `Response`, etc.
- Use `Field()` to add validation rules and descriptions
- Enable `model_config = ConfigDict(from_attributes=True)` to support ORM conversion

### Common Model Patterns

- `{Resource}Create` - Request body for creation
- `{Resource}Update` - Request body for updates (fields typically Optional)
- `{Resource}Response` - API response format
- `{Resource}List` - List response (includes pagination info)

### SQLAlchemy Model Conventions

Define database tables in `lifetrace/storage/models.py`:
- Use SQLAlchemy 2.x declarative syntax
- Add indexes for commonly queried fields
- Use relationships to define table associations
- Add `created_at` and `updated_at` timestamp fields

---

## 🗄️ Repository Layer

### Creating Repositories

Create data access classes in the `lifetrace/repositories/` directory:
- Inherit or implement interfaces defined in `interfaces.py`
- Encapsulate all database query logic
- Use async methods (`async def`)
- Support parameterized queries to prevent SQL injection

### Repository Naming Conventions

- `sql_{resource}_repository.py` - SQL database implementation
- Class names use `{Resource}Repository` format

---

## 🎯 Service Layer

### Creating Services

Create business services in the `lifetrace/services/` directory:
- Implement complex business logic
- Orchestrate multiple Repository operations
- Handle transaction boundaries
- Call external services (LLM, OCR, etc.)

### Service Conventions

- Class names use `{Resource}Service` format
- Get Repository instances through dependency injection
- Use custom Exception classes for business exceptions
- Add detailed logging

---

## 🤖 LLM Services

### LLM Client Usage

The project uses OpenAI-compatible APIs, encapsulated via `llm/llm_client.py`:
- Supports Alibaba Cloud Tongyi Qianwen, OpenAI, Claude, etc.
- Configuration managed through the `llm` section in `config/config.yaml`
- Supports streaming responses (SSE)

### RAG Service

`llm/rag_service.py` provides Retrieval-Augmented Generation:
- Smart time parsing (e.g., "last week", "yesterday")
- Hybrid retrieval strategy (vector search + full-text search)
- Context compression and ranking

### Prompt Management

Prompt templates are stored in `config/prompt.yaml`:
- Use YAML format for easy maintenance
- Support variable interpolation
- Organized by functional modules

### Agno Agent

`llm/agno_agent.py` provides AI-powered todo management via [Agno framework](https://docs.agno.com/):
- FreeTodoToolkit with 14 tools (CRUD, breakdown, time parsing, etc.)
- Internationalization support (zh/en)
- Mixin-based architecture for extensibility

See `.cursor/commands/agno_agent.md` for detailed development guide.

---

## ⏰ Background Tasks

### Task Scheduling

Use APScheduler to manage background tasks:
- Tasks defined in `lifetrace/jobs/` directory
- Managed uniformly through `job_manager.py`
- Supports scheduled tasks and interval tasks

### Task Types

- **recorder**: Screen recorder, scheduled screenshots
- **ocr**: OCR processor, processes screenshots awaiting recognition

---

## ⚙️ Configuration Management

### Configuration File Structure

- `config/default_config.yaml` - Default configuration (do not modify)
- `config/config.yaml` - User configuration (overrides default values)
- Uses Dynaconf to support configuration hot reload

### Accessing Configuration

Access through the `settings` object in `util/settings.py`:
- `settings.server.port` - Access nested configuration
- `settings.get("key", default)` - Access with default value

### Configuration Hot Reload

The following configurations support hot reload (no restart required):
- LLM configuration
- Recording configuration
- OCR configuration

---

## 📝 Logging

### Using Loguru

Import logger from `util/logging_config.py`:
- `logger.info()` - General information
- `logger.warning()` - Warning information
- `logger.error()` - Error information
- `logger.debug()` - Debug information

### Logging Conventions

- Critical operations must be logged
- Exceptions must log full stack traces
- Sensitive information (API Keys, etc.) must be sanitized
- Use structured logging for easier analysis

---

## 🗃️ Database Migration

### Using Alembic

The project uses Alembic to manage database migrations:
- Configuration file: `alembic.ini`
- Migration scripts: `migrations/versions/`

### Common Commands

- `alembic revision --autogenerate -m "description"` - Generate migration script
- `alembic upgrade head` - Apply all migrations
- `alembic downgrade -1` - Rollback one version
- `alembic history` - View migration history

---

## 🧪 Code Quality

### Ruff Checking and Formatting

The project uses Ruff for code checking and formatting:
- `uv run ruff check .` - Check code
- `uv run ruff check --fix .` - Auto-fix issues
- `uv run ruff format .` - Format code

### Code Standards

- Follow PEP 8 style guide
- Maximum 100 characters per line
- Maximum 500 lines per file (warning threshold 700 lines)
- Maximum 50 statements per function
- Cyclomatic complexity should not exceed 15

---

## 🔐 Error Handling

### HTTP Exceptions

Use FastAPI's `HTTPException`:
- `400` - Request parameter error
- `404` - Resource not found
- `422` - Validation error (automatically handled by Pydantic)
- `500` - Internal server error

### Exception Handling Conventions

- Catch specific exceptions, avoid catching all exceptions
- Log errors with context
- Return user-friendly error messages
- Do not expose sensitive information to clients

---

## 🚀 Performance Optimization

### Database Query Optimization

- Use `selectinload` to avoid N+1 queries
- Add indexes for commonly queried fields
- Use pagination to limit returned data
- Use batch operations instead of looping single operations

### Async Processing

- Use `async/await` for I/O operations
- Use async sessions for database queries
- Use async clients for external API calls

### Lazy Loading

- Large services (vector service, OCR) use lazy loading
- Initialize on-demand through `core/lazy_services.py`
- Avoid loading all dependencies at startup

---

## 📡 API and Frontend Interaction

### Naming Style Conversion

Backend uses `snake_case`, frontend uses `camelCase`:
- Frontend fetcher automatically converts
- Backend Schema uniformly uses `snake_case`
- OpenAPI Schema automatically generated by FastAPI

### Frontend Code Generation

Frontend uses Orval to automatically generate API code from OpenAPI Schema:
- After backend API changes, frontend runs `pnpm orval` to regenerate
- Ensure OpenAPI Schema is complete and accurate

---

## 📋 Dependency Management

### Using uv

The project uses uv as package manager:
- `uv sync` - Sync dependencies
- `uv add <package>` - Add dependency
- `uv remove <package>` - Remove dependency
- `uv run <command>` - Run command in virtual environment

### Dependency Groups

- Main dependencies: `dependencies` in `pyproject.toml`
- Development dependencies: `dependency-groups.dev`
- Optional dependencies: `dependency-groups.vector` (vector search functionality)

---

## 🔍 Debugging and Troubleshooting

### Starting Development Server

- `python -m lifetrace.server` - Direct start
- `uvicorn lifetrace.server:app --reload` - Hot reload mode

### API Documentation

- Swagger UI: `http://localhost:8001/docs`
- ReDoc: `http://localhost:8001/redoc`
- OpenAPI JSON: `http://localhost:8001/openapi.json`

### Log Viewing

- Log files located at `lifetrace/data/logs/`
- View via API: `GET /api/logs`
- Adjust log level: modify `logging.level` in `config/config.yaml`

---

## ✅ Code Review Checklist

Before submitting code, ensure:

- [ ] Code follows PEP 8 style guide
- [ ] Running `uv run ruff check .` produces no errors
- [ ] Running `uv run ruff format .` to format code
- [ ] All functions and classes have type annotations
- [ ] All public functions and classes have docstrings
- [ ] Appropriate error handling has been added
- [ ] Parameterized queries are used to prevent SQL injection
- [ ] Necessary logging has been added
- [ ] Relevant documentation has been updated
- [ ] API changes are reflected in OpenAPI Schema


================================================
FILE: .cursor/commands/backend_CN.md
================================================
# 后端开发快捷命令(lifetrace 版)

## 技术栈信息

- **框架**: FastAPI + Uvicorn(异步 Web 框架)
- **语言**: Python 3.12
- **ORM**: SQLAlchemy 2.x + SQLModel
- **数据库迁移**: Alembic
- **数据验证**: Pydantic 2.x
- **配置管理**: Dynaconf(支持 YAML 热重载)
- **日志**: Loguru
- **调度器**: APScheduler(后台任务调度)
- **OCR**: RapidOCR(本地 OCR 识别)
- **向量数据库**: ChromaDB(可选,用于语义搜索)
- **文本嵌入**: sentence-transformers(可选)
- **LLM**: OpenAI 兼容 API
- **包管理**: uv(推荐)
- **代码质量**: Ruff(lint/format/check)

---

## 🏗️ 项目架构

```
lifetrace/
├── server.py                 # FastAPI 应用入口
├── config/                   # 配置文件目录
│   ├── config.yaml          # 用户配置
│   ├── default_config.yaml  # 默认配置
│   └── prompt.yaml          # LLM Prompt 模板
├── routers/                  # API 路由层
├── services/                 # 业务服务层
├── repositories/             # 数据访问层(Repository 模式)
├── schemas/                  # Pydantic 数据模型
├── storage/                  # 数据存储层(SQLAlchemy 模型)
├── llm/                      # LLM 和 AI 服务
├── jobs/                     # 后台任务
├── core/                     # 核心依赖和懒加载服务
└── util/                     # 工具函数
```

### 分层架构说明

- **Router 层**:处理 HTTP 请求,参数验证,调用 Service 层
- **Service 层**:业务逻辑,编排多个 Repository 操作
- **Repository 层**:数据访问抽象,封装数据库查询
- **Schema 层**:请求/响应的 Pydantic 模型
- **Storage 层**:SQLAlchemy ORM 模型定义

---

## 🔧 路由开发

### 创建新的 API 路由

在 `lifetrace/routers/` 目录下创建新路由:
- 使用 `APIRouter` 定义路由前缀和标签
- 遵循 RESTful API 设计规范
- 使用依赖注入获取数据库会话
- 添加完整的类型注解和文档字符串

### RESTful 路由规范

- `GET /api/{resource}` - 获取列表
- `GET /api/{resource}/{id}` - 获取单个资源
- `POST /api/{resource}` - 创建资源
- `PUT /api/{resource}/{id}` - 全量更新
- `PATCH /api/{resource}/{id}` - 部分更新
- `DELETE /api/{resource}/{id}` - 删除资源

### 注册路由

在 `server.py` 中导入并注册新路由:
- 使用 `app.include_router(xxx.router)` 注册
- 路由按功能模块组织

---

## 📦 数据模型

### Pydantic Schema 规范

在 `lifetrace/schemas/` 目录下创建数据模型:
- 使用 Pydantic v2 语法
- 区分 `Create`、`Update`、`Response` 等不同场景的模型
- 使用 `Field()` 添加验证规则和描述
- 启用 `model_config = ConfigDict(from_attributes=True)` 支持 ORM 转换

### 常用模型模式

- `{Resource}Create` - 创建时的请求体
- `{Resource}Update` - 更新时的请求体(字段通常为 Optional)
- `{Resource}Response` - API 响应格式
- `{Resource}List` - 列表响应(包含分页信息)

### SQLAlchemy 模型规范

在 `lifetrace/storage/models.py` 中定义数据库表:
- 使用 SQLAlchemy 2.x 声明式语法
- 为常用查询字段添加索引
- 使用关系(relationship)定义表关联
- 添加 `created_at` 和 `updated_at` 时间戳字段

---

## 🗄️ Repository 层

### 创建 Repository

在 `lifetrace/repositories/` 目录下创建数据访问类:
- 继承或实现 `interfaces.py` 中定义的接口
- 封装所有数据库查询逻辑
- 使用异步方法(`async def`)
- 支持参数化查询,防止 SQL 注入

### Repository 命名规范

- `sql_{resource}_repository.py` - SQL 数据库实现
- 类名使用 `{Resource}Repository` 格式

---

## 🎯 Service 层

### 创建 Service

在 `lifetrace/services/` 目录下创建业务服务:
- 实现复杂的业务逻辑
- 编排多个 Repository 操作
- 处理事务边界
- 调用外部服务(LLM、OCR 等)

### Service 规范

- 类名使用 `{Resource}Service` 格式
- 通过依赖注入获取 Repository 实例
- 业务异常使用自定义 Exception 类
- 添加详细的日志记录

---

## 🤖 LLM 服务

### LLM 客户端使用

项目使用 OpenAI 兼容 API,通过 `llm/llm_client.py` 封装:
- 支持阿里云通义千问、OpenAI、Claude 等
- 配置通过 `config/config.yaml` 的 `llm` 部分管理
- 支持流式响应(SSE)

### RAG 服务

`llm/rag_service.py` 提供检索增强生成:
- 智能时间解析(如"上周"、"昨天")
- 混合检索策略(向量检索 + 全文检索)
- 上下文压缩和排序

### Prompt 管理

Prompt 模板统一存放在 `config/prompt.yaml`:
- 使用 YAML 格式便于维护
- 支持变量插值
- 按功能模块组织

### Agno Agent

`llm/agno_agent.py` 提供基于 [Agno 框架](https://docs.agno.com/) 的 AI 待办管理:
- FreeTodoToolkit 包含 14 个工具(CRUD、任务拆解、时间解析等)
- 国际化支持(中/英文)
- 基于 Mixin 的可扩展架构

详细开发指南见 `.cursor/commands/agno_agent_CN.md`。

---

## ⏰ 后台任务

### 任务调度

使用 APScheduler 管理后台任务:
- 任务定义在 `lifetrace/jobs/` 目录
- 通过 `job_manager.py` 统一管理
- 支持定时任务和间隔任务

### 任务类型

- **recorder**: 屏幕录制器,定时截图
- **ocr**: OCR 处理器,处理待识别的截图

---

## ⚙️ 配置管理

### 配置文件结构

- `config/default_config.yaml` - 默认配置(不要修改)
- `config/config.yaml` - 用户配置(覆盖默认值)
- 使用 Dynaconf 支持配置热重载

### 访问配置

通过 `util/settings.py` 中的 `settings` 对象访问:
- `settings.server.port` - 访问嵌套配置
- `settings.get("key", default)` - 带默认值访问

### 配置热重载

以下配置支持热重载(无需重启):
- LLM 配置
- 录制配置
- OCR 配置

---

## 📝 日志记录

### 使用 Loguru

从 `util/logging_config.py` 导入 logger:
- `logger.info()` - 普通信息
- `logger.warning()` - 警告信息
- `logger.error()` - 错误信息
- `logger.debug()` - 调试信息

### 日志规范

- 关键操作必须记录日志
- 异常必须记录完整堆栈
- 敏感信息(API Key 等)必须脱敏
- 使用结构化日志便于分析

---

## 🗃️ 数据库迁移

### 使用 Alembic

项目使用 Alembic 管理数据库迁移:
- 配置文件:`alembic.ini`
- 迁移脚本:`migrations/versions/`

### 常用命令

- `alembic revision --autogenerate -m "描述"` - 生成迁移脚本
- `alembic upgrade head` - 应用所有迁移
- `alembic downgrade -1` - 回滚一个版本
- `alembic history` - 查看迁移历史

---

## 🧪 代码质量

### Ruff 检查和格式化

项目使用 Ruff 进行代码检查和格式化:
- `uv run ruff check .` - 检查代码
- `uv run ruff check --fix .` - 自动修复问题
- `uv run ruff format .` - 格式化代码

### 代码规范

- 遵循 PEP 8 风格指南
- 每行不超过 100 字符
- 单个文件不超过 500 行(警戒线 700 行)
- 单个函数不超过 50 条语句
- 圈复杂度不超过 15

---

## 🔐 错误处理

### HTTP 异常

使用 FastAPI 的 `HTTPException`:
- `400` - 请求参数错误
- `404` - 资源不存在
- `422` - 验证错误(Pydantic 自动处理)
- `500` - 服务器内部错误

### 异常处理规范

- 捕获特定异常,避免捕获所有异常
- 记录错误日志并包含上下文
- 返回用户友好的错误信息
- 敏感信息不要暴露给客户端

---

## 🚀 性能优化

### 数据库查询优化

- 使用 `selectinload` 避免 N+1 查询
- 为常用查询字段添加索引
- 使用分页限制返回数据量
- 批量操作代替循环单条操作

### 异步处理

- 使用 `async/await` 处理 I/O 操作
- 数据库查询使用异步会话
- 外部 API 调用使用异步客户端

### 懒加载

- 大型服务(向量服务、OCR)使用懒加载
- 通过 `core/lazy_services.py` 按需初始化
- 避免启动时加载所有依赖

---

## 📡 API 与前端交互

### 命名风格转换

后端使用 `snake_case`,前端使用 `camelCase`:
- 前端 fetcher 自动进行转换
- 后端 Schema 统一使用 `snake_case`
- OpenAPI Schema 由 FastAPI 自动生成

### 前端代码生成

前端使用 Orval 根据 OpenAPI Schema 自动生成 API 代码:
- 后端 API 变更后,前端运行 `pnpm orval` 重新生成
- 确保 OpenAPI Schema 完整且准确

---

## 📋 依赖管理

### 使用 uv

项目使用 uv 作为包管理器:
- `uv sync` - 同步依赖
- `uv add <package>` - 添加依赖
- `uv remove <package>` - 移除依赖
- `uv run <command>` - 在虚拟环境中运行命令

### 依赖分组

- 主依赖:`pyproject.toml` 的 `dependencies`
- 开发依赖:`dependency-groups.dev`
- 可选依赖:`dependency-groups.vector`(向量搜索功能)

---

## 🔍 调试和排查

### 启动开发服务器

- `python -m lifetrace.server` - 直接启动
- `uvicorn lifetrace.server:app --reload` - 热重载模式

### API 文档

- Swagger UI: `http://localhost:8001/docs`
- ReDoc: `http://localhost:8001/redoc`
- OpenAPI JSON: `http://localhost:8001/openapi.json`

### 日志查看

- 日志文件位于 `lifetrace/data/logs/`
- 通过 API 查看:`GET /api/logs`
- 调整日志级别:修改 `config/config.yaml` 的 `logging.level`

---

## ✅ 代码检查清单

在提交代码前,请确保:

- [ ] 代码遵循 PEP 8 风格指南
- [ ] 运行 `uv run ruff check .` 没有错误
- [ ] 运行 `uv run ruff format .` 格式化代码
- [ ] 所有函数和类都有类型注解
- [ ] 所有公共函数和类都有文档字符串
- [ ] 添加了适当的错误处理
- [ ] 使用了参数化查询防止 SQL 注入
- [ ] 添加了必要的日志记录
- [ ] 更新了相关文档
- [ ] API 变更已在 OpenAPI Schema 中反映


================================================
FILE: .cursor/commands/dynamic-island.md
================================================
# 灵动岛实现指南(Dynamic Island)

## 概述

灵动岛是一个悬浮 UI 组件,为 Electron 应用提供三种交互模式:
- **FLOAT 模式**:小型悬浮岛,可拖拽,悬停时展开
- **PANEL 模式**:可调整大小的面板窗口,显示单个功能
- **MAXIMIZE 模式**:最大化工作台,显示完整的应用功能

---

## 🚀 实现原理与技术栈

### 核心技术

- **React 19 + TypeScript**:组件化开发,类型安全
- **Framer Motion**:流畅的动画和布局过渡
- **Electron IPC**:主进程与渲染进程通信
- **CSS 注入**:动态修改窗口样式(透明度、圆角等)
- **窗口管理 API**:`setIgnoreMouseEvents`、`setAlwaysOnTop`、`setBounds` 等

### 全局常驻 Overlay 设计(新实现)

- 灵动岛现在作为一个**全局常驻 overlay 层**存在:
  - 最外层容器始终是 `position: fixed; inset: 0; pointer-events: none; z-index: 1000002`。
  - 通过 `ref` 回调 + `requestAnimationFrame` 连续调用 `style.setProperty(..., 'important')`,确保上述属性不会被其他样式覆盖。
- 三种模式(FLOAT / PANEL / MAXIMIZE)只是改变「内容层」(PanelWindow / 最大化页面)的布局和 Electron 窗口策略:
  - 灵动岛的布局计算固定使用 `layoutMode = IslandMode.FLOAT`,保证拖拽位置和吸边逻辑在所有模式下统一。
  - N 徽章等全局元素也应放在这一 overlay 层内,确保不会因为窗口变窄而被“挤进 Panel”。

### Electron IPC 通信机制

**IPC(Inter-Process Communication)** 是 Electron 中主进程(Main Process)和渲染进程(Renderer Process)之间通信的桥梁。

**为什么需要 IPC?**
- Electron 应用分为主进程和渲染进程,主进程负责窗口管理、系统 API 调用等,渲染进程负责 UI 渲染
- 出于安全考虑,渲染进程无法直接调用 Node.js API 和 Electron 窗口 API
- 需要通过 IPC 让渲染进程请求主进程执行窗口操作

**在灵动岛中的使用**:
- **渲染进程 → 主进程**:通过 `ipcRenderer.send()` 或 `ipcRenderer.invoke()` 发送请求
  - `collapse-window`:请求折叠窗口到 FLOAT 模式
  - `expand-window`:请求展开窗口到 PANEL 模式
  - `expand-window-full`:请求展开窗口到 MAXIMIZE 模式
  - `set-ignore-mouse-events`:请求设置点击穿透
  - `move-window`:请求移动窗口位置
- **主进程处理**:在 `electron/ipc-handlers.ts` 中注册处理器,执行实际的窗口操作
  - 调用 `BrowserWindow` API 修改窗口属性
  - 通过 `webContents.insertCSS()` 注入样式
  - 执行窗口动画过渡

**代码示例**:
```typescript
// 渲染进程(前端)
const api = getElectronAPI();
await api.electronAPI?.collapseWindow?.();

// 主进程(electron/ipc-handlers.ts)
ipcMain.handle("collapse-window", async () => {
  const win = windowManager.getWindow();
  // 执行窗口操作...
});
```

### 实现总结

灵动岛的实现通过以下技术组合完成:

1. **通过 Electron IPC 通信**,让前端渲染进程请求主进程执行窗口操作(调整大小、位置、属性等)
2. **通过 CSS 注入**,动态修改窗口样式(透明度、圆角、裁剪路径),实现视觉效果的平滑过渡
3. **通过窗口动画**,使用缓动函数和定时器,以约 60fps 的频率更新窗口边界,实现平滑的尺寸变化
4. **通过点击穿透管理**,在 FLOAT 模式下启用 `setIgnoreMouseEvents`,让窗口不阻挡桌面操作,同时通过 `forward: true` 保持鼠标事件检测
5. **通过 Framer Motion**,在前端实现组件布局的平滑动画,配合窗口动画实现整体过渡效果
6. **通过状态管理**,使用 Zustand store 管理模式状态,使用 React Context 在组件间共享功能状态
7. **通过自定义 Hooks**,将拖拽、悬停检测、布局计算等逻辑封装,保持代码模块化和可维护性

这种架构实现了窗口级别的动画(主进程控制)和组件级别的动画(渲染进程控制)的协同工作,创造出流畅的模式切换体验。

### 关键技术点

#### 1. 点击穿透(Click-Through)

**实现方式(两层控制)**:

- **渲染层 hook**:`components/dynamic-island/hooks/useDynamicIslandClickThrough.ts`
  - 负责灵动岛本身在 FLOAT 模式下,依据悬停/拖拽状态切换局部 `pointer-events`。
- **窗口层 hook**:`lib/hooks/useElectronClickThrough.ts`
  - 统一调用 Electron 的 `setIgnoreMouseEvents`,根据模式和鼠标位置控制整窗是否穿透。

**当前行为**:

- **FLOAT 模式**:
  - 窗口层:`setIgnoreMouseEvents(true, { forward: true })`,整窗穿透但仍可接收 `mousemove`。
  - 渲染层:灵动岛在 hover/drag 时打开局部 `pointer-events`,实现“悬浮但可交互”。
- **PANEL 模式**:
  - 进入 PANEL 时立即 `setIgnoreMouseEvents(false)`,确保一开始就能点击 PanelWindow。
  - 监听全局 `mousemove`,根据 `[data-panel-window]` 的 `getBoundingClientRect()`:
    - 鼠标在 panel 内部(含顶部 8px 扩展区域)→ `setIgnoreMouseEvents(false)`。
    - 鼠标在 panel 外部透明区域 → `setIgnoreMouseEvents(true, { forward: true })`。
- **MAXIMIZE 模式**:
  - 始终 `setIgnoreMouseEvents(false)`,整窗可交互。

#### 2. 窗口动画过渡

**实现方式**:
- 使用 `easeOutCubic` 缓动函数实现平滑过渡
- 通过 `setBounds()` 以约 60fps 的频率更新窗口边界
- 动画期间通过 CSS 注入控制透明度,避免内容闪现

**代码位置**:`electron/ipc-handlers.ts` 的 `animateWindowBounds` 函数

```typescript
// 缓动函数:easeOutCubic
function easeOutCubic(t: number): number {
  return 1 - (1 - t) ** 3;
}

// 动画循环:约 60fps
setTimeout(animate, 16);
```

#### 3. 拖拽实现

**实现方式**:
- 完全手动实现,不依赖 Electron 的 `setMovable`
- 监听 `mousedown`、`mousemove`、`mouseup` 事件
- 实时更新 DOM 位置,拖拽结束后通过 Framer Motion 平滑移动到吸附位置
- 支持边缘吸附(50px 阈值)

**代码位置**:`hooks/useDynamicIslandDrag.ts`

**关键逻辑**:
1. `mousedown`:记录起始位置,禁用点击穿透
2. `mousemove`:计算新位置,限制在屏幕范围内
3. `mouseup`:计算吸附位置,通过 `setPosition` 触发 Framer Motion 动画

#### 4. 悬停检测

**实现方式**:
- 全局 `mousemove` 事件监听
- 使用 `getBoundingClientRect()` 检测鼠标是否在区域内
- 使用 `requestAnimationFrame` 节流,优化性能
- 10px 容差避免边缘抖动

**代码位置**:`hooks/useDynamicIslandHover.ts`

```typescript
// 节流处理
let rafId: number | null = null;
const throttledHandleMouseMove = (e: MouseEvent) => {
  if (rafId) return;
  rafId = requestAnimationFrame(() => {
    handleGlobalMouseMove(e);
    rafId = null;
  });
};
```

#### 5. 透明度与可见性恢复(配合全局 overlay)

**问题**:从 PANEL/MAXIMIZE 折叠到 FLOAT 时,如果主进程仍保留 `opacity: 0` 等样式,灵动岛窗口可能出现“看不见但还在”的状态。

**解决方案(新实现)**:

- 主进程在折叠/动画期间仍可以注入 `opacity: 0`,避免尺寸变化过程闪现内容。
- `DynamicIsland` 挂载与模式切换时,通过 `useEffect` 与 `ref` 回调:
  - 对 overlay 容器本身强制 `opacity: 1; visibility: visible`。
  - 必要时通过 `<style>` 注入 `html, body, #__next { opacity: 1 !important; }`,覆盖遗留样式。
- 这样可以保证:只要渲染进程在运行,灵动岛 overlay 层始终可见,不会“突然消失”。

**代码位置**:`components/dynamic-island/DynamicIsland.tsx` 中关于 overlay 容器样式修复的 `useEffect` 与 `ref` 逻辑。

#### 6. 窗口圆角实现

**实现方式**:
- 使用 `clip-path: inset(0 round 16px)` 实现完美圆角
- 通过 Electron 的 `insertCSS` API 注入样式
- 同时设置 `border-radius` 和 `overflow: hidden` 作为后备

**代码位置**:`electron/ipc-handlers.ts` 的 `expand-window` 处理器

```typescript
win.webContents.insertCSS(`
  html, body, #__next {
    border-radius: 16px !important;
    clip-path: inset(0 round 16px) !important;
  }
`);
```

#### 7. 布局计算

**实现方式(全局常驻后)**:

- 核心思路:**无论外部 mode 是 FLOAT / PANEL / MAXIMIZE,布局计算统一使用 FLOAT 语义**。
  - 在 `DynamicIsland` 内部固定 `const layoutMode = IslandMode.FLOAT;`。
  - 通过 `useDynamicIslandLayout` 只根据拖拽位置/吸边状态计算 `left/right/top/bottom` 和收起/展开尺寸。
- 尺寸语义:
  - 收起:约 36x36px。
  - 展开:约 135x48px。
- PANEL / MAXIMIZE 模式时:
  - 灵动岛仍按 FLOAT 语义布局,只是背景内容从桌面 → PanelWindow / 最大化工作台。

**代码位置**:`components/dynamic-island/hooks/useDynamicIslandLayout.ts`

#### 8. Framer Motion 动画

**实现方式**:
- 使用 `motion.div` 的 `layout` 属性实现自动布局动画
- 弹簧物理效果:`stiffness: 350, damping: 30, mass: 0.8`
- 拖拽结束后,通过更新 `position` 状态触发平滑移动

**代码示例**:
```typescript
<motion.div
  layout
  animate={layoutState}
  transition={{
    type: "spring",
    stiffness: 350,
    damping: 30,
    mass: 0.8,
  }}
/>
```

### 实现流程

#### FLOAT 模式初始化

1. 窗口创建时设置 `alwaysOnTop: true`、`resizable: false`、`movable: false`。
2. 启用点击穿透:`setIgnoreMouseEvents(true, { forward: true })`。
3. 保持窗口背景透明,只通过灵动岛 overlay 渲染内容。
4. 监听全局鼠标移动,检测悬停。

#### 模式切换流程(窗口层 + 前端层)

1. **FLOAT → PANEL**:
   - 前端调用 `expandWindow()` IPC,请求展开为「Panel 宽度 + 左侧透明走廊」的宽窗。
   - 主进程设置窗口可调整大小和可移动,注入 panel 圆角 / 透明背景 CSS,并动画到目标 bounds。
   - `useElectronClickThrough` 禁用整窗穿透,并根据 `[data-panel-window]` rect 做区域穿透。
   - 前端切换模式状态为 `PANEL`,`PanelContent` 渲染当前功能。

2. **PANEL → FLOAT**:
   - 前端调用 `collapseWindow()` IPC。
   - 主进程注入 `opacity: 0`,动画回到小岛尺寸,动画结束后启用整窗点击穿透。
   - 前端通过 overlay 样式修复确保灵动岛重新可见,并将模式切回 `FLOAT`。

3. **PANEL → MAXIMIZE**:
   - 前端调用 `expandWindowFull()` IPC。
   - 主进程最大化窗口,清理 panel 圆角/clip-path。
   - 始终禁用整窗穿透。
   - 前端切换模式状态为 `MAXIMIZE`,`MaximizeControlBar` 渲染。

---

## 🏗️ 项目架构

### 目录结构

```
components/dynamic-island/
├── DynamicIsland.tsx                  # 灵动岛主组件(协调三种模式)
├── DynamicIslandProvider.tsx         # Provider 组件,用于检测 Electron 环境
├── PanelFeatureContext.tsx           # Panel 模式功能上下文
├── PanelTitleBar.tsx                 # Panel 模式标题栏
├── PanelContent.tsx                  # Panel 模式内容区域(包含 BottomDock)
├── PanelSelectorMenu.tsx             # Panel 模式右键菜单
├── FloatContent.tsx                  # FLOAT 模式内容(收起/展开)
├── MaximizeControlBar.tsx            # MAXIMIZE 模式顶部控制栏
├── ContextMenu.tsx                   # FLOAT 模式右键上下文菜单
├── ResizeHandle.tsx                  # PANEL 模式自定义缩放把手
├── electron-api.ts                   # 前端使用的 Electron API 封装
├── ElectronTransparentScript.tsx     # 透明窗口支持脚本
├── TransparentBody.tsx               # 透明 body 包装器
├── types.ts                          # 类型定义(IslandMode 枚举等)
├── index.ts                          # 公共导出
└── hooks/                            # 自定义 Hooks
    ├── useDynamicIslandClickThrough.ts  # 点击穿透管理(渲染层)
    ├── useDynamicIslandDrag.ts          # FLOAT 模式拖拽
    ├── useDynamicIslandHover.ts         # FLOAT 模式悬停展开/收起
    └── useDynamicIslandLayout.ts        # 根据模式计算布局

components/layout/
├── PanelWindow.tsx                   # Panel 模式右侧窗口容器(含透明占位区 + panel 区域)
├── PanelRegion.tsx                   # 可复用 Panel 区域(上面 panel 栏 + 下面 BottomDock)
├── PanelContainer.tsx                # 单个 panel 容器(控制宽度、间距、拖拽态)
├── PanelContent.tsx                  # PanelRegion 中的业务内容渲染
├── ResizeHandle.tsx                  # Panel 之间的垂直分隔/拖拽把手
├── BottomDock.tsx                    # 面板底部 dock(功能切换入口)
└── AppHeader.tsx                     # 顶部应用 header(包含模式切换按钮)

lib/hooks/
└── useElectronClickThrough.ts        # 统一控制 Electron setIgnoreMouseEvents 的 hook

electron/
├── ipc-handlers.ts                   # 主进程 IPC 入口(collapse/expand/expand-full + 动画)
└── window-manager.ts                 # BrowserWindow 管理与创建
```

### 组件层次结构

```
DynamicIslandProvider
  └── DynamicIsland (mode: FLOAT | PANEL | MAXIMIZE)
      ├── FLOAT 模式:
      │   ├── FloatContent (收起/展开)
      │   └── ContextMenu (右键菜单)
      ├── PANEL 模式:
      │   ├── PanelFeatureProvider
      │   │   ├── PanelTitleBar
      │   │   └── PanelContent
      │   │       └── PanelSelectorMenu (右键菜单)
      │   └── ResizeHandle (8 个缩放把手)
      └── MAXIMIZE 模式:
          └── MaximizeControlBar
```

---

## 🎨 核心组件

### DynamicIsland.tsx

**用途**:主组件,协调所有三种模式。

**主要职责**:
- 模式切换逻辑(FLOAT ↔ PANEL ↔ MAXIMIZE)
- Electron API 集成(窗口缩放、折叠、展开)
- 模式转换后恢复透明度
- 键盘快捷键(1、4、5、Escape)
- 拖拽、悬停和上下文菜单的状态管理

**关键特性**:
- 使用 `suppressHydrationWarning` 防止水合错误
- 高 z-index(999999)确保始终置顶
- 切换到 FLOAT 模式时自动恢复透明度
- FLOAT 模式的点击穿透管理

### PanelFeatureContext.tsx

**用途**:Context,用于在 PanelTitleBar 和 PanelContent 之间共享当前功能状态。

**使用方式**:
```typescript
<PanelFeatureProvider>
  <PanelTitleBar />
  <PanelContent />
</PanelFeatureProvider>
```

### PanelTitleBar.tsx

**用途**:PANEL 模式的标题栏,显示当前功能名称和控制按钮。

**特性**:
- 显示当前功能图标和名称
- 最大化和折叠按钮
- 支持 WebkitAppRegion 拖拽
- 与 PanelFeatureContext 同步

### PanelContent.tsx

**用途**:PANEL 模式的内容区域,包含底部 Dock 用于功能切换。

**特性**:
- 底部 Dock 显示当前功能按钮
- 右键菜单用于功能选择
- 通过 `getAvailableFeatures()` 与设置面板开关同步
- 始终包含 "settings" 功能
- 鼠标移动时自动显示/隐藏 Dock

### FloatContent.tsx

**用途**:FLOAT 模式显示的内容(收起/展开状态)。

**状态**:
- **收起**:小图标(36x36px)
- **展开**:完整内容带按钮(135x48px)

### MaximizeControlBar.tsx

**用途**:MAXIMIZE 模式的顶部控制栏。

**特性**:
- 退出最大化按钮
- 折叠到灵动岛按钮
- 固定窗口(不可拖拽、不可调整大小)

---

## 🔧 自定义 Hooks

### useDynamicIslandClickThrough

**用途**:管理灵动岛自身在 FLOAT 模式下的点击穿透与交互区域(渲染层)。

**行为(新实现)**:

- FLOAT 模式:
  - 配合窗口层的 `setIgnoreMouseEvents(true, { forward: true })`,通过局部 `pointer-events` 控制实际可点击区域。
  - 悬停/拖拽时打开交互,离开时恢复为只展示但不阻挡桌面。
- PANEL / MAXIMIZE 模式:
  - 主要交由 `useElectronClickThrough` 控制整窗行为,本 hook 只做必要的样式修复。

### useDynamicIslandDrag

**用途**:处理 FLOAT 模式的拖拽功能。

**特性**:
- 手动拖拽实现
- 吸附到边缘(上、下、左、右)
- 位置持久化
- 点击按钮时阻止拖拽

### useDynamicIslandHover

**用途**:管理 FLOAT 模式的悬停状态。

**特性**:
- 全局鼠标移动检测
- 悬停时展开,离开时收起
- 使用 requestAnimationFrame 节流
- 尊重拖拽状态

### useDynamicIslandLayout

**用途**:计算不同模式的布局状态。

**布局**:
- **FLOAT**:收起(36x36)或展开(135x48),定位在边缘
- **PANEL**:全窗口(100% x 100%),圆角(16px)
- **MAXIMIZE**:全视口(100vw x 100vh)

---

## ⚡ Electron 集成

### 窗口管理

**IPC 处理器**(位于 `electron/ipc-handlers.ts`):

- `collapse-window`:折叠到 FLOAT 模式
  - 如当前窗口为 maximized,先 `unmaximize()` 再执行动画。
  - 转换期间注入 `opacity: 0` 并动画化窗口边界。
  - 结束后启用整窗点击穿透,并保持窗口置顶。
- `expand-window`:展开到 PANEL 模式
  - 使窗口可调整大小和可移动。
  - 计算 `expandedWidth = panelWidth + overlayGutter`,将 PanelWindow 固定在右侧,左侧保留透明区域给全局 overlay。
  - 注入圆角与透明背景 CSS。
  - 窗口级点击穿透由 `useElectronClickThrough` 按鼠标位置实时切换。
- `expand-window-full`:展开到 MAXIMIZE 模式
  - 最大化窗口。
  - 清理 Panel 模式的圆角/clip-path。
  - 设置 `resizable=false`、`movable=false`,并禁用点击穿透。

### 窗口属性

**FLOAT 模式**:
- `alwaysOnTop: true`
- `resizable: false`
- `movable: false`
- `ignoreMouseEvents: true`(forward: true)

**PANEL 模式**:
- `alwaysOnTop: true`
- `resizable: true`
- `movable: true`
- `ignoreMouseEvents`:由 `useElectronClickThrough` 根据鼠标是否在 PanelWindow 内部动态切换。

**MAXIMIZE 模式**:
- `alwaysOnTop: true`
- `resizable: false`
- `movable: false`
- `ignoreMouseEvents: false`

---

## 📦 状态管理

### 模式状态

由 `lib/store/dynamic-island-store.ts` 管理:
- `mode: IslandMode` - 当前模式(FLOAT、PANEL、MAXIMIZE)
- `isEnabled: boolean` - 是否启用灵动岛
- `setMode(mode)` - 切换模式

### 功能状态(Panel 模式)

由 `PanelFeatureContext` 管理:
- `currentFeature: PanelFeature` - 当前显示的功能
- `setCurrentFeature(feature)` - 切换功能

### 设置同步

Panel 模式底部 Dock 通过以下方式与设置同步:
- `useUiStore().getAvailableFeatures()` - 获取已启用且未分配的功能
- `useUiStore().isFeatureEnabled(feature)` - 检查功能是否启用
- Settings 功能始终包含在可用功能列表中

---

## 🔄 模式转换

### FLOAT → PANEL

1. 用户点击展开按钮或按 "4" 键。
2. 前端调用 `expandWindow()` IPC,请求主进程展开到「Panel 宽度 + 左侧透明走廊」。
3. 窗口动画到目标 bounds,右侧显示 PanelWindow,左侧留出透明区。
4. 模式切换到 `PANEL`,`PanelContent` 渲染当前功能。

### PANEL → MAXIMIZE

1. 用户点击最大化按钮。
2. 前端调用 `expandWindowFull()` IPC。
3. 窗口最大化并清理 Panel 圆角/clip-path。
4. 模式切换到 `MAXIMIZE`,`MaximizeControlBar` 渲染。

### PANEL → FLOAT

1. 用户点击折叠按钮。
2. 前端调用 `collapseWindow()` IPC。
3. 主进程动画窗口到小岛尺寸并重新开启整窗点击穿透。
4. 前端通过 overlay 样式修复恢复灵动岛可见性,并将模式切换到 `FLOAT`。

### MAXIMIZE → PANEL

1. 用户点击退出最大化按钮。
2. **不再主动调用 `expandWindow()`**,只切换前端模式为 `PANEL`,保持窗口仍为最大化宽度。
3. Panel 模式的 PanelWindow 使用右侧布局呈现,灵动岛等全局 overlay 依然按照 fixed 坐标保持在原位置。

### MAXIMIZE → FLOAT

1. 用户点击折叠按钮或按 Escape 键。
2. 调用 `collapseWindow()` IPC。
3. 与 PANEL → FLOAT 相同。

---

## ⌨️ 键盘快捷键

- **1**:折叠到 FLOAT 模式
- **4**:展开到 PANEL 模式
- **5**:展开到 MAXIMIZE 模式
- **Escape**:从 PANEL/MAXIMIZE 折叠到 FLOAT

---

## 🎨 样式

### Z-Index 层级(新实现)

- 全局 overlay 容器(灵动岛 + N 徽章等):`z-index: 1000002`
- PanelWindow 主容器:`z-index: 1000001`
- MAXIMIZE 控制栏:`z-index: 100010+`(在内容层之上,但仍低于全局 overlay)
- Panel 模式缩放把手:`z-index: 50`
- 上下文菜单:`z-index: 100-101`

### 动画

- **布局转换**:Framer Motion 弹簧动画
- **悬停展开**:平滑的宽度/高度转换
- **模式切换**:带弹簧物理效果的布局动画
- **Dock 显示/隐藏**:带 translateY 的弹簧动画

---

## 🔨 常见模式

### 添加新功能到 Panel 模式

1. 在 `lib/config/panel-config.ts` 中将功能添加到 `ALL_PANEL_FEATURES`
2. 将功能图标添加到 `FEATURE_ICON_MAP`
3. 在翻译文件(`messages/*.json`)中添加功能标签
4. 在 `apps/{feature}/` 中创建功能面板组件
5. 在 `PanelContent.tsx` 的渲染逻辑中添加功能分支

### 修改模式行为

1. 更新 `hooks/` 目录中对应的 hook
2. 如需要模式特定逻辑,更新 `DynamicIsland.tsx`
3. 如窗口行为改变,更新 Electron IPC 处理器
4. 测试所有模式转换

### 调试模式问题

1. 在 `useDynamicIslandStore()` 中检查 `mode` 状态
2. 在浏览器控制台中验证 Electron API 调用
3. 在 Electron DevTools 中检查窗口属性
4. 在 DOM 中检查透明度样式
5. 通过 Electron API 验证点击穿透状态

---

## ✅ 最佳实践

1. **保证 overlay 永远可见**:在 `DynamicIsland` 中持续修复 overlay 容器的 `position/z-index/opacity/visibility`。
2. **使用 Context 共享状态**:在 `PanelTitleBar` 和 `PanelContent` 之间传递当前功能等信息。
3. **与设置同步**:使用 `getAvailableFeatures()` 获取功能列表,保证 Panel 与设置面板一致。
4. **处理水合错误**:在需要的地方使用 `suppressHydrationWarning`。
5. **节流鼠标事件**:使用 `requestAnimationFrame` 提升性能,避免全局 `mousemove` 抖动。
6. **阻止按钮拖拽**:通过检查 `target.closest('button')` 防止拖拽误触。
7. **保持正确的 z-index 关系**:确保 overlay > PanelWindow > 其他内容。
8. **同步更新点击穿透状态**:模式切换时立即更新 `setIgnoreMouseEvents` 与相关 CSS,避免出现几秒钟“看得见但点不到”或“穿透但不可交互”的状态。

---

## 📏 文件大小管理

- **DynamicIsland.tsx**:382 行(在 500 行限制内)
- 组件已拆分为独立文件:
  - `PanelFeatureContext.tsx`:Context 和 Provider
  - `PanelTitleBar.tsx`:标题栏组件
  - 其他组件已分离

---

## 📚 相关文件

- `lib/store/dynamic-island-store.ts`:模式状态管理
- `lib/store/ui-store/store.ts`:功能启用/禁用状态
- `lib/config/panel-config.ts`:功能定义和图标
- `electron/ipc-handlers.ts`:窗口管理 IPC 处理器
- `electron/window-manager.ts`:窗口创建和配置

---

## 🔍 调试和排查

### 常见问题

1. **灵动岛消失**:检查透明度样式,确保切换到 FLOAT 模式时恢复 `opacity: 1`
2. **无法拖拽**:检查 `ignoreMouseEvents` 状态和 `WebkitAppRegion` 设置
3. **模式切换失败**:检查 Electron IPC 处理器是否正确注册
4. **功能不同步**:检查 `getAvailableFeatures()` 和 `isFeatureEnabled()` 的实现

### 调试技巧

- 在浏览器控制台查看 Electron API 调用日志
- 使用 React DevTools 检查组件状态
- 在 Electron DevTools 中检查窗口属性
- 检查 DOM 中的样式注入(opacity、z-index 等)

---

## ⚠️ 当前问题与改进方向

### 模式切换存在的问题

目前模式切换存在以下问题,影响用户体验:

#### 1. 瞬变问题
- **现象**:模式切换时窗口尺寸变化过于突然,缺乏平滑过渡
- **影响**:视觉上不够自然,用户体验不佳

#### 2. 闪现其他尺寸的页面
- **现象**:在模式切换过程中,会短暂显示其他尺寸的页面内容
- **影响**:特别是从 PANEL 模式切换到 FLOAT 模式时,会先闪现最大化画面,然后才缩小到 FLOAT 尺寸
- **原因分析**:
  - 窗口尺寸变化和内容渲染不同步
  - CSS 注入时机不当,导致在窗口尺寸变化过程中内容可见
  - 前端模式状态切换时机与窗口动画不匹配

#### 3. 不自然的过渡
- **现象**:窗口从一种尺寸直接跳到另一种尺寸,而不是平滑过渡
- **影响**:缺乏连贯性,感觉不和谐

### 改进方向

接下来需要实现**模式切换的自然过渡**,主要改进方向:

1. **同步窗口动画与内容渲染**
   - 在窗口尺寸变化前,先隐藏或透明化内容
   - 确保窗口动画完成后再显示新尺寸的内容
   - 避免在动画过程中显示中间状态的内容

2. **优化 CSS 注入时机**
   - 在窗口动画开始前注入 `opacity: 0`,确保内容不可见
   - 在窗口动画完成后,再恢复内容可见性
   - 避免在窗口尺寸变化过程中内容闪现

3. **协调前端状态切换与窗口动画**
   - 前端模式状态切换应该在窗口动画开始前完成
   - 或者延迟到窗口动画完成后,确保视觉一致性
   - 使用 Promise 或回调确保时序正确

4. **改进动画实现**
   - 确保窗口边界动画平滑,无跳跃
   - 前端组件布局动画与窗口动画同步
   - 使用更合适的缓动函数,让过渡更自然

5. **处理 PANEL → FLOAT 的特殊情况**
   - 这是最明显的问题场景,需要特别处理
   - 在折叠动画开始前,确保内容已透明
   - 避免在窗口缩小过程中显示最大化内容
   - 可以考虑使用截图或遮罩层,在动画期间显示当前窗口的静态图像

### 技术实现要点

- **时序控制**:使用 `async/await` 确保操作顺序
- **状态同步**:窗口状态与前端状态保持一致
- **视觉连续性**:使用遮罩、截图或预渲染保持视觉连贯
- **性能优化**:避免不必要的重渲染和布局计算


================================================
FILE: .cursor/commands/web.md
================================================
# Frontend Development Quick Commands (free-todo-frontend version)

## Tech Stack Information

- **Framework**: Next.js 16 + React 19 (App Router)
- **Language**: Node.js 22.x + TypeScript 5.x
- **Styling**: Tailwind CSS 4 + shadcn/ui
- **State Management**: Zustand + React Hooks
- **Data Fetching**: TanStack Query (React Query) v5
- **API Generation**: Orval (auto-generated from OpenAPI)
- **Data Validation**: Zod (runtime type validation)
- **Theming**: next-themes (light/dark toggle)
- **Animation/Interaction**: framer-motion, @dnd-kit
- **Markdown**: react-markdown + remark-gfm
- **Icons**: lucide-react
- **Package Manager**: pnpm 10.x
- **Code Quality**: Biome (lint/format/check)

---

## 🎨 Component Development

### Creating New React Components

Create a new React component based on project conventions, including:
- TypeScript type definitions
- Complete comments
- Tailwind CSS styling
- Responsive design
- Internationalization support (if needed)

Please create components in the `free-todo-frontend/components/` directory and follow the project's code conventions.

### Creating Shadcn UI Components

Create custom components based on existing Shadcn UI components:
- Inherit Shadcn UI's styling system
- Add project-specific functionality extensions
- Maintain consistency with project theme
- Support dark mode

### Optimizing Existing Components

- Use `React.memo/useMemo/useCallback` to control rendering
- Use `tailwind-merge` to merge class names and avoid duplicate styles
- Unify interaction animations (framer-motion) and drag-and-drop (@dnd-kit)
- Add error handling and boundary states (loading/empty/error)
- Improve type definitions, remove unused props/variables

---

## 🌐 Internationalization

The project uses next-intl for internationalization, with language switching managed through Zustand store (no URL routing mode).

- **Translation Files**: `free-todo-frontend/messages/zh.json` and `en.json`
- **Request Configuration**: `free-todo-frontend/i18n/request.ts`
- **Language Management**: `lib/store/locale.ts` (syncs to cookie on switch)
- **Access Method**: `useTranslations(namespace)` imported from `next-intl`

### Adding/Modifying Copy

- Add translation keys in both `messages/zh.json` and `en.json`
- Use nested structures to organize translations, e.g., `page.settings.title`
- Support ICU MessageFormat interpolation syntax, e.g., `{count}` and plural forms

### Implementing Multilingual Components

- Use `useTranslations(namespace)` hook to get translation function
- Access translations via `t('key')`, supports `t('key', { param: value })` for parameters
- Do not hardcode Chinese/English text in components
- Do not use `locale === "zh" ? "中文" : "English"` ternary expressions

---

## 🎨 Styling Development

### Optimizing Tailwind CSS Styles

Improve component Tailwind CSS styles:
- Use project's custom theme variables
- Implement dark mode adaptation
- Optimize responsive breakpoints
- Follow DRY principles, extract reusable styles

### Implementing Dark Mode

Add dark mode support to components:
- Use `dark:` prefix
- Use CSS variables to define colors
- Ensure contrast meets accessibility standards
- Test theme switching effects

---

## 🔧 State Management

### Creating Custom Hooks

Create reusable React Hooks:
- Follow Hook naming conventions (use prefix)
- Add complete TypeScript types
- Include detailed comments
- Implement error handling and edge cases

### Implementing Global State

Use Context API to implement global state management:
- Create Context and Provider
- Implement state update logic
- Add performance optimizations (useMemo, useCallback)
- Provide type-safe hooks

---

## 📡 API and Data Fetching

The project uses **Orval + TanStack Query + Zod** to implement type-safe API calls and data validation.

### Orval Code Generation

- **Configuration File**: `orval.config.ts`
- **Generation Command**: `pnpm orval` (requires backend service running). When backend-frontend interaction APIs change, actively use this command to generate frontend-backend interaction APIs. Do not manually write APIs.
- **Generated Content**: TypeScript types, Zod schemas, React Query hooks
- **Output Directory**: `lib/generated/` (split by API tag, e.g., `todos/`, `chat/`)

**Main Configuration**:
- `input.target`: Backend OpenAPI schema address (http://localhost:8001/openapi.json)
- `output.client`: Generate hooks using react-query
- `output.mode`: tags-split to split files by functional modules
- `override.mutator`: Use custom fetcher (`lib/generated/fetcher.ts`)
- `override.zod.strict`: Enable strict runtime validation

### Using Orval Generated API Hooks

1. **Direct use of generated hooks**: Import from `lib/generated/[module]/`, includes complete type definitions
2. **Wrap hooks to add business logic**: Encapsulate in `lib/query/`, add custom query keys, data transformation, cache strategies, etc.
3. **Reference examples**: `lib/query/todos.ts`, `lib/query/chat.ts`

### TanStack Query Usage Conventions

- **Query Keys**: Managed uniformly in `lib/query/keys.ts`, using hierarchical structure (e.g., `todos.list()`, `todos.detail(id)`)
- **Optimistic Updates**: Update cache in `onMutate`, rollback in `onError`, refetch in `onSettled`
- **Debounced Updates**: Use 500ms debounce for frequently changing fields (e.g., description, notes)
- **Cache Strategy**: Set reasonable `staleTime` (e.g., 30 seconds) to avoid excessive requests

### Zod Data Validation

- **Generated schemas**: Located in `lib/generated/schemas/`, automatically generated by Orval
- **Runtime validation**: Automatically validate API response format in fetcher
- **Form validation**: Use with React Hook Form's `zodResolver`
- **Custom rules**: Can extend custom validation logic based on generated schema

### Custom Fetcher

Located in `lib/generated/fetcher.ts`, responsible for:
- Environment adaptation (client/server URL)
- **Automatic naming style conversion**:
  - Request: camelCase → snake_case (frontend style → backend style)
  - Response: snake_case → camelCase (backend style → frontend style)
- Time string normalization (handling timezone suffix)
- Unified error handling
- Zod schema runtime validation
- Extensible (auth tokens, logging, retry, etc.)

Conversion utilities located in `lib/generated/case-transform.ts`, frontend uniformly uses camelCase type definitions (`lib/types/index.ts`).

### Streaming API Handling

Orval does not support Server-Sent Events, need to manually implement in `lib/api.ts`:
- Use native `fetch` + `ReadableStream`
- Decode and callback chunk by chunk
- Examples: `sendChatMessageStream()`, `planQuestionnaireStream()`

### Type Safety Best Practices

1. Prioritize using camelCase types from `lib/types/index.ts` (fetcher automatically converts)
2. IDs uniformly use `number` type (consistent with backend database)
3. Orval-generated types only used for API layer, business layer uses unified type definitions

### Development Workflow

1. **Backend API changes**: Run `pnpm orval` to regenerate code, check `git diff lib/generated/`
2. **New API**: Backend updates OpenAPI → Generate code → Encapsulate in `lib/query/` → Component usage
3. **Debugging**: Add logs in fetcher to view request/response and validation errors

---

## 🚀 Performance Optimization

### Optimizing Component Performance

Analyze and optimize component performance:
- Use React DevTools Profiler for analysis
- Implement code splitting (dynamic import)
- Optimize image loading (Next.js Image)
- Reduce unnecessary re-renders
- Implement virtual scrolling (if needed)

### Optimizing Bundle Size

Reduce frontend bundle size:
- Analyze bundle size
- Remove unused dependencies
- Implement on-demand loading
- Optimize third-party library imports

---

## 🧪 Testing Development

### Writing Component Tests

Write test cases for components:
- Use React Testing Library
- Test user interactions
- Test edge cases
- Ensure test coverage

### Writing E2E Tests

Write end-to-end tests:
- Use Playwright or Cypress
- Test critical user flows
- Simulate real user scenarios
- Add visual regression tests

---

## 🔍 Debugging and Fixing

### Fixing TypeScript Errors

Fix TypeScript type errors in code:
- Analyze error messages
- Add correct type definitions
- Avoid using `any` type
- Ensure type safety

### Fixing ESLint Warnings

Fix ESLint warnings in code:
- Follow project's ESLint configuration
- Fix code style issues
- Remove unused imports
- Optimize code structure

### Debugging Runtime Errors

Analyze and fix runtime errors:
- Check browser console errors
- Analyze error stack traces
- Add error boundary handling
- Implement graceful degradation

---

## 📦 Dependency Management

### Adding New npm Packages

Safely add new npm dependencies:
1. Evaluate package necessity and security
2. Use `pnpm add <package>` to install
3. Update project documentation
4. Test if functionality works correctly

### Upgrading Dependencies

Upgrade project dependencies to latest versions:
1. Check breaking changes
2. Use `pnpm update` to upgrade
3. Run tests to ensure compatibility
4. Update related code

---

## 📚 Documentation Writing

### Writing Component Documentation

Write documentation for components:
- Explain component purpose and functionality
- List all Props and types
- Provide usage examples
- Include notes and considerations

### Updating README

Update frontend-related README documentation:
- Synchronize latest tech stack
- Update development commands
- Add new feature descriptions
- Improve troubleshooting guide


================================================
FILE: .cursor/commands/web_CN.md
================================================
# 前端开发快捷命令(free-todo-frontend 版)

## 技术栈信息

- **框架**: Next.js 16 + React 19(App Router)
- **语言**: Node.js 22.x + TypeScript 5.x
- **样式**: Tailwind CSS 4 + shadcn/ui
- **状态管理**: Zustand + React Hooks
- **数据获取**: TanStack Query (React Query) v5
- **API 生成**: Orval(根据 OpenAPI 自动生成)
- **数据验证**: Zod(运行时类型验证)
- **主题**: next-themes(浅/深色切换)
- **动画/交互**: framer-motion、@dnd-kit
- **Markdown**: react-markdown + remark-gfm
- **图标**: lucide-react
- **包管理**: pnpm 10.x
- **代码质量**: Biome(lint/format/check)

---

## 🎨 组件开发

### 创建新的 React 组件

基于项目规范创建一个新的 React 组件,包含:
- TypeScript 类型定义
- 完整的中文注释
- Tailwind CSS 样式
- 响应式设计
- 国际化支持(如需要)

请在 `free-todo-frontend/components/` 目录下创建组件,并遵循项目的代码规范。

### 创建 Shadcn UI 组件

在现有的 Shadcn UI 组件基础上创建自定义组件:
- 继承 Shadcn UI 的样式系统
- 添加项目特定的功能扩展
- 保持与项目主题的一致性
- 支持深色模式

### 优化现有组件

- 使用 `React.memo/useMemo/useCallback` 控制渲染
- 使用 `tailwind-merge` 合并类名,避免重复样式
- 统一交互动画(framer-motion)与拖拽(@dnd-kit)
- 补充错误处理与边界状态(loading/empty/error)
- 完善类型定义,移除未用 props/变量

---

## 🌐 国际化

项目使用 next-intl 实现国际化,通过 Zustand store 管理语言切换(无 URL 路由模式)。

- **翻译文件**:`free-todo-frontend/messages/zh.json` 与 `en.json`
- **请求配置**:`free-todo-frontend/i18n/request.ts`
- **语言管理**:`lib/store/locale.ts`(切换时同步到 cookie)
- **访问方法**:`useTranslations(namespace)` 从 `next-intl` 导入

### 添加/修改文案

- 在 `messages/zh.json` 和 `en.json` 中同步添加翻译 key
- 使用嵌套结构组织翻译,如 `page.settings.title`
- 支持 ICU MessageFormat 插值语法,如 `{count}` 和复数形式

### 实现多语言组件

- 使用 `useTranslations(namespace)` hook 获取翻译函数
- 通过 `t('key')` 访问翻译,支持 `t('key', { param: value })` 传参
- 禁止在组件中硬编码中文/英文文本
- 禁止使用 `locale === "zh" ? "中文" : "English"` 三元表达式

---

## 🎨 样式开发

### 优化 Tailwind CSS 样式

改进组件的 Tailwind CSS 样式:
- 使用项目的自定义主题变量
- 实现深色模式适配
- 优化响应式断点
- 遵循 DRY 原则,提取可复用样式

### 实现深色模式

为组件添加深色模式支持:
- 使用 `dark:` 前缀
- 使用 CSS 变量定义颜色
- 确保对比度符合可访问性标准
- 测试主题切换效果

---

## 🔧 状态管理

### 创建自定义 Hook

创建可复用的 React Hook:
- 遵循 Hook 命名规范(use 前缀)
- 添加完整的 TypeScript 类型
- 包含详细的中文注释
- 实现错误处理和边界情况

### 实现全局状态

使用 Context API 实现全局状态管理:
- 创建 Context 和 Provider
- 实现状态更新逻辑
- 添加性能优化(useMemo、useCallback)
- 提供类型安全的 hook

---

## 📡 API 与数据获取

项目使用 **Orval + TanStack Query + Zod** 实现类型安全的 API 调用和数据验证。

### Orval 代码生成

- **配置文件**:`orval.config.ts`
- **生成命令**:`pnpm orval`(需后端服务运行)。当后端与前端交互的 api 有变化时,主动使用本命令,在前端主动采用本命令生成的前后端交互 api,不要自己手写 api。
- **生成内容**:TypeScript 类型、Zod schemas、React Query hooks
- **输出目录**:`lib/generated/`(按 API tag 分割,如 `todos/`, `chat/`)

**主要配置**:
- `input.target`:后端 OpenAPI schema 地址(http://localhost:8001/openapi.json)
- `output.client`:使用 react-query 生成 hooks
- `output.mode`:tags-split 按功能模块分文件
- `override.mutator`:使用自定义 fetcher(`lib/generated/fetcher.ts`)
- `override.zod.strict`:启用严格的运行时验证

### 使用 Orval 生成的 API Hooks

1. **直接使用生成的 hooks**:从 `lib/generated/[module]/` 导入,已包含完整类型定义
2. **包装 hooks 添加业务逻辑**:在 `lib/query/` 中封装,添加自定义 query key、数据转换、缓存策略等
3. **参考示例**:`lib/query/todos.ts`、`lib/query/chat.ts`

### TanStack Query 使用规范

- **Query Keys**:统一在 `lib/query/keys.ts` 管理,使用层级结构(如 `todos.list()`, `todos.detail(id)`)
- **乐观更新**:在 `onMutate` 中更新缓存,`onError` 回滚,`onSettled` 重新获取
- **防抖更新**:针对频繁变化字段(如描述、备注)使用 500ms 防抖
- **缓存策略**:设置合理的 `staleTime`(如 30 秒),避免过度请求

### Zod 数据验证

- **生成的 schemas**:位于 `lib/generated/schemas/`,由 Orval 自动生成
- **运行时验证**:在 fetcher 中自动验证 API 响应格式
- **表单验证**:配合 React Hook Form 的 `zodResolver` 使用
- **自定义规则**:可基于生成的 schema 扩展自定义验证逻辑

### 自定义 Fetcher

位于 `lib/generated/fetcher.ts`,负责:
- 环境适配(客户端/服务端 URL)
- **命名风格自动转换**:
  - 请求时:camelCase → snake_case(前端风格 → 后端风格)
  - 响应时:snake_case → camelCase(后端风格 → 前端风格)
- 时间字符串标准化(处理无时区后缀)
- 统一错误处理
- Zod schema 运行时验证
- 可扩展(认证 token、日志、重试等)

转换工具位于 `lib/generated/case-transform.ts`,前端统一使用 camelCase 类型定义(`lib/types/index.ts`)。

### 流式 API 处理

Orval 不支持 Server-Sent Events,需在 `lib/api.ts` 手动实现:
- 使用原生 `fetch` + `ReadableStream`
- 逐块解码并回调处理
- 示例:`sendChatMessageStream()`, `planQuestionnaireStream()`

### 类型安全最佳实践

1. 优先使用 `lib/types/index.ts` 中的 camelCase 类型(fetcher 已自动转换)
2. ID 统一使用 `number` 类型(与后端数据库一致)
3. Orval 生成的类型仅用于 API 层,业务层使用统一类型定义

### 开发工作流

1. **后端 API 变更**:运行 `pnpm orval` 重新生成代码,检查 `git diff lib/generated/`
2. **新增 API**:后端更新 OpenAPI → 生成代码 → 在 `lib/query/` 封装 → 组件使用
3. **调试**:在 fetcher 中添加日志,查看请求/响应和验证错误

---

## 🚀 性能优化

### 优化组件性能

分析并优化组件性能:
- 使用 React DevTools Profiler 分析
- 实现代码分割(dynamic import)
- 优化图片加载(Next.js Image)
- 减少不必要的重渲染
- 实现虚拟滚动(如需要)

### 优化包体积

减少前端包体积:
- 分析 bundle 大小
- 移除未使用的依赖
- 实现按需加载
- 优化第三方库引入

---

## 🧪 测试开发

### 编写组件测试

为组件编写测试用例:
- 使用 React Testing Library
- 测试用户交互
- 测试边界情况
- 确保测试覆盖率

### 编写 E2E 测试

编写端到端测试:
- 使用 Playwright 或 Cypress
- 测试关键用户流程
- 模拟真实用户场景
- 添加视觉回归测试

---

## 🔍 调试和修复

### 修复 TypeScript 错误

修复代码中的 TypeScript 类型错误:
- 分析错误信息
- 添加正确的类型定义
- 避免使用 `any` 类型
- 确保类型安全

### 修复 ESLint 警告

修复代码中的 ESLint 警告:
- 遵循项目的 ESLint 配置
- 修复代码风格问题
- 移除未使用的导入
- 优化代码结构

### 调试运行时错误

分析并修复运行时错误:
- 检查浏览器控制台错误
- 分析错误堆栈信息
- 添加错误边界处理
- 实现优雅降级

---

## 📦 依赖管理

### 添加新的 npm 包

安全地添加新的 npm 依赖:
1. 评估包的必要性和安全性
2. 使用 `pnpm add <package>` 安装
3. 更新项目文档
4. 测试功能是否正常

### 升级依赖版本

升级项目依赖到最新版本:
1. 检查 breaking changes
2. 使用 `pnpm update` 升级
3. 运行测试确保兼容性
4. 更新相关代码

---

## 📚 文档编写

### 编写组件文档

为组件编写文档:
- 说明组件用途和功能
- 列出所有 Props 和类型
- 提供使用示例
- 包含注意事项

### 更新 README

更新前端相关的 README 文档:
- 同步最新的技术栈
- 更新开发命令
- 添加新功能说明
- 完善故障排查指南


================================================
FILE: .cursor/plans/lifetrace_全面优化_76b5f86f.plan.md
================================================
---
name: LifeTrace 全面优化
overview: 针对 LifeTrace 项目的 6 个核心问题(启动速度、打包体积、插件系统、Todo 标准、社交媒体集成、依赖清理)制定系统性的优化方案。
todos:
  - id: startup-optimization
    content: 启动速度优化:数据库懒加载、后台任务异步启动、路由延迟导入、Electron 预启动优化
    status: pending
  - id: dependency-cleanup
    content: 依赖项清理:移除未使用依赖、创建依赖分组、重构 pyproject.toml
    status: pending
  - id: package-size
    content: 打包体积优化:分离大型依赖为可选扩展、替换重型依赖、优化 PyInstaller 配置
    status: pending
  - id: icalendar-support
    content: iCalendar 标准支持:添加缺失字段、创建 ICS 导入/导出服务、添加 API 端点
    status: pending
  - id: plugin-system
    content: 插件系统:设计插件接口、实现前端插件注册表和懒加载、实现后端插件系统
    status: pending
  - id: telegram-integration
    content: Telegram Bot 集成:创建 Bot 模块、实现消息处理、添加 Webhook 路由
    status: pending
  - id: feishu-integration
    content: 飞书 Bot 集成:创建 Bot 模块、实现事件回调、添加 Webhook 路由
    status: pending
isProject: false
---

# LifeTrace 全面优化计划

## 问题 1: 启动速度优化(目标: 4秒 -> 1秒内)

### 当前瓶颈分析

根据代码分析,主要耗时点:

- 数据库初始化(含 30+ 索引创建):1-3 秒
- 后台任务同步初始化:2-5 秒
- Python 模块导入:0.5-1 秒
- Electron + Next.js 启动:额外 1-2 秒

### 优化方案

**1.1 数据库初始化异步化**

修改 [`lifetrace/storage/database.py`](lifetrace/storage/database.py):

- 将模块级的 `db_base = DatabaseBase()` 改为懒加载
- 索引创建改为后台异步执行(应用启动后延迟执行)
```python
# 改为懒加载单例
_db_base: DatabaseBase | None = None

def get_db_base() -> DatabaseBase:
    global _db_base
    if _db_base is None:
        _db_base = DatabaseBase()
    return _db_base
```


**1.2 后台任务延迟启动**

修改 [`lifetrace/server.py`](lifetrace/server.py) 的 lifespan:

- `job_manager.start_all()` 改为异步执行
- 使用 `asyncio.create_task()` 并行启动各任务

**1.3 路由模块延迟导入**

使用 Python 的 `importlib` 实现路由模块的按需导入,或者在 lifespan 中注册路由。

**1.4 Electron 预启动优化**

修改 [`electron/main.ts`](free-todo-frontend/electron/main.ts):

- 先显示启动画面/骨架屏
- 后端和前端服务并行启动
- 减少健康检查等待时间(目前最多 180 秒)

---

## 问题 2: 打包体积优化(目标: 2.6GB -> 500MB 以内)

### 当前体积构成分析

根据 [`pyinstaller.spec`](lifetrace/pyinstaller.spec) 分析:

- `torch` + `transformers`(sentence-transformers 间接依赖):约 2-3GB
- `chromadb`:约 100-200MB
- `faster-whisper`:约 200-500MB
- `opencv-python`:约 50-100MB
- OCR 模型文件:约 50MB

### 优化方案

**2.1 分离大型依赖为可选扩展包**

修改 [`pyproject.toml`](pyproject.toml):

```toml
[dependency-groups]
# 核心依赖(必需)
core = [
    "fastapi>=0.100.0",
    "uvicorn[standard]>=0.20.0",
    "pydantic>=2.0.0",
    "sqlalchemy>=2.0.0",
    # ... 基础依赖
]

# 向量搜索扩展(可选下载)
vector = [
    "sentence-transformers>=2.2.0",
    "chromadb>=0.4.0",
]

# 语音识别扩展(可选下载)
audio = [
    "faster-whisper>=1.0.0",
    "pyaudio>=0.2.14",
]
```

**2.2 替换重型依赖**

- **sentence-transformers** -> 使用 API 调用(如 OpenAI Embeddings)或轻量级本地模型
- **chromadb** -> 考虑使用 SQLite FTS5 全文搜索作为基础功能
- **opencv-python** -> 使用 `opencv-python-headless`(减少约 30MB)

**2.3 PyInstaller 优化**

修改 [`pyinstaller.spec`](lifetrace/pyinstaller.spec):

- 排除未使用的子模块
- 使用 `--exclude-module` 排除测试和文档模块
- 考虑使用 `upx=True` 压缩(需测试兼容性)

**2.4 考虑替代打包方案**

- **Nuitka**:Python 编译为 C,体积更小、启动更快
- **PyOxidizer**:Rust 实现的打包工具,体积优化更好

---

## 问题 3: 插件系统设计

### 目标

实现一个完善的插件系统,支持:

- 内置模块的启用/禁用
- 按需加载减少初始加载时间
- 第三方插件开发和安装

### 架构设计

```
插件系统架构
├── 核心插件接口
│   ├── PanelPlugin(前端面板插件)
│   ├── BackendPlugin(后端服务插件)
│   └── AgentToolPlugin(Agent 工具插件)
├── 插件注册表(Registry)
│   ├── 内置插件列表
│   └── 第三方插件列表
└── 插件加载器(Loader)
    ├── 前端:动态导入 + React.lazy
    └── 后端:Python importlib + 依赖注入
```

**3.1 前端插件系统**

创建 [`lib/plugins/`](free-todo-frontend/lib/plugins/) 目录:

```typescript
// lib/plugins/types.ts
interface PanelPlugin {
  id: string;
  name: string;
  icon: string;
  version: string;
  dependencies?: string[];
  component: () => Promise<{ default: React.ComponentType }>;
  enabled: boolean;
}

// lib/plugins/registry.ts
class PluginRegistry {
  private plugins: Map<string, PanelPlugin> = new Map();

  register(plugin: PanelPlugin): void;
  get(id: string): PanelPlugin | undefined;
  getEnabled(): PanelPlugin[];
  setEnabled(id: string, enabled: boolean): void;
}
```

修改 [`components/layout/PanelContent.tsx`](free-todo-frontend/components/layout/PanelContent.tsx):

- 从硬编码 if-else 改为注册表驱动
- 使用 `React.lazy()` + `Suspense` 实现懒加载

**3.2 后端插件系统**

创建 [`lifetrace/plugins/`](lifetrace/plugins/) 目录:

```python
# lifetrace/plugins/base.py
class BackendPlugin(ABC):
    id: str
    name: str
    version: str
    dependencies: list[str] = []

    @abstractmethod
    def register_routes(self, app: FastAPI) -> None: ...

    @abstractmethod
    def startup(self) -> None: ...

    @abstractmethod
    def shutdown(self) -> None: ...
```

**3.3 插件配置持久化**

在 [`config/config.yaml`](lifetrace/config/config.yaml) 中添加:

```yaml
plugins:
  enabled:
    - todos
    - calendar
    - chat
  disabled:
    - achievements
    - debugShots
  third_party:
    - path: ~/.freetodo/plugins/my-plugin
```

---

## 问题 4: Todo 标准统一(iCalendar/ICS 格式)

### 当前 Todo 模型与 iCalendar VTODO 对照

| 当前字段 | iCalendar 属性 | 说明 |

|---------|---------------|------|

| `id` | `UID` | 唯一标识符 |

| `name` | `SUMMARY` | 摘要/标题 |

| `description` | `DESCRIPTION` | 详细描述 |

| `deadline` | `DUE` | 截止时间 |

| `start_time` | `DTSTART` | 开始时间 |

| `status` | `STATUS` | 状态(需映射) |

| `priority` | `PRIORITY` | 优先级(需映射) |

| `created_at` | `CREATED` | 创建时间 |

| `updated_at` | `LAST-MODIFIED` | 修改时间 |

| - | `COMPLETED` | 完成时间(需添加) |

| - | `PERCENT-COMPLETE` | 完成百分比(可选) |

| - | `CATEGORIES` | 分类/标签 |

| - | `RRULE` | 重复规则(可选) |

### 实现方案

**4.1 添加缺失字段**

修改 [`lifetrace/storage/models.py`](lifetrace/storage/models.py):

```python
class Todo(TimestampMixin, table=True):
    # 新增字段
    completed_at: datetime | None = None  # 完成时间
    percent_complete: int = Field(default=0, ge=0, le=100)  # 完成百分比
    rrule: str | None = None  # iCalendar RRULE 格式的重复规则
    uid: str = Field(default_factory=lambda: str(uuid.uuid4()))  # 全局唯一ID
```

**4.2 添加 iCalendar 服务**

创建 [`lifetrace/services/icalendar_service.py`](lifetrace/services/icalendar_service.py):

```python
from icalendar import Calendar, Todo as VTodo

class ICalendarService:
    def export_todos(self, todos: list[Todo]) -> str:
        """导出为 ICS 格式"""

    def import_todos(self, ics_content: str) -> list[TodoCreate]:
        """从 ICS 格式导入"""

    def _status_to_ical(self, status: str) -> str:
        """状态映射:active->NEEDS-ACTION, completed->COMPLETED, canceled->CANCELLED"""
```

**4.3 添加 API 端点**

修改 [`lifetrace/routers/todo.py`](lifetrace/routers/todo.py):

```python
@router.get("/export/ics")
async def export_ics(status: str | None = None) -> Response:
    """导出为 ICS 文件"""

@router.post("/import/ics")
async def import_ics(file: UploadFile) -> list[TodoResponse]:
    """从 ICS 文件导入"""
```

**4.4 添加依赖**

```toml
dependencies = [
    "icalendar>=6.0.0",  # iCalendar 解析/生成库
]
```

---

## 问题 5: 社交媒体 Agent 集成(Telegram + 飞书)

### 架构设计

```
用户设备 (PC)                    社交媒体平台
    │                                │
    ├── FreeTodo Server ◄────────────┤
    │   ├── Agent Gateway            │
    │   │   ├── Telegram Bot ◄───────┼── Telegram API
    │   │   └── Feishu Bot ◄─────────┼── 飞书开放平台
    │   └── AgnoAgentService         │
    │       └── FreeTodoToolkit      │
    └────────────────────────────────┘
```

**5.1 Telegram Bot 集成**

创建 [`lifetrace/integrations/telegram/`](lifetrace/integrations/telegram/) 目录:

```python
# lifetrace/integrations/telegram/bot.py
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler

class FreeTodoTelegramBot:
    def __init__(self, token: str, agent_service: AgnoAgentService):
        self.app = Application.builder().token(token).build()
        self.agent = agent_service

    async def handle_message(self, update: Update, context):
        """处理用户消息,转发给 Agent"""
        response = await self.agent.chat(update.message.text)
        await update.message.reply_text(response)
```

添加依赖:

```toml
[dependency-groups]
telegram = ["python-telegram-bot>=21.0"]
```

**5.2 飞书 Bot 集成**

创建 [`lifetrace/integrations/feishu/`](lifetrace/integrations/feishu/) 目录:

```python
# lifetrace/integrations/feishu/bot.py
import httpx

class FreeTodoFeishuBot:
    def __init__(self, app_id: str, app_secret: str, agent_service: AgnoAgentService):
        self.app_id = app_id
        self.app_secret = app_secret
        self.agent = agent_service

    async def handle_event(self, event: dict):
        """处理飞书事件回调"""

    async def send_message(self, open_id: str, content: str):
        """发送消息给用户"""
```

添加依赖:

```toml
[dependency-groups]
feishu = ["lark-oapi>=1.0.0"]
```

**5.3 统一网关路由**

修改 [`lifetrace/routers/`](lifetrace/routers/) 添加:

```python
# lifetrace/routers/integrations.py
@router.post("/telegram/webhook")
async def telegram_webhook(update: dict):
    """Telegram Webhook 回调"""

@router.post("/feishu/webhook")
async def feishu_webhook(event: dict):
    """飞书事件回调"""
```

**5.4 配置管理**

修改 [`config/config.yaml`](lifetrace/config/config.yaml):

```yaml
integrations:
  telegram:
    enabled: false
    bot_token: ""
  feishu:
    enabled: false
    app_id: ""
    app_secret: ""
    verification_token: ""
```

---

## 问题 6: 依赖项清理

### 可能未使用的依赖

根据代码分析,以下依赖可能未使用或使用较少:

| 依赖 | 状态 | 建议 |

|-----|------|------|

| `wikipedia>=1.4.0` | 未找到导入 | 移除或移至可选 |

| `arxiv>=2.4.0` | 未找到导入 | 移除或移至可选 |

| `whisperlivekit>=0.1.0` | 未找到导入 | 移除或移至可选 |

| `python-socks>=2.0.0` | websockets 可选依赖 | 如不需代理可移除 |

| `opencc-python-reimplemented` | 繁简转换,使用较少 | 移至可选 |

### 清理步骤

1. 使用 `pip-autoremove` 或手动检查每个依赖的实际使用情况
2. 运行测试确保移除后功能正常
3. 更新 `pyproject.toml` 和 `uv.lock`

### 依赖分组重构

```toml
[project]
dependencies = [
    # 仅保留核心必需依赖
    "fastapi>=0.100.0",
    "uvicorn[standard]>=0.20.0",
    "pydantic>=2.0.0",
    "sqlalchemy>=2.0.0",
    "sqlmodel>=0.0.22",
    "alembic>=1.14.0",
    "apscheduler>=3.10.0",
    "dynaconf[yaml]>=3.2.0",
    "loguru>=0.7.3",
    "psutil>=5.9.0",
    "pyyaml>=6.0",
    "openai>=1.0.0",
    "agno>=2.4.1",
    # OCR 核心
    "mss>=9.0.0",
    "Pillow>=10.0.0",
    "rapidocr-onnxruntime",
    "numpy>=1.21.0,<2.0.0",
]

[dependency-groups]
dev = ["pre-commit>=4.4.0", "ruff>=0.14.4", "pyinstaller>=6.0.0"]
vector = ["sentence-transformers>=2.2.0", "chromadb>=0.4.0", "scipy>=1.9.0", "hdbscan>=0.8.0"]
audio = ["faster-whisper>=1.0.0", "pyaudio>=0.2.14"]
search = ["ddgs>=8.0.0", "tavily-python>=0.5.0"]
telegram = ["python-telegram-bot>=21.0"]
feishu = ["lark-oapi>=1.0.0"]
calendar = ["icalendar>=6.0.0"]
```

---

## 实施优先级建议

| 优先级 | 任务 | 预计影响 |

|-------|------|---------|

| P0 | 启动速度优化 | 用户体验大幅提升 |

| P0 | 依赖项清理 + 分组 | 为体积优化做准备 |

| P1 | 打包体积优化 | 下载和安装体验改善 |

| P1 | iCalendar 标准支持 | 与其他日历软件互通 |

| P2 | 插件系统(模块化懒加载) | 代码架构改善 |

| P2 | Telegram 集成 | 新功能 |

| P3 | 飞书集成 | 新功能 |

| P3 | 插件系统(第三方支持) | 生态建设 |


================================================
FILE: .cursor/plans/tauri_迁移方案_38d8ea4b.plan.md
================================================
---
name: Tauri 迁移方案
overview: 使用 Tauri 替代 Electron,采用 HTTP Sidecar 模式与 Python 后端集成。保持现有 API 和前端代码不变,最小化迁移成本。
todos:
  - id: tauri-init
    content: 初始化 Tauri 项目:pnpm tauri init,配置 tauri.conf.json
    status: completed
  - id: rust-main
    content: 实现 Rust 主进程 main.rs,包含应用启动逻辑
    status: completed
  - id: rust-backend
    content: 实现 backend.rs:Python 后端 Sidecar 管理(启动/健康检查/停止)
    status: completed
  - id: rust-nextjs
    content: 实现 nextjs.rs:Next.js standalone 服务器管理
    status: completed
  - id: tauri-tray
    content: 实现系统托盘功能(Tauri SystemTray API)
    status: completed
  - id: tauri-shortcut
    content: 实现全局快捷键(Tauri GlobalShortcut Plugin)
    status: completed
  - id: dev-test
    content: 测试开发模式运行:tauri dev
    status: completed
  - id: prod-build
    content: 测试生产构建:tauri build
    status: completed
  - id: cross-platform
    content: 跨平台测试:Windows/macOS/Linux
    status: completed
isProject: false
---

# Tauri 替代 Electron 迁移方案

## 当前架构

```mermaid
graph TB
    subgraph electron [Electron App]
        main[main.ts - Electron 主进程]
        preload[preload.ts]
        webview[Chromium WebView]
    end

    subgraph nextjs [Next.js Server]
        standalone[standalone/server.js]
        static[静态资源]
    end

    subgraph python [Python Backend]
        fastapi[FastAPI Server]
        sidecar[Sidecar 进程]
    end

    main -->|spawn| standalone
    main -->|spawn| sidecar
    webview -->|HTTP| standalone
    webview -->|HTTP| fastapi
```

## 目标架构

```mermaid
graph TB
    subgraph tauri [Tauri App]
        rust[main.rs - Rust 主进程]
        webview[System WebView]
    end

    subgraph nextjs [Next.js Server]
        standalone[standalone/server.js]
        static[静态资源]
    end

    subgraph python [Python Backend]
        fastapi[FastAPI Server]
        sidecar[Sidecar 进程]
    end

    rust -->|Sidecar API| standalone
    rust -->|Sidecar API| sidecar
    webview -->|HTTP| standalone
    webview -->|HTTP| fastapi
```

## 迁移策略

采用 **HTTP Sidecar 模式**:

- Python 后端作为独立 Sidecar 进程运行
- 前端通过 HTTP 直接访问 FastAPI
- Rust 主进程负责启动/管理 Sidecar 进程
- 前端代码和后端 API 几乎不需要改动

---

## 第一步:创建 Tauri 项目结构

在 `free-todo-frontend/` 目录下初始化 Tauri:

```
free-todo-frontend/
├── src-tauri/              # 新增:Tauri Rust 代码
│   ├── Cargo.toml
│   ├── tauri.conf.json
│   ├── src/
│   │   ├── main.rs
│   │   ├── backend.rs      # Python 后端管理
│   │   ├── nextjs.rs       # Next.js 服务器管理
│   │   └── lib.rs
│   └── icons/
├── electron/               # 保留:可选择性删除或并行维护
├── app/                    # 不变:Next.js 前端
└── ...
```

**命令**:

```bash
cd free-todo-frontend
pnpm add -D @tauri-apps/cli@latest
pnpm tauri init
```

---

## 第二步:配置 tauri.conf.json

```json
{
  "$schema": "https://schema.tauri.app/config/2.1",
  "productName": "FreeTodo",
  "version": "0.1.0",
  "identifier": "com.freeugroup.freetodo",
  "build": {
    "beforeBuildCommand": "pnpm build",
    "devUrl": "http://localhost:3000",
    "frontendDist": "../.next/standalone"
  },
  "app": {
    "withGlobalTauri": true,
    "windows": [
      {
        "title": "FreeTodo",
        "width": 1200,
        "height": 800,
        "resizable": true,
        "fullscreen": false
      }
    ],
    "security": {
      "csp": null
    }
  },
  "bundle": {
    "active": true,
    "icon": ["icons/icon.png"],
    "targets": ["dmg", "nsis", "appimage"],
    "externalBin": ["backend/lifetrace"],
    "resources": ["standalone/**/*", "backend/**/*"]
  }
}
```

---

## 第三步:实现 Rust 主进程

### 3.1 主入口 (src/main.rs)

```rust
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

mod backend;
mod nextjs;

use tauri::Manager;

fn main() {
    tauri::Builder::default()
        .setup(|app| {
            let handle = app.handle().clone();

            // 启动 Python 后端
            tauri::async_runtime::spawn(async move {
                if let Err(e) = backend::start_backend(&handle).await {
                    eprintln!("Failed to start backend: {}", e);
                }
            });

            // 启动 Next.js 服务器(打包模式)
            #[cfg(not(debug_assertions))]
            tauri::async_runtime::spawn(async move {
                if let Err(e) = nextjs::start_nextjs(&handle).await {
                    eprintln!("Failed to start Next.js: {}", e);
                }
            });

            Ok(())
        })
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
```

### 3.2 Python 后端管理 (src/backend.rs)

```rust
use std::process::Command;
use std::path::PathBuf;
use tauri::AppHandle;

pub async fn start_backend(app: &AppHandle) -> Result<(), Box<dyn std::error::Error>> {
    let resource_path = app.path().resource_dir()?;
    let backend_path = resource_path.join("backend").join("lifetrace");
    let data_dir = app.path().app_data_dir()?;

    // 检测是否已有后端运行
    if check_backend_health(8001).await {
        println!("Backend already running on port 8001");
        return Ok(());
    }

    // 启动后端进程
    let mut cmd = Command::new(&backend_path);
    cmd.args(["--port", "8001", "--data-dir", data_dir.to_str().unwrap()]);
    cmd.spawn()?;

    // 等待后端就绪
    wait_for_backend(8001, 30).await?;

    Ok(())
}

async fn check_backend_health(port: u16) -> bool {
    let url = format!("http://127.0.0.1:{}/health", port);
    reqwest::get(&url).await.map(|r| r.status().is_success()).unwrap_or(false)
}

async fn wait_for_backend(port: u16, timeout_secs: u64) -> Result<(), &'static str> {
    for _ in 0..timeout_secs * 2 {
        if check_backend_health(port).await {
            return Ok(());
        }
        tokio::time::sleep(std::time::Duration::from_millis(500)).await;
    }
    Err("Backend did not start in time")
}
```

---

## 第四步:功能迁移对照表

| Electron 模块 | Tauri 对应 | 迁移方式 |

|--------------|-----------|---------|

| [`main.ts`](free-todo-frontend/electron/main.ts) | `src/main.rs` | 重写(Rust) |

| [`backend-server.ts`](free-todo-frontend/electron/backend-server.ts) | `src/backend.rs` | 重写(Rust) |

| [`next-server.ts`](free-todo-frontend/electron/next-server.ts) | `src/nextjs.rs` | 重写(Rust) |

| [`window-manager.ts`](free-todo-frontend/electron/window-manager.ts) | `tauri.conf.json` | 配置化 |

| [`tray-manager.ts`](free-todo-frontend/electron/tray-manager.ts) | Tauri SystemTray API | 重写(Rust) |

| [`global-shortcut-manager.ts`](free-todo-frontend/electron/global-shortcut-manager.ts) | Tauri GlobalShortcut Plugin | 重写(Rust) |

| [`ipc-handlers.ts`](free-todo-frontend/electron/ipc-handlers.ts) | Tauri Commands | 按需迁移 |

| [`preload.ts`](free-todo-frontend/electron/preload.ts) | `withGlobalTauri` | 不需要 |

| [`config.ts`](free-todo-frontend/electron/config.ts) | Rust 配置模块 | 重写(Rust) |

---

## 第五步:打包配置

### 5.1 Cargo.toml 依赖

```toml
[dependencies]
tauri = { version = "2", features = ["tray-icon", "protocol-asset"] }
tauri-plugin-shell = "2"
tauri-plugin-notification = "2"
tauri-plugin-global-shortcut = "2"
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"

[build-dependencies]
tauri-build = "2"
```

### 5.2 打包脚本更新

修改 [`package.json`](free-todo-frontend/package.json):

```json
{
  "scripts": {
    "tauri:dev": "tauri dev",
    "tauri:build": "pnpm build && pnpm backend:build && tauri build",
    "tauri:build-win": "pnpm build && pnpm backend:build:win && tauri build --target x86_64-pc-windows-msvc",
    "tauri:build-mac": "pnpm build && pnpm backend:build && tauri build --target universal-apple-darwin",
    "tauri:build-linux": "pnpm build && pnpm backend:build && tauri build --target x86_64-unknown-linux-gnu"
  }
}
```

---

## 第六步:前端适配

### 6.1 环境检测

修改前端代码检测运行环境:

```typescript
// lib/utils/platform.ts
export const isTauri = () => {
  return typeof window !== 'undefined' && '__TAURI__' in window;
};

export const isElectron = () => {
  return typeof window !== 'undefined' &&
    typeof window.process !== 'undefined' &&
    window.process.type === 'renderer';
};
```

### 6.2 API 调用保持不变

由于采用 HTTP Sidecar 模式,前端的 API 调用方式**完全不变**:

```typescript
// 现有代码继续使用,无需修改
const response = await fetch('http://localhost:8001/api/todos');
```

---

## 第七步:构建流程

### 7.1 开发模式

```bash
# 终端 1:启动 Python 后端
cd lifetrace && python -m lifetrace.server

# 终端 2:启动 Next.js 开发服务器
cd free-todo-frontend && pnpm dev

# 终端 3:启动 Tauri 开发模式
cd free-todo-frontend && pnpm tauri dev
```

### 7.2 生产构建

```bash
cd free-todo-frontend

# 1. 构建 Next.js standalone
pnpm build

# 2. 构建 Python 后端(PyInstaller)
pnpm backend:build

# 3. 构建 Tauri 应用
pnpm tauri build
```

---

## 预期收益

| 指标 | Electron 现状 | Tauri 预期 |

|-----|--------------|-----------|

| 前端体积 | 150-200 MB (Chromium) | 3-10 MB (System WebView) |

| 内存占用 | 200-400 MB | 50-100 MB |

| 启动速度 | 3-4 秒 | 1-2 秒 |

| 总打包体积 | 2.6 GB | 2.4-2.5 GB |

注:总体积减少有限,因为 Python 后端体积不变。主要收益在启动速度和内存占用。

---

## 风险与注意事项

1. **Rust 学习曲线**:需要学习 Rust 基础语法
2. **系统 WebView 兼容性**:

   - Windows: WebView2 (Edge),需要用户安装(Win11 内置)
   - macOS: WKWebView(系统内置)
   - Linux: WebKitGTK(需要安装)

3. **Island 模式**:Tauri 的无边框窗口支持有差异,需要适配
4. **全局快捷键**:Tauri 插件 API 与 Electron 略有不同
5. **IPC 通信**:如果有 Electron IPC 调用,需要迁移到 Tauri Commands

---

## 迁移步骤清单

1. 初始化 Tauri 项目(`pnpm tauri init`)
2. 配置 `tauri.conf.json`
3. 实现 Rust 主进程(`main.rs`)
4. 实现后端管理模块(`backend.rs`)
5. 实现 Next.js 服务器管理(`nextjs.rs`)
6. 实现系统托盘(Tauri SystemTray)
7. 实现全局快捷键(Tauri GlobalShortcut Plugin)
8. 测试开发模式运行
9. 测试生产构建
10. 跨平台测试(Windows/macOS/Linux)


================================================
FILE: .cursor/plans/后台持续录音方案_c7c8f0fe.plan.md
================================================
---
name: 后台持续录音方案
overview: 分析"后端驱动录音"方案的改造范围,并提供一个基于 Electron 主进程的更优替代方案,使录音不受面板切换影响。
todos:
  - id: analyze-electron-audio
    content: 实现 Electron 主进程音频录制模块 (audio-recorder.ts)
    status: pending
  - id: add-ipc-channels
    content: 添加录音控制 IPC 通道 (ipc-handlers.ts, preload.ts)
    status: pending
  - id: refactor-frontend-hook
    content: 重构 useAudioRecording hook 使用 IPC 调用
    status: pending
isProject: false
---

# 后台持续录音方案分析

## 当前架构

```mermaid
sequenceDiagram
    participant User as 用户
    participant Panel as AudioPanel渲染进程
    participant WS as WebSocket
    participant Backend as Python后端
    participant ASR as 阿里云FunASR

    User->>Panel: 点击开始录音
    Panel->>Panel: getUserMedia获取麦克风
    Panel->>Panel: AudioContext处理音频
    loop 录音中
        Panel->>WS: 发送PCM16数据
        WS->>Backend: 转发音频流
        Backend->>ASR: 发送到ASR服务
        ASR-->>Backend: 返回转录结果
        Backend-->>Panel: 推送转录文本
    end
    User->>User: 切换面板
    Note over Panel: 组件卸载,资源释放
    Note over Panel: 录音停止!
```

**问题根源**:录音资源(WebSocket、AudioContext、MediaStream)都在 `AudioPanel` 组件内部,组件卸载时资源被释放。

---

## 方案 3:Python 后端驱动录音

### 需要改造的内容

1. **启用 PyAudio 进行系统级音频采集**

   - 文件:[lifetrace/services/audio_service.py](lifetrace/services/audio_service.py)
   - 新增:音频录制线程/协程
   - 依赖:`pyaudio>=0.2.14`(已声明但未使用)

2. **新增后端录音管理 API**

   - `POST /api/audio/recording/start` - 启动录音
   - `POST /api/audio/recording/stop` - 停止录音
   - `GET /api/audio/recording/status` - 获取录音状态
   - WebSocket 仅用于推送转录结果,不再接收音频

3. **跨平台音频设备访问**

   - Windows:需要安装 PyAudio 的 Windows 预编译包
   - macOS:需要 PortAudio 库
   - Linux:需要 ALSA 开发库

4. **前端改造**

   - 移除 `useAudioRecording` 中的音频采集逻辑
   - 改为调用后端 API 控制录音
   - WebSocket 只接收转录结果

### 为什么改造范围大

| 改造点 | 复杂度 | 原因 |

|--------|--------|------|

| PyAudio 跨平台部署 | 高 | 需要编译原生依赖,不同 OS 配置不同 |

| 音频设备权限管理 | 高 | Python 进程需要独立申请麦克风权限 |

| 后端架构变化 | 中 | 从无状态变为有状态(持有录音资源) |

| 前后端接口重构 | 中 | WebSocket 协议从双向音频流变为单向推送 |

---

## 推荐方案:Electron 主进程驱动录音(方案 3 的变体)

由于这是一个 Electron 桌面应用,**在 Electron 主进程中实现录音**是更优的选择。

### 架构对比

```mermaid
flowchart TB
    subgraph current [当前架构]
        direction TB
        R1[渲染进程] --> |音频采集| R1
        R1 --> |WebSocket| B1[Python后端]
        Note1[面板切换导致组件卸载]
    end

    subgraph proposed [推荐架构]
        direction TB
        M2[Electron主进程] --> |音频采集| M2
        R2[渲染进程] --> |IPC控制| M2
        M2 --> |WebSocket| B2[Python后端]
        Note2[主进程独立于渲染进程]
    end
```

### 为什么更优

1. **Electron 主进程独立运行**:不受渲染进程中的 React 组件生命周期影响
2. **已有预留接口**:`tray-manager.ts` 中已有 `startRecording()`/`stopRecording()` 占位符
3. **IPC 机制完善**:已有成熟的 `contextBridge` + `ipcMain/ipcRenderer` 通信
4. **无需跨平台编译**:Electron 自身处理了跨平台问题

### 需要改造的内容

1. **Electron 主进程**(约 200-300 行代码)

   - 新增 [electron/audio-recorder.ts](free-todo-frontend/electron/audio-recorder.ts):使用 `node-record-lpcm16` 或 `node-microphone` 录音
   - 修改 [electron/ipc-handlers.ts](free-todo-frontend/electron/ipc-handlers.ts):添加录音控制 IPC 通道
   - 修改 [electron/preload.ts](free-todo-frontend/electron/preload.ts):暴露录音 API

2. **前端组件**(约 50-100 行代码)

   - 修改 [apps/audio/hooks/useAudioRecording.ts](free-todo-frontend/apps/audio/hooks/useAudioRecording.ts):改用 IPC 调用主进程录音
   - 可选:添加全局录音状态 store

3. **后端无需改动**:继续通过 WebSocket 接收音频流

### IPC 通道设计

```typescript
// 新增 IPC 通道
'audio:start-recording'   // 开始录音
'audio:stop-recording'    // 停止录音
'audio:recording-status'  // 录音状态变化(主进程 → 渲染进程)
'audio:transcription'     // 转录结果推送(主进程 → 渲染进程)
```

---

## 两种方案对比

| 维度 | Python 后端驱动 | Electron 主进程驱动(推荐) |

|------|----------------|---------------------------|

| 改造范围 | 大(前后端 + 跨平台编译) | 中(仅前端 Electron 层) |

| 跨平台兼容性 | 需要处理 PyAudio 部署 | Electron 原生支持 |

| 架构变化 | 后端从无状态变有状态 | 仅前端内部调整 |

| 复用现有代码 | 较少 | 复用 IPC、WebSocket 等 |

| 开发周期 | 较长 | 较短 |

---

## 结论

**如果您追求最小改动量**,推荐使用 **Electron 主进程驱动录音** 方案。它保持了现有的前后端分离架构,只在 Electron 层做改动,且 Electron 主进程天然不受面板切换影响。

**如果您有其他考虑**(如支持纯 Web 版本、与后端深度集成等),再考虑 Python 后端驱动方案。


================================================
FILE: .cursor/plans/打包与性能优化_ecd1657a.plan.md
================================================
---
name: 打包与性能优化
overview: 针对启动速度、依赖效率和打包体积三个核心问题,评估 Tauri + Nuitka 方案,并提供依赖精简和模块剔除的具体实施方案。
todos:
  - id: remove-unused-deps
    content: 移除未使用依赖:faster-whisper, whisperlivekit, wikipedia, arxiv
    status: pending
  - id: update-pyinstaller-excludes
    content: 更新 PyInstaller excludes:添加测试模块、开发工具、文档等排除项
    status: pending
  - id: use-opencv-headless
    content: 替换 opencv-python 为 opencv-python-headless
    status: pending
  - id: update-electron-builder
    content: 更新 electron-builder.yml 排除 .d.ts、测试、文档等
    status: pending
  - id: refactor-dependency-groups
    content: 重构 pyproject.toml 创建 vector/imaging/search 依赖组
    status: pending
  - id: tauri-poc
    content: 创建 Tauri POC 分支验证与 Python 后端的 Sidecar 集成
    status: pending
  - id: nuitka-test
    content: 使用 Nuitka 编译后端并对比体积和启动速度
    status: pending
isProject: false
---


================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto


================================================
FILE: .githooks/post-checkout
================================================
#!/usr/bin/env sh
set -u

repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"
if [ -z "$repo_root" ]; then
  echo "post-checkout: unable to locate repo root; skipping link_worktree_deps." >&2
  exit 0
fi

run_ps=0
sh_script="$repo_root/scripts/link_worktree_deps_here.sh"
if [ -f "$sh_script" ]; then
  if command -v bash >/dev/null 2>&1; then
    bash "$sh_script" || run_ps=1
  else
    sh "$sh_script" || run_ps=1
  fi
else
  run_ps=1
fi

if [ "$run_ps" -eq 1 ]; then
  ps_script="$repo_root/scripts/link_worktree_deps_here.ps1"
  if [ -f "$ps_script" ]; then
    if command -v powershell.exe >/dev/null 2>&1; then
      powershell.exe -ExecutionPolicy Bypass -File "$ps_script" || true
    elif command -v pwsh >/dev/null 2>&1; then
      pwsh -ExecutionPolicy Bypass -File "$ps_script" || true
    else
      echo "post-checkout: PowerShell not found; skipping link_worktree_deps." >&2
    fi
  else
    echo "post-checkout: missing link_worktree_deps scripts; skipping." >&2
  fi
fi

exit 0


================================================
FILE: .githooks/pre-commit
================================================
#!/usr/bin/env sh
set -u

if command -v pre-commit >/dev/null 2>&1; then
  exec pre-commit run --hook-stage pre-commit "$@"
fi

if command -v uv >/dev/null 2>&1; then
  exec uv run pre-commit run --hook-stage pre-commit "$@"
fi

echo "pre-commit: pre-commit/uv not found; skipping." >&2
exit 0


================================================
FILE: .github/BACKEND_GUIDELINES.md
================================================
# Backend Development Guidelines

**Language**: [English](BACKEND_GUIDELINES.md) | [中文](BACKEND_GUIDELINES_CN.md)

## 🐍 Python Backend Development Standards

This document details the development standards and best practices for the LifeTrace project backend (Python + FastAPI).

### Tech Stack

- **Framework**: FastAPI + Uvicorn (async web framework)
- **Language**: Python 3.12
- **ORM**: SQLAlchemy 2.x + SQLModel
- **Database Migration**: Alembic
- **Data Validation**: Pydantic 2.x
- **Configuration Management**: Dynaconf (supports YAML hot reload)
- **Logging**: Loguru
- **Scheduler**: APScheduler (background task scheduling)
- **OCR**: RapidOCR (local OCR recognition)
- **Vector Database**: ChromaDB (optional, for semantic search)
- **Text Embeddings**: sentence-transformers (optional)
- **LLM**: OpenAI-compatible API
- **Package Manager**: uv (recommended)
- **Code Quality**: Ruff (lint/format/check)

## 📋 Table of Contents

- [Code Style](#-code-style)
- [Project Architecture](#️-project-architecture)
- [Project Structure](#️-project-structure)
- [Naming Conventions](#-naming-conventions)
- [Type Annotations](#-type-annotations)
- [Docstrings](#-docstrings)
- [Error Handling](#-error-handling)
- [API Design](#-api-design)
- [Layered Architecture](#-layered-architecture)
- [Database Operations](#-database-operations)
- [Configuration Management](#-configuration-management)
- [LLM Services](#-llm-services)
- [Background Tasks](#-background-tasks)
- [Testing](#-testing)
- [Logging](#-logging)
- [Performance](#-performance)
- [Security](#-security)
- [API and Frontend Interaction](#-api-and-frontend-interaction)
- [Dependency Management](#-dependency-management)

## 🎨 Code Style

### PEP 8 Standard

We follow the [PEP 8](https://peps.python.org/pep-0008/) Python code style guide.

### Using Ruff

The project uses [Ruff](https://github.com/astral-sh/ruff) as the linter and formatter.

```bash
# Check code
uv run ruff check .

# Auto-fix issues
uv run ruff check --fix .

# Format code
uv run ruff format .
```

### Basic Rules

#### Indentation

```python
# ✅ Correct: Use 4 spaces
def my_function():
    if condition:
        do_something()

# ❌ Wrong: Use tabs
def my_function():
	if condition:
		do_something()
```

#### Line Length

```python
# ✅ Correct: Maximum 100 characters per line
def calculate_result(
    param1: int, param2: str, param3: float
) -> dict[str, Any]:
    return {"result": param1}

# ❌ Wrong: Line too long
def calculate_result(param1: int, param2: str, param3: float, param4: dict, param5: list) -> dict[str, Any]:
    return {"result": param1}
```

#### File Length Limits

To maintain code maintainability and readability, we provide the following guidelines for Python file length:

**Code Length Guidelines**:

- **Recommended Standard**: Keep single files under **500 lines**
- **Warning Threshold**: Consider refactoring when exceeding **700 lines**
- **Review Required**: Files over **1000 lines** must include justification and refactoring plan in PR

**Refactoring Guidelines**:

- Single function should not exceed **50 statements**
- Single class should not exceed **400 lines**
- Cyclomatic complexity must not exceed **15**
- Prioritize functional cohesion over strict line count limits

```python
# ✅ Correct: Moderate file length (~450 lines)
# task_service.py
class TaskService:
    """Task service containing complete task business logic."""

    def create_task(self, data: dict) -> Task:
        """Create a task."""
        pass

    def update_task(self, task_id: int, data: dict) -> Task:
        """Update a task."""
        pass

    # ... other related methods

# ⚠️ Needs Review: Files over 1000 lines
# complex_processor.py (1200 lines)
# PR must explain:
# 1. Why is this file so long?
# 2. Can it be split? How?
# 3. If not, what's the refactoring plan?

# ❌ Wrong: Function too complex (over 50 statements)
def process_data(data):
    # ... 100 lines of code
    pass
```

**When to Split Files**:

1. **Multiple Responsibilities**: A file handles multiple unrelated responsibilities

   ```text
   # Before: user_operations.py (800 lines)
   # Contains: user management, permissions, data export, email notifications

   # After:
   users/
   ├── manager.py          # User management
   ├── permissions.py      # Permission validation
   ├── export_service.py   # Data export
   └── notifications.py    # Email notifications
   ```

2. **Large Classes**: A single class exceeds 400 lines

   ```text
   # Before: task_handler.py (600 lines)
   class TaskHandler:
       # Contains: CRUD, validation, statistics, reporting

   # After:
   tasks/
   ├── manager.py      # TaskManager - CRUD operations
   ├── validator.py    # TaskValidator - Data validation
   ├── stats.py        # TaskStats - Statistics
   └── reporter.py     # TaskReporter - Report generation
   ```

3. **Long Functions**: A single function exceeds 50 statements, extract sub-functions

   ```python
   # ❌ Wrong: Function too long
   def process_order(order_data):
       # Validate data (20 lines)
       # Calculate price (30 lines)
       # Create order (25 lines)
       # Send notification (15 lines)
       pass  # Total 90 lines

   # ✅ Correct: Split into multiple functions
   def process_order(order_data):
       validated_data = validate_order_data(order_data)
       price = calculate_order_price(validated_data)
       order = create_order(validated_data, price)
       send_order_notification(order)
       return order
   ```

#### Imports

```python
# ✅ Correct: Import order and grouping
# 1. Standard library imports
import os
import sys
from datetime import datetime
from typing import Any, Optional

# 2. Third-party library imports
import numpy as np
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select

# 3. Local application/library imports
from lifetrace.storage.database import get_db
from lifetrace.schemas.task import TaskCreate, TaskResponse

# ❌ Wrong: Mixed import order
from lifetrace.storage.database import get_db
import os
from fastapi import APIRouter
```

#### Quotes

```python
# ✅ Correct: Use double quotes
message = "Hello, World!"
query = "SELECT * FROM users"

# ✅ Correct: Triple quotes for docstrings
description = """
This is a multi-line string.
"""
```

## 🏗️ Project Architecture

### Layered Architecture

The project follows a layered architecture pattern:

```
Router Layer (routers/)     → HTTP request handling, parameter validation
    ↓
Service Layer (services/)   → Business logic, orchestration of multiple Repository operations
    ↓
Repository Layer (repositories/) → Data access abstraction, database query encapsulation
    ↓
Storage Layer (storage/)    → SQLAlchemy ORM model definitions
```

**Layer Responsibilities**:

- **Router Layer**: Handle HTTP requests, parameter validation, call Service layer
- **Service Layer**: Business logic, orchestrate multiple Repository operations
- **Repository Layer**: Data access abstraction, encapsulate database queries
- **Schema Layer**: Request/response Pydantic models
- **Storage Layer**: SQLAlchemy ORM model definitions

## 🏗️ Project Structure

### Directory Organization

```
lifetrace/
├── server.py                 # FastAPI application entry
├── config/                   # Configuration files
│   ├── config.yaml          # User configuration
│   ├── default_config.yaml  # Default configuration
│   └── prompt.yaml          # LLM Prompt templates
├── routers/                  # API routes (Router layer)
├── services/                 # Business services (Service layer)
├── repositories/             # Data access (Repository layer)
├── schemas/                  # Pydantic data models
├── storage/                  # Data storage layer
│   ├── models.py            # SQLAlchemy models (database tables)
│   └── *_manager.py         # Data managers
├── llm/                      # LLM and AI services
├── jobs/                     # Background tasks
├── core/                     # Core dependencies and lazy-loaded services
└── util/                     # Utility functions
```

## 📝 Naming Conventions

### Variables and Functions

```python
# ✅ Correct: snake_case
user_name = "Alice"
user_age = 25

def get_user_profile(user_id: int):
    pass

# ❌ Wrong: camelCase
userName = "Alice"

def getUserProfile(userId: int):
    pass
```

### Classes

```python
# ✅ Correct: PascalCase
class UserManager:
    pass

class TaskScheduler:
    pass

# ❌ Wrong: snake_case
class user_manager:
    pass
```

### Constants

```python
# ✅ Correct: UPPER_CASE
MAX_RETRY_COUNT = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"

# ❌ Wrong: lowercase
max_retry_count = 3
```

## 🔤 Type Annotations

### Basic Type Annotations

```python
# ✅ Correct: Add type annotations
def greet(name: str) -> str:
    return f"Hello, {name}!"

def add_numbers(a: int, b: int) -> int:
    return a + b

def get_user(user_id: int) -> dict | None:
    return None

# ❌ Wrong: No type annotations
def greet(name):
    return f"Hello, {name}!"
```

### Collection Types

```python
# Python 3.9+: Use built-in types
def process_items(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

# Type aliases
from typing import TypeAlias

UserID: TypeAlias = int
UserData: TypeAlias = dict[str, Any]

def get_user_data(user_id: UserID) -> UserData:
    return {"id": user_id, "name": "Alice"}
```

### Pydantic Models

```python
from pydantic import BaseModel, Field

class User(BaseModel):
    """User model."""
    id: int
    name: str = Field(..., min_length=1, max_length=100)
    email: str
    age: Optional[int] = Field(None, ge=0, le=150)
    is_active: bool = True

    class Config:
        from_attributes = True
```

## 📚 Docstrings

### Function Docstrings

```python
def create_task(
    title: str,
    description: str | None = None,
    project_id: int | None = None
) -> Task:
    """
    Create a new task.

    Args:
        title: Task title, required and non-empty
        description: Task description, optional
        project_id: Associated project ID, optional

    Returns:
        Task: Created task object

    Raises:
        ValueError: If title is empty
        DatabaseError: If database operation fails

    Example:
        >>> task = create_task("Complete docs", "Write API docs", 1)
        >>> print(task.title)
        Complete docs
    """
    if not title:
        raise ValueError("Task title cannot be empty")

    # Implementation...
    return task
```

### Class Docstrings

```python
class TaskManager:
    """
    Task manager.

    Provides CRUD operations and advanced query functionality for tasks.

    Attributes:
        db: Database session object
        logger: Logger instance

    Example:
        >>> manager = TaskManager(db_session)
        >>> task = await manager.create_task(task_data)
    """

    def __init__(self, db: AsyncSession):
        """
        Initialize task manager.

        Args:
            db: Async database session
        """
        self.db = db
```

## 🚨 Error Handling

### Exception Handling

```python
from fastapi import HTTPException

# ✅ Correct: Catch specific exceptions
async def get_task(task_id: int) -> Task:
    try:
        task = await task_manager.get_task(task_id)
        if task is None:
            raise HTTPException(status_code=404, detail="Task not found")
        return task
    except DatabaseError as e:
        logger.error(f"Database error: {e}")
        raise HTTPException(status_code=500, detail="Database operation failed")

# ❌ Wrong: Catch all exceptions
async def get_task(task_id: int) -> Task:
    try:
        task = await task_manager.get_task(task_id)
        return task
    except Exception as e:  # Too broad
        raise HTTPException(status_code=500, detail="Error occurred")
```

## 🌐 API Design

### RESTful API Standards

```python
from fastapi import APIRouter, Depends, Query, Path
from lifetrace.repositories.task_repository import TaskRepository
from lifetrace.services.task_service import TaskService

router = APIRouter(prefix="/api/tasks", tags=["tasks"])

# ✅ Correct: RESTful route design
@router.get("/", response_model=list[TaskResponse])
async def list_tasks(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    status: Optional[str] = Query(None),
    task_service: TaskService = Depends(get_task_service)
):
    """List tasks."""
    return await task_service.list_tasks(skip=skip, limit=limit, status=status)

@router.get("/{task_id}", response_model=TaskResponse)
async def get_task(
    task_id: int = Path(..., gt=0),
    task_service: TaskService = Depends(get_task_service)
):
    """Get specific task."""
    return await task_service.get_task(task_id)

@router.post("/", response_model=TaskResponse, status_code=201)
async def create_task(
    task: TaskCreate,
    task_service: TaskService = Depends(get_task_service)
):
    """Create new task."""
    return await task_service.create_task(task)

@router.put("/{task_id}", response_model=TaskResponse)
async def update_task(
    task_id: int = Path(..., gt=0),
    task: TaskUpdate = None,
    task_service: TaskService = Depends(get_task_service)
):
    """Update task."""
    return await task_service.update_task(task_id, task)

@router.delete("/{task_id}", status_code=204)
async def delete_task(
    task_id: int = Path(..., gt=0),
    task_service: TaskService = Depends(get_task_service)
):
    """Delete task."""
    await task_service.delete_task(task_id)
```

### Registering Routes

Import and register new routes in `server.py`:

```python
from lifetrace.routers import tasks

app.include_router(tasks.router)
```

## 🏛️ Layered Architecture

### Router Layer

Handle HTTP requests, parameter validation, call Service layer:

```python
# routers/tasks.py
from fastapi import APIRouter, Depends
from lifetrace.services.task_service import TaskService

router = APIRouter(prefix="/api/tasks", tags=["tasks"])

@router.get("/", response_model=list[TaskResponse])
async def list_tasks(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    task_service: TaskService = Depends(get_task_service)
):
    """List tasks."""
    return await task_service.list_tasks(skip=skip, limit=limit)
```

### Service Layer

Implement complex business logic, orchestrate multiple Repository operations:

```python
# services/task_service.py
from lifetrace.repositories.task_repository import TaskRepository
from lifetrace.schemas.task import TaskCreate, TaskUpdate

class TaskService:
    """Task service."""

    def __init__(self, task_repository: TaskRepository):
        self.task_repository = task_repository

    async def create_task(self, task_data: TaskCreate) -> Task:
        """Create task with business logic."""
        # Business validation
        if len(task_data.title) > 200:
            raise ValueError("Task title too long")

        # Orchestrate repository operations
        return await self.task_repository.create(task_data)
```

### Repository Layer

Data access abstraction, encapsulate database queries:

```python
# repositories/task_repository.py
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from lifetrace.storage.models import Task

class TaskRepository:
    """Task repository."""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_by_id(self, task_id: int) -> Task | None:
        """Get task by ID."""
        result = await self.db.execute(
            select(Task).where(Task.id == task_id)
        )
        return result.scalar_one_or_none()

    async def create(self, task_data: TaskCreate) -> Task:
        """Create task."""
        task = Task(**task_data.model_dump())
        self.db.add(task)
        await self.db.commit()
        await self.db.refresh(task)
        return task
```

## ⚙️ Configuration Management

### Configuration File Structure

- `config/default_config.yaml` - Default configuration (do not modify)
- `config/config.yaml` - User configuration (overrides default values)
- Uses Dynaconf for configuration hot reload

### Accessing Configuration

Access via `settings` object in `util/settings.py`:

```python
from lifetrace.util.settings import settings

# Access nested configuration
port = settings.server.port

# Access with default value
timeout = settings.get("timeout", default=30)
```

### Configuration Hot Reload

The following configurations support hot reload (no restart required):
- LLM configuration
- Recorder configuration
- OCR configuration

## 💾 Database Operations

### SQLAlchemy Models

```python
from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Text
from sqlalchemy.orm import relationship

class Task(Base):
    """Task model."""
    __tablename__ = "tasks"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(200), nullable=False, index=True)
    description = Column(Text, nullable=True)
    status = Column(String(50), nullable=False, default="pending", index=True)
    priority = Column(Integer, nullable=False, default=0)
    project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
    created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
    updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationships
    project = relationship("Project", back_populates="tasks")
```

### Database Migrations

The project uses Alembic for database migrations:

- **Config file**: `alembic.ini`
- **Migration scripts**: `migrations/versions/`

**Common commands**:
- `alembic revision --autogenerate -m "description"` - Generate migration script
- `alembic upgrade head` - Apply all migrations
- `alembic downgrade -1` - Rollback one version
- `alembic history` - View migration history

### Database Queries

Use Repository layer for database queries (see [Repository Layer](#-repository-layer) above).

## 🧪 Testing

### Unit Tests

```python
import pytest
from sqlalchemy.ext.asyncio import AsyncSession

from lifetrace.schemas.task import TaskCreate
from lifetrace.storage.task_manager import TaskManager

@pytest.mark.asyncio
async def test_create_task(db_session: AsyncSession):
    """Test task creation."""
    manager = TaskManager(db_session)
    task_data = TaskCreate(title="Test Task")

    task = await manager.create_task(task_data)

    assert task.id is not None
    assert task.title == "Test Task"
    assert task.status == "pending"
```

## 🤖 LLM Services

### LLM Client Usage

The project uses OpenAI-compatible API, wrapped in `llm/llm_client.py`:

- Supports Alibaba Cloud Tongyi Qianwen, OpenAI, Claude, etc.
- Configuration managed in `config/config.yaml` under `llm` section
- Supports streaming responses (SSE)

### RAG Service

`llm/rag_service.py` provides Retrieval-Augmented Generation:

- Intelligent time parsing (e.g., "last week", "yesterday")
- Hybrid retrieval strategy (vector retrieval + full-text search)
- Context compression and ranking

### Prompt Management

Prompt templates are stored in `config/prompt.yaml`:

- Use YAML format for easy maintenance
- Support variable interpolation
- Organized by feature modules

## ⏰ Background Tasks

### Task Scheduling

Use APScheduler to manage background tasks:

- Tasks defined in `lifetrace/jobs/` directory
- Managed through `job_manager.py`
- Supports scheduled tasks and interval tasks

### Task Types

- **recorder**: Screen recorder, scheduled screenshots
- **ocr**: OCR processor, processes screenshots waiting for recognition

## 📊 Logging

Use Loguru for logging, import logger from `util/logging_config.py`:

```python
from lifetrace.util.logging_config import logger

class TaskService:
    """Task service."""

    async def create_task(self, task_data: TaskCreate) -> Task:
        """Create task."""
        logger.info(f"Creating task: {task_data.title}")

        try:
            task = Task(**task_data.model_dump())
            self.db.add(task)
            await self.db.commit()
            await self.db.refresh(task)

            logger.info(f"Task created successfully: ID={task.id}")
            return task

        except Exception as e:
            logger.error(f"Failed to create task: {e}")
            await self.db.rollback()
            raise
```

### Logging Guidelines

- Must log critical operations
- Must log complete stack trace for exceptions
- Must sanitize sensitive information (API Keys, etc.)
- Use structured logging for easy analysis

## ⚡ Performance

### Query Optimization

```python
# ✅ Correct: Use eager loading
from sqlalchemy.orm import selectinload

async def get_tasks_with_projects(self) -> list[Task]:
    """Get tasks with their associated projects."""
    result = await self.db.execute(
        select(Task).options(selectinload(Task.project))
    )
    return list(result.scalars().all())

# ✅ Correct: Batch insert
async def create_tasks_batch(self, tasks_data: list[TaskCreate]) -> list[Task]:
    """Create multiple tasks."""
    tasks = [Task(**data.model_dump()) for data in tasks_data]
    self.db.add_all(tasks)
    await self.db.commit()
    return tasks
```

## 🔒 Security

### Input Validation

```python
# ✅ Correct: Use Pydantic for validation
from pydantic import BaseModel, Field, field_validator

class TaskCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)

    @field_validator("title")
    @classmethod
    def validate_title(cls, v: str) -> str:
        if "<script>" in v.lower():
            raise ValueError("Title contains illegal characters")
        return v
```

### SQL Injection Prevention

```python
# ✅ Correct: Use parameterized queries (SQLAlchemy handles this)
task = await self.db.execute(
    select(Task).where(Task.id == task_id)
)

# ❌ Wrong: String concatenation (vulnerable to SQL injection)
query = f"SELECT * FROM tasks WHERE id = {task_id}"
```

## 📡 API and Frontend Interaction

### Naming Style Conversion

Backend uses `snake_case`, frontend uses `camelCase`:

- Frontend fetcher automatically performs conversion
- Backend Schema uniformly uses `snake_case`
- OpenAPI Schema automatically generated by FastAPI

### Frontend Code Generation

Frontend uses Orval to auto-generate API code from OpenAPI Schema:

- After backend API changes, frontend runs `pnpm orval` to regenerate
- Ensure OpenAPI Schema is complete and accurate

## 📦 Dependency Management

### Using uv

The project uses uv as the package manager:

- `uv sync` - Sync dependencies
- `uv add <package>` - Add dependency
- `uv remove <package>` - Remove dependency
- `uv run <command>` - Run command in virtual environment

### Dependency Groups

- Main dependencies: `dependencies` in `pyproject.toml`
- Development dependencies: `dependency-groups.dev`
- Optional dependencies: `dependency-groups.vector` (vector search functionality)

## ✅ Code Review Checklist

Before submitting code, ensure:

- [ ] Code follows PEP 8 style guide
- [ ] `uv run ruff check .` passes with no errors
- [ ] `uv run ruff format .` applied
- [ ] All functions have type annotations
- [ ] Public functions have docstrings
- [ ] Proper error handling added
- [ ] Parameterized queries used (no SQL injection)
- [ ] Appropriate logging added
- [ ] Unit tests written
- [ ] Tests pass
- [ ] Documentation updated
- [ ] API changes reflected in OpenAPI Schema
- [ ] Follows layered architecture (Router → Service → Repository)
- [ ] Configuration supports hot reload (if applicable)
- [ ] Background tasks properly scheduled

---

Happy Coding! 🐍


================================================
FILE: .github/BACKEND_GUIDELINES_CN.md
================================================
# 后端开发规范

**语言**: [English](BACKEND_GUIDELINES.md) | [中文](BACKEND_GUIDELINES_CN.md)

## 🐍 Python 后端开发规范

本文档详细说明了 LifeTrace 项目后端(Python + FastAPI)的开发规范和最佳实践。

### 技术栈

- **框架**: FastAPI + Uvicorn(异步 Web 框架)
- **语言**: Python 3.12
- **ORM**: SQLAlchemy 2.x + SQLModel
- **数据库迁移**: Alembic
- **数据验证**: Pydantic 2.x
- **配置管理**: Dynaconf(支持 YAML 热重载)
- **日志**: Loguru
- **调度器**: APScheduler(后台任务调度)
- **OCR**: RapidOCR(本地 OCR 识别)
- **向量数据库**: ChromaDB(可选,用于语义搜索)
- **文本嵌入**: sentence-transformers(可选)
- **LLM**: OpenAI 兼容 API
- **包管理**: uv(推荐)
- **代码质量**: Ruff(lint/format/check)

## 📋 目录

- [代码风格](#-代码风格)
- [项目架构](#️-项目架构)
- [项目结构](#️-项目结构)
- [命名规范](#-命名规范)
- [类型注解](#-类型注解)
- [文档字符串](#-文档字符串)
- [错误处理](#-错误处理)
- [API 设计](#-api-设计)
- [分层架构](#-分层架构)
- [数据库操作](#-数据库操作)
- [配置管理](#-配置管理)
- [LLM 服务](#-llm-服务)
- [后台任务](#-后台任务)
- [测试](#-测试)
- [日志记录](#-日志记录)
- [性能优化](#-性能优化)
- [安全性](#-安全性)
- [API 与前端交互](#-api-与前端交互)
- [依赖管理](#-依赖管理)

## 🎨 代码风格

### PEP 8 标准

我们遵循 [PEP 8](https://peps.python.org/pep-0008/) Python 代码风格指南。

### 使用 Ruff

项目使用 [Ruff](https://github.com/astral-sh/ruff) 作为代码检查器和格式化工具。

```bash
# 检查代码
uv run ruff check .

# 自动修复问题
uv run ruff check --fix .

# 格式化代码
uv run ruff format .
```

### 基本规则

#### 缩进和空格

```python
# ✅ 正确:使用 4 个空格缩进
def my_function():
    if condition:
        do_something()

# ❌ 错误:使用 Tab 缩进
def my_function():
	if condition:
		do_something()
```

#### 行长度

```python
# ✅ 正确:每行不超过 100 字符
def calculate_result(
    param1: int, param2: str, param3: float
) -> dict[str, Any]:
    return {"result": param1}

# ❌ 错误:行太长
def calculate_result(param1: int, param2: str, param3: float, param4: dict, param5: list) -> dict[str, Any]:
    return {"result": param1}
```

#### 文件长度限制

为了保持代码的可维护性和可读性,我们对单个 Python 文件的行数提供以下指导原则:

**代码长度指导原则**:

- **推荐标准**:单个文件保持在 **500 行**以内
- **警戒线**:超过 **700 行**时应考虑拆分
- **必须审查**:超过 **1000 行**的文件需在 PR 中说明理由,并提供重构计划

**拆分建议**:

- 单个函数不超过 **50 条语句**
- 单个类不超过 **400 行**
- 圈复杂度不超过 **15**
- 优先考虑功能内聚性,而不是强制行数限制

```python
# ✅ 正确:适度的文件长度(约 450 行)
# task_service.py
class TaskService:
    """任务服务,包含完整的任务业务逻辑。"""

    def create_task(self, data: dict) -> Task:
        """创建任务。"""
        pass

    def update_task(self, task_id: int, data: dict) -> Task:
        """更新任务。"""
        pass

    # ... 其他相关方法

# ⚠️ 需要审查:超过 1000 行的文件
# complex_processor.py (1200 行)
# 在 PR 中需要说明:
# 1. 为什么这个文件这么长?
# 2. 是否可以拆分?如何拆分?
# 3. 如果不能拆分,有什么重构计划?

# ❌ 错误:函数过于复杂(超过 50 条语句)
def process_data(data):
    # ... 100 行代码
    pass
```

**何时需要拆分文件**:

1. **文件职责过多**:一个文件承担了多个不相关的职责

   ```text
   # 拆分前:user_operations.py (800 行)
   # 包含:用户管理、权限验证、数据导出、邮件通知

   # 拆分后:
   users/
   ├── manager.py          # 用户管理
   ├── permissions.py      # 权限验证
   ├── export_service.py   # 数据导出
   └── notifications.py    # 邮件通知
   ```

2. **类过大**:单个类的代码行数超过 400 行

   ```text
   # 拆分前:task_handler.py (600 行)
   class TaskHandler:
       # 包含:CRUD、验证、统计、报表生成

   # 拆分后:
   tasks/
   ├── manager.py      # TaskManager - CRUD 操作
   ├── validator.py    # TaskValidator - 数据验证
   ├── stats.py        # TaskStats - 统计功能
   └── reporter.py     # TaskReporter - 报表生成
   ```

3. **函数过长**:单个函数超过 50 条语句,应该提取子函数

   ```python
   # ❌ 错误:函数过长
   def process_order(order_data):
       # 验证数据(20 行)
       # 计算价格(30 行)
       # 创建订单(25 行)
       # 发送通知(15 行)
       pass  # 总共 90 行

   # ✅ 正确:拆分为多个函数
   def process_order(order_data):
       validated_data = validate_order_data(order_data)
       price = calculate_order_price(validated_data)
       order = create_order(validated_data, price)
       send_order_notification(order)
       return order
   ```

#### 导入语句

```python
# ✅ 正确:导入顺序和分组
# 1. 标准库导入
import os
import sys
from datetime import datetime
from typing import Any, Optional

# 2. 第三方库导入
import numpy as np
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select

# 3. 本地应用/库导入
from lifetrace.storage.database import get_db
from lifetrace.schemas.task import TaskCreate, TaskResponse

# ❌ 错误:混乱的导入顺序
from lifetrace.storage.database import get_db
import os
from fastapi import APIRouter
```

#### 引号

```python
# ✅ 正确:使用双引号
message = "Hello, World!"
query = "SELECT * FROM users WHERE id = ?"

# ✅ 正确:三引号用于多行字符串和文档字符串
description = """
这是一个多行字符串,
包含多行内容。
"""
```

## 🏗️ 项目架构

### 分层架构

项目采用分层架构模式:

```
路由层 (routers/)     → HTTP 请求处理,参数验证
    ↓
服务层 (services/)   → 业务逻辑,编排多个 Repository 操作
    ↓
仓储层 (repositories/) → 数据访问抽象,封装数据库查询
    ↓
存储层 (storage/)    → SQLAlchemy ORM 模型定义
```

**层级职责**:

- **路由层**: 处理 HTTP 请求,参数验证,调用服务层
- **服务层**: 业务逻辑,编排多个仓储层操作
- **仓储层**: 数据访问抽象,封装数据库查询
- **模型层**: 请求/响应的 Pydantic 模型
- **存储层**: SQLAlchemy ORM 模型定义

## 🏗️ 项目结构

### 目录组织

```
lifetrace/
├── server.py                 # FastAPI 应用入口
├── config/                   # 配置文件目录
│   ├── config.yaml          # 用户配置
│   ├── default_config.yaml  # 默认配置
│   └── prompt.yaml          # LLM Prompt 模板
├── routers/                  # API 路由(路由层)
├── services/                 # 业务服务(服务层)
├── repositories/             # 数据访问(仓储层)
├── schemas/                  # Pydantic 数据模型
├── storage/                  # 数据存储层
│   ├── models.py            # SQLAlchemy 模型(数据库表)
│   └── *_manager.py         # 数据管理器
├── llm/                      # LLM 和 AI 服务
├── jobs/                     # 后台任务
├── core/                     # 核心依赖和懒加载服务
└── util/                     # 工具函数
```

## 📝 命名规范

### 变量和函数

```python
# ✅ 正确:小写字母和下划线(snake_case)
user_name = "Alice"
user_age = 25

def get_user_profile(user_id: int):
    pass

# ❌ 错误:使用驼峰命名
userName = "Alice"

def getUserProfile(userId: int):
    pass
```

### 类

```python
# ✅ 正确:驼峰命名(PascalCase)
class UserManager:
    pass

class TaskScheduler:
    pass

# ❌ 错误:使用下划线
class user_manager:
    pass
```

### 常量

```python
# ✅ 正确:全大写字母和下划线
MAX_RETRY_COUNT = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"

# ❌ 错误:使用小写
max_retry_count = 3
```

## 🔤 类型注解

### 基本类型注解

```python
from typing import Any, Optional

# ✅ 正确:为所有函数参数和返回值添加类型注解
def greet(name: str) -> str:
    return f"Hello, {name}!"

def add_numbers(a: int, b: int) -> int:
    return a + b

def get_user(user_id: int) -> dict | None:
    return None

# ❌ 错误:没有类型注解
def greet(name):
    return f"Hello, {name}!"
```

### 集合类型

```python
# Python 3.9+:使用内置类型
def process_items(items: list[str]) -> dict[str, int]:
    return {item: len(item) for item in items}

# ✅ 正确:为复杂类型使用类型别名
from typing import TypeAlias

UserID: TypeAlias = int
UserData: TypeAlias = dict[str, Any]

def get_user_data(user_id: UserID) -> UserData:
    return {"id": user_id, "name": "Alice"}
```

### Pydantic 模型

```python
from pydantic import BaseModel, Field

class User(BaseModel):
    """用户模型。"""
    id: int
    name: str = Field(..., min_length=1, max_length=100)
    email: str = Field(..., pattern=r"^[\w\.-]+@[\w\.-]+\.\w+$")
    age: Optional[int] = Field(None, ge=0, le=150)
    is_active: bool = True

    class Config:
        from_attributes = True
```

## 📚 文档字符串

### 函数文档字符串

```python
def create_task(
    title: str,
    description: str | None = None,
    project_id: int | None = None
) -> Task:
    """
    创建新任务。

    Args:
        title: 任务标题,必填且不能为空
        description: 任务描述,可选
        project_id: 关联的项目 ID,可选

    Returns:
        Task: 创建的任务对象

    Raises:
        ValueError: 如果标题为空
        DatabaseError: 如果数据库操作失败

    Example:
        >>> task = create_task("完成文档", "编写 API 文档", 1)
        >>> print(task.title)
        完成文档
    """
    if not title:
        raise ValueError("任务标题不能为空")

    # 实现逻辑...
    return task
```

### 类文档字符串

```python
class TaskManager:
    """
    任务管理器。

    提供任务的 CRUD 操作和高级查询功能。

    Attributes:
        db: 数据库会话对象
        logger: 日志记录器

    Example:
        >>> manager = TaskManager(db_session)
        >>> task = await manager.create_task(task_data)
    """

    def __init__(self, db: AsyncSession):
        """
        初始化任务管理器。

        Args:
            db: 异步数据库会话
        """
        self.db = db
```

## 🚨 错误处理

### 异常处理

```python
from fastapi import HTTPException

# ✅ 正确:捕获特定异常
async def get_task(task_id: int) -> Task:
    try:
        task = await task_manager.get_task(task_id)
        if task is None:
            raise HTTPException(status_code=404, detail="任务不存在")
        return task
    except DatabaseError as e:
        logger.error(f"数据库错误: {e}")
        raise HTTPException(status_code=500, detail="数据库操作失败")
    except ValidationError as e:
        logger.warning(f"验证错误: {e}")
        raise HTTPException(status_code=400, detail=str(e))

# ❌ 错误:捕获所有异常
async def get_task(task_id: int) -> Task:
    try:
        task = await task_manager.get_task(task_id)
        return task
    except Exception as e:  # 太宽泛
        raise HTTPException(status_code=500, detail="发生错误")
```

## 🌐 API 设计

### RESTful API 规范

```python
from fastapi import APIRouter, Depends, Query, Path
from lifetrace.repositories.task_repository import TaskRepository
from lifetrace.services.task_service import TaskService

router = APIRouter(prefix="/api/tasks", tags=["tasks"])

# ✅ 正确:RESTful 路由设计
@router.get("/", response_model=list[TaskResponse])
async def list_tasks(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    status: Optional[str] = Query(None),
    task_service: TaskService = Depends(get_task_service)
):
    """获取任务列表。"""
    return await task_service.list_tasks(skip=skip, limit=limit, status=status)

@router.get("/{task_id}", response_model=TaskResponse)
async def get_task(
    task_id: int = Path(..., gt=0),
    task_service: TaskService = Depends(get_task_service)
):
    """获取指定任务。"""
    return await task_service.get_task(task_id)

@router.post("/", response_model=TaskResponse, status_code=201)
async def create_task(
    task: TaskCreate,
    task_service: TaskService = Depends(get_task_service)
):
    """创建新任务。"""
    return await task_service.create_task(task)

@router.put("/{task_id}", response_model=TaskResponse)
async def update_task(
    task_id: int = Path(..., gt=0),
    task: TaskUpdate = None,
    task_service: TaskService = Depends(get_task_service)
):
    """更新任务。"""
    return await task_service.update_task(task_id, task)

@router.delete("/{task_id}", status_code=204)
async def delete_task(
    task_id: int = Path(..., gt=0),
    task_service: TaskService = Depends(get_task_service)
):
    """删除任务。"""
    await task_service.delete_task(task_id)
```

### 注册路由

在 `server.py` 中导入并注册新路由:

```python
from lifetrace.routers import tasks

app.include_router(tasks.router)
```

## 🏛️ 分层架构

### 路由层

处理 HTTP 请求,参数验证,调用服务层:

```python
# routers/tasks.py
from fastapi import APIRouter, Depends
from lifetrace.services.task_service import TaskService

router = APIRouter(prefix="/api/tasks", tags=["tasks"])

@router.get("/", response_model=list[TaskResponse])
async def list_tasks(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    task_service: TaskService = Depends(get_task_service)
):
    """获取任务列表。"""
    return await task_service.list_tasks(skip=skip, limit=limit)
```

### 服务层

实现复杂的业务逻辑,编排多个仓储层操作:

```python
# services/task_service.py
from lifetrace.repositories.task_repository import TaskRepository
from lifetrace.schemas.task import TaskCreate, TaskUpdate

class TaskService:
    """任务服务。"""

    def __init__(self, task_repository: TaskRepository):
        self.task_repository = task_repository

    async def create_task(self, task_data: TaskCreate) -> Task:
        """创建任务(包含业务逻辑)。"""
        # 业务验证
        if len(task_data.title) > 200:
            raise ValueError("任务标题过长")

        # 编排仓储层操作
        return await self.task_repository.create(task_data)
```

### 仓储层

数据访问抽象,封装数据库查询:

```python
# repositories/task_repository.py
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from lifetrace.storage.models import Task

class TaskRepository:
    """任务仓储。"""

    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_by_id(self, task_id: int) -> Task | None:
        """根据 ID 获取任务。"""
        result = await self.db.execute(
            select(Task).where(Task.id == task_id)
        )
        return result.scalar_one_or_none()

    async def create(self, task_data: TaskCreate) -> Task:
        """创建任务。"""
        task = Task(**task_data.model_dump())
        self.db.add(task)
        await self.db.commit()
        await self.db.refresh(task)
        return task
```

## ⚙️ 配置管理

### 配置文件结构

- `config/default_config.yaml` - 默认配置(不要修改)
- `config/config.yaml` - 用户配置(覆盖默认值)
- 使用 Dynaconf 支持配置热重载

### 访问配置

通过 `util/settings.py` 中的 `settings` 对象访问:

```python
from lifetrace.util.settings import settings

# 访问嵌套配置
port = settings.server.port

# 带默认值访问
timeout = settings.get("timeout", default=30)
```

### 配置热重载

以下配置支持热重载(无需重启):
- LLM 配置
- 录制配置
- OCR 配置

## 💾 数据库操作

### SQLAlchemy 模型

```python
from datetime import datetime
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Text
from sqlalchemy.orm import relationship

class Task(Base):
    """任务模型。"""
    __tablename__ = "tasks"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(200), nullable=False, index=True)
    description = Column(Text, nullable=True)
    status = Column(String(50), nullable=False, default="pending", index=True)
    priority = Column(Integer, nullable=False, default=0)
    project_id = Column(Integer, ForeignKey("projects.id"), nullable=True)
    created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
    updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)

    # 关系
    project = relationship("Project", back_populates="tasks")
```

### 数据库迁移

项目使用 Alembic 管理数据库迁移:

- **配置文件**: `alembic.ini`
- **迁移脚本**: `migrations/versions/`

**常用命令**:
- `alembic revision --autogenerate -m "描述"` - 生成迁移脚本
- `alembic upgrade head` - 应用所有迁移
- `alembic downgrade -1` - 回滚一个版本
- `alembic history` - 查看迁移历史

### 数据库查询

使用仓储层进行数据库查询(参见[仓储层](#-仓储层)部分)。

## 🧪 测试

### 单元测试

```python
import pytest
from sqlalchemy.ext.asyncio import AsyncSession

from lifetrace.schemas.task import TaskCreate
from lifetrace.storage.task_manager import TaskManager

@pytest.mark.asyncio
async def test_create_task(db_session: AsyncSession):
    """测试创建任务。"""
    manager = TaskManager(db_session)
    task_data = TaskCreate(title="测试任务")

    task = await manager.create_task(task_data)

    assert task.id is not None
    assert task.title == "测试任务"
    assert task.status == "pending"
```

## 🤖 LLM 服务

### LLM 客户端使用

项目使用 OpenAI 兼容 API,通过 `llm/llm_client.py` 封装:

- 支持阿里云通义千问、OpenAI、Claude 等
- 配置通过 `config/config.yaml` 的 `llm` 部分管理
- 支持流式响应(SSE)

### RAG 服务

`llm/rag_service.py` 提供检索增强生成:

- 智能时间解析(如"上周"、"昨天")
- 混合检索策略(向量检索 + 全文检索)
- 上下文压缩和排序

### Prompt 管理

Prompt 模板统一存放在 `config/prompt.yaml`:

- 使用 YAML 格式便于维护
- 支持变量插值
- 按功能模块组织

## ⏰ 后台任务

### 任务调度

使用 APScheduler 管理后台任务:

- 任务定义在 `lifetrace/jobs/` 目录
- 通过 `job_manager.py` 统一管理
- 支持定时任务和间隔任务

### 任务类型

- **recorder**: 屏幕录制器,定时截图
- **ocr**: OCR 处理器,处理待识别的截图

## 📊 日志记录

使用 Loguru,从 `util/logging_config.py` 导入 logger:

```python
from lifetrace.util.logging_config import logger

class TaskService:
    """任务服务。"""

    async def create_task(self, task_data: TaskCreate) -> Task:
        """创建任务。"""
        logger.info(f"创建任务: {task_data.title}")

        try:
            task = Task(**task_data.model_dump())
            self.db.add(task)
            await self.db.commit()
            await self.db.refresh(task)

            logger.info(f"任务创建成功: ID={task.id}")
            return task

        except Exception as e:
            logger.error(f"创建任务失败: {e}")
            await self.db.rollback()
            raise
```

### 日志规范

- 关键操作必须记录日志
- 异常必须记录完整堆栈
- 敏感信息(API Key 等)必须脱敏
- 使用结构化日志便于分析

## ⚡ 性能优化

### 数据库查询优化

```python
# ✅ 正确:使用 eager loading 避免 N+1 查询
from sqlalchemy.orm import selectinload

async def get_tasks_with_projects(self) -> list[Task]:
    """获取任务及其关联的项目。"""
    result = await self.db.execute(
        select(Task).options(selectinload(Task.project))
    )
    return list(result.scalars().all())

# ✅ 正确:批量插入
async def create_tasks_batch(self, tasks_data: list[TaskCreate]) -> list[Task]:
    """批量创建任务。"""
    tasks = [Task(**data.model_dump()) for data in tasks_data]
    self.db.add_all(tasks)
    await self.db.commit()
    return tasks
```

## 🔒 安全性

### 输入验证

```python
# ✅ 正确:使用 Pydantic 验证输入
from pydantic import BaseModel, Field, field_validator

class TaskCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=200)
    description: Optional[str] = Field(None, max_length=2000)

    @field_validator("title")
    @classmethod
    def validate_title(cls, v: str) -> str:
        # 防止 XSS
        if "<script>" in v.lower():
            raise ValueError("标题包含非法字符")
        return v
```

### SQL 注入防护

```python
# ✅ 正确:使用参数化查询(SQLAlchemy 自动处理)
task = await self.db.execute(
    select(Task).where(Task.id == task_id)
)

# ❌ 错误:字符串拼接(容易受到 SQL 注入攻击)
query = f"SELECT * FROM tasks WHERE id = {task_id}"
```

## 📡 API 与前端交互

### 命名风格转换

后端使用 `snake_case`,前端使用 `camelCase`:

- 前端 fetcher 自动进行转换
- 后端 Schema 统一使用 `snake_case`
- OpenAPI Schema 由 FastAPI 自动生成

### 前端代码生成

前端使用 Orval 根据 OpenAPI Schema 自动生成 API 代码:

- 后端 API 变更后,前端运行 `pnpm orval` 重新生成
- 确保 OpenAPI Schema 完整且准确

## 📦 依赖管理

### 使用 uv

项目使用 uv 作为包管理器:

- `uv sync` - 同步依赖
- `uv add <package>` - 添加依赖
- `uv remove <package>` - 移除依赖
- `uv run <command>` - 在虚拟环境中运行命令

### 依赖分组

- 主依赖:`pyproject.toml` 的 `dependencies`
- 开发依赖:`dependency-groups.dev`
- 可选依赖:`dependency-groups.vector`(向量搜索功能)

## ✅ 代码检查清单

在提交代码前,请确保:

- [ ] 代码遵循 PEP 8 风格指南
- [ ] 运行 `uv run ruff check .` 没有错误
- [ ] 运行 `uv run ruff format .` 格式化代码
- [ ] 所有函数和类都有类型注解
- [ ] 所有公共函数和类都有文档字符串
- [ ] 添加了适当的错误处理
- [ ] 使用了参数化查询防止 SQL 注入
- [ ] 添加了必要的日志记录
- [ ] 编写了单元测试
- [ ] 测试通过
- [ ] 更新了相关文档
- [ ] API 变更已在 OpenAPI Schema 中反映
- [ ] 遵循分层架构(Router → Service → Repository)
- [ ] 配置支持热重载(如适用)
- [ ] 后台任务已正确调度

---

Happy Coding! 🐍


================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing Guide

**Language**: [English](CONTRIBUTING.md) | [中文](CONTRIBUTING_CN.md)

> ⚠️ **Important**: Before starting to contribute, please read and configure the [**Pre-commit Guide**](PRE_COMMIT_GUIDE.md). Pre-commit automatically runs code checks and formatting on every `git commit` to ensure code quality and style consistency. This is an essential tool for maintaining code quality in the project, please complete the installation and configuration.

## 🎉 Welcome Contributors

Thank you for your interest in the FreeTodo project! We welcome and appreciate any form of contribution. Whether you're fixing a typo, reporting a bug, or proposing a major new feature, we're grateful.

## 📋 Table of Contents

- [Getting Started](#-getting-started)
- [Development Setup](#️-development-setup)
- [Git Flow Workflow](#-git-flow-workflow)
- [Contribution Workflow](#-contribution-workflow)
- [Coding Standards](#-coding-standards)
- [Commit Message Guidelines](#-commit-message-guidelines)
- [Pull Request Guidelines](#-pull-request-guidelines)
- [Reporting Issues](#-reporting-issues)
- [Community](#-community)

### Finding Tasks

1. **Browse Issues**: Check the [Issues page](https://github.com/FreeU-group/FreeTodo/issues)
2. **Look for Labels**:
   - `good first issue` - Simple tasks for beginners
   - `help wanted` - Tasks that need help
   - `bug` - Bug fixes
   - `enhancement` - New features
   - `documentation` - Documentation improvements
3. **Propose Ideas**: Create an Issue for discussion if you have new ideas

### Types of Contributions

#### 🐛 Bug Reports

- Use the Bug Report template
- Provide detailed reproduction steps
- Include environment information
- Provide screenshots or logs if possible

#### 💡 Feature Requests

- Use the Feature Request template
- Clearly describe the purpose and value
- Provide usage scenarios
- Consider technical feasibility

#### 📝 Documentation

- Fix errors in documentation
- Add missing documentation
- Improve code comments
- Translate documentation

#### 🧪 Testing

- Increase test coverage
- Fix failing tests
- Add edge case tests

#### 🔧 Code Contributions

- Fix bugs
- Implement new features
- Performance optimization
- Code refactoring

## 🛠️ Development Setup

### Prerequisites

#### Backend Development

- Python 3.12
- [uv](https://github.com/astral-sh/uv) package manager
- Git

#### Frontend Development

- Node.js 20+
- pnpm package manager
- Git

### Clone Repository

```bash
# Clone your forked repository
git clone https://github.com/YOUR_USERNAME/FreeTodo.git
cd FreeTodo

# Add upstream repository
git remote add upstream https://github.com/FreeU-group/FreeTodo.git
```

### Configure Git Hooks (Pre-commit)

This repo uses a shared `.githooks/` directory. Run the setup script once per clone/worktree:

```bash
# macOS/Linux
bash scripts/setup_hooks_here.sh

# Windows (PowerShell)
powershell -ExecutionPolicy Bypass -File scripts/setup_hooks_here.ps1
```

> **Note**: Do not run `pre-commit install` here. The repo uses `core.hooksPath` and `pre-commit install` will refuse when it is set.

### Backend Setup

```bash
# Install uv (if not already installed)
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# Install dependencies
uv sync

# Activate virtual environment
# macOS/Linux
source .venv/bin/activate

# Windows
.venv\Scripts\activate

# Start backend service
python -m lifetrace.server
```

### Frontend Setup

```bash
# Navigate to frontend directory
cd free-todo-frontend

# Install pnpm (if not already installed)
npm install -g pnpm

# Install dependencies
pnpm install

# Start development server
pnpm dev
```

### Verify Setup

1. Backend should start searching for an available port from `8001` (default runs on `http://localhost:8001`)
2. Frontend should start searching for an available port from `3001` (default runs on `http://localhost:3001`)
3. Frontend automatically detects the running backend port by checking the `/health` endpoint
4. The actual ports used will be displayed in the console
5. Visit the API documentation address shown in the console (usually `http://localhost:8001/docs`) to view the API docs
6. Visit the frontend address shown in the console (usually `http://localhost:3001`) to view the frontend interface

> **Note**: If a port is occupied, both frontend and backend will automatically search for the next available port. The console will display the actual port used.

## 🌿 Git Flow Workflow

FreeTodo project adopts a standardized Git Flow branch management strategy to ensure code quality and standardized development processes.

### Branch Structure

We maintain the following branches:

- **`main`** - Production environment branch, contains the most stable code, directly deployable
- **`dev`** - Development environment branch for daily development and feature integration
- **`test`** - Testing environment branch for complete integration testing
- **`feat/*`** - Feature development branches, created from `dev`
- **`fix/*`** - Bug fix branches, created from `dev`, `test`, or `main`
- **`hotfix/*`** - Emergency fix branches, created from `main`

### Detailed Workflow

For complete documentation on Git Flow, including branch strategy, workflow, naming conventions, common scenarios, and best practices, please refer to:

📖 **[Git Flow Workflow Documentation](GIT_FLOW.md)**

This documentation includes:

- 🌳 Complete branch strategy explanation
- 🔄 Detailed workflows for various scenarios
- 📝 Branch naming conventions
- 🎯 Common development scenario examples
- 💡 Best practices and tips
- ❓ FAQ
- 🚦 Workflow diagrams
- 📚 Git command cheat sheet

### Quick Start

If you're already familiar with Git Flow, here's a quick reference:

```bash
# 1. Create feature branch from dev
git checkout dev
git pull origin dev
git checkout -b feat/your-feature-name

# 2. Develop and commit
git add .
git commit -m "feat: your feature description"

# 3. Push and create PR
git push origin feat/your-feature-name
# Create PR to dev branch on GitHub
```

## 📝 Contribution Workflow

### 1. Create Branch

Always create a new branch from the latest `main`:

```bash
# Update local main branch
git checkout main
git pull upstream main

# Create new branch
git checkout -b feat/your-feature-name
# or
git checkout -b fix/your-bug-fix
```

Branch naming conventions:

- `feat/xxx` - New features
- `fix/xxx` - Bug fixes
- `docs/xxx` - Documentation updates
- `refactor/xxx` - Code refactoring
- `test/xxx` - Test related
- `chore/xxx` - Build tools or auxiliary changes

### 2. Make Changes

- Follow project coding standards
- Write clear code comments
- Ensure code runs correctly
- Add or update relevant tests
- Update relevant documentation

### 3. Commit Changes

```bash
# Add changed files
git add .

# Commit changes (follow commit message guidelines)
git commit -m "feat: add new feature"

# Push to your fork
git push origin feat/your-feature-name
```

### 4. Create Pull Request

1. Visit your fork on GitHub
2. Click "Compare & pull request"
3. Fill out the PR template
4. Wait for review and feedback

## 📐 Coding Standards

### Backend Standards (Python)

For detailed backend guidelines, see: [**Backend Development Guidelines**](BACKEND_GUIDELINES.md)

**Key Points**:

- Follow PEP 8 style guide
- Use type annotations (Type Hints)
- Functions and classes need docstrings
- Use Ruff for linting and formatting
- Line length limit: 100 characters

**Quick Check**:

```bash
# Run linting
uv run ruff check .

# Auto-format code
uv run ruff format .
```

### Frontend Standards (TypeScript/React)

For detailed frontend guidelines, see: [**Frontend Development Guidelines**](FRONTEND_GUIDELINES.md)

**Key Points**:

- Use TypeScript strict mode
- Follow React Hooks best practices
- Use functional components
- Use ESLint for linting
- Use Tailwind CSS for styling

**Quick Check**:

```bash
cd free-todo-frontend

# Run ESLint
pnpm lint

# Build test
pnpm build
```

## 💬 Commit Message Guidelines

We use [Conventional Commits](https://www.conventionalcommits.org/) specification.

### Format

```
<type>(<scope>): <subject>

<body>

<footer>
```

### Type

- `feat`: New feature
- `fix`: Bug fix
- `docs`: Documentation updates
- `style`: Code formatting (no code logic changes)
- `refactor`: Refactoring (neither new features nor bug fixes)
- `perf`: Performance optimization
- `test`: Adding tests
- `chore`: Build process or auxiliary tool changes
- `ci`: CI configuration changes
- `revert`: Revert previous commit

### Scope (Optional)

- `backend`: Backend related
- `frontend`: Frontend related
- `api`: API related
- `ui`: UI related
- `db`: Database related
- `config`: Configuration related

### Examples

```bash
# New feature
git commit -m "feat(frontend): add dark mode toggle button"

# Bug fix
git commit -m "fix(backend): resolve screenshot capture error on Windows"

# Documentation update
git commit -m "docs: update installation guide"

# Performance optimization
git commit -m "perf(api): improve vector search performance"

# Multi-line commit message
git commit -m "feat(backend): add task auto-association

- Implement background job for task context mapping
- Add configuration options for auto-association
- Update API endpoints to support new feature

Closes #123"
```

## 🔍 Pull Request Guidelines

### PR Title

PR titles should follow the same convention as commit messages:

```
<type>(<scope>): <description>
```

### PR Description Template

```markdown
## 📝 Description
<!-- Briefly describe the purpose and content of this PR -->

## 🔗 Related Issues
<!-- Link related issues, e.g., Closes #123 -->

## 🎯 Type of Change
<!-- Check applicable options -->
- [ ] Bug fix
- [ ] New feature
- [ ] Performance optimization
- [ ] Code refactoring
- [ ] Documentation update
- [ ] Test related
- [ ] Other (please specify)

## 🧪 Testing
<!-- Describe how to test these changes -->
- [ ] Tested locally
- [ ] Added unit tests
- [ ] Added integration tests
- [ ] Updated documentation

## 📸 Screenshots (if applicable)
<!-- Provide screenshots for UI-related changes -->

## ✅ Checklist
- [ ] Code follows project coding standards
- [ ] Performed self-review of code
- [ ] Code has appropriate comments
- [ ] Updated relevant documentation
- [ ] Changes generate no new warnings
- [ ] Added tests proving fix/feature works
- [ ] New and existing unit tests pass locally
- [ ] Dependent changes have been merged

## 📚 Additional Notes
<!-- Any other information reviewers should know -->
```

### Review Process

1. **Automated Checks**: CI/CD runs tests and checks
2. **Code Review**: Maintainers review your code
3. **Feedback**: Address feedback and make changes
4. **Merge**: After approval, maintainers merge your PR

### Review Standards

- ✅ Code quality and readability
- ✅ Follow project coding standards
- ✅ Feature completeness
- ✅ Test coverage
- ✅ Documentation completeness
- ✅ Performance impact
- ✅ Backward compatibility

## 🐛 Reporting Issues

### Bug Reports

When creating a bug report, include:

1. **Issue Description**: Clear and concise description
2. **Reproduction Steps**: Step-by-step instructions
3. **Expected Behavior**: What you expected to happen
4. **Actual Behavior**: What actually happened
5. **Environment Information**:
   - OS: [e.g., Windows 11, macOS 13.0, Ubuntu 22.04]
   - Python Version: [e.g., 3.12.0]
   - Node.js Version: [e.g., 20.0.0]
   - Browser: [e.g., Chrome 120.0]
6. **Screenshots/Logs**: If applicable
7. **Additional Context**: Any other relevant information

### Feature Requests

When creating a feature request, include:

1. **Feature Description**: Clear description of the feature
2. **Problem Context**: What problem does it solve?
3. **Proposed Solution**: How do you expect it to work?
4. **Alternatives**: Other solutions you've considered
5. **Use Cases**: Specific usage examples
6. **Additional Context**: Any other relevant information

## 💬 Community

### Getting Help

- **GitHub Issues**: Report issues and request features
- **GitHub Discussions**: Participate in community discussions
- **WeChat Group**: Join our WeChat group (see README)
- **Feishu Group**: Join our Feishu group (see README)

### Stay Connected

- 🌟 Star the project to show support
- 👀 Watch the repository for updates
- 🐦 Share the project on social media
- 📝 Write blog posts about the project

## 🎓 Learning Resources

### Backend

- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [SQLAlchemy Documentation](https://docs.sqlalchemy.org/)
- [Pydantic Documentation](https://docs.pydantic.dev/)
- [Python Type Hints](https://docs.python.org/3/library/typing.html)

### Frontend

- [Next.js Documentation](https://nextjs.org/docs)
- [React Documentation](https://react.dev/)
- [TypeScript Documentation](https://www.typescriptlang.org/docs/)
- [Tailwind CSS Documentation](https://tailwindcss.com/docs)

### Git

- [FreeTodo Git Flow Workflow](GIT_FLOW.md) - Project-specific Git workflow documentation
- [Git Guide](https://rogerdudler.github.io/git-guide/)
- [Git and GitHub Tutorial](https://www.freecodecamp.org/news/git-and-github-for-beginners/)

## 📊 Contributors

Thanks to all the people who have contributed to FreeTodo!

![Contributors](https://contrib.rocks/image?repo=FreeU-group/FreeTodo)

## ❓ FAQ

### I'm new to programming. Can I contribute?

Absolutely! We welcome contributors of all levels. You can start with:

- Fixing typos in documentation
- Improving documentation and comments
- Working on `good first issue` labeled issues
- Reporting bugs and suggesting improvements

### How long until my PR is reviewed?

We try to review PRs as quickly as possible, typically within 3-7 days. If there's no response after a week, please comment on your PR to remind us.

### Can I work on multiple issues at once?

Yes, but we recommend focusing on one issue at a time to ensure quality and efficiency.

### How do I keep my fork in sync with upstream?

```bash
# Fetch upstream updates
git fetch upstream

# Merge into local main branch
git checkout main
git merge upstream/main

# Push to your fork
git push origin main
```

### What if my PR is rejected?

Don't be discouraged! This is a normal part of the development process. Maintainers will provide feedback and suggestions. Address the feedback, or seek clarification in the discussion.

## 📜 License

FreeTodo is licensed under the **FreeU Community License**, which is based on Apache License 2.0 with additional terms regarding commercial use.

By contributing code, you agree:

1. **Your contributions will be licensed under the FreeU Community License**
   - This license is based on Apache License 2.0, with additional commercial use terms
   - For detailed license terms, please refer to the [LICENSE](../LICENSE) file

2. **As a contributor, you agree that:**
   - The producer may adjust the open source license as needed (making it more strict or more permissive)
   - Your contributed code may be used for commercial purposes, including but not limited to cloud versions

For detailed license terms and contributor conditions, please refer to the [LICENSE](../LICENSE) file.

---

## 🙏 Thanks

Thank you for taking the time to read our contribution guidelines! We look forward to your contributions to make FreeTodo better!

If you have any questions, feel free to ask in Issues or join our community groups.

Happy Coding! 🎉


================================================
FILE: .github/CONTRIBUTING_CN.md
================================================
# 贡献指南

**语言**: [English](CONTRIBUTING.md) | [中文](CONTRIBUTING_CN.md)

> ⚠️ **重要提示**:在开始贡献之前,请务必阅读并配置 [**Pre-commit 使用指南**](PRE_COMMIT_GUIDE_CN.md)。Pre-commit 会在每次 `git commit` 时自动运行代码检查和格式化,确保代码质量和风格一致性。这是项目代码质量保障的重要工具,请务必完成安装和配置。

## 🎉 欢迎贡献

感谢您对 FreeTodo 项目的关注!我们非常欢迎并感谢任何形式的贡献。无论您是修复一个拼写错误、报告一个 bug,还是提出一个重大的新功能,我们都非常感激。

## 📋 目录

- [如何开始贡献](#-如何开始贡献)
- [开发环境设置](#️-开发环境设置)
- [Git Flow 工作流程](#-git-flow-工作流程)
- [贡献流程](#-贡献流程)
- [编码规范](#-编码规范)
- [提交信息规范](#-提交信息规范)
- [Pull Request 指南](#-pull-request-指南)
- [报告问题](#-报告问题)
- [社区讨论](#-社区讨论)

## 🚀 如何开始贡献

### 寻找合适的任务

1. **浏览 Issues**:查看 [Issues 页面](https://github.com/FreeU-group/FreeTodo/issues)
2. **查找标签**:
   - `good first issue` - 适合新手的简单任务
   - `help wanted` - 需要帮助的任务
   - `bug` - Bug 修复
   - `enhancement` - 新功能
   - `documentation` - 文档改进
3. **提出想法**:如果有新的想法,先创建一个 Issue 进行讨论

### 贡献类型

#### 🐛 报告 Bug

- 使用 Bug 报告模板
- 提供详细的复现步骤
- 包含环境信息(操作系统、Python 版本、Node.js 版本等)
- 如果可能,提供截图或日志

#### 💡 功能建议

- 使用功能请求模板
- 清晰描述功能的目的和价值
- 提供使用场景示例
- 考虑技术可行性

#### 📝 改进文档

- 修复文档中的错误
- 添加缺失的文档
- 改进代码注释
- 翻译文档

#### 🧪 编写测试

- 增加测试覆盖率
- 修复失败的测试
- 添加边界情况测试

#### 🔧 代码贡献

- 修复 Bug
- 实现新功能
- 性能优化
- 代码重构

## 🛠️ 开发环境设置

### 先决条件

#### 后端开发

- Python 3.12
- [uv](https://github.com/astral-sh/uv) 包管理器
- Git

#### 前端开发

- Node.js 20+
- pnpm 包管理器
- Git

### 克隆仓库

```bash
# 克隆您 fork 的仓库
git clone https://github.com/YOUR_USERNAME/FreeTodo.git
cd FreeTodo

# 添加上游仓库
git remote add upstream https://github.com/FreeU-group/FreeTodo.git
```

### 配置 Git Hooks(Pre-commit)

本仓库使用共享的 `.githooks/` 目录。每个 clone/worktree 只需执行一次:

```bash
# macOS/Linux
bash scripts/setup_hooks_here.sh

# Windows(PowerShell)
powershell -ExecutionPolicy Bypass -File scripts/setup_hooks_here.ps1
```

> **注意**:不要运行 `pre-commit install`。仓库使用 `core.hooksPath`,因此 `pre-commit install` 会拒绝执行。

### 后端设置

```bash
# 安装 uv(如果还没有安装)
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

# 安装依赖
uv sync

# 激活虚拟环境
# macOS/Linux
source .venv/bin/activate

# Windows
.venv\Scripts\activate

# 启动后端服务
python -m lifetrace.server
```

### 前端设置

```bash
# 进入前端目录
cd frontend

# 安装 pnpm(如果还没有安装)
npm install -g pnpm

# 安装依赖
pnpm install

# 启动开发服务器
pnpm dev
```

### 验证设置

1. 后端应该从 `8001` 端口开始查找可用端口(默认运行在 `http://localhost:8001`)
2. 前端应该从 `3001` 端口开始查找可用端口(默认运行在 `http://localhost:3001`)
3. 前端会自动通过检查 `/health` 端点检测运行中的后端端口
4. 实际使用的端口会在控制台显示
5. 访问控制台显示的 API 文档地址(通常为 `http://localhost:8001/docs`)查看 API 文档
6. 访问控制台显示的前端地址(通常为 `http://localhost:3001`)查看前端界面

> **注意**:如果端口被占用,前端和后端都会自动查找下一个可用端口。控制台会显示实际使用的端口。

## 🌿 Git Flow 工作流程

FreeTodo 项目采用规范的 Git Flow 分支管理策略,以确保代码质量和开发流程的规范性。

### 分支结构

我们维护以下分支:

- **`main`** - 生产环境分支,包含最稳定的代码,可直接部署
- **`dev`** - 开发环境分支,用于日常开发和功能集成
- **`test`** - 测试环境分支,用于完整的集成测试
- **`feat/*`** - 功能开发分支,从 `dev` 创建
- **`fix/*`** - Bug 修复分支,从 `dev`、`test` 或 `main` 创建
- **`hotfix/*`** - 紧急修复分支,从 `main` 创建

### 详细工作流程

关于 Git Flow 的完整说明,包括分支策略、工作流程、命名规范、常见场景和最佳实践,请参考:

📖 **[Git Flow 工作流程详细文档](GIT_FLOW_CN.md)**

该文档包含:

- 🌳 完整的分支策略说明
- 🔄 各种场景的详细工作流程
- 📝 分支命名规范
- 🎯 常见开发场景示例
- 💡 最佳实践和技巧
- ❓ 常见问题解答
- 🚦 工作流程图
- 📚 Git 命令速查表

### 快速开始

如果您已经熟悉 Git Flow,以下是快速参考:

```bash
# 1. 从 dev 创建功能分支
git checkout dev
git pull origin dev
git checkout -b feat/your-feature-name

# 2. 开发并提交
git add .
git commit -m "feat: your feature description"

# 3. 推送并创建 PR
git push origin feat/your-feature-name
# 在 GitHub 上创建 PR 到 dev 分支
```

## 📝 贡献流程

### 1. 创建分支

始终从最新的 `main` 分支创建新分支:

```bash
# 更新本地 main 分支
git checkout main
git pull upstream main

# 创建新分支
git checkout -b feat/your-feature-name
# 或
git checkout -b fix/your-bug-fix
```

分支命名规范:

- `feat/xxx` - 新功能
- `fix/xxx` - Bug 修复
- `docs/xxx` - 文档更新
- `refactor/xxx` - 代码重构
- `test/xxx` - 测试相关
- `chore/xxx` - 构建工具或辅助工具的变动

### 2. 进行更改

- 遵循项目的编码规范(见下文)
- 编写清晰的代码注释
- 确保代码可以正常运行
- 添加或更新相关测试
- 更新相关文档

### 3. 提交更改

```bash
# 添加更改的文件
git add .

# 提交更改(遵循提交信息规范)
git commit -m "feat: add new feature"

# 推送到您的 fork
git push origin feat/your-feature-name
```

### 4. 创建 Pull Request

1. 访问您的 fork 在 GitHub 上的页面
2. 点击 "Compare & pull request" 按钮
3. 填写 PR 模板
4. 等待审查和反馈

## 📐 编码规范

### 后端规范(Python)

详细的后端开发规范请参考:[**后端开发规范**](BACKEND_GUIDELINES_CN.md)

**核心要点**:

- 遵循 PEP 8 风格指南
- 使用类型注解(Type Hints)
- 函数和类需要有文档字符串
- 使用 Ruff 进行代码检查和格式化
- 行长度限制为 100 个字符

**快速检查**:

```bash
# 运行代码检查
uv run ruff check .

# 自动格式化代码
uv run ruff format .
```

### 前端规范(TypeScript/React)

详细的前端开发规范请参考:[**前端开发规范**](FRONTEND_GUIDELINES_CN.md)

**核心要点**:

- 使用 TypeScript 严格模式
- 遵循 React Hooks 最佳实践
- 组件使用函数式组件
- 使用 ESLint 进行代码检查
- 使用 Tailwind CSS 进行样式管理

**快速检查**:

```bash
cd frontend

# 运行 ESLint 检查
pnpm lint

# 构建测试
pnpm build
```

## 💬 提交信息规范

我们使用 [Conventional Commits](https://www.conventionalcommits.org/) 规范。

### 格式

```
<type>(<scope>): <subject>

<body>

<footer>
```

### Type 类型

- `feat`: 新功能
- `fix`: Bug 修复
- `docs`: 文档更新
- `style`: 代码格式(不影响代码运行的变动)
- `refactor`: 重构(既不是新增功能,也不是修改 bug 的代码变动)
- `perf`: 性能优化
- `test`: 增加测试
- `chore`: 构建过程或辅助工具的变动
- `ci`: CI 配置文件和脚本的变动
- `revert`: 回滚之前的提交

### Scope 范围(可选)

- `backend`: 后端相关
- `frontend`: 前端相关
- `api`: API 相关
- `ui`: UI 相关
- `db`: 数据库相关
- `config`: 配置相关

### 示例

```bash
# 新功能
git commit -m "feat(frontend): add dark mode toggle button"

# Bug 修复
git commit -m "fix(backend): resolve screenshot capture error on Windows"

# 文档更新
git commit -m "docs: update installation guide"

# 性能优化
git commit -m "perf(api): improve vector search performance"

# 多行提交信息
git commit -m "feat(backend): add task auto-association

- Implement background job for task context mapping
- Add configuration options for auto-association
- Update API endpoints to support new feature

Closes #123"
```

## 🔍 Pull Request 指南

### PR 标题

PR 标题应该遵循与提交信息相同的规范:

```
<type>(<scope>): <description>
```

### PR 描述模板

```markdown
## 📝 描述
<!-- 简要描述本 PR 的目的和内容 -->

## 🔗 相关 Issue
<!-- 关联相关的 Issue,例如:Closes #123 -->

## 🎯 变更类型
<!-- 在适用的选项前打勾 -->
- [ ] Bug 修复
- [ ] 新功能
- [ ] 性能优化
- [ ] 代码重构
- [ ] 文档更新
- [ ] 测试相关
- [ ] 其他(请说明)

## 🧪 测试
<!-- 描述如何测试这些更改 -->
- [ ] 已在本地测试
- [ ] 已添加单元测试
- [ ] 已添加集成测试
- [ ] 已更新文档

## 📸 截图(如适用)
<!-- 如果是 UI 相关的更改,请提供截图 -->

## ✅ 检查清单
- [ ] 代码遵循项目的编码规范
- [ ] 已进行自我代码审查
- [ ] 代码有适当的注释
- [ ] 已更新相关文档
- [ ] 我的更改没有产生新的警告
- [ ] 已添加证明修复有效或功能正常的测试
- [ ] 新的和现有的单元测试在本地通过
- [ ] 任何依赖的更改已经合并和发布

## 📚 额外说明
<!-- 任何其他需要审查者知道的信息 -->
```

### 审查流程

1. **自动检查**:CI/CD 会自动运行测试和检查
2. **代码审查**:维护者会审查您的代码
3. **反馈处理**:根据反馈进行修改
4. **合并**:通过审查后,维护者会合并您的 PR

### 审查标准

- ✅ 代码质量和可读性
- ✅ 遵循项目编码规范
- ✅ 功能完整性
- ✅ 测试覆盖率
- ✅ 文档完整性
- ✅ 性能影响
- ✅ 向后兼容性

## 🐛 报告问题

### Bug 报告

创建 Bug 报告时,请包含以下信息:

1. **问题描述**:清晰简洁地描述问题
2. **复现步骤**:
   - 第一步
   - 第二步
   - ...
3. **期望行为**:描述您期望发生什么
4. **实际行为**:描述实际发生了什么
5. **环境信息**:
   - 操作系统:[例如 Windows 11, macOS 13.0, Ubuntu 22.04]
   - Python 版本:[例如 3.12.9]
   - Node.js 版本:[例如 18.17.0]
   - 浏览器:[例如 Chrome 120.0]
6. **截图或日志**:如果适用,添加截图或日志信息
7. **附加信息**:任何其他相关的上下文信息

### 功能请求

创建功能请求时,请包含以下信息:

1. **功能描述**:清晰描述您想要的功能
2. **问题背景**:这个功能解决什么问题?
3. **建议的解决方案**:您期望如何实现这个功能?
4. **替代方案**:您考虑过的其他解决方案
5. **使用场景**:提供具体的使用示例
6. **附加信息**:任何其他相关的上下文或截图

## 💬 社区讨论

### 获取帮助

- **GitHub Issues**:报告问题和提出功能请求
- **GitHub Discussions**:参与社区讨论
- **微信群**:加入我们的微信群(见 README)
- **飞书群**:加入我们的飞书群(见 README)

### 保持联系

- 🌟 给项目点 Star 以表示支持
- 👀 Watch 仓库以获取更新通知
- 🐦 在社交媒体上分享项目
- 📝 撰写博客文章介绍项目

## 🎓 学习资源

### 后端相关

- [FastAPI 文档](https://fastapi.tiangolo.com/)
- [SQLAlchemy 文档](https://docs.sqlalchemy.org/)
- [Pydantic 文档](https://docs.pydantic.dev/)
- [Python 类型注解](https://docs.python.org/3/library/typing.html)

### 前端相关

- [Next.js 文档](https://nextjs.org/docs)
- [React 文档](https://react.dev/)
- [TypeScript 文档](https://www.typescriptlang.org/docs/)
- [Tailwind CSS 文档](https://tailwindcss.com/docs)

### Git 相关

- [FreeTodo Git Flow 工作流程](GIT_FLOW_CN.md) - 项目专用 Git 工作流程文档
- [Git 简明教程](https://rogerdudler.github.io/git-guide/index.zh.html)
- [如何使用 Git 和 GitHub](https://www.freecodecamp.org/chinese/news/git-and-github-for-beginners/)

## 📊 贡献者统计

感谢所有为 FreeTodo 做出贡献的人!

![Contributors](https://contrib.rocks/image?repo=FreeU-group/FreeTodo)

## ❓ 常见问题

### 我是编程新手,可以贡献吗?

当然可以!我们欢迎所有级别的贡献者。您可以从以下方面开始:

- 修复文档中的拼写错误
- 改进文档和注释
- 处理标记为 `good first issue` 的问题
- 报告 Bug 和提出建议

### 我的 PR 需要多长时间才能被审查?

我们会尽快审查 PR,通常在 3-7 天内。如果超过一周没有响应,请在 PR 中留言提醒我们。

### 我可以同时处理多个 Issue 吗?

可以,但建议先专注于一个 Issue,完成后再开始下一个。这样可以确保工作质量和效率。

### 如何保持我的 Fork 与上游同步?

```bash
# 获取上游更新
git fetch upstream

# 合并到本地 main 分支
git checkout main
git merge upstream/main

# 推送到您的 fork
git push origin main
```

### 我的 PR 被拒绝了怎么办?

不要灰心!这是正常的开发流程。维护者会提供反馈和建议。根据反馈进行修改,或者在讨论中寻求澄清。

## 📜 许可证

FreeTodo 采用 **FreeU Community License** 许可证,该许可证基于 Apache License 2.0,并附加了关于商业使用的条件。

通过贡献代码,您同意:

1. **您的贡献将在 FreeU Community License 下许可**
   - 该许可证基于 Apache License 2.0,同时包含额外的商业使用条款
   - 有关详细的许可证条款,请参阅 [LICENSE](../LICENSE) 文件

2. **作为贡献者,您同意:**
   - 生产者可以根据需要调整开源协议(使其更严格或更宽松)
   - 您贡献的代码可能用于商业目的,包括但不限于其云版本

有关详细的许可证条款和贡献者条件,请参阅 [LICENSE](../LICENSE) 文件。

---

## 🙏 感谢

感谢您花时间阅读我们的贡献指南!我们期待您的贡献,让 FreeTodo 变得更好!

如果您有任何问题,请随时在 Issues 中提问或加入我们的社区群组。

Happy Coding! 🎉


================================================
FILE: .github/FRONTEND_GUIDELINES.md
================================================
# Frontend Development Guidelines

**Language**: [English](FRONTEND_GUIDELINES.md) | [中文](FRONTEND_GUIDELINES_CN.md)

## ⚛️ React + TypeScript Frontend Development Standards

This document details the development standards and best practices for the FreeTodo project frontend (Next.js + React + TypeScript).

### Tech Stack

- **Framework**: Next.js 16 + React 19 (App Router)
- **Language**: Node.js 22.x + TypeScript 5.x
- **Styling**: Tailwind CSS 4 + shadcn/ui
- **State Management**: Zustand + React Hooks
- **Data Fetching**: TanStack Query (React Query) v5
- **API Generation**: Orval (auto-generate from OpenAPI)
- **Data Validation**: Zod (runtime type validation)
- **Theming**: next-themes (light/dark mode toggle)
- **Animation/Interaction**: framer-motion, @dnd-kit
- **Markdown**: react-markdown + remark-gfm
- **Icons**: lucide-react
- **Internationalization**: next-intl
- **Package Manager**: pnpm 10.x
- **Code Quality**: Biome (lint/format/check)

## 📋 Table of Contents

- [Code Style](#-code-style)
- [Project Structure](#️-project-structure)
- [Naming Conventions](#-naming-conventions)
- [TypeScript Standards](#-typescript-standards)
- [React Component Standards](#️-react-component-standards)
- [State Management](#-state-management)
- [API Calls](#-api-calls)
- [Internationalization](#-internationalization)
- [Styling](#-styling)
- [Performance](#-performance)
- [Testing](#-testing)
- [Accessibility](#-accessibility)
- [Security](#-security)

## 🎨 Code Style

### Biome Configuration

The project uses [Biome](https://biomejs.dev/) as the linter, formatter, and type checker.

```bash
# Check code
pnpm lint

# Auto-fix issues
pnpm lint --fix

# Format code
pnpm format

# Type check
pnpm typecheck

# Build test
pnpm build
```

### Basic Rules

#### Indentation and Formatting

```typescript
// ✅ Correct: Use 2 spaces
function MyComponent() {
  const [count, setCount] = useState(0);

  if (count > 0) {
    return <div>Count: {count}</div>;
  }

  return null;
}

// ❌ Wrong: Use 4 spaces or tabs
function MyComponent() {
    const [count, setCount] = useState(0);
    return <div>Count: {count}</div>;
}
```

#### Quotes and Semicolons

```typescript
// ✅ Correct: Use double quotes, no semicolons
const message = "Hello, World!"
const name = "Alice"

// ❌ Wrong: Use single quotes and semicolons
const message = 'Hello, World!';
```

#### Imports

```typescript
// ✅ Correct: Import order and grouping
// 1. React and Next.js core
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import Image from "next/image"

// 2. Third-party libraries
import axios from "axios"
import clsx from "clsx"

// 3. Internal components
import { Button } from "@/components/common/Button"
import { Card } from "@/components/common/Card"

// 4. Utils and types
import { api } from "@/lib/api"
import type { Task } from "@/lib/types"

// 5. Styles
import styles from "./page.module.css"

// ❌ Wrong: Mixed order
import { Button } from "@/components/common/Button"
import { useState } from "react"
import axios from "axios"
```

## 🏗️ Project Structure

```
free-todo-frontend/
├── app/                      # Next.js App Router
│   ├── layout.tsx           # Root layout
│   ├── page.tsx             # Home page
│   └── apps/                # Feature pages
│       ├── todo-list/       # Todo list
│       ├── todo-detail/     # Todo detail
│       └── [feature]/       # Other features
├── components/              # React components
│   ├── common/             # Common components
│   ├── layout/             # Layout components
│   └── [feature]/          # Feature components
├── lib/                    # Utilities
│   ├── api.ts             # API client (streaming APIs)
│   ├── generated/         # Orval-generated API code
│   │   ├── [module]/      # Split by feature modules
│   │   ├── fetcher.ts     # Custom Fetcher
│   │   └── schemas/       # Zod schemas
│   ├── query/             # TanStack Query hooks wrapper
│   │   └── keys.ts        # Query Keys management
│   ├── types/             # Unified type definitions (camelCase)
│   ├── store/             # Zustand state management
│   ├── hooks/             # Custom Hooks
│   └── utils.ts           # Utility functions
├── messages/              # Internationalization files
│   ├── zh.json            # Chinese translations
│   └── en.json            # English translations
└── public/                # Static assets
```

## 📝 Naming Conventions

### File Naming

```
# ✅ Correct: Components use PascalCase
Button.tsx
TaskCard.tsx
UserProfile.tsx

# ✅ Correct: Non-components use camelCase
api.ts
utils.ts
use-tasks.ts

# ❌ Wrong: Inconsistent naming
button.tsx
task_card.tsx
```

### Component Naming

```typescript
// ✅ Correct: PascalCase
export function TaskCard() {}
export function UserProfile() {}
export default function HomePage() {}

// ❌ Wrong: camelCase
export function taskCard() {}
```

### Variables and Functions

```typescript
// ✅ Correct: camelCase
const userName = "Alice"
const taskCount = 10

function getUserProfile() {}
function calculateTotal() {}

// ❌ Wrong: PascalCase or snake_case
const UserName = "Alice"
const task_count = 10
```

### Constants

```typescript
// ✅ Correct: UPPER_SNAKE_CASE
const MAX_RETRY_COUNT = 3
const API_BASE_URL = "https://api.example.com"
const DEFAULT_PAGE_SIZE = 10

// ❌ Wrong: camelCase
const maxRetryCount = 3
```

### Hooks

```typescript
// ✅ Correct: Start with "use"
function useTasks() {}
function useUser() {}
function useDebounce() {}

// ❌ Wrong: No "use" prefix
function getTasks() {}
```

### Event Handlers

```typescript
// ✅ Correct: Use "handle" prefix
function handleClick() {}
function handleSubmit() {}
function handleChange(e: ChangeEvent<HTMLInputElement>) {}

// ✅ Correct: Callback props use "on" prefix
<Button onClick={handleClick} />
<Input onChange={handleChange} />
```

## 🔤 TypeScript Standards

### Enable Strict Mode

```json
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}
```

### Type Definitions

```typescript
// ✅ Correct: Define clear types
interface Task {
  id: number
  title: string
  description: string | null
  status: "pending" | "in_progress" | "completed"
  priority: number
  createdAt: string
  updatedAt: string
}

type TaskStatus = "pending" | "in_progress" | "completed"

// ❌ Wrong: Use any
interface Task {
  id: number
  title: string
  data: any  // Avoid any
}
```

### Component Props

```typescript
// ✅ Correct: Define Props interface
interface TaskCardProps {
  task: Task
  onEdit?: (task: Task) => void
  onDelete?: (taskId: number) => void
  className?: string
}

export function TaskCard({
  task,
  onEdit,
  onDelete,
  className
}: TaskCardProps) {
  // Component implementation
}

// ✅ Correct: Use generics
interface ListProps<T> {
  items: T[]
  renderItem: (item: T) => React.ReactNode
  keyExtractor: (item: T) => string | number
}

export function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <div>
      {items.map(item => (
        <div key={keyExtractor(item)}>
          {renderItem(item)}
        </div>
      ))}
    </div>
  )
}
```

## ⚛️ React Component Standards

### Function Components

```typescript
// ✅ Correct: Use function components
interface UserProfileProps {
  user: User
  onUpdate: (user: User) => void
}

export function UserProfile({ user, onUpdate }: UserProfileProps) {
  const [isEditing, setIsEditing] = useState(false)

  return (
    <div>
      <h2>{user.name}</h2>
      {/* Component content */}
    </div>
  )
}

// ❌ Wrong: Use class components (unless necessary)
class UserProfile extends React.Component<UserProfileProps> {
  render() {
    return <div>{this.props.user.name}</div>
  }
}
```

### Custom Hooks

```typescript
// ✅ Correct: Create custom hooks
function useTasks() {
  const [tasks, setTasks] = useState<Task[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    fetchTasks()
  }, [])

  const fetchTasks = async () => {
    setLoading(true)
    setError(null)
    try {
      const response = await api.get<Task[]>("/api/tasks")
      setTasks(response.data)
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to fetch tasks")
    } finally {
      setLoading(false)
    }
  }

  return { tasks, loading, error, fetchTasks }
}

// Use custom hook
function TasksPage() {
  const { tasks, loading, error } = useTasks()

  if (loading) return <div>Loading...</div>
  if (error) return <div>Error: {error}</div>

  return <TaskList tasks={tasks} />
}
```

## 🎯 State Management

### Local State (useState)

```typescript
// ✅ Correct: Use functional updates
function Counter() {
  const [count, setCount] = useState(0)

  const increment = () => setCount(prev => prev + 1)
  const decrement = () => setCount(prev => prev - 1)

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  )
}
```

### Global State (Zustand)

```typescript
// lib/store/taskStore.ts
import { create } from "zustand"

interface TaskState {
  tasks: Task[]
  loading: boolean
  error: string | null
  fetchTasks: () => Promise<void>
  createTask: (task: TaskCreate) => Promise<void>
}

export const useTaskStore = create<TaskState>((set) => ({
  tasks: [],
  loading: false,
  error: null,

  fetchTasks: async () => {
    set({ loading: true, error: null })
    try {
      const response = await api.get<Task[]>("/api/tasks")
      set({ tasks: response.data, loading: false })
    } catch (error) {
      set({ error: "Failed to fetch tasks", loading: false })
    }
  },

  createTask: async (taskData: TaskCreate) => {
    try {
      const response = await api.post<Task>("/api/tasks", taskData)
      set(state => ({ tasks: [...state.tasks, response.data] }))
    } catch (error) {
      set({ error: "Failed to create task" })
      throw error
    }
  }
}))
```

## 🌐 API Calls

The project uses **Orval + TanStack Query + Zod** for type-safe API calls and data validation.

### Orval Code Generation

- **Config file**: `orval.config.ts`
- **Generate command**: `pnpm orval` (requires backend service running)
- **Generated content**: TypeScript types, Zod schemas, React Query hooks
- **Output directory**: `lib/generated/` (split by API tags, e.g., `todos/`, `chat/`)

**Main configuration**:
- `input.target`: Backend OpenAPI schema URL (http://localhost:8001/openapi.json)
- `output.client`: Use react-query to generate hooks
- `output.mode`: tags-split by feature modules
- `override.mutator`: Use custom fetcher (`lib/generated/fetcher.ts`)
- `override.zod.strict`: Enable strict runtime validation

### Using Orval-Generated API Hooks

```typescript
// 1. Use generated hooks directly
import { useGetTodos, useCreateTodo } from "@/lib/generated/todos"

function TodoList() {
  const { data: todos, isLoading } = useGetTodos()
  const createTodo = useCreateTodo()

  // Use generated hooks
}

// 2. Wrap hooks in lib/query/ to add business logic
// lib/query/todos.ts
import { useGetTodos as useGetTodosBase } from "@/lib/generated/todos"
import { queryKeys } from "./keys"

export function useTodos() {
  return useGetTodosBase({
    query: {
      queryKey: queryKeys.todos.list(),
      staleTime: 30000, // 30 seconds cache
    },
  })
}
```

### TanStack Query Usage Guidelines

- **Query Keys**: Manage in `lib/query/keys.ts` with hierarchical structure (e.g., `todos.list()`, `todos.detail(id)`)
- **Optimistic Updates**: Update cache in `onMutate`, rollback in `onError`, refetch in `onSettled`
- **Debounced Updates**: Use 500ms debounce for frequently changing fields (e.g., description, notes)
- **Cache Strategy**: Set reasonable `staleTime` (e.g., 30 seconds) to avoid excessive requests

```typescript
// lib/query/keys.ts
export const queryKeys = {
  todos: {
    all: () => ["todos"] as const,
    lists: () => [...queryKeys.todos.all(), "list"] as const,
    list: (filters?: string) => [...queryKeys.todos.lists(), { filters }] as const,
    details: () => [...queryKeys.todos.all(), "detail"] as const,
    detail: (id: number) => [...queryKeys.todos.details(), id] as const,
  },
}
```

### Zod Data Validation

- **Generated schemas**: Located in `lib/generated/schemas/`, auto-generated by Orval
- **Runtime validation**: Automatically validate API response format in fetcher
- **Form validation**: Use with React Hook Form's `zodResolver`

### Custom Fetcher

Located in `lib/generated/fetcher.ts`, responsible for:
- Environment adaptation (client/server URL)
- **Automatic naming style conversion**:
  - Request: camelCase → snake_case (frontend style → backend style)
  - Response: snake_case → camelCase (backend style → frontend style)
- Time string normalization (handle missing timezone suffix)
- Unified error handling
- Zod schema runtime validation

### Streaming API Handling

Orval doesn't support Server-Sent Events, implement manually in `lib/api.ts`:

```typescript
// lib/api.ts
export async function sendChatMessageStream(
  message: string,
  onChunk: (chunk: string) => void
) {
  const response = await fetch(`${API_BASE_URL}/api/chat/stream`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message }),
  })

  const reader = response.body?.getReader()
  const decoder = new TextDecoder()

  if (!reader) return

  while (true) {
    const { done, value } = await reader.read()
    if (done) break

    const chunk = decoder.decode(value, { stream: true })
    onChunk(chunk)
  }
}
```

### Type Safety Best Practices

1. Prefer camelCase types from `lib/types/index.ts` (fetcher automatically converts)
2. IDs use `number` type uniformly (consistent with backend database)
3. Orval-generated types only for API layer, business layer uses unified type definitions

### Development Workflow

1. **Backend API changes**: Run `pnpm orval` to regenerate code, check `git diff lib/generated/`
2. **New API**: Backend updates OpenAPI → Generate code → Wrap in `lib/query/` → Use in components
3. **Debugging**: Add logs in fetcher to view requests/responses and validation errors

## 🌍 Internationalization

The project uses **next-intl** for internationalization, managed through Zustand store (no URL routing mode).

- **Translation files**: `messages/zh.json` and `en.json`
- **Request config**: `i18n/request.ts`
- **Language management**: `lib/store/locale.ts` (syncs to cookie on change)
- **Access method**: `useTranslations(namespace)` imported from `next-intl`

### Using Internationalization

```typescript
// ✅ Correct: Use translation hook
import { useTranslations } from "next-intl"

function TaskList() {
  const t = useTranslations("page.todo")

  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description", { count: tasks.length })}</p>
    </div>
  )
}

// ❌ Wrong: Hard-coded text
function TaskList() {
  const locale = useLocale()
  return <h1>{locale === "zh" ? "任务列表" : "Task List"}</h1>
}
```

### Adding/Modifying Translations

- Add translation keys synchronously in `messages/zh.json` and `en.json`
- Use nested structure to organize translations, e.g., `page.settings.title`
- Support ICU MessageFormat interpolation syntax, e.g., `{count}` and plural forms

## 🎨 Styling

### Tailwind CSS 4

The project uses Tailwind CSS 4 and shadcn/ui component library.

```typescript
// ✅ Correct: Use Tailwind utility classes with clsx/tailwind-merge
import { cn } from "@/lib/utils" // tailwind-merge wrapper

function Button({ children, variant = "primary", className }: ButtonProps) {
  return (
    <button
      className={cn(
        "px-4 py-2 rounded-lg font-medium transition-colors",
        variant === "primary" && "bg-blue-500 hover:bg-blue-600 text-white",
        variant === "secondary" && "bg-gray-200 hover:bg-gray-300 text-gray-800",
        className
      )}
    >
      {children}
    </button>
  )
}
```

### Dark Mode

Use `next-themes` to manage theme, use `dark:` prefix in components:

```typescript
function Card({ children }: CardProps) {
  return (
    <div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
      {children}
    </div>
  )
}
```

### shadcn/ui Components

Use shadcn/ui provided components, add via `npx shadcn@latest add [component]`:

```typescript
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"

function MyComponent() {
  return (
    <Card>
      <Button variant="default">Click</Button>
    </Card>
  )
}
```

## ⚡ Performance

### React.memo

```typescript
// ✅ Correct: Use React.memo
export const TaskCard = React.memo(function TaskCard({ task }: TaskCardProps) {
  return (
    <div>
      <h3>{task.title}</h3>
      <p>{task.description}</p>
    </div>
  )
})
```

### useCallback and useMemo

```typescript
// ✅ Correct: Use useCallback
function TaskList({ tasks }: TaskListProps) {
  const handleTaskClick = useCallback((taskId: number) => {
    console.log("Task clicked:", taskId)
  }, [])

  return (
    <div>
      {tasks.map(task => (
        <TaskCard key={task.id} task={task} onClick={handleTaskClick} />
      ))}
    </div>
  )
}

// ✅ Correct: Use useMemo
function TaskStats({ tasks }: TaskStatsProps) {
  const stats = useMemo(() => ({
    total: tasks.length,
    completed: tasks.filter(t => t.status === "completed").length,
    pending: tasks.filter(t => t.status === "pending").length
  }), [tasks])

  return (
    <div>
      <p>Total: {stats.total}</p>
      <p>Completed: {stats.completed}</p>
      <p>Pending: {stats.pending}</p>
    </div>
  )
}
```

## 🧪 Testing

```typescript
// TaskCard.test.tsx
import { render, screen, fireEvent } from "@testing-library/react"
import { TaskCard } from "./TaskCard"

describe("TaskCard", () => {
  const mockTask: Task = {
    id: 1,
    title: "Test Task",
    description: "Test Description",
    status: "pending",
    priority: 1,
    createdAt: "2024-01-01T00:00:00Z",
    updatedAt: "2024-01-01T00:00:00Z"
  }

  it("renders task title", () => {
    render(<TaskCard task={mockTask} />)
    expect(screen.getByText("Test Task")).toBeInTheDocument()
  })

  it("calls onEdit when edit button is clicked", () => {
    const handleEdit = jest.fn()
    render(<TaskCard task={mockTask} onEdit={handleEdit} />)

    fireEvent.click(screen.getByRole("button", { name: /edit/i }))
    expect(handleEdit).toHaveBeenCalledWith(mockTask)
  })
})
```

## ♿ Accessibility

### Semantic HTML

```typescript
// ✅ Correct: Use semantic tags
function TaskList({ tasks }: TaskListProps) {
  return (
    <section>
      <h2>Tasks</h2>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>
            <article>
              <h3>{task.title}</h3>
              <p>{task.description}</p>
            </article>
          </li>
        ))}
      </ul>
    </section>
  )
}

// ❌ Wrong: Overuse divs
function TaskList({ tasks }: TaskListProps) {
  return (
    <div>
      <div>Tasks</div>
      <div>
        {tasks.map(task => (
          <div key={task.id}>
            <div>{task.title}</div>
          </div>
        ))}
      </div>
    </div>
  )
}
```

### ARIA Attributes

```typescript
// ✅ Correct: Use ARIA attributes
function Button({ loading, children }: ButtonProps) {
  return (
    <button
      aria-busy={loading}
      aria-label={loading ? "Loading..." : undefined}
      disabled={loading}
    >
      {children}
    </button>
  )
}
```

## 🔒 Security

### XSS Protection

```typescript
// ✅ Correct: React auto-escapes
function TaskDescription({ description }: { description: string }) {
  return <p>{description}</p>
}

// ⚠️ Caution: Use dangerouslySetInnerHTML carefully
import DOMPurify from "dompurify"

function TaskDescription({ html }: { html: string }) {
  const sanitized = DOMPurify.sanitize(html)
  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />
}
```

### Environment Variables

```typescript
// ✅ Correct: Use environment variables
const API_URL = process.env.NEXT_PUBLIC_API_URL
// NEXT_PUBLIC_ prefix exposes to client
// Without prefix, only available on server
```

## ✅ Code Review Checklist

Before submitting code, ensure:

- [ ] Code passes Biome (`pnpm lint`)
- [ ] Code is formatted (`pnpm format`)
- [ ] Code builds successfully (`pnpm build`)
- [ ] All components have TypeScript types
- [ ] Props interfaces are complete
- [ ] Follow naming conventions
- [ ] No `any` types (unless necessary)
- [ ] Large components are split
- [ ] Proper React Hooks usage
- [ ] Key props added to lists
- [ ] Semantic HTML used
- [ ] Accessibility considered
- [ ] API calls use Orval-generated hooks (no manual implementation)
- [ ] Translation text uses `useTranslations`, no hard-coded text
- [ ] TanStack Query Query Keys managed in `lib/query/keys.ts`
- [ ] Streaming APIs use manual implementation in `lib/api.ts`
- [ ] Code has appropriate comments
- [ ] Documentation updated

---

Happy Coding! ⚛️


================================================
FILE: .github/FRONTEND_GUIDELINES_CN.md
================================================
# 前端开发规范

**语言**: [English](FRONTEND_GUIDELINES.md) | [中文](FRONTEND_GUIDELINES_CN.md)

## ⚛️ React + TypeScript 前端开发规范

本文档详细说明了 FreeTodo 项目前端(Next.js + React + TypeScript)的开发规范和最佳实践。

### 技术栈

- **框架**: Next.js 16 + React 19(App Router)
- **语言**: Node.js 22.x + TypeScript 5.x
- **样式**: Tailwind CSS 4 + shadcn/ui
- **状态管理**: Zustand + React Hooks
- **数据获取**: TanStack Query (React Query) v5
- **API 生成**: Orval(根据 OpenAPI 自动生成)
- **数据验证**: Zod(运行时类型验证)
- **主题**: next-themes(浅/深色切换)
- **动画/交互**: framer-motion、@dnd-kit
- **Markdown**: react-markdown + remark-gfm
- **图标**: lucide-react
- **国际化**: next-intl
- **包管理**: pnpm 10.x
- **代码质量**: Biome(lint/format/check)

## 📋 目录

- [代码风格](#-代码风格)
- [项目结构](#-项目结构)
- [命名规范](#-命名规范)
- [TypeScript 规范](#-typescript-规范)
- [React 组件规范](#️-react-组件规范)
- [状态管理](#-状态管理)
- [API 调用](#-api-调用)
- [国际化](#-国际化)
- [样式规范](#-样式规范)
- [性能优化](#-性能优化)
- [测试](#-测试)
- [可访问性](#-可访问性)
- [安全性](#-安全性)

## 🎨 代码风格

### Biome 配置

项目使用 [Biome](https://biomejs.dev/) 作为代码检查器、格式化工具和类型检查器。

```bash
# 检查代码
pnpm lint

# 自动修复问题
pnpm lint --fix

# 格式化代码
pnpm format

# 类型检查
pnpm typecheck

# 构建测试
pnpm build
```

### 基本规则

#### 缩进和格式

```typescript
// ✅ 正确:使用 2 个空格缩进
function MyComponent() {
  const [count, setCount] = useState(0);

  if (count > 0) {
    return <div>Count: {count}</div>;
  }

  return null;
}

// ❌ 错误:使用 4 个空格或 Tab
function MyComponent() {
    const [count, setCount] = useState(0);
    return <div>Count: {count}</div>;
}
```

#### 引号和分号

```typescript
// ✅ 正确:使用双引号,不使用分号
const message = "Hello, World!"
const name = "Alice"

// ❌ 错误:使用单引号和分号
const message = 'Hello, World!';
```

#### 导入语句

```typescript
// ✅ 正确:导入顺序和分组
// 1. React 和 Next.js 核心
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import Image from "next/image"

// 2. 第三方库
import axios from "axios"
import clsx from "clsx"

// 3. 内部组件
import { Button } from "@/components/common/Button"
import { Card } from "@/components/common/Card"

// 4. 工具函数和类型
import { api } from "@/lib/api"
import type { Task } from "@/lib/types"

// 5. 样式
import styles from "./page.module.css"

// ❌ 错误:混乱的导入顺序
import { Button } from "@/components/common/Button"
import { useState } from "react"
import axios from "axios"
```

## 📦 项目结构

```
free-todo-frontend/
├── app/                      # Next.js App Router
│   ├── layout.tsx           # 根布局
│   ├── page.tsx             # 首页
│   └── apps/                # 功能页面
│       ├── todo-list/       # 待办列表
│       ├── todo-detail/     # 待办详情
│       └── [feature]/       # 其他功能
├── components/              # React 组件
│   ├── common/             # 通用组件
│   ├── layout/             # 布局组件
│   └── [feature]/          # 功能组件
├── lib/                    # 工具库
│   ├── api.ts             # API 客户端(流式 API)
│   ├── generated/         # Orval 生成的 API 代码
│   │   ├── [module]/      # 按功能模块分文件
│   │   ├── fetcher.ts     # 自定义 Fetcher
│   │   └── schemas/       # Zod schemas
│   ├── query/             # TanStack Query hooks 封装
│   │   └── keys.ts        # Query Keys 管理
│   ├── types/             # 统一类型定义(camelCase)
│   ├── store/             # Zustand 状态管理
│   ├── hooks/             # 自定义 Hooks
│   └── utils.ts           # 工具函数
├── messages/              # 国际化翻译文件
│   ├── zh.json            # 中文翻译
│   └── en.json            # 英文翻译
└── public/                # 静态资源
```

## 📝 命名规范

### 文件命名

```
# ✅ 正确:组件使用 PascalCase
Button.tsx
TaskCard.tsx
UserProfile.tsx

# ✅ 正确:非组件使用 camelCase
api.ts
utils.ts
use-tasks.ts

# ❌ 错误:不一致的命名
button.tsx
task_card.tsx
```

### 组件命名

```typescript
// ✅ 正确:使用 PascalCase
export function TaskCard() {}
export function UserProfile() {}
export default function HomePage() {}

// ❌ 错误:使用 camelCase
export function taskCard() {}
```

### 变量和函数命名

```typescript
// ✅ 正确:使用 camelCase
const userName = "Alice"
const taskCount = 10

function getUserProfile() {}
function calculateTotal() {}

// ❌ 错误:使用 PascalCase 或 snake_case
const UserName = "Alice"
const task_count = 10
```

### 常量命名

```typescript
// ✅ 正确:使用 UPPER_SNAKE_CASE
const MAX_RETRY_COUNT = 3
const API_BASE_URL = "https://api.example.com"
const DEFAULT_PAGE_SIZE = 10

// ❌ 错误:使用 camelCase
const maxRetryCount = 3
```

### Hooks 命名

```typescript
// ✅ 正确:自定义 Hook 以 use 开头
function useTasks() {}
function useUser() {}
function useDebounce() {}

// ❌ 错误:不以 use 开头
function getTasks() {}
```

### 事件处理函数命名

```typescript
// ✅ 正确:使用 handle 前缀
function handleClick() {}
function handleSubmit() {}
function handleChange(e: ChangeEvent<HTMLInputElement>) {}

// ✅ 正确:传递给子组件的回调使用 on 前缀
<Button onClick={handleClick} />
<Input onChange={handleChange} />
```

## 🔤 TypeScript 规范

### 启用严格模式

```json
// tsconfig.json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  }
}
```

### 类型定义

```typescript
// ✅ 正确:定义清晰的类型
interface Task {
  id: number
  title: string
  description: string | null
  status: "pending" | "in_progress" | "completed"
  priority: number
  createdAt: string
  updatedAt: string
}

type TaskStatus = "pending" | "in_progress" | "completed"

// ❌ 错误:使用 any
interface Task {
  id: number
  title: string
  data: any  // 避免使用 any
}
```

### 组件 Props 类型

```typescript
// ✅ 正确:定义 Props 接口
interface TaskCardProps {
  task: Task
  onEdit?: (task: Task) => void
  onDelete?: (taskId: number) => void
  className?: string
}

export function TaskCard({
  task,
  onEdit,
  onDelete,
  className
}: TaskCardProps) {
  // 组件实现
}

// ✅ 正确:使用泛型
interface ListProps<T> {
  items: T[]
  renderItem: (item: T) => React.ReactNode
  keyExtractor: (item: T) => string | number
}

export function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
  return (
    <div>
      {items.map(item => (
        <div key={keyExtractor(item)}>
          {renderItem(item)}
        </div>
      ))}
    </div>
  )
}
```

## ⚛️ React 组件规范

### 函数组件

```typescript
// ✅ 正确:使用函数组件
interface UserProfileProps {
  user: User
  onUpdate: (user: User) => void
}

export function UserProfile({ user, onUpdate }: UserProfileProps) {
  const [isEditing, setIsEditing] = useState(false)

  return (
    <div>
      <h2>{user.name}</h2>
      {/* 组件内容 */}
    </div>
  )
}

// ❌ 错误:使用类组件(除非必要)
class UserProfile extends React.Component<UserProfileProps> {
  render() {
    return <div>{this.props.user.name}</div>
  }
}
```

### 自定义 Hooks

```typescript
// ✅ 正确:创建自定义 Hook
function useTasks() {
  const [tasks, setTasks] = useState<Task[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    fetchTasks()
  }, [])

  const fetchTasks = async () => {
    setLoading(true)
    setError(null)
    try {
      const response = await api.get<Task[]>("/api/tasks")
      setTasks(response.data)
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to fetch tasks")
    } finally {
      setLoading(false)
    }
  }

  return { tasks, loading, error, fetchTasks }
}

// 使用自定义 Hook
function TasksPage() {
  const { tasks, loading, error } = useTasks()

  if (loading) return <div>加载中...</div>
  if (error) return <div>错误: {error}</div>

  return <TaskList tasks={tasks} />
}
```

## 🎯 状态管理

### 本地状态(useState)

```typescript
// ✅ 正确:使用函数式更新
function Counter() {
  const [count, setCount] = useState(0)

  const increment = () => setCount(prev => prev + 1)
  const decrement = () => setCount(prev => prev - 1)

  return (
    <div>
      <p>计数: {count}</p>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  )
}
```

### 全局状态(Zustand)

```typescript
// lib/store/taskStore.ts
import { create } from "zustand"

interface TaskState {
  tasks: Task[]
  loading: boolean
  error: string | null
  fetchTasks: () => Promise<void>
  createTask: (task: TaskCreate) => Promise<void>
}

export const useTaskStore = create<TaskState>((set) => ({
  tasks: [],
  loading: false,
  error: null,

  fetchTasks: async () => {
    set({ loading: true, error: null })
    try {
      const response = await api.get<Task[]>("/api/tasks")
      set({ tasks: response.data, loading: false })
    } catch (error) {
      set({ error: "获取任务失败", loading: false })
    }
  },

  createTask: async (taskData: TaskCreate) => {
    try {
      const response = await api.post<Task>("/api/tasks", taskData)
      set(state => ({ tasks: [...state.tasks, response.data] }))
    } catch (error) {
      set({ error: "创建任务失败" })
      throw error
    }
  }
}))
```

## 🌐 API 调用

项目使用 **Orval + TanStack Query + Zod** 实现类型安全的 API 调用和数据验证。

### Orval 代码生成

- **配置文件**: `orval.config.ts`
- **生成命令**: `pnpm orval`(需后端服务运行)
- **生成内容**: TypeScript 类型、Zod schemas、React Query hooks
- **输出目录**: `lib/generated/`(按 API tag 分割,如 `todos/`, `chat/`)

**主要配置**:
- `input.target`: 后端 OpenAPI schema 地址(http://localhost:8001/openapi.json)
- `output.client`: 使用 react-query 生成 hooks
- `output.mode`: tags-split 按功能模块分文件
- `override.mutator`: 使用自定义 fetcher(`lib/generated/fetcher.ts`)
- `override.zod.strict`: 启用严格的运行时验证

### 使用 Orval 生成的 API Hooks

```typescript
// 1. 直接使用生成的 hooks
import { useGetTodos, useCreateTodo } from "@/lib/generated/todos"

function TodoList() {
  const { data: todos, isLoading } = useGetTodos()
  const createTodo = useCreateTodo()

  // 使用生成的 hooks
}

// 2. 在 lib/query/ 中封装,添加业务逻辑
// lib/query/todos.ts
import { useGetTodos as useGetTodosBase } from "@/lib/generated/todos"
import { queryKeys } from "./keys"

export function useTodos() {
  return useGetTodosBase({
    query: {
      queryKey: queryKeys.todos.list(),
      staleTime: 30000, // 30 秒缓存
    },
  })
}
```

### TanStack Query 使用规范

- **Query Keys**: 统一在 `lib/query/keys.ts` 管理,使用层级结构(如 `todos.list()`, `todos.detail(id)`)
- **乐观更新**: 在 `onMutate` 中更新缓存,`onError` 回滚,`onSettled` 重新获取
- **防抖更新**: 针对频繁变化字段(如描述、备注)使用 500ms 防抖
- **缓存策略**: 设置合理的 `staleTime`(如 30 秒),避免过度请求

```typescript
// lib/query/keys.ts
export const queryKeys = {
  todos: {
    all: () => ["todos"] as const,
    lists: () => [...queryKeys.todos.all(), "list"] as const,
    list: (filters?: string) => [...queryKeys.todos.lists(), { filters }] as const,
    details: () => [...queryKeys.todos.all(), "detail"] as const,
    detail: (id: number) => [...queryKeys.todos.details(), id] as const,
  },
}
```

### Zod 数据验证

- **生成的 schemas**: 位于 `lib/generated/schemas/`,由 Orval 自动生成
- **运行时验证**: 在 fetcher 中自动验证 API 响应格式
- **表单验证**: 配合 React Hook Form 的 `zodResolver` 使用

### 自定义 Fetcher

位于 `lib/generated/fetcher.ts`,负责:
- 环境适配(客户端/服务端 URL)
- **命名风格自动转换**:
  - 请求时:camelCase → snake_case(前端风格 → 后端风格)
  - 响应时:snake_case → camelCase(后端风格 → 前端风格)
- 时间字符串标准化(处理无时区后缀)
- 统一错误处理
- Zod schema 运行时验证

### 流式 API 处理

Orval 不支持 Server-Sent Events,需在 `lib/api.ts` 手动实现:

```typescript
// lib/api.ts
export async function sendChatMessageStream(
  message: string,
  onChunk: (chunk: string) => void
) {
  const response = await fetch(`${API_BASE_URL}/api/chat/stream`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ message }),
  })

  const reader = response.body?.getReader()
  const decoder = new TextDecoder()

  if (!reader) return

  while (true) {
    const { done, value } = await reader.read()
    if (done) break

    const chunk = decoder.decode(value, { stream: true })
    onChunk(chunk)
  }
}
```

### 类型安全最佳实践

1. 优先使用 `lib/types/index.ts` 中的 camelCase 类型(fetcher 已自动转换)
2. ID 统一使用 `number` 类型(与后端数据库一致)
3. Orval 生成的类型仅用于 API 层,业务层使用统一类型定义

### 开发工作流

1. **后端 API 变更**: 运行 `pnpm orval` 重新生成代码,检查 `git diff lib/generated/`
2. **新增 API**: 后端更新 OpenAPI → 生成代码 → 在 `lib/query/` 封装 → 组件使用
3. **调试**: 在 fetcher 中添加日志,查看请求/响应和验证错误

## 🌍 国际化

项目使用 **next-intl** 实现国际化,通过 Zustand store 管理语言切换(无 URL 路由模式)。

- **翻译文件**: `messages/zh.json` 与 `en.json`
- **请求配置**: `i18n/request.ts`
- **语言管理**: `lib/store/locale.ts`(切换时同步到 cookie)
- **访问方法**: `useTranslations(namespace)` 从 `next-intl` 导入

### 使用国际化

```typescript
// ✅ 正确:使用翻译 hook
import { useTranslations } from "next-intl"

function TaskList() {
  const t = useTranslations("page.todo")

  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description", { count: tasks.length })}</p>
    </div>
  )
}

// ❌ 错误:硬编码文本
function TaskList() {
  const locale = useLocale()
  return <h1>{locale === "zh" ? "任务列表" : "Task List"}</h1>
}
```

### 添加/修改文案

- 在 `messages/zh.json` 和 `en.json` 中同步添加翻译 key
- 使用嵌套结构组织翻译,如 `page.settings.title`
- 支持 ICU MessageFormat 插值语法,如 `{count}` 和复数形式

## 🎨 样式规范

### Tailwind CSS 4

项目使用 Tailwind CSS 4 和 shadcn/ui 组件库。

```typescript
// ✅ 正确:使用 Tailwind 工具类和 clsx/tailwind-merge
import { cn } from "@/lib/utils" // tailwind-merge 封装

function Button({ children, variant = "primary", className }: ButtonProps) {
  return (
    <button
      className={cn(
        "px-4 py-2 rounded-lg font-medium transition-colors",
        variant === "primary" && "bg-blue-500 hover:bg-blue-600 text-white",
        variant === "secondary" && "bg-gray-200 hover:bg-gray-300 text-gray-800",
        className
      )}
    >
      {children}
    </button>
  )
}
```

### 深色模式

使用 `next-themes` 管理主题,组件中使用 `dark:` 前缀:

```typescript
function Card({ children }: CardProps) {
  return (
    <div className="bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100">
      {children}
    </div>
  )
}
```

### shadcn/ui 组件

使用 shadcn/ui 提供的组件,可通过 `npx shadcn@latest add [component]` 添加:

```typescript
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"

function MyComponent() {
  return (
    <Card>
      <Button variant="default">点击</Button>
    </Card>
  )
}
```

## ⚡ 性能优化

### React.memo

```typescript
// ✅ 正确:使用 React.memo
export const TaskCard = React.memo(function TaskCard({ task }: TaskCardProps) {
  return (
    <div>
      <h3>{task.title}</h3>
      <p>{task.description}</p>
    </div>
  )
})
```

### useCallback 和 useMemo

```typescript
// ✅ 正确:使用 useCallback
function TaskList({ tasks }: TaskListProps) {
  const handleTaskClick = useCallback((taskId: number) => {
    console.log("任务点击:", taskId)
  }, [])

  return (
    <div>
      {tasks.map(task => (
        <TaskCard key={task.id} task={task} onClick={handleTaskClick} />
      ))}
    </div>
  )
}

// ✅ 正确:使用 useMemo
function TaskStats({ tasks }: TaskStatsProps) {
  const stats = useMemo(() => ({
    total: tasks.length,
    completed: tasks.filter(t => t.status === "completed").length,
    pending: tasks.filter(t => t.status === "pending").length
  }), [tasks])

  return (
    <div>
      <p>总计: {stats.total}</p>
      <p>已完成: {stats.completed}</p>
      <p>待处理: {stats.pending}</p>
    </div>
  )
}
```

## 🧪 测试

```typescript
// TaskCard.test.tsx
import { render, screen, fireEvent } from "@testing-library/react"
import { TaskCard } from "./TaskCard"

describe("TaskCard", () => {
  const mockTask: Task = {
    id: 1,
    title: "测试任务",
    description: "测试描述",
    status: "pending",
    priority: 1,
    createdAt: "2024-01-01T00:00:00Z",
    updatedAt: "2024-01-01T00:00:00Z"
  }

  it("渲染任务标题", () => {
    render(<TaskCard task={mockTask} />)
    expect(screen.getByText("测试任务")).toBeInTheDocument()
  })

  it("点击编辑按钮时调用 onEdit", () => {
    const handleEdit = jest.fn()
    render(<TaskCard task={mockTask} onEdit={handleEdit} />)

    fireEvent.click(screen.getByRole("button", { name: /编辑/i }))
    expect(handleEdit).toHaveBeenCalledWith(mockTask)
  })
})
```

## ♿ 可访问性

### 语义化 HTML

```typescript
// ✅ 正确:使用语义化标签
function TaskList({ tasks }: TaskListProps) {
  return (
    <section>
      <h2>任务列表</h2>
      <ul>
        {tasks.map(task => (
          <li key={task.id}>
            <article>
              <h3>{task.title}</h3>
              <p>{task.description}</p>
            </article>
          </li>
        ))}
      </ul>
    </section>
  )
}

// ❌ 错误:过度使用 div
function TaskList({ tasks }: TaskListProps) {
  return (
    <div>
      <div>任务列表</div>
      <div>
        {tasks.map(task => (
          <div key={task.id}>
            <div>{task.title}</div>
          </div>
        ))}
      </div>
    </div>
  )
}
```

### ARIA 属性

```typescript
// ✅ 正确:使用 ARIA 属性
function Button({ loading, children }: ButtonProps) {
  return (
    <button
      aria-busy={loading}
      aria-label={loading ? "加载中..." : undefined}
      disabled={loading}
    >
      {children}
    </button>
  )
}
```

## 🔒 安全性

### XSS 防护

```typescript
// ✅ 正确:React 自动转义
function TaskDescription({ description }: { description: string }) {
  return <p>{description}</p>
}

// ⚠️ 注意:使用 dangerouslySetInnerHTML 需谨慎
import DOMPurify from "dompurify"

function TaskDescription({ html }: { html: string }) {
  const sanitized = DOMPurify.sanitize(html)
  return <div dangerouslySetInnerHTML={{ __html: sanitized }} />
}
```

### 环境变量

```typescript
// ✅ 正确:使用环境变量
const API_URL = process.env.NEXT_PUBLIC_API_URL
// NEXT_PUBLIC_ 前缀的变量会暴露给客户端
// 没有前缀的变量只在服务端可用
```

## ✅ 代码检查清单

在提交代码前,请确保:

- [ ] 代码通过 Biome 检查(`pnpm lint`)
- [ ] 代码已格式化(`pnpm format`)
- [ ] 代码可以成功构建(`pnpm build`)
- [ ] 所有组件和函数都有 TypeScript 类型
- [ ] Props 接口定义完整
- [ ] 遵循命名规范
- [ ] 没有使用 `any` 类型(除非必要)
- [ ] 大组件已拆分为小组件
- [ ] 正确使用 React Hooks
- [ ] 添加了必要的 key 属性
- [ ] 使用了语义化 HTML 标签
- [ ] 考虑了可访问性
- [ ] API 调用使用 Orval 生成的 hooks(不要手写)
- [ ] 翻译文本使用 `useTranslations`,禁止硬编码
- [ ] TanStack Query 的 Query Keys 在 `lib/query/keys.ts` 中管理
- [ ] 流式 API 使用 `lib/api.ts` 中的手动实现
- [ ] 代码有适当的注释
- [ ] 更新了相关文档

---

Happy Coding! ⚛️


================================================
FILE: .github/GIT_FLOW.md
================================================
# Git Flow Workflow

**Language**: [English](GIT_FLOW.md) | [中文](GIT_FLOW_CN.md)

## 📋 Table of Contents

- [Overview](#-overview)
- [Branch Strategy](#-branch-strategy)
- [Workflow](#-workflow)
- [Branch Naming Convention](#-branch-naming-convention)
- [Common Scenarios](#-common-scenarios)
- [Best Practices](#-best-practices)
- [FAQ](#-faq)

## 📖 Overview

The FreeTodo project adopts a Git Flow-based branch management strategy to ensure code quality and standardized development processes. This document details our branch model and workflow.

### Core Principles

- 🔒 **Protect Main Branch**: The `main` branch is always stable and deployable
- 🔄 **Continuous Integration**: Continuous feature integration through the `dev` branch
- 🧪 **Thorough Testing**: Complete testing and verification on the `test` branch
- 🌿 **Feature Isolation**: Each feature or fix is developed in an isolated branch
- 👥 **Collaborative Development**: Clear branch strategy facilitates team collaboration

## 🌳 Branch Strategy

### Long-lived Branches

We maintain the following long-lived branches:

#### 1. `main` Branch

- **Purpose**: Production environment branch, contains the most stable code
- **Characteristics**:
  - 🔒 Protected, no direct pushes allowed
  - ✅ All code must go through complete review and testing
  - 🏷️ Each merge should be tagged with a version (e.g., `v1.0.0`)
  - 🚀 Can be directly deployed to production
- **Merge Sources**: Only accepts merges from the `test` branch

#### 2. `dev` Branch

- **Purpose**: Development environment branch for daily development and feature integration
- **Characteristics**:
  - 🔄 Continuous integration of new features
  - 👥 Main collaboration branch for team members
  - 🧪 Relatively stable but may contain untested features
  - 📦 Can be deployed to development environment for internal testing
- **Merge Sources**: Accepts merges from `feat/*` and `fix/*` branches

#### 3. `test` Branch

- **Purpose**: Testing environment branch for complete integration and acceptance testing
- **Characteristics**:
  - 🧪 Used for QA testing and User Acceptance Testing (UAT)
  - ✅ Must pass all test cases
  - 🔍 Performs performance and compatibility testing
  - 📋 Can only be merged to `main` after passing all tests
- **Merge Sources**: Accepts merges from the `dev` branch

### Temporary Branches

The following branch types are temporary and should be deleted after completion:

#### 4. `feat/*` Branches

- **Purpose**: Develop new features
- **Naming Convention**: `feat/brief-description`
- **Examples**:
  - `feat/task-auto-association`
  - `feat/dark-mode`
  - `feat/export-data`
- **Lifecycle**:
  - Created from the `dev` branch
  - Merged back to the `dev` branch when complete
  - Deleted after merging

#### 5. `fix/*` Branches

- **Purpose**: Fix bugs
- **Naming Convention**: `fix/brief-bug-description`
- **Examples**:
  - `fix/screenshot-capture-error`
  - `fix/memory-leak`
  - `fix/login-redirect`
- **Lifecycle**:
  - Created from `dev` branch (development bugs)
  - Created from `test` branch (testing bugs)
  - Created from `main` branch (production emergency bugs, see Hotfix)
  - Merged back to the original branch when complete
  - Deleted after merging

#### 6. `hotfix/*` Branches (Special Case)

- **Purpose**: Fix critical production bugs
- **Naming Convention**: `hotfix/critical-bug-description`
- **Examples**:
  - `hotfix/critical-security-issue`
  - `hotfix/data-loss-bug`
- **Lifecycle**:
  - Created from the `main` branch
  - Merged back to both `main` and `dev` branches when complete
  - Tagged with a patch version on the `main` branch
  - Deleted after merging

## 🔄 Workfl
Download .txt
gitextract_0o688pqc/

├── .cursor/
│   ├── commands/
│   │   ├── agno_agent.md
│   │   ├── agno_agent_CN.md
│   │   ├── backend.md
│   │   ├── backend_CN.md
│   │   ├── dynamic-island.md
│   │   ├── web.md
│   │   └── web_CN.md
│   └── plans/
│       ├── lifetrace_全面优化_76b5f86f.plan.md
│       ├── tauri_迁移方案_38d8ea4b.plan.md
│       ├── 后台持续录音方案_c7c8f0fe.plan.md
│       └── 打包与性能优化_ecd1657a.plan.md
├── .gitattributes
├── .githooks/
│   ├── post-checkout
│   └── pre-commit
├── .github/
│   ├── BACKEND_GUIDELINES.md
│   ├── BACKEND_GUIDELINES_CN.md
│   ├── CONTRIBUTING.md
│   ├── CONTRIBUTING_CN.md
│   ├── FRONTEND_GUIDELINES.md
│   ├── FRONTEND_GUIDELINES_CN.md
│   ├── GIT_FLOW.md
│   ├── GIT_FLOW_CN.md
│   ├── INSTALL.md
│   ├── INSTALL_CN.md
│   ├── PRE_COMMIT_GUIDE.md
│   ├── PRE_COMMIT_GUIDE_CN.md
│   ├── ROADMAP.md
│   ├── ROADMAP_CN.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── _disabled/
│       │   ├── dev-build-verify.yml
│       │   └── tauri-release.yml
│       ├── dependency-review.yml
│       └── pre-commit.yml
├── .gitignore
├── .pre-commit-config.yaml
├── .python-version
├── AGENTS.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── README_CN.md
├── bandit.yaml
├── biome.json
├── free-todo-frontend/
│   ├── .gitignore
│   ├── app/
│   │   ├── globals.css
│   │   ├── home/
│   │   │   ├── HomePageClient.tsx
│   │   │   └── HomePageEntry.tsx
│   │   ├── island/
│   │   │   ├── island.css
│   │   │   ├── layout.tsx
│   │   │   └── page.tsx
│   │   ├── layout.tsx
│   │   └── page.tsx
│   ├── apps/
│   │   ├── achievements/
│   │   │   └── AchievementsPanel.tsx
│   │   ├── activity/
│   │   │   ├── ActivityCard.tsx
│   │   │   ├── ActivityDetail.tsx
│   │   │   ├── ActivityHeader.tsx
│   │   │   ├── ActivityPanel.tsx
│   │   │   ├── ActivitySidebar.tsx
│   │   │   ├── ActivitySummary.tsx
│   │   │   └── utils/
│   │   │       └── timeUtils.ts
│   │   ├── audio/
│   │   │   ├── AudioPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── AudioExtractionPanel.tsx
│   │   │   │   ├── AudioHeader.tsx
│   │   │   │   ├── AudioList.tsx
│   │   │   │   ├── AudioPlayer.tsx
│   │   │   │   ├── RecordingStatus.tsx
│   │   │   │   ├── StopRecordingConfirm.tsx
│   │   │   │   └── TranscriptionView.tsx
│   │   │   ├── hooks/
│   │   │   │   ├── useAudioData.ts
│   │   │   │   ├── useAudioDateSwitching.ts
│   │   │   │   ├── useAudioLink.ts
│   │   │   │   ├── useAudioPlayback.ts
│   │   │   │   ├── useAudioRecording.ts
│   │   │   │   ├── useAudioRecordingControl.ts
│   │   │   │   ├── useSegmentSync.ts
│   │   │   │   └── useStopRecordingConfirm.ts
│   │   │   └── utils/
│   │   │       ├── parseTimeToIsoWithDate.ts
│   │   │       └── timeUtils.ts
│   │   ├── calendar/
│   │   │   ├── CalendarPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── DayColumn.tsx
│   │   │   │   ├── DraggableTodo.tsx
│   │   │   │   ├── FloatingTodoCard.tsx
│   │   │   │   ├── QuickCreateBar.tsx
│   │   │   │   ├── QuickCreatePopover.tsx
│   │   │   │   ├── TimelineColumn.tsx
│   │   │   │   ├── TimelineCreatePopover.tsx
│   │   │   │   ├── TimelineSlot.tsx
│   │   │   │   └── TimelineTodoCard.tsx
│   │   │   ├── hooks/
│   │   │   │   └── useMonthScroll.ts
│   │   │   ├── types.ts
│   │   │   ├── utils.ts
│   │   │   └── views/
│   │   │       ├── DayView.tsx
│   │   │       ├── MonthScroller.tsx
│   │   │       ├── MonthView.tsx
│   │   │       ├── WeekView.tsx
│   │   │       └── useWeekViewActions.ts
│   │   ├── chat/
│   │   │   ├── ChatPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── breakdown/
│   │   │   │   │   ├── BreakdownStageRenderer.tsx
│   │   │   │   │   ├── BreakdownSummary.tsx
│   │   │   │   │   └── Questionnaire.tsx
│   │   │   │   ├── input/
│   │   │   │   │   ├── ChatInputSection.tsx
│   │   │   │   │   ├── InputBox.tsx
│   │   │   │   │   ├── LinkedTodos.tsx
│   │   │   │   │   ├── PromptSuggestions.tsx
│   │   │   │   │   └── ToolSelector.tsx
│   │   │   │   ├── layout/
│   │   │   │   │   ├── HeaderBar.tsx
│   │   │   │   │   ├── HistoryDrawer.tsx
│   │   │   │   │   └── WelcomeGreetings.tsx
│   │   │   │   └── message/
│   │   │   │       ├── EditModeMessage.tsx
│   │   │   │       ├── MarkdownComponents.tsx
│   │   │   │       ├── MessageContent.tsx
│   │   │   │       ├── MessageContextMenu.tsx
│   │   │   │       ├── MessageItem.tsx
│   │   │   │       ├── MessageList.tsx
│   │   │   │       ├── MessageSources.tsx
│   │   │   │       ├── MessageTodoExtractionModal.tsx
│   │   │   │       ├── MessageTodoExtractionPanel.tsx
│   │   │   │       ├── SummaryStreaming.tsx
│   │   │   │       ├── ToolCallLoading.tsx
│   │   │   │       ├── ToolCallSteps.tsx
│   │   │   │       └── utils/
│   │   │   │           └── messageContentUtils.ts
│   │   │   ├── hooks/
│   │   │   │   ├── useBreakdownQuestionnaire.ts
│   │   │   │   ├── useBreakdownService.ts
│   │   │   │   ├── useChatController.ts
│   │   │   │   ├── useChatPrompts.ts
│   │   │   │   ├── useMessageExtraction.ts
│   │   │   │   ├── useMessageScroll.ts
│   │   │   │   ├── usePlanParser.ts
│   │   │   │   ├── useSendMessage.ts
│   │   │   │   ├── useSessionCache.ts
│   │   │   │   ├── useSessionManager.ts
│   │   │   │   ├── useStreamController.ts
│   │   │   │   └── useToolCallTracker.ts
│   │   │   ├── types.ts
│   │   │   └── utils/
│   │   │       ├── id.ts
│   │   │       ├── messageBuilder.ts
│   │   │       ├── parseEditBlocks.ts
│   │   │       ├── responseHandlers.ts
│   │   │       └── todoContext.ts
│   │   ├── cost-tracking/
│   │   │   ├── CostTrackingPanel.tsx
│   │   │   └── index.ts
│   │   ├── debug/
│   │   │   ├── DebugCapturePanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── EventCard.tsx
│   │   │   │   ├── EventSearchForm.tsx
│   │   │   │   ├── ScreenshotModal.tsx
│   │   │   │   ├── SelectedEventsBar.tsx
│   │   │   │   └── index.ts
│   │   │   ├── hooks/
│   │   │   │   ├── index.ts
│   │   │   │   ├── useEventActions.ts
│   │   │   │   └── useEventData.ts
│   │   │   └── utils.ts
│   │   ├── diary/
│   │   │   ├── DiaryEditor.tsx
│   │   │   ├── DiaryHeader.tsx
│   │   │   ├── DiaryPanel.tsx
│   │   │   ├── DiarySettings.tsx
│   │   │   ├── DiaryTabs.tsx
│   │   │   ├── JournalHistory.tsx
│   │   │   ├── index.ts
│   │   │   ├── journal-utils.ts
│   │   │   └── types.ts
│   │   ├── settings/
│   │   │   ├── SettingsPanel.tsx
│   │   │   ├── components/
│   │   │   │   ├── AudioAsrConfigSection.tsx
│   │   │   │   ├── AudioConfigSection.tsx
│   │   │   │   ├── AutoTodoDetectionSection.tsx
│   │   │   │   ├── AutomationTasksSection.tsx
│   │   │   │   ├── DifyConfigSection.tsx
│   │   │   │   ├── DockDisplayModeSection.tsx
│   │   │   │   ├── JournalSettingsSection.tsx
│   │   │   │   ├── LlmConfigSection.tsx
│   │   │   │   ├── NotificationPermissionSection.tsx
│   │   │   │   ├── OnboardingSection.tsx
│   │   │   │   ├── PanelSwitchesSection.tsx
│   │   │   │   ├── RecorderConfigSection.tsx
│   │   │   │   ├── SchedulerSection.tsx
│   │   │   │   ├── SettingsCategoryPanel.tsx
│   │   │   │   ├── SettingsSearchAction.tsx
│   │   │   │   ├── SettingsSection.tsx
│   │   │   │   ├── TavilyConfigSection.tsx
│   │   │   │   ├── ToggleSwitch.tsx
│   │   │   │   ├── VersionInfoSection.tsx
│   │   │   │   └── index.ts
│   │   │   ├── hooks/
│   │   │   │   └── useSettingsSearchMatchStats.ts
│   │   │   └── index.ts
│   │   ├── todo-detail/
│   │   │   ├── TodoDetail.tsx
│   │   │   ├── components/
│   │   │   │   ├── ArtifactsView.tsx
│   │   │   │   ├── AttachmentPreviewPanel.tsx
│   │   │   │   ├── BackgroundSection.tsx
│   │   │   │   ├── ChildTodoSection.tsx
│   │   │   │   ├── DatePickerCalendar.tsx
│   │   │   │   ├── DatePickerPopover.tsx
│   │   │   │   ├── DatePickerSidePanel.tsx
│   │   │   │   ├── DetailHeader.tsx
│   │   │   │   ├── DetailTitle.tsx
│   │   │   │   ├── MetaSection.tsx
│   │   │   │   ├── NotesEditor.tsx
│   │   │   │   └── datePickerUtils.ts
│   │   │   ├── helpers.ts
│   │   │   ├── hooks/
│   │   │   │   └── useNotesAutosize.ts
│   │   │   ├── index.ts
│   │   │   └── utils/
│   │   │       ├── date-utils.ts
│   │   │       ├── holiday-utils.ts
│   │   │       ├── index.ts
│   │   │       └── lunar-utils.ts
│   │   └── todo-list/
│   │       ├── CreateTodoForm.tsx
│   │       ├── NewTodoInlineForm.tsx
│   │       ├── TodoCard.tsx
│   │       ├── TodoExtractionModal.tsx
│   │       ├── TodoList.tsx
│   │       ├── TodoToolbar.tsx
│   │       ├── TodoTreeList.tsx
│   │       ├── components/
│   │       │   ├── TodoCardCheckbox.tsx
│   │       │   ├── TodoCardChildForm.tsx
│   │       │   ├── TodoCardDropZone.tsx
│   │       │   ├── TodoCardExpandButton.tsx
│   │       │   ├── TodoCardMetadata.tsx
│   │       │   ├── TodoCardName.tsx
│   │       │   └── TodoFilter.tsx
│   │       ├── hooks/
│   │       │   ├── useOrderedTodos.ts
│   │       │   ├── useTodoCardDrag.ts
│   │       │   ├── useTodoCardHandlers.ts
│   │       │   └── useTodoCardState.ts
│   │       ├── index.ts
│   │       └── utils/
│   │           └── todoCardUtils.ts
│   ├── components/
│   │   ├── common/
│   │   │   ├── ReminderOptions.tsx
│   │   │   ├── context-menu/
│   │   │   │   ├── BaseContextMenu.tsx
│   │   │   │   ├── MultiTodoContextMenu.tsx
│   │   │   │   └── TodoContextMenu.tsx
│   │   │   ├── layout/
│   │   │   │   ├── CollapsibleSection.tsx
│   │   │   │   ├── LayoutSelector.tsx
│   │   │   │   ├── LayoutSelectorDialogs.tsx
│   │   │   │   ├── PanelHeader.tsx
│   │   │   │   └── SectionHeader.tsx
│   │   │   ├── theme/
│   │   │   │   ├── ThemeProvider.tsx
│   │   │   │   ├── ThemeStyleSelect.tsx
│   │   │   │   └── ThemeToggle.tsx
│   │   │   └── ui/
│   │   │       ├── BackendReadyGate.tsx
│   │   │       ├── CapabilitiesSync.tsx
│   │   │       ├── DockTriggerZone.tsx
│   │   │       ├── FrontendBoot.tsx
│   │   │       ├── LanguageToggle.tsx
│   │   │       ├── LocaleSync.tsx
│   │   │       ├── ScrollbarController.tsx
│   │   │       ├── SettingsToggle.tsx
│   │   │       └── UserAvatar.tsx
│   │   ├── date-picker/
│   │   │   ├── DateOnlyPickerCalendar.tsx
│   │   │   ├── DateOnlyPickerPopover.tsx
│   │   │   └── date-picker-utils.ts
│   │   ├── island/
│   │   │   ├── DynamicIsland.tsx
│   │   │   ├── IslandContent.tsx
│   │   │   ├── IslandFullscreenContent.tsx
│   │   │   ├── IslandHeader.tsx
│   │   │   ├── IslandSidebarContent.tsx
│   │   │   └── index.ts
│   │   ├── layout/
│   │   │   ├── AppHeader.tsx
│   │   │   ├── BottomDock.tsx
│   │   │   ├── FullscreenHeader.tsx
│   │   │   ├── PanelContainer.tsx
│   │   │   ├── PanelContent.tsx
│   │   │   ├── PanelRegion.tsx
│   │   │   ├── PanelSelectorMenu.tsx
│   │   │   └── ResizeHandle.tsx
│   │   ├── notification/
│   │   │   └── HeaderIsland.tsx
│   │   └── ui/
│   │       ├── alert-dialog.tsx
│   │       ├── button.tsx
│   │       ├── dialog.tsx
│   │       └── dropdown-menu.tsx
│   ├── electron/
│   │   ├── PACKAGING_GUIDE.md
│   │   ├── PACKAGING_GUIDE_CN.md
│   │   ├── backend-server.ts
│   │   ├── bootstrap-control.ts
│   │   ├── bootstrap-status.ts
│   │   ├── bootstrap-window.ts
│   │   ├── config.ts
│   │   ├── git-info.ts
│   │   ├── global-shortcut-manager.ts
│   │   ├── ipc-handlers-todo-capture.ts
│   │   ├── ipc-handlers.ts
│   │   ├── island-window-manager.ts
│   │   ├── logger.ts
│   │   ├── main.ts
│   │   ├── next-server.ts
│   │   ├── notification.ts
│   │   ├── port-manager.ts
│   │   ├── preload.ts
│   │   ├── process-manager.ts
│   │   ├── python-runtime-command.ts
│   │   ├── python-runtime-env.ts
│   │   ├── python-runtime-installer.ts
│   │   ├── python-runtime.ts
│   │   ├── runtime-paths.ts
│   │   ├── tray-manager.ts
│   │   ├── tsconfig.json
│   │   └── window-manager.ts
│   ├── electron-builder.island.pyinstaller.yml
│   ├── electron-builder.island.script.yml
│   ├── electron-builder.island.yml
│   ├── electron-builder.web.pyinstaller.yml
│   ├── electron-builder.web.script.yml
│   ├── electron-builder.web.yml
│   ├── electron-builder.yml
│   ├── global.d.ts
│   ├── lib/
│   │   ├── api/
│   │   │   └── fetcher.ts
│   │   ├── api.ts
│   │   ├── attachments.ts
│   │   ├── config/
│   │   │   └── panel-config.ts
│   │   ├── dnd/
│   │   │   ├── context.tsx
│   │   │   ├── handlers.ts
│   │   │   ├── index.ts
│   │   │   ├── overlays.tsx
│   │   │   └── types.ts
│   │   ├── generated/
│   │   │   ├── activity/
│   │   │   │   └── activity.ts
│   │   │   ├── audio/
│   │   │   │   └── audio.ts
│   │   │   ├── case-transform.ts
│   │   │   ├── chat/
│   │   │   │   └── chat.ts
│   │   │   ├── config/
│   │   │   │   └── config.ts
│   │   │   ├── cost-tracking/
│   │   │   │   └── cost-tracking.ts
│   │   │   ├── default/
│   │   │   │   └── default.ts
│   │   │   ├── event/
│   │   │   │   └── event.ts
│   │   │   ├── floating-capture/
│   │   │   │   └── floating-capture.ts
│   │   │   ├── journals/
│   │   │   │   └── journals.ts
│   │   │   ├── logs/
│   │   │   │   └── logs.ts
│   │   │   ├── notifications/
│   │   │   │   └── notifications.ts
│   │   │   ├── ocr/
│   │   │   │   └── ocr.ts
│   │   │   ├── proactive-ocr/
│   │   │   │   └── proactive-ocr.ts
│   │   │   ├── rag/
│   │   │   │   └── rag.ts
│   │   │   ├── scheduler/
│   │   │   │   └── scheduler.ts
│   │   │   ├── schemas/
│   │   │   │   ├── activityEventsResponse.ts
│   │   │   │   ├── activityListResponse.ts
│   │   │   │   ├── activityResponse.ts
│   │   │   │   ├── activityResponseAiSummary.ts
│   │   │   │   ├── activityResponseAiTitle.ts
│   │   │   │   ├── activityResponseCreatedAt.ts
│   │   │   │   ├── activityResponseUpdatedAt.ts
│   │   │   │   ├── addMessageRequest.ts
│   │   │   │   ├── audioLinkItem.ts
│   │   │   │   ├── audioLinkRequest.ts
│   │   │   │   ├── bodyImportIcsApiTodosImportIcsPost.ts
│   │   │   │   ├── bodyUploadAttachmentsApiTodosTodoIdAttachmentsPost.ts
│   │   │   │   ├── capabilitiesResponse.ts
│   │   │   │   ├── capabilitiesResponseMissingDeps.ts
│   │   │   │   ├── chatMessage.ts
│   │   │   │   ├── chatMessageContext.ts
│   │   │   │   ├── chatMessageConversationId.ts
│   │   │   │   ├── chatMessageExternalTools.ts
│   │   │   │   ├── chatMessageMode.ts
│   │   │   │   ├── chatMessageProjectId.ts
│   │   │   │   ├── chatMessageSelectedTools.ts
│   │   │   │   ├── chatMessageSystemPrompt.ts
│   │   │   │   ├── chatMessageTaskIds.ts
│   │   │   │   ├── chatMessageUserInput.ts
│   │   │   │   ├── chatMessageWithContext.ts
│   │   │   │   ├── chatMessageWithContextConversationId.ts
│   │   │   │   ├── chatMessageWithContextEventContext.ts
│   │   │   │   ├── chatMessageWithContextEventContextAnyOfItem.ts
│   │   │   │   ├── chatMessageWorkspacePath.ts
│   │   │   │   ├── chatResponse.ts
│   │   │   │   ├── chatResponsePerformance.ts
│   │   │   │   ├── chatResponsePerformanceAnyOf.ts
│   │   │   │   ├── chatResponseQueryInfo.ts
│   │   │   │   ├── chatResponseQueryInfoAnyOf.ts
│   │   │   │   ├── chatResponseRetrievalInfo.ts
│   │   │   │   ├── chatResponseRetrievalInfoAnyOf.ts
│   │   │   │   ├── chatResponseSessionId.ts
│   │   │   │   ├── cleanupOldDataApiCleanupPostParams.ts
│   │   │   │   ├── contextListResponse.ts
│   │   │   │   ├── contextResponse.ts
│   │   │   │   ├── contextResponseAiSummary.ts
│   │   │   │   ├── contextResponseAiTitle.ts
│   │   │   │   ├── contextResponseAppName.ts
│   │   │   │   ├── contextResponseCreatedAt.ts
│   │   │   │   ├── contextResponseEndTime.ts
│   │   │   │   ├── contextResponseProjectId.ts
│   │   │   │   ├── contextResponseStartTime.ts
│   │   │   │   ├── contextResponseTaskId.ts
│   │   │   │   ├── contextResponseWindowTitle.ts
│   │   │   │   ├── contextUpdateRequest.ts
│   │   │   │   ├── contextUpdateRequestProjectId.ts
│   │   │   │   ├── contextUpdateRequestTaskId.ts
│   │   │   │   ├── countEventsApiEventsCountGetParams.ts
│   │   │   │   ├── createdTodo.ts
│   │   │   │   ├── createdTodoScheduledTime.ts
│   │   │   │   ├── eventDetailResponse.ts
│   │   │   │   ├── eventDetailResponseAiSummary.ts
│   │   │   │   ├── eventDetailResponseAiTitle.ts
│   │   │   │   ├── eventDetailResponseAppName.ts
│   │   │   │   ├── eventDetailResponseEndTime.ts
│   │   │   │   ├── eventDetailResponseWindowTitle.ts
│   │   │   │   ├── eventListResponse.ts
│   │   │   │   ├── eventResponse.ts
│   │   │   │   ├── eventResponseAiSummary.ts
│   │   │   │   ├── eventResponseAiTitle.ts
│   │   │   │   ├── eventResponseAppName.ts
│   │   │   │   ├── eventResponseEndTime.ts
│   │   │   │   ├── eventResponseFirstScreenshotId.ts
│   │   │   │   ├── eventResponseWindowTitle.ts
│   │   │   │   ├── exportIcsApiTodosExportIcsGetParams.ts
│   │   │   │   ├── extractTodosAndSchedulesApiAudioExtractPostParams.ts
│   │   │   │   ├── extractedMessageTodo.ts
│   │   │   │   ├── extractedMessageTodoDescription.ts
│   │   │   │   ├── extractedTodo.ts
│   │   │   │   ├── extractedTodoConfidence.ts
│   │   │   │   ├── extractedTodoDescription.ts
│   │   │   │   ├── extractedTodoScheduledTime.ts
│   │   │   │   ├── extractedTodoSourceText.ts
│   │   │   │   ├── extractedTodoTimeInfo.ts
│   │   │   │   ├── extractedTodoTimeInfoAnyOf.ts
│   │   │   │   ├── floatingCaptureRequest.ts
│   │   │   │   ├── floatingCaptureResponse.ts
│   │   │   │   ├── generateTasksResponse.ts
│   │   │   │   ├── generatedTaskItem.ts
│   │   │   │   ├── generatedTaskItemDescription.ts
│   │   │   │   ├── getChatHistoryApiChatHistoryGetParams.ts
│   │   │   │   ├── getChatPromptsApiGetChatPromptsGetParams.ts
│   │   │   │   ├── getContextsApiContextsGetParams.ts
│   │   │   │   ├── getCostStatsApiCostTrackingStatsGetParams.ts
│   │   │   │   ├── getLogContentApiLogsContentGetParams.ts
│   │   │   │   ├── getProjectTasksApiProjectsProjectIdTasksGetParams.ts
│   │   │   │   ├── getProjectsApiProjectsGetParams.ts
│   │   │   │   ├── getQuerySuggestionsApiChatSuggestionsGetParams.ts
│   │   │   │   ├── getRecordingsApiAudioRecordingsGetParams.ts
│   │   │   │   ├── getScreenshotsApiScreenshotsGetParams.ts
│   │   │   │   ├── getTaskProgressApiProjectsProjectIdTasksTaskIdProgressGetParams.ts
│   │   │   │   ├── getTaskProgressLatestApiProjectsProjectIdTasksTaskIdProgressLatestGet200.ts
│   │   │   │   ├── getTimeAllocationApiTimeAllocationGetParams.ts
│   │   │   │   ├── getTimelineApiAudioTimelineGetParams.ts
│   │   │   │   ├── getTranscriptionApiAudioTranscriptionRecordingIdGetParams.ts
│   │   │   │   ├── hTTPValidationError.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── jobInfo.ts
│   │   │   │   ├── jobInfoName.ts
│   │   │   │   ├── jobInfoNextRunTime.ts
│   │   │   │   ├── jobIntervalUpdateRequest.ts
│   │   │   │   ├── jobIntervalUpdateRequestHours.ts
│   │   │   │   ├── jobIntervalUpdateRequestMinutes.ts
│   │   │   │   ├── jobIntervalUpdateRequestSeconds.ts
│   │   │   │   ├── jobListResponse.ts
│   │   │   │   ├── jobOperationResponse.ts
│   │   │   │   ├── journalAutoLinkCandidate.ts
│   │   │   │   ├── journalAutoLinkRequest.ts
│   │   │   │   ├── journalAutoLinkResponse.ts
│   │   │   │   ├── journalCreate.ts
│   │   │   │   ├── journalGenerateRequest.ts
│   │   │   │   ├── journalGenerateResponse.ts
│   │   │   │   ├── journalListResponse.ts
│   │   │   │   ├── journalResponse.ts
│   │   │   │   ├── journalResponseDeletedAt.ts
│   │   │   │   ├── journalTag.ts
│   │   │   │   ├── journalUpdate.ts
│   │   │   │   ├── journalUpdateContentFormat.ts
│   │   │   │   ├── journalUpdateDate.ts
│   │   │   │   ├── journalUpdateName.ts
│   │   │   │   ├── journalUpdateTagIds.ts
│   │   │   │   ├── journalUpdateUserNotes.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodo.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoDescription.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoSourceText.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoTimeInfo.ts
│   │   │   │   ├── lifetraceSchemasFloatingCaptureExtractedTodoTimeInfoAnyOf.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodo.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoConfidence.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoDescription.ts
│   │   │   │   ├── lifetraceSchemasTodoExtractionExtractedTodoScheduledTime.ts
│   │   │   │   ├── linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostParams.ts
│   │   │   │   ├── listActivitiesApiActivitiesGetParams.ts
│   │   │   │   ├── listEventsApiEventsGetParams.ts
│   │   │   │   ├── listJournalsApiJournalsGetParams.ts
│   │   │   │   ├── listTodosApiTodosGetParams.ts
│   │   │   │   ├── manualActivityCreateRequest.ts
│   │   │   │   ├── manualActivityCreateResponse.ts
│   │   │   │   ├── manualActivityCreateResponseAiSummary.ts
│   │   │   │   ├── manualActivityCreateResponseAiTitle.ts
│   │   │   │   ├── manualActivityCreateResponseCreatedAt.ts
│   │   │   │   ├── messageTodoExtractionRequest.ts
│   │   │   │   ├── messageTodoExtractionRequestMessagesItem.ts
│   │   │   │   ├── messageTodoExtractionRequestParentTodoId.ts
│   │   │   │   ├── messageTodoExtractionRequestTodoContext.ts
│   │   │   │   ├── messageTodoExtractionResponse.ts
│   │   │   │   ├── messageTodoExtractionResponseErrorMessage.ts
│   │   │   │   ├── newChatRequest.ts
│   │   │   │   ├── newChatRequestSessionId.ts
│   │   │   │   ├── newChatResponse.ts
│   │   │   │   ├── optimizeTranscriptionApiAudioOptimizePostParams.ts
│   │   │   │   ├── planQuestionnaireRequest.ts
│   │   │   │   ├── planQuestionnaireRequestSessionId.ts
│   │   │   │   ├── planQuestionnaireRequestTodoId.ts
│   │   │   │   ├── planSummaryRequest.ts
│   │   │   │   ├── planSummaryRequestAnswers.ts
│   │   │   │   ├── planSummaryRequestSessionId.ts
│   │   │   │   ├── processInfo.ts
│   │   │   │   ├── processOcrApiOcrProcessPostParams.ts
│   │   │   │   ├── projectCreate.ts
│   │   │   │   ├── projectCreateDefinitionOfDone.ts
│   │   │   │   ├── projectCreateDescription.ts
│   │   │   │   ├── projectListResponse.ts
│   │   │   │   ├── projectResponse.ts
│   │   │   │   ├── projectResponseDefinitionOfDone.ts
│   │   │   │   ├── projectResponseDescription.ts
│   │   │   │   ├── projectStatus.ts
│   │   │   │   ├── projectUpdate.ts
│   │   │   │   ├── projectUpdateDefinitionOfDone.ts
│   │   │   │   ├── projectUpdateDescription.ts
│   │   │   │   ├── projectUpdateName.ts
│   │   │   │   ├── projectUpdateStatus.ts
│   │   │   │   ├── saveAndInitLlmApiSaveAndInitLlmPostBody.ts
│   │   │   │   ├── saveConfigApiSaveConfigPostBody.ts
│   │   │   │   ├── screenshotResponse.ts
│   │   │   │   ├── screenshotResponseAppName.ts
│   │   │   │   ├── screenshotResponseTextContent.ts
│   │   │   │   ├── screenshotResponseWindowTitle.ts
│   │   │   │   ├── searchRequest.ts
│   │   │   │   ├── searchRequestAppName.ts
│   │   │   │   ├── searchRequestEndDate.ts
│   │   │   │   ├── searchRequestQuery.ts
│   │   │   │   ├── searchRequestStartDate.ts
│   │   │   │   ├── semanticSearchRequest.ts
│   │   │   │   ├── semanticSearchRequestFilters.ts
│   │   │   │   ├── semanticSearchRequestFiltersAnyOf.ts
│   │   │   │   ├── semanticSearchRequestRetrieveK.ts
│   │   │   │   ├── semanticSearchResult.ts
│   │   │   │   ├── semanticSearchResultMetadata.ts
│   │   │   │   ├── semanticSearchResultOcrResult.ts
│   │   │   │   ├── semanticSearchResultOcrResultAnyOf.ts
│   │   │   │   ├── semanticSearchResultScreenshot.ts
│   │   │   │   ├── semanticSearchResultScreenshotAnyOf.ts
│   │   │   │   ├── statisticsResponse.ts
│   │   │   │   ├── syncVectorDatabaseApiVectorSyncPostParams.ts
│   │   │   │   ├── systemResourcesResponse.ts
│   │   │   │   ├── systemResourcesResponseCpu.ts
│   │   │   │   ├── systemResourcesResponseDisk.ts
│   │   │   │   ├── systemResourcesResponseMemory.ts
│   │   │   │   ├── systemResourcesResponseStorage.ts
│   │   │   │   ├── systemResourcesResponseSummary.ts
│   │   │   │   ├── taskBatchDeleteRequest.ts
│   │   │   │   ├── taskBatchDeleteResponse.ts
│   │   │   │   ├── taskCreate.ts
│   │   │   │   ├── taskCreateDescription.ts
│   │   │   │   ├── taskListResponse.ts
│   │   │   │   ├── taskProgressListResponse.ts
│   │   │   │   ├── taskProgressResponse.ts
│   │   │   │   ├── taskResponse.ts
│   │   │   │   ├── taskResponseDescription.ts
│   │   │   │   ├── taskStatus.ts
│   │   │   │   ├── taskUpdate.ts
│   │   │   │   ├── taskUpdateDescription.ts
│   │   │   │   ├── taskUpdateName.ts
│   │   │   │   ├── taskUpdateStatus.ts
│   │   │   │   ├── testAsrConfigApiTestAsrConfigPostBody.ts
│   │   │   │   ├── testLlmConfigApiTestLlmConfigPostBody.ts
│   │   │   │   ├── testTavilyConfigApiTestTavilyConfigPostBody.ts
│   │   │   │   ├── timeAllocationResponse.ts
│   │   │   │   ├── timeAllocationResponseAppDetailsItem.ts
│   │   │   │   ├── timeAllocationResponseDailyDistributionItem.ts
│   │   │   │   ├── todoAttachmentResponse.ts
│   │   │   │   ├── todoAttachmentResponseFileSize.ts
│   │   │   │   ├── todoAttachmentResponseMimeType.ts
│   │   │   │   ├── todoCreate.ts
│   │   │   │   ├── todoCreateCompletedAt.ts
│   │   │   │   ├── todoCreateDeadline.ts
│   │   │   │   ├── todoCreateDescription.ts
│   │   │   │   ├── todoCreateEndTime.ts
│   │   │   │   ├── todoCreateParentTodoId.ts
│   │   │   │   ├── todoCreatePercentComplete.ts
│   │   │   │   ├── todoCreateRrule.ts
│   │   │   │   ├── todoCreateStartTime.ts
│   │   │   │   ├── todoCreateUid.ts
│   │   │   │   ├── todoCreateUserNotes.ts
│   │   │   │   ├── todoExtractionRequest.ts
│   │   │   │   ├── todoExtractionRequestScreenshotSampleRatio.ts
│   │   │   │   ├── todoExtractionResponse.ts
│   │   │   │   ├── todoExtractionResponseAppName.ts
│   │   │   │   ├── todoExtractionResponseErrorMessage.ts
│   │   │   │   ├── todoExtractionResponseEventEndTime.ts
│   │   │   │   ├── todoExtractionResponseEventStartTime.ts
│   │   │   │   ├── todoExtractionResponseWindowTitle.ts
│   │   │   │   ├── todoItemType.ts
│   │   │   │   ├── todoListResponse.ts
│   │   │   │   ├── todoPriority.ts
│   │   │   │   ├── todoReorderItem.ts
│   │   │   │   ├── todoReorderItemParentTodoId.ts
│   │   │   │   ├── todoReorderRequest.ts
│   │   │   │   ├── todoResponse.ts
│   │   │   │   ├── todoResponseCompletedAt.ts
│   │   │   │   ├── todoResponseDeadline.ts
│   │   │   │   ├── todoResponseDescription.ts
│   │   │   │   ├── todoResponseEndTime.ts
│   │   │   │   ├── todoResponseParentTodoId.ts
│   │   │   │   ├── todoResponseRrule.ts
│   │   │   │   ├── todoResponseStartTime.ts
│   │   │   │   ├── todoResponseUserNotes.ts
│   │   │   │   ├── todoStatus.ts
│   │   │   │   ├── todoTimeInfo.ts
│   │   │   │   ├── todoTimeInfoAbsoluteTime.ts
│   │   │   │   ├── todoTimeInfoRelativeDays.ts
│   │   │   │   ├── todoTimeInfoRelativeTime.ts
│   │   │   │   ├── todoTimeInfoTimeType.ts
│   │   │   │   ├── todoUpdate.ts
│   │   │   │   ├── todoUpdateCompletedAt.ts
│   │   │   │   ├── todoUpdateDeadline.ts
│   │   │   │   ├── todoUpdateDescription.ts
│   │   │   │   ├── todoUpdateEndTime.ts
│   │   │   │   ├── todoUpdateName.ts
│   │   │   │   ├── todoUpdateOrder.ts
│   │   │   │   ├── todoUpdateParentTodoId.ts
│   │   │   │   ├── todoUpdatePercentComplete.ts
│   │   │   │   ├── todoUpdatePriority.ts
│   │   │   │   ├── todoUpdateRelatedActivities.ts
│   │   │   │   ├── todoUpdateRrule.ts
│   │   │   │   ├── todoUpdateStartTime.ts
│   │   │   │   ├── todoUpdateStatus.ts
│   │   │   │   ├── todoUpdateTags.ts
│   │   │   │   ├── todoUpdateUserNotes.ts
│   │   │   │   ├── updateJournalApiJournalsJournalIdPutBody.ts
│   │   │   │   ├── validationError.ts
│   │   │   │   ├── validationErrorLocItem.ts
│   │   │   │   ├── vectorStatsResponse.ts
│   │   │   │   ├── vectorStatsResponseCollectionName.ts
│   │   │   │   ├── vectorStatsResponseDocumentCount.ts
│   │   │   │   ├── vectorStatsResponseError.ts
│   │   │   │   ├── visionChatRequest.ts
│   │   │   │   ├── visionChatRequestMaxTokens.ts
│   │   │   │   ├── visionChatRequestModel.ts
│   │   │   │   ├── visionChatRequestTemperature.ts
│   │   │   │   ├── visionChatResponse.ts
│   │   │   │   ├── visionChatResponseModel.ts
│   │   │   │   ├── visionChatResponseUsageInfo.ts
│   │   │   │   └── visionChatResponseUsageInfoAnyOf.ts
│   │   │   ├── screenshot/
│   │   │   │   └── screenshot.ts
│   │   │   ├── search/
│   │   │   │   └── search.ts
│   │   │   ├── system/
│   │   │   │   └── system.ts
│   │   │   ├── time-allocation/
│   │   │   │   └── time-allocation.ts
│   │   │   ├── todo-extraction/
│   │   │   │   └── todo-extraction.ts
│   │   │   ├── todos/
│   │   │   │   └── todos.ts
│   │   │   ├── vector/
│   │   │   │   └── vector.ts
│   │   │   └── vision/
│   │   │       └── vision.ts
│   │   ├── hooks/
│   │   │   ├── useAutoRecording.ts
│   │   │   ├── useOnboardingTour.ts
│   │   │   ├── useOpenSettings.ts
│   │   │   ├── usePanelLayout.ts
│   │   │   ├── usePanelResize.ts
│   │   │   ├── usePanelWindowResize.ts
│   │   │   ├── usePanelWindowStyles.ts
│   │   │   ├── useTodoCapture.ts
│   │   │   └── useWindowAdaptivePanels.ts
│   │   ├── i18n/
│   │   │   ├── messages/
│   │   │   │   ├── en.json
│   │   │   │   └── zh.json
│   │   │   └── request.ts
│   │   ├── island/
│   │   │   └── types.ts
│   │   ├── plugins/
│   │   │   └── registry.ts
│   │   ├── query/
│   │   │   ├── activities.ts
│   │   │   ├── automation.ts
│   │   │   ├── chat.ts
│   │   │   ├── config.ts
│   │   │   ├── cost.ts
│   │   │   ├── index.ts
│   │   │   ├── journals.ts
│   │   │   ├── keys.ts
│   │   │   ├── provider.tsx
│   │   │   └── todos.ts
│   │   ├── reminders.ts
│   │   ├── services/
│   │   │   └── notification-poller.ts
│   │   ├── store/
│   │   │   ├── activity-store.ts
│   │   │   ├── audio-recording-store.ts
│   │   │   ├── breakdown-store.ts
│   │   │   ├── chat-store.ts
│   │   │   ├── color-theme.ts
│   │   │   ├── journal-store.ts
│   │   │   ├── locale.ts
│   │   │   ├── notification-store.ts
│   │   │   ├── onboarding-store.ts
│   │   │   ├── theme.ts
│   │   │   ├── todo-store.ts
│   │   │   ├── ui-store/
│   │   │   │   ├── index.ts
│   │   │   │   ├── layout-actions.ts
│   │   │   │   ├── layout-presets.ts
│   │   │   │   ├── storage.ts
│   │   │   │   ├── store.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils.ts
│   │   │   └── ui-store.ts
│   │   ├── toast.ts
│   │   ├── types/
│   │   │   └── index.ts
│   │   ├── utils/
│   │   │   ├── electron-api.ts
│   │   │   ├── electron.ts
│   │   │   ├── platform.ts
│   │   │   └── time.ts
│   │   └── utils.ts
│   ├── next.config.ts
│   ├── orval.config.ts
│   ├── package.json
│   ├── pnpm-workspace.yaml
│   ├── postcss.config.mjs
│   ├── public/
│   │   ├── app-icons/
│   │   │   └── README.md
│   │   └── free-todo-logos/
│   │       └── favicon/
│   │           └── site.webmanifest
│   ├── scripts/
│   │   ├── build-electron.js
│   │   ├── check_code_lines.js
│   │   ├── check_rust_code_lines.js
│   │   ├── collect-tauri-artifacts.js
│   │   ├── copy-missing-deps.js
│   │   ├── dev-with-auto-port.js
│   │   ├── electron-dev-electron.ps1
│   │   ├── electron-dev.ps1
│   │   ├── resolve-symlinks.js
│   │   ├── tauri-copy-resources.js
│   │   └── tauri-prebuild.js
│   ├── src-tauri/
│   │   ├── .tauri-lint-dist/
│   │   │   └── .gitkeep
│   │   ├── Cargo.toml
│   │   ├── PACKAGING_GUIDE.md
│   │   ├── build.rs
│   │   ├── icons/
│   │   │   ├── android/
│   │   │   │   ├── mipmap-anydpi-v26/
│   │   │   │   │   └── ic_launcher.xml
│   │   │   │   └── values/
│   │   │   │       └── ic_launcher_background.xml
│   │   │   └── icon.icns
│   │   ├── rust-toolchain.toml
│   │   ├── rustfmt.toml
│   │   ├── src/
│   │   │   ├── backend.rs
│   │   │   ├── backend_log.rs
│   │   │   ├── backend_paths.rs
│   │   │   ├── backend_proxy.rs
│   │   │   ├── backend_python.rs
│   │   │   ├── backend_support.rs
│   │   │   ├── config.rs
│   │   │   ├── lib.rs
│   │   │   ├── main.rs
│   │   │   ├── nextjs.rs
│   │   │   ├── shortcut.rs
│   │   │   └── tray.rs
│   │   ├── tauri.conf.json
│   │   ├── tauri.island.pyinstaller.json
│   │   ├── tauri.island.script.json
│   │   ├── tauri.lint.json
│   │   ├── tauri.web.pyinstaller.json
│   │   └── tauri.web.script.json
│   ├── tailwind.config.ts
│   └── tsconfig.json
├── lifetrace/
│   ├── __init__.py
│   ├── alembic.ini
│   ├── config/
│   │   ├── default_config.yaml
│   │   ├── prompt.yaml
│   │   ├── prompts/
│   │   │   ├── agno_tools/
│   │   │   │   ├── en/
│   │   │   │   │   ├── breakdown.yaml
│   │   │   │   │   ├── conflict.yaml
│   │   │   │   │   ├── instructions.yaml
│   │   │   │   │   ├── stats.yaml
│   │   │   │   │   ├── tags.yaml
│   │   │   │   │   ├── time.yaml
│   │   │   │   │   └── todo.yaml
│   │   │   │   └── zh/
│   │   │   │       ├── breakdown.yaml
│   │   │   │       ├── conflict.yaml
│   │   │   │       ├── instructions.yaml
│   │   │   │       ├── stats.yaml
│   │   │   │       ├── tags.yaml
│   │   │   │       ├── time.yaml
│   │   │   │       └── todo.yaml
│   │   │   ├── audio.yaml
│   │   │   ├── chat.yaml
│   │   │   ├── llm.yaml
│   │   │   ├── plan.yaml
│   │   │   ├── rag.yaml
│   │   │   ├── search.yaml
│   │   │   ├── summary.yaml
│   │   │   └── todo.yaml
│   │   └── rapidocr_config.yaml
│   ├── core/
│   │   ├── __init__.py
│   │   ├── config_watcher.py
│   │   ├── dependencies.py
│   │   ├── lazy_services.py
│   │   └── module_registry.py
│   ├── docs/
│   │   └── MIGRATION_GUIDE.md
│   ├── jobs/
│   │   ├── activity_aggregator.py
│   │   ├── clean_data.py
│   │   ├── deadline_reminder.py
│   │   ├── job_manager.py
│   │   ├── ocr.py
│   │   ├── ocr_config.py
│   │   ├── ocr_processor.py
│   │   ├── proactive_ocr/
│   │   │   ├── __init__.py
│   │   │   ├── capture.py
│   │   │   ├── models.py
│   │   │   ├── ocr_engine.py
│   │   │   ├── priors/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── base.py
│   │   │   │   ├── feishu.py
│   │   │   │   ├── registry.py
│   │   │   │   └── wechat.py
│   │   │   ├── roi.py
│   │   │   ├── router.py
│   │   │   └── service.py
│   │   ├── recorder.py
│   │   ├── recorder_blacklist.py
│   │   ├── recorder_capture.py
│   │   ├── recorder_config.py
│   │   ├── scheduler.py
│   │   └── todo_recorder.py
│   ├── llm/
│   │   ├── activity_summary_service.py
│   │   ├── agent_service.py
│   │   ├── agno_agent.py
│   │   ├── agno_tools/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── toolkit.py
│   │   │   └── tools/
│   │   │       ├── __init__.py
│   │   │       ├── breakdown_tools.py
│   │   │       ├── conflict_tools.py
│   │   │       ├── stats_tools.py
│   │   │       ├── tag_tools.py
│   │   │       ├── time_tools.py
│   │   │       └── todo_tools.py
│   │   ├── auto_todo_detection_service.py
│   │   ├── context_builder.py
│   │   ├── event_summary_clustering.py
│   │   ├── event_summary_config.py
│   │   ├── event_summary_ocr.py
│   │   ├── event_summary_service.py
│   │   ├── journal_generation_service.py
│   │   ├── llm_client.py
│   │   ├── llm_client_intent.py
│   │   ├── llm_client_query.py
│   │   ├── llm_client_vision.py
│   │   ├── ocr_todo_extractor.py
│   │   ├── rag_fallback.py
│   │   ├── rag_service.py
│   │   ├── rag_stream.py
│   │   ├── retrieval_service.py
│   │   ├── tavily_client.py
│   │   ├── todo_extraction_service.py
│   │   ├── tools/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── registry.py
│   │   │   └── web_search_tool.py
│   │   ├── vector_db.py
│   │   ├── vector_service.py
│   │   └── web_search_service.py
│   ├── migrations/
│   │   ├── MIGRATIONS.md
│   │   ├── README
│   │   ├── env.py
│   │   ├── re_extract_all_transcriptions.py
│   │   ├── script.py.mako
│   │   └── versions/
│   │       ├── 034079ad387f_add_segment_timestamps.py
│   │       ├── 4ca5036ec7c8_add_context_to_chats.py
│   │       ├── add_automation_tasks_001.py
│   │       ├── add_file_path_to_audio_recordings.py
│   │       ├── add_icalendar_fields_v2_001.py
│   │       ├── add_journal_panel_001.py
│   │       ├── add_optimized_extraction_fields.py
│   │       ├── add_text_hash_to_ocr_results.py
│   │       ├── add_todo_attachment_source_001.py
│   │       ├── add_todo_end_time_001.py
│   │       ├── add_todo_reminder_offsets_001.py
│   │       ├── add_todo_timezone_all_day_001.py
│   │       ├── b53d9b7c8e21_add_uid_to_journals.py
│   │       ├── cc25001eb19c_initial_schema.py
│   │       ├── cff6e6d7a3cf_merge_heads_segment_timestamps_and_.py
│   │       ├── d2f7a9c6b1a4_add_icalendar_fields_to_todos.py
│   │       ├── merge_automation_ical_001.py
│   │       ├── merge_heads_journal_todo_20260203.py
│   │       ├── merge_heads_todos_20260131.py
│   │       ├── merge_journal_uid_automation_20260204.py
│   │       └── remove_project_task_tables.py
│   ├── models/
│   │   ├── ch_PP-OCRv4_det_infer.onnx
│   │   ├── ch_PP-OCRv4_rec_infer.onnx
│   │   └── ch_ppocr_mobile_v2.0_cls_infer.onnx
│   ├── observability/
│   │   ├── __init__.py
│   │   ├── config.py
│   │   ├── exporters/
│   │   │   ├── __init__.py
│   │   │   ├── file_exporter.py
│   │   │   └── phoenix_exporter.py
│   │   └── setup.py
│   ├── pyinstaller.spec
│   ├── repositories/
│   │   ├── __init__.py
│   │   ├── interfaces.py
│   │   ├── sql_activity_repository.py
│   │   ├── sql_chat_repository.py
│   │   ├── sql_event_repository.py
│   │   ├── sql_journal_repository.py
│   │   └── sql_todo_repository.py
│   ├── routers/
│   │   ├── activity.py
│   │   ├── audio.py
│   │   ├── audio_ws.py
│   │   ├── audio_ws_handler.py
│   │   ├── audio_ws_segment.py
│   │   ├── automation.py
│   │   ├── chat/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── context.py
│   │   │   ├── core.py
│   │   │   ├── helpers.py
│   │   │   ├── message_todo_extraction.py
│   │   │   ├── misc.py
│   │   │   ├── modes/
│   │   │   │   ├── __init__.py
│   │   │   │   ├── agent.py
│   │   │   │   ├── agno.py
│   │   │   │   ├── dify.py
│   │   │   │   └── web_search.py
│   │   │   └── plan.py
│   │   ├── chat.py
│   │   ├── config.py
│   │   ├── cost_tracking.py
│   │   ├── event.py
│   │   ├── floating_capture.py
│   │   ├── health.py
│   │   ├── journal.py
│   │   ├── logs.py
│   │   ├── notification.py
│   │   ├── ocr.py
│   │   ├── proactive_ocr.py
│   │   ├── rag.py
│   │   ├── scheduler.py
│   │   ├── screenshot.py
│   │   ├── search.py
│   │   ├── system.py
│   │   ├── time_allocation.py
│   │   ├── todo.py
│   │   ├── todo_extraction.py
│   │   ├── vector.py
│   │   └── vision.py
│   ├── schemas/
│   │   ├── __init__.py
│   │   ├── activity.py
│   │   ├── automation.py
│   │   ├── chat.py
│   │   ├── event.py
│   │   ├── floating_capture.py
│   │   ├── journal.py
│   │   ├── message_todo_extraction.py
│   │   ├── screenshot.py
│   │   ├── search.py
│   │   ├── stats.py
│   │   ├── system.py
│   │   ├── todo.py
│   │   ├── todo_extraction.py
│   │   ├── vector.py
│   │   └── vision.py
│   ├── scripts/
│   │   ├── add_file_path_column.py
│   │   ├── build-backend.ps1
│   │   ├── build-backend.sh
│   │   ├── check_code_lines.py
│   │   ├── fix_audio_recordings_table.py
│   │   ├── fix_transcriptions_table.py
│   │   └── start_backend.py
│   ├── server.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── activity_service.py
│   │   ├── asr_client.py
│   │   ├── asr_client_dashscope.py
│   │   ├── audio_extraction_service.py
│   │   ├── audio_service.py
│   │   ├── automation_task_service.py
│   │   ├── chat_service.py
│   │   ├── config_service.py
│   │   ├── dify_client.py
│   │   ├── event_service.py
│   │   ├── icalendar_service.py
│   │   ├── journal_service.py
│   │   └── todo_service.py
│   ├── storage/
│   │   ├── __init__.py
│   │   ├── activity_manager.py
│   │   ├── automation_task_manager.py
│   │   ├── chat_manager.py
│   │   ├── database.py
│   │   ├── database_base.py
│   │   ├── event_manager.py
│   │   ├── event_queries.py
│   │   ├── event_stats.py
│   │   ├── journal_manager.py
│   │   ├── migrations/
│   │   │   └── journal_migration.py
│   │   ├── models.py
│   │   ├── notification_storage.py
│   │   ├── ocr_manager.py
│   │   ├── screenshot_manager.py
│   │   ├── sql_utils.py
│   │   ├── stats_manager.py
│   │   ├── todo_manager.py
│   │   ├── todo_manager_attachments.py
│   │   ├── todo_manager_ical.py
│   │   └── todo_manager_utils.py
│   └── util/
│       ├── app_utils.py
│       ├── base_paths.py
│       ├── image_utils.py
│       ├── language.py
│       ├── logging_config.py
│       ├── path_utils.py
│       ├── prompt_loader.py
│       ├── query_parser.py
│       ├── settings.py
│       ├── time_parser.py
│       ├── time_utils.py
│       ├── token_usage_logger.py
│       └── utils.py
├── pyproject.toml
├── pyrightconfig.json
├── requirements-runtime.txt
├── scripts/
│   ├── git-hooks/
│   │   └── post-checkout
│   ├── install.ps1
│   ├── install.sh
│   ├── link_worktree_deps.ps1
│   ├── link_worktree_deps.sh
│   ├── link_worktree_deps_here.ps1
│   ├── link_worktree_deps_here.sh
│   ├── new_worktree.py
│   ├── precommit_clippy.py
│   ├── precommit_rustfmt.py
│   ├── setup_hooks_here.ps1
│   └── setup_hooks_here.sh
└── tests/
    ├── conftest.py
    ├── test_icalendar_service.py
    ├── test_todo_serialization.py
    └── test_todo_service_mapping.py
Download .txt
Showing preview only (424K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (3969 symbols across 833 files)

FILE: free-todo-frontend/app/home/HomePageClient.tsx
  function HomePageClient (line 17) | function HomePageClient() {

FILE: free-todo-frontend/app/home/HomePageEntry.tsx
  function HomePageEntry (line 11) | function HomePageEntry() {

FILE: free-todo-frontend/app/island/layout.tsx
  function IslandLayout (line 20) | async function IslandLayout({

FILE: free-todo-frontend/app/island/page.tsx
  function IslandPage (line 16) | function IslandPage() {

FILE: free-todo-frontend/app/layout.tsx
  type RootLayoutProps (line 14) | interface RootLayoutProps {
  function RootLayout (line 23) | async function RootLayout({ children }: RootLayoutProps) {

FILE: free-todo-frontend/app/page.tsx
  function HomePage (line 3) | function HomePage() {

FILE: free-todo-frontend/apps/achievements/AchievementsPanel.tsx
  function AchievementsPanel (line 11) | function AchievementsPanel() {

FILE: free-todo-frontend/apps/activity/ActivityCard.tsx
  type ActivityCardProps (line 6) | interface ActivityCardProps {

FILE: free-todo-frontend/apps/activity/ActivityDetail.tsx
  type ActivityDetailProps (line 12) | interface ActivityDetailProps {
  function ActivityDetail (line 18) | function ActivityDetail({

FILE: free-todo-frontend/apps/activity/ActivityHeader.tsx
  type ActivityHeaderProps (line 13) | interface ActivityHeaderProps {
  function ActivityHeader (line 18) | function ActivityHeader({

FILE: free-todo-frontend/apps/activity/ActivityPanel.tsx
  function ActivityPanel (line 12) | function ActivityPanel() {

FILE: free-todo-frontend/apps/activity/ActivitySidebar.tsx
  type ActivitySidebarProps (line 6) | interface ActivitySidebarProps {
  function ActivitySidebar (line 13) | function ActivitySidebar({

FILE: free-todo-frontend/apps/activity/ActivitySummary.tsx
  type ActivitySummaryProps (line 4) | interface ActivitySummaryProps {
  function ActivitySummary (line 88) | function ActivitySummary({ summary }: ActivitySummaryProps) {

FILE: free-todo-frontend/apps/activity/utils/timeUtils.ts
  constant ONE_MINUTE (line 3) | const ONE_MINUTE = 60 * 1000;
  constant ONE_HOUR (line 4) | const ONE_HOUR = 60 * ONE_MINUTE;
  constant ONE_DAY (line 5) | const ONE_DAY = 24 * ONE_HOUR;
  function toDate (line 7) | function toDate(value?: string | null): Date | null {
  function isSameDay (line 13) | function isSameDay(a: Date, b: Date): boolean {
  function isYesterday (line 21) | function isYesterday(target: Date, now: Date): boolean {
  function isSameWeek (line 27) | function isSameWeek(target: Date, now: Date): boolean {
  function formatRelativeTime (line 38) | function formatRelativeTime(time?: string | null): string {
  function formatTimeRange (line 62) | function formatTimeRange(
  type ActivityGroup (line 82) | type ActivityGroup = {
  function groupActivitiesByTime (line 87) | function groupActivitiesByTime(activities: Activity[]): ActivityGroup[] {

FILE: free-todo-frontend/apps/audio/AudioPanel.tsx
  function AudioPanel (line 24) | function AudioPanel() {

FILE: free-todo-frontend/apps/audio/components/AudioExtractionPanel.tsx
  type TodoItem (line 9) | type TodoItem = {
  type ScheduleItem (line 22) | type ScheduleItem = {
  type ExtractionPanelProps (line 33) | interface ExtractionPanelProps {
  function AudioExtractionPanel (line 54) | function AudioExtractionPanel({

FILE: free-todo-frontend/apps/audio/components/AudioHeader.tsx
  type AudioHeaderProps (line 8) | interface AudioHeaderProps {
  function AudioHeader (line 18) | function AudioHeader({

FILE: free-todo-frontend/apps/audio/components/AudioList.tsx
  type AudioRecording (line 6) | interface AudioRecording {
  type AudioListProps (line 15) | interface AudioListProps {
  function AudioList (line 20) | function AudioList({ recordings, onPlay }: AudioListProps) {

FILE: free-todo-frontend/apps/audio/components/AudioPlayer.tsx
  type AudioPlayerProps (line 5) | interface AudioPlayerProps {
  function AudioPlayer (line 23) | function AudioPlayer({

FILE: free-todo-frontend/apps/audio/components/RecordingStatus.tsx
  type RecordingStatusProps (line 7) | interface RecordingStatusProps {
  function RecordingStatus (line 13) | function RecordingStatus({ isRecording, recordingStartedAt }: RecordingS...

FILE: free-todo-frontend/apps/audio/components/StopRecordingConfirm.tsx
  type StopRecordingConfirmProps (line 3) | interface StopRecordingConfirmProps {
  function StopRecordingConfirm (line 9) | function StopRecordingConfirm({ isOpen, onCancel, onConfirm }: StopRecor...

FILE: free-todo-frontend/apps/audio/components/TranscriptionView.tsx
  type TodoItem (line 7) | interface TodoItem {
  type ScheduleItem (line 15) | interface ScheduleItem {
  type TranscriptionViewProps (line 22) | interface TranscriptionViewProps {
  type TextSegment (line 40) | interface TextSegment {
  function TranscriptionView (line 45) | function TranscriptionView({

FILE: free-todo-frontend/apps/audio/hooks/useAudioData.ts
  type DateCacheData (line 13) | type DateCacheData = {
  constant MAX_CACHE_DAYS (line 26) | const MAX_CACHE_DAYS = 7;
  constant CACHE_EXPIRY_MS (line 27) | const CACHE_EXPIRY_MS = MAX_CACHE_DAYS * 24 * 60 * 60 * 1000;
  type TodoItem (line 29) | type TodoItem = {
  type ScheduleItem (line 40) | type ScheduleItem = {
  function useAudioData (line 51) | function useAudioData(

FILE: free-todo-frontend/apps/audio/hooks/useAudioDateSwitching.ts
  type UseAudioDateSwitchingProps (line 6) | interface UseAudioDateSwitchingProps {
  function useAudioDateSwitching (line 35) | function useAudioDateSwitching({

FILE: free-todo-frontend/apps/audio/hooks/useAudioLink.ts
  type TodoItem (line 6) | type TodoItem = {
  type ScheduleItem (line 17) | type ScheduleItem = {
  type ExtractionData (line 28) | type ExtractionData = {
  function useAudioLink (line 37) | function useAudioLink() {

FILE: free-todo-frontend/apps/audio/hooks/useAudioPlayback.ts
  function useAudioPlayback (line 5) | function useAudioPlayback() {

FILE: free-todo-frontend/apps/audio/hooks/useAudioRecording.ts
  function useAudioRecording (line 12) | function useAudioRecording() {

FILE: free-todo-frontend/apps/audio/hooks/useAudioRecordingControl.ts
  type UseAudioRecordingControlProps (line 8) | interface UseAudioRecordingControlProps {
  function useAudioRecordingControl (line 43) | function useAudioRecordingControl({

FILE: free-todo-frontend/apps/audio/hooks/useSegmentSync.ts
  type UseSegmentSyncOptions (line 5) | interface UseSegmentSyncOptions {
  type UseSegmentSyncReturn (line 16) | interface UseSegmentSyncReturn {
  function useSegmentSync (line 27) | function useSegmentSync({

FILE: free-todo-frontend/apps/audio/hooks/useStopRecordingConfirm.ts
  type UseStopRecordingConfirmOptions (line 6) | interface UseStopRecordingConfirmOptions {
  type UseStopRecordingConfirmReturn (line 13) | interface UseStopRecordingConfirmReturn {
  function useStopRecordingConfirm (line 26) | function useStopRecordingConfirm({

FILE: free-todo-frontend/apps/audio/utils/parseTimeToIsoWithDate.ts
  function parseTimeToIsoWithDate (line 6) | function parseTimeToIsoWithDate(raw: string | null | undefined, selected...

FILE: free-todo-frontend/apps/audio/utils/timeUtils.ts
  function parseLocalDate (line 13) | function parseLocalDate(dateStr: string | Date): Date {
  function toLocalISOString (line 40) | function toLocalISOString(date: Date): string {
  function calculateSegmentOffset (line 63) | function calculateSegmentOffset(
  function calculateSegmentAbsoluteTime (line 88) | function calculateSegmentAbsoluteTime(
  function isRecordingCrossDate (line 102) | function isRecordingCrossDate(
  function getSegmentDate (line 131) | function getSegmentDate(
  function formatDateTime (line 146) | function formatDateTime(date: Date): string {
  function formatTime (line 163) | function formatTime(seconds: number): string {
  function getDateString (line 175) | function getDateString(date: Date): string {
  function getLocalDateString (line 187) | function getLocalDateString(date: Date): string {
  function getLocalDateStringForCompare (line 199) | function getLocalDateStringForCompare(date: Date): string {

FILE: free-todo-frontend/apps/calendar/CalendarPanel.tsx
  function CalendarPanel (line 36) | function CalendarPanel() {

FILE: free-todo-frontend/apps/calendar/components/DayColumn.tsx
  function DayColumn (line 16) | function DayColumn({

FILE: free-todo-frontend/apps/calendar/components/DraggableTodo.tsx
  function DraggableTodo (line 16) | function DraggableTodo({

FILE: free-todo-frontend/apps/calendar/components/FloatingTodoCard.tsx
  function FloatingTodoCard (line 13) | function FloatingTodoCard({

FILE: free-todo-frontend/apps/calendar/components/QuickCreateBar.tsx
  function QuickCreateBar (line 10) | function QuickCreateBar({

FILE: free-todo-frontend/apps/calendar/components/QuickCreatePopover.tsx
  function QuickCreatePopover (line 14) | function QuickCreatePopover({

FILE: free-todo-frontend/apps/calendar/components/TimelineColumn.tsx
  constant MIN_ITEM_HEIGHT (line 20) | const MIN_ITEM_HEIGHT = 24;
  constant DEADLINE_HEIGHT (line 21) | const DEADLINE_HEIGHT = 20;
  constant MAX_TIMELINE_MINUTES (line 22) | const MAX_TIMELINE_MINUTES = 24 * 60 - MINUTES_PER_SLOT;
  type ResizePreview (line 24) | interface ResizePreview {
  function TimelineColumn (line 30) | function TimelineColumn({

FILE: free-todo-frontend/apps/calendar/components/TimelineCreatePopover.tsx
  function TimelineCreatePopover (line 14) | function TimelineCreatePopover({

FILE: free-todo-frontend/apps/calendar/components/TimelineSlot.tsx
  function TimelineSlot (line 11) | function TimelineSlot({

FILE: free-todo-frontend/apps/calendar/components/TimelineTodoCard.tsx
  function TimelineTodoCard (line 14) | function TimelineTodoCard({

FILE: free-todo-frontend/apps/calendar/hooks/useMonthScroll.ts
  type ScrollDirection (line 5) | type ScrollDirection = "prev" | "next";
  function getMonthKey (line 7) | function getMonthKey(date: Date) {
  function useMonthScroll (line 11) | function useMonthScroll({

FILE: free-todo-frontend/apps/calendar/types.ts
  type CalendarView (line 7) | type CalendarView = "month" | "week" | "day";
  type CalendarTodo (line 9) | interface CalendarTodo {
  type CalendarDay (line 18) | interface CalendarDay {
  type TimelineItem (line 23) | interface TimelineItem {
  function getStatusStyle (line 32) | function getStatusStyle(status: TodoStatus): string {
  function getScheduleSeverity (line 45) | function getScheduleSeverity(

FILE: free-todo-frontend/apps/calendar/utils.ts
  constant DEFAULT_NEW_TIME (line 5) | const DEFAULT_NEW_TIME = "09:00";
  constant DEFAULT_WORK_START_MINUTES (line 6) | const DEFAULT_WORK_START_MINUTES = 8 * 60;
  constant DEFAULT_WORK_END_MINUTES (line 7) | const DEFAULT_WORK_END_MINUTES = 22 * 60;
  constant MINUTES_PER_SLOT (line 8) | const MINUTES_PER_SLOT = 15;
  constant DEFAULT_DURATION_MINUTES (line 9) | const DEFAULT_DURATION_MINUTES = 30;
  function startOfDay (line 11) | function startOfDay(date: Date): Date {
  function endOfDay (line 17) | function endOfDay(date: Date): Date {
  function addDays (line 23) | function addDays(date: Date, days: number): Date {
  function addMonths (line 29) | function addMonths(date: Date, months: number): Date {
  function startOfWeek (line 35) | function startOfWeek(date: Date): Date {
  function startOfMonth (line 43) | function startOfMonth(date: Date): Date {
  function endOfMonth (line 47) | function endOfMonth(date: Date): Date {
  function getWeekOfYear (line 51) | function getWeekOfYear(date: Date): number {
  function toDateKey (line 63) | function toDateKey(date: Date): string {
  function parseTodoDateTime (line 70) | function parseTodoDateTime(value?: string): Date | null {
  function parseScheduleTime (line 85) | function parseScheduleTime(value?: string): Date | null {
  function parseDeadline (line 102) | function parseDeadline(deadline?: string): Date | null {
  function isAllDayDeadlineString (line 106) | function isAllDayDeadlineString(value?: string): boolean {
  function formatHumanDate (line 120) | function formatHumanDate(date: Date): string {
  function formatMonthLabel (line 124) | function formatMonthLabel(date: Date): string {
  function formatTimeLabel (line 128) | function formatTimeLabel(date: Date | null, allDayText: string): string {
  function formatTimeRangeLabel (line 135) | function formatTimeRangeLabel(start: number, end: number): string {
  function formatMinutesLabel (line 139) | function formatMinutesLabel(minutes: number): string {
  function isSameDay (line 145) | function isSameDay(a: Date, b: Date): boolean {
  function getMinutesFromDate (line 153) | function getMinutesFromDate(date: Date): number {
  function addMinutes (line 157) | function addMinutes(date: Date, minutes: number): Date {
  function setMinutesOnDate (line 163) | function setMinutesOnDate(date: Date, minutes: number): Date {
  function floorToMinutes (line 169) | function floorToMinutes(minutes: number, step = MINUTES_PER_SLOT): number {
  function ceilToMinutes (line 173) | function ceilToMinutes(minutes: number, step = MINUTES_PER_SLOT): number {
  function clampMinutes (line 177) | function clampMinutes(value: number, min: number, max: number): number {
  function buildMonthDays (line 181) | function buildMonthDays(
  function buildWeekDays (line 192) | function buildWeekDays(

FILE: free-todo-frontend/apps/calendar/views/DayView.tsx
  constant SLOT_HEIGHT (line 35) | const SLOT_HEIGHT = 12;
  type ParsedTodo (line 37) | interface ParsedTodo {
  function DayView (line 45) | function DayView({

FILE: free-todo-frontend/apps/calendar/views/MonthScroller.tsx
  type WeekKey (line 18) | type WeekKey = string;
  function getWeekKey (line 20) | function getWeekKey(date: Date): WeekKey {
  function MonthScroller (line 24) | function MonthScroller({

FILE: free-todo-frontend/apps/calendar/views/MonthView.tsx
  function MonthView (line 11) | function MonthView({

FILE: free-todo-frontend/apps/calendar/views/WeekView.tsx
  constant SLOT_HEIGHT (line 33) | const SLOT_HEIGHT = 12;
  type ParsedTodo (line 35) | interface ParsedTodo {
  function WeekView (line 43) | function WeekView({

FILE: free-todo-frontend/apps/calendar/views/useWeekViewActions.ts
  type UseWeekViewActionsParams (line 18) | interface UseWeekViewActionsParams {
  function useWeekViewActions (line 31) | function useWeekViewActions({

FILE: free-todo-frontend/apps/chat/ChatPanel.tsx
  function ChatPanel (line 17) | function ChatPanel() {

FILE: free-todo-frontend/apps/chat/components/breakdown/BreakdownStageRenderer.tsx
  type BreakdownStageRendererProps (line 12) | type BreakdownStageRendererProps = {
  function BreakdownStageRenderer (line 31) | function BreakdownStageRenderer({

FILE: free-todo-frontend/apps/chat/components/breakdown/BreakdownSummary.tsx
  type BreakdownSummaryProps (line 10) | interface BreakdownSummaryProps {
  function SubtaskTree (line 18) | function SubtaskTree({
  function BreakdownSummary (line 44) | function BreakdownSummary({

FILE: free-todo-frontend/apps/chat/components/breakdown/Questionnaire.tsx
  type QuestionnaireProps (line 9) | interface QuestionnaireProps {
  function Questionnaire (line 18) | function Questionnaire({

FILE: free-todo-frontend/apps/chat/components/input/ChatInputSection.tsx
  type ChatInputSectionProps (line 10) | type ChatInputSectionProps = {
  function ChatInputSection (line 29) | function ChatInputSection({

FILE: free-todo-frontend/apps/chat/components/input/InputBox.tsx
  type InputBoxProps (line 7) | type InputBoxProps = {
  constant MIN_TEXTAREA_HEIGHT (line 28) | const MIN_TEXTAREA_HEIGHT = 24;
  constant SINGLE_LINE_ROWS (line 30) | const SINGLE_LINE_ROWS = 1;
  constant MULTI_LINE_ROWS (line 32) | const MULTI_LINE_ROWS = 1;
  function InputBox (line 34) | function InputBox({

FILE: free-todo-frontend/apps/chat/components/input/LinkedTodos.tsx
  type LinkedTodosProps (line 4) | type LinkedTodosProps = {
  function LinkedTodos (line 14) | function LinkedTodos({

FILE: free-todo-frontend/apps/chat/components/input/PromptSuggestions.tsx
  type PromptSuggestion (line 8) | type PromptSuggestion = {
  type PromptSuggestionsProps (line 15) | type PromptSuggestionsProps = {
  function PromptSuggestions (line 20) | function PromptSuggestions({

FILE: free-todo-frontend/apps/chat/components/input/ToolSelector.tsx
  constant FREETODO_TOOLS (line 13) | const FREETODO_TOOLS = [
  constant EXTERNAL_TOOLS (line 40) | const EXTERNAL_TOOLS = [
  type ToolSelectorProps (line 51) | interface ToolSelectorProps {
  function ToolSelector (line 61) | function ToolSelector({ disabled = false }: ToolSelectorProps) {

FILE: free-todo-frontend/apps/chat/components/layout/HeaderBar.tsx
  type HeaderBarProps (line 10) | type HeaderBarProps = {
  function HeaderBar (line 17) | function HeaderBar({

FILE: free-todo-frontend/apps/chat/components/layout/HistoryDrawer.tsx
  type HistoryDrawerProps (line 5) | type HistoryDrawerProps = {
  function HistoryDrawer (line 20) | function HistoryDrawer({

FILE: free-todo-frontend/apps/chat/components/layout/WelcomeGreetings.tsx
  type WelcomeGreetingsProps (line 7) | type WelcomeGreetingsProps = {
  function WelcomeGreetings (line 11) | function WelcomeGreetings({

FILE: free-todo-frontend/apps/chat/components/message/EditModeMessage.tsx
  type EditModeMessageProps (line 16) | type EditModeMessageProps = {
  type BlockAppendState (line 27) | type BlockAppendState = {
  function EditModeMessage (line 58) | function EditModeMessage({

FILE: free-todo-frontend/apps/chat/components/message/MarkdownComponents.tsx
  type MessageRole (line 4) | type MessageRole = "user" | "assistant";
  function createMarkdownComponents (line 10) | function createMarkdownComponents(

FILE: free-todo-frontend/apps/chat/components/message/MessageContent.tsx
  type MessageContentProps (line 14) | type MessageContentProps = {
  function MessageContent (line 18) | function MessageContent({ message }: MessageContentProps) {

FILE: free-todo-frontend/apps/chat/components/message/MessageContextMenu.tsx
  type MessageContextMenuProps (line 10) | type MessageContextMenuProps = {
  function MessageContextMenu (line 20) | function MessageContextMenu({

FILE: free-todo-frontend/apps/chat/components/message/MessageItem.tsx
  type MessageItemProps (line 17) | type MessageItemProps = {
  function MessageItem (line 28) | function MessageItem({

FILE: free-todo-frontend/apps/chat/components/message/MessageList.tsx
  type MessageListProps (line 12) | type MessageListProps = {
  function MessageList (line 19) | function MessageList({

FILE: free-todo-frontend/apps/chat/components/message/MessageSources.tsx
  type MessageSourcesProps (line 5) | type MessageSourcesProps = {
  function MessageSources (line 10) | function MessageSources({ sources, messageId }: MessageSourcesProps) {

FILE: free-todo-frontend/apps/chat/components/message/MessageTodoExtractionModal.tsx
  type ExtractedTodo (line 11) | interface ExtractedTodo {
  type MessageTodoExtractionModalProps (line 21) | interface MessageTodoExtractionModalProps {
  function MessageTodoExtractionModal (line 36) | function MessageTodoExtractionModal({

FILE: free-todo-frontend/apps/chat/components/message/MessageTodoExtractionPanel.tsx
  type ExtractedTodo (line 10) | interface ExtractedTodo {
  type MessageTodoExtractionPanelProps (line 16) | interface MessageTodoExtractionPanelProps {
  function MessageTodoExtractionPanel (line 23) | function MessageTodoExtractionPanel({

FILE: free-todo-frontend/apps/chat/components/message/SummaryStreaming.tsx
  type SummaryStreamingProps (line 8) | interface SummaryStreamingProps {
  function SummaryStreaming (line 41) | function SummaryStreaming({ streamingText }: SummaryStreamingProps) {

FILE: free-todo-frontend/apps/chat/components/message/ToolCallLoading.tsx
  type ToolCallLoadingProps (line 5) | type ToolCallLoadingProps = {
  function ToolCallLoading (line 11) | function ToolCallLoading({

FILE: free-todo-frontend/apps/chat/components/message/ToolCallSteps.tsx
  type ToolCallStepsProps (line 8) | type ToolCallStepsProps = {
  function ToolCallSteps (line 17) | function ToolCallSteps({ steps, className }: ToolCallStepsProps) {
  type ToolCallStepItemProps (line 33) | type ToolCallStepItemProps = {
  function ToolCallStepItem (line 41) | function ToolCallStepItem({ step, t }: ToolCallStepItemProps) {

FILE: free-todo-frontend/apps/chat/components/message/utils/messageContentUtils.ts
  constant TOOL_CALL_PATTERN (line 3) | const TOOL_CALL_PATTERN = /\[使用工具:\s*([^|\]]+)(?:\s*\|\s*([^\]]+))?\]/g;
  constant TOOL_EVENT_PREFIX (line 4) | const TOOL_EVENT_PREFIX = "[TOOL_EVENT:";
  constant TOOL_EVENT_SUFFIX (line 5) | const TOOL_EVENT_SUFFIX = "]";
  type ToolCall (line 7) | type ToolCall = {
  function extractToolCalls (line 16) | function extractToolCalls(content: string): Array<ToolCall> {
  function removeToolCalls (line 37) | function removeToolCalls(content: string): string {
  function removeToolEvents (line 44) | function removeToolEvents(content: string): string {
  type WebSearchSources (line 77) | type WebSearchSources = Array<{ title: string; url: string }>;
  type ParsedWebSearchMessage (line 79) | type ParsedWebSearchMessage = {
  function parseWebSearchMessage (line 87) | function parseWebSearchMessage(content: string): ParsedWebSearchMessage {
  function processBodyWithCitations (line 126) | function processBodyWithCitations(

FILE: free-todo-frontend/apps/chat/hooks/useBreakdownService.ts
  type GenerateQuestionsResponse (line 6) | interface GenerateQuestionsResponse {
  type GenerateSummaryResponse (line 10) | interface GenerateSummaryResponse {

FILE: free-todo-frontend/apps/chat/hooks/useChatController.ts
  type UseChatControllerParams (line 17) | type UseChatControllerParams = {

FILE: free-todo-frontend/apps/chat/hooks/useChatPrompts.ts
  type ChatPromptsResponse (line 8) | interface ChatPromptsResponse {
  function loadPrompts (line 27) | async function loadPrompts() {

FILE: free-todo-frontend/apps/chat/hooks/useMessageExtraction.ts
  type ExtractionState (line 8) | type ExtractionState = {
  type UseMessageExtractionParams (line 18) | type UseMessageExtractionParams = {
  function useMessageExtraction (line 26) | function useMessageExtraction({

FILE: free-todo-frontend/apps/chat/hooks/useMessageScroll.ts
  function useMessageScroll (line 7) | function useMessageScroll(

FILE: free-todo-frontend/apps/chat/hooks/usePlanParser.ts
  type TranslationFunction (line 8) | type TranslationFunction = (
  type ChatPromptsResponse (line 13) | interface ChatPromptsResponse {
  function loadPrompts (line 27) | async function loadPrompts() {

FILE: free-todo-frontend/apps/chat/hooks/useSendMessage.ts
  type UseSendMessageParams (line 31) | interface UseSendMessageParams {
  type SendMessageReturn (line 70) | interface SendMessageReturn {

FILE: free-todo-frontend/apps/chat/hooks/useSessionCache.ts
  type SessionCacheReturn (line 7) | interface SessionCacheReturn {

FILE: free-todo-frontend/apps/chat/hooks/useSessionManager.ts
  type ToolEvent (line 9) | type ToolEvent = {
  type UseSessionManagerParams (line 20) | interface UseSessionManagerParams {
  type SessionManagerReturn (line 52) | interface SessionManagerReturn {

FILE: free-todo-frontend/apps/chat/hooks/useStreamController.ts
  type CreateRequestResult (line 7) | interface CreateRequestResult {
  type StreamControllerReturn (line 17) | interface StreamControllerReturn {

FILE: free-todo-frontend/apps/chat/hooks/useToolCallTracker.ts
  type ToolCallTrackerReturn (line 8) | interface ToolCallTrackerReturn {

FILE: free-todo-frontend/apps/chat/types.ts
  type ToolCallStatus (line 6) | type ToolCallStatus = "running" | "completed" | "error";
  type ToolCallStep (line 11) | type ToolCallStep = {
  type ChatMessage (line 31) | type ChatMessage = {
  type ChatMode (line 39) | type ChatMode = "agno";
  type ParsedTodo (line 41) | type ParsedTodo = Pick<
  type ParsedTodoTree (line 46) | type ParsedTodoTree = ParsedTodo & { subtasks?: ParsedTodoTree[] };
  type EditContentBlock (line 49) | type EditContentBlock = {

FILE: free-todo-frontend/apps/chat/utils/messageBuilder.ts
  type BuildPayloadMessageParams (line 4) | interface BuildPayloadMessageParams {
  type PayloadMessageResult (line 13) | interface PayloadMessageResult {

FILE: free-todo-frontend/apps/chat/utils/parseEditBlocks.ts
  function parseEditBlocks (line 29) | function parseEditBlocks(content: string): EditContentBlock[] {
  function extractAppendToMarker (line 103) | function extractAppendToMarker(content: string): {
  function getCleanBlockContent (line 129) | function getCleanBlockContent(block: EditContentBlock): string {

FILE: free-todo-frontend/apps/chat/utils/responseHandlers.ts
  function handleStreamError (line 7) | function handleStreamError(
  function handleEmptyResponse (line 41) | function handleEmptyResponse(

FILE: free-todo-frontend/apps/chat/utils/todoContext.ts
  type TranslationFunction (line 3) | type TranslationFunction = (

FILE: free-todo-frontend/apps/cost-tracking/CostTrackingPanel.tsx
  constant DEFAULT_DAYS (line 16) | const DEFAULT_DAYS = 30;
  function CostTrackingPanel (line 18) | function CostTrackingPanel() {

FILE: free-todo-frontend/apps/debug/DebugCapturePanel.tsx
  function DebugCapturePanel (line 22) | function DebugCapturePanel() {
  type DateGroupProps (line 232) | interface DateGroupProps {
  function DateGroup (line 248) | function DateGroup({
  type LoadingIndicatorProps (line 310) | interface LoadingIndicatorProps {
  function LoadingIndicator (line 319) | function LoadingIndicator({

FILE: free-todo-frontend/apps/debug/components/EventCard.tsx
  type EventCardProps (line 15) | interface EventCardProps {
  function EventCard (line 30) | function EventCard({
  type ScreenshotThumbnailsProps (line 180) | interface ScreenshotThumbnailsProps {
  function ScreenshotThumbnails (line 191) | function ScreenshotThumbnails({

FILE: free-todo-frontend/apps/debug/components/EventSearchForm.tsx
  type EventSearchFormProps (line 6) | interface EventSearchFormProps {
  function EventSearchForm (line 20) | function EventSearchForm({

FILE: free-todo-frontend/apps/debug/components/ScreenshotModal.tsx
  type ScreenshotModalProps (line 10) | interface ScreenshotModalProps {
  function ScreenshotModal (line 20) | function ScreenshotModal({

FILE: free-todo-frontend/apps/debug/components/SelectedEventsBar.tsx
  type SelectedEventsBarProps (line 6) | interface SelectedEventsBarProps {
  function SelectedEventsBar (line 17) | function SelectedEventsBar({

FILE: free-todo-frontend/apps/debug/hooks/useEventActions.ts
  type ExtractionResult (line 16) | interface ExtractionResult {
  type TranslationFunction (line 22) | type TranslationFunction = (
  type UseEventActionsOptions (line 27) | interface UseEventActionsOptions {
  function useEventActions (line 37) | function useEventActions({

FILE: free-todo-frontend/apps/debug/hooks/useEventData.ts
  constant PAGE_SIZE (line 14) | const PAGE_SIZE = 10;
  type EventDetail (line 17) | interface EventDetail {
  type GroupedEvents (line 22) | interface GroupedEvents {
  function useEventData (line 31) | function useEventData() {

FILE: free-todo-frontend/apps/debug/utils.ts
  function formatDate (line 8) | function formatDate(date: Date): string {
  constant WHITELIST_APPS (line 19) | const WHITELIST_APPS = [
  function isWhitelistApp (line 34) | function isWhitelistApp(appName: string | null | undefined): boolean {

FILE: free-todo-frontend/apps/diary/DiaryEditor.tsx
  type DiaryEditorProps (line 8) | interface DiaryEditorProps {
  function DiaryEditor (line 27) | function DiaryEditor({

FILE: free-todo-frontend/apps/diary/DiaryHeader.tsx
  type DiaryHeaderProps (line 7) | interface DiaryHeaderProps {
  function DiaryHeader (line 19) | function DiaryHeader({

FILE: free-todo-frontend/apps/diary/DiaryPanel.tsx
  function DiaryPanel (line 53) | function DiaryPanel() {

FILE: free-todo-frontend/apps/diary/DiarySettings.tsx
  type DiarySettingsProps (line 7) | interface DiarySettingsProps {
  function DiarySettings (line 26) | function DiarySettings({

FILE: free-todo-frontend/apps/diary/DiaryTabs.tsx
  type JournalTab (line 6) | type JournalTab = "original" | "objective" | "ai";
  type DiaryTabsProps (line 8) | interface DiaryTabsProps {
  function DiaryTabs (line 13) | function DiaryTabs({ activeTab, onChange }: DiaryTabsProps) {

FILE: free-todo-frontend/apps/diary/JournalHistory.tsx
  type JournalHistoryProps (line 6) | interface JournalHistoryProps {
  function JournalHistory (line 18) | function JournalHistory({

FILE: free-todo-frontend/apps/diary/types.ts
  type JournalDraft (line 1) | interface JournalDraft {

FILE: free-todo-frontend/apps/settings/SettingsPanel.tsx
  constant SETTINGS_CATEGORY_IDS (line 35) | const SETTINGS_CATEGORY_IDS: SettingsCategoryId[] = [
  function SettingsPanel (line 47) | function SettingsPanel() {

FILE: free-todo-frontend/apps/settings/components/AudioAsrConfigSection.tsx
  type AudioAsrConfigSectionProps (line 11) | interface AudioAsrConfigSectionProps {
  function AudioAsrConfigSection (line 20) | function AudioAsrConfigSection({ config, loading = false }: AudioAsrConf...

FILE: free-todo-frontend/apps/settings/components/AudioConfigSection.tsx
  type AudioConfigSectionProps (line 10) | interface AudioConfigSectionProps {
  function AudioConfigSection (line 19) | function AudioConfigSection({

FILE: free-todo-frontend/apps/settings/components/AutoTodoDetectionSection.tsx
  type AutoTodoDetectionSectionProps (line 12) | interface AutoTodoDetectionSectionProps {
  function AutoTodoDetectionSection (line 20) | function AutoTodoDetectionSection({

FILE: free-todo-frontend/apps/settings/components/AutomationTasksSection.tsx
  type AutomationTasksSectionProps (line 25) | interface AutomationTasksSectionProps {
  function AutomationTasksSection (line 29) | function AutomationTasksSection({

FILE: free-todo-frontend/apps/settings/components/DifyConfigSection.tsx
  type DifyConfigSectionProps (line 10) | interface DifyConfigSectionProps {
  function DifyConfigSection (line 20) | function DifyConfigSection({

FILE: free-todo-frontend/apps/settings/components/DockDisplayModeSection.tsx
  type DockDisplayModeSectionProps (line 9) | interface DockDisplayModeSectionProps {
  function DockDisplayModeSection (line 16) | function DockDisplayModeSection({

FILE: free-todo-frontend/apps/settings/components/JournalSettingsSection.tsx
  function JournalSettingsSection (line 9) | function JournalSettingsSection() {

FILE: free-todo-frontend/apps/settings/components/LlmConfigSection.tsx
  type LlmConfigSectionProps (line 14) | interface LlmConfigSectionProps {
  function LlmConfigSection (line 22) | function LlmConfigSection({

FILE: free-todo-frontend/apps/settings/components/NotificationPermissionSection.tsx
  type PermissionStatus (line 10) | type PermissionStatus =
  type TauriNotificationApi (line 17) | type TauriNotificationApi = {
  type NotificationPermissionSectionProps (line 41) | interface NotificationPermissionSectionProps {
  function NotificationPermissionSection (line 45) | function NotificationPermissionSection({

FILE: free-todo-frontend/apps/settings/components/OnboardingSection.tsx
  type OnboardingSectionProps (line 8) | interface OnboardingSectionProps {
  function OnboardingSection (line 16) | function OnboardingSection({ loading = false }: OnboardingSectionProps) {

FILE: free-todo-frontend/apps/settings/components/PanelSwitchesSection.tsx
  type PanelSwitchesSectionProps (line 17) | interface PanelSwitchesSectionProps {
  function PanelSwitchesSection (line 24) | function PanelSwitchesSection({

FILE: free-todo-frontend/apps/settings/components/RecorderConfigSection.tsx
  type RecorderConfigSectionProps (line 11) | interface RecorderConfigSectionProps {
  function RecorderConfigSection (line 20) | function RecorderConfigSection({

FILE: free-todo-frontend/apps/settings/components/SchedulerSection.tsx
  constant LEGACY_JOB_IDS (line 24) | const LEGACY_JOB_IDS = ["task_context_mapper_job", "task_summary_job"];
  type SchedulerSectionProps (line 26) | interface SchedulerSectionProps {
  function SchedulerSection (line 33) | function SchedulerSection({ loading = false }: SchedulerSectionProps) {

FILE: free-todo-frontend/apps/settings/components/SettingsCategoryPanel.tsx
  type SettingsCategoryId (line 8) | type SettingsCategoryId =
  type SettingsCategory (line 15) | interface SettingsCategory {
  type SettingsCategoryPanelProps (line 22) | interface SettingsCategoryPanelProps {
  function SettingsCategoryPanel (line 30) | function SettingsCategoryPanel({

FILE: free-todo-frontend/apps/settings/components/SettingsSearchAction.tsx
  type SettingsSearchActionProps (line 12) | interface SettingsSearchActionProps {
  function SettingsSearchAction (line 17) | function SettingsSearchAction({

FILE: free-todo-frontend/apps/settings/components/SettingsSection.tsx
  function SettingsSearchProvider (line 16) | function SettingsSearchProvider({
  function SettingsSearchMatchProvider (line 30) | function SettingsSearchMatchProvider({
  type SettingsSectionProps (line 60) | interface SettingsSectionProps {
  function SettingsSection (line 70) | function SettingsSection({

FILE: free-todo-frontend/apps/settings/components/TavilyConfigSection.tsx
  type TavilyConfigSectionProps (line 12) | interface TavilyConfigSectionProps {
  function TavilyConfigSection (line 22) | function TavilyConfigSection({

FILE: free-todo-frontend/apps/settings/components/ToggleSwitch.tsx
  type ToggleSwitchProps (line 3) | interface ToggleSwitchProps {
  function ToggleSwitch (line 14) | function ToggleSwitch({

FILE: free-todo-frontend/apps/settings/components/VersionInfoSection.tsx
  function VersionInfoSection (line 9) | function VersionInfoSection() {

FILE: free-todo-frontend/apps/settings/hooks/useSettingsSearchMatchStats.ts
  type UseSettingsSearchMatchStatsOptions (line 6) | interface UseSettingsSearchMatchStatsOptions {
  function useSettingsSearchMatchStats (line 11) | function useSettingsSearchMatchStats({

FILE: free-todo-frontend/apps/todo-detail/TodoDetail.tsx
  function TodoDetail (line 36) | function TodoDetail() {

FILE: free-todo-frontend/apps/todo-detail/components/ArtifactsView.tsx
  type ArtifactsViewProps (line 20) | interface ArtifactsViewProps {
  function ArtifactsView (line 41) | function ArtifactsView({

FILE: free-todo-frontend/apps/todo-detail/components/AttachmentPreviewPanel.tsx
  type AttachmentPreviewPanelProps (line 9) | interface AttachmentPreviewPanelProps {
  function AttachmentPreviewPanel (line 26) | function AttachmentPreviewPanel({

FILE: free-todo-frontend/apps/todo-detail/components/BackgroundSection.tsx
  type BackgroundSectionProps (line 10) | interface BackgroundSectionProps {
  function BackgroundSection (line 17) | function BackgroundSection({

FILE: free-todo-frontend/apps/todo-detail/components/ChildTodoSection.tsx
  type ChildTodoSectionProps (line 16) | interface ChildTodoSectionProps {
  function ChildTodoSection (line 27) | function ChildTodoSection({

FILE: free-todo-frontend/apps/todo-detail/components/DatePickerCalendar.tsx
  type MonthNavigationProps (line 15) | interface MonthNavigationProps {
  function MonthNavigation (line 23) | function MonthNavigation({
  type WeekdayHeaderProps (line 67) | interface WeekdayHeaderProps {
  function WeekdayHeader (line 71) | function WeekdayHeader({ tCalendar }: WeekdayHeaderProps) {
  type CalendarGridProps (line 89) | interface CalendarGridProps {
  function CalendarGrid (line 98) | function CalendarGrid({

FILE: free-todo-frontend/apps/todo-detail/components/DatePickerPopover.tsx
  type DatePickerPopoverProps (line 36) | interface DatePickerPopoverProps {
  constant POPOVER_MARGIN (line 48) | const POPOVER_MARGIN = 8;
  type TabKey (line 50) | type TabKey = "date" | "range";
  type DateTarget (line 52) | type DateTarget = "start" | "end";
  function DatePickerPopover (line 54) | function DatePickerPopover({

FILE: free-todo-frontend/apps/todo-detail/components/DatePickerSidePanel.tsx
  type TabKey (line 9) | type TabKey = "date" | "range";
  type DateTarget (line 10) | type DateTarget = "start" | "end";
  type DatePickerSidePanelProps (line 12) | interface DatePickerSidePanelProps {
  function DatePickerSidePanel (line 33) | function DatePickerSidePanel({

FILE: free-todo-frontend/apps/todo-detail/components/DetailHeader.tsx
  type DetailHeaderProps (line 11) | interface DetailHeaderProps {
  function DetailHeader (line 18) | function DetailHeader({

FILE: free-todo-frontend/apps/todo-detail/components/DetailTitle.tsx
  type DetailTitleProps (line 6) | interface DetailTitleProps {
  function DetailTitle (line 11) | function DetailTitle({ name, onNameChange }: DetailTitleProps) {

FILE: free-todo-frontend/apps/todo-detail/components/MetaSection.tsx
  type MetaSectionProps (line 17) | interface MetaSectionProps {
  function MetaSection (line 25) | function MetaSection({

FILE: free-todo-frontend/apps/todo-detail/components/NotesEditor.tsx
  type NotesEditorProps (line 13) | interface NotesEditorProps {
  function NotesEditor (line 21) | function NotesEditor({

FILE: free-todo-frontend/apps/todo-detail/components/datePickerUtils.ts
  constant FALLBACK_TIMEZONES (line 8) | const FALLBACK_TIMEZONES = [
  constant DEFAULT_TIME (line 18) | const DEFAULT_TIME = "09:00";
  constant DEFAULT_RANGE_MINUTES (line 19) | const DEFAULT_RANGE_MINUTES = 60;

FILE: free-todo-frontend/apps/todo-detail/hooks/useNotesAutosize.ts
  function useNotesAutosize (line 3) | function useNotesAutosize(deps: unknown[]) {

FILE: free-todo-frontend/apps/todo-detail/utils/date-utils.ts
  type CalendarDay (line 12) | interface CalendarDay {
  function startOfDay (line 28) | function startOfDay(date: Date): Date {
  function addDays (line 39) | function addDays(date: Date, days: number): Date {
  function startOfWeek (line 48) | function startOfWeek(date: Date): Date {
  function startOfMonth (line 59) | function startOfMonth(date: Date): Date {
  function toDateKey (line 66) | function toDateKey(date: Date): string {
  function buildMonthDays (line 78) | function buildMonthDays(currentDate: Date): CalendarDay[] {
  constant WEEKDAY_KEYS (line 98) | const WEEKDAY_KEYS = [
  type WeekdayKey (line 108) | type WeekdayKey = (typeof WEEKDAY_KEYS)[number];

FILE: free-todo-frontend/apps/todo-detail/utils/holiday-utils.ts
  type HolidayInfo (line 9) | interface HolidayInfo {
  type YearHolidayConfig (line 19) | type YearHolidayConfig = Record<string, HolidayInfo>;
  constant HOLIDAYS_2025 (line 25) | const HOLIDAYS_2025: YearHolidayConfig = {
  constant HOLIDAYS_2026 (line 39) | const HOLIDAYS_2026: YearHolidayConfig = {
  constant HOLIDAYS_BY_YEAR (line 49) | const HOLIDAYS_BY_YEAR: Record<number, YearHolidayConfig> = {
  function getHolidayInfo (line 59) | function getHolidayInfo(date: Date): HolidayInfo | null {
  function isHoliday (line 78) | function isHoliday(date: Date): boolean {
  function isWorkday (line 88) | function isWorkday(date: Date): boolean {

FILE: free-todo-frontend/apps/todo-detail/utils/lunar-utils.ts
  constant LUNAR_INFO (line 10) | const LUNAR_INFO = [
  constant LUNAR_MONTH (line 40) | const LUNAR_MONTH = [
  constant LUNAR_DAY (line 56) | const LUNAR_DAY = [
  constant SOLAR_TERMS (line 90) | const SOLAR_TERMS = [
  constant SOLAR_TERM_DAYS (line 118) | const SOLAR_TERM_DAYS: Record<string, number[]> = {
  function lYearDays (line 136) | function lYearDays(y: number): number {
  function leapMonth (line 148) | function leapMonth(y: number): number {
  function leapDays (line 155) | function leapDays(y: number): number {
  function monthDays (line 165) | function monthDays(y: number, m: number): number {
  type LunarDate (line 172) | interface LunarDate {
  function getLunarDate (line 183) | function getLunarDate(date: Date): LunarDate {
  function getLunarDayText (line 238) | function getLunarDayText(date: Date): string {

FILE: free-todo-frontend/apps/todo-list/CreateTodoForm.tsx
  type CreateTodoFormProps (line 9) | interface CreateTodoFormProps {
  function CreateTodoForm (line 13) | function CreateTodoForm({ onSuccess }: CreateTodoFormProps) {

FILE: free-todo-frontend/apps/todo-list/NewTodoInlineForm.tsx
  type NewTodoInlineFormProps (line 8) | interface NewTodoInlineFormProps {
  function NewTodoInlineForm (line 15) | function NewTodoInlineForm({

FILE: free-todo-frontend/apps/todo-list/TodoCard.tsx
  type TodoCardProps (line 23) | interface TodoCardProps {
  function TodoCard (line 34) | function TodoCard({

FILE: free-todo-frontend/apps/todo-list/TodoExtractionModal.tsx
  type TodoExtractionModalProps (line 12) | interface TodoExtractionModalProps {
  function TodoExtractionModal (line 20) | function TodoExtractionModal({

FILE: free-todo-frontend/apps/todo-list/TodoList.tsx
  function TodoList (line 27) | function TodoList() {

FILE: free-todo-frontend/apps/todo-list/TodoToolbar.tsx
  type TodoToolbarProps (line 16) | interface TodoToolbarProps {
  function TodoToolbar (line 24) | function TodoToolbar({

FILE: free-todo-frontend/apps/todo-list/TodoTreeList.tsx
  type TodoTreeListProps (line 18) | interface TodoTreeListProps {
  function TodoTreeList (line 25) | function TodoTreeList({

FILE: free-todo-frontend/apps/todo-list/components/TodoCardCheckbox.tsx
  type TodoCardCheckboxProps (line 6) | interface TodoCardCheckboxProps {
  function TodoCardCheckbox (line 11) | function TodoCardCheckbox({ todo, onToggle }: TodoCardCheckboxProps) {

FILE: free-todo-frontend/apps/todo-list/components/TodoCardChildForm.tsx
  type TodoCardChildFormProps (line 5) | interface TodoCardChildFormProps {
  function TodoCardChildForm (line 13) | function TodoCardChildForm({

FILE: free-todo-frontend/apps/todo-list/components/TodoCardDropZone.tsx
  type TodoCardDropZoneProps (line 6) | interface TodoCardDropZoneProps {
  function TodoCardDropZone (line 10) | function TodoCardDropZone({ droppable }: TodoCardDropZoneProps) {

FILE: free-todo-frontend/apps/todo-list/components/TodoCardExpandButton.tsx
  type TodoCardExpandButtonProps (line 5) | interface TodoCardExpandButtonProps {
  function TodoCardExpandButton (line 11) | function TodoCardExpandButton({

FILE: free-todo-frontend/apps/todo-list/components/TodoCardMetadata.tsx
  type TodoCardMetadataProps (line 5) | interface TodoCardMetadataProps {
  function TodoCardMetadata (line 9) | function TodoCardMetadata({ todo }: TodoCardMetadataProps) {

FILE: free-todo-frontend/apps/todo-list/components/TodoCardName.tsx
  type TodoCardNameProps (line 5) | interface TodoCardNameProps {
  function TodoCardName (line 16) | function TodoCardName({

FILE: free-todo-frontend/apps/todo-list/components/TodoFilter.tsx
  type DueTimeFilter (line 10) | type DueTimeFilter =
  type TodoFilterState (line 19) | interface TodoFilterState {
  type TodoFilterProps (line 25) | interface TodoFilterProps {
  function TodoFilter (line 31) | function TodoFilter({ todos, filter, onFilterChange }: TodoFilterProps) {

FILE: free-todo-frontend/apps/todo-list/hooks/useOrderedTodos.ts
  type OrderedTodo (line 6) | type OrderedTodo = {
  function isDueTimeMatch (line 11) | function isDueTimeMatch(todo: Todo, dueTimeFilter: DueTimeFilter): boole...
  function useOrderedTodos (line 68) | function useOrderedTodos(

FILE: free-todo-frontend/apps/todo-list/hooks/useTodoCardDrag.ts
  type UseTodoCardDragParams (line 9) | interface UseTodoCardDragParams {
  function useTodoCardDrag (line 15) | function useTodoCardDrag({

FILE: free-todo-frontend/apps/todo-list/hooks/useTodoCardHandlers.ts
  type UseTodoCardHandlersParams (line 10) | interface UseTodoCardHandlersParams {
  function useTodoCardHandlers (line 20) | function useTodoCardHandlers({

FILE: free-todo-frontend/apps/todo-list/hooks/useTodoCardState.ts
  function useTodoCardState (line 4) | function useTodoCardState(todo: Todo) {

FILE: free-todo-frontend/apps/todo-list/utils/todoCardUtils.ts
  function formatScheduleLabel (line 6) | function formatScheduleLabel(
  function getPriorityBorderColor (line 50) | function getPriorityBorderColor(priority: TodoPriority): string {

FILE: free-todo-frontend/components/common/ReminderOptions.tsx
  type ReminderOptionsProps (line 13) | interface ReminderOptionsProps {
  function ReminderOptions (line 20) | function ReminderOptions({

FILE: free-todo-frontend/components/common/context-menu/BaseContextMenu.tsx
  type MenuItem (line 8) | interface MenuItem {
  type BaseContextMenuProps (line 18) | interface BaseContextMenuProps {
  function BaseContextMenu (line 40) | function BaseContextMenu({
  function useContextMenu (line 130) | function useContextMenu() {

FILE: free-todo-frontend/components/common/context-menu/MultiTodoContextMenu.tsx
  type MultiTodoContextMenuProps (line 15) | interface MultiTodoContextMenuProps {
  function MultiTodoContextMenu (line 20) | function MultiTodoContextMenu({

FILE: free-todo-frontend/components/common/context-menu/TodoContextMenu.tsx
  type TodoContextMenuProps (line 18) | interface TodoContextMenuProps {
  function TodoContextMenu (line 27) | function TodoContextMenu({

FILE: free-todo-frontend/components/common/layout/CollapsibleSection.tsx
  type CollapsibleSectionProps (line 7) | interface CollapsibleSectionProps {
  function CollapsibleSection (line 19) | function CollapsibleSection({

FILE: free-todo-frontend/components/common/layout/LayoutSelector.tsx
  type LayoutSelectorProps (line 28) | interface LayoutSelectorProps {
  function LayoutSelector (line 42) | function LayoutSelector({

FILE: free-todo-frontend/components/common/layout/LayoutSelectorDialogs.tsx
  type LayoutFormMode (line 28) | type LayoutFormMode = "save" | "rename";
  type LayoutFormState (line 30) | interface LayoutFormState {
  type OverwriteConfirmState (line 36) | interface OverwriteConfirmState {
  type Translator (line 42) | type Translator = ReturnType<typeof useTranslations>;
  type LayoutSelectorDialogsProps (line 44) | interface LayoutSelectorDialogsProps {
  function LayoutSelectorDialogs (line 61) | function LayoutSelectorDialogs({

FILE: free-todo-frontend/components/common/layout/PanelHeader.tsx
  type PanelIconStyleConfig (line 40) | interface PanelIconStyleConfig {
  type PanelActionButtonStyleConfig (line 54) | interface PanelActionButtonStyleConfig {
  constant DEFAULT_HEADER_ICON_STYLE (line 79) | const DEFAULT_HEADER_ICON_STYLE: PanelIconStyleConfig = {
  constant DEFAULT_ACTION_ICON_STYLE (line 90) | const DEFAULT_ACTION_ICON_STYLE: PanelIconStyleConfig = {
  constant DEFAULT_ACTION_BUTTON_STYLE (line 107) | const DEFAULT_ACTION_BUTTON_STYLE: PanelActionButtonStyleConfig = {
  constant PRIMARY_ACTION_BUTTON_STYLE (line 120) | const PRIMARY_ACTION_BUTTON_STYLE: PanelActionButtonStyleConfig = {
  constant DESTRUCTIVE_ACTION_BUTTON_STYLE (line 128) | const DESTRUCTIVE_ACTION_BUTTON_STYLE: PanelActionButtonStyleConfig = {
  type PanelIconConfigContextValue (line 139) | interface PanelIconConfigContextValue {
  function PanelIconConfigProvider (line 164) | function PanelIconConfigProvider({
  function usePanelIconStyle (line 212) | function usePanelIconStyle(
  function usePanelActionButtonStyle (line 235) | function usePanelActionButtonStyle(
  type PanelActionButtonProps (line 266) | interface PanelActionButtonProps
  function PanelActionButton (line 280) | function PanelActionButton({
  function usePanelPosition (line 315) | function usePanelPosition(): PanelPosition | null {
  function PanelPositionProvider (line 319) | function PanelPositionProvider({
  function PanelHeaderMenu (line 333) | function PanelHeaderMenu({ position }: { position: PanelPosition }) {
  type PanelHeaderProps (line 446) | interface PanelHeaderProps {
  function PanelHeader (line 461) | function PanelHeader({

FILE: free-todo-frontend/components/common/layout/SectionHeader.tsx
  type SectionHeaderProps (line 7) | interface SectionHeaderProps {
  function SectionHeader (line 18) | function SectionHeader({

FILE: free-todo-frontend/components/common/theme/ThemeProvider.tsx
  type ThemeProviderProps (line 7) | interface ThemeProviderProps {
  function ColorThemeApplier (line 11) | function ColorThemeApplier() {
  function ThemeProvider (line 22) | function ThemeProvider({ children }: ThemeProviderProps) {

FILE: free-todo-frontend/components/common/theme/ThemeStyleSelect.tsx
  function ThemeStyleSelect (line 9) | function ThemeStyleSelect() {

FILE: free-todo-frontend/components/common/theme/ThemeToggle.tsx
  function ThemeToggle (line 8) | function ThemeToggle() {

FILE: free-todo-frontend/components/common/ui/BackendReadyGate.tsx
  type BackendReadyGateProps (line 7) | interface BackendReadyGateProps {
  function getBackendHealthUrl (line 11) | function getBackendHealthUrl(): string {
  function BackendReadyGate (line 16) | function BackendReadyGate({ children }: BackendReadyGateProps) {

FILE: free-todo-frontend/components/common/ui/CapabilitiesSync.tsx
  type CapabilitiesResponse (line 9) | type CapabilitiesResponse = {
  function computeBackendDisabledFeatures (line 16) | function computeBackendDisabledFeatures(
  function CapabilitiesSync (line 37) | function CapabilitiesSync() {

FILE: free-todo-frontend/components/common/ui/DockTriggerZone.tsx
  function DockTriggerZone (line 13) | function DockTriggerZone() {

FILE: free-todo-frontend/components/common/ui/FrontendBoot.tsx
  function FrontendBoot (line 1) | function FrontendBoot() {

FILE: free-todo-frontend/components/common/ui/LanguageToggle.tsx
  function LanguageToggle (line 9) | function LanguageToggle() {

FILE: free-todo-frontend/components/common/ui/LocaleSync.tsx
  function syncLocaleToCookie (line 12) | function syncLocaleToCookie(locale: string) {
  function LocaleSync (line 30) | function LocaleSync() {

FILE: free-todo-frontend/components/common/ui/ScrollbarController.tsx
  function ScrollbarController (line 10) | function ScrollbarController() {

FILE: free-todo-frontend/components/common/ui/SettingsToggle.tsx
  function SettingsToggle (line 14) | function SettingsToggle() {

FILE: free-todo-frontend/components/common/ui/UserAvatar.tsx
  function UserAvatar (line 6) | function UserAvatar() {

FILE: free-todo-frontend/components/date-picker/DateOnlyPickerCalendar.tsx
  type MonthNavigationProps (line 15) | interface MonthNavigationProps {
  function MonthNavigation (line 22) | function MonthNavigation({
  type WeekdayHeaderProps (line 56) | interface WeekdayHeaderProps {
  function WeekdayHeader (line 60) | function WeekdayHeader({ tCalendar }: WeekdayHeaderProps) {
  type CalendarGridProps (line 78) | interface CalendarGridProps {
  function CalendarGrid (line 84) | function CalendarGrid({

FILE: free-todo-frontend/components/date-picker/DateOnlyPickerPopover.tsx
  type DateOnlyPickerPopoverProps (line 17) | interface DateOnlyPickerPopoverProps {
  constant POPOVER_MARGIN (line 24) | const POPOVER_MARGIN = 8;
  function DateOnlyPickerPopover (line 26) | function DateOnlyPickerPopover({

FILE: free-todo-frontend/components/date-picker/date-picker-utils.ts
  type CalendarDay (line 3) | interface CalendarDay {
  constant WEEKDAY_KEYS (line 50) | const WEEKDAY_KEYS = [
  type WeekdayKey (line 60) | type WeekdayKey = (typeof WEEKDAY_KEYS)[number];

FILE: free-todo-frontend/components/island/DynamicIsland.tsx
  type DynamicIslandProps (line 19) | interface DynamicIslandProps {

FILE: free-todo-frontend/components/island/IslandContent.tsx
  type IconButtonProps (line 27) | interface IconButtonProps {
  type FloatContentProps (line 54) | interface FloatContentProps {
  type PopupContentProps (line 112) | interface PopupContentProps {

FILE: free-todo-frontend/components/island/IslandFullscreenContent.tsx
  type IslandFullscreenContentProps (line 18) | interface IslandFullscreenContentProps {
  function IslandFullscreenContent (line 22) | function IslandFullscreenContent({ onModeChange }: IslandFullscreenConte...

FILE: free-todo-frontend/components/island/IslandHeader.tsx
  type IslandHeaderProps (line 22) | interface IslandHeaderProps {
  function IslandHeader (line 35) | function IslandHeader({ mode, onModeChange, isExpanded = false, onDragSt...

FILE: free-todo-frontend/components/island/IslandSidebarContent.tsx
  type IslandSidebarContentProps (line 23) | interface IslandSidebarContentProps {
  function IslandSidebarContent (line 31) | function IslandSidebarContent({ onModeChange, onHeaderDragStart, isDragg...

FILE: free-todo-frontend/components/layout/AppHeader.tsx
  type AppHeaderProps (line 18) | interface AppHeaderProps {
  function AppHeader (line 23) | function AppHeader({ hasNotifications = false }: AppHeaderProps) {

FILE: free-todo-frontend/components/layout/BottomDock.tsx
  constant DOCK_ANIMATION_CONFIG (line 18) | const DOCK_ANIMATION_CONFIG = {
  constant DOCK_TRIGGER_ZONE (line 28) | const DOCK_TRIGGER_ZONE = 80;
  constant HIDE_DELAY_MS (line 29) | const HIDE_DELAY_MS = 1000;
  constant DOCK_BOTTOM_OFFSET (line 30) | const DOCK_BOTTOM_OFFSET = 12;
  constant PANEL_VISIBLE_OFFSET (line 31) | const PANEL_VISIBLE_OFFSET = 8;
  type BottomDockProps (line 33) | interface BottomDockProps {
  type DockItem (line 45) | interface DockItem {
  constant FEATURE_LABEL_MAP (line 54) | const FEATURE_LABEL_MAP: Partial<Record<PanelFeature, string>> = {
  function getFeatureLabelKey (line 69) | function getFeatureLabelKey(feature: PanelFeature): string {
  type DockItemButtonProps (line 74) | interface DockItemButtonProps {
  function DockItemButton (line 85) | function DockItemButton({
  function BottomDock (line 201) | function BottomDock({

FILE: free-todo-frontend/components/layout/FullscreenHeader.tsx
  type MaximizeHeaderProps (line 15) | interface MaximizeHeaderProps {
  function MaximizeHeader (line 19) | function MaximizeHeader({ hasNotifications }: MaximizeHeaderProps) {

FILE: free-todo-frontend/components/layout/PanelContainer.tsx
  type PanelContainerProps (line 10) | interface PanelContainerProps {
  constant ANIMATION_CONFIG (line 20) | const ANIMATION_CONFIG = {
  function PanelContainer (line 29) | function PanelContainer({

FILE: free-todo-frontend/components/layout/PanelContent.tsx
  type PanelContentProps (line 16) | interface PanelContentProps {
  function PanelContent (line 20) | function PanelContent({ position }: PanelContentProps) {

FILE: free-todo-frontend/components/layout/PanelRegion.tsx
  constant BOTTOM_DOCK_HEIGHT (line 14) | const BOTTOM_DOCK_HEIGHT = 60;
  constant DOCK_MARGIN_TOP (line 16) | const DOCK_MARGIN_TOP = 0;
  type PanelRegionProps (line 18) | interface PanelRegionProps {
  function PanelRegion (line 46) | function PanelRegion({

FILE: free-todo-frontend/components/layout/PanelSelectorMenu.tsx
  type PanelSelectorMenuProps (line 12) | interface PanelSelectorMenuProps {
  function getFeatureLabelKey (line 21) | function getFeatureLabelKey(feature: PanelFeature): string {
  function PanelSelectorMenu (line 25) | function PanelSelectorMenu({

FILE: free-todo-frontend/components/layout/ResizeHandle.tsx
  type ResizeHandleProps (line 11) | interface ResizeHandleProps {
  constant ANIMATION_CONFIG (line 18) | const ANIMATION_CONFIG = {
  function ResizeHandle (line 27) | function ResizeHandle({

FILE: free-todo-frontend/components/notification/HeaderIsland.tsx
  function formatTime (line 14) | function formatTime(
  function formatCurrentTime (line 40) | function formatCurrentTime(t: ReturnType<typeof useTranslations>): {
  function HeaderIsland (line 59) | function HeaderIsland() {

FILE: free-todo-frontend/components/ui/button.tsx
  type ButtonVariant (line 7) | type ButtonVariant = "default" | "outline" | "ghost" | "destructive";
  type ButtonSize (line 8) | type ButtonSize = "default" | "sm" | "lg" | "icon";
  type ButtonProps (line 10) | interface ButtonProps

FILE: free-todo-frontend/electron/backend-server.ts
  class BackendServer (line 33) | class BackendServer extends ProcessManager {
    method constructor (line 53) | constructor() {
    method getServerMode (line 73) | getServerMode(): ServerMode {
    method resolveBackendPaths (line 81) | private resolveBackendPaths(): void {
    method checkBackendExists (line 122) | private checkBackendExists(): boolean {
    method isLifeTraceBackend (line 150) | private async isLifeTraceBackend(port: number): Promise<boolean> {
    method detectRunningBackendPort (line 201) | async detectRunningBackendPort(): Promise<number | null> {
    method setPort (line 231) | setPort(port: number): void {
    method waitForReadyAndVerify (line 239) | async waitForReadyAndVerify(timeout: number): Promise<void> {
    method ensureHealthCheck (line 250) | ensureHealthCheck(): void {
    method start (line 259) | async start(options?: { waitForReady?: boolean }): Promise<void> {
    method verifyBackendMode (line 469) | private async verifyBackendMode(): Promise<void> {

FILE: free-todo-frontend/electron/bootstrap-control.ts
  function isCancelled (line 11) | function isCancelled(): boolean {
  function setActiveProcess (line 15) | function setActiveProcess(proc: ChildProcess | null): void {
  function clearActiveProcess (line 19) | function clearActiveProcess(proc: ChildProcess | null): void {
  function onCancel (line 25) | function onCancel(handler: () => void): () => void {
  function cancelBootstrap (line 30) | function cancelBootstrap(): void {

FILE: free-todo-frontend/electron/bootstrap-status.ts
  type BootstrapStatus (line 7) | type BootstrapStatus = {
  function emitStatus (line 19) | function emitStatus(status: BootstrapStatus): void {
  function emitLog (line 23) | function emitLog(line: string): void {
  function emitComplete (line 27) | function emitComplete(): void {
  function onStatus (line 31) | function onStatus(handler: (status: BootstrapStatus) => void): void {
  function onLog (line 35) | function onLog(handler: (line: string) => void): void {
  function onComplete (line 39) | function onComplete(handler: () => void): void {

FILE: free-todo-frontend/electron/bootstrap-window.ts
  function getBootstrapHtml (line 11) | function getBootstrapHtml(): string {
  function createBootstrapWindow (line 224) | function createBootstrapWindow(): BrowserWindow {
  function getBootstrapWindow (line 278) | function getBootstrapWindow(): BrowserWindow | null {
  function closeBootstrapWindow (line 282) | function closeBootstrapWindow(): void {

FILE: free-todo-frontend/electron/config.ts
  type ServerMode (line 13) | type ServerMode = "dev" | "build";
  function getServerMode (line 19) | function getServerMode(): ServerMode {
  constant PORT_RANGES (line 46) | const PORT_RANGES = {
  constant PORT_CONFIG (line 63) | const PORT_CONFIG = {
  method default (line 67) | get default(): number {
  method default (line 80) | get default(): number {
  constant TIMEOUT_CONFIG (line 95) | const TIMEOUT_CONFIG = {
  constant HEALTH_CHECK_INTERVAL (line 111) | const HEALTH_CHECK_INTERVAL = {
  constant WINDOW_CONFIG (line 121) | const WINDOW_CONFIG = {
  type WindowMode (line 139) | type WindowMode = "island" | "web";
  type BackendRuntime (line 153) | type BackendRuntime = "script" | "pyinstaller";
  function getWindowMode (line 168) | function getWindowMode(): WindowMode {
  function getBackendRuntime (line 199) | function getBackendRuntime(): BackendRuntime {
  constant LOG_CONFIG (line 223) | const LOG_CONFIG = {
  constant PROCESS_CONFIG (line 233) | const PROCESS_CONFIG = {
  function isDevelopment (line 253) | function isDevelopment(isPackaged: boolean): boolean {

FILE: free-todo-frontend/electron/git-info.ts
  function getGitCommit (line 6) | function getGitCommit(): string | null {

FILE: free-todo-frontend/electron/global-shortcut-manager.ts
  type ShortcutConfig (line 14) | interface ShortcutConfig {
  class GlobalShortcutManager (line 27) | class GlobalShortcutManager {
    method constructor (line 59) | constructor(islandWindowManager: IslandWindowManager) {
    method registerDefaults (line 67) | registerDefaults(): void {
    method register (line 97) | register(
    method unregister (line 140) | unregister(name: string): void {
    method unregisterAll (line 162) | unregisterAll(): void {
    method isRegistered (line 180) | isRegistered(accelerator: string): boolean {
    method getShortcuts (line 188) | getShortcuts(): Map<string, ShortcutConfig> {
    method updateShortcut (line 199) | updateShortcut(name: string, newAccelerator: string): boolean {
    method setupCleanup (line 238) | private setupCleanup(): void {

FILE: free-todo-frontend/electron/ipc-handlers-todo-capture.ts
  type JimpScanContext (line 11) | type JimpScanContext = {
  function sendToBackend (line 20) | async function sendToBackend(
  function maskWindowArea (line 106) | async function maskWindowArea(
  function setupTodoCaptureIpcHandlers (line 197) | function setupTodoCaptureIpcHandlers(

FILE: free-todo-frontend/electron/ipc-handlers.ts
  function setupIpcHandlers (line 21) | function setupIpcHandlers(
  function setupIslandIpcHandlers (line 113) | function setupIslandIpcHandlers(islandWindowManager: IslandWindowManager...

FILE: free-todo-frontend/electron/island-window-manager.ts
  type IslandMode (line 13) | enum IslandMode {
  constant ISLAND_SIZES (line 23) | const ISLAND_SIZES: Record<IslandMode, { width: number; height: number }...
  class IslandWindowManager (line 33) | class IslandWindowManager {
    method getPreloadPath (line 53) | private getPreloadPath(): string {
    method calculateRightAlignedX (line 64) | private calculateRightAlignedX(width: number): number {
    method calculateYPosition (line 73) | private calculateYPosition(height: number, preferredY?: number): number {
    method calculateSmartSidebarPosition (line 93) | private calculateSmartSidebarPosition(
    method getSizeForMode (line 155) | private getSizeForMode(mode: IslandMode): { width: number; height: num...
    method create (line 166) | create(serverUrl: string): void {
    method setupIpcHandlers (line 241) | private setupIpcHandlers(): void {
    method setupCustomDragHandlers (line 272) | private setupCustomDragHandlers(): void {
    method resizeToMode (line 342) | resizeToMode(mode: IslandMode): void {
    method resizeSidebarToColumns (line 416) | resizeSidebarToColumns(columnCount: 1 | 2 | 3): void {
    method show (line 457) | show(): void {
    method hide (line 468) | hide(): void {
    method toggle (line 479) | toggle(): void {
    method destroy (line 492) | destroy(): void {
    method getWindow (line 503) | getWindow(): BrowserWindow | null {
    method isEnabled (line 510) | isEnabled(): boolean {
    method hasWindow (line 517) | hasWindow(): boolean {
    method getCurrentMode (line 524) | getCurrentMode(): IslandMode {
    method sendMessage (line 531) | sendMessage(channel: string, ...args: unknown[]): void {
    method setVisibilityChangeCallback (line 541) | setVisibilityChangeCallback(callback: (visible: boolean) => void): void {
    method notifyVisibilityChange (line 549) | private notifyVisibilityChange(visible: boolean): void {
    method isVisible (line 564) | isVisible(): boolean {
    method setSidebarPinned (line 572) | setSidebarPinned(isPinned: boolean): void {

FILE: free-todo-frontend/electron/logger.ts
  type LogLevel (line 14) | type LogLevel = "INFO" | "WARN" | "ERROR" | "FATAL";
  class Logger (line 20) | class Logger {
    method constructor (line 24) | constructor() {
    method ensureLogDir (line 34) | private ensureLogDir(): void {
    method getTodayDateString (line 47) | private getTodayDateString(): string {
    method generateLogFileName (line 59) | private generateLogFileName(): string {
    method writeStartMarker (line 90) | private writeStartMarker(): void {
    method write (line 106) | private write(level: LogLevel, message: string, source?: string): void {
    method getLogFilePath (line 120) | getLogFilePath(): string {
    method info (line 127) | info(message: string, source?: string): void {
    method warn (line 134) | warn(message: string, source?: string): void {
    method error (line 141) | error(message: string, source?: string): void {
    method fatal (line 148) | fatal(message: string, source?: string): void {
    method stdout (line 155) | stdout(source: string, data: string): void {
    method stderr (line 165) | stderr(source: string, data: string): void {
    method errorWithStack (line 175) | errorWithStack(message: string, error: Error, source?: string): void {
    method console (line 185) | console(message: string, source?: string): void {
    method consoleError (line 193) | consoleError(message: string, source?: string): void {
    method writeEndMarker (line 201) | writeEndMarker(): void {

FILE: free-todo-frontend/electron/main.ts
  function setupGlobalErrorHandlers (line 240) | function setupGlobalErrorHandlers(): void {
  function attachBootstrapHandlers (line 253) | function attachBootstrapHandlers(): void {
  function confirmStopInstallation (line 300) | async function confirmStopInstallation(): Promise<void> {
  function waitForBootstrapContinue (line 321) | function waitForBootstrapContinue(): Promise<void> {
  function bootstrap (line 330) | async function bootstrap(
  function logStartupInfo (line 468) | function logStartupInfo(): void {
  function handleStartupError (line 481) | function handleStartupError(error: unknown): void {
  function cleanup (line 507) | function cleanup(

FILE: free-todo-frontend/electron/next-server.ts
  function setNextProcessRef (line 21) | function setNextProcessRef(_proc: { killed: boolean } | null): void {
  function stopHealthCheck (line 25) | function stopHealthCheck(): void {
  function waitForServer (line 29) | function waitForServer(url: string, timeout: number): Promise<void> {
  function getNextProcess (line 66) | function getNextProcess(): ChildProcess | null {
  function setNextProcess (line 73) | function setNextProcess(proc: ChildProcess | null): void {
  function getActualFrontendPort (line 84) | function getActualFrontendPort(): number {
  function setActualFrontendPort (line 91) | function setActualFrontendPort(port: number): void {
  function setBackendUrl (line 104) | function setBackendUrl(url: string): void {
  function getBackendUrl (line 111) | function getBackendUrl(): string {
  function startNextServer (line 119) | async function startNextServer(): Promise<void> {
  function stopNextServer (line 454) | function stopNextServer(): void {
  function getServerUrl (line 474) | function getServerUrl(): string {
  function waitForServerPublic (line 481) | async function waitForServerPublic(

FILE: free-todo-frontend/electron/notification.ts
  type NotificationData (line 13) | interface NotificationData {
  function requestNotificationPermission (line 30) | async function requestNotificationPermission(): Promise<void> {
  function showSystemNotification (line 41) | function showSystemNotification(

FILE: free-todo-frontend/electron/port-manager.ts
  class PortManager (line 14) | class PortManager {
    method isPortAvailable (line 20) | async isPortAvailable(port: number): Promise<boolean> {
    method findAvailablePort (line 40) | async findAvailablePort(

FILE: free-todo-frontend/electron/preload.ts
  type NotificationData (line 11) | interface NotificationData {
  function setTransparentBackground (line 21) | function setTransparentBackground() {

FILE: free-todo-frontend/electron/process-manager.ts
  type ServerConfig (line 14) | interface ServerConfig {
  method constructor (line 47) | constructor(config: ServerConfig, defaultPort: number) {
  method getUrl (line 60) | getUrl(): string {
  method getPort (line 67) | getPort(): number {
  method isRunning (line 74) | isRunning(): boolean {
  method stop (line 83) | stop(waitForExit = false): Promise<void> | void {
  method isIntentionallyStopping (line 122) | isIntentionallyStopping(): boolean {
  method waitForReady (line 131) | protected waitForReady(url: string, timeout: number): Promise<void> {
  method startHealthCheck (line 189) | protected startHealthCheck(): void {
  method stopHealthCheck (line 237) | protected stopHealthCheck(): void {
  method setupProcessOutputListeners (line 248) | protected setupProcessOutputListeners(proc: ChildProcess): void {
  method getOutputBuffers (line 283) | getOutputBuffers(): { stdout: string; stderr: string } {
  method clearOutputBuffers (line 293) | clearOutputBuffers(): void {

FILE: free-todo-frontend/electron/python-runtime-command.ts
  type CommandResult (line 13) | type CommandResult = {
  type CommandOptions (line 19) | type CommandOptions = {
  function runCommand (line 27) | async function runCommand(

FILE: free-todo-frontend/electron/python-runtime-env.ts
  constant PIP_INDEX_CN (line 9) | const PIP_INDEX_CN = "https://pypi.tuna.tsinghua.edu.cn/simple";
  constant PIP_INDEX_GLOBAL (line 10) | const PIP_INDEX_GLOBAL = "https://pypi.org/simple";
  function isMainlandChina (line 15) | function isMainlandChina(): boolean {
  function getPipEnv (line 41) | function getPipEnv(): NodeJS.ProcessEnv {
  function getUvEnv (line 66) | function getUvEnv(): NodeJS.ProcessEnv {
  function configureCondaMirror (line 82) | async function configureCondaMirror(): Promise<void> {

FILE: free-todo-frontend/electron/python-runtime-installer.ts
  constant PYTHON_VERSION_FALLBACK (line 15) | const PYTHON_VERSION_FALLBACK = "3.12.9";
  constant PYTHON_DOWNLOAD_BASE (line 16) | const PYTHON_DOWNLOAD_BASE = "https://www.python.org/ftp/python";
  constant PYTHON_RELEASES_API (line 17) | const PYTHON_RELEASES_API =
  type PythonRelease (line 20) | type PythonRelease = {
  function fetchJson (line 25) | async function fetchJson<T>(url: string): Promise<T> {
  function compareSemver (line 56) | function compareSemver(a: string, b: string): number {
  function getLatestPython312Version (line 70) | async function getLatestPython312Version(): Promise<string> {
  function downloadFile (line 92) | async function downloadFile(
  function installPythonWindows (line 136) | async function installPythonWindows(version: string): Promise<void> {
  function installPythonMac (line 190) | async function installPythonMac(version: string): Promise<void> {
  function installPythonLinux (line 213) | async function installPythonLinux(): Promise<void> {
  function installPython312 (line 238) | async function installPython312(): Promise<void> {

FILE: free-todo-frontend/electron/python-runtime.ts
  constant REQUIRED_PYTHON_MAJOR (line 17) | const REQUIRED_PYTHON_MAJOR = 3;
  constant REQUIRED_PYTHON_MINOR (line 18) | const REQUIRED_PYTHON_MINOR = 12;
  constant PYTHON_VERSION_SHORT (line 19) | const PYTHON_VERSION_SHORT = `${REQUIRED_PYTHON_MAJOR}.${REQUIRED_PYTHON...
  constant DEP_MARKER_FILE (line 20) | const DEP_MARKER_FILE = ".freetodo-deps.json";
  constant RUNTIME_MANIFEST_FILE (line 21) | const RUNTIME_MANIFEST_FILE = ".freetodo-runtime.json";
  type PythonInfo (line 25) | type PythonInfo = {
  function setPreferredPythonPath (line 32) | function setPreferredPythonPath(value: string | null): void {
  function getVenvPythonPath (line 36) | function getVenvPythonPath(venvDir: string): string {
  function getVenvUvPath (line 43) | function getVenvUvPath(venvDir: string): string {
  function readFileHash (line 50) | function readFileHash(filePath: string): string {
  function readDepsMarker (line 55) | function readDepsMarker(venvDir: string): { requirementsHash?: string } ...
  type RuntimeManifest (line 68) | type RuntimeManifest = {
  function readRuntimeManifest (line 75) | function readRuntimeManifest(runtimeRoot: string): RuntimeManifest | null {
  function writeRuntimeManifest (line 88) | function writeRuntimeManifest(runtimeRoot: string, manifest: RuntimeMani...
  function writeDepsMarker (line 93) | function writeDepsMarker(venvDir: string, requirementsHash: string): void {
  function isRequiredPython (line 102) | function isRequiredPython(version: string): boolean {
  function normalizeOutput (line 106) | function normalizeOutput(value: string): string {
  function assertNotCancelled (line 110) | function assertNotCancelled(): void {
  function getVersionFromOutput (line 116) | function getVersionFromOutput(output: string): PythonInfo | null {
  function getPythonInfo (line 142) | async function getPythonInfo(command: string, args: string[]): Promise<P...
  function validatePythonPath (line 154) | async function validatePythonPath(pythonPath: string): Promise<PythonInf...
  function isRuntimePrepared (line 161) | function isRuntimePrepared(
  function findInstalledPython312 (line 184) | async function findInstalledPython312(): Promise<PythonInfo | null> {
  function ensurePython312Installed (line 241) | async function ensurePython312Installed(): Promise<PythonInfo> {
  function ensureVenv (line 309) | async function ensureVenv(
  function ensureUvInVenv (line 333) | async function ensureUvInVenv(
  function ensureDependencies (line 358) | async function ensureDependencies(
  function ensureVenvPythonVersion (line 398) | async function ensureVenvPythonVersion(venvPython: string): Promise<bool...
  function ensurePythonRuntime (line 403) | async function ensurePythonRuntime(

FILE: free-todo-frontend/electron/runtime-paths.ts
  function getInstallRoot (line 11) | function getInstallRoot(): string {
  function canWrite (line 21) | function canWrite(dir: string): boolean {
  function resolveRuntimeRoot (line 33) | function resolveRuntimeRoot(): string {
  function resolveVenvDir (line 57) | function resolveVenvDir(): string {

FILE: free-todo-frontend/electron/tray-manager.ts
  class TrayManager (line 16) | class TrayManager {
    method constructor (line 28) | constructor(islandWindowManager: IslandWindowManager) {
    method create (line 40) | create(): void {
    method getTrayIconPath (line 79) | private getTrayIconPath(): string | null {
    method buildContextMenu (line 99) | private buildContextMenu(): void {
    method setupEventHandlers (line 156) | private setupEventHandlers(): void {
    method toggleIsland (line 178) | private toggleIsland(): void {
    method updateTrayIcon (line 191) | private updateTrayIcon(): void {
    method onIslandVisibilityChange (line 211) | private onIslandVisibilityChange(visible: boolean): void {
    method show (line 219) | show(): void {
    method hide (line 227) | hide(): void {
    method updateMenu (line 236) | updateMenu(): void {
    method destroy (line 243) | destroy(): void {
    method getTray (line 254) | getTray(): Tray | null {
    method startRecording (line 263) | private startRecording(): void {
    method stopRecording (line 271) | private stopRecording(): void {
    method takeScreenshot (line 279) | private takeScreenshot(): void {
    method viewScreenshots (line 287) | private viewScreenshots(): void {
    method openPreferences (line 295) | private openPreferences(): void {

FILE: free-todo-frontend/electron/window-manager.ts
  class WindowManager (line 18) | class WindowManager {
    method getPreloadPath (line 32) | private getPreloadPath(): string {
    method waitForServer (line 46) | private async waitForServer(url: string, timeout: number): Promise<voi...
    method getOriginalBounds (line 79) | getOriginalBounds(): typeof this.originalBounds {
    method create (line 87) | create(
    method load (line 275) | load(serverUrl: string): void {
    method getLoadingPageHtml (line 284) | private getLoadingPageHtml(): string {
    method focus (line 317) | focus(): void {
    method getWindow (line 329) | getWindow(): BrowserWindow | null {
    method hasWindow (line 337) | hasWindow(): boolean {
    method hasAnyWindows (line 344) | static hasAnyWindows(): boolean {

FILE: free-todo-frontend/global.d.ts
  type Messages (line 3) | type Messages = typeof messages;
  type IntlMessages (line 7) | interface IntlMessages extends Messages {}
  type CookieStoreSetOptions (line 10) | interface CookieStoreSetOptions {
  type CookieStoreApi (line 22) | interface CookieStoreApi {
  type Window (line 29) | interface Window {

FILE: free-todo-frontend/lib/api.ts
  function getStreamApiBaseUrl (line 5) | function getStreamApiBaseUrl(): string {
  type SendChatParams (line 14) | interface SendChatParams {
  type ToolCallEventType (line 29) | type ToolCallEventType =
  type ToolCallEvent (line 38) | interface ToolCallEvent {
  constant TOOL_EVENT_PREFIX (line 46) | const TOOL_EVENT_PREFIX = "\n[TOOL_EVENT:";
  constant TOOL_EVENT_SUFFIX (line 47) | const TOOL_EVENT_SUFFIX = "]\n";
  function parseToolEvents (line 53) | function parseToolEvents(chunk: string): [ToolCallEvent[], string] {
  function sendChatMessageStream (line 98) | async function sendChatMessageStream(
  function planQuestionnaireStream (line 241) | async function planQuestionnaireStream(
  function planSummaryStream (line 289) | async function planSummaryStream(
  function getScreenshotImage (line 339) | function getScreenshotImage(id: number): string {
  type ChatSessionSummary (line 371) | type ChatSessionSummary = {
  type ChatHistoryItem (line 379) | type ChatHistoryItem = {
  type ChatHistoryResponse (line 386) | type ChatHistoryResponse = {

FILE: free-todo-frontend/lib/api/fetcher.ts
  type CustomFetcherOptions (line 4) | type CustomFetcherOptions<T> = RequestInit & {
  function normalizeTimestamps (line 11) | function normalizeTimestamps(obj: unknown): unknown {
  function customFetcher (line 71) | async function customFetcher<T>(

FILE: free-todo-frontend/lib/attachments.ts
  constant MAX_ATTACHMENT_SIZE_BYTES (line 6) | const MAX_ATTACHMENT_SIZE_BYTES = 50 * 1024 * 1024;
  function getApiBaseUrl (line 8) | function getApiBaseUrl(): string {
  function getAttachmentFileUrl (line 14) | function getAttachmentFileUrl(attachmentId: number): string {
  function uploadTodoAttachments (line 19) | async function uploadTodoAttachments(
  function removeTodoAttachment (line 43) | async function removeTodoAttachment(

FILE: free-todo-frontend/lib/config/panel-config.ts
  type PanelPosition (line 22) | type PanelPosition = "panelA" | "panelB" | "panelC";
  type PanelFeature (line 23) | type PanelFeature =
  constant DEV_IN_PROGRESS_FEATURES (line 41) | const DEV_IN_PROGRESS_FEATURES: PanelFeature[] = [
  constant ALL_PANEL_FEATURES (line 52) | const ALL_PANEL_FEATURES: PanelFeature[] = [
  constant FEATURE_ICON_MAP (line 69) | const FEATURE_ICON_MAP: Record<PanelFeature, LucideIcon> = {

FILE: free-todo-frontend/lib/dnd/context.tsx
  function useGlobalDnd (line 46) | function useGlobalDnd(): GlobalDndContextValue {
  function useGlobalDndSafe (line 57) | function useGlobalDndSafe(): GlobalDndContextValue | null {
  function usePendingUpdate (line 65) | function usePendingUpdate() {
  type GlobalDndProviderProps (line 99) | interface GlobalDndProviderProps {
  function GlobalDndProvider (line 103) | function GlobalDndProvider({ children }: GlobalDndProviderProps) {

FILE: free-todo-frontend/lib/dnd/handlers.ts
  function registerHandler (line 117) | function registerHandler(key: HandlerKey, handler: DragDropHandler) {
  function getHandler (line 124) | function getHandler(key: HandlerKey): DragDropHandler | undefined {
  function dispatchDragDrop (line 530) | function dispatchDragDrop(

FILE: free-todo-frontend/lib/dnd/overlays.tsx
  function getStatusColor (line 20) | function getStatusColor(status: TodoStatus) {
  function getPriorityBgColor (line 33) | function getPriorityBgColor(priority: TodoPriority) {
  function formatScheduleLabel (line 46) | function formatScheduleLabel(startTime?: string, endTime?: string) {
  type TodoCardOverlayProps (line 86) | interface TodoCardOverlayProps {
  function TodoCardOverlay (line 91) | function TodoCardOverlay({ todo, depth = 0 }: TodoCardOverlayProps) {
  type CalendarTodoOverlayProps (line 229) | interface CalendarTodoOverlayProps {
  function CalendarTodoOverlay (line 233) | function CalendarTodoOverlay({ todo }: CalendarTodoOverlayProps) {
  type DragOverlayContentProps (line 264) | interface DragOverlayContentProps {
  function DragOverlayContent (line 268) | function DragOverlayContent({ data }: DragOverlayContentProps) {
  type GlobalDragOverlayProps (line 309) | interface GlobalDragOverlayProps {
  function GlobalDragOverlay (line 313) | function GlobalDragOverlay({ activeDrag }: GlobalDragOverlayProps) {

FILE: free-todo-frontend/lib/dnd/types.ts
  type DragSourceType (line 16) | type DragSourceType = "TODO_CARD" | "FILE" | "USER" | "PANEL_HEADER";
  type DragData (line 22) | type DragData =
  type DropTargetType (line 59) | type DropTargetType =
  type DropData (line 72) | type DropData =
  type ActiveDragState (line 131) | interface ActiveDragState {
  type DragDropResult (line 143) | interface DragDropResult {
  type HandlerKey (line 152) | type HandlerKey = `${DragSourceType}->${DropTargetType}`;
  type DragDropHandler (line 157) | type DragDropHandler = (
  type GlobalDndContextValue (line 169) | interface GlobalDndContextValue {
  function isTodoCardDragData (line 180) | function isTodoCardDragData(
  function isCalendarDateDropData (line 189) | function isCalendarDateDropData(
  function isTodoListDropData (line 198) | function isTodoListDropData(
  function isTodoDropZoneDropData (line 207) | function isTodoDropZoneDropData(

FILE: free-todo-frontend/lib/generated/activity/activity.ts
  type SecondParameter (line 39) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type listActivitiesApiActivitiesGetResponse200 (line 47) | type listActivitiesApiActivitiesGetResponse200 = {
  type listActivitiesApiActivitiesGetResponse422 (line 52) | type listActivitiesApiActivitiesGetResponse422 = {
  type listActivitiesApiActivitiesGetResponseSuccess (line 57) | type listActivitiesApiActivitiesGetResponseSuccess = (listActivitiesApiA...
  type listActivitiesApiActivitiesGetResponseError (line 60) | type listActivitiesApiActivitiesGetResponseError = (listActivitiesApiAct...
  type listActivitiesApiActivitiesGetResponse (line 64) | type listActivitiesApiActivitiesGetResponse = (listActivitiesApiActiviti...
  type ListActivitiesApiActivitiesGetQueryResult (line 121) | type ListActivitiesApiActivitiesGetQueryResult = NonNullable<Awaited<Ret...
  type ListActivitiesApiActivitiesGetQueryError (line 122) | type ListActivitiesApiActivitiesGetQueryError = HTTPValidationError
  function useListActivitiesApiActivitiesGet (line 153) | function useListActivitiesApiActivitiesGet<TData = Awaited<ReturnType<ty...
  type getActivityEventsApiActivitiesActivityIdEventsGetResponse200 (line 172) | type getActivityEventsApiActivitiesActivityIdEventsGetResponse200 = {
  type getActivityEventsApiActivitiesActivityIdEventsGetResponse422 (line 177) | type getActivityEventsApiActivitiesActivityIdEventsGetResponse422 = {
  type getActivityEventsApiActivitiesActivityIdEventsGetResponseSuccess (line 182) | type getActivityEventsApiActivitiesActivityIdEventsGetResponseSuccess = ...
  type getActivityEventsApiActivitiesActivityIdEventsGetResponseError (line 185) | type getActivityEventsApiActivitiesActivityIdEventsGetResponseError = (g...
  type getActivityEventsApiActivitiesActivityIdEventsGetResponse (line 189) | type getActivityEventsApiActivitiesActivityIdEventsGetResponse = (getAct...
  type GetActivityEventsApiActivitiesActivityIdEventsGetQueryResult (line 239) | type GetActivityEventsApiActivitiesActivityIdEventsGetQueryResult = NonN...
  type GetActivityEventsApiActivitiesActivityIdEventsGetQueryError (line 240) | type GetActivityEventsApiActivitiesActivityIdEventsGetQueryError = HTTPV...
  function useGetActivityEventsApiActivitiesActivityIdEventsGet (line 271) | function useGetActivityEventsApiActivitiesActivityIdEventsGet<TData = Aw...
  type createActivityManualApiActivitiesManualPostResponse201 (line 296) | type createActivityManualApiActivitiesManualPostResponse201 = {
  type createActivityManualApiActivitiesManualPostResponse422 (line 301) | type createActivityManualApiActivitiesManualPostResponse422 = {
  type createActivityManualApiActivitiesManualPostResponseSuccess (line 306) | type createActivityManualApiActivitiesManualPostResponseSuccess = (creat...
  type createActivityManualApiActivitiesManualPostResponseError (line 309) | type createActivityManualApiActivitiesManualPostResponseError = (createA...
  type createActivityManualApiActivitiesManualPostResponse (line 313) | type createActivityManualApiActivitiesManualPostResponse = (createActivi...
  type CreateActivityManualApiActivitiesManualPostMutationResult (line 365) | type CreateActivityManualApiActivitiesManualPostMutationResult = NonNull...
  type CreateActivityManualApiActivitiesManualPostMutationBody (line 366) | type CreateActivityManualApiActivitiesManualPostMutationBody = ManualAct...
  type CreateActivityManualApiActivitiesManualPostMutationError (line 367) | type CreateActivityManualApiActivitiesManualPostMutationError = HTTPVali...

FILE: free-todo-frontend/lib/generated/audio/audio.ts
  type SecondParameter (line 41) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type getRecordingsApiAudioRecordingsGetResponse200 (line 49) | type getRecordingsApiAudioRecordingsGetResponse200 = {
  type getRecordingsApiAudioRecordingsGetResponse422 (line 54) | type getRecordingsApiAudioRecordingsGetResponse422 = {
  type getRecordingsApiAudioRecordingsGetResponseSuccess (line 59) | type getRecordingsApiAudioRecordingsGetResponseSuccess = (getRecordingsA...
  type getRecordingsApiAudioRecordingsGetResponseError (line 62) | type getRecordingsApiAudioRecordingsGetResponseError = (getRecordingsApi...
  type getRecordingsApiAudioRecordingsGetResponse (line 66) | type getRecordingsApiAudioRecordingsGetResponse = (getRecordingsApiAudio...
  type GetRecordingsApiAudioRecordingsGetQueryResult (line 123) | type GetRecordingsApiAudioRecordingsGetQueryResult = NonNullable<Awaited...
  type GetRecordingsApiAudioRecordingsGetQueryError (line 124) | type GetRecordingsApiAudioRecordingsGetQueryError = HTTPValidationError
  function useGetRecordingsApiAudioRecordingsGet (line 155) | function useGetRecordingsApiAudioRecordingsGet<TData = Awaited<ReturnTyp...
  type getTimelineApiAudioTimelineGetResponse200 (line 174) | type getTimelineApiAudioTimelineGetResponse200 = {
  type getTimelineApiAudioTimelineGetResponse422 (line 179) | type getTimelineApiAudioTimelineGetResponse422 = {
  type getTimelineApiAudioTimelineGetResponseSuccess (line 184) | type getTimelineApiAudioTimelineGetResponseSuccess = (getTimelineApiAudi...
  type getTimelineApiAudioTimelineGetResponseError (line 187) | type getTimelineApiAudioTimelineGetResponseError = (getTimelineApiAudioT...
  type getTimelineApiAudioTimelineGetResponse (line 191) | type getTimelineApiAudioTimelineGetResponse = (getTimelineApiAudioTimeli...
  type GetTimelineApiAudioTimelineGetQueryResult (line 248) | type GetTimelineApiAudioTimelineGetQueryResult = NonNullable<Awaited<Ret...
  type GetTimelineApiAudioTimelineGetQueryError (line 249) | type GetTimelineApiAudioTimelineGetQueryError = HTTPValidationError
  function useGetTimelineApiAudioTimelineGet (line 280) | function useGetTimelineApiAudioTimelineGet<TData = Awaited<ReturnType<ty...
  type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse200 (line 299) | type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse200 = {
  type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse422 (line 304) | type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse422 = {
  type getRecordingFileApiAudioRecordingRecordingIdFileGetResponseSuccess (line 309) | type getRecordingFileApiAudioRecordingRecordingIdFileGetResponseSuccess ...
  type getRecordingFileApiAudioRecordingRecordingIdFileGetResponseError (line 312) | type getRecordingFileApiAudioRecordingRecordingIdFileGetResponseError = ...
  type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse (line 316) | type getRecordingFileApiAudioRecordingRecordingIdFileGetResponse = (getR...
  type GetRecordingFileApiAudioRecordingRecordingIdFileGetQueryResult (line 366) | type GetRecordingFileApiAudioRecordingRecordingIdFileGetQueryResult = No...
  type GetRecordingFileApiAudioRecordingRecordingIdFileGetQueryError (line 367) | type GetRecordingFileApiAudioRecordingRecordingIdFileGetQueryError = HTT...
  function useGetRecordingFileApiAudioRecordingRecordingIdFileGet (line 398) | function useGetRecordingFileApiAudioRecordingRecordingIdFileGet<TData = ...
  type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse200 (line 417) | type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse200 = {
  type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse422 (line 422) | type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse422 = {
  type getTranscriptionApiAudioTranscriptionRecordingIdGetResponseSuccess (line 427) | type getTranscriptionApiAudioTranscriptionRecordingIdGetResponseSuccess ...
  type getTranscriptionApiAudioTranscriptionRecordingIdGetResponseError (line 430) | type getTranscriptionApiAudioTranscriptionRecordingIdGetResponseError = ...
  type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse (line 434) | type getTranscriptionApiAudioTranscriptionRecordingIdGetResponse = (getT...
  type GetTranscriptionApiAudioTranscriptionRecordingIdGetQueryResult (line 495) | type GetTranscriptionApiAudioTranscriptionRecordingIdGetQueryResult = No...
  type GetTranscriptionApiAudioTranscriptionRecordingIdGetQueryError (line 496) | type GetTranscriptionApiAudioTranscriptionRecordingIdGetQueryError = HTT...
  function useGetTranscriptionApiAudioTranscriptionRecordingIdGet (line 530) | function useGetTranscriptionApiAudioTranscriptionRecordingIdGet<TData = ...
  type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse200 (line 555) | type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse2...
  type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse422 (line 560) | type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse4...
  type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponseSuccess (line 565) | type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponseS...
  type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponseError (line 568) | type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponseE...
  type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse (line 572) | type linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostResponse ...
  type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationResult (line 634) | type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationR...
  type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationBody (line 635) | type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationB...
  type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationError (line 636) | type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostMutationE...
  type optimizeTranscriptionApiAudioOptimizePostResponse200 (line 655) | type optimizeTranscriptionApiAudioOptimizePostResponse200 = {
  type optimizeTranscriptionApiAudioOptimizePostResponse422 (line 660) | type optimizeTranscriptionApiAudioOptimizePostResponse422 = {
  type optimizeTranscriptionApiAudioOptimizePostResponseSuccess (line 665) | type optimizeTranscriptionApiAudioOptimizePostResponseSuccess = (optimiz...
  type optimizeTranscriptionApiAudioOptimizePostResponseError (line 668) | type optimizeTranscriptionApiAudioOptimizePostResponseError = (optimizeT...
  type optimizeTranscriptionApiAudioOptimizePostResponse (line 672) | type optimizeTranscriptionApiAudioOptimizePostResponse = (optimizeTransc...
  type OptimizeTranscriptionApiAudioOptimizePostMutationResult (line 730) | type OptimizeTranscriptionApiAudioOptimizePostMutationResult = NonNullab...
  type OptimizeTranscriptionApiAudioOptimizePostMutationError (line 732) | type OptimizeTranscriptionApiAudioOptimizePostMutationError = HTTPValida...
  type extractTodosAndSchedulesApiAudioExtractPostResponse200 (line 755) | type extractTodosAndSchedulesApiAudioExtractPostResponse200 = {
  type extractTodosAndSchedulesApiAudioExtractPostResponse422 (line 760) | type extractTodosAndSchedulesApiAudioExtractPostResponse422 = {
  type extractTodosAndSchedulesApiAudioExtractPostResponseSuccess (line 765) | type extractTodosAndSchedulesApiAudioExtractPostResponseSuccess = (extra...
  type extractTodosAndSchedulesApiAudioExtractPostResponseError (line 768) | type extractTodosAndSchedulesApiAudioExtractPostResponseError = (extract...
  type extractTodosAndSchedulesApiAudioExtractPostResponse (line 772) | type extractTodosAndSchedulesApiAudioExtractPostResponse = (extractTodos...
  type ExtractTodosAndSchedulesApiAudioExtractPostMutationResult (line 830) | type ExtractTodosAndSchedulesApiAudioExtractPostMutationResult = NonNull...
  type ExtractTodosAndSchedulesApiAudioExtractPostMutationError (line 832) | type ExtractTodosAndSchedulesApiAudioExtractPostMutationError = HTTPVali...

FILE: free-todo-frontend/lib/generated/case-transform.ts
  function toCamelCase (line 10) | function toCamelCase(str: string): string {
  function toSnakeCase (line 18) | function toSnakeCase(str: string): string {
  function transformKeys (line 26) | function transformKeys<T>(

FILE: free-todo-frontend/lib/generated/chat/chat.ts
  type SecondParameter (line 46) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type chatWithContextStreamApiChatStreamWithContextPostResponse200 (line 54) | type chatWithContextStreamApiChatStreamWithContextPostResponse200 = {
  type chatWithContextStreamApiChatStreamWithContextPostResponse422 (line 59) | type chatWithContextStreamApiChatStreamWithContextPostResponse422 = {
  type chatWithContextStreamApiChatStreamWithContextPostResponseSuccess (line 64) | type chatWithContextStreamApiChatStreamWithContextPostResponseSuccess = ...
  type chatWithContextStreamApiChatStreamWithContextPostResponseError (line 67) | type chatWithContextStreamApiChatStreamWithContextPostResponseError = (c...
  type chatWithContextStreamApiChatStreamWithContextPostResponse (line 71) | type chatWithContextStreamApiChatStreamWithContextPostResponse = (chatWi...
  type ChatWithContextStreamApiChatStreamWithContextPostMutationResult (line 123) | type ChatWithContextStreamApiChatStreamWithContextPostMutationResult = N...
  type ChatWithContextStreamApiChatStreamWithContextPostMutationBody (line 124) | type ChatWithContextStreamApiChatStreamWithContextPostMutationBody = Cha...
  type ChatWithContextStreamApiChatStreamWithContextPostMutationError (line 125) | type ChatWithContextStreamApiChatStreamWithContextPostMutationError = HT...
  type chatWithLlmApiChatPostResponse200 (line 144) | type chatWithLlmApiChatPostResponse200 = {
  type chatWithLlmApiChatPostResponse422 (line 149) | type chatWithLlmApiChatPostResponse422 = {
  type chatWithLlmApiChatPostResponseSuccess (line 154) | type chatWithLlmApiChatPostResponseSuccess = (chatWithLlmApiChatPostResp...
  type chatWithLlmApiChatPostResponseError (line 157) | type chatWithLlmApiChatPostResponseError = (chatWithLlmApiChatPostRespon...
  type chatWithLlmApiChatPostResponse (line 161) | type chatWithLlmApiChatPostResponse = (chatWithLlmApiChatPostResponseSuc...
  type ChatWithLlmApiChatPostMutationResult (line 213) | type ChatWithLlmApiChatPostMutationResult = NonNullable<Awaited<ReturnTy...
  type ChatWithLlmApiChatPostMutationBody (line 214) | type ChatWithLlmApiChatPostMutationBody = ChatMessage
  type ChatWithLlmApiChatPostMutationError (line 215) | type ChatWithLlmApiChatPostMutationError = HTTPValidationError
  type chatWithLlmStreamApiChatStreamPostResponse200 (line 239) | type chatWithLlmStreamApiChatStreamPostResponse200 = {
  type chatWithLlmStreamApiChatStreamPostResponse422 (line 244) | type chatWithLlmStreamApiChatStreamPostResponse422 = {
  type chatWithLlmStreamApiChatStreamPostResponseSuccess (line 249) | type chatWithLlmStreamApiChatStreamPostResponseSuccess = (chatWithLlmStr...
  type chatWithLlmStreamApiChatStreamPostResponseError (line 252) | type chatWithLlmStreamApiChatStreamPostResponseError = (chatWithLlmStrea...
  type chatWithLlmStreamApiChatStreamPostResponse (line 256) | type chatWithLlmStreamApiChatStreamPostResponse = (chatWithLlmStreamApiC...
  type ChatWithLlmStreamApiChatStreamPostMutationResult (line 308) | type ChatWithLlmStreamApiChatStreamPostMutationResult = NonNullable<Awai...
  type ChatWithLlmStreamApiChatStreamPostMutationBody (line 309) | type ChatWithLlmStreamApiChatStreamPostMutationBody = ChatMessage
  type ChatWithLlmStreamApiChatStreamPostMutationError (line 310) | type ChatWithLlmStreamApiChatStreamPostMutationError = HTTPValidationError
  type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse200 (line 338) | type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse...
  type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse422 (line 343) | type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse...
  type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponseSuccess (line 348) | type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse...
  type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponseError (line 351) | type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse...
  type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse (line 355) | type extractTodosFromMessagesApiChatExtractTodosFromMessagesPostResponse...
  type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutationResult (line 407) | type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutation...
  type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutationBody (line 408) | type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutation...
  type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutationError (line 409) | type ExtractTodosFromMessagesApiChatExtractTodosFromMessagesPostMutation...
  type createNewChatApiChatNewPostResponse200 (line 428) | type createNewChatApiChatNewPostResponse200 = {
  type createNewChatApiChatNewPostResponse422 (line 433) | type createNewChatApiChatNewPostResponse422 = {
  type createNewChatApiChatNewPostResponseSuccess (line 438) | type createNewChatApiChatNewPostResponseSuccess = (createNewChatApiChatN...
  type createNewChatApiChatNewPostResponseError (line 441) | type createNewChatApiChatNewPostResponseError = (createNewChatApiChatNew...
  type createNewChatApiChatNewPostResponse (line 445) | type createNewChatApiChatNewPostResponse = (createNewChatApiChatNewPostR...
  type CreateNewChatApiChatNewPostMutationResult (line 497) | type CreateNewChatApiChatNewPostMutationResult = NonNullable<Awaited<Ret...
  type CreateNewChatApiChatNewPostMutationBody (line 498) | type CreateNewChatApiChatNewPostMutationBody = NewChatRequest | null
  type CreateNewChatApiChatNewPostMutationError (line 499) | type CreateNewChatApiChatNewPostMutationError = HTTPValidationError
  type addMessageToSessionApiChatSessionSessionIdMessagePostResponse200 (line 518) | type addMessageToSessionApiChatSessionSessionIdMessagePostResponse200 = {
  type addMessageToSessionApiChatSessionSessionIdMessagePostResponse422 (line 523) | type addMessageToSessionApiChatSessionSessionIdMessagePostResponse422 = {
  type addMessageToSessionApiChatSessionSessionIdMessagePostResponseSuccess (line 528) | type addMessageToSessionApiChatSessionSessionIdMessagePostResponseSucces...
  type addMessageToSessionApiChatSessionSessionIdMessagePostResponseError (line 531) | type addMessageToSessionApiChatSessionSessionIdMessagePostResponseError ...
  type addMessageToSessionApiChatSessionSessionIdMessagePostResponse (line 535) | type addMessageToSessionApiChatSessionSessionIdMessagePostResponse = (ad...
  type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationResult (line 588) | type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationResult...
  type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationBody (line 589) | type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationBody =...
  type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationError (line 590) | type AddMessageToSessionApiChatSessionSessionIdMessagePostMutationError ...
  type clearChatSessionApiChatSessionSessionIdDeleteResponse200 (line 609) | type clearChatSessionApiChatSessionSessionIdDeleteResponse200 = {
  type clearChatSessionApiChatSessionSessionIdDeleteResponse422 (line 614) | type clearChatSessionApiChatSessionSessionIdDeleteResponse422 = {
  type clearChatSessionApiChatSessionSessionIdDeleteResponseSuccess (line 619) | type clearChatSessionApiChatSessionSessionIdDeleteResponseSuccess = (cle...
  type clearChatSessionApiChatSessionSessionIdDeleteResponseError (line 622) | type clearChatSessionApiChatSessionSessionIdDeleteResponseError = (clear...
  type clearChatSessionApiChatSessionSessionIdDeleteResponse (line 626) | type clearChatSessionApiChatSessionSessionIdDeleteResponse = (clearChatS...
  type ClearChatSessionApiChatSessionSessionIdDeleteMutationResult (line 677) | type ClearChatSessionApiChatSessionSessionIdDeleteMutationResult = NonNu...
  type ClearChatSessionApiChatSessionSessionIdDeleteMutationError (line 679) | type ClearChatSessionApiChatSessionSessionIdDeleteMutationError = HTTPVa...
  type getChatHistoryApiChatHistoryGetResponse200 (line 698) | type getChatHistoryApiChatHistoryGetResponse200 = {
  type getChatHistoryApiChatHistoryGetResponse422 (line 703) | type getChatHistoryApiChatHistoryGetResponse422 = {
  type getChatHistoryApiChatHistoryGetResponseSuccess (line 708) | type getChatHistoryApiChatHistoryGetResponseSuccess = (getChatHistoryApi...
  type getChatHistoryApiChatHistoryGetResponseError (line 711) | type getChatHistoryApiChatHistoryGetResponseError = (getChatHistoryApiCh...
  type getChatHistoryApiChatHistoryGetResponse (line 715) | type getChatHistoryApiChatHistoryGetResponse = (getChatHistoryApiChatHis...
  type GetChatHistoryApiChatHistoryGetQueryResult (line 772) | type GetChatHistoryApiChatHistoryGetQueryResult = NonNullable<Awaited<Re...
  type GetChatHistoryApiChatHistoryGetQueryError (line 773) | type GetChatHistoryApiChatHistoryGetQueryError = HTTPValidationError
  function useGetChatHistoryApiChatHistoryGet (line 804) | function useGetChatHistoryApiChatHistoryGet<TData = Awaited<ReturnType<t...
  type getQuerySuggestionsApiChatSuggestionsGetResponse200 (line 823) | type getQuerySuggestionsApiChatSuggestionsGetResponse200 = {
  type getQuerySuggestionsApiChatSuggestionsGetResponse422 (line 828) | type getQuerySuggestionsApiChatSuggestionsGetResponse422 = {
  type getQuerySuggestionsApiChatSuggestionsGetResponseSuccess (line 833) | type getQuerySuggestionsApiChatSuggestionsGetResponseSuccess = (getQuery...
  type getQuerySuggestionsApiChatSuggestionsGetResponseError (line 836) | type getQuerySuggestionsApiChatSuggestionsGetResponseError = (getQuerySu...
  type getQuerySuggestionsApiChatSuggestionsGetResponse (line 840) | type getQuerySuggestionsApiChatSuggestionsGetResponse = (getQuerySuggest...
  type GetQuerySuggestionsApiChatSuggestionsGetQueryResult (line 897) | type GetQuerySuggestionsApiChatSuggestionsGetQueryResult = NonNullable<A...
  type GetQuerySuggestionsApiChatSuggestionsGetQueryError (line 898) | type GetQuerySuggestionsApiChatSuggestionsGetQueryError = HTTPValidation...
  function useGetQuerySuggestionsApiChatSuggestionsGet (line 929) | function useGetQuerySuggestionsApiChatSuggestionsGet<TData = Awaited<Ret...
  type getSupportedQueryTypesApiChatQueryTypesGetResponse200 (line 948) | type getSupportedQueryTypesApiChatQueryTypesGetResponse200 = {
  type getSupportedQueryTypesApiChatQueryTypesGetResponseSuccess (line 953) | type getSupportedQueryTypesApiChatQueryTypesGetResponseSuccess = (getSup...
  type getSupportedQueryTypesApiChatQueryTypesGetResponse (line 958) | type getSupportedQueryTypesApiChatQueryTypesGetResponse = (getSupportedQ...
  type GetSupportedQueryTypesApiChatQueryTypesGetQueryResult (line 1008) | type GetSupportedQueryTypesApiChatQueryTypesGetQueryResult = NonNullable...
  type GetSupportedQueryTypesApiChatQueryTypesGetQueryError (line 1009) | type GetSupportedQueryTypesApiChatQueryTypesGetQueryError = unknown
  function useGetSupportedQueryTypesApiChatQueryTypesGet (line 1040) | function useGetSupportedQueryTypesApiChatQueryTypesGet<TData = Awaited<R...
  type getAvailableAgnoToolsApiChatAgnoToolsGetResponse200 (line 1063) | type getAvailableAgnoToolsApiChatAgnoToolsGetResponse200 = {
  type getAvailableAgnoToolsApiChatAgnoToolsGetResponseSuccess (line 1068) | type getAvailableAgnoToolsApiChatAgnoToolsGetResponseSuccess = (getAvail...
  type getAvailableAgnoToolsApiChatAgnoToolsGetResponse (line 1073) | type getAvailableAgnoToolsApiChatAgnoToolsGetResponse = (getAvailableAgn...
  type GetAvailableAgnoToolsApiChatAgnoToolsGetQueryResult (line 1123) | type GetAvailableAgnoToolsApiChatAgnoToolsGetQueryResult = NonNullable<A...
  type GetAvailableAgnoToolsApiChatAgnoToolsGetQueryError (line 1124) | type GetAvailableAgnoToolsApiChatAgnoToolsGetQueryError = unknown
  function useGetAvailableAgnoToolsApiChatAgnoToolsGet (line 1155) | function useGetAvailableAgnoToolsApiChatAgnoToolsGet<TData = Awaited<Ret...
  type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse200 (line 1174) | type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse20...
  type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse422 (line 1179) | type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse42...
  type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponseSuccess (line 1184) | type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponseSu...
  type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponseError (line 1187) | type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponseEr...
  type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse (line 1191) | type planQuestionnaireStreamApiChatPlanQuestionnaireStreamPostResponse =...
  type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationResult (line 1243) | type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationRe...
  type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationBody (line 1244) | type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationBo...
  type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationError (line 1245) | type PlanQuestionnaireStreamApiChatPlanQuestionnaireStreamPostMutationEr...
  type planSummaryStreamApiChatPlanSummaryStreamPostResponse200 (line 1264) | type planSummaryStreamApiChatPlanSummaryStreamPostResponse200 = {
  type planSummaryStreamApiChatPlanSummaryStreamPostResponse422 (line 1269) | type planSummaryStreamApiChatPlanSummaryStreamPostResponse422 = {
  type planSummaryStreamApiChatPlanSummaryStreamPostResponseSuccess (line 1274) | type planSummaryStreamApiChatPlanSummaryStreamPostResponseSuccess = (pla...
  type planSummaryStreamApiChatPlanSummaryStreamPostResponseError (line 1277) | type planSummaryStreamApiChatPlanSummaryStreamPostResponseError = (planS...
  type planSummaryStreamApiChatPlanSummaryStreamPostResponse (line 1281) | type planSummaryStreamApiChatPlanSummaryStreamPostResponse = (planSummar...
  type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationResult (line 1333) | type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationResult = NonNu...
  type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationBody (line 1334) | type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationBody = PlanSum...
  type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationError (line 1335) | type PlanSummaryStreamApiChatPlanSummaryStreamPostMutationError = HTTPVa...

FILE: free-todo-frontend/lib/generated/config/config.ts
  type SecondParameter (line 40) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type testLlmConfigApiTestLlmConfigPostResponse200 (line 48) | type testLlmConfigApiTestLlmConfigPostResponse200 = {
  type testLlmConfigApiTestLlmConfigPostResponse422 (line 53) | type testLlmConfigApiTestLlmConfigPostResponse422 = {
  type testLlmConfigApiTestLlmConfigPostResponseSuccess (line 58) | type testLlmConfigApiTestLlmConfigPostResponseSuccess = (testLlmConfigAp...
  type testLlmConfigApiTestLlmConfigPostResponseError (line 61) | type testLlmConfigApiTestLlmConfigPostResponseError = (testLlmConfigApiT...
  type testLlmConfigApiTestLlmConfigPostResponse (line 65) | type testLlmConfigApiTestLlmConfigPostResponse = (testLlmConfigApiTestLl...
  type TestLlmConfigApiTestLlmConfigPostMutationResult (line 117) | type TestLlmConfigApiTestLlmConfigPostMutationResult = NonNullable<Await...
  type TestLlmConfigApiTestLlmConfigPostMutationBody (line 118) | type TestLlmConfigApiTestLlmConfigPostMutationBody = TestLlmConfigApiTes...
  type TestLlmConfigApiTestLlmConfigPostMutationError (line 119) | type TestLlmConfigApiTestLlmConfigPostMutationError = HTTPValidationError
  type testTavilyConfigApiTestTavilyConfigPostResponse200 (line 138) | type testTavilyConfigApiTestTavilyConfigPostResponse200 = {
  type testTavilyConfigApiTestTavilyConfigPostResponse422 (line 143) | type testTavilyConfigApiTestTavilyConfigPostResponse422 = {
  type testTavilyConfigApiTestTavilyConfigPostResponseSuccess (line 148) | type testTavilyConfigApiTestTavilyConfigPostResponseSuccess = (testTavil...
  type testTavilyConfigApiTestTavilyConfigPostResponseError (line 151) | type testTavilyConfigApiTestTavilyConfigPostResponseError = (testTavilyC...
  type testTavilyConfigApiTestTavilyConfigPostResponse (line 155) | type testTavilyConfigApiTestTavilyConfigPostResponse = (testTavilyConfig...
  type TestTavilyConfigApiTestTavilyConfigPostMutationResult (line 207) | type TestTavilyConfigApiTestTavilyConfigPostMutationResult = NonNullable...
  type TestTavilyConfigApiTestTavilyConfigPostMutationBody (line 208) | type TestTavilyConfigApiTestTavilyConfigPostMutationBody = TestTavilyCon...
  type TestTavilyConfigApiTestTavilyConfigPostMutationError (line 209) | type TestTavilyConfigApiTestTavilyConfigPostMutationError = HTTPValidati...
  type testAsrConfigApiTestAsrConfigPostResponse200 (line 228) | type testAsrConfigApiTestAsrConfigPostResponse200 = {
  type testAsrConfigApiTestAsrConfigPostResponse422 (line 233) | type testAsrConfigApiTestAsrConfigPostResponse422 = {
  type testAsrConfigApiTestAsrConfigPostResponseSuccess (line 238) | type testAsrConfigApiTestAsrConfigPostResponseSuccess = (testAsrConfigAp...
  type testAsrConfigApiTestAsrConfigPostResponseError (line 241) | type testAsrConfigApiTestAsrConfigPostResponseError = (testAsrConfigApiT...
  type testAsrConfigApiTestAsrConfigPostResponse (line 245) | type testAsrConfigApiTestAsrConfigPostResponse = (testAsrConfigApiTestAs...
  type TestAsrConfigApiTestAsrConfigPostMutationResult (line 297) | type TestAsrConfigApiTestAsrConfigPostMutationResult = NonNullable<Await...
  type TestAsrConfigApiTestAsrConfigPostMutationBody (line 298) | type TestAsrConfigApiTestAsrConfigPostMutationBody = TestAsrConfigApiTes...
  type TestAsrConfigApiTestAsrConfigPostMutationError (line 299) | type TestAsrConfigApiTestAsrConfigPostMutationError = HTTPValidationError
  type getLlmStatusApiLlmStatusGetResponse200 (line 321) | type getLlmStatusApiLlmStatusGetResponse200 = {
  type getLlmStatusApiLlmStatusGetResponseSuccess (line 326) | type getLlmStatusApiLlmStatusGetResponseSuccess = (getLlmStatusApiLlmSta...
  type getLlmStatusApiLlmStatusGetResponse (line 331) | type getLlmStatusApiLlmStatusGetResponse = (getLlmStatusApiLlmStatusGetR...
  type GetLlmStatusApiLlmStatusGetQueryResult (line 381) | type GetLlmStatusApiLlmStatusGetQueryResult = NonNullable<Awaited<Return...
  type GetLlmStatusApiLlmStatusGetQueryError (line 382) | type GetLlmStatusApiLlmStatusGetQueryError = unknown
  function useGetLlmStatusApiLlmStatusGet (line 413) | function useGetLlmStatusApiLlmStatusGet<TData = Awaited<ReturnType<typeo...
  type getConfigDetailedApiGetConfigGetResponse200 (line 432) | type getConfigDetailedApiGetConfigGetResponse200 = {
  type getConfigDetailedApiGetConfigGetResponseSuccess (line 437) | type getConfigDetailedApiGetConfigGetResponseSuccess = (getConfigDetaile...
  type getConfigDetailedApiGetConfigGetResponse (line 442) | type getConfigDetailedApiGetConfigGetResponse = (getConfigDetailedApiGet...
  type GetConfigDetailedApiGetConfigGetQueryResult (line 492) | type GetConfigDetailedApiGetConfigGetQueryResult = NonNullable<Awaited<R...
  type GetConfigDetailedApiGetConfigGetQueryError (line 493) | type GetConfigDetailedApiGetConfigGetQueryError = unknown
  function useGetConfigDetailedApiGetConfigGet (line 524) | function useGetConfigDetailedApiGetConfigGet<TData = Awaited<ReturnType<...
  type saveAndInitLlmApiSaveAndInitLlmPostResponse200 (line 543) | type saveAndInitLlmApiSaveAndInitLlmPostResponse200 = {
  type saveAndInitLlmApiSaveAndInitLlmPostResponse422 (line 548) | type saveAndInitLlmApiSaveAndInitLlmPostResponse422 = {
  type saveAndInitLlmApiSaveAndInitLlmPostResponseSuccess (line 553) | type saveAndInitLlmApiSaveAndInitLlmPostResponseSuccess = (saveAndInitLl...
  type saveAndInitLlmApiSaveAndInitLlmPostResponseError (line 556) | type saveAndInitLlmApiSaveAndInitLlmPostResponseError = (saveAndInitLlmA...
  type saveAndInitLlmApiSaveAndInitLlmPostResponse (line 560) | type saveAndInitLlmApiSaveAndInitLlmPostResponse = (saveAndInitLlmApiSav...
  type SaveAndInitLlmApiSaveAndInitLlmPostMutationResult (line 612) | type SaveAndInitLlmApiSaveAndInitLlmPostMutationResult = NonNullable<Awa...
  type SaveAndInitLlmApiSaveAndInitLlmPostMutationBody (line 613) | type SaveAndInitLlmApiSaveAndInitLlmPostMutationBody = SaveAndInitLlmApi...
  type SaveAndInitLlmApiSaveAndInitLlmPostMutationError (line 614) | type SaveAndInitLlmApiSaveAndInitLlmPostMutationError = HTTPValidationError
  type saveConfigApiSaveConfigPostResponse200 (line 633) | type saveConfigApiSaveConfigPostResponse200 = {
  type saveConfigApiSaveConfigPostResponse422 (line 638) | type saveConfigApiSaveConfigPostResponse422 = {
  type saveConfigApiSaveConfigPostResponseSuccess (line 643) | type saveConfigApiSaveConfigPostResponseSuccess = (saveConfigApiSaveConf...
  type saveConfigApiSaveConfigPostResponseError (line 646) | type saveConfigApiSaveConfigPostResponseError = (saveConfigApiSaveConfig...
  type saveConfigApiSaveConfigPostResponse (line 650) | type saveConfigApiSaveConfigPostResponse = (saveConfigApiSaveConfigPostR...
  type SaveConfigApiSaveConfigPostMutationResult (line 702) | type SaveConfigApiSaveConfigPostMutationResult = NonNullable<Awaited<Ret...
  type SaveConfigApiSaveConfigPostMutationBody (line 703) | type SaveConfigApiSaveConfigPostMutationBody = SaveConfigApiSaveConfigPo...
  type SaveConfigApiSaveConfigPostMutationError (line 704) | type SaveConfigApiSaveConfigPostMutationError = HTTPValidationError
  type getChatPromptsApiGetChatPromptsGetResponse200 (line 729) | type getChatPromptsApiGetChatPromptsGetResponse200 = {
  type getChatPromptsApiGetChatPromptsGetResponse422 (line 734) | type getChatPromptsApiGetChatPromptsGetResponse422 = {
  type getChatPromptsApiGetChatPromptsGetResponseSuccess (line 739) | type getChatPromptsApiGetChatPromptsGetResponseSuccess = (getChatPrompts...
  type getChatPromptsApiGetChatPromptsGetResponseError (line 742) | type getChatPromptsApiGetChatPromptsGetResponseError = (getChatPromptsAp...
  type getChatPromptsApiGetChatPromptsGetResponse (line 746) | type getChatPromptsApiGetChatPromptsGetResponse = (getChatPromptsApiGetC...
  type GetChatPromptsApiGetChatPromptsGetQueryResult (line 803) | type GetChatPromptsApiGetChatPromptsGetQueryResult = NonNullable<Awaited...
  type GetChatPromptsApiGetChatPromptsGetQueryError (line 804) | type GetChatPromptsApiGetChatPromptsGetQueryError = HTTPValidationError
  function useGetChatPromptsApiGetChatPromptsGet (line 835) | function useGetChatPromptsApiGetChatPromptsGet<TData = Awaited<ReturnTyp...

FILE: free-todo-frontend/lib/generated/cost-tracking/cost-tracking.ts
  type SecondParameter (line 31) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type getCostStatsApiCostTrackingStatsGetResponse200 (line 42) | type getCostStatsApiCostTrackingStatsGetResponse200 = {
  type getCostStatsApiCostTrackingStatsGetResponse422 (line 47) | type getCostStatsApiCostTrackingStatsGetResponse422 = {
  type getCostStatsApiCostTrackingStatsGetResponseSuccess (line 52) | type getCostStatsApiCostTrackingStatsGetResponseSuccess = (getCostStatsA...
  type getCostStatsApiCostTrackingStatsGetResponseError (line 55) | type getCostStatsApiCostTrackingStatsGetResponseError = (getCostStatsApi...
  type getCostStatsApiCostTrackingStatsGetResponse (line 59) | type getCostStatsApiCostTrackingStatsGetResponse = (getCostStatsApiCostT...
  type GetCostStatsApiCostTrackingStatsGetQueryResult (line 116) | type GetCostStatsApiCostTrackingStatsGetQueryResult = NonNullable<Awaite...
  type GetCostStatsApiCostTrackingStatsGetQueryError (line 117) | type GetCostStatsApiCostTrackingStatsGetQueryError = HTTPValidationError
  function useGetCostStatsApiCostTrackingStatsGet (line 148) | function useGetCostStatsApiCostTrackingStatsGet<TData = Awaited<ReturnTy...
  type getCostConfigApiCostTrackingConfigGetResponse200 (line 167) | type getCostConfigApiCostTrackingConfigGetResponse200 = {
  type getCostConfigApiCostTrackingConfigGetResponseSuccess (line 172) | type getCostConfigApiCostTrackingConfigGetResponseSuccess = (getCostConf...
  type getCostConfigApiCostTrackingConfigGetResponse (line 177) | type getCostConfigApiCostTrackingConfigGetResponse = (getCostConfigApiCo...
  type GetCostConfigApiCostTrackingConfigGetQueryResult (line 227) | type GetCostConfigApiCostTrackingConfigGetQueryResult = NonNullable<Awai...
  type GetCostConfigApiCostTrackingConfigGetQueryError (line 228) | type GetCostConfigApiCostTrackingConfigGetQueryError = unknown
  function useGetCostConfigApiCostTrackingConfigGet (line 259) | function useGetCostConfigApiCostTrackingConfigGet<TData = Awaited<Return...

FILE: free-todo-frontend/lib/generated/default/default.ts
  type SecondParameter (line 26) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type healthCheckHealthGetResponse200 (line 34) | type healthCheckHealthGetResponse200 = {
  type healthCheckHealthGetResponseSuccess (line 39) | type healthCheckHealthGetResponseSuccess = (healthCheckHealthGetResponse...
  type healthCheckHealthGetResponse (line 44) | type healthCheckHealthGetResponse = (healthCheckHealthGetResponseSuccess)
  type HealthCheckHealthGetQueryResult (line 94) | type HealthCheckHealthGetQueryResult = NonNullable<Awaited<ReturnType<ty...
  type HealthCheckHealthGetQueryError (line 95) | type HealthCheckHealthGetQueryError = unknown
  function useHealthCheckHealthGet (line 126) | function useHealthCheckHealthGet<TData = Awaited<ReturnType<typeof healt...
  type llmHealthCheckHealthLlmGetResponse200 (line 145) | type llmHealthCheckHealthLlmGetResponse200 = {
  type llmHealthCheckHealthLlmGetResponseSuccess (line 150) | type llmHealthCheckHealthLlmGetResponseSuccess = (llmHealthCheckHealthLl...
  type llmHealthCheckHealthLlmGetResponse (line 155) | type llmHealthCheckHealthLlmGetResponse = (llmHealthCheckHealthLlmGetRes...
  type LlmHealthCheckHealthLlmGetQueryResult (line 205) | type LlmHealthCheckHealthLlmGetQueryResult = NonNullable<Awaited<ReturnT...
  type LlmHealthCheckHealthLlmGetQueryError (line 206) | type LlmHealthCheckHealthLlmGetQueryError = unknown
  function useLlmHealthCheckHealthLlmGet (line 237) | function useLlmHealthCheckHealthLlmGet<TData = Awaited<ReturnType<typeof...

FILE: free-todo-frontend/lib/generated/event/event.ts
  type SecondParameter (line 38) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type listEventsApiEventsGetResponse200 (line 46) | type listEventsApiEventsGetResponse200 = {
  type listEventsApiEventsGetResponse422 (line 51) | type listEventsApiEventsGetResponse422 = {
  type listEventsApiEventsGetResponseSuccess (line 56) | type listEventsApiEventsGetResponseSuccess = (listEventsApiEventsGetResp...
  type listEventsApiEventsGetResponseError (line 59) | type listEventsApiEventsGetResponseError = (listEventsApiEventsGetRespon...
  type listEventsApiEventsGetResponse (line 63) | type listEventsApiEventsGetResponse = (listEventsApiEventsGetResponseSuc...
  type ListEventsApiEventsGetQueryResult (line 120) | type ListEventsApiEventsGetQueryResult = NonNullable<Awaited<ReturnType<...
  type ListEventsApiEventsGetQueryError (line 121) | type ListEventsApiEventsGetQueryError = HTTPValidationError
  function useListEventsApiEventsGet (line 152) | function useListEventsApiEventsGet<TData = Awaited<ReturnType<typeof lis...
  type countEventsApiEventsCountGetResponse200 (line 171) | type countEventsApiEventsCountGetResponse200 = {
  type countEventsApiEventsCountGetResponse422 (line 176) | type countEventsApiEventsCountGetResponse422 = {
  type countEventsApiEventsCountGetResponseSuccess (line 181) | type countEventsApiEventsCountGetResponseSuccess = (countEventsApiEvents...
  type countEventsApiEventsCountGetResponseError (line 184) | type countEventsApiEventsCountGetResponseError = (countEventsApiEventsCo...
  type countEventsApiEventsCountGetResponse (line 188) | type countEventsApiEventsCountGetResponse = (countEventsApiEventsCountGe...
  type CountEventsApiEventsCountGetQueryResult (line 245) | type CountEventsApiEventsCountGetQueryResult = NonNullable<Awaited<Retur...
  type CountEventsApiEventsCountGetQueryError (line 246) | type CountEventsApiEventsCountGetQueryError = HTTPValidationError
  function useCountEventsApiEventsCountGet (line 277) | function useCountEventsApiEventsCountGet<TData = Awaited<ReturnType<type...
  type getEventDetailApiEventsEventIdGetResponse200 (line 296) | type getEventDetailApiEventsEventIdGetResponse200 = {
  type getEventDetailApiEventsEventIdGetResponse422 (line 301) | type getEventDetailApiEventsEventIdGetResponse422 = {
  type getEventDetailApiEventsEventIdGetResponseSuccess (line 306) | type getEventDetailApiEventsEventIdGetResponseSuccess = (getEventDetailA...
  type getEventDetailApiEventsEventIdGetResponseError (line 309) | type getEventDetailApiEventsEventIdGetResponseError = (getEventDetailApi...
  type getEventDetailApiEventsEventIdGetResponse (line 313) | type getEventDetailApiEventsEventIdGetResponse = (getEventDetailApiEvent...
  type GetEventDetailApiEventsEventIdGetQueryResult (line 363) | type GetEventDetailApiEventsEventIdGetQueryResult = NonNullable<Awaited<...
  type GetEventDetailApiEventsEventIdGetQueryError (line 364) | type GetEventDetailApiEventsEventIdGetQueryError = HTTPValidationError
  function useGetEventDetailApiEventsEventIdGet (line 395) | function useGetEventDetailApiEventsEventIdGet<TData = Awaited<ReturnType...
  type getEventContextApiEventsEventIdContextGetResponse200 (line 414) | type getEventContextApiEventsEventIdContextGetResponse200 = {
  type getEventContextApiEventsEventIdContextGetResponse422 (line 419) | type getEventContextApiEventsEventIdContextGetResponse422 = {
  type getEventContextApiEventsEventIdContextGetResponseSuccess (line 424) | type getEventContextApiEventsEventIdContextGetResponseSuccess = (getEven...
  type getEventContextApiEventsEventIdContextGetResponseError (line 427) | type getEventContextApiEventsEventIdContextGetResponseError = (getEventC...
  type getEventContextApiEventsEventIdContextGetResponse (line 431) | type getEventContextApiEventsEventIdContextGetResponse = (getEventContex...
  type GetEventContextApiEventsEventIdContextGetQueryResult (line 481) | type GetEventContextApiEventsEventIdContextGetQueryResult = NonNullable<...
  type GetEventContextApiEventsEventIdContextGetQueryError (line 482) | type GetEventContextApiEventsEventIdContextGetQueryError = HTTPValidatio...
  function useGetEventContextApiEventsEventIdContextGet (line 513) | function useGetEventContextApiEventsEventIdContextGet<TData = Awaited<Re...
  type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse200 (line 532) | type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse200 = {
  type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse422 (line 537) | type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse422 = {
  type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponseSuccess (line 542) | type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponseSucc...
  type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponseError (line 545) | type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponseErro...
  type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse (line 549) | type generateEventSummaryApiEventsEventIdGenerateSummaryPostResponse = (...
  type GenerateEventSummaryApiEventsEventIdGenerateSummaryPostMutationResult (line 600) | type GenerateEventSummaryApiEventsEventIdGenerateSummaryPostMutationResu...
  type GenerateEventSummaryApiEventsEventIdGenerateSummaryPostMutationError (line 602) | type GenerateEventSummaryApiEventsEventIdGenerateSummaryPostMutationErro...

FILE: free-todo-frontend/lib/generated/floating-capture/floating-capture.ts
  type SecondParameter (line 36) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse200 (line 50) | type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse20...
  type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse422 (line 55) | type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse42...
  type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponseSuccess (line 60) | type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponseSu...
  type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponseError (line 63) | type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponseEr...
  type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse (line 67) | type extractTodosFromCaptureApiFloatingCaptureExtractTodosPostResponse =...
  type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationResult (line 119) | type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationRe...
  type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationBody (line 120) | type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationBo...
  type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationError (line 121) | type ExtractTodosFromCaptureApiFloatingCaptureExtractTodosPostMutationEr...
  type healthCheckApiFloatingCaptureHealthGetResponse200 (line 140) | type healthCheckApiFloatingCaptureHealthGetResponse200 = {
  type healthCheckApiFloatingCaptureHealthGetResponseSuccess (line 145) | type healthCheckApiFloatingCaptureHealthGetResponseSuccess = (healthChec...
  type healthCheckApiFloatingCaptureHealthGetResponse (line 150) | type healthCheckApiFloatingCaptureHealthGetResponse = (healthCheckApiFlo...
  type HealthCheckApiFloatingCaptureHealthGetQueryResult (line 200) | type HealthCheckApiFloatingCaptureHealthGetQueryResult = NonNullable<Awa...
  type HealthCheckApiFloatingCaptureHealthGetQueryError (line 201) | type HealthCheckApiFloatingCaptureHealthGetQueryError = unknown
  function useHealthCheckApiFloatingCaptureHealthGet (line 232) | function useHealthCheckApiFloatingCaptureHealthGet<TData = Awaited<Retur...

FILE: free-todo-frontend/lib/generated/journals/journals.ts
  type SecondParameter (line 43) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type createJournalApiJournalsPostResponse201 (line 51) | type createJournalApiJournalsPostResponse201 = {
  type createJournalApiJournalsPostResponse422 (line 56) | type createJournalApiJournalsPostResponse422 = {
  type createJournalApiJournalsPostResponseSuccess (line 61) | type createJournalApiJournalsPostResponseSuccess = (createJournalApiJour...
  type createJournalApiJournalsPostResponseError (line 64) | type createJournalApiJournalsPostResponseError = (createJournalApiJourna...
  type createJournalApiJournalsPostResponse (line 68) | type createJournalApiJournalsPostResponse = (createJournalApiJournalsPos...
  type CreateJournalApiJournalsPostMutationResult (line 120) | type CreateJournalApiJournalsPostMutationResult = NonNullable<Awaited<Re...
  type CreateJournalApiJournalsPostMutationBody (line 121) | type CreateJournalApiJournalsPostMutationBody = JournalCreate
  type CreateJournalApiJournalsPostMutationError (line 122) | type CreateJournalApiJournalsPostMutationError = HTTPValidationError
  type listJournalsApiJournalsGetResponse200 (line 141) | type listJournalsApiJournalsGetResponse200 = {
  type listJournalsApiJournalsGetResponse422 (line 146) | type listJournalsApiJournalsGetResponse422 = {
  type listJournalsApiJournalsGetResponseSuccess (line 151) | type listJournalsApiJournalsGetResponseSuccess = (listJournalsApiJournal...
  type listJournalsApiJournalsGetResponseError (line 154) | type listJournalsApiJournalsGetResponseError = (listJournalsApiJournalsG...
  type listJournalsApiJournalsGetResponse (line 158) | type listJournalsApiJournalsGetResponse = (listJournalsApiJournalsGetRes...
  type ListJournalsApiJournalsGetQueryResult (line 215) | type ListJournalsApiJournalsGetQueryResult = NonNullable<Awaited<ReturnT...
  type ListJournalsApiJournalsGetQueryError (line 216) | type ListJournalsApiJournalsGetQueryError = HTTPValidationError
  function useListJournalsApiJournalsGet (line 247) | function useListJournalsApiJournalsGet<TData = Awaited<ReturnType<typeof...
  type getJournalApiJournalsJournalIdGetResponse200 (line 266) | type getJournalApiJournalsJournalIdGetResponse200 = {
  type getJournalApiJournalsJournalIdGetResponse422 (line 271) | type getJournalApiJournalsJournalIdGetResponse422 = {
  type getJournalApiJournalsJournalIdGetResponseSuccess (line 276) | type getJournalApiJournalsJournalIdGetResponseSuccess = (getJournalApiJo...
  type getJournalApiJournalsJournalIdGetResponseError (line 279) | type getJournalApiJournalsJournalIdGetResponseError = (getJournalApiJour...
  type getJournalApiJournalsJournalIdGetResponse (line 283) | type getJournalApiJournalsJournalIdGetResponse = (getJournalApiJournalsJ...
  type GetJournalApiJournalsJournalIdGetQueryResult (line 333) | type GetJournalApiJournalsJournalIdGetQueryResult = NonNullable<Awaited<...
  type GetJournalApiJournalsJournalIdGetQueryError (line 334) | type GetJournalApiJournalsJournalIdGetQueryError = HTTPValidationError
  function useGetJournalApiJournalsJournalIdGet (line 365) | function useGetJournalApiJournalsJournalIdGet<TData = Awaited<ReturnType...
  type updateJournalApiJournalsJournalIdPutResponse200 (line 384) | type updateJournalApiJournalsJournalIdPutResponse200 = {
  type updateJournalApiJournalsJournalIdPutResponse422 (line 389) | type updateJournalApiJournalsJournalIdPutResponse422 = {
  type updateJournalApiJournalsJournalIdPutResponseSuccess (line 394) | type updateJournalApiJournalsJournalIdPutResponseSuccess = (updateJourna...
  type updateJournalApiJournalsJournalIdPutResponseError (line 397) | type updateJournalApiJournalsJournalIdPutResponseError = (updateJournalA...
  type updateJournalApiJournalsJournalIdPutResponse (line 401) | type updateJournalApiJournalsJournalIdPutResponse = (updateJournalApiJou...
  type UpdateJournalApiJournalsJournalIdPutMutationResult (line 454) | type UpdateJournalApiJournalsJournalIdPutMutationResult = NonNullable<Aw...
  type UpdateJournalApiJournalsJournalIdPutMutationBody (line 455) | type UpdateJournalApiJournalsJournalIdPutMutationBody = JournalUpdate | ...
  type UpdateJournalApiJournalsJournalIdPutMutationError (line 456) | type UpdateJournalApiJournalsJournalIdPutMutationError = HTTPValidationE...
  type deleteJournalApiJournalsJournalIdDeleteResponse204 (line 475) | type deleteJournalApiJournalsJournalIdDeleteResponse204 = {
  type deleteJournalApiJournalsJournalIdDeleteResponse422 (line 480) | type deleteJournalApiJournalsJournalIdDeleteResponse422 = {
  type deleteJournalApiJournalsJournalIdDeleteResponseSuccess (line 485) | type deleteJournalApiJournalsJournalIdDeleteResponseSuccess = (deleteJou...
  type deleteJournalApiJournalsJournalIdDeleteResponseError (line 488) | type deleteJournalApiJournalsJournalIdDeleteResponseError = (deleteJourn...
  type deleteJournalApiJournalsJournalIdDeleteResponse (line 492) | type deleteJournalApiJournalsJournalIdDeleteResponse = (deleteJournalApi...
  type DeleteJournalApiJournalsJournalIdDeleteMutationResult (line 543) | type DeleteJournalApiJournalsJournalIdDeleteMutationResult = NonNullable...
  type DeleteJournalApiJournalsJournalIdDeleteMutationError (line 545) | type DeleteJournalApiJournalsJournalIdDeleteMutationError = HTTPValidati...
  type autoLinkJournalApiJournalsAutoLinkPostResponse200 (line 564) | type autoLinkJournalApiJournalsAutoLinkPostResponse200 = {
  type autoLinkJournalApiJournalsAutoLinkPostResponse422 (line 569) | type autoLinkJournalApiJournalsAutoLinkPostResponse422 = {
  type autoLinkJournalApiJournalsAutoLinkPostResponseSuccess (line 574) | type autoLinkJournalApiJournalsAutoLinkPostResponseSuccess = (autoLinkJo...
  type autoLinkJournalApiJournalsAutoLinkPostResponseError (line 577) | type autoLinkJournalApiJournalsAutoLinkPostResponseError = (autoLinkJour...
  type autoLinkJournalApiJournalsAutoLinkPostResponse (line 581) | type autoLinkJournalApiJournalsAutoLinkPostResponse = (autoLinkJournalAp...
  type AutoLinkJournalApiJournalsAutoLinkPostMutationResult (line 633) | type AutoLinkJournalApiJournalsAutoLinkPostMutationResult = NonNullable<...
  type AutoLinkJournalApiJournalsAutoLinkPostMutationBody (line 634) | type AutoLinkJournalApiJournalsAutoLinkPostMutationBody = JournalAutoLin...
  type AutoLinkJournalApiJournalsAutoLinkPostMutationError (line 635) | type AutoLinkJournalApiJournalsAutoLinkPostMutationError = HTTPValidatio...
  type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse200 (line 654) | type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse200...
  type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse422 (line 659) | type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse422...
  type generateObjectiveJournalApiJournalsGenerateObjectivePostResponseSuccess (line 664) | type generateObjectiveJournalApiJournalsGenerateObjectivePostResponseSuc...
  type generateObjectiveJournalApiJournalsGenerateObjectivePostResponseError (line 667) | type generateObjectiveJournalApiJournalsGenerateObjectivePostResponseErr...
  type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse (line 671) | type generateObjectiveJournalApiJournalsGenerateObjectivePostResponse = ...
  type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationResult (line 723) | type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationRes...
  type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationBody (line 724) | type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationBod...
  type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationError (line 725) | type GenerateObjectiveJournalApiJournalsGenerateObjectivePostMutationErr...
  type generateAiJournalApiJournalsGenerateAiPostResponse200 (line 744) | type generateAiJournalApiJournalsGenerateAiPostResponse200 = {
  type generateAiJournalApiJournalsGenerateAiPostResponse422 (line 749) | type generateAiJournalApiJournalsGenerateAiPostResponse422 = {
  type generateAiJournalApiJournalsGenerateAiPostResponseSuccess (line 754) | type generateAiJournalApiJournalsGenerateAiPostResponseSuccess = (genera...
  type generateAiJournalApiJournalsGenerateAiPostResponseError (line 757) | type generateAiJournalApiJournalsGenerateAiPostResponseError = (generate...
  type generateAiJournalApiJournalsGenerateAiPostResponse (line 761) | type generateAiJournalApiJournalsGenerateAiPostResponse = (generateAiJou...
  type GenerateAiJournalApiJournalsGenerateAiPostMutationResult (line 813) | type GenerateAiJournalApiJournalsGenerateAiPostMutationResult = NonNulla...
  type GenerateAiJournalApiJournalsGenerateAiPostMutationBody (line 814) | type GenerateAiJournalApiJournalsGenerateAiPostMutationBody = JournalGen...
  type GenerateAiJournalApiJournalsGenerateAiPostMutationError (line 815) | type GenerateAiJournalApiJournalsGenerateAiPostMutationError = HTTPValid...

FILE: free-todo-frontend/lib/generated/logs/logs.ts
  type SecondParameter (line 31) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type getLogFilesApiLogsFilesGetResponse200 (line 39) | type getLogFilesApiLogsFilesGetResponse200 = {
  type getLogFilesApiLogsFilesGetResponseSuccess (line 44) | type getLogFilesApiLogsFilesGetResponseSuccess = (getLogFilesApiLogsFile...
  type getLogFilesApiLogsFilesGetResponse (line 49) | type getLogFilesApiLogsFilesGetResponse = (getLogFilesApiLogsFilesGetRes...
  type GetLogFilesApiLogsFilesGetQueryResult (line 99) | type GetLogFilesApiLogsFilesGetQueryResult = NonNullable<Awaited<ReturnT...
  type GetLogFilesApiLogsFilesGetQueryError (line 100) | type GetLogFilesApiLogsFilesGetQueryError = unknown
  function useGetLogFilesApiLogsFilesGet (line 131) | function useGetLogFilesApiLogsFilesGet<TData = Awaited<ReturnType<typeof...
  type getLogContentApiLogsContentGetResponse200 (line 150) | type getLogContentApiLogsContentGetResponse200 = {
  type getLogContentApiLogsContentGetResponse422 (line 155) | type getLogContentApiLogsContentGetResponse422 = {
  type getLogContentApiLogsContentGetResponseSuccess (line 160) | type getLogContentApiLogsContentGetResponseSuccess = (getLogContentApiLo...
  type getLogContentApiLogsContentGetResponseError (line 163) | type getLogContentApiLogsContentGetResponseError = (getLogContentApiLogs...
  type getLogContentApiLogsContentGetResponse (line 167) | type getLogContentApiLogsContentGetResponse = (getLogContentApiLogsConte...
  type GetLogContentApiLogsContentGetQueryResult (line 224) | type GetLogContentApiLogsContentGetQueryResult = NonNullable<Awaited<Ret...
  type GetLogContentApiLogsContentGetQueryError (line 225) | type GetLogContentApiLogsContentGetQueryError = HTTPValidationError
  function useGetLogContentApiLogsContentGet (line 256) | function useGetLogContentApiLogsContentGet<TData = Awaited<ReturnType<ty...

FILE: free-todo-frontend/lib/generated/notifications/notifications.ts
  type SecondParameter (line 34) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type getNotificationApiNotificationsGetResponse200 (line 53) | type getNotificationApiNotificationsGetResponse200 = {
  type getNotificationApiNotificationsGetResponseSuccess (line 58) | type getNotificationApiNotificationsGetResponseSuccess = (getNotificatio...
  type getNotificationApiNotificationsGetResponse (line 63) | type getNotificationApiNotificationsGetResponse = (getNotificationApiNot...
  type GetNotificationApiNotificationsGetQueryResult (line 113) | type GetNotificationApiNotificationsGetQueryResult = NonNullable<Awaited...
  type GetNotificationApiNotificationsGetQueryError (line 114) | type GetNotificationApiNotificationsGetQueryError = unknown
  function useGetNotificationApiNotificationsGet (line 145) | function useGetNotificationApiNotificationsGet<TData = Awaited<ReturnTyp...
  type deleteNotificationApiNotificationsNotificationIdDeleteResponse200 (line 170) | type deleteNotificationApiNotificationsNotificationIdDeleteResponse200 = {
  type deleteNotificationApiNotificationsNotificationIdDeleteResponse422 (line 175) | type deleteNotificationApiNotificationsNotificationIdDeleteResponse422 = {
  type deleteNotificationApiNotificationsNotificationIdDeleteResponseSuccess (line 180) | type deleteNotificationApiNotificationsNotificationIdDeleteResponseSucce...
  type deleteNotificationApiNotificationsNotificationIdDeleteResponseError (line 183) | type deleteNotificationApiNotificationsNotificationIdDeleteResponseError...
  type deleteNotificationApiNotificationsNotificationIdDeleteResponse (line 187) | type deleteNotificationApiNotificationsNotificationIdDeleteResponse = (d...
  type DeleteNotificationApiNotificationsNotificationIdDeleteMutationResult (line 238) | type DeleteNotificationApiNotificationsNotificationIdDeleteMutationResul...
  type DeleteNotificationApiNotificationsNotificationIdDeleteMutationError (line 240) | type DeleteNotificationApiNotificationsNotificationIdDeleteMutationError...

FILE: free-todo-frontend/lib/generated/ocr/ocr.ts
  type SecondParameter (line 35) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type processOcrApiOcrProcessPostResponse200 (line 43) | type processOcrApiOcrProcessPostResponse200 = {
  type processOcrApiOcrProcessPostResponse422 (line 48) | type processOcrApiOcrProcessPostResponse422 = {
  type processOcrApiOcrProcessPostResponseSuccess (line 53) | type processOcrApiOcrProcessPostResponseSuccess = (processOcrApiOcrProce...
  type processOcrApiOcrProcessPostResponseError (line 56) | type processOcrApiOcrProcessPostResponseError = (processOcrApiOcrProcess...
  type processOcrApiOcrProcessPostResponse (line 60) | type processOcrApiOcrProcessPostResponse = (processOcrApiOcrProcessPostR...
  type ProcessOcrApiOcrProcessPostMutationResult (line 118) | type ProcessOcrApiOcrProcessPostMutationResult = NonNullable<Awaited<Ret...
  type ProcessOcrApiOcrProcessPostMutationError (line 120) | type ProcessOcrApiOcrProcessPostMutationError = HTTPValidationError
  type getOcrStatisticsApiOcrStatisticsGetResponse200 (line 139) | type getOcrStatisticsApiOcrStatisticsGetResponse200 = {
  type getOcrStatisticsApiOcrStatisticsGetResponseSuccess (line 144) | type getOcrStatisticsApiOcrStatisticsGetResponseSuccess = (getOcrStatist...
  type getOcrStatisticsApiOcrStatisticsGetResponse (line 149) | type getOcrStatisticsApiOcrStatisticsGetResponse = (getOcrStatisticsApiO...
  type GetOcrStatisticsApiOcrStatisticsGetQueryResult (line 199) | type GetOcrStatisticsApiOcrStatisticsGetQueryResult = NonNullable<Awaite...
  type GetOcrStatisticsApiOcrStatisticsGetQueryError (line 200) | type GetOcrStatisticsApiOcrStatisticsGetQueryError = unknown
  function useGetOcrStatisticsApiOcrStatisticsGet (line 231) | function useGetOcrStatisticsApiOcrStatisticsGet<TData = Awaited<ReturnTy...

FILE: free-todo-frontend/lib/generated/proactive-ocr/proactive-ocr.ts
  type SecondParameter (line 30) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type startProactiveOcrApiProactiveOcrStartPostResponse200 (line 38) | type startProactiveOcrApiProactiveOcrStartPostResponse200 = {
  type startProactiveOcrApiProactiveOcrStartPostResponseSuccess (line 43) | type startProactiveOcrApiProactiveOcrStartPostResponseSuccess = (startPr...
  type startProactiveOcrApiProactiveOcrStartPostResponse (line 48) | type startProactiveOcrApiProactiveOcrStartPostResponse = (startProactive...
  type StartProactiveOcrApiProactiveOcrStartPostMutationResult (line 99) | type StartProactiveOcrApiProactiveOcrStartPostMutationResult = NonNullab...
  type StartProactiveOcrApiProactiveOcrStartPostMutationError (line 101) | type StartProactiveOcrApiProactiveOcrStartPostMutationError = unknown
  type stopProactiveOcrApiProactiveOcrStopPostResponse200 (line 120) | type stopProactiveOcrApiProactiveOcrStopPostResponse200 = {
  type stopProactiveOcrApiProactiveOcrStopPostResponseSuccess (line 125) | type stopProactiveOcrApiProactiveOcrStopPostResponseSuccess = (stopProac...
  type stopProactiveOcrApiProactiveOcrStopPostResponse (line 130) | type stopProactiveOcrApiProactiveOcrStopPostResponse = (stopProactiveOcr...
  type StopProactiveOcrApiProactiveOcrStopPostMutationResult (line 181) | type StopProactiveOcrApiProactiveOcrStopPostMutationResult = NonNullable...
  type StopProactiveOcrApiProactiveOcrStopPostMutationError (line 183) | type StopProactiveOcrApiProactiveOcrStopPostMutationError = unknown
  type captureOnceApiProactiveOcrCapturePostResponse200 (line 202) | type captureOnceApiProactiveOcrCapturePostResponse200 = {
  type captureOnceApiProactiveOcrCapturePostResponseSuccess (line 207) | type captureOnceApiProactiveOcrCapturePostResponseSuccess = (captureOnce...
  type captureOnceApiProactiveOcrCapturePostResponse (line 212) | type captureOnceApiProactiveOcrCapturePostResponse = (captureOnceApiProa...
  type CaptureOnceApiProactiveOcrCapturePostMutationResult (line 263) | type CaptureOnceApiProactiveOcrCapturePostMutationResult = NonNullable<A...
  type CaptureOnceApiProactiveOcrCapturePostMutationError (line 265) | type CaptureOnceApiProactiveOcrCapturePostMutationError = unknown
  type getProactiveOcrStatusApiProactiveOcrStatusGetResponse200 (line 284) | type getProactiveOcrStatusApiProactiveOcrStatusGetResponse200 = {
  type getProactiveOcrStatusApiProactiveOcrStatusGetResponseSuccess (line 289) | type getProactiveOcrStatusApiProactiveOcrStatusGetResponseSuccess = (get...
  type getProactiveOcrStatusApiProactiveOcrStatusGetResponse (line 294) | type getProactiveOcrStatusApiProactiveOcrStatusGetResponse = (getProacti...
  type GetProactiveOcrStatusApiProactiveOcrStatusGetQueryResult (line 344) | type GetProactiveOcrStatusApiProactiveOcrStatusGetQueryResult = NonNulla...
  type GetProactiveOcrStatusApiProactiveOcrStatusGetQueryError (line 345) | type GetProactiveOcrStatusApiProactiveOcrStatusGetQueryError = unknown
  function useGetProactiveOcrStatusApiProactiveOcrStatusGet (line 376) | function useGetProactiveOcrStatusApiProactiveOcrStatusGet<TData = Awaite...
  type healthCheckApiProactiveOcrHealthGetResponse200 (line 395) | type healthCheckApiProactiveOcrHealthGetResponse200 = {
  type healthCheckApiProactiveOcrHealthGetResponseSuccess (line 400) | type healthCheckApiProactiveOcrHealthGetResponseSuccess = (healthCheckAp...
  type healthCheckApiProactiveOcrHealthGetResponse (line 405) | type healthCheckApiProactiveOcrHealthGetResponse = (healthCheckApiProact...
  type HealthCheckApiProactiveOcrHealthGetQueryResult (line 455) | type HealthCheckApiProactiveOcrHealthGetQueryResult = NonNullable<Awaite...
  type HealthCheckApiProactiveOcrHealthGetQueryError (line 456) | type HealthCheckApiProactiveOcrHealthGetQueryError = unknown
  function useHealthCheckApiProactiveOcrHealthGet (line 487) | function useHealthCheckApiProactiveOcrHealthGet<TData = Awaited<ReturnTy...

FILE: free-todo-frontend/lib/generated/rag/rag.ts
  type SecondParameter (line 30) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type ragHealthCheckApiRagHealthGetResponse200 (line 38) | type ragHealthCheckApiRagHealthGetResponse200 = {
  type ragHealthCheckApiRagHealthGetResponseSuccess (line 43) | type ragHealthCheckApiRagHealthGetResponseSuccess = (ragHealthCheckApiRa...
  type ragHealthCheckApiRagHealthGetResponse (line 48) | type ragHealthCheckApiRagHealthGetResponse = (ragHealthCheckApiRagHealth...
  type RagHealthCheckApiRagHealthGetQueryResult (line 98) | type RagHealthCheckApiRagHealthGetQueryResult = NonNullable<Awaited<Retu...
  type RagHealthCheckApiRagHealthGetQueryError (line 99) | type RagHealthCheckApiRagHealthGetQueryError = unknown
  function useRagHealthCheckApiRagHealthGet (line 130) | function useRagHealthCheckApiRagHealthGet<TData = Awaited<ReturnType<typ...
  type getAppIconApiAppIconAppNameGetResponse200 (line 156) | type getAppIconApiAppIconAppNameGetResponse200 = {
  type getAppIconApiAppIconAppNameGetResponse422 (line 161) | type getAppIconApiAppIconAppNameGetResponse422 = {
  type getAppIconApiAppIconAppNameGetResponseSuccess (line 166) | type getAppIconApiAppIconAppNameGetResponseSuccess = (getAppIconApiAppIc...
  type getAppIconApiAppIconAppNameGetResponseError (line 169) | type getAppIconApiAppIconAppNameGetResponseError = (getAppIconApiAppIcon...
  type getAppIconApiAppIconAppNameGetResponse (line 173) | type getAppIconApiAppIconAppNameGetResponse = (getAppIconApiAppIconAppNa...
  type GetAppIconApiAppIconAppNameGetQueryResult (line 223) | type GetAppIconApiAppIconAppNameGetQueryResult = NonNullable<Awaited<Ret...
  type GetAppIconApiAppIconAppNameGetQueryError (line 224) | type GetAppIconApiAppIconAppNameGetQueryError = HTTPValidationError
  function useGetAppIconApiAppIconAppNameGet (line 255) | function useGetAppIconApiAppIconAppNameGet<TData = Awaited<ReturnType<ty...

FILE: free-todo-frontend/lib/generated/scheduler/scheduler.ts
  type SecondParameter (line 38) | type SecondParameter<T extends (...args: never) => unknown> = Parameters...
  type getAllJobsApiSchedulerJobsGetResponse200 (line 46) | type getAllJobsApiSchedulerJobsGetResponse200 = {
  type getAllJobsApiSchedulerJobsGetResponseSuccess (line 51) | type getAllJobsApiSchedulerJobsGetResponseSuccess = (getAllJobsApiSchedu...
  type getAllJobsApiSchedulerJobsGetResponse (line 56) | type getAllJobsApiSchedulerJobsGetResponse = (getAllJobsApiSchedulerJobs...
  type GetAllJobsApiSchedulerJobsGetQueryResult (line 106) | type GetAllJobsApiSchedulerJobsGetQueryResult = NonNullable<Awaited<Retu...
  type GetAllJobsApiSchedulerJobsGetQueryError (line 107) | type GetAllJobsApiSchedulerJobsGetQueryError = unknown
  function useGetAllJobsApiSchedulerJobsGet (line 138) | function useGetAllJobsApiSchedulerJobsGet<TData = Awaited<ReturnType<typ...
  type getJobDetailApiSchedulerJobsJobIdGetResponse200 (line 157) | type getJobDetailApiSchedulerJobsJobIdGetResponse200 = {
  type getJobDetailApiSchedulerJobsJobIdGetResponse422 (line 162) | type getJobDetailApiSchedulerJobsJobIdGetResponse422 = {
  type getJobDetailApiSchedulerJobsJobIdGetResponseSuccess (line 167) | type getJobDetailApiSchedulerJobsJobIdGetResponseSuccess = (getJobDetail...
  type getJobDetailApiSchedulerJobsJobIdGetResponseError (line 170) | type getJobDetailApiSchedulerJobsJobIdGetResponseError = (getJobDetailAp...
  type getJobDetailApiSchedulerJobsJobIdGetResponse (line 174) | type getJobDetailApiSchedulerJobsJobIdGetResponse = (getJobDetailApiSche...
  type GetJobDetailApiSchedulerJobsJobIdGetQueryResult (line 224) | type GetJobDetailApiSchedulerJobsJobIdGetQueryResult = NonNullable<Await...
  type GetJobDetailApiSchedulerJobsJobIdGetQueryError (line 225) | type GetJobDetailApiSchedulerJobsJobIdGetQueryError = HTTPValidationError
  function useGetJobDetailApiSchedulerJobsJobIdGet (line 256) | function useGetJobDetailApiSchedulerJobsJobIdGet<TData = Awaited<ReturnT...
  type removeJobApiSchedulerJobsJobIdDeleteResponse200 (line 275) | type removeJobApiSchedulerJobsJobIdDeleteResponse200 = {
  type removeJobApiSchedulerJobsJobIdDeleteResponse422 (line 280) | type removeJobApiSchedulerJobsJobIdDeleteResponse422 = {
  type removeJobApiSchedulerJobsJobIdDeleteResponseSuccess (line 285) | type removeJobApiSchedulerJobsJobIdDeleteResponseSuccess = (removeJobApi...
  type removeJobApiSchedulerJobsJobIdDeleteResponseError (line 288) | type removeJobApiSchedulerJobsJobIdDeleteResponseError = (removeJobApiSc...
  type removeJobApiSchedulerJobsJobIdDeleteResponse (line 292) | type removeJobApiSchedulerJobsJobIdDeleteResponse = (removeJobApiSchedul...
  type RemoveJobApiSchedulerJobsJobIdDeleteMutationResult (line 343) | type RemoveJobApiSchedulerJobsJobIdDeleteMutationResult = NonNullable<Aw...
  type RemoveJobApiSchedulerJobsJobIdDeleteMutationError (line 345) | type RemoveJobApiSchedulerJobsJobIdDeleteMutationError = HTTPValidationE...
  type pauseJobApiSchedulerJobsJobIdPausePostResponse200 (line 364) | type pauseJobApiSchedulerJobsJobIdPausePostResponse200 = {
  type pauseJobApiSchedulerJobsJobIdPausePostResponse422 (line 369) | type pauseJobApiSchedulerJobsJobIdPausePostResponse422 = {
  type pauseJobApiSchedulerJobsJobIdPausePostResponseSuccess (line 374) | type pauseJobApiSchedulerJobsJobIdPausePostResponseSuccess = (pauseJobAp...
  type pauseJobApiSchedulerJobsJobIdPausePostResponseError (line 377) | type pauseJobApiSchedulerJobsJobIdPausePostResponseError = (pauseJobApiS...
  type pauseJobApiSchedulerJobsJobIdPausePostResponse (line 381) | type pauseJobApiSchedulerJobsJobIdPausePostResponse = (pauseJobApiSchedu...
  type PauseJobApiSchedulerJobsJobIdPausePostMutationResult (line 432) | type PauseJobApiSchedulerJobsJobIdPausePostMutationResult = NonNullable<...
  type PauseJobApiSchedulerJobsJobIdPausePostMutationError (line 434) | type PauseJobApiSchedulerJobsJobIdPausePostMutationError = HTTPValidatio...
  type resumeJobApiSchedulerJobsJobIdResumePostResponse200 (line 453) | type resumeJobApiSchedulerJobsJobIdResumePostResponse200 = {
  type resumeJobApiSchedulerJobsJobIdResumePostResponse422 (line 458) | type resumeJobApiSchedulerJobsJobIdResumePostResponse422 = {
  type resumeJobApiSchedulerJobsJobIdResumePostResponseSuccess (line 463) | type resumeJobApiSchedulerJobsJobIdResumePostResponseSuccess = (resumeJo...
  type resumeJobApiSchedulerJobsJobIdResumePostResponseError (line 466) | type resumeJobApiSchedulerJobsJobIdResumePostResponseError = (resumeJobA...
  type resumeJobApiSchedulerJobsJobIdResumePostResponse (line 470) | type resumeJobApiSchedulerJobsJobIdResumePostResponse = (resumeJobApiSch...
  type ResumeJobApiSchedulerJobsJobIdResumePostMutationResult (line 521) | type ResumeJobApiSchedulerJobsJobIdResumePostMutationResult = NonNullabl...
  type ResumeJobApiSchedulerJobsJobIdResumePostMutationError (line 523) | type ResumeJobApiSchedulerJobsJobIdResumePostMutationError = HTTPValidat...
  type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse200 (line 542) | type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse200 = {
  type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse422 (line 547) | type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse422 = {
  type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponseSuccess (line 552) | type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponseSuccess = ...
  type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponseError (line 555) | type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponseError = (u...
  type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse (line 559) | type updateJobIntervalApiSchedulerJobsJobIdIntervalPutResponse = (update...
  type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationResult (line 612) | type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationResult = N...
  type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationBody (line 613) | type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationBody = Job...
  type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationError (line 614) | type UpdateJobIntervalApiSchedulerJobsJobIdIntervalPutMutationError = HT...
  type getSchedulerStatusApiSchedulerStatusGetResponse200 (line 633) | type getSchedulerStatusApiSchedulerStatusGetResponse200 = {
  type getSchedulerStatusApiSchedulerStatusGetResponseSuccess (line 638) | type getSchedulerStatusApiSchedulerStatusGetResponseSuccess = (getSchedu...
  type getSchedulerStatusApiSchedulerStatusGetResponse (line 643) | type getSchedulerStatusApiSchedulerStatusGetResponse = (getSchedulerStat...
  type GetSchedulerStatusApiSchedulerStatusGetQueryResult (line 693) | type GetSchedulerStatusApiSchedulerStatusGetQueryResult = NonNullable<Aw...
  type GetSchedulerStatusApiSchedulerStatusGetQueryError (line 694) | type GetSchedulerStatusApiSchedulerStatusGetQueryError = unknown
  function useGetSchedulerStatusApiSchedulerStatusGet (line 725) | function useGetSchedulerStatusApiSchedulerStatusGet<TData = Awaited<Retu...
  type pauseAllJobsApiSchedulerJobsPauseAllPostResponse200 (line 744) | type pauseAllJobsApiSchedulerJobsPauseAllPostResponse200 = {
  type pauseAllJobsApiSchedulerJobsPauseAllPostResponseSuccess (line 749) | type pauseAllJobsApiSchedulerJobsPauseAllPostResponseSuccess = (pauseAll...
  type pauseAllJobsApiSchedulerJobsPauseAllPostResponse (line 754) | type pauseAllJobsApiSchedulerJobsPauseAllPostResponse = (pauseAllJobsApi...
  type PauseAllJobsApiSchedulerJobsPauseAllPostMutationResult (line 805) | type PauseAllJobsApiSchedulerJobsPauseAllPostMutationResult = NonNullabl...
  type PauseAllJobsApiSchedulerJobsPauseAllPostMutationError (line 807) | type PauseAllJobsApiSchedulerJobsPauseAllPostMutationError = unknown
  type resumeAllJobsApiSchedulerJobsResumeAllPostResponse200 (line 826) | type resumeAllJobsApiSchedulerJobsResumeAllPostResponse200 = {
  type resumeAllJobsApiSchedulerJobsResumeAllPostResponseSuccess (line 831) | type resumeAllJobsApiSchedulerJobsResumeAllPostResponseSuccess = (resume...
  type resumeAllJobsApiSchedulerJobsResumeAllPostResponse (line 836) | type resumeAllJobsApiSchedulerJobsResumeAllPostResponse = (resumeAllJobs...
  type ResumeAllJobsApiSchedulerJobsResumeAllPostMutationResult (line 887) | type ResumeAllJobsApiSchedulerJobsResumeAllPostMutationResult = NonNulla...
  type ResumeAllJobsApiSchedulerJobsResumeAllPostMutationError (line 889) | type ResumeAllJobsApiSchedulerJobsResumeAllPostMutationError = unknown

FILE: free-todo-frontend/lib/generated/schemas/activityEventsResponse.ts
  type ActivityEventsResponse (line 9) | interface ActivityEventsResponse {

FILE: free-todo-frontend/lib/generated/schemas/activityListResponse.ts
  type ActivityListResponse (line 10) | interface ActivityListResponse {

FILE: free-todo-frontend/lib/generated/schemas/activityResponse.ts
  type ActivityResponse (line 9) | interface ActivityResponse {

FILE: free-todo-frontend/lib/generated/schemas/activityResponseAiSummary.ts
  type ActivityResponseAiSummary (line 9) | type ActivityResponseAiSummary = string | null;

FILE: free-todo-frontend/lib/generated/schemas/activityResponseAiTitle.ts
  type ActivityResponseAiTitle (line 9) | type ActivityResponseAiTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/activityResponseCreatedAt.ts
  type ActivityResponseCreatedAt (line 9) | type ActivityResponseCreatedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/activityResponseUpdatedAt.ts
  type ActivityResponseUpdatedAt (line 9) | type ActivityResponseUpdatedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/addMessageRequest.ts
  type AddMessageRequest (line 9) | interface AddMessageRequest {

FILE: free-todo-frontend/lib/generated/schemas/audioLinkItem.ts
  type AudioLinkItem (line 9) | interface AudioLinkItem {

FILE: free-todo-frontend/lib/generated/schemas/audioLinkRequest.ts
  type AudioLinkRequest (line 10) | interface AudioLinkRequest {

FILE: free-todo-frontend/lib/generated/schemas/bodyImportIcsApiTodosImportIcsPost.ts
  type BodyImportIcsApiTodosImportIcsPost (line 9) | interface BodyImportIcsApiTodosImportIcsPost {

FILE: free-todo-frontend/lib/generated/schemas/bodyUploadAttachmentsApiTodosTodoIdAttachmentsPost.ts
  type BodyUploadAttachmentsApiTodosTodoIdAttachmentsPost (line 9) | interface BodyUploadAttachmentsApiTodosTodoIdAttachmentsPost {

FILE: free-todo-frontend/lib/generated/schemas/capabilitiesResponse.ts
  type CapabilitiesResponse (line 10) | interface CapabilitiesResponse {

FILE: free-todo-frontend/lib/generated/schemas/capabilitiesResponseMissingDeps.ts
  type CapabilitiesResponseMissingDeps (line 9) | type CapabilitiesResponseMissingDeps = {[key: string]: string[]};

FILE: free-todo-frontend/lib/generated/schemas/chatMessage.ts
  type ChatMessage (line 9) | interface ChatMessage {

FILE: free-todo-frontend/lib/generated/schemas/chatMessageContext.ts
  type ChatMessageContext (line 9) | type ChatMessageContext = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageConversationId.ts
  type ChatMessageConversationId (line 9) | type ChatMessageConversationId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageExternalTools.ts
  type ChatMessageExternalTools (line 9) | type ChatMessageExternalTools = string[] | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageMode.ts
  type ChatMessageMode (line 9) | type ChatMessageMode = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageProjectId.ts
  type ChatMessageProjectId (line 9) | type ChatMessageProjectId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageSelectedTools.ts
  type ChatMessageSelectedTools (line 9) | type ChatMessageSelectedTools = string[] | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageSystemPrompt.ts
  type ChatMessageSystemPrompt (line 9) | type ChatMessageSystemPrompt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageTaskIds.ts
  type ChatMessageTaskIds (line 9) | type ChatMessageTaskIds = number[] | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageUserInput.ts
  type ChatMessageUserInput (line 9) | type ChatMessageUserInput = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageWithContext.ts
  type ChatMessageWithContext (line 10) | interface ChatMessageWithContext {

FILE: free-todo-frontend/lib/generated/schemas/chatMessageWithContextConversationId.ts
  type ChatMessageWithContextConversationId (line 9) | type ChatMessageWithContextConversationId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatMessageWithContextEventContext.ts
  type ChatMessageWithContextEventContext (line 9) | type ChatMessageWithContextEventContext = { [key: string]: unknown }[] |...

FILE: free-todo-frontend/lib/generated/schemas/chatMessageWithContextEventContextAnyOfItem.ts
  type ChatMessageWithContextEventContextAnyOfItem (line 9) | type ChatMessageWithContextEventContextAnyOfItem = { [key: string]: unkn...

FILE: free-todo-frontend/lib/generated/schemas/chatMessageWorkspacePath.ts
  type ChatMessageWorkspacePath (line 9) | type ChatMessageWorkspacePath = string | null;

FILE: free-todo-frontend/lib/generated/schemas/chatResponse.ts
  type ChatResponse (line 12) | interface ChatResponse {

FILE: free-todo-frontend/lib/generated/schemas/chatResponsePerformance.ts
  type ChatResponsePerformance (line 9) | type ChatResponsePerformance = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/chatResponsePerformanceAnyOf.ts
  type ChatResponsePerformanceAnyOf (line 9) | type ChatResponsePerformanceAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/chatResponseQueryInfo.ts
  type ChatResponseQueryInfo (line 9) | type ChatResponseQueryInfo = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/chatResponseQueryInfoAnyOf.ts
  type ChatResponseQueryInfoAnyOf (line 9) | type ChatResponseQueryInfoAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/chatResponseRetrievalInfo.ts
  type ChatResponseRetrievalInfo (line 9) | type ChatResponseRetrievalInfo = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/chatResponseRetrievalInfoAnyOf.ts
  type ChatResponseRetrievalInfoAnyOf (line 9) | type ChatResponseRetrievalInfoAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/chatResponseSessionId.ts
  type ChatResponseSessionId (line 9) | type ChatResponseSessionId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/cleanupOldDataApiCleanupPostParams.ts
  type CleanupOldDataApiCleanupPostParams (line 9) | type CleanupOldDataApiCleanupPostParams = {

FILE: free-todo-frontend/lib/generated/schemas/contextListResponse.ts
  type ContextListResponse (line 13) | interface ContextListResponse {

FILE: free-todo-frontend/lib/generated/schemas/contextResponse.ts
  type ContextResponse (line 22) | interface ContextResponse {

FILE: free-todo-frontend/lib/generated/schemas/contextResponseAiSummary.ts
  type ContextResponseAiSummary (line 12) | type ContextResponseAiSummary = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseAiTitle.ts
  type ContextResponseAiTitle (line 12) | type ContextResponseAiTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseAppName.ts
  type ContextResponseAppName (line 12) | type ContextResponseAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseCreatedAt.ts
  type ContextResponseCreatedAt (line 12) | type ContextResponseCreatedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseEndTime.ts
  type ContextResponseEndTime (line 12) | type ContextResponseEndTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseProjectId.ts
  type ContextResponseProjectId (line 12) | type ContextResponseProjectId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseStartTime.ts
  type ContextResponseStartTime (line 12) | type ContextResponseStartTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseTaskId.ts
  type ContextResponseTaskId (line 12) | type ContextResponseTaskId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/contextResponseWindowTitle.ts
  type ContextResponseWindowTitle (line 12) | type ContextResponseWindowTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/contextUpdateRequest.ts
  type ContextUpdateRequest (line 14) | interface ContextUpdateRequest {

FILE: free-todo-frontend/lib/generated/schemas/contextUpdateRequestProjectId.ts
  type ContextUpdateRequestProjectId (line 12) | type ContextUpdateRequestProjectId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/contextUpdateRequestTaskId.ts
  type ContextUpdateRequestTaskId (line 12) | type ContextUpdateRequestTaskId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/countEventsApiEventsCountGetParams.ts
  type CountEventsApiEventsCountGetParams (line 9) | type CountEventsApiEventsCountGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/createdTodo.ts
  type CreatedTodo (line 12) | interface CreatedTodo {

FILE: free-todo-frontend/lib/generated/schemas/createdTodoScheduledTime.ts
  type CreatedTodoScheduledTime (line 12) | type CreatedTodoScheduledTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponse.ts
  type EventDetailResponse (line 10) | interface EventDetailResponse {

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponseAiSummary.ts
  type EventDetailResponseAiSummary (line 9) | type EventDetailResponseAiSummary = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponseAiTitle.ts
  type EventDetailResponseAiTitle (line 9) | type EventDetailResponseAiTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponseAppName.ts
  type EventDetailResponseAppName (line 9) | type EventDetailResponseAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponseEndTime.ts
  type EventDetailResponseEndTime (line 9) | type EventDetailResponseEndTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventDetailResponseWindowTitle.ts
  type EventDetailResponseWindowTitle (line 9) | type EventDetailResponseWindowTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventListResponse.ts
  type EventListResponse (line 13) | interface EventListResponse {

FILE: free-todo-frontend/lib/generated/schemas/eventResponse.ts
  type EventResponse (line 9) | interface EventResponse {

FILE: free-todo-frontend/lib/generated/schemas/eventResponseAiSummary.ts
  type EventResponseAiSummary (line 9) | type EventResponseAiSummary = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventResponseAiTitle.ts
  type EventResponseAiTitle (line 9) | type EventResponseAiTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventResponseAppName.ts
  type EventResponseAppName (line 9) | type EventResponseAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventResponseEndTime.ts
  type EventResponseEndTime (line 9) | type EventResponseEndTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/eventResponseFirstScreenshotId.ts
  type EventResponseFirstScreenshotId (line 9) | type EventResponseFirstScreenshotId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/eventResponseWindowTitle.ts
  type EventResponseWindowTitle (line 9) | type EventResponseWindowTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/exportIcsApiTodosExportIcsGetParams.ts
  type ExportIcsApiTodosExportIcsGetParams (line 9) | type ExportIcsApiTodosExportIcsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/extractTodosAndSchedulesApiAudioExtractPostParams.ts
  type ExtractTodosAndSchedulesApiAudioExtractPostParams (line 9) | type ExtractTodosAndSchedulesApiAudioExtractPostParams = {

FILE: free-todo-frontend/lib/generated/schemas/extractedMessageTodo.ts
  type ExtractedMessageTodo (line 12) | interface ExtractedMessageTodo {

FILE: free-todo-frontend/lib/generated/schemas/extractedMessageTodoDescription.ts
  type ExtractedMessageTodoDescription (line 12) | type ExtractedMessageTodoDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodo.ts
  type ExtractedTodo (line 13) | interface ExtractedTodo {

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoConfidence.ts
  type ExtractedTodoConfidence (line 12) | type ExtractedTodoConfidence = number | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoDescription.ts
  type ExtractedTodoDescription (line 12) | type ExtractedTodoDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoScheduledTime.ts
  type ExtractedTodoScheduledTime (line 12) | type ExtractedTodoScheduledTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoSourceText.ts
  type ExtractedTodoSourceText (line 12) | type ExtractedTodoSourceText = string | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoTimeInfo.ts
  type ExtractedTodoTimeInfo (line 12) | type ExtractedTodoTimeInfo = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/extractedTodoTimeInfoAnyOf.ts
  type ExtractedTodoTimeInfoAnyOf (line 9) | type ExtractedTodoTimeInfoAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/floatingCaptureRequest.ts
  type FloatingCaptureRequest (line 12) | interface FloatingCaptureRequest {

FILE: free-todo-frontend/lib/generated/schemas/floatingCaptureResponse.ts
  type FloatingCaptureResponse (line 14) | interface FloatingCaptureResponse {

FILE: free-todo-frontend/lib/generated/schemas/generateTasksResponse.ts
  type GenerateTasksResponse (line 13) | interface GenerateTasksResponse {

FILE: free-todo-frontend/lib/generated/schemas/generatedTaskItem.ts
  type GeneratedTaskItem (line 13) | interface GeneratedTaskItem {

FILE: free-todo-frontend/lib/generated/schemas/generatedTaskItemDescription.ts
  type GeneratedTaskItemDescription (line 12) | type GeneratedTaskItemDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/getChatHistoryApiChatHistoryGetParams.ts
  type GetChatHistoryApiChatHistoryGetParams (line 9) | type GetChatHistoryApiChatHistoryGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getChatPromptsApiGetChatPromptsGetParams.ts
  type GetChatPromptsApiGetChatPromptsGetParams (line 9) | type GetChatPromptsApiGetChatPromptsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getContextsApiContextsGetParams.ts
  type GetContextsApiContextsGetParams (line 9) | type GetContextsApiContextsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getCostStatsApiCostTrackingStatsGetParams.ts
  type GetCostStatsApiCostTrackingStatsGetParams (line 9) | type GetCostStatsApiCostTrackingStatsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getLogContentApiLogsContentGetParams.ts
  type GetLogContentApiLogsContentGetParams (line 9) | type GetLogContentApiLogsContentGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getProjectTasksApiProjectsProjectIdTasksGetParams.ts
  type GetProjectTasksApiProjectsProjectIdTasksGetParams (line 9) | type GetProjectTasksApiProjectsProjectIdTasksGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getProjectsApiProjectsGetParams.ts
  type GetProjectsApiProjectsGetParams (line 9) | type GetProjectsApiProjectsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getQuerySuggestionsApiChatSuggestionsGetParams.ts
  type GetQuerySuggestionsApiChatSuggestionsGetParams (line 9) | type GetQuerySuggestionsApiChatSuggestionsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getRecordingsApiAudioRecordingsGetParams.ts
  type GetRecordingsApiAudioRecordingsGetParams (line 9) | type GetRecordingsApiAudioRecordingsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getScreenshotsApiScreenshotsGetParams.ts
  type GetScreenshotsApiScreenshotsGetParams (line 9) | type GetScreenshotsApiScreenshotsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getTaskProgressApiProjectsProjectIdTasksTaskIdProgressGetParams.ts
  type GetTaskProgressApiProjectsProjectIdTasksTaskIdProgressGetParams (line 9) | type GetTaskProgressApiProjectsProjectIdTasksTaskIdProgressGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getTaskProgressLatestApiProjectsProjectIdTasksTaskIdProgressLatestGet200.ts
  type GetTaskProgressLatestApiProjectsProjectIdTasksTaskIdProgressLatestGet200 (line 10) | type GetTaskProgressLatestApiProjectsProjectIdTasksTaskIdProgressLatestG...

FILE: free-todo-frontend/lib/generated/schemas/getTimeAllocationApiTimeAllocationGetParams.ts
  type GetTimeAllocationApiTimeAllocationGetParams (line 9) | type GetTimeAllocationApiTimeAllocationGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getTimelineApiAudioTimelineGetParams.ts
  type GetTimelineApiAudioTimelineGetParams (line 9) | type GetTimelineApiAudioTimelineGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/getTranscriptionApiAudioTranscriptionRecordingIdGetParams.ts
  type GetTranscriptionApiAudioTranscriptionRecordingIdGetParams (line 9) | type GetTranscriptionApiAudioTranscriptionRecordingIdGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/hTTPValidationError.ts
  type HTTPValidationError (line 10) | interface HTTPValidationError {

FILE: free-todo-frontend/lib/generated/schemas/jobInfo.ts
  type JobInfo (line 12) | interface JobInfo {

FILE: free-todo-frontend/lib/generated/schemas/jobInfoName.ts
  type JobInfoName (line 9) | type JobInfoName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/jobInfoNextRunTime.ts
  type JobInfoNextRunTime (line 9) | type JobInfoNextRunTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/jobIntervalUpdateRequest.ts
  type JobIntervalUpdateRequest (line 12) | interface JobIntervalUpdateRequest {

FILE: free-todo-frontend/lib/generated/schemas/jobIntervalUpdateRequestHours.ts
  type JobIntervalUpdateRequestHours (line 9) | type JobIntervalUpdateRequestHours = number | null;

FILE: free-todo-frontend/lib/generated/schemas/jobIntervalUpdateRequestMinutes.ts
  type JobIntervalUpdateRequestMinutes (line 9) | type JobIntervalUpdateRequestMinutes = number | null;

FILE: free-todo-frontend/lib/generated/schemas/jobIntervalUpdateRequestSeconds.ts
  type JobIntervalUpdateRequestSeconds (line 9) | type JobIntervalUpdateRequestSeconds = number | null;

FILE: free-todo-frontend/lib/generated/schemas/jobListResponse.ts
  type JobListResponse (line 13) | interface JobListResponse {

FILE: free-todo-frontend/lib/generated/schemas/jobOperationResponse.ts
  type JobOperationResponse (line 12) | interface JobOperationResponse {

FILE: free-todo-frontend/lib/generated/schemas/journalAutoLinkCandidate.ts
  type JournalAutoLinkCandidate (line 12) | interface JournalAutoLinkCandidate {

FILE: free-todo-frontend/lib/generated/schemas/journalAutoLinkRequest.ts
  type JournalAutoLinkRequest (line 12) | interface JournalAutoLinkRequest {

FILE: free-todo-frontend/lib/generated/schemas/journalAutoLinkResponse.ts
  type JournalAutoLinkResponse (line 13) | interface JournalAutoLinkResponse {

FILE: free-todo-frontend/lib/generated/schemas/journalCreate.ts
  type JournalCreate (line 12) | interface JournalCreate {

FILE: free-todo-frontend/lib/generated/schemas/journalGenerateRequest.ts
  type JournalGenerateRequest (line 12) | interface JournalGenerateRequest {

FILE: free-todo-frontend/lib/generated/schemas/journalGenerateResponse.ts
  type JournalGenerateResponse (line 12) | interface JournalGenerateResponse {

FILE: free-todo-frontend/lib/generated/schemas/journalListResponse.ts
  type JournalListResponse (line 13) | interface JournalListResponse {

FILE: free-todo-frontend/lib/generated/schemas/journalResponse.ts
  type JournalResponse (line 13) | interface JournalResponse {

FILE: free-todo-frontend/lib/generated/schemas/journalResponseDeletedAt.ts
  type JournalResponseDeletedAt (line 12) | type JournalResponseDeletedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/journalTag.ts
  type JournalTag (line 12) | interface JournalTag {

FILE: free-todo-frontend/lib/generated/schemas/journalUpdate.ts
  type JournalUpdate (line 12) | interface JournalUpdate {

FILE: free-todo-frontend/lib/generated/schemas/journalUpdateContentFormat.ts
  type JournalUpdateContentFormat (line 12) | type JournalUpdateContentFormat = string | null;

FILE: free-todo-frontend/lib/generated/schemas/journalUpdateDate.ts
  type JournalUpdateDate (line 12) | type JournalUpdateDate = string | null;

FILE: free-todo-frontend/lib/generated/schemas/journalUpdateName.ts
  type JournalUpdateName (line 12) | type JournalUpdateName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/journalUpdateTagIds.ts
  type JournalUpdateTagIds (line 12) | type JournalUpdateTagIds = number[] | null;

FILE: free-todo-frontend/lib/generated/schemas/journalUpdateUserNotes.ts
  type JournalUpdateUserNotes (line 12) | type JournalUpdateUserNotes = string | null;

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasFloatingCaptureExtractedTodo.ts
  type LifetraceSchemasFloatingCaptureExtractedTodo (line 13) | interface LifetraceSchemasFloatingCaptureExtractedTodo {

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasFloatingCaptureExtractedTodoDescription.ts
  type LifetraceSchemasFloatingCaptureExtractedTodoDescription (line 12) | type LifetraceSchemasFloatingCaptureExtractedTodoDescription = string | ...

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasFloatingCaptureExtractedTodoSourceText.ts
  type LifetraceSchemasFloatingCaptureExtractedTodoSourceText (line 12) | type LifetraceSchemasFloatingCaptureExtractedTodoSourceText = string | n...

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasFloatingCaptureExtractedTodoTimeInfo.ts
  type LifetraceSchemasFloatingCaptureExtractedTodoTimeInfo (line 12) | type LifetraceSchemasFloatingCaptureExtractedTodoTimeInfo = { [key: stri...

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasFloatingCaptureExtractedTodoTimeInfoAnyOf.ts
  type LifetraceSchemasFloatingCaptureExtractedTodoTimeInfoAnyOf (line 9) | type LifetraceSchemasFloatingCaptureExtractedTodoTimeInfoAnyOf = { [key:...

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasTodoExtractionExtractedTodo.ts
  type LifetraceSchemasTodoExtractionExtractedTodo (line 13) | interface LifetraceSchemasTodoExtractionExtractedTodo {

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasTodoExtractionExtractedTodoConfidence.ts
  type LifetraceSchemasTodoExtractionExtractedTodoConfidence (line 12) | type LifetraceSchemasTodoExtractionExtractedTodoConfidence = number | null;

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasTodoExtractionExtractedTodoDescription.ts
  type LifetraceSchemasTodoExtractionExtractedTodoDescription (line 12) | type LifetraceSchemasTodoExtractionExtractedTodoDescription = string | n...

FILE: free-todo-frontend/lib/generated/schemas/lifetraceSchemasTodoExtractionExtractedTodoScheduledTime.ts
  type LifetraceSchemasTodoExtractionExtractedTodoScheduledTime (line 12) | type LifetraceSchemasTodoExtractionExtractedTodoScheduledTime = string |...

FILE: free-todo-frontend/lib/generated/schemas/linkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostParams.ts
  type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostParams (line 9) | type LinkExtractedItemsApiAudioTranscriptionRecordingIdLinkPostParams = {

FILE: free-todo-frontend/lib/generated/schemas/listActivitiesApiActivitiesGetParams.ts
  type ListActivitiesApiActivitiesGetParams (line 9) | type ListActivitiesApiActivitiesGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/listEventsApiEventsGetParams.ts
  type ListEventsApiEventsGetParams (line 9) | type ListEventsApiEventsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/listJournalsApiJournalsGetParams.ts
  type ListJournalsApiJournalsGetParams (line 9) | type ListJournalsApiJournalsGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/listTodosApiTodosGetParams.ts
  type ListTodosApiTodosGetParams (line 9) | type ListTodosApiTodosGetParams = {

FILE: free-todo-frontend/lib/generated/schemas/manualActivityCreateRequest.ts
  type ManualActivityCreateRequest (line 9) | interface ManualActivityCreateRequest {

FILE: free-todo-frontend/lib/generated/schemas/manualActivityCreateResponse.ts
  type ManualActivityCreateResponse (line 9) | interface ManualActivityCreateResponse {

FILE: free-todo-frontend/lib/generated/schemas/manualActivityCreateResponseAiSummary.ts
  type ManualActivityCreateResponseAiSummary (line 9) | type ManualActivityCreateResponseAiSummary = string | null;

FILE: free-todo-frontend/lib/generated/schemas/manualActivityCreateResponseAiTitle.ts
  type ManualActivityCreateResponseAiTitle (line 9) | type ManualActivityCreateResponseAiTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/manualActivityCreateResponseCreatedAt.ts
  type ManualActivityCreateResponseCreatedAt (line 9) | type ManualActivityCreateResponseCreatedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionRequest.ts
  type MessageTodoExtractionRequest (line 13) | interface MessageTodoExtractionRequest {

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionRequestMessagesItem.ts
  type MessageTodoExtractionRequestMessagesItem (line 9) | type MessageTodoExtractionRequestMessagesItem = {[key: string]: string};

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionRequestParentTodoId.ts
  type MessageTodoExtractionRequestParentTodoId (line 12) | type MessageTodoExtractionRequestParentTodoId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionRequestTodoContext.ts
  type MessageTodoExtractionRequestTodoContext (line 12) | type MessageTodoExtractionRequestTodoContext = string | null;

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionResponse.ts
  type MessageTodoExtractionResponse (line 13) | interface MessageTodoExtractionResponse {

FILE: free-todo-frontend/lib/generated/schemas/messageTodoExtractionResponseErrorMessage.ts
  type MessageTodoExtractionResponseErrorMessage (line 12) | type MessageTodoExtractionResponseErrorMessage = string | null;

FILE: free-todo-frontend/lib/generated/schemas/newChatRequest.ts
  type NewChatRequest (line 9) | interface NewChatRequest {

FILE: free-todo-frontend/lib/generated/schemas/newChatRequestSessionId.ts
  type NewChatRequestSessionId (line 9) | type NewChatRequestSessionId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/newChatResponse.ts
  type NewChatResponse (line 9) | interface NewChatResponse {

FILE: free-todo-frontend/lib/generated/schemas/optimizeTranscriptionApiAudioOptimizePostParams.ts
  type OptimizeTranscriptionApiAudioOptimizePostParams (line 9) | type OptimizeTranscriptionApiAudioOptimizePostParams = {

FILE: free-todo-frontend/lib/generated/schemas/planQuestionnaireRequest.ts
  type PlanQuestionnaireRequest (line 9) | interface PlanQuestionnaireRequest {

FILE: free-todo-frontend/lib/generated/schemas/planQuestionnaireRequestSessionId.ts
  type PlanQuestionnaireRequestSessionId (line 9) | type PlanQuestionnaireRequestSessionId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/planQuestionnaireRequestTodoId.ts
  type PlanQuestionnaireRequestTodoId (line 9) | type PlanQuestionnaireRequestTodoId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/planSummaryRequest.ts
  type PlanSummaryRequest (line 10) | interface PlanSummaryRequest {

FILE: free-todo-frontend/lib/generated/schemas/planSummaryRequestAnswers.ts
  type PlanSummaryRequestAnswers (line 9) | type PlanSummaryRequestAnswers = {[key: string]: string[]};

FILE: free-todo-frontend/lib/generated/schemas/planSummaryRequestSessionId.ts
  type PlanSummaryRequestSessionId (line 9) | type PlanSummaryRequestSessionId = string | null;

FILE: free-todo-frontend/lib/generated/schemas/processInfo.ts
  type ProcessInfo (line 9) | interface ProcessInfo {

FILE: free-todo-frontend/lib/generated/schemas/processOcrApiOcrProcessPostParams.ts
  type ProcessOcrApiOcrProcessPostParams (line 9) | type ProcessOcrApiOcrProcessPostParams = {

FILE: free-todo-frontend/lib/generated/schemas/projectCreate.ts
  type ProjectCreate (line 15) | interface ProjectCreate {

FILE: free-todo-frontend/lib/generated/schemas/projectCreateDefinitionOfDone.ts
  type ProjectCreateDefinitionOfDone (line 12) | type ProjectCreateDefinitionOfDone = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectCreateDescription.ts
  type ProjectCreateDescription (line 12) | type ProjectCreateDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectListResponse.ts
  type ProjectListResponse (line 13) | interface ProjectListResponse {

FILE: free-todo-frontend/lib/generated/schemas/projectResponse.ts
  type ProjectResponse (line 14) | interface ProjectResponse {

FILE: free-todo-frontend/lib/generated/schemas/projectResponseDefinitionOfDone.ts
  type ProjectResponseDefinitionOfDone (line 12) | type ProjectResponseDefinitionOfDone = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectResponseDescription.ts
  type ProjectResponseDescription (line 12) | type ProjectResponseDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectStatus.ts
  type ProjectStatus (line 12) | type ProjectStatus = (typeof ProjectStatus)[keyof typeof ProjectStatus];

FILE: free-todo-frontend/lib/generated/schemas/projectUpdate.ts
  type ProjectUpdate (line 17) | interface ProjectUpdate {

FILE: free-todo-frontend/lib/generated/schemas/projectUpdateDefinitionOfDone.ts
  type ProjectUpdateDefinitionOfDone (line 12) | type ProjectUpdateDefinitionOfDone = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectUpdateDescription.ts
  type ProjectUpdateDescription (line 12) | type ProjectUpdateDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectUpdateName.ts
  type ProjectUpdateName (line 12) | type ProjectUpdateName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/projectUpdateStatus.ts
  type ProjectUpdateStatus (line 13) | type ProjectUpdateStatus = ProjectStatus | null;

FILE: free-todo-frontend/lib/generated/schemas/saveAndInitLlmApiSaveAndInitLlmPostBody.ts
  type SaveAndInitLlmApiSaveAndInitLlmPostBody (line 9) | type SaveAndInitLlmApiSaveAndInitLlmPostBody = {[key: string]: string};

FILE: free-todo-frontend/lib/generated/schemas/saveConfigApiSaveConfigPostBody.ts
  type SaveConfigApiSaveConfigPostBody (line 9) | type SaveConfigApiSaveConfigPostBody = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/screenshotResponse.ts
  type ScreenshotResponse (line 9) | interface ScreenshotResponse {

FILE: free-todo-frontend/lib/generated/schemas/screenshotResponseAppName.ts
  type ScreenshotResponseAppName (line 9) | type ScreenshotResponseAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/screenshotResponseTextContent.ts
  type ScreenshotResponseTextContent (line 9) | type ScreenshotResponseTextContent = string | null;

FILE: free-todo-frontend/lib/generated/schemas/screenshotResponseWindowTitle.ts
  type ScreenshotResponseWindowTitle (line 9) | type ScreenshotResponseWindowTitle = string | null;

FILE: free-todo-frontend/lib/generated/schemas/searchRequest.ts
  type SearchRequest (line 9) | interface SearchRequest {

FILE: free-todo-frontend/lib/generated/schemas/searchRequestAppName.ts
  type SearchRequestAppName (line 9) | type SearchRequestAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/searchRequestEndDate.ts
  type SearchRequestEndDate (line 9) | type SearchRequestEndDate = string | null;

FILE: free-todo-frontend/lib/generated/schemas/searchRequestQuery.ts
  type SearchRequestQuery (line 9) | type SearchRequestQuery = string | null;

FILE: free-todo-frontend/lib/generated/schemas/searchRequestStartDate.ts
  type SearchRequestStartDate (line 9) | type SearchRequestStartDate = string | null;

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchRequest.ts
  type SemanticSearchRequest (line 10) | interface SemanticSearchRequest {

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchRequestFilters.ts
  type SemanticSearchRequestFilters (line 9) | type SemanticSearchRequestFilters = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchRequestFiltersAnyOf.ts
  type SemanticSearchRequestFiltersAnyOf (line 9) | type SemanticSearchRequestFiltersAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchRequestRetrieveK.ts
  type SemanticSearchRequestRetrieveK (line 9) | type SemanticSearchRequestRetrieveK = number | null;

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResult.ts
  type SemanticSearchResult (line 12) | interface SemanticSearchResult {

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResultMetadata.ts
  type SemanticSearchResultMetadata (line 9) | type SemanticSearchResultMetadata = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResultOcrResult.ts
  type SemanticSearchResultOcrResult (line 9) | type SemanticSearchResultOcrResult = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResultOcrResultAnyOf.ts
  type SemanticSearchResultOcrResultAnyOf (line 9) | type SemanticSearchResultOcrResultAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResultScreenshot.ts
  type SemanticSearchResultScreenshot (line 9) | type SemanticSearchResultScreenshot = { [key: string]: unknown } | null;

FILE: free-todo-frontend/lib/generated/schemas/semanticSearchResultScreenshotAnyOf.ts
  type SemanticSearchResultScreenshotAnyOf (line 9) | type SemanticSearchResultScreenshotAnyOf = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/statisticsResponse.ts
  type StatisticsResponse (line 9) | interface StatisticsResponse {

FILE: free-todo-frontend/lib/generated/schemas/syncVectorDatabaseApiVectorSyncPostParams.ts
  type SyncVectorDatabaseApiVectorSyncPostParams (line 9) | type SyncVectorDatabaseApiVectorSyncPostParams = {

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponse.ts
  type SystemResourcesResponse (line 15) | interface SystemResourcesResponse {

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponseCpu.ts
  type SystemResourcesResponseCpu (line 9) | type SystemResourcesResponseCpu = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponseDisk.ts
  type SystemResourcesResponseDisk (line 9) | type SystemResourcesResponseDisk = {[key: string]: {[key: string]: numbe...

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponseMemory.ts
  type SystemResourcesResponseMemory (line 9) | type SystemResourcesResponseMemory = {[key: string]: number};

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponseStorage.ts
  type SystemResourcesResponseStorage (line 9) | type SystemResourcesResponseStorage = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/systemResourcesResponseSummary.ts
  type SystemResourcesResponseSummary (line 9) | type SystemResourcesResponseSummary = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/taskBatchDeleteRequest.ts
  type TaskBatchDeleteRequest (line 12) | interface TaskBatchDeleteRequest {

FILE: free-todo-frontend/lib/generated/schemas/taskBatchDeleteResponse.ts
  type TaskBatchDeleteResponse (line 12) | interface TaskBatchDeleteResponse {

FILE: free-todo-frontend/lib/generated/schemas/taskCreate.ts
  type TaskCreate (line 14) | interface TaskCreate {

FILE: free-todo-frontend/lib/generated/schemas/taskCreateDescription.ts
  type TaskCreateDescription (line 12) | type TaskCreateDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/taskListResponse.ts
  type TaskListResponse (line 13) | interface TaskListResponse {

FILE: free-todo-frontend/lib/generated/schemas/taskProgressListResponse.ts
  type TaskProgressListResponse (line 13) | interface TaskProgressListResponse {

FILE: free-todo-frontend/lib/generated/schemas/taskProgressResponse.ts
  type TaskProgressResponse (line 12) | interface TaskProgressResponse {

FILE: free-todo-frontend/lib/generated/schemas/taskResponse.ts
  type TaskResponse (line 13) | interface TaskResponse {

FILE: free-todo-frontend/lib/generated/schemas/taskResponseDescription.ts
  type TaskResponseDescription (line 12) | type TaskResponseDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/taskStatus.ts
  type TaskStatus (line 12) | type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];

FILE: free-todo-frontend/lib/generated/schemas/taskUpdate.ts
  type TaskUpdate (line 16) | interface TaskUpdate {

FILE: free-todo-frontend/lib/generated/schemas/taskUpdateDescription.ts
  type TaskUpdateDescription (line 12) | type TaskUpdateDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/taskUpdateName.ts
  type TaskUpdateName (line 12) | type TaskUpdateName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/taskUpdateStatus.ts
  type TaskUpdateStatus (line 13) | type TaskUpdateStatus = TaskStatus | null;

FILE: free-todo-frontend/lib/generated/schemas/testAsrConfigApiTestAsrConfigPostBody.ts
  type TestAsrConfigApiTestAsrConfigPostBody (line 9) | type TestAsrConfigApiTestAsrConfigPostBody = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/testLlmConfigApiTestLlmConfigPostBody.ts
  type TestLlmConfigApiTestLlmConfigPostBody (line 9) | type TestLlmConfigApiTestLlmConfigPostBody = {[key: string]: string};

FILE: free-todo-frontend/lib/generated/schemas/testTavilyConfigApiTestTavilyConfigPostBody.ts
  type TestTavilyConfigApiTestTavilyConfigPostBody (line 9) | type TestTavilyConfigApiTestTavilyConfigPostBody = {[key: string]: string};

FILE: free-todo-frontend/lib/generated/schemas/timeAllocationResponse.ts
  type TimeAllocationResponse (line 14) | interface TimeAllocationResponse {

FILE: free-todo-frontend/lib/generated/schemas/timeAllocationResponseAppDetailsItem.ts
  type TimeAllocationResponseAppDetailsItem (line 9) | type TimeAllocationResponseAppDetailsItem = { [key: string]: unknown };

FILE: free-todo-frontend/lib/generated/schemas/timeAllocationResponseDailyDistributionItem.ts
  type TimeAllocationResponseDailyDistributionItem (line 9) | type TimeAllocationResponseDailyDistributionItem = { [key: string]: unkn...

FILE: free-todo-frontend/lib/generated/schemas/todoAttachmentResponse.ts
  type TodoAttachmentResponse (line 12) | interface TodoAttachmentResponse {

FILE: free-todo-frontend/lib/generated/schemas/todoAttachmentResponseFileSize.ts
  type TodoAttachmentResponseFileSize (line 12) | type TodoAttachmentResponseFileSize = number | null;

FILE: free-todo-frontend/lib/generated/schemas/todoAttachmentResponseMimeType.ts
  type TodoAttachmentResponseMimeType (line 12) | type TodoAttachmentResponseMimeType = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreate.ts
  type TodoCreate (line 15) | interface TodoCreate {

FILE: free-todo-frontend/lib/generated/schemas/todoCreateCompletedAt.ts
  type TodoCreateCompletedAt (line 12) | type TodoCreateCompletedAt = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateDeadline.ts
  type TodoCreateDeadline (line 12) | type TodoCreateDeadline = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateDescription.ts
  type TodoCreateDescription (line 12) | type TodoCreateDescription = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateEndTime.ts
  type TodoCreateEndTime (line 12) | type TodoCreateEndTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateParentTodoId.ts
  type TodoCreateParentTodoId (line 12) | type TodoCreateParentTodoId = number | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreatePercentComplete.ts
  type TodoCreatePercentComplete (line 12) | type TodoCreatePercentComplete = number | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateRrule.ts
  type TodoCreateRrule (line 12) | type TodoCreateRrule = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateStartTime.ts
  type TodoCreateStartTime (line 12) | type TodoCreateStartTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateUid.ts
  type TodoCreateUid (line 12) | type TodoCreateUid = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoCreateUserNotes.ts
  type TodoCreateUserNotes (line 12) | type TodoCreateUserNotes = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionRequest.ts
  type TodoExtractionRequest (line 12) | interface TodoExtractionRequest {

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionRequestScreenshotSampleRatio.ts
  type TodoExtractionRequestScreenshotSampleRatio (line 12) | type TodoExtractionRequestScreenshotSampleRatio = number | null;

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionResponse.ts
  type TodoExtractionResponse (line 13) | interface TodoExtractionResponse {

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionResponseAppName.ts
  type TodoExtractionResponseAppName (line 12) | type TodoExtractionResponseAppName = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionResponseErrorMessage.ts
  type TodoExtractionResponseErrorMessage (line 12) | type TodoExtractionResponseErrorMessage = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionResponseEventEndTime.ts
  type TodoExtractionResponseEventEndTime (line 12) | type TodoExtractionResponseEventEndTime = string | null;

FILE: free-todo-frontend/lib/generated/schemas/todoExtractionResponseEventStartTime.ts
  type TodoExtractionResponseEventStartTime (line 12) | type TodoExtra
Condensed preview — 1003 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,702K chars).
[
  {
    "path": ".cursor/commands/agno_agent.md",
    "chars": 8025,
    "preview": "# Agno Agent Development Quick Commands\n\n## Overview\n\nThis guide covers development of **Agno Agent Tools** - the AI-pow"
  },
  {
    "path": ".cursor/commands/agno_agent_CN.md",
    "chars": 6247,
    "preview": "# Agno Agent 开发快捷命令\n\n## 概述\n\n本指南涵盖 **Agno Agent Tools** 的开发 - 基于 [Agno 框架](https://docs.agno.com/) 的 AI 待办管理工具包。\n\nFreeTod"
  },
  {
    "path": ".cursor/commands/backend.md",
    "chars": 11031,
    "preview": "# Backend Development Quick Commands (lifetrace version)\n\n## Tech Stack Information\n\n- **Framework**: FastAPI + Uvicorn "
  },
  {
    "path": ".cursor/commands/backend_CN.md",
    "chars": 6337,
    "preview": "# 后端开发快捷命令(lifetrace 版)\n\n## 技术栈信息\n\n- **框架**: FastAPI + Uvicorn(异步 Web 框架)\n- **语言**: Python 3.12\n- **ORM**: SQLAlchemy 2."
  },
  {
    "path": ".cursor/commands/dynamic-island.md",
    "chars": 16483,
    "preview": "# 灵动岛实现指南(Dynamic Island)\n\n## 概述\n\n灵动岛是一个悬浮 UI 组件,为 Electron 应用提供三种交互模式:\n- **FLOAT 模式**:小型悬浮岛,可拖拽,悬停时展开\n- **PANEL 模式**:可调"
  },
  {
    "path": ".cursor/commands/web.md",
    "chars": 9546,
    "preview": "# Frontend Development Quick Commands (free-todo-frontend version)\n\n## Tech Stack Information\n\n- **Framework**: Next.js "
  },
  {
    "path": ".cursor/commands/web_CN.md",
    "chars": 5170,
    "preview": "# 前端开发快捷命令(free-todo-frontend 版)\n\n## 技术栈信息\n\n- **框架**: Next.js 16 + React 19(App Router)\n- **语言**: Node.js 22.x + TypeScr"
  },
  {
    "path": ".cursor/plans/lifetrace_全面优化_76b5f86f.plan.md",
    "chars": 10518,
    "preview": "---\nname: LifeTrace 全面优化\noverview: 针对 LifeTrace 项目的 6 个核心问题(启动速度、打包体积、插件系统、Todo 标准、社交媒体集成、依赖清理)制定系统性的优化方案。\ntodos:\n  - id"
  },
  {
    "path": ".cursor/plans/tauri_迁移方案_38d8ea4b.plan.md",
    "chars": 9423,
    "preview": "---\nname: Tauri 迁移方案\noverview: 使用 Tauri 替代 Electron,采用 HTTP Sidecar 模式与 Python 后端集成。保持现有 API 和前端代码不变,最小化迁移成本。\ntodos:\n  -"
  },
  {
    "path": ".cursor/plans/后台持续录音方案_c7c8f0fe.plan.md",
    "chars": 3875,
    "preview": "---\nname: 后台持续录音方案\noverview: 分析\"后端驱动录音\"方案的改造范围,并提供一个基于 Electron 主进程的更优替代方案,使录音不受面板切换影响。\ntodos:\n  - id: analyze-electron-"
  },
  {
    "path": ".cursor/plans/打包与性能优化_ecd1657a.plan.md",
    "chars": 843,
    "preview": "---\nname: 打包与性能优化\noverview: 针对启动速度、依赖效率和打包体积三个核心问题,评估 Tauri + Nuitka 方案,并提供依赖精简和模块剔除的具体实施方案。\ntodos:\n  - id: remove-unuse"
  },
  {
    "path": ".gitattributes",
    "chars": 66,
    "preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": ".githooks/post-checkout",
    "chars": 1010,
    "preview": "#!/usr/bin/env sh\nset -u\n\nrepo_root=\"$(git rev-parse --show-toplevel 2>/dev/null || true)\"\nif [ -z \"$repo_root\" ]; then\n"
  },
  {
    "path": ".githooks/pre-commit",
    "chars": 294,
    "preview": "#!/usr/bin/env sh\nset -u\n\nif command -v pre-commit >/dev/null 2>&1; then\n  exec pre-commit run --hook-stage pre-commit \""
  },
  {
    "path": ".github/BACKEND_GUIDELINES.md",
    "chars": 23713,
    "preview": "# Backend Development Guidelines\n\n**Language**: [English](BACKEND_GUIDELINES.md) | [中文](BACKEND_GUIDELINES_CN.md)\n\n## 🐍 "
  },
  {
    "path": ".github/BACKEND_GUIDELINES_CN.md",
    "chars": 17899,
    "preview": "# 后端开发规范\n\n**语言**: [English](BACKEND_GUIDELINES.md) | [中文](BACKEND_GUIDELINES_CN.md)\n\n## 🐍 Python 后端开发规范\n\n本文档详细说明了 LifeTr"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "chars": 15431,
    "preview": "# Contributing Guide\n\n**Language**: [English](CONTRIBUTING.md) | [中文](CONTRIBUTING_CN.md)\n\n> ⚠️ **Important**: Before st"
  },
  {
    "path": ".github/CONTRIBUTING_CN.md",
    "chars": 8981,
    "preview": "# 贡献指南\n\n**语言**: [English](CONTRIBUTING.md) | [中文](CONTRIBUTING_CN.md)\n\n> ⚠️ **重要提示**:在开始贡献之前,请务必阅读并配置 [**Pre-commit 使用指南"
  },
  {
    "path": ".github/FRONTEND_GUIDELINES.md",
    "chars": 21147,
    "preview": "# Frontend Development Guidelines\n\n**Language**: [English](FRONTEND_GUIDELINES.md) | [中文](FRONTEND_GUIDELINES_CN.md)\n\n##"
  },
  {
    "path": ".github/FRONTEND_GUIDELINES_CN.md",
    "chars": 17449,
    "preview": "# 前端开发规范\n\n**语言**: [English](FRONTEND_GUIDELINES.md) | [中文](FRONTEND_GUIDELINES_CN.md)\n\n## ⚛️ React + TypeScript 前端开发规范\n\n"
  },
  {
    "path": ".github/GIT_FLOW.md",
    "chars": 22232,
    "preview": "# Git Flow Workflow\n\n**Language**: [English](GIT_FLOW.md) | [中文](GIT_FLOW_CN.md)\n\n## 📋 Table of Contents\n\n- [Overview](#"
  },
  {
    "path": ".github/GIT_FLOW_CN.md",
    "chars": 14520,
    "preview": "# Git Flow 工作流程\n\n**语言**: [English](GIT_FLOW.md) | [中文](GIT_FLOW_CN.md)\n\n## 📋 目录\n\n- [概述](#-概述)\n- [分支策略](#-分支策略)\n- [工作流程]("
  },
  {
    "path": ".github/INSTALL.md",
    "chars": 2980,
    "preview": "# One-Click Install (Full Options)\n\nThis document contains the full one-click install options referenced in the main REA"
  },
  {
    "path": ".github/INSTALL_CN.md",
    "chars": 2607,
    "preview": "# 一键安装(完整选项)\n\n本文件包含主 README 中提到的一键安装完整说明。\n\n## 环境要求\n- Python 3.12+\n- Node.js 20+\n- Git\n- Rust(仅 Tauri 构建需要)\n\n## 基础用法\n\nmac"
  },
  {
    "path": ".github/PRE_COMMIT_GUIDE.md",
    "chars": 13321,
    "preview": "# Pre-commit Usage Guide\n\n## Overview\n\nThis project uses [pre-commit](https://pre-commit.com/) to automatically run code"
  },
  {
    "path": ".github/PRE_COMMIT_GUIDE_CN.md",
    "chars": 9331,
    "preview": "# Pre-commit 使用指南\n\n## 概述\n\n本项目使用 [pre-commit](https://pre-commit.com/) 工具在 Git 提交前自动运行代码检查和格式化,确保代码质量和风格一致性。\n\nPre-commit "
  },
  {
    "path": ".github/ROADMAP.md",
    "chars": 9906,
    "preview": "# FreeU Project Roadmap\n\n## Project Vision\n\n**FreeU Group** (\"为您分忧\" - Sharing Your Worries) aims to build personal conte"
  },
  {
    "path": ".github/ROADMAP_CN.md",
    "chars": 3974,
    "preview": "# FreeU 项目路线图\n\n## 项目愿景\n\n**FreeU Group**(为您分忧)的愿景是通过构建个人的上下文数据库进行数据挖掘和处理,主动地为用户提供主动式服务。\n\n通过记录个人数据库(**LifeLog**,记录个人生活日志),"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 675,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"weekly\"\n  "
  },
  {
    "path": ".github/workflows/_disabled/dev-build-verify.yml",
    "chars": 5339,
    "preview": "name: Dev Build Verify\n\non:\n  push:\n    branches: [dev]\n  pull_request:\n    branches: [dev]\n  workflow_dispatch:\n\nconcur"
  },
  {
    "path": ".github/workflows/_disabled/tauri-release.yml",
    "chars": 2530,
    "preview": "name: Tauri Release\n\non:\n  push:\n    tags:\n      - \"v*\"\n\njobs:\n  check-main:\n    runs-on: ubuntu-latest\n    outputs:\n   "
  },
  {
    "path": ".github/workflows/dependency-review.yml",
    "chars": 1614,
    "preview": "name: Dependency Review\n\non:\n  pull_request:\n  workflow_dispatch:\n    inputs:\n      base-ref:\n        description: \"Base"
  },
  {
    "path": ".github/workflows/pre-commit.yml",
    "chars": 7349,
    "preview": "name: Pre-commit\n\non:\n  pull_request:\n  push:\n    branches: [main, master]\n  workflow_dispatch:\n\njobs:\n  changes:\n    ru"
  },
  {
    "path": ".gitignore",
    "chars": 815,
    "preview": "# Python\n__pycache__/\n*.py[cod]\n*$py.class\n*.so\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\n# lib/\nlib64/"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 4478,
    "preview": "repos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v6.0.0\n    hooks:\n      - id: check-yaml\n      "
  },
  {
    "path": ".python-version",
    "chars": 5,
    "preview": "3.12\n"
  },
  {
    "path": "AGENTS.md",
    "chars": 4678,
    "preview": "# Repository Guidelines\n\n## Project Structure & Module Organization\n- `lifetrace/`: FastAPI backend (routers, services, "
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5182,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to participate in"
  },
  {
    "path": "LICENSE",
    "chars": 1112,
    "preview": "FreeU Community License\n\nCopyright (c) 2026/01/10 - FreeU Group. All rights reserved.\n\n----------\n\nFrom 1.0, Free Todo i"
  },
  {
    "path": "README.md",
    "chars": 16311,
    "preview": "![FreeTodo Logo](.github/assets/free_todo_banner.png)\n\n![GitHub stars](https://img.shields.io/github/stars/FreeU-group/F"
  },
  {
    "path": "README_CN.md",
    "chars": 9721,
    "preview": "![FreeTodo Logo](.github/assets/free_todo_banner.png)\n\n![GitHub stars](https://img.shields.io/github/stars/FreeU-group/F"
  },
  {
    "path": "bandit.yaml",
    "chars": 178,
    "preview": "exclude_dirs:\n  - .venv\n  - data\n  - dist\n  - build\n  - migrations/versions\n  - lifetrace/data\n  - lifetrace/migrations/"
  },
  {
    "path": "biome.json",
    "chars": 347,
    "preview": "{\n\t\"$schema\": \"https://biomejs.dev/schemas/2.3.13/schema.json\",\n\t\"files\": {\n\t\t\"includes\": [\"**\", \"!free-todo-frontend/li"
  },
  {
    "path": "free-todo-frontend/.gitignore",
    "chars": 658,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pn"
  },
  {
    "path": "free-todo-frontend/app/globals.css",
    "chars": 14131,
    "preview": "@import url(\"https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap\");\n@import \"ta"
  },
  {
    "path": "free-todo-frontend/app/home/HomePageClient.tsx",
    "chars": 7198,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useCallback, useEffect, useRef, useState } from \"re"
  },
  {
    "path": "free-todo-frontend/app/home/HomePageEntry.tsx",
    "chars": 303,
    "preview": "\"use client\";\n\nimport dynamic from \"next/dynamic\";\nimport { FrontendBoot } from \"@/components/common/ui/FrontendBoot\";\n\n"
  },
  {
    "path": "free-todo-frontend/app/island/island.css",
    "chars": 1011,
    "preview": "/* Island 页面专用样式 */\n/* 注意: globals.css 已在 layout.tsx 中导入,提供 CSS 变量和主题支持 */\n\n/* 形态1/2: 确保透明背景(用于悬浮窗口) */\n/* 仅在 island-con"
  },
  {
    "path": "free-todo-frontend/app/island/layout.tsx",
    "chars": 1103,
    "preview": "import type { Metadata } from \"next\";\nimport { NextIntlClientProvider } from \"next-intl\";\nimport { getLocale, getMessage"
  },
  {
    "path": "free-todo-frontend/app/island/page.tsx",
    "chars": 3142,
    "preview": "\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport DynamicIsland from \"@/components/island/"
  },
  {
    "path": "free-todo-frontend/app/layout.tsx",
    "chars": 1552,
    "preview": "import type { Metadata } from \"next\";\nimport { NextIntlClientProvider } from \"next-intl\";\nimport { getLocale, getMessage"
  },
  {
    "path": "free-todo-frontend/app/page.tsx",
    "chars": 121,
    "preview": "import { HomePageEntry } from \"./home/HomePageEntry\";\n\nexport default function HomePage() {\n\treturn <HomePageEntry />;\n}"
  },
  {
    "path": "free-todo-frontend/apps/achievements/AchievementsPanel.tsx",
    "chars": 4964,
    "preview": "\"use client\";\n\nimport { Award, Star, Target, Trophy } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\n"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivityCard.tsx",
    "chars": 2227,
    "preview": "import { Clock3 } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { Activity } from \"@/lib/types\";\n"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivityDetail.tsx",
    "chars": 5189,
    "preview": "import { AppWindow, Clock3, ListChecks } from \"lucide-react\";\nimport ReactMarkdown from \"react-markdown\";\nimport remarkG"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivityHeader.tsx",
    "chars": 2415,
    "preview": "\"use client\";\n\nimport { Activity, Search } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { us"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivityPanel.tsx",
    "chars": 2604,
    "preview": "\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { ActivityDetail } from \"@/apps/activity/ActivityDetai"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivitySidebar.tsx",
    "chars": 2238,
    "preview": "import { ActivityCard } from \"@/apps/activity/ActivityCard\";\nimport type { ActivityGroup } from \"@/apps/activity/utils/t"
  },
  {
    "path": "free-todo-frontend/apps/activity/ActivitySummary.tsx",
    "chars": 2816,
    "preview": "import ReactMarkdown, { type Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\n\ninterface Activity"
  },
  {
    "path": "free-todo-frontend/apps/activity/utils/timeUtils.ts",
    "chars": 2944,
    "preview": "import type { Activity } from \"@/lib/types\";\n\nconst ONE_MINUTE = 60 * 1000;\nconst ONE_HOUR = 60 * ONE_MINUTE;\nconst ONE_"
  },
  {
    "path": "free-todo-frontend/apps/audio/AudioPanel.tsx",
    "chars": 15471,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useCallback, useMemo, useRef, useState } from \"reac"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/AudioExtractionPanel.tsx",
    "chars": 10748,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useMemo, useState } from \"react\";\nimport { MessageT"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/AudioHeader.tsx",
    "chars": 5265,
    "preview": "\"use client\";\n\nimport { motion } from \"framer-motion\";\nimport { Calendar, ChevronLeft, ChevronRight, Mic, MicOff, Radio,"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/AudioList.tsx",
    "chars": 1521,
    "preview": "\"use client\";\n\nimport { Play } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface AudioRecording {\n\tid: n"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/AudioPlayer.tsx",
    "chars": 3268,
    "preview": "\"use client\";\n\nimport { Pause, Play } from \"lucide-react\";\n\ninterface AudioPlayerProps {\n\ttitle: string;\n\tdate: string;\n"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/RecordingStatus.tsx",
    "chars": 3516,
    "preview": "\"use client\";\n\nimport { motion } from \"framer-motion\";\nimport { Mic, Radio } from \"lucide-react\";\nimport { useEffect, us"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/StopRecordingConfirm.tsx",
    "chars": 1213,
    "preview": "\"use client\";\n\ninterface StopRecordingConfirmProps {\n\tisOpen: boolean;\n\tonCancel: () => void;\n\tonConfirm: () => void;\n}\n"
  },
  {
    "path": "free-todo-frontend/apps/audio/components/TranscriptionView.tsx",
    "chars": 15188,
    "preview": "\n\"use client\";\n\nimport { useEffect, useLayoutEffect, useMemo, useRef } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioData.ts",
    "chars": 14013,
    "preview": "\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n\tcalculateSegmentOffset,\n\tform"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioDateSwitching.ts",
    "chars": 6111,
    "preview": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport { getLocalDateStringForCompare } from \"../utils/timeUti"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioLink.ts",
    "chars": 3277,
    "preview": "\"use client\";\n\nimport { useCallback } from \"react\";\nimport { getTranscriptionApiAudioTranscriptionRecordingIdGet } from "
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioPlayback.ts",
    "chars": 2362,
    "preview": "\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nexport function useAudioPlayback() {\n\tconst audio"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioRecording.ts",
    "chars": 1274,
    "preview": "\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useAudioRecordingStore } from \"@/lib/store/audio-recording-"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useAudioRecordingControl.ts",
    "chars": 12521,
    "preview": "\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport { toastInfo } from \"@/lib/toast\";\nimport {"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useSegmentSync.ts",
    "chars": 2298,
    "preview": "\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\n\ninterface UseSegmentSyncOptions {\n\tisRecording: bo"
  },
  {
    "path": "free-todo-frontend/apps/audio/hooks/useStopRecordingConfirm.ts",
    "chars": 3506,
    "preview": "\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { useAudioRecordingStore } from \"@/lib/store/audio-"
  },
  {
    "path": "free-todo-frontend/apps/audio/utils/parseTimeToIsoWithDate.ts",
    "chars": 1725,
    "preview": "\"use client\";\n\n/**\n * 将中文/自然语言时间解析为带日期的 ISO 字符串;解析失败返回 undefined。\n */\nexport function parseTimeToIsoWithDate(raw: string"
  },
  {
    "path": "free-todo-frontend/apps/audio/utils/timeUtils.ts",
    "chars": 4929,
    "preview": "\"use client\";\n\n/**\n * 统一的时间处理工具\n * 处理时区、跨日期、时间戳转换等问题\n */\n\n/**\n * 获取本地时区的 Date 对象(不进行时区转换)\n * @param dateStr ISO 8601 字符串"
  },
  {
    "path": "free-todo-frontend/apps/calendar/CalendarPanel.tsx",
    "chars": 12286,
    "preview": "\"use client\";\n\n/**\n * 日历面板组件\n * 使用全局 DndContext,支持从其他面板拖拽 Todo 到日期\n */\n\nimport { Calendar, ChevronLeft, ChevronRight, Ro"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/DayColumn.tsx",
    "chars": 3508,
    "preview": "/**\n * 日历日期列 - 作为放置目标\n * 使用 useDroppable 并传递类型化的 DropData\n */\n\nimport { useDroppable } from \"@dnd-kit/core\";\nimport type"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/DraggableTodo.tsx",
    "chars": 2929,
    "preview": "/**\n * 日历内的可拖拽 Todo 卡片\n * 使用 useDraggable 并传递类型化的 DragData\n */\n\nimport { useDraggable } from \"@dnd-kit/core\";\nimport { u"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/FloatingTodoCard.tsx",
    "chars": 1585,
    "preview": "/**\n * Floating (unscheduled) todo card.\n */\n\nimport { useDraggable } from \"@dnd-kit/core\";\nimport { useMemo } from \"rea"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/QuickCreateBar.tsx",
    "chars": 3359,
    "preview": "/**\n * 快捷创建 Todo 栏组件\n */\n\nimport { Calendar, Plus, X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/QuickCreatePopover.tsx",
    "chars": 5597,
    "preview": "\"use client\";\n\n/**\n * 日历内就地创建 Popover\n */\n\nimport { Calendar, Plus, X } from \"lucide-react\";\nimport { useTranslations } "
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/TimelineColumn.tsx",
    "chars": 7421,
    "preview": "/**\n * Timeline column with slots + items.\n */\n\nimport type React from \"react\";\nimport { useMemo, useRef, useState } fro"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/TimelineCreatePopover.tsx",
    "chars": 6572,
    "preview": "\"use client\";\n\n/**\n * Timeline quick create popover.\n */\n\nimport { Calendar, Plus, X } from \"lucide-react\";\nimport { use"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/TimelineSlot.tsx",
    "chars": 938,
    "preview": "/**\n * Timeline droppable slot (15 min).\n */\n\nimport { useDroppable } from \"@dnd-kit/core\";\nimport { useMemo } from \"rea"
  },
  {
    "path": "free-todo-frontend/apps/calendar/components/TimelineTodoCard.tsx",
    "chars": 4357,
    "preview": "/**\n * Draggable timeline todo card.\n */\n\nimport { useDraggable } from \"@dnd-kit/core\";\nimport type React from \"react\";\n"
  },
  {
    "path": "free-todo-frontend/apps/calendar/hooks/useMonthScroll.ts",
    "chars": 5596,
    "preview": "import { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { CalendarView } from \"../types\";\nimport {"
  },
  {
    "path": "free-todo-frontend/apps/calendar/types.ts",
    "chars": 1199,
    "preview": "/**\n * 日历相关类型定义\n */\n\nimport type { Todo, TodoStatus } from \"@/lib/types\";\n\nexport type CalendarView = \"month\" | \"week\" |"
  },
  {
    "path": "free-todo-frontend/apps/calendar/utils.ts",
    "chars": 5511,
    "preview": "/**\n * 日历工具函数\n */\n\nexport const DEFAULT_NEW_TIME = \"09:00\";\nexport const DEFAULT_WORK_START_MINUTES = 8 * 60;\nexport con"
  },
  {
    "path": "free-todo-frontend/apps/calendar/views/DayView.tsx",
    "chars": 14970,
    "preview": "/**\n * Day timeline view.\n */\n\nimport { useTranslations } from \"next-intl\";\nimport type React from \"react\";\nimport { use"
  },
  {
    "path": "free-todo-frontend/apps/calendar/views/MonthScroller.tsx",
    "chars": 6093,
    "preview": "/**\n * 月视图滚动容器(无限滚动)\n */\n\nimport type React from \"react\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport typ"
  },
  {
    "path": "free-todo-frontend/apps/calendar/views/MonthView.tsx",
    "chars": 1110,
    "preview": "/**\n * 月视图组件\n */\n\nimport type React from \"react\";\nimport type { Todo } from \"@/lib/types\";\nimport { DayColumn } from \".."
  },
  {
    "path": "free-todo-frontend/apps/calendar/views/WeekView.tsx",
    "chars": 11953,
    "preview": "/**\n * Week timeline view.\n */\n\nimport { useTranslations } from \"next-intl\";\nimport { useMemo, useState } from \"react\";\n"
  },
  {
    "path": "free-todo-frontend/apps/calendar/views/useWeekViewActions.ts",
    "chars": 7325,
    "preview": "/**\n * Shared handlers/state for WeekView timeline interactions.\n */\n\nimport { useState } from \"react\";\nimport type { Cr"
  },
  {
    "path": "free-todo-frontend/apps/chat/ChatPanel.tsx",
    "chars": 5912,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useCallback, useEffect, useMemo, useState } from \"r"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/breakdown/BreakdownStageRenderer.tsx",
    "chars": 3107,
    "preview": "\"use client\";\n\nimport { Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { BreakdownSu"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/breakdown/BreakdownSummary.tsx",
    "chars": 3071,
    "preview": "\"use client\";\n\nimport { Check, Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport ReactM"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/breakdown/Questionnaire.tsx",
    "chars": 12311,
    "preview": "\"use client\";\n\nimport { Check, Edit2, Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/input/ChatInputSection.tsx",
    "chars": 2194,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useRef } from \"react\";\nimport { InputBox } from \"@/"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/input/InputBox.tsx",
    "chars": 6266,
    "preview": "import { AtSign, Send, Square } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport type React from"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/input/LinkedTodos.tsx",
    "chars": 1961,
    "preview": "import { useTranslations } from \"next-intl\";\nimport type { Todo } from \"@/lib/types\";\n\ntype LinkedTodosProps = {\n\teffect"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/input/PromptSuggestions.tsx",
    "chars": 1910,
    "preview": "\"use client\";\n\nimport { Hammer, Sparkles, TrendingUp } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/input/ToolSelector.tsx",
    "chars": 11204,
    "preview": "\"use client\";\n\nimport { Check, Globe, Terminal, Wrench } from \"lucide-react\";\nimport { useTranslations } from \"next-intl"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/layout/HeaderBar.tsx",
    "chars": 904,
    "preview": "\"use client\";\n\nimport { History, MessageSquare, PlusCircle } from \"lucide-react\";\nimport { useTranslations } from \"next-"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/layout/HistoryDrawer.tsx",
    "chars": 2768,
    "preview": "import { Loader2 } from \"lucide-react\";\nimport type { ChatSessionSummary } from \"@/lib/api\";\nimport { cn } from \"@/lib/u"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/layout/WelcomeGreetings.tsx",
    "chars": 1412,
    "preview": "\"use client\";\n\nimport Image from \"next/image\";\nimport { useTranslations } from \"next-intl\";\nimport { cn } from \"@/lib/ut"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/EditModeMessage.tsx",
    "chars": 10943,
    "preview": "\"use client\";\n\nimport { Check, ChevronDown, Loader2, Plus } from \"lucide-react\";\nimport { useTranslations } from \"next-i"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MarkdownComponents.tsx",
    "chars": 3621,
    "preview": "import type { Components } from \"react-markdown\";\nimport { cn } from \"@/lib/utils\";\n\ntype MessageRole = \"user\" | \"assist"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageContent.tsx",
    "chars": 1488,
    "preview": "import ReactMarkdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport type { ChatMessage } from \"@/apps"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageContextMenu.tsx",
    "chars": 1689,
    "preview": "import { ListTodo, Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport type { ExtractionS"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageItem.tsx",
    "chars": 6002,
    "preview": "import { Loader2, MoreVertical } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useState } f"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageList.tsx",
    "chars": 4065,
    "preview": "import { useMemo, useRef, useState } from \"react\";\nimport { WelcomeGreetings } from \"@/apps/chat/components/layout/Welco"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageSources.tsx",
    "chars": 1352,
    "preview": "import { ExternalLink } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport type { WebSearchSources"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageTodoExtractionModal.tsx",
    "chars": 8446,
    "preview": "\"use client\";\n\nimport { Check, X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useEffect,"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/MessageTodoExtractionPanel.tsx",
    "chars": 4810,
    "preview": "\"use client\";\n\nimport { Check, Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useS"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/SummaryStreaming.tsx",
    "chars": 2410,
    "preview": "\"use client\";\n\nimport { Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useMemo } f"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/ToolCallLoading.tsx",
    "chars": 736,
    "preview": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype ToolCallLoadingProps = {\n\ttoolName: string;\n\tsearchQuery?: string"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/ToolCallSteps.tsx",
    "chars": 4147,
    "preview": "\"use client\";\n\nimport { AlertCircle, CheckCircle2, Loader2, Wrench } from \"lucide-react\";\nimport { useTranslations } fro"
  },
  {
    "path": "free-todo-frontend/apps/chat/components/message/utils/messageContentUtils.ts",
    "chars": 3368,
    "preview": "// 工具调用标记检测\n// 支持格式:[使用工具: tool_name] 或 [使用工具: tool_name | 关键词: query] 或 [使用工具: tool_name | param: value]\nconst TOOL_CAL"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useBreakdownQuestionnaire.ts",
    "chars": 4050,
    "preview": "import { useTranslations } from \"next-intl\";\nimport { useCallback, useEffect, useMemo } from \"react\";\nimport { useBreakd"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useBreakdownService.ts",
    "chars": 10253,
    "preview": "import { useCallback } from \"react\";\nimport type { ParsedTodoTree } from \"@/apps/chat/types\";\nimport { planQuestionnaire"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useChatController.ts",
    "chars": 5021,
    "preview": "import { useQueryClient } from \"@tanstack/react-query\";\nimport { useTranslations } from \"next-intl\";\nimport type { Keybo"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useChatPrompts.ts",
    "chars": 1312,
    "preview": "import { useEffect, useState } from \"react\";\nimport { unwrapApiData } from \"@/lib/api/fetcher\";\nimport { getChatPromptsA"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useMessageExtraction.ts",
    "chars": 5307,
    "preview": "import { useTranslations } from \"next-intl\";\nimport { useCallback, useRef, useState } from \"react\";\nimport type { ChatMe"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useMessageScroll.ts",
    "chars": 2010,
    "preview": "import { useCallback, useEffect, useRef } from \"react\";\nimport type { ChatMessage } from \"@/apps/chat/types\";\n\n/**\n * 管理"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/usePlanParser.ts",
    "chars": 5772,
    "preview": "import { useCallback, useEffect, useState } from \"react\";\nimport type { ParsedTodoTree } from \"@/apps/chat/types\";\nimpor"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useSendMessage.ts",
    "chars": 8561,
    "preview": "import type { QueryClient } from \"@tanstack/react-query\";\nimport type { useTranslations } from \"next-intl\";\nimport { use"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useSessionCache.ts",
    "chars": 2090,
    "preview": "import { useCallback, useRef } from \"react\";\nimport type { ChatMessage } from \"@/apps/chat/types\";\n\n/**\n * 会话缓存 Hook 返回值"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useSessionManager.ts",
    "chars": 6357,
    "preview": "import { useCallback, useEffect, useRef } from \"react\";\nimport type { SessionCacheReturn } from \"@/apps/chat/hooks/useSe"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useStreamController.ts",
    "chars": 2177,
    "preview": "import { useCallback, useRef } from \"react\";\nimport { createId } from \"@/apps/chat/utils/id\";\n\n/**\n * 创建请求的返回值\n */\nexpor"
  },
  {
    "path": "free-todo-frontend/apps/chat/hooks/useToolCallTracker.ts",
    "chars": 3311,
    "preview": "import { useCallback, useRef } from \"react\";\nimport type { ToolCallStep } from \"@/apps/chat/types\";\nimport type { ToolCa"
  },
  {
    "path": "free-todo-frontend/apps/chat/types.ts",
    "chars": 1041,
    "preview": "import type { CreateTodoInput } from \"@/lib/types\";\n\n/**\n * 工具调用步骤状态\n */\nexport type ToolCallStatus = \"running\" | \"compl"
  },
  {
    "path": "free-todo-frontend/apps/chat/utils/id.ts",
    "chars": 195,
    "preview": "export const createId = () => {\n\tif (typeof crypto !== \"undefined\" && crypto.randomUUID) {\n\t\treturn crypto.randomUUID();"
  },
  {
    "path": "free-todo-frontend/apps/chat/utils/messageBuilder.ts",
    "chars": 736,
    "preview": "/**\n * 消息构建参数\n */\nexport interface BuildPayloadMessageParams {\n\ttrimmedText: string;\n\tuserLabel: string;\n\ttodoContext: s"
  },
  {
    "path": "free-todo-frontend/apps/chat/utils/parseEditBlocks.ts",
    "chars": 3785,
    "preview": "import type { EditContentBlock } from \"@/apps/chat/types\";\n\n/**\n * Parse AI response in Edit mode into structured conten"
  },
  {
    "path": "free-todo-frontend/apps/chat/utils/responseHandlers.ts",
    "chars": 1292,
    "preview": "import type { useTranslations } from \"next-intl\";\nimport type { ChatMessage } from \"@/apps/chat/types\";\n\n/**\n * 处理流式请求错误"
  },
  {
    "path": "free-todo-frontend/apps/chat/utils/todoContext.ts",
    "chars": 5683,
    "preview": "import type { Todo, TodoPriority, TodoStatus } from \"@/lib/types\";\n\ntype TranslationFunction = (\n\tkey: string,\n\tvalues?:"
  },
  {
    "path": "free-todo-frontend/apps/cost-tracking/CostTrackingPanel.tsx",
    "chars": 13196,
    "preview": "\"use client\";\n\nimport {\n\tActivity,\n\tAlertCircle,\n\tCalendar,\n\tDollarSign,\n\tRefreshCw,\n\tTrendingUp,\n} from \"lucide-react\";"
  },
  {
    "path": "free-todo-frontend/apps/cost-tracking/index.ts",
    "chars": 57,
    "preview": "export { CostTrackingPanel } from \"./CostTrackingPanel\";\n"
  },
  {
    "path": "free-todo-frontend/apps/debug/DebugCapturePanel.tsx",
    "chars": 8968,
    "preview": "\"use client\";\n\nimport { Camera, ChevronDown, ChevronUp } from \"lucide-react\";\nimport { useTranslations } from \"next-intl"
  },
  {
    "path": "free-todo-frontend/apps/debug/components/EventCard.tsx",
    "chars": 7864,
    "preview": "\"use client\";\n\nimport { Check, ClipboardList, Square } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";"
  },
  {
    "path": "free-todo-frontend/apps/debug/components/EventSearchForm.tsx",
    "chars": 2745,
    "preview": "\"use client\";\n\nimport { Search } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\n\ninterface EventSearc"
  },
  {
    "path": "free-todo-frontend/apps/debug/components/ScreenshotModal.tsx",
    "chars": 9776,
    "preview": "\"use client\";\n\nimport { ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";"
  },
  {
    "path": "free-todo-frontend/apps/debug/components/SelectedEventsBar.tsx",
    "chars": 1890,
    "preview": "\"use client\";\n\nimport { Activity, Check } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\n\ninterface S"
  },
  {
    "path": "free-todo-frontend/apps/debug/components/index.ts",
    "chars": 235,
    "preview": "/**\n * Debug Capture 组件导出\n */\n\nexport { EventCard } from \"./EventCard\";\nexport { EventSearchForm } from \"./EventSearchFo"
  },
  {
    "path": "free-todo-frontend/apps/debug/hooks/index.ts",
    "chars": 135,
    "preview": "/**\n * Debug Capture Hooks 导出\n */\n\nexport { useEventActions } from \"./useEventActions\";\nexport { useEventData } from \"./"
  },
  {
    "path": "free-todo-frontend/apps/debug/hooks/useEventActions.ts",
    "chars": 5003,
    "preview": "\"use client\";\n\nimport { useState } from \"react\";\nimport { unwrapApiData } from \"@/lib/api/fetcher\";\nimport { useCreateAc"
  },
  {
    "path": "free-todo-frontend/apps/debug/hooks/useEventData.ts",
    "chars": 7766,
    "preview": "\"use client\";\n\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n\tgetEventDetailApiEventsEvent"
  },
  {
    "path": "free-todo-frontend/apps/debug/utils.ts",
    "chars": 751,
    "preview": "/**\n * Debug Capture 调试面板工具函数\n */\n\n/**\n * 格式化日期为 YYYY-MM-DD(使用本地时区)\n */\nexport function formatDate(date: Date): string {"
  },
  {
    "path": "free-todo-frontend/apps/diary/DiaryEditor.tsx",
    "chars": 4469,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { DiaryTabs, type JournalTab } from \"@/apps/diary/Dia"
  },
  {
    "path": "free-todo-frontend/apps/diary/DiaryHeader.tsx",
    "chars": 2451,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useId } from \"react\";\nimport type { JournalDraft } "
  },
  {
    "path": "free-todo-frontend/apps/diary/DiaryPanel.tsx",
    "chars": 13759,
    "preview": "\"use client\";\n\nimport { BookOpen, CalendarDays } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimpor"
  },
  {
    "path": "free-todo-frontend/apps/diary/DiarySettings.tsx",
    "chars": 5013,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useId } from \"react\";\nimport type { JournalRefreshM"
  },
  {
    "path": "free-todo-frontend/apps/diary/DiaryTabs.tsx",
    "chars": 1033,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { cn } from \"@/lib/utils\";\n\nexport type JournalTab = "
  },
  {
    "path": "free-todo-frontend/apps/diary/JournalHistory.tsx",
    "chars": 1815,
    "preview": "\"use client\";\n\nimport type { JournalView } from \"@/lib/query\";\nimport { cn } from \"@/lib/utils\";\n\ninterface JournalHisto"
  },
  {
    "path": "free-todo-frontend/apps/diary/index.ts",
    "chars": 54,
    "preview": "export { DiaryPanel } from \"@/apps/diary/DiaryPanel\";\n"
  },
  {
    "path": "free-todo-frontend/apps/diary/journal-utils.ts",
    "chars": 1859,
    "preview": "import type { JournalRefreshMode } from \"@/lib/store/journal-store\";\n\nconst pad = (value: number) => value.toString().pa"
  },
  {
    "path": "free-todo-frontend/apps/diary/types.ts",
    "chars": 263,
    "preview": "export interface JournalDraft {\n\tid: number | null;\n\tname: string;\n\tuserNotes: string;\n\tcontentObjective: string;\n\tconte"
  },
  {
    "path": "free-todo-frontend/apps/settings/SettingsPanel.tsx",
    "chars": 7953,
    "preview": "\"use client\";\n\nimport { LayoutGrid, LifeBuoy, Settings, Sparkles, Wrench, Zap } from \"lucide-react\";\nimport { useTransla"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/AudioAsrConfigSection.tsx",
    "chars": 11782,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useState } from \"react\";\n// 注意:需要运行 orva"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/AudioConfigSection.tsx",
    "chars": 2034,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useState } from \"react\";\nimport { useSav"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/AutoTodoDetectionSection.tsx",
    "chars": 7380,
    "preview": "\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useRef"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/AutomationTasksSection.tsx",
    "chars": 13715,
    "preview": "\"use client\";\n\nimport {\n\tCheck,\n\tClock,\n\tPlay,\n\tPlus,\n\tPower,\n\tTrash2,\n} from \"lucide-react\";\nimport { useTranslations }"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/DifyConfigSection.tsx",
    "chars": 4340,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useState } from \"react\";\nimport { useSav"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/DockDisplayModeSection.tsx",
    "chars": 1746,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport type { DockDisplayMode } from \"@/lib/store/ui-store\";"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/JournalSettingsSection.tsx",
    "chars": 5228,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useId } from \"react\";\nimport { useJournalStore } fr"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/LlmConfigSection.tsx",
    "chars": 11652,
    "preview": "\"use client\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { useTranslations } from \"next-intl\";\nimpo"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/NotificationPermissionSection.tsx",
    "chars": 6776,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/OnboardingSection.tsx",
    "chars": 1220,
    "preview": "\"use client\";\n\nimport { RotateCcw } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useOnboar"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/PanelSwitchesSection.tsx",
    "chars": 5015,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useState } from \"react\";\nimport { CollapsibleSectio"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/RecorderConfigSection.tsx",
    "chars": 5966,
    "preview": "\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useSta"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/SchedulerSection.tsx",
    "chars": 15069,
    "preview": "\"use client\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { Check, Clock, Edit2, Pause, Play, Refres"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/SettingsCategoryPanel.tsx",
    "chars": 2789,
    "preview": "\"use client\";\n\nimport type { LucideIcon } from \"lucide-react\";\nimport { type ReactNode, useCallback, useEffect, useState"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/SettingsSearchAction.tsx",
    "chars": 2277,
    "preview": "\"use client\";\n\nimport { Search } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, u"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/SettingsSection.tsx",
    "chars": 2525,
    "preview": "\"use client\";\n\nimport {\n\tcreateContext,\n\ttype ReactNode,\n\tuseContext,\n\tuseEffect,\n\tuseId,\n} from \"react\";\n\nconst Setting"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/TavilyConfigSection.tsx",
    "chars": 6001,
    "preview": "\"use client\";\n\nimport { Check, Loader2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useE"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/ToggleSwitch.tsx",
    "chars": 922,
    "preview": "\"use client\";\n\ninterface ToggleSwitchProps {\n\tid?: string;\n\tenabled: boolean;\n\tdisabled?: boolean;\n\tonToggle: (enabled: "
  },
  {
    "path": "free-todo-frontend/apps/settings/components/VersionInfoSection.tsx",
    "chars": 669,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\n\n/**\n * 版本信息组件\n * 显示当前应用版本号、构建类型和 Git Commit\n */\nexport func"
  },
  {
    "path": "free-todo-frontend/apps/settings/components/index.ts",
    "chars": 1286,
    "preview": "export { AudioAsrConfigSection } from \"./AudioAsrConfigSection\";\nexport { AudioConfigSection } from \"./AudioConfigSectio"
  },
  {
    "path": "free-todo-frontend/apps/settings/hooks/useSettingsSearchMatchStats.ts",
    "chars": 1219,
    "preview": "\"use client\";\n\nimport { useCallback, useMemo, useState } from \"react\";\nimport type { SettingsCategoryId } from \"../compo"
  },
  {
    "path": "free-todo-frontend/apps/settings/index.ts",
    "chars": 82,
    "preview": "export { default as SettingsPanelDefault, SettingsPanel } from \"./SettingsPanel\";\n"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/TodoDetail.tsx",
    "chars": 11517,
    "preview": "\"use client\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { useTranslations } from \"next-intl\";\nimpo"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/ArtifactsView.tsx",
    "chars": 8237,
    "preview": "\"use client\";\n\nimport {\n\tFileUp,\n\tFolderOpen,\n\tGripVertical,\n\tImageIcon,\n\tNotebookText,\n\tPaperclip,\n\tTrash2,\n} from \"luc"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/AttachmentPreviewPanel.tsx",
    "chars": 2629,
    "preview": "\"use client\";\n\nimport { Download, X } from \"lucide-react\";\nimport Image from \"next/image\";\nimport { useTranslations } fr"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/BackgroundSection.tsx",
    "chars": 5064,
    "preview": "\"use client\";\n\nimport { Check, X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useCallbac"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/ChildTodoSection.tsx",
    "chars": 8526,
    "preview": "\"use client\";\n\nimport { Calendar, Plus, Tag as TagIcon, X } from \"lucide-react\";\nimport { useTranslations } from \"next-i"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/DatePickerCalendar.tsx",
    "chars": 5473,
    "preview": "\"use client\";\n\nimport { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport type { useTranslations } from \"next-intl"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/DatePickerPopover.tsx",
    "chars": 12104,
    "preview": "\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport {\n\ttype RefObject,\n"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/DatePickerSidePanel.tsx",
    "chars": 7644,
    "preview": "\"use client\";\n\nimport { Bell, Calendar, Clock, Globe, Repeat } from \"lucide-react\";\nimport type { useTranslations } from"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/DetailHeader.tsx",
    "chars": 1935,
    "preview": "\"use client\";\n\nimport { CheckCircle2, FileText, Trash2 } from \"lucide-react\";\nimport { useTranslations } from \"next-intl"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/DetailTitle.tsx",
    "chars": 2236,
    "preview": "\"use client\";\n\nimport { useTranslations } from \"next-intl\";\nimport { useEffect, useRef, useState } from \"react\";\n\ninterf"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/MetaSection.tsx",
    "chars": 9385,
    "preview": "\"use client\";\n\nimport { Calendar, Flag, Tag as TagIcon } from \"lucide-react\";\nimport { useTranslations } from \"next-intl"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/NotesEditor.tsx",
    "chars": 2542,
    "preview": "\"use client\";\n\nimport type { Editor } from \"@tiptap/core\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimpo"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/components/datePickerUtils.ts",
    "chars": 2139,
    "preview": "import dayjs from \"dayjs\";\nimport timezone from \"dayjs/plugin/timezone\";\nimport utc from \"dayjs/plugin/utc\";\n\ndayjs.exte"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/helpers.ts",
    "chars": 3933,
    "preview": "import dayjs from \"dayjs\";\nimport timezone from \"dayjs/plugin/timezone\";\nimport utc from \"dayjs/plugin/utc\";\nimport type"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/hooks/useNotesAutosize.ts",
    "chars": 1092,
    "preview": "import { useCallback, useEffect, useRef } from \"react\";\n\nexport function useNotesAutosize(deps: unknown[]) {\n\tconst note"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/index.ts",
    "chars": 43,
    "preview": "export { TodoDetail } from \"./TodoDetail\";\n"
  },
  {
    "path": "free-todo-frontend/apps/todo-detail/utils/date-utils.ts",
    "chars": 2106,
    "preview": "/**\n * 日期选择器工具函数\n * 提供日期计算和格式化功能\n */\n\nimport { getHolidayInfo, type HolidayInfo } from \"./holiday-utils\";\nimport { getLu"
  }
]

// ... and 803 more files (download for full content)

About this extraction

This page contains the full source code of the FreeU-group/LifeTrace GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1003 files (14.1 MB), approximately 1.0M tokens, and a symbol index with 3969 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!