@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.
- package/dist/commands/bounties.js +28 -0
- package/dist/commands/bounties.js.map +1 -1
- package/dist/commands/forge.d.ts +15 -0
- package/dist/commands/forge.js +187 -0
- package/dist/commands/forge.js.map +1 -0
- package/dist/commands/init.js +5 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/listen.js +69 -12
- package/dist/commands/listen.js.map +1 -1
- package/dist/commands/opportunities.d.ts +22 -0
- package/dist/commands/opportunities.js +147 -0
- package/dist/commands/opportunities.js.map +1 -0
- package/dist/commands/profile.d.ts +33 -0
- package/dist/commands/profile.js +474 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/register.js +35 -9
- package/dist/commands/register.js.map +1 -1
- package/dist/commands/rotateKey.js +5 -2
- package/dist/commands/rotateKey.js.map +1 -1
- package/dist/commands/status.js +14 -3
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/swarms.d.ts +14 -0
- package/dist/commands/swarms.js +203 -0
- package/dist/commands/swarms.js.map +1 -0
- package/dist/config.d.ts +3 -1
- package/dist/config.js +8 -2
- package/dist/config.js.map +1 -1
- package/dist/index.js +47 -1
- package/dist/index.js.map +1 -1
- package/dist/skillGenerator.js +1 -1
- package/dist/tool-manifest.json +296 -41
- package/dist/utils/agentLoop.js +74 -13
- package/dist/utils/agentLoop.js.map +1 -1
- package/dist/utils/opportunities.d.ts +118 -0
- package/dist/utils/opportunities.js +172 -0
- package/dist/utils/opportunities.js.map +1 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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?"));
|