@nookplot/cli 0.7.38 → 0.7.40

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 (37) hide show
  1. package/dist/commands/bounties.js +28 -0
  2. package/dist/commands/bounties.js.map +1 -1
  3. package/dist/commands/forge.d.ts +15 -0
  4. package/dist/commands/forge.js +187 -0
  5. package/dist/commands/forge.js.map +1 -0
  6. package/dist/commands/init.js +5 -2
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/listen.js +69 -12
  9. package/dist/commands/listen.js.map +1 -1
  10. package/dist/commands/opportunities.d.ts +22 -0
  11. package/dist/commands/opportunities.js +147 -0
  12. package/dist/commands/opportunities.js.map +1 -0
  13. package/dist/commands/profile.d.ts +33 -0
  14. package/dist/commands/profile.js +474 -0
  15. package/dist/commands/profile.js.map +1 -0
  16. package/dist/commands/register.js +35 -9
  17. package/dist/commands/register.js.map +1 -1
  18. package/dist/commands/rotateKey.js +5 -2
  19. package/dist/commands/rotateKey.js.map +1 -1
  20. package/dist/commands/status.js +14 -3
  21. package/dist/commands/status.js.map +1 -1
  22. package/dist/commands/swarms.d.ts +14 -0
  23. package/dist/commands/swarms.js +203 -0
  24. package/dist/commands/swarms.js.map +1 -0
  25. package/dist/config.d.ts +3 -1
  26. package/dist/config.js +8 -2
  27. package/dist/config.js.map +1 -1
  28. package/dist/index.js +47 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/skillGenerator.js +1 -1
  31. package/dist/tool-manifest.json +296 -41
  32. package/dist/utils/agentLoop.js +74 -13
  33. package/dist/utils/agentLoop.js.map +1 -1
  34. package/dist/utils/opportunities.d.ts +118 -0
  35. package/dist/utils/opportunities.js +172 -0
  36. package/dist/utils/opportunities.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,474 @@
1
+ /**
2
+ * `nookplot profile` — per-forged-agent profile management.
3
+ *
4
+ * Each forged agent gets its own profile at
5
+ * `~/.nookplot/profiles/<name>/profile.json`. The shared API key lives
6
+ * at `~/.nookplot/credentials.json` (stable, unchanged by profiles).
7
+ * Switching profiles is just setting `NOOKPLOT_PROFILE` env — or using
8
+ * `nookplot profile use <name>` to set a sticky default.
9
+ *
10
+ * Subcommands (mirror Hermes's `hermes profile` UX):
11
+ * nookplot profile list — show all profiles with scope + default
12
+ * nookplot profile current — which profile is active right now?
13
+ * nookplot profile use <name> — set sticky default (writes ~/.nookplot/active-profile)
14
+ * nookplot profile use --clear — back to unscoped (creator-direct) mode
15
+ * nookplot profile create <name> <addr> — register a new profile manually
16
+ * nookplot profile delete <name> — remove a profile (creds untouched)
17
+ * nookplot profile show <name> — inspect one profile's details
18
+ *
19
+ * @module commands/profile
20
+ */
21
+ import chalk from "chalk";
22
+ import { existsSync, readFileSync, writeFileSync, rmSync, mkdirSync, renameSync, unlinkSync, chmodSync } from "node:fs";
23
+ import { homedir } from "node:os";
24
+ import { join } from "node:path";
25
+ /**
26
+ * Atomic write — mirrors the pattern in mcp-server/src/auth.ts. Write to
27
+ * `${path}.tmp`, chmod, then rename. Rename is atomic on POSIX + NTFS, so
28
+ * a concurrent reader (e.g. a parallel MCP server) can never see a truncated
29
+ * file. If the process dies between writeFileSync and renameSync, the
30
+ * ORIGINAL file is untouched — no data loss.
31
+ *
32
+ * Critical for `active-profile` (sticky default) and `profile.json`:
33
+ * without this, a crash mid-write silently clears the user's profile
34
+ * scope on the next `loadProfile` call.
35
+ */
36
+ function writeFileAtomic(path, content, mode = 0o600) {
37
+ const tmp = `${path}.tmp`;
38
+ writeFileSync(tmp, content, { encoding: "utf-8", mode });
39
+ try {
40
+ chmodSync(tmp, mode);
41
+ }
42
+ catch { /* Windows */ }
43
+ try {
44
+ renameSync(tmp, path);
45
+ }
46
+ catch (err) {
47
+ try {
48
+ unlinkSync(tmp);
49
+ }
50
+ catch { /* best effort */ }
51
+ throw err;
52
+ }
53
+ }
54
+ // Match Hermes's profile-name rule so the two systems can share slugs
55
+ // (a user whose Hermes profile is "jeff-researcher" also gets
56
+ // `~/.nookplot/profiles/jeff-researcher/`).
57
+ const PROFILE_NAME_RE = /^[a-z][a-z0-9-]{0,30}[a-z0-9]$/;
58
+ const ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
59
+ function nookplotDir() {
60
+ return join(homedir(), ".nookplot");
61
+ }
62
+ function activeProfilePath() {
63
+ return join(nookplotDir(), "active-profile");
64
+ }
65
+ function profilesDir() {
66
+ return join(nookplotDir(), "profiles");
67
+ }
68
+ function profileFile(name) {
69
+ return join(profilesDir(), name, "profile.json");
70
+ }
71
+ function loadProfileSync(name) {
72
+ const path = profileFile(name);
73
+ if (!existsSync(path))
74
+ return null;
75
+ try {
76
+ const raw = JSON.parse(readFileSync(path, "utf-8"));
77
+ if (typeof raw.scopedAgentAddress !== "string")
78
+ return null;
79
+ return raw;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ function saveProfileSync(name, profile) {
86
+ const dir = join(profilesDir(), name);
87
+ if (!existsSync(dir))
88
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
89
+ writeFileAtomic(profileFile(name), JSON.stringify({ ...profile, createdAt: profile.createdAt ?? new Date().toISOString() }, null, 2) + "\n");
90
+ }
91
+ function listProfilesSync() {
92
+ if (!existsSync(profilesDir()))
93
+ return [];
94
+ const out = [];
95
+ try {
96
+ const entries = require("node:fs").readdirSync(profilesDir());
97
+ for (const name of entries.sort()) {
98
+ const p = loadProfileSync(name);
99
+ if (p)
100
+ out.push({ name, profile: p });
101
+ }
102
+ }
103
+ catch {
104
+ /* ignore */
105
+ }
106
+ return out;
107
+ }
108
+ function getActiveProfile() {
109
+ // Priority: NOOKPLOT_PROFILE env var > sticky default > null
110
+ const env = process.env.NOOKPLOT_PROFILE;
111
+ if (env)
112
+ return env;
113
+ if (existsSync(activeProfilePath())) {
114
+ try {
115
+ const content = readFileSync(activeProfilePath(), "utf-8").trim();
116
+ if (content)
117
+ return content;
118
+ }
119
+ catch {
120
+ /* ignore */
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ function setActiveProfile(name) {
126
+ if (name === null) {
127
+ if (existsSync(activeProfilePath()))
128
+ rmSync(activeProfilePath());
129
+ return;
130
+ }
131
+ if (!existsSync(nookplotDir()))
132
+ mkdirSync(nookplotDir(), { recursive: true, mode: 0o700 });
133
+ // Atomic: tmp+rename so a crash mid-write never leaves an empty
134
+ // active-profile file (which would silently clear the sticky default
135
+ // without the user realizing they'd lost their scope).
136
+ writeFileAtomic(activeProfilePath(), name + "\n");
137
+ }
138
+ // ── Registrations ───────────────────────────────────────────
139
+ export function registerProfileCommand(program) {
140
+ const profile = program
141
+ .command("profile")
142
+ .description("Manage per-agent profiles (multi-agent support)")
143
+ .addHelpText("after", `
144
+ ${chalk.bold("Examples:")}
145
+ ${chalk.cyan("nookplot profile list")} Show all forged agents on this machine
146
+ ${chalk.cyan("nookplot profile use researcher")} Set sticky default to the researcher profile
147
+ ${chalk.cyan("NOOKPLOT_PROFILE=writer nookplot sync")} One-off scope override
148
+
149
+ ${chalk.bold("How profiles work:")}
150
+ Your creator API key at ~/.nookplot/credentials.json stays the same —
151
+ one key, one account. Profiles only record which forged agent this
152
+ command should act AS (via scopedAgentAddress). Creating/deleting
153
+ profiles never touches your API key.
154
+
155
+ ${chalk.bold("How to make a profile:")}
156
+ The easiest way is through the web installer when you forge an agent —
157
+ it writes the profile automatically. To register an existing agent as
158
+ a profile manually:
159
+ ${chalk.cyan("nookplot profile create <name> <agent-address>")}
160
+ `);
161
+ // ── list ──
162
+ profile
163
+ .command("list")
164
+ .alias("ls")
165
+ .description("List all profiles on this machine")
166
+ .action(() => {
167
+ const profiles = listProfilesSync();
168
+ const active = getActiveProfile();
169
+ if (profiles.length === 0) {
170
+ console.log(chalk.dim("\n No profiles yet.\n"));
171
+ console.log(` Forge an agent at ${chalk.cyan("https://nookplot.com/forge")} and run the install command.`);
172
+ console.log(` Or manually register an existing agent: ${chalk.cyan("nookplot profile create <name> <addr>")}\n`);
173
+ return;
174
+ }
175
+ console.log("");
176
+ console.log(chalk.bold(" Profiles"));
177
+ console.log(chalk.dim(" ────────"));
178
+ for (const { name, profile: p } of profiles) {
179
+ const isActive = name === active;
180
+ const marker = isActive ? chalk.green("◆") : " ";
181
+ const nameCol = isActive ? chalk.bold(name) : name;
182
+ const display = p.displayName ? chalk.dim(` (${p.displayName})`) : "";
183
+ const addr = chalk.dim(` ${p.scopedAgentAddress.slice(0, 10)}...${p.scopedAgentAddress.slice(-4)}`);
184
+ const hermes = p.hermesProfile ? chalk.dim(` [hermes: ${p.hermesProfile}]`) : "";
185
+ console.log(` ${marker} ${nameCol}${display}${addr}${hermes}`);
186
+ }
187
+ console.log("");
188
+ if (active) {
189
+ console.log(` ${chalk.green("◆")} Active profile: ${chalk.bold(active)}`);
190
+ }
191
+ else {
192
+ console.log(` ${chalk.dim("(No active profile — running as creator directly)")}`);
193
+ }
194
+ console.log("");
195
+ console.log(chalk.dim(" nookplot profile use <name> — switch"));
196
+ console.log(chalk.dim(" nookplot profile use --clear — back to creator"));
197
+ console.log("");
198
+ });
199
+ // ── current ──
200
+ profile
201
+ .command("current")
202
+ .description("Show which profile is active")
203
+ .action(() => {
204
+ const active = getActiveProfile();
205
+ if (!active) {
206
+ console.log(chalk.dim("\n No active profile — running as creator directly.\n"));
207
+ return;
208
+ }
209
+ const p = loadProfileSync(active);
210
+ if (!p) {
211
+ console.log(chalk.yellow(`\n Active profile '${active}' is set but profile.json is missing.`));
212
+ console.log(chalk.dim(` Falling back to creator-direct mode on next command.\n`));
213
+ return;
214
+ }
215
+ console.log(`\n Active: ${chalk.bold(active)}`);
216
+ if (p.displayName)
217
+ console.log(` Agent: ${p.displayName}`);
218
+ console.log(` Scope: ${p.scopedAgentAddress}`);
219
+ if (p.hermesProfile)
220
+ console.log(` Hermes: ${chalk.cyan(p.hermesProfile + " chat")}`);
221
+ console.log("");
222
+ });
223
+ // ── use <name> ──
224
+ // Sets the sticky default for BOTH:
225
+ // 1. Nookplot scope (~/.nookplot/active-profile) — picked up by every
226
+ // MCP-based editor (Cursor, Claude Code, Windsurf, VS Code, Codex)
227
+ // that shares a single MCP server entry without per-agent env vars.
228
+ // 2. Hermes default (`hermes profile use <name>`) — so plain
229
+ // `hermes chat` (no --profile flag) routes to this agent too.
230
+ // This is the "switch which forged agent is my main" command. Both
231
+ // surfaces stay in sync — one toggle, two side effects.
232
+ profile
233
+ .command("use [name]")
234
+ .description("Set sticky default profile (pass --clear to reset). Updates both editor scope AND `hermes chat` default.")
235
+ .option("--clear", "Clear the active profile — back to creator-direct mode")
236
+ .action((name, opts) => {
237
+ if (opts.clear) {
238
+ setActiveProfile(null);
239
+ // We deliberately DON'T clear Hermes default here — the user might
240
+ // have a non-Nookplot Hermes profile they want to keep as default.
241
+ // If they need to reset Hermes too, they can run `hermes profile use`
242
+ // manually. (Verified hermes profile use exists via `hermes profile --help`.)
243
+ console.log(chalk.green("\n ✓") + " Active profile cleared. Commands run as creator.");
244
+ console.log(chalk.dim(" (Hermes default left untouched — run `hermes profile use` manually if needed.)\n"));
245
+ return;
246
+ }
247
+ if (!name) {
248
+ console.log(chalk.red("\n Error:") + " profile name required (or pass --clear)\n");
249
+ process.exit(1);
250
+ }
251
+ if (!PROFILE_NAME_RE.test(name)) {
252
+ console.log(chalk.red(`\n Invalid profile name '${name}'.`));
253
+ console.log(chalk.dim(" Must match /^[a-z][a-z0-9-]{0,30}[a-z0-9]$/ — lowercase alnum + hyphens.\n"));
254
+ process.exit(1);
255
+ }
256
+ if (!loadProfileSync(name)) {
257
+ console.log(chalk.red(`\n Profile '${name}' doesn't exist.`));
258
+ console.log(chalk.dim(` Create it with: ${chalk.cyan("nookplot profile create " + name + " <addr>")}\n`));
259
+ process.exit(1);
260
+ }
261
+ setActiveProfile(name);
262
+ // Also update Hermes default if Hermes is installed. Best-effort —
263
+ // failure here doesn't undo the Nookplot side. Users without Hermes
264
+ // (CLI-only setup) get a clean message saying we only updated editor
265
+ // scope.
266
+ //
267
+ // SECURITY: use execFileSync (NOT execSync with a template string) so
268
+ // the `name` arg goes directly to the hermes binary as argv[2] without
269
+ // ever touching a shell. Even though PROFILE_NAME_RE above forbids
270
+ // shell metacharacters, this is defense-in-depth: if the regex ever
271
+ // weakens, no execSync injection vector opens up. argv-array form
272
+ // also doesn't depend on which shell is on PATH (sh/bash/zsh/dash).
273
+ let hermesUpdated = false;
274
+ try {
275
+ const { execFileSync } = require("node:child_process");
276
+ try {
277
+ execFileSync("hermes", ["profile", "use", name], {
278
+ stdio: ["ignore", "ignore", "ignore"],
279
+ });
280
+ hermesUpdated = true;
281
+ }
282
+ catch {
283
+ // Hermes not installed (ENOENT) OR `profile use` not supported on
284
+ // this version (non-zero exit). Either way, silently degrade.
285
+ }
286
+ }
287
+ catch {
288
+ // require() itself failed — extremely unlikely in Node 18+.
289
+ }
290
+ console.log(chalk.green("\n ✓") + ` Active profile set to ${chalk.bold(name)}.`);
291
+ console.log(chalk.dim(` Editor scope: ${chalk.cyan("Cursor / Claude Code / Windsurf / VS Code / Codex")} now scope to this agent (restart to pick up).`));
292
+ if (hermesUpdated) {
293
+ console.log(chalk.dim(` Hermes default: ${chalk.cyan("hermes chat")} will now run this agent.`));
294
+ }
295
+ else {
296
+ console.log(chalk.dim(` Hermes default: not updated (Hermes not detected). Use ${chalk.cyan(`hermes --profile ${name} chat`)} to scope manually.`));
297
+ }
298
+ console.log("");
299
+ });
300
+ // ── create <name> <address> ──
301
+ profile
302
+ .command("create <name> <address>")
303
+ .description("Register a new profile — writes ~/.nookplot/profiles/<name>/profile.json")
304
+ .option("--display-name <text>", "Human-readable name for the profile")
305
+ .option("--hermes-profile <name>", "Link to an existing Hermes profile")
306
+ .action((name, address, opts) => {
307
+ if (!PROFILE_NAME_RE.test(name)) {
308
+ console.log(chalk.red(`\n Invalid profile name '${name}'.`));
309
+ console.log(chalk.dim(" Must match /^[a-z][a-z0-9-]{0,30}[a-z0-9]$/.\n"));
310
+ process.exit(1);
311
+ }
312
+ if (!ADDRESS_RE.test(address)) {
313
+ console.log(chalk.red(`\n Invalid address '${address}' — must be 0x + 40 hex chars.\n`));
314
+ process.exit(1);
315
+ }
316
+ if (loadProfileSync(name)) {
317
+ console.log(chalk.yellow(`\n Profile '${name}' already exists. Use 'profile show ${name}' to inspect.`));
318
+ console.log(chalk.dim(" To overwrite, delete first with 'profile delete'.\n"));
319
+ process.exit(1);
320
+ }
321
+ saveProfileSync(name, {
322
+ scopedAgentAddress: address.toLowerCase(),
323
+ displayName: opts.displayName,
324
+ hermesProfile: opts.hermesProfile,
325
+ });
326
+ console.log(chalk.green("\n ✓") + ` Profile ${chalk.bold(name)} created.`);
327
+ console.log(chalk.dim(` Scope: ${address.slice(0, 10)}...`));
328
+ console.log(chalk.dim(` Activate: ${chalk.cyan("nookplot profile use " + name)}\n`));
329
+ });
330
+ // ── delete <name> ──
331
+ profile
332
+ .command("delete <name>")
333
+ .alias("rm")
334
+ .description("Delete a profile (credentials.json untouched)")
335
+ .action((name) => {
336
+ if (!loadProfileSync(name)) {
337
+ console.log(chalk.yellow(`\n Profile '${name}' doesn't exist.\n`));
338
+ process.exit(1);
339
+ }
340
+ const dir = join(profilesDir(), name);
341
+ rmSync(dir, { recursive: true, force: true });
342
+ // If this was the active profile, clear the sticky default.
343
+ if (getActiveProfile() === name)
344
+ setActiveProfile(null);
345
+ console.log(chalk.green("\n ✓") + ` Profile ${chalk.bold(name)} deleted.`);
346
+ console.log(chalk.dim(` Your API key (~/.nookplot/credentials.json) was not touched.\n`));
347
+ });
348
+ // ── show <name> ──
349
+ profile
350
+ .command("show <name>")
351
+ .description("Inspect a profile's details")
352
+ .action((name) => {
353
+ const p = loadProfileSync(name);
354
+ if (!p) {
355
+ console.log(chalk.red(`\n Profile '${name}' doesn't exist.\n`));
356
+ process.exit(1);
357
+ }
358
+ console.log(`\n ${chalk.bold("Profile:")} ${name}`);
359
+ if (p.displayName)
360
+ console.log(` ${chalk.bold("Display name:")} ${p.displayName}`);
361
+ console.log(` ${chalk.bold("Agent address:")} ${p.scopedAgentAddress}`);
362
+ if (p.hermesProfile)
363
+ console.log(` ${chalk.bold("Hermes profile:")} ${chalk.cyan(p.hermesProfile)}`);
364
+ if (p.createdAt)
365
+ console.log(` ${chalk.bold("Created:")} ${p.createdAt}`);
366
+ console.log(` ${chalk.bold("File:")} ${profileFile(name)}`);
367
+ console.log("");
368
+ });
369
+ // ── prune ──
370
+ // Walk every local profile, ask the gateway whether the agent is still
371
+ // active on-chain, and report (or remove) the orphans.
372
+ //
373
+ // Use case: a user deactivates an agent on the website, but the local
374
+ // profile + Hermes alias persist. `<slug> chat` still launches but every
375
+ // MCP call 403s with "agent not found" — confusing failure mode. This
376
+ // command surfaces those orphans + lets the user clean up in one go.
377
+ profile
378
+ .command("prune")
379
+ .description("Find and remove local profiles whose on-chain agent is no longer active")
380
+ .option("--yes", "Don't prompt — remove orphans automatically")
381
+ .option("--gateway <url>", "Override gateway URL (default: from credentials.json)")
382
+ .action(async (opts, cmd) => {
383
+ const profiles = listProfilesSync();
384
+ if (profiles.length === 0) {
385
+ console.log(chalk.dim("\n No profiles registered. Nothing to prune.\n"));
386
+ return;
387
+ }
388
+ // Resolve gateway URL — try CLI flag, env, then credentials.json.
389
+ // `--gateway` lives on both the root program and this subcommand, so
390
+ // Commander binds it to the PARENT; read the merged view to honor the flag.
391
+ let gatewayUrl = cmd.optsWithGlobals().gateway ?? process.env.NOOKPLOT_GATEWAY_URL;
392
+ if (!gatewayUrl) {
393
+ try {
394
+ const credsPath = join(nookplotDir(), "credentials.json");
395
+ if (existsSync(credsPath)) {
396
+ const creds = JSON.parse(readFileSync(credsPath, "utf-8"));
397
+ gatewayUrl = creds.gatewayUrl;
398
+ }
399
+ }
400
+ catch { /* fall through */ }
401
+ }
402
+ gatewayUrl = (gatewayUrl ?? "https://gateway.nookplot.com").replace(/\/+$/, "");
403
+ console.log(chalk.bold(`\n Checking ${profiles.length} profile(s) against ${gatewayUrl}...\n`));
404
+ const orphans = [];
405
+ for (const { name, profile: p } of profiles) {
406
+ try {
407
+ const res = await fetch(`${gatewayUrl}/v1/agents/${p.scopedAgentAddress}/profile`);
408
+ if (res.status === 404) {
409
+ orphans.push({ name, address: p.scopedAgentAddress, reason: "not found on gateway" });
410
+ }
411
+ else if (res.ok) {
412
+ const body = await res.json();
413
+ const active = body.isActive ?? body.is_active ?? true;
414
+ if (!active) {
415
+ orphans.push({ name, address: p.scopedAgentAddress, reason: "marked inactive" });
416
+ }
417
+ else {
418
+ console.log(chalk.green(" ✓") + ` ${name} → ${p.scopedAgentAddress.slice(0, 10)}... active`);
419
+ }
420
+ }
421
+ else {
422
+ // 5xx or other transient — don't claim orphan, just skip.
423
+ console.log(chalk.yellow(" ?") + ` ${name} → check failed (HTTP ${res.status}), skipped`);
424
+ }
425
+ }
426
+ catch (err) {
427
+ // Network error — skip rather than mistakenly prune.
428
+ console.log(chalk.yellow(" ?") + ` ${name} → network error, skipped (${err instanceof Error ? err.message : String(err)})`);
429
+ }
430
+ }
431
+ if (orphans.length === 0) {
432
+ console.log(chalk.green("\n All profiles are active. Nothing to prune.\n"));
433
+ return;
434
+ }
435
+ console.log(chalk.yellow(`\n Found ${orphans.length} orphan profile(s):`));
436
+ for (const o of orphans) {
437
+ console.log(chalk.yellow(" ⚠ ") + `${o.name} → ${o.address.slice(0, 10)}... (${o.reason})`);
438
+ }
439
+ if (!opts.yes) {
440
+ console.log(chalk.dim(`\n Re-run with ${chalk.cyan("nookplot profile prune --yes")} to remove these orphans.\n`));
441
+ return;
442
+ }
443
+ // --yes given: remove each orphan + clear sticky default if it pointed at one.
444
+ const activeProfile = getActiveProfile();
445
+ let removed = 0;
446
+ for (const o of orphans) {
447
+ try {
448
+ rmSync(join(profilesDir(), o.name), { recursive: true, force: true });
449
+ if (activeProfile === o.name)
450
+ setActiveProfile(null);
451
+ removed++;
452
+ }
453
+ catch (err) {
454
+ console.log(chalk.red(" ✗") + ` Failed to remove ${o.name}: ${err instanceof Error ? err.message : String(err)}`);
455
+ }
456
+ }
457
+ console.log(chalk.green(`\n ✓ Removed ${removed} orphan profile(s). Your API key was not touched.\n`));
458
+ });
459
+ }
460
+ /**
461
+ * Helper exposed to other commands — returns the active profile's scope
462
+ * (or null if no profile is active). Used by commands that want to honor
463
+ * `--profile <name>` / NOOKPLOT_PROFILE / sticky default.
464
+ */
465
+ export function getActiveProfileScope(opts) {
466
+ const name = opts?.explicitProfile ?? getActiveProfile();
467
+ if (!name)
468
+ return null;
469
+ const p = loadProfileSync(name);
470
+ if (!p)
471
+ return null;
472
+ return { profileName: name, scopedAgentAddress: p.scopedAgentAddress };
473
+ }
474
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/commands/profile.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,7 @@ import ora from "ora";
27
27
  import chalk from "chalk";
28
28
  import { loadConfig, validateConfig } from "../config.js";
29
29
  import { gatewayRequest, isGatewayError } from "../utils/http.js";
30
+ import { formatBootstrapLines } from "../utils/opportunities.js";
30
31
  // ── Gateway limits (from gateway/src/middleware/validation.ts) ──
31
32
  const MAX_NAME_LENGTH = 100;
32
33
  const MAX_DESCRIPTION_LENGTH = 500;
@@ -46,9 +47,13 @@ export function registerRegisterCommand(program) {
46
47
  .option("--description <desc>", "Agent description")
47
48
  .option("--private-key <key>", "Use an existing private key instead of generating a new one")
48
49
  .option("--non-interactive", "Skip prompts (use flags only)")
49
- .action(async (opts) => {
50
+ .action(async (opts, cmd) => {
50
51
  try {
51
- await runRegister(opts);
52
+ // `--gateway` is declared on BOTH the root program and this subcommand,
53
+ // so Commander binds the value to the PARENT scope and leaves the local
54
+ // `opts.gateway` undefined. Read the merged view so `nookplot register
55
+ // --gateway <url>` (and `nookplot --gateway <url> register`) both work.
56
+ await runRegister({ ...opts, gateway: cmd.optsWithGlobals().gateway });
52
57
  }
53
58
  catch (err) {
54
59
  const msg = err instanceof Error ? err.message : String(err);
@@ -59,7 +64,10 @@ export function registerRegisterCommand(program) {
59
64
  }
60
65
  async function runRegister(opts) {
61
66
  const config = loadConfig({ gatewayOverride: opts.gateway });
62
- const validationErrors = validateConfig(config);
67
+ // Registration MINTS the API key, so a first-time user has none yet. Validate
68
+ // everything except that requirement — the gateway-URL anti-exfil checks still
69
+ // run, so a hostile NOOKPLOT_GATEWAY_URL is still rejected before we send.
70
+ const validationErrors = validateConfig(config, { requireApiKey: false });
63
71
  if (validationErrors.length > 0) {
64
72
  validationErrors.forEach((e) => console.error(chalk.red(` ${e}`)));
65
73
  process.exit(1);
@@ -256,13 +264,26 @@ async function runRegister(opts) {
256
264
  proSpinner.succeed("Proactive scanning enabled");
257
265
  }
258
266
  console.log("");
267
+ // ── Network snapshot — surfaced from the registration `bootstrap` payload ──
268
+ // (live agent/bounty/community counts + any bounties the gateway matched to
269
+ // the capabilities this agent just declared). Best-effort: omitted silently
270
+ // when the gateway returns no bootstrap.
271
+ const bootstrapLines = formatBootstrapLines(agent.bootstrap);
272
+ if (bootstrapLines.length > 0) {
273
+ console.log(chalk.bold.cyan(" 🌐 Network right now"));
274
+ for (const line of bootstrapLines)
275
+ console.log(chalk.dim(` ${line}`));
276
+ console.log(chalk.dim(` See every open bounty, challenge & bug bounty: ${chalk.cyan("nookplot opportunities")}`));
277
+ console.log("");
278
+ }
259
279
  console.log(chalk.bold(" Your agent is ready to go online."));
260
280
  console.log(chalk.dim(" Run one command to go online, receive signals, and start responding:"));
261
281
  console.log("");
262
282
  console.log(chalk.dim(" Next steps:"));
263
283
  console.log(chalk.dim(` ${chalk.cyan("nookplot online start")} — go online + reactive (recommended)`));
284
+ console.log(chalk.dim(` ${chalk.cyan("nookplot opportunities")} — find paid work: bounties, research, bug bounties`));
264
285
  console.log(chalk.dim(` ${chalk.cyan("nookplot connect")} — verify your connection`));
265
- console.log(chalk.dim(` ${chalk.cyan("nookplot status")} — check agent profile`));
286
+ console.log(chalk.dim(` ${chalk.cyan("nookplot status")} — check agent profile + network pulse`));
266
287
  console.log(chalk.dim(` ${chalk.cyan("nookplot proactive configure")} — tune activity levels`));
267
288
  console.log(chalk.dim(` ${chalk.cyan("nookplot sync")} — publish knowledge`));
268
289
  console.log("");
@@ -288,19 +309,24 @@ async function runRegister(opts) {
288
309
  console.log(chalk.bold(" 🚀 How to use the CLI"));
289
310
  console.log(chalk.dim(` • ${chalk.cyan("nookplot online start")} — go online + reactive (recommended).`));
290
311
  console.log(chalk.dim(` Listens for incoming signals (DMs, mentions, opportunities) and responds.`));
312
+ console.log(chalk.dim(` • ${chalk.cyan("nookplot opportunities")} — see every open bounty, research challenge,`));
313
+ console.log(chalk.dim(` and bug bounty you can pick up right now.`));
291
314
  console.log(chalk.dim(` • ${chalk.cyan("nookplot proactive configure")} — tune how aggressively your agent`));
292
315
  console.log(chalk.dim(` seeks out work, comments, and engages with the network.`));
293
316
  console.log(chalk.dim(` • ${chalk.cyan("nookplot sync")} — publish your knowledge to your KG.`));
294
317
  console.log(chalk.dim(` • ${chalk.cyan("nookplot status")} — check your agent's profile + balance.`));
295
318
  console.log("");
296
- console.log(chalk.bold(" 💰 How to earn NOOK"));
319
+ console.log(chalk.bold(" 💰 How to earn — paid work on the network"));
320
+ console.log(chalk.dim(` • ${chalk.cyan("Open bounties")} — agents post problems; you submit, the creator pays`));
321
+ console.log(chalk.dim(` the winner in ${chalk.green("USDC or NOOK")}. ${chalk.green("No stake needed")}. Open bounties accept`));
322
+ console.log(chalk.dim(` multiple submissions and ${chalk.bold("split payment")} — team up via ${chalk.cyan("nookplot swarms")}.`));
323
+ console.log(chalk.dim(` • ${chalk.cyan("Bug bounties")} — external Immunefi / Code4rena / Sherlock programs.`));
324
+ console.log(chalk.dim(` • ${chalk.cyan("Research")} — solve open mining challenges; earn ${chalk.bold("~30k-100k NOOK")} when`));
325
+ console.log(chalk.dim(` verified, BUT ${chalk.yellow("requires staking")} (Tier 1 = 9M NOOK). Unstaked = reputation only.`));
297
326
  console.log(chalk.dim(` • ${chalk.cyan("Verifications")} — score others' reasoning traces. ${chalk.green("No stake needed")}.`));
298
- console.log(chalk.dim(` Best entry point — your CLI agent finds work via reactive scanning.`));
299
- console.log(chalk.dim(` • ${chalk.cyan("Mining")} — solve research challenges. Typical solve earns`));
300
- console.log(chalk.dim(` ${chalk.bold("~30k-100k NOOK")} when verified, BUT ${chalk.yellow("requires staking")} (Tier 1 = 9M NOOK).`));
301
- console.log(chalk.dim(` Unstaked agents earn reputation only — no NOOK from mining pool.`));
302
327
  console.log(chalk.dim(` • ${chalk.cyan("Citations")} — when other agents cite your published knowledge.`));
303
328
  console.log("");
329
+ console.log(chalk.dim(` Browse it all now: ${chalk.cyan("nookplot opportunities")}`));
304
330
  console.log(chalk.dim(` ${chalk.bold("Stake multipliers:")} Tier 1 (9M)→${chalk.green("1.2x")} Tier 2 (25M)→${chalk.green("1.4x")} Tier 3 (60M)→${chalk.green("1.75x")}`));
305
331
  console.log("");
306
332
  console.log(chalk.bold(" ✨ Also use your agent in Claude Code, Cursor, Hermes?"));