@awareness-sdk/local 0.1.4 → 0.1.6

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.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Local-first AI agent memory system. No account needed.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/src/daemon.mjs CHANGED
@@ -42,6 +42,26 @@ function nowISO() {
42
42
  return new Date().toISOString();
43
43
  }
44
44
 
45
+ /** Categories surfaced as top-level user_preferences (mirrors cloud PREFERENCE_FIRST_CATEGORIES). */
46
+ const PREFERENCE_FIRST_CATEGORIES = new Set([
47
+ 'personal_preference', 'activity_preference', 'important_detail', 'career_info',
48
+ ]);
49
+ const MAX_USER_PREFERENCES = 15;
50
+
51
+ /** Split knowledge cards into {user_preferences, knowledge_cards}. */
52
+ function splitPreferences(cards) {
53
+ const prefs = [];
54
+ const other = [];
55
+ for (const c of cards) {
56
+ if (PREFERENCE_FIRST_CATEGORIES.has(c.category) && prefs.length < MAX_USER_PREFERENCES) {
57
+ prefs.push(c);
58
+ } else {
59
+ other.push(c);
60
+ }
61
+ }
62
+ return { user_preferences: prefs, knowledge_cards: other };
63
+ }
64
+
45
65
  /**
46
66
  * Send a JSON response.
47
67
  * @param {http.ServerResponse} res
@@ -647,16 +667,40 @@ export class AwarenessLocalDaemon {
647
667
  const recentSessions = this.indexer.getRecentSessions(args.days ?? 7);
648
668
  const spec = this._loadSpec();
649
669
 
670
+ // Compute attention_summary for LLM-side triage
671
+ const now = Date.now();
672
+ const staleDays = 3;
673
+ const staleCutoff = now - staleDays * 86400000;
674
+ const staleTasks = openTasks.filter(t => {
675
+ const created = t.created_at ? new Date(t.created_at).getTime() : now;
676
+ return created < staleCutoff;
677
+ }).length;
678
+ const riskCards = this.indexer.db
679
+ .prepare("SELECT COUNT(*) as cnt FROM knowledge_cards WHERE (category = 'risk' OR category = 'pitfall') AND status = 'active'")
680
+ .get();
681
+ const highRisks = riskCards?.cnt || 0;
682
+
683
+ const attentionSummary = {
684
+ stale_tasks: staleTasks,
685
+ high_risks: highRisks,
686
+ total_open_tasks: openTasks.length,
687
+ total_knowledge_cards: recentCards.length,
688
+ needs_attention: staleTasks > 0 || highRisks > 0,
689
+ };
690
+
691
+ const { user_preferences, knowledge_cards: otherCards } = splitPreferences(recentCards);
650
692
  return {
651
693
  content: [{
652
694
  type: 'text',
653
695
  text: JSON.stringify({
654
696
  session_id: session.id,
655
697
  mode: 'local',
656
- knowledge_cards: recentCards,
698
+ user_preferences,
699
+ knowledge_cards: otherCards,
657
700
  open_tasks: openTasks,
658
701
  recent_sessions: recentSessions,
659
702
  stats,
703
+ attention_summary: attentionSummary,
660
704
  synthesized_rules: spec.core_lines?.join('\n') || '',
661
705
  init_guides: spec.init_guides || {},
662
706
  agent_profiles: [],
@@ -1526,12 +1570,13 @@ ${item.description || item.title || ''}
1526
1570
 
1527
1571
  switch (type) {
1528
1572
  case 'context': {
1529
- // Full context dump
1573
+ // Full context dump with preference separation
1530
1574
  const stats = this.indexer.getStats();
1531
1575
  const knowledge = this.indexer.getRecentKnowledge(limit);
1532
1576
  const tasks = this.indexer.getOpenTasks(0);
1533
1577
  const sessions = this.indexer.getRecentSessions(7);
1534
- return { stats, knowledge_cards: knowledge, open_tasks: tasks, recent_sessions: sessions, mode: 'local' };
1578
+ const { user_preferences, knowledge_cards: otherCards } = splitPreferences(knowledge);
1579
+ return { stats, user_preferences, knowledge_cards: otherCards, open_tasks: tasks, recent_sessions: sessions, mode: 'local' };
1535
1580
  }
1536
1581
 
1537
1582
  case 'tasks': {
@@ -19,6 +19,26 @@ import { z } from 'zod';
19
19
  // Helpers
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
+ /** Categories surfaced as top-level user_preferences (mirrors cloud). */
23
+ const PREFERENCE_FIRST_CATEGORIES = new Set([
24
+ 'personal_preference', 'activity_preference', 'important_detail', 'career_info',
25
+ ]);
26
+ const MAX_USER_PREFERENCES = 15;
27
+
28
+ /** Split knowledge cards into {user_preferences, knowledge_cards}. */
29
+ function splitPreferences(cards) {
30
+ const prefs = [];
31
+ const other = [];
32
+ for (const c of cards) {
33
+ if (PREFERENCE_FIRST_CATEGORIES.has(c.category) && prefs.length < MAX_USER_PREFERENCES) {
34
+ prefs.push(c);
35
+ } else {
36
+ other.push(c);
37
+ }
38
+ }
39
+ return { user_preferences: prefs, knowledge_cards: other };
40
+ }
41
+
22
42
  /**
23
43
  * Wrap a result object in the MCP-standard content envelope.
24
44
  * @param {object} result
@@ -118,10 +138,12 @@ export class LocalMcpServer {
118
138
  // Load workflow rules from awareness-spec.json
119
139
  const spec = this.engine.loadSpec();
120
140
 
141
+ const { user_preferences, knowledge_cards: otherCards } = splitPreferences(recentCards);
121
142
  return mcpResult({
122
143
  session_id: session.id,
123
144
  mode: 'local',
124
- knowledge_cards: recentCards,
145
+ user_preferences,
146
+ knowledge_cards: otherCards,
125
147
  open_tasks: openTasks,
126
148
  recent_sessions: recentSessions,
127
149
  stats,
@@ -58,7 +58,7 @@
58
58
  {
59
59
  "name": "awareness_init",
60
60
  "short_desc": "Load cross-session project memory and context",
61
- "long_desc": "Load cross-session project memory. Returns session_id, context (narratives, tasks, knowledge, active_skills), and usage rules. Call ONCE at session start."
61
+ "long_desc": "Load cross-session project memory. Returns session_id, context (narratives, tasks, knowledge, active_skills, attention_summary), and usage rules. Call ONCE at session start. ATTENTION PROTOCOL: When context.attention_summary.needs_attention is true, review all attention items (stale tasks, high risks) and automatically: (1) remind the user about stale tasks, (2) warn about high risks before starting work, (3) update resolved items via awareness_record."
62
62
  },
63
63
  {
64
64
  "name": "awareness_get_agent_prompt",
@@ -385,7 +385,8 @@
385
385
  "notes_lines": [
386
386
  "## OpenClaw Notes",
387
387
  "- OpenClaw uses a plugin-based configuration via ~/.openclaw/openclaw.json.",
388
- "- Install the Awareness plugin: openclaw plugins install @awareness-sdk/openclaw-memory",
388
+ "- Install as plugin: openclaw plugins install @awareness-sdk/openclaw-memory",
389
+ "- Or install as skill: npx clawhub@latest install awareness-memory",
389
390
  "- MCP tools are exposed through the plugin system, no rules file needed."
390
391
  ]
391
392
  }