@gmickel/gno 0.31.1 → 0.32.0
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/package.json +2 -2
- package/src/serve/jobs.ts +12 -0
- package/src/serve/public/components/BacklinksPanel.tsx +3 -1
- package/src/serve/public/components/OutgoingLinksPanel.tsx +3 -1
- package/src/serve/public/components/RelatedNotesSidebar.tsx +1 -1
- package/src/serve/public/pages/Browse.tsx +10 -10
- package/src/serve/routes/api.ts +37 -5
- package/src/serve/server.ts +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmickel/gno",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Local semantic search for your documents. Index Markdown, PDF, and Office files with hybrid BM25 + vector search.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"embeddings",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"research:finetune:autonomous:confirm-winner": "bun research/finetune/autonomous/scripts/confirm-winner.ts",
|
|
81
81
|
"research:finetune:autonomous:check-promotion-targets": "bun research/finetune/autonomous/scripts/check-promotion-targets.ts",
|
|
82
82
|
"research:finetune:validate": "bun research/finetune/scripts/validate-sandbox.ts",
|
|
83
|
-
"research:finetune:qmd-import": "bun research/finetune/scripts/import-qmd-training.ts",
|
|
83
|
+
"research:finetune:qmd-import:legacy": "bun research/finetune/scripts/import-qmd-training.ts",
|
|
84
84
|
"research:finetune:mlx:build-dataset": "bun research/finetune/scripts/build-mlx-dataset.ts",
|
|
85
85
|
"research:finetune:build-variant-dataset": "bun research/finetune/scripts/build-variant-dataset.ts",
|
|
86
86
|
"research:finetune:list-mix-variants": "bun research/finetune/scripts/list-mix-variants.ts",
|
package/src/serve/jobs.ts
CHANGED
|
@@ -37,6 +37,7 @@ export interface StartJobError {
|
|
|
37
37
|
ok: false;
|
|
38
38
|
error: string;
|
|
39
39
|
status: 409;
|
|
40
|
+
activeJobId: string;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export type StartJobResult = StartJobSuccess | StartJobError;
|
|
@@ -84,6 +85,7 @@ export function startJob(
|
|
|
84
85
|
ok: false,
|
|
85
86
|
error: `Job ${activeJobId} already running`,
|
|
86
87
|
status: 409,
|
|
88
|
+
activeJobId,
|
|
87
89
|
};
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -142,6 +144,16 @@ export function getActiveJobId(): string | null {
|
|
|
142
144
|
return activeJobId;
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Get the currently active job status, if any.
|
|
149
|
+
*/
|
|
150
|
+
export function getActiveJob(): JobStatus | null {
|
|
151
|
+
if (!activeJobId) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
return jobs.get(activeJobId) ?? null;
|
|
155
|
+
}
|
|
156
|
+
|
|
145
157
|
/**
|
|
146
158
|
* Update job progress (called from within job execution).
|
|
147
159
|
*
|
|
@@ -167,7 +167,9 @@ function BacklinkItem({
|
|
|
167
167
|
<Tooltip>
|
|
168
168
|
<TooltipTrigger asChild>
|
|
169
169
|
<div className="min-w-0 flex-1">
|
|
170
|
-
<span className="block
|
|
170
|
+
<span className="block break-words font-medium leading-tight whitespace-normal">
|
|
171
|
+
{displayName}
|
|
172
|
+
</span>
|
|
171
173
|
{/* Line reference as subtitle */}
|
|
172
174
|
<span className="block truncate text-[10px] opacity-60">
|
|
173
175
|
L{backlink.startLine}:{backlink.startCol}
|
|
@@ -170,7 +170,9 @@ function LinkItem({
|
|
|
170
170
|
<Tooltip>
|
|
171
171
|
<TooltipTrigger asChild>
|
|
172
172
|
<div className="min-w-0 flex-1">
|
|
173
|
-
<span className="block
|
|
173
|
+
<span className="block break-words font-medium leading-tight whitespace-normal">
|
|
174
|
+
{displayText}
|
|
175
|
+
</span>
|
|
174
176
|
{link.targetAnchor && (
|
|
175
177
|
<span className="block truncate text-[10px] opacity-60">
|
|
176
178
|
#{link.targetAnchor}
|
|
@@ -260,7 +260,7 @@ function RelatedNoteItem({
|
|
|
260
260
|
{/* Title with tooltip for long names */}
|
|
261
261
|
<Tooltip>
|
|
262
262
|
<TooltipTrigger asChild>
|
|
263
|
-
<h4 className="
|
|
263
|
+
<h4 className="line-clamp-3 break-words font-mono text-[13px] leading-tight text-foreground/90 group-hover:text-foreground">
|
|
264
264
|
{doc.title || "Untitled"}
|
|
265
265
|
</h4>
|
|
266
266
|
</TooltipTrigger>
|
|
@@ -443,12 +443,12 @@ export default function Browse({ navigate }: PageProps) {
|
|
|
443
443
|
{/* Document Table */}
|
|
444
444
|
{docs.length > 0 && (
|
|
445
445
|
<div className="animate-fade-in opacity-0">
|
|
446
|
-
<Table>
|
|
446
|
+
<Table className="table-fixed">
|
|
447
447
|
<TableHeader>
|
|
448
448
|
<TableRow>
|
|
449
|
-
<TableHead className="w-[
|
|
450
|
-
<TableHead>Collection</TableHead>
|
|
451
|
-
<TableHead className="text-right">Type</TableHead>
|
|
449
|
+
<TableHead className="w-[68%]">Document</TableHead>
|
|
450
|
+
<TableHead className="w-[220px]">Collection</TableHead>
|
|
451
|
+
<TableHead className="w-[72px] text-right">Type</TableHead>
|
|
452
452
|
</TableRow>
|
|
453
453
|
</TableHeader>
|
|
454
454
|
<TableBody>
|
|
@@ -460,14 +460,14 @@ export default function Browse({ navigate }: PageProps) {
|
|
|
460
460
|
navigate(`/doc?uri=${encodeURIComponent(doc.uri)}`)
|
|
461
461
|
}
|
|
462
462
|
>
|
|
463
|
-
<TableCell>
|
|
463
|
+
<TableCell className="align-top whitespace-normal">
|
|
464
464
|
<div className="flex items-center gap-2">
|
|
465
465
|
<FileText className="size-4 shrink-0 text-muted-foreground" />
|
|
466
466
|
<div className="min-w-0">
|
|
467
|
-
<div className="
|
|
467
|
+
<div className="break-words font-medium leading-tight transition-colors group-hover:text-primary">
|
|
468
468
|
{doc.title || doc.relPath}
|
|
469
469
|
</div>
|
|
470
|
-
<div className="
|
|
470
|
+
<div className="break-all font-mono text-muted-foreground text-xs leading-relaxed">
|
|
471
471
|
{doc.relPath}
|
|
472
472
|
</div>
|
|
473
473
|
</div>
|
|
@@ -499,9 +499,9 @@ export default function Browse({ navigate }: PageProps) {
|
|
|
499
499
|
<ChevronRight className="ml-auto size-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100" />
|
|
500
500
|
</div>
|
|
501
501
|
</TableCell>
|
|
502
|
-
<TableCell>
|
|
502
|
+
<TableCell className="align-top whitespace-normal">
|
|
503
503
|
<Badge
|
|
504
|
-
className="cursor-pointer font-mono text-xs transition-colors hover:border-primary hover:text-primary"
|
|
504
|
+
className="inline-flex min-h-[2.5rem] max-w-[180px] cursor-pointer items-center px-3 py-1 text-center whitespace-normal break-words font-mono text-xs leading-tight transition-colors hover:border-primary hover:text-primary"
|
|
505
505
|
onClick={(event) => {
|
|
506
506
|
event.stopPropagation();
|
|
507
507
|
navigateToCollection(doc.collection);
|
|
@@ -511,7 +511,7 @@ export default function Browse({ navigate }: PageProps) {
|
|
|
511
511
|
{doc.collection}
|
|
512
512
|
</Badge>
|
|
513
513
|
</TableCell>
|
|
514
|
-
<TableCell className="text-right">
|
|
514
|
+
<TableCell className="align-top text-right">
|
|
515
515
|
<Badge
|
|
516
516
|
className="font-mono text-xs"
|
|
517
517
|
variant={getExtBadgeVariant(doc.sourceExt)}
|
package/src/serve/routes/api.ts
CHANGED
|
@@ -17,6 +17,7 @@ import type { SqliteAdapter } from "../../store/sqlite/adapter";
|
|
|
17
17
|
import type { DocumentRow } from "../../store/types";
|
|
18
18
|
import type { DocumentEventBus } from "../doc-events";
|
|
19
19
|
import type { EmbedScheduler } from "../embed-scheduler";
|
|
20
|
+
import type { StartJobError } from "../jobs";
|
|
20
21
|
import type { CollectionWatchService } from "../watch-service";
|
|
21
22
|
|
|
22
23
|
import { modelsPull } from "../../cli/commands/models/pull";
|
|
@@ -58,7 +59,7 @@ import {
|
|
|
58
59
|
type ServerContext,
|
|
59
60
|
} from "../context";
|
|
60
61
|
import { analyzeImportPath } from "../import-preview";
|
|
61
|
-
import { getJobStatus, startJob } from "../jobs";
|
|
62
|
+
import { getActiveJob, getJobStatus, startJob } from "../jobs";
|
|
62
63
|
import { buildAppStatus, type StatusBuildDeps } from "../status";
|
|
63
64
|
|
|
64
65
|
/** Mutable context holder for hot-reloading presets */
|
|
@@ -78,6 +79,7 @@ export interface ApiError {
|
|
|
78
79
|
error: {
|
|
79
80
|
code: string;
|
|
80
81
|
message: string;
|
|
82
|
+
details?: Record<string, unknown>;
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
|
|
@@ -211,8 +213,28 @@ function jsonResponse(data: unknown, status = 200): Response {
|
|
|
211
213
|
return Response.json(data, { status });
|
|
212
214
|
}
|
|
213
215
|
|
|
214
|
-
function errorResponse(
|
|
215
|
-
|
|
216
|
+
function errorResponse(
|
|
217
|
+
code: string,
|
|
218
|
+
message: string,
|
|
219
|
+
status = 400,
|
|
220
|
+
details?: Record<string, unknown>
|
|
221
|
+
): Response {
|
|
222
|
+
return jsonResponse(
|
|
223
|
+
{
|
|
224
|
+
error: {
|
|
225
|
+
code,
|
|
226
|
+
message,
|
|
227
|
+
...(details ? { details } : {}),
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
status
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function jobConflictResponse(jobResult: StartJobError): Response {
|
|
235
|
+
return errorResponse("CONFLICT", jobResult.error, 409, {
|
|
236
|
+
activeJobId: jobResult.activeJobId,
|
|
237
|
+
});
|
|
216
238
|
}
|
|
217
239
|
|
|
218
240
|
function parseCommaSeparatedValues(input: string): string[] {
|
|
@@ -591,7 +613,7 @@ export async function handleCreateCollection(
|
|
|
591
613
|
});
|
|
592
614
|
|
|
593
615
|
if (!jobResult.ok) {
|
|
594
|
-
return
|
|
616
|
+
return jobConflictResponse(jobResult);
|
|
595
617
|
}
|
|
596
618
|
|
|
597
619
|
return jsonResponse(
|
|
@@ -742,7 +764,7 @@ export async function handleSync(
|
|
|
742
764
|
});
|
|
743
765
|
|
|
744
766
|
if (!jobResult.ok) {
|
|
745
|
-
return
|
|
767
|
+
return jobConflictResponse(jobResult);
|
|
746
768
|
}
|
|
747
769
|
|
|
748
770
|
return jsonResponse({ jobId: jobResult.jobId }, 202);
|
|
@@ -2619,6 +2641,16 @@ export function handleJob(jobId: string): Response {
|
|
|
2619
2641
|
return jsonResponse(status);
|
|
2620
2642
|
}
|
|
2621
2643
|
|
|
2644
|
+
/**
|
|
2645
|
+
* GET /api/jobs/active
|
|
2646
|
+
* Returns the current active job, or null when idle.
|
|
2647
|
+
*/
|
|
2648
|
+
export function handleActiveJob(): Response {
|
|
2649
|
+
return jsonResponse({
|
|
2650
|
+
activeJob: getActiveJob(),
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2622
2654
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2623
2655
|
// Embed Scheduler
|
|
2624
2656
|
// ─────────────────────────────────────────────────────────────────────────────
|
package/src/serve/server.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { DocumentEventBus } from "./doc-events";
|
|
|
13
13
|
// HTML import - Bun handles bundling TSX/CSS automatically via routes
|
|
14
14
|
import homepage from "./public/index.html";
|
|
15
15
|
import {
|
|
16
|
+
handleActiveJob,
|
|
16
17
|
handleAsk,
|
|
17
18
|
handleCapabilities,
|
|
18
19
|
handleCollections,
|
|
@@ -421,6 +422,9 @@ export async function startServer(
|
|
|
421
422
|
return withSecurityHeaders(handleModelPull(ctxHolder), isDev);
|
|
422
423
|
},
|
|
423
424
|
},
|
|
425
|
+
"/api/jobs/active": {
|
|
426
|
+
GET: () => withSecurityHeaders(handleActiveJob(), isDev),
|
|
427
|
+
},
|
|
424
428
|
"/api/jobs/:id": {
|
|
425
429
|
GET: (req: Request) => {
|
|
426
430
|
const url = new URL(req.url);
|