Add deploy-cli.sh: ship the CLI as a single bundled file, no git clone needed
The CLI only touches Node builtins and libsodium-wrappers (no native addons like better-sqlite3, which the server needs but the CLI never imports) -- confirmed by checking its actual import graph, not assumed. That makes it a good candidate for a single-file esbuild bundle rather than requiring a full git checkout + npm install on every machine that needs to run `keep pull`. deploy-cli.sh bundles src/cli (~18kb) and ships it straight to a host over SSH -- HOST=user@vps ./deploy-cli.sh -- mirroring flit's deploy-daemon.sh ssh-cat-chmod pattern rather than inventing a new convention. No git, no npm install, no node_modules on the target at all, just the one file plus a `node` runtime already there from whatever else is deployed on that box. Caught a real bug while building this: --banner:js="#!/usr/bin/env node" duplicated the shebang esbuild already preserves from the source file automatically, landing it on line 2 instead of line 1 -- Node only special-cases a shebang on line 1, so the bundle threw a syntax error on every invocation until the redundant banner flag was removed. Verified the bundle for real, not just that it builds: ran `keep identity init` / `identity show` against it directly and confirmed a real Ed25519 keypair comes out the other end -- the specific thing worth checking given libsodium-wrappers needed a createRequire workaround for its own broken ESM packaging, and bundling could easily have broken that differently. Also documents both CLI-provisioning paths in INTEGRATION.md (scripts/install-cli.sh for a machine you're fine cloning onto, deploy-cli.sh for one you'd rather not) as a "getting keep onto a machine" prerequisite section, ahead of the existing deploy-pattern docs that all assume it's already there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
|
dist-bundle/
|
||||||
.env
|
.env
|
||||||
data/
|
data/
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,42 @@ A deploy identity should almost always be granted **read-only** access
|
|||||||
needs to `pull`, and a read-only grant means a compromised deploy box
|
needs to `pull`, and a read-only grant means a compromised deploy box
|
||||||
can't also rotate the vault or add itself more recipients.
|
can't also rotate the vault or add itself more recipients.
|
||||||
|
|
||||||
|
## Getting the `keep` CLI onto a machine
|
||||||
|
|
||||||
|
Chicken-and-egg: every pattern below assumes `keep` is already a runnable
|
||||||
|
command on the machine doing the pulling. Two ways to get there, pick
|
||||||
|
based on whether you're fine with a git checkout existing on that
|
||||||
|
machine:
|
||||||
|
|
||||||
|
**A machine you're already developing on, or don't mind cloning onto**
|
||||||
|
(your laptop, a VPS you administer directly):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <this repo>
|
||||||
|
cd keep
|
||||||
|
npm install
|
||||||
|
./scripts/install-cli.sh # builds, symlinks dist/cli/index.js onto PATH as `keep`
|
||||||
|
```
|
||||||
|
|
||||||
|
Symlinked rather than copied — a future `git pull && npm run build` is
|
||||||
|
the entire upgrade story, no need to re-run the install script.
|
||||||
|
|
||||||
|
**A deploy target you'd rather not clone a git repo onto** — bundle the
|
||||||
|
CLI into a single portable file and ship just that, over SSH, the same
|
||||||
|
way flit/waste-go's `deploy-*.sh` scripts ship a compiled binary:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
HOST=user@your-vps ./deploy-cli.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This bundles `src/cli` (esbuild, single file, ~18kb — the CLI only
|
||||||
|
touches Node builtins and libsodium-wrappers, no native addons, so it's
|
||||||
|
fully portable) and `cat`s it straight to `~/bin/keep` on the target over
|
||||||
|
SSH — no git, no npm install, no node_modules on that machine at all,
|
||||||
|
just a `node` runtime (already there, if it's running any of the other
|
||||||
|
Node-based projects in this family) and the one file. Re-run it any time
|
||||||
|
the CLI changes; it's a single file, safe to overwrite.
|
||||||
|
|
||||||
## Pattern: several docker-compose projects on one or more VPSes
|
## Pattern: several docker-compose projects on one or more VPSes
|
||||||
|
|
||||||
The common shape once more than one or two projects are on `keep`:
|
The common shape once more than one or two projects are on `keep`:
|
||||||
|
|||||||
23
deploy-cli.sh
Executable file
23
deploy-cli.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# deploy-cli.sh — bundle the keep CLI into a single portable file and ship
|
||||||
|
# it straight to a host over SSH. No git clone, no npm install on the
|
||||||
|
# target — the bundle only touches Node builtins and libsodium-wrappers
|
||||||
|
# (pure JS/WASM, no native compilation), so the file itself is the whole
|
||||||
|
# artifact. Mirrors flit/deploy-daemon.sh's ssh-cat-chmod pattern.
|
||||||
|
#
|
||||||
|
# Usage: HOST=user@host ./deploy-cli.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
HOST="${HOST:?usage: HOST=user@host ./deploy-cli.sh}"
|
||||||
|
BIN_DIR="${BIN_DIR:-~/bin}"
|
||||||
|
|
||||||
|
echo "→ bundling keep CLI…"
|
||||||
|
npm run build:cli-bundle
|
||||||
|
|
||||||
|
echo "→ uploading to $HOST:$BIN_DIR/keep…"
|
||||||
|
ssh "$HOST" "mkdir -p $BIN_DIR && cat > $BIN_DIR/keep && chmod +x $BIN_DIR/keep" < dist-bundle/keep
|
||||||
|
|
||||||
|
echo "→ verifying…"
|
||||||
|
ssh "$HOST" "$BIN_DIR/keep --help" | head -1
|
||||||
|
|
||||||
|
echo "✓ done — re-run this script any time the CLI changes; it's one file, safe to overwrite."
|
||||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -21,6 +21,7 @@
|
|||||||
"@types/express": "^4.17.21",
|
"@types/express": "^4.17.21",
|
||||||
"@types/libsodium-wrappers": "^0.7.14",
|
"@types/libsodium-wrappers": "^0.7.14",
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
|
"esbuild": "^0.28.1",
|
||||||
"tsx": "^4.15.0",
|
"tsx": "^4.15.0",
|
||||||
"typescript": "^5.5.0"
|
"typescript": "^5.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,18 +10,20 @@
|
|||||||
"dev:server": "tsx watch --env-file=.env src/server/index.ts",
|
"dev:server": "tsx watch --env-file=.env src/server/index.ts",
|
||||||
"cli": "tsx src/cli/index.ts",
|
"cli": "tsx src/cli/index.ts",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
|
"build:cli-bundle": "esbuild src/cli/index.ts --bundle --platform=node --format=esm --outfile=dist-bundle/keep --external:node:*",
|
||||||
"start": "node --env-file=.env dist/server/index.js"
|
"start": "node --env-file=.env dist/server/index.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.19.2",
|
|
||||||
"better-sqlite3": "^11.3.0",
|
"better-sqlite3": "^11.3.0",
|
||||||
|
"express": "^4.19.2",
|
||||||
"libsodium-wrappers": "^0.7.15"
|
"libsodium-wrappers": "^0.7.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^4.17.21",
|
|
||||||
"@types/node": "^22.0.0",
|
|
||||||
"@types/better-sqlite3": "^7.6.11",
|
"@types/better-sqlite3": "^7.6.11",
|
||||||
|
"@types/express": "^4.17.21",
|
||||||
"@types/libsodium-wrappers": "^0.7.14",
|
"@types/libsodium-wrappers": "^0.7.14",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"esbuild": "^0.28.1",
|
||||||
"tsx": "^4.15.0",
|
"tsx": "^4.15.0",
|
||||||
"typescript": "^5.5.0"
|
"typescript": "^5.5.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user