Rework the bundled Info plugin from a demo into an always-available
status view: running and installed versions, installation details,
release state, and per-service health rendered from host-provided
state, plus machine and workspace details. Replace the window.alert
demo action with a Copy PI WEB Diagnostics action that copies a
plain-text summary for bug reports.
Add state.selectedMachine to the stable plugin runtime state so
actions and other runtime callbacks can read the selected machine's
identity, and split the plugin into a copy-paste-friendly skeleton
(pi-web-plugin.ts) and replaceable internals (infoInternals.ts).
Builds on marcus's plugin-api-completeness work. Narrows the new plugin
surface to capabilities that expose real, otherwise-unreachable pi-web
functionality, and drops invented/duplicative surfaces:
Kept:
- files.writeFile / deleteFile / moveFile (genuine workspace mutation,
federated, path-safe)
- prompt.insertText / getText / getSelection (editor state access)
Dropped:
- attachments.* (insertFileReference/getAttachedFiles/removeFileReference):
getAttachedFiles invented a structured-attachment notion pi-web does not
have and duplicated prompt.getText() + a regex with a false email-safety
claim; insert/removeFileReference were thin sugar over readFile +
insertText that plugins can compose themselves.
- prompt.onPaste / onKeyDown: an incomplete two-event hook system shaped
around a single use case, overlapping the editor's native image-paste
handling. Deferred until a real editor event/hook surface is designed.
- prompt.focus: redundant and buggier duplicate of the existing
focusPrompt() (silently no-ops when not on the chat view). Focus stays
as focusPrompt().
Security fix:
- deleteWorkspaceFile now resolves the parent via realpath + ensureInside
before lstat/unlink, closing a symlinked-parent-directory escape that
allowed deleting files outside the workspace (write/move already did
this). Final path component is still not resolved, so deleting a symlink
removes the link, not its target. Adds a regression test.
Docs and the registry test mock updated to match the trimmed surface.
- WorkspaceFiles: writeFile, deleteFile, moveFile with path safety
- writeFile: text/binary, auto-create dirs, overwrite option
- deleteFile: idempotent, uses lstat (removes symlinks not targets)
- moveFile: unix mv semantics, overwrite defaults to false
- All mutations auto-refreshFiles() in File Explorer
- Symlink escape prevention via realpath(dirname) check
- PluginPromptEditor: insertText, getText, getSelection, onPaste, onKeyDown, focus
- Uses CM6 EditorView.domEventHandlers() via Compartment (not raw DOM)
- Handlers registered before mount are preserved and applied on mount
- First-to-consume-wins ordering for multi-plugin scenarios
- insertText replaces selection (not inserts after)
- PluginAttachments: insertFileReference, getAttachedFiles, removeFileReference
- insertFileReference validates file exists before inserting @path
- Does not auto-focus editor (unlike prompt.insertText)
- @file regex requires file extension to avoid matching emails
- Server endpoints: PUT /file, DELETE /file, POST /file/move
- All work for local and federated machines
- Tests: 31 unit tests, 9 integration tests, 5 client tests
- Docs: 3 new sections in plugins.md