Files
Termix/scripts/plugin-manifest.schema.json
T
LukeGus 2d6c1cdecb feat: add a permission-gated UI action registry and action slots for plugins
Moves the terminal toolbar's hardwired AI button into a slot the ssh-terminal
plugin offers and the ai plugin fills, gated on ai.services.use.
2026-09-21 16:56:15 -05:00

348 lines
11 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://termix.site/schemas/plugin-manifest.schema.json",
"title": "Termix Plugin Manifest",
"type": "object",
"additionalProperties": false,
"required": [
"id",
"name",
"version",
"description",
"author",
"license",
"engine",
"category",
"capabilities",
"permissions",
"sidecars"
],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z0-9-]+$",
"description": "Unique plugin id, lowercase alphanumeric and hyphens only."
},
"name": {
"type": "string",
"minLength": 1
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$",
"description": "Semver version string."
},
"description": {
"type": "string",
"minLength": 1
},
"author": {
"type": "object",
"additionalProperties": false,
"required": ["name"],
"properties": {
"name": { "type": "string", "minLength": 1 },
"url": { "type": "string", "format": "uri" }
}
},
"license": {
"type": "string",
"minLength": 1
},
"repository": {
"type": "string",
"format": "uri"
},
"category": {
"type": "string",
"enum": [
"Terminal",
"Files & Transfer",
"Infrastructure",
"Monitoring",
"Networking",
"Access & Security",
"Productivity"
],
"description": "Store category used for browsing/filtering. Must match one of the categories the store UI filters by."
},
"icon": {
"type": "string",
"minLength": 1,
"description": "Either a Lucide icon name (same convention as contributes.tabs[].icon) or a relative path to an icon.svg shipped in the plugin package root. If both a Lucide name and an icon.svg are present, the registry-index build should prefer icon.svg."
},
"engine": {
"type": "object",
"additionalProperties": false,
"required": ["termix", "api"],
"properties": {
"termix": {
"type": "string",
"minLength": 1,
"description": "Informational-only Termix version range this plugin targets. Not mechanically enforced."
},
"api": {
"type": "string",
"pattern": "^[0-9]+$",
"description": "Plugin SDK major version, as a string. The real compatibility gate."
}
}
},
"capabilities": {
"type": "object",
"additionalProperties": false,
"required": ["backend", "frontend", "electron", "platforms"],
"properties": {
"backend": { "type": "boolean" },
"frontend": { "type": "boolean" },
"electron": { "type": "boolean" },
"platforms": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
}
},
"permissions": {
"type": "array",
"items": {
"type": "string",
"enum": [
"hosts.read",
"hosts.write",
"credentials.use",
"ssh.exec",
"ssh.sftp",
"storage.own",
"storage.secrets",
"network.outbound",
"events.read",
"notify.send",
"users.read",
"process.sidecar",
"process:transport-owner",
"ui.tab",
"ui.rail",
"ui.card",
"ui.settings",
"ui.palette"
]
}
},
"contributes": {
"type": "object",
"additionalProperties": false,
"properties": {
"tabs": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "titleKey", "icon", "openFrom"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"titleKey": { "type": "string", "minLength": 1 },
"icon": { "type": "string", "minLength": 1 },
"openFrom": {
"type": "array",
"items": {
"type": "string",
"enum": ["rail", "host-context-menu", "palette"]
},
"minItems": 1
}
}
}
},
"hostCapability": {
"type": "object",
"additionalProperties": false,
"required": ["key", "labelKey", "editorTab"],
"properties": {
"key": { "type": "string", "minLength": 1 },
"labelKey": { "type": "string", "minLength": 1 },
"editorTab": { "type": "string", "minLength": 1 }
}
},
"permissionGroup": {
"type": "object",
"additionalProperties": false,
"required": ["group", "permissions"],
"properties": {
"group": { "type": "string", "minLength": 1 },
"permissions": {
"type": "array",
"items": { "type": "string", "minLength": 1 },
"minItems": 1
},
"defaultForRole": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
}
}
},
"settingsPanel": {
"type": "object",
"additionalProperties": false,
"required": ["titleKey"],
"properties": {
"titleKey": { "type": "string", "minLength": 1 }
}
},
"dashboardCards": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "titleKey"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"titleKey": { "type": "string", "minLength": 1 }
}
}
},
"apiPrefix": {
"type": "string",
"pattern": "^[a-z0-9-]+$",
"description": "Mounted at /plugin-api/<id>/<apiPrefix>/*."
},
"actions": {
"type": "array",
"description": "Named frontend actions this plugin exposes for other plugins to invoke.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "titleKey", "handler"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z0-9-]+(\\.[a-zA-Z0-9-]+)+$",
"description": "Dotted, globally unique action name, e.g. \"ai.openWithContext\"."
},
"titleKey": { "type": "string", "minLength": 1 },
"handler": {
"type": "string",
"pattern": "^[A-Za-z_$][A-Za-z0-9_$]*$",
"description": "Name of the frontend export implementing this action. The runtime binding is registerAction(id, fn)."
},
"icon": { "type": "string", "minLength": 1 },
"permission": {
"type": "string",
"minLength": 1,
"description": "Role permission a user needs. Must also appear in contributes.permissionGroup.permissions."
},
"slot": {
"type": "string",
"pattern": "^[a-z0-9-]+(\\.[a-zA-Z0-9-]+)+$",
"description": "Slot this action is intended for. Advisory; binding happens at runtime."
},
"kind": { "type": "string", "enum": ["button"] }
}
}
},
"actionSlots": {
"type": "array",
"description": "Places this plugin offers other plugins to contribute a UI element.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "accepts"],
"properties": {
"id": {
"type": "string",
"pattern": "^[a-z0-9-]+(\\.[a-zA-Z0-9-]+)+$",
"description": "Dotted slot name, e.g. \"terminal.toolbar\"."
},
"accepts": {
"type": "array",
"minItems": 1,
"items": { "type": "string", "enum": ["button"] },
"description": "Contribution kinds this slot will render. Checked in the frontend at registration time."
},
"descriptionKey": { "type": "string", "minLength": 1 }
}
}
}
}
},
"dependencies": {
"type": "object",
"additionalProperties": false,
"properties": {
"plugins": {
"type": "object",
"additionalProperties": {
"type": "string",
"minLength": 1,
"description": "Semver range string."
}
}
}
},
"provides": {
"type": "array",
"description": "Named services this plugin exposes to other plugins.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["service", "version", "permission"],
"properties": {
"service": {
"type": "string",
"pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+$",
"description": "Dotted service name, e.g. \"ssh.transport\"."
},
"version": {
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-.]+)?(\\+[0-9A-Za-z-.]+)?$",
"description": "Semver version of this service contract."
},
"permission": {
"type": "string",
"minLength": 1,
"description": "Role permission a calling user needs. Must also appear in contributes.permissionGroup.permissions."
}
}
}
},
"requires": {
"type": "array",
"description": "Named services this plugin needs another active plugin to provide.",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["service", "versionRange"],
"properties": {
"service": {
"type": "string",
"pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+$"
},
"versionRange": {
"type": "string",
"minLength": 1,
"description": "Semver range, e.g. \"^1.2.0\"."
},
"optional": {
"type": "boolean",
"description": "When true, an unsatisfied requirement is skipped instead of failing activation."
}
}
}
},
"sidecars": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id", "binary"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"binary": { "type": "string", "minLength": 1 }
}
}
}
}
}