Compare commits
No commits in common. "main" and "v0.1.0-alpha.4" have entirely different histories.
main
...
v0.1.0-alp
21
README.md
21
README.md
|
|
@ -1,26 +1,13 @@
|
|||
<div align="center">
|
||||
|
||||
# Verstak Official Plugins
|
||||
|
||||
### The first-party plugin set — Files, Notes, Editor, Activity, Journal and more.
|
||||
|
||||
**English** · [Русский](README.ru.md)
|
||||
|
||||
[](https://github.com/mirivlad/verstak-official-plugins/releases)
|
||||

|
||||
[](LICENSE)
|
||||
|
||||
</div>
|
||||
The first-party plugin set for Verstak Desktop: Files, Trash, Notes, editor and
|
||||
preview providers, Browser Inbox, Activity, Journal, Todo, Search, Secrets and
|
||||
Templates. Plugin bundles are built into independent directories that the
|
||||
desktop host loads from its `plugins/` folder.
|
||||
|
||||
> **Alpha software.** Build this repository together with compatible
|
||||
> `verstak-desktop` and `verstak-sdk` checkouts.
|
||||
|
||||
Verstak Official Plugins is the first-party plugin set for Verstak Desktop:
|
||||
Files, Trash, Notes, Default Editor, File Preview, Browser Inbox, Activity,
|
||||
Journal, Todo, Search, Secrets, Sync, and Templates. Plugin bundles are built
|
||||
into independent directories that the desktop host loads from its `plugins/`
|
||||
folder.
|
||||
|
||||
## Build
|
||||
|
||||
Requirements: Node.js with npm, Go and Python 3. Keep this repository next to
|
||||
|
|
|
|||
91
README.ru.md
91
README.ru.md
|
|
@ -1,91 +0,0 @@
|
|||
<div align="center">
|
||||
|
||||
# Официальные плагины Верстака
|
||||
|
||||
### Базовый набор плагинов — Файлы, Заметки, Редактор, Активность, Журнал и другие.
|
||||
|
||||
[English](README.md) · **Русский**
|
||||
|
||||
[](https://github.com/mirivlad/verstak-official-plugins/releases)
|
||||

|
||||
[](LICENSE)
|
||||
|
||||
</div>
|
||||
|
||||
> **Alpha-версия.** Собирайте этот репозиторий вместе с совместимыми
|
||||
> версиями `verstak-desktop` и `verstak-sdk`.
|
||||
|
||||
Официальные плагины — базовый набор инструментов Верстака: Файлы, Корзина,
|
||||
Заметки, Редактор, Предпросмотр, Входящие из браузера, Активность, Журнал,
|
||||
Задачи, Поиск, Секреты, Синхронизация и Шаблоны. Плагины собираются в
|
||||
независимые пакеты, которые desktop-приложение загружает из папки `plugins/`.
|
||||
|
||||
## Состав
|
||||
|
||||
| Плагин | Назначение |
|
||||
|--------|------------|
|
||||
| `verstak.files` | Файловый менеджер внутри дела |
|
||||
| `verstak.trash` | Корзина: восстановление и удаление |
|
||||
| `verstak.notes` | Заметки в формате Markdown |
|
||||
| `verstak.default-editor` | Редактор текста и Markdown |
|
||||
| `verstak.file-preview` | Предпросмотр изображений |
|
||||
| `verstak.activity` | История активности и реконструкция работы |
|
||||
| `verstak.journal` | Журнал работ |
|
||||
| `verstak.browser-inbox` | Приём материалов из браузера |
|
||||
| `verstak.search` | Поиск по файлам и заметкам |
|
||||
| `verstak.secrets` | Защищённое хранилище доступов |
|
||||
| `verstak.todo` | Списки задач |
|
||||
| `verstak.sync` | Синхронизация между устройствами |
|
||||
| `verstak.templates` | Шаблоны дел |
|
||||
|
||||
Все плагины используют один и тот же runtime, что и сторонние.
|
||||
|
||||
## Сборка
|
||||
|
||||
Требования: Node.js с npm, Go и Python 3. Репозиторий должен находиться рядом
|
||||
с `verstak-sdk`, чтобы проверка manifest использовала SDK-схему.
|
||||
|
||||
```bash
|
||||
npm --version
|
||||
go version
|
||||
./scripts/check.sh
|
||||
./scripts/build.sh
|
||||
```
|
||||
|
||||
Сборка создаёт пакеты в `dist/<plugin-id>/`. Чтобы установить их в соседний
|
||||
desktop-репозиторий:
|
||||
|
||||
```bash
|
||||
cd ../verstak-desktop
|
||||
./scripts/install-dev-plugins.sh
|
||||
```
|
||||
|
||||
## Портативные архивы плагинов
|
||||
|
||||
Сборка архивов под конкретную платформу (Linux):
|
||||
|
||||
```bash
|
||||
sudo apt install gcc-mingw-w64-x86-64
|
||||
./scripts/package-portable.sh v0.1.0-alpha.1
|
||||
```
|
||||
|
||||
Команда создаёт `release/verstak-official-plugins-linux-amd64-<version>.tar.gz`
|
||||
и `release/verstak-official-plugins-windows-amd64-<version>.zip`, а также
|
||||
`SHA256SUMS`. Каждый архив распаковывается прямо в `plugins/` desktop-приложения.
|
||||
Frontend и manifest общие; нативные Go sidecar собираются под целевую ОС.
|
||||
Это локальная операция упаковки, она не создаёт GitHub Release.
|
||||
|
||||
## Публикация GitHub Release
|
||||
|
||||
```bash
|
||||
./scripts/publish-github-release.sh v0.1.0-alpha.1
|
||||
```
|
||||
|
||||
Требуется авторизованный [`gh`](https://cli.github.com/) CLI и чистый
|
||||
актуальный `main`. Создаёт и отправляет аннотированный тег, затем создаёт
|
||||
или обновляет GitHub Release с Linux-архивом, Windows-архивом и `SHA256SUMS`.
|
||||
|
||||
## Лицензия
|
||||
|
||||
Copyright © 2026 Verstak contributors. Распространяется на условиях
|
||||
[GNU AGPLv3 или новее](LICENSE).
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
# План улучшений файлового менеджера Verstak2
|
||||
|
||||
> **Архитектура:** Плагин `verstak.files` в монорепозитории `verstak-official-plugins`.
|
||||
> Код: `plugins/files/frontend/src/index.js` (vanilla JS, VerstakPluginRegister).
|
||||
> API: `api.files.*`, `api.workbench.openResource()`, `api.settings`, `api.events`, `api.commands`.
|
||||
|
||||
## Порядок реализации
|
||||
|
||||
| # | Feature | Приоритет | Зависит от |
|
||||
|---|---------|-----------|------------|
|
||||
| 1 | Контекстное меню (правый клик) | 🔥 High | — |
|
||||
| 2 | Open External / Show in Explorer | ✅ Done | `files.openExternal` |
|
||||
| 3 | Кастомный ConfirmModal | 🔥 High | — |
|
||||
| 4 | Duplicate | 🔥 High | — |
|
||||
| 5 | Cut/Copy/Paste | 🔥 High | — |
|
||||
| 6 | Множественное выделение | 🔥 High | — |
|
||||
| 7 | Drag-and-Drop | 🔥 High | — |
|
||||
| 8 | Клавиатурная навигация (Ctrl+A, Escape, стрелки) | Medium | #6 |
|
||||
| 9 | Богатые иконки (как в v1) | Medium | — |
|
||||
| 10 | История навигации | Medium | — |
|
||||
| 11 | Rename с валидацией | Medium | — |
|
||||
|
||||
---
|
||||
|
||||
### Feature 1: Контекстное меню (правый клик)
|
||||
|
||||
**Описание:** При правом клике на файле/папке показывать меню с действиями.
|
||||
|
||||
**Пункты меню:** Open, Open External, Show in Explorer, Rename, Duplicate, Cut, Copy, Delete — с разделителями.
|
||||
|
||||
**Архитектура:**
|
||||
- Событие `contextmenu` на `.files-item`
|
||||
- Позиционирование у курсора (event.clientX/Y)
|
||||
- Кастомный `<div>` с пунктами, закрывается по клику вне или Escape
|
||||
- Класс `.files-context-menu` для стилей
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 2: Open External / Show in Explorer
|
||||
|
||||
**Описание:** Пункты меню для открытия файла во внешнем приложении и показа
|
||||
файла/папки в системном файловом менеджере.
|
||||
|
||||
**Текущий v2 статус:** плагин использует публичные методы
|
||||
`api.files.openExternal(relativePath)` и `api.files.showInFolder(relativePath)`,
|
||||
guarded by `files.openExternal`. Fallback modal с vault-relative path и кнопкой
|
||||
`Copy Path` показывается только если API недоступен или вернул ошибку.
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 3: Кастомный ConfirmModal
|
||||
|
||||
**Описание:** Вместо `window.confirm()` — стилизованный modal с кнопками Отмена/Удалить, опасным стилем (красная кнопка).
|
||||
|
||||
**Архитектура:**
|
||||
- Функция `confirmModal(message, options)` возвращает Promise
|
||||
- Создаёт overlay + modal в DOM
|
||||
- Закрывается по Escape или кнопке Отмена
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 4: Duplicate
|
||||
|
||||
**Описание:** Копирование файла/папки в той же папке с добавлением суффикса (напр. "filename_copy.ext", "filename_2.ext").
|
||||
|
||||
**Архитектура:**
|
||||
- Для файла: `api.files.readText()` + `api.files.writeText()` с новым именем
|
||||
- Для папки: рекурсивное копирование (сложнее, можно defer)
|
||||
- Пункт в контекстном меню: "Duplicate"
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 5: Cut/Copy/Paste
|
||||
|
||||
**Описание:** Буфер обмена внутри файлового менеджера. Cut → перенос. Copy → дублирование. Paste в текущую папку.
|
||||
|
||||
**Архитектура:**
|
||||
- `clipboard: { items: [...], mode: 'cut'|'copy' }`
|
||||
- Клавиши Ctrl+X/C/V
|
||||
- Пункты в контекстном меню
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 6: Множественное выделение
|
||||
|
||||
**Описание:** Ctrl+click (toggle), Shift+click (range), Ctrl+A (select all). Массовые операции (Trash, Copy, Paste).
|
||||
|
||||
**Архитектура:**
|
||||
- `selectedPaths: Set<string>` вместо `selectedPath: string`
|
||||
- Ctrl+click → toggle entry в Set
|
||||
- Shift+click → range select от последнего клика
|
||||
- Действия применяются ко всем выделенным
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 7: Drag-and-Drop
|
||||
|
||||
**Описание:** Перемещение файлов/папок между папками через drag-and-drop.
|
||||
|
||||
**Архитектура:**
|
||||
- HTML5 DnD API: `dragstart`, `dragover`, `drop` на `.files-item`
|
||||
- При drop на папку → `api.files.move()`
|
||||
- Визуальная индикация (подсветка папки при наведении)
|
||||
- Отмена по Escape
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 8: Клавиатурная навигация
|
||||
|
||||
**Описание:** Escape (снять выделение), Ctrl+A (select all), стрелки (навигация по строкам).
|
||||
|
||||
**Зависит от:** Feature 6 (множественное выделение)
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 9: Богатые иконки
|
||||
|
||||
**Описание:** Как в v1 — отдельные SVG иконки для image, video, audio, pdf, document, spreadsheet, presentation, archive, code, text.
|
||||
|
||||
**Архитектура:** Расширить функцию `fileIcon()`.
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 10: История навигации
|
||||
|
||||
**Описание:** Кнопки Back/Forward в тулбаре, как в браузере. Хранение стека посещённых папок.
|
||||
|
||||
**Архитектура:**
|
||||
- `historyStack: string[]` с индексом
|
||||
- back() / forward() / push(path)
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
||||
---
|
||||
|
||||
### Feature 11: Rename с валидацией
|
||||
|
||||
**Описание:** Проверять имя через API до применения. Показывать ошибку под полем, а не в placeholder.
|
||||
|
||||
**Архитектура:**
|
||||
- Проверка: не пустое, нет `/`, нет null byte, не `.verstak`
|
||||
- API коллизии: `api.files.metadata(newPath)` — если существует, ошибка
|
||||
|
||||
**Файлы:** `plugins/files/frontend/src/index.js`
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
let connectionOk = null
|
||||
|
||||
let serverUrl = ''
|
||||
let vaultId = ''
|
||||
let username = ''
|
||||
let password = ''
|
||||
let syncInterval = 5
|
||||
|
|
@ -31,9 +30,6 @@
|
|||
|
||||
function reportError(key, fallback, error) {
|
||||
console.warn('[verstak.sync] operation failed:', error)
|
||||
const code = String(error?.message || error || '').match(/sync-server:([a-z_]+)/)?.[1]
|
||||
const localized = code ? tr(`ui.serverError.${code}`, null, '') : ''
|
||||
if (localized && localized !== `ui.serverError.${code}`) return localized
|
||||
return tr(key, null, fallback)
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +44,6 @@
|
|||
const saved = await api.settings.read()
|
||||
if (saved) {
|
||||
serverUrl = saved.serverUrl || ''
|
||||
vaultId = saved.vaultId || ''
|
||||
username = saved.username || ''
|
||||
autoSync = !!saved.autoSync
|
||||
syncInterval = saved.syncInterval || 5
|
||||
|
|
@ -61,7 +56,6 @@
|
|||
settings = await syncAPI().status()
|
||||
if (settings) {
|
||||
if (settings.serverUrl) serverUrl = settings.serverUrl
|
||||
if (settings.vaultId) vaultId = settings.vaultId
|
||||
if (settings.syncInterval != null) syncInterval = settings.syncInterval
|
||||
if (settings.syncInterval > 0) autoSync = true
|
||||
if (settings.lastError) console.warn('[verstak.sync] last sync failed:', settings.lastError)
|
||||
|
|
@ -84,7 +78,7 @@
|
|||
resultMsg = ''
|
||||
try {
|
||||
if (api?.settings?.writeAll) {
|
||||
await api.settings.writeAll({ serverUrl, vaultId, username, autoSync, syncInterval })
|
||||
await api.settings.writeAll({ serverUrl, username, autoSync, syncInterval })
|
||||
}
|
||||
await syncAPI().setInterval(autoSync ? syncInterval : 0)
|
||||
resultMsg = tr('ui.settingsSaved', null, 'Settings saved.')
|
||||
|
|
@ -118,7 +112,7 @@
|
|||
errorMsg = ''
|
||||
connectionResult = ''
|
||||
try {
|
||||
await syncAPI().configure(serverUrl, username, password, vaultId)
|
||||
await syncAPI().configure(serverUrl, username, password)
|
||||
connectionResult = tr('ui.connectedSuccessfully', null, 'Connected successfully.')
|
||||
connectionOk = true
|
||||
username = ''
|
||||
|
|
@ -241,11 +235,6 @@
|
|||
{tr('ui.lastSyncError', null, 'The last synchronization did not finish. Try again.')}
|
||||
</div>
|
||||
{/if}
|
||||
{#if settings && settings.lastWarning && !errorMsg}
|
||||
<div style="padding:0.5rem 0.75rem;margin-bottom:0.75rem;background:rgba(245,158,11,0.1);border:1px solid rgba(245,158,11,0.3);border-radius:6px;color:#f59e0b;font-size:0.85rem;">
|
||||
{tr('ui.unresolvedFilesWarning', null, 'Some files are not synchronized yet. Resolve the file warning and run sync again.')}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div style="background:#16213e;border:1px solid #0f3460;border-radius:8px;padding:1rem 1.25rem;margin-bottom:1rem;">
|
||||
<h3 style="margin:0 0 0.75rem;color:#e0e0f0;font-size:0.95rem;">{tr('ui.server', null, 'Server')}</h3>
|
||||
|
|
@ -255,12 +244,6 @@
|
|||
<input id="sync-server-url" type="text" style={INPUT_STYLE} on:focus={e => e.target.style.cssText = INPUT_FOCUS_STYLE} on:blur={e => e.target.style.cssText = INPUT_STYLE} bind:value={serverUrl} placeholder="https://example.com" />
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:0.75rem;">
|
||||
<label for="sync-vault-id" style="display:block;color:#a0a0b8;font-size:0.85rem;margin-bottom:0.35rem;">{tr('ui.remoteVaultId', null, 'Remote vault ID (optional)')}</label>
|
||||
<input id="sync-vault-id" type="text" style={INPUT_STYLE} on:focus={e => e.target.style.cssText = INPUT_FOCUS_STYLE} on:blur={e => e.target.style.cssText = INPUT_STYLE} bind:value={vaultId} />
|
||||
<div style="color:#a0a0b8;font-size:0.78rem;margin-top:0.3rem;">{tr('ui.remoteVaultHint', null, 'Leave empty for this vault. Enter an existing remote vault ID to restore it on this device.')}</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:0.75rem;">
|
||||
<label for="sync-username" style="display:block;color:#a0a0b8;font-size:0.85rem;margin-bottom:0.35rem;">{tr('ui.username', null, 'Username')}</label>
|
||||
<input id="sync-username" type="text" style={INPUT_STYLE} on:focus={e => e.target.style.cssText = INPUT_FOCUS_STYLE} on:blur={e => e.target.style.cssText = INPUT_STYLE} bind:value={username} />
|
||||
|
|
|
|||
|
|
@ -24,12 +24,9 @@
|
|||
"ui.keyReset": "Sync key reset. Connect again to pair this device.",
|
||||
"ui.syncConflicts": "Sync conflicts",
|
||||
"ui.lastSyncError": "The last synchronization did not finish. Try again.",
|
||||
"ui.unresolvedFilesWarning": "Some files are not synchronized yet. Resolve the file warning and run sync again.",
|
||||
"ui.syncConflictItem": "A synchronization conflict needs attention.",
|
||||
"ui.server": "Server",
|
||||
"ui.serverUrl": "Server URL",
|
||||
"ui.remoteVaultId": "Remote vault ID (optional)",
|
||||
"ui.remoteVaultHint": "Leave empty for this vault. Enter an existing remote vault ID to restore it on this device.",
|
||||
"ui.username": "Username",
|
||||
"ui.password": "Password",
|
||||
"ui.testConnection": "Test Connection",
|
||||
|
|
@ -48,14 +45,4 @@
|
|||
"ui.status.disabled": "Not configured",
|
||||
"ui.status.error": "Error",
|
||||
"ui.status.revoked": "Revoked"
|
||||
,"ui.serverError.rate_limited": "Too many attempts. Wait a little and try again."
|
||||
,"ui.serverError.request_too_large": "The synchronization request is too large."
|
||||
,"ui.serverError.payload_too_large": "A file operation is too large to send inline."
|
||||
,"ui.serverError.too_many_operations": "Too many pending changes were sent at once. Try synchronization again."
|
||||
,"ui.serverError.blob_too_large": "This file exceeds the server blob size limit."
|
||||
,"ui.serverError.quota_exceeded": "The server storage quota for this vault has been reached."
|
||||
,"ui.serverError.blob_not_owned": "The file data must be uploaded before it can be synchronized."
|
||||
,"ui.serverError.blob_not_found": "The required file data is unavailable on the server."
|
||||
,"ui.serverError.unauthorized": "This device is no longer authorized. Connect it again."
|
||||
,"ui.serverError.forbidden": "The server denied this synchronization request."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,12 +24,9 @@
|
|||
"ui.keyReset": "Ключ синхронизации сброшен. Подключитесь снова, чтобы связать устройство.",
|
||||
"ui.syncConflicts": "Конфликты синхронизации",
|
||||
"ui.lastSyncError": "Последняя синхронизация не завершилась. Повторите попытку.",
|
||||
"ui.unresolvedFilesWarning": "Некоторые файлы ещё не синхронизированы. Устраните предупреждение по файлу и повторите синхронизацию.",
|
||||
"ui.syncConflictItem": "Конфликт синхронизации требует внимания.",
|
||||
"ui.server": "Сервер",
|
||||
"ui.serverUrl": "URL сервера",
|
||||
"ui.remoteVaultId": "ID удалённого хранилища (необязательно)",
|
||||
"ui.remoteVaultHint": "Оставьте пустым для этого хранилища. Укажите ID существующего удалённого хранилища, чтобы восстановить его на этом устройстве.",
|
||||
"ui.username": "Имя пользователя",
|
||||
"ui.password": "Пароль",
|
||||
"ui.testConnection": "Проверить подключение",
|
||||
|
|
@ -48,14 +45,4 @@
|
|||
"ui.status.disabled": "Не настроено",
|
||||
"ui.status.error": "Ошибка",
|
||||
"ui.status.revoked": "Доступ отозван"
|
||||
,"ui.serverError.rate_limited": "Слишком много попыток. Подождите и повторите попытку."
|
||||
,"ui.serverError.request_too_large": "Запрос синхронизации слишком велик."
|
||||
,"ui.serverError.payload_too_large": "Операция с файлом слишком велика для отправки в этом виде."
|
||||
,"ui.serverError.too_many_operations": "Одновременно отправлено слишком много изменений. Повторите синхронизацию."
|
||||
,"ui.serverError.blob_too_large": "Размер файла превышает разрешённый сервером лимит."
|
||||
,"ui.serverError.quota_exceeded": "Достигнута квота серверного хранилища для этого vault."
|
||||
,"ui.serverError.blob_not_owned": "Данные файла должны быть загружены до синхронизации операции."
|
||||
,"ui.serverError.blob_not_found": "Необходимые данные файла недоступны на сервере."
|
||||
,"ui.serverError.unauthorized": "Устройство больше не авторизовано. Подключите его заново."
|
||||
,"ui.serverError.forbidden": "Сервер отклонил этот запрос синхронизации."
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"manifest.name": "Workspace Folders",
|
||||
"manifest.description": "Nested folders with icons, colors and drag-and-drop for the Deal tree.",
|
||||
"common.close": "Close",
|
||||
"common.cancel": "Cancel",
|
||||
"common.save": "Save",
|
||||
"common.create": "Create",
|
||||
"common.select": "Select",
|
||||
"workspaceTree.title": "Deals",
|
||||
"workspaceTree.new": "New Deal",
|
||||
"workspaceTree.nameRequired": "Name is required",
|
||||
"workspaceTree.namePlaceholder": "Deal name",
|
||||
"workspaceTree.template": "Template",
|
||||
"workspaceTree.create": "Create Deal",
|
||||
"workspaceTree.trash": "Move Deal to trash",
|
||||
"pluginCard.name": "Name",
|
||||
"folder.create": "Create Folder",
|
||||
"folder.edit": "Edit Folder",
|
||||
"folder.delete": "Delete Folder",
|
||||
"folder.deleteConfirm": "Delete folder? Deals inside will move to the parent folder.",
|
||||
"folder.namePlaceholder": "Folder name",
|
||||
"folder.nameRequired": "Name is required",
|
||||
"folder.icon": "Icon",
|
||||
"folder.chooseIcon": "Choose...",
|
||||
"folder.color": "Color",
|
||||
"folder.chooseColor": "Choose...",
|
||||
"folder.iconPickerTitle": "Choose Icon",
|
||||
"folder.iconSearch": "Search icons...",
|
||||
"folder.colorPickerTitle": "Choose Color"
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"manifest.name": "Папки дел",
|
||||
"manifest.description": "Вложенные папки с иконками, цветами и drag-and-drop для дерева Дел.",
|
||||
"common.close": "Закрыть",
|
||||
"common.cancel": "Отмена",
|
||||
"common.save": "Сохранить",
|
||||
"common.create": "Создать",
|
||||
"common.select": "Выбрать",
|
||||
"workspaceTree.title": "Дела",
|
||||
"workspaceTree.new": "Новое дело",
|
||||
"workspaceTree.nameRequired": "Имя обязательно",
|
||||
"workspaceTree.namePlaceholder": "Название дела",
|
||||
"workspaceTree.template": "Шаблон",
|
||||
"workspaceTree.create": "Создать дело",
|
||||
"workspaceTree.trash": "Переместить дело в корзину",
|
||||
"pluginCard.name": "Имя",
|
||||
"folder.create": "Создать папку",
|
||||
"folder.edit": "Редактировать папку",
|
||||
"folder.delete": "Удалить папку",
|
||||
"folder.deleteConfirm": "Удалить папку? Дела внутри переместятся в родительскую папку.",
|
||||
"folder.namePlaceholder": "Название папки",
|
||||
"folder.nameRequired": "Имя обязательно",
|
||||
"folder.icon": "Иконка",
|
||||
"folder.chooseIcon": "Выбрать...",
|
||||
"folder.color": "Цвет",
|
||||
"folder.chooseColor": "Выбрать...",
|
||||
"folder.iconPickerTitle": "Выбрать иконку",
|
||||
"folder.iconSearch": "Поиск иконок...",
|
||||
"folder.colorPickerTitle": "Выбрать цвет"
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "verstak.workspace-folders",
|
||||
"name": "Workspace Folders",
|
||||
"version": "0.1.0",
|
||||
"apiVersion": "0.1.0",
|
||||
"description": "Nested folders with icons, colors and drag-and-drop for the Deal tree.",
|
||||
"source": "official",
|
||||
"icon": "folder",
|
||||
"localization": {
|
||||
"defaultLocale": "en",
|
||||
"locales": {
|
||||
"en": "locales/en.json",
|
||||
"ru": "locales/ru.json"
|
||||
}
|
||||
},
|
||||
"provides": ["workspace.folders"],
|
||||
"requires": [
|
||||
"verstak/core/files/v1",
|
||||
"verstak/core/workspace/v1"
|
||||
],
|
||||
"optionalRequires": [],
|
||||
"permissions": [
|
||||
"files.read",
|
||||
"files.write",
|
||||
"ui.register",
|
||||
"events.publish",
|
||||
"events.subscribe",
|
||||
"storage.namespace"
|
||||
],
|
||||
"frontend": {
|
||||
"entry": "frontend/src/index.js",
|
||||
"style": "frontend/src/style.css"
|
||||
},
|
||||
"contributes": {
|
||||
"workspaceTree": {
|
||||
"component": "FolderTreeView"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
## Highlights
|
||||
|
||||
- First public bundle of Verstak's official plugins.
|
||||
- Includes Files, Notes, Journal, Todo, Secrets, Browser Inbox, Activity, Search, Trash, Sync, and supporting editors and previews.
|
||||
- Adds durable browser captures, archive handling, activity sessions, and localized plugin interfaces.
|
||||
|
||||
**Commit history**: https://github.com/mirivlad/verstak-official-plugins/commits/v0.1.0-alpha.1
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
## Highlights
|
||||
|
||||
- Todo tasks can schedule native reminders through the Desktop notification capability.
|
||||
|
||||
**Full Changelog**: https://github.com/mirivlad/verstak-official-plugins/compare/v0.1.0-alpha.1...v0.1.0-alpha.2
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
## Highlights
|
||||
|
||||
- Makes Todo reminder time selection, global Secrets, and global Journal entry creation usable.
|
||||
- Localizes plugin errors, browser materials, activity review, files menus, and other key workflows.
|
||||
- Replaces technical terminology with “Deal” and improves modal forms and secret safety.
|
||||
|
||||
**Full Changelog**: https://github.com/mirivlad/verstak-official-plugins/compare/v0.1.0-alpha.2...v0.1.0-alpha.3
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
## Highlights
|
||||
|
||||
- Folder rows in the Files plugin now use localized labels instead of the internal `folder` type.
|
||||
- File icons have localized, accessible names in both supported languages.
|
||||
|
||||
Install the archive matching your platform into Verstak's plugins directory, replacing the previous official plugins bundle.
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
## Highlights
|
||||
|
||||
- **Workspace Folders plugin.** A new official plugin `verstak.workspace-folders`
|
||||
replaces the sidebar Deal tree with a rich folder tree: icons (1703 Lucide
|
||||
icons), 12 preset colors, drag‑and‑drop between folders, inline folder
|
||||
creation and editing, and a Deal creation modal with parent folder selector.
|
||||
|
||||
## Install
|
||||
|
||||
Unpack the archive for your platform into Verstak's `plugins/` directory,
|
||||
replacing the previous official plugins bundle.
|
||||
|
|
@ -6,7 +6,6 @@ VERSION="${1:-}"
|
|||
REPOSITORY="mirivlad/verstak-official-plugins"
|
||||
RELEASE_SCRIPT="${VERSTAK_RELEASE_SCRIPT:-$ROOT/scripts/release.sh}"
|
||||
RELEASE_DIR="${VERSTAK_RELEASE_DIR:-$ROOT/release}"
|
||||
RELEASE_NOTES_DIR="${VERSTAK_RELEASE_NOTES_DIR:-$ROOT/release-notes}"
|
||||
GIT_BIN="${GIT_BIN:-git}"
|
||||
GH_BIN="${GH_BIN:-gh}"
|
||||
|
||||
|
|
@ -65,17 +64,7 @@ fi
|
|||
if "$GH_BIN" release view "$VERSION" --repo "$REPOSITORY" >/dev/null 2>&1; then
|
||||
"$GH_BIN" release upload "$VERSION" "${ASSETS[@]}" --repo "$REPOSITORY" --clobber
|
||||
else
|
||||
NOTES_FILE="$RELEASE_NOTES_DIR/$VERSION.md"
|
||||
if [[ ! -s "$NOTES_FILE" ]]; then
|
||||
echo "human-readable release notes are required: $NOTES_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RELEASE_OPTIONS=(--notes-file "$NOTES_FILE" --generate-notes --verify-tag)
|
||||
PREVIOUS_TAG="$("$GIT_BIN" describe --tags --abbrev=0 "${HEAD}^" 2>/dev/null || true)"
|
||||
if [[ -n "$PREVIOUS_TAG" ]]; then
|
||||
RELEASE_OPTIONS+=(--notes-start-tag "$PREVIOUS_TAG")
|
||||
fi
|
||||
RELEASE_OPTIONS=(--generate-notes --verify-tag)
|
||||
if [[ "$VERSION" == *-* ]]; then
|
||||
RELEASE_OPTIONS+=(--prerelease)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -27,14 +27,5 @@ if (!source.includes('conflictDetails')) {
|
|||
if (!source.includes('Sync conflicts')) {
|
||||
throw new Error('SyncSettings must label the conflict details section');
|
||||
}
|
||||
if (!source.includes('syncAPI().configure(serverUrl, username, password, vaultId)')) {
|
||||
throw new Error('SyncSettings must pass the optional remote vault ID during pairing');
|
||||
}
|
||||
if (!source.includes('settings.lastWarning')) {
|
||||
throw new Error('SyncSettings must render unresolved scanner warnings');
|
||||
}
|
||||
if (!source.includes("tr('ui.remoteVaultHint'")) {
|
||||
throw new Error('SyncSettings must explain remote vault restoration');
|
||||
}
|
||||
|
||||
console.log('sync plugin smoke passed');
|
||||
|
|
|
|||
|
|
@ -17,10 +17,9 @@ if [[ ! -x "$PUBLISHER" ]]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$WORK/bin" "$WORK/release" "$WORK/release-notes" "$WORK/state"
|
||||
mkdir -p "$WORK/bin" "$WORK/release" "$WORK/state"
|
||||
LOG="$WORK/log"
|
||||
export LOG
|
||||
printf '## Highlights\n\nHuman-readable release notes.\n' > "$WORK/release-notes/$VERSION.md"
|
||||
|
||||
cat > "$WORK/release.sh" <<'SCRIPT'
|
||||
#!/usr/bin/env bash
|
||||
|
|
@ -50,7 +49,6 @@ case "${1:-}" in
|
|||
fi
|
||||
echo test-commit
|
||||
;;
|
||||
describe) echo v0.0.0-previous ;;
|
||||
tag) touch "$TEST_STATE/tag"; printf 'tag:%s\n' "${3:-}" >> "$LOG" ;;
|
||||
push) printf 'push:%s:%s\n' "${2:-}" "${3:-}" >> "$LOG" ;;
|
||||
*) echo "unexpected git invocation: $*" >&2; exit 1 ;;
|
||||
|
|
@ -76,7 +74,6 @@ chmod +x "$WORK/bin/gh"
|
|||
run_publisher() {
|
||||
VERSTAK_RELEASE_SCRIPT="$WORK/release.sh" \
|
||||
VERSTAK_RELEASE_DIR="$WORK/release" \
|
||||
VERSTAK_RELEASE_NOTES_DIR="$WORK/release-notes" \
|
||||
GIT_BIN="$WORK/bin/git" \
|
||||
GH_BIN="$WORK/bin/gh" \
|
||||
EXPECTED_ROOT="$ROOT" \
|
||||
|
|
@ -93,9 +90,6 @@ for asset in "${ASSET_NAMES[@]}"; do
|
|||
grep -F "$asset" "$LOG" >/dev/null
|
||||
done
|
||||
grep -F "SHA256SUMS" "$LOG" >/dev/null
|
||||
grep -F -- "--notes-file $WORK/release-notes/$VERSION.md" "$LOG" >/dev/null
|
||||
grep -F -- "--generate-notes" "$LOG" >/dev/null
|
||||
grep -F -- "--notes-start-tag v0.0.0-previous" "$LOG" >/dev/null
|
||||
grep -F -- "--prerelease" "$LOG" >/dev/null
|
||||
|
||||
run_publisher
|
||||
|
|
|
|||
Loading…
Reference in New Issue