Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.3.0

Windows support (Ervisio 0.6). Plugins written for 0.2 run unchanged on Linux; the contract version stays 3.

- `Manifest.platforms` (`'linux' | 'windows'`, type `Platform`): where the plugin works (Ervisio 0.6.1). Missing = Linux only.
- `platforms` on `Command`, `HttpApi` and object `Folder` entries (Ervisio 0.6.2): per-system forms of one command or API
under one name; Windows named pipes as `socket`.
- `sdk.platform`: the server's system.
- docs/sdk.md: "Windows" section.

## 0.2.0

Needs Ervisio 0.5 for the new members; plugins written for 0.1 run unchanged and the contract version stays 3. The new
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Then turn on developer mode in Ervisio and load `dist/hello` from Plugins › De
The package is not on npm yet; the template depends on it through git:

```json
"devDependencies": { "@ervisio/plugin-sdk": "github:Ervisio/plugin-sdk#v0.2.0" }
"devDependencies": { "@ervisio/plugin-sdk": "github:Ervisio/plugin-sdk#v0.3.0" }
```

npm 12 refuses git dependencies by default; the template's `.npmrc` allows them for direct dependencies only
Expand Down
46 changes: 46 additions & 0 deletions docs/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ types (`Manifest`, `Capabilities`, `Command`, `HttpApi`, `Folder`, `Contributes`
| `version` | `3`. Check it if your plugin also supports older consoles: `if (sdk.version < 3) …` (v3 adds `api.http`, `api.httpStream`, `api.pty`, `files.mkdir`, `files.remove`). |
| `plugin` | `{ id, name, version }`. |
| `appOrigin` | The console's origin as the user reaches it (`https://host:9090`, or the proxy's). Use it for webhook URLs: `location.origin` is opaque inside the frame. Ervisio 0.5.0 and later. |
| `platform` | `'linux'` or `'windows'`: the server's system. Ervisio 0.6.1 and later; undefined (Linux) on older consoles. See "Windows" below. |
| `view` | `{ kind: 'page' \| 'widget', id }`: what this frame shows. |
| `react` | React 18, shared by the runtime and the UI kit. |
| `ui` | The app's own component kit (`Button`, `IconButton`, `Input`, `Select`, `Switch`, `Checkbox`, `Segmented`, `Table`, `Card`, `StatCard`, `Page`, `Panel`, `Dialog`, `ConfirmDialog`, `Sheet`, `Tabs`, `Badge`, `Chip`, `Progress`, `Skeleton`, `EmptyState`, `Menu`, `DropdownMenu`, `Tooltip`, `Icon`, `Sparkline`, `AreaChart`, `toast`, ...). `toast.ok/err/info(title, detail?)` shows the toast in the app, prefixed with your plugin's name. |
Expand Down Expand Up @@ -447,6 +448,51 @@ the field refuse the manifest ("unknown field"), with the same result. Put the s
when you publish (see [publishing.md](publishing.md)) so Browse shows "Needs a newer Ervisio" instead of an Install button.
To use a new member on a console that may be older, guard on it instead (`if (sdk.appOrigin)`, `if (sdk.api.jobs)`).

## Windows (SDK 0.3)

Ervisio 0.6 runs on Windows too. A plugin says where it works with `platforms` in the manifest:
`["linux"]`, `["windows"]` or `["linux", "windows"]`. Without it the plugin is Linux only (every plugin written
before 0.6 was). Plugins and Browse show a Linux and/or Windows mark next to Install, and a plugin for the other
system cannot be installed. `platforms` needs Ervisio 0.6.1: add `"minCore": "0.6.1"` (0.6.2 if you use the
per-entry form below), or older consoles refuse the manifest.

The page code, the UI kit and the SDK calls are the same on both systems. What differs is what the manifest
declares, so commands, HTTP APIs and folders take `platforms` too (Ervisio 0.6.2). Two entries may share a name
when their systems do not overlap; the daemon keeps the one for its system, so the page calls the same name:

```json
{
"platforms": ["linux", "windows"],
"minCore": "0.6.2",
"capabilities": {
"commands": [
{"name": "services", "argv": ["systemctl", "list-units", "--type=service", "--output=json"], "platforms": ["linux"]},
{"name": "services", "argv": ["powershell.exe", "-NoProfile", "-NonInteractive", "-Command", "Get-Service | Select-Object Name,Status | ConvertTo-Json"], "platforms": ["windows"]}
],
"http": [
{"name": "docker", "socket": "/run/docker.sock", "platforms": ["linux"], "rules": [{"methods": ["GET"], "path": "/.*"}]},
{"name": "docker", "socket": "\\\\.\\pipe\\docker_engine", "platforms": ["windows"], "rules": [{"methods": ["GET"], "path": "/.*"}]}
],
"files": {"read": [{"path": "/var/log/demo", "platforms": ["linux"]}, {"path": "C:\\ProgramData\\Demo", "platforms": ["windows"]}]}
}
}
```

```ts
const r = await sdk.api.exec('services'); // systemctl on Linux, PowerShell on Windows
const parse = sdk.platform === 'windows' ? parseGetService : parseSystemctl;
```

* Commands run without a shell on both systems. On Windows `argv[0]` is a program on the `PATH` (`powershell.exe`,
`sc.exe`, `netsh.exe`, `winget.exe`) or an absolute path. Keep PowerShell scripts fixed in the manifest and pass
values as `{N}` arguments (read them from `$args`), never build a script from user input.
* HTTP APIs: a unix socket, or on Windows a named pipe (`\\.\pipe\name`, only in an entry for `["windows"]`). Docker
Desktop and Docker Engine on Windows listen on `\\.\pipe\docker_engine`.
* Folders: `C:\dir` paths on Windows, `/dir` on Linux, `~/...` on both (the user's home or profile).
* `admin` asks members of Administrators to unlock administrator rights; `adminUnlessGroup` takes a Windows group
name (`docker-users`).
* `pty: true` commands run in a ConPTY on Windows.

## Styling

The frame already carries the app's tokens, the UI kit CSS and the Figtree / JetBrains Mono fonts. All theme tokens are
Expand Down
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ export interface PluginSDK {
* on older consoles it is undefined.
*/
appOrigin: string;
/** SDK 0.3: the server's system, `'linux'` or `'windows'` (Ervisio 0.6.1; undefined on older consoles, which are Linux). */
platform: 'linux' | 'windows';
plugin: { id: string; name: string; version: string };
/** What this frame shows. */
view: { kind: 'page' | 'widget'; id: string };
Expand Down
19 changes: 18 additions & 1 deletion manifest.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export interface Command {
* `docker` and argv must hold exactly one `{env}` item, which the daemon replaces with the environment's address.
*/
remote?: 'docker';
/** SDK 0.3: systems this entry is for (Ervisio 0.6.2). Missing = all the plugin's `platforms`. Two entries may share a name when their systems do not overlap; the daemon uses the one for its system. */
platforms?: Platform[];
}

/** One rule of an HTTP API: methods allowed on paths matching the regular expression. */
Expand All @@ -61,10 +63,19 @@ export interface HttpApi {
remote?: 'docker';
/** Default 30, max 600. */
timeoutSec?: number;
/**
* SDK 0.3: systems this entry is for (Ervisio 0.6.2). In an entry for `["windows"]` alone, `socket` may be a named
* pipe, `\\.\pipe\docker_engine`.
*/
platforms?: Platform[];
}

/** A capabilities.files entry: a path, or an object with options (SDK v3). */
export type Folder = string | { path: string; admin?: boolean; adminUnlessGroup?: string; create?: boolean };
/** A system Ervisio runs on. */
export type Platform = 'linux' | 'windows';

/** A capabilities.files entry. SDK 0.3: `platforms` limits it to some systems (Windows paths are `C:\\dir`). */
export type Folder = string | { path: string; admin?: boolean; adminUnlessGroup?: string; create?: boolean; platforms?: Platform[] };

/** A parameter of a job: the whole value must match `pattern`. */
export interface JobParam {
Expand Down Expand Up @@ -173,6 +184,12 @@ export interface Manifest {
minCore?: string;
/** `{ ervisio: ">=0.5.0" }`: another spelling of `minCore`. Only `>=` or a bare version is understood. */
requires?: { ervisio?: string };
/**
* SDK 0.3: the systems the plugin works on (Ervisio 0.6.1). Missing = Linux only. On another system the plugin is
* shown with a Linux/Windows mark but cannot be installed, enabled or run. Older cores refuse the field ("unknown
* field"), so add `minCore: "0.6.1"` with it.
*/
platforms?: Platform[];
/** sha256 of every file; written by the signer, never by hand. */
files?: Record<string, string>;
capabilities?: Capabilities;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ervisio/plugin-sdk",
"version": "0.2.0",
"version": "0.3.0",
"description": "Types, React shim and Vite preset for Ervisio plugins (plugin SDK contract version 3).",
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"typecheck": "tsc --noEmit"
},
"devDependencies": {
"@ervisio/plugin-sdk": "github:Ervisio/plugin-sdk#v0.2.0",
"@ervisio/plugin-sdk": "github:Ervisio/plugin-sdk#v0.3.0",
"@types/react": "^18.3.31",
"typescript": "^6.0.3",
"vite": "^8.3.2"
Expand Down
Loading