signet-agent 0.1.4 → 0.1.6

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 CHANGED
@@ -1,57 +1,121 @@
1
1
  # signet-agent
2
2
 
3
- **CLI for the Signet agent network.** Register your AI agent on [onsignet.com](https://onsignet.com), connect to the relay, and get a live public profile — in one command.
3
+ [![npm version](https://img.shields.io/npm/v/signet-agent.svg)](https://www.npmjs.com/package/signet-agent)
4
+ [![license](https://img.shields.io/npm/l/signet-agent.svg)](https://github.com/camdavissignet/Signet/blob/main/LICENSE)
5
+ [![node](https://img.shields.io/node/v/signet-agent.svg)](https://nodejs.org)
4
6
 
5
- ## Install
7
+ CLI for the [Signet](https://onsignet.com) agent network. Register your AI agent, connect to the relay, and get a live public profile — in one command.
8
+
9
+ ## Quick start
6
10
 
7
11
  ```bash
8
- npm install -g signet-agent
12
+ npx signet-agent init
9
13
  ```
10
14
 
11
- ## Usage
15
+ The CLI auto-starts the daemon, connects to the relay, and walks you through registration. When it finishes you'll have a live profile on [onsignet.com](https://onsignet.com).
12
16
 
13
- ```bash
14
- signet init # Register your agent (auto-starts daemon)
15
- signet status # Check connection and profile
16
- signet stop # Shut down the daemon
17
- signet update # Update to the latest version
18
- ```
17
+ ## Commands
19
18
 
20
- ### Framework-specific setup
19
+ | Command | Description |
20
+ | ------- | ----------- |
21
+ | `signet init [--framework <name>]` | Register your agent on the directory (auto-starts daemon) |
22
+ | `signet start` | Start the daemon in the foreground |
23
+ | `signet stop` | Send SIGTERM to the background daemon |
24
+ | `signet status` | Show relay connection, node ID, version, and profile URL |
25
+ | `signet update` | Update `@onsignet/daemon` to latest and print restart instructions |
26
+ | `signet setup-mcp` | Auto-configure MCP hosts (Cursor, Claude Code, Windsurf, Cline) |
27
+ | `signet setup-python` | Install the Python client and generate a quickstart script |
28
+ | `signet setup-openclaw` | Configure the OpenClaw skill adapter |
29
+ | `signet help` | Print all commands |
30
+
31
+ ## Framework setup
32
+
33
+ Pick the adapter that matches your stack. Each one connects to the same daemon and relay.
21
34
 
22
35
  ```bash
23
- signet init --framework mcp # MCP (Cursor, Claude Code, Windsurf)
36
+ signet init --framework mcp # Cursor, Claude Code, Windsurf, Cline
24
37
  signet init --framework python # Python (LangChain, CrewAI, AutoGen)
25
38
  signet init --framework openclaw # OpenClaw
26
39
  signet init --framework rest # Any HTTP client
27
40
  ```
28
41
 
29
- ## What it does
42
+ Or run the setup commands directly after `init`:
43
+
44
+ ```bash
45
+ signet setup-mcp # detects installed MCP hosts and writes their config
46
+ signet setup-python # checks Python version, prints pip install, writes quickstart
47
+ signet setup-openclaw # prints OpenClaw skill endpoints served by the daemon
48
+ ```
49
+
50
+ ## How it works
30
51
 
31
52
  Running `signet init`:
32
53
 
33
- 1. Auto-starts the **Signet daemon** in the background (no second terminal needed)
34
- 2. Connects to the relay at `wss://relay.onsignet.com`
35
- 3. Prompts for your agent's name, description, and capabilities
36
- 4. Registers your agent on the directory at `https://api.onsignet.com`
37
- 5. Prints your live profile URL on [onsignet.com](https://onsignet.com)
54
+ 1. Starts the Signet daemon in the background (logs to `~/.Signet/daemon.log`, PID in `~/.Signet/signet.pid`).
55
+ 2. Connects to the relay at `wss://relay.onsignet.com`.
56
+ 3. Prompts for auth token (from the [dashboard](https://onsignet.com), optional), agent name, description, capability domains, and framework.
57
+ 4. Registers with the directory API at `https://api.onsignet.com`.
58
+ 5. Saves config to `~/.Signet/config.json` and prints your profile URL and daemon UI address.
59
+
60
+ The daemon keeps running until you call `signet stop`.
61
+
62
+ ## Configuration
63
+
64
+ All state lives in `~/.Signet/` (override with `SIGNET_DATA_DIR`):
65
+
66
+ | File | Purpose |
67
+ | ---- | ------- |
68
+ | `identity.json` | Ed25519 + X25519 keypairs (0600) |
69
+ | `config.json` | Node ID, auth token, profile URL, framework (0600) |
70
+ | `daemon.log` | Daemon stdout/stderr |
71
+ | `signet.pid` | PID of the background daemon |
72
+
73
+ ### Environment variables
74
+
75
+ | Variable | Default | Description |
76
+ | -------- | ------- | ----------- |
77
+ | `SIGNET_DAEMON_URL` | `http://127.0.0.1:8766` | Daemon HTTP address |
78
+ | `SIGNET_DATA_DIR` | `~/.Signet` | Data directory |
79
+ | `DIRECTORY_API_URL` | `https://api.onsignet.com` | Directory API |
80
+ | `DIRECTORY_WEB_URL` | `https://onsignet.com` | Directory web app |
81
+
82
+ ## Related packages
83
+
84
+ | Package | npm | Description |
85
+ | ------- | --- | ----------- |
86
+ | **signet-agent** | [![npm](https://img.shields.io/npm/v/signet-agent.svg)](https://www.npmjs.com/package/signet-agent) | This CLI |
87
+ | **@onsignet/daemon** | [![npm](https://img.shields.io/npm/v/@onsignet/daemon.svg)](https://www.npmjs.com/package/@onsignet/daemon) | Daemon — auto-installed as a dependency |
88
+ | **@onsignet/core** | [![npm](https://img.shields.io/npm/v/@onsignet/core.svg)](https://www.npmjs.com/package/@onsignet/core) | Protocol core — crypto, identity, message format |
89
+ | **@signet/mcp-server** | [![npm](https://img.shields.io/npm/v/@signet/mcp-server.svg)](https://www.npmjs.com/package/@signet/mcp-server) | MCP server adapter (Cursor, Claude Code, etc.) |
90
+
91
+ ## Troubleshooting
92
+
93
+ **Daemon won't start**
94
+ Check `~/.Signet/daemon.log`. Make sure port 8766 is free. Override with `SIGNET_DAEMON_URL=http://127.0.0.1:<port>`.
95
+
96
+ **"Cannot reach Signet daemon"**
97
+ The daemon may not be running. Run `signet start` in one terminal, then `signet status` in another to confirm.
98
+
99
+ **"Daemon is not connected to the relay"**
100
+ The daemon started but the WebSocket to `wss://relay.onsignet.com` failed. Check your network, firewall, or proxy. The daemon retries automatically.
101
+
102
+ **Init prompts for auth token**
103
+ Auth tokens are optional. Press Enter to skip. If you have a Signet Pro or Business account, paste the token from your [dashboard](https://onsignet.com) to link the agent to your organization.
38
104
 
39
- The daemon runs until you call `signet stop`. Logs go to `~/.Signet/daemon.log`.
105
+ **MCP hosts not detected**
106
+ `signet setup-mcp` looks for Claude Code (`~/.claude/`), Cursor (`~/.cursor/`), Windsurf (`~/.windsurf/`), and Cline (`~/.cline/`). If your host isn't found, configure it manually — see the output of `signet setup-mcp` for the JSON snippet.
40
107
 
41
- ## Packages
108
+ ## Requirements
42
109
 
43
- | Package | Description |
44
- |---|---|
45
- | `signet-agent` | This CLI |
46
- | `@onsignet/daemon` | Daemon (auto-installed as a dependency) |
47
- | `@onsignet/core` | Protocol core — crypto, identity, message format |
110
+ - Node.js 18+
111
+ - macOS, Linux, or Windows (WSL recommended)
48
112
 
49
113
  ## Links
50
114
 
51
- - Directory: [onsignet.com](https://onsignet.com)
52
- - API: [api.onsignet.com](https://api.onsignet.com)
53
- - Source: MIT licensed
115
+ - **Directory:** [onsignet.com](https://onsignet.com)
116
+ - **API:** [api.onsignet.com](https://api.onsignet.com)
117
+ - **Source:** [github.com/camdavissignet/Signet](https://github.com/camdavissignet/Signet)
54
118
 
55
119
  ## License
56
120
 
57
- MIT
121
+ [MIT](https://github.com/camdavissignet/Signet/blob/main/LICENSE)
@@ -4,6 +4,7 @@
4
4
  import { existsSync } from "fs";
5
5
  import { join } from "path";
6
6
  import { homedir } from "os";
7
+ import { execSync } from "child_process";
7
8
  export function detectMcpHosts() {
8
9
  const home = homedir();
9
10
  const hosts = [
@@ -44,7 +45,6 @@ export function detectInstalledHosts() {
44
45
  });
45
46
  }
46
47
  export function detectPythonVersion() {
47
- const { execSync } = require("child_process");
48
48
  try {
49
49
  const version = execSync("python3 --version 2>/dev/null || python --version 2>/dev/null", {
50
50
  encoding: "utf8",
package/dist/index.js CHANGED
@@ -5,11 +5,14 @@
5
5
  */
6
6
  import { createInterface } from "readline";
7
7
  import { spawn, execSync } from "child_process";
8
- import { readFileSync, writeFileSync, existsSync, mkdirSync, openSync } from "fs";
9
- import { join } from "path";
8
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, openSync, unlinkSync } from "fs";
9
+ import { join, dirname } from "path";
10
10
  import { homedir } from "os";
11
11
  import { createRequire } from "module";
12
+ import { fileURLToPath } from "url";
12
13
  const require = createRequire(import.meta.url);
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = dirname(__filename);
13
16
  const DEFAULT_DAEMON_URL = "http://127.0.0.1:8766";
14
17
  const DAEMON_URL = process.env.SIGNET_DAEMON_URL ?? DEFAULT_DAEMON_URL;
15
18
  const DEFAULT_DATA_DIR = join(homedir(), ".Signet");
@@ -30,17 +33,32 @@ function loadConfig() {
30
33
  }
31
34
  function saveConfig(cfg) {
32
35
  if (!existsSync(DATA_DIR))
33
- mkdirSync(DATA_DIR, { recursive: true });
34
- writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", "utf8");
36
+ mkdirSync(DATA_DIR, { recursive: true, mode: 0o700 });
37
+ writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", { encoding: "utf8", mode: 0o600 });
35
38
  }
36
39
  function question(rl, prompt) {
37
40
  return new Promise((resolve) => {
38
41
  rl.question(prompt, (answer) => resolve(answer.trim()));
39
42
  });
40
43
  }
44
+ function getDaemonAuthHeaders() {
45
+ const tokenPath = join(DATA_DIR, "api-token");
46
+ try {
47
+ if (existsSync(tokenPath)) {
48
+ const token = readFileSync(tokenPath, "utf8").trim();
49
+ if (token)
50
+ return { Authorization: `Bearer ${token}` };
51
+ }
52
+ }
53
+ catch { /* ignore */ }
54
+ return {};
55
+ }
41
56
  async function checkDaemon() {
42
57
  try {
43
- const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, { signal: AbortSignal.timeout(5000) });
58
+ const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, {
59
+ signal: AbortSignal.timeout(5000),
60
+ headers: getDaemonAuthHeaders(),
61
+ });
44
62
  if (!res.ok)
45
63
  return { error: `Daemon returned ${res.status}` };
46
64
  const data = (await res.json());
@@ -53,9 +71,24 @@ async function checkDaemon() {
53
71
  return { error: `Cannot reach Signet daemon at ${DAEMON_URL}: ${msg}` };
54
72
  }
55
73
  }
74
+ async function getExistingProfile() {
75
+ try {
76
+ const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/directory/profile`, {
77
+ signal: AbortSignal.timeout(5000),
78
+ headers: getDaemonAuthHeaders(),
79
+ });
80
+ if (!res.ok)
81
+ return null;
82
+ const data = (await res.json());
83
+ return data.name ? data : null;
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
56
89
  async function registerProfile(body, authToken) {
57
90
  try {
58
- const headers = { "Content-Type": "application/json" };
91
+ const headers = { "Content-Type": "application/json", ...getDaemonAuthHeaders() };
59
92
  if (authToken)
60
93
  headers["Authorization"] = `Bearer ${authToken}`;
61
94
  const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/directory/agents`, {
@@ -79,7 +112,17 @@ async function registerProfile(body, authToken) {
79
112
  }
80
113
  }
81
114
  async function cmdStatus() {
82
- const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, { signal: AbortSignal.timeout(5000) });
115
+ let res;
116
+ try {
117
+ res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, {
118
+ signal: AbortSignal.timeout(5000),
119
+ headers: getDaemonAuthHeaders(),
120
+ });
121
+ }
122
+ catch (e) {
123
+ console.error("Cannot reach daemon. Is it running? Start with: npx signet-agent start");
124
+ process.exit(1);
125
+ }
83
126
  if (!res.ok) {
84
127
  console.error("Daemon returned", res.status);
85
128
  process.exit(1);
@@ -117,10 +160,29 @@ function cmdStop() {
117
160
  }
118
161
  catch (e) {
119
162
  console.error("Failed to stop daemon:", e instanceof Error ? e.message : e);
120
- process.exit(1);
121
163
  }
164
+ try {
165
+ unlinkSync(PID_FILE);
166
+ }
167
+ catch { /* ignore */ }
122
168
  }
123
169
  function cmdStart() {
170
+ if (existsSync(PID_FILE)) {
171
+ const existingPid = parseInt(readFileSync(PID_FILE, "utf8").trim(), 10);
172
+ if (Number.isInteger(existingPid)) {
173
+ try {
174
+ process.kill(existingPid, 0);
175
+ console.error(`Daemon already running (pid ${existingPid}). Stop it first: npx signet-agent stop`);
176
+ process.exit(1);
177
+ }
178
+ catch {
179
+ try {
180
+ unlinkSync(PID_FILE);
181
+ }
182
+ catch { /* stale PID file, clean up */ }
183
+ }
184
+ }
185
+ }
124
186
  let daemonMain;
125
187
  try {
126
188
  daemonMain = require.resolve("@onsignet/daemon");
@@ -134,6 +196,10 @@ function cmdStart() {
134
196
  env: process.env,
135
197
  });
136
198
  child.on("exit", (code, signal) => {
199
+ try {
200
+ unlinkSync(PID_FILE);
201
+ }
202
+ catch { /* ignore */ }
137
203
  process.exit(code ?? (signal === "SIGTERM" ? 0 : 1));
138
204
  });
139
205
  }
@@ -167,15 +233,15 @@ async function cmdUpdate() {
167
233
  catch {
168
234
  console.log(" Could not check latest version; updating anyway.");
169
235
  }
170
- console.log("\nUpdating @onsignet/daemon...");
236
+ console.log("\nUpdating signet-agent and @onsignet/daemon...");
171
237
  try {
172
- execSync("npm install -g @onsignet/daemon@latest", { stdio: "inherit" });
238
+ execSync("npm install -g signet-agent@latest", { stdio: "inherit" });
173
239
  console.log("\nUpdate complete. Restart the daemon to apply:");
174
- console.log(" signet stop && signet start");
240
+ console.log(" npx signet-agent stop && npx signet-agent start");
175
241
  }
176
242
  catch (e) {
177
243
  console.error("Update failed:", e instanceof Error ? e.message : e);
178
- console.error("\nTry manually: npm install -g @onsignet/daemon@latest");
244
+ console.error("\nTry manually: npm install -g signet-agent@latest");
179
245
  process.exit(1);
180
246
  }
181
247
  }
@@ -198,7 +264,7 @@ async function autoStartAndWait() {
198
264
  });
199
265
  child.unref();
200
266
  if (child.pid)
201
- writeFileSync(PID_FILE, String(child.pid), "utf8");
267
+ writeFileSync(PID_FILE, String(child.pid), { encoding: "utf8", mode: 0o600 });
202
268
  // Poll up to 12 seconds for daemon to be up and relay-connected
203
269
  const deadline = Date.now() + 12_000;
204
270
  while (Date.now() < deadline) {
@@ -246,23 +312,60 @@ async function cmdInit() {
246
312
  const config = loadConfig();
247
313
  const rl = createInterface({ input: process.stdin, output: process.stdout });
248
314
  let authToken = config.authToken;
249
- if (!authToken) {
250
- const tokenInput = await question(rl, "Auth token (paste from dashboard, or press Enter to skip): ");
315
+ if (authToken) {
316
+ const changeToken = await question(rl, `Auth token saved. Change it? (y/N): `);
317
+ if (changeToken.toLowerCase() === "y") {
318
+ const tokenInput = await question(rl, "New auth token: ");
319
+ if (tokenInput)
320
+ authToken = tokenInput;
321
+ }
322
+ }
323
+ else {
324
+ console.log(" To link this agent to your account:");
325
+ console.log(" 1. Sign in at onsignet.com/dashboard");
326
+ console.log(' 2. Click "Copy token" in the setup section');
327
+ console.log(" 3. Paste it below\n");
328
+ const tokenInput = await question(rl, "Auth token (or press Enter to skip): ");
251
329
  if (tokenInput)
252
330
  authToken = tokenInput;
253
331
  }
254
- const name = await question(rl, "Agent name (e.g. My Research Assistant): ") || "My Agent";
255
- const description = await question(rl, "Short description (optional): ");
332
+ const existing = await getExistingProfile();
333
+ const defaultName = existing?.name ?? "My Agent";
334
+ if (existing?.name) {
335
+ console.log(" Updating existing directory profile. Press Enter to keep current values.\n");
336
+ }
337
+ const namePrompt = existing?.name
338
+ ? `Agent name [${existing.name}] (press Enter to keep): `
339
+ : "Agent name (e.g. My Research Assistant): ";
340
+ const nameInput = await question(rl, namePrompt);
341
+ const name = nameInput || defaultName;
342
+ const descPrompt = existing?.description != null && existing.description !== ""
343
+ ? `Short description [${existing.description}] (press Enter to keep): `
344
+ : "Short description (optional): ";
345
+ const descriptionInput = await question(rl, descPrompt);
346
+ const description = descriptionInput !== "" ? descriptionInput : (existing?.description ?? "");
256
347
  const domainsInput = await question(rl, "Capability domains, comma-separated (e.g. research, scheduling) (optional): ");
257
348
  const capabilities = domainsInput
258
349
  ? domainsInput.split(",").map((d) => ({ domain: d.trim() })).filter((c) => c.domain.length > 0)
259
350
  : undefined;
260
351
  // Framework selection if not provided via flag
261
352
  if (!framework) {
262
- const frameworkInput = await question(rl, "Framework (openclaw / mcp / python / rest) [press Enter to auto-detect]: ");
353
+ const frameworkDefault = existing?.framework ? ` [${existing.framework}]` : "";
354
+ const frameworkInput = await question(rl, `Framework (openclaw / mcp / python / rest)${frameworkDefault} [press Enter to auto-detect]: `);
263
355
  if (frameworkInput && ["openclaw", "mcp", "python", "rest"].includes(frameworkInput)) {
264
356
  framework = frameworkInput;
265
357
  }
358
+ else if (existing?.framework && ["openclaw", "mcp", "python", "rest"].includes(existing.framework)) {
359
+ framework = existing.framework;
360
+ }
361
+ else {
362
+ const { detectFramework } = await import("./detect-framework.js");
363
+ const detected = detectFramework();
364
+ if (detected !== "unknown") {
365
+ framework = detected;
366
+ console.log(` Auto-detected framework: ${detected}`);
367
+ }
368
+ }
266
369
  }
267
370
  rl.close();
268
371
  console.log("\nRegistering with the directory...");
@@ -356,12 +459,24 @@ async function main() {
356
459
  await cmdSetupOpenclaw();
357
460
  return;
358
461
  case "serve-mcp": {
359
- const { execSync: exec } = await import("child_process");
462
+ let mcpPath = join(__dirname, "..", "..", "adapters", "mcp", "dist", "index.js");
463
+ if (!existsSync(mcpPath)) {
464
+ try {
465
+ mcpPath = require.resolve("@signet/mcp-server");
466
+ }
467
+ catch {
468
+ try {
469
+ mcpPath = require.resolve("@onsignet/mcp-server");
470
+ }
471
+ catch { /* use default */ }
472
+ }
473
+ }
360
474
  try {
361
- exec("node adapters/mcp/dist/index.js", { stdio: "inherit", cwd: join(__dirname, "..", "..") });
475
+ const child = spawn(process.execPath, [mcpPath], { stdio: "inherit", env: process.env });
476
+ child.on("exit", (code) => process.exit(code ?? 1));
362
477
  }
363
478
  catch {
364
- console.error("Failed to start MCP server. Build it first: cd adapters/mcp && npm run build");
479
+ console.error(`Failed to start MCP server at ${mcpPath}. Build it first: cd adapters/mcp && npm run build`);
365
480
  }
366
481
  return;
367
482
  }
package/dist/setup-mcp.js CHANGED
@@ -2,9 +2,28 @@
2
2
  * `signet setup-mcp` — auto-configure MCP hosts to use Signet tools.
3
3
  */
4
4
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
5
- import { join, resolve } from "path";
5
+ import { join, resolve, dirname } from "path";
6
+ import { fileURLToPath } from "url";
7
+ import { createRequire } from "module";
8
+ import { homedir } from "os";
6
9
  import { detectMcpHosts } from "./detect-framework.js";
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+ const require = createRequire(import.meta.url);
7
13
  const DAEMON_URL = process.env.SIGNET_DAEMON_URL ?? "http://127.0.0.1:8766";
14
+ const DATA_DIR = process.env.SIGNET_DATA_DIR ?? join(homedir(), ".Signet");
15
+ function getDaemonAuthHeaders() {
16
+ const tokenPath = join(DATA_DIR, "api-token");
17
+ try {
18
+ if (existsSync(tokenPath)) {
19
+ const token = readFileSync(tokenPath, "utf8").trim();
20
+ if (token)
21
+ return { Authorization: `Bearer ${token}` };
22
+ }
23
+ }
24
+ catch { /* ignore */ }
25
+ return {};
26
+ }
8
27
  function findMcpServerPath() {
9
28
  const candidates = [
10
29
  join(__dirname, "..", "..", "adapters", "mcp", "dist", "index.js"),
@@ -15,16 +34,28 @@ function findMcpServerPath() {
15
34
  if (existsSync(resolved))
16
35
  return resolved;
17
36
  }
18
- // Fall back: try require resolution
19
37
  try {
20
- const path = require.resolve("@onsignet/mcp-server");
21
- return path;
38
+ return require.resolve("@signet/mcp-server");
22
39
  }
23
- catch {
24
- // Assume it's in the standard monorepo location relative to CLI
40
+ catch { /* not installed */ }
41
+ try {
42
+ return require.resolve("@onsignet/mcp-server");
25
43
  }
44
+ catch { /* not installed */ }
26
45
  return resolve(join(__dirname, "..", "..", "adapters", "mcp", "dist", "index.js"));
27
46
  }
47
+ function getApiTokenForEnv() {
48
+ if (process.env.SIGNET_API_TOKEN)
49
+ return process.env.SIGNET_API_TOKEN;
50
+ const tokenPath = join(DATA_DIR, "api-token");
51
+ try {
52
+ if (existsSync(tokenPath)) {
53
+ return readFileSync(tokenPath, "utf8").trim();
54
+ }
55
+ }
56
+ catch { /* ignore */ }
57
+ return "";
58
+ }
28
59
  function addToMcpConfig(configPath, serverPath) {
29
60
  let config = {};
30
61
  if (existsSync(configPath)) {
@@ -32,17 +63,19 @@ function addToMcpConfig(configPath, serverPath) {
32
63
  config = JSON.parse(readFileSync(configPath, "utf8"));
33
64
  }
34
65
  catch {
35
- config = {};
66
+ console.error(` Error: ${configPath} contains invalid JSON. Please fix or delete it before running setup-mcp.`);
67
+ return false;
36
68
  }
37
69
  }
38
70
  const servers = (config.mcpServers ?? {});
39
71
  if (servers.signet) {
40
- return false; // Already configured
72
+ return false;
41
73
  }
74
+ const apiToken = getApiTokenForEnv();
42
75
  servers.signet = {
43
76
  command: "node",
44
77
  args: [serverPath],
45
- env: {},
78
+ env: apiToken ? { SIGNET_API_TOKEN: apiToken } : {},
46
79
  };
47
80
  config.mcpServers = servers;
48
81
  const dir = configPath.replace(/[/\\][^/\\]+$/, "");
@@ -53,11 +86,13 @@ function addToMcpConfig(configPath, serverPath) {
53
86
  }
54
87
  export async function cmdSetupMcp() {
55
88
  console.log("Signet MCP Setup\n");
56
- // 1. Check daemon
57
89
  try {
58
- const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, { signal: AbortSignal.timeout(5000) });
90
+ const res = await fetch(`${DAEMON_URL.replace(/\/$/, "")}/status`, {
91
+ signal: AbortSignal.timeout(5000),
92
+ headers: getDaemonAuthHeaders(),
93
+ });
59
94
  if (!res.ok) {
60
- console.error(`Daemon returned HTTP ${res.status}. Start the daemon first: npx signet start`);
95
+ console.error(`Daemon returned HTTP ${res.status}. Start the daemon first: npx signet-agent start`);
61
96
  process.exit(1);
62
97
  }
63
98
  const data = (await res.json());
@@ -67,16 +102,14 @@ export async function cmdSetupMcp() {
67
102
  }
68
103
  }
69
104
  catch {
70
- console.error(`Cannot reach daemon at ${DAEMON_URL}.\nStart it first: npx signet start`);
105
+ console.error(`Cannot reach daemon at ${DAEMON_URL}.\nStart it first: npx signet-agent start`);
71
106
  process.exit(1);
72
107
  }
73
- // 2. Find MCP server binary
74
108
  const serverPath = findMcpServerPath();
75
109
  console.log(` MCP server: ${serverPath}`);
76
110
  if (!existsSync(serverPath)) {
77
111
  console.warn(` Warning: MCP server not found at ${serverPath}. Build it first: cd adapters/mcp && npm run build`);
78
112
  }
79
- // 3. Detect and configure MCP hosts
80
113
  const hosts = detectMcpHosts();
81
114
  const detected = hosts.filter((h) => {
82
115
  const dir = h.configPath.replace(/[/\\][^/\\]+$/, "");
@@ -84,7 +117,7 @@ export async function cmdSetupMcp() {
84
117
  });
85
118
  if (detected.length === 0) {
86
119
  console.log("\n No MCP-compatible hosts detected (Claude Code, Cursor, Windsurf, Cline).");
87
- console.log(" Install one, then run `npx signet setup-mcp` again.");
120
+ console.log(" Install one, then run `npx signet-agent setup-mcp` again.");
88
121
  console.log("\n Manual configuration:");
89
122
  console.log(` Add this to your MCP config file:`);
90
123
  console.log(` {`);
@@ -102,11 +135,11 @@ export async function cmdSetupMcp() {
102
135
  for (const host of detected) {
103
136
  const added = addToMcpConfig(host.configPath, serverPath);
104
137
  if (added) {
105
- console.log(` ${host.name} — configured (${host.configPath})`);
138
+ console.log(` + ${host.name} — configured (${host.configPath})`);
106
139
  configured++;
107
140
  }
108
141
  else {
109
- console.log(` · ${host.name} — already configured`);
142
+ console.log(` . ${host.name} — already configured`);
110
143
  }
111
144
  }
112
145
  console.log();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "signet-agent",
3
- "version": "0.1.4",
4
- "description": "Signet CLI register your agent on the Signet directory",
3
+ "version": "0.1.6",
4
+ "description": "CLI for the Signet agent network. Register your AI agent on onsignet.com, connect to the relay, and get a live public profile — in one command.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "files": [
@@ -17,7 +17,7 @@
17
17
  "init": "node dist/index.js"
18
18
  },
19
19
  "dependencies": {
20
- "@onsignet/daemon": "0.1.3"
20
+ "@onsignet/daemon": "^0.1.3"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^20.10.0",
@@ -25,5 +25,29 @@
25
25
  },
26
26
  "engines": {
27
27
  "node": ">=18.0.0"
28
- }
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/camdavissignet/Signet.git",
32
+ "directory": "cli"
33
+ },
34
+ "homepage": "https://onsignet.com",
35
+ "bugs": {
36
+ "url": "https://github.com/camdavissignet/Signet/issues"
37
+ },
38
+ "keywords": [
39
+ "signet",
40
+ "ai-agents",
41
+ "agent-directory",
42
+ "agent-identity",
43
+ "agent-communication",
44
+ "mcp",
45
+ "model-context-protocol",
46
+ "langchain",
47
+ "crewai",
48
+ "autogen",
49
+ "openclaw",
50
+ "daemon",
51
+ "cli"
52
+ ]
29
53
  }