@1presence/bridge 0.1.2
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 +141 -0
- package/dist/claude.js +102 -0
- package/dist/index.js +148 -0
- package/dist/sessions.js +32 -0
- package/package.json +26 -0
package/dist/auth.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getValidAuth = getValidAuth;
|
|
4
|
+
exports.refreshAuth = refreshAuth;
|
|
5
|
+
exports.clearAuth = clearAuth;
|
|
6
|
+
const http_1 = require("http");
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const os_1 = require("os");
|
|
9
|
+
const path_1 = require("path");
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
// ─── Paths ────────────────────────────────────────────────────────────────────
|
|
12
|
+
const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.1presence');
|
|
13
|
+
const AUTH_FILE = (0, path_1.join)(CONFIG_DIR, 'auth.json');
|
|
14
|
+
function ensureConfigDir() {
|
|
15
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
// ─── JWT helpers ──────────────────────────────────────────────────────────────
|
|
18
|
+
function parseJwt(token) {
|
|
19
|
+
try {
|
|
20
|
+
const payload = token.split('.')[1];
|
|
21
|
+
const decoded = Buffer.from(payload, 'base64url').toString('utf-8');
|
|
22
|
+
return JSON.parse(decoded);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function isTokenValid(token) {
|
|
29
|
+
const { exp } = parseJwt(token);
|
|
30
|
+
if (!exp)
|
|
31
|
+
return false;
|
|
32
|
+
// Require at least 5 minutes of validity remaining
|
|
33
|
+
return exp > Math.floor(Date.now() / 1000) + 300;
|
|
34
|
+
}
|
|
35
|
+
function uidFromToken(token) {
|
|
36
|
+
return parseJwt(token).sub ?? '';
|
|
37
|
+
}
|
|
38
|
+
function emailFromToken(token) {
|
|
39
|
+
return parseJwt(token).email;
|
|
40
|
+
}
|
|
41
|
+
// ─── Cache read/write ─────────────────────────────────────────────────────────
|
|
42
|
+
function loadCachedAuth() {
|
|
43
|
+
try {
|
|
44
|
+
const raw = (0, fs_1.readFileSync)(AUTH_FILE, 'utf-8');
|
|
45
|
+
const data = JSON.parse(raw);
|
|
46
|
+
if (!data.token || !isTokenValid(data.token))
|
|
47
|
+
return null;
|
|
48
|
+
return { token: data.token, uid: data.uid, email: data.email };
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function saveCachedAuth(auth) {
|
|
55
|
+
ensureConfigDir();
|
|
56
|
+
const data = { ...auth, savedAt: Date.now() };
|
|
57
|
+
(0, fs_1.writeFileSync)(AUTH_FILE, JSON.stringify(data, null, 2), 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
// ─── Browser auth flow ────────────────────────────────────────────────────────
|
|
60
|
+
function openBrowser(url) {
|
|
61
|
+
const platform = process.platform;
|
|
62
|
+
const cmd = platform === 'darwin' ? `open "${url}"`
|
|
63
|
+
: platform === 'win32' ? `start "" "${url}"`
|
|
64
|
+
: `xdg-open "${url}"`;
|
|
65
|
+
(0, child_process_1.exec)(cmd, (err) => {
|
|
66
|
+
if (err)
|
|
67
|
+
console.error('Could not open browser automatically. Please open this URL manually:\n' + url);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function runBrowserAuthFlow(gatewayUrl) {
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const server = (0, http_1.createServer)((req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
const url = new URL(req.url ?? '/', 'http://localhost');
|
|
75
|
+
const token = url.searchParams.get('token');
|
|
76
|
+
if (!token) {
|
|
77
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
78
|
+
res.end('Missing token');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
82
|
+
res.end(`<!DOCTYPE html>
|
|
83
|
+
<html>
|
|
84
|
+
<head><title>1Presence Bridge</title>
|
|
85
|
+
<style>
|
|
86
|
+
body { font-family: Georgia, serif; display:flex; align-items:center; justify-content:center;
|
|
87
|
+
min-height:100vh; margin:0; background:#faf8f4; color:#3a3028; }
|
|
88
|
+
.card { text-align:center; padding:40px; }
|
|
89
|
+
h1 { font-size:1.5rem; font-weight:400; margin:0 0 12px; }
|
|
90
|
+
p { color:#7a6a5a; font-size:0.9rem; }
|
|
91
|
+
</style></head>
|
|
92
|
+
<body><div class="card">
|
|
93
|
+
<h1>Bridge connected</h1>
|
|
94
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
95
|
+
</div></body></html>`);
|
|
96
|
+
server.close();
|
|
97
|
+
const uid = uidFromToken(token);
|
|
98
|
+
const email = emailFromToken(token);
|
|
99
|
+
if (!uid) {
|
|
100
|
+
reject(new Error('Invalid token — missing uid'));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
resolve({ token, uid, email });
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
reject(err);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
server.listen(0, '127.0.0.1', () => {
|
|
110
|
+
const { port } = server.address();
|
|
111
|
+
const base = gatewayUrl.replace(/^wss?:/, 'https:').replace(/\/$/, '');
|
|
112
|
+
const authUrl = `${base}/cli-auth?port=${port}`;
|
|
113
|
+
console.log('\nOpening browser for sign-in…');
|
|
114
|
+
console.log(`If the browser doesn't open, visit:\n ${authUrl}\n`);
|
|
115
|
+
openBrowser(authUrl);
|
|
116
|
+
});
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
server.close();
|
|
119
|
+
reject(new Error('Sign-in timed out after 5 minutes. Please try again.'));
|
|
120
|
+
}, 5 * 60 * 1000);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
124
|
+
async function getValidAuth(gatewayUrl) {
|
|
125
|
+
const cached = loadCachedAuth();
|
|
126
|
+
if (cached)
|
|
127
|
+
return cached;
|
|
128
|
+
console.log('Sign-in required.');
|
|
129
|
+
const auth = await runBrowserAuthFlow(gatewayUrl);
|
|
130
|
+
saveCachedAuth(auth);
|
|
131
|
+
return auth;
|
|
132
|
+
}
|
|
133
|
+
function refreshAuth(auth) {
|
|
134
|
+
saveCachedAuth(auth);
|
|
135
|
+
}
|
|
136
|
+
function clearAuth() {
|
|
137
|
+
try {
|
|
138
|
+
(0, fs_1.writeFileSync)(AUTH_FILE, '{}', 'utf-8');
|
|
139
|
+
}
|
|
140
|
+
catch { /* ignore */ }
|
|
141
|
+
}
|
package/dist/claude.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.spawnClaude = spawnClaude;
|
|
4
|
+
exports.killAll = killAll;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const sessions_1 = require("./sessions");
|
|
9
|
+
// ─── Active processes ─────────────────────────────────────────────────────────
|
|
10
|
+
const active = new Map();
|
|
11
|
+
// ─── Spawn ────────────────────────────────────────────────────────────────────
|
|
12
|
+
function spawnClaude(params) {
|
|
13
|
+
const { conversationId, presenceSessionId, text, uid, onEvent, onDone, onError } = params;
|
|
14
|
+
const systemPromptPath = (0, path_1.join)((0, os_1.tmpdir)(), `agent-${uid}.md`);
|
|
15
|
+
const mcpConfigPath = (0, path_1.join)((0, os_1.tmpdir)(), `mcp-${uid}.json`);
|
|
16
|
+
const claudeSessionId = presenceSessionId ? (0, sessions_1.getClaudeSession)(presenceSessionId) : undefined;
|
|
17
|
+
const args = [
|
|
18
|
+
'-p', text,
|
|
19
|
+
'--output-format', 'stream-json',
|
|
20
|
+
'--verbose',
|
|
21
|
+
'--allowedTools', 'mcp__1presence__*',
|
|
22
|
+
'--system-prompt', systemPromptPath,
|
|
23
|
+
'--mcp-config', mcpConfigPath,
|
|
24
|
+
];
|
|
25
|
+
if (claudeSessionId) {
|
|
26
|
+
args.push('--resume', claudeSessionId);
|
|
27
|
+
}
|
|
28
|
+
const proc = (0, child_process_1.spawn)('claude', args, {
|
|
29
|
+
env: { ...process.env },
|
|
30
|
+
});
|
|
31
|
+
active.set(conversationId, proc);
|
|
32
|
+
let sessionIdExtracted = false;
|
|
33
|
+
let messageCount = 0;
|
|
34
|
+
let buffer = '';
|
|
35
|
+
proc.stdout.on('data', (chunk) => {
|
|
36
|
+
buffer += chunk.toString('utf-8');
|
|
37
|
+
const lines = buffer.split('\n');
|
|
38
|
+
buffer = lines.pop() ?? '';
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
const trimmed = line.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
continue;
|
|
43
|
+
let event;
|
|
44
|
+
try {
|
|
45
|
+
event = JSON.parse(trimmed);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const type = event['type'];
|
|
51
|
+
// Extract claude session ID from the first system/init event
|
|
52
|
+
if (!sessionIdExtracted && type === 'system' && event['subtype'] === 'init') {
|
|
53
|
+
const sid = event['session_id'];
|
|
54
|
+
if (sid && presenceSessionId) {
|
|
55
|
+
(0, sessions_1.saveClaudeSession)(presenceSessionId, sid);
|
|
56
|
+
}
|
|
57
|
+
sessionIdExtracted = true;
|
|
58
|
+
}
|
|
59
|
+
// Count complete assistant turns
|
|
60
|
+
if (type === 'assistant')
|
|
61
|
+
messageCount++;
|
|
62
|
+
onEvent(event);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
proc.stderr.on('data', (chunk) => {
|
|
66
|
+
// claude CLI writes logs to stderr — not errors, just noise
|
|
67
|
+
const line = chunk.toString('utf-8').trim();
|
|
68
|
+
if (line)
|
|
69
|
+
process.stderr.write(`[claude] ${line}\n`);
|
|
70
|
+
});
|
|
71
|
+
proc.on('close', (code) => {
|
|
72
|
+
active.delete(conversationId);
|
|
73
|
+
// Flush any remaining buffer
|
|
74
|
+
if (buffer.trim()) {
|
|
75
|
+
try {
|
|
76
|
+
onEvent(JSON.parse(buffer.trim()));
|
|
77
|
+
}
|
|
78
|
+
catch { /* ignore */ }
|
|
79
|
+
}
|
|
80
|
+
if (code !== 0 && code !== null) {
|
|
81
|
+
onError(`claude exited with code ${code}`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
onDone(messageCount);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
proc.on('error', (err) => {
|
|
88
|
+
active.delete(conversationId);
|
|
89
|
+
if (err.code === 'ENOENT') {
|
|
90
|
+
onError('claude CLI not found. Please install Claude Code: https://claude.ai/code');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
onError(err.message);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function killAll() {
|
|
98
|
+
for (const [, proc] of active) {
|
|
99
|
+
proc.kill('SIGTERM');
|
|
100
|
+
}
|
|
101
|
+
active.clear();
|
|
102
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const ws_1 = __importDefault(require("ws"));
|
|
8
|
+
const fs_1 = require("fs");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const auth_1 = require("./auth");
|
|
12
|
+
const claude_1 = require("./claude");
|
|
13
|
+
// ─── Config ───────────────────────────────────────────────────────────────────
|
|
14
|
+
const GATEWAY_URL = process.env.BRIDGE_GATEWAY_URL ?? 'https://1presence.com';
|
|
15
|
+
const GATEWAY_WS = GATEWAY_URL.replace(/^https?:/, 'wss:').replace(/\/$/, '') + '/bridge';
|
|
16
|
+
const GATEWAY_HTTP = GATEWAY_URL.replace(/^wss?:/, 'https:').replace(/\/$/, '');
|
|
17
|
+
// ─── In-memory state ──────────────────────────────────────────────────────────
|
|
18
|
+
let currentAuth = null;
|
|
19
|
+
// ─── Vault file fetch ─────────────────────────────────────────────────────────
|
|
20
|
+
async function fetchVaultFile(path, token) {
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(`${GATEWAY_HTTP}/vault/file?path=${encodeURIComponent(path)}`, {
|
|
23
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok)
|
|
26
|
+
return null;
|
|
27
|
+
return res.text();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// ─── Setup files ──────────────────────────────────────────────────────────────
|
|
34
|
+
function tmpFile(name) {
|
|
35
|
+
return (0, path_1.join)((0, os_1.tmpdir)(), name);
|
|
36
|
+
}
|
|
37
|
+
async function writeSetupFiles(auth) {
|
|
38
|
+
const { uid, token } = auth;
|
|
39
|
+
// Fetch user's AGENT.md (fall back to empty if missing — claude will still run)
|
|
40
|
+
const agentMd = await fetchVaultFile('AGENT.md', token)
|
|
41
|
+
?? await fetchVaultFile('CLAUDE.md', token)
|
|
42
|
+
?? '';
|
|
43
|
+
(0, fs_1.writeFileSync)(tmpFile(`agent-${uid}.md`), agentMd, 'utf-8');
|
|
44
|
+
// MCP config pointing at gateway's /mcp endpoint (proxied to agent-api)
|
|
45
|
+
const mcpConfig = {
|
|
46
|
+
mcpServers: {
|
|
47
|
+
'1presence': {
|
|
48
|
+
type: 'sse',
|
|
49
|
+
url: `${GATEWAY_HTTP}/mcp`,
|
|
50
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
(0, fs_1.writeFileSync)(tmpFile(`mcp-${uid}.json`), JSON.stringify(mcpConfig, null, 2), 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
// ─── WebSocket connection ─────────────────────────────────────────────────────
|
|
57
|
+
function connect(auth, retryDelay = 1000) {
|
|
58
|
+
const ws = new ws_1.default(GATEWAY_WS, {
|
|
59
|
+
headers: { Authorization: `Bearer ${auth.token}` },
|
|
60
|
+
});
|
|
61
|
+
ws.on('open', () => {
|
|
62
|
+
console.log('✓ Bridge connected. Local Mode active on all your devices.\n');
|
|
63
|
+
});
|
|
64
|
+
ws.on('message', (raw) => {
|
|
65
|
+
let msg;
|
|
66
|
+
try {
|
|
67
|
+
msg = JSON.parse(raw.toString());
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (msg.type !== 'message' || !msg.conversationId || !msg.text)
|
|
73
|
+
return;
|
|
74
|
+
const { conversationId, text, sessionId } = msg;
|
|
75
|
+
(0, claude_1.spawnClaude)({
|
|
76
|
+
conversationId,
|
|
77
|
+
presenceSessionId: sessionId ?? null,
|
|
78
|
+
text,
|
|
79
|
+
uid: auth.uid,
|
|
80
|
+
onEvent: (event) => {
|
|
81
|
+
if (ws.readyState === ws_1.default.OPEN) {
|
|
82
|
+
ws.send(JSON.stringify({ type: 'stream', conversationId, event }));
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
onDone: (messageCount) => {
|
|
86
|
+
if (ws.readyState === ws_1.default.OPEN) {
|
|
87
|
+
ws.send(JSON.stringify({ type: 'done', conversationId, messageCount, costUsd: 0 }));
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
onError: (message) => {
|
|
91
|
+
console.error(`[bridge] conversation ${conversationId}: ${message}`);
|
|
92
|
+
if (ws.readyState === ws_1.default.OPEN) {
|
|
93
|
+
ws.send(JSON.stringify({ type: 'error', conversationId, message }));
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
ws.on('close', (code, reason) => {
|
|
99
|
+
if (code === 4001) {
|
|
100
|
+
console.error('Authentication failed — clearing cached credentials. Please restart the bridge.');
|
|
101
|
+
(0, auth_1.clearAuth)();
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
const delay = Math.min(retryDelay, 30_000);
|
|
105
|
+
console.log(`Bridge disconnected (${code}). Reconnecting in ${delay / 1000}s…`);
|
|
106
|
+
setTimeout(async () => {
|
|
107
|
+
try {
|
|
108
|
+
// Refresh setup files on reconnect in case token was refreshed
|
|
109
|
+
if (currentAuth)
|
|
110
|
+
await writeSetupFiles(currentAuth);
|
|
111
|
+
connect(currentAuth, Math.min(retryDelay * 2, 30_000));
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error('Reconnect failed:', err.message);
|
|
115
|
+
}
|
|
116
|
+
}, delay);
|
|
117
|
+
});
|
|
118
|
+
ws.on('error', (err) => {
|
|
119
|
+
// close event fires after error — reconnect handled there
|
|
120
|
+
console.error(`[bridge] ws error: ${err.message}`);
|
|
121
|
+
});
|
|
122
|
+
return ws;
|
|
123
|
+
}
|
|
124
|
+
// ─── Main ─────────────────────────────────────────────────────────────────────
|
|
125
|
+
async function main() {
|
|
126
|
+
console.log('1Presence Bridge\n');
|
|
127
|
+
// Auth
|
|
128
|
+
const auth = await (0, auth_1.getValidAuth)(GATEWAY_HTTP);
|
|
129
|
+
currentAuth = auth;
|
|
130
|
+
// Write system prompt + MCP config
|
|
131
|
+
process.stdout.write('Setting up…');
|
|
132
|
+
await writeSetupFiles(auth);
|
|
133
|
+
process.stdout.write(' done.\n');
|
|
134
|
+
// Connect
|
|
135
|
+
connect(auth);
|
|
136
|
+
// Graceful shutdown
|
|
137
|
+
const shutdown = () => {
|
|
138
|
+
console.log('\nShutting down…');
|
|
139
|
+
(0, claude_1.killAll)();
|
|
140
|
+
process.exit(0);
|
|
141
|
+
};
|
|
142
|
+
process.on('SIGINT', shutdown);
|
|
143
|
+
process.on('SIGTERM', shutdown);
|
|
144
|
+
}
|
|
145
|
+
main().catch((err) => {
|
|
146
|
+
console.error('Fatal:', err.message);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
package/dist/sessions.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getClaudeSession = getClaudeSession;
|
|
4
|
+
exports.saveClaudeSession = saveClaudeSession;
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const os_1 = require("os");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
// ─── Storage ──────────────────────────────────────────────────────────────────
|
|
9
|
+
const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), '.1presence');
|
|
10
|
+
const SESSIONS_FILE = (0, path_1.join)(CONFIG_DIR, 'sessions.json');
|
|
11
|
+
function load() {
|
|
12
|
+
try {
|
|
13
|
+
const raw = (0, fs_1.readFileSync)(SESSIONS_FILE, 'utf-8');
|
|
14
|
+
return JSON.parse(raw);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function save(map) {
|
|
21
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
22
|
+
(0, fs_1.writeFileSync)(SESSIONS_FILE, JSON.stringify(map, null, 2), 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
25
|
+
function getClaudeSession(presenceSessionId) {
|
|
26
|
+
return load()[presenceSessionId];
|
|
27
|
+
}
|
|
28
|
+
function saveClaudeSession(presenceSessionId, claudeSessionId) {
|
|
29
|
+
const map = load();
|
|
30
|
+
map[presenceSessionId] = claudeSessionId;
|
|
31
|
+
save(map);
|
|
32
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1presence/bridge",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
|
|
5
|
+
"bin": {
|
|
6
|
+
"1presence-bridge": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsx src/index.ts",
|
|
15
|
+
"start": "node dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"ws": "^8.20.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/node": "^20.0.0",
|
|
22
|
+
"@types/ws": "^8.18.1",
|
|
23
|
+
"tsx": "^4.19.0",
|
|
24
|
+
"typescript": "^5.5.0"
|
|
25
|
+
}
|
|
26
|
+
}
|