@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.
@@ -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)** для всех доступных методов.