@garydevenay/emporion 0.0.2 → 0.0.3

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 (45) hide show
  1. package/README.md +213 -5
  2. package/dist/src/cli.js +1195 -182
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/context-store.d.ts +22 -0
  5. package/dist/src/context-store.js +133 -0
  6. package/dist/src/context-store.js.map +1 -0
  7. package/dist/src/daemon.d.ts +2 -0
  8. package/dist/src/daemon.js.map +1 -1
  9. package/dist/src/errors.d.ts +8 -0
  10. package/dist/src/errors.js +8 -0
  11. package/dist/src/errors.js.map +1 -1
  12. package/dist/src/experience/deals-store.d.ts +37 -0
  13. package/dist/src/experience/deals-store.js +96 -0
  14. package/dist/src/experience/deals-store.js.map +1 -0
  15. package/dist/src/index.d.ts +5 -0
  16. package/dist/src/index.js +4 -0
  17. package/dist/src/index.js.map +1 -1
  18. package/dist/src/wallet/config-store.d.ts +16 -0
  19. package/dist/src/wallet/config-store.js +180 -0
  20. package/dist/src/wallet/config-store.js.map +1 -0
  21. package/dist/src/wallet/index.d.ts +3 -0
  22. package/dist/src/wallet/index.js +4 -0
  23. package/dist/src/wallet/index.js.map +1 -0
  24. package/dist/src/wallet/ledger.d.ts +50 -0
  25. package/dist/src/wallet/ledger.js +340 -0
  26. package/dist/src/wallet/ledger.js.map +1 -0
  27. package/dist/src/wallet/nostr-nwc-adapter.d.ts +40 -0
  28. package/dist/src/wallet/nostr-nwc-adapter.js +506 -0
  29. package/dist/src/wallet/nostr-nwc-adapter.js.map +1 -0
  30. package/dist/src/wallet/nwc-adapter.d.ts +20 -0
  31. package/dist/src/wallet/nwc-adapter.js +233 -0
  32. package/dist/src/wallet/nwc-adapter.js.map +1 -0
  33. package/dist/src/wallet/service.d.ts +42 -0
  34. package/dist/src/wallet/service.js +390 -0
  35. package/dist/src/wallet/service.js.map +1 -0
  36. package/dist/src/wallet/types.d.ts +140 -0
  37. package/dist/src/wallet/types.js +2 -0
  38. package/dist/src/wallet/types.js.map +1 -0
  39. package/dist/test/experience.test.d.ts +1 -0
  40. package/dist/test/experience.test.js +232 -0
  41. package/dist/test/experience.test.js.map +1 -0
  42. package/dist/test/wallet.test.d.ts +1 -0
  43. package/dist/test/wallet.test.js +853 -0
  44. package/dist/test/wallet.test.js.map +1 -0
  45. package/package.json +2 -1
package/dist/src/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
3
  import { spawn } from "node:child_process";
4
+ import { randomUUID } from "node:crypto";
4
5
  import { once } from "node:events";
5
6
  import { closeSync } from "node:fs";
6
7
  import { readFile } from "node:fs/promises";
@@ -13,6 +14,11 @@ import { loadPersistentIdentityMaterial } from "./persistent-agent.js";
13
14
  import * as Protocol from "./protocol/index.js";
14
15
  import { sha256Hex } from "./protocol/shared.js";
15
16
  import { TransportStorage } from "./storage.js";
17
+ import { WalletService } from "./wallet/index.js";
18
+ import { ContextStore } from "./context-store.js";
19
+ import { DealsStore } from "./experience/deals-store.js";
20
+ const DEFAULT_DAEMON_PROXY_TIMEOUT_MS = 5_000;
21
+ const WALLET_DAEMON_PROXY_TIMEOUT_MS = 30_000;
16
22
  const DEFAULT_IO = {
17
23
  stdout(message) {
18
24
  process.stdout.write(message);
@@ -51,6 +57,12 @@ function parseArgs(argv) {
51
57
  function commandMatches(commandPath, ...expected) {
52
58
  return commandPath.length === expected.length && expected.every((value, index) => commandPath[index] === value);
53
59
  }
60
+ function isContextCommand(commandPath) {
61
+ return commandPath[0] === "context";
62
+ }
63
+ function isWalletCommand(commandPath) {
64
+ return commandPath[0] === "wallet";
65
+ }
54
66
  function getOptionValues(args, name) {
55
67
  return args.options.get(name) ?? [];
56
68
  }
@@ -92,6 +104,17 @@ function parseOptionalNonNegativeInteger(args, name) {
92
104
  const value = getOptionalOption(args, name);
93
105
  return value === undefined ? undefined : parseNonNegativeInteger(value, `--${name}`);
94
106
  }
107
+ function parseOptionalIsoTimestamp(args, name) {
108
+ const value = getOptionalOption(args, name);
109
+ if (value === undefined) {
110
+ return undefined;
111
+ }
112
+ const epochMs = Date.parse(value);
113
+ if (Number.isNaN(epochMs)) {
114
+ throw new Error(`--${name} must be a valid ISO-8601 timestamp`);
115
+ }
116
+ return new Date(epochMs).toISOString();
117
+ }
95
118
  function parseEnum(value, fieldName, allowed) {
96
119
  if (allowed.includes(value)) {
97
120
  return value;
@@ -193,16 +216,161 @@ function writeJson(io, value) {
193
216
  function normalizeDataDirPath(dataDir) {
194
217
  return path.resolve(dataDir);
195
218
  }
219
+ function parsedArgsFromCommand(commandPath, options) {
220
+ const map = new Map();
221
+ for (const [name, value] of Object.entries(options)) {
222
+ if (value === undefined) {
223
+ continue;
224
+ }
225
+ if (typeof value === "boolean") {
226
+ if (value) {
227
+ map.set(name, ["true"]);
228
+ }
229
+ continue;
230
+ }
231
+ if (Array.isArray(value)) {
232
+ map.set(name, value.map((entry) => `${entry}`));
233
+ continue;
234
+ }
235
+ map.set(name, [`${value}`]);
236
+ }
237
+ return {
238
+ commandPath: [...commandPath],
239
+ options: map
240
+ };
241
+ }
242
+ async function runNestedCommand(commandPath, options) {
243
+ return executeCapturedInDaemon(parsedArgsFromCommand(commandPath, options));
244
+ }
245
+ function ensureObjectIdPrefix(objectId, prefixes) {
246
+ const trimmed = objectId.trim();
247
+ if (!prefixes.some((prefix) => trimmed.startsWith(prefix))) {
248
+ throw new Error(`Unsupported object id: ${trimmed}`);
249
+ }
250
+ return trimmed;
251
+ }
252
+ function stageOrder(stage) {
253
+ switch (stage) {
254
+ case "draft":
255
+ return 0;
256
+ case "negotiating":
257
+ return 1;
258
+ case "agreed":
259
+ return 2;
260
+ case "in_progress":
261
+ return 3;
262
+ case "proof_submitted":
263
+ return 4;
264
+ case "proof_accepted":
265
+ return 5;
266
+ case "settlement_pending":
267
+ return 6;
268
+ case "settled":
269
+ return 7;
270
+ case "closed":
271
+ return 8;
272
+ }
273
+ }
274
+ function stageAtLeast(current, expected) {
275
+ return stageOrder(current) >= stageOrder(expected);
276
+ }
277
+ function toChangedObjects(record) {
278
+ const entries = [];
279
+ if (record.rootObjectKind && record.rootObjectId)
280
+ entries.push({ kind: record.rootObjectKind, id: record.rootObjectId });
281
+ if (record.proposalKind && record.proposalId)
282
+ entries.push({ kind: record.proposalKind, id: record.proposalId });
283
+ if (record.agreementId)
284
+ entries.push({ kind: "agreement", id: record.agreementId });
285
+ if (record.contractId)
286
+ entries.push({ kind: "contract", id: record.contractId });
287
+ if (record.evidenceId)
288
+ entries.push({ kind: "evidence-bundle", id: record.evidenceId });
289
+ if (record.invoiceId)
290
+ entries.push({ kind: "invoice", id: record.invoiceId });
291
+ if (record.paymentId)
292
+ entries.push({ kind: "payment", id: record.paymentId });
293
+ return entries;
294
+ }
295
+ function nextActionsForStage(stage) {
296
+ switch (stage) {
297
+ case "draft":
298
+ case "negotiating":
299
+ return ["deal.propose", "deal.accept"];
300
+ case "agreed":
301
+ return ["deal.start"];
302
+ case "in_progress":
303
+ return ["proof.submit"];
304
+ case "proof_submitted":
305
+ return ["proof.accept"];
306
+ case "proof_accepted":
307
+ return ["settlement.invoice.create", "settlement.pay"];
308
+ case "settlement_pending":
309
+ return ["settlement.pay", "settlement.status"];
310
+ case "settled":
311
+ return ["deal.status"];
312
+ case "closed":
313
+ return [];
314
+ }
315
+ }
316
+ function writeDealResponse(io, command, deal, overrides) {
317
+ writeJson(io, {
318
+ command,
319
+ dealId: deal.dealId,
320
+ stage: deal.stage,
321
+ changedObjects: toChangedObjects(deal),
322
+ nextActions: nextActionsForStage(deal.stage),
323
+ safety: {
324
+ policy: "proof-gated",
325
+ earlySettlementAllowed: overrides?.safety?.earlySettlementAllowed ?? false
326
+ }
327
+ });
328
+ }
329
+ function asRecord(value, label) {
330
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
331
+ throw new Error(`Expected ${label} to be an object`);
332
+ }
333
+ return value;
334
+ }
335
+ function readString(value, fieldName) {
336
+ if (typeof value !== "string" || value.trim().length === 0) {
337
+ throw new Error(`Expected ${fieldName} to be a non-empty string`);
338
+ }
339
+ return value;
340
+ }
341
+ function inferIntentFromRootObjectKind(kind) {
342
+ return kind === "request" ? "sell" : "buy";
343
+ }
344
+ function inferRootObjectKindFromId(objectId) {
345
+ if (objectId.startsWith("emporion:request:")) {
346
+ return "request";
347
+ }
348
+ if (objectId.startsWith("emporion:listing:")) {
349
+ return "listing";
350
+ }
351
+ throw new Error(`Unsupported target object id for proposal: ${objectId}`);
352
+ }
353
+ function inferProposalKindFromId(proposalId) {
354
+ if (proposalId.startsWith("emporion:offer:")) {
355
+ return "offer";
356
+ }
357
+ if (proposalId.startsWith("emporion:bid:")) {
358
+ return "bid";
359
+ }
360
+ throw new Error(`Unsupported proposal id: ${proposalId}`);
361
+ }
196
362
  async function openCliContext(dataDir) {
197
363
  const identityMaterial = await loadPersistentIdentityMaterial(dataDir);
198
364
  const repository = await Protocol.ProtocolRepository.create(dataDir);
199
365
  const transportStorage = await TransportStorage.create(dataDir, identityMaterial.storagePrimaryKey, createLogger("error"));
366
+ const walletService = await WalletService.create({ dataDir });
200
367
  await transportStorage.initializeDefaults();
201
368
  return {
202
369
  dataDir,
203
370
  identityMaterial,
204
371
  repository,
205
372
  transportStorage,
373
+ walletService,
206
374
  signer: {
207
375
  did: identityMaterial.agentIdentity.did,
208
376
  publicKey: identityMaterial.transportKeyPair.publicKey,
@@ -211,6 +379,7 @@ async function openCliContext(dataDir) {
211
379
  };
212
380
  }
213
381
  async function closeCliContext(context) {
382
+ await context.walletService.close();
214
383
  await context.transportStorage.close();
215
384
  await context.repository.close();
216
385
  }
@@ -224,7 +393,7 @@ async function withCliContext(dataDir, fn) {
224
393
  }
225
394
  const context = await openCliContext(dataDir);
226
395
  try {
227
- return await fn(context);
396
+ return await CLI_CONTEXT_STORAGE.run(context, async () => fn(context));
228
397
  }
229
398
  finally {
230
399
  await closeCliContext(context);
@@ -1770,11 +1939,640 @@ async function handleMarketList(args, io) {
1770
1939
  });
1771
1940
  });
1772
1941
  }
1942
+ async function handleContextAdd(args, io) {
1943
+ const name = requireOption(args, "name");
1944
+ const dataDir = requireOption(args, "data-dir");
1945
+ const makeActive = hasFlag(args, "make-active");
1946
+ const store = new ContextStore();
1947
+ const snapshot = await store.add(name, dataDir, makeActive);
1948
+ writeJson(io, {
1949
+ command: "context.add",
1950
+ activeContext: snapshot.activeContext,
1951
+ contexts: snapshot.contexts
1952
+ });
1953
+ }
1954
+ async function handleContextUse(args, io) {
1955
+ const name = requireOption(args, "name");
1956
+ const store = new ContextStore();
1957
+ const snapshot = await store.use(name);
1958
+ writeJson(io, {
1959
+ command: "context.use",
1960
+ activeContext: snapshot.activeContext,
1961
+ contexts: snapshot.contexts
1962
+ });
1963
+ }
1964
+ async function handleContextList(io) {
1965
+ const store = new ContextStore();
1966
+ const snapshot = await store.snapshot();
1967
+ writeJson(io, {
1968
+ command: "context.list",
1969
+ activeContext: snapshot.activeContext,
1970
+ contexts: snapshot.contexts
1971
+ });
1972
+ }
1973
+ async function handleContextShow(io) {
1974
+ const store = new ContextStore();
1975
+ const snapshot = await store.snapshot();
1976
+ const active = snapshot.activeContext
1977
+ ? snapshot.contexts.find((entry) => entry.name === snapshot.activeContext)
1978
+ : undefined;
1979
+ writeJson(io, {
1980
+ command: "context.show",
1981
+ activeContext: snapshot.activeContext,
1982
+ active: active ?? null
1983
+ });
1984
+ }
1985
+ async function handleContextRemove(args, io) {
1986
+ const name = requireOption(args, "name");
1987
+ const store = new ContextStore();
1988
+ const snapshot = await store.remove(name);
1989
+ writeJson(io, {
1990
+ command: "context.remove",
1991
+ activeContext: snapshot.activeContext,
1992
+ contexts: snapshot.contexts
1993
+ });
1994
+ }
1995
+ function applyWalletRuntimeKeyFromArgs(context, args) {
1996
+ const walletKey = getOptionalOption(args, "wallet-key");
1997
+ if (walletKey && walletKey.trim().length > 0) {
1998
+ context.walletService.setRuntimeKey(walletKey);
1999
+ }
2000
+ }
2001
+ async function handleWalletConnectNwc(args, io) {
2002
+ const dataDir = requireOption(args, "data-dir");
2003
+ const connectionUri = requireOption(args, "connection-uri");
2004
+ const publishEndpoint = hasFlag(args, "publish-payment-endpoint");
2005
+ await withCliContext(dataDir, async (context) => {
2006
+ applyWalletRuntimeKeyFromArgs(context, args);
2007
+ const connected = await context.walletService.connect(connectionUri);
2008
+ let paymentEndpointEventId;
2009
+ if (publishEndpoint) {
2010
+ await ensureAgentProfileExists(context);
2011
+ const capabilities = getCsvOptionValues(args, "payment-capability");
2012
+ const accountId = getOptionalOption(args, "payment-account-id");
2013
+ const endpoint = {
2014
+ id: getOptionalOption(args, "payment-endpoint-id") ?? "wallet-nwc",
2015
+ network: "bitcoin",
2016
+ custodial: true,
2017
+ capabilities: capabilities.length > 0 ? capabilities : ["invoice.create", "invoice.pay", "auto-settle"],
2018
+ ...(accountId ? { accountId } : {}),
2019
+ nodeUri: connected.endpoint
2020
+ };
2021
+ const result = await appendEnvelope(context, {
2022
+ objectKind: "agent-profile",
2023
+ objectId: context.identityMaterial.agentIdentity.did,
2024
+ eventKind: "agent-profile.payment-endpoint-added",
2025
+ subjectId: context.identityMaterial.agentIdentity.did,
2026
+ payload: Protocol.paymentEndpointToJson(endpoint)
2027
+ });
2028
+ paymentEndpointEventId = result.envelope.eventId;
2029
+ }
2030
+ writeJson(io, {
2031
+ command: "wallet.connect.nwc",
2032
+ wallet: connected.status,
2033
+ endpoint: connected.endpoint,
2034
+ ...(paymentEndpointEventId ? { paymentEndpointEventId } : {})
2035
+ });
2036
+ });
2037
+ }
2038
+ async function handleWalletDisconnect(args, io) {
2039
+ const dataDir = requireOption(args, "data-dir");
2040
+ await withCliContext(dataDir, async (context) => {
2041
+ applyWalletRuntimeKeyFromArgs(context, args);
2042
+ const wallet = await context.walletService.disconnect();
2043
+ writeJson(io, {
2044
+ command: "wallet.disconnect",
2045
+ wallet
2046
+ });
2047
+ });
2048
+ }
2049
+ async function handleWalletStatus(args, io) {
2050
+ const dataDir = requireOption(args, "data-dir");
2051
+ await withCliContext(dataDir, async (context) => {
2052
+ applyWalletRuntimeKeyFromArgs(context, args);
2053
+ writeJson(io, {
2054
+ command: "wallet.status",
2055
+ wallet: await context.walletService.status()
2056
+ });
2057
+ });
2058
+ }
2059
+ async function handleWalletUnlock(args, io) {
2060
+ if (process.env.EMPORION_DAEMON !== "1") {
2061
+ throw new Error("wallet unlock requires a running daemon for this data-dir");
2062
+ }
2063
+ const dataDir = requireOption(args, "data-dir");
2064
+ const walletKey = requireOption(args, "wallet-key");
2065
+ if (walletKey.trim().length === 0) {
2066
+ throw new Error("--wallet-key must not be blank");
2067
+ }
2068
+ await withCliContext(dataDir, async (context) => {
2069
+ context.walletService.setRuntimeKey(walletKey);
2070
+ writeJson(io, {
2071
+ command: "wallet.unlock",
2072
+ wallet: await context.walletService.status()
2073
+ });
2074
+ });
2075
+ }
2076
+ async function handleWalletLock(args, io) {
2077
+ if (process.env.EMPORION_DAEMON !== "1") {
2078
+ throw new Error("wallet lock requires a running daemon for this data-dir");
2079
+ }
2080
+ const dataDir = requireOption(args, "data-dir");
2081
+ await withCliContext(dataDir, async (context) => {
2082
+ context.walletService.setRuntimeKey(null);
2083
+ writeJson(io, {
2084
+ command: "wallet.lock",
2085
+ wallet: await context.walletService.status()
2086
+ });
2087
+ });
2088
+ }
2089
+ async function handleWalletInvoiceCreate(args, io) {
2090
+ const dataDir = requireOption(args, "data-dir");
2091
+ const amountSats = parsePositiveInteger(requireOption(args, "amount-sats"), "--amount-sats");
2092
+ const memo = getOptionalOption(args, "memo");
2093
+ const expiresAt = parseOptionalIsoTimestamp(args, "expires-at");
2094
+ await withCliContext(dataDir, async (context) => {
2095
+ applyWalletRuntimeKeyFromArgs(context, args);
2096
+ const created = await context.walletService.createInvoice({
2097
+ amountSats,
2098
+ ...(memo ? { memo } : {}),
2099
+ ...(expiresAt ? { expiresAt } : {})
2100
+ });
2101
+ writeJson(io, {
2102
+ command: "wallet.invoice.create",
2103
+ invoice: created.invoice,
2104
+ bolt11: created.bolt11
2105
+ });
2106
+ });
2107
+ }
2108
+ async function handleWalletPayBolt11(args, io) {
2109
+ const dataDir = requireOption(args, "data-dir");
2110
+ const invoice = requireOption(args, "invoice");
2111
+ const sourceRef = getOptionalOption(args, "source-ref");
2112
+ await withCliContext(dataDir, async (context) => {
2113
+ applyWalletRuntimeKeyFromArgs(context, args);
2114
+ const paid = await context.walletService.payInvoice({
2115
+ invoice,
2116
+ ...(sourceRef ? { sourceRef } : {})
2117
+ });
2118
+ writeJson(io, {
2119
+ command: "wallet.pay.bolt11",
2120
+ payment: paid.payment
2121
+ });
2122
+ });
2123
+ }
2124
+ async function handleWalletLedgerList(args, io) {
2125
+ const dataDir = requireOption(args, "data-dir");
2126
+ const kindValue = getOptionalOption(args, "kind");
2127
+ const status = getOptionalOption(args, "status");
2128
+ const kind = kindValue ? parseEnum(kindValue, "--kind", ["invoice", "payment"]) : undefined;
2129
+ await withCliContext(dataDir, async (context) => {
2130
+ applyWalletRuntimeKeyFromArgs(context, args);
2131
+ const filters = {
2132
+ ...(kind ? { kind } : {}),
2133
+ ...(status ? { status } : {})
2134
+ };
2135
+ writeJson(io, {
2136
+ command: "wallet.ledger.list",
2137
+ kind: kind ?? null,
2138
+ status: status ?? null,
2139
+ entries: await context.walletService.listLedger(filters)
2140
+ });
2141
+ });
2142
+ }
2143
+ async function handleWalletKeyRotate(args, io) {
2144
+ const dataDir = requireOption(args, "data-dir");
2145
+ const newKey = requireOption(args, "new-key");
2146
+ await withCliContext(dataDir, async (context) => {
2147
+ applyWalletRuntimeKeyFromArgs(context, args);
2148
+ await context.walletService.rotateKey(newKey);
2149
+ writeJson(io, {
2150
+ command: "wallet.key.rotate",
2151
+ rotated: true
2152
+ });
2153
+ });
2154
+ }
2155
+ async function handleDealOpen(args, io) {
2156
+ const dataDir = requireOption(args, "data-dir");
2157
+ const intent = parseEnum(requireOption(args, "intent"), "--intent", ["buy", "sell"]);
2158
+ const marketplaceId = requireOption(args, "marketplace");
2159
+ const title = requireOption(args, "title");
2160
+ const amountSats = parsePositiveInteger(requireOption(args, "amount-sats"), "--amount-sats");
2161
+ const dealId = getOptionalOption(args, "deal-id") ?? `deal:${randomUUID()}`;
2162
+ await withCliContext(dataDir, async () => {
2163
+ const deals = await DealsStore.create(dataDir);
2164
+ if (deals.get(dealId)) {
2165
+ throw new Error(`Deal already exists: ${dealId}`);
2166
+ }
2167
+ const created = await runNestedCommand(["market", intent === "buy" ? "request" : "listing", "publish"], {
2168
+ "data-dir": dataDir,
2169
+ marketplace: marketplaceId,
2170
+ title,
2171
+ "amount-sats": `${amountSats}`
2172
+ });
2173
+ const createdRecord = asRecord(created, `${intent}.publish result`);
2174
+ const objectId = readString(createdRecord.objectId, "objectId");
2175
+ const nowIso = now();
2176
+ const deal = {
2177
+ dealId,
2178
+ stage: "negotiating",
2179
+ intent,
2180
+ marketplaceId,
2181
+ title,
2182
+ amountSats,
2183
+ rootObjectKind: intent === "buy" ? "request" : "listing",
2184
+ rootObjectId: objectId,
2185
+ createdAt: nowIso,
2186
+ updatedAt: nowIso
2187
+ };
2188
+ await deals.save(deal);
2189
+ writeDealResponse(io, "deal.open", deal);
2190
+ });
2191
+ }
2192
+ async function handleDealPropose(args, io) {
2193
+ const dataDir = requireOption(args, "data-dir");
2194
+ const targetId = requireOption(args, "target-id");
2195
+ const amountSats = parsePositiveInteger(requireOption(args, "amount-sats"), "--amount-sats");
2196
+ const proposalId = getOptionalOption(args, "proposal-id");
2197
+ const proposerDid = getOptionalOption(args, "proposer-did");
2198
+ await withCliContext(dataDir, async (context) => {
2199
+ const rootObjectKind = inferRootObjectKindFromId(targetId);
2200
+ const deals = await DealsStore.create(dataDir);
2201
+ const targetState = rootObjectKind === "request"
2202
+ ? await readRequiredState(context.repository, "request", targetId)
2203
+ : await readRequiredState(context.repository, "listing", targetId);
2204
+ const proposalKind = rootObjectKind === "request" ? "offer" : "bid";
2205
+ const proposed = await runNestedCommand(["market", proposalKind, "submit"], {
2206
+ "data-dir": dataDir,
2207
+ marketplace: targetState.marketplaceId,
2208
+ "target-object-id": targetId,
2209
+ "amount-sats": `${amountSats}`,
2210
+ ...(proposerDid ? { "proposer-did": proposerDid } : {}),
2211
+ ...(proposalId ? { id: proposalId } : {})
2212
+ });
2213
+ const proposedRecord = asRecord(proposed, `${proposalKind}.submit result`);
2214
+ const resolvedProposalId = readString(proposedRecord.objectId, "objectId");
2215
+ const existing = deals.findByRootObjectId(targetId);
2216
+ const nowIso = now();
2217
+ const deal = existing
2218
+ ? await deals.update(existing.dealId, (current) => ({
2219
+ ...current,
2220
+ stage: "negotiating",
2221
+ proposalKind,
2222
+ proposalId: resolvedProposalId,
2223
+ amountSats,
2224
+ updatedAt: nowIso
2225
+ }))
2226
+ : await deals.save({
2227
+ dealId: `deal:${randomUUID()}`,
2228
+ stage: "negotiating",
2229
+ intent: inferIntentFromRootObjectKind(rootObjectKind),
2230
+ marketplaceId: targetState.marketplaceId,
2231
+ title: "proposal-only-deal",
2232
+ amountSats,
2233
+ rootObjectKind,
2234
+ rootObjectId: targetId,
2235
+ proposalKind,
2236
+ proposalId: resolvedProposalId,
2237
+ createdAt: nowIso,
2238
+ updatedAt: nowIso
2239
+ });
2240
+ writeDealResponse(io, "deal.propose", deal);
2241
+ });
2242
+ }
2243
+ async function handleDealAccept(args, io) {
2244
+ const dataDir = requireOption(args, "data-dir");
2245
+ const proposalId = requireOption(args, "proposal-id");
2246
+ const proposalKind = inferProposalKindFromId(proposalId);
2247
+ await withCliContext(dataDir, async () => {
2248
+ const deals = await DealsStore.create(dataDir);
2249
+ await runNestedCommand(["market", proposalKind, "accept"], {
2250
+ "data-dir": dataDir,
2251
+ id: proposalId
2252
+ });
2253
+ const existing = deals.findByProposalId(proposalId);
2254
+ const nowIso = now();
2255
+ const deal = existing
2256
+ ? await deals.update(existing.dealId, (current) => ({
2257
+ ...current,
2258
+ stage: "agreed",
2259
+ proposalKind,
2260
+ proposalId,
2261
+ updatedAt: nowIso
2262
+ }))
2263
+ : await deals.save({
2264
+ dealId: `deal:${randomUUID()}`,
2265
+ stage: "agreed",
2266
+ proposalKind,
2267
+ proposalId,
2268
+ createdAt: nowIso,
2269
+ updatedAt: nowIso
2270
+ });
2271
+ writeDealResponse(io, "deal.accept", deal);
2272
+ });
2273
+ }
2274
+ async function handleDealStart(args, io) {
2275
+ const dataDir = requireOption(args, "data-dir");
2276
+ const proposalId = requireOption(args, "proposal-id");
2277
+ const scope = requireOption(args, "scope");
2278
+ const milestoneId = requireOption(args, "milestone-id");
2279
+ const milestoneTitle = requireOption(args, "milestone-title");
2280
+ const deadline = parseOptionalIsoTimestamp(args, "deadline");
2281
+ if (!deadline) {
2282
+ throw new Error("--deadline is required");
2283
+ }
2284
+ const deliverableKind = parseEnum(requireOption(args, "deliverable-kind"), "--deliverable-kind", ["artifact", "generic", "oracle-claim"]);
2285
+ const requiredArtifactKinds = getCsvOptionValues(args, "required-artifact-kind");
2286
+ if (requiredArtifactKinds.length === 0) {
2287
+ throw new Error("--required-artifact-kind must include at least one value");
2288
+ }
2289
+ const proposalKind = inferProposalKindFromId(proposalId);
2290
+ await withCliContext(dataDir, async (context) => {
2291
+ const deals = await DealsStore.create(dataDir);
2292
+ const proposalState = proposalKind === "offer"
2293
+ ? await readRequiredState(context.repository, "offer", proposalId)
2294
+ : await readRequiredState(context.repository, "bid", proposalId);
2295
+ if (proposalState.status !== "accepted") {
2296
+ throw new Error(`Proposal must be accepted before deal start: ${proposalId}`);
2297
+ }
2298
+ const agreement = await runNestedCommand(["market", "agreement", "create"], {
2299
+ "data-dir": dataDir,
2300
+ "source-kind": proposalKind,
2301
+ "source-id": proposalId,
2302
+ deliverable: [milestoneTitle],
2303
+ counterparty: [context.identityMaterial.agentIdentity.did, proposalState.proposerDid],
2304
+ "amount-sats": `${proposalState.paymentTerms.amountSats}`
2305
+ });
2306
+ const agreementRecord = asRecord(agreement, "agreement.create result");
2307
+ const agreementId = readString(agreementRecord.objectId, "objectId");
2308
+ const milestonesJson = JSON.stringify([{
2309
+ milestoneId,
2310
+ title: milestoneTitle,
2311
+ deliverableSchema: {
2312
+ kind: deliverableKind,
2313
+ requiredArtifactKinds
2314
+ },
2315
+ proofPolicy: {
2316
+ allowedModes: ["artifact-verifiable"],
2317
+ verifierRefs: [],
2318
+ minArtifacts: 1,
2319
+ requireCounterpartyAcceptance: true
2320
+ },
2321
+ settlementAdapters: []
2322
+ }]);
2323
+ const contract = await runNestedCommand(["contract", "create"], {
2324
+ "data-dir": dataDir,
2325
+ "origin-kind": "agreement",
2326
+ "origin-id": agreementId,
2327
+ party: [context.identityMaterial.agentIdentity.did, proposalState.proposerDid],
2328
+ scope,
2329
+ "milestones-json": milestonesJson,
2330
+ "deliverable-schema-json": JSON.stringify({ kind: deliverableKind, requiredArtifactKinds }),
2331
+ "proof-policy-json": JSON.stringify({
2332
+ allowedModes: ["artifact-verifiable"],
2333
+ verifierRefs: [],
2334
+ minArtifacts: 1,
2335
+ requireCounterpartyAcceptance: true
2336
+ }),
2337
+ "resolution-policy-json": JSON.stringify({ mode: "mutual", deterministicVerifierIds: [] }),
2338
+ "settlement-policy-json": JSON.stringify({ adapters: [], releaseCondition: "contract-completed" }),
2339
+ "deadline-policy-json": JSON.stringify({ milestoneDeadlines: { [milestoneId]: deadline } })
2340
+ });
2341
+ const contractRecord = asRecord(contract, "contract.create result");
2342
+ const contractId = readString(contractRecord.objectId, "objectId");
2343
+ await runNestedCommand(["contract", "open-milestone"], {
2344
+ "data-dir": dataDir,
2345
+ id: contractId,
2346
+ "milestone-id": milestoneId
2347
+ });
2348
+ const existing = deals.findByProposalId(proposalId);
2349
+ const nowIso = now();
2350
+ const deal = existing
2351
+ ? await deals.update(existing.dealId, (current) => ({
2352
+ ...current,
2353
+ stage: "in_progress",
2354
+ proposalKind,
2355
+ proposalId,
2356
+ agreementId,
2357
+ contractId,
2358
+ milestoneId,
2359
+ updatedAt: nowIso
2360
+ }))
2361
+ : await deals.save({
2362
+ dealId: `deal:${randomUUID()}`,
2363
+ stage: "in_progress",
2364
+ proposalKind,
2365
+ proposalId,
2366
+ agreementId,
2367
+ contractId,
2368
+ milestoneId,
2369
+ createdAt: nowIso,
2370
+ updatedAt: nowIso
2371
+ });
2372
+ writeDealResponse(io, "deal.start", deal);
2373
+ });
2374
+ }
2375
+ async function handleDealStatus(args, io) {
2376
+ const dataDir = requireOption(args, "data-dir");
2377
+ const dealId = requireOption(args, "deal-id");
2378
+ const deals = await DealsStore.create(dataDir);
2379
+ const deal = deals.get(dealId);
2380
+ if (!deal) {
2381
+ throw new Error(`Unknown deal: ${dealId}`);
2382
+ }
2383
+ writeDealResponse(io, "deal.status", deal);
2384
+ }
2385
+ async function handleProofSubmit(args, io) {
2386
+ const dataDir = requireOption(args, "data-dir");
2387
+ const dealId = requireOption(args, "deal-id");
2388
+ const milestoneId = requireOption(args, "milestone-id");
2389
+ const preset = parseEnum(requireOption(args, "proof-preset"), "--proof-preset", ["simple-artifact"]);
2390
+ if (preset !== "simple-artifact") {
2391
+ throw new Error(`Unsupported --proof-preset: ${preset}`);
2392
+ }
2393
+ const artifactId = requireOption(args, "artifact-id");
2394
+ const artifactHash = requireOption(args, "artifact-hash");
2395
+ const repro = getOptionalOption(args, "repro");
2396
+ await withCliContext(dataDir, async () => {
2397
+ const deals = await DealsStore.create(dataDir);
2398
+ const existing = deals.get(dealId);
2399
+ if (!existing) {
2400
+ throw new Error(`Unknown deal: ${dealId}`);
2401
+ }
2402
+ if (!existing.contractId) {
2403
+ throw new Error("Deal has no contract yet; run deal start first");
2404
+ }
2405
+ if (!stageAtLeast(existing.stage, "in_progress")) {
2406
+ throw new Error("Deal is not ready for proof submission");
2407
+ }
2408
+ const evidence = await runNestedCommand(["evidence", "record"], {
2409
+ "data-dir": dataDir,
2410
+ "contract-id": existing.contractId,
2411
+ "milestone-id": milestoneId,
2412
+ "proof-mode": "artifact-verifiable",
2413
+ "artifact-json": JSON.stringify([{ artifactId, hash: artifactHash }]),
2414
+ "verifier-json": JSON.stringify([{ verifierId: "simple-artifact-check", verifierKind: "human-review" }]),
2415
+ ...(repro ? { repro } : {})
2416
+ });
2417
+ const evidenceRecord = asRecord(evidence, "evidence.record result");
2418
+ const evidenceId = readString(evidenceRecord.objectId, "objectId");
2419
+ await runNestedCommand(["contract", "submit-milestone"], {
2420
+ "data-dir": dataDir,
2421
+ id: existing.contractId,
2422
+ "milestone-id": milestoneId,
2423
+ "evidence-bundle-id": evidenceId
2424
+ });
2425
+ const nowIso = now();
2426
+ const deal = await deals.update(dealId, (current) => ({
2427
+ ...current,
2428
+ stage: "proof_submitted",
2429
+ milestoneId,
2430
+ evidenceId,
2431
+ updatedAt: nowIso
2432
+ }));
2433
+ writeDealResponse(io, "proof.submit", deal);
2434
+ });
2435
+ }
2436
+ async function handleProofAccept(args, io) {
2437
+ const dataDir = requireOption(args, "data-dir");
2438
+ const dealId = requireOption(args, "deal-id");
2439
+ const milestoneId = requireOption(args, "milestone-id");
2440
+ await withCliContext(dataDir, async () => {
2441
+ const deals = await DealsStore.create(dataDir);
2442
+ const existing = deals.get(dealId);
2443
+ if (!existing) {
2444
+ throw new Error(`Unknown deal: ${dealId}`);
2445
+ }
2446
+ if (!existing.contractId) {
2447
+ throw new Error("Deal has no contract yet");
2448
+ }
2449
+ if (!stageAtLeast(existing.stage, "proof_submitted")) {
2450
+ throw new Error("Deal proof must be submitted before acceptance");
2451
+ }
2452
+ await runNestedCommand(["contract", "accept-milestone"], {
2453
+ "data-dir": dataDir,
2454
+ id: existing.contractId,
2455
+ "milestone-id": milestoneId
2456
+ });
2457
+ const nowIso = now();
2458
+ const deal = await deals.update(dealId, (current) => ({
2459
+ ...current,
2460
+ stage: "proof_accepted",
2461
+ milestoneId,
2462
+ updatedAt: nowIso
2463
+ }));
2464
+ writeDealResponse(io, "proof.accept", deal);
2465
+ });
2466
+ }
2467
+ async function handleSettlementInvoiceCreate(args, io) {
2468
+ const dataDir = requireOption(args, "data-dir");
2469
+ const dealId = requireOption(args, "deal-id");
2470
+ const amountSats = parsePositiveInteger(requireOption(args, "amount-sats"), "--amount-sats");
2471
+ const memo = getOptionalOption(args, "memo");
2472
+ const expiresAt = parseOptionalIsoTimestamp(args, "expires-at");
2473
+ const allowEarlySettlement = hasFlag(args, "allow-early-settlement");
2474
+ await withCliContext(dataDir, async (context) => {
2475
+ const deals = await DealsStore.create(dataDir);
2476
+ const existing = deals.get(dealId);
2477
+ if (!existing) {
2478
+ throw new Error(`Unknown deal: ${dealId}`);
2479
+ }
2480
+ if (!allowEarlySettlement && !stageAtLeast(existing.stage, "proof_accepted")) {
2481
+ throw new Error("Settlement invoice creation is proof-gated. Use --allow-early-settlement to override.");
2482
+ }
2483
+ applyWalletRuntimeKeyFromArgs(context, args);
2484
+ const created = await context.walletService.createInvoice({
2485
+ amountSats,
2486
+ ...(memo ? { memo } : {}),
2487
+ ...(expiresAt ? { expiresAt } : {})
2488
+ });
2489
+ const nowIso = now();
2490
+ const deal = await deals.update(dealId, (current) => ({
2491
+ ...current,
2492
+ stage: "settlement_pending",
2493
+ invoiceId: created.invoice.id,
2494
+ invoiceBolt11: created.bolt11,
2495
+ updatedAt: nowIso
2496
+ }));
2497
+ writeDealResponse(io, "settlement.invoice.create", deal, {
2498
+ safety: { earlySettlementAllowed: allowEarlySettlement }
2499
+ });
2500
+ });
2501
+ }
2502
+ async function handleSettlementPay(args, io) {
2503
+ const dataDir = requireOption(args, "data-dir");
2504
+ const dealId = requireOption(args, "deal-id");
2505
+ const invoice = requireOption(args, "invoice");
2506
+ const allowEarlySettlement = hasFlag(args, "allow-early-settlement");
2507
+ await withCliContext(dataDir, async (context) => {
2508
+ const deals = await DealsStore.create(dataDir);
2509
+ const existing = deals.get(dealId);
2510
+ if (!existing) {
2511
+ throw new Error(`Unknown deal: ${dealId}`);
2512
+ }
2513
+ if (!allowEarlySettlement && !stageAtLeast(existing.stage, "proof_accepted")) {
2514
+ throw new Error("Settlement payment is proof-gated. Use --allow-early-settlement to override.");
2515
+ }
2516
+ applyWalletRuntimeKeyFromArgs(context, args);
2517
+ const sourceRef = existing.contractId
2518
+ ? `${existing.contractId}:${existing.milestoneId ?? "milestone"}`
2519
+ : dealId;
2520
+ const paid = await context.walletService.payInvoice({
2521
+ invoice,
2522
+ sourceRef
2523
+ });
2524
+ const nowIso = now();
2525
+ const deal = await deals.update(dealId, (current) => ({
2526
+ ...current,
2527
+ stage: "settled",
2528
+ paymentId: paid.payment.id,
2529
+ updatedAt: nowIso
2530
+ }));
2531
+ writeDealResponse(io, "settlement.pay", deal, {
2532
+ safety: { earlySettlementAllowed: allowEarlySettlement }
2533
+ });
2534
+ });
2535
+ }
2536
+ async function handleSettlementStatus(args, io) {
2537
+ const dataDir = requireOption(args, "data-dir");
2538
+ const dealId = requireOption(args, "deal-id");
2539
+ const deals = await DealsStore.create(dataDir);
2540
+ const deal = deals.get(dealId);
2541
+ if (!deal) {
2542
+ throw new Error(`Unknown deal: ${dealId}`);
2543
+ }
2544
+ writeDealResponse(io, "settlement.status", deal);
2545
+ }
1773
2546
  function usage() {
1774
2547
  return [
1775
2548
  "Usage:",
2549
+ " Global data-dir resolution: --data-dir <path> > --context <name> > active context",
2550
+ " emporion context add --name <context> --data-dir <path> [--make-active]",
2551
+ " emporion context use --name <context>",
2552
+ " emporion context list",
2553
+ " emporion context show",
2554
+ " emporion context remove --name <context>",
1776
2555
  " emporion agent init --data-dir <path> [--display-name <name>] [--bio <text>]",
1777
2556
  " emporion agent show --data-dir <path>",
2557
+ " emporion wallet connect nwc --data-dir <path> --connection-uri <uri> [--publish-payment-endpoint]",
2558
+ " emporion wallet disconnect --data-dir <path>",
2559
+ " emporion wallet status --data-dir <path>",
2560
+ " emporion wallet unlock [--data-dir <path>|--context <name>] --wallet-key <key-material>",
2561
+ " emporion wallet lock [--data-dir <path>|--context <name>]",
2562
+ " emporion wallet invoice create --data-dir <path> --amount-sats <n> [--memo <text>] [--expires-at <iso>]",
2563
+ " emporion wallet pay bolt11 --data-dir <path> --invoice <bolt11>",
2564
+ " emporion wallet ledger list --data-dir <path> [--kind <invoice|payment>] [--status <status>]",
2565
+ " emporion wallet key rotate --data-dir <path> --new-key <key-material>",
2566
+ " emporion deal open [--data-dir <path>|--context <name>] --intent <buy|sell> --marketplace <id> --title <text> --amount-sats <n> [--deal-id <id>]",
2567
+ " emporion deal propose [--data-dir <path>|--context <name>] --target-id <object-id> --amount-sats <n> [--proposal-id <id>] [--proposer-did <did>]",
2568
+ " emporion deal accept [--data-dir <path>|--context <name>] --proposal-id <offer-or-bid-id>",
2569
+ " emporion deal start [--data-dir <path>|--context <name>] --proposal-id <offer-or-bid-id> --scope <text> --milestone-id <id> --milestone-title <text> --deadline <iso> --deliverable-kind <artifact|generic|oracle-claim> --required-artifact-kind <kind>[,<kind>...]",
2570
+ " emporion deal status [--data-dir <path>|--context <name>] --deal-id <id>",
2571
+ " emporion proof submit [--data-dir <path>|--context <name>] --deal-id <id> --milestone-id <id> --proof-preset <simple-artifact> --artifact-id <id> --artifact-hash <hex> [--repro <text>]",
2572
+ " emporion proof accept [--data-dir <path>|--context <name>] --deal-id <id> --milestone-id <id>",
2573
+ " emporion settlement invoice create [--data-dir <path>|--context <name>] --deal-id <id> --amount-sats <n> [--memo <text>] [--expires-at <iso>]",
2574
+ " emporion settlement pay [--data-dir <path>|--context <name>] --deal-id <id> --invoice <bolt11>",
2575
+ " emporion settlement status [--data-dir <path>|--context <name>] --deal-id <id>",
1778
2576
  " emporion agent payment-endpoint add --data-dir <path> --id <id> --capability <cap>[,<cap>...]",
1779
2577
  " emporion agent wallet-attestation add --data-dir <path> --attestation-id <id> --wallet-account-id <id> --balance-sats <n> --expires-at <iso>",
1780
2578
  " emporion agent feedback add --data-dir <path> --credential-id <id> --issuer-did <did> --contract-id <id> --agreement-id <id> --score <n> --max-score <n>",
@@ -1805,6 +2603,53 @@ function usage() {
1805
2603
  function getDataDirFromArgs(args) {
1806
2604
  return getOptionalOption(args, "data-dir");
1807
2605
  }
2606
+ async function withResolvedDataDir(args) {
2607
+ if (isContextCommand(args.commandPath)) {
2608
+ return args;
2609
+ }
2610
+ if (getOptionalOption(args, "data-dir")) {
2611
+ return args;
2612
+ }
2613
+ const requestedContext = getOptionalOption(args, "context");
2614
+ const store = new ContextStore();
2615
+ const resolved = await store.resolveDataDir(requestedContext);
2616
+ if (requestedContext && !resolved) {
2617
+ throw new Error(`Unknown context: ${requestedContext}`);
2618
+ }
2619
+ if (!resolved) {
2620
+ return args;
2621
+ }
2622
+ const options = new Map(args.options);
2623
+ options.set("data-dir", [resolved]);
2624
+ return {
2625
+ commandPath: [...args.commandPath],
2626
+ options
2627
+ };
2628
+ }
2629
+ function withDaemonWalletKeyForwarding(args) {
2630
+ if (!isWalletCommand(args.commandPath)) {
2631
+ return args;
2632
+ }
2633
+ if (getOptionalOption(args, "wallet-key")) {
2634
+ return args;
2635
+ }
2636
+ const walletKey = process.env.EMPORION_WALLET_KEY;
2637
+ if (!walletKey || walletKey.trim().length === 0) {
2638
+ return args;
2639
+ }
2640
+ const options = new Map(args.options);
2641
+ options.set("wallet-key", [walletKey]);
2642
+ return {
2643
+ commandPath: [...args.commandPath],
2644
+ options
2645
+ };
2646
+ }
2647
+ function getDaemonProxyTimeoutMs(commandPath) {
2648
+ if (isWalletCommand(commandPath) || commandPath[0] === "settlement") {
2649
+ return WALLET_DAEMON_PROXY_TIMEOUT_MS;
2650
+ }
2651
+ return DEFAULT_DAEMON_PROXY_TIMEOUT_MS;
2652
+ }
1808
2653
  function createCaptureIo() {
1809
2654
  const stdout = [];
1810
2655
  const stderr = [];
@@ -1944,7 +2789,7 @@ async function proxyParsedArgsToDaemon(args, io) {
1944
2789
  if (!dataDir) {
1945
2790
  return 1;
1946
2791
  }
1947
- const response = await sendDaemonCommand(dataDir, daemonRequestFromParsed(args.commandPath, daemonRequestOptionsToRecord(args.options)));
2792
+ const response = await sendDaemonCommand(dataDir, daemonRequestFromParsed(args.commandPath, daemonRequestOptionsToRecord(args.options)), getDaemonProxyTimeoutMs(args.commandPath));
1948
2793
  if (!response.ok) {
1949
2794
  throw new Error(response.error ?? "Daemon command failed");
1950
2795
  }
@@ -2088,7 +2933,7 @@ async function handleDaemonLogs(args, io) {
2088
2933
  process.off("SIGTERM", stop);
2089
2934
  }
2090
2935
  }
2091
- async function buildDaemonSharedContext(dataDir, transport) {
2936
+ async function buildDaemonSharedContext(dataDir, transport, walletService) {
2092
2937
  const identityMaterial = transport.getIdentityMaterial();
2093
2938
  const repository = await Protocol.ProtocolRepository.create(dataDir);
2094
2939
  return {
@@ -2096,6 +2941,7 @@ async function buildDaemonSharedContext(dataDir, transport) {
2096
2941
  identityMaterial,
2097
2942
  repository,
2098
2943
  transportStorage: transport.getStorage(),
2944
+ walletService,
2099
2945
  signer: {
2100
2946
  did: identityMaterial.agentIdentity.did,
2101
2947
  publicKey: identityMaterial.transportKeyPair.publicKey,
@@ -2103,7 +2949,7 @@ async function buildDaemonSharedContext(dataDir, transport) {
2103
2949
  }
2104
2950
  };
2105
2951
  }
2106
- function buildDaemonStatus(dataDir, startedAt, transport) {
2952
+ function buildDaemonStatus(dataDir, startedAt, transport, walletStatus) {
2107
2953
  return {
2108
2954
  dataDir: normalizeDataDirPath(dataDir),
2109
2955
  pid: process.pid,
@@ -2113,9 +2959,56 @@ function buildDaemonStatus(dataDir, startedAt, transport) {
2113
2959
  logPath: getDaemonLogPath(dataDir),
2114
2960
  topics: transport.getJoinedTopics(),
2115
2961
  connectedPeers: [...transport.getPeerSessions().values()],
2962
+ wallet: walletStatus,
2116
2963
  healthy: true
2117
2964
  };
2118
2965
  }
2966
+ function collectAutoSettleCandidates(snapshot) {
2967
+ const candidates = [];
2968
+ for (const offer of snapshot.offers.values()) {
2969
+ if (offer.status !== "accepted") {
2970
+ continue;
2971
+ }
2972
+ for (const lightningRef of offer.lightningRefs) {
2973
+ candidates.push({
2974
+ triggerObjectKind: "offer",
2975
+ triggerObjectId: offer.objectId,
2976
+ eventId: offer.latestEventId,
2977
+ lightningRef,
2978
+ amountSats: offer.paymentTerms.amountSats
2979
+ });
2980
+ }
2981
+ }
2982
+ for (const bid of snapshot.bids.values()) {
2983
+ if (bid.status !== "accepted") {
2984
+ continue;
2985
+ }
2986
+ for (const lightningRef of bid.lightningRefs) {
2987
+ candidates.push({
2988
+ triggerObjectKind: "bid",
2989
+ triggerObjectId: bid.objectId,
2990
+ eventId: bid.latestEventId,
2991
+ lightningRef,
2992
+ amountSats: bid.paymentTerms.amountSats
2993
+ });
2994
+ }
2995
+ }
2996
+ for (const agreement of snapshot.agreements.values()) {
2997
+ if (agreement.status !== "active") {
2998
+ continue;
2999
+ }
3000
+ for (const lightningRef of agreement.lightningRefs) {
3001
+ candidates.push({
3002
+ triggerObjectKind: "agreement",
3003
+ triggerObjectId: agreement.objectId,
3004
+ eventId: agreement.latestEventId,
3005
+ lightningRef,
3006
+ amountSats: agreement.paymentTerms.amountSats
3007
+ });
3008
+ }
3009
+ }
3010
+ return candidates;
3011
+ }
2119
3012
  async function runProtocolDiscoveryWatcher(transport, seenControlLengths, io) {
2120
3013
  for (const session of transport.getPeerSessions().values()) {
2121
3014
  const remoteFeed = transport.getRemoteFeed(session.remoteControlFeedKey);
@@ -2144,56 +3037,118 @@ async function waitForProcessSignal() {
2144
3037
  }
2145
3038
  async function handleDaemonRun(args, io) {
2146
3039
  const dataDir = requireOption(args, "data-dir");
2147
- const transport = await AgentTransport.create(buildTransportConfigFromArgs(args));
2148
3040
  const startup = getDaemonStartupOptions(args);
3041
+ const walletService = await WalletService.create({
3042
+ dataDir,
3043
+ logger: createLogger("warn")
3044
+ });
3045
+ walletService.setRuntimeKey(process.env.EMPORION_WALLET_KEY ?? null);
3046
+ let transport;
2149
3047
  let sharedContext;
2150
3048
  let daemon;
2151
3049
  let discoveryInterval;
3050
+ let walletPollInterval;
3051
+ let autoSettleInterval;
3052
+ let walletStatus = await walletService.daemonStatus();
3053
+ let walletPollRunning = false;
3054
+ let autoSettleRunning = false;
2152
3055
  const seenControlLengths = new Map();
2153
3056
  const startedAt = new Date().toISOString();
2154
3057
  try {
3058
+ transport = await AgentTransport.create(buildTransportConfigFromArgs(args));
2155
3059
  await transport.start();
2156
- sharedContext = await buildDaemonSharedContext(dataDir, transport);
2157
- const topics = buildTopicsFromArgs(args, transport.identity.did);
3060
+ const activeTransport = transport;
3061
+ sharedContext = await buildDaemonSharedContext(dataDir, activeTransport, walletService);
3062
+ const topics = buildTopicsFromArgs(args, activeTransport.identity.did);
2158
3063
  startup.topics.push(...topics);
2159
3064
  for (const topic of startup.topics) {
2160
- await transport.joinTopic(topic);
3065
+ await activeTransport.joinTopic(topic);
2161
3066
  }
2162
3067
  for (const did of startup.connectDids) {
2163
- await transport.connectToDid(did);
3068
+ await activeTransport.connectToDid(did);
2164
3069
  }
2165
3070
  for (const publicKey of startup.connectNoiseKeys) {
2166
- await transport.connectToNoiseKey(publicKey);
3071
+ await activeTransport.connectToNoiseKey(publicKey);
2167
3072
  }
2168
3073
  if (startup.watchProtocol) {
2169
3074
  discoveryInterval = setInterval(() => {
2170
- void runProtocolDiscoveryWatcher(transport, seenControlLengths, io).catch((error) => {
3075
+ void runProtocolDiscoveryWatcher(activeTransport, seenControlLengths, io).catch((error) => {
2171
3076
  io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
2172
3077
  });
2173
3078
  }, 2_000);
2174
3079
  }
3080
+ walletPollInterval = setInterval(() => {
3081
+ if (walletPollRunning) {
3082
+ return;
3083
+ }
3084
+ walletPollRunning = true;
3085
+ void (async () => {
3086
+ try {
3087
+ await walletService.pollUpdates();
3088
+ walletStatus = await walletService.daemonStatus();
3089
+ }
3090
+ catch (error) {
3091
+ io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
3092
+ }
3093
+ finally {
3094
+ walletPollRunning = false;
3095
+ }
3096
+ })();
3097
+ }, 3_000);
3098
+ autoSettleInterval = setInterval(() => {
3099
+ if (autoSettleRunning || !sharedContext) {
3100
+ return;
3101
+ }
3102
+ autoSettleRunning = true;
3103
+ void (async () => {
3104
+ try {
3105
+ const candidates = collectAutoSettleCandidates(sharedContext.repository.getSnapshot());
3106
+ for (const candidate of candidates) {
3107
+ await walletService.attemptAutoSettle(candidate);
3108
+ }
3109
+ walletStatus = await walletService.daemonStatus();
3110
+ }
3111
+ catch (error) {
3112
+ io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
3113
+ }
3114
+ finally {
3115
+ autoSettleRunning = false;
3116
+ }
3117
+ })();
3118
+ }, 2_000);
2175
3119
  daemon = new AgentDaemon({
2176
3120
  dataDir,
2177
- statusProvider: () => buildDaemonStatus(dataDir, startedAt, transport),
3121
+ statusProvider: () => buildDaemonStatus(dataDir, startedAt, activeTransport, walletStatus),
2178
3122
  commandHandler: async (request) => {
2179
3123
  if (!sharedContext) {
2180
3124
  throw new Error("Daemon context is not available");
2181
3125
  }
2182
- return CLI_CONTEXT_STORAGE.run(sharedContext, async () => executeCapturedInDaemon({
3126
+ const result = await CLI_CONTEXT_STORAGE.run(sharedContext, async () => executeCapturedInDaemon({
2183
3127
  commandPath: request.commandPath,
2184
3128
  options: daemonOptionsRecordToMap(request.options)
2185
3129
  }));
3130
+ walletStatus = await walletService.daemonStatus();
3131
+ return result;
2186
3132
  },
2187
3133
  onShutdown: async () => {
2188
3134
  if (discoveryInterval) {
2189
3135
  clearInterval(discoveryInterval);
2190
3136
  discoveryInterval = undefined;
2191
3137
  }
3138
+ if (walletPollInterval) {
3139
+ clearInterval(walletPollInterval);
3140
+ walletPollInterval = undefined;
3141
+ }
3142
+ if (autoSettleInterval) {
3143
+ clearInterval(autoSettleInterval);
3144
+ autoSettleInterval = undefined;
3145
+ }
2192
3146
  if (sharedContext) {
2193
3147
  await sharedContext.repository.close();
2194
3148
  sharedContext = undefined;
2195
3149
  }
2196
- await transport.stop();
3150
+ await walletService.close();
3151
+ await activeTransport.stop();
2197
3152
  }
2198
3153
  });
2199
3154
  await daemon.start();
@@ -2208,10 +3163,19 @@ async function handleDaemonRun(args, io) {
2208
3163
  if (discoveryInterval) {
2209
3164
  clearInterval(discoveryInterval);
2210
3165
  }
3166
+ if (walletPollInterval) {
3167
+ clearInterval(walletPollInterval);
3168
+ }
3169
+ if (autoSettleInterval) {
3170
+ clearInterval(autoSettleInterval);
3171
+ }
2211
3172
  if (sharedContext) {
2212
3173
  await sharedContext.repository.close();
2213
3174
  }
2214
- await transport.stop();
3175
+ await walletService.close();
3176
+ if (transport) {
3177
+ await transport.stop();
3178
+ }
2215
3179
  }
2216
3180
  }
2217
3181
  }
@@ -2220,180 +3184,229 @@ async function executeParsedArgs(args, io, options) {
2220
3184
  io.stdout(`${usage()}\n`);
2221
3185
  return 0;
2222
3186
  }
2223
- if (commandMatches(args.commandPath, "daemon", "start"))
2224
- return await handleDaemonStart(args, io).then(() => 0);
2225
- if (commandMatches(args.commandPath, "daemon", "status"))
2226
- return await handleDaemonStatus(args, io).then(() => 0);
2227
- if (commandMatches(args.commandPath, "daemon", "stop"))
2228
- return await handleDaemonStop(args, io).then(() => 0);
2229
- if (commandMatches(args.commandPath, "daemon", "logs"))
2230
- return await handleDaemonLogs(args, io).then(() => 0);
2231
- if (commandMatches(args.commandPath, "daemon", "run"))
2232
- return await handleDaemonRun(args, io).then(() => 0);
3187
+ const resolvedArgs = await withResolvedDataDir(args);
3188
+ if (commandMatches(resolvedArgs.commandPath, "daemon", "start"))
3189
+ return await handleDaemonStart(resolvedArgs, io).then(() => 0);
3190
+ if (commandMatches(resolvedArgs.commandPath, "daemon", "status"))
3191
+ return await handleDaemonStatus(resolvedArgs, io).then(() => 0);
3192
+ if (commandMatches(resolvedArgs.commandPath, "daemon", "stop"))
3193
+ return await handleDaemonStop(resolvedArgs, io).then(() => 0);
3194
+ if (commandMatches(resolvedArgs.commandPath, "daemon", "logs"))
3195
+ return await handleDaemonLogs(resolvedArgs, io).then(() => 0);
3196
+ if (commandMatches(resolvedArgs.commandPath, "daemon", "run"))
3197
+ return await handleDaemonRun(resolvedArgs, io).then(() => 0);
2233
3198
  if (options.allowDaemonProxy) {
2234
- const dataDir = getDataDirFromArgs(args);
3199
+ const dataDir = getDataDirFromArgs(resolvedArgs);
2235
3200
  if (dataDir) {
2236
3201
  const activeDaemon = await probeDaemonStatus(dataDir, 1_000);
2237
3202
  if (activeDaemon) {
2238
- return proxyParsedArgsToDaemon(args, io);
3203
+ return proxyParsedArgsToDaemon(withDaemonWalletKeyForwarding(resolvedArgs), io);
2239
3204
  }
2240
3205
  }
2241
3206
  }
2242
- if (commandMatches(args.commandPath, "agent", "init"))
2243
- return await handleAgentInit(args, io).then(() => 0);
2244
- if (commandMatches(args.commandPath, "agent", "show"))
2245
- return await handleAgentShow(args, io).then(() => 0);
2246
- if (commandMatches(args.commandPath, "agent", "payment-endpoint", "add"))
2247
- return await handleAgentPaymentEndpointAdd(args, io).then(() => 0);
2248
- if (commandMatches(args.commandPath, "agent", "payment-endpoint", "remove"))
2249
- return await handleAgentPaymentEndpointRemove(args, io).then(() => 0);
2250
- if (commandMatches(args.commandPath, "agent", "wallet-attestation", "add"))
2251
- return await handleAgentWalletAttestationAdd(args, io).then(() => 0);
2252
- if (commandMatches(args.commandPath, "agent", "wallet-attestation", "remove"))
2253
- return await handleAgentWalletAttestationRemove(args, io).then(() => 0);
2254
- if (commandMatches(args.commandPath, "agent", "feedback", "add"))
2255
- return await handleAgentFeedbackAdd(args, io).then(() => 0);
2256
- if (commandMatches(args.commandPath, "agent", "feedback", "remove"))
2257
- return await handleAgentFeedbackRemove(args, io).then(() => 0);
2258
- if (commandMatches(args.commandPath, "company", "create"))
2259
- return await handleCompanyCreate(args, io).then(() => 0);
2260
- if (commandMatches(args.commandPath, "company", "show"))
2261
- return await handleCompanyShow(args, io).then(() => 0);
2262
- if (commandMatches(args.commandPath, "company", "update"))
2263
- return await handleCompanyUpdate(args, io).then(() => 0);
2264
- if (commandMatches(args.commandPath, "company", "grant-role"))
2265
- return await handleCompanyRoleChange(args, io, "grant").then(() => 0);
2266
- if (commandMatches(args.commandPath, "company", "revoke-role"))
2267
- return await handleCompanyRoleChange(args, io, "revoke").then(() => 0);
2268
- if (commandMatches(args.commandPath, "company", "join-market"))
2269
- return await handleCompanyMarketMembership(args, io, "join").then(() => 0);
2270
- if (commandMatches(args.commandPath, "company", "leave-market"))
2271
- return await handleCompanyMarketMembership(args, io, "leave").then(() => 0);
2272
- if (commandMatches(args.commandPath, "company", "treasury-attest"))
2273
- return await handleCompanyTreasuryAttest(args, io).then(() => 0);
2274
- if (commandMatches(args.commandPath, "company", "treasury-reserve"))
2275
- return await handleCompanyTreasuryReserve(args, io).then(() => 0);
2276
- if (commandMatches(args.commandPath, "company", "treasury-release"))
2277
- return await handleCompanyTreasuryRelease(args, io).then(() => 0);
2278
- if (commandMatches(args.commandPath, "market", "product", "create"))
2279
- return await handleMarketProductCreate(args, io).then(() => 0);
2280
- if (commandMatches(args.commandPath, "market", "product", "update"))
2281
- return await handleMarketProductUpdate(args, io).then(() => 0);
2282
- if (commandMatches(args.commandPath, "market", "product", "publish"))
2283
- return await handleMarketProductStateChange(args, io, "product.published").then(() => 0);
2284
- if (commandMatches(args.commandPath, "market", "product", "unpublish"))
2285
- return await handleMarketProductStateChange(args, io, "product.unpublished").then(() => 0);
2286
- if (commandMatches(args.commandPath, "market", "product", "retire"))
2287
- return await handleMarketProductStateChange(args, io, "product.retired").then(() => 0);
2288
- if (commandMatches(args.commandPath, "market", "listing", "publish"))
2289
- return await handleMarketListingPublish(args, io).then(() => 0);
2290
- if (commandMatches(args.commandPath, "market", "listing", "revise"))
2291
- return await handleMarketListingRevise(args, io).then(() => 0);
2292
- if (commandMatches(args.commandPath, "market", "listing", "withdraw"))
2293
- return await handleSimpleMarketStateChange(args, io, "listing", "listing.withdrawn").then(() => 0);
2294
- if (commandMatches(args.commandPath, "market", "listing", "expire"))
2295
- return await handleSimpleMarketStateChange(args, io, "listing", "listing.expired").then(() => 0);
2296
- if (commandMatches(args.commandPath, "market", "request", "publish"))
2297
- return await handleMarketRequestPublish(args, io).then(() => 0);
2298
- if (commandMatches(args.commandPath, "market", "request", "revise"))
2299
- return await handleMarketRequestRevise(args, io).then(() => 0);
2300
- if (commandMatches(args.commandPath, "market", "request", "close"))
2301
- return await handleSimpleMarketStateChange(args, io, "request", "request.closed").then(() => 0);
2302
- if (commandMatches(args.commandPath, "market", "request", "expire"))
2303
- return await handleSimpleMarketStateChange(args, io, "request", "request.expired").then(() => 0);
2304
- if (commandMatches(args.commandPath, "market", "offer", "submit"))
2305
- return await handleMarketOfferSubmit(args, io).then(() => 0);
2306
- if (commandMatches(args.commandPath, "market", "offer", "counter"))
2307
- return await handleMarketOfferCounter(args, io).then(() => 0);
2308
- if (commandMatches(args.commandPath, "market", "offer", "accept"))
2309
- return await handleSimpleMarketStateChange(args, io, "offer", "offer.accepted").then(() => 0);
2310
- if (commandMatches(args.commandPath, "market", "offer", "reject"))
2311
- return await handleSimpleMarketStateChange(args, io, "offer", "offer.rejected").then(() => 0);
2312
- if (commandMatches(args.commandPath, "market", "offer", "cancel"))
2313
- return await handleSimpleMarketStateChange(args, io, "offer", "offer.canceled").then(() => 0);
2314
- if (commandMatches(args.commandPath, "market", "offer", "expire"))
2315
- return await handleSimpleMarketStateChange(args, io, "offer", "offer.expired").then(() => 0);
2316
- if (commandMatches(args.commandPath, "market", "bid", "submit"))
2317
- return await handleMarketBidSubmit(args, io).then(() => 0);
2318
- if (commandMatches(args.commandPath, "market", "bid", "counter"))
2319
- return await handleMarketBidCounter(args, io).then(() => 0);
2320
- if (commandMatches(args.commandPath, "market", "bid", "accept"))
2321
- return await handleSimpleMarketStateChange(args, io, "bid", "bid.accepted").then(() => 0);
2322
- if (commandMatches(args.commandPath, "market", "bid", "reject"))
2323
- return await handleSimpleMarketStateChange(args, io, "bid", "bid.rejected").then(() => 0);
2324
- if (commandMatches(args.commandPath, "market", "bid", "cancel"))
2325
- return await handleSimpleMarketStateChange(args, io, "bid", "bid.canceled").then(() => 0);
2326
- if (commandMatches(args.commandPath, "market", "bid", "expire"))
2327
- return await handleSimpleMarketStateChange(args, io, "bid", "bid.expired").then(() => 0);
2328
- if (commandMatches(args.commandPath, "market", "agreement", "create"))
2329
- return await handleMarketAgreementCreate(args, io).then(() => 0);
2330
- if (commandMatches(args.commandPath, "market", "agreement", "complete"))
2331
- return await handleSimpleMarketStateChange(args, io, "agreement", "agreement.completed").then(() => 0);
2332
- if (commandMatches(args.commandPath, "market", "agreement", "cancel"))
2333
- return await handleSimpleMarketStateChange(args, io, "agreement", "agreement.canceled").then(() => 0);
2334
- if (commandMatches(args.commandPath, "market", "agreement", "dispute"))
2335
- return await handleSimpleMarketStateChange(args, io, "agreement", "agreement.disputed").then(() => 0);
2336
- if (commandMatches(args.commandPath, "market", "list"))
2337
- return await handleMarketList(args, io).then(() => 0);
2338
- if (commandMatches(args.commandPath, "contract", "create"))
2339
- return await handleContractCreate(args, io).then(() => 0);
2340
- if (commandMatches(args.commandPath, "contract", "open-milestone"))
2341
- return await handleContractMilestoneAction(args, io, "contract.milestone-opened").then(() => 0);
2342
- if (commandMatches(args.commandPath, "contract", "submit-milestone"))
2343
- return await handleContractMilestoneAction(args, io, "contract.milestone-submitted").then(() => 0);
2344
- if (commandMatches(args.commandPath, "contract", "accept-milestone"))
2345
- return await handleContractMilestoneAction(args, io, "contract.milestone-accepted").then(() => 0);
2346
- if (commandMatches(args.commandPath, "contract", "reject-milestone"))
2347
- return await handleContractMilestoneAction(args, io, "contract.milestone-rejected").then(() => 0);
2348
- if (commandMatches(args.commandPath, "contract", "pause"))
2349
- return await handleContractStateChange(args, io, "contract.paused").then(() => 0);
2350
- if (commandMatches(args.commandPath, "contract", "resume"))
2351
- return await handleContractStateChange(args, io, "contract.resumed").then(() => 0);
2352
- if (commandMatches(args.commandPath, "contract", "complete"))
2353
- return await handleContractStateChange(args, io, "contract.completed").then(() => 0);
2354
- if (commandMatches(args.commandPath, "contract", "cancel"))
2355
- return await handleContractStateChange(args, io, "contract.canceled").then(() => 0);
2356
- if (commandMatches(args.commandPath, "contract", "dispute"))
2357
- return await handleContractStateChange(args, io, "contract.disputed").then(() => 0);
2358
- if (commandMatches(args.commandPath, "contract", "entries"))
2359
- return await handleContractEntries(args, io).then(() => 0);
2360
- if (commandMatches(args.commandPath, "evidence", "record"))
2361
- return await handleEvidenceRecord(args, io).then(() => 0);
2362
- if (commandMatches(args.commandPath, "oracle", "attest"))
2363
- return await handleOracleAttest(args, io).then(() => 0);
2364
- if (commandMatches(args.commandPath, "dispute", "open"))
2365
- return await handleDisputeOpen(args, io).then(() => 0);
2366
- if (commandMatches(args.commandPath, "dispute", "add-evidence"))
2367
- return await handleDisputeAddEvidence(args, io).then(() => 0);
2368
- if (commandMatches(args.commandPath, "dispute", "request-oracle"))
2369
- return await handleDisputeRequestOracle(args, io).then(() => 0);
2370
- if (commandMatches(args.commandPath, "dispute", "rule"))
2371
- return await handleDisputeRule(args, io).then(() => 0);
2372
- if (commandMatches(args.commandPath, "dispute", "close"))
2373
- return await handleDisputeClose(args, io).then(() => 0);
2374
- if (commandMatches(args.commandPath, "space", "create"))
2375
- return await handleSpaceCreate(args, io).then(() => 0);
2376
- if (commandMatches(args.commandPath, "space", "add-member"))
2377
- return await handleSpaceMembershipAction(args, io, "space-membership.member-added").then(() => 0);
2378
- if (commandMatches(args.commandPath, "space", "remove-member"))
2379
- return await handleSpaceMembershipAction(args, io, "space-membership.member-removed").then(() => 0);
2380
- if (commandMatches(args.commandPath, "space", "mute-member"))
2381
- return await handleSpaceMembershipAction(args, io, "space-membership.member-muted").then(() => 0);
2382
- if (commandMatches(args.commandPath, "space", "set-role"))
2383
- return await handleSpaceMembershipAction(args, io, "space-membership.member-role-updated").then(() => 0);
2384
- if (commandMatches(args.commandPath, "space", "entries"))
2385
- return await handleSpaceEntries(args, io).then(() => 0);
2386
- if (commandMatches(args.commandPath, "message", "send"))
2387
- return await handleMessageSend(args, io).then(() => 0);
2388
- if (commandMatches(args.commandPath, "message", "edit"))
2389
- return await handleMessageEdit(args, io).then(() => 0);
2390
- if (commandMatches(args.commandPath, "message", "delete"))
2391
- return await handleMessageDelete(args, io).then(() => 0);
2392
- if (commandMatches(args.commandPath, "message", "react"))
2393
- return await handleMessageReact(args, io).then(() => 0);
2394
- if (commandMatches(args.commandPath, "object", "show"))
2395
- return await handleObjectShow(args, io).then(() => 0);
2396
- throw new Error(`Unknown command: ${args.commandPath.join(" ")}`);
3207
+ if (commandMatches(resolvedArgs.commandPath, "context", "add"))
3208
+ return await handleContextAdd(resolvedArgs, io).then(() => 0);
3209
+ if (commandMatches(resolvedArgs.commandPath, "context", "use"))
3210
+ return await handleContextUse(resolvedArgs, io).then(() => 0);
3211
+ if (commandMatches(resolvedArgs.commandPath, "context", "list"))
3212
+ return await handleContextList(io).then(() => 0);
3213
+ if (commandMatches(resolvedArgs.commandPath, "context", "show"))
3214
+ return await handleContextShow(io).then(() => 0);
3215
+ if (commandMatches(resolvedArgs.commandPath, "context", "remove"))
3216
+ return await handleContextRemove(resolvedArgs, io).then(() => 0);
3217
+ if (commandMatches(resolvedArgs.commandPath, "agent", "init"))
3218
+ return await handleAgentInit(resolvedArgs, io).then(() => 0);
3219
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "connect", "nwc"))
3220
+ return await handleWalletConnectNwc(resolvedArgs, io).then(() => 0);
3221
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "disconnect"))
3222
+ return await handleWalletDisconnect(resolvedArgs, io).then(() => 0);
3223
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "status"))
3224
+ return await handleWalletStatus(resolvedArgs, io).then(() => 0);
3225
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "unlock"))
3226
+ return await handleWalletUnlock(resolvedArgs, io).then(() => 0);
3227
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "lock"))
3228
+ return await handleWalletLock(resolvedArgs, io).then(() => 0);
3229
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "invoice", "create"))
3230
+ return await handleWalletInvoiceCreate(resolvedArgs, io).then(() => 0);
3231
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "pay", "bolt11"))
3232
+ return await handleWalletPayBolt11(resolvedArgs, io).then(() => 0);
3233
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "ledger", "list"))
3234
+ return await handleWalletLedgerList(resolvedArgs, io).then(() => 0);
3235
+ if (commandMatches(resolvedArgs.commandPath, "wallet", "key", "rotate"))
3236
+ return await handleWalletKeyRotate(resolvedArgs, io).then(() => 0);
3237
+ if (commandMatches(resolvedArgs.commandPath, "deal", "open"))
3238
+ return await handleDealOpen(resolvedArgs, io).then(() => 0);
3239
+ if (commandMatches(resolvedArgs.commandPath, "deal", "propose"))
3240
+ return await handleDealPropose(resolvedArgs, io).then(() => 0);
3241
+ if (commandMatches(resolvedArgs.commandPath, "deal", "accept"))
3242
+ return await handleDealAccept(resolvedArgs, io).then(() => 0);
3243
+ if (commandMatches(resolvedArgs.commandPath, "deal", "start"))
3244
+ return await handleDealStart(resolvedArgs, io).then(() => 0);
3245
+ if (commandMatches(resolvedArgs.commandPath, "deal", "status"))
3246
+ return await handleDealStatus(resolvedArgs, io).then(() => 0);
3247
+ if (commandMatches(resolvedArgs.commandPath, "proof", "submit"))
3248
+ return await handleProofSubmit(resolvedArgs, io).then(() => 0);
3249
+ if (commandMatches(resolvedArgs.commandPath, "proof", "accept"))
3250
+ return await handleProofAccept(resolvedArgs, io).then(() => 0);
3251
+ if (commandMatches(resolvedArgs.commandPath, "settlement", "invoice", "create"))
3252
+ return await handleSettlementInvoiceCreate(resolvedArgs, io).then(() => 0);
3253
+ if (commandMatches(resolvedArgs.commandPath, "settlement", "pay"))
3254
+ return await handleSettlementPay(resolvedArgs, io).then(() => 0);
3255
+ if (commandMatches(resolvedArgs.commandPath, "settlement", "status"))
3256
+ return await handleSettlementStatus(resolvedArgs, io).then(() => 0);
3257
+ if (commandMatches(resolvedArgs.commandPath, "agent", "show"))
3258
+ return await handleAgentShow(resolvedArgs, io).then(() => 0);
3259
+ if (commandMatches(resolvedArgs.commandPath, "agent", "payment-endpoint", "add"))
3260
+ return await handleAgentPaymentEndpointAdd(resolvedArgs, io).then(() => 0);
3261
+ if (commandMatches(resolvedArgs.commandPath, "agent", "payment-endpoint", "remove"))
3262
+ return await handleAgentPaymentEndpointRemove(resolvedArgs, io).then(() => 0);
3263
+ if (commandMatches(resolvedArgs.commandPath, "agent", "wallet-attestation", "add"))
3264
+ return await handleAgentWalletAttestationAdd(resolvedArgs, io).then(() => 0);
3265
+ if (commandMatches(resolvedArgs.commandPath, "agent", "wallet-attestation", "remove"))
3266
+ return await handleAgentWalletAttestationRemove(resolvedArgs, io).then(() => 0);
3267
+ if (commandMatches(resolvedArgs.commandPath, "agent", "feedback", "add"))
3268
+ return await handleAgentFeedbackAdd(resolvedArgs, io).then(() => 0);
3269
+ if (commandMatches(resolvedArgs.commandPath, "agent", "feedback", "remove"))
3270
+ return await handleAgentFeedbackRemove(resolvedArgs, io).then(() => 0);
3271
+ if (commandMatches(resolvedArgs.commandPath, "company", "create"))
3272
+ return await handleCompanyCreate(resolvedArgs, io).then(() => 0);
3273
+ if (commandMatches(resolvedArgs.commandPath, "company", "show"))
3274
+ return await handleCompanyShow(resolvedArgs, io).then(() => 0);
3275
+ if (commandMatches(resolvedArgs.commandPath, "company", "update"))
3276
+ return await handleCompanyUpdate(resolvedArgs, io).then(() => 0);
3277
+ if (commandMatches(resolvedArgs.commandPath, "company", "grant-role"))
3278
+ return await handleCompanyRoleChange(resolvedArgs, io, "grant").then(() => 0);
3279
+ if (commandMatches(resolvedArgs.commandPath, "company", "revoke-role"))
3280
+ return await handleCompanyRoleChange(resolvedArgs, io, "revoke").then(() => 0);
3281
+ if (commandMatches(resolvedArgs.commandPath, "company", "join-market"))
3282
+ return await handleCompanyMarketMembership(resolvedArgs, io, "join").then(() => 0);
3283
+ if (commandMatches(resolvedArgs.commandPath, "company", "leave-market"))
3284
+ return await handleCompanyMarketMembership(resolvedArgs, io, "leave").then(() => 0);
3285
+ if (commandMatches(resolvedArgs.commandPath, "company", "treasury-attest"))
3286
+ return await handleCompanyTreasuryAttest(resolvedArgs, io).then(() => 0);
3287
+ if (commandMatches(resolvedArgs.commandPath, "company", "treasury-reserve"))
3288
+ return await handleCompanyTreasuryReserve(resolvedArgs, io).then(() => 0);
3289
+ if (commandMatches(resolvedArgs.commandPath, "company", "treasury-release"))
3290
+ return await handleCompanyTreasuryRelease(resolvedArgs, io).then(() => 0);
3291
+ if (commandMatches(resolvedArgs.commandPath, "market", "product", "create"))
3292
+ return await handleMarketProductCreate(resolvedArgs, io).then(() => 0);
3293
+ if (commandMatches(resolvedArgs.commandPath, "market", "product", "update"))
3294
+ return await handleMarketProductUpdate(resolvedArgs, io).then(() => 0);
3295
+ if (commandMatches(resolvedArgs.commandPath, "market", "product", "publish"))
3296
+ return await handleMarketProductStateChange(resolvedArgs, io, "product.published").then(() => 0);
3297
+ if (commandMatches(resolvedArgs.commandPath, "market", "product", "unpublish"))
3298
+ return await handleMarketProductStateChange(resolvedArgs, io, "product.unpublished").then(() => 0);
3299
+ if (commandMatches(resolvedArgs.commandPath, "market", "product", "retire"))
3300
+ return await handleMarketProductStateChange(resolvedArgs, io, "product.retired").then(() => 0);
3301
+ if (commandMatches(resolvedArgs.commandPath, "market", "listing", "publish"))
3302
+ return await handleMarketListingPublish(resolvedArgs, io).then(() => 0);
3303
+ if (commandMatches(resolvedArgs.commandPath, "market", "listing", "revise"))
3304
+ return await handleMarketListingRevise(resolvedArgs, io).then(() => 0);
3305
+ if (commandMatches(resolvedArgs.commandPath, "market", "listing", "withdraw"))
3306
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "listing", "listing.withdrawn").then(() => 0);
3307
+ if (commandMatches(resolvedArgs.commandPath, "market", "listing", "expire"))
3308
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "listing", "listing.expired").then(() => 0);
3309
+ if (commandMatches(resolvedArgs.commandPath, "market", "request", "publish"))
3310
+ return await handleMarketRequestPublish(resolvedArgs, io).then(() => 0);
3311
+ if (commandMatches(resolvedArgs.commandPath, "market", "request", "revise"))
3312
+ return await handleMarketRequestRevise(resolvedArgs, io).then(() => 0);
3313
+ if (commandMatches(resolvedArgs.commandPath, "market", "request", "close"))
3314
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "request", "request.closed").then(() => 0);
3315
+ if (commandMatches(resolvedArgs.commandPath, "market", "request", "expire"))
3316
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "request", "request.expired").then(() => 0);
3317
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "submit"))
3318
+ return await handleMarketOfferSubmit(resolvedArgs, io).then(() => 0);
3319
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "counter"))
3320
+ return await handleMarketOfferCounter(resolvedArgs, io).then(() => 0);
3321
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "accept"))
3322
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "offer", "offer.accepted").then(() => 0);
3323
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "reject"))
3324
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "offer", "offer.rejected").then(() => 0);
3325
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "cancel"))
3326
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "offer", "offer.canceled").then(() => 0);
3327
+ if (commandMatches(resolvedArgs.commandPath, "market", "offer", "expire"))
3328
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "offer", "offer.expired").then(() => 0);
3329
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "submit"))
3330
+ return await handleMarketBidSubmit(resolvedArgs, io).then(() => 0);
3331
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "counter"))
3332
+ return await handleMarketBidCounter(resolvedArgs, io).then(() => 0);
3333
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "accept"))
3334
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "bid", "bid.accepted").then(() => 0);
3335
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "reject"))
3336
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "bid", "bid.rejected").then(() => 0);
3337
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "cancel"))
3338
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "bid", "bid.canceled").then(() => 0);
3339
+ if (commandMatches(resolvedArgs.commandPath, "market", "bid", "expire"))
3340
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "bid", "bid.expired").then(() => 0);
3341
+ if (commandMatches(resolvedArgs.commandPath, "market", "agreement", "create"))
3342
+ return await handleMarketAgreementCreate(resolvedArgs, io).then(() => 0);
3343
+ if (commandMatches(resolvedArgs.commandPath, "market", "agreement", "complete"))
3344
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "agreement", "agreement.completed").then(() => 0);
3345
+ if (commandMatches(resolvedArgs.commandPath, "market", "agreement", "cancel"))
3346
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "agreement", "agreement.canceled").then(() => 0);
3347
+ if (commandMatches(resolvedArgs.commandPath, "market", "agreement", "dispute"))
3348
+ return await handleSimpleMarketStateChange(resolvedArgs, io, "agreement", "agreement.disputed").then(() => 0);
3349
+ if (commandMatches(resolvedArgs.commandPath, "market", "list"))
3350
+ return await handleMarketList(resolvedArgs, io).then(() => 0);
3351
+ if (commandMatches(resolvedArgs.commandPath, "contract", "create"))
3352
+ return await handleContractCreate(resolvedArgs, io).then(() => 0);
3353
+ if (commandMatches(resolvedArgs.commandPath, "contract", "open-milestone"))
3354
+ return await handleContractMilestoneAction(resolvedArgs, io, "contract.milestone-opened").then(() => 0);
3355
+ if (commandMatches(resolvedArgs.commandPath, "contract", "submit-milestone"))
3356
+ return await handleContractMilestoneAction(resolvedArgs, io, "contract.milestone-submitted").then(() => 0);
3357
+ if (commandMatches(resolvedArgs.commandPath, "contract", "accept-milestone"))
3358
+ return await handleContractMilestoneAction(resolvedArgs, io, "contract.milestone-accepted").then(() => 0);
3359
+ if (commandMatches(resolvedArgs.commandPath, "contract", "reject-milestone"))
3360
+ return await handleContractMilestoneAction(resolvedArgs, io, "contract.milestone-rejected").then(() => 0);
3361
+ if (commandMatches(resolvedArgs.commandPath, "contract", "pause"))
3362
+ return await handleContractStateChange(resolvedArgs, io, "contract.paused").then(() => 0);
3363
+ if (commandMatches(resolvedArgs.commandPath, "contract", "resume"))
3364
+ return await handleContractStateChange(resolvedArgs, io, "contract.resumed").then(() => 0);
3365
+ if (commandMatches(resolvedArgs.commandPath, "contract", "complete"))
3366
+ return await handleContractStateChange(resolvedArgs, io, "contract.completed").then(() => 0);
3367
+ if (commandMatches(resolvedArgs.commandPath, "contract", "cancel"))
3368
+ return await handleContractStateChange(resolvedArgs, io, "contract.canceled").then(() => 0);
3369
+ if (commandMatches(resolvedArgs.commandPath, "contract", "dispute"))
3370
+ return await handleContractStateChange(resolvedArgs, io, "contract.disputed").then(() => 0);
3371
+ if (commandMatches(resolvedArgs.commandPath, "contract", "entries"))
3372
+ return await handleContractEntries(resolvedArgs, io).then(() => 0);
3373
+ if (commandMatches(resolvedArgs.commandPath, "evidence", "record"))
3374
+ return await handleEvidenceRecord(resolvedArgs, io).then(() => 0);
3375
+ if (commandMatches(resolvedArgs.commandPath, "oracle", "attest"))
3376
+ return await handleOracleAttest(resolvedArgs, io).then(() => 0);
3377
+ if (commandMatches(resolvedArgs.commandPath, "dispute", "open"))
3378
+ return await handleDisputeOpen(resolvedArgs, io).then(() => 0);
3379
+ if (commandMatches(resolvedArgs.commandPath, "dispute", "add-evidence"))
3380
+ return await handleDisputeAddEvidence(resolvedArgs, io).then(() => 0);
3381
+ if (commandMatches(resolvedArgs.commandPath, "dispute", "request-oracle"))
3382
+ return await handleDisputeRequestOracle(resolvedArgs, io).then(() => 0);
3383
+ if (commandMatches(resolvedArgs.commandPath, "dispute", "rule"))
3384
+ return await handleDisputeRule(resolvedArgs, io).then(() => 0);
3385
+ if (commandMatches(resolvedArgs.commandPath, "dispute", "close"))
3386
+ return await handleDisputeClose(resolvedArgs, io).then(() => 0);
3387
+ if (commandMatches(resolvedArgs.commandPath, "space", "create"))
3388
+ return await handleSpaceCreate(resolvedArgs, io).then(() => 0);
3389
+ if (commandMatches(resolvedArgs.commandPath, "space", "add-member"))
3390
+ return await handleSpaceMembershipAction(resolvedArgs, io, "space-membership.member-added").then(() => 0);
3391
+ if (commandMatches(resolvedArgs.commandPath, "space", "remove-member"))
3392
+ return await handleSpaceMembershipAction(resolvedArgs, io, "space-membership.member-removed").then(() => 0);
3393
+ if (commandMatches(resolvedArgs.commandPath, "space", "mute-member"))
3394
+ return await handleSpaceMembershipAction(resolvedArgs, io, "space-membership.member-muted").then(() => 0);
3395
+ if (commandMatches(resolvedArgs.commandPath, "space", "set-role"))
3396
+ return await handleSpaceMembershipAction(resolvedArgs, io, "space-membership.member-role-updated").then(() => 0);
3397
+ if (commandMatches(resolvedArgs.commandPath, "space", "entries"))
3398
+ return await handleSpaceEntries(resolvedArgs, io).then(() => 0);
3399
+ if (commandMatches(resolvedArgs.commandPath, "message", "send"))
3400
+ return await handleMessageSend(resolvedArgs, io).then(() => 0);
3401
+ if (commandMatches(resolvedArgs.commandPath, "message", "edit"))
3402
+ return await handleMessageEdit(resolvedArgs, io).then(() => 0);
3403
+ if (commandMatches(resolvedArgs.commandPath, "message", "delete"))
3404
+ return await handleMessageDelete(resolvedArgs, io).then(() => 0);
3405
+ if (commandMatches(resolvedArgs.commandPath, "message", "react"))
3406
+ return await handleMessageReact(resolvedArgs, io).then(() => 0);
3407
+ if (commandMatches(resolvedArgs.commandPath, "object", "show"))
3408
+ return await handleObjectShow(resolvedArgs, io).then(() => 0);
3409
+ throw new Error(`Unknown command: ${resolvedArgs.commandPath.join(" ")}`);
2397
3410
  }
2398
3411
  export async function runCli(argv, io = DEFAULT_IO) {
2399
3412
  try {