@phoundry/phials-plugin-sdk 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Phoundry Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @phoundry/phials-plugin-sdk
2
+
3
+ Generated public Plugin API contract for Phials. Do not edit this package output directly.
@@ -0,0 +1,288 @@
1
+ // @generated from phials - do not edit
2
+ // Source graph: phials/scripts/lib/public-sdk-manifest.mjs
3
+
4
+ /// <reference path="./pane-context.generated.d.ts" />
5
+
6
+ /**
7
+ * Command System Type Definitions
8
+ *
9
+ * Defines interfaces for the unified command architecture including:
10
+ * - Context keys for fast filtering
11
+ * - Command definition and configuration
12
+ * - UI placement configuration
13
+ * - User settings persistence
14
+ */
15
+
16
+ // ─── Context Keys (Fast Pre-Filter) ──────────────────────────────────────────
17
+
18
+ /**
19
+ * Context keys for fast command filtering.
20
+ * Commands declare which keys they require, and the CommandManager
21
+ * maintains the current set of active keys based on app state.
22
+ */
23
+ type CommandContextKey =
24
+ // Selection state
25
+ | "hasSelection" // Any file(s) selected
26
+ | "hasSingleSelection" // Exactly one file selected
27
+ | "hasMultiSelection" // 2+ files selected
28
+ // File type (based on selection)
29
+ | "selectionIsFile" // All selected are files
30
+ | "selectionIsDirectory" // All selected are directories
31
+ | "selectionIsMixed" // Mix of files and directories
32
+ // Vial/Collection state
33
+ | "inVial" // Current directory is a vial
34
+ | "hasVialSelection" // Selected files are in a vial
35
+ // Clipboard
36
+ | "hasClipboard" // Files in clipboard (cut/copy)
37
+ | "clipboardIsCut" // Clipboard operation is cut
38
+ | "clipboardIsCopy" // Clipboard operation is copy
39
+ | "clipboardIsCopySymlink" // Clipboard operation is copy-as-symlink
40
+ // Navigation state
41
+ | "canGoBack" // Navigation history has back
42
+ | "canGoForward" // Navigation history has forward
43
+ // Always
44
+ | "always"; // No filtering (always visible)
45
+
46
+ // ─── Command Context ─────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Runtime context passed to command handlers and predicates.
50
+ * Built from the active pane's current state.
51
+ */
52
+ interface CommandContext {
53
+ /** The active pane (always available) */
54
+ pane: PluginPaneContext;
55
+
56
+ /** Selected files (empty if none) */
57
+ selectedFiles: FileEntry[];
58
+
59
+ /** The "target" file (for context menu: right-clicked file; otherwise: first selected) */
60
+ targetFile: FileEntry | null;
61
+
62
+ /** Current directory path */
63
+ currentPath: string;
64
+
65
+ /** Whether current directory is a vial */
66
+ isVial: boolean;
67
+
68
+ /** Whether the saved-views scope has a property schema (e.g. Boards). */
69
+ hasPropertySchema: boolean;
70
+
71
+ /** Active context keys (for debugging/inspection) */
72
+ activeContextKeys: ReadonlySet<CommandContextKey>;
73
+ }
74
+
75
+ // ─── Command Shortcut ────────────────────────────────────────────────────────
76
+
77
+ /**
78
+ * Keyboard shortcut configuration for a command.
79
+ */
80
+ interface CommandShortcut {
81
+ /** Default shortcut(s) - up to 3 */
82
+ defaults?: ShortcutDefinition[];
83
+
84
+ /** If true, don't call preventDefault() after handling */
85
+ allowDefault?: boolean;
86
+
87
+ /** Priority for conflict resolution (higher = checked first) */
88
+ priority?: number;
89
+ }
90
+
91
+ // ─── Command Placements ──────────────────────────────────────────────────────
92
+
93
+ /**
94
+ * Areas where commands can be placed in the UI.
95
+ */
96
+ type CommandPlacementArea = "toolbar" | "contextMenu";
97
+
98
+ /**
99
+ * Base placement configuration.
100
+ */
101
+ interface CommandPlacementBase {
102
+ area: CommandPlacementArea;
103
+ }
104
+
105
+ /**
106
+ * Toolbar placement configuration (PathBar toolbar).
107
+ */
108
+ interface ToolbarPlacementConfig extends CommandPlacementBase {
109
+ area: "toolbar";
110
+ /** Icon override for toolbar display */
111
+ icon?: string | ((ctx: CommandContext) => string);
112
+ /** Order priority (higher = more left) */
113
+ priority?: number;
114
+ /** If true, cannot be removed by user */
115
+ fixed?: boolean;
116
+ /** Whether to show text label by default (can be overridden by user config) */
117
+ showLabel?: boolean;
118
+ /** Whether to show the dropdown chevron on commands with children (default true) */
119
+ showArrow?: boolean;
120
+ /** Toggle/active state indicator */
121
+ active?: (ctx: CommandContext) => boolean;
122
+ /** Optional activity badge count on the path bar button */
123
+ badgeCount?: (ctx: CommandContext) => number;
124
+ /** Optional sub-toolbar component shown when button is toggled */
125
+ subToolbar?: import("svelte").Component<{ ctx: ToolbarContext }>;
126
+ }
127
+
128
+ /**
129
+ * Context menu placement configuration.
130
+ */
131
+ interface ContextMenuPlacementConfig extends CommandPlacementBase {
132
+ area: "contextMenu";
133
+ /** Selection mode this applies to */
134
+ selectionMode?: "single" | "multi" | "both";
135
+ /** Default submenu (null = root level) */
136
+ submenu?: { id: string; label: string; icon?: string } | null;
137
+ /** Show as dangerous (red styling) */
138
+ danger?: boolean;
139
+ /** Order within section/submenu (lower = higher in menu) */
140
+ order?: number;
141
+ }
142
+
143
+ /**
144
+ * Union of all placement configurations.
145
+ */
146
+ type CommandPlacement =
147
+ | ToolbarPlacementConfig
148
+ | ContextMenuPlacementConfig;
149
+
150
+ // ─── Command Definition ──────────────────────────────────────────────────────
151
+
152
+ /**
153
+ * A command is a discrete action that can be invoked via:
154
+ * - Keyboard shortcut
155
+ * - Command bar
156
+ * - Context menu
157
+ * - Toolbar button
158
+ * - Programmatically
159
+ */
160
+ interface CommandPresentation {
161
+ label?: string;
162
+ description?: string;
163
+ tooltip?: string;
164
+ icon?: string;
165
+ searchAliases?: string[];
166
+ }
167
+
168
+ interface Command {
169
+ /** Unique command identifier (e.g., 'core.file.delete', 'plugin.terminal.toggle') */
170
+ id: string;
171
+
172
+ /** Human-readable label */
173
+ label: string;
174
+
175
+ /** Optional description for command bar/settings */
176
+ description?: string;
177
+
178
+ /** Tooltip text shown on hover (defaults to label if not set) */
179
+ tooltip?: string;
180
+
181
+ /** Icon for UI display */
182
+ icon?: string;
183
+
184
+ // ─── Visibility & Availability ─────────────────────────────────────────────
185
+
186
+ /**
187
+ * Context keys required for this command to be visible.
188
+ * Used for fast pre-filtering before evaluating `when()`.
189
+ * If omitted or contains 'always', command is always considered.
190
+ */
191
+ contextKeys?: CommandContextKey[];
192
+
193
+ /**
194
+ * Fine-grained visibility check.
195
+ * Only called if contextKeys pass (or are not specified).
196
+ * Return false to hide the command.
197
+ */
198
+ when?: (ctx: CommandContext) => boolean;
199
+
200
+ /**
201
+ * Whether the command is disabled (visible but not executable).
202
+ * Return true to disable.
203
+ */
204
+ disabled?: (ctx: CommandContext) => boolean;
205
+
206
+ /** Dynamic display metadata for runtime surfaces; never changes availability. */
207
+ presentation?: (ctx: CommandContext) => CommandPresentation;
208
+
209
+ // ─── Execution ─────────────────────────────────────────────────────────────
210
+
211
+ /** The action to execute */
212
+ action: (ctx: CommandContext) => void | Promise<void>;
213
+
214
+ /**
215
+ * Optional toast shown after the action completes successfully (no throw).
216
+ * Static entry or a function of the same context passed to `action`.
217
+ */
218
+ toastData?:
219
+ | import("phoundry-ui").ToastEntry
220
+ | ((
221
+ ctx: CommandContext,
222
+ ) => import("phoundry-ui").ToastEntry | null | undefined);
223
+
224
+ // ─── Keyboard Shortcut ─────────────────────────────────────────────────────
225
+
226
+ /** Keyboard shortcut configuration */
227
+ shortcut?: CommandShortcut;
228
+
229
+ // ─── Default UI Placements ─────────────────────────────────────────────────
230
+
231
+ /**
232
+ * Where this command appears by default.
233
+ * Users can override these in settings.
234
+ */
235
+ defaultPlacements?: CommandPlacement[];
236
+
237
+ // ─── Command Bar ───────────────────────────────────────────────────────────
238
+
239
+ /**
240
+ * Category for grouping in command bar.
241
+ * E.g., 'File', 'Edit', 'View', 'Navigation', 'Tabs'
242
+ */
243
+ category?: string;
244
+
245
+ /** Alternative search terms for command bar fuzzy search */
246
+ searchAliases?: string[];
247
+
248
+ /** Optional group for path bar dropdown separators between sibling child commands */
249
+ menuGroup?: string;
250
+
251
+ // ─── Child Commands ───────────────────────────────────────────────────────
252
+
253
+ /**
254
+ * Child commands for dropdown/submenu patterns.
255
+ * When a command has children, its action typically does nothing
256
+ * and the UI shows a dropdown menu of child commands instead.
257
+ */
258
+ children?: Command[];
259
+
260
+ // ─── Custom Rendering ─────────────────────────────────────────────────────
261
+
262
+ /**
263
+ * Custom render snippet for context menu.
264
+ * When provided, the command renders as a custom menu item instead of
265
+ * a standard action item. Useful for inline controls like ratings.
266
+ *
267
+ * @returns A Svelte Snippet to render in the menu
268
+ */
269
+ renderSnippet?: (ctx: CommandContext) => import("svelte").Snippet;
270
+ }
271
+
272
+ // ─── Command Provider ────────────────────────────────────────────────────────
273
+
274
+ /**
275
+ * A command provider contributes commands from a plugin.
276
+ */
277
+ interface CommandProvider {
278
+ type: "command";
279
+
280
+ /** Provider identifier */
281
+ id: string;
282
+
283
+ /** Human-readable name */
284
+ name: string;
285
+
286
+ /** Commands contributed by this provider */
287
+ commands: Command[];
288
+ }
@@ -0,0 +1,195 @@
1
+ // @generated from phials - do not edit
2
+ // Source graph: phials/scripts/lib/public-sdk-manifest.mjs
3
+
4
+ /**
5
+ * Event System Type Definitions
6
+ *
7
+ * Defines types for the pub/sub event system used for cross-plugin
8
+ * communication and internal app events.
9
+ */
10
+
11
+ // ─── Event Definition ────────────────────────────────────────────────────────
12
+
13
+ /**
14
+ * Event type definition - registered for introspection/validation
15
+ */
16
+ interface EventDefinition<T = unknown> {
17
+ /** Unique event ID (e.g., 'core.navigation.changed', 'phials.terminal.command-executed') */
18
+ id: string;
19
+ /** Optional description for docs/debugging */
20
+ description?: string;
21
+ /** First Plugin API version that exposes this event. */
22
+ sincePluginApiVersion: string;
23
+ /** Plugin owner for custom events; core events have no plugin owner. */
24
+ pluginId?: string;
25
+ }
26
+
27
+ /**
28
+ * Subscription handle for cleanup
29
+ */
30
+ interface EventSubscription {
31
+ /** Unsubscribe from the event */
32
+ unsubscribe(): void;
33
+ }
34
+
35
+ /**
36
+ * Event handler callback type
37
+ */
38
+ type EventHandler<T = unknown> = (payload: T) => void | Promise<void>;
39
+
40
+ /** Details column layout live-sync payload (ADR-0010). */
41
+ interface ColumnLayoutChangedPayload {
42
+ browsedPath: string;
43
+ savedViewsCount: number;
44
+ activeSavedViewId: string | null;
45
+ columnConfig: DetailsViewColumnConfig[];
46
+ calculationRowVisible: boolean;
47
+ sourcePaneId: string;
48
+ }
49
+
50
+ type LayoutSettledReason =
51
+ | "center-divider"
52
+ | "center-structure"
53
+ | "panel-resize"
54
+ | "panel-structure"
55
+ | "panel-transition"
56
+ | "window-resize"
57
+ | "window-restore";
58
+
59
+ /** Semantic notification emitted after shell-owned geometry reaches the DOM. */
60
+ interface LayoutSettledPayload {
61
+ reasons: LayoutSettledReason[];
62
+ affectedIds: string[];
63
+ timestamp: number;
64
+ }
65
+
66
+ // ─── Core Events ─────────────────────────────────────────────────────────────
67
+
68
+ /**
69
+ * Built-in core events (strongly typed)
70
+ */
71
+ interface CoreEvents {
72
+ /** Pane navigation path changed */
73
+ "core.navigation.changed": { path: string; paneId: string };
74
+
75
+ /** File selection changed in a pane */
76
+ "core.selection.changed": { paths: string[]; paneId: string };
77
+
78
+ /** New tab created */
79
+ "core.tab.created": { tabId: string };
80
+
81
+ /** Tab closed */
82
+ "core.tab.closed": { tabId: string };
83
+
84
+ /** Active tab changed */
85
+ "core.tab.switched": { tabId: string; previousTabId: string };
86
+
87
+ /** File or directory renamed */
88
+ "core.file.renamed": { oldPath: string; newPath: string };
89
+
90
+ /** Files deleted */
91
+ "core.file.deleted": { paths: string[] };
92
+ /** File saved */
93
+ "core.file.saved": { path: string };
94
+ /** Persisted File Note content was created, updated, or removed */
95
+ "core.file-note.saved": {
96
+ path: string;
97
+ vialPath: string;
98
+ hasNote: boolean;
99
+ };
100
+ /** Portable Page visibility/order changed for one Vial. */
101
+ "core.vial-page-config.changed": {
102
+ vialPath: string;
103
+ page: VialPageConfig;
104
+ };
105
+ /** Canonical cell deltas or a filtered compatibility refetch for one Vial. */
106
+ "core.vial-values.changed": VialValuesChangedEvent;
107
+ /** Formula output types changed; every pane must normalize its consumers. */
108
+ "core.vial-formula-output-types.changed": {
109
+ vialId?: string;
110
+ vialPath: string;
111
+ propertyIds: string[];
112
+ savedViews: SavedVialView[];
113
+ sourcePaneId: string;
114
+ };
115
+ /** File opened */
116
+ "core.file.opened": { path: string };
117
+ /** File created */
118
+ "core.file.created": { path: string };
119
+
120
+ /** Directory contents changed (files added/removed/modified) */
121
+ "core.directory.changed": { path: string; paneId: string };
122
+ /** Directory renamed */
123
+ "core.directory.renamed": { oldPath: string; newPath: string };
124
+ /** Directory deleted */
125
+ "core.directory.deleted": { path: string };
126
+ /** Directory created */
127
+ "core.directory.created": { path: string };
128
+
129
+ /** App setting value changed */
130
+ "core.settings.changed": { key: string; value: unknown };
131
+
132
+ /** Known vials list changed (add/remove/rename in session) */
133
+ "core.known-vials.changed": { paths: string[] };
134
+
135
+ /** Explorer always-hide globs changed */
136
+ "core.config.hidden-globs.changed": { globs: string[] };
137
+
138
+ /** Global audio: current track or index changed */
139
+ "core.audio.track.changed": {
140
+ trackId: string | null;
141
+ path: string | null;
142
+ index: number;
143
+ };
144
+
145
+ /** Global audio: queue contents changed */
146
+ "core.audio.queue.changed": { trackIds: string[]; length: number };
147
+
148
+ /** Global audio: playback error (e.g. decode / missing file) */
149
+ "core.audio.playback.error": { trackId: string | null; message: string };
150
+
151
+ /** Drive/volume set may have changed (after pane drive caches refreshed) */
152
+ "core.drives.changed": DrivesChangedPayload;
153
+
154
+ /** Details column layout changed in a pane (path-owned or saved-view-owned) */
155
+ "core.columns.layout.changed": ColumnLayoutChangedPayload;
156
+
157
+ /** Shell-owned geometry changed and presented consumers may measure locally. */
158
+ "core.layout.settled": LayoutSettledPayload;
159
+ }
160
+
161
+ // ─── Plugin Events ───────────────────────────────────────────────────────────
162
+
163
+ /**
164
+ * Plugin event map - plugins extend this via declaration merging.
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * // In a plugin file:
169
+ * declare global {
170
+ * interface PluginEvents {
171
+ * 'phials.terminal.command-executed': {
172
+ * command: string;
173
+ * exitCode: number;
174
+ * duration: number;
175
+ * };
176
+ * }
177
+ * }
178
+ * ```
179
+ */
180
+ interface PluginEvents {
181
+ // Plugins add their events here via module augmentation
182
+ }
183
+
184
+ // ─── Combined Event Map ──────────────────────────────────────────────────────
185
+
186
+ /**
187
+ * Combined event map for type safety.
188
+ * Merges CoreEvents and PluginEvents.
189
+ */
190
+ type EventMap = CoreEvents & PluginEvents;
191
+
192
+ /**
193
+ * Helper type to get event payload for a given event ID
194
+ */
195
+ type EventPayload<K extends keyof EventMap> = EventMap[K];