@termix-ssh/plugin-sdk 1.0.10 → 1.0.12

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 (123) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/PLUGIN-GUIDE.md +151 -36
  3. package/cli/commands/build.mjs +36 -22
  4. package/cli/commands/pack.mjs +12 -2
  5. package/cli/commands/validate.mjs +63 -3
  6. package/cli/lib/plugin-dir.mjs +11 -0
  7. package/cli/lib/tmxplug.mjs +9 -0
  8. package/dist/backend.d.ts +37 -3
  9. package/dist/capabilities.js +2 -0
  10. package/dist/frontend.d.ts +152 -0
  11. package/dist/frontend.js +7 -0
  12. package/dist/host/PluginsTab-EV4MSGY6.js +2933 -0
  13. package/dist/host/{chunk-G346FUE4.js → chunk-AWR6FYDO.js} +8877 -11159
  14. package/dist/host/{chunk-NZG6HNQH.js → chunk-RUPLD6RF.js} +1504 -15
  15. package/dist/host/{chunk-DIOJ3KW2.js → chunk-VEWOYAMZ.js} +6 -1
  16. package/dist/host/chunk-X4QZKO5G.js +3120 -0
  17. package/dist/host/chunk-XKA3DBB2.js +10375 -0
  18. package/dist/host/chunk-YGYBM7SQ.js +58 -0
  19. package/dist/host/core-classes.json +1 -1
  20. package/dist/host/{linked-server-QAKKDBFM.js → linked-server-B4NEG4MA.js} +2 -2
  21. package/dist/host/{rbac-api-5267EMX7.js → rbac-api-OUO3LUOC.js} +2 -2
  22. package/dist/host/testing-host.js +123 -57
  23. package/dist/host/types/src/types/ui-types.d.ts +2 -1
  24. package/dist/host/types/src/ui/api/audit-log-api.d.ts +46 -0
  25. package/dist/host/types/src/ui/api/host-defaults-api.d.ts +42 -0
  26. package/dist/host/types/src/ui/api/host-tags-api.d.ts +2 -0
  27. package/dist/host/types/src/ui/api/look-api.d.ts +40 -0
  28. package/dist/host/types/src/ui/api/open-tabs-api.d.ts +4 -0
  29. package/dist/host/types/src/ui/api/plugins-api.d.ts +26 -0
  30. package/dist/host/types/src/ui/api/private-endpoints-api.d.ts +6 -0
  31. package/dist/host/types/src/ui/api/tls-api.d.ts +25 -0
  32. package/dist/host/types/src/ui/auth/ElectronLoginForm.d.ts +9 -0
  33. package/dist/host/types/src/ui/components/command.d.ts +78 -0
  34. package/dist/host/types/src/ui/components/folder-style.d.ts +16 -0
  35. package/dist/host/types/src/ui/components/theme-provider.d.ts +2 -1
  36. package/dist/host/types/src/ui/components/version-badge.d.ts +7 -0
  37. package/dist/host/types/src/ui/hooks/use-page-visible-interval.d.ts +10 -0
  38. package/dist/host/types/src/ui/lib/activity-types.d.ts +15 -0
  39. package/dist/host/types/src/ui/lib/app-version.d.ts +2 -0
  40. package/dist/host/types/src/ui/lib/apply-ui-preset.d.ts +19 -0
  41. package/dist/host/types/src/ui/lib/connection-origin.d.ts +4 -5
  42. package/dist/host/types/src/ui/lib/create-id.d.ts +2 -0
  43. package/dist/host/types/src/ui/lib/database-transfer-url.d.ts +8 -0
  44. package/dist/host/types/src/ui/lib/desktop-updates.d.ts +29 -0
  45. package/dist/host/types/src/ui/lib/electron.d.ts +5 -0
  46. package/dist/host/types/src/ui/lib/host-connection-tabs.d.ts +14 -0
  47. package/dist/host/types/src/ui/lib/host-to-ssh-host.d.ts +4 -0
  48. package/dist/host/types/src/ui/lib/issue-url.d.ts +21 -0
  49. package/dist/host/types/src/ui/lib/local-adaptive-preferences.d.ts +9 -0
  50. package/dist/host/types/src/ui/lib/pane-nav-hotkey.d.ts +7 -0
  51. package/dist/host/types/src/ui/lib/plugin-i18n.d.ts +16 -0
  52. package/dist/host/types/src/ui/lib/role-label.d.ts +3 -0
  53. package/dist/host/types/src/ui/look/LookSettings.d.ts +8 -0
  54. package/dist/host/types/src/ui/look/layout-registry.d.ts +34 -0
  55. package/dist/host/types/src/ui/look/look-store.d.ts +29 -0
  56. package/dist/host/types/src/ui/look/resolve-look.d.ts +18 -0
  57. package/dist/host/types/src/ui/look/theme-css.d.ts +7 -0
  58. package/dist/host/types/src/ui/look/theme-registry.d.ts +41 -0
  59. package/dist/host/types/src/ui/look/use-look-theme.d.ts +12 -0
  60. package/dist/host/types/src/ui/manage/manage-requests.d.ts +34 -0
  61. package/dist/host/types/src/ui/plugin-host/loader.d.ts +2 -0
  62. package/dist/host/types/src/ui/plugin-host/scope.d.ts +6 -0
  63. package/dist/host/types/src/ui/plugin-host/sdk-ui.d.ts +102 -0
  64. package/dist/host/types/src/ui/plugin-host/view-ownership.d.ts +1 -1
  65. package/dist/host/types/src/ui/plugins/PluginConsentPrompt.d.ts +20 -0
  66. package/dist/host/types/src/ui/plugins/PluginDetail.d.ts +7 -0
  67. package/dist/host/types/src/ui/plugins/PluginReleaseNotes.d.ts +14 -0
  68. package/dist/host/types/src/ui/plugins/PluginsTab.d.ts +1 -0
  69. package/dist/host/types/src/ui/plugins/RegistriesSection.d.ts +4 -0
  70. package/dist/host/types/src/ui/plugins/plugin-bits.d.ts +23 -0
  71. package/dist/host/types/src/ui/plugins/plugin-model.d.ts +116 -0
  72. package/dist/host/types/src/ui/plugins/use-plugins-manager.d.ts +75 -0
  73. package/dist/host/types/src/ui/settings/appearance/appearance-controls.d.ts +53 -0
  74. package/dist/host/types/src/ui/settings/sync/LinkServerDialog.d.ts +12 -0
  75. package/dist/host/types/src/ui/settings/sync/ProxySettingsFields.d.ts +15 -0
  76. package/dist/host/types/src/ui/settings/sync/saved-servers.d.ts +3 -0
  77. package/dist/host/types/src/ui/shell/controller/ShellControllerProvider.d.ts +20 -0
  78. package/dist/host/types/src/ui/shell/controller/plugin-shell.d.ts +7 -0
  79. package/dist/host/types/src/ui/shell/controller/shell-store.d.ts +4 -0
  80. package/dist/host/types/src/ui/shell/controller/types.d.ts +156 -0
  81. package/dist/host/types/src/ui/shell/controller/use-hosts.d.ts +10 -0
  82. package/dist/host/types/src/ui/shell/controller/use-regions.d.ts +5 -0
  83. package/dist/host/types/src/ui/shell/controller/use-shell-keybindings.d.ts +12 -0
  84. package/dist/host/types/src/ui/shell/controller/use-shell-lifecycle.d.ts +17 -0
  85. package/dist/host/types/src/ui/shell/controller/use-split.d.ts +21 -0
  86. package/dist/host/types/src/ui/shell/controller/use-tabs.d.ts +70 -0
  87. package/dist/host/types/src/ui/shell/controller/use-workspace-layout.d.ts +4 -0
  88. package/dist/host/types/src/ui/shell/reconnect-tabs.d.ts +6 -0
  89. package/dist/host/types/src/ui/shell/shell-layout.d.ts +46 -0
  90. package/dist/host/types/src/ui/shell/split/EmptyPanePicker.d.ts +32 -0
  91. package/dist/host/types/src/ui/shell/split/SplitDropOverlay.d.ts +9 -0
  92. package/dist/host/types/src/ui/shell/split/SplitLayoutMenu.d.ts +16 -0
  93. package/dist/host/types/src/ui/shell/split/SplitView.d.ts +31 -0
  94. package/dist/host/types/src/ui/shell/split/split-drag.d.ts +58 -0
  95. package/dist/host/types/src/ui/shell/split/split-presets.d.ts +28 -0
  96. package/dist/host/types/src/ui/shell/split/split-tabs.d.ts +95 -0
  97. package/dist/host/types/src/ui/shell/split/split-targets.d.ts +30 -0
  98. package/dist/host/types/src/ui/shell/split/split-tree.d.ts +89 -0
  99. package/dist/host/types/src/ui/shell/stage/TabStage.d.ts +9 -0
  100. package/dist/host/types/src/ui/shell/stage/tab-stage-store.d.ts +24 -0
  101. package/dist/host/types/src/ui/shell/tab-close-guards.d.ts +9 -0
  102. package/dist/host/types/src/ui/shell/tab-handles.d.ts +8 -0
  103. package/dist/host/types/src/ui/shell/tabUtils.d.ts +15 -0
  104. package/dist/host/types/src/ui/sidebar/AuthEnrollmentSections.d.ts +5 -0
  105. package/dist/host/types/src/ui/sidebar/HostManagerData.d.ts +4 -0
  106. package/dist/host/types/src/ui/sidebar/HostManagerTabs.d.ts +10 -4
  107. package/dist/host/types/src/ui/sidebar/build-host-tree.d.ts +25 -0
  108. package/dist/host/types/src/ui/sidebar/host-export-payload.d.ts +30 -0
  109. package/dist/host/ui.js +6238 -4054
  110. package/dist/host/{use-permissions-2P2TP6GY.js → use-permissions-6VSHHUMB.js} +2 -2
  111. package/dist/manifest.d.ts +41 -1
  112. package/dist/manifest.js +89 -1
  113. package/dist/testing/setup.js +1 -0
  114. package/dist/testing.d.ts +12 -1
  115. package/dist/testing.js +25 -1
  116. package/dist/theme-css.d.ts +11 -0
  117. package/dist/theme-css.js +142 -0
  118. package/dist/vitest-preset.d.ts +18 -0
  119. package/dist/vitest-preset.js +14 -3
  120. package/package.json +1 -1
  121. package/schema/manifest.schema.json +111 -8
  122. package/tsconfig.plugin.json +1 -0
  123. package/dist/host/chunk-YC2MAKSP.js +0 -14
@@ -0,0 +1,156 @@
1
+ import type { MutableRefObject } from "react";
2
+ import type { TabHandle } from "@termix-ssh/plugin-sdk/frontend";
3
+ import type { ConfirmOptions, EditingWidth } from "../../components/surface/surface-scope";
4
+ import type { Host, HostFolder, Tab, TabType } from "../../../types/ui-types";
5
+ import type { OpenTabRecord, UserPreferences } from "../../main-axios";
6
+ import type { TabShellCallbacks } from "../tab-registry";
7
+ import type { SplitViewActions } from "../split/SplitView";
8
+ import type { NewTabOption, PickHostTarget } from "../split/EmptyPanePicker";
9
+ import type { SplitSummary, SplitTab, TabSplitAction } from "../split/split-tabs";
10
+ export interface DockRegion {
11
+ view: string;
12
+ open: boolean;
13
+ width: number;
14
+ dragging: boolean;
15
+ editing: EditingWidth;
16
+ setView: (view: string | ((prev: string) => string)) => void;
17
+ setOpen: (open: boolean | ((prev: boolean) => boolean)) => void;
18
+ setWidth: (width: number) => void;
19
+ startResize: (e: React.MouseEvent) => void;
20
+ resetWidth: () => void;
21
+ }
22
+ export interface RightDockRegion {
23
+ view: string | null;
24
+ open: boolean;
25
+ width: number;
26
+ dragging: boolean;
27
+ setView: (view: string | null | ((prev: string | null) => string | null)) => void;
28
+ setWidth: (width: number) => void;
29
+ startResize: (e: React.MouseEvent) => void;
30
+ resetWidth: () => void;
31
+ }
32
+ export interface ShellRegions {
33
+ left: DockRegion;
34
+ right: RightDockRegion;
35
+ /** What clicking a rail item does: toggles or switches the left dock. */
36
+ railClick: (view: string) => void;
37
+ openInRightDock: (view: string) => void;
38
+ toggleRightDock: () => void;
39
+ previousView: () => string | null;
40
+ /** Stable setters a panel reports its wanted sidebar width with. */
41
+ panelEditingSetter: (view: string) => (editing: EditingWidth) => void;
42
+ scopeEditingSetter: (view: string) => (editing: EditingWidth) => void;
43
+ }
44
+ export interface OpenTabOptions {
45
+ data?: Record<string, unknown>;
46
+ label?: string;
47
+ forceNewTab?: boolean;
48
+ }
49
+ export interface RestoreTarget {
50
+ instanceId: string;
51
+ restoredSessionId: string | null;
52
+ savedLabel?: string;
53
+ }
54
+ export interface ShellTabs {
55
+ list: Tab[];
56
+ /** Tabs shown in a tab bar: everything not sitting inside a split. */
57
+ topLevel: Tab[];
58
+ activeId: string;
59
+ active: Tab | undefined;
60
+ ready: boolean;
61
+ /** Tabs panels can type into. */
62
+ terminalTabs: Tab[];
63
+ /** The terminal command panels act on right now. */
64
+ targetTerminal: Tab | undefined;
65
+ showNumbers: boolean;
66
+ background: OpenTabRecord[];
67
+ setBackground: (next: OpenTabRecord[] | ((prev: OpenTabRecord[]) => OpenTabRecord[])) => void;
68
+ setActive: (id: string) => void;
69
+ setList: (next: Tab[] | ((prev: Tab[]) => Tab[])) => void;
70
+ reorder: (topLevel: Tab[]) => void;
71
+ open: (host: Host, type: TabType, restore?: RestoreTarget, options?: OpenTabOptions) => string;
72
+ openSingleton: (type: TabType, pendingEvent?: string, host?: Host, data?: Record<string, unknown>, label?: string) => string | undefined;
73
+ openMultiInstance: (type: TabType, options?: {
74
+ host?: Host;
75
+ data?: Record<string, unknown>;
76
+ label?: string;
77
+ }) => string;
78
+ connectHost: (host: Host, type?: TabType, options?: OpenTabOptions) => void;
79
+ close: (id: string) => Promise<void>;
80
+ rename: (id: string, label: string) => void;
81
+ refresh: (id: string) => void;
82
+ reconnectAll: () => void;
83
+ handleFor: (id: string) => TabHandle | null | undefined;
84
+ }
85
+ export interface EmptyPaneApi {
86
+ freeTabs: Tab[];
87
+ newTabOptions: NewTabOption[];
88
+ pickTab: (splitTabId: string, paneId: string, tabId: string) => void;
89
+ pickHost: (splitTabId: string, paneId: string, host: Host, pick: PickHostTarget) => void;
90
+ openType: (splitTabId: string, paneId: string, type: string) => void;
91
+ closePane: (splitTabId: string, paneId: string) => void;
92
+ }
93
+ export interface ShellSplit {
94
+ active: SplitTab | null;
95
+ /** The pane each on-screen tab sits in, for the active split only. */
96
+ paneIdByTabId: Map<string, string>;
97
+ focusedPaneId: string | null;
98
+ summaries: SplitSummary[];
99
+ activeFull: boolean;
100
+ handleAction: (action: TabSplitAction) => void;
101
+ viewActions: (splitTabId: string) => SplitViewActions;
102
+ emptyPane: EmptyPaneApi;
103
+ }
104
+ export interface ShellHosts {
105
+ list: Host[];
106
+ tree: HostFolder | null;
107
+ loading: boolean;
108
+ loaded: boolean;
109
+ reload: () => Promise<void>;
110
+ edit: (host: Host) => void;
111
+ }
112
+ export interface ShellPalette {
113
+ isOpen: boolean;
114
+ open: () => void;
115
+ close: () => void;
116
+ setOpen: (open: boolean | ((prev: boolean) => boolean)) => void;
117
+ }
118
+ export interface ShellSettingsProps {
119
+ username: string;
120
+ isAdmin: boolean;
121
+ onLogout: (options?: {
122
+ manual?: boolean;
123
+ }) => void;
124
+ userPrefs: UserPreferences;
125
+ onPrefsChange: (updates: Partial<UserPreferences>) => void;
126
+ onOpenHostTab: (host: Host) => void;
127
+ }
128
+ /** Everything the shell knows and can do, minus drawing it. */
129
+ export interface ShellController {
130
+ username: string;
131
+ isAdmin: boolean;
132
+ isMobile: boolean;
133
+ isElectron: boolean;
134
+ pluginsSettled: boolean;
135
+ logout: (options?: {
136
+ manual?: boolean;
137
+ }) => void;
138
+ tabs: ShellTabs;
139
+ split: ShellSplit;
140
+ hosts: ShellHosts;
141
+ regions: ShellRegions;
142
+ palette: ShellPalette;
143
+ fullscreen: {
144
+ active: boolean;
145
+ toggle: () => void;
146
+ };
147
+ /** One stable bag that forwards to the latest shell, for tabs and plugins. */
148
+ callbacks: TabShellCallbacks;
149
+ /** Same, but closes the sidebar on mobile after opening a tab. */
150
+ panelCallbacks: TabShellCallbacks;
151
+ settings: ShellSettingsProps;
152
+ /** Where the main area's confirm is captured, see ShellConfirmCapture. */
153
+ confirmRef: MutableRefObject<((options: ConfirmOptions) => Promise<boolean>) | null>;
154
+ /** Refits every visible terminal, e.g. after a pane resize ends. */
155
+ resizeAllTerminals: () => number;
156
+ }
@@ -0,0 +1,10 @@
1
+ import type { Host, HostFolder } from "../../../types/ui-types";
2
+ /** The saved hosts and their folder tree, kept fresh on change events. */
3
+ export declare function useHostList(): {
4
+ list: Host[];
5
+ listRef: import("react").RefObject<Host[]>;
6
+ tree: HostFolder;
7
+ loading: boolean;
8
+ loaded: boolean;
9
+ reload: () => Promise<void>;
10
+ };
@@ -0,0 +1,5 @@
1
+ import type { ShellRegions } from "./types";
2
+ /** The left sidebar and the right dock: what they show, open state and size. */
3
+ /** A dock's width after Reset width, in Normal-size pixels. */
4
+ export declare const DOCK_DEFAULT_WIDTH = 291;
5
+ export declare function useRegions(isMobile: boolean): ShellRegions;
@@ -0,0 +1,12 @@
1
+ import { type MutableRefObject } from "react";
2
+ import type { TabsState } from "./use-tabs";
3
+ import type { SplitActions } from "./use-split";
4
+ import type { ShellPalette, ShellRegions } from "./types";
5
+ /** Every shell-wide shortcut: custom bindings, palette, panes and tabs. */
6
+ export declare function useShellKeybindings({ tabsState, regions, palette, splitActionsRef, toggleFullscreen, }: {
7
+ tabsState: TabsState;
8
+ regions: ShellRegions;
9
+ palette: ShellPalette;
10
+ splitActionsRef: MutableRefObject<SplitActions | null>;
11
+ toggleFullscreen: () => void;
12
+ }): void;
@@ -0,0 +1,17 @@
1
+ import { type MutableRefObject } from "react";
2
+ import { type UserPreferences } from "../../main-axios";
3
+ import type { TabType } from "../../../types/ui-types";
4
+ /** Who is signed in and what the shell does around the tabs: prefs, health, logout. */
5
+ export declare function useShellLifecycle({ onLogout, openSingletonTabRef, }: {
6
+ onLogout: (options?: {
7
+ manual?: boolean;
8
+ }) => void;
9
+ openSingletonTabRef: MutableRefObject<(type: TabType) => string | undefined>;
10
+ }): {
11
+ isAdmin: boolean;
12
+ userPrefs: UserPreferences;
13
+ setUserPrefs: import("react").Dispatch<import("react").SetStateAction<UserPreferences>>;
14
+ userPrefsLoaded: boolean;
15
+ isAppFullscreen: boolean;
16
+ toggleAppFullscreen: () => Promise<void>;
17
+ };
@@ -0,0 +1,21 @@
1
+ import type { TabShellCallbacks } from "../tab-registry";
2
+ import { type NavDirection } from "../split/split-tree";
3
+ import { type TabsState } from "./use-tabs";
4
+ import type { ShellSplit } from "./types";
5
+ export interface SplitActions {
6
+ splitActive: (edge: "right" | "bottom") => void;
7
+ navigate: (direction: NavDirection) => boolean;
8
+ zoomFocused: () => boolean;
9
+ closeFocusedPane: () => void;
10
+ }
11
+ export declare function useSplit({ tabsState, isMobile, paneEls, callbacks, resizeAllTerminals, }: {
12
+ tabsState: TabsState;
13
+ isMobile: boolean;
14
+ paneEls: Map<string, HTMLDivElement>;
15
+ callbacks: TabShellCallbacks;
16
+ resizeAllTerminals: () => number;
17
+ }): {
18
+ split: ShellSplit;
19
+ splitShapeKey: string;
20
+ splitActionsRef: import("react").RefObject<SplitActions>;
21
+ };
@@ -0,0 +1,70 @@
1
+ import { type MutableRefObject } from "react";
2
+ import type { TabHandle } from "@termix-ssh/plugin-sdk/frontend";
3
+ import type { ConfirmOptions } from "../../components/surface/surface-scope";
4
+ import type { Host, Tab, TabType } from "../../../types/ui-types";
5
+ import { type OpenTabRecord, type UserPreferences } from "../../main-axios";
6
+ import type { OpenTabOptions, RestoreTarget } from "./types";
7
+ export declare function dashboardTab(label: string): Tab;
8
+ /** What the tab code needs from the split code, filled in by useSplit. */
9
+ export interface SplitOps {
10
+ unsplit: (splitTabId: string) => void;
11
+ closePaneOf: (splitTabId: string, paneId: string) => void;
12
+ }
13
+ export declare function useSplitLabel(): (number: number) => string;
14
+ export declare function useTabs({ hosts, hostsRef, hostsLoaded, reloadHosts, userPrefs, userPrefsLoaded, pluginsSettled, confirmRef, layoutDeps, }: {
15
+ hosts: Host[];
16
+ hostsRef: MutableRefObject<Host[]>;
17
+ hostsLoaded: boolean;
18
+ reloadHosts: () => Promise<void>;
19
+ userPrefs: UserPreferences;
20
+ userPrefsLoaded: boolean;
21
+ pluginsSettled: boolean;
22
+ confirmRef: MutableRefObject<((options: ConfirmOptions) => Promise<boolean>) | null>;
23
+ /** Region state whose change also counts as a layout change for plugins. */
24
+ layoutDeps: unknown[];
25
+ }): {
26
+ tabs: Tab[];
27
+ setTabs: import("react").Dispatch<import("react").SetStateAction<Tab[]>>;
28
+ activeTabId: string;
29
+ setActiveTabId: import("react").Dispatch<import("react").SetStateAction<string>>;
30
+ tabsReady: boolean;
31
+ backgroundTabRecords: OpenTabRecord[];
32
+ setBackgroundTabRecords: import("react").Dispatch<import("react").SetStateAction<OpenTabRecord[]>>;
33
+ tabsRef: import("react").RefObject<Tab[]>;
34
+ activeTabIdRef: import("react").RefObject<string>;
35
+ closeActiveTabRef: import("react").RefObject<() => void>;
36
+ reconnectAllRef: import("react").RefObject<() => void>;
37
+ terminalRefs: import("react").RefObject<Map<string, import("react").RefObject<unknown>>>;
38
+ splitOpsRef: import("react").RefObject<SplitOps>;
39
+ suppressPaneTargetRef: import("react").RefObject<boolean>;
40
+ pendingPaneTargetRef: import("react").RefObject<{
41
+ splitTabId: string;
42
+ paneId: string;
43
+ at: number;
44
+ fresh: boolean;
45
+ }>;
46
+ openSingletonTabRef: import("react").RefObject<(type: TabType, pendingEvent?: string, host?: Host, data?: Record<string, unknown>, tabLabel?: string) => string | undefined>;
47
+ hostsRef: MutableRefObject<Host[]>;
48
+ focusedSessionTabId: () => string | null;
49
+ targetPane: (splitTabId: string, paneId: string, fresh?: boolean) => void;
50
+ openTab: (host: Host, type: TabType, restore?: RestoreTarget, options?: OpenTabOptions) => string;
51
+ connectHost: (host: Host, preferredType?: TabType, options?: OpenTabOptions) => void;
52
+ saveQuickConnectHost: (tab: Tab, host: Host) => Promise<void>;
53
+ openMultiInstanceTab: (type: TabType, options?: {
54
+ host?: Host;
55
+ data?: Record<string, unknown>;
56
+ label?: string;
57
+ }) => string;
58
+ openSingletonTab: (type: TabType, pendingEvent?: string, host?: Host, data?: Record<string, unknown>, tabLabel?: string) => string | undefined;
59
+ doCloseTab: (id: string) => void;
60
+ closeTab: (id: string) => Promise<void>;
61
+ renameTab: (tabId: string, newLabel: string) => void;
62
+ refreshTab: (id: string) => void;
63
+ reconnectAllDisconnected: () => void;
64
+ reorderTopLevelTabs: (reordered: Tab[]) => void;
65
+ showTabNumbers: boolean;
66
+ terminalTabs: Tab[];
67
+ targetTerminalTab: Tab;
68
+ handleFor: (id: string) => TabHandle | null | undefined;
69
+ };
70
+ export type TabsState = ReturnType<typeof useTabs>;
@@ -0,0 +1,4 @@
1
+ import { type TabsState } from "./use-tabs";
2
+ import type { ShellRegions } from "./types";
3
+ /** Saving and applying a whole arrangement, for workspaces and plugins. */
4
+ export declare function useWorkspaceLayout(tabsState: TabsState, regions: ShellRegions): void;
@@ -0,0 +1,6 @@
1
+ import type { Tab } from "../../types/ui-types";
2
+ /** Includes hidden tabs and split children; each plugin decides whether it is idle. */
3
+ export declare function reconnectDisconnectedTabs(tabs: readonly Tab[]): {
4
+ reconnected: number;
5
+ failed: number;
6
+ };
@@ -0,0 +1,46 @@
1
+ import type { Host, SplitState, Tab, WorkspacePayload, WorkspaceTabSnapshot } from "../../types/ui-types";
2
+ export declare function isCapturableTabType(type: string): boolean;
3
+ /**
4
+ * Maps live tabs to snapshots, with a fresh slotId per tab. slotId is a
5
+ * stable key within the saved payload, distinct from Tab.id, which is
6
+ * regenerated every time a tab opens.
7
+ */
8
+ export declare function buildLayoutTabSnapshots(tabs: Tab[], genSlotId?: () => string): {
9
+ snapshots: WorkspaceTabSnapshot[];
10
+ slotIdByTabId: Map<string, string>;
11
+ };
12
+ /**
13
+ * The tab's plugin payload. Payloads saved before tabs carried `data` stored
14
+ * the fleet a fleet-inventory tab showed as a field of its own.
15
+ */
16
+ export declare function snapshotData(snapshot: WorkspaceTabSnapshot): Record<string, unknown> | undefined;
17
+ /**
18
+ * How to reopen one saved tab. "singleton" types go through
19
+ * openSingletonTab with an optional host; "host" types need a resolved host
20
+ * to open at all.
21
+ */
22
+ export declare function resolveLayoutTabTarget(snapshot: WorkspaceTabSnapshot, allHosts: Host[]): {
23
+ kind: "singleton";
24
+ host?: Host;
25
+ } | {
26
+ kind: "host";
27
+ host: Host;
28
+ } | {
29
+ kind: "skip";
30
+ };
31
+ export declare function buildLayoutPayload(input: {
32
+ tabs: Tab[];
33
+ activeTabId: string;
34
+ genSlotId?: () => string;
35
+ sidebar?: WorkspacePayload["sidebar"];
36
+ }): WorkspacePayload;
37
+ /**
38
+ * The splits a saved layout describes, with live tab ids. Version 1 payloads
39
+ * held one split as a fixed mode; it comes back with no label or slotId, so
40
+ * the caller names it.
41
+ */
42
+ export declare function resolveLayoutSplits(payload: WorkspacePayload, slotIdToTabId: Map<string, string>): {
43
+ slotId: string | null;
44
+ label: string | null;
45
+ split: SplitState;
46
+ }[];
@@ -0,0 +1,32 @@
1
+ import { type HostActionDef } from "../../sidebar/host-contributions";
2
+ import type { Host, Tab } from "../../../types/ui-types";
3
+ export interface NewTabOption {
4
+ type: string;
5
+ label: string;
6
+ icon?: React.ComponentType<{
7
+ className?: string;
8
+ }>;
9
+ }
10
+ export type PickHostTarget = {
11
+ action: HostActionDef;
12
+ } | {
13
+ action: HostActionDef;
14
+ item: {
15
+ id: string;
16
+ label: string;
17
+ };
18
+ };
19
+ /**
20
+ * What an empty pane shows: the tabs that could move in, new tabs to start,
21
+ * and every host with the ways to open it. Picking anything fills this pane.
22
+ */
23
+ export declare function EmptyPanePicker({ paneIndex, freeTabs, hosts, newTabOptions, onPickTab, onPickHost, onOpenType, onClosePane, }: {
24
+ paneIndex: number;
25
+ freeTabs: Tab[];
26
+ hosts: Host[];
27
+ newTabOptions: NewTabOption[];
28
+ onPickTab: (tabId: string) => void;
29
+ onPickHost: (host: Host, target: PickHostTarget) => void;
30
+ onOpenType: (type: string) => void;
31
+ onClosePane: () => void;
32
+ }): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { type RefObject } from "react";
2
+ /**
3
+ * Drop zones over the main area while a tab or pane is dragged. Over a
4
+ * split, each pane offers its four edges (split there) and its center (show
5
+ * it there). Over a plain tab only the edges count, to start a new split.
6
+ */
7
+ export declare function SplitDropOverlay({ containerRef, }: {
8
+ containerRef: RefObject<HTMLElement | null>;
9
+ }): import("react").ReactPortal;
@@ -0,0 +1,16 @@
1
+ import { type SplitPresetId } from "./split-presets";
2
+ import { type PaneEdge } from "./split-tree";
3
+ /** A small drawing of a preset's panes. */
4
+ export declare function PresetThumb({ id }: {
5
+ id: SplitPresetId;
6
+ }): import("react").JSX.Element;
7
+ /**
8
+ * The tab bar's split button: split the active tab right or down, or lay it
9
+ * out as one of the presets.
10
+ */
11
+ export declare function SplitLayoutMenu({ activeIsSplit, canAddPane, onSplit, onPreset, }: {
12
+ activeIsSplit: boolean;
13
+ canAddPane: boolean;
14
+ onSplit: (edge: Extract<PaneEdge, "right" | "bottom">) => void;
15
+ onPreset: (id: SplitPresetId) => void;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ import type { Tab } from "../../../types/ui-types";
3
+ import type { SplitTab } from "./split-tabs";
4
+ import { type PaneEdge } from "./split-tree";
5
+ export interface SplitViewActions {
6
+ focusPane: (paneId: string) => void;
7
+ resize: (nodeId: string, sizes: number[]) => void;
8
+ equalize: (nodeId: string) => void;
9
+ splitPane: (paneId: string, edge: Extract<PaneEdge, "right" | "bottom">) => void;
10
+ closePane: (paneId: string) => void;
11
+ closeSession: (tabId: string) => void;
12
+ moveToTab: (paneId: string) => void;
13
+ showInPane: (paneId: string, tabId: string | null) => void;
14
+ swapPanes: (firstId: string, secondId: string) => void;
15
+ toggleZoom: (paneId: string) => void;
16
+ /** A divider drag finished, so sessions can fit their new size. */
17
+ resizeEnd: () => void;
18
+ }
19
+ /**
20
+ * A split tab's panes. Each pane with a tab renders an empty host element;
21
+ * the shell moves the tab's own DOM node into it, so switching panes never
22
+ * remounts a session.
23
+ */
24
+ export declare function SplitView({ splitTab, tabs, isMobile, actions, onPaneContentRef, renderEmptyPane, }: {
25
+ splitTab: SplitTab;
26
+ tabs: Tab[];
27
+ isMobile: boolean;
28
+ actions: SplitViewActions;
29
+ onPaneContentRef: (paneId: string, el: HTMLDivElement | null) => void;
30
+ renderEmptyPane: (paneId: string, paneIndex: number) => React.ReactNode;
31
+ }): React.JSX.Element;
@@ -0,0 +1,58 @@
1
+ import type { DropTarget } from "./split-tree";
2
+ /**
3
+ * Dragging a tab or a pane onto the main area to split it. The tab bar and
4
+ * pane headers start a drag, the drop overlay over the main area answers
5
+ * where the pointer is, and the shell's handler acts on the drop.
6
+ */
7
+ export type SplitDragSource = {
8
+ kind: "tab";
9
+ tabId: string;
10
+ label: string;
11
+ } | {
12
+ kind: "pane";
13
+ splitTabId: string;
14
+ paneId: string;
15
+ label: string;
16
+ };
17
+ export interface SplitDropHover {
18
+ /** The pane under the pointer, or null over a view that is not split. */
19
+ paneId: string | null;
20
+ target: DropTarget;
21
+ rect: {
22
+ left: number;
23
+ top: number;
24
+ width: number;
25
+ height: number;
26
+ };
27
+ }
28
+ export interface SplitDragState {
29
+ source: SplitDragSource;
30
+ x: number;
31
+ y: number;
32
+ hover: SplitDropHover | null;
33
+ }
34
+ type HitTest = (x: number, y: number, source: SplitDragSource) => SplitDropHover | null;
35
+ type DropHandler = (source: SplitDragSource, hover: SplitDropHover) => void;
36
+ export declare function beginSplitDrag(source: SplitDragSource, x: number, y: number): void;
37
+ export declare function moveSplitDrag(x: number, y: number): void;
38
+ /** Ends the drag, dropping it where it is when `commit` is true. */
39
+ export declare function endSplitDrag(commit: boolean): void;
40
+ export declare function isSplitDragging(): boolean;
41
+ export declare function setSplitDropHitTest(next: HitTest): () => void;
42
+ export declare function setSplitDropHandler(next: DropHandler): () => void;
43
+ export declare function useSplitDrag(): SplitDragState | null;
44
+ /** Which zone of a rect a point falls in: an edge band, else the center. */
45
+ export declare function dropTargetAt(rect: {
46
+ left: number;
47
+ top: number;
48
+ width: number;
49
+ height: number;
50
+ }, x: number, y: number): DropTarget;
51
+ /** The part of a rect a drop target covers, for drawing the highlight. */
52
+ export declare function dropTargetRect(rect: {
53
+ left: number;
54
+ top: number;
55
+ width: number;
56
+ height: number;
57
+ }, target: DropTarget): SplitDropHover["rect"];
58
+ export {};
@@ -0,0 +1,28 @@
1
+ import { type LayoutNode, type SplitState } from "./split-tree";
2
+ /** Starting layouts offered in the layout picker. Any pane can be split further. */
3
+ export type SplitPresetId = "columns-2" | "rows-2" | "columns-3" | "main-left-3" | "main-bottom-3" | "grid-4" | "grid-5" | "grid-6";
4
+ export interface SplitPreset {
5
+ id: SplitPresetId;
6
+ titleKey: string;
7
+ panes: number;
8
+ }
9
+ export declare const SPLIT_PRESETS: SplitPreset[];
10
+ type Sizes = {
11
+ outer?: number[];
12
+ inner?: number[][];
13
+ };
14
+ /**
15
+ * Builds a preset's tree, filling panes in reading order from `tabIds`.
16
+ * `sizes` lets the legacy mapping keep the user's divider positions.
17
+ */
18
+ export declare function buildPreset(id: SplitPresetId, tabIds?: (string | null)[], sizes?: Sizes): LayoutNode;
19
+ /**
20
+ * Re-lays an existing split out as a preset, keeping its tabs in reading
21
+ * order. Tabs past the preset's pane count drop out of the split.
22
+ */
23
+ export declare function applyPreset(state: SplitState, id: SplitPresetId): SplitState;
24
+ /** Split modes from before the layout tree, still found in storage and old workspaces. */
25
+ export type LegacySplitMode = "2-way" | "2-way-horizontal" | "3-way" | "3-way-horizontal" | "4-way" | "5-way" | "6-way";
26
+ /** Maps an old fixed-mode split onto the tree, keeping sizes where they fit. */
27
+ export declare function fromLegacyConfig(mode: string, paneTabIds: (string | null)[], rowSizes?: unknown, rowColSizes?: unknown): LayoutNode | null;
28
+ export {};
@@ -0,0 +1,95 @@
1
+ import type { LayoutNode, SplitState, Tab } from "../../../types/ui-types";
2
+ import { type SplitPresetId } from "./split-presets";
3
+ /**
4
+ * Split tabs as they live in the shell's tab list. A split tab owns its
5
+ * layout tree; every tab shown in one of its panes carries parentSplitTabId
6
+ * so the tab bar hides it. These keep the two in step.
7
+ */
8
+ export declare const SPLIT_TAB_TYPE = "split-screen";
9
+ export type SplitTab = Tab & {
10
+ split: SplitState;
11
+ };
12
+ export declare function isSplitTab(tab: Tab | undefined | null): tab is SplitTab;
13
+ /** Tabs a pane may hold: anything but the dashboard and other splits. */
14
+ export declare function canJoinSplit(tab: Tab | undefined | null): boolean;
15
+ export declare function splitTabOf(tabs: Tab[], tabId: string): SplitTab | undefined;
16
+ /**
17
+ * Makes parentSplitTabId match the trees. Pane tab ids that no longer exist
18
+ * are emptied, and a tab claimed by two splits stays with the first.
19
+ */
20
+ export declare function syncSplitChildren(tabs: Tab[]): Tab[];
21
+ /**
22
+ * Applies `fn` to one split's state. Returning null closes the split and
23
+ * sends its tabs back to the tab bar.
24
+ */
25
+ export declare function updateSplit(tabs: Tab[], splitTabId: string, fn: (state: SplitState) => SplitState | null): Tab[];
26
+ export declare function makeSplitTab(instanceId: string, label: string, split: SplitState, openedAt?: number): SplitTab;
27
+ /** Adds a split tab, taking its tabs out of any other split. */
28
+ export declare function addSplitTab(tabs: Tab[], splitTab: SplitTab): Tab[];
29
+ /** Removes a split tab. Its tabs go back to the tab bar. */
30
+ export declare function closeSplitTab(tabs: Tab[], splitTabId: string): Tab[];
31
+ /**
32
+ * Removes a closed tab. A pane that held it stays, empty and focused, so the
33
+ * next thing the user opens can go straight into it.
34
+ */
35
+ export declare function removeTab(tabs: Tab[], tabId: string): Tab[];
36
+ /** Puts a tab in a pane of a split and focuses that pane. */
37
+ export declare function placeTabInPane(tabs: Tab[], splitTabId: string, paneId: string, tabId: string): Tab[];
38
+ /** What the tab bar asks the shell to do with splits. */
39
+ export type TabSplitAction = {
40
+ kind: "split";
41
+ tabId: string;
42
+ edge: "right" | "bottom";
43
+ } | {
44
+ kind: "addToPane";
45
+ tabId: string;
46
+ splitTabId: string;
47
+ paneId: string;
48
+ } | {
49
+ kind: "addPane";
50
+ tabId: string;
51
+ splitTabId: string;
52
+ edge: "right" | "bottom";
53
+ } | {
54
+ kind: "unsplit";
55
+ splitTabId: string;
56
+ } | {
57
+ kind: "splitActive";
58
+ edge: "right" | "bottom";
59
+ } | {
60
+ kind: "preset";
61
+ presetId: SplitPresetId;
62
+ };
63
+ /** The lowest N not already used by a "Split N" style label. */
64
+ export declare function nextSplitNumber(tabs: Tab[], labelFor: (n: number) => string): number;
65
+ export interface SplitPaneSummary {
66
+ id: string;
67
+ /** 1-based, in reading order. */
68
+ index: number;
69
+ tabId: string | null;
70
+ /** The tab's label, or null for an empty pane. */
71
+ label: string | null;
72
+ }
73
+ export interface SplitSummary {
74
+ id: string;
75
+ label: string;
76
+ panes: SplitPaneSummary[];
77
+ full: boolean;
78
+ }
79
+ export declare function summarizeSplits(tabs: Tab[], maxPanes: number): SplitSummary[];
80
+ /** Saved in localStorage; pane tab ids are tab instanceIds, which survive a reload. */
81
+ export type PersistedSplitTab = {
82
+ version: 2;
83
+ instanceId: string;
84
+ label: string;
85
+ root: LayoutNode;
86
+ focusedPaneId: string;
87
+ };
88
+ export declare function serializeSplitTabs(tabs: Tab[]): PersistedSplitTab[];
89
+ /**
90
+ * Rebuilds a saved split's tree with live tab ids. `resolve` maps whatever
91
+ * the save used (instanceIds, workspace slotIds) to a live tab id. Null when
92
+ * the entry is unreadable or none of its tabs came back.
93
+ */
94
+ export declare function restoreSplitState(entry: unknown, resolve: (savedId: string) => string | null): SplitState | null;
95
+ export declare function restoreSplitTabs(persisted: unknown[], tabs: Tab[], openedAt?: number): Tab[];
@@ -0,0 +1,30 @@
1
+ import type { SplitSummary } from "./split-tabs";
2
+ /**
3
+ * Lets menus outside the shell (the host list) offer "Open in split" without
4
+ * threading split state through every sidebar component. The shell publishes
5
+ * its splits here and registers how to aim the next opened tab at a pane.
6
+ */
7
+ export type SplitOpenTarget = {
8
+ kind: "pane";
9
+ splitTabId: string;
10
+ paneId: string;
11
+ } | {
12
+ kind: "newPane";
13
+ splitTabId: string;
14
+ }
15
+ /** A new split holding the active tab and the opened one. */
16
+ | {
17
+ kind: "newSplit";
18
+ };
19
+ export interface SplitTargetsSnapshot {
20
+ splits: SplitSummary[];
21
+ /** The active tab can start a new split. */
22
+ canStartSplit: boolean;
23
+ }
24
+ type Opener = (target: SplitOpenTarget, open: () => void) => void;
25
+ export declare function publishSplitTargets(next: SplitTargetsSnapshot): void;
26
+ export declare function setSplitOpener(next: Opener): () => void;
27
+ /** Runs `open` so whatever tab it opens lands in `target`. */
28
+ export declare function openInSplit(target: SplitOpenTarget, open: () => void): void;
29
+ export declare function useSplitTargets(): SplitTargetsSnapshot;
30
+ export {};