peerband 0.1.0 → 0.1.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/README.md +18 -16
- package/dist/peerband.mjs +88 -13
- package/herdr-plugin.toml +1 -1
- package/install/install.ps1 +3 -9
- package/install/install.sh +6 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,18 @@ Your MCP client can list agents, read their status and bounded recent output, an
|
|
|
17
17
|
|
|
18
18
|
## Install
|
|
19
19
|
|
|
20
|
+
Recommended (Node.js 22.13+, Herdr 0.9.3+):
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install -g peerband && peerband login
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`peerband login` opens your browser so you can approve this machine, then checks for Herdr and offers to add the PeerBand plugin to it (`Add the PeerBand plugin to Herdr now? [Y/n]`). After that, `peerband relay` opens the PeerBand Relay tab. If Herdr is not installed yet, login tells you how to finish later (install Herdr from https://herdr.dev, then `peerband herdr install` and `peerband relay`). Use `peerband login --herdr-plugin install` to add the plugin without being asked, or `--herdr-plugin skip` to leave Herdr alone.
|
|
27
|
+
|
|
28
|
+
### One-step install script (alternative)
|
|
29
|
+
|
|
30
|
+
The script checks Node, runs `npm install -g peerband`, then runs `peerband login --herdr-plugin install`.
|
|
31
|
+
|
|
20
32
|
macOS and Linux:
|
|
21
33
|
|
|
22
34
|
```sh
|
|
@@ -29,25 +41,15 @@ Windows PowerShell:
|
|
|
29
41
|
irm https://peerband.com/install.ps1 | iex
|
|
30
42
|
```
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
```sh
|
|
35
|
-
npm install -g peerband
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
The installers check Node, install the CLI, run `peerband login` (which opens your browser), and set up the Herdr plugin when Herdr is present.
|
|
39
|
-
|
|
40
|
-
Headless machine or CI with no browser? Pass a one-time grant from the PeerBand dashboard instead: `curl -fsSL https://peerband.com/install.sh | sh -s -- --grant GRANT --name "my-server"`, or on Windows `$env:PEERBAND_GRANT = 'GRANT'; irm https://peerband.com/install.ps1 | iex`.
|
|
44
|
+
### Headless machines and CI
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
No browser available? Pass a one-time grant from the PeerBand dashboard instead: `peerband login --grant GRANT` (or set `PEERBAND_GRANT`). With the scripts: `curl -fsSL https://peerband.com/install.sh | sh -s -- --grant GRANT --name "my-server"`, or on Windows `$env:PEERBAND_GRANT = 'GRANT'; irm https://peerband.com/install.ps1 | iex`.
|
|
43
47
|
|
|
44
48
|
## Quickstart
|
|
45
49
|
|
|
46
|
-
1.
|
|
47
|
-
2. `peerband
|
|
48
|
-
3. `peerband
|
|
49
|
-
4. `peerband relay` to open the PeerBand Relay tab, then press Space to connect.
|
|
50
|
-
5. Add the MCP server URL that `peerband relay` and `peerband status` print (`https://mcp.peerband.com/mcp`) to your MCP client: a custom connector in ChatGPT or Claude, or `claude mcp add --transport http peerband https://mcp.peerband.com/mcp` in Claude Code. Sign in and approve access when the client asks.
|
|
50
|
+
1. `npm install -g peerband && peerband login`. Confirm the code shown in your terminal when your browser opens, and answer Y to adding the Herdr plugin.
|
|
51
|
+
2. `peerband relay` to open the PeerBand Relay tab, then press Space to connect. (If you skipped the plugin: `peerband herdr install` first.)
|
|
52
|
+
3. Add the MCP server URL that `peerband relay` and `peerband status` print (`https://mcp.peerband.com/mcp`) to your MCP client: a custom connector in ChatGPT or Claude, or `claude mcp add --transport http peerband https://mcp.peerband.com/mcp` in Claude Code. Sign in and approve access when the client asks.
|
|
51
53
|
|
|
52
54
|
## Logging in
|
|
53
55
|
|
|
@@ -82,7 +84,7 @@ The plugin adds a persistent tab titled `PeerBand Relay [On]` or `[Off]` that sh
|
|
|
82
84
|
|
|
83
85
|
| Command | What it does |
|
|
84
86
|
| --- | --- |
|
|
85
|
-
| `peerband login` | Sign in through your browser. Flags: `--no-browser`, `--name NAME`, `--server URL`; headless/CI: `--grant GRANT` |
|
|
87
|
+
| `peerband login` | Sign in through your browser, then offer to add the Herdr plugin. Flags: `--no-browser`, `--name NAME`, `--server URL`, `--herdr-plugin ask\|install\|skip`; headless/CI: `--grant GRANT` |
|
|
86
88
|
| `peerband logout` | Stop a running relay and delete the local credential. Does not revoke it on the server |
|
|
87
89
|
| `peerband status` | Show login, relay and Herdr state. `--json` for machine-readable output |
|
|
88
90
|
| `peerband connect` | Run the connector in the foreground. Flags: `--runtime herdr\|mock`, `--enable-writes`, `--config PATH`, `--server URL` |
|
package/dist/peerband.mjs
CHANGED
|
@@ -14338,6 +14338,84 @@ function openBrowser(url, platform = process.platform) {
|
|
|
14338
14338
|
});
|
|
14339
14339
|
}
|
|
14340
14340
|
|
|
14341
|
+
// src/cli/prompt.ts
|
|
14342
|
+
var PromptAborted = class extends Error {
|
|
14343
|
+
constructor() {
|
|
14344
|
+
super("Prompt cancelled.");
|
|
14345
|
+
this.name = "PromptAborted";
|
|
14346
|
+
}
|
|
14347
|
+
};
|
|
14348
|
+
function askYesNo(stdin, stderr, prompt, defaultYes = true) {
|
|
14349
|
+
return new Promise((resolve3, reject) => {
|
|
14350
|
+
let value = "";
|
|
14351
|
+
const cleanup = () => {
|
|
14352
|
+
stdin.off("data", onData);
|
|
14353
|
+
stdin.pause();
|
|
14354
|
+
};
|
|
14355
|
+
const onData = (chunk) => {
|
|
14356
|
+
const text2 = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
14357
|
+
if (text2.includes("") || text2.includes("")) {
|
|
14358
|
+
cleanup();
|
|
14359
|
+
return reject(new PromptAborted());
|
|
14360
|
+
}
|
|
14361
|
+
const end = text2.search(/[\r\n]/);
|
|
14362
|
+
value += end === -1 ? text2 : text2.slice(0, end);
|
|
14363
|
+
if (end === -1) return;
|
|
14364
|
+
cleanup();
|
|
14365
|
+
const answer = value.trim().toLowerCase();
|
|
14366
|
+
resolve3(answer === "" ? defaultYes : answer === "y" || answer === "yes");
|
|
14367
|
+
};
|
|
14368
|
+
stderr.write(prompt);
|
|
14369
|
+
stdin.resume();
|
|
14370
|
+
stdin.on("data", onData);
|
|
14371
|
+
});
|
|
14372
|
+
}
|
|
14373
|
+
|
|
14374
|
+
// src/cli/commands/herdr-setup.ts
|
|
14375
|
+
var HERDR_PLUGIN_MODES = ["ask", "install", "skip"];
|
|
14376
|
+
async function herdrSetup(ctx, mode) {
|
|
14377
|
+
const s = ctx.out.stdout;
|
|
14378
|
+
const manual = `${s.dim("Next:")} peerband herdr install ${s.dim("then")} peerband relay`;
|
|
14379
|
+
const state = await pluginInstalled(ctx);
|
|
14380
|
+
if (!state.found) {
|
|
14381
|
+
ctx.out.print("");
|
|
14382
|
+
ctx.out.print(`${s.yellow(symbols.warn)} Herdr was not found. The PeerBand Relay tab needs Herdr 0.9.3 or newer.`);
|
|
14383
|
+
ctx.out.print(" 1. Install Herdr: https://herdr.dev");
|
|
14384
|
+
ctx.out.print(` 2. ${s.bold("peerband herdr install")} ${s.dim("then")} ${s.bold("peerband relay")}`);
|
|
14385
|
+
return;
|
|
14386
|
+
}
|
|
14387
|
+
if (state.installed) {
|
|
14388
|
+
ctx.out.print(`${s.dim("Next:")} peerband relay ${s.dim("(opens the PeerBand Relay tab in Herdr)")}`);
|
|
14389
|
+
return;
|
|
14390
|
+
}
|
|
14391
|
+
let install = mode === "install";
|
|
14392
|
+
if (mode === "ask" && ctx.stdin.isTTY && ctx.stderr.isTTY) {
|
|
14393
|
+
try {
|
|
14394
|
+
install = await askYesNo(ctx.stdin, ctx.stderr, "Add the PeerBand plugin to Herdr now? [Y/n] ");
|
|
14395
|
+
} catch (error) {
|
|
14396
|
+
if (!(error instanceof PromptAborted)) throw error;
|
|
14397
|
+
ctx.out.print(manual);
|
|
14398
|
+
return;
|
|
14399
|
+
}
|
|
14400
|
+
if (!install) {
|
|
14401
|
+
ctx.out.print(s.dim("Skipped. Add it later with `peerband herdr install`, then open the relay with `peerband relay`."));
|
|
14402
|
+
return;
|
|
14403
|
+
}
|
|
14404
|
+
}
|
|
14405
|
+
if (!install) {
|
|
14406
|
+
ctx.out.print(manual);
|
|
14407
|
+
return;
|
|
14408
|
+
}
|
|
14409
|
+
try {
|
|
14410
|
+
await installSpec.run({ values: {}, positionals: [] }, ctx);
|
|
14411
|
+
} catch (error) {
|
|
14412
|
+
const message = error.message;
|
|
14413
|
+
ctx.out.warn(`${s.yellow(symbols.warn)} Could not add the PeerBand plugin to Herdr: ${message}`);
|
|
14414
|
+
if (error instanceof CliError && error.hint) ctx.out.warn(` ${error.hint}`);
|
|
14415
|
+
ctx.out.print(s.dim("You are logged in. Add the plugin later with `peerband herdr install`, then run `peerband relay`."));
|
|
14416
|
+
}
|
|
14417
|
+
}
|
|
14418
|
+
|
|
14341
14419
|
// src/cli/commands/login.ts
|
|
14342
14420
|
async function persist(ctx, redeemed) {
|
|
14343
14421
|
const credentials = { ...redeemed, enrolledAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
@@ -14456,22 +14534,27 @@ function mapFailure(error, serverUrl) {
|
|
|
14456
14534
|
var spec3 = {
|
|
14457
14535
|
name: "login",
|
|
14458
14536
|
summary: "Connect this machine to your PeerBand account",
|
|
14459
|
-
usage: "peerband login [--name NAME] [--no-browser] [--server URL]\n peerband login --grant GRANT [--name NAME] [--server URL]",
|
|
14460
|
-
description: "Signs this machine in through your browser. login prints a link and a short code, opens the page (unless you are on SSH, a headless machine or pass --no-browser), and waits while you confirm the code in your PeerBand account. The credential is stored in your PeerBand config directory (readable only by you). Running login again replaces the existing enrollment.\n\nOn a headless machine or in CI, use a one-time grant instead: create it in the PeerBand dashboard and pass --grant GRANT (or set PEERBAND_GRANT).",
|
|
14537
|
+
usage: "peerband login [--name NAME] [--no-browser] [--server URL] [--herdr-plugin ask|install|skip]\n peerband login --grant GRANT [--name NAME] [--server URL]",
|
|
14538
|
+
description: "Signs this machine in through your browser. login prints a link and a short code, opens the page (unless you are on SSH, a headless machine or pass --no-browser), and waits while you confirm the code in your PeerBand account. The credential is stored in your PeerBand config directory (readable only by you). Running login again replaces the existing enrollment.\n\nOn a headless machine or in CI, use a one-time grant instead: create it in the PeerBand dashboard and pass --grant GRANT (or set PEERBAND_GRANT).\n\nWhen login succeeds it checks for Herdr. If the PeerBand plugin is missing it offers to add it (--herdr-plugin ask, the default; it only asks on a terminal), adds it without asking (install), or just prints the command (skip).",
|
|
14461
14539
|
options: [
|
|
14462
14540
|
{ name: "no-browser", type: "boolean", description: "Do not open a browser; print the link and code only (SSH, containers)." },
|
|
14463
14541
|
{ name: "name", type: "string", valueName: "NAME", description: "Name shown for this machine in the dashboard. Default: this computer's hostname." },
|
|
14464
14542
|
{ name: "server", type: "string", valueName: "URL", description: "PeerBand server. Default: $PEERBAND_SERVER or https://peerband.com." },
|
|
14465
|
-
{ name: "grant", type: "string", valueName: "GRANT", description: "Headless/CI: enroll with a dashboard grant instead of the browser. Default: $PEERBAND_GRANT." }
|
|
14543
|
+
{ name: "grant", type: "string", valueName: "GRANT", description: "Headless/CI: enroll with a dashboard grant instead of the browser. Default: $PEERBAND_GRANT." },
|
|
14544
|
+
{ name: "herdr-plugin", type: "string", valueName: "ask|install|skip", description: "After login, add the PeerBand plugin to Herdr: ask (default; prompts on a terminal), install, or skip." }
|
|
14466
14545
|
],
|
|
14467
14546
|
examples: [
|
|
14468
14547
|
["peerband login", "Open your browser, confirm the code, done"],
|
|
14548
|
+
["peerband login --herdr-plugin install", "Also add the PeerBand plugin to Herdr without asking (used by the install scripts)"],
|
|
14469
14549
|
["peerband login --no-browser", "Print the link and code; open the link on any other device"],
|
|
14470
14550
|
["PEERBAND_GRANT=... peerband login --name work-laptop", "Headless/CI with a dashboard grant; keeps it out of the process list"],
|
|
14471
14551
|
["peerband login --server http://localhost:8000", "Against a local development server"]
|
|
14472
14552
|
],
|
|
14473
14553
|
notes: ["The code you confirm in the browser must match the one shown here. The secret device code and any grant are never printed or stored. Plain HTTP is only accepted for localhost."],
|
|
14474
14554
|
async run(parsed, ctx) {
|
|
14555
|
+
const rawMode = str(parsed, "herdr-plugin")?.trim().toLowerCase() ?? "ask";
|
|
14556
|
+
if (!HERDR_PLUGIN_MODES.includes(rawMode)) throw new UsageError(`Invalid --herdr-plugin value "${rawMode}".`, "Use --herdr-plugin ask, install or skip.");
|
|
14557
|
+
const herdrMode = rawMode;
|
|
14475
14558
|
const serverUrl = resolveServerUrl(str(parsed, "server"), ctx.env);
|
|
14476
14559
|
const name = str(parsed, "name")?.trim() || hostname();
|
|
14477
14560
|
const grant = (str(parsed, "grant") ?? ctx.env.PEERBAND_GRANT)?.trim();
|
|
@@ -14483,7 +14566,7 @@ var spec3 = {
|
|
|
14483
14566
|
if (previous) ctx.out.print(s.dim(`Replaced the previous login (${previous.machineName ?? previous.installationId} on ${previous.serverUrl}).`));
|
|
14484
14567
|
const who = credentials.accountEmail ? ` (${credentials.accountEmail})` : "";
|
|
14485
14568
|
ctx.out.print(`${s.green(symbols.ok)} Logged in as ${s.bold(credentials.machineName ?? name)}${who}`);
|
|
14486
|
-
|
|
14569
|
+
await herdrSetup(ctx, herdrMode);
|
|
14487
14570
|
return 0;
|
|
14488
14571
|
}
|
|
14489
14572
|
};
|
|
@@ -14630,16 +14713,8 @@ function herdrGroupHelp(s) {
|
|
|
14630
14713
|
`;
|
|
14631
14714
|
}
|
|
14632
14715
|
|
|
14633
|
-
// src/cli/prompt.ts
|
|
14634
|
-
var PromptAborted = class extends Error {
|
|
14635
|
-
constructor() {
|
|
14636
|
-
super("Prompt cancelled.");
|
|
14637
|
-
this.name = "PromptAborted";
|
|
14638
|
-
}
|
|
14639
|
-
};
|
|
14640
|
-
|
|
14641
14716
|
// src/cli/cli.ts
|
|
14642
|
-
var VERSION = true ? "0.1.
|
|
14717
|
+
var VERSION = true ? "0.1.1" : "0.0.0-dev";
|
|
14643
14718
|
function createContext(overrides = {}) {
|
|
14644
14719
|
const env = overrides.env ?? process.env;
|
|
14645
14720
|
const stdout = overrides.stdout ?? process.stdout;
|
package/herdr-plugin.toml
CHANGED
package/install/install.ps1
CHANGED
|
@@ -90,7 +90,7 @@ if (-not $pbOnPath) {
|
|
|
90
90
|
Say ' ok peerband installed' Green
|
|
91
91
|
|
|
92
92
|
Say '==> Logging in' Cyan
|
|
93
|
-
$loginArgs = @('login')
|
|
93
|
+
$loginArgs = @('login', '--herdr-plugin', 'install')
|
|
94
94
|
if ($pbName) { $loginArgs += @('--name', $pbName) }
|
|
95
95
|
try {
|
|
96
96
|
if ($pbGrant) { $env:PEERBAND_GRANT = $pbGrant }
|
|
@@ -102,20 +102,14 @@ try {
|
|
|
102
102
|
}
|
|
103
103
|
if ($loginCode -ne 0) { Fail "peerband login failed. Run 'peerband login' again, or on a headless machine use 'peerband login --grant GRANT' with a grant from your PeerBand dashboard." }
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
# `peerband login --herdr-plugin install` has already added the plugin to Herdr when Herdr is present.
|
|
106
106
|
$pbHasHerdr = [bool](Get-Command herdr -ErrorAction SilentlyContinue)
|
|
107
|
-
if ($pbHasHerdr) {
|
|
108
|
-
& $pbExe herdr install
|
|
109
|
-
if ($LASTEXITCODE -ne 0) { Fail 'peerband herdr install failed. Fix the error above and run it again.' }
|
|
110
|
-
} else {
|
|
111
|
-
Say ' !! Herdr was not found. PeerBand reaches the agents you run in Herdr.' Yellow
|
|
112
|
-
}
|
|
113
107
|
|
|
114
108
|
Say ''
|
|
115
109
|
if ($pbHasHerdr) {
|
|
116
110
|
Say 'PeerBand is ready. Next:' Green
|
|
117
111
|
Say ' peerband relay open the PeerBand Relay tab in Herdr'
|
|
118
|
-
Say ' peerband status check your connection'
|
|
112
|
+
Say ' peerband status check your connection (and the Herdr plugin)'
|
|
119
113
|
} else {
|
|
120
114
|
Say 'PeerBand is installed and logged in. Next:' Green
|
|
121
115
|
Say ' 1. Install Herdr 0.9.3 or newer: https://herdr.dev'
|
package/install/install.sh
CHANGED
|
@@ -79,14 +79,14 @@ ok "peerband installed"
|
|
|
79
79
|
step "Logging in"
|
|
80
80
|
if [ -n "$grant" ]; then
|
|
81
81
|
if [ -n "$name" ]; then
|
|
82
|
-
PEERBAND_GRANT=$grant "$pb" login --name "$name" || die "peerband login failed. Get a fresh grant from your PeerBand dashboard."
|
|
82
|
+
PEERBAND_GRANT=$grant "$pb" login --herdr-plugin install --name "$name" || die "peerband login failed. Get a fresh grant from your PeerBand dashboard."
|
|
83
83
|
else
|
|
84
|
-
PEERBAND_GRANT=$grant "$pb" login || die "peerband login failed. Get a fresh grant from your PeerBand dashboard."
|
|
84
|
+
PEERBAND_GRANT=$grant "$pb" login --herdr-plugin install || die "peerband login failed. Get a fresh grant from your PeerBand dashboard."
|
|
85
85
|
fi
|
|
86
86
|
else
|
|
87
87
|
# Browser sign-in. Under `curl | sh` stdin is the script itself; use the terminal instead.
|
|
88
|
-
set --
|
|
89
|
-
[ -z "$name" ] || set -- --name "$name"
|
|
88
|
+
set -- --herdr-plugin install
|
|
89
|
+
[ -z "$name" ] || set -- "$@" --name "$name"
|
|
90
90
|
if (exec </dev/tty) 2>/dev/null; then
|
|
91
91
|
"$pb" login "$@" </dev/tty
|
|
92
92
|
else
|
|
@@ -95,10 +95,9 @@ else
|
|
|
95
95
|
fi
|
|
96
96
|
grant=''
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
# `peerband login --herdr-plugin install` has already added the plugin to Herdr when Herdr is present.
|
|
99
99
|
if command -v herdr >/dev/null 2>&1; then
|
|
100
|
-
|
|
101
|
-
printf '\n%sPeerBand is ready.%s Next:\n peerband relay open the PeerBand Relay tab in Herdr\n peerband status check your connection\n' "$G" "$N"
|
|
100
|
+
printf '\n%sPeerBand is ready.%s Next:\n peerband relay open the PeerBand Relay tab in Herdr\n peerband status check your connection (and the Herdr plugin)\n' "$G" "$N"
|
|
102
101
|
else
|
|
103
102
|
warn "Herdr was not found. PeerBand reaches the agents you run in Herdr."
|
|
104
103
|
printf '\n%sPeerBand is installed and logged in.%s Next:\n 1. Install Herdr 0.9.3 or newer: https://herdr.dev\n 2. peerband herdr install then peerband relay\n peerband status check your connection\n' "$G" "$N"
|
package/package.json
CHANGED