@abraca/mcp 1.0.5 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abracadabra-mcp.cjs +1105 -47
- package/dist/abracadabra-mcp.cjs.map +1 -1
- package/dist/abracadabra-mcp.esm.js +1107 -47
- package/dist/abracadabra-mcp.esm.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/package.json +2 -1
- package/src/crypto.ts +68 -0
- package/src/index.ts +40 -13
- package/src/server.ts +31 -19
- package/src/tools/tree.ts +74 -19
|
@@ -3,8 +3,12 @@ import { ZodOptional, z } from "zod";
|
|
|
3
3
|
import process$1 from "node:process";
|
|
4
4
|
import * as Y from "yjs";
|
|
5
5
|
import { AbracadabraClient, AbracadabraProvider, awarenessStatesToArray } from "@abraca/dabra";
|
|
6
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
6
7
|
import * as fs from "node:fs";
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
7
10
|
import * as path from "node:path";
|
|
11
|
+
import { dirname, join } from "node:path";
|
|
8
12
|
|
|
9
13
|
//#region \0rolldown/runtime.js
|
|
10
14
|
var __create = Object.create;
|
|
@@ -18430,6 +18434,992 @@ function waitForSync(provider, timeoutMs = 15e3) {
|
|
|
18430
18434
|
});
|
|
18431
18435
|
}
|
|
18432
18436
|
|
|
18437
|
+
//#endregion
|
|
18438
|
+
//#region node_modules/@noble/ed25519/index.js
|
|
18439
|
+
/*! noble-ed25519 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
|
|
18440
|
+
/**
|
|
18441
|
+
* 4KB JS implementation of ed25519 EdDSA signatures.
|
|
18442
|
+
* Compliant with RFC8032, FIPS 186-5 & ZIP215.
|
|
18443
|
+
* @module
|
|
18444
|
+
* @example
|
|
18445
|
+
* ```js
|
|
18446
|
+
import * as ed from '@noble/ed25519';
|
|
18447
|
+
(async () => {
|
|
18448
|
+
const privKey = ed.utils.randomPrivateKey();
|
|
18449
|
+
const message = Uint8Array.from([0xab, 0xbc, 0xcd, 0xde]);
|
|
18450
|
+
const pubKey = await ed.getPublicKeyAsync(privKey); // Sync methods are also present
|
|
18451
|
+
const signature = await ed.signAsync(message, privKey);
|
|
18452
|
+
const isValid = await ed.verifyAsync(signature, message, pubKey);
|
|
18453
|
+
})();
|
|
18454
|
+
```
|
|
18455
|
+
*/
|
|
18456
|
+
/**
|
|
18457
|
+
* Curve params. ed25519 is twisted edwards curve. Equation is −x² + y² = -a + dx²y².
|
|
18458
|
+
* * P = `2n**255n - 19n` // field over which calculations are done
|
|
18459
|
+
* * N = `2n**252n + 27742317777372353535851937790883648493n` // group order, amount of curve points
|
|
18460
|
+
* * h = 8 // cofactor
|
|
18461
|
+
* * a = `Fp.create(BigInt(-1))` // equation param
|
|
18462
|
+
* * d = -121665/121666 a.k.a. `Fp.neg(121665 * Fp.inv(121666))` // equation param
|
|
18463
|
+
* * Gx, Gy are coordinates of Generator / base point
|
|
18464
|
+
*/
|
|
18465
|
+
const ed25519_CURVE = {
|
|
18466
|
+
p: 57896044618658097711785492504343953926634992332820282019728792003956564819949n,
|
|
18467
|
+
n: 7237005577332262213973186563042994240857116359379907606001950938285454250989n,
|
|
18468
|
+
h: 8n,
|
|
18469
|
+
a: 57896044618658097711785492504343953926634992332820282019728792003956564819948n,
|
|
18470
|
+
d: 37095705934669439343138083508754565189542113879843219016388785533085940283555n,
|
|
18471
|
+
Gx: 15112221349535400772501151409588531511454012693041857206046113283949847762202n,
|
|
18472
|
+
Gy: 46316835694926478169428394003475163141307993866256225615783033603165251855960n
|
|
18473
|
+
};
|
|
18474
|
+
const { p: P, n: N, Gx, Gy, a: _a, d: _d } = ed25519_CURVE;
|
|
18475
|
+
const h = 8n;
|
|
18476
|
+
const L = 32;
|
|
18477
|
+
const L2 = 64;
|
|
18478
|
+
const err = (m = "") => {
|
|
18479
|
+
throw new Error(m);
|
|
18480
|
+
};
|
|
18481
|
+
const isBig = (n) => typeof n === "bigint";
|
|
18482
|
+
const isStr = (s) => typeof s === "string";
|
|
18483
|
+
const isBytes$1 = (a) => a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
18484
|
+
/** assert is Uint8Array (of specific length) */
|
|
18485
|
+
const abytes$1 = (a, l) => !isBytes$1(a) || typeof l === "number" && l > 0 && a.length !== l ? err("Uint8Array expected") : a;
|
|
18486
|
+
/** create Uint8Array */
|
|
18487
|
+
const u8n = (len) => new Uint8Array(len);
|
|
18488
|
+
const u8fr = (buf) => Uint8Array.from(buf);
|
|
18489
|
+
const padh = (n, pad) => n.toString(16).padStart(pad, "0");
|
|
18490
|
+
const bytesToHex = (b) => Array.from(abytes$1(b)).map((e) => padh(e, 2)).join("");
|
|
18491
|
+
const C = {
|
|
18492
|
+
_0: 48,
|
|
18493
|
+
_9: 57,
|
|
18494
|
+
A: 65,
|
|
18495
|
+
F: 70,
|
|
18496
|
+
a: 97,
|
|
18497
|
+
f: 102
|
|
18498
|
+
};
|
|
18499
|
+
const _ch = (ch) => {
|
|
18500
|
+
if (ch >= C._0 && ch <= C._9) return ch - C._0;
|
|
18501
|
+
if (ch >= C.A && ch <= C.F) return ch - (C.A - 10);
|
|
18502
|
+
if (ch >= C.a && ch <= C.f) return ch - (C.a - 10);
|
|
18503
|
+
};
|
|
18504
|
+
const hexToBytes = (hex) => {
|
|
18505
|
+
const e = "hex invalid";
|
|
18506
|
+
if (!isStr(hex)) return err(e);
|
|
18507
|
+
const hl = hex.length;
|
|
18508
|
+
const al = hl / 2;
|
|
18509
|
+
if (hl % 2) return err(e);
|
|
18510
|
+
const array = u8n(al);
|
|
18511
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
18512
|
+
const n1 = _ch(hex.charCodeAt(hi));
|
|
18513
|
+
const n2 = _ch(hex.charCodeAt(hi + 1));
|
|
18514
|
+
if (n1 === void 0 || n2 === void 0) return err(e);
|
|
18515
|
+
array[ai] = n1 * 16 + n2;
|
|
18516
|
+
}
|
|
18517
|
+
return array;
|
|
18518
|
+
};
|
|
18519
|
+
/** normalize hex or ui8a to ui8a */
|
|
18520
|
+
const toU8 = (a, len) => abytes$1(isStr(a) ? hexToBytes(a) : u8fr(abytes$1(a)), len);
|
|
18521
|
+
const cr = () => globalThis?.crypto;
|
|
18522
|
+
const subtle = () => cr()?.subtle ?? err("crypto.subtle must be defined");
|
|
18523
|
+
const concatBytes = (...arrs) => {
|
|
18524
|
+
const r = u8n(arrs.reduce((sum, a) => sum + abytes$1(a).length, 0));
|
|
18525
|
+
let pad = 0;
|
|
18526
|
+
arrs.forEach((a) => {
|
|
18527
|
+
r.set(a, pad);
|
|
18528
|
+
pad += a.length;
|
|
18529
|
+
});
|
|
18530
|
+
return r;
|
|
18531
|
+
};
|
|
18532
|
+
/** WebCrypto OS-level CSPRNG (random number generator). Will throw when not available. */
|
|
18533
|
+
const randomBytes = (len = L) => {
|
|
18534
|
+
return cr().getRandomValues(u8n(len));
|
|
18535
|
+
};
|
|
18536
|
+
const big = BigInt;
|
|
18537
|
+
const arange = (n, min, max, msg = "bad number: out of range") => isBig(n) && min <= n && n < max ? n : err(msg);
|
|
18538
|
+
/** modular division */
|
|
18539
|
+
const M = (a, b = P) => {
|
|
18540
|
+
const r = a % b;
|
|
18541
|
+
return r >= 0n ? r : b + r;
|
|
18542
|
+
};
|
|
18543
|
+
const modN = (a) => M(a, N);
|
|
18544
|
+
/** Modular inversion using eucledian GCD (non-CT). No negative exponent for now. */
|
|
18545
|
+
const invert = (num, md) => {
|
|
18546
|
+
if (num === 0n || md <= 0n) err("no inverse n=" + num + " mod=" + md);
|
|
18547
|
+
let a = M(num, md), b = md, x = 0n, y = 1n, u = 1n, v = 0n;
|
|
18548
|
+
while (a !== 0n) {
|
|
18549
|
+
const q = b / a, r = b % a;
|
|
18550
|
+
const m = x - u * q, n = y - v * q;
|
|
18551
|
+
b = a, a = r, x = u, y = v, u = m, v = n;
|
|
18552
|
+
}
|
|
18553
|
+
return b === 1n ? M(x, md) : err("no inverse");
|
|
18554
|
+
};
|
|
18555
|
+
const callHash = (name) => {
|
|
18556
|
+
const fn = etc[name];
|
|
18557
|
+
if (typeof fn !== "function") err("hashes." + name + " not set");
|
|
18558
|
+
return fn;
|
|
18559
|
+
};
|
|
18560
|
+
const apoint = (p) => p instanceof Point ? p : err("Point expected");
|
|
18561
|
+
const B256 = 2n ** 256n;
|
|
18562
|
+
/** Point in XYZT extended coordinates. */
|
|
18563
|
+
var Point = class Point {
|
|
18564
|
+
static BASE;
|
|
18565
|
+
static ZERO;
|
|
18566
|
+
ex;
|
|
18567
|
+
ey;
|
|
18568
|
+
ez;
|
|
18569
|
+
et;
|
|
18570
|
+
constructor(ex, ey, ez, et) {
|
|
18571
|
+
const max = B256;
|
|
18572
|
+
this.ex = arange(ex, 0n, max);
|
|
18573
|
+
this.ey = arange(ey, 0n, max);
|
|
18574
|
+
this.ez = arange(ez, 1n, max);
|
|
18575
|
+
this.et = arange(et, 0n, max);
|
|
18576
|
+
Object.freeze(this);
|
|
18577
|
+
}
|
|
18578
|
+
static fromAffine(p) {
|
|
18579
|
+
return new Point(p.x, p.y, 1n, M(p.x * p.y));
|
|
18580
|
+
}
|
|
18581
|
+
/** RFC8032 5.1.3: Uint8Array to Point. */
|
|
18582
|
+
static fromBytes(hex, zip215 = false) {
|
|
18583
|
+
const d = _d;
|
|
18584
|
+
const normed = u8fr(abytes$1(hex, L));
|
|
18585
|
+
const lastByte = hex[31];
|
|
18586
|
+
normed[31] = lastByte & -129;
|
|
18587
|
+
const y = bytesToNumLE(normed);
|
|
18588
|
+
arange(y, 0n, zip215 ? B256 : P);
|
|
18589
|
+
const y2 = M(y * y);
|
|
18590
|
+
let { isValid, value: x } = uvRatio(M(y2 - 1n), M(d * y2 + 1n));
|
|
18591
|
+
if (!isValid) err("bad point: y not sqrt");
|
|
18592
|
+
const isXOdd = (x & 1n) === 1n;
|
|
18593
|
+
const isLastByteOdd = (lastByte & 128) !== 0;
|
|
18594
|
+
if (!zip215 && x === 0n && isLastByteOdd) err("bad point: x==0, isLastByteOdd");
|
|
18595
|
+
if (isLastByteOdd !== isXOdd) x = M(-x);
|
|
18596
|
+
return new Point(x, y, 1n, M(x * y));
|
|
18597
|
+
}
|
|
18598
|
+
/** Checks if the point is valid and on-curve. */
|
|
18599
|
+
assertValidity() {
|
|
18600
|
+
const a = _a;
|
|
18601
|
+
const d = _d;
|
|
18602
|
+
const p = this;
|
|
18603
|
+
if (p.is0()) throw new Error("bad point: ZERO");
|
|
18604
|
+
const { ex: X, ey: Y, ez: Z, et: T } = p;
|
|
18605
|
+
const X2 = M(X * X);
|
|
18606
|
+
const Y2 = M(Y * Y);
|
|
18607
|
+
const Z2 = M(Z * Z);
|
|
18608
|
+
const Z4 = M(Z2 * Z2);
|
|
18609
|
+
if (M(Z2 * M(M(X2 * a) + Y2)) !== M(Z4 + M(d * M(X2 * Y2)))) throw new Error("bad point: equation left != right (1)");
|
|
18610
|
+
if (M(X * Y) !== M(Z * T)) throw new Error("bad point: equation left != right (2)");
|
|
18611
|
+
return this;
|
|
18612
|
+
}
|
|
18613
|
+
/** Equality check: compare points P&Q. */
|
|
18614
|
+
equals(other) {
|
|
18615
|
+
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
|
18616
|
+
const { ex: X2, ey: Y2, ez: Z2 } = apoint(other);
|
|
18617
|
+
const X1Z2 = M(X1 * Z2);
|
|
18618
|
+
const X2Z1 = M(X2 * Z1);
|
|
18619
|
+
const Y1Z2 = M(Y1 * Z2);
|
|
18620
|
+
const Y2Z1 = M(Y2 * Z1);
|
|
18621
|
+
return X1Z2 === X2Z1 && Y1Z2 === Y2Z1;
|
|
18622
|
+
}
|
|
18623
|
+
is0() {
|
|
18624
|
+
return this.equals(I);
|
|
18625
|
+
}
|
|
18626
|
+
/** Flip point over y coordinate. */
|
|
18627
|
+
negate() {
|
|
18628
|
+
return new Point(M(-this.ex), this.ey, this.ez, M(-this.et));
|
|
18629
|
+
}
|
|
18630
|
+
/** Point doubling. Complete formula. Cost: `4M + 4S + 1*a + 6add + 1*2`. */
|
|
18631
|
+
double() {
|
|
18632
|
+
const { ex: X1, ey: Y1, ez: Z1 } = this;
|
|
18633
|
+
const a = _a;
|
|
18634
|
+
const A = M(X1 * X1);
|
|
18635
|
+
const B = M(Y1 * Y1);
|
|
18636
|
+
const C = M(2n * M(Z1 * Z1));
|
|
18637
|
+
const D = M(a * A);
|
|
18638
|
+
const x1y1 = X1 + Y1;
|
|
18639
|
+
const E = M(M(x1y1 * x1y1) - A - B);
|
|
18640
|
+
const G = D + B;
|
|
18641
|
+
const F = G - C;
|
|
18642
|
+
const H = D - B;
|
|
18643
|
+
const X3 = M(E * F);
|
|
18644
|
+
const Y3 = M(G * H);
|
|
18645
|
+
const T3 = M(E * H);
|
|
18646
|
+
return new Point(X3, Y3, M(F * G), T3);
|
|
18647
|
+
}
|
|
18648
|
+
/** Point addition. Complete formula. Cost: `8M + 1*k + 8add + 1*2`. */
|
|
18649
|
+
add(other) {
|
|
18650
|
+
const { ex: X1, ey: Y1, ez: Z1, et: T1 } = this;
|
|
18651
|
+
const { ex: X2, ey: Y2, ez: Z2, et: T2 } = apoint(other);
|
|
18652
|
+
const a = _a;
|
|
18653
|
+
const d = _d;
|
|
18654
|
+
const A = M(X1 * X2);
|
|
18655
|
+
const B = M(Y1 * Y2);
|
|
18656
|
+
const C = M(T1 * d * T2);
|
|
18657
|
+
const D = M(Z1 * Z2);
|
|
18658
|
+
const E = M((X1 + Y1) * (X2 + Y2) - A - B);
|
|
18659
|
+
const F = M(D - C);
|
|
18660
|
+
const G = M(D + C);
|
|
18661
|
+
const H = M(B - a * A);
|
|
18662
|
+
const X3 = M(E * F);
|
|
18663
|
+
const Y3 = M(G * H);
|
|
18664
|
+
const T3 = M(E * H);
|
|
18665
|
+
return new Point(X3, Y3, M(F * G), T3);
|
|
18666
|
+
}
|
|
18667
|
+
/**
|
|
18668
|
+
* Point-by-scalar multiplication. Scalar must be in range 1 <= n < CURVE.n.
|
|
18669
|
+
* Uses {@link wNAF} for base point.
|
|
18670
|
+
* Uses fake point to mitigate side-channel leakage.
|
|
18671
|
+
* @param n scalar by which point is multiplied
|
|
18672
|
+
* @param safe safe mode guards against timing attacks; unsafe mode is faster
|
|
18673
|
+
*/
|
|
18674
|
+
multiply(n, safe = true) {
|
|
18675
|
+
if (!safe && (n === 0n || this.is0())) return I;
|
|
18676
|
+
arange(n, 1n, N);
|
|
18677
|
+
if (n === 1n) return this;
|
|
18678
|
+
if (this.equals(G)) return wNAF(n).p;
|
|
18679
|
+
let p = I;
|
|
18680
|
+
let f = G;
|
|
18681
|
+
for (let d = this; n > 0n; d = d.double(), n >>= 1n) if (n & 1n) p = p.add(d);
|
|
18682
|
+
else if (safe) f = f.add(d);
|
|
18683
|
+
return p;
|
|
18684
|
+
}
|
|
18685
|
+
/** Convert point to 2d xy affine point. (X, Y, Z) ∋ (x=X/Z, y=Y/Z) */
|
|
18686
|
+
toAffine() {
|
|
18687
|
+
const { ex: x, ey: y, ez: z } = this;
|
|
18688
|
+
if (this.equals(I)) return {
|
|
18689
|
+
x: 0n,
|
|
18690
|
+
y: 1n
|
|
18691
|
+
};
|
|
18692
|
+
const iz = invert(z, P);
|
|
18693
|
+
if (M(z * iz) !== 1n) err("invalid inverse");
|
|
18694
|
+
return {
|
|
18695
|
+
x: M(x * iz),
|
|
18696
|
+
y: M(y * iz)
|
|
18697
|
+
};
|
|
18698
|
+
}
|
|
18699
|
+
toBytes() {
|
|
18700
|
+
const { x, y } = this.assertValidity().toAffine();
|
|
18701
|
+
const b = numTo32bLE(y);
|
|
18702
|
+
b[31] |= x & 1n ? 128 : 0;
|
|
18703
|
+
return b;
|
|
18704
|
+
}
|
|
18705
|
+
toHex() {
|
|
18706
|
+
return bytesToHex(this.toBytes());
|
|
18707
|
+
}
|
|
18708
|
+
clearCofactor() {
|
|
18709
|
+
return this.multiply(big(h), false);
|
|
18710
|
+
}
|
|
18711
|
+
isSmallOrder() {
|
|
18712
|
+
return this.clearCofactor().is0();
|
|
18713
|
+
}
|
|
18714
|
+
isTorsionFree() {
|
|
18715
|
+
let p = this.multiply(N / 2n, false).double();
|
|
18716
|
+
if (N % 2n) p = p.add(this);
|
|
18717
|
+
return p.is0();
|
|
18718
|
+
}
|
|
18719
|
+
static fromHex(hex, zip215) {
|
|
18720
|
+
return Point.fromBytes(toU8(hex), zip215);
|
|
18721
|
+
}
|
|
18722
|
+
get x() {
|
|
18723
|
+
return this.toAffine().x;
|
|
18724
|
+
}
|
|
18725
|
+
get y() {
|
|
18726
|
+
return this.toAffine().y;
|
|
18727
|
+
}
|
|
18728
|
+
toRawBytes() {
|
|
18729
|
+
return this.toBytes();
|
|
18730
|
+
}
|
|
18731
|
+
};
|
|
18732
|
+
/** Generator / base point */
|
|
18733
|
+
const G = new Point(Gx, Gy, 1n, M(Gx * Gy));
|
|
18734
|
+
/** Identity / zero point */
|
|
18735
|
+
const I = new Point(0n, 1n, 1n, 0n);
|
|
18736
|
+
Point.BASE = G;
|
|
18737
|
+
Point.ZERO = I;
|
|
18738
|
+
const numTo32bLE = (num) => hexToBytes(padh(arange(num, 0n, B256), L2)).reverse();
|
|
18739
|
+
const bytesToNumLE = (b) => big("0x" + bytesToHex(u8fr(abytes$1(b)).reverse()));
|
|
18740
|
+
const pow2 = (x, power) => {
|
|
18741
|
+
let r = x;
|
|
18742
|
+
while (power-- > 0n) {
|
|
18743
|
+
r *= r;
|
|
18744
|
+
r %= P;
|
|
18745
|
+
}
|
|
18746
|
+
return r;
|
|
18747
|
+
};
|
|
18748
|
+
const pow_2_252_3 = (x) => {
|
|
18749
|
+
const b2 = x * x % P * x % P;
|
|
18750
|
+
const b5 = pow2(pow2(b2, 2n) * b2 % P, 1n) * x % P;
|
|
18751
|
+
const b10 = pow2(b5, 5n) * b5 % P;
|
|
18752
|
+
const b20 = pow2(b10, 10n) * b10 % P;
|
|
18753
|
+
const b40 = pow2(b20, 20n) * b20 % P;
|
|
18754
|
+
const b80 = pow2(b40, 40n) * b40 % P;
|
|
18755
|
+
return {
|
|
18756
|
+
pow_p_5_8: pow2(pow2(pow2(pow2(b80, 80n) * b80 % P, 80n) * b80 % P, 10n) * b10 % P, 2n) * x % P,
|
|
18757
|
+
b2
|
|
18758
|
+
};
|
|
18759
|
+
};
|
|
18760
|
+
const RM1 = 19681161376707505956807079304988542015446066515923890162744021073123829784752n;
|
|
18761
|
+
const uvRatio = (u, v) => {
|
|
18762
|
+
const v3 = M(v * v * v);
|
|
18763
|
+
const pow = pow_2_252_3(u * M(v3 * v3 * v)).pow_p_5_8;
|
|
18764
|
+
let x = M(u * v3 * pow);
|
|
18765
|
+
const vx2 = M(v * x * x);
|
|
18766
|
+
const root1 = x;
|
|
18767
|
+
const root2 = M(x * RM1);
|
|
18768
|
+
const useRoot1 = vx2 === u;
|
|
18769
|
+
const useRoot2 = vx2 === M(-u);
|
|
18770
|
+
const noRoot = vx2 === M(-u * RM1);
|
|
18771
|
+
if (useRoot1) x = root1;
|
|
18772
|
+
if (useRoot2 || noRoot) x = root2;
|
|
18773
|
+
if ((M(x) & 1n) === 1n) x = M(-x);
|
|
18774
|
+
return {
|
|
18775
|
+
isValid: useRoot1 || useRoot2,
|
|
18776
|
+
value: x
|
|
18777
|
+
};
|
|
18778
|
+
};
|
|
18779
|
+
const modL_LE = (hash) => modN(bytesToNumLE(hash));
|
|
18780
|
+
const sha512a = (...m) => etc.sha512Async(...m);
|
|
18781
|
+
const sha512s = (...m) => callHash("sha512Sync")(...m);
|
|
18782
|
+
const hash2extK = (hashed) => {
|
|
18783
|
+
const head = hashed.slice(0, L);
|
|
18784
|
+
head[0] &= 248;
|
|
18785
|
+
head[31] &= 127;
|
|
18786
|
+
head[31] |= 64;
|
|
18787
|
+
const prefix = hashed.slice(L, L2);
|
|
18788
|
+
const scalar = modL_LE(head);
|
|
18789
|
+
const point = G.multiply(scalar);
|
|
18790
|
+
return {
|
|
18791
|
+
head,
|
|
18792
|
+
prefix,
|
|
18793
|
+
scalar,
|
|
18794
|
+
point,
|
|
18795
|
+
pointBytes: point.toBytes()
|
|
18796
|
+
};
|
|
18797
|
+
};
|
|
18798
|
+
const getExtendedPublicKeyAsync = (priv) => sha512a(toU8(priv, L)).then(hash2extK);
|
|
18799
|
+
const getExtendedPublicKey = (priv) => hash2extK(sha512s(toU8(priv, L)));
|
|
18800
|
+
/** Creates 32-byte ed25519 public key from 32-byte private key. To use, set `etc.sha512Sync` first. */
|
|
18801
|
+
const getPublicKey = (priv) => getExtendedPublicKey(priv).pointBytes;
|
|
18802
|
+
const hashFinishS = (res) => res.finish(sha512s(res.hashable));
|
|
18803
|
+
const _sign = (e, rBytes, msg) => {
|
|
18804
|
+
const { pointBytes: P, scalar: s } = e;
|
|
18805
|
+
const r = modL_LE(rBytes);
|
|
18806
|
+
const R = G.multiply(r).toBytes();
|
|
18807
|
+
const hashable = concatBytes(R, P, msg);
|
|
18808
|
+
const finish = (hashed) => {
|
|
18809
|
+
return abytes$1(concatBytes(R, numTo32bLE(modN(r + modL_LE(hashed) * s))), L2);
|
|
18810
|
+
};
|
|
18811
|
+
return {
|
|
18812
|
+
hashable,
|
|
18813
|
+
finish
|
|
18814
|
+
};
|
|
18815
|
+
};
|
|
18816
|
+
/**
|
|
18817
|
+
* Signs message (NOT message hash) using private key. To use, set `hashes.sha512` first.
|
|
18818
|
+
* Follows RFC8032 5.1.6.
|
|
18819
|
+
*/
|
|
18820
|
+
const sign = (msg, privKey) => {
|
|
18821
|
+
const m = toU8(msg);
|
|
18822
|
+
const e = getExtendedPublicKey(privKey);
|
|
18823
|
+
return hashFinishS(_sign(e, sha512s(e.prefix, m), m));
|
|
18824
|
+
};
|
|
18825
|
+
/** Math, hex, byte helpers. Not in `utils` because utils share API with noble-curves. */
|
|
18826
|
+
const etc = {
|
|
18827
|
+
sha512Async: async (...messages) => {
|
|
18828
|
+
const s = subtle();
|
|
18829
|
+
const m = concatBytes(...messages);
|
|
18830
|
+
return u8n(await s.digest("SHA-512", m.buffer));
|
|
18831
|
+
},
|
|
18832
|
+
sha512Sync: void 0,
|
|
18833
|
+
bytesToHex,
|
|
18834
|
+
hexToBytes,
|
|
18835
|
+
concatBytes,
|
|
18836
|
+
mod: M,
|
|
18837
|
+
invert,
|
|
18838
|
+
randomBytes
|
|
18839
|
+
};
|
|
18840
|
+
/** ed25519-specific key utilities. */
|
|
18841
|
+
const utils = {
|
|
18842
|
+
getExtendedPublicKeyAsync,
|
|
18843
|
+
getExtendedPublicKey,
|
|
18844
|
+
randomPrivateKey: () => randomBytes(L),
|
|
18845
|
+
precompute: (w = 8, p = G) => {
|
|
18846
|
+
p.multiply(3n);
|
|
18847
|
+
return p;
|
|
18848
|
+
}
|
|
18849
|
+
};
|
|
18850
|
+
const W = 8;
|
|
18851
|
+
const pwindows = Math.ceil(256 / W) + 1;
|
|
18852
|
+
const pwindowSize = 2 ** (W - 1);
|
|
18853
|
+
const precompute = () => {
|
|
18854
|
+
const points = [];
|
|
18855
|
+
let p = G;
|
|
18856
|
+
let b = p;
|
|
18857
|
+
for (let w = 0; w < pwindows; w++) {
|
|
18858
|
+
b = p;
|
|
18859
|
+
points.push(b);
|
|
18860
|
+
for (let i = 1; i < pwindowSize; i++) {
|
|
18861
|
+
b = b.add(p);
|
|
18862
|
+
points.push(b);
|
|
18863
|
+
}
|
|
18864
|
+
p = b.double();
|
|
18865
|
+
}
|
|
18866
|
+
return points;
|
|
18867
|
+
};
|
|
18868
|
+
let Gpows = void 0;
|
|
18869
|
+
const ctneg = (cnd, p) => {
|
|
18870
|
+
const n = p.negate();
|
|
18871
|
+
return cnd ? n : p;
|
|
18872
|
+
};
|
|
18873
|
+
/**
|
|
18874
|
+
* Precomputes give 12x faster getPublicKey(), 10x sign(), 2x verify() by
|
|
18875
|
+
* caching multiples of G (base point). Cache is stored in 32MB of RAM.
|
|
18876
|
+
* Any time `G.multiply` is done, precomputes are used.
|
|
18877
|
+
* Not used for getSharedSecret, which instead multiplies random pubkey `P.multiply`.
|
|
18878
|
+
*
|
|
18879
|
+
* w-ary non-adjacent form (wNAF) precomputation method is 10% slower than windowed method,
|
|
18880
|
+
* but takes 2x less RAM. RAM reduction is possible by utilizing `.subtract`.
|
|
18881
|
+
*
|
|
18882
|
+
* !! Precomputes can be disabled by commenting-out call of the wNAF() inside Point#multiply().
|
|
18883
|
+
*/
|
|
18884
|
+
const wNAF = (n) => {
|
|
18885
|
+
const comp = Gpows || (Gpows = precompute());
|
|
18886
|
+
let p = I;
|
|
18887
|
+
let f = G;
|
|
18888
|
+
const pow_2_w = 2 ** W;
|
|
18889
|
+
const maxNum = pow_2_w;
|
|
18890
|
+
const mask = big(pow_2_w - 1);
|
|
18891
|
+
const shiftBy = big(W);
|
|
18892
|
+
for (let w = 0; w < pwindows; w++) {
|
|
18893
|
+
let wbits = Number(n & mask);
|
|
18894
|
+
n >>= shiftBy;
|
|
18895
|
+
if (wbits > pwindowSize) {
|
|
18896
|
+
wbits -= maxNum;
|
|
18897
|
+
n += 1n;
|
|
18898
|
+
}
|
|
18899
|
+
const off = w * pwindowSize;
|
|
18900
|
+
const offF = off;
|
|
18901
|
+
const offP = off + Math.abs(wbits) - 1;
|
|
18902
|
+
const isEven = w % 2 !== 0;
|
|
18903
|
+
const isNeg = wbits < 0;
|
|
18904
|
+
if (wbits === 0) f = f.add(ctneg(isEven, comp[offF]));
|
|
18905
|
+
else p = p.add(ctneg(isNeg, comp[offP]));
|
|
18906
|
+
}
|
|
18907
|
+
return {
|
|
18908
|
+
p,
|
|
18909
|
+
f
|
|
18910
|
+
};
|
|
18911
|
+
};
|
|
18912
|
+
|
|
18913
|
+
//#endregion
|
|
18914
|
+
//#region node_modules/@noble/hashes/esm/utils.js
|
|
18915
|
+
/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */
|
|
18916
|
+
function isBytes(a) {
|
|
18917
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
18918
|
+
}
|
|
18919
|
+
/** Asserts something is Uint8Array. */
|
|
18920
|
+
function abytes(b, ...lengths) {
|
|
18921
|
+
if (!isBytes(b)) throw new Error("Uint8Array expected");
|
|
18922
|
+
if (lengths.length > 0 && !lengths.includes(b.length)) throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
|
|
18923
|
+
}
|
|
18924
|
+
/** Asserts a hash instance has not been destroyed / finished */
|
|
18925
|
+
function aexists(instance, checkFinished = true) {
|
|
18926
|
+
if (instance.destroyed) throw new Error("Hash instance has been destroyed");
|
|
18927
|
+
if (checkFinished && instance.finished) throw new Error("Hash#digest() has already been called");
|
|
18928
|
+
}
|
|
18929
|
+
/** Asserts output is properly-sized byte array */
|
|
18930
|
+
function aoutput(out, instance) {
|
|
18931
|
+
abytes(out);
|
|
18932
|
+
const min = instance.outputLen;
|
|
18933
|
+
if (out.length < min) throw new Error("digestInto() expects output buffer of length at least " + min);
|
|
18934
|
+
}
|
|
18935
|
+
/** Zeroize a byte array. Warning: JS provides no guarantees. */
|
|
18936
|
+
function clean(...arrays) {
|
|
18937
|
+
for (let i = 0; i < arrays.length; i++) arrays[i].fill(0);
|
|
18938
|
+
}
|
|
18939
|
+
/** Create DataView of an array for easy byte-level manipulation. */
|
|
18940
|
+
function createView(arr) {
|
|
18941
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
18942
|
+
}
|
|
18943
|
+
/** Is current platform little-endian? Most are. Big-Endian platform: IBM */
|
|
18944
|
+
const isLE = new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68;
|
|
18945
|
+
const hasHexBuiltin = typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function";
|
|
18946
|
+
/**
|
|
18947
|
+
* Converts string to bytes using UTF8 encoding.
|
|
18948
|
+
* @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])
|
|
18949
|
+
*/
|
|
18950
|
+
function utf8ToBytes(str) {
|
|
18951
|
+
if (typeof str !== "string") throw new Error("string expected");
|
|
18952
|
+
return new Uint8Array(new TextEncoder().encode(str));
|
|
18953
|
+
}
|
|
18954
|
+
/**
|
|
18955
|
+
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
|
|
18956
|
+
* Warning: when Uint8Array is passed, it would NOT get copied.
|
|
18957
|
+
* Keep in mind for future mutable operations.
|
|
18958
|
+
*/
|
|
18959
|
+
function toBytes(data) {
|
|
18960
|
+
if (typeof data === "string") data = utf8ToBytes(data);
|
|
18961
|
+
abytes(data);
|
|
18962
|
+
return data;
|
|
18963
|
+
}
|
|
18964
|
+
/** For runtime check if class implements interface */
|
|
18965
|
+
var Hash = class {};
|
|
18966
|
+
/** Wraps hash function, creating an interface on top of it */
|
|
18967
|
+
function createHasher(hashCons) {
|
|
18968
|
+
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
|
|
18969
|
+
const tmp = hashCons();
|
|
18970
|
+
hashC.outputLen = tmp.outputLen;
|
|
18971
|
+
hashC.blockLen = tmp.blockLen;
|
|
18972
|
+
hashC.create = () => hashCons();
|
|
18973
|
+
return hashC;
|
|
18974
|
+
}
|
|
18975
|
+
|
|
18976
|
+
//#endregion
|
|
18977
|
+
//#region node_modules/@noble/hashes/esm/_md.js
|
|
18978
|
+
/**
|
|
18979
|
+
* Internal Merkle-Damgard hash utils.
|
|
18980
|
+
* @module
|
|
18981
|
+
*/
|
|
18982
|
+
/** Polyfill for Safari 14. https://caniuse.com/mdn-javascript_builtins_dataview_setbiguint64 */
|
|
18983
|
+
function setBigUint64(view, byteOffset, value, isLE) {
|
|
18984
|
+
if (typeof view.setBigUint64 === "function") return view.setBigUint64(byteOffset, value, isLE);
|
|
18985
|
+
const _32n = BigInt(32);
|
|
18986
|
+
const _u32_max = BigInt(4294967295);
|
|
18987
|
+
const wh = Number(value >> _32n & _u32_max);
|
|
18988
|
+
const wl = Number(value & _u32_max);
|
|
18989
|
+
const h = isLE ? 4 : 0;
|
|
18990
|
+
const l = isLE ? 0 : 4;
|
|
18991
|
+
view.setUint32(byteOffset + h, wh, isLE);
|
|
18992
|
+
view.setUint32(byteOffset + l, wl, isLE);
|
|
18993
|
+
}
|
|
18994
|
+
/**
|
|
18995
|
+
* Merkle-Damgard hash construction base class.
|
|
18996
|
+
* Could be used to create MD5, RIPEMD, SHA1, SHA2.
|
|
18997
|
+
*/
|
|
18998
|
+
var HashMD = class extends Hash {
|
|
18999
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
19000
|
+
super();
|
|
19001
|
+
this.finished = false;
|
|
19002
|
+
this.length = 0;
|
|
19003
|
+
this.pos = 0;
|
|
19004
|
+
this.destroyed = false;
|
|
19005
|
+
this.blockLen = blockLen;
|
|
19006
|
+
this.outputLen = outputLen;
|
|
19007
|
+
this.padOffset = padOffset;
|
|
19008
|
+
this.isLE = isLE;
|
|
19009
|
+
this.buffer = new Uint8Array(blockLen);
|
|
19010
|
+
this.view = createView(this.buffer);
|
|
19011
|
+
}
|
|
19012
|
+
update(data) {
|
|
19013
|
+
aexists(this);
|
|
19014
|
+
data = toBytes(data);
|
|
19015
|
+
abytes(data);
|
|
19016
|
+
const { view, buffer, blockLen } = this;
|
|
19017
|
+
const len = data.length;
|
|
19018
|
+
for (let pos = 0; pos < len;) {
|
|
19019
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
19020
|
+
if (take === blockLen) {
|
|
19021
|
+
const dataView = createView(data);
|
|
19022
|
+
for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);
|
|
19023
|
+
continue;
|
|
19024
|
+
}
|
|
19025
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
19026
|
+
this.pos += take;
|
|
19027
|
+
pos += take;
|
|
19028
|
+
if (this.pos === blockLen) {
|
|
19029
|
+
this.process(view, 0);
|
|
19030
|
+
this.pos = 0;
|
|
19031
|
+
}
|
|
19032
|
+
}
|
|
19033
|
+
this.length += data.length;
|
|
19034
|
+
this.roundClean();
|
|
19035
|
+
return this;
|
|
19036
|
+
}
|
|
19037
|
+
digestInto(out) {
|
|
19038
|
+
aexists(this);
|
|
19039
|
+
aoutput(out, this);
|
|
19040
|
+
this.finished = true;
|
|
19041
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
19042
|
+
let { pos } = this;
|
|
19043
|
+
buffer[pos++] = 128;
|
|
19044
|
+
clean(this.buffer.subarray(pos));
|
|
19045
|
+
if (this.padOffset > blockLen - pos) {
|
|
19046
|
+
this.process(view, 0);
|
|
19047
|
+
pos = 0;
|
|
19048
|
+
}
|
|
19049
|
+
for (let i = pos; i < blockLen; i++) buffer[i] = 0;
|
|
19050
|
+
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
|
|
19051
|
+
this.process(view, 0);
|
|
19052
|
+
const oview = createView(out);
|
|
19053
|
+
const len = this.outputLen;
|
|
19054
|
+
if (len % 4) throw new Error("_sha2: outputLen should be aligned to 32bit");
|
|
19055
|
+
const outLen = len / 4;
|
|
19056
|
+
const state = this.get();
|
|
19057
|
+
if (outLen > state.length) throw new Error("_sha2: outputLen bigger than state");
|
|
19058
|
+
for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);
|
|
19059
|
+
}
|
|
19060
|
+
digest() {
|
|
19061
|
+
const { buffer, outputLen } = this;
|
|
19062
|
+
this.digestInto(buffer);
|
|
19063
|
+
const res = buffer.slice(0, outputLen);
|
|
19064
|
+
this.destroy();
|
|
19065
|
+
return res;
|
|
19066
|
+
}
|
|
19067
|
+
_cloneInto(to) {
|
|
19068
|
+
to || (to = new this.constructor());
|
|
19069
|
+
to.set(...this.get());
|
|
19070
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
19071
|
+
to.destroyed = destroyed;
|
|
19072
|
+
to.finished = finished;
|
|
19073
|
+
to.length = length;
|
|
19074
|
+
to.pos = pos;
|
|
19075
|
+
if (length % blockLen) to.buffer.set(buffer);
|
|
19076
|
+
return to;
|
|
19077
|
+
}
|
|
19078
|
+
clone() {
|
|
19079
|
+
return this._cloneInto();
|
|
19080
|
+
}
|
|
19081
|
+
};
|
|
19082
|
+
/** Initial SHA512 state. Bits 0..64 of frac part of sqrt of primes 2..19 */
|
|
19083
|
+
const SHA512_IV = /* @__PURE__ */ Uint32Array.from([
|
|
19084
|
+
1779033703,
|
|
19085
|
+
4089235720,
|
|
19086
|
+
3144134277,
|
|
19087
|
+
2227873595,
|
|
19088
|
+
1013904242,
|
|
19089
|
+
4271175723,
|
|
19090
|
+
2773480762,
|
|
19091
|
+
1595750129,
|
|
19092
|
+
1359893119,
|
|
19093
|
+
2917565137,
|
|
19094
|
+
2600822924,
|
|
19095
|
+
725511199,
|
|
19096
|
+
528734635,
|
|
19097
|
+
4215389547,
|
|
19098
|
+
1541459225,
|
|
19099
|
+
327033209
|
|
19100
|
+
]);
|
|
19101
|
+
|
|
19102
|
+
//#endregion
|
|
19103
|
+
//#region node_modules/@noble/hashes/esm/_u64.js
|
|
19104
|
+
/**
|
|
19105
|
+
* Internal helpers for u64. BigUint64Array is too slow as per 2025, so we implement it using Uint32Array.
|
|
19106
|
+
* @todo re-check https://issues.chromium.org/issues/42212588
|
|
19107
|
+
* @module
|
|
19108
|
+
*/
|
|
19109
|
+
const U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
|
|
19110
|
+
const _32n = /* @__PURE__ */ BigInt(32);
|
|
19111
|
+
function fromBig(n, le = false) {
|
|
19112
|
+
if (le) return {
|
|
19113
|
+
h: Number(n & U32_MASK64),
|
|
19114
|
+
l: Number(n >> _32n & U32_MASK64)
|
|
19115
|
+
};
|
|
19116
|
+
return {
|
|
19117
|
+
h: Number(n >> _32n & U32_MASK64) | 0,
|
|
19118
|
+
l: Number(n & U32_MASK64) | 0
|
|
19119
|
+
};
|
|
19120
|
+
}
|
|
19121
|
+
function split(lst, le = false) {
|
|
19122
|
+
const len = lst.length;
|
|
19123
|
+
let Ah = new Uint32Array(len);
|
|
19124
|
+
let Al = new Uint32Array(len);
|
|
19125
|
+
for (let i = 0; i < len; i++) {
|
|
19126
|
+
const { h, l } = fromBig(lst[i], le);
|
|
19127
|
+
[Ah[i], Al[i]] = [h, l];
|
|
19128
|
+
}
|
|
19129
|
+
return [Ah, Al];
|
|
19130
|
+
}
|
|
19131
|
+
const shrSH = (h, _l, s) => h >>> s;
|
|
19132
|
+
const shrSL = (h, l, s) => h << 32 - s | l >>> s;
|
|
19133
|
+
const rotrSH = (h, l, s) => h >>> s | l << 32 - s;
|
|
19134
|
+
const rotrSL = (h, l, s) => h << 32 - s | l >>> s;
|
|
19135
|
+
const rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32;
|
|
19136
|
+
const rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s;
|
|
19137
|
+
function add(Ah, Al, Bh, Bl) {
|
|
19138
|
+
const l = (Al >>> 0) + (Bl >>> 0);
|
|
19139
|
+
return {
|
|
19140
|
+
h: Ah + Bh + (l / 2 ** 32 | 0) | 0,
|
|
19141
|
+
l: l | 0
|
|
19142
|
+
};
|
|
19143
|
+
}
|
|
19144
|
+
const add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
|
|
19145
|
+
const add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
|
|
19146
|
+
const add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);
|
|
19147
|
+
const add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0;
|
|
19148
|
+
const add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
|
|
19149
|
+
const add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
|
|
19150
|
+
|
|
19151
|
+
//#endregion
|
|
19152
|
+
//#region node_modules/@noble/hashes/esm/sha2.js
|
|
19153
|
+
/**
|
|
19154
|
+
* SHA2 hash function. A.k.a. sha256, sha384, sha512, sha512_224, sha512_256.
|
|
19155
|
+
* SHA256 is the fastest hash implementable in JS, even faster than Blake3.
|
|
19156
|
+
* Check out [RFC 4634](https://datatracker.ietf.org/doc/html/rfc4634) and
|
|
19157
|
+
* [FIPS 180-4](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf).
|
|
19158
|
+
* @module
|
|
19159
|
+
*/
|
|
19160
|
+
const K512 = split([
|
|
19161
|
+
"0x428a2f98d728ae22",
|
|
19162
|
+
"0x7137449123ef65cd",
|
|
19163
|
+
"0xb5c0fbcfec4d3b2f",
|
|
19164
|
+
"0xe9b5dba58189dbbc",
|
|
19165
|
+
"0x3956c25bf348b538",
|
|
19166
|
+
"0x59f111f1b605d019",
|
|
19167
|
+
"0x923f82a4af194f9b",
|
|
19168
|
+
"0xab1c5ed5da6d8118",
|
|
19169
|
+
"0xd807aa98a3030242",
|
|
19170
|
+
"0x12835b0145706fbe",
|
|
19171
|
+
"0x243185be4ee4b28c",
|
|
19172
|
+
"0x550c7dc3d5ffb4e2",
|
|
19173
|
+
"0x72be5d74f27b896f",
|
|
19174
|
+
"0x80deb1fe3b1696b1",
|
|
19175
|
+
"0x9bdc06a725c71235",
|
|
19176
|
+
"0xc19bf174cf692694",
|
|
19177
|
+
"0xe49b69c19ef14ad2",
|
|
19178
|
+
"0xefbe4786384f25e3",
|
|
19179
|
+
"0x0fc19dc68b8cd5b5",
|
|
19180
|
+
"0x240ca1cc77ac9c65",
|
|
19181
|
+
"0x2de92c6f592b0275",
|
|
19182
|
+
"0x4a7484aa6ea6e483",
|
|
19183
|
+
"0x5cb0a9dcbd41fbd4",
|
|
19184
|
+
"0x76f988da831153b5",
|
|
19185
|
+
"0x983e5152ee66dfab",
|
|
19186
|
+
"0xa831c66d2db43210",
|
|
19187
|
+
"0xb00327c898fb213f",
|
|
19188
|
+
"0xbf597fc7beef0ee4",
|
|
19189
|
+
"0xc6e00bf33da88fc2",
|
|
19190
|
+
"0xd5a79147930aa725",
|
|
19191
|
+
"0x06ca6351e003826f",
|
|
19192
|
+
"0x142929670a0e6e70",
|
|
19193
|
+
"0x27b70a8546d22ffc",
|
|
19194
|
+
"0x2e1b21385c26c926",
|
|
19195
|
+
"0x4d2c6dfc5ac42aed",
|
|
19196
|
+
"0x53380d139d95b3df",
|
|
19197
|
+
"0x650a73548baf63de",
|
|
19198
|
+
"0x766a0abb3c77b2a8",
|
|
19199
|
+
"0x81c2c92e47edaee6",
|
|
19200
|
+
"0x92722c851482353b",
|
|
19201
|
+
"0xa2bfe8a14cf10364",
|
|
19202
|
+
"0xa81a664bbc423001",
|
|
19203
|
+
"0xc24b8b70d0f89791",
|
|
19204
|
+
"0xc76c51a30654be30",
|
|
19205
|
+
"0xd192e819d6ef5218",
|
|
19206
|
+
"0xd69906245565a910",
|
|
19207
|
+
"0xf40e35855771202a",
|
|
19208
|
+
"0x106aa07032bbd1b8",
|
|
19209
|
+
"0x19a4c116b8d2d0c8",
|
|
19210
|
+
"0x1e376c085141ab53",
|
|
19211
|
+
"0x2748774cdf8eeb99",
|
|
19212
|
+
"0x34b0bcb5e19b48a8",
|
|
19213
|
+
"0x391c0cb3c5c95a63",
|
|
19214
|
+
"0x4ed8aa4ae3418acb",
|
|
19215
|
+
"0x5b9cca4f7763e373",
|
|
19216
|
+
"0x682e6ff3d6b2b8a3",
|
|
19217
|
+
"0x748f82ee5defb2fc",
|
|
19218
|
+
"0x78a5636f43172f60",
|
|
19219
|
+
"0x84c87814a1f0ab72",
|
|
19220
|
+
"0x8cc702081a6439ec",
|
|
19221
|
+
"0x90befffa23631e28",
|
|
19222
|
+
"0xa4506cebde82bde9",
|
|
19223
|
+
"0xbef9a3f7b2c67915",
|
|
19224
|
+
"0xc67178f2e372532b",
|
|
19225
|
+
"0xca273eceea26619c",
|
|
19226
|
+
"0xd186b8c721c0c207",
|
|
19227
|
+
"0xeada7dd6cde0eb1e",
|
|
19228
|
+
"0xf57d4f7fee6ed178",
|
|
19229
|
+
"0x06f067aa72176fba",
|
|
19230
|
+
"0x0a637dc5a2c898a6",
|
|
19231
|
+
"0x113f9804bef90dae",
|
|
19232
|
+
"0x1b710b35131c471b",
|
|
19233
|
+
"0x28db77f523047d84",
|
|
19234
|
+
"0x32caab7b40c72493",
|
|
19235
|
+
"0x3c9ebe0a15c9bebc",
|
|
19236
|
+
"0x431d67c49c100d4c",
|
|
19237
|
+
"0x4cc5d4becb3e42b6",
|
|
19238
|
+
"0x597f299cfc657e2a",
|
|
19239
|
+
"0x5fcb6fab3ad6faec",
|
|
19240
|
+
"0x6c44198c4a475817"
|
|
19241
|
+
].map((n) => BigInt(n)));
|
|
19242
|
+
const SHA512_Kh = K512[0];
|
|
19243
|
+
const SHA512_Kl = K512[1];
|
|
19244
|
+
const SHA512_W_H = /* @__PURE__ */ new Uint32Array(80);
|
|
19245
|
+
const SHA512_W_L = /* @__PURE__ */ new Uint32Array(80);
|
|
19246
|
+
var SHA512 = class extends HashMD {
|
|
19247
|
+
constructor(outputLen = 64) {
|
|
19248
|
+
super(128, outputLen, 16, false);
|
|
19249
|
+
this.Ah = SHA512_IV[0] | 0;
|
|
19250
|
+
this.Al = SHA512_IV[1] | 0;
|
|
19251
|
+
this.Bh = SHA512_IV[2] | 0;
|
|
19252
|
+
this.Bl = SHA512_IV[3] | 0;
|
|
19253
|
+
this.Ch = SHA512_IV[4] | 0;
|
|
19254
|
+
this.Cl = SHA512_IV[5] | 0;
|
|
19255
|
+
this.Dh = SHA512_IV[6] | 0;
|
|
19256
|
+
this.Dl = SHA512_IV[7] | 0;
|
|
19257
|
+
this.Eh = SHA512_IV[8] | 0;
|
|
19258
|
+
this.El = SHA512_IV[9] | 0;
|
|
19259
|
+
this.Fh = SHA512_IV[10] | 0;
|
|
19260
|
+
this.Fl = SHA512_IV[11] | 0;
|
|
19261
|
+
this.Gh = SHA512_IV[12] | 0;
|
|
19262
|
+
this.Gl = SHA512_IV[13] | 0;
|
|
19263
|
+
this.Hh = SHA512_IV[14] | 0;
|
|
19264
|
+
this.Hl = SHA512_IV[15] | 0;
|
|
19265
|
+
}
|
|
19266
|
+
get() {
|
|
19267
|
+
const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
|
19268
|
+
return [
|
|
19269
|
+
Ah,
|
|
19270
|
+
Al,
|
|
19271
|
+
Bh,
|
|
19272
|
+
Bl,
|
|
19273
|
+
Ch,
|
|
19274
|
+
Cl,
|
|
19275
|
+
Dh,
|
|
19276
|
+
Dl,
|
|
19277
|
+
Eh,
|
|
19278
|
+
El,
|
|
19279
|
+
Fh,
|
|
19280
|
+
Fl,
|
|
19281
|
+
Gh,
|
|
19282
|
+
Gl,
|
|
19283
|
+
Hh,
|
|
19284
|
+
Hl
|
|
19285
|
+
];
|
|
19286
|
+
}
|
|
19287
|
+
set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) {
|
|
19288
|
+
this.Ah = Ah | 0;
|
|
19289
|
+
this.Al = Al | 0;
|
|
19290
|
+
this.Bh = Bh | 0;
|
|
19291
|
+
this.Bl = Bl | 0;
|
|
19292
|
+
this.Ch = Ch | 0;
|
|
19293
|
+
this.Cl = Cl | 0;
|
|
19294
|
+
this.Dh = Dh | 0;
|
|
19295
|
+
this.Dl = Dl | 0;
|
|
19296
|
+
this.Eh = Eh | 0;
|
|
19297
|
+
this.El = El | 0;
|
|
19298
|
+
this.Fh = Fh | 0;
|
|
19299
|
+
this.Fl = Fl | 0;
|
|
19300
|
+
this.Gh = Gh | 0;
|
|
19301
|
+
this.Gl = Gl | 0;
|
|
19302
|
+
this.Hh = Hh | 0;
|
|
19303
|
+
this.Hl = Hl | 0;
|
|
19304
|
+
}
|
|
19305
|
+
process(view, offset) {
|
|
19306
|
+
for (let i = 0; i < 16; i++, offset += 4) {
|
|
19307
|
+
SHA512_W_H[i] = view.getUint32(offset);
|
|
19308
|
+
SHA512_W_L[i] = view.getUint32(offset += 4);
|
|
19309
|
+
}
|
|
19310
|
+
for (let i = 16; i < 80; i++) {
|
|
19311
|
+
const W15h = SHA512_W_H[i - 15] | 0;
|
|
19312
|
+
const W15l = SHA512_W_L[i - 15] | 0;
|
|
19313
|
+
const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7);
|
|
19314
|
+
const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7);
|
|
19315
|
+
const W2h = SHA512_W_H[i - 2] | 0;
|
|
19316
|
+
const W2l = SHA512_W_L[i - 2] | 0;
|
|
19317
|
+
const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6);
|
|
19318
|
+
const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6);
|
|
19319
|
+
const SUMl = add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]);
|
|
19320
|
+
SHA512_W_H[i] = add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]) | 0;
|
|
19321
|
+
SHA512_W_L[i] = SUMl | 0;
|
|
19322
|
+
}
|
|
19323
|
+
let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this;
|
|
19324
|
+
for (let i = 0; i < 80; i++) {
|
|
19325
|
+
const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41);
|
|
19326
|
+
const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41);
|
|
19327
|
+
const CHIh = Eh & Fh ^ ~Eh & Gh;
|
|
19328
|
+
const CHIl = El & Fl ^ ~El & Gl;
|
|
19329
|
+
const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]);
|
|
19330
|
+
const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]);
|
|
19331
|
+
const T1l = T1ll | 0;
|
|
19332
|
+
const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39);
|
|
19333
|
+
const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39);
|
|
19334
|
+
const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch;
|
|
19335
|
+
const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl;
|
|
19336
|
+
Hh = Gh | 0;
|
|
19337
|
+
Hl = Gl | 0;
|
|
19338
|
+
Gh = Fh | 0;
|
|
19339
|
+
Gl = Fl | 0;
|
|
19340
|
+
Fh = Eh | 0;
|
|
19341
|
+
Fl = El | 0;
|
|
19342
|
+
({h: Eh, l: El} = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0));
|
|
19343
|
+
Dh = Ch | 0;
|
|
19344
|
+
Dl = Cl | 0;
|
|
19345
|
+
Ch = Bh | 0;
|
|
19346
|
+
Cl = Bl | 0;
|
|
19347
|
+
Bh = Ah | 0;
|
|
19348
|
+
Bl = Al | 0;
|
|
19349
|
+
const All = add3L(T1l, sigma0l, MAJl);
|
|
19350
|
+
Ah = add3H(All, T1h, sigma0h, MAJh);
|
|
19351
|
+
Al = All | 0;
|
|
19352
|
+
}
|
|
19353
|
+
({h: Ah, l: Al} = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0));
|
|
19354
|
+
({h: Bh, l: Bl} = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0));
|
|
19355
|
+
({h: Ch, l: Cl} = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0));
|
|
19356
|
+
({h: Dh, l: Dl} = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0));
|
|
19357
|
+
({h: Eh, l: El} = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0));
|
|
19358
|
+
({h: Fh, l: Fl} = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0));
|
|
19359
|
+
({h: Gh, l: Gl} = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0));
|
|
19360
|
+
({h: Hh, l: Hl} = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0));
|
|
19361
|
+
this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl);
|
|
19362
|
+
}
|
|
19363
|
+
roundClean() {
|
|
19364
|
+
clean(SHA512_W_H, SHA512_W_L);
|
|
19365
|
+
}
|
|
19366
|
+
destroy() {
|
|
19367
|
+
clean(this.buffer);
|
|
19368
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
19369
|
+
}
|
|
19370
|
+
};
|
|
19371
|
+
/** SHA2-512 hash function from RFC 4634. */
|
|
19372
|
+
const sha512 = /* @__PURE__ */ createHasher(() => new SHA512());
|
|
19373
|
+
|
|
19374
|
+
//#endregion
|
|
19375
|
+
//#region packages/mcp/src/crypto.ts
|
|
19376
|
+
/**
|
|
19377
|
+
* Ed25519 key generation, persistence, and challenge signing for MCP agent auth.
|
|
19378
|
+
*/
|
|
19379
|
+
etc.sha512Sync = (...msgs) => sha512(etc.concatBytes(...msgs));
|
|
19380
|
+
const DEFAULT_KEY_PATH = join(homedir(), ".abracadabra", "agent.key");
|
|
19381
|
+
function toBase64url(bytes) {
|
|
19382
|
+
return Buffer.from(bytes).toString("base64url");
|
|
19383
|
+
}
|
|
19384
|
+
function fromBase64url(b64) {
|
|
19385
|
+
return new Uint8Array(Buffer.from(b64, "base64url"));
|
|
19386
|
+
}
|
|
19387
|
+
/**
|
|
19388
|
+
* Load an existing Ed25519 keypair from disk, or generate and persist a new one.
|
|
19389
|
+
* The file stores the raw 32-byte private key seed.
|
|
19390
|
+
*/
|
|
19391
|
+
async function loadOrCreateKeypair(keyPath) {
|
|
19392
|
+
const path = keyPath || DEFAULT_KEY_PATH;
|
|
19393
|
+
if (existsSync(path)) {
|
|
19394
|
+
const seed = await readFile(path);
|
|
19395
|
+
if (seed.length !== 32) throw new Error(`Invalid key file at ${path}: expected 32 bytes, got ${seed.length}`);
|
|
19396
|
+
const privateKey = new Uint8Array(seed);
|
|
19397
|
+
return {
|
|
19398
|
+
privateKey,
|
|
19399
|
+
publicKeyB64: toBase64url(getPublicKey(privateKey))
|
|
19400
|
+
};
|
|
19401
|
+
}
|
|
19402
|
+
const privateKey = utils.randomPrivateKey();
|
|
19403
|
+
const publicKey = getPublicKey(privateKey);
|
|
19404
|
+
const dir = dirname(path);
|
|
19405
|
+
if (!existsSync(dir)) await mkdir(dir, {
|
|
19406
|
+
recursive: true,
|
|
19407
|
+
mode: 448
|
|
19408
|
+
});
|
|
19409
|
+
await writeFile(path, Buffer.from(privateKey), { mode: 384 });
|
|
19410
|
+
console.error(`[abracadabra-mcp] Generated new agent keypair at ${path}`);
|
|
19411
|
+
console.error(`[abracadabra-mcp] Public key: ${toBase64url(publicKey)}`);
|
|
19412
|
+
return {
|
|
19413
|
+
privateKey,
|
|
19414
|
+
publicKeyB64: toBase64url(publicKey)
|
|
19415
|
+
};
|
|
19416
|
+
}
|
|
19417
|
+
/** Sign a base64url challenge with the agent's private key; returns base64url signature. */
|
|
19418
|
+
function signChallenge(challengeB64, privateKey) {
|
|
19419
|
+
const challenge = fromBase64url(challengeB64);
|
|
19420
|
+
return toBase64url(sign(challenge, privateKey));
|
|
19421
|
+
}
|
|
19422
|
+
|
|
18433
19423
|
//#endregion
|
|
18434
19424
|
//#region packages/mcp/src/server.ts
|
|
18435
19425
|
/**
|
|
@@ -18483,20 +19473,28 @@ var AbracadabraMCPServer = class {
|
|
|
18483
19473
|
get userId() {
|
|
18484
19474
|
return this._userId;
|
|
18485
19475
|
}
|
|
18486
|
-
/** Start the server:
|
|
19476
|
+
/** Start the server: authenticate with Ed25519 key, discover spaces/root doc, connect provider. */
|
|
18487
19477
|
async connect() {
|
|
18488
|
-
await this.
|
|
18489
|
-
|
|
18490
|
-
|
|
18491
|
-
});
|
|
18492
|
-
console.error(`[abracadabra-mcp] Logged in as ${this.config.username}`);
|
|
19478
|
+
const keypair = await loadOrCreateKeypair(this.config.keyFile);
|
|
19479
|
+
this._userId = keypair.publicKeyB64;
|
|
19480
|
+
const signFn = (challenge) => Promise.resolve(signChallenge(challenge, keypair.privateKey));
|
|
18493
19481
|
try {
|
|
18494
|
-
|
|
18495
|
-
|
|
18496
|
-
|
|
18497
|
-
|
|
18498
|
-
|
|
19482
|
+
await this.client.loginWithKey(keypair.publicKeyB64, signFn);
|
|
19483
|
+
} catch (err) {
|
|
19484
|
+
const status = err?.status ?? err?.response?.status;
|
|
19485
|
+
if (status === 404 || status === 422) {
|
|
19486
|
+
console.error("[abracadabra-mcp] Key not registered, creating new account...");
|
|
19487
|
+
await this.client.registerWithKey({
|
|
19488
|
+
publicKey: keypair.publicKeyB64,
|
|
19489
|
+
username: this.agentName.replace(/\s+/g, "-").toLowerCase(),
|
|
19490
|
+
displayName: this.agentName,
|
|
19491
|
+
deviceName: "MCP Agent",
|
|
19492
|
+
inviteCode: this.config.inviteCode
|
|
19493
|
+
});
|
|
19494
|
+
await this.client.loginWithKey(keypair.publicKeyB64, signFn);
|
|
19495
|
+
} else throw err;
|
|
18499
19496
|
}
|
|
19497
|
+
console.error(`[abracadabra-mcp] Authenticated as ${this.agentName} (${keypair.publicKeyB64.slice(0, 12)}...)`);
|
|
18500
19498
|
this._serverInfo = await this.client.serverInfo();
|
|
18501
19499
|
let initialDocId = this._serverInfo.index_doc_id ?? null;
|
|
18502
19500
|
try {
|
|
@@ -18757,6 +19755,15 @@ var AbracadabraMCPServer = class {
|
|
|
18757
19755
|
|
|
18758
19756
|
//#endregion
|
|
18759
19757
|
//#region packages/mcp/src/tools/tree.ts
|
|
19758
|
+
/**
|
|
19759
|
+
* Normalize a document ID so the hub/root doc ID is treated as the tree root (null).
|
|
19760
|
+
* This lets callers pass the hub doc_id from list_spaces as parentId/rootId
|
|
19761
|
+
* and get the expected root-level results instead of an empty set.
|
|
19762
|
+
*/
|
|
19763
|
+
function normalizeRootId(id, server) {
|
|
19764
|
+
if (id == null) return null;
|
|
19765
|
+
return id === server.rootDocId ? null : id;
|
|
19766
|
+
}
|
|
18760
19767
|
function readEntries$1(treeMap) {
|
|
18761
19768
|
const entries = [];
|
|
18762
19769
|
treeMap.forEach((value, id) => {
|
|
@@ -18806,51 +19813,76 @@ function buildTree$1(entries, rootId, maxDepth, currentDepth = 0, visited = /* @
|
|
|
18806
19813
|
});
|
|
18807
19814
|
}
|
|
18808
19815
|
function registerTreeTools(mcp, server) {
|
|
18809
|
-
mcp.tool("
|
|
19816
|
+
mcp.tool("list_documents", "List direct children of a document (defaults to root). Returns id, label, type, meta, order. NOTE: Only returns ONE level. Use find_document to search by name across the full tree, or get_document_tree to see the complete hierarchy.", { parentId: z.string().optional().describe("Parent document ID. Omit for root-level documents.") }, async ({ parentId }) => {
|
|
18810
19817
|
const treeMap = server.getTreeMap();
|
|
18811
19818
|
if (!treeMap) return { content: [{
|
|
18812
19819
|
type: "text",
|
|
18813
19820
|
text: "Not connected"
|
|
18814
19821
|
}] };
|
|
18815
|
-
const
|
|
19822
|
+
const targetId = normalizeRootId(parentId, server);
|
|
19823
|
+
const children = childrenOf$1(readEntries$1(treeMap), targetId);
|
|
18816
19824
|
return { content: [{
|
|
18817
19825
|
type: "text",
|
|
18818
|
-
text: JSON.stringify(
|
|
18819
|
-
id: e.id,
|
|
18820
|
-
label: e.label,
|
|
18821
|
-
parentId: e.parentId,
|
|
18822
|
-
type: e.type
|
|
18823
|
-
})), null, 2)
|
|
19826
|
+
text: JSON.stringify(children, null, 2)
|
|
18824
19827
|
}] };
|
|
18825
19828
|
});
|
|
18826
|
-
mcp.tool("
|
|
19829
|
+
mcp.tool("get_document_tree", "Get the full document tree as nested JSON. Call this FIRST when exploring a space or looking for documents — it shows the complete hierarchy including all nested documents. Use rootId to scope to a subtree.", {
|
|
19830
|
+
rootId: z.string().optional().describe("Root document ID to start from. Omit for the entire tree."),
|
|
19831
|
+
depth: z.number().optional().describe("Maximum depth to traverse. Default 3. Use -1 for unlimited.")
|
|
19832
|
+
}, async ({ rootId, depth }) => {
|
|
18827
19833
|
const treeMap = server.getTreeMap();
|
|
18828
19834
|
if (!treeMap) return { content: [{
|
|
18829
19835
|
type: "text",
|
|
18830
19836
|
text: "Not connected"
|
|
18831
19837
|
}] };
|
|
18832
|
-
const targetId =
|
|
18833
|
-
const
|
|
19838
|
+
const targetId = normalizeRootId(rootId, server);
|
|
19839
|
+
const maxDepth = depth ?? 3;
|
|
19840
|
+
const tree = buildTree$1(readEntries$1(treeMap), targetId, maxDepth);
|
|
18834
19841
|
return { content: [{
|
|
18835
19842
|
type: "text",
|
|
18836
|
-
text: JSON.stringify(
|
|
19843
|
+
text: JSON.stringify(tree, null, 2)
|
|
18837
19844
|
}] };
|
|
18838
19845
|
});
|
|
18839
|
-
mcp.tool("
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
}, async ({
|
|
19846
|
+
mcp.tool("find_document", "Search for documents by name across the entire tree. Returns matching documents with their full ancestor path. Use this when you're looking for a specific document and don't know where it is in the hierarchy.", {
|
|
19847
|
+
query: z.string().describe("Search query — matched case-insensitively against document labels (substring match)."),
|
|
19848
|
+
rootId: z.string().optional().describe("Restrict search to descendants of this document. Omit to search the entire tree.")
|
|
19849
|
+
}, async ({ query, rootId }) => {
|
|
18843
19850
|
const treeMap = server.getTreeMap();
|
|
18844
19851
|
if (!treeMap) return { content: [{
|
|
18845
19852
|
type: "text",
|
|
18846
19853
|
text: "Not connected"
|
|
18847
19854
|
}] };
|
|
18848
|
-
const
|
|
18849
|
-
const
|
|
18850
|
-
const
|
|
19855
|
+
const entries = readEntries$1(treeMap);
|
|
19856
|
+
const lowerQuery = query.toLowerCase();
|
|
19857
|
+
const normalizedRoot = normalizeRootId(rootId, server);
|
|
19858
|
+
const matches = (normalizedRoot ? descendantsOf(entries, normalizedRoot) : entries).filter((e) => e.label.toLowerCase().includes(lowerQuery));
|
|
19859
|
+
const byId = new Map(entries.map((e) => [e.id, e]));
|
|
19860
|
+
const results = matches.map((entry) => {
|
|
19861
|
+
const path = [];
|
|
19862
|
+
let current = entry.parentId;
|
|
19863
|
+
const visited = /* @__PURE__ */ new Set();
|
|
19864
|
+
while (current && !visited.has(current)) {
|
|
19865
|
+
visited.add(current);
|
|
19866
|
+
const parent = byId.get(current);
|
|
19867
|
+
if (!parent) break;
|
|
19868
|
+
path.unshift(parent.label);
|
|
19869
|
+
current = parent.parentId;
|
|
19870
|
+
}
|
|
19871
|
+
return {
|
|
19872
|
+
id: entry.id,
|
|
19873
|
+
label: entry.label,
|
|
19874
|
+
type: entry.type,
|
|
19875
|
+
meta: entry.meta,
|
|
19876
|
+
path
|
|
19877
|
+
};
|
|
19878
|
+
});
|
|
19879
|
+
if (results.length === 0) return { content: [{
|
|
19880
|
+
type: "text",
|
|
19881
|
+
text: `No documents found matching "${query}". Try get_document_tree to see the full hierarchy.`
|
|
19882
|
+
}] };
|
|
18851
19883
|
return { content: [{
|
|
18852
19884
|
type: "text",
|
|
18853
|
-
text: JSON.stringify(
|
|
19885
|
+
text: JSON.stringify(results, null, 2)
|
|
18854
19886
|
}] };
|
|
18855
19887
|
});
|
|
18856
19888
|
mcp.tool("create_document", "Create a new document in the tree. Returns the new document ID.", {
|
|
@@ -18866,11 +19898,12 @@ function registerTreeTools(mcp, server) {
|
|
|
18866
19898
|
text: "Not connected"
|
|
18867
19899
|
}] };
|
|
18868
19900
|
const id = crypto.randomUUID();
|
|
19901
|
+
const normalizedParent = normalizeRootId(parentId, server);
|
|
18869
19902
|
const now = Date.now();
|
|
18870
19903
|
rootDoc.transact(() => {
|
|
18871
19904
|
treeMap.set(id, {
|
|
18872
19905
|
label,
|
|
18873
|
-
parentId:
|
|
19906
|
+
parentId: normalizedParent,
|
|
18874
19907
|
order: now,
|
|
18875
19908
|
type,
|
|
18876
19909
|
meta,
|
|
@@ -18929,7 +19962,7 @@ function registerTreeTools(mcp, server) {
|
|
|
18929
19962
|
}] };
|
|
18930
19963
|
treeMap.set(id, {
|
|
18931
19964
|
...entry,
|
|
18932
|
-
parentId: newParentId
|
|
19965
|
+
parentId: normalizeRootId(newParentId, server),
|
|
18933
19966
|
order: order ?? Date.now(),
|
|
18934
19967
|
updatedAt: Date.now()
|
|
18935
19968
|
});
|
|
@@ -20956,36 +21989,63 @@ function registerServerInfoResource(mcp, server) {
|
|
|
20956
21989
|
* Abracadabra MCP Server — entry point.
|
|
20957
21990
|
*
|
|
20958
21991
|
* Environment variables:
|
|
20959
|
-
* ABRA_URL
|
|
20960
|
-
*
|
|
20961
|
-
*
|
|
20962
|
-
*
|
|
20963
|
-
*
|
|
21992
|
+
* ABRA_URL (required) — Server URL (e.g. http://localhost:1234)
|
|
21993
|
+
* ABRA_AGENT_NAME — Display name (default: "AI Assistant")
|
|
21994
|
+
* ABRA_AGENT_COLOR — HSL color for presence (default: "hsl(270, 80%, 60%)")
|
|
21995
|
+
* ABRA_INVITE_CODE — Invite code for first-run registration (grants role)
|
|
21996
|
+
* ABRA_KEY_FILE — Path to Ed25519 key file (default: ~/.abracadabra/agent.key)
|
|
20964
21997
|
*/
|
|
20965
21998
|
async function main() {
|
|
20966
21999
|
const url = process.env.ABRA_URL;
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
if (!url || !username || !password) {
|
|
20970
|
-
console.error("Missing required environment variables: ABRA_URL, ABRA_USERNAME, ABRA_PASSWORD");
|
|
22000
|
+
if (!url) {
|
|
22001
|
+
console.error("Missing required environment variable: ABRA_URL");
|
|
20971
22002
|
process.exit(1);
|
|
20972
22003
|
}
|
|
20973
22004
|
const server = new AbracadabraMCPServer({
|
|
20974
22005
|
url,
|
|
20975
|
-
username,
|
|
20976
|
-
password,
|
|
20977
22006
|
agentName: process.env.ABRA_AGENT_NAME,
|
|
20978
|
-
agentColor: process.env.ABRA_AGENT_COLOR
|
|
22007
|
+
agentColor: process.env.ABRA_AGENT_COLOR,
|
|
22008
|
+
inviteCode: process.env.ABRA_INVITE_CODE,
|
|
22009
|
+
keyFile: process.env.ABRA_KEY_FILE
|
|
20979
22010
|
});
|
|
20980
22011
|
const mcp = new McpServer({
|
|
20981
22012
|
name: "abracadabra",
|
|
20982
22013
|
version: "1.0.0"
|
|
20983
22014
|
}, {
|
|
20984
22015
|
capabilities: { experimental: { "claude/channel": {} } },
|
|
20985
|
-
instructions: `
|
|
22016
|
+
instructions: `Abracadabra is a CRDT collaboration platform where everything is a document in a tree.
|
|
22017
|
+
|
|
22018
|
+
## Quick Start Workflow
|
|
22019
|
+
1. list_spaces → note the active space's doc_id (this is the hub/root document)
|
|
22020
|
+
2. get_document_tree(rootId: hubDocId) → see the FULL hierarchy before doing anything
|
|
22021
|
+
3. find_document(query) → search for a document by name if you know what you're looking for
|
|
22022
|
+
4. read_document / write_document / create_document → operate on specific documents
|
|
22023
|
+
|
|
22024
|
+
## Key Concepts
|
|
22025
|
+
- Documents form a tree. A kanban board's columns are child documents; cards are grandchildren.
|
|
22026
|
+
- A document's label IS its display name everywhere. Children ARE the content (not just the body text).
|
|
22027
|
+
- Page types (doc, kanban, table, calendar, timeline, outline, etc.) are views over the SAME tree — switching types preserves data.
|
|
22028
|
+
- An empty markdown body does NOT mean empty content — always check the children array.
|
|
22029
|
+
|
|
22030
|
+
## Finding Documents
|
|
22031
|
+
- list_documents only shows ONE level of children. If you don't find what you need, use find_document to search the entire tree by name, or get_document_tree to see the full hierarchy.
|
|
22032
|
+
- NEVER conclude a document doesn't exist after only checking root-level documents.
|
|
22033
|
+
|
|
22034
|
+
## Rules
|
|
22035
|
+
- Always call list_spaces first to get the hub doc ID before creating documents.
|
|
22036
|
+
- Always call get_document_tree to understand existing structure before creating documents.
|
|
22037
|
+
- Use Lucide icon names in kebab-case (e.g. "star", "code-2") for meta.icon — NEVER emoji.
|
|
22038
|
+
- Never rename or write content to the hub document itself.
|
|
22039
|
+
- Use universal meta keys (color, icon, dateStart) — never prefix with page type names.
|
|
22040
|
+
|
|
22041
|
+
## Channel Events
|
|
22042
|
+
Events from the abracadabra channel arrive as <channel source="abracadabra" ...>. They may be:
|
|
20986
22043
|
- ai:task events from human users (includes sender, doc_id context)
|
|
20987
22044
|
- chat messages from the platform chat system (includes channel, sender, sender_id)
|
|
20988
|
-
When you receive a channel event, read it, do the work using your tools, and reply using the reply tool (for document responses) or send_chat_message (for chat responses)
|
|
22045
|
+
When you receive a channel event, read it, do the work using your tools, and reply using the reply tool (for document responses) or send_chat_message (for chat responses).
|
|
22046
|
+
|
|
22047
|
+
## Full Reference
|
|
22048
|
+
Read the resource at abracadabra://agent-guide for the complete guide covering page type schemas, metadata reference, awareness/presence, content structure, and detailed examples.`
|
|
20989
22049
|
});
|
|
20990
22050
|
registerTreeTools(mcp, server);
|
|
20991
22051
|
registerContentTools(mcp, server);
|