@jmfederico/pi-web 1.202606.0 → 1.202606.2

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 (95) hide show
  1. package/README.md +23 -7
  2. package/dist/client/assets/{CodeViewer-N88Bx8F6.js → CodeViewer-iYSv2-dg.js} +1 -1
  3. package/dist/client/assets/{TerminalPanel-DKiL51Xi.js → TerminalPanel-BpFW6j27.js} +4 -4
  4. package/dist/client/assets/index-D4dbiKXF.js +2210 -0
  5. package/dist/client/index.html +1 -1
  6. package/dist/config.js +63 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/pi-web-plugins/info/pi-web-plugin.js +8 -1
  9. package/dist/pi-web-plugins/updates/package.json +9 -0
  10. package/dist/pi-web-plugins/{pi-web → updates}/pi-web-plugin.js +38 -30
  11. package/dist/pi-web-plugins/workspace-tasks/config.js +91 -0
  12. package/dist/pi-web-plugins/workspace-tasks/package.json +9 -0
  13. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +48 -0
  14. package/dist/pi-web-plugins/workspace-tasks/taskRunner.js +12 -0
  15. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +292 -0
  16. package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +47 -0
  17. package/dist/plugin-api/unstable.d.ts +22 -0
  18. package/dist/plugin-api.d.ts +169 -0
  19. package/dist/server/app.js +63 -26
  20. package/dist/server/app.js.map +1 -1
  21. package/dist/server/configRoutes.js +123 -0
  22. package/dist/server/configRoutes.js.map +1 -0
  23. package/dist/server/git/gitEnv.js +15 -0
  24. package/dist/server/git/gitEnv.js.map +1 -0
  25. package/dist/server/git/gitService.js +2 -1
  26. package/dist/server/git/gitService.js.map +1 -1
  27. package/dist/server/gitRoutes.js +3 -3
  28. package/dist/server/gitRoutes.js.map +1 -1
  29. package/dist/server/machines/machineClient.js +134 -0
  30. package/dist/server/machines/machineClient.js.map +1 -0
  31. package/dist/server/machines/machinePluginProxyRoutes.js +187 -0
  32. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -0
  33. package/dist/server/machines/machineProxyRoutes.js +92 -0
  34. package/dist/server/machines/machineProxyRoutes.js.map +1 -0
  35. package/dist/server/machines/machineRoutes.js +56 -0
  36. package/dist/server/machines/machineRoutes.js.map +1 -0
  37. package/dist/server/machines/machineService.js +260 -0
  38. package/dist/server/machines/machineService.js.map +1 -0
  39. package/dist/server/machines/machineStore.js +128 -0
  40. package/dist/server/machines/machineStore.js.map +1 -0
  41. package/dist/server/piWebPluginService.js +45 -15
  42. package/dist/server/piWebPluginService.js.map +1 -1
  43. package/dist/server/piWebStatus.js +127 -36
  44. package/dist/server/piWebStatus.js.map +1 -1
  45. package/dist/server/piWebStatusCache.js +32 -0
  46. package/dist/server/piWebStatusCache.js.map +1 -0
  47. package/dist/server/sessiond/sessionProxyRoutes.js +17 -14
  48. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  49. package/dist/server/sessiond.js +18 -7
  50. package/dist/server/sessiond.js.map +1 -1
  51. package/dist/server/sessions/piSessionManagerGateway.js +87 -0
  52. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -0
  53. package/dist/server/sessions/piSessionService.js +147 -66
  54. package/dist/server/sessions/piSessionService.js.map +1 -1
  55. package/dist/server/sessions/sessionArchiveStore.js +12 -0
  56. package/dist/server/sessions/sessionArchiveStore.js.map +1 -1
  57. package/dist/server/sessions/sessionNameGenerator.js +2 -0
  58. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  59. package/dist/server/sessions/sessionRoutes.js +126 -43
  60. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  61. package/dist/server/terminalProxyRoutes.js +20 -10
  62. package/dist/server/terminalProxyRoutes.js.map +1 -1
  63. package/dist/server/terminals/terminalRoutes.js +11 -0
  64. package/dist/server/terminals/terminalRoutes.js.map +1 -1
  65. package/dist/server/terminals/terminalService.js +6 -0
  66. package/dist/server/terminals/terminalService.js.map +1 -1
  67. package/dist/server/workspaceExplorerRoutes.js +4 -4
  68. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  69. package/dist/server/workspaces/fileSuggestions.js +98 -17
  70. package/dist/server/workspaces/fileSuggestions.js.map +1 -1
  71. package/dist/server/workspaces/gitWorktreeDiscovery.js +3 -2
  72. package/dist/server/workspaces/gitWorktreeDiscovery.js.map +1 -1
  73. package/dist/server/workspaces/workspaceDeletionRoutes.js +113 -0
  74. package/dist/server/workspaces/workspaceDeletionRoutes.js.map +1 -0
  75. package/dist/shared/apiTypes.d.ts +498 -0
  76. package/dist/shared/apiTypes.js +3 -1
  77. package/dist/shared/apiTypes.js.map +1 -1
  78. package/dist/shared/capabilities.js +25 -0
  79. package/dist/shared/capabilities.js.map +1 -0
  80. package/dist/shared/federatedRoutes.js +61 -0
  81. package/dist/shared/federatedRoutes.js.map +1 -0
  82. package/dist/shared/machinePluginIds.js +41 -0
  83. package/dist/shared/machinePluginIds.js.map +1 -0
  84. package/dist/shared/piWebStatusParsing.js +43 -0
  85. package/dist/shared/piWebStatusParsing.js.map +1 -1
  86. package/dist/shared/pluginIds.js +5 -0
  87. package/dist/shared/pluginIds.js.map +1 -0
  88. package/dist/shared/workspaceDeletion.js +12 -0
  89. package/dist/shared/workspaceDeletion.js.map +1 -0
  90. package/docs/plugins.md +278 -71
  91. package/package.json +8 -12
  92. package/plugin-api/unstable.d.ts +1 -0
  93. package/plugin-api.d.ts +1 -148
  94. package/dist/client/assets/index-DeSR1RUE.js +0 -1446
  95. package/dist/pi-web-plugins/pi-web/package.json +0 -9
@@ -50,7 +50,7 @@
50
50
  html, body { margin: 0; height: 100%; overflow: hidden; background: var(--pi-bg); color: var(--pi-text); }
51
51
  body { min-height: 100dvh; }
52
52
  </style>
53
- <script type="module" crossorigin src="/assets/index-DeSR1RUE.js"></script>
53
+ <script type="module" crossorigin src="/assets/index-D4dbiKXF.js"></script>
54
54
  <link rel="modulepreload" crossorigin href="/assets/vendor-editor-core-B4Sq6exx.js">
55
55
  <link rel="modulepreload" crossorigin href="/assets/vendor-editor-languages-DznYbTkJ.js">
56
56
  </head>
package/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join, resolve } from "node:path";
4
+ import { isPiWebPluginId, piWebPluginIdPattern } from "./shared/pluginIds.js";
4
5
  export function defaultPiWebConfigPath(env = process.env) {
5
6
  const xdgConfigHome = env["XDG_CONFIG_HOME"];
6
7
  return join(xdgConfigHome !== undefined && xdgConfigHome !== "" ? xdgConfigHome : join(homedir(), ".config"), "pi-web", "config.json");
@@ -46,11 +47,45 @@ export function effectivePiWebConfig(options = {}) {
46
47
  },
47
48
  };
48
49
  }
50
+ export function savePiWebConfig(config, options = {}) {
51
+ const env = options.env ?? process.env;
52
+ const path = piWebConfigPath(env, options.cwd ?? process.cwd());
53
+ const normalized = parsePiWebConfig(piWebConfigRecord(config), path);
54
+ const existing = readExistingConfigObject(path);
55
+ delete existing["host"];
56
+ delete existing["port"];
57
+ delete existing["allowedHosts"];
58
+ delete existing["shortcuts"];
59
+ delete existing["plugins"];
60
+ const merged = { ...existing, ...piWebConfigRecord(normalized) };
61
+ mkdirSync(dirname(path), { recursive: true });
62
+ writeFileSync(path, `${JSON.stringify(merged, null, 2)}\n`, "utf8");
63
+ return { path, exists: true, config: normalized };
64
+ }
65
+ function readExistingConfigObject(path) {
66
+ if (!existsSync(path))
67
+ return {};
68
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
69
+ if (!isRecord(parsed))
70
+ throw new Error(`PI WEB config must be a JSON object: ${path}`);
71
+ return parsed;
72
+ }
73
+ function piWebConfigRecord(config) {
74
+ return {
75
+ ...(config.host !== undefined ? { host: config.host } : {}),
76
+ ...(config.port !== undefined ? { port: config.port } : {}),
77
+ ...(config.allowedHosts !== undefined ? { allowedHosts: config.allowedHosts } : {}),
78
+ ...(config.shortcuts !== undefined ? { shortcuts: config.shortcuts } : {}),
79
+ ...(config.plugins !== undefined ? { plugins: config.plugins } : {}),
80
+ };
81
+ }
49
82
  function parsePiWebConfig(value, path) {
50
83
  return {
51
84
  ...(value["host"] !== undefined ? { host: parseString(value["host"], "host", path) } : {}),
52
85
  ...(value["port"] !== undefined ? { port: parsePort(value["port"], "port", path) } : {}),
53
86
  ...(value["allowedHosts"] !== undefined ? { allowedHosts: parseAllowedHosts(value["allowedHosts"], path) } : {}),
87
+ ...(value["shortcuts"] !== undefined ? { shortcuts: parseShortcuts(value["shortcuts"], path) } : {}),
88
+ ...(value["plugins"] !== undefined ? { plugins: parsePlugins(value["plugins"], path) } : {}),
54
89
  };
55
90
  }
56
91
  function parseString(value, key, path) {
@@ -77,6 +112,33 @@ function parseAllowedHostsEnv(value) {
77
112
  return true;
78
113
  return value.split(",").map((host) => host.trim()).filter((host) => host !== "");
79
114
  }
115
+ function parseShortcuts(value, path) {
116
+ if (!isRecord(value))
117
+ throw new Error(`PI WEB config shortcuts must be an object: ${path}`);
118
+ return Object.fromEntries(Object.entries(value).map(([actionId, shortcut]) => {
119
+ if (shortcut !== null && (typeof shortcut !== "string" || shortcut === "")) {
120
+ throw new Error(`PI WEB config shortcut values must be non-empty strings or null: ${path}`);
121
+ }
122
+ return [actionId, shortcut];
123
+ }));
124
+ }
125
+ function parsePlugins(value, path) {
126
+ if (!isRecord(value) || Array.isArray(value))
127
+ throw new Error(`PI WEB config plugins must be an object: ${path}`);
128
+ return Object.fromEntries(Object.entries(value).map(([pluginId, config]) => {
129
+ if (!isPiWebPluginId(pluginId))
130
+ throw new Error(`PI WEB config plugin ids must match ${piWebPluginIdPattern.source}: ${path}`);
131
+ if (!isRecord(config) || Array.isArray(config))
132
+ throw new Error(`PI WEB config plugin entries must be objects: ${path}`);
133
+ const enabled = config["enabled"];
134
+ if (enabled !== undefined && typeof enabled !== "boolean")
135
+ throw new Error(`PI WEB config plugin enabled values must be booleans: ${path}`);
136
+ const settings = config["settings"];
137
+ if (settings !== undefined && (!isRecord(settings) || Array.isArray(settings)))
138
+ throw new Error(`PI WEB config plugin settings must be objects: ${path}`);
139
+ return [pluginId, config];
140
+ }));
141
+ }
80
142
  function isRecord(value) {
81
143
  return typeof value === "object" && value !== null && !Array.isArray(value);
82
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  const plugin = {
3
3
  apiVersion: 1,
4
4
  name: "Info Plugin",
5
- activate: ({ html }) => ({
5
+ activate: ({ html, svg }) => ({
6
6
  contributions: {
7
7
  actions: [
8
8
  {
@@ -27,6 +27,13 @@ const plugin = {
27
27
  {
28
28
  id: "workspace.info",
29
29
  title: "Info",
30
+ icon: svg `
31
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
32
+ <circle cx="12" cy="12" r="9"></circle>
33
+ <path d="M12 11v5"></path>
34
+ <path d="M12 8h.01"></path>
35
+ </svg>
36
+ `,
30
37
  order: 1000,
31
38
  render: (context) => html `
32
39
  <section class="toolbar"><strong>Info</strong></section>
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@pi-web/updates-plugin",
3
+ "private": true,
4
+ "piWeb": {
5
+ "plugins": [
6
+ { "id": "updates", "module": "pi-web-plugin.js", "machineSpecific": true }
7
+ ]
8
+ }
9
+ }
@@ -1,9 +1,9 @@
1
- // Generated from pi-web-plugins/pi-web/pi-web-plugin.ts. Do not edit directly.
1
+ // Generated from pi-web-plugins/updates/pi-web-plugin.ts. Do not edit directly.
2
2
  function messagesFor(state) {
3
- return state.piWebStatus?.messages ?? [];
3
+ return state?.piWebStatus?.messages ?? [];
4
4
  }
5
5
  function statusFor(state) {
6
- return state.piWebStatus;
6
+ return state?.piWebStatus;
7
7
  }
8
8
  function messageCount(state) {
9
9
  return messagesFor(state).length;
@@ -11,7 +11,7 @@ function messageCount(state) {
11
11
  function isLocalOrUnknownInstallation(installation) {
12
12
  return installation === undefined || installation.kind === "local" || installation.kind === "unknown";
13
13
  }
14
- function shouldShowStatusPanel(state) {
14
+ function shouldShowUpdatesPanel(state) {
15
15
  const status = statusFor(state);
16
16
  if (messageCount(state) > 0)
17
17
  return true;
@@ -44,7 +44,7 @@ function renderComponent(html, component) {
44
44
  ? "restart needed"
45
45
  : "current";
46
46
  return html `
47
- <div class="pi-web-version-row">
47
+ <div class="updates-version-row">
48
48
  <strong>${component.label}</strong>
49
49
  <span>${status}</span>
50
50
  <small>running ${formatVersion(component.runtimeVersion)} · installed ${formatVersion(component.installedVersion)}</small>
@@ -54,7 +54,7 @@ function renderComponent(html, component) {
54
54
  }
55
55
  function renderCommand(html, label, command) {
56
56
  return html `
57
- <div class="pi-web-command">
57
+ <div class="updates-command">
58
58
  <span>${label}</span>
59
59
  <code>${command}</code>
60
60
  <button @click=${() => { void navigator.clipboard.writeText(command); }}>Copy</button>
@@ -78,7 +78,7 @@ function renderCommands(html, status) {
78
78
  </section>
79
79
  `;
80
80
  }
81
- function renderStatusPanel(html, state) {
81
+ function renderUpdatesPanel(html, state) {
82
82
  const status = statusFor(state);
83
83
  if (status === undefined) {
84
84
  return html `
@@ -89,29 +89,29 @@ function renderStatusPanel(html, state) {
89
89
  const messages = status.messages;
90
90
  return html `
91
91
  <style>
92
- .viewer.pi-web-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
93
- .viewer.pi-web-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
94
- .pi-web-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
95
- .pi-web-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
96
- .pi-web-message.error { border-color: var(--pi-danger); }
97
- .pi-web-message-title { display: flex; gap: 8px; align-items: baseline; }
98
- .pi-web-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
99
- .pi-web-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
100
- .pi-web-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
101
- .pi-web-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
102
- .pi-web-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
103
- .pi-web-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
92
+ .viewer.updates-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
93
+ .viewer.updates-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
94
+ .updates-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
95
+ .updates-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
96
+ .updates-message.error { border-color: var(--pi-danger); }
97
+ .updates-message-title { display: flex; gap: 8px; align-items: baseline; }
98
+ .updates-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
99
+ .updates-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
100
+ .updates-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
101
+ .updates-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
102
+ .updates-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
103
+ .updates-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
104
104
  @media (max-width: 520px) {
105
- .pi-web-command { grid-template-columns: minmax(0, 1fr) auto; }
106
- .pi-web-command > span { grid-column: 1 / -1; }
105
+ .updates-command { grid-template-columns: minmax(0, 1fr) auto; }
106
+ .updates-command > span { grid-column: 1 / -1; }
107
107
  }
108
108
  </style>
109
109
  <section class="toolbar"><strong>Updates</strong><span class="stale">beta</span>${messages.length > 0 ? html `<span class="stale">${String(messages.length)}</span>` : null}</section>
110
- <section class="viewer pi-web-status">
110
+ <section class="viewer updates-status">
111
111
  <section>
112
112
  ${messages.length === 0 ? html `<p class="muted">No PI WEB update or restart messages.</p>` : messages.map((message) => html `
113
- <article class=${`pi-web-message ${message.severity}`}>
114
- <div class="pi-web-message-title"><strong>${message.title}</strong><span>${message.severity}</span></div>
113
+ <article class=${`updates-message ${message.severity}`}>
114
+ <div class="updates-message-title"><strong>${message.title}</strong><span>${message.severity}</span></div>
115
115
  <p>${message.body}</p>
116
116
  ${message.command === undefined ? null : html `<code>${message.command}</code>`}
117
117
  </article>
@@ -126,7 +126,7 @@ function renderStatusPanel(html, state) {
126
126
 
127
127
  ${renderCommands(html, status)}
128
128
 
129
- <section class="pi-web-meta">
129
+ <section class="updates-meta">
130
130
  <span>Generated ${status.generatedAt}</span>
131
131
  ${status.release.latestVersion === undefined ? null : html `<span>Latest npm release ${status.release.latestVersion}</span>`}
132
132
  ${status.release.skipped === true ? html `<span>Remote version check skipped.</span>` : null}
@@ -137,20 +137,28 @@ function renderStatusPanel(html, state) {
137
137
  }
138
138
  const plugin = {
139
139
  apiVersion: 1,
140
- name: "PI WEB Updates",
141
- activate: ({ html }) => ({
140
+ name: "Updates",
141
+ activate: ({ html, svg }) => ({
142
142
  contributions: {
143
143
  workspacePanels: [
144
144
  {
145
- id: "workspace.status",
145
+ id: "workspace.updates",
146
146
  title: "Updates",
147
+ icon: svg `
148
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
149
+ <path d="M20 6v5h-5"></path>
150
+ <path d="M4 18v-5h5"></path>
151
+ <path d="M18.4 9A7 7 0 0 0 6.1 6.7L4 8.8"></path>
152
+ <path d="M5.6 15A7 7 0 0 0 17.9 17.3L20 15.2"></path>
153
+ </svg>
154
+ `,
147
155
  order: 100,
148
- visible: (context) => shouldShowStatusPanel(context.state),
156
+ visible: (context) => shouldShowUpdatesPanel(context.state),
149
157
  badge: (context) => {
150
158
  const count = messageCount(context.state);
151
159
  return html `beta${count > 0 ? html ` · ${String(count)}` : null}`;
152
160
  },
153
- render: (context) => renderStatusPanel(html, context.state),
161
+ render: (context) => renderUpdatesPanel(html, context.state),
154
162
  },
155
163
  ],
156
164
  },
@@ -0,0 +1,91 @@
1
+ // Generated from pi-web-plugins/workspace-tasks/config.ts. Do not edit directly.
2
+ export const TASKS_CONFIG_PATH = ".pi-web/tasks.json";
3
+ export const TASKS_CONFIG_VERSION = 1;
4
+ const taskIdPattern = /^[a-z][a-z0-9.-]*$/u;
5
+ export function parseTasksConfigText(text) {
6
+ let parsed;
7
+ try {
8
+ parsed = JSON.parse(text);
9
+ }
10
+ catch (error) {
11
+ return { ok: false, error: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}` };
12
+ }
13
+ return parseTasksConfig(parsed);
14
+ }
15
+ export function parseTasksConfig(value) {
16
+ if (!isRecord(value))
17
+ return invalid("Config must be an object");
18
+ if (value["version"] !== TASKS_CONFIG_VERSION)
19
+ return invalid("Config version must be 1");
20
+ const tasks = value["tasks"];
21
+ if (!Array.isArray(tasks))
22
+ return invalid("Config tasks must be an array");
23
+ const ids = new Set();
24
+ const parsedTasks = [];
25
+ for (const [index, task] of tasks.entries()) {
26
+ const parsedTask = parseTask(task, index);
27
+ if (!parsedTask.ok)
28
+ return parsedTask;
29
+ if (ids.has(parsedTask.task.id))
30
+ return invalid(`Duplicate task id: ${parsedTask.task.id}`);
31
+ ids.add(parsedTask.task.id);
32
+ parsedTasks.push(parsedTask.task);
33
+ }
34
+ return { ok: true, config: { version: TASKS_CONFIG_VERSION, tasks: parsedTasks } };
35
+ }
36
+ function parseTask(value, index) {
37
+ const label = `Task ${String(index + 1)}`;
38
+ if (!isRecord(value))
39
+ return invalid(`${label} must be an object`);
40
+ const id = requireNonEmptyString(value, "id", label);
41
+ if (!id.ok)
42
+ return id;
43
+ if (!taskIdPattern.test(id.value))
44
+ return invalid(`${label} id must match ${taskIdPattern.source}`);
45
+ const title = requireNonEmptyString(value, "title", label);
46
+ if (!title.ok)
47
+ return title;
48
+ const command = requireNonEmptyString(value, "command", label);
49
+ if (!command.ok)
50
+ return command;
51
+ const description = optionalNonEmptyString(value, "description", label);
52
+ if (!description.ok)
53
+ return description;
54
+ const group = optionalNonEmptyString(value, "group", label);
55
+ if (!group.ok)
56
+ return group;
57
+ const confirm = value["confirm"];
58
+ if (confirm !== undefined && typeof confirm !== "boolean")
59
+ return invalid(`${label} confirm must be a boolean`);
60
+ return {
61
+ ok: true,
62
+ task: {
63
+ id: id.value,
64
+ title: title.value,
65
+ command: command.value,
66
+ ...(description.value === undefined ? {} : { description: description.value }),
67
+ ...(group.value === undefined ? {} : { group: group.value }),
68
+ confirm: confirm ?? false,
69
+ },
70
+ };
71
+ }
72
+ function requireNonEmptyString(record, key, label) {
73
+ const value = record[key];
74
+ if (typeof value !== "string" || value.trim() === "")
75
+ return invalid(`${label} ${key} must be a non-empty string`);
76
+ return { ok: true, value };
77
+ }
78
+ function optionalNonEmptyString(record, key, label) {
79
+ const value = record[key];
80
+ if (value === undefined)
81
+ return { ok: true, value: undefined };
82
+ if (typeof value !== "string" || value.trim() === "")
83
+ return invalid(`${label} ${key} must be a non-empty string when provided`);
84
+ return { ok: true, value };
85
+ }
86
+ function invalid(error) {
87
+ return { ok: false, error };
88
+ }
89
+ function isRecord(value) {
90
+ return typeof value === "object" && value !== null && !Array.isArray(value);
91
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@pi-web/workspace-tasks-plugin",
3
+ "private": true,
4
+ "piWeb": {
5
+ "plugins": [
6
+ { "id": "workspace-tasks", "module": "pi-web-plugin.js" }
7
+ ]
8
+ }
9
+ }
@@ -0,0 +1,48 @@
1
+ // Generated from pi-web-plugins/workspace-tasks/pi-web-plugin.ts. Do not edit directly.
2
+ import { TASKS_CONFIG_PATH } from "./config.js";
3
+ import { defineTasksPanelElement, tasksPanelBadge } from "./tasksPanelElement.js";
4
+ const plugin = {
5
+ apiVersion: 1,
6
+ name: "Workspace Tasks",
7
+ activate: ({ pluginId, html, svg }) => {
8
+ defineTasksPanelElement();
9
+ return {
10
+ contributions: {
11
+ actions: [
12
+ {
13
+ id: "workspace.open-tasks",
14
+ title: "Open Workspace Tasks",
15
+ description: `Open the workspace Tasks tab. Configure tasks in ${TASKS_CONFIG_PATH}.`,
16
+ group: "Workspace",
17
+ enabled: (context) => context.state.selectedWorkspace !== undefined,
18
+ run: (context) => {
19
+ if (context.state.selectedWorkspace === undefined)
20
+ return;
21
+ context.selectWorkspaceTool(`${pluginId}:workspace.tasks`);
22
+ },
23
+ },
24
+ ],
25
+ workspacePanels: [
26
+ {
27
+ id: "workspace.tasks",
28
+ title: "Tasks",
29
+ icon: svg `
30
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
31
+ <path d="M9 6h11"></path>
32
+ <path d="M9 12h11"></path>
33
+ <path d="M9 18h11"></path>
34
+ <path d="m4 6 .8 .8L6.5 5"></path>
35
+ <path d="m4 12 .8 .8 1.7-1.8"></path>
36
+ <path d="m4 18 .8 .8 1.7-1.8"></path>
37
+ </svg>
38
+ `,
39
+ order: 40,
40
+ badge: (context) => tasksPanelBadge(context),
41
+ render: (context) => html `<pi-web-workspace-tasks-panel .context=${context}></pi-web-workspace-tasks-panel>`,
42
+ },
43
+ ],
44
+ },
45
+ };
46
+ },
47
+ };
48
+ export default plugin;
@@ -0,0 +1,12 @@
1
+ // Generated from pi-web-plugins/workspace-tasks/taskRunner.ts. Do not edit directly.
2
+ export function runWorkspaceTaskInTerminal(terminal, task) {
3
+ return terminal.runCommand({
4
+ title: task.title,
5
+ command: task.command,
6
+ open: true,
7
+ metadata: {
8
+ "pi.plugin": "workspace-tasks",
9
+ "task.id": task.id,
10
+ },
11
+ });
12
+ }