gnosys 5.11.4 → 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.
Files changed (265) hide show
  1. package/dist/cli.js +377 -5162
  2. package/dist/index.js +542 -244
  3. package/dist/lib/addCommand.d.ts +9 -0
  4. package/dist/lib/addCommand.js +102 -0
  5. package/dist/lib/addStructuredCommand.d.ts +16 -0
  6. package/dist/lib/addStructuredCommand.js +103 -0
  7. package/dist/lib/ambiguityCommand.d.ts +4 -0
  8. package/dist/lib/ambiguityCommand.js +36 -0
  9. package/dist/lib/apiKeyVault.d.ts +78 -0
  10. package/dist/lib/apiKeyVault.js +447 -0
  11. package/dist/lib/archive.js +0 -2
  12. package/dist/lib/askCommand.d.ts +13 -0
  13. package/dist/lib/askCommand.js +145 -0
  14. package/dist/lib/attachCommand.d.ts +17 -0
  15. package/dist/lib/attachCommand.js +66 -0
  16. package/dist/lib/attachments.d.ts +43 -2
  17. package/dist/lib/attachments.js +81 -2
  18. package/dist/lib/audioExtract.js +4 -1
  19. package/dist/lib/auditCommand.d.ts +7 -0
  20. package/dist/lib/auditCommand.js +27 -0
  21. package/dist/lib/backupCommand.d.ts +6 -0
  22. package/dist/lib/backupCommand.js +54 -0
  23. package/dist/lib/bootstrapCommand.d.ts +15 -0
  24. package/dist/lib/bootstrapCommand.js +51 -0
  25. package/dist/lib/briefingCommand.d.ts +7 -0
  26. package/dist/lib/briefingCommand.js +92 -0
  27. package/dist/lib/centralizeCommand.d.ts +5 -0
  28. package/dist/lib/centralizeCommand.js +16 -0
  29. package/dist/lib/chat/choose.js +2 -2
  30. package/dist/lib/chatCommand.d.ts +12 -0
  31. package/dist/lib/chatCommand.js +46 -0
  32. package/dist/lib/checkCommand.d.ts +4 -0
  33. package/dist/lib/checkCommand.js +133 -0
  34. package/dist/lib/clientReadOverlay.d.ts +27 -0
  35. package/dist/lib/clientReadOverlay.js +76 -0
  36. package/dist/lib/clientReadResolve.d.ts +32 -0
  37. package/dist/lib/clientReadResolve.js +84 -0
  38. package/dist/lib/commitContextCommand.d.ts +9 -0
  39. package/dist/lib/commitContextCommand.js +142 -0
  40. package/dist/lib/config.d.ts +41 -48
  41. package/dist/lib/config.js +58 -57
  42. package/dist/lib/configCommand.d.ts +10 -0
  43. package/dist/lib/configCommand.js +321 -0
  44. package/dist/lib/connectCommand.d.ts +8 -0
  45. package/dist/lib/connectCommand.js +19 -0
  46. package/dist/lib/db.d.ts +68 -1
  47. package/dist/lib/db.js +385 -120
  48. package/dist/lib/dbWrite.d.ts +1 -1
  49. package/dist/lib/dearchiveCommand.d.ts +7 -0
  50. package/dist/lib/dearchiveCommand.js +41 -0
  51. package/dist/lib/discoverCommand.d.ts +9 -0
  52. package/dist/lib/discoverCommand.js +87 -0
  53. package/dist/lib/doctorCommand.d.ts +6 -0
  54. package/dist/lib/doctorCommand.js +256 -0
  55. package/dist/lib/docxExtract.js +1 -1
  56. package/dist/lib/dream.d.ts +50 -2
  57. package/dist/lib/dream.js +324 -30
  58. package/dist/lib/dreamCommand.d.ts +10 -0
  59. package/dist/lib/dreamCommand.js +195 -0
  60. package/dist/lib/dreamLaunchd.d.ts +2 -0
  61. package/dist/lib/dreamLaunchd.js +72 -0
  62. package/dist/lib/dreamLogCommand.d.ts +10 -0
  63. package/dist/lib/dreamLogCommand.js +58 -0
  64. package/dist/lib/dreamReport.d.ts +7 -0
  65. package/dist/lib/dreamReport.js +114 -0
  66. package/dist/lib/dreamRunLog.d.ts +121 -0
  67. package/dist/lib/dreamRunLog.js +234 -0
  68. package/dist/lib/embeddings.js +3 -3
  69. package/dist/lib/exportCommand.d.ts +18 -0
  70. package/dist/lib/exportCommand.js +101 -0
  71. package/dist/lib/exportProject.d.ts +3 -2
  72. package/dist/lib/exportProject.js +2 -1
  73. package/dist/lib/federated.js +1 -1
  74. package/dist/lib/fsearchCommand.d.ts +8 -0
  75. package/dist/lib/fsearchCommand.js +44 -0
  76. package/dist/lib/graphCommand.d.ts +4 -0
  77. package/dist/lib/graphCommand.js +68 -0
  78. package/dist/lib/helperGenerateCommand.d.ts +5 -0
  79. package/dist/lib/helperGenerateCommand.js +27 -0
  80. package/dist/lib/historyCommand.d.ts +5 -0
  81. package/dist/lib/historyCommand.js +51 -0
  82. package/dist/lib/hybridSearchCommand.d.ts +12 -0
  83. package/dist/lib/hybridSearchCommand.js +95 -0
  84. package/dist/lib/importCommand.d.ts +16 -0
  85. package/dist/lib/importCommand.js +89 -0
  86. package/dist/lib/importProject.js +2 -1
  87. package/dist/lib/importProjectCommand.d.ts +6 -0
  88. package/dist/lib/importProjectCommand.js +43 -0
  89. package/dist/lib/ingestCommand.d.ts +13 -0
  90. package/dist/lib/ingestCommand.js +95 -0
  91. package/dist/lib/installOutput.d.ts +36 -0
  92. package/dist/lib/installOutput.js +55 -0
  93. package/dist/lib/lensCommand.d.ts +20 -0
  94. package/dist/lib/lensCommand.js +61 -0
  95. package/dist/lib/lensing.d.ts +1 -0
  96. package/dist/lib/lensing.js +50 -9
  97. package/dist/lib/linksCommand.d.ts +7 -0
  98. package/dist/lib/linksCommand.js +48 -0
  99. package/dist/lib/listCommand.d.ts +8 -0
  100. package/dist/lib/listCommand.js +74 -0
  101. package/dist/lib/llm.d.ts +1 -1
  102. package/dist/lib/llm.js +27 -9
  103. package/dist/lib/localDiskCheck.d.ts +17 -0
  104. package/dist/lib/localDiskCheck.js +54 -0
  105. package/dist/lib/lock.d.ts +1 -1
  106. package/dist/lib/lock.js +5 -3
  107. package/dist/lib/machineConfig.d.ts +11 -1
  108. package/dist/lib/machineConfig.js +16 -0
  109. package/dist/lib/machineRegistry.d.ts +61 -0
  110. package/dist/lib/machineRegistry.js +80 -0
  111. package/dist/lib/maintainCommand.d.ts +8 -0
  112. package/dist/lib/maintainCommand.js +34 -0
  113. package/dist/lib/masterLease.d.ts +20 -0
  114. package/dist/lib/masterLease.js +68 -0
  115. package/dist/lib/migrate.js +0 -1
  116. package/dist/lib/migrateCommand.d.ts +7 -0
  117. package/dist/lib/migrateCommand.js +158 -0
  118. package/dist/lib/migrateDbCommand.d.ts +9 -0
  119. package/dist/lib/migrateDbCommand.js +94 -0
  120. package/dist/lib/modelValidation.d.ts +5 -0
  121. package/dist/lib/modelValidation.js +27 -0
  122. package/dist/lib/multimodalIngest.js +1 -1
  123. package/dist/lib/openrouterTiers.d.ts +29 -0
  124. package/dist/lib/openrouterTiers.js +113 -0
  125. package/dist/lib/platform.d.ts +0 -6
  126. package/dist/lib/platform.js +0 -28
  127. package/dist/lib/prefCommand.d.ts +10 -0
  128. package/dist/lib/prefCommand.js +118 -0
  129. package/dist/lib/projectsCommand.d.ts +8 -0
  130. package/dist/lib/projectsCommand.js +131 -0
  131. package/dist/lib/readCommand.d.ts +7 -0
  132. package/dist/lib/readCommand.js +63 -0
  133. package/dist/lib/recall.d.ts +3 -0
  134. package/dist/lib/recall.js +19 -4
  135. package/dist/lib/recallCommand.d.ts +11 -0
  136. package/dist/lib/recallCommand.js +112 -0
  137. package/dist/lib/reflectCommand.d.ts +8 -0
  138. package/dist/lib/reflectCommand.js +61 -0
  139. package/dist/lib/reindexCommand.d.ts +4 -0
  140. package/dist/lib/reindexCommand.js +34 -0
  141. package/dist/lib/reindexGraphCommand.d.ts +4 -0
  142. package/dist/lib/reindexGraphCommand.js +12 -0
  143. package/dist/lib/reinforceCommand.d.ts +8 -0
  144. package/dist/lib/reinforceCommand.js +40 -0
  145. package/dist/lib/remote.d.ts +5 -1
  146. package/dist/lib/remote.js +5 -1
  147. package/dist/lib/remoteWizard.d.ts +24 -5
  148. package/dist/lib/remoteWizard.js +308 -319
  149. package/dist/lib/restoreCommand.d.ts +5 -0
  150. package/dist/lib/restoreCommand.js +35 -0
  151. package/dist/lib/rulesGen.d.ts +8 -0
  152. package/dist/lib/rulesGen.js +16 -0
  153. package/dist/lib/sandboxStartCommand.d.ts +6 -0
  154. package/dist/lib/sandboxStartCommand.js +25 -0
  155. package/dist/lib/sandboxStatusCommand.d.ts +4 -0
  156. package/dist/lib/sandboxStatusCommand.js +24 -0
  157. package/dist/lib/sandboxStopCommand.d.ts +4 -0
  158. package/dist/lib/sandboxStopCommand.js +21 -0
  159. package/dist/lib/search.d.ts +0 -2
  160. package/dist/lib/search.js +0 -7
  161. package/dist/lib/searchCommand.d.ts +9 -0
  162. package/dist/lib/searchCommand.js +90 -0
  163. package/dist/lib/semanticSearchCommand.d.ts +8 -0
  164. package/dist/lib/semanticSearchCommand.js +52 -0
  165. package/dist/lib/setup/configSetRender.js +2 -0
  166. package/dist/lib/setup/providerGlyphs.d.ts +19 -0
  167. package/dist/lib/setup/providerGlyphs.js +42 -0
  168. package/dist/lib/setup/remoteRender.d.ts +31 -1
  169. package/dist/lib/setup/remoteRender.js +95 -4
  170. package/dist/lib/setup/sections/providers.d.ts +17 -0
  171. package/dist/lib/setup/sections/providers.js +307 -0
  172. package/dist/lib/setup/sections/routing.d.ts +2 -6
  173. package/dist/lib/setup/sections/routing.js +67 -82
  174. package/dist/lib/setup/sections/taskRoutingEditor.d.ts +13 -0
  175. package/dist/lib/setup/sections/taskRoutingEditor.js +139 -0
  176. package/dist/lib/setup/summary.d.ts +9 -0
  177. package/dist/lib/setup/summary.js +51 -37
  178. package/dist/lib/setup/ui/header.js +0 -1
  179. package/dist/lib/setup.d.ts +105 -15
  180. package/dist/lib/setup.js +747 -287
  181. package/dist/lib/setupKeys.d.ts +42 -0
  182. package/dist/lib/setupKeys.js +564 -0
  183. package/dist/lib/setupRemoteCommand.d.ts +4 -0
  184. package/dist/lib/setupRemoteCommand.js +28 -0
  185. package/dist/lib/setupRemotePullCommand.d.ts +5 -0
  186. package/dist/lib/setupRemotePullCommand.js +52 -0
  187. package/dist/lib/setupRemotePushCommand.d.ts +5 -0
  188. package/dist/lib/setupRemotePushCommand.js +57 -0
  189. package/dist/lib/setupRemoteResolveCommand.d.ts +4 -0
  190. package/dist/lib/setupRemoteResolveCommand.js +48 -0
  191. package/dist/lib/setupRemoteStatusCommand.d.ts +4 -0
  192. package/dist/lib/setupRemoteStatusCommand.js +73 -0
  193. package/dist/lib/setupRemoteSyncCommand.d.ts +6 -0
  194. package/dist/lib/setupRemoteSyncCommand.js +65 -0
  195. package/dist/lib/setupSyncProjectsCommand.d.ts +4 -0
  196. package/dist/lib/setupSyncProjectsCommand.js +292 -0
  197. package/dist/lib/staleCommand.d.ts +8 -0
  198. package/dist/lib/staleCommand.js +34 -0
  199. package/dist/lib/statsCommand.d.ts +6 -0
  200. package/dist/lib/statsCommand.js +142 -0
  201. package/dist/lib/statusCommand.d.ts +18 -0
  202. package/dist/lib/statusCommand.js +250 -0
  203. package/dist/lib/storesCommand.d.ts +2 -0
  204. package/dist/lib/storesCommand.js +4 -0
  205. package/dist/lib/syncClient.d.ts +41 -0
  206. package/dist/lib/syncClient.js +234 -0
  207. package/dist/lib/syncCommand.d.ts +6 -0
  208. package/dist/lib/syncCommand.js +57 -0
  209. package/dist/lib/syncDoctorCommand.d.ts +5 -0
  210. package/dist/lib/syncDoctorCommand.js +100 -0
  211. package/dist/lib/syncIngest.d.ts +30 -0
  212. package/dist/lib/syncIngest.js +175 -0
  213. package/dist/lib/syncIngestLaunchd.d.ts +8 -0
  214. package/dist/lib/syncIngestLaunchd.js +93 -0
  215. package/dist/lib/syncIngestStartup.d.ts +5 -0
  216. package/dist/lib/syncIngestStartup.js +29 -0
  217. package/dist/lib/syncIngestSystemd.d.ts +10 -0
  218. package/dist/lib/syncIngestSystemd.js +97 -0
  219. package/dist/lib/syncIngestTimer.d.ts +8 -0
  220. package/dist/lib/syncIngestTimer.js +27 -0
  221. package/dist/lib/syncIngestTimerCommand.d.ts +7 -0
  222. package/dist/lib/syncIngestTimerCommand.js +83 -0
  223. package/dist/lib/syncLock.d.ts +6 -0
  224. package/dist/lib/syncLock.js +74 -0
  225. package/dist/lib/syncSnapshot.d.ts +32 -0
  226. package/dist/lib/syncSnapshot.js +188 -0
  227. package/dist/lib/syncStaging.d.ts +79 -0
  228. package/dist/lib/syncStaging.js +237 -0
  229. package/dist/lib/tagsAddCommand.d.ts +8 -0
  230. package/dist/lib/tagsAddCommand.js +18 -0
  231. package/dist/lib/tagsCommand.d.ts +4 -0
  232. package/dist/lib/tagsCommand.js +16 -0
  233. package/dist/lib/timelineCommand.d.ts +7 -0
  234. package/dist/lib/timelineCommand.js +49 -0
  235. package/dist/lib/traceCommand.d.ts +6 -0
  236. package/dist/lib/traceCommand.js +39 -0
  237. package/dist/lib/traverseCommand.d.ts +6 -0
  238. package/dist/lib/traverseCommand.js +58 -0
  239. package/dist/lib/updateCommand.d.ts +13 -0
  240. package/dist/lib/updateCommand.js +67 -0
  241. package/dist/lib/updateStatusCommand.d.ts +5 -0
  242. package/dist/lib/updateStatusCommand.js +38 -0
  243. package/dist/lib/webAddCommand.d.ts +8 -0
  244. package/dist/lib/webAddCommand.js +55 -0
  245. package/dist/lib/webBuildCommand.d.ts +10 -0
  246. package/dist/lib/webBuildCommand.js +65 -0
  247. package/dist/lib/webBuildIndexCommand.d.ts +8 -0
  248. package/dist/lib/webBuildIndexCommand.js +37 -0
  249. package/dist/lib/webIndex.js +0 -1
  250. package/dist/lib/webIngestCommand.d.ts +11 -0
  251. package/dist/lib/webIngestCommand.js +51 -0
  252. package/dist/lib/webInitCommand.d.ts +9 -0
  253. package/dist/lib/webInitCommand.js +167 -0
  254. package/dist/lib/webRemoveCommand.d.ts +5 -0
  255. package/dist/lib/webRemoveCommand.js +41 -0
  256. package/dist/lib/webStatusCommand.d.ts +5 -0
  257. package/dist/lib/webStatusCommand.js +94 -0
  258. package/dist/lib/webUpdateCommand.d.ts +7 -0
  259. package/dist/lib/webUpdateCommand.js +72 -0
  260. package/dist/lib/workingSetCommand.d.ts +6 -0
  261. package/dist/lib/workingSetCommand.js +37 -0
  262. package/dist/sandbox/client.js +1 -1
  263. package/dist/sandbox/manager.js +1 -14
  264. package/dist/sandbox/server.js +3 -5
  265. package/package.json +6 -2
@@ -0,0 +1,66 @@
1
+ /**
2
+ * CLI handlers for inline DB-blob attachments (v5.12).
3
+ *
4
+ * gnosys attach <file> --memory <id> store bytes inline on a memory
5
+ * gnosys get-attachment <id> [--out path] retrieve the stored bytes
6
+ *
7
+ * Inline attachments live in the memory row, so they ride the normal sync
8
+ * rail to other machines and a remote/dockerized server.
9
+ */
10
+ import { GnosysDB } from "./db.js";
11
+ export async function runAttachCommand(filePath, opts) {
12
+ const db = GnosysDB.openCentral();
13
+ try {
14
+ if (!db.isAvailable()) {
15
+ console.error("Database not available.");
16
+ process.exitCode = 1;
17
+ return;
18
+ }
19
+ const { attachFileToMemory } = await import("./attachments.js");
20
+ const result = await attachFileToMemory(db, opts.memory, filePath);
21
+ const sizeKb = (result.sizeBytes / 1024).toFixed(1);
22
+ const verb = result.unchanged ? "Already attached (no change)" : "Attached";
23
+ console.log(`${verb}: ${result.name} (${result.mime}, ${sizeKb} KB) → ${opts.memory}`);
24
+ }
25
+ catch (err) {
26
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
27
+ process.exitCode = 1;
28
+ }
29
+ finally {
30
+ db.close();
31
+ }
32
+ }
33
+ export async function runGetAttachmentCommand(memoryId, opts) {
34
+ const db = GnosysDB.openCentral();
35
+ try {
36
+ if (!db.isAvailable()) {
37
+ console.error("Database not available.");
38
+ process.exitCode = 1;
39
+ return;
40
+ }
41
+ const { getMemoryAttachment } = await import("./attachments.js");
42
+ const att = getMemoryAttachment(db, memoryId);
43
+ if (!att) {
44
+ console.error(`No attachment found on memory: ${memoryId}`);
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+ if (opts.out) {
49
+ const { writeFile } = await import("fs/promises");
50
+ await writeFile(opts.out, att.data);
51
+ console.log(`Wrote ${att.name} (${att.mime}, ${att.data.length} bytes) to ${opts.out}`);
52
+ }
53
+ else {
54
+ // No output path: print metadata + base64 so it can be piped/redirected.
55
+ console.error(`${att.name} (${att.mime}, ${att.data.length} bytes)`);
56
+ console.log(att.data.toString("base64"));
57
+ }
58
+ }
59
+ catch (err) {
60
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
61
+ process.exitCode = 1;
62
+ }
63
+ finally {
64
+ db.close();
65
+ }
66
+ }
@@ -1,9 +1,15 @@
1
1
  /**
2
2
  * Gnosys Attachments — File attachment management for multimodal ingestion.
3
3
  *
4
- * Stores binary files in .gnosys/attachments/<uuid>.<ext> with a JSON manifest
5
- * at .gnosys/attachments/attachments.json for tracking metadata and memory links.
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
  */
12
+ import type { GnosysDB } from "./db.js";
7
13
  export interface AttachmentRecord {
8
14
  uuid: string;
9
15
  originalName: string;
@@ -14,6 +20,8 @@ export interface AttachmentRecord {
14
20
  createdAt: string;
15
21
  memoryIds: string[];
16
22
  }
23
+ /** Infer a MIME type from a file path's extension. */
24
+ export declare function inferMimeType(filePath: string): string;
17
25
  /**
18
26
  * Initialize the attachments directory and manifest in a store.
19
27
  * Safe to call multiple times — creates only if missing.
@@ -40,3 +48,36 @@ export declare function getAttachmentPath(storePath: string, uuid: string, ext:
40
48
  * tracks which memories reference it.
41
49
  */
42
50
  export declare function linkMemoryToAttachment(storePath: string, uuid: string, memoryId: string): Promise<void>;
51
+ /**
52
+ * Maximum size for an inline DB-blob attachment. Larger files should use the
53
+ * filesystem path (`gnosys ingest`) so the synced central DB stays lean.
54
+ */
55
+ export declare const MAX_INLINE_ATTACHMENT_BYTES: number;
56
+ export interface InlineAttachment {
57
+ /** Raw file bytes. */
58
+ data: Buffer;
59
+ /** MIME type, e.g. "image/svg+xml". */
60
+ mime: string;
61
+ /** Original filename, e.g. "prospero-logo.svg". */
62
+ name: string;
63
+ /** Size in bytes. */
64
+ sizeBytes: number;
65
+ }
66
+ export interface AttachToMemoryResult {
67
+ memoryId: string;
68
+ name: string;
69
+ mime: string;
70
+ sizeBytes: number;
71
+ /** True when the file was identical to what was already attached (no write). */
72
+ unchanged: boolean;
73
+ }
74
+ /**
75
+ * Read a file and store its bytes inline on a memory row (attachment_data).
76
+ * Enforces the size cap and skips the write if the same bytes are already
77
+ * attached (content-hash dedup). Bumps `modified` so remote sync picks it up.
78
+ */
79
+ export declare function attachFileToMemory(db: GnosysDB, memoryId: string, filePath: string): Promise<AttachToMemoryResult>;
80
+ /** Return the inline attachment stored on a memory row, or null if none. */
81
+ export declare function getMemoryAttachment(db: GnosysDB, memoryId: string): InlineAttachment | null;
82
+ /** Remove an inline attachment from a memory row (keeps the memory itself). */
83
+ export declare function detachFromMemory(db: GnosysDB, memoryId: string): boolean;
@@ -1,8 +1,13 @@
1
1
  /**
2
2
  * Gnosys Attachments — File attachment management for multimodal ingestion.
3
3
  *
4
- * Stores binary files in .gnosys/attachments/<uuid>.<ext> with a JSON manifest
5
- * at .gnosys/attachments/attachments.json for tracking metadata and memory links.
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
+ }
@@ -71,7 +71,10 @@ async function transcribeWithOpenAI(audioBuffer, fileName, mimeType, apiKey, opt
71
71
  async function transcribeWithLocal(filePath, options) {
72
72
  let pipeline;
73
73
  try {
74
- // Dynamic import — @huggingface/transformers is an optional dependency
74
+ // Dynamic import — @huggingface/transformers is an optional dependency.
75
+ // Cast to any so TypeScript does not require the module's type declarations
76
+ // at compile time (the package is optional; CI and clean checkouts may not
77
+ // have it installed when running `tsc` / `npm run build`).
75
78
  const transformers = await import("@huggingface/transformers");
76
79
  pipeline = transformers.pipeline;
77
80
  }
@@ -0,0 +1,7 @@
1
+ export type AuditCommandOptions = {
2
+ days: string;
3
+ operation?: string;
4
+ limit?: string;
5
+ json?: boolean;
6
+ };
7
+ export declare function runAuditCommand(opts: AuditCommandOptions): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import { GnosysDB } from "./db.js";
2
+ export async function runAuditCommand(opts) {
3
+ const { readAuditFromDb, formatAuditTimeline } = await import("./audit.js");
4
+ let centralDb = null;
5
+ try {
6
+ centralDb = GnosysDB.openCentral();
7
+ if (!centralDb.isAvailable()) {
8
+ console.error("Central DB unavailable.");
9
+ process.exitCode = 1;
10
+ return;
11
+ }
12
+ const entries = readAuditFromDb(centralDb, {
13
+ days: parseInt(opts.days, 10),
14
+ operation: opts.operation,
15
+ limit: opts.limit ? parseInt(opts.limit, 10) : undefined,
16
+ });
17
+ if (opts.json) {
18
+ console.log(JSON.stringify(entries, null, 2));
19
+ }
20
+ else {
21
+ console.log(formatAuditTimeline(entries));
22
+ }
23
+ }
24
+ finally {
25
+ centralDb?.close();
26
+ }
27
+ }
@@ -0,0 +1,6 @@
1
+ export type BackupCommandOptions = {
2
+ output?: string;
3
+ to?: string;
4
+ json?: boolean;
5
+ };
6
+ export declare function runBackupCommand(opts: BackupCommandOptions): Promise<void>;
@@ -0,0 +1,54 @@
1
+ import { copyFileSync, existsSync } from "fs";
2
+ import path from "path";
3
+ import { GnosysDB } from "./db.js";
4
+ export async function runBackupCommand(opts) {
5
+ let centralDb = null;
6
+ try {
7
+ centralDb = GnosysDB.openCentral();
8
+ if (!centralDb.isAvailable()) {
9
+ console.error("Central DB not available (better-sqlite3 missing).");
10
+ process.exitCode = 1;
11
+ return;
12
+ }
13
+ const outputDir = opts.to || opts.output;
14
+ const backupPath = await centralDb.backup(outputDir);
15
+ const counts = centralDb.getMemoryCount();
16
+ const projectCount = centralDb.getAllProjects().length;
17
+ const centralDir = GnosysDB.getCentralDbDir();
18
+ const copiedFiles = [backupPath];
19
+ const backupDir = path.dirname(backupPath);
20
+ const sandboxLog = path.join(centralDir, "sandbox", "sandbox.log");
21
+ if (existsSync(sandboxLog)) {
22
+ const logDest = path.join(backupDir, "sandbox.log.bak");
23
+ copyFileSync(sandboxLog, logDest);
24
+ copiedFiles.push(logDest);
25
+ }
26
+ if (opts.json) {
27
+ console.log(JSON.stringify({
28
+ ok: true, backupPath, memories: counts.total,
29
+ active: counts.active, archived: counts.archived,
30
+ projects: projectCount, files: copiedFiles,
31
+ }));
32
+ }
33
+ else {
34
+ console.log(`Backup created: ${backupPath}`);
35
+ console.log(` Memories: ${counts.total} (${counts.active} active, ${counts.archived} archived)`);
36
+ console.log(` Projects: ${projectCount}`);
37
+ if (copiedFiles.length > 1)
38
+ console.log(` Additional files: ${copiedFiles.length - 1}`);
39
+ }
40
+ }
41
+ catch (err) {
42
+ if (opts.json) {
43
+ console.log(JSON.stringify({ ok: false, error: err instanceof Error ? err.message : String(err) }));
44
+ }
45
+ else {
46
+ console.error(`Backup failed: ${err instanceof Error ? err.message : err}`);
47
+ }
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+ finally {
52
+ centralDb?.close();
53
+ }
54
+ }
@@ -0,0 +1,15 @@
1
+ import type { GnosysResolver } from "./resolver.js";
2
+ export type BootstrapCommandOptions = {
3
+ pattern?: string[];
4
+ skipExisting?: boolean;
5
+ category: string;
6
+ author: string;
7
+ authority: string;
8
+ confidence: string;
9
+ preserveFrontmatter?: boolean;
10
+ dryRun?: boolean;
11
+ store?: string;
12
+ };
13
+ type GetResolver = () => Promise<GnosysResolver>;
14
+ export declare function runBootstrapCommand(getResolver: GetResolver, sourceDir: string, opts: BootstrapCommandOptions): Promise<void>;
15
+ export {};
@@ -0,0 +1,51 @@
1
+ export async function runBootstrapCommand(getResolver, sourceDir, opts) {
2
+ const resolver = await getResolver();
3
+ const writeTarget = resolver.getWriteTarget(opts.store || undefined);
4
+ if (!writeTarget) {
5
+ console.error("No writable store found.");
6
+ process.exit(1);
7
+ }
8
+ // Show what we'll scan
9
+ const { bootstrap, discoverFiles } = await import("./bootstrap.js");
10
+ const files = await discoverFiles(sourceDir, opts.pattern);
11
+ console.log(`Found ${files.length} files in ${sourceDir}\n`);
12
+ if (files.length === 0) {
13
+ console.log("Nothing to import.");
14
+ return;
15
+ }
16
+ const result = await bootstrap(writeTarget.store, {
17
+ sourceDir,
18
+ patterns: opts.pattern,
19
+ skipExisting: opts.skipExisting,
20
+ defaultCategory: opts.category,
21
+ defaultAuthor: opts.author,
22
+ defaultAuthority: opts.authority,
23
+ defaultConfidence: parseFloat(opts.confidence),
24
+ preserveFrontmatter: opts.preserveFrontmatter,
25
+ dryRun: opts.dryRun,
26
+ });
27
+ const mode = opts.dryRun ? "DRY RUN" : "COMPLETE";
28
+ console.log(`\nBootstrap ${mode}:`);
29
+ console.log(` Scanned: ${result.totalScanned}`);
30
+ console.log(` ${opts.dryRun ? "Would import" : "Imported"}: ${result.imported.length}`);
31
+ console.log(` Skipped: ${result.skipped.length}`);
32
+ console.log(` Failed: ${result.failed.length}`);
33
+ if (result.imported.length > 0) {
34
+ console.log(`\n${opts.dryRun ? "Would import" : "Imported"}:`);
35
+ for (const f of result.imported) {
36
+ console.log(` + ${f}`);
37
+ }
38
+ }
39
+ if (result.skipped.length > 0) {
40
+ console.log(`\nSkipped (already exist):`);
41
+ for (const f of result.skipped) {
42
+ console.log(` ⏭ ${f}`);
43
+ }
44
+ }
45
+ if (result.failed.length > 0) {
46
+ console.log(`\nFailed:`);
47
+ for (const f of result.failed) {
48
+ console.log(` ❌ ${f.path}: ${f.error}`);
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,7 @@
1
+ export type BriefingCommandOptions = {
2
+ project?: string;
3
+ all?: boolean;
4
+ directory?: string;
5
+ json: boolean;
6
+ };
7
+ export declare function runBriefingCommand(projectNameOrId: string | undefined, opts: BriefingCommandOptions): Promise<void>;
@@ -0,0 +1,92 @@
1
+ import { GnosysDB } from "./db.js";
2
+ export async function runBriefingCommand(projectNameOrId, opts) {
3
+ let centralDb = null;
4
+ try {
5
+ centralDb = GnosysDB.openCentral();
6
+ if (!centralDb.isAvailable()) {
7
+ console.error("Central DB not available.");
8
+ process.exitCode = 1;
9
+ return;
10
+ }
11
+ const { generateBriefing, generateAllBriefings, detectCurrentProject } = await import("./federated.js");
12
+ if (opts.all) {
13
+ const briefings = generateAllBriefings(centralDb);
14
+ if (opts.json) {
15
+ console.log(JSON.stringify({ count: briefings.length, briefings }, null, 2));
16
+ }
17
+ else {
18
+ if (briefings.length === 0) {
19
+ console.log("No projects registered.");
20
+ return;
21
+ }
22
+ for (const b of briefings) {
23
+ console.log(`\n## ${b.projectName}`);
24
+ console.log(b.summary);
25
+ }
26
+ }
27
+ return;
28
+ }
29
+ // v5.7.0: accept project name as positional argument in addition to --project <id>.
30
+ // Resolution order: positional name → --project flag → cwd auto-detect.
31
+ let pid = opts.project ?? null;
32
+ if (!pid && projectNameOrId) {
33
+ const byId = centralDb.getProject(projectNameOrId);
34
+ if (byId) {
35
+ pid = byId.id;
36
+ }
37
+ else {
38
+ const all = centralDb.getAllProjects();
39
+ const byName = all.find((p) => p.name === projectNameOrId);
40
+ if (byName)
41
+ pid = byName.id;
42
+ }
43
+ if (!pid) {
44
+ console.error(`Project not found: "${projectNameOrId}". Run 'gnosys projects' to list registered projects.`);
45
+ process.exitCode = 1;
46
+ return;
47
+ }
48
+ }
49
+ if (!pid)
50
+ pid = await detectCurrentProject(centralDb, opts.directory || undefined);
51
+ if (!pid) {
52
+ console.error("No project specified and none detected.");
53
+ process.exitCode = 1;
54
+ return;
55
+ }
56
+ const briefing = generateBriefing(centralDb, pid);
57
+ if (!briefing) {
58
+ console.error(`Project not found: ${pid}`);
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+ if (opts.json) {
63
+ console.log(JSON.stringify(briefing, null, 2));
64
+ }
65
+ else {
66
+ console.log(`# Briefing: ${briefing.projectName}`);
67
+ console.log(`Directory: ${briefing.workingDirectory}`);
68
+ console.log(`Active memories: ${briefing.activeMemories} / ${briefing.totalMemories}`);
69
+ console.log(`\nCategories:`);
70
+ for (const [cat, count] of Object.entries(briefing.categories).sort((a, b) => b[1] - a[1])) {
71
+ console.log(` ${cat}: ${count}`);
72
+ }
73
+ console.log(`\nRecent activity (7d):`);
74
+ if (briefing.recentActivity.length === 0) {
75
+ console.log(" None");
76
+ }
77
+ for (const r of briefing.recentActivity) {
78
+ console.log(` - ${r.title} (${r.modified})`);
79
+ }
80
+ console.log(`\nTop tags: ${briefing.topTags.slice(0, 10).map((t) => `${t.tag}(${t.count})`).join(", ") || "None"}`);
81
+ console.log(`\n${briefing.summary}`);
82
+ }
83
+ }
84
+ catch (err) {
85
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+ finally {
90
+ centralDb?.close();
91
+ }
92
+ }
@@ -0,0 +1,5 @@
1
+ export type CentralizeCommandOptions = {
2
+ to: string;
3
+ force?: boolean;
4
+ };
5
+ export declare function runCentralizeCommand(opts: CentralizeCommandOptions): Promise<void>;
@@ -0,0 +1,16 @@
1
+ import { centralizeDb } from "./centralize.js";
2
+ export async function runCentralizeCommand(opts) {
3
+ try {
4
+ const r = await centralizeDb({ to: opts.to, force: opts.force });
5
+ const mb = (r.bytes / 1024 / 1024).toFixed(1);
6
+ console.log("✓ Seeded central brain:");
7
+ console.log(` from: ${r.source}`);
8
+ console.log(` to: ${r.target} (${mb} MB)`);
9
+ console.log("");
10
+ console.log(`Run the server against it with GNOSYS_HOME=${opts.to}, or mount this dir as the container's /data volume.`);
11
+ }
12
+ catch (e) {
13
+ console.error(`centralize failed: ${e instanceof Error ? e.message : e}`);
14
+ process.exitCode = 1;
15
+ }
16
+ }
@@ -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 && current.label)
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 && current.label)
136
+ if (current?.label)
137
137
  options.push(current);
138
138
  return { prompt, options };
139
139
  }
@@ -0,0 +1,12 @@
1
+ import type { GnosysResolver } from "./resolver.js";
2
+ export type ChatCommandOptions = {
3
+ resume?: string;
4
+ list?: boolean;
5
+ search?: string;
6
+ provider?: string;
7
+ model?: string;
8
+ limit: string;
9
+ };
10
+ type GetResolver = () => Promise<GnosysResolver>;
11
+ export declare function runChatCommand(getResolver: GetResolver, opts: ChatCommandOptions): Promise<void>;
12
+ export {};
@@ -0,0 +1,46 @@
1
+ import { DEFAULT_CONFIG, loadConfig, resolveTaskModel, } from "./config.js";
2
+ export async function runChatCommand(getResolver, opts) {
3
+ const limit = parseInt(opts.limit, 10) || 20;
4
+ const chat = await import("./chat/index.js");
5
+ if (opts.list) {
6
+ chat.printSessionList(limit);
7
+ return;
8
+ }
9
+ if (opts.search) {
10
+ chat.printSearchResults(opts.search, limit);
11
+ return;
12
+ }
13
+ const resolver = await getResolver();
14
+ const stores = resolver.getStores();
15
+ const storePath = stores[0]?.path ?? process.cwd();
16
+ let cliConfig;
17
+ try {
18
+ cliConfig = await loadConfig(storePath);
19
+ }
20
+ catch {
21
+ cliConfig = DEFAULT_CONFIG;
22
+ }
23
+ // Fail-fast on missing API key before TUI render.
24
+ {
25
+ const chatTask = resolveTaskModel(cliConfig, "chat");
26
+ const provider = opts.provider ?? chatTask.provider;
27
+ if (provider !== "ollama" && provider !== "lmstudio") {
28
+ const { getApiKeyForProvider } = await import("./setup.js");
29
+ const key = await getApiKeyForProvider(provider);
30
+ if (!key) {
31
+ const { Status } = await import("./setup/ui/status.js");
32
+ const envVar = `${provider.toUpperCase()}_API_KEY`;
33
+ process.stderr.write(`${Status("fail", `no API key for ${provider} (the configured chat provider)`)}\n`);
34
+ process.stderr.write(` fix: gnosys setup pick a provider with a key, or add one\n`);
35
+ process.stderr.write(` export ${envVar}=...\n`);
36
+ process.exit(1);
37
+ }
38
+ }
39
+ }
40
+ await chat.startChat({
41
+ config: cliConfig,
42
+ resume: opts.resume,
43
+ providerName: opts.provider,
44
+ modelName: opts.model,
45
+ });
46
+ }
@@ -0,0 +1,4 @@
1
+ export type CheckCommandOptions = {
2
+ task?: string;
3
+ };
4
+ export declare function runCheckCommand(opts: CheckCommandOptions): Promise<void>;