gnosys 5.12.0 → 5.12.2
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/dist/cli.js +48 -7
- package/dist/index.js +179 -10
- package/dist/lib/addCommand.js +0 -1
- package/dist/lib/archive.js +0 -2
- package/dist/lib/askCommand.js +1 -1
- package/dist/lib/attachCommand.d.ts +17 -0
- package/dist/lib/attachCommand.js +66 -0
- package/dist/lib/attachments.d.ts +43 -2
- package/dist/lib/attachments.js +81 -2
- package/dist/lib/chat/choose.js +2 -2
- package/dist/lib/clientReadOverlay.js +3 -0
- package/dist/lib/config.d.ts +1 -48
- package/dist/lib/configCommand.js +2 -2
- package/dist/lib/db.d.ts +16 -1
- package/dist/lib/db.js +216 -119
- package/dist/lib/dbWrite.d.ts +1 -1
- package/dist/lib/dearchiveCommand.js +1 -1
- package/dist/lib/docxExtract.js +1 -1
- package/dist/lib/dream.d.ts +8 -0
- package/dist/lib/dream.js +35 -1
- package/dist/lib/dreamLogCommand.js +1 -1
- package/dist/lib/dreamRunLog.d.ts +1 -1
- package/dist/lib/dreamRunLog.js +26 -4
- package/dist/lib/embeddings.js +0 -3
- package/dist/lib/exportProject.d.ts +3 -2
- package/dist/lib/exportProject.js +2 -1
- package/dist/lib/federated.js +1 -1
- package/dist/lib/hybridSearchCommand.js +1 -1
- package/dist/lib/importProject.js +2 -1
- package/dist/lib/llm.js +1 -1
- package/dist/lib/lock.d.ts +1 -1
- package/dist/lib/lock.js +5 -3
- package/dist/lib/migrate.js +0 -1
- package/dist/lib/multimodalIngest.js +1 -1
- package/dist/lib/platform.d.ts +0 -6
- package/dist/lib/platform.js +0 -28
- package/dist/lib/readCommand.js +11 -10
- package/dist/lib/remoteWizard.d.ts +1 -1
- package/dist/lib/remoteWizard.js +4 -4
- package/dist/lib/rulesGen.d.ts +8 -0
- package/dist/lib/rulesGen.js +16 -0
- package/dist/lib/search.d.ts +0 -2
- package/dist/lib/search.js +0 -7
- package/dist/lib/semanticSearchCommand.js +1 -1
- package/dist/lib/setup/sections/providers.js +56 -4
- package/dist/lib/setup/sections/routing.js +42 -5
- package/dist/lib/setup/sections/taskRoutingEditor.d.ts +1 -5
- package/dist/lib/setup/sections/taskRoutingEditor.js +0 -10
- package/dist/lib/setup/ui/header.js +0 -1
- package/dist/lib/setup/ui/status.d.ts +0 -1
- package/dist/lib/setup/ui/status.js +0 -2
- package/dist/lib/setup.d.ts +0 -15
- package/dist/lib/setup.js +13 -158
- package/dist/lib/staleCommand.js +2 -2
- package/dist/lib/syncClient.d.ts +0 -6
- package/dist/lib/syncClient.js +36 -14
- package/dist/lib/syncDoctorCommand.js +2 -2
- package/dist/lib/syncIngest.d.ts +11 -0
- package/dist/lib/syncIngest.js +24 -1
- package/dist/lib/syncIngestStartup.js +2 -2
- package/dist/lib/syncSnapshot.d.ts +2 -0
- package/dist/lib/syncSnapshot.js +4 -0
- package/dist/lib/syncStaging.d.ts +0 -2
- package/dist/lib/syncStaging.js +0 -2
- package/dist/lib/updateCommand.js +1 -1
- package/dist/lib/webBuildCommand.js +1 -1
- package/dist/lib/webIndex.js +0 -1
- package/dist/lib/webIngestCommand.js +1 -1
- package/dist/sandbox/client.js +1 -1
- package/dist/sandbox/manager.js +1 -14
- package/dist/sandbox/server.js +3 -5
- package/package.json +5 -2
package/dist/lib/attachments.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Gnosys Attachments — File attachment management for multimodal ingestion.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Two storage modes:
|
|
5
|
+
* - Filesystem (legacy, large media): bytes copied to .gnosys/attachments/<uuid>.<ext>
|
|
6
|
+
* with a JSON manifest. Does NOT travel between machines.
|
|
7
|
+
* - Inline DB blob (v5.12, small assets): bytes stored in the memory row's
|
|
8
|
+
* attachment_data column. Travels over the same row-copy sync rail as
|
|
9
|
+
* embeddings, so it works single-machine, multi-machine, and with a future
|
|
10
|
+
* dockerized MCP without any shared volume.
|
|
6
11
|
*/
|
|
7
12
|
import * as fs from "fs/promises";
|
|
8
13
|
import * as path from "path";
|
|
@@ -37,6 +42,10 @@ const MIME_MAP = {
|
|
|
37
42
|
function mimeFromExtension(ext) {
|
|
38
43
|
return MIME_MAP[ext.toLowerCase()] || "application/octet-stream";
|
|
39
44
|
}
|
|
45
|
+
/** Infer a MIME type from a file path's extension. */
|
|
46
|
+
export function inferMimeType(filePath) {
|
|
47
|
+
return mimeFromExtension(path.extname(filePath).slice(1));
|
|
48
|
+
}
|
|
40
49
|
// ─── Helpers ────────────────────────────────────────────────────────────
|
|
41
50
|
function getAttachmentsDir(storePath) {
|
|
42
51
|
return path.join(storePath, "attachments");
|
|
@@ -151,3 +160,73 @@ export async function linkMemoryToAttachment(storePath, uuid, memoryId) {
|
|
|
151
160
|
await writeManifest(storePath, manifest);
|
|
152
161
|
}
|
|
153
162
|
}
|
|
163
|
+
// ─── Inline DB-blob attachments (v5.12) ─────────────────────────────────
|
|
164
|
+
//
|
|
165
|
+
// Small binary assets (logos, diagrams, screenshots) are stored directly in
|
|
166
|
+
// the memory row's attachment_data column. Because remote sync copies whole
|
|
167
|
+
// rows (the same way it already moves the `embedding` blob), these attachments
|
|
168
|
+
// travel machine-to-machine for free and need no shared filesystem — which is
|
|
169
|
+
// exactly what a dockerized MCP server needs.
|
|
170
|
+
/**
|
|
171
|
+
* Maximum size for an inline DB-blob attachment. Larger files should use the
|
|
172
|
+
* filesystem path (`gnosys ingest`) so the synced central DB stays lean.
|
|
173
|
+
*/
|
|
174
|
+
export const MAX_INLINE_ATTACHMENT_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
175
|
+
/**
|
|
176
|
+
* Read a file and store its bytes inline on a memory row (attachment_data).
|
|
177
|
+
* Enforces the size cap and skips the write if the same bytes are already
|
|
178
|
+
* attached (content-hash dedup). Bumps `modified` so remote sync picks it up.
|
|
179
|
+
*/
|
|
180
|
+
export async function attachFileToMemory(db, memoryId, filePath) {
|
|
181
|
+
const mem = db.getMemory(memoryId);
|
|
182
|
+
if (!mem) {
|
|
183
|
+
throw new Error(`Memory not found: ${memoryId}`);
|
|
184
|
+
}
|
|
185
|
+
const stat = await fs.stat(filePath);
|
|
186
|
+
if (stat.size > MAX_INLINE_ATTACHMENT_BYTES) {
|
|
187
|
+
const limitMb = (MAX_INLINE_ATTACHMENT_BYTES / (1024 * 1024)).toFixed(0);
|
|
188
|
+
const sizeMb = (stat.size / (1024 * 1024)).toFixed(1);
|
|
189
|
+
throw new Error(`File is ${sizeMb}MB, which exceeds the ${limitMb}MB inline-attachment limit. ` +
|
|
190
|
+
`Use 'gnosys ingest' for large media (it stores the file on disk instead).`);
|
|
191
|
+
}
|
|
192
|
+
const data = await fs.readFile(filePath);
|
|
193
|
+
const name = path.basename(filePath);
|
|
194
|
+
const mime = inferMimeType(filePath);
|
|
195
|
+
// Dedup: if the same bytes are already attached, skip the write.
|
|
196
|
+
if (mem.attachment_data && Buffer.from(mem.attachment_data).equals(data)) {
|
|
197
|
+
return { memoryId, name, mime, sizeBytes: data.length, unchanged: true };
|
|
198
|
+
}
|
|
199
|
+
db.updateMemory(memoryId, {
|
|
200
|
+
attachment_data: data,
|
|
201
|
+
attachment_mime: mime,
|
|
202
|
+
attachment_name: name,
|
|
203
|
+
modified: new Date().toISOString(),
|
|
204
|
+
});
|
|
205
|
+
return { memoryId, name, mime, sizeBytes: data.length, unchanged: false };
|
|
206
|
+
}
|
|
207
|
+
/** Return the inline attachment stored on a memory row, or null if none. */
|
|
208
|
+
export function getMemoryAttachment(db, memoryId) {
|
|
209
|
+
const mem = db.getMemory(memoryId);
|
|
210
|
+
if (!mem?.attachment_data)
|
|
211
|
+
return null;
|
|
212
|
+
const data = Buffer.from(mem.attachment_data);
|
|
213
|
+
return {
|
|
214
|
+
data,
|
|
215
|
+
mime: mem.attachment_mime || "application/octet-stream",
|
|
216
|
+
name: mem.attachment_name || `${memoryId}.bin`,
|
|
217
|
+
sizeBytes: data.length,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/** Remove an inline attachment from a memory row (keeps the memory itself). */
|
|
221
|
+
export function detachFromMemory(db, memoryId) {
|
|
222
|
+
const mem = db.getMemory(memoryId);
|
|
223
|
+
if (!mem?.attachment_data)
|
|
224
|
+
return false;
|
|
225
|
+
db.updateMemory(memoryId, {
|
|
226
|
+
attachment_data: null,
|
|
227
|
+
attachment_mime: null,
|
|
228
|
+
attachment_name: null,
|
|
229
|
+
modified: new Date().toISOString(),
|
|
230
|
+
});
|
|
231
|
+
return true;
|
|
232
|
+
}
|
package/dist/lib/chat/choose.js
CHANGED
|
@@ -115,7 +115,7 @@ export function parseChooseYaml(yaml) {
|
|
|
115
115
|
const itemStart = line.match(/^\s*-\s*id:\s*(.+?)\s*$/);
|
|
116
116
|
if (itemStart) {
|
|
117
117
|
// Push previous item if any
|
|
118
|
-
if (current
|
|
118
|
+
if (current?.label)
|
|
119
119
|
options.push(current);
|
|
120
120
|
current = { id: itemStart[1], label: "" };
|
|
121
121
|
continue;
|
|
@@ -133,7 +133,7 @@ export function parseChooseYaml(yaml) {
|
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
// Flush the last option
|
|
136
|
-
if (current
|
|
136
|
+
if (current?.label)
|
|
137
137
|
options.push(current);
|
|
138
138
|
return { prompt, options };
|
|
139
139
|
}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Uses Zod for schema validation with sensible defaults.
|
|
4
4
|
*/
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
export type { LlmTaskName } from "./apiKeyVault.js";
|
|
7
6
|
declare const LLMProviderEnum: z.ZodEnum<{
|
|
8
7
|
anthropic: "anthropic";
|
|
9
8
|
ollama: "ollama";
|
|
@@ -52,53 +51,6 @@ declare const RecallConfigSchema: z.ZodObject<{
|
|
|
52
51
|
minRelevance: z.ZodDefault<z.ZodNumber>;
|
|
53
52
|
}, z.core.$strip>;
|
|
54
53
|
export type RecallConfig = z.infer<typeof RecallConfigSchema>;
|
|
55
|
-
declare const ChatConfigSchema: z.ZodObject<{
|
|
56
|
-
toolsEnabled: z.ZodDefault<z.ZodBoolean>;
|
|
57
|
-
autoSummarizeAfterTurns: z.ZodDefault<z.ZodNumber>;
|
|
58
|
-
systemPromptPrefix: z.ZodDefault<z.ZodString>;
|
|
59
|
-
}, z.core.$strip>;
|
|
60
|
-
export type ChatConfig = z.infer<typeof ChatConfigSchema>;
|
|
61
|
-
declare const MultimodalConfigSchema: z.ZodObject<{
|
|
62
|
-
transcriptionProvider: z.ZodDefault<z.ZodEnum<{
|
|
63
|
-
groq: "groq";
|
|
64
|
-
openai: "openai";
|
|
65
|
-
local: "local";
|
|
66
|
-
}>>;
|
|
67
|
-
whisperModel: z.ZodDefault<z.ZodString>;
|
|
68
|
-
visionProvider: z.ZodOptional<z.ZodEnum<{
|
|
69
|
-
anthropic: "anthropic";
|
|
70
|
-
ollama: "ollama";
|
|
71
|
-
groq: "groq";
|
|
72
|
-
openai: "openai";
|
|
73
|
-
lmstudio: "lmstudio";
|
|
74
|
-
xai: "xai";
|
|
75
|
-
mistral: "mistral";
|
|
76
|
-
openrouter: "openrouter";
|
|
77
|
-
custom: "custom";
|
|
78
|
-
}>>;
|
|
79
|
-
visionModel: z.ZodOptional<z.ZodString>;
|
|
80
|
-
chunkSize: z.ZodDefault<z.ZodNumber>;
|
|
81
|
-
maxFileSizeMb: z.ZodDefault<z.ZodNumber>;
|
|
82
|
-
}, z.core.$strip>;
|
|
83
|
-
export type MultimodalConfig = z.infer<typeof MultimodalConfigSchema>;
|
|
84
|
-
declare const WebConfigSchema: z.ZodObject<{
|
|
85
|
-
source: z.ZodDefault<z.ZodEnum<{
|
|
86
|
-
sitemap: "sitemap";
|
|
87
|
-
directory: "directory";
|
|
88
|
-
urls: "urls";
|
|
89
|
-
}>>;
|
|
90
|
-
sitemapUrl: z.ZodOptional<z.ZodString>;
|
|
91
|
-
contentDir: z.ZodOptional<z.ZodString>;
|
|
92
|
-
urls: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
93
|
-
outputDir: z.ZodDefault<z.ZodString>;
|
|
94
|
-
exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
95
|
-
categories: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
96
|
-
llmEnrich: z.ZodDefault<z.ZodBoolean>;
|
|
97
|
-
prune: z.ZodDefault<z.ZodBoolean>;
|
|
98
|
-
concurrency: z.ZodDefault<z.ZodNumber>;
|
|
99
|
-
crawlDelayMs: z.ZodDefault<z.ZodNumber>;
|
|
100
|
-
}, z.core.$strip>;
|
|
101
|
-
export type WebConfig = z.infer<typeof WebConfigSchema>;
|
|
102
54
|
export declare const GnosysConfigSchema: z.ZodObject<{
|
|
103
55
|
llm: z.ZodDefault<z.ZodObject<{
|
|
104
56
|
defaultProvider: z.ZodDefault<z.ZodEnum<{
|
|
@@ -422,3 +374,4 @@ export declare function generateConfigTemplate(): string;
|
|
|
422
374
|
* All supported provider names.
|
|
423
375
|
*/
|
|
424
376
|
export declare const ALL_PROVIDERS: LLMProviderName[];
|
|
377
|
+
export {};
|
|
@@ -243,7 +243,7 @@ export async function runConfigSetCommand(getResolver, key, value, extra) {
|
|
|
243
243
|
break;
|
|
244
244
|
case "maxMemories": {
|
|
245
245
|
const n = parseInt(recallValue, 10);
|
|
246
|
-
if (isNaN(n) || n < 1 || n > 20) {
|
|
246
|
+
if (Number.isNaN(n) || n < 1 || n > 20) {
|
|
247
247
|
printStatus("fail", "maxMemories must be between 1 and 20");
|
|
248
248
|
process.exit(1);
|
|
249
249
|
}
|
|
@@ -253,7 +253,7 @@ export async function runConfigSetCommand(getResolver, key, value, extra) {
|
|
|
253
253
|
}
|
|
254
254
|
case "minRelevance": {
|
|
255
255
|
const f = parseFloat(recallValue);
|
|
256
|
-
if (isNaN(f) || f < 0 || f > 1) {
|
|
256
|
+
if (Number.isNaN(f) || f < 0 || f > 1) {
|
|
257
257
|
printStatus("fail", "minRelevance must be between 0 and 1");
|
|
258
258
|
process.exit(1);
|
|
259
259
|
}
|
package/dist/lib/db.d.ts
CHANGED
|
@@ -32,6 +32,9 @@ export interface DbMemory {
|
|
|
32
32
|
source_file: string | null;
|
|
33
33
|
source_page: string | null;
|
|
34
34
|
source_timerange: string | null;
|
|
35
|
+
attachment_data: Buffer | null;
|
|
36
|
+
attachment_mime: string | null;
|
|
37
|
+
attachment_name: string | null;
|
|
35
38
|
project_id: string | null;
|
|
36
39
|
scope: string;
|
|
37
40
|
}
|
|
@@ -96,6 +99,9 @@ export interface MigrationStats {
|
|
|
96
99
|
declare function fnv1a(str: string): string;
|
|
97
100
|
export declare class GnosysDB {
|
|
98
101
|
private db;
|
|
102
|
+
/** v5.12.x perf: prepared-statement cache, keyed by SQL. Invalidated on
|
|
103
|
+
* reopen()/close() — statements are bound to their connection handle. */
|
|
104
|
+
private stmtCache;
|
|
99
105
|
private storePath;
|
|
100
106
|
private available;
|
|
101
107
|
private dbFilePath;
|
|
@@ -175,6 +181,12 @@ export declare class GnosysDB {
|
|
|
175
181
|
* Read methods are also wrapped because reads against stale pages can
|
|
176
182
|
* surface the same error.
|
|
177
183
|
*/
|
|
184
|
+
/**
|
|
185
|
+
* Prepare-with-cache for fixed-SQL hot paths. Dynamic SQL (e.g. the
|
|
186
|
+
* field-built UPDATE in updateMemory) must keep using db.prepare directly
|
|
187
|
+
* so the cache stays bounded. Cache is invalidated on reopen()/close().
|
|
188
|
+
*/
|
|
189
|
+
private prep;
|
|
178
190
|
private withRecovery;
|
|
179
191
|
/**
|
|
180
192
|
* Restore from a backup file. Closes current DB, copies backup over, re-opens.
|
|
@@ -189,11 +201,14 @@ export declare class GnosysDB {
|
|
|
189
201
|
isAvailable(): boolean;
|
|
190
202
|
getDbPath(): string;
|
|
191
203
|
getStorePath(): string;
|
|
192
|
-
insertMemory(mem: Omit<DbMemory, "embedding" | "source_file" | "source_page" | "source_timerange"> & {
|
|
204
|
+
insertMemory(mem: Omit<DbMemory, "embedding" | "source_file" | "source_page" | "source_timerange" | "attachment_data" | "attachment_mime" | "attachment_name"> & {
|
|
193
205
|
embedding?: Buffer | null;
|
|
194
206
|
source_file?: string | null;
|
|
195
207
|
source_page?: string | null;
|
|
196
208
|
source_timerange?: string | null;
|
|
209
|
+
attachment_data?: Buffer | null;
|
|
210
|
+
attachment_mime?: string | null;
|
|
211
|
+
attachment_name?: string | null;
|
|
197
212
|
}): void;
|
|
198
213
|
getMemory(id: string): DbMemory | null;
|
|
199
214
|
getActiveMemories(): DbMemory[];
|