@eclipse-lyra/extension-utils 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/commands/cat.d.ts +2 -0
  2. package/dist/commands/cat.d.ts.map +1 -0
  3. package/dist/commands/exists.d.ts +2 -0
  4. package/dist/commands/exists.d.ts.map +1 -0
  5. package/dist/commands/filebrowser-contributions.d.ts +2 -0
  6. package/dist/commands/filebrowser-contributions.d.ts.map +1 -0
  7. package/dist/commands/head.d.ts +2 -0
  8. package/dist/commands/head.d.ts.map +1 -0
  9. package/dist/commands/index.d.ts +1 -0
  10. package/dist/commands/index.d.ts.map +1 -0
  11. package/dist/commands/js.d.ts +2 -0
  12. package/dist/commands/js.d.ts.map +1 -0
  13. package/dist/commands/ls.d.ts +2 -0
  14. package/dist/commands/ls.d.ts.map +1 -0
  15. package/dist/commands/mv.d.ts +2 -0
  16. package/dist/commands/mv.d.ts.map +1 -0
  17. package/dist/commands/p12split.d.ts +2 -0
  18. package/dist/commands/p12split.d.ts.map +1 -0
  19. package/dist/commands/rm.d.ts +2 -0
  20. package/dist/commands/rm.d.ts.map +1 -0
  21. package/dist/commands/tail.d.ts +2 -0
  22. package/dist/commands/tail.d.ts.map +1 -0
  23. package/dist/commands/touch.d.ts +2 -0
  24. package/dist/commands/touch.d.ts.map +1 -0
  25. package/dist/commands/unzip.d.ts +2 -0
  26. package/dist/commands/unzip.d.ts.map +1 -0
  27. package/dist/commands/wc.d.ts +2 -0
  28. package/dist/commands/wc.d.ts.map +1 -0
  29. package/dist/commands/wget.d.ts +2 -0
  30. package/dist/commands/wget.d.ts.map +1 -0
  31. package/dist/i18n.json.d.ts +17 -0
  32. package/dist/index-Bm7Xxv-I.js +862 -0
  33. package/dist/index-Bm7Xxv-I.js.map +1 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +19 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/p12splitter--4Q2vYnp.js +5 -0
  39. package/dist/p12splitter--4Q2vYnp.js.map +1 -0
  40. package/dist/shared.d.ts +5 -0
  41. package/dist/shared.d.ts.map +1 -0
  42. package/package.json +30 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=exists.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exists.d.ts","sourceRoot":"","sources":["../../src/commands/exists.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=filebrowser-contributions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filebrowser-contributions.d.ts","sourceRoot":"","sources":["../../src/commands/filebrowser-contributions.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=head.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../../src/commands/head.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC;AAChB,OAAO,MAAM,CAAC;AACd,OAAO,SAAS,CAAC;AACjB,OAAO,MAAM,CAAC;AACd,OAAO,MAAM,CAAC;AACd,OAAO,6BAA6B,CAAC;AACrC,OAAO,QAAQ,CAAC;AAChB,OAAO,QAAQ,CAAC;AAChB,OAAO,OAAO,CAAC;AACf,OAAO,UAAU,CAAC;AAClB,OAAO,MAAM,CAAC;AACd,OAAO,SAAS,CAAC;AACjB,OAAO,YAAY,CAAC;AACpB,OAAO,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=js.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"js.d.ts","sourceRoot":"","sources":["../../src/commands/js.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../src/commands/ls.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mv.d.ts","sourceRoot":"","sources":["../../src/commands/mv.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=p12split.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"p12split.d.ts","sourceRoot":"","sources":["../../src/commands/p12split.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rm.d.ts","sourceRoot":"","sources":["../../src/commands/rm.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tail.d.ts","sourceRoot":"","sources":["../../src/commands/tail.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=touch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"touch.d.ts","sourceRoot":"","sources":["../../src/commands/touch.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=unzip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unzip.d.ts","sourceRoot":"","sources":["../../src/commands/unzip.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wc.d.ts","sourceRoot":"","sources":["../../src/commands/wc.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wget.d.ts","sourceRoot":"","sources":["../../src/commands/wget.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ declare const _default: {
2
+ "namespace": "extensions",
3
+ "en": {
4
+ "EXT_UTILS_NAME": "Utilities",
5
+ "EXT_UTILS_DESC": "Utility commands such as wget, unzip and certificate tools.",
6
+ "CMD_WGET_NAME": "wget",
7
+ "CMD_WGET_DESC": "Download a file from a URL to the workspace.",
8
+ "CMD_UNZIP_NAME": "Unzip Archive",
9
+ "CMD_UNZIP_DESC": "Extract a zip archive from the workspace.",
10
+ "CMD_P12SPLIT_NAME": ".p12 file splitter",
11
+ "CMD_P12SPLIT_DESC": "Split a .p12 certificate file into separate PEM files.",
12
+ "RENAME": "Rename",
13
+ "DELETE": "Delete"
14
+ }
15
+ };
16
+
17
+ export default _default;
@@ -0,0 +1,862 @@
1
+ import { registerAll, toastError, workspaceService, taskService, FileContentType, toastInfo, File, Directory, promptDialog, activeSelectionSignal, confirmDialog, i18nLazy, contributionRegistry } from "@eclipse-lyra/core";
2
+ import JSZip from "jszip";
3
+ import { PyEnv } from "@eclipse-lyra/extension-python-runtime/api";
4
+ registerAll({
5
+ command: {
6
+ id: "wget",
7
+ name: "wget",
8
+ description: "Download a file from a URL to the workspace",
9
+ parameters: [
10
+ {
11
+ name: "url",
12
+ description: "the URL of the file to download",
13
+ required: true
14
+ },
15
+ {
16
+ name: "filename",
17
+ description: "optional filename to save as (will be auto-detected if not provided)",
18
+ required: false
19
+ }
20
+ ]
21
+ },
22
+ handler: {
23
+ canExecute: (context) => {
24
+ const url = context.params && context.params["url"];
25
+ if (!url) {
26
+ return false;
27
+ }
28
+ return url.startsWith("http://") || url.startsWith("https://");
29
+ },
30
+ execute: async (context) => {
31
+ const url = context.params && context.params["url"];
32
+ if (!url) {
33
+ toastError("No URL provided.");
34
+ return;
35
+ }
36
+ const workspaceDir = await workspaceService.getWorkspace();
37
+ if (!workspaceDir) {
38
+ toastError("No workspace selected.");
39
+ return;
40
+ }
41
+ const folders = await workspaceService.getFolders();
42
+ const targetFolderName = folders.length > 0 ? folders[0].name : null;
43
+ await taskService.runAsync("Downloading file", async (progress) => {
44
+ progress.message = "Starting download...";
45
+ progress.progress = 0;
46
+ try {
47
+ const response = await fetch(url, {
48
+ mode: "cors",
49
+ credentials: "omit"
50
+ });
51
+ if (!response.ok) {
52
+ toastError("Failed to download file: " + response.statusText);
53
+ return;
54
+ }
55
+ let fileName = context.params && context.params["filename"];
56
+ if (!fileName) {
57
+ const contentDisposition = response.headers.get("content-disposition");
58
+ if (contentDisposition) {
59
+ let filenameMatch = contentDisposition.match(/filename="([^"]+)"/);
60
+ if (filenameMatch && filenameMatch[1]) {
61
+ fileName = filenameMatch[1];
62
+ } else {
63
+ filenameMatch = contentDisposition.match(/filename=([^;]+)/);
64
+ if (filenameMatch && filenameMatch[1]) {
65
+ fileName = filenameMatch[1].trim();
66
+ }
67
+ }
68
+ }
69
+ if (!fileName) {
70
+ const urlSegments = new URL(url).pathname.split("/").filter((s) => s.length > 0);
71
+ const lastSegment = urlSegments[urlSegments.length - 1];
72
+ if (lastSegment && lastSegment.includes(".")) {
73
+ fileName = lastSegment;
74
+ } else {
75
+ const now = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").replace("T", "_").slice(0, -5);
76
+ fileName = `downloaded-file-${now}`;
77
+ }
78
+ }
79
+ }
80
+ const targetPath = targetFolderName ? `${targetFolderName}/${fileName}` : fileName;
81
+ const downloadedFile = await workspaceDir.getResource(targetPath, { create: true });
82
+ progress.message = `Downloading ${fileName}...`;
83
+ progress.progress = 50;
84
+ await downloadedFile.saveContents(response.body, {
85
+ contentType: FileContentType.BINARY
86
+ });
87
+ progress.progress = 100;
88
+ toastInfo(`File downloaded: ${fileName}`);
89
+ } catch (err) {
90
+ toastError("Failed to download file: " + err);
91
+ throw err;
92
+ }
93
+ });
94
+ }
95
+ }
96
+ });
97
+ async function getTextFileFromPath(path) {
98
+ const workspaceDir = await workspaceService.getWorkspace();
99
+ if (!workspaceDir) {
100
+ toastError("No workspace selected.");
101
+ return null;
102
+ }
103
+ try {
104
+ const resource = await workspaceDir.getResource(path);
105
+ if (!resource || !(resource instanceof File)) {
106
+ toastError("File not found: " + path);
107
+ return null;
108
+ }
109
+ return resource;
110
+ } catch (err) {
111
+ toastError(`Failed to access file: ${err.message ?? err}`);
112
+ return null;
113
+ }
114
+ }
115
+ async function readTextFile(file) {
116
+ try {
117
+ const contents = await file.getContents();
118
+ if (typeof contents !== "string") {
119
+ toastError("File is not a text file");
120
+ return null;
121
+ }
122
+ return contents;
123
+ } catch (err) {
124
+ toastError(`Failed to read file: ${err.message ?? err}`);
125
+ return null;
126
+ }
127
+ }
128
+ async function collectFilesRecursive(directory) {
129
+ const files = [];
130
+ const children = await directory.listChildren(true);
131
+ for (const child of children) {
132
+ if (child instanceof File) {
133
+ files.push(child.getWorkspacePath());
134
+ } else if (child instanceof Directory) {
135
+ const subFiles = await collectFilesRecursive(child);
136
+ files.push(...subFiles);
137
+ }
138
+ }
139
+ return files;
140
+ }
141
+ registerAll({
142
+ command: {
143
+ id: "ls",
144
+ name: "List files",
145
+ description: "Lists files from a directory. If recursive is provided, it traverses from the provided directory down to all leaves. If no directory is provided, it will traverse from the workspace root.",
146
+ parameters: [
147
+ {
148
+ name: "path",
149
+ description: "the path of the directory to list, relative to the workspace. If not provided, uses workspace root",
150
+ required: false
151
+ },
152
+ {
153
+ name: "recursive",
154
+ description: "whether to recursively traverse all subdirectories",
155
+ type: "boolean",
156
+ required: false
157
+ }
158
+ ],
159
+ output: [
160
+ {
161
+ name: "files",
162
+ description: "array of file objects with path and size information"
163
+ }
164
+ ]
165
+ },
166
+ handler: {
167
+ execute: async ({ params }) => {
168
+ const workspace = await workspaceService.getWorkspace();
169
+ if (!workspace) {
170
+ toastError("No workspace available");
171
+ return [];
172
+ }
173
+ const path = params?.path;
174
+ const recursive = params?.recursive === true || params?.recursive === "true";
175
+ try {
176
+ let targetDir = workspace;
177
+ if (path) {
178
+ const resource = await workspace.getResource(path);
179
+ if (!resource) {
180
+ toastError(`Path not found: ${path}`);
181
+ return [];
182
+ }
183
+ if (!(resource instanceof Directory)) {
184
+ toastError(`Path is not a directory: ${path}`);
185
+ return [];
186
+ }
187
+ targetDir = resource;
188
+ }
189
+ if (recursive) {
190
+ const files = await collectFilesRecursive(targetDir);
191
+ const result2 = [];
192
+ for (const filePath of files) {
193
+ const file = await workspace.getResource(filePath);
194
+ if (file instanceof File) {
195
+ const size = await file.size();
196
+ result2.push({
197
+ path: filePath,
198
+ size
199
+ });
200
+ }
201
+ }
202
+ return result2;
203
+ }
204
+ const children = await targetDir.listChildren(true);
205
+ const result = [];
206
+ for (const child of children) {
207
+ if (child instanceof File) {
208
+ const size = await child.size();
209
+ result.push({
210
+ path: child.getWorkspacePath(),
211
+ size
212
+ });
213
+ }
214
+ }
215
+ return result;
216
+ } catch (err) {
217
+ toastError(`Failed to list files: ${err.message ?? err}`);
218
+ return [];
219
+ }
220
+ }
221
+ }
222
+ });
223
+ registerAll({
224
+ command: {
225
+ id: "touch",
226
+ name: "Touch - Create new file",
227
+ description: "Creates a new file within the workspace. For .geospace map files, use create_map_file instead.",
228
+ parameters: [
229
+ {
230
+ name: "path",
231
+ description: "the path including name of the file to be created, must be relative to the workspace",
232
+ required: false
233
+ },
234
+ {
235
+ name: "contents",
236
+ description: "the textual contents of the file",
237
+ required: false
238
+ },
239
+ {
240
+ name: "ask",
241
+ description: "whether to prompt the user for the file path",
242
+ required: false
243
+ },
244
+ {
245
+ name: "extension",
246
+ description: "required file extension (e.g., '.geospace'), will be appended if missing",
247
+ required: false
248
+ }
249
+ ],
250
+ output: [
251
+ {
252
+ name: "path",
253
+ description: "the path of the created file"
254
+ }
255
+ ]
256
+ },
257
+ handler: {
258
+ execute: async ({ params }) => {
259
+ let path = params?.path;
260
+ const contents = params?.contents;
261
+ const ask = params?.ask;
262
+ const extension = params?.extension;
263
+ if (ask || !path) {
264
+ path = await promptDialog(
265
+ "Enter path to new file (directories will be created if not exist):",
266
+ path || ""
267
+ );
268
+ if (!path) {
269
+ return;
270
+ }
271
+ }
272
+ if (extension && path && !path.endsWith(extension)) {
273
+ path += extension;
274
+ }
275
+ if (path) {
276
+ const selection = activeSelectionSignal.get();
277
+ const dirPath = selection instanceof Directory ? selection.getWorkspacePath() : selection instanceof File ? selection.getParent()?.getWorkspacePath() : void 0;
278
+ if (dirPath && !path.startsWith(dirPath + "/")) path = dirPath + "/" + path;
279
+ }
280
+ const workspaceDir = await workspaceService.getWorkspace();
281
+ if (!workspaceDir) {
282
+ toastError("No workspace selected.");
283
+ return;
284
+ }
285
+ const existingResource = await workspaceDir.getResource(path);
286
+ if (existingResource) {
287
+ const overwrite = await confirmDialog(
288
+ `File "${path}" already exists. Do you want to overwrite it?`
289
+ );
290
+ if (!overwrite) {
291
+ return;
292
+ }
293
+ }
294
+ const createdResource = await workspaceDir.getResource(path, { create: true });
295
+ if (!createdResource) {
296
+ toastError("Could not create file: " + path);
297
+ return;
298
+ }
299
+ if (contents) {
300
+ await createdResource.saveContents(contents);
301
+ }
302
+ toastInfo(`File created: ${path}`);
303
+ return path;
304
+ }
305
+ }
306
+ });
307
+ registerAll({
308
+ command: {
309
+ id: "mv",
310
+ name: "mv - Rename a resource (file or directory)",
311
+ description: "Renames a resource (file or directory)",
312
+ parameters: [
313
+ {
314
+ name: "path",
315
+ description: "the path of the resource within the workspace to rename or the currently active selection",
316
+ required: false
317
+ },
318
+ {
319
+ name: "newName",
320
+ description: "the new name for the resource",
321
+ required: false
322
+ }
323
+ ]
324
+ },
325
+ handler: {
326
+ execute: async (context) => {
327
+ const workspaceDir = await workspaceService.getWorkspace();
328
+ if (!workspaceDir) {
329
+ toastError("No workspace selected.");
330
+ return;
331
+ }
332
+ const path = context.params?.path;
333
+ let resource = null;
334
+ if (path) {
335
+ resource = await workspaceDir.getResource(path);
336
+ }
337
+ if (!resource) {
338
+ resource = activeSelectionSignal.get();
339
+ }
340
+ if (!resource) {
341
+ toastError("No resource to rename provided!");
342
+ return;
343
+ }
344
+ const currentName = resource.getName();
345
+ const newName = context.params?.newName ?? await promptDialog(`Enter new name for "${currentName}":`, currentName);
346
+ if (!newName || newName === currentName) {
347
+ return;
348
+ }
349
+ try {
350
+ await resource.rename(newName);
351
+ toastInfo(`Resource renamed to: ${newName}`);
352
+ } catch (err) {
353
+ toastError(`Failed to rename ${currentName}: ${err.message ?? err}`);
354
+ }
355
+ }
356
+ }
357
+ });
358
+ registerAll({
359
+ command: {
360
+ id: "rm",
361
+ name: "rm - Delete a resource (file or directory)",
362
+ description: "Deletes a resource (file or directory)",
363
+ parameters: [
364
+ {
365
+ name: "path",
366
+ description: "the path of the resource within the workspace to delete or the currently active selection",
367
+ required: false
368
+ },
369
+ {
370
+ name: "confirm",
371
+ description: "whether to ask the user to confirm the deletion, true by default",
372
+ required: false
373
+ }
374
+ ]
375
+ },
376
+ handler: {
377
+ execute: async (context) => {
378
+ const workspaceDir = await workspaceService.getWorkspace();
379
+ if (!workspaceDir) {
380
+ toastError("No workspace selected.");
381
+ return;
382
+ }
383
+ const path = context.params?.path;
384
+ let resource = null;
385
+ if (path) {
386
+ resource = await workspaceDir.getResource(path);
387
+ }
388
+ if (!resource) {
389
+ resource = activeSelectionSignal.get();
390
+ }
391
+ if (!resource) {
392
+ toastError("No resource to delete provided!");
393
+ return;
394
+ }
395
+ const resourcePath = resource.getWorkspacePath();
396
+ const confirmParam = context.params && context.params["confirm"];
397
+ let yes = true;
398
+ if (confirmParam === void 0 || confirmParam === true) {
399
+ yes = await confirmDialog(`Are you sure you want to delete ${resourcePath}?`);
400
+ }
401
+ if (!yes) {
402
+ return;
403
+ }
404
+ try {
405
+ await resource.delete();
406
+ toastInfo("Resource deleted: " + resourcePath);
407
+ } catch (err) {
408
+ toastError(
409
+ `Resource ${resourcePath} could not be deleted: ${err.message ?? err}`
410
+ );
411
+ }
412
+ }
413
+ }
414
+ });
415
+ const t = i18nLazy("extensions");
416
+ function isResource(obj) {
417
+ return obj instanceof File || obj instanceof Directory;
418
+ }
419
+ const disabled = () => !isResource(activeSelectionSignal.get());
420
+ contributionRegistry.registerContribution("toolbar:filebrowser", {
421
+ command: "mv",
422
+ icon: "pen",
423
+ label: t("RENAME"),
424
+ disabled
425
+ });
426
+ contributionRegistry.registerContribution("toolbar:filebrowser", {
427
+ command: "rm",
428
+ icon: "trash",
429
+ label: t("DELETE"),
430
+ disabled
431
+ });
432
+ contributionRegistry.registerContribution("contextmenu:filebrowser", {
433
+ command: "mv",
434
+ icon: "pen",
435
+ label: t("RENAME"),
436
+ disabled
437
+ });
438
+ contributionRegistry.registerContribution("contextmenu:filebrowser", {
439
+ command: "rm",
440
+ icon: "trash",
441
+ label: t("DELETE"),
442
+ disabled
443
+ });
444
+ registerAll({
445
+ command: {
446
+ id: "head",
447
+ name: "Head - Show first lines",
448
+ description: "Shows the first N lines of a file",
449
+ parameters: [
450
+ {
451
+ name: "path",
452
+ description: "the path of the file to read",
453
+ required: true
454
+ },
455
+ {
456
+ name: "lines",
457
+ description: "number of lines to show from the beginning (default: 10)",
458
+ type: "number",
459
+ required: false
460
+ }
461
+ ],
462
+ output: [
463
+ {
464
+ name: "content",
465
+ description: "the first N lines of the file"
466
+ }
467
+ ]
468
+ },
469
+ handler: {
470
+ execute: async ({ params }) => {
471
+ const path = params?.path;
472
+ if (!path) {
473
+ toastError("No file path provided.");
474
+ return;
475
+ }
476
+ const file = await getTextFileFromPath(path);
477
+ if (!file) {
478
+ return;
479
+ }
480
+ const numLines = params?.lines ? parseInt(params.lines, 10) : 10;
481
+ if (Number.isNaN(numLines) || numLines < 1) {
482
+ toastError("Number of lines must be a positive integer");
483
+ return;
484
+ }
485
+ const contents = await readTextFile(file);
486
+ if (!contents) {
487
+ return;
488
+ }
489
+ const lines = contents.split("\n");
490
+ return lines.slice(0, numLines).join("\n");
491
+ }
492
+ }
493
+ });
494
+ registerAll({
495
+ command: {
496
+ id: "tail",
497
+ name: "Tail - Show last lines",
498
+ description: "Shows the last N lines of a file",
499
+ parameters: [
500
+ {
501
+ name: "path",
502
+ description: "the path of the file to read",
503
+ required: true
504
+ },
505
+ {
506
+ name: "lines",
507
+ description: "number of lines to show from the end (default: 10)",
508
+ type: "number",
509
+ required: false
510
+ }
511
+ ],
512
+ output: [
513
+ {
514
+ name: "content",
515
+ description: "the last N lines of the file"
516
+ }
517
+ ]
518
+ },
519
+ handler: {
520
+ execute: async ({ params }) => {
521
+ const path = params?.path;
522
+ if (!path) {
523
+ toastError("No file path provided.");
524
+ return;
525
+ }
526
+ const file = await getTextFileFromPath(path);
527
+ if (!file) {
528
+ return;
529
+ }
530
+ const numLines = params?.lines ? parseInt(params.lines, 10) : 10;
531
+ if (Number.isNaN(numLines) || numLines < 1) {
532
+ toastError("Number of lines must be a positive integer");
533
+ return;
534
+ }
535
+ const contents = await readTextFile(file);
536
+ if (!contents) {
537
+ return;
538
+ }
539
+ const lines = contents.split("\n");
540
+ return lines.slice(-numLines).join("\n");
541
+ }
542
+ }
543
+ });
544
+ registerAll({
545
+ command: {
546
+ id: "cat",
547
+ name: "Cat - Show file contents",
548
+ description: "Shows the complete contents of a file",
549
+ parameters: [
550
+ {
551
+ name: "path",
552
+ description: "the path of the file to read",
553
+ required: true
554
+ }
555
+ ],
556
+ output: [
557
+ {
558
+ name: "content",
559
+ description: "the complete contents of the file"
560
+ }
561
+ ]
562
+ },
563
+ handler: {
564
+ execute: async ({ params }) => {
565
+ const path = params?.path;
566
+ if (!path) {
567
+ toastError("No file path provided.");
568
+ return;
569
+ }
570
+ const file = await getTextFileFromPath(path);
571
+ if (!file) {
572
+ return;
573
+ }
574
+ return readTextFile(file);
575
+ }
576
+ }
577
+ });
578
+ registerAll({
579
+ command: {
580
+ id: "exists",
581
+ name: "Exists",
582
+ description: "Checks if a file exists at the given path (like bash test -f)",
583
+ parameters: [
584
+ {
585
+ name: "path",
586
+ description: "Path of the file to check, relative to the workspace",
587
+ required: true
588
+ }
589
+ ],
590
+ output: [
591
+ {
592
+ name: "exists",
593
+ description: "true if the file exists, false otherwise"
594
+ }
595
+ ]
596
+ },
597
+ handler: {
598
+ execute: async ({ params }) => {
599
+ const workspace = await workspaceService.getWorkspace();
600
+ if (!workspace) return false;
601
+ const path = params?.path;
602
+ if (!path) return false;
603
+ try {
604
+ const resource = await workspace.getResource(path);
605
+ return resource instanceof File;
606
+ } catch {
607
+ return false;
608
+ }
609
+ }
610
+ }
611
+ });
612
+ registerAll({
613
+ command: {
614
+ id: "wc",
615
+ name: "Word count",
616
+ description: "Counts lines, words, and characters in a file",
617
+ parameters: [
618
+ {
619
+ name: "path",
620
+ description: "the path of the file to analyze",
621
+ required: true
622
+ }
623
+ ],
624
+ output: [
625
+ {
626
+ name: "lines",
627
+ description: "number of lines in the file"
628
+ },
629
+ {
630
+ name: "words",
631
+ description: "number of words in the file"
632
+ },
633
+ {
634
+ name: "characters",
635
+ description: "number of characters in the file"
636
+ }
637
+ ]
638
+ },
639
+ handler: {
640
+ execute: async ({ params }) => {
641
+ const path = params?.path;
642
+ if (!path) {
643
+ toastError("No file path provided.");
644
+ return;
645
+ }
646
+ const file = await getTextFileFromPath(path);
647
+ if (!file) {
648
+ return;
649
+ }
650
+ const contents = await readTextFile(file);
651
+ if (!contents) {
652
+ return;
653
+ }
654
+ const lines = contents.split("\n");
655
+ const lineCount = lines.length;
656
+ const trimmed = contents.trim();
657
+ const wordCount = trimmed === "" ? 0 : trimmed.split(/\s+/).filter((w) => w.length > 0).length;
658
+ const charCount = contents.length;
659
+ return {
660
+ lines: lineCount,
661
+ words: wordCount,
662
+ characters: charCount
663
+ };
664
+ }
665
+ }
666
+ });
667
+ registerAll({
668
+ command: {
669
+ id: "unzip",
670
+ name: "Unzip Archive",
671
+ description: "Extract a zip archive from the workspace",
672
+ parameters: [
673
+ {
674
+ name: "file",
675
+ description: "the zip file to extract, if not provided, the current selection will be used",
676
+ required: false
677
+ },
678
+ {
679
+ name: "target",
680
+ description: "target folder to extract into, defaults to the zip filename without extension",
681
+ required: false
682
+ }
683
+ ]
684
+ },
685
+ handler: {
686
+ canExecute: (context) => {
687
+ let filePath = context.params && context.params["file"];
688
+ if (!filePath) {
689
+ const selectedItem = activeSelectionSignal.get();
690
+ if (!selectedItem || !("path" in selectedItem)) {
691
+ return false;
692
+ }
693
+ filePath = selectedItem.path;
694
+ }
695
+ return filePath.toLowerCase().endsWith(".zip");
696
+ },
697
+ execute: async (context) => {
698
+ let filePath = context.params && context.params["file"];
699
+ if (!filePath) {
700
+ const selectedItem = activeSelectionSignal.get();
701
+ filePath = selectedItem.path;
702
+ }
703
+ const workspaceDir = await workspaceService.getWorkspace();
704
+ if (!workspaceDir) {
705
+ toastError("No workspace selected.");
706
+ return;
707
+ }
708
+ await taskService.runAsync("Extracting archive", async (progress) => {
709
+ try {
710
+ const fileResource = await workspaceDir.getResource(filePath);
711
+ if (!fileResource) {
712
+ toastError("File not found: " + filePath);
713
+ return;
714
+ }
715
+ let targetFolder = context.params && context.params["target"];
716
+ if (!targetFolder) {
717
+ const fileName = filePath.split("/").pop() || "extracted";
718
+ targetFolder = fileName.replace(/\.zip$/i, "") + "/";
719
+ }
720
+ progress.message = "Loading archive...";
721
+ progress.progress = 0;
722
+ await workspaceDir.getResource(targetFolder, { create: true });
723
+ const file = fileResource;
724
+ const blob = await file.getContents({ blob: true });
725
+ const zip = await JSZip.loadAsync(blob);
726
+ const totalFiles = Object.values(zip.files).filter((entry) => !entry.dir).length;
727
+ let extractedCount = 0;
728
+ progress.message = `Extracting to ${targetFolder.replace(/\/$/, "")}...`;
729
+ for (const [relativePath, zipEntry] of Object.entries(zip.files)) {
730
+ if (zipEntry.dir) {
731
+ continue;
732
+ }
733
+ const entryBlob = await zipEntry.async("blob");
734
+ const fullPath = `${targetFolder}${relativePath}`;
735
+ const entryResource = await workspaceDir.getResource(fullPath, { create: true });
736
+ const newFile = entryResource;
737
+ await newFile.saveContents(entryBlob, {
738
+ contentType: FileContentType.BINARY
739
+ });
740
+ extractedCount++;
741
+ progress.progress = Math.round(extractedCount / totalFiles * 100);
742
+ progress.message = `Extracting ${extractedCount}/${totalFiles} files...`;
743
+ }
744
+ progress.progress = 100;
745
+ toastInfo(`Archive extracted to ${targetFolder.replace(/\/$/, "")}: ${extractedCount} file(s)`);
746
+ } catch (err) {
747
+ toastError("Failed to extract archive: " + err);
748
+ throw err;
749
+ }
750
+ });
751
+ }
752
+ }
753
+ });
754
+ registerAll({
755
+ command: {
756
+ id: "p12split",
757
+ name: ".p12 file splitter",
758
+ description: "Splits a .p12 file into private/public and additional .pem files",
759
+ parameters: [
760
+ {
761
+ name: "p12_path",
762
+ description: "Path of the .p12 file to split",
763
+ required: true
764
+ },
765
+ {
766
+ name: "password",
767
+ description: "The password of the .p12 file, will prompt for input if not specified, use empty string for no password",
768
+ required: false
769
+ },
770
+ {
771
+ name: "output_path",
772
+ description: "Directory path of the files to write to, if not provided, will be parent directory of p12_path",
773
+ required: false
774
+ }
775
+ ]
776
+ },
777
+ handler: {
778
+ execute: async ({ params: { p12_path, password, output_path } }) => {
779
+ const workspace = await workspaceService.getWorkspace();
780
+ if (!workspace) {
781
+ toastError("No Workspace selected!");
782
+ return;
783
+ }
784
+ await taskService.runAsync("Splitting .p12 certificate file", async () => {
785
+ const pyEnv = new PyEnv();
786
+ await pyEnv.init(workspace);
787
+ await pyEnv.loadPackages(["cryptography"]);
788
+ const pyModule = await import("./p12splitter--4Q2vYnp.js");
789
+ const pyScript = pyModule.default ?? pyModule;
790
+ await pyEnv.execCode(pyScript);
791
+ await pyEnv.runFunction("p12splitter", {
792
+ p12_path,
793
+ password: password === '""' ? void 0 : password,
794
+ output_path: output_path === '""' ? "" : output_path
795
+ });
796
+ toastInfo(".p12 file successfully splitted");
797
+ });
798
+ }
799
+ }
800
+ });
801
+ async function getScriptUrl(params) {
802
+ if (params.code?.trim()) {
803
+ return URL.createObjectURL(new Blob([params.code], { type: "application/javascript" }));
804
+ }
805
+ if (!params.script) {
806
+ toastError("Provide 'script' (file path) or 'code'.");
807
+ return null;
808
+ }
809
+ const workspace = await workspaceService.getWorkspace();
810
+ if (!workspace) {
811
+ toastError("No workspace selected.");
812
+ return null;
813
+ }
814
+ const file = await getTextFileFromPath(params.script);
815
+ if (!file) return null;
816
+ const uri = await file.getContents({ uri: true }).catch(() => null);
817
+ if (typeof uri === "string" && uri.startsWith("blob:")) return uri;
818
+ const content = await readTextFile(file);
819
+ return content ? URL.createObjectURL(new Blob([content], { type: "application/javascript" })) : null;
820
+ }
821
+ function runWorker(url) {
822
+ const worker = new Worker(url);
823
+ const cleanup = () => {
824
+ worker.terminate();
825
+ URL.revokeObjectURL(url);
826
+ };
827
+ return new Promise((resolve, reject) => {
828
+ worker.onmessage = (e) => {
829
+ cleanup();
830
+ resolve(e.data);
831
+ };
832
+ worker.onerror = (e) => {
833
+ cleanup();
834
+ reject(new Error(e.message ?? String(e)));
835
+ };
836
+ });
837
+ }
838
+ registerAll({
839
+ command: {
840
+ id: "js",
841
+ name: "Run JavaScript file",
842
+ description: "Runs a script in a Web Worker. Use self.postMessage(value) to return a result.",
843
+ parameters: [
844
+ { name: "script", description: "workspace path to a .js file", required: false },
845
+ { name: "code", description: "inline JavaScript", required: false }
846
+ ]
847
+ },
848
+ handler: {
849
+ execute: async (context) => {
850
+ const url = await getScriptUrl(context.params ?? {});
851
+ if (!url) return;
852
+ try {
853
+ const result = await runWorker(url);
854
+ if (result !== void 0) toastInfo(String(result));
855
+ return result;
856
+ } catch (err) {
857
+ toastError(err?.message ?? String(err));
858
+ }
859
+ }
860
+ }
861
+ });
862
+ //# sourceMappingURL=index-Bm7Xxv-I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-Bm7Xxv-I.js","sources":["../src/commands/wget.ts","../src/shared.ts","../src/commands/ls.ts","../src/commands/touch.ts","../src/commands/mv.ts","../src/commands/rm.ts","../src/commands/filebrowser-contributions.ts","../src/commands/head.ts","../src/commands/tail.ts","../src/commands/cat.ts","../src/commands/exists.ts","../src/commands/wc.ts","../src/commands/unzip.ts","../src/commands/p12split.ts","../src/commands/js.ts"],"sourcesContent":["import { File, FileContentType, workspaceService, taskService, toastError, toastInfo, registerAll } from \"@eclipse-lyra/core\";\n\nregisterAll({\n command: {\n id: \"wget\",\n name: \"wget\",\n description: \"Download a file from a URL to the workspace\",\n parameters: [\n {\n name: \"url\",\n description: \"the URL of the file to download\",\n required: true\n },\n {\n name: \"filename\",\n description: \"optional filename to save as (will be auto-detected if not provided)\",\n required: false\n }\n ]\n },\n handler: {\n canExecute: (context: any) => {\n const url = context.params && context.params[\"url\"];\n if (!url) {\n return false;\n }\n return url.startsWith(\"http://\") || url.startsWith(\"https://\");\n },\n execute: async (context: any) => {\n const url = context.params && context.params[\"url\"];\n\n if (!url) {\n toastError(\"No URL provided.\");\n return;\n }\n\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return;\n }\n\n const folders = await workspaceService.getFolders();\n const targetFolderName = folders.length > 0 ? folders[0].name : null;\n\n await taskService.runAsync(\"Downloading file\", async (progress: any) => {\n progress.message = \"Starting download...\";\n progress.progress = 0;\n\n try {\n const response = await fetch(url, {\n mode: \"cors\",\n credentials: \"omit\"\n });\n\n if (!response.ok) {\n toastError(\"Failed to download file: \" + response.statusText);\n return;\n }\n\n let fileName = context.params && context.params[\"filename\"];\n\n if (!fileName) {\n const contentDisposition = response.headers.get(\"content-disposition\");\n if (contentDisposition) {\n let filenameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/);\n if (filenameMatch && filenameMatch[1]) {\n fileName = filenameMatch[1];\n } else {\n filenameMatch = contentDisposition.match(/filename=([^;]+)/);\n if (filenameMatch && filenameMatch[1]) {\n fileName = filenameMatch[1].trim();\n }\n }\n }\n\n if (!fileName) {\n const urlSegments = new URL(url).pathname.split(\"/\").filter(s => s.length > 0);\n const lastSegment = urlSegments[urlSegments.length - 1];\n if (lastSegment && lastSegment.includes(\".\")) {\n fileName = lastSegment;\n } else {\n const now = new Date().toISOString().replace(/[:.]/g, \"-\").replace(\"T\", \"_\").slice(0, -5);\n fileName = `downloaded-file-${now}`;\n }\n }\n }\n\n const targetPath = targetFolderName ? `${targetFolderName}/${fileName}` : fileName;\n const downloadedFile = await workspaceDir.getResource(targetPath, { create: true }) as File;\n\n progress.message = `Downloading ${fileName}...`;\n progress.progress = 50;\n\n await downloadedFile.saveContents(response.body, {\n contentType: FileContentType.BINARY\n });\n\n progress.progress = 100;\n toastInfo(`File downloaded: ${fileName}`);\n } catch (err) {\n toastError(\"Failed to download file: \" + err);\n throw err;\n }\n });\n }\n }\n});\n\n","import { File, Directory, workspaceService, toastError } from \"@eclipse-lyra/core\";\n\nexport async function getTextFileFromPath(path: string): Promise<File | null> {\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return null;\n }\n\n try {\n const resource = await workspaceDir.getResource(path);\n if (!resource || !(resource instanceof File)) {\n toastError(\"File not found: \" + path);\n return null;\n }\n return resource;\n } catch (err: any) {\n toastError(`Failed to access file: ${err.message ?? err}`);\n return null;\n }\n}\n\nexport async function readTextFile(file: File): Promise<string | null> {\n try {\n const contents = await file.getContents();\n if (typeof contents !== \"string\") {\n toastError(\"File is not a text file\");\n return null;\n }\n return contents;\n } catch (err: any) {\n toastError(`Failed to read file: ${err.message ?? err}`);\n return null;\n }\n}\n\nexport async function collectFilesRecursive(directory: Directory): Promise<string[]> {\n const files: string[] = [];\n const children = await directory.listChildren(true);\n\n for (const child of children) {\n if (child instanceof File) {\n files.push(child.getWorkspacePath());\n } else if (child instanceof Directory) {\n const subFiles = await collectFilesRecursive(child);\n files.push(...subFiles);\n }\n }\n\n return files;\n}\n\n","import { File, Directory, workspaceService, toastError, registerAll } from \"@eclipse-lyra/core\";\nimport { collectFilesRecursive } from \"../shared\";\n\nregisterAll({\n command: {\n id: \"ls\",\n name: \"List files\",\n description:\n \"Lists files from a directory. If recursive is provided, it traverses from the provided directory down to all leaves. If no directory is provided, it will traverse from the workspace root.\",\n parameters: [\n {\n name: \"path\",\n description:\n \"the path of the directory to list, relative to the workspace. If not provided, uses workspace root\",\n required: false\n },\n {\n name: \"recursive\",\n description: \"whether to recursively traverse all subdirectories\",\n type: \"boolean\",\n required: false\n }\n ],\n output: [\n {\n name: \"files\",\n description: \"array of file objects with path and size information\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) {\n toastError(\"No workspace available\");\n return [];\n }\n\n const path = params?.path as string | undefined;\n const recursive =\n params?.recursive === true || params?.recursive === \"true\";\n\n try {\n let targetDir: Directory = workspace;\n\n if (path) {\n const resource = await workspace.getResource(path);\n if (!resource) {\n toastError(`Path not found: ${path}`);\n return [];\n }\n if (!(resource instanceof Directory)) {\n toastError(`Path is not a directory: ${path}`);\n return [];\n }\n targetDir = resource;\n }\n\n if (recursive) {\n const files = await collectFilesRecursive(targetDir);\n const result: Array<{ path: string; size: number | null }> = [];\n for (const filePath of files) {\n const file = await workspace.getResource(filePath);\n if (file instanceof File) {\n const size = await file.size();\n result.push({\n path: filePath,\n size\n });\n }\n }\n return result;\n }\n\n const children = await targetDir.listChildren(true);\n const result: Array<{ path: string; size: number | null }> = [];\n for (const child of children) {\n if (child instanceof File) {\n const size = await child.size();\n result.push({\n path: child.getWorkspacePath(),\n size\n });\n }\n }\n return result;\n } catch (err: any) {\n toastError(`Failed to list files: ${err.message ?? err}`);\n return [];\n }\n }\n }\n});\n\n","import { File, Directory, workspaceService, activeSelectionSignal, promptDialog, confirmDialog, toastError, toastInfo, registerAll } from \"@eclipse-lyra/core\";\n\nregisterAll({\n command: {\n id: \"touch\",\n name: \"Touch - Create new file\",\n description: \"Creates a new file within the workspace. For .geospace map files, use create_map_file instead.\",\n parameters: [\n {\n name: \"path\",\n description: \"the path including name of the file to be created, must be relative to the workspace\",\n required: false\n },\n {\n name: \"contents\",\n description: \"the textual contents of the file\",\n required: false\n },\n {\n name: \"ask\",\n description: \"whether to prompt the user for the file path\",\n required: false\n },\n {\n name: \"extension\",\n description: \"required file extension (e.g., '.geospace'), will be appended if missing\",\n required: false\n }\n ],\n output: [\n {\n name: \"path\",\n description: \"the path of the created file\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n let path = params?.path as string | undefined | null;\n const contents = params?.contents as string | undefined;\n const ask = params?.ask;\n const extension = params?.extension as string | undefined;\n\n if (ask || !path) {\n path = await promptDialog(\n \"Enter path to new file (directories will be created if not exist):\",\n path || \"\"\n );\n if (!path) {\n return;\n }\n }\n\n if (extension && path && !path.endsWith(extension)) {\n path += extension;\n }\n\n if (path) {\n const selection = activeSelectionSignal.get();\n const dirPath =\n selection instanceof Directory\n ? selection.getWorkspacePath()\n : selection instanceof File\n ? selection.getParent()?.getWorkspacePath()\n : undefined;\n if (dirPath && !path.startsWith(dirPath + \"/\")) path = dirPath + \"/\" + path;\n }\n\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return;\n }\n\n const existingResource = await workspaceDir.getResource(path);\n if (existingResource) {\n const overwrite = await confirmDialog(\n `File \"${path}\" already exists. Do you want to overwrite it?`\n );\n if (!overwrite) {\n return;\n }\n }\n\n const createdResource = await workspaceDir.getResource(path, { create: true });\n if (!createdResource) {\n toastError(\"Could not create file: \" + path);\n return;\n }\n\n if (contents) {\n await (createdResource as File).saveContents(contents);\n }\n\n toastInfo(`File created: ${path}`);\n return path;\n }\n }\n});\n\n","import { workspaceService, activeSelectionSignal, promptDialog, toastError, toastInfo, registerAll } from \"@eclipse-lyra/core\";\n\nregisterAll({\n command: {\n id: \"mv\",\n name: \"mv - Rename a resource (file or directory)\",\n description: \"Renames a resource (file or directory)\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the resource within the workspace to rename or the currently active selection\",\n required: false\n },\n {\n name: \"newName\",\n description: \"the new name for the resource\",\n required: false\n }\n ]\n },\n handler: {\n execute: async (context: any) => {\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return;\n }\n\n const path = context.params?.path as string | undefined;\n let resource: any = null;\n\n if (path) {\n resource = await workspaceDir.getResource(path);\n }\n\n if (!resource) {\n resource = activeSelectionSignal.get();\n }\n\n if (!resource) {\n toastError(\"No resource to rename provided!\");\n return;\n }\n\n const currentName = resource.getName();\n const newName =\n context.params?.newName ??\n (await promptDialog(`Enter new name for \"${currentName}\":`, currentName));\n\n if (!newName || newName === currentName) {\n return;\n }\n\n try {\n await resource.rename(newName);\n toastInfo(`Resource renamed to: ${newName}`);\n } catch (err: any) {\n toastError(`Failed to rename ${currentName}: ${err.message ?? err}`);\n }\n }\n }\n});\n\n","import { workspaceService, activeSelectionSignal, confirmDialog, toastError, toastInfo, registerAll } from \"@eclipse-lyra/core\";\n\nregisterAll({\n command: {\n id: \"rm\",\n name: \"rm - Delete a resource (file or directory)\",\n description: \"Deletes a resource (file or directory)\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the resource within the workspace to delete or the currently active selection\",\n required: false\n },\n {\n name: \"confirm\",\n description: \"whether to ask the user to confirm the deletion, true by default\",\n required: false\n }\n ]\n },\n handler: {\n execute: async (context: any) => {\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return;\n }\n\n const path = context.params?.path as string | undefined;\n let resource: any = null;\n\n if (path) {\n resource = await workspaceDir.getResource(path);\n }\n\n if (!resource) {\n resource = activeSelectionSignal.get();\n }\n\n if (!resource) {\n toastError(\"No resource to delete provided!\");\n return;\n }\n\n const resourcePath = resource.getWorkspacePath();\n const confirmParam = context.params && context.params[\"confirm\"];\n let yes = true;\n if (confirmParam === undefined || confirmParam === true) {\n yes = await confirmDialog(`Are you sure you want to delete ${resourcePath}?`);\n }\n\n if (!yes) {\n return;\n }\n\n try {\n await resource.delete();\n toastInfo(\"Resource deleted: \" + resourcePath);\n } catch (err: any) {\n toastError(\n `Resource ${resourcePath} could not be deleted: ${err.message ?? err}`\n );\n }\n }\n }\n});\n\n","import {\n contributionRegistry,\n activeSelectionSignal,\n File,\n Directory,\n i18nLazy,\n} from \"@eclipse-lyra/core\";\n\nconst t = i18nLazy(\"extensions\");\n\nfunction isResource(obj: unknown): obj is File | Directory {\n return obj instanceof File || obj instanceof Directory;\n}\n\nconst disabled = () => !isResource(activeSelectionSignal.get());\n\ncontributionRegistry.registerContribution(\"toolbar:filebrowser\", {\n command: \"mv\",\n icon: \"pen\",\n label: t(\"RENAME\") as unknown as string,\n disabled,\n});\ncontributionRegistry.registerContribution(\"toolbar:filebrowser\", {\n command: \"rm\",\n icon: \"trash\",\n label: t(\"DELETE\") as unknown as string,\n disabled,\n});\ncontributionRegistry.registerContribution(\"contextmenu:filebrowser\", {\n command: \"mv\",\n icon: \"pen\",\n label: t(\"RENAME\") as unknown as string,\n disabled,\n});\ncontributionRegistry.registerContribution(\"contextmenu:filebrowser\", {\n command: \"rm\",\n icon: \"trash\",\n label: t(\"DELETE\") as unknown as string,\n disabled,\n});\n","import { registerAll, toastError } from \"@eclipse-lyra/core\";\nimport { getTextFileFromPath, readTextFile } from \"../shared\";\n\nregisterAll({\n command: {\n id: \"head\",\n name: \"Head - Show first lines\",\n description: \"Shows the first N lines of a file\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the file to read\",\n required: true\n },\n {\n name: \"lines\",\n description: \"number of lines to show from the beginning (default: 10)\",\n type: \"number\",\n required: false\n }\n ],\n output: [\n {\n name: \"content\",\n description: \"the first N lines of the file\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const path = params?.path;\n if (!path) {\n toastError(\"No file path provided.\");\n return;\n }\n\n const file = await getTextFileFromPath(path);\n if (!file) {\n return;\n }\n\n const numLines = params?.lines ? parseInt(params.lines, 10) : 10;\n if (Number.isNaN(numLines) || numLines < 1) {\n toastError(\"Number of lines must be a positive integer\");\n return;\n }\n\n const contents = await readTextFile(file);\n if (!contents) {\n return;\n }\n\n const lines = contents.split(\"\\n\");\n return lines.slice(0, numLines).join(\"\\n\");\n }\n }\n});\n\n","import { registerAll, toastError } from \"@eclipse-lyra/core\";\nimport { getTextFileFromPath, readTextFile } from \"../shared\";\n\nregisterAll({\n command: {\n id: \"tail\",\n name: \"Tail - Show last lines\",\n description: \"Shows the last N lines of a file\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the file to read\",\n required: true\n },\n {\n name: \"lines\",\n description: \"number of lines to show from the end (default: 10)\",\n type: \"number\",\n required: false\n }\n ],\n output: [\n {\n name: \"content\",\n description: \"the last N lines of the file\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const path = params?.path;\n if (!path) {\n toastError(\"No file path provided.\");\n return;\n }\n\n const file = await getTextFileFromPath(path);\n if (!file) {\n return;\n }\n\n const numLines = params?.lines ? parseInt(params.lines, 10) : 10;\n if (Number.isNaN(numLines) || numLines < 1) {\n toastError(\"Number of lines must be a positive integer\");\n return;\n }\n\n const contents = await readTextFile(file);\n if (!contents) {\n return;\n }\n\n const lines = contents.split(\"\\n\");\n return lines.slice(-numLines).join(\"\\n\");\n }\n }\n});\n\n","import { registerAll, toastError } from \"@eclipse-lyra/core\";\nimport { getTextFileFromPath, readTextFile } from \"../shared\";\n\nregisterAll({\n command: {\n id: \"cat\",\n name: \"Cat - Show file contents\",\n description: \"Shows the complete contents of a file\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the file to read\",\n required: true\n }\n ],\n output: [\n {\n name: \"content\",\n description: \"the complete contents of the file\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const path = params?.path;\n if (!path) {\n toastError(\"No file path provided.\");\n return;\n }\n\n const file = await getTextFileFromPath(path);\n if (!file) {\n return;\n }\n\n return readTextFile(file);\n }\n }\n});\n\n","import { File, workspaceService, registerAll } from \"@eclipse-lyra/core\";\n\nregisterAll({\n command: {\n id: \"exists\",\n name: \"Exists\",\n description: \"Checks if a file exists at the given path (like bash test -f)\",\n parameters: [\n {\n name: \"path\",\n description: \"Path of the file to check, relative to the workspace\",\n required: true\n }\n ],\n output: [\n {\n name: \"exists\",\n description: \"true if the file exists, false otherwise\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) return false;\n\n const path = params?.path;\n if (!path) return false;\n\n try {\n const resource = await workspace.getResource(path);\n return resource instanceof File;\n } catch {\n return false;\n }\n }\n }\n});\n","import { registerAll, toastError } from \"@eclipse-lyra/core\";\nimport { getTextFileFromPath, readTextFile } from \"../shared\";\n\nregisterAll({\n command: {\n id: \"wc\",\n name: \"Word count\",\n description: \"Counts lines, words, and characters in a file\",\n parameters: [\n {\n name: \"path\",\n description: \"the path of the file to analyze\",\n required: true\n }\n ],\n output: [\n {\n name: \"lines\",\n description: \"number of lines in the file\"\n },\n {\n name: \"words\",\n description: \"number of words in the file\"\n },\n {\n name: \"characters\",\n description: \"number of characters in the file\"\n }\n ]\n },\n handler: {\n execute: async ({ params }: any) => {\n const path = params?.path;\n if (!path) {\n toastError(\"No file path provided.\");\n return;\n }\n\n const file = await getTextFileFromPath(path);\n if (!file) {\n return;\n }\n\n const contents = await readTextFile(file);\n if (!contents) {\n return;\n }\n\n const lines = contents.split(\"\\n\");\n const lineCount = lines.length;\n const trimmed = contents.trim();\n const wordCount = trimmed === \"\" ? 0 : trimmed.split(/\\s+/).filter(w => w.length > 0).length;\n const charCount = contents.length;\n\n return {\n lines: lineCount,\n words: wordCount,\n characters: charCount\n };\n }\n }\n});\n\n","import {\n File,\n FileContentType,\n workspaceService,\n taskService,\n activeSelectionSignal,\n TOOLBAR_MAIN,\n registerAll,\n toastError,\n toastInfo,\n type CommandContribution\n} from \"@eclipse-lyra/core\";\nimport JSZip from \"jszip\";\n\nregisterAll({\n command: {\n id: \"unzip\",\n name: \"Unzip Archive\",\n description: \"Extract a zip archive from the workspace\",\n parameters: [\n {\n name: \"file\",\n description: \"the zip file to extract, if not provided, the current selection will be used\",\n required: false\n },\n {\n name: \"target\",\n description: \"target folder to extract into, defaults to the zip filename without extension\",\n required: false\n }\n ]\n },\n handler: {\n canExecute: (context: any) => {\n let filePath: string = context.params && context.params[\"file\"];\n\n if (!filePath) {\n const selectedItem = activeSelectionSignal.get();\n if (!selectedItem || !(\"path\" in selectedItem)) {\n return false;\n }\n filePath = (selectedItem as any).path;\n }\n\n return filePath.toLowerCase().endsWith(\".zip\");\n },\n execute: async (context: any) => {\n let filePath: string = context.params && context.params[\"file\"];\n\n if (!filePath) {\n const selectedItem = activeSelectionSignal.get();\n filePath = (selectedItem as any).path;\n }\n\n const workspaceDir = await workspaceService.getWorkspace();\n if (!workspaceDir) {\n toastError(\"No workspace selected.\");\n return;\n }\n\n await taskService.runAsync(\"Extracting archive\", async (progress: any) => {\n try {\n const fileResource = await workspaceDir.getResource(filePath);\n if (!fileResource) {\n toastError(\"File not found: \" + filePath);\n return;\n }\n\n let targetFolder = context.params && context.params[\"target\"];\n if (!targetFolder) {\n const fileName = filePath.split(\"/\").pop() || \"extracted\";\n targetFolder = fileName.replace(/\\.zip$/i, \"\") + \"/\";\n }\n\n progress.message = \"Loading archive...\";\n progress.progress = 0;\n\n await workspaceDir.getResource(targetFolder, { create: true });\n\n const file = fileResource as File;\n const blob = await file.getContents({ blob: true });\n\n const zip = await JSZip.loadAsync(blob);\n const totalFiles = Object.values(zip.files).filter(entry => !entry.dir).length;\n let extractedCount = 0;\n\n progress.message = `Extracting to ${targetFolder.replace(/\\/$/, \"\")}...`;\n\n for (const [relativePath, zipEntry] of Object.entries(zip.files)) {\n if (zipEntry.dir) {\n continue;\n }\n\n const entryBlob = await zipEntry.async(\"blob\");\n\n const fullPath = `${targetFolder}${relativePath}`;\n const entryResource = await workspaceDir.getResource(fullPath, { create: true });\n const newFile = entryResource as File;\n await newFile.saveContents(entryBlob, {\n contentType: FileContentType.BINARY\n });\n extractedCount++;\n\n progress.progress = Math.round((extractedCount / totalFiles) * 100);\n progress.message = `Extracting ${extractedCount}/${totalFiles} files...`;\n }\n\n progress.progress = 100;\n toastInfo(`Archive extracted to ${targetFolder.replace(/\\/$/, \"\")}: ${extractedCount} file(s)`);\n } catch (err: any) {\n toastError(\"Failed to extract archive: \" + err);\n throw err;\n }\n });\n }\n }\n});\n\n","import { workspaceService, taskService, toastError, toastInfo, registerAll } from \"@eclipse-lyra/core\";\nimport { PyEnv } from \"@eclipse-lyra/extension-python-runtime/api\";\n\nregisterAll({\n command: {\n id: \"p12split\",\n name: \".p12 file splitter\",\n description: \"Splits a .p12 file into private/public and additional .pem files\",\n parameters: [\n {\n name: \"p12_path\",\n description: \"Path of the .p12 file to split\",\n required: true\n },\n {\n name: \"password\",\n description:\n \"The password of the .p12 file, will prompt for input if not specified, use empty string for no password\",\n required: false\n },\n {\n name: \"output_path\",\n description:\n \"Directory path of the files to write to, if not provided, will be parent directory of p12_path\",\n required: false\n }\n ]\n },\n handler: {\n execute: async ({ params: { p12_path, password, output_path } }: any) => {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) {\n toastError(\"No Workspace selected!\");\n return;\n }\n\n await taskService.runAsync(\"Splitting .p12 certificate file\", async () => {\n const pyEnv = new PyEnv();\n await pyEnv.init(workspace);\n await pyEnv.loadPackages([\"cryptography\"]);\n const pyModule = await import(\"../p12splitter.py?raw\");\n const pyScript = (pyModule as any).default ?? pyModule;\n await pyEnv.execCode(pyScript as string);\n await pyEnv.runFunction(\"p12splitter\", {\n p12_path,\n password: password === '\"\"' ? undefined : password,\n output_path: output_path === '\"\"' ? \"\" : output_path\n });\n toastInfo(\".p12 file successfully splitted\");\n });\n }\n }\n});\n\n","import {\n registerAll,\n commandRegistry,\n workspaceService,\n toastError,\n toastInfo,\n} from \"@eclipse-lyra/core\";\nimport { getTextFileFromPath, readTextFile } from \"../shared\";\n\nasync function getScriptUrl(params: { script?: string; code?: string }): Promise<string | null> {\n if (params.code?.trim()) {\n return URL.createObjectURL(new Blob([params.code], { type: \"application/javascript\" }));\n }\n if (!params.script) {\n toastError(\"Provide 'script' (file path) or 'code'.\");\n return null;\n }\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) {\n toastError(\"No workspace selected.\");\n return null;\n }\n const file = await getTextFileFromPath(params.script);\n if (!file) return null;\n const uri = await file.getContents({ uri: true }).catch(() => null);\n if (typeof uri === \"string\" && uri.startsWith(\"blob:\")) return uri;\n const content = await readTextFile(file);\n return content ? URL.createObjectURL(new Blob([content], { type: \"application/javascript\" })) : null;\n}\n\nfunction runWorker(url: string): Promise<unknown> {\n const worker = new Worker(url);\n const cleanup = () => {\n worker.terminate();\n URL.revokeObjectURL(url);\n };\n return new Promise((resolve, reject) => {\n worker.onmessage = (e) => {\n cleanup();\n resolve(e.data);\n };\n worker.onerror = (e) => {\n cleanup();\n reject(new Error(e.message ?? String(e)));\n };\n });\n}\n\nregisterAll({\n command: {\n id: \"js\",\n name: \"Run JavaScript file\",\n description: \"Runs a script in a Web Worker. Use self.postMessage(value) to return a result.\",\n parameters: [\n { name: \"script\", description: \"workspace path to a .js file\", required: false },\n { name: \"code\", description: \"inline JavaScript\", required: false }\n ]\n },\n handler: {\n execute: async (context: any) => {\n const url = await getScriptUrl(context.params ?? {});\n if (!url) return;\n try {\n const result = await runWorker(url);\n if (result !== undefined) toastInfo(String(result));\n return result;\n } catch (err: any) {\n toastError(err?.message ?? String(err));\n }\n }\n }\n});\n\n"],"names":["result"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ import { contributionRegistry, SYSTEM_LANGUAGE_BUNDLES, i18nLazy, extensionRegistry } from "@eclipse-lyra/core";
2
+ import pkg from "../package.json";
3
+ const namespace = "extensions";
4
+ const en = { "EXT_UTILS_NAME": "Utilities", "EXT_UTILS_DESC": "Utility commands such as wget, unzip and certificate tools.", "CMD_WGET_NAME": "wget", "CMD_WGET_DESC": "Download a file from a URL to the workspace.", "CMD_UNZIP_NAME": "Unzip Archive", "CMD_UNZIP_DESC": "Extract a zip archive from the workspace.", "CMD_P12SPLIT_NAME": ".p12 file splitter", "CMD_P12SPLIT_DESC": "Split a .p12 certificate file into separate PEM files.", "RENAME": "Rename", "DELETE": "Delete" };
5
+ const bundle = {
6
+ namespace,
7
+ en
8
+ };
9
+ contributionRegistry.registerContribution(SYSTEM_LANGUAGE_BUNDLES, bundle);
10
+ const t = i18nLazy("extensions");
11
+ extensionRegistry.registerExtension({
12
+ id: pkg.name,
13
+ name: t("EXT_UTILS_NAME"),
14
+ description: t("EXT_UTILS_DESC"),
15
+ loader: () => import("./index-Bm7Xxv-I.js"),
16
+ icon: "toolbox",
17
+ dependencies: ["@eclipse-lyra/extension-python-runtime"]
18
+ });
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { extensionRegistry, i18nLazy, contributionRegistry, SYSTEM_LANGUAGE_BUNDLES } from \"@eclipse-lyra/core\";\nimport bundle from \"./i18n.json\";\nimport pkg from \"../package.json\";\n\ncontributionRegistry.registerContribution(SYSTEM_LANGUAGE_BUNDLES, bundle as any);\n\nconst t = i18nLazy(\"extensions\");\n\nextensionRegistry.registerExtension({\n id: pkg.name,\n name: t(\"EXT_UTILS_NAME\"),\n description: t(\"EXT_UTILS_DESC\"),\n loader: () => import(\"./commands\"),\n icon: \"toolbox\",\n dependencies: [\"@eclipse-lyra/extension-python-runtime\"]\n});\n\n"],"names":[],"mappings":";;;;;;;;AAIA,qBAAqB,qBAAqB,yBAAyB,MAAa;AAEhF,MAAM,IAAI,SAAS,YAAY;AAE/B,kBAAkB,kBAAkB;AAAA,EAClC,IAAI,IAAI;AAAA,EACR,MAAM,EAAE,gBAAgB;AAAA,EACxB,aAAa,EAAE,gBAAgB;AAAA,EAC/B,QAAQ,MAAM,OAAO,qBAAY;AAAA,EACjC,MAAM;AAAA,EACN,cAAc,CAAC,wCAAwC;AACzD,CAAC;"}
@@ -0,0 +1,5 @@
1
+ const p12splitter = 'import os\n\nfrom cryptography.hazmat.primitives.serialization import pkcs12, Encoding, PrivateFormat, NoEncryption\n\n\ndef p12splitter(p12_path, password=None, output_path=None):\n if output_path is None:\n output_path = os.path.dirname(p12_path)\n\n if p12_path is None:\n return\n\n cert_name = os.path.basename(p12_path)\n\n # Read the .p12 file\n with open(p12_path, "rb") as f:\n p12_data = f.read()\n\n if password is not None:\n password = password.encode("utf-8")\n\n # Load the PKCS#12 container\n private_key, certificate, additional_certs = pkcs12.load_key_and_certificates(p12_data, password)\n\n # Write the private key\n with open(os.path.join(output_path, f"{cert_name}.key.pem"), "wb") as key_file:\n key_file.write(private_key.private_bytes(\n encoding=Encoding.PEM,\n format=PrivateFormat.TraditionalOpenSSL,\n encryption_algorithm=NoEncryption()\n ))\n\n # Write the main certificate\n with open(os.path.join(output_path, f"{cert_name}.cert.pem"), "wb") as cert_file:\n cert_file.write(certificate.public_bytes(Encoding.PEM))\n\n # Optionally, write any additional certs (CA chain/intermediates)\n if additional_certs:\n with open(os.path.join(output_path, f"{cert_name}.chain.pem"), "wb") as ca_file:\n for ac in additional_certs:\n ca_file.write(ac.public_bytes(Encoding.PEM))\n\n';
2
+ export {
3
+ p12splitter as default
4
+ };
5
+ //# sourceMappingURL=p12splitter--4Q2vYnp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"p12splitter--4Q2vYnp.js","sources":["../src/p12splitter.py?raw"],"sourcesContent":["export default \"import os\\n\\nfrom cryptography.hazmat.primitives.serialization import pkcs12, Encoding, PrivateFormat, NoEncryption\\n\\n\\ndef p12splitter(p12_path, password=None, output_path=None):\\n if output_path is None:\\n output_path = os.path.dirname(p12_path)\\n\\n if p12_path is None:\\n return\\n\\n cert_name = os.path.basename(p12_path)\\n\\n # Read the .p12 file\\n with open(p12_path, \\\"rb\\\") as f:\\n p12_data = f.read()\\n\\n if password is not None:\\n password = password.encode(\\\"utf-8\\\")\\n\\n # Load the PKCS#12 container\\n private_key, certificate, additional_certs = pkcs12.load_key_and_certificates(p12_data, password)\\n\\n # Write the private key\\n with open(os.path.join(output_path, f\\\"{cert_name}.key.pem\\\"), \\\"wb\\\") as key_file:\\n key_file.write(private_key.private_bytes(\\n encoding=Encoding.PEM,\\n format=PrivateFormat.TraditionalOpenSSL,\\n encryption_algorithm=NoEncryption()\\n ))\\n\\n # Write the main certificate\\n with open(os.path.join(output_path, f\\\"{cert_name}.cert.pem\\\"), \\\"wb\\\") as cert_file:\\n cert_file.write(certificate.public_bytes(Encoding.PEM))\\n\\n # Optionally, write any additional certs (CA chain/intermediates)\\n if additional_certs:\\n with open(os.path.join(output_path, f\\\"{cert_name}.chain.pem\\\"), \\\"wb\\\") as ca_file:\\n for ac in additional_certs:\\n ca_file.write(ac.public_bytes(Encoding.PEM))\\n\\n\""],"names":[],"mappings":"AAAA,MAAA,cAAe;"}
@@ -0,0 +1,5 @@
1
+ import { File, Directory } from '@eclipse-lyra/core';
2
+ export declare function getTextFileFromPath(path: string): Promise<File | null>;
3
+ export declare function readTextFile(file: File): Promise<string | null>;
4
+ export declare function collectFilesRecursive(directory: Directory): Promise<string[]>;
5
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAgC,MAAM,oBAAoB,CAAC;AAEnF,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAkB5E;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYrE;AAED,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAcnF"}
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@eclipse-lyra/extension-utils",
3
+ "version": "0.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ }
11
+ },
12
+ "dependencies": {
13
+ "@eclipse-lyra/core": "*",
14
+ "@eclipse-lyra/extension-python-runtime": "*",
15
+ "jszip": "^3.10.1"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.9.3",
19
+ "vite": "^7.1.12",
20
+ "vite-plugin-dts": "^4.5.4"
21
+ },
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "build": "vite build"
29
+ }
30
+ }