clawdbot-penfield 1.0.1
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/LICENSE +21 -0
- package/README.md +519 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/src/api-client.d.ts +14 -0
- package/dist/src/api-client.d.ts.map +1 -0
- package/dist/src/api-client.js +53 -0
- package/dist/src/auth-service.d.ts +35 -0
- package/dist/src/auth-service.d.ts.map +1 -0
- package/dist/src/auth-service.js +197 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +50 -0
- package/dist/src/config.d.ts +16 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +14 -0
- package/dist/src/device-flow.d.ts +35 -0
- package/dist/src/device-flow.d.ts.map +1 -0
- package/dist/src/device-flow.js +169 -0
- package/dist/src/runtime.d.ts +18 -0
- package/dist/src/runtime.d.ts.map +1 -0
- package/dist/src/runtime.js +18 -0
- package/dist/src/store.d.ts +49 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +66 -0
- package/dist/src/tools/awaken.d.ts +4 -0
- package/dist/src/tools/awaken.d.ts.map +1 -0
- package/dist/src/tools/awaken.js +17 -0
- package/dist/src/tools/connect.d.ts +9 -0
- package/dist/src/tools/connect.d.ts.map +1 -0
- package/dist/src/tools/connect.js +41 -0
- package/dist/src/tools/delete-artifact.d.ts +6 -0
- package/dist/src/tools/delete-artifact.d.ts.map +1 -0
- package/dist/src/tools/delete-artifact.js +24 -0
- package/dist/src/tools/explore.d.ts +9 -0
- package/dist/src/tools/explore.d.ts.map +1 -0
- package/dist/src/tools/explore.js +35 -0
- package/dist/src/tools/fetch.d.ts +6 -0
- package/dist/src/tools/fetch.d.ts.map +1 -0
- package/dist/src/tools/fetch.js +21 -0
- package/dist/src/tools/index.d.ts +4 -0
- package/dist/src/tools/index.d.ts.map +1 -0
- package/dist/src/tools/index.js +58 -0
- package/dist/src/tools/list-artifacts.d.ts +7 -0
- package/dist/src/tools/list-artifacts.d.ts.map +1 -0
- package/dist/src/tools/list-artifacts.js +32 -0
- package/dist/src/tools/list-contexts.d.ts +7 -0
- package/dist/src/tools/list-contexts.d.ts.map +1 -0
- package/dist/src/tools/list-contexts.js +32 -0
- package/dist/src/tools/recall.d.ts +13 -0
- package/dist/src/tools/recall.d.ts.map +1 -0
- package/dist/src/tools/recall.js +64 -0
- package/dist/src/tools/reflect.d.ts +8 -0
- package/dist/src/tools/reflect.d.ts.map +1 -0
- package/dist/src/tools/reflect.js +38 -0
- package/dist/src/tools/restore-context.d.ts +8 -0
- package/dist/src/tools/restore-context.d.ts.map +1 -0
- package/dist/src/tools/restore-context.js +34 -0
- package/dist/src/tools/retrieve-artifact.d.ts +6 -0
- package/dist/src/tools/retrieve-artifact.d.ts.map +1 -0
- package/dist/src/tools/retrieve-artifact.js +24 -0
- package/dist/src/tools/save-artifact.d.ts +8 -0
- package/dist/src/tools/save-artifact.d.ts.map +1 -0
- package/dist/src/tools/save-artifact.js +27 -0
- package/dist/src/tools/save-context.d.ts +7 -0
- package/dist/src/tools/save-context.d.ts.map +1 -0
- package/dist/src/tools/save-context.js +27 -0
- package/dist/src/tools/search.d.ts +9 -0
- package/dist/src/tools/search.d.ts.map +1 -0
- package/dist/src/tools/search.js +41 -0
- package/dist/src/tools/store.d.ts +11 -0
- package/dist/src/tools/store.d.ts.map +1 -0
- package/dist/src/tools/store.js +36 -0
- package/dist/src/tools/update-memory.d.ts +11 -0
- package/dist/src/tools/update-memory.d.ts.map +1 -0
- package/dist/src/tools/update-memory.js +34 -0
- package/dist/src/types/typebox.d.ts +19 -0
- package/dist/src/types/typebox.d.ts.map +1 -0
- package/dist/src/types/typebox.js +91 -0
- package/dist/src/types.d.ts +73 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +7 -0
- package/dist/src/validation.d.ts +21 -0
- package/dist/src/validation.d.ts.map +1 -0
- package/dist/src/validation.js +43 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 penfieldlabs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# Penfield Memory for Clawdbot (clawdbot-penfield)
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/clawdbot-penfield)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
**Persistent, searchable memory for [Clawdbot](https://clawd.bot).**
|
|
7
|
+
|
|
8
|
+
Your lobster remembers every conversation, learns your preferences, and builds knowledge over time—across all your channels.
|
|
9
|
+
|
|
10
|
+
## 🦞 What is this?
|
|
11
|
+
|
|
12
|
+
A Clawdbot plugin that connects your agent to [Penfield](https://penfield.app), giving it:
|
|
13
|
+
|
|
14
|
+
- **Long-term memory** — Conversations persist forever, not just one session
|
|
15
|
+
- **Semantic search** — "What did I say about the Tokyo trip?" actually works
|
|
16
|
+
- **Knowledge graphs** — Memories connect to memories, building real understanding
|
|
17
|
+
- **Cross-channel recall** — Remember WhatsApp convos from Discord
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
clawdbot plugins install clawdbot-penfield
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
clawdbot penfield login
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Tell your Clawdbot to "Awaken with Penfield"
|
|
30
|
+
|
|
31
|
+
## 🔑 Get Access
|
|
32
|
+
|
|
33
|
+
Penfield is in **free beta**. Sign up for access:
|
|
34
|
+
|
|
35
|
+
**👉 [accounts.penfield.app/waitlist](https://accounts.penfield.app/waitlist)**
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
Native Clawdbot plugin providing direct integration with Penfield's memory and knowledge graph API. This plugin offers 4-5x performance improvement over the MCP server approach by eliminating the mcporter → MCP → Penfield stack.
|
|
40
|
+
|
|
41
|
+
- **16 Memory Tools**: Complete 1:1 feature parity with Penfield MCP server
|
|
42
|
+
- **OAuth Device Code Flow**: Secure authentication following RFC 8628
|
|
43
|
+
- **Automatic Token Refresh**: Transparent token management with 240-minute expiry buffer
|
|
44
|
+
- **Hybrid Search**: BM25 + vector + graph search capabilities
|
|
45
|
+
- **Knowledge Graph**: Build and traverse relationships between memories
|
|
46
|
+
- **Context Management**: Save and restore memory checkpoints
|
|
47
|
+
- **Artifact Storage**: Store and retrieve files in Penfield
|
|
48
|
+
- **Reflection & Analysis**: Analyze memory patterns and generate insights
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
clawdbot plugins install clawdbot-penfield
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### From Source (for contributors)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/penfieldlabs/clawdbot-penfield.git
|
|
60
|
+
cd clawdbot-penfield
|
|
61
|
+
npm install
|
|
62
|
+
npm run build
|
|
63
|
+
clawdbot plugins install -l .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Configuration
|
|
67
|
+
|
|
68
|
+
The plugin is **auto-enabled when loaded**. No configuration required for production use.
|
|
69
|
+
|
|
70
|
+
**Default URLs (production):**
|
|
71
|
+
- API: `https://api.penfield.app`
|
|
72
|
+
- Auth: `https://auth.penfield.app`
|
|
73
|
+
|
|
74
|
+
**Override with environment variables (for development):**
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export PENFIELD_API_URL="https://api-dev.penfield.app"
|
|
78
|
+
export PENFIELD_AUTH_URL="https://auth-dev.penfield.app"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Or with config in `~/.clawdbot/clawdbot.json`:**
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"plugins": {
|
|
86
|
+
"entries": {
|
|
87
|
+
"penfield": {
|
|
88
|
+
"enabled": true,
|
|
89
|
+
"config": {
|
|
90
|
+
"apiUrl": "https://api-dev.penfield.app",
|
|
91
|
+
"authUrl": "https://auth-dev.penfield.app"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Authentication
|
|
100
|
+
|
|
101
|
+
The plugin uses OAuth 2.0 Device Code Flow (RFC 8628) with automatic token refresh.
|
|
102
|
+
|
|
103
|
+
### CLI Login
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
clawdbot penfield login
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
This will:
|
|
110
|
+
1. Discover OAuth endpoints from the auth server
|
|
111
|
+
2. Register a dynamic client (DCR) if needed
|
|
112
|
+
3. Display a device code for user authentication
|
|
113
|
+
4. Poll for token completion
|
|
114
|
+
|
|
115
|
+
### Credentials
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"version": 1,
|
|
120
|
+
"clientId": "dyn_abc123...",
|
|
121
|
+
"access": "eyJ...",
|
|
122
|
+
"refresh": "eyJ...",
|
|
123
|
+
"expires": 1234567890000,
|
|
124
|
+
"createdAt": 1234567890000
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Location: `~/.clawdbot/extensions/penfield/credentials.json`
|
|
129
|
+
File permissions: `0o600` (owner-only read/write)
|
|
130
|
+
|
|
131
|
+
## Available Tools
|
|
132
|
+
|
|
133
|
+
### Memory Management
|
|
134
|
+
|
|
135
|
+
#### `penfield_store`
|
|
136
|
+
Store a new memory in Penfield.
|
|
137
|
+
|
|
138
|
+
**Parameters:**
|
|
139
|
+
- `content` (required): Memory content (max 10,000 chars)
|
|
140
|
+
- `memory_type` (optional): Type of memory (default: "fact")
|
|
141
|
+
- Options: fact, insight, conversation, correction, reference, task, checkpoint, identity_core, personality_trait, relationship, strategy
|
|
142
|
+
- `importance` (optional): Score 0-1 (default: 0.5)
|
|
143
|
+
- `confidence` (optional): Score 0-1 (default: 0.8)
|
|
144
|
+
- `source_type` (optional): Source type (e.g., "direct_input", "conversation")
|
|
145
|
+
- `tags` (optional): Array of tags (max 10)
|
|
146
|
+
|
|
147
|
+
**Example:**
|
|
148
|
+
```typescript
|
|
149
|
+
{
|
|
150
|
+
"content": "User prefers TypeScript over JavaScript",
|
|
151
|
+
"memory_type": "fact",
|
|
152
|
+
"importance": 0.7,
|
|
153
|
+
"tags": ["preferences", "programming"]
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `penfield_recall`
|
|
158
|
+
Hybrid search using BM25 + vector + graph.
|
|
159
|
+
|
|
160
|
+
**Parameters:**
|
|
161
|
+
- `query` (required): Search query (1-4,000 chars)
|
|
162
|
+
- `limit` (optional): Max results (default: 20, max: 100)
|
|
163
|
+
- `bm25_weight` (optional): Keyword weight (default: 0.4)
|
|
164
|
+
- `vector_weight` (optional): Semantic weight (default: 0.4)
|
|
165
|
+
- `graph_weight` (optional): Relationship weight (default: 0.2)
|
|
166
|
+
- `memory_types` (optional): Filter by types
|
|
167
|
+
- `importance_threshold` (optional): Minimum importance
|
|
168
|
+
- `enable_graph_expansion` (optional): Enable traversal (default: true)
|
|
169
|
+
|
|
170
|
+
**Example:**
|
|
171
|
+
```typescript
|
|
172
|
+
{
|
|
173
|
+
"query": "programming preferences",
|
|
174
|
+
"limit": 10,
|
|
175
|
+
"vector_weight": 0.5,
|
|
176
|
+
"bm25_weight": 0.3,
|
|
177
|
+
"graph_weight": 0.2
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
#### `penfield_search`
|
|
182
|
+
Semantic search variant (higher vector weight).
|
|
183
|
+
|
|
184
|
+
**Parameters:**
|
|
185
|
+
- `query` (required): Search query
|
|
186
|
+
- `limit` (optional): Max results
|
|
187
|
+
- `memory_types` (optional): Filter by types
|
|
188
|
+
- `importance_threshold` (optional): Minimum importance
|
|
189
|
+
|
|
190
|
+
#### `penfield_fetch`
|
|
191
|
+
Get a specific memory by ID.
|
|
192
|
+
|
|
193
|
+
**Parameters:**
|
|
194
|
+
- `memory_id` (required): Memory ID to fetch
|
|
195
|
+
|
|
196
|
+
#### `penfield_update_memory`
|
|
197
|
+
Update an existing memory.
|
|
198
|
+
|
|
199
|
+
**Parameters:**
|
|
200
|
+
- `memory_id` (required): Memory ID to update
|
|
201
|
+
- `content` (optional): Updated content
|
|
202
|
+
- `memory_type` (optional): Updated type
|
|
203
|
+
- `importance` (optional): Updated importance
|
|
204
|
+
- `confidence` (optional): Updated confidence
|
|
205
|
+
- `tags` (optional): Updated tags
|
|
206
|
+
|
|
207
|
+
### Knowledge Graph
|
|
208
|
+
|
|
209
|
+
#### `penfield_connect`
|
|
210
|
+
Create a relationship between two memories.
|
|
211
|
+
|
|
212
|
+
**Parameters:**
|
|
213
|
+
- `from_memory_id` (required): Source memory ID
|
|
214
|
+
- `to_memory_id` (required): Target memory ID
|
|
215
|
+
- `relationship_type` (required): Type of relationship
|
|
216
|
+
- **Knowledge Evolution**: supersedes, updates, evolution_of
|
|
217
|
+
- **Evidence & Support**: supports, contradicts, disputes
|
|
218
|
+
- **Hierarchy & Structure**: parent_of, child_of, sibling_of, composed_of, part_of
|
|
219
|
+
- **Cause & Prerequisites**: causes, influenced_by, prerequisite_for
|
|
220
|
+
- **Implementation & Testing**: implements, documents, tests, example_of
|
|
221
|
+
- **Conversation & Attribution**: responds_to, references, inspired_by
|
|
222
|
+
- **Sequence & Flow**: follows, precedes
|
|
223
|
+
- **Dependencies**: depends_on
|
|
224
|
+
- `strength` (optional): Relationship strength 0-1 (default: 0.8)
|
|
225
|
+
|
|
226
|
+
**Example:**
|
|
227
|
+
```typescript
|
|
228
|
+
{
|
|
229
|
+
"from_memory_id": "22618318-8d82-49c9-8bb8-1cf3a61b3c75",
|
|
230
|
+
"to_memory_id": "20413926-2446-4f88-bfd6-749b37969f34",
|
|
231
|
+
"relationship_type": "supports",
|
|
232
|
+
"strength": 0.9
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### `penfield_explore`
|
|
237
|
+
Traverse the knowledge graph from a starting memory.
|
|
238
|
+
|
|
239
|
+
**Parameters:**
|
|
240
|
+
- `start_memory_id` (required): Starting memory ID
|
|
241
|
+
- `max_depth` (optional): Max traversal depth (default: 3, max: 10)
|
|
242
|
+
- `relationship_types` (optional): Filter by relationship types
|
|
243
|
+
- `min_strength` (optional): Minimum relationship strength
|
|
244
|
+
|
|
245
|
+
### Context Management
|
|
246
|
+
|
|
247
|
+
#### `penfield_save_context`
|
|
248
|
+
Save a checkpoint of current memory state.
|
|
249
|
+
|
|
250
|
+
**Parameters:**
|
|
251
|
+
- `memory_ids` (required): Array of memory IDs to save
|
|
252
|
+
- `session_id` (optional): Session identifier
|
|
253
|
+
|
|
254
|
+
#### `penfield_restore_context`
|
|
255
|
+
Restore a previously saved checkpoint.
|
|
256
|
+
|
|
257
|
+
**Parameters:**
|
|
258
|
+
- `checkpoint_id` (required): Checkpoint ID to restore
|
|
259
|
+
- `full_restore` (optional): Create new copies of memories instead of referencing existing (default: false)
|
|
260
|
+
- `merge_mode` (optional): How to handle conflicts - "append", "replace", or "smart_merge" (default: "append")
|
|
261
|
+
|
|
262
|
+
#### `penfield_list_contexts`
|
|
263
|
+
List all saved checkpoints.
|
|
264
|
+
|
|
265
|
+
**Parameters:**
|
|
266
|
+
- `session_id` (optional): Filter by session ID
|
|
267
|
+
- `limit` (optional): Max results (default: 20, max: 100)
|
|
268
|
+
|
|
269
|
+
### Analysis
|
|
270
|
+
|
|
271
|
+
#### `penfield_reflect`
|
|
272
|
+
Analyze memory patterns and generate insights.
|
|
273
|
+
|
|
274
|
+
**Parameters:**
|
|
275
|
+
- `time_window` (optional): Time window - "1d", "7d", "30d", or "90d" (default: "7d")
|
|
276
|
+
- `focus_areas` (optional): Areas to analyze - "memory_usage", "relationships", "importance", "topics", "patterns"
|
|
277
|
+
- `memory_types` (optional): Filter by memory types - "fact", "insight", "conversation", "correction", "reference", "task", "checkpoint", "identity_core", "personality_trait", "relationship", "strategy"
|
|
278
|
+
|
|
279
|
+
### Artifact Storage
|
|
280
|
+
|
|
281
|
+
#### `penfield_save_artifact`
|
|
282
|
+
Save a file artifact to Penfield storage.
|
|
283
|
+
|
|
284
|
+
**Parameters:**
|
|
285
|
+
- `path` (required): Artifact path (e.g., "/project/file.txt")
|
|
286
|
+
- `content` (required): Artifact content
|
|
287
|
+
- `content_type` (optional): MIME type (default: "text/plain")
|
|
288
|
+
|
|
289
|
+
#### `penfield_retrieve_artifact`
|
|
290
|
+
Retrieve a file artifact from Penfield storage.
|
|
291
|
+
|
|
292
|
+
**Parameters:**
|
|
293
|
+
- `path` (required): Artifact path to retrieve
|
|
294
|
+
|
|
295
|
+
#### `penfield_list_artifacts`
|
|
296
|
+
List artifacts in a directory.
|
|
297
|
+
|
|
298
|
+
**Parameters:**
|
|
299
|
+
- `prefix` (optional): Directory prefix (e.g., "/project/")
|
|
300
|
+
- `limit` (optional): Max results (default: 100, max: 1000)
|
|
301
|
+
|
|
302
|
+
#### `penfield_delete_artifact`
|
|
303
|
+
Delete a file artifact from Penfield storage.
|
|
304
|
+
|
|
305
|
+
**Parameters:**
|
|
306
|
+
- `path` (required): Artifact path to delete
|
|
307
|
+
|
|
308
|
+
### Personality
|
|
309
|
+
|
|
310
|
+
#### `penfield_awaken`
|
|
311
|
+
Load personality configuration and identity core memories.
|
|
312
|
+
|
|
313
|
+
**Parameters:** None
|
|
314
|
+
|
|
315
|
+
## Usage Examples
|
|
316
|
+
|
|
317
|
+
### Basic Memory Storage and Retrieval
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// Store a memory
|
|
321
|
+
await penfield_store({
|
|
322
|
+
content: "User prefers dark mode for coding",
|
|
323
|
+
memory_type: "fact",
|
|
324
|
+
importance: 0.8,
|
|
325
|
+
tags: ["preferences", "ui"]
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Recall memories
|
|
329
|
+
const results = await penfield_recall({
|
|
330
|
+
query: "user interface preferences",
|
|
331
|
+
limit: 5
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Building Knowledge Graphs
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Store two related memories
|
|
339
|
+
const mem1 = await penfield_store({
|
|
340
|
+
content: "TypeScript provides static typing",
|
|
341
|
+
memory_type: "fact"
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const mem2 = await penfield_store({
|
|
345
|
+
content: "Static typing helps catch bugs early",
|
|
346
|
+
memory_type: "insight"
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Connect them
|
|
350
|
+
await penfield_connect({
|
|
351
|
+
from_memory_id: mem1.id,
|
|
352
|
+
to_memory_id: mem2.id,
|
|
353
|
+
relationship_type: "supports",
|
|
354
|
+
strength: 0.9
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Explore the graph
|
|
358
|
+
const graph = await penfield_explore({
|
|
359
|
+
start_memory_id: mem1.id,
|
|
360
|
+
max_depth: 2
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Context Checkpoints
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
// Save context
|
|
368
|
+
const checkpoint = await penfield_save_context({
|
|
369
|
+
memory_ids: ["mem_1", "mem_2", "mem_3"],
|
|
370
|
+
session_id: "session_123"
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Restore later
|
|
374
|
+
await penfield_restore_context({
|
|
375
|
+
checkpoint_id: checkpoint.id,
|
|
376
|
+
full_restore: true
|
|
377
|
+
});
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Development
|
|
381
|
+
|
|
382
|
+
### Setup
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm install
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Type Check
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
npm run typecheck
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Lint
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
npm run lint
|
|
398
|
+
npm run lint:fix
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Format
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
npm run format
|
|
405
|
+
npm run format:check
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Build
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
npm run build
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## Architecture
|
|
415
|
+
|
|
416
|
+
```
|
|
417
|
+
index.ts # Plugin entry point and registration
|
|
418
|
+
src/
|
|
419
|
+
├── config.ts # Zod configuration schema with DEFAULT_AUTH_URL/DEFAULT_API_URL
|
|
420
|
+
├── types.ts # TypeScript type definitions (single source)
|
|
421
|
+
├── types/typebox.ts # Centralized TypeBox exports
|
|
422
|
+
├── auth-service.ts # Background OAuth token refresh service
|
|
423
|
+
├── api-client.ts # HTTP client wrapper
|
|
424
|
+
├── runtime.ts # Runtime factory (receives authService from index.ts)
|
|
425
|
+
├── store.ts # Credential file I/O with TOKEN_EXPIRY_BUFFER_MS
|
|
426
|
+
├── cli.ts # CLI command registration (penfield login)
|
|
427
|
+
├── device-flow.ts # RFC 8628 Device Code Flow implementation
|
|
428
|
+
└── tools/
|
|
429
|
+
├── index.ts # Tool registry (16 tools)
|
|
430
|
+
├── store.ts # penfield_store
|
|
431
|
+
├── recall.ts # penfield_recall
|
|
432
|
+
├── search.ts # penfield_search
|
|
433
|
+
├── fetch.ts # penfield_fetch
|
|
434
|
+
├── update-memory.ts # penfield_update_memory
|
|
435
|
+
├── connect.ts # penfield_connect
|
|
436
|
+
├── explore.ts # penfield_explore
|
|
437
|
+
├── save-context.ts # penfield_save_context
|
|
438
|
+
├── restore-context.ts # penfield_restore_context
|
|
439
|
+
├── list-contexts.ts # penfield_list_contexts
|
|
440
|
+
├── reflect.ts # penfield_reflect
|
|
441
|
+
├── save-artifact.ts # penfield_save_artifact
|
|
442
|
+
├── retrieve-artifact.ts # penfield_retrieve_artifact
|
|
443
|
+
├── list-artifacts.ts # penfield_list_artifacts
|
|
444
|
+
├── delete-artifact.ts # penfield_delete_artifact
|
|
445
|
+
└── awaken.ts # penfield_awaken
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
## Service Lifecycle
|
|
449
|
+
|
|
450
|
+
The plugin uses two services registered with Clawdbot:
|
|
451
|
+
|
|
452
|
+
1. **penfield-auth**: Background token refresh service
|
|
453
|
+
- Started when plugin loads
|
|
454
|
+
- Checks token expiry every 60 minutes
|
|
455
|
+
- Auto-refreshes if within 240-minute buffer
|
|
456
|
+
|
|
457
|
+
2. **penfield**: Runtime lifecycle service
|
|
458
|
+
- Manages runtime initialization
|
|
459
|
+
- Handles cleanup on shutdown
|
|
460
|
+
|
|
461
|
+
## API Endpoint Mapping
|
|
462
|
+
|
|
463
|
+
| Tool | Method | Endpoint |
|
|
464
|
+
|------|--------|----------|
|
|
465
|
+
| awaken | GET | /api/v2/personality/awakening |
|
|
466
|
+
| connect | POST | /api/v2/relationships |
|
|
467
|
+
| delete_artifact | DELETE | /api/v2/artifacts |
|
|
468
|
+
| explore | POST | /api/v2/relationships/traverse |
|
|
469
|
+
| fetch | GET | /api/v2/memories/{id} |
|
|
470
|
+
| list_artifacts | GET | /api/v2/artifacts/list |
|
|
471
|
+
| list_contexts | GET | /api/v2/checkpoint |
|
|
472
|
+
| recall | POST | /api/v2/search/hybrid |
|
|
473
|
+
| reflect | POST | /api/v2/analysis/reflect |
|
|
474
|
+
| restore_context | POST | /api/v2/checkpoint/{id}/recall |
|
|
475
|
+
| retrieve_artifact | GET | /api/v2/artifacts |
|
|
476
|
+
| save_artifact | POST | /api/v2/artifacts |
|
|
477
|
+
| save_context | POST | /api/v2/checkpoint/create |
|
|
478
|
+
| search | POST | /api/v2/search/hybrid |
|
|
479
|
+
| store | POST | /api/v2/memories |
|
|
480
|
+
| update_memory | PUT | /api/v2/memories/{id} |
|
|
481
|
+
|
|
482
|
+
## Error Handling
|
|
483
|
+
|
|
484
|
+
All tools return errors in a consistent format:
|
|
485
|
+
|
|
486
|
+
```json
|
|
487
|
+
{
|
|
488
|
+
"error": "Error message here"
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Common errors:
|
|
493
|
+
- **401 Unauthorized**: Token expired or invalid (auto-refreshes)
|
|
494
|
+
- **429 Rate Limited**: Too many requests (includes retry-after header)
|
|
495
|
+
- **500 Internal Server Error**: API error
|
|
496
|
+
|
|
497
|
+
## Performance
|
|
498
|
+
|
|
499
|
+
This native plugin provides significant performance improvements over the MCP server approach:
|
|
500
|
+
|
|
501
|
+
- **4-5x faster**: Direct HTTP calls vs. mcporter → MCP → Penfield
|
|
502
|
+
- **Lower latency**: No intermediate proxy servers
|
|
503
|
+
- **Reduced overhead**: Fewer serialization/deserialization steps
|
|
504
|
+
- **Auto token refresh**: No re-authentication delays
|
|
505
|
+
|
|
506
|
+
## Security
|
|
507
|
+
|
|
508
|
+
- Automatic token refresh 240 minutes before expiry
|
|
509
|
+
- RFC 8628 compliant Device Code Flow
|
|
510
|
+
- All API calls use HTTPS
|
|
511
|
+
|
|
512
|
+
## License
|
|
513
|
+
|
|
514
|
+
MIT
|
|
515
|
+
|
|
516
|
+
## Support
|
|
517
|
+
|
|
518
|
+
For issues or questions:
|
|
519
|
+
- GitHub Issues: https://github.com/penfieldlabs/clawdbot-penfield/issues
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type PenfieldConfig } from "./src/config.js";
|
|
2
|
+
import type { ClawdbotPluginApi } from "./src/types.js";
|
|
3
|
+
declare const penfieldPlugin: {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
configSchema: {
|
|
8
|
+
parse(value: unknown): PenfieldConfig;
|
|
9
|
+
uiHints: {
|
|
10
|
+
enabled: {
|
|
11
|
+
label: string;
|
|
12
|
+
help: string;
|
|
13
|
+
};
|
|
14
|
+
authUrl: {
|
|
15
|
+
label: string;
|
|
16
|
+
help: string;
|
|
17
|
+
};
|
|
18
|
+
apiUrl: {
|
|
19
|
+
label: string;
|
|
20
|
+
help: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
register(api: ClawdbotPluginApi): void;
|
|
25
|
+
};
|
|
26
|
+
export default penfieldPlugin;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0C,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAK9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,QAAA,MAAM,cAAc;;;;;qBAMH,OAAO,GAAG,cAAc;;;;;;;;;;;;;;;;kBAuBzB,iBAAiB;CAkEhC,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { DEFAULT_AUTH_URL, PenfieldConfigSchema } from "./src/config.js";
|
|
2
|
+
import { createPenfieldRuntime } from "./src/runtime.js";
|
|
3
|
+
import { registerPenfieldTools } from "./src/tools/index.js";
|
|
4
|
+
import { registerLoginCommand } from "./src/cli.js";
|
|
5
|
+
import { createAuthService } from "./src/auth-service.js";
|
|
6
|
+
const penfieldPlugin = {
|
|
7
|
+
id: "penfield",
|
|
8
|
+
name: "Penfield Memory",
|
|
9
|
+
description: "Native Penfield memory integration with 16 tools for knowledge management",
|
|
10
|
+
configSchema: {
|
|
11
|
+
parse(value) {
|
|
12
|
+
// Handle undefined/null when no config section exists
|
|
13
|
+
if (value === undefined || value === null) {
|
|
14
|
+
return {};
|
|
15
|
+
}
|
|
16
|
+
return PenfieldConfigSchema.parse(value);
|
|
17
|
+
},
|
|
18
|
+
uiHints: {
|
|
19
|
+
enabled: {
|
|
20
|
+
label: "Enable Penfield",
|
|
21
|
+
help: "Enable Penfield memory integration",
|
|
22
|
+
},
|
|
23
|
+
authUrl: {
|
|
24
|
+
label: "Auth URL",
|
|
25
|
+
help: "Penfield Auth service URL (default: https://auth.penfield.app)",
|
|
26
|
+
},
|
|
27
|
+
apiUrl: {
|
|
28
|
+
label: "API URL",
|
|
29
|
+
help: "Penfield API URL (default: https://api.penfield.app)",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
register(api) {
|
|
34
|
+
const cfg = PenfieldConfigSchema.parse(api.pluginConfig ?? {});
|
|
35
|
+
const logger = api.logger;
|
|
36
|
+
// Runtime state - follows voice-call pattern
|
|
37
|
+
let runtimePromise = null;
|
|
38
|
+
let runtime = null;
|
|
39
|
+
// Create auth service (single instance)
|
|
40
|
+
const authUrl = cfg.authUrl || DEFAULT_AUTH_URL;
|
|
41
|
+
const authService = createAuthService(api, {
|
|
42
|
+
authUrl,
|
|
43
|
+
// clientId loaded from credentials on first login
|
|
44
|
+
});
|
|
45
|
+
// Lazy runtime initialization with race condition protection
|
|
46
|
+
const ensureRuntime = async () => {
|
|
47
|
+
if (runtime)
|
|
48
|
+
return runtime;
|
|
49
|
+
if (!runtimePromise) {
|
|
50
|
+
runtimePromise = createPenfieldRuntime({
|
|
51
|
+
api,
|
|
52
|
+
config: cfg,
|
|
53
|
+
authService,
|
|
54
|
+
logger,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
runtime = await runtimePromise;
|
|
58
|
+
return runtime;
|
|
59
|
+
};
|
|
60
|
+
// Register CLI commands (penfield login)
|
|
61
|
+
registerLoginCommand(api);
|
|
62
|
+
// Register background auth service
|
|
63
|
+
api.registerService({
|
|
64
|
+
id: "penfield-auth",
|
|
65
|
+
async start() {
|
|
66
|
+
await authService.start();
|
|
67
|
+
logger.info("[penfield-auth] Service started");
|
|
68
|
+
},
|
|
69
|
+
async stop() {
|
|
70
|
+
await authService.stop();
|
|
71
|
+
logger.info("[penfield-auth] Service stopped");
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
// Register all 16 tools
|
|
75
|
+
registerPenfieldTools(api, ensureRuntime);
|
|
76
|
+
// Register service for runtime lifecycle
|
|
77
|
+
api.registerService({
|
|
78
|
+
id: "penfield",
|
|
79
|
+
async start() {
|
|
80
|
+
logger.info("[penfield] Service started");
|
|
81
|
+
},
|
|
82
|
+
async stop() {
|
|
83
|
+
if (runtime) {
|
|
84
|
+
await runtime.stop();
|
|
85
|
+
runtime = null;
|
|
86
|
+
runtimePromise = null;
|
|
87
|
+
}
|
|
88
|
+
logger.info("[penfield] Service stopped");
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
export default penfieldPlugin;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuthService } from "./auth-service.js";
|
|
2
|
+
import type { Logger } from "./types.js";
|
|
3
|
+
export declare class PenfieldApiClient {
|
|
4
|
+
private auth;
|
|
5
|
+
private apiUrl;
|
|
6
|
+
private logger?;
|
|
7
|
+
constructor(auth: AuthService, apiUrl: string, logger?: Logger | undefined);
|
|
8
|
+
request<T>(method: string, endpoint: string, body?: unknown, queryParams?: Record<string, string>): Promise<T>;
|
|
9
|
+
get<T>(endpoint: string, queryParams?: Record<string, string>): Promise<T>;
|
|
10
|
+
post<T>(endpoint: string, body?: unknown): Promise<T>;
|
|
11
|
+
put<T>(endpoint: string, body?: unknown): Promise<T>;
|
|
12
|
+
delete<T>(endpoint: string, queryParams?: Record<string, string>): Promise<T>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM,CAAC;gBAFP,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,YAAA;IAGnB,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,EACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,CAAC,CAAC;IAuCP,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAI1E,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpD,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAGpF"}
|