@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.
- package/README.md +1 -1
- package/dist/client/assets/{CodeViewer-BNKhIElN.js → CodeViewer-8znVN61S.js} +1 -1
- package/dist/client/assets/{TerminalPanel-VPiiPQfC.js → TerminalPanel-DrdWnF1y.js} +1 -1
- package/dist/client/assets/index-BiGrW6IC.js +2169 -0
- package/dist/client/index.html +1 -1
- package/dist/config.js +72 -0
- package/dist/config.js.map +1 -1
- package/dist/plugin-api.d.ts +17 -11
- package/dist/server/app.js +55 -17
- package/dist/server/app.js.map +1 -1
- package/dist/server/configRoutes.js +77 -0
- package/dist/server/configRoutes.js.map +1 -1
- package/dist/server/gitRoutes.js +16 -3
- package/dist/server/gitRoutes.js.map +1 -1
- package/dist/server/machines/machinePluginProxyRoutes.js +179 -0
- package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
- package/dist/server/machines/machineProxyRoutes.js +1 -0
- package/dist/server/machines/machineProxyRoutes.js.map +1 -1
- package/dist/server/managementEmbed.js +205 -0
- package/dist/server/managementEmbed.js.map +1 -0
- package/dist/server/sessiond/sessionProxyRoutes.js +66 -8
- package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
- package/dist/server/sessions/managementPermissionSystem.js +94 -0
- package/dist/server/sessions/managementPermissionSystem.js.map +1 -0
- package/dist/server/sessions/managementSandbox.js +156 -0
- package/dist/server/sessions/managementSandbox.js.map +1 -0
- package/dist/server/sessions/piSessionService.js +339 -31
- package/dist/server/sessions/piSessionService.js.map +1 -1
- package/dist/server/sessions/sessionNameGenerator.js +2 -0
- package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
- package/dist/server/sessions/sessionRoutes.js +9 -4
- package/dist/server/sessions/sessionRoutes.js.map +1 -1
- package/dist/server/terminalProxyRoutes.js +64 -8
- package/dist/server/terminalProxyRoutes.js.map +1 -1
- package/dist/server/terminals/terminalRoutes.js +23 -3
- package/dist/server/terminals/terminalRoutes.js.map +1 -1
- package/dist/server/terminals/terminalService.js +54 -4
- package/dist/server/terminals/terminalService.js.map +1 -1
- package/dist/server/workspaceExplorerRoutes.js +103 -4
- package/dist/server/workspaceExplorerRoutes.js.map +1 -1
- package/dist/server/workspaces/fileOperationService.js +95 -0
- package/dist/server/workspaces/fileOperationService.js.map +1 -0
- package/dist/server/workspaces/fileUploadService.js +23 -0
- package/dist/server/workspaces/fileUploadService.js.map +1 -0
- package/dist/server/workspaces/pathSafety.js +9 -2
- package/dist/server/workspaces/pathSafety.js.map +1 -1
- package/dist/server/workspaces/workspaceDeletionRoutes.js +127 -0
- package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
- package/dist/sessiond/sessionDaemonClient.js +12 -12
- package/dist/sessiond/sessionDaemonClient.js.map +1 -1
- package/dist/shared/apiTypes.d.ts +30 -0
- package/dist/shared/federatedRoutes.js +9 -0
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/dist/shared/machinePluginIds.js +41 -0
- package/dist/shared/machinePluginIds.js.map +1 -0
- package/dist/shared/workspaceDeletion.js +12 -0
- package/dist/shared/workspaceDeletion.js.map +1 -0
- package/docs/plugins.md +88 -12
- package/package.json +1 -1
- 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
|
-
:
|
|
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":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,OAAO,mBAAmB;IAAhC;QACmB,YAAO,GAAG,eAAe,EAAE,CAAC;QAC5B,eAAU,GAAG,kBAAkB,EAAE,CAAC;IA6DrD,CAAC;IA3DC,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,IAAY,EAAE,IAAc;
|
|
1
|
+
{"version":3,"file":"sessionDaemonClient.js","sourceRoot":"","sources":["../../src/sessiond/sessionDaemonClient.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAElE,MAAM,OAAO,mBAAmB;IAAhC;QACmB,YAAO,GAAG,eAAe,EAAE,CAAC;QAC5B,eAAU,GAAG,kBAAkB,EAAE,CAAC;IA6DrD,CAAC;IA3DC,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,IAAY,EAAE,IAAc,EAAE,UAAkC,EAAE;QAC9F,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtE,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9G,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAED,gBAAgB,CAAC,IAAY,EAAE,UAAkC,EAAE;QACjE,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,KAAK,EAAE,EAAE,CAAC;YACtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;YAC1D,OAAO,IAAI,SAAS,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,SAAS,CAAC,WAAW,IAAI,CAAC,UAAU,IAAI,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,MAAc,EAAE,IAAY,EAAE,OAAgB,EAAE,UAAkC,EAAE;QAC3G,MAAM,IAAI,GAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC9C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;YAClE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACtB,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QAChE,OAAO;YACL,UAAU,EAAE,QAAQ,CAAC,MAAM;YAC3B,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACvD,IAAI,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE;SAC5B,CAAC;IACJ,CAAC;IAEO,aAAa,CAAC,MAAc,EAAE,IAAY,EAAE,OAAgB,EAAE,UAAkC,EAAE;QACxG,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAC1B;gBACE,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,IAAI;gBACJ,MAAM;gBACN,OAAO,EAAE,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;oBAC9C,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE;oBAClG,CAAC,CAAC,OAAO;aACZ,EACD,CAAC,QAAQ,EAAE,EAAE;gBACX,MAAM,MAAM,GAAiB,EAAE,CAAC;gBAChC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAsB,EAAE,EAAE;oBAC7C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;gBACnE,CAAC,CAAC,CAAC;gBACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACtB,OAAO,CAAC;wBACN,UAAU,EAAE,QAAQ,CAAC,UAAU,IAAI,GAAG;wBACtC,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;wBACjJ,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;qBAC7C,CAAC,CAAC;gBACL,CAAC,CAAC,CAAC;YACL,CAAC,CACF,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5B,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,EAAE;gBAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpE,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -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
|
|
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
|
|
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 `
|
|
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
|
|
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
|
-
##
|
|
766
|
+
## Private and experimental PI WEB APIs
|
|
691
767
|
|
|
692
|
-
PI WEB's `/api/...` HTTP and WebSocket routes are private implementation details.
|
|
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