@jetcrab/pi-desk 1.1.18-dev → 1.1.20-dev
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.
- package/docs/plugins.md +1 -1
- package/next.config.ts +1 -0
- package/package.json +3 -2
- package/src/client/l2_biz/workbench/file-workspace/l2-file-workspace-runtime.ts +1 -1
- package/src/client/l2_biz/workbench/hooks/l2-workbench-chat-reload.ts +42 -0
- package/src/client/l2_biz/workbench/l2-work-session-sidebar.tsx +19 -1
- package/src/client/l2_biz/workbench/l2-workbench-chat.ts +45 -0
- package/src/client/l2_biz/workbench/l2-workbench.tsx +4 -0
- package/src/client/l3_modules/conversation/l3-conversation-markdown.tsx +10 -1
- package/src/client/l3_modules/project-files/l3-markdown-preview.tsx +10 -1
- package/src/client/l3_modules/project-files/l3-project-document-view.tsx +2 -0
- package/src/client/l3_modules/project-files/l3-project-file-browser.tsx +171 -229
- package/src/client/l3_modules/project-files/l3-project-file-runtime.ts +133 -70
- package/src/client/l3_modules/project-files/l3-project-reader.ts +4 -3
- package/src/client/l3_modules/project-files/views/l3-project-search-controls.tsx +201 -0
- package/src/client/l3_modules/project-files/views/l3-project-search-results.tsx +333 -0
- package/src/client/l4_foundation/ui/code/l4-code-preview.tsx +47 -3
- package/src/client/l4_foundation/ui/markdown/l4-markdown-remark.ts +89 -0
- package/src/client/l4_foundation/ui/markdown/l4-markdown.module.css +58 -0
- package/src/client/l4_foundation/ui/markdown/l4-markdown.tsx +108 -0
- package/src/common/l2_biz/work-session/l2-work-session-file-contract.ts +4 -3
- package/src/common/l2_biz/workbench/l2-workbench-locale-messages.ts +6 -0
- package/src/common/l3_modules/project-files/l3-project-files-contract.ts +2 -3
- package/src/common/l3_modules/project-files/l3-project-files-locale-messages.ts +56 -10
- package/src/common/l4_foundation/file/l4-project-file-contract.ts +51 -1
- package/src/common/l4_foundation/locale/l4-host-error-messages.ts +11 -0
- package/src/common/l4_foundation/locale/l4-locale-messages.ts +16 -0
- package/src/instrumentation.ts +0 -2
- package/src/server/l1_entry/api/l1-project-read-routes.ts +6 -4
- package/src/server/l1_entry/api/l1-project-route.ts +9 -8
- package/src/server/l1_entry/api/l1-work-session-file-error.ts +23 -0
- package/src/server/l2_biz/plugin-management/l2-plugin-management.ts +0 -3
- package/src/server/l2_biz/work-session/l2-work-session-chat-runtime.ts +30 -58
- package/src/server/l2_biz/work-session/l2-work-session-manage.ts +0 -4
- package/src/server/l4_foundation/file/l4-project-file-index.ts +276 -0
- package/src/server/l4_foundation/file/l4-project-search.ts +399 -0
- package/src/server/l4_foundation/file/l4-ripgrep-search.ts +192 -0
- package/src/server/l4_foundation/file/l4-work-session-project-file.ts +8 -332
- package/src/server/l4_foundation/pi/l4-pi-package-maintenance.ts +0 -6
- package/src/server/l4_foundation/pi/l4-pi-plugin-capability-probe.ts +1 -3
- package/src/server/l4_foundation/pi/l4-pi-plugin-probe.ts +1 -3
- package/src/server/l4_foundation/pi/l4-pi-runner-process.ts +2 -2
- package/src/server/l4_foundation/process/l4-process-tree.js +23 -4
- package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
- package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/prerender-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/react-loadable-manifest.json +1 -1
- package/temp/build/pi-desk/release/.next/required-server-files.js +3 -2
- package/temp/build/pi-desk/release/.next/required-server-files.json +3 -2
- package/temp/build/pi-desk/release/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.html +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_not-found/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/health/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/reveal/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/search/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +2 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/page.js +77 -77
- package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/{33658.js → 10881.js} +8 -8
- package/temp/build/pi-desk/release/.next/server/chunks/23054.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/25406.js +3 -3
- package/temp/build/pi-desk/release/.next/server/chunks/35985.js +5 -5
- package/temp/build/pi-desk/release/.next/server/chunks/50520.js +2 -4
- package/temp/build/pi-desk/release/.next/server/chunks/6917.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/70780.js +1 -0
- package/temp/build/pi-desk/release/.next/server/chunks/74528.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/92386.js +1 -1
- package/temp/build/pi-desk/release/.next/server/instrumentation.js +1 -1
- package/temp/build/pi-desk/release/.next/server/middleware-build-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/pages/500.html +1 -1
- package/temp/build/pi-desk/release/.next/server/server-reference-manifest.json +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/27611-0890482fe76bd9d6.js +238 -0
- package/temp/build/pi-desk/release/.next/static/chunks/{31087-ba426d09d6f68bfd.js → 31087-d8e5765d541d5c26.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/{49516-cc4dcd84d64ab4fe.js → 51474-8dc714cb76b2e60a.js} +2 -2
- package/temp/build/pi-desk/release/.next/static/chunks/77592-5bef6acb8e7c4b96.js +13 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/layout-a50c456648537afb.js +3 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{page-a984139e99586041.js → page-0789c43551b29dd2.js} +4 -4
- package/temp/build/pi-desk/release/.next/static/chunks/{webpack-40a782fc8a3535b9.js → webpack-d7248206b7fc7ba8.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/css/250a6b93cc2222d1.css +1 -0
- package/temp/build/pi-desk/release/.next/static/css/6dbae2922f88ca31.css +1 -0
- package/temp/build/pi-desk/release/.next/static/css/a4cf28fd76c70165.css +1 -0
- package/temp/build/pi-desk/release/.next/trace-build +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/8584.js +0 -2
- package/temp/build/pi-desk/release/.next/static/chunks/39654-b5fedd762ea0312e.js +0 -238
- package/temp/build/pi-desk/release/.next/static/chunks/75130-d2ca74894aff8085.js +0 -13
- package/temp/build/pi-desk/release/.next/static/chunks/app/layout-c0e1c5cef8620cf8.js +0 -3
- package/temp/build/pi-desk/release/.next/static/css/6427d02b6edf406f.css +0 -1
- package/temp/build/pi-desk/release/.next/static/css/79e06f05df9edff0.css +0 -1
- /package/temp/build/pi-desk/release/.next/static/{n2LrXQgq8UkbH_AzhR3fw → RLKcK-RQF5FvEeDmS9uih}/_buildManifest.js +0 -0
- /package/temp/build/pi-desk/release/.next/static/{n2LrXQgq8UkbH_AzhR3fw → RLKcK-RQF5FvEeDmS9uih}/_ssgManifest.js +0 -0
package/docs/plugins.md
CHANGED
|
@@ -211,7 +211,7 @@ export default {
|
|
|
211
211
|
- 首屏和实时必需内容放 `summary`;大内容或用户展开后才用的数据放 `detail`。需要详情时,仅在消息已有 `entryId` 且 `fixed.hasDetail` 为真后调用 `target.message.loadDetail()`;异步结果须检查挂载的 `signal`,不能写回失效视图。
|
|
212
212
|
- 视图从 `getSnapshot()` 读取完整当前状态,并通过 `subscribe()` 跟随更新;同 `viewKey` 的消息更新不重新挂载,Temporary 转 Durable 保持同一 Handle,`viewKey` 改变时会重挂。释放时解除订阅并清理自有资源。
|
|
213
213
|
- Declaration 和 View 分别按 `priority` 选择,数值越大越优先;同最高优先级冲突会报错。声明、加载或展示失败不自动尝试低优先级实现;异步展示错误通过 `target.reportError(error)` 交给宿主处理。
|
|
214
|
-
- 刷新后仍需展示的数据必须存在于最终 Pi Entry,仅通过 Tool `onUpdate()`
|
|
214
|
+
- 刷新后仍需展示的数据必须存在于最终 Pi Entry,仅通过 Tool `onUpdate()` 提供的数据不会自动持久化。插件初始化、更新和热加载不自动重投影或重传旧聊天,新消息使用当前声明;Browser View 需兼容已有消息结构,不靠自动重载旧会话解决兼容问题。
|
|
215
215
|
|
|
216
216
|
## 任务
|
|
217
217
|
|
package/next.config.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetcrab/pi-desk",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20-dev",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@streamdown/code": "^1.1.1",
|
|
38
38
|
"@streamdown/math": "^1.0.2",
|
|
39
39
|
"@streamdown/mermaid": "^1.0.2",
|
|
40
|
+
"@vscode/ripgrep": "1.18.0",
|
|
40
41
|
"@xterm/addon-fit": "0.11.0",
|
|
41
42
|
"@xterm/addon-serialize": "0.14.0",
|
|
42
43
|
"@xterm/headless": "6.0.0",
|
|
@@ -111,7 +112,7 @@
|
|
|
111
112
|
"build:plugin-host-runtime": "pnpm --filter @jetcrab/pi-desk-sdk build",
|
|
112
113
|
"start": "node bin/pi-desk.js --no-open",
|
|
113
114
|
"test:package": "node --test tests/l4-pi-desk-package.test.mjs",
|
|
114
|
-
"test:pidesk": "node --import tsx --test tests/l4-pidesk-command.test.ts tests/l2-plugin-commands.test.ts tests/l4-pidesk-session-reload.test.ts tests/l4-pidesk-runtime.test.ts tests/l4-pidesk-runtime-bundle.test.mjs tests/l4-pidesk-docs.test.mjs tests/l4-pidesk-installed-runners.test.mjs tests/l4-pidesk-package-maintenance.test.ts tests/l4-pidesk-release-gate.test.mjs tests/l4-pi-global-runtime.test.mjs tests/l4-pi-desk-supervisor-cli.test.mjs",
|
|
115
|
+
"test:pidesk": "node --import tsx --test tests/l4-pidesk-command.test.ts tests/l2-plugin-commands.test.ts tests/l4-pidesk-session-reload.test.ts tests/l4-pidesk-runtime.test.ts tests/l4-pidesk-runtime-bundle.test.mjs tests/l4-pidesk-docs.test.mjs tests/l4-pidesk-installed-runners.test.mjs tests/l4-pidesk-package-maintenance.test.ts tests/l4-pidesk-release-gate.test.mjs tests/l4-pi-desk-process-tree.test.mjs tests/l4-pi-runner-process.test.ts tests/l4-pi-global-runtime.test.mjs tests/l4-pi-desk-supervisor-cli.test.mjs",
|
|
115
116
|
"test:app-websocket": "pnpm build && node --import tsx --test tests/l2-chat-state.test.ts tests/l2-workbench-chat-repository.test.ts tests/l2-workbench-chat.test.ts tests/l2-workbench-layout.test.ts tests/l2-work-session-column-layout.test.ts tests/l2-work-session-update.test.ts tests/l1-app-websocket.test.mjs",
|
|
116
117
|
"lint": "eslint .",
|
|
117
118
|
"lint:production": "eslint . --ignore-pattern \"apps/desktop/**\" --ignore-pattern \"**/tests/**\" --ignore-pattern \"**/__tests__/**\" --ignore-pattern \"**/*.test.*\" --ignore-pattern \"**/*.spec.*\"",
|
|
@@ -346,7 +346,7 @@ export class L2FileWorkspaceRuntime {
|
|
|
346
346
|
cwd,
|
|
347
347
|
{
|
|
348
348
|
list: (path, signal) => this.biz.list({ ...context, path }, signal),
|
|
349
|
-
search: (
|
|
349
|
+
search: (input, signal) => this.biz.search({ ...context, ...input }, signal),
|
|
350
350
|
get: (path, imagePreviewMode, signal) =>
|
|
351
351
|
this.biz.get({ ...context, path, imagePreviewMode }, signal),
|
|
352
352
|
diff: (repositoryRoot, path, signal) =>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useCallback, useMemo, useSyncExternalStore } from 'react'
|
|
4
|
+
import { useTranslation } from 'react-i18next'
|
|
5
|
+
import type { L2WorkSessionListItem } from '@common/l2_biz/work-session/l2-work-session-contract'
|
|
6
|
+
import { useL4AppToast } from '@client/l4_foundation/ui/l4-app-toast'
|
|
7
|
+
import type { L2WorkbenchChatRuntime } from '../l2-workbench-chat'
|
|
8
|
+
|
|
9
|
+
export function useL2WorkbenchChatReload(
|
|
10
|
+
runtime: L2WorkbenchChatRuntime,
|
|
11
|
+
workSessions: readonly L2WorkSessionListItem[]
|
|
12
|
+
): {
|
|
13
|
+
syncingWorkIds: readonly string[]
|
|
14
|
+
reload: (workSession: L2WorkSessionListItem) => void
|
|
15
|
+
} {
|
|
16
|
+
const { t } = useTranslation('workbench')
|
|
17
|
+
const toast = useL4AppToast()
|
|
18
|
+
const getSyncing = useCallback(
|
|
19
|
+
(): string =>
|
|
20
|
+
JSON.stringify(
|
|
21
|
+
workSessions
|
|
22
|
+
.filter(
|
|
23
|
+
({ workId, sessionId, branchId }) =>
|
|
24
|
+
runtime.getSourceState({ workId, sessionId, branchId }).syncStatus === 'syncing'
|
|
25
|
+
)
|
|
26
|
+
.map((session) => session.workId)
|
|
27
|
+
),
|
|
28
|
+
[runtime, workSessions]
|
|
29
|
+
)
|
|
30
|
+
const syncing = useSyncExternalStore(runtime.subscribe, getSyncing, getSyncing)
|
|
31
|
+
const syncingWorkIds = useMemo((): string[] => JSON.parse(syncing), [syncing])
|
|
32
|
+
const reload = useCallback(
|
|
33
|
+
(session: L2WorkSessionListItem): void => {
|
|
34
|
+
const { workId, sessionId, branchId } = session
|
|
35
|
+
void runtime.reloadMessages({ workId, sessionId, branchId }).catch((cause: unknown) => {
|
|
36
|
+
toast.error(cause instanceof Error ? cause.message : t('reloadChatDataFailed'))
|
|
37
|
+
})
|
|
38
|
+
},
|
|
39
|
+
[runtime, t, toast]
|
|
40
|
+
)
|
|
41
|
+
return { syncingWorkIds, reload }
|
|
42
|
+
}
|
|
@@ -140,6 +140,8 @@ interface L2WorkSessionSidebarProps {
|
|
|
140
140
|
onTogglePin: (workId: string) => void
|
|
141
141
|
onDelete: (workId: string) => void
|
|
142
142
|
onRename: (workSession: L2WorkSessionListItem) => void
|
|
143
|
+
syncingWorkIds: readonly string[]
|
|
144
|
+
onReloadChat: (workSession: L2WorkSessionListItem) => void
|
|
143
145
|
onArrangementChange: (arrangement: L2WorkSessionArrangement, movedWorkId: string) => void
|
|
144
146
|
}
|
|
145
147
|
|
|
@@ -343,7 +345,9 @@ const SortableWorkSessionRow = memo(function SortableWorkSessionRow({
|
|
|
343
345
|
onSelect,
|
|
344
346
|
onTogglePin,
|
|
345
347
|
onDelete,
|
|
346
|
-
onRename
|
|
348
|
+
onRename,
|
|
349
|
+
syncing,
|
|
350
|
+
onReloadChat
|
|
347
351
|
}: {
|
|
348
352
|
workSession: L2WorkSessionListItem
|
|
349
353
|
mobile: boolean
|
|
@@ -357,6 +361,8 @@ const SortableWorkSessionRow = memo(function SortableWorkSessionRow({
|
|
|
357
361
|
onTogglePin: (workId: string) => void
|
|
358
362
|
onDelete: (workId: string) => void
|
|
359
363
|
onRename: (workSession: L2WorkSessionListItem) => void
|
|
364
|
+
syncing: boolean
|
|
365
|
+
onReloadChat: (workSession: L2WorkSessionListItem) => void
|
|
360
366
|
}): React.JSX.Element {
|
|
361
367
|
const suppressTouchClick = useRef(false)
|
|
362
368
|
const lastPointer = useRef('')
|
|
@@ -606,6 +612,14 @@ const SortableWorkSessionRow = memo(function SortableWorkSessionRow({
|
|
|
606
612
|
<PencilIcon />
|
|
607
613
|
{t('renameSessionTitle')}
|
|
608
614
|
</ContextMenuItem>
|
|
615
|
+
<ContextMenuItem
|
|
616
|
+
data-testid={`work-session-reload-chat-${workSession.workId}`}
|
|
617
|
+
disabled={actionsDisabled || deleting || syncing}
|
|
618
|
+
onClick={() => onReloadChat(workSession)}
|
|
619
|
+
>
|
|
620
|
+
{syncing ? <LoaderCircleIcon className="animate-spin" /> : <RefreshCwIcon />}
|
|
621
|
+
{t('reloadChatData')}
|
|
622
|
+
</ContextMenuItem>
|
|
609
623
|
<ContextMenuItem
|
|
610
624
|
data-testid={`work-session-copy-project-path-${workSession.workId}`}
|
|
611
625
|
onClick={copyProjectPath}
|
|
@@ -675,6 +689,8 @@ function L2WorkSessionSidebarComponent({
|
|
|
675
689
|
onTogglePin,
|
|
676
690
|
onDelete,
|
|
677
691
|
onRename,
|
|
692
|
+
syncingWorkIds,
|
|
693
|
+
onReloadChat,
|
|
678
694
|
onArrangementChange
|
|
679
695
|
}: L2WorkSessionSidebarProps): React.JSX.Element {
|
|
680
696
|
const { t } = useTranslation('workbench')
|
|
@@ -888,6 +904,8 @@ function L2WorkSessionSidebarComponent({
|
|
|
888
904
|
onTogglePin={onTogglePin}
|
|
889
905
|
onDelete={onDelete}
|
|
890
906
|
onRename={onRename}
|
|
907
|
+
syncing={syncingWorkIds.includes(workSession.workId)}
|
|
908
|
+
onReloadChat={onReloadChat}
|
|
891
909
|
/>
|
|
892
910
|
)
|
|
893
911
|
})
|
|
@@ -73,6 +73,7 @@ export interface L2WorkbenchChatRuntime {
|
|
|
73
73
|
) => Promise<L2ChatMessageDetail>
|
|
74
74
|
compact: (source: L2ChatSource) => Promise<void>
|
|
75
75
|
reload: (source: L2ChatSource, mode?: L2ChatMode) => Promise<void>
|
|
76
|
+
reloadMessages: (source: L2ChatSource) => Promise<void>
|
|
76
77
|
setPresentation: (source: L2ChatSource, mode: L2ChatMode) => Promise<void>
|
|
77
78
|
disconnected: () => void
|
|
78
79
|
dispose: () => void
|
|
@@ -611,6 +612,50 @@ export function createL2WorkbenchChatRuntime(
|
|
|
611
612
|
)
|
|
612
613
|
},
|
|
613
614
|
|
|
615
|
+
async reloadMessages(sourceInput): Promise<void> {
|
|
616
|
+
const source = L2ChatSourceSchema.parse(sourceInput)
|
|
617
|
+
const key = sourceKey(source)
|
|
618
|
+
const workSession = currentWorkSessions.get(source.workId)
|
|
619
|
+
if (!workSession || !sameSource(sourceFor(workSession), source)) {
|
|
620
|
+
throw new Error(l2WorkbenchText('reloadChatSourceChanged'))
|
|
621
|
+
}
|
|
622
|
+
const previous = statesBySource.get(key)
|
|
623
|
+
if (
|
|
624
|
+
!workSessionsReady ||
|
|
625
|
+
disposed ||
|
|
626
|
+
pendingSyncs.has(key) ||
|
|
627
|
+
previous?.syncStatus === 'syncing'
|
|
628
|
+
) {
|
|
629
|
+
throw new Error(l2WorkbenchText('sourceSyncing'))
|
|
630
|
+
}
|
|
631
|
+
const epoch = connectionEpoch
|
|
632
|
+
const queue = eventQueues.get(key)
|
|
633
|
+
const previousSyncEpoch = queue?.syncEpoch ?? null
|
|
634
|
+
if (queue) queue.syncEpoch = null
|
|
635
|
+
subscriptionPool.set(source.workId, source)
|
|
636
|
+
setSourceState(source, { ...(previous ?? EMPTY_CHAT_SOURCE_STATE), syncStatus: 'syncing' })
|
|
637
|
+
try {
|
|
638
|
+
// 重拉期间继续接收旧基线上的实时消息,失败时无需丢弃缓存或补偿重放。
|
|
639
|
+
await appSocket.request(L2ChatSocketContracts.subscribe, {
|
|
640
|
+
subscriptions: [{ source, cursor: null }]
|
|
641
|
+
})
|
|
642
|
+
} catch (error) {
|
|
643
|
+
if (!disposed && epoch === connectionEpoch && isCurrentAndSubscribed(source)) {
|
|
644
|
+
if (queue && eventQueues.get(key) === queue) queue.syncEpoch = previousSyncEpoch
|
|
645
|
+
const current = statesBySource.get(key)
|
|
646
|
+
if (current)
|
|
647
|
+
setSourceState(source, { ...current, syncStatus: previous?.syncStatus ?? 'loading' })
|
|
648
|
+
}
|
|
649
|
+
console.error('[Pi Desk][WorkbenchChat] 重新加载聊天数据失败,保留已有缓存', {
|
|
650
|
+
workId: source.workId,
|
|
651
|
+
sessionId: source.sessionId,
|
|
652
|
+
branchId: source.branchId,
|
|
653
|
+
message: error instanceof Error ? error.message : String(error)
|
|
654
|
+
})
|
|
655
|
+
throw error
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
|
|
614
659
|
async setPresentation(sourceInput, mode): Promise<void> {
|
|
615
660
|
const source = L2ChatSourceSchema.parse(sourceInput)
|
|
616
661
|
const key = sourceKey(source)
|
|
@@ -112,6 +112,7 @@ import {
|
|
|
112
112
|
} from './l2-work-session-sidebar-order'
|
|
113
113
|
import { useL2WorkbenchBranchPicker } from './hooks/l2-workbench-branch-picker'
|
|
114
114
|
import { useL2WorkSessionRename } from './hooks/l2-work-session-rename'
|
|
115
|
+
import { useL2WorkbenchChatReload } from './hooks/l2-workbench-chat-reload'
|
|
115
116
|
import { L2WorkSessionRenameDialog } from './views/l2-work-session-rename-dialog'
|
|
116
117
|
import { useL2WorkbenchPluginHealth } from './hooks/l2-workbench-plugin-health'
|
|
117
118
|
import { useL2WorkbenchSessionHistory } from './hooks/l2-workbench-session-history'
|
|
@@ -370,6 +371,7 @@ export function L2Workbench({
|
|
|
370
371
|
createL2WorkbenchChatRuntime(appSocket, (input) => workbenchBiz.getChatMessageDetail(input)),
|
|
371
372
|
[appSocket, workbenchBiz]
|
|
372
373
|
)
|
|
374
|
+
const chatReload = useL2WorkbenchChatReload(chatRuntime, workSessions)
|
|
373
375
|
const chatInputRuntime = useMemo(
|
|
374
376
|
() => createL2WorkbenchChatInputRuntime(workbenchBiz, chatRuntime),
|
|
375
377
|
[chatRuntime, workbenchBiz]
|
|
@@ -1928,6 +1930,8 @@ export function L2Workbench({
|
|
|
1928
1930
|
onTogglePin={togglePinnedWorkSession}
|
|
1929
1931
|
onDelete={requestDeleteWorkSession}
|
|
1930
1932
|
onRename={renameSession.show}
|
|
1933
|
+
syncingWorkIds={chatReload.syncingWorkIds}
|
|
1934
|
+
onReloadChat={chatReload.reload}
|
|
1931
1935
|
onArrangementChange={requestArrangementUpdate}
|
|
1932
1936
|
/>
|
|
1933
1937
|
)
|
|
@@ -10,6 +10,12 @@ import { MessageResponse } from '@client/l4_foundation/ui/ai-elements/message'
|
|
|
10
10
|
import { copyL4BrowserText } from '@client/l4_foundation/lib/l4-browser-clipboard'
|
|
11
11
|
import { cn } from '@client/l4_foundation/lib/l4-utils'
|
|
12
12
|
import { L4ImageViewer } from '@client/l4_foundation/ui/l4-image-viewer'
|
|
13
|
+
import {
|
|
14
|
+
L4_MARKDOWN_ALLOWED_TAGS,
|
|
15
|
+
L4_MARKDOWN_CLASS_NAME,
|
|
16
|
+
L4_MARKDOWN_COMPONENTS,
|
|
17
|
+
L4_MARKDOWN_REMARK_PLUGINS
|
|
18
|
+
} from '@client/l4_foundation/ui/markdown/l4-markdown'
|
|
13
19
|
import { useL4AppToast } from '@client/l4_foundation/ui/l4-app-toast'
|
|
14
20
|
import styles from './l3-conversation-markdown.module.css'
|
|
15
21
|
|
|
@@ -140,11 +146,14 @@ export function L3ConversationMarkdown({
|
|
|
140
146
|
return (
|
|
141
147
|
<div className="contents" onClickCapture={handleCodeCopyFallback}>
|
|
142
148
|
<MessageResponse
|
|
143
|
-
className={cn('space-y-0', styles.markdown, className)}
|
|
149
|
+
className={cn('space-y-0', styles.markdown, L4_MARKDOWN_CLASS_NAME, className)}
|
|
144
150
|
controls={COMPACT_CODE_CONTROLS}
|
|
145
151
|
isAnimating={isAnimating}
|
|
146
152
|
lineNumbers={false}
|
|
153
|
+
allowedTags={L4_MARKDOWN_ALLOWED_TAGS}
|
|
154
|
+
remarkPlugins={L4_MARKDOWN_REMARK_PLUGINS}
|
|
147
155
|
components={{
|
|
156
|
+
...L4_MARKDOWN_COMPONENTS,
|
|
148
157
|
...components,
|
|
149
158
|
a: L3ConversationMarkdownLink,
|
|
150
159
|
img: L3ConversationMarkdownImage
|
|
@@ -4,6 +4,12 @@ import { cjk } from '@streamdown/cjk'
|
|
|
4
4
|
import { code } from '@streamdown/code'
|
|
5
5
|
import { memo, useLayoutEffect, useRef } from 'react'
|
|
6
6
|
import { Streamdown } from 'streamdown'
|
|
7
|
+
import {
|
|
8
|
+
L4_MARKDOWN_ALLOWED_TAGS,
|
|
9
|
+
L4_MARKDOWN_CLASS_NAME,
|
|
10
|
+
L4_MARKDOWN_COMPONENTS,
|
|
11
|
+
L4_MARKDOWN_REMARK_PLUGINS
|
|
12
|
+
} from '@client/l4_foundation/ui/markdown/l4-markdown'
|
|
7
13
|
import styles from './l3-markdown-preview.module.css'
|
|
8
14
|
|
|
9
15
|
const plugins = { cjk, code }
|
|
@@ -37,7 +43,10 @@ export const L3MarkdownPreview = memo(function L3MarkdownPreview({
|
|
|
37
43
|
onScroll={(event) => onScroll(event.currentTarget.scrollTop)}
|
|
38
44
|
>
|
|
39
45
|
<Streamdown
|
|
40
|
-
className={styles.document}
|
|
46
|
+
className={`${styles.document} ${L4_MARKDOWN_CLASS_NAME}`}
|
|
47
|
+
allowedTags={L4_MARKDOWN_ALLOWED_TAGS}
|
|
48
|
+
components={L4_MARKDOWN_COMPONENTS}
|
|
49
|
+
remarkPlugins={L4_MARKDOWN_REMARK_PLUGINS}
|
|
41
50
|
mode="static"
|
|
42
51
|
parseIncompleteMarkdown={false}
|
|
43
52
|
isAnimating={false}
|
|
@@ -418,6 +418,8 @@ export function L3ProjectDocumentView({
|
|
|
418
418
|
}}
|
|
419
419
|
onOpenDiff={openDiff}
|
|
420
420
|
savedState={document.editorState}
|
|
421
|
+
navigation={runtime.pendingNavigation}
|
|
422
|
+
onNavigation={(target, exists) => runtime.consumeNavigation(target, exists)}
|
|
421
423
|
onSaveState={(path, state) => runtime.saveEditorState(path, state)}
|
|
422
424
|
onEscape={escape}
|
|
423
425
|
/>
|