borgmcp 0.2.0-beta.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/dist/setup.js ADDED
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Borg MCP Setup Wizard
4
+ *
5
+ * Interactive setup flow:
6
+ * 1. Configure Claude Code MCP settings
7
+ * 2. Google OAuth authentication
8
+ * 3. Subscription setup (web dashboard or Stripe)
9
+ */
10
+ import prompts from 'prompts';
11
+ import chalk from 'chalk';
12
+ import open from 'open';
13
+ import which from 'which';
14
+ import { authenticateWithGoogle } from './auth.js';
15
+ import { checkSubscriptionStatus, createSubscription } from './remote-client.js';
16
+ import { addMcpServer } from './config-utils.js';
17
+ import { isAuthenticated } from './config.js';
18
+ /**
19
+ * Main setup wizard
20
+ */
21
+ async function main() {
22
+ console.log(chalk.blue.bold('\n🧠 Borg MCP Setup Wizard'));
23
+ console.log(chalk.blue('━'.repeat(40)) + '\n');
24
+ // Step 0: Check if Claude CLI exists
25
+ let claudeCliPath;
26
+ try {
27
+ claudeCliPath = which.sync('claude');
28
+ console.log(chalk.gray(`Found Claude CLI: ${claudeCliPath}\n`));
29
+ }
30
+ catch (error) {
31
+ console.error(chalk.red('āŒ Claude CLI not found\n'));
32
+ console.error(chalk.yellow('Please install Claude Code first:'));
33
+ console.error(chalk.gray(' https://claude.ai/download\n'));
34
+ process.exit(1);
35
+ }
36
+ // Step 1: MCP Configuration
37
+ console.log(chalk.blue('šŸ“¦ MCP Server Configuration'));
38
+ const { confirmConfig } = await prompts({
39
+ type: 'confirm',
40
+ name: 'confirmConfig',
41
+ message: 'Add borgmcp to Claude Code?',
42
+ initial: true
43
+ });
44
+ if (!confirmConfig) {
45
+ console.log(chalk.red('\nāŒ Setup cancelled\n'));
46
+ process.exit(0);
47
+ }
48
+ try {
49
+ addMcpServer();
50
+ console.log(chalk.green('āœ“ borgmcp added to Claude Code\n'));
51
+ }
52
+ catch (error) {
53
+ console.error(chalk.red(`\nāŒ Failed to add MCP server: ${error.message}\n`));
54
+ process.exit(1);
55
+ }
56
+ // Step 2: Authentication
57
+ console.log(chalk.blue('šŸ” Google Authentication'));
58
+ const authed = await isAuthenticated();
59
+ if (!authed) {
60
+ try {
61
+ await authenticateWithGoogle();
62
+ }
63
+ catch (error) {
64
+ console.error(chalk.red(`\nāŒ Authentication failed: ${error.message}\n`));
65
+ process.exit(1);
66
+ }
67
+ }
68
+ else {
69
+ console.log(chalk.green('āœ“ Already authenticated\n'));
70
+ }
71
+ // Step 3: Subscription
72
+ console.log(chalk.blue('šŸ’³ Subscription Check'));
73
+ let status;
74
+ try {
75
+ status = await checkSubscriptionStatus();
76
+ }
77
+ catch (error) {
78
+ console.error(chalk.red(`\nāŒ Failed to check subscription: ${error.message}\n`));
79
+ process.exit(1);
80
+ }
81
+ if (!status.hasAccess) {
82
+ console.log(chalk.yellow('⚠ No active subscription found'));
83
+ console.log(chalk.gray('šŸ’° $2/month with 7-day free trial\n'));
84
+ const { subscribeMethod } = await prompts({
85
+ type: 'select',
86
+ name: 'subscribeMethod',
87
+ message: 'How would you like to subscribe?',
88
+ choices: [
89
+ {
90
+ title: '🌐 Open web dashboard (recommended)',
91
+ value: 'web',
92
+ description: 'Full onboarding experience with features & pricing'
93
+ },
94
+ {
95
+ title: '⚔ Quick Stripe checkout',
96
+ value: 'stripe',
97
+ description: 'Fast checkout in browser'
98
+ },
99
+ {
100
+ title: 'āœ“ I already subscribed',
101
+ value: 'recheck',
102
+ description: 'Check subscription status again'
103
+ },
104
+ {
105
+ title: 'āŒ Skip for now',
106
+ value: 'skip',
107
+ description: 'Tools will not work until you subscribe'
108
+ }
109
+ ]
110
+ });
111
+ switch (subscribeMethod) {
112
+ case 'web':
113
+ console.log(chalk.blue('\n🌐 Opening: https://borgmcp.ai/subscribe'));
114
+ try {
115
+ await open('https://borgmcp.ai/subscribe');
116
+ console.log(chalk.gray('ā³ Waiting for subscription (checking every 5s for 2 min)...\n'));
117
+ await pollForSubscription();
118
+ }
119
+ catch (error) {
120
+ console.error(chalk.yellow(`\n⚠ ${error.message}`));
121
+ }
122
+ break;
123
+ case 'stripe':
124
+ try {
125
+ const checkoutUrl = await createSubscription();
126
+ console.log(chalk.blue(`\n⚔ Opening Stripe: ${checkoutUrl}`));
127
+ await open(checkoutUrl);
128
+ console.log(chalk.gray('ā³ Waiting for subscription...\n'));
129
+ await pollForSubscription();
130
+ }
131
+ catch (error) {
132
+ console.error(chalk.red(`\nāŒ Failed to create checkout: ${error.message}\n`));
133
+ }
134
+ break;
135
+ case 'recheck':
136
+ try {
137
+ const recheckStatus = await checkSubscriptionStatus();
138
+ if (recheckStatus.hasAccess) {
139
+ console.log(chalk.green('\nāœ“ Subscription found!\n'));
140
+ }
141
+ else {
142
+ console.log(chalk.yellow('\n⚠ No subscription found\n'));
143
+ }
144
+ }
145
+ catch (error) {
146
+ console.error(chalk.red(`\nāŒ Failed to recheck: ${error.message}\n`));
147
+ }
148
+ break;
149
+ case 'skip':
150
+ console.log(chalk.yellow('\n⚠ Skipped subscription - tools will not work until you subscribe\n'));
151
+ break;
152
+ }
153
+ }
154
+ else {
155
+ console.log(chalk.green('āœ“ Active subscription found'));
156
+ if (status.expiresAt) {
157
+ const expiresAt = new Date(status.expiresAt);
158
+ console.log(chalk.gray(` Expires: ${expiresAt.toLocaleDateString()}\n`));
159
+ }
160
+ else {
161
+ console.log('');
162
+ }
163
+ }
164
+ // Success message
165
+ console.log(chalk.green.bold('šŸŽ‰ Setup complete!\n'));
166
+ console.log(chalk.gray('Next steps:'));
167
+ console.log(chalk.gray('1. Use borg:regen tool in Claude Code'));
168
+ console.log(chalk.gray('2. Manage context at: https://borgmcp.ai/dashboard\n'));
169
+ }
170
+ /**
171
+ * Poll for subscription activation
172
+ * Checks every 5 seconds for 2 minutes (24 attempts)
173
+ */
174
+ async function pollForSubscription() {
175
+ const maxAttempts = 24;
176
+ for (let i = 0; i < maxAttempts; i++) {
177
+ await new Promise(resolve => setTimeout(resolve, 5000));
178
+ try {
179
+ const status = await checkSubscriptionStatus();
180
+ if (status.hasAccess) {
181
+ console.log(chalk.green('āœ“ Subscription activated!\n'));
182
+ return;
183
+ }
184
+ }
185
+ catch (error) {
186
+ // Continue polling even on errors
187
+ }
188
+ }
189
+ throw new Error('Timeout - Run setup again after subscribing');
190
+ }
191
+ // Run wizard
192
+ main().catch((error) => {
193
+ console.error(chalk.red(`\nāŒ Setup failed: ${error.message}\n`));
194
+ process.exit(1);
195
+ });
196
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
package/dist/sync.d.ts ADDED
@@ -0,0 +1,57 @@
1
+ /**
2
+ * File sync logic with conflict detection
3
+ *
4
+ * Addresses consensus finding: Last-write-wins causes silent data loss
5
+ * Solution: Track both local and remote timestamps, detect conflicts explicitly
6
+ */
7
+ import type { FileMetadata, ConflictInfo } from './types.js';
8
+ /**
9
+ * Calculate SHA-256 hash of file content
10
+ */
11
+ export declare function hashContent(content: string): string;
12
+ /**
13
+ * Load sync metadata from disk
14
+ */
15
+ export declare function loadMetadata(): Promise<FileMetadata | null>;
16
+ /**
17
+ * Save sync metadata to disk
18
+ */
19
+ export declare function saveMetadata(metadata: FileMetadata): Promise<void>;
20
+ /**
21
+ * Read local CLAUDE.md file
22
+ */
23
+ export declare function readLocalFile(): Promise<string | null>;
24
+ /**
25
+ * Write content to local CLAUDE.md file
26
+ */
27
+ export declare function writeLocalFile(content: string): Promise<void>;
28
+ /**
29
+ * Get local file modification time
30
+ */
31
+ export declare function getLocalMtime(): Promise<number | null>;
32
+ /**
33
+ * Detect if there's a sync conflict
34
+ *
35
+ * Conflict occurs when:
36
+ * 1. Both local and remote have changed since last sync
37
+ * 2. Changes are different (different content hashes)
38
+ */
39
+ export declare function detectConflict(localContent: string, remoteContent: string, metadata: FileMetadata | null): Promise<ConflictInfo | null>;
40
+ /**
41
+ * Handle sync conflict by creating a conflict file
42
+ *
43
+ * Strategy: Create CLAUDE.md.conflict with remote content
44
+ * Keep local file unchanged, let user resolve manually
45
+ */
46
+ export declare function handleConflict(conflict: ConflictInfo): Promise<void>;
47
+ /**
48
+ * Determine sync action based on file states
49
+ *
50
+ * Returns: 'push' | 'pull' | 'conflict' | 'skip'
51
+ */
52
+ export declare function determineSyncAction(localContent: string | null, remoteContent: string | null, metadata: FileMetadata | null): Promise<'push' | 'pull' | 'conflict' | 'skip'>;
53
+ /**
54
+ * Update metadata after successful sync
55
+ */
56
+ export declare function updateMetadataAfterSync(content: string): Promise<void>;
57
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK7D;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAUD;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAUjE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS5D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAInE;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAU5D;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,YAAY,GAAG,IAAI,GAC5B,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAgC9B;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAc1E;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,QAAQ,EAAE,YAAY,GAAG,IAAI,GAC5B,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,CAkDhD;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5E"}
package/dist/sync.js ADDED
@@ -0,0 +1,196 @@
1
+ /**
2
+ * File sync logic with conflict detection
3
+ *
4
+ * Addresses consensus finding: Last-write-wins causes silent data loss
5
+ * Solution: Track both local and remote timestamps, detect conflicts explicitly
6
+ */
7
+ import * as crypto from 'crypto';
8
+ import * as fs from 'fs/promises';
9
+ import * as path from 'path';
10
+ import { homedir } from 'os';
11
+ const METADATA_FILE = path.join(homedir(), '.borg-mcp', 'sync-metadata.json');
12
+ const CLAUDE_MD_PATH = path.join(homedir(), '.claude', 'CLAUDE.md');
13
+ /**
14
+ * Calculate SHA-256 hash of file content
15
+ */
16
+ export function hashContent(content) {
17
+ return crypto.createHash('sha256').update(content, 'utf8').digest('hex');
18
+ }
19
+ /**
20
+ * Ensure metadata directory exists
21
+ */
22
+ async function ensureMetadataDir() {
23
+ const dir = path.dirname(METADATA_FILE);
24
+ await fs.mkdir(dir, { recursive: true });
25
+ }
26
+ /**
27
+ * Load sync metadata from disk
28
+ */
29
+ export async function loadMetadata() {
30
+ try {
31
+ const data = await fs.readFile(METADATA_FILE, 'utf8');
32
+ return JSON.parse(data);
33
+ }
34
+ catch (error) {
35
+ if (error.code === 'ENOENT') {
36
+ return null; // File doesn't exist yet
37
+ }
38
+ throw error;
39
+ }
40
+ }
41
+ /**
42
+ * Save sync metadata to disk
43
+ */
44
+ export async function saveMetadata(metadata) {
45
+ await ensureMetadataDir();
46
+ await fs.writeFile(METADATA_FILE, JSON.stringify(metadata, null, 2), 'utf8');
47
+ }
48
+ /**
49
+ * Read local CLAUDE.md file
50
+ */
51
+ export async function readLocalFile() {
52
+ try {
53
+ return await fs.readFile(CLAUDE_MD_PATH, 'utf8');
54
+ }
55
+ catch (error) {
56
+ if (error.code === 'ENOENT') {
57
+ return null; // File doesn't exist
58
+ }
59
+ throw error;
60
+ }
61
+ }
62
+ /**
63
+ * Write content to local CLAUDE.md file
64
+ */
65
+ export async function writeLocalFile(content) {
66
+ const dir = path.dirname(CLAUDE_MD_PATH);
67
+ await fs.mkdir(dir, { recursive: true });
68
+ await fs.writeFile(CLAUDE_MD_PATH, content, 'utf8');
69
+ }
70
+ /**
71
+ * Get local file modification time
72
+ */
73
+ export async function getLocalMtime() {
74
+ try {
75
+ const stats = await fs.stat(CLAUDE_MD_PATH);
76
+ return stats.mtimeMs;
77
+ }
78
+ catch (error) {
79
+ if (error.code === 'ENOENT') {
80
+ return null;
81
+ }
82
+ throw error;
83
+ }
84
+ }
85
+ /**
86
+ * Detect if there's a sync conflict
87
+ *
88
+ * Conflict occurs when:
89
+ * 1. Both local and remote have changed since last sync
90
+ * 2. Changes are different (different content hashes)
91
+ */
92
+ export async function detectConflict(localContent, remoteContent, metadata) {
93
+ // No conflict if no metadata (first sync)
94
+ if (!metadata) {
95
+ return null;
96
+ }
97
+ const localHash = hashContent(localContent);
98
+ const remoteHash = hashContent(remoteContent);
99
+ // No conflict if content is identical
100
+ if (localHash === remoteHash) {
101
+ return null;
102
+ }
103
+ // Check if both have changed since last sync
104
+ const localChanged = localHash !== metadata.lastSyncHash;
105
+ const remoteChanged = remoteHash !== metadata.lastSyncHash;
106
+ if (localChanged && remoteChanged) {
107
+ // CONFLICT: Both local and remote changed since last sync
108
+ const localMtime = await getLocalMtime();
109
+ return {
110
+ localContent,
111
+ remoteContent,
112
+ localMtime: localMtime || Date.now(),
113
+ remoteMtime: Date.now(), // Remote doesn't track mtime, use current time
114
+ };
115
+ }
116
+ // No conflict - only one side changed
117
+ return null;
118
+ }
119
+ /**
120
+ * Handle sync conflict by creating a conflict file
121
+ *
122
+ * Strategy: Create CLAUDE.md.conflict with remote content
123
+ * Keep local file unchanged, let user resolve manually
124
+ */
125
+ export async function handleConflict(conflict) {
126
+ const conflictPath = `${CLAUDE_MD_PATH}.conflict`;
127
+ // Write remote content to conflict file
128
+ await fs.writeFile(conflictPath, conflict.remoteContent, 'utf8');
129
+ // Log conflict to stderr for user visibility
130
+ console.error('\nāš ļø SYNC CONFLICT DETECTED');
131
+ console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
132
+ console.error('Both local and remote CLAUDE.md have been modified.');
133
+ console.error(`Local file: ${CLAUDE_MD_PATH}`);
134
+ console.error(`Remote backup: ${conflictPath}\n`);
135
+ console.error('Please resolve manually by choosing one version or merging them.');
136
+ console.error('Delete the .conflict file once resolved.\n');
137
+ }
138
+ /**
139
+ * Determine sync action based on file states
140
+ *
141
+ * Returns: 'push' | 'pull' | 'conflict' | 'skip'
142
+ */
143
+ export async function determineSyncAction(localContent, remoteContent, metadata) {
144
+ // Case 1: Neither exists - skip
145
+ if (!localContent && !remoteContent) {
146
+ return 'skip';
147
+ }
148
+ // Case 2: Only remote exists - pull
149
+ if (!localContent && remoteContent) {
150
+ return 'pull';
151
+ }
152
+ // Case 3: Only local exists - push
153
+ if (localContent && !remoteContent) {
154
+ return 'push';
155
+ }
156
+ // Case 4: Both exist - check for conflicts
157
+ if (localContent && remoteContent) {
158
+ const conflict = await detectConflict(localContent, remoteContent, metadata);
159
+ if (conflict) {
160
+ return 'conflict';
161
+ }
162
+ // No conflict - determine direction based on content hash
163
+ const localHash = hashContent(localContent);
164
+ const remoteHash = hashContent(remoteContent);
165
+ if (localHash === remoteHash) {
166
+ return 'skip'; // Identical content
167
+ }
168
+ // One side changed - sync in that direction
169
+ if (metadata) {
170
+ const localChanged = localHash !== metadata.lastSyncHash;
171
+ const remoteChanged = remoteHash !== metadata.lastSyncHash;
172
+ if (localChanged) {
173
+ return 'push';
174
+ }
175
+ if (remoteChanged) {
176
+ return 'pull';
177
+ }
178
+ }
179
+ // No metadata - default to push (local is source of truth for first sync)
180
+ return 'push';
181
+ }
182
+ return 'skip';
183
+ }
184
+ /**
185
+ * Update metadata after successful sync
186
+ */
187
+ export async function updateMetadataAfterSync(content) {
188
+ const metadata = {
189
+ localMtime: await getLocalMtime() || Date.now(),
190
+ remoteMtime: Date.now(),
191
+ lastSyncHash: hashContent(content),
192
+ lastSyncTime: Date.now(),
193
+ };
194
+ await saveMetadata(metadata);
195
+ }
196
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Type definitions for Borg MCP Client
3
+ */
4
+ export interface FileMetadata {
5
+ localMtime: number;
6
+ remoteMtime: number;
7
+ lastSyncHash: string;
8
+ lastSyncTime: number;
9
+ }
10
+ export interface SyncState {
11
+ inProgress: boolean;
12
+ lastSync: number;
13
+ pendingChanges: PendingChange[];
14
+ }
15
+ export interface PendingChange {
16
+ operation: 'set' | 'delete';
17
+ content?: string;
18
+ timestamp: number;
19
+ retryCount: number;
20
+ }
21
+ export interface GoogleOAuthTokens {
22
+ id_token: string;
23
+ refresh_token?: string;
24
+ expires_at: number;
25
+ }
26
+ export interface RemoteResponse {
27
+ success: boolean;
28
+ data?: any;
29
+ error?: string;
30
+ }
31
+ export interface ConflictInfo {
32
+ localContent: string;
33
+ remoteContent: string;
34
+ localMtime: number;
35
+ remoteMtime: number;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,aAAa,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type definitions for Borg MCP Client
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "borgmcp",
3
+ "version": "0.2.0-beta.1",
4
+ "description": "Centralized context storage for Claude - install once, sync everywhere",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "borgmcp": "dist/index.js",
9
+ "borgmcp-setup": "dist/setup.js"
10
+ },
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsc --watch",
14
+ "start": "node dist/index.js",
15
+ "postinstall": "node dist/postinstall.js || true",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "keywords": [
24
+ "mcp",
25
+ "claude",
26
+ "ai",
27
+ "context",
28
+ "sync",
29
+ "anthropic",
30
+ "claude-code",
31
+ "borg"
32
+ ],
33
+ "author": "Theodor Storm <theodor@byteventures.se>",
34
+ "license": "Apache-2.0",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/theodorstorm/borg-mcp",
38
+ "directory": "client"
39
+ },
40
+ "homepage": "https://borgmcp.ai",
41
+ "bugs": {
42
+ "url": "https://github.com/theodorstorm/borg-mcp/issues"
43
+ },
44
+ "dependencies": {
45
+ "@modelcontextprotocol/sdk": "^1.0.4",
46
+ "chalk": "^5.3.0",
47
+ "keytar": "^7.9.0",
48
+ "open": "^10.0.0",
49
+ "prompts": "^2.4.2",
50
+ "which": "^4.0.0",
51
+ "zod": "^3.24.1"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^22.10.2",
55
+ "@types/prompts": "^2.4.9",
56
+ "@types/which": "^3.0.4",
57
+ "typescript": "^5.7.2"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ }
62
+ }