@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,747 @@
1
+ # API Reference
2
+
3
+ Complete reference for all Notehub.md API methods available to plugins.
4
+
5
+ Use `ctx.invokeApi(methodName, ...args)` to call any of these methods.
6
+
7
+ ---
8
+
9
+ ## Logger API
10
+
11
+ Structured logging for debugging and monitoring.
12
+
13
+ ### `logger:log`
14
+
15
+ Log a message with a specified level.
16
+
17
+ ```typescript
18
+ await ctx.invokeApi('logger:log', level: string, source: string, message: string): void;
19
+ ```
20
+
21
+ | Param | Type | Description |
22
+ |-------|------|-------------|
23
+ | `level` | `string` | Log level: 'info', 'warn', 'error' |
24
+ | `source` | `string` | Source identifier (usually plugin name) |
25
+ | `message` | `string` | Message to log |
26
+
27
+ ### `logger:info`
28
+
29
+ Log an INFO level message.
30
+
31
+ ```typescript
32
+ await ctx.invokeApi('logger:info', 'MyPlugin', 'Operation completed');
33
+ ```
34
+
35
+ ### `logger:warn`
36
+
37
+ Log a WARN level message.
38
+
39
+ ```typescript
40
+ await ctx.invokeApi('logger:warn', 'MyPlugin', 'Config file not found, using defaults');
41
+ ```
42
+
43
+ ### `logger:error`
44
+
45
+ Log an ERROR level message.
46
+
47
+ ```typescript
48
+ await ctx.invokeApi('logger:error', 'MyPlugin', 'Failed to load data');
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Config API
54
+
55
+ Persistent configuration stored on disk.
56
+
57
+ ### `config:get`
58
+
59
+ Get a configuration value by key.
60
+
61
+ ```typescript
62
+ const value = await ctx.invokeApi<T>('config:get', key: string, defaultValue?: T): T | undefined;
63
+ ```
64
+
65
+ **Example:**
66
+ ```typescript
67
+ const fontSize = await ctx.invokeApi<number>('config:get', 'editor.font-size', 14);
68
+ const theme = await ctx.invokeApi<string>('config:get', 'theme.current', 'dark');
69
+ ```
70
+
71
+ ### `config:set`
72
+
73
+ Set a configuration value (automatically persisted to disk).
74
+
75
+ ```typescript
76
+ await ctx.invokeApi('config:set', 'my-plugin.option', true);
77
+ ```
78
+
79
+ ### `config:delete`
80
+
81
+ Delete a configuration value.
82
+
83
+ ```typescript
84
+ await ctx.invokeApi('config:delete', 'my-plugin.option');
85
+ ```
86
+
87
+ ### `config:reload`
88
+
89
+ Reload configuration from disk.
90
+
91
+ ```typescript
92
+ await ctx.invokeApi('config:reload');
93
+ ```
94
+
95
+ ---
96
+
97
+ ## State API
98
+
99
+ Runtime state (not persisted - lost on restart).
100
+
101
+ ### `state:set`
102
+
103
+ Store a value in runtime state.
104
+
105
+ ```typescript
106
+ await ctx.invokeApi('state:set', 'my-plugin.cache', { data: [...] });
107
+ ```
108
+
109
+ ### `state:get`
110
+
111
+ Retrieve a value from runtime state.
112
+
113
+ ```typescript
114
+ const cache = await ctx.invokeApi<MyData>('state:get', 'my-plugin.cache');
115
+ ```
116
+
117
+ ### `state:delete`
118
+
119
+ Delete a value from state.
120
+
121
+ ```typescript
122
+ await ctx.invokeApi('state:delete', 'my-plugin.cache');
123
+ // Returns: boolean (true if deleted)
124
+ ```
125
+
126
+ ### `state:has`
127
+
128
+ Check if a key exists.
129
+
130
+ ```typescript
131
+ const exists = await ctx.invokeApi<boolean>('state:has', 'my-plugin.cache');
132
+ ```
133
+
134
+ ### `state:keys`
135
+
136
+ Get all keys in state.
137
+
138
+ ```typescript
139
+ const keys = await ctx.invokeApi<string[]>('state:keys');
140
+ ```
141
+
142
+ ### `state:clear`
143
+
144
+ Clear all state.
145
+
146
+ ```typescript
147
+ await ctx.invokeApi('state:clear');
148
+ ```
149
+
150
+ ### `state:dump`
151
+
152
+ Export entire state as an object.
153
+
154
+ ```typescript
155
+ const snapshot = await ctx.invokeApi<Record<string, unknown>>('state:dump');
156
+ ```
157
+
158
+ ### `state:restore`
159
+
160
+ Restore state from a dump object.
161
+
162
+ ```typescript
163
+ await ctx.invokeApi('state:restore', snapshot);
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Filesystem API
169
+
170
+ Access files in the vault.
171
+
172
+ ### `fs:read-text-file`
173
+
174
+ Read a file as UTF-8 text.
175
+
176
+ ```typescript
177
+ const content = await ctx.invokeApi<string>('fs:read-text-file', '/path/to/file.md');
178
+ ```
179
+
180
+ ### `fs:read-file`
181
+
182
+ Read a file as binary data.
183
+
184
+ ```typescript
185
+ const data = await ctx.invokeApi<Uint8Array>('fs:read-file', '/path/to/image.png');
186
+ ```
187
+
188
+ ### `fs:write-text-file`
189
+
190
+ Write text to a file.
191
+
192
+ ```typescript
193
+ await ctx.invokeApi('fs:write-text-file', '/path/to/file.md', '# Hello World');
194
+ ```
195
+
196
+ ### `fs:write-file`
197
+
198
+ Write binary data to a file.
199
+
200
+ ```typescript
201
+ await ctx.invokeApi('fs:write-file', '/path/to/file.bin', new Uint8Array([...]));
202
+ ```
203
+
204
+ ### `fs:exists`
205
+
206
+ Check if a path exists.
207
+
208
+ ```typescript
209
+ const exists = await ctx.invokeApi<boolean>('fs:exists', '/path/to/file.md');
210
+ ```
211
+
212
+ ### `fs:read-dir`
213
+
214
+ Read directory contents.
215
+
216
+ ```typescript
217
+ interface DirEntry {
218
+ name: string;
219
+ isDirectory: boolean;
220
+ isFile: boolean;
221
+ }
222
+
223
+ const entries = await ctx.invokeApi<DirEntry[]>('fs:read-dir', '/path/to/folder');
224
+ ```
225
+
226
+ ### `fs:create-dir`
227
+
228
+ Create a directory.
229
+
230
+ ```typescript
231
+ await ctx.invokeApi('fs:create-dir', '/path/to/new-folder', { recursive: true });
232
+ ```
233
+
234
+ ### `fs:remove-file`
235
+
236
+ Delete a file.
237
+
238
+ ```typescript
239
+ await ctx.invokeApi('fs:remove-file', '/path/to/file.md');
240
+ ```
241
+
242
+ ### `fs:remove-dir`
243
+
244
+ Delete a directory.
245
+
246
+ ```typescript
247
+ await ctx.invokeApi('fs:remove-dir', '/path/to/folder', { recursive: true });
248
+ ```
249
+
250
+ ### `fs:rename`
251
+
252
+ Rename or move a file/directory.
253
+
254
+ ```typescript
255
+ await ctx.invokeApi('fs:rename', '/old/path.md', '/new/path.md');
256
+ ```
257
+
258
+ ### `fs:watch`
259
+
260
+ Watch a path for changes.
261
+
262
+ ```typescript
263
+ interface FsEvent {
264
+ path: string;
265
+ type: 'create' | 'modify' | 'remove' | 'any';
266
+ }
267
+
268
+ const unwatch = await ctx.invokeApi<() => void>(
269
+ 'fs:watch',
270
+ '/path/to/folder',
271
+ (event: FsEvent) => {
272
+ console.log('Change detected:', event);
273
+ }
274
+ );
275
+
276
+ // Later: stop watching
277
+ unwatch();
278
+ ```
279
+
280
+ ### `fs:pick-directory`
281
+
282
+ Open native directory picker dialog.
283
+
284
+ ```typescript
285
+ const path = await ctx.invokeApi<string | null>('fs:pick-directory');
286
+ if (path) {
287
+ console.log('User selected:', path);
288
+ }
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Dialog API
294
+
295
+ Show modal dialogs to the user.
296
+
297
+ ### `dialog:alert`
298
+
299
+ Show an alert message.
300
+
301
+ ```typescript
302
+ await ctx.invokeApi('dialog:alert', 'Warning', 'File has been deleted');
303
+ ```
304
+
305
+ ### `dialog:confirm`
306
+
307
+ Show a confirmation dialog.
308
+
309
+ ```typescript
310
+ const confirmed = await ctx.invokeApi<boolean>(
311
+ 'dialog:confirm',
312
+ 'Delete File',
313
+ 'Are you sure you want to delete this file?'
314
+ );
315
+
316
+ if (confirmed) {
317
+ // User clicked OK
318
+ }
319
+ ```
320
+
321
+ ### `dialog:prompt`
322
+
323
+ Show a prompt for user input.
324
+
325
+ ```typescript
326
+ const name = await ctx.invokeApi<string | null>(
327
+ 'dialog:prompt',
328
+ 'Rename File',
329
+ 'Enter new filename:',
330
+ 'untitled.md' // default value
331
+ );
332
+
333
+ if (name !== null) {
334
+ // User entered a value
335
+ }
336
+ ```
337
+
338
+ ---
339
+
340
+ ## Theme API
341
+
342
+ Manage themes and colors.
343
+
344
+ ### `theme:register`
345
+
346
+ Register a custom theme.
347
+
348
+ ```typescript
349
+ const myPalette = {
350
+ 'bg-main': '#1a1a2e',
351
+ 'bg-sidebar': '#16213e',
352
+ 'bg-surface': '#0f3460',
353
+ 'text-primary': '#e6e6e6',
354
+ 'accent-primary': '#e94560',
355
+ // ... more colors
356
+ 'font-family': 'Inter, sans-serif'
357
+ };
358
+
359
+ await ctx.invokeApi('theme:register', 'my-dark-theme', myPalette);
360
+ ```
361
+
362
+ ### `theme:set`
363
+
364
+ Apply a theme.
365
+
366
+ ```typescript
367
+ const success = await ctx.invokeApi<boolean>('theme:set', 'my-dark-theme');
368
+ ```
369
+
370
+ ### `theme:get-current`
371
+
372
+ Get current theme name.
373
+
374
+ ```typescript
375
+ const themeName = await ctx.invokeApi<string>('theme:get-current');
376
+ ```
377
+
378
+ ### `theme:list`
379
+
380
+ List all registered themes.
381
+
382
+ ```typescript
383
+ const themes = await ctx.invokeApi<string[]>('theme:list');
384
+ // ['deep-space', 'light', 'my-dark-theme']
385
+ ```
386
+
387
+ ### `theme:get`
388
+
389
+ Get a theme palette by name.
390
+
391
+ ```typescript
392
+ const palette = await ctx.invokeApi<ThemePalette | undefined>('theme:get', 'deep-space');
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Layout API
398
+
399
+ Manage application layouts and zones.
400
+
401
+ ### `layout:register-component`
402
+
403
+ Register a layout component.
404
+
405
+ ```typescript
406
+ const MyLayout: React.FC = () => <div>My Custom Layout</div>;
407
+ await ctx.invokeApi('layout:register-component', 'my-layout', MyLayout);
408
+ ```
409
+
410
+ ### `layout:set`
411
+
412
+ Set the active layout.
413
+
414
+ ```typescript
415
+ await ctx.invokeApi('layout:set', 'editor-layout', { showSidebar: true });
416
+ ```
417
+
418
+ ### `layout:get-active`
419
+
420
+ Get current layout info.
421
+
422
+ ```typescript
423
+ interface ActiveLayout {
424
+ name: string;
425
+ props: Record<string, unknown>;
426
+ }
427
+
428
+ const layout = await ctx.invokeApi<ActiveLayout | null>('layout:get-active');
429
+ ```
430
+
431
+ ### `layout:list`
432
+
433
+ List registered layouts.
434
+
435
+ ```typescript
436
+ const layouts = await ctx.invokeApi<string[]>('layout:list');
437
+ ```
438
+
439
+ ### `zone:register`
440
+
441
+ Register a component in a layout zone.
442
+
443
+ ```typescript
444
+ await ctx.invokeApi('zone:register', 'sidebar-top', {
445
+ component: 'my-sidebar-widget',
446
+ priority: 100 // Higher = rendered first
447
+ });
448
+ ```
449
+
450
+ ### `zone:get`
451
+
452
+ Get all items in a zone.
453
+
454
+ ```typescript
455
+ const items = await ctx.invokeApi<ZoneItem[]>('zone:get', 'sidebar-top');
456
+ ```
457
+
458
+ ### `zone:clear`
459
+
460
+ Clear all items in a zone.
461
+
462
+ ```typescript
463
+ await ctx.invokeApi('zone:clear', 'sidebar-top');
464
+ ```
465
+
466
+ ---
467
+
468
+ ## Controller API
469
+
470
+ Register React components as named controllers.
471
+
472
+ ### `controller:register`
473
+
474
+ Register a controller component.
475
+
476
+ ```typescript
477
+ const MyComponent: React.FC = () => <div>Hello!</div>;
478
+ await ctx.invokeApi('controller:register', 'my-component', MyComponent);
479
+ ```
480
+
481
+ ### `controller:unregister`
482
+
483
+ Unregister a controller.
484
+
485
+ ```typescript
486
+ await ctx.invokeApi('controller:unregister', 'my-component');
487
+ ```
488
+
489
+ ### `controller:get`
490
+
491
+ Get a controller by name.
492
+
493
+ ```typescript
494
+ const Component = await ctx.invokeApi<React.FC>('controller:get', 'my-component');
495
+ ```
496
+
497
+ ---
498
+
499
+ ## Icon API
500
+
501
+ Register and retrieve icons.
502
+
503
+ ### `icon:register`
504
+
505
+ Register a custom icon.
506
+
507
+ ```typescript
508
+ import { MyCustomIcon } from './icons';
509
+ await ctx.invokeApi('icon:register', 'my-icon', MyCustomIcon);
510
+ ```
511
+
512
+ ### `icon:get`
513
+
514
+ Get an icon component.
515
+
516
+ ```typescript
517
+ const IconComponent = await ctx.invokeApi<React.ElementType>('icon:get', 'my-icon');
518
+ ```
519
+
520
+ ---
521
+
522
+ ## Editor API
523
+
524
+ Register custom editor widgets (Portals).
525
+
526
+ ### `editor:register-widget`
527
+
528
+ Register an inline widget that renders for regex matches.
529
+
530
+ ```typescript
531
+ const ProgressBar: React.FC<{ match: RegExpExecArray }> = ({ match }) => {
532
+ const progress = parseInt(match[1], 10);
533
+ return <div style={{ width: `${progress}%` }} />;
534
+ };
535
+
536
+ await ctx.invokeApi(
537
+ 'editor:register-widget',
538
+ 'my-plugin:progress-bar',
539
+ /\[progress:(\d+)\]/g,
540
+ ProgressBar
541
+ );
542
+ ```
543
+
544
+ ### `editor:unregister-widget`
545
+
546
+ Unregister a widget (auto-cleaned on unload).
547
+
548
+ ```typescript
549
+ await ctx.invokeApi('editor:unregister-widget', 'my-plugin:progress-bar');
550
+ ```
551
+
552
+ See **[Widgets (Portals)](04-widgets.md)** for detailed widget documentation.
553
+
554
+ ---
555
+
556
+ ## Settings API
557
+
558
+ Add configuration UI to the Settings modal.
559
+
560
+ ### `settings:register-tab`
561
+
562
+ Register a settings tab.
563
+
564
+ ```typescript
565
+ await ctx.invokeApi('settings:register-tab', {
566
+ id: 'my-plugin-settings',
567
+ label: 'My Plugin',
568
+ icon: 'puzzle',
569
+ order: 100
570
+ });
571
+ ```
572
+
573
+ ### `settings:register-group`
574
+
575
+ Register a settings group within a tab.
576
+
577
+ ```typescript
578
+ await ctx.invokeApi('settings:register-group', {
579
+ id: 'my-plugin-general',
580
+ tabId: 'my-plugin-settings',
581
+ label: 'General Settings',
582
+ order: 0
583
+ });
584
+ ```
585
+
586
+ ### `settings:register-item`
587
+
588
+ Register a settings item within a group.
589
+
590
+ ```typescript
591
+ await ctx.invokeApi('settings:register-item', {
592
+ key: 'my-plugin.enabled',
593
+ type: 'toggle',
594
+ label: 'Enable plugin',
595
+ description: 'Turn the plugin on or off',
596
+ groupId: 'my-plugin-general',
597
+ order: 0,
598
+ defaultValue: true
599
+ });
600
+ ```
601
+
602
+ See **[Settings Integration](05-settings.md)** for detailed settings documentation.
603
+
604
+ ### `settings:open` / `settings:close` / `settings:toggle`
605
+
606
+ Control the settings modal.
607
+
608
+ ```typescript
609
+ await ctx.invokeApi('settings:open');
610
+ await ctx.invokeApi('settings:close');
611
+ await ctx.invokeApi('settings:toggle');
612
+ ```
613
+
614
+ ---
615
+
616
+ ## Context Menu API
617
+
618
+ Add items to right-click menus.
619
+
620
+ ### `context-menu:register`
621
+
622
+ Register a menu provider for a context.
623
+
624
+ ```typescript
625
+ const unsubscribe = await ctx.invokeApi<() => void>(
626
+ 'context-menu:register',
627
+ 'explorer-item', // Context ID
628
+ (payload: { path: string }) => [
629
+ {
630
+ type: 'action',
631
+ id: 'my-action',
632
+ label: 'My Custom Action',
633
+ icon: 'star',
634
+ onClick: () => {
635
+ console.log('Clicked on:', payload.path);
636
+ }
637
+ }
638
+ ]
639
+ );
640
+ ```
641
+
642
+ See **[Context Menu](06-context-menu.md)** for detailed documentation.
643
+
644
+ ---
645
+
646
+ ## Explorer API
647
+
648
+ Control the file explorer.
649
+
650
+ ### `explorer:open`
651
+
652
+ Open a folder in the explorer.
653
+
654
+ ```typescript
655
+ await ctx.invokeApi('explorer:open', '/path/to/folder');
656
+ ```
657
+
658
+ ### `explorer:set-root`
659
+
660
+ Set the root path for the explorer.
661
+
662
+ ```typescript
663
+ await ctx.invokeApi('explorer:set-root', '/new/vault/path');
664
+ ```
665
+
666
+ ---
667
+
668
+ ## Synapse API
669
+
670
+ Manage external plugins programmatically.
671
+
672
+ ### `synapse:load-plugin`
673
+
674
+ Load an external plugin from a path.
675
+
676
+ ```typescript
677
+ interface SynapseLoadResult {
678
+ success: boolean;
679
+ pluginId?: string;
680
+ error?: string;
681
+ }
682
+
683
+ const result = await ctx.invokeApi<SynapseLoadResult>(
684
+ 'synapse:load-plugin',
685
+ '/path/to/plugin-folder'
686
+ );
687
+ ```
688
+
689
+ ### `synapse:unload-plugin`
690
+
691
+ Unload an external plugin.
692
+
693
+ ```typescript
694
+ const success = await ctx.invokeApi<boolean>('synapse:unload-plugin', 'plugin-id');
695
+ ```
696
+
697
+ ### `synapse:list-plugins`
698
+
699
+ List loaded plugin IDs.
700
+
701
+ ```typescript
702
+ const pluginIds = await ctx.invokeApi<string[]>('synapse:list-plugins');
703
+ ```
704
+
705
+ ### `synapse:get-details`
706
+
707
+ Get detailed metadata for all plugins.
708
+
709
+ ```typescript
710
+ const details = await ctx.invokeApi<unknown[]>('synapse:get-details');
711
+ ```
712
+
713
+ ---
714
+
715
+ ## Shell API
716
+
717
+ Open external resources.
718
+
719
+ ### `shell:open`
720
+
721
+ Open a URL in the default browser.
722
+
723
+ ```typescript
724
+ await ctx.invokeApi('shell:open', 'https://notehub.md');
725
+ ```
726
+
727
+ ---
728
+
729
+ ## Vault API
730
+
731
+ Vault-level operations.
732
+
733
+ ### `vault:close`
734
+
735
+ Close the current vault and return to welcome screen.
736
+
737
+ ```typescript
738
+ await ctx.invokeApi('vault:close');
739
+ ```
740
+
741
+ ---
742
+
743
+ ## Next Steps
744
+
745
+ - Learn to create **[Widgets (Portals)](04-widgets.md)**
746
+ - Add **[Settings](05-settings.md)** to your plugin
747
+ - Integrate with **[Context Menus](06-context-menu.md)**