@lightninglabs/lightning-mcp-server 0.2.0

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 (68) hide show
  1. package/.claude-plugin/marketplace.json +36 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/README.md +307 -0
  4. package/bin/lightning-mcp-server +15 -0
  5. package/docs/architecture.md +455 -0
  6. package/docs/commerce.md +357 -0
  7. package/docs/l402-and-lnget.md +267 -0
  8. package/docs/mcp-server.md +285 -0
  9. package/docs/quickref.md +263 -0
  10. package/docs/security.md +298 -0
  11. package/docs/two-agent-setup.md +394 -0
  12. package/package.json +52 -0
  13. package/postinstall.js +160 -0
  14. package/skills/aperture/SKILL.md +330 -0
  15. package/skills/aperture/scripts/install.sh +68 -0
  16. package/skills/aperture/scripts/setup.sh +155 -0
  17. package/skills/aperture/scripts/start.sh +81 -0
  18. package/skills/aperture/scripts/stop.sh +57 -0
  19. package/skills/aperture/templates/aperture-regtest.yaml +36 -0
  20. package/skills/aperture/templates/aperture.yaml.template +64 -0
  21. package/skills/aperture/templates/docker-compose-aperture.yml +59 -0
  22. package/skills/commerce/SKILL.md +211 -0
  23. package/skills/lib/config-gen.sh +127 -0
  24. package/skills/lib/rest.sh +69 -0
  25. package/skills/lightning-security-module/SKILL.md +253 -0
  26. package/skills/lightning-security-module/references/architecture.md +133 -0
  27. package/skills/lightning-security-module/scripts/docker-start.sh +117 -0
  28. package/skills/lightning-security-module/scripts/docker-stop.sh +53 -0
  29. package/skills/lightning-security-module/scripts/export-credentials.sh +268 -0
  30. package/skills/lightning-security-module/scripts/install.sh +178 -0
  31. package/skills/lightning-security-module/scripts/setup-signer.sh +307 -0
  32. package/skills/lightning-security-module/scripts/start-signer.sh +152 -0
  33. package/skills/lightning-security-module/scripts/stop-signer.sh +240 -0
  34. package/skills/lightning-security-module/templates/docker-compose-signer.yml +35 -0
  35. package/skills/lightning-security-module/templates/signer-lnd.conf.template +69 -0
  36. package/skills/lnd/SKILL.md +441 -0
  37. package/skills/lnd/profiles/debug.env +4 -0
  38. package/skills/lnd/profiles/default.env +3 -0
  39. package/skills/lnd/profiles/regtest.env +4 -0
  40. package/skills/lnd/profiles/taproot.env +3 -0
  41. package/skills/lnd/profiles/wumbo.env +3 -0
  42. package/skills/lnd/references/security.md +156 -0
  43. package/skills/lnd/scripts/create-wallet.sh +464 -0
  44. package/skills/lnd/scripts/docker-start.sh +256 -0
  45. package/skills/lnd/scripts/docker-stop.sh +109 -0
  46. package/skills/lnd/scripts/import-credentials.sh +145 -0
  47. package/skills/lnd/scripts/install.sh +195 -0
  48. package/skills/lnd/scripts/lncli.sh +150 -0
  49. package/skills/lnd/scripts/start-lnd.sh +241 -0
  50. package/skills/lnd/scripts/stop-lnd.sh +218 -0
  51. package/skills/lnd/scripts/unlock-wallet.sh +134 -0
  52. package/skills/lnd/templates/docker-compose-regtest.yml +122 -0
  53. package/skills/lnd/templates/docker-compose-watchonly.yml +71 -0
  54. package/skills/lnd/templates/docker-compose.yml +49 -0
  55. package/skills/lnd/templates/litd-regtest.conf.template +61 -0
  56. package/skills/lnd/templates/litd-watchonly.conf.template +57 -0
  57. package/skills/lnd/templates/litd.conf.template +88 -0
  58. package/skills/lnd/templates/lnd.conf.template +91 -0
  59. package/skills/lnget/SKILL.md +288 -0
  60. package/skills/lnget/scripts/install.sh +69 -0
  61. package/skills/macaroon-bakery/SKILL.md +179 -0
  62. package/skills/macaroon-bakery/scripts/bake.sh +337 -0
  63. package/skills/mcp-lnc/SKILL.md +280 -0
  64. package/skills/mcp-lnc/scripts/configure.sh +130 -0
  65. package/skills/mcp-lnc/scripts/install.sh +103 -0
  66. package/skills/mcp-lnc/scripts/setup-claude-config.sh +162 -0
  67. package/skills/mcp-lnc/templates/env.template +16 -0
  68. package/versions.env +23 -0
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@lightninglabs/lightning-mcp-server",
3
+ "version": "0.2.0",
4
+ "description": "Lightning Network agent toolkit for Claude Code — MCP server, L402 payments, node operations, and 7 composable skills",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/lightninglabs/lightning-agent-kit"
9
+ },
10
+ "homepage": "https://github.com/lightninglabs/lightning-agent-kit#quick-start",
11
+ "keywords": [
12
+ "lightning",
13
+ "lightning-network",
14
+ "lnc",
15
+ "l402",
16
+ "mcp",
17
+ "claude-code",
18
+ "bitcoin",
19
+ "lnd",
20
+ "aperture",
21
+ "agent"
22
+ ],
23
+ "bin": {
24
+ "lightning-mcp-server": "./bin/lightning-mcp-server"
25
+ },
26
+ "scripts": {
27
+ "postinstall": "node postinstall.js"
28
+ },
29
+ "files": [
30
+ "bin/",
31
+ "skills/",
32
+ "docs/",
33
+ ".claude-plugin/",
34
+ ".claude/",
35
+ "postinstall.js",
36
+ "versions.env",
37
+ "README.md",
38
+ "LICENSE"
39
+ ],
40
+ "engines": {
41
+ "node": ">=16"
42
+ },
43
+ "os": [
44
+ "darwin",
45
+ "linux",
46
+ "win32"
47
+ ],
48
+ "cpu": [
49
+ "x64",
50
+ "arm64"
51
+ ]
52
+ }
package/postinstall.js ADDED
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+
3
+ // postinstall.js downloads the pre-built lightning-mcp-server binary for the
4
+ // current platform and architecture from GitHub Releases. This follows the
5
+ // same pattern used by esbuild, turbo, and other Go/Rust projects distributed
6
+ // via npm.
7
+ //
8
+ // The binary is placed in bin/ so the npm "bin" entry in package.json can
9
+ // reference it directly, making `npx lightning-mcp-server` work out of the
10
+ // box.
11
+
12
+ const https = require("https");
13
+ const fs = require("fs");
14
+ const path = require("path");
15
+ const { execSync } = require("child_process");
16
+ const os = require("os");
17
+
18
+ // PLATFORM_MAP translates Node.js platform/arch identifiers to the Go build
19
+ // system naming convention used by the release workflow.
20
+ const PLATFORM_MAP = {
21
+ "darwin-arm64": "darwin-arm64",
22
+ "darwin-x64": "darwin-amd64",
23
+ "linux-arm64": "linux-arm64",
24
+ "linux-x64": "linux-amd64",
25
+ "win32-x64": "windows-amd64",
26
+ };
27
+
28
+ // REPO is the GitHub repository that hosts the release binaries.
29
+ const REPO = "lightninglabs/lightning-agent-kit";
30
+
31
+ // BINARY_NAME is the name of the binary inside the release tarball.
32
+ const BINARY_NAME = "lightning-mcp-server";
33
+
34
+ // getPackageVersion reads the version from package.json to determine which
35
+ // GitHub release tag to download from.
36
+ function getPackageVersion() {
37
+ const pkg = JSON.parse(
38
+ fs.readFileSync(path.join(__dirname, "package.json"), "utf8"),
39
+ );
40
+ return pkg.version;
41
+ }
42
+
43
+ // getPlatformKey returns the platform-architecture key for the current
44
+ // system, e.g. "darwin-arm64" or "linux-x64".
45
+ function getPlatformKey() {
46
+ const platform = os.platform();
47
+ const arch = os.arch();
48
+ return `${platform}-${arch}`;
49
+ }
50
+
51
+ // getBinaryPath returns the file path where the downloaded binary will be
52
+ // placed within the package's bin directory.
53
+ function getBinaryPath() {
54
+ const ext = os.platform() === "win32" ? ".exe" : "";
55
+ return path.join(__dirname, "bin", `${BINARY_NAME}${ext}`);
56
+ }
57
+
58
+ // fetchBuffer follows HTTP redirects (GitHub Releases redirects to a CDN)
59
+ // and returns the final response body as a buffer.
60
+ function fetchBuffer(url) {
61
+ return new Promise((resolve, reject) => {
62
+ const opts = { headers: { "User-Agent": "npm-postinstall" } };
63
+ https.get(url, opts, (res) => {
64
+ if (res.statusCode >= 300 && res.statusCode < 400 &&
65
+ res.headers.location) {
66
+ fetchBuffer(res.headers.location)
67
+ .then(resolve, reject);
68
+ return;
69
+ }
70
+ if (res.statusCode !== 200) {
71
+ reject(new Error(
72
+ `Download failed: HTTP ${res.statusCode} ` +
73
+ `from ${url}`,
74
+ ));
75
+ return;
76
+ }
77
+ const chunks = [];
78
+ res.on("data", (chunk) => chunks.push(chunk));
79
+ res.on("end", () => resolve(Buffer.concat(chunks)));
80
+ res.on("error", reject);
81
+ }).on("error", reject);
82
+ });
83
+ }
84
+
85
+ // extractTarGz extracts a .tar.gz buffer to the specified directory using
86
+ // the system tar command. The binary is expected at the root of the archive.
87
+ function extractTarGz(buffer, destDir) {
88
+ const tmpFile = path.join(
89
+ os.tmpdir(), `${BINARY_NAME}-${Date.now()}.tar.gz`,
90
+ );
91
+ fs.writeFileSync(tmpFile, buffer);
92
+ try {
93
+ execSync(`tar xzf "${tmpFile}" -C "${destDir}"`, {
94
+ stdio: "pipe",
95
+ });
96
+ } finally {
97
+ fs.unlinkSync(tmpFile);
98
+ }
99
+ }
100
+
101
+ // main downloads and installs the correct binary for the current platform.
102
+ async function main() {
103
+ const platformKey = getPlatformKey();
104
+ const goTarget = PLATFORM_MAP[platformKey];
105
+
106
+ if (!goTarget) {
107
+ console.error(
108
+ `Unsupported platform: ${platformKey}. ` +
109
+ `Supported: ${Object.keys(PLATFORM_MAP).join(", ")}`,
110
+ );
111
+ console.error(
112
+ "You can build from source instead:\n" +
113
+ " cd mcp-server && make build",
114
+ );
115
+ process.exit(1);
116
+ }
117
+
118
+ const version = getPackageVersion();
119
+ const tag = `v${version}`;
120
+ const assetName = `${BINARY_NAME}-${goTarget}.tar.gz`;
121
+ const url =
122
+ `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
123
+
124
+ console.log(
125
+ `Downloading ${BINARY_NAME} ${tag} for ${goTarget}...`,
126
+ );
127
+
128
+ try {
129
+ const buffer = await fetchBuffer(url);
130
+
131
+ // Ensure the bin directory exists before extracting.
132
+ const binDir = path.join(__dirname, "bin");
133
+ fs.mkdirSync(binDir, { recursive: true });
134
+
135
+ extractTarGz(buffer, binDir);
136
+
137
+ // Make the binary executable on Unix systems.
138
+ const binaryPath = getBinaryPath();
139
+ if (os.platform() !== "win32") {
140
+ fs.chmodSync(binaryPath, 0o755);
141
+ }
142
+
143
+ console.log(`Installed ${BINARY_NAME} to ${binaryPath}`);
144
+ } catch (err) {
145
+ console.error(
146
+ `Failed to download ${BINARY_NAME}: ${err.message}`,
147
+ );
148
+ console.error("");
149
+ console.error("You can build from source instead:");
150
+ console.error(" cd mcp-server && make build");
151
+ console.error("");
152
+ console.error(
153
+ "Or download from: " +
154
+ `https://github.com/${REPO}/releases/tag/${tag}`,
155
+ );
156
+ process.exit(1);
157
+ }
158
+ }
159
+
160
+ main();
@@ -0,0 +1,330 @@
1
+ ---
2
+ name: aperture
3
+ description: Install and run Aperture, the L402 Lightning reverse proxy from Lightning Labs. Use when creating L402 paywalls, configuring paid API endpoints, hosting paid content for other agents, or testing L402 authentication flows.
4
+ ---
5
+
6
+ # Aperture - L402 Lightning Reverse Proxy
7
+
8
+ Aperture is a reverse proxy that implements the L402 protocol, enabling
9
+ payment-gated API access via the Lightning Network. It sits in front of your
10
+ backend services and requires Lightning micropayments before granting access.
11
+
12
+ **Source:** `github.com/lightninglabs/aperture`
13
+
14
+ ## Quick Start
15
+
16
+ ```bash
17
+ # 1. Install aperture
18
+ skills/aperture/scripts/install.sh
19
+
20
+ # 2. Generate config (connects to local lnd)
21
+ skills/aperture/scripts/setup.sh
22
+
23
+ # 3. Start aperture
24
+ skills/aperture/scripts/start.sh
25
+
26
+ # 4. Test with lnget
27
+ lnget -k --no-pay https://localhost:8081/api/test
28
+ ```
29
+
30
+ ## How Aperture Works
31
+
32
+ 1. Client requests a protected resource through Aperture
33
+ 2. Aperture responds with HTTP 402 + `WWW-Authenticate: L402` header containing
34
+ a macaroon and a Lightning invoice
35
+ 3. Client pays the invoice and obtains the preimage
36
+ 4. Client retries with `Authorization: L402 <macaroon>:<preimage>`
37
+ 5. Aperture validates the token and proxies to the backend service
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ skills/aperture/scripts/install.sh
43
+ ```
44
+
45
+ This will:
46
+ - Verify Go is installed
47
+ - Run `go install github.com/lightninglabs/aperture/cmd/aperture@latest`
48
+ - Verify `aperture` is on `$PATH`
49
+
50
+ To install manually:
51
+
52
+ ```bash
53
+ go install github.com/lightninglabs/aperture/cmd/aperture@latest
54
+ ```
55
+
56
+ Or build from source:
57
+
58
+ ```bash
59
+ git clone https://github.com/lightninglabs/aperture.git
60
+ cd aperture
61
+ make install
62
+ ```
63
+
64
+ ## Setup
65
+
66
+ ```bash
67
+ skills/aperture/scripts/setup.sh
68
+ ```
69
+
70
+ This generates `~/.aperture/aperture.yaml` from the config template with
71
+ sensible defaults. The setup script auto-detects the local lnd node paths.
72
+
73
+ **Options:**
74
+
75
+ ```bash
76
+ # Custom network
77
+ setup.sh --network testnet
78
+
79
+ # Custom lnd paths
80
+ setup.sh --lnd-host localhost:10009 \
81
+ --lnd-tls ~/.lnd/tls.cert \
82
+ --lnd-macdir ~/.lnd/data/chain/bitcoin/mainnet
83
+
84
+ # Custom listen port
85
+ setup.sh --port 8081
86
+
87
+ # Disable TLS (development only)
88
+ setup.sh --insecure
89
+
90
+ # Disable auth (no payments required)
91
+ setup.sh --no-auth
92
+ ```
93
+
94
+ ## Running Aperture
95
+
96
+ ### Start
97
+
98
+ ```bash
99
+ skills/aperture/scripts/start.sh
100
+ ```
101
+
102
+ Starts aperture as a background process reading `~/.aperture/aperture.yaml`.
103
+
104
+ **Options:**
105
+
106
+ ```bash
107
+ start.sh --foreground # Run in foreground
108
+ start.sh --config /path/to # Custom config path
109
+ ```
110
+
111
+ ### Stop
112
+
113
+ ```bash
114
+ skills/aperture/scripts/stop.sh
115
+ ```
116
+
117
+ ## Configuration
118
+
119
+ Config file: `~/.aperture/aperture.yaml`
120
+
121
+ ### Minimal Agent Configuration
122
+
123
+ This is the minimal config for an agent hosting paid endpoints with a local
124
+ lnd node:
125
+
126
+ ```yaml
127
+ listenaddr: "localhost:8081"
128
+ insecure: true
129
+ debuglevel: "info"
130
+ dbbackend: "sqlite"
131
+ sqlite:
132
+ dbfile: "~/.aperture/aperture.db"
133
+
134
+ authenticator:
135
+ network: "mainnet"
136
+ lndhost: "localhost:10009"
137
+ tlspath: "~/.lnd/tls.cert"
138
+ macdir: "~/.lnd/data/chain/bitcoin/mainnet"
139
+
140
+ services:
141
+ - name: "my-api"
142
+ hostregexp: ".*"
143
+ pathregexp: "^/api/.*$"
144
+ address: "127.0.0.1:8080"
145
+ protocol: http
146
+ price: 100
147
+ ```
148
+
149
+ ### Service Configuration
150
+
151
+ Each service entry defines a backend to protect:
152
+
153
+ ```yaml
154
+ services:
155
+ - name: "service-name"
156
+ # Match requests by host (regex).
157
+ hostregexp: "^api.example.com$"
158
+
159
+ # Match requests by path (regex).
160
+ pathregexp: "^/paid/.*$"
161
+
162
+ # Backend address to proxy to.
163
+ address: "127.0.0.1:8080"
164
+
165
+ # Protocol: http or https.
166
+ protocol: http
167
+
168
+ # Static price in satoshis.
169
+ price: 100
170
+
171
+ # Macaroon capabilities granted at base tier.
172
+ capabilities: "read,write"
173
+
174
+ # Token expiry in seconds (31557600 = 1 year).
175
+ timeout: 31557600
176
+
177
+ # Paths exempt from payment.
178
+ authwhitelistpaths:
179
+ - "^/health$"
180
+ - "^/public/.*$"
181
+
182
+ # Per-endpoint rate limits (token bucket).
183
+ ratelimits:
184
+ - pathregexp: "^/api/query.*$"
185
+ requests: 10
186
+ per: 1s
187
+ burst: 20
188
+ ```
189
+
190
+ ### Authentication Backends
191
+
192
+ #### Direct LND Connection
193
+
194
+ ```yaml
195
+ authenticator:
196
+ network: "mainnet"
197
+ lndhost: "localhost:10009"
198
+ tlspath: "~/.lnd/tls.cert"
199
+ macdir: "~/.lnd/data/chain/bitcoin/mainnet"
200
+ ```
201
+
202
+ #### Lightning Node Connect (LNC)
203
+
204
+ ```yaml
205
+ authenticator:
206
+ network: "mainnet"
207
+ passphrase: "your-pairing-phrase"
208
+ mailboxaddress: "mailbox.terminal.lightning.today:443"
209
+ ```
210
+
211
+ #### Disable Authentication
212
+
213
+ ```yaml
214
+ authenticator:
215
+ disable: true
216
+ ```
217
+
218
+ ### Database Backends
219
+
220
+ **SQLite (recommended for agents):**
221
+
222
+ ```yaml
223
+ dbbackend: "sqlite"
224
+ sqlite:
225
+ dbfile: "~/.aperture/aperture.db"
226
+ ```
227
+
228
+ **PostgreSQL:**
229
+
230
+ ```yaml
231
+ dbbackend: "postgres"
232
+ postgres:
233
+ host: "localhost"
234
+ port: 5432
235
+ user: "aperture"
236
+ password: "secret"
237
+ dbname: "aperture"
238
+ ```
239
+
240
+ ### TLS Configuration
241
+
242
+ ```yaml
243
+ # Auto Let's Encrypt certificate.
244
+ autocert: true
245
+ servername: "api.example.com"
246
+
247
+ # Or disable TLS (development/local only).
248
+ insecure: true
249
+ ```
250
+
251
+ If neither is set, Aperture generates self-signed certs in `~/.aperture/`.
252
+
253
+ ### Dynamic Pricing
254
+
255
+ Connect to a gRPC price server instead of static prices:
256
+
257
+ ```yaml
258
+ services:
259
+ - name: "my-api"
260
+ dynamicprice:
261
+ enabled: true
262
+ grpcaddress: "127.0.0.1:10010"
263
+ insecure: false
264
+ tlscertpath: "/path/to/pricer/tls.cert"
265
+ ```
266
+
267
+ ## Hosting Paid Content for Agents
268
+
269
+ A common pattern is hosting information that other agents pay to access:
270
+
271
+ ```bash
272
+ # 1. Start a simple HTTP backend with your content
273
+ mkdir -p /tmp/paid-content
274
+ echo '{"data": "valuable information"}' > /tmp/paid-content/info.json
275
+ cd /tmp/paid-content && python3 -m http.server 8080 &
276
+
277
+ # 2. Configure aperture to protect it
278
+ skills/aperture/scripts/setup.sh --insecure --port 8081
279
+
280
+ # 3. Start aperture
281
+ skills/aperture/scripts/start.sh
282
+
283
+ # 4. Other agents can now pay and fetch
284
+ lnget --max-cost 100 https://localhost:8081/api/info.json
285
+ ```
286
+
287
+ ## Integration with lnget and lnd
288
+
289
+ With all three components running:
290
+
291
+ ```bash
292
+ # Verify lnd is running
293
+ skills/lnd/scripts/lncli.sh getinfo
294
+
295
+ # Start aperture (uses same lnd for invoice generation)
296
+ skills/aperture/scripts/start.sh
297
+
298
+ # Fetch a paid resource
299
+ lnget --max-cost 1000 https://localhost:8081/api/data
300
+
301
+ # Check tokens
302
+ lnget tokens list
303
+ ```
304
+
305
+ ## File Locations
306
+
307
+ | Path | Purpose |
308
+ |------|---------|
309
+ | `~/.aperture/aperture.yaml` | Configuration file |
310
+ | `~/.aperture/aperture.db` | SQLite database |
311
+ | `~/.aperture/tls.cert` | TLS certificate |
312
+ | `~/.aperture/tls.key` | TLS private key |
313
+ | `~/.aperture/aperture.log` | Log file |
314
+
315
+ ## Troubleshooting
316
+
317
+ ### Port already in use
318
+ Change `listenaddr` in config to a different port, or use `setup.sh --port`.
319
+
320
+ ### LND connection refused
321
+ Verify lnd is running and wallet is unlocked. Check `lndhost`, `tlspath`, and
322
+ `macdir` in the config point to the correct lnd instance.
323
+
324
+ ### No 402 challenge returned
325
+ Check that the request path matches a service's `pathregexp` and is not in
326
+ `authwhitelistpaths`. Verify `authenticator.disable` is not `true`.
327
+
328
+ ### Token validation fails
329
+ The client must present the exact macaroon from the challenge with the correct
330
+ preimage. Verify the preimage matches the payment hash.
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # Install aperture from source.
3
+ #
4
+ # Usage:
5
+ # install.sh # Install latest
6
+ # install.sh --version v0.3.3-beta # Specific version
7
+
8
+ set -e
9
+
10
+ VERSION=""
11
+
12
+ # Parse arguments.
13
+ while [[ $# -gt 0 ]]; do
14
+ case $1 in
15
+ --version)
16
+ VERSION="@$2"
17
+ shift 2
18
+ ;;
19
+ -h|--help)
20
+ echo "Usage: install.sh [--version VERSION]"
21
+ echo ""
22
+ echo "Install aperture L402 reverse proxy."
23
+ echo ""
24
+ echo "Options:"
25
+ echo " --version VERSION Go module version (e.g., v0.3.3-beta)"
26
+ exit 0
27
+ ;;
28
+ *)
29
+ echo "Unknown option: $1" >&2
30
+ exit 1
31
+ ;;
32
+ esac
33
+ done
34
+
35
+ echo "=== Installing Aperture ==="
36
+ echo ""
37
+
38
+ # Verify Go is installed.
39
+ if ! command -v go &>/dev/null; then
40
+ echo "Error: Go is not installed." >&2
41
+ echo "Install Go from https://go.dev/dl/" >&2
42
+ exit 1
43
+ fi
44
+
45
+ echo "Go version: $(go version | grep -oE 'go[0-9]+\.[0-9]+')"
46
+ echo ""
47
+
48
+ # Install aperture.
49
+ echo "Installing aperture..."
50
+ go install "github.com/lightninglabs/aperture/cmd/aperture${VERSION}"
51
+ echo "Done."
52
+ echo ""
53
+
54
+ # Verify installation.
55
+ if command -v aperture &>/dev/null; then
56
+ echo "aperture installed: $(which aperture)"
57
+ else
58
+ echo "Warning: aperture not found on PATH." >&2
59
+ echo "Ensure \$GOPATH/bin is in your PATH." >&2
60
+ echo " export PATH=\$PATH:\$(go env GOPATH)/bin" >&2
61
+ fi
62
+
63
+ echo ""
64
+ echo "Installation complete."
65
+ echo ""
66
+ echo "Next steps:"
67
+ echo " 1. Setup config: skills/aperture/scripts/setup.sh"
68
+ echo " 2. Start: skills/aperture/scripts/start.sh"