@vincenthanxiaodu/pi-web 1.202608.1
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/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/cli.js +1149 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/apple-touch-icon.png +0 -0
- package/dist/client/assets/CodeViewer-D_Q6ljLV.js +4 -0
- package/dist/client/assets/TerminalPanel-CTGixJIz.js +187 -0
- package/dist/client/assets/index-C2phil_t.js +5637 -0
- package/dist/client/assets/vendor-editor-core-CXO8gGab.js +12 -0
- package/dist/client/assets/vendor-editor-languages-CpW4sJsX.js +46 -0
- package/dist/client/assets/vendor-editor-legacy-CYBnW6ZU.js +1 -0
- package/dist/client/assets/vendor-terminal-BrP-ENHg.css +1 -0
- package/dist/client/assets/vendor-terminal-D8k4UKM2.js +35 -0
- package/dist/client/favicon.svg +11 -0
- package/dist/client/index.html +124 -0
- package/dist/client/manifest.webmanifest +24 -0
- package/dist/client/pwa-icon-192.png +0 -0
- package/dist/client/pwa-icon-512.png +0 -0
- package/dist/config.js +505 -0
- package/dist/config.js.map +1 -0
- package/dist/docker/piWebDockerCommandPlan.js +212 -0
- package/dist/docker/piWebDockerCommandPlan.js.map +1 -0
- package/dist/environment.js +4 -0
- package/dist/environment.js.map +1 -0
- package/dist/nativeServices/installedServiceDefinitions.js +602 -0
- package/dist/nativeServices/installedServiceDefinitions.js.map +1 -0
- package/dist/nativeServices/serviceAction.js +174 -0
- package/dist/nativeServices/serviceAction.js.map +1 -0
- package/dist/nativeServices/serviceDoctor.js +783 -0
- package/dist/nativeServices/serviceDoctor.js.map +1 -0
- package/dist/nativeServices/serviceInstall.js +35 -0
- package/dist/nativeServices/serviceInstall.js.map +1 -0
- package/dist/nativeServices/servicePlan.js +358 -0
- package/dist/nativeServices/servicePlan.js.map +1 -0
- package/dist/nativeServices/serviceProbe.js +447 -0
- package/dist/nativeServices/serviceProbe.js.map +1 -0
- package/dist/nativeServices/serviceRendering.js +132 -0
- package/dist/nativeServices/serviceRendering.js.map +1 -0
- package/dist/pi-web-plugins/git/browser/git-contract.js +108 -0
- package/dist/pi-web-plugins/git/browser/git-panel.js +609 -0
- package/dist/pi-web-plugins/git/browser/gitFileList.js +43 -0
- package/dist/pi-web-plugins/git/browser/gitFileShared.js +16 -0
- package/dist/pi-web-plugins/git/browser/gitFileTree.js +81 -0
- package/dist/pi-web-plugins/git/browser/gitFileViewPreference.js +35 -0
- package/dist/pi-web-plugins/git/browser/gitRoute.js +42 -0
- package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +10 -0
- package/dist/pi-web-plugins/git/browser/unifiedDiff.js +301 -0
- package/dist/pi-web-plugins/git/git-backend.js +439 -0
- package/dist/pi-web-plugins/git/package.json +16 -0
- package/dist/pi-web-plugins/git/server-plugin.js +176 -0
- package/dist/pi-web-plugins/info/infoInternals.js +222 -0
- package/dist/pi-web-plugins/info/package.json +9 -0
- package/dist/pi-web-plugins/info/pi-web-plugin.js +48 -0
- package/dist/pi-web-plugins/relays/markdownDocument.js +81 -0
- package/dist/pi-web-plugins/relays/package.json +9 -0
- package/dist/pi-web-plugins/relays/pi-web-plugin.js +44 -0
- package/dist/pi-web-plugins/relays/relayDiscovery.js +228 -0
- package/dist/pi-web-plugins/relays/relaysPanelElement.js +550 -0
- package/dist/pi-web-plugins/relays/vendor/README.md +24 -0
- package/dist/pi-web-plugins/relays/vendor/marked.esm.js +76 -0
- package/dist/pi-web-plugins/updates/package.json +9 -0
- package/dist/pi-web-plugins/updates/pi-web-plugin.js +185 -0
- package/dist/pi-web-plugins/updates/updatesLogic.js +97 -0
- package/dist/pi-web-plugins/workspace-tasks/config.js +91 -0
- package/dist/pi-web-plugins/workspace-tasks/package.json +9 -0
- package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +48 -0
- package/dist/pi-web-plugins/workspace-tasks/taskRunner.js +12 -0
- package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +288 -0
- package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +47 -0
- package/dist/piWebVersionReport.js +278 -0
- package/dist/piWebVersionReport.js.map +1 -0
- package/dist/plugin-api.d.ts +222 -0
- package/dist/pluginRecoveryCli.js +172 -0
- package/dist/pluginRecoveryCli.js.map +1 -0
- package/dist/server/activeAgentProfileProvider.js +25 -0
- package/dist/server/activeAgentProfileProvider.js.map +1 -0
- package/dist/server/activity/workspaceActivityService.js +106 -0
- package/dist/server/activity/workspaceActivityService.js.map +1 -0
- package/dist/server/app.js +218 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/browserMessageProjection.js +54 -0
- package/dist/server/browserMessageProjection.js.map +1 -0
- package/dist/server/configRoutes.js +293 -0
- package/dist/server/configRoutes.js.map +1 -0
- package/dist/server/diagnostics/nodePtyNativeModule.js +36 -0
- package/dist/server/diagnostics/nodePtyNativeModule.js.map +1 -0
- package/dist/server/diagnostics/nodePtySpawnHelper.js +135 -0
- package/dist/server/diagnostics/nodePtySpawnHelper.js.map +1 -0
- package/dist/server/git/gitEnv.js +15 -0
- package/dist/server/git/gitEnv.js.map +1 -0
- package/dist/server/goals/goalArchive.js +184 -0
- package/dist/server/goals/goalArchive.js.map +1 -0
- package/dist/server/goals/goalFile.js +200 -0
- package/dist/server/goals/goalFile.js.map +1 -0
- package/dist/server/goals/goalStore.js +65 -0
- package/dist/server/goals/goalStore.js.map +1 -0
- package/dist/server/index.js +7 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/machines/machineClient.js +191 -0
- package/dist/server/machines/machineClient.js.map +1 -0
- package/dist/server/machines/machinePluginProxyRoutes.js +247 -0
- package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
- package/dist/server/machines/machineProxyRoutes.js +318 -0
- package/dist/server/machines/machineProxyRoutes.js.map +1 -0
- package/dist/server/machines/machineRoutes.js +56 -0
- package/dist/server/machines/machineRoutes.js.map +1 -0
- package/dist/server/machines/machineService.js +274 -0
- package/dist/server/machines/machineService.js.map +1 -0
- package/dist/server/machines/machineStore.js +143 -0
- package/dist/server/machines/machineStore.js.map +1 -0
- package/dist/server/piPackageRoutes.js +91 -0
- package/dist/server/piPackageRoutes.js.map +1 -0
- package/dist/server/piPackageService.js +101 -0
- package/dist/server/piPackageService.js.map +1 -0
- package/dist/server/piWebPluginCatalog.js +584 -0
- package/dist/server/piWebPluginCatalog.js.map +1 -0
- package/dist/server/piWebPluginLifecycle.js +162 -0
- package/dist/server/piWebPluginLifecycle.js.map +1 -0
- package/dist/server/piWebPluginService.js +224 -0
- package/dist/server/piWebPluginService.js.map +1 -0
- package/dist/server/piWebReleaseLookupCache.js +37 -0
- package/dist/server/piWebReleaseLookupCache.js.map +1 -0
- package/dist/server/piWebStatus.js +624 -0
- package/dist/server/piWebStatus.js.map +1 -0
- package/dist/server/piWebStatusCache.js +45 -0
- package/dist/server/piWebStatusCache.js.map +1 -0
- package/dist/server/plugins/pluginBackendProxyRoutes.js +69 -0
- package/dist/server/plugins/pluginBackendProxyRoutes.js.map +1 -0
- package/dist/server/plugins/serverPluginExec.js +184 -0
- package/dist/server/plugins/serverPluginExec.js.map +1 -0
- package/dist/server/plugins/serverPluginRuntime.js +480 -0
- package/dist/server/plugins/serverPluginRuntime.js.map +1 -0
- package/dist/server/projectTrustRoutes.js +80 -0
- package/dist/server/projectTrustRoutes.js.map +1 -0
- package/dist/server/projects/directorySuggestions.js +207 -0
- package/dist/server/projects/directorySuggestions.js.map +1 -0
- package/dist/server/projects/projectService.js +33 -0
- package/dist/server/projects/projectService.js.map +1 -0
- package/dist/server/realtime/sessionEventHub.js +93 -0
- package/dist/server/realtime/sessionEventHub.js.map +1 -0
- package/dist/server/requestCancellation.js +32 -0
- package/dist/server/requestCancellation.js.map +1 -0
- package/dist/server/sessiond/agentHttpDispatcher.js +108 -0
- package/dist/server/sessiond/agentHttpDispatcher.js.map +1 -0
- package/dist/server/sessiond/agentProcessEnvironment.js +61 -0
- package/dist/server/sessiond/agentProcessEnvironment.js.map +1 -0
- package/dist/server/sessiond/pluginBackendRoutes.js +64 -0
- package/dist/server/sessiond/pluginBackendRoutes.js.map +1 -0
- package/dist/server/sessiond/sessionDaemonShutdown.js +31 -0
- package/dist/server/sessiond/sessionDaemonShutdown.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +61 -0
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -0
- package/dist/server/sessiond/sessionServiceDependencies.js +34 -0
- package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -0
- package/dist/server/sessiond/sessiondStateOwnership.js +235 -0
- package/dist/server/sessiond/sessiondStateOwnership.js.map +1 -0
- package/dist/server/sessiond/workspaceCatalogRoutes.js +31 -0
- package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -0
- package/dist/server/sessiond/workspaceRemovalRoutes.js +41 -0
- package/dist/server/sessiond/workspaceRemovalRoutes.js.map +1 -0
- package/dist/server/sessiond.js +387 -0
- package/dist/server/sessiond.js.map +1 -0
- package/dist/server/sessions/askUserTool.js +102 -0
- package/dist/server/sessions/askUserTool.js.map +1 -0
- package/dist/server/sessions/attachmentService.js +119 -0
- package/dist/server/sessions/attachmentService.js.map +1 -0
- package/dist/server/sessions/authProviderOptions.js +50 -0
- package/dist/server/sessions/authProviderOptions.js.map +1 -0
- package/dist/server/sessions/authRoutes.js +59 -0
- package/dist/server/sessions/authRoutes.js.map +1 -0
- package/dist/server/sessions/authService.js +122 -0
- package/dist/server/sessions/authService.js.map +1 -0
- package/dist/server/sessions/builtinCommands.js +27 -0
- package/dist/server/sessions/builtinCommands.js.map +1 -0
- package/dist/server/sessions/dockerEnvironmentFacts.js +254 -0
- package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -0
- package/dist/server/sessions/editPreview.js +196 -0
- package/dist/server/sessions/editPreview.js.map +1 -0
- package/dist/server/sessions/extensionDialogWaiters.js +76 -0
- package/dist/server/sessions/extensionDialogWaiters.js.map +1 -0
- package/dist/server/sessions/globalProviderPolicy.js +167 -0
- package/dist/server/sessions/globalProviderPolicy.js.map +1 -0
- package/dist/server/sessions/interruptedRunStore.js +147 -0
- package/dist/server/sessions/interruptedRunStore.js.map +1 -0
- package/dist/server/sessions/messagePaging.js +43 -0
- package/dist/server/sessions/messagePaging.js.map +1 -0
- package/dist/server/sessions/modelCatalogRefresher.js +193 -0
- package/dist/server/sessions/modelCatalogRefresher.js.map +1 -0
- package/dist/server/sessions/oauthLoginFlowService.js +346 -0
- package/dist/server/sessions/oauthLoginFlowService.js.map +1 -0
- package/dist/server/sessions/pendingAskStore.js +275 -0
- package/dist/server/sessions/pendingAskStore.js.map +1 -0
- package/dist/server/sessions/pendingExtensionDialogStore.js +196 -0
- package/dist/server/sessions/pendingExtensionDialogStore.js.map +1 -0
- package/dist/server/sessions/piSessionManagerGateway.js +246 -0
- package/dist/server/sessions/piSessionManagerGateway.js.map +1 -0
- package/dist/server/sessions/piSessionService.js +4059 -0
- package/dist/server/sessions/piSessionService.js.map +1 -0
- package/dist/server/sessions/plainTextTheme.js +112 -0
- package/dist/server/sessions/plainTextTheme.js.map +1 -0
- package/dist/server/sessions/sessionArchiveStore.js +273 -0
- package/dist/server/sessions/sessionArchiveStore.js.map +1 -0
- package/dist/server/sessions/sessionArchiveTree.js +35 -0
- package/dist/server/sessions/sessionArchiveTree.js.map +1 -0
- package/dist/server/sessions/sessionCleanup.js +157 -0
- package/dist/server/sessions/sessionCleanup.js.map +1 -0
- package/dist/server/sessions/sessionCommandService.js +336 -0
- package/dist/server/sessions/sessionCommandService.js.map +1 -0
- package/dist/server/sessions/sessionEnvironmentFacts.js +48 -0
- package/dist/server/sessions/sessionEnvironmentFacts.js.map +1 -0
- package/dist/server/sessions/sessionFileFormat.js +27 -0
- package/dist/server/sessions/sessionFileFormat.js.map +1 -0
- package/dist/server/sessions/sessionFileHeader.js +104 -0
- package/dist/server/sessions/sessionFileHeader.js.map +1 -0
- package/dist/server/sessions/sessionModelScope.js +141 -0
- package/dist/server/sessions/sessionModelScope.js.map +1 -0
- package/dist/server/sessions/sessionNameGenerator.js +90 -0
- package/dist/server/sessions/sessionNameGenerator.js.map +1 -0
- package/dist/server/sessions/sessionNotificationStore.js +484 -0
- package/dist/server/sessions/sessionNotificationStore.js.map +1 -0
- package/dist/server/sessions/sessionRoutes.js +744 -0
- package/dist/server/sessions/sessionRoutes.js.map +1 -0
- package/dist/server/sessions/sessionRuntimeStore.js +2 -0
- package/dist/server/sessions/sessionRuntimeStore.js.map +1 -0
- package/dist/server/sessions/sessionService.js +2 -0
- package/dist/server/sessions/sessionService.js.map +1 -0
- package/dist/server/sessions/sessionSummaryScanner.js +491 -0
- package/dist/server/sessions/sessionSummaryScanner.js.map +1 -0
- package/dist/server/sessions/sessionTreeProjection.js +250 -0
- package/dist/server/sessions/sessionTreeProjection.js.map +1 -0
- package/dist/server/sessions/sessionUnreadStore.js +520 -0
- package/dist/server/sessions/sessionUnreadStore.js.map +1 -0
- package/dist/server/sessions/shutdownDrain.js +73 -0
- package/dist/server/sessions/shutdownDrain.js.map +1 -0
- package/dist/server/sessions/spawnSessionTool.js +48 -0
- package/dist/server/sessions/spawnSessionTool.js.map +1 -0
- package/dist/server/sessions/spawnSubsessionTool.js +216 -0
- package/dist/server/sessions/spawnSubsessionTool.js.map +1 -0
- package/dist/server/sessions/spawnTargetResolver.js +23 -0
- package/dist/server/sessions/spawnTargetResolver.js.map +1 -0
- package/dist/server/sessions/subsessionTranscript.js +235 -0
- package/dist/server/sessions/subsessionTranscript.js.map +1 -0
- package/dist/server/status/machineStatusRoutes.js +8 -0
- package/dist/server/status/machineStatusRoutes.js.map +1 -0
- package/dist/server/status/machineStatusService.js +181 -0
- package/dist/server/status/machineStatusService.js.map +1 -0
- package/dist/server/status/workspaceAttribution.js +87 -0
- package/dist/server/status/workspaceAttribution.js.map +1 -0
- package/dist/server/storage/projectStore.js +88 -0
- package/dist/server/storage/projectStore.js.map +1 -0
- package/dist/server/terminalProxyRoutes.js +141 -0
- package/dist/server/terminalProxyRoutes.js.map +1 -0
- package/dist/server/terminals/terminalRoutes.js +155 -0
- package/dist/server/terminals/terminalRoutes.js.map +1 -0
- package/dist/server/terminals/terminalService.js +305 -0
- package/dist/server/terminals/terminalService.js.map +1 -0
- package/dist/server/terminals/terminalSize.js +17 -0
- package/dist/server/terminals/terminalSize.js.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/updates/fleetRoutes.js +111 -0
- package/dist/server/updates/fleetRoutes.js.map +1 -0
- package/dist/server/updates/restartRoutes.js +48 -0
- package/dist/server/updates/restartRoutes.js.map +1 -0
- package/dist/server/updates/selfUpdateRoutes.js +145 -0
- package/dist/server/updates/selfUpdateRoutes.js.map +1 -0
- package/dist/server/webSocketBridge.js +32 -0
- package/dist/server/webSocketBridge.js.map +1 -0
- package/dist/server/workingDirectory.js +44 -0
- package/dist/server/workingDirectory.js.map +1 -0
- package/dist/server/workspaceExplorerRoutes.js +147 -0
- package/dist/server/workspaceExplorerRoutes.js.map +1 -0
- package/dist/server/workspaces/effectivePathAccess.js +8 -0
- package/dist/server/workspaces/effectivePathAccess.js.map +1 -0
- package/dist/server/workspaces/fileContentService.js +190 -0
- package/dist/server/workspaces/fileContentService.js.map +1 -0
- package/dist/server/workspaces/filePreviewResponseHeaders.js +18 -0
- package/dist/server/workspaces/filePreviewResponseHeaders.js.map +1 -0
- package/dist/server/workspaces/filePreviewResponsePolicy.js +55 -0
- package/dist/server/workspaces/filePreviewResponsePolicy.js.map +1 -0
- package/dist/server/workspaces/filePreviewService.js +81 -0
- package/dist/server/workspaces/filePreviewService.js.map +1 -0
- package/dist/server/workspaces/fileSuggestions.js +520 -0
- package/dist/server/workspaces/fileSuggestions.js.map +1 -0
- package/dist/server/workspaces/fileTreeService.js +35 -0
- package/dist/server/workspaces/fileTreeService.js.map +1 -0
- package/dist/server/workspaces/pathAccessPolicy.js +90 -0
- package/dist/server/workspaces/pathAccessPolicy.js.map +1 -0
- package/dist/server/workspaces/pathSafety.js +45 -0
- package/dist/server/workspaces/pathSafety.js.map +1 -0
- package/dist/server/workspaces/projectPiWebConfig.js +61 -0
- package/dist/server/workspaces/projectPiWebConfig.js.map +1 -0
- package/dist/server/workspaces/projectWorkspaceCwds.js +17 -0
- package/dist/server/workspaces/projectWorkspaceCwds.js.map +1 -0
- package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +402 -0
- package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -0
- package/dist/server/workspaces/workspaceCatalog.js +47 -0
- package/dist/server/workspaces/workspaceCatalog.js.map +1 -0
- package/dist/server/workspaces/workspaceContext.js +6 -0
- package/dist/server/workspaces/workspaceContext.js.map +1 -0
- package/dist/server/workspaces/workspaceDeletionRoutes.js +49 -0
- package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
- package/dist/server/workspaces/workspaceProviderRegistry.js +651 -0
- package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -0
- package/dist/server/workspaces/workspaceRemovalService.js +256 -0
- package/dist/server/workspaces/workspaceRemovalService.js.map +1 -0
- package/dist/server/workspaces/workspaceRouteErrors.js +7 -0
- package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -0
- package/dist/server/workspaces/worktreePreRemoveHook.js +39 -0
- package/dist/server/workspaces/worktreePreRemoveHook.js.map +1 -0
- package/dist/server-plugin-api.d.ts +140 -0
- package/dist/server-plugin-api.js +2 -0
- package/dist/server-plugin-api.js.map +1 -0
- package/dist/serverPluginRecovery.js +138 -0
- package/dist/serverPluginRecovery.js.map +1 -0
- package/dist/sessiond/activeAgentProfile.js +12 -0
- package/dist/sessiond/activeAgentProfile.js.map +1 -0
- package/dist/sessiond/config.js +20 -0
- package/dist/sessiond/config.js.map +1 -0
- package/dist/sessiond/sessionDaemonClient.js +105 -0
- package/dist/sessiond/sessionDaemonClient.js.map +1 -0
- package/dist/shared/activeAgentProfile.js +37 -0
- package/dist/shared/activeAgentProfile.js.map +1 -0
- package/dist/shared/activity.js +16 -0
- package/dist/shared/activity.js.map +1 -0
- package/dist/shared/apiTypes.js +41 -0
- package/dist/shared/apiTypes.js.map +1 -0
- package/dist/shared/capabilities.js +37 -0
- package/dist/shared/capabilities.js.map +1 -0
- package/dist/shared/federatedRoutes.js +127 -0
- package/dist/shared/federatedRoutes.js.map +1 -0
- package/dist/shared/machinePluginIds.js +43 -0
- package/dist/shared/machinePluginIds.js.map +1 -0
- package/dist/shared/machineStatus.js +94 -0
- package/dist/shared/machineStatus.js.map +1 -0
- package/dist/shared/piWebStatusParsing.js +141 -0
- package/dist/shared/piWebStatusParsing.js.map +1 -0
- package/dist/shared/pluginApiTypes.d.ts +150 -0
- package/dist/shared/pluginApiTypes.js +3 -0
- package/dist/shared/pluginApiTypes.js.map +1 -0
- package/dist/shared/pluginBackendProtocol.js +110 -0
- package/dist/shared/pluginBackendProtocol.js.map +1 -0
- package/dist/shared/pluginIds.js +10 -0
- package/dist/shared/pluginIds.js.map +1 -0
- package/dist/shared/pluginRecoveryCommands.js +14 -0
- package/dist/shared/pluginRecoveryCommands.js.map +1 -0
- package/dist/shared/promptAttachments.js +92 -0
- package/dist/shared/promptAttachments.js.map +1 -0
- package/dist/shared/selfUpdate.js +3 -0
- package/dist/shared/selfUpdate.js.map +1 -0
- package/dist/shared/thinkingLevels.js +31 -0
- package/dist/shared/thinkingLevels.js.map +1 -0
- package/dist/shared/workspaceDeletion.js +12 -0
- package/dist/shared/workspaceDeletion.js.map +1 -0
- package/dist/shared/workspaceFiles.js +42 -0
- package/dist/shared/workspaceFiles.js.map +1 -0
- package/dist/shared/workspaceRemovalProtocol.js +24 -0
- package/dist/shared/workspaceRemovalProtocol.js.map +1 -0
- package/docs/assets/favicon.svg +11 -0
- package/docs/assets/pi-web-banner.png +0 -0
- package/docs/assets/pi-web-desktop.png +0 -0
- package/docs/assets/pi-web-mobile.png +0 -0
- package/docs/assets/pi-web-tablet.png +0 -0
- package/docs/config.md +444 -0
- package/docs/plugins.md +1305 -0
- package/examples/workspace-provider-plugin/README.md +52 -0
- package/examples/workspace-provider-plugin/package.json +25 -0
- package/examples/workspace-provider-plugin/src/browser/index.ts +69 -0
- package/examples/workspace-provider-plugin/src/server.ts +64 -0
- package/examples/workspace-provider-plugin/tsconfig.json +21 -0
- package/extensions/README-pi-web-restart-migration.md +45 -0
- package/extensions/pi-web.ts +324 -0
- package/install.sh +5 -0
- package/package.json +173 -0
- package/plugin-api.d.ts +1 -0
- package/server-plugin-api.d.ts +1 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { realpath, stat } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { isAbsolute, relative, resolve, sep, win32 } from "node:path";
|
|
4
|
+
import { normalizeRelativePath } from "./pathSafety.js";
|
|
5
|
+
export async function createPathAccessPolicy(workspaceRootPath, pathAccess, options = {}) {
|
|
6
|
+
return {
|
|
7
|
+
workspaceRoot: await canonicalDirectory(workspaceRootPath, "Workspace path"),
|
|
8
|
+
allowedRoots: await resolveAllowedRoots(pathAccess?.allowedPaths ?? [], options),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export async function resolveWorkspacePathAccessTarget(rootPath, requestedPath, pathAccess, options = {}) {
|
|
12
|
+
const request = requestedPath ?? "";
|
|
13
|
+
const workspaceRoot = await canonicalDirectory(rootPath, "Workspace path");
|
|
14
|
+
const allowedRoots = isAbsoluteishPath(request) ? await resolveAllowedRoots(pathAccess?.allowedPaths ?? [], options) : [];
|
|
15
|
+
return resolvePathAccessTarget({ workspaceRoot, allowedRoots }, requestedPath, options);
|
|
16
|
+
}
|
|
17
|
+
export async function resolvePathAccessTarget(policy, requestedPath, options = {}) {
|
|
18
|
+
const request = requestedPath ?? "";
|
|
19
|
+
if (isAbsoluteishPath(request))
|
|
20
|
+
return resolveAllowedTarget(policy, request, options);
|
|
21
|
+
const displayPath = normalizeRelativePath(request);
|
|
22
|
+
const target = await canonicalExistingPath(resolve(policy.workspaceRoot, displayPath));
|
|
23
|
+
ensureInside(policy.workspaceRoot, target, "Path escapes workspace");
|
|
24
|
+
return { kind: "workspace", root: policy.workspaceRoot, target, displayPath };
|
|
25
|
+
}
|
|
26
|
+
export function isAbsoluteishPath(path) {
|
|
27
|
+
return path === "~" || path.startsWith("~/") || path.startsWith("~\\") || isAbsolute(path) || win32.isAbsolute(path);
|
|
28
|
+
}
|
|
29
|
+
async function resolveAllowedRoots(allowedPaths, options) {
|
|
30
|
+
const roots = [];
|
|
31
|
+
for (const source of allowedPaths) {
|
|
32
|
+
const expanded = expandAbsoluteishPath(source, options, `Allowed path must be absolute or start with ~: ${source}`);
|
|
33
|
+
const realPath = await canonicalDirectory(expanded, `Allowed path ${source}`);
|
|
34
|
+
if (roots.some((root) => root.realPath === realPath))
|
|
35
|
+
continue;
|
|
36
|
+
roots.push({ source, path: expanded, realPath });
|
|
37
|
+
}
|
|
38
|
+
return roots;
|
|
39
|
+
}
|
|
40
|
+
async function resolveAllowedTarget(policy, request, options) {
|
|
41
|
+
if (policy.allowedRoots.length === 0)
|
|
42
|
+
throw new Error("Absolute paths are not allowed");
|
|
43
|
+
const displayPath = expandAbsoluteishPath(request, options, `Path is not absolute: ${request}`);
|
|
44
|
+
const target = await canonicalExistingPath(displayPath);
|
|
45
|
+
const root = policy.allowedRoots.find((allowedRoot) => isInsideOrSame(allowedRoot.realPath, target));
|
|
46
|
+
if (root === undefined)
|
|
47
|
+
throw new Error("Path is outside allowed paths");
|
|
48
|
+
return { kind: "allowed", root: root.realPath, target, displayPath };
|
|
49
|
+
}
|
|
50
|
+
function expandAbsoluteishPath(path, options, relativeMessage) {
|
|
51
|
+
const home = options.homeDir ?? homedir();
|
|
52
|
+
if (path === "~")
|
|
53
|
+
return home;
|
|
54
|
+
if (path.startsWith("~/") || path.startsWith("~\\"))
|
|
55
|
+
return resolve(home, path.slice(2));
|
|
56
|
+
if (isAbsolute(path))
|
|
57
|
+
return resolve(path);
|
|
58
|
+
if (win32.isAbsolute(path))
|
|
59
|
+
throw new Error(`Absolute path is not valid on this host: ${path}`);
|
|
60
|
+
throw new Error(relativeMessage);
|
|
61
|
+
}
|
|
62
|
+
async function canonicalDirectory(path, label) {
|
|
63
|
+
const canonical = await canonicalExistingPath(path, `${label} does not exist`);
|
|
64
|
+
const result = await stat(canonical);
|
|
65
|
+
if (!result.isDirectory())
|
|
66
|
+
throw new Error(`${label} must be a directory`);
|
|
67
|
+
return canonical;
|
|
68
|
+
}
|
|
69
|
+
async function canonicalExistingPath(path, missingMessage = "Path does not exist") {
|
|
70
|
+
try {
|
|
71
|
+
return await realpath(path);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (isNodeErrorWithCode(error, "ENOENT"))
|
|
75
|
+
throw new Error(missingMessage, { cause: error });
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function ensureInside(root, target, message) {
|
|
80
|
+
if (!isInsideOrSame(root, target))
|
|
81
|
+
throw new Error(message);
|
|
82
|
+
}
|
|
83
|
+
function isInsideOrSame(root, target) {
|
|
84
|
+
const rel = relative(root, target);
|
|
85
|
+
return rel === "" || (!rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel));
|
|
86
|
+
}
|
|
87
|
+
function isNodeErrorWithCode(error, code) {
|
|
88
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=pathAccessPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathAccessPolicy.js","sourceRoot":"","sources":["../../../src/server/workspaces/pathAccessPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, join, relative, sep } from "node:path";
|
|
3
|
+
export async function resolveInsideWorkspace(rootPath, relativePath) {
|
|
4
|
+
const requested = normalizeRelativePath(relativePath);
|
|
5
|
+
const root = await realpath(rootPath);
|
|
6
|
+
const joined = join(root, requested);
|
|
7
|
+
const target = await realpath(joined).catch((error) => {
|
|
8
|
+
if (isNodeErrorWithCode(error, "ENOENT"))
|
|
9
|
+
throw new Error("Path does not exist");
|
|
10
|
+
throw error;
|
|
11
|
+
});
|
|
12
|
+
ensureInside(root, target);
|
|
13
|
+
return { root, target, relativePath: requested };
|
|
14
|
+
}
|
|
15
|
+
export async function resolveParentInsideWorkspace(rootPath, relativePath) {
|
|
16
|
+
const requested = normalizeRelativePath(relativePath);
|
|
17
|
+
const root = await realpath(rootPath);
|
|
18
|
+
const target = join(root, requested);
|
|
19
|
+
ensureInside(root, target);
|
|
20
|
+
return { root, target, relativePath: requested };
|
|
21
|
+
}
|
|
22
|
+
export function normalizeRelativePath(input) {
|
|
23
|
+
const value = input ?? "";
|
|
24
|
+
if (value === "" || value === ".")
|
|
25
|
+
return "";
|
|
26
|
+
if (isAbsolute(value))
|
|
27
|
+
throw new Error("Absolute paths are not allowed");
|
|
28
|
+
const parts = value.split(/[\\/]+/).filter((part) => part !== "" && part !== ".");
|
|
29
|
+
if (parts.some((part) => part === ".."))
|
|
30
|
+
throw new Error("Path traversal is not allowed");
|
|
31
|
+
return parts.join("/");
|
|
32
|
+
}
|
|
33
|
+
export function isNodeErrorWithCode(error, code) {
|
|
34
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
35
|
+
}
|
|
36
|
+
export function ensureInside(root, target) {
|
|
37
|
+
const rel = relative(root, target);
|
|
38
|
+
if (rel === "")
|
|
39
|
+
return;
|
|
40
|
+
if (rel.startsWith("..") || isAbsolute(rel))
|
|
41
|
+
throw new Error("Path escapes workspace");
|
|
42
|
+
if (sep !== "/" && rel.split(sep).includes(".."))
|
|
43
|
+
throw new Error("Path escapes workspace");
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=pathSafety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathSafety.js","sourceRoot":"","sources":["../../../src/server/workspaces/pathSafety.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAgB,EAAE,YAAgC;IAC7F,MAAM,SAAS,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC7D,IAAI,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACjF,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,QAAgB,EAAE,YAAoB;IACvF,MAAM,SAAS,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACrC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAyB;IAC7D,MAAM,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC;IAC1B,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC;IAC7C,IAAI,UAAU,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC;IAClF,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAc,EAAE,IAAY;IAC9D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,MAAc;IACvD,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO;IACvB,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACvF,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAC9F,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { effectiveUploadsConfig, parsePathAccessConfig, parseUploadsConfig } from "../../config.js";
|
|
4
|
+
export const PROJECT_PI_WEB_CONFIG_PATH = ".pi-web/config.json";
|
|
5
|
+
export async function loadProjectPiWebConfig(projectPath) {
|
|
6
|
+
const path = join(projectPath, PROJECT_PI_WEB_CONFIG_PATH);
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(await readFile(path, "utf8"));
|
|
9
|
+
if (!isRecord(parsed))
|
|
10
|
+
throw new Error(`PI WEB project config must be a JSON object: ${path}`);
|
|
11
|
+
return { path, exists: true, config: parseProjectPiWebConfig(parsed, path) };
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (isNodeErrorWithCode(error, "ENOENT"))
|
|
15
|
+
return { path, exists: false, config: {} };
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function loadEffectiveProjectPathAccess(projectPath, globalConfig) {
|
|
20
|
+
const projectConfig = await loadProjectPiWebConfig(projectPath);
|
|
21
|
+
return mergePathAccessConfigs(globalConfig.pathAccess, projectConfig.config.pathAccess);
|
|
22
|
+
}
|
|
23
|
+
export async function loadEffectiveProjectUploadsConfig(projectPath, globalConfig) {
|
|
24
|
+
const projectConfig = await loadProjectPiWebConfig(projectPath);
|
|
25
|
+
return effectiveUploadsConfig({ uploads: { ...(globalConfig.uploads ?? {}), ...(projectConfig.config.uploads ?? {}) } });
|
|
26
|
+
}
|
|
27
|
+
export function mergePathAccessConfigs(...configs) {
|
|
28
|
+
const allowedPaths = dedupe(configs.flatMap((config) => config?.allowedPaths ?? []));
|
|
29
|
+
return allowedPaths.length === 0 ? undefined : { allowedPaths };
|
|
30
|
+
}
|
|
31
|
+
function parseProjectPiWebConfig(value, path) {
|
|
32
|
+
const version = value["version"];
|
|
33
|
+
return {
|
|
34
|
+
...(version !== undefined ? { version: parseProjectConfigVersion(version, path) } : {}),
|
|
35
|
+
...(value["pathAccess"] !== undefined ? { pathAccess: parsePathAccessConfig(value["pathAccess"], path) } : {}),
|
|
36
|
+
...(value["uploads"] !== undefined ? { uploads: parseUploadsConfig(value["uploads"], path) } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function parseProjectConfigVersion(value, path) {
|
|
40
|
+
if (value !== 1)
|
|
41
|
+
throw new Error(`PI WEB project config version must be 1: ${path}`);
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
function dedupe(values) {
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
const result = [];
|
|
47
|
+
for (const value of values) {
|
|
48
|
+
if (seen.has(value))
|
|
49
|
+
continue;
|
|
50
|
+
seen.add(value);
|
|
51
|
+
result.push(value);
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
function isNodeErrorWithCode(error, code) {
|
|
56
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
57
|
+
}
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=projectPiWebConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectPiWebConfig.js","sourceRoot":"","sources":["../../../src/server/workspaces/projectPiWebConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { cwdPathsEqual } from "../workingDirectory.js";
|
|
2
|
+
export class RegisteredProjectWorkspaceCwds {
|
|
3
|
+
constructor(deps) {
|
|
4
|
+
this.deps = deps;
|
|
5
|
+
}
|
|
6
|
+
async forCwd(cwd) {
|
|
7
|
+
const projects = await this.deps.projects.list();
|
|
8
|
+
for (const project of projects) {
|
|
9
|
+
const workspaces = await this.deps.workspaces.list(project);
|
|
10
|
+
const paths = workspaces.map((workspace) => workspace.path);
|
|
11
|
+
if (paths.some((path) => cwdPathsEqual(path, cwd)))
|
|
12
|
+
return paths;
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=projectWorkspaceCwds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectWorkspaceCwds.js","sourceRoot":"","sources":["../../../src/server/workspaces/projectWorkspaceCwds.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAgCvD,MAAM,OAAO,8BAA8B;IACzC,YAA6B,IAA8B;QAA9B,SAAI,GAAJ,IAAI,CAA0B;IAAG,CAAC;IAE/D,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC5D,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;QACnE,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { isPiWebPluginId } from "../../shared/pluginIds.js";
|
|
3
|
+
import { WorkspaceCatalogProtocolError, WorkspaceCatalogRequestError, WorkspaceCatalogUnavailableError, WORKSPACE_PROVIDER_RUNTIME_PROTOCOL_VERSION, } from "./workspaceCatalog.js";
|
|
4
|
+
const WORKSPACE_CATALOG_PATH = "/workspace-catalog";
|
|
5
|
+
/** Narrow web adapter over sessiond's internal workspace-authority protocol. */
|
|
6
|
+
export class SessionDaemonWorkspaceCatalog {
|
|
7
|
+
constructor(daemon) {
|
|
8
|
+
this.daemon = daemon;
|
|
9
|
+
}
|
|
10
|
+
async resolveProject(projectId) {
|
|
11
|
+
const value = await this.requestJson(`${WORKSPACE_CATALOG_PATH}/projects/${encodedId(projectId, "project")}/workspaces`);
|
|
12
|
+
return parseWorkspaceProviderResolution(value, projectId);
|
|
13
|
+
}
|
|
14
|
+
async list(projectId) {
|
|
15
|
+
return [...(await this.resolveProject(projectId)).workspaces];
|
|
16
|
+
}
|
|
17
|
+
async resolve(projectId, workspaceId) {
|
|
18
|
+
const value = await this.requestJson(`${WORKSPACE_CATALOG_PATH}/projects/${encodedId(projectId, "project")}/workspaces/${encodedId(workspaceId, "workspace")}`);
|
|
19
|
+
const workspace = parseWorkspace(value, "workspace resolution response");
|
|
20
|
+
if (workspace.projectId !== projectId || workspace.id !== workspaceId) {
|
|
21
|
+
throw protocolError("workspace resolution response did not match the requested project and workspace");
|
|
22
|
+
}
|
|
23
|
+
return workspace;
|
|
24
|
+
}
|
|
25
|
+
async providerRuntime() {
|
|
26
|
+
return parseProviderRuntimeSnapshot(await this.requestJson(`${WORKSPACE_CATALOG_PATH}/provider-runtime`));
|
|
27
|
+
}
|
|
28
|
+
async requestJson(path) {
|
|
29
|
+
let response;
|
|
30
|
+
try {
|
|
31
|
+
response = await this.daemon.request("GET", path);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new WorkspaceCatalogUnavailableError(`Session daemon workspace authority unavailable: ${errorMessage(error)}`, { cause: error });
|
|
35
|
+
}
|
|
36
|
+
if (response.statusCode < 200 || response.statusCode >= 300) {
|
|
37
|
+
if (isUnknownWorkspaceCatalogRoute(response.statusCode, response.body)) {
|
|
38
|
+
throw new WorkspaceCatalogProtocolError("Session daemon does not support workspace authority operations; restart or upgrade the session daemon");
|
|
39
|
+
}
|
|
40
|
+
throw new WorkspaceCatalogRequestError(workspaceCatalogRequestMessage(response.statusCode, response.body), response.statusCode);
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
if (response.body === "")
|
|
44
|
+
return undefined;
|
|
45
|
+
const value = JSON.parse(response.body);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw new WorkspaceCatalogProtocolError("Session daemon workspace authority returned invalid JSON", { cause: error });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function parseWorkspaceProviderResolution(value, expectedProjectId) {
|
|
54
|
+
if (!isRecord(value))
|
|
55
|
+
throw protocolError("workspace resolution response must be an object");
|
|
56
|
+
const status = parseWorkspaceProviderResolutionStatus(value["status"]);
|
|
57
|
+
const projectId = requireString(value, "projectId", "workspace resolution response");
|
|
58
|
+
if (projectId !== expectedProjectId)
|
|
59
|
+
throw protocolError("workspace resolution response did not match the requested project");
|
|
60
|
+
const ownerPluginId = optionalPluginId(value, "ownerPluginId", "workspace resolution response");
|
|
61
|
+
if (status === "provider" && ownerPluginId === undefined) {
|
|
62
|
+
throw protocolError("provider workspace resolution must identify its owner");
|
|
63
|
+
}
|
|
64
|
+
if (status === "folder" && ownerPluginId !== undefined) {
|
|
65
|
+
throw protocolError("folder workspace resolution must not identify a provider owner");
|
|
66
|
+
}
|
|
67
|
+
const workspaces = parseWorkspaceList(value["workspaces"], projectId);
|
|
68
|
+
const diagnostics = parseArray(value["diagnostics"], "workspace provider diagnostics", parseWorkspaceProviderDiagnostic);
|
|
69
|
+
return Object.freeze({
|
|
70
|
+
status,
|
|
71
|
+
projectId,
|
|
72
|
+
...(ownerPluginId === undefined ? {} : { ownerPluginId }),
|
|
73
|
+
workspaces: Object.freeze(workspaces),
|
|
74
|
+
diagnostics: Object.freeze(diagnostics),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function parseWorkspaceProviderResolutionStatus(value) {
|
|
78
|
+
if (value === "provider" || value === "folder" || value === "degraded")
|
|
79
|
+
return value;
|
|
80
|
+
throw protocolError("workspace resolution status is invalid");
|
|
81
|
+
}
|
|
82
|
+
function parseWorkspaceProviderDiagnostic(value, index) {
|
|
83
|
+
const label = `workspace provider diagnostic ${String(index + 1)}`;
|
|
84
|
+
if (!isRecord(value))
|
|
85
|
+
throw protocolError(`${label} must be an object`);
|
|
86
|
+
const code = parseWorkspaceProviderDiagnosticCode(value["code"], label);
|
|
87
|
+
const tier = parseWorkspaceProviderTier(value["tier"], label);
|
|
88
|
+
const pluginId = optionalPluginId(value, "pluginId", label);
|
|
89
|
+
const pluginIds = value["pluginIds"] === undefined
|
|
90
|
+
? undefined
|
|
91
|
+
: parsePluginIds(value["pluginIds"], `${label} pluginIds`);
|
|
92
|
+
return Object.freeze({
|
|
93
|
+
code,
|
|
94
|
+
message: requireString(value, "message", label),
|
|
95
|
+
tier,
|
|
96
|
+
...(pluginId === undefined ? {} : { pluginId }),
|
|
97
|
+
...(pluginIds === undefined ? {} : { pluginIds: Object.freeze(pluginIds) }),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function parseWorkspaceProviderDiagnosticCode(value, label) {
|
|
101
|
+
if (value === "probe-failed" || value === "claim-conflict" || value === "list-failed")
|
|
102
|
+
return value;
|
|
103
|
+
throw protocolError(`${label} code is invalid`);
|
|
104
|
+
}
|
|
105
|
+
function parseWorkspaceProviderTier(value, label) {
|
|
106
|
+
if (value === "primary" || value === "fallback")
|
|
107
|
+
return value;
|
|
108
|
+
throw protocolError(`${label} tier is invalid`);
|
|
109
|
+
}
|
|
110
|
+
function parsePluginIds(value, label) {
|
|
111
|
+
if (!Array.isArray(value))
|
|
112
|
+
throw protocolError(`${label} must be an array`);
|
|
113
|
+
return value.map((pluginId, index) => {
|
|
114
|
+
if (typeof pluginId !== "string" || !isPiWebPluginId(pluginId)) {
|
|
115
|
+
throw protocolError(`${label} item ${String(index + 1)} is invalid`);
|
|
116
|
+
}
|
|
117
|
+
return pluginId;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function parseWorkspaceList(value, projectId) {
|
|
121
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
122
|
+
throw protocolError("workspace list must be a non-empty array");
|
|
123
|
+
const ids = new Set();
|
|
124
|
+
const paths = new Set();
|
|
125
|
+
const workspaces = value.map((item, index) => parseWorkspace(item, `workspace list item ${String(index + 1)}`));
|
|
126
|
+
let mainCount = 0;
|
|
127
|
+
for (const workspace of workspaces) {
|
|
128
|
+
if (workspace.projectId !== projectId)
|
|
129
|
+
throw protocolError("workspace list contained a workspace for another project");
|
|
130
|
+
if (ids.has(workspace.id))
|
|
131
|
+
throw protocolError(`workspace list contained duplicate id: ${workspace.id}`);
|
|
132
|
+
if (paths.has(workspace.path))
|
|
133
|
+
throw protocolError(`workspace list contained duplicate path: ${workspace.path}`);
|
|
134
|
+
ids.add(workspace.id);
|
|
135
|
+
paths.add(workspace.path);
|
|
136
|
+
if (workspace.isMain)
|
|
137
|
+
mainCount += 1;
|
|
138
|
+
}
|
|
139
|
+
if (mainCount !== 1)
|
|
140
|
+
throw protocolError("workspace list must contain exactly one main workspace");
|
|
141
|
+
return workspaces;
|
|
142
|
+
}
|
|
143
|
+
function parseWorkspace(value, label) {
|
|
144
|
+
if (!isRecord(value))
|
|
145
|
+
throw protocolError(`${label} must be an object`);
|
|
146
|
+
const path = requireString(value, "path", label);
|
|
147
|
+
if (!isAbsolute(path))
|
|
148
|
+
throw protocolError(`${label} path must be absolute`);
|
|
149
|
+
const provider = value["provider"] === undefined ? undefined : parseProvider(value["provider"], label);
|
|
150
|
+
const removal = value["removal"] === undefined ? undefined : parseRemoval(value["removal"], label);
|
|
151
|
+
return Object.freeze({
|
|
152
|
+
id: requireString(value, "id", label),
|
|
153
|
+
projectId: requireString(value, "projectId", label),
|
|
154
|
+
path,
|
|
155
|
+
label: requireString(value, "label", label),
|
|
156
|
+
isMain: requireBoolean(value, "isMain", label),
|
|
157
|
+
...(provider === undefined ? {} : { provider }),
|
|
158
|
+
...(removal === undefined ? {} : { removal }),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function parseProvider(value, workspaceLabel) {
|
|
162
|
+
const label = `${workspaceLabel} provider`;
|
|
163
|
+
if (!isRecord(value))
|
|
164
|
+
throw protocolError(`${label} must be an object`);
|
|
165
|
+
const capabilities = value["capabilities"];
|
|
166
|
+
if (!isRecord(capabilities))
|
|
167
|
+
throw protocolError(`${label} capabilities must be an object`);
|
|
168
|
+
const metadata = value["metadata"] === undefined ? undefined : parseJsonObject(value["metadata"], `${label} metadata`);
|
|
169
|
+
return Object.freeze({
|
|
170
|
+
pluginId: requirePluginId(value, "pluginId", label),
|
|
171
|
+
capabilities: Object.freeze({
|
|
172
|
+
request: requireBoolean(capabilities, "request", `${label} capabilities`),
|
|
173
|
+
remove: requireBoolean(capabilities, "remove", `${label} capabilities`),
|
|
174
|
+
}),
|
|
175
|
+
...(metadata === undefined ? {} : { metadata }),
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function parseRemoval(value, workspaceLabel) {
|
|
179
|
+
const label = `${workspaceLabel} removal`;
|
|
180
|
+
if (!isRecord(value))
|
|
181
|
+
throw protocolError(`${label} must be an object`);
|
|
182
|
+
return Object.freeze({
|
|
183
|
+
actionLabel: requireString(value, "actionLabel", label),
|
|
184
|
+
confirmation: requireString(value, "confirmation", label),
|
|
185
|
+
precondition: requireString(value, "precondition", label),
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function parseProviderRuntimeSnapshot(value) {
|
|
189
|
+
if (!isRecord(value))
|
|
190
|
+
throw protocolError("provider runtime response must be an object");
|
|
191
|
+
if (value["protocolVersion"] !== WORKSPACE_PROVIDER_RUNTIME_PROTOCOL_VERSION) {
|
|
192
|
+
throw protocolError("provider runtime protocol is unsupported; restart or upgrade the session daemon");
|
|
193
|
+
}
|
|
194
|
+
const safeStart = parseSafeStart(value["safeStart"]);
|
|
195
|
+
const records = parseArray(value["records"], "provider runtime records", parseRuntimeRecord);
|
|
196
|
+
const health = parseArray(value["health"], "provider runtime health", parseHealthInspection);
|
|
197
|
+
const diagnostics = parseArray(value["diagnostics"], "provider runtime diagnostics", parseCatalogDiagnostic);
|
|
198
|
+
return Object.freeze({
|
|
199
|
+
protocolVersion: WORKSPACE_PROVIDER_RUNTIME_PROTOCOL_VERSION,
|
|
200
|
+
...(safeStart === undefined ? {} : { safeStart }),
|
|
201
|
+
records: Object.freeze(records),
|
|
202
|
+
health: Object.freeze(health),
|
|
203
|
+
diagnostics: Object.freeze(diagnostics),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
function parseRuntimeRecord(value, index) {
|
|
207
|
+
const label = `provider runtime record ${String(index + 1)}`;
|
|
208
|
+
if (!isRecord(value))
|
|
209
|
+
throw protocolError(`${label} must be an object`);
|
|
210
|
+
const state = value["state"];
|
|
211
|
+
const scope = value["scope"];
|
|
212
|
+
const phase = value["phase"];
|
|
213
|
+
if (!isRuntimeState(state))
|
|
214
|
+
throw protocolError(`${label} state is invalid`);
|
|
215
|
+
if (scope !== "bundled" && scope !== "local" && scope !== "user" && scope !== "project") {
|
|
216
|
+
throw protocolError(`${label} scope is invalid`);
|
|
217
|
+
}
|
|
218
|
+
if (phase !== undefined && !isLifecyclePhase(phase))
|
|
219
|
+
throw protocolError(`${label} phase is invalid`);
|
|
220
|
+
const name = optionalString(value, "name", label);
|
|
221
|
+
const message = optionalString(value, "message", label);
|
|
222
|
+
const browserRevision = optionalString(value, "browserRevision", label);
|
|
223
|
+
return Object.freeze({
|
|
224
|
+
pluginId: requirePluginId(value, "pluginId", label),
|
|
225
|
+
source: requireString(value, "source", label),
|
|
226
|
+
scope,
|
|
227
|
+
moduleRevision: requireString(value, "moduleRevision", label),
|
|
228
|
+
...(browserRevision === undefined ? {} : { browserRevision }),
|
|
229
|
+
settingsRevision: requireString(value, "settingsRevision", label),
|
|
230
|
+
machineSpecific: requireBoolean(value, "machineSpecific", label),
|
|
231
|
+
state,
|
|
232
|
+
...(name === undefined ? {} : { name }),
|
|
233
|
+
...(phase === undefined ? {} : { phase }),
|
|
234
|
+
...(message === undefined ? {} : { message }),
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
function parseCatalogDiagnostic(value, index) {
|
|
238
|
+
const label = `provider runtime diagnostic ${String(index + 1)}`;
|
|
239
|
+
if (!isRecord(value))
|
|
240
|
+
throw protocolError(`${label} must be an object`);
|
|
241
|
+
const code = value["code"];
|
|
242
|
+
if (!isCatalogDiagnosticCode(code))
|
|
243
|
+
throw protocolError(`${label} code is invalid`);
|
|
244
|
+
const pluginId = optionalPluginId(value, "pluginId", label);
|
|
245
|
+
return Object.freeze({
|
|
246
|
+
code,
|
|
247
|
+
source: requireString(value, "source", label),
|
|
248
|
+
message: requireString(value, "message", label),
|
|
249
|
+
...(pluginId === undefined ? {} : { pluginId }),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function parseHealthInspection(value, index) {
|
|
253
|
+
const label = `provider runtime health item ${String(index + 1)}`;
|
|
254
|
+
if (!isRecord(value))
|
|
255
|
+
throw protocolError(`${label} must be an object`);
|
|
256
|
+
const phase = value["phase"];
|
|
257
|
+
if (phase !== undefined && phase !== "health")
|
|
258
|
+
throw protocolError(`${label} phase is invalid`);
|
|
259
|
+
const error = optionalString(value, "error", label);
|
|
260
|
+
return Object.freeze({
|
|
261
|
+
pluginId: requirePluginId(value, "pluginId", label),
|
|
262
|
+
health: parseHealth(value["health"], label),
|
|
263
|
+
...(phase === undefined ? {} : { phase }),
|
|
264
|
+
...(error === undefined ? {} : { error }),
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function parseHealth(value, inspectionLabel) {
|
|
268
|
+
const label = `${inspectionLabel} health`;
|
|
269
|
+
if (!isRecord(value))
|
|
270
|
+
throw protocolError(`${label} must be an object`);
|
|
271
|
+
const status = value["status"];
|
|
272
|
+
if (status !== "healthy" && status !== "degraded" && status !== "unhealthy") {
|
|
273
|
+
throw protocolError(`${label} status is invalid`);
|
|
274
|
+
}
|
|
275
|
+
const message = optionalString(value, "message", label);
|
|
276
|
+
const details = value["details"] === undefined ? undefined : parseJsonObject(value["details"], `${label} details`);
|
|
277
|
+
return Object.freeze({
|
|
278
|
+
status,
|
|
279
|
+
...(message === undefined ? {} : { message }),
|
|
280
|
+
...(details === undefined ? {} : { details }),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
function parseSafeStart(value) {
|
|
284
|
+
if (value === undefined)
|
|
285
|
+
return undefined;
|
|
286
|
+
if (value === "bundled-only" || value === "none")
|
|
287
|
+
return value;
|
|
288
|
+
throw protocolError("provider runtime safeStart is invalid");
|
|
289
|
+
}
|
|
290
|
+
function parseArray(value, label, parse) {
|
|
291
|
+
if (!Array.isArray(value))
|
|
292
|
+
throw protocolError(`${label} must be an array`);
|
|
293
|
+
return value.map(parse);
|
|
294
|
+
}
|
|
295
|
+
function parseJsonObject(value, label) {
|
|
296
|
+
if (!isRecord(value))
|
|
297
|
+
throw protocolError(`${label} must be a JSON object`);
|
|
298
|
+
const output = Object.fromEntries(Object.entries(value).map(([key, child]) => [key, parseJsonValue(child, label)]));
|
|
299
|
+
Object.freeze(output);
|
|
300
|
+
return output;
|
|
301
|
+
}
|
|
302
|
+
function parseJsonValue(value, label) {
|
|
303
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
304
|
+
return value;
|
|
305
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
306
|
+
return value;
|
|
307
|
+
if (Array.isArray(value)) {
|
|
308
|
+
const output = value.map((item) => parseJsonValue(item, label));
|
|
309
|
+
Object.freeze(output);
|
|
310
|
+
return output;
|
|
311
|
+
}
|
|
312
|
+
if (isRecord(value))
|
|
313
|
+
return parseJsonObject(value, label);
|
|
314
|
+
throw protocolError(`${label} must contain only JSON values`);
|
|
315
|
+
}
|
|
316
|
+
function requireString(record, field, label) {
|
|
317
|
+
const value = record[field];
|
|
318
|
+
if (typeof value !== "string" || value === "")
|
|
319
|
+
throw protocolError(`${label} ${field} must be a non-empty string`);
|
|
320
|
+
return value;
|
|
321
|
+
}
|
|
322
|
+
function optionalString(record, field, label) {
|
|
323
|
+
const value = record[field];
|
|
324
|
+
if (value === undefined)
|
|
325
|
+
return undefined;
|
|
326
|
+
if (typeof value !== "string")
|
|
327
|
+
throw protocolError(`${label} ${field} must be a string`);
|
|
328
|
+
return value;
|
|
329
|
+
}
|
|
330
|
+
function requirePluginId(record, field, label) {
|
|
331
|
+
const value = requireString(record, field, label);
|
|
332
|
+
if (!isPiWebPluginId(value))
|
|
333
|
+
throw protocolError(`${label} ${field} is invalid`);
|
|
334
|
+
return value;
|
|
335
|
+
}
|
|
336
|
+
function optionalPluginId(record, field, label) {
|
|
337
|
+
const value = optionalString(record, field, label);
|
|
338
|
+
if (value !== undefined && !isPiWebPluginId(value))
|
|
339
|
+
throw protocolError(`${label} ${field} is invalid`);
|
|
340
|
+
return value;
|
|
341
|
+
}
|
|
342
|
+
function requireBoolean(record, field, label) {
|
|
343
|
+
const value = record[field];
|
|
344
|
+
if (typeof value !== "boolean")
|
|
345
|
+
throw protocolError(`${label} ${field} must be a boolean`);
|
|
346
|
+
return value;
|
|
347
|
+
}
|
|
348
|
+
function isRuntimeState(value) {
|
|
349
|
+
return value === "active" || value === "failed" || value === "incompatible" || value === "disabled";
|
|
350
|
+
}
|
|
351
|
+
function isLifecyclePhase(value) {
|
|
352
|
+
return value === "import" || value === "activate" || value === "validate" || value === "start" || value === "health" || value === "stop";
|
|
353
|
+
}
|
|
354
|
+
function isCatalogDiagnosticCode(value) {
|
|
355
|
+
return value === "invalid-package" || value === "duplicate-id";
|
|
356
|
+
}
|
|
357
|
+
function encodedId(value, label) {
|
|
358
|
+
if (value === "")
|
|
359
|
+
throw new Error(`${label} id must be a non-empty string`);
|
|
360
|
+
return encodeURIComponent(value);
|
|
361
|
+
}
|
|
362
|
+
function workspaceCatalogRequestMessage(statusCode, body) {
|
|
363
|
+
const detail = responseError(body);
|
|
364
|
+
if (statusCode < 500 && detail !== undefined)
|
|
365
|
+
return detail;
|
|
366
|
+
return `Session daemon workspace authority returned HTTP ${String(statusCode)}${detail === undefined ? "" : `: ${detail}`}`;
|
|
367
|
+
}
|
|
368
|
+
function responseError(body) {
|
|
369
|
+
const value = parseResponseBody(body);
|
|
370
|
+
return isRecord(value) && typeof value["error"] === "string" ? value["error"] : undefined;
|
|
371
|
+
}
|
|
372
|
+
function isUnknownWorkspaceCatalogRoute(statusCode, body) {
|
|
373
|
+
if (statusCode !== 404)
|
|
374
|
+
return false;
|
|
375
|
+
const value = parseResponseBody(body);
|
|
376
|
+
if (!isRecord(value))
|
|
377
|
+
return true;
|
|
378
|
+
const error = value["error"];
|
|
379
|
+
const message = value["message"];
|
|
380
|
+
return error === "Not Found" || (typeof message === "string" && /^Route .* not found$/u.test(message));
|
|
381
|
+
}
|
|
382
|
+
function parseResponseBody(body) {
|
|
383
|
+
try {
|
|
384
|
+
if (body === "")
|
|
385
|
+
return undefined;
|
|
386
|
+
const value = JSON.parse(body);
|
|
387
|
+
return value;
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
function protocolError(message) {
|
|
394
|
+
return new WorkspaceCatalogProtocolError(`Invalid session daemon workspace authority response: ${message}`);
|
|
395
|
+
}
|
|
396
|
+
function errorMessage(error) {
|
|
397
|
+
return error instanceof Error ? error.message : String(error);
|
|
398
|
+
}
|
|
399
|
+
function isRecord(value) {
|
|
400
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
401
|
+
}
|
|
402
|
+
//# sourceMappingURL=sessionDaemonWorkspaceCatalog.js.map
|