@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,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="img" aria-labelledby="title desc">
2
+ <title id="title">PI WEB mark</title>
3
+ <desc id="desc">A horizontal brand bar.</desc>
4
+ <style>
5
+ .bar { fill: #00f0d8; }
6
+ @media (prefers-color-scheme: light) {
7
+ .bar { fill: #008c82; }
8
+ }
9
+ </style>
10
+ <rect class="bar" x="128" y="448" width="768" height="128"/>
11
+ </svg>
@@ -0,0 +1,124 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
6
+ <title>PI WEB</title>
7
+ <meta name="theme-color" content="#0d1117" />
8
+ <link rel="icon" type="image/svg+xml" href="./favicon.svg" />
9
+ <link rel="apple-touch-icon" href="./apple-touch-icon.png" />
10
+ <link rel="manifest" href="./manifest.webmanifest" />
11
+ <style>
12
+ :root {
13
+ color-scheme: dark;
14
+ /*
15
+ * Scale tokens: the parts of the look that do not change with the
16
+ * palette. Themes decide colour; these decide density, rhythm and
17
+ * shape, so two themes cannot disagree about how tall a row is or how
18
+ * round a card corner should be. Custom properties inherit through
19
+ * shadow roots, which is what lets every component read them.
20
+ *
21
+ * Spacing is a 2px-based scale with the small steps a dense tool
22
+ * actually uses; type is a compact scale for glancing rather than
23
+ * reading; radii step with the size of the thing they round.
24
+ */
25
+ --pi-space-1: 2px;
26
+ --pi-space-2: 4px;
27
+ --pi-space-3: 6px;
28
+ --pi-space-4: 8px;
29
+ --pi-space-5: 10px;
30
+ --pi-space-6: 12px;
31
+ --pi-space-7: 16px;
32
+ --pi-space-8: 20px;
33
+ --pi-space-9: 24px;
34
+ --pi-text-2xs: 11px;
35
+ --pi-text-xs: 12px;
36
+ --pi-text-sm: 13px;
37
+ --pi-text-base: 14px;
38
+ --pi-text-md: 15px;
39
+ --pi-text-lg: 17px;
40
+ --pi-text-xl: 20px;
41
+ --pi-leading-tight: 1.25;
42
+ --pi-leading-normal: 1.45;
43
+ --pi-weight-regular: 400;
44
+ --pi-weight-medium: 500;
45
+ --pi-weight-semibold: 600;
46
+ --pi-radius-xs: 4px;
47
+ --pi-radius-sm: 6px;
48
+ --pi-radius-md: 8px;
49
+ --pi-radius-lg: 12px;
50
+ --pi-radius-xl: 16px;
51
+ --pi-radius-pill: 999px;
52
+ /* Touch floor first: a control is 44px on a finger, 32px under a mouse. */
53
+ --pi-control-height: 32px;
54
+ --pi-control-height-touch: 44px;
55
+ --pi-motion-fast: 120ms;
56
+ --pi-motion-base: 180ms;
57
+ --pi-motion-slow: 260ms;
58
+ --pi-ease: cubic-bezier(0.2, 0, 0, 1);
59
+ --pi-focus-ring-width: 2px;
60
+ --pi-focus-ring-offset: 2px;
61
+ /*
62
+ * Type stacks, named by role. Nothing is downloaded: this app is a PWA
63
+ * that has to work offline and on a LAN address, so the identity comes
64
+ * from the pairing and the scale rather than from a webfont. A theme or
65
+ * a plugin can override any of these.
66
+ *
67
+ * UI prefers the platform's own interface face (SF, Segoe, Roboto);
68
+ * display reaches for a more characterful grotesque when the system has
69
+ * one and falls back to the UI stack; mono is the terminal's face, so
70
+ * transcript code and the terminal agree.
71
+ */
72
+ --pi-font-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
73
+ --pi-font-display: "SF Pro Display", "Segoe UI Variable Display", Inter, "Helvetica Neue", var(--pi-font-ui);
74
+ --pi-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
75
+ --pi-control-font-size: 16px;
76
+ --pi-control-font-family: var(--pi-font-ui);
77
+ --pi-control-monospace-font-family: var(--pi-font-mono);
78
+ --pi-bg: #0d1117;
79
+ --pi-surface: #161b22;
80
+ --pi-surface-hover: #21262d;
81
+ --pi-terminal-bg: #05070a;
82
+ --pi-terminal-text: #e6edf3;
83
+ --pi-border: #30363d;
84
+ --pi-border-muted: #21262d;
85
+ --pi-text: #e6edf3;
86
+ --pi-text-secondary: #c9d1d9;
87
+ --pi-text-bright: #f0f6fc;
88
+ --pi-muted: #8b949e;
89
+ --pi-dim: #6e7681;
90
+ --pi-accent: #58a6ff;
91
+ --pi-accent-border: #2f81f7;
92
+ --pi-selection-bg: #0d2847;
93
+ --pi-success: #3fb950;
94
+ --pi-success-border: #238636;
95
+ --pi-success-bg: #0f1b12;
96
+ --pi-success-surface: #0f2a16;
97
+ --pi-success-ring: #3fb95055;
98
+ --pi-warning: #d29922;
99
+ --pi-warning-border: #6e5200;
100
+ --pi-warning-surface: #1f1a10;
101
+ --pi-danger: #ff7b72;
102
+ --pi-purple: #d2a8ff;
103
+ --pi-purple-border: #a371f7;
104
+ --pi-purple-surface: #21132f;
105
+ --pi-overlay: #0008;
106
+ --pi-shadow-soft: #0006;
107
+ --pi-shadow: #0008;
108
+ --pi-shadow-strong: #000b;
109
+ --pi-bg-overlay-soft: #0d1117dd;
110
+ --pi-bg-overlay: #0d1117e6;
111
+ --pi-success-bg-overlay: #0f1b12ee;
112
+ --pi-terminal-selection: #264f78;
113
+ }
114
+ html, body { margin: 0; height: 100%; overflow: hidden; background: var(--pi-bg); color: var(--pi-text); }
115
+ body { min-height: 100dvh; }
116
+ </style>
117
+ <script type="module" crossorigin src="./assets/index-C2phil_t.js"></script>
118
+ <link rel="modulepreload" crossorigin href="./assets/vendor-editor-core-CXO8gGab.js">
119
+ <link rel="modulepreload" crossorigin href="./assets/vendor-editor-languages-CpW4sJsX.js">
120
+ </head>
121
+ <body>
122
+ <pi-web-app></pi-web-app>
123
+ </body>
124
+ </html>
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "PI WEB",
3
+ "short_name": "PI WEB",
4
+ "description": "Remote web UI and browser control plane for persistent Pi Coding Agent sessions.",
5
+ "start_url": "./",
6
+ "scope": "./",
7
+ "display": "standalone",
8
+ "background_color": "#0d1117",
9
+ "theme_color": "#0d1117",
10
+ "icons": [
11
+ {
12
+ "src": "./pwa-icon-192.png",
13
+ "sizes": "192x192",
14
+ "type": "image/png",
15
+ "purpose": "any maskable"
16
+ },
17
+ {
18
+ "src": "./pwa-icon-512.png",
19
+ "sizes": "512x512",
20
+ "type": "image/png",
21
+ "purpose": "any maskable"
22
+ }
23
+ ]
24
+ }
Binary file
Binary file
package/dist/config.js ADDED
@@ -0,0 +1,505 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, isAbsolute, join, normalize, resolve } from "node:path";
4
+ import { isPiWebPluginId, piWebPluginIdPattern } from "./shared/pluginIds.js";
5
+ export function defaultPiWebConfigPath(env = process.env) {
6
+ const xdgConfigHome = env["XDG_CONFIG_HOME"];
7
+ return join(xdgConfigHome !== undefined && xdgConfigHome !== "" ? xdgConfigHome : join(homedir(), ".config"), "pi-web", "config.json");
8
+ }
9
+ export function defaultPiWebDataDir() {
10
+ return join(homedir(), ".pi-web");
11
+ }
12
+ /**
13
+ * Default maximum HTTP body size (bytes) for the web/API and session daemon.
14
+ * Generous headroom for base64 image attachments (well above pi's 4.5MB
15
+ * per-image inline limit so several images fit in one request).
16
+ */
17
+ export const DEFAULT_MAX_UPLOAD_BYTES = 64 * 1024 * 1024;
18
+ export const DEFAULT_UPLOADS_FOLDER = ".pi-web/uploads";
19
+ /**
20
+ * Default auto-cancel delay for extension dialogs whose extension set no
21
+ * `timeout` of its own: five minutes. `extensionDialogsTimeoutMs: 0` waits
22
+ * forever. Tunes the unattended-dialog safety valve only; dialogs are always
23
+ * enabled.
24
+ */
25
+ export const DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS = 300_000;
26
+ export const PI_WEB_AGENT_COMMAND_ENV = "PI_WEB_AGENT_COMMAND";
27
+ export const PI_WEB_AGENT_DIR_ENV = "PI_WEB_AGENT_DIR";
28
+ export const PI_WEB_AGENT_SESSION_DIR_ENV = "PI_WEB_AGENT_SESSION_DIR";
29
+ export const PI_CODING_AGENT_DIR_ENV = "PI_CODING_AGENT_DIR";
30
+ export const PI_CODING_AGENT_SESSION_DIR_ENV = "PI_CODING_AGENT_SESSION_DIR";
31
+ /**
32
+ * Session storage override env keys in precedence order: the deprecated
33
+ * `PI_WEB_` alias first so it keeps winning when both are set (today's
34
+ * precedence, preserved for the deprecation window), then the canonical pi
35
+ * SDK name.
36
+ */
37
+ export const AGENT_SESSION_DIR_ENV_KEYS = [PI_WEB_AGENT_SESSION_DIR_ENV, PI_CODING_AGENT_SESSION_DIR_ENV];
38
+ /**
39
+ * Resolve the pi agent state directory. PI WEB runs sessions on the bundled pi
40
+ * SDK only, so there is no command abstraction: the directory comes from the
41
+ * deprecated `PI_WEB_AGENT_DIR` alias, then the canonical `PI_CODING_AGENT_DIR`,
42
+ * then the deprecated `agent.dir` config alias, then the pi SDK default
43
+ * (`~/.pi/agent`, mirrored from the SDK's `getAgentDir()`). The session daemon
44
+ * exports the resolved value as `PI_CODING_AGENT_DIR` at startup, so the
45
+ * embedded SDK's own `getAgentDir()` observes the same directory and pi-web
46
+ * cannot drift from pi.
47
+ */
48
+ export function effectiveAgentConfig(env = process.env, config = {}) {
49
+ const sources = [
50
+ [PI_WEB_AGENT_DIR_ENV, envValue(env, PI_WEB_AGENT_DIR_ENV)],
51
+ [PI_CODING_AGENT_DIR_ENV, envValue(env, PI_CODING_AGENT_DIR_ENV)],
52
+ ["agent.dir", config.agent?.dir],
53
+ ];
54
+ const configured = sources.find((source) => source[1] !== undefined);
55
+ const [sourceName, configuredDir] = configured ?? ["the agent directory default", defaultAgentDir(env)];
56
+ return { dir: resolveAgentDirPath(configuredDir, env, sourceName, "environment") };
57
+ }
58
+ /** The session storage override from the environment, in `AGENT_SESSION_DIR_ENV_KEYS` precedence order. */
59
+ export function agentSessionDirEnvOverride(env) {
60
+ for (const key of AGENT_SESSION_DIR_ENV_KEYS) {
61
+ const value = env[key];
62
+ if (value !== undefined && value !== "")
63
+ return value;
64
+ }
65
+ return undefined;
66
+ }
67
+ export function detectDeprecatedAgentInputs(env, config = {}) {
68
+ const inputs = [];
69
+ if (isEnvSet(env[PI_WEB_AGENT_COMMAND_ENV]))
70
+ inputs.push({ source: "environment", name: PI_WEB_AGENT_COMMAND_ENV });
71
+ if (isEnvSet(env[PI_WEB_AGENT_DIR_ENV]))
72
+ inputs.push({ source: "environment", name: PI_WEB_AGENT_DIR_ENV, replacement: PI_CODING_AGENT_DIR_ENV });
73
+ if (isEnvSet(env[PI_WEB_AGENT_SESSION_DIR_ENV]))
74
+ inputs.push({ source: "environment", name: PI_WEB_AGENT_SESSION_DIR_ENV, replacement: PI_CODING_AGENT_SESSION_DIR_ENV });
75
+ if (config.agent?.command !== undefined)
76
+ inputs.push({ source: "config", name: "agent.command" });
77
+ if (config.agent?.dir !== undefined)
78
+ inputs.push({ source: "config", name: "agent.dir", replacement: PI_CODING_AGENT_DIR_ENV });
79
+ return inputs;
80
+ }
81
+ export function effectiveUploadsConfig(config = {}) {
82
+ return { defaultFolder: config.uploads?.defaultFolder ?? DEFAULT_UPLOADS_FOLDER };
83
+ }
84
+ export function maxUploadBytes(env = process.env, config = {}) {
85
+ const fromEnv = env["PI_WEB_MAX_UPLOAD_BYTES"];
86
+ if (fromEnv !== undefined && fromEnv !== "") {
87
+ const parsed = Number(fromEnv);
88
+ if (Number.isInteger(parsed) && parsed > 0)
89
+ return parsed;
90
+ }
91
+ if (config.maxUploadBytes !== undefined)
92
+ return config.maxUploadBytes;
93
+ return DEFAULT_MAX_UPLOAD_BYTES;
94
+ }
95
+ export function piWebDataDir(env = process.env, cwd = process.cwd()) {
96
+ const configured = env["PI_WEB_DATA_DIR"];
97
+ if (configured === undefined || configured === "")
98
+ return defaultPiWebDataDir();
99
+ return resolve(cwd, configured);
100
+ }
101
+ export function piWebConfigPath(env = process.env, cwd = process.cwd()) {
102
+ const configured = env["PI_WEB_CONFIG"];
103
+ if (configured === undefined || configured === "")
104
+ return defaultPiWebConfigPath(env);
105
+ return resolve(cwd, configured);
106
+ }
107
+ export function loadPiWebConfig(options = {}) {
108
+ const env = options.env ?? process.env;
109
+ const path = piWebConfigPath(env, options.cwd ?? process.cwd());
110
+ if (!existsSync(path))
111
+ return { path, exists: false, config: {}, deprecatedAgentInputs: detectDeprecatedAgentInputs(env) };
112
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
113
+ if (!isRecord(parsed))
114
+ throw new Error(`PI WEB config must be a JSON object: ${path}`);
115
+ const config = parsePiWebConfig(parsed, path);
116
+ return { path, exists: true, config, deprecatedAgentInputs: detectDeprecatedAgentInputs(env, config) };
117
+ }
118
+ export function effectivePiWebConfig(options = {}) {
119
+ return resolveEffectivePiWebConfig(loadPiWebConfig(options), options);
120
+ }
121
+ export function resolveEffectivePiWebConfig(loaded, options = {}) {
122
+ const env = options.env ?? process.env;
123
+ const host = env["PI_WEB_HOST"];
124
+ const port = env["PI_WEB_PORT"] ?? env["PORT"];
125
+ const allowedHosts = env["PI_WEB_ALLOWED_HOSTS"];
126
+ const maxUpload = env["PI_WEB_MAX_UPLOAD_BYTES"];
127
+ const agent = effectiveAgentConfig(env, loaded.config);
128
+ return {
129
+ ...loaded,
130
+ config: {
131
+ ...loaded.config,
132
+ ...(host !== undefined && host !== "" ? { host } : {}),
133
+ ...(port !== undefined && port !== "" ? { port: parsePort(port, "PI_WEB_PORT") } : {}),
134
+ ...(allowedHosts !== undefined && allowedHosts !== "" ? { allowedHosts: parseAllowedHostsEnv(allowedHosts) } : {}),
135
+ ...(maxUpload !== undefined && maxUpload !== "" ? { maxUploadBytes: parseMaxUploadBytes(maxUpload, "PI_WEB_MAX_UPLOAD_BYTES") } : {}),
136
+ uploads: effectiveUploadsConfig(loaded.config),
137
+ // Always resolved (on by default) so the effective config is the single
138
+ // source of truth for the runtime state and the settings UI toggle.
139
+ spawnSessions: spawnSessionsEnabled(env, loaded.config),
140
+ // Resolved on by default like the other capabilities,
141
+ // so the effective config is the single source of truth for the runtime
142
+ // state and the settings UI toggle.
143
+ subsessions: subsessionsEnabled(env, loaded.config),
144
+ // Always resolved (on by default); the user is present for every ask.
145
+ askUser: askUserEnabled(env, loaded.config),
146
+ // Always resolved (on by default); inert outside Docker deployments.
147
+ environmentFacts: environmentFactsEnabled(env, loaded.config),
148
+ // Always resolved; the unattended-dialog safety valve, not a gate.
149
+ extensionDialogsTimeoutMs: loaded.config.extensionDialogsTimeoutMs ?? DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS,
150
+ agent,
151
+ },
152
+ };
153
+ }
154
+ export function savePiWebConfig(config, options = {}) {
155
+ const env = options.env ?? process.env;
156
+ const path = piWebConfigPath(env, options.cwd ?? process.cwd());
157
+ const normalized = parsePiWebConfig(piWebConfigRecord(config), path);
158
+ effectiveAgentConfig(env, normalized);
159
+ const existing = readExistingConfigObject(path);
160
+ if (existing["agent"] !== undefined)
161
+ parseAgentConfig(existing["agent"], path);
162
+ delete existing["host"];
163
+ delete existing["port"];
164
+ delete existing["allowedHosts"];
165
+ delete existing["shortcuts"];
166
+ delete existing["plugins"];
167
+ delete existing["pathAccess"];
168
+ delete existing["uploads"];
169
+ delete existing["maxUploadBytes"];
170
+ delete existing["spawnSessions"];
171
+ delete existing["subsessions"];
172
+ delete existing["askUser"];
173
+ delete existing["respectProjectTrust"];
174
+ delete existing["environmentFacts"];
175
+ delete existing["agent"];
176
+ const merged = { ...existing, ...piWebConfigRecord(normalized) };
177
+ mkdirSync(dirname(path), { recursive: true });
178
+ writeFileSync(path, `${JSON.stringify(merged, null, 2)}\n`, "utf8");
179
+ return { path, exists: true, config: normalized, deprecatedAgentInputs: detectDeprecatedAgentInputs(env, normalized) };
180
+ }
181
+ function readExistingConfigObject(path) {
182
+ if (!existsSync(path))
183
+ return {};
184
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
185
+ if (!isRecord(parsed))
186
+ throw new Error(`PI WEB config must be a JSON object: ${path}`);
187
+ return parsed;
188
+ }
189
+ function piWebConfigRecord(config) {
190
+ return {
191
+ ...(config.host !== undefined ? { host: config.host } : {}),
192
+ ...(config.port !== undefined ? { port: config.port } : {}),
193
+ ...(config.allowedHosts !== undefined ? { allowedHosts: config.allowedHosts } : {}),
194
+ ...(config.shortcuts !== undefined ? { shortcuts: config.shortcuts } : {}),
195
+ ...(config.plugins !== undefined ? { plugins: config.plugins } : {}),
196
+ ...(config.pathAccess !== undefined ? { pathAccess: config.pathAccess } : {}),
197
+ ...(config.uploads !== undefined ? { uploads: config.uploads } : {}),
198
+ ...(config.maxUploadBytes !== undefined ? { maxUploadBytes: config.maxUploadBytes } : {}),
199
+ ...(config.spawnSessions !== undefined ? { spawnSessions: config.spawnSessions } : {}),
200
+ ...(config.subsessions !== undefined ? { subsessions: config.subsessions } : {}),
201
+ ...(config.askUser !== undefined ? { askUser: config.askUser } : {}),
202
+ ...(config.environmentFacts !== undefined ? { environmentFacts: config.environmentFacts } : {}),
203
+ ...(config.agent !== undefined ? { agent: config.agent } : {}),
204
+ };
205
+ }
206
+ function parsePiWebConfig(value, path) {
207
+ return {
208
+ ...(value["host"] !== undefined ? { host: parseString(value["host"], "host", path) } : {}),
209
+ ...(value["port"] !== undefined ? { port: parsePort(value["port"], "port", path) } : {}),
210
+ ...(value["allowedHosts"] !== undefined ? { allowedHosts: parseAllowedHosts(value["allowedHosts"], path) } : {}),
211
+ ...(value["shortcuts"] !== undefined ? { shortcuts: parseShortcuts(value["shortcuts"], path) } : {}),
212
+ ...(value["plugins"] !== undefined ? { plugins: parsePlugins(value["plugins"], path) } : {}),
213
+ ...(value["pathAccess"] !== undefined ? { pathAccess: parsePathAccessConfig(value["pathAccess"], path) } : {}),
214
+ ...(value["uploads"] !== undefined ? { uploads: parseUploadsConfig(value["uploads"], path) } : {}),
215
+ ...(value["maxUploadBytes"] !== undefined ? { maxUploadBytes: parseMaxUploadBytes(value["maxUploadBytes"], "maxUploadBytes", path) } : {}),
216
+ ...(value["spawnSessions"] !== undefined ? { spawnSessions: parseSpawnSessions(value["spawnSessions"], path) } : {}),
217
+ ...(value["subsessions"] !== undefined ? { subsessions: parseSubsessions(value["subsessions"], path) } : {}),
218
+ ...(value["askUser"] !== undefined ? { askUser: parseAskUser(value["askUser"], path) } : {}),
219
+ ...(value["environmentFacts"] !== undefined ? { environmentFacts: parseBooleanKey(value["environmentFacts"], "environmentFacts", path) } : {}),
220
+ ...(value["extensionDialogsTimeoutMs"] !== undefined ? { extensionDialogsTimeoutMs: parseExtensionDialogsTimeoutMs(value["extensionDialogsTimeoutMs"], path) } : {}),
221
+ ...(value["agent"] !== undefined ? { agent: parseAgentConfig(value["agent"], path) } : {}),
222
+ };
223
+ }
224
+ function parseMaxUploadBytes(value, key, path = "environment") {
225
+ const bytes = typeof value === "number" ? value : typeof value === "string" && value !== "" ? Number(value) : NaN;
226
+ if (!Number.isInteger(bytes) || bytes < 1)
227
+ throw new Error(`PI WEB config ${key} must be a positive integer: ${path}`);
228
+ return bytes;
229
+ }
230
+ function parseSpawnSessions(value, path) {
231
+ if (typeof value !== "boolean")
232
+ throw new Error(`PI WEB config spawnSessions must be a boolean: ${path}`);
233
+ return value;
234
+ }
235
+ /**
236
+ * Whether LLMs may start new sessions via the spawn_session tool. On by default
237
+ * (spawned sessions appear in the session list, so humans notice them); set the
238
+ * env var `PI_WEB_SPAWN_SESSIONS` or the `spawnSessions` config key to `false`
239
+ * to disable. The env var takes precedence over the config file.
240
+ */
241
+ export function spawnSessionsEnabled(env = process.env, config = {}) {
242
+ const fromEnv = env["PI_WEB_SPAWN_SESSIONS"];
243
+ if (fromEnv !== undefined && fromEnv !== "")
244
+ return fromEnv === "1" || fromEnv.toLowerCase() === "true";
245
+ return config.spawnSessions ?? true;
246
+ }
247
+ function parseSubsessions(value, path) {
248
+ if (typeof value !== "boolean")
249
+ throw new Error(`PI WEB config subsessions must be a boolean: ${path}`);
250
+ return value;
251
+ }
252
+ /**
253
+ * Whether LLMs may start tracked child sessions via the spawn_subsession
254
+ * family of tools. On by default; set the env var `PI_WEB_SUBSESSIONS` or the
255
+ * `subsessions` config key to `false` to disable. The env var takes precedence
256
+ * over the config file. Subsessions also require spawnSessions to be enabled
257
+ * (they share the same project-scope resolver).
258
+ */
259
+ export function subsessionsEnabled(env = process.env, config = {}) {
260
+ const fromEnv = env["PI_WEB_SUBSESSIONS"];
261
+ if (fromEnv !== undefined && fromEnv !== "")
262
+ return fromEnv === "1" || fromEnv.toLowerCase() === "true";
263
+ return config.subsessions ?? true;
264
+ }
265
+ function parseAskUser(value, path) {
266
+ if (typeof value !== "boolean")
267
+ throw new Error(`PI WEB config askUser must be a boolean: ${path}`);
268
+ return value;
269
+ }
270
+ function parseExtensionDialogsTimeoutMs(value, path) {
271
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
272
+ throw new Error(`PI WEB config extensionDialogsTimeoutMs must be a non-negative integer: ${path}`);
273
+ }
274
+ return value;
275
+ }
276
+ /**
277
+ * Whether LLMs may post a question set to the browser via the ask_user tool. On
278
+ * by default: the questions land in the session the user is already watching and
279
+ * nothing happens without them acting. Set the env var `PI_WEB_ASK_USER` or the
280
+ * `askUser` config key to `false` to remove the tool. The env var takes
281
+ * precedence over the config file.
282
+ */
283
+ export function askUserEnabled(env = process.env, config = {}) {
284
+ const fromEnv = env["PI_WEB_ASK_USER"];
285
+ if (fromEnv !== undefined && fromEnv !== "")
286
+ return fromEnv === "1" || fromEnv.toLowerCase() === "true";
287
+ return config.askUser ?? true;
288
+ }
289
+ function parseBooleanKey(value, key, path) {
290
+ if (typeof value !== "boolean")
291
+ throw new Error(`PI WEB config ${key} must be a boolean: ${path}`);
292
+ return value;
293
+ }
294
+ /**
295
+ * Whether PI WEB appends deployment environment facts to session system
296
+ * prompts. On by default; set the env var `PI_WEB_ENVIRONMENT_FACTS` or the
297
+ * `environmentFacts` config key to `false` to leave the system prompt
298
+ * untouched. The env var takes precedence over the config file.
299
+ *
300
+ * The facts describe the pi-web session nesting every session runs in; Docker
301
+ * deployments append container facts on top. The env var deliberately avoids
302
+ * the `PI_WEB_DOCKER_` prefix, which agent processes inherit for
303
+ * `pi-web-docker`.
304
+ */
305
+ export function environmentFactsEnabled(env = process.env, config = {}) {
306
+ const fromEnv = env["PI_WEB_ENVIRONMENT_FACTS"];
307
+ if (fromEnv !== undefined && fromEnv !== "")
308
+ return fromEnv === "1" || fromEnv.toLowerCase() === "true";
309
+ return config.environmentFacts ?? true;
310
+ }
311
+ const OFFLINE_ENV_KEYS = ["PI_WEB_OFFLINE", "PI_OFFLINE"];
312
+ /**
313
+ * Whether the operator asked PI WEB (or pi itself) to stay offline, meaning
314
+ * background network access must be skipped. Matches the "set and non-empty"
315
+ * semantics used for the other runtime-only env switches.
316
+ *
317
+ * Deliberately narrower than `piWebStatus`'s update-check suppression: the
318
+ * `*_SKIP_VERSION_CHECK` keys only silence release lookups, while these keys ask
319
+ * for no background network at all.
320
+ */
321
+ export function offlineModeEnabled(env = process.env) {
322
+ return OFFLINE_ENV_KEYS.some((key) => isEnvSet(env[key]));
323
+ }
324
+ function parseString(value, key, path) {
325
+ if (typeof value !== "string" || value === "")
326
+ throw new Error(`PI WEB config ${key} must be a non-empty string: ${path}`);
327
+ return value;
328
+ }
329
+ /**
330
+ * Keys still accepted under `agent` during the deprecation window: `command`
331
+ * is parsed only so the file round-trips and the deprecation detector can name
332
+ * it (the concept is gone), and `dir` remains honored as a deprecated alias.
333
+ * The section has no live schema — every accepted key is deprecated — so any
334
+ * other key fails loudly, naming the deprecated survivors.
335
+ */
336
+ const DEPRECATED_AGENT_CONFIG_KEYS = new Set(["command", "dir"]);
337
+ export function parseAgentConfig(value, path, pathHost = "current") {
338
+ if (!isRecord(value))
339
+ throw new Error(`PI WEB config agent must be an object: ${path}`);
340
+ const unknownKey = Object.keys(value).find((key) => !DEPRECATED_AGENT_CONFIG_KEYS.has(key));
341
+ if (unknownKey !== undefined)
342
+ throw new Error(`PI WEB config agent accepts only the deprecated keys "command" and "dir"; unknown key ${JSON.stringify(unknownKey)}: ${path}`);
343
+ const command = value["command"];
344
+ const dir = value["dir"];
345
+ return {
346
+ // `agent.command` is deprecated and ignored (the multi-CLI abstraction is
347
+ // gone): it is parsed only so the file round-trips faithfully and the
348
+ // deprecation detector can name it. `agent.dir` is still honored as a
349
+ // deprecated alias during the deprecation window, so it keeps validation.
350
+ ...(command !== undefined ? { command: parseString(command, "agent.command", path) } : {}),
351
+ ...(dir !== undefined ? { dir: parseAgentDir(dir, "agent.dir", path, pathHost) } : {}),
352
+ };
353
+ }
354
+ function parseAgentDir(value, key, path, pathHost) {
355
+ const dir = parseString(value, key, path).trim();
356
+ const isAbsoluteDir = pathHost === "current" ? isHostAbsoluteAgentDir(dir) : isPortableAbsoluteAgentPath(dir);
357
+ if (!isAbsoluteDir && !isHomePath(dir, pathHost)) {
358
+ const absoluteLabel = pathHost === "current" ? "a host-absolute" : "an absolute";
359
+ throw new Error(`PI WEB config ${key} must be ${absoluteLabel} path or start with ~: ${path}`);
360
+ }
361
+ return dir;
362
+ }
363
+ function resolveAgentDirPath(value, env, key, path) {
364
+ const parsed = parseAgentDir(value, key, path, "current");
365
+ const expanded = expandHomePath(parsed, env);
366
+ if (!isHostAbsoluteAgentDir(expanded)) {
367
+ throw new Error(`PI WEB config ${key} must resolve to a host-absolute path: ${path}`);
368
+ }
369
+ return normalize(expanded);
370
+ }
371
+ export function isHostAbsoluteAgentDir(value) {
372
+ return isSafeAgentDirPath(value) && isAbsolute(value);
373
+ }
374
+ function isPortableAbsoluteAgentPath(value) {
375
+ return isSafeAgentDirPath(value) && isAbsoluteLike(value);
376
+ }
377
+ function isSafeAgentDirPath(value) {
378
+ return value !== "" && value === value.trim() && !hasControlCharacter(value);
379
+ }
380
+ function parsePort(value, key, path = "environment") {
381
+ const port = typeof value === "number" ? value : typeof value === "string" && value !== "" ? Number(value) : NaN;
382
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
383
+ throw new Error(`PI WEB config ${key} must be an integer from 1 to 65535: ${path}`);
384
+ return port;
385
+ }
386
+ function parseAllowedHosts(value, path) {
387
+ if (value === true)
388
+ return true;
389
+ if (!isNonEmptyStringArray(value)) {
390
+ throw new Error(`PI WEB config allowedHosts must be true or an array of non-empty strings: ${path}`);
391
+ }
392
+ return value;
393
+ }
394
+ function parseAllowedHostsEnv(value) {
395
+ if (value === "true")
396
+ return true;
397
+ return value.split(",").map((host) => host.trim()).filter((host) => host !== "");
398
+ }
399
+ export function parsePathAccessConfig(value, path) {
400
+ if (!isRecord(value))
401
+ throw new Error(`PI WEB config pathAccess must be an object: ${path}`);
402
+ const allowedPaths = value["allowedPaths"];
403
+ return {
404
+ ...(allowedPaths !== undefined ? { allowedPaths: parseAllowedPaths(allowedPaths, path) } : {}),
405
+ };
406
+ }
407
+ function parseAllowedPaths(value, path) {
408
+ if (!isNonEmptyStringArray(value))
409
+ throw new Error(`PI WEB config pathAccess.allowedPaths must be an array of non-empty strings: ${path}`);
410
+ return value;
411
+ }
412
+ export function parseUploadsConfig(value, path) {
413
+ if (!isRecord(value))
414
+ throw new Error(`PI WEB config uploads must be an object: ${path}`);
415
+ const defaultFolder = value["defaultFolder"];
416
+ return {
417
+ ...(defaultFolder !== undefined ? { defaultFolder: parseWorkspaceRelativeFolder(defaultFolder, "uploads.defaultFolder", path) } : {}),
418
+ };
419
+ }
420
+ function parseWorkspaceRelativeFolder(value, key, path) {
421
+ if (typeof value !== "string" || value.trim() === "")
422
+ throw new Error(`PI WEB config ${key} must be a non-empty workspace-relative path: ${path}`);
423
+ if (isAbsoluteLike(value))
424
+ throw new Error(`PI WEB config ${key} must be workspace-relative: ${path}`);
425
+ const parts = value.split(/[\\/]+/).filter((part) => part !== "" && part !== ".");
426
+ if (parts.length === 0)
427
+ throw new Error(`PI WEB config ${key} must be a non-empty workspace-relative path: ${path}`);
428
+ if (parts.some((part) => part === ".."))
429
+ throw new Error(`PI WEB config ${key} must not contain path traversal: ${path}`);
430
+ return parts.join("/");
431
+ }
432
+ function isHomePath(value, pathHost) {
433
+ return value === "~" || value.startsWith("~/") || ((pathHost === "portable" || process.platform === "win32") && value.startsWith("~\\"));
434
+ }
435
+ function expandHomePath(value, env) {
436
+ const home = env["HOME"] !== undefined && env["HOME"] !== "" ? env["HOME"] : homedir();
437
+ if (value === "~")
438
+ return home;
439
+ if (value.startsWith("~/") || (process.platform === "win32" && value.startsWith("~\\")))
440
+ return join(home, value.slice(2));
441
+ return value;
442
+ }
443
+ // Exact mirror of the pi SDK default (`getAgentDir()`: `~/.pi/agent`) rather
444
+ // than a delegation, so the injected `env` stays authoritative; if the bundled
445
+ // SDK is ever swapped for a fork whose default moves, this mirror must move
446
+ // with it or the two resolutions drift.
447
+ function defaultAgentDir(env) {
448
+ return expandHomePath("~/.pi/agent", env);
449
+ }
450
+ function envValue(env, key) {
451
+ const value = env[key];
452
+ return value !== undefined && value !== "" ? value : undefined;
453
+ }
454
+ function isEnvSet(value) {
455
+ return value !== undefined && value !== "";
456
+ }
457
+ function hasControlCharacter(value) {
458
+ for (const character of value) {
459
+ const code = character.charCodeAt(0);
460
+ if (code < 32 || code === 127)
461
+ return true;
462
+ }
463
+ return false;
464
+ }
465
+ function isAbsoluteLike(value) {
466
+ const withForwardSlashes = value.replace(/\\/g, "/");
467
+ return isAbsolute(value) || withForwardSlashes.startsWith("/") || /^[A-Za-z]:\//.test(withForwardSlashes);
468
+ }
469
+ function parseShortcuts(value, path) {
470
+ if (!isRecord(value))
471
+ throw new Error(`PI WEB config shortcuts must be an object: ${path}`);
472
+ return Object.fromEntries(Object.entries(value).map(([actionId, shortcut]) => {
473
+ if (shortcut !== null && (typeof shortcut !== "string" || shortcut === "")) {
474
+ throw new Error(`PI WEB config shortcut values must be non-empty strings or null: ${path}`);
475
+ }
476
+ return [actionId, shortcut];
477
+ }));
478
+ }
479
+ function parsePlugins(value, path) {
480
+ if (!isRecord(value) || Array.isArray(value))
481
+ throw new Error(`PI WEB config plugins must be an object: ${path}`);
482
+ return Object.fromEntries(Object.entries(value).map(([pluginId, config]) => {
483
+ if (!isPiWebPluginId(pluginId))
484
+ throw new Error(`PI WEB config plugin ids must match ${piWebPluginIdPattern.source}: ${path}`);
485
+ if (!isRecord(config) || Array.isArray(config))
486
+ throw new Error(`PI WEB config plugin entries must be objects: ${path}`);
487
+ const enabled = config["enabled"];
488
+ if (enabled !== undefined && typeof enabled !== "boolean")
489
+ throw new Error(`PI WEB config plugin enabled values must be booleans: ${path}`);
490
+ const settings = config["settings"];
491
+ if (settings !== undefined && (!isRecord(settings) || Array.isArray(settings)))
492
+ throw new Error(`PI WEB config plugin settings must be objects: ${path}`);
493
+ return [pluginId, config];
494
+ }));
495
+ }
496
+ function isRecord(value) {
497
+ return typeof value === "object" && value !== null && !Array.isArray(value);
498
+ }
499
+ function isNonEmptyStringArray(value) {
500
+ return Array.isArray(value) && value.every((item) => typeof item === "string" && item !== "");
501
+ }
502
+ export function examplePiWebConfig(config = {}) {
503
+ return `${JSON.stringify({ host: config.host ?? "127.0.0.1", port: config.port ?? 8504, allowedHosts: config.allowedHosts ?? [] }, null, 2)}\n`;
504
+ }
505
+ //# sourceMappingURL=config.js.map