@esparkman/pensieve 0.1.2 → 0.1.4
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/.claude/commands/recall.md +183 -0
- package/.claude/commands/remember.md +145 -0
- package/.claude/commands/session-end.md +162 -0
- package/.claude/commands/session-start.md +97 -0
- package/dist/database.d.ts +6 -0
- package/dist/database.js +65 -7
- package/package.json +3 -2
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Query the Pensieve knowledge base for stored information. Use to retrieve decisions, preferences, entities, discoveries, or session history.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /recall
|
|
6
|
+
|
|
7
|
+
Query the Pensieve knowledge base for specific information.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/recall authentication -> Returns all auth-related memories
|
|
13
|
+
/recall entities -> Returns domain model understanding
|
|
14
|
+
/recall session:last -> Returns last session summary
|
|
15
|
+
/recall preferences:testing -> Returns testing preferences
|
|
16
|
+
/recall discoveries -> Returns all discoveries
|
|
17
|
+
/recall patterns -> Returns identified patterns
|
|
18
|
+
/recall questions -> Returns open questions
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Step 1: Parse Query
|
|
22
|
+
|
|
23
|
+
Identify what the user wants to recall:
|
|
24
|
+
- Topic keyword -> Search all memories for that topic
|
|
25
|
+
- `entities` -> List all entities
|
|
26
|
+
- `session:last` -> Get last session
|
|
27
|
+
- `preferences:[category]` -> Get preferences in category
|
|
28
|
+
- `discoveries` -> List all discoveries
|
|
29
|
+
- `patterns` -> List identified patterns
|
|
30
|
+
- `questions` -> List open questions
|
|
31
|
+
|
|
32
|
+
## Step 2: Use Pensieve MCP Tool
|
|
33
|
+
|
|
34
|
+
Use the `pensieve_recall` MCP tool with the appropriate query.
|
|
35
|
+
|
|
36
|
+
### Topic Search (Default)
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"query": "[topic_keyword]"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Entities
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"query": "entities"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Last Session
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"query": "session:last"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Preferences by Category
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"query": "preferences:[category]"
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Discoveries
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"query": "discoveries"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Patterns
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"query": "patterns"
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Open Questions
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"query": "questions"
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Step 3: Format Results
|
|
93
|
+
|
|
94
|
+
Present the results to the user in a clear format:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
## Recall: [query]
|
|
98
|
+
|
|
99
|
+
Found [N] results:
|
|
100
|
+
|
|
101
|
+
### Decisions
|
|
102
|
+
- [Topic]: [Decision] (recorded [date])
|
|
103
|
+
|
|
104
|
+
### Discoveries
|
|
105
|
+
- [Name]: [Description] at [location]
|
|
106
|
+
|
|
107
|
+
### Preferences
|
|
108
|
+
- [category]/[key]: [value]
|
|
109
|
+
|
|
110
|
+
### Entities
|
|
111
|
+
- [Name]: [Description] -> [Relationships]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If no results found:
|
|
115
|
+
"No memories found for '[query]'. Try a different search term or use `/remember` to save new knowledge."
|
|
116
|
+
|
|
117
|
+
## Examples
|
|
118
|
+
|
|
119
|
+
**Input:** `/recall authentication`
|
|
120
|
+
|
|
121
|
+
**Action:** Call `pensieve_recall` with:
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"query": "authentication"
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Output:**
|
|
129
|
+
```
|
|
130
|
+
## Recall: authentication
|
|
131
|
+
|
|
132
|
+
Found 3 results:
|
|
133
|
+
|
|
134
|
+
### Decisions
|
|
135
|
+
- Authentication: We use Devise with magic links (recorded 2024-01-15)
|
|
136
|
+
- Session Management: Use Redis for session storage (recorded 2024-01-14)
|
|
137
|
+
|
|
138
|
+
### Discoveries
|
|
139
|
+
- DeviseConfig: Custom Devise configuration at config/initializers/devise.rb
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Input:** `/recall preferences:testing`
|
|
143
|
+
|
|
144
|
+
**Action:** Call `pensieve_recall` with:
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"query": "preferences:testing"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Output:**
|
|
152
|
+
```
|
|
153
|
+
## Recall: preferences:testing
|
|
154
|
+
|
|
155
|
+
### Preferences
|
|
156
|
+
- testing/approach: system tests for UI flows
|
|
157
|
+
- testing/coverage: 80% minimum
|
|
158
|
+
- testing/framework: RSpec with Capybara
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Input:** `/recall session:last`
|
|
162
|
+
|
|
163
|
+
**Action:** Call `pensieve_recall` with:
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"query": "session:last"
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Output:**
|
|
171
|
+
```
|
|
172
|
+
## Recall: Last Session
|
|
173
|
+
|
|
174
|
+
**Date:** 2024-01-15 14:30
|
|
175
|
+
**Summary:** Implemented user authentication with Devise
|
|
176
|
+
|
|
177
|
+
### Work in Progress
|
|
178
|
+
Email templates (partially styled)
|
|
179
|
+
|
|
180
|
+
### Next Steps
|
|
181
|
+
1. Complete email templates
|
|
182
|
+
2. Add OAuth providers
|
|
183
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Save discoveries, decisions, or preferences to Pensieve memory. Use to persist important learnings like architectural decisions, coding preferences, or discovered patterns.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /remember
|
|
6
|
+
|
|
7
|
+
Save discoveries, decisions, or preferences to Pensieve memory.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/remember decision: We use Devise for authentication with magic links
|
|
13
|
+
/remember preference: Always use system tests over request specs for UI flows
|
|
14
|
+
/remember entity: Customer belongs_to Tenant, has_many Orders
|
|
15
|
+
/remember discovery: Found ButtonComponent at app/components/base/button_component.rb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Step 1: Parse Input
|
|
19
|
+
|
|
20
|
+
Identify the type from the user's input:
|
|
21
|
+
- `decision:` -> Save as decision
|
|
22
|
+
- `preference:` -> Save as preference
|
|
23
|
+
- `entity:` -> Save as entity
|
|
24
|
+
- `discovery:` -> Save as discovery
|
|
25
|
+
|
|
26
|
+
Extract the content after the type indicator.
|
|
27
|
+
|
|
28
|
+
## Step 2: Use Pensieve MCP Tool
|
|
29
|
+
|
|
30
|
+
Use the `pensieve_remember` MCP tool with the appropriate parameters.
|
|
31
|
+
|
|
32
|
+
### For Decisions
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"type": "decision",
|
|
37
|
+
"topic": "[extracted_topic]",
|
|
38
|
+
"content": "[decision_text]",
|
|
39
|
+
"rationale": "[rationale_if_provided]"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### For Preferences
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"type": "preference",
|
|
48
|
+
"category": "[category]",
|
|
49
|
+
"key": "[key]",
|
|
50
|
+
"value": "[value]"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### For Entities
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"type": "entity",
|
|
59
|
+
"name": "[entity_name]",
|
|
60
|
+
"description": "[description]",
|
|
61
|
+
"relationships": "[relationships]",
|
|
62
|
+
"location": "[file_location_if_known]"
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### For Discoveries
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"type": "discovery",
|
|
71
|
+
"category": "[component|pattern|token|other]",
|
|
72
|
+
"name": "[name]",
|
|
73
|
+
"location": "[file_path]",
|
|
74
|
+
"description": "[description]"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Step 3: Confirm
|
|
79
|
+
|
|
80
|
+
Report what was saved to the user:
|
|
81
|
+
|
|
82
|
+
"Saved [type]: [summary]"
|
|
83
|
+
|
|
84
|
+
If the save failed, report the error and suggest a fix.
|
|
85
|
+
|
|
86
|
+
## Examples
|
|
87
|
+
|
|
88
|
+
**Input:** `/remember decision: We use TypeScript for all new code because it catches errors at compile time`
|
|
89
|
+
|
|
90
|
+
**Action:** Call `pensieve_remember` with:
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"type": "decision",
|
|
94
|
+
"topic": "Language Choice",
|
|
95
|
+
"content": "We use TypeScript for all new code",
|
|
96
|
+
"rationale": "Catches errors at compile time"
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Output:**
|
|
101
|
+
```
|
|
102
|
+
Saved decision:
|
|
103
|
+
Topic: Language Choice
|
|
104
|
+
Decision: We use TypeScript for all new code
|
|
105
|
+
Rationale: Catches errors at compile time
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Input:** `/remember preference: testing/approach = system tests for UI flows`
|
|
109
|
+
|
|
110
|
+
**Action:** Call `pensieve_remember` with:
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"type": "preference",
|
|
114
|
+
"category": "testing",
|
|
115
|
+
"key": "approach",
|
|
116
|
+
"value": "system tests for UI flows"
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Output:**
|
|
121
|
+
```
|
|
122
|
+
Saved preference:
|
|
123
|
+
Category: testing
|
|
124
|
+
Key: approach
|
|
125
|
+
Value: system tests for UI flows
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Input:** `/remember entity: Order has_many LineItems, belongs_to Customer`
|
|
129
|
+
|
|
130
|
+
**Action:** Call `pensieve_remember` with:
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"type": "entity",
|
|
134
|
+
"name": "Order",
|
|
135
|
+
"description": "Represents a customer order",
|
|
136
|
+
"relationships": "has_many LineItems, belongs_to Customer"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Output:**
|
|
141
|
+
```
|
|
142
|
+
Saved entity:
|
|
143
|
+
Name: Order
|
|
144
|
+
Relationships: has_many LineItems, belongs_to Customer
|
|
145
|
+
```
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Persist learnings and summarize the session before ending. Use this before closing a conversation to save decisions, discoveries, and next steps for continuity.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /session-end
|
|
6
|
+
|
|
7
|
+
Persist learnings and summarize the session before context is cleared.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Save everything learned during this session so the next conversation can pick up seamlessly:
|
|
12
|
+
- Summarize accomplishments
|
|
13
|
+
- Note work in progress
|
|
14
|
+
- Record planned next steps
|
|
15
|
+
- Persist any unrecorded decisions or preferences
|
|
16
|
+
|
|
17
|
+
## Step 1: Gather Session Information
|
|
18
|
+
|
|
19
|
+
Ask the user (or infer from conversation):
|
|
20
|
+
- What was accomplished this session?
|
|
21
|
+
- What is still in progress?
|
|
22
|
+
- What are the planned next steps?
|
|
23
|
+
|
|
24
|
+
If the user doesn't provide this, attempt to summarize based on the conversation.
|
|
25
|
+
|
|
26
|
+
## Step 2: Identify Key Files
|
|
27
|
+
|
|
28
|
+
List the key files that were worked on during this session:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# If git is available, check recent changes
|
|
32
|
+
git diff --name-only HEAD~1 2>/dev/null || echo "Unable to detect changed files"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or track files mentioned during the conversation.
|
|
36
|
+
|
|
37
|
+
## Step 3: Save Any Pending Memories
|
|
38
|
+
|
|
39
|
+
Before ending the session, use `pensieve_remember` to save any decisions, discoveries, or preferences that were made but not yet recorded.
|
|
40
|
+
|
|
41
|
+
For each unrecorded decision:
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"type": "decision",
|
|
45
|
+
"topic": "[topic]",
|
|
46
|
+
"content": "[decision]",
|
|
47
|
+
"rationale": "[rationale]"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For each unrecorded discovery:
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"type": "discovery",
|
|
55
|
+
"category": "[category]",
|
|
56
|
+
"name": "[name]",
|
|
57
|
+
"location": "[location]",
|
|
58
|
+
"description": "[description]"
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Step 4: End Session with Summary
|
|
63
|
+
|
|
64
|
+
Use the `pensieve_session_end` MCP tool to finalize the session:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"summary": "[what was accomplished]",
|
|
69
|
+
"work_in_progress": "[what's still ongoing]",
|
|
70
|
+
"next_steps": "[planned actions for next session]",
|
|
71
|
+
"key_files": ["file1.rb", "file2.ts"]
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Step 5: Confirm Session Saved
|
|
76
|
+
|
|
77
|
+
Present a summary to the user:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
## Session Saved
|
|
81
|
+
|
|
82
|
+
### Summary
|
|
83
|
+
[what was accomplished]
|
|
84
|
+
|
|
85
|
+
### Work in Progress
|
|
86
|
+
[what's still ongoing]
|
|
87
|
+
|
|
88
|
+
### Next Steps
|
|
89
|
+
[planned actions for next session]
|
|
90
|
+
|
|
91
|
+
### Key Files
|
|
92
|
+
- [file1]
|
|
93
|
+
- [file2]
|
|
94
|
+
|
|
95
|
+
### Decisions Recorded
|
|
96
|
+
- [decision1]
|
|
97
|
+
- [decision2]
|
|
98
|
+
|
|
99
|
+
### Open Questions
|
|
100
|
+
- [question1]
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
Your session has been saved. When you start a new conversation,
|
|
105
|
+
Pensieve will automatically load this context.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Automatic Triggers
|
|
109
|
+
|
|
110
|
+
Consider running `/session-end` when:
|
|
111
|
+
- User says "goodbye", "done", "that's all", etc.
|
|
112
|
+
- User explicitly requests to save progress
|
|
113
|
+
- A significant milestone is completed
|
|
114
|
+
|
|
115
|
+
## Example
|
|
116
|
+
|
|
117
|
+
**User:** "Okay, I think we're done for now. We finished the user authentication flow."
|
|
118
|
+
|
|
119
|
+
**Action:** Call `pensieve_session_end` with:
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"summary": "Completed user authentication flow with Devise, including login, logout, password reset, and magic link support",
|
|
123
|
+
"work_in_progress": "Email templates (partially styled)",
|
|
124
|
+
"next_steps": "1. Complete email templates\n2. Add OAuth providers\n3. Add two-factor authentication",
|
|
125
|
+
"key_files": [
|
|
126
|
+
"app/models/user.rb",
|
|
127
|
+
"app/controllers/sessions_controller.rb",
|
|
128
|
+
"config/initializers/devise.rb"
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Output:**
|
|
134
|
+
```
|
|
135
|
+
## Session Saved
|
|
136
|
+
|
|
137
|
+
### Summary
|
|
138
|
+
Completed user authentication flow with Devise, including:
|
|
139
|
+
- Login/logout functionality
|
|
140
|
+
- Password reset flow
|
|
141
|
+
- Magic link support
|
|
142
|
+
|
|
143
|
+
### Work in Progress
|
|
144
|
+
Email templates (partially styled)
|
|
145
|
+
|
|
146
|
+
### Next Steps
|
|
147
|
+
1. Complete email templates
|
|
148
|
+
2. Add OAuth providers
|
|
149
|
+
3. Add two-factor authentication
|
|
150
|
+
|
|
151
|
+
### Key Files
|
|
152
|
+
- app/models/user.rb
|
|
153
|
+
- app/controllers/sessions_controller.rb
|
|
154
|
+
- config/initializers/devise.rb
|
|
155
|
+
|
|
156
|
+
### Decisions Recorded
|
|
157
|
+
- Use Devise with magic links for passwordless auth
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
Your session has been saved. See you next time!
|
|
162
|
+
```
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Load and display context from Pensieve at the start of a conversation. Use this at the beginning of every session to ensure continuity from previous work.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /session-start
|
|
6
|
+
|
|
7
|
+
Display and confirm the context loaded from Pensieve at the start of a conversation.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Pensieve automatically loads context when the MCP server starts. This command:
|
|
12
|
+
- Displays what was loaded for transparency
|
|
13
|
+
- Starts session tracking for the current conversation
|
|
14
|
+
- Provides continuity from previous sessions
|
|
15
|
+
|
|
16
|
+
## Step 1: Start Session Tracking
|
|
17
|
+
|
|
18
|
+
Use the `pensieve_session_start` MCP tool to begin tracking this session:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This creates a new session record that will be updated when `/session-end` is called.
|
|
25
|
+
|
|
26
|
+
## Step 2: Get Full Context
|
|
27
|
+
|
|
28
|
+
Use the `pensieve_get_context` MCP tool to retrieve all loaded context:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This returns:
|
|
35
|
+
- Last session summary and next steps
|
|
36
|
+
- Key decisions
|
|
37
|
+
- User preferences
|
|
38
|
+
- Open questions
|
|
39
|
+
- Recent discoveries
|
|
40
|
+
|
|
41
|
+
## Step 3: Present Context
|
|
42
|
+
|
|
43
|
+
Format and present the loaded context to the user:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
## Session Started
|
|
47
|
+
|
|
48
|
+
### Last Session
|
|
49
|
+
**Date:** [started_at]
|
|
50
|
+
**Summary:** [summary]
|
|
51
|
+
|
|
52
|
+
### Work in Progress
|
|
53
|
+
[work_in_progress or "None"]
|
|
54
|
+
|
|
55
|
+
### Planned Next Steps
|
|
56
|
+
[next_steps or "None"]
|
|
57
|
+
|
|
58
|
+
### Key Decisions
|
|
59
|
+
- [topic]: [decision]
|
|
60
|
+
- [topic]: [decision]
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
### Your Preferences
|
|
64
|
+
- [category]/[key]: [value]
|
|
65
|
+
...
|
|
66
|
+
|
|
67
|
+
### Open Questions
|
|
68
|
+
- [question]
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
Ready to continue. What would you like to work on?
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Fresh Installation
|
|
77
|
+
|
|
78
|
+
If Pensieve returns no prior context, inform the user:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
## Session Started (Fresh Installation)
|
|
82
|
+
|
|
83
|
+
No prior context found. This appears to be a fresh Pensieve installation.
|
|
84
|
+
|
|
85
|
+
Your memories will be stored as you work. Use:
|
|
86
|
+
- `/remember` to save decisions, preferences, and discoveries
|
|
87
|
+
- `/recall` to query stored knowledge
|
|
88
|
+
- `/session-end` before ending to save your progress
|
|
89
|
+
|
|
90
|
+
What would you like to work on?
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Notes
|
|
94
|
+
|
|
95
|
+
- Pensieve auto-loads context when the MCP server starts, so this command primarily displays what's already loaded
|
|
96
|
+
- Session tracking begins with this command and ends with `/session-end`
|
|
97
|
+
- Context persists in `~/.pensieve/memory.sqlite` (user-level) or project-level if configured
|
package/dist/database.d.ts
CHANGED
|
@@ -65,7 +65,13 @@ export interface OpenQuestion {
|
|
|
65
65
|
export declare class MemoryDatabase {
|
|
66
66
|
private db;
|
|
67
67
|
private projectPath;
|
|
68
|
+
private dbPath;
|
|
68
69
|
constructor(projectPath?: string);
|
|
70
|
+
private openDatabase;
|
|
71
|
+
/**
|
|
72
|
+
* Check if the database is writable and reconnect if needed
|
|
73
|
+
*/
|
|
74
|
+
ensureWritable(): boolean;
|
|
69
75
|
private getDbPath;
|
|
70
76
|
/**
|
|
71
77
|
* Truncate a string to the maximum field length
|
package/dist/database.js
CHANGED
|
@@ -15,32 +15,82 @@ export const LIMITS = {
|
|
|
15
15
|
export class MemoryDatabase {
|
|
16
16
|
db;
|
|
17
17
|
projectPath;
|
|
18
|
+
dbPath;
|
|
18
19
|
constructor(projectPath) {
|
|
19
20
|
// Use provided path, or detect from current directory, or use home
|
|
20
21
|
this.projectPath = projectPath || process.cwd();
|
|
21
|
-
|
|
22
|
+
this.dbPath = this.getDbPath();
|
|
22
23
|
// Ensure directory exists
|
|
23
|
-
const dbDir = dirname(dbPath);
|
|
24
|
+
const dbDir = dirname(this.dbPath);
|
|
24
25
|
if (!existsSync(dbDir)) {
|
|
25
26
|
mkdirSync(dbDir, { recursive: true });
|
|
26
27
|
}
|
|
27
|
-
this.db =
|
|
28
|
+
this.db = this.openDatabase();
|
|
28
29
|
this.initSchema();
|
|
29
30
|
}
|
|
31
|
+
openDatabase() {
|
|
32
|
+
// Always try to open in read-write mode
|
|
33
|
+
// If file doesn't exist, it will be created
|
|
34
|
+
try {
|
|
35
|
+
return new Database(this.dbPath, { fileMustExist: false });
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
console.error(`[Pensieve] Failed to open database: ${error}`);
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if the database is writable and reconnect if needed
|
|
44
|
+
*/
|
|
45
|
+
ensureWritable() {
|
|
46
|
+
try {
|
|
47
|
+
// Test write capability
|
|
48
|
+
this.db.exec('SELECT 1');
|
|
49
|
+
this.db.prepare('CREATE TABLE IF NOT EXISTS _pensieve_health_check (id INTEGER)').run();
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
54
|
+
if (errorMessage.includes('readonly')) {
|
|
55
|
+
console.error('[Pensieve] Database is read-only, attempting reconnection...');
|
|
56
|
+
try {
|
|
57
|
+
this.db.close();
|
|
58
|
+
this.db = this.openDatabase();
|
|
59
|
+
console.error('[Pensieve] Reconnected successfully');
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch (reconnectError) {
|
|
63
|
+
console.error(`[Pensieve] Reconnection failed: ${reconnectError}`);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
30
70
|
getDbPath() {
|
|
31
|
-
// Check for explicit
|
|
71
|
+
// Check for explicit database path override
|
|
32
72
|
const envPath = process.env.PENSIEVE_DB_PATH;
|
|
33
73
|
if (envPath) {
|
|
34
74
|
console.error(`[Pensieve] Using database from PENSIEVE_DB_PATH: ${envPath}`);
|
|
35
75
|
return envPath;
|
|
36
76
|
}
|
|
37
|
-
//
|
|
77
|
+
// Check for explicit project path (recommended for MCP server usage)
|
|
78
|
+
// This should be set in the MCP server config to ensure deterministic behavior
|
|
79
|
+
const projectDir = process.env.PENSIEVE_PROJECT_DIR;
|
|
80
|
+
if (projectDir) {
|
|
81
|
+
const projectPath = join(projectDir, '.pensieve', 'memory.sqlite');
|
|
82
|
+
console.error(`[Pensieve] Using project database from PENSIEVE_PROJECT_DIR: ${projectPath}`);
|
|
83
|
+
return projectPath;
|
|
84
|
+
}
|
|
85
|
+
// Fallback: Try project-local first, then fall back to home directory
|
|
86
|
+
// WARNING: Using process.cwd() is unreliable in MCP server context
|
|
38
87
|
const localPath = join(this.projectPath, '.pensieve', 'memory.sqlite');
|
|
39
88
|
const globalPath = join(homedir(), '.claude-pensieve', 'memory.sqlite');
|
|
40
89
|
// If local .pensieve directory exists or we're in a git repo, use local
|
|
41
90
|
if (existsSync(join(this.projectPath, '.pensieve')) ||
|
|
42
91
|
existsSync(join(this.projectPath, '.git'))) {
|
|
43
|
-
console.error(`[Pensieve] Using
|
|
92
|
+
console.error(`[Pensieve] WARNING: Using cwd-based path (unreliable): ${localPath}`);
|
|
93
|
+
console.error(`[Pensieve] Set PENSIEVE_PROJECT_DIR for deterministic behavior`);
|
|
44
94
|
return localPath;
|
|
45
95
|
}
|
|
46
96
|
console.error(`[Pensieve] Using global database: ${globalPath}`);
|
|
@@ -177,6 +227,7 @@ export class MemoryDatabase {
|
|
|
177
227
|
}
|
|
178
228
|
// Decision methods
|
|
179
229
|
addDecision(decision) {
|
|
230
|
+
this.ensureWritable();
|
|
180
231
|
this.pruneIfNeeded();
|
|
181
232
|
const stmt = this.db.prepare(`
|
|
182
233
|
INSERT INTO decisions (topic, decision, rationale, alternatives, source)
|
|
@@ -205,6 +256,7 @@ export class MemoryDatabase {
|
|
|
205
256
|
}
|
|
206
257
|
// Preference methods
|
|
207
258
|
setPreference(pref) {
|
|
259
|
+
this.ensureWritable();
|
|
208
260
|
const stmt = this.db.prepare(`
|
|
209
261
|
INSERT OR REPLACE INTO preferences (category, key, value, notes, updated_at)
|
|
210
262
|
VALUES (?, ?, ?, ?, datetime('now'))
|
|
@@ -231,6 +283,7 @@ export class MemoryDatabase {
|
|
|
231
283
|
}
|
|
232
284
|
// Discovery methods
|
|
233
285
|
addDiscovery(discovery) {
|
|
286
|
+
this.ensureWritable();
|
|
234
287
|
this.pruneIfNeeded();
|
|
235
288
|
const stmt = this.db.prepare(`
|
|
236
289
|
INSERT INTO discoveries (category, name, location, description, metadata, confidence)
|
|
@@ -257,6 +310,7 @@ export class MemoryDatabase {
|
|
|
257
310
|
}
|
|
258
311
|
// Entity methods
|
|
259
312
|
upsertEntity(entity) {
|
|
313
|
+
this.ensureWritable();
|
|
260
314
|
const stmt = this.db.prepare(`
|
|
261
315
|
INSERT OR REPLACE INTO entities (name, description, relationships, attributes, location, updated_at)
|
|
262
316
|
VALUES (?, ?, ?, ?, ?, datetime('now'))
|
|
@@ -273,11 +327,13 @@ export class MemoryDatabase {
|
|
|
273
327
|
}
|
|
274
328
|
// Session methods
|
|
275
329
|
startSession() {
|
|
330
|
+
this.ensureWritable();
|
|
276
331
|
const stmt = this.db.prepare(`INSERT INTO sessions (started_at) VALUES (datetime('now'))`);
|
|
277
332
|
const result = stmt.run();
|
|
278
333
|
return result.lastInsertRowid;
|
|
279
334
|
}
|
|
280
335
|
endSession(sessionId, summary, workInProgress, nextSteps, keyFiles, tags) {
|
|
336
|
+
this.ensureWritable();
|
|
281
337
|
this.pruneIfNeeded();
|
|
282
338
|
const stmt = this.db.prepare(`
|
|
283
339
|
UPDATE sessions
|
|
@@ -305,6 +361,7 @@ export class MemoryDatabase {
|
|
|
305
361
|
}
|
|
306
362
|
// Open questions methods
|
|
307
363
|
addQuestion(question, context) {
|
|
364
|
+
this.ensureWritable();
|
|
308
365
|
const stmt = this.db.prepare(`
|
|
309
366
|
INSERT INTO open_questions (question, context) VALUES (?, ?)
|
|
310
367
|
`);
|
|
@@ -312,6 +369,7 @@ export class MemoryDatabase {
|
|
|
312
369
|
return result.lastInsertRowid;
|
|
313
370
|
}
|
|
314
371
|
resolveQuestion(id, resolution) {
|
|
372
|
+
this.ensureWritable();
|
|
315
373
|
const stmt = this.db.prepare(`
|
|
316
374
|
UPDATE open_questions
|
|
317
375
|
SET status = 'resolved', resolution = ?, resolved_at = datetime('now')
|
|
@@ -336,7 +394,7 @@ export class MemoryDatabase {
|
|
|
336
394
|
}
|
|
337
395
|
// Get database path for debugging
|
|
338
396
|
getPath() {
|
|
339
|
-
return this.
|
|
397
|
+
return this.dbPath;
|
|
340
398
|
}
|
|
341
399
|
close() {
|
|
342
400
|
this.db.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@esparkman/pensieve",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Pensieve - persistent memory for Claude Code. Remember decisions, preferences, and context across sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"node": ">=18"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
|
-
"dist"
|
|
43
|
+
"dist",
|
|
44
|
+
".claude"
|
|
44
45
|
]
|
|
45
46
|
}
|