@tummycrypt/remote-juggler 2.1.0-beta.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/README.md +73 -0
- package/bin/cli.js +38 -0
- package/bin/install.js +122 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# @tummycrypt/remote-juggler
|
|
2
|
+
|
|
3
|
+
Multi-provider git identity management with MCP server support for AI agents.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### As an MCP Server (for AI agents)
|
|
8
|
+
|
|
9
|
+
Add to your MCP client configuration (Claude Code, Cursor, VS Code):
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"remote-juggler": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "@tummycrypt/remote-juggler", "--mode=mcp"]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### As a CLI Tool
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @tummycrypt/remote-juggler list
|
|
26
|
+
npx @tummycrypt/remote-juggler switch gitlab-personal
|
|
27
|
+
npx @tummycrypt/remote-juggler status
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Full Installation
|
|
31
|
+
|
|
32
|
+
For a permanent installation with shell completions and IDE integration:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
curl -fsSL https://raw.githubusercontent.com/Jesssullivan/RemoteJuggler/main/install.sh | bash
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## What It Does
|
|
39
|
+
|
|
40
|
+
RemoteJuggler manages multiple git identities across providers (GitLab, GitHub, Bitbucket). It handles:
|
|
41
|
+
|
|
42
|
+
- SSH key selection per identity
|
|
43
|
+
- GPG signing configuration
|
|
44
|
+
- Git user.name/user.email switching
|
|
45
|
+
- Credential resolution (Keychain, env vars, SSH agent)
|
|
46
|
+
- Automatic identity detection from repository remotes
|
|
47
|
+
|
|
48
|
+
## MCP Tools
|
|
49
|
+
|
|
50
|
+
When running as an MCP server, these tools are available to AI agents:
|
|
51
|
+
|
|
52
|
+
| Tool | Description |
|
|
53
|
+
|------|-------------|
|
|
54
|
+
| `juggler_list_identities` | List all configured identities |
|
|
55
|
+
| `juggler_detect_identity` | Auto-detect identity from repo remote URL |
|
|
56
|
+
| `juggler_switch` | Switch to a different identity |
|
|
57
|
+
| `juggler_status` | Get current identity and git config status |
|
|
58
|
+
| `juggler_validate` | Test SSH/API connectivity for an identity |
|
|
59
|
+
| `juggler_store_token` | Store API token in keychain |
|
|
60
|
+
| `juggler_sync_config` | Synchronize managed SSH/git config blocks |
|
|
61
|
+
|
|
62
|
+
## Supported Platforms
|
|
63
|
+
|
|
64
|
+
- Linux x86_64
|
|
65
|
+
- Linux ARM64
|
|
66
|
+
- macOS x86_64 (Intel)
|
|
67
|
+
- macOS ARM64 (Apple Silicon)
|
|
68
|
+
|
|
69
|
+
## Links
|
|
70
|
+
|
|
71
|
+
- [GitHub Repository](https://github.com/Jesssullivan/RemoteJuggler)
|
|
72
|
+
- [Full Documentation](https://github.com/Jesssullivan/RemoteJuggler/blob/main/README.md)
|
|
73
|
+
- [MCP Registry](https://modelcontextprotocol.io)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RemoteJuggler CLI wrapper
|
|
4
|
+
*
|
|
5
|
+
* Spawns the platform-native binary with all arguments and stdio inherited,
|
|
6
|
+
* forwarding the exit code. This enables the `npx @tummycrypt/remote-juggler`
|
|
7
|
+
* and `npx @tummycrypt/remote-juggler --mode=mcp` usage patterns.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { spawn } = require("child_process");
|
|
11
|
+
const { join } = require("path");
|
|
12
|
+
const { existsSync } = require("fs");
|
|
13
|
+
|
|
14
|
+
const BINARY_PATH = join(__dirname, "remote-juggler-binary");
|
|
15
|
+
|
|
16
|
+
if (!existsSync(BINARY_PATH)) {
|
|
17
|
+
console.error("RemoteJuggler binary not found. Run: npm install @tummycrypt/remote-juggler");
|
|
18
|
+
console.error("Or install directly: curl -fsSL https://raw.githubusercontent.com/Jesssullivan/RemoteJuggler/main/install.sh | bash");
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const child = spawn(BINARY_PATH, process.argv.slice(2), {
|
|
23
|
+
stdio: "inherit",
|
|
24
|
+
env: process.env,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
child.on("error", (err) => {
|
|
28
|
+
console.error(`Failed to start RemoteJuggler: ${err.message}`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
child.on("exit", (code, signal) => {
|
|
33
|
+
if (signal) {
|
|
34
|
+
process.kill(process.pid, signal);
|
|
35
|
+
} else {
|
|
36
|
+
process.exit(code || 0);
|
|
37
|
+
}
|
|
38
|
+
});
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RemoteJuggler npm postinstall script
|
|
4
|
+
*
|
|
5
|
+
* Downloads the correct platform-specific binary from GitHub Releases
|
|
6
|
+
* and places it alongside this script for the CLI wrapper to invoke.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { createWriteStream, chmodSync, existsSync } = require("fs");
|
|
10
|
+
const { join } = require("path");
|
|
11
|
+
const https = require("https");
|
|
12
|
+
const { execSync } = require("child_process");
|
|
13
|
+
|
|
14
|
+
const pkg = require("../package.json");
|
|
15
|
+
const VERSION = pkg.version;
|
|
16
|
+
const BINARY_PATH = join(__dirname, "remote-juggler-binary");
|
|
17
|
+
|
|
18
|
+
// Map Node.js platform/arch to GitHub Release asset names
|
|
19
|
+
const PLATFORM_MAP = {
|
|
20
|
+
"linux-x64": "remote-juggler-linux-amd64",
|
|
21
|
+
"linux-arm64": "remote-juggler-linux-arm64",
|
|
22
|
+
"darwin-x64": "remote-juggler-darwin-amd64",
|
|
23
|
+
"darwin-arm64": "remote-juggler-darwin-arm64",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function getPlatformKey() {
|
|
27
|
+
return `${process.platform}-${process.arch}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getDownloadUrl() {
|
|
31
|
+
const key = getPlatformKey();
|
|
32
|
+
const asset = PLATFORM_MAP[key];
|
|
33
|
+
if (!asset) {
|
|
34
|
+
if (process.platform === "win32") {
|
|
35
|
+
console.error("RemoteJuggler does not have a native Windows build.");
|
|
36
|
+
console.error("Use WSL (Windows Subsystem for Linux) instead:");
|
|
37
|
+
console.error(" wsl --install && wsl npm install -g @tummycrypt/remote-juggler");
|
|
38
|
+
console.error("");
|
|
39
|
+
console.error("Or install in WSL directly:");
|
|
40
|
+
console.error(" wsl curl -fsSL https://raw.githubusercontent.com/Jesssullivan/RemoteJuggler/main/install.sh | bash");
|
|
41
|
+
} else {
|
|
42
|
+
console.error(
|
|
43
|
+
`Unsupported platform: ${key}. Supported: ${Object.keys(PLATFORM_MAP).join(", ")}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
return `https://github.com/Jesssullivan/RemoteJuggler/releases/download/v${VERSION}/${asset}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function download(url) {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const request = https.get(url, (response) => {
|
|
54
|
+
// Handle redirects (GitHub sends 302 to S3)
|
|
55
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
56
|
+
return download(response.headers.location).then(resolve).catch(reject);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (response.statusCode !== 200) {
|
|
60
|
+
reject(new Error(`Download failed: HTTP ${response.statusCode} from ${url}`));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const file = createWriteStream(BINARY_PATH);
|
|
65
|
+
response.pipe(file);
|
|
66
|
+
file.on("finish", () => {
|
|
67
|
+
file.close();
|
|
68
|
+
chmodSync(BINARY_PATH, 0o755);
|
|
69
|
+
resolve();
|
|
70
|
+
});
|
|
71
|
+
file.on("error", (err) => {
|
|
72
|
+
reject(err);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
request.on("error", reject);
|
|
77
|
+
request.setTimeout(60000, () => {
|
|
78
|
+
request.destroy();
|
|
79
|
+
reject(new Error("Download timeout (60s)"));
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function main() {
|
|
85
|
+
// Skip download if binary already exists (e.g., local development)
|
|
86
|
+
if (existsSync(BINARY_PATH)) {
|
|
87
|
+
console.log("RemoteJuggler binary already exists, skipping download.");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const url = getDownloadUrl();
|
|
92
|
+
const key = getPlatformKey();
|
|
93
|
+
console.log(`Downloading RemoteJuggler v${VERSION} for ${key}...`);
|
|
94
|
+
console.log(` URL: ${url}`);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await download(url);
|
|
98
|
+
console.log(`RemoteJuggler v${VERSION} installed successfully.`);
|
|
99
|
+
|
|
100
|
+
// Quick sanity check
|
|
101
|
+
try {
|
|
102
|
+
const output = execSync(`"${BINARY_PATH}" --help`, {
|
|
103
|
+
timeout: 5000,
|
|
104
|
+
encoding: "utf-8",
|
|
105
|
+
});
|
|
106
|
+
if (output.includes("remote-juggler") || output.includes("RemoteJuggler")) {
|
|
107
|
+
console.log(" Binary verified OK.");
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
// Binary may not be fully compatible (e.g., missing libs) but install succeeded
|
|
111
|
+
console.log(" Binary downloaded (verification skipped).");
|
|
112
|
+
}
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(`Failed to download RemoteJuggler: ${err.message}`);
|
|
115
|
+
console.error("");
|
|
116
|
+
console.error("You can install manually:");
|
|
117
|
+
console.error(" curl -fsSL https://raw.githubusercontent.com/Jesssullivan/RemoteJuggler/main/install.sh | bash");
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tummycrypt/remote-juggler",
|
|
3
|
+
"version": "2.1.0-beta.2",
|
|
4
|
+
"description": "Multi-provider git identity management with MCP server support for AI agents",
|
|
5
|
+
"bin": {
|
|
6
|
+
"remote-juggler": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node bin/install.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/Jesssullivan/RemoteJuggler.git"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/Jesssullivan/RemoteJuggler",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"git",
|
|
19
|
+
"identity",
|
|
20
|
+
"gitlab",
|
|
21
|
+
"github",
|
|
22
|
+
"ssh",
|
|
23
|
+
"gpg",
|
|
24
|
+
"model-context-protocol"
|
|
25
|
+
],
|
|
26
|
+
"license": "Zlib",
|
|
27
|
+
"os": [
|
|
28
|
+
"linux",
|
|
29
|
+
"darwin"
|
|
30
|
+
],
|
|
31
|
+
"cpu": [
|
|
32
|
+
"x64",
|
|
33
|
+
"arm64"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
}
|
|
38
|
+
}
|