@awareness-sdk/local 0.2.0 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awareness-sdk/local",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Local-first AI agent memory system. No account needed.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -375,6 +375,10 @@ export class CloudSync {
375
375
  console.error(`${LOG_PREFIX} syncToCloud failed:`, err.message);
376
376
  }
377
377
 
378
+ if (synced > 0) {
379
+ this._recordSyncEvent('memories', { count: synced, direction: 'push' });
380
+ }
381
+
378
382
  return { synced, errors };
379
383
  }
380
384
 
@@ -426,6 +430,7 @@ export class CloudSync {
426
430
 
427
431
  if (pulled > 0) {
428
432
  console.log(`${LOG_PREFIX} Pulled ${pulled} memories from cloud`);
433
+ this._recordSyncEvent('memories', { count: pulled, direction: 'pull' });
429
434
  }
430
435
  } catch (err) {
431
436
  console.error(`${LOG_PREFIX} pullFromCloud failed:`, err.message);
@@ -496,6 +501,7 @@ export class CloudSync {
496
501
 
497
502
  if (synced > 0) {
498
503
  console.log(`${LOG_PREFIX} Pushed ${synced} knowledge cards to cloud` + (errors ? ` (${errors} errors)` : ''));
504
+ this._recordSyncEvent('insights', { count: synced, direction: 'push' });
499
505
  }
500
506
  } catch (err) {
501
507
  console.error(`${LOG_PREFIX} syncInsightsToCloud failed:`, err.message);
@@ -563,6 +569,7 @@ export class CloudSync {
563
569
 
564
570
  if (synced > 0) {
565
571
  console.log(`${LOG_PREFIX} Pushed ${synced} tasks to cloud` + (errors ? ` (${errors} errors)` : ''));
572
+ this._recordSyncEvent('tasks', { count: synced, direction: 'push' });
566
573
  }
567
574
  } catch (err) {
568
575
  console.error(`${LOG_PREFIX} syncTasksToCloud failed:`, err.message);
@@ -1171,6 +1178,51 @@ export class CloudSync {
1171
1178
  }
1172
1179
  }
1173
1180
 
1181
+ // =========================================================================
1182
+ // Public — sync history
1183
+ // =========================================================================
1184
+
1185
+ /**
1186
+ * Record a sync event to the sync_state table for history tracking.
1187
+ * @param {string} type — "memories" | "insights" | "tasks"
1188
+ * @param {object} details — { count, direction: "push"|"pull" }
1189
+ */
1190
+ _recordSyncEvent(type, details) {
1191
+ try {
1192
+ const timestamp = new Date().toISOString();
1193
+ const key = `sync_log:${timestamp}`;
1194
+ const value = JSON.stringify({ type, details, timestamp });
1195
+ this._setSyncState(key, value);
1196
+ } catch {
1197
+ // Non-critical — don't crash on history logging failure
1198
+ }
1199
+ }
1200
+
1201
+ /**
1202
+ * Get recent sync history events.
1203
+ * @param {number} [limit=20] — Maximum number of events to return
1204
+ * @returns {Array<{ type: string, details: object, timestamp: string }>}
1205
+ */
1206
+ getSyncHistory(limit = 20) {
1207
+ try {
1208
+ const rows = this.indexer.db
1209
+ .prepare(
1210
+ `SELECT value FROM sync_state WHERE key LIKE 'sync_log:%' ORDER BY key DESC LIMIT ?`
1211
+ )
1212
+ .all(limit);
1213
+
1214
+ return rows.map((row) => {
1215
+ try {
1216
+ return JSON.parse(row.value);
1217
+ } catch {
1218
+ return null;
1219
+ }
1220
+ }).filter(Boolean);
1221
+ } catch {
1222
+ return [];
1223
+ }
1224
+ }
1225
+
1174
1226
  // =========================================================================
1175
1227
  // Internal — utilities
1176
1228
  // =========================================================================
@@ -84,8 +84,14 @@ export class KnowledgeExtractor {
84
84
  if (preExtractedInsights && this._hasInsights(preExtractedInsights)) {
85
85
  result = this.processPreExtracted(preExtractedInsights, metadata);
86
86
  } else {
87
- // Layer 2: Rule engine fallback (SDK/API writes without agent)
88
- result = this.extractByRules(content, metadata);
87
+ // Skip rule engine for raw tool captures — they produce low-quality cards
88
+ const skipTypes = new Set(['tool_use', 'code_change', 'session_checkpoint']);
89
+ if (skipTypes.has(metadata?.type)) {
90
+ result = { cards: [], tasks: [], risks: [] };
91
+ } else {
92
+ // Layer 2: Rule engine fallback (SDK/API writes without agent)
93
+ result = this.extractByRules(content, metadata);
94
+ }
89
95
  }
90
96
 
91
97
  // Persist extracted artifacts to disk + index
package/src/daemon.mjs CHANGED
@@ -1072,6 +1072,8 @@ export class AwarenessLocalDaemon {
1072
1072
  const config = this._loadConfig();
1073
1073
  const cloud = config.cloud || {};
1074
1074
 
1075
+ const history = this.cloudSync ? this.cloudSync.getSyncHistory() : [];
1076
+
1075
1077
  return jsonResponse(res, {
1076
1078
  cloud_enabled: !!cloud.enabled,
1077
1079
  api_base: cloud.api_base || null,
@@ -1079,6 +1081,7 @@ export class AwarenessLocalDaemon {
1079
1081
  auto_sync: cloud.auto_sync ?? true,
1080
1082
  last_push_at: cloud.last_push_at || null,
1081
1083
  last_pull_at: cloud.last_pull_at || null,
1084
+ history,
1082
1085
  });
1083
1086
  }
1084
1087
 
@@ -215,6 +215,17 @@ body {
215
215
  .sync-history { margin-top: 20px; }
216
216
  .sync-history h4 { font-size: 0.9rem; font-weight: 600; margin-bottom: 12px; color: var(--text-secondary); }
217
217
  .sync-history-empty { font-size: 0.85rem; color: var(--text-muted); padding: 16px; text-align: center; }
218
+ .sync-history-list { max-height: 300px; overflow-y: auto; }
219
+ .sync-history-item {
220
+ display: flex; align-items: center; gap: 10px;
221
+ padding: 8px 12px; border-bottom: 1px solid var(--border);
222
+ font-size: 0.85rem;
223
+ }
224
+ .sync-history-item:last-child { border-bottom: none; }
225
+ .sync-history-icon { font-size: 1rem; flex-shrink: 0; }
226
+ .sync-history-type { font-weight: 500; min-width: 70px; }
227
+ .sync-history-count { color: var(--text-secondary); }
228
+ .sync-history-time { margin-left: auto; color: var(--text-muted); font-size: 0.8rem; white-space: nowrap; }
218
229
 
219
230
  /* ---- Settings ---- */
220
231
  .settings-section { margin-bottom: 28px; }
@@ -754,6 +765,31 @@ async function loadSync() {
754
765
  descEl.textContent = 'Memories are stored locally only. Connect to cloud for backup and cross-device sync.';
755
766
  btnEl.textContent = 'Connect to Cloud';
756
767
  }
768
+
769
+ // Render sync history
770
+ var historyEl = document.getElementById('sync-history');
771
+ if (data.history && data.history.length > 0) {
772
+ var html = '<h4>Sync History</h4><div class="sync-history-list">';
773
+ for (var i = 0; i < data.history.length; i++) {
774
+ var item = data.history[i];
775
+ var dir = (item.details && item.details.direction) || 'push';
776
+ var icon = dir === 'pull' ? '\u2B07\uFE0F' : '\u2B06\uFE0F';
777
+ var type = item.type || 'memories';
778
+ var count = (item.details && item.details.count) || 0;
779
+ var time = item.timestamp ? formatDate(item.timestamp) : '';
780
+ html += '<div class="sync-history-item">'
781
+ + '<span class="sync-history-icon">' + icon + '</span>'
782
+ + '<span class="sync-history-type">' + type + '</span>'
783
+ + '<span class="sync-history-count">' + count + ' ' + dir + '</span>'
784
+ + '<span class="sync-history-time">' + time + '</span>'
785
+ + '</div>';
786
+ }
787
+ html += '</div>';
788
+ historyEl.innerHTML = html;
789
+ } else {
790
+ historyEl.innerHTML = '<h4>Sync History</h4>'
791
+ + '<div class="sync-history-empty">No sync history yet. Connect to cloud to enable sync.</div>';
792
+ }
757
793
  }
758
794
 
759
795
  var _authApiKey = null;