@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,31 @@
|
|
|
1
|
+
/** Quiesces ingress, disposes consumers, then tears down plugin providers and dependencies. */
|
|
2
|
+
export async function runSessionDaemonShutdown(options) {
|
|
3
|
+
const { dependencies } = options;
|
|
4
|
+
const operations = [
|
|
5
|
+
["quiesce server", () => dependencies.quiesceServer()],
|
|
6
|
+
// Between quiescing and disposal: no new work can arrive, and the runs
|
|
7
|
+
// already underway get a bounded chance to finish. An agent turn cannot be
|
|
8
|
+
// resumed after the process exits, so not interrupting it is the only way a
|
|
9
|
+
// restart is non-disruptive.
|
|
10
|
+
...(dependencies.drainActiveWork === undefined
|
|
11
|
+
? []
|
|
12
|
+
: [["drain active work", () => dependencies.drainActiveWork?.()]]),
|
|
13
|
+
["dispose terminals", () => dependencies.terminals.dispose()],
|
|
14
|
+
["dispose catalog refresher", () => dependencies.catalogRefresher.dispose()],
|
|
15
|
+
["dispose sessions", () => dependencies.sessions.dispose()],
|
|
16
|
+
["close server", () => dependencies.closeServer()],
|
|
17
|
+
["stop server plugins", () => dependencies.serverPlugins.stop()],
|
|
18
|
+
["dispose auth", () => dependencies.auth.dispose()],
|
|
19
|
+
["flush session unread state", () => dependencies.unreadStore.flush()],
|
|
20
|
+
];
|
|
21
|
+
for (const [operation, run] of operations) {
|
|
22
|
+
try {
|
|
23
|
+
await run();
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
options.onFailure?.();
|
|
27
|
+
options.logger.error({ err: error, operation }, "session daemon shutdown operation failed");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=sessionDaemonShutdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionDaemonShutdown.js","sourceRoot":"","sources":["../../../src/server/sessiond/sessionDaemonShutdown.ts"],"names":[],"mappings":"AA2BA,+FAA+F;AAC/F,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,OAAqC;IAClF,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;IACjC,MAAM,UAAU,GAA+D;QAC7E,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC;QACtD,uEAAuE;QACvE,2EAA2E;QAC3E,4EAA4E;QAC5E,6BAA6B;QAC7B,GAAG,CAAC,YAAY,CAAC,eAAe,KAAK,SAAS;YAC5C,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,EAAE,EAAE,CAAU,CAAC,CAAC;QAC7E,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC7D,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;QAC5E,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC3D,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAClD,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAChE,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACnD,CAAC,4BAA4B,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;KACvE,CAAC;IAEF,KAAK,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,GAAG,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,0CAA0C,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { WebSocket } from "ws";
|
|
2
|
+
import { SessionDaemonClient, } from "../../sessiond/sessionDaemonClient.js";
|
|
3
|
+
export function registerSessionProxyRoutes(app, daemon = new SessionDaemonClient(), prefix = "/api") {
|
|
4
|
+
const proxy = async (request, reply) => {
|
|
5
|
+
try {
|
|
6
|
+
const upstream = await daemon.request(request.method, stripPrefix(request.url, prefix), request.body);
|
|
7
|
+
reply.code(upstream.statusCode);
|
|
8
|
+
const contentType = upstream.headers["content-type"];
|
|
9
|
+
if (contentType !== undefined && contentType !== "")
|
|
10
|
+
reply.header("content-type", contentType);
|
|
11
|
+
return upstream.body !== "" ? parseJson(upstream.body) : undefined;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
requestFailed(reply, error);
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
app.get(`${prefix}/sessiond/health`, (_request, reply) => proxy({ method: "GET", url: `${prefix}/health` }, reply));
|
|
19
|
+
app.get(`${prefix}/sessiond/runtime`, (_request, reply) => proxy({ method: "GET", url: `${prefix}/runtime` }, reply));
|
|
20
|
+
app.get(`${prefix}/sessions/:sessionId/events`, { websocket: true }, (socket, request) => {
|
|
21
|
+
bridgeSockets(socket, daemon.connectWebSocket(stripPrefix(request.url, prefix)));
|
|
22
|
+
});
|
|
23
|
+
app.get(`${prefix}/sessions/events`, { websocket: true }, (socket) => {
|
|
24
|
+
bridgeSockets(socket, daemon.connectWebSocket("/sessions/events"));
|
|
25
|
+
});
|
|
26
|
+
app.get(`${prefix}/events`, { websocket: true }, (socket) => {
|
|
27
|
+
bridgeSockets(socket, daemon.connectWebSocket("/events"));
|
|
28
|
+
});
|
|
29
|
+
app.all(`${prefix}/status`, (request, reply) => proxy(request, reply));
|
|
30
|
+
app.all(`${prefix}/auth`, (request, reply) => proxy(request, reply));
|
|
31
|
+
app.all(`${prefix}/auth/*`, (request, reply) => proxy(request, reply));
|
|
32
|
+
app.all(`${prefix}/sessions`, (request, reply) => proxy(request, reply));
|
|
33
|
+
app.all(`${prefix}/sessions/*`, (request, reply) => proxy(request, reply));
|
|
34
|
+
}
|
|
35
|
+
function stripPrefix(url, prefix) {
|
|
36
|
+
const path = url.split("?", 1)[0] ?? url;
|
|
37
|
+
const query = url.slice(path.length);
|
|
38
|
+
const stripped = path.startsWith(prefix) ? `${path.slice(prefix.length)}${query}` : url;
|
|
39
|
+
return stripped === "" ? "/" : stripped;
|
|
40
|
+
}
|
|
41
|
+
function parseJson(text) {
|
|
42
|
+
const value = JSON.parse(text);
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
function requestFailed(reply, error) {
|
|
46
|
+
reply.code(502).send({ error: `Session daemon unavailable: ${error instanceof Error ? error.message : String(error)}` });
|
|
47
|
+
}
|
|
48
|
+
function bridgeSockets(client, upstream) {
|
|
49
|
+
client.on("message", (data) => { sendIfOpen(upstream, data); });
|
|
50
|
+
upstream.on("message", (data) => { sendIfOpen(client, data); });
|
|
51
|
+
client.on("close", () => { upstream.close(); });
|
|
52
|
+
upstream.on("close", () => { client.close(); });
|
|
53
|
+
upstream.on("error", () => { client.close(); });
|
|
54
|
+
client.on("error", () => { upstream.close(); });
|
|
55
|
+
}
|
|
56
|
+
function sendIfOpen(socket, data) {
|
|
57
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
58
|
+
socket.send(data);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=sessionProxyRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionProxyRoutes.js","sourceRoot":"","sources":["../../../src/server/sessiond/sessionProxyRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Map sessiond's constructed collaborators onto the session service's
|
|
3
|
+
* dependencies.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from `sessiond.ts`, which starts a daemon as an import side effect
|
|
6
|
+
* and so cannot be loaded by a test. This function performs no side effects and
|
|
7
|
+
* constructs nothing, so lifting it changes no startup ordering; it exists only
|
|
8
|
+
* so a test can build a service the way the daemon does and assert what a user
|
|
9
|
+
* is actually told.
|
|
10
|
+
*/
|
|
11
|
+
export function sessionServiceDependencies(input) {
|
|
12
|
+
return {
|
|
13
|
+
modelRuntime: input.modelRuntime,
|
|
14
|
+
agentDir: input.agentDir,
|
|
15
|
+
archiveStore: input.archiveStore,
|
|
16
|
+
workspaceActivity: input.workspaceActivity,
|
|
17
|
+
logger: input.logger,
|
|
18
|
+
...(input.spawnTargets === undefined ? {} : { spawnTargets: input.spawnTargets }),
|
|
19
|
+
// Tracked subsessions share the spawn capability's project-scope resolver,
|
|
20
|
+
// so they stay off unless spawning is configured too.
|
|
21
|
+
subsessionsEnabled: input.spawnTargets !== undefined && input.subsessionsEnabled,
|
|
22
|
+
askUserEnabled: input.askUserEnabled,
|
|
23
|
+
appendSystemPromptSections: input.appendSystemPromptSections,
|
|
24
|
+
extensionDialogsTimeoutMs: input.extensionDialogsTimeoutMs,
|
|
25
|
+
notificationStore: input.notificationStore,
|
|
26
|
+
unreadStore: input.unreadStore,
|
|
27
|
+
onUnreadChanged: input.onUnreadChanged,
|
|
28
|
+
// Read-only, so session startup can tell a waiting user that provider
|
|
29
|
+
// model lists are refreshing at the same time.
|
|
30
|
+
catalogRefreshStatus: input.catalogRefreshStatus,
|
|
31
|
+
sessionManager: input.sessionManager,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=sessionServiceDependencies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionServiceDependencies.js","sourceRoot":"","sources":["../../../src/server/sessiond/sessionServiceDependencies.ts"],"names":[],"mappings":"AAmCA;;;;;;;;;GASG;AACH,MAAM,UAAU,0BAA0B,CAAC,KAAoC;IAC7E,OAAO;QACL,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,GAAG,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;QACjF,2EAA2E;QAC3E,sDAAsD;QACtD,kBAAkB,EAAE,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,KAAK,CAAC,kBAAkB;QAChF,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,0BAA0B,EAAE,KAAK,CAAC,0BAA0B;QAC5D,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;QAC1D,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,eAAe,EAAE,KAAK,CAAC,eAAe;QACtC,sEAAsE;QACtE,+CAA+C;QAC/C,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;QAChD,cAAc,EAAE,KAAK,CAAC,cAAc;KACrC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session daemon state ownership.
|
|
3
|
+
*
|
|
4
|
+
* The session daemon is the authority over a pi-web instance's durable state:
|
|
5
|
+
* projects, machines, session archives, and unread state all live in the data
|
|
6
|
+
* directory, and the daemon is the only process allowed to own it while
|
|
7
|
+
* running (the web/API process of the same instance shares the directory but
|
|
8
|
+
* never claims it). A second daemon resolving the same data directory would
|
|
9
|
+
* corrupt that state silently, so the daemon records its ownership in
|
|
10
|
+
* `<data dir>/sessiond-owner.json` at startup and refuses to start while a
|
|
11
|
+
* live owner holds the marker.
|
|
12
|
+
*
|
|
13
|
+
* Liveness uses the owning process's Linux `/proc` start-time ticks when both
|
|
14
|
+
* the marker and the probe have them: the recorded value distinguishes the
|
|
15
|
+
* original owner from a reused pid — including the same numeric pid in a
|
|
16
|
+
* recreated container's fresh PID namespace — so stale markers never block
|
|
17
|
+
* startup and live owners always do. Otherwise it falls back to a
|
|
18
|
+
* `kill(pid, 0)` probe. Detection is scoped to one PID namespace; two daemons
|
|
19
|
+
* in different containers sharing one data volume cannot see each other's
|
|
20
|
+
* processes, an operator error no pid-based mechanism can catch.
|
|
21
|
+
*
|
|
22
|
+
* Service and `tsx watch` restarts briefly overlap the outgoing daemon, so a
|
|
23
|
+
* claimant that finds a live owner waits a short grace for the owner to
|
|
24
|
+
* release (orderly shutdown removes the marker) before failing. When the
|
|
25
|
+
* owner persists past the grace window, startup fails with a
|
|
26
|
+
* {@link SessiondStateOwnershipConflictError} naming the owner and the
|
|
27
|
+
* configuration a second instance needs: a distinct `PI_WEB_DATA_DIR`,
|
|
28
|
+
* `PI_WEB_SESSIOND_SOCKET` (or `PI_WEB_SESSIOND_PORT` / `PI_WEB_SESSIOND_HOST`),
|
|
29
|
+
* and web port.
|
|
30
|
+
*/
|
|
31
|
+
import { readFileSync } from "node:fs";
|
|
32
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
33
|
+
import { join } from "node:path";
|
|
34
|
+
import { piWebDataDir } from "../../config.js";
|
|
35
|
+
import { sessiondEndpointDescription } from "../../sessiond/config.js";
|
|
36
|
+
/** Marker file recording the owning daemon, inside the instance data directory. */
|
|
37
|
+
export const SESSIOND_OWNER_MARKER_FILENAME = "sessiond-owner.json";
|
|
38
|
+
/**
|
|
39
|
+
* The daemon could not start because a live session daemon owns the state this
|
|
40
|
+
* one resolved. The message is the user- and agent-facing remediation, so it
|
|
41
|
+
* names the owner and the distinct configuration a second instance needs.
|
|
42
|
+
*/
|
|
43
|
+
export class SessiondStateOwnershipConflictError extends Error {
|
|
44
|
+
constructor(options) {
|
|
45
|
+
const { dataDir, markerPath, owner } = options;
|
|
46
|
+
super(`another pi-web session daemon already owns this state\n\n` +
|
|
47
|
+
`The data directory "${dataDir}" is owned by a live session daemon ` +
|
|
48
|
+
`(pid ${String(owner.pid)}, started ${owner.startedAt}, listening on ${owner.endpoint}; ` +
|
|
49
|
+
`ownership marker ${markerPath}). Two daemons sharing one data directory corrupt each other's state.\n\n` +
|
|
50
|
+
`To run a second pi-web instance, give it its own state and endpoints:\n` +
|
|
51
|
+
`- PI_WEB_DATA_DIR: a different data directory\n` +
|
|
52
|
+
`- PI_WEB_SESSIOND_SOCKET (or PI_WEB_SESSIOND_PORT / PI_WEB_SESSIOND_HOST): a different session daemon endpoint\n` +
|
|
53
|
+
`- PI_WEB_PORT: a different web/API port\n\n` +
|
|
54
|
+
`If pid ${String(owner.pid)} is not a running pi-web session daemon, remove the stale marker file and start again.`);
|
|
55
|
+
this.name = "SessiondStateOwnershipConflictError";
|
|
56
|
+
this.dataDir = dataDir;
|
|
57
|
+
this.owner = owner;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const DEFAULT_GRACE_MS = 15_000;
|
|
61
|
+
const DEFAULT_POLL_INTERVAL_MS = 250;
|
|
62
|
+
/**
|
|
63
|
+
* Claim ownership of the instance data directory for this daemon.
|
|
64
|
+
*
|
|
65
|
+
* Resolves once the marker records this daemon; throws
|
|
66
|
+
* {@link SessiondStateOwnershipConflictError} when a live owner persists past
|
|
67
|
+
* the grace window.
|
|
68
|
+
*/
|
|
69
|
+
export async function claimSessiondStateOwnership(options) {
|
|
70
|
+
const ownPid = options.ownPid ?? process.pid;
|
|
71
|
+
const isAlive = options.isAlive ?? isOwnershipRecordAlive;
|
|
72
|
+
const graceMs = options.graceMs ?? DEFAULT_GRACE_MS;
|
|
73
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
74
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
75
|
+
const logger = options.logger;
|
|
76
|
+
const dataDir = options.dataDir ?? piWebDataDir(options.env);
|
|
77
|
+
const markerPath = join(dataDir, SESSIOND_OWNER_MARKER_FILENAME);
|
|
78
|
+
const processStartTime = readProcessStartTime(ownPid);
|
|
79
|
+
const record = {
|
|
80
|
+
pid: ownPid,
|
|
81
|
+
startedAt: new Date().toISOString(),
|
|
82
|
+
...(processStartTime === undefined ? {} : { processStartTime }),
|
|
83
|
+
endpoint: sessiondEndpointDescription(options.env),
|
|
84
|
+
};
|
|
85
|
+
await mkdir(dataDir, { recursive: true });
|
|
86
|
+
const deadline = Date.now() + graceMs;
|
|
87
|
+
let waitedForOwner = false;
|
|
88
|
+
for (;;) {
|
|
89
|
+
const existing = await readOwnershipRecord(markerPath);
|
|
90
|
+
if (existing !== undefined && existing !== "invalid") {
|
|
91
|
+
if (existing.pid !== ownPid && isAlive(existing)) {
|
|
92
|
+
// A live different owner: wait out the grace window for an orderly
|
|
93
|
+
// restart to release, then fail loudly.
|
|
94
|
+
if (Date.now() >= deadline) {
|
|
95
|
+
throw new SessiondStateOwnershipConflictError({ dataDir, markerPath, owner: existing });
|
|
96
|
+
}
|
|
97
|
+
if (!waitedForOwner) {
|
|
98
|
+
logger?.warn({ markerPath, owner: existing }, "another live session daemon owns this state; waiting briefly for it to release ownership");
|
|
99
|
+
waitedForOwner = true;
|
|
100
|
+
}
|
|
101
|
+
await sleep(pollIntervalMs);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (existing.pid !== ownPid) {
|
|
105
|
+
logger?.info({ markerPath, previousOwner: existing }, "taking over session daemon state ownership from a stale marker");
|
|
106
|
+
}
|
|
107
|
+
await rm(markerPath, { force: true });
|
|
108
|
+
}
|
|
109
|
+
else if (existing === "invalid") {
|
|
110
|
+
// Possibly a torn write by a claimant mid-create; give it the grace
|
|
111
|
+
// window to finish before discarding the marker.
|
|
112
|
+
if (Date.now() < deadline) {
|
|
113
|
+
await sleep(pollIntervalMs);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
logger?.warn({ markerPath }, "discarding an unreadable session daemon ownership marker");
|
|
117
|
+
await rm(markerPath, { force: true });
|
|
118
|
+
}
|
|
119
|
+
// No live owner holds the marker: claim it exclusively. The loser of a
|
|
120
|
+
// create race re-reads and re-evaluates the winner's marker above.
|
|
121
|
+
try {
|
|
122
|
+
await writeFile(markerPath, `${JSON.stringify(record, null, 2)}\n`, { flag: "wx" });
|
|
123
|
+
return {
|
|
124
|
+
markerPath,
|
|
125
|
+
record,
|
|
126
|
+
release: () => releaseOwnershipMarker(markerPath, record, logger),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (!isErrorCode(error, "EEXIST"))
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Parse marker content; `"invalid"` when it is not a readable ownership record. */
|
|
136
|
+
export function parseOwnershipRecord(content) {
|
|
137
|
+
try {
|
|
138
|
+
const value = JSON.parse(content);
|
|
139
|
+
if (!isRecord(value))
|
|
140
|
+
return "invalid";
|
|
141
|
+
if (typeof value["pid"] !== "number" || typeof value["startedAt"] !== "string" || typeof value["endpoint"] !== "string") {
|
|
142
|
+
return "invalid";
|
|
143
|
+
}
|
|
144
|
+
if (value["processStartTime"] !== undefined && typeof value["processStartTime"] !== "string")
|
|
145
|
+
return "invalid";
|
|
146
|
+
return {
|
|
147
|
+
pid: value["pid"],
|
|
148
|
+
startedAt: value["startedAt"],
|
|
149
|
+
...(value["processStartTime"] === undefined ? {} : { processStartTime: value["processStartTime"] }),
|
|
150
|
+
endpoint: value["endpoint"],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return "invalid";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Whether the process a marker records is still that same running process.
|
|
159
|
+
*
|
|
160
|
+
* With both the recorded and the current `/proc` start time available, a
|
|
161
|
+
* mismatch pins down pid reuse; otherwise the pid probe is all there is.
|
|
162
|
+
*/
|
|
163
|
+
export function isOwnershipRecordAlive(record) {
|
|
164
|
+
const currentStartTime = readProcessStartTime(record.pid);
|
|
165
|
+
if (currentStartTime !== undefined && record.processStartTime !== undefined) {
|
|
166
|
+
return currentStartTime === record.processStartTime;
|
|
167
|
+
}
|
|
168
|
+
return isProcessAlive(record.pid);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Linux-only precise process identity: `/proc/<pid>/stat` field 22 (start time
|
|
172
|
+
* in clock ticks since boot). `undefined` off Linux or when the process is
|
|
173
|
+
* gone. The `comm` field may contain spaces and parentheses, so parsing starts
|
|
174
|
+
* after its closing parenthesis.
|
|
175
|
+
*/
|
|
176
|
+
export function readProcessStartTime(pid) {
|
|
177
|
+
try {
|
|
178
|
+
const stat = readFileSync(`/proc/${String(pid)}/stat`, "utf8");
|
|
179
|
+
const closeParen = stat.lastIndexOf(")");
|
|
180
|
+
if (closeParen === -1)
|
|
181
|
+
return undefined;
|
|
182
|
+
const afterComm = stat.slice(closeParen + 2).split(" ");
|
|
183
|
+
return afterComm[19];
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function readOwnershipRecord(markerPath) {
|
|
190
|
+
let content;
|
|
191
|
+
try {
|
|
192
|
+
content = await readFile(markerPath, "utf8");
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (isErrorCode(error, "ENOENT"))
|
|
196
|
+
return undefined;
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
return parseOwnershipRecord(content);
|
|
200
|
+
}
|
|
201
|
+
async function releaseOwnershipMarker(markerPath, record, logger) {
|
|
202
|
+
try {
|
|
203
|
+
const current = await readOwnershipRecord(markerPath);
|
|
204
|
+
if (current === undefined || current === "invalid")
|
|
205
|
+
return;
|
|
206
|
+
// Remove only our own marker: pid plus the wall-clock start makes a newer
|
|
207
|
+
// owner that reused the pid after a takeover race safe from deletion.
|
|
208
|
+
if (current.pid === record.pid && current.startedAt === record.startedAt) {
|
|
209
|
+
await rm(markerPath, { force: true });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
logger?.warn({ err: error, markerPath }, "could not release the session daemon ownership marker; the next start discards it as stale");
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function isProcessAlive(pid) {
|
|
217
|
+
try {
|
|
218
|
+
process.kill(pid, 0);
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
// EPERM means the process exists but belongs to someone else.
|
|
223
|
+
return isErrorCode(error, "EPERM");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function defaultSleep(ms) {
|
|
227
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
228
|
+
}
|
|
229
|
+
function isRecord(value) {
|
|
230
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
231
|
+
}
|
|
232
|
+
function isErrorCode(error, code) {
|
|
233
|
+
return isRecord(error) && error["code"] === code;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=sessiondStateOwnership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessiondStateOwnership.js","sourceRoot":"","sources":["../../../src/server/sessiond/sessiondStateOwnership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Internal sessiond protocol; browser-facing routes consume it through a typed client. */
|
|
2
|
+
export function registerWorkspaceCatalogRoutes(app, dependencies, prefix = "/workspace-catalog") {
|
|
3
|
+
app.get(`${prefix}/provider-runtime`, () => dependencies.providerRuntime);
|
|
4
|
+
app.get(`${prefix}/projects/:projectId/workspaces`, async (request, reply) => {
|
|
5
|
+
try {
|
|
6
|
+
const project = await dependencies.projects.requireProject(request.params.projectId);
|
|
7
|
+
return await dependencies.workspaces.resolve(project);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
return catalogRequestFailed(reply, error);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
app.get(`${prefix}/projects/:projectId/workspaces/:workspaceId`, async (request, reply) => {
|
|
14
|
+
try {
|
|
15
|
+
const project = await dependencies.projects.requireProject(request.params.projectId);
|
|
16
|
+
const resolution = await dependencies.workspaces.resolve(project);
|
|
17
|
+
const workspace = resolution.workspaces.find((candidate) => candidate.id === request.params.workspaceId);
|
|
18
|
+
if (workspace === undefined)
|
|
19
|
+
return await reply.code(404).send({ error: "Workspace not found" });
|
|
20
|
+
return workspace;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return catalogRequestFailed(reply, error);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function catalogRequestFailed(reply, error) {
|
|
28
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29
|
+
return reply.code(message === "Project not found" ? 404 : 500).send({ error: message });
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=workspaceCatalogRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceCatalogRoutes.js","sourceRoot":"","sources":["../../../src/server/sessiond/workspaceCatalogRoutes.ts"],"names":[],"mappings":"AAmBA,2FAA2F;AAC3F,MAAM,UAAU,8BAA8B,CAC5C,GAAoB,EACpB,YAA+C,EAC/C,MAAM,GAAG,oBAAoB;IAE7B,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,mBAAmB,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;IAE1E,GAAG,CAAC,GAAG,CAAoC,GAAG,MAAM,iCAAiC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC9G,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACrF,OAAO,MAAM,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAyD,GAAG,MAAM,8CAA8C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAChJ,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACrF,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAClE,MAAM,SAAS,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACzG,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;YACjG,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmB,EAAE,KAAc;IAC/D,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;AAC1F,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { parseWorkspaceRemovalRequest, WORKSPACE_REMOVAL_REQUEST_BODY_MAX_BYTES, } from "../../shared/workspaceRemovalProtocol.js";
|
|
2
|
+
import { requestCancellation } from "../requestCancellation.js";
|
|
3
|
+
import { workspaceRemovalHttpStatus } from "../workspaces/workspaceRemovalService.js";
|
|
4
|
+
/** Internal sessiond endpoint for host-orchestrated provider workspace removal. */
|
|
5
|
+
export function registerWorkspaceRemovalRoutes(app, dependencies, prefix = "/workspace-removals") {
|
|
6
|
+
app.delete(`${prefix}/projects/:projectId/workspaces/:workspaceId`, { bodyLimit: WORKSPACE_REMOVAL_REQUEST_BODY_MAX_BYTES }, async (request, reply) => {
|
|
7
|
+
let precondition;
|
|
8
|
+
try {
|
|
9
|
+
precondition = parseWorkspaceRemovalRequest(request.body).precondition;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
return reply.code(400).send({ error: errorMessage(error) });
|
|
13
|
+
}
|
|
14
|
+
let project;
|
|
15
|
+
try {
|
|
16
|
+
project = await dependencies.projects.requireProject(request.params.projectId);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
const message = errorMessage(error);
|
|
20
|
+
return reply.code(message === "Project not found" ? 404 : 500).send({ error: message });
|
|
21
|
+
}
|
|
22
|
+
const cancellation = requestCancellation(request, reply);
|
|
23
|
+
try {
|
|
24
|
+
return await dependencies.removals.remove(project, request.params.workspaceId, precondition, cancellation.signal);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
return await removalRequestFailed(reply, error);
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
dependencies.onWorkspacesMutated();
|
|
31
|
+
cancellation.dispose();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function removalRequestFailed(reply, error) {
|
|
36
|
+
return reply.code(workspaceRemovalHttpStatus(error)).send({ error: errorMessage(error) });
|
|
37
|
+
}
|
|
38
|
+
function errorMessage(error) {
|
|
39
|
+
return error instanceof Error ? error.message : String(error);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=workspaceRemovalRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceRemovalRoutes.js","sourceRoot":"","sources":["../../../src/server/sessiond/workspaceRemovalRoutes.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,4BAA4B,EAC5B,wCAAwC,GACzC,MAAM,0CAA0C,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AA0BtF,mFAAmF;AACnF,MAAM,UAAU,8BAA8B,CAC5C,GAAoB,EACpB,YAA+C,EAC/C,MAAM,GAAG,qBAAqB;IAE9B,GAAG,CAAC,MAAM,CACR,GAAG,MAAM,8CAA8C,EACvD,EAAE,SAAS,EAAE,wCAAwC,EAAE,EACvD,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QACvB,IAAI,YAAoB,CAAC;QACzB,IAAI,CAAC;YACH,YAAY,GAAG,4BAA4B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC;QACzE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,OAAgB,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACjF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;YACpC,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,mBAAmB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1F,CAAC;QAED,MAAM,YAAY,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,OAAO,MAAM,YAAY,CAAC,QAAQ,CAAC,MAAM,CACvC,OAAO,EACP,OAAO,CAAC,MAAM,CAAC,WAAW,EAC1B,YAAY,EACZ,YAAY,CAAC,MAAM,CACpB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,MAAM,oBAAoB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,mBAAmB,EAAE,CAAC;YACnC,YAAY,CAAC,OAAO,EAAE,CAAC;QACzB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAmB,EAAE,KAAc;IAC/D,OAAO,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC5F,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|