gnosys 5.11.4 → 5.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/dist/cli.js +324 -5150
  2. package/dist/index.js +364 -235
  3. package/dist/lib/addCommand.d.ts +9 -0
  4. package/dist/lib/addCommand.js +103 -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/askCommand.d.ts +13 -0
  12. package/dist/lib/askCommand.js +145 -0
  13. package/dist/lib/audioExtract.js +4 -1
  14. package/dist/lib/auditCommand.d.ts +7 -0
  15. package/dist/lib/auditCommand.js +27 -0
  16. package/dist/lib/backupCommand.d.ts +6 -0
  17. package/dist/lib/backupCommand.js +54 -0
  18. package/dist/lib/bootstrapCommand.d.ts +15 -0
  19. package/dist/lib/bootstrapCommand.js +51 -0
  20. package/dist/lib/briefingCommand.d.ts +7 -0
  21. package/dist/lib/briefingCommand.js +92 -0
  22. package/dist/lib/centralizeCommand.d.ts +5 -0
  23. package/dist/lib/centralizeCommand.js +16 -0
  24. package/dist/lib/chatCommand.d.ts +12 -0
  25. package/dist/lib/chatCommand.js +46 -0
  26. package/dist/lib/checkCommand.d.ts +4 -0
  27. package/dist/lib/checkCommand.js +133 -0
  28. package/dist/lib/clientReadOverlay.d.ts +27 -0
  29. package/dist/lib/clientReadOverlay.js +73 -0
  30. package/dist/lib/clientReadResolve.d.ts +32 -0
  31. package/dist/lib/clientReadResolve.js +84 -0
  32. package/dist/lib/commitContextCommand.d.ts +9 -0
  33. package/dist/lib/commitContextCommand.js +142 -0
  34. package/dist/lib/config.d.ts +43 -3
  35. package/dist/lib/config.js +58 -57
  36. package/dist/lib/configCommand.d.ts +10 -0
  37. package/dist/lib/configCommand.js +321 -0
  38. package/dist/lib/connectCommand.d.ts +8 -0
  39. package/dist/lib/connectCommand.js +19 -0
  40. package/dist/lib/db.d.ts +52 -0
  41. package/dist/lib/db.js +169 -1
  42. package/dist/lib/dearchiveCommand.d.ts +7 -0
  43. package/dist/lib/dearchiveCommand.js +41 -0
  44. package/dist/lib/discoverCommand.d.ts +9 -0
  45. package/dist/lib/discoverCommand.js +87 -0
  46. package/dist/lib/doctorCommand.d.ts +6 -0
  47. package/dist/lib/doctorCommand.js +256 -0
  48. package/dist/lib/dream.d.ts +42 -2
  49. package/dist/lib/dream.js +290 -30
  50. package/dist/lib/dreamCommand.d.ts +10 -0
  51. package/dist/lib/dreamCommand.js +195 -0
  52. package/dist/lib/dreamLaunchd.d.ts +2 -0
  53. package/dist/lib/dreamLaunchd.js +72 -0
  54. package/dist/lib/dreamLogCommand.d.ts +10 -0
  55. package/dist/lib/dreamLogCommand.js +58 -0
  56. package/dist/lib/dreamReport.d.ts +7 -0
  57. package/dist/lib/dreamReport.js +114 -0
  58. package/dist/lib/dreamRunLog.d.ts +121 -0
  59. package/dist/lib/dreamRunLog.js +212 -0
  60. package/dist/lib/embeddings.js +3 -0
  61. package/dist/lib/exportCommand.d.ts +18 -0
  62. package/dist/lib/exportCommand.js +101 -0
  63. package/dist/lib/fsearchCommand.d.ts +8 -0
  64. package/dist/lib/fsearchCommand.js +44 -0
  65. package/dist/lib/graphCommand.d.ts +4 -0
  66. package/dist/lib/graphCommand.js +68 -0
  67. package/dist/lib/helperGenerateCommand.d.ts +5 -0
  68. package/dist/lib/helperGenerateCommand.js +27 -0
  69. package/dist/lib/historyCommand.d.ts +5 -0
  70. package/dist/lib/historyCommand.js +51 -0
  71. package/dist/lib/hybridSearchCommand.d.ts +12 -0
  72. package/dist/lib/hybridSearchCommand.js +95 -0
  73. package/dist/lib/importCommand.d.ts +16 -0
  74. package/dist/lib/importCommand.js +89 -0
  75. package/dist/lib/importProjectCommand.d.ts +6 -0
  76. package/dist/lib/importProjectCommand.js +43 -0
  77. package/dist/lib/ingestCommand.d.ts +13 -0
  78. package/dist/lib/ingestCommand.js +95 -0
  79. package/dist/lib/installOutput.d.ts +36 -0
  80. package/dist/lib/installOutput.js +55 -0
  81. package/dist/lib/lensCommand.d.ts +20 -0
  82. package/dist/lib/lensCommand.js +61 -0
  83. package/dist/lib/lensing.d.ts +1 -0
  84. package/dist/lib/lensing.js +50 -9
  85. package/dist/lib/linksCommand.d.ts +7 -0
  86. package/dist/lib/linksCommand.js +48 -0
  87. package/dist/lib/listCommand.d.ts +8 -0
  88. package/dist/lib/listCommand.js +74 -0
  89. package/dist/lib/llm.d.ts +1 -1
  90. package/dist/lib/llm.js +26 -8
  91. package/dist/lib/localDiskCheck.d.ts +17 -0
  92. package/dist/lib/localDiskCheck.js +54 -0
  93. package/dist/lib/machineConfig.d.ts +11 -1
  94. package/dist/lib/machineConfig.js +16 -0
  95. package/dist/lib/machineRegistry.d.ts +61 -0
  96. package/dist/lib/machineRegistry.js +80 -0
  97. package/dist/lib/maintainCommand.d.ts +8 -0
  98. package/dist/lib/maintainCommand.js +34 -0
  99. package/dist/lib/masterLease.d.ts +20 -0
  100. package/dist/lib/masterLease.js +68 -0
  101. package/dist/lib/migrateCommand.d.ts +7 -0
  102. package/dist/lib/migrateCommand.js +158 -0
  103. package/dist/lib/migrateDbCommand.d.ts +9 -0
  104. package/dist/lib/migrateDbCommand.js +94 -0
  105. package/dist/lib/modelValidation.d.ts +5 -0
  106. package/dist/lib/modelValidation.js +27 -0
  107. package/dist/lib/openrouterTiers.d.ts +29 -0
  108. package/dist/lib/openrouterTiers.js +113 -0
  109. package/dist/lib/prefCommand.d.ts +10 -0
  110. package/dist/lib/prefCommand.js +118 -0
  111. package/dist/lib/projectsCommand.d.ts +8 -0
  112. package/dist/lib/projectsCommand.js +131 -0
  113. package/dist/lib/readCommand.d.ts +7 -0
  114. package/dist/lib/readCommand.js +62 -0
  115. package/dist/lib/recall.d.ts +3 -0
  116. package/dist/lib/recall.js +19 -4
  117. package/dist/lib/recallCommand.d.ts +11 -0
  118. package/dist/lib/recallCommand.js +112 -0
  119. package/dist/lib/reflectCommand.d.ts +8 -0
  120. package/dist/lib/reflectCommand.js +61 -0
  121. package/dist/lib/reindexCommand.d.ts +4 -0
  122. package/dist/lib/reindexCommand.js +34 -0
  123. package/dist/lib/reindexGraphCommand.d.ts +4 -0
  124. package/dist/lib/reindexGraphCommand.js +12 -0
  125. package/dist/lib/reinforceCommand.d.ts +8 -0
  126. package/dist/lib/reinforceCommand.js +40 -0
  127. package/dist/lib/remote.d.ts +5 -1
  128. package/dist/lib/remote.js +5 -1
  129. package/dist/lib/remoteWizard.d.ts +24 -5
  130. package/dist/lib/remoteWizard.js +308 -319
  131. package/dist/lib/restoreCommand.d.ts +5 -0
  132. package/dist/lib/restoreCommand.js +35 -0
  133. package/dist/lib/sandboxStartCommand.d.ts +6 -0
  134. package/dist/lib/sandboxStartCommand.js +25 -0
  135. package/dist/lib/sandboxStatusCommand.d.ts +4 -0
  136. package/dist/lib/sandboxStatusCommand.js +24 -0
  137. package/dist/lib/sandboxStopCommand.d.ts +4 -0
  138. package/dist/lib/sandboxStopCommand.js +21 -0
  139. package/dist/lib/searchCommand.d.ts +9 -0
  140. package/dist/lib/searchCommand.js +90 -0
  141. package/dist/lib/semanticSearchCommand.d.ts +8 -0
  142. package/dist/lib/semanticSearchCommand.js +52 -0
  143. package/dist/lib/setup/configSetRender.js +2 -0
  144. package/dist/lib/setup/providerGlyphs.d.ts +19 -0
  145. package/dist/lib/setup/providerGlyphs.js +42 -0
  146. package/dist/lib/setup/remoteRender.d.ts +31 -1
  147. package/dist/lib/setup/remoteRender.js +95 -4
  148. package/dist/lib/setup/sections/providers.d.ts +17 -0
  149. package/dist/lib/setup/sections/providers.js +255 -0
  150. package/dist/lib/setup/sections/routing.d.ts +2 -6
  151. package/dist/lib/setup/sections/routing.js +33 -85
  152. package/dist/lib/setup/sections/taskRoutingEditor.d.ts +17 -0
  153. package/dist/lib/setup/sections/taskRoutingEditor.js +149 -0
  154. package/dist/lib/setup/summary.d.ts +9 -0
  155. package/dist/lib/setup/summary.js +51 -37
  156. package/dist/lib/setup/ui/status.d.ts +1 -0
  157. package/dist/lib/setup/ui/status.js +2 -0
  158. package/dist/lib/setup.d.ts +108 -3
  159. package/dist/lib/setup.js +762 -157
  160. package/dist/lib/setupKeys.d.ts +42 -0
  161. package/dist/lib/setupKeys.js +564 -0
  162. package/dist/lib/setupRemoteCommand.d.ts +4 -0
  163. package/dist/lib/setupRemoteCommand.js +28 -0
  164. package/dist/lib/setupRemotePullCommand.d.ts +5 -0
  165. package/dist/lib/setupRemotePullCommand.js +52 -0
  166. package/dist/lib/setupRemotePushCommand.d.ts +5 -0
  167. package/dist/lib/setupRemotePushCommand.js +57 -0
  168. package/dist/lib/setupRemoteResolveCommand.d.ts +4 -0
  169. package/dist/lib/setupRemoteResolveCommand.js +48 -0
  170. package/dist/lib/setupRemoteStatusCommand.d.ts +4 -0
  171. package/dist/lib/setupRemoteStatusCommand.js +73 -0
  172. package/dist/lib/setupRemoteSyncCommand.d.ts +6 -0
  173. package/dist/lib/setupRemoteSyncCommand.js +65 -0
  174. package/dist/lib/setupSyncProjectsCommand.d.ts +4 -0
  175. package/dist/lib/setupSyncProjectsCommand.js +292 -0
  176. package/dist/lib/staleCommand.d.ts +8 -0
  177. package/dist/lib/staleCommand.js +34 -0
  178. package/dist/lib/statsCommand.d.ts +6 -0
  179. package/dist/lib/statsCommand.js +142 -0
  180. package/dist/lib/statusCommand.d.ts +18 -0
  181. package/dist/lib/statusCommand.js +250 -0
  182. package/dist/lib/storesCommand.d.ts +2 -0
  183. package/dist/lib/storesCommand.js +4 -0
  184. package/dist/lib/syncClient.d.ts +47 -0
  185. package/dist/lib/syncClient.js +212 -0
  186. package/dist/lib/syncCommand.d.ts +6 -0
  187. package/dist/lib/syncCommand.js +57 -0
  188. package/dist/lib/syncDoctorCommand.d.ts +5 -0
  189. package/dist/lib/syncDoctorCommand.js +100 -0
  190. package/dist/lib/syncIngest.d.ts +19 -0
  191. package/dist/lib/syncIngest.js +152 -0
  192. package/dist/lib/syncIngestLaunchd.d.ts +8 -0
  193. package/dist/lib/syncIngestLaunchd.js +93 -0
  194. package/dist/lib/syncIngestStartup.d.ts +5 -0
  195. package/dist/lib/syncIngestStartup.js +29 -0
  196. package/dist/lib/syncIngestSystemd.d.ts +10 -0
  197. package/dist/lib/syncIngestSystemd.js +97 -0
  198. package/dist/lib/syncIngestTimer.d.ts +8 -0
  199. package/dist/lib/syncIngestTimer.js +27 -0
  200. package/dist/lib/syncIngestTimerCommand.d.ts +7 -0
  201. package/dist/lib/syncIngestTimerCommand.js +83 -0
  202. package/dist/lib/syncLock.d.ts +6 -0
  203. package/dist/lib/syncLock.js +74 -0
  204. package/dist/lib/syncSnapshot.d.ts +30 -0
  205. package/dist/lib/syncSnapshot.js +184 -0
  206. package/dist/lib/syncStaging.d.ts +81 -0
  207. package/dist/lib/syncStaging.js +239 -0
  208. package/dist/lib/tagsAddCommand.d.ts +8 -0
  209. package/dist/lib/tagsAddCommand.js +18 -0
  210. package/dist/lib/tagsCommand.d.ts +4 -0
  211. package/dist/lib/tagsCommand.js +16 -0
  212. package/dist/lib/timelineCommand.d.ts +7 -0
  213. package/dist/lib/timelineCommand.js +49 -0
  214. package/dist/lib/traceCommand.d.ts +6 -0
  215. package/dist/lib/traceCommand.js +39 -0
  216. package/dist/lib/traverseCommand.d.ts +6 -0
  217. package/dist/lib/traverseCommand.js +58 -0
  218. package/dist/lib/updateCommand.d.ts +13 -0
  219. package/dist/lib/updateCommand.js +67 -0
  220. package/dist/lib/updateStatusCommand.d.ts +5 -0
  221. package/dist/lib/updateStatusCommand.js +38 -0
  222. package/dist/lib/webAddCommand.d.ts +8 -0
  223. package/dist/lib/webAddCommand.js +55 -0
  224. package/dist/lib/webBuildCommand.d.ts +10 -0
  225. package/dist/lib/webBuildCommand.js +65 -0
  226. package/dist/lib/webBuildIndexCommand.d.ts +8 -0
  227. package/dist/lib/webBuildIndexCommand.js +37 -0
  228. package/dist/lib/webIngestCommand.d.ts +11 -0
  229. package/dist/lib/webIngestCommand.js +51 -0
  230. package/dist/lib/webInitCommand.d.ts +9 -0
  231. package/dist/lib/webInitCommand.js +167 -0
  232. package/dist/lib/webRemoveCommand.d.ts +5 -0
  233. package/dist/lib/webRemoveCommand.js +41 -0
  234. package/dist/lib/webStatusCommand.d.ts +5 -0
  235. package/dist/lib/webStatusCommand.js +94 -0
  236. package/dist/lib/webUpdateCommand.d.ts +7 -0
  237. package/dist/lib/webUpdateCommand.js +72 -0
  238. package/dist/lib/workingSetCommand.d.ts +6 -0
  239. package/dist/lib/workingSetCommand.js +37 -0
  240. package/package.json +2 -1
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, 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,112 @@ 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
+ }
113
+ addTouched(phase, memoryIds) {
114
+ for (const id of memoryIds) {
115
+ if (id)
116
+ phase.memoryIdsTouched.push(id);
117
+ }
118
+ }
119
+ recordLLMSkip(phase, label, reason, memoryIds = [], fingerprint) {
120
+ phase.llmCallsSkipped++;
121
+ this.llmCalls.push({
122
+ phase: phase.name,
123
+ label,
124
+ status: "skipped",
125
+ reason,
126
+ provider: this.dreamConfig.provider,
127
+ model: this.dreamConfig.model || this.provider?.model || getProviderModel(this.config, this.dreamConfig.provider),
128
+ memoryIds,
129
+ fingerprint,
130
+ estimatedInputTokens: 0,
131
+ estimatedOutputTokens: 0,
132
+ estimatedCostUsd: 0,
133
+ });
134
+ }
135
+ llmCalls = [];
136
+ async generateWithAccounting(phase, label, prompt, maxTokens, memoryIds, fingerprint) {
137
+ if (!this.provider) {
138
+ this.recordLLMSkip(phase, label, "provider unavailable", memoryIds, fingerprint);
139
+ return null;
140
+ }
141
+ if (fingerprint && (this.dreamState.analyzedFingerprints[fingerprint] || this.pendingFingerprints[fingerprint])) {
142
+ this.recordLLMSkip(phase, label, "already analyzed fingerprint", memoryIds, fingerprint);
143
+ return null;
144
+ }
145
+ if (this.llmCallsMade >= this.dreamConfig.maxLLMCallsPerRun) {
146
+ this.recordLLMSkip(phase, label, "maxLLMCallsPerRun reached", memoryIds, fingerprint);
147
+ return null;
148
+ }
149
+ const inputTokens = estimateTokens(prompt);
150
+ this.llmCallsMade++;
151
+ try {
152
+ const response = await this.provider.generate(prompt, { maxTokens });
153
+ const outputTokens = estimateTokens(response);
154
+ const cost = estimateCost(this.provider.model, inputTokens, outputTokens);
155
+ phase.llmCallsMade++;
156
+ phase.estimatedInputTokens += inputTokens;
157
+ phase.estimatedOutputTokens += outputTokens;
158
+ phase.estimatedCostUsd += cost;
159
+ this.llmCalls.push({
160
+ phase: phase.name,
161
+ label,
162
+ status: "made",
163
+ provider: this.provider.name,
164
+ model: this.provider.model,
165
+ memoryIds,
166
+ fingerprint,
167
+ estimatedInputTokens: inputTokens,
168
+ estimatedOutputTokens: outputTokens,
169
+ estimatedCostUsd: cost,
170
+ });
171
+ if (fingerprint && response) {
172
+ this.pendingFingerprints[fingerprint] = {
173
+ kind: phase.name === "relationships" ? "relationship" : phase.name === "summaries" ? "summary" : "critique",
174
+ lastAnalyzedAt: new Date().toISOString(),
175
+ memoryIds,
176
+ };
177
+ }
178
+ return response;
179
+ }
180
+ catch (err) {
181
+ phase.llmCallsMade++;
182
+ const cost = estimateCost(this.provider.model, inputTokens, 0);
183
+ phase.estimatedInputTokens += inputTokens;
184
+ phase.estimatedCostUsd += cost;
185
+ this.llmCalls.push({
186
+ phase: phase.name,
187
+ label,
188
+ status: "failed",
189
+ reason: err instanceof Error ? err.message : String(err),
190
+ provider: this.provider.name,
191
+ model: this.provider.model,
192
+ memoryIds,
193
+ fingerprint,
194
+ estimatedInputTokens: inputTokens,
195
+ estimatedOutputTokens: 0,
196
+ estimatedCostUsd: cost,
197
+ });
198
+ throw err;
199
+ }
200
+ }
67
201
  /** Expose the local DB so DreamScheduler can read designation meta. */
68
202
  getDb() {
69
203
  return this.db;
@@ -100,9 +234,16 @@ export class GnosysDreamEngine {
100
234
  async dream(onProgress) {
101
235
  this.startTime = Date.now();
102
236
  this.abortRequested = false;
237
+ this.llmCallsMade = 0;
238
+ this.llmCalls = [];
239
+ this.pendingFingerprints = {};
240
+ this.dreamState = readDreamState();
103
241
  const log = onProgress || (() => { });
242
+ const startedAt = new Date().toISOString();
104
243
  const report = {
105
- startedAt: new Date().toISOString(),
244
+ id: `dream-${Date.parse(startedAt)}-${Math.random().toString(36).slice(2, 8)}`,
245
+ trigger: this.trigger,
246
+ startedAt,
106
247
  finishedAt: "",
107
248
  durationMs: 0,
108
249
  decayUpdated: 0,
@@ -113,6 +254,27 @@ export class GnosysDreamEngine {
113
254
  duplicatesFound: 0,
114
255
  errors: [],
115
256
  aborted: false,
257
+ machine: { hostname: os.hostname(), machineId: this.machineId },
258
+ provider: this.dreamConfig.provider,
259
+ model: this.dreamConfig.model || this.provider?.model,
260
+ phases: [],
261
+ llmCalls: [],
262
+ totals: {
263
+ llmCallsMade: 0,
264
+ llmCallsSkipped: 0,
265
+ estimatedInputTokens: 0,
266
+ estimatedOutputTokens: 0,
267
+ estimatedCostUsd: 0,
268
+ },
269
+ effectiveness: {
270
+ usefulOutputScore: 0,
271
+ costPerUsefulOutput: null,
272
+ decaysApplied: 0,
273
+ summariesGenerated: 0,
274
+ summariesUpdated: 0,
275
+ reviewSuggestions: 0,
276
+ relationshipsDiscovered: 0,
277
+ },
116
278
  };
117
279
  if (!this.db.isAvailable() || !this.db.isMigrated()) {
118
280
  report.errors.push("gnosys.db not available or not migrated");
@@ -161,13 +323,21 @@ export class GnosysDreamEngine {
161
323
  }
162
324
  // ─── Phase 1: Confidence Decay Sweep ─────────────────────────────────
163
325
  log("decay", "Phase 1: Confidence decay sweep...");
326
+ const decayPhase = this.createPhase("decay");
327
+ const decayStart = Date.now();
328
+ report.phases.push(decayPhase);
164
329
  try {
165
- report.decayUpdated = this.decaySweep();
330
+ const decayResult = this.decaySweep();
331
+ report.decayUpdated = decayResult.count;
332
+ this.addTouched(decayPhase, decayResult.memoryIds);
166
333
  log("decay", `Updated ${report.decayUpdated} memories`);
167
334
  }
168
335
  catch (err) {
169
336
  report.errors.push(`Decay sweep: ${err instanceof Error ? err.message : String(err)}`);
170
337
  }
338
+ finally {
339
+ this.finishPhase(decayPhase, decayStart);
340
+ }
171
341
  let check = this.shouldStop();
172
342
  if (check.stop) {
173
343
  report.aborted = true;
@@ -177,13 +347,20 @@ export class GnosysDreamEngine {
177
347
  // ─── Phase 2: Self-Critique (Review Suggestions) ─────────────────────
178
348
  if (this.dreamConfig.selfCritique) {
179
349
  log("critique", "Phase 2: Self-critique...");
350
+ const critiquePhase = this.createPhase("critique");
351
+ const critiqueStart = Date.now();
352
+ report.phases.push(critiquePhase);
180
353
  try {
181
- report.reviewSuggestions = await this.selfCritique(log);
354
+ report.reviewSuggestions = await this.selfCritique(log, critiquePhase);
355
+ this.addTouched(critiquePhase, report.reviewSuggestions.map((s) => s.memoryId));
182
356
  log("critique", `Generated ${report.reviewSuggestions.length} review suggestions`);
183
357
  }
184
358
  catch (err) {
185
359
  report.errors.push(`Self-critique: ${err instanceof Error ? err.message : String(err)}`);
186
360
  }
361
+ finally {
362
+ this.finishPhase(critiquePhase, critiqueStart);
363
+ }
187
364
  check = this.shouldStop();
188
365
  if (check.stop) {
189
366
  report.aborted = true;
@@ -194,15 +371,22 @@ export class GnosysDreamEngine {
194
371
  // ─── Phase 3: Summary Generation ─────────────────────────────────────
195
372
  if (this.dreamConfig.generateSummaries && this.provider) {
196
373
  log("summaries", "Phase 3: Summary generation...");
374
+ const summariesPhase = this.createPhase("summaries");
375
+ const summariesStart = Date.now();
376
+ report.phases.push(summariesPhase);
197
377
  try {
198
- const summaryResult = await this.generateSummaries(log);
378
+ const summaryResult = await this.generateSummaries(log, summariesPhase);
199
379
  report.summariesGenerated = summaryResult.generated;
200
380
  report.summariesUpdated = summaryResult.updated;
381
+ this.addTouched(summariesPhase, summaryResult.memoryIds);
201
382
  log("summaries", `Generated ${summaryResult.generated}, updated ${summaryResult.updated}`);
202
383
  }
203
384
  catch (err) {
204
385
  report.errors.push(`Summary generation: ${err instanceof Error ? err.message : String(err)}`);
205
386
  }
387
+ finally {
388
+ this.finishPhase(summariesPhase, summariesStart);
389
+ }
206
390
  check = this.shouldStop();
207
391
  if (check.stop) {
208
392
  report.aborted = true;
@@ -213,19 +397,73 @@ export class GnosysDreamEngine {
213
397
  // ─── Phase 4: Relationship Discovery ─────────────────────────────────
214
398
  if (this.dreamConfig.discoverRelationships && this.provider) {
215
399
  log("relationships", "Phase 4: Relationship discovery...");
400
+ const relationshipsPhase = this.createPhase("relationships");
401
+ const relationshipsStart = Date.now();
402
+ report.phases.push(relationshipsPhase);
216
403
  try {
217
- report.relationshipsDiscovered = await this.discoverRelationships(log);
404
+ const relationshipsResult = await this.discoverRelationships(log, relationshipsPhase);
405
+ report.relationshipsDiscovered = relationshipsResult.count;
406
+ this.addTouched(relationshipsPhase, relationshipsResult.memoryIds);
218
407
  log("relationships", `Discovered ${report.relationshipsDiscovered} new relationships`);
219
408
  }
220
409
  catch (err) {
221
410
  report.errors.push(`Relationship discovery: ${err instanceof Error ? err.message : String(err)}`);
222
411
  }
412
+ finally {
413
+ this.finishPhase(relationshipsPhase, relationshipsStart);
414
+ }
223
415
  }
224
416
  return this.finalize(report);
225
417
  }
226
418
  finalize(report) {
227
419
  report.finishedAt = new Date().toISOString();
228
420
  report.durationMs = Date.now() - this.startTime;
421
+ report.llmCalls = this.llmCalls;
422
+ report.totals = this.llmCalls.reduce((totals, call) => {
423
+ if (call.status === "made" || call.status === "failed")
424
+ totals.llmCallsMade++;
425
+ if (call.status === "skipped")
426
+ totals.llmCallsSkipped++;
427
+ totals.estimatedInputTokens += call.estimatedInputTokens;
428
+ totals.estimatedOutputTokens += call.estimatedOutputTokens;
429
+ totals.estimatedCostUsd += call.estimatedCostUsd;
430
+ return totals;
431
+ }, {
432
+ llmCallsMade: 0,
433
+ llmCallsSkipped: 0,
434
+ estimatedInputTokens: 0,
435
+ estimatedOutputTokens: 0,
436
+ estimatedCostUsd: 0,
437
+ });
438
+ report.totals.estimatedCostUsd = Math.round(report.totals.estimatedCostUsd * 1_000_000) / 1_000_000;
439
+ const usefulOutputScore = report.decayUpdated +
440
+ report.summariesGenerated * 5 +
441
+ report.summariesUpdated * 3 +
442
+ report.relationshipsDiscovered * 2;
443
+ report.effectiveness = {
444
+ usefulOutputScore,
445
+ costPerUsefulOutput: usefulOutputScore > 0
446
+ ? Math.round((report.totals.estimatedCostUsd / usefulOutputScore) * 1_000_000) / 1_000_000
447
+ : null,
448
+ decaysApplied: report.decayUpdated,
449
+ summariesGenerated: report.summariesGenerated,
450
+ summariesUpdated: report.summariesUpdated,
451
+ reviewSuggestions: report.reviewSuggestions.length,
452
+ relationshipsDiscovered: report.relationshipsDiscovered,
453
+ };
454
+ const memories = this.db.isAvailable() ? this.db.getActiveMemories() : [];
455
+ const watermark = memoryWatermark(memories);
456
+ writeDreamState({
457
+ ...this.dreamState,
458
+ lastRunAt: report.finishedAt,
459
+ lastSuccessfulRunAt: report.errors.length === 0 && !report.aborted ? report.finishedAt : this.dreamState.lastSuccessfulRunAt,
460
+ lastMemoryCount: watermark.count,
461
+ lastMemoryMaxModified: watermark.maxModified,
462
+ analyzedFingerprints: {
463
+ ...this.dreamState.analyzedFingerprints,
464
+ ...this.pendingFingerprints,
465
+ },
466
+ });
229
467
  // v5.4.2: A run is considered "successful with LLM work" if any of the
230
468
  // LLM-dependent counters moved. Resetting the consecutive-failure count
231
469
  // here ensures Layer 4 doesn't keep firing once dream is healthy again.
@@ -241,6 +479,10 @@ export class GnosysDreamEngine {
241
479
  summariesGenerated: report.summariesGenerated,
242
480
  reviewSuggestions: report.reviewSuggestions.length,
243
481
  relationshipsDiscovered: report.relationshipsDiscovered,
482
+ llmCallsMade: report.totals.llmCallsMade,
483
+ llmCallsSkipped: report.totals.llmCallsSkipped,
484
+ estimatedCostUsd: report.totals.estimatedCostUsd,
485
+ usefulOutputScore: report.effectiveness.usefulOutputScore,
244
486
  errors: report.errors.length,
245
487
  aborted: report.aborted,
246
488
  providerUnreachable: !this.provider,
@@ -257,9 +499,9 @@ export class GnosysDreamEngine {
257
499
  */
258
500
  decaySweep() {
259
501
  const now = new Date();
260
- const today = now.toISOString().split("T")[0];
261
502
  const memories = this.db.getActiveMemories();
262
503
  let updated = 0;
504
+ const memoryIds = [];
263
505
  for (const mem of memories) {
264
506
  const lastReinforced = mem.last_reinforced || mem.modified || mem.created;
265
507
  const lastDate = new Date(lastReinforced);
@@ -272,16 +514,17 @@ export class GnosysDreamEngine {
272
514
  if (Math.abs(rounded - mem.confidence) > 0.01) {
273
515
  syncConfidenceToDb(this.db, mem.id, rounded);
274
516
  updated++;
517
+ memoryIds.push(mem.id);
275
518
  }
276
519
  }
277
- return updated;
520
+ return { count: updated, memoryIds };
278
521
  }
279
522
  // ─── Phase 2: Self-Critique ────────────────────────────────────────────
280
523
  /**
281
524
  * Score memories and generate review suggestions.
282
525
  * NEVER deletes or archives — only flags for human review.
283
526
  */
284
- async selfCritique(log) {
527
+ async selfCritique(log, phase) {
285
528
  const suggestions = [];
286
529
  const memories = this.db.getActiveMemories();
287
530
  for (const mem of memories) {
@@ -308,7 +551,7 @@ export class GnosysDreamEngine {
308
551
  if (check.stop)
309
552
  break;
310
553
  try {
311
- const llmSuggestion = await this.llmCritique(mem);
554
+ const llmSuggestion = await this.llmCritique(mem, phase);
312
555
  if (llmSuggestion) {
313
556
  suggestions.push(llmSuggestion);
314
557
  }
@@ -374,9 +617,10 @@ export class GnosysDreamEngine {
374
617
  /**
375
618
  * LLM-based critique for borderline memories.
376
619
  */
377
- async llmCritique(mem) {
620
+ async llmCritique(mem, phase) {
378
621
  if (!this.provider)
379
622
  return null;
623
+ const fingerprint = fingerprintMemories("critique", [mem]);
380
624
  const prompt = `You are a knowledge management quality reviewer. Evaluate this memory and decide if it needs attention.
381
625
 
382
626
  Title: ${mem.title}
@@ -395,7 +639,9 @@ Respond with ONLY one of these JSON objects (no explanation):
395
639
  - {"action": "needs-update", "reason": "..."} if content seems outdated
396
640
  - {"action": "consider-merge", "reason": "..."} if it seems to overlap with other common knowledge`;
397
641
  try {
398
- const response = await this.provider.generate(prompt, { maxTokens: 200 });
642
+ const response = await this.generateWithAccounting(phase, `critique:${mem.id}`, prompt, 200, [mem.id], fingerprint);
643
+ if (!response)
644
+ return null;
399
645
  const jsonMatch = response.match(/\{[^}]+\}/);
400
646
  if (!jsonMatch)
401
647
  return null;
@@ -429,12 +675,13 @@ Respond with ONLY one of these JSON objects (no explanation):
429
675
  * Generate or update hierarchical summaries per category.
430
676
  * Uses LLM to synthesize category-level overviews.
431
677
  */
432
- async generateSummaries(log) {
678
+ async generateSummaries(log, phase) {
433
679
  if (!this.provider)
434
- return { generated: 0, updated: 0 };
680
+ return { generated: 0, updated: 0, memoryIds: [] };
435
681
  const categories = this.db.getCategories();
436
682
  let generated = 0;
437
683
  let updated = 0;
684
+ const touched = [];
438
685
  for (const category of categories) {
439
686
  const check = this.shouldStop();
440
687
  if (check.stop)
@@ -449,12 +696,15 @@ Respond with ONLY one of these JSON objects (no explanation):
449
696
  const currentIds = memories.map((m) => m.id);
450
697
  const unchanged = existingIds.length === currentIds.length &&
451
698
  existingIds.every((id) => currentIds.includes(id));
452
- if (unchanged)
699
+ if (unchanged) {
700
+ phase.llmCallsSkipped++;
701
+ phase.reason = phase.reason || "unchanged summaries skipped";
453
702
  continue; // No new memories in this category
703
+ }
454
704
  }
455
705
  log("summaries", `Summarizing ${category} (${memories.length} memories)...`);
456
706
  try {
457
- const summary = await this.summarizeCategory(category, memories);
707
+ const summary = await this.summarizeCategory(category, memories, phase);
458
708
  if (summary) {
459
709
  const today = new Date().toISOString().split("T")[0];
460
710
  const id = existing?.id || `summary-${category}-${today}`;
@@ -473,18 +723,19 @@ Respond with ONLY one of these JSON objects (no explanation):
473
723
  else {
474
724
  generated++;
475
725
  }
726
+ touched.push(...memories.map((m) => m.id));
476
727
  }
477
728
  }
478
729
  catch (err) {
479
730
  log("summaries", `Failed to summarize ${category}: ${err instanceof Error ? err.message : String(err)}`);
480
731
  }
481
732
  }
482
- return { generated, updated };
733
+ return { generated, updated, memoryIds: touched };
483
734
  }
484
735
  /**
485
736
  * Use LLM to generate a category summary.
486
737
  */
487
- async summarizeCategory(category, memories) {
738
+ async summarizeCategory(category, memories, phase) {
488
739
  if (!this.provider)
489
740
  return null;
490
741
  // Build context from memories (truncate to fit context window)
@@ -506,7 +757,7 @@ ${memoryTexts}
506
757
 
507
758
  Category summary:`;
508
759
  try {
509
- return await this.provider.generate(prompt, { maxTokens: 1024 });
760
+ return await this.generateWithAccounting(phase, `summary:${category}`, prompt, 1024, memories.map((m) => m.id), fingerprintMemories("summary", memories));
510
761
  }
511
762
  catch {
512
763
  return null;
@@ -517,13 +768,14 @@ Category summary:`;
517
768
  * Use LLM to discover relationships between memories.
518
769
  * Only creates new edges — never removes existing ones.
519
770
  */
520
- async discoverRelationships(log) {
771
+ async discoverRelationships(log, phase) {
521
772
  if (!this.provider)
522
- return 0;
773
+ return { count: 0, memoryIds: [] };
523
774
  const memories = this.db.getActiveMemories();
524
775
  if (memories.length < 3)
525
- return 0;
776
+ return { count: 0, memoryIds: [] };
526
777
  let discovered = 0;
778
+ const touched = new Set();
527
779
  const today = new Date().toISOString().split("T")[0];
528
780
  // Get existing relationships to avoid duplicates
529
781
  const existingPairs = new Set();
@@ -548,7 +800,7 @@ Category summary:`;
548
800
  const batchTitles = batch.map((m) => `[${m.id}] ${m.title}`).join(", ");
549
801
  log("relationships", `Analyzing relationships for: ${batchTitles}`);
550
802
  try {
551
- const relationships = await this.findRelationships(batch, memoryIndex);
803
+ const relationships = await this.findRelationships(batch, memoryIndex, phase);
552
804
  for (const rel of relationships) {
553
805
  const key = `${rel.source_id}→${rel.target_id}→${rel.rel_type}`;
554
806
  if (existingPairs.has(key))
@@ -563,18 +815,20 @@ Category summary:`;
563
815
  });
564
816
  existingPairs.add(key);
565
817
  discovered++;
818
+ touched.add(rel.source_id);
819
+ touched.add(rel.target_id);
566
820
  }
567
821
  }
568
822
  catch (err) {
569
823
  log("relationships", `Failed for batch: ${err instanceof Error ? err.message : String(err)}`);
570
824
  }
571
825
  }
572
- return discovered;
826
+ return { count: discovered, memoryIds: Array.from(touched) };
573
827
  }
574
828
  /**
575
829
  * Use LLM to find relationships for a batch of source memories.
576
830
  */
577
- async findRelationships(sources, memoryIndex) {
831
+ async findRelationships(sources, memoryIndex, phase) {
578
832
  if (!this.provider)
579
833
  return [];
580
834
  const sourceContext = sources
@@ -594,7 +848,9 @@ For each relationship found, output a JSON array of objects with: source_id, tar
594
848
  Only output relationships with confidence >= 0.7. Do NOT create self-referencing relationships.
595
849
  Output ONLY the JSON array, no explanation.`;
596
850
  try {
597
- const response = await this.provider.generate(prompt, { maxTokens: 1024 });
851
+ const response = await this.generateWithAccounting(phase, `relationships:${sources.map((s) => s.id).join(",")}`, prompt, 1024, sources.map((s) => s.id), fingerprintMemories("relationship", sources));
852
+ if (!response)
853
+ return [];
598
854
  // Extract JSON array from response
599
855
  const jsonMatch = response.match(/\[[\s\S]*\]/);
600
856
  if (!jsonMatch)
@@ -769,7 +1025,7 @@ export function formatDreamReport(report) {
769
1025
  lines.push(`Started: ${report.startedAt}`);
770
1026
  lines.push(`Finished: ${report.finishedAt}`);
771
1027
  if (report.aborted) {
772
- lines.push(`⚠ Aborted: ${report.abortReason}`);
1028
+ lines.push(`Aborted: ${report.abortReason}`);
773
1029
  }
774
1030
  lines.push("");
775
1031
  lines.push("Results:");
@@ -778,6 +1034,10 @@ export function formatDreamReport(report) {
778
1034
  lines.push(` Summaries updated: ${report.summariesUpdated}`);
779
1035
  lines.push(` Relationships discovered: ${report.relationshipsDiscovered}`);
780
1036
  lines.push(` Duplicates flagged: ${report.duplicatesFound}`);
1037
+ if (report.totals) {
1038
+ lines.push(` LLM calls: ${report.totals.llmCallsMade} made, ${report.totals.llmCallsSkipped} skipped`);
1039
+ lines.push(` Estimated cost: $${report.totals.estimatedCostUsd.toFixed(6)}`);
1040
+ }
781
1041
  lines.push("");
782
1042
  if (report.reviewSuggestions.length > 0) {
783
1043
  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>;