@jetcrab/pi-desk 1.1.20-dev → 1.1.22-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 +81 -1
- package/package.json +3 -3
- package/src/app/page.tsx +6 -1
- package/src/app/project-preview/page.tsx +10 -0
- package/src/client/l1_entry/pages/l1-home-page.tsx +30 -0
- package/src/client/l1_entry/pages/l1-project-preview-page.tsx +33 -0
- package/src/client/l1_entry/providers/l1-app-providers.tsx +18 -15
- package/src/client/l1_entry/providers/l1-app-runtime-provider.tsx +2 -2
- package/src/client/l2_biz/auth/l2-login-biz.ts +3 -0
- package/src/client/l2_biz/auth/l2-login.tsx +2 -3
- package/src/client/l2_biz/plugin-host/l2-plugin-capability-details.tsx +6 -1
- package/src/client/l2_biz/plugin-host/l2-plugin-contribution-host.tsx +71 -10
- package/src/client/l2_biz/plugin-host/l2-plugin-management-controls.tsx +9 -0
- package/src/client/l2_biz/plugin-host/l2-plugin-session-header-layout.ts +18 -0
- package/src/client/l2_biz/plugin-host/l2-plugin-session-header.tsx +247 -0
- package/src/client/l2_biz/plugin-host/l2-plugin-widgets.tsx +50 -0
- package/src/client/l2_biz/plugin-host/views/l2-plugin-session-header-action.tsx +112 -0
- package/src/client/l2_biz/project-preview/hooks/l2-use-project-picker.ts +76 -0
- package/src/client/l2_biz/project-preview/hooks/l2-use-project-preview.ts +214 -0
- package/src/client/l2_biz/project-preview/l2-project-preview-biz.ts +49 -4
- package/src/client/l2_biz/project-preview/l2-project-preview-dialog.tsx +42 -450
- package/src/client/l2_biz/project-preview/l2-project-preview-page.tsx +61 -0
- package/src/client/l2_biz/project-preview/l2-project-preview.tsx +342 -0
- package/src/client/l2_biz/project-preview/runtime/l2-project-history-runtime.ts +9 -3
- package/src/client/l2_biz/project-preview/views/l2-project-picker.tsx +168 -0
- package/src/client/l2_biz/settings/hooks/l2-use-model-settings.ts +34 -31
- package/src/client/l2_biz/settings/views/l2-model-replacement-preview.tsx +7 -1
- package/src/client/l2_biz/workbench/file-workspace/l2-project-preview-biz.ts +4 -3
- package/src/client/l2_biz/workbench/hooks/l2-workbench-chat-viewport.ts +28 -21
- package/src/client/l2_biz/workbench/l2-work-session-columns.module.css +32 -0
- package/src/client/l2_biz/workbench/l2-work-session-columns.tsx +55 -16
- package/src/client/l2_biz/workbench/l2-work-session-sidebar.tsx +19 -8
- package/src/client/l2_biz/workbench/l2-workbench-chat-composer.tsx +12 -1
- package/src/client/l2_biz/workbench/l2-workbench-initialization-notice.tsx +8 -3
- package/src/client/l2_biz/workbench/l2-workbench-plugin-slots.ts +13 -0
- package/src/client/l2_biz/workbench/l2-workbench.tsx +15 -2
- package/src/client/l3_modules/conversation/l3-conversation-viewport.tsx +12 -6
- package/src/client/l3_modules/project-files/l3-markdown-preview.module.css +1 -1
- package/src/client/l3_modules/project-files/l3-project-document-git.ts +4 -3
- package/src/client/l3_modules/project-files/l3-project-document-view.tsx +4 -1
- package/src/client/l3_modules/project-files/l3-project-reader.ts +23 -35
- package/src/client/l4_foundation/lib/l4-client-id.tsx +11 -0
- package/src/client/l4_foundation/plugin-host/l4-plugin-host-runtime.ts +316 -35
- package/src/common/l2_biz/auth/l2-auth-return-to.ts +41 -0
- package/src/common/l2_biz/model-settings/l2-model-settings-contract.ts +5 -1
- package/src/common/l2_biz/plugin/l2-plugin-management-messages.ts +4 -0
- package/src/common/l2_biz/project-preview/l2-project-history-messages.ts +28 -0
- package/src/common/l2_biz/project-preview/l2-project-preview-navigation.ts +5 -0
- package/src/common/l2_biz/settings/l2-settings-messages.ts +4 -3
- package/src/common/l2_biz/workbench/l2-workbench-locale-messages.ts +2 -0
- package/src/server/l1_entry/node/l1-server.ts +8 -4
- package/src/server/l4_foundation/model-settings/l4-model-settings-store.ts +29 -20
- package/src/server/l4_foundation/model-settings/l4-model-settings-types.ts +1 -1
- package/src/server/l4_foundation/pi/l4-pi-chat-worker.ts +22 -5
- package/src/server/l4_foundation/pi/l4-pi-plugin-owner-runtime.ts +133 -13
- package/src/server/l4_foundation/pi/l4-pi-session-initialization.ts +9 -0
- package/temp/build/pi-desk/release/.next/BUILD_ID +1 -1
- package/temp/build/pi-desk/release/.next/app-path-routes-manifest.json +3 -2
- package/temp/build/pi-desk/release/.next/build-manifest.json +3 -3
- package/temp/build/pi-desk/release/.next/react-loadable-manifest.json +1 -2
- package/temp/build/pi-desk/release/.next/required-server-files.js +2 -2
- package/temp/build/pi-desk/release/.next/required-server-files.json +2 -2
- package/temp/build/pi-desk/release/.next/routes-manifest.json +6 -0
- package/temp/build/pi-desk/release/.next/server/app/_global-error/page.js +1 -1
- 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 +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
- package/temp/build/pi-desk/release/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +3 -3
- 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/auth/login/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth/logout/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/auth-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/capability-modes/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/context/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/images/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/chat/messages/get/route.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/mcp-check/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/mcp-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-catalog/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/preview/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/model-settings/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directories/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-entries/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/directory-ignores/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/models/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/session-user-messages/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/pi/sessions/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/search/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugin-catalog/settings-replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/apply/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/batch/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/browser-resources/[resourceGroup]/[...resourcePath]/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/enabled-set/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/host-runtime/[runtimeVersion]/[...resourcePath]/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/reload/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/plugins/update/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-files/list/route.js +1 -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 -2
- package/temp/build/pi-desk/release/.next/server/app/api/project-git/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-branches/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-changes/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-diff/get/route.js +2 -2
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-heads/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-git-log/list/route.js +2 -2
- package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/project-model-default/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skill-files/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/skills/list/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/task-center/images/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/task-center/messages/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-git-branch/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-session-tree-entry/get/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/add/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/branch/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/del/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/rename/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/replace/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/api/work-sessions/sort/route.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/favicon.ico/route.js +1 -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 +140 -140
- package/temp/build/pi-desk/release/.next/server/app/page_client-reference-manifest.js +1 -1
- package/temp/build/pi-desk/release/.next/server/app/project-preview/page.js +1 -0
- package/temp/build/pi-desk/release/.next/server/app/project-preview/page_client-reference-manifest.js +1 -0
- package/temp/build/pi-desk/release/.next/server/app-paths-manifest.json +3 -2
- package/temp/build/pi-desk/release/.next/server/chunks/10912.js +2 -2
- package/temp/build/pi-desk/release/.next/server/chunks/20460.js +15 -0
- package/temp/build/pi-desk/release/.next/server/chunks/25406.js +8 -8
- package/temp/build/pi-desk/release/.next/server/chunks/35985.js +3 -17
- package/temp/build/pi-desk/release/.next/server/chunks/36361.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/48180.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/56830.js +235 -0
- package/temp/build/pi-desk/release/.next/server/chunks/78262.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/79686.js +62 -0
- package/temp/build/pi-desk/release/.next/server/chunks/80780.js +1 -0
- package/temp/build/pi-desk/release/.next/server/chunks/81363.js +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/82499.js +4 -4
- package/temp/build/pi-desk/release/.next/server/chunks/92386.js +8 -8
- 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/static/MV6_lBt7Mzmi1rBNI-3dx/_buildManifest.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/11937-1d0a9822f2c7995b.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/14825-5579aed34a631ad7.js +62 -0
- package/temp/build/pi-desk/release/.next/static/chunks/15302-9c807afc6c60de0c.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/19991.8aa2e4b6df15fad6.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/22092-6d1bfbefa825ec03.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/37313-d5970e2d0c270d22.js +238 -0
- package/temp/build/pi-desk/release/.next/static/chunks/57235-03ba1044f22b6c84.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/79267-7d21d7cdbd7cfca1.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/82371-f7ba4a07a5dbcf34.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/9038-03144ed96d613f75.js +15 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{error-0296a3b20cd1bf00.js → error-216b14b5da089ed3.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/layout-20718f1503910291.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/login/page-0d3d4827802108e5.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/{not-found-2aab8b33ebbf3257.js → not-found-720cdf6a606b821a.js} +1 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-e8a5274c115f528d.js +158 -0
- package/temp/build/pi-desk/release/.next/static/chunks/app/project-preview/page-d70ee4e9409b970a.js +1 -0
- package/temp/build/pi-desk/release/.next/static/chunks/webpack-b60891a214e0925d.js +1 -0
- package/temp/build/pi-desk/release/.next/static/css/{250a6b93cc2222d1.css → 1e780a4936aa6ba3.css} +1 -1
- package/temp/build/pi-desk/release/.next/static/css/f646ca6c07245c4c.css +1 -0
- package/temp/build/pi-desk/release/.next/trace-build +1 -1
- package/temp/build/pi-desk/release/.next/server/chunks/10881.js +0 -296
- package/temp/build/pi-desk/release/.next/static/RLKcK-RQF5FvEeDmS9uih/_buildManifest.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/27611-0890482fe76bd9d6.js +0 -238
- package/temp/build/pi-desk/release/.next/static/chunks/31087-d8e5765d541d5c26.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/3814-35cfab0ce3aa7c41.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/70669.07f3670bfb7d6dd2.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/74220-795a2e7185bd66cb.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/77592-5bef6acb8e7c4b96.js +0 -13
- package/temp/build/pi-desk/release/.next/static/chunks/78923-17a9c337b29dcecd.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/81881-f11dbe7dc0d04ed9.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/96995-8f8313ea2ac3abd7.js +0 -62
- package/temp/build/pi-desk/release/.next/static/chunks/app/layout-a50c456648537afb.js +0 -3
- package/temp/build/pi-desk/release/.next/static/chunks/app/login/page-84892b06243891f0.js +0 -1
- package/temp/build/pi-desk/release/.next/static/chunks/app/page-0789c43551b29dd2.js +0 -158
- package/temp/build/pi-desk/release/.next/static/chunks/webpack-d7248206b7fc7ba8.js +0 -1
- package/temp/build/pi-desk/release/.next/static/css/a4cf28fd76c70165.css +0 -1
- /package/temp/build/pi-desk/release/.next/static/{RLKcK-RQF5FvEeDmS9uih → MV6_lBt7Mzmi1rBNI-3dx}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createServer, type IncomingMessage, type ServerResponse } from 'node:http'
|
|
2
2
|
import type { Duplex } from 'node:stream'
|
|
3
3
|
import { URL } from 'node:url'
|
|
4
|
+
import { L2BuildLoginHref, L2ResolveAuthReturnTo } from '@common/l2_biz/auth/l2-auth-return-to'
|
|
4
5
|
import {
|
|
5
6
|
L4_APP_WEBSOCKET_ENDPOINT,
|
|
6
7
|
L4_APP_WEBSOCKET_PROTOCOL,
|
|
@@ -97,15 +98,16 @@ function allowHttpRequest(
|
|
|
97
98
|
response: ServerResponse,
|
|
98
99
|
hostname: string
|
|
99
100
|
): boolean {
|
|
100
|
-
let
|
|
101
|
+
let requestUrl: URL
|
|
101
102
|
try {
|
|
102
|
-
|
|
103
|
+
requestUrl = new URL(request.url ?? '/', `http://${request.headers.host ?? hostname}`)
|
|
103
104
|
} catch {
|
|
104
105
|
response.statusCode = 400
|
|
105
106
|
response.end('Bad Request')
|
|
106
107
|
return false
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
const pathname = requestUrl.pathname
|
|
109
111
|
if (isPublicHttpPath(pathname) && pathname !== LOGIN_PAGE_PATH) return true
|
|
110
112
|
|
|
111
113
|
const authRuntime = getL1WebAuthRuntimeBridge()
|
|
@@ -119,9 +121,11 @@ function allowHttpRequest(
|
|
|
119
121
|
}
|
|
120
122
|
if (pathname === LOGIN_PAGE_PATH) {
|
|
121
123
|
if (!authenticated) return true
|
|
124
|
+
const returnTo = L2ResolveAuthReturnTo(requestUrl.searchParams.get('returnTo'))
|
|
122
125
|
response.statusCode = 302
|
|
123
126
|
response.setHeader('Cache-Control', 'no-store')
|
|
124
|
-
|
|
127
|
+
// 保留已校验的原路径,避免将 /.//host 规范化为协议相对 Location。
|
|
128
|
+
response.setHeader('Location', encodeURI(returnTo).replace(/%25/g, '%'))
|
|
125
129
|
response.end()
|
|
126
130
|
return false
|
|
127
131
|
}
|
|
@@ -146,7 +150,7 @@ function allowHttpRequest(
|
|
|
146
150
|
|
|
147
151
|
response.statusCode = 302
|
|
148
152
|
response.setHeader('Cache-Control', 'no-store')
|
|
149
|
-
response.setHeader('Location',
|
|
153
|
+
response.setHeader('Location', L2BuildLoginHref(`${requestUrl.pathname}${requestUrl.search}`))
|
|
150
154
|
response.end()
|
|
151
155
|
return false
|
|
152
156
|
}
|
|
@@ -624,7 +624,7 @@ async function assertConnectionCredentials(
|
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
async function prepareProjectDefaultChanges(
|
|
627
|
-
|
|
627
|
+
removed: Set<string>,
|
|
628
628
|
candidate: JsonRecord,
|
|
629
629
|
input: L4ModelSettingsReplaceInput,
|
|
630
630
|
runtime: ModelRuntime,
|
|
@@ -633,16 +633,14 @@ async function prepareProjectDefaultChanges(
|
|
|
633
633
|
projectDefaults: L4ModelSettingsPreview['projectDefaults']
|
|
634
634
|
files: Array<{ path: string; value: JsonRecord }>
|
|
635
635
|
}> {
|
|
636
|
-
const previousKeys = collectedModelKeys(current)
|
|
637
636
|
const nextKeys = collectedModelKeys(candidate)
|
|
638
|
-
const removed = new Set([...previousKeys].filter((key) => !nextKeys.has(key)))
|
|
639
637
|
const replacements = new Map<string, L4ModelOption>()
|
|
640
638
|
for (const { from, to } of input.modelReplacements ?? []) {
|
|
641
639
|
const fromKey = collectedModelKey(from.provider, from.modelId)
|
|
642
640
|
const toKey = collectedModelKey(to.provider, to.modelId)
|
|
643
641
|
if (fromKey === toKey) throw new Error('模型替换来源和目标不能相同')
|
|
644
642
|
if (replacements.has(fromKey)) throw new Error('模型替换来源不能重复')
|
|
645
|
-
if (!
|
|
643
|
+
if (!removed.has(fromKey)) {
|
|
646
644
|
throw new Error(`替换来源 ${from.provider}/${from.modelId} 必须是本次移除的已收录模型`)
|
|
647
645
|
}
|
|
648
646
|
const target = models.find(
|
|
@@ -658,13 +656,6 @@ async function prepareProjectDefaultChanges(
|
|
|
658
656
|
files: Array<{ path: string; value: JsonRecord }>
|
|
659
657
|
} = { projectDefaults: [], files: [] }
|
|
660
658
|
if (!removed.size) return result
|
|
661
|
-
for (const preset of normalizePresets(candidate)) {
|
|
662
|
-
if (removed.has(collectedModelKey(preset.provider, preset.modelId))) {
|
|
663
|
-
throw new Error(
|
|
664
|
-
`模型 ${preset.provider}/${preset.modelId} 仍被常用组合引用,请先移除对应组合`
|
|
665
|
-
)
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
659
|
// 仅在移除模型时检查已知项目,不扫描文件系统寻找任意项目配置。
|
|
669
660
|
const projects = await listL4PiDirectorySummaries(true)
|
|
670
661
|
for (const { cwd } of projects) {
|
|
@@ -681,11 +672,20 @@ async function prepareProjectDefaultChanges(
|
|
|
681
672
|
const provider = merged.getDefaultProvider()
|
|
682
673
|
const modelId = merged.getDefaultModel()
|
|
683
674
|
if (!provider || !modelId || !removed.has(collectedModelKey(provider, modelId))) continue
|
|
675
|
+
const from: L4ModelSelection = {
|
|
676
|
+
provider,
|
|
677
|
+
modelId,
|
|
678
|
+
thinkingLevel: merged.getDefaultThinkingLevel() ?? 'off'
|
|
679
|
+
}
|
|
684
680
|
const target = replacements.get(collectedModelKey(provider, modelId))
|
|
685
681
|
if (!target) {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
682
|
+
const value = { ...settings }
|
|
683
|
+
delete value.defaultProvider
|
|
684
|
+
delete value.defaultModel
|
|
685
|
+
delete value.defaultThinkingLevel
|
|
686
|
+
result.projectDefaults.push({ cwd, from, to: null })
|
|
687
|
+
result.files.push({ path, value })
|
|
688
|
+
continue
|
|
689
689
|
}
|
|
690
690
|
const projectModels = await availableModelOptions(runtime, cwd, candidate)
|
|
691
691
|
if (
|
|
@@ -695,11 +695,6 @@ async function prepareProjectDefaultChanges(
|
|
|
695
695
|
) {
|
|
696
696
|
throw new Error(`替换目标 ${target.provider}/${target.modelId} 在项目“${cwd}”中不可用`)
|
|
697
697
|
}
|
|
698
|
-
const from: L4ModelSelection = {
|
|
699
|
-
provider,
|
|
700
|
-
modelId,
|
|
701
|
-
thinkingLevel: merged.getDefaultThinkingLevel() ?? 'off'
|
|
702
|
-
}
|
|
703
698
|
const thinkingLevel = target.thinkingLevels.includes(from.thinkingLevel)
|
|
704
699
|
? from.thinkingLevel
|
|
705
700
|
: target.thinkingLevels[0]
|
|
@@ -785,11 +780,25 @@ async function prepareModelSettings(input: L4ModelSettingsReplaceInput): Promise
|
|
|
785
780
|
: await ModelRuntime.create({ modelsPath: null, allowModelNetwork: false })
|
|
786
781
|
candidate = mergeModelsRoot(current, input, currentRuntime, defaults)
|
|
787
782
|
}
|
|
783
|
+
const nextKeys = collectedModelKeys(candidate)
|
|
784
|
+
const removed = new Set([...collectedModelKeys(current)].filter((key) => !nextKeys.has(key)))
|
|
785
|
+
if (removed.size && Array.isArray(candidate.modelPresets)) {
|
|
786
|
+
candidate = {
|
|
787
|
+
...candidate,
|
|
788
|
+
modelPresets: candidate.modelPresets.filter(
|
|
789
|
+
(preset) =>
|
|
790
|
+
!isRecord(preset) ||
|
|
791
|
+
typeof preset.provider !== 'string' ||
|
|
792
|
+
typeof preset.modelId !== 'string' ||
|
|
793
|
+
!removed.has(collectedModelKey(preset.provider, preset.modelId))
|
|
794
|
+
)
|
|
795
|
+
}
|
|
796
|
+
}
|
|
788
797
|
const runtime = await validateModelsRoot(candidate)
|
|
789
798
|
const models = await availableModelOptions(runtime, undefined, candidate)
|
|
790
799
|
await assertConnectionCredentials(current, candidate, runtime)
|
|
791
800
|
assertPresetsValid(normalizePresets(candidate), models, normalizePresets(current))
|
|
792
|
-
const result = await prepareProjectDefaultChanges(
|
|
801
|
+
const result = await prepareProjectDefaultChanges(removed, candidate, input, runtime, models)
|
|
793
802
|
result.files.push({ path, value: candidate })
|
|
794
803
|
return result
|
|
795
804
|
}
|
|
@@ -97,7 +97,7 @@ export interface L4ModelReplacement {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
export interface L4ModelSettingsPreview {
|
|
100
|
-
projectDefaults: Array<{ cwd: string; from: L4ModelSelection; to: L4ModelSelection }>
|
|
100
|
+
projectDefaults: Array<{ cwd: string; from: L4ModelSelection; to: L4ModelSelection | null }>
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
export type L4ModelSettingsReplaceInput =
|
|
@@ -425,6 +425,24 @@ export class L4PiChatWorker {
|
|
|
425
425
|
readCapabilities: this.capabilities.rules,
|
|
426
426
|
onInput: (event) =>
|
|
427
427
|
this.validateFinalInput(event.text, event.images, event.streamingBehavior),
|
|
428
|
+
onMessageEnd: ({ message }) => {
|
|
429
|
+
if (
|
|
430
|
+
this.disposed ||
|
|
431
|
+
!this.oversizedToolCallAbortRequested ||
|
|
432
|
+
message.role !== 'assistant' ||
|
|
433
|
+
(message.stopReason !== 'aborted' && message.stopReason !== 'error')
|
|
434
|
+
) {
|
|
435
|
+
return
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
message: {
|
|
439
|
+
...message,
|
|
440
|
+
stopReason: 'error',
|
|
441
|
+
// Pi 按错误文本识别可重试失败,保留其已支持的重试提示。
|
|
442
|
+
errorMessage: `工具参数流超过 ${L4_PI_CHAT_MAX_STREAMING_TOOL_ARGUMENT_CHARS} 字符上限,本次响应中的工具均未执行。Please retry your request.`
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
},
|
|
428
446
|
onTree: () => this.resetBranchRuntime(),
|
|
429
447
|
onCommand: (args, toolCallId) => {
|
|
430
448
|
const signal = this.commandLifetime.signal
|
|
@@ -862,9 +880,8 @@ export class L4PiChatWorker {
|
|
|
862
880
|
this.nativeUi.cancelAll()
|
|
863
881
|
this.discardAcceptedInputs()
|
|
864
882
|
const session = await this.ensureSession()
|
|
865
|
-
|
|
866
|
-
session.
|
|
867
|
-
session.agent.abort()
|
|
883
|
+
this.oversizedToolCallAbortRequested = false
|
|
884
|
+
await session.abort()
|
|
868
885
|
}
|
|
869
886
|
|
|
870
887
|
async navigateTree(entryId: string): Promise<boolean> {
|
|
@@ -1604,9 +1621,9 @@ export class L4PiChatWorker {
|
|
|
1604
1621
|
const oversized = findOversizedStreamingToolCall(message)
|
|
1605
1622
|
if (!oversized) return false
|
|
1606
1623
|
|
|
1607
|
-
if (!this.oversizedToolCallAbortRequested) {
|
|
1624
|
+
if (!this.oversizedToolCallAbortRequested && !this.session?.agent.signal?.aborted) {
|
|
1608
1625
|
this.oversizedToolCallAbortRequested = true
|
|
1609
|
-
console.warn('[Pi Desk][PiChatWorker]
|
|
1626
|
+
console.warn('[Pi Desk][PiChatWorker] 工具参数流过大,已中止当前运行,交由 Pi 重试策略处理', {
|
|
1610
1627
|
sessionId: this.sessionManager.getSessionId(),
|
|
1611
1628
|
toolCallId: oversized.toolCallId,
|
|
1612
1629
|
toolName: oversized.toolName,
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
const L4_PLUGIN_PUSH_MAX_JSON_BYTES = 64 * 1024
|
|
46
46
|
const L4_PLUGIN_LIFECYCLE_TIMEOUT_MS = 1_500
|
|
47
47
|
const L4_PLUGIN_LOAD_TIMEOUT_MS = 15_000
|
|
48
|
+
const L4_PLUGIN_RECOVERY_DELAY_MS = 10_000
|
|
48
49
|
const L4_PLUGIN_BROWSER_TOTAL_BYTES = 128 * 1024 * 1024
|
|
49
50
|
const L4PiPluginPushDataSchema = z.record(z.string(), z.json())
|
|
50
51
|
const L4PiSourceSchema = z
|
|
@@ -153,6 +154,22 @@ class L4PiPluginPhaseError extends Error {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
class L4PiPluginLoadTimeoutError extends L4PiPluginPhaseError {
|
|
158
|
+
constructor(
|
|
159
|
+
phase: L4PiPluginDiagnosticPhase,
|
|
160
|
+
readonly execution: Promise<void>
|
|
161
|
+
) {
|
|
162
|
+
super(phase, new Error('插件加载超时,已停止本次加载'))
|
|
163
|
+
this.name = 'L4PiPluginLoadTimeoutError'
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface L4PiPluginRecovery {
|
|
168
|
+
installedPath: string
|
|
169
|
+
settled: Promise<void>
|
|
170
|
+
controller: AbortController
|
|
171
|
+
}
|
|
172
|
+
|
|
156
173
|
interface L4PiPluginOwner {
|
|
157
174
|
source: string
|
|
158
175
|
packageName: string | null
|
|
@@ -163,6 +180,7 @@ interface L4PiPluginOwner {
|
|
|
163
180
|
pluginNames: Set<string>
|
|
164
181
|
activeCalls: Set<AbortController>
|
|
165
182
|
subscriptions: Set<PluginDisposer>
|
|
183
|
+
pendingCleanup: Set<Promise<void>>
|
|
166
184
|
beforeReload: PiDeskPluginLifecycle['beforeReload'] | null
|
|
167
185
|
disposer: PluginDisposer | null
|
|
168
186
|
}
|
|
@@ -269,11 +287,15 @@ async function runLifecycleWithTimeout(input: {
|
|
|
269
287
|
}): Promise<void> {
|
|
270
288
|
let timer: ReturnType<typeof setTimeout> | null = null
|
|
271
289
|
const timeoutMs = L4_PLUGIN_LIFECYCLE_TIMEOUT_MS
|
|
290
|
+
const execution = Promise.resolve().then(input.execute)
|
|
291
|
+
input.owner.pendingCleanup.add(execution)
|
|
292
|
+
const release = (): void => {
|
|
293
|
+
input.owner.pendingCleanup.delete(execution)
|
|
294
|
+
}
|
|
295
|
+
void execution.then(release, release)
|
|
272
296
|
try {
|
|
273
297
|
const completed = await Promise.race([
|
|
274
|
-
|
|
275
|
-
.then(input.execute)
|
|
276
|
-
.then(() => true),
|
|
298
|
+
execution.then(() => true),
|
|
277
299
|
new Promise<false>((resolveTimeout) => {
|
|
278
300
|
timer = setTimeout(() => resolveTimeout(false), timeoutMs)
|
|
279
301
|
})
|
|
@@ -307,6 +329,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
307
329
|
private readonly maintainingSources = new Set<string>()
|
|
308
330
|
private readonly lifetime = new AbortController()
|
|
309
331
|
private readonly packageDiagnostics = new Map<string, L4PiPluginPackageDiagnostic>()
|
|
332
|
+
private readonly recoveries = new Map<string, L4PiPluginRecovery>()
|
|
310
333
|
private initializePromise: Promise<void> | null = null
|
|
311
334
|
private initialized = false
|
|
312
335
|
private disposed = false
|
|
@@ -386,6 +409,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
386
409
|
) {
|
|
387
410
|
throw new L4PiPluginRuntimeBusyError()
|
|
388
411
|
}
|
|
412
|
+
this.cancelRecovery(source)
|
|
389
413
|
this.maintainingSources.add(source)
|
|
390
414
|
try {
|
|
391
415
|
while (this.owners.some((owner) => owner.source === source && owner.activeCalls.size > 0)) {
|
|
@@ -404,6 +428,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
404
428
|
if (this.disposed || !this.acceptingCalls || this.changingSources.has(source)) {
|
|
405
429
|
throw new L4PiPluginRuntimeBusyError()
|
|
406
430
|
}
|
|
431
|
+
this.cancelRecovery(source)
|
|
407
432
|
const owner = this.owners.find((item) => item.source === source)
|
|
408
433
|
|
|
409
434
|
this.changingSources.add(source)
|
|
@@ -487,6 +512,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
487
512
|
}
|
|
488
513
|
|
|
489
514
|
this.acceptingCalls = false
|
|
515
|
+
for (const source of this.recoveries.keys()) this.cancelRecovery(source)
|
|
490
516
|
for (const owner of this.owners) owner.draining = true
|
|
491
517
|
await Promise.all(
|
|
492
518
|
[...this.owners].reverse().map(async (owner) => {
|
|
@@ -648,6 +674,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
648
674
|
if (this.disposed) return
|
|
649
675
|
this.disposed = true
|
|
650
676
|
this.lifetime.abort()
|
|
677
|
+
for (const source of this.recoveries.keys()) this.cancelRecovery(source)
|
|
651
678
|
this.acceptingCalls = false
|
|
652
679
|
this.changeListeners.clear()
|
|
653
680
|
this.workSessionProvider = null
|
|
@@ -671,7 +698,56 @@ export class L4PiPluginOwnerRuntime {
|
|
|
671
698
|
this.packageDiagnostics.clear()
|
|
672
699
|
for (const item of await this.packageProvider()) {
|
|
673
700
|
if (this.disposed) return
|
|
674
|
-
await this.loadPackage(item.source, item.installedPath)
|
|
701
|
+
const settled = await this.loadPackage(item.source, item.installedPath)
|
|
702
|
+
if (settled && !this.disposed) {
|
|
703
|
+
this.recoveries.set(item.source, {
|
|
704
|
+
installedPath: item.installedPath,
|
|
705
|
+
settled: settled.execution,
|
|
706
|
+
controller: new AbortController()
|
|
707
|
+
})
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
for (const [source, recovery] of this.recoveries) {
|
|
711
|
+
void this.recoverSource(source, recovery)
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
private cancelRecovery(source: string): void {
|
|
716
|
+
const recovery = this.recoveries.get(source)
|
|
717
|
+
this.recoveries.delete(source)
|
|
718
|
+
recovery?.controller.abort()
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
private async recoverSource(source: string, recovery: L4PiPluginRecovery): Promise<void> {
|
|
722
|
+
const signal = recovery.controller.signal
|
|
723
|
+
let onAbort!: () => void
|
|
724
|
+
const canceled = new Promise<never>((_, reject) => {
|
|
725
|
+
onAbort = (): void => reject(signal.reason)
|
|
726
|
+
signal.addEventListener('abort', onAbort, { once: true })
|
|
727
|
+
})
|
|
728
|
+
try {
|
|
729
|
+
// 超时只结束等待;旧 setup 和清理真正结束后才允许自动创建新实例。
|
|
730
|
+
await Promise.race([recovery.settled, canceled])
|
|
731
|
+
signal.throwIfAborted()
|
|
732
|
+
console.info('[Pi Desk][GlobalPluginRuntime] 插件加载超时,稍后自动重试一次', {
|
|
733
|
+
source,
|
|
734
|
+
delayMs: L4_PLUGIN_RECOVERY_DELAY_MS
|
|
735
|
+
})
|
|
736
|
+
await delay(L4_PLUGIN_RECOVERY_DELAY_MS, undefined, { signal })
|
|
737
|
+
signal.throwIfAborted()
|
|
738
|
+
this.recoveries.delete(source)
|
|
739
|
+
await this.replaceSource(source, recovery.installedPath)
|
|
740
|
+
console.info('[Pi Desk][GlobalPluginRuntime] 插件自动重试成功', { source })
|
|
741
|
+
} catch (error) {
|
|
742
|
+
if (!signal.aborted) {
|
|
743
|
+
console.warn('[Pi Desk][GlobalPluginRuntime] 插件自动重试失败,不再自动加载', {
|
|
744
|
+
source,
|
|
745
|
+
message: errorMessage(error)
|
|
746
|
+
})
|
|
747
|
+
}
|
|
748
|
+
} finally {
|
|
749
|
+
signal.removeEventListener('abort', onAbort)
|
|
750
|
+
if (this.recoveries.get(source) === recovery) this.recoveries.delete(source)
|
|
675
751
|
}
|
|
676
752
|
}
|
|
677
753
|
|
|
@@ -681,9 +757,28 @@ export class L4PiPluginOwnerRuntime {
|
|
|
681
757
|
globalInput: unknown
|
|
682
758
|
): Promise<void> {
|
|
683
759
|
let timer: ReturnType<typeof setTimeout> | undefined
|
|
760
|
+
let phase: L4PiPluginDiagnosticPhase = 'entry'
|
|
761
|
+
let phaseStartedAt = performance.now()
|
|
762
|
+
const logPhase = (): void => {
|
|
763
|
+
const durationMs = Math.round(performance.now() - phaseStartedAt)
|
|
764
|
+
if (durationMs < 1_000) return
|
|
765
|
+
console.info('[Pi Desk][GlobalPluginRuntime] 插件加载阶段耗时', {
|
|
766
|
+
source: owner.source,
|
|
767
|
+
packageName: owner.packageName,
|
|
768
|
+
phase,
|
|
769
|
+
durationMs
|
|
770
|
+
})
|
|
771
|
+
}
|
|
772
|
+
const enterPhase = (next: L4PiPluginDiagnosticPhase): void => {
|
|
773
|
+
logPhase()
|
|
774
|
+
phase = next
|
|
775
|
+
phaseStartedAt = performance.now()
|
|
776
|
+
}
|
|
684
777
|
const execution = (async (): Promise<void> => {
|
|
685
|
-
|
|
686
|
-
|
|
778
|
+
const onSetup = (): void => enterPhase('setup')
|
|
779
|
+
if (entryInput !== undefined) await this.loadEntryOwner(owner, entryInput, onSetup)
|
|
780
|
+
else await this.loadLegacyOwner(owner, globalInput, onSetup)
|
|
781
|
+
enterPhase('resources')
|
|
687
782
|
try {
|
|
688
783
|
await this.validateOwnerResources(owner)
|
|
689
784
|
} catch (error) {
|
|
@@ -696,16 +791,20 @@ export class L4PiPluginOwnerRuntime {
|
|
|
696
791
|
execution,
|
|
697
792
|
new Promise<never>((_, reject) => {
|
|
698
793
|
timer = setTimeout(() => {
|
|
699
|
-
reject(new
|
|
794
|
+
reject(new L4PiPluginLoadTimeoutError(phase, execution))
|
|
700
795
|
}, L4_PLUGIN_LOAD_TIMEOUT_MS)
|
|
701
796
|
})
|
|
702
797
|
])
|
|
703
798
|
} finally {
|
|
704
799
|
if (timer) clearTimeout(timer)
|
|
800
|
+
logPhase()
|
|
705
801
|
}
|
|
706
802
|
}
|
|
707
803
|
|
|
708
|
-
private async loadPackage(
|
|
804
|
+
private async loadPackage(
|
|
805
|
+
source: string,
|
|
806
|
+
installedPath: string
|
|
807
|
+
): Promise<{ execution: Promise<void> } | null> {
|
|
709
808
|
const startedAt = performance.now()
|
|
710
809
|
const packageRoot = resolve(installedPath)
|
|
711
810
|
let manifest: L4PiDeskPackageManifest
|
|
@@ -721,13 +820,13 @@ export class L4PiPluginOwnerRuntime {
|
|
|
721
820
|
status: 'failed',
|
|
722
821
|
error: { phase: 'package', message: errorMessage(error) }
|
|
723
822
|
})
|
|
724
|
-
return
|
|
823
|
+
return null
|
|
725
824
|
}
|
|
726
825
|
|
|
727
826
|
const entryInput = manifest.piDesk?.entry
|
|
728
827
|
const globalInput = manifest.piDesk?.global
|
|
729
|
-
if (entryInput === undefined && globalInput === undefined) return
|
|
730
|
-
if (this.disposed) return
|
|
828
|
+
if (entryInput === undefined && globalInput === undefined) return null
|
|
829
|
+
if (this.disposed) return null
|
|
731
830
|
const owner: L4PiPluginOwner = {
|
|
732
831
|
source,
|
|
733
832
|
packageName: typeof manifest.name === 'string' ? manifest.name : null,
|
|
@@ -738,6 +837,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
738
837
|
pluginNames: new Set(),
|
|
739
838
|
activeCalls: new Set(),
|
|
740
839
|
subscriptions: new Set(),
|
|
840
|
+
pendingCleanup: new Set(),
|
|
741
841
|
beforeReload: null,
|
|
742
842
|
disposer: null
|
|
743
843
|
}
|
|
@@ -783,12 +883,26 @@ export class L4PiPluginOwnerRuntime {
|
|
|
783
883
|
message,
|
|
784
884
|
durationMs: Math.round(performance.now() - startedAt)
|
|
785
885
|
})
|
|
886
|
+
if (error instanceof L4PiPluginLoadTimeoutError) {
|
|
887
|
+
return {
|
|
888
|
+
execution: error.execution
|
|
889
|
+
.catch(() => {})
|
|
890
|
+
.then(async () => {
|
|
891
|
+
await Promise.allSettled([...owner.pendingCleanup])
|
|
892
|
+
})
|
|
893
|
+
}
|
|
894
|
+
}
|
|
786
895
|
} finally {
|
|
787
896
|
this.loadingOwners.delete(owner)
|
|
788
897
|
}
|
|
898
|
+
return null
|
|
789
899
|
}
|
|
790
900
|
|
|
791
|
-
private async loadEntryOwner(
|
|
901
|
+
private async loadEntryOwner(
|
|
902
|
+
owner: L4PiPluginOwner,
|
|
903
|
+
entryInput: unknown,
|
|
904
|
+
onSetup: () => void
|
|
905
|
+
): Promise<void> {
|
|
792
906
|
const entryPath = packageEntryPath(owner.packageRoot, entryInput, 'piDesk.entry')
|
|
793
907
|
const entryStat = await stat(entryPath)
|
|
794
908
|
if (!entryStat.isFile()) throw new Error('Pi Desk Plugin entry is not a file')
|
|
@@ -806,6 +920,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
806
920
|
|
|
807
921
|
const pluginName = parseL4PiPluginName(definition.name)
|
|
808
922
|
this.claimPluginName(owner, pluginName)
|
|
923
|
+
onSetup()
|
|
809
924
|
try {
|
|
810
925
|
const lifecycle = normalizeSetupResult(
|
|
811
926
|
await definition.setup(this.createPiDeskFacade(owner, pluginName, owner.packageRoot))
|
|
@@ -821,7 +936,11 @@ export class L4PiPluginOwnerRuntime {
|
|
|
821
936
|
}
|
|
822
937
|
}
|
|
823
938
|
|
|
824
|
-
private async loadLegacyOwner(
|
|
939
|
+
private async loadLegacyOwner(
|
|
940
|
+
owner: L4PiPluginOwner,
|
|
941
|
+
entryInput: unknown,
|
|
942
|
+
onSetup: () => void
|
|
943
|
+
): Promise<void> {
|
|
825
944
|
const entryPath = packageEntryPath(owner.packageRoot, entryInput, 'piDesk.global')
|
|
826
945
|
const entryStat = await stat(entryPath)
|
|
827
946
|
if (!entryStat.isFile()) throw new Error('Global Plugin entry is not a file')
|
|
@@ -832,6 +951,7 @@ export class L4PiPluginOwnerRuntime {
|
|
|
832
951
|
}
|
|
833
952
|
|
|
834
953
|
const factory = loaded.default as GlobalPluginFactory
|
|
954
|
+
onSetup()
|
|
835
955
|
try {
|
|
836
956
|
const disposer = await factory(this.createLegacyApi(owner))
|
|
837
957
|
if (disposer !== undefined && typeof disposer !== 'function') {
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
type ExtensionHandler,
|
|
10
10
|
type InputEvent,
|
|
11
11
|
type InputEventResult,
|
|
12
|
+
type MessageEndEvent,
|
|
13
|
+
type MessageEndEventResult,
|
|
12
14
|
type SessionManager,
|
|
13
15
|
type SessionBeforeTreeEvent
|
|
14
16
|
} from '@earendil-works/pi-coding-agent'
|
|
@@ -40,6 +42,7 @@ interface InitializationOptions {
|
|
|
40
42
|
resources: L4PiSessionResources
|
|
41
43
|
readCapabilities: () => CapabilityMode | undefined
|
|
42
44
|
onInput: ExtensionHandler<InputEvent, InputEventResult>
|
|
45
|
+
onMessageEnd: (event: MessageEndEvent) => MessageEndEventResult | undefined
|
|
43
46
|
onTree?: () => void
|
|
44
47
|
onCommand?: (args: string[], toolCallId: string) => Promise<L4PiDeskCommandResult>
|
|
45
48
|
pluginEvents: ConstructorParameters<typeof L4PiSessionPluginRuntime>[0]
|
|
@@ -296,6 +299,12 @@ export class L4PiSessionInitialization {
|
|
|
296
299
|
this.plugins.reset()
|
|
297
300
|
}
|
|
298
301
|
)
|
|
302
|
+
extension.handlers.set('message_end', [
|
|
303
|
+
async (event) => {
|
|
304
|
+
this.assertActive()
|
|
305
|
+
return this.options.onMessageEnd(event as MessageEndEvent)
|
|
306
|
+
}
|
|
307
|
+
])
|
|
299
308
|
extension.handlers.set('session_tree', [async () => this.options.onTree?.()])
|
|
300
309
|
extension.handlers.set('session_before_tree', [
|
|
301
310
|
async (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
MV6_lBt7Mzmi1rBNI-3dx
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"/api/work-sessions/replace/route": "/api/work-sessions/replace",
|
|
71
71
|
"/api/work-sessions/sort/route": "/api/work-sessions/sort",
|
|
72
72
|
"/favicon.ico/route": "/favicon.ico",
|
|
73
|
-
"/page": "/",
|
|
74
|
-
"/login/page": "/login"
|
|
73
|
+
"/project-preview/page": "/project-preview",
|
|
74
|
+
"/login/page": "/login",
|
|
75
|
+
"/page": "/"
|
|
75
76
|
}
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
],
|
|
5
5
|
"devFiles": [],
|
|
6
6
|
"lowPriorityFiles": [
|
|
7
|
-
"static/
|
|
8
|
-
"static/
|
|
7
|
+
"static/MV6_lBt7Mzmi1rBNI-3dx/_buildManifest.js",
|
|
8
|
+
"static/MV6_lBt7Mzmi1rBNI-3dx/_ssgManifest.js"
|
|
9
9
|
],
|
|
10
10
|
"rootMainFiles": [
|
|
11
|
-
"static/chunks/webpack-
|
|
11
|
+
"static/chunks/webpack-b60891a214e0925d.js",
|
|
12
12
|
"static/chunks/e388c842-1ca92f1ea0dfe8ee.js",
|
|
13
13
|
"static/chunks/64444-3e955f910569274d.js",
|
|
14
14
|
"static/chunks/main-app-6230945a5a062fce.js"
|
|
@@ -2610,8 +2610,7 @@
|
|
|
2610
2610
|
"client/l2_biz/workbench/file-workspace/l2-work-session-file-layout.tsx -> ./l2-file-workspace-view": {
|
|
2611
2611
|
"id": 19991,
|
|
2612
2612
|
"files": [
|
|
2613
|
-
"static/chunks/
|
|
2614
|
-
"static/chunks/70669.07f3670bfb7d6dd2.js"
|
|
2613
|
+
"static/chunks/19991.8aa2e4b6df15fad6.js"
|
|
2615
2614
|
]
|
|
2616
2615
|
},
|
|
2617
2616
|
"client/l4_foundation/terminal/l4-terminal-renderer.ts -> @xterm/addon-fit": {
|
|
@@ -2,8 +2,8 @@ self.__SERVER_FILES_MANIFEST={
|
|
|
2
2
|
"version": 1,
|
|
3
3
|
"config": {
|
|
4
4
|
"env": {
|
|
5
|
-
"PI_DESK_APP_VERSION": "1.1.
|
|
6
|
-
"PI_DESK_VERSION_UPDATED_AT": "2026-10-
|
|
5
|
+
"PI_DESK_APP_VERSION": "1.1.22-dev",
|
|
6
|
+
"PI_DESK_VERSION_UPDATED_AT": "2026-10-27T09:27:15+08:00"
|
|
7
7
|
},
|
|
8
8
|
"webpack": null,
|
|
9
9
|
"typescript": {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"version": 1,
|
|
3
3
|
"config": {
|
|
4
4
|
"env": {
|
|
5
|
-
"PI_DESK_APP_VERSION": "1.1.
|
|
6
|
-
"PI_DESK_VERSION_UPDATED_AT": "2026-10-
|
|
5
|
+
"PI_DESK_APP_VERSION": "1.1.22-dev",
|
|
6
|
+
"PI_DESK_VERSION_UPDATED_AT": "2026-10-27T09:27:15+08:00"
|
|
7
7
|
},
|
|
8
8
|
"webpack": null,
|
|
9
9
|
"typescript": {
|
|
@@ -467,6 +467,12 @@
|
|
|
467
467
|
"regex": "^/login(?:/)?$",
|
|
468
468
|
"routeKeys": {},
|
|
469
469
|
"namedRegex": "^/login(?:/)?$"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
"page": "/project-preview",
|
|
473
|
+
"regex": "^/project\\-preview(?:/)?$",
|
|
474
|
+
"routeKeys": {},
|
|
475
|
+
"namedRegex": "^/project\\-preview(?:/)?$"
|
|
470
476
|
}
|
|
471
477
|
],
|
|
472
478
|
"dataRoutes": [],
|
|
@@ -28,4 +28,4 @@
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }
|
|
31
|
-
`.replace(/\n\s*/g,"");function i(){return(0,f.jsx)("svg",{width:"32",height:"32",viewBox:"-0.2 -1.5 32 32",fill:"none",style:g.icon,children:(0,f.jsx)("path",{d:"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z",fill:"var(--next-error-title)"})})}("function"==typeof b.default||"object"==typeof b.default&&null!==b.default)&&void 0===b.default.__esModule&&(Object.defineProperty(b.default,"__esModule",{value:!0}),Object.assign(b.default,b),a.exports=b.default)},28354:a=>{"use strict";a.exports=require("util")},
|
|
31
|
+
`.replace(/\n\s*/g,"");function i(){return(0,f.jsx)("svg",{width:"32",height:"32",viewBox:"-0.2 -1.5 32 32",fill:"none",style:g.icon,children:(0,f.jsx)("path",{d:"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z",fill:"var(--next-error-title)"})})}("function"==typeof b.default||"object"==typeof b.default&&null!==b.default)&&void 0===b.default.__esModule&&(Object.defineProperty(b.default,"__esModule",{value:!0}),Object.assign(b.default,b),a.exports=b.default)},28354:a=>{"use strict";a.exports=require("util")},29294:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-async-storage.external.js")},30897:(a,b,c)=>{Promise.resolve().then(c.t.bind(c,17179,23)),Promise.resolve().then(c.t.bind(c,39159,23)),Promise.resolve().then(c.t.bind(c,52442,23)),Promise.resolve().then(c.t.bind(c,270,23)),Promise.resolve().then(c.t.bind(c,47594,23)),Promise.resolve().then(c.t.bind(c,52047,23)),Promise.resolve().then(c.t.bind(c,7770,23))},31326:(a,b,c)=>{"use strict";Object.defineProperty(b,"__esModule",{value:!0}),Object.defineProperty(b,"default",{enumerable:!0,get:function(){return f}}),c(9812);let d=c(89564);c(76549);let e=c(26011),f=function(){return(0,d.jsxs)("html",{id:"__next_error__",children:[(0,d.jsxs)("head",{children:[(0,d.jsx)("title",{children:"500: This page couldn’t load"}),(0,d.jsx)("style",{dangerouslySetInnerHTML:{__html:e.errorThemeCss}})]}),(0,d.jsx)("body",{children:(0,d.jsx)("div",{style:e.errorStyles.container,children:(0,d.jsxs)("div",{style:e.errorStyles.card,children:[(0,d.jsx)(e.WarningIcon,{}),(0,d.jsx)("h1",{style:e.errorStyles.title,children:"This page couldn’t load"}),(0,d.jsx)("p",{style:e.errorStyles.message,children:"A server error occurred. Reload to try again."}),(0,d.jsx)("form",{style:e.errorStyles.form,children:(0,d.jsx)("button",{type:"submit",style:e.errorStyles.button,children:"Reload"})})]})})})]})};("function"==typeof b.default||"object"==typeof b.default&&null!==b.default)&&void 0===b.default.__esModule&&(Object.defineProperty(b.default,"__esModule",{value:!0}),Object.assign(b.default,b),a.exports=b.default)},33873:a=>{"use strict";a.exports=require("path")},35166:()=>{},37957:(a,b,c)=>{Promise.resolve().then(c.bind(c,56951))},38522:a=>{"use strict";a.exports=require("node:zlib")},40217:(a,b,c)=>{Promise.resolve().then(c.bind(c,70961))},41025:a=>{"use strict";a.exports=require("next/dist/server/app-render/dynamic-access-async-storage.external.js")},43305:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>f});var d=c(52834);c(49147);var e=c(4527);function f({error:a,reset:b}){return(0,d.jsx)(e.L1ErrorPage,{retry:b})}},46060:a=>{"use strict";a.exports=require("next/dist/shared/lib/no-fallback-error.external.js")},56951:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>d});let d=(0,c(68032).registerClientReference)(function(){throw Error("Attempted to call the default export of \"/home/runner/work/pi-desk/pi-desk/src/app/error.tsx\" from the server, but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/home/runner/work/pi-desk/pi-desk/src/app/error.tsx","default")},63033:a=>{"use strict";a.exports=require("next/dist/server/app-render/work-unit-async-storage.external.js")},70961:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>d});let d=(0,c(68032).registerClientReference)(function(){throw Error("Attempted to call the default export of \"/home/runner/work/pi-desk/pi-desk/src/app/global-error.tsx\" from the server, but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/home/runner/work/pi-desk/pi-desk/src/app/global-error.tsx","default")},74405:(a,b,c)=>{Promise.resolve().then(c.bind(c,43305))},76665:(a,b,c)=>{Promise.resolve().then(c.bind(c,21147))},82117:(a,b,c)=>{"use strict";c.r(b),c.d(b,{default:()=>f});var d=c(89564),e=c(88893);function f(){return(0,d.jsx)(e.L1ErrorPage,{notFound:!0})}},88893:(a,b,c)=>{"use strict";c.d(b,{L1ErrorPage:()=>d});let d=(0,c(68032).registerClientReference)(function(){throw Error("Attempted to call L1ErrorPage() from the server but L1ErrorPage is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"/home/runner/work/pi-desk/pi-desk/src/client/l1_entry/pages/l1-error-page.tsx","L1ErrorPage")},93822:(a,b,c)=>{"use strict";c.r(b),c.d(b,{__next_app__:()=>k,handler:()=>m,routeModule:()=>l});var d=c(85426),e=c(3372),f=c(2629),g=c(86804),h={};for(let a in g)0>["default","__next_app__","routeModule","handler"].indexOf(a)&&(h[a]=()=>g[a]);c.d(b,h);let i={children:["",{children:["_global-error",{children:["__PAGE__",{},{page:[(0,d.p)(()=>Promise.resolve().then(c.t.bind(c,31326,23))),"next/dist/client/components/builtin/app-error.js"]}]},{}]},{error:[(0,d.p)(()=>Promise.resolve().then(c.bind(c,56951))),"/home/runner/work/pi-desk/pi-desk/src/app/error.tsx"],"global-error":[(0,d.p)(()=>Promise.resolve().then(c.bind(c,70961))),"/home/runner/work/pi-desk/pi-desk/src/app/global-error.tsx"],"not-found":[(0,d.p)(()=>Promise.resolve().then(c.bind(c,82117))),"/home/runner/work/pi-desk/pi-desk/src/app/not-found.tsx"],forbidden:[(0,d.p)(()=>Promise.resolve().then(c.t.bind(c,10719,23))),"next/dist/client/components/builtin/forbidden.js"],unauthorized:[(0,d.p)(()=>Promise.resolve().then(c.t.bind(c,58434,23))),"next/dist/client/components/builtin/unauthorized.js"]},[]]}.children,j=(0,e.H)({tree:i,page:"/_global-error/page",pathname:"/_global-error",require:c,loadChunk:()=>Promise.resolve(),interopDefault:f.T}),k=j.__next_app__,l=j.routeModule,m=j.handler},99883:(a,b,c)=>{Promise.resolve().then(c.bind(c,4527))}};var b=require("../../webpack-runtime.js");b.C(a);var c=b.X(0,[43416,9874],()=>b(b.s=93822));module.exports=c})();
|