@silo-code/sdk 0.6.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 +21 -0
- package/README.md +69 -0
- package/dist/context-keys.d.ts +19 -0
- package/dist/context-keys.d.ts.map +1 -0
- package/dist/context-keys.js +2 -0
- package/dist/context-keys.js.map +1 -0
- package/dist/dnd-service.d.ts +140 -0
- package/dist/dnd-service.d.ts.map +1 -0
- package/dist/dnd-service.js +17 -0
- package/dist/dnd-service.js.map +1 -0
- package/dist/domain-types.d.ts +237 -0
- package/dist/domain-types.d.ts.map +1 -0
- package/dist/domain-types.js +11 -0
- package/dist/domain-types.js.map +1 -0
- package/dist/editor-service.d.ts +175 -0
- package/dist/editor-service.d.ts.map +1 -0
- package/dist/editor-service.js +2 -0
- package/dist/editor-service.js.map +1 -0
- package/dist/extension-storage.d.ts +26 -0
- package/dist/extension-storage.d.ts.map +1 -0
- package/dist/extension-storage.js +2 -0
- package/dist/extension-storage.js.map +1 -0
- package/dist/file-service.d.ts +84 -0
- package/dist/file-service.d.ts.map +1 -0
- package/dist/file-service.js +2 -0
- package/dist/file-service.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/layout-service.d.ts +46 -0
- package/dist/layout-service.d.ts.map +1 -0
- package/dist/layout-service.js +2 -0
- package/dist/layout-service.js.map +1 -0
- package/dist/permissions.d.ts +41 -0
- package/dist/permissions.d.ts.map +1 -0
- package/dist/permissions.js +40 -0
- package/dist/permissions.js.map +1 -0
- package/dist/process-service.d.ts +132 -0
- package/dist/process-service.d.ts.map +1 -0
- package/dist/process-service.js +2 -0
- package/dist/process-service.js.map +1 -0
- package/dist/terminal-service.d.ts +38 -0
- package/dist/terminal-service.d.ts.map +1 -0
- package/dist/terminal-service.js +2 -0
- package/dist/terminal-service.js.map +1 -0
- package/dist/theme-service.d.ts +87 -0
- package/dist/theme-service.d.ts.map +1 -0
- package/dist/theme-service.js +2 -0
- package/dist/theme-service.js.map +1 -0
- package/dist/types.d.ts +495 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui-service.d.ts +469 -0
- package/dist/ui-service.d.ts.map +1 -0
- package/dist/ui-service.js +2 -0
- package/dist/ui-service.js.map +1 -0
- package/dist/use-focus-group.d.ts +202 -0
- package/dist/use-focus-group.d.ts.map +1 -0
- package/dist/use-focus-group.js +236 -0
- package/dist/use-focus-group.js.map +1 -0
- package/dist/use-service-state.d.ts +36 -0
- package/dist/use-service-state.d.ts.map +1 -0
- package/dist/use-service-state.js +25 -0
- package/dist/use-service-state.js.map +1 -0
- package/dist/workspace-service.d.ts +72 -0
- package/dist/workspace-service.d.ts.map +1 -0
- package/dist/workspace-service.js +2 -0
- package/dist/workspace-service.js.map +1 -0
- package/package.json +54 -0
- package/src/context-keys.ts +18 -0
- package/src/dnd-service.ts +151 -0
- package/src/domain-types.ts +252 -0
- package/src/editor-service.ts +196 -0
- package/src/extension-storage.ts +25 -0
- package/src/file-service.ts +90 -0
- package/src/index.ts +151 -0
- package/src/layout-service.ts +49 -0
- package/src/permissions.ts +55 -0
- package/src/process-service.ts +143 -0
- package/src/terminal-service.ts +41 -0
- package/src/theme-service.ts +102 -0
- package/src/types.ts +513 -0
- package/src/ui-service.ts +487 -0
- package/src/use-focus-group.test.ts +168 -0
- package/src/use-focus-group.ts +382 -0
- package/src/use-service-state.ts +43 -0
- package/src/workspace-service.ts +76 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public domain types shared across the `ctx` services. These describe the
|
|
3
|
+
* persisted, user-facing shapes an extension sees through the consumer services
|
|
4
|
+
* (e.g. {@link WorkspaceService}, {@link TerminalService}, {@link ThemeService}).
|
|
5
|
+
* The host's internal state module re-exports these so app code names a single
|
|
6
|
+
* source of truth.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The kind of a terminal session.
|
|
13
|
+
*
|
|
14
|
+
* @category Core Types
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export type TerminalKind = "shell" | "claude" | "pi";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A terminal tab record in a workspace.
|
|
21
|
+
*
|
|
22
|
+
* @category Core Types
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
export interface TerminalRecord {
|
|
26
|
+
id: string;
|
|
27
|
+
sessionId: string;
|
|
28
|
+
kind: TerminalKind;
|
|
29
|
+
title: string;
|
|
30
|
+
/**
|
|
31
|
+
* A user-assigned name (via the tab's "Rename…" menu). When set, it wins over
|
|
32
|
+
* the PTY-derived {@link TerminalRecord.title} and stays put until the user
|
|
33
|
+
* renames again or the terminal is closed. Cleared by renaming to an empty
|
|
34
|
+
* string, which hands the title back to PTY auto-derivation.
|
|
35
|
+
*/
|
|
36
|
+
customName?: string;
|
|
37
|
+
/** Working directory override. Falls back to ws.folder when absent. */
|
|
38
|
+
cwd?: string;
|
|
39
|
+
/** ISO timestamp of the last output we observed; used to pick a workspace's "primary" terminal. */
|
|
40
|
+
lastActiveAt?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The two modes of the one editor surface: a read-write text editor, or a
|
|
45
|
+
* read-only two-model diff. Absent on a record means `"text"`.
|
|
46
|
+
*
|
|
47
|
+
* @category Core Types
|
|
48
|
+
* @public
|
|
49
|
+
*/
|
|
50
|
+
export type EditorMode = "text" | "diff";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* An editor tab record in a workspace — a text editor or a diff.
|
|
54
|
+
*
|
|
55
|
+
* @category Core Types
|
|
56
|
+
* @public
|
|
57
|
+
*/
|
|
58
|
+
export interface EditorRecord {
|
|
59
|
+
id: string;
|
|
60
|
+
/** null for an untitled buffer that hasn't been saved yet. */
|
|
61
|
+
filePath: string | null;
|
|
62
|
+
title: string;
|
|
63
|
+
/** When true, the tab is a temporary preview that gets replaced by the next single-click open. */
|
|
64
|
+
isPreview?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Which mode this record renders in. Absent ⇒ `"text"`. A `"diff"` record
|
|
67
|
+
* additionally carries {@link EditorRecord.providerId}/{@link EditorRecord.args}
|
|
68
|
+
* and always has a non-null `filePath`.
|
|
69
|
+
*/
|
|
70
|
+
mode?: EditorMode;
|
|
71
|
+
/**
|
|
72
|
+
* Diff mode only: which registered diff-content provider resolves the two
|
|
73
|
+
* sides (e.g. "silo.git"). The diff is content-agnostic — the provider owns
|
|
74
|
+
* what the two sides contain.
|
|
75
|
+
*/
|
|
76
|
+
providerId?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Diff mode only: serializable args the provider needs to (re)compute content
|
|
79
|
+
* on mount / restart.
|
|
80
|
+
*/
|
|
81
|
+
args?: Record<string, unknown>;
|
|
82
|
+
/**
|
|
83
|
+
* The chosen editor *view* for this tab, referencing an {@link Editor.id}
|
|
84
|
+
* (e.g. `"text"`, `"silo.markdown-preview"`). Absent ⇒ the host renders the
|
|
85
|
+
* highest-priority matching editor (the default). Honored only when the
|
|
86
|
+
* referenced editor is still registered **and** still matches the file;
|
|
87
|
+
* otherwise the host falls back to priority resolution (so a stale value left
|
|
88
|
+
* by an uninstalled extension never breaks the tab). Orthogonal to
|
|
89
|
+
* {@link EditorRecord.mode}: `viewType` selects among `"text"`-mode editors; a
|
|
90
|
+
* `"diff"` record ignores it.
|
|
91
|
+
*/
|
|
92
|
+
viewType?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Which slot a side panel renders in.
|
|
97
|
+
*
|
|
98
|
+
* @category Core Types
|
|
99
|
+
* @public
|
|
100
|
+
*/
|
|
101
|
+
export type SidePanelSlot = "left" | "right" | "left-bottom" | "right-bottom";
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* A workspace — the unit Silo switches between, keeping its terminals, editors,
|
|
105
|
+
* and layout alive. Read via {@link WorkspaceService}.
|
|
106
|
+
*
|
|
107
|
+
* @category Core Types
|
|
108
|
+
* @public
|
|
109
|
+
*/
|
|
110
|
+
export interface Workspace {
|
|
111
|
+
id: string;
|
|
112
|
+
name: string;
|
|
113
|
+
folder: string;
|
|
114
|
+
/** Additional folders beyond the primary one. */
|
|
115
|
+
extraFolders?: string[];
|
|
116
|
+
createdAt: string;
|
|
117
|
+
lastOpenedAt: string;
|
|
118
|
+
terminals: TerminalRecord[];
|
|
119
|
+
/** Editor tabs — text editors and diffs alike (a diff is a record with `mode: "diff"`). */
|
|
120
|
+
editors: EditorRecord[];
|
|
121
|
+
dockLayout: unknown | null;
|
|
122
|
+
/** Scroll positions keyed by editor record ID: { top, left } in pixels. */
|
|
123
|
+
editorScrollPositions?: Record<string, { top: number; left: number }>;
|
|
124
|
+
/**
|
|
125
|
+
* ISO timestamp of when the workspace was soft-closed, or null/undefined
|
|
126
|
+
* if the workspace is open. Closed workspaces are hidden from the main
|
|
127
|
+
* list and surfaced in a "reopen" picker.
|
|
128
|
+
*/
|
|
129
|
+
closedAt?: string | null;
|
|
130
|
+
/** Per-workspace side panel state — saved/restored on workspace switch. */
|
|
131
|
+
sidePanelLocations?: Record<string, SidePanelSlot>;
|
|
132
|
+
sidePanelOrder?: Record<string, number>;
|
|
133
|
+
activeSidePanelTabs?: Record<string, string>;
|
|
134
|
+
sidePanelScrollPositions?: Record<string, number>;
|
|
135
|
+
extensionState?: Record<string, Record<string, unknown>>;
|
|
136
|
+
leftPanelCollapsed?: boolean;
|
|
137
|
+
rightPanelCollapsed?: boolean;
|
|
138
|
+
/** ID of the current preview (temporary) editor, if any. */
|
|
139
|
+
previewEditorId?: string | null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Light or dark theme base.
|
|
144
|
+
*
|
|
145
|
+
* @category Core Types
|
|
146
|
+
* @public
|
|
147
|
+
*/
|
|
148
|
+
export type ThemeBase = "dark" | "light";
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* The full theme-override surface, in type form: every `--silo-*` token a theme
|
|
152
|
+
* preset's `vars` may recolor. Per the theming contract it spans **the design
|
|
153
|
+
* tokens' generic colors + font families** _and_ **all the component tokens**.
|
|
154
|
+
* The keys are the literal CSS custom-property names; renaming a key here
|
|
155
|
+
* renames the token in `theme.css` in lockstep. Font-sizes and the radius scale
|
|
156
|
+
* are intentionally absent (not theme-overridable).
|
|
157
|
+
*
|
|
158
|
+
* @see docs/architecture-audit/theming-contract.md
|
|
159
|
+
* @category Core Types
|
|
160
|
+
* @public
|
|
161
|
+
*/
|
|
162
|
+
export interface ThemeVars {
|
|
163
|
+
// ── Design tokens — generic colors (also consumable by extensions) ──
|
|
164
|
+
"--silo-color-bg": string;
|
|
165
|
+
"--silo-color-bg-hover": string;
|
|
166
|
+
"--silo-color-bg-active": string;
|
|
167
|
+
"--silo-color-text": string;
|
|
168
|
+
"--silo-color-text-hi": string;
|
|
169
|
+
"--silo-color-text-lo": string;
|
|
170
|
+
"--silo-color-accent": string;
|
|
171
|
+
"--silo-color-accent-2": string;
|
|
172
|
+
"--silo-color-border": string;
|
|
173
|
+
"--silo-color-border-strong": string;
|
|
174
|
+
"--silo-color-ok": string;
|
|
175
|
+
"--silo-color-warn": string;
|
|
176
|
+
"--silo-color-err": string;
|
|
177
|
+
"--silo-color-input-bg": string;
|
|
178
|
+
"--silo-color-input-text": string;
|
|
179
|
+
"--silo-color-button-bg": string;
|
|
180
|
+
"--silo-color-button-text": string;
|
|
181
|
+
// ── Design tokens — font families ──
|
|
182
|
+
"--silo-font-ui"?: string;
|
|
183
|
+
"--silo-font-mono"?: string;
|
|
184
|
+
// ── Component tokens — content (editor / terminal / tabs) colors ──
|
|
185
|
+
"--silo-content-text": string;
|
|
186
|
+
"--silo-content-terminal-bg": string;
|
|
187
|
+
"--silo-content-editor-bg": string;
|
|
188
|
+
"--silo-content-editor-selection": string;
|
|
189
|
+
"--silo-content-editor-selection-inactive": string;
|
|
190
|
+
"--silo-content-editor-text-dim": string;
|
|
191
|
+
"--silo-content-editor-text-faint": string;
|
|
192
|
+
"--silo-content-tab-bg": string;
|
|
193
|
+
"--silo-content-tab-tray-bg": string;
|
|
194
|
+
"--silo-content-tab-tray-text": string;
|
|
195
|
+
"--silo-content-tab-text": string;
|
|
196
|
+
"--silo-content-tab-text-inactive": string;
|
|
197
|
+
"--silo-content-tab-text-active": string;
|
|
198
|
+
// ── Component tokens — breadcrumb colors ──
|
|
199
|
+
"--silo-breadcrumb-bg": string;
|
|
200
|
+
"--silo-breadcrumb-text": string;
|
|
201
|
+
"--silo-breadcrumb-text-active": string;
|
|
202
|
+
"--silo-breadcrumb-icon": string;
|
|
203
|
+
// ── Component tokens — status bar colors ──
|
|
204
|
+
"--silo-statusbar-bg": string;
|
|
205
|
+
"--silo-statusbar-text": string;
|
|
206
|
+
"--silo-statusbar-bg-hover": string;
|
|
207
|
+
// ── Component tokens — side-tab colors ──
|
|
208
|
+
"--silo-tab-text": string;
|
|
209
|
+
"--silo-tab-text-active": string;
|
|
210
|
+
"--silo-tab-bg-hover": string;
|
|
211
|
+
"--silo-tab-border-active": string;
|
|
212
|
+
// ── Component tokens — menu / dropdown colors (the host <Menu> primitive) ──
|
|
213
|
+
"--silo-menu-bg": string;
|
|
214
|
+
"--silo-menu-text": string;
|
|
215
|
+
"--silo-menu-item-hover-bg": string;
|
|
216
|
+
"--silo-menu-border": string;
|
|
217
|
+
// ── Component tokens — modal shell (ctx.ui.confirm/prompt + the host Modal) ──
|
|
218
|
+
"--silo-modal-bg": string;
|
|
219
|
+
"--silo-modal-border": string;
|
|
220
|
+
// ── Component tokens — notify (toast) surface (ctx.ui.notify) ──
|
|
221
|
+
"--silo-notify-bg": string;
|
|
222
|
+
"--silo-notify-text": string;
|
|
223
|
+
"--silo-notify-text-hi": string;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* A persisted custom theme.
|
|
228
|
+
*
|
|
229
|
+
* @category Core Types
|
|
230
|
+
* @public
|
|
231
|
+
*/
|
|
232
|
+
export interface CustomTheme {
|
|
233
|
+
id: string;
|
|
234
|
+
/**
|
|
235
|
+
* `2` since the `--silo-*` token rename (theming-contract.md › Migration).
|
|
236
|
+
* v1 themes used the legacy bare names (`--bg`, `--text-hi`, …).
|
|
237
|
+
*/
|
|
238
|
+
version: 2;
|
|
239
|
+
name: string;
|
|
240
|
+
base: ThemeBase;
|
|
241
|
+
colorScheme: "dark" | "light";
|
|
242
|
+
vars: Partial<ThemeVars>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* A {@link CustomTheme} without its `id` — the shape exported/imported as a
|
|
247
|
+
* shareable theme file.
|
|
248
|
+
*
|
|
249
|
+
* @category Core Types
|
|
250
|
+
* @public
|
|
251
|
+
*/
|
|
252
|
+
export type ThemeExport = Omit<CustomTheme, "id">;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Disposable } from "./types";
|
|
2
|
+
|
|
3
|
+
// `ctx.editors` — the editor & document domain (public contract). Opening files
|
|
4
|
+
// into editor tabs, the active-editor save/close commands, and the diff-content
|
|
5
|
+
// provider registry. The host implementation lives in the extension host.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for the editor open methods.
|
|
9
|
+
*
|
|
10
|
+
* @category Consumer Services
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export interface OpenFileOptions {
|
|
14
|
+
/** Target workspace. Defaults to the active workspace. */
|
|
15
|
+
workspaceId?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Open as a preview tab (single-click style — replaced by the next preview,
|
|
18
|
+
* italic title) instead of a permanent editor. Defaults to false.
|
|
19
|
+
*/
|
|
20
|
+
preview?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Open with a specific editor view — an {@link Editor.id}, e.g. from an
|
|
23
|
+
* "Open With" menu. Persisted on the tab as {@link EditorRecord.viewType}.
|
|
24
|
+
* Ignored if no registered editor with that id matches the path (the host
|
|
25
|
+
* falls back to the highest-priority match). When omitted the default view is
|
|
26
|
+
* used and any existing tab's view is left unchanged.
|
|
27
|
+
*/
|
|
28
|
+
viewType?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* One editor view that can render a given file — its id, user-facing label, and
|
|
33
|
+
* whether it is the view the host would pick by default. Returned by
|
|
34
|
+
* {@link EditorService.editorsFor}; used to build "Open With" menus and the
|
|
35
|
+
* breadcrumb view-switcher.
|
|
36
|
+
*
|
|
37
|
+
* @category Consumer Services
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
export interface EditorViewInfo {
|
|
41
|
+
/** The editor's id (an {@link Editor.id}); pass back as `viewType`. */
|
|
42
|
+
id: string;
|
|
43
|
+
/** Human-facing label (falls back to {@link EditorViewInfo.id}). */
|
|
44
|
+
label: string;
|
|
45
|
+
/** True for the editor the host resolves by default (highest priority). */
|
|
46
|
+
isDefault: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Save callbacks an editor viewer registers via
|
|
51
|
+
* {@link EditorService.registerSaveHandler}, so the active-editor `save` /
|
|
52
|
+
* `saveAs` commands can dispatch to whichever editor is focused.
|
|
53
|
+
*
|
|
54
|
+
* @category Consumer Services
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
export interface EditorSaveHandlers {
|
|
58
|
+
/** Save the editor's contents. */
|
|
59
|
+
save: () => void | Promise<void>;
|
|
60
|
+
/** Save-as (prompt for a new path). Optional. */
|
|
61
|
+
saveAs?: () => void | Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What to open in a diff view, passed to {@link EditorService.openDiff}. The
|
|
66
|
+
* diff is **generic** — it renders two contents and knows nothing about where
|
|
67
|
+
* they come from. `providerId` names a {@link DiffContentProvider} (registered
|
|
68
|
+
* via {@link EditorService.registerDiffContentProvider}) that resolves the two
|
|
69
|
+
* sides; `args` is the serializable payload that provider needs (e.g. a git
|
|
70
|
+
* revision/mode) and is persisted so the content can be recomputed on restart.
|
|
71
|
+
*
|
|
72
|
+
* @category Consumer Services
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
export interface OpenDiffSpec {
|
|
76
|
+
/** The file the diff is OF — drives language detection, breadcrumb, title. */
|
|
77
|
+
filePath: string;
|
|
78
|
+
/** Id of the registered content provider that resolves the two sides. */
|
|
79
|
+
providerId: string;
|
|
80
|
+
/** Serializable args handed back to the provider to (re)compute content. */
|
|
81
|
+
args?: Record<string, unknown>;
|
|
82
|
+
/** Tab title. Defaults to the file's base name. */
|
|
83
|
+
title?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The two sides of a diff, resolved by a {@link DiffContentProvider}.
|
|
87
|
+
*
|
|
88
|
+
* @category Consumer Services
|
|
89
|
+
* @public
|
|
90
|
+
*/
|
|
91
|
+
export interface DiffContent {
|
|
92
|
+
/** Left/original side. */
|
|
93
|
+
original: string;
|
|
94
|
+
/** Right/modified side. */
|
|
95
|
+
modified: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The request a {@link DiffContentProvider} receives to resolve a diff's two
|
|
100
|
+
* sides — the {@link OpenDiffSpec}'s `filePath`/`args` plus the folder of the
|
|
101
|
+
* workspace the diff lives in (the natural cwd for path-relative providers).
|
|
102
|
+
*
|
|
103
|
+
* @category Consumer Services
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
export interface DiffContentRequest {
|
|
107
|
+
/** The file the diff is OF (from {@link OpenDiffSpec.filePath}). */
|
|
108
|
+
filePath: string;
|
|
109
|
+
/** The provider's args (from {@link OpenDiffSpec.args}). */
|
|
110
|
+
args?: Record<string, unknown>;
|
|
111
|
+
/** Folder of the workspace the diff lives in, or `null` if none. */
|
|
112
|
+
workspaceFolder: string | null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Resolves the two sides of a diff on demand — called by the host whenever a
|
|
117
|
+
* diff panel mounts (open, tab switch, app restart), so content stays a pure
|
|
118
|
+
* computed view and never has to be persisted. Register one with
|
|
119
|
+
* {@link EditorService.registerDiffContentProvider}.
|
|
120
|
+
*
|
|
121
|
+
* @category Consumer Services
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
export type DiffContentProvider = (
|
|
125
|
+
request: DiffContentRequest,
|
|
126
|
+
) => Promise<DiffContent>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The editor & document domain, exposed as {@link ExtensionContext.editors}.
|
|
130
|
+
* Open files into editor tabs, drive the active editor (save / close), and let
|
|
131
|
+
* editor viewers register save handlers. The single entry point for opening
|
|
132
|
+
* editors — prefer it over reaching into workspace/editor state.
|
|
133
|
+
*
|
|
134
|
+
* @category Consumer Services
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
137
|
+
export interface EditorService {
|
|
138
|
+
/**
|
|
139
|
+
* Open a file in an editor tab. Promotes an existing preview, focuses an
|
|
140
|
+
* already-open tab, or opens a new one.
|
|
141
|
+
*/
|
|
142
|
+
open(path: string, opts?: OpenFileOptions): void;
|
|
143
|
+
/** Open a fresh untitled editor. */
|
|
144
|
+
openUntitled(opts?: OpenFileOptions): void;
|
|
145
|
+
/**
|
|
146
|
+
* Open a diff view. The content is supplied by the {@link OpenDiffSpec.providerId | provider}
|
|
147
|
+
* named in `spec` — the editor itself is content-agnostic.
|
|
148
|
+
*/
|
|
149
|
+
openDiff(spec: OpenDiffSpec, opts?: OpenFileOptions): void;
|
|
150
|
+
/** Save the active editor. Returns false if there's no active saveable editor. */
|
|
151
|
+
save(): boolean;
|
|
152
|
+
/** Save-as the active editor. Returns false if unavailable. */
|
|
153
|
+
saveAs(): boolean;
|
|
154
|
+
/** Close the active dock panel. Returns false if there's nothing to close. */
|
|
155
|
+
closeActive(): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* List the editor views that match `path` (or `null` for an untitled buffer),
|
|
158
|
+
* highest-priority first, each flagged whether it's the one the host resolves
|
|
159
|
+
* by default. Read-only enumeration for building "Open With" menus and the
|
|
160
|
+
* breadcrumb view-switcher. Returns `[]` only when nothing matches — in
|
|
161
|
+
* practice never empty for a real path, since the core text editor matches
|
|
162
|
+
* everything.
|
|
163
|
+
*/
|
|
164
|
+
editorsFor(path: string | null): EditorViewInfo[];
|
|
165
|
+
/**
|
|
166
|
+
* Switch an already-open editor tab to a different view in place — without
|
|
167
|
+
* closing and reopening it — and persist the choice on the tab. No-op if the
|
|
168
|
+
* editor isn't found, `viewType` names no registered editor, or that editor
|
|
169
|
+
* doesn't match the tab's file. The panel remounts onto the new view, so
|
|
170
|
+
* per-instance state (scroll, selection) resets — expected, it's a different
|
|
171
|
+
* presenter.
|
|
172
|
+
*/
|
|
173
|
+
setViewType(
|
|
174
|
+
editorId: string,
|
|
175
|
+
viewType: string,
|
|
176
|
+
opts?: { workspaceId?: string },
|
|
177
|
+
): void;
|
|
178
|
+
/**
|
|
179
|
+
* Register save handlers for an editor instance (by its `editorId`), so the
|
|
180
|
+
* active-editor `save` / `saveAs` dispatch to it while it's focused. Dispose
|
|
181
|
+
* to unregister (do this when the editor unmounts).
|
|
182
|
+
*/
|
|
183
|
+
registerSaveHandler(
|
|
184
|
+
editorId: string,
|
|
185
|
+
handlers: EditorSaveHandlers,
|
|
186
|
+
): Disposable;
|
|
187
|
+
/**
|
|
188
|
+
* Register a {@link DiffContentProvider} under `providerId`. A diff opened
|
|
189
|
+
* with that `providerId` (see {@link OpenDiffSpec}) resolves its two sides
|
|
190
|
+
* through this provider, on every mount. Dispose to unregister.
|
|
191
|
+
*/
|
|
192
|
+
registerDiffContentProvider(
|
|
193
|
+
providerId: string,
|
|
194
|
+
provider: DiffContentProvider,
|
|
195
|
+
): Disposable;
|
|
196
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespaced, persisted key/value storage handed to side-panel components
|
|
3
|
+
* via `SidePanelProps.storage`. Each panel id gets its own bag; values are
|
|
4
|
+
* persisted alongside the rest of the app state.
|
|
5
|
+
*
|
|
6
|
+
* The store is hydrated asynchronously after the panels mount, so consumers
|
|
7
|
+
* that need to wait for restored values should check `props.hydrated` or
|
|
8
|
+
* use `subscribe` to re-read once it flips.
|
|
9
|
+
*
|
|
10
|
+
* @category Consumer Services
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export interface ExtensionStorage {
|
|
14
|
+
/** Read a value. Returns `fallback` if the key is missing. */
|
|
15
|
+
get<T>(key: string): T | undefined;
|
|
16
|
+
get<T>(key: string, fallback: T): T;
|
|
17
|
+
/** Write a value. `undefined` deletes the key. */
|
|
18
|
+
set(key: string, value: unknown): void;
|
|
19
|
+
/**
|
|
20
|
+
* Subscribe to changes in this namespace. Called on any set within this
|
|
21
|
+
* namespace, and also whenever the underlying app state finishes hydrating
|
|
22
|
+
* (so callers can re-read after persisted state loads).
|
|
23
|
+
*/
|
|
24
|
+
subscribe(listener: () => void): () => void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Disposable } from "./types";
|
|
2
|
+
|
|
3
|
+
// `ctx.files` — host-mediated filesystem access. The public contract; the host
|
|
4
|
+
// implementation (a single chokepoint over the privileged Tauri fs/watch
|
|
5
|
+
// commands) lives in the extension host.
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Metadata for a single directory entry, as returned by
|
|
9
|
+
* {@link FileService.readDir}.
|
|
10
|
+
*
|
|
11
|
+
* @category Core Types
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export interface FileMeta {
|
|
15
|
+
/** The entry's base name (no path). */
|
|
16
|
+
name: string;
|
|
17
|
+
/** Absolute path to the entry. */
|
|
18
|
+
path: string;
|
|
19
|
+
/** True if the entry is a directory. */
|
|
20
|
+
isDir: boolean;
|
|
21
|
+
/** Size in bytes (0 for directories). */
|
|
22
|
+
size: number;
|
|
23
|
+
/** Last-modified time, milliseconds since the Unix epoch. */
|
|
24
|
+
modifiedMs: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A filesystem change event delivered to a {@link FileService.watch} listener,
|
|
29
|
+
* for changes under that watch's path.
|
|
30
|
+
*
|
|
31
|
+
* @category Core Types
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
export interface FileChangeEvent {
|
|
35
|
+
/** The paths that changed in this event. */
|
|
36
|
+
paths: string[];
|
|
37
|
+
/** The backend's change kind (e.g. `"create"`, `"modify"`, `"remove"`). */
|
|
38
|
+
kind: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The filesystem domain, exposed as {@link ExtensionContext.files}. All access
|
|
43
|
+
* is host-mediated: extensions read, write, and watch the filesystem through
|
|
44
|
+
* here rather than calling Tauri directly.
|
|
45
|
+
*
|
|
46
|
+
* **Paths are workspace-scoped.** A relative path resolves against the open
|
|
47
|
+
* workspace folder (`"src/index.ts"` → `<workspace>/src/index.ts`); an absolute
|
|
48
|
+
* path is allowed only if it falls inside a workspace folder. A path outside the
|
|
49
|
+
* workspace throws {@link PathDeniedError} unless the extension declared the
|
|
50
|
+
* matching {@link Permission} (`fs:read` for reads, `fs:write` for writes).
|
|
51
|
+
* First-party (bundled) extensions are unscoped. Prefer relative paths — they're
|
|
52
|
+
* portable across machines.
|
|
53
|
+
*
|
|
54
|
+
* Watching is host-owned: {@link FileService.watch} expresses intent — "tell me
|
|
55
|
+
* about changes under this path" — and the host owns the underlying OS
|
|
56
|
+
* watcher(s). Many in-workspace subscriptions are served from a single,
|
|
57
|
+
* ref-counted workspace watcher the host manages; extensions never start or
|
|
58
|
+
* stop watchers themselves, and each listener receives only events scoped to
|
|
59
|
+
* its path.
|
|
60
|
+
*
|
|
61
|
+
* @category Consumer Services
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export interface FileService {
|
|
65
|
+
/** Read a file's contents as UTF-8 text. */
|
|
66
|
+
readText(path: string): Promise<string>;
|
|
67
|
+
/** Read a file's raw bytes. */
|
|
68
|
+
readBytes(path: string): Promise<ArrayBuffer>;
|
|
69
|
+
/** List a directory's immediate entries. */
|
|
70
|
+
readDir(path: string): Promise<FileMeta[]>;
|
|
71
|
+
/** Resolve true if a file or directory exists at `path`. */
|
|
72
|
+
pathExists(path: string): Promise<boolean>;
|
|
73
|
+
/** Write UTF-8 text to a file, creating or overwriting it. */
|
|
74
|
+
writeText(path: string, content: string): Promise<void>;
|
|
75
|
+
/** Create a directory (and any missing parents). */
|
|
76
|
+
createDir(path: string): Promise<void>;
|
|
77
|
+
/** Rename / move a file or directory. */
|
|
78
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
79
|
+
/** Delete a file or directory. */
|
|
80
|
+
delete(path: string): Promise<void>;
|
|
81
|
+
/** Reveal a path in the OS file manager (Finder / Explorer). */
|
|
82
|
+
reveal(path: string): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Watch `path` recursively, invoking `listener` for each change under it.
|
|
85
|
+
* Returns a {@link Disposable} that stops listening when disposed. Watcher
|
|
86
|
+
* lifecycle is the host's concern — in-workspace paths ride the host's
|
|
87
|
+
* ref-counted workspace watcher rather than each spinning up its own.
|
|
88
|
+
*/
|
|
89
|
+
watch(path: string, listener: (event: FileChangeEvent) => void): Disposable;
|
|
90
|
+
}
|