@nookplot/mcp 0.4.92 → 0.4.93

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 (77) hide show
  1. package/README.md +2 -2
  2. package/SKILL.md +2 -2
  3. package/dist/auth.d.ts +4 -112
  4. package/dist/auth.d.ts.map +1 -1
  5. package/dist/auth.js +19 -326
  6. package/dist/auth.js.map +1 -1
  7. package/dist/gateway.d.ts.map +1 -1
  8. package/dist/gateway.js +1 -5
  9. package/dist/gateway.js.map +1 -1
  10. package/dist/index.d.ts +1 -12
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +18 -580
  13. package/dist/index.js.map +1 -1
  14. package/dist/server.d.ts.map +1 -1
  15. package/dist/server.js +4 -2
  16. package/dist/server.js.map +1 -1
  17. package/dist/setup.d.ts +1 -28
  18. package/dist/setup.d.ts.map +1 -1
  19. package/dist/setup.js +6 -204
  20. package/dist/setup.js.map +1 -1
  21. package/dist/tools/ecosystem.d.ts +14 -0
  22. package/dist/tools/ecosystem.d.ts.map +1 -0
  23. package/dist/tools/ecosystem.js +187 -0
  24. package/dist/tools/ecosystem.js.map +1 -0
  25. package/dist/tools/forgePresets.d.ts +2 -7
  26. package/dist/tools/forgePresets.d.ts.map +1 -1
  27. package/dist/tools/forgePresets.js +3 -130
  28. package/dist/tools/forgePresets.js.map +1 -1
  29. package/dist/tools/index.d.ts.map +1 -1
  30. package/dist/tools/index.js +2 -0
  31. package/dist/tools/index.js.map +1 -1
  32. package/dist/tools/knowledgeGraph.d.ts.map +1 -1
  33. package/dist/tools/knowledgeGraph.js +2 -8
  34. package/dist/tools/knowledgeGraph.js.map +1 -1
  35. package/dist/tools/memory.d.ts.map +1 -1
  36. package/dist/tools/memory.js +33 -0
  37. package/dist/tools/memory.js.map +1 -1
  38. package/dist/tools/miningPipeline.d.ts +2 -6
  39. package/dist/tools/miningPipeline.d.ts.map +1 -1
  40. package/dist/tools/miningPipeline.js +3 -392
  41. package/dist/tools/miningPipeline.js.map +1 -1
  42. package/dist/tools/onchain.d.ts.map +1 -1
  43. package/dist/tools/onchain.js +0 -11
  44. package/dist/tools/onchain.js.map +1 -1
  45. package/dist/tools/read.d.ts.map +1 -1
  46. package/dist/tools/read.js +6 -27
  47. package/dist/tools/read.js.map +1 -1
  48. package/dist/tools/swarms.d.ts.map +1 -1
  49. package/dist/tools/swarms.js +1 -21
  50. package/dist/tools/swarms.js.map +1 -1
  51. package/package.json +4 -3
  52. package/dist/applyConfig.d.ts +0 -73
  53. package/dist/applyConfig.d.ts.map +0 -1
  54. package/dist/applyConfig.js +0 -418
  55. package/dist/applyConfig.js.map +0 -1
  56. package/dist/profileName.d.ts +0 -65
  57. package/dist/profileName.d.ts.map +0 -1
  58. package/dist/profileName.js +0 -114
  59. package/dist/profileName.js.map +0 -1
  60. package/dist/syncSessions.d.ts +0 -84
  61. package/dist/syncSessions.d.ts.map +0 -1
  62. package/dist/syncSessions.js +0 -260
  63. package/dist/syncSessions.js.map +0 -1
  64. package/dist/syncSessionsExtractor.d.ts +0 -123
  65. package/dist/syncSessionsExtractor.d.ts.map +0 -1
  66. package/dist/syncSessionsExtractor.js +0 -362
  67. package/dist/syncSessionsExtractor.js.map +0 -1
  68. package/dist/syncSessionsState.d.ts +0 -89
  69. package/dist/syncSessionsState.d.ts.map +0 -1
  70. package/dist/syncSessionsState.js +0 -145
  71. package/dist/syncSessionsState.js.map +0 -1
  72. package/skills/hermes/nookplot/DESCRIPTION.md +0 -59
  73. package/skills/hermes/nookplot/daemon/SKILL.md +0 -103
  74. package/skills/hermes/nookplot/learn/SKILL.md +0 -131
  75. package/skills/hermes/nookplot/mine/SKILL.md +0 -111
  76. package/skills/hermes/nookplot/social/SKILL.md +0 -104
  77. package/skills/hermes/nookplot/sync/SKILL.md +0 -110
@@ -1,418 +0,0 @@
1
- /**
2
- * `nookplot-mcp apply-config` — redeem + decrypt + apply a Nookplot config
3
- * bundle to the user's local Hermes installation.
4
- *
5
- * This is the final mile of the one-stop-shop installer flow:
6
- *
7
- * 1. User configured BYOK / model / messaging on the Nookplot web UI.
8
- * 2. The browser encrypted it with AES-256-GCM and a random 256-bit key,
9
- * POSTed the ciphertext to `/v1/agent-config/stage`, and got back a
10
- * one-time token.
11
- * 3. The install command exposed both as terminal env vars:
12
- * NOOKPLOT_CONFIG_TOKEN=<token>
13
- * NOOKPLOT_CONFIG_KEY=<base64url-encoded key>
14
- * 4. The installer bash script calls this command with those values.
15
- *
16
- * We then:
17
- * - Fetch the ciphertext via GET /v1/agent-config/redeem/:token. The
18
- * gateway deletes the row as it returns the payload, so replays fail.
19
- * - Decrypt locally using the key (which never left the terminal).
20
- * - For each (key, value) pair in the JSON config, run
21
- * `hermes config set KEY VALUE`. Hermes auto-routes secrets (API keys,
22
- * bot tokens) to ~/.hermes/.env and other settings to ~/.hermes/config.yaml.
23
- *
24
- * @module applyConfig
25
- */
26
- import { createDecipheriv } from "node:crypto";
27
- import { execFileSync } from "node:child_process";
28
- import { readFileSync, existsSync } from "node:fs";
29
- import { homedir } from "node:os";
30
- import { join } from "node:path";
31
- /**
32
- * Decode a base64url string (`-` `_`, no padding) to a Buffer.
33
- * Web Crypto emits base64url by default, so our browser-side encryption
34
- * produces keys in this form.
35
- */
36
- function fromBase64Url(value) {
37
- // Convert base64url → base64 by replacing URL-safe chars and
38
- // re-padding to a multiple of 4.
39
- let b64 = value.replace(/-/g, "+").replace(/_/g, "/");
40
- const pad = b64.length % 4;
41
- if (pad)
42
- b64 += "=".repeat(4 - pad);
43
- return Buffer.from(b64, "base64");
44
- }
45
- /**
46
- * Redeem the ciphertext from the gateway. The endpoint deletes the row as
47
- * it returns the payload, so replays will 404.
48
- */
49
- async function redeemCiphertext(gatewayUrl, token, fetchFn, timeoutMs) {
50
- const url = `${gatewayUrl.replace(/\/$/, "")}/v1/agent-config/redeem/${encodeURIComponent(token)}`;
51
- // AbortController gives us a hard ceiling on wait time so a hung
52
- // gateway can't freeze the installer.
53
- const controller = new AbortController();
54
- const timer = setTimeout(() => controller.abort(), timeoutMs);
55
- try {
56
- const res = await fetchFn(url, { signal: controller.signal });
57
- if (!res.ok) {
58
- const body = await res.text().catch(() => "");
59
- if (res.status === 404) {
60
- throw new Error("Config token not found, already used, or expired. " +
61
- "Regenerate the install command on your agent's Nookplot page.");
62
- }
63
- throw new Error(`Gateway returned ${res.status}: ${body.slice(0, 200)}`);
64
- }
65
- const payload = (await res.json());
66
- if (typeof payload.ciphertext !== "string" ||
67
- typeof payload.iv !== "string" ||
68
- typeof payload.authTag !== "string" ||
69
- typeof payload.agentAddress !== "string") {
70
- throw new Error("Gateway returned an unexpected payload shape.");
71
- }
72
- return payload;
73
- }
74
- finally {
75
- clearTimeout(timer);
76
- }
77
- }
78
- /**
79
- * Decrypt an AES-256-GCM ciphertext. Throws on auth-tag mismatch (i.e.
80
- * wrong key or tampered ciphertext).
81
- */
82
- function decryptBundle(stage, key) {
83
- if (key.length !== 32) {
84
- throw new Error(`AES-256 key must be 32 bytes (got ${key.length}). ` +
85
- `Check NOOKPLOT_CONFIG_KEY is the full base64url value.`);
86
- }
87
- const iv = Buffer.from(stage.iv, "base64");
88
- const authTag = Buffer.from(stage.authTag, "base64");
89
- const ciphertext = Buffer.from(stage.ciphertext, "base64");
90
- if (iv.length !== 12) {
91
- throw new Error(`Invalid IV length (${iv.length}) — expected 12 bytes.`);
92
- }
93
- if (authTag.length !== 16) {
94
- throw new Error(`Invalid auth tag length (${authTag.length}) — expected 16 bytes.`);
95
- }
96
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
97
- decipher.setAuthTag(authTag);
98
- let plaintext;
99
- try {
100
- plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
101
- }
102
- catch (err) {
103
- // Auth-tag failure → either wrong key or tampered bytes. In practice
104
- // the first is common (user pasted the wrong install command), the
105
- // second means someone was intercepting — either way, bail loud.
106
- throw new Error("Decryption failed — auth tag mismatch. " +
107
- "This usually means NOOKPLOT_CONFIG_KEY doesn't match the token " +
108
- "(regenerate the install command on your agent page).");
109
- }
110
- let parsed;
111
- try {
112
- parsed = JSON.parse(plaintext.toString("utf8"));
113
- }
114
- catch {
115
- throw new Error("Decrypted payload was not valid JSON.");
116
- }
117
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
118
- throw new Error("Decrypted payload was not a JSON object.");
119
- }
120
- return parsed;
121
- }
122
- // ---------------------------------------------------------------------------
123
- // Apply to Hermes
124
- // ---------------------------------------------------------------------------
125
- /**
126
- * Valid Hermes config key shape.
127
- *
128
- * Hermes accepts:
129
- * - Dotted lowercase keys (e.g. `model.default`, `terminal.backend`)
130
- * - SCREAMING_SNAKE_CASE (auto-routed to ~/.hermes/.env, for API keys)
131
- * - Simple `a-z0-9_` keys for top-level settings
132
- *
133
- * We gate strictly here because we're about to exec a subprocess: anything
134
- * that smells like a shell metachar gets dropped with a recorded failure
135
- * rather than quietly becoming an argv surprise.
136
- */
137
- function isValidHermesKey(key) {
138
- return /^[A-Za-z][A-Za-z0-9_.]{0,127}$/.test(key);
139
- }
140
- /**
141
- * Run `hermes config set <key> <value>` for each entry in the config.
142
- *
143
- * We skip — and record — anything whose value isn't serializable as a flat
144
- * string, as well as anything whose key fails our whitelist. The Hermes
145
- * CLI itself does the routing between config.yaml (plain settings) and
146
- * .env (API keys), so we don't have to duplicate that logic here.
147
- */
148
- function applyToHermes(config, hermesBin, execFn, profile) {
149
- let applied = 0;
150
- const failures = [];
151
- // When a profile is set, every `hermes config set` call is prefixed
152
- // with `--profile <name>` so the writes land in
153
- // ~/.hermes/profiles/<name>/config.yaml rather than the default
154
- // ~/.hermes/config.yaml. This is how multi-agent installs stay
155
- // isolated: Agent A's BYOK keys don't clobber Agent B's.
156
- const profilePrefix = profile ? ["--profile", profile] : [];
157
- for (const [key, rawValue] of Object.entries(config)) {
158
- if (!isValidHermesKey(key)) {
159
- failures.push({ key, error: "Invalid key format (must match /^[A-Za-z][A-Za-z0-9_.]*$/)" });
160
- continue;
161
- }
162
- // Flatten to string. Booleans/numbers become their textual form;
163
- // nested objects are rejected — Hermes uses dotted keys for nesting.
164
- let value;
165
- if (typeof rawValue === "string") {
166
- value = rawValue;
167
- }
168
- else if (typeof rawValue === "number" || typeof rawValue === "boolean") {
169
- value = String(rawValue);
170
- }
171
- else if (rawValue === null || rawValue === undefined) {
172
- failures.push({ key, error: "Value is null or undefined" });
173
- continue;
174
- }
175
- else {
176
- failures.push({
177
- key,
178
- error: "Value must be a string, number, or boolean (use dotted keys for nesting)",
179
- });
180
- continue;
181
- }
182
- try {
183
- // We pass each arg as a separate argv element — no shell involved,
184
- // so there's no shell-injection surface even if `value` contains
185
- // funky characters. (Which it will, for API keys.)
186
- execFn(hermesBin, [...profilePrefix, "config", "set", key, value]);
187
- applied += 1;
188
- }
189
- catch (err) {
190
- failures.push({
191
- key,
192
- error: err instanceof Error ? err.message : String(err),
193
- });
194
- }
195
- }
196
- return { applied, failures };
197
- }
198
- // ---------------------------------------------------------------------------
199
- // Entry point
200
- // ---------------------------------------------------------------------------
201
- // ---------------------------------------------------------------------------
202
- // Platform-mode expansion
203
- // ---------------------------------------------------------------------------
204
- /**
205
- * Expand a "platform" mode bundle into concrete Hermes inference config.
206
- *
207
- * When the user picked "Fast & cheap" or "Smart max-effort" on Forge, the
208
- * bundle from the web UI doesn't carry a real API key — those presets use
209
- * Nookplot's gateway proxy (OpenAI-compat at /v1/openai/v1/chat/completions),
210
- * which charges the user's NOOK balance. The bundle instead carries SENTINEL
211
- * keys that signal "expand me locally":
212
- *
213
- * __nookplot_inference_mode = "platform"
214
- * __nookplot_platform_model = "hermes-3-llama-3.1-8b" (or whichever model)
215
- * __nookplot_gateway_base = "https://gateway.nookplot.com" (optional)
216
- *
217
- * This function:
218
- * 1. Detects the platform-mode marker.
219
- * 2. Reads the user's Nookplot API key from local ~/.nookplot/credentials.json.
220
- * The API key NEVER touches the bundle (so it never lands on the gateway
221
- * staging table or in transit). The web-staged bundle only has the
222
- * metadata above; expansion happens at install time on the user's machine.
223
- * 3. Returns a NEW config object with sentinels stripped + gateway-proxy
224
- * Hermes config keys added (model.base_url, OPENAI_API_KEY, model.default).
225
- *
226
- * Returns the original config unchanged when no platform marker is present —
227
- * BYOK + messaging-only bundles continue to work exactly as before.
228
- *
229
- * Why the indirection vs. just including the API key in the bundle:
230
- * - Bundle ciphertext lands on the gateway briefly (15-minute TTL). Even
231
- * though it's encrypted client-side, fewer copies of the user's API key
232
- * in transit = less attack surface.
233
- * - Bundle is one-time-use; a user re-installing on a new machine would
234
- * need a new bundle. Reading from local creds avoids that round-trip.
235
- * - Future per-agent scoped tokens slot in here without changing the
236
- * bundle protocol.
237
- */
238
- /**
239
- * Whitelist of trusted gateway origins for the `__nookplot_gateway_base`
240
- * override. This guards against bundle-tamper key exfiltration.
241
- *
242
- * The installer's own `gatewayUrl` argument is always trusted (it was
243
- * baked into the install script by the gateway that served it), so we
244
- * also accept any URL whose origin matches `gatewayUrl`'s origin —
245
- * that covers staging environments transparently.
246
- */
247
- const TRUSTED_GATEWAY_ORIGINS = new Set([
248
- "https://gateway.nookplot.com",
249
- "https://gateway-dev.nookplot.com",
250
- "http://localhost:8080",
251
- "http://localhost:3000",
252
- "http://127.0.0.1:8080",
253
- "http://127.0.0.1:3000",
254
- ]);
255
- export function isAllowedGatewayBase(candidate, installerGatewayUrl) {
256
- let candidateOrigin;
257
- try {
258
- candidateOrigin = new URL(candidate).origin;
259
- }
260
- catch {
261
- return false; // malformed URL
262
- }
263
- if (TRUSTED_GATEWAY_ORIGINS.has(candidateOrigin))
264
- return true;
265
- // Also accept anything matching the installer's own gateway origin.
266
- try {
267
- if (new URL(installerGatewayUrl).origin === candidateOrigin)
268
- return true;
269
- }
270
- catch {
271
- /* fall through */
272
- }
273
- return false;
274
- }
275
- function expandPlatformInference(config, gatewayUrl, credentialsReader) {
276
- const mode = config["__nookplot_inference_mode"];
277
- if (mode !== "platform") {
278
- // Fast path: nothing to expand. Strip any rogue __nookplot_* keys
279
- // anyway so they never reach the Hermes key-validity check.
280
- const stripped = {};
281
- for (const [k, v] of Object.entries(config)) {
282
- if (!k.startsWith("__nookplot_"))
283
- stripped[k] = v;
284
- }
285
- return stripped;
286
- }
287
- const model = typeof config["__nookplot_platform_model"] === "string"
288
- ? config["__nookplot_platform_model"]
289
- : null;
290
- // The bundle MAY override the gateway base for staging / dev contexts, but
291
- // we whitelist the host because this URL becomes `model.base_url` in Hermes
292
- // — which means the user's freshly-written `OPENAI_API_KEY` (read from
293
- // local credentials) will be sent there on every inference. A bundle that
294
- // smuggles `__nookplot_gateway_base: "https://evil.example/..."` would
295
- // exfiltrate the user's API key on first call.
296
- //
297
- // Trust set: production gateway, dev gateway, localhost (development),
298
- // plus whatever was passed as `gatewayUrl` (the installer's argument —
299
- // already validated upstream). Anything else is silently ignored, falling
300
- // back to `gatewayUrl`.
301
- const rawBaseOverride = typeof config["__nookplot_gateway_base"] === "string"
302
- ? config["__nookplot_gateway_base"]
303
- : null;
304
- const baseOverride = rawBaseOverride && isAllowedGatewayBase(rawBaseOverride, gatewayUrl)
305
- ? rawBaseOverride
306
- : null;
307
- if (rawBaseOverride && !baseOverride) {
308
- console.error(`[nookplot-mcp] Ignoring untrusted __nookplot_gateway_base override (${rawBaseOverride}). Using ${gatewayUrl} instead. ` +
309
- `This protects your API key from being sent to an attacker-controlled gateway.`);
310
- }
311
- // Read local API key. If not found, abort the expansion — the user needs
312
- // to register first via `nookplot register` or by deploying their first
313
- // agent through the web flow.
314
- const creds = credentialsReader();
315
- if (!creds || !creds.apiKey) {
316
- throw new Error("Platform inference mode requires a registered Nookplot account, " +
317
- "but no credentials were found at ~/.nookplot/credentials.json. " +
318
- "Run `nookplot register` first, or deploy your first agent on nookplot.com.");
319
- }
320
- // Build the expanded config. Strip ALL __nookplot_* sentinels so the
321
- // downstream Hermes-key validator never sees them.
322
- const expanded = {};
323
- for (const [k, v] of Object.entries(config)) {
324
- if (!k.startsWith("__nookplot_"))
325
- expanded[k] = v;
326
- }
327
- // Trailing-slash-safe base URL. Hermes will append /chat/completions to
328
- // model.base_url, so we end at /v1/openai/v1 (path includes the inner /v1
329
- // because OpenAI-compat clients expect it — see openaiAdapter.ts mounting).
330
- const base = (baseOverride ?? gatewayUrl).replace(/\/+$/, "");
331
- expanded["model.base_url"] = `${base}/v1/openai/v1`;
332
- // Use OPENAI_API_KEY because the gateway adapter speaks OpenAI's protocol;
333
- // Hermes routes auth via the OpenAI provider config when model.base_url
334
- // is set. Hermes auto-routes SCREAMING_SNAKE_CASE keys to ~/.hermes/.env
335
- // (or the per-profile .env).
336
- expanded["OPENAI_API_KEY"] = creds.apiKey;
337
- // Default model — only set if the bundle specified one. (Forge always
338
- // does, but we don't blow up if it's missing.)
339
- if (model && !expanded["model.default"]) {
340
- expanded["model.default"] = model;
341
- }
342
- return expanded;
343
- }
344
- /**
345
- * Default credentials reader — reads ~/.nookplot/credentials.json and returns
346
- * { apiKey } or null. Isolated from applyConfig main logic so tests can
347
- * inject a stub without filesystem access.
348
- */
349
- function defaultCredentialsReader() {
350
- try {
351
- const credsPath = join(homedir(), ".nookplot", "credentials.json");
352
- if (!existsSync(credsPath))
353
- return null;
354
- const raw = readFileSync(credsPath, "utf-8");
355
- const parsed = JSON.parse(raw);
356
- if (typeof parsed.apiKey !== "string" || !parsed.apiKey)
357
- return null;
358
- return { apiKey: parsed.apiKey };
359
- }
360
- catch {
361
- return null;
362
- }
363
- }
364
- /**
365
- * Main orchestration: fetch → decrypt → apply. Returns a result with per-key
366
- * success/failure so the caller can surface what happened to the user.
367
- */
368
- export async function applyConfig(opts) {
369
- if (!opts.token || !/^[a-f0-9]{64}$/i.test(opts.token)) {
370
- throw new Error("Invalid NOOKPLOT_CONFIG_TOKEN (must be 64 hex chars). " +
371
- "Regenerate the install command on your agent's Nookplot page.");
372
- }
373
- if (!opts.key) {
374
- throw new Error("Missing NOOKPLOT_CONFIG_KEY env var.");
375
- }
376
- const gatewayUrl = opts.gatewayUrl ?? "https://gateway.nookplot.com";
377
- const timeoutMs = opts.timeoutMs ?? 15_000;
378
- const hermesBin = opts.hermesBin ?? "hermes";
379
- const fetchFn = opts._fetch ?? fetch;
380
- const execFn = opts._exec ??
381
- ((bin, args) => {
382
- execFileSync(bin, args, { stdio: "pipe" });
383
- });
384
- // Parse the key from base64url.
385
- let keyBytes;
386
- try {
387
- keyBytes = fromBase64Url(opts.key);
388
- }
389
- catch (err) {
390
- throw new Error(`Could not decode NOOKPLOT_CONFIG_KEY as base64url: ${err instanceof Error ? err.message : String(err)}`);
391
- }
392
- // 1. Fetch the encrypted bundle (one-time-use token — gateway deletes
393
- // the row as it responds).
394
- const stage = await redeemCiphertext(gatewayUrl, opts.token, fetchFn, timeoutMs);
395
- // 2. Decrypt locally. Auth-tag failures are surfaced as a clear error
396
- // so the user can regenerate the install command.
397
- const config = decryptBundle(stage, keyBytes);
398
- // 2b. Expand platform-mode bundles. For Fast/Smart presets, the bundle
399
- // contains __nookplot_* sentinel keys that we resolve locally —
400
- // fetching the user's API key from ~/.nookplot/credentials.json
401
- // (NEVER from the bundle) and rewriting to concrete model.base_url
402
- // + OPENAI_API_KEY + model.default config that points Hermes at
403
- // our gateway's OpenAI-compat adapter.
404
- //
405
- // For BYOK + messaging-only bundles this is a no-op (just strips
406
- // any rogue __nookplot_* keys defensively).
407
- const credsReader = opts._credentialsReader ?? defaultCredentialsReader;
408
- const expanded = expandPlatformInference(config, gatewayUrl, credsReader);
409
- // 3. Apply each entry via `hermes config set`. Hermes routes secrets
410
- // to .env and other settings to config.yaml.
411
- const { applied, failures } = applyToHermes(expanded, hermesBin, execFn, opts.profile);
412
- return {
413
- applied,
414
- failures,
415
- agentAddress: stage.agentAddress,
416
- };
417
- }
418
- //# sourceMappingURL=applyConfig.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"applyConfig.js","sourceRoot":"","sources":["../src/applyConfig.ts"],"names":[],"mappings":"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"}
@@ -1,65 +0,0 @@
1
- /**
2
- * Profile-name derivation for Hermes's `hermes profile create <name>`.
3
- *
4
- * Every forged agent on Nookplot maps to its own Hermes profile — a fully
5
- * isolated directory tree at `~/.hermes/profiles/<name>/` with its own
6
- * config.yaml, .env, sessions, and (optionally) Telegram bot token. The
7
- * profile name is the user-facing handle: they run `<name> chat` (via the
8
- * alias wrapper at `~/.local/bin/<name>`), and it shows up in
9
- * `hermes profile list`.
10
- *
11
- * Hermes's validation rule (from `hermes profile create --help`):
12
- * "Profile name (lowercase, alphanumeric)"
13
- *
14
- * Empirically, it also accepts hyphens. The pattern we target is
15
- * `/^[a-z][a-z0-9-]{0,30}[a-z0-9]$/` — 2..32 chars, letter-prefix,
16
- * alnum-or-hyphen middle, alnum suffix.
17
- *
18
- * Input sources, in preference order:
19
- * 1. `display_name` from `agents.display_name` (slugged)
20
- * 2. `agent-<last6-hex>` fallback derived from the agent address
21
- *
22
- * Collision handling is the caller's job — we just produce the candidate
23
- * from inputs. The bash installer does a `hermes profile show $NAME ||
24
- * hermes profile create $NAME` pattern, so a name that already exists
25
- * with a DIFFERENT agent is the user's problem (rare, and giving them a
26
- * clear error beats silently shadowing).
27
- *
28
- * @module profileName
29
- */
30
- /** Validate against Hermes's profile-name rule. Exported for tests. */
31
- export declare function isValidProfileName(name: string): boolean;
32
- /**
33
- * Slugify a free-form string (display name, title, etc.) into a safe
34
- * profile name. Rules:
35
- * - lowercase
36
- * - unicode → ASCII approximation (NFKD strips diacritics)
37
- * - non-alnum runs become single hyphens
38
- * - leading/trailing hyphens trimmed
39
- * - leading digits replaced with "a-" so the name starts with a letter
40
- * - length capped at MAX_PROFILE_NAME_LEN, trimmed at a hyphen if possible
41
- *
42
- * Returns empty string if the input has no usable alphanumeric chars
43
- * (e.g. pure emoji). Callers should treat that as "fall back to the
44
- * address-based default."
45
- */
46
- export declare function slugifyDisplayName(input: string): string;
47
- /**
48
- * Fallback name from an agent's on-chain address: `agent-<last6-hex>`.
49
- * Always valid (short, letter-prefix, alnum).
50
- */
51
- export declare function profileNameFromAddress(address: string): string;
52
- /**
53
- * Top-level derivation: try display_name first, fall back to address.
54
- *
55
- * Takes optional collision-check hook — if provided, we'll try `<name>-2`,
56
- * `<name>-3`, ... up to `-9` before giving up. That's enough headroom for
57
- * normal users; power users who hit it can rename via `hermes profile
58
- * rename` after the fact.
59
- */
60
- export declare function deriveProfileName(opts: {
61
- displayName?: string | null;
62
- agentAddress: string;
63
- isTaken?: (candidate: string) => boolean;
64
- }): string;
65
- //# sourceMappingURL=profileName.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"profileName.d.ts","sourceRoot":"","sources":["../src/profileName.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA2BxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI9D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE;IACJ,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAC1C,GACA,MAAM,CAmBR"}
@@ -1,114 +0,0 @@
1
- /**
2
- * Profile-name derivation for Hermes's `hermes profile create <name>`.
3
- *
4
- * Every forged agent on Nookplot maps to its own Hermes profile — a fully
5
- * isolated directory tree at `~/.hermes/profiles/<name>/` with its own
6
- * config.yaml, .env, sessions, and (optionally) Telegram bot token. The
7
- * profile name is the user-facing handle: they run `<name> chat` (via the
8
- * alias wrapper at `~/.local/bin/<name>`), and it shows up in
9
- * `hermes profile list`.
10
- *
11
- * Hermes's validation rule (from `hermes profile create --help`):
12
- * "Profile name (lowercase, alphanumeric)"
13
- *
14
- * Empirically, it also accepts hyphens. The pattern we target is
15
- * `/^[a-z][a-z0-9-]{0,30}[a-z0-9]$/` — 2..32 chars, letter-prefix,
16
- * alnum-or-hyphen middle, alnum suffix.
17
- *
18
- * Input sources, in preference order:
19
- * 1. `display_name` from `agents.display_name` (slugged)
20
- * 2. `agent-<last6-hex>` fallback derived from the agent address
21
- *
22
- * Collision handling is the caller's job — we just produce the candidate
23
- * from inputs. The bash installer does a `hermes profile show $NAME ||
24
- * hermes profile create $NAME` pattern, so a name that already exists
25
- * with a DIFFERENT agent is the user's problem (rare, and giving them a
26
- * clear error beats silently shadowing).
27
- *
28
- * @module profileName
29
- */
30
- const MAX_PROFILE_NAME_LEN = 32;
31
- const MIN_PROFILE_NAME_LEN = 2;
32
- /** Validate against Hermes's profile-name rule. Exported for tests. */
33
- export function isValidProfileName(name) {
34
- return /^[a-z][a-z0-9-]{0,30}[a-z0-9]$/.test(name);
35
- }
36
- /**
37
- * Slugify a free-form string (display name, title, etc.) into a safe
38
- * profile name. Rules:
39
- * - lowercase
40
- * - unicode → ASCII approximation (NFKD strips diacritics)
41
- * - non-alnum runs become single hyphens
42
- * - leading/trailing hyphens trimmed
43
- * - leading digits replaced with "a-" so the name starts with a letter
44
- * - length capped at MAX_PROFILE_NAME_LEN, trimmed at a hyphen if possible
45
- *
46
- * Returns empty string if the input has no usable alphanumeric chars
47
- * (e.g. pure emoji). Callers should treat that as "fall back to the
48
- * address-based default."
49
- */
50
- export function slugifyDisplayName(input) {
51
- if (typeof input !== "string" || input.length === 0)
52
- return "";
53
- let s = input
54
- .normalize("NFKD")
55
- .replace(/[\u0300-\u036f]/g, "") // strip combining accents
56
- .toLowerCase()
57
- .replace(/[^a-z0-9]+/g, "-") // non-alnum runs → hyphen
58
- .replace(/^-+|-+$/g, ""); // trim leading/trailing hyphens
59
- if (s.length === 0)
60
- return "";
61
- // Hermes requires a letter prefix.
62
- if (/^[0-9]/.test(s))
63
- s = "a-" + s;
64
- // Cap length. If we have to cut, prefer cutting at a hyphen so we don't
65
- // leave a mid-word stump.
66
- if (s.length > MAX_PROFILE_NAME_LEN) {
67
- const cut = s.slice(0, MAX_PROFILE_NAME_LEN);
68
- const lastHyphen = cut.lastIndexOf("-");
69
- s = lastHyphen > MIN_PROFILE_NAME_LEN ? cut.slice(0, lastHyphen) : cut;
70
- }
71
- // Trim trailing hyphen that could remain after length cut.
72
- s = s.replace(/-+$/, "");
73
- // After all of that, still must pass the Hermes rule. If not, give up.
74
- return isValidProfileName(s) ? s : "";
75
- }
76
- /**
77
- * Fallback name from an agent's on-chain address: `agent-<last6-hex>`.
78
- * Always valid (short, letter-prefix, alnum).
79
- */
80
- export function profileNameFromAddress(address) {
81
- const clean = address.replace(/^0x/, "").toLowerCase();
82
- const last6 = clean.slice(-6);
83
- return `agent-${last6}`;
84
- }
85
- /**
86
- * Top-level derivation: try display_name first, fall back to address.
87
- *
88
- * Takes optional collision-check hook — if provided, we'll try `<name>-2`,
89
- * `<name>-3`, ... up to `-9` before giving up. That's enough headroom for
90
- * normal users; power users who hit it can rename via `hermes profile
91
- * rename` after the fact.
92
- */
93
- export function deriveProfileName(opts) {
94
- const fromDisplay = opts.displayName ? slugifyDisplayName(opts.displayName) : "";
95
- const primary = fromDisplay || profileNameFromAddress(opts.agentAddress);
96
- if (!opts.isTaken)
97
- return primary;
98
- if (!opts.isTaken(primary))
99
- return primary;
100
- for (let i = 2; i <= 9; i++) {
101
- const candidate = `${primary}-${i}`;
102
- if (candidate.length > MAX_PROFILE_NAME_LEN) {
103
- // Primary was too long to suffix; fall back to address-based.
104
- const addrName = profileNameFromAddress(opts.agentAddress);
105
- return opts.isTaken(addrName) ? `${addrName}-${i}` : addrName;
106
- }
107
- if (!opts.isTaken(candidate))
108
- return candidate;
109
- }
110
- // Give up — return the primary. Hermes will error on duplicate create;
111
- // user sees the error and can rename.
112
- return primary;
113
- }
114
- //# sourceMappingURL=profileName.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"profileName.js","sourceRoot":"","sources":["../src/profileName.ts"],"names":[],"mappings":"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"}