Implement Cline-style checkpoint functionality using detached git directory:
- Shadow checkpoint repository with metadata file for labels
- Create checkpoint: git write-tree + metadata storage
- List checkpoints: read from metadata JSON
- Restore checkpoint: direct file writes to avoid watcher deletion events
- UI in GitLog panel with checkpoint list and restore buttons
- E2E test coverage for checkpoint scenario
Fixes window recreation issue by using recreateUnlessWorkspaceID
Excludes $:/StoryList from restore to preserve UI state
Implements Cline-style checkpoint functionality:
- Desktop: shadow checkpoint repo via dugite, service APIs, GitLog UI actions
- Mobile: matching checkpoint primitives in isomorphic-git GitService
- Shared: IGitCheckpointInfo data model across both platforms
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
- Moved default model selection to a dedicated 'AIModels' (默认模型) section.
- Renamed 'External API' to 'Service Providers' (服务提供商).
- Converted Node Management custom items into generic schema items (action, action-input).
- Eliminated NodeManagementItem custom component, instead rendering dynamic data through Native message box alerts.
- Fixed UI overflow of 'Get API Key'/Login button in ProviderPanel using FlexShrink and precise margin alignments.
- Removed the hardcoded exclusion of \item.type === 'custom'\ from \PreferenceSearchResultsView.tsx\. Now any valid custom item is automatically indexed and searchable.
- Added multiple custom items to \iAgent.ts\ schema (\NodeIdentity\, \KnownNodes\, \ConnectPeer\, \SyncStatus\, \RemoteWikis\) pointing to \iAgent.nodeManagement\ componentId so they show in search.
- Cleaned up \NodeManagementItem.tsx\ to use standard \Box\ layouts instead of separated \Paper\ cards, making it seamlessly integrate with the surrounding \AIAgent\ section.
- Moved the browser login/Get API key button in \ProviderPanel.tsx\ inline beside the API Key text field (using a flex box) to make it more obvious. Added conditional \mt\ to balance heights.
Root cause: getAIProviders() returns stored providers from DB which never
include loginUrl/apiKeyUrl (these fields exist only in defaultProviders.ts
source code, not persisted). ProviderPanel checks provider.loginUrl and
provider.apiKeyUrl to show the 'Login in Browser'/'Get API Key' buttons,
so the buttons were never visible.
Fix: merge loginUrl/apiKeyUrl from defaultProviders back into stored
providers inside getAIProviders() -- only fills in if not already set,
so user overrides are respected.
Also: add check:i18n to CI (test.yml) and package.json scripts, update
check-i18n-dups.mjs to exit 1 on duplicates so CI fails properly.
JSON duplicate key fixes (found by scripts/check-i18n-dups.mjs):
- en/agent.json: remove duplicate ToolApprovalSettings/Description,
ToolPermissions/Description (second occurrence at line 301-304)
- zh-Hans/agent.json: same 4 duplicates + duplicate WikiEmbed block at EOF
NodeManagement rendering fix:
- aiAgent section has CustomSectionComponent (AIAgent.tsx) which takes
priority over schema items, so the 'custom' schema item NodeManagement
was never actually rendered -- schema-based search indexing still works
- Fix: import NodeManagementItem into AIAgent.tsx and render it directly
after the delete-database dialog, with Divider + SectionTitle header
Add scripts/check-i18n-dups.mjs: precise same-level duplicate key detector
using a JSON string parser (handles escape sequences and nested objects
correctly, unlike naive regex approach)
- Delete ProviderSettings.tsx: it rendered a redundant custom-provider table
(with its own add/edit/delete) that duplicated the functionality already
provided by ProviderConfig with its Tab UI. The table was the source of
the confusing '暂无自定义提供商' empty-state message.
- Remove ProviderSettings import and usage from ExternalAPI/index.tsx
- Remove dead/duplicate keys from Preference block in en+zh-Hans agent.json:
ManageSubscription, MemeloopAPIKey, MemeloopAPIKeyHelp, MemeloopSubscription,
NoCustomProviders, CustomProviders, SaveSubscriptionMode, SelfHostedMode,
SelfHostedModeDescription, SubscriptionActiveUntil, SubscriptionInfo,
SubscriptionMode, SubscriptionModeDescription, Status (ProviderSettings-only),
duplicate Save and Saving keys
- ProviderNameCannotBeChanged and ProviderNameHelp kept (used in ProviderFormDialog)
- Replace all hardcoded English strings in AIAgent.tsx with t() calls:
Tool Approval, Tool Permissions, scheduled task dialog labels,
table column headers, schedule description strings
- Add 30+ translation keys to en/agent.json and zh-Hans/agent.json covering
all scheduled task UI strings
- Extract NodeManagementSection + sub-panels (Identity, KnownNodes, SyncStatus,
AddPeer, RemoteWikiList) from AIAgent.tsx into
customItems/NodeManagementItem.tsx with ICustomItemProps interface
- Register 'aiAgent.nodeManagement' custom item in registerCustomSections.tsx
- Add 'custom' schema item to aiAgent.ts with titleKey/descriptionKey so
search index can find '节点管理 / Node Management' and its description
- Add loginUrl field to AIProviderConfig interface
- Add loginUrl and apiKeyUrl to memeloop (browser login) and siliconflow
(referral https://cloud.siliconflow.cn/i/AwRxPUi7) in defaultProviders
- Add 'Login in Browser' / 'Get API Key' button in ProviderPanel using
window.service.native.openURI for external browser open
- Add WikiSync.NodeManagementDescription translation key (en + zh-Hans)