@lobehub/lobehub 2.0.0-next.291 → 2.0.0-next.293

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/.conductor/setup.sh +107 -0
  2. package/.cursor/rules/linear.mdc +53 -0
  3. package/.github/actions/desktop-build-setup/action.yml +29 -0
  4. package/.github/actions/desktop-upload-artifacts/action.yml +46 -0
  5. package/.github/workflows/release-desktop-beta.yml +76 -115
  6. package/.github/workflows/release-desktop-stable.yml +472 -0
  7. package/CHANGELOG.md +58 -0
  8. package/CLAUDE.md +2 -48
  9. package/apps/desktop/dev-app-update.yml +10 -0
  10. package/apps/desktop/electron-builder.mjs +40 -10
  11. package/apps/desktop/electron.vite.config.ts +3 -2
  12. package/apps/desktop/package.json +2 -1
  13. package/apps/desktop/scripts/update-test/README.md +222 -0
  14. package/apps/desktop/scripts/update-test/dev-app-update.local.yml +18 -0
  15. package/apps/desktop/scripts/update-test/generate-manifest.sh +277 -0
  16. package/apps/desktop/scripts/update-test/run-test.sh +105 -0
  17. package/apps/desktop/scripts/update-test/setup.sh +111 -0
  18. package/apps/desktop/scripts/update-test/start-server.sh +70 -0
  19. package/apps/desktop/scripts/update-test/stop-server.sh +33 -0
  20. package/apps/desktop/src/main/core/infrastructure/UpdaterManager.ts +120 -9
  21. package/apps/desktop/src/main/core/infrastructure/__tests__/UpdaterManager.test.ts +17 -1
  22. package/apps/desktop/src/main/env.ts +19 -11
  23. package/apps/desktop/src/main/modules/updater/configs.ts +14 -1
  24. package/changelog/v1.json +14 -0
  25. package/conductor.json +5 -0
  26. package/locales/en-US/subscription.json +2 -2
  27. package/locales/zh-CN/subscription.json +2 -2
  28. package/package.json +1 -1
  29. package/packages/builtin-tool-notebook/src/client/Render/CreateDocument/DocumentCard.tsx +16 -14
  30. package/packages/const/src/cacheControl.ts +1 -0
  31. package/packages/electron-client-ipc/src/useWatchBroadcast.ts +10 -4
  32. package/packages/model-bank/src/aiModels/qiniu.ts +6 -6
  33. package/packages/observability-otel/src/node.ts +39 -37
  34. package/scripts/electronWorkflow/mergeMacReleaseFiles.js +22 -8
  35. package/src/app/(backend)/api/desktop/latest/route.ts +115 -0
  36. package/src/app/(backend)/api/version/route.ts +13 -0
  37. package/src/app/(backend)/middleware/validate/createValidator.test.ts +61 -0
  38. package/src/app/(backend)/middleware/validate/createValidator.ts +79 -0
  39. package/src/app/(backend)/middleware/validate/index.ts +3 -0
  40. package/src/app/[variants]/(desktop)/desktop-onboarding/_layout/index.tsx +2 -1
  41. package/src/app/[variants]/(main)/_layout/index.tsx +2 -1
  42. package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobScheduleConfig.tsx +0 -1
  43. package/src/app/[variants]/(main)/agent/cron/[cronId]/index.tsx +5 -5
  44. package/src/app/[variants]/(main)/agent/features/Conversation/ThreadHydration.tsx +3 -1
  45. package/src/app/[variants]/(main)/group/features/Conversation/ThreadHydration.tsx +3 -1
  46. package/src/app/[variants]/(main)/settings/provider/features/ProviderConfig/Checker.tsx +3 -3
  47. package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +1 -4
  48. package/src/app/[variants]/router/desktopRouter.config.tsx +1 -4
  49. package/src/components/HtmlPreview/PreviewDrawer.tsx +1 -1
  50. package/src/features/Conversation/Messages/AssistantGroup/components/GroupItem.tsx +12 -2
  51. package/src/features/Conversation/Messages/Tool/Tool/index.tsx +10 -1
  52. package/src/features/{ElectronTitlebar/hooks → Electron/navigation}/useNavigationHistory.ts +1 -1
  53. package/src/features/{ElectronTitlebar/NavigationBar/index.tsx → Electron/titlebar/NavigationBar.tsx} +1 -1
  54. package/src/features/{ElectronTitlebar/NavigationBar → Electron/titlebar}/RecentlyViewed.tsx +1 -1
  55. package/src/features/{ElectronTitlebar/index.tsx → Electron/titlebar/TitleBar.tsx} +19 -9
  56. package/src/features/Electron/titlebar/WinControl.tsx +5 -0
  57. package/src/features/Electron/updater/UpdateModal.tsx +299 -0
  58. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.test.tsx +24 -0
  59. package/src/features/LibraryModal/AddFilesToKnowledgeBase/index.tsx +21 -24
  60. package/src/features/LibraryModal/CreateNew/index.tsx +18 -22
  61. package/src/features/PluginDevModal/index.tsx +1 -1
  62. package/src/layout/GlobalProvider/AppTheme.tsx +1 -1
  63. package/src/libs/swr/index.ts +26 -30
  64. package/src/server/services/desktopRelease/index.test.ts +65 -0
  65. package/src/server/services/desktopRelease/index.ts +208 -0
  66. package/src/store/aiInfra/slices/aiProvider/action.ts +16 -17
  67. package/src/store/chat/slices/portal/action.test.ts +0 -2
  68. package/src/store/chat/slices/portal/action.ts +17 -44
  69. package/src/store/chat/slices/thread/action.test.ts +4 -1
  70. package/src/store/chat/slices/thread/action.ts +6 -1
  71. package/src/components/FunctionModal/createModalHooks.ts +0 -48
  72. package/src/components/FunctionModal/index.ts +0 -1
  73. package/src/components/FunctionModal/style.tsx +0 -44
  74. package/src/features/ElectronTitlebar/UpdateModal.tsx +0 -274
  75. package/src/features/ElectronTitlebar/WinControl/index.tsx +0 -90
  76. /package/src/features/{ElectronTitlebar/Connection/index.tsx → Electron/connection/Connection.tsx} +0 -0
  77. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/ConnectionMode.tsx +0 -0
  78. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Option.tsx +0 -0
  79. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/RemoteStatus.tsx +0 -0
  80. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/Waiting.tsx +0 -0
  81. /package/src/features/{ElectronTitlebar/Connection → Electron/connection}/WaitingAnim.tsx +0 -0
  82. /package/src/features/{ElectronTitlebar/helpers → Electron/navigation}/routeMetadata.ts +0 -0
  83. /package/src/features/{ElectronTitlebar/hooks → Electron/system}/useWatchThemeUpdate.ts +0 -0
  84. /package/src/features/{ElectronTitlebar → Electron/titlebar}/SimpleTitleBar.tsx +0 -0
  85. /package/src/features/{ElectronTitlebar → Electron/updater}/UpdateNotification.tsx +0 -0
@@ -1,44 +0,0 @@
1
- import { Icon } from '@lobehub/ui';
2
- import { createStaticStyles , responsive } from 'antd-style';
3
- import { XIcon } from 'lucide-react';
4
-
5
- const prefixCls = 'ant';
6
-
7
- export const styles = createStaticStyles(({ css, cssVar }) => {
8
- return {
9
- content: css`
10
- .${prefixCls}-modal-container {
11
- overflow: hidden;
12
-
13
- width: min(90vw, 450px);
14
- padding: 0;
15
- border: 1px solid ${cssVar.colorSplit};
16
- border-radius: ${cssVar.borderRadiusLG};
17
-
18
- background: ${cssVar.colorBgLayout};
19
-
20
- ${responsive.sm} {
21
- width: unset;
22
- }
23
- }
24
- .${prefixCls}-modal-confirm-title {
25
- display: block;
26
- padding-block: 16px 0;
27
- padding-inline: 16px;
28
- }
29
- .${prefixCls}-modal-confirm-btns {
30
- margin-block-start: 0;
31
- padding: 16px;
32
- }
33
-
34
- .${prefixCls}-modal-confirm-paragraph {
35
- max-width: 100%;
36
- }
37
- `,
38
- wrap: css`
39
- overflow: hidden auto;
40
- `,
41
- };
42
- });
43
-
44
- export const closeIcon = <Icon icon={XIcon} size={20} />;
@@ -1,274 +0,0 @@
1
- import {
2
- type ProgressInfo,
3
- type UpdateInfo,
4
- useWatchBroadcast,
5
- } from '@lobechat/electron-client-ipc';
6
- import { Button } from '@lobehub/ui';
7
- import { App, Modal, Progress, Spin } from 'antd';
8
- import React, { memo, useRef, useState } from 'react';
9
- import { useTranslation } from 'react-i18next';
10
-
11
- import { autoUpdateService } from '@/services/electron/autoUpdate';
12
- import { formatSpeed } from '@/utils/format';
13
-
14
- export const UpdateModal = memo(() => {
15
- const { t } = useTranslation(['electron', 'common']);
16
-
17
- const [isChecking, setIsChecking] = useState(false);
18
- const [isDownloading, setIsDownloading] = useState(false);
19
- // 仅用于手动触发的更新流程(用户从设置页点“检查更新”)
20
- const manualFlowRef = useRef(false);
21
- const [updateAvailableInfo, setUpdateAvailableInfo] = useState<UpdateInfo | null>(null);
22
- const [downloadedInfo, setDownloadedInfo] = useState<UpdateInfo | null>(null);
23
- const [progress, setProgress] = useState<ProgressInfo | null>(null);
24
- const [latestVersionInfo, setLatestVersionInfo] = useState<UpdateInfo | null>(null); // State for latest version modal
25
- const { modal } = App.useApp();
26
- // --- Event Listeners ---
27
-
28
- useWatchBroadcast('manualUpdateCheckStart', () => {
29
- console.log('[Manual Update] Check Start');
30
- manualFlowRef.current = true;
31
-
32
- setIsChecking(true);
33
- setUpdateAvailableInfo(null);
34
- setDownloadedInfo(null);
35
- setProgress(null);
36
- setLatestVersionInfo(null); // Reset latest version info
37
- // Optional: Show a brief notification that check has started
38
- // notification.info({ message: t('updater.checking') });
39
- });
40
-
41
- useWatchBroadcast('manualUpdateAvailable', (info: UpdateInfo) => {
42
- console.log('[Manual Update] Available:', info);
43
- // Only react if it's part of a manual check flow (i.e., isChecking was true)
44
- // No need to check isChecking here as this event is specific
45
- setIsChecking(false);
46
- setUpdateAvailableInfo(info);
47
- });
48
-
49
- useWatchBroadcast('manualUpdateNotAvailable', (info) => {
50
- console.log('[Manual Update] Not Available:', info);
51
- // Only react if it's part of a manual check flow
52
- // No need to check isChecking here as this event is specific
53
- setIsChecking(false);
54
- manualFlowRef.current = false;
55
-
56
- setLatestVersionInfo(info); // Set info for the modal
57
- // notification.success({
58
- // description: t('updater.isLatestVersionDesc', { version: info.version }),
59
- // message: t('updater.isLatestVersion'),
60
- // });
61
- });
62
-
63
- useWatchBroadcast('updateError', (message: string) => {
64
- console.log('[Manual Update] Error:', message);
65
- // Only react if it's part of a manual check/download flow
66
- if (isChecking || isDownloading) {
67
- setIsChecking(false);
68
- setIsDownloading(false);
69
- // Show error modal or notification
70
- modal.error({ content: message, title: t('updater.updateError') });
71
- setLatestVersionInfo(null); // Ensure other modals are closed on error
72
- setUpdateAvailableInfo(null);
73
- setDownloadedInfo(null);
74
- manualFlowRef.current = false;
75
- }
76
- });
77
-
78
- useWatchBroadcast('updateDownloadStart', () => {
79
- console.log('[Manual Update] Download Start');
80
- // This event implies a manual download was triggered (likely from the 'updateAvailable' modal)
81
- manualFlowRef.current = true;
82
-
83
- setIsDownloading(true);
84
- setUpdateAvailableInfo(null); // Hide the 'download' button modal
85
- setProgress({ bytesPerSecond: 0, percent: 0, total: 0, transferred: 0 }); // Reset progress
86
- setLatestVersionInfo(null); // Ensure other modals are closed
87
- // Optional: Show notification that download started
88
- // notification.info({ message: t('updater.downloadingUpdate') });
89
- });
90
-
91
- useWatchBroadcast('updateDownloadProgress', (progressInfo: ProgressInfo) => {
92
- console.log('[Manual Update] Progress:', progressInfo);
93
- // Only update progress if we are in the manual download state
94
- setProgress(progressInfo);
95
- });
96
-
97
- useWatchBroadcast('updateDownloaded', (info: UpdateInfo) => {
98
- console.log('[Manual Update] Downloaded:', info);
99
- // 仅在手动流程里展示阻塞式的“更新就绪”弹窗
100
- if (manualFlowRef.current) {
101
- setIsChecking(false);
102
- setIsDownloading(false);
103
- setDownloadedInfo(info);
104
- setProgress(null); // Clear progress
105
- setLatestVersionInfo(null); // Ensure other modals are closed
106
- setUpdateAvailableInfo(null);
107
- }
108
- });
109
-
110
- // --- Render Logic ---
111
-
112
- const handleDownload = () => {
113
- if (!updateAvailableInfo) return;
114
- // No need to set states here, 'updateDownloadStart' will handle it
115
- autoUpdateService.downloadUpdate();
116
- };
117
-
118
- const handleInstallNow = () => {
119
- setDownloadedInfo(null); // Close modal immediately
120
- autoUpdateService.installNow();
121
- manualFlowRef.current = false;
122
- };
123
-
124
- const handleInstallLater = () => {
125
- // No need to set state here, 'updateWillInstallLater' handles it
126
- autoUpdateService.installLater();
127
- setDownloadedInfo(null); // Close the modal after clicking
128
- manualFlowRef.current = false;
129
- };
130
-
131
- const closeAvailableModal = () => setUpdateAvailableInfo(null);
132
- const closeDownloadedModal = () => setDownloadedInfo(null);
133
- const closeLatestVersionModal = () => setLatestVersionInfo(null);
134
-
135
- const handleCancelCheck = () => {
136
- setIsChecking(false);
137
- setUpdateAvailableInfo(null);
138
- setDownloadedInfo(null);
139
- setProgress(null);
140
- setLatestVersionInfo(null);
141
- manualFlowRef.current = false;
142
- };
143
-
144
- const renderCheckingModal = () => (
145
- <Modal
146
- closable
147
- footer={[
148
- <Button key="cancel" onClick={handleCancelCheck}>
149
- {t('cancel', { ns: 'common' })}
150
- </Button>,
151
- ]}
152
- onCancel={handleCancelCheck}
153
- open={isChecking}
154
- title={t('updater.checkingUpdate')}
155
- >
156
- <Spin spinning={true}>
157
- <div style={{ padding: '20px', textAlign: 'center' }}>
158
- {t('updater.checkingUpdateDesc')}
159
- </div>
160
- </Spin>
161
- </Modal>
162
- );
163
-
164
- const renderAvailableModal = () => (
165
- <Modal
166
- footer={[
167
- <Button key="cancel" onClick={closeAvailableModal}>
168
- {t('cancel', { ns: 'common' })}
169
- </Button>,
170
- <Button key="download" onClick={handleDownload} type="primary">
171
- {t('updater.downloadNewVersion')}
172
- </Button>,
173
- ]}
174
- onCancel={closeAvailableModal}
175
- open={!!updateAvailableInfo}
176
- title={t('updater.newVersionAvailable')}
177
- >
178
- <h4>{t('updater.newVersionAvailableDesc', { version: updateAvailableInfo?.version })}</h4>
179
- {updateAvailableInfo?.releaseNotes && (
180
- <div
181
- dangerouslySetInnerHTML={{ __html: updateAvailableInfo.releaseNotes as string }}
182
- style={{
183
- // background:theme
184
- borderRadius: 4,
185
- marginTop: 8,
186
- maxHeight: 300,
187
- overflow: 'auto',
188
- padding: '8px 12px',
189
- }}
190
- />
191
- )}
192
- </Modal>
193
- );
194
-
195
- const renderDownloadingModal = () => {
196
- const percent = progress ? Math.round(progress.percent) : 0;
197
- return (
198
- <Modal
199
- closable={false}
200
- footer={null}
201
- maskClosable={false}
202
- open={isDownloading && !downloadedInfo}
203
- title={t('updater.downloadingUpdate')}
204
- >
205
- <div style={{ padding: '20px 0' }}>
206
- <Progress percent={percent} status="active" />
207
- <div style={{ fontSize: 12, marginTop: 8, textAlign: 'center' }}>
208
- {t('updater.downloadingUpdateDesc', { percent })}
209
- {progress && progress.bytesPerSecond > 0 && (
210
- <span>{formatSpeed(progress.bytesPerSecond)}</span>
211
- )}
212
- </div>
213
- </div>
214
- </Modal>
215
- );
216
- };
217
-
218
- const renderDownloadedModal = () => (
219
- <Modal
220
- footer={[
221
- <Button key="later" onClick={handleInstallLater}>
222
- {t('updater.installLater')}
223
- </Button>,
224
- <Button key="now" onClick={handleInstallNow} type="primary">
225
- {t('updater.restartAndInstall')}
226
- </Button>,
227
- ]}
228
- onCancel={closeDownloadedModal} // Allow closing if they don't want to decide now
229
- open={!!downloadedInfo}
230
- title={t('updater.updateReady')}
231
- >
232
- <h4>{t('updater.updateReadyDesc', { version: downloadedInfo?.version })}</h4>
233
- {downloadedInfo?.releaseNotes && (
234
- <div
235
- dangerouslySetInnerHTML={{ __html: downloadedInfo.releaseNotes as string }}
236
- style={{
237
- borderRadius: 4,
238
- marginTop: 8,
239
- maxHeight: 300,
240
- overflow: 'auto',
241
- padding: '8px 12px',
242
- }}
243
- />
244
- )}
245
- </Modal>
246
- );
247
-
248
- // New modal for "latest version"
249
- const renderLatestVersionModal = () => (
250
- <Modal
251
- footer={[
252
- <Button key="ok" onClick={closeLatestVersionModal} type="primary">
253
- {t('ok', { ns: 'common' })}
254
- </Button>,
255
- ]}
256
- onCancel={closeLatestVersionModal}
257
- open={!!latestVersionInfo}
258
- title={t('updater.isLatestVersion')}
259
- >
260
- <p>{t('updater.isLatestVersionDesc', { version: latestVersionInfo?.version })}</p>
261
- </Modal>
262
- );
263
-
264
- return (
265
- <>
266
- {renderCheckingModal()}
267
- {renderAvailableModal()}
268
- {renderDownloadingModal()}
269
- {renderDownloadedModal()}
270
- {renderLatestVersionModal()}
271
- {/* Error state is handled by Modal.error currently */}
272
- </>
273
- );
274
- });
@@ -1,90 +0,0 @@
1
- // const useStyles = createStyles(({ css, cx, token }) => {
2
- // const icon = css`
3
- // display: flex;
4
- // align-items: center;
5
- // justify-content: center;
6
- //
7
- // width: ${TITLE_BAR_HEIGHT * 1.2}px;
8
- // min-height: ${TITLE_BAR_HEIGHT}px;
9
- //
10
- // color: ${token.colorTextSecondary};
11
- //
12
- // transition: all ease-in-out 100ms;
13
- //
14
- // -webkit-app-region: no-drag;
15
- //
16
- // &:hover {
17
- // color: ${token.colorText};
18
- // background: ${token.colorFillTertiary};
19
- // }
20
- //
21
- // &:active {
22
- // color: ${token.colorText};
23
- // background: ${token.colorFillSecondary};
24
- // }
25
- // `;
26
- // return {
27
- // close: cx(
28
- // icon,
29
- // css`
30
- // padding-inline-end: 2px;
31
- //
32
- // &:hover {
33
- // color: ${token.colorTextLightSolid};
34
- //
35
- // /* win11 的色值,亮暗色均不变 */
36
- // background: #d33328;
37
- // }
38
- //
39
- // &:active {
40
- // color: ${token.colorTextLightSolid};
41
- //
42
- // /* win11 的色值 */
43
- // background: #8b2b25;
44
- // }
45
- // `,
46
- // ),
47
- // container: css`
48
- // cursor: pointer;
49
- // display: flex;
50
- // `,
51
- // icon,
52
- // };
53
- // });
54
-
55
- const WinControl = () => {
56
- return <div style={{ width: 132 }} />;
57
-
58
- // const { styles } = useStyles();
59
- //
60
- // return (
61
- // <div className={styles.container}>
62
- // <div
63
- // className={styles.icon}
64
- // onClick={() => {
65
- // electronSystemService.minimizeWindow();
66
- // }}
67
- // >
68
- // <Minus absoluteStrokeWidth size={14} strokeWidth={1.2} />
69
- // </div>
70
- // <div
71
- // className={styles.icon}
72
- // onClick={() => {
73
- // electronSystemService.maximizeWindow();
74
- // }}
75
- // >
76
- // <Square absoluteStrokeWidth size={10} strokeWidth={1.2} />
77
- // </div>
78
- // <div
79
- // className={styles.close}
80
- // onClick={() => {
81
- // electronSystemService.closeWindow();
82
- // }}
83
- // >
84
- // <XIcon absoluteStrokeWidth size={14} strokeWidth={1.2} />
85
- // </div>
86
- // </div>
87
- // );
88
- };
89
-
90
- export default WinControl;