diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index c9e5a7c..c0af452 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,14 +6,14 @@ }, "metadata": { "description": "Sovereign, decay-aware memory for AI coding agents on Arkiv. Your sessions become a memory your agent owns.", - "version": "0.1.0" + "version": "0.1.1" }, "plugins": [ { "name": "cortex-memory", "source": "./cortex-plugin", "description": "Every Claude Code session becomes a memory node: auto-captured before the context compacts and written to Arkiv (wallet-encrypted), recalled at session start so you never re-explain your project. Adds the cortex_recall / cortex_act / cortex_store_document / cortex_summarize_session MCP tools and a recall→cite→store working-agreement skill.", - "version": "0.1.0", + "version": "0.1.1", "keywords": ["memory", "arkiv", "recall", "sovereign", "agent-memory"] } ] diff --git a/.github/workflows/dist-check.yml b/.github/workflows/dist-check.yml new file mode 100644 index 0000000..ce5e98c --- /dev/null +++ b/.github/workflows/dist-check.yml @@ -0,0 +1,37 @@ +name: plugin-dist-check + +# Guards against the stale-bundle class of bug: the committed cortex-plugin/dist +# bundles MUST match what `bun run build:plugin` produces from src. If a source fix +# lands without rebuilding dist, marketplace installers silently run pre-fix code. +# This job rebuilds and fails the PR if the committed dist differs. + +on: + pull_request: + paths: + - "src/**" + - "scripts/**" + - "ui/connect/**" + - "cortex-plugin/dist/**" + - "scripts/build-plugin.ts" + - ".github/workflows/dist-check.yml" + push: + branches: [main] + +jobs: + dist-matches-src: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + - run: bun install --frozen-lockfile + - name: Rebuild plugin bundles + run: bun run build:plugin + - name: Fail if committed dist is stale + run: | + if ! git diff --exit-code -- cortex-plugin/dist; then + echo "::error::cortex-plugin/dist is out of date with src. Run 'bun run build:plugin' and commit the result." + exit 1 + fi + echo "✓ cortex-plugin/dist matches a fresh build from src." diff --git a/.gitignore b/.gitignore index 1026fd1..3f9d2ce 100644 --- a/.gitignore +++ b/.gitignore @@ -28,10 +28,13 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json .cache *.tsbuildinfo -# Next.js (distDir: dist in next.config.ts for Vercel output path) +# Next.js (distDir: dist in next.config.ts for Vercel output path). +# Anchored to repo root — an unanchored `dist/`/`out/` would also match +# cortex-plugin/dist (the standalone plugin bundles that MUST ship) and silently +# drop newly-hashed connect assets from commits + the CI dist-check. .next/ -dist/ -out/ +/dist/ +/out/ # Copied at build time from assets/ (see package.json build script) public/ diff --git a/README.md b/README.md index 8059239..b1f852f 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,19 @@ One repo — not a monorepo. `app/` + `src/` + `cortex-plugin/` ship together. Agent surface: **`recall(query, k)`** and **`act(action, citations[])`** only. -### Live console (`/console`) - -An autonomous loop (server session key) recalls and cites on a timer; each step emits typed events on **`/sse`**. The UI shows Braga tx links, topology graph, and manual query/cite. **File upload** uses your **browser wallet** on Braga (prepare on server → sign tx in MetaMask). +### Where it runs + +**Cortex has no backend you depend on.** The product is the Claude Code plugin: it +runs **locally** in your agent — the MCP server speaks over stdio via `bun`, the +SQLite mirror lives on your disk, and writes are signed by **your own funded +session key**. Nothing requires the maintainer's infrastructure. + +The website is a **landing + install + video** surface, not a live autonomous demo. +The `/console` loop, mirror, and SSE stream are for **local development** (`bun run dev`) +— they are stateful and long-running, which serverless cannot host, so the public +deployment does not run them. For the autonomous loop in action, see the +[video walkthrough](https://www.loom.com/share/68178caad4034e8282ac412a440e0738); for +real on-chain evidence, see [`docs/proof/`](./docs/proof/). --- diff --git a/cortex-plugin/.claude-plugin/plugin.json b/cortex-plugin/.claude-plugin/plugin.json index 2e698ae..12786a7 100644 --- a/cortex-plugin/.claude-plugin/plugin.json +++ b/cortex-plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "cortex-memory", - "version": "0.1.0", + "version": "0.1.1", "description": "Every Claude Code session becomes a sovereign memory node: auto-captured before compaction and saved to Arkiv, recalled at session start, owned by your wallet. Reuses the Cortex decay-aware memory engine.", "author": { "name": "Cortex" diff --git a/cortex-plugin/README.md b/cortex-plugin/README.md index a60892e..17714c4 100644 --- a/cortex-plugin/README.md +++ b/cortex-plugin/README.md @@ -30,6 +30,19 @@ Memories that get cited grow their lease (accumulative extend); memories that go unused decay for free. Same wallet → same key → a fresh machine can re-sync and decrypt your memory from the public Arkiv RPC. No key escrow. +## Prerequisites + +- **`bun` on your PATH.** The hooks, MCP server, and `cortex auth` run as bundled + `bun` scripts over stdio. Install from [bun.sh](https://bun.sh) if you don't have it. +- **A funded session key on Braga.** `cortex auth` generates a session-key EOA and + prints its address. Fund it on the [Braga faucet](https://braga.hoodi.arkiv.network/faucet/) + **before** any Arkiv write (store / cite / extend) — an unfunded key cannot pay for + the transaction. + +There is **no backend to depend on**: everything runs locally in your Claude Code +on your machine — the MCP server over stdio, a SQLite mirror on your disk, and writes +signed by your own funded session key. + ## Install ### Marketplace (recommended) @@ -69,11 +82,20 @@ run `bun run build:plugin` to produce those bundles. **MCP without the plugin:** `bun run mcp` from the repo root (stdio server for Cursor and other MCP clients). -## Required environment +## Configuration + +**After `cortex auth`, no environment variables are required.** `cortex auth` writes +`~/.cortex/config.json` (your owner wallet address, a generated session-key private +key, an EIP-191 user signature, and optionally an embeddings key), and the MCP server +and session hooks read their credentials from that file. Run it once after install and +you're done. + +Capture/recall degrade gracefully — without credentials, summaries queue locally and +sealed memories simply don't surface (no crash). -Capture/recall degrade gracefully — without these, summaries queue locally and -sealed memories simply don't surface (no crash). To actually write to and read -from Arkiv: +The variables below are an **advanced / dev-only override**: if set in the environment +(or a repo-root `.env`, which Bun auto-loads), they take precedence over +`~/.cortex/config.json`. A normal plugin user does not need to set any of them. | Variable | Purpose | Required for | |---|---|---| @@ -84,7 +106,9 @@ from Arkiv: | `USER_PRIMARY_ADDRESS` | Owner EOA, used by `cortex_act` to attribute tier promotions. | `cortex_act` | | `CORTEX_PLUGIN_DATA_DIR` | Optional. Where queued/pending summaries live. Default: `~/.cortex/plugin`. | — | -Bun auto-loads `.env`, so a `.env` at the repo root is the simplest setup. +For a normal install, `cortex auth` → `~/.cortex/config.json` is the simplest setup and +no `.env` is needed. For clone-based dev, Bun auto-loads a repo-root `.env` if you +prefer to override via env vars. ## Safety / design notes diff --git a/cortex-plugin/commands/auth.md b/cortex-plugin/commands/auth.md index c0c023d..ce54431 100644 --- a/cortex-plugin/commands/auth.md +++ b/cortex-plugin/commands/auth.md @@ -9,6 +9,11 @@ Run the Cortex onboarding flow: it generates a local session key, opens your browser to connect your wallet, you sign once, and it writes `~/.cortex/config.json` so the plugin can read/write your sovereign memory on Arkiv. +> **Requires [`bun`](https://bun.sh) on your PATH.** The plugin's hooks, MCP server, +> and this command all run as bundled `bun` scripts. If `bun` isn't installed you'll +> see `command not found: bun` — install it (`curl -fsSL https://bun.sh/install | bash`) +> and re-run. No other global install is needed. + Run this command: ```bash diff --git a/cortex-plugin/dist/cortex-drain.js b/cortex-plugin/dist/cortex-drain.js index 5b78ad3..dc03763 100755 --- a/cortex-plugin/dist/cortex-drain.js +++ b/cortex-plugin/dist/cortex-drain.js @@ -19373,6 +19373,391 @@ var init_events = __esm(() => { wrappedListeners = new Set; }); +// src/compression/fht.ts +function log2PowerOfTwo(n) { + if (n <= 0) + return -1; + let k = 0; + let v = n; + while ((v & 1) === 0) { + v >>= 1; + k++; + } + return v === 1 ? k : -1; +} +function fastHadamardTransform(x) { + const D = x.length; + const logD = log2PowerOfTwo(D); + if (logD < 0) { + throw new Error(`fastHadamardTransform: length must be a power of two, got ${D}`); + } + let h = 1; + while (h < D) { + const twoH = h << 1; + for (let i = 0;i < D; i += twoH) { + for (let j = i;j < i + h; j++) { + const a = x[j]; + const b = x[j + h]; + x[j] = a + b; + x[j + h] = a - b; + } + } + h = twoH; + } + const invSqrtD = 1 / Math.sqrt(D); + for (let i = 0;i < D; i++) { + x[i] = x[i] * invSqrtD; + } +} +function makeXorshift128(seedHex) { + const FNV_OFFSET = 2166136261; + const FNV_PRIME = 16777619; + const seeds = new Uint32Array(4); + for (let k = 0;k < 4; k++) { + let h = (FNV_OFFSET ^ k * 2654435769) >>> 0; + for (let i = 0;i < seedHex.length; i++) { + h ^= seedHex.charCodeAt(i); + h = Math.imul(h, FNV_PRIME) >>> 0; + } + seeds[k] = h === 0 ? 2654435769 : h; + } + let s0 = seeds[0]; + let s1 = seeds[1]; + let s2 = seeds[2]; + let s3 = seeds[3]; + return function next() { + let t = s0 ^ s0 << 11; + t ^= t >>> 8; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = s3 ^ s3 >>> 19 ^ (t ^ t >>> 8); + return s3 >>> 0; + }; +} +function rotateWithSeed(x, seedHex) { + const D = x.length; + const rng = makeXorshift128(seedHex); + for (let i = 0;i < D; i += 32) { + const word = rng(); + const lim = Math.min(32, D - i); + for (let b = 0;b < lim; b++) { + const bit = word >>> b & 1; + if (bit === 0) + x[i + b] = -x[i + b]; + } + } + fastHadamardTransform(x); +} + +// src/compression/rabitq.ts +function f32ToF16(value) { + f32[0] = value; + const x = u322[0]; + const sign2 = x >>> 16 & 32768; + let mant = x & 8388607; + let exp = x >>> 23 & 255; + if (exp === 255) { + return sign2 | 31744 | (mant !== 0 ? 512 | mant >>> 13 : 0); + } + let newExp = exp - 127 + 15; + if (newExp >= 31) { + return sign2 | 31744; + } + if (newExp <= 0) { + if (newExp < -10) + return sign2; + mant = (mant | 8388608) >>> 1 - newExp; + if ((mant & 4096) !== 0) + mant += 8192; + return sign2 | mant >>> 13; + } + if ((mant & 4096) !== 0) { + mant += 8192; + if ((mant & 8388608) !== 0) { + mant = 0; + newExp++; + if (newExp >= 31) + return sign2 | 31744; + } + } + return sign2 | newExp << 10 | mant >>> 13; +} +function padToRotationDim(vec) { + const out = new Float32Array(PADDED_DIM); + const n = Math.min(vec.length, EMBED_DIM); + for (let i = 0;i < n; i++) + out[i] = vec[i]; + return out; +} +function l2Norm(vec) { + let s = 0; + for (let i = 0;i < vec.length; i++) { + const v = vec[i]; + s += v * v; + } + return Math.sqrt(s); +} +function rotateUnit(vec) { + const padded = padToRotationDim(vec); + const norm = l2Norm(padded); + if (norm > 0) { + const inv = 1 / norm; + for (let i = 0;i < PADDED_DIM; i++) + padded[i] = padded[i] * inv; + } + rotateWithSeed(padded, ROTATION_SEED); + return { rotated: padded, norm }; +} +function packSigns(rotated) { + const out = new Uint8Array(SIGN_BYTES); + for (let i = 0;i < EMBED_DIM; i++) { + if (rotated[i] >= 0) { + const byteIdx = i >>> 3; + const bitInByte = 7 - (i & 7); + out[byteIdx] = out[byteIdx] | 1 << bitInByte; + } + } + return out; +} +function rabitqEncode(vec) { + const { rotated, norm } = rotateUnit(vec); + const signs = packSigns(rotated); + const invSqrtD = 1 / Math.sqrt(EMBED_DIM); + let align = 0; + for (let i = 0;i < EMBED_DIM; i++) { + const r = rotated[i]; + align += r >= 0 ? r : -r; + } + align *= invSqrtD; + return { + signs, + normFp16: f32ToF16(norm), + alignFp16: f32ToF16(align) + }; +} +function packCode(code) { + if (code.signs.length !== SIGN_BYTES) { + throw new Error(`packCode: signs must be ${SIGN_BYTES} bytes, got ${code.signs.length}`); + } + const out = new Uint8Array(PACK_SIZE); + out.set(code.signs, 0); + out[NORM_OFFSET] = code.normFp16 & 255; + out[NORM_OFFSET + 1] = code.normFp16 >>> 8 & 255; + out[ALIGN_OFFSET] = code.alignFp16 & 255; + out[ALIGN_OFFSET + 1] = code.alignFp16 >>> 8 & 255; + out[CENTROID_OFFSET] = 0; + out[CENTROID_OFFSET + 1] = 0; + return out; +} +var EMBED_DIM = 1536, PADDED_DIM = 2048, SIGN_BYTES, ROTATION_SEED = "cortex.rabitq.rotation.v1", NORM_OFFSET, ALIGN_OFFSET, CENTROID_OFFSET, PACK_SIZE, f32, u322; +var init_rabitq = __esm(() => { + SIGN_BYTES = EMBED_DIM >> 3; + NORM_OFFSET = SIGN_BYTES; + ALIGN_OFFSET = SIGN_BYTES + 2; + CENTROID_OFFSET = SIGN_BYTES + 4; + PACK_SIZE = SIGN_BYTES + 2 + 2 + 2; + f32 = new Float32Array(1); + u322 = new Uint32Array(f32.buffer); +}); + +// src/compression/embeddings.ts +var exports_embeddings = {}; +__export(exports_embeddings, { + isUsableEmbeddingKey: () => isUsableEmbeddingKey, + isMissingEmbeddingKey: () => isMissingEmbeddingKey, + hasEmbeddingKey: () => hasEmbeddingKey, + embedText: () => embedText, + embedAndQuantize: () => embedAndQuantize, + MissingEmbeddingKeyError: () => MissingEmbeddingKeyError, + EMBEDDING_SETUP_MESSAGE: () => EMBEDDING_SETUP_MESSAGE +}); +function isMissingEmbeddingKey(err) { + return err instanceof MissingEmbeddingKeyError || typeof err === "object" && err !== null && "isMissingEmbeddingKey" in err; +} +function isUsableEmbeddingKey(key) { + if (typeof key !== "string") + return false; + const v = key.trim(); + if (v.length < 16) + return false; + if (/\.{2,}|\u2026|placeholder|your[-_]?key/i.test(v)) + return false; + return true; +} +function hasEmbeddingKey() { + return resolveCredentials().embedding !== null; +} +function toFloat32(arr, provider) { + if (!Array.isArray(arr)) { + throw new Error(`embedText: unexpected ${provider} response shape`); + } + if (arr.length !== EMBED_DIM2) { + throw new Error(`embedText: expected ${EMBED_DIM2}-d from ${provider}, got ${arr.length}. ` + `RaBitQ requires exactly ${EMBED_DIM2}-d \u2014 set OPENROUTER_EMBED_MODEL to a 1536-d model.`); + } + const out = new Float32Array(EMBED_DIM2); + for (let i = 0;i < EMBED_DIM2; i++) + out[i] = arr[i]; + return out; +} +async function embedViaOpenAI(text, apiKey) { + const res = await fetch(OPENAI_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: OPENAI_MODEL, + input: [text], + dimensions: EMBED_DIM2, + encoding_format: "float" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: OpenAI request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json = await res.json(); + const first = json.data?.[0]?.embedding; + return toFloat32(first, `OpenAI(${OPENAI_MODEL})`); +} +async function embedViaOpenRouter(text, apiKey) { + const res = await fetch(OPENROUTER_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: OPENROUTER_MODEL, + input: [text], + encoding_format: "float" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: OpenRouter request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json = await res.json(); + const first = json.data?.[0]?.embedding; + return toFloat32(first, `OpenRouter(${OPENROUTER_MODEL})`); +} +async function embedViaVoyage(text, apiKey) { + const res = await fetch(VOYAGE_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: VOYAGE_MODEL, + input: [text], + input_type: "document" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: Voyage request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json = await res.json(); + const first = json.data?.[0]?.embedding; + return toFloat32(first, `Voyage(${VOYAGE_MODEL})`); +} +async function embedViaCohere(text, apiKey) { + const res = await fetch(COHERE_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: COHERE_MODEL, + texts: [text], + input_type: "search_document", + embedding_types: ["float"], + output_dimension: EMBED_DIM2 + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: Cohere request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json = await res.json(); + const first = json.embeddings?.float?.[0]; + return toFloat32(first, "Cohere"); +} +async function embedText(text) { + if (typeof text !== "string" || text.length === 0) { + throw new Error("embedText: input text must be a non-empty string"); + } + const emb = resolveCredentials().embedding; + if (!emb) + throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); + switch (emb.provider) { + case "openrouter": + return embedViaOpenRouter(text, emb.key); + case "voyage": + return embedViaVoyage(text, emb.key); + case "cohere": + return embedViaCohere(text, emb.key); + case "openai": + default: + return embedViaOpenAI(text, emb.key); + } +} +async function embedAndQuantize(text) { + const rawEmbedding = await embedText(text); + const t0 = performance.now(); + const code = rabitqEncode(rawEmbedding); + const bytes = packCode(code); + const ms = performance.now() - t0; + publish({ + type: "rabitq.encoded", + ts: Date.now(), + dim: EMBED_DIM2, + bytes: bytes.byteLength, + ratio: EMBED_DIM2 * 4 / bytes.byteLength, + ms + }); + return { bytes, rawEmbedding }; +} +var EMBED_DIM2 = 1536, EMBED_FETCH_TIMEOUT_MS = 30000, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", OPENAI_MODEL, OPENROUTER_EMBED_URL = "https://openrouter.ai/api/v1/embeddings", OPENROUTER_MODEL, VOYAGE_EMBED_URL = "https://api.voyageai.com/v1/embeddings", VOYAGE_MODEL, COHERE_EMBED_URL = "https://api.cohere.com/v2/embed", COHERE_MODEL = "embed-v4.0", MissingEmbeddingKeyError, EMBEDDING_SETUP_MESSAGE; +var init_embeddings = __esm(() => { + init_rabitq(); + init_events(); + init_credentials(); + OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; + OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; + VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; + MissingEmbeddingKeyError = class MissingEmbeddingKeyError extends Error { + isMissingEmbeddingKey = true; + constructor(message) { + super(message); + this.name = "MissingEmbeddingKeyError"; + } + }; + EMBEDDING_SETUP_MESSAGE = [ + "Cortex needs an embedding API key to turn your notes into searchable memory.", + "", + "Add ONE of these to your environment (your shell profile, or a .env in your project):", + " \u2022 OPENAI_API_KEY=sk-\u2026 \u2190 get one at https://platform.openai.com/api-keys", + " \u2022 OPENROUTER_API_KEY=sk-or-\u2026 \u2190 or https://openrouter.ai/keys", + " \u2022 VOYAGE_API_KEY=\u2026 \u2190 Claude/Anthropic users: Anthropic has no embeddings", + " API, so use Voyage (their recommended partner):", + " https://dashboard.voyageai.com/", + " \u2022 COHERE_API_KEY=\u2026 \u2190 or https://dashboard.cohere.com/api-keys", + "", + "Then restart your session. (Your text is only sent to that provider to embed;", + "the memory itself is encrypted with your wallet and stored on Arkiv.)" + ].join(` +`); +}); + // src/lib/cortex-config.ts import { homedir } from "os"; import { join, dirname } from "path"; @@ -19399,11 +19784,96 @@ function readConfig() { var _cached; var init_cortex_config = () => {}; +// src/lib/credentials.ts +function validPk(v) { + return typeof v === "string" && PK_RE.test(v) ? v : null; +} +function validEoa(v) { + return typeof v === "string" && EOA_RE.test(v) ? v : null; +} +function validSig(v) { + return typeof v === "string" && SIG_RE.test(v) ? v : null; +} +function deriveAddressFromPk(pk) { + try { + return privateKeyToAccount(pk).address; + } catch { + return null; + } +} +function resolveEmbedding() { + const envProviders = [ + ["OPENAI_API_KEY", "openai"], + ["OPENROUTER_API_KEY", "openrouter"], + ["VOYAGE_API_KEY", "voyage"], + ["COHERE_API_KEY", "cohere"] + ]; + for (const [envName, provider] of envProviders) { + const v = process.env[envName]; + if (isUsableEmbeddingKey(v)) + return { value: { key: v.trim(), provider }, source: "env" }; + } + const cfg = readConfig(); + if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { + return { + value: { key: cfg.embeddingKey.trim(), provider: cfg.embeddingProvider ?? "openai" }, + source: "config" + }; + } + return { value: null, source: "none" }; +} +function resolveCredentials() { + const cfg = readConfig(); + const skEnv = validPk(process.env.SESSION_KEY_PRIVATE_KEY); + const skCfg = validPk(cfg?.sessionKeyPrivate); + const sessionKeyPrivate = skEnv ?? skCfg; + const sessionKeySource = skEnv ? "env" : skCfg ? "config" : "none"; + const userPrivateKey = validPk(process.env.CORTEX_USER_PRIVATE_KEY); + const ownerEnv = validEoa(process.env.USER_PRIMARY_ADDRESS); + const ownerCfg = validEoa(cfg?.ownerAddress); + let ownerEOA = ownerEnv ?? ownerCfg; + let ownerSource = ownerEnv ? "env" : ownerCfg ? "config" : "none"; + if (!ownerEOA && userPrivateKey) { + const derived = deriveAddressFromPk(userPrivateKey); + if (derived) { + ownerEOA = derived; + ownerSource = "derived"; + } + } + const sigEnv = validSig(process.env.CORTEX_USER_SIGNATURE); + const sigCfg = validSig(cfg?.userSignature); + const userSignature = sigEnv ?? sigCfg; + const signatureSource = sigEnv ? "env" : sigCfg ? "config" : "none"; + const emb = resolveEmbedding(); + return { + sessionKeyPrivate, + ownerEOA, + userSignature, + userPrivateKey, + embedding: emb.value, + source: { + sessionKey: sessionKeySource, + owner: ownerSource, + signature: signatureSource, + embedding: emb.source + } + }; +} +var EOA_RE, PK_RE, SIG_RE; +var init_credentials = __esm(() => { + init_accounts(); + init_embeddings(); + init_cortex_config(); + EOA_RE = /^0x[0-9a-fA-F]{40}$/; + PK_RE = /^0x[0-9a-fA-F]{64}$/; + SIG_RE = /^0x[0-9a-fA-F]+$/; +}); + // src/lib/arkiv-client.ts function getWalletClient() { if (_walletClient) return _walletClient; - const pk = process.env.SESSION_KEY_PRIVATE_KEY ?? readConfig()?.sessionKeyPrivate; + const pk = resolveCredentials().sessionKeyPrivate; if (!pk) { throw new Error("No session key. Run `cortex auth` (connect your wallet) \u2014 or set " + "SESSION_KEY_PRIVATE_KEY and fund the EOA via " + BRAGA.faucet); } @@ -19465,7 +19935,7 @@ var init_arkiv_client = __esm(() => { init_chains(); init_constants(); init_events(); - init_cortex_config(); + init_credentials(); }); // src/lib/errors.ts @@ -19594,23 +20064,17 @@ __export(exports_owner_identity, { _peekCached: () => _peekCached }); async function resolveFromEnv() { - const addr = process.env.USER_PRIMARY_ADDRESS; - const ownerAddress = addr && ADDR_RE.test(addr) ? addr : null; + const creds = resolveCredentials(); + const ownerAddress = creds.ownerEOA ?? null; let signature = null; - const sigEnv = process.env.CORTEX_USER_SIGNATURE; - if (sigEnv && SIG_RE.test(sigEnv)) { - signature = sigEnv; - } else { - const pkEnv = process.env.CORTEX_USER_PRIVATE_KEY; - if (pkEnv && PK_RE.test(pkEnv)) { - const account = privateKeyToAccount(pkEnv); - const message = keyDerivationMessage(account.address); - signature = await account.signMessage({ message }); - } else { - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE.test(cfgSig)) - signature = cfgSig; - } + if (creds.source.signature === "env") { + signature = creds.userSignature; + } else if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); + const message = keyDerivationMessage(account.address); + signature = await account.signMessage({ message }); + } else if (creds.source.signature === "config") { + signature = creds.userSignature; } const payloadKey = signature ? await derivePayloadKey(signature) : null; const source = ownerAddress || signature ? "env" : "none"; @@ -19626,7 +20090,7 @@ async function adopt(opts) { if (!ADDR_RE.test(opts.address)) { throw new Error("adopt: address must be 0x-prefixed 40-hex EOA"); } - if (!SIG_RE.test(opts.signature)) { + if (!SIG_RE2.test(opts.signature)) { throw new Error("adopt: signature must be 0x-prefixed hex"); } const message = keyDerivationMessage(opts.address); @@ -19656,31 +20120,28 @@ function _setOwnerIdentityForTest(view) { function _peekCached() { return _cached2; } -var ADDR_RE, PK_RE, SIG_RE, _cached2 = null; +var ADDR_RE, SIG_RE2, _cached2 = null; var init_owner_identity = __esm(() => { init__esm(); init_accounts(); init_crypto(); - init_cortex_config(); + init_credentials(); ADDR_RE = /^0x[0-9a-fA-F]{40}$/; - PK_RE = /^0x[0-9a-fA-F]{64}$/; - SIG_RE = /^0x[0-9a-fA-F]+$/; + SIG_RE2 = /^0x[0-9a-fA-F]+$/; }); // src/lib/payload-key.ts async function resolveSignature() { - const sig = process.env.CORTEX_USER_SIGNATURE; - if (sig && SIG_RE2.test(sig)) - return sig; - const pk = process.env.CORTEX_USER_PRIVATE_KEY; - if (pk && PK_RE2.test(pk)) { - const account = privateKeyToAccount(pk); + const creds = resolveCredentials(); + if (creds.source.signature === "env") + return creds.userSignature; + if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); const message = keyDerivationMessage(account.address); return await account.signMessage({ message }); } - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE2.test(cfgSig)) - return cfgSig; + if (creds.source.signature === "config") + return creds.userSignature; return null; } async function getPayloadKey() { @@ -19701,13 +20162,11 @@ async function requirePayloadKey() { } return key; } -var _cached3, SIG_RE2, PK_RE2; +var _cached3; var init_payload_key = __esm(() => { init_accounts2(); init_crypto(); - init_cortex_config(); - SIG_RE2 = /^0x[0-9a-fA-F]+$/; - PK_RE2 = /^0x[0-9a-fA-F]{64}$/; + init_credentials(); }); // node_modules/cbor-x/decode.js @@ -22521,241 +22980,53 @@ var require_node_gyp_build_optional_packages = __commonJS((exports, module) => { } }; } - function isElectron() { - if (process.versions && process.versions.electron) - return true; - if (process.env.ELECTRON_RUN_AS_NODE) - return true; - return typeof window !== "undefined" && window.process && window.process.type === "renderer"; - } - function isMusl(platform2) { - if (platform2 !== "linux") - return false; - const { familySync, MUSL } = require_detect_libc(); - return familySync() === MUSL; - } - load2.parseTags = parseTags; - load2.matchTags = matchTags; - load2.compareTags = compareTags; - load2.parseTuple = parseTuple; - load2.matchTuple = matchTuple; - load2.compareTuples = compareTuples; -}); - -// node_modules/cbor-extract/index.js -var require_cbor_extract = __commonJS((exports, module) => { - var __dirname = "/Users/lingsiewwin/Documents/Github/Arkiv/node_modules/cbor-extract"; - module.exports = require_node_gyp_build_optional_packages()(__dirname); -}); - -// node_modules/cbor-x/node-index.js -var nativeAccelerationDisabled; -var init_node_index = __esm(() => { - init_encode(); - init_decode(); - init_stream(); - init_iterators(); - init_decode(); - nativeAccelerationDisabled = process.env.CBOR_NATIVE_ACCELERATION_DISABLED !== undefined && process.env.CBOR_NATIVE_ACCELERATION_DISABLED.toLowerCase() === "true"; - if (!nativeAccelerationDisabled) { - let extractor; - try { - if (true) - extractor = require_cbor_extract(); - else - ; - if (extractor) - setExtractor(extractor.extractStrings); - } catch (error) {} - } -}); - -// src/compression/fht.ts -function log2PowerOfTwo(n) { - if (n <= 0) - return -1; - let k = 0; - let v = n; - while ((v & 1) === 0) { - v >>= 1; - k++; - } - return v === 1 ? k : -1; -} -function fastHadamardTransform(x) { - const D = x.length; - const logD = log2PowerOfTwo(D); - if (logD < 0) { - throw new Error(`fastHadamardTransform: length must be a power of two, got ${D}`); - } - let h = 1; - while (h < D) { - const twoH = h << 1; - for (let i = 0;i < D; i += twoH) { - for (let j = i;j < i + h; j++) { - const a = x[j]; - const b = x[j + h]; - x[j] = a + b; - x[j + h] = a - b; - } - } - h = twoH; - } - const invSqrtD = 1 / Math.sqrt(D); - for (let i = 0;i < D; i++) { - x[i] = x[i] * invSqrtD; - } -} -function makeXorshift128(seedHex) { - const FNV_OFFSET = 2166136261; - const FNV_PRIME = 16777619; - const seeds = new Uint32Array(4); - for (let k = 0;k < 4; k++) { - let h = (FNV_OFFSET ^ k * 2654435769) >>> 0; - for (let i = 0;i < seedHex.length; i++) { - h ^= seedHex.charCodeAt(i); - h = Math.imul(h, FNV_PRIME) >>> 0; - } - seeds[k] = h === 0 ? 2654435769 : h; - } - let s0 = seeds[0]; - let s1 = seeds[1]; - let s2 = seeds[2]; - let s3 = seeds[3]; - return function next() { - let t = s0 ^ s0 << 11; - t ^= t >>> 8; - s0 = s1; - s1 = s2; - s2 = s3; - s3 = s3 ^ s3 >>> 19 ^ (t ^ t >>> 8); - return s3 >>> 0; - }; -} -function rotateWithSeed(x, seedHex) { - const D = x.length; - const rng = makeXorshift128(seedHex); - for (let i = 0;i < D; i += 32) { - const word = rng(); - const lim = Math.min(32, D - i); - for (let b = 0;b < lim; b++) { - const bit = word >>> b & 1; - if (bit === 0) - x[i + b] = -x[i + b]; - } - } - fastHadamardTransform(x); -} - -// src/compression/rabitq.ts -function f32ToF16(value) { - f32[0] = value; - const x = u322[0]; - const sign2 = x >>> 16 & 32768; - let mant = x & 8388607; - let exp = x >>> 23 & 255; - if (exp === 255) { - return sign2 | 31744 | (mant !== 0 ? 512 | mant >>> 13 : 0); - } - let newExp = exp - 127 + 15; - if (newExp >= 31) { - return sign2 | 31744; - } - if (newExp <= 0) { - if (newExp < -10) - return sign2; - mant = (mant | 8388608) >>> 1 - newExp; - if ((mant & 4096) !== 0) - mant += 8192; - return sign2 | mant >>> 13; - } - if ((mant & 4096) !== 0) { - mant += 8192; - if ((mant & 8388608) !== 0) { - mant = 0; - newExp++; - if (newExp >= 31) - return sign2 | 31744; - } - } - return sign2 | newExp << 10 | mant >>> 13; -} -function padToRotationDim(vec) { - const out = new Float32Array(PADDED_DIM); - const n = Math.min(vec.length, EMBED_DIM); - for (let i = 0;i < n; i++) - out[i] = vec[i]; - return out; -} -function l2Norm(vec) { - let s = 0; - for (let i = 0;i < vec.length; i++) { - const v = vec[i]; - s += v * v; - } - return Math.sqrt(s); -} -function rotateUnit(vec) { - const padded = padToRotationDim(vec); - const norm = l2Norm(padded); - if (norm > 0) { - const inv = 1 / norm; - for (let i = 0;i < PADDED_DIM; i++) - padded[i] = padded[i] * inv; - } - rotateWithSeed(padded, ROTATION_SEED); - return { rotated: padded, norm }; -} -function packSigns(rotated) { - const out = new Uint8Array(SIGN_BYTES); - for (let i = 0;i < EMBED_DIM; i++) { - if (rotated[i] >= 0) { - const byteIdx = i >>> 3; - const bitInByte = 7 - (i & 7); - out[byteIdx] = out[byteIdx] | 1 << bitInByte; - } - } - return out; -} -function rabitqEncode(vec) { - const { rotated, norm } = rotateUnit(vec); - const signs = packSigns(rotated); - const invSqrtD = 1 / Math.sqrt(EMBED_DIM); - let align = 0; - for (let i = 0;i < EMBED_DIM; i++) { - const r = rotated[i]; - align += r >= 0 ? r : -r; + function isElectron() { + if (process.versions && process.versions.electron) + return true; + if (process.env.ELECTRON_RUN_AS_NODE) + return true; + return typeof window !== "undefined" && window.process && window.process.type === "renderer"; } - align *= invSqrtD; - return { - signs, - normFp16: f32ToF16(norm), - alignFp16: f32ToF16(align) - }; -} -function packCode(code) { - if (code.signs.length !== SIGN_BYTES) { - throw new Error(`packCode: signs must be ${SIGN_BYTES} bytes, got ${code.signs.length}`); + function isMusl(platform2) { + if (platform2 !== "linux") + return false; + const { familySync, MUSL } = require_detect_libc(); + return familySync() === MUSL; + } + load2.parseTags = parseTags; + load2.matchTags = matchTags; + load2.compareTags = compareTags; + load2.parseTuple = parseTuple; + load2.matchTuple = matchTuple; + load2.compareTuples = compareTuples; +}); + +// node_modules/cbor-extract/index.js +var require_cbor_extract = __commonJS((exports, module) => { + var __dirname = "/Users/lingsiewwin/Documents/Github/Arkiv/node_modules/cbor-extract"; + module.exports = require_node_gyp_build_optional_packages()(__dirname); +}); + +// node_modules/cbor-x/node-index.js +var nativeAccelerationDisabled; +var init_node_index = __esm(() => { + init_encode(); + init_decode(); + init_stream(); + init_iterators(); + init_decode(); + nativeAccelerationDisabled = process.env.CBOR_NATIVE_ACCELERATION_DISABLED !== undefined && process.env.CBOR_NATIVE_ACCELERATION_DISABLED.toLowerCase() === "true"; + if (!nativeAccelerationDisabled) { + let extractor; + try { + if (true) + extractor = require_cbor_extract(); + else + ; + if (extractor) + setExtractor(extractor.extractStrings); + } catch (error) {} } - const out = new Uint8Array(PACK_SIZE); - out.set(code.signs, 0); - out[NORM_OFFSET] = code.normFp16 & 255; - out[NORM_OFFSET + 1] = code.normFp16 >>> 8 & 255; - out[ALIGN_OFFSET] = code.alignFp16 & 255; - out[ALIGN_OFFSET + 1] = code.alignFp16 >>> 8 & 255; - out[CENTROID_OFFSET] = 0; - out[CENTROID_OFFSET + 1] = 0; - return out; -} -var EMBED_DIM = 1536, PADDED_DIM = 2048, SIGN_BYTES, ROTATION_SEED = "cortex.rabitq.rotation.v1", NORM_OFFSET, ALIGN_OFFSET, CENTROID_OFFSET, PACK_SIZE, f32, u322; -var init_rabitq = __esm(() => { - SIGN_BYTES = EMBED_DIM >> 3; - NORM_OFFSET = SIGN_BYTES; - ALIGN_OFFSET = SIGN_BYTES + 2; - CENTROID_OFFSET = SIGN_BYTES + 4; - PACK_SIZE = SIGN_BYTES + 2 + 2 + 2; - f32 = new Float32Array(1); - u322 = new Uint32Array(f32.buffer); }); // src/compression/document-payload.ts @@ -22773,8 +23044,8 @@ function encodeDocumentPayload(input) { if (typeof input.text !== "string" || input.text.length === 0) { throw new Error("encodeDocumentPayload: text must be a non-empty string"); } - if (input.embedding.length !== EMBED_DIM2) { - throw new Error(`encodeDocumentPayload: embedding must be ${EMBED_DIM2}-d, got ${input.embedding.length}`); + if (input.embedding.length !== EMBED_DIM3) { + throw new Error(`encodeDocumentPayload: embedding must be ${EMBED_DIM3}-d, got ${input.embedding.length}`); } const obj = { v: DOCUMENT_SCHEMA_VERSION, @@ -22799,7 +23070,7 @@ function encodeDocumentPayload(input) { obj.fm = input.frontmatter; return new Uint8Array(encode4(obj)); } -var DOCUMENT_SCHEMA_VERSION = 1, EMBED_DIM2 = 1536; +var DOCUMENT_SCHEMA_VERSION = 1, EMBED_DIM3 = 1536; var init_document_payload = __esm(() => { init_node_index(); init_rabitq(); @@ -22915,224 +23186,6 @@ var init_batch_writer = __esm(() => { }; }); -// src/compression/embeddings.ts -var exports_embeddings = {}; -__export(exports_embeddings, { - isUsableEmbeddingKey: () => isUsableEmbeddingKey, - isMissingEmbeddingKey: () => isMissingEmbeddingKey, - hasEmbeddingKey: () => hasEmbeddingKey, - embedText: () => embedText, - embedAndQuantize: () => embedAndQuantize, - MissingEmbeddingKeyError: () => MissingEmbeddingKeyError, - EMBEDDING_SETUP_MESSAGE: () => EMBEDDING_SETUP_MESSAGE -}); -function isMissingEmbeddingKey(err) { - return err instanceof MissingEmbeddingKeyError || typeof err === "object" && err !== null && "isMissingEmbeddingKey" in err; -} -function isUsableEmbeddingKey(key) { - if (typeof key !== "string") - return false; - const v = key.trim(); - if (v.length < 16) - return false; - if (/\.{2,}|\u2026|placeholder|your[-_]?key/i.test(v)) - return false; - return true; -} -function envEmbeddingKey(name) { - const v = process.env[name]; - return isUsableEmbeddingKey(v) ? v.trim() : undefined; -} -function hasEmbeddingKey() { - if (envEmbeddingKey("OPENAI_API_KEY") || envEmbeddingKey("OPENROUTER_API_KEY") || envEmbeddingKey("VOYAGE_API_KEY") || envEmbeddingKey("COHERE_API_KEY")) { - return true; - } - const cfg = readConfig(); - return isUsableEmbeddingKey(cfg?.embeddingKey); -} -function toFloat32(arr, provider) { - if (!Array.isArray(arr)) { - throw new Error(`embedText: unexpected ${provider} response shape`); - } - if (arr.length !== EMBED_DIM3) { - throw new Error(`embedText: expected ${EMBED_DIM3}-d from ${provider}, got ${arr.length}. ` + `RaBitQ requires exactly ${EMBED_DIM3}-d \u2014 set OPENROUTER_EMBED_MODEL to a 1536-d model.`); - } - const out = new Float32Array(EMBED_DIM3); - for (let i = 0;i < EMBED_DIM3; i++) - out[i] = arr[i]; - return out; -} -async function embedViaOpenAI(text, apiKey) { - const res = await fetch(OPENAI_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: OPENAI_MODEL, - input: [text], - dimensions: EMBED_DIM3, - encoding_format: "float" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: OpenAI request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json = await res.json(); - const first = json.data?.[0]?.embedding; - return toFloat32(first, `OpenAI(${OPENAI_MODEL})`); -} -async function embedViaOpenRouter(text, apiKey) { - const res = await fetch(OPENROUTER_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: OPENROUTER_MODEL, - input: [text], - encoding_format: "float" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: OpenRouter request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json = await res.json(); - const first = json.data?.[0]?.embedding; - return toFloat32(first, `OpenRouter(${OPENROUTER_MODEL})`); -} -async function embedViaVoyage(text, apiKey) { - const res = await fetch(VOYAGE_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: VOYAGE_MODEL, - input: [text], - input_type: "document" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: Voyage request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json = await res.json(); - const first = json.data?.[0]?.embedding; - return toFloat32(first, `Voyage(${VOYAGE_MODEL})`); -} -async function embedViaCohere(text, apiKey) { - const res = await fetch(COHERE_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: COHERE_MODEL, - texts: [text], - input_type: "search_document", - embedding_types: ["float"], - output_dimension: EMBED_DIM3 - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: Cohere request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json = await res.json(); - const first = json.embeddings?.float?.[0]; - return toFloat32(first, "Cohere"); -} -async function embedText(text) { - if (typeof text !== "string" || text.length === 0) { - throw new Error("embedText: input text must be a non-empty string"); - } - const openAiKey = envEmbeddingKey("OPENAI_API_KEY"); - if (openAiKey) - return embedViaOpenAI(text, openAiKey); - const openRouterKey = envEmbeddingKey("OPENROUTER_API_KEY"); - if (openRouterKey) - return embedViaOpenRouter(text, openRouterKey); - const voyageKey = envEmbeddingKey("VOYAGE_API_KEY"); - if (voyageKey) - return embedViaVoyage(text, voyageKey); - const cohereKey = envEmbeddingKey("COHERE_API_KEY"); - if (cohereKey) - return embedViaCohere(text, cohereKey); - const cfg = readConfig(); - if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { - switch (cfg.embeddingProvider ?? "openai") { - case "openrouter": - return embedViaOpenRouter(text, cfg.embeddingKey); - case "voyage": - return embedViaVoyage(text, cfg.embeddingKey); - case "cohere": - return embedViaCohere(text, cfg.embeddingKey); - case "openai": - default: - return embedViaOpenAI(text, cfg.embeddingKey); - } - } - throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); -} -async function embedAndQuantize(text) { - const rawEmbedding = await embedText(text); - const t0 = performance.now(); - const code = rabitqEncode(rawEmbedding); - const bytes = packCode(code); - const ms = performance.now() - t0; - publish({ - type: "rabitq.encoded", - ts: Date.now(), - dim: EMBED_DIM3, - bytes: bytes.byteLength, - ratio: EMBED_DIM3 * 4 / bytes.byteLength, - ms - }); - return { bytes, rawEmbedding }; -} -var EMBED_DIM3 = 1536, EMBED_FETCH_TIMEOUT_MS = 30000, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", OPENAI_MODEL, OPENROUTER_EMBED_URL = "https://openrouter.ai/api/v1/embeddings", OPENROUTER_MODEL, VOYAGE_EMBED_URL = "https://api.voyageai.com/v1/embeddings", VOYAGE_MODEL, COHERE_EMBED_URL = "https://api.cohere.com/v2/embed", COHERE_MODEL = "embed-v4.0", MissingEmbeddingKeyError, EMBEDDING_SETUP_MESSAGE; -var init_embeddings = __esm(() => { - init_rabitq(); - init_events(); - init_cortex_config(); - OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; - OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; - VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; - MissingEmbeddingKeyError = class MissingEmbeddingKeyError extends Error { - isMissingEmbeddingKey = true; - constructor(message) { - super(message); - this.name = "MissingEmbeddingKeyError"; - } - }; - EMBEDDING_SETUP_MESSAGE = [ - "Cortex needs an embedding API key to turn your notes into searchable memory.", - "", - "Add ONE of these to your environment (your shell profile, or a .env in your project):", - " \u2022 OPENAI_API_KEY=sk-\u2026 \u2190 get one at https://platform.openai.com/api-keys", - " \u2022 OPENROUTER_API_KEY=sk-or-\u2026 \u2190 or https://openrouter.ai/keys", - " \u2022 VOYAGE_API_KEY=\u2026 \u2190 Claude/Anthropic users: Anthropic has no embeddings", - " API, so use Voyage (their recommended partner):", - " https://dashboard.voyageai.com/", - " \u2022 COHERE_API_KEY=\u2026 \u2190 or https://dashboard.cohere.com/api-keys", - "", - "Then restart your session. (Your text is only sent to that provider to embed;", - "the memory itself is encrypted with your wallet and stored on Arkiv.)" - ].join(` -`); -}); - // src/agent/session-summary.ts var exports_session_summary = {}; __export(exports_session_summary, { diff --git a/cortex-plugin/dist/cortex-hook-capture.js b/cortex-plugin/dist/cortex-hook-capture.js index a6fdfc9..9ce23f9 100755 --- a/cortex-plugin/dist/cortex-hook-capture.js +++ b/cortex-plugin/dist/cortex-hook-capture.js @@ -223,6 +223,4829 @@ var init_events = __esm(() => { wrappedListeners = new Set; }); +// node_modules/@noble/hashes/esm/cryptoNode.js +import * as nc from "crypto"; +var crypto; +var init_cryptoNode = __esm(() => { + crypto = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && ("randomBytes" in nc) ? nc : undefined; +}); + +// node_modules/@noble/hashes/esm/utils.js +function isBytes(a) { + return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; +} +function anumber(n) { + if (!Number.isSafeInteger(n) || n < 0) + throw new Error("positive integer expected, got " + n); +} +function abytes(b, ...lengths) { + if (!isBytes(b)) + throw new Error("Uint8Array expected"); + if (lengths.length > 0 && !lengths.includes(b.length)) + throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length); +} +function ahash(h) { + if (typeof h !== "function" || typeof h.create !== "function") + throw new Error("Hash should be wrapped by utils.createHasher"); + anumber(h.outputLen); + anumber(h.blockLen); +} +function aexists(instance, checkFinished = true) { + if (instance.destroyed) + throw new Error("Hash instance has been destroyed"); + if (checkFinished && instance.finished) + throw new Error("Hash#digest() has already been called"); +} +function aoutput(out, instance) { + abytes(out); + const min = instance.outputLen; + if (out.length < min) { + throw new Error("digestInto() expects output buffer of length at least " + min); + } +} +function u322(arr) { + return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4)); +} +function clean(...arrays) { + for (let i = 0;i < arrays.length; i++) { + arrays[i].fill(0); + } +} +function createView(arr) { + return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); +} +function rotr(word, shift) { + return word << 32 - shift | word >>> shift; +} +function byteSwap(word) { + return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255; +} +function byteSwap32(arr) { + for (let i = 0;i < arr.length; i++) { + arr[i] = byteSwap(arr[i]); + } + return arr; +} +function utf8ToBytes(str) { + if (typeof str !== "string") + throw new Error("string expected"); + return new Uint8Array(new TextEncoder().encode(str)); +} +function toBytes(data) { + if (typeof data === "string") + data = utf8ToBytes(data); + abytes(data); + return data; +} +function concatBytes(...arrays) { + let sum = 0; + for (let i = 0;i < arrays.length; i++) { + const a = arrays[i]; + abytes(a); + sum += a.length; + } + const res = new Uint8Array(sum); + for (let i = 0, pad = 0;i < arrays.length; i++) { + const a = arrays[i]; + res.set(a, pad); + pad += a.length; + } + return res; +} + +class Hash { +} +function createHasher(hashCons) { + const hashC = (msg) => hashCons().update(toBytes(msg)).digest(); + const tmp = hashCons(); + hashC.outputLen = tmp.outputLen; + hashC.blockLen = tmp.blockLen; + hashC.create = () => hashCons(); + return hashC; +} +function randomBytes(bytesLength = 32) { + if (crypto && typeof crypto.getRandomValues === "function") { + return crypto.getRandomValues(new Uint8Array(bytesLength)); + } + if (crypto && typeof crypto.randomBytes === "function") { + return Uint8Array.from(crypto.randomBytes(bytesLength)); + } + throw new Error("crypto.getRandomValues must be defined"); +} +var isLE, swap32IfBE; +var init_utils = __esm(() => { + init_cryptoNode(); + /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)(); + swap32IfBE = isLE ? (u) => u : byteSwap32; +}); + +// node_modules/@noble/curves/esm/abstract/utils.js +function isBytes2(a) { + return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; +} +function abytes2(item) { + if (!isBytes2(item)) + throw new Error("Uint8Array expected"); +} +function abool(title, value) { + if (typeof value !== "boolean") + throw new Error(title + " boolean expected, got " + value); +} +function numberToHexUnpadded(num) { + const hex = num.toString(16); + return hex.length & 1 ? "0" + hex : hex; +} +function hexToNumber(hex) { + if (typeof hex !== "string") + throw new Error("hex string expected, got " + typeof hex); + return hex === "" ? _0n : BigInt("0x" + hex); +} +function bytesToHex(bytes) { + abytes2(bytes); + if (hasHexBuiltin) + return bytes.toHex(); + let hex = ""; + for (let i = 0;i < bytes.length; i++) { + hex += hexes[bytes[i]]; + } + return hex; +} +function asciiToBase16(ch) { + if (ch >= asciis._0 && ch <= asciis._9) + return ch - asciis._0; + if (ch >= asciis.A && ch <= asciis.F) + return ch - (asciis.A - 10); + if (ch >= asciis.a && ch <= asciis.f) + return ch - (asciis.a - 10); + return; +} +function hexToBytes(hex) { + if (typeof hex !== "string") + throw new Error("hex string expected, got " + typeof hex); + if (hasHexBuiltin) + return Uint8Array.fromHex(hex); + const hl = hex.length; + const al = hl / 2; + if (hl % 2) + throw new Error("hex string expected, got unpadded hex of length " + hl); + const array = new Uint8Array(al); + for (let ai = 0, hi = 0;ai < al; ai++, hi += 2) { + const n1 = asciiToBase16(hex.charCodeAt(hi)); + const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); + if (n1 === undefined || n2 === undefined) { + const char = hex[hi] + hex[hi + 1]; + throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi); + } + array[ai] = n1 * 16 + n2; + } + return array; +} +function bytesToNumberBE(bytes) { + return hexToNumber(bytesToHex(bytes)); +} +function bytesToNumberLE(bytes) { + abytes2(bytes); + return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse())); +} +function numberToBytesBE(n, len) { + return hexToBytes(n.toString(16).padStart(len * 2, "0")); +} +function numberToBytesLE(n, len) { + return numberToBytesBE(n, len).reverse(); +} +function ensureBytes(title, hex, expectedLength) { + let res; + if (typeof hex === "string") { + try { + res = hexToBytes(hex); + } catch (e) { + throw new Error(title + " must be hex string or Uint8Array, cause: " + e); + } + } else if (isBytes2(hex)) { + res = Uint8Array.from(hex); + } else { + throw new Error(title + " must be hex string or Uint8Array"); + } + const len = res.length; + if (typeof expectedLength === "number" && len !== expectedLength) + throw new Error(title + " of length " + expectedLength + " expected, got " + len); + return res; +} +function concatBytes2(...arrays) { + let sum = 0; + for (let i = 0;i < arrays.length; i++) { + const a = arrays[i]; + abytes2(a); + sum += a.length; + } + const res = new Uint8Array(sum); + for (let i = 0, pad = 0;i < arrays.length; i++) { + const a = arrays[i]; + res.set(a, pad); + pad += a.length; + } + return res; +} +function inRange(n, min, max) { + return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max; +} +function aInRange(title, n, min, max) { + if (!inRange(n, min, max)) + throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n); +} +function bitLen(n) { + let len; + for (len = 0;n > _0n; n >>= _1n, len += 1) + ; + return len; +} +function createHmacDrbg(hashLen, qByteLen, hmacFn) { + if (typeof hashLen !== "number" || hashLen < 2) + throw new Error("hashLen must be a number"); + if (typeof qByteLen !== "number" || qByteLen < 2) + throw new Error("qByteLen must be a number"); + if (typeof hmacFn !== "function") + throw new Error("hmacFn must be a function"); + let v = u8n(hashLen); + let k = u8n(hashLen); + let i = 0; + const reset = () => { + v.fill(1); + k.fill(0); + i = 0; + }; + const h = (...b) => hmacFn(k, v, ...b); + const reseed = (seed = u8n(0)) => { + k = h(u8fr([0]), seed); + v = h(); + if (seed.length === 0) + return; + k = h(u8fr([1]), seed); + v = h(); + }; + const gen = () => { + if (i++ >= 1000) + throw new Error("drbg: tried 1000 values"); + let len = 0; + const out = []; + while (len < qByteLen) { + v = h(); + const sl = v.slice(); + out.push(sl); + len += v.length; + } + return concatBytes2(...out); + }; + const genUntil = (seed, pred) => { + reset(); + reseed(seed); + let res = undefined; + while (!(res = pred(gen()))) + reseed(); + reset(); + return res; + }; + return genUntil; +} +function validateObject(object, validators, optValidators = {}) { + const checkField = (fieldName, type, isOptional) => { + const checkVal = validatorFns[type]; + if (typeof checkVal !== "function") + throw new Error("invalid validator function"); + const val = object[fieldName]; + if (isOptional && val === undefined) + return; + if (!checkVal(val, object)) { + throw new Error("param " + String(fieldName) + " is invalid. Expected " + type + ", got " + val); + } + }; + for (const [fieldName, type] of Object.entries(validators)) + checkField(fieldName, type, false); + for (const [fieldName, type] of Object.entries(optValidators)) + checkField(fieldName, type, true); + return object; +} +function memoized(fn) { + const map = new WeakMap; + return (arg, ...args) => { + const val = map.get(arg); + if (val !== undefined) + return val; + const computed = fn(arg, ...args); + map.set(arg, computed); + return computed; + }; +} +var _0n, _1n, hasHexBuiltin, hexes, asciis, isPosBig = (n) => typeof n === "bigint" && _0n <= n, bitMask = (n) => (_1n << BigInt(n)) - _1n, u8n = (len) => new Uint8Array(len), u8fr = (arr) => Uint8Array.from(arr), validatorFns; +var init_utils2 = __esm(() => { + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + _0n = /* @__PURE__ */ BigInt(0); + _1n = /* @__PURE__ */ BigInt(1); + hasHexBuiltin = typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"; + hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")); + asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; + validatorFns = { + bigint: (val) => typeof val === "bigint", + function: (val) => typeof val === "function", + boolean: (val) => typeof val === "boolean", + string: (val) => typeof val === "string", + stringOrUint8Array: (val) => typeof val === "string" || isBytes2(val), + isSafeInteger: (val) => Number.isSafeInteger(val), + array: (val) => Array.isArray(val), + field: (val, object) => object.Fp.isValid(val), + hash: (val) => typeof val === "function" && Number.isSafeInteger(val.outputLen) + }; +}); + +// node_modules/@noble/curves/esm/abstract/modular.js +function mod(a, b) { + const result = a % b; + return result >= _0n2 ? result : b + result; +} +function pow2(x, power, modulo) { + let res = x; + while (power-- > _0n2) { + res *= res; + res %= modulo; + } + return res; +} +function invert(number, modulo) { + if (number === _0n2) + throw new Error("invert: expected non-zero number"); + if (modulo <= _0n2) + throw new Error("invert: expected positive modulus, got " + modulo); + let a = mod(number, modulo); + let b = modulo; + let x = _0n2, y = _1n2, u = _1n2, v = _0n2; + while (a !== _0n2) { + const q = b / a; + const r = b % a; + const m = x - u * q; + const n = y - v * q; + b = a, a = r, x = u, y = v, u = m, v = n; + } + const gcd = b; + if (gcd !== _1n2) + throw new Error("invert: does not exist"); + return mod(x, modulo); +} +function sqrt3mod4(Fp, n) { + const p1div4 = (Fp.ORDER + _1n2) / _4n; + const root = Fp.pow(n, p1div4); + if (!Fp.eql(Fp.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; +} +function sqrt5mod8(Fp, n) { + const p5div8 = (Fp.ORDER - _5n) / _8n; + const n2 = Fp.mul(n, _2n); + const v = Fp.pow(n2, p5div8); + const nv = Fp.mul(n, v); + const i = Fp.mul(Fp.mul(nv, _2n), v); + const root = Fp.mul(nv, Fp.sub(i, Fp.ONE)); + if (!Fp.eql(Fp.sqr(root), n)) + throw new Error("Cannot find square root"); + return root; +} +function tonelliShanks(P) { + if (P < BigInt(3)) + throw new Error("sqrt is not defined for small field"); + let Q = P - _1n2; + let S = 0; + while (Q % _2n === _0n2) { + Q /= _2n; + S++; + } + let Z = _2n; + const _Fp = Field(P); + while (FpLegendre(_Fp, Z) === 1) { + if (Z++ > 1000) + throw new Error("Cannot find square root: probably non-prime P"); + } + if (S === 1) + return sqrt3mod4; + let cc = _Fp.pow(Z, Q); + const Q1div2 = (Q + _1n2) / _2n; + return function tonelliSlow(Fp, n) { + if (Fp.is0(n)) + return n; + if (FpLegendre(Fp, n) !== 1) + throw new Error("Cannot find square root"); + let M = S; + let c = Fp.mul(Fp.ONE, cc); + let t = Fp.pow(n, Q); + let R = Fp.pow(n, Q1div2); + while (!Fp.eql(t, Fp.ONE)) { + if (Fp.is0(t)) + return Fp.ZERO; + let i = 1; + let t_tmp = Fp.sqr(t); + while (!Fp.eql(t_tmp, Fp.ONE)) { + i++; + t_tmp = Fp.sqr(t_tmp); + if (i === M) + throw new Error("Cannot find square root"); + } + const exponent = _1n2 << BigInt(M - i - 1); + const b = Fp.pow(c, exponent); + M = i; + c = Fp.sqr(b); + t = Fp.mul(t, c); + R = Fp.mul(R, b); + } + return R; + }; +} +function FpSqrt(P) { + if (P % _4n === _3n) + return sqrt3mod4; + if (P % _8n === _5n) + return sqrt5mod8; + return tonelliShanks(P); +} +function validateField(field) { + const initial = { + ORDER: "bigint", + MASK: "bigint", + BYTES: "isSafeInteger", + BITS: "isSafeInteger" + }; + const opts = FIELD_FIELDS.reduce((map, val) => { + map[val] = "function"; + return map; + }, initial); + return validateObject(field, opts); +} +function FpPow(Fp, num, power) { + if (power < _0n2) + throw new Error("invalid exponent, negatives unsupported"); + if (power === _0n2) + return Fp.ONE; + if (power === _1n2) + return num; + let p = Fp.ONE; + let d = num; + while (power > _0n2) { + if (power & _1n2) + p = Fp.mul(p, d); + d = Fp.sqr(d); + power >>= _1n2; + } + return p; +} +function FpInvertBatch(Fp, nums, passZero = false) { + const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined); + const multipliedAcc = nums.reduce((acc, num, i) => { + if (Fp.is0(num)) + return acc; + inverted[i] = acc; + return Fp.mul(acc, num); + }, Fp.ONE); + const invertedAcc = Fp.inv(multipliedAcc); + nums.reduceRight((acc, num, i) => { + if (Fp.is0(num)) + return acc; + inverted[i] = Fp.mul(acc, inverted[i]); + return Fp.mul(acc, num); + }, invertedAcc); + return inverted; +} +function FpLegendre(Fp, n) { + const p1mod2 = (Fp.ORDER - _1n2) / _2n; + const powered = Fp.pow(n, p1mod2); + const yes = Fp.eql(powered, Fp.ONE); + const zero = Fp.eql(powered, Fp.ZERO); + const no = Fp.eql(powered, Fp.neg(Fp.ONE)); + if (!yes && !zero && !no) + throw new Error("invalid Legendre symbol result"); + return yes ? 1 : zero ? 0 : -1; +} +function nLength(n, nBitLength) { + if (nBitLength !== undefined) + anumber(nBitLength); + const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length; + const nByteLength = Math.ceil(_nBitLength / 8); + return { nBitLength: _nBitLength, nByteLength }; +} +function Field(ORDER, bitLen2, isLE2 = false, redef = {}) { + if (ORDER <= _0n2) + throw new Error("invalid field: expected ORDER > 0, got " + ORDER); + const { nBitLength: BITS, nByteLength: BYTES } = nLength(ORDER, bitLen2); + if (BYTES > 2048) + throw new Error("invalid field: expected ORDER of <= 2048 bytes"); + let sqrtP; + const f = Object.freeze({ + ORDER, + isLE: isLE2, + BITS, + BYTES, + MASK: bitMask(BITS), + ZERO: _0n2, + ONE: _1n2, + create: (num) => mod(num, ORDER), + isValid: (num) => { + if (typeof num !== "bigint") + throw new Error("invalid field element: expected bigint, got " + typeof num); + return _0n2 <= num && num < ORDER; + }, + is0: (num) => num === _0n2, + isOdd: (num) => (num & _1n2) === _1n2, + neg: (num) => mod(-num, ORDER), + eql: (lhs, rhs) => lhs === rhs, + sqr: (num) => mod(num * num, ORDER), + add: (lhs, rhs) => mod(lhs + rhs, ORDER), + sub: (lhs, rhs) => mod(lhs - rhs, ORDER), + mul: (lhs, rhs) => mod(lhs * rhs, ORDER), + pow: (num, power) => FpPow(f, num, power), + div: (lhs, rhs) => mod(lhs * invert(rhs, ORDER), ORDER), + sqrN: (num) => num * num, + addN: (lhs, rhs) => lhs + rhs, + subN: (lhs, rhs) => lhs - rhs, + mulN: (lhs, rhs) => lhs * rhs, + inv: (num) => invert(num, ORDER), + sqrt: redef.sqrt || ((n) => { + if (!sqrtP) + sqrtP = FpSqrt(ORDER); + return sqrtP(f, n); + }), + toBytes: (num) => isLE2 ? numberToBytesLE(num, BYTES) : numberToBytesBE(num, BYTES), + fromBytes: (bytes) => { + if (bytes.length !== BYTES) + throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); + return isLE2 ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); + }, + invertBatch: (lst) => FpInvertBatch(f, lst), + cmov: (a, b, c) => c ? b : a + }); + return Object.freeze(f); +} +function getFieldBytesLength(fieldOrder) { + if (typeof fieldOrder !== "bigint") + throw new Error("field order must be bigint"); + const bitLength = fieldOrder.toString(2).length; + return Math.ceil(bitLength / 8); +} +function getMinHashLength(fieldOrder) { + const length = getFieldBytesLength(fieldOrder); + return length + Math.ceil(length / 2); +} +function mapHashToField(key, fieldOrder, isLE2 = false) { + const len = key.length; + const fieldLen = getFieldBytesLength(fieldOrder); + const minLen = getMinHashLength(fieldOrder); + if (len < 16 || len < minLen || len > 1024) + throw new Error("expected " + minLen + "-1024 bytes of input, got " + len); + const num = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key); + const reduced = mod(num, fieldOrder - _1n2) + _1n2; + return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); +} +var _0n2, _1n2, _2n, _3n, _4n, _5n, _8n, FIELD_FIELDS; +var init_modular = __esm(() => { + init_utils(); + init_utils2(); + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + _0n2 = BigInt(0); + _1n2 = BigInt(1); + _2n = /* @__PURE__ */ BigInt(2); + _3n = /* @__PURE__ */ BigInt(3); + _4n = /* @__PURE__ */ BigInt(4); + _5n = /* @__PURE__ */ BigInt(5); + _8n = /* @__PURE__ */ BigInt(8); + FIELD_FIELDS = [ + "create", + "isValid", + "is0", + "neg", + "inv", + "sqrt", + "sqr", + "eql", + "add", + "sub", + "mul", + "pow", + "div", + "addN", + "subN", + "mulN", + "sqrN" + ]; +}); + +// node_modules/@noble/hashes/esm/_md.js +function setBigUint64(view, byteOffset, value, isLE2) { + if (typeof view.setBigUint64 === "function") + return view.setBigUint64(byteOffset, value, isLE2); + const _32n = BigInt(32); + const _u32_max = BigInt(4294967295); + const wh = Number(value >> _32n & _u32_max); + const wl = Number(value & _u32_max); + const h = isLE2 ? 4 : 0; + const l = isLE2 ? 0 : 4; + view.setUint32(byteOffset + h, wh, isLE2); + view.setUint32(byteOffset + l, wl, isLE2); +} +function Chi(a, b, c) { + return a & b ^ ~a & c; +} +function Maj(a, b, c) { + return a & b ^ a & c ^ b & c; +} +var HashMD, SHA256_IV; +var init__md = __esm(() => { + init_utils(); + HashMD = class HashMD extends Hash { + constructor(blockLen, outputLen, padOffset, isLE2) { + super(); + this.finished = false; + this.length = 0; + this.pos = 0; + this.destroyed = false; + this.blockLen = blockLen; + this.outputLen = outputLen; + this.padOffset = padOffset; + this.isLE = isLE2; + this.buffer = new Uint8Array(blockLen); + this.view = createView(this.buffer); + } + update(data) { + aexists(this); + data = toBytes(data); + abytes(data); + const { view, buffer, blockLen } = this; + const len = data.length; + for (let pos = 0;pos < len; ) { + const take = Math.min(blockLen - this.pos, len - pos); + if (take === blockLen) { + const dataView = createView(data); + for (;blockLen <= len - pos; pos += blockLen) + this.process(dataView, pos); + continue; + } + buffer.set(data.subarray(pos, pos + take), this.pos); + this.pos += take; + pos += take; + if (this.pos === blockLen) { + this.process(view, 0); + this.pos = 0; + } + } + this.length += data.length; + this.roundClean(); + return this; + } + digestInto(out) { + aexists(this); + aoutput(out, this); + this.finished = true; + const { buffer, view, blockLen, isLE: isLE2 } = this; + let { pos } = this; + buffer[pos++] = 128; + clean(this.buffer.subarray(pos)); + if (this.padOffset > blockLen - pos) { + this.process(view, 0); + pos = 0; + } + for (let i = pos;i < blockLen; i++) + buffer[i] = 0; + setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE2); + this.process(view, 0); + const oview = createView(out); + const len = this.outputLen; + if (len % 4) + throw new Error("_sha2: outputLen should be aligned to 32bit"); + const outLen = len / 4; + const state = this.get(); + if (outLen > state.length) + throw new Error("_sha2: outputLen bigger than state"); + for (let i = 0;i < outLen; i++) + oview.setUint32(4 * i, state[i], isLE2); + } + digest() { + const { buffer, outputLen } = this; + this.digestInto(buffer); + const res = buffer.slice(0, outputLen); + this.destroy(); + return res; + } + _cloneInto(to) { + to || (to = new this.constructor); + to.set(...this.get()); + const { blockLen, buffer, length, finished, destroyed, pos } = this; + to.destroyed = destroyed; + to.finished = finished; + to.length = length; + to.pos = pos; + if (length % blockLen) + to.buffer.set(buffer); + return to; + } + clone() { + return this._cloneInto(); + } + }; + SHA256_IV = /* @__PURE__ */ Uint32Array.from([ + 1779033703, + 3144134277, + 1013904242, + 2773480762, + 1359893119, + 2600822924, + 528734635, + 1541459225 + ]); +}); + +// node_modules/@noble/hashes/esm/_u64.js +function fromBig(n, le = false) { + if (le) + return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) }; + return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; +} +function split(lst, le = false) { + const len = lst.length; + let Ah = new Uint32Array(len); + let Al = new Uint32Array(len); + for (let i = 0;i < len; i++) { + const { h, l } = fromBig(lst[i], le); + [Ah[i], Al[i]] = [h, l]; + } + return [Ah, Al]; +} +var U32_MASK64, _32n, rotlSH = (h, l, s) => h << s | l >>> 32 - s, rotlSL = (h, l, s) => l << s | h >>> 32 - s, rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s, rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s; +var init__u64 = __esm(() => { + U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); + _32n = /* @__PURE__ */ BigInt(32); +}); + +// node_modules/@noble/hashes/esm/sha2.js +var SHA256_K, SHA256_W, SHA256, sha256; +var init_sha2 = __esm(() => { + init__md(); + init_utils(); + SHA256_K = /* @__PURE__ */ Uint32Array.from([ + 1116352408, + 1899447441, + 3049323471, + 3921009573, + 961987163, + 1508970993, + 2453635748, + 2870763221, + 3624381080, + 310598401, + 607225278, + 1426881987, + 1925078388, + 2162078206, + 2614888103, + 3248222580, + 3835390401, + 4022224774, + 264347078, + 604807628, + 770255983, + 1249150122, + 1555081692, + 1996064986, + 2554220882, + 2821834349, + 2952996808, + 3210313671, + 3336571891, + 3584528711, + 113926993, + 338241895, + 666307205, + 773529912, + 1294757372, + 1396182291, + 1695183700, + 1986661051, + 2177026350, + 2456956037, + 2730485921, + 2820302411, + 3259730800, + 3345764771, + 3516065817, + 3600352804, + 4094571909, + 275423344, + 430227734, + 506948616, + 659060556, + 883997877, + 958139571, + 1322822218, + 1537002063, + 1747873779, + 1955562222, + 2024104815, + 2227730452, + 2361852424, + 2428436474, + 2756734187, + 3204031479, + 3329325298 + ]); + SHA256_W = /* @__PURE__ */ new Uint32Array(64); + SHA256 = class SHA256 extends HashMD { + constructor(outputLen = 32) { + super(64, outputLen, 8, false); + this.A = SHA256_IV[0] | 0; + this.B = SHA256_IV[1] | 0; + this.C = SHA256_IV[2] | 0; + this.D = SHA256_IV[3] | 0; + this.E = SHA256_IV[4] | 0; + this.F = SHA256_IV[5] | 0; + this.G = SHA256_IV[6] | 0; + this.H = SHA256_IV[7] | 0; + } + get() { + const { A, B, C, D, E, F, G, H } = this; + return [A, B, C, D, E, F, G, H]; + } + set(A, B, C, D, E, F, G, H) { + this.A = A | 0; + this.B = B | 0; + this.C = C | 0; + this.D = D | 0; + this.E = E | 0; + this.F = F | 0; + this.G = G | 0; + this.H = H | 0; + } + process(view, offset) { + for (let i = 0;i < 16; i++, offset += 4) + SHA256_W[i] = view.getUint32(offset, false); + for (let i = 16;i < 64; i++) { + const W15 = SHA256_W[i - 15]; + const W2 = SHA256_W[i - 2]; + const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; + const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; + SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; + } + let { A, B, C, D, E, F, G, H } = this; + for (let i = 0;i < 64; i++) { + const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); + const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; + const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); + const T2 = sigma0 + Maj(A, B, C) | 0; + H = G; + G = F; + F = E; + E = D + T1 | 0; + D = C; + C = B; + B = A; + A = T1 + T2 | 0; + } + A = A + this.A | 0; + B = B + this.B | 0; + C = C + this.C | 0; + D = D + this.D | 0; + E = E + this.E | 0; + F = F + this.F | 0; + G = G + this.G | 0; + H = H + this.H | 0; + this.set(A, B, C, D, E, F, G, H); + } + roundClean() { + clean(SHA256_W); + } + destroy() { + this.set(0, 0, 0, 0, 0, 0, 0, 0); + clean(this.buffer); + } + }; + sha256 = /* @__PURE__ */ createHasher(() => new SHA256); +}); + +// node_modules/@noble/hashes/esm/hmac.js +var HMAC, hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest(); +var init_hmac = __esm(() => { + init_utils(); + HMAC = class HMAC extends Hash { + constructor(hash, _key) { + super(); + this.finished = false; + this.destroyed = false; + ahash(hash); + const key = toBytes(_key); + this.iHash = hash.create(); + if (typeof this.iHash.update !== "function") + throw new Error("Expected instance of class which extends utils.Hash"); + this.blockLen = this.iHash.blockLen; + this.outputLen = this.iHash.outputLen; + const blockLen = this.blockLen; + const pad = new Uint8Array(blockLen); + pad.set(key.length > blockLen ? hash.create().update(key).digest() : key); + for (let i = 0;i < pad.length; i++) + pad[i] ^= 54; + this.iHash.update(pad); + this.oHash = hash.create(); + for (let i = 0;i < pad.length; i++) + pad[i] ^= 54 ^ 92; + this.oHash.update(pad); + clean(pad); + } + update(buf) { + aexists(this); + this.iHash.update(buf); + return this; + } + digestInto(out) { + aexists(this); + abytes(out, this.outputLen); + this.finished = true; + this.iHash.digestInto(out); + this.oHash.update(out); + this.oHash.digestInto(out); + this.destroy(); + } + digest() { + const out = new Uint8Array(this.oHash.outputLen); + this.digestInto(out); + return out; + } + _cloneInto(to) { + to || (to = Object.create(Object.getPrototypeOf(this), {})); + const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this; + to = to; + to.finished = finished; + to.destroyed = destroyed; + to.blockLen = blockLen; + to.outputLen = outputLen; + to.oHash = oHash._cloneInto(to.oHash); + to.iHash = iHash._cloneInto(to.iHash); + return to; + } + clone() { + return this._cloneInto(); + } + destroy() { + this.destroyed = true; + this.oHash.destroy(); + this.iHash.destroy(); + } + }; + hmac.create = (hash, key) => new HMAC(hash, key); +}); + +// node_modules/@noble/curves/esm/abstract/curve.js +function constTimeNegate(condition, item) { + const neg = item.negate(); + return condition ? neg : item; +} +function validateW(W, bits) { + if (!Number.isSafeInteger(W) || W <= 0 || W > bits) + throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W); +} +function calcWOpts(W, scalarBits) { + validateW(W, scalarBits); + const windows = Math.ceil(scalarBits / W) + 1; + const windowSize = 2 ** (W - 1); + const maxNumber = 2 ** W; + const mask = bitMask(W); + const shiftBy = BigInt(W); + return { windows, windowSize, mask, maxNumber, shiftBy }; +} +function calcOffsets(n, window, wOpts) { + const { windowSize, mask, maxNumber, shiftBy } = wOpts; + let wbits = Number(n & mask); + let nextN = n >> shiftBy; + if (wbits > windowSize) { + wbits -= maxNumber; + nextN += _1n3; + } + const offsetStart = window * windowSize; + const offset = offsetStart + Math.abs(wbits) - 1; + const isZero = wbits === 0; + const isNeg = wbits < 0; + const isNegF = window % 2 !== 0; + const offsetF = offsetStart; + return { nextN, offset, isZero, isNeg, isNegF, offsetF }; +} +function validateMSMPoints(points, c) { + if (!Array.isArray(points)) + throw new Error("array expected"); + points.forEach((p, i) => { + if (!(p instanceof c)) + throw new Error("invalid point at index " + i); + }); +} +function validateMSMScalars(scalars, field) { + if (!Array.isArray(scalars)) + throw new Error("array of scalars expected"); + scalars.forEach((s, i) => { + if (!field.isValid(s)) + throw new Error("invalid scalar at index " + i); + }); +} +function getW(P) { + return pointWindowSizes.get(P) || 1; +} +function wNAF(c, bits) { + return { + constTimeNegate, + hasPrecomputes(elm) { + return getW(elm) !== 1; + }, + unsafeLadder(elm, n, p = c.ZERO) { + let d = elm; + while (n > _0n3) { + if (n & _1n3) + p = p.add(d); + d = d.double(); + n >>= _1n3; + } + return p; + }, + precomputeWindow(elm, W) { + const { windows, windowSize } = calcWOpts(W, bits); + const points = []; + let p = elm; + let base = p; + for (let window = 0;window < windows; window++) { + base = p; + points.push(base); + for (let i = 1;i < windowSize; i++) { + base = base.add(p); + points.push(base); + } + p = base.double(); + } + return points; + }, + wNAF(W, precomputes, n) { + let p = c.ZERO; + let f = c.BASE; + const wo = calcWOpts(W, bits); + for (let window = 0;window < wo.windows; window++) { + const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo); + n = nextN; + if (isZero) { + f = f.add(constTimeNegate(isNegF, precomputes[offsetF])); + } else { + p = p.add(constTimeNegate(isNeg, precomputes[offset])); + } + } + return { p, f }; + }, + wNAFUnsafe(W, precomputes, n, acc = c.ZERO) { + const wo = calcWOpts(W, bits); + for (let window = 0;window < wo.windows; window++) { + if (n === _0n3) + break; + const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo); + n = nextN; + if (isZero) { + continue; + } else { + const item = precomputes[offset]; + acc = acc.add(isNeg ? item.negate() : item); + } + } + return acc; + }, + getPrecomputes(W, P, transform) { + let comp = pointPrecomputes.get(P); + if (!comp) { + comp = this.precomputeWindow(P, W); + if (W !== 1) + pointPrecomputes.set(P, transform(comp)); + } + return comp; + }, + wNAFCached(P, n, transform) { + const W = getW(P); + return this.wNAF(W, this.getPrecomputes(W, P, transform), n); + }, + wNAFCachedUnsafe(P, n, transform, prev) { + const W = getW(P); + if (W === 1) + return this.unsafeLadder(P, n, prev); + return this.wNAFUnsafe(W, this.getPrecomputes(W, P, transform), n, prev); + }, + setWindowSize(P, W) { + validateW(W, bits); + pointWindowSizes.set(P, W); + pointPrecomputes.delete(P); + } + }; +} +function pippenger(c, fieldN, points, scalars) { + validateMSMPoints(points, c); + validateMSMScalars(scalars, fieldN); + const plength = points.length; + const slength = scalars.length; + if (plength !== slength) + throw new Error("arrays of points and scalars must have equal length"); + const zero = c.ZERO; + const wbits = bitLen(BigInt(plength)); + let windowSize = 1; + if (wbits > 12) + windowSize = wbits - 3; + else if (wbits > 4) + windowSize = wbits - 2; + else if (wbits > 0) + windowSize = 2; + const MASK = bitMask(windowSize); + const buckets = new Array(Number(MASK) + 1).fill(zero); + const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize; + let sum = zero; + for (let i = lastBits;i >= 0; i -= windowSize) { + buckets.fill(zero); + for (let j = 0;j < slength; j++) { + const scalar = scalars[j]; + const wbits2 = Number(scalar >> BigInt(i) & MASK); + buckets[wbits2] = buckets[wbits2].add(points[j]); + } + let resI = zero; + for (let j = buckets.length - 1, sumI = zero;j > 0; j--) { + sumI = sumI.add(buckets[j]); + resI = resI.add(sumI); + } + sum = sum.add(resI); + if (i !== 0) + for (let j = 0;j < windowSize; j++) + sum = sum.double(); + } + return sum; +} +function validateBasic(curve) { + validateField(curve.Fp); + validateObject(curve, { + n: "bigint", + h: "bigint", + Gx: "field", + Gy: "field" + }, { + nBitLength: "isSafeInteger", + nByteLength: "isSafeInteger" + }); + return Object.freeze({ + ...nLength(curve.n, curve.nBitLength), + ...curve, + ...{ p: curve.Fp.ORDER } + }); +} +var _0n3, _1n3, pointPrecomputes, pointWindowSizes; +var init_curve = __esm(() => { + init_modular(); + init_utils2(); + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + _0n3 = BigInt(0); + _1n3 = BigInt(1); + pointPrecomputes = new WeakMap; + pointWindowSizes = new WeakMap; +}); + +// node_modules/@noble/curves/esm/abstract/weierstrass.js +function validateSigVerOpts(opts) { + if (opts.lowS !== undefined) + abool("lowS", opts.lowS); + if (opts.prehash !== undefined) + abool("prehash", opts.prehash); +} +function validatePointOpts(curve) { + const opts = validateBasic(curve); + validateObject(opts, { + a: "field", + b: "field" + }, { + allowInfinityPoint: "boolean", + allowedPrivateKeyLengths: "array", + clearCofactor: "function", + fromBytes: "function", + isTorsionFree: "function", + toBytes: "function", + wrapPrivateKey: "boolean" + }); + const { endo, Fp, a } = opts; + if (endo) { + if (!Fp.eql(a, Fp.ZERO)) { + throw new Error("invalid endo: CURVE.a must be 0"); + } + if (typeof endo !== "object" || typeof endo.beta !== "bigint" || typeof endo.splitScalar !== "function") { + throw new Error('invalid endo: expected "beta": bigint and "splitScalar": function'); + } + } + return Object.freeze({ ...opts }); +} +function numToSizedHex(num, size) { + return bytesToHex(numberToBytesBE(num, size)); +} +function weierstrassPoints(opts) { + const CURVE = validatePointOpts(opts); + const { Fp } = CURVE; + const Fn = Field(CURVE.n, CURVE.nBitLength); + const toBytes2 = CURVE.toBytes || ((_c, point, _isCompressed) => { + const a = point.toAffine(); + return concatBytes2(Uint8Array.from([4]), Fp.toBytes(a.x), Fp.toBytes(a.y)); + }); + const fromBytes = CURVE.fromBytes || ((bytes) => { + const tail = bytes.subarray(1); + const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES)); + const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES)); + return { x, y }; + }); + function weierstrassEquation(x) { + const { a, b } = CURVE; + const x2 = Fp.sqr(x); + const x3 = Fp.mul(x2, x); + return Fp.add(Fp.add(x3, Fp.mul(x, a)), b); + } + function isValidXY(x, y) { + const left = Fp.sqr(y); + const right = weierstrassEquation(x); + return Fp.eql(left, right); + } + if (!isValidXY(CURVE.Gx, CURVE.Gy)) + throw new Error("bad curve params: generator point"); + const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2); + const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27)); + if (Fp.is0(Fp.add(_4a3, _27b2))) + throw new Error("bad curve params: a or b"); + function isWithinCurveOrder(num) { + return inRange(num, _1n4, CURVE.n); + } + function normPrivateKeyToScalar(key) { + const { allowedPrivateKeyLengths: lengths, nByteLength, wrapPrivateKey, n: N } = CURVE; + if (lengths && typeof key !== "bigint") { + if (isBytes2(key)) + key = bytesToHex(key); + if (typeof key !== "string" || !lengths.includes(key.length)) + throw new Error("invalid private key"); + key = key.padStart(nByteLength * 2, "0"); + } + let num; + try { + num = typeof key === "bigint" ? key : bytesToNumberBE(ensureBytes("private key", key, nByteLength)); + } catch (error) { + throw new Error("invalid private key, expected hex or " + nByteLength + " bytes, got " + typeof key); + } + if (wrapPrivateKey) + num = mod(num, N); + aInRange("private key", num, _1n4, N); + return num; + } + function aprjpoint(other) { + if (!(other instanceof Point)) + throw new Error("ProjectivePoint expected"); + } + const toAffineMemo = memoized((p, iz) => { + const { px: x, py: y, pz: z } = p; + if (Fp.eql(z, Fp.ONE)) + return { x, y }; + const is0 = p.is0(); + if (iz == null) + iz = is0 ? Fp.ONE : Fp.inv(z); + const ax = Fp.mul(x, iz); + const ay = Fp.mul(y, iz); + const zz = Fp.mul(z, iz); + if (is0) + return { x: Fp.ZERO, y: Fp.ZERO }; + if (!Fp.eql(zz, Fp.ONE)) + throw new Error("invZ was invalid"); + return { x: ax, y: ay }; + }); + const assertValidMemo = memoized((p) => { + if (p.is0()) { + if (CURVE.allowInfinityPoint && !Fp.is0(p.py)) + return; + throw new Error("bad point: ZERO"); + } + const { x, y } = p.toAffine(); + if (!Fp.isValid(x) || !Fp.isValid(y)) + throw new Error("bad point: x or y not FE"); + if (!isValidXY(x, y)) + throw new Error("bad point: equation left != right"); + if (!p.isTorsionFree()) + throw new Error("bad point: not in prime-order subgroup"); + return true; + }); + + class Point { + constructor(px, py, pz) { + if (px == null || !Fp.isValid(px)) + throw new Error("x required"); + if (py == null || !Fp.isValid(py) || Fp.is0(py)) + throw new Error("y required"); + if (pz == null || !Fp.isValid(pz)) + throw new Error("z required"); + this.px = px; + this.py = py; + this.pz = pz; + Object.freeze(this); + } + static fromAffine(p) { + const { x, y } = p || {}; + if (!p || !Fp.isValid(x) || !Fp.isValid(y)) + throw new Error("invalid affine point"); + if (p instanceof Point) + throw new Error("projective point not allowed"); + const is0 = (i) => Fp.eql(i, Fp.ZERO); + if (is0(x) && is0(y)) + return Point.ZERO; + return new Point(x, y, Fp.ONE); + } + get x() { + return this.toAffine().x; + } + get y() { + return this.toAffine().y; + } + static normalizeZ(points) { + const toInv = FpInvertBatch(Fp, points.map((p) => p.pz)); + return points.map((p, i) => p.toAffine(toInv[i])).map(Point.fromAffine); + } + static fromHex(hex) { + const P = Point.fromAffine(fromBytes(ensureBytes("pointHex", hex))); + P.assertValidity(); + return P; + } + static fromPrivateKey(privateKey) { + return Point.BASE.multiply(normPrivateKeyToScalar(privateKey)); + } + static msm(points, scalars) { + return pippenger(Point, Fn, points, scalars); + } + _setWindowSize(windowSize) { + wnaf.setWindowSize(this, windowSize); + } + assertValidity() { + assertValidMemo(this); + } + hasEvenY() { + const { y } = this.toAffine(); + if (Fp.isOdd) + return !Fp.isOdd(y); + throw new Error("Field doesn't support isOdd"); + } + equals(other) { + aprjpoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1)); + const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1)); + return U1 && U2; + } + negate() { + return new Point(this.px, Fp.neg(this.py), this.pz); + } + double() { + const { a, b } = CURVE; + const b3 = Fp.mul(b, _3n2); + const { px: X1, py: Y1, pz: Z1 } = this; + let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp; + let t0 = Fp.mul(X1, X1); + let t1 = Fp.mul(Y1, Y1); + let t2 = Fp.mul(Z1, Z1); + let t3 = Fp.mul(X1, Y1); + t3 = Fp.add(t3, t3); + Z3 = Fp.mul(X1, Z1); + Z3 = Fp.add(Z3, Z3); + X3 = Fp.mul(a, Z3); + Y3 = Fp.mul(b3, t2); + Y3 = Fp.add(X3, Y3); + X3 = Fp.sub(t1, Y3); + Y3 = Fp.add(t1, Y3); + Y3 = Fp.mul(X3, Y3); + X3 = Fp.mul(t3, X3); + Z3 = Fp.mul(b3, Z3); + t2 = Fp.mul(a, t2); + t3 = Fp.sub(t0, t2); + t3 = Fp.mul(a, t3); + t3 = Fp.add(t3, Z3); + Z3 = Fp.add(t0, t0); + t0 = Fp.add(Z3, t0); + t0 = Fp.add(t0, t2); + t0 = Fp.mul(t0, t3); + Y3 = Fp.add(Y3, t0); + t2 = Fp.mul(Y1, Z1); + t2 = Fp.add(t2, t2); + t0 = Fp.mul(t2, t3); + X3 = Fp.sub(X3, t0); + Z3 = Fp.mul(t2, t1); + Z3 = Fp.add(Z3, Z3); + Z3 = Fp.add(Z3, Z3); + return new Point(X3, Y3, Z3); + } + add(other) { + aprjpoint(other); + const { px: X1, py: Y1, pz: Z1 } = this; + const { px: X2, py: Y2, pz: Z2 } = other; + let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp; + const a = CURVE.a; + const b3 = Fp.mul(CURVE.b, _3n2); + let t0 = Fp.mul(X1, X2); + let t1 = Fp.mul(Y1, Y2); + let t2 = Fp.mul(Z1, Z2); + let t3 = Fp.add(X1, Y1); + let t4 = Fp.add(X2, Y2); + t3 = Fp.mul(t3, t4); + t4 = Fp.add(t0, t1); + t3 = Fp.sub(t3, t4); + t4 = Fp.add(X1, Z1); + let t5 = Fp.add(X2, Z2); + t4 = Fp.mul(t4, t5); + t5 = Fp.add(t0, t2); + t4 = Fp.sub(t4, t5); + t5 = Fp.add(Y1, Z1); + X3 = Fp.add(Y2, Z2); + t5 = Fp.mul(t5, X3); + X3 = Fp.add(t1, t2); + t5 = Fp.sub(t5, X3); + Z3 = Fp.mul(a, t4); + X3 = Fp.mul(b3, t2); + Z3 = Fp.add(X3, Z3); + X3 = Fp.sub(t1, Z3); + Z3 = Fp.add(t1, Z3); + Y3 = Fp.mul(X3, Z3); + t1 = Fp.add(t0, t0); + t1 = Fp.add(t1, t0); + t2 = Fp.mul(a, t2); + t4 = Fp.mul(b3, t4); + t1 = Fp.add(t1, t2); + t2 = Fp.sub(t0, t2); + t2 = Fp.mul(a, t2); + t4 = Fp.add(t4, t2); + t0 = Fp.mul(t1, t4); + Y3 = Fp.add(Y3, t0); + t0 = Fp.mul(t5, t4); + X3 = Fp.mul(t3, X3); + X3 = Fp.sub(X3, t0); + t0 = Fp.mul(t3, t1); + Z3 = Fp.mul(t5, Z3); + Z3 = Fp.add(Z3, t0); + return new Point(X3, Y3, Z3); + } + subtract(other) { + return this.add(other.negate()); + } + is0() { + return this.equals(Point.ZERO); + } + wNAF(n) { + return wnaf.wNAFCached(this, n, Point.normalizeZ); + } + multiplyUnsafe(sc) { + const { endo: endo2, n: N } = CURVE; + aInRange("scalar", sc, _0n4, N); + const I = Point.ZERO; + if (sc === _0n4) + return I; + if (this.is0() || sc === _1n4) + return this; + if (!endo2 || wnaf.hasPrecomputes(this)) + return wnaf.wNAFCachedUnsafe(this, sc, Point.normalizeZ); + let { k1neg, k1, k2neg, k2 } = endo2.splitScalar(sc); + let k1p = I; + let k2p = I; + let d = this; + while (k1 > _0n4 || k2 > _0n4) { + if (k1 & _1n4) + k1p = k1p.add(d); + if (k2 & _1n4) + k2p = k2p.add(d); + d = d.double(); + k1 >>= _1n4; + k2 >>= _1n4; + } + if (k1neg) + k1p = k1p.negate(); + if (k2neg) + k2p = k2p.negate(); + k2p = new Point(Fp.mul(k2p.px, endo2.beta), k2p.py, k2p.pz); + return k1p.add(k2p); + } + multiply(scalar) { + const { endo: endo2, n: N } = CURVE; + aInRange("scalar", scalar, _1n4, N); + let point, fake; + if (endo2) { + const { k1neg, k1, k2neg, k2 } = endo2.splitScalar(scalar); + let { p: k1p, f: f1p } = this.wNAF(k1); + let { p: k2p, f: f2p } = this.wNAF(k2); + k1p = wnaf.constTimeNegate(k1neg, k1p); + k2p = wnaf.constTimeNegate(k2neg, k2p); + k2p = new Point(Fp.mul(k2p.px, endo2.beta), k2p.py, k2p.pz); + point = k1p.add(k2p); + fake = f1p.add(f2p); + } else { + const { p, f } = this.wNAF(scalar); + point = p; + fake = f; + } + return Point.normalizeZ([point, fake])[0]; + } + multiplyAndAddUnsafe(Q, a, b) { + const G = Point.BASE; + const mul = (P, a2) => a2 === _0n4 || a2 === _1n4 || !P.equals(G) ? P.multiplyUnsafe(a2) : P.multiply(a2); + const sum = mul(this, a).add(mul(Q, b)); + return sum.is0() ? undefined : sum; + } + toAffine(iz) { + return toAffineMemo(this, iz); + } + isTorsionFree() { + const { h: cofactor, isTorsionFree } = CURVE; + if (cofactor === _1n4) + return true; + if (isTorsionFree) + return isTorsionFree(Point, this); + throw new Error("isTorsionFree() has not been declared for the elliptic curve"); + } + clearCofactor() { + const { h: cofactor, clearCofactor } = CURVE; + if (cofactor === _1n4) + return this; + if (clearCofactor) + return clearCofactor(Point, this); + return this.multiplyUnsafe(CURVE.h); + } + toRawBytes(isCompressed = true) { + abool("isCompressed", isCompressed); + this.assertValidity(); + return toBytes2(Point, this, isCompressed); + } + toHex(isCompressed = true) { + abool("isCompressed", isCompressed); + return bytesToHex(this.toRawBytes(isCompressed)); + } + } + Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE); + Point.ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); + const { endo, nBitLength } = CURVE; + const wnaf = wNAF(Point, endo ? Math.ceil(nBitLength / 2) : nBitLength); + return { + CURVE, + ProjectivePoint: Point, + normPrivateKeyToScalar, + weierstrassEquation, + isWithinCurveOrder + }; +} +function validateOpts(curve) { + const opts = validateBasic(curve); + validateObject(opts, { + hash: "hash", + hmac: "function", + randomBytes: "function" + }, { + bits2int: "function", + bits2int_modN: "function", + lowS: "boolean" + }); + return Object.freeze({ lowS: true, ...opts }); +} +function weierstrass(curveDef) { + const CURVE = validateOpts(curveDef); + const { Fp, n: CURVE_ORDER, nByteLength, nBitLength } = CURVE; + const compressedLen = Fp.BYTES + 1; + const uncompressedLen = 2 * Fp.BYTES + 1; + function modN(a) { + return mod(a, CURVE_ORDER); + } + function invN(a) { + return invert(a, CURVE_ORDER); + } + const { ProjectivePoint: Point, normPrivateKeyToScalar, weierstrassEquation, isWithinCurveOrder } = weierstrassPoints({ + ...CURVE, + toBytes(_c, point, isCompressed) { + const a = point.toAffine(); + const x = Fp.toBytes(a.x); + const cat = concatBytes2; + abool("isCompressed", isCompressed); + if (isCompressed) { + return cat(Uint8Array.from([point.hasEvenY() ? 2 : 3]), x); + } else { + return cat(Uint8Array.from([4]), x, Fp.toBytes(a.y)); + } + }, + fromBytes(bytes) { + const len = bytes.length; + const head = bytes[0]; + const tail = bytes.subarray(1); + if (len === compressedLen && (head === 2 || head === 3)) { + const x = bytesToNumberBE(tail); + if (!inRange(x, _1n4, Fp.ORDER)) + throw new Error("Point is not on curve"); + const y2 = weierstrassEquation(x); + let y; + try { + y = Fp.sqrt(y2); + } catch (sqrtError) { + const suffix = sqrtError instanceof Error ? ": " + sqrtError.message : ""; + throw new Error("Point is not on curve" + suffix); + } + const isYOdd = (y & _1n4) === _1n4; + const isHeadOdd = (head & 1) === 1; + if (isHeadOdd !== isYOdd) + y = Fp.neg(y); + return { x, y }; + } else if (len === uncompressedLen && head === 4) { + const x = Fp.fromBytes(tail.subarray(0, Fp.BYTES)); + const y = Fp.fromBytes(tail.subarray(Fp.BYTES, 2 * Fp.BYTES)); + return { x, y }; + } else { + const cl = compressedLen; + const ul = uncompressedLen; + throw new Error("invalid Point, expected length of " + cl + ", or uncompressed " + ul + ", got " + len); + } + } + }); + function isBiggerThanHalfOrder(number) { + const HALF = CURVE_ORDER >> _1n4; + return number > HALF; + } + function normalizeS(s) { + return isBiggerThanHalfOrder(s) ? modN(-s) : s; + } + const slcNum = (b, from, to) => bytesToNumberBE(b.slice(from, to)); + + class Signature { + constructor(r, s, recovery) { + aInRange("r", r, _1n4, CURVE_ORDER); + aInRange("s", s, _1n4, CURVE_ORDER); + this.r = r; + this.s = s; + if (recovery != null) + this.recovery = recovery; + Object.freeze(this); + } + static fromCompact(hex) { + const l = nByteLength; + hex = ensureBytes("compactSignature", hex, l * 2); + return new Signature(slcNum(hex, 0, l), slcNum(hex, l, 2 * l)); + } + static fromDER(hex) { + const { r, s } = DER.toSig(ensureBytes("DER", hex)); + return new Signature(r, s); + } + assertValidity() {} + addRecoveryBit(recovery) { + return new Signature(this.r, this.s, recovery); + } + recoverPublicKey(msgHash) { + const { r, s, recovery: rec } = this; + const h = bits2int_modN(ensureBytes("msgHash", msgHash)); + if (rec == null || ![0, 1, 2, 3].includes(rec)) + throw new Error("recovery id invalid"); + const radj = rec === 2 || rec === 3 ? r + CURVE.n : r; + if (radj >= Fp.ORDER) + throw new Error("recovery id 2 or 3 invalid"); + const prefix = (rec & 1) === 0 ? "02" : "03"; + const R = Point.fromHex(prefix + numToSizedHex(radj, Fp.BYTES)); + const ir = invN(radj); + const u1 = modN(-h * ir); + const u2 = modN(s * ir); + const Q = Point.BASE.multiplyAndAddUnsafe(R, u1, u2); + if (!Q) + throw new Error("point at infinify"); + Q.assertValidity(); + return Q; + } + hasHighS() { + return isBiggerThanHalfOrder(this.s); + } + normalizeS() { + return this.hasHighS() ? new Signature(this.r, modN(-this.s), this.recovery) : this; + } + toDERRawBytes() { + return hexToBytes(this.toDERHex()); + } + toDERHex() { + return DER.hexFromSig(this); + } + toCompactRawBytes() { + return hexToBytes(this.toCompactHex()); + } + toCompactHex() { + const l = nByteLength; + return numToSizedHex(this.r, l) + numToSizedHex(this.s, l); + } + } + const utils = { + isValidPrivateKey(privateKey) { + try { + normPrivateKeyToScalar(privateKey); + return true; + } catch (error) { + return false; + } + }, + normPrivateKeyToScalar, + randomPrivateKey: () => { + const length = getMinHashLength(CURVE.n); + return mapHashToField(CURVE.randomBytes(length), CURVE.n); + }, + precompute(windowSize = 8, point = Point.BASE) { + point._setWindowSize(windowSize); + point.multiply(BigInt(3)); + return point; + } + }; + function getPublicKey(privateKey, isCompressed = true) { + return Point.fromPrivateKey(privateKey).toRawBytes(isCompressed); + } + function isProbPub(item) { + if (typeof item === "bigint") + return false; + if (item instanceof Point) + return true; + const arr = ensureBytes("key", item); + const len = arr.length; + const fpl = Fp.BYTES; + const compLen = fpl + 1; + const uncompLen = 2 * fpl + 1; + if (CURVE.allowedPrivateKeyLengths || nByteLength === compLen) { + return; + } else { + return len === compLen || len === uncompLen; + } + } + function getSharedSecret(privateA, publicB, isCompressed = true) { + if (isProbPub(privateA) === true) + throw new Error("first arg must be private key"); + if (isProbPub(publicB) === false) + throw new Error("second arg must be public key"); + const b = Point.fromHex(publicB); + return b.multiply(normPrivateKeyToScalar(privateA)).toRawBytes(isCompressed); + } + const bits2int = CURVE.bits2int || function(bytes) { + if (bytes.length > 8192) + throw new Error("input is too large"); + const num = bytesToNumberBE(bytes); + const delta = bytes.length * 8 - nBitLength; + return delta > 0 ? num >> BigInt(delta) : num; + }; + const bits2int_modN = CURVE.bits2int_modN || function(bytes) { + return modN(bits2int(bytes)); + }; + const ORDER_MASK = bitMask(nBitLength); + function int2octets(num) { + aInRange("num < 2^" + nBitLength, num, _0n4, ORDER_MASK); + return numberToBytesBE(num, nByteLength); + } + function prepSig(msgHash, privateKey, opts = defaultSigOpts) { + if (["recovered", "canonical"].some((k) => (k in opts))) + throw new Error("sign() legacy options not supported"); + const { hash, randomBytes: randomBytes2 } = CURVE; + let { lowS, prehash, extraEntropy: ent } = opts; + if (lowS == null) + lowS = true; + msgHash = ensureBytes("msgHash", msgHash); + validateSigVerOpts(opts); + if (prehash) + msgHash = ensureBytes("prehashed msgHash", hash(msgHash)); + const h1int = bits2int_modN(msgHash); + const d = normPrivateKeyToScalar(privateKey); + const seedArgs = [int2octets(d), int2octets(h1int)]; + if (ent != null && ent !== false) { + const e = ent === true ? randomBytes2(Fp.BYTES) : ent; + seedArgs.push(ensureBytes("extraEntropy", e)); + } + const seed = concatBytes2(...seedArgs); + const m = h1int; + function k2sig(kBytes) { + const k = bits2int(kBytes); + if (!isWithinCurveOrder(k)) + return; + const ik = invN(k); + const q = Point.BASE.multiply(k).toAffine(); + const r = modN(q.x); + if (r === _0n4) + return; + const s = modN(ik * modN(m + r * d)); + if (s === _0n4) + return; + let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n4); + let normS = s; + if (lowS && isBiggerThanHalfOrder(s)) { + normS = normalizeS(s); + recovery ^= 1; + } + return new Signature(r, normS, recovery); + } + return { seed, k2sig }; + } + const defaultSigOpts = { lowS: CURVE.lowS, prehash: false }; + const defaultVerOpts = { lowS: CURVE.lowS, prehash: false }; + function sign(msgHash, privKey, opts = defaultSigOpts) { + const { seed, k2sig } = prepSig(msgHash, privKey, opts); + const C = CURVE; + const drbg = createHmacDrbg(C.hash.outputLen, C.nByteLength, C.hmac); + return drbg(seed, k2sig); + } + Point.BASE._setWindowSize(8); + function verify(signature, msgHash, publicKey, opts = defaultVerOpts) { + const sg = signature; + msgHash = ensureBytes("msgHash", msgHash); + publicKey = ensureBytes("publicKey", publicKey); + const { lowS, prehash, format } = opts; + validateSigVerOpts(opts); + if ("strict" in opts) + throw new Error("options.strict was renamed to lowS"); + if (format !== undefined && format !== "compact" && format !== "der") + throw new Error("format must be compact or der"); + const isHex = typeof sg === "string" || isBytes2(sg); + const isObj = !isHex && !format && typeof sg === "object" && sg !== null && typeof sg.r === "bigint" && typeof sg.s === "bigint"; + if (!isHex && !isObj) + throw new Error("invalid signature, expected Uint8Array, hex string or Signature instance"); + let _sig = undefined; + let P; + try { + if (isObj) + _sig = new Signature(sg.r, sg.s); + if (isHex) { + try { + if (format !== "compact") + _sig = Signature.fromDER(sg); + } catch (derError) { + if (!(derError instanceof DER.Err)) + throw derError; + } + if (!_sig && format !== "der") + _sig = Signature.fromCompact(sg); + } + P = Point.fromHex(publicKey); + } catch (error) { + return false; + } + if (!_sig) + return false; + if (lowS && _sig.hasHighS()) + return false; + if (prehash) + msgHash = CURVE.hash(msgHash); + const { r, s } = _sig; + const h = bits2int_modN(msgHash); + const is = invN(s); + const u1 = modN(h * is); + const u2 = modN(r * is); + const R = Point.BASE.multiplyAndAddUnsafe(P, u1, u2)?.toAffine(); + if (!R) + return false; + const v = modN(R.x); + return v === r; + } + return { + CURVE, + getPublicKey, + getSharedSecret, + sign, + verify, + ProjectivePoint: Point, + Signature, + utils + }; +} +var DERErr, DER, _0n4, _1n4, _2n2, _3n2, _4n2; +var init_weierstrass = __esm(() => { + init_curve(); + init_modular(); + init_utils2(); + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + DERErr = class DERErr extends Error { + constructor(m = "") { + super(m); + } + }; + DER = { + Err: DERErr, + _tlv: { + encode: (tag, data) => { + const { Err: E } = DER; + if (tag < 0 || tag > 256) + throw new E("tlv.encode: wrong tag"); + if (data.length & 1) + throw new E("tlv.encode: unpadded data"); + const dataLen = data.length / 2; + const len = numberToHexUnpadded(dataLen); + if (len.length / 2 & 128) + throw new E("tlv.encode: long form length too big"); + const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : ""; + const t = numberToHexUnpadded(tag); + return t + lenLen + len + data; + }, + decode(tag, data) { + const { Err: E } = DER; + let pos = 0; + if (tag < 0 || tag > 256) + throw new E("tlv.encode: wrong tag"); + if (data.length < 2 || data[pos++] !== tag) + throw new E("tlv.decode: wrong tlv"); + const first = data[pos++]; + const isLong = !!(first & 128); + let length = 0; + if (!isLong) + length = first; + else { + const lenLen = first & 127; + if (!lenLen) + throw new E("tlv.decode(long): indefinite length not supported"); + if (lenLen > 4) + throw new E("tlv.decode(long): byte length is too big"); + const lengthBytes = data.subarray(pos, pos + lenLen); + if (lengthBytes.length !== lenLen) + throw new E("tlv.decode: length bytes not complete"); + if (lengthBytes[0] === 0) + throw new E("tlv.decode(long): zero leftmost byte"); + for (const b of lengthBytes) + length = length << 8 | b; + pos += lenLen; + if (length < 128) + throw new E("tlv.decode(long): not minimal encoding"); + } + const v = data.subarray(pos, pos + length); + if (v.length !== length) + throw new E("tlv.decode: wrong value length"); + return { v, l: data.subarray(pos + length) }; + } + }, + _int: { + encode(num) { + const { Err: E } = DER; + if (num < _0n4) + throw new E("integer: negative integers are not allowed"); + let hex = numberToHexUnpadded(num); + if (Number.parseInt(hex[0], 16) & 8) + hex = "00" + hex; + if (hex.length & 1) + throw new E("unexpected DER parsing assertion: unpadded hex"); + return hex; + }, + decode(data) { + const { Err: E } = DER; + if (data[0] & 128) + throw new E("invalid signature integer: negative"); + if (data[0] === 0 && !(data[1] & 128)) + throw new E("invalid signature integer: unnecessary leading zero"); + return bytesToNumberBE(data); + } + }, + toSig(hex) { + const { Err: E, _int: int, _tlv: tlv } = DER; + const data = ensureBytes("signature", hex); + const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data); + if (seqLeftBytes.length) + throw new E("invalid signature: left bytes after parsing"); + const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes); + const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes); + if (sLeftBytes.length) + throw new E("invalid signature: left bytes after parsing"); + return { r: int.decode(rBytes), s: int.decode(sBytes) }; + }, + hexFromSig(sig) { + const { _tlv: tlv, _int: int } = DER; + const rs = tlv.encode(2, int.encode(sig.r)); + const ss = tlv.encode(2, int.encode(sig.s)); + const seq2 = rs + ss; + return tlv.encode(48, seq2); + } + }; + _0n4 = BigInt(0); + _1n4 = BigInt(1); + _2n2 = BigInt(2); + _3n2 = BigInt(3); + _4n2 = BigInt(4); +}); + +// node_modules/@noble/curves/esm/_shortw_utils.js +function getHash(hash) { + return { + hash, + hmac: (key, ...msgs) => hmac(hash, key, concatBytes(...msgs)), + randomBytes + }; +} +function createCurve(curveDef, defHash) { + const create = (hash) => weierstrass({ ...curveDef, ...getHash(hash) }); + return { ...create(defHash), create }; +} +var init__shortw_utils = __esm(() => { + init_hmac(); + init_utils(); + init_weierstrass(); + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ +}); + +// node_modules/@noble/curves/esm/secp256k1.js +function sqrtMod(y) { + const P = secp256k1P; + const _3n3 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22); + const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88); + const b2 = y * y * y % P; + const b3 = b2 * b2 * y % P; + const b6 = pow2(b3, _3n3, P) * b3 % P; + const b9 = pow2(b6, _3n3, P) * b3 % P; + const b11 = pow2(b9, _2n3, P) * b2 % P; + const b22 = pow2(b11, _11n, P) * b11 % P; + const b44 = pow2(b22, _22n, P) * b22 % P; + const b88 = pow2(b44, _44n, P) * b44 % P; + const b176 = pow2(b88, _88n, P) * b88 % P; + const b220 = pow2(b176, _44n, P) * b44 % P; + const b223 = pow2(b220, _3n3, P) * b3 % P; + const t1 = pow2(b223, _23n, P) * b22 % P; + const t2 = pow2(t1, _6n, P) * b2 % P; + const root = pow2(t2, _2n3, P); + if (!Fpk1.eql(Fpk1.sqr(root), y)) + throw new Error("Cannot find square root"); + return root; +} +var secp256k1P, secp256k1N, _0n5, _1n5, _2n3, divNearest = (a, b) => (a + b / _2n3) / b, Fpk1, secp256k1; +var init_secp256k1 = __esm(() => { + init_sha2(); + init__shortw_utils(); + init_modular(); + /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ + secp256k1P = BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); + secp256k1N = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); + _0n5 = BigInt(0); + _1n5 = BigInt(1); + _2n3 = BigInt(2); + Fpk1 = Field(secp256k1P, undefined, undefined, { sqrt: sqrtMod }); + secp256k1 = createCurve({ + a: _0n5, + b: BigInt(7), + Fp: Fpk1, + n: secp256k1N, + Gx: BigInt("55066263022277343669578718895168534326250603453777594175500187360389116729240"), + Gy: BigInt("32670510020758816978083085130507043184471273380659243275938904335757337482424"), + h: BigInt(1), + lowS: true, + endo: { + beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"), + splitScalar: (k) => { + const n = secp256k1N; + const a1 = BigInt("0x3086d221a7d46bcde86c90e49284eb15"); + const b1 = -_1n5 * BigInt("0xe4437ed6010e88286f547fa90abfe4c3"); + const a2 = BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"); + const b2 = a1; + const POW_2_128 = BigInt("0x100000000000000000000000000000000"); + const c1 = divNearest(b2 * k, n); + const c2 = divNearest(-b1 * k, n); + let k1 = mod(k - c1 * a1 - c2 * a2, n); + let k2 = mod(-c1 * b1 - c2 * b2, n); + const k1neg = k1 > POW_2_128; + const k2neg = k2 > POW_2_128; + if (k1neg) + k1 = n - k1; + if (k2neg) + k2 = n - k2; + if (k1 > POW_2_128 || k2 > POW_2_128) { + throw new Error("splitScalar: Endomorphism failed, k=" + k); + } + return { k1neg, k1, k2neg, k2 }; + } + } + }, sha256); +}); + +// node_modules/viem/_esm/errors/version.js +var version = "2.49.3"; + +// node_modules/viem/_esm/errors/base.js +function walk(err, fn) { + if (fn?.(err)) + return err; + if (err && typeof err === "object" && "cause" in err && err.cause !== undefined) + return walk(err.cause, fn); + return fn ? null : err; +} +var errorConfig, BaseError; +var init_base = __esm(() => { + errorConfig = { + getDocsUrl: ({ docsBaseUrl, docsPath = "", docsSlug }) => docsPath ? `${docsBaseUrl ?? "https://viem.sh"}${docsPath}${docsSlug ? `#${docsSlug}` : ""}` : undefined, + version: `viem@${version}` + }; + BaseError = class BaseError extends Error { + constructor(shortMessage, args = {}) { + const details = (() => { + if (args.cause instanceof BaseError) + return args.cause.details; + if (args.cause?.message) + return args.cause.message; + return args.details; + })(); + const docsPath = (() => { + if (args.cause instanceof BaseError) + return args.cause.docsPath || args.docsPath; + return args.docsPath; + })(); + const docsUrl = errorConfig.getDocsUrl?.({ ...args, docsPath }); + const message = [ + shortMessage || "An error occurred.", + "", + ...args.metaMessages ? [...args.metaMessages, ""] : [], + ...docsUrl ? [`Docs: ${docsUrl}`] : [], + ...details ? [`Details: ${details}`] : [], + ...errorConfig.version ? [`Version: ${errorConfig.version}`] : [] + ].join(` +`); + super(message, args.cause ? { cause: args.cause } : undefined); + Object.defineProperty(this, "details", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + Object.defineProperty(this, "docsPath", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + Object.defineProperty(this, "metaMessages", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + Object.defineProperty(this, "shortMessage", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + Object.defineProperty(this, "version", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + Object.defineProperty(this, "name", { + enumerable: true, + configurable: true, + writable: true, + value: "BaseError" + }); + this.details = details; + this.docsPath = docsPath; + this.metaMessages = args.metaMessages; + this.name = args.name ?? this.name; + this.shortMessage = shortMessage; + this.version = version; + } + walk(fn) { + return walk(this, fn); + } + }; +}); + +// node_modules/viem/_esm/errors/encoding.js +var IntegerOutOfRangeError, SizeOverflowError; +var init_encoding = __esm(() => { + init_base(); + IntegerOutOfRangeError = class IntegerOutOfRangeError extends BaseError { + constructor({ max, min, signed, size, value }) { + super(`Number "${value}" is not in safe ${size ? `${size * 8}-bit ${signed ? "signed" : "unsigned"} ` : ""}integer range ${max ? `(${min} to ${max})` : `(above ${min})`}`, { name: "IntegerOutOfRangeError" }); + } + }; + SizeOverflowError = class SizeOverflowError extends BaseError { + constructor({ givenSize, maxSize }) { + super(`Size cannot exceed ${maxSize} bytes. Given size: ${givenSize} bytes.`, { name: "SizeOverflowError" }); + } + }; +}); + +// node_modules/viem/_esm/utils/data/isHex.js +function isHex(value, { strict = true } = {}) { + if (!value) + return false; + if (typeof value !== "string") + return false; + return strict ? /^0x[0-9a-fA-F]*$/.test(value) : value.startsWith("0x"); +} + +// node_modules/viem/_esm/utils/data/size.js +function size(value) { + if (isHex(value, { strict: false })) + return Math.ceil((value.length - 2) / 2); + return value.length; +} +var init_size = () => {}; + +// node_modules/viem/_esm/utils/data/trim.js +function trim(hexOrBytes, { dir = "left" } = {}) { + let data = typeof hexOrBytes === "string" ? hexOrBytes.replace("0x", "") : hexOrBytes; + let sliceLength = 0; + for (let i = 0;i < data.length - 1; i++) { + if (data[dir === "left" ? i : data.length - i - 1].toString() === "0") + sliceLength++; + else + break; + } + data = dir === "left" ? data.slice(sliceLength) : data.slice(0, data.length - sliceLength); + if (typeof hexOrBytes === "string") { + if (data.length === 1 && dir === "right") + data = `${data}0`; + return `0x${data.length % 2 === 1 ? `0${data}` : data}`; + } + return data; +} + +// node_modules/viem/_esm/errors/data.js +var SliceOffsetOutOfBoundsError, SizeExceedsPaddingSizeError; +var init_data = __esm(() => { + init_base(); + SliceOffsetOutOfBoundsError = class SliceOffsetOutOfBoundsError extends BaseError { + constructor({ offset, position, size: size2 }) { + super(`Slice ${position === "start" ? "starting" : "ending"} at offset "${offset}" is out-of-bounds (size: ${size2}).`, { name: "SliceOffsetOutOfBoundsError" }); + } + }; + SizeExceedsPaddingSizeError = class SizeExceedsPaddingSizeError extends BaseError { + constructor({ size: size2, targetSize, type }) { + super(`${type.charAt(0).toUpperCase()}${type.slice(1).toLowerCase()} size (${size2}) exceeds padding size (${targetSize}).`, { name: "SizeExceedsPaddingSizeError" }); + } + }; +}); + +// node_modules/viem/_esm/utils/data/pad.js +function pad(hexOrBytes, { dir, size: size2 = 32 } = {}) { + if (typeof hexOrBytes === "string") + return padHex(hexOrBytes, { dir, size: size2 }); + return padBytes(hexOrBytes, { dir, size: size2 }); +} +function padHex(hex_, { dir, size: size2 = 32 } = {}) { + if (size2 === null) + return hex_; + const hex = hex_.replace("0x", ""); + if (hex.length > size2 * 2) + throw new SizeExceedsPaddingSizeError({ + size: Math.ceil(hex.length / 2), + targetSize: size2, + type: "hex" + }); + return `0x${hex[dir === "right" ? "padEnd" : "padStart"](size2 * 2, "0")}`; +} +function padBytes(bytes, { dir, size: size2 = 32 } = {}) { + if (size2 === null) + return bytes; + if (bytes.length > size2) + throw new SizeExceedsPaddingSizeError({ + size: bytes.length, + targetSize: size2, + type: "bytes" + }); + const paddedBytes = new Uint8Array(size2); + for (let i = 0;i < size2; i++) { + const padEnd = dir === "right"; + paddedBytes[padEnd ? i : size2 - i - 1] = bytes[padEnd ? i : bytes.length - i - 1]; + } + return paddedBytes; +} +var init_pad = __esm(() => { + init_data(); +}); + +// node_modules/viem/_esm/utils/encoding/toHex.js +function toHex(value, opts = {}) { + if (typeof value === "number" || typeof value === "bigint") + return numberToHex(value, opts); + if (typeof value === "string") { + return stringToHex(value, opts); + } + if (typeof value === "boolean") + return boolToHex(value, opts); + return bytesToHex2(value, opts); +} +function boolToHex(value, opts = {}) { + const hex = `0x${Number(value)}`; + if (typeof opts.size === "number") { + assertSize(hex, { size: opts.size }); + return pad(hex, { size: opts.size }); + } + return hex; +} +function bytesToHex2(value, opts = {}) { + let string = ""; + for (let i = 0;i < value.length; i++) { + string += hexes2[value[i]]; + } + const hex = `0x${string}`; + if (typeof opts.size === "number") { + assertSize(hex, { size: opts.size }); + return pad(hex, { dir: "right", size: opts.size }); + } + return hex; +} +function numberToHex(value_, opts = {}) { + const { signed, size: size2 } = opts; + const value = BigInt(value_); + let maxValue; + if (size2) { + if (signed) + maxValue = (1n << BigInt(size2) * 8n - 1n) - 1n; + else + maxValue = 2n ** (BigInt(size2) * 8n) - 1n; + } else if (typeof value_ === "number") { + maxValue = BigInt(Number.MAX_SAFE_INTEGER); + } + const minValue = typeof maxValue === "bigint" && signed ? -maxValue - 1n : 0; + if (maxValue && value > maxValue || value < minValue) { + const suffix = typeof value_ === "bigint" ? "n" : ""; + throw new IntegerOutOfRangeError({ + max: maxValue ? `${maxValue}${suffix}` : undefined, + min: `${minValue}${suffix}`, + signed, + size: size2, + value: `${value_}${suffix}` + }); + } + const hex = `0x${(signed && value < 0 ? (1n << BigInt(size2 * 8)) + BigInt(value) : value).toString(16)}`; + if (size2) + return pad(hex, { size: size2 }); + return hex; +} +function stringToHex(value_, opts = {}) { + const value = encoder.encode(value_); + return bytesToHex2(value, opts); +} +var hexes2, encoder; +var init_toHex = __esm(() => { + init_encoding(); + init_pad(); + init_fromHex(); + hexes2 = /* @__PURE__ */ Array.from({ length: 256 }, (_v, i) => i.toString(16).padStart(2, "0")); + encoder = /* @__PURE__ */ new TextEncoder; +}); + +// node_modules/viem/_esm/utils/encoding/toBytes.js +function toBytes2(value, opts = {}) { + if (typeof value === "number" || typeof value === "bigint") + return numberToBytes(value, opts); + if (typeof value === "boolean") + return boolToBytes(value, opts); + if (isHex(value)) + return hexToBytes2(value, opts); + return stringToBytes(value, opts); +} +function boolToBytes(value, opts = {}) { + const bytes = new Uint8Array(1); + bytes[0] = Number(value); + if (typeof opts.size === "number") { + assertSize(bytes, { size: opts.size }); + return pad(bytes, { size: opts.size }); + } + return bytes; +} +function charCodeToBase16(char) { + if (char >= charCodeMap.zero && char <= charCodeMap.nine) + return char - charCodeMap.zero; + if (char >= charCodeMap.A && char <= charCodeMap.F) + return char - (charCodeMap.A - 10); + if (char >= charCodeMap.a && char <= charCodeMap.f) + return char - (charCodeMap.a - 10); + return; +} +function hexToBytes2(hex_, opts = {}) { + let hex = hex_; + if (opts.size) { + assertSize(hex, { size: opts.size }); + hex = pad(hex, { dir: "right", size: opts.size }); + } + let hexString = hex.slice(2); + if (hexString.length % 2) + hexString = `0${hexString}`; + const length = hexString.length / 2; + const bytes = new Uint8Array(length); + for (let index = 0, j = 0;index < length; index++) { + const nibbleLeft = charCodeToBase16(hexString.charCodeAt(j++)); + const nibbleRight = charCodeToBase16(hexString.charCodeAt(j++)); + if (nibbleLeft === undefined || nibbleRight === undefined) { + throw new BaseError(`Invalid byte sequence ("${hexString[j - 2]}${hexString[j - 1]}" in "${hexString}").`); + } + bytes[index] = nibbleLeft * 16 + nibbleRight; + } + return bytes; +} +function numberToBytes(value, opts) { + const hex = numberToHex(value, opts); + return hexToBytes2(hex); +} +function stringToBytes(value, opts = {}) { + const bytes = encoder2.encode(value); + if (typeof opts.size === "number") { + assertSize(bytes, { size: opts.size }); + return pad(bytes, { dir: "right", size: opts.size }); + } + return bytes; +} +var encoder2, charCodeMap; +var init_toBytes = __esm(() => { + init_base(); + init_pad(); + init_fromHex(); + init_toHex(); + encoder2 = /* @__PURE__ */ new TextEncoder; + charCodeMap = { + zero: 48, + nine: 57, + A: 65, + F: 70, + a: 97, + f: 102 + }; +}); + +// node_modules/viem/_esm/utils/encoding/fromHex.js +function assertSize(hexOrBytes, { size: size2 }) { + if (size(hexOrBytes) > size2) + throw new SizeOverflowError({ + givenSize: size(hexOrBytes), + maxSize: size2 + }); +} +function hexToBigInt(hex, opts = {}) { + const { signed } = opts; + if (opts.size) + assertSize(hex, { size: opts.size }); + const value = BigInt(hex); + if (!signed) + return value; + const size2 = (hex.length - 2) / 2; + const max = (1n << BigInt(size2) * 8n - 1n) - 1n; + if (value <= max) + return value; + return value - BigInt(`0x${"f".padStart(size2 * 2, "f")}`) - 1n; +} +function hexToNumber2(hex, opts = {}) { + const value = hexToBigInt(hex, opts); + const number = Number(value); + if (!Number.isSafeInteger(number)) + throw new IntegerOutOfRangeError({ + max: `${Number.MAX_SAFE_INTEGER}`, + min: `${Number.MIN_SAFE_INTEGER}`, + signed: opts.signed, + size: opts.size, + value: `${value}n` + }); + return number; +} +var init_fromHex = __esm(() => { + init_encoding(); + init_size(); +}); + +// node_modules/viem/_esm/utils/lru.js +var LruMap; +var init_lru = __esm(() => { + LruMap = class LruMap extends Map { + constructor(size2) { + super(); + Object.defineProperty(this, "maxSize", { + enumerable: true, + configurable: true, + writable: true, + value: undefined + }); + this.maxSize = size2; + } + get(key) { + const value = super.get(key); + if (super.has(key)) { + super.delete(key); + super.set(key, value); + } + return value; + } + set(key, value) { + if (super.has(key)) + super.delete(key); + super.set(key, value); + if (this.maxSize && this.size > this.maxSize) { + const firstKey = super.keys().next().value; + if (firstKey !== undefined) + super.delete(firstKey); + } + return this; + } + }; +}); + +// node_modules/viem/_esm/utils/signature/serializeSignature.js +function serializeSignature({ r, s, to = "hex", v, yParity }) { + const yParity_ = (() => { + if (yParity === 0 || yParity === 1) + return yParity; + if (v && (v === 27n || v === 28n || v >= 35n)) + return v % 2n === 0n ? 1 : 0; + throw new Error("Invalid `v` or `yParity` value"); + })(); + const signature = `0x${new secp256k1.Signature(hexToBigInt(r), hexToBigInt(s)).toCompactHex()}${yParity_ === 0 ? "1b" : "1c"}`; + if (to === "hex") + return signature; + return hexToBytes2(signature); +} +var init_serializeSignature = __esm(() => { + init_secp256k1(); + init_fromHex(); + init_toBytes(); +}); + +// node_modules/viem/_esm/errors/address.js +var InvalidAddressError; +var init_address = __esm(() => { + init_base(); + InvalidAddressError = class InvalidAddressError extends BaseError { + constructor({ address }) { + super(`Address "${address}" is invalid.`, { + metaMessages: [ + "- Address must be a hex value of 20 bytes (40 hex characters).", + "- Address must match its checksum counterpart." + ], + name: "InvalidAddressError" + }); + } + }; +}); + +// node_modules/@noble/hashes/esm/sha3.js +function keccakP(s, rounds = 24) { + const B = new Uint32Array(5 * 2); + for (let round = 24 - rounds;round < 24; round++) { + for (let x = 0;x < 10; x++) + B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40]; + for (let x = 0;x < 10; x += 2) { + const idx1 = (x + 8) % 10; + const idx0 = (x + 2) % 10; + const B0 = B[idx0]; + const B1 = B[idx0 + 1]; + const Th = rotlH(B0, B1, 1) ^ B[idx1]; + const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1]; + for (let y = 0;y < 50; y += 10) { + s[x + y] ^= Th; + s[x + y + 1] ^= Tl; + } + } + let curH = s[2]; + let curL = s[3]; + for (let t = 0;t < 24; t++) { + const shift = SHA3_ROTL[t]; + const Th = rotlH(curH, curL, shift); + const Tl = rotlL(curH, curL, shift); + const PI = SHA3_PI[t]; + curH = s[PI]; + curL = s[PI + 1]; + s[PI] = Th; + s[PI + 1] = Tl; + } + for (let y = 0;y < 50; y += 10) { + for (let x = 0;x < 10; x++) + B[x] = s[y + x]; + for (let x = 0;x < 10; x++) + s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10]; + } + s[0] ^= SHA3_IOTA_H[round]; + s[1] ^= SHA3_IOTA_L[round]; + } + clean(B); +} +var _0n6, _1n6, _2n4, _7n, _256n, _0x71n, SHA3_PI, SHA3_ROTL, _SHA3_IOTA, IOTAS, SHA3_IOTA_H, SHA3_IOTA_L, rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s), rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s), Keccak, gen = (suffix, blockLen, outputLen) => createHasher(() => new Keccak(blockLen, suffix, outputLen)), keccak_256; +var init_sha3 = __esm(() => { + init__u64(); + init_utils(); + _0n6 = BigInt(0); + _1n6 = BigInt(1); + _2n4 = BigInt(2); + _7n = BigInt(7); + _256n = BigInt(256); + _0x71n = BigInt(113); + SHA3_PI = []; + SHA3_ROTL = []; + _SHA3_IOTA = []; + for (let round = 0, R = _1n6, x = 1, y = 0;round < 24; round++) { + [x, y] = [y, (2 * x + 3 * y) % 5]; + SHA3_PI.push(2 * (5 * y + x)); + SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64); + let t = _0n6; + for (let j = 0;j < 7; j++) { + R = (R << _1n6 ^ (R >> _7n) * _0x71n) % _256n; + if (R & _2n4) + t ^= _1n6 << (_1n6 << /* @__PURE__ */ BigInt(j)) - _1n6; + } + _SHA3_IOTA.push(t); + } + IOTAS = split(_SHA3_IOTA, true); + SHA3_IOTA_H = IOTAS[0]; + SHA3_IOTA_L = IOTAS[1]; + Keccak = class Keccak extends Hash { + constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) { + super(); + this.pos = 0; + this.posOut = 0; + this.finished = false; + this.destroyed = false; + this.enableXOF = false; + this.blockLen = blockLen; + this.suffix = suffix; + this.outputLen = outputLen; + this.enableXOF = enableXOF; + this.rounds = rounds; + anumber(outputLen); + if (!(0 < blockLen && blockLen < 200)) + throw new Error("only keccak-f1600 function is supported"); + this.state = new Uint8Array(200); + this.state32 = u322(this.state); + } + clone() { + return this._cloneInto(); + } + keccak() { + swap32IfBE(this.state32); + keccakP(this.state32, this.rounds); + swap32IfBE(this.state32); + this.posOut = 0; + this.pos = 0; + } + update(data) { + aexists(this); + data = toBytes(data); + abytes(data); + const { blockLen, state } = this; + const len = data.length; + for (let pos = 0;pos < len; ) { + const take = Math.min(blockLen - this.pos, len - pos); + for (let i = 0;i < take; i++) + state[this.pos++] ^= data[pos++]; + if (this.pos === blockLen) + this.keccak(); + } + return this; + } + finish() { + if (this.finished) + return; + this.finished = true; + const { state, suffix, pos, blockLen } = this; + state[pos] ^= suffix; + if ((suffix & 128) !== 0 && pos === blockLen - 1) + this.keccak(); + state[blockLen - 1] ^= 128; + this.keccak(); + } + writeInto(out) { + aexists(this, false); + abytes(out); + this.finish(); + const bufferOut = this.state; + const { blockLen } = this; + for (let pos = 0, len = out.length;pos < len; ) { + if (this.posOut >= blockLen) + this.keccak(); + const take = Math.min(blockLen - this.posOut, len - pos); + out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos); + this.posOut += take; + pos += take; + } + return out; + } + xofInto(out) { + if (!this.enableXOF) + throw new Error("XOF is not possible for this instance"); + return this.writeInto(out); + } + xof(bytes) { + anumber(bytes); + return this.xofInto(new Uint8Array(bytes)); + } + digestInto(out) { + aoutput(out, this); + if (this.finished) + throw new Error("digest() was already called"); + this.writeInto(out); + this.destroy(); + return out; + } + digest() { + return this.digestInto(new Uint8Array(this.outputLen)); + } + destroy() { + this.destroyed = true; + clean(this.state); + } + _cloneInto(to) { + const { blockLen, suffix, outputLen, rounds, enableXOF } = this; + to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds)); + to.state32.set(this.state32); + to.pos = this.pos; + to.posOut = this.posOut; + to.finished = this.finished; + to.rounds = rounds; + to.suffix = suffix; + to.outputLen = outputLen; + to.enableXOF = enableXOF; + to.destroyed = this.destroyed; + return to; + } + }; + keccak_256 = /* @__PURE__ */ (() => gen(1, 136, 256 / 8))(); +}); + +// node_modules/viem/_esm/utils/hash/keccak256.js +function keccak256(value, to_) { + const to = to_ || "hex"; + const bytes = keccak_256(isHex(value, { strict: false }) ? toBytes2(value) : value); + if (to === "bytes") + return bytes; + return toHex(bytes); +} +var init_keccak256 = __esm(() => { + init_sha3(); + init_toBytes(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/address/getAddress.js +function checksumAddress(address_, chainId) { + if (checksumAddressCache.has(`${address_}.${chainId}`)) + return checksumAddressCache.get(`${address_}.${chainId}`); + const hexAddress = chainId ? `${chainId}${address_.toLowerCase()}` : address_.substring(2).toLowerCase(); + const hash = keccak256(stringToBytes(hexAddress), "bytes"); + const address = (chainId ? hexAddress.substring(`${chainId}0x`.length) : hexAddress).split(""); + for (let i = 0;i < 40; i += 2) { + if (hash[i >> 1] >> 4 >= 8 && address[i]) { + address[i] = address[i].toUpperCase(); + } + if ((hash[i >> 1] & 15) >= 8 && address[i + 1]) { + address[i + 1] = address[i + 1].toUpperCase(); + } + } + const result = `0x${address.join("")}`; + checksumAddressCache.set(`${address_}.${chainId}`, result); + return result; +} +var checksumAddressCache; +var init_getAddress = __esm(() => { + init_toBytes(); + init_keccak256(); + init_lru(); + checksumAddressCache = /* @__PURE__ */ new LruMap(8192); +}); + +// node_modules/viem/_esm/utils/address/isAddress.js +function isAddress(address, options) { + const { strict = true } = options ?? {}; + const cacheKey = `${address}.${strict}`; + if (isAddressCache.has(cacheKey)) + return isAddressCache.get(cacheKey); + const result = (() => { + if (!addressRegex.test(address)) + return false; + if (address.toLowerCase() === address) + return true; + if (strict) + return checksumAddress(address) === address; + return true; + })(); + isAddressCache.set(cacheKey, result); + return result; +} +var addressRegex, isAddressCache; +var init_isAddress = __esm(() => { + init_lru(); + init_getAddress(); + addressRegex = /^0x[a-fA-F0-9]{40}$/; + isAddressCache = /* @__PURE__ */ new LruMap(8192); +}); + +// node_modules/viem/_esm/accounts/toAccount.js +function toAccount(source) { + if (typeof source === "string") { + if (!isAddress(source, { strict: false })) + throw new InvalidAddressError({ address: source }); + return { + address: source, + type: "json-rpc" + }; + } + if (!isAddress(source.address, { strict: false })) + throw new InvalidAddressError({ address: source.address }); + return { + address: source.address, + nonceManager: source.nonceManager, + sign: source.sign, + signAuthorization: source.signAuthorization, + signMessage: source.signMessage, + signTransaction: source.signTransaction, + signTypedData: source.signTypedData, + source: "custom", + type: "local" + }; +} +var init_toAccount = __esm(() => { + init_address(); + init_isAddress(); +}); + +// node_modules/viem/_esm/accounts/utils/publicKeyToAddress.js +function publicKeyToAddress(publicKey) { + const address = keccak256(`0x${publicKey.substring(4)}`).substring(26); + return checksumAddress(`0x${address}`); +} +var init_publicKeyToAddress = __esm(() => { + init_getAddress(); + init_keccak256(); +}); + +// node_modules/viem/_esm/accounts/utils/sign.js +async function sign({ hash, privateKey, to = "object" }) { + const { r, s, recovery } = secp256k1.sign(hash.slice(2), privateKey.slice(2), { + lowS: true, + extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes2(extraEntropy) : extraEntropy + }); + const signature = { + r: numberToHex(r, { size: 32 }), + s: numberToHex(s, { size: 32 }), + v: recovery ? 28n : 27n, + yParity: recovery + }; + return (() => { + if (to === "bytes" || to === "hex") + return serializeSignature({ ...signature, to }); + return signature; + })(); +} +var extraEntropy = false; +var init_sign = __esm(() => { + init_secp256k1(); + init_toBytes(); + init_toHex(); + init_serializeSignature(); +}); + +// node_modules/viem/_esm/utils/data/concat.js +function concat(values) { + if (typeof values[0] === "string") + return concatHex(values); + return concatBytes3(values); +} +function concatBytes3(values) { + let length = 0; + for (const arr of values) { + length += arr.length; + } + const result = new Uint8Array(length); + let offset = 0; + for (const arr of values) { + result.set(arr, offset); + offset += arr.length; + } + return result; +} +function concatHex(values) { + return `0x${values.reduce((acc, x) => acc + x.replace("0x", ""), "")}`; +} + +// node_modules/viem/_esm/errors/cursor.js +var NegativeOffsetError, PositionOutOfBoundsError, RecursiveReadLimitExceededError; +var init_cursor = __esm(() => { + init_base(); + NegativeOffsetError = class NegativeOffsetError extends BaseError { + constructor({ offset }) { + super(`Offset \`${offset}\` cannot be negative.`, { + name: "NegativeOffsetError" + }); + } + }; + PositionOutOfBoundsError = class PositionOutOfBoundsError extends BaseError { + constructor({ length, position }) { + super(`Position \`${position}\` is out of bounds (\`0 < position < ${length}\`).`, { name: "PositionOutOfBoundsError" }); + } + }; + RecursiveReadLimitExceededError = class RecursiveReadLimitExceededError extends BaseError { + constructor({ count, limit }) { + super(`Recursive read limit of \`${limit}\` exceeded (recursive read count: \`${count}\`).`, { name: "RecursiveReadLimitExceededError" }); + } + }; +}); + +// node_modules/viem/_esm/utils/cursor.js +function createCursor(bytes, { recursiveReadLimit = 8192 } = {}) { + const cursor = Object.create(staticCursor); + cursor.bytes = bytes; + cursor.dataView = new DataView(bytes.buffer ?? bytes, bytes.byteOffset, bytes.byteLength); + cursor.positionReadCount = new Map; + cursor.recursiveReadLimit = recursiveReadLimit; + return cursor; +} +var staticCursor; +var init_cursor2 = __esm(() => { + init_cursor(); + staticCursor = { + bytes: new Uint8Array, + dataView: new DataView(new ArrayBuffer(0)), + position: 0, + positionReadCount: new Map, + recursiveReadCount: 0, + recursiveReadLimit: Number.POSITIVE_INFINITY, + assertReadLimit() { + if (this.recursiveReadCount >= this.recursiveReadLimit) + throw new RecursiveReadLimitExceededError({ + count: this.recursiveReadCount + 1, + limit: this.recursiveReadLimit + }); + }, + assertPosition(position) { + if (position < 0 || position > this.bytes.length - 1) + throw new PositionOutOfBoundsError({ + length: this.bytes.length, + position + }); + }, + decrementPosition(offset) { + if (offset < 0) + throw new NegativeOffsetError({ offset }); + const position = this.position - offset; + this.assertPosition(position); + this.position = position; + }, + getReadCount(position) { + return this.positionReadCount.get(position || this.position) || 0; + }, + incrementPosition(offset) { + if (offset < 0) + throw new NegativeOffsetError({ offset }); + const position = this.position + offset; + this.assertPosition(position); + this.position = position; + }, + inspectByte(position_) { + const position = position_ ?? this.position; + this.assertPosition(position); + return this.bytes[position]; + }, + inspectBytes(length, position_) { + const position = position_ ?? this.position; + this.assertPosition(position + length - 1); + return this.bytes.subarray(position, position + length); + }, + inspectUint8(position_) { + const position = position_ ?? this.position; + this.assertPosition(position); + return this.bytes[position]; + }, + inspectUint16(position_) { + const position = position_ ?? this.position; + this.assertPosition(position + 1); + return this.dataView.getUint16(position); + }, + inspectUint24(position_) { + const position = position_ ?? this.position; + this.assertPosition(position + 2); + return (this.dataView.getUint16(position) << 8) + this.dataView.getUint8(position + 2); + }, + inspectUint32(position_) { + const position = position_ ?? this.position; + this.assertPosition(position + 3); + return this.dataView.getUint32(position); + }, + pushByte(byte) { + this.assertPosition(this.position); + this.bytes[this.position] = byte; + this.position++; + }, + pushBytes(bytes) { + this.assertPosition(this.position + bytes.length - 1); + this.bytes.set(bytes, this.position); + this.position += bytes.length; + }, + pushUint8(value) { + this.assertPosition(this.position); + this.bytes[this.position] = value; + this.position++; + }, + pushUint16(value) { + this.assertPosition(this.position + 1); + this.dataView.setUint16(this.position, value); + this.position += 2; + }, + pushUint24(value) { + this.assertPosition(this.position + 2); + this.dataView.setUint16(this.position, value >> 8); + this.dataView.setUint8(this.position + 2, value & ~4294967040); + this.position += 3; + }, + pushUint32(value) { + this.assertPosition(this.position + 3); + this.dataView.setUint32(this.position, value); + this.position += 4; + }, + readByte() { + this.assertReadLimit(); + this._touch(); + const value = this.inspectByte(); + this.position++; + return value; + }, + readBytes(length, size2) { + this.assertReadLimit(); + this._touch(); + const value = this.inspectBytes(length); + this.position += size2 ?? length; + return value; + }, + readUint8() { + this.assertReadLimit(); + this._touch(); + const value = this.inspectUint8(); + this.position += 1; + return value; + }, + readUint16() { + this.assertReadLimit(); + this._touch(); + const value = this.inspectUint16(); + this.position += 2; + return value; + }, + readUint24() { + this.assertReadLimit(); + this._touch(); + const value = this.inspectUint24(); + this.position += 3; + return value; + }, + readUint32() { + this.assertReadLimit(); + this._touch(); + const value = this.inspectUint32(); + this.position += 4; + return value; + }, + get remaining() { + return this.bytes.length - this.position; + }, + setPosition(position) { + const oldPosition = this.position; + this.assertPosition(position); + this.position = position; + return () => this.position = oldPosition; + }, + _touch() { + if (this.recursiveReadLimit === Number.POSITIVE_INFINITY) + return; + const count = this.getReadCount(); + this.positionReadCount.set(this.position, count + 1); + if (count > 0) + this.recursiveReadCount++; + } + }; +}); + +// node_modules/viem/_esm/utils/encoding/toRlp.js +function toRlp(bytes, to = "hex") { + const encodable = getEncodable(bytes); + const cursor = createCursor(new Uint8Array(encodable.length)); + encodable.encode(cursor); + if (to === "hex") + return bytesToHex2(cursor.bytes); + return cursor.bytes; +} +function getEncodable(bytes) { + if (Array.isArray(bytes)) + return getEncodableList(bytes.map((x) => getEncodable(x))); + return getEncodableBytes(bytes); +} +function getEncodableList(list) { + const bodyLength = list.reduce((acc, x) => acc + x.length, 0); + const sizeOfBodyLength = getSizeOfLength(bodyLength); + const length = (() => { + if (bodyLength <= 55) + return 1 + bodyLength; + return 1 + sizeOfBodyLength + bodyLength; + })(); + return { + length, + encode(cursor) { + if (bodyLength <= 55) { + cursor.pushByte(192 + bodyLength); + } else { + cursor.pushByte(192 + 55 + sizeOfBodyLength); + if (sizeOfBodyLength === 1) + cursor.pushUint8(bodyLength); + else if (sizeOfBodyLength === 2) + cursor.pushUint16(bodyLength); + else if (sizeOfBodyLength === 3) + cursor.pushUint24(bodyLength); + else + cursor.pushUint32(bodyLength); + } + for (const { encode } of list) { + encode(cursor); + } + } + }; +} +function getEncodableBytes(bytesOrHex) { + const bytes = typeof bytesOrHex === "string" ? hexToBytes2(bytesOrHex) : bytesOrHex; + const sizeOfBytesLength = getSizeOfLength(bytes.length); + const length = (() => { + if (bytes.length === 1 && bytes[0] < 128) + return 1; + if (bytes.length <= 55) + return 1 + bytes.length; + return 1 + sizeOfBytesLength + bytes.length; + })(); + return { + length, + encode(cursor) { + if (bytes.length === 1 && bytes[0] < 128) { + cursor.pushBytes(bytes); + } else if (bytes.length <= 55) { + cursor.pushByte(128 + bytes.length); + cursor.pushBytes(bytes); + } else { + cursor.pushByte(128 + 55 + sizeOfBytesLength); + if (sizeOfBytesLength === 1) + cursor.pushUint8(bytes.length); + else if (sizeOfBytesLength === 2) + cursor.pushUint16(bytes.length); + else if (sizeOfBytesLength === 3) + cursor.pushUint24(bytes.length); + else + cursor.pushUint32(bytes.length); + cursor.pushBytes(bytes); + } + } + }; +} +function getSizeOfLength(length) { + if (length < 2 ** 8) + return 1; + if (length < 2 ** 16) + return 2; + if (length < 2 ** 24) + return 3; + if (length < 2 ** 32) + return 4; + throw new BaseError("Length is too large."); +} +var init_toRlp = __esm(() => { + init_base(); + init_cursor2(); + init_toBytes(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/authorization/hashAuthorization.js +function hashAuthorization(parameters) { + const { chainId, nonce, to } = parameters; + const address = parameters.contractAddress ?? parameters.address; + const hash = keccak256(concatHex([ + "0x05", + toRlp([ + chainId ? numberToHex(chainId) : "0x", + address, + nonce ? numberToHex(nonce) : "0x" + ]) + ])); + if (to === "bytes") + return hexToBytes2(hash); + return hash; +} +var init_hashAuthorization = __esm(() => { + init_toBytes(); + init_toHex(); + init_toRlp(); + init_keccak256(); +}); + +// node_modules/viem/_esm/accounts/utils/signAuthorization.js +async function signAuthorization(parameters) { + const { chainId, nonce, privateKey, to = "object" } = parameters; + const address = parameters.contractAddress ?? parameters.address; + const signature = await sign({ + hash: hashAuthorization({ address, chainId, nonce }), + privateKey, + to + }); + if (to === "object") + return { + address, + chainId, + nonce, + ...signature + }; + return signature; +} +var init_signAuthorization = __esm(() => { + init_hashAuthorization(); + init_sign(); +}); + +// node_modules/viem/_esm/constants/strings.js +var presignMessagePrefix = `\x19Ethereum Signed Message: +`; + +// node_modules/viem/_esm/utils/signature/toPrefixedMessage.js +function toPrefixedMessage(message_) { + const message = (() => { + if (typeof message_ === "string") + return stringToHex(message_); + if (typeof message_.raw === "string") + return message_.raw; + return bytesToHex2(message_.raw); + })(); + const prefix = stringToHex(`${presignMessagePrefix}${size(message)}`); + return concat([prefix, message]); +} +var init_toPrefixedMessage = __esm(() => { + init_size(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/signature/hashMessage.js +function hashMessage(message, to_) { + return keccak256(toPrefixedMessage(message), to_); +} +var init_hashMessage = __esm(() => { + init_keccak256(); + init_toPrefixedMessage(); +}); + +// node_modules/viem/_esm/accounts/utils/signMessage.js +async function signMessage({ message, privateKey }) { + return await sign({ hash: hashMessage(message), privateKey, to: "hex" }); +} +var init_signMessage = __esm(() => { + init_hashMessage(); + init_sign(); +}); + +// node_modules/viem/_esm/constants/unit.js +var gweiUnits; +var init_unit = __esm(() => { + gweiUnits = { + ether: -9, + wei: 9 + }; +}); + +// node_modules/viem/_esm/utils/unit/formatUnits.js +function formatUnits(value, decimals) { + let display = value.toString(); + const negative = display.startsWith("-"); + if (negative) + display = display.slice(1); + display = display.padStart(decimals, "0"); + let [integer, fraction] = [ + display.slice(0, display.length - decimals), + display.slice(display.length - decimals) + ]; + fraction = fraction.replace(/(0+)$/, ""); + return `${negative ? "-" : ""}${integer || "0"}${fraction ? `.${fraction}` : ""}`; +} + +// node_modules/viem/_esm/utils/unit/formatGwei.js +function formatGwei(wei, unit = "wei") { + return formatUnits(wei, gweiUnits[unit]); +} +var init_formatGwei = __esm(() => { + init_unit(); +}); + +// node_modules/viem/_esm/errors/transaction.js +function prettyPrint(args) { + const entries = Object.entries(args).map(([key, value]) => { + if (value === undefined || value === false) + return null; + return [key, value]; + }).filter(Boolean); + const maxLength = entries.reduce((acc, [key]) => Math.max(acc, key.length), 0); + return entries.map(([key, value]) => ` ${`${key}:`.padEnd(maxLength + 1)} ${value}`).join(` +`); +} +var InvalidLegacyVError, InvalidSerializableTransactionError, InvalidStorageKeySizeError; +var init_transaction = __esm(() => { + init_base(); + InvalidLegacyVError = class InvalidLegacyVError extends BaseError { + constructor({ v }) { + super(`Invalid \`v\` value "${v}". Expected 27 or 28.`, { + name: "InvalidLegacyVError" + }); + } + }; + InvalidSerializableTransactionError = class InvalidSerializableTransactionError extends BaseError { + constructor({ transaction }) { + super("Cannot infer a transaction type from provided transaction.", { + metaMessages: [ + "Provided Transaction:", + "{", + prettyPrint(transaction), + "}", + "", + "To infer the type, either provide:", + "- a `type` to the Transaction, or", + "- an EIP-1559 Transaction with `maxFeePerGas`, or", + "- an EIP-2930 Transaction with `gasPrice` & `accessList`, or", + "- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or", + "- an EIP-7702 Transaction with `authorizationList`, or", + "- a Legacy Transaction with `gasPrice`" + ], + name: "InvalidSerializableTransactionError" + }); + } + }; + InvalidStorageKeySizeError = class InvalidStorageKeySizeError extends BaseError { + constructor({ storageKey }) { + super(`Size for storage key "${storageKey}" is invalid. Expected 32 bytes. Got ${Math.floor((storageKey.length - 2) / 2)} bytes.`, { name: "InvalidStorageKeySizeError" }); + } + }; +}); + +// node_modules/viem/_esm/utils/authorization/serializeAuthorizationList.js +function serializeAuthorizationList(authorizationList) { + if (!authorizationList || authorizationList.length === 0) + return []; + const serializedAuthorizationList = []; + for (const authorization of authorizationList) { + const { chainId, nonce, ...signature } = authorization; + const contractAddress = authorization.address; + serializedAuthorizationList.push([ + chainId ? toHex(chainId) : "0x", + contractAddress, + nonce ? toHex(nonce) : "0x", + ...toYParitySignatureArray({}, signature) + ]); + } + return serializedAuthorizationList; +} +var init_serializeAuthorizationList = __esm(() => { + init_toHex(); + init_serializeTransaction(); +}); + +// node_modules/viem/_esm/utils/blob/blobsToCommitments.js +function blobsToCommitments(parameters) { + const { kzg } = parameters; + const to = parameters.to ?? (typeof parameters.blobs[0] === "string" ? "hex" : "bytes"); + const blobs = typeof parameters.blobs[0] === "string" ? parameters.blobs.map((x) => hexToBytes2(x)) : parameters.blobs; + const commitments = []; + for (const blob of blobs) + commitments.push(Uint8Array.from(kzg.blobToKzgCommitment(blob))); + return to === "bytes" ? commitments : commitments.map((x) => bytesToHex2(x)); +} +var init_blobsToCommitments = __esm(() => { + init_toBytes(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/blob/blobsToProofs.js +function blobsToProofs(parameters) { + const { kzg } = parameters; + const to = parameters.to ?? (typeof parameters.blobs[0] === "string" ? "hex" : "bytes"); + const blobs = typeof parameters.blobs[0] === "string" ? parameters.blobs.map((x) => hexToBytes2(x)) : parameters.blobs; + const commitments = typeof parameters.commitments[0] === "string" ? parameters.commitments.map((x) => hexToBytes2(x)) : parameters.commitments; + const proofs = []; + for (let i = 0;i < blobs.length; i++) { + const blob = blobs[i]; + const commitment = commitments[i]; + proofs.push(Uint8Array.from(kzg.computeBlobKzgProof(blob, commitment))); + } + return to === "bytes" ? proofs : proofs.map((x) => bytesToHex2(x)); +} +var init_blobsToProofs = __esm(() => { + init_toBytes(); + init_toHex(); +}); + +// node_modules/@noble/hashes/esm/sha256.js +var sha2562; +var init_sha256 = __esm(() => { + init_sha2(); + sha2562 = sha256; +}); + +// node_modules/viem/_esm/utils/hash/sha256.js +function sha2563(value, to_) { + const to = to_ || "hex"; + const bytes = sha2562(isHex(value, { strict: false }) ? toBytes2(value) : value); + if (to === "bytes") + return bytes; + return toHex(bytes); +} +var init_sha2562 = __esm(() => { + init_sha256(); + init_toBytes(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/blob/commitmentToVersionedHash.js +function commitmentToVersionedHash(parameters) { + const { commitment, version: version2 = 1 } = parameters; + const to = parameters.to ?? (typeof commitment === "string" ? "hex" : "bytes"); + const versionedHash = sha2563(commitment, "bytes"); + versionedHash.set([version2], 0); + return to === "bytes" ? versionedHash : bytesToHex2(versionedHash); +} +var init_commitmentToVersionedHash = __esm(() => { + init_toHex(); + init_sha2562(); +}); + +// node_modules/viem/_esm/utils/blob/commitmentsToVersionedHashes.js +function commitmentsToVersionedHashes(parameters) { + const { commitments, version: version2 } = parameters; + const to = parameters.to ?? (typeof commitments[0] === "string" ? "hex" : "bytes"); + const hashes = []; + for (const commitment of commitments) { + hashes.push(commitmentToVersionedHash({ + commitment, + to, + version: version2 + })); + } + return hashes; +} +var init_commitmentsToVersionedHashes = __esm(() => { + init_commitmentToVersionedHash(); +}); + +// node_modules/viem/_esm/constants/blob.js +var blobsPerTransaction = 6, bytesPerFieldElement = 32, fieldElementsPerBlob = 4096, bytesPerBlob, maxBytesPerTransaction; +var init_blob = __esm(() => { + bytesPerBlob = bytesPerFieldElement * fieldElementsPerBlob; + maxBytesPerTransaction = bytesPerBlob * blobsPerTransaction - 1 - 1 * fieldElementsPerBlob * blobsPerTransaction; +}); + +// node_modules/viem/_esm/constants/kzg.js +var versionedHashVersionKzg = 1; + +// node_modules/viem/_esm/errors/blob.js +var BlobSizeTooLargeError, EmptyBlobError, InvalidVersionedHashSizeError, InvalidVersionedHashVersionError; +var init_blob2 = __esm(() => { + init_base(); + BlobSizeTooLargeError = class BlobSizeTooLargeError extends BaseError { + constructor({ maxSize, size: size2 }) { + super("Blob size is too large.", { + metaMessages: [`Max: ${maxSize} bytes`, `Given: ${size2} bytes`], + name: "BlobSizeTooLargeError" + }); + } + }; + EmptyBlobError = class EmptyBlobError extends BaseError { + constructor() { + super("Blob data must not be empty.", { name: "EmptyBlobError" }); + } + }; + InvalidVersionedHashSizeError = class InvalidVersionedHashSizeError extends BaseError { + constructor({ hash, size: size2 }) { + super(`Versioned hash "${hash}" size is invalid.`, { + metaMessages: ["Expected: 32", `Received: ${size2}`], + name: "InvalidVersionedHashSizeError" + }); + } + }; + InvalidVersionedHashVersionError = class InvalidVersionedHashVersionError extends BaseError { + constructor({ hash, version: version2 }) { + super(`Versioned hash "${hash}" version is invalid.`, { + metaMessages: [ + `Expected: ${versionedHashVersionKzg}`, + `Received: ${version2}` + ], + name: "InvalidVersionedHashVersionError" + }); + } + }; +}); + +// node_modules/viem/_esm/utils/blob/toBlobs.js +function toBlobs(parameters) { + const to = parameters.to ?? (typeof parameters.data === "string" ? "hex" : "bytes"); + const data = typeof parameters.data === "string" ? hexToBytes2(parameters.data) : parameters.data; + const size_ = size(data); + if (!size_) + throw new EmptyBlobError; + if (size_ > maxBytesPerTransaction) + throw new BlobSizeTooLargeError({ + maxSize: maxBytesPerTransaction, + size: size_ + }); + const blobs = []; + let active = true; + let position = 0; + while (active) { + const blob = createCursor(new Uint8Array(bytesPerBlob)); + let size2 = 0; + while (size2 < fieldElementsPerBlob) { + const bytes = data.slice(position, position + (bytesPerFieldElement - 1)); + blob.pushByte(0); + blob.pushBytes(bytes); + if (bytes.length < 31) { + blob.pushByte(128); + active = false; + break; + } + size2++; + position += 31; + } + blobs.push(blob); + } + return to === "bytes" ? blobs.map((x) => x.bytes) : blobs.map((x) => bytesToHex2(x.bytes)); +} +var init_toBlobs = __esm(() => { + init_blob(); + init_blob2(); + init_cursor2(); + init_size(); + init_toBytes(); + init_toHex(); +}); + +// node_modules/viem/_esm/utils/blob/toBlobSidecars.js +function toBlobSidecars(parameters) { + const { data, kzg, to } = parameters; + const blobs = parameters.blobs ?? toBlobs({ data, to }); + const commitments = parameters.commitments ?? blobsToCommitments({ blobs, kzg, to }); + const proofs = parameters.proofs ?? blobsToProofs({ blobs, commitments, kzg, to }); + const sidecars = []; + for (let i = 0;i < blobs.length; i++) + sidecars.push({ + blob: blobs[i], + commitment: commitments[i], + proof: proofs[i] + }); + return sidecars; +} +var init_toBlobSidecars = __esm(() => { + init_blobsToCommitments(); + init_blobsToProofs(); + init_toBlobs(); +}); + +// node_modules/viem/_esm/constants/number.js +var maxInt8, maxInt16, maxInt24, maxInt32, maxInt40, maxInt48, maxInt56, maxInt64, maxInt72, maxInt80, maxInt88, maxInt96, maxInt104, maxInt112, maxInt120, maxInt128, maxInt136, maxInt144, maxInt152, maxInt160, maxInt168, maxInt176, maxInt184, maxInt192, maxInt200, maxInt208, maxInt216, maxInt224, maxInt232, maxInt240, maxInt248, maxInt256, minInt8, minInt16, minInt24, minInt32, minInt40, minInt48, minInt56, minInt64, minInt72, minInt80, minInt88, minInt96, minInt104, minInt112, minInt120, minInt128, minInt136, minInt144, minInt152, minInt160, minInt168, minInt176, minInt184, minInt192, minInt200, minInt208, minInt216, minInt224, minInt232, minInt240, minInt248, minInt256, maxUint8, maxUint16, maxUint24, maxUint32, maxUint40, maxUint48, maxUint56, maxUint64, maxUint72, maxUint80, maxUint88, maxUint96, maxUint104, maxUint112, maxUint120, maxUint128, maxUint136, maxUint144, maxUint152, maxUint160, maxUint168, maxUint176, maxUint184, maxUint192, maxUint200, maxUint208, maxUint216, maxUint224, maxUint232, maxUint240, maxUint248, maxUint256; +var init_number = __esm(() => { + maxInt8 = 2n ** (8n - 1n) - 1n; + maxInt16 = 2n ** (16n - 1n) - 1n; + maxInt24 = 2n ** (24n - 1n) - 1n; + maxInt32 = 2n ** (32n - 1n) - 1n; + maxInt40 = 2n ** (40n - 1n) - 1n; + maxInt48 = 2n ** (48n - 1n) - 1n; + maxInt56 = 2n ** (56n - 1n) - 1n; + maxInt64 = 2n ** (64n - 1n) - 1n; + maxInt72 = 2n ** (72n - 1n) - 1n; + maxInt80 = 2n ** (80n - 1n) - 1n; + maxInt88 = 2n ** (88n - 1n) - 1n; + maxInt96 = 2n ** (96n - 1n) - 1n; + maxInt104 = 2n ** (104n - 1n) - 1n; + maxInt112 = 2n ** (112n - 1n) - 1n; + maxInt120 = 2n ** (120n - 1n) - 1n; + maxInt128 = 2n ** (128n - 1n) - 1n; + maxInt136 = 2n ** (136n - 1n) - 1n; + maxInt144 = 2n ** (144n - 1n) - 1n; + maxInt152 = 2n ** (152n - 1n) - 1n; + maxInt160 = 2n ** (160n - 1n) - 1n; + maxInt168 = 2n ** (168n - 1n) - 1n; + maxInt176 = 2n ** (176n - 1n) - 1n; + maxInt184 = 2n ** (184n - 1n) - 1n; + maxInt192 = 2n ** (192n - 1n) - 1n; + maxInt200 = 2n ** (200n - 1n) - 1n; + maxInt208 = 2n ** (208n - 1n) - 1n; + maxInt216 = 2n ** (216n - 1n) - 1n; + maxInt224 = 2n ** (224n - 1n) - 1n; + maxInt232 = 2n ** (232n - 1n) - 1n; + maxInt240 = 2n ** (240n - 1n) - 1n; + maxInt248 = 2n ** (248n - 1n) - 1n; + maxInt256 = 2n ** (256n - 1n) - 1n; + minInt8 = -(2n ** (8n - 1n)); + minInt16 = -(2n ** (16n - 1n)); + minInt24 = -(2n ** (24n - 1n)); + minInt32 = -(2n ** (32n - 1n)); + minInt40 = -(2n ** (40n - 1n)); + minInt48 = -(2n ** (48n - 1n)); + minInt56 = -(2n ** (56n - 1n)); + minInt64 = -(2n ** (64n - 1n)); + minInt72 = -(2n ** (72n - 1n)); + minInt80 = -(2n ** (80n - 1n)); + minInt88 = -(2n ** (88n - 1n)); + minInt96 = -(2n ** (96n - 1n)); + minInt104 = -(2n ** (104n - 1n)); + minInt112 = -(2n ** (112n - 1n)); + minInt120 = -(2n ** (120n - 1n)); + minInt128 = -(2n ** (128n - 1n)); + minInt136 = -(2n ** (136n - 1n)); + minInt144 = -(2n ** (144n - 1n)); + minInt152 = -(2n ** (152n - 1n)); + minInt160 = -(2n ** (160n - 1n)); + minInt168 = -(2n ** (168n - 1n)); + minInt176 = -(2n ** (176n - 1n)); + minInt184 = -(2n ** (184n - 1n)); + minInt192 = -(2n ** (192n - 1n)); + minInt200 = -(2n ** (200n - 1n)); + minInt208 = -(2n ** (208n - 1n)); + minInt216 = -(2n ** (216n - 1n)); + minInt224 = -(2n ** (224n - 1n)); + minInt232 = -(2n ** (232n - 1n)); + minInt240 = -(2n ** (240n - 1n)); + minInt248 = -(2n ** (248n - 1n)); + minInt256 = -(2n ** (256n - 1n)); + maxUint8 = 2n ** 8n - 1n; + maxUint16 = 2n ** 16n - 1n; + maxUint24 = 2n ** 24n - 1n; + maxUint32 = 2n ** 32n - 1n; + maxUint40 = 2n ** 40n - 1n; + maxUint48 = 2n ** 48n - 1n; + maxUint56 = 2n ** 56n - 1n; + maxUint64 = 2n ** 64n - 1n; + maxUint72 = 2n ** 72n - 1n; + maxUint80 = 2n ** 80n - 1n; + maxUint88 = 2n ** 88n - 1n; + maxUint96 = 2n ** 96n - 1n; + maxUint104 = 2n ** 104n - 1n; + maxUint112 = 2n ** 112n - 1n; + maxUint120 = 2n ** 120n - 1n; + maxUint128 = 2n ** 128n - 1n; + maxUint136 = 2n ** 136n - 1n; + maxUint144 = 2n ** 144n - 1n; + maxUint152 = 2n ** 152n - 1n; + maxUint160 = 2n ** 160n - 1n; + maxUint168 = 2n ** 168n - 1n; + maxUint176 = 2n ** 176n - 1n; + maxUint184 = 2n ** 184n - 1n; + maxUint192 = 2n ** 192n - 1n; + maxUint200 = 2n ** 200n - 1n; + maxUint208 = 2n ** 208n - 1n; + maxUint216 = 2n ** 216n - 1n; + maxUint224 = 2n ** 224n - 1n; + maxUint232 = 2n ** 232n - 1n; + maxUint240 = 2n ** 240n - 1n; + maxUint248 = 2n ** 248n - 1n; + maxUint256 = 2n ** 256n - 1n; +}); + +// node_modules/viem/_esm/errors/chain.js +var InvalidChainIdError; +var init_chain = __esm(() => { + init_base(); + InvalidChainIdError = class InvalidChainIdError extends BaseError { + constructor({ chainId }) { + super(typeof chainId === "number" ? `Chain ID "${chainId}" is invalid.` : "Chain ID is invalid.", { name: "InvalidChainIdError" }); + } + }; +}); + +// node_modules/viem/_esm/errors/node.js +var ExecutionRevertedError, FeeCapTooHighError, FeeCapTooLowError, NonceTooHighError, NonceTooLowError, NonceMaxValueError, InsufficientFundsError, IntrinsicGasTooHighError, IntrinsicGasTooLowError, TransactionTypeNotSupportedError, TipAboveFeeCapError; +var init_node = __esm(() => { + init_formatGwei(); + init_base(); + ExecutionRevertedError = class ExecutionRevertedError extends BaseError { + constructor({ cause, message } = {}) { + const reason = message?.replace("execution reverted: ", "")?.replace("execution reverted", ""); + super(`Execution reverted ${reason ? `with reason: ${reason}` : "for an unknown reason"}.`, { + cause, + name: "ExecutionRevertedError" + }); + } + }; + Object.defineProperty(ExecutionRevertedError, "code", { + enumerable: true, + configurable: true, + writable: true, + value: 3 + }); + Object.defineProperty(ExecutionRevertedError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /execution reverted|gas required exceeds allowance/ + }); + FeeCapTooHighError = class FeeCapTooHighError extends BaseError { + constructor({ cause, maxFeePerGas } = {}) { + super(`The fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)} gwei` : ""}) cannot be higher than the maximum allowed value (2^256-1).`, { + cause, + name: "FeeCapTooHighError" + }); + } + }; + Object.defineProperty(FeeCapTooHighError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /max fee per gas higher than 2\^256-1|fee cap higher than 2\^256-1/ + }); + FeeCapTooLowError = class FeeCapTooLowError extends BaseError { + constructor({ cause, maxFeePerGas } = {}) { + super(`The fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)}` : ""} gwei) cannot be lower than the block base fee.`, { + cause, + name: "FeeCapTooLowError" + }); + } + }; + Object.defineProperty(FeeCapTooLowError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /max fee per gas less than block base fee|fee cap less than block base fee|transaction is outdated/ + }); + NonceTooHighError = class NonceTooHighError extends BaseError { + constructor({ cause, nonce } = {}) { + super(`Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}is higher than the next one expected.`, { cause, name: "NonceTooHighError" }); + } + }; + Object.defineProperty(NonceTooHighError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /nonce too high/ + }); + NonceTooLowError = class NonceTooLowError extends BaseError { + constructor({ cause, nonce } = {}) { + super([ + `Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}is lower than the current nonce of the account.`, + "Try increasing the nonce or find the latest nonce with `getTransactionCount`." + ].join(` +`), { cause, name: "NonceTooLowError" }); + } + }; + Object.defineProperty(NonceTooLowError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /nonce too low|transaction already imported|already known/ + }); + NonceMaxValueError = class NonceMaxValueError extends BaseError { + constructor({ cause, nonce } = {}) { + super(`Nonce provided for the transaction ${nonce ? `(${nonce}) ` : ""}exceeds the maximum allowed nonce.`, { cause, name: "NonceMaxValueError" }); + } + }; + Object.defineProperty(NonceMaxValueError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /nonce has max value/ + }); + InsufficientFundsError = class InsufficientFundsError extends BaseError { + constructor({ cause } = {}) { + super([ + "The total cost (gas * gas fee + value) of executing this transaction exceeds the balance of the account." + ].join(` +`), { + cause, + metaMessages: [ + "This error could arise when the account does not have enough funds to:", + " - pay for the total gas fee,", + " - pay for the value to send.", + " ", + "The cost of the transaction is calculated as `gas * gas fee + value`, where:", + " - `gas` is the amount of gas needed for transaction to execute,", + " - `gas fee` is the gas fee,", + " - `value` is the amount of ether to send to the recipient." + ], + name: "InsufficientFundsError" + }); + } + }; + Object.defineProperty(InsufficientFundsError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /insufficient funds|exceeds transaction sender account balance/ + }); + IntrinsicGasTooHighError = class IntrinsicGasTooHighError extends BaseError { + constructor({ cause, gas } = {}) { + super(`The amount of gas ${gas ? `(${gas}) ` : ""}provided for the transaction exceeds the limit allowed for the block.`, { + cause, + name: "IntrinsicGasTooHighError" + }); + } + }; + Object.defineProperty(IntrinsicGasTooHighError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /intrinsic gas too high|gas limit reached/ + }); + IntrinsicGasTooLowError = class IntrinsicGasTooLowError extends BaseError { + constructor({ cause, gas } = {}) { + super(`The amount of gas ${gas ? `(${gas}) ` : ""}provided for the transaction is too low.`, { + cause, + name: "IntrinsicGasTooLowError" + }); + } + }; + Object.defineProperty(IntrinsicGasTooLowError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /intrinsic gas too low/ + }); + TransactionTypeNotSupportedError = class TransactionTypeNotSupportedError extends BaseError { + constructor({ cause }) { + super("The transaction type is not supported for this chain.", { + cause, + name: "TransactionTypeNotSupportedError" + }); + } + }; + Object.defineProperty(TransactionTypeNotSupportedError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /transaction type not valid/ + }); + TipAboveFeeCapError = class TipAboveFeeCapError extends BaseError { + constructor({ cause, maxPriorityFeePerGas, maxFeePerGas } = {}) { + super([ + `The provided tip (\`maxPriorityFeePerGas\`${maxPriorityFeePerGas ? ` = ${formatGwei(maxPriorityFeePerGas)} gwei` : ""}) cannot be higher than the fee cap (\`maxFeePerGas\`${maxFeePerGas ? ` = ${formatGwei(maxFeePerGas)} gwei` : ""}).` + ].join(` +`), { + cause, + name: "TipAboveFeeCapError" + }); + } + }; + Object.defineProperty(TipAboveFeeCapError, "nodeMessage", { + enumerable: true, + configurable: true, + writable: true, + value: /max priority fee per gas higher than max fee per gas|tip higher than fee cap/ + }); +}); + +// node_modules/viem/_esm/utils/data/slice.js +function slice(value, start, end, { strict } = {}) { + if (isHex(value, { strict: false })) + return sliceHex(value, start, end, { + strict + }); + return sliceBytes(value, start, end, { + strict + }); +} +function assertStartOffset(value, start) { + if (typeof start === "number" && start > 0 && start > size(value) - 1) + throw new SliceOffsetOutOfBoundsError({ + offset: start, + position: "start", + size: size(value) + }); +} +function assertEndOffset(value, start, end) { + if (typeof start === "number" && typeof end === "number" && size(value) !== end - start) { + throw new SliceOffsetOutOfBoundsError({ + offset: end, + position: "end", + size: size(value) + }); + } +} +function sliceBytes(value_, start, end, { strict } = {}) { + assertStartOffset(value_, start); + const value = value_.slice(start, end); + if (strict) + assertEndOffset(value, start, end); + return value; +} +function sliceHex(value_, start, end, { strict } = {}) { + assertStartOffset(value_, start); + const value = `0x${value_.replace("0x", "").slice((start ?? 0) * 2, (end ?? value_.length) * 2)}`; + if (strict) + assertEndOffset(value, start, end); + return value; +} +var init_slice = __esm(() => { + init_data(); + init_size(); +}); + +// node_modules/viem/_esm/utils/transaction/assertTransaction.js +function assertTransactionEIP7702(transaction) { + const { authorizationList } = transaction; + if (authorizationList) { + for (const authorization of authorizationList) { + const { chainId } = authorization; + const address = authorization.address; + if (!isAddress(address)) + throw new InvalidAddressError({ address }); + if (chainId < 0) + throw new InvalidChainIdError({ chainId }); + } + } + assertTransactionEIP1559(transaction); +} +function assertTransactionEIP4844(transaction) { + const { blobVersionedHashes } = transaction; + if (blobVersionedHashes) { + if (blobVersionedHashes.length === 0) + throw new EmptyBlobError; + for (const hash of blobVersionedHashes) { + const size_ = size(hash); + const version2 = hexToNumber2(slice(hash, 0, 1)); + if (size_ !== 32) + throw new InvalidVersionedHashSizeError({ hash, size: size_ }); + if (version2 !== versionedHashVersionKzg) + throw new InvalidVersionedHashVersionError({ + hash, + version: version2 + }); + } + } + assertTransactionEIP1559(transaction); +} +function assertTransactionEIP1559(transaction) { + const { chainId, maxPriorityFeePerGas, maxFeePerGas, to } = transaction; + if (chainId <= 0) + throw new InvalidChainIdError({ chainId }); + if (to && !isAddress(to)) + throw new InvalidAddressError({ address: to }); + if (maxFeePerGas && maxFeePerGas > maxUint256) + throw new FeeCapTooHighError({ maxFeePerGas }); + if (maxPriorityFeePerGas && maxFeePerGas && maxPriorityFeePerGas > maxFeePerGas) + throw new TipAboveFeeCapError({ maxFeePerGas, maxPriorityFeePerGas }); +} +function assertTransactionEIP2930(transaction) { + const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to } = transaction; + if (chainId <= 0) + throw new InvalidChainIdError({ chainId }); + if (to && !isAddress(to)) + throw new InvalidAddressError({ address: to }); + if (maxPriorityFeePerGas || maxFeePerGas) + throw new BaseError("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid EIP-2930 Transaction attribute."); + if (gasPrice && gasPrice > maxUint256) + throw new FeeCapTooHighError({ maxFeePerGas: gasPrice }); +} +function assertTransactionLegacy(transaction) { + const { chainId, maxPriorityFeePerGas, gasPrice, maxFeePerGas, to } = transaction; + if (to && !isAddress(to)) + throw new InvalidAddressError({ address: to }); + if (typeof chainId !== "undefined" && chainId <= 0) + throw new InvalidChainIdError({ chainId }); + if (maxPriorityFeePerGas || maxFeePerGas) + throw new BaseError("`maxFeePerGas`/`maxPriorityFeePerGas` is not a valid Legacy Transaction attribute."); + if (gasPrice && gasPrice > maxUint256) + throw new FeeCapTooHighError({ maxFeePerGas: gasPrice }); +} +var init_assertTransaction = __esm(() => { + init_number(); + init_address(); + init_base(); + init_blob2(); + init_chain(); + init_node(); + init_isAddress(); + init_size(); + init_slice(); + init_fromHex(); +}); + +// node_modules/viem/_esm/utils/transaction/getTransactionType.js +function getTransactionType(transaction) { + if (transaction.type) + return transaction.type; + if (typeof transaction.authorizationList !== "undefined") + return "eip7702"; + if (typeof transaction.blobs !== "undefined" || typeof transaction.blobVersionedHashes !== "undefined" || typeof transaction.maxFeePerBlobGas !== "undefined" || typeof transaction.sidecars !== "undefined") + return "eip4844"; + if (typeof transaction.maxFeePerGas !== "undefined" || typeof transaction.maxPriorityFeePerGas !== "undefined") { + return "eip1559"; + } + if (typeof transaction.gasPrice !== "undefined") { + if (typeof transaction.accessList !== "undefined") + return "eip2930"; + return "legacy"; + } + throw new InvalidSerializableTransactionError({ transaction }); +} +var init_getTransactionType = __esm(() => { + init_transaction(); +}); + +// node_modules/viem/_esm/utils/transaction/serializeAccessList.js +function serializeAccessList(accessList) { + if (!accessList || accessList.length === 0) + return []; + const serializedAccessList = []; + for (let i = 0;i < accessList.length; i++) { + const { address, storageKeys } = accessList[i]; + for (let j = 0;j < storageKeys.length; j++) { + if (storageKeys[j].length - 2 !== 64) { + throw new InvalidStorageKeySizeError({ storageKey: storageKeys[j] }); + } + } + if (!isAddress(address, { strict: false })) { + throw new InvalidAddressError({ address }); + } + serializedAccessList.push([address, storageKeys]); + } + return serializedAccessList; +} +var init_serializeAccessList = __esm(() => { + init_address(); + init_transaction(); + init_isAddress(); +}); + +// node_modules/viem/_esm/utils/transaction/serializeTransaction.js +function serializeTransaction(transaction, signature) { + const type = getTransactionType(transaction); + if (type === "eip1559") + return serializeTransactionEIP1559(transaction, signature); + if (type === "eip2930") + return serializeTransactionEIP2930(transaction, signature); + if (type === "eip4844") + return serializeTransactionEIP4844(transaction, signature); + if (type === "eip7702") + return serializeTransactionEIP7702(transaction, signature); + return serializeTransactionLegacy(transaction, signature); +} +function serializeTransactionEIP7702(transaction, signature) { + const { authorizationList, chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + assertTransactionEIP7702(transaction); + const serializedAccessList = serializeAccessList(accessList); + const serializedAuthorizationList = serializeAuthorizationList(authorizationList); + return concatHex([ + "0x04", + toRlp([ + numberToHex(chainId), + nonce ? numberToHex(nonce) : "0x", + maxPriorityFeePerGas ? numberToHex(maxPriorityFeePerGas) : "0x", + maxFeePerGas ? numberToHex(maxFeePerGas) : "0x", + gas ? numberToHex(gas) : "0x", + to ?? "0x", + value ? numberToHex(value) : "0x", + data ?? "0x", + serializedAccessList, + serializedAuthorizationList, + ...toYParitySignatureArray(transaction, signature) + ]) + ]); +} +function serializeTransactionEIP4844(transaction, signature) { + const { chainId, gas, nonce, to, value, maxFeePerBlobGas, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + assertTransactionEIP4844(transaction); + let blobVersionedHashes = transaction.blobVersionedHashes; + let sidecars = transaction.sidecars; + if (transaction.blobs && (typeof blobVersionedHashes === "undefined" || typeof sidecars === "undefined")) { + const blobs2 = typeof transaction.blobs[0] === "string" ? transaction.blobs : transaction.blobs.map((x) => bytesToHex2(x)); + const kzg = transaction.kzg; + const commitments2 = blobsToCommitments({ + blobs: blobs2, + kzg + }); + if (typeof blobVersionedHashes === "undefined") + blobVersionedHashes = commitmentsToVersionedHashes({ + commitments: commitments2 + }); + if (typeof sidecars === "undefined") { + const proofs2 = blobsToProofs({ blobs: blobs2, commitments: commitments2, kzg }); + sidecars = toBlobSidecars({ blobs: blobs2, commitments: commitments2, proofs: proofs2 }); + } + } + const serializedAccessList = serializeAccessList(accessList); + const serializedTransaction = [ + numberToHex(chainId), + nonce ? numberToHex(nonce) : "0x", + maxPriorityFeePerGas ? numberToHex(maxPriorityFeePerGas) : "0x", + maxFeePerGas ? numberToHex(maxFeePerGas) : "0x", + gas ? numberToHex(gas) : "0x", + to ?? "0x", + value ? numberToHex(value) : "0x", + data ?? "0x", + serializedAccessList, + maxFeePerBlobGas ? numberToHex(maxFeePerBlobGas) : "0x", + blobVersionedHashes ?? [], + ...toYParitySignatureArray(transaction, signature) + ]; + const blobs = []; + const commitments = []; + const proofs = []; + if (sidecars) + for (let i = 0;i < sidecars.length; i++) { + const { blob, commitment, proof } = sidecars[i]; + blobs.push(blob); + commitments.push(commitment); + proofs.push(proof); + } + return concatHex([ + "0x03", + sidecars ? toRlp([serializedTransaction, blobs, commitments, proofs]) : toRlp(serializedTransaction) + ]); +} +function serializeTransactionEIP1559(transaction, signature) { + const { chainId, gas, nonce, to, value, maxFeePerGas, maxPriorityFeePerGas, accessList, data } = transaction; + assertTransactionEIP1559(transaction); + const serializedAccessList = serializeAccessList(accessList); + const serializedTransaction = [ + numberToHex(chainId), + nonce ? numberToHex(nonce) : "0x", + maxPriorityFeePerGas ? numberToHex(maxPriorityFeePerGas) : "0x", + maxFeePerGas ? numberToHex(maxFeePerGas) : "0x", + gas ? numberToHex(gas) : "0x", + to ?? "0x", + value ? numberToHex(value) : "0x", + data ?? "0x", + serializedAccessList, + ...toYParitySignatureArray(transaction, signature) + ]; + return concatHex([ + "0x02", + toRlp(serializedTransaction) + ]); +} +function serializeTransactionEIP2930(transaction, signature) { + const { chainId, gas, data, nonce, to, value, accessList, gasPrice } = transaction; + assertTransactionEIP2930(transaction); + const serializedAccessList = serializeAccessList(accessList); + const serializedTransaction = [ + numberToHex(chainId), + nonce ? numberToHex(nonce) : "0x", + gasPrice ? numberToHex(gasPrice) : "0x", + gas ? numberToHex(gas) : "0x", + to ?? "0x", + value ? numberToHex(value) : "0x", + data ?? "0x", + serializedAccessList, + ...toYParitySignatureArray(transaction, signature) + ]; + return concatHex([ + "0x01", + toRlp(serializedTransaction) + ]); +} +function serializeTransactionLegacy(transaction, signature) { + const { chainId = 0, gas, data, nonce, to, value, gasPrice } = transaction; + assertTransactionLegacy(transaction); + let serializedTransaction = [ + nonce ? numberToHex(nonce) : "0x", + gasPrice ? numberToHex(gasPrice) : "0x", + gas ? numberToHex(gas) : "0x", + to ?? "0x", + value ? numberToHex(value) : "0x", + data ?? "0x" + ]; + if (signature) { + const v = (() => { + if (signature.v >= 35n) { + const inferredChainId = (signature.v - 35n) / 2n; + if (inferredChainId > 0) + return signature.v; + return 27n + (signature.v === 35n ? 0n : 1n); + } + if (chainId > 0) + return BigInt(chainId * 2) + BigInt(35n + signature.v - 27n); + const v2 = 27n + (signature.v === 27n ? 0n : 1n); + if (signature.v !== v2) + throw new InvalidLegacyVError({ v: signature.v }); + return v2; + })(); + const r = trim(signature.r); + const s = trim(signature.s); + serializedTransaction = [ + ...serializedTransaction, + numberToHex(v), + r === "0x00" ? "0x" : r, + s === "0x00" ? "0x" : s + ]; + } else if (chainId > 0) { + serializedTransaction = [ + ...serializedTransaction, + numberToHex(chainId), + "0x", + "0x" + ]; + } + return toRlp(serializedTransaction); +} +function toYParitySignatureArray(transaction, signature_) { + const signature = signature_ ?? transaction; + const { v, yParity } = signature; + if (typeof signature.r === "undefined") + return []; + if (typeof signature.s === "undefined") + return []; + if (typeof v === "undefined" && typeof yParity === "undefined") + return []; + const r = trim(signature.r); + const s = trim(signature.s); + const yParity_ = (() => { + if (typeof yParity === "number") + return yParity ? numberToHex(1) : "0x"; + if (v === 0n) + return "0x"; + if (v === 1n) + return numberToHex(1); + return v === 27n ? "0x" : numberToHex(1); + })(); + return [yParity_, r === "0x00" ? "0x" : r, s === "0x00" ? "0x" : s]; +} +var init_serializeTransaction = __esm(() => { + init_transaction(); + init_serializeAuthorizationList(); + init_blobsToCommitments(); + init_blobsToProofs(); + init_commitmentsToVersionedHashes(); + init_toBlobSidecars(); + init_toHex(); + init_toRlp(); + init_assertTransaction(); + init_getTransactionType(); + init_serializeAccessList(); +}); + +// node_modules/viem/_esm/accounts/utils/signTransaction.js +async function signTransaction(parameters) { + const { privateKey, transaction, serializer = serializeTransaction } = parameters; + const signableTransaction = (() => { + if (transaction.type === "eip4844") + return { + ...transaction, + sidecars: false + }; + return transaction; + })(); + const signature = await sign({ + hash: keccak256(await serializer(signableTransaction)), + privateKey + }); + return await serializer(transaction, signature); +} +var init_signTransaction = __esm(() => { + init_keccak256(); + init_serializeTransaction(); + init_sign(); +}); + +// node_modules/viem/_esm/errors/abi.js +var AbiEncodingArrayLengthMismatchError, AbiEncodingBytesSizeMismatchError, AbiEncodingLengthMismatchError, BytesSizeMismatchError, InvalidAbiEncodingTypeError, InvalidArrayError; +var init_abi = __esm(() => { + init_size(); + init_base(); + AbiEncodingArrayLengthMismatchError = class AbiEncodingArrayLengthMismatchError extends BaseError { + constructor({ expectedLength, givenLength, type }) { + super([ + `ABI encoding array length mismatch for type ${type}.`, + `Expected length: ${expectedLength}`, + `Given length: ${givenLength}` + ].join(` +`), { name: "AbiEncodingArrayLengthMismatchError" }); + } + }; + AbiEncodingBytesSizeMismatchError = class AbiEncodingBytesSizeMismatchError extends BaseError { + constructor({ expectedSize, value }) { + super(`Size of bytes "${value}" (bytes${size(value)}) does not match expected size (bytes${expectedSize}).`, { name: "AbiEncodingBytesSizeMismatchError" }); + } + }; + AbiEncodingLengthMismatchError = class AbiEncodingLengthMismatchError extends BaseError { + constructor({ expectedLength, givenLength }) { + super([ + "ABI encoding params/values length mismatch.", + `Expected length (params): ${expectedLength}`, + `Given length (values): ${givenLength}` + ].join(` +`), { name: "AbiEncodingLengthMismatchError" }); + } + }; + BytesSizeMismatchError = class BytesSizeMismatchError extends BaseError { + constructor({ expectedSize, givenSize }) { + super(`Expected bytes${expectedSize}, got bytes${givenSize}.`, { + name: "BytesSizeMismatchError" + }); + } + }; + InvalidAbiEncodingTypeError = class InvalidAbiEncodingTypeError extends BaseError { + constructor(type, { docsPath }) { + super([ + `Type "${type}" is not a valid encoding type.`, + "Please provide a valid ABI type." + ].join(` +`), { docsPath, name: "InvalidAbiEncodingType" }); + } + }; + InvalidArrayError = class InvalidArrayError extends BaseError { + constructor(value) { + super([`Value "${value}" is not a valid array.`].join(` +`), { + name: "InvalidArrayError" + }); + } + }; +}); + +// node_modules/viem/_esm/utils/regex.js +var bytesRegex, integerRegex; +var init_regex = __esm(() => { + bytesRegex = /^bytes([1-9]|1[0-9]|2[0-9]|3[0-2])?$/; + integerRegex = /^(u?int)(8|16|24|32|40|48|56|64|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224|232|240|248|256)?$/; +}); + +// node_modules/viem/_esm/utils/abi/encodeAbiParameters.js +function encodeAbiParameters(params, values) { + if (params.length !== values.length) + throw new AbiEncodingLengthMismatchError({ + expectedLength: params.length, + givenLength: values.length + }); + const preparedParams = prepareParams({ + params, + values + }); + const data = encodeParams(preparedParams); + if (data.length === 0) + return "0x"; + return data; +} +function prepareParams({ params, values }) { + const preparedParams = []; + for (let i = 0;i < params.length; i++) { + preparedParams.push(prepareParam({ param: params[i], value: values[i] })); + } + return preparedParams; +} +function prepareParam({ param, value }) { + const arrayComponents = getArrayComponents(param.type); + if (arrayComponents) { + const [length, type] = arrayComponents; + return encodeArray(value, { length, param: { ...param, type } }); + } + if (param.type === "tuple") { + return encodeTuple(value, { + param + }); + } + if (param.type === "address") { + return encodeAddress(value); + } + if (param.type === "bool") { + return encodeBool(value); + } + if (param.type.startsWith("uint") || param.type.startsWith("int")) { + const signed = param.type.startsWith("int"); + const [, , size2 = "256"] = integerRegex.exec(param.type) ?? []; + return encodeNumber(value, { + signed, + size: Number(size2) + }); + } + if (param.type.startsWith("bytes")) { + return encodeBytes(value, { param }); + } + if (param.type === "string") { + return encodeString(value); + } + throw new InvalidAbiEncodingTypeError(param.type, { + docsPath: "/docs/contract/encodeAbiParameters" + }); +} +function encodeParams(preparedParams) { + let staticSize = 0; + for (let i = 0;i < preparedParams.length; i++) { + const { dynamic, encoded } = preparedParams[i]; + if (dynamic) + staticSize += 32; + else + staticSize += size(encoded); + } + const staticParams = []; + const dynamicParams = []; + let dynamicSize = 0; + for (let i = 0;i < preparedParams.length; i++) { + const { dynamic, encoded } = preparedParams[i]; + if (dynamic) { + staticParams.push(numberToHex(staticSize + dynamicSize, { size: 32 })); + dynamicParams.push(encoded); + dynamicSize += size(encoded); + } else { + staticParams.push(encoded); + } + } + return concat([...staticParams, ...dynamicParams]); +} +function encodeAddress(value) { + if (!isAddress(value)) + throw new InvalidAddressError({ address: value }); + return { dynamic: false, encoded: padHex(value.toLowerCase()) }; +} +function encodeArray(value, { length, param }) { + const dynamic = length === null; + if (!Array.isArray(value)) + throw new InvalidArrayError(value); + if (!dynamic && value.length !== length) + throw new AbiEncodingArrayLengthMismatchError({ + expectedLength: length, + givenLength: value.length, + type: `${param.type}[${length}]` + }); + let dynamicChild = false; + const preparedParams = []; + for (let i = 0;i < value.length; i++) { + const preparedParam = prepareParam({ param, value: value[i] }); + if (preparedParam.dynamic) + dynamicChild = true; + preparedParams.push(preparedParam); + } + if (dynamic || dynamicChild) { + const data = encodeParams(preparedParams); + if (dynamic) { + const length2 = numberToHex(preparedParams.length, { size: 32 }); + return { + dynamic: true, + encoded: preparedParams.length > 0 ? concat([length2, data]) : length2 + }; + } + if (dynamicChild) + return { dynamic: true, encoded: data }; + } + return { + dynamic: false, + encoded: concat(preparedParams.map(({ encoded }) => encoded)) + }; +} +function encodeBytes(value, { param }) { + const [, paramSize] = param.type.split("bytes"); + const bytesSize = size(value); + if (!paramSize) { + let value_ = value; + if (bytesSize % 32 !== 0) + value_ = padHex(value_, { + dir: "right", + size: Math.ceil((value.length - 2) / 2 / 32) * 32 + }); + return { + dynamic: true, + encoded: concat([padHex(numberToHex(bytesSize, { size: 32 })), value_]) + }; + } + if (bytesSize !== Number.parseInt(paramSize, 10)) + throw new AbiEncodingBytesSizeMismatchError({ + expectedSize: Number.parseInt(paramSize, 10), + value + }); + return { dynamic: false, encoded: padHex(value, { dir: "right" }) }; +} +function encodeBool(value) { + if (typeof value !== "boolean") + throw new BaseError(`Invalid boolean value: "${value}" (type: ${typeof value}). Expected: \`true\` or \`false\`.`); + return { dynamic: false, encoded: padHex(boolToHex(value)) }; +} +function encodeNumber(value, { signed, size: size2 = 256 }) { + if (typeof size2 === "number") { + const max = 2n ** (BigInt(size2) - (signed ? 1n : 0n)) - 1n; + const min = signed ? -max - 1n : 0n; + if (value > max || value < min) + throw new IntegerOutOfRangeError({ + max: max.toString(), + min: min.toString(), + signed, + size: size2 / 8, + value: value.toString() + }); + } + return { + dynamic: false, + encoded: numberToHex(value, { + size: 32, + signed + }) + }; +} +function encodeString(value) { + const hexValue = stringToHex(value); + const partsLength = Math.ceil(size(hexValue) / 32); + const parts = []; + for (let i = 0;i < partsLength; i++) { + parts.push(padHex(slice(hexValue, i * 32, (i + 1) * 32), { + dir: "right" + })); + } + return { + dynamic: true, + encoded: concat([ + padHex(numberToHex(size(hexValue), { size: 32 })), + ...parts + ]) + }; +} +function encodeTuple(value, { param }) { + let dynamic = false; + const preparedParams = []; + for (let i = 0;i < param.components.length; i++) { + const param_ = param.components[i]; + const index = Array.isArray(value) ? i : param_.name; + const preparedParam = prepareParam({ + param: param_, + value: value[index] + }); + preparedParams.push(preparedParam); + if (preparedParam.dynamic) + dynamic = true; + } + return { + dynamic, + encoded: dynamic ? encodeParams(preparedParams) : concat(preparedParams.map(({ encoded }) => encoded)) + }; +} +function getArrayComponents(type) { + const matches = type.match(/^(.*)\[(\d+)?\]$/); + return matches ? [matches[2] ? Number(matches[2]) : null, matches[1]] : undefined; +} +var init_encodeAbiParameters = __esm(() => { + init_abi(); + init_address(); + init_base(); + init_encoding(); + init_isAddress(); + init_pad(); + init_size(); + init_slice(); + init_toHex(); + init_regex(); +}); + +// node_modules/viem/_esm/utils/stringify.js +var stringify = (value, replacer, space) => JSON.stringify(value, (key, value_) => { + const value2 = typeof value_ === "bigint" ? value_.toString() : value_; + return typeof replacer === "function" ? replacer(key, value2) : value2; +}, space); + +// node_modules/viem/_esm/errors/typedData.js +var InvalidDomainError, InvalidPrimaryTypeError, InvalidStructTypeError; +var init_typedData = __esm(() => { + init_base(); + InvalidDomainError = class InvalidDomainError extends BaseError { + constructor({ domain }) { + super(`Invalid domain "${stringify(domain)}".`, { + metaMessages: ["Must be a valid EIP-712 domain."] + }); + } + }; + InvalidPrimaryTypeError = class InvalidPrimaryTypeError extends BaseError { + constructor({ primaryType, types }) { + super(`Invalid primary type \`${primaryType}\` must be one of \`${JSON.stringify(Object.keys(types))}\`.`, { + docsPath: "/api/glossary/Errors#typeddatainvalidprimarytypeerror", + metaMessages: ["Check that the primary type is a key in `types`."] + }); + } + }; + InvalidStructTypeError = class InvalidStructTypeError extends BaseError { + constructor({ type }) { + super(`Struct type "${type}" is invalid.`, { + metaMessages: ["Struct type must not be a Solidity type."], + name: "InvalidStructTypeError" + }); + } + }; +}); + +// node_modules/viem/_esm/utils/typedData.js +function validateTypedData(parameters) { + const { domain, message, primaryType, types } = parameters; + const validateData = (struct, data) => { + for (const param of struct) { + const { name, type } = param; + const value = data[name]; + const integerMatch = type.match(integerRegex); + if (integerMatch && (typeof value === "number" || typeof value === "bigint")) { + const [_type, base, size_] = integerMatch; + numberToHex(value, { + signed: base === "int", + size: Number.parseInt(size_, 10) / 8 + }); + } + if (type === "address" && typeof value === "string" && !isAddress(value)) + throw new InvalidAddressError({ address: value }); + const bytesMatch = type.match(bytesRegex); + if (bytesMatch) { + const [_type, size_] = bytesMatch; + if (size_ && size(value) !== Number.parseInt(size_, 10)) + throw new BytesSizeMismatchError({ + expectedSize: Number.parseInt(size_, 10), + givenSize: size(value) + }); + } + const struct2 = types[type]; + if (struct2) { + validateReference(type); + validateData(struct2, value); + } + } + }; + if (types.EIP712Domain && domain) { + if (typeof domain !== "object") + throw new InvalidDomainError({ domain }); + validateData(types.EIP712Domain, domain); + } + if (primaryType !== "EIP712Domain") { + if (types[primaryType]) + validateData(types[primaryType], message); + else + throw new InvalidPrimaryTypeError({ primaryType, types }); + } +} +function getTypesForEIP712Domain({ domain }) { + return [ + typeof domain?.name === "string" && { name: "name", type: "string" }, + domain?.version && { name: "version", type: "string" }, + (typeof domain?.chainId === "number" || typeof domain?.chainId === "bigint") && { + name: "chainId", + type: "uint256" + }, + domain?.verifyingContract && { + name: "verifyingContract", + type: "address" + }, + domain?.salt && { name: "salt", type: "bytes32" } + ].filter(Boolean); +} +function validateReference(type) { + if (type === "address" || type === "bool" || type === "string" || type.startsWith("bytes") || type.startsWith("uint") || type.startsWith("int")) + throw new InvalidStructTypeError({ type }); +} +var init_typedData2 = __esm(() => { + init_abi(); + init_address(); + init_typedData(); + init_isAddress(); + init_size(); + init_toHex(); + init_regex(); +}); + +// node_modules/viem/_esm/utils/signature/hashTypedData.js +function hashTypedData(parameters) { + const { domain = {}, message, primaryType } = parameters; + const types = { + EIP712Domain: getTypesForEIP712Domain({ domain }), + ...parameters.types + }; + validateTypedData({ + domain, + message, + primaryType, + types + }); + const parts = ["0x1901"]; + if (domain) + parts.push(hashDomain({ + domain, + types + })); + if (primaryType !== "EIP712Domain") + parts.push(hashStruct({ + data: message, + primaryType, + types + })); + return keccak256(concat(parts)); +} +function hashDomain({ domain, types }) { + return hashStruct({ + data: domain, + primaryType: "EIP712Domain", + types + }); +} +function hashStruct({ data, primaryType, types }) { + const encoded = encodeData({ + data, + primaryType, + types + }); + return keccak256(encoded); +} +function encodeData({ data, primaryType, types }) { + const encodedTypes = [{ type: "bytes32" }]; + const encodedValues = [hashType({ primaryType, types })]; + for (const field of types[primaryType]) { + const [type, value] = encodeField({ + types, + name: field.name, + type: field.type, + value: data[field.name] + }); + encodedTypes.push(type); + encodedValues.push(value); + } + return encodeAbiParameters(encodedTypes, encodedValues); +} +function hashType({ primaryType, types }) { + const encodedHashType = toHex(encodeType({ primaryType, types })); + return keccak256(encodedHashType); +} +function encodeType({ primaryType, types }) { + let result = ""; + const unsortedDeps = findTypeDependencies({ primaryType, types }); + unsortedDeps.delete(primaryType); + const deps = [primaryType, ...Array.from(unsortedDeps).sort()]; + for (const type of deps) { + result += `${type}(${types[type].map(({ name, type: t }) => `${t} ${name}`).join(",")})`; + } + return result; +} +function findTypeDependencies({ primaryType: primaryType_, types }, results = new Set) { + const match = primaryType_.match(/^\w*/u); + const primaryType = match?.[0]; + if (results.has(primaryType) || types[primaryType] === undefined) { + return results; + } + results.add(primaryType); + for (const field of types[primaryType]) { + findTypeDependencies({ primaryType: field.type, types }, results); + } + return results; +} +function encodeField({ types, name, type, value }) { + if (types[type] !== undefined) { + return [ + { type: "bytes32" }, + keccak256(encodeData({ data: value, primaryType: type, types })) + ]; + } + if (type === "bytes") + return [{ type: "bytes32" }, keccak256(value)]; + if (type === "string") + return [{ type: "bytes32" }, keccak256(toHex(value))]; + if (type.lastIndexOf("]") === type.length - 1) { + const parsedType = type.slice(0, type.lastIndexOf("[")); + const typeValuePairs = value.map((item) => encodeField({ + name, + type: parsedType, + types, + value: item + })); + return [ + { type: "bytes32" }, + keccak256(encodeAbiParameters(typeValuePairs.map(([t]) => t), typeValuePairs.map(([, v]) => v))) + ]; + } + return [{ type }, value]; +} +var init_hashTypedData = __esm(() => { + init_encodeAbiParameters(); + init_toHex(); + init_keccak256(); + init_typedData2(); +}); + +// node_modules/viem/_esm/accounts/utils/signTypedData.js +async function signTypedData(parameters) { + const { privateKey, ...typedData } = parameters; + return await sign({ + hash: hashTypedData(typedData), + privateKey, + to: "hex" + }); +} +var init_signTypedData = __esm(() => { + init_hashTypedData(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/privateKeyToAccount.js +function privateKeyToAccount(privateKey, options = {}) { + const { nonceManager } = options; + const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); + const address = publicKeyToAddress(publicKey); + const account = toAccount({ + address, + nonceManager, + async sign({ hash }) { + return sign({ hash, privateKey, to: "hex" }); + }, + async signAuthorization(authorization) { + return signAuthorization({ ...authorization, privateKey }); + }, + async signMessage({ message }) { + return signMessage({ message, privateKey }); + }, + async signTransaction(transaction, { serializer } = {}) { + return signTransaction({ privateKey, transaction, serializer }); + }, + async signTypedData(typedData) { + return signTypedData({ ...typedData, privateKey }); + } + }); + return { + ...account, + publicKey, + source: "privateKey" + }; +} +var init_privateKeyToAccount = __esm(() => { + init_secp256k1(); + init_toHex(); + init_toAccount(); + init_publicKeyToAddress(); + init_sign(); + init_signAuthorization(); + init_signMessage(); + init_signTransaction(); + init_signTypedData(); +}); + +// node_modules/viem/_esm/accounts/index.js +var init_accounts = __esm(() => { + init_privateKeyToAccount(); +}); + // src/lib/cortex-config.ts import { homedir } from "os"; import { join, dirname } from "path"; @@ -249,6 +5072,91 @@ function readConfig() { var _cached; var init_cortex_config = () => {}; +// src/lib/credentials.ts +function validPk(v) { + return typeof v === "string" && PK_RE.test(v) ? v : null; +} +function validEoa(v) { + return typeof v === "string" && EOA_RE.test(v) ? v : null; +} +function validSig(v) { + return typeof v === "string" && SIG_RE.test(v) ? v : null; +} +function deriveAddressFromPk(pk) { + try { + return privateKeyToAccount(pk).address; + } catch { + return null; + } +} +function resolveEmbedding() { + const envProviders = [ + ["OPENAI_API_KEY", "openai"], + ["OPENROUTER_API_KEY", "openrouter"], + ["VOYAGE_API_KEY", "voyage"], + ["COHERE_API_KEY", "cohere"] + ]; + for (const [envName, provider] of envProviders) { + const v = process.env[envName]; + if (isUsableEmbeddingKey(v)) + return { value: { key: v.trim(), provider }, source: "env" }; + } + const cfg = readConfig(); + if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { + return { + value: { key: cfg.embeddingKey.trim(), provider: cfg.embeddingProvider ?? "openai" }, + source: "config" + }; + } + return { value: null, source: "none" }; +} +function resolveCredentials() { + const cfg = readConfig(); + const skEnv = validPk(process.env.SESSION_KEY_PRIVATE_KEY); + const skCfg = validPk(cfg?.sessionKeyPrivate); + const sessionKeyPrivate = skEnv ?? skCfg; + const sessionKeySource = skEnv ? "env" : skCfg ? "config" : "none"; + const userPrivateKey = validPk(process.env.CORTEX_USER_PRIVATE_KEY); + const ownerEnv = validEoa(process.env.USER_PRIMARY_ADDRESS); + const ownerCfg = validEoa(cfg?.ownerAddress); + let ownerEOA = ownerEnv ?? ownerCfg; + let ownerSource = ownerEnv ? "env" : ownerCfg ? "config" : "none"; + if (!ownerEOA && userPrivateKey) { + const derived = deriveAddressFromPk(userPrivateKey); + if (derived) { + ownerEOA = derived; + ownerSource = "derived"; + } + } + const sigEnv = validSig(process.env.CORTEX_USER_SIGNATURE); + const sigCfg = validSig(cfg?.userSignature); + const userSignature = sigEnv ?? sigCfg; + const signatureSource = sigEnv ? "env" : sigCfg ? "config" : "none"; + const emb = resolveEmbedding(); + return { + sessionKeyPrivate, + ownerEOA, + userSignature, + userPrivateKey, + embedding: emb.value, + source: { + sessionKey: sessionKeySource, + owner: ownerSource, + signature: signatureSource, + embedding: emb.source + } + }; +} +var EOA_RE, PK_RE, SIG_RE; +var init_credentials = __esm(() => { + init_accounts(); + init_embeddings(); + init_cortex_config(); + EOA_RE = /^0x[0-9a-fA-F]{40}$/; + PK_RE = /^0x[0-9a-fA-F]{64}$/; + SIG_RE = /^0x[0-9a-fA-F]+$/; +}); + // src/compression/embeddings.ts var exports_embeddings = {}; __export(exports_embeddings, { @@ -273,16 +5181,8 @@ function isUsableEmbeddingKey(key) { return false; return true; } -function envEmbeddingKey(name) { - const v = process.env[name]; - return isUsableEmbeddingKey(v) ? v.trim() : undefined; -} function hasEmbeddingKey() { - if (envEmbeddingKey("OPENAI_API_KEY") || envEmbeddingKey("OPENROUTER_API_KEY") || envEmbeddingKey("VOYAGE_API_KEY") || envEmbeddingKey("COHERE_API_KEY")) { - return true; - } - const cfg = readConfig(); - return isUsableEmbeddingKey(cfg?.embeddingKey); + return resolveCredentials().embedding !== null; } function toFloat32(arr, provider) { if (!Array.isArray(arr)) { @@ -391,33 +5291,20 @@ async function embedText(text) { if (typeof text !== "string" || text.length === 0) { throw new Error("embedText: input text must be a non-empty string"); } - const openAiKey = envEmbeddingKey("OPENAI_API_KEY"); - if (openAiKey) - return embedViaOpenAI(text, openAiKey); - const openRouterKey = envEmbeddingKey("OPENROUTER_API_KEY"); - if (openRouterKey) - return embedViaOpenRouter(text, openRouterKey); - const voyageKey = envEmbeddingKey("VOYAGE_API_KEY"); - if (voyageKey) - return embedViaVoyage(text, voyageKey); - const cohereKey = envEmbeddingKey("COHERE_API_KEY"); - if (cohereKey) - return embedViaCohere(text, cohereKey); - const cfg = readConfig(); - if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { - switch (cfg.embeddingProvider ?? "openai") { - case "openrouter": - return embedViaOpenRouter(text, cfg.embeddingKey); - case "voyage": - return embedViaVoyage(text, cfg.embeddingKey); - case "cohere": - return embedViaCohere(text, cfg.embeddingKey); - case "openai": - default: - return embedViaOpenAI(text, cfg.embeddingKey); - } + const emb = resolveCredentials().embedding; + if (!emb) + throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); + switch (emb.provider) { + case "openrouter": + return embedViaOpenRouter(text, emb.key); + case "voyage": + return embedViaVoyage(text, emb.key); + case "cohere": + return embedViaCohere(text, emb.key); + case "openai": + default: + return embedViaOpenAI(text, emb.key); } - throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); } async function embedAndQuantize(text) { const rawEmbedding = await embedText(text); @@ -439,7 +5326,7 @@ var EMBED_DIM2 = 1536, EMBED_FETCH_TIMEOUT_MS = 30000, OPENAI_EMBED_URL = "https var init_embeddings = __esm(() => { init_rabitq(); init_events(); - init_cortex_config(); + init_credentials(); OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; diff --git a/cortex-plugin/dist/cortex-hook-recall.js b/cortex-plugin/dist/cortex-hook-recall.js index 9b79703..58ed946 100755 --- a/cortex-plugin/dist/cortex-hook-recall.js +++ b/cortex-plugin/dist/cortex-hook-recall.js @@ -18439,6 +18439,177 @@ var init_events = __esm(() => { wrappedListeners = new Set; }); +// node_modules/viem/_esm/accounts/toAccount.js +function toAccount(source) { + if (typeof source === "string") { + if (!isAddress(source, { strict: false })) + throw new InvalidAddressError({ address: source }); + return { + address: source, + type: "json-rpc" + }; + } + if (!isAddress(source.address, { strict: false })) + throw new InvalidAddressError({ address: source.address }); + return { + address: source.address, + nonceManager: source.nonceManager, + sign: source.sign, + signAuthorization: source.signAuthorization, + signMessage: source.signMessage, + signTransaction: source.signTransaction, + signTypedData: source.signTypedData, + source: "custom", + type: "local" + }; +} +var init_toAccount = __esm(() => { + init_address(); + init_isAddress(); +}); + +// node_modules/viem/_esm/accounts/utils/sign.js +async function sign({ hash: hash3, privateKey, to = "object" }) { + const { r, s, recovery } = secp256k1.sign(hash3.slice(2), privateKey.slice(2), { + lowS: true, + extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes(extraEntropy) : extraEntropy + }); + const signature = { + r: numberToHex(r, { size: 32 }), + s: numberToHex(s, { size: 32 }), + v: recovery ? 28n : 27n, + yParity: recovery + }; + return (() => { + if (to === "bytes" || to === "hex") + return serializeSignature({ ...signature, to }); + return signature; + })(); +} +var extraEntropy = false; +var init_sign = __esm(() => { + init_secp256k1(); + init_toBytes(); + init_toHex(); + init_serializeSignature(); +}); + +// node_modules/viem/_esm/accounts/utils/signAuthorization.js +async function signAuthorization2(parameters) { + const { chainId, nonce, privateKey, to = "object" } = parameters; + const address = parameters.contractAddress ?? parameters.address; + const signature = await sign({ + hash: hashAuthorization({ address, chainId, nonce }), + privateKey, + to + }); + if (to === "object") + return { + address, + chainId, + nonce, + ...signature + }; + return signature; +} +var init_signAuthorization2 = __esm(() => { + init_hashAuthorization(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signMessage.js +async function signMessage2({ message, privateKey }) { + return await sign({ hash: hashMessage(message), privateKey, to: "hex" }); +} +var init_signMessage2 = __esm(() => { + init_hashMessage(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signTransaction.js +async function signTransaction2(parameters) { + const { privateKey, transaction, serializer = serializeTransaction } = parameters; + const signableTransaction = (() => { + if (transaction.type === "eip4844") + return { + ...transaction, + sidecars: false + }; + return transaction; + })(); + const signature = await sign({ + hash: keccak256(await serializer(signableTransaction)), + privateKey + }); + return await serializer(transaction, signature); +} +var init_signTransaction2 = __esm(() => { + init_keccak256(); + init_serializeTransaction(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signTypedData.js +async function signTypedData2(parameters) { + const { privateKey, ...typedData } = parameters; + return await sign({ + hash: hashTypedData(typedData), + privateKey, + to: "hex" + }); +} +var init_signTypedData2 = __esm(() => { + init_hashTypedData(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/privateKeyToAccount.js +function privateKeyToAccount(privateKey, options = {}) { + const { nonceManager } = options; + const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); + const address = publicKeyToAddress(publicKey); + const account = toAccount({ + address, + nonceManager, + async sign({ hash: hash3 }) { + return sign({ hash: hash3, privateKey, to: "hex" }); + }, + async signAuthorization(authorization) { + return signAuthorization2({ ...authorization, privateKey }); + }, + async signMessage({ message }) { + return signMessage2({ message, privateKey }); + }, + async signTransaction(transaction, { serializer } = {}) { + return signTransaction2({ privateKey, transaction, serializer }); + }, + async signTypedData(typedData) { + return signTypedData2({ ...typedData, privateKey }); + } + }); + return { + ...account, + publicKey, + source: "privateKey" + }; +} +var init_privateKeyToAccount = __esm(() => { + init_secp256k1(); + init_toHex(); + init_toAccount(); + init_publicKeyToAddress(); + init_sign(); + init_signAuthorization2(); + init_signMessage2(); + init_signTransaction2(); + init_signTypedData2(); +}); + +// node_modules/viem/_esm/accounts/index.js +var init_accounts = __esm(() => { + init_privateKeyToAccount(); +}); + // src/lib/cortex-config.ts import { homedir } from "os"; import { join, dirname } from "path"; @@ -18465,7 +18636,95 @@ function readConfig() { var _cached; var init_cortex_config = () => {}; +// src/lib/credentials.ts +function validPk(v) { + return typeof v === "string" && PK_RE.test(v) ? v : null; +} +function validEoa(v) { + return typeof v === "string" && EOA_RE.test(v) ? v : null; +} +function validSig(v) { + return typeof v === "string" && SIG_RE.test(v) ? v : null; +} +function deriveAddressFromPk(pk) { + try { + return privateKeyToAccount(pk).address; + } catch { + return null; + } +} +function resolveEmbedding() { + const envProviders = [ + ["OPENAI_API_KEY", "openai"], + ["OPENROUTER_API_KEY", "openrouter"], + ["VOYAGE_API_KEY", "voyage"], + ["COHERE_API_KEY", "cohere"] + ]; + for (const [envName, provider] of envProviders) { + const v = process.env[envName]; + if (isUsableEmbeddingKey(v)) + return { value: { key: v.trim(), provider }, source: "env" }; + } + const cfg = readConfig(); + if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { + return { + value: { key: cfg.embeddingKey.trim(), provider: cfg.embeddingProvider ?? "openai" }, + source: "config" + }; + } + return { value: null, source: "none" }; +} +function resolveCredentials() { + const cfg = readConfig(); + const skEnv = validPk(process.env.SESSION_KEY_PRIVATE_KEY); + const skCfg = validPk(cfg?.sessionKeyPrivate); + const sessionKeyPrivate = skEnv ?? skCfg; + const sessionKeySource = skEnv ? "env" : skCfg ? "config" : "none"; + const userPrivateKey = validPk(process.env.CORTEX_USER_PRIVATE_KEY); + const ownerEnv = validEoa(process.env.USER_PRIMARY_ADDRESS); + const ownerCfg = validEoa(cfg?.ownerAddress); + let ownerEOA = ownerEnv ?? ownerCfg; + let ownerSource = ownerEnv ? "env" : ownerCfg ? "config" : "none"; + if (!ownerEOA && userPrivateKey) { + const derived = deriveAddressFromPk(userPrivateKey); + if (derived) { + ownerEOA = derived; + ownerSource = "derived"; + } + } + const sigEnv = validSig(process.env.CORTEX_USER_SIGNATURE); + const sigCfg = validSig(cfg?.userSignature); + const userSignature = sigEnv ?? sigCfg; + const signatureSource = sigEnv ? "env" : sigCfg ? "config" : "none"; + const emb = resolveEmbedding(); + return { + sessionKeyPrivate, + ownerEOA, + userSignature, + userPrivateKey, + embedding: emb.value, + source: { + sessionKey: sessionKeySource, + owner: ownerSource, + signature: signatureSource, + embedding: emb.source + } + }; +} +var EOA_RE, PK_RE, SIG_RE; +var init_credentials = __esm(() => { + init_accounts(); + init_embeddings(); + init_cortex_config(); + EOA_RE = /^0x[0-9a-fA-F]{40}$/; + PK_RE = /^0x[0-9a-fA-F]{64}$/; + SIG_RE = /^0x[0-9a-fA-F]+$/; +}); + // src/compression/embeddings.ts +function isMissingEmbeddingKey(err) { + return err instanceof MissingEmbeddingKeyError || typeof err === "object" && err !== null && "isMissingEmbeddingKey" in err; +} function isUsableEmbeddingKey(key) { if (typeof key !== "string") return false; @@ -18476,10 +18735,6 @@ function isUsableEmbeddingKey(key) { return false; return true; } -function envEmbeddingKey(name) { - const v = process.env[name]; - return isUsableEmbeddingKey(v) ? v.trim() : undefined; -} function toFloat32(arr, provider) { if (!Array.isArray(arr)) { throw new Error(`embedText: unexpected ${provider} response shape`); @@ -18587,39 +18842,26 @@ async function embedText(text) { if (typeof text !== "string" || text.length === 0) { throw new Error("embedText: input text must be a non-empty string"); } - const openAiKey = envEmbeddingKey("OPENAI_API_KEY"); - if (openAiKey) - return embedViaOpenAI(text, openAiKey); - const openRouterKey = envEmbeddingKey("OPENROUTER_API_KEY"); - if (openRouterKey) - return embedViaOpenRouter(text, openRouterKey); - const voyageKey = envEmbeddingKey("VOYAGE_API_KEY"); - if (voyageKey) - return embedViaVoyage(text, voyageKey); - const cohereKey = envEmbeddingKey("COHERE_API_KEY"); - if (cohereKey) - return embedViaCohere(text, cohereKey); - const cfg = readConfig(); - if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { - switch (cfg.embeddingProvider ?? "openai") { - case "openrouter": - return embedViaOpenRouter(text, cfg.embeddingKey); - case "voyage": - return embedViaVoyage(text, cfg.embeddingKey); - case "cohere": - return embedViaCohere(text, cfg.embeddingKey); - case "openai": - default: - return embedViaOpenAI(text, cfg.embeddingKey); - } + const emb = resolveCredentials().embedding; + if (!emb) + throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); + switch (emb.provider) { + case "openrouter": + return embedViaOpenRouter(text, emb.key); + case "voyage": + return embedViaVoyage(text, emb.key); + case "cohere": + return embedViaCohere(text, emb.key); + case "openai": + default: + return embedViaOpenAI(text, emb.key); } - throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); } var EMBED_DIM2 = 1536, EMBED_FETCH_TIMEOUT_MS = 30000, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", OPENAI_MODEL, OPENROUTER_EMBED_URL = "https://openrouter.ai/api/v1/embeddings", OPENROUTER_MODEL, VOYAGE_EMBED_URL = "https://api.voyageai.com/v1/embeddings", VOYAGE_MODEL, COHERE_EMBED_URL = "https://api.cohere.com/v2/embed", COHERE_MODEL = "embed-v4.0", MissingEmbeddingKeyError, EMBEDDING_SETUP_MESSAGE; var init_embeddings = __esm(() => { init_rabitq(); init_events(); - init_cortex_config(); + init_credentials(); OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; @@ -21682,177 +21924,6 @@ var init_crypto = __esm(() => { init_constants(); }); -// node_modules/viem/_esm/accounts/toAccount.js -function toAccount(source) { - if (typeof source === "string") { - if (!isAddress(source, { strict: false })) - throw new InvalidAddressError({ address: source }); - return { - address: source, - type: "json-rpc" - }; - } - if (!isAddress(source.address, { strict: false })) - throw new InvalidAddressError({ address: source.address }); - return { - address: source.address, - nonceManager: source.nonceManager, - sign: source.sign, - signAuthorization: source.signAuthorization, - signMessage: source.signMessage, - signTransaction: source.signTransaction, - signTypedData: source.signTypedData, - source: "custom", - type: "local" - }; -} -var init_toAccount = __esm(() => { - init_address(); - init_isAddress(); -}); - -// node_modules/viem/_esm/accounts/utils/sign.js -async function sign({ hash: hash3, privateKey, to = "object" }) { - const { r, s, recovery } = secp256k1.sign(hash3.slice(2), privateKey.slice(2), { - lowS: true, - extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes(extraEntropy) : extraEntropy - }); - const signature = { - r: numberToHex(r, { size: 32 }), - s: numberToHex(s, { size: 32 }), - v: recovery ? 28n : 27n, - yParity: recovery - }; - return (() => { - if (to === "bytes" || to === "hex") - return serializeSignature({ ...signature, to }); - return signature; - })(); -} -var extraEntropy = false; -var init_sign = __esm(() => { - init_secp256k1(); - init_toBytes(); - init_toHex(); - init_serializeSignature(); -}); - -// node_modules/viem/_esm/accounts/utils/signAuthorization.js -async function signAuthorization2(parameters) { - const { chainId, nonce, privateKey, to = "object" } = parameters; - const address = parameters.contractAddress ?? parameters.address; - const signature = await sign({ - hash: hashAuthorization({ address, chainId, nonce }), - privateKey, - to - }); - if (to === "object") - return { - address, - chainId, - nonce, - ...signature - }; - return signature; -} -var init_signAuthorization2 = __esm(() => { - init_hashAuthorization(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signMessage.js -async function signMessage2({ message, privateKey }) { - return await sign({ hash: hashMessage(message), privateKey, to: "hex" }); -} -var init_signMessage2 = __esm(() => { - init_hashMessage(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signTransaction.js -async function signTransaction2(parameters) { - const { privateKey, transaction, serializer = serializeTransaction } = parameters; - const signableTransaction = (() => { - if (transaction.type === "eip4844") - return { - ...transaction, - sidecars: false - }; - return transaction; - })(); - const signature = await sign({ - hash: keccak256(await serializer(signableTransaction)), - privateKey - }); - return await serializer(transaction, signature); -} -var init_signTransaction2 = __esm(() => { - init_keccak256(); - init_serializeTransaction(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signTypedData.js -async function signTypedData2(parameters) { - const { privateKey, ...typedData } = parameters; - return await sign({ - hash: hashTypedData(typedData), - privateKey, - to: "hex" - }); -} -var init_signTypedData2 = __esm(() => { - init_hashTypedData(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/privateKeyToAccount.js -function privateKeyToAccount(privateKey, options = {}) { - const { nonceManager } = options; - const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); - const address = publicKeyToAddress(publicKey); - const account = toAccount({ - address, - nonceManager, - async sign({ hash: hash3 }) { - return sign({ hash: hash3, privateKey, to: "hex" }); - }, - async signAuthorization(authorization) { - return signAuthorization2({ ...authorization, privateKey }); - }, - async signMessage({ message }) { - return signMessage2({ message, privateKey }); - }, - async signTransaction(transaction, { serializer } = {}) { - return signTransaction2({ privateKey, transaction, serializer }); - }, - async signTypedData(typedData) { - return signTypedData2({ ...typedData, privateKey }); - } - }); - return { - ...account, - publicKey, - source: "privateKey" - }; -} -var init_privateKeyToAccount = __esm(() => { - init_secp256k1(); - init_toHex(); - init_toAccount(); - init_publicKeyToAddress(); - init_sign(); - init_signAuthorization2(); - init_signMessage2(); - init_signTransaction2(); - init_signTypedData2(); -}); - -// node_modules/viem/_esm/accounts/index.js -var init_accounts = __esm(() => { - init_privateKeyToAccount(); -}); - // node_modules/@arkiv-network/sdk/src/accounts/index.ts var init_accounts2 = __esm(() => { init_accounts(); @@ -21868,23 +21939,17 @@ __export(exports_owner_identity, { _peekCached: () => _peekCached }); async function resolveFromEnv() { - const addr = process.env.USER_PRIMARY_ADDRESS; - const ownerAddress = addr && ADDR_RE.test(addr) ? addr : null; + const creds = resolveCredentials(); + const ownerAddress = creds.ownerEOA ?? null; let signature = null; - const sigEnv = process.env.CORTEX_USER_SIGNATURE; - if (sigEnv && SIG_RE.test(sigEnv)) { - signature = sigEnv; - } else { - const pkEnv = process.env.CORTEX_USER_PRIVATE_KEY; - if (pkEnv && PK_RE.test(pkEnv)) { - const account = privateKeyToAccount(pkEnv); - const message = keyDerivationMessage(account.address); - signature = await account.signMessage({ message }); - } else { - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE.test(cfgSig)) - signature = cfgSig; - } + if (creds.source.signature === "env") { + signature = creds.userSignature; + } else if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); + const message = keyDerivationMessage(account.address); + signature = await account.signMessage({ message }); + } else if (creds.source.signature === "config") { + signature = creds.userSignature; } const payloadKey = signature ? await derivePayloadKey(signature) : null; const source = ownerAddress || signature ? "env" : "none"; @@ -21900,7 +21965,7 @@ async function adopt(opts) { if (!ADDR_RE.test(opts.address)) { throw new Error("adopt: address must be 0x-prefixed 40-hex EOA"); } - if (!SIG_RE.test(opts.signature)) { + if (!SIG_RE2.test(opts.signature)) { throw new Error("adopt: signature must be 0x-prefixed hex"); } const message = keyDerivationMessage(opts.address); @@ -21930,31 +21995,28 @@ function _setOwnerIdentityForTest(view) { function _peekCached() { return _cached2; } -var ADDR_RE, PK_RE, SIG_RE, _cached2 = null; +var ADDR_RE, SIG_RE2, _cached2 = null; var init_owner_identity = __esm(() => { init__esm(); init_accounts(); init_crypto(); - init_cortex_config(); + init_credentials(); ADDR_RE = /^0x[0-9a-fA-F]{40}$/; - PK_RE = /^0x[0-9a-fA-F]{64}$/; - SIG_RE = /^0x[0-9a-fA-F]+$/; + SIG_RE2 = /^0x[0-9a-fA-F]+$/; }); // src/lib/payload-key.ts async function resolveSignature() { - const sig = process.env.CORTEX_USER_SIGNATURE; - if (sig && SIG_RE2.test(sig)) - return sig; - const pk = process.env.CORTEX_USER_PRIVATE_KEY; - if (pk && PK_RE2.test(pk)) { - const account = privateKeyToAccount(pk); + const creds = resolveCredentials(); + if (creds.source.signature === "env") + return creds.userSignature; + if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); const message = keyDerivationMessage(account.address); return await account.signMessage({ message }); } - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE2.test(cfgSig)) - return cfgSig; + if (creds.source.signature === "config") + return creds.userSignature; return null; } async function getPayloadKey() { @@ -21968,13 +22030,11 @@ async function getPayloadKey() { _cached3 = sig ? await derivePayloadKey(sig) : null; return _cached3; } -var _cached3, SIG_RE2, PK_RE2; +var _cached3; var init_payload_key = __esm(() => { init_accounts2(); init_crypto(); - init_cortex_config(); - SIG_RE2 = /^0x[0-9a-fA-F]+$/; - PK_RE2 = /^0x[0-9a-fA-F]{64}$/; + init_credentials(); }); // src/darwinian/utility.ts @@ -23605,7 +23665,7 @@ function getPublicClient() { function getWalletClient() { if (_walletClient) return _walletClient; - const pk = process.env.SESSION_KEY_PRIVATE_KEY ?? readConfig()?.sessionKeyPrivate; + const pk = resolveCredentials().sessionKeyPrivate; if (!pk) { throw new Error("No session key. Run `cortex auth` (connect your wallet) \u2014 or set " + "SESSION_KEY_PRIVATE_KEY and fund the EOA via " + BRAGA.faucet); } @@ -23650,7 +23710,7 @@ var init_arkiv_client = __esm(() => { init_query2(); init_constants(); init_events(); - init_cortex_config(); + init_credentials(); }); // node_modules/better-sqlite3/lib/util.js @@ -25021,19 +25081,28 @@ async function recall(opts) { } const embed = opts._deps?.embedQuery ?? embedText; const fetchCandidates = opts._deps?.fetchCandidates ?? defaultFetchCandidates; - const queryEmbedding = await embed(opts.query); + let queryEmbedding = null; try { - const t0 = performance.now(); - const packed = packCode(rabitqEncode(queryEmbedding)); - publish({ - type: "rabitq.encoded", - ts: Date.now(), - dim: queryEmbedding.length, - bytes: packed.byteLength, - ratio: queryEmbedding.length * 4 / packed.byteLength, - ms: performance.now() - t0 - }); - } catch {} + queryEmbedding = await embed(opts.query); + } catch (err) { + if (!isMissingEmbeddingKey(err)) + throw err; + queryEmbedding = null; + } + if (queryEmbedding) { + try { + const t0 = performance.now(); + const packed = packCode(rabitqEncode(queryEmbedding)); + publish({ + type: "rabitq.encoded", + ts: Date.now(), + dim: queryEmbedding.length, + bytes: packed.byteLength, + ratio: queryEmbedding.length * 4 / packed.byteLength, + ms: performance.now() - t0 + }); + } catch {} + } const candidates = await fetchCandidates(opts.entityType, opts.project); const payloadKey = await getPayloadKey(); const hits = []; @@ -25064,25 +25133,31 @@ async function recall(opts) { if (raw) { try { const doc = decodeDocumentPayload(raw); - let stage1 = 0; - try { - stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc.code)); - } catch {} - let bestOffset = 0; - for (const s of doc.sections) { + if (!queryEmbedding) { + score = textOverlapScore(opts.query, doc.text); + docText = doc.text; + preview = doc.text.slice(0, PREVIEW_LIMIT); + } else { + let stage1 = 0; try { - const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); - if (ss > stage1) { - stage1 = ss; - bestOffset = s.offset; - } + stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc.code)); } catch {} + let bestOffset = 0; + for (const s of doc.sections) { + try { + const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); + if (ss > stage1) { + stage1 = ss; + bestOffset = s.offset; + } + } catch {} + } + score = cosineF32(queryEmbedding, doc.rerankEmbedding); + if (!Number.isFinite(score) || score === 0) + score = stage1; + docText = doc.text; + preview = doc.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } - score = cosineF32(queryEmbedding, doc.rerankEmbedding); - if (!Number.isFinite(score) || score === 0) - score = stage1; - docText = doc.text; - preview = doc.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } catch { score = 0; } @@ -25103,7 +25178,7 @@ async function recall(opts) { } } } else { - if (raw && raw.length === RABITQ_PACK_SIZE) { + if (queryEmbedding && raw && raw.length === RABITQ_PACK_SIZE) { try { const code = unpackCode(raw); score = rabitqInnerProduct(queryEmbedding, code); diff --git a/cortex-plugin/dist/cortex-mcp.js b/cortex-plugin/dist/cortex-mcp.js index 0b87dc1..785832e 100644 --- a/cortex-plugin/dist/cortex-mcp.js +++ b/cortex-plugin/dist/cortex-mcp.js @@ -24730,156 +24730,847 @@ var init__esm = __esm(() => { init_verifyMessage(); }); -// src/lib/cortex-config.ts -import { homedir } from "os"; -import { join, dirname } from "path"; -import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, chmodSync } from "fs"; -function configPath() { - return process.env.CORTEX_CONFIG_PATH ?? join(homedir(), ".cortex", "config.json"); +// src/compression/fht.ts +function log2PowerOfTwo(n) { + if (n <= 0) + return -1; + let k = 0; + let v = n; + while ((v & 1) === 0) { + v >>= 1; + k++; + } + return v === 1 ? k : -1; } -function readConfig() { - if (_cached !== undefined) - return _cached; - const path = configPath(); - try { - if (!existsSync(path)) { - _cached = null; - return null; +function fastHadamardTransform(x) { + const D = x.length; + const logD = log2PowerOfTwo(D); + if (logD < 0) { + throw new Error(`fastHadamardTransform: length must be a power of two, got ${D}`); + } + let h = 1; + while (h < D) { + const twoH = h << 1; + for (let i = 0;i < D; i += twoH) { + for (let j = i;j < i + h; j++) { + const a = x[j]; + const b = x[j + h]; + x[j] = a + b; + x[j + h] = a - b; + } } - const parsed = JSON.parse(readFileSync(path, "utf-8")); - _cached = parsed && typeof parsed === "object" ? parsed : null; - } catch { - _cached = null; + h = twoH; + } + const invSqrtD = 1 / Math.sqrt(D); + for (let i = 0;i < D; i++) { + x[i] = x[i] * invSqrtD; } - return _cached; } -var _cached; -var init_cortex_config = () => {}; - -// node_modules/detect-libc/lib/process.js -var require_process = __commonJS((exports, module) => { - var isLinux = () => process.platform === "linux"; - var report = null; - var getReport = () => { - if (!report) { - if (isLinux() && process.report) { - const orig = process.report.excludeNetwork; - process.report.excludeNetwork = true; - report = process.report.getReport(); - process.report.excludeNetwork = orig; - } else { - report = {}; - } +function makeXorshift128(seedHex) { + const FNV_OFFSET = 2166136261; + const FNV_PRIME = 16777619; + const seeds = new Uint32Array(4); + for (let k = 0;k < 4; k++) { + let h = (FNV_OFFSET ^ k * 2654435769) >>> 0; + for (let i = 0;i < seedHex.length; i++) { + h ^= seedHex.charCodeAt(i); + h = Math.imul(h, FNV_PRIME) >>> 0; } - return report; - }; - module.exports = { isLinux, getReport }; -}); - -// node_modules/detect-libc/lib/filesystem.js -var require_filesystem = __commonJS((exports, module) => { - var fs = __require("fs"); - var LDD_PATH = "/usr/bin/ldd"; - var SELF_PATH = "/proc/self/exe"; - var MAX_LENGTH = 2048; - var readFileSync2 = (path) => { - const fd = fs.openSync(path, "r"); - const buffer2 = Buffer.alloc(MAX_LENGTH); - const bytesRead = fs.readSync(fd, buffer2, 0, MAX_LENGTH, 0); - fs.close(fd, () => {}); - return buffer2.subarray(0, bytesRead); - }; - var readFile = (path) => new Promise((resolve, reject) => { - fs.open(path, "r", (err, fd) => { - if (err) { - reject(err); - } else { - const buffer2 = Buffer.alloc(MAX_LENGTH); - fs.read(fd, buffer2, 0, MAX_LENGTH, 0, (_, bytesRead) => { - resolve(buffer2.subarray(0, bytesRead)); - fs.close(fd, () => {}); - }); - } - }); - }); - module.exports = { - LDD_PATH, - SELF_PATH, - readFileSync: readFileSync2, - readFile + seeds[k] = h === 0 ? 2654435769 : h; + } + let s0 = seeds[0]; + let s1 = seeds[1]; + let s2 = seeds[2]; + let s3 = seeds[3]; + return function next() { + let t = s0 ^ s0 << 11; + t ^= t >>> 8; + s0 = s1; + s1 = s2; + s2 = s3; + s3 = s3 ^ s3 >>> 19 ^ (t ^ t >>> 8); + return s3 >>> 0; }; -}); - -// node_modules/detect-libc/lib/elf.js -var require_elf = __commonJS((exports, module) => { - var interpreterPath = (elf) => { - if (elf.length < 64) { - return null; - } - if (elf.readUInt32BE(0) !== 2135247942) { - return null; - } - if (elf.readUInt8(4) !== 2) { - return null; - } - if (elf.readUInt8(5) !== 1) { - return null; - } - const offset = elf.readUInt32LE(32); - const size5 = elf.readUInt16LE(54); - const count = elf.readUInt16LE(56); - for (let i = 0;i < count; i++) { - const headerOffset = offset + i * size5; - const type = elf.readUInt32LE(headerOffset); - if (type === 3) { - const fileOffset = elf.readUInt32LE(headerOffset + 8); - const fileSize = elf.readUInt32LE(headerOffset + 32); - return elf.subarray(fileOffset, fileOffset + fileSize).toString().replace(/\0.*$/g, ""); - } +} +function rotateWithSeed(x, seedHex) { + const D = x.length; + const rng = makeXorshift128(seedHex); + for (let i = 0;i < D; i += 32) { + const word = rng(); + const lim = Math.min(32, D - i); + for (let b = 0;b < lim; b++) { + const bit = word >>> b & 1; + if (bit === 0) + x[i + b] = -x[i + b]; } - return null; - }; - module.exports = { - interpreterPath - }; -}); + } + fastHadamardTransform(x); +} -// node_modules/detect-libc/lib/detect-libc.js -var require_detect_libc = __commonJS((exports, module) => { - var childProcess = __require("child_process"); - var { isLinux, getReport } = require_process(); - var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync2 } = require_filesystem(); - var { interpreterPath } = require_elf(); - var cachedFamilyInterpreter; - var cachedFamilyFilesystem; - var cachedVersionFilesystem; - var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true"; - var commandOut = ""; - var safeCommand = () => { - if (!commandOut) { - return new Promise((resolve) => { - childProcess.exec(command, (err, out) => { - commandOut = err ? " " : out; - resolve(commandOut); - }); - }); +// src/compression/rabitq.ts +function f32ToF16(value) { + f32[0] = value; + const x = u322[0]; + const sign = x >>> 16 & 32768; + let mant = x & 8388607; + let exp = x >>> 23 & 255; + if (exp === 255) { + return sign | 31744 | (mant !== 0 ? 512 | mant >>> 13 : 0); + } + let newExp = exp - 127 + 15; + if (newExp >= 31) { + return sign | 31744; + } + if (newExp <= 0) { + if (newExp < -10) + return sign; + mant = (mant | 8388608) >>> 1 - newExp; + if ((mant & 4096) !== 0) + mant += 8192; + return sign | mant >>> 13; + } + if ((mant & 4096) !== 0) { + mant += 8192; + if ((mant & 8388608) !== 0) { + mant = 0; + newExp++; + if (newExp >= 31) + return sign | 31744; } - return commandOut; - }; - var safeCommandSync = () => { - if (!commandOut) { - try { - commandOut = childProcess.execSync(command, { encoding: "utf8" }); - } catch (_err) { - commandOut = " "; + } + return sign | newExp << 10 | mant >>> 13; +} +function f16ToF32(value) { + const sign = (value & 32768) << 16; + const exp = value >>> 10 & 31; + const mant = value & 1023; + let outBits; + if (exp === 0) { + if (mant === 0) { + outBits = sign; + } else { + let m = mant; + let e = 1; + while ((m & 1024) === 0) { + m <<= 1; + e--; } + m &= 1023; + outBits = sign | e + 127 - 15 << 23 | m << 13; } - return commandOut; - }; - var GLIBC = "glibc"; - var RE_GLIBC_VERSION = /LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i; - var MUSL = "musl"; - var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"); + } else if (exp === 31) { + outBits = sign | 2139095040 | mant << 13; + } else { + outBits = sign | exp + 127 - 15 << 23 | mant << 13; + } + u322[0] = outBits >>> 0; + return f32[0]; +} +function padToRotationDim(vec) { + const out = new Float32Array(PADDED_DIM); + const n = Math.min(vec.length, EMBED_DIM); + for (let i = 0;i < n; i++) + out[i] = vec[i]; + return out; +} +function l2Norm(vec) { + let s = 0; + for (let i = 0;i < vec.length; i++) { + const v = vec[i]; + s += v * v; + } + return Math.sqrt(s); +} +function rotateUnit(vec) { + const padded = padToRotationDim(vec); + const norm = l2Norm(padded); + if (norm > 0) { + const inv = 1 / norm; + for (let i = 0;i < PADDED_DIM; i++) + padded[i] = padded[i] * inv; + } + rotateWithSeed(padded, ROTATION_SEED); + return { rotated: padded, norm }; +} +function packSigns(rotated) { + const out = new Uint8Array(SIGN_BYTES); + for (let i = 0;i < EMBED_DIM; i++) { + if (rotated[i] >= 0) { + const byteIdx = i >>> 3; + const bitInByte = 7 - (i & 7); + out[byteIdx] = out[byteIdx] | 1 << bitInByte; + } + } + return out; +} +function signAt(signs, i) { + const byteIdx = i >>> 3; + const bitInByte = 7 - (i & 7); + return signs[byteIdx] >>> bitInByte & 1 ? 1 : -1; +} +function rabitqEncode(vec) { + const { rotated, norm } = rotateUnit(vec); + const signs = packSigns(rotated); + const invSqrtD = 1 / Math.sqrt(EMBED_DIM); + let align = 0; + for (let i = 0;i < EMBED_DIM; i++) { + const r = rotated[i]; + align += r >= 0 ? r : -r; + } + align *= invSqrtD; + return { + signs, + normFp16: f32ToF16(norm), + alignFp16: f32ToF16(align) + }; +} +function packCode(code) { + if (code.signs.length !== SIGN_BYTES) { + throw new Error(`packCode: signs must be ${SIGN_BYTES} bytes, got ${code.signs.length}`); + } + const out = new Uint8Array(PACK_SIZE); + out.set(code.signs, 0); + out[NORM_OFFSET] = code.normFp16 & 255; + out[NORM_OFFSET + 1] = code.normFp16 >>> 8 & 255; + out[ALIGN_OFFSET] = code.alignFp16 & 255; + out[ALIGN_OFFSET + 1] = code.alignFp16 >>> 8 & 255; + out[CENTROID_OFFSET] = 0; + out[CENTROID_OFFSET + 1] = 0; + return out; +} +function unpackCode(bytes) { + if (bytes.length !== PACK_SIZE) { + throw new Error(`unpackCode: expected ${PACK_SIZE} bytes, got ${bytes.length}`); + } + const signs = new Uint8Array(SIGN_BYTES); + signs.set(bytes.subarray(0, SIGN_BYTES)); + const normFp16 = bytes[NORM_OFFSET] | bytes[NORM_OFFSET + 1] << 8; + const alignFp16 = bytes[ALIGN_OFFSET] | bytes[ALIGN_OFFSET + 1] << 8; + return { signs, normFp16, alignFp16 }; +} +function rabitqInnerProduct(query, code) { + const { rotated: qRot, norm: qNorm } = rotateUnit(query); + const align = f16ToF32(code.alignFp16); + const vecNorm = f16ToF32(code.normFp16); + if (align === 0 || qNorm === 0 || vecNorm === 0) + return 0; + const invSqrtD = 1 / Math.sqrt(EMBED_DIM); + let dot = 0; + for (let i = 0;i < EMBED_DIM; i++) { + dot += signAt(code.signs, i) * qRot[i]; + } + dot *= invSqrtD; + const unitIp = dot / align; + return unitIp * vecNorm * qNorm; +} +var EMBED_DIM = 1536, PADDED_DIM = 2048, SIGN_BYTES, ROTATION_SEED = "cortex.rabitq.rotation.v1", NORM_OFFSET, ALIGN_OFFSET, CENTROID_OFFSET, PACK_SIZE, f32, u322; +var init_rabitq = __esm(() => { + SIGN_BYTES = EMBED_DIM >> 3; + NORM_OFFSET = SIGN_BYTES; + ALIGN_OFFSET = SIGN_BYTES + 2; + CENTROID_OFFSET = SIGN_BYTES + 4; + PACK_SIZE = SIGN_BYTES + 2 + 2 + 2; + f32 = new Float32Array(1); + u322 = new Uint32Array(f32.buffer); +}); + +// src/lib/events.ts +function publish(event) { + seq += 1; + const envelope = { + id: String(seq), + type: event.type, + event + }; + const ring = buffers.get(event.type) ?? []; + ring.push(envelope); + if (ring.length > RING_CAP_PER_TYPE) + ring.shift(); + buffers.set(event.type, ring); + dispatcher.dispatchEvent(new CustomEvent("evt", { detail: envelope })); + return envelope; +} +var RING_CAP_PER_TYPE = 200, buffers, dispatcher, wrappedListeners, seq = 0; +var init_events = __esm(() => { + buffers = new Map; + dispatcher = new EventTarget; + wrappedListeners = new Set; +}); + +// node_modules/viem/_esm/accounts/toAccount.js +function toAccount(source) { + if (typeof source === "string") { + if (!isAddress(source, { strict: false })) + throw new InvalidAddressError({ address: source }); + return { + address: source, + type: "json-rpc" + }; + } + if (!isAddress(source.address, { strict: false })) + throw new InvalidAddressError({ address: source.address }); + return { + address: source.address, + nonceManager: source.nonceManager, + sign: source.sign, + signAuthorization: source.signAuthorization, + signMessage: source.signMessage, + signTransaction: source.signTransaction, + signTypedData: source.signTypedData, + source: "custom", + type: "local" + }; +} +var init_toAccount = __esm(() => { + init_address(); + init_isAddress(); +}); + +// node_modules/viem/_esm/accounts/utils/sign.js +async function sign({ hash: hash4, privateKey, to = "object" }) { + const { r, s, recovery } = secp256k1.sign(hash4.slice(2), privateKey.slice(2), { + lowS: true, + extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes(extraEntropy) : extraEntropy + }); + const signature = { + r: numberToHex(r, { size: 32 }), + s: numberToHex(s, { size: 32 }), + v: recovery ? 28n : 27n, + yParity: recovery + }; + return (() => { + if (to === "bytes" || to === "hex") + return serializeSignature({ ...signature, to }); + return signature; + })(); +} +var extraEntropy = false; +var init_sign = __esm(() => { + init_secp256k1(); + init_toBytes(); + init_toHex(); + init_serializeSignature(); +}); + +// node_modules/viem/_esm/accounts/utils/signAuthorization.js +async function signAuthorization2(parameters) { + const { chainId, nonce, privateKey, to = "object" } = parameters; + const address = parameters.contractAddress ?? parameters.address; + const signature = await sign({ + hash: hashAuthorization({ address, chainId, nonce }), + privateKey, + to + }); + if (to === "object") + return { + address, + chainId, + nonce, + ...signature + }; + return signature; +} +var init_signAuthorization2 = __esm(() => { + init_hashAuthorization(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signMessage.js +async function signMessage2({ message, privateKey }) { + return await sign({ hash: hashMessage(message), privateKey, to: "hex" }); +} +var init_signMessage2 = __esm(() => { + init_hashMessage(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signTransaction.js +async function signTransaction2(parameters) { + const { privateKey, transaction, serializer = serializeTransaction } = parameters; + const signableTransaction = (() => { + if (transaction.type === "eip4844") + return { + ...transaction, + sidecars: false + }; + return transaction; + })(); + const signature = await sign({ + hash: keccak256(await serializer(signableTransaction)), + privateKey + }); + return await serializer(transaction, signature); +} +var init_signTransaction2 = __esm(() => { + init_keccak256(); + init_serializeTransaction(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/utils/signTypedData.js +async function signTypedData2(parameters) { + const { privateKey, ...typedData } = parameters; + return await sign({ + hash: hashTypedData(typedData), + privateKey, + to: "hex" + }); +} +var init_signTypedData2 = __esm(() => { + init_hashTypedData(); + init_sign(); +}); + +// node_modules/viem/_esm/accounts/privateKeyToAccount.js +function privateKeyToAccount(privateKey, options = {}) { + const { nonceManager } = options; + const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); + const address = publicKeyToAddress(publicKey); + const account = toAccount({ + address, + nonceManager, + async sign({ hash: hash4 }) { + return sign({ hash: hash4, privateKey, to: "hex" }); + }, + async signAuthorization(authorization) { + return signAuthorization2({ ...authorization, privateKey }); + }, + async signMessage({ message }) { + return signMessage2({ message, privateKey }); + }, + async signTransaction(transaction, { serializer } = {}) { + return signTransaction2({ privateKey, transaction, serializer }); + }, + async signTypedData(typedData) { + return signTypedData2({ ...typedData, privateKey }); + } + }); + return { + ...account, + publicKey, + source: "privateKey" + }; +} +var init_privateKeyToAccount = __esm(() => { + init_secp256k1(); + init_toHex(); + init_toAccount(); + init_publicKeyToAddress(); + init_sign(); + init_signAuthorization2(); + init_signMessage2(); + init_signTransaction2(); + init_signTypedData2(); +}); + +// node_modules/viem/_esm/accounts/index.js +var init_accounts = __esm(() => { + init_privateKeyToAccount(); +}); + +// src/lib/cortex-config.ts +import { homedir } from "os"; +import { join, dirname } from "path"; +import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, chmodSync } from "fs"; +function configPath() { + return process.env.CORTEX_CONFIG_PATH ?? join(homedir(), ".cortex", "config.json"); +} +function readConfig() { + if (_cached !== undefined) + return _cached; + const path = configPath(); + try { + if (!existsSync(path)) { + _cached = null; + return null; + } + const parsed = JSON.parse(readFileSync(path, "utf-8")); + _cached = parsed && typeof parsed === "object" ? parsed : null; + } catch { + _cached = null; + } + return _cached; +} +var _cached; +var init_cortex_config = () => {}; + +// src/lib/credentials.ts +function validPk(v) { + return typeof v === "string" && PK_RE.test(v) ? v : null; +} +function validEoa(v) { + return typeof v === "string" && EOA_RE.test(v) ? v : null; +} +function validSig(v) { + return typeof v === "string" && SIG_RE.test(v) ? v : null; +} +function deriveAddressFromPk(pk) { + try { + return privateKeyToAccount(pk).address; + } catch { + return null; + } +} +function resolveEmbedding() { + const envProviders = [ + ["OPENAI_API_KEY", "openai"], + ["OPENROUTER_API_KEY", "openrouter"], + ["VOYAGE_API_KEY", "voyage"], + ["COHERE_API_KEY", "cohere"] + ]; + for (const [envName, provider] of envProviders) { + const v = process.env[envName]; + if (isUsableEmbeddingKey(v)) + return { value: { key: v.trim(), provider }, source: "env" }; + } + const cfg = readConfig(); + if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { + return { + value: { key: cfg.embeddingKey.trim(), provider: cfg.embeddingProvider ?? "openai" }, + source: "config" + }; + } + return { value: null, source: "none" }; +} +function resolveCredentials() { + const cfg = readConfig(); + const skEnv = validPk(process.env.SESSION_KEY_PRIVATE_KEY); + const skCfg = validPk(cfg?.sessionKeyPrivate); + const sessionKeyPrivate = skEnv ?? skCfg; + const sessionKeySource = skEnv ? "env" : skCfg ? "config" : "none"; + const userPrivateKey = validPk(process.env.CORTEX_USER_PRIVATE_KEY); + const ownerEnv = validEoa(process.env.USER_PRIMARY_ADDRESS); + const ownerCfg = validEoa(cfg?.ownerAddress); + let ownerEOA = ownerEnv ?? ownerCfg; + let ownerSource = ownerEnv ? "env" : ownerCfg ? "config" : "none"; + if (!ownerEOA && userPrivateKey) { + const derived = deriveAddressFromPk(userPrivateKey); + if (derived) { + ownerEOA = derived; + ownerSource = "derived"; + } + } + const sigEnv = validSig(process.env.CORTEX_USER_SIGNATURE); + const sigCfg = validSig(cfg?.userSignature); + const userSignature = sigEnv ?? sigCfg; + const signatureSource = sigEnv ? "env" : sigCfg ? "config" : "none"; + const emb = resolveEmbedding(); + return { + sessionKeyPrivate, + ownerEOA, + userSignature, + userPrivateKey, + embedding: emb.value, + source: { + sessionKey: sessionKeySource, + owner: ownerSource, + signature: signatureSource, + embedding: emb.source + } + }; +} +var EOA_RE, PK_RE, SIG_RE; +var init_credentials = __esm(() => { + init_accounts(); + init_embeddings(); + init_cortex_config(); + EOA_RE = /^0x[0-9a-fA-F]{40}$/; + PK_RE = /^0x[0-9a-fA-F]{64}$/; + SIG_RE = /^0x[0-9a-fA-F]+$/; +}); + +// src/compression/embeddings.ts +function isMissingEmbeddingKey(err) { + return err instanceof MissingEmbeddingKeyError || typeof err === "object" && err !== null && "isMissingEmbeddingKey" in err; +} +function isUsableEmbeddingKey(key) { + if (typeof key !== "string") + return false; + const v = key.trim(); + if (v.length < 16) + return false; + if (/\.{2,}|\u2026|placeholder|your[-_]?key/i.test(v)) + return false; + return true; +} +function toFloat32(arr, provider) { + if (!Array.isArray(arr)) { + throw new Error(`embedText: unexpected ${provider} response shape`); + } + if (arr.length !== EMBED_DIM2) { + throw new Error(`embedText: expected ${EMBED_DIM2}-d from ${provider}, got ${arr.length}. ` + `RaBitQ requires exactly ${EMBED_DIM2}-d \u2014 set OPENROUTER_EMBED_MODEL to a 1536-d model.`); + } + const out = new Float32Array(EMBED_DIM2); + for (let i = 0;i < EMBED_DIM2; i++) + out[i] = arr[i]; + return out; +} +async function embedViaOpenAI(text, apiKey) { + const res = await fetch(OPENAI_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: OPENAI_MODEL, + input: [text], + dimensions: EMBED_DIM2, + encoding_format: "float" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: OpenAI request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json2 = await res.json(); + const first = json2.data?.[0]?.embedding; + return toFloat32(first, `OpenAI(${OPENAI_MODEL})`); +} +async function embedViaOpenRouter(text, apiKey) { + const res = await fetch(OPENROUTER_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: OPENROUTER_MODEL, + input: [text], + encoding_format: "float" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: OpenRouter request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json2 = await res.json(); + const first = json2.data?.[0]?.embedding; + return toFloat32(first, `OpenRouter(${OPENROUTER_MODEL})`); +} +async function embedViaVoyage(text, apiKey) { + const res = await fetch(VOYAGE_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: VOYAGE_MODEL, + input: [text], + input_type: "document" + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: Voyage request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json2 = await res.json(); + const first = json2.data?.[0]?.embedding; + return toFloat32(first, `Voyage(${VOYAGE_MODEL})`); +} +async function embedViaCohere(text, apiKey) { + const res = await fetch(COHERE_EMBED_URL, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}` + }, + signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), + body: JSON.stringify({ + model: COHERE_MODEL, + texts: [text], + input_type: "search_document", + embedding_types: ["float"], + output_dimension: EMBED_DIM2 + }) + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`embedText: Cohere request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + } + const json2 = await res.json(); + const first = json2.embeddings?.float?.[0]; + return toFloat32(first, "Cohere"); +} +async function embedText(text) { + if (typeof text !== "string" || text.length === 0) { + throw new Error("embedText: input text must be a non-empty string"); + } + const emb = resolveCredentials().embedding; + if (!emb) + throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); + switch (emb.provider) { + case "openrouter": + return embedViaOpenRouter(text, emb.key); + case "voyage": + return embedViaVoyage(text, emb.key); + case "cohere": + return embedViaCohere(text, emb.key); + case "openai": + default: + return embedViaOpenAI(text, emb.key); + } +} +var EMBED_DIM2 = 1536, EMBED_FETCH_TIMEOUT_MS = 30000, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", OPENAI_MODEL, OPENROUTER_EMBED_URL = "https://openrouter.ai/api/v1/embeddings", OPENROUTER_MODEL, VOYAGE_EMBED_URL = "https://api.voyageai.com/v1/embeddings", VOYAGE_MODEL, COHERE_EMBED_URL = "https://api.cohere.com/v2/embed", COHERE_MODEL = "embed-v4.0", MissingEmbeddingKeyError, EMBEDDING_SETUP_MESSAGE; +var init_embeddings = __esm(() => { + init_rabitq(); + init_events(); + init_credentials(); + OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; + OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; + VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; + MissingEmbeddingKeyError = class MissingEmbeddingKeyError extends Error { + isMissingEmbeddingKey = true; + constructor(message) { + super(message); + this.name = "MissingEmbeddingKeyError"; + } + }; + EMBEDDING_SETUP_MESSAGE = [ + "Cortex needs an embedding API key to turn your notes into searchable memory.", + "", + "Add ONE of these to your environment (your shell profile, or a .env in your project):", + " \u2022 OPENAI_API_KEY=sk-\u2026 \u2190 get one at https://platform.openai.com/api-keys", + " \u2022 OPENROUTER_API_KEY=sk-or-\u2026 \u2190 or https://openrouter.ai/keys", + " \u2022 VOYAGE_API_KEY=\u2026 \u2190 Claude/Anthropic users: Anthropic has no embeddings", + " API, so use Voyage (their recommended partner):", + " https://dashboard.voyageai.com/", + " \u2022 COHERE_API_KEY=\u2026 \u2190 or https://dashboard.cohere.com/api-keys", + "", + "Then restart your session. (Your text is only sent to that provider to embed;", + "the memory itself is encrypted with your wallet and stored on Arkiv.)" + ].join(` +`); +}); + +// node_modules/detect-libc/lib/process.js +var require_process = __commonJS((exports, module) => { + var isLinux = () => process.platform === "linux"; + var report = null; + var getReport = () => { + if (!report) { + if (isLinux() && process.report) { + const orig = process.report.excludeNetwork; + process.report.excludeNetwork = true; + report = process.report.getReport(); + process.report.excludeNetwork = orig; + } else { + report = {}; + } + } + return report; + }; + module.exports = { isLinux, getReport }; +}); + +// node_modules/detect-libc/lib/filesystem.js +var require_filesystem = __commonJS((exports, module) => { + var fs = __require("fs"); + var LDD_PATH = "/usr/bin/ldd"; + var SELF_PATH = "/proc/self/exe"; + var MAX_LENGTH = 2048; + var readFileSync2 = (path) => { + const fd = fs.openSync(path, "r"); + const buffer2 = Buffer.alloc(MAX_LENGTH); + const bytesRead = fs.readSync(fd, buffer2, 0, MAX_LENGTH, 0); + fs.close(fd, () => {}); + return buffer2.subarray(0, bytesRead); + }; + var readFile = (path) => new Promise((resolve, reject) => { + fs.open(path, "r", (err, fd) => { + if (err) { + reject(err); + } else { + const buffer2 = Buffer.alloc(MAX_LENGTH); + fs.read(fd, buffer2, 0, MAX_LENGTH, 0, (_, bytesRead) => { + resolve(buffer2.subarray(0, bytesRead)); + fs.close(fd, () => {}); + }); + } + }); + }); + module.exports = { + LDD_PATH, + SELF_PATH, + readFileSync: readFileSync2, + readFile + }; +}); + +// node_modules/detect-libc/lib/elf.js +var require_elf = __commonJS((exports, module) => { + var interpreterPath = (elf) => { + if (elf.length < 64) { + return null; + } + if (elf.readUInt32BE(0) !== 2135247942) { + return null; + } + if (elf.readUInt8(4) !== 2) { + return null; + } + if (elf.readUInt8(5) !== 1) { + return null; + } + const offset = elf.readUInt32LE(32); + const size5 = elf.readUInt16LE(54); + const count = elf.readUInt16LE(56); + for (let i = 0;i < count; i++) { + const headerOffset = offset + i * size5; + const type = elf.readUInt32LE(headerOffset); + if (type === 3) { + const fileOffset = elf.readUInt32LE(headerOffset + 8); + const fileSize = elf.readUInt32LE(headerOffset + 32); + return elf.subarray(fileOffset, fileOffset + fileSize).toString().replace(/\0.*$/g, ""); + } + } + return null; + }; + module.exports = { + interpreterPath + }; +}); + +// node_modules/detect-libc/lib/detect-libc.js +var require_detect_libc = __commonJS((exports, module) => { + var childProcess = __require("child_process"); + var { isLinux, getReport } = require_process(); + var { LDD_PATH, SELF_PATH, readFile, readFileSync: readFileSync2 } = require_filesystem(); + var { interpreterPath } = require_elf(); + var cachedFamilyInterpreter; + var cachedFamilyFilesystem; + var cachedVersionFilesystem; + var command = "getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true"; + var commandOut = ""; + var safeCommand = () => { + if (!commandOut) { + return new Promise((resolve) => { + childProcess.exec(command, (err, out) => { + commandOut = err ? " " : out; + resolve(commandOut); + }); + }); + } + return commandOut; + }; + var safeCommandSync = () => { + if (!commandOut) { + try { + commandOut = childProcess.execSync(command, { encoding: "utf8" }); + } catch (_err) { + commandOut = " "; + } + } + return commandOut; + }; + var GLIBC = "glibc"; + var RE_GLIBC_VERSION = /LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i; + var MUSL = "musl"; + var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-"); var familyFromReport = () => { const report = getReport(); if (report.header && report.header.glibcVersionRuntime) { @@ -25351,266 +26042,95 @@ var init_constants = __esm(() => { GRANT: "grant", STATE_ROOT: "state_root" }; - REINFORCEMENT = { - initialWorkingSeconds: 60 * 60, - workingReinforcementSeconds: 24 * 60 * 60, - episodicReinforcementSeconds: 7 * 24 * 60 * 60, - semanticInitialSeconds: 365 * 24 * 60 * 60, - documentInitialSeconds: 365 * 24 * 60 * 60, - promoteToEpisodic: 2, - promoteToSemantic: 5, - distinctSessionsForSemantic: 3 - }; - UTILITY = { - alpha: 0.6, - beta: 0.1, - gamma: 0.5, - wMax: 4, - wMin: 0.2, - wInit: 1, - recencyTauMs: 6 * 60 * 60 * 1000, - sigRecency: 0.3, - sigCoCite: 0.2, - sigRank: 0.2, - sigOutcome: 0.3, - defaultOutcome: 0.5 - }; - MARKET = { - defaultListingPriceWei: 5000000000000000n, - seededAgentCount: 3, - contractAddress: process.env["MARKET_CONTRACT_ADDRESS"]?.toLowerCase() ?? MARKET_ZERO_ADDRESS - }; - SESSION = { - defaultValidDurationSeconds: 4 * 60 * 60, - defaultMaxWrites: 1000, - keyDerivationDomain: KEY_DERIVATION_DOMAIN - }; -}); - -// src/lib/crypto.ts -async function derivePayloadKey(signatureHex) { - const seed = toArrayBuffer(hexToBytes3(signatureHex)); - const ikm = await crypto.subtle.importKey("raw", seed, "HKDF", false, ["deriveBits"]); - const bits = await crypto.subtle.deriveBits({ - name: "HKDF", - hash: "SHA-256", - salt: new TextEncoder().encode(SESSION.keyDerivationDomain), - info: new TextEncoder().encode(DERIVATION_INFO_PAYLOAD) - }, ikm, 256); - return crypto.subtle.importKey("raw", bits, { name: "AES-GCM", length: 256 }, false, [ - "encrypt", - "decrypt" - ]); -} -async function sealPayload(key, plaintext) { - const nonceBytes = crypto.getRandomValues(new Uint8Array(NONCE_BYTES)); - const nonce = toArrayBuffer(nonceBytes); - const pt = toArrayBuffer(plaintext); - const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, pt); - const out = new Uint8Array(NONCE_BYTES + ct.byteLength); - out.set(nonceBytes, 0); - out.set(new Uint8Array(ct), NONCE_BYTES); - return out; -} -async function openPayload(key, sealed) { - if (sealed.length <= NONCE_BYTES) { - throw new Error("Sealed payload too short to contain a nonce"); - } - const nonce = toArrayBuffer(sealed.slice(0, NONCE_BYTES)); - const ct = toArrayBuffer(sealed.slice(NONCE_BYTES)); - const pt = await crypto.subtle.decrypt({ name: "AES-GCM", iv: nonce }, key, ct); - return new Uint8Array(pt); -} -function hexToBytes3(hex3) { - const clean2 = hex3.startsWith("0x") ? hex3.slice(2) : hex3; - if (clean2.length % 2 !== 0) { - throw new Error("hex string has odd length"); - } - const out = new Uint8Array(clean2.length / 2); - for (let i = 0;i < out.length; i++) { - out[i] = parseInt(clean2.slice(i * 2, i * 2 + 2), 16); - } - return out; -} -function toArrayBuffer(bytes) { - const buf = new ArrayBuffer(bytes.byteLength); - new Uint8Array(buf).set(bytes); - return buf; -} -var DERIVATION_INFO_PAYLOAD = "cortex.payload.aes256gcm", NONCE_BYTES = 12; -var init_crypto = __esm(() => { - init_constants(); -}); - -// node_modules/viem/_esm/accounts/toAccount.js -function toAccount(source) { - if (typeof source === "string") { - if (!isAddress(source, { strict: false })) - throw new InvalidAddressError({ address: source }); - return { - address: source, - type: "json-rpc" - }; - } - if (!isAddress(source.address, { strict: false })) - throw new InvalidAddressError({ address: source.address }); - return { - address: source.address, - nonceManager: source.nonceManager, - sign: source.sign, - signAuthorization: source.signAuthorization, - signMessage: source.signMessage, - signTransaction: source.signTransaction, - signTypedData: source.signTypedData, - source: "custom", - type: "local" - }; -} -var init_toAccount = __esm(() => { - init_address(); - init_isAddress(); -}); - -// node_modules/viem/_esm/accounts/utils/sign.js -async function sign({ hash: hash4, privateKey, to = "object" }) { - const { r, s, recovery } = secp256k1.sign(hash4.slice(2), privateKey.slice(2), { - lowS: true, - extraEntropy: isHex(extraEntropy, { strict: false }) ? hexToBytes(extraEntropy) : extraEntropy - }); - const signature = { - r: numberToHex(r, { size: 32 }), - s: numberToHex(s, { size: 32 }), - v: recovery ? 28n : 27n, - yParity: recovery - }; - return (() => { - if (to === "bytes" || to === "hex") - return serializeSignature({ ...signature, to }); - return signature; - })(); -} -var extraEntropy = false; -var init_sign = __esm(() => { - init_secp256k1(); - init_toBytes(); - init_toHex(); - init_serializeSignature(); -}); - -// node_modules/viem/_esm/accounts/utils/signAuthorization.js -async function signAuthorization2(parameters) { - const { chainId, nonce, privateKey, to = "object" } = parameters; - const address = parameters.contractAddress ?? parameters.address; - const signature = await sign({ - hash: hashAuthorization({ address, chainId, nonce }), - privateKey, - to - }); - if (to === "object") - return { - address, - chainId, - nonce, - ...signature - }; - return signature; -} -var init_signAuthorization2 = __esm(() => { - init_hashAuthorization(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signMessage.js -async function signMessage2({ message, privateKey }) { - return await sign({ hash: hashMessage(message), privateKey, to: "hex" }); -} -var init_signMessage2 = __esm(() => { - init_hashMessage(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signTransaction.js -async function signTransaction2(parameters) { - const { privateKey, transaction, serializer = serializeTransaction } = parameters; - const signableTransaction = (() => { - if (transaction.type === "eip4844") - return { - ...transaction, - sidecars: false - }; - return transaction; - })(); - const signature = await sign({ - hash: keccak256(await serializer(signableTransaction)), - privateKey - }); - return await serializer(transaction, signature); -} -var init_signTransaction2 = __esm(() => { - init_keccak256(); - init_serializeTransaction(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/utils/signTypedData.js -async function signTypedData2(parameters) { - const { privateKey, ...typedData } = parameters; - return await sign({ - hash: hashTypedData(typedData), - privateKey, - to: "hex" - }); -} -var init_signTypedData2 = __esm(() => { - init_hashTypedData(); - init_sign(); -}); - -// node_modules/viem/_esm/accounts/privateKeyToAccount.js -function privateKeyToAccount(privateKey, options = {}) { - const { nonceManager } = options; - const publicKey = toHex(secp256k1.getPublicKey(privateKey.slice(2), false)); - const address = publicKeyToAddress(publicKey); - const account = toAccount({ - address, - nonceManager, - async sign({ hash: hash4 }) { - return sign({ hash: hash4, privateKey, to: "hex" }); - }, - async signAuthorization(authorization) { - return signAuthorization2({ ...authorization, privateKey }); - }, - async signMessage({ message }) { - return signMessage2({ message, privateKey }); - }, - async signTransaction(transaction, { serializer } = {}) { - return signTransaction2({ privateKey, transaction, serializer }); - }, - async signTypedData(typedData) { - return signTypedData2({ ...typedData, privateKey }); - } - }); - return { - ...account, - publicKey, - source: "privateKey" + REINFORCEMENT = { + initialWorkingSeconds: 60 * 60, + workingReinforcementSeconds: 24 * 60 * 60, + episodicReinforcementSeconds: 7 * 24 * 60 * 60, + semanticInitialSeconds: 365 * 24 * 60 * 60, + documentInitialSeconds: 365 * 24 * 60 * 60, + promoteToEpisodic: 2, + promoteToSemantic: 5, + distinctSessionsForSemantic: 3 + }; + UTILITY = { + alpha: 0.6, + beta: 0.1, + gamma: 0.5, + wMax: 4, + wMin: 0.2, + wInit: 1, + recencyTauMs: 6 * 60 * 60 * 1000, + sigRecency: 0.3, + sigCoCite: 0.2, + sigRank: 0.2, + sigOutcome: 0.3, + defaultOutcome: 0.5 + }; + MARKET = { + defaultListingPriceWei: 5000000000000000n, + seededAgentCount: 3, + contractAddress: process.env["MARKET_CONTRACT_ADDRESS"]?.toLowerCase() ?? MARKET_ZERO_ADDRESS + }; + SESSION = { + defaultValidDurationSeconds: 4 * 60 * 60, + defaultMaxWrites: 1000, + keyDerivationDomain: KEY_DERIVATION_DOMAIN }; -} -var init_privateKeyToAccount = __esm(() => { - init_secp256k1(); - init_toHex(); - init_toAccount(); - init_publicKeyToAddress(); - init_sign(); - init_signAuthorization2(); - init_signMessage2(); - init_signTransaction2(); - init_signTypedData2(); }); -// node_modules/viem/_esm/accounts/index.js -var init_accounts = __esm(() => { - init_privateKeyToAccount(); +// src/lib/crypto.ts +async function derivePayloadKey(signatureHex) { + const seed = toArrayBuffer(hexToBytes3(signatureHex)); + const ikm = await crypto.subtle.importKey("raw", seed, "HKDF", false, ["deriveBits"]); + const bits = await crypto.subtle.deriveBits({ + name: "HKDF", + hash: "SHA-256", + salt: new TextEncoder().encode(SESSION.keyDerivationDomain), + info: new TextEncoder().encode(DERIVATION_INFO_PAYLOAD) + }, ikm, 256); + return crypto.subtle.importKey("raw", bits, { name: "AES-GCM", length: 256 }, false, [ + "encrypt", + "decrypt" + ]); +} +async function sealPayload(key, plaintext) { + const nonceBytes = crypto.getRandomValues(new Uint8Array(NONCE_BYTES)); + const nonce = toArrayBuffer(nonceBytes); + const pt = toArrayBuffer(plaintext); + const ct = await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, key, pt); + const out = new Uint8Array(NONCE_BYTES + ct.byteLength); + out.set(nonceBytes, 0); + out.set(new Uint8Array(ct), NONCE_BYTES); + return out; +} +async function openPayload(key, sealed) { + if (sealed.length <= NONCE_BYTES) { + throw new Error("Sealed payload too short to contain a nonce"); + } + const nonce = toArrayBuffer(sealed.slice(0, NONCE_BYTES)); + const ct = toArrayBuffer(sealed.slice(NONCE_BYTES)); + const pt = await crypto.subtle.decrypt({ name: "AES-GCM", iv: nonce }, key, ct); + return new Uint8Array(pt); +} +function hexToBytes3(hex3) { + const clean2 = hex3.startsWith("0x") ? hex3.slice(2) : hex3; + if (clean2.length % 2 !== 0) { + throw new Error("hex string has odd length"); + } + const out = new Uint8Array(clean2.length / 2); + for (let i = 0;i < out.length; i++) { + out[i] = parseInt(clean2.slice(i * 2, i * 2 + 2), 16); + } + return out; +} +function toArrayBuffer(bytes) { + const buf = new ArrayBuffer(bytes.byteLength); + new Uint8Array(buf).set(bytes); + return buf; +} +var DERIVATION_INFO_PAYLOAD = "cortex.payload.aes256gcm", NONCE_BYTES = 12; +var init_crypto = __esm(() => { + init_constants(); }); // src/agent/owner-identity.ts @@ -25623,23 +26143,17 @@ __export(exports_owner_identity, { _peekCached: () => _peekCached }); async function resolveFromEnv() { - const addr = process.env.USER_PRIMARY_ADDRESS; - const ownerAddress = addr && ADDR_RE.test(addr) ? addr : null; + const creds = resolveCredentials(); + const ownerAddress = creds.ownerEOA ?? null; let signature = null; - const sigEnv = process.env.CORTEX_USER_SIGNATURE; - if (sigEnv && SIG_RE.test(sigEnv)) { - signature = sigEnv; - } else { - const pkEnv = process.env.CORTEX_USER_PRIVATE_KEY; - if (pkEnv && PK_RE.test(pkEnv)) { - const account = privateKeyToAccount(pkEnv); - const message = keyDerivationMessage(account.address); - signature = await account.signMessage({ message }); - } else { - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE.test(cfgSig)) - signature = cfgSig; - } + if (creds.source.signature === "env") { + signature = creds.userSignature; + } else if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); + const message = keyDerivationMessage(account.address); + signature = await account.signMessage({ message }); + } else if (creds.source.signature === "config") { + signature = creds.userSignature; } const payloadKey = signature ? await derivePayloadKey(signature) : null; const source = ownerAddress || signature ? "env" : "none"; @@ -25655,7 +26169,7 @@ async function adopt(opts) { if (!ADDR_RE.test(opts.address)) { throw new Error("adopt: address must be 0x-prefixed 40-hex EOA"); } - if (!SIG_RE.test(opts.signature)) { + if (!SIG_RE2.test(opts.signature)) { throw new Error("adopt: signature must be 0x-prefixed hex"); } const message = keyDerivationMessage(opts.address); @@ -25685,15 +26199,14 @@ function _setOwnerIdentityForTest(view) { function _peekCached() { return _cached2; } -var ADDR_RE, PK_RE, SIG_RE, _cached2 = null; +var ADDR_RE, SIG_RE2, _cached2 = null; var init_owner_identity = __esm(() => { init__esm(); init_accounts(); init_crypto(); - init_cortex_config(); + init_credentials(); ADDR_RE = /^0x[0-9a-fA-F]{40}$/; - PK_RE = /^0x[0-9a-fA-F]{64}$/; - SIG_RE = /^0x[0-9a-fA-F]+$/; + SIG_RE2 = /^0x[0-9a-fA-F]+$/; }); // node_modules/brotli-wasm/pkg.web/brotli_wasm.js @@ -48626,1332 +49139,880 @@ function validateToolName(name) { } if (!TOOL_NAME_REGEX.test(name)) { const invalidChars = name.split("").filter((char) => !/[A-Za-z0-9._-]/.test(char)).filter((char, index, arr) => arr.indexOf(char) === index); - warnings.push(`Tool name contains invalid characters: ${invalidChars.map((c) => `"${c}"`).join(", ")}`, "Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)"); - return { - isValid: false, - warnings - }; - } - return { - isValid: true, - warnings - }; -} -function issueToolNameWarning(name, warnings) { - if (warnings.length > 0) { - console.warn(`Tool name validation warning for "${name}":`); - for (const warning of warnings) { - console.warn(` - ${warning}`); - } - console.warn("Tool registration will proceed, but this may cause compatibility issues."); - console.warn("Consider updating the tool name to conform to the MCP tool naming standard."); - console.warn("See SEP: Specify Format for Tool Names (https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986) for more details."); - } -} -function validateAndWarnToolName(name) { - const result = validateToolName(name); - issueToolNameWarning(name, result.warnings); - return result.isValid; -} - -// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js -class ExperimentalMcpServerTasks { - constructor(_mcpServer) { - this._mcpServer = _mcpServer; - } - registerToolTask(name, config2, handler) { - const execution = { taskSupport: "required", ...config2.execution }; - if (execution.taskSupport === "forbidden") { - throw new Error(`Cannot register task-based tool '${name}' with taskSupport 'forbidden'. Use registerTool() instead.`); - } - const mcpServerInternal = this._mcpServer; - return mcpServerInternal._createRegisteredTool(name, config2.title, config2.description, config2.inputSchema, config2.outputSchema, config2.annotations, execution, config2._meta, handler); - } -} -// node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js -class McpServer { - constructor(serverInfo, options) { - this._registeredResources = {}; - this._registeredResourceTemplates = {}; - this._registeredTools = {}; - this._registeredPrompts = {}; - this._toolHandlersInitialized = false; - this._completionHandlerInitialized = false; - this._resourceHandlersInitialized = false; - this._promptHandlersInitialized = false; - this.server = new Server(serverInfo, options); - } - get experimental() { - if (!this._experimental) { - this._experimental = { - tasks: new ExperimentalMcpServerTasks(this) - }; - } - return this._experimental; - } - async connect(transport) { - return await this.server.connect(transport); - } - async close() { - await this.server.close(); - } - setToolRequestHandlers() { - if (this._toolHandlersInitialized) { - return; - } - this.server.assertCanSetRequestHandler(getMethodValue(ListToolsRequestSchema)); - this.server.assertCanSetRequestHandler(getMethodValue(CallToolRequestSchema)); - this.server.registerCapabilities({ - tools: { - listChanged: true - } - }); - this.server.setRequestHandler(ListToolsRequestSchema, () => ({ - tools: Object.entries(this._registeredTools).filter(([, tool]) => tool.enabled).map(([name, tool]) => { - const toolDefinition = { - name, - title: tool.title, - description: tool.description, - inputSchema: (() => { - const obj = normalizeObjectSchema(tool.inputSchema); - return obj ? toJsonSchemaCompat(obj, { - strictUnions: true, - pipeStrategy: "input" - }) : EMPTY_OBJECT_JSON_SCHEMA; - })(), - annotations: tool.annotations, - execution: tool.execution, - _meta: tool._meta - }; - if (tool.outputSchema) { - const obj = normalizeObjectSchema(tool.outputSchema); - if (obj) { - toolDefinition.outputSchema = toJsonSchemaCompat(obj, { - strictUnions: true, - pipeStrategy: "output" - }); - } - } - return toolDefinition; - }) - })); - this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { - try { - const tool = this._registeredTools[request.params.name]; - if (!tool) { - throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} not found`); - } - if (!tool.enabled) { - throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} disabled`); - } - const isTaskRequest = !!request.params.task; - const taskSupport = tool.execution?.taskSupport; - const isTaskHandler = "createTask" in tool.handler; - if ((taskSupport === "required" || taskSupport === "optional") && !isTaskHandler) { - throw new McpError(ErrorCode.InternalError, `Tool ${request.params.name} has taskSupport '${taskSupport}' but was not registered with registerToolTask`); - } - if (taskSupport === "required" && !isTaskRequest) { - throw new McpError(ErrorCode.MethodNotFound, `Tool ${request.params.name} requires task augmentation (taskSupport: 'required')`); - } - if (taskSupport === "optional" && !isTaskRequest && isTaskHandler) { - return await this.handleAutomaticTaskPolling(tool, request, extra); - } - const args = await this.validateToolInput(tool, request.params.arguments, request.params.name); - const result = await this.executeToolHandler(tool, args, extra); - if (isTaskRequest) { - return result; - } - await this.validateToolOutput(tool, result, request.params.name); - return result; - } catch (error51) { - if (error51 instanceof McpError) { - if (error51.code === ErrorCode.UrlElicitationRequired) { - throw error51; - } - } - return this.createToolError(error51 instanceof Error ? error51.message : String(error51)); - } - }); - this._toolHandlersInitialized = true; - } - createToolError(errorMessage) { + warnings.push(`Tool name contains invalid characters: ${invalidChars.map((c) => `"${c}"`).join(", ")}`, "Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)"); return { - content: [ - { - type: "text", - text: errorMessage - } - ], - isError: true + isValid: false, + warnings }; } - async validateToolInput(tool, args, toolName) { - if (!tool.inputSchema) { - return; - } - const inputObj = normalizeObjectSchema(tool.inputSchema); - const schemaToParse = inputObj ?? tool.inputSchema; - const parseResult = await safeParseAsync2(schemaToParse, args); - if (!parseResult.success) { - const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; - const errorMessage = getParseErrorMessage(error51); - throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`); - } - return parseResult.data; - } - async validateToolOutput(tool, result, toolName) { - if (!tool.outputSchema) { - return; - } - if (!("content" in result)) { - return; - } - if (result.isError) { - return; - } - if (!result.structuredContent) { - throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`); - } - const outputObj = normalizeObjectSchema(tool.outputSchema); - const parseResult = await safeParseAsync2(outputObj, result.structuredContent); - if (!parseResult.success) { - const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; - const errorMessage = getParseErrorMessage(error51); - throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage}`); + return { + isValid: true, + warnings + }; +} +function issueToolNameWarning(name, warnings) { + if (warnings.length > 0) { + console.warn(`Tool name validation warning for "${name}":`); + for (const warning of warnings) { + console.warn(` - ${warning}`); } + console.warn("Tool registration will proceed, but this may cause compatibility issues."); + console.warn("Consider updating the tool name to conform to the MCP tool naming standard."); + console.warn("See SEP: Specify Format for Tool Names (https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986) for more details."); } - async executeToolHandler(tool, args, extra) { - const handler = tool.handler; - const isTaskHandler = "createTask" in handler; - if (isTaskHandler) { - if (!extra.taskStore) { - throw new Error("No task store provided."); - } - const taskExtra = { ...extra, taskStore: extra.taskStore }; - if (tool.inputSchema) { - const typedHandler = handler; - return await Promise.resolve(typedHandler.createTask(args, taskExtra)); - } else { - const typedHandler = handler; - return await Promise.resolve(typedHandler.createTask(taskExtra)); - } - } - if (tool.inputSchema) { - const typedHandler = handler; - return await Promise.resolve(typedHandler(args, extra)); - } else { - const typedHandler = handler; - return await Promise.resolve(typedHandler(extra)); - } +} +function validateAndWarnToolName(name) { + const result = validateToolName(name); + issueToolNameWarning(name, result.warnings); + return result.isValid; +} + +// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js +class ExperimentalMcpServerTasks { + constructor(_mcpServer) { + this._mcpServer = _mcpServer; } - async handleAutomaticTaskPolling(tool, request, extra) { - if (!extra.taskStore) { - throw new Error("No task store provided for task-capable tool."); - } - const args = await this.validateToolInput(tool, request.params.arguments, request.params.name); - const handler = tool.handler; - const taskExtra = { ...extra, taskStore: extra.taskStore }; - const createTaskResult = args ? await Promise.resolve(handler.createTask(args, taskExtra)) : await Promise.resolve(handler.createTask(taskExtra)); - const taskId = createTaskResult.task.taskId; - let task = createTaskResult.task; - const pollInterval = task.pollInterval ?? 5000; - while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") { - await new Promise((resolve) => setTimeout(resolve, pollInterval)); - const updatedTask = await extra.taskStore.getTask(taskId); - if (!updatedTask) { - throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`); - } - task = updatedTask; + registerToolTask(name, config2, handler) { + const execution = { taskSupport: "required", ...config2.execution }; + if (execution.taskSupport === "forbidden") { + throw new Error(`Cannot register task-based tool '${name}' with taskSupport 'forbidden'. Use registerTool() instead.`); } - return await extra.taskStore.getTaskResult(taskId); + const mcpServerInternal = this._mcpServer; + return mcpServerInternal._createRegisteredTool(name, config2.title, config2.description, config2.inputSchema, config2.outputSchema, config2.annotations, execution, config2._meta, handler); } - setCompletionRequestHandler() { - if (this._completionHandlerInitialized) { - return; - } - this.server.assertCanSetRequestHandler(getMethodValue(CompleteRequestSchema)); - this.server.registerCapabilities({ - completions: {} - }); - this.server.setRequestHandler(CompleteRequestSchema, async (request) => { - switch (request.params.ref.type) { - case "ref/prompt": - assertCompleteRequestPrompt(request); - return this.handlePromptCompletion(request, request.params.ref); - case "ref/resource": - assertCompleteRequestResourceTemplate(request); - return this.handleResourceCompletion(request, request.params.ref); - default: - throw new McpError(ErrorCode.InvalidParams, `Invalid completion reference: ${request.params.ref}`); - } - }); - this._completionHandlerInitialized = true; +} +// node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js +class McpServer { + constructor(serverInfo, options) { + this._registeredResources = {}; + this._registeredResourceTemplates = {}; + this._registeredTools = {}; + this._registeredPrompts = {}; + this._toolHandlersInitialized = false; + this._completionHandlerInitialized = false; + this._resourceHandlersInitialized = false; + this._promptHandlersInitialized = false; + this.server = new Server(serverInfo, options); } - async handlePromptCompletion(request, ref) { - const prompt = this._registeredPrompts[ref.name]; - if (!prompt) { - throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} not found`); - } - if (!prompt.enabled) { - throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} disabled`); - } - if (!prompt.argsSchema) { - return EMPTY_COMPLETION_RESULT; - } - const promptShape = getObjectShape(prompt.argsSchema); - const field = promptShape?.[request.params.argument.name]; - if (!isCompletable(field)) { - return EMPTY_COMPLETION_RESULT; - } - const completer = getCompleter(field); - if (!completer) { - return EMPTY_COMPLETION_RESULT; + get experimental() { + if (!this._experimental) { + this._experimental = { + tasks: new ExperimentalMcpServerTasks(this) + }; } - const suggestions = await completer(request.params.argument.value, request.params.context); - return createCompletionResult(suggestions); + return this._experimental; } - async handleResourceCompletion(request, ref) { - const template = Object.values(this._registeredResourceTemplates).find((t) => t.resourceTemplate.uriTemplate.toString() === ref.uri); - if (!template) { - if (this._registeredResources[ref.uri]) { - return EMPTY_COMPLETION_RESULT; - } - throw new McpError(ErrorCode.InvalidParams, `Resource template ${request.params.ref.uri} not found`); - } - const completer = template.resourceTemplate.completeCallback(request.params.argument.name); - if (!completer) { - return EMPTY_COMPLETION_RESULT; - } - const suggestions = await completer(request.params.argument.value, request.params.context); - return createCompletionResult(suggestions); + async connect(transport) { + return await this.server.connect(transport); } - setResourceRequestHandlers() { - if (this._resourceHandlersInitialized) { - return; - } - this.server.assertCanSetRequestHandler(getMethodValue(ListResourcesRequestSchema)); - this.server.assertCanSetRequestHandler(getMethodValue(ListResourceTemplatesRequestSchema)); - this.server.assertCanSetRequestHandler(getMethodValue(ReadResourceRequestSchema)); - this.server.registerCapabilities({ - resources: { - listChanged: true - } - }); - this.server.setRequestHandler(ListResourcesRequestSchema, async (request, extra) => { - const resources = Object.entries(this._registeredResources).filter(([_, resource]) => resource.enabled).map(([uri, resource]) => ({ - uri, - name: resource.name, - ...resource.metadata - })); - const templateResources = []; - for (const template of Object.values(this._registeredResourceTemplates)) { - if (!template.resourceTemplate.listCallback) { - continue; - } - const result = await template.resourceTemplate.listCallback(extra); - for (const resource of result.resources) { - templateResources.push({ - ...template.metadata, - ...resource - }); - } - } - return { resources: [...resources, ...templateResources] }; - }); - this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => { - const resourceTemplates = Object.entries(this._registeredResourceTemplates).map(([name, template]) => ({ - name, - uriTemplate: template.resourceTemplate.uriTemplate.toString(), - ...template.metadata - })); - return { resourceTemplates }; - }); - this.server.setRequestHandler(ReadResourceRequestSchema, async (request, extra) => { - const uri = new URL(request.params.uri); - const resource = this._registeredResources[uri.toString()]; - if (resource) { - if (!resource.enabled) { - throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} disabled`); - } - return resource.readCallback(uri, extra); - } - for (const template of Object.values(this._registeredResourceTemplates)) { - const variables = template.resourceTemplate.uriTemplate.match(uri.toString()); - if (variables) { - return template.readCallback(uri, variables, extra); - } - } - throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} not found`); - }); - this._resourceHandlersInitialized = true; + async close() { + await this.server.close(); } - setPromptRequestHandlers() { - if (this._promptHandlersInitialized) { + setToolRequestHandlers() { + if (this._toolHandlersInitialized) { return; } - this.server.assertCanSetRequestHandler(getMethodValue(ListPromptsRequestSchema)); - this.server.assertCanSetRequestHandler(getMethodValue(GetPromptRequestSchema)); + this.server.assertCanSetRequestHandler(getMethodValue(ListToolsRequestSchema)); + this.server.assertCanSetRequestHandler(getMethodValue(CallToolRequestSchema)); this.server.registerCapabilities({ - prompts: { + tools: { listChanged: true } }); - this.server.setRequestHandler(ListPromptsRequestSchema, () => ({ - prompts: Object.entries(this._registeredPrompts).filter(([, prompt]) => prompt.enabled).map(([name, prompt]) => { - return { + this.server.setRequestHandler(ListToolsRequestSchema, () => ({ + tools: Object.entries(this._registeredTools).filter(([, tool]) => tool.enabled).map(([name, tool]) => { + const toolDefinition = { name, - title: prompt.title, - description: prompt.description, - arguments: prompt.argsSchema ? promptArgumentsFromSchema(prompt.argsSchema) : undefined + title: tool.title, + description: tool.description, + inputSchema: (() => { + const obj = normalizeObjectSchema(tool.inputSchema); + return obj ? toJsonSchemaCompat(obj, { + strictUnions: true, + pipeStrategy: "input" + }) : EMPTY_OBJECT_JSON_SCHEMA; + })(), + annotations: tool.annotations, + execution: tool.execution, + _meta: tool._meta }; + if (tool.outputSchema) { + const obj = normalizeObjectSchema(tool.outputSchema); + if (obj) { + toolDefinition.outputSchema = toJsonSchemaCompat(obj, { + strictUnions: true, + pipeStrategy: "output" + }); + } + } + return toolDefinition; }) })); - this.server.setRequestHandler(GetPromptRequestSchema, async (request, extra) => { - const prompt = this._registeredPrompts[request.params.name]; - if (!prompt) { - throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} not found`); - } - if (!prompt.enabled) { - throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} disabled`); - } - if (prompt.argsSchema) { - const argsObj = normalizeObjectSchema(prompt.argsSchema); - const parseResult = await safeParseAsync2(argsObj, request.params.arguments); - if (!parseResult.success) { - const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; - const errorMessage = getParseErrorMessage(error51); - throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request.params.name}: ${errorMessage}`); + this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { + try { + const tool = this._registeredTools[request.params.name]; + if (!tool) { + throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} not found`); } - const args = parseResult.data; - const cb = prompt.callback; - return await Promise.resolve(cb(args, extra)); - } else { - const cb = prompt.callback; - return await Promise.resolve(cb(extra)); - } - }); - this._promptHandlersInitialized = true; - } - resource(name, uriOrTemplate, ...rest) { - let metadata; - if (typeof rest[0] === "object") { - metadata = rest.shift(); - } - const readCallback = rest[0]; - if (typeof uriOrTemplate === "string") { - if (this._registeredResources[uriOrTemplate]) { - throw new Error(`Resource ${uriOrTemplate} is already registered`); - } - const registeredResource = this._createRegisteredResource(name, undefined, uriOrTemplate, metadata, readCallback); - this.setResourceRequestHandlers(); - this.sendResourceListChanged(); - return registeredResource; - } else { - if (this._registeredResourceTemplates[name]) { - throw new Error(`Resource template ${name} is already registered`); - } - const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, undefined, uriOrTemplate, metadata, readCallback); - this.setResourceRequestHandlers(); - this.sendResourceListChanged(); - return registeredResourceTemplate; - } - } - registerResource(name, uriOrTemplate, config2, readCallback) { - if (typeof uriOrTemplate === "string") { - if (this._registeredResources[uriOrTemplate]) { - throw new Error(`Resource ${uriOrTemplate} is already registered`); - } - const registeredResource = this._createRegisteredResource(name, config2.title, uriOrTemplate, config2, readCallback); - this.setResourceRequestHandlers(); - this.sendResourceListChanged(); - return registeredResource; - } else { - if (this._registeredResourceTemplates[name]) { - throw new Error(`Resource template ${name} is already registered`); - } - const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, config2.title, uriOrTemplate, config2, readCallback); - this.setResourceRequestHandlers(); - this.sendResourceListChanged(); - return registeredResourceTemplate; - } - } - _createRegisteredResource(name, title, uri, metadata, readCallback) { - const registeredResource = { - name, - title, - metadata, - readCallback, - enabled: true, - disable: () => registeredResource.update({ enabled: false }), - enable: () => registeredResource.update({ enabled: true }), - remove: () => registeredResource.update({ uri: null }), - update: (updates) => { - if (typeof updates.uri !== "undefined" && updates.uri !== uri) { - delete this._registeredResources[uri]; - if (updates.uri) - this._registeredResources[updates.uri] = registeredResource; + if (!tool.enabled) { + throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} disabled`); } - if (typeof updates.name !== "undefined") - registeredResource.name = updates.name; - if (typeof updates.title !== "undefined") - registeredResource.title = updates.title; - if (typeof updates.metadata !== "undefined") - registeredResource.metadata = updates.metadata; - if (typeof updates.callback !== "undefined") - registeredResource.readCallback = updates.callback; - if (typeof updates.enabled !== "undefined") - registeredResource.enabled = updates.enabled; - this.sendResourceListChanged(); - } - }; - this._registeredResources[uri] = registeredResource; - return registeredResource; - } - _createRegisteredResourceTemplate(name, title, template, metadata, readCallback) { - const registeredResourceTemplate = { - resourceTemplate: template, - title, - metadata, - readCallback, - enabled: true, - disable: () => registeredResourceTemplate.update({ enabled: false }), - enable: () => registeredResourceTemplate.update({ enabled: true }), - remove: () => registeredResourceTemplate.update({ name: null }), - update: (updates) => { - if (typeof updates.name !== "undefined" && updates.name !== name) { - delete this._registeredResourceTemplates[name]; - if (updates.name) - this._registeredResourceTemplates[updates.name] = registeredResourceTemplate; + const isTaskRequest = !!request.params.task; + const taskSupport = tool.execution?.taskSupport; + const isTaskHandler = "createTask" in tool.handler; + if ((taskSupport === "required" || taskSupport === "optional") && !isTaskHandler) { + throw new McpError(ErrorCode.InternalError, `Tool ${request.params.name} has taskSupport '${taskSupport}' but was not registered with registerToolTask`); } - if (typeof updates.title !== "undefined") - registeredResourceTemplate.title = updates.title; - if (typeof updates.template !== "undefined") - registeredResourceTemplate.resourceTemplate = updates.template; - if (typeof updates.metadata !== "undefined") - registeredResourceTemplate.metadata = updates.metadata; - if (typeof updates.callback !== "undefined") - registeredResourceTemplate.readCallback = updates.callback; - if (typeof updates.enabled !== "undefined") - registeredResourceTemplate.enabled = updates.enabled; - this.sendResourceListChanged(); - } - }; - this._registeredResourceTemplates[name] = registeredResourceTemplate; - const variableNames = template.uriTemplate.variableNames; - const hasCompleter = Array.isArray(variableNames) && variableNames.some((v) => !!template.completeCallback(v)); - if (hasCompleter) { - this.setCompletionRequestHandler(); - } - return registeredResourceTemplate; - } - _createRegisteredPrompt(name, title, description, argsSchema, callback) { - const registeredPrompt = { - title, - description, - argsSchema: argsSchema === undefined ? undefined : objectFromShape(argsSchema), - callback, - enabled: true, - disable: () => registeredPrompt.update({ enabled: false }), - enable: () => registeredPrompt.update({ enabled: true }), - remove: () => registeredPrompt.update({ name: null }), - update: (updates) => { - if (typeof updates.name !== "undefined" && updates.name !== name) { - delete this._registeredPrompts[name]; - if (updates.name) - this._registeredPrompts[updates.name] = registeredPrompt; + if (taskSupport === "required" && !isTaskRequest) { + throw new McpError(ErrorCode.MethodNotFound, `Tool ${request.params.name} requires task augmentation (taskSupport: 'required')`); } - if (typeof updates.title !== "undefined") - registeredPrompt.title = updates.title; - if (typeof updates.description !== "undefined") - registeredPrompt.description = updates.description; - if (typeof updates.argsSchema !== "undefined") - registeredPrompt.argsSchema = objectFromShape(updates.argsSchema); - if (typeof updates.callback !== "undefined") - registeredPrompt.callback = updates.callback; - if (typeof updates.enabled !== "undefined") - registeredPrompt.enabled = updates.enabled; - this.sendPromptListChanged(); - } - }; - this._registeredPrompts[name] = registeredPrompt; - if (argsSchema) { - const hasCompletable = Object.values(argsSchema).some((field) => { - const inner = field instanceof ZodOptional2 ? field._def?.innerType : field; - return isCompletable(inner); - }); - if (hasCompletable) { - this.setCompletionRequestHandler(); - } - } - return registeredPrompt; - } - _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, execution, _meta, handler) { - validateAndWarnToolName(name); - const registeredTool = { - title, - description, - inputSchema: getZodSchemaObject(inputSchema), - outputSchema: getZodSchemaObject(outputSchema), - annotations, - execution, - _meta, - handler, - enabled: true, - disable: () => registeredTool.update({ enabled: false }), - enable: () => registeredTool.update({ enabled: true }), - remove: () => registeredTool.update({ name: null }), - update: (updates) => { - if (typeof updates.name !== "undefined" && updates.name !== name) { - if (typeof updates.name === "string") { - validateAndWarnToolName(updates.name); + if (taskSupport === "optional" && !isTaskRequest && isTaskHandler) { + return await this.handleAutomaticTaskPolling(tool, request, extra); + } + const args = await this.validateToolInput(tool, request.params.arguments, request.params.name); + const result = await this.executeToolHandler(tool, args, extra); + if (isTaskRequest) { + return result; + } + await this.validateToolOutput(tool, result, request.params.name); + return result; + } catch (error51) { + if (error51 instanceof McpError) { + if (error51.code === ErrorCode.UrlElicitationRequired) { + throw error51; } - delete this._registeredTools[name]; - if (updates.name) - this._registeredTools[updates.name] = registeredTool; } - if (typeof updates.title !== "undefined") - registeredTool.title = updates.title; - if (typeof updates.description !== "undefined") - registeredTool.description = updates.description; - if (typeof updates.paramsSchema !== "undefined") - registeredTool.inputSchema = objectFromShape(updates.paramsSchema); - if (typeof updates.outputSchema !== "undefined") - registeredTool.outputSchema = objectFromShape(updates.outputSchema); - if (typeof updates.callback !== "undefined") - registeredTool.handler = updates.callback; - if (typeof updates.annotations !== "undefined") - registeredTool.annotations = updates.annotations; - if (typeof updates._meta !== "undefined") - registeredTool._meta = updates._meta; - if (typeof updates.enabled !== "undefined") - registeredTool.enabled = updates.enabled; - this.sendToolListChanged(); + return this.createToolError(error51 instanceof Error ? error51.message : String(error51)); } + }); + this._toolHandlersInitialized = true; + } + createToolError(errorMessage) { + return { + content: [ + { + type: "text", + text: errorMessage + } + ], + isError: true }; - this._registeredTools[name] = registeredTool; - this.setToolRequestHandlers(); - this.sendToolListChanged(); - return registeredTool; } - tool(name, ...rest) { - if (this._registeredTools[name]) { - throw new Error(`Tool ${name} is already registered`); - } - let description; - let inputSchema; - let outputSchema; - let annotations; - if (typeof rest[0] === "string") { - description = rest.shift(); + async validateToolInput(tool, args, toolName) { + if (!tool.inputSchema) { + return; } - if (rest.length > 1) { - const firstArg = rest[0]; - if (isZodRawShapeCompat(firstArg)) { - inputSchema = rest.shift(); - if (rest.length > 1 && typeof rest[0] === "object" && rest[0] !== null && !isZodRawShapeCompat(rest[0])) { - annotations = rest.shift(); - } - } else if (typeof firstArg === "object" && firstArg !== null) { - if (Object.values(firstArg).some((v) => typeof v === "object" && v !== null)) { - throw new Error(`Tool ${name} expected a Zod schema or ToolAnnotations, but received an unrecognized object`); - } - annotations = rest.shift(); - } + const inputObj = normalizeObjectSchema(tool.inputSchema); + const schemaToParse = inputObj ?? tool.inputSchema; + const parseResult = await safeParseAsync2(schemaToParse, args); + if (!parseResult.success) { + const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; + const errorMessage = getParseErrorMessage(error51); + throw new McpError(ErrorCode.InvalidParams, `Input validation error: Invalid arguments for tool ${toolName}: ${errorMessage}`); } - const callback = rest[0]; - return this._createRegisteredTool(name, undefined, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, undefined, callback); + return parseResult.data; } - registerTool(name, config2, cb) { - if (this._registeredTools[name]) { - throw new Error(`Tool ${name} is already registered`); + async validateToolOutput(tool, result, toolName) { + if (!tool.outputSchema) { + return; } - const { title, description, inputSchema, outputSchema, annotations, _meta } = config2; - return this._createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, _meta, cb); - } - prompt(name, ...rest) { - if (this._registeredPrompts[name]) { - throw new Error(`Prompt ${name} is already registered`); + if (!("content" in result)) { + return; } - let description; - if (typeof rest[0] === "string") { - description = rest.shift(); + if (result.isError) { + return; } - let argsSchema; - if (rest.length > 1) { - argsSchema = rest.shift(); + if (!result.structuredContent) { + throw new McpError(ErrorCode.InvalidParams, `Output validation error: Tool ${toolName} has an output schema but no structured content was provided`); } - const cb = rest[0]; - const registeredPrompt = this._createRegisteredPrompt(name, undefined, description, argsSchema, cb); - this.setPromptRequestHandlers(); - this.sendPromptListChanged(); - return registeredPrompt; - } - registerPrompt(name, config2, cb) { - if (this._registeredPrompts[name]) { - throw new Error(`Prompt ${name} is already registered`); + const outputObj = normalizeObjectSchema(tool.outputSchema); + const parseResult = await safeParseAsync2(outputObj, result.structuredContent); + if (!parseResult.success) { + const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; + const errorMessage = getParseErrorMessage(error51); + throw new McpError(ErrorCode.InvalidParams, `Output validation error: Invalid structured content for tool ${toolName}: ${errorMessage}`); } - const { title, description, argsSchema } = config2; - const registeredPrompt = this._createRegisteredPrompt(name, title, description, argsSchema, cb); - this.setPromptRequestHandlers(); - this.sendPromptListChanged(); - return registeredPrompt; - } - isConnected() { - return this.server.transport !== undefined; } - async sendLoggingMessage(params, sessionId) { - return this.server.sendLoggingMessage(params, sessionId); - } - sendResourceListChanged() { - if (this.isConnected()) { - this.server.sendResourceListChanged(); + async executeToolHandler(tool, args, extra) { + const handler = tool.handler; + const isTaskHandler = "createTask" in handler; + if (isTaskHandler) { + if (!extra.taskStore) { + throw new Error("No task store provided."); + } + const taskExtra = { ...extra, taskStore: extra.taskStore }; + if (tool.inputSchema) { + const typedHandler = handler; + return await Promise.resolve(typedHandler.createTask(args, taskExtra)); + } else { + const typedHandler = handler; + return await Promise.resolve(typedHandler.createTask(taskExtra)); + } } - } - sendToolListChanged() { - if (this.isConnected()) { - this.server.sendToolListChanged(); + if (tool.inputSchema) { + const typedHandler = handler; + return await Promise.resolve(typedHandler(args, extra)); + } else { + const typedHandler = handler; + return await Promise.resolve(typedHandler(extra)); } } - sendPromptListChanged() { - if (this.isConnected()) { - this.server.sendPromptListChanged(); + async handleAutomaticTaskPolling(tool, request, extra) { + if (!extra.taskStore) { + throw new Error("No task store provided for task-capable tool."); } + const args = await this.validateToolInput(tool, request.params.arguments, request.params.name); + const handler = tool.handler; + const taskExtra = { ...extra, taskStore: extra.taskStore }; + const createTaskResult = args ? await Promise.resolve(handler.createTask(args, taskExtra)) : await Promise.resolve(handler.createTask(taskExtra)); + const taskId = createTaskResult.task.taskId; + let task = createTaskResult.task; + const pollInterval = task.pollInterval ?? 5000; + while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") { + await new Promise((resolve) => setTimeout(resolve, pollInterval)); + const updatedTask = await extra.taskStore.getTask(taskId); + if (!updatedTask) { + throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`); + } + task = updatedTask; + } + return await extra.taskStore.getTaskResult(taskId); } -} -var EMPTY_OBJECT_JSON_SCHEMA = { - type: "object", - properties: {} -}; -function isZodTypeLike(value) { - return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function"; -} -function isZodSchemaInstance(obj) { - return "_def" in obj || "_zod" in obj || isZodTypeLike(obj); -} -function isZodRawShapeCompat(obj) { - if (typeof obj !== "object" || obj === null) { - return false; - } - if (isZodSchemaInstance(obj)) { - return false; - } - if (Object.keys(obj).length === 0) { - return true; - } - return Object.values(obj).some(isZodTypeLike); -} -function getZodSchemaObject(schema) { - if (!schema) { - return; - } - if (isZodRawShapeCompat(schema)) { - return objectFromShape(schema); - } - if (!isZodSchemaInstance(schema)) { - throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object"); + setCompletionRequestHandler() { + if (this._completionHandlerInitialized) { + return; + } + this.server.assertCanSetRequestHandler(getMethodValue(CompleteRequestSchema)); + this.server.registerCapabilities({ + completions: {} + }); + this.server.setRequestHandler(CompleteRequestSchema, async (request) => { + switch (request.params.ref.type) { + case "ref/prompt": + assertCompleteRequestPrompt(request); + return this.handlePromptCompletion(request, request.params.ref); + case "ref/resource": + assertCompleteRequestResourceTemplate(request); + return this.handleResourceCompletion(request, request.params.ref); + default: + throw new McpError(ErrorCode.InvalidParams, `Invalid completion reference: ${request.params.ref}`); + } + }); + this._completionHandlerInitialized = true; } - return schema; -} -function promptArgumentsFromSchema(schema) { - const shape = getObjectShape(schema); - if (!shape) - return []; - return Object.entries(shape).map(([name, field]) => { - const description = getSchemaDescription(field); - const isOptional = isSchemaOptional(field); - return { - name, - description, - required: !isOptional - }; - }); -} -function getMethodValue(schema) { - const shape = getObjectShape(schema); - const methodSchema = shape?.method; - if (!methodSchema) { - throw new Error("Schema is missing a method literal"); + async handlePromptCompletion(request, ref) { + const prompt = this._registeredPrompts[ref.name]; + if (!prompt) { + throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} not found`); + } + if (!prompt.enabled) { + throw new McpError(ErrorCode.InvalidParams, `Prompt ${ref.name} disabled`); + } + if (!prompt.argsSchema) { + return EMPTY_COMPLETION_RESULT; + } + const promptShape = getObjectShape(prompt.argsSchema); + const field = promptShape?.[request.params.argument.name]; + if (!isCompletable(field)) { + return EMPTY_COMPLETION_RESULT; + } + const completer = getCompleter(field); + if (!completer) { + return EMPTY_COMPLETION_RESULT; + } + const suggestions = await completer(request.params.argument.value, request.params.context); + return createCompletionResult(suggestions); } - const value = getLiteralValue(methodSchema); - if (typeof value === "string") { - return value; + async handleResourceCompletion(request, ref) { + const template = Object.values(this._registeredResourceTemplates).find((t) => t.resourceTemplate.uriTemplate.toString() === ref.uri); + if (!template) { + if (this._registeredResources[ref.uri]) { + return EMPTY_COMPLETION_RESULT; + } + throw new McpError(ErrorCode.InvalidParams, `Resource template ${request.params.ref.uri} not found`); + } + const completer = template.resourceTemplate.completeCallback(request.params.argument.name); + if (!completer) { + return EMPTY_COMPLETION_RESULT; + } + const suggestions = await completer(request.params.argument.value, request.params.context); + return createCompletionResult(suggestions); } - throw new Error("Schema method literal must be a string"); -} -function createCompletionResult(suggestions) { - return { - completion: { - values: suggestions.slice(0, 100), - total: suggestions.length, - hasMore: suggestions.length > 100 + setResourceRequestHandlers() { + if (this._resourceHandlersInitialized) { + return; } - }; -} -var EMPTY_COMPLETION_RESULT = { - completion: { - values: [], - hasMore: false + this.server.assertCanSetRequestHandler(getMethodValue(ListResourcesRequestSchema)); + this.server.assertCanSetRequestHandler(getMethodValue(ListResourceTemplatesRequestSchema)); + this.server.assertCanSetRequestHandler(getMethodValue(ReadResourceRequestSchema)); + this.server.registerCapabilities({ + resources: { + listChanged: true + } + }); + this.server.setRequestHandler(ListResourcesRequestSchema, async (request, extra) => { + const resources = Object.entries(this._registeredResources).filter(([_, resource]) => resource.enabled).map(([uri, resource]) => ({ + uri, + name: resource.name, + ...resource.metadata + })); + const templateResources = []; + for (const template of Object.values(this._registeredResourceTemplates)) { + if (!template.resourceTemplate.listCallback) { + continue; + } + const result = await template.resourceTemplate.listCallback(extra); + for (const resource of result.resources) { + templateResources.push({ + ...template.metadata, + ...resource + }); + } + } + return { resources: [...resources, ...templateResources] }; + }); + this.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => { + const resourceTemplates = Object.entries(this._registeredResourceTemplates).map(([name, template]) => ({ + name, + uriTemplate: template.resourceTemplate.uriTemplate.toString(), + ...template.metadata + })); + return { resourceTemplates }; + }); + this.server.setRequestHandler(ReadResourceRequestSchema, async (request, extra) => { + const uri = new URL(request.params.uri); + const resource = this._registeredResources[uri.toString()]; + if (resource) { + if (!resource.enabled) { + throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} disabled`); + } + return resource.readCallback(uri, extra); + } + for (const template of Object.values(this._registeredResourceTemplates)) { + const variables = template.resourceTemplate.uriTemplate.match(uri.toString()); + if (variables) { + return template.readCallback(uri, variables, extra); + } + } + throw new McpError(ErrorCode.InvalidParams, `Resource ${uri} not found`); + }); + this._resourceHandlersInitialized = true; } -}; - -// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js -import process3 from "process"; - -// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js -class ReadBuffer { - append(chunk) { - this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk; + setPromptRequestHandlers() { + if (this._promptHandlersInitialized) { + return; + } + this.server.assertCanSetRequestHandler(getMethodValue(ListPromptsRequestSchema)); + this.server.assertCanSetRequestHandler(getMethodValue(GetPromptRequestSchema)); + this.server.registerCapabilities({ + prompts: { + listChanged: true + } + }); + this.server.setRequestHandler(ListPromptsRequestSchema, () => ({ + prompts: Object.entries(this._registeredPrompts).filter(([, prompt]) => prompt.enabled).map(([name, prompt]) => { + return { + name, + title: prompt.title, + description: prompt.description, + arguments: prompt.argsSchema ? promptArgumentsFromSchema(prompt.argsSchema) : undefined + }; + }) + })); + this.server.setRequestHandler(GetPromptRequestSchema, async (request, extra) => { + const prompt = this._registeredPrompts[request.params.name]; + if (!prompt) { + throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} not found`); + } + if (!prompt.enabled) { + throw new McpError(ErrorCode.InvalidParams, `Prompt ${request.params.name} disabled`); + } + if (prompt.argsSchema) { + const argsObj = normalizeObjectSchema(prompt.argsSchema); + const parseResult = await safeParseAsync2(argsObj, request.params.arguments); + if (!parseResult.success) { + const error51 = "error" in parseResult ? parseResult.error : "Unknown error"; + const errorMessage = getParseErrorMessage(error51); + throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${request.params.name}: ${errorMessage}`); + } + const args = parseResult.data; + const cb = prompt.callback; + return await Promise.resolve(cb(args, extra)); + } else { + const cb = prompt.callback; + return await Promise.resolve(cb(extra)); + } + }); + this._promptHandlersInitialized = true; } - readMessage() { - if (!this._buffer) { - return null; + resource(name, uriOrTemplate, ...rest) { + let metadata; + if (typeof rest[0] === "object") { + metadata = rest.shift(); } - const index = this._buffer.indexOf(` -`); - if (index === -1) { - return null; + const readCallback = rest[0]; + if (typeof uriOrTemplate === "string") { + if (this._registeredResources[uriOrTemplate]) { + throw new Error(`Resource ${uriOrTemplate} is already registered`); + } + const registeredResource = this._createRegisteredResource(name, undefined, uriOrTemplate, metadata, readCallback); + this.setResourceRequestHandlers(); + this.sendResourceListChanged(); + return registeredResource; + } else { + if (this._registeredResourceTemplates[name]) { + throw new Error(`Resource template ${name} is already registered`); + } + const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, undefined, uriOrTemplate, metadata, readCallback); + this.setResourceRequestHandlers(); + this.sendResourceListChanged(); + return registeredResourceTemplate; } - const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, ""); - this._buffer = this._buffer.subarray(index + 1); - return deserializeMessage(line); } - clear() { - this._buffer = undefined; + registerResource(name, uriOrTemplate, config2, readCallback) { + if (typeof uriOrTemplate === "string") { + if (this._registeredResources[uriOrTemplate]) { + throw new Error(`Resource ${uriOrTemplate} is already registered`); + } + const registeredResource = this._createRegisteredResource(name, config2.title, uriOrTemplate, config2, readCallback); + this.setResourceRequestHandlers(); + this.sendResourceListChanged(); + return registeredResource; + } else { + if (this._registeredResourceTemplates[name]) { + throw new Error(`Resource template ${name} is already registered`); + } + const registeredResourceTemplate = this._createRegisteredResourceTemplate(name, config2.title, uriOrTemplate, config2, readCallback); + this.setResourceRequestHandlers(); + this.sendResourceListChanged(); + return registeredResourceTemplate; + } } -} -function deserializeMessage(line) { - return JSONRPCMessageSchema.parse(JSON.parse(line)); -} -function serializeMessage(message) { - return JSON.stringify(message) + ` -`; -} - -// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js -class StdioServerTransport { - constructor(_stdin = process3.stdin, _stdout = process3.stdout) { - this._stdin = _stdin; - this._stdout = _stdout; - this._readBuffer = new ReadBuffer; - this._started = false; - this._ondata = (chunk) => { - this._readBuffer.append(chunk); - this.processReadBuffer(); - }; - this._onerror = (error51) => { - this.onerror?.(error51); + _createRegisteredResource(name, title, uri, metadata, readCallback) { + const registeredResource = { + name, + title, + metadata, + readCallback, + enabled: true, + disable: () => registeredResource.update({ enabled: false }), + enable: () => registeredResource.update({ enabled: true }), + remove: () => registeredResource.update({ uri: null }), + update: (updates) => { + if (typeof updates.uri !== "undefined" && updates.uri !== uri) { + delete this._registeredResources[uri]; + if (updates.uri) + this._registeredResources[updates.uri] = registeredResource; + } + if (typeof updates.name !== "undefined") + registeredResource.name = updates.name; + if (typeof updates.title !== "undefined") + registeredResource.title = updates.title; + if (typeof updates.metadata !== "undefined") + registeredResource.metadata = updates.metadata; + if (typeof updates.callback !== "undefined") + registeredResource.readCallback = updates.callback; + if (typeof updates.enabled !== "undefined") + registeredResource.enabled = updates.enabled; + this.sendResourceListChanged(); + } }; + this._registeredResources[uri] = registeredResource; + return registeredResource; } - async start() { - if (this._started) { - throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically."); - } - this._started = true; - this._stdin.on("data", this._ondata); - this._stdin.on("error", this._onerror); - } - processReadBuffer() { - while (true) { - try { - const message = this._readBuffer.readMessage(); - if (message === null) { - break; + _createRegisteredResourceTemplate(name, title, template, metadata, readCallback) { + const registeredResourceTemplate = { + resourceTemplate: template, + title, + metadata, + readCallback, + enabled: true, + disable: () => registeredResourceTemplate.update({ enabled: false }), + enable: () => registeredResourceTemplate.update({ enabled: true }), + remove: () => registeredResourceTemplate.update({ name: null }), + update: (updates) => { + if (typeof updates.name !== "undefined" && updates.name !== name) { + delete this._registeredResourceTemplates[name]; + if (updates.name) + this._registeredResourceTemplates[updates.name] = registeredResourceTemplate; } - this.onmessage?.(message); - } catch (error51) { - this.onerror?.(error51); + if (typeof updates.title !== "undefined") + registeredResourceTemplate.title = updates.title; + if (typeof updates.template !== "undefined") + registeredResourceTemplate.resourceTemplate = updates.template; + if (typeof updates.metadata !== "undefined") + registeredResourceTemplate.metadata = updates.metadata; + if (typeof updates.callback !== "undefined") + registeredResourceTemplate.readCallback = updates.callback; + if (typeof updates.enabled !== "undefined") + registeredResourceTemplate.enabled = updates.enabled; + this.sendResourceListChanged(); } + }; + this._registeredResourceTemplates[name] = registeredResourceTemplate; + const variableNames = template.uriTemplate.variableNames; + const hasCompleter = Array.isArray(variableNames) && variableNames.some((v) => !!template.completeCallback(v)); + if (hasCompleter) { + this.setCompletionRequestHandler(); } + return registeredResourceTemplate; } - async close() { - this._stdin.off("data", this._ondata); - this._stdin.off("error", this._onerror); - const remainingDataListeners = this._stdin.listenerCount("data"); - if (remainingDataListeners === 0) { - this._stdin.pause(); + _createRegisteredPrompt(name, title, description, argsSchema, callback) { + const registeredPrompt = { + title, + description, + argsSchema: argsSchema === undefined ? undefined : objectFromShape(argsSchema), + callback, + enabled: true, + disable: () => registeredPrompt.update({ enabled: false }), + enable: () => registeredPrompt.update({ enabled: true }), + remove: () => registeredPrompt.update({ name: null }), + update: (updates) => { + if (typeof updates.name !== "undefined" && updates.name !== name) { + delete this._registeredPrompts[name]; + if (updates.name) + this._registeredPrompts[updates.name] = registeredPrompt; + } + if (typeof updates.title !== "undefined") + registeredPrompt.title = updates.title; + if (typeof updates.description !== "undefined") + registeredPrompt.description = updates.description; + if (typeof updates.argsSchema !== "undefined") + registeredPrompt.argsSchema = objectFromShape(updates.argsSchema); + if (typeof updates.callback !== "undefined") + registeredPrompt.callback = updates.callback; + if (typeof updates.enabled !== "undefined") + registeredPrompt.enabled = updates.enabled; + this.sendPromptListChanged(); + } + }; + this._registeredPrompts[name] = registeredPrompt; + if (argsSchema) { + const hasCompletable = Object.values(argsSchema).some((field) => { + const inner = field instanceof ZodOptional2 ? field._def?.innerType : field; + return isCompletable(inner); + }); + if (hasCompletable) { + this.setCompletionRequestHandler(); + } } - this._readBuffer.clear(); - this.onclose?.(); + return registeredPrompt; } - send(message) { - return new Promise((resolve) => { - const json2 = serializeMessage(message); - if (this._stdout.write(json2)) { - resolve(); - } else { - this._stdout.once("drain", resolve); + _createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, execution, _meta, handler) { + validateAndWarnToolName(name); + const registeredTool = { + title, + description, + inputSchema: getZodSchemaObject(inputSchema), + outputSchema: getZodSchemaObject(outputSchema), + annotations, + execution, + _meta, + handler, + enabled: true, + disable: () => registeredTool.update({ enabled: false }), + enable: () => registeredTool.update({ enabled: true }), + remove: () => registeredTool.update({ name: null }), + update: (updates) => { + if (typeof updates.name !== "undefined" && updates.name !== name) { + if (typeof updates.name === "string") { + validateAndWarnToolName(updates.name); + } + delete this._registeredTools[name]; + if (updates.name) + this._registeredTools[updates.name] = registeredTool; + } + if (typeof updates.title !== "undefined") + registeredTool.title = updates.title; + if (typeof updates.description !== "undefined") + registeredTool.description = updates.description; + if (typeof updates.paramsSchema !== "undefined") + registeredTool.inputSchema = objectFromShape(updates.paramsSchema); + if (typeof updates.outputSchema !== "undefined") + registeredTool.outputSchema = objectFromShape(updates.outputSchema); + if (typeof updates.callback !== "undefined") + registeredTool.handler = updates.callback; + if (typeof updates.annotations !== "undefined") + registeredTool.annotations = updates.annotations; + if (typeof updates._meta !== "undefined") + registeredTool._meta = updates._meta; + if (typeof updates.enabled !== "undefined") + registeredTool.enabled = updates.enabled; + this.sendToolListChanged(); } - }); - } -} - -// node_modules/@arkiv-network/sdk/src/consts.ts -var ARKIV_ADDRESS = "0x00000000000000000000000000000061726b6976"; -var BLOCK_TIME = 2; - -// node_modules/@arkiv-network/sdk/src/utils/payload.ts -init__esm(); -function jsonToPayload(json2) { - return toBytes(JSON.stringify(json2)); -} - -// src/darwinian/recall.ts -init__esm(); - -// src/compression/fht.ts -function log2PowerOfTwo(n) { - if (n <= 0) - return -1; - let k = 0; - let v = n; - while ((v & 1) === 0) { - v >>= 1; - k++; - } - return v === 1 ? k : -1; -} -function fastHadamardTransform(x) { - const D = x.length; - const logD = log2PowerOfTwo(D); - if (logD < 0) { - throw new Error(`fastHadamardTransform: length must be a power of two, got ${D}`); + }; + this._registeredTools[name] = registeredTool; + this.setToolRequestHandlers(); + this.sendToolListChanged(); + return registeredTool; } - let h = 1; - while (h < D) { - const twoH = h << 1; - for (let i = 0;i < D; i += twoH) { - for (let j = i;j < i + h; j++) { - const a = x[j]; - const b = x[j + h]; - x[j] = a + b; - x[j + h] = a - b; + tool(name, ...rest) { + if (this._registeredTools[name]) { + throw new Error(`Tool ${name} is already registered`); + } + let description; + let inputSchema; + let outputSchema; + let annotations; + if (typeof rest[0] === "string") { + description = rest.shift(); + } + if (rest.length > 1) { + const firstArg = rest[0]; + if (isZodRawShapeCompat(firstArg)) { + inputSchema = rest.shift(); + if (rest.length > 1 && typeof rest[0] === "object" && rest[0] !== null && !isZodRawShapeCompat(rest[0])) { + annotations = rest.shift(); + } + } else if (typeof firstArg === "object" && firstArg !== null) { + if (Object.values(firstArg).some((v) => typeof v === "object" && v !== null)) { + throw new Error(`Tool ${name} expected a Zod schema or ToolAnnotations, but received an unrecognized object`); + } + annotations = rest.shift(); } } - h = twoH; + const callback = rest[0]; + return this._createRegisteredTool(name, undefined, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, undefined, callback); } - const invSqrtD = 1 / Math.sqrt(D); - for (let i = 0;i < D; i++) { - x[i] = x[i] * invSqrtD; + registerTool(name, config2, cb) { + if (this._registeredTools[name]) { + throw new Error(`Tool ${name} is already registered`); + } + const { title, description, inputSchema, outputSchema, annotations, _meta } = config2; + return this._createRegisteredTool(name, title, description, inputSchema, outputSchema, annotations, { taskSupport: "forbidden" }, _meta, cb); } -} -function makeXorshift128(seedHex) { - const FNV_OFFSET = 2166136261; - const FNV_PRIME = 16777619; - const seeds = new Uint32Array(4); - for (let k = 0;k < 4; k++) { - let h = (FNV_OFFSET ^ k * 2654435769) >>> 0; - for (let i = 0;i < seedHex.length; i++) { - h ^= seedHex.charCodeAt(i); - h = Math.imul(h, FNV_PRIME) >>> 0; + prompt(name, ...rest) { + if (this._registeredPrompts[name]) { + throw new Error(`Prompt ${name} is already registered`); + } + let description; + if (typeof rest[0] === "string") { + description = rest.shift(); + } + let argsSchema; + if (rest.length > 1) { + argsSchema = rest.shift(); } - seeds[k] = h === 0 ? 2654435769 : h; + const cb = rest[0]; + const registeredPrompt = this._createRegisteredPrompt(name, undefined, description, argsSchema, cb); + this.setPromptRequestHandlers(); + this.sendPromptListChanged(); + return registeredPrompt; } - let s0 = seeds[0]; - let s1 = seeds[1]; - let s2 = seeds[2]; - let s3 = seeds[3]; - return function next() { - let t = s0 ^ s0 << 11; - t ^= t >>> 8; - s0 = s1; - s1 = s2; - s2 = s3; - s3 = s3 ^ s3 >>> 19 ^ (t ^ t >>> 8); - return s3 >>> 0; - }; -} -function rotateWithSeed(x, seedHex) { - const D = x.length; - const rng = makeXorshift128(seedHex); - for (let i = 0;i < D; i += 32) { - const word = rng(); - const lim = Math.min(32, D - i); - for (let b = 0;b < lim; b++) { - const bit = word >>> b & 1; - if (bit === 0) - x[i + b] = -x[i + b]; + registerPrompt(name, config2, cb) { + if (this._registeredPrompts[name]) { + throw new Error(`Prompt ${name} is already registered`); } + const { title, description, argsSchema } = config2; + const registeredPrompt = this._createRegisteredPrompt(name, title, description, argsSchema, cb); + this.setPromptRequestHandlers(); + this.sendPromptListChanged(); + return registeredPrompt; } - fastHadamardTransform(x); -} - -// src/compression/rabitq.ts -var EMBED_DIM = 1536; -var PADDED_DIM = 2048; -var SIGN_BYTES = EMBED_DIM >> 3; -var ROTATION_SEED = "cortex.rabitq.rotation.v1"; -var NORM_OFFSET = SIGN_BYTES; -var ALIGN_OFFSET = SIGN_BYTES + 2; -var CENTROID_OFFSET = SIGN_BYTES + 4; -var PACK_SIZE = SIGN_BYTES + 2 + 2 + 2; -var f32 = new Float32Array(1); -var u322 = new Uint32Array(f32.buffer); -function f32ToF16(value) { - f32[0] = value; - const x = u322[0]; - const sign = x >>> 16 & 32768; - let mant = x & 8388607; - let exp = x >>> 23 & 255; - if (exp === 255) { - return sign | 31744 | (mant !== 0 ? 512 | mant >>> 13 : 0); + isConnected() { + return this.server.transport !== undefined; } - let newExp = exp - 127 + 15; - if (newExp >= 31) { - return sign | 31744; + async sendLoggingMessage(params, sessionId) { + return this.server.sendLoggingMessage(params, sessionId); } - if (newExp <= 0) { - if (newExp < -10) - return sign; - mant = (mant | 8388608) >>> 1 - newExp; - if ((mant & 4096) !== 0) - mant += 8192; - return sign | mant >>> 13; + sendResourceListChanged() { + if (this.isConnected()) { + this.server.sendResourceListChanged(); + } } - if ((mant & 4096) !== 0) { - mant += 8192; - if ((mant & 8388608) !== 0) { - mant = 0; - newExp++; - if (newExp >= 31) - return sign | 31744; + sendToolListChanged() { + if (this.isConnected()) { + this.server.sendToolListChanged(); } } - return sign | newExp << 10 | mant >>> 13; -} -function f16ToF32(value) { - const sign = (value & 32768) << 16; - const exp = value >>> 10 & 31; - const mant = value & 1023; - let outBits; - if (exp === 0) { - if (mant === 0) { - outBits = sign; - } else { - let m = mant; - let e = 1; - while ((m & 1024) === 0) { - m <<= 1; - e--; - } - m &= 1023; - outBits = sign | e + 127 - 15 << 23 | m << 13; + sendPromptListChanged() { + if (this.isConnected()) { + this.server.sendPromptListChanged(); } - } else if (exp === 31) { - outBits = sign | 2139095040 | mant << 13; - } else { - outBits = sign | exp + 127 - 15 << 23 | mant << 13; } - u322[0] = outBits >>> 0; - return f32[0]; } -function padToRotationDim(vec) { - const out = new Float32Array(PADDED_DIM); - const n = Math.min(vec.length, EMBED_DIM); - for (let i = 0;i < n; i++) - out[i] = vec[i]; - return out; +var EMPTY_OBJECT_JSON_SCHEMA = { + type: "object", + properties: {} +}; +function isZodTypeLike(value) { + return value !== null && typeof value === "object" && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function"; } -function l2Norm(vec) { - let s = 0; - for (let i = 0;i < vec.length; i++) { - const v = vec[i]; - s += v * v; - } - return Math.sqrt(s); +function isZodSchemaInstance(obj) { + return "_def" in obj || "_zod" in obj || isZodTypeLike(obj); } -function rotateUnit(vec) { - const padded = padToRotationDim(vec); - const norm = l2Norm(padded); - if (norm > 0) { - const inv = 1 / norm; - for (let i = 0;i < PADDED_DIM; i++) - padded[i] = padded[i] * inv; +function isZodRawShapeCompat(obj) { + if (typeof obj !== "object" || obj === null) { + return false; } - rotateWithSeed(padded, ROTATION_SEED); - return { rotated: padded, norm }; -} -function packSigns(rotated) { - const out = new Uint8Array(SIGN_BYTES); - for (let i = 0;i < EMBED_DIM; i++) { - if (rotated[i] >= 0) { - const byteIdx = i >>> 3; - const bitInByte = 7 - (i & 7); - out[byteIdx] = out[byteIdx] | 1 << bitInByte; - } + if (isZodSchemaInstance(obj)) { + return false; } - return out; -} -function signAt(signs, i) { - const byteIdx = i >>> 3; - const bitInByte = 7 - (i & 7); - return signs[byteIdx] >>> bitInByte & 1 ? 1 : -1; -} -function rabitqEncode(vec) { - const { rotated, norm } = rotateUnit(vec); - const signs = packSigns(rotated); - const invSqrtD = 1 / Math.sqrt(EMBED_DIM); - let align = 0; - for (let i = 0;i < EMBED_DIM; i++) { - const r = rotated[i]; - align += r >= 0 ? r : -r; + if (Object.keys(obj).length === 0) { + return true; } - align *= invSqrtD; - return { - signs, - normFp16: f32ToF16(norm), - alignFp16: f32ToF16(align) - }; + return Object.values(obj).some(isZodTypeLike); } -function packCode(code) { - if (code.signs.length !== SIGN_BYTES) { - throw new Error(`packCode: signs must be ${SIGN_BYTES} bytes, got ${code.signs.length}`); +function getZodSchemaObject(schema) { + if (!schema) { + return; } - const out = new Uint8Array(PACK_SIZE); - out.set(code.signs, 0); - out[NORM_OFFSET] = code.normFp16 & 255; - out[NORM_OFFSET + 1] = code.normFp16 >>> 8 & 255; - out[ALIGN_OFFSET] = code.alignFp16 & 255; - out[ALIGN_OFFSET + 1] = code.alignFp16 >>> 8 & 255; - out[CENTROID_OFFSET] = 0; - out[CENTROID_OFFSET + 1] = 0; - return out; -} -function unpackCode(bytes) { - if (bytes.length !== PACK_SIZE) { - throw new Error(`unpackCode: expected ${PACK_SIZE} bytes, got ${bytes.length}`); + if (isZodRawShapeCompat(schema)) { + return objectFromShape(schema); } - const signs = new Uint8Array(SIGN_BYTES); - signs.set(bytes.subarray(0, SIGN_BYTES)); - const normFp16 = bytes[NORM_OFFSET] | bytes[NORM_OFFSET + 1] << 8; - const alignFp16 = bytes[ALIGN_OFFSET] | bytes[ALIGN_OFFSET + 1] << 8; - return { signs, normFp16, alignFp16 }; + if (!isZodSchemaInstance(schema)) { + throw new Error("inputSchema must be a Zod schema or raw shape, received an unrecognized object"); + } + return schema; } -function rabitqInnerProduct(query, code) { - const { rotated: qRot, norm: qNorm } = rotateUnit(query); - const align = f16ToF32(code.alignFp16); - const vecNorm = f16ToF32(code.normFp16); - if (align === 0 || qNorm === 0 || vecNorm === 0) - return 0; - const invSqrtD = 1 / Math.sqrt(EMBED_DIM); - let dot = 0; - for (let i = 0;i < EMBED_DIM; i++) { - dot += signAt(code.signs, i) * qRot[i]; +function promptArgumentsFromSchema(schema) { + const shape = getObjectShape(schema); + if (!shape) + return []; + return Object.entries(shape).map(([name, field]) => { + const description = getSchemaDescription(field); + const isOptional = isSchemaOptional(field); + return { + name, + description, + required: !isOptional + }; + }); +} +function getMethodValue(schema) { + const shape = getObjectShape(schema); + const methodSchema = shape?.method; + if (!methodSchema) { + throw new Error("Schema is missing a method literal"); } - dot *= invSqrtD; - const unitIp = dot / align; - return unitIp * vecNorm * qNorm; + const value = getLiteralValue(methodSchema); + if (typeof value === "string") { + return value; + } + throw new Error("Schema method literal must be a string"); } - -// src/lib/events.ts -var RING_CAP_PER_TYPE = 200; -var buffers = new Map; -var dispatcher = new EventTarget; -var wrappedListeners = new Set; -var seq = 0; -function publish(event) { - seq += 1; - const envelope = { - id: String(seq), - type: event.type, - event +function createCompletionResult(suggestions) { + return { + completion: { + values: suggestions.slice(0, 100), + total: suggestions.length, + hasMore: suggestions.length > 100 + } }; - const ring = buffers.get(event.type) ?? []; - ring.push(envelope); - if (ring.length > RING_CAP_PER_TYPE) - ring.shift(); - buffers.set(event.type, ring); - dispatcher.dispatchEvent(new CustomEvent("evt", { detail: envelope })); - return envelope; } +var EMPTY_COMPLETION_RESULT = { + completion: { + values: [], + hasMore: false + } +}; -// src/compression/embeddings.ts -init_cortex_config(); -var EMBED_DIM2 = 1536; -var EMBED_FETCH_TIMEOUT_MS = 30000; -var OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings"; -var OPENAI_MODEL = process.env["OPENAI_EMBED_MODEL"] ?? "text-embedding-3-small"; -var OPENROUTER_EMBED_URL = "https://openrouter.ai/api/v1/embeddings"; -var OPENROUTER_MODEL = process.env["OPENROUTER_EMBED_MODEL"] ?? "openai/text-embedding-3-small"; -var VOYAGE_EMBED_URL = "https://api.voyageai.com/v1/embeddings"; -var VOYAGE_MODEL = process.env["VOYAGE_EMBED_MODEL"] ?? "voyage-large-2"; -var COHERE_EMBED_URL = "https://api.cohere.com/v2/embed"; -var COHERE_MODEL = "embed-v4.0"; - -class MissingEmbeddingKeyError extends Error { - isMissingEmbeddingKey = true; - constructor(message) { - super(message); - this.name = "MissingEmbeddingKeyError"; +// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js +import process3 from "process"; + +// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js +class ReadBuffer { + append(chunk) { + this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk; } -} -function isMissingEmbeddingKey(err) { - return err instanceof MissingEmbeddingKeyError || typeof err === "object" && err !== null && "isMissingEmbeddingKey" in err; -} -function isUsableEmbeddingKey(key) { - if (typeof key !== "string") - return false; - const v = key.trim(); - if (v.length < 16) - return false; - if (/\.{2,}|\u2026|placeholder|your[-_]?key/i.test(v)) - return false; - return true; -} -function envEmbeddingKey(name) { - const v = process.env[name]; - return isUsableEmbeddingKey(v) ? v.trim() : undefined; -} -var EMBEDDING_SETUP_MESSAGE = [ - "Cortex needs an embedding API key to turn your notes into searchable memory.", - "", - "Add ONE of these to your environment (your shell profile, or a .env in your project):", - " \u2022 OPENAI_API_KEY=sk-\u2026 \u2190 get one at https://platform.openai.com/api-keys", - " \u2022 OPENROUTER_API_KEY=sk-or-\u2026 \u2190 or https://openrouter.ai/keys", - " \u2022 VOYAGE_API_KEY=\u2026 \u2190 Claude/Anthropic users: Anthropic has no embeddings", - " API, so use Voyage (their recommended partner):", - " https://dashboard.voyageai.com/", - " \u2022 COHERE_API_KEY=\u2026 \u2190 or https://dashboard.cohere.com/api-keys", - "", - "Then restart your session. (Your text is only sent to that provider to embed;", - "the memory itself is encrypted with your wallet and stored on Arkiv.)" -].join(` + readMessage() { + if (!this._buffer) { + return null; + } + const index = this._buffer.indexOf(` `); -function toFloat32(arr, provider) { - if (!Array.isArray(arr)) { - throw new Error(`embedText: unexpected ${provider} response shape`); + if (index === -1) { + return null; + } + const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, ""); + this._buffer = this._buffer.subarray(index + 1); + return deserializeMessage(line); } - if (arr.length !== EMBED_DIM2) { - throw new Error(`embedText: expected ${EMBED_DIM2}-d from ${provider}, got ${arr.length}. ` + `RaBitQ requires exactly ${EMBED_DIM2}-d \u2014 set OPENROUTER_EMBED_MODEL to a 1536-d model.`); + clear() { + this._buffer = undefined; } - const out = new Float32Array(EMBED_DIM2); - for (let i = 0;i < EMBED_DIM2; i++) - out[i] = arr[i]; - return out; } -async function embedViaOpenAI(text, apiKey) { - const res = await fetch(OPENAI_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: OPENAI_MODEL, - input: [text], - dimensions: EMBED_DIM2, - encoding_format: "float" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: OpenAI request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json2 = await res.json(); - const first = json2.data?.[0]?.embedding; - return toFloat32(first, `OpenAI(${OPENAI_MODEL})`); +function deserializeMessage(line) { + return JSONRPCMessageSchema.parse(JSON.parse(line)); } -async function embedViaOpenRouter(text, apiKey) { - const res = await fetch(OPENROUTER_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: OPENROUTER_MODEL, - input: [text], - encoding_format: "float" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: OpenRouter request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); - } - const json2 = await res.json(); - const first = json2.data?.[0]?.embedding; - return toFloat32(first, `OpenRouter(${OPENROUTER_MODEL})`); +function serializeMessage(message) { + return JSON.stringify(message) + ` +`; } -async function embedViaVoyage(text, apiKey) { - const res = await fetch(VOYAGE_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: VOYAGE_MODEL, - input: [text], - input_type: "document" - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: Voyage request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + +// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js +class StdioServerTransport { + constructor(_stdin = process3.stdin, _stdout = process3.stdout) { + this._stdin = _stdin; + this._stdout = _stdout; + this._readBuffer = new ReadBuffer; + this._started = false; + this._ondata = (chunk) => { + this._readBuffer.append(chunk); + this.processReadBuffer(); + }; + this._onerror = (error51) => { + this.onerror?.(error51); + }; } - const json2 = await res.json(); - const first = json2.data?.[0]?.embedding; - return toFloat32(first, `Voyage(${VOYAGE_MODEL})`); -} -async function embedViaCohere(text, apiKey) { - const res = await fetch(COHERE_EMBED_URL, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${apiKey}` - }, - signal: AbortSignal.timeout(EMBED_FETCH_TIMEOUT_MS), - body: JSON.stringify({ - model: COHERE_MODEL, - texts: [text], - input_type: "search_document", - embedding_types: ["float"], - output_dimension: EMBED_DIM2 - }) - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`embedText: Cohere request failed ${res.status} ${res.statusText} \u2014 ${body.slice(0, 500)}`); + async start() { + if (this._started) { + throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically."); + } + this._started = true; + this._stdin.on("data", this._ondata); + this._stdin.on("error", this._onerror); } - const json2 = await res.json(); - const first = json2.embeddings?.float?.[0]; - return toFloat32(first, "Cohere"); -} -async function embedText(text) { - if (typeof text !== "string" || text.length === 0) { - throw new Error("embedText: input text must be a non-empty string"); + processReadBuffer() { + while (true) { + try { + const message = this._readBuffer.readMessage(); + if (message === null) { + break; + } + this.onmessage?.(message); + } catch (error51) { + this.onerror?.(error51); + } + } } - const openAiKey = envEmbeddingKey("OPENAI_API_KEY"); - if (openAiKey) - return embedViaOpenAI(text, openAiKey); - const openRouterKey = envEmbeddingKey("OPENROUTER_API_KEY"); - if (openRouterKey) - return embedViaOpenRouter(text, openRouterKey); - const voyageKey = envEmbeddingKey("VOYAGE_API_KEY"); - if (voyageKey) - return embedViaVoyage(text, voyageKey); - const cohereKey = envEmbeddingKey("COHERE_API_KEY"); - if (cohereKey) - return embedViaCohere(text, cohereKey); - const cfg = readConfig(); - if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { - switch (cfg.embeddingProvider ?? "openai") { - case "openrouter": - return embedViaOpenRouter(text, cfg.embeddingKey); - case "voyage": - return embedViaVoyage(text, cfg.embeddingKey); - case "cohere": - return embedViaCohere(text, cfg.embeddingKey); - case "openai": - default: - return embedViaOpenAI(text, cfg.embeddingKey); + async close() { + this._stdin.off("data", this._ondata); + this._stdin.off("error", this._onerror); + const remainingDataListeners = this._stdin.listenerCount("data"); + if (remainingDataListeners === 0) { + this._stdin.pause(); } + this._readBuffer.clear(); + this.onclose?.(); + } + send(message) { + return new Promise((resolve) => { + const json2 = serializeMessage(message); + if (this._stdout.write(json2)) { + resolve(); + } else { + this._stdout.once("drain", resolve); + } + }); } - throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); } +// node_modules/@arkiv-network/sdk/src/consts.ts +var ARKIV_ADDRESS = "0x00000000000000000000000000000061726b6976"; +var BLOCK_TIME = 2; + +// node_modules/@arkiv-network/sdk/src/utils/payload.ts +init__esm(); +function jsonToPayload(json2) { + return toBytes(JSON.stringify(json2)); +} + +// src/darwinian/recall.ts +init__esm(); +init_embeddings(); +init_rabitq(); + // node_modules/cbor-x/decode.js var decoder2; try { @@ -52277,6 +52338,7 @@ if (!nativeAccelerationDisabled) { } // src/compression/document-payload.ts +init_rabitq(); var DOCUMENT_SCHEMA_VERSION = 1; var EMBED_DIM3 = 1536; function f32ToF16Bytes(vec) { @@ -52361,27 +52423,24 @@ function decodeDocumentPayload(bytes) { // src/darwinian/recall.ts init_constants(); +init_events(); init_crypto(); // src/lib/payload-key.ts init_crypto(); -init_cortex_config(); +init_credentials(); var _cached3; -var SIG_RE2 = /^0x[0-9a-fA-F]+$/; -var PK_RE2 = /^0x[0-9a-fA-F]{64}$/; async function resolveSignature() { - const sig = process.env.CORTEX_USER_SIGNATURE; - if (sig && SIG_RE2.test(sig)) - return sig; - const pk = process.env.CORTEX_USER_PRIVATE_KEY; - if (pk && PK_RE2.test(pk)) { - const account = privateKeyToAccount(pk); + const creds = resolveCredentials(); + if (creds.source.signature === "env") + return creds.userSignature; + if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey); const message = keyDerivationMessage(account.address); return await account.signMessage({ message }); } - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE2.test(cfgSig)) - return cfgSig; + if (creds.source.signature === "config") + return creds.userSignature; return null; } async function getPayloadKey() { @@ -53534,7 +53593,8 @@ function eq(key, value) { // src/lib/arkiv-client.ts init_constants(); -init_cortex_config(); +init_events(); +init_credentials(); var _publicClient; var _walletClient; function getPublicClient() { @@ -53554,7 +53614,7 @@ function getPublicClient() { function getWalletClient() { if (_walletClient) return _walletClient; - const pk = process.env.SESSION_KEY_PRIVATE_KEY ?? readConfig()?.sessionKeyPrivate; + const pk = resolveCredentials().sessionKeyPrivate; if (!pk) { throw new Error("No session key. Run `cortex auth` (connect your wallet) \u2014 or set " + "SESSION_KEY_PRIVATE_KEY and fund the EOA via " + BRAGA.faucet); } @@ -54252,19 +54312,28 @@ async function recall(opts) { } const embed = opts._deps?.embedQuery ?? embedText; const fetchCandidates = opts._deps?.fetchCandidates ?? defaultFetchCandidates; - const queryEmbedding = await embed(opts.query); + let queryEmbedding = null; try { - const t0 = performance.now(); - const packed = packCode(rabitqEncode(queryEmbedding)); - publish({ - type: "rabitq.encoded", - ts: Date.now(), - dim: queryEmbedding.length, - bytes: packed.byteLength, - ratio: queryEmbedding.length * 4 / packed.byteLength, - ms: performance.now() - t0 - }); - } catch {} + queryEmbedding = await embed(opts.query); + } catch (err) { + if (!isMissingEmbeddingKey(err)) + throw err; + queryEmbedding = null; + } + if (queryEmbedding) { + try { + const t0 = performance.now(); + const packed = packCode(rabitqEncode(queryEmbedding)); + publish({ + type: "rabitq.encoded", + ts: Date.now(), + dim: queryEmbedding.length, + bytes: packed.byteLength, + ratio: queryEmbedding.length * 4 / packed.byteLength, + ms: performance.now() - t0 + }); + } catch {} + } const candidates = await fetchCandidates(opts.entityType, opts.project); const payloadKey = await getPayloadKey(); const hits = []; @@ -54295,25 +54364,31 @@ async function recall(opts) { if (raw) { try { const doc2 = decodeDocumentPayload(raw); - let stage1 = 0; - try { - stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc2.code)); - } catch {} - let bestOffset = 0; - for (const s of doc2.sections) { + if (!queryEmbedding) { + score = textOverlapScore(opts.query, doc2.text); + docText = doc2.text; + preview = doc2.text.slice(0, PREVIEW_LIMIT); + } else { + let stage1 = 0; try { - const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); - if (ss > stage1) { - stage1 = ss; - bestOffset = s.offset; - } + stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc2.code)); } catch {} + let bestOffset = 0; + for (const s of doc2.sections) { + try { + const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); + if (ss > stage1) { + stage1 = ss; + bestOffset = s.offset; + } + } catch {} + } + score = cosineF32(queryEmbedding, doc2.rerankEmbedding); + if (!Number.isFinite(score) || score === 0) + score = stage1; + docText = doc2.text; + preview = doc2.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } - score = cosineF32(queryEmbedding, doc2.rerankEmbedding); - if (!Number.isFinite(score) || score === 0) - score = stage1; - docText = doc2.text; - preview = doc2.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } catch { score = 0; } @@ -54334,7 +54409,7 @@ async function recall(opts) { } } } else { - if (raw && raw.length === RABITQ_PACK_SIZE) { + if (queryEmbedding && raw && raw.length === RABITQ_PACK_SIZE) { try { const code = unpackCode(raw); score = rabitqInnerProduct(queryEmbedding, code); @@ -54434,7 +54509,11 @@ async function fetchCandidatesFromArkiv(entityType, project) { })); } +// src/openclaw/adapter.ts +init_embeddings(); + // src/lib/batch-writer.ts +init_events(); init_crypto(); init_constants(); var TIER_BY_ENTITY_TYPE = { @@ -54564,6 +54643,7 @@ ${lines.join(` // src/darwinian/citation.ts init__esm(); init_constants(); +init_events(); function defaultEntityTypeOf(db, entityKey) { const cached2 = db.prepare("SELECT entity_type FROM citation_counts WHERE entity_key = ?").get(entityKey); if (cached2?.entity_type) { @@ -54739,6 +54819,7 @@ function buildCitationPayload(action, citations, scores) { } // src/agent/session-summary.ts +init_embeddings(); async function storeSessionSummary(input) { if (typeof input.summary !== "string" || input.summary.trim().length === 0) { throw new Error("storeSessionSummary: summary must be a non-empty string"); @@ -54759,6 +54840,43 @@ async function storeSessionSummary(input) { }); } +// src/mcp/server.ts +init_embeddings(); +init_credentials(); + +// src/lib/braga-preflight.ts +init_constants(); +function formatBragaError(error51) { + const parts = []; + let cur = error51; + const seen = new Set; + while (cur && !seen.has(cur)) { + seen.add(cur); + if (cur instanceof Error) { + if (cur.message && !parts.includes(cur.message)) + parts.push(cur.message); + const x = cur; + if (x.details && !parts.includes(x.details)) + parts.push(x.details); + if (x.shortMessage && !parts.includes(x.shortMessage)) + parts.push(x.shortMessage); + cur = x.cause; + } else + break; + } + const combined = parts.join(" \u2014 "); + if (/replacement transaction underpriced/i.test(combined)) { + return "Stuck pending Braga tx \u2014 cancel or speed up in your wallet, then retry."; + } + if (/rejected|denied|cancelled/i.test(combined)) { + return "Transaction rejected in wallet."; + } + if (/insufficient|funds|balance|GLM/i.test(combined)) { + return `${combined} ` + `On Braga, GLM is the native gas coin (not an ERC-20 token list entry). ` + `In MetaMask, switch to the Braga network (chain ${BRAGA.chainId}) \u2014 your L3/explorer balance is only spendable there. ` + `Fund: ${BRAGA.faucet}`; + } + return combined || "Braga transaction failed \u2014 switch to Braga testnet and retry."; +} + // src/mcp/server.ts init_constants(); console.log = (...args) => console.error(...args); @@ -54789,20 +54907,20 @@ server.registerTool("cortex_recall", { }); server.registerTool("cortex_act", { title: "Cortex act", - description: "Record a decision and cite the memories that informed it. Each valid " + "citation fires an accumulative lease extension (remaining + reinforcement) " + "so useful memories survive and the rest decay for free. Citations are " + "validated against the most recent cortex_recall in this session.", + description: "Record a decision and cite the memories that informed it. Each valid " + "citation fires an accumulative lease extension (+24h per citation) " + "so useful memories survive and the rest decay for free. Citations are " + "validated against the most recent cortex_recall in this session.", inputSchema: { action: exports_external.string().min(1).describe("The decision/action being taken."), citations: exports_external.array(exports_external.string()).describe("Entity ids from the latest cortex_recall that you used.") } }, async ({ action, citations }) => { - const userPrimaryEOA = process.env.USER_PRIMARY_ADDRESS; + const userPrimaryEOA = resolveCredentials().ownerEOA ?? undefined; if (!userPrimaryEOA) { return { isError: true, content: [ { type: "text", - text: "cortex_act unavailable: USER_PRIMARY_ADDRESS is not set. Cortex needs the owner EOA to attribute tier promotions." + text: "cortex_act unavailable: no owner wallet. Run `cortex auth` (writes your " + "owner address to ~/.cortex/config.json) or set USER_PRIMARY_ADDRESS. " + "Cortex needs the owner EOA to attribute tier promotions." } ] }; @@ -54880,7 +54998,7 @@ ${msg}` }] }; content: [ { type: "text", - text: `cortex_store_document failed: ${msg} + text: `cortex_store_document failed: ${formatBragaError(err)} ` + `(Needs a configured wallet: SESSION_KEY_PRIVATE_KEY for the write + ` + `CORTEX_USER_SIGNATURE or CORTEX_USER_PRIVATE_KEY to derive the seal key, ` + `plus an embedding provider key.)` } ] @@ -54926,7 +55044,7 @@ ${msg}` }] }; } return { isError: true, - content: [{ type: "text", text: `cortex_summarize_session failed: ${msg}` }] + content: [{ type: "text", text: `cortex_summarize_session failed: ${formatBragaError(err)}` }] }; } }); diff --git a/lib/web/hooks/use-connect-wallet.ts b/lib/web/hooks/use-connect-wallet.ts index 02610fc..906741a 100644 --- a/lib/web/hooks/use-connect-wallet.ts +++ b/lib/web/hooks/use-connect-wallet.ts @@ -1,6 +1,6 @@ "use client"; -import { useCallback } from "react"; +import { useCallback, useState } from "react"; import { useConnect, useConnectors } from "wagmi"; import { useAppKit } from "@reown/appkit/react"; import { isWalletConnectConfigured } from "../config"; @@ -13,16 +13,44 @@ function pickInjectedConnector(connectors: ReturnType) { ); } +/** + * Is an injected wallet ACTUALLY present in this browser? A configured `injected` + * connector always exists in wagmi even with no extension installed, so connecting + * to it throws a raw `ProviderNotFoundError`. We detect the real provider first so + * we can show actionable guidance instead — the bug a mobile / no-extension visitor hit. + */ +async function hasInjectedProvider( + connector: { getProvider?: () => Promise } | undefined, +): Promise { + // Fast path: MetaMask / Rabby inject window.ethereum. + if (typeof window !== "undefined" && (window as { ethereum?: unknown }).ethereum) return true; + // EIP-6963 wallets surface a provider via the connector even without window.ethereum. + try { + return !!(await connector?.getProvider?.()); + } catch { + return false; + } +} + +const NO_WALLET_MESSAGE = + "No browser wallet detected. On desktop, install MetaMask or Rabby and refresh. " + + "On mobile, open this page inside your wallet app's in-app browser. " + + "(A free WalletConnect projectId enables QR + mobile connect for everyone — see the README.)"; + export function useConnectWallet() { const { open } = useAppKit(); const { connectAsync, connectors, isPending, error } = useConnect(); + // Our own channel for pre-flight guidance: a thrown error from the click handler + // is void-discarded and never reaches the UI, and wagmi's `error` only covers + // calls that actually reached a connector (i.e. the raw ProviderNotFoundError). + const [localError, setLocalError] = useState(null); const connectBrowserWallet = useCallback(async () => { + setLocalError(null); const injected = pickInjectedConnector(connectors); - if (!injected) { - throw new Error( - "No browser wallet found. Install MetaMask (or another EIP-1193 wallet) and refresh.", - ); + if (!injected || !(await hasInjectedProvider(injected))) { + setLocalError(NO_WALLET_MESSAGE); + return; } await connectAsync({ connector: injected }); }, [connectors, connectAsync]); @@ -44,6 +72,6 @@ export function useConnectWallet() { connectWallet, openWalletModal, isPending, - error: error?.message ?? null, + error: localError ?? error?.message ?? null, }; } diff --git a/scripts/proof-config-only-cite.ts b/scripts/proof-config-only-cite.ts new file mode 100644 index 0000000..27968b7 --- /dev/null +++ b/scripts/proof-config-only-cite.ts @@ -0,0 +1,102 @@ +/** + * Cortex — PROOF: config-only fresh-installer cortex_act on Braga. + * + * Simulates a fresh installer who ran `cortex auth` (so ~/.cortex/config.json holds + * owner + session key + signature + embedding key) but never exported any env var. + * Before the credential-centralization fix, the MCP cortex_act path read the owner + * from process.env.USER_PRIMARY_ADDRESS ONLY and failed here. Now it resolves from + * config. This script proves both: (1) the owner resolves from config, and (2) a + * real accumulative extend fires on Braga. + * + * Cheap by design: it does NOT create entities. It recalls existing memories from + * the local mirror and cites them, firing one extend bundle. + * + * Run: bun scripts/proof-config-only-cite.ts + */ + +// --- Simulate "fresh installer": no owner env var. resolveCredentials() must +// fall back to ~/.cortex/config.json. (Session key may come from either; +// the bug under test was specifically the owner read.) --- +delete process.env.USER_PRIMARY_ADDRESS; +delete process.env.CORTEX_USER_PRIVATE_KEY; + +import type { Hex } from "@arkiv-network/sdk"; +import { resolveCredentials } from "../src/lib/credentials"; +import { recall } from "../src/darwinian/recall"; +import { act } from "../src/darwinian/citation"; +import { drainOutbox } from "../src/agent/anchor-worker"; +import { initMirrorDb } from "../src/mirror/db"; +import { BRAGA } from "../src/constants"; + +const tx = (h: string) => `${BRAGA.explorer}tx/${h}`; + +async function main() { + console.log("\n=== Cortex proof — config-only fresh-installer cortex_act ===\n"); + + // 1. Prove the FIX: owner resolves from ~/.cortex/config.json with env unset. + const creds = resolveCredentials(); + console.log("resolveCredentials().source:", JSON.stringify(creds.source)); + console.log("owner EOA :", creds.ownerEOA); + if (!creds.ownerEOA) { + console.error("\n❌ No owner resolved. Run `cortex auth` to write ~/.cortex/config.json."); + process.exit(1); + } + if (creds.source.owner !== "config") { + console.warn( + `\n⚠️ owner resolved from '${creds.source.owner}', not 'config'. ` + + "An env var is still set — the fresh-installer simulation isn't clean, " + + "but the resolution path is the same.", + ); + } else { + console.log("✅ FIX confirmed: owner came from ~/.cortex/config.json (env was unset).\n"); + } + + // 2. recall existing memories from the local mirror. + const query = "session key ownership and accumulative extend on Arkiv"; + console.log(`[recall] "${query}"`); + const hits = await recall({ query, k: 5 }); + console.log(`[recall] ${hits.length} candidate(s):`); + for (const h of hits.slice(0, 5)) { + console.log(` ${h.entityKey.slice(0, 14)}… type=${h.entityType} score=${h.score.toFixed(4)}`); + } + if (hits.length === 0) { + console.error("\n❌ recall returned nothing — mirror has no citable memories. Seed first (bun run seed)."); + process.exit(3); + } + + // 3. act() — cite the top hits. Owner comes from the fix above. + const citations = hits.slice(0, 2).map((h) => h.entityKey as Hex); + console.log(`\n[act] citing ${citations.length} memory(ies) with config-resolved owner…`); + const db = await initMirrorDb(); + const res = await act({ + action: "PROOF: verify config-only owner resolution fires a real extend", + citations, + userPrimaryEOA: creds.ownerEOA as Hex, + }); + console.log(`[act] status=${res.status} outboxId=${res.outboxId ?? "—"}`); + if (res.status === "noop") { + console.error("\n❌ act() found no valid citation (recall/act mismatch). No extend fired."); + process.exit(3); + } + + // 4. Drain the outbox → real extendEntity tx on Braga. + console.log("\n[drain] flushing the act bundle to Braga (real extendEntity)…"); + const drained = await drainOutbox(db); + const txHashes = drained.flatMap((r) => r.txHashes ?? []); + if (txHashes.length === 0) { + console.error( + "\n❌ Drain produced no tx — the cited memories may be expired on-chain " + + "(Braga auto-deletes expired entities; extend reverts 'no entity'). " + + "Re-seed and retry: bun run seed.", + ); + process.exit(4); + } + console.log("\n✅ Real Braga extend fired. Proof:"); + for (const h of txHashes) console.log(` ${h}\n → ${tx(h)}`); + console.log("\n=== DONE — config-only cortex_act produced a real on-chain extend. ===\n"); +} + +main().catch((err) => { + console.error("\n❌ proof failed:", err instanceof Error ? err.message : err); + process.exit(1); +}); diff --git a/scripts/proof-fresh-extend.ts b/scripts/proof-fresh-extend.ts new file mode 100644 index 0000000..d654b5f --- /dev/null +++ b/scripts/proof-fresh-extend.ts @@ -0,0 +1,97 @@ +/** + * Cortex — PROOF: real accumulative extend on a LIVE Braga entity, config-only. + * + * The companion proof (proof-config-only-cite.ts) showed the owner resolves from + * ~/.cortex/config.json with env unset and act() enqueues — but the mirror's + * memories had expired on-chain so no extend fired. This script closes the loop: + * it creates ONE fresh observation (live, 1h lease) and fires the accumulative + * extend primitive on it, capturing the real extendEntity tx and the + * before/after expiresAtBlock increase. + * + * Run: bun scripts/proof-fresh-extend.ts (spends a little Braga GLM — 2 writes) + */ + +// Fresh-installer simulation: no owner env var → resolveCredentials() falls back +// to ~/.cortex/config.json. +delete process.env.USER_PRIMARY_ADDRESS; +delete process.env.CORTEX_USER_PRIVATE_KEY; + +import { ExpirationTime } from "@arkiv-network/sdk/utils"; +import type { Hex } from "@arkiv-network/sdk"; +import { resolveCredentials } from "../src/lib/credentials"; +import { singleCreate } from "../src/lib/batch-writer"; +import { getPublicClient } from "../src/lib/arkiv-client"; +import { reinforce } from "../src/darwinian/extend"; +import { rabitqEncode, packCode } from "../src/compression/rabitq"; +import { ENTITY_TYPE, BRAGA } from "../src/constants"; + +const tx = (h: string) => `${BRAGA.explorer}tx/${h}`; +const ent = (k: string) => `${BRAGA.explorer}entities/${k}`; + +function synthVector(seed: number): Float32Array { + let s = seed >>> 0; + const v = new Float32Array(1536); + let norm = 0; + for (let i = 0; i < 1536; i++) { + s = (Math.imul(s, 1664525) + 1013904223) >>> 0; + const x = s / 0x1_0000_0000 - 0.5; + v[i] = x; + norm += x * x; + } + const inv = 1 / Math.sqrt(norm); + for (let i = 0; i < 1536; i++) v[i]! *= inv; + return v; +} + +async function main() { + console.log("\n=== Cortex proof — real accumulative extend on a live Braga entity ===\n"); + + const creds = resolveCredentials(); + console.log("resolveCredentials().source:", JSON.stringify(creds.source)); + console.log("owner EOA:", creds.ownerEOA, `(from '${creds.source.owner}')\n`); + + // 1. Create ONE fresh observation (live, 1h lease). + console.log("[create] one fresh observation (1h lease)…"); + const seed = Number(process.hrtime.bigint() % 2_000_000_000n); + const created = await singleCreate({ + payload: packCode(rabitqEncode(synthVector(seed))), + contentType: "application/octet-stream", + attributes: [ + { key: "entityType", value: ENTITY_TYPE.OBSERVATION }, + { key: "marker", value: `proof-extend-${seed}` }, + ], + expiresInSeconds: ExpirationTime.fromMinutes(60), + }); + const entityKey = created.entityKey as Hex; + console.log(` entityKey : ${entityKey}`); + console.log(` create tx : ${created.txHash}`); + console.log(` → ${tx(created.txHash)}`); + console.log(` → ${ent(entityKey)}\n`); + + // 2. Read expiresAtBlock BEFORE the extend. + const before = await getPublicClient().getEntity(entityKey); + console.log(`[before] expiresAtBlock = ${before.expiresAtBlock}`); + + // 3. Fire the accumulative extend (+24h) — the Darwinian reinforcement primitive. + console.log("\n[extend] reinforce(+24h) — real extendEntity on Braga…"); + const extendTx = await reinforce(entityKey, 24 * 60 * 60); + console.log(` extend tx : ${extendTx}`); + console.log(` → ${tx(extendTx)}`); + + // 4. Read expiresAtBlock AFTER — must have increased by ~24h / 2s = 43200 blocks. + const after = await getPublicClient().getEntity(entityKey); + console.log(`\n[after] expiresAtBlock = ${after.expiresAtBlock}`); + const delta = Number((after.expiresAtBlock ?? 0n) - (before.expiresAtBlock ?? 0n)); + console.log(`[delta] +${delta} blocks (~${(delta * 2 / 3600).toFixed(2)} h added)`); + + if (delta <= 0) { + console.error("\n❌ expiresAtBlock did not increase — extend did not take effect."); + process.exit(1); + } + console.log("\n✅ PROOF COMPLETE — config-resolved owner, real on-chain accumulative extend.\n"); +} + +main().catch((err) => { + console.error("\n❌ proof failed:", err instanceof Error ? err.message : err); + process.exit(1); +}); diff --git a/src/agent/owner-identity.ts b/src/agent/owner-identity.ts index 5eacaae..fe19313 100644 --- a/src/agent/owner-identity.ts +++ b/src/agent/owner-identity.ts @@ -13,7 +13,7 @@ import { verifyMessage, type Hex } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { derivePayloadKey } from "../lib/crypto"; import { keyDerivationMessage } from "../lib/derivation-message"; -import { readConfig } from "../lib/cortex-config"; +import { resolveCredentials } from "../lib/credentials"; export type IdentitySource = "env" | "browser" | "none"; @@ -25,29 +25,29 @@ export interface IdentityView { } const ADDR_RE = /^0x[0-9a-fA-F]{40}$/; -const PK_RE = /^0x[0-9a-fA-F]{64}$/; const SIG_RE = /^0x[0-9a-fA-F]+$/; let _cached: IdentityView | null = null; +/** + * Resolve the effective identity from env → ~/.cortex/config.json via the central + * resolveCredentials(). The owner address now falls back to config (it was env-only + * before — the gap that broke fresh installers). Signature precedence mirrors + * payload-key: env signature > env private-key (sign in-process) > config signature. + */ async function resolveFromEnv(): Promise { - const addr = process.env.USER_PRIMARY_ADDRESS; - const ownerAddress: Hex | null = addr && ADDR_RE.test(addr) ? (addr as Hex) : null; + const creds = resolveCredentials(); + const ownerAddress = (creds.ownerEOA as Hex | null) ?? null; let signature: Hex | null = null; - const sigEnv = process.env.CORTEX_USER_SIGNATURE; - if (sigEnv && SIG_RE.test(sigEnv)) { - signature = sigEnv as Hex; - } else { - const pkEnv = process.env.CORTEX_USER_PRIVATE_KEY; - if (pkEnv && PK_RE.test(pkEnv)) { - const account = privateKeyToAccount(pkEnv as Hex); - const message = keyDerivationMessage(account.address); - signature = (await account.signMessage({ message })) as Hex; - } else { - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE.test(cfgSig)) signature = cfgSig as Hex; - } + if (creds.source.signature === "env") { + signature = creds.userSignature as Hex; + } else if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey as Hex); + const message = keyDerivationMessage(account.address); + signature = (await account.signMessage({ message })) as Hex; + } else if (creds.source.signature === "config") { + signature = creds.userSignature as Hex; } const payloadKey = signature ? await derivePayloadKey(signature) : null; diff --git a/src/compression/embeddings.ts b/src/compression/embeddings.ts index 2412c8b..84e1863 100644 --- a/src/compression/embeddings.ts +++ b/src/compression/embeddings.ts @@ -18,7 +18,7 @@ import { packCode, rabitqEncode } from "./rabitq.ts"; import { publish } from "../lib/events.ts"; -import { readConfig } from "../lib/cortex-config.ts"; +import { resolveCredentials } from "../lib/credentials.ts"; const EMBED_DIM = 1536; const EMBED_FETCH_TIMEOUT_MS = 30_000; @@ -71,23 +71,9 @@ export function isUsableEmbeddingKey(key: string | undefined | null): boolean { return true; } -function envEmbeddingKey(name: string): string | undefined { - const v = process.env[name]; - return isUsableEmbeddingKey(v) ? v!.trim() : undefined; -} - /** True if ANY embedding provider key is configured. Lets hooks warn up-front. */ export function hasEmbeddingKey(): boolean { - if ( - envEmbeddingKey("OPENAI_API_KEY") || - envEmbeddingKey("OPENROUTER_API_KEY") || - envEmbeddingKey("VOYAGE_API_KEY") || - envEmbeddingKey("COHERE_API_KEY") - ) { - return true; - } - const cfg = readConfig(); - return isUsableEmbeddingKey(cfg?.embeddingKey); + return resolveCredentials().embedding !== null; } /** The polished, friendly "set your key" message. One place, reused everywhere. */ @@ -241,39 +227,23 @@ export async function embedText(text: string): Promise { if (typeof text !== "string" || text.length === 0) { throw new Error("embedText: input text must be a non-empty string"); } - // Provider order: direct OpenAI (the key most devs have) → OpenRouter → Cohere. - // All return 1536-d, so RaBitQ stays locked and stable. - const openAiKey = envEmbeddingKey("OPENAI_API_KEY"); - if (openAiKey) return embedViaOpenAI(text, openAiKey); - - const openRouterKey = envEmbeddingKey("OPENROUTER_API_KEY"); - if (openRouterKey) return embedViaOpenRouter(text, openRouterKey); + // Provider + key resolved centrally (env order OpenAI → OpenRouter → Voyage → + // Cohere, then the ~/.cortex/config.json key routed to its provider). All + // providers return 1536-d, so RaBitQ stays locked and stable. + const emb = resolveCredentials().embedding; + if (!emb) throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); - // Voyage — the Claude/Anthropic-ecosystem path (Anthropic has no embeddings API). - const voyageKey = envEmbeddingKey("VOYAGE_API_KEY"); - if (voyageKey) return embedViaVoyage(text, voyageKey); - - const cohereKey = envEmbeddingKey("COHERE_API_KEY"); - if (cohereKey) return embedViaCohere(text, cohereKey); - - // Fallback: the key `cortex auth` stored in ~/.cortex/config.json, routed to the - // provider it belongs to. Env always wins above; this only fires when no env key. - const cfg = readConfig(); - if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { - switch (cfg.embeddingProvider ?? "openai") { - case "openrouter": - return embedViaOpenRouter(text, cfg.embeddingKey); - case "voyage": - return embedViaVoyage(text, cfg.embeddingKey); - case "cohere": - return embedViaCohere(text, cfg.embeddingKey); - case "openai": - default: - return embedViaOpenAI(text, cfg.embeddingKey); - } + switch (emb.provider) { + case "openrouter": + return embedViaOpenRouter(text, emb.key); + case "voyage": + return embedViaVoyage(text, emb.key); + case "cohere": + return embedViaCohere(text, emb.key); + case "openai": + default: + return embedViaOpenAI(text, emb.key); } - - throw new MissingEmbeddingKeyError(EMBEDDING_SETUP_MESSAGE); } /** diff --git a/src/darwinian/recall.ts b/src/darwinian/recall.ts index c9d2c52..2887618 100644 --- a/src/darwinian/recall.ts +++ b/src/darwinian/recall.ts @@ -25,7 +25,7 @@ import type { Hex } from "@arkiv-network/sdk"; import { bytesToHex } from "viem"; -import { embedText } from "../compression/embeddings.ts"; +import { embedText, isMissingEmbeddingKey } from "../compression/embeddings.ts"; import { rabitqInnerProduct, unpackCode, rabitqEncode, packCode } from "../compression/rabitq.ts"; import { decodeDocumentPayload } from "../compression/document-payload.ts"; import { ENTITY_TYPE, SEALED_CONTENT_TYPE, UTILITY, WORKSPACE_ATTR } from "../constants.ts"; @@ -270,25 +270,38 @@ export async function recall(opts: RecallOptions): Promise { // Embed once. Rule scoring doesn't need the embedding, but we do it eagerly // because most candidates will be observation/episode in steady state. - const queryEmbedding = await embed(opts.query); + // No embeddings key → degrade to keyword/text-overlap scoring rather than + // throwing, so the plugin stays useful for a fresh installer with no provider + // key (rules + documents still recall by keyword; pure-vector observations + // simply can't match without an embedding). + let queryEmbedding: Float32Array | null = null; + try { + queryEmbedding = await embed(opts.query); + } catch (err) { + if (!isMissingEmbeddingKey(err)) throw err; + queryEmbedding = null; + } // Live spine: the query is RaBitQ-encoded with the same 1-bit codec the // corpus uses (we keep the raw embedding for full-precision scoring, but the // encode is real). This keeps the RaBitQ tile live on every recall, not just // on memory creation. Best-effort — never let instrumentation break recall. - try { - const t0 = performance.now(); - const packed = packCode(rabitqEncode(queryEmbedding)); - publish({ - type: "rabitq.encoded", - ts: Date.now(), - dim: queryEmbedding.length, - bytes: packed.byteLength, - ratio: (queryEmbedding.length * 4) / packed.byteLength, - ms: performance.now() - t0, - }); - } catch { - /* instrumentation only — ignore */ + // Skipped in keyword-only mode (no embedding to encode). + if (queryEmbedding) { + try { + const t0 = performance.now(); + const packed = packCode(rabitqEncode(queryEmbedding)); + publish({ + type: "rabitq.encoded", + ts: Date.now(), + dim: queryEmbedding.length, + bytes: packed.byteLength, + ratio: (queryEmbedding.length * 4) / packed.byteLength, + ms: performance.now() - t0, + }); + } catch { + /* instrumentation only — ignore */ + } } const candidates = await fetchCandidates(opts.entityType, opts.project); @@ -338,30 +351,39 @@ export async function recall(opts: RecallOptions): Promise { if (raw) { try { const doc = decodeDocumentPayload(raw); - // Stage 1: best 1-bit estimate across whole-note + sections. - let stage1 = 0; - try { - stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc.code)); - } catch { - /* ignore */ - } - let bestOffset = 0; - for (const s of doc.sections) { + if (!queryEmbedding) { + // Keyword-only mode (no embeddings key): score the recovered note + // text directly via text overlap. The note is stored losslessly, so + // documents still recall without a provider key. + score = textOverlapScore(opts.query, doc.text); + docText = doc.text; + preview = doc.text.slice(0, PREVIEW_LIMIT); + } else { + // Stage 1: best 1-bit estimate across whole-note + sections. + let stage1 = 0; try { - const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); - if (ss > stage1) { - stage1 = ss; - bestOffset = s.offset; - } + stage1 = rabitqInnerProduct(queryEmbedding, unpackCode(doc.code)); } catch { - /* ignore bad section */ + /* ignore */ + } + let bestOffset = 0; + for (const s of doc.sections) { + try { + const ss = rabitqInnerProduct(queryEmbedding, unpackCode(s.code)); + if (ss > stage1) { + stage1 = ss; + bestOffset = s.offset; + } + } catch { + /* ignore bad section */ + } } + // Stage 2: full-precision cosine rerank (the score we actually use). + score = cosineF32(queryEmbedding, doc.rerankEmbedding); + if (!Number.isFinite(score) || score === 0) score = stage1; + docText = doc.text; + preview = doc.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } - // Stage 2: full-precision cosine rerank (the score we actually use). - score = cosineF32(queryEmbedding, doc.rerankEmbedding); - if (!Number.isFinite(score) || score === 0) score = stage1; - docText = doc.text; - preview = doc.text.slice(bestOffset, bestOffset + PREVIEW_LIMIT); } catch { score = 0; } @@ -384,8 +406,9 @@ export async function recall(opts: RecallOptions): Promise { } } } else { - // observation | episode — RaBitQ packed bytes. - if (raw && raw.length === RABITQ_PACK_SIZE) { + // observation | episode — RaBitQ packed bytes. Need the query embedding; + // in keyword-only mode these have no plaintext to match, so they score 0. + if (queryEmbedding && raw && raw.length === RABITQ_PACK_SIZE) { try { const code = unpackCode(raw); score = rabitqInnerProduct(queryEmbedding, code); diff --git a/src/lib/arkiv-client.ts b/src/lib/arkiv-client.ts index 219e021..9efeebd 100644 --- a/src/lib/arkiv-client.ts +++ b/src/lib/arkiv-client.ts @@ -28,7 +28,7 @@ import type { Attribute } from "@arkiv-network/sdk/types"; import { eq } from "@arkiv-network/sdk/query"; import { PROJECT_ATTRIBUTE, BRAGA } from "../constants"; import { publish, type ArkivRpcMethod } from "./events"; -import { readConfig } from "./cortex-config"; +import { resolveCredentials } from "./credentials"; // --------------------------------------------------------------------------- // Singletons @@ -60,8 +60,9 @@ export function getPublicClient(): PublicArkivClient { export function getWalletClient(): WalletArkivClient { if (_walletClient) return _walletClient; - // env wins; else the session key `cortex auth` generated into ~/.cortex/config.json - const pk = process.env.SESSION_KEY_PRIVATE_KEY ?? readConfig()?.sessionKeyPrivate; + // env wins; else the session key `cortex auth` generated into ~/.cortex/config.json. + // Resolution centralized in resolveCredentials() (already validates 0x+64hex). + const pk = resolveCredentials().sessionKeyPrivate; if (!pk) { throw new Error( "No session key. Run `cortex auth` (connect your wallet) — or set " + @@ -88,6 +89,16 @@ export function getWalletClient(): WalletArkivClient { return _walletClient; } +/** + * Test seam: drop the memoized public + wallet clients so the next access + * re-resolves the session key from env/config. Mirrors `_resetPayloadKey` / + * `_resetOwnerIdentity`. Production code never calls this. + */ +export function _resetArkivClients(): void { + _publicClient = undefined; + _walletClient = undefined; +} + /** The address of the active session-key EOA (the `$creator` for everything we write). */ export function getSessionKeyAddress(): Hex { const account = getWalletClient().account; @@ -121,18 +132,8 @@ function parseEoaAddress(v: string | undefined): Hex | null { /** Resolve $owner from env, cortex auth config, or CORTEX_USER_PRIVATE_KEY. */ function resolveUserPrimaryEOA(): Hex | null { - const fromEnv = parseEoaAddress(process.env.USER_PRIMARY_ADDRESS); - if (fromEnv) return fromEnv; - - const fromConfig = parseEoaAddress(readConfig()?.ownerAddress); - if (fromConfig) return fromConfig; - - const pk = process.env.CORTEX_USER_PRIVATE_KEY; - if (pk && /^0x[0-9a-fA-F]{64}$/.test(pk)) { - return privateKeyToAccount(pk as Hex).address; - } - - return null; + // Centralized in resolveCredentials() (env → config → derive from primary key). + return (resolveCredentials().ownerEOA as Hex | null) ?? null; } export function getUserPrimaryEOA(): Hex { diff --git a/src/lib/credentials.ts b/src/lib/credentials.ts new file mode 100644 index 0000000..2568e2d --- /dev/null +++ b/src/lib/credentials.ts @@ -0,0 +1,148 @@ +/** + * Cortex — single source of truth for credential resolution. + * + * Every secret Cortex consumes (session key, owner EOA, encryption signature, + * embedding key) resolves the SAME way: environment variable first, then the + * `~/.cortex/config.json` that `cortex auth` writes. This module centralizes that + * precedence so a fresh installer who ran `cortex auth` gets a working plugin + * without exporting a single env var — and so the rule lives in one place instead + * of being re-implemented (inconsistently) across arkiv-client, payload-key, + * embeddings, owner-identity, and the MCP server. + * + * Design constraints (do not break): + * - PURE and SYNCHRONOUS. No network, no message signing, no key derivation. + * Returns RAW material; the async layers (signing a derivation message with + * CORTEX_USER_PRIVATE_KEY, deriving the AES key, browser adoption) stay in + * their existing modules and call this underneath. + * - Precedence is ALWAYS env → config. This matches every currently-working path; + * the only new behavior is owner falling back to config where it didn't before. + * - The `source` map records where each credential came from, for honest + * "what's missing / where it resolved" diagnostics. + */ + +import { privateKeyToAccount } from "viem/accounts"; +import { isUsableEmbeddingKey } from "../compression/embeddings.ts"; +import { readConfig, type EmbeddingProvider } from "./cortex-config.ts"; + +export type CredSource = "env" | "config" | "derived" | "none"; + +export interface ResolvedCredentials { + /** Session-key private key ($creator / Arkiv write signer). 0x + 64 hex. */ + sessionKeyPrivate: string | null; + /** Owner EOA ($owner). Validated 0x + 40 hex (derived from CORTEX_USER_PRIVATE_KEY if needed). */ + ownerEOA: string | null; + /** EIP-191 signature of the key-derivation message (seeds the encryption key). */ + userSignature: string | null; + /** Dev-convenience primary private key (used to derive owner + sign in-process). 0x + 64 hex. */ + userPrivateKey: string | null; + /** Embedding provider key + which provider it belongs to. */ + embedding: { key: string; provider: EmbeddingProvider } | null; + /** Where each credential resolved from — for diagnostics, not control flow. */ + source: { + sessionKey: CredSource; + owner: CredSource; + signature: CredSource; + embedding: CredSource; + }; +} + +const EOA_RE = /^0x[0-9a-fA-F]{40}$/; +const PK_RE = /^0x[0-9a-fA-F]{64}$/; +const SIG_RE = /^0x[0-9a-fA-F]+$/; + +function validPk(v: string | undefined | null): string | null { + return typeof v === "string" && PK_RE.test(v) ? v : null; +} +function validEoa(v: string | undefined | null): string | null { + return typeof v === "string" && EOA_RE.test(v) ? v : null; +} +function validSig(v: string | undefined | null): string | null { + return typeof v === "string" && SIG_RE.test(v) ? v : null; +} + +/** Derive the owner address from a primary private key (the rare derive path). */ +function deriveAddressFromPk(pk: string): string | null { + try { + return privateKeyToAccount(pk as `0x${string}`).address; + } catch { + return null; + } +} + +/** Resolve the embedding key from env (provider order) then config. */ +function resolveEmbedding(): { value: { key: string; provider: EmbeddingProvider } | null; source: CredSource } { + const envProviders: Array<[string, EmbeddingProvider]> = [ + ["OPENAI_API_KEY", "openai"], + ["OPENROUTER_API_KEY", "openrouter"], + ["VOYAGE_API_KEY", "voyage"], + ["COHERE_API_KEY", "cohere"], + ]; + for (const [envName, provider] of envProviders) { + const v = process.env[envName]; + if (isUsableEmbeddingKey(v)) return { value: { key: v!.trim(), provider }, source: "env" }; + } + const cfg = readConfig(); + if (cfg?.embeddingKey && isUsableEmbeddingKey(cfg.embeddingKey)) { + // Default to "openai" when a key is present without an explicit provider, + // matching embeddings.ts embedText() (`cfg.embeddingProvider ?? "openai"`). + return { + value: { key: cfg.embeddingKey.trim(), provider: cfg.embeddingProvider ?? "openai" }, + source: "config", + }; + } + return { value: null, source: "none" }; +} + +/** + * Resolve every Cortex credential from env → `~/.cortex/config.json`, with a + * `source` map. Pure + synchronous. Returns raw material; callers do their own + * async derivation/signing. + */ +export function resolveCredentials(): ResolvedCredentials { + const cfg = readConfig(); + + // Session key: env → config. + const skEnv = validPk(process.env.SESSION_KEY_PRIVATE_KEY); + const skCfg = validPk(cfg?.sessionKeyPrivate); + const sessionKeyPrivate = skEnv ?? skCfg; + const sessionKeySource: CredSource = skEnv ? "env" : skCfg ? "config" : "none"; + + // Dev primary private key (env only). + const userPrivateKey = validPk(process.env.CORTEX_USER_PRIVATE_KEY); + + // Owner EOA: env addr → config addr → derive from primary private key. + const ownerEnv = validEoa(process.env.USER_PRIMARY_ADDRESS); + const ownerCfg = validEoa(cfg?.ownerAddress); + let ownerEOA: string | null = ownerEnv ?? ownerCfg; + let ownerSource: CredSource = ownerEnv ? "env" : ownerCfg ? "config" : "none"; + if (!ownerEOA && userPrivateKey) { + const derived = deriveAddressFromPk(userPrivateKey); + if (derived) { + ownerEOA = derived; + ownerSource = "derived"; + } + } + + // Encryption signature: env → config. + const sigEnv = validSig(process.env.CORTEX_USER_SIGNATURE); + const sigCfg = validSig(cfg?.userSignature); + const userSignature = sigEnv ?? sigCfg; + const signatureSource: CredSource = sigEnv ? "env" : sigCfg ? "config" : "none"; + + // Embedding key: env (provider order) → config. + const emb = resolveEmbedding(); + + return { + sessionKeyPrivate, + ownerEOA, + userSignature, + userPrivateKey, + embedding: emb.value, + source: { + sessionKey: sessionKeySource, + owner: ownerSource, + signature: signatureSource, + embedding: emb.source, + }, + }; +} diff --git a/src/lib/payload-key.ts b/src/lib/payload-key.ts index 8738ee7..768741f 100644 --- a/src/lib/payload-key.ts +++ b/src/lib/payload-key.ts @@ -23,28 +23,27 @@ import type { Hex } from "@arkiv-network/sdk"; import { privateKeyToAccount } from "@arkiv-network/sdk/accounts"; import { derivePayloadKey, keyDerivationMessage } from "./crypto.ts"; -import { readConfig } from "./cortex-config.ts"; +import { resolveCredentials } from "./credentials.ts"; // `undefined` = not yet resolved; `null` = resolved, no wallet material. let _cached: CryptoKey | null | undefined; -const SIG_RE = /^0x[0-9a-fA-F]+$/; -const PK_RE = /^0x[0-9a-fA-F]{64}$/; - async function resolveSignature(): Promise { - const sig = process.env.CORTEX_USER_SIGNATURE; - if (sig && SIG_RE.test(sig)) return sig as Hex; + const creds = resolveCredentials(); + + // Precedence preserved: env signature > env private-key (sign in-process) > config signature. + // 1. Explicit signature from env — the fresh-machine "Proof of Sovereignty" path. + if (creds.source.signature === "env") return creds.userSignature as Hex; - const pk = process.env.CORTEX_USER_PRIVATE_KEY; - if (pk && PK_RE.test(pk)) { - const account = privateKeyToAccount(pk as Hex); + // 2. Dev convenience: sign the derivation message with the primary private key. + if (creds.userPrivateKey) { + const account = privateKeyToAccount(creds.userPrivateKey as Hex); const message = keyDerivationMessage(account.address); return (await account.signMessage({ message })) as Hex; } - // Fallback: the signature `cortex auth` captured into ~/.cortex/config.json. - const cfgSig = readConfig()?.userSignature; - if (cfgSig && SIG_RE.test(cfgSig)) return cfgSig as Hex; + // 3. Signature `cortex auth` captured into ~/.cortex/config.json. + if (creds.source.signature === "config") return creds.userSignature as Hex; return null; } diff --git a/src/mcp/server.ts b/src/mcp/server.ts index 38e6f96..e3f1ce4 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -38,6 +38,8 @@ import { act } from "../darwinian/citation.ts"; import { createDocumentMemory } from "../lib/batch-writer.ts"; import { storeSessionSummary } from "../agent/session-summary.ts"; import { embedText, isMissingEmbeddingKey } from "../compression/embeddings.ts"; +import { resolveCredentials } from "../lib/credentials.ts"; +import { formatBragaError } from "../lib/braga-preflight.ts"; import { BRAGA } from "../constants.ts"; const VERSION = "0.1.0"; @@ -99,7 +101,7 @@ server.registerTool( title: "Cortex act", description: "Record a decision and cite the memories that informed it. Each valid " + - "citation fires an accumulative lease extension (remaining + reinforcement) " + + "citation fires an accumulative lease extension (+24h per citation) " + "so useful memories survive and the rest decay for free. Citations are " + "validated against the most recent cortex_recall in this session.", inputSchema: { @@ -110,14 +112,19 @@ server.registerTool( }, }, async ({ action, citations }) => { - const userPrimaryEOA = process.env.USER_PRIMARY_ADDRESS as Hex | undefined; + // Owner EOA resolves env → ~/.cortex/config.json (written by `cortex auth`). + // Previously env-only, which broke cortex_act for every fresh installer. + const userPrimaryEOA = (resolveCredentials().ownerEOA ?? undefined) as Hex | undefined; if (!userPrimaryEOA) { return { isError: true, content: [ { type: "text" as const, - text: "cortex_act unavailable: USER_PRIMARY_ADDRESS is not set. Cortex needs the owner EOA to attribute tier promotions.", + text: + "cortex_act unavailable: no owner wallet. Run `cortex auth` (writes your " + + "owner address to ~/.cortex/config.json) or set USER_PRIMARY_ADDRESS. " + + "Cortex needs the owner EOA to attribute tier promotions.", }, ], }; @@ -220,8 +227,10 @@ server.registerTool( content: [ { type: "text" as const, + // Route through formatBragaError so an unfunded session key surfaces the + // Braga faucet link + network hint instead of a raw revert string. text: - `cortex_store_document failed: ${msg}\n` + + `cortex_store_document failed: ${formatBragaError(err)}\n` + `(Needs a configured wallet: SESSION_KEY_PRIVATE_KEY for the write + ` + `CORTEX_USER_SIGNATURE or CORTEX_USER_PRIVATE_KEY to derive the seal key, ` + `plus an embedding provider key.)`, @@ -282,7 +291,7 @@ server.registerTool( } return { isError: true, - content: [{ type: "text" as const, text: `cortex_summarize_session failed: ${msg}` }], + content: [{ type: "text" as const, text: `cortex_summarize_session failed: ${formatBragaError(err)}` }], }; } }, diff --git a/tests/cortex-auth-config.test.ts b/tests/cortex-auth-config.test.ts index dc2330e..19e6623 100644 --- a/tests/cortex-auth-config.test.ts +++ b/tests/cortex-auth-config.test.ts @@ -110,7 +110,8 @@ test("env→config fallback: hasEmbeddingKey true from config", async () => { const { writeConfig, _resetConfigCache } = await import("../src/lib/cortex-config.ts"); const { hasEmbeddingKey } = await import("../src/compression/embeddings.ts"); expect(hasEmbeddingKey()).toBe(false); // nothing set yet - writeConfig({ embeddingKey: "sk-x", embeddingProvider: "openai" }); + // Key must be ≥16 chars and not a placeholder to pass isUsableEmbeddingKey. + writeConfig({ embeddingKey: "sk-test-abcdef0123456789", embeddingProvider: "openai" }); _resetConfigCache(); expect(hasEmbeddingKey()).toBe(true); }); diff --git a/tests/credentials-characterization.test.ts b/tests/credentials-characterization.test.ts new file mode 100644 index 0000000..0e95a0d --- /dev/null +++ b/tests/credentials-characterization.test.ts @@ -0,0 +1,217 @@ +/** + * Cortex — CHARACTERIZATION tests for credential resolution. + * + * These lock the CURRENT (pre-refactor) behavior of how each credential resolves + * from env vs. ~/.cortex/config.json, so the `resolveCredentials()` centralization + * cannot silently change a working path. Precedence everywhere is env → config. + * + * Two CURRENT GAPS are captured here as explicit assertions and flagged: + * - owner-identity `getEffective().ownerAddress` is env-only (no config fallback) + * - (the MCP server's owner read is also env-only — covered in the MCP test) + * These two assertions are FLIPPED by Task 6 / Task 7 once the gaps are fixed. + * + * Hermetic: CORTEX_CONFIG_PATH points at an empty temp dir; all credential env + * vars are cleared in beforeEach and restored in afterEach. + */ + +import { test, expect, beforeEach, afterEach, describe } from "bun:test"; +import { join } from "node:path"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; +import { keyDerivationMessage } from "../src/lib/crypto.ts"; + +const CRED_ENVS = [ + "USER_PRIMARY_ADDRESS", + "SESSION_KEY_PRIVATE_KEY", + "CORTEX_USER_SIGNATURE", + "CORTEX_USER_PRIVATE_KEY", + "OPENAI_API_KEY", + "OPENROUTER_API_KEY", + "VOYAGE_API_KEY", + "COHERE_API_KEY", +]; + +let dir: string; +const SAVED: Record = {}; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "cortex-cred-")); + SAVED.CORTEX_CONFIG_PATH = process.env.CORTEX_CONFIG_PATH; + process.env.CORTEX_CONFIG_PATH = join(dir, "config.json"); // absent until writeConfig + for (const k of CRED_ENVS) { + SAVED[k] = process.env[k]; + delete process.env[k]; + } +}); + +// Drop the memoized wallet client between tests so session-key resolution +// re-reads env/config (getWalletClient caches the first-resolved key). +async function freshArkivClients() { + (await import("../src/lib/arkiv-client.ts"))._resetArkivClients(); +} + +afterEach(() => { + if (SAVED.CORTEX_CONFIG_PATH === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = SAVED.CORTEX_CONFIG_PATH; + for (const k of CRED_ENVS) { + if (SAVED[k] === undefined) delete process.env[k]; + else process.env[k] = SAVED[k]!; + } + rmSync(dir, { recursive: true, force: true }); +}); + +const OWNER_ENV = "0x1111111111111111111111111111111111111111"; +const OWNER_CFG = "0x2222222222222222222222222222222222222222"; +const SK_ENV = ("0x" + "11".repeat(32)); +const SK_CFG = ("0x" + "22".repeat(32)); + +async function freshConfig() { + const m = await import("../src/lib/cortex-config.ts"); + m._resetConfigCache(); + return m; +} + +describe("owner resolution via arkiv-client.getUserPrimaryEOA (already has config fallback)", () => { + test("env wins over config", async () => { + process.env.USER_PRIMARY_ADDRESS = OWNER_ENV; + const { writeConfig } = await freshConfig(); + writeConfig({ ownerAddress: OWNER_CFG }); + (await freshConfig())._resetConfigCache(); + const { getUserPrimaryEOA } = await import("../src/lib/arkiv-client.ts"); + expect(getUserPrimaryEOA().toLowerCase()).toBe(OWNER_ENV); + }); + + test("falls back to config when env unset", async () => { + const { writeConfig } = await freshConfig(); + writeConfig({ ownerAddress: OWNER_CFG }); + (await freshConfig())._resetConfigCache(); + const { getUserPrimaryEOA } = await import("../src/lib/arkiv-client.ts"); + expect(getUserPrimaryEOA().toLowerCase()).toBe(OWNER_CFG); + }); + + test("derives from CORTEX_USER_PRIVATE_KEY when neither env addr nor config", async () => { + const pk = generatePrivateKey(); + const expected = privateKeyToAccount(pk).address.toLowerCase(); + process.env.CORTEX_USER_PRIVATE_KEY = pk; + await freshConfig(); + const { getUserPrimaryEOA } = await import("../src/lib/arkiv-client.ts"); + expect(getUserPrimaryEOA().toLowerCase()).toBe(expected); + }); + + test("throws when nothing resolves", async () => { + await freshConfig(); + const { getUserPrimaryEOA } = await import("../src/lib/arkiv-client.ts"); + expect(() => getUserPrimaryEOA()).toThrow(); + }); +}); + +describe("owner resolution via owner-identity.getEffective (CURRENT GAP: env-only)", () => { + test("resolves owner from env", async () => { + process.env.USER_PRIMARY_ADDRESS = OWNER_ENV; + const { _resetOwnerIdentity, getEffective } = await import("../src/agent/owner-identity.ts"); + _resetOwnerIdentity(); + expect((await getEffective()).ownerAddress?.toLowerCase()).toBe(OWNER_ENV); + _resetOwnerIdentity(); + }); + + test("FIXED (Task 6): ownerAddress falls back to config when env unset", async () => { + const { writeConfig } = await freshConfig(); + writeConfig({ ownerAddress: OWNER_CFG }); + (await freshConfig())._resetConfigCache(); + const { _resetOwnerIdentity, getEffective } = await import("../src/agent/owner-identity.ts"); + _resetOwnerIdentity(); + // Task 6: owner address now resolves from ~/.cortex/config.json. + expect((await getEffective()).ownerAddress?.toLowerCase()).toBe(OWNER_CFG); + _resetOwnerIdentity(); + }); +}); + +describe("session key resolution via arkiv-client.getWalletClient", () => { + test("env wins over config", async () => { + process.env.SESSION_KEY_PRIVATE_KEY = SK_ENV; + const { writeConfig } = await freshConfig(); + writeConfig({ sessionKeyPrivate: SK_CFG }); + (await freshConfig())._resetConfigCache(); + await freshArkivClients(); + const { getSessionKeyAddress } = await import("../src/lib/arkiv-client.ts"); + const envAddr = privateKeyToAccount(SK_ENV as `0x${string}`).address.toLowerCase(); + expect(getSessionKeyAddress().toLowerCase()).toBe(envAddr); + }); + + test("falls back to config when env unset", async () => { + const { writeConfig } = await freshConfig(); + writeConfig({ sessionKeyPrivate: SK_CFG }); + (await freshConfig())._resetConfigCache(); + await freshArkivClients(); + const { getSessionKeyAddress } = await import("../src/lib/arkiv-client.ts"); + const cfgAddr = privateKeyToAccount(SK_CFG as `0x${string}`).address.toLowerCase(); + expect(getSessionKeyAddress().toLowerCase()).toBe(cfgAddr); + }); +}); + +describe("signature resolution via payload-key.getPayloadKey", () => { + test("env CORTEX_USER_SIGNATURE yields a key", async () => { + const account = privateKeyToAccount(generatePrivateKey()); + const sig = await account.signMessage({ message: keyDerivationMessage(account.address) }); + process.env.CORTEX_USER_SIGNATURE = sig; + const { _resetOwnerIdentity } = await import("../src/agent/owner-identity.ts"); + _resetOwnerIdentity(); + const { getPayloadKey, _resetPayloadKey } = await import("../src/lib/payload-key.ts"); + _resetPayloadKey(); + expect(await getPayloadKey()).not.toBeNull(); + _resetPayloadKey(); + _resetOwnerIdentity(); + }); + + test("falls back to config.userSignature when env unset", async () => { + const account = privateKeyToAccount(generatePrivateKey()); + const sig = await account.signMessage({ message: keyDerivationMessage(account.address) }); + const { writeConfig } = await freshConfig(); + writeConfig({ userSignature: sig }); + (await freshConfig())._resetConfigCache(); + const { _resetOwnerIdentity } = await import("../src/agent/owner-identity.ts"); + _resetOwnerIdentity(); + const { getPayloadKey, _resetPayloadKey } = await import("../src/lib/payload-key.ts"); + _resetPayloadKey(); + expect(await getPayloadKey()).not.toBeNull(); + _resetPayloadKey(); + _resetOwnerIdentity(); + }); + + test("null when no signature anywhere", async () => { + await freshConfig(); + const { _resetOwnerIdentity } = await import("../src/agent/owner-identity.ts"); + _resetOwnerIdentity(); + const { getPayloadKey, _resetPayloadKey } = await import("../src/lib/payload-key.ts"); + _resetPayloadKey(); + expect(await getPayloadKey()).toBeNull(); + _resetPayloadKey(); + _resetOwnerIdentity(); + }); +}); + +describe("embeddings resolution via embeddings.hasEmbeddingKey", () => { + const GOOD = "sk-test-abcdef0123456789"; // ≥16 chars, not a placeholder + + test("false when nothing set", async () => { + await freshConfig(); + const { hasEmbeddingKey } = await import("../src/compression/embeddings.ts"); + expect(hasEmbeddingKey()).toBe(false); + }); + + test("true from env (any provider)", async () => { + process.env.OPENROUTER_API_KEY = GOOD; + await freshConfig(); + const { hasEmbeddingKey } = await import("../src/compression/embeddings.ts"); + expect(hasEmbeddingKey()).toBe(true); + }); + + test("falls back to config.embeddingKey", async () => { + const { writeConfig } = await freshConfig(); + writeConfig({ embeddingKey: GOOD, embeddingProvider: "openai" }); + (await freshConfig())._resetConfigCache(); + const { hasEmbeddingKey } = await import("../src/compression/embeddings.ts"); + expect(hasEmbeddingKey()).toBe(true); + }); +}); diff --git a/tests/credentials.test.ts b/tests/credentials.test.ts new file mode 100644 index 0000000..11d33f8 --- /dev/null +++ b/tests/credentials.test.ts @@ -0,0 +1,168 @@ +/** + * Cortex — unit tests for resolveCredentials() (the centralized resolver). + * + * Verifies env → config precedence + the `source` map for every credential, + * including the owner-from-config fallback that the scattered call sites lacked. + * Hermetic: empty temp CORTEX_CONFIG_PATH, all credential env vars cleared. + */ + +import { test, expect, beforeEach, afterEach, describe } from "bun:test"; +import { join } from "node:path"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; + +const CRED_ENVS = [ + "USER_PRIMARY_ADDRESS", + "SESSION_KEY_PRIVATE_KEY", + "CORTEX_USER_SIGNATURE", + "CORTEX_USER_PRIVATE_KEY", + "OPENAI_API_KEY", + "OPENROUTER_API_KEY", + "VOYAGE_API_KEY", + "COHERE_API_KEY", +]; +let dir: string; +const SAVED: Record = {}; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "cortex-rc-")); + SAVED.CORTEX_CONFIG_PATH = process.env.CORTEX_CONFIG_PATH; + process.env.CORTEX_CONFIG_PATH = join(dir, "config.json"); + for (const k of CRED_ENVS) { + SAVED[k] = process.env[k]; + delete process.env[k]; + } +}); +afterEach(() => { + if (SAVED.CORTEX_CONFIG_PATH === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = SAVED.CORTEX_CONFIG_PATH; + for (const k of CRED_ENVS) { + if (SAVED[k] === undefined) delete process.env[k]; + else process.env[k] = SAVED[k]!; + } + rmSync(dir, { recursive: true, force: true }); +}); + +async function withConfig(cfg: Record) { + const m = await import("../src/lib/cortex-config.ts"); + m._resetConfigCache(); + if (Object.keys(cfg).length) m.writeConfig(cfg as never); + m._resetConfigCache(); +} +async function resolve() { + (await import("../src/lib/cortex-config.ts"))._resetConfigCache(); + return (await import("../src/lib/credentials.ts")).resolveCredentials(); +} + +const OWNER_ENV = "0x1111111111111111111111111111111111111111"; +const OWNER_CFG = "0x2222222222222222222222222222222222222222"; +const SK_ENV = "0x" + "11".repeat(32); +const SK_CFG = "0x" + "22".repeat(32); +const GOOD_EMB = "sk-test-abcdef0123456789"; + +describe("everything empty", () => { + test("all null, all source 'none'", async () => { + await withConfig({}); + const c = await resolve(); + expect(c.sessionKeyPrivate).toBeNull(); + expect(c.ownerEOA).toBeNull(); + expect(c.userSignature).toBeNull(); + expect(c.embedding).toBeNull(); + expect(c.source).toEqual({ sessionKey: "none", owner: "none", signature: "none", embedding: "none" }); + }); +}); + +describe("session key", () => { + test("env wins, source env", async () => { + process.env.SESSION_KEY_PRIVATE_KEY = SK_ENV; + await withConfig({ sessionKeyPrivate: SK_CFG }); + const c = await resolve(); + expect(c.sessionKeyPrivate).toBe(SK_ENV); + expect(c.source.sessionKey).toBe("env"); + }); + test("config fallback, source config", async () => { + await withConfig({ sessionKeyPrivate: SK_CFG }); + const c = await resolve(); + expect(c.sessionKeyPrivate).toBe(SK_CFG); + expect(c.source.sessionKey).toBe("config"); + }); + test("malformed env ignored", async () => { + process.env.SESSION_KEY_PRIVATE_KEY = "0xnothex"; + await withConfig({ sessionKeyPrivate: SK_CFG }); + const c = await resolve(); + expect(c.sessionKeyPrivate).toBe(SK_CFG); + expect(c.source.sessionKey).toBe("config"); + }); +}); + +describe("owner EOA", () => { + test("env wins, source env", async () => { + process.env.USER_PRIMARY_ADDRESS = OWNER_ENV; + await withConfig({ ownerAddress: OWNER_CFG }); + const c = await resolve(); + expect(c.ownerEOA?.toLowerCase()).toBe(OWNER_ENV); + expect(c.source.owner).toBe("env"); + }); + test("config fallback (THE FIX), source config", async () => { + await withConfig({ ownerAddress: OWNER_CFG }); + const c = await resolve(); + expect(c.ownerEOA?.toLowerCase()).toBe(OWNER_CFG); + expect(c.source.owner).toBe("config"); + }); + test("derived from CORTEX_USER_PRIVATE_KEY, source derived", async () => { + const pk = generatePrivateKey(); + const expected = privateKeyToAccount(pk).address.toLowerCase(); + process.env.CORTEX_USER_PRIVATE_KEY = pk; + await withConfig({}); + const c = await resolve(); + expect(c.ownerEOA?.toLowerCase()).toBe(expected); + expect(c.source.owner).toBe("derived"); + expect(c.userPrivateKey).toBe(pk); + }); +}); + +describe("signature", () => { + test("env wins, source env", async () => { + process.env.CORTEX_USER_SIGNATURE = "0xdeadbeef"; + await withConfig({ userSignature: "0xabcabc" }); + const c = await resolve(); + expect(c.userSignature).toBe("0xdeadbeef"); + expect(c.source.signature).toBe("env"); + }); + test("config fallback, source config", async () => { + await withConfig({ userSignature: "0xabcabc" }); + const c = await resolve(); + expect(c.userSignature).toBe("0xabcabc"); + expect(c.source.signature).toBe("config"); + }); +}); + +describe("embedding", () => { + test("env provider order: OpenAI before OpenRouter", async () => { + process.env.OPENAI_API_KEY = GOOD_EMB; + process.env.OPENROUTER_API_KEY = GOOD_EMB + "xx"; + await withConfig({}); + const c = await resolve(); + expect(c.embedding).toEqual({ key: GOOD_EMB, provider: "openai" }); + expect(c.source.embedding).toBe("env"); + }); + test("config fallback uses its provider", async () => { + await withConfig({ embeddingKey: GOOD_EMB, embeddingProvider: "cohere" }); + const c = await resolve(); + expect(c.embedding).toEqual({ key: GOOD_EMB, provider: "cohere" }); + expect(c.source.embedding).toBe("config"); + }); + test("config without provider defaults to openai (matches embedText)", async () => { + await withConfig({ embeddingKey: GOOD_EMB }); + const c = await resolve(); + expect(c.embedding).toEqual({ key: GOOD_EMB, provider: "openai" }); + }); + test("placeholder/too-short key rejected", async () => { + process.env.OPENAI_API_KEY = "sk-x"; // < 16 chars + await withConfig({}); + const c = await resolve(); + expect(c.embedding).toBeNull(); + expect(c.source.embedding).toBe("none"); + }); +}); diff --git a/tests/dashboard.test.ts b/tests/dashboard.test.ts index 9f921f4..7d81818 100644 --- a/tests/dashboard.test.ts +++ b/tests/dashboard.test.ts @@ -305,12 +305,18 @@ test("POST /api/auth/adopt 401 without SIWE cookie", async () => { test("GET /api/auth/me returns source 'none' when nothing set", async () => { const { _resetOwnerIdentity } = await import("../src/agent/owner-identity"); + const { _resetConfigCache } = await import("../src/lib/cortex-config"); const savedUser = process.env.USER_PRIMARY_ADDRESS; const savedSig = process.env.CORTEX_USER_SIGNATURE; const savedPk = process.env.CORTEX_USER_PRIVATE_KEY; + const savedCfg = process.env.CORTEX_CONFIG_PATH; delete process.env.USER_PRIMARY_ADDRESS; delete process.env.CORTEX_USER_SIGNATURE; delete process.env.CORTEX_USER_PRIVATE_KEY; + // Hermetic: point config at an absent path so readConfig() doesn't resolve the + // owner from the dev's real ~/.cortex/config.json (now a config fallback). + process.env.CORTEX_CONFIG_PATH = "/nonexistent/cortex-auth-me-none/config.json"; + _resetConfigCache(); _resetOwnerIdentity(); const { handleAuthMe } = await import("../src/api/auth-adopt"); const res = await handleAuthMe(new Request("http://localhost/api/auth/me")); @@ -321,5 +327,8 @@ test("GET /api/auth/me returns source 'none' when nothing set", async () => { if (savedUser !== undefined) process.env.USER_PRIMARY_ADDRESS = savedUser; if (savedSig !== undefined) process.env.CORTEX_USER_SIGNATURE = savedSig; if (savedPk !== undefined) process.env.CORTEX_USER_PRIVATE_KEY = savedPk; + if (savedCfg === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = savedCfg; + _resetConfigCache(); _resetOwnerIdentity(); }); diff --git a/tests/owner-identity.test.ts b/tests/owner-identity.test.ts index 0075b4a..2722377 100644 --- a/tests/owner-identity.test.ts +++ b/tests/owner-identity.test.ts @@ -6,6 +6,9 @@ */ import { test, expect, beforeEach, afterEach } from "bun:test"; +import { join } from "node:path"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; import { privateKeyToAccount } from "viem/accounts"; import type { Hex } from "@arkiv-network/sdk"; import { @@ -13,6 +16,7 @@ import { getEffective, _resetOwnerIdentity, } from "../src/agent/owner-identity"; +import { _resetConfigCache } from "../src/lib/cortex-config"; import { keyDerivationMessage } from "../src/lib/derivation-message"; const PK_A = ("0x" + "11".repeat(32)) as Hex; @@ -27,17 +31,30 @@ const SAVED_ENV = { CORTEX_USER_PRIVATE_KEY: process.env.CORTEX_USER_PRIVATE_KEY, }; +// Hermetic config: point CORTEX_CONFIG_PATH at an empty temp dir so readConfig() +// returns null instead of leaking the developer's real ~/.cortex/config.json +// (which exists after `cortex auth` and otherwise supplies an owner/signature). +let cfgDir: string; +const SAVED_CONFIG_PATH = process.env.CORTEX_CONFIG_PATH; + beforeEach(() => { + cfgDir = mkdtempSync(join(tmpdir(), "cortex-oid-")); + process.env.CORTEX_CONFIG_PATH = join(cfgDir, "config.json"); // never created → absent delete process.env.USER_PRIMARY_ADDRESS; delete process.env.CORTEX_USER_SIGNATURE; delete process.env.CORTEX_USER_PRIVATE_KEY; + _resetConfigCache(); _resetOwnerIdentity(); }); afterEach(() => { + if (SAVED_CONFIG_PATH === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = SAVED_CONFIG_PATH; if (SAVED_ENV.USER_PRIMARY_ADDRESS !== undefined) process.env.USER_PRIMARY_ADDRESS = SAVED_ENV.USER_PRIMARY_ADDRESS; if (SAVED_ENV.CORTEX_USER_SIGNATURE !== undefined) process.env.CORTEX_USER_SIGNATURE = SAVED_ENV.CORTEX_USER_SIGNATURE; if (SAVED_ENV.CORTEX_USER_PRIVATE_KEY !== undefined) process.env.CORTEX_USER_PRIVATE_KEY = SAVED_ENV.CORTEX_USER_PRIVATE_KEY; + rmSync(cfgDir, { recursive: true, force: true }); + _resetConfigCache(); _resetOwnerIdentity(); }); diff --git a/tests/recall-no-key.test.ts b/tests/recall-no-key.test.ts new file mode 100644 index 0000000..7149bf1 --- /dev/null +++ b/tests/recall-no-key.test.ts @@ -0,0 +1,117 @@ +/** + * Cortex — recall degrades gracefully when no embeddings key is configured. + * + * A fresh installer with no provider key must still get a useful plugin: recall + * must NOT throw — it falls back to keyword/text-overlap scoring. Rules and + * documents (which carry text) still recall; pure-vector observations can't be + * keyword-matched and simply drop out. Verifies the MissingEmbeddingKeyError + * catch in recall(). + */ + +import { test, expect, beforeEach, afterEach } from "bun:test"; +import { join } from "node:path"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import type { Hex } from "@arkiv-network/sdk"; +import { recall, _resetLastRecallIds, type RecallCandidate } from "../src/darwinian/recall.ts"; +import { MissingEmbeddingKeyError } from "../src/compression/embeddings.ts"; +import { rabitqEncode, packCode } from "../src/compression/rabitq.ts"; +import { ENTITY_TYPE } from "../src/constants.ts"; +import { _resetConfigCache } from "../src/lib/cortex-config.ts"; +import { _resetPayloadKey } from "../src/lib/payload-key.ts"; +import { _resetOwnerIdentity } from "../src/agent/owner-identity.ts"; + +let dir: string; +const SAVED_CONFIG_PATH = process.env.CORTEX_CONFIG_PATH; + +beforeEach(() => { + dir = mkdtempSync(join(tmpdir(), "cortex-nokey-")); + process.env.CORTEX_CONFIG_PATH = join(dir, "config.json"); + _resetConfigCache(); + _resetOwnerIdentity(); + _resetPayloadKey(); + _resetLastRecallIds(); +}); +afterEach(() => { + if (SAVED_CONFIG_PATH === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = SAVED_CONFIG_PATH; + rmSync(dir, { recursive: true, force: true }); + _resetConfigCache(); + _resetOwnerIdentity(); + _resetPayloadKey(); +}); + +const KEY_RULE = "0x2222222222222222222222222222222222222222222222222222222222222222" as Hex; +const KEY_OBS = "0x1111111111111111111111111111111111111111111111111111111111111111" as Hex; + +// An embed that behaves exactly like embedText with no provider key. +const noKeyEmbed = async (): Promise => { + throw new MissingEmbeddingKeyError("no embeddings key (test)"); +}; + +function ruleCandidate(key: Hex, ruleText: string): RecallCandidate { + return { + key, + payload: new TextEncoder().encode(JSON.stringify({ ruleText })), + attributes: [{ key: "entityType", value: ENTITY_TYPE.RULE }], + expiresAtBlock: 1_000_000n, + }; +} + +function unitVector(seed: number): Float32Array { + let s = seed >>> 0; + const v = new Float32Array(1536); + let norm = 0; + for (let i = 0; i < 1536; i++) { + s = (Math.imul(s, 1664525) + 1013904223) >>> 0; + const x = s / 0x1_0000_0000 - 0.5; + v[i] = x; + norm += x * x; + } + const inv = 1 / Math.sqrt(norm); + for (let i = 0; i < 1536; i++) v[i]! *= inv; + return v; +} + +const noKeyDeps = (cands: RecallCandidate[]) => ({ + embedQuery: noKeyEmbed, + fetchCandidates: async () => cands, + loadWeights: async () => new Map(), +}); + +test("no embeddings key: recall does NOT throw and keyword-scores a matching rule", async () => { + const cand = ruleCandidate(KEY_RULE, "Always use bun instead of npm for this repo"); + const hits = await recall({ + query: "should I use bun or npm to install", + k: 5, + _deps: noKeyDeps([cand]), + }); + expect(hits.length).toBeGreaterThanOrEqual(1); + expect(hits[0]!.entityKey).toBe(KEY_RULE); + expect(hits[0]!.score).toBeGreaterThan(0); +}); + +test("no embeddings key: a non-matching rule scores 0 (no false positive, no throw)", async () => { + const cand = ruleCandidate(KEY_RULE, "Deploy the frontend to Vercel on every push to main"); + const hits = await recall({ + query: "quantum chromodynamics lattice gauge theory", + k: 5, + _deps: noKeyDeps([cand]), + }); + // recall returns top-k including zero-score hits; no keyword overlap → score 0. + expect(hits.length).toBe(1); + expect(hits[0]!.score).toBe(0); +}); + +test("no embeddings key: a pure-vector observation scores 0 (can't keyword-match), no throw", async () => { + const obs: RecallCandidate = { + key: KEY_OBS, + payload: packCode(rabitqEncode(unitVector(7))), + attributes: [{ key: "entityType", value: ENTITY_TYPE.OBSERVATION }], + expiresAtBlock: 1_000_000n, + }; + const hits = await recall({ query: "anything at all", k: 5, _deps: noKeyDeps([obs]) }); + // Present but unscorable without an embedding → score 0 (ranks last, agent ignores). + expect(hits.length).toBe(1); + expect(hits[0]!.score).toBe(0); +}); diff --git a/tests/sealed-memory.test.ts b/tests/sealed-memory.test.ts index a208e2c..489e336 100644 --- a/tests/sealed-memory.test.ts +++ b/tests/sealed-memory.test.ts @@ -13,6 +13,9 @@ */ import { test, expect, beforeEach, afterEach } from "bun:test"; +import { join } from "node:path"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; import type { Hex } from "@arkiv-network/sdk"; import { recall, _resetLastRecallIds, type RecallCandidate } from "../src/darwinian/recall"; import { @@ -20,6 +23,8 @@ import { _resetPayloadKey, getPayloadKey, } from "../src/lib/payload-key"; +import { _resetConfigCache } from "../src/lib/cortex-config"; +import { _resetOwnerIdentity } from "../src/agent/owner-identity"; import { derivePayloadKey, sealPayload, openPayload } from "../src/lib/crypto"; import { rabitqEncode, packCode } from "../src/compression/rabitq"; import { SEALED_CONTENT_TYPE, ENTITY_TYPE } from "../src/constants"; @@ -80,14 +85,30 @@ function deps(candidates: RecallCandidate[], queryVec: Float32Array) { }; } +// Hermetic config: an empty temp CORTEX_CONFIG_PATH so getPayloadKey() (via the +// owner-identity singleton) doesn't derive a key from the developer's real +// ~/.cortex/config.json. Without this, the "payload key is null" negative control +// fails on any machine where `cortex auth` has run. +let cfgDir: string; +const SAVED_CONFIG_PATH = process.env.CORTEX_CONFIG_PATH; + beforeEach(() => { + cfgDir = mkdtempSync(join(tmpdir(), "cortex-seal-")); + process.env.CORTEX_CONFIG_PATH = join(cfgDir, "config.json"); // never created → absent _resetPayloadKey(); + _resetOwnerIdentity(); + _resetConfigCache(); _resetLastRecallIds(); delete process.env.CORTEX_USER_SIGNATURE; delete process.env.CORTEX_USER_PRIVATE_KEY; }); afterEach(() => { + if (SAVED_CONFIG_PATH === undefined) delete process.env.CORTEX_CONFIG_PATH; + else process.env.CORTEX_CONFIG_PATH = SAVED_CONFIG_PATH; + rmSync(cfgDir, { recursive: true, force: true }); _resetPayloadKey(); + _resetOwnerIdentity(); + _resetConfigCache(); delete process.env.CORTEX_USER_SIGNATURE; delete process.env.CORTEX_USER_PRIVATE_KEY; }); diff --git a/ui/components/LocalFirstPanel.tsx b/ui/components/LocalFirstPanel.tsx new file mode 100644 index 0000000..b436d91 --- /dev/null +++ b/ui/components/LocalFirstPanel.tsx @@ -0,0 +1,114 @@ +/** + * Cortex — local-first explainer panel. + * + * Shown on the public web surface when there is no live backend: the + * autonomous loop is not configured AND the SQLite mirror is empty (the state + * a serverless deploy is permanently stuck in). Instead of a silently-empty + * dashboard, a public visitor sees an honest explainer: Cortex has no backend — + * it runs locally in Claude Code via the plugin (or `bun run dev`). Install + * steps + Loom walkthrough as proof. + * + * When the loop IS running / the mirror HAS data (local dev), the console + * renders the real dashboard and this panel never mounts. + */ + +import { useCallback, useState } from "react"; + +const VIDEO_URL = + "https://www.loom.com/share/68178caad4034e8282ac412a440e0738"; + +const INSTALL_CMD = `/plugin marketplace add LingSiewWin/Cortex +/plugin install cortex-memory +cortex auth`; + +export function LocalFirstPanel() { + const [copied, setCopied] = useState(false); + + const onCopy = useCallback(() => { + navigator.clipboard + ?.writeText(INSTALL_CMD) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 1400); + }) + .catch(() => { + /* clipboard blocked (non-secure context / denied) — fail silently */ + }); + }, []); + + return ( +
+
+ No backend by design +

+ Cortex runs locally, in + your agent. +

+

+ There is no server you depend on. The product is the Claude Code + plugin: the MCP server runs on your machine over stdio via{" "} + bun, the SQLite mirror lives on your disk, and Arkiv + writes are signed by your own funded session key. This deployment is a + landing surface — so it shows an empty console here instead of + pretending to run an autonomous loop it cannot host. +

+
+ +
+
+
+ Install in Claude Code + +
+
{INSTALL_CMD}
+

+ Sign once with your wallet, fund the printed session key on the{" "} + + Braga faucet + + , then recall and cite memory from any session. Requires{" "} + bun on your PATH. +

+
+ +
+
+ See it run +
+

+ The autonomous loop and live console below are for local development + (bun run dev). Watch the walkthrough to see the + Darwinian memory engine reinforcing and decaying memory on Braga. +

+ + + ▶ + + Watch the walkthrough + +
+
+ +

+ Running it yourself? bun run seed →{" "} + bun run dev brings this console fully alive. +

+
+ ); +} diff --git a/ui/console-editorial.css b/ui/console-editorial.css index fc52dd8..c21b06d 100644 --- a/ui/console-editorial.css +++ b/ui/console-editorial.css @@ -745,3 +745,170 @@ body:has(.cx-console) { grid-template-columns: 1fr; } } + +/* =========================================================================== + * Local-first explainer — shown when there is no live backend (serverless + * deploy). Editorial paper theme, square hairlines, ember accent. + * =========================================================================== */ + +.cx-console .local-first { + margin-top: clamp(28px, 6vw, 64px); +} + +.cx-console .local-first-hero { + max-width: 64ch; + margin-bottom: clamp(28px, 5vw, 48px); +} + +.cx-console .local-first-eyebrow { + display: inline-block; + color: var(--ember); + margin-bottom: 18px; +} + +.cx-console .local-first-title { + font-family: var(--font-display); + font-size: clamp(2rem, 5.5vw, 3.4rem); + font-weight: 600; + letter-spacing: -0.035em; + line-height: 1.04; + margin: 0 0 20px; + color: var(--ink); +} + +.cx-console .local-first-accent { + color: var(--ember); +} + +.cx-console .local-first-lead { + font-size: clamp(0.95rem, 1.6vw, 1.06rem); + line-height: 1.65; + color: #444; + margin: 0; +} + +.cx-console .local-first-lead code, +.cx-console .local-first-hint code, +.cx-console .local-first-foot code { + font-family: var(--font-mono); + font-size: 0.82em; + background: var(--surface-3); + padding: 1px 6px; + border: 1px solid var(--border); +} + +.cx-console .local-first-grid { + display: grid; + grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); + gap: 1px; + background: rgba(17, 17, 17, 0.1); + border: 1px solid rgba(17, 17, 17, 0.1); +} + +.cx-console .local-first-cell { + background: var(--paper); + padding: clamp(22px, 3vw, 32px); + display: flex; + flex-direction: column; + gap: 16px; +} + +.cx-console .local-first-cell-head { + display: flex; + align-items: center; + justify-content: space-between; +} + +.cx-console .local-first-cell-head .mono { + color: #999; +} + +.cx-console .local-first-copy { + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: 0.12em; + text-transform: uppercase; + background: transparent; + border: 1px solid var(--border-strong); + color: var(--ink); + padding: 5px 12px; + cursor: pointer; + border-radius: 0; +} +.cx-console .local-first-copy:hover { + border-color: var(--ember); + color: var(--ember); +} + +.cx-console .local-first-code { + background: #f1f1f3; + color: #1a1a1a; + border: 1px solid var(--border); + padding: 16px 18px; + margin: 0; + font-family: var(--font-mono); + font-size: 12.5px; + line-height: 1.7; + text-transform: none; + letter-spacing: 0; + white-space: pre-wrap; + overflow-x: auto; +} + +.cx-console .local-first-hint { + font-size: 13.5px; + line-height: 1.6; + color: #555; + margin: 0; +} + +.cx-console .local-first-hint a { + color: var(--ember); + text-decoration: none; + border-bottom: 1px solid currentColor; +} + +.cx-console .local-first-watch { + justify-content: space-between; +} + +.cx-console .local-first-watch-btn { + display: inline-flex; + align-items: center; + gap: 12px; + align-self: flex-start; + padding: 12px 20px; + background: var(--ink); + color: var(--paper); + text-decoration: none; + font-weight: 500; + font-size: 14px; + border: 1px solid var(--ink); + transition: background 0.15s ease; +} +.cx-console .local-first-watch-btn:hover { + background: var(--ember); + border-color: var(--ember); +} + +.cx-console .local-first-play { + font-size: 10px; +} + +.cx-console .local-first-foot { + margin-top: 22px; + color: var(--muted); + text-transform: none; + letter-spacing: 0.04em; + font-size: 12px; + line-height: 1.6; +} +.cx-console .local-first-foot code { + text-transform: none; +} + +@media (max-width: 760px) { + .cx-console .local-first-grid { + grid-template-columns: 1fr; + } +} diff --git a/ui/console.tsx b/ui/console.tsx index 365cd88..b25a3d9 100644 --- a/ui/console.tsx +++ b/ui/console.tsx @@ -23,6 +23,7 @@ import { AllowanceCard } from "./components/AllowanceCard"; import { ProofPlayground } from "./components/ProofPlayground"; import { GraphHero } from "./components/GraphHero"; import { PluginInstallStrip } from "./components/PluginInstallStrip"; +import { LocalFirstPanel } from "./components/LocalFirstPanel"; import { WalletUpload } from "./components/WalletUpload"; import MemoryGraph from "./components/MemoryGraph/MemoryGraph"; import { DecisionTimeline } from "./components/DecisionTimeline"; @@ -143,6 +144,9 @@ function ConsoleApp() { const [inspectErr, setInspectErr] = useState(null); const [mode, setMode] = useState(() => readInitialMode()); const [effectiveOwner, setEffectiveOwner] = useState(null); + // null = not yet probed; true = the autonomous loop is configured on this + // server (local dev); false = no live backend (the serverless deploy state). + const [loopConfigured, setLoopConfigured] = useState(null); const onToggleMode = useCallback((next: ConsoleMode) => { try { @@ -178,6 +182,24 @@ function ConsoleApp() { }; }, []); + // Probe whether this server runs the autonomous loop. On a serverless deploy + // the loop can never be configured (stateful long-running process), so this + // stays false and gates the local-first explainer below. + useEffect(() => { + let alive = true; + void fetch("/api/loop/status") + .then((r) => (r.ok ? r.json() : null)) + .then((s: { configured?: boolean } | null) => { + if (alive) setLoopConfigured(s?.configured === true); + }) + .catch(() => { + if (alive) setLoopConfigured(false); + }); + return () => { + alive = false; + }; + }, []); + // Initial load + polling. Re-runs when effectiveOwner changes so the scoped // /api/memories result swaps as soon as adoption completes. useEffect(() => { @@ -240,6 +262,43 @@ function ConsoleApp() { [recentMemories], ); + // No-live-backend detection (the serverless deploy state). True only once we + // have probed BOTH signals and both say "dead": the autonomous loop is not + // configured AND the mirror is empty (zero memories at block 0). While either + // probe is still pending we do NOT show the explainer — that avoids a flash + // of the panel on a healthy local-dev load. When the backend is live (loop + // running OR mirror has data) this is false and the real console renders. + const noLiveBackend = useMemo(() => { + if (loopConfigured !== false) return false; // not probed, or loop is live + const mem = data.memories; + if (!mem) return false; // memories not loaded yet — don't flash the panel + return mem.currentBlock === 0 && mem.counts.total === 0; + }, [loopConfigured, data.memories]); + + if (noLiveBackend) { + return ( +
+
+
+
+ + Home + + + Cortex + Console +
+
+ local-first +
+
+ +
+ +
+ ); + } + return (
<>