@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.
Files changed (62) hide show
  1. package/dist/client/assets/{CodeViewer-CHZziPur.js → CodeViewer-CCHq9DpL.js} +1 -1
  2. package/dist/client/assets/{UnifiedDiffViewer-j1-AFZ8f.js → UnifiedDiffViewer-JFQMCnzP.js} +1 -1
  3. package/dist/client/assets/{index-2RMTbgnM.js → index-WjewjFVt.js} +469 -469
  4. package/dist/client/index.html +1 -1
  5. package/dist/config.js +10 -0
  6. package/dist/config.js.map +1 -1
  7. package/dist/configMutationCoordinator.js +10 -1
  8. package/dist/configMutationCoordinator.js.map +1 -1
  9. package/dist/pi-webui-plugins/workspace-tasks/config.js +3 -132
  10. package/dist/pi-webui-plugins/workspace-tasks/pi-webui-plugin.js +14 -2
  11. package/dist/pi-webui-plugins/workspace-tasks/taskDomain.js +203 -0
  12. package/dist/pi-webui-plugins/workspace-tasks/taskRunner.js +3 -2
  13. package/dist/pi-webui-plugins/workspace-tasks/tasksPanelElement.js +947 -673
  14. package/dist/server/app.js +20 -4
  15. package/dist/server/app.js.map +1 -1
  16. package/dist/server/configRoutes.js +5 -0
  17. package/dist/server/configRoutes.js.map +1 -1
  18. package/dist/server/machines/machineProxyRoutes.js +4 -4
  19. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  20. package/dist/server/workspaceExplorerRoutes.js +64 -4
  21. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  22. package/dist/server/workspaceTasks/workspaceTasksCatalogService.js +318 -0
  23. package/dist/server/workspaceTasks/workspaceTasksCatalogService.js.map +1 -0
  24. package/dist/server/workspaceTasks/workspaceTasksComposition.js +67 -0
  25. package/dist/server/workspaceTasks/workspaceTasksComposition.js.map +1 -0
  26. package/dist/server/workspaceTasks/workspaceTasksErrors.js +34 -0
  27. package/dist/server/workspaceTasks/workspaceTasksErrors.js.map +1 -0
  28. package/dist/server/workspaceTasks/workspaceTasksGlobalCatalogAdapter.js +169 -0
  29. package/dist/server/workspaceTasks/workspaceTasksGlobalCatalogAdapter.js.map +1 -0
  30. package/dist/server/workspaceTasks/workspaceTasksGlobalMutationGate.js +75 -0
  31. package/dist/server/workspaceTasks/workspaceTasksGlobalMutationGate.js.map +1 -0
  32. package/dist/server/workspaceTasks/workspaceTasksMoveProtocol.js +313 -0
  33. package/dist/server/workspaceTasks/workspaceTasksMoveProtocol.js.map +1 -0
  34. package/dist/server/workspaceTasks/workspaceTasksMoveRegistry.js +352 -0
  35. package/dist/server/workspaceTasks/workspaceTasksMoveRegistry.js.map +1 -0
  36. package/dist/server/workspaceTasks/workspaceTasksProxyRoutes.js +63 -0
  37. package/dist/server/workspaceTasks/workspaceTasksProxyRoutes.js.map +1 -0
  38. package/dist/server/workspaceTasks/workspaceTasksRoutes.js +153 -0
  39. package/dist/server/workspaceTasks/workspaceTasksRoutes.js.map +1 -0
  40. package/dist/server/workspaceTasks/workspaceTasksWorkspaceCatalogAdapter.js +171 -0
  41. package/dist/server/workspaceTasks/workspaceTasksWorkspaceCatalogAdapter.js.map +1 -0
  42. package/dist/server/workspaceTasks/workspaceTasksWorkspaceFile.js +227 -0
  43. package/dist/server/workspaceTasks/workspaceTasksWorkspaceFile.js.map +1 -0
  44. package/dist/server/workspaceTasks/workspaceTasksWorkspacePathGate.js +42 -0
  45. package/dist/server/workspaceTasks/workspaceTasksWorkspacePathGate.js.map +1 -0
  46. package/dist/server/workspaces/fileContentService.js +116 -6
  47. package/dist/server/workspaces/fileContentService.js.map +1 -1
  48. package/dist/shared/apiTypes.d.ts +132 -0
  49. package/dist/shared/apiTypes.js.map +1 -1
  50. package/dist/shared/federatedRoutes.js +15 -0
  51. package/dist/shared/federatedRoutes.js.map +1 -1
  52. package/dist/shared/workspaceFiles.js +2 -0
  53. package/dist/shared/workspaceFiles.js.map +1 -1
  54. package/dist/shared/workspaceTasks.d.ts +53 -0
  55. package/dist/shared/workspaceTasks.js +203 -0
  56. package/dist/shared/workspaceTasks.js.map +1 -0
  57. package/dist/shared/workspaceTasksApi.js +379 -0
  58. package/dist/shared/workspaceTasksApi.js.map +1 -0
  59. package/docs/config.md +22 -4
  60. package/docs/plugins.md +24 -13
  61. package/package.json +1 -1
  62. package/dist/pi-webui-plugins/workspace-tasks/workspaceTasksClient.js +0 -242
@@ -0,0 +1,379 @@
1
+ import { assertWorkspaceTasksCatalogSize, isWorkspaceTaskId, parseWorkspaceTasksConfig, } from "./workspaceTasks.js";
2
+ import { isCanonicalLowercaseUuid } from "./speechInput.js";
3
+ export const WORKSPACE_TASKS_REPLACE_BODY_LIMIT_BYTES = 576 * 1024;
4
+ export const WORKSPACE_TASKS_MOVE_BODY_LIMIT_BYTES = 1_835_008;
5
+ const WORKSPACE_TASKS_MOVE_CONFLICT_REASONS = [
6
+ "source-changed",
7
+ "destination-collision",
8
+ "invalid-catalog",
9
+ "unrecognized-state",
10
+ "unowned-intermediate-state",
11
+ "move-in-progress",
12
+ "retry-pristine",
13
+ ];
14
+ const WORKSPACE_TASKS_MOVE_CONFLICT_REASON_SET = new Set(WORKSPACE_TASKS_MOVE_CONFLICT_REASONS);
15
+ const WORKSPACE_TASKS_CONFLICT_REASONS = [
16
+ "revision-conflict",
17
+ "invalid-catalog",
18
+ "move-in-progress",
19
+ "move-recovery-pending",
20
+ "unowned-intermediate-state",
21
+ ];
22
+ const WORKSPACE_TASKS_CONFLICT_REASON_SET = new Set(WORKSPACE_TASKS_CONFLICT_REASONS);
23
+ export function parseReplaceWorkspaceTasksRequest(value) {
24
+ assertJsonByteLimit(value, WORKSPACE_TASKS_REPLACE_BODY_LIMIT_BYTES, "workspace task replace request");
25
+ const record = requirePlainRecord(value, ["expectedRevision", "config"], "workspace task replace request");
26
+ return {
27
+ expectedRevision: parseRevision(record, "expectedRevision", "workspace task replace request"),
28
+ config: parseCatalog(record["config"], "workspace task replace request catalog"),
29
+ };
30
+ }
31
+ export function parseReplaceGlobalWorkspaceTasksRequest(value) {
32
+ assertJsonByteLimit(value, WORKSPACE_TASKS_REPLACE_BODY_LIMIT_BYTES, "global workspace task replace request");
33
+ const record = requirePlainRecord(value, ["expectedRevision", "config"], "global workspace task replace request");
34
+ return {
35
+ expectedRevision: parseRevision(record, "expectedRevision", "global workspace task replace request"),
36
+ config: parseCatalog(record["config"], "global workspace task replace request catalog"),
37
+ };
38
+ }
39
+ export function parseMoveWorkspaceTaskRequest(value) {
40
+ assertJsonByteLimit(value, WORKSPACE_TASKS_MOVE_BODY_LIMIT_BYTES, "workspace task move request");
41
+ const record = requirePlainRecord(value, ["operationId", "intent", "source", "destination"], "workspace task move request");
42
+ const source = parseMoveSource(record["source"]);
43
+ const destination = parseMoveDestination(record["destination"]);
44
+ if (source.ref.scope === destination.scope)
45
+ throw invalid("workspace task move request");
46
+ const sourceMatches = source.expectedCatalog.config.tasks.filter((task) => task.id === source.ref.id);
47
+ if (sourceMatches.length !== 1)
48
+ throw invalid("workspace task move request");
49
+ return {
50
+ operationId: parseOperationId(record, "operationId", "workspace task move request"),
51
+ intent: parseMoveIntent(record["intent"]),
52
+ source,
53
+ destination,
54
+ };
55
+ }
56
+ export function parseWorkspaceTasksCatalogResponse(value) {
57
+ const record = requirePlainRecord(value, ["kind", "config", "revision", "message", "hint", "detail"], "workspace tasks catalog response");
58
+ switch (record["kind"]) {
59
+ case "loaded": {
60
+ const loaded = requirePlainRecord(value, ["kind", "config", "revision"], "workspace tasks loaded response");
61
+ return {
62
+ kind: "loaded",
63
+ config: parseCatalog(loaded["config"], "workspace tasks loaded catalog"),
64
+ revision: parseRevision(loaded, "revision", "workspace tasks loaded response"),
65
+ };
66
+ }
67
+ case "missing": {
68
+ const missing = requirePlainRecord(value, ["kind", "message", "hint", "revision"], "workspace tasks missing response");
69
+ return {
70
+ kind: "missing",
71
+ message: parseMessage(missing, "message", "workspace tasks missing response"),
72
+ hint: parseMessage(missing, "hint", "workspace tasks missing response"),
73
+ revision: parseRevision(missing, "revision", "workspace tasks missing response"),
74
+ };
75
+ }
76
+ case "invalid": {
77
+ const invalidResponse = requirePlainRecord(value, ["kind", "message", "hint", "detail"], "workspace tasks invalid response");
78
+ return {
79
+ kind: "invalid",
80
+ message: parseMessage(invalidResponse, "message", "workspace tasks invalid response"),
81
+ hint: parseMessage(invalidResponse, "hint", "workspace tasks invalid response"),
82
+ detail: parseMessage(invalidResponse, "detail", "workspace tasks invalid response"),
83
+ };
84
+ }
85
+ case "unavailable": {
86
+ const unavailable = requirePlainRecord(value, ["kind", "message", "hint", "detail"], "workspace tasks unavailable response");
87
+ const detail = parseOptionalDetail(unavailable, "workspace tasks unavailable response");
88
+ return {
89
+ kind: "unavailable",
90
+ message: parseMessage(unavailable, "message", "workspace tasks unavailable response"),
91
+ hint: parseMessage(unavailable, "hint", "workspace tasks unavailable response"),
92
+ ...(detail === undefined ? {} : { detail }),
93
+ };
94
+ }
95
+ default:
96
+ throw invalid("workspace tasks catalog response");
97
+ }
98
+ }
99
+ export function parseGlobalWorkspaceTasksResponse(value) {
100
+ const record = requirePlainRecord(value, ["kind", "config", "revision", "message", "hint", "detail"], "global workspace tasks response");
101
+ switch (record["kind"]) {
102
+ case "loaded": {
103
+ const loaded = requirePlainRecord(value, ["kind", "config", "revision"], "global workspace tasks loaded response");
104
+ return {
105
+ kind: "loaded",
106
+ config: parseCatalog(loaded["config"], "global workspace tasks loaded catalog"),
107
+ revision: parseRevision(loaded, "revision", "global workspace tasks loaded response"),
108
+ };
109
+ }
110
+ case "invalid": {
111
+ const invalidResponse = requirePlainRecord(value, ["kind", "message", "hint", "detail"], "global workspace tasks invalid response");
112
+ return {
113
+ kind: "invalid",
114
+ message: parseMessage(invalidResponse, "message", "global workspace tasks invalid response"),
115
+ hint: parseMessage(invalidResponse, "hint", "global workspace tasks invalid response"),
116
+ detail: parseMessage(invalidResponse, "detail", "global workspace tasks invalid response"),
117
+ };
118
+ }
119
+ default:
120
+ throw invalid("global workspace tasks response");
121
+ }
122
+ }
123
+ export function parseMoveWorkspaceTaskResult(value) {
124
+ const record = requirePlainRecord(value, ["kind", "operationId", "phase", "workspace", "global", "reason", "message"], "workspace task move result");
125
+ switch (record["kind"]) {
126
+ case "completed": {
127
+ const completed = requirePlainRecord(value, ["kind", "operationId", "workspace", "global"], "workspace task completed result");
128
+ return {
129
+ kind: "completed",
130
+ operationId: parseOperationId(completed, "operationId", "workspace task completed result"),
131
+ workspace: parseWorkspaceTasksCatalogResponse(completed["workspace"]),
132
+ global: parseGlobalWorkspaceTasksResponse(completed["global"]),
133
+ };
134
+ }
135
+ case "partial": {
136
+ const partial = requirePlainRecord(value, ["kind", "operationId", "phase", "workspace", "global"], "workspace task partial result");
137
+ if (partial["phase"] !== "destination-written")
138
+ throw invalid("workspace task partial result");
139
+ return {
140
+ kind: "partial",
141
+ operationId: parseOperationId(partial, "operationId", "workspace task partial result"),
142
+ phase: "destination-written",
143
+ workspace: parseWorkspaceTasksCatalogResponse(partial["workspace"]),
144
+ global: parseGlobalWorkspaceTasksResponse(partial["global"]),
145
+ };
146
+ }
147
+ case "conflict": {
148
+ const conflict = requirePlainRecord(value, ["kind", "reason", "message"], "workspace task move conflict result");
149
+ return {
150
+ kind: "conflict",
151
+ reason: parseMoveConflictReason(conflict["reason"]),
152
+ message: parseMessage(conflict, "message", "workspace task move conflict result"),
153
+ };
154
+ }
155
+ case "validation": {
156
+ const validation = requirePlainRecord(value, ["kind", "message"], "workspace task move validation result");
157
+ return { kind: "validation", message: parseMessage(validation, "message", "workspace task move validation result") };
158
+ }
159
+ case "unavailable": {
160
+ const unavailable = requirePlainRecord(value, ["kind", "message"], "workspace task move unavailable result");
161
+ return { kind: "unavailable", message: parseMessage(unavailable, "message", "workspace task move unavailable result") };
162
+ }
163
+ case "unknown-outcome": {
164
+ const unknownOutcome = requirePlainRecord(value, ["kind", "message"], "workspace task move unknown-outcome result");
165
+ return { kind: "unknown-outcome", message: parseMessage(unknownOutcome, "message", "workspace task move unknown-outcome result") };
166
+ }
167
+ default:
168
+ throw invalid("workspace task move result");
169
+ }
170
+ }
171
+ export function parseWorkspaceTasksFailureResponse(value) {
172
+ const record = requirePlainRecord(value, ["kind", "reason", "message", "retryable"], "workspace tasks failure response");
173
+ switch (record["kind"]) {
174
+ case "validation": {
175
+ const validation = requirePlainRecord(value, ["kind", "message"], "workspace tasks validation failure");
176
+ return { kind: "validation", message: parseMessage(validation, "message", "workspace tasks validation failure") };
177
+ }
178
+ case "conflict": {
179
+ const conflict = requirePlainRecord(value, ["kind", "reason", "message"], "workspace tasks conflict failure");
180
+ return {
181
+ kind: "conflict",
182
+ reason: parseConflictReason(conflict["reason"]),
183
+ message: parseMessage(conflict, "message", "workspace tasks conflict failure"),
184
+ };
185
+ }
186
+ case "unavailable": {
187
+ const unavailable = requirePlainRecord(value, ["kind", "message", "retryable"], "workspace tasks unavailable failure");
188
+ return {
189
+ kind: "unavailable",
190
+ message: parseMessage(unavailable, "message", "workspace tasks unavailable failure"),
191
+ retryable: requireBoolean(unavailable, "retryable", "workspace tasks unavailable failure"),
192
+ };
193
+ }
194
+ case "unknown-outcome": {
195
+ const unknownOutcome = requirePlainRecord(value, ["kind", "message"], "workspace tasks unknown-outcome failure");
196
+ return { kind: "unknown-outcome", message: parseMessage(unknownOutcome, "message", "workspace tasks unknown-outcome failure") };
197
+ }
198
+ default:
199
+ throw invalid("workspace tasks failure response");
200
+ }
201
+ }
202
+ function parseMoveSource(value) {
203
+ const record = requirePlainRecord(value, ["ref", "expectedCatalog"], "workspace task move source");
204
+ const ref = parseTaskRef(record["ref"], "workspace task move source reference");
205
+ if (ref.scope === "workspace") {
206
+ const expectedCatalog = parseWorkspaceCatalogExpectation(record["expectedCatalog"], "workspace task move source expectation", true);
207
+ if (expectedCatalog.kind !== "loaded")
208
+ throw invalid("workspace task move source expectation");
209
+ return { ref, expectedCatalog };
210
+ }
211
+ return {
212
+ ref,
213
+ expectedCatalog: parseGlobalCatalogExpectation(record["expectedCatalog"], "global workspace task move source expectation"),
214
+ };
215
+ }
216
+ function parseMoveDestination(value) {
217
+ const record = requirePlainRecord(value, ["scope", "expectedCatalog", "task"], "workspace task move destination");
218
+ const scope = parseScope(record["scope"], "workspace task move destination");
219
+ const task = parseTask(record["task"], "workspace task move destination task");
220
+ if (scope === "workspace") {
221
+ return {
222
+ scope,
223
+ expectedCatalog: parseWorkspaceCatalogExpectation(record["expectedCatalog"], "workspace task move destination expectation", false),
224
+ task,
225
+ };
226
+ }
227
+ return {
228
+ scope,
229
+ expectedCatalog: parseGlobalCatalogExpectation(record["expectedCatalog"], "global workspace task move destination expectation"),
230
+ task,
231
+ };
232
+ }
233
+ function parseWorkspaceCatalogExpectation(value, label, requireLoaded) {
234
+ const record = requirePlainRecord(value, ["kind", "revision", "config"], label);
235
+ switch (record["kind"]) {
236
+ case "loaded": {
237
+ const loaded = requirePlainRecord(value, ["kind", "revision", "config"], label);
238
+ return {
239
+ kind: "loaded",
240
+ revision: parseRevision(loaded, "revision", label),
241
+ config: parseCatalog(loaded["config"], `${label} catalog`),
242
+ };
243
+ }
244
+ case "missing": {
245
+ if (requireLoaded)
246
+ throw invalid(label);
247
+ const missing = requirePlainRecord(value, ["kind", "revision"], label);
248
+ return { kind: "missing", revision: parseRevision(missing, "revision", label) };
249
+ }
250
+ default:
251
+ throw invalid(label);
252
+ }
253
+ }
254
+ function parseGlobalCatalogExpectation(value, label) {
255
+ const record = requirePlainRecord(value, ["kind", "revision", "config"], label);
256
+ if (record["kind"] !== "loaded")
257
+ throw invalid(label);
258
+ const loaded = requirePlainRecord(value, ["kind", "revision", "config"], label);
259
+ return {
260
+ kind: "loaded",
261
+ revision: parseRevision(loaded, "revision", label),
262
+ config: parseCatalog(loaded["config"], `${label} catalog`),
263
+ };
264
+ }
265
+ function parseTaskRef(value, label) {
266
+ const record = requirePlainRecord(value, ["scope", "id"], label);
267
+ const scope = parseScope(record["scope"], label);
268
+ const id = requireNonBlankString(record, "id", label);
269
+ if (!isWorkspaceTaskId(id))
270
+ throw invalid(label);
271
+ if (scope === "workspace")
272
+ return { scope: "workspace", id };
273
+ return { scope: "global", id };
274
+ }
275
+ function parseTask(value, label) {
276
+ const config = parseCatalog({ version: 1, tasks: [value] }, `${label} catalog`);
277
+ const task = config.tasks[0];
278
+ if (task === undefined)
279
+ throw invalid(label);
280
+ return task;
281
+ }
282
+ function parseCatalog(value, label) {
283
+ const result = parseWorkspaceTasksConfig(value);
284
+ if (!result.ok)
285
+ throw invalid(label);
286
+ try {
287
+ assertWorkspaceTasksCatalogSize(result.config);
288
+ }
289
+ catch {
290
+ throw invalid(label);
291
+ }
292
+ return result.config;
293
+ }
294
+ function parseOperationId(record, key, label) {
295
+ const operationId = requireNonBlankString(record, key, label);
296
+ if (!isCanonicalLowercaseUuid(operationId))
297
+ throw invalid(label);
298
+ return operationId;
299
+ }
300
+ function parseRevision(record, key, label) {
301
+ return requireNonBlankString(record, key, label);
302
+ }
303
+ function parseMoveIntent(value) {
304
+ if (value !== "start" && value !== "retry")
305
+ throw invalid("workspace task move request");
306
+ return value;
307
+ }
308
+ function parseScope(value, label) {
309
+ if (value !== "global" && value !== "workspace")
310
+ throw invalid(label);
311
+ return value;
312
+ }
313
+ function parseMoveConflictReason(value) {
314
+ if (!isMoveConflictReason(value))
315
+ throw invalid("workspace task move conflict result");
316
+ return value;
317
+ }
318
+ function parseConflictReason(value) {
319
+ if (!isConflictReason(value))
320
+ throw invalid("workspace tasks conflict failure");
321
+ return value;
322
+ }
323
+ function isMoveConflictReason(value) {
324
+ return typeof value === "string" && WORKSPACE_TASKS_MOVE_CONFLICT_REASON_SET.has(value);
325
+ }
326
+ function isConflictReason(value) {
327
+ return typeof value === "string" && WORKSPACE_TASKS_CONFLICT_REASON_SET.has(value);
328
+ }
329
+ function parseMessage(record, key, label) {
330
+ return requireNonBlankString(record, key, label);
331
+ }
332
+ function parseOptionalDetail(record, label) {
333
+ if (!Object.hasOwn(record, "detail"))
334
+ return undefined;
335
+ return requireNonBlankString(record, "detail", label);
336
+ }
337
+ function requireBoolean(record, key, label) {
338
+ const value = record[key];
339
+ if (typeof value !== "boolean")
340
+ throw invalid(label);
341
+ return value;
342
+ }
343
+ function requireNonBlankString(record, key, label) {
344
+ const value = record[key];
345
+ if (typeof value !== "string" || value.trim() === "")
346
+ throw invalid(label);
347
+ return value;
348
+ }
349
+ function requirePlainRecord(value, allowedFields, label) {
350
+ if (!isPlainRecord(value))
351
+ throw invalid(label);
352
+ if (Reflect.ownKeys(value).some((key) => typeof key !== "string" || !allowedFields.includes(key)))
353
+ throw invalid(label);
354
+ return value;
355
+ }
356
+ function assertJsonByteLimit(value, limit, label) {
357
+ let serialized;
358
+ try {
359
+ const candidate = JSON.stringify(value);
360
+ if (typeof candidate !== "string")
361
+ throw new Error();
362
+ serialized = candidate;
363
+ }
364
+ catch {
365
+ throw invalid(label);
366
+ }
367
+ if (new TextEncoder().encode(serialized).byteLength > limit)
368
+ throw invalid(label);
369
+ }
370
+ function invalid(label) {
371
+ return new Error(`Invalid ${label}`);
372
+ }
373
+ function isPlainRecord(value) {
374
+ if (value === null || typeof value !== "object" || Array.isArray(value))
375
+ return false;
376
+ const prototype = Reflect.getPrototypeOf(value);
377
+ return prototype === Object.prototype || prototype === null;
378
+ }
379
+ //# sourceMappingURL=workspaceTasksApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaceTasksApi.js","sourceRoot":"","sources":["../../src/shared/workspaceTasksApi.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,+BAA+B,EAC/B,iBAAiB,EACjB,yBAAyB,GAI1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAE5D,MAAM,CAAC,MAAM,wCAAwC,GAAG,GAAG,GAAG,IAAI,CAAC;AACnE,MAAM,CAAC,MAAM,qCAAqC,GAAG,SAAS,CAAC;AAE/D,MAAM,qCAAqC,GAAG;IAC5C,gBAAgB;IAChB,uBAAuB;IACvB,iBAAiB;IACjB,oBAAoB;IACpB,4BAA4B;IAC5B,kBAAkB;IAClB,gBAAgB;CACR,CAAC;AAIX,MAAM,wCAAwC,GAAG,IAAI,GAAG,CAAS,qCAAqC,CAAC,CAAC;AAExG,MAAM,gCAAgC,GAAG;IACvC,mBAAmB;IACnB,iBAAiB;IACjB,kBAAkB;IAClB,uBAAuB;IACvB,4BAA4B;CAC8B,CAAC;AAE7D,MAAM,mCAAmC,GAAG,IAAI,GAAG,CAAS,gCAAgC,CAAC,CAAC;AAE9F,MAAM,UAAU,iCAAiC,CAAC,KAAc;IAC9D,mBAAmB,CAAC,KAAK,EAAE,wCAAwC,EAAE,gCAAgC,CAAC,CAAC;IACvG,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,kBAAkB,EAAE,QAAQ,CAAC,EAAE,gCAAgC,CAAC,CAAC;IAC3G,OAAO;QACL,gBAAgB,EAAE,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,gCAAgC,CAAC;QAC7F,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,wCAAwC,CAAC;KACjF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uCAAuC,CAAC,KAAc;IACpE,mBAAmB,CAAC,KAAK,EAAE,wCAAwC,EAAE,uCAAuC,CAAC,CAAC;IAC9G,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,kBAAkB,EAAE,QAAQ,CAAC,EAAE,uCAAuC,CAAC,CAAC;IAClH,OAAO;QACL,gBAAgB,EAAE,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,uCAAuC,CAAC;QACpG,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,+CAA+C,CAAC;KACxF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAc;IAC1D,mBAAmB,CAAC,KAAK,EAAE,qCAAqC,EAAE,6BAA6B,CAAC,CAAC;IACjG,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAC5H,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,WAAW,CAAC,KAAK;QAAE,MAAM,OAAO,CAAC,6BAA6B,CAAC,CAAC;IAEzF,MAAM,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtG,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,OAAO,CAAC,6BAA6B,CAAC,CAAC;IAE7E,OAAO;QACL,WAAW,EAAE,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,6BAA6B,CAAC;QACnF,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM;QACN,WAAW;KACZ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,KAAc;IAC/D,MAAM,MAAM,GAAG,kBAAkB,CAC/B,KAAK,EACL,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAC3D,kCAAkC,CACnC,CAAC;IACF,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,iCAAiC,CAAC,CAAC;YAC5G,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,gCAAgC,CAAC;gBACxE,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,iCAAiC,CAAC;aAC/E,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kCAAkC,CAAC,CAAC;YACvH,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,kCAAkC,CAAC;gBAC7E,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,kCAAkC,CAAC;gBACvE,QAAQ,EAAE,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,kCAAkC,CAAC;aACjF,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,kCAAkC,CAAC,CAAC;YAC7H,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,YAAY,CAAC,eAAe,EAAE,SAAS,EAAE,kCAAkC,CAAC;gBACrF,IAAI,EAAE,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,kCAAkC,CAAC;gBAC/E,MAAM,EAAE,YAAY,CAAC,eAAe,EAAE,QAAQ,EAAE,kCAAkC,CAAC;aACpF,CAAC;QACJ,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,sCAAsC,CAAC,CAAC;YAC7H,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,EAAE,sCAAsC,CAAC,CAAC;YACxF,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,YAAY,CAAC,WAAW,EAAE,SAAS,EAAE,sCAAsC,CAAC;gBACrF,IAAI,EAAE,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,sCAAsC,CAAC;gBAC/E,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;aAC5C,CAAC;QACJ,CAAC;QACD;YACE,MAAM,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iCAAiC,CAAC,KAAc;IAC9D,MAAM,MAAM,GAAG,kBAAkB,CAC/B,KAAK,EACL,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAC3D,iCAAiC,CAClC,CAAC;IACF,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,wCAAwC,CAAC,CAAC;YACnH,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,uCAAuC,CAAC;gBAC/E,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,wCAAwC,CAAC;aACtF,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,yCAAyC,CAAC,CAAC;YACpI,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,YAAY,CAAC,eAAe,EAAE,SAAS,EAAE,yCAAyC,CAAC;gBAC5F,IAAI,EAAE,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,yCAAyC,CAAC;gBACtF,MAAM,EAAE,YAAY,CAAC,eAAe,EAAE,QAAQ,EAAE,yCAAyC,CAAC;aAC3F,CAAC;QACJ,CAAC;QACD;YACE,MAAM,OAAO,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,MAAM,MAAM,GAAG,kBAAkB,CAC/B,KAAK,EACL,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,EAC5E,4BAA4B,CAC7B,CAAC;IACF,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,iCAAiC,CAAC,CAAC;YAC/H,OAAO;gBACL,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,gBAAgB,CAAC,SAAS,EAAE,aAAa,EAAE,iCAAiC,CAAC;gBAC1F,SAAS,EAAE,kCAAkC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;gBACrE,MAAM,EAAE,iCAAiC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;aAC/D,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,+BAA+B,CAAC,CAAC;YACpI,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,qBAAqB;gBAAE,MAAM,OAAO,CAAC,+BAA+B,CAAC,CAAC;YAC/F,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,+BAA+B,CAAC;gBACtF,KAAK,EAAE,qBAAqB;gBAC5B,SAAS,EAAE,kCAAkC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;gBACnE,MAAM,EAAE,iCAAiC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;aAC7D,CAAC;QACJ,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,qCAAqC,CAAC,CAAC;YACjH,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,uBAAuB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACnD,OAAO,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,qCAAqC,CAAC;aAClF,CAAC;QACJ,CAAC;QACD,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,uCAAuC,CAAC,CAAC;YAC3G,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,uCAAuC,CAAC,EAAE,CAAC;QACvH,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,wCAAwC,CAAC,CAAC;YAC7G,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,CAAC,WAAW,EAAE,SAAS,EAAE,wCAAwC,CAAC,EAAE,CAAC;QAC1H,CAAC;QACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,cAAc,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,4CAA4C,CAAC,CAAC;YACpH,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,YAAY,CAAC,cAAc,EAAE,SAAS,EAAE,4CAA4C,CAAC,EAAE,CAAC;QACrI,CAAC;QACD;YACE,MAAM,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,KAAc;IAC/D,MAAM,MAAM,GAAG,kBAAkB,CAC/B,KAAK,EACL,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,CAAC,EAC1C,kCAAkC,CACnC,CAAC;IACF,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,oCAAoC,CAAC,CAAC;YACxG,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,oCAAoC,CAAC,EAAE,CAAC;QACpH,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,kCAAkC,CAAC,CAAC;YAC9G,OAAO;gBACL,IAAI,EAAE,UAAU;gBAChB,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAC/C,OAAO,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,EAAE,kCAAkC,CAAC;aAC/E,CAAC;QACJ,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,WAAW,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,EAAE,qCAAqC,CAAC,CAAC;YACvH,OAAO;gBACL,IAAI,EAAE,aAAa;gBACnB,OAAO,EAAE,YAAY,CAAC,WAAW,EAAE,SAAS,EAAE,qCAAqC,CAAC;gBACpF,SAAS,EAAE,cAAc,CAAC,WAAW,EAAE,WAAW,EAAE,qCAAqC,CAAC;aAC3F,CAAC;QACJ,CAAC;QACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,MAAM,cAAc,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,yCAAyC,CAAC,CAAC;YACjH,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,YAAY,CAAC,cAAc,EAAE,SAAS,EAAE,yCAAyC,CAAC,EAAE,CAAC;QAClI,CAAC;QACD;YACE,MAAM,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE,4BAA4B,CAAC,CAAC;IACnG,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,sCAAsC,CAAC,CAAC;IAChF,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;QAC9B,MAAM,eAAe,GAAG,gCAAgC,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,wCAAwC,EAAE,IAAI,CAAC,CAAC;QACpI,IAAI,eAAe,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAC/F,OAAO,EAAE,GAAG,EAAE,eAAe,EAAE,CAAC;IAClC,CAAC;IACD,OAAO;QACL,GAAG;QACH,eAAe,EAAE,6BAA6B,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,+CAA+C,CAAC;KAC3H,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAClH,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,sCAAsC,CAAC,CAAC;IAC/E,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QAC1B,OAAO;YACL,KAAK;YACL,eAAe,EAAE,gCAAgC,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,6CAA6C,EAAE,KAAK,CAAC;YAClI,IAAI;SACL,CAAC;IACJ,CAAC;IACD,OAAO;QACL,KAAK;QACL,eAAe,EAAE,6BAA6B,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,oDAAoD,CAAC;QAC/H,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAS,gCAAgC,CAAC,KAAc,EAAE,KAAa,EAAE,aAAsB;IAC7F,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAChF,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACvB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;YAChF,OAAO;gBACL,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC;gBAClD,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,UAAU,CAAC;aAC3D,CAAC;QACJ,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,IAAI,aAAa;gBAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;YACvE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;QAClF,CAAC;QACD;YACE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,6BAA6B,CAAC,KAAc,EAAE,KAAa;IAClE,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAChF,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IAChF,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC;QAClD,MAAM,EAAE,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,UAAU,CAAC;KAC3D,CAAC;AACJ,CAAC;AAMD,SAAS,YAAY,CAAC,KAAc,EAAE,KAAa;IACjD,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACtD,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,WAAW;QAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC7D,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,SAAS,CAAC,KAAc,EAAE,KAAa;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,KAAK,UAAU,CAAC,CAAC;IAChF,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,KAAa;IACjD,MAAM,MAAM,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,+BAA+B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAA+B,EAAE,GAAW,EAAE,KAAa;IACnF,MAAM,WAAW,GAAG,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC9D,IAAI,CAAC,wBAAwB,CAAC,WAAW,CAAC;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACjE,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,aAAa,CAAC,MAA+B,EAAE,GAAW,EAAE,KAAa;IAChF,OAAO,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO;QAAE,MAAM,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACzF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,KAAa;IAC/C,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,WAAW;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACtE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC7C,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC;QAAE,MAAM,OAAO,CAAC,qCAAqC,CAAC,CAAC;IACvF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC;QAAE,MAAM,OAAO,CAAC,kCAAkC,CAAC,CAAC;IAChF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAc;IAC1C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,wCAAwC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,mCAAmC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,YAAY,CAAC,MAA+B,EAAE,GAAW,EAAE,KAAa;IAC/E,OAAO,qBAAqB,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA+B,EAAE,KAAa;IACzE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IACvD,OAAO,qBAAqB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,cAAc,CAAC,MAA+B,EAAE,GAAW,EAAE,KAAa;IACjF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,MAA+B,EAAE,GAAW,EAAE,KAAa;IACxF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc,EAAE,aAAgC,EAAE,KAAa;IACzF,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACxH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc,EAAE,KAAa,EAAE,KAAa;IACvE,IAAI,UAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,OAAO,SAAS,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,EAAE,CAAC;QACrD,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IACD,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,UAAU,GAAG,KAAK;QAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,MAAM,SAAS,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAChD,OAAO,SAAS,KAAK,MAAM,CAAC,SAAS,IAAI,SAAS,KAAK,IAAI,CAAC;AAC9D,CAAC"}
package/docs/config.md CHANGED
@@ -158,7 +158,7 @@ Rows with JSON key `—` are runtime-only environment variables, not config-file
158
158
  | Utility model routing | `utilityModels` | — | Global | Not supported locally | Saved settings apply immediately on the next utility operation; requires remote peer capability `settings.utilityModels` |
159
159
  | Local gateway text to speech | `tts` | — | Global | Not supported locally | Next utterance after settings save; no service restart |
160
160
  | Speech input (dictation) | `speechInput` | — | Global (gateway) | Not supported locally | Next dictation run after settings save; installing/updating this feature requires one manual session-daemon restart |
161
- | Plugin enablement/settings | `plugins.<id>.enabled`, `plugins.<id>.settings` | — | Global | Not core local config; plugins may read their own project files | Reload browser tab |
161
+ | Plugin enablement/settings and global tasks | `plugins.<id>.enabled`, `plugins.<id>.settings`, `plugins.workspace-tasks.settings.globalTasks` | — | Global | Plugin-owned global settings; Project task catalogs remain in each selected workspace's `.pi-webui/tasks.json` | Reload browser tab / Tasks panel |
162
162
  | Keyboard shortcuts | `shortcuts.<actionId>` | — | Global | Not supported locally | Applies after settings save/config refresh |
163
163
  | Project config version | `version` | — | Project | Project-local only; must be `1` when present | Next project-config read |
164
164
  | **Runtime-only environment variables** | | | | | |
@@ -419,20 +419,38 @@ In **Settings → Session daemon**, these keys are saved on the selected machine
419
419
 
420
420
  ### Plugin config
421
421
 
422
- The `plugins` key is only for PI WEBUI browser plugin enablement/settings on the machine whose config you are editing. It does not install, remove, or update Pi packages; use **Settings → Pi packages** or Pi's package manager for package operations. In a federated setup, **Settings → PI WEBUI plugins** and **Settings → Pi packages** both target the currently selected machine, and each panel labels where changes will be saved or run.
422
+ The `plugins` key is for PI WEBUI browser plugin enablement and plugin-owned settings on the machine whose config you are editing. It does not install, remove, or update Pi packages; use **Settings → Pi packages** or Pi's package manager for package operations. In a federated setup, **Settings → PI WEBUI plugins** and **Settings → Pi packages** both target the currently selected machine, and each panel labels where changes will be saved or run.
423
423
 
424
424
  Plugins are enabled by default. Set `plugins.<id>.enabled` to `false` to remove a plugin from that machine's `/pi-webui-plugins/manifest.json` before the browser imports it. Settings lists discovered plugins from the selected machine, including disabled entries exposed by that machine.
425
425
 
426
+ The built-in Workspace Tasks plugin stores its machine-global catalog at the exact nested key `plugins.workspace-tasks.settings.globalTasks`. The value is a version-one task catalog, uses the same task fields as `.pi-webui/tasks.json`, and does not add a scope field to individual tasks:
427
+
426
428
  ```json
427
429
  {
428
430
  "plugins": {
429
- "workspace-tasks": { "enabled": true, "settings": {} },
431
+ "workspace-tasks": {
432
+ "enabled": true,
433
+ "settings": {
434
+ "globalTasks": {
435
+ "version": 1,
436
+ "tasks": []
437
+ }
438
+ }
439
+ },
430
440
  "updates": { "enabled": false }
431
441
  }
432
442
  }
433
443
  ```
434
444
 
435
- Reload the browser tab after changing plugin enablement. Already-loaded plugin JavaScript is not unloaded from the current page.
445
+ If `globalTasks` is absent, Workspace Tasks treats it as the canonical empty version-one catalog. If it is present but malformed, the Tasks panel reports the global catalog as invalid and does not replace it with an empty value. Repair malformed global data through normal PI WEBUI configuration administration, such as a reviewed configuration update or a carefully reviewed config-file change while the relevant service is stopped; then use **Refresh** in the Tasks panel to load the repaired catalog.
446
+
447
+ Global reads and writes use an opaque semantic revision for compare-and-swap (CAS). The revision represents the canonical supported task projection: unchanged task content keeps the same revision, a semantic change produces a new one, and replacing a catalog with the same content is a no-op. A stale conditional write is rejected without changing either the catalog or unrelated configuration, so the browser must **Refresh** before trying again. Browser writes canonicalize supported fields and drop unknown fields.
448
+
449
+ This protection covers coordinated PI WEBUI task mutations, not arbitrary external editors, Git operations, or other processes writing the same files. External conflict detection is best-effort and is not an atomic cross-process CAS guarantee. Promotion and demotion use guarded server-owned recovery: a destination collision or source conflict leaves both catalogs unchanged; an uncertain or partial move requires **Refresh** and, only when offered, **Retry move**. There is no automatic merge, retry, compensation, or overwrite of an unrecognized intermediate state.
450
+
451
+ Move ownership is process-local. A web/API restart loses ownership of an intermediate move, so the resulting state is manual-resolution-only rather than automatically retried. Run exactly one active web/API route owner for a machine's PI WEBUI config; multiple web/API processes serving the same config are unsupported for guarded moves because process-local recovery is not a distributed lock.
452
+
453
+ Reload the browser tab after changing plugin enablement or the global task catalog. Already-loaded plugin JavaScript is not unloaded from the current page.
436
454
 
437
455
  ### Shortcut config
438
456
 
package/docs/plugins.md CHANGED
@@ -264,8 +264,9 @@ Updates is enabled by default. It declares `machineSpecific: true` so the gatewa
264
264
  ### Workspace Tasks
265
265
 
266
266
  **Plugin id:** `workspace-tasks`
267
- **Config file:** `.pi-webui/tasks.json`
268
- **What it does:** adds a **Tasks** workspace tab for running configured shell commands in dedicated PI WEBUI terminals.
267
+ **Project catalog file:** `.pi-webui/tasks.json`
268
+ **Global catalog setting:** `plugins.workspace-tasks.settings.globalTasks`
269
+ **What it does:** adds a **Tasks** workspace tab for browsing, editing, and running configured shell commands in dedicated PI WEBUI terminals.
269
270
 
270
271
  Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → PI WEBUI plugins** or set:
271
272
 
@@ -277,7 +278,7 @@ Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in
277
278
  }
278
279
  ```
279
280
 
280
- Configure workspace tasks in `.pi-webui/tasks.json`:
281
+ Configure Project tasks in `.pi-webui/tasks.json`:
281
282
 
282
283
  ```json
283
284
  {
@@ -312,16 +313,24 @@ Task fields:
312
313
  - `group`: optional group heading.
313
314
  - `confirm`: optional boolean. When true, the browser asks before dispatching the command.
314
315
 
315
- Open a workspace, choose the **Tasks** tab, and use the editor to manage tasks in the browser:
316
+ The Tasks panel has **All**, **Global**, and **Project** filters. **All** shows separate Global and Project headings, while the other filters show one catalog. Counts reflect the tasks currently loaded in each scope. Equal task IDs are valid in both scopes: a Global task and a Project task with the same ID remain separate rows with independent edit, delete, and run actions.
316
317
 
317
- - **Add** creates a task and appends it to the task array.
318
- - **Edit** updates the task at its existing position in the array.
318
+ Tasks with a `group` use native collapsible disclosure groups. Groups keep their first-seen order within each catalog, start collapsed, and retain their open state while the panel remains mounted. The **All** view keeps the scopes and their groups distinct even when group names or task IDs match.
319
+
320
+ The UI calls the workspace-rooted catalog **Project**. A Project task is stored at the selected workspace's `.pi-webui/tasks.json`, so the main checkout and each linked Git worktree have separate catalogs. A Global task is stored once in the selected machine's PI WEBUI configuration and is independently editable from every workspace on that machine; it is not linked to the workspace where it was created.
321
+
322
+ The editor uses the **Available in all projects on this machine** checkbox. It is unchecked for a new Project task and checked for a new Global task. Creating a new task in either scope writes directly to that catalog. Changing the checkbox for an existing task asks for confirmation, names the source and destination scope, and then performs a guarded promotion or demotion that removes the source definition only after the destination definition is written and verified.
323
+
324
+ - **Add** creates a task and appends it to the selected catalog.
325
+ - **Edit** preserves its position in that catalog.
319
326
  - **Delete** removes the selected task without reordering the remaining tasks.
320
- - **Reset** is offered only for a complete, readable task-file snapshot whose text is invalid, including parse- or schema-invalid text. It is unavailable for binary, truncated, or otherwise unavailable files. After confirmation, it replaces the file with the canonical empty version-1 configuration `{"version":1,"tasks":[]}`.
327
+ - **Repair invalid Project files manually.** The panel does not offer a reset action because guarded writes require a valid source snapshot. Open `.pi-webui/tasks.json` in the file explorer, correct the invalid text, then click **Refresh**. Binary, truncated, or otherwise unavailable files must be repaired at the workspace or machine configuration source.
321
328
 
322
- Browser saves write canonical JSON for the supported task fields. They preserve supported task values and task-array order, but canonicalize whitespace and key order and drop unsupported fields; original JSON formatting is not preserved.
329
+ Browser writes canonicalize whitespace and key order, preserve supported task values and array order, and drop unknown fields; original JSON formatting and unsupported fields are not preserved.
323
330
 
324
- For a multiline script, encode line feeds as `\n` in JSON:
331
+ The global catalog uses the same version-one task shape as a Project catalog. A missing global catalog is treated as an empty version-one catalog. If the stored global value is malformed, the Tasks panel reports the global catalog as invalid and does not replace it with an empty catalog. Repair malformed global configuration through normal PI WEBUI configuration administration; the panel's manual Project-file repair does not repair global configuration.
332
+
333
+ For a multiline command, encode line feeds as `\n` in JSON:
325
334
 
326
335
  ```json
327
336
  {
@@ -330,13 +339,15 @@ For a multiline script, encode line feeds as `\n` in JSON:
330
339
  {
331
340
  "id": "verify",
332
341
  "title": "Build and test",
333
- "command": "set -e\nnpm run build\nnpm test"
342
+ "group": "Quality",
343
+ "command": "set -e\nnpm run build\nnpm test",
344
+ "confirm": true
334
345
  }
335
346
  ]
336
347
  }
337
348
  ```
338
349
 
339
- Click **Run** next to a task to send one terminal request. The server starts one dedicated terminal in the workspace root with `$SHELL -lc`, so lines in a multiline script share shell state such as variables and the current directory. The shell's final exit status determines whether the run succeeds or fails. For POSIX-compatible fail-fast behavior, use syntax such as:
350
+ Click **Run** next to a task to send one terminal request. Both Project and Global tasks run in the currently selected workspace root, so a Global task adapts to the workspace in which it is launched. The server starts one dedicated terminal with `$SHELL -lc`; all lines in a multiline command share shell state such as variables and the current directory, and the shell's final exit status determines whether the run succeeds or fails. This is one terminal request, not one request per line. For POSIX-compatible fail-fast behavior, use syntax such as:
340
351
 
341
352
  ```sh
342
353
  set -e
@@ -352,9 +363,9 @@ npm run build && npm test
352
363
 
353
364
  These are POSIX-compatible examples, not shell-neutral guarantees.
354
365
 
355
- If the task file changed after the browser loaded it, the editor refuses the stale save as a best-effort conflict guard instead of merging the changes. Use **Refresh** to load the latest file, review it, and retry. This protects against sequential stale browser edits; it is not an atomic cross-tab or cross-process compare-and-swap guarantee.
366
+ A stale catalog save or destination collision leaves the affected catalogs unchanged. Use **Refresh** to load authoritative data, review the draft, and try again. A partial or uncertain promotion/demotion remains in guarded recovery: **Retry move** is available only after Refresh confirms the exact destination-written state, and it is still checked by the server before the source is removed. There is no automatic merge, retry, compensation, or overwrite of an unrecognized intermediate state. A server restart loses process-local move ownership, so any intermediate state left after restart requires manual resolution rather than an automatic retry.
356
367
 
357
- Review task configs before running them, especially in shared projects. Workspace Tasks runs trusted shell commands from your repositories.
368
+ Review task definitions before running them, especially in shared repositories. Workspace Tasks runs trusted shell commands from your repositories, and both Global and Project tasks execute in the selected workspace root.
358
369
 
359
370
  ## Discovery and packaging
360
371
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperdreamer/pi-webui",
3
- "version": "1.15.2",
3
+ "version": "1.16.0",
4
4
  "description": "Web UI for persistent Pi Coding Agent sessions in real workspaces.",
5
5
  "license": "MIT",
6
6
  "author": "Federico Jaramillo Martinez and HyperDreamer",