@termix-ssh/plugin-sdk 1.0.21 → 1.0.22

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 (39) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/PLUGIN-GUIDE.md +62 -3
  3. package/cli/commands/build.mjs +55 -36
  4. package/cli/commands/validate.mjs +4 -0
  5. package/dist/backend.d.ts +32 -7
  6. package/dist/frontend.d.ts +7 -0
  7. package/dist/host/{PluginsTab-HQGSDSHS.js → PluginsTab-CM2B33BD.js} +22 -14
  8. package/dist/host/chunk-7J4QNGFM.js +345 -0
  9. package/dist/host/{chunk-A5CULDWV.js → chunk-HQ6NNFSX.js} +109 -1574
  10. package/dist/host/chunk-I5F2PSMR.js +1526 -0
  11. package/dist/host/{chunk-FGX27MAA.js → chunk-JRV2HIDK.js} +1 -1
  12. package/dist/host/{chunk-JFQGI4OD.js → chunk-P26QKKU5.js} +38 -9
  13. package/dist/host/{chunk-WWFRBU2E.js → chunk-ROB2SH5Q.js} +76 -49
  14. package/dist/host/chunk-TK3Y437H.js +53 -0
  15. package/dist/host/{chunk-GTHINW3L.js → chunk-VKNGNEF3.js} +34650 -34968
  16. package/dist/host/core-classes.json +1 -1
  17. package/dist/host/frame-host.css +2 -0
  18. package/dist/host/frame-host.js +242 -0
  19. package/dist/host/{linked-server-UDSFY3N7.js → linked-server-J5G457OA.js} +1 -1
  20. package/dist/host/{rbac-api-AAAPMF52.js → rbac-api-PY22W5UY.js} +5 -1
  21. package/dist/host/testing-host.js +9 -6
  22. package/dist/host/types/src/types/host-sidebar-preferences.d.ts +2 -0
  23. package/dist/host/types/src/types/index.d.ts +8 -0
  24. package/dist/host/types/src/ui/api/plugins-api.d.ts +2 -1
  25. package/dist/host/types/src/ui/api/rbac-api.d.ts +19 -1
  26. package/dist/host/types/src/ui/components/data-view.d.ts +1 -1
  27. package/dist/host/types/src/ui/main-axios.d.ts +1 -1
  28. package/dist/host/types/src/ui/plugin-host/loader.d.ts +6 -0
  29. package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +1 -1
  30. package/dist/host/types/src/ui/plugins/use-plugins-manager.d.ts +1 -1
  31. package/dist/host/types/src/ui/shell/tab-registry.d.ts +2 -0
  32. package/dist/host/ui.js +356 -369
  33. package/dist/host/{use-permissions-VAND5GEG.js → use-permissions-EWRI3WLT.js} +1 -1
  34. package/dist/host-commands.d.ts +7 -0
  35. package/dist/host-commands.js +35 -5
  36. package/dist/manifest.d.ts +28 -1
  37. package/dist/manifest.js +108 -1
  38. package/package.json +5 -1
  39. package/schema/manifest.schema.json +42 -0
@@ -0,0 +1,345 @@
1
+ const __termixNoGlob = () => ({});
2
+ import {
3
+ Puzzle,
4
+ RotateCcw,
5
+ X,
6
+ clsx,
7
+ cn,
8
+ dist_exports,
9
+ icons_exports,
10
+ isFieldActive,
11
+ usePluginScope
12
+ } from "./chunk-VKNGNEF3.js";
13
+ import {
14
+ init_define_import_meta_env
15
+ } from "./chunk-YGYBM7SQ.js";
16
+
17
+ // src/ui/components/button.tsx
18
+ init_define_import_meta_env();
19
+
20
+ // node_modules/class-variance-authority/dist/index.mjs
21
+ init_define_import_meta_env();
22
+ var falsyToString = (value) => typeof value === "boolean" ? `${value}` : value === 0 ? "0" : value;
23
+ var cx = clsx;
24
+ var cva = (base, config) => (props) => {
25
+ var _config_compoundVariants;
26
+ if ((config === null || config === void 0 ? void 0 : config.variants) == null) return cx(base, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
27
+ const { variants, defaultVariants } = config;
28
+ const getVariantClassNames = Object.keys(variants).map((variant) => {
29
+ const variantProp = props === null || props === void 0 ? void 0 : props[variant];
30
+ const defaultVariantProp = defaultVariants === null || defaultVariants === void 0 ? void 0 : defaultVariants[variant];
31
+ if (variantProp === null) return null;
32
+ const variantKey = falsyToString(variantProp) || falsyToString(defaultVariantProp);
33
+ return variants[variant][variantKey];
34
+ });
35
+ const propsWithoutUndefined = props && Object.entries(props).reduce((acc, param) => {
36
+ let [key, value] = param;
37
+ if (value === void 0) {
38
+ return acc;
39
+ }
40
+ acc[key] = value;
41
+ return acc;
42
+ }, {});
43
+ const getCompoundVariantClassNames = config === null || config === void 0 ? void 0 : (_config_compoundVariants = config.compoundVariants) === null || _config_compoundVariants === void 0 ? void 0 : _config_compoundVariants.reduce((acc, param) => {
44
+ let { class: cvClass, className: cvClassName, ...compoundVariantOptions } = param;
45
+ return Object.entries(compoundVariantOptions).every((param2) => {
46
+ let [key, value] = param2;
47
+ return Array.isArray(value) ? value.includes({
48
+ ...defaultVariants,
49
+ ...propsWithoutUndefined
50
+ }[key]) : {
51
+ ...defaultVariants,
52
+ ...propsWithoutUndefined
53
+ }[key] === value;
54
+ }) ? [
55
+ ...acc,
56
+ cvClass,
57
+ cvClassName
58
+ ] : acc;
59
+ }, []);
60
+ return cx(base, getVariantClassNames, getCompoundVariantClassNames, props === null || props === void 0 ? void 0 : props.class, props === null || props === void 0 ? void 0 : props.className);
61
+ };
62
+
63
+ // src/ui/components/button.tsx
64
+ import { jsx } from "react/jsx-runtime";
65
+ var buttonVariants = cva(
66
+ "group/button inline-flex shrink-0 items-center justify-center rounded-none border border-transparent bg-clip-padding text-xs font-medium whitespace-nowrap transition-[color,background-color,border-color,opacity,box-shadow,transform] outline-none select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
67
+ {
68
+ variants: {
69
+ variant: {
70
+ default: "border-accent-brand/40 bg-accent-brand/15 text-accent-brand hover:bg-accent-brand/25 aria-expanded:bg-accent-brand/25",
71
+ outline: "border-accent-brand/40 bg-transparent text-accent-brand hover:bg-accent-brand/10 aria-expanded:bg-accent-brand/10",
72
+ secondary: "border-accent-brand/20 bg-accent-brand/10 text-accent-brand hover:bg-accent-brand/20 aria-expanded:bg-accent-brand/20",
73
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
74
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
75
+ link: "text-accent-brand underline-offset-4 hover:underline"
76
+ },
77
+ size: {
78
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
79
+ xs: "h-6 gap-1 rounded-none px-2 text-xs has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
80
+ sm: "h-7 gap-1 rounded-none px-2.5 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
81
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
82
+ icon: "size-8",
83
+ "icon-xs": "size-6 rounded-none [&_svg:not([class*='size-'])]:size-3",
84
+ "icon-sm": "size-7 rounded-none",
85
+ "icon-lg": "size-9"
86
+ }
87
+ },
88
+ defaultVariants: {
89
+ variant: "default",
90
+ size: "default"
91
+ }
92
+ }
93
+ );
94
+ function Button({
95
+ className,
96
+ variant = "default",
97
+ size = "default",
98
+ asChild = false,
99
+ ...props
100
+ }) {
101
+ const Comp = asChild ? dist_exports.Root : "button";
102
+ return /* @__PURE__ */ jsx(
103
+ Comp,
104
+ {
105
+ "data-slot": "button",
106
+ "data-variant": variant,
107
+ "data-size": size,
108
+ className: cn(buttonVariants({ variant, size, className })),
109
+ ...props
110
+ }
111
+ );
112
+ }
113
+
114
+ // src/ui/components/input.tsx
115
+ init_define_import_meta_env();
116
+ import { jsx as jsx2 } from "react/jsx-runtime";
117
+ function Input({ className, type, ...props }) {
118
+ return /* @__PURE__ */ jsx2(
119
+ "input",
120
+ {
121
+ type,
122
+ "data-slot": "input",
123
+ className: cn(
124
+ "h-8 w-full min-w-0 rounded-none border border-input bg-transparent px-2.5 py-1 text-xs transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-xs file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-1 aria-invalid:ring-destructive/20 md:text-xs dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
125
+ type === "number" && "[appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
126
+ className
127
+ ),
128
+ ...props
129
+ }
130
+ );
131
+ }
132
+
133
+ // src/ui/lib/host-defaults-context.tsx
134
+ init_define_import_meta_env();
135
+ import { createContext, useContext } from "react";
136
+ import { useTranslation } from "react-i18next";
137
+ import { Fragment, jsx as jsx3, jsxs } from "react/jsx-runtime";
138
+ var HostDefaultsContext = createContext(null);
139
+ function useHostDefaults() {
140
+ return useContext(HostDefaultsContext);
141
+ }
142
+ function useIsDefaultsEditor() {
143
+ return useContext(HostDefaultsContext)?.mode === "defaults";
144
+ }
145
+ function useDefaultKey(settingKey) {
146
+ const scope = usePluginScope();
147
+ if (!settingKey) return null;
148
+ if (settingKey.includes(".")) return settingKey;
149
+ return scope ? `${scope}.${settingKey}` : null;
150
+ }
151
+ function useSourceLabel() {
152
+ const { t } = useTranslation();
153
+ return (source) => {
154
+ switch (source?.level) {
155
+ case "folder":
156
+ return t("hostDefaults.source.folder", {
157
+ name: source.folderName ?? ""
158
+ });
159
+ case "user":
160
+ return t("hostDefaults.source.user");
161
+ case "admin":
162
+ return t("hostDefaults.source.admin");
163
+ default:
164
+ return t("hostDefaults.source.builtin");
165
+ }
166
+ };
167
+ }
168
+ function HostDefaultBadge({ settingKey }) {
169
+ const { t } = useTranslation();
170
+ const context = useHostDefaults();
171
+ const fullKey = useDefaultKey(settingKey);
172
+ const sourceLabel = useSourceLabel();
173
+ if (!context || !fullKey || !context.isAvailable(fullKey)) return null;
174
+ const own = context.isOwn(fullKey);
175
+ const source = context.source(fullKey);
176
+ const from = sourceLabel(source);
177
+ if (own && (context.mode === "defaults" || source)) {
178
+ const defaults = context.mode === "defaults";
179
+ return /* @__PURE__ */ jsxs(
180
+ "button",
181
+ {
182
+ type: "button",
183
+ onClick: () => context.reset(fullKey),
184
+ title: defaults ? t("hostDefaults.clearTitle", { source: from }) : t("hostDefaults.resetTitle", { source: from }),
185
+ className: "inline-flex items-center gap-0.5 border border-accent-brand/40 px-1 text-[10px] font-medium normal-case tracking-normal text-accent-brand hover:bg-accent-brand/10",
186
+ children: [
187
+ defaults ? /* @__PURE__ */ jsx3(X, { className: "size-2.5" }) : /* @__PURE__ */ jsx3(RotateCcw, { className: "size-2.5" }),
188
+ defaults ? t("hostDefaults.setHere") : t("hostDefaults.custom")
189
+ ]
190
+ }
191
+ );
192
+ }
193
+ if (own || source?.level === "builtin") return null;
194
+ return /* @__PURE__ */ jsx3(
195
+ "span",
196
+ {
197
+ title: source ? t("hostDefaults.inheritedTitle", { source: from }) : t("hostDefaults.notSetTitle"),
198
+ className: "border border-border px-1 text-[10px] font-normal normal-case tracking-normal text-muted-foreground",
199
+ children: source ? from : t("hostDefaults.notSet")
200
+ }
201
+ );
202
+ }
203
+ function DefaultsOnly({
204
+ settingKey,
205
+ children
206
+ }) {
207
+ const context = useHostDefaults();
208
+ const fullKey = useDefaultKey(settingKey);
209
+ if (context?.mode === "defaults" && fullKey && !context.isAvailable(fullKey)) {
210
+ return null;
211
+ }
212
+ return /* @__PURE__ */ jsx3(Fragment, { children });
213
+ }
214
+ function HostOnly({ children }) {
215
+ return useIsDefaultsEditor() ? null : /* @__PURE__ */ jsx3(Fragment, { children });
216
+ }
217
+
218
+ // src/ui/components/section-card.tsx
219
+ init_define_import_meta_env();
220
+ import { useState } from "react";
221
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
222
+ function SectionCard({
223
+ title,
224
+ icon,
225
+ action,
226
+ children,
227
+ className,
228
+ rowId
229
+ }) {
230
+ return /* @__PURE__ */ jsxs2(
231
+ "div",
232
+ {
233
+ "data-setting-row": rowId,
234
+ className: `flex flex-col border border-border bg-card overflow-hidden ${className ?? ""}`,
235
+ children: [
236
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 px-4 py-2.5 border-b border-border shrink-0", children: [
237
+ /* @__PURE__ */ jsx4("span", { className: "text-muted-foreground", children: icon }),
238
+ /* @__PURE__ */ jsx4("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-muted-foreground flex-1", children: title }),
239
+ action && /* @__PURE__ */ jsx4("div", { className: "ml-auto", children: action })
240
+ ] }),
241
+ /* @__PURE__ */ jsx4("div", { className: "px-3 md:px-4 py-1", children })
242
+ ]
243
+ }
244
+ );
245
+ }
246
+ function SettingRow({
247
+ label,
248
+ badge,
249
+ description,
250
+ defaultKey,
251
+ rowId,
252
+ children
253
+ }) {
254
+ return /* @__PURE__ */ jsx4(DefaultsOnly, { settingKey: defaultKey ?? "", children: /* @__PURE__ */ jsxs2(
255
+ "div",
256
+ {
257
+ "data-setting-row": rowId ?? "",
258
+ className: "flex items-center justify-between gap-3 py-3 border-b border-border last:border-0 [.gap-4>&]:py-0 [.gap-4>&]:border-0",
259
+ children: [
260
+ /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-0.5 min-w-0 flex-1", children: [
261
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1.5 flex-wrap", children: [
262
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium leading-snug", children: label }),
263
+ badge && /* @__PURE__ */ jsx4("span", { className: "text-[10px] font-bold text-warning border border-warning/40 px-1 shrink-0", children: badge }),
264
+ defaultKey && /* @__PURE__ */ jsx4(HostDefaultBadge, { settingKey: defaultKey })
265
+ ] }),
266
+ description && /* @__PURE__ */ jsx4("span", { className: "text-xs text-muted-foreground leading-snug", children: description })
267
+ ] }),
268
+ /* @__PURE__ */ jsx4("div", { className: "shrink-0", children })
269
+ ]
270
+ }
271
+ ) });
272
+ }
273
+ function FakeSwitch({
274
+ defaultChecked = false,
275
+ disabled = false,
276
+ checked,
277
+ onChange
278
+ }) {
279
+ const [internalOn, setInternalOn] = useState(defaultChecked);
280
+ const on = checked !== void 0 ? checked : internalOn;
281
+ return /* @__PURE__ */ jsx4(
282
+ "button",
283
+ {
284
+ type: "button",
285
+ role: "switch",
286
+ "aria-checked": on,
287
+ disabled,
288
+ onClick: () => {
289
+ const next = !on;
290
+ if (checked === void 0) setInternalOn(next);
291
+ onChange?.(next);
292
+ },
293
+ className: `relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center border-2 transition-colors disabled:cursor-not-allowed disabled:opacity-50 ${on ? "bg-accent-brand border-accent-brand" : "bg-muted border-border"}`,
294
+ children: /* @__PURE__ */ jsx4(
295
+ "span",
296
+ {
297
+ className: `pointer-events-none inline-block h-3 w-3 bg-background shadow-sm transition-transform ${on ? "translate-x-4" : "translate-x-0.5"}`
298
+ }
299
+ )
300
+ }
301
+ );
302
+ }
303
+
304
+ // src/ui/lib/plugin-icon.tsx
305
+ init_define_import_meta_env();
306
+ import { jsx as jsx5 } from "react/jsx-runtime";
307
+ function PluginIcon({
308
+ name,
309
+ ...props
310
+ }) {
311
+ const Icon = name && icons_exports[name] || Puzzle;
312
+ return /* @__PURE__ */ jsx5(Icon, { ...props });
313
+ }
314
+
315
+ // src/ui/settings/settings-fields-util.ts
316
+ init_define_import_meta_env();
317
+ function isFieldShown(field, values) {
318
+ return !field.hidden && isFieldActive(field, values);
319
+ }
320
+ function hasVisibleFields(fields) {
321
+ return fields.some((field) => !field.hidden);
322
+ }
323
+ function hasSettingsPage(plugin, isAdmin) {
324
+ const settings = plugin.contributes?.settings;
325
+ return plugin.enabled && (hasVisibleFields(settings?.user ?? []) || isAdmin && hasVisibleFields(settings?.admin ?? []));
326
+ }
327
+
328
+ export {
329
+ cva,
330
+ buttonVariants,
331
+ Button,
332
+ Input,
333
+ HostDefaultsContext,
334
+ useIsDefaultsEditor,
335
+ HostDefaultBadge,
336
+ DefaultsOnly,
337
+ HostOnly,
338
+ SectionCard,
339
+ SettingRow,
340
+ FakeSwitch,
341
+ PluginIcon,
342
+ isFieldShown,
343
+ hasVisibleFields,
344
+ hasSettingsPage
345
+ };