@jmfederico/pi-web 1.202606.7 → 1.202607.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 (84) hide show
  1. package/README.md +9 -3
  2. package/dist/client/assets/CodeViewer-tXF3UTsY.js +4 -0
  3. package/dist/client/assets/TerminalPanel-D_ihiWAt.js +187 -0
  4. package/dist/client/assets/UnifiedDiffViewer-BziirXBJ.js +39 -0
  5. package/dist/client/assets/index-Brfk1lwl.js +2950 -0
  6. package/dist/client/assets/vendor-editor-core-vUi74DnD.js +12 -0
  7. package/dist/client/assets/vendor-editor-languages-DoaXUodB.js +46 -0
  8. package/dist/client/assets/vendor-editor-legacy-CYBnW6ZU.js +1 -0
  9. package/dist/client/assets/vendor-terminal-BrP-ENHg.css +1 -0
  10. package/dist/client/assets/vendor-terminal-D8k4UKM2.js +35 -0
  11. package/dist/client/index.html +6 -3
  12. package/dist/docker/piWebDockerCommandPlan.js +211 -0
  13. package/dist/docker/piWebDockerCommandPlan.js.map +1 -0
  14. package/dist/pi-web-plugins/updates/pi-web-plugin.js +15 -5
  15. package/dist/pi-web-plugins/updates/updatesLogic.js +37 -5
  16. package/dist/piWebVersionReport.js +4 -0
  17. package/dist/piWebVersionReport.js.map +1 -1
  18. package/dist/plugin-api.d.ts +1 -1
  19. package/dist/server/app.js +16 -1
  20. package/dist/server/app.js.map +1 -1
  21. package/dist/server/browserMessageProjection.js +56 -0
  22. package/dist/server/browserMessageProjection.js.map +1 -0
  23. package/dist/server/configRoutes.js +108 -1
  24. package/dist/server/configRoutes.js.map +1 -1
  25. package/dist/server/machines/machineClient.js +19 -9
  26. package/dist/server/machines/machineClient.js.map +1 -1
  27. package/dist/server/machines/machineProxyRoutes.js +64 -11
  28. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  29. package/dist/server/machines/machineService.js +4 -26
  30. package/dist/server/machines/machineService.js.map +1 -1
  31. package/dist/server/piPackageRoutes.js +87 -0
  32. package/dist/server/piPackageRoutes.js.map +1 -0
  33. package/dist/server/piPackageService.js +69 -0
  34. package/dist/server/piPackageService.js.map +1 -0
  35. package/dist/server/piWebPluginService.js +43 -8
  36. package/dist/server/piWebPluginService.js.map +1 -1
  37. package/dist/server/piWebStatus.js +57 -0
  38. package/dist/server/piWebStatus.js.map +1 -1
  39. package/dist/server/realtime/sessionEventHub.js +2 -1
  40. package/dist/server/realtime/sessionEventHub.js.map +1 -1
  41. package/dist/server/sessions/builtinCommands.js +1 -1
  42. package/dist/server/sessions/builtinCommands.js.map +1 -1
  43. package/dist/server/sessions/piSessionService.js +503 -104
  44. package/dist/server/sessions/piSessionService.js.map +1 -1
  45. package/dist/server/sessions/sessionArchiveStore.js +51 -22
  46. package/dist/server/sessions/sessionArchiveStore.js.map +1 -1
  47. package/dist/server/sessions/sessionCommandService.js +16 -0
  48. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  49. package/dist/server/sessions/sessionNameGenerator.js +27 -44
  50. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  51. package/dist/server/sessions/sessionRoutes.js +38 -1
  52. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  53. package/dist/server/sessions/spawnSessionTool.js +9 -4
  54. package/dist/server/sessions/spawnSessionTool.js.map +1 -1
  55. package/dist/server/sessions/spawnSubsessionTool.js +22 -15
  56. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  57. package/dist/server/workspaces/fileSuggestions.js +7 -3
  58. package/dist/server/workspaces/fileSuggestions.js.map +1 -1
  59. package/dist/shared/activity.js +0 -15
  60. package/dist/shared/activity.js.map +1 -1
  61. package/dist/shared/apiTypes.d.ts +63 -1
  62. package/dist/shared/apiTypes.js +4 -0
  63. package/dist/shared/apiTypes.js.map +1 -1
  64. package/dist/shared/capabilities.js +28 -2
  65. package/dist/shared/capabilities.js.map +1 -1
  66. package/dist/shared/federatedRoutes.js +10 -0
  67. package/dist/shared/federatedRoutes.js.map +1 -1
  68. package/dist/shared/piWebStatusParsing.js +20 -8
  69. package/dist/shared/piWebStatusParsing.js.map +1 -1
  70. package/dist/shared/thinkingLevels.d.ts +1 -1
  71. package/dist/shared/thinkingLevels.js +1 -1
  72. package/dist/shared/thinkingLevels.js.map +1 -1
  73. package/docs/config.md +24 -13
  74. package/docs/plugins.md +28 -14
  75. package/package.json +35 -31
  76. package/dist/client/assets/CodeViewer-CQU9mJ74.js +0 -4
  77. package/dist/client/assets/TerminalPanel-DtfVBsqI.js +0 -126
  78. package/dist/client/assets/UnifiedDiffViewer-BZQQK99S.js +0 -34
  79. package/dist/client/assets/index-CbE7df66.js +0 -2742
  80. package/dist/client/assets/vendor-editor-core-C7aWiQy0.js +0 -12
  81. package/dist/client/assets/vendor-editor-languages-EW34FfVy.js +0 -26
  82. package/dist/client/assets/vendor-editor-legacy-B4QLsWF8.js +0 -1
  83. package/dist/client/assets/vendor-terminal-DDGTF8rc.css +0 -1
  84. package/dist/client/assets/vendor-terminal-DjQ08hXu.js +0 -16
package/docs/plugins.md CHANGED
@@ -13,6 +13,18 @@ Plugins can currently:
13
13
 
14
14
  They do **not** run in the session daemon, do not get a server-side hook API, and are not sandboxed.
15
15
 
16
+ ## Pi packages vs PI WEB plugins
17
+
18
+ **Pi packages** are packages managed by Pi (`pi install`, `pi remove`, `pi update`). A Pi package can provide extensions, skills, prompt templates, themes, context/system prompt files, and/or PI WEB browser plugins. Many Pi packages do not include a PI WEB plugin.
19
+
20
+ **PI WEB plugins** are browser-side PI WEB UI modules discovered from bundled, local, dev, and installed Pi-package sources. Enabling or disabling a PI WEB plugin is a PI WEB config task; installing, removing, or updating a Pi package is a Pi package-manager task.
21
+
22
+ Use **Settings → Pi packages** to view configured Pi packages or install/remove/update a package. Enter only the package source, such as `npm:@scope/package`, a git/URL source, or a local path. PI WEB uses Pi's default package location, equivalent to `pi install <source>`, and does not ask for an install location.
23
+
24
+ When machine federation is enabled, **Settings → Pi packages** targets the currently selected machine. The panel labels whether changes will run on the local/gateway machine or on a selected remote PI WEB machine. If an older or unavailable remote PI WEB server does not expose package-management routes, PI WEB reports the package management operation as unsupported or unavailable instead of silently falling back to the gateway.
25
+
26
+ Use **Settings → PI WEB plugins** to enable or disable discovered PI WEB browser plugins before the browser imports them. In a federated setup, this plugin enablement surface targets the currently selected machine and labels where changes are saved. If an older or unavailable remote PI WEB server does not advertise selected-machine settings support, PI WEB reports the plugin settings as unsupported or unavailable instead of silently falling back to the gateway. After installing, removing, or updating a Pi package, type `/reload` in each idle PI WEB session on the target machine to refresh Pi runtime resources such as extensions, skills, prompt templates, themes, and context/system prompt files as supported by Pi. Reload the browser page separately for newly discovered or changed PI WEB browser plugins. A routine session daemon restart is not required.
27
+
16
28
  ## Trust model
17
29
 
18
30
  Plugins run as JavaScript in the browser app. Treat them as trusted code:
@@ -140,7 +152,7 @@ When [machine federation](https://pi-web.dev/machines) is enabled, PI WEB also l
140
152
  - remote theme contributions are ignored for now because themes are app-wide;
141
153
  - mixed PI WEB versions across federated machines are best-effort and not guaranteed compatible.
142
154
 
143
- Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable a remote machine plugin, open that machine directly or update its config file.
155
+ Remote plugin enablement is controlled by the remote machine's PI WEB plugin config. To edit or disable a remote machine plugin, select that machine and use **Settings → PI WEB plugins** when the remote server exposes selected-machine settings, or open that machine directly/update its config file.
144
156
 
145
157
  Plugin package metadata may set `machineSpecific: true` when the plugin's meaning is tied to the selected PI WEB machine:
146
158
 
@@ -155,9 +167,11 @@ const url = new URL("./asset.json", import.meta.url);
155
167
 
156
168
  If a remote plugin constructs absolute asset URLs, it should use the `pluginId` from `activate()` because PI WEB gives remote plugins a gateway-scoped runtime id. Hard-coded `/pi-web-plugins/<original-id>/...` URLs may point at the gateway instead of the remote machine.
157
169
 
158
- ## Manage plugins
170
+ ## Manage PI WEB plugins
171
+
172
+ Open **Settings → PI WEB plugins** to review discovered bundled, local, dev, and Pi package plugins for the selected PI WEB machine. When the local machine is selected, this is the gateway plugin list; when a remote machine is selected, the list comes from that remote PI WEB server and includes disabled discovered plugins it exposes. PI WEB can disable any discovered selected-machine plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
159
173
 
160
- Open **Settings → Plugins** to review discovered bundled, local, dev, and Pi package plugins for the PI WEB gateway you opened. PI WEB can disable any discovered gateway plugin before the browser imports it. Core app contributions such as the built-in command palette, base workspace tools, and themes are not managed through this plugin list.
174
+ This surface is only for PI WEB plugin enablement. To install, remove, or update Pi packages that may provide plugins or other Pi resources, use **Settings → Pi packages**. In a federated setup, both the Pi packages panel and the PI WEB plugins panel target the selected machine; plugin enablement still writes the PI WEB `plugins` config key rather than changing Pi package-manager settings.
161
175
 
162
176
  Plugin preferences are stored under the top-level `plugins` config key in the PI WEB config file:
163
177
 
@@ -183,14 +197,14 @@ After changing plugin enablement, reload the PI WEB browser tab. Already-loaded
183
197
 
184
198
  PI WEB ships core, discoverable plugins in the main `@jmfederico/pi-web` npm package. No separate `pi install` step is required: update PI WEB, reload the browser tab, and the bundled plugins appear in `/pi-web-plugins/manifest.json`.
185
199
 
186
- Built-in plugins can be managed from **Settings → Plugins** or with the top-level `plugins` config key.
200
+ Built-in plugins can be managed from **Settings → PI WEB plugins** or with the top-level `plugins` config key.
187
201
 
188
202
  ### Updates
189
203
 
190
204
  **Plugin id:** `updates`
191
205
  **What it does:** adds a conditional **Updates** workspace tab with PI WEB update, restart, and installed-service guidance.
192
206
 
193
- Updates is enabled by default. It declares `machineSpecific: true` so the gateway Updates tab only appears for the local machine; while a remote machine is selected, that remote machine's Updates plugin is used if available. To hide it, disable `updates` in **Settings → Plugins** or set:
207
+ Updates is enabled by default. It declares `machineSpecific: true` so the gateway Updates tab only appears for the local machine; while a remote machine is selected, that remote machine's Updates plugin is used if available. To hide it, disable `updates` in **Settings → PI WEB plugins** or set:
194
208
 
195
209
  ```json
196
210
  {
@@ -206,7 +220,7 @@ Updates is enabled by default. It declares `machineSpecific: true` so the gatewa
206
220
  **Config file:** `.pi-web/tasks.json`
207
221
  **What it does:** adds a **Tasks** workspace tab for running configured shell commands in dedicated PI WEB terminals.
208
222
 
209
- Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → Plugins** or set:
223
+ Workspace Tasks is enabled by default. To hide it, disable `workspace-tasks` in **Settings → PI WEB plugins** or set:
210
224
 
211
225
  ```json
212
226
  {
@@ -223,11 +237,11 @@ Configure workspace tasks in `.pi-web/tasks.json`:
223
237
  "version": 1,
224
238
  "tasks": [
225
239
  {
226
- "id": "docker.start",
227
- "title": "Start Docker",
228
- "group": "Docker",
229
- "description": "Start the local Docker Compose environment.",
230
- "command": "./docker/scripts/docker-compose-dev up -d"
240
+ "id": "app.start",
241
+ "title": "Start app",
242
+ "group": "Development",
243
+ "description": "Start the local development server.",
244
+ "command": "npm run dev"
231
245
  },
232
246
  {
233
247
  "id": "db.reset",
@@ -273,7 +287,7 @@ PI WEB builds the gateway `/pi-web-plugins/manifest.json` from these sources:
273
287
 
274
288
  Entries may be real directories or symlinks. This is the recommended development workflow.
275
289
 
276
- 3. Installed Pi packages that expose PI WEB plugin metadata. Pi packages may be user or project scoped.
290
+ 3. Installed Pi packages that expose PI WEB plugin metadata. Pi packages may be user or project scoped. Installing/removing/updating Pi packages is done from **Settings → Pi packages** (or Pi's package manager), not from the PI WEB plugin enable/disable list.
277
291
 
278
292
  Remote machines expose their own manifests through the gateway at `/api/machines/<machine-id>/pi-web-plugins/manifest.json`. Those plugin modules are rewritten to gateway-scoped asset URLs and registered under machine-scoped runtime ids so duplicate plugin ids on different machines do not collide.
279
293
 
@@ -746,7 +760,7 @@ Labels should use the same helper through a plugin-owned cache because `items()`
746
760
  const envCache = new Map();
747
761
 
748
762
  function envKey(machine, workspace) {
749
- return `${machine.id}:${workspace.id}:docker/development.be-go.local.env`;
763
+ return `${machine.id}:${workspace.id}:.env.local`;
750
764
  }
751
765
 
752
766
  function loadEnvLabel(context) {
@@ -756,7 +770,7 @@ function loadEnvLabel(context) {
756
770
 
757
771
  const pending = { status: "loading", label: undefined };
758
772
  envCache.set(key, pending);
759
- context.files.readFile("docker/development.be-go.local.env")
773
+ context.files.readFile(".env.local")
760
774
  .then((file) => {
761
775
  pending.status = "ready";
762
776
  pending.label = file.content.match(/^DEV_URL=(.+)$/m)?.[1];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmfederico/pi-web",
3
- "version": "1.202606.7",
3
+ "version": "1.202607.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",
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "files": [
14
14
  "dist",
15
+ "!dist/**/*.testSupport.*",
15
16
  "install.sh",
16
17
  "README.md",
17
18
  "LICENSE",
@@ -29,18 +30,20 @@
29
30
  "dev:server": "npm run dev:web",
30
31
  "dev:client": "vite --host 0.0.0.0",
31
32
  "dev:plugins": "node scripts/build-plugins.mjs --watch",
32
- "build": "tsc -p tsconfig.build.json && npm run build:plugin-api && npm run build:plugins && vite build",
33
+ "build": "npm run clean && tsc -p tsconfig.build.json && npm run build:plugin-api && npm run build:plugins && vite build",
33
34
  "build:plugin-api": "tsc -p tsconfig.plugin-api.json",
34
35
  "build:plugins": "tsc -p tsconfig.plugins.json && node scripts/build-plugins.mjs",
35
36
  "capture:screenshots": "node scripts/capture-screenshots.mjs",
36
37
  "typecheck": "tsc --noEmit",
38
+ "typecheck:cached": "tsc --noEmit --incremental --tsBuildInfoFile node_modules/.cache/pi-web/typecheck.tsbuildinfo",
37
39
  "knip": "knip",
38
40
  "lint": "eslint \"src/**/*.ts\" \"extensions/**/*.ts\" \"pi-web-plugins/**/*.ts\" vite.config.ts vitest.config.ts",
39
41
  "test": "vitest run --config vitest.config.ts",
40
42
  "verify": "npm run typecheck && npm run lint && npm run knip && npm test",
43
+ "verify:staged": "node scripts/verify-staged.mjs",
41
44
  "start": "tsx src/server/index.ts",
42
45
  "start:sessiond": "tsx src/server/sessiond.ts",
43
- "clean": "rm -rf dist",
46
+ "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
44
47
  "prepack": "npm run build",
45
48
  "pack:dry": "npm pack --dry-run",
46
49
  "prepublishOnly": "npm run verify",
@@ -51,7 +54,7 @@
51
54
  "changelog:status": "changeset status"
52
55
  },
53
56
  "dependencies": {
54
- "@codemirror/commands": "^6.10.3",
57
+ "@codemirror/commands": "^6.10.4",
55
58
  "@codemirror/lang-css": "^6.3.1",
56
59
  "@codemirror/lang-go": "^6.0.1",
57
60
  "@codemirror/lang-html": "^6.4.11",
@@ -60,38 +63,39 @@
60
63
  "@codemirror/lang-markdown": "^6.5.0",
61
64
  "@codemirror/lang-python": "^6.2.1",
62
65
  "@codemirror/lang-rust": "^6.0.2",
63
- "@codemirror/language": "^6.12.3",
64
- "@codemirror/legacy-modes": "^6.5.2",
65
- "@codemirror/state": "^6.6.0",
66
- "@codemirror/view": "^6.42.1",
67
- "@fastify/static": "^9.1.3",
68
- "@fastify/websocket": "^11.2.0",
66
+ "@codemirror/language": "^6.12.4",
67
+ "@codemirror/legacy-modes": "^6.5.3",
68
+ "@codemirror/state": "^6.7.1",
69
+ "@codemirror/view": "^6.43.6",
70
+ "@fastify/compress": "^9.0.0",
71
+ "@fastify/static": "^9.3.0",
72
+ "@fastify/websocket": "^11.3.0",
69
73
  "@xterm/addon-fit": "^0.11.0",
70
74
  "@xterm/xterm": "^6.0.0",
71
- "diff": "^8.0.4",
72
- "fastify": "^5.6.1",
73
- "lit": "^3.3.1",
74
- "marked": "^18.0.3",
75
+ "diff": "^9.0.0",
76
+ "fastify": "^5.10.0",
77
+ "lit": "^3.3.3",
78
+ "marked": "^18.0.6",
75
79
  "node-pty": "^1.1.0",
76
- "typebox": "1.1.38",
77
- "ws": "^8.20.1"
80
+ "typebox": "1.3.6",
81
+ "ws": "^8.21.0"
78
82
  },
79
83
  "devDependencies": {
80
84
  "@changesets/cli": "^2.31.0",
81
- "@earendil-works/pi-agent-core": "^0.79.1",
82
- "@earendil-works/pi-ai": "^0.79.1",
83
- "@earendil-works/pi-coding-agent": "^0.79.1",
85
+ "@earendil-works/pi-agent-core": "^0.80.6",
86
+ "@earendil-works/pi-ai": "^0.80.6",
87
+ "@earendil-works/pi-coding-agent": "^0.80.6",
84
88
  "@eslint/js": "^10.0.1",
85
- "@types/node": "^24.10.1",
89
+ "@types/node": "^24.13.3",
86
90
  "@types/ws": "^8.18.1",
87
- "eslint": "^10.3.0",
88
- "globals": "^17.6.0",
89
- "knip": "^6.16.1",
90
- "tsx": "^4.20.6",
91
- "typescript": "^5.9.3",
92
- "typescript-eslint": "^8.59.2",
93
- "vite": "^7.2.4",
94
- "vitest": "^4.1.5"
91
+ "eslint": "^10.6.0",
92
+ "globals": "^17.7.0",
93
+ "knip": "^6.25.0",
94
+ "tsx": "^4.23.0",
95
+ "typescript": "^6.0.3",
96
+ "typescript-eslint": "^8.63.0",
97
+ "vite": "^8.1.4",
98
+ "vitest": "^4.1.10"
95
99
  },
96
100
  "publishConfig": {
97
101
  "access": "public"
@@ -109,9 +113,9 @@
109
113
  "homepage": "https://pi-web.dev/",
110
114
  "packageManager": "npm@11.11.0",
111
115
  "peerDependencies": {
112
- "@earendil-works/pi-agent-core": ">=0.78.0 <1",
113
- "@earendil-works/pi-ai": ">=0.78.0 <1",
114
- "@earendil-works/pi-coding-agent": ">=0.78.0 <1"
116
+ "@earendil-works/pi-agent-core": ">=0.80.0 <1",
117
+ "@earendil-works/pi-ai": ">=0.80.0 <1",
118
+ "@earendil-works/pi-coding-agent": ">=0.80.0 <1"
115
119
  },
116
120
  "keywords": [
117
121
  "pi-package",
@@ -1,4 +0,0 @@
1
- import{v as r,J as d,$ as h,A as m,Y as g,U as f,a0 as v,V as b}from"./vendor-editor-core-C7aWiQy0.js";import{g as y,r as w,p as x,h as C,c as j,m as k,j as E,a as l}from"./vendor-editor-languages-EW34FfVy.js";import{d as H}from"./vendor-editor-legacy-B4QLsWF8.js";import{i as _,b as O,a as S,n as p,f as P,t as T}from"./index-CbE7df66.js";var A=Object.defineProperty,L=Object.getOwnPropertyDescriptor,i=(e,s,n,a)=>{for(var t=a>1?void 0:a?L(s,n):s,c=e.length-1,u;c>=0;c--)(u=e[c])&&(t=(a?u(s,n,t):u(t))||t);return a&&t&&A(s,n,t),t};let o=class extends _{constructor(){super(...arguments),this.content=""}firstUpdated(){this.recreateEditor()}updated(e){(e.has("content")||e.has("language"))&&this.recreateEditor()}disconnectedCallback(){this.view?.destroy(),this.view=void 0,super.disconnectedCallback()}render(){return O`<div class="host"></div>`}recreateEditor(){this.editorHost&&(this.view?.destroy(),this.view=new r({parent:this.editorHost,state:d.create({doc:this.content,extensions:[h(),m.of(g),f(b,{fallback:!0}),d.readOnly.of(!0),r.editable.of(!1),r.lineWrapping,V,...F(this.language),...M(this.language)]})}))}};o.styles=S`
2
- :host { display: block; min-height: 0; height: 100%; }
3
- .host { height: 100%; min-height: 0; overflow: auto; }
4
- `;i([p()],o.prototype,"content",2);i([p()],o.prototype,"language",2);i([P(".host")],o.prototype,"editorHost",2);o=i([T("code-viewer")],o);const V=r.theme({"&":{height:"100%",color:"var(--pi-text)",backgroundColor:"var(--pi-bg)",fontSize:"12px"},".cm-scroller":{fontFamily:"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",lineHeight:"1.45"},".cm-gutters":{backgroundColor:"var(--pi-bg)",color:"var(--pi-dim)",borderRight:"1px solid var(--pi-border-muted)"},".cm-activeLineGutter":{backgroundColor:"transparent"},".cm-activeLine":{backgroundColor:"transparent"},".cm-content":{caretColor:"transparent"},"&.cm-focused":{outline:"none"}}),D=r.theme({".cm-content":{textAlign:"start"},".cm-line":{unicodeBidi:"plaintext"}});function F(e){return e==="markdown"?[r.contentAttributes.of({dir:"auto"}),D]:[]}function M(e){if(e===void 0)return[];switch(e){case"typescript":return[l({typescript:!0})];case"javascript":return[l()];case"json":return[E()];case"markdown":return[k()];case"css":return[j()];case"html":return[C()];case"python":return[x()];case"rust":return[w()];case"go":return[y()];case"diff":return[v.define(H)];default:return[]}}export{o as CodeViewer};
@@ -1,126 +0,0 @@
1
- import{a as E,n as m,i as K,b as l,t as R,c as h,s as A,d as w,e as _,f as F,r as c}from"./index-CbE7df66.js";import{D as S,o as T}from"./vendor-terminal-DjQ08hXu.js";import"./vendor-editor-core-C7aWiQy0.js";import"./vendor-editor-languages-EW34FfVy.js";const P="pi-web.terminal.softKeys",N="(pointer: coarse), (max-width: 760px)";function z(e,t){return e??t}function V(e){if(e==="true")return!0;if(e==="false")return!1}function $(){return typeof window<"u"&&"matchMedia"in window?window.matchMedia(N):void 0}function M(e){return e?.matches===!0}function H(e=$()){return z(O(),M(e))}function B(){return O()!==void 0}function O(e=D()){if(e!==void 0)try{return V(e.getItem(P))}catch{return}}function j(e,t=D()){if(t!==void 0)try{t.setItem(P,String(e))}catch{}}function D(){if(!(typeof window>"u"))try{return window.localStorage}catch{return}}const U=[{id:"escape",label:"Esc",ariaLabel:"Escape",title:"Send Escape"},{id:"tab",label:"Tab",ariaLabel:"Tab",title:"Send Tab"},{id:"ctrl-c",label:"Ctrl+C",ariaLabel:"Control C",title:"Interrupt the foreground process"},{id:"ctrl-d",label:"Ctrl+D",ariaLabel:"Control D",title:"Send EOF / close input"},{id:"ctrl-z",label:"Ctrl+Z",ariaLabel:"Control Z",title:"Suspend the foreground process"},{id:"ctrl-l",label:"Ctrl+L",ariaLabel:"Control L",title:"Clear / redraw the terminal"},{id:"ctrl-r",label:"Ctrl+R",ariaLabel:"Control R",title:"Reverse search history"},{id:"ctrl-u",label:"Ctrl+U",ariaLabel:"Control U",title:"Delete to the start of the line"},{id:"ctrl-w",label:"Ctrl+W",ariaLabel:"Control W",title:"Delete the previous word"},{id:"arrow-left",label:"←",ariaLabel:"Left arrow",title:"Move left"},{id:"arrow-up",label:"↑",ariaLabel:"Up arrow",title:"Move up / previous command"},{id:"arrow-down",label:"↓",ariaLabel:"Down arrow",title:"Move down / next command"},{id:"arrow-right",label:"→",ariaLabel:"Right arrow",title:"Move right"},{id:"home",label:"Home",ariaLabel:"Home",title:"Move to the start"},{id:"end",label:"End",ariaLabel:"End",title:"Move to the end"},{id:"page-up",label:"PgUp",ariaLabel:"Page up",title:"Page up"},{id:"page-down",label:"PgDn",ariaLabel:"Page down",title:"Page down"},{id:"delete",label:"Del",ariaLabel:"Delete",title:"Delete forward"},{id:"backspace",label:"⌫",ariaLabel:"Backspace",title:"Backspace"},{id:"meta-backward-word",label:"M-B",ariaLabel:"Meta B",title:"Move backward one word"},{id:"meta-forward-word",label:"M-F",ariaLabel:"Meta F",title:"Move forward one word"}],d="\x1B",q="";function Y(e,t){switch(e){case"escape":return d;case"tab":return" ";case"ctrl-c":return p("c");case"ctrl-d":return p("d");case"ctrl-z":return p("z");case"ctrl-l":return p("l");case"ctrl-r":return p("r");case"ctrl-u":return p("u");case"ctrl-w":return p("w");case"arrow-left":return b("D",t);case"arrow-up":return b("A",t);case"arrow-down":return b("B",t);case"arrow-right":return b("C",t);case"home":return x("H",t);case"end":return x("F",t);case"page-up":return`${d}[5~`;case"page-down":return`${d}[6~`;case"delete":return`${d}[3~`;case"backspace":return q;case"meta-backward-word":return`${d}b`;case"meta-forward-word":return`${d}f`}}function p(e){return String.fromCharCode(e.toUpperCase().charCodeAt(0)-64)}function b(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}function x(e,t){return t?.applicationCursorKeysMode===!0?`${d}O${e}`:`${d}[${e}`}var W=Object.defineProperty,X=Object.getOwnPropertyDescriptor,y=(e,t,i,n)=>{for(var r=n>1?void 0:n?X(t,i):t,a=e.length-1,u;a>=0;a--)(u=e[a])&&(r=(n?u(t,i,r):u(r))||r);return n&&r&&W(t,i,r),r};const J=8,Z=500;let f=class extends K{constructor(){super(...arguments),this.refocusOnClick=!0,this.onInput=()=>{},this.lastPointerFinishedAt=0}sendSoftKey(e,t){this.onInput(Y(e.id,this.modes),t)}onSoftKeyPointerDown(e,t){e.pointerType==="mouse"&&e.button!==0||(e.preventDefault(),this.pointerStart={pointerId:e.pointerId,key:t,clientX:e.clientX,clientY:e.clientY})}onSoftKeyPointerMove(e){const t=this.pointerStart;t?.pointerId===e.pointerId&&I(t,e)&&this.finishSoftKeyPointer()}onSoftKeyPointerUp(e,t){const i=this.pointerStart;i?.pointerId===e.pointerId&&(e.preventDefault(),this.finishSoftKeyPointer(),!(i.key.id!==t.id||I(i,e))&&this.sendSoftKey(t,{refocus:e.pointerType==="mouse"}))}onSoftKeyPointerCancel(e){this.pointerStart?.pointerId===e.pointerId&&this.finishSoftKeyPointer()}finishSoftKeyPointer(){this.pointerStart=void 0,this.lastPointerFinishedAt=Date.now()}onSoftKeyClick(e,t){if(Date.now()-this.lastPointerFinishedAt<Z){e.preventDefault();return}this.sendSoftKey(t,{refocus:this.refocusOnClick})}render(){return l`
2
- <div class="terminal-soft-keys" role="toolbar" aria-label="Terminal soft keys">
3
- ${U.map(e=>l`
4
- <button
5
- type="button"
6
- class="soft-key"
7
- title=${e.title}
8
- aria-label=${e.ariaLabel}
9
- @pointerdown=${t=>{this.onSoftKeyPointerDown(t,e)}}
10
- @pointermove=${t=>{this.onSoftKeyPointerMove(t)}}
11
- @pointerup=${t=>{this.onSoftKeyPointerUp(t,e)}}
12
- @pointercancel=${t=>{this.onSoftKeyPointerCancel(t)}}
13
- @click=${t=>{this.onSoftKeyClick(t,e)}}
14
- >${e.label}</button>
15
- `)}
16
- </div>
17
- `}};f.styles=E`
18
- :host { flex: 0 0 auto; display: block; }
19
- .terminal-soft-keys { display: flex; gap: 6px; align-items: center; padding: 6px; border-bottom: 1px solid var(--pi-border-muted); background: var(--pi-bg); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; touch-action: pan-x; }
20
- .terminal-soft-keys::-webkit-scrollbar { display: none; }
21
- button { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; max-width: none; min-height: 34px; border: 1px solid var(--pi-border); border-radius: 7px; background: var(--pi-surface); color: var(--pi-text); padding: 6px 9px; font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; cursor: pointer; touch-action: pan-x; -webkit-touch-callout: none; user-select: none; }
22
- button:disabled { opacity: .5; cursor: not-allowed; }
23
- `;y([m({attribute:!1})],f.prototype,"modes",2);y([m({type:Boolean})],f.prototype,"refocusOnClick",2);y([m({attribute:!1})],f.prototype,"onInput",2);f=y([R("terminal-soft-keys")],f);function I(e,t){return Math.hypot(t.clientX-e.clientX,t.clientY-e.clientY)>J}var G=Object.defineProperty,Q=Object.getOwnPropertyDescriptor,s=(e,t,i,n)=>{for(var r=n>1?void 0:n?Q(t,i):t,a=e.length-1,u;a>=0;a--)(u=e[a])&&(r=(n?u(t,i,r):u(r))||r);return n&&r&&G(t,i,r),r};const ee={cursorBlink:!0,convertEol:!0,fontFamily:"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",fontSize:13},te={cols:100,rows:30},ie=1e3;let o=class extends K{constructor(){super(...arguments),this.machineId="local",this.autoStart=!1,this.onSelectTerminal=()=>{},this.terminals=[],this.commandRuns=[],this.loading=!1,this.visible=!1,this.cancellingRunIds=[],this.continuingTerminalIds=[],this.defaultSoftKeysEnvironment=!1,this.softKeysEnabled=H(),this.suppressTerminalInput=!1,this.softKeysDefaultEnvironmentMedia=$(),this.softKeysPreferenceStored=B(),this.onSoftKeysDefaultEnvironmentChange=()=>{this.syncDefaultSoftKeysEnvironment()}}connectedCallback(){super.connectedCallback(),this.syncDefaultSoftKeysEnvironment(),this.softKeysDefaultEnvironmentMedia?.addEventListener("change",this.onSoftKeysDefaultEnvironmentChange),this.themeObserver=new MutationObserver(()=>{this.applyTerminalTheme()}),this.themeObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["class","style","data-theme"]})}firstUpdated(){this.intersectionObserver=new IntersectionObserver(e=>{this.visible=e[0]?.isIntersecting===!0}),this.intersectionObserver.observe(this)}disconnectedCallback(){this.intersectionObserver?.disconnect(),this.intersectionObserver=void 0,this.themeObserver?.disconnect(),this.themeObserver=void 0,this.softKeysDefaultEnvironmentMedia?.removeEventListener("change",this.onSoftKeysDefaultEnvironmentChange),this.updateCommandRunPolling(!1),this.disposeTerminalView(),super.disconnectedCallback()}syncDefaultSoftKeysEnvironment(){const e=M(this.softKeysDefaultEnvironmentMedia),t=this.softKeysEnabled;this.defaultSoftKeysEnvironment=e,this.softKeysPreferenceStored||(this.softKeysEnabled=e),this.softKeysEnabled!==t&&this.scheduleFitAndNotify()}scheduleFitAndNotify(){this.updateComplete.then(()=>{this.fitAndNotify()})}willUpdate(e){const t=this.workspace===void 0?void 0:JSON.stringify([this.machineId,this.workspace.path]);if(t!==this.observedWorkspaceScope){this.observedWorkspaceScope=t,this.loadedCwd=void 0,this.autoStartConsumedCwd=void 0,this.terminals=[],this.commandRuns=[],this.selectedId=void 0,this.cancellingRunIds=[],this.continuingTerminalIds=[],this.updateCommandRunPolling(!1),this.disposeTerminalView();return}if(e.has("selectedTerminalId")){if(e.get("selectedTerminalId")!==void 0&&this.selectedTerminalId===void 0){this.loadedCwd=void 0,this.selectTerminalIdInView(void 0);return}this.applyRequestedTerminalSelection()}}updated(e){this.visible?this.hasPendingCommandRuns()&&this.updateCommandRunPolling(!0):this.updateCommandRunPolling(!1),this.loadVisibleWorkspaceTerminals(),e.has("selectedTerminalId")&&this.shouldReloadForRequestedTerminal()&&this.loadTerminals(),this.ensureTerminalView()}loadVisibleWorkspaceTerminals(){const e=this.workspace?.path;!this.visible||e===void 0||e===this.loadedCwd||(this.loadedCwd=e,this.loadTerminals())}async loadTerminals(){this.loading=!0,this.error=void 0;try{const e=this.workspace;if(e===void 0)return;const t=this.consumeAutoStart(),[i,n]=await Promise.all([h.terminals(e.projectId,e.id,this.machineId),h.listCommandRuns({projectId:e.projectId,workspaceId:e.id},this.machineId)]);this.terminals=i,this.commandRuns=n,this.selectPreferredLoadedTerminal({replaceUrl:!0}),this.updateCommandRunPolling(this.hasPendingCommandRuns(n)),i.length===0&&t&&await this.startTerminal()}catch(e){this.error=e instanceof Error?e.message:String(e)}finally{this.loading=!1}}applyRequestedTerminalSelection(){this.selectedTerminalId!==void 0&&!this.terminals.some(e=>e.id===this.selectedTerminalId)||this.selectPreferredLoadedTerminal({replaceUrl:!0})}consumeAutoStart(){const e=this.workspace?.path;return!this.autoStart||e===void 0||this.autoStartConsumedCwd===e?!1:(this.autoStartConsumedCwd=e,!0)}shouldReloadForRequestedTerminal(){const e=this.workspace?.path;return this.visible&&e!==void 0&&e===this.loadedCwd&&this.selectedTerminalId!==void 0&&!this.loading&&!this.terminals.some(t=>t.id===this.selectedTerminalId)}selectPreferredLoadedTerminal(e){let t=A(this.terminals,{targetTerminalId:this.selectedTerminalId});t===void 0&&this.selectedTerminalId!==void 0&&(t=w(this.terminals)),this.selectTerminalIdInView(t?.id),(t?.id!==this.selectedTerminalId||t===void 0&&this.selectedTerminalId!==void 0)&&this.onSelectTerminal(t?.id,{replace:e?.replaceUrl===!0})}selectTerminalIdInView(e){this.selectedId!==e&&(this.selectedId=e,this.disposeTerminalView())}async startTerminal(){if(this.workspace!==void 0){this.error=void 0;try{const e=this.measureTerminalSize()??te,t=await h.startTerminal(this.workspace.projectId,this.workspace.id,e,this.machineId);this.terminals=[...this.terminals,t],this.selectTerminal(t.id)}catch(e){this.error=e instanceof Error?e.message:String(e)}}}async closeTerminal(e,t){t.stopPropagation();try{if(this.workspace===void 0)return;await h.closeTerminal(this.workspace.projectId,this.workspace.id,e,this.machineId);const i=this.terminals.filter(n=>n.id!==e);if(this.terminals=i,this.selectedId===e||this.selectedTerminalId===e){const n=w(i)?.id;this.selectTerminalIdInView(n),this.onSelectTerminal(n,{replace:!0})}}catch(i){this.error=i instanceof Error?i.message:String(i)}}selectTerminal(e){this.selectedId!==e&&this.selectTerminalIdInView(e),this.onSelectTerminal(e)}selectedTerminalInfo(){return this.terminals.find(e=>e.id===this.selectedId)}selectedCommandRun(){const e=this.selectedTerminalInfo()?.commandRunId;if(e!==void 0)return this.commandRuns.find(t=>t.id===e)}async loadCommandRuns(){const e=this.workspace;if(e!==void 0)try{const t=await h.listCommandRuns({projectId:e.projectId,workspaceId:e.id},this.machineId);this.commandRuns=t,this.cancellingRunIds=this.cancellingRunIds.filter(i=>t.some(n=>n.id===i&&v(n))),this.updateCommandRunPolling(this.hasPendingCommandRuns(t))}catch(t){this.error=t instanceof Error?t.message:String(t)}}updateCommandRunPolling(e){if(e&&this.commandRunPollTimer===void 0){this.commandRunPollTimer=window.setInterval(()=>{this.loadCommandRuns()},ie);return}!e&&this.commandRunPollTimer!==void 0&&(window.clearInterval(this.commandRunPollTimer),this.commandRunPollTimer=void 0)}hasPendingCommandRuns(e=this.commandRuns){return e.some(v)}async cancelCommandRun(e){if(!(!v(e)||this.cancellingRunIds.includes(e.id))){this.error=void 0,this.cancellingRunIds=[...this.cancellingRunIds,e.id];try{await h.cancelCommandRun(e.id,this.machineId),await this.loadCommandRuns()}catch(t){this.error=t instanceof Error?t.message:String(t)}finally{this.cancellingRunIds=this.cancellingRunIds.filter(t=>t!==e.id)}}}async continueTerminal(e){if(!(this.workspace===void 0||this.continuingTerminalIds.includes(e))){this.error=void 0,this.continuingTerminalIds=[...this.continuingTerminalIds,e];try{const t=await h.continueTerminal(this.workspace.projectId,this.workspace.id,e,this.machineId);this.terminals=this.terminals.map(i=>i.id===e?t:i),this.socket===void 0&&this.disposeTerminalView(),this.fitAndNotify(),this.terminal?.focus()}catch(t){this.error=t instanceof Error?t.message:String(t)}finally{this.continuingTerminalIds=this.continuingTerminalIds.filter(t=>t!==e)}}}ensureTerminalView(){const e=this.workspace,t=this.terminalHostElement();if(!this.visible||this.terminal!==void 0||this.selectedId===void 0||t===void 0||e===void 0)return;const i=new S(C(this)),n=new T;i.loadAddon(n),i.open(t),this.terminal=i,this.fitAddon=n,this.resizeObserver=new ResizeObserver(()=>{this.fitAndNotify()}),this.resizeObserver.observe(t),i.onData(a=>{this.suppressTerminalInput||this.sendTerminalInput(a)});const r=this.fitTerminal();this.connectSocket(e.projectId,e.id,this.selectedId,i,r),requestAnimationFrame(()=>{this.fitAndNotify()}),i.focus()}connectSocket(e,t,i,n,r){const a=_(e,t,i,r,this.machineId);a.binaryType="arraybuffer",this.socket=a,a.addEventListener("open",()=>{this.fitAndNotify()}),a.addEventListener("message",u=>{this.handleSocketMessage(u.data,i,n)}),a.addEventListener("close",()=>{this.socket===a&&(this.socket=void 0)})}async handleSocketMessage(e,t,i){try{const n=re(await se(e));n.type==="output"&&this.writeTerminalOutput(i,n.data,n.replay===!0),n.type==="exit"&&(i.writeln(`\r
24
- [process exited${n.exitCode===void 0?"":` with code ${String(n.exitCode)}`}]`),this.terminals=this.terminals.map(r=>r.id===t?{...r,exited:!0,...n.exitCode===void 0?{}:{exitCode:n.exitCode}}:r),this.loadCommandRuns()),n.type==="error"&&i.writeln(`\r
25
- [terminal error: ${n.message}]`)}catch(n){i.writeln(`\r
26
- [terminal error: ${n instanceof Error?n.message:String(n)}]`)}}writeTerminalOutput(e,t,i){if(!i){e.write(t);return}this.suppressTerminalInput=!0,e.write(t,()=>{this.suppressTerminalInput=!1})}fitAndNotify(){const e=this.fitTerminal();e!==void 0&&this.send({type:"resize",...e})}fitTerminal(){if(this.fitAddon===void 0||this.terminal===void 0)return;const e=this.fitAddon.proposeDimensions(),t=k(e);if(t!==void 0)return this.fitAddon.fit(),t}measureTerminalSize(){const e=this.fitTerminal();if(e!==void 0)return e;const t=this.terminalHostElement();if(this.terminal!==void 0||t===void 0)return;const i=new S(C(this)),n=new T;i.loadAddon(n),i.open(t);const r=k(n.proposeDimensions());return i.dispose(),r}terminalHostElement(){const e=this.terminalHost;return e instanceof HTMLDivElement?e:void 0}applyTerminalTheme(){this.terminal!==void 0&&(this.terminal.options.theme=L(this))}sendTerminalInput(e){const t=oe(e);t!==""&&this.send({type:"input",data:t})}sendSoftKeyInput(e,t){this.sendTerminalInput(e),t.refocus&&this.focusTerminal()}focusTerminal(){const e=this.terminal;e!==void 0&&(e.focus(),requestAnimationFrame(()=>{e.focus()}))}send(e){this.socket?.readyState===WebSocket.OPEN&&this.socket.send(JSON.stringify(e))}disposeTerminalView(){this.resizeObserver?.disconnect(),this.resizeObserver=void 0,this.socket?.close(),this.socket=void 0,this.terminal?.dispose(),this.terminal=void 0,this.fitAddon=void 0}renderCommandRunNotice(){const e=this.selectedCommandRun();if(e===void 0)return null;const t=this.selectedTerminalInfo();if(v(e)){const i=this.cancellingRunIds.includes(e.id);return l`
27
- <section class="command-run-notice running">
28
- <div>
29
- <strong>${e.title}</strong>
30
- <p>Command is running. Press <kbd>Ctrl</kbd>+<kbd>C</kbd> or use the button to cancel.</p>
31
- <code>${e.command}</code>
32
- </div>
33
- <button class="danger" ?disabled=${i} @click=${()=>{this.cancelCommandRun(e)}}>${i?"Cancel sent…":"Cancel command"}</button>
34
- </section>
35
- `}if(t?.exited===!0){const i=this.continuingTerminalIds.includes(t.id);return l`
36
- <section class=${`command-run-notice ${e.status}`}>
37
- <div>
38
- <strong>${ne(e)}</strong>
39
- <p>Output is preserved. Continue in a shell to inspect or run follow-up commands.</p>
40
- <code>${e.command}</code>
41
- </div>
42
- <button ?disabled=${i} @click=${()=>{this.continueTerminal(t.id)}}>${i?"Starting shell…":"Continue in shell"}</button>
43
- </section>
44
- `}return null}selectedTerminalAcceptsInput(){const e=this.selectedTerminalInfo();return e!==void 0&&!e.exited}shouldShowSoftKeys(){return this.selectedTerminalAcceptsInput()&&this.softKeysEnabled}shouldShowSoftKeysToggle(){return this.selectedTerminalAcceptsInput()}toggleSoftKeys(){this.softKeysEnabled=!this.softKeysEnabled,this.softKeysPreferenceStored=!0,j(this.softKeysEnabled),this.scheduleFitAndNotify()}renderSoftKeysToggle(){return this.shouldShowSoftKeysToggle()?l`
45
- <button
46
- type="button"
47
- class=${this.softKeysEnabled?"soft-keys-toggle selected":"soft-keys-toggle"}
48
- title=${this.softKeysEnabled?"Hide terminal soft keys":"Show terminal soft keys"}
49
- aria-label=${this.softKeysEnabled?"Hide terminal soft keys":"Show terminal soft keys"}
50
- aria-pressed=${String(this.softKeysEnabled)}
51
- @click=${()=>{this.toggleSoftKeys()}}
52
- >
53
- <svg class="keyboard-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
54
- <rect x="3" y="5" width="18" height="14" rx="2"></rect>
55
- <path d="M7 9h.01M10 9h.01M13 9h.01M16 9h.01M7 12h.01M10 12h.01M13 12h.01M16 12h.01M8 16h8"></path>
56
- </svg>
57
- <span>Keys</span>
58
- </button>
59
- `:null}renderSoftKeys(){return l`
60
- <terminal-soft-keys
61
- .modes=${this.terminal?.modes}
62
- .refocusOnClick=${!this.defaultSoftKeysEnvironment}
63
- .onInput=${(e,t)=>{this.sendSoftKeyInput(e,t)}}
64
- ></terminal-soft-keys>
65
- `}render(){return l`
66
- <section class="terminal-shell">
67
- <div class="terminal-tabs">
68
- ${this.renderSoftKeysToggle()}
69
- ${this.terminals.map(e=>l`
70
- <button class=${this.selectedId===e.id?"selected":""} @click=${()=>{this.selectTerminal(e.id)}}>
71
- <span>${e.name}${e.exited?" · exited":""}</span>
72
- <small @click=${t=>{this.closeTerminal(e.id,t)}}>×</small>
73
- </button>
74
- `)}
75
- <button class="new" ?disabled=${this.workspace===void 0} @click=${()=>{this.startTerminal()}}>+ Shell</button>
76
- </div>
77
- ${this.error===void 0?null:l`<p class="error">${this.error}</p>`}
78
- ${this.renderCommandRunNotice()}
79
- ${this.shouldShowSoftKeys()?this.renderSoftKeys():null}
80
- ${this.loading?l`<p class="muted">Loading terminals…</p>`:null}
81
- <div class="terminal-host"></div>
82
- </section>
83
- `}};o.styles=E`
84
- :host { flex: 1 1 auto; min-height: 0; display: flex; }
85
- .terminal-shell { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--pi-terminal-bg); }
86
- .terminal-tabs { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; padding: 6px; border-bottom: 1px solid var(--pi-border-muted); background: var(--pi-bg); overflow: auto; }
87
- button { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 180px; border: 1px solid var(--pi-border); border-radius: 7px; background: var(--pi-surface); color: var(--pi-text); padding: 5px 7px; cursor: pointer; }
88
- button.selected { border-color: var(--pi-accent); background: var(--pi-selection-bg); }
89
- button.new { flex: 0 0 auto; color: var(--pi-muted); }
90
- .soft-keys-toggle { flex: 0 0 auto; }
91
- .soft-keys-toggle .keyboard-icon { flex: 0 0 auto; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
92
- button span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
93
- button small { color: var(--pi-muted); font-size: 14px; line-height: 1; }
94
- button small:hover { color: var(--pi-danger); }
95
- button.danger { color: var(--pi-danger); }
96
- button:disabled { opacity: .5; cursor: not-allowed; }
97
- .command-run-notice { flex: 0 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 8px 10px; border-bottom: 1px solid var(--pi-border-muted); background: var(--pi-surface); color: var(--pi-text); }
98
- .command-run-notice.running { border-color: var(--pi-warning-border); }
99
- .command-run-notice.succeeded { border-color: var(--pi-success-border); }
100
- .command-run-notice.failed { border-color: var(--pi-danger); }
101
- .command-run-notice p { margin: 3px 0; color: var(--pi-muted); }
102
- .command-run-notice code { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--pi-text-secondary); font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
103
- .command-run-notice kbd { border: 1px solid var(--pi-border); border-radius: 4px; background: var(--pi-bg); padding: 0 4px; font: 11px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
104
- .command-run-notice button { justify-self: end; max-width: none; }
105
- .terminal-host { flex: 1 1 auto; min-height: 0; padding: 6px; box-sizing: border-box; overflow: hidden; }
106
- .terminal-host .xterm { height: 100%; cursor: text; position: relative; user-select: none; }
107
- .terminal-host .xterm.focus, .terminal-host .xterm:focus { outline: none; }
108
- .terminal-host .xterm-helpers { position: absolute; top: 0; z-index: 5; }
109
- /* Hide the helper textarea without using !important on the positional properties (left/top/width/height/z-index). xterm sets those inline during IME/dead-key composition (e.g. "~" on a Swedish layout) so the composition is positioned at the cursor and committed correctly; forcing them here would pin the textarea off-screen with zero size and break composition. */
110
- .terminal-host .xterm-helper-textarea { position: absolute; left: -9999em; top: 0; width: 0; height: 0; padding: 0 !important; border: 0 !important; margin: 0 !important; opacity: 0 !important; z-index: -5; white-space: nowrap !important; overflow: hidden !important; resize: none !important; outline: 0 !important; appearance: none !important; }
111
- /* The composition view shows pending dead-key/IME input. Without these rules it renders as a static block in the top-left corner instead of overlaying the cursor. */
112
- .terminal-host .composition-view { position: absolute; display: none; white-space: nowrap; z-index: 1; background: var(--pi-terminal-bg, #000); color: var(--pi-terminal-text, #fff); }
113
- .terminal-host .composition-view.active { display: block; }
114
- .terminal-host .xterm-viewport { position: absolute; inset: 0; overflow-y: scroll; cursor: default; background-color: var(--pi-terminal-bg); }
115
- .terminal-host .xterm-screen { position: relative; }
116
- .terminal-host .xterm-screen canvas { position: absolute; left: 0; top: 0; }
117
- .terminal-host .xterm-char-measure-element { display: inline-block; visibility: hidden; position: absolute; top: 0; left: -9999em; line-height: normal; }
118
- .terminal-host .xterm-accessibility:not(.debug), .terminal-host .xterm-message { position: absolute; inset: 0; z-index: 10; color: transparent; pointer-events: none; }
119
- .terminal-host .xterm-accessibility-tree:not(.debug) *::selection { color: transparent; }
120
- .terminal-host .xterm-accessibility-tree { font-family: monospace; user-select: text; white-space: pre; }
121
- .terminal-host .xterm-accessibility-tree > div { transform-origin: left; width: fit-content; }
122
- .terminal-host .live-region { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
123
- .error { flex: 0 0 auto; margin: 0; padding: 8px; color: var(--pi-danger); border-bottom: 1px solid var(--pi-border); background: var(--pi-surface); }
124
- .muted { margin: 10px; color: var(--pi-muted); }
125
- .xterm { height: 100%; }
126
- `;s([m({attribute:!1})],o.prototype,"workspace",2);s([m()],o.prototype,"machineId",2);s([m({attribute:!1})],o.prototype,"selectedTerminalId",2);s([m({type:Boolean})],o.prototype,"autoStart",2);s([m({attribute:!1})],o.prototype,"onSelectTerminal",2);s([F(".terminal-host")],o.prototype,"terminalHost",2);s([c()],o.prototype,"terminals",2);s([c()],o.prototype,"commandRuns",2);s([c()],o.prototype,"selectedId",2);s([c()],o.prototype,"loading",2);s([c()],o.prototype,"error",2);s([c()],o.prototype,"visible",2);s([c()],o.prototype,"cancellingRunIds",2);s([c()],o.prototype,"continuingTerminalIds",2);s([c()],o.prototype,"defaultSoftKeysEnvironment",2);s([c()],o.prototype,"softKeysEnabled",2);o=s([R("terminal-panel")],o);function v(e){return e.status==="queued"||e.status==="running"}function ne(e){return e.status==="succeeded"?`Command succeeded${e.exitCode===void 0?"":` with exit code ${String(e.exitCode)}`}`:`Command failed${e.exitCode===void 0?"":` with exit code ${String(e.exitCode)}`}`}function re(e){const t=JSON.parse(e);if(!le(t))return{type:"error",message:"Invalid terminal message"};const i=t;return i.type==="output"&&typeof i.data=="string"?{type:"output",data:i.data,...typeof i.replay=="boolean"?{replay:i.replay}:{}}:i.type==="exit"?{type:"exit",...typeof i.exitCode=="number"?{exitCode:i.exitCode}:{}}:i.type==="error"&&typeof i.message=="string"?{type:"error",message:i.message}:{type:"error",message:"Invalid terminal message"}}function oe(e){return e.replaceAll("\x1B[I","").replaceAll("\x1B[O","")}async function se(e){return typeof e=="string"?e:e instanceof ArrayBuffer?new TextDecoder().decode(e):e instanceof Blob?await e.text():String(e)}function C(e){return{...ee,theme:L(e)}}function L(e){return{background:g(e,"--pi-terminal-bg","#05070a"),foreground:g(e,"--pi-terminal-text","#e6edf3"),cursor:g(e,"--pi-accent","#58a6ff"),selectionBackground:g(e,"--pi-terminal-selection","#264f78")}}function g(e,t,i){const n=getComputedStyle(e).getPropertyValue(t).trim();return n===""?i:n}function k(e){if(!(e===void 0||!ae(e.cols,e.rows)))return{cols:Math.floor(e.cols),rows:Math.floor(e.rows)}}function ae(e,t){return Number.isFinite(e)&&Number.isFinite(t)&&e>0&&t>0}function le(e){return typeof e=="object"&&e!==null}export{o as TerminalPanel,oe as filterTerminalInput};
@@ -1,34 +0,0 @@
1
- import{i as A,b as P,a as V,n as z,t as F}from"./index-CbE7df66.js";import"./vendor-editor-core-C7aWiQy0.js";import"./vendor-editor-languages-EW34FfVy.js";class U{diff(e,t,i={}){let o;typeof i=="function"?(o=i,i={}):"callback"in i&&(o=i.callback);const r=this.castInput(e,i),s=this.castInput(t,i),u=this.removeEmpty(this.tokenize(r,i)),l=this.removeEmpty(this.tokenize(s,i));return this.diffWithOptionsObj(u,l,i,o)}diffWithOptionsObj(e,t,i,o){var r;const s=c=>{if(c=this.postProcess(c,i),o){setTimeout(function(){o(c)},0);return}else return c},u=t.length,l=e.length;let d=1,a=u+l;i.maxEditLength!=null&&(a=Math.min(a,i.maxEditLength));const g=(r=i.timeout)!==null&&r!==void 0?r:1/0,v=Date.now()+g,f=[{oldPos:-1,lastComponent:void 0}];let h=this.extractCommon(f[0],t,e,0,i);if(f[0].oldPos+1>=l&&h+1>=u)return s(this.buildValues(f[0].lastComponent,t,e));let w=-1/0,y=1/0;const $=()=>{for(let c=Math.max(w,-d);c<=Math.min(y,d);c+=2){let p;const x=f[c-1],b=f[c+1];x&&(f[c-1]=void 0);let D=!1;if(b){const S=b.oldPos-c;D=b&&0<=S&&S<u}const k=x&&x.oldPos+1<l;if(!D&&!k){f[c]=void 0;continue}if(!k||D&&x.oldPos<b.oldPos?p=this.addToPath(b,!0,!1,0,i):p=this.addToPath(x,!1,!0,1,i),h=this.extractCommon(p,t,e,c,i),p.oldPos+1>=l&&h+1>=u)return s(this.buildValues(p.lastComponent,t,e))||!0;f[c]=p,p.oldPos+1>=l&&(y=Math.min(y,c-1)),h+1>=u&&(w=Math.max(w,c+1))}d++};if(o)(function c(){setTimeout(function(){if(d>a||Date.now()>v)return o(void 0);$()||c()},0)})();else for(;d<=a&&Date.now()<=v;){const c=$();if(c)return c}}addToPath(e,t,i,o,r){const s=e.lastComponent;return s&&!r.oneChangePerToken&&s.added===t&&s.removed===i?{oldPos:e.oldPos+o,lastComponent:{count:s.count+1,added:t,removed:i,previousComponent:s.previousComponent}}:{oldPos:e.oldPos+o,lastComponent:{count:1,added:t,removed:i,previousComponent:s}}}extractCommon(e,t,i,o,r){const s=t.length,u=i.length;let l=e.oldPos,d=l-o,a=0;for(;d+1<s&&l+1<u&&this.equals(i[l+1],t[d+1],r);)d++,l++,a++,r.oneChangePerToken&&(e.lastComponent={count:1,previousComponent:e.lastComponent,added:!1,removed:!1});return a&&!r.oneChangePerToken&&(e.lastComponent={count:a,previousComponent:e.lastComponent,added:!1,removed:!1}),e.oldPos=l,d}equals(e,t,i){return i.comparator?i.comparator(e,t):e===t||!!i.ignoreCase&&e.toLowerCase()===t.toLowerCase()}removeEmpty(e){const t=[];for(let i=0;i<e.length;i++)e[i]&&t.push(e[i]);return t}castInput(e,t){return e}tokenize(e,t){return Array.from(e)}join(e){return e.join("")}postProcess(e,t){return e}get useLongestToken(){return!1}buildValues(e,t,i){const o=[];let r;for(;e;)o.push(e),r=e.previousComponent,delete e.previousComponent,e=r;o.reverse();const s=o.length;let u=0,l=0,d=0;for(;u<s;u++){const a=o[u];if(a.removed)a.value=this.join(i.slice(d,d+a.count)),d+=a.count;else{if(!a.added&&this.useLongestToken){let g=t.slice(l,l+a.count);g=g.map(function(v,f){const h=i[d+f];return h.length>v.length?h:v}),a.value=this.join(g)}else a.value=this.join(t.slice(l,l+a.count));l+=a.count,a.added||(d+=a.count)}}return o}}class R extends U{}const q=new R;function j(n,e,t){return q.diff(n,e,t)}const B=/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/,C=5e3,H=20,G=.2,E=.25;function J(n){const e=K(n);return X(e),e}function K(n){const e=Q(n),t=[];let i,o;for(const r of e){const s=B.exec(r);if(s!==null){i=Number(s[1]),o=Number(s[2]),t.push(m("hunk","",r));continue}if(i!==void 0&&o!==void 0){if(r.startsWith("+")){t.push(m("add","+",r.slice(1),{newLineNumber:o})),o++;continue}if(r.startsWith("-")){t.push(m("remove","-",r.slice(1),{oldLineNumber:i})),i++;continue}if(r.startsWith(" ")){t.push(m("context"," ",r.slice(1),{oldLineNumber:i,newLineNumber:o})),i++,o++;continue}if(r.startsWith("\\")){t.push(m("marker","",r));continue}}i=void 0,o=void 0,t.push(m("meta","",r))}return t}function Q(n){if(n==="")return[];const e=n.replace(/\r\n/g,`
2
- `).replace(/\r/g,`
3
- `).split(`
4
- `);return e.at(-1)===""&&e.pop(),e}function m(n,e,t,i={}){return{kind:n,prefix:e,text:t,spans:t===""?[]:[{text:t,changed:!1}],...i}}function X(n){let e=0;for(;e<n.length;){if(n[e]?.kind!=="remove"){e++;continue}const i=e;for(;n[e]?.kind==="remove";)e++;const o=e;for(;n[e]?.kind==="add";)e++;if(o===e)continue;const r=n.slice(i,o),s=n.slice(o,e);Y(r,s)}}function Y(n,e){if(!(n.length+e.length>H))for(const t of Z(n,e)){const i=te(t.removed.text,t.added.text);i!==void 0&&(t.removed.spans=i.removed,t.added.spans=i.added)}}function Z(n,e){if(n.length===e.length)return n.map((o,r)=>({removed:o,added:e[r]})).filter(T);if(n.length===1)return ee(n[0],e);if(e.length===1)return ne(n,e[0]);const t=[],i=Math.min(n.length,e.length);for(let o=0;o<i;o++){const r=n[o],s=e[o];r===void 0||s===void 0||O(r.text,s.text)>=E&&t.push({removed:r,added:s})}return t}function T(n){return n.added!==void 0}function ee(n,e){if(n===void 0)return[];const t=N(n.text,e);return t===void 0?[]:[{removed:n,added:t}]}function ne(n,e){if(e===void 0)return[];const t=N(e.text,n);return t===void 0?[]:[{removed:t,added:e}]}function N(n,e){let t,i=E;for(const o of e){const r=O(n,o.text);r<=i||(t=o,i=r)}return t}function te(n,e){if(n===e||n.length>C||e.length>C)return;const t=j(n,e),i=_(t,n,e);if(Math.max(n.length,e.length)>=20&&i<G)return;const o=[],r=[];for(const s of t)s.value!==""&&(s.added?r.push({text:s.value,changed:!0}):s.removed?o.push({text:s.value,changed:!0}):(o.push({text:s.value,changed:!1}),r.push({text:s.value,changed:!1})));if(!(!o.some(s=>s.changed)&&!r.some(s=>s.changed)))return{removed:M(o),added:M(r)}}function O(n,e){return n===e?1:n.length>C||e.length>C?0:_(j(n,e),n,e)}function _(n,e,t){const i=Math.max(e.length,t.length);return i===0?1:n.reduce((r,s)=>s.added||s.removed?r:r+s.value.length,0)/i}function M(n){const e=[];for(const t of n){const i=e[e.length-1];i?.changed===t.changed?i.text+=t.text:e.push({...t})}return e}var ie=Object.defineProperty,oe=Object.getOwnPropertyDescriptor,W=(n,e,t,i)=>{for(var o=i>1?void 0:i?oe(e,t):e,r=n.length-1,s;r>=0;r--)(s=n[r])&&(o=(i?s(e,t,o):s(o))||o);return i&&o&&ie(e,t,o),o};let L=class extends A{constructor(){super(...arguments),this.diff=""}render(){const n=J(this.diff);return n.length===0?P`<p class="empty">No diff.</p>`:P`
5
- <div class="scroller">
6
- <div class="diff-grid" role="table" aria-label="Unified diff">
7
- ${n.map(e=>this.renderLine(e))}
8
- </div>
9
- </div>
10
- `}renderLine(n){const e=n.kind;return P`
11
- <div class="line" role="row">
12
- <span class=${`cell line-number old ${e}`} role="cell">${I(n.oldLineNumber)}</span>
13
- <span class=${`cell line-number new ${e}`} role="cell">${I(n.newLineNumber)}</span>
14
- <span class=${`cell prefix ${e}`} role="cell">${n.prefix}</span>
15
- <span class=${`cell content ${e}`} role="cell">${re(n.spans)}</span>
16
- </div>
17
- `}};L.styles=V`
18
- :host { display: block; min-height: 0; height: 100%; color: var(--pi-text); background: var(--pi-bg); }
19
- .empty { box-sizing: border-box; margin: 0; padding: 10px; color: var(--pi-muted); }
20
- .scroller { height: 100%; min-height: 0; overflow: auto; background: var(--pi-bg); }
21
- .diff-grid { display: grid; grid-template-columns: max-content max-content 2ch max-content; width: max-content; min-width: 100%; padding: 6px 0; font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; line-height: 1.45; }
22
- .line { display: contents; }
23
- .cell { min-height: 1.45em; white-space: pre; }
24
- .line-number { min-width: 4ch; padding: 0 8px; border-right: 1px solid var(--pi-border-muted); color: var(--pi-dim); text-align: right; user-select: none; }
25
- .prefix { padding: 0 4px; color: var(--pi-dim); text-align: center; user-select: none; }
26
- .content { padding: 0 12px 0 4px; }
27
- .meta { color: var(--pi-dim); }
28
- .hunk { background: color-mix(in srgb, var(--pi-accent) 9%, transparent); color: var(--pi-accent); }
29
- .add { background: color-mix(in srgb, var(--pi-success) 12%, transparent); }
30
- .remove { background: color-mix(in srgb, var(--pi-danger) 12%, transparent); }
31
- .marker { color: var(--pi-dim); }
32
- .content.add .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-success) 36%, transparent); color: var(--pi-text); }
33
- .content.remove .inline-change { border-radius: 2px; background: color-mix(in srgb, var(--pi-danger) 36%, transparent); color: var(--pi-text); }
34
- `;W([z()],L.prototype,"diff",2);L=W([F("unified-diff-viewer")],L);function re(n){return n.map(e=>P`<span class=${e.changed?"inline-change":""}>${e.text}</span>`)}function I(n){return n===void 0?"":String(n)}export{L as UnifiedDiffViewer};