@termix-ssh/plugin-sdk 1.0.22 → 1.0.23
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.
- package/CHANGELOG.md +11 -0
- package/PLUGIN-GUIDE.md +69 -1
- package/dist/backend.d.ts +107 -0
- package/dist/capabilities.js +3 -0
- package/dist/host/{PluginsTab-CM2B33BD.js → PluginsTab-MNQU5OJ3.js} +4 -4
- package/dist/host/{chunk-P26QKKU5.js → chunk-6WLECSNB.js} +35 -5
- package/dist/host/{chunk-TK3Y437H.js → chunk-BP42N374.js} +1 -1
- package/dist/host/{chunk-ROB2SH5Q.js → chunk-C52NRTA6.js} +9 -5
- package/dist/host/{chunk-VKNGNEF3.js → chunk-DN6YKMFJ.js} +1 -1
- package/dist/host/{chunk-I5F2PSMR.js → chunk-GBBKHJRQ.js} +9 -9
- package/dist/host/{chunk-JRV2HIDK.js → chunk-GRH7GSKG.js} +1 -1
- package/dist/host/{chunk-7J4QNGFM.js → chunk-IMPLAAUM.js} +1 -1
- package/dist/host/{chunk-HQ6NNFSX.js → chunk-X65V7ZRW.js} +15 -3
- package/dist/host/core-classes.json +1 -1
- package/dist/host/frame-host.css +1 -1
- package/dist/host/frame-host.js +5 -5
- package/dist/host/{linked-server-J5G457OA.js → linked-server-YCAJ2NX3.js} +1 -1
- package/dist/host/{rbac-api-PY22W5UY.js → rbac-api-A64TXDL5.js} +1 -1
- package/dist/host/testing-host.js +6 -6
- package/dist/host/types/src/ui/lib/db-health-monitor.d.ts +5 -0
- package/dist/host/ui.js +9 -9
- package/dist/host/{use-permissions-EWRI3WLT.js → use-permissions-FLQAN6I7.js} +1 -1
- package/dist/manifest.d.ts +6 -1
- package/dist/manifest.js +7 -1
- package/dist/operations.d.ts +222 -0
- package/dist/operations.js +650 -0
- package/dist/testing.d.ts +9 -1
- package/dist/testing.js +45 -0
- package/package.json +5 -1
- package/schema/manifest.schema.json +25 -0
package/dist/host/frame-host.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const __termixNoGlob = () => ({});
|
|
2
2
|
import {
|
|
3
3
|
Toaster
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BP42N374.js";
|
|
5
5
|
import {
|
|
6
6
|
ThemeProvider,
|
|
7
7
|
createPluginApp,
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
setPluginThemes,
|
|
13
13
|
sshHostToHost,
|
|
14
14
|
useTheme
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-X65V7ZRW.js";
|
|
16
|
+
import "./chunk-GRH7GSKG.js";
|
|
17
17
|
import {
|
|
18
18
|
SurfaceScope,
|
|
19
19
|
notifyShellReady,
|
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
setShellCallbacks,
|
|
22
22
|
setShellHosts,
|
|
23
23
|
shellHost
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-DN6YKMFJ.js";
|
|
25
25
|
import {
|
|
26
26
|
getSSHHosts,
|
|
27
27
|
getTabType,
|
|
28
28
|
setFrontendState,
|
|
29
29
|
setPluginSummaries
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-6WLECSNB.js";
|
|
31
31
|
import {
|
|
32
32
|
init_define_import_meta_env
|
|
33
33
|
} from "./chunk-YGYBM7SQ.js";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
PluginViewPlaceholder,
|
|
8
8
|
renderTabContent,
|
|
9
9
|
trackTabHandle
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GBBKHJRQ.js";
|
|
11
11
|
import {
|
|
12
12
|
RAIL_ITEMS,
|
|
13
13
|
ServerStatusProvider,
|
|
@@ -61,11 +61,11 @@ import {
|
|
|
61
61
|
setRemoteServerUrlForTesting,
|
|
62
62
|
useShellController,
|
|
63
63
|
useTabStageStore
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-X65V7ZRW.js";
|
|
65
65
|
import {
|
|
66
66
|
setPermissionsForTesting
|
|
67
|
-
} from "./chunk-
|
|
68
|
-
import "./chunk-
|
|
67
|
+
} from "./chunk-GRH7GSKG.js";
|
|
68
|
+
import "./chunk-IMPLAAUM.js";
|
|
69
69
|
import {
|
|
70
70
|
SurfaceScope,
|
|
71
71
|
notifyShellReady,
|
|
@@ -73,14 +73,14 @@ import {
|
|
|
73
73
|
setShellCallbacks,
|
|
74
74
|
setShellHosts,
|
|
75
75
|
setShellLayoutProvider
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-DN6YKMFJ.js";
|
|
77
77
|
import {
|
|
78
78
|
getTabType,
|
|
79
79
|
listTabTypes,
|
|
80
80
|
resetPluginStore,
|
|
81
81
|
setFrontendState,
|
|
82
82
|
setPluginSummaries
|
|
83
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-6WLECSNB.js";
|
|
84
84
|
import {
|
|
85
85
|
init_define_import_meta_env
|
|
86
86
|
} from "./chunk-YGYBM7SQ.js";
|
|
@@ -19,6 +19,8 @@ declare class DatabaseHealthMonitor {
|
|
|
19
19
|
private static instance;
|
|
20
20
|
private listeners;
|
|
21
21
|
private degradedActive;
|
|
22
|
+
private probe;
|
|
23
|
+
private probing;
|
|
22
24
|
private constructor();
|
|
23
25
|
static getInstance(): DatabaseHealthMonitor;
|
|
24
26
|
on(event: string, listener: EventListener): void;
|
|
@@ -26,6 +28,9 @@ declare class DatabaseHealthMonitor {
|
|
|
26
28
|
private emit;
|
|
27
29
|
reportSessionExpired(): void;
|
|
28
30
|
reportDatabaseError(error: unknown): void;
|
|
31
|
+
/** Sets the quick check used after a request times out. */
|
|
32
|
+
setReachabilityProbe(probe: (() => Promise<boolean>) | null): void;
|
|
33
|
+
private markDegraded;
|
|
29
34
|
reportDatabaseSuccess(): void;
|
|
30
35
|
isDegraded(): boolean;
|
|
31
36
|
reset(): void;
|
package/dist/host/ui.js
CHANGED
|
@@ -21,10 +21,10 @@ import {
|
|
|
21
21
|
useInstalledPlugins,
|
|
22
22
|
usePluginHostSections,
|
|
23
23
|
useTabHandlesVersion
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-GBBKHJRQ.js";
|
|
25
25
|
import {
|
|
26
26
|
Toaster
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-BP42N374.js";
|
|
28
28
|
import {
|
|
29
29
|
ACCENT_PRESET_COLORS,
|
|
30
30
|
BUILTIN_THEMES,
|
|
@@ -165,10 +165,10 @@ import {
|
|
|
165
165
|
useThemes,
|
|
166
166
|
verifySecondFactor,
|
|
167
167
|
withProtocolSettings
|
|
168
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-X65V7ZRW.js";
|
|
169
169
|
import {
|
|
170
170
|
usePermissions
|
|
171
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-GRH7GSKG.js";
|
|
172
172
|
import {
|
|
173
173
|
AddButton,
|
|
174
174
|
Card,
|
|
@@ -189,7 +189,7 @@ import {
|
|
|
189
189
|
isPrerelease,
|
|
190
190
|
reportBetaFeedbackUrl,
|
|
191
191
|
reportCoreIssueUrl
|
|
192
|
-
} from "./chunk-
|
|
192
|
+
} from "./chunk-C52NRTA6.js";
|
|
193
193
|
import {
|
|
194
194
|
Button,
|
|
195
195
|
DefaultsOnly,
|
|
@@ -206,7 +206,7 @@ import {
|
|
|
206
206
|
hasVisibleFields,
|
|
207
207
|
isFieldShown,
|
|
208
208
|
useIsDefaultsEditor
|
|
209
|
-
} from "./chunk-
|
|
209
|
+
} from "./chunk-IMPLAAUM.js";
|
|
210
210
|
import {
|
|
211
211
|
Action,
|
|
212
212
|
Activity,
|
|
@@ -381,7 +381,7 @@ import {
|
|
|
381
381
|
useSurfaceKind,
|
|
382
382
|
useUiPreference,
|
|
383
383
|
useUiPreferencesContext
|
|
384
|
-
} from "./chunk-
|
|
384
|
+
} from "./chunk-DN6YKMFJ.js";
|
|
385
385
|
import {
|
|
386
386
|
CREDENTIAL_ROW_FIELD_KEYS,
|
|
387
387
|
PRESETS,
|
|
@@ -544,7 +544,7 @@ import {
|
|
|
544
544
|
useTabs,
|
|
545
545
|
useTabsSafe,
|
|
546
546
|
verifyPasswordResetCode
|
|
547
|
-
} from "./chunk-
|
|
547
|
+
} from "./chunk-6WLECSNB.js";
|
|
548
548
|
import {
|
|
549
549
|
define_import_meta_env_default,
|
|
550
550
|
init_define_import_meta_env
|
|
@@ -557,7 +557,7 @@ init_define_import_meta_env();
|
|
|
557
557
|
init_define_import_meta_env();
|
|
558
558
|
import { jsx } from "react/jsx-runtime";
|
|
559
559
|
var alertVariants = cva(
|
|
560
|
-
"relative w-full border border-border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
560
|
+
"relative w-full border border-border px-4 py-3 text-sm not-has-[>svg]:block grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
|
561
561
|
{
|
|
562
562
|
variants: {
|
|
563
563
|
variant: {
|
package/dist/manifest.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* "permissionGroups" used to validate clean and be silently dropped, which
|
|
10
10
|
* made a manifest look like it declared something it did not.
|
|
11
11
|
*/
|
|
12
|
+
import { type PluginOperationsContribution } from "./operations.js";
|
|
12
13
|
import { type PluginEnvVar } from "./docs.js";
|
|
13
14
|
export { validateThemeCss } from "./theme-css.js";
|
|
14
15
|
export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDocsUrl, pluginEnvVars, type PluginEnvVar, } from "./docs.js";
|
|
@@ -20,7 +21,7 @@ export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDoc
|
|
|
20
21
|
* "^1.2" needs 1.2 or later). engine.termix is checked against the core
|
|
21
22
|
* version by the server.
|
|
22
23
|
*/
|
|
23
|
-
export declare const PLUGIN_API_VERSION = "1.
|
|
24
|
+
export declare const PLUGIN_API_VERSION = "1.14.0";
|
|
24
25
|
/** The API major, the default engine.api for a new plugin. */
|
|
25
26
|
export declare const SUPPORTED_PLUGIN_API_VERSION: string;
|
|
26
27
|
/** Whether this build's plugin API satisfies a manifest's engine.api. */
|
|
@@ -305,6 +306,10 @@ export interface PluginContributions {
|
|
|
305
306
|
tabs?: PluginTabContribution[];
|
|
306
307
|
panels?: PluginViewContribution[];
|
|
307
308
|
dashboardCards?: PluginViewContribution[];
|
|
309
|
+
/** Cards on the host page, filled with app.registerHostSection. */
|
|
310
|
+
hostSections?: PluginViewContribution[];
|
|
311
|
+
/** What this plugin can do, for every surface to find on its own. */
|
|
312
|
+
operations?: PluginOperationsContribution;
|
|
308
313
|
/**
|
|
309
314
|
* The frontend also runs on anonymous guest pages (shared-session and
|
|
310
315
|
* collab links), where it is activated with app.guest set.
|
package/dist/manifest.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import semver from "semver";
|
|
13
13
|
import { isKnownCapability } from "./capabilities.js";
|
|
14
|
+
import { checkOperationReferences, validateOperations, } from "./operations.js";
|
|
14
15
|
import { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsUrl, } from "./docs.js";
|
|
15
16
|
export { validateThemeCss } from "./theme-css.js";
|
|
16
17
|
export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDocsUrl, pluginEnvVars, } from "./docs.js";
|
|
@@ -22,7 +23,7 @@ export { ENV_NAME_PATTERN, MAX_ENV_DESCRIPTION_LENGTH, pluginDocsPage, pluginDoc
|
|
|
22
23
|
* "^1.2" needs 1.2 or later). engine.termix is checked against the core
|
|
23
24
|
* version by the server.
|
|
24
25
|
*/
|
|
25
|
-
export const PLUGIN_API_VERSION = "1.
|
|
26
|
+
export const PLUGIN_API_VERSION = "1.14.0";
|
|
26
27
|
/** The API major, the default engine.api for a new plugin. */
|
|
27
28
|
export const SUPPORTED_PLUGIN_API_VERSION = String(semver.major(PLUGIN_API_VERSION));
|
|
28
29
|
/** Whether this build's plugin API satisfies a manifest's engine.api. */
|
|
@@ -245,6 +246,8 @@ const ALLOWED_CONTRIBUTES = new Set([
|
|
|
245
246
|
"tabs",
|
|
246
247
|
"panels",
|
|
247
248
|
"dashboardCards",
|
|
249
|
+
"hostSections",
|
|
250
|
+
"operations",
|
|
248
251
|
"guest",
|
|
249
252
|
"guestViews",
|
|
250
253
|
"actions",
|
|
@@ -835,6 +838,8 @@ function validateContributes(contributes, pluginId, errors) {
|
|
|
835
838
|
validateTabs(contributes.tabs, errors);
|
|
836
839
|
validateViews(contributes.panels, "panels", errors);
|
|
837
840
|
validateViews(contributes.dashboardCards, "dashboardCards", errors);
|
|
841
|
+
validateViews(contributes.hostSections, "hostSections", errors);
|
|
842
|
+
validateOperations(contributes.operations, pluginId, errors);
|
|
838
843
|
if (contributes.guest !== undefined &&
|
|
839
844
|
typeof contributes.guest !== "boolean") {
|
|
840
845
|
errors.push('Field "contributes.guest" must be a boolean');
|
|
@@ -1767,6 +1772,7 @@ export function parseManifest(raw) {
|
|
|
1767
1772
|
errors.push(`contributes.actions["${action.id}"].permission "${action.permission}" is not declared in contributes.permissions`);
|
|
1768
1773
|
}
|
|
1769
1774
|
}
|
|
1775
|
+
checkOperationReferences(manifest.contributes?.operations, manifest.capabilities, (name) => declared.has(qualifyPermission(manifest.id, name)), errors);
|
|
1770
1776
|
// A settings field may gate on one of this plugin's own permissions, or on
|
|
1771
1777
|
// a core/other-plugin id used as given. Only the first form is checkable
|
|
1772
1778
|
// here, and an undeclared one would hide the field from every admin.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The operations contract: what a plugin declares it can do, in one shape every
|
|
3
|
+
* surface reads (Automations, Fleets, AI, CLI, Mobile, palette, API, MCP).
|
|
4
|
+
*
|
|
5
|
+
* Declarations are data in the manifest, so a surface can list and describe an
|
|
6
|
+
* action without loading the plugin's code. Handlers are registered at
|
|
7
|
+
* activation with ctx.operations.register and must match a declaration.
|
|
8
|
+
*
|
|
9
|
+
* No Node imports: the frontend, the CLI and Mobile read this file too.
|
|
10
|
+
*/
|
|
11
|
+
import type { PluginSettingsOption } from "./manifest.js";
|
|
12
|
+
export declare const OPERATION_RISKS: readonly ["read", "change", "destructive"];
|
|
13
|
+
export type OperationRisk = (typeof OPERATION_RISKS)[number];
|
|
14
|
+
export declare const OPERATION_SCOPES: readonly ["host", "resource", "server"];
|
|
15
|
+
export type OperationScope = (typeof OPERATION_SCOPES)[number];
|
|
16
|
+
export declare const OPERATION_HOST_ACCESS: readonly ["connect", "view", "edit", "manage"];
|
|
17
|
+
export type OperationHostAccess = (typeof OPERATION_HOST_ACCESS)[number];
|
|
18
|
+
export declare const OPERATION_DRY_RUN: readonly ["native", "describe"];
|
|
19
|
+
/** native: the handler checks ctx.dryRun. describe: core reports its text. */
|
|
20
|
+
export type OperationDryRun = (typeof OPERATION_DRY_RUN)[number];
|
|
21
|
+
export declare const OPERATION_FIELD_TYPES: readonly ["boolean", "string", "number", "select", "multiselect", "secret", "textarea", "json", "resource"];
|
|
22
|
+
export type OperationFieldType = (typeof OPERATION_FIELD_TYPES)[number];
|
|
23
|
+
export declare const OPERATION_SEVERITIES: readonly ["info", "warning", "critical"];
|
|
24
|
+
export type OperationSeverity = (typeof OPERATION_SEVERITIES)[number];
|
|
25
|
+
export declare const SIGNAL_KINDS: readonly ["count", "gauge", "status", "list"];
|
|
26
|
+
export type SignalKind = (typeof SIGNAL_KINDS)[number];
|
|
27
|
+
export declare const SIGNAL_STATUSES: readonly ["ok", "warn", "fail", "unknown"];
|
|
28
|
+
export type SignalStatus = (typeof SIGNAL_STATUSES)[number];
|
|
29
|
+
export declare const RESOURCE_COLUMN_TYPES: readonly ["text", "status", "bytes", "percent", "time", "tags"];
|
|
30
|
+
export type ResourceColumnType = (typeof RESOURCE_COLUMN_TYPES)[number];
|
|
31
|
+
/** One input or output of an action. A subset of a settings field, plus rules. */
|
|
32
|
+
export interface OperationField {
|
|
33
|
+
key: string;
|
|
34
|
+
type: OperationFieldType;
|
|
35
|
+
labelKey?: string;
|
|
36
|
+
descriptionKey?: string;
|
|
37
|
+
placeholderKey?: string;
|
|
38
|
+
default?: unknown;
|
|
39
|
+
options?: PluginSettingsOption[];
|
|
40
|
+
min?: number;
|
|
41
|
+
max?: number;
|
|
42
|
+
/** Key of a boolean field in the same list that must be on. */
|
|
43
|
+
requires?: string;
|
|
44
|
+
group?: string;
|
|
45
|
+
required?: boolean;
|
|
46
|
+
/** string and textarea only. A regular expression the whole value matches. */
|
|
47
|
+
pattern?: string;
|
|
48
|
+
/** Read action whose rows fill the choices, for a list known only at run time. */
|
|
49
|
+
optionsFrom?: string;
|
|
50
|
+
/** type "resource" only: the resource id whose list fills the picker. */
|
|
51
|
+
resource?: string;
|
|
52
|
+
/** Outputs only: dropped before a run is stored or shown. */
|
|
53
|
+
sensitive?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface OperationWhen {
|
|
56
|
+
/** Host setting values that must match, such as { enableDocker: true }. */
|
|
57
|
+
settings?: Record<string, boolean | string | number>;
|
|
58
|
+
/** Lowercase OS names. A host with no known OS passes. */
|
|
59
|
+
os?: string[];
|
|
60
|
+
}
|
|
61
|
+
export interface OperationSurfaces {
|
|
62
|
+
/** Offered to the AI assistant. Off unless set. */
|
|
63
|
+
assistant?: boolean;
|
|
64
|
+
/** Offered over MCP. Off unless set. */
|
|
65
|
+
mcp?: boolean;
|
|
66
|
+
/** Set false to keep out of the command palette. */
|
|
67
|
+
palette?: boolean;
|
|
68
|
+
/** Set false to keep out of Automations. */
|
|
69
|
+
automations?: boolean;
|
|
70
|
+
/** Set false to keep out of the phone app. */
|
|
71
|
+
mobile?: boolean;
|
|
72
|
+
/** Set false to keep out of the CLI. */
|
|
73
|
+
cli?: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface OperationAction {
|
|
76
|
+
/** `<pluginId>.<name>`. */
|
|
77
|
+
id: string;
|
|
78
|
+
/** Bump when inputs change in a way saved references cannot follow. */
|
|
79
|
+
version?: number;
|
|
80
|
+
titleKey: string;
|
|
81
|
+
descriptionKey?: string;
|
|
82
|
+
icon?: string;
|
|
83
|
+
scope: OperationScope;
|
|
84
|
+
/** Required for scope "resource": the resource this acts on. */
|
|
85
|
+
resource?: string;
|
|
86
|
+
inputs?: OperationField[];
|
|
87
|
+
outputs?: OperationField[];
|
|
88
|
+
risk: OperationRisk;
|
|
89
|
+
/** One of this plugin's own permissions, short or full. */
|
|
90
|
+
permission: string;
|
|
91
|
+
/** Lowest share level. Required for host and resource scopes. */
|
|
92
|
+
hostAccess?: OperationHostAccess;
|
|
93
|
+
dryRun?: OperationDryRun;
|
|
94
|
+
/** A read action of this plugin that proves the result. */
|
|
95
|
+
check?: string;
|
|
96
|
+
/** An action of this plugin that reverses this one. */
|
|
97
|
+
undo?: string;
|
|
98
|
+
/** Safe to run twice, so a rollout may retry it. */
|
|
99
|
+
idempotent?: boolean;
|
|
100
|
+
/** Only one such action per host at a time. */
|
|
101
|
+
exclusive?: boolean;
|
|
102
|
+
timeoutMs?: number;
|
|
103
|
+
when?: OperationWhen;
|
|
104
|
+
surfaces?: OperationSurfaces;
|
|
105
|
+
}
|
|
106
|
+
export interface OperationEvent {
|
|
107
|
+
id: string;
|
|
108
|
+
titleKey: string;
|
|
109
|
+
descriptionKey?: string;
|
|
110
|
+
severity?: OperationSeverity;
|
|
111
|
+
scope: "host" | "server";
|
|
112
|
+
payload?: OperationField[];
|
|
113
|
+
}
|
|
114
|
+
export interface ResourceColumn {
|
|
115
|
+
key: string;
|
|
116
|
+
titleKey: string;
|
|
117
|
+
type?: ResourceColumnType;
|
|
118
|
+
}
|
|
119
|
+
export interface OperationResource {
|
|
120
|
+
id: string;
|
|
121
|
+
titleKey: string;
|
|
122
|
+
icon?: string;
|
|
123
|
+
/** Read action that returns { rows: [...] } for one host. */
|
|
124
|
+
list: string;
|
|
125
|
+
/** Row field that is unique on a host. */
|
|
126
|
+
key: string;
|
|
127
|
+
/** Row field shown as the name. */
|
|
128
|
+
name: string;
|
|
129
|
+
/** Row field holding a status word. */
|
|
130
|
+
status?: string;
|
|
131
|
+
/** Row field holding a link, for auto links on the homepage. */
|
|
132
|
+
url?: string;
|
|
133
|
+
/** Tab type that opens this on a host. */
|
|
134
|
+
tab?: string;
|
|
135
|
+
columns?: ResourceColumn[];
|
|
136
|
+
filters?: string[];
|
|
137
|
+
}
|
|
138
|
+
export interface OperationSignal {
|
|
139
|
+
id: string;
|
|
140
|
+
titleKey: string;
|
|
141
|
+
/** Read action that returns a SignalResult. */
|
|
142
|
+
read: string;
|
|
143
|
+
scope: "host" | "server";
|
|
144
|
+
kind: SignalKind;
|
|
145
|
+
refreshSec?: number;
|
|
146
|
+
/** Action offered as the fix when this signal is not ok. */
|
|
147
|
+
fix?: string;
|
|
148
|
+
}
|
|
149
|
+
export interface PluginOperationsContribution {
|
|
150
|
+
actions?: OperationAction[];
|
|
151
|
+
events?: OperationEvent[];
|
|
152
|
+
resources?: OperationResource[];
|
|
153
|
+
signals?: OperationSignal[];
|
|
154
|
+
/**
|
|
155
|
+
* Actions this plugin may run through ctx.operations.invoke: exact ids,
|
|
156
|
+
* `<pluginId>.*`, or `*`.
|
|
157
|
+
*/
|
|
158
|
+
invokes?: string[];
|
|
159
|
+
}
|
|
160
|
+
/** What a signal's read action returns. */
|
|
161
|
+
export interface SignalResult {
|
|
162
|
+
value?: number | string | null;
|
|
163
|
+
status: SignalStatus;
|
|
164
|
+
label?: string;
|
|
165
|
+
items?: {
|
|
166
|
+
label: string;
|
|
167
|
+
status?: SignalStatus;
|
|
168
|
+
}[];
|
|
169
|
+
link?: {
|
|
170
|
+
tab?: string;
|
|
171
|
+
data?: Record<string, unknown>;
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** What a resource's list action returns. */
|
|
175
|
+
export interface ResourceListResult {
|
|
176
|
+
rows: Record<string, unknown>[];
|
|
177
|
+
}
|
|
178
|
+
/** What a handler returns. */
|
|
179
|
+
export interface OperationResult {
|
|
180
|
+
/** One plain line for history and per host results. */
|
|
181
|
+
summary: string;
|
|
182
|
+
/** Whether anything actually changed. */
|
|
183
|
+
changed?: boolean;
|
|
184
|
+
data?: unknown;
|
|
185
|
+
/** Input for the `undo` action that reverses this exact run. */
|
|
186
|
+
undoInput?: Record<string, unknown>;
|
|
187
|
+
}
|
|
188
|
+
export declare const OPERATION_ID_PATTERN: RegExp;
|
|
189
|
+
export declare const MAX_OPERATION_TIMEOUT_MS = 3600000;
|
|
190
|
+
export declare const REDACTED_VALUE = "[redacted]";
|
|
191
|
+
/** Shape checks for contributes.operations, run by validateManifest. */
|
|
192
|
+
export declare function validateOperations(value: unknown, pluginId: string | undefined, errors: string[]): void;
|
|
193
|
+
/**
|
|
194
|
+
* The cross-field rules: every id one declaration names must exist in this
|
|
195
|
+
* plugin, or a surface would offer a button that goes nowhere.
|
|
196
|
+
*/
|
|
197
|
+
export declare function checkOperationReferences(operations: PluginOperationsContribution | undefined, capabilities: readonly string[], hasPermission: (name: string) => boolean, errors: string[]): void;
|
|
198
|
+
/** Whether a plugin's invokes list lets it run an action. */
|
|
199
|
+
export declare function invokeAllowed(invokes: readonly string[] | undefined, actionId: string): boolean;
|
|
200
|
+
export declare function riskRank(risk: OperationRisk): number;
|
|
201
|
+
/** A surface's own switch. The assistant and MCP are opt in, the rest opt out. */
|
|
202
|
+
export declare function onSurface(action: Pick<OperationAction, "surfaces">, surface: keyof OperationSurfaces): boolean;
|
|
203
|
+
/** Whether an action applies to a host, from fields any client can read. */
|
|
204
|
+
export declare function matchesWhen(when: OperationWhen | undefined, host: {
|
|
205
|
+
settings?: Record<string, unknown>;
|
|
206
|
+
os?: string | null;
|
|
207
|
+
}): boolean;
|
|
208
|
+
export interface OperationInputResult {
|
|
209
|
+
values: Record<string, unknown>;
|
|
210
|
+
errors: string[];
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Turns raw input into validated values. Keys no field declares are refused,
|
|
214
|
+
* so nothing a handler did not ask for ever reaches it.
|
|
215
|
+
*/
|
|
216
|
+
export declare function parseOperationInput(fields: readonly OperationField[] | undefined, raw: unknown): OperationInputResult;
|
|
217
|
+
/** A copy safe to store or show: secret and sensitive values are replaced. */
|
|
218
|
+
export declare function redactFields(fields: readonly OperationField[] | undefined, values: unknown): unknown;
|
|
219
|
+
/** Trims text to a byte-friendly length with a plain marker. */
|
|
220
|
+
export declare function capText(text: string, maxLength: number): string;
|
|
221
|
+
/** JSON Schema for a field list, for AI tools, MCP and OpenAPI. */
|
|
222
|
+
export declare function toJsonSchema(fields: readonly OperationField[] | undefined, describe?: (field: OperationField) => string | undefined): Record<string, unknown>;
|