@chainingintention/pi-web-cn 1.202608.8 → 2.0.0

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 (199) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +123 -72
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client/assets/{CodeViewer-CWKEeX0r.js → CodeViewer-DCl56K0Z.js} +2 -2
  5. package/dist/client/assets/{TerminalPanel-BmA7Ayzk.js → TerminalPanel-DCvoEjUF.js} +6 -6
  6. package/dist/client/assets/{index-D6j67Izj.js → index-CMvms5cF.js} +534 -512
  7. package/dist/client/index.html +1 -1
  8. package/dist/config.js +39 -18
  9. package/dist/config.js.map +1 -1
  10. package/dist/nativeServices/serviceAction.js +128 -0
  11. package/dist/nativeServices/serviceAction.js.map +1 -0
  12. package/dist/pi-web-plugins/git/browser/git-contract.js +108 -0
  13. package/dist/pi-web-plugins/git/browser/git-panel.js +609 -0
  14. package/dist/pi-web-plugins/git/browser/gitFileList.js +43 -0
  15. package/dist/pi-web-plugins/git/browser/gitFileShared.js +16 -0
  16. package/dist/pi-web-plugins/git/browser/gitFileTree.js +81 -0
  17. package/dist/pi-web-plugins/git/browser/gitFileViewPreference.js +35 -0
  18. package/dist/pi-web-plugins/git/browser/gitRoute.js +42 -0
  19. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +10 -0
  20. package/dist/pi-web-plugins/git/browser/unifiedDiff.js +301 -0
  21. package/dist/pi-web-plugins/git/git-backend.js +433 -0
  22. package/dist/pi-web-plugins/git/package.json +15 -0
  23. package/dist/pi-web-plugins/git/server-plugin.js +176 -0
  24. package/dist/pi-web-plugins/info/infoInternals.js +1 -1
  25. package/dist/pi-web-plugins/info/pi-web-plugin.js +2 -2
  26. package/dist/pi-web-plugins/relays/pi-web-plugin.js +1 -1
  27. package/dist/pi-web-plugins/relays/relayDiscovery.js +128 -23
  28. package/dist/pi-web-plugins/relays/relaysPanelElement.js +138 -16
  29. package/dist/pi-web-plugins/updates/pi-web-plugin.js +1 -1
  30. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +1 -1
  31. package/dist/piWebVersionReport.js +63 -4
  32. package/dist/piWebVersionReport.js.map +1 -1
  33. package/dist/plugin-api.d.ts +40 -18
  34. package/dist/pluginRecoveryCli.js +172 -0
  35. package/dist/pluginRecoveryCli.js.map +1 -0
  36. package/dist/server/activity/workspaceActivityService.js +7 -1
  37. package/dist/server/activity/workspaceActivityService.js.map +1 -1
  38. package/dist/server/app.js +49 -23
  39. package/dist/server/app.js.map +1 -1
  40. package/dist/server/audit/managementAuditStore.js +4 -2
  41. package/dist/server/audit/managementAuditStore.js.map +1 -1
  42. package/dist/server/configRoutes.js +4 -5
  43. package/dist/server/configRoutes.js.map +1 -1
  44. package/dist/server/machines/machineClient.js +23 -4
  45. package/dist/server/machines/machineClient.js.map +1 -1
  46. package/dist/server/machines/machineProxyRoutes.js +162 -8
  47. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  48. package/dist/server/managementEmbed.js +6 -0
  49. package/dist/server/managementEmbed.js.map +1 -1
  50. package/dist/server/piWebPluginCatalog.js +441 -0
  51. package/dist/server/piWebPluginCatalog.js.map +1 -0
  52. package/dist/server/piWebPluginLifecycle.js +162 -0
  53. package/dist/server/piWebPluginLifecycle.js.map +1 -0
  54. package/dist/server/piWebPluginService.js +55 -7
  55. package/dist/server/piWebPluginService.js.map +1 -1
  56. package/dist/server/plugins/pluginBackendProxyRoutes.js +80 -0
  57. package/dist/server/plugins/pluginBackendProxyRoutes.js.map +1 -0
  58. package/dist/server/plugins/serverPluginExec.js +184 -0
  59. package/dist/server/plugins/serverPluginExec.js.map +1 -0
  60. package/dist/server/plugins/serverPluginRuntime.js +480 -0
  61. package/dist/server/plugins/serverPluginRuntime.js.map +1 -0
  62. package/dist/server/realtime/sessionEventHub.js +13 -0
  63. package/dist/server/realtime/sessionEventHub.js.map +1 -1
  64. package/dist/server/realtime/sessionEventScope.js +8 -1
  65. package/dist/server/realtime/sessionEventScope.js.map +1 -1
  66. package/dist/server/requestCancellation.js +28 -0
  67. package/dist/server/requestCancellation.js.map +1 -0
  68. package/dist/server/sessiond/agentProcessEnvironment.js +61 -0
  69. package/dist/server/sessiond/agentProcessEnvironment.js.map +1 -0
  70. package/dist/server/sessiond/managementProjectResolver.js +16 -0
  71. package/dist/server/sessiond/managementProjectResolver.js.map +1 -0
  72. package/dist/server/sessiond/pluginBackendRoutes.js +78 -0
  73. package/dist/server/sessiond/pluginBackendRoutes.js.map +1 -0
  74. package/dist/server/sessiond/sessionProxyRoutes.js +1 -0
  75. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  76. package/dist/server/sessiond/sessionServiceDependencies.js +0 -1
  77. package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -1
  78. package/dist/server/sessiond/sessiondStateOwnership.js +139 -0
  79. package/dist/server/sessiond/sessiondStateOwnership.js.map +1 -0
  80. package/dist/server/sessiond/workspaceCatalogRoutes.js +38 -0
  81. package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -0
  82. package/dist/server/sessiond/workspaceRemovalRoutes.js +56 -0
  83. package/dist/server/sessiond/workspaceRemovalRoutes.js.map +1 -0
  84. package/dist/server/sessiond.js +98 -11
  85. package/dist/server/sessiond.js.map +1 -1
  86. package/dist/server/sessions/authService.js +15 -51
  87. package/dist/server/sessions/authService.js.map +1 -1
  88. package/dist/server/sessions/dockerEnvironmentFacts.js +181 -0
  89. package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -0
  90. package/dist/server/sessions/managementAgentTools.js +12 -4
  91. package/dist/server/sessions/managementAgentTools.js.map +1 -1
  92. package/dist/server/sessions/managementSandbox.js +5 -5
  93. package/dist/server/sessions/managementSandbox.js.map +1 -1
  94. package/dist/server/sessions/piSessionManagerGateway.js +129 -2
  95. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -1
  96. package/dist/server/sessions/piSessionService.js +268 -119
  97. package/dist/server/sessions/piSessionService.js.map +1 -1
  98. package/dist/server/sessions/sessionCommandService.js +15 -1
  99. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  100. package/dist/server/sessions/sessionEnvironmentFacts.js +48 -0
  101. package/dist/server/sessions/sessionEnvironmentFacts.js.map +1 -0
  102. package/dist/server/sessions/sessionFileFormat.js +27 -0
  103. package/dist/server/sessions/sessionFileFormat.js.map +1 -0
  104. package/dist/server/sessions/sessionFileHeader.js +82 -23
  105. package/dist/server/sessions/sessionFileHeader.js.map +1 -1
  106. package/dist/server/sessions/sessionRoutes.js +16 -2
  107. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  108. package/dist/server/sessions/sessionSummaryScanner.js +491 -0
  109. package/dist/server/sessions/sessionSummaryScanner.js.map +1 -0
  110. package/dist/server/sessions/spawnSubsessionTool.js +4 -8
  111. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  112. package/dist/server/sessions/spawnTargetResolver.js +2 -2
  113. package/dist/server/sessions/spawnTargetResolver.js.map +1 -1
  114. package/dist/server/status/machineStatusRoutes.js +10 -0
  115. package/dist/server/status/machineStatusRoutes.js.map +1 -0
  116. package/dist/server/status/machineStatusService.js +115 -0
  117. package/dist/server/status/machineStatusService.js.map +1 -0
  118. package/dist/server/status/workspaceAttribution.js +71 -0
  119. package/dist/server/status/workspaceAttribution.js.map +1 -0
  120. package/dist/server/terminalProxyRoutes.js.map +1 -1
  121. package/dist/server/workbench/skillSync.js +9 -1
  122. package/dist/server/workbench/skillSync.js.map +1 -1
  123. package/dist/server/workspaceExplorerRoutes.js +12 -25
  124. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  125. package/dist/server/workspaces/effectivePathAccess.js +3 -2
  126. package/dist/server/workspaces/effectivePathAccess.js.map +1 -1
  127. package/dist/server/workspaces/fileContentService.js +17 -9
  128. package/dist/server/workspaces/fileContentService.js.map +1 -1
  129. package/dist/server/workspaces/fileOperationService.js +4 -17
  130. package/dist/server/workspaces/fileOperationService.js.map +1 -1
  131. package/dist/server/workspaces/filePreviewResponseHeaders.js +18 -0
  132. package/dist/server/workspaces/filePreviewResponseHeaders.js.map +1 -0
  133. package/dist/server/workspaces/filePreviewResponsePolicy.js +55 -0
  134. package/dist/server/workspaces/filePreviewResponsePolicy.js.map +1 -0
  135. package/dist/server/workspaces/filePreviewService.js +81 -0
  136. package/dist/server/workspaces/filePreviewService.js.map +1 -0
  137. package/dist/server/workspaces/projectWorkspaceCwds.js +2 -2
  138. package/dist/server/workspaces/projectWorkspaceCwds.js.map +1 -1
  139. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +416 -0
  140. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -0
  141. package/dist/server/workspaces/workspaceCatalog.js +87 -0
  142. package/dist/server/workspaces/workspaceCatalog.js.map +1 -0
  143. package/dist/server/workspaces/workspaceContext.js +5 -5
  144. package/dist/server/workspaces/workspaceContext.js.map +1 -1
  145. package/dist/server/workspaces/workspaceDeletionRoutes.js +114 -99
  146. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -1
  147. package/dist/server/workspaces/workspaceProviderRegistry.js +650 -0
  148. package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -0
  149. package/dist/server/workspaces/workspaceRemovalService.js +258 -0
  150. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -0
  151. package/dist/server/workspaces/workspaceRouteContext.js +2 -1
  152. package/dist/server/workspaces/workspaceRouteContext.js.map +1 -1
  153. package/dist/server/workspaces/workspaceRouteErrors.js +7 -0
  154. package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -0
  155. package/dist/server/workspaces/worktreePreRemoveHook.js +39 -0
  156. package/dist/server/workspaces/worktreePreRemoveHook.js.map +1 -0
  157. package/dist/server-plugin-api.d.ts +115 -0
  158. package/dist/server-plugin-api.js +2 -0
  159. package/dist/server-plugin-api.js.map +1 -0
  160. package/dist/serverPluginRecovery.js +138 -0
  161. package/dist/serverPluginRecovery.js.map +1 -0
  162. package/dist/sessiond/config.js +6 -0
  163. package/dist/sessiond/config.js.map +1 -1
  164. package/dist/sessiond/sessionDaemonClient.js +7 -6
  165. package/dist/sessiond/sessionDaemonClient.js.map +1 -1
  166. package/dist/shared/apiTypes.js +2 -0
  167. package/dist/shared/apiTypes.js.map +1 -1
  168. package/dist/shared/capabilities.js +2 -0
  169. package/dist/shared/capabilities.js.map +1 -1
  170. package/dist/shared/federatedRoutes.js +28 -2
  171. package/dist/shared/federatedRoutes.js.map +1 -1
  172. package/dist/shared/machineStatus.js +60 -0
  173. package/dist/shared/machineStatus.js.map +1 -0
  174. package/dist/shared/pluginApiTypes.d.ts +155 -0
  175. package/dist/shared/pluginBackendProtocol.js +110 -0
  176. package/dist/shared/pluginBackendProtocol.js.map +1 -0
  177. package/dist/shared/pluginIds.js +3 -0
  178. package/dist/shared/pluginIds.js.map +1 -1
  179. package/dist/shared/pluginRecoveryCommands.js +14 -0
  180. package/dist/shared/pluginRecoveryCommands.js.map +1 -0
  181. package/dist/shared/workspaceFiles.js +41 -2
  182. package/dist/shared/workspaceFiles.js.map +1 -1
  183. package/dist/shared/workspaceRemovalProtocol.js +24 -0
  184. package/dist/shared/workspaceRemovalProtocol.js.map +1 -0
  185. package/docs/config.md +12 -5
  186. package/docs/plugins.md +15 -21
  187. package/package.json +27 -8
  188. package/server-plugin-api.d.ts +1 -0
  189. package/skills/README.md +12 -0
  190. package/skills/relay/SKILL.md +115 -0
  191. package/dist/client/assets/UnifiedDiffViewer-2DACwxFY.js +0 -39
  192. package/dist/plugin-api/unstable.d.ts +0 -22
  193. package/dist/server/sessions/parentSessionLocator.js +0 -75
  194. package/dist/server/sessions/parentSessionLocator.js.map +0 -1
  195. package/dist/server/workspaces/imagePreviewService.js +0 -40
  196. package/dist/server/workspaces/imagePreviewService.js.map +0 -1
  197. package/dist/shared/apiTypes.d.ts +0 -1323
  198. package/dist/shared/thinkingLevels.d.ts +0 -29
  199. package/plugin-api/unstable.d.ts +0 -1
@@ -0,0 +1,110 @@
1
+ /** Maximum UTF-8 JSON input accepted from a browser plugin. */
2
+ export const PLUGIN_BACKEND_JSON_MAX_BYTES = 256 * 1024;
3
+ /** Bounded result allowance demonstrated by Git's existing 2 MiB command-output limit. */
4
+ export const PLUGIN_BACKEND_RESPONSE_JSON_MAX_BYTES = 8 * 1024 * 1024;
5
+ /** Envelope allowance for the active backend revision and JSON field names. */
6
+ export const PLUGIN_BACKEND_REQUEST_BODY_MAX_BYTES = PLUGIN_BACKEND_JSON_MAX_BYTES + 4 * 1024;
7
+ /** Allowance for an attributed error envelope around a bounded result. */
8
+ export const PLUGIN_BACKEND_RESPONSE_BODY_MAX_BYTES = PLUGIN_BACKEND_RESPONSE_JSON_MAX_BYTES + 4 * 1024;
9
+ /** Bounded provider callback deadline inside sessiond. */
10
+ export const PLUGIN_BACKEND_REQUEST_TIMEOUT_MS = 10_000;
11
+ /** End-to-end sessiond deadline, including owner re-resolution and validation. */
12
+ export const PLUGIN_BACKEND_DISPATCH_TIMEOUT_MS = 25_000;
13
+ /** Remote gateway deadline, including workspace owner re-resolution. */
14
+ export const PLUGIN_BACKEND_FEDERATION_TIMEOUT_MS = 30_000;
15
+ export const PLUGIN_BACKEND_OPERATION_MAX_LENGTH = 128;
16
+ export const PLUGIN_BACKEND_REVISION_MAX_LENGTH = 512;
17
+ const OPERATION_PATTERN = /^[a-z][a-z0-9.-]*$/u;
18
+ const MAX_JSON_DEPTH = 64;
19
+ export function isPluginBackendOperation(value) {
20
+ return value.length <= PLUGIN_BACKEND_OPERATION_MAX_LENGTH && OPERATION_PATTERN.test(value);
21
+ }
22
+ export function requirePluginBackendOperation(value) {
23
+ if (!isPluginBackendOperation(value)) {
24
+ throw new Error(`Plugin backend operation must match ${String(OPERATION_PATTERN)} and be at most ${String(PLUGIN_BACKEND_OPERATION_MAX_LENGTH)} characters`);
25
+ }
26
+ return value;
27
+ }
28
+ export function requirePluginBackendRevision(value) {
29
+ if (typeof value !== "string" || value === "" || value.length > PLUGIN_BACKEND_REVISION_MAX_LENGTH) {
30
+ throw new Error(`Plugin backend revision must be a non-empty string of at most ${String(PLUGIN_BACKEND_REVISION_MAX_LENGTH)} characters`);
31
+ }
32
+ return value;
33
+ }
34
+ /** Clone and freeze a runtime value after enforcing the JSON and byte contract. */
35
+ export function cloneBoundedPluginBackendJson(value, label, maxBytes = PLUGIN_BACKEND_JSON_MAX_BYTES) {
36
+ const cloned = cloneJsonValue(value, new Set(), label, 0);
37
+ const serialized = JSON.stringify(cloned);
38
+ if (utf8ByteLength(serialized) > maxBytes) {
39
+ throw new Error(`${label} exceeds the ${String(maxBytes)} byte limit`);
40
+ }
41
+ return cloned;
42
+ }
43
+ export function serializeBoundedPluginBackendJson(value, label, maxBytes = PLUGIN_BACKEND_JSON_MAX_BYTES) {
44
+ return JSON.stringify(cloneBoundedPluginBackendJson(value, label, maxBytes));
45
+ }
46
+ export function parseBoundedPluginBackendJson(text, label, maxBytes = PLUGIN_BACKEND_JSON_MAX_BYTES) {
47
+ if (utf8ByteLength(text) > maxBytes) {
48
+ throw new Error(`${label} exceeds the ${String(maxBytes)} byte limit`);
49
+ }
50
+ let value;
51
+ try {
52
+ value = JSON.parse(text);
53
+ }
54
+ catch (error) {
55
+ throw new Error(`${label} must be valid JSON`, { cause: error });
56
+ }
57
+ return cloneBoundedPluginBackendJson(value, label, maxBytes);
58
+ }
59
+ export function parsePluginBackendRequestEnvelope(value) {
60
+ if (!isPlainRecord(value))
61
+ throw new Error("Plugin backend request body must be an object");
62
+ return Object.freeze({
63
+ revision: requirePluginBackendRevision(value["revision"]),
64
+ input: cloneBoundedPluginBackendJson(value["input"], "Plugin backend request input"),
65
+ });
66
+ }
67
+ export function utf8ByteLength(value) {
68
+ return new TextEncoder().encode(value).byteLength;
69
+ }
70
+ function cloneJsonValue(value, ancestors, label, depth) {
71
+ if (depth > MAX_JSON_DEPTH)
72
+ throw new Error(`${label} exceeds the maximum JSON depth of ${String(MAX_JSON_DEPTH)}`);
73
+ if (value === null || typeof value === "string" || typeof value === "boolean")
74
+ return value;
75
+ if (typeof value === "number") {
76
+ if (!Number.isFinite(value))
77
+ throw new Error(`${label} must contain only finite JSON numbers`);
78
+ return value;
79
+ }
80
+ if (Array.isArray(value)) {
81
+ if (ancestors.has(value))
82
+ throw new Error(`${label} must not contain cycles`);
83
+ ancestors.add(value);
84
+ const output = value.map((child) => cloneJsonValue(child, ancestors, label, depth + 1));
85
+ ancestors.delete(value);
86
+ Object.freeze(output);
87
+ return output;
88
+ }
89
+ if (!isPlainRecord(value))
90
+ throw new Error(`${label} must contain only JSON values`);
91
+ if (ancestors.has(value))
92
+ throw new Error(`${label} must not contain cycles`);
93
+ ancestors.add(value);
94
+ const output = {};
95
+ for (const [key, child] of Object.entries(value)) {
96
+ defineJsonProperty(output, key, cloneJsonValue(child, ancestors, label, depth + 1));
97
+ }
98
+ ancestors.delete(value);
99
+ return Object.freeze(output);
100
+ }
101
+ function defineJsonProperty(record, key, value) {
102
+ Object.defineProperty(record, key, { value, enumerable: true, configurable: true, writable: true });
103
+ }
104
+ function isPlainRecord(value) {
105
+ if (typeof value !== "object" || value === null || Array.isArray(value))
106
+ return false;
107
+ const prototype = Object.getPrototypeOf(value);
108
+ return prototype === Object.prototype || prototype === null;
109
+ }
110
+ //# sourceMappingURL=pluginBackendProtocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginBackendProtocol.js","sourceRoot":"","sources":["../../src/shared/pluginBackendProtocol.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,7 @@ export const piWebPluginIdPattern = /^[a-z][a-z0-9.-]*$/u;
2
2
  export function isPiWebPluginId(value) {
3
3
  return piWebPluginIdPattern.test(value);
4
4
  }
5
+ export function isReservedPiWebPluginId(value) {
6
+ return value === "core";
7
+ }
5
8
  //# sourceMappingURL=pluginIds.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pluginIds.js","sourceRoot":"","sources":["../../src/shared/pluginIds.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC"}
1
+ {"version":3,"file":"pluginIds.js","sourceRoot":"","sources":["../../src/shared/pluginIds.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,OAAO,KAAK,KAAK,MAAM,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { isPiWebPluginId } from "./pluginIds.js";
2
+ /** Secret-free commands accepted by the offline recovery CLI. */
3
+ export const PI_WEB_PLUGIN_RECOVERY_COMMANDS = Object.freeze({
4
+ showSafeStart: "pi-web plugins safe-start show",
5
+ bundledOnly: "pi-web plugins safe-start set bundled-only --restart",
6
+ noServerPlugins: "pi-web plugins safe-start set none --restart",
7
+ clearSafeStart: "pi-web plugins safe-start clear --restart",
8
+ });
9
+ export function pluginDisableRecoveryCommand(pluginId) {
10
+ if (!isPiWebPluginId(pluginId))
11
+ throw new Error(`Invalid PI WEB plugin id: ${pluginId}`);
12
+ return `pi-web plugins disable ${pluginId} --restart`;
13
+ }
14
+ //# sourceMappingURL=pluginRecoveryCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pluginRecoveryCommands.js","sourceRoot":"","sources":["../../src/shared/pluginRecoveryCommands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,iEAAiE;AACjE,MAAM,CAAC,MAAM,+BAA+B,GAA0C,MAAM,CAAC,MAAM,CAAC;IAClG,aAAa,EAAE,gCAAgC;IAC/C,WAAW,EAAE,sDAAsD;IACnE,eAAe,EAAE,8CAA8C;IAC/D,cAAc,EAAE,2CAA2C;CAC5D,CAAC,CAAC;AAEH,MAAM,UAAU,4BAA4B,CAAC,QAAgB;IAC3D,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;IACzF,OAAO,0BAA0B,QAAQ,YAAY,CAAC;AACxD,CAAC"}
@@ -1,3 +1,42 @@
1
- export const MAX_IMAGE_PREVIEW_BYTES = 10 * 1024 * 1024;
2
- export const MAX_IMAGE_PREVIEW_LABEL = "10 MB";
1
+ export const MAX_INLINE_PREVIEW_BYTES = 10 * 1024 * 1024;
2
+ export const MAX_INLINE_PREVIEW_LABEL = "10 MB";
3
+ export const MAX_WORKSPACE_FILE_CONTENT_BYTES = 512 * 1024;
4
+ // Extension classification is shared by JSON source reads, streamed previews,
5
+ // and proxy response policy. Keep this an allowlist: only classifications with
6
+ // a preview MIME type may be served as browser-rendered bytes.
7
+ //
8
+ // `source` decides what a JSON file read carries: "text" formats keep capped
9
+ // literal UTF-8 source so the viewer can offer Raw mode, while "stream" formats
10
+ // stay out of JSON and are only ever served as preview bytes.
11
+ const WORKSPACE_FILE_CLASSIFICATIONS = {
12
+ ".avif": { mediaType: "image", source: "stream", previewMimeType: "image/avif" },
13
+ ".bmp": { mediaType: "image", source: "stream", previewMimeType: "image/bmp" },
14
+ ".gif": { mediaType: "image", source: "stream", previewMimeType: "image/gif" },
15
+ ".ico": { mediaType: "image", source: "stream", previewMimeType: "image/x-icon" },
16
+ ".jpeg": { mediaType: "image", source: "stream", previewMimeType: "image/jpeg" },
17
+ ".jpg": { mediaType: "image", source: "stream", previewMimeType: "image/jpeg" },
18
+ ".png": { mediaType: "image", source: "stream", previewMimeType: "image/png" },
19
+ // SVG is markup: it previews as an image but also has readable source, so it
20
+ // keeps literal text for Raw mode.
21
+ ".svg": { mediaType: "image", source: "text", previewMimeType: "image/svg+xml" },
22
+ ".webp": { mediaType: "image", source: "stream", previewMimeType: "image/webp" },
23
+ ".htm": { mediaType: "html", source: "text", previewMimeType: "text/html; charset=utf-8" },
24
+ ".html": { mediaType: "html", source: "text", previewMimeType: "text/html; charset=utf-8" },
25
+ ".pdf": { mediaType: "pdf", source: "stream", previewMimeType: "application/pdf" },
26
+ ".md": { mediaType: "markdown", source: "text" },
27
+ ".markdown": { mediaType: "markdown", source: "text" },
28
+ };
29
+ export function classifyWorkspaceFile(path) {
30
+ const slashIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
31
+ const dotIndex = path.lastIndexOf(".");
32
+ if (dotIndex <= slashIndex)
33
+ return undefined;
34
+ const extension = path.slice(dotIndex).toLowerCase();
35
+ return WORKSPACE_FILE_CLASSIFICATIONS[extension];
36
+ }
37
+ /** Return the leaf filename for either POSIX or Windows-style workspace paths. */
38
+ export function workspaceFileName(path) {
39
+ const separatorIndex = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
40
+ return path.slice(separatorIndex + 1);
41
+ }
3
42
  //# sourceMappingURL=workspaceFiles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspaceFiles.js","sourceRoot":"","sources":["../../src/shared/workspaceFiles.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AACxD,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAC"}
1
+ {"version":3,"file":"workspaceFiles.js","sourceRoot":"","sources":["../../src/shared/workspaceFiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /** Small JSON request carrying the host-issued confirmation precondition. */
2
+ export const WORKSPACE_REMOVAL_REQUEST_BODY_MAX_BYTES = 4 * 1024;
3
+ /** One sessiond-owned deadline across owner resolution, validation, and planning. */
4
+ export const WORKSPACE_REMOVAL_OPERATION_TIMEOUT_MS = 25_000;
5
+ /** Leaves time for cancellation to reach remote web/sessiond before gateway timeout. */
6
+ export const WORKSPACE_REMOVAL_FEDERATION_TIMEOUT_MS = 30_000;
7
+ export const WORKSPACE_REMOVAL_PRECONDITION_MAX_LENGTH = 256;
8
+ export function parseWorkspaceRemovalRequest(value) {
9
+ if (!isRecord(value))
10
+ throw new Error("Workspace removal request must be an object");
11
+ return { precondition: requireWorkspaceRemovalPrecondition(value["precondition"]) };
12
+ }
13
+ export function requireWorkspaceRemovalPrecondition(value) {
14
+ if (typeof value !== "string"
15
+ || value === ""
16
+ || value.length > WORKSPACE_REMOVAL_PRECONDITION_MAX_LENGTH) {
17
+ throw new Error(`Workspace removal precondition must be a non-empty string of at most ${String(WORKSPACE_REMOVAL_PRECONDITION_MAX_LENGTH)} characters`);
18
+ }
19
+ return value;
20
+ }
21
+ function isRecord(value) {
22
+ return typeof value === "object" && value !== null && !Array.isArray(value);
23
+ }
24
+ //# sourceMappingURL=workspaceRemovalProtocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceRemovalProtocol.js","sourceRoot":"","sources":["../../src/shared/workspaceRemovalProtocol.ts"],"names":[],"mappings":"AAEA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,GAAG,IAAI,CAAC;AACjE,qFAAqF;AACrF,MAAM,CAAC,MAAM,sCAAsC,GAAG,MAAM,CAAC;AAC7D,wFAAwF;AACxF,MAAM,CAAC,MAAM,uCAAuC,GAAG,MAAM,CAAC;AAC9D,MAAM,CAAC,MAAM,yCAAyC,GAAG,GAAG,CAAC;AAE7D,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACrF,OAAO,EAAE,YAAY,EAAE,mCAAmC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,KAAc;IAChE,IACE,OAAO,KAAK,KAAK,QAAQ;WACtB,KAAK,KAAK,EAAE;WACZ,KAAK,CAAC,MAAM,GAAG,yCAAyC,EAC3D,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wEAAwE,MAAM,CAAC,yCAAyC,CAAC,aAAa,CACvI,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
package/docs/config.md CHANGED
@@ -40,7 +40,7 @@ defaults → global config file → environment overrides
40
40
 
41
41
  Supported project-local settings are then applied for that project's workspaces. For upload defaults, `<project>/.pi-web/config.json` overrides the global value.
42
42
 
43
- Environment overrides include `PI_WEB_HOST`, `PI_WEB_PORT` / `PORT`, `PI_WEB_ALLOWED_HOSTS`, `PI_WEB_MAX_UPLOAD_BYTES`, `PI_WEB_AGENT_COMMAND`, `PI_WEB_AGENT_DIR`, `PI_WEB_AGENT_SESSION_DIR`, `PI_CODING_AGENT_DIR` / `PI_CODING_AGENT_SESSION_DIR` for Pi compatibility, `PI_WEB_SPAWN_SESSIONS`, `PI_WEB_SUBSESSIONS`, and `PI_WEB_ASK_USER`.
43
+ Environment overrides include `PI_WEB_HOST`, `PI_WEB_PORT` / `PORT`, `PI_WEB_ALLOWED_HOSTS`, `PI_WEB_MAX_UPLOAD_BYTES`, `PI_WEB_AGENT_COMMAND`, `PI_WEB_AGENT_DIR`, `PI_WEB_AGENT_SESSION_DIR`, `PI_CODING_AGENT_DIR` / `PI_CODING_AGENT_SESSION_DIR`, `PI_WEB_ENVIRONMENT_FACTS`, `PI_WEB_SPAWN_SESSIONS`, `PI_WEB_SUBSESSIONS`, and `PI_WEB_ASK_USER`.
44
44
 
45
45
  Process restarts depend on the key:
46
46
 
@@ -72,7 +72,7 @@ Process restarts depend on the key:
72
72
  "dir": "~/agent-profiles/research"
73
73
  },
74
74
  "spawnSessions": true,
75
- "subsessions": false,
75
+ "subsessions": true,
76
76
  "askUser": true,
77
77
  "extensionDialogsTimeoutMs": 300000,
78
78
  "workbenchIntegration": {
@@ -147,8 +147,9 @@ Rows with JSON key `—` are runtime-only environment variables, not config-file
147
147
  | Companion CLI command | `agent.command` | `PI_WEB_AGENT_COMMAND` | Global/session daemon | Not supported locally | Restart session daemon on that machine; affects doctor/status/update checks |
148
148
  | Agent profile state directory | `agent.dir` | `PI_WEB_AGENT_DIR` (`PI_CODING_AGENT_DIR` for Pi compatibility) | Global/session daemon | Not supported locally | Restart session daemon on that machine; affects auth, models, settings, sessions, Pi packages, and Pi-package-backed PI WEB plugins |
149
149
  | Agent can spawn sessions | `spawnSessions` | `PI_WEB_SPAWN_SESSIONS` | Global/session daemon | Not supported locally | Restart session daemon on that machine |
150
- | Tracked subsessions (beta) | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon on that machine |
150
+ | Tracked subsessions | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon on that machine |
151
151
  | Agent can post question forms | `askUser` | `PI_WEB_ASK_USER` | Global/session daemon | Not supported locally | Restart session daemon on that machine |
152
+ | Ordinary-session environment facts | `environmentFacts` | `PI_WEB_ENVIRONMENT_FACTS` | Global/session daemon | Not supported locally | Restart session daemon on that machine; affects newly started sessions |
152
153
  | 扩展对话框自动取消超时 | `extensionDialogsTimeoutMs` | — | 全局/会话守护进程 | 不支持项目级配置 | 重启对应机器上的会话守护进程 |
153
154
  | Workbench/MCP integration | `workbenchIntegration.*` | `PI_WEB_WORKBENCH_URL`, `PI_WEB_MCP_URL`, `PI_WEB_WORKBENCH_TIMEOUT_MS`, `PI_WEB_MCP_TIMEOUT_MS`, `PI_WEB_SKILL_BUNDLE_MAX_BYTES`, `PI_WEB_SKILL_FILE_MAX_BYTES`, `PI_WEB_SKILL_FILE_COUNT_MAX` | Web/API + session daemon | Not supported locally | Restart web/API and session daemon; both must match |
154
155
  | Ordinary tool audit | `auditLog.normalMode.*` | — | Global/session daemon | Not supported locally | Restart session daemon |
@@ -264,6 +265,8 @@ The per-request size limit is still controlled by `maxUploadBytes` / `PI_WEB_MAX
264
265
 
265
266
  ### Pi-compatible agent profile and companion CLI
266
267
 
268
+ PI WEB embeds Pi Coding Agent `0.84.x` or newer compatible runtime packages. The session daemon owns one resolved Pi state directory and refuses to start a second daemon against the same `PI_WEB_DATA_DIR`; use distinct data and endpoint variables for another instance.
269
+
267
270
  `agent.command` selects the Pi-compatible companion CLI used by `pi-web doctor` and, when it can be generated safely, package-managed update commands. It defaults to `pi`. This setting does **not** replace the embedded runtime: every session continues to use PI WEB's bundled Pi SDK.
268
271
 
269
272
  `agent.dir` selects the Pi-compatible state profile used for auth providers, models, settings, sessions, Pi packages, and Pi-package-backed PI WEB plugin discovery. It defaults to `~/.pi/agent` only for a canonical Pi companion command. The directory must use the data layout supported by the bundled Pi SDK; PI WEB does not load or convert incompatible fork formats, migrate profile data, or repartition PI WEB-managed archives when the profile changes.
@@ -279,7 +282,9 @@ The per-request size limit is still controlled by `maxUploadBytes` / `PI_WEB_MAX
279
282
 
280
283
  An alternate command always requires an explicit state directory. The command must be a safe bare executable name such as `pi-lab` or a host-absolute executable path such as `/opt/pi/bin/pi`; relative paths, shell expressions, and launcher strings are rejected. The state directory must be host-absolute or start with `~`. In a federated save, the gateway transports Unix and Windows absolute paths without reinterpreting them, and the target machine validates and returns the persisted profile.
281
284
 
282
- Environment variables take precedence over the config file. `PI_WEB_AGENT_COMMAND` selects the companion CLI, `PI_WEB_AGENT_DIR` sets the profile state directory, and `PI_WEB_AGENT_SESSION_DIR` overrides session storage separately from `agent.dir`. The legacy `PI_CODING_AGENT_DIR` and `PI_CODING_AGENT_SESSION_DIR` names apply only to a canonical Pi companion command; PI WEB never derives ambient environment-variable names from an arbitrary command. Use the explicit `PI_WEB_AGENT_*` names for alternate commands. `PI_WEB_AGENT_DIR` is an unconditional override, while a legacy `PI_CODING_AGENT_DIR` override stops applying when Settings selects an alternate command so the command and directory can transition together.
285
+ Environment variables take precedence over the config file. For the state directory, precedence is `PI_WEB_AGENT_DIR` > `PI_CODING_AGENT_DIR` > `agent.dir` > the Pi default. For session storage, `PI_WEB_AGENT_SESSION_DIR` remains first for compatibility, followed by `PI_CODING_AGENT_SESSION_DIR`. The resolved directory is exported as `PI_CODING_AGENT_DIR` to embedded Pi processes.
286
+
287
+ `environmentFacts` controls factual system-prompt sections appended only to ordinary sessions. These describe PI WEB session nesting and, when the daemon runs in Docker, the observed container filesystem, persistent mounts, host access, and development mount shape. `PI_WEB_ENVIRONMENT_FACTS` takes precedence and accepts `0|1|true|false`; the default is enabled. Set it to `false` to disable all such sections, restart the session daemon, and start a new session. Existing sessions retain the prompt they started with. Management-embed sessions do not receive these ordinary-session facts.
283
288
 
284
289
  The session daemon resolves the persisted desired values plus its environment once at startup. That secret-free active profile stays fixed for the daemon lifetime. **Settings → Session daemon** saves command and directory together as desired configuration and shows whether the profile is active, needs a restart, or cannot be compared. Until the daemon restarts, sessions, Pi package operations, Pi-package-backed PI WEB plugin discovery, status/install detection, and update planning continue to use the daemon-owned active profile; a web/API restart recovers that same active profile instead of applying the newly saved values.
285
290
 
@@ -335,10 +340,12 @@ To turn the background refresh off entirely, set `PI_WEB_OFFLINE` or `PI_OFFLINE
335
340
 
336
341
  `spawnSessions` controls whether agents receive the `spawn_session` tool. It defaults to `true`; set it to `false` if you do not want an agent to start independent PI WEB sessions.
337
342
 
338
- `subsessions` is beta and controls whether agents receive the tracked-subsession tools: `spawn_subsession`, `list_subsessions`, `check_subsession`, `read_subsession`, and `yield_to_subsessions`. It defaults to `false` and also requires `spawnSessions` to be enabled.
343
+ `subsessions` controls whether agents receive the tracked-subsession tools: `spawn_subsession`, `list_subsessions`, `check_subsession`, `read_subsession`, and `yield_to_subsessions`. It defaults to `true` and also requires `spawnSessions` to be enabled.
339
344
 
340
345
  Tracked subsessions are join-oriented. Calling `spawn_subsession` returns immediately, so the parent can continue independent work while the child runs. Work whose result the parent does not need to join belongs in the fire-and-forget `spawn_session` tool instead.
341
346
 
347
+ A tracked subsession always runs in the spawning session's working directory, so it stays in that workspace's session tree next to its parent. `spawn_subsession` takes no `cwd`. For work in another workspace, use `spawn_session` to create an independent session there.
348
+
342
349
  At a join point, after finishing its independent work, the parent calls `yield_to_subsessions` alone as the final action in its tool batch. Pi ends a tool batch early only when every result in that batch is terminating. If any tracked child is still working, the action ends the current agent run so the parent becomes idle. If none are working, it does not end the run and clearly reports that there is nothing to wait for.
343
350
 
344
351
  A completion notice wakes an idle parent or queues behind in-flight work. Each notice lists any other tracked children still working, so the parent can continue work or call `yield_to_subsessions` again at the next join point. Further notices arrive automatically; do not poll. The notice includes the child's final output when it fits. If that output is too long, PI WEB omits it entirely instead of adding a truncated duplicate to the parent's context and directs the parent to retrieve it with `check_subsession`.
package/docs/plugins.md CHANGED
@@ -133,7 +133,7 @@ Module shape excerpt:
133
133
 
134
134
  ```js
135
135
  export default {
136
- apiVersion: 1,
136
+ apiVersion: 2,
137
137
  name: "Info Plugin",
138
138
  activate: ({ html, svg }) => ({
139
139
  contributions: {
@@ -301,6 +301,8 @@ Review task configs before running them, especially in shared projects. Workspac
301
301
 
302
302
  A relay is a directory of markdown notes under `.pi-web/relays/<name>/` in the workspace root — the convention used by the Relay method for chaining agent sessions. The tab lists each relay's documents with `status.md`, `charter.md`, and `log.md` first (in that order), followed by any other files alphabetically, and opens `status.md` by default. Markdown documents render as sanitized HTML; other files render as preformatted text, and binary files have no preview. Truncated documents show a notice, and **Refresh** re-scans the workspace and reloads the open document.
303
303
 
304
+ Documents in subfolders are listed too. Folders appear as chips in the document strip, and expanding one inserts its files inline after it. Expanding a folder collapses its siblings at the same level, while collapsing the folder that contains the open document keeps the selection and highlights that folder. Relay trees deeper than five levels, larger than 200 documents, or containing more than 50 folders are listed partially with a notice.
305
+
304
306
  With several relays, a picker pre-selects the most recently modified one; a single relay opens directly. A workspace without `.pi-web/relays/` shows an empty state explaining the convention. The tab never creates, edits, or deletes relay files.
305
307
 
306
308
  Relays is enabled by default. To hide it, disable `relays` in **Settings → PI WEB plugins** or set:
@@ -409,14 +411,15 @@ The entry module must default-export a plugin object:
409
411
 
410
412
  ```ts
411
413
  interface PiWebPlugin {
412
- apiVersion: 1;
414
+ apiVersion: 2;
413
415
  name: string;
414
416
  activate: (context: PluginActivationContext) => PluginActivationResult;
415
417
  }
416
418
 
417
419
  interface PluginActivationContext {
418
- apiVersion: 1;
420
+ apiVersion: 2;
419
421
  pluginId: string;
422
+ runtimePluginId?: string;
420
423
  html: typeof import("lit").html;
421
424
  svg: typeof import("lit").svg;
422
425
  }
@@ -430,7 +433,7 @@ Example:
430
433
 
431
434
  ```js
432
435
  export default {
433
- apiVersion: 1,
436
+ apiVersion: 2,
434
437
  name: "My Plugin",
435
438
  activate: ({ pluginId, html }) => ({
436
439
  contributions: {
@@ -444,6 +447,8 @@ export default {
444
447
 
445
448
  `activate()` is called once when the UI loads the plugin. Keep it cheap: define contributions there, but move expensive or async work into actions, custom elements, or explicit user interactions.
446
449
 
450
+ Browser API v2 is a deliberate compatibility break. PI WEB rejects browser API v1 modules instead of silently adapting them. Migrate by setting `apiVersion: 2`, using `pluginId` for the stable package/provider identity, and using `runtimePluginId` when a host-qualified contribution id is required. The former `@chainingintention/pi-web-cn/plugin-api/unstable` path is no longer exported; rely on the documented stable helpers instead.
451
+
447
452
  The plugin id comes from `package.json`, not from the JavaScript module. Contribution ids are local to the plugin and PI WEB qualifies them internally as:
448
453
 
449
454
  ```text
@@ -535,7 +540,7 @@ Notes:
535
540
  - `enabled` is evaluated when the action palette asks for actions.
536
541
  - `selectWorkspaceTool()` expects a qualified panel id such as `my-plugin:workspace.info`.
537
542
  - `openTerminal()` switches to the built-in terminal panel. Pass `{ terminalId }` to deep-link to a specific terminal.
538
- - Only fields documented here and declared in `plugin-api.d.ts` are stable public plugin API. Unstable runtime fields are intentionally omitted from these types; if a plugin author chooses to depend on them, they must explicitly import unstable types from `@chainingintention/pi-web-cn/plugin-api/unstable` and type-assert the context in their own code.
543
+ - Only fields documented here and declared in `plugin-api.d.ts` are stable public browser plugin API. Runtime-only fields and private HTTP routes are not compatibility surfaces.
539
544
 
540
545
  ### Prompt editor API
541
546
 
@@ -760,7 +765,7 @@ if (!customElements.get("my-workspace-badge")) {
760
765
  }
761
766
 
762
767
  export default {
763
- apiVersion: 1,
768
+ apiVersion: 2,
764
769
  name: "My Plugin",
765
770
  activate: ({ html }) => ({
766
771
  contributions: {
@@ -995,18 +1000,7 @@ Review command strings carefully. They are trusted shell commands executed in th
995
1000
 
996
1001
  PI WEB's `/api/...` HTTP and WebSocket routes and runtime-only fields are private implementation details. They exist because plugins are trusted browser code, and because some capabilities may be evaluated there before they are designed as stable helpers.
997
1002
 
998
- If a plugin author deliberately chooses to depend on an unstable runtime field while a public helper is still being designed, make that decision explicit in code with a type-only unstable import and a local type assertion:
999
-
1000
- ```ts
1001
- import type { WorkspacePanelContext } from "@chainingintention/pi-web-cn/plugin-api";
1002
- import type { UnstableWorkspacePanelContext } from "@chainingintention/pi-web-cn/plugin-api/unstable";
1003
-
1004
- function unstableContext(context: WorkspacePanelContext) {
1005
- return context as WorkspacePanelContext & UnstableWorkspacePanelContext;
1006
- }
1007
- ```
1008
-
1009
- Unstable APIs are not covered by the v1 compatibility promise. Prefer documented helpers whenever they exist.
1003
+ The stable browser API is the documented helper surface and the type-only `@chainingintention/pi-web-cn/plugin-api` export. The stable server API is the separate type-only `@chainingintention/pi-web-cn/server-plugin-api` export. The former browser `plugin-api/unstable` entry is not part of API v2 and is no longer exported. Code that deliberately depends on another private runtime surface must keep that dependency local and expect to revisit it after PI WEB upgrades.
1010
1004
 
1011
1005
  ## Async data and caching
1012
1006
 
@@ -1024,7 +1018,7 @@ If you are an AI agent building or editing a PI WEB plugin, follow this checklis
1024
1018
 
1025
1019
  1. Create or update a plugin folder with `package.json` and a JavaScript module such as `pi-web-plugin.js`.
1026
1020
  2. Use the single supported package metadata shape: `piWeb.plugins` array with `{ id, module, machineSpecific? }` entries.
1027
- 3. Default-export `{ apiVersion: 1, name, activate }` from the module.
1021
+ 3. Default-export `{ apiVersion: 2, name, activate }` from a browser module. Server modules use server-plugin API v1.
1028
1022
  4. Return `{ contributions: { actions, workspacePanels, workspaceLabels } }` from `activate()`.
1029
1023
  5. Use ids matching `^[a-z][a-z0-9.-]*$`.
1030
1024
  6. Use the activation context's `html` function for Lit templates.
@@ -1034,7 +1028,7 @@ If you are an AI agent building or editing a PI WEB plugin, follow this checklis
1034
1028
  10. Add workspace labels for compact inline metadata.
1035
1029
  11. Return arrays from workspace label `items()`; return an empty array to render nothing.
1036
1030
  12. Use documented context helpers first: `files`, `terminal`, `host.requestRender`, `workspace`, `machine`, `state.selectedWorkspace`, `state.selectedSession`, `state.piWebStatus`, and `prompt`.
1037
- 13. Do not fetch PI WEB `/api/...` endpoints directly unless you intentionally accept private API churn; prefer documented helpers. If an unstable runtime field is intentionally required, import the type from `@chainingintention/pi-web-cn/plugin-api/unstable` and type-assert locally.
1031
+ 13. Do not fetch PI WEB `/api/...` endpoints directly unless you intentionally accept private API churn; prefer documented helpers such as the paired workspace `backend` bridge.
1038
1032
  14. Treat plugins as trusted code and avoid reading or displaying secrets unless intentional.
1039
1033
  15. After local edits, tell the user to hard reload the browser and check the console for plugin errors.
1040
1034
 
@@ -1056,7 +1050,7 @@ Common issues:
1056
1050
 
1057
1051
  - invalid plugin id or contribution id;
1058
1052
  - missing default export;
1059
- - missing `apiVersion: 1`, `name`, or `activate` function;
1053
+ - missing browser `apiVersion: 2`, `name`, or `activate` function;
1060
1054
  - missing `package.json` or incorrect `piWeb.plugins` metadata;
1061
1055
  - legacy shortcuts such as `piWeb.plugin`, string plugin entries, or no-`package.json` fallback;
1062
1056
  - duplicate plugin ids; later duplicates are skipped rather than renamed;
package/package.json CHANGED
@@ -1,10 +1,28 @@
1
1
  {
2
2
  "name": "@chainingintention/pi-web-cn",
3
- "version": "1.202608.8",
3
+ "version": "2.0.0",
4
4
  "description": "Remote web UI and browser control plane for persistent Pi Coding Agent sessions.",
5
5
  "license": "MIT",
6
6
  "author": "Federico Jaramillo Martinez",
7
7
  "type": "module",
8
+ "exports": {
9
+ "./plugin-api": {
10
+ "types": "./dist/plugin-api.d.ts"
11
+ },
12
+ "./server-plugin-api": {
13
+ "types": "./dist/server-plugin-api.d.ts"
14
+ }
15
+ },
16
+ "typesVersions": {
17
+ "*": {
18
+ "plugin-api": [
19
+ "dist/plugin-api.d.ts"
20
+ ],
21
+ "server-plugin-api": [
22
+ "dist/server-plugin-api.d.ts"
23
+ ]
24
+ }
25
+ },
8
26
  "bin": {
9
27
  "pi-web": "dist/cli.js",
10
28
  "pi-web-server": "dist/server/index.js",
@@ -16,12 +34,13 @@
16
34
  "install.sh",
17
35
  "README.md",
18
36
  "LICENSE",
37
+ "skills/relay/SKILL.md",
19
38
  "extensions",
20
39
  "docs/plugins.md",
21
40
  "docs/config.md",
22
41
  "docs/assets",
23
42
  "plugin-api.d.ts",
24
- "plugin-api/unstable.d.ts"
43
+ "server-plugin-api.d.ts"
25
44
  ],
26
45
  "scripts": {
27
46
  "dev": "bash -c 'trap \"kill 0\" EXIT; npm run dev:sessiond & npm run dev:web & npm run dev:client & wait'",
@@ -84,9 +103,9 @@
84
103
  },
85
104
  "devDependencies": {
86
105
  "@changesets/cli": "^2.31.0",
87
- "@earendil-works/pi-agent-core": "^0.82.1",
88
- "@earendil-works/pi-ai": "^0.82.1",
89
- "@earendil-works/pi-coding-agent": "^0.82.1",
106
+ "@earendil-works/pi-agent-core": "^0.84.1",
107
+ "@earendil-works/pi-ai": "^0.84.1",
108
+ "@earendil-works/pi-coding-agent": "^0.84.1",
90
109
  "@eslint/js": "^10.0.1",
91
110
  "@types/node": "^24.13.3",
92
111
  "@types/ws": "^8.18.1",
@@ -119,9 +138,9 @@
119
138
  "homepage": "https://github.com/nayuto-wakusei/pi-web-ChineseTranslation#readme",
120
139
  "packageManager": "npm@11.11.0",
121
140
  "peerDependencies": {
122
- "@earendil-works/pi-agent-core": ">=0.82.1 <0.83",
123
- "@earendil-works/pi-ai": ">=0.82.1 <0.83",
124
- "@earendil-works/pi-coding-agent": ">=0.82.1 <0.83"
141
+ "@earendil-works/pi-agent-core": ">=0.84.0",
142
+ "@earendil-works/pi-ai": ">=0.84.0",
143
+ "@earendil-works/pi-coding-agent": ">=0.84.0"
125
144
  },
126
145
  "keywords": [
127
146
  "pi-package",
@@ -0,0 +1 @@
1
+ export * from "./dist/server-plugin-api.js";
@@ -0,0 +1,12 @@
1
+ # skills
2
+
3
+ Distributable agent skills developed alongside pi-web.
4
+
5
+ ## relay
6
+
7
+ Execute a long or complex plan as a chain of independent sessions, each running
8
+ one well-sized leg and handing off to the next via `spawn_session`.
9
+
10
+ ```bash
11
+ npx skills add jmfederico/pi-web --skill relay -a pi -g
12
+ ```