@1presence/bridge 0.2.0 → 0.4.0
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/dist/auth.js +25 -0
- package/dist/claude.js +31 -5
- package/dist/index.js +5 -0
- package/package.json +1 -1
package/dist/auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthCancelledError = void 0;
|
|
3
4
|
exports.isTokenValid = isTokenValid;
|
|
4
5
|
exports.ensureFreshToken = ensureFreshToken;
|
|
5
6
|
exports.getValidAuth = getValidAuth;
|
|
@@ -69,8 +70,13 @@ function openBrowser(url) {
|
|
|
69
70
|
console.error('Could not open browser automatically. Please open this URL manually:\n' + url);
|
|
70
71
|
});
|
|
71
72
|
}
|
|
73
|
+
class AuthCancelledError extends Error {
|
|
74
|
+
constructor() { super('Sign-in cancelled — the browser tab was closed.'); }
|
|
75
|
+
}
|
|
76
|
+
exports.AuthCancelledError = AuthCancelledError;
|
|
72
77
|
function runBrowserAuthFlow(gatewayUrl, pwaUrl) {
|
|
73
78
|
return new Promise((resolve, reject) => {
|
|
79
|
+
let resolved = false;
|
|
74
80
|
const server = (0, http_1.createServer)((req, res) => {
|
|
75
81
|
// CORS headers so the PWA (https) can POST to http://localhost
|
|
76
82
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
@@ -86,6 +92,21 @@ function runBrowserAuthFlow(gatewayUrl, pwaUrl) {
|
|
|
86
92
|
res.end();
|
|
87
93
|
return;
|
|
88
94
|
}
|
|
95
|
+
// Status beacon from the PWA — currently used so we exit early when
|
|
96
|
+
// the user closes the auth tab before signing in (sendBeacon path).
|
|
97
|
+
const path = (req.url ?? '/').split('?')[0];
|
|
98
|
+
if (path === '/status') {
|
|
99
|
+
const params = new URL(req.url ?? '/', 'http://localhost').searchParams;
|
|
100
|
+
const event = params.get('event');
|
|
101
|
+
res.writeHead(204);
|
|
102
|
+
res.end();
|
|
103
|
+
if (event === 'closed' && !resolved) {
|
|
104
|
+
resolved = true;
|
|
105
|
+
server.close();
|
|
106
|
+
reject(new AuthCancelledError());
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
89
110
|
let body = '';
|
|
90
111
|
req.on('data', (chunk) => { body += chunk.toString(); });
|
|
91
112
|
req.on('end', () => {
|
|
@@ -98,6 +119,7 @@ function runBrowserAuthFlow(gatewayUrl, pwaUrl) {
|
|
|
98
119
|
}
|
|
99
120
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
100
121
|
res.end(JSON.stringify({ ok: true }));
|
|
122
|
+
resolved = true;
|
|
101
123
|
server.close();
|
|
102
124
|
const uid = uidFromToken(token);
|
|
103
125
|
const email = emailFromToken(token);
|
|
@@ -122,6 +144,9 @@ function runBrowserAuthFlow(gatewayUrl, pwaUrl) {
|
|
|
122
144
|
openBrowser(authUrl);
|
|
123
145
|
});
|
|
124
146
|
setTimeout(() => {
|
|
147
|
+
if (resolved)
|
|
148
|
+
return;
|
|
149
|
+
resolved = true;
|
|
125
150
|
server.close();
|
|
126
151
|
reject(new Error('Sign-in timed out after 5 minutes. Please try again.'));
|
|
127
152
|
}, 5 * 60 * 1000);
|
package/dist/claude.js
CHANGED
|
@@ -12,7 +12,7 @@ const sessions_1 = require("./sessions");
|
|
|
12
12
|
// Claude Code always loads CLAUDE.md files from cwd upward plus the global
|
|
13
13
|
// ~/.claude/CLAUDE.md. If the bridge is launched from within a development
|
|
14
14
|
// repo (e.g. PresenceAI), it would pick up project CLAUDE.md instructions that
|
|
15
|
-
// direct it to write to local vault paths and call
|
|
15
|
+
// direct it to write to local vault paths and call mempalace — both wrong in
|
|
16
16
|
// bridge/Local Mode. We run Claude in a dedicated temp dir with a LOCAL MODE
|
|
17
17
|
// CLAUDE.md that explicitly overrides those behaviors.
|
|
18
18
|
const BRIDGE_CWD = (0, path_1.join)((0, os_1.tmpdir)(), '1presence-bridge');
|
|
@@ -33,11 +33,20 @@ You have NO permission to write files to this machine.
|
|
|
33
33
|
All vault reads and writes go through the \`mcp__1presence__*\` MCP tools.
|
|
34
34
|
Use those tools instead of any local file paths.
|
|
35
35
|
|
|
36
|
-
##
|
|
36
|
+
## Memory (memory map / knowledge graph / agent diary)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
via MCP, use them. If a
|
|
40
|
-
silently — do NOT
|
|
38
|
+
The user's memory is hosted in the cloud, not locally. If \`mempalace_*\` tools
|
|
39
|
+
are available via MCP, use them. If a call fails with "not initialised", skip
|
|
40
|
+
it silently — do NOT write memory files locally as a fallback.
|
|
41
|
+
|
|
42
|
+
**User-facing language.** Never say "MemPalace", "memory palace", "memory
|
|
43
|
+
graph", "ChromaDB", "vector database", "embeddings", or "drawer" to the user
|
|
44
|
+
in any context, even casually, even in progress/status updates. The internal
|
|
45
|
+
tool prefix is \`mempalace_\` but the product name does not exist to the user.
|
|
46
|
+
Use "memory map" (wings/rooms view), "knowledge graph" (facts view), "agent
|
|
47
|
+
diary" (session log), or "your memory" (general). Correct: "Indexed in your
|
|
48
|
+
memory map for semantic search." Wrong: "Indexed in MemPalace for semantic
|
|
49
|
+
search."
|
|
41
50
|
|
|
42
51
|
## Session notes / chat history
|
|
43
52
|
|
|
@@ -166,6 +175,7 @@ function spawnClaude(params) {
|
|
|
166
175
|
let usage = null;
|
|
167
176
|
let extractedModel = null;
|
|
168
177
|
let buffer = '';
|
|
178
|
+
let killedForViolation = false;
|
|
169
179
|
proc.stdout.on('data', (chunk) => {
|
|
170
180
|
buffer += chunk.toString('utf-8');
|
|
171
181
|
const lines = buffer.split('\n');
|
|
@@ -231,6 +241,19 @@ function spawnClaude(params) {
|
|
|
231
241
|
const toolName = block['name'];
|
|
232
242
|
const prefix = toolName.startsWith('mcp__') ? '[mcp]' : '[tool]';
|
|
233
243
|
process.stderr.write(`[bridge] ${prefix} ${toolName}\n`);
|
|
244
|
+
// Defense-in-depth: CLI flags (--tools "", --allowedTools, --strict-mcp-config,
|
|
245
|
+
// --setting-sources "") are supposed to make this unreachable. If we see a
|
|
246
|
+
// non-1Presence tool here anyway, something has bypassed those guards — kill
|
|
247
|
+
// immediately so any side effect already in flight is the only damage done.
|
|
248
|
+
if (!toolName.startsWith('mcp__1presence__')) {
|
|
249
|
+
killedForViolation = true;
|
|
250
|
+
const violation = `bridge tool violation: ${toolName} is not allowed in Local Mode`;
|
|
251
|
+
process.stderr.write(`[bridge] FATAL ${violation} — killing\n`);
|
|
252
|
+
active.delete(conversationId);
|
|
253
|
+
proc.kill('SIGKILL');
|
|
254
|
+
onError(violation, usage, extractedModel);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
234
257
|
}
|
|
235
258
|
else if (block['type'] === 'text') {
|
|
236
259
|
const text = block['text'];
|
|
@@ -261,6 +284,9 @@ function spawnClaude(params) {
|
|
|
261
284
|
});
|
|
262
285
|
proc.on('close', (code) => {
|
|
263
286
|
active.delete(conversationId);
|
|
287
|
+
// Violation path already called onError + killed — don't double-fire.
|
|
288
|
+
if (killedForViolation)
|
|
289
|
+
return;
|
|
264
290
|
// Flush any remaining buffer
|
|
265
291
|
if (buffer.trim()) {
|
|
266
292
|
try {
|
package/dist/index.js
CHANGED
|
@@ -290,6 +290,11 @@ async function main() {
|
|
|
290
290
|
process.on('SIGTERM', shutdown);
|
|
291
291
|
}
|
|
292
292
|
main().catch((err) => {
|
|
293
|
+
if (err instanceof auth_1.AuthCancelledError) {
|
|
294
|
+
console.error(`\n${err.message}`);
|
|
295
|
+
console.error('Run `npx @1presence/bridge` again when you are ready to sign in.');
|
|
296
|
+
process.exit(0);
|
|
297
|
+
}
|
|
293
298
|
console.error('Fatal:', err.message);
|
|
294
299
|
process.exit(1);
|
|
295
300
|
});
|