@notehub.md/cli 0.1.8 → 0.1.10
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/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +1 -3
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +13 -1
- package/dist/commands/create.js.map +1 -1
- package/package.json +2 -2
- package/templates/docs/en/01-getting-started.md +207 -0
- package/templates/docs/en/02-architecture.md +228 -0
- package/templates/docs/en/03-api-reference.md +747 -0
- package/templates/docs/en/04-widgets.md +322 -0
- package/templates/docs/en/05-settings.md +303 -0
- package/templates/docs/en/06-context-menu.md +283 -0
- package/templates/docs/en/07-examples.md +547 -0
- package/templates/docs/en/README.md +125 -0
- package/templates/docs/ru/01-getting-started.md +207 -0
- package/templates/docs/ru/02-architecture.md +228 -0
- package/templates/docs/ru/03-api-reference.md +747 -0
- package/templates/docs/ru/04-widgets.md +293 -0
- package/templates/docs/ru/05-settings.md +303 -0
- package/templates/docs/ru/06-context-menu.md +283 -0
- package/templates/docs/ru/07-examples.md +547 -0
- package/templates/docs/ru/README.md +125 -0
- package/templates/docs.html +6 -4
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Начало работы
|
|
2
|
+
|
|
3
|
+
Это руководство проведет вас через создание вашего первого плагина Notehub.md.
|
|
4
|
+
|
|
5
|
+
## Предварительные требования
|
|
6
|
+
|
|
7
|
+
- **Node.js** v18+ с npm/pnpm
|
|
8
|
+
- **TypeScript** (рекомендуется, но JavaScript тоже работает)
|
|
9
|
+
- **Сборщик**: esbuild, Vite или Rollup
|
|
10
|
+
- Хранилище Notehub.md для тестирования
|
|
11
|
+
|
|
12
|
+
## Структура плагина
|
|
13
|
+
|
|
14
|
+
Каждый плагин требует как минимум:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
my-plugin/
|
|
18
|
+
├── manifest.json # Метаданные плагина (обязательно)
|
|
19
|
+
├── main.js # Точка входа (скомпилированная)
|
|
20
|
+
└── src/ # Исходные файлы (опционально)
|
|
21
|
+
└── index.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## manifest.json
|
|
25
|
+
|
|
26
|
+
Манифест описывает ваш плагин для Notehub:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"id": "my-awesome-plugin",
|
|
31
|
+
"name": "Мой Крутой Плагин",
|
|
32
|
+
"version": "1.0.0",
|
|
33
|
+
"main": "main.js",
|
|
34
|
+
"dependencies": []
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| Поле | Обязательно | Описание |
|
|
39
|
+
|------|-------------|----------|
|
|
40
|
+
| `id` | ✅ | Уникальный идентификатор (строчные буквы, дефисы разрешены) |
|
|
41
|
+
| `name` | ✅ | Человекочитаемое имя |
|
|
42
|
+
| `version` | ✅ | Семантическая версия (например, `1.0.0`) |
|
|
43
|
+
| `main` | ❌ | Файл точки входа, по умолчанию `main.js` |
|
|
44
|
+
| `dependencies` | ❌ | Массив ID внутренних плагинов, от которых зависит этот плагин |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Вариант 1: Генератор плагинов (Внутренние плагины)
|
|
49
|
+
|
|
50
|
+
Если вы разрабатываете плагин **внутри монорепо Notehub**, используйте генератор:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm gen:plugin
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Интерактивный CLI:
|
|
57
|
+
1. ✔ Запросит имя плагина (kebab-case)
|
|
58
|
+
2. ✔ Предложит выбрать категорию (`system`, `ui`, `features`)
|
|
59
|
+
3. ✔ Сгенерирует полную структуру со всем boilerplate
|
|
60
|
+
|
|
61
|
+
**Генерируемые файлы:**
|
|
62
|
+
- `package.json` — Конфиг пакета с зависимостью `@notehub/core`
|
|
63
|
+
- `tsconfig.json` — TypeScript конфиг, расширяющий базовый
|
|
64
|
+
- `manifest.json` — Метаданные плагина
|
|
65
|
+
- `src/index.ts` — Класс плагина, реализующий `IPlugin`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Вариант 2: Ручная настройка (Внешние плагины)
|
|
70
|
+
|
|
71
|
+
Для плагинов, которые живут **вне монорепо** и загружаются в runtime из хранилища:
|
|
72
|
+
|
|
73
|
+
### Шаг 1: Создайте структуру папок
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
mkdir my-plugin
|
|
77
|
+
cd my-plugin
|
|
78
|
+
npm init -y
|
|
79
|
+
npm install @notehub/api typescript esbuild --save-dev
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Шаг 2: Создайте manifest.json
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"id": "hello-world",
|
|
87
|
+
"name": "Hello World",
|
|
88
|
+
"version": "1.0.0"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Шаг 3: Создайте src/index.ts
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { NotehubPlugin, PluginContext } from '@notehub/api';
|
|
96
|
+
|
|
97
|
+
export default class HelloWorldPlugin extends NotehubPlugin {
|
|
98
|
+
async onload(ctx: PluginContext): Promise<void> {
|
|
99
|
+
// Логируем сообщение при загрузке плагина
|
|
100
|
+
await ctx.invokeApi('logger:info', 'HelloWorld', 'Привет из моего плагина!');
|
|
101
|
+
|
|
102
|
+
// Регистрируем кастомный API
|
|
103
|
+
ctx.registerApi('hello:say', (message: string) => {
|
|
104
|
+
console.log(`[HelloWorld] ${message}`);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Подписываемся на события выбора файла
|
|
108
|
+
ctx.subscribe<{ path: string }>('explorer:file-selected', (payload) => {
|
|
109
|
+
console.log('Выбран файл:', payload.path);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async onunload(): Promise<void> {
|
|
114
|
+
// Ничего делать не нужно - очистка автоматическая!
|
|
115
|
+
console.log('Плагин HelloWorld выгружен');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Шаг 4: Создайте tsconfig.json
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"compilerOptions": {
|
|
125
|
+
"target": "ES2020",
|
|
126
|
+
"module": "ESNext",
|
|
127
|
+
"moduleResolution": "bundler",
|
|
128
|
+
"lib": ["ES2020", "DOM"],
|
|
129
|
+
"strict": true,
|
|
130
|
+
"esModuleInterop": true,
|
|
131
|
+
"skipLibCheck": true,
|
|
132
|
+
"declaration": false,
|
|
133
|
+
"outDir": "./dist"
|
|
134
|
+
},
|
|
135
|
+
"include": ["src/**/*"]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Шаг 5: Создайте скрипт сборки
|
|
140
|
+
|
|
141
|
+
Добавьте в `package.json`:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"scripts": {
|
|
146
|
+
"build": "esbuild src/index.ts --bundle --format=esm --outfile=main.js --external:@notehub/api --external:react"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Шаг 6: Соберите и установите
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm run build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Скопируйте папку в ваше хранилище:
|
|
158
|
+
```
|
|
159
|
+
MyVault/.notehub/plugins/hello-world/
|
|
160
|
+
├── manifest.json
|
|
161
|
+
└── main.js
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Шаг 7: Тестирование
|
|
165
|
+
|
|
166
|
+
1. Откройте Notehub.md с вашим хранилищем
|
|
167
|
+
2. Ваш плагин загрузится автоматически!
|
|
168
|
+
3. Проверьте консоль на сообщение "Привет из моего плагина!"
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Важно: Внешние зависимости
|
|
173
|
+
|
|
174
|
+
Ваш плагин работает в **общей области видимости** с Notehub. Эти пакеты предоставляются хостом:
|
|
175
|
+
|
|
176
|
+
| Пакет | Описание |
|
|
177
|
+
|-------|----------|
|
|
178
|
+
| `@notehub/api` | API плагинов (`NotehubPlugin`, `PluginContext`) |
|
|
179
|
+
| `react` | Библиотека React |
|
|
180
|
+
| `react-dom` | React DOM рендерер |
|
|
181
|
+
|
|
182
|
+
**Отметьте их как external** в конфигурации сборщика, чтобы избежать дублирования!
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Горячая перезагрузка
|
|
187
|
+
|
|
188
|
+
Notehub следит за директорией `.notehub/plugins/`. Когда вы обновляете плагин:
|
|
189
|
+
|
|
190
|
+
1. Старая версия автоматически выгружается
|
|
191
|
+
2. Новая версия загружается
|
|
192
|
+
3. Все ваши регистрации API очищаются автоматически!
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Советы по отладке
|
|
197
|
+
|
|
198
|
+
1. **Откройте DevTools** (Ctrl+Shift+I) чтобы видеть логи консоли
|
|
199
|
+
2. **Используйте `logger:info`** API для структурированного логирования
|
|
200
|
+
3. **Проверьте логи плагина Synapse** для событий загрузки/выгрузки
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Следующие шаги
|
|
205
|
+
|
|
206
|
+
- Прочитайте **[Архитектура](02-architecture.md)** чтобы понять жизненный цикл плагина
|
|
207
|
+
- Изучите **[Справочник API](03-api-reference.md)** для всех доступных методов
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Архитектура плагинов
|
|
2
|
+
|
|
3
|
+
Этот документ объясняет, как работают плагины Notehub.md под капотом.
|
|
4
|
+
|
|
5
|
+
## Микроядерная архитектура
|
|
6
|
+
|
|
7
|
+
Notehub.md следует **микроядерному** дизайну, где ядро минимально, а вся функциональность приходит от плагинов:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ NotehubCore │
|
|
12
|
+
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
|
|
13
|
+
│ │ EventBus │ │ ApiBus │ │ Plugin Registry │ │
|
|
14
|
+
│ │ (pub/sub) │ │ (RPC вызовы)│ │ (управление ЖЦ) │ │
|
|
15
|
+
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
|
|
16
|
+
└─────────────────────────────────────────────────────────────┘
|
|
17
|
+
▲ ▲ ▲
|
|
18
|
+
│ │ │
|
|
19
|
+
┌────┴───┐ ┌─────┴────┐ ┌─────┴────┐
|
|
20
|
+
│ Logger │ │ Editor │ │ Explorer │
|
|
21
|
+
│ Plugin │ │ Plugin │ │ Plugin │
|
|
22
|
+
└────────┘ └──────────┘ └──────────┘
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Типы плагинов
|
|
26
|
+
|
|
27
|
+
### Внутренние плагины (IPlugin)
|
|
28
|
+
|
|
29
|
+
Основные функции реализуют интерфейс `IPlugin` напрямую:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
interface IPlugin {
|
|
33
|
+
readonly manifest: PluginManifest;
|
|
34
|
+
load(app: NotehubCore): Promise<void> | void;
|
|
35
|
+
onReady?(app: NotehubCore): Promise<void> | void;
|
|
36
|
+
unload(app: NotehubCore): Promise<void> | void;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Внешние плагины (NotehubPlugin)
|
|
41
|
+
|
|
42
|
+
Ваши плагины наследуют `NotehubPlugin` и используют `PluginContext`:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
abstract class NotehubPlugin {
|
|
46
|
+
abstract onload(ctx: PluginContext): Promise<void> | void;
|
|
47
|
+
abstract onunload(): Promise<void> | void;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Ключевое отличие: **внешние плагины получают автоматическую очистку** через `PluginContext`!
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Жизненный цикл плагина
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
┌──────────────────────────────────────────────────────────┐
|
|
59
|
+
│ Жизненный цикл плагина │
|
|
60
|
+
├──────────────────────────────────────────────────────────┤
|
|
61
|
+
│ │
|
|
62
|
+
│ 1. ОБНАРУЖЕНИЕ │
|
|
63
|
+
│ └─ Synapse сканирует папку .notehub/plugins/ │
|
|
64
|
+
│ └─ Читает manifest.json для каждого плагина │
|
|
65
|
+
│ │
|
|
66
|
+
│ 2. ЗАГРУЗКА │
|
|
67
|
+
│ └─ SystemJS импортирует модуль main.js │
|
|
68
|
+
│ └─ Создается экземпляр класса плагина │
|
|
69
|
+
│ └─ Создается PluginContext (для внешних плагинов) │
|
|
70
|
+
│ │
|
|
71
|
+
│ 3. ИНИЦИАЛИЗАЦИЯ (onload) │
|
|
72
|
+
│ └─ Плагин регистрирует API │
|
|
73
|
+
│ └─ Плагин подписывается на события │
|
|
74
|
+
│ └─ Плагин настраивает UI-компоненты │
|
|
75
|
+
│ │
|
|
76
|
+
│ 4. РАБОТА │
|
|
77
|
+
│ └─ Плагин реагирует на события │
|
|
78
|
+
│ └─ Плагин обрабатывает API-вызовы │
|
|
79
|
+
│ │
|
|
80
|
+
│ 5. ВЫГРУЗКА (onunload) │
|
|
81
|
+
│ └─ Плагин выполняет ручную очистку (опционально) │
|
|
82
|
+
│ └─ PluginContext автоматически очищает регистрации │
|
|
83
|
+
│ └─ Модуль SystemJS выгружается │
|
|
84
|
+
│ │
|
|
85
|
+
└──────────────────────────────────────────────────────────┘
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## PluginContext
|
|
91
|
+
|
|
92
|
+
`PluginContext` — это ваш шлюз в экосистему Notehub:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface PluginContext {
|
|
96
|
+
// Регистрация API, который могут вызывать другие плагины
|
|
97
|
+
registerApi(name: string, handler: (...args: unknown[]) => unknown): void;
|
|
98
|
+
|
|
99
|
+
// Вызов API, зарегистрированного любым плагином
|
|
100
|
+
invokeApi<T>(name: string, ...args: unknown[]): Promise<T>;
|
|
101
|
+
|
|
102
|
+
// Подписка на события приложения
|
|
103
|
+
subscribe<T>(event: string, handler: (payload: T) => void): void;
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Магия автоматической очистки
|
|
108
|
+
|
|
109
|
+
Когда ваш плагин выгружается, `PluginContext` автоматически:
|
|
110
|
+
|
|
111
|
+
- ✅ Отменяет регистрацию всех ваших API
|
|
112
|
+
- ✅ Отписывается от всех событий
|
|
113
|
+
- ✅ Удаляет виджеты редактора, которые вы зарегистрировали
|
|
114
|
+
- ✅ Удаляет вкладки/группы/элементы настроек, которые вы добавили
|
|
115
|
+
|
|
116
|
+
**Вам не нужно вручную это очищать!**
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Паттерны коммуникации
|
|
121
|
+
|
|
122
|
+
### 1. EventBus (Pub/Sub)
|
|
123
|
+
|
|
124
|
+
Для **broadcast** информации множеству слушателей:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Подписка на событие
|
|
128
|
+
ctx.subscribe<{ path: string }>('explorer:file-selected', (payload) => {
|
|
129
|
+
console.log('Выбран файл:', payload.path);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// События испускаются плагинами внутренне
|
|
133
|
+
// Внешние плагины могут только подписываться, не испускать
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Частые события:
|
|
137
|
+
- `explorer:file-selected` — пользователь кликнул на файл
|
|
138
|
+
- `editor:file-opened` — контент файла загружен
|
|
139
|
+
- `editor:file-closed` — редактор очищен
|
|
140
|
+
- `vault:opened` — хранилище было открыто
|
|
141
|
+
- `vault:closed` — хранилище было закрыто
|
|
142
|
+
|
|
143
|
+
### 2. ApiBus (RPC)
|
|
144
|
+
|
|
145
|
+
Для **прямых вызовов методов** между плагинами:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Регистрация API
|
|
149
|
+
ctx.registerApi('my-plugin:calculate', (a: number, b: number) => a + b);
|
|
150
|
+
|
|
151
|
+
// Вызов чужого API
|
|
152
|
+
const result = await ctx.invokeApi<number>('my-plugin:calculate', 5, 3);
|
|
153
|
+
// result = 8
|
|
154
|
+
|
|
155
|
+
// Все системные API доступны через invokeApi
|
|
156
|
+
const content = await ctx.invokeApi<string>('fs:read-text-file', '/path/to/file.md');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Разрешение зависимостей
|
|
162
|
+
|
|
163
|
+
Плагины могут объявлять зависимости в `manifest.json`:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"id": "my-plugin",
|
|
168
|
+
"dependencies": ["nh.features.editor"]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Загрузчик гарантирует, что зависимости загрузятся до вашего плагина.
|
|
173
|
+
|
|
174
|
+
**Примечание:** Для внешних плагинов системные плагины всегда доступны. Обычно вам не нужно объявлять зависимости, если только вы не зависите от другого внешнего плагина.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Горячая перезагрузка
|
|
179
|
+
|
|
180
|
+
Notehub следит за папкой плагинов. При изменении файла:
|
|
181
|
+
|
|
182
|
+
1. **Обнаружение** — файловый наблюдатель срабатывает на изменение `.js` или `manifest.json`
|
|
183
|
+
2. **Выгрузка** — старая версия плагина выгружается (вызывается `onunload()`)
|
|
184
|
+
3. **Очистка** — PluginContext удаляет все регистрации
|
|
185
|
+
4. **Перезагрузка** — новая версия загружается (вызывается `onload()`)
|
|
186
|
+
|
|
187
|
+
Это позволяет **быстро разрабатывать** без перезапуска Notehub!
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Лучшие практики
|
|
192
|
+
|
|
193
|
+
### 1. Используйте пространства имен для API
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// ✅ Хорошо — с пространством имен
|
|
197
|
+
ctx.registerApi('my-plugin:do-something', handler);
|
|
198
|
+
|
|
199
|
+
// ❌ Плохо — может конфликтовать
|
|
200
|
+
ctx.registerApi('do-something', handler);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 2. Обрабатывайте ошибки корректно
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
async onload(ctx: PluginContext): Promise<void> {
|
|
207
|
+
try {
|
|
208
|
+
const data = await ctx.invokeApi('fs:read-text-file', '/config.json');
|
|
209
|
+
// ...
|
|
210
|
+
} catch (error) {
|
|
211
|
+
await ctx.invokeApi('logger:error', 'MyPlugin', `Ошибка загрузки: ${error}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 3. Используйте TypeScript для лучшего IntelliSense
|
|
217
|
+
|
|
218
|
+
Пакет `@notehub/api` включает полные определения типов для всех API.
|
|
219
|
+
|
|
220
|
+
### 4. Держите onload() быстрым
|
|
221
|
+
|
|
222
|
+
Не блокируйте инициализацию тяжелой работой. Используйте асинхронные паттерны или отложите работу.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Следующие шаги
|
|
227
|
+
|
|
228
|
+
Смотрите полный **[Справочник API](03-api-reference.md)** для всех доступных методов.
|