permaura 1.3.26 → 1.3.28

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.
Files changed (3) hide show
  1. package/bin/cli.mjs +22 -22
  2. package/bin/lib.mjs +5 -5
  3. package/package.json +1 -1
package/bin/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // permaura — the dead-easy way to run the Permaura gateway.
2
+ // permaura: the dead-easy way to run the Permaura gateway.
3
3
  // npx -y permaura start # install-or-upgrade, run, print URL + token
4
4
  // npx -y permaura start --pair PGW-XXXX # …and connect it to your permaura.com account
5
5
  // npx -y permaura status # …or any other permaura command, against a running one
@@ -11,7 +11,7 @@
11
11
  // newer binary when one ships (skip with --no-upgrade / PERMAURA_NO_UPGRADE=1).
12
12
  //
13
13
  // This is a launcher, not a second CLI. Everything but the install/upgrade half is handed to the
14
- // binary verbatim, so there is exactly one implementation of every command — including `--pair`,
14
+ // binary verbatim, so there is exactly one implementation of every command, including `--pair`,
15
15
  // which the binary performs itself once it is up.
16
16
  import os from "node:os";
17
17
  import fs from "node:fs";
@@ -58,7 +58,7 @@ const warn = (s) => console.log(`${C.yellow("!")} ${s}`);
58
58
  /**
59
59
  * The binary's own subcommands. The launcher keeps the list so a typo costs nothing: a mistyped
60
60
  * command is rejected here, before anything downloads a binary or binds a port. It is the same list
61
- * the binary's clap definition carries, and the two drift only when a command is added — at which
61
+ * the binary's clap definition carries, and the two drift only when a command is added, at which
62
62
  * point the worst case is that the new one has to be run through the installed binary directly.
63
63
  */
64
64
  const KNOWN = new Set([
@@ -90,7 +90,7 @@ const VALUE_FLAGS = new Set(["--url", "--token"]);
90
90
  * people arrive by and wrong for the other one that installs this file: `npm i -g permaura` puts the
91
91
  * launcher on PATH, and telling someone to reach it through npx then sends them back out to the
92
92
  * registry to fetch a copy of what they are already running. It is not in the docs, but it is the
93
- * reflex for anything published on npm, and it works — so the help has to know.
93
+ * reflex for anything published on npm, and it works, so the help has to know.
94
94
  *
95
95
  * npx runs the package out of its own cache (`~/.npm/_npx/<hash>/node_modules/permaura/bin/cli.mjs`),
96
96
  * so the path this module was loaded from is the answer; nothing else needs to be probed or asked.
@@ -98,7 +98,7 @@ const VALUE_FLAGS = new Set(["--url", "--token"]);
98
98
  * reader on PATH gets a command that works, and an npx user gets one their shell will tell them
99
99
  * about immediately.
100
100
  *
101
- * The `curl | sh` route never reaches here at all — it installs the Rust binary, whose own clap help
101
+ * The `curl | sh` route never reaches here at all: it installs the Rust binary, whose own clap help
102
102
  * has said `permaura <command>` throughout.
103
103
  */
104
104
  function invocation() {
@@ -106,7 +106,7 @@ function invocation() {
106
106
  return self.includes(`${path.sep}_npx${path.sep}`) ? "npx -y permaura" : "permaura";
107
107
  }
108
108
 
109
- const usage = (me = invocation()) => `permaura — the dead-easy way to run the Permaura gateway.
109
+ const usage = (me = invocation()) => `permaura: the dead-easy way to run the Permaura gateway.
110
110
 
111
111
  Usage:
112
112
  ${me} start install-or-upgrade, run, print URL + token
@@ -116,7 +116,7 @@ Usage:
116
116
  ${me} --version print the launcher + installed-binary versions
117
117
  ${me} --help print this
118
118
 
119
- Commands (${[...KNOWN].sort().join(", ")}) are the binary's own — run
119
+ Commands (${[...KNOWN].sort().join(", ")}) are the binary's own: run
120
120
  \`${me} help <command>\` for one of them.
121
121
 
122
122
  Launcher options:
@@ -138,7 +138,7 @@ Environment:
138
138
  *
139
139
  * NO arguments prints help and starts nothing. A multi-command tool that boots a long-running server
140
140
  * when invoked bare is a surprise, and this is the first command most people type. An unrecognised
141
- * subcommand is an ERROR for the same reason it always was — `--help`, and every typo, used to
141
+ * subcommand is an ERROR for the same reason it always was: `--help`, and every typo, used to
142
142
  * silently boot a gateway and bind a port.
143
143
  *
144
144
  * Everything else is forwarded to the binary untouched (minus the launcher-only flags), so the
@@ -272,7 +272,7 @@ function sha256File(p) {
272
272
  * The release signing keys this launcher accepts (Ed25519, SPKI PEM), newest first.
273
273
  *
274
274
  * Why this matters: `asset.sha256` comes from the SAME manifest as `asset.url`. That is integrity
275
- * against a corrupted download, not authenticity — anyone who can change the manifest changes both
275
+ * against a corrupted download, not authenticity: anyone who can change the manifest changes both
276
276
  * numbers and the checksum cheerfully confirms their binary. Only a signature made by a key we pinned
277
277
  * out-of-band says "Permaura built this".
278
278
  *
@@ -280,7 +280,7 @@ function sha256File(p) {
280
280
  * gateway binary is, so whatever is pinned here sits on people's machines until they think to run
281
281
  * `npm update -g permaura`. With one key, rotating it breaks every one of those installs at once, and
282
282
  * the break is unrecoverable from the client side: the thing that would carry the new key is itself
283
- * signed with it. A set gives rotation an overlap window — see RELEASING.md, but the shape is: add
283
+ * signed with it. A set gives rotation an overlap window. See RELEASING.md, but the shape is: add
284
284
  * the next key here, ship, wait, and only then sign with it.
285
285
  *
286
286
  * MUST stay in step with the other three pin sites, or an install verifies on one surface and fails on
@@ -315,7 +315,7 @@ const REQUIRE_SIGNATURE = RELEASE_PUBKEY_PEMS.length > 0;
315
315
  * parse.
316
316
  *
317
317
  * Returns true when verified, false when no key is configured (nothing to verify against), and throws
318
- * when a key IS configured and the signature is missing or bad — that is an attack, not a hiccup.
318
+ * when a key IS configured and the signature is missing or bad: that is an attack, not a hiccup.
319
319
  */
320
320
  async function verifyManifestSignature(rawManifest, sigUrl) {
321
321
  if (!REQUIRE_SIGNATURE) return false;
@@ -344,13 +344,13 @@ async function ensureBinary({ noUpgrade, force }) {
344
344
  const key = platformKey();
345
345
  if (!key) {
346
346
  throw new Error(
347
- `unsupported platform ${process.platform}/${process.arch} — prebuilt gateways cover macOS, Linux and Windows on arm64/x64. https://permaura.com/docs`,
347
+ `unsupported platform ${process.platform}/${process.arch}: prebuilt gateways cover macOS, Linux and Windows on arm64/x64. https://permaura.com/docs`,
348
348
  );
349
349
  }
350
350
  fs.mkdirSync(path.join(DIR, "bin"), { recursive: true });
351
351
 
352
352
  // Sweep binaries parked by a previous rename-aside upgrade (D9 cleanup-on-start; no-op when no
353
- // live binary exists — a lone .old may be the only working copy after a failed swap).
353
+ // live binary exists: a lone .old may be the only working copy after a failed swap).
354
354
  sweepOldBinaries(BIN);
355
355
 
356
356
  const have = installedVersion();
@@ -368,7 +368,7 @@ async function ensureBinary({ noUpgrade, force }) {
368
368
  throw new Error(`bad manifest JSON: ${e.message}`);
369
369
  }
370
370
  } catch (e) {
371
- // A signature failure is never "the network was flaky" — it must not fall back to a cached binary
371
+ // A signature failure is never "the network was flaky": it must not fall back to a cached binary
372
372
  // and carry on as though nothing happened.
373
373
  if (REQUIRE_SIGNATURE && /signature|signed|release key/i.test(e.message)) throw e;
374
374
  if (haveBinary && !force) {
@@ -379,7 +379,7 @@ async function ensureBinary({ noUpgrade, force }) {
379
379
  }
380
380
  if (!REQUIRE_SIGNATURE) {
381
381
  warn(
382
- "This build cannot verify that the gateway binary came from Permaura — no release key is pinned yet. The download is checksummed, but a checksum from an unsigned manifest only proves the file arrived intact, not who made it.",
382
+ "This build cannot verify that the gateway binary came from Permaura: no release key is pinned yet. The download is checksummed, but a checksum from an unsigned manifest only proves the file arrived intact, not who made it.",
383
383
  );
384
384
  }
385
385
 
@@ -427,14 +427,14 @@ async function ensureBinary({ noUpgrade, force }) {
427
427
 
428
428
  fs.chmodSync(tmp, 0o755);
429
429
  // Rename-aside swap (the rustup pattern, D9): park the current binary at `.old`, move the verified
430
- // download into place, restore the parked copy if that fails — a runnable binary exists at BIN on
430
+ // download into place, restore the parked copy if that fails: a runnable binary exists at BIN on
431
431
  // every exit path. A gateway already running the old inode keeps working on every platform; the
432
432
  // sweep above collects parked files on a later run.
433
433
  swapBinaryIntoPlace(BIN, tmp);
434
434
  // Quarantine is macOS's own "you didn't make this" flag, so stripping it from an artifact we could
435
435
  // not authenticate throws away the last check standing. Once a release key is pinned this only runs
436
436
  // for a signature-verified binary; until then it must still run, because the gateway binary is not
437
- // notarized and Gatekeeper would otherwise refuse to execute it at all — removing the strip today
437
+ // notarized and Gatekeeper would otherwise refuse to execute it at all: removing the strip today
438
438
  // would simply break every macOS install. Un-gating it is part of the signing work, not separate
439
439
  // from it (see HANDBACK, § H-04).
440
440
  if (process.platform === "darwin" && (manifestVerified || !REQUIRE_SIGNATURE)) {
@@ -450,7 +450,7 @@ async function ensureBinary({ noUpgrade, force }) {
450
450
 
451
451
  /**
452
452
  * The operator bearer for this install: an explicit PERMAURA_TOKEN, else the one the gateway minted
453
- * into `operator.token` on clean bootstrap. Returns null when neither exists — a gateway initialised
453
+ * into `operator.token` on clean bootstrap. Returns null when neither exists: a gateway initialised
454
454
  * by an older build has a bearer we can't read, and inventing a shared one is exactly the hole this
455
455
  * closes. Callers degrade to manual pairing instead.
456
456
  */
@@ -488,7 +488,7 @@ async function waitHealthz(addr, tries = 20) {
488
488
  /**
489
489
  * Best-effort graceful stop: `POST /v1/shutdown` (operator-authed, loopback-only) asks the gateway to
490
490
  * drain in-flight requests and exit on its own. Resolves true on 202. Falls through to the caller's
491
- * hard kill on any failure — e.g. a clean (non-seeded) gateway where the demo token isn't valid.
491
+ * hard kill on any failure, e.g. a clean (non-seeded) gateway where the demo token isn't valid.
492
492
  */
493
493
  function postShutdown(addr, token) {
494
494
  return new Promise((resolve) => {
@@ -533,7 +533,7 @@ async function main() {
533
533
 
534
534
  if (!cmd) {
535
535
  if (forward.length) {
536
- // Arguments but no command — a mistyped flag. It must not fall through to the bare-invocation
536
+ // Arguments but no command: a mistyped flag. It must not fall through to the bare-invocation
537
537
  // help and exit 0, and it certainly must not start anything.
538
538
  console.error(`${C.red("✗")} unknown argument${forward.length > 1 ? "s" : ""}: ${forward.join(", ")}\n`);
539
539
  console.error(usage());
@@ -546,7 +546,7 @@ async function main() {
546
546
  }
547
547
 
548
548
  if (!KNOWN.has(cmd)) {
549
- // Exit before anything binds a port or downloads a binary — a mistyped command should cost
549
+ // Exit before anything binds a port or downloads a binary: a mistyped command should cost
550
550
  // nothing.
551
551
  console.error(`${C.red("✗")} unknown command: ${cmd}\n`);
552
552
  console.error(usage());
@@ -598,7 +598,7 @@ async function main() {
598
598
  const token = readOperatorToken();
599
599
  const pairing = forward.some((a) => a === "--pair" || a.startsWith("--pair="));
600
600
  if (!token) {
601
- // The gateway is up and healthy — only adding it to an account needs the bearer. Say so plainly
601
+ // The gateway is up and healthy: only adding it to an account needs the bearer. Say so plainly
602
602
  // rather than guessing at a token.
603
603
  warn(
604
604
  `This gateway was initialised by an earlier build, so its operator token isn't readable here.\n Re-pair from Console → Settings → Gateways, or re-run with PERMAURA_TOKEN=<token> set.`,
package/bin/lib.mjs CHANGED
@@ -34,7 +34,7 @@ export function assetName(key) {
34
34
  /**
35
35
  * Sweep binaries parked by a previous rename-aside upgrade (D9 cleanup-on-start). Only sweeps when
36
36
  * a live binary exists at `binPath`: after a failed swap the newest `.old` may be the only working
37
- * copy on disk, and it must survive until a later successful swap replaces it. Best-effort — on
37
+ * copy on disk, and it must survive until a later successful swap replaces it. Best-effort: on
38
38
  * Windows a still-running old gateway keeps its file locked and is collected on a later run.
39
39
  */
40
40
  export function sweepOldBinaries(binPath, fsOps = fs) {
@@ -46,7 +46,7 @@ export function sweepOldBinaries(binPath, fsOps = fs) {
46
46
  try {
47
47
  fsOps.rmSync(path.join(dir, f), { force: true });
48
48
  } catch {
49
- /* locked by a running process — leave it for next time */
49
+ /* locked by a running process, leave it for next time */
50
50
  }
51
51
  }
52
52
  }
@@ -55,7 +55,7 @@ export function sweepOldBinaries(binPath, fsOps = fs) {
55
55
  /**
56
56
  * Rename-aside swap (D9, the rustup pattern): park the current binary at `.old` (Windows can't
57
57
  * overwrite a running executable but CAN rename it), then move the verified download into place.
58
- * If that final rename fails, the parked binary is restored — there is a runnable binary at
58
+ * If that final rename fails, the parked binary is restored: there is a runnable binary at
59
59
  * `binPath` on every exit path, success or throw.
60
60
  */
61
61
  export function swapBinaryIntoPlace(binPath, tmpPath, fsOps = fs) {
@@ -80,7 +80,7 @@ export function swapBinaryIntoPlace(binPath, tmpPath, fsOps = fs) {
80
80
  try {
81
81
  fsOps.renameSync(parkedAt, binPath);
82
82
  } catch {
83
- /* restore failed — surface the original swap error below */
83
+ /* restore failed: surface the original swap error below */
84
84
  }
85
85
  }
86
86
  throw e;
@@ -91,7 +91,7 @@ export function swapBinaryIntoPlace(binPath, tmpPath, fsOps = fs) {
91
91
  * Compare versions by semver precedence. `<0` if a<b, `0` equal, `>0` if a>b.
92
92
  *
93
93
  * The pre-release suffix is part of the order, not noise to be discarded. It used to be dropped, so
94
- * `1.2.5-dev.1` compared EQUAL to the released `1.2.5` and the upgrade was never offered — a
94
+ * `1.2.5-dev.1` compared EQUAL to the released `1.2.5` and the upgrade was never offered: a
95
95
  * dev build of a version permanently masked that version's real release, on exactly the machines
96
96
  * most likely to be running one.
97
97
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "permaura",
3
- "version": "1.3.26",
3
+ "version": "1.3.28",
4
4
  "description": "Run the Permaura gateway with one command. Give your AI agents permission, not keys. `npm i -g permaura` then `permaura start --pair <code>` installs the gateway, starts it, and connects it to your permaura.com account.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",