@hyperdreamer/pi-webui 1.15.2 → 1.16.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.
- package/dist/client/assets/{CodeViewer-CHZziPur.js → CodeViewer-CCHq9DpL.js} +1 -1
- package/dist/client/assets/{UnifiedDiffViewer-j1-AFZ8f.js → UnifiedDiffViewer-JFQMCnzP.js} +1 -1
- package/dist/client/assets/{index-2RMTbgnM.js → index-WjewjFVt.js} +469 -469
- package/dist/client/index.html +1 -1
- package/dist/config.js +10 -0
- package/dist/config.js.map +1 -1
- package/dist/configMutationCoordinator.js +10 -1
- package/dist/configMutationCoordinator.js.map +1 -1
- package/dist/pi-webui-plugins/workspace-tasks/config.js +3 -132
- package/dist/pi-webui-plugins/workspace-tasks/pi-webui-plugin.js +14 -2
- package/dist/pi-webui-plugins/workspace-tasks/taskDomain.js +203 -0
- package/dist/pi-webui-plugins/workspace-tasks/taskRunner.js +3 -2
- package/dist/pi-webui-plugins/workspace-tasks/tasksPanelElement.js +947 -673
- package/dist/server/app.js +20 -4
- package/dist/server/app.js.map +1 -1
- package/dist/server/configRoutes.js +5 -0
- package/dist/server/configRoutes.js.map +1 -1
- package/dist/server/machines/machineProxyRoutes.js +4 -4
- package/dist/server/machines/machineProxyRoutes.js.map +1 -1
- package/dist/server/workspaceExplorerRoutes.js +64 -4
- package/dist/server/workspaceExplorerRoutes.js.map +1 -1
- package/dist/server/workspaceTasks/workspaceTasksCatalogService.js +318 -0
- package/dist/server/workspaceTasks/workspaceTasksCatalogService.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksComposition.js +67 -0
- package/dist/server/workspaceTasks/workspaceTasksComposition.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksErrors.js +34 -0
- package/dist/server/workspaceTasks/workspaceTasksErrors.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksGlobalCatalogAdapter.js +169 -0
- package/dist/server/workspaceTasks/workspaceTasksGlobalCatalogAdapter.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksGlobalMutationGate.js +75 -0
- package/dist/server/workspaceTasks/workspaceTasksGlobalMutationGate.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksMoveProtocol.js +313 -0
- package/dist/server/workspaceTasks/workspaceTasksMoveProtocol.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksMoveRegistry.js +352 -0
- package/dist/server/workspaceTasks/workspaceTasksMoveRegistry.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksProxyRoutes.js +63 -0
- package/dist/server/workspaceTasks/workspaceTasksProxyRoutes.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksRoutes.js +153 -0
- package/dist/server/workspaceTasks/workspaceTasksRoutes.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspaceCatalogAdapter.js +171 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspaceCatalogAdapter.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspaceFile.js +227 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspaceFile.js.map +1 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspacePathGate.js +42 -0
- package/dist/server/workspaceTasks/workspaceTasksWorkspacePathGate.js.map +1 -0
- package/dist/server/workspaces/fileContentService.js +116 -6
- package/dist/server/workspaces/fileContentService.js.map +1 -1
- package/dist/shared/apiTypes.d.ts +132 -0
- package/dist/shared/apiTypes.js.map +1 -1
- package/dist/shared/federatedRoutes.js +15 -0
- package/dist/shared/federatedRoutes.js.map +1 -1
- package/dist/shared/workspaceFiles.js +2 -0
- package/dist/shared/workspaceFiles.js.map +1 -1
- package/dist/shared/workspaceTasks.d.ts +53 -0
- package/dist/shared/workspaceTasks.js +203 -0
- package/dist/shared/workspaceTasks.js.map +1 -0
- package/dist/shared/workspaceTasksApi.js +379 -0
- package/dist/shared/workspaceTasksApi.js.map +1 -0
- package/docs/config.md +22 -4
- package/docs/plugins.md +24 -13
- package/package.json +1 -1
- package/dist/pi-webui-plugins/workspace-tasks/workspaceTasksClient.js +0 -242
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// Generated from Workspace Tasks task domain. Do not edit directly.
|
|
2
|
+
export const TASKS_CONFIG_PATH = ".pi-webui/tasks.json";
|
|
3
|
+
export const WORKSPACE_TASKS_CONFIG_VERSION = 1;
|
|
4
|
+
export const WORKSPACE_TASKS_CATALOG_MAX_BYTES = 512 * 1024;
|
|
5
|
+
const workspaceTaskIdPattern = /^[a-z][a-z0-9.-]*$/u;
|
|
6
|
+
export function parseWorkspaceTasksConfig(value) {
|
|
7
|
+
if (!isRecord(value))
|
|
8
|
+
return invalid("Config must be an object");
|
|
9
|
+
if (value["version"] !== WORKSPACE_TASKS_CONFIG_VERSION)
|
|
10
|
+
return invalid("Config version must be 1");
|
|
11
|
+
const tasks = value["tasks"];
|
|
12
|
+
if (!Array.isArray(tasks))
|
|
13
|
+
return invalid("Config tasks must be an array");
|
|
14
|
+
const ids = new Set();
|
|
15
|
+
const parsedTasks = [];
|
|
16
|
+
for (const [index, task] of tasks.entries()) {
|
|
17
|
+
const parsedTask = parseTask(task, index);
|
|
18
|
+
if (!parsedTask.ok)
|
|
19
|
+
return parsedTask;
|
|
20
|
+
if (ids.has(parsedTask.task.id))
|
|
21
|
+
return invalid(`Duplicate task id: ${parsedTask.task.id}`);
|
|
22
|
+
ids.add(parsedTask.task.id);
|
|
23
|
+
parsedTasks.push(parsedTask.task);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
ok: true,
|
|
27
|
+
config: {
|
|
28
|
+
version: WORKSPACE_TASKS_CONFIG_VERSION,
|
|
29
|
+
tasks: parsedTasks,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function parseWorkspaceTasksConfigText(text) {
|
|
34
|
+
let parsed;
|
|
35
|
+
try {
|
|
36
|
+
parsed = JSON.parse(text);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return invalid(`Invalid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
40
|
+
}
|
|
41
|
+
return parseWorkspaceTasksConfig(parsed);
|
|
42
|
+
}
|
|
43
|
+
export function serializeWorkspaceTasksConfig(config) {
|
|
44
|
+
const canonicalConfig = {
|
|
45
|
+
version: config.version,
|
|
46
|
+
tasks: config.tasks.map((task) => ({
|
|
47
|
+
id: task.id,
|
|
48
|
+
title: task.title,
|
|
49
|
+
command: task.command,
|
|
50
|
+
...(task.description === undefined ? {} : { description: task.description }),
|
|
51
|
+
...(task.group === undefined ? {} : { group: task.group }),
|
|
52
|
+
confirm: task.confirm,
|
|
53
|
+
})),
|
|
54
|
+
};
|
|
55
|
+
return `${JSON.stringify(canonicalConfig, null, 2)}\n`;
|
|
56
|
+
}
|
|
57
|
+
export function workspaceTasksCanonicalByteLength(config) {
|
|
58
|
+
return new TextEncoder().encode(serializeWorkspaceTasksConfig(config)).byteLength;
|
|
59
|
+
}
|
|
60
|
+
export function assertWorkspaceTasksCatalogSize(config) {
|
|
61
|
+
const byteLength = workspaceTasksCanonicalByteLength(config);
|
|
62
|
+
if (byteLength > WORKSPACE_TASKS_CATALOG_MAX_BYTES) {
|
|
63
|
+
throw new RangeError(`Workspace tasks catalog is ${String(byteLength)} bytes; maximum is ${String(WORKSPACE_TASKS_CATALOG_MAX_BYTES)} bytes`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function isWorkspaceTaskId(value) {
|
|
67
|
+
return workspaceTaskIdPattern.test(value);
|
|
68
|
+
}
|
|
69
|
+
export function workspaceTaskRefKey(ref) {
|
|
70
|
+
assertWorkspaceTaskScope(ref.scope);
|
|
71
|
+
assertWorkspaceTaskId(ref.id);
|
|
72
|
+
return `${ref.scope}:${ref.id}`;
|
|
73
|
+
}
|
|
74
|
+
export function parseWorkspaceTaskRefKey(key) {
|
|
75
|
+
const parts = key.split(":");
|
|
76
|
+
if (parts.length !== 2)
|
|
77
|
+
throw new Error(`Invalid workspace task reference key: ${key}`);
|
|
78
|
+
const [scope, id] = parts;
|
|
79
|
+
assertWorkspaceTaskScope(scope);
|
|
80
|
+
assertWorkspaceTaskId(id);
|
|
81
|
+
return { scope, id };
|
|
82
|
+
}
|
|
83
|
+
export function workspaceTaskGroupKey(scope, group) {
|
|
84
|
+
assertWorkspaceTaskScope(scope);
|
|
85
|
+
if (typeof group !== "string")
|
|
86
|
+
throw new TypeError("Workspace task group must be a string");
|
|
87
|
+
return JSON.stringify([scope, group]);
|
|
88
|
+
}
|
|
89
|
+
export function appendWorkspaceTask(config, task) {
|
|
90
|
+
return { version: config.version, tasks: [...config.tasks, task] };
|
|
91
|
+
}
|
|
92
|
+
export function replaceWorkspaceTaskAt(config, index, task) {
|
|
93
|
+
assertWorkspaceTaskIndex(config, index);
|
|
94
|
+
return {
|
|
95
|
+
version: config.version,
|
|
96
|
+
tasks: [...config.tasks.slice(0, index), task, ...config.tasks.slice(index + 1)],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function removeWorkspaceTaskAt(config, index) {
|
|
100
|
+
assertWorkspaceTaskIndex(config, index);
|
|
101
|
+
return {
|
|
102
|
+
version: config.version,
|
|
103
|
+
tasks: [...config.tasks.slice(0, index), ...config.tasks.slice(index + 1)],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function deriveWorkspaceTaskMove(input) {
|
|
107
|
+
assertWorkspaceTaskScope(input.source.ref.scope);
|
|
108
|
+
assertWorkspaceTaskId(input.source.ref.id);
|
|
109
|
+
assertWorkspaceTaskScope(input.destination.scope);
|
|
110
|
+
assertWorkspaceTaskId(input.destination.task.id);
|
|
111
|
+
if (input.source.ref.scope === input.destination.scope) {
|
|
112
|
+
throw new Error("Workspace task moves must cross scopes");
|
|
113
|
+
}
|
|
114
|
+
const sourceIndex = input.source.config.tasks.findIndex((task) => task.id === input.source.ref.id);
|
|
115
|
+
if (sourceIndex === -1) {
|
|
116
|
+
throw new Error(`Source workspace task not found: ${input.source.ref.id}`);
|
|
117
|
+
}
|
|
118
|
+
if (input.destination.config.tasks.some((task) => task.id === input.destination.task.id)) {
|
|
119
|
+
throw new Error(`Destination workspace task already exists: ${input.destination.task.id}`);
|
|
120
|
+
}
|
|
121
|
+
const sourceAfter = removeWorkspaceTaskAt(input.source.config, sourceIndex);
|
|
122
|
+
const destinationAfter = appendWorkspaceTask(input.destination.config, input.destination.task);
|
|
123
|
+
assertWorkspaceTasksCatalogSize(sourceAfter);
|
|
124
|
+
assertWorkspaceTasksCatalogSize(destinationAfter);
|
|
125
|
+
return { sourceAfter, destinationAfter };
|
|
126
|
+
}
|
|
127
|
+
function parseTask(value, index) {
|
|
128
|
+
const label = `Task ${String(index + 1)}`;
|
|
129
|
+
if (!isRecord(value))
|
|
130
|
+
return invalid(`${label} must be an object`);
|
|
131
|
+
const id = requireNonEmptyString(value, "id", label);
|
|
132
|
+
if (!id.ok)
|
|
133
|
+
return id;
|
|
134
|
+
if (!isWorkspaceTaskId(id.value))
|
|
135
|
+
return invalid(`${label} id must match ${workspaceTaskIdPattern.source}`);
|
|
136
|
+
const title = requireNonEmptyString(value, "title", label);
|
|
137
|
+
if (!title.ok)
|
|
138
|
+
return title;
|
|
139
|
+
const command = requireNonEmptyString(value, "command", label);
|
|
140
|
+
if (!command.ok)
|
|
141
|
+
return command;
|
|
142
|
+
const description = optionalNonEmptyString(value, "description", label);
|
|
143
|
+
if (!description.ok)
|
|
144
|
+
return description;
|
|
145
|
+
const group = optionalNonEmptyString(value, "group", label);
|
|
146
|
+
if (!group.ok)
|
|
147
|
+
return group;
|
|
148
|
+
const confirm = value["confirm"];
|
|
149
|
+
if (confirm !== undefined && typeof confirm !== "boolean") {
|
|
150
|
+
return invalid(`${label} confirm must be a boolean`);
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
task: {
|
|
155
|
+
id: id.value,
|
|
156
|
+
title: title.value,
|
|
157
|
+
command: command.value,
|
|
158
|
+
...(description.value === undefined ? {} : { description: description.value }),
|
|
159
|
+
...(group.value === undefined ? {} : { group: group.value }),
|
|
160
|
+
confirm: confirm ?? false,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function requireNonEmptyString(record, key, label) {
|
|
165
|
+
const value = record[key];
|
|
166
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
167
|
+
return invalid(`${label} ${key} must be a non-empty string`);
|
|
168
|
+
}
|
|
169
|
+
return { ok: true, value };
|
|
170
|
+
}
|
|
171
|
+
function optionalNonEmptyString(record, key, label) {
|
|
172
|
+
const value = record[key];
|
|
173
|
+
if (value === undefined)
|
|
174
|
+
return { ok: true, value: undefined };
|
|
175
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
176
|
+
return invalid(`${label} ${key} must be a non-empty string when provided`);
|
|
177
|
+
}
|
|
178
|
+
return { ok: true, value };
|
|
179
|
+
}
|
|
180
|
+
function assertWorkspaceTaskIndex(config, index) {
|
|
181
|
+
if (!Number.isInteger(index) || index < 0 || index >= config.tasks.length) {
|
|
182
|
+
throw new RangeError(`Task index ${String(index)} is out of range`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function assertWorkspaceTaskScope(scope) {
|
|
186
|
+
if (!isWorkspaceTaskScope(scope)) {
|
|
187
|
+
throw new Error(`Invalid workspace task scope: ${String(scope)}`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function assertWorkspaceTaskId(id) {
|
|
191
|
+
if (typeof id !== "string" || !isWorkspaceTaskId(id)) {
|
|
192
|
+
throw new Error(`Invalid workspace task id: ${String(id)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function isWorkspaceTaskScope(value) {
|
|
196
|
+
return value === "global" || value === "workspace";
|
|
197
|
+
}
|
|
198
|
+
function invalid(error) {
|
|
199
|
+
return { ok: false, error };
|
|
200
|
+
}
|
|
201
|
+
function isRecord(value) {
|
|
202
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
203
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
// Generated from pi-webui-plugins/workspace-tasks/taskRunner.ts. Do not edit directly.
|
|
2
|
-
export function runWorkspaceTaskInTerminal(terminal, task) {
|
|
2
|
+
export function runWorkspaceTaskInTerminal(terminal, ref, task) {
|
|
3
3
|
return terminal.runCommand({
|
|
4
4
|
title: task.title,
|
|
5
5
|
command: task.command,
|
|
6
6
|
open: true,
|
|
7
7
|
metadata: {
|
|
8
8
|
"pi.plugin": "workspace-tasks",
|
|
9
|
-
"task.
|
|
9
|
+
"task.scope": ref.scope,
|
|
10
|
+
"task.id": ref.id,
|
|
10
11
|
},
|
|
11
12
|
});
|
|
12
13
|
}
|