@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.
Files changed (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/dist/cli.js +1149 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/client/apple-touch-icon.png +0 -0
  6. package/dist/client/assets/CodeViewer-D_Q6ljLV.js +4 -0
  7. package/dist/client/assets/TerminalPanel-CTGixJIz.js +187 -0
  8. package/dist/client/assets/index-C2phil_t.js +5637 -0
  9. package/dist/client/assets/vendor-editor-core-CXO8gGab.js +12 -0
  10. package/dist/client/assets/vendor-editor-languages-CpW4sJsX.js +46 -0
  11. package/dist/client/assets/vendor-editor-legacy-CYBnW6ZU.js +1 -0
  12. package/dist/client/assets/vendor-terminal-BrP-ENHg.css +1 -0
  13. package/dist/client/assets/vendor-terminal-D8k4UKM2.js +35 -0
  14. package/dist/client/favicon.svg +11 -0
  15. package/dist/client/index.html +124 -0
  16. package/dist/client/manifest.webmanifest +24 -0
  17. package/dist/client/pwa-icon-192.png +0 -0
  18. package/dist/client/pwa-icon-512.png +0 -0
  19. package/dist/config.js +505 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/docker/piWebDockerCommandPlan.js +212 -0
  22. package/dist/docker/piWebDockerCommandPlan.js.map +1 -0
  23. package/dist/environment.js +4 -0
  24. package/dist/environment.js.map +1 -0
  25. package/dist/nativeServices/installedServiceDefinitions.js +602 -0
  26. package/dist/nativeServices/installedServiceDefinitions.js.map +1 -0
  27. package/dist/nativeServices/serviceAction.js +174 -0
  28. package/dist/nativeServices/serviceAction.js.map +1 -0
  29. package/dist/nativeServices/serviceDoctor.js +783 -0
  30. package/dist/nativeServices/serviceDoctor.js.map +1 -0
  31. package/dist/nativeServices/serviceInstall.js +35 -0
  32. package/dist/nativeServices/serviceInstall.js.map +1 -0
  33. package/dist/nativeServices/servicePlan.js +358 -0
  34. package/dist/nativeServices/servicePlan.js.map +1 -0
  35. package/dist/nativeServices/serviceProbe.js +447 -0
  36. package/dist/nativeServices/serviceProbe.js.map +1 -0
  37. package/dist/nativeServices/serviceRendering.js +132 -0
  38. package/dist/nativeServices/serviceRendering.js.map +1 -0
  39. package/dist/pi-web-plugins/git/browser/git-contract.js +108 -0
  40. package/dist/pi-web-plugins/git/browser/git-panel.js +609 -0
  41. package/dist/pi-web-plugins/git/browser/gitFileList.js +43 -0
  42. package/dist/pi-web-plugins/git/browser/gitFileShared.js +16 -0
  43. package/dist/pi-web-plugins/git/browser/gitFileTree.js +81 -0
  44. package/dist/pi-web-plugins/git/browser/gitFileViewPreference.js +35 -0
  45. package/dist/pi-web-plugins/git/browser/gitRoute.js +42 -0
  46. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +10 -0
  47. package/dist/pi-web-plugins/git/browser/unifiedDiff.js +301 -0
  48. package/dist/pi-web-plugins/git/git-backend.js +439 -0
  49. package/dist/pi-web-plugins/git/package.json +16 -0
  50. package/dist/pi-web-plugins/git/server-plugin.js +176 -0
  51. package/dist/pi-web-plugins/info/infoInternals.js +222 -0
  52. package/dist/pi-web-plugins/info/package.json +9 -0
  53. package/dist/pi-web-plugins/info/pi-web-plugin.js +48 -0
  54. package/dist/pi-web-plugins/relays/markdownDocument.js +81 -0
  55. package/dist/pi-web-plugins/relays/package.json +9 -0
  56. package/dist/pi-web-plugins/relays/pi-web-plugin.js +44 -0
  57. package/dist/pi-web-plugins/relays/relayDiscovery.js +228 -0
  58. package/dist/pi-web-plugins/relays/relaysPanelElement.js +550 -0
  59. package/dist/pi-web-plugins/relays/vendor/README.md +24 -0
  60. package/dist/pi-web-plugins/relays/vendor/marked.esm.js +76 -0
  61. package/dist/pi-web-plugins/updates/package.json +9 -0
  62. package/dist/pi-web-plugins/updates/pi-web-plugin.js +185 -0
  63. package/dist/pi-web-plugins/updates/updatesLogic.js +97 -0
  64. package/dist/pi-web-plugins/workspace-tasks/config.js +91 -0
  65. package/dist/pi-web-plugins/workspace-tasks/package.json +9 -0
  66. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +48 -0
  67. package/dist/pi-web-plugins/workspace-tasks/taskRunner.js +12 -0
  68. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +288 -0
  69. package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +47 -0
  70. package/dist/piWebVersionReport.js +278 -0
  71. package/dist/piWebVersionReport.js.map +1 -0
  72. package/dist/plugin-api.d.ts +222 -0
  73. package/dist/pluginRecoveryCli.js +172 -0
  74. package/dist/pluginRecoveryCli.js.map +1 -0
  75. package/dist/server/activeAgentProfileProvider.js +25 -0
  76. package/dist/server/activeAgentProfileProvider.js.map +1 -0
  77. package/dist/server/activity/workspaceActivityService.js +106 -0
  78. package/dist/server/activity/workspaceActivityService.js.map +1 -0
  79. package/dist/server/app.js +218 -0
  80. package/dist/server/app.js.map +1 -0
  81. package/dist/server/browserMessageProjection.js +54 -0
  82. package/dist/server/browserMessageProjection.js.map +1 -0
  83. package/dist/server/configRoutes.js +293 -0
  84. package/dist/server/configRoutes.js.map +1 -0
  85. package/dist/server/diagnostics/nodePtyNativeModule.js +36 -0
  86. package/dist/server/diagnostics/nodePtyNativeModule.js.map +1 -0
  87. package/dist/server/diagnostics/nodePtySpawnHelper.js +135 -0
  88. package/dist/server/diagnostics/nodePtySpawnHelper.js.map +1 -0
  89. package/dist/server/git/gitEnv.js +15 -0
  90. package/dist/server/git/gitEnv.js.map +1 -0
  91. package/dist/server/goals/goalArchive.js +184 -0
  92. package/dist/server/goals/goalArchive.js.map +1 -0
  93. package/dist/server/goals/goalFile.js +200 -0
  94. package/dist/server/goals/goalFile.js.map +1 -0
  95. package/dist/server/goals/goalStore.js +65 -0
  96. package/dist/server/goals/goalStore.js.map +1 -0
  97. package/dist/server/index.js +7 -0
  98. package/dist/server/index.js.map +1 -0
  99. package/dist/server/machines/machineClient.js +191 -0
  100. package/dist/server/machines/machineClient.js.map +1 -0
  101. package/dist/server/machines/machinePluginProxyRoutes.js +247 -0
  102. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
  103. package/dist/server/machines/machineProxyRoutes.js +318 -0
  104. package/dist/server/machines/machineProxyRoutes.js.map +1 -0
  105. package/dist/server/machines/machineRoutes.js +56 -0
  106. package/dist/server/machines/machineRoutes.js.map +1 -0
  107. package/dist/server/machines/machineService.js +274 -0
  108. package/dist/server/machines/machineService.js.map +1 -0
  109. package/dist/server/machines/machineStore.js +143 -0
  110. package/dist/server/machines/machineStore.js.map +1 -0
  111. package/dist/server/piPackageRoutes.js +91 -0
  112. package/dist/server/piPackageRoutes.js.map +1 -0
  113. package/dist/server/piPackageService.js +101 -0
  114. package/dist/server/piPackageService.js.map +1 -0
  115. package/dist/server/piWebPluginCatalog.js +584 -0
  116. package/dist/server/piWebPluginCatalog.js.map +1 -0
  117. package/dist/server/piWebPluginLifecycle.js +162 -0
  118. package/dist/server/piWebPluginLifecycle.js.map +1 -0
  119. package/dist/server/piWebPluginService.js +224 -0
  120. package/dist/server/piWebPluginService.js.map +1 -0
  121. package/dist/server/piWebReleaseLookupCache.js +37 -0
  122. package/dist/server/piWebReleaseLookupCache.js.map +1 -0
  123. package/dist/server/piWebStatus.js +624 -0
  124. package/dist/server/piWebStatus.js.map +1 -0
  125. package/dist/server/piWebStatusCache.js +45 -0
  126. package/dist/server/piWebStatusCache.js.map +1 -0
  127. package/dist/server/plugins/pluginBackendProxyRoutes.js +69 -0
  128. package/dist/server/plugins/pluginBackendProxyRoutes.js.map +1 -0
  129. package/dist/server/plugins/serverPluginExec.js +184 -0
  130. package/dist/server/plugins/serverPluginExec.js.map +1 -0
  131. package/dist/server/plugins/serverPluginRuntime.js +480 -0
  132. package/dist/server/plugins/serverPluginRuntime.js.map +1 -0
  133. package/dist/server/projectTrustRoutes.js +80 -0
  134. package/dist/server/projectTrustRoutes.js.map +1 -0
  135. package/dist/server/projects/directorySuggestions.js +207 -0
  136. package/dist/server/projects/directorySuggestions.js.map +1 -0
  137. package/dist/server/projects/projectService.js +33 -0
  138. package/dist/server/projects/projectService.js.map +1 -0
  139. package/dist/server/realtime/sessionEventHub.js +93 -0
  140. package/dist/server/realtime/sessionEventHub.js.map +1 -0
  141. package/dist/server/requestCancellation.js +32 -0
  142. package/dist/server/requestCancellation.js.map +1 -0
  143. package/dist/server/sessiond/agentHttpDispatcher.js +108 -0
  144. package/dist/server/sessiond/agentHttpDispatcher.js.map +1 -0
  145. package/dist/server/sessiond/agentProcessEnvironment.js +61 -0
  146. package/dist/server/sessiond/agentProcessEnvironment.js.map +1 -0
  147. package/dist/server/sessiond/pluginBackendRoutes.js +64 -0
  148. package/dist/server/sessiond/pluginBackendRoutes.js.map +1 -0
  149. package/dist/server/sessiond/sessionDaemonShutdown.js +31 -0
  150. package/dist/server/sessiond/sessionDaemonShutdown.js.map +1 -0
  151. package/dist/server/sessiond/sessionProxyRoutes.js +61 -0
  152. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -0
  153. package/dist/server/sessiond/sessionServiceDependencies.js +34 -0
  154. package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -0
  155. package/dist/server/sessiond/sessiondStateOwnership.js +235 -0
  156. package/dist/server/sessiond/sessiondStateOwnership.js.map +1 -0
  157. package/dist/server/sessiond/workspaceCatalogRoutes.js +31 -0
  158. package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -0
  159. package/dist/server/sessiond/workspaceRemovalRoutes.js +41 -0
  160. package/dist/server/sessiond/workspaceRemovalRoutes.js.map +1 -0
  161. package/dist/server/sessiond.js +387 -0
  162. package/dist/server/sessiond.js.map +1 -0
  163. package/dist/server/sessions/askUserTool.js +102 -0
  164. package/dist/server/sessions/askUserTool.js.map +1 -0
  165. package/dist/server/sessions/attachmentService.js +119 -0
  166. package/dist/server/sessions/attachmentService.js.map +1 -0
  167. package/dist/server/sessions/authProviderOptions.js +50 -0
  168. package/dist/server/sessions/authProviderOptions.js.map +1 -0
  169. package/dist/server/sessions/authRoutes.js +59 -0
  170. package/dist/server/sessions/authRoutes.js.map +1 -0
  171. package/dist/server/sessions/authService.js +122 -0
  172. package/dist/server/sessions/authService.js.map +1 -0
  173. package/dist/server/sessions/builtinCommands.js +27 -0
  174. package/dist/server/sessions/builtinCommands.js.map +1 -0
  175. package/dist/server/sessions/dockerEnvironmentFacts.js +254 -0
  176. package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -0
  177. package/dist/server/sessions/editPreview.js +196 -0
  178. package/dist/server/sessions/editPreview.js.map +1 -0
  179. package/dist/server/sessions/extensionDialogWaiters.js +76 -0
  180. package/dist/server/sessions/extensionDialogWaiters.js.map +1 -0
  181. package/dist/server/sessions/globalProviderPolicy.js +167 -0
  182. package/dist/server/sessions/globalProviderPolicy.js.map +1 -0
  183. package/dist/server/sessions/interruptedRunStore.js +147 -0
  184. package/dist/server/sessions/interruptedRunStore.js.map +1 -0
  185. package/dist/server/sessions/messagePaging.js +43 -0
  186. package/dist/server/sessions/messagePaging.js.map +1 -0
  187. package/dist/server/sessions/modelCatalogRefresher.js +193 -0
  188. package/dist/server/sessions/modelCatalogRefresher.js.map +1 -0
  189. package/dist/server/sessions/oauthLoginFlowService.js +346 -0
  190. package/dist/server/sessions/oauthLoginFlowService.js.map +1 -0
  191. package/dist/server/sessions/pendingAskStore.js +275 -0
  192. package/dist/server/sessions/pendingAskStore.js.map +1 -0
  193. package/dist/server/sessions/pendingExtensionDialogStore.js +196 -0
  194. package/dist/server/sessions/pendingExtensionDialogStore.js.map +1 -0
  195. package/dist/server/sessions/piSessionManagerGateway.js +246 -0
  196. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -0
  197. package/dist/server/sessions/piSessionService.js +4059 -0
  198. package/dist/server/sessions/piSessionService.js.map +1 -0
  199. package/dist/server/sessions/plainTextTheme.js +112 -0
  200. package/dist/server/sessions/plainTextTheme.js.map +1 -0
  201. package/dist/server/sessions/sessionArchiveStore.js +273 -0
  202. package/dist/server/sessions/sessionArchiveStore.js.map +1 -0
  203. package/dist/server/sessions/sessionArchiveTree.js +35 -0
  204. package/dist/server/sessions/sessionArchiveTree.js.map +1 -0
  205. package/dist/server/sessions/sessionCleanup.js +157 -0
  206. package/dist/server/sessions/sessionCleanup.js.map +1 -0
  207. package/dist/server/sessions/sessionCommandService.js +336 -0
  208. package/dist/server/sessions/sessionCommandService.js.map +1 -0
  209. package/dist/server/sessions/sessionEnvironmentFacts.js +48 -0
  210. package/dist/server/sessions/sessionEnvironmentFacts.js.map +1 -0
  211. package/dist/server/sessions/sessionFileFormat.js +27 -0
  212. package/dist/server/sessions/sessionFileFormat.js.map +1 -0
  213. package/dist/server/sessions/sessionFileHeader.js +104 -0
  214. package/dist/server/sessions/sessionFileHeader.js.map +1 -0
  215. package/dist/server/sessions/sessionModelScope.js +141 -0
  216. package/dist/server/sessions/sessionModelScope.js.map +1 -0
  217. package/dist/server/sessions/sessionNameGenerator.js +90 -0
  218. package/dist/server/sessions/sessionNameGenerator.js.map +1 -0
  219. package/dist/server/sessions/sessionNotificationStore.js +484 -0
  220. package/dist/server/sessions/sessionNotificationStore.js.map +1 -0
  221. package/dist/server/sessions/sessionRoutes.js +744 -0
  222. package/dist/server/sessions/sessionRoutes.js.map +1 -0
  223. package/dist/server/sessions/sessionRuntimeStore.js +2 -0
  224. package/dist/server/sessions/sessionRuntimeStore.js.map +1 -0
  225. package/dist/server/sessions/sessionService.js +2 -0
  226. package/dist/server/sessions/sessionService.js.map +1 -0
  227. package/dist/server/sessions/sessionSummaryScanner.js +491 -0
  228. package/dist/server/sessions/sessionSummaryScanner.js.map +1 -0
  229. package/dist/server/sessions/sessionTreeProjection.js +250 -0
  230. package/dist/server/sessions/sessionTreeProjection.js.map +1 -0
  231. package/dist/server/sessions/sessionUnreadStore.js +520 -0
  232. package/dist/server/sessions/sessionUnreadStore.js.map +1 -0
  233. package/dist/server/sessions/shutdownDrain.js +73 -0
  234. package/dist/server/sessions/shutdownDrain.js.map +1 -0
  235. package/dist/server/sessions/spawnSessionTool.js +48 -0
  236. package/dist/server/sessions/spawnSessionTool.js.map +1 -0
  237. package/dist/server/sessions/spawnSubsessionTool.js +216 -0
  238. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -0
  239. package/dist/server/sessions/spawnTargetResolver.js +23 -0
  240. package/dist/server/sessions/spawnTargetResolver.js.map +1 -0
  241. package/dist/server/sessions/subsessionTranscript.js +235 -0
  242. package/dist/server/sessions/subsessionTranscript.js.map +1 -0
  243. package/dist/server/status/machineStatusRoutes.js +8 -0
  244. package/dist/server/status/machineStatusRoutes.js.map +1 -0
  245. package/dist/server/status/machineStatusService.js +181 -0
  246. package/dist/server/status/machineStatusService.js.map +1 -0
  247. package/dist/server/status/workspaceAttribution.js +87 -0
  248. package/dist/server/status/workspaceAttribution.js.map +1 -0
  249. package/dist/server/storage/projectStore.js +88 -0
  250. package/dist/server/storage/projectStore.js.map +1 -0
  251. package/dist/server/terminalProxyRoutes.js +141 -0
  252. package/dist/server/terminalProxyRoutes.js.map +1 -0
  253. package/dist/server/terminals/terminalRoutes.js +155 -0
  254. package/dist/server/terminals/terminalRoutes.js.map +1 -0
  255. package/dist/server/terminals/terminalService.js +305 -0
  256. package/dist/server/terminals/terminalService.js.map +1 -0
  257. package/dist/server/terminals/terminalSize.js +17 -0
  258. package/dist/server/terminals/terminalSize.js.map +1 -0
  259. package/dist/server/types.js +2 -0
  260. package/dist/server/types.js.map +1 -0
  261. package/dist/server/updates/fleetRoutes.js +111 -0
  262. package/dist/server/updates/fleetRoutes.js.map +1 -0
  263. package/dist/server/updates/restartRoutes.js +48 -0
  264. package/dist/server/updates/restartRoutes.js.map +1 -0
  265. package/dist/server/updates/selfUpdateRoutes.js +145 -0
  266. package/dist/server/updates/selfUpdateRoutes.js.map +1 -0
  267. package/dist/server/webSocketBridge.js +32 -0
  268. package/dist/server/webSocketBridge.js.map +1 -0
  269. package/dist/server/workingDirectory.js +44 -0
  270. package/dist/server/workingDirectory.js.map +1 -0
  271. package/dist/server/workspaceExplorerRoutes.js +147 -0
  272. package/dist/server/workspaceExplorerRoutes.js.map +1 -0
  273. package/dist/server/workspaces/effectivePathAccess.js +8 -0
  274. package/dist/server/workspaces/effectivePathAccess.js.map +1 -0
  275. package/dist/server/workspaces/fileContentService.js +190 -0
  276. package/dist/server/workspaces/fileContentService.js.map +1 -0
  277. package/dist/server/workspaces/filePreviewResponseHeaders.js +18 -0
  278. package/dist/server/workspaces/filePreviewResponseHeaders.js.map +1 -0
  279. package/dist/server/workspaces/filePreviewResponsePolicy.js +55 -0
  280. package/dist/server/workspaces/filePreviewResponsePolicy.js.map +1 -0
  281. package/dist/server/workspaces/filePreviewService.js +81 -0
  282. package/dist/server/workspaces/filePreviewService.js.map +1 -0
  283. package/dist/server/workspaces/fileSuggestions.js +520 -0
  284. package/dist/server/workspaces/fileSuggestions.js.map +1 -0
  285. package/dist/server/workspaces/fileTreeService.js +35 -0
  286. package/dist/server/workspaces/fileTreeService.js.map +1 -0
  287. package/dist/server/workspaces/pathAccessPolicy.js +90 -0
  288. package/dist/server/workspaces/pathAccessPolicy.js.map +1 -0
  289. package/dist/server/workspaces/pathSafety.js +45 -0
  290. package/dist/server/workspaces/pathSafety.js.map +1 -0
  291. package/dist/server/workspaces/projectPiWebConfig.js +61 -0
  292. package/dist/server/workspaces/projectPiWebConfig.js.map +1 -0
  293. package/dist/server/workspaces/projectWorkspaceCwds.js +17 -0
  294. package/dist/server/workspaces/projectWorkspaceCwds.js.map +1 -0
  295. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +402 -0
  296. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -0
  297. package/dist/server/workspaces/workspaceCatalog.js +47 -0
  298. package/dist/server/workspaces/workspaceCatalog.js.map +1 -0
  299. package/dist/server/workspaces/workspaceContext.js +6 -0
  300. package/dist/server/workspaces/workspaceContext.js.map +1 -0
  301. package/dist/server/workspaces/workspaceDeletionRoutes.js +49 -0
  302. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
  303. package/dist/server/workspaces/workspaceProviderRegistry.js +651 -0
  304. package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -0
  305. package/dist/server/workspaces/workspaceRemovalService.js +256 -0
  306. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -0
  307. package/dist/server/workspaces/workspaceRouteErrors.js +7 -0
  308. package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -0
  309. package/dist/server/workspaces/worktreePreRemoveHook.js +39 -0
  310. package/dist/server/workspaces/worktreePreRemoveHook.js.map +1 -0
  311. package/dist/server-plugin-api.d.ts +140 -0
  312. package/dist/server-plugin-api.js +2 -0
  313. package/dist/server-plugin-api.js.map +1 -0
  314. package/dist/serverPluginRecovery.js +138 -0
  315. package/dist/serverPluginRecovery.js.map +1 -0
  316. package/dist/sessiond/activeAgentProfile.js +12 -0
  317. package/dist/sessiond/activeAgentProfile.js.map +1 -0
  318. package/dist/sessiond/config.js +20 -0
  319. package/dist/sessiond/config.js.map +1 -0
  320. package/dist/sessiond/sessionDaemonClient.js +105 -0
  321. package/dist/sessiond/sessionDaemonClient.js.map +1 -0
  322. package/dist/shared/activeAgentProfile.js +37 -0
  323. package/dist/shared/activeAgentProfile.js.map +1 -0
  324. package/dist/shared/activity.js +16 -0
  325. package/dist/shared/activity.js.map +1 -0
  326. package/dist/shared/apiTypes.js +41 -0
  327. package/dist/shared/apiTypes.js.map +1 -0
  328. package/dist/shared/capabilities.js +37 -0
  329. package/dist/shared/capabilities.js.map +1 -0
  330. package/dist/shared/federatedRoutes.js +127 -0
  331. package/dist/shared/federatedRoutes.js.map +1 -0
  332. package/dist/shared/machinePluginIds.js +43 -0
  333. package/dist/shared/machinePluginIds.js.map +1 -0
  334. package/dist/shared/machineStatus.js +94 -0
  335. package/dist/shared/machineStatus.js.map +1 -0
  336. package/dist/shared/piWebStatusParsing.js +141 -0
  337. package/dist/shared/piWebStatusParsing.js.map +1 -0
  338. package/dist/shared/pluginApiTypes.d.ts +150 -0
  339. package/dist/shared/pluginApiTypes.js +3 -0
  340. package/dist/shared/pluginApiTypes.js.map +1 -0
  341. package/dist/shared/pluginBackendProtocol.js +110 -0
  342. package/dist/shared/pluginBackendProtocol.js.map +1 -0
  343. package/dist/shared/pluginIds.js +10 -0
  344. package/dist/shared/pluginIds.js.map +1 -0
  345. package/dist/shared/pluginRecoveryCommands.js +14 -0
  346. package/dist/shared/pluginRecoveryCommands.js.map +1 -0
  347. package/dist/shared/promptAttachments.js +92 -0
  348. package/dist/shared/promptAttachments.js.map +1 -0
  349. package/dist/shared/selfUpdate.js +3 -0
  350. package/dist/shared/selfUpdate.js.map +1 -0
  351. package/dist/shared/thinkingLevels.js +31 -0
  352. package/dist/shared/thinkingLevels.js.map +1 -0
  353. package/dist/shared/workspaceDeletion.js +12 -0
  354. package/dist/shared/workspaceDeletion.js.map +1 -0
  355. package/dist/shared/workspaceFiles.js +42 -0
  356. package/dist/shared/workspaceFiles.js.map +1 -0
  357. package/dist/shared/workspaceRemovalProtocol.js +24 -0
  358. package/dist/shared/workspaceRemovalProtocol.js.map +1 -0
  359. package/docs/assets/favicon.svg +11 -0
  360. package/docs/assets/pi-web-banner.png +0 -0
  361. package/docs/assets/pi-web-desktop.png +0 -0
  362. package/docs/assets/pi-web-mobile.png +0 -0
  363. package/docs/assets/pi-web-tablet.png +0 -0
  364. package/docs/config.md +444 -0
  365. package/docs/plugins.md +1305 -0
  366. package/examples/workspace-provider-plugin/README.md +52 -0
  367. package/examples/workspace-provider-plugin/package.json +25 -0
  368. package/examples/workspace-provider-plugin/src/browser/index.ts +69 -0
  369. package/examples/workspace-provider-plugin/src/server.ts +64 -0
  370. package/examples/workspace-provider-plugin/tsconfig.json +21 -0
  371. package/extensions/README-pi-web-restart-migration.md +45 -0
  372. package/extensions/pi-web.ts +324 -0
  373. package/install.sh +5 -0
  374. package/package.json +173 -0
  375. package/plugin-api.d.ts +1 -0
  376. package/server-plugin-api.d.ts +1 -0
@@ -0,0 +1,624 @@
1
+ import { execFile } from "node:child_process";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { readFile, realpath, stat } from "node:fs/promises";
4
+ import { promisify } from "node:util";
5
+ import { homedir } from "node:os";
6
+ import { dirname, join, relative, resolve, sep } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+ import { DefaultPackageManager, SettingsManager, VERSION as PI_CODING_AGENT_VERSION } from "@earendil-works/pi-coding-agent";
9
+ import { effectivePiWebCapabilities, WEB_RUNTIME_CAPABILITIES } from "../shared/capabilities.js";
10
+ import { piWebDockerCommand } from "../docker/piWebDockerCommandPlan.js";
11
+ import { parsePiWebRuntimeComponent } from "../shared/piWebStatusParsing.js";
12
+ import { SessionDaemonClient } from "../sessiond/sessionDaemonClient.js";
13
+ import { isHostAbsoluteAgentDir, loadPiWebConfig, PI_CODING_AGENT_DIR_ENV } from "../config.js";
14
+ import { createPiWebReleaseLookupCache } from "./piWebReleaseLookupCache.js";
15
+ const PI_WEB_PACKAGE_NAME = "@vincenthanxiaodu/pi-web";
16
+ const PI_WEB_NPM_SOURCE = `npm:${PI_WEB_PACKAGE_NAME}`;
17
+ const DEFAULT_VERSION = "0.0.0-dev";
18
+ const VERSION_CHECK_TIMEOUT_MS = 5000;
19
+ const execFileAsync = promisify(execFile);
20
+ const serviceRefs = {
21
+ sessiond: {
22
+ id: "sessiond",
23
+ systemdName: "pi-web-sessiond.service",
24
+ launchdLabel: "com.pi-web.sessiond",
25
+ launchdPlistName: "com.pi-web.sessiond.plist",
26
+ },
27
+ web: {
28
+ id: "web",
29
+ systemdName: "pi-web.service",
30
+ launchdLabel: "com.pi-web.web",
31
+ launchdPlistName: "com.pi-web.web.plist",
32
+ },
33
+ uiDev: {
34
+ id: "uiDev",
35
+ systemdName: "pi-web-ui-dev.service",
36
+ launchdLabel: "com.pi-web.ui-dev",
37
+ launchdPlistName: "com.pi-web.ui-dev.plist",
38
+ },
39
+ };
40
+ const startServiceOrder = ["sessiond", "web", "uiDev"];
41
+ // Restart web/UI before sessiond: when the restart command runs in a pi-web
42
+ // terminal (owned by sessiond), restarting sessiond kills the command, so any
43
+ // services listed after it would never be restarted.
44
+ const restartServiceOrder = ["web", "uiDev", "sessiond"];
45
+ const latestReleaseLookupCache = createPiWebReleaseLookupCache(fetchLatestNpmVersion);
46
+ const runtimePackageInfo = readPackageInfoSync();
47
+ export function getPiWebRuntimeComponent(component, capabilities = [], deprecatedAgentInputs = []) {
48
+ return {
49
+ component,
50
+ label: component === "web" ? "Web/UI" : "Session daemon",
51
+ runtimeVersion: runtimePackageInfo?.version ?? DEFAULT_VERSION,
52
+ piVersion: PI_CODING_AGENT_VERSION,
53
+ available: true,
54
+ capabilities: [...capabilities],
55
+ ...(deprecatedAgentInputs.length === 0 ? {} : { deprecatedAgentInputs }),
56
+ };
57
+ }
58
+ /**
59
+ * The web component's runtime report with deprecated-input detection contained
60
+ * at the component boundary: a malformed config file must not blank the whole
61
+ * runtime report (the endpoint has no error handler, and federation peers
62
+ * would mark the machine failed). Version and capabilities stay intact and
63
+ * only the undetectable web-sourced deprecated inputs are omitted; the failure
64
+ * travels through the component error channel, the same channel
65
+ * `unavailableSessiondRuntime` uses for the daemon.
66
+ */
67
+ function webRuntimeComponent(loadConfig) {
68
+ try {
69
+ return getPiWebRuntimeComponent("web", WEB_RUNTIME_CAPABILITIES, loadConfig().deprecatedAgentInputs);
70
+ }
71
+ catch (error) {
72
+ return {
73
+ ...getPiWebRuntimeComponent("web", WEB_RUNTIME_CAPABILITIES),
74
+ error: `Could not check for deprecated agent configuration inputs: ${error instanceof Error ? error.message : String(error)}`,
75
+ };
76
+ }
77
+ }
78
+ export async function getPiWebRuntime(daemon = new SessionDaemonClient(), options = {}) {
79
+ const web = webRuntimeComponent(options.loadConfig ?? loadPiWebConfig);
80
+ const sessiond = await getSessiondRuntimeComponent(daemon);
81
+ return {
82
+ packageName: PI_WEB_PACKAGE_NAME,
83
+ generatedAt: new Date().toISOString(),
84
+ components: { web, sessiond },
85
+ capabilities: effectivePiWebCapabilities({ web, sessiond }),
86
+ };
87
+ }
88
+ export async function getPiWebComponentStatus(component, options = {}) {
89
+ const [installed, installation] = await Promise.all([
90
+ readInstalledPackageInfo(),
91
+ detectPiWebInstallation(options.activeAgentProfile?.dir),
92
+ ]);
93
+ const runtimeVersion = runtimePackageInfo?.version ?? DEFAULT_VERSION;
94
+ const installedVersion = installed?.version;
95
+ return {
96
+ component,
97
+ label: component === "web" ? "Web/UI" : "Session daemon",
98
+ runtimeVersion,
99
+ ...(installedVersion === undefined ? {} : { installedVersion }),
100
+ piVersion: PI_CODING_AGENT_VERSION,
101
+ stale: isInstalledVersionNewer(installedVersion, runtimeVersion),
102
+ available: true,
103
+ installation,
104
+ };
105
+ }
106
+ export async function getPiWebVersionStatus(daemon = new SessionDaemonClient(), options = {}) {
107
+ const [web, sessiond] = await Promise.all([
108
+ getPiWebComponentStatus("web", options),
109
+ getSessiondComponentStatus(daemon, options),
110
+ ]);
111
+ return {
112
+ packageName: PI_WEB_PACKAGE_NAME,
113
+ generatedAt: new Date().toISOString(),
114
+ components: { web, sessiond },
115
+ };
116
+ }
117
+ export async function getPiWebStatus(daemon = new SessionDaemonClient(), options = {}) {
118
+ const versionStatus = await getPiWebVersionStatus(daemon, options);
119
+ const { web, sessiond } = versionStatus.components;
120
+ const release = await getLatestReleaseStatus(web.installedVersion ?? web.runtimeVersion ?? DEFAULT_VERSION, options.forceReleaseCheck === true);
121
+ const components = { web, sessiond };
122
+ const commands = await commandsFor(components, {
123
+ activeAgentProfile: options.activeAgentProfile,
124
+ hasCommand: options.hasCommand ?? hasCommand,
125
+ });
126
+ const messages = buildMessages(components, release, commands);
127
+ return {
128
+ ...versionStatus,
129
+ release,
130
+ commands,
131
+ messages,
132
+ };
133
+ }
134
+ export function comparePackageVersions(leftVersion, rightVersion) {
135
+ const left = parsePackageVersion(leftVersion);
136
+ const right = parsePackageVersion(rightVersion);
137
+ if (left === undefined || right === undefined)
138
+ return undefined;
139
+ if (left.major !== right.major)
140
+ return left.major - right.major;
141
+ if (left.minor !== right.minor)
142
+ return left.minor - right.minor;
143
+ if (left.patch !== right.patch)
144
+ return left.patch - right.patch;
145
+ if (left.prerelease === right.prerelease)
146
+ return 0;
147
+ if (left.prerelease === undefined)
148
+ return 1;
149
+ if (right.prerelease === undefined)
150
+ return -1;
151
+ return left.prerelease.localeCompare(right.prerelease);
152
+ }
153
+ function readPackageInfoSync() {
154
+ const path = packageJsonPath();
155
+ try {
156
+ return parsePackageInfo(JSON.parse(readFileSync(path, "utf8")), path);
157
+ }
158
+ catch {
159
+ return undefined;
160
+ }
161
+ }
162
+ async function readInstalledPackageInfo() {
163
+ const path = packageJsonPath();
164
+ try {
165
+ await stat(path);
166
+ return parsePackageInfo(JSON.parse(await readFile(path, "utf8")), path);
167
+ }
168
+ catch {
169
+ return undefined;
170
+ }
171
+ }
172
+ function packageJsonPath() {
173
+ return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
174
+ }
175
+ function parsePackageInfo(value, path) {
176
+ if (!isRecord(value))
177
+ return undefined;
178
+ const name = value["name"];
179
+ const version = value["version"];
180
+ if (typeof name !== "string" || name === "" || typeof version !== "string" || version === "")
181
+ return undefined;
182
+ return { name, version, path };
183
+ }
184
+ async function detectPiWebInstallation(agentDir) {
185
+ const docker = detectDockerInstallation();
186
+ if (docker !== undefined)
187
+ return docker;
188
+ const root = packageRootPath();
189
+ const realRoot = await realPathOrSelf(root);
190
+ if (agentDir !== undefined) {
191
+ const piPackage = await detectPiPackageInstallation(realRoot, root, agentDir);
192
+ if (piPackage !== undefined)
193
+ return piPackage;
194
+ }
195
+ const npmGlobal = await detectNpmGlobalInstallation(realRoot, root);
196
+ if (npmGlobal !== undefined)
197
+ return npmGlobal;
198
+ return { kind: "local", path: root };
199
+ }
200
+ function detectDockerInstallation() {
201
+ if (!isTruthyEnv("PI_WEB_DOCKER_RUNTIME"))
202
+ return undefined;
203
+ const dockerMode = dockerModeFromEnv(process.env["PI_WEB_DOCKER_MODE"]) ?? inferredDockerModeFromRoots();
204
+ const path = dockerRootPathFromEnv(dockerMode);
205
+ return {
206
+ kind: "docker",
207
+ ...(path === undefined ? {} : { path }),
208
+ ...(dockerMode === undefined ? {} : { dockerMode }),
209
+ };
210
+ }
211
+ function dockerModeFromEnv(value) {
212
+ return value === "runtime" || value === "dev" ? value : undefined;
213
+ }
214
+ function inferredDockerModeFromRoots() {
215
+ if (firstNonEmptyEnv("PI_WEB_DOCKER_DEV_REPO_ROOT") !== undefined)
216
+ return "dev";
217
+ if (firstNonEmptyEnv("PI_WEB_DOCKER_INSTALL_DIR") !== undefined)
218
+ return "runtime";
219
+ return undefined;
220
+ }
221
+ function dockerRootPathFromEnv(mode) {
222
+ if (mode === "dev")
223
+ return firstNonEmptyEnv("PI_WEB_DOCKER_DEV_REPO_ROOT", "PI_WEB_DOCKER_INSTALL_DIR");
224
+ if (mode === "runtime")
225
+ return firstNonEmptyEnv("PI_WEB_DOCKER_INSTALL_DIR", "PI_WEB_DOCKER_DEV_REPO_ROOT");
226
+ return firstNonEmptyEnv("PI_WEB_DOCKER_INSTALL_DIR", "PI_WEB_DOCKER_DEV_REPO_ROOT");
227
+ }
228
+ function firstNonEmptyEnv(...keys) {
229
+ for (const key of keys) {
230
+ const value = process.env[key];
231
+ if (value !== undefined && value !== "")
232
+ return value;
233
+ }
234
+ return undefined;
235
+ }
236
+ function isTruthyEnv(key) {
237
+ const value = process.env[key];
238
+ return value !== undefined && value !== "" && value !== "0" && value.toLowerCase() !== "false";
239
+ }
240
+ async function detectPiPackageInstallation(realRoot, displayPath, agentDir) {
241
+ try {
242
+ const packageManager = new DefaultPackageManager({
243
+ cwd: process.cwd(),
244
+ agentDir,
245
+ settingsManager: SettingsManager.create(process.cwd(), agentDir),
246
+ });
247
+ for (const configuredPackage of packageManager.listConfiguredPackages()) {
248
+ const installedPath = configuredPackage.installedPath ?? packageManager.getInstalledPath(configuredPackage.source, configuredPackage.scope);
249
+ if (installedPath === undefined)
250
+ continue;
251
+ const realInstalledPath = await realPathOrSelf(installedPath);
252
+ if (isSameOrWithin(realInstalledPath, realRoot) || isSameOrWithin(realRoot, realInstalledPath)) {
253
+ return { kind: "pi-package", path: displayPath, source: configuredPackage.source, scope: configuredPackage.scope };
254
+ }
255
+ }
256
+ }
257
+ catch {
258
+ return undefined;
259
+ }
260
+ return undefined;
261
+ }
262
+ async function detectNpmGlobalInstallation(realRoot, displayPath) {
263
+ const npmRoot = await npmGlobalRoot();
264
+ if (npmRoot === undefined)
265
+ return undefined;
266
+ const realNpmRoot = await realPathOrSelf(npmRoot);
267
+ if (!isSameOrWithin(realNpmRoot, realRoot))
268
+ return undefined;
269
+ return { kind: "npm-global", path: displayPath, npmRoot };
270
+ }
271
+ async function npmGlobalRoot() {
272
+ try {
273
+ const { stdout } = await execFileAsync("npm", ["root", "-g"], { encoding: "utf8" });
274
+ const root = stdout.trim();
275
+ return root === "" ? undefined : root;
276
+ }
277
+ catch {
278
+ return undefined;
279
+ }
280
+ }
281
+ function packageRootPath() {
282
+ return dirname(packageJsonPath());
283
+ }
284
+ async function realPathOrSelf(path) {
285
+ return realpath(path).catch(() => resolve(path));
286
+ }
287
+ function isSameOrWithin(parent, candidate) {
288
+ const rel = relative(parent, candidate);
289
+ return rel === "" || (!rel.startsWith("..") && !rel.startsWith(sep));
290
+ }
291
+ async function getSessiondRuntimeComponent(daemon) {
292
+ try {
293
+ const upstream = await daemon.request("GET", "/runtime");
294
+ if (upstream.statusCode < 200 || upstream.statusCode >= 300) {
295
+ return unavailableSessiondRuntime(`runtime check returned HTTP ${String(upstream.statusCode)}`);
296
+ }
297
+ const parsed = upstream.body === "" ? undefined : JSON.parse(upstream.body);
298
+ const runtime = parsePiWebRuntimeComponent(parsed);
299
+ if (runtime !== undefined)
300
+ return runtime;
301
+ return unavailableSessiondRuntime("runtime response did not include valid runtime information");
302
+ }
303
+ catch (error) {
304
+ return unavailableSessiondRuntime(error instanceof Error ? error.message : String(error));
305
+ }
306
+ }
307
+ async function getSessiondComponentStatus(daemon, options = {}) {
308
+ try {
309
+ const upstream = await daemon.request("GET", "/runtime");
310
+ if (upstream.statusCode < 200 || upstream.statusCode >= 300) {
311
+ return unavailableSessiond(`runtime check returned HTTP ${String(upstream.statusCode)}`);
312
+ }
313
+ const parsed = upstream.body === "" ? undefined : JSON.parse(upstream.body);
314
+ const runtime = parsePiWebRuntimeComponent(parsed);
315
+ if (runtime?.available !== true)
316
+ return unavailableSessiond(runtime?.error ?? "runtime response did not include valid runtime information");
317
+ const status = await getPiWebComponentStatus("sessiond", options);
318
+ const runtimeVersion = runtime.runtimeVersion ?? status.runtimeVersion;
319
+ return {
320
+ ...status,
321
+ ...(runtimeVersion === undefined ? {} : { runtimeVersion }),
322
+ // The daemon reports the Pi version it has loaded in its own process;
323
+ // the spread of `status` already carries this process's Pi version as
324
+ // the fallback for daemons that predate Pi version reporting, mirroring
325
+ // the runtimeVersion fallback.
326
+ ...(runtime.piVersion === undefined ? {} : { piVersion: runtime.piVersion }),
327
+ stale: isInstalledVersionNewer(status.installedVersion, runtimeVersion),
328
+ available: true,
329
+ };
330
+ }
331
+ catch (error) {
332
+ return unavailableSessiond(error instanceof Error ? error.message : String(error));
333
+ }
334
+ }
335
+ function unavailableSessiondRuntime(error) {
336
+ return {
337
+ component: "sessiond",
338
+ label: "Session daemon",
339
+ available: false,
340
+ capabilities: [],
341
+ error,
342
+ };
343
+ }
344
+ function unavailableSessiond(error) {
345
+ return {
346
+ component: "sessiond",
347
+ label: "Session daemon",
348
+ stale: false,
349
+ available: false,
350
+ error,
351
+ };
352
+ }
353
+ async function getLatestReleaseStatus(currentVersion, force) {
354
+ const checkedAtMs = Date.now();
355
+ if (skipVersionCheck()) {
356
+ return { packageName: PI_WEB_PACKAGE_NAME, updateAvailable: false, checkedAt: new Date(checkedAtMs).toISOString(), skipped: true };
357
+ }
358
+ return releaseStatusFromCache(await latestReleaseLookupCache.get(currentVersion, { force }), currentVersion);
359
+ }
360
+ function releaseStatusFromCache(cache, currentVersion) {
361
+ return {
362
+ packageName: PI_WEB_PACKAGE_NAME,
363
+ ...(cache.latestVersion === undefined ? {} : { latestVersion: cache.latestVersion }),
364
+ updateAvailable: cache.latestVersion === undefined ? false : isNewerPackageVersion(cache.latestVersion, currentVersion),
365
+ checkedAt: new Date(cache.checkedAtMs).toISOString(),
366
+ ...(cache.error === undefined ? {} : { error: cache.error }),
367
+ };
368
+ }
369
+ async function fetchLatestNpmVersion(currentVersion) {
370
+ const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(PI_WEB_PACKAGE_NAME)}/latest`, {
371
+ headers: {
372
+ accept: "application/json",
373
+ "user-agent": `${PI_WEB_PACKAGE_NAME}/${currentVersion}`,
374
+ },
375
+ signal: AbortSignal.timeout(VERSION_CHECK_TIMEOUT_MS),
376
+ });
377
+ if (!response.ok)
378
+ throw new Error(`npm registry returned HTTP ${String(response.status)}`);
379
+ const data = await response.json();
380
+ const version = isRecord(data) ? data["version"] : undefined;
381
+ if (typeof version !== "string" || version === "")
382
+ throw new Error("npm registry response did not include a version");
383
+ return version;
384
+ }
385
+ async function commandsFor(components, options) {
386
+ const installation = preferredInstallation(components);
387
+ if (installation?.kind === "docker")
388
+ return dockerCommands(installation);
389
+ const [serviceCommands, cliCommands] = await Promise.all([
390
+ nativeServiceCommands(),
391
+ piWebCliCommands(installation),
392
+ ]);
393
+ const restart = restartCommandFor(installation, serviceCommands, cliCommands);
394
+ const restartWeb = serviceCommands.restartWeb ?? cliCommands.restart;
395
+ const restartSessiond = serviceCommands.restartSessiond ?? cliCommands.restart;
396
+ const status = serviceCommands.status ?? cliCommands.status;
397
+ const update = await updateCommandFor(installation, restart, options);
398
+ return {
399
+ ...(update === undefined ? {} : { update }),
400
+ ...(restart === undefined ? {} : { restart }),
401
+ ...(restartWeb === undefined ? {} : { restartWeb }),
402
+ ...(restartSessiond === undefined ? {} : { restartSessiond }),
403
+ ...(status === undefined ? {} : { status }),
404
+ };
405
+ }
406
+ function preferredInstallation(components) {
407
+ const web = components.web.installation;
408
+ const sessiond = components.sessiond.installation;
409
+ if (web?.kind === "docker" || sessiond?.kind === "docker")
410
+ return web?.kind === "docker" ? web : sessiond;
411
+ if (web?.kind === "local" || sessiond?.kind === "local")
412
+ return web?.kind === "local" ? web : sessiond;
413
+ return web ?? sessiond;
414
+ }
415
+ function dockerCommands(installation) {
416
+ return {
417
+ update: piWebDockerCommand(installation.dockerMode, "update"),
418
+ restart: piWebDockerCommand(installation.dockerMode, "restart"),
419
+ restartWeb: piWebDockerCommand(installation.dockerMode, "restart-web"),
420
+ restartSessiond: piWebDockerCommand(installation.dockerMode, "restart-sessiond"),
421
+ status: piWebDockerCommand(installation.dockerMode, "status"),
422
+ };
423
+ }
424
+ async function piWebCliCommands(installation) {
425
+ if (installation?.kind !== "npm-global" || !(await hasCommand("pi-web")))
426
+ return {};
427
+ return { restart: "pi-web restart", status: "pi-web status" };
428
+ }
429
+ function restartCommandFor(installation, serviceCommands, cliCommands) {
430
+ if (installation?.kind === "local" || installation?.kind === "pi-package")
431
+ return serviceCommands.restart ?? cliCommands.restart;
432
+ return cliCommands.restart ?? serviceCommands.restart;
433
+ }
434
+ export async function updateCommandFor(installation, restartCommand, options) {
435
+ if (restartCommand === undefined)
436
+ return undefined;
437
+ if (installation?.kind === "pi-package") {
438
+ const profile = options.activeAgentProfile;
439
+ if (profile === undefined || !isHostAbsoluteAgentDir(profile.dir))
440
+ return undefined;
441
+ if (!(await options.hasCommand("pi")))
442
+ return undefined;
443
+ return `${PI_CODING_AGENT_DIR_ENV}=${shellQuote(profile.dir)} pi update ${shellQuote(installation.source ?? PI_WEB_NPM_SOURCE)} && ${restartCommand}`;
444
+ }
445
+ if (installation?.kind === "local" && installation.path !== undefined) {
446
+ if (!(await hasCommand("npm")) || !(await isGitCheckoutWithUpstream(installation.path)))
447
+ return undefined;
448
+ return `cd ${shellQuote(installation.path)} && git pull --ff-only && npm install && npm run build && ${restartCommand}`;
449
+ }
450
+ if (installation?.kind !== "npm-global" || !(await options.hasCommand("npm")))
451
+ return undefined;
452
+ return `npm install -g ${PI_WEB_PACKAGE_NAME} --allow-scripts=node-pty && ${restartCommand}`;
453
+ }
454
+ async function nativeServiceCommands() {
455
+ const backend = await nativeServiceBackend();
456
+ if (backend === undefined)
457
+ return {};
458
+ const installed = installedServiceIds(backend);
459
+ if (installed.size === 0)
460
+ return {};
461
+ const web = installedServiceRefs(installed, ["web", "uiDev"]);
462
+ const sessiond = installedServiceRefs(installed, ["sessiond"]);
463
+ const restartable = web.length === 0 ? [] : installedServiceRefs(installed, restartServiceOrder, restartServiceOrder);
464
+ const status = installedServiceRefs(installed);
465
+ return {
466
+ ...(restartable.length === 0 ? {} : { restart: restartNativeServicesCommand(backend, restartable, "pi-web-restart") }),
467
+ ...(web.length === 0 ? {} : { restartWeb: restartNativeServicesCommand(backend, web, "pi-web-restart-web") }),
468
+ ...(sessiond.length === 0 ? {} : { restartSessiond: restartNativeServicesCommand(backend, sessiond, "pi-web-restart-sessiond") }),
469
+ ...(status.length === 0 ? {} : { status: statusNativeServicesCommand(backend, status) }),
470
+ };
471
+ }
472
+ async function nativeServiceBackend() {
473
+ if (process.platform === "linux" && await hasCommand("systemctl"))
474
+ return "systemd";
475
+ if (process.platform === "darwin" && await hasCommand("launchctl"))
476
+ return "launchd";
477
+ return undefined;
478
+ }
479
+ function installedServiceIds(backend) {
480
+ return new Set(startServiceOrder.filter((id) => existsSync(serviceFilePath(backend, serviceRefs[id]))));
481
+ }
482
+ function installedServiceRefs(installed, candidates = startServiceOrder, order = startServiceOrder) {
483
+ return order.filter((id) => candidates.includes(id) && installed.has(id)).map((id) => serviceRefs[id]);
484
+ }
485
+ function serviceFilePath(backend, ref) {
486
+ return backend === "systemd" ? join(systemdServiceDir(), ref.systemdName) : join(launchdServiceDir(), ref.launchdPlistName);
487
+ }
488
+ function systemdServiceDir() {
489
+ return join(homedir(), ".config", "systemd", "user");
490
+ }
491
+ function launchdServiceDir() {
492
+ return join(homedir(), "Library", "LaunchAgents");
493
+ }
494
+ function restartNativeServicesCommand(backend, refs, systemdUnit) {
495
+ // On systemd, run the restart inside a transient, detached `.service` unit
496
+ // (the default `systemd-run` mode, not `--scope`). A scope would stay a child
497
+ // of the calling shell and die with the terminal; a transient service is
498
+ // reparented to the user service manager, so the restart finishes even when
499
+ // restarting the session daemon kills the pi-web terminal that launched it.
500
+ // `--collect` cleans the unit up afterwards, and the fixed `--unit` name makes
501
+ // logs easy to find with `journalctl --user -u <unit>`.
502
+ if (backend === "systemd") {
503
+ const names = refs.map((ref) => ref.systemdName).join(" ");
504
+ return `systemd-run --user --collect --unit=${systemdUnit} -- systemctl --user restart ${names}`;
505
+ }
506
+ return refs.map((ref) => `launchctl kickstart -k gui/$(id -u)/${ref.launchdLabel}`).join(" && ");
507
+ }
508
+ function statusNativeServicesCommand(backend, refs) {
509
+ if (backend === "systemd")
510
+ return `systemctl --user status ${refs.map((ref) => ref.systemdName).join(" ")}`;
511
+ return refs.map((ref) => `launchctl print gui/$(id -u)/${ref.launchdLabel}`).join(" && ");
512
+ }
513
+ async function isGitCheckoutWithUpstream(path) {
514
+ return await hasCommand("git")
515
+ && await commandSucceeds("git", ["-C", path, "rev-parse", "--is-inside-work-tree"])
516
+ && await commandSucceeds("git", ["-C", path, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"]);
517
+ }
518
+ function hasCommand(command) {
519
+ return commandSucceeds("/usr/bin/env", ["sh", "-c", `command -v ${shellQuote(command)}`]);
520
+ }
521
+ async function commandSucceeds(command, args) {
522
+ try {
523
+ await execFileAsync(command, args, { encoding: "utf8" });
524
+ return true;
525
+ }
526
+ catch {
527
+ return false;
528
+ }
529
+ }
530
+ function shellQuote(value) {
531
+ return `'${value.replaceAll("'", "'\\''")}'`;
532
+ }
533
+ function buildMessages(components, release, commands) {
534
+ const messages = [];
535
+ const installedVersion = components.web.installedVersion ?? components.web.runtimeVersion;
536
+ if (release.updateAvailable && release.latestVersion !== undefined) {
537
+ messages.push({
538
+ id: "update-available",
539
+ severity: "info",
540
+ title: "PI WEB update available",
541
+ body: commands.update === undefined
542
+ ? `PI WEB ${release.latestVersion} is available${installedVersion === undefined ? "" : `; installed version is ${installedVersion}`}. Update PI WEB, then restart the services or processes for this installation.`
543
+ : `PI WEB ${release.latestVersion} is available${installedVersion === undefined ? "" : `; installed version is ${installedVersion}`}. Run the update command to update PI WEB and restart its services.`,
544
+ ...optionalMessageCommand(commands.update),
545
+ });
546
+ }
547
+ if (components.web.stale) {
548
+ const command = commands.restartWeb ?? commands.restart;
549
+ messages.push({
550
+ id: "web-stale",
551
+ severity: "warning",
552
+ title: "Web/UI service restart needed",
553
+ body: command === undefined
554
+ ? `The Web/UI service is running ${formatVersion(components.web.runtimeVersion)}, but ${formatVersion(components.web.installedVersion)} is installed. Restart the Web/UI service or process to use the installed version.`
555
+ : `The Web/UI service is running ${formatVersion(components.web.runtimeVersion)}, but ${formatVersion(components.web.installedVersion)} is installed. Restart the service to use the installed version.`,
556
+ ...optionalMessageCommand(command),
557
+ });
558
+ }
559
+ if (!components.sessiond.available) {
560
+ messages.push({
561
+ id: "sessiond-unavailable",
562
+ severity: "warning",
563
+ title: "Session daemon version unavailable",
564
+ body: commands.status === undefined
565
+ ? `PI WEB could not check the session daemon version${components.sessiond.error === undefined ? "." : `: ${components.sessiond.error}`}. Check the session daemon service or process that runs this installation.`
566
+ : `PI WEB could not check the session daemon version${components.sessiond.error === undefined ? "." : `: ${components.sessiond.error}`}`,
567
+ ...optionalMessageCommand(commands.status),
568
+ });
569
+ }
570
+ else if (components.sessiond.stale) {
571
+ const command = commands.restartSessiond ?? commands.restart;
572
+ messages.push({
573
+ id: "sessiond-stale",
574
+ severity: "warning",
575
+ title: "Session daemon restart needed",
576
+ body: command === undefined
577
+ ? `The session daemon is running ${formatVersion(components.sessiond.runtimeVersion)}, but ${formatVersion(components.sessiond.installedVersion)} is installed. Restart the session daemon service or process to use the installed version.`
578
+ : `The session daemon is running ${formatVersion(components.sessiond.runtimeVersion)}, but ${formatVersion(components.sessiond.installedVersion)} is installed. Restart the daemon to use the installed version.`,
579
+ ...optionalMessageCommand(command),
580
+ });
581
+ }
582
+ return messages;
583
+ }
584
+ function optionalMessageCommand(command) {
585
+ return command === undefined ? {} : { command };
586
+ }
587
+ function skipVersionCheck() {
588
+ return ["PI_WEB_SKIP_VERSION_CHECK", "PI_WEB_OFFLINE", "PI_SKIP_VERSION_CHECK", "PI_OFFLINE"].some((key) => {
589
+ const value = process.env[key];
590
+ return value !== undefined && value !== "";
591
+ });
592
+ }
593
+ function isInstalledVersionNewer(installedVersion, runtimeVersion) {
594
+ if (installedVersion === undefined || runtimeVersion === undefined)
595
+ return false;
596
+ return isNewerPackageVersion(installedVersion, runtimeVersion);
597
+ }
598
+ function isNewerPackageVersion(candidateVersion, currentVersion) {
599
+ const comparison = comparePackageVersions(candidateVersion, currentVersion);
600
+ if (comparison !== undefined)
601
+ return comparison > 0;
602
+ return candidateVersion.trim() !== currentVersion.trim();
603
+ }
604
+ function parsePackageVersion(version) {
605
+ const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/u.exec(version.trim());
606
+ if (match === null)
607
+ return undefined;
608
+ const [, major, minor, patch, prerelease] = match;
609
+ if (major === undefined || minor === undefined || patch === undefined)
610
+ return undefined;
611
+ return {
612
+ major: Number.parseInt(major, 10),
613
+ minor: Number.parseInt(minor, 10),
614
+ patch: Number.parseInt(patch, 10),
615
+ ...(prerelease === undefined ? {} : { prerelease }),
616
+ };
617
+ }
618
+ function formatVersion(version) {
619
+ return version ?? "unknown";
620
+ }
621
+ function isRecord(value) {
622
+ return typeof value === "object" && value !== null && !Array.isArray(value);
623
+ }
624
+ //# sourceMappingURL=piWebStatus.js.map