Window
sdk.window охватывает всё, что пользователь видит за пределами графа. Здесь же создаются вебвью — у них своя страница.
Уведомления
showInfoMessage(title: string, message?: string, options?: Partial<SDkNotificationOptions>): Promise<SDkNotificationHandle | undefined>
showWarnMessage(title, message?, options?)
showErrorMessage(title, message?, options?)
showSuccessMessage(title, message?, options?)
Метод задаёт вид уведомления (info, warning, error, success). Promise разрешается дескриптором или undefined, если уведомление не удалось показать.
| Опция | Описание |
| --- | --- |
| sticky | Не закрывать автоматически. По умолчанию false. |
| timeout | Задержка автозакрытия в мс. По умолчанию 5000; 0 тоже означает значение по умолчанию. Игнорируется, пока задан sticky или loading. |
| progress | Прогресс-бар, 0–100, или null — скрыть (по умолчанию). Не показывается при loading. |
| loading | Показать спиннер. Уведомление с loading не закрывается автоматически. По умолчанию false. |
| type | NotificationType: 'info', 'warning', 'error' или 'success'. Переопределяет вид, заданный методом. |
| title / message | То же, что аргументы — пригодится в update(). |
| source | Сейчас ни на что не влияет: источником всегда показывается display name (или id) вашего расширения. |
| severity | Сейчас ни на что не влияет. |
Пока задан loading или ненулевой progress, у уведомления нет кнопки закрытия. Уведомление с progress всё равно закроется через timeout, если оно не sticky.
Дескриптор позволяет управлять уведомлением после его показа:
| Опция | Описание |
| --- | --- |
| id | Id уведомления. |
| update(options) | Изменить заголовок, текст или любую опцию (кроме source). |
| progress(value) | Прогресс-бар (0–100, null — скрыть). |
| loading(value) | Спиннер вкл/выкл. |
| dismiss() | Закрыть уведомление. |
| dispose() | То же, что dismiss() — handle можно положить в context.subscriptions. |
| markAsRead() | Пометить прочитанным, не закрывая. |
Вызовы на уже закрытом уведомлении ничего не делают.
const handle = await sdk.window.showInfoMessage('Деплой', 'Загружаем образ…', { sticky: true })
handle?.progress(40)
// ...
handle?.dismiss()
SDkNotificationOptions
interface SDkNotificationOptions {
title: string
message?: string
type?: NotificationType // 'info' | 'warning' | 'error' | 'success'
severity?: NotificationSeverity // 0 | 1 | 2 | 3 — сейчас ни на что не влияет
source?: string // сейчас ни на что не влияет
sticky?: boolean // по умолчанию false
timeout?: number // мс, по умолчанию 5000
progress?: number | null // 0–100, по умолчанию null
loading?: boolean // по умолчанию false
}
SDkNotificationHandle
interface SDkNotificationHandle {
readonly id: string
update(options: Partial<SDkNotificationOptions>): void
progress(value: number | null): void
loading(value: boolean): void
dismiss(): void
markAsRead(): void
dispose(): void
}
Быстрый ввод
showInputBox(options: SdkInputBoxOptions, abortSignal?: AbortSignal): Promise<string | undefined>
showQuickPick(items: QuickPickItemEntry[], options?: QuickPickOptions, abortSignal?: AbortSignal): Promise<QuickPickResult<QuickPickOptions> | undefined>
showConfirm(options?: ConfirmOptions, abortSignal?: AbortSignal): Promise<boolean | undefined>
Что возвращает каждый вызов:
| Метод | Результат |
| --- | --- |
| showInputBox | Введённый текст. undefined, если пользователь отменил ввод (Escape, закрытие) или отправил пустое значение. |
| showQuickPick | Выбранный элемент или массив элементов при canSelectMany: true. undefined, если пользователь отменил выбор или принял пустой выбор. |
| showConfirm | true — подтверждено, false — отменено (Cancel, Escape, закрытие). undefined — только если диалог не удалось показать. |
Срабатывание abortSignal закрывает диалог и завершает вызов как отменённый (undefined, для showConfirm — false).
Input box
| Опция | Описание |
| --- | --- |
| title | Заголовок. |
| value | Начальное значение. |
| placeholder | Текст-заглушка. |
| prompt | Подсказка под полем. |
| password | Скрывать ввод. Игнорируется при textArea. |
| textArea | Многострочное поле. Enter отправляет значение, поэтому перенос строки не ввести. |
| wrapperClassName | CSS-класс контейнера диалога. |
| validateInputDebounceMs | Сейчас ни на что не влияет — функцию валидации нельзя передать через SDK. |
| skippable | Сейчас ни на что не влияет — показывает кнопку Skip, которая ничего не делает. Не задавайте. |
Быстрый выбор
Элементы — объекты QuickPickItem, между группами — разделители { type: 'separator' }:
| Поле | Описание |
| --- | --- |
| id | Id элемента — возвращается в результате. |
| displayName | Подпись. Участвует в поиске. |
| type | 'item'. |
| detail | Дополнительный текст справа. Участвует в поиске. |
| picked | Отмечен заранее в режиме множественного выбора (только элементы верхнего уровня). |
| children | Вложенные элементы. Выбор элемента (или →) открывает подсписок; Escape или ← — назад. В режиме множественного выбора выбранный дочерний элемент заменяет выбранного соседа и возвращает к родительскому списку. |
| commandId | Показывает рядом с элементом сочетание клавиш этой команды. Выбор элемента команду не запускает. |
| color | Сейчас ни на что не влияет. |
| Опция | Описание |
| --- | --- |
| title | Заголовок. |
| placeholder | Заглушка поля поиска. |
| value | id элемента, подсвеченного при открытии списка. |
| canSelectMany | Режим с чекбоксами: клик или Enter переключает элемент, кнопка Accept подтверждает. Результат становится массивом. |
| acceptLabel | Подпись кнопки Accept. По умолчанию "Accept". |
| hideSearch | Скрыть поле поиска. |
| wrapperClassName | CSS-класс контейнера диалога. |
| skippable | Сейчас ни на что не влияет — показывает кнопку Skip, которая ничего не делает. Не задавайте. |
В режиме одиночного выбора клик по элементу или Enter на нём сразу завершает вызов.
const pick = await sdk.window.showQuickPick(
[
{ id: 'dev', displayName: 'Development', type: 'item' },
{ id: 'prod', displayName: 'Production', type: 'item' },
],
{ title: 'Выберите окружение' },
)
if (pick) { /* pick.id */ }
Подтверждение
| Опция | Описание |
| --- | --- |
| title | Заголовок. |
| message | Текст. Вставьте в него {highlight}, чтобы показать highlightedText бейджем в этом месте. |
| highlightedText | Текст на месте {highlight}. |
| confirmLabel | Подпись кнопки подтверждения. По умолчанию 'Confirm'. |
| cancelLabel | Подпись кнопки отмены. По умолчанию 'Cancel'. |
| wrapperClassName | CSS-класс контейнера диалога. |
Enter подтверждает, Escape отменяет.
import type { ConfirmOptions } from '@fragmenta/extension'
const ui = sdk.window as typeof sdk.window & {
showConfirm(options?: ConfirmOptions, abortSignal?: AbortSignal): Promise<boolean | undefined>
}
const confirmed = await ui.showConfirm({
title: 'Удаление окружения',
message: 'Удалить {highlight}? Это нельзя отменить.',
highlightedText: 'production',
confirmLabel: 'Удалить',
})
if (confirmed) { /* ... */ }
SdkInputBoxOptions
interface SdkInputBoxOptions {
title?: string
value?: string
placeholder?: string
prompt?: string
password?: boolean
textArea?: boolean
wrapperClassName?: string
validateInputDebounceMs?: number // сейчас ни на что не влияет
skippable?: boolean // сейчас ни на что не влияет
}
QuickPickItemEntry
type QuickPickItemEntry = QuickPickItem | QuickPickSeparator
interface QuickPickItem {
id: string
displayName: string
type: 'item'
detail?: string
picked?: boolean
children?: QuickPickItemEntry[]
commandId?: string
color?: string // сейчас ни на что не влияет
}
interface QuickPickSeparator {
type: 'separator'
}
QuickPickOptions
interface QuickPickOptions {
title?: string
placeholder?: string
value?: string
canSelectMany?: boolean
acceptLabel?: string
hideSearch?: boolean
wrapperClassName?: string
skippable?: boolean // сейчас ни на что не влияет
}
QuickPickResult
type QuickPickResult<T extends QuickPickOptions> = T extends { canSelectMany: true }
? QuickPickItem[] | undefined
: QuickPickItem | undefined
ConfirmOptions
interface ConfirmOptions {
title?: string
message?: string
highlightedText?: string
confirmLabel?: string // по умолчанию 'Confirm'
cancelLabel?: string // по умолчанию 'Cancel'
wrapperClassName?: string
skippable?: boolean // для confirm ни на что не влияет
}
Модальные окна
showModal(options: SdkModalOptions): Promise<void>
hideModal(): Promise<void>
Модальное окно содержит либо вебвью ({ webviewId } — id из handle webview), либо встроенное представление ({ viewId, viewArgs? }).
| Опция | Описание |
| --- | --- |
| size | Пресет или свой размер (см. ниже). По умолчанию 'md'. |
| position | 'center' (по умолчанию), 'top', 'bottom', 'left' или 'right'. |
| closeOnOverlayClick | Закрывать по клику вне модалки. По умолчанию true. |
| closeOnEscape | Закрывать по Escape. По умолчанию true. |
| preventScroll | По умолчанию true: модальный диалог с затемнённым фоном, который блокирует прокрутку и удерживает фокус внутри. false — показать без затемнения. |
| transparent | Без фона, рамки и тени — рамку рисует ваш контент. По умолчанию false. |
| className | Дополнительный CSS-класс контейнера модалки. |
Пресеты размера: 'xs', 'sm', 'md', 'lg', 'xl', '2xl' задают возрастающую максимальную ширину, высота подстраивается под контент. 'full' — до 90% окна по обеим осям, 'auto' — по ширине контента.
Пользовательский размер: { width, height, maxWidth, maxHeight, minWidth, minHeight }, все поля необязательны. Строки — CSS-значения ('85%', '40rem'), числа — пиксели.
Одновременно может быть открыто только одно модальное окно — вызов showModal заменяет текущее. showModal разрешается, когда модальное окно открыто, а не когда оно закрывается. Если представление модального окна не существует, ничего не открывается, и promise всё равно разрешается. hideModal закрывает любое открытое модальное окно. Закрытие модального окна не освобождает его веб-представление.
const webview = await sdk.window.createWebview('mapper-view', { html })
await sdk.window.showModal({
webviewId: webview.id,
position: 'center',
size: { width: '85%', height: '85%' },
closeOnEscape: true,
})
SdkModalOptions
type SdkModalOptions =
| (SdkModalBaseOptions & { webviewId: string })
| (SdkModalBaseOptions & { viewId: string; viewArgs?: unknown })
interface SdkModalBaseOptions {
size?: ModalSizePreset | ModalCustomSize // по умолчанию 'md'
position?: 'center' | 'top' | 'bottom' | 'left' | 'right' // по умолчанию 'center'
closeOnOverlayClick?: boolean // по умолчанию true
closeOnEscape?: boolean // по умолчанию true
preventScroll?: boolean // по умолчанию true
transparent?: boolean // по умолчанию false
className?: string
}
type ModalSizePreset = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | 'auto'
interface ModalCustomSize {
width?: string | number
height?: string | number
maxWidth?: string | number
maxHeight?: string | number
minWidth?: string | number
minHeight?: string | number
}
Файловые диалоги
showOpenDialog(options: SdkFsOpenDialogOptions): Promise<FsHandle[] | undefined>
showSaveDialog(options: SdkFsSaveDialogOptions): Promise<FsHandle | undefined>
showOpenDialog возвращает выбранные записи или undefined, если пользователь отменил выбор.
| Опция | Описание |
| --- | --- |
| title | Заголовок диалога. |
| buttonLabel | Подпись кнопки подтверждения. |
| canSelectFiles | Разрешить файлы. По умолчанию true. |
| canSelectFolders | Разрешить папки. По умолчанию false. |
| canSelectMany | Разрешить несколько записей. По умолчанию false. |
| filters | [{ name, extensions }]. Все фильтры объединяются в один список разрешённых расширений, name не показывается. Расширения можно писать с точкой или без; '*' игнорируется. |
Когда разрешены и файлы, и папки, macOS позволяет пользователю выбрать любое, а в Windows и Linux показывается выбор папки. В браузере title и buttonLabel игнорируются, и если выбор папок разрешён, всегда показывается выбор папки.
Возвращаемый FsHandle даёт scoped-доступ к выбранной записи:
| Член | Описание |
| --- | --- |
| kind | 'file' или 'directory'. У записей из readDir() также бывает 'symbolicLink' или 'unknown'. |
| name | Имя файла или папки. |
| path | Полный путь в формате ОС (на Windows через \). |
| size | Размер в байтах; 0 у папок. |
| type | 'application/octet-stream' у файлов и '' у папок. Файлы, выбранные в браузере, сообщают свой MIME-тип. |
| readFile() | Promise<Uint8Array>. |
| readTextFile() | Promise<string>. |
| stat() | Promise<FileStats \| null> — { name, size, type }. |
| readDir() | Записи папки с name, type, полным path и собственным handle — так обходятся вложенные папки. |
| writeFile(content) | Записать Uint8Array или строку. См. ограничение ниже. |
Дескрипторы принадлежат вашему расширению и истекают через 30 минут после выдачи — вызовы на истёкшем дескрипторе отклоняются. readDir() выдаёт записям новые дескрипторы.
const [folder] = (await sdk.window.showOpenDialog({ canSelectFiles: false, canSelectFolders: true })) ?? []
for (const entry of (await folder?.readDir()) ?? []) {
if (entry.handle.kind === 'directory') await entry.handle.readDir()
else await entry.handle.readTextFile()
}
SdkFsOpenDialogOptions / SdkFsSaveDialogOptions
interface SdkFsOpenDialogOptions {
title?: string
buttonLabel?: string
canSelectFiles?: boolean // по умолчанию true
canSelectFolders?: boolean // по умолчанию false
canSelectMany?: boolean // по умолчанию false
filters?: SdkFsFileFilter[]
}
interface SdkFsSaveDialogOptions {
title?: string
buttonLabel?: string
defaultFileName?: string
filters?: SdkFsFileFilter[]
}
interface SdkFsFileFilter {
name: string
extensions: string[]
}
FsHandle
type FsHandleKind = 'file' | 'directory' | 'symbolicLink' | 'unknown'
interface FsHandle {
readonly kind: FsHandleKind
readonly name: string
readonly path: string
readonly size: number
readonly type: string
readonly readFile: () => Promise<Uint8Array>
readonly readTextFile: () => Promise<string>
readonly writeFile: (content: Uint8Array | string) => Promise<void>
readonly stat: () => Promise<FileStats | null>
readonly readDir: () => Promise<FsHandleDirEntry[]>
}
interface FsHandleDirEntry {
readonly name: string
readonly type: FsHandleKind
readonly path: string
readonly handle: FsHandle
}
interface FileStats {
name: string
size: number
type: FsHandleKind
}
Statusbar
createStatusbarItem(id: string, alignment?: 'left' | 'right', priority?: number, workspace?: AppActiveWorkspace): IExtensionSdkStatusbarItem
Элемент создаётся сразу видимым, с пустым текстом — задайте text сразу после создания или сначала выставьте visible = false. id должен быть уникальным в пределах расширения; к нему добавляется префикс с id расширения. Методов show()/hide() нет — переключайте visible.
Элемент настраивается мутабельными свойствами:
| Свойство | Описание |
| --- | --- |
| id | Только чтение. <extensionId>.<id>. |
| extensionId | Только чтение. Id вашего расширения. |
| text | Текст в статус-баре. По умолчанию ''. $(icon-name) вставляет иконку Lucide, например '$(check) Готово'. Длинный текст обрезается. |
| tooltip | Текст при наведении, рендерится как Markdown. string или { value: string }. |
| command | Id вашей команды, выполняемой по клику. Id расширения добавляется автоматически. |
| color / backgroundColor | CSS-цвета. |
| showProgress | Крутящаяся иконка после текста: true, 'loading' или 'syncing' (у каждого своя иконка). false или не задано — скрыта. |
| when | Контекстное выражение. Элемент виден, только пока оно истинно и visible равно true. |
| visible | Показать или скрыть элемент. По умолчанию true. |
| alignment | 'left' или 'right'. По умолчанию 'right'. |
| priority | Порядок на своей стороне. Слева больший приоритет — левее, справа — правее. По умолчанию 0. |
| workspace | Показывать элемент только в одном workspace: 'auth', 'project', 'team', 'extensionWorkshop' или 'home'. Не задано — во всех. |
| dispose() | Удалить элемент. |
const item = sdk.window.createStatusbarItem('my-status', 'right')
item.text = 'Готово'
item.command = 'sayHello'
item.visible = true
context.subscriptions.push(item)
IExtensionSdkStatusbarItem
interface IExtensionSdkStatusbarItem {
readonly id: string
readonly extensionId: string
alignment: 'left' | 'right'
priority?: number
workspace?: AppActiveWorkspace // 'auth' | 'project' | 'team' | 'extensionWorkshop' | 'home'
text: string
tooltip?: string | { value: string }
command?: string
color?: string
backgroundColor?: string
showProgress?: boolean | 'loading' | 'syncing'
when?: string
visible: boolean
dispose(): void
}
Output-каналы
createOutputChannel(name: string, options?: ExtensionSdkCreateOutputChannelOptions): Promise<ExtensionSdkOutputChannelHandle | undefined>
createLogOutputChannel(name: string, options?: ExtensionSdkCreateLogOutputChannelOptions): Promise<ExtensionSdkLogOutputChannelHandle | undefined>
| Опция | Описание |
| --- | --- |
| id | Id канала. Если не задан, генерируется. |
| maxLines | Сколько строк хранить; старые строки отбрасываются. По умолчанию 5000. |
| minLevel | Только для log-каналов: минимальный показываемый уровень. По умолчанию INFO (1). |
Оба метода возвращают undefined, если канал с таким же id или таким же name уже существует — имена общие для всех расширений. Каналы удаляются при деактивации расширения.
Обычный канал — текстовый поток:
| Член | Описание |
| --- | --- |
| id / name | Id и имя канала. |
| append(value) | Добавить текст без переноса строки. |
| appendLine(value) | Добавить текст и перенос строки. |
| replace(value) | Заменить всё содержимое. |
| clear() | Очистить содержимое. |
| reveal() | Открыть view Output в нижней панели на вашем канале. |
| dispose() | Удалить канал. |
Все члены, кроме dispose(), возвращают Promise<void>.
Log-канал добавляет уровни — trace, debug, info, warn(message, ...args) и error(messageOrError, ...args) — и setMinLevel(level). Если в error передан Error, логируется его сообщение, а сама ошибка уходит дополнительным аргументом.
Значения LogLevel:
| Уровень | Значение |
| --- | --- |
| DEBUG | 0 |
| INFO | 1 |
| WARN | 2 |
| ERROR | 3 |
| TRACE | 4 |
@fragmenta/extension не экспортирует LogLevel — передавайте число.
const log = await sdk.window.createLogOutputChannel('My Extension')
log?.info('Запустились', { version: context.extension.version })
log?.error(new Error('Что-то сломалось'))
Опции канала
interface ExtensionSdkCreateOutputChannelOptions {
readonly id?: string
readonly maxLines?: number // по умолчанию 5000
}
interface ExtensionSdkCreateLogOutputChannelOptions extends ExtensionSdkCreateOutputChannelOptions {
readonly minLevel?: LogLevel // по умолчанию INFO (1)
}
enum LogLevel {
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
TRACE = 4,
}
ExtensionSdkOutputChannelHandle
interface ExtensionSdkOutputChannelHandle {
readonly id: string
readonly name: string
append(value: string): Promise<void>
appendLine(value: string): Promise<void>
replace(value: string): Promise<void>
clear(): Promise<void>
reveal(): Promise<void>
dispose(): void
}
ExtensionSdkLogOutputChannelHandle
interface ExtensionSdkLogOutputChannelHandle extends ExtensionSdkOutputChannelHandle {
setMinLevel(level: LogLevel): Promise<void>
trace(message: string, ...args: unknown[]): Promise<void>
debug(message: string, ...args: unknown[]): Promise<void>
info(message: string, ...args: unknown[]): Promise<void>
warn(message: string, ...args: unknown[]): Promise<void>
error(message: string | Error, ...args: unknown[]): Promise<void>
}