@jmfederico/pi-web 1.202606.6 → 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 (103) hide show
  1. package/README.md +87 -293
  2. package/dist/cli.js +25 -7
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client/assets/CodeViewer-tXF3UTsY.js +4 -0
  5. package/dist/client/assets/TerminalPanel-D_ihiWAt.js +187 -0
  6. package/dist/client/assets/UnifiedDiffViewer-BziirXBJ.js +39 -0
  7. package/dist/client/assets/index-Brfk1lwl.js +2950 -0
  8. package/dist/client/assets/vendor-editor-core-vUi74DnD.js +12 -0
  9. package/dist/client/assets/vendor-editor-languages-DoaXUodB.js +46 -0
  10. package/dist/client/assets/vendor-editor-legacy-CYBnW6ZU.js +1 -0
  11. package/dist/client/assets/vendor-terminal-BrP-ENHg.css +1 -0
  12. package/dist/client/assets/vendor-terminal-D8k4UKM2.js +35 -0
  13. package/dist/client/index.html +6 -3
  14. package/dist/config.js +33 -1
  15. package/dist/config.js.map +1 -1
  16. package/dist/docker/piWebDockerCommandPlan.js +211 -0
  17. package/dist/docker/piWebDockerCommandPlan.js.map +1 -0
  18. package/dist/pi-web-plugins/updates/pi-web-plugin.js +15 -5
  19. package/dist/pi-web-plugins/updates/updatesLogic.js +37 -5
  20. package/dist/piWebVersionReport.js +4 -0
  21. package/dist/piWebVersionReport.js.map +1 -1
  22. package/dist/plugin-api.d.ts +30 -2
  23. package/dist/server/app.js +32 -5
  24. package/dist/server/app.js.map +1 -1
  25. package/dist/server/browserMessageProjection.js +56 -0
  26. package/dist/server/browserMessageProjection.js.map +1 -0
  27. package/dist/server/configRoutes.js +112 -2
  28. package/dist/server/configRoutes.js.map +1 -1
  29. package/dist/server/machines/machineClient.js +51 -13
  30. package/dist/server/machines/machineClient.js.map +1 -1
  31. package/dist/server/machines/machineProxyRoutes.js +72 -4
  32. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  33. package/dist/server/machines/machineService.js +4 -26
  34. package/dist/server/machines/machineService.js.map +1 -1
  35. package/dist/server/piPackageRoutes.js +87 -0
  36. package/dist/server/piPackageRoutes.js.map +1 -0
  37. package/dist/server/piPackageService.js +69 -0
  38. package/dist/server/piPackageService.js.map +1 -0
  39. package/dist/server/piWebPluginService.js +43 -8
  40. package/dist/server/piWebPluginService.js.map +1 -1
  41. package/dist/server/piWebStatus.js +57 -0
  42. package/dist/server/piWebStatus.js.map +1 -1
  43. package/dist/server/realtime/sessionEventHub.js +2 -1
  44. package/dist/server/realtime/sessionEventHub.js.map +1 -1
  45. package/dist/server/sessions/attachmentService.js +69 -11
  46. package/dist/server/sessions/attachmentService.js.map +1 -1
  47. package/dist/server/sessions/builtinCommands.js +1 -1
  48. package/dist/server/sessions/builtinCommands.js.map +1 -1
  49. package/dist/server/sessions/piSessionManagerGateway.js +20 -2
  50. package/dist/server/sessions/piSessionManagerGateway.js.map +1 -1
  51. package/dist/server/sessions/piSessionService.js +905 -73
  52. package/dist/server/sessions/piSessionService.js.map +1 -1
  53. package/dist/server/sessions/sessionArchiveStore.js +51 -22
  54. package/dist/server/sessions/sessionArchiveStore.js.map +1 -1
  55. package/dist/server/sessions/sessionCleanup.js +157 -0
  56. package/dist/server/sessions/sessionCleanup.js.map +1 -0
  57. package/dist/server/sessions/sessionCommandService.js +16 -0
  58. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  59. package/dist/server/sessions/sessionNameGenerator.js +27 -44
  60. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  61. package/dist/server/sessions/sessionRoutes.js +55 -1
  62. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  63. package/dist/server/sessions/spawnSessionTool.js +9 -4
  64. package/dist/server/sessions/spawnSessionTool.js.map +1 -1
  65. package/dist/server/sessions/spawnSubsessionTool.js +28 -18
  66. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  67. package/dist/server/workspaceExplorerRoutes.js +55 -3
  68. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  69. package/dist/server/workspaces/fileContentService.js +112 -1
  70. package/dist/server/workspaces/fileContentService.js.map +1 -1
  71. package/dist/server/workspaces/fileSuggestions.js +7 -3
  72. package/dist/server/workspaces/fileSuggestions.js.map +1 -1
  73. package/dist/server/workspaces/pathSafety.js +16 -1
  74. package/dist/server/workspaces/pathSafety.js.map +1 -1
  75. package/dist/server/workspaces/projectPiWebConfig.js +6 -1
  76. package/dist/server/workspaces/projectPiWebConfig.js.map +1 -1
  77. package/dist/shared/activity.js +0 -15
  78. package/dist/shared/activity.js.map +1 -1
  79. package/dist/shared/apiTypes.d.ts +146 -7
  80. package/dist/shared/apiTypes.js +5 -0
  81. package/dist/shared/apiTypes.js.map +1 -1
  82. package/dist/shared/capabilities.js +29 -2
  83. package/dist/shared/capabilities.js.map +1 -1
  84. package/dist/shared/federatedRoutes.js +15 -0
  85. package/dist/shared/federatedRoutes.js.map +1 -1
  86. package/dist/shared/piWebStatusParsing.js +20 -8
  87. package/dist/shared/piWebStatusParsing.js.map +1 -1
  88. package/dist/shared/promptAttachments.js +30 -11
  89. package/dist/shared/promptAttachments.js.map +1 -1
  90. package/dist/shared/thinkingLevels.d.ts +1 -1
  91. package/dist/shared/thinkingLevels.js +1 -1
  92. package/dist/shared/thinkingLevels.js.map +1 -1
  93. package/docs/config.md +62 -14
  94. package/docs/plugins.md +155 -17
  95. package/package.json +35 -31
  96. package/dist/client/assets/CodeViewer-Bv8l_MFi.js +0 -4
  97. package/dist/client/assets/TerminalPanel-BZKsaE9s.js +0 -126
  98. package/dist/client/assets/index-C9oPLpm7.js +0 -2408
  99. package/dist/client/assets/vendor-editor-core-Bc1A7SO7.js +0 -12
  100. package/dist/client/assets/vendor-editor-languages-D0CnB2js.js +0 -26
  101. package/dist/client/assets/vendor-editor-legacy-B4QLsWF8.js +0 -1
  102. package/dist/client/assets/vendor-terminal-DDGTF8rc.css +0 -1
  103. package/dist/client/assets/vendor-terminal-DjQ08hXu.js +0 -16
@@ -5,7 +5,7 @@
5
5
  * either breaks, update this list and give the new level a label/description
6
6
  * where thinking levels are presented.
7
7
  */
8
- export const KNOWN_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"];
8
+ export const KNOWN_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
9
9
  export function isKnownThinkingLevel(value) {
10
10
  return KNOWN_THINKING_LEVELS.some((level) => level === value);
11
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"thinkingLevels.js","sourceRoot":"","sources":["../../src/shared/thinkingLevels.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAA6C,CAAC;AAEtI,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB,EAAE,SAA4B;IACnF,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACvE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"thinkingLevels.js","sourceRoot":"","sources":["../../src/shared/thinkingLevels.ts"],"names":[],"mappings":"AAQA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAA6C,CAAC;AAE7I,MAAM,UAAU,oBAAoB,CAAC,KAAa;IAChD,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAyB;IAC1D,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7D,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB,EAAE,SAA4B;IACnF,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC;IACvE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,MAAM,UAAU,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACvD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC"}
package/docs/config.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # PI WEB configuration reference
2
2
 
3
- PI WEB configuration covers the machine-local and project-local settings you usually need: the web/API bind address, trusted development-host settings, UI preferences, plugin enablement, file-explorer path access, upload limits, and session-daemon tools.
3
+ PI WEB configuration covers the machine-local and project-local settings you usually need: the web/API bind address, trusted development-host settings, UI preferences, plugin enablement, file-explorer path access, manual upload defaults, upload limits, and session-daemon tools.
4
4
 
5
5
  This file is the markdown reference for agents and package consumers. The website page is <https://pi-web.dev/config>.
6
6
 
@@ -11,27 +11,33 @@ PI WEB uses two config files:
11
11
  - **Global PI WEB config:** `$PI_WEB_CONFIG`, or `$XDG_CONFIG_HOME/pi-web/config.json`, or `~/.config/pi-web/config.json`.
12
12
  - **Project-local PI WEB config:** `<project>/.pi-web/config.json` for commit-able project settings.
13
13
 
14
- Each PI WEB machine has its own config. When using Fleet/machine federation, edit a remote machine's config by opening that machine directly or changing files on that machine.
14
+ Each PI WEB machine has its own config. When using Fleet/machine federation, Settings uses the selected machine for config that affects work running there: session daemon tools, PI WEB plugin enablement, external path access, and upload defaults. Gateway/browser-only settings stay local to the gateway: keyboard shortcuts, remote machine registry/tokens, and gateway host/port/allowed-hosts. Remote servers that do not advertise selected-machine settings support report those settings as unavailable instead of silently falling back to the gateway.
15
+
16
+ Pi package settings are separate from PI WEB config. They live in Pi's package-manager settings on the target machine and are managed by Pi (`pi install`, `pi remove`, `pi update`) or **Settings → Pi packages**. In a federated setup, **Settings → Pi packages** targets the currently selected machine. The PI WEB `plugins` config key only enables or disables discovered PI WEB browser plugins on the machine whose config you are editing; it does not install, remove, or update Pi packages.
15
17
 
16
18
  If you installed services with a custom config path, rerun `pi-web install --config /path/to/config.json` after changing that path or after upgrading from a version that only applied the custom path to the web service. This regenerates service files so the web/API and session daemon use the same `PI_WEB_CONFIG`.
17
19
 
18
20
  ## Precedence and reloads
19
21
 
20
- Runtime values are resolved as:
22
+ Machine-global runtime values are resolved as:
21
23
 
22
24
  ```text
23
- defaults → config file → environment overrides
25
+ defaults → global config file → environment overrides
24
26
  ```
25
27
 
28
+ Supported project-local settings are then applied for that project's workspaces. For upload defaults, `<project>/.pi-web/config.json` overrides the global value.
29
+
26
30
  Environment overrides include `PI_WEB_HOST`, `PI_WEB_PORT` / `PORT`, `PI_WEB_ALLOWED_HOSTS`, `PI_WEB_MAX_UPLOAD_BYTES`, `PI_WEB_SPAWN_SESSIONS`, and `PI_WEB_SUBSESSIONS`.
27
31
 
28
32
  Process restarts depend on the key:
29
33
 
30
- - `host` / `port`: restart the web/API service or process.
31
- - `maxUploadBytes`: restart both the web/API process and the session daemon.
32
- - `spawnSessions` / `subsessions`: restart the session daemon.
34
+ - `host` / `port`: restart the gateway web/API service or process.
35
+ - `maxUploadBytes`: restart both the web/API process and the session daemon on that machine.
36
+ - `spawnSessions` / `subsessions`: restart the session daemon on that machine.
33
37
  - `pathAccess`: applies on the next request; existing file views may need a browser refresh.
34
- - `plugins`: reload the browser tab after changing plugin enablement.
38
+ - `uploads.defaultFolder`: applies to newly opened Files upload dialogs and new direct drag/drop batches after config/workspace refresh.
39
+ - `plugins`: reload the browser tab after changing PI WEB plugin enablement.
40
+ - Pi package install/remove/update: not a PI WEB config key; after a mutation, 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 PI WEB browser plugin changes. A routine session daemon restart is not required.
35
41
  - `shortcuts`: saved settings apply in the browser after config refresh/save.
36
42
 
37
43
  ## Global config example
@@ -43,6 +49,9 @@ Process restarts depend on the key:
43
49
  "pathAccess": {
44
50
  "allowedPaths": ["~/SDKs", "/opt/reference"]
45
51
  },
52
+ "uploads": {
53
+ "defaultFolder": ".pi-web/uploads"
54
+ },
46
55
  "maxUploadBytes": 67108864,
47
56
  "spawnSessions": true,
48
57
  "subsessions": false,
@@ -67,17 +76,22 @@ Project-local config lives at `<project>/.pi-web/config.json`. Use it for settin
67
76
  "version": 1,
68
77
  "pathAccess": {
69
78
  "allowedPaths": ["~/SDKs", "/opt/reference"]
79
+ },
80
+ "uploads": {
81
+ "defaultFolder": "manual/uploads"
70
82
  }
71
83
  }
72
84
  ```
73
85
 
74
86
  Project-local `pathAccess.allowedPaths` entries are merged after the global list and deduplicated. Paths must still be host-absolute or `~`-prefixed; relative roots are not supported.
75
87
 
88
+ Project-local `uploads.defaultFolder` overrides the global upload destination for workspaces in that project. Current PI WEB servers include this workspace-effective value on the existing workspace responses used locally and through machine federation. Older remote servers may omit the optional field; the browser falls back to the global/default upload folder.
89
+
76
90
  Plugins may own separate project files, such as `.pi-web/tasks.json` for the built-in Workspace Tasks plugin.
77
91
 
78
92
  ## Configuration matrix
79
93
 
80
- Rows with JSON key `—` are runtime-only environment variables, not config-file keys.
94
+ Rows with JSON key `—` are runtime-only environment variables, not config-file keys. `Global` means machine-global. In Settings, selected-machine-safe global keys (`pathAccess`, `uploads`, `maxUploadBytes`, `spawnSessions`, `subsessions`, and `plugins`) are edited for the selected machine; gateway host/port/allowed-hosts, keyboard shortcuts, and machine registry/tokens stay local.
81
95
 
82
96
  | Config | JSON key | Env var | Scope | Project-local behavior | Applies / restart |
83
97
  | --- | --- | --- | --- | --- | --- |
@@ -86,9 +100,10 @@ Rows with JSON key `—` are runtime-only environment variables, not config-file
86
100
  | Web/API port | `port` | `PI_WEB_PORT`, `PORT` | Global | Not supported locally | Restart web/API |
87
101
  | Dev-server allowed hosts | `allowedHosts` | `PI_WEB_ALLOWED_HOSTS` | Global | Not supported locally | Restart dev web/UI |
88
102
  | External filesystem roots | `pathAccess.allowedPaths` | — | Global + project | **Merges**: global roots first, then project roots; duplicates removed | Next file request; refresh existing views if needed |
89
- | Upload/body limit | `maxUploadBytes` | `PI_WEB_MAX_UPLOAD_BYTES` | Global | Not supported locally | Restart web/API and session daemon |
90
- | Agent can spawn sessions | `spawnSessions` | `PI_WEB_SPAWN_SESSIONS` | Global/session daemon | Not supported locally | Restart session daemon |
91
- | Tracked subsessions (beta) | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon |
103
+ | Manual file upload default folder | `uploads.defaultFolder` | — | Global + project | **Overrides**: project value wins for workspaces in that project; otherwise global/default applies | New Upload dialogs and direct drag/drop batches after config/workspace refresh |
104
+ | Upload/body limit | `maxUploadBytes` | `PI_WEB_MAX_UPLOAD_BYTES` | Global | Not supported locally | Restart web/API and session daemon on that machine |
105
+ | Agent can spawn sessions | `spawnSessions` | `PI_WEB_SPAWN_SESSIONS` | Global/session daemon | Not supported locally | Restart session daemon on that machine |
106
+ | Tracked subsessions (beta) | `subsessions` | `PI_WEB_SUBSESSIONS` | Global/session daemon | Not supported locally; also requires `spawnSessions` | Restart session daemon on that machine |
92
107
  | Plugin enablement/settings | `plugins.<id>.enabled`, `plugins.<id>.settings` | — | Global | Not core local config; plugins may read their own project files | Reload browser tab |
93
108
  | Keyboard shortcuts | `shortcuts.<actionId>` | — | Global | Not supported locally | Applies after settings save/config refresh |
94
109
  | Project config version | `version` | — | Project | Project-local only; must be `1` when present | Next project-config read |
@@ -121,19 +136,52 @@ Accepted root forms:
121
136
 
122
137
  When an absolute request is served, PI WEB expands `~`, canonicalizes the configured roots with `realpath`, requires roots to be existing directories, and rejects symlink escapes outside the allowed roots.
123
138
 
139
+ In **Settings → General**, external filesystem roots are saved on the selected machine. Gateway host, port, and allowed-hosts fields stay on the gateway config.
140
+
124
141
  This is not a sandbox for the underlying Pi Coding Agent or your OS user. It only controls PI WEB UI/API file exposure outside a workspace.
125
142
 
143
+ ### Manual upload defaults
144
+
145
+ The Files panel can upload one or more files in two ways:
146
+
147
+ - Drop files onto the Files panel to upload immediately to the workspace-effective default folder.
148
+ - Use the toolbar **Upload** button to open the review dialog, edit the destination, and opt into upload options.
149
+
150
+ `uploads.defaultFolder` sets the workspace-effective default destination. The built-in default is `.pi-web/uploads`; a global config value applies to every project unless `<project>/.pi-web/config.json` sets a project-local override.
151
+
152
+ ```json
153
+ {
154
+ "uploads": {
155
+ "defaultFolder": "manual/uploads"
156
+ }
157
+ }
158
+ ```
159
+
160
+ The value must be a non-empty workspace-relative folder. PI WEB normalizes repeated separators and backslashes to `/`, and rejects absolute paths or `..` traversal. In the upload dialog only, clearing the destination field uploads that batch to the workspace root.
161
+
162
+ Manual uploads use the workspace file-write path: paths stay workspace-relative, parent folder creation is enabled by default, and overwrite is disabled by default. Direct drag/drop always keeps `overwrite` off; the review dialog lets you explicitly enable overwrite when needed. Browser-owned XHR progress is shown per batch/file, conflicts and errors stay visible in the upload progress UI, and the final file-write response is the source of truth.
163
+
164
+ For machine federation, Settings saves the global upload default on the selected machine. Current remote PI WEB servers also return `workspace.effectiveConfig.uploads.defaultFolder` on the existing workspace-list response. Older remote servers can omit that optional field without breaking clients; the Files panel falls back to the global/default upload folder.
165
+
166
+ The per-request size limit is still controlled by `maxUploadBytes` / `PI_WEB_MAX_UPLOAD_BYTES` on the machine serving the upload.
167
+
126
168
  ### Session daemon tools
127
169
 
128
170
  `spawnSessions` controls whether agents receive the `spawn_session` tool. It defaults to `true`; set it to `false` if you do not want an agent to start independent PI WEB sessions.
129
171
 
130
172
  `subsessions` is beta and controls whether agents receive the tracked-subsession tools: `spawn_subsession`, `list_subsessions`, `check_subsession`, and `read_subsession`. It defaults to `false` and also requires `spawnSessions` to be enabled.
131
173
 
132
- Tracked subsessions let an agent delegate work to child sessions, get notified when children stop working, and inspect their transcripts.
174
+ Tracked subsessions let an agent delegate work to child sessions, receive a notification when each child stops working, and inspect their status and transcripts. Calling `spawn_subsession` returns immediately. The parent can continue independent work while treating every child whose result it needs as pending. Before producing work that depends on those results, the parent reaches a join point and yields until every required child has sent a completion notice.
175
+
176
+ A completion notice wakes an idle parent. If the parent is busy, the notice queues until the current turn ends rather than interrupting in-flight work. For multiple required children, each notice resolves one pending child; after processing it, the parent yields again if another required child is pending. `list_subsessions`, `check_subsession`, and `read_subsession` provide on-demand status and transcript inspection for deliberate progress checks or recovery. Completion notifications, rather than polling these tools, are the normal synchronization mechanism.
177
+
178
+ In **Settings → Session daemon**, these keys are saved on the selected machine. Restart the session daemon on that machine after changing them.
133
179
 
134
180
  ### Plugin config
135
181
 
136
- Plugins are enabled by default. Set `plugins.<id>.enabled` to `false` to remove a plugin from `/pi-web-plugins/manifest.json` before the browser imports it.
182
+ The `plugins` key is only for PI WEB browser plugin enablement/settings on the machine whose config you are editing. It does not install, remove, or update Pi packages; use **Settings → Pi packages** or Pi's package manager for package operations. In a federated setup, **Settings → PI WEB plugins** and **Settings → Pi packages** both target the currently selected machine, and each panel labels where changes will be saved or run.
183
+
184
+ Plugins are enabled by default. Set `plugins.<id>.enabled` to `false` to remove a plugin from that machine's `/pi-web-plugins/manifest.json` before the browser imports it. Settings lists discovered plugins from the selected machine, including disabled entries exposed by that machine.
137
185
 
138
186
  ```json
139
187
  {
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
159
171
 
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.
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.
173
+
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
 
@@ -426,10 +440,13 @@ interface PluginAction {
426
440
  shortcut?: string;
427
441
  group?: string;
428
442
  enabled?: (context: PluginRuntimeContext) => boolean;
443
+ disabledReason?: (context: PluginRuntimeContext) => string | undefined;
429
444
  run: (context: PluginRuntimeContext) => void | Promise<void>;
430
445
  }
431
446
  ```
432
447
 
448
+ If an action is disabled and returns `disabledReason`, PI WEB can keep it visible in the action palette with that explanation instead of hiding it.
449
+
433
450
  Stable runtime context fields:
434
451
 
435
452
  ```ts
@@ -439,6 +456,7 @@ interface PluginRuntimeContext {
439
456
  selectedSession?: unknown;
440
457
  piWebStatus?: PiWebStatusResponse;
441
458
  };
459
+ prompt: PluginPromptEditor;
442
460
  openActionPalette: () => void;
443
461
  focusPrompt: () => void;
444
462
  addProject: () => void | Promise<void>;
@@ -464,6 +482,29 @@ Notes:
464
482
  - `openTerminal()` switches to the built-in terminal panel. Pass `{ terminalId }` to deep-link to a specific terminal.
465
483
  - Only fields documented here and declared in `plugin-api.d.ts` are stable public plugin API. Anything else is experimental: it may become public API later, change shape, or disappear.
466
484
 
485
+ ### Prompt editor API
486
+
487
+ The `prompt` helper on `PluginRuntimeContext` and `WorkspacePanelContext` provides stable access to the chat prompt editor:
488
+
489
+ | Method | Description |
490
+ | --- | --- |
491
+ | `insertText(text)` | Insert text at cursor position. When text is selected, replaces the selection. Focuses the editor first if not focused. |
492
+ | `getText()` | Returns the full prompt text. |
493
+ | `getSelection()` | Returns `{ start, end, text }` if text is selected, or `null`. |
494
+
495
+ Usage:
496
+
497
+ ```js
498
+ // Insert text at the cursor (e.g. a file mention)
499
+ context.prompt.insertText("@file.txt");
500
+
501
+ // Read the current prompt and selection
502
+ const text = context.prompt.getText();
503
+ const selection = context.prompt.getSelection(); // { start, end, text } | null
504
+ ```
505
+
506
+ Use `focusPrompt()` on `PluginRuntimeContext` to move focus to the prompt editor. Workspace panels can call `context.prompt.insertText()` from explicit user interactions such as button clicks; panel contexts target the currently selected session's mounted prompt editor.
507
+
467
508
  #### Keyboard shortcuts
468
509
 
469
510
  - App-level keyboard shortcuts must be attached to actions. PI WEB does not support standalone plugin keyboard commands; contribute an action first, then add a `shortcut` if it needs a keybinding.
@@ -521,7 +562,11 @@ interface WorkspacePanelContext {
521
562
  state?: PluginRuntimeState;
522
563
  files: {
523
564
  readFile(path: string): Promise<FileContentResponse>;
565
+ writeFile(path: string, content: string | Uint8Array, options?: WriteWorkspaceFileOptions): Promise<WriteWorkspaceFileResponse>;
566
+ deleteFile(path: string): Promise<DeleteWorkspaceFileResponse>;
567
+ moveFile(fromPath: string, toPath: string, options?: MoveWorkspaceFileOptions): Promise<MoveWorkspaceFileResponse>;
524
568
  };
569
+ prompt: PluginPromptEditor;
525
570
  terminal: {
526
571
  open(options?: { terminalId?: string }): void;
527
572
  runCommand(input: {
@@ -539,7 +584,7 @@ interface WorkspacePanelContext {
539
584
 
540
585
  `icon` is optional and is used in the compact mobile tab bar. Prefer an SVG rendered with the `svg` helper from `PluginActivationContext`; use `currentColor` so PI WEB themes can style it. If `icon` is omitted, mobile tabs fall back to initials from the panel title, or to the full title when initials collide.
541
586
 
542
- `machine`, `workspace`, `files`, `terminal`, and `host` are documented as stable for panel callbacks. Use `terminal.open()` to switch to the built-in terminal panel; pass `{ terminalId }` to deep-link to a specific terminal. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate panel callbacks such as `badge`, `visible`, or `render`.
587
+ `machine`, `workspace`, `files`, `prompt`, `terminal`, and `host` are documented as stable for panel callbacks. The `files` helper supports `readFile`, `writeFile`, `deleteFile`, and `moveFile` — see [Reading workspace files](#reading-workspace-files) and [Writing workspace files](#writing-workspace-files). The `prompt` helper supports panel interactions that insert workspace context into the current prompt — see [Prompt editor API](#prompt-editor-api). Use `terminal.open()` to switch to the built-in terminal panel; pass `{ terminalId }` to deep-link to a specific terminal. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate panel callbacks such as `badge`, `visible`, or `render`.
543
588
 
544
589
  For compatibility, PI WEB still provides the old `context.openTerminal()` workspace-panel helper at runtime. It is deprecated, intentionally omitted from the public TypeScript declarations, and planned for removal in v2. Existing JavaScript plugins keep working, while typed plugins should migrate to `context.terminal.open()`.
545
590
 
@@ -607,6 +652,9 @@ interface WorkspaceLabelContext {
607
652
  state?: PluginRuntimeState;
608
653
  files: {
609
654
  readFile(path: string): Promise<FileContentResponse>;
655
+ writeFile(path: string, content: string | Uint8Array, options?: WriteWorkspaceFileOptions): Promise<WriteWorkspaceFileResponse>;
656
+ deleteFile(path: string): Promise<DeleteWorkspaceFileResponse>;
657
+ moveFile(fromPath: string, toPath: string, options?: MoveWorkspaceFileOptions): Promise<MoveWorkspaceFileResponse>;
610
658
  };
611
659
  host: {
612
660
  requestRender(): void;
@@ -614,7 +662,7 @@ interface WorkspaceLabelContext {
614
662
  }
615
663
  ```
616
664
 
617
- `machine`, `workspace`, `files`, and `host` are documented as stable for label callbacks. Include `machine.id` in any label caches that depend on workspace data. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate label `visible` or `items` callbacks.
665
+ `machine`, `workspace`, `files`, and `host` are documented as stable for label callbacks. The `files` helper supports `readFile`, `writeFile`, `deleteFile`, and `moveFile` — see [Reading workspace files](#reading-workspace-files) and [Writing workspace files](#writing-workspace-files). Include `machine.id` in any label caches that depend on workspace data. Call `host.requestRender()` when async plugin-owned state changes should make PI WEB re-evaluate label `visible` or `items` callbacks.
618
666
 
619
667
  Items are sorted by `order` and then id. Return an empty array to render nothing. Keep callbacks synchronous and lightweight; start async work from the callback, return cached items, then call `host.requestRender()` when the cache changes.
620
668
 
@@ -712,7 +760,7 @@ Labels should use the same helper through a plugin-owned cache because `items()`
712
760
  const envCache = new Map();
713
761
 
714
762
  function envKey(machine, workspace) {
715
- return `${machine.id}:${workspace.id}:docker/development.be-go.local.env`;
763
+ return `${machine.id}:${workspace.id}:.env.local`;
716
764
  }
717
765
 
718
766
  function loadEnvLabel(context) {
@@ -722,7 +770,7 @@ function loadEnvLabel(context) {
722
770
 
723
771
  const pending = { status: "loading", label: undefined };
724
772
  envCache.set(key, pending);
725
- context.files.readFile("docker/development.be-go.local.env")
773
+ context.files.readFile(".env.local")
726
774
  .then((file) => {
727
775
  pending.status = "ready";
728
776
  pending.label = file.content.match(/^DEV_URL=(.+)$/m)?.[1];
@@ -753,6 +801,96 @@ workspaceLabels: [
753
801
 
754
802
  The file response includes fields such as `path`, `content`, `truncated`, and `binary`. Be careful with sensitive files such as `.env`: plugins are trusted browser code, and file contents are exposed to the plugin.
755
803
 
804
+ ## Writing, deleting, and moving workspace files
805
+
806
+ Workspace panels and workspace labels can write, delete, and move files through the documented `files` helper. Like `readFile`, PI WEB binds these helpers to the callback's machine and workspace, so they work the same for local and federated machines.
807
+
808
+ ### Writing files
809
+
810
+ ```js
811
+ workspacePanels: [
812
+ {
813
+ id: "workspace.generate",
814
+ title: "Generate",
815
+ render: ({ files }) => html`
816
+ <button @click=${async () => {
817
+ const result = await files.writeFile("output/result.txt", "Generated content\n");
818
+ console.log("Wrote", result.path, result.size, "bytes");
819
+ }}>Generate</button>
820
+ `,
821
+ },
822
+ ]
823
+ ```
824
+
825
+ ### Binary writes
826
+
827
+ Pass a `Uint8Array` for binary content such as images:
828
+
829
+ ```js
830
+ const png = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a]);
831
+ await files.writeFile("screenshots/thumb.png", png);
832
+ ```
833
+
834
+ ### Options
835
+
836
+ `files.writeFile` accepts an optional third argument:
837
+
838
+ - `createDirs` (default `true`): create intermediate directories, like `mkdir -p`.
839
+ - `overwrite` (default `true`): overwrite existing files. Set to `false` to throw if the file already exists.
840
+
841
+ ```js
842
+ // Create only — throw if the file already exists
843
+ await files.writeFile("config/new-config.json", jsonContent, { overwrite: false });
844
+ ```
845
+
846
+ ### Deleting files
847
+
848
+ `files.deleteFile` removes a workspace file. It is idempotent: deleting a file that does not exist returns `{ existed: false }` instead of throwing.
849
+
850
+ ```js
851
+ const result = await files.deleteFile("temp/cache.json");
852
+ console.log(result.existed ? "File deleted" : "File did not exist");
853
+ ```
854
+
855
+ ### Moving files
856
+
857
+ `files.moveFile` renames or moves a file within the workspace, like `mv`. The default is safe: it will not overwrite an existing target file.
858
+
859
+ ```js
860
+ // Rename a file
861
+ await files.moveFile("old-name.txt", "new-name.txt");
862
+
863
+ // Move into a subdirectory (creates intermediate dirs by default)
864
+ await files.moveFile("file.txt", "archive/file.txt");
865
+
866
+ // Overwrite an existing target
867
+ await files.moveFile("incoming.txt", "current.txt", { overwrite: true });
868
+
869
+ // Move without creating intermediate directories
870
+ await files.moveFile("file.txt", "deep/nested/file.txt", { createDirs: false }); // throws if dirs don't exist
871
+ ```
872
+
873
+ `files.moveFile` accepts an optional third argument:
874
+
875
+ - `createDirs` (default `true`): create intermediate directories for the target path.
876
+ - `overwrite` (default `false`): overwrite the target file if it exists. The default is safer than `writeFile` because moving is a more destructive operation.
877
+
878
+ ### Error handling
879
+
880
+ All file mutations share the same safety layer:
881
+
882
+ - `overwrite: false` on `writeFile` or existing target on `moveFile` (default) throws if the file already exists.
883
+ - Path traversal (e.g., `../../etc/passwd`) is blocked by the workspace safety layer.
884
+ - Writing to or moving to a path that is a directory returns an error.
885
+ - Deleting a directory returns an error.
886
+ - Intermediate directory creation with `createDirs: false` fails if the parent directory does not exist.
887
+
888
+ After any mutation (`writeFile`, `deleteFile`, or `moveFile`), the File Explorer updates automatically. No explicit `refreshFiles()` call is needed from plugin code. For label and badge updates, call `context.host.requestRender()` if the UI should reflect the change.
889
+
890
+ ### Security
891
+
892
+ Plugins are trusted browser code. File writes go through the same path safety validation as reads — paths are resolved and checked to stay inside the workspace root.
893
+
756
894
  ## Running workspace terminal commands
757
895
 
758
896
  Workspace panels can start terminal commands through the documented `terminal` helper. Commands run in the current workspace on the panel's machine.
@@ -801,7 +939,7 @@ If you are an AI agent building or editing a PI WEB plugin, follow this checklis
801
939
  9. Add workspace panels for larger workspace UI.
802
940
  10. Add workspace labels for compact inline metadata.
803
941
  11. Return arrays from workspace label `items()`; return an empty array to render nothing.
804
- 12. Use documented context helpers first: `files`, `terminal`, `host.requestRender`, `workspace`, `machine`, `state.selectedWorkspace`, `state.selectedSession`, and `state.piWebStatus`.
942
+ 12. Use documented context helpers first: `files`, `terminal`, `host.requestRender`, `workspace`, `machine`, `state.selectedWorkspace`, `state.selectedSession`, `state.piWebStatus`, and `prompt`.
805
943
  13. Do not fetch PI WEB `/api/...` endpoints directly unless you intentionally accept private API churn; prefer documented helpers.
806
944
  14. Treat plugins as trusted code and avoid reading or displaying secrets unless intentional.
807
945
  15. After local edits, tell the user to hard reload the browser and check the console for plugin errors.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmfederico/pi-web",
3
- "version": "1.202606.6",
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{w as a,J as p,$ as h,A as m,X as g,U as f,_ as v,a0 as b}from"./vendor-editor-core-Bc1A7SO7.js";import{g as y,r as w,p as C,h as x,c as j,m as _,j as k,a as u}from"./vendor-editor-languages-D0CnB2js.js";import{d as E}from"./vendor-editor-legacy-B4QLsWF8.js";import{i as H,b as O,a as S,n as d,e as P,t as L}from"./index-C9oPLpm7.js";var D=Object.defineProperty,F=Object.getOwnPropertyDescriptor,i=(e,o,n,s)=>{for(var t=s>1?void 0:s?F(o,n):o,c=e.length-1,l;c>=0;c--)(l=e[c])&&(t=(s?l(o,n,t):l(t))||t);return s&&t&&D(o,n,t),t};let r=class extends H{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 a({parent:this.editorHost,state:p.create({doc:this.content,extensions:[h(),m.of(g),f(v,{fallback:!0}),p.readOnly.of(!0),a.editable.of(!1),a.lineWrapping,M,...R(this.language)]})}))}};r.styles=S`
2
- :host { display: block; min-height: 0; height: 100%; }
3
- .host { height: 100%; min-height: 0; overflow: auto; }
4
- `;i([d()],r.prototype,"content",2);i([d()],r.prototype,"language",2);i([P(".host")],r.prototype,"editorHost",2);r=i([L("code-viewer")],r);const M=a.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"}});function R(e){if(e===void 0)return[];switch(e){case"typescript":return[u({typescript:!0})];case"javascript":return[u()];case"json":return[k()];case"markdown":return[_()];case"css":return[j()];case"html":return[x()];case"python":return[C()];case"rust":return[w()];case"go":return[y()];case"diff":return[b.define(E)];default:return[]}}export{r as CodeViewer};