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