opencode-mem 2.0.1 → 2.2.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 (45) hide show
  1. package/README.md +54 -11
  2. package/dist/config.d.ts +5 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +62 -6
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +18 -11
  7. package/dist/plugin.d.ts.map +1 -1
  8. package/dist/plugin.js +0 -4
  9. package/dist/services/ai/providers/anthropic-messages.d.ts.map +1 -1
  10. package/dist/services/ai/providers/anthropic-messages.js +11 -17
  11. package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -1
  12. package/dist/services/ai/providers/openai-chat-completion.js +11 -17
  13. package/dist/services/ai/providers/openai-responses.d.ts.map +1 -1
  14. package/dist/services/ai/providers/openai-responses.js +11 -17
  15. package/dist/services/api-handlers.d.ts +4 -0
  16. package/dist/services/api-handlers.d.ts.map +1 -1
  17. package/dist/services/api-handlers.js +155 -1
  18. package/dist/services/auto-capture.js +2 -2
  19. package/dist/services/client.d.ts +1 -16
  20. package/dist/services/client.d.ts.map +1 -1
  21. package/dist/services/client.js +0 -35
  22. package/dist/services/context.d.ts +1 -7
  23. package/dist/services/context.d.ts.map +1 -1
  24. package/dist/services/context.js +6 -14
  25. package/dist/services/deduplication-service.d.ts.map +1 -1
  26. package/dist/services/deduplication-service.js +1 -3
  27. package/dist/services/logger.js +1 -1
  28. package/dist/services/user-memory-learning.d.ts.map +1 -1
  29. package/dist/services/user-memory-learning.js +122 -84
  30. package/dist/services/user-profile/profile-context.d.ts +2 -0
  31. package/dist/services/user-profile/profile-context.d.ts.map +1 -0
  32. package/dist/services/user-profile/profile-context.js +40 -0
  33. package/dist/services/user-profile/types.d.ts +51 -0
  34. package/dist/services/user-profile/types.d.ts.map +1 -0
  35. package/dist/services/user-profile/types.js +1 -0
  36. package/dist/services/user-profile/user-profile-manager.d.ts +22 -0
  37. package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -0
  38. package/dist/services/user-profile/user-profile-manager.js +267 -0
  39. package/dist/services/web-server-worker.js +29 -1
  40. package/dist/types/index.d.ts +1 -3
  41. package/dist/types/index.d.ts.map +1 -1
  42. package/dist/web/app.js +249 -29
  43. package/dist/web/index.html +31 -5
  44. package/dist/web/styles.css +309 -0
  45. package/package.json +1 -1
@@ -0,0 +1,40 @@
1
+ import { userProfileManager } from "./user-profile-manager.js";
2
+ export function getUserProfileContext(userId) {
3
+ const profile = userProfileManager.getActiveProfile(userId);
4
+ if (!profile) {
5
+ return null;
6
+ }
7
+ const profileData = JSON.parse(profile.profileData);
8
+ const parts = [];
9
+ if (profileData.preferences.length > 0) {
10
+ parts.push("User Preferences:");
11
+ profileData.preferences
12
+ .sort((a, b) => b.confidence - a.confidence)
13
+ .slice(0, 5)
14
+ .forEach((pref) => {
15
+ parts.push(`- [${pref.category}] ${pref.description}`);
16
+ });
17
+ }
18
+ if (profileData.patterns.length > 0) {
19
+ parts.push("\nUser Patterns:");
20
+ profileData.patterns
21
+ .sort((a, b) => b.frequency - a.frequency)
22
+ .slice(0, 5)
23
+ .forEach((pattern) => {
24
+ parts.push(`- [${pattern.category}] ${pattern.description}`);
25
+ });
26
+ }
27
+ if (profileData.workflows.length > 0) {
28
+ parts.push("\nUser Workflows:");
29
+ profileData.workflows
30
+ .sort((a, b) => b.frequency - a.frequency)
31
+ .slice(0, 3)
32
+ .forEach((workflow) => {
33
+ parts.push(`- ${workflow.description}`);
34
+ });
35
+ }
36
+ if (parts.length === 0) {
37
+ return null;
38
+ }
39
+ return parts.join("\n");
40
+ }
@@ -0,0 +1,51 @@
1
+ export interface UserProfilePreference {
2
+ category: string;
3
+ description: string;
4
+ confidence: number;
5
+ evidence: string[];
6
+ lastUpdated: number;
7
+ }
8
+ export interface UserProfilePattern {
9
+ category: string;
10
+ description: string;
11
+ frequency: number;
12
+ lastSeen: number;
13
+ }
14
+ export interface UserProfileWorkflow {
15
+ description: string;
16
+ steps: string[];
17
+ frequency: number;
18
+ }
19
+ export interface UserProfileSkillLevel {
20
+ overall: string;
21
+ domains: Record<string, string>;
22
+ }
23
+ export interface UserProfileData {
24
+ preferences: UserProfilePreference[];
25
+ patterns: UserProfilePattern[];
26
+ workflows: UserProfileWorkflow[];
27
+ skillLevel: UserProfileSkillLevel;
28
+ }
29
+ export interface UserProfile {
30
+ id: string;
31
+ userId: string;
32
+ displayName: string;
33
+ userName: string;
34
+ userEmail: string;
35
+ profileData: string;
36
+ version: number;
37
+ createdAt: number;
38
+ lastAnalyzedAt: number;
39
+ totalPromptsAnalyzed: number;
40
+ isActive: boolean;
41
+ }
42
+ export interface UserProfileChangelog {
43
+ id: string;
44
+ profileId: string;
45
+ version: number;
46
+ changeType: string;
47
+ changeSummary: string;
48
+ profileDataSnapshot: string;
49
+ createdAt: number;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,qBAAqB,EAAE,CAAC;IACrC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,UAAU,EAAE,qBAAqB,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { UserProfile, UserProfileChangelog, UserProfileData } from "./types.js";
2
+ export declare class UserProfileManager {
3
+ private db;
4
+ private readonly dbPath;
5
+ constructor();
6
+ private initDatabase;
7
+ getActiveProfile(userId: string): UserProfile | null;
8
+ createProfile(userId: string, displayName: string, userName: string, userEmail: string, profileData: UserProfileData, promptsAnalyzed: number): string;
9
+ updateProfile(profileId: string, profileData: UserProfileData, additionalPromptsAnalyzed: number, changeSummary: string): void;
10
+ private addChangelog;
11
+ private cleanupOldChangelogs;
12
+ getProfileChangelogs(profileId: string, limit?: number): UserProfileChangelog[];
13
+ applyConfidenceDecay(profileId: string): void;
14
+ deleteProfile(profileId: string): void;
15
+ getProfileById(profileId: string): UserProfile | null;
16
+ getAllActiveProfiles(): UserProfile[];
17
+ private rowToProfile;
18
+ private rowToChangelog;
19
+ mergeProfileData(existing: UserProfileData, updates: Partial<UserProfileData>): UserProfileData;
20
+ }
21
+ export declare const userProfileManager: UserProfileManager;
22
+ //# sourceMappingURL=user-profile-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-profile-manager.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/user-profile-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIrF,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;;IAQhC,OAAO,CAAC,YAAY;IA0CpB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAapD,aAAa,CACX,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,eAAe,EAAE,MAAM,GACtB,MAAM;IA8BT,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,yBAAyB,EAAE,MAAM,EACjC,aAAa,EAAE,MAAM,GACpB,IAAI;IA6BP,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,oBAAoB;IAiB5B,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,oBAAoB,EAAE;IAYnF,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IA2B7C,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKtC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAOrD,oBAAoB,IAAI,WAAW,EAAE;IAMrC,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,cAAc;IAYtB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe;CAyFhG;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
@@ -0,0 +1,267 @@
1
+ import { Database } from "bun:sqlite";
2
+ import { join } from "node:path";
3
+ import { connectionManager } from "../sqlite/connection-manager.js";
4
+ import { CONFIG } from "../../config.js";
5
+ const USER_PROFILES_DB_NAME = "user-profiles.db";
6
+ export class UserProfileManager {
7
+ db;
8
+ dbPath;
9
+ constructor() {
10
+ this.dbPath = join(CONFIG.storagePath, USER_PROFILES_DB_NAME);
11
+ this.db = connectionManager.getConnection(this.dbPath);
12
+ this.initDatabase();
13
+ }
14
+ initDatabase() {
15
+ this.db.run(`
16
+ CREATE TABLE IF NOT EXISTS user_profiles (
17
+ id TEXT PRIMARY KEY,
18
+ user_id TEXT NOT NULL UNIQUE,
19
+ display_name TEXT NOT NULL,
20
+ user_name TEXT NOT NULL,
21
+ user_email TEXT NOT NULL,
22
+ profile_data TEXT NOT NULL,
23
+ version INTEGER NOT NULL DEFAULT 1,
24
+ created_at INTEGER NOT NULL,
25
+ last_analyzed_at INTEGER NOT NULL,
26
+ total_prompts_analyzed INTEGER NOT NULL DEFAULT 0,
27
+ is_active BOOLEAN NOT NULL DEFAULT 1
28
+ )
29
+ `);
30
+ this.db.run(`
31
+ CREATE TABLE IF NOT EXISTS user_profile_changelogs (
32
+ id TEXT PRIMARY KEY,
33
+ profile_id TEXT NOT NULL,
34
+ version INTEGER NOT NULL,
35
+ change_type TEXT NOT NULL,
36
+ change_summary TEXT NOT NULL,
37
+ profile_data_snapshot TEXT NOT NULL,
38
+ created_at INTEGER NOT NULL,
39
+ FOREIGN KEY (profile_id) REFERENCES user_profiles(id) ON DELETE CASCADE
40
+ )
41
+ `);
42
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_user_profiles_user_id ON user_profiles(user_id)");
43
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_user_profiles_is_active ON user_profiles(is_active)");
44
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_user_profile_changelogs_profile_id ON user_profile_changelogs(profile_id)");
45
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_user_profile_changelogs_version ON user_profile_changelogs(version DESC)");
46
+ }
47
+ getActiveProfile(userId) {
48
+ const stmt = this.db.prepare(`
49
+ SELECT * FROM user_profiles
50
+ WHERE user_id = ? AND is_active = 1
51
+ LIMIT 1
52
+ `);
53
+ const row = stmt.get(userId);
54
+ if (!row)
55
+ return null;
56
+ return this.rowToProfile(row);
57
+ }
58
+ createProfile(userId, displayName, userName, userEmail, profileData, promptsAnalyzed) {
59
+ const id = `profile_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
60
+ const now = Date.now();
61
+ const stmt = this.db.prepare(`
62
+ INSERT INTO user_profiles (
63
+ id, user_id, display_name, user_name, user_email,
64
+ profile_data, version, created_at, last_analyzed_at,
65
+ total_prompts_analyzed, is_active
66
+ )
67
+ VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, 1)
68
+ `);
69
+ stmt.run(id, userId, displayName, userName, userEmail, JSON.stringify(profileData), now, now, promptsAnalyzed);
70
+ this.addChangelog(id, 1, "create", "Initial profile creation", profileData);
71
+ return id;
72
+ }
73
+ updateProfile(profileId, profileData, additionalPromptsAnalyzed, changeSummary) {
74
+ const now = Date.now();
75
+ const getVersionStmt = this.db.prepare(`SELECT version FROM user_profiles WHERE id = ?`);
76
+ const versionRow = getVersionStmt.get(profileId);
77
+ const newVersion = (versionRow?.version || 0) + 1;
78
+ const updateStmt = this.db.prepare(`
79
+ UPDATE user_profiles
80
+ SET profile_data = ?,
81
+ version = ?,
82
+ last_analyzed_at = ?,
83
+ total_prompts_analyzed = total_prompts_analyzed + ?
84
+ WHERE id = ?
85
+ `);
86
+ updateStmt.run(JSON.stringify(profileData), newVersion, now, additionalPromptsAnalyzed, profileId);
87
+ this.addChangelog(profileId, newVersion, "update", changeSummary, profileData);
88
+ this.cleanupOldChangelogs(profileId);
89
+ }
90
+ addChangelog(profileId, version, changeType, changeSummary, profileData) {
91
+ const id = `changelog_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
92
+ const now = Date.now();
93
+ const stmt = this.db.prepare(`
94
+ INSERT INTO user_profile_changelogs (
95
+ id, profile_id, version, change_type, change_summary,
96
+ profile_data_snapshot, created_at
97
+ )
98
+ VALUES (?, ?, ?, ?, ?, ?, ?)
99
+ `);
100
+ stmt.run(id, profileId, version, changeType, changeSummary, JSON.stringify(profileData), now);
101
+ }
102
+ cleanupOldChangelogs(profileId) {
103
+ const retentionCount = CONFIG.userProfileChangelogRetentionCount;
104
+ const stmt = this.db.prepare(`
105
+ DELETE FROM user_profile_changelogs
106
+ WHERE profile_id = ?
107
+ AND id NOT IN (
108
+ SELECT id FROM user_profile_changelogs
109
+ WHERE profile_id = ?
110
+ ORDER BY version DESC
111
+ LIMIT ?
112
+ )
113
+ `);
114
+ stmt.run(profileId, profileId, retentionCount);
115
+ }
116
+ getProfileChangelogs(profileId, limit = 10) {
117
+ const stmt = this.db.prepare(`
118
+ SELECT * FROM user_profile_changelogs
119
+ WHERE profile_id = ?
120
+ ORDER BY version DESC
121
+ LIMIT ?
122
+ `);
123
+ const rows = stmt.all(profileId, limit);
124
+ return rows.map((row) => this.rowToChangelog(row));
125
+ }
126
+ applyConfidenceDecay(profileId) {
127
+ const profile = this.getProfileById(profileId);
128
+ if (!profile)
129
+ return;
130
+ const profileData = JSON.parse(profile.profileData);
131
+ const now = Date.now();
132
+ const decayThreshold = CONFIG.userProfileConfidenceDecayDays * 24 * 60 * 60 * 1000;
133
+ let hasChanges = false;
134
+ profileData.preferences = profileData.preferences
135
+ .map((pref) => {
136
+ const age = now - pref.lastUpdated;
137
+ if (age > decayThreshold) {
138
+ hasChanges = true;
139
+ const decayFactor = Math.max(0.5, 1 - (age - decayThreshold) / decayThreshold);
140
+ return { ...pref, confidence: pref.confidence * decayFactor };
141
+ }
142
+ return pref;
143
+ })
144
+ .filter((pref) => pref.confidence >= 0.3);
145
+ if (hasChanges) {
146
+ this.updateProfile(profileId, profileData, 0, "Applied confidence decay to preferences");
147
+ }
148
+ }
149
+ deleteProfile(profileId) {
150
+ const stmt = this.db.prepare(`DELETE FROM user_profiles WHERE id = ?`);
151
+ stmt.run(profileId);
152
+ }
153
+ getProfileById(profileId) {
154
+ const stmt = this.db.prepare(`SELECT * FROM user_profiles WHERE id = ?`);
155
+ const row = stmt.get(profileId);
156
+ if (!row)
157
+ return null;
158
+ return this.rowToProfile(row);
159
+ }
160
+ getAllActiveProfiles() {
161
+ const stmt = this.db.prepare(`SELECT * FROM user_profiles WHERE is_active = 1`);
162
+ const rows = stmt.all();
163
+ return rows.map((row) => this.rowToProfile(row));
164
+ }
165
+ rowToProfile(row) {
166
+ return {
167
+ id: row.id,
168
+ userId: row.user_id,
169
+ displayName: row.display_name,
170
+ userName: row.user_name,
171
+ userEmail: row.user_email,
172
+ profileData: row.profile_data,
173
+ version: row.version,
174
+ createdAt: row.created_at,
175
+ lastAnalyzedAt: row.last_analyzed_at,
176
+ totalPromptsAnalyzed: row.total_prompts_analyzed,
177
+ isActive: row.is_active === 1,
178
+ };
179
+ }
180
+ rowToChangelog(row) {
181
+ return {
182
+ id: row.id,
183
+ profileId: row.profile_id,
184
+ version: row.version,
185
+ changeType: row.change_type,
186
+ changeSummary: row.change_summary,
187
+ profileDataSnapshot: row.profile_data_snapshot,
188
+ createdAt: row.created_at,
189
+ };
190
+ }
191
+ mergeProfileData(existing, updates) {
192
+ const merged = {
193
+ preferences: [...existing.preferences],
194
+ patterns: [...existing.patterns],
195
+ workflows: [...existing.workflows],
196
+ skillLevel: { ...existing.skillLevel },
197
+ };
198
+ if (updates.preferences) {
199
+ for (const newPref of updates.preferences) {
200
+ const existingIndex = merged.preferences.findIndex((p) => p.category === newPref.category && p.description === newPref.description);
201
+ if (existingIndex >= 0) {
202
+ const existing = merged.preferences[existingIndex];
203
+ if (existing) {
204
+ merged.preferences[existingIndex] = {
205
+ ...newPref,
206
+ confidence: Math.min(1, existing.confidence + 0.1),
207
+ evidence: [...new Set([...existing.evidence, ...newPref.evidence])].slice(0, 5),
208
+ lastUpdated: Date.now(),
209
+ };
210
+ }
211
+ }
212
+ else {
213
+ merged.preferences.push({ ...newPref, lastUpdated: Date.now() });
214
+ }
215
+ }
216
+ merged.preferences.sort((a, b) => b.confidence - a.confidence);
217
+ merged.preferences = merged.preferences.slice(0, CONFIG.userProfileMaxPreferences);
218
+ }
219
+ if (updates.patterns) {
220
+ for (const newPattern of updates.patterns) {
221
+ const existingIndex = merged.patterns.findIndex((p) => p.category === newPattern.category && p.description === newPattern.description);
222
+ if (existingIndex >= 0) {
223
+ const existing = merged.patterns[existingIndex];
224
+ if (existing) {
225
+ merged.patterns[existingIndex] = {
226
+ ...newPattern,
227
+ frequency: existing.frequency + 1,
228
+ lastSeen: Date.now(),
229
+ };
230
+ }
231
+ }
232
+ else {
233
+ merged.patterns.push({ ...newPattern, frequency: 1, lastSeen: Date.now() });
234
+ }
235
+ }
236
+ merged.patterns.sort((a, b) => b.frequency - a.frequency);
237
+ merged.patterns = merged.patterns.slice(0, CONFIG.userProfileMaxPatterns);
238
+ }
239
+ if (updates.workflows) {
240
+ for (const newWorkflow of updates.workflows) {
241
+ const existingIndex = merged.workflows.findIndex((w) => w.description === newWorkflow.description);
242
+ if (existingIndex >= 0) {
243
+ const existing = merged.workflows[existingIndex];
244
+ if (existing) {
245
+ merged.workflows[existingIndex] = {
246
+ ...newWorkflow,
247
+ frequency: existing.frequency + 1,
248
+ };
249
+ }
250
+ }
251
+ else {
252
+ merged.workflows.push({ ...newWorkflow, frequency: 1 });
253
+ }
254
+ }
255
+ merged.workflows.sort((a, b) => b.frequency - a.frequency);
256
+ merged.workflows = merged.workflows.slice(0, CONFIG.userProfileMaxWorkflows);
257
+ }
258
+ if (updates.skillLevel) {
259
+ merged.skillLevel = {
260
+ overall: updates.skillLevel.overall || merged.skillLevel.overall,
261
+ domains: { ...merged.skillLevel.domains, ...updates.skillLevel.domains },
262
+ };
263
+ }
264
+ return merged;
265
+ }
266
+ }
267
+ export const userProfileManager = new UserProfileManager();
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join, dirname } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { handleListTags, handleListMemories, handleAddMemory, handleDeleteMemory, handleBulkDelete, handleUpdateMemory, handleSearch, handleStats, handlePinMemory, handleUnpinMemory, handleRunCleanup, handleRunDeduplication, handleDetectMigration, handleRunMigration, handleDeletePrompt, handleBulkDeletePrompts, } from "./api-handlers.js";
4
+ import { handleListTags, handleListMemories, handleAddMemory, handleDeleteMemory, handleBulkDelete, handleUpdateMemory, handleSearch, handleStats, handlePinMemory, handleUnpinMemory, handleRunCleanup, handleRunDeduplication, handleDetectMigration, handleRunMigration, handleDeletePrompt, handleBulkDeletePrompts, handleGetUserProfile, handleGetProfileChangelog, handleGetProfileSnapshot, handleRefreshProfile, } from "./api-handlers.js";
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = dirname(__filename);
7
7
  let server = null;
@@ -133,6 +133,34 @@ async function handleRequest(req) {
133
133
  const result = await handleBulkDeletePrompts(body.ids || [], cascade);
134
134
  return jsonResponse(result);
135
135
  }
136
+ if (path === "/api/user-profile" && method === "GET") {
137
+ const userId = url.searchParams.get("userId") || undefined;
138
+ const result = await handleGetUserProfile(userId);
139
+ return jsonResponse(result);
140
+ }
141
+ if (path === "/api/user-profile/changelog" && method === "GET") {
142
+ const profileId = url.searchParams.get("profileId");
143
+ const limit = parseInt(url.searchParams.get("limit") || "5");
144
+ if (!profileId) {
145
+ return jsonResponse({ success: false, error: "profileId parameter required" });
146
+ }
147
+ const result = await handleGetProfileChangelog(profileId, limit);
148
+ return jsonResponse(result);
149
+ }
150
+ if (path === "/api/user-profile/snapshot" && method === "GET") {
151
+ const changelogId = url.searchParams.get("chlogId");
152
+ if (!changelogId) {
153
+ return jsonResponse({ success: false, error: "changelogId parameter required" });
154
+ }
155
+ const result = await handleGetProfileSnapshot(changelogId);
156
+ return jsonResponse(result);
157
+ }
158
+ if (path === "/api/user-profile/refresh" && method === "POST") {
159
+ const body = (await req.json().catch(() => ({})));
160
+ const userId = body.userId || undefined;
161
+ const result = await handleRefreshProfile(userId);
162
+ return jsonResponse(result);
163
+ }
136
164
  return new Response("Not Found", { status: 404 });
137
165
  }
138
166
  catch (error) {
@@ -32,13 +32,11 @@ export interface ConversationIngestResponse {
32
32
  }
33
33
  export interface MemoryMetadata {
34
34
  type?: MemoryType;
35
- source?: "manual" | "auto-capture" | "import" | "api" | "user-learning";
35
+ source?: "manual" | "auto-capture" | "import" | "api";
36
36
  tool?: string;
37
37
  sessionID?: string;
38
38
  reasoning?: string;
39
39
  captureTimestamp?: number;
40
- promptCount?: number;
41
- analysisTimestamp?: number;
42
40
  promptId?: string;
43
41
  displayName?: string;
44
42
  userName?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExE,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,CAAC;IACxE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,kBAAkB,GAAG,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExE,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,GAAG,uBAAuB,EAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,kBAAkB,GAAG,WAAW,CAAC"}