@elisym/mcp 0.15.1 → 0.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/index.js +641 -111
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,19 +5,19 @@ import { createIrohTransport, loadGlobalConfig, writeGlobalConfig } from '@elisy
|
|
|
5
5
|
import { getBase58Encoder, getBase58Decoder, generateKeyPairSigner, createSolanaRpc, address, createSolanaRpcSubscriptions, sendAndConfirmTransactionFactory, getSignatureFromTransaction, pipe, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, createKeyPairSignerFromBytes, isAddress } from '@solana/kit';
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { generateSecretKey, nip19, getPublicKey } from 'nostr-tools';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
9
|
+
import { realpath, readFile, stat, mkdir, rm, writeFile, rename, unlink } from 'node:fs/promises';
|
|
10
|
+
import { tmpdir, platform, homedir } from 'node:os';
|
|
10
11
|
import { dirname, join, resolve, isAbsolute, basename, relative } from 'node:path';
|
|
11
|
-
import {
|
|
12
|
-
import { fileURLToPath } from 'node:url';
|
|
12
|
+
import { promisify } from 'node:util';
|
|
13
13
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
14
14
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
15
15
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
16
16
|
import { z, ZodError } from 'zod';
|
|
17
17
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
18
|
+
import { readFileSync, mkdtempSync } from 'node:fs';
|
|
18
19
|
import pino from 'pino';
|
|
19
|
-
import {
|
|
20
|
-
import { promisify } from 'node:util';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
21
|
import { randomBytes } from 'node:crypto';
|
|
22
22
|
import { getTransferSolInstruction } from '@solana-program/system';
|
|
23
23
|
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, getCreateAssociatedTokenIdempotentInstruction, ASSOCIATED_TOKEN_PROGRAM_ADDRESS, getTransferCheckedInstruction } from '@solana-program/token';
|
|
@@ -271,104 +271,39 @@ async function writeFileAtomic(path, content, mode = 384) {
|
|
|
271
271
|
throw err;
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return pkg.version;
|
|
280
|
-
} catch {
|
|
281
|
-
return "0.0.0";
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
var PACKAGE_VERSION = readPackageVersion();
|
|
285
|
-
function formatSol(lamports) {
|
|
286
|
-
return `${formatSolNumeric(lamports)} SOL`;
|
|
287
|
-
}
|
|
288
|
-
function formatSolNumeric(lamports) {
|
|
289
|
-
const sign = lamports < 0n ? "-" : "";
|
|
290
|
-
const abs = lamports < 0n ? -lamports : lamports;
|
|
291
|
-
const whole = abs / LAMPORTS_PER_SOL;
|
|
292
|
-
const frac = abs % LAMPORTS_PER_SOL;
|
|
293
|
-
return `${sign}${whole}.${frac.toString().padStart(9, "0")}`;
|
|
274
|
+
|
|
275
|
+
// src/install.ts
|
|
276
|
+
var execFileAsync = promisify(execFile);
|
|
277
|
+
function elisymPackageArgs() {
|
|
278
|
+
return ["-y", "@elisym/mcp@latest"];
|
|
294
279
|
}
|
|
295
|
-
function
|
|
296
|
-
|
|
297
|
-
return NATIVE_SOL;
|
|
298
|
-
}
|
|
299
|
-
const known = resolveKnownAsset(payment2.chain, payment2.token ?? "sol", payment2.mint);
|
|
300
|
-
if (known) {
|
|
301
|
-
return known;
|
|
302
|
-
}
|
|
303
|
-
if (payment2.token && payment2.symbol && typeof payment2.decimals === "number") {
|
|
304
|
-
return {
|
|
305
|
-
chain: payment2.chain,
|
|
306
|
-
token: payment2.token,
|
|
307
|
-
mint: payment2.mint,
|
|
308
|
-
symbol: payment2.symbol,
|
|
309
|
-
decimals: payment2.decimals
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
return NATIVE_SOL;
|
|
280
|
+
function userHome() {
|
|
281
|
+
return process.env.HOME ?? homedir();
|
|
313
282
|
}
|
|
314
|
-
function
|
|
315
|
-
const
|
|
316
|
-
if (
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
if (trimmed.startsWith("-")) {
|
|
320
|
-
throw new Error("amount cannot be negative");
|
|
321
|
-
}
|
|
322
|
-
if (!/^(\d+\.\d*|\d*\.\d+|\d+)$/.test(trimmed)) {
|
|
323
|
-
throw new Error(
|
|
324
|
-
'amount must be a non-negative decimal number (e.g. "0.5", "1", "0.000000001")'
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
const dotPos = trimmed.indexOf(".");
|
|
328
|
-
if (dotPos === -1) {
|
|
329
|
-
const whole = BigInt(trimmed);
|
|
330
|
-
return whole * LAMPORTS_PER_SOL;
|
|
331
|
-
}
|
|
332
|
-
const wholePart = dotPos === 0 ? 0n : BigInt(trimmed.slice(0, dotPos));
|
|
333
|
-
const fracStr = trimmed.slice(dotPos + 1);
|
|
334
|
-
if (fracStr.length > 9) {
|
|
335
|
-
throw new Error("too many decimal places (max 9)");
|
|
283
|
+
async function resolveNpmCacheDir() {
|
|
284
|
+
const fromEnv = process.env.npm_config_cache;
|
|
285
|
+
if (fromEnv && fromEnv.trim() !== "") {
|
|
286
|
+
return fromEnv.trim();
|
|
336
287
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
288
|
+
try {
|
|
289
|
+
const { stdout } = await execFileAsync("npm", ["config", "get", "cache"]);
|
|
290
|
+
const value = stdout.trim();
|
|
291
|
+
if (value && value !== "undefined" && value !== "null") {
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
} catch {
|
|
344
295
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
var MAX_TIMEOUT_SECS = LIMITS.MAX_TIMEOUT_SECS;
|
|
349
|
-
LIMITS.NIP44_MAX_PLAINTEXT_BYTES;
|
|
350
|
-
LIMITS.MAX_ENCRYPTED_INLINE_BYTES;
|
|
351
|
-
LIMITS.MAX_REINLINE_TEXT_BYTES;
|
|
352
|
-
var MAX_NPUB_LEN = 128;
|
|
353
|
-
var MAX_EVENT_ID_LEN = 128;
|
|
354
|
-
var MAX_PAYMENT_REQ_LEN = 1e4;
|
|
355
|
-
var MAX_SOLANA_ADDR_LEN = 64;
|
|
356
|
-
var _paymentStrategy = null;
|
|
357
|
-
function payment() {
|
|
358
|
-
_paymentStrategy ??= new SolanaPaymentStrategy();
|
|
359
|
-
return _paymentStrategy;
|
|
360
|
-
}
|
|
361
|
-
function decodeNpub(npub) {
|
|
362
|
-
const decoded = nip19.decode(npub);
|
|
363
|
-
if (decoded.type !== "npub") {
|
|
364
|
-
throw new Error(`Expected npub, got ${decoded.type}`);
|
|
296
|
+
if (platform() === "win32") {
|
|
297
|
+
const localAppData = process.env.LOCALAPPDATA ?? join(userHome(), "AppData", "Local");
|
|
298
|
+
return join(localAppData, "npm-cache");
|
|
365
299
|
}
|
|
366
|
-
return
|
|
300
|
+
return join(userHome(), ".npm");
|
|
367
301
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
302
|
+
async function clearNpxCache() {
|
|
303
|
+
const cacheDir = await resolveNpmCacheDir();
|
|
304
|
+
const npxDir = join(cacheDir, "_npx");
|
|
305
|
+
await rm(npxDir, { recursive: true, force: true });
|
|
306
|
+
console.log(`Cleared npx cache: ${npxDir}`);
|
|
372
307
|
}
|
|
373
308
|
function validateClientName(name) {
|
|
374
309
|
if (name === void 0) {
|
|
@@ -399,8 +334,9 @@ async function safeRewriteJson(path, expectedRaw, newConfig) {
|
|
|
399
334
|
var CLIENTS = [
|
|
400
335
|
{
|
|
401
336
|
name: "claude-desktop",
|
|
337
|
+
format: "json",
|
|
402
338
|
configPath() {
|
|
403
|
-
const home =
|
|
339
|
+
const home = userHome();
|
|
404
340
|
switch (platform()) {
|
|
405
341
|
case "darwin":
|
|
406
342
|
return join(home, "Library/Application Support/Claude/claude_desktop_config.json");
|
|
@@ -413,21 +349,29 @@ var CLIENTS = [
|
|
|
413
349
|
},
|
|
414
350
|
{
|
|
415
351
|
name: "claude-code",
|
|
352
|
+
format: "json",
|
|
416
353
|
// Claude Code CLI keeps user-scope MCP servers under `mcpServers` at the top
|
|
417
354
|
// level of `~/.claude.json`. Project-scope (`.mcp.json` in cwd) and local-scope
|
|
418
355
|
// (`projects.<path>.mcpServers` inside the same file) are deliberately not
|
|
419
356
|
// touched here - this installer only writes user scope so the server is
|
|
420
357
|
// available across all projects.
|
|
421
|
-
configPath: () => join(
|
|
358
|
+
configPath: () => join(userHome(), ".claude.json")
|
|
422
359
|
},
|
|
423
360
|
{
|
|
424
361
|
name: "cursor",
|
|
425
|
-
|
|
362
|
+
format: "json",
|
|
363
|
+
configPath: () => join(userHome(), ".cursor/mcp.json")
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
name: "codex",
|
|
367
|
+
format: "codex-toml",
|
|
368
|
+
configPath: () => join(userHome(), ".codex/config.toml")
|
|
426
369
|
},
|
|
427
370
|
{
|
|
428
371
|
name: "windsurf",
|
|
372
|
+
format: "json",
|
|
429
373
|
configPath() {
|
|
430
|
-
const home =
|
|
374
|
+
const home = userHome();
|
|
431
375
|
if (platform() === "darwin") {
|
|
432
376
|
return join(home, "Library/Application Support/Windsurf/mcp.json");
|
|
433
377
|
}
|
|
@@ -480,7 +424,7 @@ async function runInstall(options) {
|
|
|
480
424
|
continue;
|
|
481
425
|
}
|
|
482
426
|
try {
|
|
483
|
-
const result = await installToConfig(path, entry,
|
|
427
|
+
const result = client.format === "codex-toml" ? await installToCodexConfig(path, entry, options.agent) : await installToConfig(path, entry, options.agent);
|
|
484
428
|
if (result === "installed") {
|
|
485
429
|
console.log(`Installed to ${client.name}: ${path}`);
|
|
486
430
|
installed++;
|
|
@@ -499,7 +443,7 @@ async function runInstall(options) {
|
|
|
499
443
|
}
|
|
500
444
|
}
|
|
501
445
|
async function resolveDefaultAgent() {
|
|
502
|
-
const agents = await listAgents(
|
|
446
|
+
const agents = await listAgents(userHome());
|
|
503
447
|
const [first, second] = agents;
|
|
504
448
|
if (!first) {
|
|
505
449
|
return { kind: "none" };
|
|
@@ -523,6 +467,20 @@ async function runUpdate(options) {
|
|
|
523
467
|
if (!path) {
|
|
524
468
|
continue;
|
|
525
469
|
}
|
|
470
|
+
if (client.format === "codex-toml") {
|
|
471
|
+
try {
|
|
472
|
+
const result = await updateCodexConfig(path, options.agent);
|
|
473
|
+
if (result === "updated") {
|
|
474
|
+
console.log(`Updated ${client.name}: ${path} -> @elisym/mcp@latest`);
|
|
475
|
+
updated++;
|
|
476
|
+
}
|
|
477
|
+
} catch (err) {
|
|
478
|
+
if (err.code !== "ENOENT") {
|
|
479
|
+
console.log(`Skipped ${client.name}: ${err.message}`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
526
484
|
let raw;
|
|
527
485
|
try {
|
|
528
486
|
raw = await readFile(path, "utf-8");
|
|
@@ -561,12 +519,16 @@ async function runUpdate(options) {
|
|
|
561
519
|
}
|
|
562
520
|
const entry = existing;
|
|
563
521
|
const newArgs = elisymPackageArgs();
|
|
522
|
+
const packageArg = newArgs[1];
|
|
523
|
+
if (packageArg === void 0) {
|
|
524
|
+
throw new Error("Internal error: missing package argument for elisym MCP install.");
|
|
525
|
+
}
|
|
564
526
|
if (Array.isArray(entry.args)) {
|
|
565
527
|
const idx = entry.args.findIndex(
|
|
566
528
|
(a) => typeof a === "string" && a.startsWith("@elisym/mcp@")
|
|
567
529
|
);
|
|
568
530
|
if (idx >= 0) {
|
|
569
|
-
entry.args[idx] =
|
|
531
|
+
entry.args[idx] = packageArg;
|
|
570
532
|
} else {
|
|
571
533
|
entry.args = newArgs;
|
|
572
534
|
}
|
|
@@ -584,12 +546,15 @@ async function runUpdate(options) {
|
|
|
584
546
|
console.log(`Skipped ${client.name}: ${err.message}`);
|
|
585
547
|
continue;
|
|
586
548
|
}
|
|
587
|
-
console.log(`Updated ${client.name}: ${path} -> @elisym/mcp
|
|
549
|
+
console.log(`Updated ${client.name}: ${path} -> @elisym/mcp@latest`);
|
|
588
550
|
updated++;
|
|
589
551
|
}
|
|
590
552
|
if (updated === 0) {
|
|
591
553
|
console.log("No existing elisym MCP installs found to update.");
|
|
592
554
|
}
|
|
555
|
+
{
|
|
556
|
+
await clearNpxCache();
|
|
557
|
+
}
|
|
593
558
|
}
|
|
594
559
|
async function runUninstall(options) {
|
|
595
560
|
validateClientName(options.client);
|
|
@@ -601,6 +566,16 @@ async function runUninstall(options) {
|
|
|
601
566
|
if (!path) {
|
|
602
567
|
continue;
|
|
603
568
|
}
|
|
569
|
+
if (client.format === "codex-toml") {
|
|
570
|
+
try {
|
|
571
|
+
const result = await uninstallFromCodexConfig(path);
|
|
572
|
+
if (result === "removed") {
|
|
573
|
+
console.log(`Removed from ${client.name}: ${path}`);
|
|
574
|
+
}
|
|
575
|
+
} catch {
|
|
576
|
+
}
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
604
579
|
let raw;
|
|
605
580
|
try {
|
|
606
581
|
raw = await readFile(path, "utf-8");
|
|
@@ -634,8 +609,7 @@ async function runList() {
|
|
|
634
609
|
}
|
|
635
610
|
try {
|
|
636
611
|
const raw = await readFile(path, "utf-8");
|
|
637
|
-
const
|
|
638
|
-
const installed = !!config.mcpServers?.elisym;
|
|
612
|
+
const installed = client.format === "codex-toml" ? findCodexElisymBlock(raw) !== null : !!JSON.parse(raw).mcpServers?.elisym;
|
|
639
613
|
console.log(`${client.name}: ${installed ? "installed" : "available"} (${path})`);
|
|
640
614
|
} catch {
|
|
641
615
|
console.log(`${client.name}: not found`);
|
|
@@ -687,6 +661,460 @@ async function installToConfig(path, entry, agentRebind) {
|
|
|
687
661
|
await safeRewriteJson(path, raw, config);
|
|
688
662
|
return "installed";
|
|
689
663
|
}
|
|
664
|
+
function findCodexElisymBlock(raw) {
|
|
665
|
+
const table = findTomlTableRange(raw, "mcp_servers.elisym");
|
|
666
|
+
if (!table) {
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
return { start: table.start, end: table.end, body: raw.slice(table.start, table.end) };
|
|
670
|
+
}
|
|
671
|
+
function findTomlTableRange(raw, path) {
|
|
672
|
+
return findTomlTableRanges(raw).find((table) => table.path === path) ?? null;
|
|
673
|
+
}
|
|
674
|
+
function findTomlTableRanges(raw) {
|
|
675
|
+
const lines = raw.match(/^.*(?:\n|$)/gm) ?? [];
|
|
676
|
+
const offsets = [];
|
|
677
|
+
let offset = 0;
|
|
678
|
+
for (const line of lines) {
|
|
679
|
+
offsets.push(offset);
|
|
680
|
+
offset += line.length;
|
|
681
|
+
}
|
|
682
|
+
const ranges = [];
|
|
683
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
684
|
+
const path = parseTomlTableHeader(line);
|
|
685
|
+
if (!path) {
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
let end = raw.length;
|
|
689
|
+
for (let nextLineIndex = lineIndex + 1; nextLineIndex < lines.length; nextLineIndex++) {
|
|
690
|
+
if (parseTomlTableHeader(lines[nextLineIndex] ?? "")) {
|
|
691
|
+
end = offsets[nextLineIndex] ?? raw.length;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
ranges.push({ start: offsets[lineIndex] ?? 0, end, path });
|
|
696
|
+
}
|
|
697
|
+
return ranges;
|
|
698
|
+
}
|
|
699
|
+
function parseTomlTableHeader(line) {
|
|
700
|
+
const match = /^\s*\[([^\]]+)\]\s*(?:#.*)?$/.exec(line.trimEnd());
|
|
701
|
+
return match ? match[1] : null;
|
|
702
|
+
}
|
|
703
|
+
function parseCodexEnv(block) {
|
|
704
|
+
const env = {};
|
|
705
|
+
let section = "other";
|
|
706
|
+
for (const line of block.split(/\r?\n/)) {
|
|
707
|
+
const trimmed = line.trim();
|
|
708
|
+
if (trimmed.startsWith("[")) {
|
|
709
|
+
if (/^\[mcp_servers\.elisym\]\s*(?:#.*)?$/.test(trimmed)) {
|
|
710
|
+
section = "elisym";
|
|
711
|
+
} else if (/^\[mcp_servers\.elisym\.env\]\s*(?:#.*)?$/.test(trimmed)) {
|
|
712
|
+
section = "env";
|
|
713
|
+
} else {
|
|
714
|
+
section = "other";
|
|
715
|
+
}
|
|
716
|
+
continue;
|
|
717
|
+
}
|
|
718
|
+
if (trimmed === "" || trimmed.startsWith("#")) {
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
if (section === "elisym") {
|
|
722
|
+
Object.assign(env, parseCodexInlineEnv(trimmed));
|
|
723
|
+
} else if (section === "env") {
|
|
724
|
+
const match = /^([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+?)\s*(?:#.*)?$/.exec(trimmed);
|
|
725
|
+
if (!match) {
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
const [, key, rawValue] = match;
|
|
729
|
+
const value = parseTomlString(rawValue);
|
|
730
|
+
if (value !== void 0) {
|
|
731
|
+
env[key] = value;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return env;
|
|
736
|
+
}
|
|
737
|
+
function parseCodexInlineEnv(line) {
|
|
738
|
+
const env = {};
|
|
739
|
+
const match = /^env\s*=\s*\{(.*)\}\s*(?:#.*)?$/.exec(line);
|
|
740
|
+
if (!match) {
|
|
741
|
+
return env;
|
|
742
|
+
}
|
|
743
|
+
const [, body] = match;
|
|
744
|
+
for (const entry of splitInlineTableEntries(body)) {
|
|
745
|
+
const entryMatch = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+?)\s*$/.exec(entry);
|
|
746
|
+
if (!entryMatch) {
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
const [, key, rawValue] = entryMatch;
|
|
750
|
+
const value = parseTomlString(rawValue);
|
|
751
|
+
if (value !== void 0) {
|
|
752
|
+
env[key] = value;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
return env;
|
|
756
|
+
}
|
|
757
|
+
function splitInlineTableEntries(body) {
|
|
758
|
+
const entries = [];
|
|
759
|
+
let current = "";
|
|
760
|
+
let inString = false;
|
|
761
|
+
let escaped = false;
|
|
762
|
+
for (const char of body) {
|
|
763
|
+
if (escaped) {
|
|
764
|
+
current += char;
|
|
765
|
+
escaped = false;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
if (char === "\\" && inString) {
|
|
769
|
+
current += char;
|
|
770
|
+
escaped = true;
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
if (char === '"') {
|
|
774
|
+
current += char;
|
|
775
|
+
inString = !inString;
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (char === "," && !inString) {
|
|
779
|
+
entries.push(current);
|
|
780
|
+
current = "";
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
current += char;
|
|
784
|
+
}
|
|
785
|
+
if (current.trim() !== "") {
|
|
786
|
+
entries.push(current);
|
|
787
|
+
}
|
|
788
|
+
return entries;
|
|
789
|
+
}
|
|
790
|
+
function parseTomlString(rawValue) {
|
|
791
|
+
if (rawValue.startsWith("'") && rawValue.endsWith("'")) {
|
|
792
|
+
return rawValue.slice(1, -1);
|
|
793
|
+
}
|
|
794
|
+
try {
|
|
795
|
+
return JSON.parse(rawValue);
|
|
796
|
+
} catch {
|
|
797
|
+
return void 0;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
function quoteTomlString(value) {
|
|
801
|
+
return JSON.stringify(value);
|
|
802
|
+
}
|
|
803
|
+
function renderTomlStringArray(values) {
|
|
804
|
+
return `[${values.map((value) => quoteTomlString(value)).join(", ")}]`;
|
|
805
|
+
}
|
|
806
|
+
function renderCodexTomlBlock(entry) {
|
|
807
|
+
const lines = [
|
|
808
|
+
"[mcp_servers.elisym]",
|
|
809
|
+
`command = ${quoteTomlString(String(entry.command ?? "npx"))}`,
|
|
810
|
+
`args = ${renderTomlStringArray(Array.isArray(entry.args) ? entry.args.map(String) : [])}`
|
|
811
|
+
];
|
|
812
|
+
const env = entry.env && typeof entry.env === "object" && !Array.isArray(entry.env) ? entry.env : {};
|
|
813
|
+
const envEntries = Object.entries(env);
|
|
814
|
+
if (envEntries.length > 0) {
|
|
815
|
+
lines.push("", "[mcp_servers.elisym.env]");
|
|
816
|
+
for (const [key, value] of envEntries) {
|
|
817
|
+
lines.push(`${key} = ${quoteTomlString(String(value))}`);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return `${lines.join("\n")}
|
|
821
|
+
`;
|
|
822
|
+
}
|
|
823
|
+
function updateCodexTomlBlock(body, env, rewriteEnv) {
|
|
824
|
+
const withFreshPackagePin = updateCodexPackagePin(body);
|
|
825
|
+
if (!rewriteEnv) {
|
|
826
|
+
return withFreshPackagePin;
|
|
827
|
+
}
|
|
828
|
+
const agent = env.ELISYM_AGENT;
|
|
829
|
+
if (agent === void 0) {
|
|
830
|
+
return withFreshPackagePin;
|
|
831
|
+
}
|
|
832
|
+
return replaceCodexAgentEnv(withFreshPackagePin, agent);
|
|
833
|
+
}
|
|
834
|
+
function updateCodexPackagePin(body) {
|
|
835
|
+
const lines = body.match(/^.*(?:\n|$)/gm) ?? [];
|
|
836
|
+
let section = "other";
|
|
837
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
838
|
+
const trimmed = line.trim();
|
|
839
|
+
if (trimmed.startsWith("[")) {
|
|
840
|
+
if (/^\[mcp_servers\.elisym\]\s*(?:#.*)?$/.test(trimmed)) {
|
|
841
|
+
section = "elisym";
|
|
842
|
+
} else if (/^\[mcp_servers\.elisym\.env\]\s*(?:#.*)?$/.test(trimmed)) {
|
|
843
|
+
section = "env";
|
|
844
|
+
} else {
|
|
845
|
+
section = "other";
|
|
846
|
+
}
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
if (section !== "elisym" || !/^\s*args\s*=/.test(line)) {
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
const packageSpec = elisymPackageArgs()[1];
|
|
853
|
+
if (packageSpec === void 0) {
|
|
854
|
+
throw new Error("Internal error: missing package argument for elisym MCP install.");
|
|
855
|
+
}
|
|
856
|
+
const assignmentEndIndex = findTomlAssignmentEnd(lines, lineIndex);
|
|
857
|
+
const assignmentLines = lines.slice(lineIndex, assignmentEndIndex + 1);
|
|
858
|
+
const packageLineOffset = assignmentLines.findIndex(
|
|
859
|
+
(assignmentLine) => assignmentLine.includes("@elisym/mcp@")
|
|
860
|
+
);
|
|
861
|
+
if (packageLineOffset >= 0) {
|
|
862
|
+
const packageLineIndex = lineIndex + packageLineOffset;
|
|
863
|
+
const packageLine = lines[packageLineIndex] ?? "";
|
|
864
|
+
lines[packageLineIndex] = packageLine.replace(/@elisym\/mcp@[^"\],\s]+/, packageSpec);
|
|
865
|
+
} else {
|
|
866
|
+
lines.splice(
|
|
867
|
+
lineIndex,
|
|
868
|
+
assignmentEndIndex - lineIndex + 1,
|
|
869
|
+
replaceTomlAssignmentValue(line, renderTomlStringArray(elisymPackageArgs()))
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
return lines.join("");
|
|
875
|
+
}
|
|
876
|
+
function findTomlAssignmentEnd(lines, startIndex) {
|
|
877
|
+
const firstLine = lines[startIndex] ?? "";
|
|
878
|
+
const assignmentStart = firstLine.indexOf("=");
|
|
879
|
+
if (assignmentStart < 0) {
|
|
880
|
+
return startIndex;
|
|
881
|
+
}
|
|
882
|
+
let depth = 0;
|
|
883
|
+
let sawArray = false;
|
|
884
|
+
for (let lineIndex = startIndex; lineIndex < lines.length; lineIndex++) {
|
|
885
|
+
const line = lines[lineIndex] ?? "";
|
|
886
|
+
if (lineIndex > startIndex && /^\s*\[/.test(line) && depth > 0) {
|
|
887
|
+
return lineIndex - 1;
|
|
888
|
+
}
|
|
889
|
+
const scanFrom = lineIndex === startIndex ? assignmentStart + 1 : 0;
|
|
890
|
+
const scan = scanTomlArrayLine(line, scanFrom, depth);
|
|
891
|
+
depth = scan.depth;
|
|
892
|
+
sawArray = sawArray || scan.sawArray;
|
|
893
|
+
if (!sawArray) {
|
|
894
|
+
return startIndex;
|
|
895
|
+
}
|
|
896
|
+
if (depth <= 0) {
|
|
897
|
+
return lineIndex;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return lines.length - 1;
|
|
901
|
+
}
|
|
902
|
+
function scanTomlArrayLine(line, startIndex, initialDepth) {
|
|
903
|
+
let depth = initialDepth;
|
|
904
|
+
let sawArray = false;
|
|
905
|
+
let inString = false;
|
|
906
|
+
let escaped = false;
|
|
907
|
+
for (let charIndex = startIndex; charIndex < line.length; charIndex++) {
|
|
908
|
+
const char = line[charIndex];
|
|
909
|
+
if (escaped) {
|
|
910
|
+
escaped = false;
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
if (char === "\\" && inString) {
|
|
914
|
+
escaped = true;
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (char === '"') {
|
|
918
|
+
inString = !inString;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (char === "#" && !inString) {
|
|
922
|
+
break;
|
|
923
|
+
}
|
|
924
|
+
if (char === "[" && !inString) {
|
|
925
|
+
depth++;
|
|
926
|
+
sawArray = true;
|
|
927
|
+
} else if (char === "]" && !inString) {
|
|
928
|
+
depth--;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return { depth, sawArray };
|
|
932
|
+
}
|
|
933
|
+
function replaceTomlAssignmentValue(line, value) {
|
|
934
|
+
const match = /^(\s*[A-Za-z_][A-Za-z0-9_]*\s*=\s*).*(\r?\n)?$/.exec(line);
|
|
935
|
+
if (!match) {
|
|
936
|
+
return line;
|
|
937
|
+
}
|
|
938
|
+
const [, prefix, newline = ""] = match;
|
|
939
|
+
return `${prefix}${value}${newline}`;
|
|
940
|
+
}
|
|
941
|
+
function replaceCodexAgentEnv(body, agent) {
|
|
942
|
+
const lines = body.match(/^.*(?:\n|$)/gm) ?? [];
|
|
943
|
+
let section = "other";
|
|
944
|
+
let envInsertionIndex = -1;
|
|
945
|
+
let elisymInsertionIndex = -1;
|
|
946
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
947
|
+
const trimmed = line.trim();
|
|
948
|
+
if (trimmed.startsWith("[")) {
|
|
949
|
+
if (section === "env" && envInsertionIndex < 0) {
|
|
950
|
+
envInsertionIndex = lineIndex;
|
|
951
|
+
}
|
|
952
|
+
if (section === "elisym") {
|
|
953
|
+
elisymInsertionIndex = lineIndex;
|
|
954
|
+
}
|
|
955
|
+
const header = parseTomlTableHeader(trimmed);
|
|
956
|
+
if (header === "mcp_servers.elisym") {
|
|
957
|
+
section = "elisym";
|
|
958
|
+
} else if (header === "mcp_servers.elisym.env") {
|
|
959
|
+
section = "env";
|
|
960
|
+
continue;
|
|
961
|
+
} else {
|
|
962
|
+
section = "other";
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (section === "env") {
|
|
966
|
+
if (/^\s*ELISYM_AGENT\s*=/.test(line)) {
|
|
967
|
+
lines[lineIndex] = replaceTomlAssignmentValue(line, quoteTomlString(agent));
|
|
968
|
+
return lines.join("");
|
|
969
|
+
}
|
|
970
|
+
continue;
|
|
971
|
+
}
|
|
972
|
+
if (section === "elisym") {
|
|
973
|
+
elisymInsertionIndex = lineIndex + 1;
|
|
974
|
+
if (/^\s*env\s*=/.test(line)) {
|
|
975
|
+
const nextLine = replaceCodexInlineEnvAgent(line, agent);
|
|
976
|
+
if (nextLine !== null) {
|
|
977
|
+
lines[lineIndex] = nextLine;
|
|
978
|
+
return lines.join("");
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if (section === "env") {
|
|
984
|
+
envInsertionIndex = lines.length;
|
|
985
|
+
} else if (section === "elisym") {
|
|
986
|
+
elisymInsertionIndex = lines.length;
|
|
987
|
+
}
|
|
988
|
+
const agentLine = `ELISYM_AGENT = ${quoteTomlString(agent)}
|
|
989
|
+
`;
|
|
990
|
+
if (envInsertionIndex >= 0) {
|
|
991
|
+
lines.splice(envInsertionIndex, 0, agentLine);
|
|
992
|
+
return lines.join("");
|
|
993
|
+
}
|
|
994
|
+
const insertionIndex = elisymInsertionIndex >= 0 ? elisymInsertionIndex : lines.length;
|
|
995
|
+
lines.splice(insertionIndex, 0, "\n", "[mcp_servers.elisym.env]\n", agentLine);
|
|
996
|
+
return lines.join("");
|
|
997
|
+
}
|
|
998
|
+
function replaceCodexInlineEnvAgent(line, agent) {
|
|
999
|
+
const match = /^(\s*env\s*=\s*\{)(.*)(\}\s*(?:#.*)?(?:\r?\n)?)$/.exec(line);
|
|
1000
|
+
if (!match) {
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
const [, prefix, body, suffix] = match;
|
|
1004
|
+
const entries = splitInlineTableEntries(body);
|
|
1005
|
+
const nextEntries = [];
|
|
1006
|
+
let replaced = false;
|
|
1007
|
+
for (const entry of entries) {
|
|
1008
|
+
if (/^\s*ELISYM_AGENT\s*=/.test(entry)) {
|
|
1009
|
+
const entryMatch = /^(\s*ELISYM_AGENT\s*=\s*).*$/.exec(entry);
|
|
1010
|
+
if (!entryMatch) {
|
|
1011
|
+
return null;
|
|
1012
|
+
}
|
|
1013
|
+
nextEntries.push(`${entryMatch[1]}${quoteTomlString(agent)}`);
|
|
1014
|
+
replaced = true;
|
|
1015
|
+
} else {
|
|
1016
|
+
nextEntries.push(entry);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
if (!replaced) {
|
|
1020
|
+
nextEntries.push(` ELISYM_AGENT = ${quoteTomlString(agent)} `);
|
|
1021
|
+
}
|
|
1022
|
+
return `${prefix}${nextEntries.join(",")}${suffix}`;
|
|
1023
|
+
}
|
|
1024
|
+
function removeCodexElisymTables(raw) {
|
|
1025
|
+
const ranges = findTomlTableRanges(raw).filter((table) => isCodexElisymPath(table.path)).sort((left, right) => right.start - left.start);
|
|
1026
|
+
let nextRaw = raw;
|
|
1027
|
+
for (const range of ranges) {
|
|
1028
|
+
nextRaw = `${nextRaw.slice(0, range.start)}${nextRaw.slice(range.end)}`;
|
|
1029
|
+
}
|
|
1030
|
+
return nextRaw;
|
|
1031
|
+
}
|
|
1032
|
+
function isCodexElisymPath(path) {
|
|
1033
|
+
return path === "mcp_servers.elisym" || path.startsWith("mcp_servers.elisym.");
|
|
1034
|
+
}
|
|
1035
|
+
function replaceCodexBlock(raw, block, replacement) {
|
|
1036
|
+
{
|
|
1037
|
+
let separator = "\n\n";
|
|
1038
|
+
if (raw.length === 0 || raw.endsWith("\n\n")) {
|
|
1039
|
+
separator = "";
|
|
1040
|
+
} else if (raw.endsWith("\n")) {
|
|
1041
|
+
separator = "\n";
|
|
1042
|
+
}
|
|
1043
|
+
return `${raw}${separator}${replacement}`;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async function installToCodexConfig(path, entry, agentRebind) {
|
|
1047
|
+
let raw;
|
|
1048
|
+
try {
|
|
1049
|
+
raw = await readFile(path, "utf-8");
|
|
1050
|
+
} catch (err) {
|
|
1051
|
+
if (err.code !== "ENOENT") {
|
|
1052
|
+
throw err;
|
|
1053
|
+
}
|
|
1054
|
+
await mkdir(dirname(path), { recursive: true });
|
|
1055
|
+
await writeFileAtomic(path, renderCodexTomlBlock(entry), 384);
|
|
1056
|
+
return "installed";
|
|
1057
|
+
}
|
|
1058
|
+
const block = findCodexElisymBlock(raw);
|
|
1059
|
+
if (block) {
|
|
1060
|
+
if (agentRebind === void 0) {
|
|
1061
|
+
return "unchanged";
|
|
1062
|
+
}
|
|
1063
|
+
const env = parseCodexEnv(raw);
|
|
1064
|
+
if (env.ELISYM_AGENT === agentRebind) {
|
|
1065
|
+
return "unchanged";
|
|
1066
|
+
}
|
|
1067
|
+
env.ELISYM_AGENT = agentRebind;
|
|
1068
|
+
const replacement = updateCodexTomlBlock(raw, env, true);
|
|
1069
|
+
await safeRewriteRaw(path, raw, replacement);
|
|
1070
|
+
return "rebound";
|
|
1071
|
+
}
|
|
1072
|
+
await safeRewriteRaw(path, raw, replaceCodexBlock(raw, null, renderCodexTomlBlock(entry)));
|
|
1073
|
+
return "installed";
|
|
1074
|
+
}
|
|
1075
|
+
async function updateCodexConfig(path, agentOverride) {
|
|
1076
|
+
const raw = await readFile(path, "utf-8");
|
|
1077
|
+
const block = findCodexElisymBlock(raw);
|
|
1078
|
+
if (!block) {
|
|
1079
|
+
return "unchanged";
|
|
1080
|
+
}
|
|
1081
|
+
const env = parseCodexEnv(raw);
|
|
1082
|
+
const existingAgentRaw = typeof env.ELISYM_AGENT === "string" ? env.ELISYM_AGENT : void 0;
|
|
1083
|
+
if (existingAgentRaw !== void 0 && agentOverride === void 0) {
|
|
1084
|
+
validateAgentName(existingAgentRaw);
|
|
1085
|
+
}
|
|
1086
|
+
if (agentOverride !== void 0) {
|
|
1087
|
+
env.ELISYM_AGENT = agentOverride;
|
|
1088
|
+
}
|
|
1089
|
+
const replacement = updateCodexTomlBlock(raw, env, agentOverride !== void 0);
|
|
1090
|
+
await safeRewriteRaw(path, raw, replacement);
|
|
1091
|
+
return "updated";
|
|
1092
|
+
}
|
|
1093
|
+
async function uninstallFromCodexConfig(path) {
|
|
1094
|
+
const raw = await readFile(path, "utf-8");
|
|
1095
|
+
const replacement = removeCodexElisymTables(raw);
|
|
1096
|
+
if (replacement === raw) {
|
|
1097
|
+
return "unchanged";
|
|
1098
|
+
}
|
|
1099
|
+
await safeRewriteRaw(path, raw, replacement);
|
|
1100
|
+
return "removed";
|
|
1101
|
+
}
|
|
1102
|
+
async function safeRewriteRaw(path, expectedRaw, nextRaw) {
|
|
1103
|
+
let recheck;
|
|
1104
|
+
try {
|
|
1105
|
+
recheck = await readFile(path, "utf-8");
|
|
1106
|
+
} catch (err) {
|
|
1107
|
+
throw new Error(
|
|
1108
|
+
`${path} disappeared between read and write: ${err.message}. Re-run after the file is restored.`
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
if (recheck !== expectedRaw) {
|
|
1112
|
+
throw new Error(
|
|
1113
|
+
`${path} was modified by another process during update. Close the MCP client and re-run.`
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
await writeFileAtomic(path, nextRaw, 384);
|
|
1117
|
+
}
|
|
690
1118
|
function ensureIrohTransport(agent) {
|
|
691
1119
|
if (agent.irohTransport) {
|
|
692
1120
|
return agent.irohTransport;
|
|
@@ -1036,6 +1464,102 @@ Solana: ${solanaSigner.address}
|
|
|
1036
1464
|
}
|
|
1037
1465
|
})
|
|
1038
1466
|
];
|
|
1467
|
+
var LAMPORTS_PER_SOL = 1000000000n;
|
|
1468
|
+
function readPackageVersion() {
|
|
1469
|
+
try {
|
|
1470
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
1471
|
+
const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf-8"));
|
|
1472
|
+
return pkg.version;
|
|
1473
|
+
} catch {
|
|
1474
|
+
return "0.0.0";
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
var PACKAGE_VERSION = readPackageVersion();
|
|
1478
|
+
function formatSol(lamports) {
|
|
1479
|
+
return `${formatSolNumeric(lamports)} SOL`;
|
|
1480
|
+
}
|
|
1481
|
+
function formatSolNumeric(lamports) {
|
|
1482
|
+
const sign = lamports < 0n ? "-" : "";
|
|
1483
|
+
const abs = lamports < 0n ? -lamports : lamports;
|
|
1484
|
+
const whole = abs / LAMPORTS_PER_SOL;
|
|
1485
|
+
const frac = abs % LAMPORTS_PER_SOL;
|
|
1486
|
+
return `${sign}${whole}.${frac.toString().padStart(9, "0")}`;
|
|
1487
|
+
}
|
|
1488
|
+
function assetFromCardPayment(payment2) {
|
|
1489
|
+
if (!payment2) {
|
|
1490
|
+
return NATIVE_SOL;
|
|
1491
|
+
}
|
|
1492
|
+
const known = resolveKnownAsset(payment2.chain, payment2.token ?? "sol", payment2.mint);
|
|
1493
|
+
if (known) {
|
|
1494
|
+
return known;
|
|
1495
|
+
}
|
|
1496
|
+
if (payment2.token && payment2.symbol && typeof payment2.decimals === "number") {
|
|
1497
|
+
return {
|
|
1498
|
+
chain: payment2.chain,
|
|
1499
|
+
token: payment2.token,
|
|
1500
|
+
mint: payment2.mint,
|
|
1501
|
+
symbol: payment2.symbol,
|
|
1502
|
+
decimals: payment2.decimals
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
return NATIVE_SOL;
|
|
1506
|
+
}
|
|
1507
|
+
function parseSolToLamports(s) {
|
|
1508
|
+
const trimmed = s.trim();
|
|
1509
|
+
if (!trimmed) {
|
|
1510
|
+
throw new Error("amount is empty");
|
|
1511
|
+
}
|
|
1512
|
+
if (trimmed.startsWith("-")) {
|
|
1513
|
+
throw new Error("amount cannot be negative");
|
|
1514
|
+
}
|
|
1515
|
+
if (!/^(\d+\.\d*|\d*\.\d+|\d+)$/.test(trimmed)) {
|
|
1516
|
+
throw new Error(
|
|
1517
|
+
'amount must be a non-negative decimal number (e.g. "0.5", "1", "0.000000001")'
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
const dotPos = trimmed.indexOf(".");
|
|
1521
|
+
if (dotPos === -1) {
|
|
1522
|
+
const whole = BigInt(trimmed);
|
|
1523
|
+
return whole * LAMPORTS_PER_SOL;
|
|
1524
|
+
}
|
|
1525
|
+
const wholePart = dotPos === 0 ? 0n : BigInt(trimmed.slice(0, dotPos));
|
|
1526
|
+
const fracStr = trimmed.slice(dotPos + 1);
|
|
1527
|
+
if (fracStr.length > 9) {
|
|
1528
|
+
throw new Error("too many decimal places (max 9)");
|
|
1529
|
+
}
|
|
1530
|
+
const padded = fracStr.padEnd(9, "0");
|
|
1531
|
+
const frac = BigInt(padded);
|
|
1532
|
+
return wholePart * LAMPORTS_PER_SOL + frac;
|
|
1533
|
+
}
|
|
1534
|
+
function checkLen(field, value, max) {
|
|
1535
|
+
if (new TextEncoder().encode(value).length > max) {
|
|
1536
|
+
throw new Error(`${field} too long (max ${max} bytes)`);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
var MAX_INPUT_LEN = LIMITS.MAX_INPUT_LENGTH;
|
|
1540
|
+
var MAX_CAPABILITIES = LIMITS.MAX_CAPABILITIES;
|
|
1541
|
+
var MAX_TIMEOUT_SECS = LIMITS.MAX_TIMEOUT_SECS;
|
|
1542
|
+
LIMITS.NIP44_MAX_PLAINTEXT_BYTES;
|
|
1543
|
+
LIMITS.MAX_ENCRYPTED_INLINE_BYTES;
|
|
1544
|
+
LIMITS.MAX_REINLINE_TEXT_BYTES;
|
|
1545
|
+
var MAX_NPUB_LEN = 128;
|
|
1546
|
+
var MAX_EVENT_ID_LEN = 128;
|
|
1547
|
+
var MAX_PAYMENT_REQ_LEN = 1e4;
|
|
1548
|
+
var MAX_SOLANA_ADDR_LEN = 64;
|
|
1549
|
+
var _paymentStrategy = null;
|
|
1550
|
+
function payment() {
|
|
1551
|
+
_paymentStrategy ??= new SolanaPaymentStrategy();
|
|
1552
|
+
return _paymentStrategy;
|
|
1553
|
+
}
|
|
1554
|
+
function decodeNpub(npub) {
|
|
1555
|
+
const decoded = nip19.decode(npub);
|
|
1556
|
+
if (decoded.type !== "npub") {
|
|
1557
|
+
throw new Error(`Expected npub, got ${decoded.type}`);
|
|
1558
|
+
}
|
|
1559
|
+
return decoded.data;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/job-input.ts
|
|
1039
1563
|
var execFileP = promisify(execFile);
|
|
1040
1564
|
var MAX_INPUT_PATH_LEN = 4096;
|
|
1041
1565
|
var SENSITIVE_NAME_RE = /(^|[/\\])(\.secrets\.json|\.env(\..+)?|id_rsa|id_dsa|id_ecdsa|id_ed25519|.*-keypair\.json|.*\.pem|.*\.key|\.bashrc|\.bash_profile|\.bash_login|\.bash_logout|\.bash_aliases|\.profile|\.zshrc|\.zprofile|\.zshenv|\.zlogin|\.zlogout|config\.fish|\.gitconfig|\.npmrc|\.netrc|crontab|sudoers|bash\.bashrc|.*\.service|.*\.desktop)$/i;
|
|
@@ -4446,7 +4970,10 @@ program.command("init [name]").description("Create a new agent identity").option
|
|
|
4446
4970
|
}
|
|
4447
4971
|
})
|
|
4448
4972
|
);
|
|
4449
|
-
program.command("install").description("Install elisym MCP server into client configs").option(
|
|
4973
|
+
program.command("install").description("Install elisym MCP server into client configs").option(
|
|
4974
|
+
"--client <name>",
|
|
4975
|
+
"Specific client (claude-desktop, claude-code, cursor, codex, windsurf)"
|
|
4976
|
+
).option("--agent <name>", "Bind to specific agent").option("--list", "List detected clients").action(
|
|
4450
4977
|
safe(async (options) => {
|
|
4451
4978
|
if (options.list) {
|
|
4452
4979
|
await runList();
|
|
@@ -4455,9 +4982,12 @@ program.command("install").description("Install elisym MCP server into client co
|
|
|
4455
4982
|
}
|
|
4456
4983
|
})
|
|
4457
4984
|
);
|
|
4458
|
-
program.command("update").description("
|
|
4985
|
+
program.command("update").description("Force-refresh installed elisym MCP entries to @latest and clear the npx cache").option(
|
|
4986
|
+
"--client <name>",
|
|
4987
|
+
"Specific client (claude-desktop, claude-code, cursor, codex, windsurf)"
|
|
4988
|
+
).option("--agent <name>", "Override the agent binding").action(
|
|
4459
4989
|
safe(async (options) => {
|
|
4460
|
-
await runUpdate({ client: options.client, agent: options.agent });
|
|
4990
|
+
await runUpdate({ client: options.client, agent: options.agent, clearCache: true });
|
|
4461
4991
|
})
|
|
4462
4992
|
);
|
|
4463
4993
|
program.command("uninstall").description("Remove elisym from MCP client configs").option("--client <name>", "Specific client").action(
|