@gmickel/gno 0.31.2 → 0.33.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmickel/gno",
3
- "version": "0.31.2",
3
+ "version": "0.33.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
  *
@@ -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(code: string, message: string, status = 400): Response {
215
- return jsonResponse({ error: { code, message } }, status);
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 errorResponse("CONFLICT", jobResult.error, 409);
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 errorResponse("CONFLICT", jobResult.error, 409);
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
  // ─────────────────────────────────────────────────────────────────────────────
@@ -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);