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
package/dist/lib/dream.js CHANGED
@@ -18,10 +18,12 @@
18
18
  * - Uses cheap/local LLM (configurable, defaults to Ollama)
19
19
  */
20
20
  import os from "os";
21
- import { getLLMProvider } from "./llm.js";
21
+ import { getProviderModel } from "./config.js";
22
+ import { createProvider } from "./llm.js";
22
23
  import { notifyDesktop } from "./desktopNotify.js";
23
24
  import { syncConfidenceToDb, auditToDb } from "./dbWrite.js";
24
25
  import { logError } from "./log.js";
26
+ import { estimateCost, acquireDreamLock, estimateTokens, fingerprintMemories, memoryWatermark, readDreamState, writeDreamState, } from "./dreamRunLog.js";
25
27
  /** Layer 4 alert threshold: fire desktop notification at this many consecutive provider failures. */
26
28
  const DREAM_FAILURE_NOTIFY_THRESHOLD = 3;
27
29
  export const DEFAULT_DREAM_CONFIG = {
@@ -34,6 +36,11 @@ export const DEFAULT_DREAM_CONFIG = {
34
36
  generateSummaries: true,
35
37
  discoverRelationships: true,
36
38
  minMemories: 10,
39
+ schedule: { startHour: 2, endHour: 5 },
40
+ systemIdleMinutes: 30,
41
+ minNewMemoriesToDream: 10,
42
+ minHoursBetweenRuns: 20,
43
+ maxLLMCallsPerRun: 12,
37
44
  };
38
45
  // ─── Decay Constants ─────────────────────────────────────────────────────
39
46
  const DECAY_LAMBDA = 0.005;
@@ -46,16 +53,37 @@ export class GnosysDreamEngine {
46
53
  provider = null;
47
54
  abortRequested = false;
48
55
  startTime = 0;
49
- constructor(db, config, dreamConfig) {
56
+ trigger;
57
+ machineId;
58
+ dreamState = readDreamState();
59
+ pendingFingerprints = {};
60
+ llmCallsMade = 0;
61
+ constructor(db, config, dreamConfig, options) {
50
62
  this.db = db;
51
63
  this.config = config;
52
- this.dreamConfig = { ...DEFAULT_DREAM_CONFIG, ...dreamConfig };
64
+ this.dreamConfig = {
65
+ ...DEFAULT_DREAM_CONFIG,
66
+ ...dreamConfig,
67
+ schedule: { ...DEFAULT_DREAM_CONFIG.schedule, ...(dreamConfig?.schedule ?? {}) },
68
+ };
69
+ this.trigger = options?.trigger ?? "manual";
70
+ this.machineId = options?.machineId;
53
71
  // Initialize LLM provider for dream operations.
54
72
  // v5.4.2: Failure here is no longer silent — when dream tries to actually
55
73
  // run (in dream()), we record the unavailability to audit_log so the
56
74
  // user gets visibility (Layer 2 alert) and can react via the dashboard.
57
75
  try {
58
- this.provider = getLLMProvider(this.config, "structuring");
76
+ const provider = this.dreamConfig.provider;
77
+ let model = this.dreamConfig.model;
78
+ if (!model) {
79
+ try {
80
+ model = getProviderModel(this.config, provider);
81
+ }
82
+ catch {
83
+ model = "";
84
+ }
85
+ }
86
+ this.provider = createProvider(provider, model, this.config);
59
87
  }
60
88
  catch (err) {
61
89
  this.provider = null;
@@ -64,6 +92,136 @@ export class GnosysDreamEngine {
64
92
  }
65
93
  /** Captured at construction if getLLMProvider throws. Used in dream() to write a Layer 2 audit entry. */
66
94
  providerInitError = null;
95
+ createPhase(name) {
96
+ return {
97
+ name,
98
+ status: "ran",
99
+ durationMs: 0,
100
+ memoryIdsTouched: [],
101
+ llmCallsMade: 0,
102
+ llmCallsSkipped: 0,
103
+ estimatedInputTokens: 0,
104
+ estimatedOutputTokens: 0,
105
+ estimatedCostUsd: 0,
106
+ };
107
+ }
108
+ finishPhase(phase, startedAtMs) {
109
+ phase.durationMs = Date.now() - startedAtMs;
110
+ phase.memoryIdsTouched = Array.from(new Set(phase.memoryIdsTouched));
111
+ phase.estimatedCostUsd = Math.round(phase.estimatedCostUsd * 1_000_000) / 1_000_000;
112
+ this.checkpointFingerprints();
113
+ }
114
+ /**
115
+ * v5.12.1 crash safety: persist analyzed fingerprints at every phase
116
+ * boundary, not only in finalize(). A crash mid-run previously lost all
117
+ * pendingFingerprints, so the next run re-analyzed (and re-paid for) the
118
+ * same memory sets and could double-create summaries. Checkpointing only
119
+ * merges fingerprints — lastRunAt / watermarks remain finalize()'s job.
120
+ */
121
+ checkpointFingerprints() {
122
+ if (Object.keys(this.pendingFingerprints).length === 0)
123
+ return;
124
+ try {
125
+ writeDreamState({
126
+ ...this.dreamState,
127
+ analyzedFingerprints: {
128
+ ...this.dreamState.analyzedFingerprints,
129
+ ...this.pendingFingerprints,
130
+ },
131
+ });
132
+ }
133
+ catch {
134
+ // Best-effort: a failed checkpoint only costs re-analysis on resume.
135
+ }
136
+ }
137
+ addTouched(phase, memoryIds) {
138
+ for (const id of memoryIds) {
139
+ if (id)
140
+ phase.memoryIdsTouched.push(id);
141
+ }
142
+ }
143
+ recordLLMSkip(phase, label, reason, memoryIds = [], fingerprint) {
144
+ phase.llmCallsSkipped++;
145
+ this.llmCalls.push({
146
+ phase: phase.name,
147
+ label,
148
+ status: "skipped",
149
+ reason,
150
+ provider: this.dreamConfig.provider,
151
+ model: this.dreamConfig.model || this.provider?.model || getProviderModel(this.config, this.dreamConfig.provider),
152
+ memoryIds,
153
+ fingerprint,
154
+ estimatedInputTokens: 0,
155
+ estimatedOutputTokens: 0,
156
+ estimatedCostUsd: 0,
157
+ });
158
+ }
159
+ llmCalls = [];
160
+ async generateWithAccounting(phase, label, prompt, maxTokens, memoryIds, fingerprint) {
161
+ if (!this.provider) {
162
+ this.recordLLMSkip(phase, label, "provider unavailable", memoryIds, fingerprint);
163
+ return null;
164
+ }
165
+ if (fingerprint && (this.dreamState.analyzedFingerprints[fingerprint] || this.pendingFingerprints[fingerprint])) {
166
+ this.recordLLMSkip(phase, label, "already analyzed fingerprint", memoryIds, fingerprint);
167
+ return null;
168
+ }
169
+ if (this.llmCallsMade >= this.dreamConfig.maxLLMCallsPerRun) {
170
+ this.recordLLMSkip(phase, label, "maxLLMCallsPerRun reached", memoryIds, fingerprint);
171
+ return null;
172
+ }
173
+ const inputTokens = estimateTokens(prompt);
174
+ this.llmCallsMade++;
175
+ try {
176
+ const response = await this.provider.generate(prompt, { maxTokens });
177
+ const outputTokens = estimateTokens(response);
178
+ const cost = estimateCost(this.provider.model, inputTokens, outputTokens);
179
+ phase.llmCallsMade++;
180
+ phase.estimatedInputTokens += inputTokens;
181
+ phase.estimatedOutputTokens += outputTokens;
182
+ phase.estimatedCostUsd += cost;
183
+ this.llmCalls.push({
184
+ phase: phase.name,
185
+ label,
186
+ status: "made",
187
+ provider: this.provider.name,
188
+ model: this.provider.model,
189
+ memoryIds,
190
+ fingerprint,
191
+ estimatedInputTokens: inputTokens,
192
+ estimatedOutputTokens: outputTokens,
193
+ estimatedCostUsd: cost,
194
+ });
195
+ if (fingerprint && response) {
196
+ this.pendingFingerprints[fingerprint] = {
197
+ kind: phase.name === "relationships" ? "relationship" : phase.name === "summaries" ? "summary" : "critique",
198
+ lastAnalyzedAt: new Date().toISOString(),
199
+ memoryIds,
200
+ };
201
+ }
202
+ return response;
203
+ }
204
+ catch (err) {
205
+ phase.llmCallsMade++;
206
+ const cost = estimateCost(this.provider.model, inputTokens, 0);
207
+ phase.estimatedInputTokens += inputTokens;
208
+ phase.estimatedCostUsd += cost;
209
+ this.llmCalls.push({
210
+ phase: phase.name,
211
+ label,
212
+ status: "failed",
213
+ reason: err instanceof Error ? err.message : String(err),
214
+ provider: this.provider.name,
215
+ model: this.provider.model,
216
+ memoryIds,
217
+ fingerprint,
218
+ estimatedInputTokens: inputTokens,
219
+ estimatedOutputTokens: 0,
220
+ estimatedCostUsd: cost,
221
+ });
222
+ throw err;
223
+ }
224
+ }
67
225
  /** Expose the local DB so DreamScheduler can read designation meta. */
68
226
  getDb() {
69
227
  return this.db;
@@ -100,9 +258,16 @@ export class GnosysDreamEngine {
100
258
  async dream(onProgress) {
101
259
  this.startTime = Date.now();
102
260
  this.abortRequested = false;
261
+ this.llmCallsMade = 0;
262
+ this.llmCalls = [];
263
+ this.pendingFingerprints = {};
264
+ this.dreamState = readDreamState();
103
265
  const log = onProgress || (() => { });
266
+ const startedAt = new Date().toISOString();
104
267
  const report = {
105
- startedAt: new Date().toISOString(),
268
+ id: `dream-${Date.parse(startedAt)}-${Math.random().toString(36).slice(2, 8)}`,
269
+ trigger: this.trigger,
270
+ startedAt,
106
271
  finishedAt: "",
107
272
  durationMs: 0,
108
273
  decayUpdated: 0,
@@ -113,6 +278,27 @@ export class GnosysDreamEngine {
113
278
  duplicatesFound: 0,
114
279
  errors: [],
115
280
  aborted: false,
281
+ machine: { hostname: os.hostname(), machineId: this.machineId },
282
+ provider: this.dreamConfig.provider,
283
+ model: this.dreamConfig.model || this.provider?.model,
284
+ phases: [],
285
+ llmCalls: [],
286
+ totals: {
287
+ llmCallsMade: 0,
288
+ llmCallsSkipped: 0,
289
+ estimatedInputTokens: 0,
290
+ estimatedOutputTokens: 0,
291
+ estimatedCostUsd: 0,
292
+ },
293
+ effectiveness: {
294
+ usefulOutputScore: 0,
295
+ costPerUsefulOutput: null,
296
+ decaysApplied: 0,
297
+ summariesGenerated: 0,
298
+ summariesUpdated: 0,
299
+ reviewSuggestions: 0,
300
+ relationshipsDiscovered: 0,
301
+ },
116
302
  };
117
303
  if (!this.db.isAvailable() || !this.db.isMigrated()) {
118
304
  report.errors.push("gnosys.db not available or not migrated");
@@ -161,13 +347,21 @@ export class GnosysDreamEngine {
161
347
  }
162
348
  // ─── Phase 1: Confidence Decay Sweep ─────────────────────────────────
163
349
  log("decay", "Phase 1: Confidence decay sweep...");
350
+ const decayPhase = this.createPhase("decay");
351
+ const decayStart = Date.now();
352
+ report.phases.push(decayPhase);
164
353
  try {
165
- report.decayUpdated = this.decaySweep();
354
+ const decayResult = this.decaySweep();
355
+ report.decayUpdated = decayResult.count;
356
+ this.addTouched(decayPhase, decayResult.memoryIds);
166
357
  log("decay", `Updated ${report.decayUpdated} memories`);
167
358
  }
168
359
  catch (err) {
169
360
  report.errors.push(`Decay sweep: ${err instanceof Error ? err.message : String(err)}`);
170
361
  }
362
+ finally {
363
+ this.finishPhase(decayPhase, decayStart);
364
+ }
171
365
  let check = this.shouldStop();
172
366
  if (check.stop) {
173
367
  report.aborted = true;
@@ -177,13 +371,20 @@ export class GnosysDreamEngine {
177
371
  // ─── Phase 2: Self-Critique (Review Suggestions) ─────────────────────
178
372
  if (this.dreamConfig.selfCritique) {
179
373
  log("critique", "Phase 2: Self-critique...");
374
+ const critiquePhase = this.createPhase("critique");
375
+ const critiqueStart = Date.now();
376
+ report.phases.push(critiquePhase);
180
377
  try {
181
- report.reviewSuggestions = await this.selfCritique(log);
378
+ report.reviewSuggestions = await this.selfCritique(log, critiquePhase);
379
+ this.addTouched(critiquePhase, report.reviewSuggestions.map((s) => s.memoryId));
182
380
  log("critique", `Generated ${report.reviewSuggestions.length} review suggestions`);
183
381
  }
184
382
  catch (err) {
185
383
  report.errors.push(`Self-critique: ${err instanceof Error ? err.message : String(err)}`);
186
384
  }
385
+ finally {
386
+ this.finishPhase(critiquePhase, critiqueStart);
387
+ }
187
388
  check = this.shouldStop();
188
389
  if (check.stop) {
189
390
  report.aborted = true;
@@ -194,15 +395,22 @@ export class GnosysDreamEngine {
194
395
  // ─── Phase 3: Summary Generation ─────────────────────────────────────
195
396
  if (this.dreamConfig.generateSummaries && this.provider) {
196
397
  log("summaries", "Phase 3: Summary generation...");
398
+ const summariesPhase = this.createPhase("summaries");
399
+ const summariesStart = Date.now();
400
+ report.phases.push(summariesPhase);
197
401
  try {
198
- const summaryResult = await this.generateSummaries(log);
402
+ const summaryResult = await this.generateSummaries(log, summariesPhase);
199
403
  report.summariesGenerated = summaryResult.generated;
200
404
  report.summariesUpdated = summaryResult.updated;
405
+ this.addTouched(summariesPhase, summaryResult.memoryIds);
201
406
  log("summaries", `Generated ${summaryResult.generated}, updated ${summaryResult.updated}`);
202
407
  }
203
408
  catch (err) {
204
409
  report.errors.push(`Summary generation: ${err instanceof Error ? err.message : String(err)}`);
205
410
  }
411
+ finally {
412
+ this.finishPhase(summariesPhase, summariesStart);
413
+ }
206
414
  check = this.shouldStop();
207
415
  if (check.stop) {
208
416
  report.aborted = true;
@@ -213,19 +421,73 @@ export class GnosysDreamEngine {
213
421
  // ─── Phase 4: Relationship Discovery ─────────────────────────────────
214
422
  if (this.dreamConfig.discoverRelationships && this.provider) {
215
423
  log("relationships", "Phase 4: Relationship discovery...");
424
+ const relationshipsPhase = this.createPhase("relationships");
425
+ const relationshipsStart = Date.now();
426
+ report.phases.push(relationshipsPhase);
216
427
  try {
217
- report.relationshipsDiscovered = await this.discoverRelationships(log);
428
+ const relationshipsResult = await this.discoverRelationships(log, relationshipsPhase);
429
+ report.relationshipsDiscovered = relationshipsResult.count;
430
+ this.addTouched(relationshipsPhase, relationshipsResult.memoryIds);
218
431
  log("relationships", `Discovered ${report.relationshipsDiscovered} new relationships`);
219
432
  }
220
433
  catch (err) {
221
434
  report.errors.push(`Relationship discovery: ${err instanceof Error ? err.message : String(err)}`);
222
435
  }
436
+ finally {
437
+ this.finishPhase(relationshipsPhase, relationshipsStart);
438
+ }
223
439
  }
224
440
  return this.finalize(report);
225
441
  }
226
442
  finalize(report) {
227
443
  report.finishedAt = new Date().toISOString();
228
444
  report.durationMs = Date.now() - this.startTime;
445
+ report.llmCalls = this.llmCalls;
446
+ report.totals = this.llmCalls.reduce((totals, call) => {
447
+ if (call.status === "made" || call.status === "failed")
448
+ totals.llmCallsMade++;
449
+ if (call.status === "skipped")
450
+ totals.llmCallsSkipped++;
451
+ totals.estimatedInputTokens += call.estimatedInputTokens;
452
+ totals.estimatedOutputTokens += call.estimatedOutputTokens;
453
+ totals.estimatedCostUsd += call.estimatedCostUsd;
454
+ return totals;
455
+ }, {
456
+ llmCallsMade: 0,
457
+ llmCallsSkipped: 0,
458
+ estimatedInputTokens: 0,
459
+ estimatedOutputTokens: 0,
460
+ estimatedCostUsd: 0,
461
+ });
462
+ report.totals.estimatedCostUsd = Math.round(report.totals.estimatedCostUsd * 1_000_000) / 1_000_000;
463
+ const usefulOutputScore = report.decayUpdated +
464
+ report.summariesGenerated * 5 +
465
+ report.summariesUpdated * 3 +
466
+ report.relationshipsDiscovered * 2;
467
+ report.effectiveness = {
468
+ usefulOutputScore,
469
+ costPerUsefulOutput: usefulOutputScore > 0
470
+ ? Math.round((report.totals.estimatedCostUsd / usefulOutputScore) * 1_000_000) / 1_000_000
471
+ : null,
472
+ decaysApplied: report.decayUpdated,
473
+ summariesGenerated: report.summariesGenerated,
474
+ summariesUpdated: report.summariesUpdated,
475
+ reviewSuggestions: report.reviewSuggestions.length,
476
+ relationshipsDiscovered: report.relationshipsDiscovered,
477
+ };
478
+ const memories = this.db.isAvailable() ? this.db.getActiveMemories() : [];
479
+ const watermark = memoryWatermark(memories);
480
+ writeDreamState({
481
+ ...this.dreamState,
482
+ lastRunAt: report.finishedAt,
483
+ lastSuccessfulRunAt: report.errors.length === 0 && !report.aborted ? report.finishedAt : this.dreamState.lastSuccessfulRunAt,
484
+ lastMemoryCount: watermark.count,
485
+ lastMemoryMaxModified: watermark.maxModified,
486
+ analyzedFingerprints: {
487
+ ...this.dreamState.analyzedFingerprints,
488
+ ...this.pendingFingerprints,
489
+ },
490
+ });
229
491
  // v5.4.2: A run is considered "successful with LLM work" if any of the
230
492
  // LLM-dependent counters moved. Resetting the consecutive-failure count
231
493
  // here ensures Layer 4 doesn't keep firing once dream is healthy again.
@@ -241,6 +503,10 @@ export class GnosysDreamEngine {
241
503
  summariesGenerated: report.summariesGenerated,
242
504
  reviewSuggestions: report.reviewSuggestions.length,
243
505
  relationshipsDiscovered: report.relationshipsDiscovered,
506
+ llmCallsMade: report.totals.llmCallsMade,
507
+ llmCallsSkipped: report.totals.llmCallsSkipped,
508
+ estimatedCostUsd: report.totals.estimatedCostUsd,
509
+ usefulOutputScore: report.effectiveness.usefulOutputScore,
244
510
  errors: report.errors.length,
245
511
  aborted: report.aborted,
246
512
  providerUnreachable: !this.provider,
@@ -257,9 +523,9 @@ export class GnosysDreamEngine {
257
523
  */
258
524
  decaySweep() {
259
525
  const now = new Date();
260
- const today = now.toISOString().split("T")[0];
261
526
  const memories = this.db.getActiveMemories();
262
527
  let updated = 0;
528
+ const memoryIds = [];
263
529
  for (const mem of memories) {
264
530
  const lastReinforced = mem.last_reinforced || mem.modified || mem.created;
265
531
  const lastDate = new Date(lastReinforced);
@@ -272,16 +538,17 @@ export class GnosysDreamEngine {
272
538
  if (Math.abs(rounded - mem.confidence) > 0.01) {
273
539
  syncConfidenceToDb(this.db, mem.id, rounded);
274
540
  updated++;
541
+ memoryIds.push(mem.id);
275
542
  }
276
543
  }
277
- return updated;
544
+ return { count: updated, memoryIds };
278
545
  }
279
546
  // ─── Phase 2: Self-Critique ────────────────────────────────────────────
280
547
  /**
281
548
  * Score memories and generate review suggestions.
282
549
  * NEVER deletes or archives — only flags for human review.
283
550
  */
284
- async selfCritique(log) {
551
+ async selfCritique(log, phase) {
285
552
  const suggestions = [];
286
553
  const memories = this.db.getActiveMemories();
287
554
  for (const mem of memories) {
@@ -308,7 +575,7 @@ export class GnosysDreamEngine {
308
575
  if (check.stop)
309
576
  break;
310
577
  try {
311
- const llmSuggestion = await this.llmCritique(mem);
578
+ const llmSuggestion = await this.llmCritique(mem, phase);
312
579
  if (llmSuggestion) {
313
580
  suggestions.push(llmSuggestion);
314
581
  }
@@ -374,9 +641,10 @@ export class GnosysDreamEngine {
374
641
  /**
375
642
  * LLM-based critique for borderline memories.
376
643
  */
377
- async llmCritique(mem) {
644
+ async llmCritique(mem, phase) {
378
645
  if (!this.provider)
379
646
  return null;
647
+ const fingerprint = fingerprintMemories("critique", [mem]);
380
648
  const prompt = `You are a knowledge management quality reviewer. Evaluate this memory and decide if it needs attention.
381
649
 
382
650
  Title: ${mem.title}
@@ -395,7 +663,9 @@ Respond with ONLY one of these JSON objects (no explanation):
395
663
  - {"action": "needs-update", "reason": "..."} if content seems outdated
396
664
  - {"action": "consider-merge", "reason": "..."} if it seems to overlap with other common knowledge`;
397
665
  try {
398
- const response = await this.provider.generate(prompt, { maxTokens: 200 });
666
+ const response = await this.generateWithAccounting(phase, `critique:${mem.id}`, prompt, 200, [mem.id], fingerprint);
667
+ if (!response)
668
+ return null;
399
669
  const jsonMatch = response.match(/\{[^}]+\}/);
400
670
  if (!jsonMatch)
401
671
  return null;
@@ -429,12 +699,13 @@ Respond with ONLY one of these JSON objects (no explanation):
429
699
  * Generate or update hierarchical summaries per category.
430
700
  * Uses LLM to synthesize category-level overviews.
431
701
  */
432
- async generateSummaries(log) {
702
+ async generateSummaries(log, phase) {
433
703
  if (!this.provider)
434
- return { generated: 0, updated: 0 };
704
+ return { generated: 0, updated: 0, memoryIds: [] };
435
705
  const categories = this.db.getCategories();
436
706
  let generated = 0;
437
707
  let updated = 0;
708
+ const touched = [];
438
709
  for (const category of categories) {
439
710
  const check = this.shouldStop();
440
711
  if (check.stop)
@@ -449,12 +720,15 @@ Respond with ONLY one of these JSON objects (no explanation):
449
720
  const currentIds = memories.map((m) => m.id);
450
721
  const unchanged = existingIds.length === currentIds.length &&
451
722
  existingIds.every((id) => currentIds.includes(id));
452
- if (unchanged)
723
+ if (unchanged) {
724
+ phase.llmCallsSkipped++;
725
+ phase.reason = phase.reason || "unchanged summaries skipped";
453
726
  continue; // No new memories in this category
727
+ }
454
728
  }
455
729
  log("summaries", `Summarizing ${category} (${memories.length} memories)...`);
456
730
  try {
457
- const summary = await this.summarizeCategory(category, memories);
731
+ const summary = await this.summarizeCategory(category, memories, phase);
458
732
  if (summary) {
459
733
  const today = new Date().toISOString().split("T")[0];
460
734
  const id = existing?.id || `summary-${category}-${today}`;
@@ -473,18 +747,19 @@ Respond with ONLY one of these JSON objects (no explanation):
473
747
  else {
474
748
  generated++;
475
749
  }
750
+ touched.push(...memories.map((m) => m.id));
476
751
  }
477
752
  }
478
753
  catch (err) {
479
754
  log("summaries", `Failed to summarize ${category}: ${err instanceof Error ? err.message : String(err)}`);
480
755
  }
481
756
  }
482
- return { generated, updated };
757
+ return { generated, updated, memoryIds: touched };
483
758
  }
484
759
  /**
485
760
  * Use LLM to generate a category summary.
486
761
  */
487
- async summarizeCategory(category, memories) {
762
+ async summarizeCategory(category, memories, phase) {
488
763
  if (!this.provider)
489
764
  return null;
490
765
  // Build context from memories (truncate to fit context window)
@@ -506,7 +781,7 @@ ${memoryTexts}
506
781
 
507
782
  Category summary:`;
508
783
  try {
509
- return await this.provider.generate(prompt, { maxTokens: 1024 });
784
+ return await this.generateWithAccounting(phase, `summary:${category}`, prompt, 1024, memories.map((m) => m.id), fingerprintMemories("summary", memories));
510
785
  }
511
786
  catch {
512
787
  return null;
@@ -517,13 +792,14 @@ Category summary:`;
517
792
  * Use LLM to discover relationships between memories.
518
793
  * Only creates new edges — never removes existing ones.
519
794
  */
520
- async discoverRelationships(log) {
795
+ async discoverRelationships(log, phase) {
521
796
  if (!this.provider)
522
- return 0;
797
+ return { count: 0, memoryIds: [] };
523
798
  const memories = this.db.getActiveMemories();
524
799
  if (memories.length < 3)
525
- return 0;
800
+ return { count: 0, memoryIds: [] };
526
801
  let discovered = 0;
802
+ const touched = new Set();
527
803
  const today = new Date().toISOString().split("T")[0];
528
804
  // Get existing relationships to avoid duplicates
529
805
  const existingPairs = new Set();
@@ -548,7 +824,7 @@ Category summary:`;
548
824
  const batchTitles = batch.map((m) => `[${m.id}] ${m.title}`).join(", ");
549
825
  log("relationships", `Analyzing relationships for: ${batchTitles}`);
550
826
  try {
551
- const relationships = await this.findRelationships(batch, memoryIndex);
827
+ const relationships = await this.findRelationships(batch, memoryIndex, phase);
552
828
  for (const rel of relationships) {
553
829
  const key = `${rel.source_id}→${rel.target_id}→${rel.rel_type}`;
554
830
  if (existingPairs.has(key))
@@ -563,18 +839,20 @@ Category summary:`;
563
839
  });
564
840
  existingPairs.add(key);
565
841
  discovered++;
842
+ touched.add(rel.source_id);
843
+ touched.add(rel.target_id);
566
844
  }
567
845
  }
568
846
  catch (err) {
569
847
  log("relationships", `Failed for batch: ${err instanceof Error ? err.message : String(err)}`);
570
848
  }
571
849
  }
572
- return discovered;
850
+ return { count: discovered, memoryIds: Array.from(touched) };
573
851
  }
574
852
  /**
575
853
  * Use LLM to find relationships for a batch of source memories.
576
854
  */
577
- async findRelationships(sources, memoryIndex) {
855
+ async findRelationships(sources, memoryIndex, phase) {
578
856
  if (!this.provider)
579
857
  return [];
580
858
  const sourceContext = sources
@@ -594,7 +872,9 @@ For each relationship found, output a JSON array of objects with: source_id, tar
594
872
  Only output relationships with confidence >= 0.7. Do NOT create self-referencing relationships.
595
873
  Output ONLY the JSON array, no explanation.`;
596
874
  try {
597
- const response = await this.provider.generate(prompt, { maxTokens: 1024 });
875
+ const response = await this.generateWithAccounting(phase, `relationships:${sources.map((s) => s.id).join(",")}`, prompt, 1024, sources.map((s) => s.id), fingerprintMemories("relationship", sources));
876
+ if (!response)
877
+ return [];
598
878
  // Extract JSON array from response
599
879
  const jsonMatch = response.match(/\[[\s\S]*\]/);
600
880
  if (!jsonMatch)
@@ -730,6 +1010,15 @@ export class DreamScheduler {
730
1010
  const idleMs = Date.now() - this.lastActivity;
731
1011
  const idleMinutes = idleMs / 60_000;
732
1012
  if (idleMinutes >= this.config.idleMinutes) {
1013
+ // v5.12.1: the in-memory `running` flag does not survive a sandbox
1014
+ // restart and cannot see a concurrent manual `gnosys dream`. Tie the
1015
+ // scheduler to the same cross-process file lock the CLI uses.
1016
+ const lock = acquireDreamLock();
1017
+ if (!lock.acquired) {
1018
+ console.error(`[dream] scheduler skipped: ${lock.reason}`);
1019
+ this.lastActivity = Date.now(); // back off a full idle window
1020
+ return;
1021
+ }
733
1022
  this.running = true;
734
1023
  try {
735
1024
  this.currentDream = this.engine.dream((phase, detail) => {
@@ -746,6 +1035,7 @@ export class DreamScheduler {
746
1035
  this.running = false;
747
1036
  this.currentDream = null;
748
1037
  this.lastActivity = Date.now(); // Reset idle timer after dream
1038
+ lock.release();
749
1039
  }
750
1040
  }
751
1041
  }
@@ -769,7 +1059,7 @@ export function formatDreamReport(report) {
769
1059
  lines.push(`Started: ${report.startedAt}`);
770
1060
  lines.push(`Finished: ${report.finishedAt}`);
771
1061
  if (report.aborted) {
772
- lines.push(`⚠ Aborted: ${report.abortReason}`);
1062
+ lines.push(`Aborted: ${report.abortReason}`);
773
1063
  }
774
1064
  lines.push("");
775
1065
  lines.push("Results:");
@@ -778,6 +1068,10 @@ export function formatDreamReport(report) {
778
1068
  lines.push(` Summaries updated: ${report.summariesUpdated}`);
779
1069
  lines.push(` Relationships discovered: ${report.relationshipsDiscovered}`);
780
1070
  lines.push(` Duplicates flagged: ${report.duplicatesFound}`);
1071
+ if (report.totals) {
1072
+ lines.push(` LLM calls: ${report.totals.llmCallsMade} made, ${report.totals.llmCallsSkipped} skipped`);
1073
+ lines.push(` Estimated cost: $${report.totals.estimatedCostUsd.toFixed(6)}`);
1074
+ }
781
1075
  lines.push("");
782
1076
  if (report.reviewSuggestions.length > 0) {
783
1077
  lines.push(`Review Suggestions (${report.reviewSuggestions.length}):`);
@@ -0,0 +1,10 @@
1
+ export type DreamCommandOptions = {
2
+ maxRuntime?: string;
3
+ critique?: boolean;
4
+ summaries?: boolean;
5
+ relationships?: boolean;
6
+ json?: boolean;
7
+ force?: boolean;
8
+ scheduled?: boolean;
9
+ };
10
+ export declare function runDreamCommand(opts: DreamCommandOptions): Promise<void>;