@supercuts-walrus/backend 0.0.0-stage → 0.1.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.
Files changed (155) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +249 -2
  3. package/dist/audit.d.ts +52 -0
  4. package/dist/audit.js +157 -0
  5. package/dist/backend.d.ts +27 -0
  6. package/dist/backend.js +62 -0
  7. package/dist/buyer-setup.d.ts +6 -0
  8. package/dist/buyer-setup.js +241 -0
  9. package/dist/capability.d.ts +32 -0
  10. package/dist/capability.js +87 -0
  11. package/dist/claude.d.ts +44 -0
  12. package/dist/claude.js +98 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +32 -0
  15. package/dist/config.d.ts +20 -0
  16. package/dist/config.js +58 -0
  17. package/dist/dashboard.d.ts +5 -0
  18. package/dist/dashboard.js +21 -0
  19. package/dist/deal-adapter.d.ts +3 -0
  20. package/dist/deal-adapter.js +39 -0
  21. package/dist/deal-engine.d.ts +62 -0
  22. package/dist/deal-engine.js +211 -0
  23. package/dist/deal-wire.d.ts +16 -0
  24. package/dist/deal-wire.js +65 -0
  25. package/dist/deal.d.ts +79 -0
  26. package/dist/deal.js +228 -0
  27. package/dist/demo.d.ts +2 -0
  28. package/dist/demo.js +511 -0
  29. package/dist/errors.d.ts +6 -0
  30. package/dist/errors.js +13 -0
  31. package/dist/events.d.ts +27 -0
  32. package/dist/events.js +68 -0
  33. package/dist/facilitator.d.ts +21 -0
  34. package/dist/facilitator.js +173 -0
  35. package/dist/finality.d.ts +2 -0
  36. package/dist/finality.js +27 -0
  37. package/dist/funding.d.ts +38 -0
  38. package/dist/funding.js +78 -0
  39. package/dist/hosted-exit-cli.d.ts +2 -0
  40. package/dist/hosted-exit-cli.js +37 -0
  41. package/dist/hosted-exit.d.ts +24 -0
  42. package/dist/hosted-exit.js +70 -0
  43. package/dist/hosted-seller-import.d.ts +2 -0
  44. package/dist/hosted-seller-import.js +70 -0
  45. package/dist/hosted-seller-repository.d.ts +31 -0
  46. package/dist/hosted-seller-repository.js +214 -0
  47. package/dist/index.d.ts +37 -0
  48. package/dist/index.js +37 -0
  49. package/dist/indexer.d.ts +63 -0
  50. package/dist/indexer.js +60 -0
  51. package/dist/live-deal-ports.d.ts +41 -0
  52. package/dist/live-deal-ports.js +212 -0
  53. package/dist/live-index.d.ts +28 -0
  54. package/dist/live-index.js +149 -0
  55. package/dist/live-runtime.d.ts +85 -0
  56. package/dist/live-runtime.js +644 -0
  57. package/dist/live-seller-transport.d.ts +30 -0
  58. package/dist/live-seller-transport.js +169 -0
  59. package/dist/live-seller-verifier.d.ts +11 -0
  60. package/dist/live-seller-verifier.js +65 -0
  61. package/dist/mandate.d.ts +34 -0
  62. package/dist/mandate.js +179 -0
  63. package/dist/mcp-bootstrap.d.ts +2 -0
  64. package/dist/mcp-bootstrap.js +61 -0
  65. package/dist/mcp.d.ts +2 -0
  66. package/dist/mcp.js +207 -0
  67. package/dist/memory-worker.d.ts +2 -0
  68. package/dist/memory-worker.js +38 -0
  69. package/dist/memory.d.ts +15 -0
  70. package/dist/memory.js +17 -0
  71. package/dist/memwal.d.ts +35 -0
  72. package/dist/memwal.js +83 -0
  73. package/dist/negotiation.d.ts +23 -0
  74. package/dist/negotiation.js +58 -0
  75. package/dist/notes.d.ts +11 -0
  76. package/dist/notes.js +26 -0
  77. package/dist/onboarding-doctor.d.ts +1 -0
  78. package/dist/onboarding-doctor.js +87 -0
  79. package/dist/phase3.d.ts +100 -0
  80. package/dist/phase3.js +1174 -0
  81. package/dist/procurement.d.ts +8 -0
  82. package/dist/procurement.js +19 -0
  83. package/dist/protocol-engine.d.ts +121 -0
  84. package/dist/protocol-engine.js +149 -0
  85. package/dist/prover.d.ts +28 -0
  86. package/dist/prover.js +70 -0
  87. package/dist/relayer.d.ts +32 -0
  88. package/dist/relayer.js +43 -0
  89. package/dist/remote-buyer.d.ts +85 -0
  90. package/dist/remote-buyer.js +285 -0
  91. package/dist/resource-server.d.ts +2 -0
  92. package/dist/resource-server.js +24 -0
  93. package/dist/resource.d.ts +22 -0
  94. package/dist/resource.js +55 -0
  95. package/dist/role-lock.d.ts +8 -0
  96. package/dist/role-lock.js +54 -0
  97. package/dist/seam.d.ts +2 -0
  98. package/dist/seam.js +117 -0
  99. package/dist/seller-catalog-generate.d.ts +2 -0
  100. package/dist/seller-catalog-generate.js +68 -0
  101. package/dist/seller-database.d.ts +41 -0
  102. package/dist/seller-database.js +80 -0
  103. package/dist/seller-directory-cli.d.ts +2 -0
  104. package/dist/seller-directory-cli.js +24 -0
  105. package/dist/seller-directory.d.ts +5 -0
  106. package/dist/seller-directory.js +50 -0
  107. package/dist/seller-live-cli.d.ts +2 -0
  108. package/dist/seller-live-cli.js +53 -0
  109. package/dist/seller-package.d.ts +9 -0
  110. package/dist/seller-package.js +50 -0
  111. package/dist/seller-provision.d.ts +2 -0
  112. package/dist/seller-provision.js +84 -0
  113. package/dist/seller-register-cli.d.ts +2 -0
  114. package/dist/seller-register-cli.js +40 -0
  115. package/dist/seller-runtime.d.ts +60 -0
  116. package/dist/seller-runtime.js +96 -0
  117. package/dist/seller-service.d.ts +34 -0
  118. package/dist/seller-service.js +422 -0
  119. package/dist/seller-state.d.ts +19 -0
  120. package/dist/seller-state.js +60 -0
  121. package/dist/seller-stdio.d.ts +6 -0
  122. package/dist/seller-stdio.js +29 -0
  123. package/dist/seller-v2-provision.d.ts +2 -0
  124. package/dist/seller-v2-provision.js +71 -0
  125. package/dist/seller-watch.d.ts +2 -0
  126. package/dist/seller-watch.js +45 -0
  127. package/dist/settlement.d.ts +95 -0
  128. package/dist/settlement.js +141 -0
  129. package/dist/store.d.ts +36 -0
  130. package/dist/store.js +193 -0
  131. package/dist/sui.d.ts +49 -0
  132. package/dist/sui.js +77 -0
  133. package/dist/tatum.d.ts +17 -0
  134. package/dist/tatum.js +83 -0
  135. package/dist/transcript.d.ts +31 -0
  136. package/dist/transcript.js +52 -0
  137. package/dist/v2-exit-relayer.d.ts +34 -0
  138. package/dist/v2-exit-relayer.js +102 -0
  139. package/dist/v2-exit-worker.d.ts +2 -0
  140. package/dist/v2-exit-worker.js +97 -0
  141. package/dist/v2-exits.d.ts +30 -0
  142. package/dist/v2-exits.js +78 -0
  143. package/dist/v2-prefund.d.ts +19 -0
  144. package/dist/v2-prefund.js +43 -0
  145. package/dist/v2-relayer-cli.d.ts +2 -0
  146. package/dist/v2-relayer-cli.js +39 -0
  147. package/dist/wallet.d.ts +32 -0
  148. package/dist/wallet.js +90 -0
  149. package/dist/workflow-memory.d.ts +22 -0
  150. package/dist/workflow-memory.js +49 -0
  151. package/dist/x402-resource-service.d.ts +36 -0
  152. package/dist/x402-resource-service.js +173 -0
  153. package/dist/x402.d.ts +46 -0
  154. package/dist/x402.js +136 -0
  155. package/package.json +60 -3
@@ -0,0 +1,285 @@
1
+ import { createDecipheriv, createHash, createPrivateKey, createPublicKey, diffieHellman, hkdfSync, randomBytes } from "node:crypto";
2
+ import { isValidPersonalMessageSignature } from "@mysten/sui/verify";
3
+ import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
4
+ import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
5
+ import { validateCapabilityManifest, verifySignedCapability } from "./capability.js";
6
+ import { fail } from "./errors.js";
7
+ import { executeMandated } from "./mandate.js";
8
+ export function analysisAgreementDraft(input) {
9
+ const scalar = input.scalar ?? (() => BigInt(`0x${randomBytes(16).toString("hex")}`).toString());
10
+ return {
11
+ sessionId: input.sessionId, rail: "shielded", dealId: scalar(), revision: "1",
12
+ transcriptRootLo: BigInt(`0x${input.transcriptHash.slice(0, 32)}`).toString(),
13
+ transcriptRootHi: BigInt(`0x${input.transcriptHash.slice(32)}`).toString(),
14
+ serviceDigestLo: BigInt(`0x${input.serviceHash.slice(0, 32)}`).toString(),
15
+ serviceDigestHi: BigInt(`0x${input.serviceHash.slice(32)}`).toString(),
16
+ settlementNonceLo: scalar(), settlementNonceHi: scalar(), paymentAmount: input.paymentAmount,
17
+ blinding: scalar(), expiry: String((input.now ?? Date.now()) + 30 * 60_000),
18
+ buyerPublicKey: input.buyerPublicKey, counterparty: input.counterparty,
19
+ capabilityId: input.capabilityId, manifestHash: input.manifestHash,
20
+ };
21
+ }
22
+ import { decryptSessionMessage, encryptSessionMessage } from "./negotiation.js";
23
+ const sha256 = (value) => createHash("sha256").update(value).digest("hex");
24
+ const num = (value, name) => typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1 ? value : fail("SELLER_PREVIEW_INVALID", `${name} must be between zero and one`);
25
+ export class RemoteBuyer {
26
+ app;
27
+ mandate;
28
+ http;
29
+ #origin;
30
+ constructor(app, mandate, origin, http = fetch) {
31
+ this.app = app;
32
+ this.mandate = mandate;
33
+ this.http = http;
34
+ this.#origin = new URL(origin);
35
+ if (this.#origin.protocol !== "https:" && !(this.#origin.protocol === "http:" && ["127.0.0.1", "localhost", "::1"].includes(this.#origin.hostname)))
36
+ fail("SELLER_ORIGIN_INVALID", "seller origin must use HTTPS except on loopback");
37
+ }
38
+ async request(path, init = {}) {
39
+ let response;
40
+ for (let attempt = 0; attempt < 2; attempt++) {
41
+ try {
42
+ response = await this.http(new URL(path, this.#origin), { ...init, headers: { ...(init.body ? { "content-type": "application/json" } : {}), ...(init.headers ?? {}) }, signal: init.signal ?? AbortSignal.timeout(90_000), redirect: "error" });
43
+ }
44
+ catch (error) {
45
+ if (attempt === 0)
46
+ continue;
47
+ return fail("REMOTE_SELLER_UNAVAILABLE", "seller transport failed after retry", error);
48
+ }
49
+ if (response.status !== 503 || attempt === 1)
50
+ break;
51
+ await response.arrayBuffer();
52
+ await new Promise((done) => setTimeout(done, 3000));
53
+ }
54
+ const received = response ?? fail("REMOTE_SELLER_UNAVAILABLE", "seller did not respond");
55
+ const value = await received.json();
56
+ if (!received.ok && received.status !== 202)
57
+ fail("REMOTE_SELLER_ERROR", `seller returned ${received.status}: ${String(value.error ?? "unknown error")}`);
58
+ return value;
59
+ }
60
+ async catalog() {
61
+ const listed = await this.request("/v1/catalog"), entries = listed.capabilities;
62
+ if (!Array.isArray(entries) || !entries.length || entries.length > 100)
63
+ fail("SELLER_CATALOG_INVALID", "remote catalog is empty or too large");
64
+ const discovered = (await this.app.execute("capability.discover", { "blob-ids": Buffer.from(JSON.stringify(entries.map((entry) => entry.blobId))).toString("base64url") })).data.capabilities;
65
+ if (discovered.length !== entries.length)
66
+ fail("SELLER_CATALOG_INVALID", "Walrus discovery returned a different capability count");
67
+ for (let i = 0; i < entries.length; i++) {
68
+ const entry = entries[i];
69
+ validateCapabilityManifest(entry.manifest);
70
+ if (entry.manifest.manifestHash !== discovered[i].manifestHash || entry.blobId !== discovered[i].blobId || !this.mandate.allowedCounterparties.includes(entry.manifest.sellerId))
71
+ fail("SELLER_CATALOG_INVALID", "catalog differs from Walrus or owner allowlist");
72
+ await verifySignedCapability({ manifest: entry.manifest, manifestBlobId: entry.blobId, transportPublicKey: entry.transportPublicKey, sellerSignature: entry.signature });
73
+ }
74
+ return { capabilities: entries };
75
+ }
76
+ async rankBriefs(input) {
77
+ if (!/^[1-9][0-9]*$/.test(input.budget))
78
+ fail("BUYER_BUDGET_INVALID", "budget must be positive MIST");
79
+ const budget = BigInt(input.budget), catalog = await this.catalog();
80
+ const analysis = catalog.capabilities.find((entry) => entry.manifest.capability === "sui.competitor-analysis" && entry.manifest.supportedRails.includes("shielded")) ?? fail("ANALYSIS_UNAVAILABLE", "no shielded competitor analysis is available");
81
+ const analysisPrice = BigInt(analysis.manifest.priceBand.minimum), variants = analysis.preview.artifactHashes;
82
+ const candidates = catalog.capabilities.filter((entry) => {
83
+ const briefHash = entry.preview.artifactHashes?.default;
84
+ return entry.manifest.capability === "sui.market-brief" && entry.manifest.supportedRails.includes("x402") && typeof briefHash === "string" && /^[0-9a-f]{64}$/.test(briefHash) && typeof variants?.[briefHash] === "string" && BigInt(entry.manifest.priceBand.minimum) + analysisPrice <= budget;
85
+ });
86
+ if (candidates.length < 2)
87
+ fail("BRIEF_COMPARISON_UNAVAILABLE", "at least two eligible market briefs are required");
88
+ const scored = candidates.map((entry) => {
89
+ const preview = entry.preview, relevance = num(preview.relevance, "relevance"), sourceQuality = num(preview.sourceQuality, "sourceQuality"), freshnessDays = Number(preview.freshnessDays);
90
+ if (!Number.isFinite(freshnessDays) || freshnessDays < 0 || freshnessDays > 365)
91
+ fail("SELLER_PREVIEW_INVALID", "freshnessDays is invalid");
92
+ const freshness = Math.max(0, 1 - freshnessDays / 30), price = BigInt(entry.manifest.priceBand.minimum), totalPrice = price + analysisPrice, priceScore = Number((budget - totalPrice) * 1000n / budget) / 1000;
93
+ const score = Math.round((0.35 * relevance + 0.30 * sourceQuality + 0.20 * freshness + 0.15 * priceScore) * 1000) / 1000;
94
+ return { capabilityId: entry.manifest.capabilityId, sellerId: entry.manifest.sellerId, priceMist: price.toString(), projectedTotalMist: totalPrice.toString(), score, components: { relevance, sourceQuality, freshness, price: priceScore }, preview: { title: preview.title, summary: preview.summary, citations: preview.citations, freshnessDays }, manifestHash: entry.manifest.manifestHash };
95
+ }).sort((a, b) => b.score - a.score || (BigInt(a.priceMist) < BigInt(b.priceMist) ? -1 : BigInt(a.priceMist) > BigInt(b.priceMist) ? 1 : a.capabilityId.localeCompare(b.capabilityId)));
96
+ return { topic: input.topic, budgetMist: input.budget, analysisCapabilityId: analysis.manifest.capabilityId, analysisPriceMist: analysisPrice.toString(), rubric: { relevance: 0.35, sourceQuality: 0.30, freshness: 0.20, price: 0.15 }, rankings: scored, winner: scored[0], note: "Preview quality fields are seller supplied; the buyer checks artifact citations after delivery." };
97
+ }
98
+ async negotiate(input) {
99
+ const catalog = await this.catalog(), entry = catalog.capabilities.find((item) => item.manifest.capabilityId === input.capabilityId) ?? fail("SELLER_CAPABILITY_UNKNOWN", "capability is not in the verified catalog");
100
+ if (!/^[1-9][0-9]*$/.test(input.opening) || !/^[1-9][0-9]*$/.test(input.maximum) || BigInt(input.opening) > BigInt(input.maximum) || BigInt(input.maximum) < BigInt(entry.manifest.priceBand.minimum) || BigInt(input.maximum) > BigInt(entry.manifest.priceBand.maximum))
101
+ fail("NEGOTIATION_BOUNDS_INVALID", "offer bounds are outside the seller price band");
102
+ if (input.briefHash !== undefined && !/^[0-9a-f]{64}$/.test(input.briefHash))
103
+ fail("BUYER_BRIEF_HASH_INVALID", "brief hash is invalid");
104
+ const privateDer = this.app.store.getSecret("identity:x25519-private") ?? fail("IDENTITY_MISSING", "buyer negotiation key is missing"), publicKey = this.app.store.getSecret("identity:x25519-public")?.toString("base64url") ?? fail("IDENTITY_MISSING", "buyer negotiation key is missing");
105
+ const shared = diffieHellman({ privateKey: createPrivateKey({ key: privateDer, format: "der", type: "pkcs8" }), publicKey: createPublicKey({ key: Buffer.from(entry.transportPublicKey, "base64url"), format: "der", type: "spki" }) });
106
+ const key = Buffer.from(hkdfSync("sha256", shared, Buffer.from(input.sessionId), Buffer.from("supercuts-negotiation-v1"), 32));
107
+ this.app.store.db.exec("CREATE TABLE IF NOT EXISTS remote_buyer_negotiations(session_id TEXT PRIMARY KEY, capability_id TEXT NOT NULL, run_id TEXT NOT NULL, offer_hash TEXT NOT NULL, request_ciphertext TEXT NOT NULL, buyer_signature TEXT NOT NULL, reply_json TEXT)");
108
+ const offer = { task: input.task.slice(0, 512), opening: input.opening, maximum: input.maximum, ...(input.briefHash ? { briefHash: input.briefHash } : {}) }, offerHash = sha256(JSON.stringify(offer));
109
+ const existing = this.app.store.db.prepare("SELECT capability_id AS capabilityId,run_id AS runId,offer_hash AS offerHash,request_ciphertext AS ciphertext,buyer_signature AS buyerSignature,reply_json AS replyJson FROM remote_buyer_negotiations WHERE session_id=?").get(input.sessionId);
110
+ if (existing && (existing.capabilityId !== input.capabilityId || existing.runId !== input.runId || existing.offerHash !== offerHash))
111
+ fail("NEGOTIATION_SESSION_CONFLICT", "session belongs to another offer or run");
112
+ const encrypted = existing?.ciphertext ?? encryptSessionMessage(key, input.sessionId, `${input.sessionId}:buyer:1`, Buffer.from(JSON.stringify(offer)));
113
+ const encodedSigner = this.app.store.getSecret("live:sui-private-key")?.toString() ?? fail("LIVE_CREDENTIAL_MISSING", "buyer signing key is missing"), decoded = decodeSuiPrivateKey(encodedSigner);
114
+ if (decoded.scheme !== "ED25519")
115
+ fail("SIGNER_UNSUPPORTED", "buyer requires an ED25519 signer");
116
+ const signer = Ed25519Keypair.fromSecretKey(decoded.secretKey), signedBytes = Buffer.from(`${input.sessionId}:${input.capabilityId}:${publicKey}:${sha256(Buffer.from(encrypted, "base64"))}`);
117
+ const buyerSignature = existing?.buyerSignature ?? (await signer.signPersonalMessage(signedBytes)).signature;
118
+ if (!existing)
119
+ this.app.store.db.prepare("INSERT INTO remote_buyer_negotiations(session_id,capability_id,run_id,offer_hash,request_ciphertext,buyer_signature) VALUES(?,?,?,?,?,?)").run(input.sessionId, input.capabilityId, input.runId, offerHash, encrypted, buyerSignature);
120
+ const result = existing?.replyJson ? JSON.parse(existing.replyJson) : await this.request("/v1/negotiate", { method: "POST", body: JSON.stringify({ capabilityId: input.capabilityId, sessionId: input.sessionId, runId: input.runId, buyerAddress: signer.toSuiAddress(), buyerPublicKey: publicKey, buyerSignature, ciphertext: encrypted }) });
121
+ const replyCiphertext = String(result.ciphertext ?? ""), transcriptHash = sha256(JSON.stringify({ request: sha256(Buffer.from(encrypted, "base64")), reply: sha256(Buffer.from(replyCiphertext, "base64")) }));
122
+ if (result.sessionId !== input.sessionId || result.capabilityId !== input.capabilityId || result.transcriptHash !== transcriptHash || !(await isValidPersonalMessageSignature(Buffer.from(`${input.sessionId}:${input.capabilityId}:${sha256(Buffer.from(replyCiphertext, "base64"))}:${transcriptHash}`), String(result.signature), { address: entry.manifest.sellerId })))
123
+ fail("NEGOTIATION_RESPONSE_INVALID", "seller response or signature is invalid");
124
+ const aggregator = this.app.profile.live?.walrusAggregatorUrl ?? fail("LIVE_WALRUS_CONFIG_MISSING", "buyer needs a Walrus aggregator");
125
+ for (const [blobId, ciphertext] of [[result.requestBlobId, encrypted], [result.replyBlobId, replyCiphertext]]) {
126
+ const read = await this.http(`${aggregator.replace(/\/$/, "")}/v1/blobs/${encodeURIComponent(String(blobId))}`, { signal: AbortSignal.timeout(60_000) });
127
+ if (!read.ok || !Buffer.from(await read.arrayBuffer()).equals(Buffer.from(ciphertext, "base64")))
128
+ fail("WALRUS_BLOB_MISMATCH", "encrypted offer or response differs from Walrus");
129
+ }
130
+ const response = JSON.parse(decryptSessionMessage(key, input.sessionId, `${input.sessionId}:seller:2`, replyCiphertext).toString());
131
+ if (response.capabilityId !== input.capabilityId || response.asset !== entry.manifest.asset || response.amount !== entry.manifest.priceBand.minimum || response.accepted !== true)
132
+ fail("NEGOTIATION_RESPONSE_INVALID", "seller response changed the approved price or capability");
133
+ if (!existing?.replyJson)
134
+ this.app.store.db.prepare("UPDATE remote_buyer_negotiations SET reply_json=? WHERE session_id=?").run(JSON.stringify(result), input.sessionId);
135
+ return { sessionId: input.sessionId, capabilityId: input.capabilityId, sellerId: entry.manifest.sellerId, opening: input.opening, amount: response.amount, asset: response.asset, accepted: true, transcriptHash, requestBlobId: result.requestBlobId, replyBlobId: result.replyBlobId };
136
+ }
137
+ async quote(input) {
138
+ const catalog = await this.catalog(), entry = catalog.capabilities.find((item) => item.manifest.capabilityId === input.capabilityId) ?? fail("SELLER_CAPABILITY_UNKNOWN", "capability is not in the verified catalog");
139
+ if (!entry.manifest.supportedRails.includes("x402"))
140
+ fail("SELLER_RAIL_UNSUPPORTED", "capability does not support public settlement");
141
+ const quote = await this.request("/v1/quote", { method: "POST", body: JSON.stringify(input) });
142
+ if (quote.capabilityId !== entry.manifest.capabilityId || quote.sellerId !== entry.manifest.sellerId || quote.asset !== entry.manifest.asset || quote.amount !== entry.manifest.priceBand.minimum || quote.requestId !== input.requestId || quote.operationId !== input.operationId)
143
+ fail("SELLER_QUOTE_INVALID", "seller quote differs from its manifest or request");
144
+ const endpoint = new URL(entry.manifest.endpoint), resource = new URL(String(quote.resourceUrl));
145
+ if (resource.origin !== endpoint.origin || resource.pathname !== `${endpoint.pathname.replace(/\/$/, "")}/${encodeURIComponent(input.requestId)}` || resource.search || resource.hash)
146
+ fail("SELLER_QUOTE_INVALID", "seller resource URL is outside its capability endpoint");
147
+ return quote;
148
+ }
149
+ async purchaseBrief(input) {
150
+ if (!/^[1-9][0-9]*$/.test(input.budget))
151
+ fail("BUYER_BUDGET_INVALID", "budget must be positive MIST");
152
+ const catalog = await this.catalog(), entry = catalog.capabilities.find((item) => item.manifest.capabilityId === input.capabilityId) ?? fail("SELLER_CAPABILITY_UNKNOWN", "capability is not in the verified catalog");
153
+ if (entry.manifest.capability !== "sui.market-brief")
154
+ fail("BUYER_CAPABILITY_INVALID", "selected capability is not a market brief");
155
+ const briefHash = entry.preview.artifactHashes?.default;
156
+ const analysis = catalog.capabilities.find((item) => item.manifest.capability === "sui.competitor-analysis" && typeof item.preview.artifactHashes?.[String(briefHash)] === "string") ?? fail("ANALYSIS_UNAVAILABLE", "analysis seller has no matching prepared variant");
157
+ if (BigInt(entry.manifest.priceBand.minimum) + BigInt(analysis.manifest.priceBand.minimum) > BigInt(input.budget))
158
+ fail("BUYER_BUDGET_EXCEEDED", "brief and analysis exceed the total task budget");
159
+ const minimum = BigInt(entry.manifest.priceBand.minimum), opening = minimum > 1n ? minimum - (minimum / 10n || 1n) : minimum;
160
+ const negotiated = await this.negotiate({ capabilityId: input.capabilityId, sessionId: input.requestId, runId: input.runId, task: input.task, opening: opening.toString(), maximum: (BigInt(input.budget) - BigInt(analysis.manifest.priceBand.minimum) < BigInt(entry.manifest.priceBand.maximum) ? BigInt(input.budget) - BigInt(analysis.manifest.priceBand.minimum) : BigInt(entry.manifest.priceBand.maximum)).toString() });
161
+ const quote = await this.quote(input);
162
+ if (BigInt(String(quote.amount)) > BigInt(input.budget))
163
+ fail("BUYER_BUDGET_EXCEEDED", "seller quote exceeds the budget");
164
+ const plan = await executeMandated(this.app, this.mandate, "settlement.plan", { "operation-id": input.operationId, manifest: entry.manifest, "requested-amount": String(quote.amount) });
165
+ if (plan.status !== "approved" || plan.rail !== "x402")
166
+ fail("BUYER_RAIL_DENIED", "public brief settlement plan was not approved for x402");
167
+ const paid = await executeMandated(this.app, this.mandate, "pay.x402", { "operation-id": input.operationId, "resource-url": String(quote.resourceUrl), amount: String(quote.amount), "plan-hash": String(plan.planHash) });
168
+ const artifact = Buffer.from(String(paid.response), "base64");
169
+ if (sha256(artifact) !== quote.artifactSha256 || sha256(artifact) !== paid.responseSha256)
170
+ fail("DELIVERY_HASH_MISMATCH", "delivered brief differs from the seller quote or payment receipt");
171
+ let report;
172
+ try {
173
+ report = JSON.parse(artifact.toString());
174
+ }
175
+ catch (error) {
176
+ return fail("BRIEF_INVALID", "paid brief is not JSON", error);
177
+ }
178
+ if (typeof report.title !== "string" || typeof report.body !== "string" || !Array.isArray(report.citations) || report.citations.length < 2 || report.citations.some((value) => typeof value !== "string" || !/^https:\/\//.test(value)))
179
+ fail("BRIEF_INVALID", "paid brief needs a title, body, and at least two HTTPS citations");
180
+ const recorded = (await this.app.execute("resource.fetch", { "request-id": input.requestId, "operation-id": input.operationId, response: artifact.toString("base64url") })).data;
181
+ this.app.store.db.exec("CREATE TABLE IF NOT EXISTS remote_purchases(run_id TEXT PRIMARY KEY,brief_hash TEXT NOT NULL,brief_amount TEXT NOT NULL,budget TEXT NOT NULL,capability_id TEXT NOT NULL,operation_id TEXT NOT NULL)");
182
+ const prior = this.app.store.db.prepare("SELECT brief_hash AS briefHash,brief_amount AS briefAmount,budget,capability_id AS capabilityId,operation_id AS operationId FROM remote_purchases WHERE run_id=?").get(input.runId);
183
+ const purchase = { briefHash: sha256(artifact), briefAmount: String(paid.amount), budget: input.budget, capabilityId: input.capabilityId, operationId: input.operationId };
184
+ if (prior && JSON.stringify(prior) !== JSON.stringify(purchase))
185
+ fail("BUYER_RUN_CONFLICT", "run ID identifies a different purchased brief or budget");
186
+ if (!prior)
187
+ this.app.store.db.prepare("INSERT INTO remote_purchases(run_id,brief_hash,brief_amount,budget,capability_id,operation_id) VALUES(?,?,?,?,?,?)").run(input.runId, purchase.briefHash, purchase.briefAmount, purchase.budget, purchase.capabilityId, purchase.operationId);
188
+ return { capabilityId: input.capabilityId, sellerId: entry.manifest.sellerId, negotiation: negotiated, artifact: report, artifactSha256: sha256(artifact), deliveryStatus: recorded.deliveryStatus, transactionDigest: paid.transactionDigest, checkpoint: paid.checkpoint, rail: "x402", amount: paid.amount, payee: paid.counterparty, planHash: plan.planHash };
189
+ }
190
+ async agreement(input) {
191
+ if (!/^[0-9a-f]{64}$/.test(input.briefHash))
192
+ fail("BUYER_BRIEF_HASH_INVALID", "brief hash is invalid");
193
+ const catalog = await this.catalog(), entry = catalog.capabilities.find((item) => item.manifest.capabilityId === input.capabilityId) ?? fail("SELLER_CAPABILITY_UNKNOWN", "capability is not in the verified catalog");
194
+ this.app.store.db.exec("CREATE TABLE IF NOT EXISTS remote_purchases(run_id TEXT PRIMARY KEY,brief_hash TEXT NOT NULL,brief_amount TEXT NOT NULL,budget TEXT NOT NULL,capability_id TEXT NOT NULL,operation_id TEXT NOT NULL)");
195
+ const purchased = this.app.store.db.prepare("SELECT brief_hash AS briefHash,brief_amount AS briefAmount,budget FROM remote_purchases WHERE run_id=?").get(input.runId);
196
+ if (!purchased || purchased.briefHash !== input.briefHash || BigInt(purchased.briefAmount) + BigInt(entry.manifest.priceBand.minimum) > BigInt(purchased.budget))
197
+ fail("BUYER_PURCHASE_REQUIRED", "analysis requires the matching paid brief within the total budget");
198
+ const hashes = entry.preview.artifactHashes, artifactSha256 = hashes?.[input.briefHash];
199
+ if (!artifactSha256 || !/^[0-9a-f]{64}$/.test(artifactSha256))
200
+ fail("SELLER_ARTIFACT_MISSING", "seller has no prepared analysis for the purchased brief");
201
+ const analysisMinimum = BigInt(entry.manifest.priceBand.minimum), analysisOpening = analysisMinimum > 1n ? analysisMinimum - (analysisMinimum / 10n || 1n) : analysisMinimum;
202
+ const negotiated = await this.negotiate({ capabilityId: input.capabilityId, sessionId: input.sessionId, runId: input.runId, task: "Confidential competitor analysis of the purchased Sui brief", opening: analysisOpening.toString(), maximum: entry.manifest.priceBand.minimum, briefHash: input.briefHash });
203
+ const plan = await executeMandated(this.app, this.mandate, "settlement.plan", { "operation-id": input.operationId, manifest: entry.manifest, "requested-amount": entry.manifest.priceBand.minimum });
204
+ if (plan.status !== "approved" || plan.rail !== "shielded" || !Array.isArray(plan.reasonCodes) || !plan.reasonCodes.includes("MEMORY_PRIVACY_APPLIED"))
205
+ fail("BUYER_PRIVACY_REQUIRED", "saved owner privacy rule did not select shielded settlement");
206
+ const publicKey = this.app.store.getSecret("identity:x25519-public")?.toString("base64url") ?? fail("IDENTITY_MISSING", "buyer delivery key is missing");
207
+ const identity = (await this.app.execute("doctor", {})).data;
208
+ const serviceHash = sha256(JSON.stringify({ capabilityId: input.capabilityId, briefHash: input.briefHash, artifactSha256, deliveryPublicKey: publicKey }));
209
+ this.app.store.db.exec("CREATE TABLE IF NOT EXISTS remote_buyer_agreements(session_id TEXT PRIMARY KEY,context_hash TEXT NOT NULL,draft_json TEXT NOT NULL,created_at INTEGER NOT NULL)");
210
+ const contextHash = sha256(JSON.stringify({ capabilityId: input.capabilityId, operationId: input.operationId, sessionId: input.sessionId, runId: input.runId, briefHash: input.briefHash, transcriptHash: negotiated.transcriptHash, serviceHash, artifactSha256 }));
211
+ const priorDraft = this.app.store.db.prepare("SELECT context_hash AS contextHash,draft_json AS draftJson FROM remote_buyer_agreements WHERE session_id=?").get(input.sessionId);
212
+ if (priorDraft && priorDraft.contextHash !== contextHash)
213
+ fail("AGREEMENT_SESSION_CONFLICT", "analysis session identifies a different agreement context");
214
+ const draft = priorDraft ? JSON.parse(priorDraft.draftJson) : analysisAgreementDraft({ sessionId: input.sessionId, transcriptHash: String(negotiated.transcriptHash), serviceHash, paymentAmount: entry.manifest.priceBand.minimum, buyerPublicKey: identity.babyJubPublicKey, counterparty: entry.manifest.sellerId, capabilityId: entry.manifest.capabilityId, manifestHash: entry.manifest.manifestHash });
215
+ if (!priorDraft)
216
+ this.app.store.db.prepare("INSERT INTO remote_buyer_agreements(session_id,context_hash,draft_json,created_at) VALUES(?,?,?,?)").run(input.sessionId, contextHash, JSON.stringify(draft), Date.now());
217
+ const signed = await this.request("/v1/agreement", { method: "POST", body: JSON.stringify({ capabilityId: input.capabilityId, sessionId: input.sessionId, runId: input.runId, briefHash: input.briefHash, deliveryPublicKey: publicKey, agreement: Buffer.from(JSON.stringify(draft)).toString("base64url") }) });
218
+ if (signed.artifactSha256 !== artifactSha256 || signed.capabilityId !== input.capabilityId || signed.sessionId !== input.sessionId)
219
+ fail("AGREEMENT_BINDING_MISMATCH", "seller response changed the prepared artifact or session");
220
+ const accepted = await executeMandated(this.app, this.mandate, "offer.accept", { "operation-id": `accept-${input.sessionId}`, session: input.sessionId, agreement: signed.agreement, "plan-hash": String(plan.planHash) });
221
+ return { plan, accepted, negotiation: negotiated, sessionId: input.sessionId, artifactSha256, memoryCitationCount: Array.isArray(plan.citations) ? plan.citations.length : 0 };
222
+ }
223
+ async settleAnalysis(input) {
224
+ const agreement = this.app.store.db.prepare("SELECT agreement FROM live_agreements WHERE session_id=?").get(input.sessionId) ?? fail("AGREEMENT_NOT_ACCEPTED", "analysis session has no accepted seller agreement");
225
+ const accepted = JSON.parse(agreement.agreement);
226
+ const binding = this.app.store.db.prepare("SELECT plan_hash FROM settlement_agreement_bindings WHERE session_id=?").get(input.sessionId) ?? fail("SETTLEMENT_PLAN_REQUIRED", "analysis agreement is not bound to an approved plan");
227
+ const receipt = await executeMandated(this.app, this.mandate, "pay.shielded", { "operation-id": input.operationId, session: input.sessionId, amount: accepted.paymentAmount, counterparty: accepted.counterparty, "plan-hash": binding.plan_hash });
228
+ return { sessionId: input.sessionId, rail: "shielded", transactionDigest: receipt.transactionDigest, checkpoint: receipt.checkpoint, finalized: receipt.finalized, tatumVerified: receipt.tatumVerified, dealCommitment: receipt.dealCommitment, planHash: binding.plan_hash, visibility: "pool transaction and gas sender visible; direct amount and counterparty absent" };
229
+ }
230
+ async delivery(input) {
231
+ const response = await this.request(`/v1/delivery/${encodeURIComponent(input.sessionId)}`);
232
+ if (response.status === "payment-pending")
233
+ return response;
234
+ if (response.status !== "delivered" || response.sessionId !== input.sessionId || !/^[0-9a-f]{64}$/.test(String(response.artifactSha256)))
235
+ fail("DELIVERY_INVALID", "seller delivery is invalid");
236
+ const privateDer = this.app.store.getSecret("identity:x25519-private") ?? fail("IDENTITY_MISSING", "buyer delivery key is missing");
237
+ const privateKey = createPrivateKey({ key: privateDer, format: "der", type: "pkcs8" }), ephemeral = createPublicKey({ key: Buffer.from(response.ephemeralPublicKey, "base64url"), format: "der", type: "spki" });
238
+ const shared = diffieHellman({ privateKey, publicKey: ephemeral }), key = Buffer.from(hkdfSync("sha256", shared, Buffer.from(input.sessionId), Buffer.from("supercuts-delivery-v1"), 32));
239
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(response.nonce, "base64url"));
240
+ decipher.setAAD(Buffer.from(`${input.sessionId}:${String(response.capabilityId)}:${String(response.artifactSha256)}`));
241
+ decipher.setAuthTag(Buffer.from(response.tag, "base64url"));
242
+ const artifact = Buffer.concat([decipher.update(Buffer.from(response.ciphertext, "base64url")), decipher.final()]);
243
+ if (sha256(artifact) !== response.artifactSha256)
244
+ fail("DELIVERY_HASH_MISMATCH", "seller artifact differs from its accepted hash");
245
+ const recorded = (await this.app.execute("resource.fetch", { "request-id": input.sessionId, "operation-id": input.operationId, response: artifact.toString("base64url") })).data;
246
+ return { status: "delivered", sessionId: input.sessionId, artifactSha256: response.artifactSha256, body: artifact.toString("utf8"), record: { deliveryStatus: recorded.deliveryStatus, responseHash: recorded.responseHash } };
247
+ }
248
+ async research(input) {
249
+ if (!input.operationId || input.operationId.length > 256 || !/^[1-9][0-9]*$/.test(input.budget))
250
+ fail("BUYER_WORKFLOW_INVALID", "research requires a stable operation ID and positive total budget");
251
+ this.app.store.db.exec("CREATE TABLE IF NOT EXISTS remote_research_workflows(operation_id TEXT PRIMARY KEY,input_hash TEXT NOT NULL,created_at INTEGER NOT NULL,updated_at INTEGER NOT NULL,completed_at INTEGER)");
252
+ const inputHash = sha256(JSON.stringify({ runId: input.runId, topic: input.topic, budget: input.budget })), existing = this.app.store.db.prepare("SELECT input_hash AS inputHash,completed_at AS completedAt FROM remote_research_workflows WHERE operation_id=?").get(input.operationId);
253
+ if (existing && existing.inputHash !== inputHash)
254
+ fail("DEAL_OPERATION_CONFLICT", "research operation ID identifies another topic, budget, or run");
255
+ if (!existing)
256
+ this.app.store.db.prepare("INSERT INTO remote_research_workflows(operation_id,input_hash,created_at,updated_at) VALUES(?,?,?,?)").run(input.operationId, inputHash, Date.now(), Date.now());
257
+ const checkpoint = async (stage, action) => {
258
+ const key = `research:${input.operationId}:${stage}`, prior = this.app.store.getSecret(key);
259
+ if (prior)
260
+ return JSON.parse(prior.toString());
261
+ const value = await action();
262
+ this.app.store.putSecretOnce(key, Buffer.from(JSON.stringify(value)));
263
+ this.app.store.db.prepare("UPDATE remote_research_workflows SET updated_at=? WHERE operation_id=?").run(Date.now(), input.operationId);
264
+ return value;
265
+ };
266
+ const child = (stage) => `research:${stage}:${sha256(`${input.operationId}:${stage}`).slice(0, 40)}`;
267
+ const ranked = await checkpoint("selection", () => this.rankBriefs({ topic: input.topic, budget: input.budget }));
268
+ const winnerCapabilityId = String(ranked.winner?.capabilityId ?? "");
269
+ const analysisCapabilityId = String(ranked.analysisCapabilityId ?? "");
270
+ if (!winnerCapabilityId || !analysisCapabilityId)
271
+ fail("ANALYSIS_UNAVAILABLE", "ranked catalog has no affordable brief and matching analysis");
272
+ const brief = await checkpoint("brief", () => this.purchaseBrief({ capabilityId: winnerCapabilityId, operationId: child("brief-payment"), requestId: child("brief-request"), runId: input.runId, task: `Sui research: ${input.topic}`, budget: input.budget }));
273
+ const briefHash = String(brief.artifactSha256);
274
+ const sessionId = child("analysis-session"), paymentOperationId = child("analysis-payment");
275
+ const agreement = await checkpoint("agreement", () => this.agreement({ capabilityId: analysisCapabilityId, operationId: paymentOperationId, sessionId, runId: input.runId, briefHash }));
276
+ const settlement = await checkpoint("settlement", () => this.settleAnalysis({ sessionId, operationId: paymentOperationId }));
277
+ const analysis = await checkpoint("delivery", async () => {
278
+ const value = await this.delivery({ sessionId, operationId: paymentOperationId });
279
+ return value.status === "delivered" ? value : fail("DELIVERY_PENDING", "analysis payment is finalized and seller delivery is still pending; resume the same research operation");
280
+ });
281
+ this.app.store.db.prepare("UPDATE remote_research_workflows SET completed_at=COALESCE(completed_at,?),updated_at=? WHERE operation_id=?").run(Date.now(), Date.now(), input.operationId);
282
+ return { operationId: input.operationId, state: "complete", replayed: Boolean(existing?.completedAt), selection: ranked, brief, agreement, settlement, analysis };
283
+ }
284
+ async events(runId) { return this.request(`/v1/events?runId=${encodeURIComponent(runId)}`); }
285
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { Phase3App, errorOutput, homePath, parseArgs } from "./phase3.js";
5
+ import { X402ResourceService } from "./x402-resource-service.js";
6
+ import { fail } from "./errors.js";
7
+ const args = parseArgs(process.argv.slice(2)), required = (name) => typeof args[name] === "string" ? args[name] : fail("ARGUMENT_REQUIRED", `--${name} is required`);
8
+ try {
9
+ const app = new Phase3App(homePath(args));
10
+ if (app.profile.role !== "seller")
11
+ fail("ROLE_FORBIDDEN", "resource service requires a seller role home");
12
+ const document = JSON.parse(readFileSync(resolve(required("config")), "utf8"));
13
+ if (!Array.isArray(document.artifacts) || !document.artifacts.length)
14
+ fail("RESOURCE_CONFIG_INVALID", "resource config needs at least one artifact");
15
+ const service = new X402ResourceService(app.store, document.service), registered = document.artifacts.map((item) => ({ requestId: item.requestId, operationId: item.operationId, ...service.register(item.requestId, item.operationId, readFileSync(resolve(item.file))) })), server = service.createServer(), origin = new URL(document.service.origin), port = Number(origin.port || (origin.protocol === "https:" ? 443 : 80));
16
+ server.listen(port, origin.hostname, () => process.stdout.write(`${JSON.stringify({ schemaVersion: "supercuts.resource.v1", ok: true, origin: document.service.origin, payTo: document.service.payTo, artifacts: registered })}\n`));
17
+ const close = () => server.close(() => { app.close(); process.exit(0); });
18
+ process.on("SIGINT", close);
19
+ process.on("SIGTERM", close);
20
+ }
21
+ catch (error) {
22
+ process.stdout.write(`${JSON.stringify(errorOutput(error))}\n`);
23
+ process.exitCode = 1;
24
+ }
@@ -0,0 +1,22 @@
1
+ import { ExactRequirements, FinalPayment, PaymentBinding, PaymentConsumptionLedger } from "./x402.js";
2
+ export interface PaymentSubmission {
3
+ binding: PaymentBinding;
4
+ }
5
+ export type PayerSignatureVerifier = (binding: PaymentBinding, requirements: ExactRequirements) => Promise<boolean>;
6
+ export type PaymentSettlementReader = (digest: string) => Promise<FinalPayment | undefined>;
7
+ export interface PaymentChallenge {
8
+ status: 402;
9
+ requestId: string;
10
+ nonce: string;
11
+ requirements: ExactRequirements;
12
+ }
13
+ export declare function verifySuiPaymentBinding(binding: PaymentBinding): Promise<boolean>;
14
+ export declare class ExactResourceServer {
15
+ private readonly ledger;
16
+ private readonly requirements;
17
+ private readonly verifyPayer;
18
+ private readonly readSettlement;
19
+ constructor(ledger: PaymentConsumptionLedger, requirements: ExactRequirements, verifyPayer: PayerSignatureVerifier, readSettlement: PaymentSettlementReader);
20
+ challenge(requestId: string): PaymentChallenge;
21
+ deliver(requestId: string, submission: PaymentSubmission, produce: () => Promise<Uint8Array>): Promise<Buffer>;
22
+ }
@@ -0,0 +1,55 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { isValidPersonalMessageSignature } from "@mysten/sui/verify";
3
+ import { fail } from "./errors.js";
4
+ import { requirementsHash, verifyBinding, verifyExactPayment } from "./x402.js";
5
+ import { paymentBindingBytes } from "./x402.js";
6
+ export async function verifySuiPaymentBinding(binding) {
7
+ const { payerSignature: _signature, ...unsigned } = binding;
8
+ return isValidPersonalMessageSignature(paymentBindingBytes(unsigned), binding.payerSignature, { address: binding.payer });
9
+ }
10
+ export class ExactResourceServer {
11
+ ledger;
12
+ requirements;
13
+ verifyPayer;
14
+ readSettlement;
15
+ constructor(ledger, requirements, verifyPayer, readSettlement) {
16
+ this.ledger = ledger;
17
+ this.requirements = requirements;
18
+ this.verifyPayer = verifyPayer;
19
+ this.readSettlement = readSettlement;
20
+ }
21
+ challenge(requestId) {
22
+ const nonce = this.ledger.challenge(requestId, requirementsHash(this.requirements), () => randomBytes(24).toString("hex"));
23
+ return { status: 402, requestId, nonce, requirements: structuredClone(this.requirements) };
24
+ }
25
+ async deliver(requestId, submission, produce) {
26
+ const stored = this.ledger.getChallenge(requestId, requirementsHash(this.requirements)) ?? fail("X402_CHALLENGE_MISSING", "request has no active payment challenge");
27
+ const challenge = { requestId, nonce: stored.nonce, requirements: this.requirements };
28
+ verifyBinding(submission.binding, requestId, challenge.nonce, challenge.requirements, submission.binding.transactionDigest);
29
+ if (!(await this.verifyPayer(submission.binding, challenge.requirements)))
30
+ fail("X402_PAYER_SIGNATURE_INVALID", "payer did not authorize this request binding");
31
+ if (!submission.binding.payer)
32
+ fail("X402_PAYER_SIGNATURE_INVALID", "payment binding has no payer identity");
33
+ const cached = this.ledger.getDelivery(requestId);
34
+ if (this.ledger.isDeliveryComplete(requestId))
35
+ return cached ?? fail("DELIVERY_STATE_INVALID", "completed delivery has no persisted response");
36
+ if (Date.now() > stored.createdAt + this.requirements.maxTimeoutSeconds * 1_000)
37
+ fail("X402_CHALLENGE_EXPIRED", "payment challenge has expired");
38
+ const payment = await this.readSettlement(submission.binding.transactionDigest) ?? fail("PAYMENT_NOT_FOUND", "payment transaction was not found");
39
+ if (payment.digest !== submission.binding.transactionDigest)
40
+ fail("PAYMENT_DIGEST_MISMATCH", "settlement reader returned another transaction");
41
+ verifyExactPayment(payment, challenge.requirements);
42
+ this.ledger.claim(payment, requestId);
43
+ if (!this.ledger.acquireDelivery(requestId))
44
+ fail("DELIVERY_IN_PROGRESS", "resource delivery is already being produced");
45
+ try {
46
+ const response = Buffer.from(await produce());
47
+ this.ledger.completeDelivery(requestId, response);
48
+ return response;
49
+ }
50
+ catch (error) {
51
+ this.ledger.releaseDelivery(requestId);
52
+ throw error;
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,8 @@
1
+ export interface RoleHomeLease {
2
+ acquired: boolean;
3
+ ownerPid?: number;
4
+ release(): void;
5
+ }
6
+ /** Best-effort process lease. SQLite still owns data integrity; this prevents
7
+ * multiple MCP event/memory workers from operating one role home at once. */
8
+ export declare function acquireRoleHomeLease(home: string): RoleHomeLease;
@@ -0,0 +1,54 @@
1
+ import { closeSync, openSync, readFileSync, unlinkSync, writeSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ function active(pid) {
5
+ if (!Number.isSafeInteger(pid) || pid <= 0)
6
+ return false;
7
+ try {
8
+ process.kill(pid, 0);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ /** Best-effort process lease. SQLite still owns data integrity; this prevents
16
+ * multiple MCP event/memory workers from operating one role home at once. */
17
+ export function acquireRoleHomeLease(home) {
18
+ const path = join(home, ".mcp.lock"), token = randomUUID();
19
+ for (let attempt = 0; attempt < 2; attempt++) {
20
+ try {
21
+ const fd = openSync(path, "wx", 0o600);
22
+ writeSync(fd, `${JSON.stringify({ pid: process.pid, token, startedAt: Date.now() })}\n`);
23
+ closeSync(fd);
24
+ let released = false;
25
+ return { acquired: true, release: () => {
26
+ if (released)
27
+ return;
28
+ released = true;
29
+ try {
30
+ const value = JSON.parse(readFileSync(path, "utf8"));
31
+ if (value.token === token)
32
+ unlinkSync(path);
33
+ }
34
+ catch { /* already removed */ }
35
+ } };
36
+ }
37
+ catch (error) {
38
+ if (error.code !== "EEXIST")
39
+ throw error;
40
+ let ownerPid;
41
+ try {
42
+ ownerPid = Number(JSON.parse(readFileSync(path, "utf8")).pid);
43
+ }
44
+ catch { /* stale malformed lock */ }
45
+ if (ownerPid !== undefined && active(ownerPid))
46
+ return { acquired: false, ownerPid, release: () => { } };
47
+ try {
48
+ unlinkSync(path);
49
+ }
50
+ catch { /* another process won the cleanup race */ }
51
+ }
52
+ }
53
+ return { acquired: false, release: () => { } };
54
+ }
package/dist/seam.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/seam.js ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ import { Phase3App, errorOutput, homePath, initialize } from "./phase3.js";
3
+ import { DealJournal } from "./deal.js";
4
+ import { createConfiguredDealEngine } from "./deal-adapter.js";
5
+ import { loadMandate } from "./mandate.js";
6
+ import { LiveDealPorts } from "./live-deal-ports.js";
7
+ import { createRequire } from "node:module";
8
+ const PROTOCOL = 1;
9
+ const PACKAGE_VERSION = createRequire(import.meta.url)("../package.json").version;
10
+ const envelope = (requestId, value) => ({ protocol: PROTOCOL, requestId, ...value });
11
+ let responded = false;
12
+ const write = (value, status = 0) => { if (responded)
13
+ return; responded = true; process.stdout.write(`${JSON.stringify(value)}\n`); process.exitCode = status; };
14
+ const asArgs = (value) => {
15
+ const result = {};
16
+ for (const [key, item] of Object.entries(value ?? {})) {
17
+ if (typeof item === "boolean" || typeof item === "string")
18
+ result[key] = item;
19
+ else if (typeof item === "number" && Number.isSafeInteger(item))
20
+ result[key] = String(item);
21
+ else if (item !== undefined)
22
+ result[key] = Buffer.from(JSON.stringify(item)).toString("base64url");
23
+ }
24
+ return result;
25
+ };
26
+ let raw = "";
27
+ process.stdin.setEncoding("utf8");
28
+ process.stdin.on("data", (chunk) => { raw += chunk; if (raw.length > 1024 * 1024)
29
+ write(envelope(null, { ok: false, error: { code: "SEAM_REQUEST_TOO_LARGE", message: "request exceeds 1 MiB; reduce the input", retryable: false } }), 1); });
30
+ process.stdin.on("error", () => write(envelope(null, { ok: false, error: { code: "SEAM_REQUEST_INVALID", message: "request stream failed", retryable: false } }), 1));
31
+ process.stdin.on("end", async () => {
32
+ if (responded)
33
+ return;
34
+ let request;
35
+ try {
36
+ request = JSON.parse(raw);
37
+ }
38
+ catch {
39
+ return write(envelope(null, { ok: false, error: { code: "SEAM_REQUEST_INVALID", message: "request is not valid JSON", retryable: false } }), 1);
40
+ }
41
+ if (!request || request.protocol !== PROTOCOL || typeof request.requestId !== "string" || !request.requestId || request.requestId.length > 256 || typeof request.method !== "string" || !request.method || request.method.length > 128)
42
+ return write(envelope(typeof request?.requestId === "string" ? request.requestId : null, { ok: false, error: { code: "SEAM_PROTOCOL_MISMATCH", message: `supercuts seam protocol ${PROTOCOL} and a bounded request identity and method are required`, retryable: false } }), 1);
43
+ try {
44
+ if (request.method === "version")
45
+ return write(envelope(request.requestId, { ok: true, result: { protocol: PROTOCOL, packageVersion: PACKAGE_VERSION } }));
46
+ if (typeof request.home !== "string" || !request.home)
47
+ return write(envelope(request.requestId, { ok: false, error: { code: "SEAM_HOME_REQUIRED", message: "an explicit role home is required", retryable: false } }), 1);
48
+ if (request.params !== undefined && (!request.params || typeof request.params !== "object" || Array.isArray(request.params)))
49
+ return write(envelope(request.requestId, { ok: false, error: { code: "SEAM_REQUEST_INVALID", message: "params must be an object", retryable: false } }), 1);
50
+ const params = asArgs(request.params), home = homePath({ home: request.home ?? "" });
51
+ if (request.method === "initialize") {
52
+ const result = initialize(home, { ...params, role: String(request.params?.role ?? "") });
53
+ return write(envelope(request.requestId, { ok: true, result: result.data }));
54
+ }
55
+ const app = new Phase3App(home);
56
+ try {
57
+ if (request.method.startsWith("deal.")) {
58
+ if (app.profile.role !== "buyer")
59
+ throw Object.assign(new Error("deal methods require a buyer role home"), { code: "ROLE_FORBIDDEN" });
60
+ const journal = new DealJournal(app.store);
61
+ if (request.method === "deal.catalog") {
62
+ const mandate = loadMandate(home);
63
+ const entries = await new LiveDealPorts(app, mandate).catalog();
64
+ return write(envelope(request.requestId, { ok: true, result: { capabilities: entries.map(({ origin, registration }) => ({ origin, manifest: registration.manifest, manifestBlobId: registration.manifestBlobId })) } }));
65
+ }
66
+ if (request.method === "deal.policy") {
67
+ const mandate = loadMandate(home), hasTable = Boolean(app.store.db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='mandate_operations'").get());
68
+ const reserved = hasTable ? app.store.db.prepare("SELECT amount FROM mandate_operations").all().reduce((sum, row) => sum + BigInt(row.amount), 0n) : 0n;
69
+ return write(envelope(request.requestId, { ok: true, result: { perDealCeiling: mandate.perDealCeiling, totalBudget: mandate.totalRunBudget, remainingBudget: (BigInt(mandate.totalRunBudget) - reserved).toString(), expiresAt: mandate.expiresAt, defaultRail: "shielded", allowPublicX402: mandate.allowPublicX402 === true, allowedAssets: mandate.allowedAssets, allowedCapabilityIds: mandate.allowedCapabilityIds, allowedCapabilityClasses: mandate.allowedCapabilityClasses } }));
70
+ }
71
+ if (request.method === "deal.execute") {
72
+ const engine = await createConfiguredDealEngine(app);
73
+ return write(envelope(request.requestId, { ok: true, result: await engine.execute(request.params?.input) }));
74
+ }
75
+ if (request.method === "deal.resume") {
76
+ const engine = await createConfiguredDealEngine(app);
77
+ return write(envelope(request.requestId, { ok: true, result: await engine.resume(String(request.params?.operationId ?? "")) }));
78
+ }
79
+ if (request.method === "deal.reconcile") {
80
+ if (!loadMandate(home).allowedCommands.includes("deal.resume"))
81
+ throw Object.assign(new Error("deal reconciliation requires owner deal authority"), { code: "MANDATE_COMMAND_FORBIDDEN" });
82
+ return write(envelope(request.requestId, { ok: true, result: await app.reconcileDealOutcome(String(request.params?.operationId ?? "")) }));
83
+ }
84
+ if (request.method === "deal.get")
85
+ return write(envelope(request.requestId, { ok: true, result: journal.get(String(request.params?.operationId ?? "")) }));
86
+ if (request.method === "deal.evidence")
87
+ return write(envelope(request.requestId, { ok: true, result: journal.evidence(String(request.params?.dealId ?? "")) }));
88
+ if (request.method === "deal.delivery") {
89
+ const delivery = journal.delivery(String(request.params?.dealId ?? ""));
90
+ return write(envelope(request.requestId, { ok: true, result: { ...delivery, artifact: Buffer.from(delivery.artifact).toString("base64") } }));
91
+ }
92
+ }
93
+ if (request.method === "authorization.preview") {
94
+ const command = String(request.params?.command ?? ""), commandArgs = asArgs(request.params?.arguments);
95
+ return write(envelope(request.requestId, { ok: true, result: app.preview(command, commandArgs) }));
96
+ }
97
+ if (request.method === "authorization.approve")
98
+ return write(envelope(request.requestId, { ok: true, result: app.approve(String(request.params?.challengeId ?? "")) }));
99
+ if (request.method === "command.execute") {
100
+ const command = String(request.params?.command ?? ""), commandArgs = asArgs(request.params?.arguments);
101
+ if (typeof request.params?.approvalToken === "string")
102
+ commandArgs["approval-token"] = request.params.approvalToken;
103
+ const result = await app.execute(command, commandArgs);
104
+ return write(envelope(request.requestId, { ok: true, result: result.data }));
105
+ }
106
+ return write(envelope(request.requestId, { ok: false, error: { code: "SEAM_METHOD_UNKNOWN", message: `unknown seam method ${request.method}`, retryable: false } }), 1);
107
+ }
108
+ finally {
109
+ app.close();
110
+ }
111
+ }
112
+ catch (error) {
113
+ const shaped = errorOutput(error);
114
+ const code = String(shaped.error.code ?? "INTERNAL_ERROR");
115
+ return write(envelope(request.requestId, { ok: false, error: { ...shaped.error, retryable: ["DELIVERY_IN_PROGRESS", "MEMORY_JOB_PENDING", "TATUM_TIMEOUT"].includes(code) } }), 1);
116
+ }
117
+ });
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};