@chainingintention/pi-web-cn 1.202606.4 → 1.202606.6

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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/client/assets/{CodeViewer-BNKhIElN.js → CodeViewer-8znVN61S.js} +1 -1
  3. package/dist/client/assets/{TerminalPanel-VPiiPQfC.js → TerminalPanel-DrdWnF1y.js} +1 -1
  4. package/dist/client/assets/index-BiGrW6IC.js +2169 -0
  5. package/dist/client/index.html +1 -1
  6. package/dist/config.js +72 -0
  7. package/dist/config.js.map +1 -1
  8. package/dist/plugin-api.d.ts +17 -11
  9. package/dist/server/app.js +55 -17
  10. package/dist/server/app.js.map +1 -1
  11. package/dist/server/configRoutes.js +77 -0
  12. package/dist/server/configRoutes.js.map +1 -1
  13. package/dist/server/gitRoutes.js +16 -3
  14. package/dist/server/gitRoutes.js.map +1 -1
  15. package/dist/server/machines/machinePluginProxyRoutes.js +179 -0
  16. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
  17. package/dist/server/machines/machineProxyRoutes.js +1 -0
  18. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  19. package/dist/server/managementEmbed.js +205 -0
  20. package/dist/server/managementEmbed.js.map +1 -0
  21. package/dist/server/sessiond/sessionProxyRoutes.js +66 -8
  22. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  23. package/dist/server/sessions/managementPermissionSystem.js +94 -0
  24. package/dist/server/sessions/managementPermissionSystem.js.map +1 -0
  25. package/dist/server/sessions/managementSandbox.js +156 -0
  26. package/dist/server/sessions/managementSandbox.js.map +1 -0
  27. package/dist/server/sessions/piSessionService.js +339 -31
  28. package/dist/server/sessions/piSessionService.js.map +1 -1
  29. package/dist/server/sessions/sessionNameGenerator.js +2 -0
  30. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  31. package/dist/server/sessions/sessionRoutes.js +9 -4
  32. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  33. package/dist/server/terminalProxyRoutes.js +64 -8
  34. package/dist/server/terminalProxyRoutes.js.map +1 -1
  35. package/dist/server/terminals/terminalRoutes.js +23 -3
  36. package/dist/server/terminals/terminalRoutes.js.map +1 -1
  37. package/dist/server/terminals/terminalService.js +54 -4
  38. package/dist/server/terminals/terminalService.js.map +1 -1
  39. package/dist/server/workspaceExplorerRoutes.js +103 -4
  40. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  41. package/dist/server/workspaces/fileOperationService.js +95 -0
  42. package/dist/server/workspaces/fileOperationService.js.map +1 -0
  43. package/dist/server/workspaces/fileUploadService.js +23 -0
  44. package/dist/server/workspaces/fileUploadService.js.map +1 -0
  45. package/dist/server/workspaces/pathSafety.js +9 -2
  46. package/dist/server/workspaces/pathSafety.js.map +1 -1
  47. package/dist/server/workspaces/workspaceDeletionRoutes.js +127 -0
  48. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
  49. package/dist/sessiond/sessionDaemonClient.js +12 -12
  50. package/dist/sessiond/sessionDaemonClient.js.map +1 -1
  51. package/dist/shared/apiTypes.d.ts +30 -0
  52. package/dist/shared/federatedRoutes.js +9 -0
  53. package/dist/shared/federatedRoutes.js.map +1 -1
  54. package/dist/shared/machinePluginIds.js +41 -0
  55. package/dist/shared/machinePluginIds.js.map +1 -0
  56. package/dist/shared/workspaceDeletion.js +12 -0
  57. package/dist/shared/workspaceDeletion.js.map +1 -0
  58. package/docs/plugins.md +88 -12
  59. package/package.json +1 -1
  60. package/dist/client/assets/index-Csx3hC75.js +0 -1994
@@ -0,0 +1,127 @@
1
+ import { workspaceDeletionMetadata } from "../../shared/workspaceDeletion.js";
2
+ import { SessionDaemonClient } from "../../sessiond/sessionDaemonClient.js";
3
+ import { encodeManagementContext, managementContextForRequest, managementToolAllowed, MANAGEMENT_EMBED_CONTEXT_HEADER, projectFromManagedEmbedContext, } from "../managementEmbed.js";
4
+ export function registerWorkspaceDeletionRoutes(app, projects, workspaces, daemon = new SessionDaemonClient(), prefix = "/api", managementEmbed) {
5
+ app.delete(`${prefix}/projects/:projectId/workspaces/:workspaceId`, async (request, reply) => {
6
+ try {
7
+ const managementContext = await managementContextForRequest(request, managementEmbed);
8
+ if (managementContext !== undefined && !managementToolAllowed(managementContext, "terminal-command-runs"))
9
+ return await reply.code(403).send({ error: "Terminal command runs are disabled in management embed mode" });
10
+ return await deleteWorkspace(projects, workspaces, daemon, request.params.projectId, request.params.workspaceId, managementEmbed, managementContext);
11
+ }
12
+ catch (error) {
13
+ return reply.code(400).send({ error: error instanceof Error ? error.message : String(error) });
14
+ }
15
+ });
16
+ }
17
+ async function deleteWorkspace(projects, workspaces, daemon, projectId, workspaceId, managementEmbed, managementContext) {
18
+ const project = managementContext === undefined
19
+ ? await projects.requireProject(projectId)
20
+ : await projectFromManagedEmbedContext(managementProjectRoot(managementEmbed), managementContext, projectId);
21
+ const projectWorkspaces = await workspaces.list(project);
22
+ const targetWorkspace = projectWorkspaces.find((workspace) => workspace.id === workspaceId);
23
+ if (targetWorkspace === undefined)
24
+ throw new Error("Workspace not found");
25
+ if (!canDeleteWorkspace(targetWorkspace))
26
+ throw new Error("Only secondary Git worktrees can be deleted");
27
+ const commandWorkspace = projectWorkspaces.find((workspace) => workspace.isMain) ?? projectWorkspaces.find((workspace) => workspace.id !== targetWorkspace.id);
28
+ if (commandWorkspace === undefined)
29
+ throw new Error("Project main workspace not found");
30
+ const closeResponse = await requestJson(daemon, "DELETE", `/terminals?cwd=${encodeURIComponent(targetWorkspace.path)}`, undefined, managementHeaders(managementContext));
31
+ if (closeResponse.statusCode < 200 || closeResponse.statusCode >= 300)
32
+ throw new Error(`Failed to close workspace terminals: ${responseError(closeResponse.body, closeResponse.statusCode)}`);
33
+ const deleteResponse = await requestJson(daemon, "POST", "/terminal-command-runs", {
34
+ origin: "core",
35
+ projectId: project.id,
36
+ workspaceId: commandWorkspace.id,
37
+ cwd: commandWorkspace.path,
38
+ title: `Delete workspace: ${workspaceLabel(targetWorkspace)}`,
39
+ command: `git worktree remove ${shellQuote(targetWorkspace.path)}`,
40
+ metadata: workspaceDeletionMetadata(targetWorkspace),
41
+ }, managementHeaders(managementContext));
42
+ if (deleteResponse.statusCode < 200 || deleteResponse.statusCode >= 300)
43
+ throw new Error(`Failed to start workspace deletion: ${responseError(deleteResponse.body, deleteResponse.statusCode)}`);
44
+ return parseTerminalCommandRun(deleteResponse.body);
45
+ }
46
+ function canDeleteWorkspace(workspace) {
47
+ return workspace.isGitWorktree && !workspace.isMain;
48
+ }
49
+ function workspaceLabel(workspace) {
50
+ return workspace.branch ?? workspace.label;
51
+ }
52
+ async function requestJson(daemon, method, path, body, headers) {
53
+ const response = await daemon.request(method, path, body, headers);
54
+ return { statusCode: response.statusCode, body: response.body === "" ? undefined : JSON.parse(response.body) };
55
+ }
56
+ function managementHeaders(context) {
57
+ return context === undefined ? undefined : { [MANAGEMENT_EMBED_CONTEXT_HEADER]: encodeManagementContext(context) };
58
+ }
59
+ function managementProjectRoot(managementEmbed) {
60
+ if (managementEmbed === undefined)
61
+ throw new Error("Management embed mode is not configured");
62
+ return managementEmbed.projectRoot;
63
+ }
64
+ function responseError(body, statusCode) {
65
+ if (isRecord(body) && typeof body["error"] === "string")
66
+ return body["error"];
67
+ return `HTTP ${String(statusCode)}`;
68
+ }
69
+ function parseTerminalCommandRun(value) {
70
+ if (!isRecord(value))
71
+ throw new Error("Invalid terminal command run response");
72
+ const metadata = value["metadata"];
73
+ if (!isRecord(metadata))
74
+ throw new Error("Invalid terminal command run response");
75
+ const startedAt = optionalString(value, "startedAt");
76
+ const exitCode = optionalNumber(value, "exitCode");
77
+ const completedAt = optionalString(value, "completedAt");
78
+ return {
79
+ id: requireString(value, "id"),
80
+ origin: requireString(value, "origin"),
81
+ projectId: requireString(value, "projectId"),
82
+ workspaceId: requireString(value, "workspaceId"),
83
+ terminalId: requireString(value, "terminalId"),
84
+ title: requireString(value, "title"),
85
+ command: requireString(value, "command"),
86
+ status: parseStatus(value["status"]),
87
+ createdAt: requireString(value, "createdAt"),
88
+ metadata: Object.fromEntries(Object.entries(metadata).filter((entry) => typeof entry[1] === "string")),
89
+ ...(startedAt === undefined ? {} : { startedAt }),
90
+ ...(exitCode === undefined ? {} : { exitCode }),
91
+ ...(completedAt === undefined ? {} : { completedAt }),
92
+ };
93
+ }
94
+ function parseStatus(value) {
95
+ if (value === "queued" || value === "running" || value === "succeeded" || value === "failed")
96
+ return value;
97
+ throw new Error("Invalid terminal command run response");
98
+ }
99
+ function requireString(record, field) {
100
+ const value = record[field];
101
+ if (typeof value !== "string")
102
+ throw new Error("Invalid terminal command run response");
103
+ return value;
104
+ }
105
+ function optionalString(record, field) {
106
+ const value = record[field];
107
+ if (value === undefined)
108
+ return undefined;
109
+ if (typeof value !== "string")
110
+ throw new Error("Invalid terminal command run response");
111
+ return value;
112
+ }
113
+ function optionalNumber(record, field) {
114
+ const value = record[field];
115
+ if (value === undefined)
116
+ return undefined;
117
+ if (typeof value !== "number")
118
+ throw new Error("Invalid terminal command run response");
119
+ return value;
120
+ }
121
+ function shellQuote(value) {
122
+ return `'${value.replaceAll("'", "'\\''")}'`;
123
+ }
124
+ function isRecord(value) {
125
+ return typeof value === "object" && value !== null && !Array.isArray(value);
126
+ }
127
+ //# sourceMappingURL=workspaceDeletionRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceDeletionRoutes.js","sourceRoot":"","sources":["../../../src/server/workspaces/workspaceDeletionRoutes.ts"],"names":[],"mappings":"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"}
@@ -6,24 +6,24 @@ export class SessionDaemonClient {
6
6
  this.baseUrl = sessiondHttpUrl();
7
7
  this.socketPath = sessiondSocketPath();
8
8
  }
9
- async request(method, path, body) {
9
+ async request(method, path, body, headers = {}) {
10
10
  const payload = body === undefined ? undefined : JSON.stringify(body);
11
11
  if (this.baseUrl !== undefined && this.baseUrl !== "")
12
- return this.requestUrl(method, path, payload);
13
- return this.requestSocket(method, path, payload);
12
+ return this.requestUrl(method, path, payload, headers);
13
+ return this.requestSocket(method, path, payload, headers);
14
14
  }
15
- connectWebSocket(path) {
15
+ connectWebSocket(path, headers = {}) {
16
16
  if (this.baseUrl !== undefined && this.baseUrl !== "") {
17
17
  const url = new URL(path, this.baseUrl);
18
18
  url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
19
- return new WebSocket(url);
19
+ return new WebSocket(url, { headers });
20
20
  }
21
- return new WebSocket(`ws+unix:${this.socketPath}:${path}`);
21
+ return new WebSocket(`ws+unix:${this.socketPath}:${path}`, { headers });
22
22
  }
23
- async requestUrl(method, path, payload) {
24
- const init = { method };
23
+ async requestUrl(method, path, payload, headers = {}) {
24
+ const init = { method, headers };
25
25
  if (payload !== undefined && payload !== "") {
26
- init.headers = { "content-type": "application/json" };
26
+ init.headers = { ...headers, "content-type": "application/json" };
27
27
  init.body = payload;
28
28
  }
29
29
  const response = await fetch(new URL(path, this.baseUrl), init);
@@ -33,15 +33,15 @@ export class SessionDaemonClient {
33
33
  body: await response.text(),
34
34
  };
35
35
  }
36
- requestSocket(method, path, payload) {
36
+ requestSocket(method, path, payload, headers = {}) {
37
37
  return new Promise((resolve, reject) => {
38
38
  const request = http.request({
39
39
  socketPath: this.socketPath,
40
40
  path,
41
41
  method,
42
42
  headers: payload !== undefined && payload !== ""
43
- ? { "content-type": "application/json", "content-length": Buffer.byteLength(payload) }
44
- : undefined,
43
+ ? { ...headers, "content-type": "application/json", "content-length": Buffer.byteLength(payload) }
44
+ : headers,
45
45
  }, (response) => {
46
46
  const chunks = [];
47
47
  response.on("data", (chunk) => {
@@ -1 +1 @@
1
- {"version":3,"file":"sessionDaemonClient.js","sourceRoot":"","sources":["../../src/sessiond/sessionDaemonClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionDaemonClient.js","sourceRoot":"","sources":["../../src/sessiond/sessionDaemonClient.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,24 @@ export interface PiWebConfigValues {
33
33
  allowedHosts?: string[] | true;
34
34
  shortcuts?: PiWebShortcutConfig;
35
35
  plugins?: PiWebPluginConfigMap;
36
+ managementEmbed?: PiWebManagementEmbedConfig;
37
+ }
38
+ export interface PiWebManagementEmbedConfig {
39
+ enabled?: boolean;
40
+ projectRoot?: string;
41
+ auth?: {
42
+ introspectionUrl?: string;
43
+ serviceSecretEnv?: string;
44
+ };
45
+ sandbox?: {
46
+ pythonExecutable?: string;
47
+ env?: Record<string, string>;
48
+ };
49
+ tools?: {
50
+ allow?: string[];
51
+ deny?: string[];
52
+ permissions?: Record<string, boolean>;
53
+ };
36
54
  }
37
55
  export type PiWebPluginScope = "bundled" | "local" | "user" | "project";
38
56
  export interface PiWebPluginInfo {
@@ -226,6 +244,18 @@ export interface FileContentResponse {
226
244
  truncated: boolean;
227
245
  binary: boolean;
228
246
  }
247
+ export interface WorkspaceUploadResponse {
248
+ path: string;
249
+ size: number;
250
+ modifiedAt: string;
251
+ }
252
+ export interface WorkspacePathOperationResponse {
253
+ path: string;
254
+ }
255
+ export interface WorkspaceDeleteResponse {
256
+ deleted: true;
257
+ path: string;
258
+ }
229
259
  export type GitFileState = "unmodified" | "modified" | "added" | "deleted" | "renamed" | "copied" | "untracked" | "ignored" | "conflicted";
230
260
  export interface GitStatusFile {
231
261
  path: string;
@@ -4,13 +4,22 @@ export const FEDERATED_HTTP_ROUTES = [
4
4
  { method: "DELETE", path: "/projects/:projectId" },
5
5
  { method: "GET", path: "/project-directories" },
6
6
  { method: "GET", path: "/projects/:projectId/workspaces" },
7
+ { method: "DELETE", path: "/projects/:projectId/workspaces/:workspaceId" },
7
8
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/tree" },
8
9
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/file" },
10
+ { method: "POST", path: "/projects/:projectId/workspaces/:workspaceId/file" },
11
+ { method: "PATCH", path: "/projects/:projectId/workspaces/:workspaceId/file" },
12
+ { method: "DELETE", path: "/projects/:projectId/workspaces/:workspaceId/file" },
13
+ { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/file/download" },
9
14
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/file/preview" },
15
+ { method: "POST", path: "/projects/:projectId/workspaces/:workspaceId/directory" },
16
+ { method: "PATCH", path: "/projects/:projectId/workspaces/:workspaceId/directory" },
17
+ { method: "DELETE", path: "/projects/:projectId/workspaces/:workspaceId/directory" },
10
18
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/git/status" },
11
19
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/git/diff" },
12
20
  { method: "GET", path: "/projects/:projectId/workspaces/:workspaceId/terminals" },
13
21
  { method: "POST", path: "/projects/:projectId/workspaces/:workspaceId/terminals" },
22
+ { method: "DELETE", path: "/projects/:projectId/workspaces/:workspaceId/terminals" },
14
23
  { method: "POST", path: "/projects/:projectId/workspaces/:workspaceId/terminals/:terminalId/continue" },
15
24
  { method: "DELETE", path: "/projects/:projectId/workspaces/:workspaceId/terminals/:terminalId" },
16
25
  { method: "POST", path: "/projects/:projectId/workspaces/:workspaceId/terminal-command-runs" },
@@ -1 +1 @@
1
- {"version":3,"file":"federatedRoutes.js","sourceRoot":"","sources":["../../src/shared/federatedRoutes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"federatedRoutes.js","sourceRoot":"","sources":["../../src/shared/federatedRoutes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { isPiWebPluginId } from "./pluginIds.js";
2
+ const MACHINE_PLUGIN_ID_PREFIX = "machine.";
3
+ export function machineScopedPluginId(machineId, pluginId) {
4
+ if (machineId === "")
5
+ throw new Error("Machine id is required");
6
+ if (!isPiWebPluginId(pluginId))
7
+ throw new Error(`Invalid PI WEB plugin id: ${pluginId}`);
8
+ return `${MACHINE_PLUGIN_ID_PREFIX}${stringToHex(machineId)}.${pluginId}`;
9
+ }
10
+ export function parseMachineScopedPluginId(pluginId) {
11
+ if (!pluginId.startsWith(MACHINE_PLUGIN_ID_PREFIX))
12
+ return undefined;
13
+ const rest = pluginId.slice(MACHINE_PLUGIN_ID_PREFIX.length);
14
+ const separator = rest.indexOf(".");
15
+ if (separator < 1)
16
+ return undefined;
17
+ const encodedMachineId = rest.slice(0, separator);
18
+ const sourcePluginId = rest.slice(separator + 1);
19
+ if (!isHexString(encodedMachineId) || !isPiWebPluginId(sourcePluginId))
20
+ return undefined;
21
+ const machineId = hexToString(encodedMachineId);
22
+ if (machineId === "")
23
+ return undefined;
24
+ return { machineId, pluginId: sourcePluginId };
25
+ }
26
+ function stringToHex(value) {
27
+ return [...new TextEncoder().encode(value)]
28
+ .map((byte) => byte.toString(16).padStart(2, "0"))
29
+ .join("");
30
+ }
31
+ function hexToString(value) {
32
+ const bytes = new Uint8Array(value.length / 2);
33
+ for (let index = 0; index < value.length; index += 2) {
34
+ bytes[index / 2] = Number.parseInt(value.slice(index, index + 2), 16);
35
+ }
36
+ return new TextDecoder().decode(bytes);
37
+ }
38
+ function isHexString(value) {
39
+ return value.length > 0 && value.length % 2 === 0 && /^[0-9a-f]+$/u.test(value);
40
+ }
41
+ //# sourceMappingURL=machinePluginIds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"machinePluginIds.js","sourceRoot":"","sources":["../../src/shared/machinePluginIds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,wBAAwB,GAAG,UAAU,CAAC;AAO5C,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,QAAgB;IACvE,IAAI,SAAS,KAAK,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAChE,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,EAAE,CAAC,CAAC;IACzF,OAAO,GAAG,wBAAwB,GAAG,WAAW,CAAC,SAAS,CAAC,IAAI,QAAQ,EAAE,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IACzD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,wBAAwB,CAAC;QAAE,OAAO,SAAS,CAAC;IACrE,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAEpC,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACjD,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzF,MAAM,SAAS,GAAG,WAAW,CAAC,gBAAgB,CAAC,CAAC;IAChD,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IACvC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;AACjD,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,CAAC,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SACjD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAClF,CAAC"}
@@ -0,0 +1,12 @@
1
+ export const workspaceDeleteOperation = "workspace.delete";
2
+ export const workspaceDeleteOperationMetadataKey = "pi.operation";
3
+ export const targetWorkspaceIdMetadataKey = "target.workspaceId";
4
+ export const targetWorkspacePathMetadataKey = "target.workspacePath";
5
+ export function workspaceDeletionMetadata(workspace) {
6
+ return {
7
+ [workspaceDeleteOperationMetadataKey]: workspaceDeleteOperation,
8
+ [targetWorkspaceIdMetadataKey]: workspace.id,
9
+ [targetWorkspacePathMetadataKey]: workspace.path,
10
+ };
11
+ }
12
+ //# sourceMappingURL=workspaceDeletion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceDeletion.js","sourceRoot":"","sources":["../../src/shared/workspaceDeletion.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,kBAAkB,CAAC;AAC3D,MAAM,CAAC,MAAM,mCAAmC,GAAG,cAAc,CAAC;AAClE,MAAM,CAAC,MAAM,4BAA4B,GAAG,oBAAoB,CAAC;AACjE,MAAM,CAAC,MAAM,8BAA8B,GAAG,sBAAsB,CAAC;AAOrE,MAAM,UAAU,yBAAyB,CAAC,SAAkC;IAC1E,OAAO;QACL,CAAC,mCAAmC,CAAC,EAAE,wBAAwB;QAC/D,CAAC,4BAA4B,CAAC,EAAE,SAAS,CAAC,EAAE;QAC5C,CAAC,8BAA8B,CAAC,EAAE,SAAS,CAAC,IAAI;KACjD,CAAC;AACJ,CAAC"}
package/docs/plugins.md CHANGED
@@ -22,7 +22,7 @@ Plugins run as JavaScript in the browser app. Treat them as trusted code:
22
22
  - they can render arbitrary Lit templates/custom elements in plugin contribution areas;
23
23
  - they should not be installed from untrusted sources.
24
24
 
25
- PI WEB's `/api/...` HTTP and WebSocket endpoints are internal implementation details. Plugin code should not fetch PI WEB API endpoints directly; use the documented context helpers instead.
25
+ PI WEB's `/api/...` HTTP and WebSocket endpoints are internal implementation details. Plugin code should use the documented context helpers instead. Daring plugins can still reach private routes or runtime objects because they run in the browser, but those private surfaces are experimental: they may graduate into stable helpers, change shape, or disappear.
26
26
 
27
27
  ## What to ask AI to build
28
28
 
@@ -129,9 +129,30 @@ ln -s /path/to/plugin-folder ~/.pi-web/plugins/plugin-id
129
129
 
130
130
  Reload the PI WEB browser tab. PI WEB serves plugin modules with an mtime-based `?v=` cache buster. After editing a plugin, hard reload the browser if you do not see changes.
131
131
 
132
+ ## Remote machine plugins
133
+
134
+ When [machine federation](https://pi-web.dev/machines.html) is enabled, PI WEB also loads discovered plugins from the selected remote machine. Remote plugins are trusted browser-side code like local plugins, but their contributions are machine-scoped:
135
+
136
+ - actions, workspace panels, and workspace labels only appear while that machine is selected;
137
+ - plugin file and terminal helpers run against that machine;
138
+ - plugin code is loaded best-effort through the current gateway and cached for the browser page lifetime;
139
+ - if the gateway already has an enabled plugin with the same original id, the gateway plugin wins and the remote duplicate stays hidden;
140
+ - remote theme contributions are ignored for now because themes are app-wide;
141
+ - mixed PI WEB versions across federated machines are best-effort and not guaranteed compatible.
142
+
143
+ Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable a remote machine plugin, open that machine directly or update its config file.
144
+
145
+ For portable plugin assets, prefer URLs relative to the plugin module, for example:
146
+
147
+ ```js
148
+ const url = new URL("./asset.json", import.meta.url);
149
+ ```
150
+
151
+ If a remote plugin constructs absolute asset URLs, it should use the `pluginId` from `activate()` because PI WEB gives remote plugins a gateway-scoped runtime id. Hard-coded `/pi-web-plugins/<original-id>/...` URLs may point at the gateway instead of the remote machine.
152
+
132
153
  ## Manage plugins
133
154
 
134
- Open **Settings → Plugins** to review discovered bundled, local, dev, and Pi package plugins. PI WEB can disable any discovered plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
155
+ Open **Settings → Plugins** to review discovered bundled, local, dev, and Pi package plugins for the PI WEB gateway you opened. PI WEB can disable any discovered gateway plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
135
156
 
136
157
  Plugin preferences are stored under the top-level `plugins` config key in the PI WEB config file:
137
158
 
@@ -161,7 +182,7 @@ Built-in plugins can be managed from **Settings → Plugins** or with the top-le
161
182
 
162
183
  ### Updates
163
184
 
164
- **Plugin id:** `updates`
185
+ **Plugin id:** `updates`
165
186
  **What it does:** adds a conditional **Updates** workspace tab with PI WEB update, restart, and installed-service guidance.
166
187
 
167
188
  Updates is enabled by default. To hide it, disable `updates` in **Settings → Plugins** or set:
@@ -176,8 +197,8 @@ Updates is enabled by default. To hide it, disable `updates` in **Settings → P
176
197
 
177
198
  ### Workspace Tasks
178
199
 
179
- **Plugin id:** `workspace-tasks`
180
- **Config file:** `.pi-web/tasks.json`
200
+ **Plugin id:** `workspace-tasks`
201
+ **Config file:** `.pi-web/tasks.json`
181
202
  **What it does:** adds a **Tasks** workspace tab for running configured shell commands in dedicated PI WEB terminals.
182
203
 
183
204
  Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → Plugins** or set:
@@ -231,7 +252,7 @@ Review task configs before running them, especially in shared projects. Workspac
231
252
 
232
253
  ## Discovery and packaging
233
254
 
234
- PI WEB builds `/pi-web-plugins/manifest.json` from these sources:
255
+ PI WEB builds the gateway `/pi-web-plugins/manifest.json` from these sources:
235
256
 
236
257
  1. Bundled plugins in the PI WEB package:
237
258
 
@@ -249,6 +270,8 @@ PI WEB builds `/pi-web-plugins/manifest.json` from these sources:
249
270
 
250
271
  3. Installed Pi packages that expose PI WEB plugin metadata. Pi packages may be user or project scoped.
251
272
 
273
+ Remote machines expose their own manifests through the gateway at `/api/machines/<machine-id>/pi-web-plugins/manifest.json`. Those plugin modules are rewritten to gateway-scoped asset URLs and registered under machine-scoped runtime ids so duplicate plugin ids on different machines do not collide.
274
+
252
275
  Plugin package directory names and plugin ids must be valid identifiers:
253
276
 
254
277
  ```text
@@ -428,7 +451,7 @@ Notes:
428
451
 
429
452
  - `state` is a snapshot of current UI state when actions are built.
430
453
  - The stable state fields are `state.selectedWorkspace`, `state.selectedSession`, and `state.piWebStatus`.
431
- - Other `state` fields may exist at runtime, but they are PI WEB internals and can change quickly.
454
+ - Other `state` fields may exist at runtime, but they are private PI WEB internals that may graduate into stable helpers, change shape, or disappear.
432
455
  - `enabled` is evaluated when the action palette asks for actions.
433
456
  - `selectWorkspaceTool()` expects a qualified panel id such as `my-plugin:workspace.info`.
434
457
  - `openTerminal()` switches to the built-in terminal panel. Pass `{ terminalId }` to deep-link to a specific terminal.
@@ -511,6 +534,8 @@ interface WorkspacePanelContext {
511
534
 
512
535
  `machine`, `workspace`, `files`, `terminal`, and `host` are documented as stable for panel callbacks. Use `terminal.open()` to switch to the built-in terminal panel; pass `{ terminalId }` to deep-link to a specific terminal. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate panel callbacks such as `badge`, `visible`, or `render`.
513
536
 
537
+ For compatibility, PI WEB still provides the old `context.openTerminal()` workspace-panel helper at runtime. It is deprecated, intentionally omitted from the public TypeScript declarations, and planned for removal in v2. Existing JavaScript plugins keep working, while typed plugins should migrate to `context.terminal.open()`.
538
+
514
539
  Useful workspace and machine shapes:
515
540
 
516
541
  ```ts
@@ -573,12 +598,18 @@ interface WorkspaceLabelContext {
573
598
  machine: PluginMachine;
574
599
  workspace: Workspace;
575
600
  state?: PluginRuntimeState;
601
+ files: {
602
+ readFile(path: string): Promise<FileContentResponse>;
603
+ };
604
+ host: {
605
+ requestRender(): void;
606
+ };
576
607
  }
577
608
  ```
578
609
 
579
- `machine` and `workspace` are documented as stable for label callbacks. Include `machine.id` in any label caches that depend on workspace data.
610
+ `machine`, `workspace`, `files`, and `host` are documented as stable for label callbacks. Include `machine.id` in any label caches that depend on workspace data. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate label `visible` or `items` callbacks.
580
611
 
581
- Items are sorted by `order` and then id. Return an empty array to render nothing.
612
+ Items are sorted by `order` and then id. Return an empty array to render nothing. Keep callbacks synchronous and lightweight; start async work from the callback, return cached items, then call `host.requestRender()` when the cache changes.
582
613
 
583
614
  #### Text items
584
615
 
@@ -638,7 +669,7 @@ export default {
638
669
 
639
670
  ## Reading workspace files
640
671
 
641
- Workspace panels can read files through the documented `files` helper. PI WEB binds this helper to the panel's machine and workspace, so it works the same for local and federated machines.
672
+ Workspace panels and workspace labels can read files through the documented `files` helper. PI WEB binds this helper to the callback's machine and workspace, so it works the same for local and federated machines.
642
673
 
643
674
  ```js
644
675
  workspacePanels: [
@@ -668,6 +699,51 @@ class MyEnvViewer extends HTMLElement {
668
699
  }
669
700
  ```
670
701
 
702
+ Labels should use the same helper through a plugin-owned cache because `items()` itself must return synchronously:
703
+
704
+ ```js
705
+ const envCache = new Map();
706
+
707
+ function envKey(machine, workspace) {
708
+ return `${machine.id}:${workspace.id}:docker/development.be-go.local.env`;
709
+ }
710
+
711
+ function loadEnvLabel(context) {
712
+ const key = envKey(context.machine, context.workspace);
713
+ const cached = envCache.get(key);
714
+ if (cached !== undefined) return cached;
715
+
716
+ const pending = { status: "loading", label: undefined };
717
+ envCache.set(key, pending);
718
+ context.files.readFile("docker/development.be-go.local.env")
719
+ .then((file) => {
720
+ pending.status = "ready";
721
+ pending.label = file.content.match(/^DEV_URL=(.+)$/m)?.[1];
722
+ context.host.requestRender();
723
+ })
724
+ .catch(() => {
725
+ pending.status = "missing";
726
+ context.host.requestRender();
727
+ });
728
+ return pending;
729
+ }
730
+
731
+ workspaceLabels: [
732
+ {
733
+ id: "dev-url",
734
+ items: (context) => {
735
+ const cached = loadEnvLabel(context);
736
+ return cached.label === undefined ? [] : [{
737
+ type: "link",
738
+ text: cached.label,
739
+ href: cached.label,
740
+ target: "_blank",
741
+ }];
742
+ },
743
+ },
744
+ ]
745
+ ```
746
+
671
747
  The file response includes fields such as `path`, `content`, `truncated`, and `binary`. Be careful with sensitive files such as `.env`: plugins are trusted browser code, and file contents are exposed to the plugin.
672
748
 
673
749
  ## Running workspace terminal commands
@@ -687,9 +763,9 @@ render: ({ terminal }) => html`
687
763
 
688
764
  Review command strings carefully. They are trusted shell commands executed in the workspace terminal.
689
765
 
690
- ## Internal PI WEB APIs and explicit unstable opt-in
766
+ ## Private and experimental PI WEB APIs
691
767
 
692
- PI WEB's `/api/...` HTTP and WebSocket routes are private implementation details. Plugin code should not fetch PI WEB API endpoints directly because those URLs, response shapes, and machine-federation routing rules can change.
768
+ 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.
693
769
 
694
770
  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:
695
771
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chainingintention/pi-web-cn",
3
- "version": "1.202606.4",
3
+ "version": "1.202606.6",
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",