@finchagentic/mcp 4.7.1 → 4.7.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 +74 -39
- package/dist/_zod-helpers.js +10 -0
- package/dist/cli-doctor.js +300 -0
- package/dist/cli-env.js +91 -0
- package/dist/cli-install.js +236 -0
- package/dist/cli-login.js +101 -0
- package/dist/cli-orders.js +175 -0
- package/dist/cli-setup.js +270 -0
- package/dist/cli-ui.js +168 -0
- package/dist/cli-vault.js +75 -0
- package/dist/cli.js +61 -1152
- package/dist/config.js +3 -2
- package/dist/enrichment-router.js +5 -18
- package/dist/finch-output.js +30 -29
- package/dist/finch-status.js +105 -40
- package/dist/index.js +0 -0
- package/dist/local-vault.js +5 -12
- package/dist/output-schemas.js +3 -12
- package/dist/project.js +4 -13
- package/dist/server.js +13 -35
- package/dist/tool-filter.js +4 -13
- package/dist/tools/_solidity-scan.js +5 -14
- package/dist/tools/agents.js +14 -26
- package/dist/tools/deep-research-constants.js +33 -0
- package/dist/tools/deep-research-firecrawl.js +88 -0
- package/dist/tools/deep-research-planning.js +249 -0
- package/dist/tools/deep-research-synthesis.js +343 -0
- package/dist/tools/deep-research-text.js +158 -0
- package/dist/tools/deep-research-tools.js +90 -0
- package/dist/tools/deep-research.js +47 -938
- package/dist/tools/defi.js +4 -3
- package/dist/tools/insider.js +4 -14
- package/dist/tools/insight.js +7 -6
- package/dist/tools/market.js +16 -15
- package/dist/tools/memory.js +57 -62
- package/dist/tools/monitor.js +7 -6
- package/dist/tools/os.js +7 -85
- package/dist/tools/research.js +7 -6
- package/dist/tools/rh-mcp-constants.js +65 -0
- package/dist/tools/rh-mcp-dex.js +107 -0
- package/dist/tools/rh-mcp-provider.js +127 -0
- package/dist/tools/rh-mcp-resolve.js +137 -0
- package/dist/tools/rh-mcp-risk.js +230 -0
- package/dist/tools/rh-mcp-safety.js +234 -0
- package/dist/tools/rh-mcp-swap.js +181 -0
- package/dist/tools/rh-mcp-tools.js +137 -0
- package/dist/tools/rh-mcp.js +75 -1191
- package/dist/tools/scanner.js +10 -9
- package/dist/tools/stake.js +7 -20
- package/dist/tools/vault.js +52 -59
- package/package.json +12 -9
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// `finch setup` - BYOK LLM provider + local memory/vault configuration wizard.
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.setupFlow = setupFlow;
|
|
38
|
+
const readline = __importStar(require("readline"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process = __importStar(require("child_process"));
|
|
43
|
+
const config_js_1 = require("./config.js");
|
|
44
|
+
const clink_input_js_1 = require("./clink-input.js");
|
|
45
|
+
const cli_ui_js_1 = require("./cli-ui.js");
|
|
46
|
+
const PROVIDER_CHOICES = {
|
|
47
|
+
"1": { configKey: "bankrApiKey", envVar: "BANKR_API_KEY", label: "Bankr" },
|
|
48
|
+
"2": { configKey: "anthropicApiKey", envVar: "ANTHROPIC_API_KEY", label: "Anthropic" },
|
|
49
|
+
"3": { configKey: "openaiApiKey", envVar: "OPENAI_API_KEY", label: "OpenAI" },
|
|
50
|
+
};
|
|
51
|
+
const LOCAL_MEMORY_INSTALL_CMD = ["npx", ["-y", "supermemory", "local"]];
|
|
52
|
+
const LOCAL_MEMORY_POLL_MS = 2000;
|
|
53
|
+
const LOCAL_MEMORY_POLL_MAX_MS = 45000;
|
|
54
|
+
const LOCAL_MEMORY_KEY_RE = /\b(sm_[A-Za-z0-9_-]{8,})\b/;
|
|
55
|
+
async function setupFlow() {
|
|
56
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
57
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
58
|
+
console.log(`\n ${cli_ui_js_1.C.cyan}${cli_ui_js_1.C.bold}finch setup${cli_ui_js_1.C.reset}`);
|
|
59
|
+
console.log(` ${cli_ui_js_1.C.dim}Bring your own LLM key and/or run memory fully local - zero cost, zero lock-in.${cli_ui_js_1.C.reset}\n`);
|
|
60
|
+
// ── Step 1: LLM provider ──────────────────────────────────────────────────
|
|
61
|
+
// Say plainly that skipping is fine. Tools return data and structure for the
|
|
62
|
+
// calling model; only `finch run` and scheduled agents need a key of
|
|
63
|
+
// their own, because nothing else is there to do the thinking.
|
|
64
|
+
console.log(` ${cli_ui_js_1.C.dim}Optional. Every MCP tool works without a key - your client's model does the reasoning.${cli_ui_js_1.C.reset}`);
|
|
65
|
+
console.log(` ${cli_ui_js_1.C.dim}A key is what lets finch think on its own: \`finch run\` and scheduled agents.${cli_ui_js_1.C.reset}\n`);
|
|
66
|
+
console.log(` ${cli_ui_js_1.C.dim}[1] Bankr [2] Anthropic [3] OpenAI [4] Custom endpoint (self-hosted/VPS) [5] Skip${cli_ui_js_1.C.reset}\n`);
|
|
67
|
+
const providerChoice = (0, clink_input_js_1.dedupClinkInput)((await ask(` Choose [1-5]: `)).trim());
|
|
68
|
+
const provider = PROVIDER_CHOICES[providerChoice];
|
|
69
|
+
// Tracks whatever key got configured in this step, regardless of which
|
|
70
|
+
// branch set it, so step 2 can forward it to the local-memory subprocess
|
|
71
|
+
// env uniformly instead of only handling the named-provider case.
|
|
72
|
+
let chosenProviderKey;
|
|
73
|
+
let chosenProviderEnvVar;
|
|
74
|
+
if (provider) {
|
|
75
|
+
const key = (0, clink_input_js_1.dedupClinkInput)((await ask(` ${provider.label} API key: `)).trim()).replace(/[^\x20-\x7E]/g, "").trim();
|
|
76
|
+
if (key) {
|
|
77
|
+
(0, config_js_1.writeConfig)({ [provider.configKey]: key });
|
|
78
|
+
process.env[provider.envVar] = key;
|
|
79
|
+
chosenProviderKey = key;
|
|
80
|
+
chosenProviderEnvVar = provider.envVar;
|
|
81
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Saved. ${provider.label} will be used for LLM calls in the interactive shell and MCP server.`);
|
|
82
|
+
console.log(` ${cli_ui_js_1.C.dim}(Stored in ~/.finch/config.json, mode 0600 - same protection as your session token.)${cli_ui_js_1.C.reset}\n`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(`\n ${cli_ui_js_1.C.dim}No key entered - skipped.${cli_ui_js_1.C.reset}\n`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (providerChoice === "4") {
|
|
89
|
+
console.log(` ${cli_ui_js_1.C.dim}Any OpenAI Chat Completions-compatible endpoint works (LiteLLM, vLLM, Ollama, OpenRouter, your own VPS gateway).${cli_ui_js_1.C.reset}`);
|
|
90
|
+
const baseUrl = (0, clink_input_js_1.dedupClinkInput)((await ask(` Base URL (e.g. https://your-vps:8000/v1): `)).trim()).replace(/[^\x20-\x7E]/g, "").trim().replace(/\/+$/, "");
|
|
91
|
+
if (baseUrl) {
|
|
92
|
+
const key = (0, clink_input_js_1.dedupClinkInput)((await ask(` API key (leave blank if your endpoint doesn't need one): `)).trim()).replace(/[^\x20-\x7E]/g, "").trim();
|
|
93
|
+
(0, config_js_1.writeConfig)({ openaiBaseUrl: baseUrl, openaiApiKey: key || "local" });
|
|
94
|
+
process.env.OPENAI_BASE_URL = baseUrl;
|
|
95
|
+
process.env.OPENAI_API_KEY = key || "local";
|
|
96
|
+
chosenProviderKey = key || "local";
|
|
97
|
+
chosenProviderEnvVar = "OPENAI_API_KEY";
|
|
98
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Saved. Requests route to ${baseUrl} using the OpenAI protocol.\n`);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log(`\n ${cli_ui_js_1.C.dim}No URL entered - skipped.${cli_ui_js_1.C.reset}\n`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
console.log(`\n ${cli_ui_js_1.C.dim}Skipped - using Finch proxy.${cli_ui_js_1.C.reset}\n`);
|
|
106
|
+
}
|
|
107
|
+
// ── Step 2: local memory ──────────────────────────────────────────────────
|
|
108
|
+
console.log(` ${cli_ui_js_1.C.cyan}${cli_ui_js_1.C.bold}Local memory${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.dim}(self-hosted - your choice of backend)${cli_ui_js_1.C.reset}`);
|
|
109
|
+
console.log(` ${cli_ui_js_1.C.dim}[1] Simple file-based (recommended) - zero dependency, JSON on disk at ~/.finch/memory/, keyword search only.${cli_ui_js_1.C.reset}`);
|
|
110
|
+
console.log(` ${cli_ui_js_1.C.dim}[2] Supermemory server - real semantic/embedding search, but you run a separate process yourself.${cli_ui_js_1.C.reset}`);
|
|
111
|
+
console.log(` ${cli_ui_js_1.C.dim}[3] Skip - memory tools use the Finch-hosted proxy.${cli_ui_js_1.C.reset}\n`);
|
|
112
|
+
const memChoice = (0, clink_input_js_1.dedupClinkInput)((await ask(` Choose [1-3]: `)).trim());
|
|
113
|
+
if (memChoice === "1") {
|
|
114
|
+
(0, config_js_1.writeConfig)({ memoryBackend: "local-file" });
|
|
115
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Local file memory enabled at ~/.finch/memory/. No server, no key - memory tools run fully local.\n`);
|
|
116
|
+
}
|
|
117
|
+
else if (memChoice === "2") {
|
|
118
|
+
const url = "http://localhost:6767";
|
|
119
|
+
console.log(`\n ${cli_ui_js_1.C.dim}Checking ${url}...${cli_ui_js_1.C.reset}`);
|
|
120
|
+
let reachable = await isLocalMemoryReachableRaw(url);
|
|
121
|
+
let installerError;
|
|
122
|
+
if (!reachable) {
|
|
123
|
+
console.log(` ${cli_ui_js_1.C.dim}Not running - launching \`npx -y supermemory local\` in the background...${cli_ui_js_1.C.reset}`);
|
|
124
|
+
const providerEnv = chosenProviderEnvVar && chosenProviderKey ? { [chosenProviderEnvVar]: chosenProviderKey } : {};
|
|
125
|
+
const result = await launchLocalMemoryServer(url, providerEnv);
|
|
126
|
+
reachable = result.reachable;
|
|
127
|
+
installerError = result.installerError;
|
|
128
|
+
}
|
|
129
|
+
if (reachable) {
|
|
130
|
+
const key = await readLocalMemoryKey();
|
|
131
|
+
if (key) {
|
|
132
|
+
(0, config_js_1.writeConfig)({ memoryBackend: "local", supermemoryUrl: url, supermemoryApiKey: key });
|
|
133
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Local memory enabled at ${url}. Memory tools now run fully local - zero cost, private to this machine.\n`);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
console.log(`\n ${cli_ui_js_1.C.yellow}⚠${cli_ui_js_1.C.reset} Server is running but its API key couldn't be auto-detected.`);
|
|
137
|
+
const manualKey = (0, clink_input_js_1.dedupClinkInput)((await ask(` Paste the key printed by the server (starts with sm_), or press Enter to skip: `)).trim());
|
|
138
|
+
if (manualKey) {
|
|
139
|
+
(0, config_js_1.writeConfig)({ memoryBackend: "local", supermemoryUrl: url, supermemoryApiKey: manualKey });
|
|
140
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Local memory enabled at ${url}.\n`);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.log(`\n ${cli_ui_js_1.C.dim}Skipped - memory tools will keep using the Finch proxy. Run \`finch setup\` again once you have the key.${cli_ui_js_1.C.reset}\n`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
else if (installerError) {
|
|
148
|
+
console.log(`\n ${cli_ui_js_1.C.yellow}⚠${cli_ui_js_1.C.reset} Local install failed: ${installerError}`);
|
|
149
|
+
console.log(` ${cli_ui_js_1.C.dim}Memory tools keep using the Finch proxy until this is resolved. Run \`finch setup\` again after fixing it.${cli_ui_js_1.C.reset}\n`);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.log(`\n ${cli_ui_js_1.C.yellow}⚠${cli_ui_js_1.C.reset} Couldn't reach a local supermemory server after ${LOCAL_MEMORY_POLL_MAX_MS / 1000}s.`);
|
|
153
|
+
console.log(` ${cli_ui_js_1.C.dim}Install it yourself in another terminal: ${cli_ui_js_1.C.cyan}npx -y supermemory local${cli_ui_js_1.C.reset}`);
|
|
154
|
+
console.log(` ${cli_ui_js_1.C.dim}Then run \`finch setup\` again - memory tools keep using the Finch proxy until then.${cli_ui_js_1.C.reset}\n`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.log(`\n ${cli_ui_js_1.C.dim}Skipped - memory tools use the Finch-hosted proxy.${cli_ui_js_1.C.reset}\n`);
|
|
159
|
+
}
|
|
160
|
+
// ── Step 3: local vault ───────────────────────────────────────────────────
|
|
161
|
+
// Unlike local memory, this needs no server - it's a plain on-disk store, so
|
|
162
|
+
// enabling it is a config flip. Data lives under ~/.finch/vault/.
|
|
163
|
+
console.log(` ${cli_ui_js_1.C.cyan}${cli_ui_js_1.C.bold}Local vault${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.dim}(versioned artifacts on your own disk - ~/.finch/vault/)${cli_ui_js_1.C.reset}`);
|
|
164
|
+
console.log(` ${cli_ui_js_1.C.dim}No account, no Convex, no cost. vault_save/read/search/history/diff run fully local.${cli_ui_js_1.C.reset}\n`);
|
|
165
|
+
const enableVault = (0, clink_input_js_1.dedupClinkInput)((await ask(` Enable local vault? [y/N]: `)).trim()).toLowerCase();
|
|
166
|
+
if (enableVault === "y" || enableVault === "yes") {
|
|
167
|
+
(0, config_js_1.writeConfig)({ vaultBackend: "local" });
|
|
168
|
+
console.log(`\n ${cli_ui_js_1.C.green}✓${cli_ui_js_1.C.reset} Local vault enabled. All vault tools now store on this machine - you own the data, no account needed.\n`);
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(`\n ${cli_ui_js_1.C.dim}Skipped - vault tools use the Finch-hosted store (needs \`finch login\`).${cli_ui_js_1.C.reset}\n`);
|
|
172
|
+
}
|
|
173
|
+
rl.close();
|
|
174
|
+
}
|
|
175
|
+
async function isLocalMemoryReachableRaw(url) {
|
|
176
|
+
try {
|
|
177
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(1500) });
|
|
178
|
+
return res.status < 500;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Spawns the local supermemory server detached so it survives after this CLI
|
|
185
|
+
// process exits (same lifecycle model as a local daemon, e.g. Ollama).
|
|
186
|
+
// Captures stdout briefly to look for a printed sm_... key (the binary's
|
|
187
|
+
// first-boot wizard prints one), then stops watching it - the process itself
|
|
188
|
+
// keeps running in the background regardless of whether we caught the key.
|
|
189
|
+
let capturedLocalMemoryKey;
|
|
190
|
+
// Known installer failure signatures worth surfacing verbatim instead of a
|
|
191
|
+
// generic "couldn't reach" message. Confirmed on Windows: the installer
|
|
192
|
+
// shells out via WSL, and fails immediately (before ever listening on the
|
|
193
|
+
// port) if WSL isn't installed/registered - waiting out the full poll
|
|
194
|
+
// window for that case just wastes the user's time.
|
|
195
|
+
const KNOWN_INSTALLER_FAILURES = [
|
|
196
|
+
{ re: /unsupported OS/i, hint: "The installer doesn't support this shell/OS directly (seen from Git Bash/MINGW on Windows)." },
|
|
197
|
+
{ re: /REGDB_E_CLASSNOTREG|Class not registered/i, hint: "The installer needs WSL (Windows Subsystem for Linux) to run its install script, and WSL isn't set up on this machine. Install it with `wsl --install` (needs a restart), then try again." },
|
|
198
|
+
];
|
|
199
|
+
async function launchLocalMemoryServer(url, providerEnv) {
|
|
200
|
+
const [cmd, args] = LOCAL_MEMORY_INSTALL_CMD;
|
|
201
|
+
let installerError;
|
|
202
|
+
// Authoritative "did the process die" signal - independent of whether the
|
|
203
|
+
// regex hints below happen to match. A spawn failure (e.g. npx not found)
|
|
204
|
+
// emits an async 'error' event rather than throwing synchronously, so it
|
|
205
|
+
// is NOT caught by the try/catch around spawn() itself; without this
|
|
206
|
+
// listener it becomes an uncaught exception that crashes the whole CLI.
|
|
207
|
+
let exited = false;
|
|
208
|
+
// Accumulated across all chunks (not tested per-chunk) so a known error
|
|
209
|
+
// string split across two writes still matches.
|
|
210
|
+
let outputBuffer = "";
|
|
211
|
+
try {
|
|
212
|
+
const child = child_process.spawn(cmd, [...args], {
|
|
213
|
+
detached: true,
|
|
214
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
215
|
+
env: { ...process.env, ...providerEnv },
|
|
216
|
+
});
|
|
217
|
+
child.on("error", (err) => {
|
|
218
|
+
exited = true;
|
|
219
|
+
if (!installerError)
|
|
220
|
+
installerError = `Couldn't launch \`${cmd}\`: ${err.message}`;
|
|
221
|
+
});
|
|
222
|
+
child.on("exit", () => { exited = true; });
|
|
223
|
+
const onData = (chunk) => {
|
|
224
|
+
outputBuffer += chunk.toString("utf8");
|
|
225
|
+
const keyMatch = outputBuffer.match(LOCAL_MEMORY_KEY_RE);
|
|
226
|
+
if (keyMatch)
|
|
227
|
+
capturedLocalMemoryKey = keyMatch[1];
|
|
228
|
+
if (!installerError) {
|
|
229
|
+
const known = KNOWN_INSTALLER_FAILURES.find((k) => k.re.test(outputBuffer));
|
|
230
|
+
if (known)
|
|
231
|
+
installerError = known.hint;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
child.stdout?.on("data", onData);
|
|
235
|
+
child.stderr?.on("data", onData);
|
|
236
|
+
child.unref();
|
|
237
|
+
}
|
|
238
|
+
catch (err) {
|
|
239
|
+
return { reachable: false, installerError: `Couldn't launch \`${cmd}\`: ${err.message}` };
|
|
240
|
+
}
|
|
241
|
+
const deadline = Date.now() + LOCAL_MEMORY_POLL_MAX_MS;
|
|
242
|
+
while (Date.now() < deadline) {
|
|
243
|
+
if (await isLocalMemoryReachableRaw(url))
|
|
244
|
+
return { reachable: true };
|
|
245
|
+
// Fail fast once the process has died (confirmed via 'error'/'exit') or
|
|
246
|
+
// a known error signature was recognized - polling further won't help.
|
|
247
|
+
if (installerError || exited)
|
|
248
|
+
return { reachable: false, installerError };
|
|
249
|
+
await new Promise((r) => setTimeout(r, LOCAL_MEMORY_POLL_MS));
|
|
250
|
+
}
|
|
251
|
+
return { reachable: false, installerError };
|
|
252
|
+
}
|
|
253
|
+
async function readLocalMemoryKey() {
|
|
254
|
+
if (capturedLocalMemoryKey)
|
|
255
|
+
return capturedLocalMemoryKey;
|
|
256
|
+
// Fall back to the documented on-disk location ("everything lives in
|
|
257
|
+
// ./.supermemory") - exact path may need adjusting once verified against
|
|
258
|
+
// the real binary; this covers the most likely spot.
|
|
259
|
+
try {
|
|
260
|
+
const candidate = path.join(os.homedir(), ".supermemory", "config.json");
|
|
261
|
+
if (fs.existsSync(candidate)) {
|
|
262
|
+
const data = JSON.parse(fs.readFileSync(candidate, "utf8"));
|
|
263
|
+
const key = data?.apiKey ?? data?.api_key ?? data?.key;
|
|
264
|
+
if (typeof key === "string" && LOCAL_MEMORY_KEY_RE.test(key))
|
|
265
|
+
return key;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch { /* best-effort only */ }
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
package/dist/cli-ui.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared terminal UI: ANSI palette, the startup banner, post-login success
|
|
3
|
+
// block, spinner, in-REPL help text, and the npm update check.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.SEP = exports.C = void 0;
|
|
6
|
+
exports.buildBanner = buildBanner;
|
|
7
|
+
exports.printLoginSuccess = printLoginSuccess;
|
|
8
|
+
exports.spinner = spinner;
|
|
9
|
+
exports.printHelp = printHelp;
|
|
10
|
+
exports.checkForUpdate = checkForUpdate;
|
|
11
|
+
const config_js_1 = require("./config.js");
|
|
12
|
+
const cli_env_js_1 = require("./cli-env.js");
|
|
13
|
+
// ── ANSI ─────────────────────────────────────────────────────────────────────
|
|
14
|
+
exports.C = {
|
|
15
|
+
reset: "\x1b[0m",
|
|
16
|
+
bold: "\x1b[1m",
|
|
17
|
+
dim: "\x1b[2m",
|
|
18
|
+
green: "\x1b[32m",
|
|
19
|
+
cyan: "\x1b[36m",
|
|
20
|
+
violet: "\x1b[35m",
|
|
21
|
+
red: "\x1b[31m",
|
|
22
|
+
yellow: "\x1b[33m",
|
|
23
|
+
white: "\x1b[97m",
|
|
24
|
+
bg: "\x1b[48;5;17m",
|
|
25
|
+
};
|
|
26
|
+
// ── Banner ────────────────────────────────────────────────────────────────────
|
|
27
|
+
//
|
|
28
|
+
// ███╗ ██╗ ██████╗ ███████╗██╗ ██████╗██╗ █████╗ ██╗ ██╗
|
|
29
|
+
// ████╗ ██║██╔═══██╗██╔════╝██║ ██╔════╝██║ ██╔══██╗██║ ██║
|
|
30
|
+
// ██╔██╗ ██║██║ ██║█████╗ ██║ ██║ ██║ ███████║██║ █╗ ██║
|
|
31
|
+
// ██║╚██╗██║██║ ██║██╔══╝ ██║ ██║ ██║ ██╔══██║██║███╗██║
|
|
32
|
+
// ██║ ╚████║╚██████╔╝███████╗███████╗╚██████╗███████╗██║ ██║╚███╔███╔╝
|
|
33
|
+
// ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
|
|
34
|
+
const LOGO_LINES = [
|
|
35
|
+
` ███████╗ ██╗ ███╗ ██╗ ██████╗ ██╗ ██╗`,
|
|
36
|
+
` ██╔════╝ ██║ ████╗ ██║ ██╔════╝ ██║ ██║`,
|
|
37
|
+
` █████╗ ██║ ██╔██╗ ██║ ██║ ███████║`,
|
|
38
|
+
` ██╔══╝ ██║ ██║╚██╗██║ ██║ ██╔══██║`,
|
|
39
|
+
` ██║ ██║ ██║ ╚████║ ╚██████╗ ██║ ██║`,
|
|
40
|
+
` ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝`,
|
|
41
|
+
];
|
|
42
|
+
exports.SEP = ` ${"─".repeat(70)}`;
|
|
43
|
+
function buildBanner() {
|
|
44
|
+
const cfg = (0, config_js_1.readConfig)();
|
|
45
|
+
// Every base_mcp_*/rh_mcp_* tool signs locally via getOrCreateWallet()
|
|
46
|
+
// (~/.finch/wallet.json) on BOTH Base and Robinhood Chain (RH reuses the
|
|
47
|
+
// same local address) - this CLI never touches the account's custodial
|
|
48
|
+
// webapp wallet. Showing that other address here would mismatch what
|
|
49
|
+
// every tool call actually reports and operates on.
|
|
50
|
+
const walletAddr = (0, cli_env_js_1.getLocalWalletAddress)();
|
|
51
|
+
const provider = process.env.BANKR_API_KEY ? "Bankr"
|
|
52
|
+
: process.env.ANTHROPIC_API_KEY ? "Anthropic"
|
|
53
|
+
: process.env.OPENAI_API_KEY ? "OpenAI"
|
|
54
|
+
: "Finch proxy";
|
|
55
|
+
const logo = LOGO_LINES.map(l => `${exports.C.cyan}${exports.C.bold}${l}${exports.C.reset}`).join("\n");
|
|
56
|
+
// ── meta row ──
|
|
57
|
+
const meta = `\n${exports.SEP}\n ${exports.C.dim}v${cli_env_js_1.PKG_VERSION} · ${cli_env_js_1.TOTAL_TOOL_COUNT} tools · finchagentic.com${exports.C.reset}\n${exports.SEP}`;
|
|
58
|
+
// ── auth block ──
|
|
59
|
+
let authBlock;
|
|
60
|
+
if (cfg.sessionToken) {
|
|
61
|
+
const displayName = cfg.name ? `${exports.C.white}${exports.C.bold}${cfg.name}${exports.C.reset}` : "";
|
|
62
|
+
const displayEmail = cfg.email ? `${exports.C.dim}${cfg.email}${exports.C.reset}` : "";
|
|
63
|
+
const nameLine = displayName
|
|
64
|
+
? ` ${exports.C.green}●${exports.C.reset} ${displayName} ${displayEmail}`
|
|
65
|
+
: ` ${exports.C.green}●${exports.C.reset} ${displayEmail || `${exports.C.green}Signed in${exports.C.reset}`}`;
|
|
66
|
+
const walletNote = "Base + Robinhood Chain · local device wallet · keys never leave your machine";
|
|
67
|
+
const walletLine = walletAddr
|
|
68
|
+
? ` ${exports.C.dim}Wallet${exports.C.reset} ${exports.C.cyan}${walletAddr.slice(0, 6)}...${walletAddr.slice(-4)}${exports.C.reset} ${exports.C.dim}· ${walletNote}${exports.C.reset}`
|
|
69
|
+
: ` ${exports.C.dim}Wallet not created yet · auto-creates on first DeFi call${exports.C.reset}`;
|
|
70
|
+
const llmLine = ` ${exports.C.dim}LLM ${exports.C.reset}${exports.C.green}${provider}${exports.C.reset} ${exports.C.dim}· ${cli_env_js_1.TOTAL_TOOL_COUNT} tools active${exports.C.reset}`;
|
|
71
|
+
authBlock = `\n${nameLine}\n${walletLine}\n${llmLine}`;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
authBlock = [
|
|
75
|
+
``,
|
|
76
|
+
` ${exports.C.yellow}○${exports.C.reset} ${exports.C.yellow}Not signed in${exports.C.reset} ${exports.C.dim}- tools that need your account will fail${exports.C.reset}`,
|
|
77
|
+
` ${exports.C.dim}Run ${exports.C.reset}${exports.C.cyan}/login${exports.C.reset}${exports.C.dim} to unlock all ${cli_env_js_1.TOTAL_TOOL_COUNT} tools${exports.C.reset}`,
|
|
78
|
+
` ${exports.C.dim}LLM ${provider} · basic tools still work${exports.C.reset}`,
|
|
79
|
+
].join("\n");
|
|
80
|
+
}
|
|
81
|
+
const hint = `\n${exports.SEP}\n ${exports.C.dim}Type anything to chat · /help · Ctrl+C to exit${exports.C.reset}\n`;
|
|
82
|
+
return `\n${logo}\n${meta}\n${authBlock}\n${hint}`;
|
|
83
|
+
}
|
|
84
|
+
// ── Post-login success block ──────────────────────────────────────────────────
|
|
85
|
+
function printLoginSuccess({ email, name }) {
|
|
86
|
+
// Always show the local per-device wallet: every base_mcp_*/rh_mcp_* tool
|
|
87
|
+
// signs with it on BOTH chains. The account's custodial webapp wallet is a
|
|
88
|
+
// separate address this CLI never touches - showing it here would mismatch
|
|
89
|
+
// what every subsequent tool call actually reports.
|
|
90
|
+
const walletAddr = (0, cli_env_js_1.getLocalWalletAddress)();
|
|
91
|
+
const displayName = name ?? "";
|
|
92
|
+
console.log(`\n${exports.SEP}`);
|
|
93
|
+
if (displayName) {
|
|
94
|
+
console.log(` ${exports.C.green}✓${exports.C.reset} ${exports.C.white}${exports.C.bold}${displayName}${exports.C.reset} ${exports.C.dim}${email}${exports.C.reset}`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.log(` ${exports.C.green}✓${exports.C.reset} ${exports.C.green}${exports.C.bold}Signed in${exports.C.reset} ${exports.C.dim}as ${email}${exports.C.reset}`);
|
|
98
|
+
}
|
|
99
|
+
if (walletAddr) {
|
|
100
|
+
const note = "Base + Robinhood Chain · local device wallet";
|
|
101
|
+
console.log(` ${exports.C.dim}Wallet${exports.C.reset} ${exports.C.cyan}${walletAddr.slice(0, 6)}...${walletAddr.slice(-4)}${exports.C.reset} ${exports.C.dim}· ${note}${exports.C.reset}`);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
console.log(` ${exports.C.dim}Wallet auto-creates on first DeFi tool call${exports.C.reset}`);
|
|
105
|
+
}
|
|
106
|
+
console.log(` ${exports.C.dim}Token saved to ~/.finch/config.json${exports.C.reset}`);
|
|
107
|
+
console.log(` ${exports.C.dim}All ${cli_env_js_1.TOTAL_TOOL_COUNT} tools unlocked${exports.C.reset}`);
|
|
108
|
+
console.log(`${exports.SEP}\n`);
|
|
109
|
+
}
|
|
110
|
+
// ── Spinner ───────────────────────────────────────────────────────────────────
|
|
111
|
+
function spinner(label) {
|
|
112
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
113
|
+
let i = 0;
|
|
114
|
+
const iv = setInterval(() => {
|
|
115
|
+
process.stdout.write(`\r ${exports.C.dim}${frames[i % frames.length]} ${label}${exports.C.reset} `);
|
|
116
|
+
i++;
|
|
117
|
+
}, 80);
|
|
118
|
+
return () => {
|
|
119
|
+
clearInterval(iv);
|
|
120
|
+
process.stdout.write("\r" + " ".repeat(label.length + 12) + "\r");
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// ── Help ─────────────────────────────────────────────────────────────────────
|
|
124
|
+
function printHelp() {
|
|
125
|
+
const cfg = (0, config_js_1.readConfig)();
|
|
126
|
+
const authLine = cfg.email
|
|
127
|
+
? ` ${exports.C.dim}Signed in as ${exports.C.reset}${exports.C.green}${cfg.email}${exports.C.reset}`
|
|
128
|
+
: ` ${exports.C.yellow}⚠${exports.C.reset} ${exports.C.dim}Not signed in - run /login to unlock all tools${exports.C.reset}`;
|
|
129
|
+
console.log(`
|
|
130
|
+
${exports.C.cyan}Commands:${exports.C.reset}
|
|
131
|
+
/login Sign in to unlock all ${cli_env_js_1.TOTAL_TOOL_COUNT} tools
|
|
132
|
+
/logout Sign out and clear saved token
|
|
133
|
+
/clear Clear conversation history
|
|
134
|
+
/tools List all available tools
|
|
135
|
+
/quit Exit
|
|
136
|
+
|
|
137
|
+
${authLine}
|
|
138
|
+
|
|
139
|
+
${exports.C.dim}Examples:
|
|
140
|
+
remember that I prefer concise answers
|
|
141
|
+
search the web for recent AI news
|
|
142
|
+
save a note to my vault
|
|
143
|
+
research "top AI agent frameworks in 2025"
|
|
144
|
+
spawn an agent to monitor competitor releases weekly${exports.C.reset}
|
|
145
|
+
`);
|
|
146
|
+
}
|
|
147
|
+
// ── Version check ─────────────────────────────────────────────────────────────
|
|
148
|
+
async function checkForUpdate() {
|
|
149
|
+
try {
|
|
150
|
+
const res = await fetch("https://registry.npmjs.org/@finchagentic/mcp/latest", {
|
|
151
|
+
signal: AbortSignal.timeout(5000),
|
|
152
|
+
});
|
|
153
|
+
if (!res.ok)
|
|
154
|
+
return;
|
|
155
|
+
const data = await res.json();
|
|
156
|
+
const latest = data.version;
|
|
157
|
+
if (!latest || latest === cli_env_js_1.PKG_VERSION)
|
|
158
|
+
return;
|
|
159
|
+
const sep = ` ${"─".repeat(58)}`;
|
|
160
|
+
console.log(`\n${sep}`);
|
|
161
|
+
console.log(` ${exports.C.yellow}⚠${exports.C.reset} Update available: ${exports.C.yellow}v${cli_env_js_1.PKG_VERSION}${exports.C.reset} → ${exports.C.cyan}v${latest}${exports.C.reset}`);
|
|
162
|
+
console.log(` ${exports.C.dim}npm install -g @finchagentic/mcp@${latest}${exports.C.reset} ${exports.C.dim}or restart your MCP client${exports.C.reset}`);
|
|
163
|
+
console.log(`${sep}\n`);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// silently ignore
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// `finch vault` - inspect the local, user-owned vault.
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.vaultFlow = vaultFlow;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const config_js_1 = require("./config.js");
|
|
42
|
+
const cli_ui_js_1 = require("./cli-ui.js");
|
|
43
|
+
function vaultFlow() {
|
|
44
|
+
const cfg = (0, config_js_1.readConfig)();
|
|
45
|
+
const dir = path.join(os.homedir(), ".finch", "vault");
|
|
46
|
+
const shortDir = dir.replace(os.homedir(), "~");
|
|
47
|
+
const SEP_V = ` ${"─".repeat(52)}`;
|
|
48
|
+
console.log(`\n ${cli_ui_js_1.C.cyan}${cli_ui_js_1.C.bold}finch vault${cli_ui_js_1.C.reset}\n`);
|
|
49
|
+
if (cfg.vaultBackend !== "local") {
|
|
50
|
+
console.log(` ${cli_ui_js_1.C.yellow}○${cli_ui_js_1.C.reset} Local vault is ${cli_ui_js_1.C.yellow}off${cli_ui_js_1.C.reset} - vault tools use the hosted store (needs \`finch login\`).`);
|
|
51
|
+
console.log(` ${cli_ui_js_1.C.dim}Turn it on:${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.cyan}finch setup${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.dim}(answer "y" to local vault) - then your data lives here, on your machine.${cli_ui_js_1.C.reset}\n`);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
let entries = 0, versions = 0, creds = 0;
|
|
55
|
+
try {
|
|
56
|
+
const idx = JSON.parse(fs.readFileSync(path.join(dir, "index.json"), "utf8"));
|
|
57
|
+
const e = idx.entries ?? {};
|
|
58
|
+
entries = Object.keys(e).length;
|
|
59
|
+
versions = Object.values(e).reduce((n, x) => n + (x?.versions?.length ?? 0), 0);
|
|
60
|
+
}
|
|
61
|
+
catch { /* no index yet */ }
|
|
62
|
+
try {
|
|
63
|
+
creds = Object.keys(JSON.parse(fs.readFileSync(path.join(dir, "credentials.json"), "utf8"))).length;
|
|
64
|
+
}
|
|
65
|
+
catch { /* none */ }
|
|
66
|
+
console.log(` ${cli_ui_js_1.C.green}●${cli_ui_js_1.C.reset} Local vault is ${cli_ui_js_1.C.green}on${cli_ui_js_1.C.reset} - your data, on your machine, no account.`);
|
|
67
|
+
console.log(`${SEP_V}`);
|
|
68
|
+
console.log(` ${cli_ui_js_1.C.dim}Location ${cli_ui_js_1.C.reset}${shortDir}`);
|
|
69
|
+
console.log(` ${cli_ui_js_1.C.dim}Contents ${cli_ui_js_1.C.reset}${entries} entr${entries === 1 ? "y" : "ies"} ${cli_ui_js_1.C.dim}·${cli_ui_js_1.C.reset} ${versions} version${versions === 1 ? "" : "s"} ${cli_ui_js_1.C.dim}·${cli_ui_js_1.C.reset} ${creds} credential${creds === 1 ? "" : "s"} ${cli_ui_js_1.C.dim}(encrypted)${cli_ui_js_1.C.reset}`);
|
|
70
|
+
console.log(`${SEP_V}`);
|
|
71
|
+
console.log(` ${cli_ui_js_1.C.dim}It's a plain folder - back it up or sync it however you like:${cli_ui_js_1.C.reset}`);
|
|
72
|
+
console.log(` ${cli_ui_js_1.C.cyan}cp -r ${shortDir} ~/backup${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.dim}# copy${cli_ui_js_1.C.reset}`);
|
|
73
|
+
console.log(` ${cli_ui_js_1.C.cyan}git -C ${shortDir} init${cli_ui_js_1.C.reset} ${cli_ui_js_1.C.dim}# version-control it${cli_ui_js_1.C.reset}`);
|
|
74
|
+
console.log(` ${cli_ui_js_1.C.dim}Nothing leaves this machine unless you move it.${cli_ui_js_1.C.reset}\n`);
|
|
75
|
+
}
|