@provian/mcp 0.0.0-stage → 1.2.1
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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +266 -2
- package/bin/provian-mcp.mjs +18 -0
- package/dist/agent-wallet-registration.d.ts +34 -0
- package/dist/agent-wallet-registration.d.ts.map +1 -0
- package/dist/agent-wallet-registration.js +440 -0
- package/dist/agent-wallet-registration.js.map +1 -0
- package/dist/core/challenge.d.ts +187 -0
- package/dist/core/challenge.d.ts.map +1 -0
- package/dist/core/challenge.js +536 -0
- package/dist/core/challenge.js.map +1 -0
- package/dist/core/crypto.d.ts +44 -0
- package/dist/core/crypto.d.ts.map +1 -0
- package/dist/core/crypto.js +124 -0
- package/dist/core/crypto.js.map +1 -0
- package/dist/core/disclosure-request.d.ts +169 -0
- package/dist/core/disclosure-request.d.ts.map +1 -0
- package/dist/core/disclosure-request.js +400 -0
- package/dist/core/disclosure-request.js.map +1 -0
- package/dist/core/genesis-offer.d.ts +25 -0
- package/dist/core/genesis-offer.d.ts.map +1 -0
- package/dist/core/genesis-offer.js +34 -0
- package/dist/core/genesis-offer.js.map +1 -0
- package/dist/core/harness-tool-vocabulary.d.ts +55 -0
- package/dist/core/harness-tool-vocabulary.d.ts.map +1 -0
- package/dist/core/harness-tool-vocabulary.js +116 -0
- package/dist/core/harness-tool-vocabulary.js.map +1 -0
- package/dist/core/keccak256.d.ts +15 -0
- package/dist/core/keccak256.d.ts.map +1 -0
- package/dist/core/keccak256.js +111 -0
- package/dist/core/keccak256.js.map +1 -0
- package/dist/core/key-custody.d.ts +33 -0
- package/dist/core/key-custody.d.ts.map +1 -0
- package/dist/core/key-custody.js +59 -0
- package/dist/core/key-custody.js.map +1 -0
- package/dist/core/meter-hash.d.ts +2 -0
- package/dist/core/meter-hash.d.ts.map +1 -0
- package/dist/core/meter-hash.js +8 -0
- package/dist/core/meter-hash.js.map +1 -0
- package/dist/core/meter-wire.d.ts +193 -0
- package/dist/core/meter-wire.d.ts.map +1 -0
- package/dist/core/meter-wire.js +418 -0
- package/dist/core/meter-wire.js.map +1 -0
- package/dist/core/output-signature.d.ts +162 -0
- package/dist/core/output-signature.d.ts.map +1 -0
- package/dist/core/output-signature.js +367 -0
- package/dist/core/output-signature.js.map +1 -0
- package/dist/core/presentation.d.ts +141 -0
- package/dist/core/presentation.d.ts.map +1 -0
- package/dist/core/presentation.js +160 -0
- package/dist/core/presentation.js.map +1 -0
- package/dist/core/recovery-seal.d.ts +36 -0
- package/dist/core/recovery-seal.d.ts.map +1 -0
- package/dist/core/recovery-seal.js +122 -0
- package/dist/core/recovery-seal.js.map +1 -0
- package/dist/core/server.d.ts +38 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +106 -0
- package/dist/core/server.js.map +1 -0
- package/dist/core/thread-reader.d.ts +8 -0
- package/dist/core/thread-reader.d.ts.map +1 -0
- package/dist/core/thread-reader.js +47 -0
- package/dist/core/thread-reader.js.map +1 -0
- package/dist/core/tool-set.d.ts +28 -0
- package/dist/core/tool-set.d.ts.map +1 -0
- package/dist/core/tool-set.js +71 -0
- package/dist/core/tool-set.js.map +1 -0
- package/dist/core/tools.d.ts +151 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +3623 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/core/types.d.ts +189 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +17 -0
- package/dist/core/types.js.map +1 -0
- package/dist/credentials.d.ts +46 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +213 -0
- package/dist/credentials.js.map +1 -0
- package/dist/device-credentials.d.ts +57 -0
- package/dist/device-credentials.d.ts.map +1 -0
- package/dist/device-credentials.js +403 -0
- package/dist/device-credentials.js.map +1 -0
- package/dist/eip191.d.ts +18 -0
- package/dist/eip191.d.ts.map +1 -0
- package/dist/eip191.js +41 -0
- package/dist/eip191.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime-env.d.ts +131 -0
- package/dist/runtime-env.d.ts.map +1 -0
- package/dist/runtime-env.js +328 -0
- package/dist/runtime-env.js.map +1 -0
- package/dist/stdio.d.ts +6 -0
- package/dist/stdio.d.ts.map +1 -0
- package/dist/stdio.js +136 -0
- package/dist/stdio.js.map +1 -0
- package/package.json +60 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Burn-to-present — canonical binding + claims digest for the MCP `present` tool.
|
|
4
|
+
*
|
|
5
|
+
* SHARED CORE — canonical in `provian-mcp/src/core/`, mirrored byte-identically
|
|
6
|
+
* into `provian-backend/src/mcp/core/`. Edit only the canonical copy and run
|
|
7
|
+
* `scripts/sync-mcp-core.sh`.
|
|
8
|
+
*
|
|
9
|
+
* a presentation against a SIGNED challenge binds `provian-presentation-v2` the v1 lines
|
|
10
|
+
* plus `req=<requesterString>` and `chal_exp=<n>`; without a signed challenge the binding is v1,
|
|
11
|
+
* byte-identical to before. The challenge envelope itself lives in `challenge.ts`.
|
|
12
|
+
*
|
|
13
|
+
* A LINE-FOR-LINE PORT of `provian-agent-sdk/src/presentation.ts`
|
|
14
|
+
* (`claimsDigest` / `presentationBindingString` / `canonicalReputationDirective`)
|
|
15
|
+
* and the backend's `core/presentation/types.ts` the SAME bytes the presenter
|
|
16
|
+
* signs and the relay verifies. The MCP core cannot import the SDK (separate
|
|
17
|
+
* package) or the relay internals, so it carries its own audited copy, exactly as
|
|
18
|
+
* `crypto.ts` ports the SDK key handling. Pinned by a fixed-vector parity test
|
|
19
|
+
* (`presentation.test.ts`); a drift there means the presenter PoP would verify
|
|
20
|
+
* against the wrong bytes. Node-crypto-only (no npm deps), so the backend mirror
|
|
21
|
+
* compiles with nothing new.
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.PREDICATE_SET_MAX = exports.PREDICATE_OPS = exports.PRESENTATION_AUDIENCE_MAX_LEN = exports.PRESENTATION_CHALLENGE_MAX_LEN = exports.PRESENTATION_CHALLENGE_MIN_LEN = exports.PRESENTATION_CLOCK_SKEW_SECONDS = exports.PRESENTATION_DEFAULT_TTL_SECONDS = exports.PRESENTATION_MAX_TTL_SECONDS = exports.PRESENTATION_MIN_TTL_SECONDS = exports.PRESENTATION_BINDING_TAG_V2 = exports.PRESENTATION_BINDING_TAG = void 0;
|
|
25
|
+
exports.requesterString = requesterString;
|
|
26
|
+
exports.canonicalPredicate = canonicalPredicate;
|
|
27
|
+
exports.normalizePredicateRequests = normalizePredicateRequests;
|
|
28
|
+
exports.predicateMatchesRequest = predicateMatchesRequest;
|
|
29
|
+
exports.canonicalReputationDirective = canonicalReputationDirective;
|
|
30
|
+
exports.claimsDigest = claimsDigest;
|
|
31
|
+
exports.disclosureAnswersForCommitment = disclosureAnswersForCommitment;
|
|
32
|
+
exports.presentationBindingString = presentationBindingString;
|
|
33
|
+
const crypto_1 = require("crypto");
|
|
34
|
+
const disclosure_request_1 = require("./disclosure-request");
|
|
35
|
+
exports.PRESENTATION_BINDING_TAG = 'provian-presentation-v1';
|
|
36
|
+
/** the binding tag for a presentation produced against a SIGNED challenge. */
|
|
37
|
+
exports.PRESENTATION_BINDING_TAG_V2 = 'provian-presentation-v2';
|
|
38
|
+
exports.PRESENTATION_MIN_TTL_SECONDS = 60;
|
|
39
|
+
exports.PRESENTATION_MAX_TTL_SECONDS = 900;
|
|
40
|
+
exports.PRESENTATION_DEFAULT_TTL_SECONDS = 300;
|
|
41
|
+
/** Clock skew every verifier tolerates past a deadline (seconds). */
|
|
42
|
+
exports.PRESENTATION_CLOCK_SKEW_SECONDS = 60;
|
|
43
|
+
/** Challenge nonce length bounds (characters) and the audience length cap — mirror the relay. */
|
|
44
|
+
exports.PRESENTATION_CHALLENGE_MIN_LEN = 16;
|
|
45
|
+
exports.PRESENTATION_CHALLENGE_MAX_LEN = 512;
|
|
46
|
+
exports.PRESENTATION_AUDIENCE_MAX_LEN = 512;
|
|
47
|
+
/** `domain:<host>` | `wallet:<walletId>:<lowercase address>` — the signing-string / binding form. */
|
|
48
|
+
function requesterString(r) {
|
|
49
|
+
return r.type === 'wallet' ? `wallet:${r.id}:${(r.address ?? '').toLowerCase()}` : `domain:${r.id}`;
|
|
50
|
+
}
|
|
51
|
+
exports.PREDICATE_OPS = ['gte', 'gt', 'lte', 'lt', 'eq', 'in'];
|
|
52
|
+
exports.PREDICATE_SET_MAX = 64;
|
|
53
|
+
function isFiniteNumber(v) {
|
|
54
|
+
return typeof v === 'number' && Number.isFinite(v);
|
|
55
|
+
}
|
|
56
|
+
/** One predicate in canonical form: `in` carries a sorted, de-duplicated set; every other op its threshold. */
|
|
57
|
+
function canonicalPredicate(p) {
|
|
58
|
+
if (p.op === 'in') {
|
|
59
|
+
const set = [...new Set((p.set ?? []).filter(isFiniteNumber))].sort((a, b) => a - b);
|
|
60
|
+
return { field: p.field, op: 'in', set };
|
|
61
|
+
}
|
|
62
|
+
return { field: p.field, op: p.op, threshold: isFiniteNumber(p.threshold) ? p.threshold : NaN };
|
|
63
|
+
}
|
|
64
|
+
function predicateSortKey(c) {
|
|
65
|
+
return `${c.field}\n${c.op}\n${'set' in c ? c.set.join(',') : c.threshold}`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse an untrusted predicate list into well-formed requests, fail-closed (`null` on any malformed
|
|
69
|
+
* entry). Mirrors the backend `normalizePredicateRequests`.
|
|
70
|
+
*/
|
|
71
|
+
function normalizePredicateRequests(raw) {
|
|
72
|
+
if (raw === undefined || raw === null)
|
|
73
|
+
return [];
|
|
74
|
+
if (!Array.isArray(raw) || raw.length > exports.PREDICATE_SET_MAX)
|
|
75
|
+
return null;
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const entry of raw) {
|
|
78
|
+
if (typeof entry !== 'object' || entry === null)
|
|
79
|
+
return null;
|
|
80
|
+
const p = entry;
|
|
81
|
+
const field = typeof p.field === 'string' ? p.field.trim() : '';
|
|
82
|
+
if (field.length === 0 || field.length > 128)
|
|
83
|
+
return null;
|
|
84
|
+
const op = p.op;
|
|
85
|
+
if (typeof op !== 'string' || !exports.PREDICATE_OPS.includes(op))
|
|
86
|
+
return null;
|
|
87
|
+
if (op === 'in') {
|
|
88
|
+
if (!Array.isArray(p.set) || p.set.length === 0 || p.set.length > exports.PREDICATE_SET_MAX || !p.set.every(isFiniteNumber))
|
|
89
|
+
return null;
|
|
90
|
+
out.push({ field, op: 'in', set: [...p.set] });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
if (!isFiniteNumber(p.threshold))
|
|
94
|
+
return null;
|
|
95
|
+
out.push({ field, op: op, threshold: p.threshold });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
/** Two predicates are the same request when their canonical forms are byte-identical. */
|
|
101
|
+
function predicateMatchesRequest(answered, requested) {
|
|
102
|
+
return JSON.stringify(canonicalPredicate(answered)) === JSON.stringify(canonicalPredicate(requested));
|
|
103
|
+
}
|
|
104
|
+
function sha256hex(input) {
|
|
105
|
+
return (0, crypto_1.createHash)('sha256').update(input, 'utf8').digest('hex');
|
|
106
|
+
}
|
|
107
|
+
/** Canonical, order-independent disclosure directive — matches SDK + backend. */
|
|
108
|
+
function canonicalReputationDirective(directive) {
|
|
109
|
+
return {
|
|
110
|
+
redact: [...(directive.redact ?? [])].sort(),
|
|
111
|
+
predicates: [...(directive.predicates ?? [])]
|
|
112
|
+
.map(canonicalPredicate)
|
|
113
|
+
.sort((a, b) => predicateSortKey(a).localeCompare(predicateSortKey(b))),
|
|
114
|
+
// Present ONLY in share-only mode, so every pre-existing directive's bytes (and digest) are unchanged.
|
|
115
|
+
...(directive.share !== undefined ? { share: [...new Set(directive.share)].sort() } : {}),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Tier-specific claims digest — matches SDK + backend claimsDigest. */
|
|
119
|
+
function claimsDigest(input) {
|
|
120
|
+
if (input.tier === 'pe_fact') {
|
|
121
|
+
const lines = [...(input.peFacts ?? [])].map((f) => `${f.peId}:${f.envelopeHash.toLowerCase()}`).sort();
|
|
122
|
+
return sha256hex(`pe_fact\n${lines.join('\n')}`);
|
|
123
|
+
}
|
|
124
|
+
// The disclosure commitment line exists ONLY when the presentation answers disclosure requests.
|
|
125
|
+
const disclosures = input.disclosures !== undefined && input.disclosures.length > 0
|
|
126
|
+
? `\ndisclosures=${(0, disclosure_request_1.disclosureCommitmentDigest)(input.disclosures)}`
|
|
127
|
+
: '';
|
|
128
|
+
return sha256hex(`reputation\n${JSON.stringify(canonicalReputationDirective(input.directive ?? {}))}${disclosures}`);
|
|
129
|
+
}
|
|
130
|
+
/** The identity-only commitment the presenter signs for its disclosure answers (mirrors the SDK). */
|
|
131
|
+
function disclosureAnswersForCommitment(answers) {
|
|
132
|
+
return answers.map((a) => ({
|
|
133
|
+
request: a.request,
|
|
134
|
+
election: a.election,
|
|
135
|
+
...(a.election === 'disclosed' ? { records: (a.records ?? []).map((r) => ({ pe_id: r.peId, pe_hash: r.envelopeHash.toLowerCase(), action_type: '-', timestamp: 0, witness: { kind: 'device' } })) } : {}),
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The canonical binding string the presenter signs — matches SDK + backend. With a signed challenge
|
|
140
|
+
* (`requester` AND `chalExp`) it is v2: the v2 tag, the same lines, then `req=` and `chal_exp=`.
|
|
141
|
+
*/
|
|
142
|
+
function presentationBindingString(fields) {
|
|
143
|
+
const signed = fields.requester !== undefined && fields.chalExp !== undefined;
|
|
144
|
+
const lines = [
|
|
145
|
+
signed ? exports.PRESENTATION_BINDING_TAG_V2 : exports.PRESENTATION_BINDING_TAG,
|
|
146
|
+
`tier=${fields.tier}`,
|
|
147
|
+
`presenter=${fields.presenterAddress.toLowerCase()}`,
|
|
148
|
+
`aud=${fields.aud}`,
|
|
149
|
+
`chal=${fields.chal}`,
|
|
150
|
+
`iat=${fields.iat}`,
|
|
151
|
+
`exp=${fields.exp}`,
|
|
152
|
+
`jti=${fields.jti}`,
|
|
153
|
+
`burn=${fields.burnId}`,
|
|
154
|
+
`claims=${fields.claimsDigest}`,
|
|
155
|
+
];
|
|
156
|
+
if (signed)
|
|
157
|
+
lines.push(`req=${requesterString(fields.requester)}`, `chal_exp=${fields.chalExp}`);
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/core/presentation.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AA4BH,0CAEC;AA6BD,gDAMC;AAUD,gEAoBC;AAGD,0DAEC;AAOD,oEAaC;AAeD,oCAUC;AAkBD,wEAMC;AAMD,8DA6BC;AA1MD,mCAAoC;AACpC,6DAAmJ;AAEtI,QAAA,wBAAwB,GAAG,yBAAyB,CAAC;AAClE,8EAA8E;AACjE,QAAA,2BAA2B,GAAG,yBAAyB,CAAC;AACxD,QAAA,4BAA4B,GAAG,EAAE,CAAC;AAClC,QAAA,4BAA4B,GAAG,GAAG,CAAC;AACnC,QAAA,gCAAgC,GAAG,GAAG,CAAC;AACpD,qEAAqE;AACxD,QAAA,+BAA+B,GAAG,EAAE,CAAC;AAClD,iGAAiG;AACpF,QAAA,8BAA8B,GAAG,EAAE,CAAC;AACpC,QAAA,8BAA8B,GAAG,GAAG,CAAC;AACrC,QAAA,6BAA6B,GAAG,GAAG,CAAC;AAWjD,qGAAqG;AACrG,SAAgB,eAAe,CAAC,CAA8D;IAC5F,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC;AACtG,CAAC;AAIY,QAAA,aAAa,GAA2B,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC/E,QAAA,iBAAiB,GAAG,EAAE,CAAC;AAmBpC,SAAS,cAAc,CAAC,CAAU;IAChC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,+GAA+G;AAC/G,SAAgB,kBAAkB,CAAC,CAAmB;IACpD,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACrF,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AAClG,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAqB;IAC7C,OAAO,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,SAAgB,0BAA0B,CAAC,GAAY;IACrD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IACjD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,yBAAiB;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,GAAG,GAAuB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC7D,MAAM,CAAC,GAAG,KAAgC,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;QAC1D,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;QAChB,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAE,qBAAmC,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9F,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,yBAAiB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC;gBAAE,OAAO,IAAI,CAAC;YACjI,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,GAAI,CAAC,CAAC,GAAgB,CAAC,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAiB,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yFAAyF;AACzF,SAAgB,uBAAuB,CAAC,QAA0B,EAAE,SAA2B;IAC7F,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;AACxG,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,iFAAiF;AACjF,SAAgB,4BAA4B,CAAC,SAA8B;IAKzE,OAAO;QACL,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;QAC5C,UAAU,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;aAC1C,GAAG,CAAC,kBAAkB,CAAC;aACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;QACzE,uGAAuG;QACvG,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC;AACJ,CAAC;AAcD,wEAAwE;AACxE,SAAgB,YAAY,CAAC,KAA0I;IACrK,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxG,OAAO,SAAS,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,gGAAgG;IAChG,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QACjF,CAAC,CAAC,iBAAiB,IAAA,+CAA0B,EAAC,KAAK,CAAC,WAAW,CAAC,EAAE;QAClE,CAAC,CAAC,EAAE,CAAC;IACP,OAAO,SAAS,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,WAAW,EAAE,CAAC,CAAC;AACvH,CAAC;AAiBD,qGAAqG;AACrG,SAAgB,8BAA8B,CAAC,OAAyC;IACtF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,GAAG,CAAC,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnN,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;GAGG;AACH,SAAgB,yBAAyB,CAAC,MAazC;IACC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC;IAC9E,MAAM,KAAK,GAAG;QACZ,MAAM,CAAC,CAAC,CAAC,mCAA2B,CAAC,CAAC,CAAC,gCAAwB;QAC/D,QAAQ,MAAM,CAAC,IAAI,EAAE;QACrB,aAAa,MAAM,CAAC,gBAAgB,CAAC,WAAW,EAAE,EAAE;QACpD,OAAO,MAAM,CAAC,GAAG,EAAE;QACnB,QAAQ,MAAM,CAAC,IAAI,EAAE;QACrB,OAAO,MAAM,CAAC,GAAG,EAAE;QACnB,OAAO,MAAM,CAAC,GAAG,EAAE;QACnB,OAAO,MAAM,CAAC,GAAG,EAAE;QACnB,QAAQ,MAAM,CAAC,MAAM,EAAE;QACvB,UAAU,MAAM,CAAC,YAAY,EAAE;KAChC,CAAC;IACF,IAAI,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,eAAe,CAAC,MAAM,CAAC,SAAkC,CAAC,EAAE,EAAE,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1H,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* recovery-seal — seal an agent's wallet key to its recovering human's phone anchor,
|
|
3
|
+
* with node:crypto ONLY, byte-for-byte the SDK's `sealToAnchor` (provian-agent-sdk/src/agent-key-recovery.ts,
|
|
4
|
+
* itself byte-identical to the app's copy). A pinned vector in recovery-seal.test.ts holds the three equal.
|
|
5
|
+
*
|
|
6
|
+
* SHARED CORE — canonical in `provian-mcp/src/core/`, mirrored into `provian-backend/src/mcp/core/`
|
|
7
|
+
* by scripts/sync-mcp-core.sh. The relay's mirror never CALLS this with a key: the hosted endpoint
|
|
8
|
+
* holds no key, so in remote mode a hosted agent seals in its own runtime by the recipe below and
|
|
9
|
+
* sends only the ciphertext. Local stdio mode seals in-process with the local identity's key.
|
|
10
|
+
*
|
|
11
|
+
* Wire format (version 0x01):
|
|
12
|
+
* blob = 0x01 ‖ ephemeral_x25519_pub(32) ‖ XChaCha20-Poly1305(key, nonce, aad, privkey32) (‖ 16-byte tag)
|
|
13
|
+
* shared = X25519(ephemeral_secret, anchor_pub)
|
|
14
|
+
* okm = HKDF-SHA256(ikm = shared, salt = ephemeral_pub ‖ anchor_pub, info = "provian-agent-recovery-v1", 56)
|
|
15
|
+
* key = okm[0..32), nonce = okm[32..56)
|
|
16
|
+
* aad = 0x01 ‖ anchor_pub
|
|
17
|
+
* XChaCha20-Poly1305 = ChaCha20-Poly1305 (IETF) under subkey HChaCha20(key, nonce[0..16)) with the
|
|
18
|
+
* 12-byte nonce 0x00000000 ‖ nonce[16..24) — the construction libsodium and @noble/ciphers use.
|
|
19
|
+
*/
|
|
20
|
+
export declare const RECOVERY_SEAL_VERSION = 1;
|
|
21
|
+
/** The recipe a hosted agent follows in its own runtime (served in the MCP tool descriptions). */
|
|
22
|
+
export declare const RECOVERY_SEAL_RECIPE: {
|
|
23
|
+
readonly plaintext: "your 32-byte secp256k1 private key (raw bytes, not hex text)";
|
|
24
|
+
readonly anchor: "recovery_anchor_pubkey: base64url (no padding) of a 32-byte X25519 public key";
|
|
25
|
+
readonly steps: readonly ["eph_secret = 32 random bytes; eph_pub = X25519 public key of eph_secret", "shared = X25519(eph_secret, anchor)", "okm = HKDF-SHA256(ikm=shared, salt=eph_pub||anchor, info=UTF-8 \"provian-agent-recovery-v1\", length=56); key = okm[0:32], nonce = okm[32:56]", "aad = 0x01 || anchor", "ct = XChaCha20-Poly1305(key, nonce, aad).encrypt(private_key) — ciphertext followed by the 16-byte tag (libsodium crypto_aead_xchacha20poly1305_ietf_encrypt)", "sealed_key_blob = base64url-nopad(0x01 || eph_pub || ct) (81 bytes → 108 characters)"];
|
|
26
|
+
readonly never: "Never send the private key itself, to any tool. Only sealed_key_blob leaves your runtime.";
|
|
27
|
+
};
|
|
28
|
+
/** HChaCha20(key32, nonce16) → 32-byte subkey (RFC draft-irtf-cfrg-xchacha §2.2). */
|
|
29
|
+
export declare function hchacha20(key: Buffer, nonce16: Buffer): Buffer;
|
|
30
|
+
export declare function xchacha20poly1305Encrypt(key: Buffer, nonce24: Buffer, aad: Buffer, plaintext: Buffer): Buffer;
|
|
31
|
+
/**
|
|
32
|
+
* Seal `privateKeyHex` (32-byte secp256k1 key, hex) to `anchorPubkeyB64u`. Returns the base64url
|
|
33
|
+
* sealed blob the relay stores as `sealed_key_blob`. `ephemeralSecret` is a test seam (pinned vector).
|
|
34
|
+
*/
|
|
35
|
+
export declare function sealToRecoveryAnchor(anchorPubkeyB64u: string, privateKeyHex: string, ephemeralSecret?: Buffer): string;
|
|
36
|
+
//# sourceMappingURL=recovery-seal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-seal.d.ts","sourceRoot":"","sources":["../../src/core/recovery-seal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAWH,eAAO,MAAM,qBAAqB,IAAO,CAAC;AAK1C,kGAAkG;AAClG,eAAO,MAAM,oBAAoB;;;;;CAYvB,CAAC;AAWX,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAmB9D;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ7G;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,gBAAgB,EAAE,MAAM,EACxB,aAAa,EAAE,MAAM,EACrB,eAAe,GAAE,MAA4B,GAC5C,MAAM,CAcR"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* recovery-seal — seal an agent's wallet key to its recovering human's phone anchor,
|
|
4
|
+
* with node:crypto ONLY, byte-for-byte the SDK's `sealToAnchor` (provian-agent-sdk/src/agent-key-recovery.ts,
|
|
5
|
+
* itself byte-identical to the app's copy). A pinned vector in recovery-seal.test.ts holds the three equal.
|
|
6
|
+
*
|
|
7
|
+
* SHARED CORE — canonical in `provian-mcp/src/core/`, mirrored into `provian-backend/src/mcp/core/`
|
|
8
|
+
* by scripts/sync-mcp-core.sh. The relay's mirror never CALLS this with a key: the hosted endpoint
|
|
9
|
+
* holds no key, so in remote mode a hosted agent seals in its own runtime by the recipe below and
|
|
10
|
+
* sends only the ciphertext. Local stdio mode seals in-process with the local identity's key.
|
|
11
|
+
*
|
|
12
|
+
* Wire format (version 0x01):
|
|
13
|
+
* blob = 0x01 ‖ ephemeral_x25519_pub(32) ‖ XChaCha20-Poly1305(key, nonce, aad, privkey32) (‖ 16-byte tag)
|
|
14
|
+
* shared = X25519(ephemeral_secret, anchor_pub)
|
|
15
|
+
* okm = HKDF-SHA256(ikm = shared, salt = ephemeral_pub ‖ anchor_pub, info = "provian-agent-recovery-v1", 56)
|
|
16
|
+
* key = okm[0..32), nonce = okm[32..56)
|
|
17
|
+
* aad = 0x01 ‖ anchor_pub
|
|
18
|
+
* XChaCha20-Poly1305 = ChaCha20-Poly1305 (IETF) under subkey HChaCha20(key, nonce[0..16)) with the
|
|
19
|
+
* 12-byte nonce 0x00000000 ‖ nonce[16..24) — the construction libsodium and @noble/ciphers use.
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.RECOVERY_SEAL_RECIPE = exports.RECOVERY_SEAL_VERSION = void 0;
|
|
23
|
+
exports.hchacha20 = hchacha20;
|
|
24
|
+
exports.xchacha20poly1305Encrypt = xchacha20poly1305Encrypt;
|
|
25
|
+
exports.sealToRecoveryAnchor = sealToRecoveryAnchor;
|
|
26
|
+
const node_crypto_1 = require("node:crypto");
|
|
27
|
+
exports.RECOVERY_SEAL_VERSION = 0x01;
|
|
28
|
+
const HKDF_INFO = Buffer.from('provian-agent-recovery-v1', 'utf8');
|
|
29
|
+
const X25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b656e04220420', 'hex');
|
|
30
|
+
const X25519_SPKI_PREFIX = Buffer.from('302a300506032b656e032100', 'hex');
|
|
31
|
+
/** The recipe a hosted agent follows in its own runtime (served in the MCP tool descriptions). */
|
|
32
|
+
exports.RECOVERY_SEAL_RECIPE = {
|
|
33
|
+
plaintext: 'your 32-byte secp256k1 private key (raw bytes, not hex text)',
|
|
34
|
+
anchor: 'recovery_anchor_pubkey: base64url (no padding) of a 32-byte X25519 public key',
|
|
35
|
+
steps: [
|
|
36
|
+
'eph_secret = 32 random bytes; eph_pub = X25519 public key of eph_secret',
|
|
37
|
+
'shared = X25519(eph_secret, anchor)',
|
|
38
|
+
'okm = HKDF-SHA256(ikm=shared, salt=eph_pub||anchor, info=UTF-8 "provian-agent-recovery-v1", length=56); key = okm[0:32], nonce = okm[32:56]',
|
|
39
|
+
'aad = 0x01 || anchor',
|
|
40
|
+
'ct = XChaCha20-Poly1305(key, nonce, aad).encrypt(private_key) — ciphertext followed by the 16-byte tag (libsodium crypto_aead_xchacha20poly1305_ietf_encrypt)',
|
|
41
|
+
'sealed_key_blob = base64url-nopad(0x01 || eph_pub || ct) (81 bytes → 108 characters)',
|
|
42
|
+
],
|
|
43
|
+
never: 'Never send the private key itself, to any tool. Only sealed_key_blob leaves your runtime.',
|
|
44
|
+
};
|
|
45
|
+
function b64uDecode(value) {
|
|
46
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value))
|
|
47
|
+
throw new Error('not base64url');
|
|
48
|
+
return Buffer.from(value, 'base64url');
|
|
49
|
+
}
|
|
50
|
+
function rotl(v, n) {
|
|
51
|
+
return ((v << n) | (v >>> (32 - n))) >>> 0;
|
|
52
|
+
}
|
|
53
|
+
/** HChaCha20(key32, nonce16) → 32-byte subkey (RFC draft-irtf-cfrg-xchacha §2.2). */
|
|
54
|
+
function hchacha20(key, nonce16) {
|
|
55
|
+
if (key.length !== 32 || nonce16.length !== 16)
|
|
56
|
+
throw new Error('hchacha20: key 32 / nonce 16 bytes');
|
|
57
|
+
const s = new Uint32Array(16);
|
|
58
|
+
s[0] = 0x61707865;
|
|
59
|
+
s[1] = 0x3320646e;
|
|
60
|
+
s[2] = 0x79622d32;
|
|
61
|
+
s[3] = 0x6b206574;
|
|
62
|
+
for (let i = 0; i < 8; i += 1)
|
|
63
|
+
s[4 + i] = key.readUInt32LE(i * 4);
|
|
64
|
+
for (let i = 0; i < 4; i += 1)
|
|
65
|
+
s[12 + i] = nonce16.readUInt32LE(i * 4);
|
|
66
|
+
const qr = (a, b, c, d) => {
|
|
67
|
+
s[a] = (s[a] + s[b]) >>> 0;
|
|
68
|
+
s[d] = rotl(s[d] ^ s[a], 16);
|
|
69
|
+
s[c] = (s[c] + s[d]) >>> 0;
|
|
70
|
+
s[b] = rotl(s[b] ^ s[c], 12);
|
|
71
|
+
s[a] = (s[a] + s[b]) >>> 0;
|
|
72
|
+
s[d] = rotl(s[d] ^ s[a], 8);
|
|
73
|
+
s[c] = (s[c] + s[d]) >>> 0;
|
|
74
|
+
s[b] = rotl(s[b] ^ s[c], 7);
|
|
75
|
+
};
|
|
76
|
+
for (let i = 0; i < 10; i += 1) {
|
|
77
|
+
qr(0, 4, 8, 12);
|
|
78
|
+
qr(1, 5, 9, 13);
|
|
79
|
+
qr(2, 6, 10, 14);
|
|
80
|
+
qr(3, 7, 11, 15);
|
|
81
|
+
qr(0, 5, 10, 15);
|
|
82
|
+
qr(1, 6, 11, 12);
|
|
83
|
+
qr(2, 7, 8, 13);
|
|
84
|
+
qr(3, 4, 9, 14);
|
|
85
|
+
}
|
|
86
|
+
const out = Buffer.alloc(32);
|
|
87
|
+
[0, 1, 2, 3, 12, 13, 14, 15].forEach((w, i) => out.writeUInt32LE(s[w], i * 4));
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
function xchacha20poly1305Encrypt(key, nonce24, aad, plaintext) {
|
|
91
|
+
if (nonce24.length !== 24)
|
|
92
|
+
throw new Error('xchacha20poly1305: nonce must be 24 bytes');
|
|
93
|
+
const subkey = hchacha20(key, nonce24.subarray(0, 16));
|
|
94
|
+
const nonce12 = Buffer.concat([Buffer.alloc(4), nonce24.subarray(16, 24)]);
|
|
95
|
+
const cipher = (0, node_crypto_1.createCipheriv)('chacha20-poly1305', subkey, nonce12, { authTagLength: 16 });
|
|
96
|
+
cipher.setAAD(aad, { plaintextLength: plaintext.length });
|
|
97
|
+
const ct = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
98
|
+
return Buffer.concat([ct, cipher.getAuthTag()]);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Seal `privateKeyHex` (32-byte secp256k1 key, hex) to `anchorPubkeyB64u`. Returns the base64url
|
|
102
|
+
* sealed blob the relay stores as `sealed_key_blob`. `ephemeralSecret` is a test seam (pinned vector).
|
|
103
|
+
*/
|
|
104
|
+
function sealToRecoveryAnchor(anchorPubkeyB64u, privateKeyHex, ephemeralSecret = (0, node_crypto_1.randomBytes)(32)) {
|
|
105
|
+
const anchor = b64uDecode(anchorPubkeyB64u);
|
|
106
|
+
if (anchor.length !== 32)
|
|
107
|
+
throw new Error('recovery anchor must be a 32-byte X25519 public key');
|
|
108
|
+
const keyHex = privateKeyHex.replace(/^0x/, '');
|
|
109
|
+
if (!/^[0-9a-fA-F]{64}$/.test(keyHex))
|
|
110
|
+
throw new Error('private key must be 32 bytes of hex');
|
|
111
|
+
if (ephemeralSecret.length !== 32)
|
|
112
|
+
throw new Error('ephemeral secret must be 32 bytes');
|
|
113
|
+
const ephPrivate = (0, node_crypto_1.createPrivateKey)({ key: Buffer.concat([X25519_PKCS8_PREFIX, ephemeralSecret]), format: 'der', type: 'pkcs8' });
|
|
114
|
+
const ephPub = Buffer.from((0, node_crypto_1.createPublicKey)(ephPrivate).export({ format: 'der', type: 'spki' })).subarray(-32);
|
|
115
|
+
const anchorKey = (0, node_crypto_1.createPublicKey)({ key: Buffer.concat([X25519_SPKI_PREFIX, anchor]), format: 'der', type: 'spki' });
|
|
116
|
+
const shared = (0, node_crypto_1.diffieHellman)({ privateKey: ephPrivate, publicKey: anchorKey });
|
|
117
|
+
const okm = Buffer.from((0, node_crypto_1.hkdfSync)('sha256', shared, Buffer.concat([ephPub, anchor]), HKDF_INFO, 56));
|
|
118
|
+
const aad = Buffer.concat([Buffer.of(exports.RECOVERY_SEAL_VERSION), anchor]);
|
|
119
|
+
const ct = xchacha20poly1305Encrypt(okm.subarray(0, 32), okm.subarray(32, 56), aad, Buffer.from(keyHex, 'hex'));
|
|
120
|
+
return Buffer.concat([Buffer.of(exports.RECOVERY_SEAL_VERSION), ephPub, ct]).toString('base64url');
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=recovery-seal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery-seal.js","sourceRoot":"","sources":["../../src/core/recovery-seal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server assembly over the Provian tool core.
|
|
3
|
+
*
|
|
4
|
+
* SHARED CORE — canonical in `provian-mcp/src/core/`, mirrored into
|
|
5
|
+
* `provian-backend/src/mcp/core/`. Edit only the canonical copy.
|
|
6
|
+
*
|
|
7
|
+
* Both transports call this: the stdio entrypoint (npx @provian/mcp) serves the
|
|
8
|
+
* returned Server through `serveStdio`; the relay's /mcp route serves a fresh
|
|
9
|
+
* instance per request through `createMcpHandler`. Identical tool list,
|
|
10
|
+
* identical handlers.
|
|
11
|
+
*
|
|
12
|
+
* PROTOCOL: MCP TS SDK v2, opting into revision 2026-07-28. The serving entries
|
|
13
|
+
* (`serveStdio` / `createMcpHandler`) own the era decision per connection /
|
|
14
|
+
* request, so ONE factory serves BOTH a modern 2026-07-28 client (stateless,
|
|
15
|
+
* `_meta`-versioned, `server/discover`, `resultType`, cacheable list results)
|
|
16
|
+
* AND a current-era client that opens with the 2025 `initialize` handshake.
|
|
17
|
+
* Version negotiation, required-header validation, `resultType` stamping and
|
|
18
|
+
* cache-hint attachment all live in the SDK; this module only registers the two
|
|
19
|
+
* tool methods and the per-operation cache hint.
|
|
20
|
+
*/
|
|
21
|
+
import { Server } from '@modelcontextprotocol/server';
|
|
22
|
+
import type { ToolContext } from './types';
|
|
23
|
+
/**
|
|
24
|
+
* The initialize `instructions`, LED by the Genesis offer line while the window is
|
|
25
|
+
* open (runtime date check — the line drops out at the window's end, no redeploy).
|
|
26
|
+
* Evaluated per server instance: the hosted relay builds one per request, stdio one
|
|
27
|
+
* per connection.
|
|
28
|
+
*/
|
|
29
|
+
export declare function serverInstructions(nowMs?: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* Build a Provian MCP Server wired to the shared tool set.
|
|
32
|
+
*
|
|
33
|
+
* @param getContext Resolves the per-call ToolContext (credentials, base URL,
|
|
34
|
+
* mode). Called once per tool invocation so remote requests
|
|
35
|
+
* can carry per-caller auth.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildProvianMcpServer(getContext: () => ToolContext | Promise<ToolContext>): Server;
|
|
38
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAGtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA6B3C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,MAAmB,GAAG,MAAM,CAErE;AAaD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,GACnD,MAAM,CAiCR"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server assembly over the Provian tool core.
|
|
4
|
+
*
|
|
5
|
+
* SHARED CORE — canonical in `provian-mcp/src/core/`, mirrored into
|
|
6
|
+
* `provian-backend/src/mcp/core/`. Edit only the canonical copy.
|
|
7
|
+
*
|
|
8
|
+
* Both transports call this: the stdio entrypoint (npx @provian/mcp) serves the
|
|
9
|
+
* returned Server through `serveStdio`; the relay's /mcp route serves a fresh
|
|
10
|
+
* instance per request through `createMcpHandler`. Identical tool list,
|
|
11
|
+
* identical handlers.
|
|
12
|
+
*
|
|
13
|
+
* PROTOCOL: MCP TS SDK v2, opting into revision 2026-07-28. The serving entries
|
|
14
|
+
* (`serveStdio` / `createMcpHandler`) own the era decision per connection /
|
|
15
|
+
* request, so ONE factory serves BOTH a modern 2026-07-28 client (stateless,
|
|
16
|
+
* `_meta`-versioned, `server/discover`, `resultType`, cacheable list results)
|
|
17
|
+
* AND a current-era client that opens with the 2025 `initialize` handshake.
|
|
18
|
+
* Version negotiation, required-header validation, `resultType` stamping and
|
|
19
|
+
* cache-hint attachment all live in the SDK; this module only registers the two
|
|
20
|
+
* tool methods and the per-operation cache hint.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.serverInstructions = serverInstructions;
|
|
24
|
+
exports.buildProvianMcpServer = buildProvianMcpServer;
|
|
25
|
+
const server_1 = require("@modelcontextprotocol/server");
|
|
26
|
+
const tools_1 = require("./tools");
|
|
27
|
+
const genesis_offer_1 = require("./genesis-offer");
|
|
28
|
+
const SERVER_INSTRUCTIONS = 'Provian is the trust layer for the intelligence economy: agents carry verifiable, hash-chained proof ' +
|
|
29
|
+
'they own (Provenance Envelopes), and every act of work mints PVT once at its best-supported value. A PE lives ' +
|
|
30
|
+
'with its owner: the observer keeps it on the machine that witnessed it. The relay keeps totals, identity and ' +
|
|
31
|
+
'integrity state, compact batch economics, output trust rows and owner-encrypted copies until ACK; proving a specific act later requires keeping ' +
|
|
32
|
+
'its PE. Local stdio ' +
|
|
33
|
+
'can start with create_wallet, which encrypts a relay-bound pending identity before networking and returns ' +
|
|
34
|
+
'api_key/api_secret. Remote create_wallet is disabled before key generation; a hosted agent instead generates its ' +
|
|
35
|
+
'own key in its own runtime and calls wallet_challenge (with its link code) then wallet_create with only the public ' +
|
|
36
|
+
'key, a signature and its key sealed to the recovery anchor the challenge names (ciphertext only: wallet_create ' +
|
|
37
|
+
'escrows it at birth; otherwise recovery_escrow right after — escrow is how the linked human can restore the ' +
|
|
38
|
+
'agent\'s key if its runtime or key is lost, and it never holds earnings), then request_link with its human\'s link code. ' +
|
|
39
|
+
'With no code from a human, the agent calls invite_human with the human\'s email: the human accepts from the email in the ' +
|
|
40
|
+
'Provian app and becomes its beneficiary (invite sends someone the app, and they can link from it too; invite_device sets up a computer for this ' +
|
|
41
|
+
'agent). Authenticated tools take the API credential api_key:api_secret on ' +
|
|
42
|
+
'the remote endpoint as `Authorization: Bearer …`, `X-API-Key` or `x-provian-api-key` (a connector\'s API-key ' +
|
|
43
|
+
'field), or PROVIAN_API_KEY/PROVIAN_API_SECRET in the local server environment. A PROV- link code is never a ' +
|
|
44
|
+
'credential. People and agents message you in end-to-end encrypted Commons threads. The observer receives ' +
|
|
45
|
+
'authenticated events, decrypts each message locally and dispatches a turn through your OpenClaw agent or ' +
|
|
46
|
+
'~/.provian/commons-runtime.json adapter. It acknowledges only confirmed completion and recovers without ' +
|
|
47
|
+
'repeating replies. Follow the owner’s reply_policy: under ask_me_first, answer your linked human directly ' +
|
|
48
|
+
'and request_human_approval before replying to anyone else. No Commons heartbeat is needed. Manual reads use ' +
|
|
49
|
+
'read_threads with unread: true, or ~/.provian/bin/provian threads --unread. Without a local observer/runtime, ' +
|
|
50
|
+
'read threads on turns you already run; never schedule a model turn just to look for mail. Full REST catalog: https://api.provian.ai/v1/openapi.json — ' +
|
|
51
|
+
'human-readable index: https://provian.ai/llms.txt';
|
|
52
|
+
/**
|
|
53
|
+
* The initialize `instructions`, LED by the Genesis offer line while the window is
|
|
54
|
+
* open (runtime date check — the line drops out at the window's end, no redeploy).
|
|
55
|
+
* Evaluated per server instance: the hosted relay builds one per request, stdio one
|
|
56
|
+
* per connection.
|
|
57
|
+
*/
|
|
58
|
+
function serverInstructions(nowMs = Date.now()) {
|
|
59
|
+
return [...(0, genesis_offer_1.genesisOfferLines)(nowMs), SERVER_INSTRUCTIONS].join(' ');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Freshness hint (ms) for the cacheable list results under the 2026-07-28
|
|
63
|
+
* `CacheableResult` contract (SEP-2549). The Provian tool set is fixed for the
|
|
64
|
+
* life of a running server and only ever changes on redeploy/republish, so a
|
|
65
|
+
* few-minutes hint lets a modern client cache `tools/list` without ever going
|
|
66
|
+
* stale within a deploy. `cacheScope: 'private'` because every surface that
|
|
67
|
+
* may carry caller-specific context, so a shared intermediary must not cache the response.
|
|
68
|
+
* Both fields are ignored for 2025-era responses.
|
|
69
|
+
*/
|
|
70
|
+
const TOOLS_LIST_CACHE_TTL_MS = 300000;
|
|
71
|
+
/**
|
|
72
|
+
* Build a Provian MCP Server wired to the shared tool set.
|
|
73
|
+
*
|
|
74
|
+
* @param getContext Resolves the per-call ToolContext (credentials, base URL,
|
|
75
|
+
* mode). Called once per tool invocation so remote requests
|
|
76
|
+
* can carry per-caller auth.
|
|
77
|
+
*/
|
|
78
|
+
function buildProvianMcpServer(getContext) {
|
|
79
|
+
const server = new server_1.Server({ name: tools_1.PROVIAN_MCP_SERVER_NAME, version: tools_1.PROVIAN_MCP_VERSION }, {
|
|
80
|
+
capabilities: { tools: {} },
|
|
81
|
+
instructions: serverInstructions(),
|
|
82
|
+
// 2026-07-28 cache hints. Absent hints default to {ttlMs:0, cacheScope:'private'};
|
|
83
|
+
// this makes the tools/list ttl explicit and deploy-static.
|
|
84
|
+
cacheHints: { 'tools/list': { ttlMs: TOOLS_LIST_CACHE_TTL_MS, cacheScope: 'private' } },
|
|
85
|
+
});
|
|
86
|
+
// Deterministic tools/list ordering (2026-07-28 SHOULD, SEP-2549): PROVIAN_TOOLS
|
|
87
|
+
// is a fixed source-order array, so the emitted order is stable across calls
|
|
88
|
+
// and processes, which lets modern clients cache the listing.
|
|
89
|
+
server.setRequestHandler('tools/list', async () => ({
|
|
90
|
+
tools: tools_1.PROVIAN_TOOLS.map((t) => ({
|
|
91
|
+
name: t.name,
|
|
92
|
+
description: t.description,
|
|
93
|
+
// Every ProvianToolDef.inputSchema is a `{ type: 'object', ... }` JSON
|
|
94
|
+
// Schema; the shared-core type is the transport-agnostic Record, so narrow
|
|
95
|
+
// to the SDK's Tool schema shape here (the one SDK-coupled cast).
|
|
96
|
+
inputSchema: t.inputSchema,
|
|
97
|
+
})),
|
|
98
|
+
}));
|
|
99
|
+
server.setRequestHandler('tools/call', async (request) => {
|
|
100
|
+
const ctx = await getContext();
|
|
101
|
+
const args = (request.params.arguments ?? {});
|
|
102
|
+
return (0, tools_1.callProvianTool)(request.params.name, args, ctx);
|
|
103
|
+
});
|
|
104
|
+
return server;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;AAwCH,gDAEC;AAoBD,sDAmCC;AA/FD,yDAAsD;AAEtD,mCAAuG;AAEvG,mDAAoD;AAEpD,MAAM,mBAAmB,GACvB,uGAAuG;IACvG,gHAAgH;IAChH,+GAA+G;IAC/G,kJAAkJ;IAClJ,sBAAsB;IACtB,4GAA4G;IAC5G,mHAAmH;IACnH,qHAAqH;IACrH,iHAAiH;IACjH,8GAA8G;IAC9G,2HAA2H;IAC3H,2HAA2H;IAC3H,kJAAkJ;IAClJ,4EAA4E;IAC5E,+GAA+G;IAC/G,8GAA8G;IAC9G,2GAA2G;IAC3G,2GAA2G;IAC3G,0GAA0G;IAC1G,4GAA4G;IAC5G,8GAA8G;IAC9G,gHAAgH;IAChH,wJAAwJ;IACxJ,mDAAmD,CAAC;AAEtD;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,QAAgB,IAAI,CAAC,GAAG,EAAE;IAC3D,OAAO,CAAC,GAAG,IAAA,iCAAiB,EAAC,KAAK,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,uBAAuB,GAAG,MAAO,CAAC;AAExC;;;;;;GAMG;AACH,SAAgB,qBAAqB,CACnC,UAAoD;IAEpD,MAAM,MAAM,GAAG,IAAI,eAAM,CACvB,EAAE,IAAI,EAAE,+BAAuB,EAAE,OAAO,EAAE,2BAAmB,EAAE,EAC/D;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,YAAY,EAAE,kBAAkB,EAAE;QAClC,mFAAmF;QACnF,4DAA4D;QAC5D,UAAU,EAAE,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE;KACxF,CACF,CAAC;IAEF,iFAAiF;IACjF,6EAA6E;IAC7E,8DAA8D;IAC9D,MAAM,CAAC,iBAAiB,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAClD,KAAK,EAAE,qBAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,uEAAuE;YACvE,2EAA2E;YAC3E,kEAAkE;YAClE,WAAW,EAAE,CAAC,CAAC,WAAkC;SAClD,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAA2B,EAAE;QAChF,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,CAA4B,CAAC;QACzE,OAAO,IAAA,uBAAe,EAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type OutputSignature } from './output-signature';
|
|
2
|
+
export interface ThreadTextView {
|
|
3
|
+
text: string | null;
|
|
4
|
+
provian_output_signature: OutputSignature | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function readThreadPlaintext(plaintext: string): ThreadTextView;
|
|
7
|
+
export declare function decryptLocalThreadMessage(privateKeyHex: string, ciphertext: string): ThreadTextView;
|
|
8
|
+
//# sourceMappingURL=thread-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-reader.d.ts","sourceRoot":"","sources":["../../src/core/thread-reader.ts"],"names":[],"mappings":"AAGA,OAAO,EAA8B,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEtF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,wBAAwB,EAAE,eAAe,GAAG,IAAI,CAAC;CAClD;AAED,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAGrE;AAED,wBAAgB,yBAAyB,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,CAwBnG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readThreadPlaintext = readThreadPlaintext;
|
|
4
|
+
exports.decryptLocalThreadMessage = decryptLocalThreadMessage;
|
|
5
|
+
/** Local-only decryption, compatible with the SDK's sealed thread boxes. */
|
|
6
|
+
const node_crypto_1 = require("node:crypto");
|
|
7
|
+
const recovery_seal_1 = require("./recovery-seal");
|
|
8
|
+
const output_signature_1 = require("./output-signature");
|
|
9
|
+
function readThreadPlaintext(plaintext) {
|
|
10
|
+
const { text, signature } = (0, output_signature_1.splitThreadOutputSignature)(plaintext);
|
|
11
|
+
return { text, provian_output_signature: signature };
|
|
12
|
+
}
|
|
13
|
+
function decryptLocalThreadMessage(privateKeyHex, ciphertext) {
|
|
14
|
+
const key = Buffer.from(privateKeyHex.replace(/^0x/, ''), 'hex');
|
|
15
|
+
if (key.length !== 32 || !/^[A-Za-z0-9_-]+$/.test(ciphertext))
|
|
16
|
+
throw new Error('invalid thread key or ciphertext');
|
|
17
|
+
const secret = Buffer.from((0, node_crypto_1.hkdfSync)('sha256', key, Buffer.from('provian-thread-msgkey-v1'), Buffer.from('provian.thread.msgkey.v1'), 32));
|
|
18
|
+
const privateKey = (0, node_crypto_1.createPrivateKey)({ key: Buffer.concat([Buffer.from('302e020100300506032b656e04220420', 'hex'), secret]), type: 'pkcs8', format: 'der' });
|
|
19
|
+
const pubkey = Buffer.from((0, node_crypto_1.createPublicKey)(privateKey).export({ type: 'spki', format: 'der' })).subarray(-32);
|
|
20
|
+
const blob = Buffer.from(ciphertext, 'base64url');
|
|
21
|
+
if (blob.length < 49 || blob[0] !== 1)
|
|
22
|
+
throw new Error('invalid thread ciphertext');
|
|
23
|
+
let shared;
|
|
24
|
+
let okm;
|
|
25
|
+
let subkey;
|
|
26
|
+
try {
|
|
27
|
+
const ephemeral = blob.subarray(1, 33);
|
|
28
|
+
const publicKey = (0, node_crypto_1.createPublicKey)({ key: Buffer.concat([Buffer.from('302a300506032b656e032100', 'hex'), ephemeral]), type: 'spki', format: 'der' });
|
|
29
|
+
shared = (0, node_crypto_1.diffieHellman)({ privateKey, publicKey });
|
|
30
|
+
okm = Buffer.from((0, node_crypto_1.hkdfSync)('sha256', shared, Buffer.concat([ephemeral, pubkey]), Buffer.from('provian-agent-recovery-v1'), 56));
|
|
31
|
+
const nonce = okm.subarray(32);
|
|
32
|
+
subkey = (0, recovery_seal_1.hchacha20)(okm.subarray(0, 32), nonce.subarray(0, 16));
|
|
33
|
+
const decipher = (0, node_crypto_1.createDecipheriv)('chacha20-poly1305', subkey, Buffer.concat([Buffer.alloc(4), nonce.subarray(16)]), { authTagLength: 16 });
|
|
34
|
+
const body = blob.subarray(33, -16);
|
|
35
|
+
decipher.setAuthTag(blob.subarray(-16));
|
|
36
|
+
decipher.setAAD(Buffer.concat([Buffer.of(1), pubkey]), { plaintextLength: body.length });
|
|
37
|
+
return readThreadPlaintext(Buffer.concat([decipher.update(body), decipher.final()]).toString('utf8'));
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
key.fill(0);
|
|
41
|
+
secret.fill(0);
|
|
42
|
+
shared?.fill(0);
|
|
43
|
+
okm?.fill(0);
|
|
44
|
+
subkey?.fill(0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=thread-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-reader.js","sourceRoot":"","sources":["../../src/core/thread-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ToolSetDiff {
|
|
2
|
+
/** Registered tools the served list omits. */
|
|
3
|
+
readonly missing: string[];
|
|
4
|
+
/** Served names the registry does not register. */
|
|
5
|
+
readonly extra: string[];
|
|
6
|
+
/** Names the served list carries more than once. */
|
|
7
|
+
readonly duplicates: string[];
|
|
8
|
+
}
|
|
9
|
+
/** The registered tool names, sorted — the single source every pin compares against. */
|
|
10
|
+
export declare function registeredToolNames(): string[];
|
|
11
|
+
export declare function diffToolSet(served: readonly string[], registered?: readonly string[]): ToolSetDiff;
|
|
12
|
+
/** Throws unless `served` is exactly the registered set, once each, over a non-empty registry. */
|
|
13
|
+
export declare function assertServedToolSet(served: readonly string[], registered?: readonly string[]): void;
|
|
14
|
+
export interface KeyFieldViolation {
|
|
15
|
+
readonly tool: string;
|
|
16
|
+
readonly field: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Every input, across the given tools, that names private key material and is not the one
|
|
20
|
+
* declared local-only field. Empty means no tool schema accepts a private key. The input
|
|
21
|
+
* type is wide on purpose (any name + schema) so a violating registry is constructible in
|
|
22
|
+
* the RED control.
|
|
23
|
+
*/
|
|
24
|
+
export declare function privateKeyFieldViolations(tools?: ReadonlyArray<{
|
|
25
|
+
name: string;
|
|
26
|
+
inputSchema: Record<string, unknown>;
|
|
27
|
+
}>): KeyFieldViolation[];
|
|
28
|
+
//# sourceMappingURL=tool-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-set.d.ts","sourceRoot":"","sources":["../../src/core/tool-set.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,UAAU,GAAE,SAAS,MAAM,EAA0B,GACpD,WAAW,CAcb;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,UAAU,GAAE,SAAS,MAAM,EAA0B,GACpD,IAAI,CAWN;AAMD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,GAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAiB,GAC3F,iBAAiB,EAAE,CASrB"}
|