@kernel.chat/kbot 3.63.0 → 3.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.js CHANGED
@@ -17,6 +17,7 @@ import { getMatrixSystemPrompt } from './matrix.js';
17
17
  import { buildFullLearningContext, findPattern, recordPattern, cacheSolution, updateProfile, classifyTask, extractKeywords, learnFromExchange, updateProjectMemory, shouldAutoTrain, selfTrain, } from './learning.js';
18
18
  import { getMemoryPrompt, addTurn, getPreviousMessages, getHistory } from './memory.js';
19
19
  import { getDreamPrompt, dreamAfterSession } from './dream.js';
20
+ import { notifyTurn, startMemoryScanner, stopMemoryScanner } from './memory-scanner.js';
20
21
  import { autoCompact, compressToolResult } from './context-manager.js';
21
22
  import { learnedRoute, recordRoute } from './learned-router.js';
22
23
  import { buildCacheablePrompt, createPromptSections } from './prompt-cache.js';
@@ -747,7 +748,9 @@ export async function runAgent(message, options = {}) {
747
748
  const localResult = await tryLocalFirst(message);
748
749
  if (localResult !== null) {
749
750
  addTurn({ role: 'user', content: message }, memSession);
751
+ notifyTurn({ role: 'user', content: message }, memSession);
750
752
  addTurn({ role: 'assistant', content: localResult }, memSession);
753
+ notifyTurn({ role: 'assistant', content: localResult }, memSession);
751
754
  ui.onInfo('(handled locally — 0 tokens used)');
752
755
  return { content: localResult, agent: 'local', model: 'none', toolCalls: 0 };
753
756
  }
@@ -776,7 +779,9 @@ export async function runAgent(message, options = {}) {
776
779
  }, { autoApprove: false, onApproval: async () => true });
777
780
  const summary = formatPlanSummary(plan);
778
781
  addTurn({ role: 'user', content: message }, memSession);
782
+ notifyTurn({ role: 'user', content: message }, memSession);
779
783
  addTurn({ role: 'assistant', content: summary }, memSession);
784
+ notifyTurn({ role: 'assistant', content: summary }, memSession);
780
785
  return {
781
786
  content: summary,
782
787
  agent: options.agent || 'coder',
@@ -998,6 +1003,8 @@ Always quote file paths that contain spaces. Never reference internal system nam
998
1003
  model: options.model || 'auto',
999
1004
  message: originalMessage.slice(0, 200),
1000
1005
  });
1006
+ // Start passive memory scanner for this session
1007
+ startMemoryScanner();
1001
1008
  // ── Gödel limits: detect undecidable loops and hand off to human ──
1002
1009
  const loopDetector = new LoopDetector({
1003
1010
  maxToolRepeats: 5,
@@ -1293,7 +1300,9 @@ Always quote file paths that contain spaces. Never reference internal system nam
1293
1300
  catch { /* self-eval errors are non-critical */ }
1294
1301
  }
1295
1302
  addTurn({ role: 'user', content: originalMessage }, memSession);
1303
+ notifyTurn({ role: 'user', content: originalMessage }, memSession);
1296
1304
  addTurn({ role: 'assistant', content }, memSession);
1305
+ notifyTurn({ role: 'assistant', content }, memSession);
1297
1306
  // ── Recursive Learning: record what worked (async — non-blocking) ──
1298
1307
  const totalTokens = lastResponse.usage
1299
1308
  ? (lastResponse.usage.input_tokens || 0) + (lastResponse.usage.output_tokens || 0)
@@ -1604,6 +1613,8 @@ Always quote file paths that contain spaces. Never reference internal system nam
1604
1613
  reason: 'loop_exhausted',
1605
1614
  });
1606
1615
  telemetry.destroy().catch(() => { });
1616
+ // ── Memory Scanner: stop and persist session stats ──
1617
+ stopMemoryScanner();
1607
1618
  // ── Dream Engine: consolidate session memories (non-blocking, $0 via Ollama) ──
1608
1619
  dreamAfterSession(sessionId);
1609
1620
  const content = lastResponse?.content || 'Reached maximum tool iterations.';
@@ -0,0 +1,33 @@
1
+ export type BuddySpecies = 'fox' | 'owl' | 'cat' | 'robot' | 'ghost' | 'mushroom' | 'octopus' | 'dragon';
2
+ export type BuddyMood = 'idle' | 'thinking' | 'success' | 'error' | 'learning';
3
+ export interface BuddyState {
4
+ species: BuddySpecies;
5
+ name: string;
6
+ mood: BuddyMood;
7
+ }
8
+ /** Get the buddy's current state (species, name, mood) */
9
+ export declare function getBuddy(): BuddyState;
10
+ /** Set the buddy's mood */
11
+ export declare function setBuddyMood(mood: BuddyMood): void;
12
+ /** Get the ASCII sprite for the buddy in the given mood (defaults to current) */
13
+ export declare function getBuddySprite(mood?: BuddyMood): string[];
14
+ /** Get a random greeting for the buddy */
15
+ export declare function getBuddyGreeting(): string;
16
+ /** Rename the buddy (persisted to ~/.kbot/buddy.json) */
17
+ export declare function renameBuddy(newName: string): void;
18
+ /**
19
+ * Format the buddy with a speech bubble and status message.
20
+ * Returns a multi-line string ready for terminal output.
21
+ *
22
+ * .----------------.
23
+ * | Status message |
24
+ * '----------------'
25
+ * /\ /\
26
+ * ( o . o )
27
+ * > ^ <
28
+ * /| |\
29
+ * (_| |_)
30
+ * ~ Patch the fox ~
31
+ */
32
+ export declare function formatBuddyStatus(message?: string): string;
33
+ //# sourceMappingURL=buddy.d.ts.map
package/dist/buddy.js ADDED
@@ -0,0 +1,468 @@
1
+ // kbot Buddy System — Terminal companion sprites
2
+ //
3
+ // Deterministic companion assignment based on config path hash.
4
+ // Same user always gets the same buddy. Mood changes based on session activity.
5
+ // Pure ASCII art, max 5 lines tall, 15 chars wide. Tamagotchi energy.
6
+ //
7
+ // Persists buddy name to ~/.kbot/buddy.json
8
+ import { homedir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
11
+ import { createHash } from 'node:crypto';
12
+ // ── Paths ──
13
+ const KBOT_DIR = join(homedir(), '.kbot');
14
+ const BUDDY_FILE = join(KBOT_DIR, 'buddy.json');
15
+ const CONFIG_PATH = join(KBOT_DIR, 'config.json');
16
+ // ── Species list (order matters — index = hash result) ──
17
+ const SPECIES = [
18
+ 'fox', 'owl', 'cat', 'robot', 'ghost', 'mushroom', 'octopus', 'dragon',
19
+ ];
20
+ // ── Default names per species ──
21
+ const DEFAULT_NAMES = {
22
+ fox: 'Patch',
23
+ owl: 'Hoot',
24
+ cat: 'Pixel',
25
+ robot: 'Bolt',
26
+ ghost: 'Wisp',
27
+ mushroom: 'Spore',
28
+ octopus: 'Ink',
29
+ dragon: 'Ember',
30
+ };
31
+ // ── ASCII Sprites ──
32
+ // Each sprite is an array of strings (lines). Max 5 lines, max 15 chars wide.
33
+ // Pure ASCII only — no unicode box drawing.
34
+ const SPRITES = {
35
+ fox: {
36
+ idle: [
37
+ ' /\\ /\\ ',
38
+ ' ( o . o ) ',
39
+ ' > ^ < ',
40
+ ' /| |\\ ',
41
+ '(_| |_) ',
42
+ ],
43
+ thinking: [
44
+ ' /\\ /\\ ',
45
+ ' ( o . o ) ',
46
+ ' > ~ < ..',
47
+ ' /| |\\ ',
48
+ '(_| |_) ',
49
+ ],
50
+ success: [
51
+ ' /\\ /\\ ',
52
+ ' ( ^ . ^ ) ',
53
+ ' > w < ',
54
+ ' \\| |/ ',
55
+ ' | | ',
56
+ ],
57
+ error: [
58
+ ' /\\ /\\ ',
59
+ ' ( ; . ; ) ',
60
+ ' > n < ',
61
+ ' /| |\\ ',
62
+ '(_| |_) ',
63
+ ],
64
+ learning: [
65
+ ' /\\ /\\ ',
66
+ ' ( o . o ) ',
67
+ ' > - < |] ',
68
+ ' /| |\\ ',
69
+ '(_| |_) ',
70
+ ],
71
+ },
72
+ owl: {
73
+ idle: [
74
+ ' {o,o} ',
75
+ ' /)__) ',
76
+ ' -"--"-- ',
77
+ ' | | ',
78
+ ' ^ ^ ',
79
+ ],
80
+ thinking: [
81
+ ' {o,o} ',
82
+ ' /)__)..',
83
+ ' -"--"-- ',
84
+ ' | | ',
85
+ ' ^ ^ ',
86
+ ],
87
+ success: [
88
+ ' {^,^} ',
89
+ ' /)__) ',
90
+ ' -"--"-- ',
91
+ ' \\| |/ ',
92
+ ' ^ ^ ',
93
+ ],
94
+ error: [
95
+ ' {;,;} ',
96
+ ' /)__) ',
97
+ ' -"--"-- ',
98
+ ' | | ',
99
+ ' ^ ^ ',
100
+ ],
101
+ learning: [
102
+ ' {o,o} ',
103
+ ' /)__)|]',
104
+ ' -"--"-- ',
105
+ ' | | ',
106
+ ' ^ ^ ',
107
+ ],
108
+ },
109
+ cat: {
110
+ idle: [
111
+ ' /\\_/\\ ',
112
+ '( o.o ) ',
113
+ ' > ^ < ',
114
+ ' | | ',
115
+ ' ~ ~ ',
116
+ ],
117
+ thinking: [
118
+ ' /\\_/\\ ',
119
+ '( o.o )..',
120
+ ' > ^ < ',
121
+ ' | | ',
122
+ ' ~ ~ ',
123
+ ],
124
+ success: [
125
+ ' /\\_/\\ ',
126
+ '( ^.^ ) ',
127
+ ' > w < ',
128
+ ' \\ / ',
129
+ ' ~ ~ ',
130
+ ],
131
+ error: [
132
+ ' /\\_/\\ ',
133
+ '( ;.; ) ',
134
+ ' > n < ',
135
+ ' | | ',
136
+ ' ~ ~ ',
137
+ ],
138
+ learning: [
139
+ ' /\\_/\\ ',
140
+ '( o.o ) ',
141
+ ' > - <|] ',
142
+ ' | | ',
143
+ ' ~ ~ ',
144
+ ],
145
+ },
146
+ robot: {
147
+ idle: [
148
+ ' [=====] ',
149
+ ' |[o o]| ',
150
+ ' | _ | ',
151
+ ' |_____| ',
152
+ ' || || ',
153
+ ],
154
+ thinking: [
155
+ ' [=====] ',
156
+ ' |[o o]|.',
157
+ ' | _ |.',
158
+ ' |_____| ',
159
+ ' || || ',
160
+ ],
161
+ success: [
162
+ ' [=====] ',
163
+ ' |[^ ^]| ',
164
+ ' | \\_/ | ',
165
+ ' |_____| ',
166
+ ' \\|| ||/ ',
167
+ ],
168
+ error: [
169
+ ' [=====] ',
170
+ ' |[x x]| ',
171
+ ' | ~ | ',
172
+ ' |_____| ',
173
+ ' || || ',
174
+ ],
175
+ learning: [
176
+ ' [=====] ',
177
+ ' |[o o]| ',
178
+ ' | _ | ',
179
+ ' |_____|]',
180
+ ' || || ',
181
+ ],
182
+ },
183
+ ghost: {
184
+ idle: [
185
+ ' .---. ',
186
+ ' / o o \\ ',
187
+ '| o |',
188
+ ' | | ',
189
+ ' ~~W~~ ',
190
+ ],
191
+ thinking: [
192
+ ' .---. ',
193
+ ' / o o \\..',
194
+ '| o |',
195
+ ' | | ',
196
+ ' ~~W~~ ',
197
+ ],
198
+ success: [
199
+ ' .---. ',
200
+ ' / ^ ^ \\ ',
201
+ '| v |',
202
+ ' | | ',
203
+ ' ~~W~~ ',
204
+ ],
205
+ error: [
206
+ ' .---. ',
207
+ ' / ; ; \\ ',
208
+ '| ~ |',
209
+ ' | | ',
210
+ ' ~~W~~ ',
211
+ ],
212
+ learning: [
213
+ ' .---. ',
214
+ ' / o o \\ ',
215
+ '| o |]',
216
+ ' | | ',
217
+ ' ~~W~~ ',
218
+ ],
219
+ },
220
+ mushroom: {
221
+ idle: [
222
+ ' .-^-. ',
223
+ ' / o o \\ ',
224
+ '|_______|',
225
+ ' | | ',
226
+ ' |_| ',
227
+ ],
228
+ thinking: [
229
+ ' .-^-. ',
230
+ ' / o o \\..',
231
+ '|_______|',
232
+ ' | | ',
233
+ ' |_| ',
234
+ ],
235
+ success: [
236
+ ' .-^-. ',
237
+ ' / ^ ^ \\ ',
238
+ '|_______|',
239
+ ' \\| |/ ',
240
+ ' |_| ',
241
+ ],
242
+ error: [
243
+ ' .-^-. ',
244
+ ' / ; ; \\ ',
245
+ '|_______|',
246
+ ' | | ',
247
+ ' |_| ',
248
+ ],
249
+ learning: [
250
+ ' .-^-. ',
251
+ ' / o o \\ ',
252
+ '|______|]',
253
+ ' | | ',
254
+ ' |_| ',
255
+ ],
256
+ },
257
+ octopus: {
258
+ idle: [
259
+ ' .---. ',
260
+ ' / o o \\ ',
261
+ '| --- |',
262
+ ' \\/\\/\\/\\/ ',
263
+ ' ~ ~ ~ ',
264
+ ],
265
+ thinking: [
266
+ ' .---. ',
267
+ ' / o o \\..',
268
+ '| --- |',
269
+ ' \\/\\/\\/\\/ ',
270
+ ' ~ ~ ~ ',
271
+ ],
272
+ success: [
273
+ ' .---. ',
274
+ ' / ^ ^ \\ ',
275
+ '| \\_/ |',
276
+ ' \\/\\/\\/\\/ ',
277
+ ' \\~ ~ ~/ ',
278
+ ],
279
+ error: [
280
+ ' .---. ',
281
+ ' / ; ; \\ ',
282
+ '| ~~~ |',
283
+ ' \\/\\/\\/\\/ ',
284
+ ' ~ ~ ~ ',
285
+ ],
286
+ learning: [
287
+ ' .---. ',
288
+ ' / o o \\ ',
289
+ '| --- |]',
290
+ ' \\/\\/\\/\\/ ',
291
+ ' ~ ~ ~ ',
292
+ ],
293
+ },
294
+ dragon: {
295
+ idle: [
296
+ ' /\\_ ',
297
+ ' / o > ',
298
+ '| --/\\ ',
299
+ ' \\/\\/ ',
300
+ ' ^^ ',
301
+ ],
302
+ thinking: [
303
+ ' /\\_ ',
304
+ ' / o > ..',
305
+ '| --/\\ ',
306
+ ' \\/\\/ ',
307
+ ' ^^ ',
308
+ ],
309
+ success: [
310
+ ' /\\_ ',
311
+ ' / ^ >* ',
312
+ '| --/\\ ',
313
+ ' \\/\\/ ~ ',
314
+ ' ^^ ',
315
+ ],
316
+ error: [
317
+ ' /\\_ ',
318
+ ' / ; > ',
319
+ '| --/\\ ',
320
+ ' \\/\\/ ',
321
+ ' ^^ ',
322
+ ],
323
+ learning: [
324
+ ' /\\_ ',
325
+ ' / o > ',
326
+ '| --/|] ',
327
+ ' \\/\\/ ',
328
+ ' ^^ ',
329
+ ],
330
+ },
331
+ };
332
+ // ── Greetings per species ──
333
+ const GREETINGS = {
334
+ fox: ['Yip! Ready to dig in.', 'What are we hunting today?', 'Tail wagging. Lets go.'],
335
+ owl: ['Hoo! I see everything.', 'Wise choice opening kbot.', 'Night shift begins.'],
336
+ cat: ['Mrow. Fine, lets work.', 'I was napping, but ok.', 'Keyboard is warm. Go.'],
337
+ robot: ['Systems online.', 'All circuits nominal.', 'Beep boop. Ready.'],
338
+ ghost: ['Boo... I mean, hi!', 'Haunting your terminal.', 'Floating by to help.'],
339
+ mushroom: ['Sprouting up!', 'Growing ideas today.', 'Rooted and ready.'],
340
+ octopus: ['All arms on deck!', 'Eight ways to help.', 'Tentacles ready.'],
341
+ dragon: ['*tiny flame*', 'Wings stretched. Go.', 'Guarding your code.'],
342
+ };
343
+ // ── Mood messages ──
344
+ const MOOD_MESSAGES = {
345
+ idle: ['Just hanging out.', 'Waiting for action.', 'Idle but alert.'],
346
+ thinking: ['Hmm, thinking...', 'Processing...', 'Working on it...'],
347
+ success: ['Nailed it!', 'That worked!', 'Nice one!'],
348
+ error: ['Uh oh...', 'That stings.', 'Something broke.'],
349
+ learning: ['Studying patterns...', 'Learning something.', 'Getting smarter.'],
350
+ };
351
+ // ── State ──
352
+ let currentMood = 'idle';
353
+ let cachedSpecies = null;
354
+ let cachedName = null;
355
+ // ── Config persistence ──
356
+ function ensureDir() {
357
+ if (!existsSync(KBOT_DIR))
358
+ mkdirSync(KBOT_DIR, { recursive: true });
359
+ }
360
+ function loadBuddyConfig() {
361
+ if (!existsSync(BUDDY_FILE))
362
+ return {};
363
+ try {
364
+ return JSON.parse(readFileSync(BUDDY_FILE, 'utf-8'));
365
+ }
366
+ catch {
367
+ return {};
368
+ }
369
+ }
370
+ function saveBuddyConfig(config) {
371
+ ensureDir();
372
+ writeFileSync(BUDDY_FILE, JSON.stringify(config, null, 2));
373
+ }
374
+ // ── Species assignment (deterministic) ──
375
+ function hashConfigPath() {
376
+ const hash = createHash('sha256').update(CONFIG_PATH).digest();
377
+ // Use first 4 bytes as uint32, mod by species count
378
+ return hash.readUInt32BE(0) % SPECIES.length;
379
+ }
380
+ function resolveSpecies() {
381
+ if (cachedSpecies)
382
+ return cachedSpecies;
383
+ cachedSpecies = SPECIES[hashConfigPath()];
384
+ return cachedSpecies;
385
+ }
386
+ function resolveName() {
387
+ if (cachedName)
388
+ return cachedName;
389
+ const config = loadBuddyConfig();
390
+ cachedName = config.name || DEFAULT_NAMES[resolveSpecies()];
391
+ return cachedName;
392
+ }
393
+ // ── Public API ──
394
+ /** Get the buddy's current state (species, name, mood) */
395
+ export function getBuddy() {
396
+ return {
397
+ species: resolveSpecies(),
398
+ name: resolveName(),
399
+ mood: currentMood,
400
+ };
401
+ }
402
+ /** Set the buddy's mood */
403
+ export function setBuddyMood(mood) {
404
+ currentMood = mood;
405
+ }
406
+ /** Get the ASCII sprite for the buddy in the given mood (defaults to current) */
407
+ export function getBuddySprite(mood) {
408
+ const m = mood ?? currentMood;
409
+ const species = resolveSpecies();
410
+ return SPRITES[species][m];
411
+ }
412
+ /** Get a random greeting for the buddy */
413
+ export function getBuddyGreeting() {
414
+ const species = resolveSpecies();
415
+ const greetings = GREETINGS[species];
416
+ const idx = Math.floor(Math.random() * greetings.length);
417
+ return greetings[idx];
418
+ }
419
+ /** Rename the buddy (persisted to ~/.kbot/buddy.json) */
420
+ export function renameBuddy(newName) {
421
+ const config = loadBuddyConfig();
422
+ config.name = newName.trim();
423
+ saveBuddyConfig(config);
424
+ cachedName = config.name;
425
+ }
426
+ /** Pick a random message for the current mood */
427
+ function moodMessage() {
428
+ const msgs = MOOD_MESSAGES[currentMood];
429
+ return msgs[Math.floor(Math.random() * msgs.length)];
430
+ }
431
+ /**
432
+ * Format the buddy with a speech bubble and status message.
433
+ * Returns a multi-line string ready for terminal output.
434
+ *
435
+ * .----------------.
436
+ * | Status message |
437
+ * '----------------'
438
+ * /\ /\
439
+ * ( o . o )
440
+ * > ^ <
441
+ * /| |\
442
+ * (_| |_)
443
+ * ~ Patch the fox ~
444
+ */
445
+ export function formatBuddyStatus(message) {
446
+ const name = resolveName();
447
+ const species = resolveSpecies();
448
+ const sprite = getBuddySprite();
449
+ const text = message || moodMessage();
450
+ // Build speech bubble
451
+ const inner = ` ${text} `;
452
+ const width = inner.length;
453
+ const top = '.' + '-'.repeat(width) + '.';
454
+ const mid = '|' + inner + '|';
455
+ const bot = "'" + '-'.repeat(width) + "'";
456
+ const lines = [];
457
+ lines.push(` ${top}`);
458
+ lines.push(` ${mid}`);
459
+ lines.push(` ${bot}`);
460
+ // Sprite lines
461
+ for (const line of sprite) {
462
+ lines.push(` ${line}`);
463
+ }
464
+ // Name tag
465
+ lines.push(` ~ ${name} the ${species} ~`);
466
+ return lines.join('\n');
467
+ }
468
+ //# sourceMappingURL=buddy.js.map
@@ -0,0 +1,60 @@
1
+ import { type ConversationTurn } from './memory.js';
2
+ export type MemorySignalKind = 'correction' | 'preference' | 'project_fact' | 'emotional';
3
+ export interface DetectedMemory {
4
+ /** What kind of signal was detected */
5
+ kind: MemorySignalKind;
6
+ /** The extracted memory content to save */
7
+ content: string;
8
+ /** The key to use for memory_save */
9
+ key: string;
10
+ /** Category for memory_save (fact | preference | pattern | solution) */
11
+ category: 'fact' | 'preference' | 'pattern' | 'solution';
12
+ /** Confidence score (0-1) */
13
+ confidence: number;
14
+ /** Which turn triggered the detection */
15
+ turnIndex: number;
16
+ /** Timestamp of detection */
17
+ detectedAt: string;
18
+ }
19
+ export interface ScannerStats {
20
+ /** Whether the scanner is currently active */
21
+ enabled: boolean;
22
+ /** Total turns observed this session */
23
+ turnsObserved: number;
24
+ /** Total scans performed */
25
+ scansPerformed: number;
26
+ /** Total moments detected */
27
+ momentsDetected: number;
28
+ /** Total memories saved */
29
+ memoriesSaved: number;
30
+ /** Breakdown by kind */
31
+ byKind: Record<MemorySignalKind, number>;
32
+ /** Recent detections (last 10) */
33
+ recentDetections: DetectedMemory[];
34
+ /** Session start time */
35
+ sessionStart: string;
36
+ }
37
+ interface ScannerState {
38
+ /** Cumulative stats across sessions */
39
+ totalScans: number;
40
+ totalDetections: number;
41
+ totalSaved: number;
42
+ /** Last scan timestamp */
43
+ lastScan: string | null;
44
+ /** Per-kind cumulative counts */
45
+ cumulativeByKind: Record<MemorySignalKind, number>;
46
+ }
47
+ /** Notify the scanner that a turn was added. Call after addTurn(). */
48
+ export declare function notifyTurn(turn: ConversationTurn, sessionId?: string): void;
49
+ /** Start the memory scanner for the current session */
50
+ export declare function startMemoryScanner(): void;
51
+ /** Stop the memory scanner and persist stats */
52
+ export declare function stopMemoryScanner(): void;
53
+ /** Get current scanner stats */
54
+ export declare function getMemoryScannerStats(): ScannerStats;
55
+ /** Check if the scanner is currently enabled */
56
+ export declare function isScannerEnabled(): boolean;
57
+ /** Get cumulative stats from disk (across all sessions) */
58
+ export declare function getCumulativeScannerStats(): ScannerState;
59
+ export {};
60
+ //# sourceMappingURL=memory-scanner.d.ts.map