jasper-recall 0.4.0 → 0.4.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/cli/jasper-recall.js +38 -4
- package/extensions/moltbook-setup/setup.js +254 -103
- package/package.json +1 -1
package/cli/jasper-recall.js
CHANGED
|
@@ -198,6 +198,36 @@ function setup() {
|
|
|
198
198
|
console.log(' 1. index-digests # Index your memory files');
|
|
199
199
|
console.log(' 2. recall "query" # Search your memory');
|
|
200
200
|
console.log(' 3. digest-sessions # Process session logs');
|
|
201
|
+
console.log('');
|
|
202
|
+
|
|
203
|
+
// Check for sandboxed agents
|
|
204
|
+
const sandboxedWorkspaces = findSandboxedWorkspaces();
|
|
205
|
+
if (sandboxedWorkspaces.length > 0) {
|
|
206
|
+
console.log('📦 Sandboxed agents detected:');
|
|
207
|
+
sandboxedWorkspaces.forEach(ws => console.log(` - ${ws}`));
|
|
208
|
+
console.log('');
|
|
209
|
+
console.log(' Configure them with: npx jasper-recall sandboxed-setup');
|
|
210
|
+
console.log(' (gives them --public-only access to shared memories)');
|
|
211
|
+
console.log('');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function findSandboxedWorkspaces() {
|
|
216
|
+
const openclawDir = path.join(os.homedir(), '.openclaw');
|
|
217
|
+
const workspaces = [];
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
const entries = fs.readdirSync(openclawDir);
|
|
221
|
+
for (const entry of entries) {
|
|
222
|
+
if (entry.startsWith('workspace-') && entry !== 'workspace') {
|
|
223
|
+
workspaces.push(entry.replace('workspace-', ''));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
} catch (e) {
|
|
227
|
+
// Directory doesn't exist
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return workspaces;
|
|
201
231
|
}
|
|
202
232
|
|
|
203
233
|
function showHelp() {
|
|
@@ -219,8 +249,8 @@ COMMANDS:
|
|
|
219
249
|
serve Start HTTP API server (for sandboxed agents)
|
|
220
250
|
config Show or set configuration
|
|
221
251
|
update Check for updates
|
|
222
|
-
|
|
223
|
-
|
|
252
|
+
sandboxed-setup Configure sandboxed agents (email, social, calendar, etc.)
|
|
253
|
+
sandboxed-verify Verify sandboxed agent configurations
|
|
224
254
|
help Show this help message
|
|
225
255
|
|
|
226
256
|
CONFIGURATION:
|
|
@@ -313,14 +343,18 @@ switch (command) {
|
|
|
313
343
|
};
|
|
314
344
|
process.exit(runDoctor(options));
|
|
315
345
|
break;
|
|
346
|
+
case 'sandboxed-setup':
|
|
347
|
+
case 'sandbox-setup':
|
|
316
348
|
case 'moltbook-setup':
|
|
317
349
|
case 'moltbook':
|
|
318
|
-
//
|
|
350
|
+
// Interactive setup for sandboxed agents
|
|
319
351
|
process.argv = [process.argv[0], process.argv[1], 'setup'];
|
|
320
352
|
require('../extensions/moltbook-setup/setup.js');
|
|
321
353
|
break;
|
|
354
|
+
case 'sandboxed-verify':
|
|
355
|
+
case 'sandbox-verify':
|
|
322
356
|
case 'moltbook-verify':
|
|
323
|
-
// Verify
|
|
357
|
+
// Verify sandboxed agent setups
|
|
324
358
|
process.argv = [process.argv[0], process.argv[1], 'verify'];
|
|
325
359
|
require('../extensions/moltbook-setup/setup.js');
|
|
326
360
|
break;
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Sandboxed Agent Setup for jasper-recall
|
|
4
4
|
*
|
|
5
|
-
* Configures
|
|
6
|
-
* This ensures
|
|
5
|
+
* Configures sandboxed agents to use jasper-recall with --public-only restriction.
|
|
6
|
+
* This ensures agents can only access shared/public memories, not private ones.
|
|
7
|
+
*
|
|
8
|
+
* Use cases:
|
|
9
|
+
* - Moltbook scanner (social media engagement)
|
|
10
|
+
* - Email agent (inbox management)
|
|
11
|
+
* - Calendar agent (scheduling)
|
|
12
|
+
* - Any agent that shouldn't see private memories
|
|
7
13
|
*/
|
|
8
14
|
|
|
9
15
|
const fs = require('fs');
|
|
@@ -11,12 +17,12 @@ const path = require('path');
|
|
|
11
17
|
const os = require('os');
|
|
12
18
|
const readline = require('readline');
|
|
13
19
|
|
|
14
|
-
const
|
|
15
|
-
const MAIN_WORKSPACE = path.join(
|
|
20
|
+
const OPENCLAW_DIR = path.join(os.homedir(), '.openclaw');
|
|
21
|
+
const MAIN_WORKSPACE = path.join(OPENCLAW_DIR, 'workspace');
|
|
16
22
|
const RECALL_BIN = path.join(os.homedir(), '.local', 'bin', 'recall');
|
|
17
23
|
|
|
18
24
|
function log(msg) {
|
|
19
|
-
console.log(
|
|
25
|
+
console.log(`🔒 ${msg}`);
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
function warn(msg) {
|
|
@@ -45,43 +51,110 @@ async function prompt(question) {
|
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
async function
|
|
54
|
+
async function interactiveSetup() {
|
|
49
55
|
console.log('');
|
|
50
|
-
log('
|
|
51
|
-
console.log('='.repeat(
|
|
56
|
+
log('Sandboxed Agent Setup — jasper-recall Integration');
|
|
57
|
+
console.log('='.repeat(60));
|
|
52
58
|
console.log('');
|
|
53
|
-
console.log(' This configures
|
|
54
|
-
console.log('
|
|
59
|
+
console.log(' This configures a sandboxed agent to use jasper-recall with');
|
|
60
|
+
console.log(' privacy restrictions (--public-only).');
|
|
55
61
|
console.log('');
|
|
56
|
-
console.log('
|
|
57
|
-
console.log('
|
|
58
|
-
console.log(' 2. Symlinks shared/ folder from main workspace');
|
|
59
|
-
console.log(' 3. Verifies jasper-recall is installed');
|
|
62
|
+
console.log(' 🔒 Privacy: Sandboxed agents can ONLY see [public] memories.');
|
|
63
|
+
console.log(' They cannot access your private notes or secrets.');
|
|
60
64
|
console.log('');
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
|
|
66
|
+
// List existing workspaces
|
|
67
|
+
const workspaces = findAgentWorkspaces();
|
|
68
|
+
|
|
69
|
+
if (workspaces.length === 0) {
|
|
70
|
+
console.log(' No sandboxed agent workspaces found.');
|
|
71
|
+
console.log('');
|
|
72
|
+
console.log(' To create one, add an agent to your openclaw.json:');
|
|
73
|
+
console.log('');
|
|
74
|
+
showAgentExample();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
console.log(' Found agent workspaces:');
|
|
79
|
+
workspaces.forEach((ws, i) => {
|
|
80
|
+
const status = checkWorkspaceStatus(ws.path);
|
|
81
|
+
const statusIcon = status.configured ? '✅' : '⚪';
|
|
82
|
+
console.log(` ${i + 1}. ${statusIcon} ${ws.name} (${ws.path})`);
|
|
83
|
+
});
|
|
84
|
+
console.log('');
|
|
85
|
+
|
|
86
|
+
const choice = await prompt(' Configure which agent? (number, or "skip" to exit): ');
|
|
87
|
+
|
|
88
|
+
if (choice.toLowerCase() === 'skip' || choice === '') {
|
|
89
|
+
console.log('\n Skipped.\n');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const index = parseInt(choice, 10) - 1;
|
|
94
|
+
if (isNaN(index) || index < 0 || index >= workspaces.length) {
|
|
95
|
+
error('Invalid selection');
|
|
96
|
+
return;
|
|
67
97
|
}
|
|
98
|
+
|
|
99
|
+
const selected = workspaces[index];
|
|
100
|
+
await setupWorkspace(selected.path, selected.name);
|
|
101
|
+
}
|
|
68
102
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
function findAgentWorkspaces() {
|
|
104
|
+
const workspaces = [];
|
|
105
|
+
|
|
106
|
+
// Look for workspace-* directories
|
|
107
|
+
try {
|
|
108
|
+
const entries = fs.readdirSync(OPENCLAW_DIR);
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
if (entry.startsWith('workspace-') && entry !== 'workspace') {
|
|
111
|
+
const wsPath = path.join(OPENCLAW_DIR, entry);
|
|
112
|
+
if (fs.statSync(wsPath).isDirectory()) {
|
|
113
|
+
workspaces.push({
|
|
114
|
+
name: entry.replace('workspace-', ''),
|
|
115
|
+
path: wsPath
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (e) {
|
|
121
|
+
// Directory doesn't exist or not readable
|
|
73
122
|
}
|
|
123
|
+
|
|
124
|
+
return workspaces;
|
|
125
|
+
}
|
|
74
126
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
127
|
+
function checkWorkspaceStatus(wsPath) {
|
|
128
|
+
const wrapperPath = path.join(wsPath, 'bin', 'recall');
|
|
129
|
+
const sharedPath = path.join(wsPath, 'shared');
|
|
130
|
+
|
|
131
|
+
let configured = false;
|
|
132
|
+
|
|
133
|
+
if (fs.existsSync(wrapperPath)) {
|
|
134
|
+
const content = fs.readFileSync(wrapperPath, 'utf8');
|
|
135
|
+
configured = content.includes('--public-only');
|
|
79
136
|
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
configured,
|
|
140
|
+
hasWrapper: fs.existsSync(wrapperPath),
|
|
141
|
+
hasShared: fs.existsSync(sharedPath)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
80
144
|
|
|
145
|
+
async function setupWorkspace(wsPath, name) {
|
|
81
146
|
console.log('');
|
|
82
|
-
|
|
147
|
+
log(`Configuring ${name}...`);
|
|
148
|
+
|
|
149
|
+
// Check prerequisites
|
|
150
|
+
if (!fs.existsSync(RECALL_BIN)) {
|
|
151
|
+
error(`jasper-recall not installed: ${RECALL_BIN}`);
|
|
152
|
+
console.log(' Run the main setup first: npx jasper-recall setup');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
83
156
|
// Step 1: Create bin directory and wrapper
|
|
84
|
-
const binDir = path.join(
|
|
157
|
+
const binDir = path.join(wsPath, 'bin');
|
|
85
158
|
const wrapperPath = path.join(binDir, 'recall');
|
|
86
159
|
|
|
87
160
|
fs.mkdirSync(binDir, { recursive: true });
|
|
@@ -95,11 +168,11 @@ exec ${RECALL_BIN} "$@" --public-only
|
|
|
95
168
|
|
|
96
169
|
fs.writeFileSync(wrapperPath, wrapperScript);
|
|
97
170
|
fs.chmodSync(wrapperPath, '755');
|
|
98
|
-
success(`Created recall wrapper:
|
|
171
|
+
success(`Created recall wrapper: bin/recall`);
|
|
99
172
|
|
|
100
173
|
// Step 2: Create shared folder symlink
|
|
101
174
|
const sharedSource = path.join(MAIN_WORKSPACE, 'memory', 'shared');
|
|
102
|
-
const sharedTarget = path.join(
|
|
175
|
+
const sharedTarget = path.join(wsPath, 'shared');
|
|
103
176
|
|
|
104
177
|
// Ensure source exists
|
|
105
178
|
fs.mkdirSync(sharedSource, { recursive: true });
|
|
@@ -109,8 +182,6 @@ exec ${RECALL_BIN} "$@" --public-only
|
|
|
109
182
|
const stat = fs.lstatSync(sharedTarget);
|
|
110
183
|
if (stat.isSymbolicLink()) {
|
|
111
184
|
fs.unlinkSync(sharedTarget);
|
|
112
|
-
} else if (stat.isDirectory()) {
|
|
113
|
-
warn(`${sharedTarget} is a directory, not a symlink. Skipping.`);
|
|
114
185
|
}
|
|
115
186
|
} catch (e) {
|
|
116
187
|
// Doesn't exist, that's fine
|
|
@@ -118,58 +189,106 @@ exec ${RECALL_BIN} "$@" --public-only
|
|
|
118
189
|
|
|
119
190
|
if (!fs.existsSync(sharedTarget)) {
|
|
120
191
|
fs.symlinkSync(sharedSource, sharedTarget);
|
|
121
|
-
success(`Created symlink: shared/ →
|
|
192
|
+
success(`Created symlink: shared/ → main workspace`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Step 3: Check if AGENTS.md exists and suggest update
|
|
196
|
+
const agentsMd = path.join(wsPath, 'AGENTS.md');
|
|
197
|
+
if (fs.existsSync(agentsMd)) {
|
|
198
|
+
const content = fs.readFileSync(agentsMd, 'utf8');
|
|
199
|
+
if (!content.includes('public-only') && !content.includes('--public-only')) {
|
|
200
|
+
warn('Consider adding recall restrictions to AGENTS.md');
|
|
201
|
+
console.log('');
|
|
202
|
+
console.log(' Suggested addition:');
|
|
203
|
+
console.log(' ```');
|
|
204
|
+
console.log(' ## Memory Access');
|
|
205
|
+
console.log(' Use `~/bin/recall "query"` for memory search.');
|
|
206
|
+
console.log(' This wrapper enforces --public-only (you cannot see private memories).');
|
|
207
|
+
console.log(' ```');
|
|
208
|
+
}
|
|
122
209
|
}
|
|
123
210
|
|
|
124
|
-
// Step 3: Verify setup
|
|
125
211
|
console.log('');
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
212
|
+
success(`${name} configured!`);
|
|
213
|
+
console.log('');
|
|
214
|
+
console.log(' The agent can now use:');
|
|
215
|
+
console.log(` ~/bin/recall "query" — searches public memories only`);
|
|
216
|
+
console.log(` shared/ — symlink to shared memory folder`);
|
|
217
|
+
console.log('');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function showAgentExample() {
|
|
221
|
+
console.log(` Example openclaw.json agent config:
|
|
129
222
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
223
|
+
{
|
|
224
|
+
"agents": {
|
|
225
|
+
"list": [
|
|
226
|
+
{
|
|
227
|
+
"id": "email-agent",
|
|
228
|
+
"workspace": "~/.openclaw/workspace-email",
|
|
229
|
+
"model": { "primary": "anthropic/claude-sonnet-4-5" },
|
|
230
|
+
"sandbox": {
|
|
231
|
+
"mode": "all",
|
|
232
|
+
"workspaceAccess": "rw"
|
|
233
|
+
},
|
|
234
|
+
"tools": {
|
|
235
|
+
"profile": "minimal",
|
|
236
|
+
"allow": ["read", "write", "exec", "web_fetch"]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
}
|
|
146
241
|
}
|
|
242
|
+
|
|
243
|
+
Common sandboxed agent use cases:
|
|
244
|
+
|
|
245
|
+
📧 Email Agent
|
|
246
|
+
- Checks inbox, drafts replies, summarizes threads
|
|
247
|
+
- Sandbox: Only email API access, no filesystem
|
|
248
|
+
- Memory: Sees [public] context about projects
|
|
249
|
+
|
|
250
|
+
📱 Social Agent (Moltbook, Twitter, etc.)
|
|
251
|
+
- Monitors feeds, engages with posts
|
|
252
|
+
- Sandbox: Only that platform's API
|
|
253
|
+
- Memory: Sees [public] product info for authentic engagement
|
|
254
|
+
|
|
255
|
+
📅 Calendar Agent
|
|
256
|
+
- Manages scheduling, sends reminders
|
|
257
|
+
- Sandbox: Only calendar API
|
|
258
|
+
- Memory: Sees [public] project timelines
|
|
259
|
+
|
|
260
|
+
🔍 Research Agent
|
|
261
|
+
- Web searches, summarizes articles
|
|
262
|
+
- Sandbox: Read-only web access
|
|
263
|
+
- Memory: Sees [public] research context
|
|
264
|
+
|
|
265
|
+
After creating the workspace, run:
|
|
266
|
+
npx jasper-recall sandboxed-setup
|
|
267
|
+
`);
|
|
147
268
|
}
|
|
148
269
|
|
|
149
|
-
function verify(options = {}) {
|
|
270
|
+
function verify(wsPath, options = {}) {
|
|
150
271
|
const { quiet = false } = options;
|
|
151
272
|
const issues = [];
|
|
152
273
|
|
|
153
274
|
if (!quiet) {
|
|
154
275
|
console.log('');
|
|
155
|
-
log('
|
|
156
|
-
console.log('='.repeat(55));
|
|
276
|
+
log('Verifying sandboxed agent setup...');
|
|
157
277
|
console.log('');
|
|
158
278
|
}
|
|
159
279
|
|
|
160
280
|
// Check 1: Workspace exists
|
|
161
|
-
if (!fs.existsSync(
|
|
162
|
-
issues.push(`Workspace missing: ${
|
|
281
|
+
if (!fs.existsSync(wsPath)) {
|
|
282
|
+
issues.push(`Workspace missing: ${wsPath}`);
|
|
163
283
|
} else if (!quiet) {
|
|
164
|
-
success(`Workspace exists
|
|
284
|
+
success(`Workspace exists`);
|
|
165
285
|
}
|
|
166
286
|
|
|
167
|
-
// Check 2: Recall wrapper exists and is
|
|
168
|
-
const wrapperPath = path.join(
|
|
287
|
+
// Check 2: Recall wrapper exists and is correct
|
|
288
|
+
const wrapperPath = path.join(wsPath, 'bin', 'recall');
|
|
169
289
|
if (!fs.existsSync(wrapperPath)) {
|
|
170
|
-
issues.push(`Recall wrapper missing:
|
|
290
|
+
issues.push(`Recall wrapper missing: bin/recall`);
|
|
171
291
|
} else {
|
|
172
|
-
// Check it has --public-only
|
|
173
292
|
const content = fs.readFileSync(wrapperPath, 'utf8');
|
|
174
293
|
if (!content.includes('--public-only')) {
|
|
175
294
|
issues.push('Recall wrapper missing --public-only flag!');
|
|
@@ -179,16 +298,14 @@ function verify(options = {}) {
|
|
|
179
298
|
}
|
|
180
299
|
|
|
181
300
|
// Check 3: Shared folder is a symlink
|
|
182
|
-
const sharedPath = path.join(
|
|
301
|
+
const sharedPath = path.join(wsPath, 'shared');
|
|
183
302
|
try {
|
|
184
303
|
const stat = fs.lstatSync(sharedPath);
|
|
185
304
|
if (!stat.isSymbolicLink()) {
|
|
186
|
-
issues.push(`shared/ is not a symlink
|
|
187
|
-
} else {
|
|
305
|
+
issues.push(`shared/ is not a symlink`);
|
|
306
|
+
} else if (!quiet) {
|
|
188
307
|
const target = fs.readlinkSync(sharedPath);
|
|
189
|
-
|
|
190
|
-
success(`shared/ symlink → ${target}`);
|
|
191
|
-
}
|
|
308
|
+
success(`shared/ → ${target}`);
|
|
192
309
|
}
|
|
193
310
|
} catch (e) {
|
|
194
311
|
issues.push(`shared/ folder missing`);
|
|
@@ -196,33 +313,20 @@ function verify(options = {}) {
|
|
|
196
313
|
|
|
197
314
|
// Check 4: jasper-recall is installed
|
|
198
315
|
if (!fs.existsSync(RECALL_BIN)) {
|
|
199
|
-
issues.push(`jasper-recall not installed
|
|
316
|
+
issues.push(`jasper-recall not installed`);
|
|
200
317
|
} else if (!quiet) {
|
|
201
|
-
success(`jasper-recall installed
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Check 5: AGENTS.md mentions recall restrictions
|
|
205
|
-
const agentsMd = path.join(MOLTBOOK_WORKSPACE, 'AGENTS.md');
|
|
206
|
-
if (fs.existsSync(agentsMd)) {
|
|
207
|
-
const content = fs.readFileSync(agentsMd, 'utf8');
|
|
208
|
-
if (!content.includes('public-only') && !content.includes('public_only')) {
|
|
209
|
-
issues.push('AGENTS.md should document --public-only restriction');
|
|
210
|
-
} else if (!quiet) {
|
|
211
|
-
success('AGENTS.md documents recall restrictions');
|
|
212
|
-
}
|
|
318
|
+
success(`jasper-recall installed`);
|
|
213
319
|
}
|
|
214
320
|
|
|
215
321
|
if (!quiet) {
|
|
216
322
|
console.log('');
|
|
217
323
|
if (issues.length === 0) {
|
|
218
|
-
|
|
219
|
-
success('All checks passed! Moltbook agent is properly configured.');
|
|
324
|
+
success('All checks passed!');
|
|
220
325
|
} else {
|
|
221
|
-
console.log('='.repeat(55));
|
|
222
326
|
warn(`Found ${issues.length} issue(s):`);
|
|
223
327
|
issues.forEach(issue => console.log(` ❌ ${issue}`));
|
|
224
328
|
console.log('');
|
|
225
|
-
console.log(' Run setup to fix: npx jasper-recall
|
|
329
|
+
console.log(' Run setup to fix: npx jasper-recall sandboxed-setup');
|
|
226
330
|
}
|
|
227
331
|
console.log('');
|
|
228
332
|
}
|
|
@@ -230,27 +334,71 @@ function verify(options = {}) {
|
|
|
230
334
|
return issues;
|
|
231
335
|
}
|
|
232
336
|
|
|
337
|
+
async function verifyInteractive() {
|
|
338
|
+
const workspaces = findAgentWorkspaces();
|
|
339
|
+
|
|
340
|
+
if (workspaces.length === 0) {
|
|
341
|
+
console.log('');
|
|
342
|
+
warn('No sandboxed agent workspaces found.');
|
|
343
|
+
console.log('');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
console.log('');
|
|
348
|
+
log('Sandboxed Agent Verification');
|
|
349
|
+
console.log('='.repeat(60));
|
|
350
|
+
|
|
351
|
+
for (const ws of workspaces) {
|
|
352
|
+
console.log('');
|
|
353
|
+
console.log(` 📁 ${ws.name}`);
|
|
354
|
+
const issues = verify(ws.path, { quiet: true });
|
|
355
|
+
if (issues.length === 0) {
|
|
356
|
+
console.log(` ✅ Properly configured`);
|
|
357
|
+
} else {
|
|
358
|
+
console.log(` ⚠️ ${issues.length} issue(s):`);
|
|
359
|
+
issues.forEach(issue => console.log(` - ${issue}`));
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
console.log('');
|
|
364
|
+
}
|
|
365
|
+
|
|
233
366
|
function showHelp() {
|
|
234
367
|
console.log(`
|
|
235
|
-
|
|
368
|
+
Sandboxed Agent Setup — jasper-recall Integration
|
|
236
369
|
|
|
237
370
|
USAGE:
|
|
238
|
-
npx jasper-recall
|
|
239
|
-
npx jasper-recall
|
|
371
|
+
npx jasper-recall sandboxed-setup Interactive setup for any sandboxed agent
|
|
372
|
+
npx jasper-recall sandboxed-verify Check all sandboxed agents
|
|
373
|
+
npx jasper-recall moltbook-setup (alias) Setup for moltbook specifically
|
|
374
|
+
npx jasper-recall moltbook-verify (alias) Verify moltbook specifically
|
|
240
375
|
|
|
241
376
|
WHAT IT DOES:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
private ones from the main workspace.
|
|
377
|
+
Configures sandboxed agents to use jasper-recall with privacy restrictions.
|
|
378
|
+
Agents can only access [public] tagged memories, not private ones.
|
|
245
379
|
|
|
246
|
-
COMPONENTS:
|
|
247
|
-
|
|
248
|
-
shared/
|
|
380
|
+
COMPONENTS CREATED:
|
|
381
|
+
bin/recall Wrapper script that forces --public-only flag
|
|
382
|
+
shared/ Symlink to main workspace's shared memory folder
|
|
383
|
+
|
|
384
|
+
USE CASES:
|
|
385
|
+
📧 Email Agent — inbox management, drafts, summaries
|
|
386
|
+
📱 Social Agent — moltbook, twitter engagement
|
|
387
|
+
📅 Calendar Agent — scheduling, reminders
|
|
388
|
+
🔍 Research Agent — web searches, article summaries
|
|
249
389
|
|
|
250
390
|
PRIVACY MODEL:
|
|
251
|
-
Main agent tags memories as [public] or [private] in daily notes
|
|
252
|
-
sync-shared
|
|
253
|
-
Sandboxed agents can ONLY search the shared collection
|
|
391
|
+
1. Main agent tags memories as [public] or [private] in daily notes
|
|
392
|
+
2. sync-shared extracts [public] content to memory/shared/
|
|
393
|
+
3. Sandboxed agents can ONLY search the shared collection
|
|
394
|
+
|
|
395
|
+
EXAMPLE:
|
|
396
|
+
# Main agent daily note
|
|
397
|
+
## 2026-02-11 [public] - Shipped jasper-recall v0.4.0
|
|
398
|
+
New sandboxed agent setup feature.
|
|
399
|
+
|
|
400
|
+
## 2026-02-11 [private] - Personal context
|
|
401
|
+
This stays private, sandboxed agents can't see it.
|
|
254
402
|
`);
|
|
255
403
|
}
|
|
256
404
|
|
|
@@ -260,14 +408,17 @@ const command = process.argv[2];
|
|
|
260
408
|
switch (command) {
|
|
261
409
|
case 'setup':
|
|
262
410
|
case 'install':
|
|
263
|
-
|
|
411
|
+
interactiveSetup().catch(err => {
|
|
264
412
|
error(err.message);
|
|
265
413
|
process.exit(1);
|
|
266
414
|
});
|
|
267
415
|
break;
|
|
268
416
|
case 'verify':
|
|
269
417
|
case 'check':
|
|
270
|
-
|
|
418
|
+
verifyInteractive().catch(err => {
|
|
419
|
+
error(err.message);
|
|
420
|
+
process.exit(1);
|
|
421
|
+
});
|
|
271
422
|
break;
|
|
272
423
|
case 'help':
|
|
273
424
|
case '--help':
|