@supercuts-walrus/backend 0.0.0-stage → 0.1.0

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 (149) 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 +29 -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 +449 -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/hosted-exit-cli.d.ts +2 -0
  38. package/dist/hosted-exit-cli.js +37 -0
  39. package/dist/hosted-exit.d.ts +24 -0
  40. package/dist/hosted-exit.js +70 -0
  41. package/dist/hosted-seller-import.d.ts +2 -0
  42. package/dist/hosted-seller-import.js +70 -0
  43. package/dist/hosted-seller-repository.d.ts +31 -0
  44. package/dist/hosted-seller-repository.js +214 -0
  45. package/dist/index.d.ts +37 -0
  46. package/dist/index.js +37 -0
  47. package/dist/indexer.d.ts +63 -0
  48. package/dist/indexer.js +60 -0
  49. package/dist/live-deal-ports.d.ts +41 -0
  50. package/dist/live-deal-ports.js +212 -0
  51. package/dist/live-index.d.ts +28 -0
  52. package/dist/live-index.js +149 -0
  53. package/dist/live-runtime.d.ts +82 -0
  54. package/dist/live-runtime.js +570 -0
  55. package/dist/live-seller-transport.d.ts +30 -0
  56. package/dist/live-seller-transport.js +169 -0
  57. package/dist/live-seller-verifier.d.ts +11 -0
  58. package/dist/live-seller-verifier.js +65 -0
  59. package/dist/mandate.d.ts +34 -0
  60. package/dist/mandate.js +178 -0
  61. package/dist/mcp-bootstrap.d.ts +2 -0
  62. package/dist/mcp-bootstrap.js +39 -0
  63. package/dist/mcp.d.ts +2 -0
  64. package/dist/mcp.js +187 -0
  65. package/dist/memory-worker.d.ts +2 -0
  66. package/dist/memory-worker.js +38 -0
  67. package/dist/memory.d.ts +15 -0
  68. package/dist/memory.js +17 -0
  69. package/dist/memwal.d.ts +35 -0
  70. package/dist/memwal.js +83 -0
  71. package/dist/negotiation.d.ts +23 -0
  72. package/dist/negotiation.js +58 -0
  73. package/dist/notes.d.ts +11 -0
  74. package/dist/notes.js +26 -0
  75. package/dist/onboarding-doctor.d.ts +1 -0
  76. package/dist/onboarding-doctor.js +76 -0
  77. package/dist/phase3.d.ts +100 -0
  78. package/dist/phase3.js +1144 -0
  79. package/dist/procurement.d.ts +8 -0
  80. package/dist/procurement.js +19 -0
  81. package/dist/protocol-engine.d.ts +121 -0
  82. package/dist/protocol-engine.js +149 -0
  83. package/dist/prover.d.ts +28 -0
  84. package/dist/prover.js +70 -0
  85. package/dist/relayer.d.ts +32 -0
  86. package/dist/relayer.js +43 -0
  87. package/dist/remote-buyer.d.ts +67 -0
  88. package/dist/remote-buyer.js +231 -0
  89. package/dist/resource-server.d.ts +2 -0
  90. package/dist/resource-server.js +24 -0
  91. package/dist/resource.d.ts +22 -0
  92. package/dist/resource.js +55 -0
  93. package/dist/seam.d.ts +2 -0
  94. package/dist/seam.js +117 -0
  95. package/dist/seller-catalog-generate.d.ts +2 -0
  96. package/dist/seller-catalog-generate.js +68 -0
  97. package/dist/seller-database.d.ts +41 -0
  98. package/dist/seller-database.js +80 -0
  99. package/dist/seller-directory-cli.d.ts +2 -0
  100. package/dist/seller-directory-cli.js +24 -0
  101. package/dist/seller-directory.d.ts +5 -0
  102. package/dist/seller-directory.js +50 -0
  103. package/dist/seller-live-cli.d.ts +2 -0
  104. package/dist/seller-live-cli.js +53 -0
  105. package/dist/seller-provision.d.ts +2 -0
  106. package/dist/seller-provision.js +84 -0
  107. package/dist/seller-register-cli.d.ts +2 -0
  108. package/dist/seller-register-cli.js +40 -0
  109. package/dist/seller-runtime.d.ts +60 -0
  110. package/dist/seller-runtime.js +96 -0
  111. package/dist/seller-service.d.ts +34 -0
  112. package/dist/seller-service.js +416 -0
  113. package/dist/seller-state.d.ts +19 -0
  114. package/dist/seller-state.js +60 -0
  115. package/dist/seller-stdio.d.ts +6 -0
  116. package/dist/seller-stdio.js +29 -0
  117. package/dist/seller-v2-provision.d.ts +2 -0
  118. package/dist/seller-v2-provision.js +71 -0
  119. package/dist/seller-watch.d.ts +2 -0
  120. package/dist/seller-watch.js +45 -0
  121. package/dist/settlement.d.ts +95 -0
  122. package/dist/settlement.js +141 -0
  123. package/dist/store.d.ts +36 -0
  124. package/dist/store.js +193 -0
  125. package/dist/sui.d.ts +49 -0
  126. package/dist/sui.js +77 -0
  127. package/dist/tatum.d.ts +17 -0
  128. package/dist/tatum.js +83 -0
  129. package/dist/transcript.d.ts +31 -0
  130. package/dist/transcript.js +52 -0
  131. package/dist/v2-exit-relayer.d.ts +34 -0
  132. package/dist/v2-exit-relayer.js +102 -0
  133. package/dist/v2-exit-worker.d.ts +2 -0
  134. package/dist/v2-exit-worker.js +97 -0
  135. package/dist/v2-exits.d.ts +30 -0
  136. package/dist/v2-exits.js +78 -0
  137. package/dist/v2-prefund.d.ts +19 -0
  138. package/dist/v2-prefund.js +43 -0
  139. package/dist/v2-relayer-cli.d.ts +2 -0
  140. package/dist/v2-relayer-cli.js +39 -0
  141. package/dist/wallet.d.ts +32 -0
  142. package/dist/wallet.js +90 -0
  143. package/dist/workflow-memory.d.ts +22 -0
  144. package/dist/workflow-memory.js +49 -0
  145. package/dist/x402-resource-service.d.ts +34 -0
  146. package/dist/x402-resource-service.js +154 -0
  147. package/dist/x402.d.ts +46 -0
  148. package/dist/x402.js +136 -0
  149. package/package.json +60 -3
package/dist/demo.js ADDED
@@ -0,0 +1,449 @@
1
+ #!/usr/bin/env node
2
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
3
+ import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { decodeSuiPrivateKey } from "@mysten/sui/cryptography";
7
+ import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
8
+ import { DemoEventLog, readDemoEvents, recordedReplay } from "./events.js";
9
+ import { Phase3App, errorOutput, initialize, parseArgs } from "./phase3.js";
10
+ import { serveEventDashboard } from "./dashboard.js";
11
+ import { fail } from "./errors.js";
12
+ import { validateCapabilityManifest } from "./capability.js";
13
+ import { deterministicCounteroffer } from "./procurement.js";
14
+ import { BoundedClaude } from "./claude.js";
15
+ import { loadMandate } from "./mandate.js";
16
+ import { LiveDealPorts } from "./live-deal-ports.js";
17
+ import { DealJournal } from "./deal.js";
18
+ import { V2ExitQueue } from "./v2-exits.js";
19
+ import { inspectHostedExit } from "./hosted-exit.js";
20
+ import { SellerDatabase } from "./seller-database.js";
21
+ const [command = "", ...words] = process.argv.slice(2), args = parseArgs(words);
22
+ const value = (name, fallback) => typeof args[name] === "string" ? args[name] : fallback ?? fail("ARGUMENT_REQUIRED", `--${name} is required`);
23
+ const stateDir = () => resolve(value("state-dir", ".supercuts-demo"));
24
+ const homes = (root) => ({ buyer: join(root, "buyer"), publicSeller: join(root, "public-seller"), secondPublicSeller: join(root, "second-public-seller"), confidentialSeller: join(root, "confidential-seller"), auditor: join(root, "auditor") });
25
+ const send = (data) => process.stdout.write(`${JSON.stringify({ schemaVersion: "supercuts.demo.v1", ok: true, command, data })}\n`);
26
+ function keyAddress(path) { const decoded = decodeSuiPrivateKey(readFileSync(path, "utf8").trim()); if (decoded.scheme !== "ED25519")
27
+ fail("SIGNER_UNSUPPORTED", "demo requires ED25519 Sui keys"); return Ed25519Keypair.fromSecretKey(decoded.secretKey).toSuiAddress(); }
28
+ function createKey(path) { if (!existsSync(path))
29
+ writeFileSync(path, Ed25519Keypair.generate().getSecretKey(), { mode: 0o600 }); chmodSync(path, 0o600); }
30
+ async function setup() {
31
+ const root = stateDir(), roles = homes(root);
32
+ mkdirSync(root, { recursive: true, mode: 0o700 });
33
+ chmodSync(root, 0o700);
34
+ const mock = args.mock === true, secrets = join(root, "secrets");
35
+ mkdirSync(secrets, { recursive: true, mode: 0o700 });
36
+ const keys = { buyer: join(secrets, "buyer.sui.key"), publicSeller: join(secrets, "public-seller.sui.key"), secondPublicSeller: join(secrets, "second-public-seller.sui.key"), confidentialSeller: join(secrets, "confidential-seller.sui.key"), auditor: join(secrets, "auditor.sui.key") };
37
+ for (const path of Object.values(keys))
38
+ createKey(path);
39
+ const addresses = Object.fromEntries(Object.entries(keys).map(([name, path]) => [name, keyAddress(path)]));
40
+ const common = mock ? { mock: true } : { "deployment-config": resolve(value("deployment-config")), "tatum-key-file": resolve(value("tatum-key-file")), "write-grpc": value("write-grpc"), "tatum-grpc": value("tatum-grpc"), "walrus-publisher": value("walrus-publisher"), "walrus-aggregator": value("walrus-aggregator"), ...(typeof args.rapidsnark === "string" ? { rapidsnark: resolve(args.rapidsnark) } : {}) };
41
+ const roleInputs = [["buyer", "buyer", keys.buyer], ["publicSeller", "seller", keys.publicSeller], ["secondPublicSeller", "seller", keys.secondPublicSeller], ["confidentialSeller", "seller", keys.confidentialSeller], ["auditor", "auditor", keys.auditor]];
42
+ for (const [name, role, key] of roleInputs) {
43
+ const profilePath = join(roles[name], "profile.json");
44
+ if (!existsSync(profilePath))
45
+ initialize(roles[name], { role, ...common, ...(!mock ? { "sui-key-file": key } : {}), ...(role === "buyer" ? { "allow-counterparty": `${addresses.publicSeller},${addresses.secondPublicSeller},${addresses.confidentialSeller}`, ...(typeof args["memory-config-file"] === "string" ? { "memory-config-file": resolve(args["memory-config-file"]) } : {}), ...(typeof args["max-memory-distance"] === "string" ? { "max-memory-distance": args["max-memory-distance"] } : {}) } : {}) });
46
+ const profile = JSON.parse(readFileSync(profilePath, "utf8"));
47
+ if (profile.role !== role || profile.mock !== mock || !mock && profile.verifierVersion !== 2)
48
+ fail("DEMO_ROLE_PROFILE_MISMATCH", "demo setup needs fresh isolated live v2 role homes; choose a new --state-dir instead of reusing v1 or mock profiles");
49
+ }
50
+ const workflowPath = typeof args.workflow === "string" ? resolve(args.workflow) : !mock && typeof args["seller-url"] !== "string" ? resolve(value("workflow")) : undefined;
51
+ if (workflowPath) {
52
+ const workflow = JSON.parse(readFileSync(workflowPath, "utf8")), capabilities = workflow.capabilities ?? [];
53
+ if (!capabilities.length)
54
+ fail("DEMO_CAPABILITIES_REQUIRED", "live workflow must provide capability manifests for the buyer mandate");
55
+ for (const manifest of capabilities)
56
+ validateCapabilityManifest(manifest);
57
+ const mandatePath = join(roles.buyer, "mandate.json"), mandate = JSON.parse(readFileSync(mandatePath, "utf8"));
58
+ mandate.requireSettlementPlan = true;
59
+ mandate.allowedCommands = [...new Set([...(Array.isArray(mandate.allowedCommands) ? mandate.allowedCommands : []), "settlement.plan"])];
60
+ mandate.allowedCapabilityIds = [...new Set(capabilities.map((item) => item.capabilityId))];
61
+ mandate.allowedCapabilityClasses = [...new Set(capabilities.map((item) => item.capability))];
62
+ mandate.allowedRails = [...new Set(capabilities.flatMap((item) => item.supportedRails))];
63
+ writeFileSync(mandatePath, `${JSON.stringify(mandate, null, 2)}\n`, { mode: 0o600 });
64
+ chmodSync(mandatePath, 0o600);
65
+ }
66
+ const mcpScript = join(dirname(fileURLToPath(import.meta.url)), "mcp.js");
67
+ const mcp = { mcpServers: Object.fromEntries(Object.entries(roles).map(([name, home]) => [`supercuts-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}`, { command: process.execPath, args: [mcpScript], env: { SUPERCUTS_HOME: home } }])) };
68
+ writeFileSync(join(root, "mcp.json"), `${JSON.stringify(mcp, null, 2)}\n`, { mode: 0o600 });
69
+ const runId = randomUUID(), eventPath = join(root, `events-${runId}.jsonl`);
70
+ if (typeof args["seller-url"] === "string") {
71
+ const sellerUrl = new URL(args["seller-url"]);
72
+ if (sellerUrl.protocol !== "https:" && !(sellerUrl.protocol === "http:" && ["127.0.0.1", "localhost", "::1"].includes(sellerUrl.hostname)))
73
+ fail("SELLER_ORIGIN_INVALID", "seller URL must use HTTPS except on loopback");
74
+ const codex = `[mcp_servers.supercuts-buyer]\ncommand = ${JSON.stringify(process.execPath)}\nargs = ${JSON.stringify([mcpScript])}\n[mcp_servers.supercuts-buyer.env]\nSUPERCUTS_HOME = ${JSON.stringify(roles.buyer)}\nSUPERCUTS_SELLER_URL = ${JSON.stringify(sellerUrl.toString())}\nSUPERCUTS_RUN_ID = ${JSON.stringify(runId)}\nSUPERCUTS_EVENT_PATH = ${JSON.stringify(eventPath)}\n`;
75
+ writeFileSync(join(root, "buyer-codex.toml"), codex, { mode: 0o600 });
76
+ }
77
+ const remote = typeof args["seller-url"] === "string";
78
+ writeFileSync(join(root, "run.json"), `${JSON.stringify({ schema: "supercuts.demo.run.v1", createdAt: new Date().toISOString(), runId, ...(remote ? { eventPath } : {}), mock, homes: roles, addresses }, null, 2)}\n`, { mode: 0o600 });
79
+ return { stateDir: root, mock, funding: mock ? [] : [{ address: addresses.buyer, needs: ["Testnet SUI gas", "configured x402 asset", "shielded deposit value"] }], sellerPayTo: addresses.publicSeller, sellerAddresses: { publicA: addresses.publicSeller, publicB: addresses.secondPublicSeller, analysis: addresses.confidentialSeller }, files: { mcp: join(root, "mcp.json"), run: join(root, "run.json"), events: remote ? eventPath : join(root, "events.jsonl"), ...(remote ? { codex: join(root, "buyer-codex.toml") } : {}) } };
80
+ }
81
+ async function doctor() {
82
+ if (typeof args["buyer-home"] === "string") {
83
+ const home = resolve(args["buyer-home"]), app = new Phase3App(home);
84
+ try {
85
+ if (app.profile.role !== "buyer" || app.profile.mock || app.profile.verifierVersion !== 2)
86
+ fail("LIVE_PROFILE_REQUIRED", "generic Codex doctor requires a live v2 buyer");
87
+ const mandate = loadMandate(home), buyer = (await app.execute("doctor", {})).data;
88
+ if (buyer.readyForDemo === false)
89
+ fail("DEMO_PREREQUISITES_MISSING", buyer.fixes.join(" "));
90
+ const catalog = await new LiveDealPorts(app, mandate).catalog();
91
+ if (!catalog.length)
92
+ fail("SELLER_CATALOG_EMPTY", "configured seller origins have no allowed signed v2 capability");
93
+ return { healthy: true, buyer, sellerCapabilities: catalog.map(({ registration }) => registration.manifest.capabilityId) };
94
+ }
95
+ finally {
96
+ app.close();
97
+ }
98
+ }
99
+ const roles = homes(stateDir()), reports = {};
100
+ for (const [name, home] of Object.entries(roles)) {
101
+ const app = new Phase3App(home);
102
+ try {
103
+ const report = (await app.execute("doctor", {})).data;
104
+ if (report.readyForDemo === false)
105
+ fail("DEMO_PREREQUISITES_MISSING", `${name}: ${report.fixes.join(" ")}`);
106
+ reports[name] = report;
107
+ }
108
+ finally {
109
+ app.close();
110
+ }
111
+ }
112
+ let remote;
113
+ if (typeof args["seller-url"] === "string") {
114
+ const base = new URL(args["seller-url"]), health = await fetch(new URL("/health", base), { signal: AbortSignal.timeout(90_000) }), catalog = await fetch(new URL("/v1/catalog", base), { signal: AbortSignal.timeout(30_000) });
115
+ if (!health.ok || !catalog.ok)
116
+ fail("SELLER_SERVICE_UNAVAILABLE", "remote seller health or catalog check failed");
117
+ const body = await catalog.json(), capabilities = body.capabilities ?? [];
118
+ if (capabilities.filter((item) => item.manifest?.capability === "sui.market-brief").length < 2 || !capabilities.some((item) => item.manifest?.capability === "sui.competitor-analysis"))
119
+ fail("SELLER_CATALOG_INVALID", "remote catalog needs two briefs and one competitor analysis");
120
+ remote = { healthy: true, origin: base.origin, capabilities: capabilities.length };
121
+ }
122
+ return { healthy: true, roles: reports, isolation: new Set(Object.values(roles)).size === 5, ...(remote ? { remote } : {}) };
123
+ }
124
+ async function seedPolicy() {
125
+ const source = JSON.parse(readFileSync(resolve(value("workflow")), "utf8"));
126
+ const manifest = source.capabilities?.find((item) => item.capability === "sui.competitor-analysis") ?? fail("DEMO_POLICY_SCOPE_INVALID", "workflow has no competitor analysis capability");
127
+ validateCapabilityManifest(manifest);
128
+ if (manifest.capability !== "sui.competitor-analysis")
129
+ fail("DEMO_POLICY_SCOPE_INVALID", "privacy policy must target the competitor analysis capability");
130
+ const app = new Phase3App(homes(stateDir()).buyer);
131
+ try {
132
+ if (app.profile.mock)
133
+ fail("LIVE_PROFILE_REQUIRED", "saved demo privacy policy requires a live buyer profile");
134
+ const memory = { version: "supercuts.settlement-memory.v1", kind: "privacy_rule", scope: { capabilityId: manifest.capabilityId, counterparty: manifest.sellerId, network: "sui:testnet", asset: manifest.asset }, createdAt: Date.now(), signal: { requiresShielded: true } };
135
+ const parameters = { "operation-id": value("operation-id", `privacy-${manifest.capabilityId}`), memory: Buffer.from(JSON.stringify(memory)).toString("base64url") };
136
+ const token = app.approve(app.preview("memory.policy", parameters).challengeId);
137
+ const result = (await app.execute("memory.policy", { ...parameters, "approval-token": token.token })).data;
138
+ return { capabilityId: manifest.capabilityId, sellerId: manifest.sellerId, blobId: result.blobId, kind: result.kind, provenance: result.provenance };
139
+ }
140
+ finally {
141
+ app.close();
142
+ }
143
+ }
144
+ async function check() {
145
+ if (typeof args["buyer-home"] === "string") {
146
+ const home = resolve(args["buyer-home"]), sellerHome = resolve(value("seller-home")), path = resolve(value("events"));
147
+ if (!existsSync(home) || (statSync(home).mode & 0o077) !== 0 || !existsSync(sellerHome) || (statSync(sellerHome).mode & 0o077) !== 0 || !existsSync(path) || (statSync(path).mode & 0o077) !== 0)
148
+ fail("DEMO_PERMISSIONS", "generic role homes and event stream must be owner-only");
149
+ const profile = JSON.parse(readFileSync(join(home, "profile.json"), "utf8"));
150
+ if (profile.role !== "buyer" || profile.mock || profile.verifierVersion !== 2)
151
+ fail("LIVE_PROFILE_REQUIRED", "generic Codex demo requires a live v2 buyer home");
152
+ const raw = readFileSync(path, "utf8");
153
+ if (/(?:suiprivkey|BEGIN [A-Z ]*PRIVATE KEY|approval.?token|note.?opening|full.?prompt)/i.test(raw))
154
+ fail("SECRET_SCAN_FAILED", "event bundle contains forbidden secret material");
155
+ const events = readDemoEvents(path), deals = events.filter((event) => event.stage === "deal-lifecycle" && event.status === "complete" && event.publicDetails.state === "complete");
156
+ if (!events.length || events.some((event) => event.mode !== "live" || event.runId !== events[0].runId))
157
+ fail("DEMO_EVENTS_INVALID", "recording needs one nonempty live event stream for a single run");
158
+ const rails = new Map(deals.map((event) => [event.publicDetails.rail, event]));
159
+ const memories = events.filter((event) => event.stage === "memory" && event.status === "complete" && typeof event.publicDetails.blobId === "string");
160
+ const recall = events.find((event) => event.stage === "memory-recall" && Array.isArray(event.publicDetails.citations) && event.publicDetails.citations.some((citation) => citation.kind === "privacy_rule" && citation.provenance === "owner_policy"));
161
+ const policyCitation = recall?.publicDetails.citations?.find((citation) => citation.kind === "privacy_rule" && citation.provenance === "owner_policy" && typeof citation.blobId === "string");
162
+ const privacyPlan = events.find((event) => event.stage === "settlement-plan" && event.status === "complete" && event.publicDetails.rail === "shielded" && Array.isArray(event.publicDetails.reasonCodes) && event.publicDetails.reasonCodes.includes("MEMORY_PRIVACY_APPLIED") && recall && event.sequence > recall.sequence && policyCitation && Array.isArray(event.publicDetails.blobIds) && event.publicDetails.blobIds.includes(policyCitation.blobId));
163
+ const prefund = events.find((event) => event.stage === "prefunding" && event.status === "complete" && typeof event.publicDetails.transactionDigest === "string");
164
+ const exit = events.find((event) => event.actor === "confidential-seller" && event.stage === "delayed-exit" && event.status === "complete" && event.publicDetails.state === "queued");
165
+ const publicDeal = rails.get("x402"), privateDeal = rails.get("shielded");
166
+ if (!prefund || !exit || !recall || !privacyPlan || memories.length < 10 || new Set(memories.map((event) => event.publicDetails.blobId)).size < 10 || memories.some((event) => String(event.publicDetails.blobId).startsWith("mockwalrus_")) || !publicDeal || !privateDeal || [...rails.values()].some((event) => event.publicDetails.payment !== "finalized" || event.publicDetails.agreement !== "verified" || event.publicDetails.delivery !== "verified" || event.publicDetails.outcomeMemory !== "indexed" || typeof event.publicDetails.paymentDigest !== "string") || prefund.sequence >= publicDeal.sequence || publicDeal.sequence >= Math.min(...memories.map((event) => event.sequence)) || Math.max(...memories.map((event) => event.sequence)) >= recall.sequence || recall.sequence >= privacyPlan.sequence || privacyPlan.sequence >= privateDeal.sequence || privateDeal.sequence >= exit.sequence)
167
+ fail("DEMO_ACCEPTANCE_INCOMPLETE", "generic Codex stream needs prefunding, public delivery, ten memories, recalled privacy, shielded delivery, then a queued seller exit in that order");
168
+ const buyer = new Phase3App(home), seller = new Phase3App(sellerHome);
169
+ try {
170
+ if (seller.profile.role !== "seller" || seller.profile.mock || seller.profile.verifierVersion !== 2)
171
+ fail("LIVE_PROFILE_REQUIRED", "queued exit must belong to a separate live v2 seller");
172
+ const journal = new DealJournal(buyer.store);
173
+ for (const event of memories) {
174
+ const row = buyer.store.db.prepare("SELECT 1 FROM memory_jobs WHERE blob_id=? AND status='complete'").get(String(event.publicDetails.blobId));
175
+ if (!row)
176
+ fail("DEMO_EVIDENCE_MISMATCH", "logged memory is absent from completed buyer writes");
177
+ }
178
+ for (const event of rails.values()) {
179
+ const dealId = String(event.publicDetails.dealId ?? ""), row = buyer.store.db.prepare("SELECT operation_id FROM deal_operations WHERE deal_id=?").get(dealId);
180
+ if (!row)
181
+ fail("DEMO_EVIDENCE_MISMATCH", "logged deal is absent from buyer journal");
182
+ const view = journal.get(row.operation_id), evidence = journal.evidence(dealId);
183
+ if (view.state !== "complete" || view.rail !== event.publicDetails.rail || view.paymentDigest !== event.publicDetails.paymentDigest || evidence.inventory !== "indexed" || !evidence.paymentFinalized || evidence.ciphertextReadback !== "verified")
184
+ fail("DEMO_EVIDENCE_MISMATCH", "logged deal differs from verified buyer journal");
185
+ }
186
+ const funded = buyer.store.db.prepare("SELECT 1 FROM live_signed_transactions AS tx JOIN live_operation_context AS context ON context.operation_id=tx.operation_id WHERE tx.digest=? AND tx.status='finalized' AND context.kind='deposit' AND context.subject=?").get(String(prefund.publicDetails.transactionDigest), String(prefund.publicDetails.amount ?? ""));
187
+ const queued = new V2ExitQueue(seller.store).get(String(exit.publicDetails.operationId ?? ""));
188
+ const recovered = queued ? seller.store.db.prepare("SELECT 1 FROM notes WHERE commitment=? AND role='payment'").get(queued.commitment) : undefined;
189
+ if (!funded || !queued || !recovered)
190
+ fail("DEMO_EVIDENCE_MISMATCH", "prefunding or recovered seller exit is absent from its role journal");
191
+ return { healthy: true, checked: [home, sellerHome, path], secretScan: "pass", deals: deals.length };
192
+ }
193
+ finally {
194
+ buyer.close();
195
+ seller.close();
196
+ }
197
+ }
198
+ const root = stateDir(), roles = homes(root), checked = [];
199
+ for (const path of [root, ...Object.values(roles)]) {
200
+ if (!existsSync(path) || (statSync(path).mode & 0o077) !== 0)
201
+ fail("DEMO_PERMISSIONS", `${path} is missing or not owner-only`);
202
+ checked.push(path);
203
+ }
204
+ const runPath = join(root, "run.json"), run = existsSync(runPath) ? JSON.parse(readFileSync(runPath, "utf8")) : {};
205
+ const eventPath = typeof args.events === "string" ? resolve(args.events) : run.eventPath ?? join(root, "events.jsonl");
206
+ if (!existsSync(eventPath))
207
+ fail("DEMO_EVENTS_MISSING", "demo event stream is missing");
208
+ if (existsSync(eventPath)) {
209
+ const text = readFileSync(eventPath, "utf8");
210
+ if (/(?:suiprivkey|BEGIN [A-Z ]*PRIVATE KEY|approval.?token|note.?opening|full.?prompt)/i.test(text))
211
+ fail("SECRET_SCAN_FAILED", "event bundle contains forbidden secret material");
212
+ const events = readDemoEvents(eventPath);
213
+ checked.push(eventPath);
214
+ if (!events.length || events.some((event) => event.mode !== "live" || event.runId !== events[0].runId))
215
+ fail("DEMO_EVENTS_INVALID", "recording needs one nonempty live event stream for a single run");
216
+ const remoteFlow = events.some((event) => event.stage === "run" && event.publicDetails.flow === "codex-remote");
217
+ if (args["require-claude"] === true && !remoteFlow && !["buyer", "public-seller", "confidential-seller"].every((actor) => events.some((event) => event.actor === actor && event.stage === "agent-decision" && event.status === "complete" && typeof event.publicDetails.model === "string" && Number(event.publicDetails.outputTokens) > 0)))
218
+ fail("DEMO_CLAUDE_EVIDENCE_MISSING", "event stream is missing live Claude decisions from a buyer or seller agent");
219
+ const decisionKeys = { "settlement-plan": new Set(["phase", "planHash", "capabilityId", "rail", "openingAmount", "maximumAmount", "riskLevel", "reasonCodes", "blobIds"]), "memory-recall": new Set(["restarted", "citations", "policyBlobId"]) };
220
+ for (const event of events) {
221
+ const allowed = decisionKeys[event.stage];
222
+ if (allowed && Object.keys(event.publicDetails).some((key) => !allowed.has(key)))
223
+ fail("DEMO_DECISION_EVENT_INVALID", `${event.stage} contains a non-allowlisted public field`);
224
+ }
225
+ if (remoteFlow) {
226
+ const memories = events.filter((event) => event.stage === "memory" && event.status === "complete" && event.publicDetails.kind !== undefined);
227
+ const deliveries = events.filter((event) => event.stage === "artifact-delivery" && event.status === "complete");
228
+ if (memories.length < 10 || new Set(memories.map((event) => event.publicDetails.blobId)).size < 10 || memories.some((event) => String(event.publicDetails.blobId).startsWith("mockwalrus_")) || !events.some((event) => event.stage === "memory-recall" && Array.isArray(event.publicDetails.citations) && event.publicDetails.citations.some((citation) => citation.kind === "privacy_rule" && citation.provenance === "owner_policy")) || !events.some((event) => event.stage === "settlement-plan" && event.publicDetails.rail === "shielded" && Array.isArray(event.publicDetails.reasonCodes) && event.publicDetails.reasonCodes.includes("MEMORY_PRIVACY_APPLIED")) || !events.some((event) => event.stage === "public-settlement" && typeof event.publicDetails.transactionDigest === "string") || !events.some((event) => event.stage === "private-settlement" && typeof event.publicDetails.transactionDigest === "string" && event.evidenceHashes.length > 0) || deliveries.length < 2 || new Set(deliveries.map((event) => event.publicDetails.artifactSha256)).size < 2)
229
+ fail("DEMO_ACCEPTANCE_INCOMPLETE", "remote event stream lacks ten memories, recalled privacy, both funded payments, or both deliveries");
230
+ }
231
+ else if (events.some((event) => event.stage === "settlement-plan")) {
232
+ const memoryBlobIds = events.filter((event) => event.stage === "memory" && event.status === "complete").map((event) => String(event.publicDetails.blobId ?? ""));
233
+ if (memoryBlobIds.length < 10 || new Set(memoryBlobIds).size < 10 || memoryBlobIds.some((id) => !id || id.startsWith("mockwalrus_")) || !events.some((event) => event.stage === "memory-recall" && event.publicDetails.restarted === true && Array.isArray(event.publicDetails.citations) && event.publicDetails.citations.some((citation) => citation.kind === "privacy_rule" && citation.provenance === "owner_policy")) || !events.some((event) => event.stage === "settlement-plan" && event.publicDetails.phase === "after-memory" && event.publicDetails.rail === "shielded" && Array.isArray(event.publicDetails.reasonCodes) && event.publicDetails.reasonCodes.includes("MEMORY_PRIVACY_APPLIED")) || !events.some((event) => event.stage === "public-settlement" && event.status === "complete") || !events.some((event) => event.stage === "artifact-delivery" && event.status === "complete") || !events.some((event) => event.stage === "private-settlement" && event.status === "complete" && event.evidenceHashes.length > 0))
234
+ fail("DEMO_ACCEPTANCE_INCOMPLETE", "event stream does not contain the required memory-native funded settlement sequence");
235
+ }
236
+ if (events.some((event) => event.stage === "private-settlement" && event.publicDetails.poolVersion === 2)) {
237
+ const prefund = events.find((event) => event.stage === "prefunding" && event.status === "complete" && typeof event.publicDetails.transactionDigest === "string");
238
+ const negotiation = events.find((event) => event.stage === "negotiation" && event.status === "complete");
239
+ const privatePayment = events.find((event) => event.stage === "private-settlement" && event.status === "complete");
240
+ const delayed = events.find((event) => event.stage === "delayed-exit" && event.status === "complete" && event.publicDetails.state === "queued");
241
+ if (!prefund || !negotiation || !privatePayment || !delayed || prefund.sequence >= negotiation.sequence || privatePayment.sequence >= delayed.sequence)
242
+ fail("DEMO_V2_SEQUENCE_INVALID", "v2 demo needs finalized prefunding before negotiation and a queued seller exit after settlement");
243
+ }
244
+ const required = (stage) => events.find((event) => event.stage === stage && event.status === "complete")?.sequence;
245
+ const lastMemory = Math.max(...events.filter((event) => event.stage === "memory" && event.status === "complete").map((event) => event.sequence));
246
+ const recallAfterMemories = events.find((event) => event.stage === "memory-recall" && event.status === "complete" && event.sequence > lastMemory)?.sequence;
247
+ const sequence = [required("prefunding"), required("negotiation"), required("public-settlement"), required("artifact-delivery"), required("memory"), recallAfterMemories, events.find((event) => event.stage === "settlement-plan" && event.status === "complete" && event.publicDetails.rail === "shielded" && event.sequence > (recallAfterMemories ?? 0))?.sequence, required("private-settlement"), events.find((event) => event.actor === "confidential-seller" && event.stage === "delayed-exit" && event.status === "complete" && event.publicDetails.state === "queued")?.sequence];
248
+ if (sequence.some((step) => step === undefined) || sequence.some((step, index) => index > 0 && step <= sequence[index - 1]))
249
+ fail("DEMO_SEQUENCE_INVALID", "live recording must show prefunding, public purchase, memories, privacy recall, shielded payment, and seller exit in order");
250
+ const completedMemories = events.filter((event) => event.stage === "memory" && event.status === "complete" && typeof event.publicDetails.blobId === "string" && !event.publicDetails.blobId.startsWith("mockwalrus_"));
251
+ if (new Set(completedMemories.map((event) => event.publicDetails.blobId)).size < 10 || completedMemories.some((event) => event.sequence <= sequence[3] || event.sequence >= sequence[5]))
252
+ fail("DEMO_MEMORY_SEQUENCE_INVALID", "ten distinct completed live memories must appear after public delivery and before privacy recall");
253
+ const cited = events.find((event) => event.stage === "memory-recall" && event.sequence === sequence[5])?.publicDetails.citations;
254
+ const policyBlobId = Array.isArray(cited) ? cited.find((item) => item.kind === "privacy_rule" && item.provenance === "owner_policy")?.blobId : undefined;
255
+ const plan = events.find((event) => event.stage === "settlement-plan" && event.sequence === sequence[6]);
256
+ if (!policyBlobId || !Array.isArray(plan?.publicDetails.blobIds) || !plan.publicDetails.blobIds.includes(policyBlobId) || !Array.isArray(plan.publicDetails.reasonCodes) || !plan.publicDetails.reasonCodes.includes("MEMORY_PRIVACY_APPLIED"))
257
+ fail("DEMO_PRIVACY_EVIDENCE_MISSING", "shielded plan must cite the recalled owner privacy rule");
258
+ if (remoteFlow) {
259
+ const exitEvent = events.find((event) => event.actor === "confidential-seller" && event.stage === "delayed-exit" && event.sequence === sequence[8]);
260
+ const requiredEnv = (name) => process.env[name] ?? fail("SELLER_CONFIG_MISSING", `${name} is required to verify the hosted seller exit`);
261
+ const runId = run.runId || fail("DEMO_RUN_INVALID", "run.json is missing the run ID"), sellerId = run.addresses?.confidentialSeller || fail("DEMO_RUN_INVALID", "run.json is missing the confidential seller");
262
+ if (runId !== events[0].runId)
263
+ fail("DEMO_RUN_INVALID", "remote event stream does not match run.json");
264
+ const queued = await inspectHostedExit(new SellerDatabase(requiredEnv("SUPABASE_URL"), requiredEnv("SUPABASE_SERVICE_ROLE_KEY")), requiredEnv("SELLER_STATE_KEY"), { sellerId, runId, sessionId: String(exitEvent.publicDetails.sessionId ?? "") });
265
+ if (queued.operationId !== exitEvent.publicDetails.operationId || queued.amount !== exitEvent.publicDetails.amount || queued.executeAt !== exitEvent.publicDetails.executeAt || queued.windowEnd !== exitEvent.publicDetails.windowEnd)
266
+ fail("DEMO_EVIDENCE_MISMATCH", "recorded hosted seller exit differs from its encrypted state snapshot");
267
+ }
268
+ else {
269
+ const buyer = new Phase3App(roles.buyer), seller = new Phase3App(roles.confidentialSeller);
270
+ try {
271
+ if (buyer.profile.mock || seller.profile.mock || buyer.profile.verifierVersion !== 2 || seller.profile.verifierVersion !== 2)
272
+ fail("LIVE_PROFILE_REQUIRED", "recorded payment evidence needs separate live v2 buyer and seller roles");
273
+ for (const [stage, kind] of [["prefunding", "deposit"], ["public-settlement", "x402"], ["private-settlement", "shielded"]]) {
274
+ const digest = events.find((event) => event.stage === stage && event.status === "complete")?.publicDetails.transactionDigest;
275
+ const row = typeof digest === "string" && buyer.store.db.prepare("SELECT 1 FROM live_signed_transactions AS tx JOIN live_operation_context AS context ON context.operation_id=tx.operation_id WHERE tx.digest=? AND tx.status='finalized' AND context.kind=?").get(digest, kind);
276
+ if (!row)
277
+ fail("DEMO_EVIDENCE_MISMATCH", `${stage} digest is not a finalized ${kind} transaction in the buyer journal`);
278
+ }
279
+ for (const event of completedMemories)
280
+ if (!buyer.store.db.prepare("SELECT 1 FROM memory_jobs WHERE blob_id=? AND status='complete'").get(String(event.publicDetails.blobId)))
281
+ fail("DEMO_EVIDENCE_MISMATCH", "recorded memory is not a completed buyer write");
282
+ const exitEvent = events.find((event) => event.stage === "delayed-exit" && event.sequence === sequence[8]);
283
+ const queued = new V2ExitQueue(seller.store).get(String(exitEvent.publicDetails.operationId ?? ""));
284
+ if (!queued || queued.amount.toString() !== exitEvent.publicDetails.amount || !seller.store.db.prepare("SELECT 1 FROM notes WHERE commitment=? AND role='payment'").get(queued.commitment))
285
+ fail("DEMO_EVIDENCE_MISMATCH", "recorded exit is not queued against a recovered seller payment note");
286
+ }
287
+ finally {
288
+ buyer.close();
289
+ seller.close();
290
+ }
291
+ }
292
+ }
293
+ return { healthy: true, checked, secretScan: "pass" };
294
+ }
295
+ function reuseMemories() {
296
+ const home = resolve(value("buyer-home")), path = resolve(value("events")), buyer = new Phase3App(home);
297
+ try {
298
+ if (buyer.profile.role !== "buyer" || buyer.profile.mock)
299
+ fail("LIVE_PROFILE_REQUIRED", "memory reuse requires a live buyer home");
300
+ const completed = buyer.store.db.prepare("SELECT operation_id,blob_id FROM memory_jobs WHERE operation_id LIKE 'memory-%' AND status='complete' AND blob_id IS NOT NULL ORDER BY created_at DESC").all();
301
+ const selected = [...new Map(completed.filter((item) => !item.blob_id.startsWith("mockwalrus_")).map((item) => [item.blob_id, item])).values()].slice(0, 10);
302
+ if (selected.length < 10)
303
+ fail("DEMO_MEMORIES_MISSING", "buyer has fewer than ten completed live advisory memories");
304
+ const existing = readDemoEvents(path), runId = existing[0]?.runId ?? fail("DEMO_EVENTS_MISSING", "start the Codex MCP event stream before recording reused memories");
305
+ const log = new DemoEventLog(path, runId);
306
+ for (const item of selected)
307
+ log.append({ actor: "buyer", stage: "memory", status: "complete", publicDetails: { blobId: item.blob_id, kind: "reused-live-memory", reused: true }, evidenceHashes: [], explorerLinks: [] });
308
+ return { reused: selected.length, eventPath: path, runId };
309
+ }
310
+ finally {
311
+ buyer.close();
312
+ }
313
+ }
314
+ async function live() {
315
+ const root = stateDir(), workflow = JSON.parse(readFileSync(resolve(value("workflow")), "utf8")), eventPath = typeof args.events === "string" ? resolve(args.events) : join(root, "events.jsonl"), log = new DemoEventLog(eventPath, randomUUID(), "live"), roleHomes = homes(root);
316
+ let buyer = new Phase3App(roleHomes.buyer);
317
+ const publicSeller = new Phase3App(roleHomes.publicSeller), confidentialSeller = new Phase3App(roleHomes.confidentialSeller);
318
+ if (buyer.profile.mock)
319
+ fail("LIVE_PROFILE_REQUIRED", "supercuts-demo live refuses mock profiles");
320
+ const claudeKeyPath = typeof args["claude-key-file"] === "string" ? resolve(args["claude-key-file"]) : undefined;
321
+ if (claudeKeyPath && (statSync(claudeKeyPath).mode & 0o077) !== 0)
322
+ fail("CREDENTIAL_PERMISSIONS", "Claude key file must be owner-only");
323
+ const claudeKey = (claudeKeyPath ? readFileSync(claudeKeyPath, "utf8") : process.env.CLAUDE_API_KEY ?? "").trim();
324
+ if (!claudeKey)
325
+ fail("CLAUDE_CREDENTIAL_MISSING", "export CLAUDE_API_KEY or provide --claude-key-file");
326
+ const claude = (actor) => new BoundedClaude({ apiKey: claudeKey, onDecision: (entry) => log.append({ actor, stage: "agent-decision", status: "complete", publicDetails: { model: entry.model, action: entry.action, inputTokens: entry.usage.inputTokens, outputTokens: entry.usage.outputTokens }, evidenceHashes: [], explorerLinks: [] }) });
327
+ const mutate = async (app, name, parameters) => { const intent = app.preview(name, parameters), approval = app.approve(intent.challengeId); return (await app.execute(name, { ...parameters, "approval-token": approval.token })).data; };
328
+ try {
329
+ log.append({ actor: "operator", stage: "run", status: "started", publicDetails: { label: "fresh funded run" }, evidenceHashes: [], explorerLinks: [] });
330
+ for (const manifest of workflow.capabilities)
331
+ validateCapabilityManifest(manifest);
332
+ const publicCapabilities = workflow.capabilities.filter((item) => item.supportedRails.includes("x402") && item.endpoint === workflow.publicResourceUrl), confidentialCapabilities = workflow.capabilities.filter((item) => item.supportedRails.includes("shielded"));
333
+ if (!publicCapabilities.length || !confidentialCapabilities.length)
334
+ fail("DEMO_CAPABILITIES_REQUIRED", "workflow must contain matching public x402 and confidential shielded capabilities");
335
+ const confidential = confidentialCapabilities[0], depositAmount = BigInt(workflow.buyerDepositAmount ?? "0");
336
+ if (depositAmount <= BigInt(confidential.priceBand.minimum))
337
+ fail("DEMO_DEPOSIT_INSUFFICIENT", "buyerDepositAmount must exceed the confidential payment to leave a change note");
338
+ if (buyer.profile.verifierVersion === 2 && (!workflow.exitWindow || !Number.isSafeInteger(workflow.exitWindow.startOffsetMs) || !Number.isSafeInteger(workflow.exitWindow.endOffsetMs) || workflow.exitWindow.startOffsetMs < 60_000 || workflow.exitWindow.endOffsetMs <= workflow.exitWindow.startOffsetMs || workflow.exitWindow.endOffsetMs - workflow.exitWindow.startOffsetMs > 7 * 24 * 60 * 60_000))
339
+ fail("DEMO_EXIT_WINDOW_REQUIRED", "v2 workflow needs an owner-selected delayed exit window");
340
+ const prefund = await mutate(buyer, "wallet.deposit", { "operation-id": `prefund-${log.runId}`, amount: depositAmount.toString() });
341
+ log.append({ actor: "buyer", stage: "prefunding", status: "complete", publicDetails: { amount: depositAmount.toString(), transactionDigest: prefund.transactionDigest, visibility: "deposit amount, sender, gas, and timing are public" }, evidenceHashes: [], explorerLinks: [] });
342
+ const buyerChoice = await claude("buyer").decide({ system: "You are the buyer agent. Select one listed public capability. Amounts and payment authority are enforced by Supercuts.", task: workflow.publicTask, candidates: publicCapabilities.map((item) => ({ capabilityId: item.capabilityId, description: item.description, priceBand: item.priceBand })), schema: { name: "select_public_capability", description: "Select one policy-approved public capability.", properties: { choice: { type: "string", enum: publicCapabilities.map((item) => item.capabilityId) } }, required: ["choice"] } });
343
+ const selectedPublic = publicCapabilities.find((item) => item.capabilityId === buyerChoice.action.choice) ?? fail("CLAUDE_OUTPUT_INVALID", "buyer selected an unknown capability");
344
+ if (!workflow.publicOperationId || workflow.publicOperationId.length > 256)
345
+ fail("DEMO_PUBLIC_OPERATION_REQUIRED", "workflow must bind the seller resource to a fixed publicOperationId");
346
+ const publicOperation = workflow.publicOperationId, publicPlan = await mutate(buyer, "settlement.plan", { "operation-id": publicOperation, manifest: Buffer.from(JSON.stringify(selectedPublic)).toString("base64url"), alternatives: Buffer.from(JSON.stringify(publicCapabilities.filter((item) => item !== selectedPublic))).toString("base64url"), "requested-amount": workflow.buyerOpeningAmount });
347
+ log.append({ actor: "buyer", stage: "settlement-plan", status: "complete", publicDetails: { phase: "before-memory", planHash: publicPlan.planHash, capabilityId: publicPlan.capabilityId, rail: publicPlan.rail, openingAmount: publicPlan.openingAmount, maximumAmount: publicPlan.maximumAmount, riskLevel: publicPlan.riskLevel, reasonCodes: publicPlan.reasonCodes, blobIds: [] }, evidenceHashes: [String(publicPlan.manifestHash)], explorerLinks: [] });
348
+ const challengeResponse = await fetch(workflow.publicResourceUrl, { redirect: "error", signal: AbortSignal.timeout(30_000) });
349
+ if (challengeResponse.status !== 402)
350
+ fail("X402_CHALLENGE_REQUIRED", "public seller did not return an x402 challenge");
351
+ const challengeHeader = challengeResponse.headers.get("payment-required") ?? fail("X402_CHALLENGE_INVALID", "public seller challenge omitted PAYMENT-REQUIRED"), challenge = JSON.parse(Buffer.from(challengeHeader, "base64").toString()), sellerMinimum = BigInt(String(challenge.accepts?.[0]?.amount ?? "0"));
352
+ await challengeResponse.arrayBuffer();
353
+ const agreed = deterministicCounteroffer({ buyerOffer: BigInt(workflow.buyerOpeningAmount), buyerMaximum: BigInt(workflow.buyerMaximum), sellerMinimum });
354
+ if (agreed !== sellerMinimum)
355
+ fail("NEGOTIATION_PAYMENT_MISMATCH", "deterministic agreement must equal the seller's exact x402 requirement");
356
+ await claude("public-seller").decide({ system: "You are the public seller agent. The exact price is fixed by the signed x402 challenge. You may only present the approved counteroffer.", task: `Respond to the buyer offer for capability ${selectedPublic.capabilityId}.`, candidates: [{ action: "present_counteroffer", amount: agreed.toString(), asset: selectedPublic.asset }], schema: { name: "respond_to_offer", description: "Present the backend-approved exact amount.", properties: { action: { type: "string", enum: ["present_counteroffer"] } }, required: ["action"] } });
357
+ const session = `public-${log.runId}`;
358
+ await mutate(buyer, "offer.open", { "operation-id": `${session}-open`, session });
359
+ await mutate(buyer, "offer.propose", { "operation-id": `${session}-propose`, session, revision: "1", terms: JSON.stringify({ amount: workflow.buyerOpeningAmount, rail: "x402" }) });
360
+ await mutate(publicSeller, "offer.counter", { "operation-id": `${session}-counter`, session, revision: "2", terms: JSON.stringify({ amount: agreed.toString(), rail: "x402" }) });
361
+ await mutate(buyer, "offer.accept", { "operation-id": `${session}-accept`, session, revision: "3", terms: JSON.stringify({ amount: agreed.toString(), rail: "x402" }) });
362
+ log.append({ actor: "supercuts", stage: "negotiation", status: "complete", publicDetails: { session, agreedAmount: agreed.toString(), rail: "x402", pricing: "deterministic" }, evidenceHashes: [], explorerLinks: [] });
363
+ const publicPayment = await mutate(buyer, "pay.x402", { "operation-id": publicOperation, "resource-url": workflow.publicResourceUrl, "plan-hash": String(publicPlan.planHash) });
364
+ const { response: _artifactBytes, ...publicEvidence } = publicPayment;
365
+ log.append({ actor: "buyer", stage: "public-settlement", status: "complete", publicDetails: { rail: "x402", visibility: "public amount and payee", ...publicEvidence }, evidenceHashes: [String(publicPayment.responseSha256 ?? "")].filter(Boolean), explorerLinks: [] });
366
+ log.append({ actor: "buyer", stage: "artifact-delivery", status: "complete", publicDetails: { capabilityId: publicPlan.capabilityId, requestId: publicPayment.requestId, artifactSha256: publicPayment.responseSha256 }, evidenceHashes: [String(publicPayment.responseSha256 ?? "")].filter(Boolean), explorerLinks: [] });
367
+ const memories = workflow.memories;
368
+ if (!Array.isArray(memories) || memories.length !== 10 || memories.some((item) => typeof item !== "string" || !item.trim() || item.length > 512))
369
+ fail("DEMO_MEMORY_COUNT", "live workflow must provide exactly ten short meaningful first-purchase memories");
370
+ const reuseRunId = typeof args["reuse-memory-run-id"] === "string" ? args["reuse-memory-run-id"] : undefined;
371
+ if (reuseRunId && !/^[0-9a-f-]{36}$/i.test(reuseRunId))
372
+ fail("DEMO_MEMORY_RUN_INVALID", "reuse-memory-run-id must identify a prior run");
373
+ const reusedMemory = (operationId, expectedKind, expectedObservation) => {
374
+ const row = buyer.store.db.prepare("SELECT blob_id,status FROM memory_jobs WHERE operation_id=?").get(operationId);
375
+ if (!row || row.status !== "complete" || !row.blob_id)
376
+ fail("DEMO_MEMORY_REUSE_MISSING", "prior memory is not complete");
377
+ const stored = buyer.store.getSecret(`memory:${row.blob_id}`) ?? fail("DEMO_MEMORY_REUSE_MISSING", "prior memory opening is unavailable locally");
378
+ const memory = JSON.parse(stored.toString());
379
+ if (memory.kind !== expectedKind || (expectedObservation !== undefined && memory.observation !== expectedObservation) || (expectedKind === "privacy_rule" && (memory.scope?.capabilityId !== confidential.capabilityId || memory.scope?.counterparty !== confidential.sellerId)))
380
+ fail("DEMO_MEMORY_REUSE_MISMATCH", "prior memory does not match this workflow");
381
+ return { blobId: row.blob_id, kind: memory.kind, provenance: memory.provenance ?? "agent_observation" };
382
+ };
383
+ for (let index = 0; index < memories.length; index++) {
384
+ const envelope = { version: "supercuts.settlement-memory.v1", kind: index % 2 ? "quality" : "reliability", observation: memories[index], scope: { capabilityId: String(publicPlan.capabilityId), counterparty: String(publicPlan.sellerId), network: "sui:testnet", asset: String(publicPlan.asset) }, createdAt: Date.now() + index, signal: index % 2 ? { quality: Math.min(1, 0.8 + index / 100) } : { reliability: Math.min(1, 0.8 + index / 100) } };
385
+ const operationId = reuseRunId ? `memory-${reuseRunId}-${index}` : `memory-${log.runId}-${index}`;
386
+ const remembered = reuseRunId ? reusedMemory(operationId, envelope.kind, memories[index]) : await mutate(buyer, "memory.remember", { "operation-id": operationId, memory: Buffer.from(JSON.stringify(envelope)).toString("base64url") });
387
+ log.append({ actor: "buyer", stage: "memory", status: "complete", publicDetails: { index: index + 1, blobId: remembered.blobId, kind: remembered.kind, provenance: remembered.provenance, ...(reuseRunId ? { reusedFromRun: reuseRunId } : {}) }, evidenceHashes: [], explorerLinks: [] });
388
+ }
389
+ const policyEnvelope = { version: "supercuts.settlement-memory.v1", kind: "privacy_rule", scope: { capabilityId: confidential.capabilityId, counterparty: confidential.sellerId, network: "sui:testnet", asset: confidential.asset }, createdAt: Date.now() + 20, signal: { requiresShielded: true } };
390
+ const privacyOperation = `privacy-${reuseRunId ?? log.runId}`;
391
+ const privacy = reuseRunId ? reusedMemory(privacyOperation, "privacy_rule") : await mutate(buyer, "memory.policy", { "operation-id": privacyOperation, memory: Buffer.from(JSON.stringify(policyEnvelope)).toString("base64url") });
392
+ buyer.close();
393
+ buyer = new Phase3App(roleHomes.buyer);
394
+ const recalled = (await buyer.execute("memory.recall", { query: `${confidential.capabilityId} privacy settlement` })).data;
395
+ log.append({ actor: "supercuts", stage: "memory-recall", status: "complete", publicDetails: { restarted: true, citations: recalled.citations, policyBlobId: privacy.blobId }, evidenceHashes: [], explorerLinks: [] });
396
+ if (!confidential.supportedRails.includes("x402"))
397
+ fail("DEMO_PRIVACY_ALTERNATIVE_REQUIRED", "confidential capability must offer x402 and shielded rails to demonstrate memory-driven selection");
398
+ if (!recalled.citations.some((item) => item.blobId === privacy.blobId && item.kind === "privacy_rule"))
399
+ fail("DEMO_PRIVACY_RECALL_MISSING", "owner privacy rule was not cited by Walrus Memory recall");
400
+ const privateOperation = `private-${log.runId}`, privatePlan = await mutate(buyer, "settlement.plan", { "operation-id": privateOperation, manifest: Buffer.from(JSON.stringify(confidential)).toString("base64url"), alternatives: Buffer.from(JSON.stringify(confidentialCapabilities.slice(1))).toString("base64url"), "requested-amount": confidential.priceBand.minimum });
401
+ if (privatePlan.rail !== "shielded" || !privatePlan.reasonCodes.includes("MEMORY_PRIVACY_APPLIED"))
402
+ fail("DEMO_PRIVACY_PLAN_MISSING", "the recalled owner policy did not select shielded settlement");
403
+ await claude("buyer").decide({ system: "You are the buyer agent. The owner privacy rule and approved settlement plan require the shielded rail. You may only choose the approved next action.", task: workflow.confidentialTask, candidates: [{ action: "proceed_shielded", capabilityId: privatePlan.capabilityId, rail: privatePlan.rail }], schema: { name: "choose_private_action", description: "Choose the policy-approved action.", properties: { action: { type: "string", enum: ["proceed_shielded"] } }, required: ["action"] } });
404
+ log.append({ actor: "buyer", stage: "settlement-plan", status: "complete", publicDetails: { phase: "after-memory", planHash: privatePlan.planHash, capabilityId: privatePlan.capabilityId, rail: privatePlan.rail, openingAmount: privatePlan.openingAmount, maximumAmount: privatePlan.maximumAmount, riskLevel: privatePlan.riskLevel, reasonCodes: privatePlan.reasonCodes, blobIds: privatePlan.citations.map((item) => item.blobId) }, evidenceHashes: [String(privatePlan.manifestHash)], explorerLinks: [] });
405
+ const buyerIdentity = (await buyer.execute("doctor", {})).data;
406
+ const scalar = () => BigInt(`0x${randomBytes(16).toString("hex")}`).toString();
407
+ const sessionId = workflow.shieldedSession || `confidential-${log.runId}`;
408
+ const halves = (content) => { const digest = createHash("sha256").update(content).digest("hex"); return [BigInt(`0x${digest.slice(0, 32)}`).toString(), BigInt(`0x${digest.slice(32)}`).toString()]; };
409
+ const [transcriptRootLo, transcriptRootHi] = halves(JSON.stringify({ publicTransaction: publicPayment.transactionDigest, artifactSha256: publicPayment.responseSha256, confidentialTask: workflow.confidentialTask }));
410
+ const [serviceDigestLo, serviceDigestHi] = halves(JSON.stringify({ capabilityId: confidential.capabilityId, manifestHash: confidential.manifestHash, task: workflow.confidentialTask }));
411
+ const draft = { dealId: scalar(), revision: "1", transcriptRootLo, transcriptRootHi, serviceDigestLo, serviceDigestHi, settlementNonceLo: scalar(), settlementNonceHi: scalar(), paymentAmount: confidential.priceBand.minimum, blinding: scalar(), expiry: String(Date.now() + 30 * 60_000), buyerPublicKey: buyerIdentity.babyJubPublicKey, counterparty: confidential.sellerId, capabilityId: confidential.capabilityId, manifestHash: confidential.manifestHash };
412
+ await claude("confidential-seller").decide({ system: "You are the confidential seller agent. The backend validates and signs the exact cryptographic agreement. You may only proceed with the approved service offer.", task: `Accept the approved confidential capability ${confidential.capabilityId}.`, candidates: [{ action: "sign_approved_agreement", capabilityId: confidential.capabilityId, rail: "shielded" }], schema: { name: "respond_to_private_offer", description: "Accept the backend-approved confidential agreement.", properties: { action: { type: "string", enum: ["sign_approved_agreement"] } }, required: ["action"] } });
413
+ const signed = await mutate(confidentialSeller, "offer.counter", { "operation-id": `confidential-counter-${log.runId}`, session: sessionId, agreement: Buffer.from(JSON.stringify(draft)).toString("base64url") });
414
+ await mutate(buyer, "offer.accept", { "operation-id": `confidential-accept-${log.runId}`, session: sessionId, agreement: String(signed.agreement), manifest: Buffer.from(JSON.stringify(confidential)).toString("base64url"), "plan-hash": String(privatePlan.planHash) });
415
+ const privatePayment = await mutate(buyer, "pay.shielded", { "operation-id": privateOperation, session: sessionId, "plan-hash": String(privatePlan.planHash) });
416
+ log.append({ actor: "buyer", stage: "private-settlement", status: "complete", publicDetails: { rail: "shielded", poolVersion: buyer.profile.verifierVersion, visibility: "no direct public payment reveals the deal amount or counterparty; funding, deposits, withdrawals, gas, and pool activity remain visible", transactionDigest: privatePayment.transactionDigest, tatumVerified: privatePayment.tatumVerified, prover: privatePayment.prover }, evidenceHashes: [String(privatePayment.dealCommitment ?? "")].filter(Boolean), explorerLinks: [] });
417
+ if (buyer.profile.verifierVersion === 2) {
418
+ await mutate(confidentialSeller, "wallet.recover", { "operation-id": `recover-${log.runId}` });
419
+ const now = Date.now(), window = workflow.exitWindow;
420
+ const queued = await mutate(confidentialSeller, "wallet.exit.queue", { "operation-id": `exit-${log.runId}`, commitment: String(privatePayment.paymentCommitment), amount: "1000000", "window-start": String(now + window.startOffsetMs), "window-end": String(now + window.endOffsetMs) });
421
+ log.append({ actor: "confidential-seller", stage: "delayed-exit", status: "complete", publicDetails: { state: "queued", operationId: queued.operationId, executeAt: queued.executeAt, windowEnd: queued.windowEnd, amount: "1000000", visibility: "standard exit and payout address are public when executed; sparse pool use reduces privacy" }, evidenceHashes: [], explorerLinks: [] });
422
+ }
423
+ return { runId: log.runId, events: eventPath, publicTransaction: publicPayment.transactionDigest, shieldedTransaction: privatePayment.transactionDigest };
424
+ }
425
+ finally {
426
+ buyer.close();
427
+ publicSeller.close();
428
+ confidentialSeller.close();
429
+ }
430
+ }
431
+ async function replay() {
432
+ const path = resolve(value("events", join(stateDir(), "events.jsonl"))), events = recordedReplay(readDemoEvents(path));
433
+ if (args.serve === true) {
434
+ const port = Number(value("port", "4173"));
435
+ const dashboard = await serveEventDashboard(path, port, true);
436
+ process.stderr.write(`recorded funded run: ${dashboard.url}\n`);
437
+ await new Promise((done) => { process.on("SIGINT", () => { dashboard.server.close(); done(); }); process.on("SIGTERM", () => { dashboard.server.close(); done(); }); });
438
+ return { label: "recorded funded run", events: events.length, url: dashboard.url };
439
+ }
440
+ return { label: "recorded funded run", freshTransaction: false, events };
441
+ }
442
+ try {
443
+ const data = command === "setup" ? await setup() : command === "doctor" ? await doctor() : command === "seed-policy" ? await seedPolicy() : command === "reuse-memories" ? reuseMemories() : command === "check" ? await check() : command === "live" ? await live() : command === "replay" ? await replay() : fail("COMMAND_UNKNOWN", "use setup, doctor, seed-policy, reuse-memories, live, replay, or check");
444
+ send(data);
445
+ }
446
+ catch (error) {
447
+ process.stdout.write(`${JSON.stringify(errorOutput(error))}\n`);
448
+ process.exitCode = 1;
449
+ }
@@ -0,0 +1,6 @@
1
+ export declare class SupercutsError extends Error {
2
+ readonly code: string;
3
+ readonly cause?: unknown | undefined;
4
+ constructor(code: string, message: string, cause?: unknown | undefined);
5
+ }
6
+ export declare const fail: (code: string, message: string, cause?: unknown) => never;
package/dist/errors.js ADDED
@@ -0,0 +1,13 @@
1
+ export class SupercutsError extends Error {
2
+ code;
3
+ cause;
4
+ constructor(code, message, cause) {
5
+ super(message);
6
+ this.code = code;
7
+ this.cause = cause;
8
+ this.name = "SupercutsError";
9
+ }
10
+ }
11
+ export const fail = (code, message, cause) => {
12
+ throw new SupercutsError(code, message, cause);
13
+ };
@@ -0,0 +1,27 @@
1
+ export type DemoActor = "operator" | "buyer" | "public-seller" | "confidential-seller" | "auditor" | "supercuts";
2
+ export type DemoStatus = "started" | "pending" | "allowed" | "rejected" | "complete" | "failed" | "recorded";
3
+ export interface DemoEvent {
4
+ schema: "supercuts.demo.v1";
5
+ sequence: number;
6
+ runId: string;
7
+ timestamp: string;
8
+ actor: DemoActor;
9
+ stage: string;
10
+ status: DemoStatus;
11
+ mode: "live" | "recorded-funded-run";
12
+ publicDetails: Record<string, unknown>;
13
+ evidenceHashes: string[];
14
+ explorerLinks: string[];
15
+ }
16
+ export declare function redactPublicDetails(value: unknown, key?: string): unknown;
17
+ export declare function evidenceHash(value: string | Uint8Array): string;
18
+ export declare class DemoEventLog {
19
+ #private;
20
+ readonly path: string;
21
+ readonly mode: DemoEvent["mode"];
22
+ readonly runId: string;
23
+ constructor(path: string, runId?: string, mode?: DemoEvent["mode"]);
24
+ append(input: Omit<DemoEvent, "schema" | "sequence" | "runId" | "timestamp" | "mode">): DemoEvent;
25
+ }
26
+ export declare function readDemoEvents(path: string): DemoEvent[];
27
+ export declare function recordedReplay(events: DemoEvent[]): DemoEvent[];
package/dist/events.js ADDED
@@ -0,0 +1,68 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync, appendFileSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ import { fail } from "./errors.js";
5
+ const secretKey = /(?:secret|private.?key|seed|witness|opening|approval.?token|signature|ciphertext|prompt|authorization)/i;
6
+ const secretText = /(?:suiprivkey|-----BEGIN [A-Z ]*PRIVATE KEY-----|(?:mnemonic|seed phrase|approval token)\s*[:=])/i;
7
+ export function redactPublicDetails(value, key = "root") {
8
+ if (secretKey.test(key))
9
+ return "[REDACTED]";
10
+ if (typeof value === "string")
11
+ return secretText.test(value) ? "[REDACTED]" : value;
12
+ if (Array.isArray(value))
13
+ return value.map((item) => redactPublicDetails(item, key));
14
+ if (value && typeof value === "object")
15
+ return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, redactPublicDetails(item, name)]));
16
+ return value;
17
+ }
18
+ export function evidenceHash(value) { return createHash("sha256").update(value).digest("hex"); }
19
+ export class DemoEventLog {
20
+ path;
21
+ mode;
22
+ runId;
23
+ #sequence = 0;
24
+ constructor(path, runId = randomUUID(), mode = "live") {
25
+ this.path = path;
26
+ this.mode = mode;
27
+ this.runId = runId;
28
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
29
+ if (existsSync(path)) {
30
+ if ((statSync(path).mode & 0o077) !== 0)
31
+ fail("EVENT_PERMISSIONS", "demo event stream must be owner-only");
32
+ const events = readDemoEvents(path);
33
+ this.#sequence = events.at(-1)?.sequence ?? 0;
34
+ if (events.some((event) => event.runId !== runId))
35
+ fail("EVENT_RUN_CONFLICT", "event file already belongs to another run");
36
+ }
37
+ else
38
+ writeFileSync(path, "", { mode: 0o600 });
39
+ chmodSync(path, 0o600);
40
+ }
41
+ append(input) {
42
+ const event = {
43
+ schema: "supercuts.demo.v1", sequence: ++this.#sequence, runId: this.runId, timestamp: new Date().toISOString(), mode: this.mode,
44
+ ...input, publicDetails: redactPublicDetails(input.publicDetails),
45
+ };
46
+ appendFileSync(this.path, `${JSON.stringify(event)}\n`, { encoding: "utf8", mode: 0o600 });
47
+ return event;
48
+ }
49
+ }
50
+ export function readDemoEvents(path) {
51
+ if (!existsSync(path))
52
+ fail("EVENT_STREAM_NOT_FOUND", `event stream ${path} does not exist`);
53
+ return readFileSync(path, "utf8").split("\n").filter(Boolean).map((line, index) => {
54
+ let event;
55
+ try {
56
+ event = JSON.parse(line);
57
+ }
58
+ catch (error) {
59
+ return fail("EVENT_STREAM_INVALID", `event line ${index + 1} is invalid JSON`, error);
60
+ }
61
+ if (event.schema !== "supercuts.demo.v1" || event.sequence !== index + 1 || !event.runId || !event.actor || !event.stage || !event.status || !event.publicDetails || !Array.isArray(event.evidenceHashes) || !Array.isArray(event.explorerLinks))
62
+ fail("EVENT_STREAM_INVALID", `event line ${index + 1} has an invalid shape or sequence`);
63
+ return event;
64
+ });
65
+ }
66
+ export function recordedReplay(events) {
67
+ return events.map((event) => ({ ...event, mode: "recorded-funded-run", status: event.status === "started" || event.status === "pending" ? "recorded" : event.status }));
68
+ }