feat(config): add gmgn-cli config command for API Key onboarding

Add a new `gmgn-cli config` command that automates Ed25519 key pair
generation for new users. The command reuses an existing keypair.pem if
present, or generates a new one, then outputs a pre-filled API Key
creation link with the public key embedded. Guidance text is output in
the user's system locale (zh-CN, zh-TW, or English).

All 6 SKILL.md files are updated with a BEFORE RUNNING ANY COMMAND
block that detects missing GMGN_API_KEY, triggers gmgn-cli config, and
instructs the Agent to write both GMGN_API_KEY and GMGN_PRIVATE_KEY
into ~/.config/gmgn/.env once the user provides their API Key.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gina888666
2026-06-24 13:53:48 +08:00
parent 845a8aaa62
commit e8af4b88b5
8 changed files with 124 additions and 0 deletions
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli cooking --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai — all token creation operations must go through the CLI. The CLI handles signing and submission automatically.**
**IMPORTANT: Do NOT guess field names or values. When a field's meaning is unclear, look it up in the Response Fields sections below before using it.**
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli market --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai to fetch this data — the website requires login and will not return structured data. The CLI is the only correct method.**
**IMPORTANT: Do NOT guess field names or values. When a field's meaning is unclear, look it up in the Response Fields sections below before using it.**
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli portfolio --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai to fetch this data — the website requires login and will not return structured data. The CLI is the only correct method.**
**⚠️ IPv6 NOT SUPPORTED: If you get a `401` or `403` error and credentials look correct, check for IPv6 immediately: (1) list all network interfaces and their IPv6 addresses — run `ifconfig | grep inet6` (macOS) or `ip addr show | grep inet6` (Linux); (2) send a test request to `https://ipv6.icanhazip.com` — if the response is an IPv6 address, outbound traffic is going via IPv6. Tell the user immediately: "Please disable IPv6 on your network interface — gmgn-cli commands only work over IPv4."**
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli swap --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai — all swap operations must go through the CLI. The CLI handles signing and submission automatically.**
**IMPORTANT: Do NOT guess field names or values. When a field's meaning is unclear, look it up in the Response Fields sections below before using it.**
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli token --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai to fetch this data — the website requires login and will not return structured data. The CLI is the only correct method.**
**⚠️ IPv6 NOT SUPPORTED: If you get a `401` or `403` error and credentials look correct, check for IPv6 immediately: (1) list all network interfaces and their IPv6 addresses — run `ifconfig | grep inet6` (macOS) or `ip addr show | grep inet6` (Linux); (2) send a test request to `https://ipv6.icanhazip.com` — if the response is an IPv6 address, outbound traffic is going via IPv6. Tell the user immediately: "Please disable IPv6 on your network interface — gmgn-cli commands only work over IPv4."**
+11
View File
@@ -6,6 +6,17 @@ metadata:
cliHelp: "gmgn-cli track --help"
---
**BEFORE RUNNING ANY COMMAND: Check whether `GMGN_API_KEY` exists in `<cwd>/.env` or `~/.config/gmgn/.env`. If found in either location, proceed normally. If not found in either location, stop and run `gmgn-cli config` first — this generates an Ed25519 key pair and outputs a pre-filled link. Show the link to the user and ask them to create their API Key. Once the user sends back the API Key, write `GMGN_API_KEY` and `GMGN_PRIVATE_KEY` together into `~/.config/gmgn/.env` using the following commands, then proceed:**
```bash
PRIVATE_KEY=$(awk '/-----BEGIN PRIVATE KEY-----/{p=1} p{printf "%s\\n", $0} /-----END PRIVATE KEY-----/{p=0}' ~/.config/gmgn/keypair.pem)
grep -v "^GMGN_API_KEY=\|^GMGN_PRIVATE_KEY=" ~/.config/gmgn/.env 2>/dev/null > /tmp/gmgn_env_tmp
echo "GMGN_API_KEY=<key_from_user>" >> /tmp/gmgn_env_tmp
echo "GMGN_PRIVATE_KEY=$PRIVATE_KEY" >> /tmp/gmgn_env_tmp
mv /tmp/gmgn_env_tmp ~/.config/gmgn/.env
chmod 600 ~/.config/gmgn/.env
```
**IMPORTANT: Always use `gmgn-cli` commands below. Do NOT use web search, WebFetch, curl, or visit gmgn.ai to fetch this data — the website requires login and will not return structured data. The CLI is the only correct method.**
**IMPORTANT: Do NOT guess field names or values. When a field's meaning is unclear, look it up in the Response Fields sections below before using it.**
+56
View File
@@ -0,0 +1,56 @@
import { Command } from "commander";
import * as crypto from "crypto";
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
const GMGN_CONFIG_DIR = path.join(os.homedir(), ".config", "gmgn");
const KEYPAIR_FILE = path.join(GMGN_CONFIG_DIR, "keypair.pem");
const GMGN_API_URL = "https://gmgn.ai/ai/generateapi";
export function registerConfigCommands(program: Command): void {
program
.command("config")
.description("Generate an Ed25519 key pair and output a pre-filled GMGN API Key creation link")
.action(async () => {
fs.mkdirSync(GMGN_CONFIG_DIR, { recursive: true });
let publicPem: string;
if (fs.existsSync(KEYPAIR_FILE)) {
// Reuse existing key pair
const content = fs.readFileSync(KEYPAIR_FILE, "utf-8");
const match = content.match(/(-----BEGIN PUBLIC KEY-----[\s\S]+?-----END PUBLIC KEY-----)/);
if (!match) {
console.error("Error: keypair.pem exists but public key could not be parsed. Delete ~/.config/gmgn/keypair.pem and try again.");
process.exit(1);
}
publicPem = match[1] + "\n";
} else {
// Generate new Ed25519 key pair
const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519");
const privatePem = privateKey.export({ type: "pkcs8", format: "pem" }) as string;
publicPem = publicKey.export({ type: "spki", format: "pem" }) as string;
const entry = `# Private Key\n${privatePem}\n# Public Key\n${publicPem}\n`;
fs.writeFileSync(KEYPAIR_FILE, entry, { mode: 0o600 });
}
const link = `${GMGN_API_URL}?pbk=${encodeURIComponent(publicPem)}`;
const locale = (process.env.LANG ?? process.env.LC_ALL ?? process.env.LC_MESSAGES ?? "").toLowerCase();
let message: string;
if (locale.startsWith("zh_tw") || locale.startsWith("zh_hk")) {
message = "請點擊連結建立你的 GMGN API Key,完成後將 Key 發給我,我來幫你完成配置:";
} else if (locale.startsWith("zh")) {
message = "请点击链接创建你的 GMGN API Key,完成后将 Key 发给我,我来帮你完成配置:";
} else {
message = "Please click the link below to create your GMGN API Key. Once created, send me the API Key and I will finish the configuration:";
}
console.log("");
console.log(message);
console.log(link);
console.log("");
});
}
+2
View File
@@ -11,6 +11,7 @@ import { registerPortfolioCommands } from "./commands/portfolio.js";
import { registerTrackCommands } from "./commands/track.js";
import { registerSwapCommands } from "./commands/swap.js";
import { registerCookingCommands } from "./commands/cooking.js";
import { registerConfigCommands } from "./commands/config.js";
const proxy = process.env.HTTPS_PROXY ?? process.env.https_proxy
?? process.env.HTTP_PROXY ?? process.env.http_proxy;
@@ -60,6 +61,7 @@ registerPortfolioCommands(program);
registerTrackCommands(program);
registerSwapCommands(program);
registerCookingCommands(program);
registerConfigCommands(program);
program.parseAsync().catch((err) => {
console.error(`[gmgn-cli] ${err.message}`);