slashvibe-mcp 0.3.21 → 0.3.23
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 +280 -47
- package/auto-update.js +10 -15
- package/config.js +36 -31
- package/crypto.js +1 -6
- package/debug.js +12 -0
- package/discord.js +19 -19
- package/eslint.config.js +54 -0
- package/index.js +217 -207
- package/intelligence/index.js +2 -9
- package/intelligence/infer.js +10 -16
- package/intelligence/patterns.js +23 -18
- package/intelligence/proactive.js +16 -15
- package/intelligence/serendipity.js +57 -20
- package/memory.js +13 -8
- package/migrate-v2.js +72 -0
- package/notification-emitter.js +2 -2
- package/notify.js +39 -14
- package/package.json +28 -29
- package/post-install.js +141 -0
- package/presence.js +2 -2
- package/prompts.js +5 -9
- package/protocol/index.js +123 -87
- package/protocol/telegram-commands.js +36 -37
- package/store/api.js +358 -529
- package/store/local.js +9 -10
- package/store/profiles.js +48 -192
- package/store/reservations.js +2 -9
- package/store/skills.js +69 -71
- package/store/sqlite.js +355 -0
- package/test-skills-bootstrap.js +20 -0
- package/test-v2-integration.js +385 -0
- package/tools/_actions.js +48 -387
- package/tools/_connection-queue.js +45 -56
- package/tools/_discovery-enhanced.js +52 -57
- package/tools/_discovery.js +87 -185
- package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
- package/tools/{shipback.js → _experimental/shipback.js} +4 -3
- package/tools/_proactive-discovery.js +60 -73
- package/tools/_shared/index.js +41 -64
- package/tools/admin-inbox.js +10 -15
- package/tools/agents.js +1 -1
- package/tools/artifact-create.js +13 -23
- package/tools/artifact-view.js +4 -4
- package/tools/{_deprecated/back.js → back.js} +1 -1
- package/tools/bye.js +3 -5
- package/tools/consent.js +2 -2
- package/tools/context.js +9 -10
- package/tools/crossword.js +3 -2
- package/tools/discover.js +94 -356
- package/tools/dm.js +27 -86
- package/tools/doctor.js +12 -41
- package/tools/drawing.js +34 -20
- package/tools/echo.js +11 -11
- package/tools/feed.js +30 -58
- package/tools/follow.js +64 -187
- package/tools/{_deprecated/forget.js → forget.js} +4 -7
- package/tools/game.js +144 -48
- package/tools/handoff.js +6 -8
- package/tools/help.js +3 -3
- package/tools/idea.js +15 -27
- package/tools/inbox.js +121 -293
- package/tools/init.js +54 -151
- package/tools/invite.js +8 -21
- package/tools/migrate.js +27 -24
- package/tools/multiplayer-game.js +50 -40
- package/tools/{_deprecated/mute.js → mute.js} +4 -3
- package/tools/notifications.js +58 -48
- package/tools/observe.js +12 -15
- package/tools/onboarding.js +8 -11
- package/tools/open.js +13 -144
- package/tools/party-game.js +23 -12
- package/tools/patterns.js +2 -1
- package/tools/ping.js +5 -7
- package/tools/react.js +28 -30
- package/tools/{_deprecated/recall.js → recall.js} +5 -10
- package/tools/release.js +4 -2
- package/tools/{_deprecated/remember.js → remember.js} +4 -6
- package/tools/report.js +2 -2
- package/tools/request.js +6 -26
- package/tools/reserve.js +1 -1
- package/tools/session-fork.js +97 -0
- package/tools/session-save.js +109 -0
- package/tools/settings.js +30 -99
- package/tools/ship.js +74 -56
- package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
- package/tools/social-inbox.js +22 -28
- package/tools/social-post.js +24 -27
- package/tools/solo-game.js +54 -46
- package/tools/start.js +14 -148
- package/tools/status.js +21 -68
- package/tools/submit.js +4 -2
- package/tools/suggest-tags.js +36 -33
- package/tools/summarize.js +19 -16
- package/tools/tag-suggestions.js +72 -73
- package/tools/test.js +1 -1
- package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
- package/tools/token.js +4 -4
- package/tools/update.js +1 -2
- package/tools/watch.js +132 -112
- package/tools/who.js +20 -40
- package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
- package/tools/workshop-buddy.js +52 -53
- package/tools/x-mentions.js +0 -1
- package/tools/x-reply.js +0 -1
- package/twitter.js +14 -20
- package/version.json +8 -10
- package/webhook-runner.js +132 -0
- package/auth-store.js +0 -148
- package/bridges/bridge-monitor.js +0 -388
- package/bridges/discord-bot.js +0 -431
- package/bridges/farcaster.js +0 -299
- package/bridges/telegram.js +0 -261
- package/bridges/webhook-health.js +0 -420
- package/bridges/webhook-server.js +0 -437
- package/bridges/whatsapp.js +0 -441
- package/bridges/x-webhook.js +0 -423
- package/games/arcade.js +0 -406
- package/games/chess.js +0 -451
- package/games/colorguess.js +0 -343
- package/games/crossword-words.js +0 -171
- package/games/crossword.js +0 -461
- package/games/drawing.js +0 -347
- package/games/gameroulette.js +0 -300
- package/games/gamerouter.js +0 -336
- package/games/gamestatus.js +0 -337
- package/games/guessnumber.js +0 -209
- package/games/hangman.js +0 -279
- package/games/memory.js +0 -338
- package/games/multiplayer-tictactoe.js +0 -389
- package/games/pixelart.js +0 -399
- package/games/quickduel.js +0 -354
- package/games/riddle.js +0 -371
- package/games/rockpaperscissors.js +0 -291
- package/games/snake.js +0 -406
- package/games/storybuilder.js +0 -343
- package/games/tictactoe.js +0 -345
- package/games/twentyquestions.js +0 -286
- package/games/twotruths.js +0 -207
- package/games/werewolf.js +0 -508
- package/games/wordassociation.js +0 -247
- package/games/wordchain.js +0 -135
- package/intelligence/interests.js +0 -369
- package/setup.js +0 -480
- package/smart-inbox.js +0 -276
- package/tools/_deprecated/auto-suggest-connections.js +0 -304
- package/tools/_deprecated/bootstrap-skills.js +0 -231
- package/tools/_deprecated/bridge-dashboard.js +0 -342
- package/tools/_deprecated/bridge-health.js +0 -400
- package/tools/_deprecated/bridge-live.js +0 -384
- package/tools/_deprecated/bridges.js +0 -383
- package/tools/_deprecated/colorguess.js +0 -281
- package/tools/_deprecated/discover-insights.js +0 -379
- package/tools/_deprecated/discover-momentum.js +0 -256
- package/tools/_deprecated/discovery-analytics.js +0 -345
- package/tools/_deprecated/discovery-auto-suggest.js +0 -275
- package/tools/_deprecated/discovery-bootstrap.js +0 -267
- package/tools/_deprecated/discovery-daily.js +0 -375
- package/tools/_deprecated/discovery-dashboard.js +0 -385
- package/tools/_deprecated/discovery-digest.js +0 -314
- package/tools/_deprecated/discovery-hub.js +0 -357
- package/tools/_deprecated/discovery-insights.js +0 -384
- package/tools/_deprecated/discovery-momentum.js +0 -281
- package/tools/_deprecated/discovery-monitor.js +0 -319
- package/tools/_deprecated/discovery-proactive.js +0 -300
- package/tools/_deprecated/draw.js +0 -317
- package/tools/_deprecated/farcaster.js +0 -307
- package/tools/_deprecated/games-catalog.js +0 -376
- package/tools/_deprecated/games.js +0 -313
- package/tools/_deprecated/guessnumber.js +0 -194
- package/tools/_deprecated/hangman.js +0 -129
- package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
- package/tools/_deprecated/riddle.js +0 -240
- package/tools/_deprecated/run-bootstrap.js +0 -69
- package/tools/_deprecated/skills-analytics.js +0 -349
- package/tools/_deprecated/skills-bootstrap.js +0 -301
- package/tools/_deprecated/skills-dashboard.js +0 -268
- package/tools/_deprecated/skills.js +0 -380
- package/tools/_deprecated/smart-intro.js +0 -353
- package/tools/_deprecated/storybuilder.js +0 -331
- package/tools/_deprecated/telegram-bot.js +0 -183
- package/tools/_deprecated/telegram-setup.js +0 -214
- package/tools/_deprecated/twentyquestions.js +0 -143
- package/tools/_shared.js +0 -234
- package/tools/_work-context.js +0 -338
- package/tools/_work-context.manual-test.js +0 -199
- package/tools/_work-context.test.js +0 -260
- package/tools/activity.js +0 -220
- package/tools/agent-treasury.js +0 -288
- package/tools/analytics.js +0 -191
- package/tools/approve.js +0 -197
- package/tools/arcade.js +0 -173
- package/tools/artifacts-price.js +0 -107
- package/tools/ask-expert.js +0 -160
- package/tools/available.js +0 -120
- package/tools/become-expert.js +0 -150
- package/tools/broadcast.js +0 -325
- package/tools/chat.js +0 -202
- package/tools/collaborative-drawing.js +0 -286
- package/tools/connection-status.js +0 -178
- package/tools/earnings.js +0 -126
- package/tools/friends.js +0 -207
- package/tools/genesis.js +0 -233
- package/tools/gig-browse.js +0 -206
- package/tools/gig-complete.js +0 -144
- package/tools/health.js +0 -87
- package/tools/leaderboard.js +0 -117
- package/tools/lib/git-apply.js +0 -206
- package/tools/lib/git-bundle.js +0 -407
- package/tools/mint.js +0 -377
- package/tools/plan.js +0 -225
- package/tools/profile.js +0 -219
- package/tools/proof-of-work.js +0 -144
- package/tools/pulse.js +0 -218
- package/tools/reply.js +0 -166
- package/tools/reputation.js +0 -175
- package/tools/schedule.js +0 -367
- package/tools/search-messages.js +0 -123
- package/tools/session.js +0 -467
- package/tools/session_price.js +0 -128
- package/tools/smart-check.js +0 -201
- package/tools/social-processor.js +0 -445
- package/tools/streak.js +0 -147
- package/tools/stuck.js +0 -297
- package/tools/subscribe.js +0 -148
- package/tools/subscriptions.js +0 -134
- package/tools/tip.js +0 -193
- package/tools/wallet.js +0 -269
- package/tools/webhook-test.js +0 -388
- package/tools/withdraw.js +0 -145
- package/tools/work-summary.js +0 -96
- package/tools/workshop.js +0 -327
- /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
- /package/tools/{l2.js → _experimental/l2.js} +0 -0
- /package/tools/{_deprecated/away.js → away.js} +0 -0
package/tools/lib/git-bundle.js
DELETED
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Git Bundle Library
|
|
3
|
-
*
|
|
4
|
-
* Creates and validates git bundles for session sharing.
|
|
5
|
-
* Used by broadcast.js to capture code changes during a broadcast.
|
|
6
|
-
*
|
|
7
|
-
* Key functions:
|
|
8
|
-
* - captureSessionStart() - Returns current HEAD commit
|
|
9
|
-
* - createBundle(startCommit) - Creates bundle from startCommit to HEAD
|
|
10
|
-
* - validateBundle(buffer) - Validates bundle integrity
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const { execSync, spawn } = require('child_process');
|
|
14
|
-
const fs = require('fs');
|
|
15
|
-
const path = require('path');
|
|
16
|
-
const os = require('os');
|
|
17
|
-
|
|
18
|
-
// Max bundle size (10MB)
|
|
19
|
-
const MAX_BUNDLE_SIZE = 10 * 1024 * 1024;
|
|
20
|
-
|
|
21
|
-
// Files to exclude from bundles (security)
|
|
22
|
-
const EXCLUDED_PATTERNS = [
|
|
23
|
-
'.env',
|
|
24
|
-
'.env.*',
|
|
25
|
-
'*.pem',
|
|
26
|
-
'*.key',
|
|
27
|
-
'*.p12',
|
|
28
|
-
'*.pfx',
|
|
29
|
-
'.npmrc',
|
|
30
|
-
'.netrc',
|
|
31
|
-
'credentials.json',
|
|
32
|
-
'secrets.json',
|
|
33
|
-
'*_rsa',
|
|
34
|
-
'*_dsa',
|
|
35
|
-
'*_ed25519',
|
|
36
|
-
'*_ecdsa',
|
|
37
|
-
'id_rsa*',
|
|
38
|
-
'id_dsa*',
|
|
39
|
-
'*.keystore',
|
|
40
|
-
];
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Check if we're in a git repository
|
|
44
|
-
*/
|
|
45
|
-
function isGitRepo() {
|
|
46
|
-
try {
|
|
47
|
-
execSync('git rev-parse --is-inside-work-tree', {
|
|
48
|
-
stdio: 'pipe',
|
|
49
|
-
encoding: 'utf8',
|
|
50
|
-
});
|
|
51
|
-
return true;
|
|
52
|
-
} catch (e) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Get current git branch
|
|
59
|
-
*/
|
|
60
|
-
function getCurrentBranch() {
|
|
61
|
-
try {
|
|
62
|
-
return execSync('git rev-parse --abbrev-ref HEAD', {
|
|
63
|
-
stdio: 'pipe',
|
|
64
|
-
encoding: 'utf8',
|
|
65
|
-
}).trim();
|
|
66
|
-
} catch (e) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get current HEAD commit hash
|
|
73
|
-
*/
|
|
74
|
-
function getHeadCommit() {
|
|
75
|
-
try {
|
|
76
|
-
return execSync('git rev-parse HEAD', {
|
|
77
|
-
stdio: 'pipe',
|
|
78
|
-
encoding: 'utf8',
|
|
79
|
-
}).trim();
|
|
80
|
-
} catch (e) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Get commit count between two commits
|
|
87
|
-
*/
|
|
88
|
-
function getCommitCount(startCommit, endCommit = 'HEAD') {
|
|
89
|
-
try {
|
|
90
|
-
const output = execSync(`git rev-list --count ${startCommit}..${endCommit}`, {
|
|
91
|
-
stdio: 'pipe',
|
|
92
|
-
encoding: 'utf8',
|
|
93
|
-
});
|
|
94
|
-
return parseInt(output.trim(), 10);
|
|
95
|
-
} catch (e) {
|
|
96
|
-
return 0;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Get list of files changed between commits
|
|
102
|
-
*/
|
|
103
|
-
function getChangedFiles(startCommit, endCommit = 'HEAD') {
|
|
104
|
-
try {
|
|
105
|
-
const output = execSync(`git diff --name-only ${startCommit}..${endCommit}`, {
|
|
106
|
-
stdio: 'pipe',
|
|
107
|
-
encoding: 'utf8',
|
|
108
|
-
});
|
|
109
|
-
return output.trim().split('\n').filter(Boolean);
|
|
110
|
-
} catch (e) {
|
|
111
|
-
return [];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Check if any excluded files would be in the bundle
|
|
117
|
-
*/
|
|
118
|
-
function hasExcludedFiles(changedFiles) {
|
|
119
|
-
const excluded = [];
|
|
120
|
-
|
|
121
|
-
for (const file of changedFiles) {
|
|
122
|
-
const basename = path.basename(file);
|
|
123
|
-
|
|
124
|
-
for (const pattern of EXCLUDED_PATTERNS) {
|
|
125
|
-
// Simple glob matching
|
|
126
|
-
if (pattern.startsWith('*')) {
|
|
127
|
-
const suffix = pattern.slice(1);
|
|
128
|
-
if (basename.endsWith(suffix)) {
|
|
129
|
-
excluded.push(file);
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
} else if (pattern.endsWith('*')) {
|
|
133
|
-
const prefix = pattern.slice(0, -1);
|
|
134
|
-
if (basename.startsWith(prefix)) {
|
|
135
|
-
excluded.push(file);
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
} else if (pattern.includes('*')) {
|
|
139
|
-
// Pattern like ".env.*"
|
|
140
|
-
const [prefix, suffix] = pattern.split('*');
|
|
141
|
-
if (basename.startsWith(prefix) && (suffix === '' || basename.endsWith(suffix))) {
|
|
142
|
-
excluded.push(file);
|
|
143
|
-
break;
|
|
144
|
-
}
|
|
145
|
-
} else if (basename === pattern || file === pattern) {
|
|
146
|
-
excluded.push(file);
|
|
147
|
-
break;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return excluded;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Capture git state at session start
|
|
157
|
-
* @returns {object} - { success, commit, branch, error? }
|
|
158
|
-
*/
|
|
159
|
-
function captureSessionStart() {
|
|
160
|
-
if (!isGitRepo()) {
|
|
161
|
-
return { success: false, error: 'Not a git repository' };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const commit = getHeadCommit();
|
|
165
|
-
const branch = getCurrentBranch();
|
|
166
|
-
|
|
167
|
-
if (!commit) {
|
|
168
|
-
return { success: false, error: 'Could not get HEAD commit' };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
success: true,
|
|
173
|
-
commit,
|
|
174
|
-
branch,
|
|
175
|
-
capturedAt: new Date().toISOString(),
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Create a git bundle from startCommit to HEAD
|
|
181
|
-
* @param {string} startCommit - Starting commit hash
|
|
182
|
-
* @returns {object} - { success, buffer, metadata, error? }
|
|
183
|
-
*/
|
|
184
|
-
function createBundle(startCommit) {
|
|
185
|
-
if (!isGitRepo()) {
|
|
186
|
-
return { success: false, error: 'Not a git repository' };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (!startCommit) {
|
|
190
|
-
return { success: false, error: 'Start commit required' };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const endCommit = getHeadCommit();
|
|
194
|
-
const branch = getCurrentBranch();
|
|
195
|
-
|
|
196
|
-
if (!endCommit) {
|
|
197
|
-
return { success: false, error: 'Could not get HEAD commit' };
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Check if there are any new commits
|
|
201
|
-
const commitCount = getCommitCount(startCommit, endCommit);
|
|
202
|
-
if (commitCount === 0) {
|
|
203
|
-
return {
|
|
204
|
-
success: false,
|
|
205
|
-
error: 'No new commits since session start',
|
|
206
|
-
metadata: {
|
|
207
|
-
startCommit,
|
|
208
|
-
endCommit,
|
|
209
|
-
branch,
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Check for excluded files
|
|
215
|
-
const changedFiles = getChangedFiles(startCommit, endCommit);
|
|
216
|
-
const excludedFiles = hasExcludedFiles(changedFiles);
|
|
217
|
-
|
|
218
|
-
if (excludedFiles.length > 0) {
|
|
219
|
-
console.log(`[git-bundle] Warning: Excluding sensitive files: ${excludedFiles.join(', ')}`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Create temp file for bundle
|
|
223
|
-
const tmpDir = os.tmpdir();
|
|
224
|
-
const bundlePath = path.join(tmpDir, `vibe-bundle-${Date.now()}.bundle`);
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
// Create the bundle
|
|
228
|
-
// Format: git bundle create <file> <range>
|
|
229
|
-
const bundleRange = `${startCommit}..HEAD`;
|
|
230
|
-
|
|
231
|
-
execSync(`git bundle create "${bundlePath}" ${bundleRange}`, {
|
|
232
|
-
stdio: 'pipe',
|
|
233
|
-
encoding: 'utf8',
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Read the bundle
|
|
237
|
-
const buffer = fs.readFileSync(bundlePath);
|
|
238
|
-
|
|
239
|
-
// Check size
|
|
240
|
-
if (buffer.length > MAX_BUNDLE_SIZE) {
|
|
241
|
-
fs.unlinkSync(bundlePath);
|
|
242
|
-
return {
|
|
243
|
-
success: false,
|
|
244
|
-
error: `Bundle too large (${Math.round(buffer.length / 1024 / 1024)}MB > ${MAX_BUNDLE_SIZE / 1024 / 1024}MB limit)`,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Clean up temp file
|
|
249
|
-
fs.unlinkSync(bundlePath);
|
|
250
|
-
|
|
251
|
-
const metadata = {
|
|
252
|
-
initialCommit: startCommit,
|
|
253
|
-
finalCommit: endCommit,
|
|
254
|
-
branch,
|
|
255
|
-
commitCount,
|
|
256
|
-
changedFiles: changedFiles.filter((f) => !excludedFiles.includes(f)),
|
|
257
|
-
excludedFiles,
|
|
258
|
-
size: buffer.length,
|
|
259
|
-
createdAt: new Date().toISOString(),
|
|
260
|
-
};
|
|
261
|
-
|
|
262
|
-
console.log(`[git-bundle] Created bundle: ${commitCount} commits, ${changedFiles.length} files, ${buffer.length} bytes`);
|
|
263
|
-
|
|
264
|
-
return {
|
|
265
|
-
success: true,
|
|
266
|
-
buffer,
|
|
267
|
-
metadata,
|
|
268
|
-
};
|
|
269
|
-
} catch (error) {
|
|
270
|
-
// Clean up on error
|
|
271
|
-
try {
|
|
272
|
-
if (fs.existsSync(bundlePath)) {
|
|
273
|
-
fs.unlinkSync(bundlePath);
|
|
274
|
-
}
|
|
275
|
-
} catch (e) {
|
|
276
|
-
// Ignore cleanup errors
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
console.error('[git-bundle] Failed to create bundle:', error.message);
|
|
280
|
-
return { success: false, error: error.message };
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Validate a git bundle
|
|
286
|
-
* @param {Buffer} buffer - The bundle data
|
|
287
|
-
* @returns {object} - { success, info, error? }
|
|
288
|
-
*/
|
|
289
|
-
function validateBundle(buffer) {
|
|
290
|
-
if (!buffer || buffer.length === 0) {
|
|
291
|
-
return { success: false, error: 'Empty buffer' };
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// Check magic bytes (git bundles start with "# v2 git bundle" or "# v3 git bundle")
|
|
295
|
-
const header = buffer.slice(0, 20).toString('utf8');
|
|
296
|
-
if (!header.startsWith('# v2 git bundle') && !header.startsWith('# v3 git bundle')) {
|
|
297
|
-
return { success: false, error: 'Invalid bundle format' };
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// Write to temp and verify
|
|
301
|
-
const tmpDir = os.tmpdir();
|
|
302
|
-
const bundlePath = path.join(tmpDir, `vibe-verify-${Date.now()}.bundle`);
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
fs.writeFileSync(bundlePath, buffer);
|
|
306
|
-
|
|
307
|
-
// Verify the bundle
|
|
308
|
-
const output = execSync(`git bundle verify "${bundlePath}"`, {
|
|
309
|
-
stdio: 'pipe',
|
|
310
|
-
encoding: 'utf8',
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
fs.unlinkSync(bundlePath);
|
|
314
|
-
|
|
315
|
-
return {
|
|
316
|
-
success: true,
|
|
317
|
-
info: output.trim(),
|
|
318
|
-
size: buffer.length,
|
|
319
|
-
};
|
|
320
|
-
} catch (error) {
|
|
321
|
-
try {
|
|
322
|
-
if (fs.existsSync(bundlePath)) {
|
|
323
|
-
fs.unlinkSync(bundlePath);
|
|
324
|
-
}
|
|
325
|
-
} catch (e) {
|
|
326
|
-
// Ignore cleanup errors
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return { success: false, error: error.message };
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Apply a bundle to create a new branch (for forking)
|
|
335
|
-
* @param {Buffer} buffer - The bundle data
|
|
336
|
-
* @param {string} branchName - Name for the new branch
|
|
337
|
-
* @returns {object} - { success, branch, error? }
|
|
338
|
-
*/
|
|
339
|
-
function applyBundle(buffer, branchName = 'forked-session') {
|
|
340
|
-
if (!isGitRepo()) {
|
|
341
|
-
return { success: false, error: 'Not a git repository' };
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const validation = validateBundle(buffer);
|
|
345
|
-
if (!validation.success) {
|
|
346
|
-
return { success: false, error: `Invalid bundle: ${validation.error}` };
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
const tmpDir = os.tmpdir();
|
|
350
|
-
const bundlePath = path.join(tmpDir, `vibe-apply-${Date.now()}.bundle`);
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
fs.writeFileSync(bundlePath, buffer);
|
|
354
|
-
|
|
355
|
-
// Get the refs in the bundle
|
|
356
|
-
const listOutput = execSync(`git bundle list-heads "${bundlePath}"`, {
|
|
357
|
-
stdio: 'pipe',
|
|
358
|
-
encoding: 'utf8',
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
const refs = listOutput.trim().split('\n');
|
|
362
|
-
if (refs.length === 0) {
|
|
363
|
-
throw new Error('No refs in bundle');
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Get the first commit hash from the bundle
|
|
367
|
-
const firstRef = refs[0].split(/\s+/)[0];
|
|
368
|
-
|
|
369
|
-
// Unbundle (fetch from bundle)
|
|
370
|
-
execSync(`git fetch "${bundlePath}" ${firstRef}:${branchName}`, {
|
|
371
|
-
stdio: 'pipe',
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
fs.unlinkSync(bundlePath);
|
|
375
|
-
|
|
376
|
-
console.log(`[git-bundle] Applied bundle to branch: ${branchName}`);
|
|
377
|
-
|
|
378
|
-
return {
|
|
379
|
-
success: true,
|
|
380
|
-
branch: branchName,
|
|
381
|
-
refs: refs.map((r) => r.split(/\s+/)),
|
|
382
|
-
};
|
|
383
|
-
} catch (error) {
|
|
384
|
-
try {
|
|
385
|
-
if (fs.existsSync(bundlePath)) {
|
|
386
|
-
fs.unlinkSync(bundlePath);
|
|
387
|
-
}
|
|
388
|
-
} catch (e) {
|
|
389
|
-
// Ignore cleanup errors
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
console.error('[git-bundle] Failed to apply bundle:', error.message);
|
|
393
|
-
return { success: false, error: error.message };
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
module.exports = {
|
|
398
|
-
isGitRepo,
|
|
399
|
-
getCurrentBranch,
|
|
400
|
-
getHeadCommit,
|
|
401
|
-
captureSessionStart,
|
|
402
|
-
createBundle,
|
|
403
|
-
validateBundle,
|
|
404
|
-
applyBundle,
|
|
405
|
-
MAX_BUNDLE_SIZE,
|
|
406
|
-
EXCLUDED_PATTERNS,
|
|
407
|
-
};
|