@yugenlab/vaayu 0.1.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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +365 -0
  3. package/chunks/chunk-E5A3SCDJ.js +246 -0
  4. package/chunks/chunk-G5VYCA6O.js +69 -0
  5. package/chunks/chunk-H76V36OF.js +1029 -0
  6. package/chunks/chunk-HAPVUJ6A.js +238 -0
  7. package/chunks/chunk-IEKAYVA3.js +137 -0
  8. package/chunks/chunk-IGKYKEKT.js +43 -0
  9. package/chunks/chunk-IIET2K6D.js +7728 -0
  10. package/chunks/chunk-ITIVYGUG.js +347 -0
  11. package/chunks/chunk-JAWZ7ANC.js +208 -0
  12. package/chunks/chunk-JZU37VQ5.js +714 -0
  13. package/chunks/chunk-KC6NRZ7U.js +198 -0
  14. package/chunks/chunk-KDRROLVN.js +433 -0
  15. package/chunks/chunk-L7JICQBW.js +1006 -0
  16. package/chunks/chunk-MINFB5LT.js +1479 -0
  17. package/chunks/chunk-MJ74G5RB.js +5816 -0
  18. package/chunks/chunk-S4TBVCL2.js +2158 -0
  19. package/chunks/chunk-SMVJRPAH.js +2753 -0
  20. package/chunks/chunk-U6OLJ36B.js +438 -0
  21. package/chunks/chunk-URGEODS5.js +752 -0
  22. package/chunks/chunk-YSU3BWV6.js +123 -0
  23. package/chunks/consolidation-indexer-TOTTDZXW.js +21 -0
  24. package/chunks/day-consolidation-NKO63HZQ.js +24 -0
  25. package/chunks/graphrag-ZI2FSU7S.js +13 -0
  26. package/chunks/hierarchical-temporal-search-ZD46UMKR.js +8 -0
  27. package/chunks/hybrid-search-ZVLZVGFS.js +19 -0
  28. package/chunks/memory-store-KNJPMBLQ.js +17 -0
  29. package/chunks/periodic-consolidation-BPKOZDGB.js +10 -0
  30. package/chunks/postgres-3ZXBYTPC.js +8 -0
  31. package/chunks/recall-GMVHWQWW.js +20 -0
  32. package/chunks/search-7HZETVMZ.js +18 -0
  33. package/chunks/session-store-XKPGKXUS.js +44 -0
  34. package/chunks/sqlite-JPF5TICX.js +152 -0
  35. package/chunks/src-6GVZTUH6.js +12 -0
  36. package/chunks/src-QAXOD5SB.js +273 -0
  37. package/chunks/suncalc-NOHGYHDU.js +186 -0
  38. package/chunks/tree-RSHKDTCR.js +10 -0
  39. package/gateway.js +61944 -0
  40. package/package.json +51 -0
  41. package/pair-cli.js +133 -0
@@ -0,0 +1,1029 @@
1
+ import {
2
+ EmbeddingService,
3
+ cosineSimilarity,
4
+ fallbackEmbedding
5
+ } from "./chunk-JAWZ7ANC.js";
6
+ import {
7
+ SessionError,
8
+ getChitraguptaHome
9
+ } from "./chunk-KC6NRZ7U.js";
10
+
11
+ // ../chitragupta/packages/smriti/src/day-consolidation.ts
12
+ import fs from "fs";
13
+ import path from "path";
14
+
15
+ // ../chitragupta/packages/smriti/src/event-extractor.ts
16
+ var DOMAIN_SIGNALS = {
17
+ planning: [
18
+ /\b(?:plan for|roadmap|milestone|timeline|schedule|deadline|sprint|backlog|prioriti[sz]e)\b/i,
19
+ /\b(?:next steps|action items|todo list|to-do list|project plan|gantt|kanban)\b/i,
20
+ /\b(?:due date|estimated time|target date|delivery date|eta for)\b/i
21
+ ],
22
+ learning: [
23
+ /\b(?:teach me|learn about|learn how|tutorial|take a course|study for)\b/i,
24
+ /\b(?:explain to me|help me understand|walkthrough|lesson on)\b/i,
25
+ /\b(?:what is a|what are the|concept of|fundamentals of|theory behind)\b/i
26
+ ],
27
+ creative: [
28
+ /\b(?:write a|draft a|compose a|brainstorm|ideate|creative writing|story about|poem|essay|blog post)\b/i,
29
+ /\b(?:sketch a|mockup|wireframe|logo for|brand identity)\b/i,
30
+ /\b(?:name suggestions|tagline|slogan|elevator pitch)\b/i
31
+ ],
32
+ operational: [
33
+ /\b(?:deploy to|release to|rollback|rollout|uptime|downtime|incident)\b/i,
34
+ /\b(?:docker|kubernetes|k8s|nginx|systemd|terraform|ansible)\b/i,
35
+ /\b(?:infrastructure|ci\/cd pipeline|staging|production environment)\b/i
36
+ ],
37
+ research: [
38
+ /\b(?:research on|investigate|deep dive|literature review|state of the art|sota)\b/i,
39
+ /\b(?:arxiv|paper on|survey of|systematic review|meta-analysis)\b/i,
40
+ /\b(?:pros and cons|tradeoffs? between|trade-offs? between|compare .+ vs)\b/i
41
+ ],
42
+ health: [
43
+ /\b(?:health|wellness|fitness|exercise routine|workout|diet plan|nutrition|calories)\b/i,
44
+ /\b(?:sleep schedule|meditation|mindfulness|mental health|therapy session)\b/i,
45
+ /\b(?:doctor appointment|symptoms of|medicine|prescription|blood pressure)\b/i
46
+ ],
47
+ social: [
48
+ /\b(?:send a message|reply to|draft an email|write an email|schedule a meeting)\b/i,
49
+ /\b(?:birthday|anniversary|gift for|party for|event planning|gathering)\b/i,
50
+ /\b(?:my friend|my family|my colleague|my partner|my wife|my husband)\b/i
51
+ ],
52
+ finance: [
53
+ /\b(?:budget for|monthly expenses|income|salary|payment for|invoice)\b/i,
54
+ /\b(?:invest in|stock|portfolio|crypto|savings account|retirement|tax return)\b/i,
55
+ /\b(?:how much does|subscription|billing|net worth|financial)\b/i
56
+ ],
57
+ reflection: [
58
+ /\b(?:reflect on|journal entry|diary entry|retrospective|look back on)\b/i,
59
+ /\b(?:what went well|what could improve|lessons learned|takeaways from)\b/i,
60
+ /\b(?:grateful for|gratitude|how am i doing|self-assessment)\b/i
61
+ ],
62
+ security: [
63
+ /\b(?:security audit|vulnerability|exploit|threat model|attack vector|data breach)\b/i,
64
+ /\b(?:encrypt|decrypt|ssl certificate|tls|oauth|authentication flow)\b/i,
65
+ /\b(?:access control|firewall rule|security compliance|penetration test|pentest)\b/i
66
+ ]
67
+ };
68
+ var DOMAIN_EXTRACTOR_MAP = {
69
+ planning: "discussion",
70
+ learning: "discussion",
71
+ creative: "discussion",
72
+ operational: "mixed",
73
+ research: "discussion",
74
+ health: "personal",
75
+ social: "personal",
76
+ finance: "personal",
77
+ reflection: "discussion",
78
+ security: "mixed"
79
+ };
80
+ function scoreDomainSignals(turns) {
81
+ const scores = /* @__PURE__ */ new Map();
82
+ const userContent = turns.filter((t) => t.role === "user").map((t) => t.content).join(" ");
83
+ for (const [domain, patterns] of Object.entries(DOMAIN_SIGNALS)) {
84
+ let groupsMatched = 0;
85
+ for (const pattern of patterns) {
86
+ if (new RegExp(pattern.source, "i").test(userContent)) {
87
+ groupsMatched++;
88
+ }
89
+ }
90
+ if (groupsMatched > 0) scores.set(domain, groupsMatched);
91
+ }
92
+ return scores;
93
+ }
94
+ function detectSessionType(turns) {
95
+ if (turns.length === 0) return "personal";
96
+ let toolTurns = 0;
97
+ let textTurns = 0;
98
+ let totalUserLength = 0;
99
+ let userTurnCount = 0;
100
+ for (const turn of turns) {
101
+ const hasToolCall = /\[tool:\w+\]/.test(turn.content) || turn.toolCalls && turn.toolCalls.length > 0;
102
+ if (hasToolCall) {
103
+ toolTurns++;
104
+ } else {
105
+ textTurns++;
106
+ }
107
+ if (turn.role === "user") {
108
+ totalUserLength += turn.content.length;
109
+ userTurnCount++;
110
+ }
111
+ }
112
+ const avgUserLength = userTurnCount > 0 ? totalUserLength / userTurnCount : 0;
113
+ const toolRatio = turns.length > 0 ? toolTurns / turns.length : 0;
114
+ let coreType;
115
+ if (turns.length <= 4 && avgUserLength < 100) {
116
+ coreType = "personal";
117
+ } else if (toolRatio > 0.6) {
118
+ coreType = "coding";
119
+ } else if (toolRatio < 0.15) {
120
+ coreType = "discussion";
121
+ } else {
122
+ coreType = "mixed";
123
+ }
124
+ if (coreType === "coding") return "coding";
125
+ const domainScores = scoreDomainSignals(turns);
126
+ if (domainScores.size === 0) return coreType;
127
+ let topDomain = null;
128
+ let topScore = 0;
129
+ for (const [domain, score] of domainScores) {
130
+ if (score > topScore) {
131
+ topScore = score;
132
+ topDomain = domain;
133
+ }
134
+ }
135
+ if (topDomain && topScore >= 2) {
136
+ return topDomain;
137
+ }
138
+ return coreType;
139
+ }
140
+ function getExtractorStrategy(sessionType) {
141
+ if (sessionType === "coding" || sessionType === "discussion" || sessionType === "mixed" || sessionType === "personal") {
142
+ return sessionType;
143
+ }
144
+ return DOMAIN_EXTRACTOR_MAP[sessionType];
145
+ }
146
+ function extractEventChain(meta, turns) {
147
+ const sessionType = detectSessionType(turns);
148
+ const provider = meta.provider ?? meta.metadata?.provider ?? meta.agent ?? "unknown";
149
+ const events = [];
150
+ const topics = [];
151
+ const strategy = getExtractorStrategy(sessionType);
152
+ for (let i = 0; i < turns.length; i++) {
153
+ const turn = turns[i];
154
+ const timestamp = turn.createdAt;
155
+ if (turn.role === "user") {
156
+ const userEvents = extractFromUserTurn(turn, timestamp, meta.id, provider);
157
+ events.push(...userEvents);
158
+ const topic = extractTopic(turn.content);
159
+ if (topic && !topics.includes(topic)) {
160
+ topics.push(topic);
161
+ }
162
+ } else if (turn.role === "assistant") {
163
+ switch (strategy) {
164
+ case "coding":
165
+ events.push(...extractFromCodingAssistant(turn, timestamp, meta.id, provider));
166
+ break;
167
+ case "discussion":
168
+ events.push(...extractFromDiscussionAssistant(turn, timestamp, meta.id, provider));
169
+ break;
170
+ case "mixed":
171
+ events.push(...extractFromCodingAssistant(turn, timestamp, meta.id, provider));
172
+ events.push(...extractFromDiscussionAssistant(turn, timestamp, meta.id, provider));
173
+ break;
174
+ case "personal":
175
+ if (turn.content.length < 500) {
176
+ events.push({
177
+ type: "action",
178
+ summary: turn.content.split("\n")[0].slice(0, 200),
179
+ timestamp,
180
+ sessionId: meta.id,
181
+ provider,
182
+ turnNumber: turn.turnNumber
183
+ });
184
+ }
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ const deduped = deduplicateEvents(events);
190
+ deduped.sort((a, b) => a.timestamp - b.timestamp);
191
+ const narrative = generateNarrative(sessionType, deduped, meta, provider);
192
+ return { sessionType, events: deduped, narrative, topics, meta };
193
+ }
194
+ function extractFromUserTurn(turn, timestamp, sessionId, provider) {
195
+ const events = [];
196
+ const content = turn.content.trim();
197
+ const toolMatch = content.match(/\[tool:(\w+)\]\s*(.*)/s);
198
+ if (toolMatch) {
199
+ events.push({
200
+ type: "action",
201
+ summary: `Used ${toolMatch[1]}`,
202
+ timestamp,
203
+ sessionId,
204
+ provider,
205
+ tool: toolMatch[1],
206
+ turnNumber: turn.turnNumber
207
+ });
208
+ return events;
209
+ }
210
+ const factPatterns = [
211
+ { pattern: /(?:i live in|i'm from|i am from|based in)\s+(.+)/i, type: "fact" },
212
+ { pattern: /(?:my name is|i'm called|call me)\s+(.+)/i, type: "fact" },
213
+ { pattern: /(?:i work at|i work for|my company)\s+(.+)/i, type: "fact" },
214
+ { pattern: /(?:always use|never use|i prefer|i use)\s+(.+)/i, type: "preference" },
215
+ { pattern: /(?:remember that|don't forget|note that)\s+(.+)/i, type: "fact" }
216
+ ];
217
+ for (const { pattern, type } of factPatterns) {
218
+ const match = content.match(pattern);
219
+ if (match) {
220
+ events.push({
221
+ type,
222
+ summary: match[0].trim().slice(0, 200),
223
+ timestamp,
224
+ sessionId,
225
+ provider,
226
+ turnNumber: turn.turnNumber
227
+ });
228
+ }
229
+ }
230
+ if (content.endsWith("?") || /^(how|what|why|where|when|can|do|is|should)\b/i.test(content)) {
231
+ events.push({
232
+ type: "question",
233
+ summary: content.split("\n")[0].slice(0, 200),
234
+ timestamp,
235
+ sessionId,
236
+ provider,
237
+ turnNumber: turn.turnNumber
238
+ });
239
+ } else if (content.length < 300 && !toolMatch) {
240
+ events.push({
241
+ type: "decision",
242
+ summary: content.split("\n")[0].slice(0, 200),
243
+ timestamp,
244
+ sessionId,
245
+ provider,
246
+ turnNumber: turn.turnNumber
247
+ });
248
+ }
249
+ return events;
250
+ }
251
+ function extractFromCodingAssistant(turn, timestamp, sessionId, provider) {
252
+ const events = [];
253
+ const content = turn.content;
254
+ const toolResultMatch = content.match(/\[(\w+)\s*→\s*(\d+(?:\.\d+)?m?s)\]\s*(.*)/);
255
+ if (toolResultMatch) {
256
+ const resultPreview = toolResultMatch[3].slice(0, 150);
257
+ events.push({
258
+ type: "action",
259
+ summary: `${toolResultMatch[1]}: ${resultPreview}`,
260
+ timestamp,
261
+ sessionId,
262
+ provider,
263
+ tool: toolResultMatch[1],
264
+ turnNumber: turn.turnNumber
265
+ });
266
+ }
267
+ const filePatterns = content.matchAll(/(?:(?:File|Modified|Created|Edited|Deleted)[:\s]+)([^\n,]+\.\w+)/gi);
268
+ const files = [];
269
+ for (const match of filePatterns) {
270
+ files.push(match[1].trim());
271
+ }
272
+ if (files.length > 0) {
273
+ events.push({
274
+ type: "action",
275
+ summary: `Modified ${files.length} file(s): ${files.slice(0, 3).join(", ")}${files.length > 3 ? "..." : ""}`,
276
+ timestamp,
277
+ sessionId,
278
+ provider,
279
+ files,
280
+ turnNumber: turn.turnNumber
281
+ });
282
+ }
283
+ const errorMatch = content.match(/(?:Error|Failed|error|FAIL)[:\s]+(.+)/);
284
+ if (errorMatch) {
285
+ events.push({
286
+ type: "error",
287
+ summary: errorMatch[0].slice(0, 200),
288
+ timestamp,
289
+ sessionId,
290
+ provider,
291
+ turnNumber: turn.turnNumber
292
+ });
293
+ }
294
+ const commitMatch = content.match(/(?:commit|committed|pushed)[:\s]+([a-f0-9]{7,})/i);
295
+ if (commitMatch) {
296
+ events.push({
297
+ type: "commit",
298
+ summary: `Committed ${commitMatch[1]}`,
299
+ timestamp,
300
+ sessionId,
301
+ provider,
302
+ turnNumber: turn.turnNumber
303
+ });
304
+ }
305
+ if (events.length === 0 && content.length < 300 && content.length > 10) {
306
+ events.push({
307
+ type: "decision",
308
+ summary: content.split("\n")[0].slice(0, 200),
309
+ timestamp,
310
+ sessionId,
311
+ provider,
312
+ turnNumber: turn.turnNumber
313
+ });
314
+ }
315
+ return events;
316
+ }
317
+ function extractFromDiscussionAssistant(turn, timestamp, sessionId, provider) {
318
+ const events = [];
319
+ const content = turn.content;
320
+ const lines = content.split("\n").filter((l) => l.trim());
321
+ if (lines.length > 0) {
322
+ const firstLine = lines[0].replace(/^#+\s*/, "").trim();
323
+ if (firstLine.length > 10) {
324
+ events.push({
325
+ type: "topic",
326
+ summary: firstLine.slice(0, 200),
327
+ timestamp,
328
+ sessionId,
329
+ provider,
330
+ turnNumber: turn.turnNumber
331
+ });
332
+ }
333
+ }
334
+ const optionLines = lines.filter(
335
+ (l) => /^(?:\d+\.|[-*]|\*\*Option|Option [A-C])/i.test(l.trim())
336
+ );
337
+ if (optionLines.length >= 2) {
338
+ const summary = optionLines.slice(0, 4).map((l) => l.trim().slice(0, 100)).join("; ");
339
+ events.push({
340
+ type: "decision",
341
+ summary: `Options: ${summary}`,
342
+ timestamp,
343
+ sessionId,
344
+ provider,
345
+ turnNumber: turn.turnNumber
346
+ });
347
+ }
348
+ const lastLines = lines.slice(-3);
349
+ for (const line of lastLines) {
350
+ const trimmed = line.trim();
351
+ if (/^(?:So|In summary|The (?:key|main|bottom)|To summarize|Overall)/i.test(trimmed)) {
352
+ events.push({
353
+ type: "decision",
354
+ summary: trimmed.slice(0, 200),
355
+ timestamp,
356
+ sessionId,
357
+ provider,
358
+ turnNumber: turn.turnNumber
359
+ });
360
+ break;
361
+ }
362
+ }
363
+ return events;
364
+ }
365
+ function extractTopic(content) {
366
+ const firstLine = content.split("\n")[0].trim();
367
+ if (firstLine.length < 5 || firstLine.length > 200) return null;
368
+ const cleaned = firstLine.replace(/^(?:hey|hi|hello|ok|okay|so|well|please|pls|can you|could you)\s+/i, "").trim();
369
+ return cleaned.length > 5 ? cleaned.slice(0, 100) : null;
370
+ }
371
+ function deduplicateEvents(events) {
372
+ const seen = /* @__PURE__ */ new Set();
373
+ return events.filter((event) => {
374
+ const key = `${event.type}:${event.summary.toLowerCase().replace(/[^\w\s]/g, "").trim().slice(0, 50)}`;
375
+ if (seen.has(key)) return false;
376
+ seen.add(key);
377
+ return true;
378
+ });
379
+ }
380
+ var DOMAIN_LABELS = {
381
+ planning: "Planning",
382
+ learning: "Learning",
383
+ creative: "Creative",
384
+ operational: "Operations",
385
+ research: "Research",
386
+ health: "Health",
387
+ social: "Social",
388
+ finance: "Finance",
389
+ reflection: "Reflection",
390
+ security: "Security"
391
+ };
392
+ function generateNarrative(sessionType, events, meta, provider) {
393
+ const time = new Date(meta.created).toLocaleTimeString("en-US", {
394
+ hour: "2-digit",
395
+ minute: "2-digit",
396
+ hour12: false
397
+ });
398
+ const parts = [];
399
+ parts.push(`${time} via ${provider}`);
400
+ const strategy = getExtractorStrategy(sessionType);
401
+ if (sessionType !== strategy) {
402
+ parts.push(`[${DOMAIN_LABELS[sessionType]}]`);
403
+ }
404
+ if (strategy === "coding") {
405
+ const actions = events.filter((e) => e.type === "action");
406
+ const errors = events.filter((e) => e.type === "error");
407
+ const commits = events.filter((e) => e.type === "commit");
408
+ const decisions = events.filter((e) => e.type === "decision");
409
+ if (decisions.length > 0) parts.push(decisions[0].summary);
410
+ parts.push(`${actions.length} actions`);
411
+ if (errors.length > 0) parts.push(`${errors.length} errors`);
412
+ if (commits.length > 0) parts.push(`${commits.length} commits`);
413
+ } else if (strategy === "discussion") {
414
+ const topics = events.filter((e) => e.type === "topic");
415
+ const decisions = events.filter((e) => e.type === "decision");
416
+ if (topics.length > 0) parts.push(`Discussed: ${topics.map((t) => t.summary).slice(0, 3).join(", ")}`);
417
+ if (decisions.length > 0) parts.push(`${decisions.length} decisions`);
418
+ } else if (strategy === "personal") {
419
+ const facts = events.filter((e) => e.type === "fact" || e.type === "preference");
420
+ if (facts.length > 0) parts.push(facts.map((f) => f.summary).join("; "));
421
+ } else {
422
+ parts.push(`${events.length} events`);
423
+ }
424
+ return parts.join(" \u2014 ");
425
+ }
426
+
427
+ // ../chitragupta/packages/smriti/src/fact-extractor.ts
428
+ var DEFAULT_CONFIG = {
429
+ minConfidence: 0.5,
430
+ useVectors: true,
431
+ vectorThreshold: 0.65
432
+ };
433
+ var FACT_PATTERNS = [
434
+ {
435
+ category: "identity",
436
+ patterns: [
437
+ /(?:my name is|i'm called|call me|i am|i'm)\s+([a-z][a-z\s]{1,30})/i,
438
+ /(?:they call me|people call me|everyone calls me)\s+([a-z][a-z\s]{1,30})/i
439
+ ],
440
+ confidence: 0.9
441
+ },
442
+ {
443
+ category: "location",
444
+ patterns: [
445
+ /(?:i live in|i'm from|i am from|based in|i'm based in|i reside in|living in|i'm in)\s+([a-z][a-z\s,]{1,50})/i,
446
+ /(?:my home is in|my city is|i'm located in|located in)\s+([a-z][a-z\s,]{1,50})/i
447
+ ],
448
+ confidence: 0.9
449
+ },
450
+ {
451
+ category: "work",
452
+ patterns: [
453
+ /(?:i work at|i work for|my company is|i'm at|employed at|employed by)\s+([a-z][a-z\s&.]{1,50})/i,
454
+ /(?:my job is|my role is|i'm a|i am a|i work as)\s+([a-z][a-z\s]{1,50})/i,
455
+ /(?:my team|our team|my department)\s+(?:is|works on)\s+([a-z][a-z\s]{1,50})/i
456
+ ],
457
+ confidence: 0.85
458
+ },
459
+ {
460
+ category: "preference",
461
+ patterns: [
462
+ /(?:always use|i prefer|i use|i like using|we use|we always)\s+([a-z][a-z\s./-]{1,50})/i,
463
+ /(?:never use|don't use|avoid|i hate|stop using)\s+([a-z][a-z\s./-]{1,50})/i,
464
+ /(?:my editor is|my ide is|i code in|i develop in|my stack is)\s+([a-z][a-z\s./-]{1,50})/i
465
+ ],
466
+ confidence: 0.85
467
+ },
468
+ {
469
+ category: "relationship",
470
+ patterns: [
471
+ /(?:my wife|my husband|my partner|my girlfriend|my boyfriend)\s+(?:is|'s)\s+([a-z][a-z\s]{1,30})/i,
472
+ /(?:my colleague|my friend|my boss|my manager|my coworker)\s+([a-z][a-z\s]{1,30})/i
473
+ ],
474
+ confidence: 0.85
475
+ },
476
+ {
477
+ category: "instruction",
478
+ patterns: [
479
+ /(?:remember that|don't forget|note that|keep in mind|save (?:that|this))\s+(.{5,200})/i,
480
+ /(?:from now on|going forward|always remember)\s+(.{5,200})/i
481
+ ],
482
+ confidence: 0.95
483
+ },
484
+ {
485
+ category: "personal",
486
+ patterns: [
487
+ /(?:my birthday is|i was born on|i was born in)\s+([a-z0-9][a-z0-9\s,]{1,30})/i,
488
+ /(?:my favorite|my favourite)\s+(\w+)\s+is\s+(.{1,50})/i,
489
+ /(?:i speak|my language is|my native language)\s+([a-z][a-z\s,]{1,30})/i
490
+ ],
491
+ confidence: 0.8
492
+ }
493
+ ];
494
+ var VECTOR_TEMPLATES = [
495
+ { category: "identity", template: "my name is" },
496
+ { category: "identity", template: "people call me" },
497
+ { category: "location", template: "i live in a city" },
498
+ { category: "location", template: "i am from a country" },
499
+ { category: "location", template: "i am based in a place" },
500
+ { category: "work", template: "i work at a company" },
501
+ { category: "work", template: "my job role is" },
502
+ { category: "preference", template: "i always prefer to use this tool" },
503
+ { category: "preference", template: "never use that library" },
504
+ { category: "relationship", template: "my family member is named" },
505
+ { category: "instruction", template: "remember this important fact" },
506
+ { category: "instruction", template: "always do this from now on" },
507
+ { category: "personal", template: "my birthday is on a date" },
508
+ { category: "personal", template: "my favorite thing is" }
509
+ ];
510
+ var FactExtractor = class {
511
+ config;
512
+ embeddingService;
513
+ templateEmbeddings = /* @__PURE__ */ new Map();
514
+ initialized = false;
515
+ /** Recently saved facts (dedup cache). Cleared periodically. */
516
+ recentFacts = /* @__PURE__ */ new Set();
517
+ recentFactsCleanupTimer = null;
518
+ constructor(config) {
519
+ this.config = { ...DEFAULT_CONFIG, ...config };
520
+ this.embeddingService = new EmbeddingService();
521
+ }
522
+ /**
523
+ * Initialize vector templates (lazy, on first use).
524
+ */
525
+ async ensureInitialized() {
526
+ if (this.initialized) return;
527
+ if (!this.config.useVectors) {
528
+ this.initialized = true;
529
+ return;
530
+ }
531
+ for (const tmpl of VECTOR_TEMPLATES) {
532
+ const embedding = fallbackEmbedding(tmpl.template);
533
+ this.templateEmbeddings.set(tmpl.template, embedding);
534
+ }
535
+ this.initialized = true;
536
+ this.recentFactsCleanupTimer = setInterval(() => {
537
+ this.recentFacts.clear();
538
+ }, 10 * 60 * 1e3);
539
+ if (this.recentFactsCleanupTimer.unref) {
540
+ this.recentFactsCleanupTimer.unref();
541
+ }
542
+ }
543
+ /**
544
+ * Extract facts from user input text.
545
+ * Uses pattern matching first, then vector similarity for misses.
546
+ */
547
+ async extract(text) {
548
+ await this.ensureInitialized();
549
+ const facts = [];
550
+ if (text.length < 5 || text.length > 5e3) return facts;
551
+ for (const rule of FACT_PATTERNS) {
552
+ for (const pattern of rule.patterns) {
553
+ const match = text.match(pattern);
554
+ if (match) {
555
+ const extracted = match[1]?.trim() || match[0].trim();
556
+ const fact = normalizeFact(rule.category, extracted);
557
+ if (fact) {
558
+ facts.push({
559
+ category: rule.category,
560
+ fact,
561
+ source: match[0].trim(),
562
+ confidence: rule.confidence,
563
+ method: "pattern"
564
+ });
565
+ }
566
+ }
567
+ }
568
+ }
569
+ if (this.config.useVectors && facts.length === 0) {
570
+ const inputEmbedding = fallbackEmbedding(text.toLowerCase().slice(0, 200));
571
+ let bestScore = 0;
572
+ let bestTemplate = null;
573
+ for (const tmpl of VECTOR_TEMPLATES) {
574
+ const tmplEmbedding = this.templateEmbeddings.get(tmpl.template);
575
+ if (!tmplEmbedding) continue;
576
+ const score = cosineSimilarity(inputEmbedding, tmplEmbedding);
577
+ if (score > bestScore) {
578
+ bestScore = score;
579
+ bestTemplate = tmpl;
580
+ }
581
+ }
582
+ if (bestTemplate && bestScore >= this.config.vectorThreshold) {
583
+ const fact = normalizeFact(bestTemplate.category, text.trim());
584
+ if (fact) {
585
+ facts.push({
586
+ category: bestTemplate.category,
587
+ fact,
588
+ source: text.trim().slice(0, 200),
589
+ confidence: Math.min(bestScore, 0.85),
590
+ // Cap vector confidence slightly lower
591
+ method: "vector"
592
+ });
593
+ }
594
+ }
595
+ }
596
+ return facts.filter((f) => f.confidence >= this.config.minConfidence);
597
+ }
598
+ /**
599
+ * Extract facts and save to memory immediately.
600
+ * Deduplicates against recently saved facts.
601
+ *
602
+ * @param text - User input text.
603
+ * @param scope - Memory scope to save to (default: global).
604
+ * @param projectScope - Optional project scope for project-level preferences.
605
+ * @returns Extracted and saved facts.
606
+ */
607
+ async extractAndSave(text, scope, projectScope) {
608
+ const facts = await this.extract(text);
609
+ if (facts.length === 0) return [];
610
+ const { appendMemory, getMemory } = await import("./memory-store-KNJPMBLQ.js");
611
+ const globalScope = scope ?? { type: "global" };
612
+ const existingMemory = getMemory(globalScope).toLowerCase();
613
+ for (const fact of facts) {
614
+ const dedupeKey = `${fact.category}:${fact.fact.toLowerCase().slice(0, 50)}`;
615
+ if (this.recentFacts.has(dedupeKey)) continue;
616
+ if (existingMemory.includes(fact.fact.toLowerCase().slice(0, 30))) continue;
617
+ const entry = `[${fact.category}] ${fact.fact}`;
618
+ if (fact.category === "preference" && projectScope) {
619
+ await appendMemory(projectScope, entry);
620
+ } else {
621
+ await appendMemory(globalScope, entry);
622
+ }
623
+ this.recentFacts.add(dedupeKey);
624
+ }
625
+ return facts;
626
+ }
627
+ /**
628
+ * Cleanup resources.
629
+ */
630
+ dispose() {
631
+ if (this.recentFactsCleanupTimer) {
632
+ clearInterval(this.recentFactsCleanupTimer);
633
+ this.recentFactsCleanupTimer = null;
634
+ }
635
+ }
636
+ };
637
+ function normalizeFact(category, raw) {
638
+ const cleaned = raw.replace(/[.!?,;:]+$/, "").trim();
639
+ if (cleaned.length < 2) return null;
640
+ switch (category) {
641
+ case "identity":
642
+ return `Name: ${capitalize(cleaned)}`;
643
+ case "location":
644
+ return `Lives in ${capitalize(cleaned)}`;
645
+ case "work":
646
+ return `Works at/as ${cleaned}`;
647
+ case "preference":
648
+ return `Preference: ${cleaned}`;
649
+ case "relationship":
650
+ return `Relationship: ${cleaned}`;
651
+ case "instruction":
652
+ return cleaned;
653
+ case "personal":
654
+ return cleaned;
655
+ default:
656
+ return cleaned;
657
+ }
658
+ }
659
+ function capitalize(s) {
660
+ return s.charAt(0).toUpperCase() + s.slice(1);
661
+ }
662
+ var _instance = null;
663
+ function getFactExtractor(config) {
664
+ if (!_instance) {
665
+ _instance = new FactExtractor(config);
666
+ }
667
+ return _instance;
668
+ }
669
+
670
+ // ../chitragupta/packages/smriti/src/day-consolidation.ts
671
+ function getDaysRoot() {
672
+ return path.join(getChitraguptaHome(), "days");
673
+ }
674
+ function getDayFilePath(date) {
675
+ const match = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
676
+ if (!match) throw new SessionError(`Invalid date: ${date}. Expected YYYY-MM-DD.`);
677
+ return path.join(getDaysRoot(), match[1], match[2], `${match[3]}.md`);
678
+ }
679
+ async function consolidateDay(date, options) {
680
+ const t0 = performance.now();
681
+ const dayPath = getDayFilePath(date);
682
+ if (!options?.force && fs.existsSync(dayPath)) {
683
+ const content = fs.readFileSync(dayPath, "utf-8");
684
+ const sessionCount = (content.match(/^### Session:/gm) || []).length;
685
+ return {
686
+ date,
687
+ filePath: dayPath,
688
+ sessionsProcessed: sessionCount,
689
+ projectCount: (content.match(/^## Project:/gm) || []).length,
690
+ totalTurns: 0,
691
+ extractedFacts: [],
692
+ durationMs: performance.now() - t0
693
+ };
694
+ }
695
+ let sessions;
696
+ if (options?.loadSessions) {
697
+ sessions = await options.loadSessions(date);
698
+ } else {
699
+ const { listSessionsByDate, listTurnsWithTimestamps, loadSession } = await import("./session-store-XKPGKXUS.js");
700
+ const metas = listSessionsByDate(date);
701
+ sessions = metas.map((meta) => {
702
+ try {
703
+ const turns = listTurnsWithTimestamps(meta.id, meta.project);
704
+ return { meta, turns };
705
+ } catch {
706
+ try {
707
+ const session = loadSession(meta.id, meta.project);
708
+ const baseTime = new Date(meta.created).getTime();
709
+ return {
710
+ meta,
711
+ turns: session.turns.map((t, i) => ({
712
+ ...t,
713
+ createdAt: baseTime + i * 1e3
714
+ }))
715
+ };
716
+ } catch {
717
+ return { meta, turns: [] };
718
+ }
719
+ }
720
+ });
721
+ }
722
+ if (sessions.length === 0) {
723
+ return {
724
+ date,
725
+ filePath: dayPath,
726
+ sessionsProcessed: 0,
727
+ projectCount: 0,
728
+ totalTurns: 0,
729
+ extractedFacts: [],
730
+ durationMs: performance.now() - t0
731
+ };
732
+ }
733
+ const projectMap = /* @__PURE__ */ new Map();
734
+ let totalTurns = 0;
735
+ for (const { meta, turns } of sessions) {
736
+ const key = meta.project;
737
+ if (!projectMap.has(key)) {
738
+ projectMap.set(key, {
739
+ project: meta.project,
740
+ branch: meta.branch,
741
+ providers: /* @__PURE__ */ new Set(),
742
+ sessions: [],
743
+ eventChains: [],
744
+ turns: [],
745
+ filesModified: /* @__PURE__ */ new Set()
746
+ });
747
+ }
748
+ const activity = projectMap.get(key);
749
+ activity.sessions.push(meta);
750
+ const provider = meta.metadata?.provider ?? meta.agent ?? "unknown";
751
+ activity.providers.add(provider);
752
+ if (meta.branch) activity.branch = meta.branch;
753
+ const eventChain = extractEventChain(meta, turns);
754
+ activity.eventChains.push(eventChain);
755
+ for (const turn of turns) {
756
+ totalTurns++;
757
+ activity.turns.push({ ...turn, sessionId: meta.id, createdAt: turn.createdAt });
758
+ }
759
+ for (const event of eventChain.events) {
760
+ if (event.files) {
761
+ for (const f of event.files) {
762
+ activity.filesModified.add(f);
763
+ }
764
+ }
765
+ }
766
+ activity.turns.sort((a, b) => a.createdAt - b.createdAt);
767
+ }
768
+ const extractedFacts = await extractFactsWithEngine(sessions);
769
+ const markdown = generateDayMarkdown(date, projectMap, sessions.length, totalTurns, extractedFacts);
770
+ const dir = path.dirname(dayPath);
771
+ fs.mkdirSync(dir, { recursive: true });
772
+ fs.writeFileSync(dayPath, markdown, "utf-8");
773
+ try {
774
+ const { indexConsolidationSummary } = await import("./consolidation-indexer-TOTTDZXW.js");
775
+ await indexConsolidationSummary("daily", date, markdown);
776
+ } catch {
777
+ }
778
+ return {
779
+ date,
780
+ filePath: dayPath,
781
+ sessionsProcessed: sessions.length,
782
+ projectCount: projectMap.size,
783
+ totalTurns,
784
+ extractedFacts,
785
+ durationMs: performance.now() - t0
786
+ };
787
+ }
788
+ async function extractFactsWithEngine(sessions) {
789
+ const facts = [];
790
+ const seen = /* @__PURE__ */ new Set();
791
+ try {
792
+ const extractor = new FactExtractor({ useVectors: true });
793
+ for (const { turns } of sessions) {
794
+ for (const turn of turns) {
795
+ if (turn.role !== "user") continue;
796
+ if (turn.content.length < 5 || turn.content.length > 5e3) continue;
797
+ const extracted = await extractor.extract(turn.content);
798
+ for (const fact of extracted) {
799
+ const key = fact.fact.toLowerCase().slice(0, 50);
800
+ if (!seen.has(key)) {
801
+ seen.add(key);
802
+ facts.push(`[${fact.category}] ${fact.fact}`);
803
+ }
804
+ }
805
+ }
806
+ }
807
+ extractor.dispose();
808
+ } catch {
809
+ return extractFactsFallback(sessions);
810
+ }
811
+ return facts;
812
+ }
813
+ function extractFactsFallback(sessions) {
814
+ const facts = [];
815
+ const factPatterns = [
816
+ /(?:i live in|i'm from|i am from|my home is in)\s+([^.!?\n]+)/i,
817
+ /(?:my name is|i'm called|i am called)\s+([^.!?\n]+)/i,
818
+ /(?:i work at|i work for|my company is)\s+([^.!?\n]+)/i,
819
+ /(?:i use|i prefer|my editor is|my ide is)\s+([^.!?\n]+)/i,
820
+ /(?:always use|never use|remember to|don't forget)\s+([^.!?\n]+)/i
821
+ ];
822
+ for (const { turns } of sessions) {
823
+ for (const turn of turns) {
824
+ if (turn.role !== "user") continue;
825
+ for (const pattern of factPatterns) {
826
+ const match = turn.content.match(pattern);
827
+ if (match) {
828
+ facts.push(match[0].trim());
829
+ }
830
+ }
831
+ }
832
+ }
833
+ return [...new Set(facts)];
834
+ }
835
+ function generateDayMarkdown(date, projectMap, sessionCount, totalTurns, facts) {
836
+ const lines = [];
837
+ const dayName = (/* @__PURE__ */ new Date(`${date}T12:00:00Z`)).toLocaleDateString("en-US", { weekday: "long" });
838
+ lines.push(`# ${date} \u2014 ${dayName}`);
839
+ lines.push("");
840
+ lines.push(`> ${sessionCount} sessions | ${projectMap.size} projects | ${totalTurns} turns`);
841
+ lines.push("");
842
+ if (facts.length > 0) {
843
+ lines.push("## Facts Learned");
844
+ lines.push("");
845
+ for (const fact of facts) {
846
+ lines.push(`- ${fact}`);
847
+ }
848
+ lines.push("");
849
+ }
850
+ for (const [, activity] of projectMap) {
851
+ lines.push(`## Project: ${activity.project}`);
852
+ lines.push("");
853
+ const meta = [];
854
+ if (activity.branch) meta.push(`**Branch**: ${activity.branch}`);
855
+ meta.push(`**Providers**: ${[...activity.providers].join(", ")}`);
856
+ meta.push(`**Sessions**: ${activity.sessions.length}`);
857
+ if (activity.filesModified.size > 0) {
858
+ meta.push(`**Files Modified**: ${activity.filesModified.size}`);
859
+ }
860
+ lines.push(meta.join(" | "));
861
+ lines.push("");
862
+ for (let i = 0; i < activity.sessions.length; i++) {
863
+ const session = activity.sessions[i];
864
+ const chain = activity.eventChains[i];
865
+ const time = new Date(session.created).toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", hour12: false });
866
+ const provider = session.metadata?.provider ?? session.agent ?? "unknown";
867
+ const turnCount = activity.turns.filter((t) => t.sessionId === session.id).length;
868
+ lines.push(`### Session: ${session.id}`);
869
+ lines.push(`*${time} | ${provider} | ${turnCount} turns | ${chain?.sessionType ?? "unknown"} session*`);
870
+ lines.push("");
871
+ if (chain) {
872
+ if (chain.narrative) {
873
+ lines.push(`> ${chain.narrative}`);
874
+ lines.push("");
875
+ }
876
+ if (chain.topics.length > 0) {
877
+ lines.push(`**Topics**: ${chain.topics.slice(0, 5).join(", ")}`);
878
+ lines.push("");
879
+ }
880
+ const keyEvents = chain.events.filter(
881
+ (e) => e.type === "decision" || e.type === "error" || e.type === "commit" || e.type === "fact" || e.type === "preference"
882
+ );
883
+ if (keyEvents.length > 0) {
884
+ for (const event of keyEvents.slice(0, 10)) {
885
+ const icon = eventIcon(event.type);
886
+ lines.push(`- ${icon} ${event.summary}`);
887
+ }
888
+ lines.push("");
889
+ }
890
+ }
891
+ }
892
+ const toolCounts = /* @__PURE__ */ new Map();
893
+ for (const chain of activity.eventChains) {
894
+ for (const event of chain.events) {
895
+ if (event.tool) {
896
+ toolCounts.set(event.tool, (toolCounts.get(event.tool) ?? 0) + 1);
897
+ }
898
+ }
899
+ }
900
+ if (toolCounts.size > 0) {
901
+ lines.push("### Tools Used");
902
+ lines.push("");
903
+ for (const [tool, count] of toolCounts) {
904
+ lines.push(`- **${tool}**: ${count} calls`);
905
+ }
906
+ lines.push("");
907
+ }
908
+ if (activity.filesModified.size > 0) {
909
+ lines.push("### Files Modified");
910
+ lines.push("");
911
+ for (const f of activity.filesModified) {
912
+ lines.push(`- ${f}`);
913
+ }
914
+ lines.push("");
915
+ }
916
+ }
917
+ lines.push("---");
918
+ lines.push(`*Consolidated by Chitragupta at ${(/* @__PURE__ */ new Date()).toISOString()}*`);
919
+ lines.push("");
920
+ return lines.join("\n");
921
+ }
922
+ function eventIcon(type) {
923
+ switch (type) {
924
+ case "decision":
925
+ return "**Decision**:";
926
+ case "error":
927
+ return "**Error**:";
928
+ case "commit":
929
+ return "**Commit**:";
930
+ case "fact":
931
+ return "**Fact**:";
932
+ case "preference":
933
+ return "**Pref**:";
934
+ case "question":
935
+ return "**Q**:";
936
+ case "action":
937
+ return "**Action**:";
938
+ case "topic":
939
+ return "**Topic**:";
940
+ case "problem":
941
+ return "**Problem**:";
942
+ default:
943
+ return "-";
944
+ }
945
+ }
946
+ function readDayFile(date) {
947
+ const dayPath = getDayFilePath(date);
948
+ if (!fs.existsSync(dayPath)) return null;
949
+ return fs.readFileSync(dayPath, "utf-8");
950
+ }
951
+ function listDayFiles() {
952
+ const daysRoot = getDaysRoot();
953
+ if (!fs.existsSync(daysRoot)) return [];
954
+ const dates = [];
955
+ try {
956
+ const years = fs.readdirSync(daysRoot, { withFileTypes: true });
957
+ for (const year of years) {
958
+ if (!year.isDirectory()) continue;
959
+ const yearPath = path.join(daysRoot, year.name);
960
+ const months = fs.readdirSync(yearPath, { withFileTypes: true });
961
+ for (const month of months) {
962
+ if (!month.isDirectory()) continue;
963
+ const monthPath = path.join(yearPath, month.name);
964
+ const days = fs.readdirSync(monthPath);
965
+ for (const day of days) {
966
+ if (!day.endsWith(".md")) continue;
967
+ const dd = day.replace(".md", "");
968
+ dates.push(`${year.name}-${month.name}-${dd}`);
969
+ }
970
+ }
971
+ }
972
+ } catch {
973
+ }
974
+ return dates.sort().reverse();
975
+ }
976
+ function searchDayFiles(query, options) {
977
+ const limit = options?.limit ?? 10;
978
+ const dates = listDayFiles();
979
+ const results = [];
980
+ const queryLower = query.toLowerCase();
981
+ for (const date of dates) {
982
+ if (results.length >= limit) break;
983
+ const content = readDayFile(date);
984
+ if (!content) continue;
985
+ const lines = content.split("\n");
986
+ const matches = [];
987
+ for (let i = 0; i < lines.length; i++) {
988
+ if (lines[i].toLowerCase().includes(queryLower)) {
989
+ matches.push({ line: i + 1, text: lines[i].trim() });
990
+ }
991
+ }
992
+ if (matches.length > 0) {
993
+ results.push({ date, matches: matches.slice(0, 5) });
994
+ }
995
+ }
996
+ return results;
997
+ }
998
+ function isDayConsolidated(date) {
999
+ return fs.existsSync(getDayFilePath(date));
1000
+ }
1001
+ async function getUnconsolidatedDates(limit) {
1002
+ const { listSessionDates } = await import("./session-store-XKPGKXUS.js");
1003
+ const sessionDates = listSessionDates();
1004
+ const unconsolidated = [];
1005
+ for (const date of sessionDates) {
1006
+ if (unconsolidated.length >= (limit ?? 30)) break;
1007
+ if (!isDayConsolidated(date)) {
1008
+ unconsolidated.push(date);
1009
+ }
1010
+ }
1011
+ return unconsolidated;
1012
+ }
1013
+
1014
+ export {
1015
+ detectSessionType,
1016
+ getExtractorStrategy,
1017
+ extractEventChain,
1018
+ FactExtractor,
1019
+ getFactExtractor,
1020
+ getDaysRoot,
1021
+ getDayFilePath,
1022
+ consolidateDay,
1023
+ readDayFile,
1024
+ listDayFiles,
1025
+ searchDayFiles,
1026
+ isDayConsolidated,
1027
+ getUnconsolidatedDates
1028
+ };
1029
+ //# sourceMappingURL=chunk-H76V36OF.js.map