opencode-mem 2.7.0 → 2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/services/client.d.ts.map +1 -1
- package/dist/services/client.js +4 -3
- package/dist/services/user-profile/profile-utils.d.ts +2 -2
- package/dist/services/user-profile/profile-utils.d.ts.map +1 -1
- package/dist/services/user-profile/profile-utils.js +45 -2
- package/dist/services/user-profile/user-profile-manager.d.ts +1 -0
- package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -1
- package/dist/services/user-profile/user-profile-manager.js +51 -23
- package/dist/web/app.js +65 -15
- package/dist/web/index.html +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/services/client.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA4CpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,aAAa,CAAkB;;YAIzB,UAAU;IAiBlB,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjE,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;IAIjC,SAAS,IAAI;QACX,WAAW,EAAE,OAAO,CAAC;QACrB,WAAW,EAAE,OAAO,CAAC;QACrB,KAAK,EAAE,OAAO,CAAC;KAChB;IAQD,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM;;;;;;;;;;;;;IA6BlD,SAAS,CACb,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,KAAK,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB;;;;;;;;;IA+DG,YAAY,CAAC,QAAQ,EAAE,MAAM;;;;;;;IA2B7B,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,SAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDpD;AAED,eAAO,MAAM,YAAY,mBAA0B,CAAC"}
|
package/dist/services/client.js
CHANGED
|
@@ -141,9 +141,10 @@ export class LocalMemoryClient {
|
|
|
141
141
|
async deleteMemory(memoryId) {
|
|
142
142
|
try {
|
|
143
143
|
await this.initialize();
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
|
|
144
|
+
const userShards = shardManager.getAllShards("user", "");
|
|
145
|
+
const projectShards = shardManager.getAllShards("project", "");
|
|
146
|
+
const allShards = [...userShards, ...projectShards];
|
|
147
|
+
for (const shard of allShards) {
|
|
147
148
|
const db = connectionManager.getConnection(shard.dbPath);
|
|
148
149
|
const memory = vectorSearch.getMemoryById(db, memoryId);
|
|
149
150
|
if (memory) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const safeArray: <T>(arr:
|
|
2
|
-
export declare const safeObject: <T extends object>(obj:
|
|
1
|
+
export declare const safeArray: <T>(arr: any) => T[];
|
|
2
|
+
export declare const safeObject: <T extends object>(obj: any, fallback: T) => T;
|
|
3
3
|
//# sourceMappingURL=profile-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-utils.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"profile-utils.d.ts","sourceRoot":"","sources":["../../../src/services/user-profile/profile-utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,GAAI,CAAC,EAAE,KAAK,GAAG,KAAG,CAAC,EA0BxC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,KAAK,GAAG,EAAE,UAAU,CAAC,KAAG,CAWpE,CAAC"}
|
|
@@ -1,2 +1,45 @@
|
|
|
1
|
-
export const safeArray = (arr) =>
|
|
2
|
-
|
|
1
|
+
export const safeArray = (arr) => {
|
|
2
|
+
if (!arr)
|
|
3
|
+
return [];
|
|
4
|
+
let result = arr;
|
|
5
|
+
if (typeof result === "string") {
|
|
6
|
+
try {
|
|
7
|
+
result = JSON.parse(result);
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
try {
|
|
11
|
+
result = JSON.parse(result.trim().replace(/,$/, ""));
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (!Array.isArray(result))
|
|
19
|
+
return [];
|
|
20
|
+
const flattened = [];
|
|
21
|
+
const walk = (item) => {
|
|
22
|
+
if (Array.isArray(item)) {
|
|
23
|
+
item.forEach(walk);
|
|
24
|
+
}
|
|
25
|
+
else if (item) {
|
|
26
|
+
flattened.push(item);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
walk(result);
|
|
30
|
+
return flattened;
|
|
31
|
+
};
|
|
32
|
+
export const safeObject = (obj, fallback) => {
|
|
33
|
+
if (!obj)
|
|
34
|
+
return fallback;
|
|
35
|
+
let result = obj;
|
|
36
|
+
if (typeof result === "string") {
|
|
37
|
+
try {
|
|
38
|
+
result = JSON.parse(result);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result && typeof result === "object" && !Array.isArray(result) ? result : fallback;
|
|
45
|
+
};
|
|
@@ -17,6 +17,7 @@ export declare class UserProfileManager {
|
|
|
17
17
|
private rowToProfile;
|
|
18
18
|
private rowToChangelog;
|
|
19
19
|
mergeProfileData(existing: UserProfileData, updates: Partial<UserProfileData>): UserProfileData;
|
|
20
|
+
private ensureArray;
|
|
20
21
|
}
|
|
21
22
|
export declare const userProfileManager: UserProfileManager;
|
|
22
23
|
//# sourceMappingURL=user-profile-manager.d.ts.map
|
|
@@ -1 +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;AAKrF,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;
|
|
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;AAKrF,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;IAoCT,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,eAAe,EAC5B,yBAAyB,EAAE,MAAM,EACjC,aAAa,EAAE,MAAM,GACpB,IAAI;IAmCP,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;IA0F/F,OAAO,CAAC,WAAW;CAWpB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC"}
|
|
@@ -59,6 +59,11 @@ export class UserProfileManager {
|
|
|
59
59
|
createProfile(userId, displayName, userName, userEmail, profileData, promptsAnalyzed) {
|
|
60
60
|
const id = `profile_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
61
61
|
const now = Date.now();
|
|
62
|
+
const cleanedData = {
|
|
63
|
+
preferences: safeArray(profileData.preferences),
|
|
64
|
+
patterns: safeArray(profileData.patterns),
|
|
65
|
+
workflows: safeArray(profileData.workflows),
|
|
66
|
+
};
|
|
62
67
|
const stmt = this.db.prepare(`
|
|
63
68
|
INSERT INTO user_profiles (
|
|
64
69
|
id, user_id, display_name, user_name, user_email,
|
|
@@ -67,12 +72,17 @@ export class UserProfileManager {
|
|
|
67
72
|
)
|
|
68
73
|
VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?, ?, 1)
|
|
69
74
|
`);
|
|
70
|
-
stmt.run(id, userId, displayName, userName, userEmail, JSON.stringify(
|
|
71
|
-
this.addChangelog(id, 1, "create", "Initial profile creation",
|
|
75
|
+
stmt.run(id, userId, displayName, userName, userEmail, JSON.stringify(cleanedData), now, now, promptsAnalyzed);
|
|
76
|
+
this.addChangelog(id, 1, "create", "Initial profile creation", cleanedData);
|
|
72
77
|
return id;
|
|
73
78
|
}
|
|
74
79
|
updateProfile(profileId, profileData, additionalPromptsAnalyzed, changeSummary) {
|
|
75
80
|
const now = Date.now();
|
|
81
|
+
const cleanedData = {
|
|
82
|
+
preferences: safeArray(profileData.preferences),
|
|
83
|
+
patterns: safeArray(profileData.patterns),
|
|
84
|
+
workflows: safeArray(profileData.workflows),
|
|
85
|
+
};
|
|
76
86
|
const getVersionStmt = this.db.prepare(`SELECT version FROM user_profiles WHERE id = ?`);
|
|
77
87
|
const versionRow = getVersionStmt.get(profileId);
|
|
78
88
|
const newVersion = (versionRow?.version || 0) + 1;
|
|
@@ -84,8 +94,8 @@ export class UserProfileManager {
|
|
|
84
94
|
total_prompts_analyzed = total_prompts_analyzed + ?
|
|
85
95
|
WHERE id = ?
|
|
86
96
|
`);
|
|
87
|
-
updateStmt.run(JSON.stringify(
|
|
88
|
-
this.addChangelog(profileId, newVersion, "update", changeSummary,
|
|
97
|
+
updateStmt.run(JSON.stringify(cleanedData), newVersion, now, additionalPromptsAnalyzed, profileId);
|
|
98
|
+
this.addChangelog(profileId, newVersion, "update", changeSummary, cleanedData);
|
|
89
99
|
this.cleanupOldChangelogs(profileId);
|
|
90
100
|
}
|
|
91
101
|
addChangelog(profileId, version, changeType, changeSummary, profileData) {
|
|
@@ -191,21 +201,25 @@ export class UserProfileManager {
|
|
|
191
201
|
}
|
|
192
202
|
mergeProfileData(existing, updates) {
|
|
193
203
|
const merged = {
|
|
194
|
-
preferences:
|
|
195
|
-
patterns:
|
|
196
|
-
workflows:
|
|
204
|
+
preferences: this.ensureArray(existing?.preferences),
|
|
205
|
+
patterns: this.ensureArray(existing?.patterns),
|
|
206
|
+
workflows: this.ensureArray(existing?.workflows),
|
|
197
207
|
};
|
|
198
208
|
if (updates.preferences) {
|
|
199
|
-
|
|
209
|
+
const incomingPrefs = this.ensureArray(updates.preferences);
|
|
210
|
+
for (const newPref of incomingPrefs) {
|
|
200
211
|
const existingIndex = merged.preferences.findIndex((p) => p.category === newPref.category && p.description === newPref.description);
|
|
201
212
|
if (existingIndex >= 0) {
|
|
202
|
-
const
|
|
203
|
-
if (
|
|
213
|
+
const existingItem = merged.preferences[existingIndex];
|
|
214
|
+
if (existingItem) {
|
|
204
215
|
merged.preferences[existingIndex] = {
|
|
205
216
|
...newPref,
|
|
206
|
-
confidence: Math.min(1,
|
|
217
|
+
confidence: Math.min(1, (existingItem.confidence || 0) + 0.1),
|
|
207
218
|
evidence: [
|
|
208
|
-
...new Set([
|
|
219
|
+
...new Set([
|
|
220
|
+
...this.ensureArray(existingItem.evidence),
|
|
221
|
+
...this.ensureArray(newPref.evidence),
|
|
222
|
+
]),
|
|
209
223
|
].slice(0, 5),
|
|
210
224
|
lastUpdated: Date.now(),
|
|
211
225
|
};
|
|
@@ -215,18 +229,19 @@ export class UserProfileManager {
|
|
|
215
229
|
merged.preferences.push({ ...newPref, lastUpdated: Date.now() });
|
|
216
230
|
}
|
|
217
231
|
}
|
|
218
|
-
merged.preferences.sort((a, b) => b.confidence - a.confidence);
|
|
232
|
+
merged.preferences.sort((a, b) => (b.confidence || 0) - (a.confidence || 0));
|
|
219
233
|
merged.preferences = merged.preferences.slice(0, CONFIG.userProfileMaxPreferences);
|
|
220
234
|
}
|
|
221
235
|
if (updates.patterns) {
|
|
222
|
-
|
|
236
|
+
const incomingPatterns = this.ensureArray(updates.patterns);
|
|
237
|
+
for (const newPattern of incomingPatterns) {
|
|
223
238
|
const existingIndex = merged.patterns.findIndex((p) => p.category === newPattern.category && p.description === newPattern.description);
|
|
224
239
|
if (existingIndex >= 0) {
|
|
225
|
-
const
|
|
226
|
-
if (
|
|
240
|
+
const existingItem = merged.patterns[existingIndex];
|
|
241
|
+
if (existingItem) {
|
|
227
242
|
merged.patterns[existingIndex] = {
|
|
228
243
|
...newPattern,
|
|
229
|
-
frequency:
|
|
244
|
+
frequency: (existingItem.frequency || 1) + 1,
|
|
230
245
|
lastSeen: Date.now(),
|
|
231
246
|
};
|
|
232
247
|
}
|
|
@@ -235,18 +250,19 @@ export class UserProfileManager {
|
|
|
235
250
|
merged.patterns.push({ ...newPattern, frequency: 1, lastSeen: Date.now() });
|
|
236
251
|
}
|
|
237
252
|
}
|
|
238
|
-
merged.patterns.sort((a, b) => b.frequency - a.frequency);
|
|
253
|
+
merged.patterns.sort((a, b) => (b.frequency || 0) - (a.frequency || 0));
|
|
239
254
|
merged.patterns = merged.patterns.slice(0, CONFIG.userProfileMaxPatterns);
|
|
240
255
|
}
|
|
241
256
|
if (updates.workflows) {
|
|
242
|
-
|
|
257
|
+
const incomingWorkflows = this.ensureArray(updates.workflows);
|
|
258
|
+
for (const newWorkflow of incomingWorkflows) {
|
|
243
259
|
const existingIndex = merged.workflows.findIndex((w) => w.description === newWorkflow.description);
|
|
244
260
|
if (existingIndex >= 0) {
|
|
245
|
-
const
|
|
246
|
-
if (
|
|
261
|
+
const existingItem = merged.workflows[existingIndex];
|
|
262
|
+
if (existingItem) {
|
|
247
263
|
merged.workflows[existingIndex] = {
|
|
248
264
|
...newWorkflow,
|
|
249
|
-
frequency:
|
|
265
|
+
frequency: (existingItem.frequency || 1) + 1,
|
|
250
266
|
};
|
|
251
267
|
}
|
|
252
268
|
}
|
|
@@ -254,10 +270,22 @@ export class UserProfileManager {
|
|
|
254
270
|
merged.workflows.push({ ...newWorkflow, frequency: 1 });
|
|
255
271
|
}
|
|
256
272
|
}
|
|
257
|
-
merged.workflows.sort((a, b) => b.frequency - a.frequency);
|
|
273
|
+
merged.workflows.sort((a, b) => (b.frequency || 0) - (a.frequency || 0));
|
|
258
274
|
merged.workflows = merged.workflows.slice(0, CONFIG.userProfileMaxWorkflows);
|
|
259
275
|
}
|
|
260
276
|
return merged;
|
|
261
277
|
}
|
|
278
|
+
ensureArray(val) {
|
|
279
|
+
if (typeof val === "string") {
|
|
280
|
+
try {
|
|
281
|
+
const parsed = JSON.parse(val);
|
|
282
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return Array.isArray(val) ? val : [];
|
|
289
|
+
}
|
|
262
290
|
}
|
|
263
291
|
export const userProfileManager = new UserProfileManager();
|
package/dist/web/app.js
CHANGED
|
@@ -170,6 +170,7 @@ function groupMemories(items) {
|
|
|
170
170
|
function renderCombinedCard(pair) {
|
|
171
171
|
const { memory, prompt } = pair;
|
|
172
172
|
const isSelected = state.selectedMemories.has(memory.id);
|
|
173
|
+
const isPinned = memory.isPinned || false;
|
|
173
174
|
const similarityHtml =
|
|
174
175
|
memory.similarity !== undefined
|
|
175
176
|
? `<span class="similarity-score">${Math.round(memory.similarity * 100)}%</span>`
|
|
@@ -180,8 +181,20 @@ function renderCombinedCard(pair) {
|
|
|
180
181
|
? `<div class="tags-list">${memory.tags.map((t) => `<span class="tag-badge">${escapeHtml(t)}</span>`).join("")}</div>`
|
|
181
182
|
: "";
|
|
182
183
|
|
|
184
|
+
const pinButton = isPinned
|
|
185
|
+
? `<button class="btn-pin pinned" onclick="unpinMemory('${memory.id}')" title="Unpin"><i data-lucide="pin" class="icon icon-filled"></i></button>`
|
|
186
|
+
: `<button class="btn-pin" onclick="pinMemory('${memory.id}')" title="Pin"><i data-lucide="pin" class="icon"></i></button>`;
|
|
187
|
+
|
|
188
|
+
const createdDate = formatDate(memory.createdAt);
|
|
189
|
+
const updatedDate =
|
|
190
|
+
memory.updatedAt && memory.updatedAt !== memory.createdAt ? formatDate(memory.updatedAt) : null;
|
|
191
|
+
|
|
192
|
+
const dateInfo = updatedDate
|
|
193
|
+
? `<span>Created: ${createdDate}</span><span>Updated: ${updatedDate}</span>`
|
|
194
|
+
: `<span>Created: ${createdDate}</span>`;
|
|
195
|
+
|
|
183
196
|
return `
|
|
184
|
-
<div class="combined-card ${isSelected ? "selected" : ""}" data-id="${memory.id}">
|
|
197
|
+
<div class="combined-card ${isSelected ? "selected" : ""} ${isPinned ? "pinned" : ""}" data-id="${memory.id}">
|
|
185
198
|
<div class="combined-prompt-section">
|
|
186
199
|
<div class="combined-header">
|
|
187
200
|
<span class="badge badge-prompt">USER PROMPT</span>
|
|
@@ -201,9 +214,12 @@ function renderCombinedCard(pair) {
|
|
|
201
214
|
<span class="badge badge-memory">MEMORY</span>
|
|
202
215
|
${memory.memoryType ? `<span class="badge badge-type">${memory.memoryType}</span>` : ""}
|
|
203
216
|
${similarityHtml}
|
|
217
|
+
${isPinned ? '<span class="badge badge-pinned">PINNED</span>' : ""}
|
|
204
218
|
<span class="memory-display-name">${escapeHtml(memory.displayName || memory.id)}</span>
|
|
205
219
|
</div>
|
|
206
220
|
<div class="memory-actions">
|
|
221
|
+
${pinButton}
|
|
222
|
+
<button class="btn-edit" onclick="editMemory('${memory.id}')"><i data-lucide="edit-3" class="icon"></i></button>
|
|
207
223
|
<button class="btn-delete" onclick="deleteMemoryWithLink('${memory.id}', true)">
|
|
208
224
|
<i data-lucide="trash-2" class="icon"></i> Delete Pair
|
|
209
225
|
</button>
|
|
@@ -211,6 +227,10 @@ function renderCombinedCard(pair) {
|
|
|
211
227
|
</div>
|
|
212
228
|
${tagsHtml}
|
|
213
229
|
<div class="memory-content markdown-content">${renderMarkdown(memory.content)}</div>
|
|
230
|
+
<div class="memory-footer">
|
|
231
|
+
${dateInfo}
|
|
232
|
+
<span>ID: ${memory.id}</span>
|
|
233
|
+
</div>
|
|
214
234
|
</div>
|
|
215
235
|
</div>
|
|
216
236
|
`;
|
|
@@ -907,10 +927,40 @@ function renderUserProfile() {
|
|
|
907
927
|
return;
|
|
908
928
|
}
|
|
909
929
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
930
|
+
let data = profile.profileData;
|
|
931
|
+
if (typeof data === "string") {
|
|
932
|
+
try {
|
|
933
|
+
data = JSON.parse(data);
|
|
934
|
+
} catch (e) {
|
|
935
|
+
console.error("Failed to parse profileData string", e);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
const parseField = (field) => {
|
|
940
|
+
if (!field) return [];
|
|
941
|
+
let result = field;
|
|
942
|
+
let lastResult = null;
|
|
943
|
+
while (typeof result === "string" && result !== lastResult) {
|
|
944
|
+
lastResult = result;
|
|
945
|
+
try {
|
|
946
|
+
result = JSON.parse(typeof jsonrepair === "function" ? jsonrepair(result) : result);
|
|
947
|
+
} catch {
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (!Array.isArray(result)) return [];
|
|
952
|
+
const flattened = [];
|
|
953
|
+
const walk = (item) => {
|
|
954
|
+
if (Array.isArray(item)) item.forEach(walk);
|
|
955
|
+
else if (item && typeof item === "object") flattened.push(item);
|
|
956
|
+
};
|
|
957
|
+
walk(result);
|
|
958
|
+
return flattened;
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
const preferences = parseField(data.preferences);
|
|
962
|
+
const patterns = parseField(data.patterns);
|
|
963
|
+
const workflows = parseField(data.workflows);
|
|
914
964
|
|
|
915
965
|
container.innerHTML = `
|
|
916
966
|
<div class="profile-header">
|
|
@@ -945,18 +995,18 @@ function renderUserProfile() {
|
|
|
945
995
|
: `
|
|
946
996
|
<div class="cards-grid">
|
|
947
997
|
${preferences
|
|
948
|
-
.sort((a, b) => b.confidence - a.confidence)
|
|
998
|
+
.sort((a, b) => (b.confidence || 0) - (a.confidence || 0))
|
|
949
999
|
.map(
|
|
950
1000
|
(p) => `
|
|
951
1001
|
<div class="compact-card preference-card">
|
|
952
1002
|
<div class="card-top">
|
|
953
|
-
<span class="category-tag">${escapeHtml(p.category)}</span>
|
|
954
|
-
<div class="confidence-ring" style="--p:${Math.round(p.confidence * 100)}">
|
|
955
|
-
<span>${Math.round(p.confidence * 100)}%</span>
|
|
1003
|
+
<span class="category-tag">${escapeHtml(p.category || "General")}</span>
|
|
1004
|
+
<div class="confidence-ring" style="--p:${Math.round((p.confidence || 0) * 100)}">
|
|
1005
|
+
<span>${Math.round((p.confidence || 0) * 100)}%</span>
|
|
956
1006
|
</div>
|
|
957
1007
|
</div>
|
|
958
1008
|
<div class="card-body">
|
|
959
|
-
<p class="card-text">${escapeHtml(p.description)}</p>
|
|
1009
|
+
<p class="card-text">${escapeHtml(p.description || "")}</p>
|
|
960
1010
|
</div>
|
|
961
1011
|
${
|
|
962
1012
|
p.evidence && p.evidence.length > 0
|
|
@@ -989,10 +1039,10 @@ function renderUserProfile() {
|
|
|
989
1039
|
(p) => `
|
|
990
1040
|
<div class="compact-card pattern-card">
|
|
991
1041
|
<div class="card-top">
|
|
992
|
-
<span class="category-tag">${escapeHtml(p.category)}</span>
|
|
1042
|
+
<span class="category-tag">${escapeHtml(p.category || "General")}</span>
|
|
993
1043
|
</div>
|
|
994
1044
|
<div class="card-body">
|
|
995
|
-
<p class="card-text">${escapeHtml(p.description)}</p>
|
|
1045
|
+
<p class="card-text">${escapeHtml(p.description || "")}</p>
|
|
996
1046
|
</div>
|
|
997
1047
|
</div>
|
|
998
1048
|
`
|
|
@@ -1014,16 +1064,16 @@ function renderUserProfile() {
|
|
|
1014
1064
|
.map(
|
|
1015
1065
|
(w) => `
|
|
1016
1066
|
<div class="workflow-row">
|
|
1017
|
-
<div class="workflow-title">${escapeHtml(w.description)}</div>
|
|
1067
|
+
<div class="workflow-title">${escapeHtml(w.description || "")}</div>
|
|
1018
1068
|
<div class="workflow-steps-horizontal">
|
|
1019
|
-
${w.steps
|
|
1069
|
+
${(w.steps || [])
|
|
1020
1070
|
.map(
|
|
1021
1071
|
(step, i) => `
|
|
1022
1072
|
<div class="step-node">
|
|
1023
1073
|
<span class="step-idx">${i + 1}</span>
|
|
1024
1074
|
<span class="step-content">${escapeHtml(step)}</span>
|
|
1025
1075
|
</div>
|
|
1026
|
-
${i < w.steps.length - 1 ? '<i data-lucide="arrow-right" class="step-arrow"></i>' : ""}
|
|
1076
|
+
${i < (w.steps || []).length - 1 ? '<i data-lucide="arrow-right" class="step-arrow"></i>' : ""}
|
|
1027
1077
|
`
|
|
1028
1078
|
)
|
|
1029
1079
|
.join("")}
|
package/dist/web/index.html
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
<script src="https://unpkg.com/lucide@latest"></script>
|
|
10
10
|
<script src="https://cdn.jsdelivr.net/npm/marked@17.0.1/lib/marked.umd.min.js"></script>
|
|
11
11
|
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.2/dist/purify.min.js"></script>
|
|
12
|
+
<script src="https://cdn.jsdelivr.net/npm/jsonrepair@latest/lib/umd/jsonrepair.min.js"></script>
|
|
12
13
|
</head>
|
|
13
14
|
<body>
|
|
14
15
|
<div class="container">
|