@gmickel/gno 0.28.2 → 0.29.1

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.
Files changed (52) hide show
  1. package/README.md +10 -2
  2. package/package.json +1 -1
  3. package/src/app/constants.ts +4 -2
  4. package/src/cli/commands/mcp/install.ts +4 -4
  5. package/src/cli/commands/mcp/status.ts +7 -7
  6. package/src/cli/commands/skill/install.ts +5 -5
  7. package/src/cli/program.ts +2 -2
  8. package/src/collection/add.ts +10 -0
  9. package/src/collection/types.ts +1 -0
  10. package/src/config/types.ts +12 -2
  11. package/src/core/depth-policy.ts +1 -1
  12. package/src/core/file-ops.ts +203 -1
  13. package/src/llm/registry.ts +20 -4
  14. package/src/serve/AGENTS.md +16 -16
  15. package/src/serve/CLAUDE.md +16 -16
  16. package/src/serve/config-sync.ts +32 -1
  17. package/src/serve/connectors.ts +243 -0
  18. package/src/serve/context.ts +9 -0
  19. package/src/serve/doc-events.ts +31 -1
  20. package/src/serve/embed-scheduler.ts +12 -0
  21. package/src/serve/import-preview.ts +173 -0
  22. package/src/serve/public/app.tsx +101 -7
  23. package/src/serve/public/components/AIModelSelector.tsx +383 -145
  24. package/src/serve/public/components/AddCollectionDialog.tsx +123 -7
  25. package/src/serve/public/components/BootstrapStatus.tsx +133 -0
  26. package/src/serve/public/components/CaptureModal.tsx +5 -2
  27. package/src/serve/public/components/CollectionsEmptyState.tsx +63 -0
  28. package/src/serve/public/components/FirstRunWizard.tsx +622 -0
  29. package/src/serve/public/components/HealthCenter.tsx +128 -0
  30. package/src/serve/public/components/IndexingProgress.tsx +21 -2
  31. package/src/serve/public/components/QuickSwitcher.tsx +62 -36
  32. package/src/serve/public/components/TagInput.tsx +5 -1
  33. package/src/serve/public/components/WikiLinkAutocomplete.tsx +15 -6
  34. package/src/serve/public/components/WorkspaceTabs.tsx +60 -0
  35. package/src/serve/public/hooks/use-doc-events.ts +48 -4
  36. package/src/serve/public/lib/local-history.ts +40 -7
  37. package/src/serve/public/lib/navigation-state.ts +156 -0
  38. package/src/serve/public/lib/workspace-tabs.ts +235 -0
  39. package/src/serve/public/pages/Ask.tsx +11 -1
  40. package/src/serve/public/pages/Browse.tsx +73 -0
  41. package/src/serve/public/pages/Collections.tsx +29 -13
  42. package/src/serve/public/pages/Connectors.tsx +178 -0
  43. package/src/serve/public/pages/Dashboard.tsx +493 -67
  44. package/src/serve/public/pages/DocView.tsx +192 -34
  45. package/src/serve/public/pages/DocumentEditor.tsx +127 -5
  46. package/src/serve/public/pages/Search.tsx +12 -1
  47. package/src/serve/routes/api.ts +541 -62
  48. package/src/serve/server.ts +79 -2
  49. package/src/serve/status-model.ts +149 -0
  50. package/src/serve/status.ts +706 -0
  51. package/src/serve/watch-service.ts +73 -8
  52. package/src/types/electrobun-shell.d.ts +43 -0
@@ -21,6 +21,7 @@ import {
21
21
  handleAsk,
22
22
  handleCapabilities,
23
23
  handleCollections,
24
+ handleConnectors,
24
25
  handleCreateCollection,
25
26
  handleCreateEditableCopy,
26
27
  handleCreateDoc,
@@ -32,16 +33,21 @@ import {
32
33
  handleEmbed,
33
34
  handleEmbedStatus,
34
35
  handleHealth,
36
+ handleImportPreview,
37
+ handleInstallConnector,
35
38
  handleJob,
36
39
  handleModelPull,
37
40
  handleModelStatus,
38
41
  handlePresets,
39
42
  handleQuery,
43
+ handleRenameDoc,
44
+ handleRevealDoc,
40
45
  handleSearch,
41
46
  handleSetPreset,
42
47
  handleStatus,
43
48
  handleSync,
44
49
  handleTags,
50
+ handleTrashDoc,
45
51
  handleUpdateDoc,
46
52
  } from "./routes/api";
47
53
  import { handleGraph } from "./routes/graph";
@@ -184,8 +190,10 @@ export async function startServer(
184
190
  getModelUri: () => getActivePreset(ctxHolder.config).embed,
185
191
  });
186
192
  ctxHolder.scheduler = scheduler;
193
+ ctxHolder.current.scheduler = scheduler;
187
194
  const eventBus = new DocumentEventBus();
188
195
  ctxHolder.eventBus = eventBus;
196
+ ctxHolder.current.eventBus = eventBus;
189
197
  const watchService = new CollectionWatchService({
190
198
  collections: config.collections,
191
199
  store,
@@ -194,6 +202,7 @@ export async function startServer(
194
202
  });
195
203
  watchService.start();
196
204
  ctxHolder.watchService = watchService;
205
+ ctxHolder.current.watchService = watchService;
197
206
 
198
207
  // Shutdown controller for clean lifecycle
199
208
  const shutdownController = new AbortController();
@@ -231,6 +240,7 @@ export async function startServer(
231
240
  "/doc": homepage,
232
241
  "/edit": homepage,
233
242
  "/collections": homepage,
243
+ "/connectors": homepage,
234
244
  "/ask": homepage,
235
245
  "/graph": homepage,
236
246
 
@@ -240,7 +250,7 @@ export async function startServer(
240
250
  },
241
251
  "/api/status": {
242
252
  GET: async () =>
243
- withSecurityHeaders(await handleStatus(store), isDev),
253
+ withSecurityHeaders(await handleStatus(ctxHolder.current), isDev),
244
254
  },
245
255
  "/api/collections": {
246
256
  GET: async () =>
@@ -255,6 +265,31 @@ export async function startServer(
255
265
  );
256
266
  },
257
267
  },
268
+ "/api/connectors": {
269
+ GET: async () => withSecurityHeaders(await handleConnectors(), isDev),
270
+ },
271
+ "/api/connectors/install": {
272
+ POST: async (req: Request) => {
273
+ if (!isRequestAllowed(req, port)) {
274
+ return withSecurityHeaders(forbiddenResponse(), isDev);
275
+ }
276
+ return withSecurityHeaders(
277
+ await handleInstallConnector(req),
278
+ isDev
279
+ );
280
+ },
281
+ },
282
+ "/api/import/preview": {
283
+ POST: async (req: Request) => {
284
+ if (!isRequestAllowed(req, port)) {
285
+ return withSecurityHeaders(forbiddenResponse(), isDev);
286
+ }
287
+ return withSecurityHeaders(
288
+ await handleImportPreview(ctxHolder, req),
289
+ isDev
290
+ );
291
+ },
292
+ },
258
293
  "/api/sync": {
259
294
  POST: async (req: Request) => {
260
295
  if (!isRequestAllowed(req, port)) {
@@ -300,7 +335,49 @@ export async function startServer(
300
335
  const parts = url.pathname.split("/");
301
336
  const id = decodeURIComponent(parts[3] || "");
302
337
  return withSecurityHeaders(
303
- await handleDeactivateDoc(store, id),
338
+ await handleDeactivateDoc(store, id, req),
339
+ isDev
340
+ );
341
+ },
342
+ },
343
+ "/api/docs/:id/rename": {
344
+ POST: async (req: Request) => {
345
+ if (!isRequestAllowed(req, port)) {
346
+ return withSecurityHeaders(forbiddenResponse(), isDev);
347
+ }
348
+ const url = new URL(req.url);
349
+ const parts = url.pathname.split("/");
350
+ const id = decodeURIComponent(parts[3] || "");
351
+ return withSecurityHeaders(
352
+ await handleRenameDoc(ctxHolder, store, id, req),
353
+ isDev
354
+ );
355
+ },
356
+ },
357
+ "/api/docs/:id/trash": {
358
+ POST: async (req: Request) => {
359
+ if (!isRequestAllowed(req, port)) {
360
+ return withSecurityHeaders(forbiddenResponse(), isDev);
361
+ }
362
+ const url = new URL(req.url);
363
+ const parts = url.pathname.split("/");
364
+ const id = decodeURIComponent(parts[3] || "");
365
+ return withSecurityHeaders(
366
+ await handleTrashDoc(ctxHolder, store, id, req),
367
+ isDev
368
+ );
369
+ },
370
+ },
371
+ "/api/docs/:id/reveal": {
372
+ POST: async (req: Request) => {
373
+ if (!isRequestAllowed(req, port)) {
374
+ return withSecurityHeaders(forbiddenResponse(), isDev);
375
+ }
376
+ const url = new URL(req.url);
377
+ const parts = url.pathname.split("/");
378
+ const id = decodeURIComponent(parts[3] || "");
379
+ return withSecurityHeaders(
380
+ await handleRevealDoc(ctxHolder, store, id, req),
304
381
  isDev
305
382
  );
306
383
  },
@@ -0,0 +1,149 @@
1
+ export type HealthCheckStatus = "ok" | "warn" | "error";
2
+
3
+ export type HealthActionKind =
4
+ | "add-collection"
5
+ | "open-collections"
6
+ | "sync"
7
+ | "embed"
8
+ | "download-models"
9
+ | "free-space";
10
+
11
+ export type OnboardingStepStatus = "complete" | "current" | "upcoming";
12
+
13
+ export interface StatusCollection {
14
+ name: string;
15
+ path: string;
16
+ documentCount: number;
17
+ chunkCount: number;
18
+ embeddedCount: number;
19
+ }
20
+
21
+ export interface SuggestedCollection {
22
+ label: string;
23
+ path: string;
24
+ reason: string;
25
+ }
26
+
27
+ export interface OnboardingStep {
28
+ id: string;
29
+ title: string;
30
+ status: OnboardingStepStatus;
31
+ detail: string;
32
+ }
33
+
34
+ export interface OnboardingState {
35
+ ready: boolean;
36
+ stage: "add-collection" | "models" | "indexing" | "ready";
37
+ headline: string;
38
+ detail: string;
39
+ suggestedCollections: SuggestedCollection[];
40
+ steps: OnboardingStep[];
41
+ }
42
+
43
+ export interface HealthCheck {
44
+ id: string;
45
+ title: string;
46
+ status: HealthCheckStatus;
47
+ summary: string;
48
+ detail: string;
49
+ actionLabel?: string;
50
+ actionKind?: HealthActionKind;
51
+ }
52
+
53
+ export interface HealthCenterState {
54
+ state: "healthy" | "needs-attention" | "setup-required";
55
+ summary: string;
56
+ checks: HealthCheck[];
57
+ }
58
+
59
+ export interface BackgroundServiceState {
60
+ watcher: {
61
+ expectedCollections: string[];
62
+ activeCollections: string[];
63
+ failedCollections: Array<{ collection: string; reason: string }>;
64
+ queuedCollections: string[];
65
+ syncingCollections: string[];
66
+ lastEventAt: string | null;
67
+ lastSyncAt: string | null;
68
+ };
69
+ embedding: {
70
+ available: boolean;
71
+ pendingDocCount: number;
72
+ running: boolean;
73
+ nextRunAt: number | null;
74
+ lastRunAt: number | null;
75
+ lastResult: { embedded: number; errors: number } | null;
76
+ };
77
+ events: {
78
+ connectedClients: number;
79
+ retryMs: number;
80
+ };
81
+ }
82
+
83
+ export interface BootstrapState {
84
+ runtime: {
85
+ kind: "bun";
86
+ strategy: "manual-install-beta";
87
+ currentVersion: string;
88
+ requiredVersion: string;
89
+ ready: boolean;
90
+ managedByApp: boolean;
91
+ summary: string;
92
+ detail: string;
93
+ };
94
+ policy: {
95
+ offline: boolean;
96
+ allowDownload: boolean;
97
+ source: "default" | "hf-hub-offline" | "gno-offline" | "no-auto-download";
98
+ summary: string;
99
+ };
100
+ cache: {
101
+ path: string;
102
+ totalSizeBytes: number;
103
+ totalSizeLabel: string;
104
+ };
105
+ models: {
106
+ activePresetId: string;
107
+ activePresetName: string;
108
+ estimatedFootprint: string | null;
109
+ downloading: boolean;
110
+ cachedCount: number;
111
+ totalCount: number;
112
+ summary: string;
113
+ entries: Array<{
114
+ role: "embed" | "rerank" | "expand" | "gen";
115
+ uri: string;
116
+ cached: boolean;
117
+ path: string | null;
118
+ sizeBytes: number | null;
119
+ statusLabel: string;
120
+ }>;
121
+ };
122
+ }
123
+
124
+ export interface AppStatusResponse {
125
+ indexName: string;
126
+ configPath: string;
127
+ dbPath: string;
128
+ collections: StatusCollection[];
129
+ totalDocuments: number;
130
+ totalChunks: number;
131
+ embeddingBacklog: number;
132
+ lastUpdated: string | null;
133
+ recentErrors: number;
134
+ healthy: boolean;
135
+ activePreset: {
136
+ id: string;
137
+ name: string;
138
+ };
139
+ capabilities: {
140
+ bm25: boolean;
141
+ vector: boolean;
142
+ hybrid: boolean;
143
+ answer: boolean;
144
+ };
145
+ onboarding: OnboardingState;
146
+ health: HealthCenterState;
147
+ background: BackgroundServiceState;
148
+ bootstrap: BootstrapState;
149
+ }