@garydevenay/emporion 0.0.1 → 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.
- package/README.md +230 -10
- package/dist/src/cli.js +1626 -300
- package/dist/src/cli.js.map +1 -1
- package/dist/src/context-store.d.ts +22 -0
- package/dist/src/context-store.js +133 -0
- package/dist/src/context-store.js.map +1 -0
- package/dist/src/daemon.d.ts +76 -0
- package/dist/src/daemon.js +341 -0
- package/dist/src/daemon.js.map +1 -0
- package/dist/src/errors.d.ts +8 -0
- package/dist/src/errors.js +8 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/experience/deals-store.d.ts +37 -0
- package/dist/src/experience/deals-store.js +96 -0
- package/dist/src/experience/deals-store.js.map +1 -0
- package/dist/src/handshake.js +69 -45
- package/dist/src/handshake.js.map +1 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/transport.d.ts +6 -1
- package/dist/src/transport.js +17 -1
- package/dist/src/transport.js.map +1 -1
- package/dist/src/wallet/config-store.d.ts +16 -0
- package/dist/src/wallet/config-store.js +180 -0
- package/dist/src/wallet/config-store.js.map +1 -0
- package/dist/src/wallet/index.d.ts +3 -0
- package/dist/src/wallet/index.js +4 -0
- package/dist/src/wallet/index.js.map +1 -0
- package/dist/src/wallet/ledger.d.ts +50 -0
- package/dist/src/wallet/ledger.js +340 -0
- package/dist/src/wallet/ledger.js.map +1 -0
- package/dist/src/wallet/nostr-nwc-adapter.d.ts +40 -0
- package/dist/src/wallet/nostr-nwc-adapter.js +506 -0
- package/dist/src/wallet/nostr-nwc-adapter.js.map +1 -0
- package/dist/src/wallet/nwc-adapter.d.ts +20 -0
- package/dist/src/wallet/nwc-adapter.js +233 -0
- package/dist/src/wallet/nwc-adapter.js.map +1 -0
- package/dist/src/wallet/service.d.ts +42 -0
- package/dist/src/wallet/service.js +390 -0
- package/dist/src/wallet/service.js.map +1 -0
- package/dist/src/wallet/types.d.ts +140 -0
- package/dist/src/wallet/types.js +2 -0
- package/dist/src/wallet/types.js.map +1 -0
- package/dist/test/cli.test.js +76 -15
- package/dist/test/cli.test.js.map +1 -1
- package/dist/test/experience.test.d.ts +1 -0
- package/dist/test/experience.test.js +232 -0
- package/dist/test/experience.test.js.map +1 -0
- package/dist/test/integration.test.js +37 -31
- package/dist/test/integration.test.js.map +1 -1
- package/dist/test/unit.test.js +26 -0
- package/dist/test/unit.test.js.map +1 -1
- package/dist/test/wallet.test.d.ts +1 -0
- package/dist/test/wallet.test.js +853 -0
- package/dist/test/wallet.test.js.map +1 -0
- package/package.json +2 -1
package/dist/src/cli.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
2
5
|
import { once } from "node:events";
|
|
6
|
+
import { closeSync } from "node:fs";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
10
|
+
import { AgentDaemon, cleanupStaleDaemonArtifacts, daemonOptionsRecordToMap, daemonRequestFromParsed, daemonRequestOptionsToRecord, ensureDaemonRuntimeDir, getDaemonLogPath, getLocalControlEndpoint, openDaemonLogFd, probeDaemonStatus, sendDaemonCommand } from "./daemon.js";
|
|
3
11
|
import { AgentTransport } from "./transport.js";
|
|
4
12
|
import { createLogger } from "./logger.js";
|
|
5
13
|
import { loadPersistentIdentityMaterial } from "./persistent-agent.js";
|
|
6
14
|
import * as Protocol from "./protocol/index.js";
|
|
7
15
|
import { sha256Hex } from "./protocol/shared.js";
|
|
8
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;
|
|
9
22
|
const DEFAULT_IO = {
|
|
10
23
|
stdout(message) {
|
|
11
24
|
process.stdout.write(message);
|
|
@@ -14,6 +27,7 @@ const DEFAULT_IO = {
|
|
|
14
27
|
process.stderr.write(message);
|
|
15
28
|
}
|
|
16
29
|
};
|
|
30
|
+
const CLI_CONTEXT_STORAGE = new AsyncLocalStorage();
|
|
17
31
|
function parseArgs(argv) {
|
|
18
32
|
const commandPath = [];
|
|
19
33
|
const options = new Map();
|
|
@@ -43,6 +57,12 @@ function parseArgs(argv) {
|
|
|
43
57
|
function commandMatches(commandPath, ...expected) {
|
|
44
58
|
return commandPath.length === expected.length && expected.every((value, index) => commandPath[index] === value);
|
|
45
59
|
}
|
|
60
|
+
function isContextCommand(commandPath) {
|
|
61
|
+
return commandPath[0] === "context";
|
|
62
|
+
}
|
|
63
|
+
function isWalletCommand(commandPath) {
|
|
64
|
+
return commandPath[0] === "wallet";
|
|
65
|
+
}
|
|
46
66
|
function getOptionValues(args, name) {
|
|
47
67
|
return args.options.get(name) ?? [];
|
|
48
68
|
}
|
|
@@ -84,6 +104,17 @@ function parseOptionalNonNegativeInteger(args, name) {
|
|
|
84
104
|
const value = getOptionalOption(args, name);
|
|
85
105
|
return value === undefined ? undefined : parseNonNegativeInteger(value, `--${name}`);
|
|
86
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
|
+
}
|
|
87
118
|
function parseEnum(value, fieldName, allowed) {
|
|
88
119
|
if (allowed.includes(value)) {
|
|
89
120
|
return value;
|
|
@@ -182,27 +213,190 @@ function getUniqueOptionValues(args, name) {
|
|
|
182
213
|
function writeJson(io, value) {
|
|
183
214
|
io.stdout(`${JSON.stringify(value, null, 2)}\n`);
|
|
184
215
|
}
|
|
185
|
-
|
|
216
|
+
function normalizeDataDirPath(dataDir) {
|
|
217
|
+
return path.resolve(dataDir);
|
|
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
|
+
}
|
|
362
|
+
async function openCliContext(dataDir) {
|
|
186
363
|
const identityMaterial = await loadPersistentIdentityMaterial(dataDir);
|
|
187
364
|
const repository = await Protocol.ProtocolRepository.create(dataDir);
|
|
188
365
|
const transportStorage = await TransportStorage.create(dataDir, identityMaterial.storagePrimaryKey, createLogger("error"));
|
|
366
|
+
const walletService = await WalletService.create({ dataDir });
|
|
189
367
|
await transportStorage.initializeDefaults();
|
|
368
|
+
return {
|
|
369
|
+
dataDir,
|
|
370
|
+
identityMaterial,
|
|
371
|
+
repository,
|
|
372
|
+
transportStorage,
|
|
373
|
+
walletService,
|
|
374
|
+
signer: {
|
|
375
|
+
did: identityMaterial.agentIdentity.did,
|
|
376
|
+
publicKey: identityMaterial.transportKeyPair.publicKey,
|
|
377
|
+
secretKey: identityMaterial.transportKeyPair.secretKey
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
async function closeCliContext(context) {
|
|
382
|
+
await context.walletService.close();
|
|
383
|
+
await context.transportStorage.close();
|
|
384
|
+
await context.repository.close();
|
|
385
|
+
}
|
|
386
|
+
async function withCliContext(dataDir, fn) {
|
|
387
|
+
const sharedContext = CLI_CONTEXT_STORAGE.getStore();
|
|
388
|
+
if (sharedContext) {
|
|
389
|
+
if (normalizeDataDirPath(sharedContext.dataDir) !== normalizeDataDirPath(dataDir)) {
|
|
390
|
+
throw new Error(`Daemon context is bound to ${sharedContext.dataDir}, not ${dataDir}`);
|
|
391
|
+
}
|
|
392
|
+
return fn(sharedContext);
|
|
393
|
+
}
|
|
394
|
+
const context = await openCliContext(dataDir);
|
|
190
395
|
try {
|
|
191
|
-
return await fn(
|
|
192
|
-
dataDir,
|
|
193
|
-
identityMaterial,
|
|
194
|
-
repository,
|
|
195
|
-
transportStorage,
|
|
196
|
-
signer: {
|
|
197
|
-
did: identityMaterial.agentIdentity.did,
|
|
198
|
-
publicKey: identityMaterial.transportKeyPair.publicKey,
|
|
199
|
-
secretKey: identityMaterial.transportKeyPair.secretKey
|
|
200
|
-
}
|
|
201
|
-
});
|
|
396
|
+
return await CLI_CONTEXT_STORAGE.run(context, async () => fn(context));
|
|
202
397
|
}
|
|
203
398
|
finally {
|
|
204
|
-
await
|
|
205
|
-
await repository.close();
|
|
399
|
+
await closeCliContext(context);
|
|
206
400
|
}
|
|
207
401
|
}
|
|
208
402
|
async function readRequiredState(repository, objectKind, objectId) {
|
|
@@ -1745,101 +1939,640 @@ async function handleMarketList(args, io) {
|
|
|
1745
1939
|
});
|
|
1746
1940
|
});
|
|
1747
1941
|
}
|
|
1748
|
-
async function
|
|
1942
|
+
async function handleContextAdd(args, io) {
|
|
1943
|
+
const name = requireOption(args, "name");
|
|
1749
1944
|
const dataDir = requireOption(args, "data-dir");
|
|
1750
|
-
const
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
"
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
const
|
|
1761
|
-
const
|
|
1762
|
-
const
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
};
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
const
|
|
1771
|
-
const
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
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;
|
|
1792
2029
|
}
|
|
1793
2030
|
writeJson(io, {
|
|
1794
|
-
command: "
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
2031
|
+
command: "wallet.connect.nwc",
|
|
2032
|
+
wallet: connected.status,
|
|
2033
|
+
endpoint: connected.endpoint,
|
|
2034
|
+
...(paymentEndpointEventId ? { paymentEndpointEventId } : {})
|
|
1798
2035
|
});
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
if (exitAfterMs) {
|
|
1826
|
-
await sleep(parsePositiveInteger(exitAfterMs, "--exit-after-ms"));
|
|
1827
|
-
return;
|
|
1828
|
-
}
|
|
1829
|
-
await Promise.race([once(process, "SIGINT"), once(process, "SIGTERM")]);
|
|
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");
|
|
1830
2062
|
}
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
await transport.stop();
|
|
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");
|
|
1836
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);
|
|
1837
2545
|
}
|
|
1838
2546
|
function usage() {
|
|
1839
2547
|
return [
|
|
1840
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>",
|
|
1841
2555
|
" emporion agent init --data-dir <path> [--display-name <name>] [--bio <text>]",
|
|
1842
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>",
|
|
1843
2576
|
" emporion agent payment-endpoint add --data-dir <path> --id <id> --capability <cap>[,<cap>...]",
|
|
1844
2577
|
" emporion agent wallet-attestation add --data-dir <path> --attestation-id <id> --wallet-account-id <id> --balance-sats <n> --expires-at <iso>",
|
|
1845
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>",
|
|
@@ -1861,238 +2594,831 @@ function usage() {
|
|
|
1861
2594
|
" emporion message send --data-dir <path> --space-id <id> --body <text>",
|
|
1862
2595
|
" emporion market list --data-dir <path> --marketplace <id>",
|
|
1863
2596
|
" emporion object show --data-dir <path> --kind <kind> --id <id>",
|
|
1864
|
-
" emporion
|
|
2597
|
+
" emporion daemon start --data-dir <path> [--marketplace <id>] [--company <did>] [--agent-topic]",
|
|
2598
|
+
" emporion daemon status --data-dir <path>",
|
|
2599
|
+
" emporion daemon stop --data-dir <path>",
|
|
2600
|
+
" emporion daemon logs --data-dir <path> [--tail <n>] [--follow]"
|
|
1865
2601
|
].join("\n");
|
|
1866
2602
|
}
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
return await handleMarketProductStateChange(args, io, "product.published").then(() => 0);
|
|
1931
|
-
}
|
|
1932
|
-
if (commandMatches(args.commandPath, "market", "product", "unpublish")) {
|
|
1933
|
-
return await handleMarketProductStateChange(args, io, "product.unpublished").then(() => 0);
|
|
1934
|
-
}
|
|
1935
|
-
if (commandMatches(args.commandPath, "market", "product", "retire")) {
|
|
1936
|
-
return await handleMarketProductStateChange(args, io, "product.retired").then(() => 0);
|
|
1937
|
-
}
|
|
1938
|
-
if (commandMatches(args.commandPath, "market", "listing", "publish")) {
|
|
1939
|
-
return await handleMarketListingPublish(args, io).then(() => 0);
|
|
1940
|
-
}
|
|
1941
|
-
if (commandMatches(args.commandPath, "market", "listing", "revise")) {
|
|
1942
|
-
return await handleMarketListingRevise(args, io).then(() => 0);
|
|
1943
|
-
}
|
|
1944
|
-
if (commandMatches(args.commandPath, "market", "listing", "withdraw")) {
|
|
1945
|
-
return await handleSimpleMarketStateChange(args, io, "listing", "listing.withdrawn").then(() => 0);
|
|
1946
|
-
}
|
|
1947
|
-
if (commandMatches(args.commandPath, "market", "listing", "expire")) {
|
|
1948
|
-
return await handleSimpleMarketStateChange(args, io, "listing", "listing.expired").then(() => 0);
|
|
1949
|
-
}
|
|
1950
|
-
if (commandMatches(args.commandPath, "market", "request", "publish")) {
|
|
1951
|
-
return await handleMarketRequestPublish(args, io).then(() => 0);
|
|
1952
|
-
}
|
|
1953
|
-
if (commandMatches(args.commandPath, "market", "request", "revise")) {
|
|
1954
|
-
return await handleMarketRequestRevise(args, io).then(() => 0);
|
|
1955
|
-
}
|
|
1956
|
-
if (commandMatches(args.commandPath, "market", "request", "close")) {
|
|
1957
|
-
return await handleSimpleMarketStateChange(args, io, "request", "request.closed").then(() => 0);
|
|
1958
|
-
}
|
|
1959
|
-
if (commandMatches(args.commandPath, "market", "request", "expire")) {
|
|
1960
|
-
return await handleSimpleMarketStateChange(args, io, "request", "request.expired").then(() => 0);
|
|
1961
|
-
}
|
|
1962
|
-
if (commandMatches(args.commandPath, "market", "offer", "submit")) {
|
|
1963
|
-
return await handleMarketOfferSubmit(args, io).then(() => 0);
|
|
1964
|
-
}
|
|
1965
|
-
if (commandMatches(args.commandPath, "market", "offer", "counter")) {
|
|
1966
|
-
return await handleMarketOfferCounter(args, io).then(() => 0);
|
|
1967
|
-
}
|
|
1968
|
-
if (commandMatches(args.commandPath, "market", "offer", "accept")) {
|
|
1969
|
-
return await handleSimpleMarketStateChange(args, io, "offer", "offer.accepted").then(() => 0);
|
|
1970
|
-
}
|
|
1971
|
-
if (commandMatches(args.commandPath, "market", "offer", "reject")) {
|
|
1972
|
-
return await handleSimpleMarketStateChange(args, io, "offer", "offer.rejected").then(() => 0);
|
|
1973
|
-
}
|
|
1974
|
-
if (commandMatches(args.commandPath, "market", "offer", "cancel")) {
|
|
1975
|
-
return await handleSimpleMarketStateChange(args, io, "offer", "offer.canceled").then(() => 0);
|
|
1976
|
-
}
|
|
1977
|
-
if (commandMatches(args.commandPath, "market", "offer", "expire")) {
|
|
1978
|
-
return await handleSimpleMarketStateChange(args, io, "offer", "offer.expired").then(() => 0);
|
|
1979
|
-
}
|
|
1980
|
-
if (commandMatches(args.commandPath, "market", "bid", "submit")) {
|
|
1981
|
-
return await handleMarketBidSubmit(args, io).then(() => 0);
|
|
1982
|
-
}
|
|
1983
|
-
if (commandMatches(args.commandPath, "market", "bid", "counter")) {
|
|
1984
|
-
return await handleMarketBidCounter(args, io).then(() => 0);
|
|
1985
|
-
}
|
|
1986
|
-
if (commandMatches(args.commandPath, "market", "bid", "accept")) {
|
|
1987
|
-
return await handleSimpleMarketStateChange(args, io, "bid", "bid.accepted").then(() => 0);
|
|
1988
|
-
}
|
|
1989
|
-
if (commandMatches(args.commandPath, "market", "bid", "reject")) {
|
|
1990
|
-
return await handleSimpleMarketStateChange(args, io, "bid", "bid.rejected").then(() => 0);
|
|
1991
|
-
}
|
|
1992
|
-
if (commandMatches(args.commandPath, "market", "bid", "cancel")) {
|
|
1993
|
-
return await handleSimpleMarketStateChange(args, io, "bid", "bid.canceled").then(() => 0);
|
|
1994
|
-
}
|
|
1995
|
-
if (commandMatches(args.commandPath, "market", "bid", "expire")) {
|
|
1996
|
-
return await handleSimpleMarketStateChange(args, io, "bid", "bid.expired").then(() => 0);
|
|
2603
|
+
function getDataDirFromArgs(args) {
|
|
2604
|
+
return getOptionalOption(args, "data-dir");
|
|
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
|
+
}
|
|
2653
|
+
function createCaptureIo() {
|
|
2654
|
+
const stdout = [];
|
|
2655
|
+
const stderr = [];
|
|
2656
|
+
return {
|
|
2657
|
+
stdout,
|
|
2658
|
+
stderr,
|
|
2659
|
+
io: {
|
|
2660
|
+
stdout(message) {
|
|
2661
|
+
stdout.push(message);
|
|
2662
|
+
},
|
|
2663
|
+
stderr(message) {
|
|
2664
|
+
stderr.push(message);
|
|
2665
|
+
}
|
|
1997
2666
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2667
|
+
};
|
|
2668
|
+
}
|
|
2669
|
+
function buildTransportConfigFromArgs(args) {
|
|
2670
|
+
const dataDir = requireOption(args, "data-dir");
|
|
2671
|
+
const logLevel = parseEnum(getOptionalOption(args, "log-level") ?? "info", "--log-level", [
|
|
2672
|
+
"debug",
|
|
2673
|
+
"info",
|
|
2674
|
+
"warn",
|
|
2675
|
+
"error"
|
|
2676
|
+
]);
|
|
2677
|
+
const bootstrap = getCsvOptionValues(args, "bootstrap");
|
|
2678
|
+
return {
|
|
2679
|
+
dataDir,
|
|
2680
|
+
logLevel,
|
|
2681
|
+
...(bootstrap.length > 0 ? { bootstrap } : {})
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
function buildTopicsFromArgs(args, agentDid) {
|
|
2685
|
+
const topics = [];
|
|
2686
|
+
if (hasFlag(args, "agent-topic")) {
|
|
2687
|
+
topics.push({ kind: "agent", agentDid });
|
|
2688
|
+
}
|
|
2689
|
+
for (const marketplaceId of getCsvOptionValues(args, "marketplace")) {
|
|
2690
|
+
topics.push({ kind: "marketplace", marketplaceId });
|
|
2691
|
+
}
|
|
2692
|
+
for (const companyId of getCsvOptionValues(args, "company")) {
|
|
2693
|
+
topics.push({ kind: "company", companyId });
|
|
2694
|
+
}
|
|
2695
|
+
return topics;
|
|
2696
|
+
}
|
|
2697
|
+
function getDaemonStartupOptions(args) {
|
|
2698
|
+
return {
|
|
2699
|
+
topics: [],
|
|
2700
|
+
connectDids: getCsvOptionValues(args, "connect-did"),
|
|
2701
|
+
connectNoiseKeys: getCsvOptionValues(args, "connect-noise-key"),
|
|
2702
|
+
watchProtocol: !hasFlag(args, "no-watch-protocol")
|
|
2703
|
+
};
|
|
2704
|
+
}
|
|
2705
|
+
function sanitizeExecArgv() {
|
|
2706
|
+
return process.execArgv.filter((value) => value !== "--test" && !value.startsWith("--test-"));
|
|
2707
|
+
}
|
|
2708
|
+
function buildDaemonRunArgv(args) {
|
|
2709
|
+
const forwarded = new Set([
|
|
2710
|
+
"data-dir",
|
|
2711
|
+
"log-level",
|
|
2712
|
+
"bootstrap",
|
|
2713
|
+
"marketplace",
|
|
2714
|
+
"company",
|
|
2715
|
+
"connect-did",
|
|
2716
|
+
"connect-noise-key",
|
|
2717
|
+
"agent-topic",
|
|
2718
|
+
"no-watch-protocol"
|
|
2719
|
+
]);
|
|
2720
|
+
const argv = [...sanitizeExecArgv()];
|
|
2721
|
+
argv.push(fileURLToPath(import.meta.url), "daemon", "run");
|
|
2722
|
+
for (const [name, values] of args.options.entries()) {
|
|
2723
|
+
if (!forwarded.has(name)) {
|
|
2724
|
+
continue;
|
|
2725
|
+
}
|
|
2726
|
+
for (const value of values) {
|
|
2727
|
+
argv.push(`--${name}`);
|
|
2728
|
+
if (value !== "true") {
|
|
2729
|
+
argv.push(value);
|
|
2730
|
+
}
|
|
2000
2731
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2732
|
+
}
|
|
2733
|
+
return argv;
|
|
2734
|
+
}
|
|
2735
|
+
function tailText(input, lineCount) {
|
|
2736
|
+
if (lineCount <= 0) {
|
|
2737
|
+
return "";
|
|
2738
|
+
}
|
|
2739
|
+
const lines = input.split("\n");
|
|
2740
|
+
const slice = lines.slice(Math.max(lines.length - lineCount - 1, 0)).join("\n");
|
|
2741
|
+
return slice.length > 0 && !slice.endsWith("\n") ? `${slice}\n` : slice;
|
|
2742
|
+
}
|
|
2743
|
+
async function readDaemonLogTail(dataDir, lineCount) {
|
|
2744
|
+
try {
|
|
2745
|
+
return tailText(await readFile(getDaemonLogPath(dataDir), "utf8"), lineCount);
|
|
2746
|
+
}
|
|
2747
|
+
catch {
|
|
2748
|
+
return "";
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
async function waitForDaemonReady(dataDir, timeoutMs) {
|
|
2752
|
+
const deadline = Date.now() + timeoutMs;
|
|
2753
|
+
let lastError;
|
|
2754
|
+
while (Date.now() < deadline) {
|
|
2755
|
+
try {
|
|
2756
|
+
const status = await probeDaemonStatus(dataDir, 1_000);
|
|
2757
|
+
if (status) {
|
|
2758
|
+
return status;
|
|
2759
|
+
}
|
|
2003
2760
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2761
|
+
catch (error) {
|
|
2762
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2006
2763
|
}
|
|
2007
|
-
|
|
2008
|
-
|
|
2764
|
+
await sleep(100);
|
|
2765
|
+
}
|
|
2766
|
+
if (lastError) {
|
|
2767
|
+
throw lastError;
|
|
2768
|
+
}
|
|
2769
|
+
throw new Error(`Daemon for ${dataDir} did not become ready within ${timeoutMs}ms`);
|
|
2770
|
+
}
|
|
2771
|
+
async function waitForDaemonExit(dataDir, timeoutMs) {
|
|
2772
|
+
const deadline = Date.now() + timeoutMs;
|
|
2773
|
+
while (Date.now() < deadline) {
|
|
2774
|
+
try {
|
|
2775
|
+
const status = await probeDaemonStatus(dataDir, 1_000);
|
|
2776
|
+
if (!status) {
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2009
2779
|
}
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
if (commandMatches(args.commandPath, "contract", "create"))
|
|
2013
|
-
return await handleContractCreate(args, io).then(() => 0);
|
|
2014
|
-
if (commandMatches(args.commandPath, "contract", "open-milestone")) {
|
|
2015
|
-
return await handleContractMilestoneAction(args, io, "contract.milestone-opened").then(() => 0);
|
|
2780
|
+
catch {
|
|
2781
|
+
// The daemon may tear down the socket before the pid disappears.
|
|
2016
2782
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2783
|
+
await sleep(100);
|
|
2784
|
+
}
|
|
2785
|
+
throw new Error(`Daemon for ${dataDir} did not stop within ${timeoutMs}ms`);
|
|
2786
|
+
}
|
|
2787
|
+
async function proxyParsedArgsToDaemon(args, io) {
|
|
2788
|
+
const dataDir = getDataDirFromArgs(args);
|
|
2789
|
+
if (!dataDir) {
|
|
2790
|
+
return 1;
|
|
2791
|
+
}
|
|
2792
|
+
const response = await sendDaemonCommand(dataDir, daemonRequestFromParsed(args.commandPath, daemonRequestOptionsToRecord(args.options)), getDaemonProxyTimeoutMs(args.commandPath));
|
|
2793
|
+
if (!response.ok) {
|
|
2794
|
+
throw new Error(response.error ?? "Daemon command failed");
|
|
2795
|
+
}
|
|
2796
|
+
if (response.result !== undefined) {
|
|
2797
|
+
writeJson(io, response.result);
|
|
2798
|
+
}
|
|
2799
|
+
return 0;
|
|
2800
|
+
}
|
|
2801
|
+
async function executeCapturedInDaemon(args) {
|
|
2802
|
+
const capture = createCaptureIo();
|
|
2803
|
+
const exitCode = await executeParsedArgs(args, capture.io, { allowDaemonProxy: false });
|
|
2804
|
+
if (exitCode !== 0) {
|
|
2805
|
+
throw new Error(capture.stderr.join("").trim() || "Daemon command failed");
|
|
2806
|
+
}
|
|
2807
|
+
const output = capture.stdout.join("").trim();
|
|
2808
|
+
return output.length === 0 ? null : JSON.parse(output);
|
|
2809
|
+
}
|
|
2810
|
+
async function handleDaemonStart(args, io) {
|
|
2811
|
+
const dataDir = requireOption(args, "data-dir");
|
|
2812
|
+
const existing = await probeDaemonStatus(dataDir, 1_000);
|
|
2813
|
+
if (existing) {
|
|
2814
|
+
writeJson(io, {
|
|
2815
|
+
command: "daemon.start",
|
|
2816
|
+
alreadyRunning: true,
|
|
2817
|
+
status: existing
|
|
2818
|
+
});
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
await ensureDaemonRuntimeDir(dataDir);
|
|
2822
|
+
const logFd = openDaemonLogFd(dataDir);
|
|
2823
|
+
let childError;
|
|
2824
|
+
try {
|
|
2825
|
+
const child = spawn(process.execPath, buildDaemonRunArgv(args), {
|
|
2826
|
+
detached: true,
|
|
2827
|
+
stdio: ["ignore", logFd, logFd],
|
|
2828
|
+
env: {
|
|
2829
|
+
...process.env,
|
|
2830
|
+
EMPORION_DAEMON: "1"
|
|
2831
|
+
}
|
|
2832
|
+
});
|
|
2833
|
+
child.once("error", (error) => {
|
|
2834
|
+
childError = error;
|
|
2835
|
+
});
|
|
2836
|
+
child.unref();
|
|
2837
|
+
}
|
|
2838
|
+
finally {
|
|
2839
|
+
closeSync(logFd);
|
|
2840
|
+
}
|
|
2841
|
+
if (childError) {
|
|
2842
|
+
throw childError;
|
|
2843
|
+
}
|
|
2844
|
+
const status = await waitForDaemonReady(dataDir, 10_000);
|
|
2845
|
+
writeJson(io, {
|
|
2846
|
+
command: "daemon.start",
|
|
2847
|
+
alreadyRunning: false,
|
|
2848
|
+
status
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
async function handleDaemonStatus(args, io) {
|
|
2852
|
+
const dataDir = requireOption(args, "data-dir");
|
|
2853
|
+
const status = await probeDaemonStatus(dataDir, 1_000);
|
|
2854
|
+
if (!status) {
|
|
2855
|
+
throw new Error(`No daemon is running for ${dataDir}`);
|
|
2856
|
+
}
|
|
2857
|
+
writeJson(io, {
|
|
2858
|
+
command: "daemon.status",
|
|
2859
|
+
status
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2862
|
+
async function handleDaemonStop(args, io) {
|
|
2863
|
+
const dataDir = requireOption(args, "data-dir");
|
|
2864
|
+
const status = await probeDaemonStatus(dataDir, 1_000);
|
|
2865
|
+
if (!status) {
|
|
2866
|
+
await cleanupStaleDaemonArtifacts(dataDir);
|
|
2867
|
+
writeJson(io, {
|
|
2868
|
+
command: "daemon.stop",
|
|
2869
|
+
stopped: true,
|
|
2870
|
+
alreadyStopped: true
|
|
2871
|
+
});
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2874
|
+
const response = await sendDaemonCommand(dataDir, {
|
|
2875
|
+
commandPath: ["daemon", "stop"],
|
|
2876
|
+
options: {}
|
|
2877
|
+
});
|
|
2878
|
+
if (!response.ok) {
|
|
2879
|
+
throw new Error(response.error ?? "Daemon stop request failed");
|
|
2880
|
+
}
|
|
2881
|
+
await waitForDaemonExit(dataDir, 10_000);
|
|
2882
|
+
writeJson(io, {
|
|
2883
|
+
command: "daemon.stop",
|
|
2884
|
+
stopped: true,
|
|
2885
|
+
pid: status.pid
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
async function handleDaemonLogs(args, io) {
|
|
2889
|
+
const dataDir = requireOption(args, "data-dir");
|
|
2890
|
+
const tail = parseNonNegativeInteger(getOptionalOption(args, "tail") ?? "100", "--tail");
|
|
2891
|
+
const follow = hasFlag(args, "follow");
|
|
2892
|
+
const logPath = getDaemonLogPath(dataDir);
|
|
2893
|
+
let currentContents = await readDaemonLogTail(dataDir, tail);
|
|
2894
|
+
if (currentContents.length > 0) {
|
|
2895
|
+
io.stdout(currentContents);
|
|
2896
|
+
}
|
|
2897
|
+
if (!follow) {
|
|
2898
|
+
return;
|
|
2899
|
+
}
|
|
2900
|
+
let stopped = false;
|
|
2901
|
+
const stop = () => {
|
|
2902
|
+
stopped = true;
|
|
2903
|
+
};
|
|
2904
|
+
process.once("SIGINT", stop);
|
|
2905
|
+
process.once("SIGTERM", stop);
|
|
2906
|
+
try {
|
|
2907
|
+
try {
|
|
2908
|
+
currentContents = await readFile(logPath, "utf8");
|
|
2019
2909
|
}
|
|
2020
|
-
|
|
2021
|
-
|
|
2910
|
+
catch {
|
|
2911
|
+
currentContents = "";
|
|
2022
2912
|
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2913
|
+
let lastLength = currentContents.length;
|
|
2914
|
+
while (!stopped) {
|
|
2915
|
+
await sleep(500);
|
|
2916
|
+
if (stopped) {
|
|
2917
|
+
break;
|
|
2918
|
+
}
|
|
2919
|
+
try {
|
|
2920
|
+
const next = await readFile(logPath, "utf8");
|
|
2921
|
+
if (next.length > lastLength) {
|
|
2922
|
+
io.stdout(next.slice(lastLength));
|
|
2923
|
+
}
|
|
2924
|
+
lastLength = next.length;
|
|
2925
|
+
}
|
|
2926
|
+
catch {
|
|
2927
|
+
// Keep polling while the operator waits for logs to appear.
|
|
2928
|
+
}
|
|
2025
2929
|
}
|
|
2026
|
-
|
|
2027
|
-
|
|
2930
|
+
}
|
|
2931
|
+
finally {
|
|
2932
|
+
process.off("SIGINT", stop);
|
|
2933
|
+
process.off("SIGTERM", stop);
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
async function buildDaemonSharedContext(dataDir, transport, walletService) {
|
|
2937
|
+
const identityMaterial = transport.getIdentityMaterial();
|
|
2938
|
+
const repository = await Protocol.ProtocolRepository.create(dataDir);
|
|
2939
|
+
return {
|
|
2940
|
+
dataDir,
|
|
2941
|
+
identityMaterial,
|
|
2942
|
+
repository,
|
|
2943
|
+
transportStorage: transport.getStorage(),
|
|
2944
|
+
walletService,
|
|
2945
|
+
signer: {
|
|
2946
|
+
did: identityMaterial.agentIdentity.did,
|
|
2947
|
+
publicKey: identityMaterial.transportKeyPair.publicKey,
|
|
2948
|
+
secretKey: identityMaterial.transportKeyPair.secretKey
|
|
2028
2949
|
}
|
|
2029
|
-
|
|
2030
|
-
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
function buildDaemonStatus(dataDir, startedAt, transport, walletStatus) {
|
|
2953
|
+
return {
|
|
2954
|
+
dataDir: normalizeDataDirPath(dataDir),
|
|
2955
|
+
pid: process.pid,
|
|
2956
|
+
startedAt,
|
|
2957
|
+
identity: transport.identity,
|
|
2958
|
+
runtimeEndpoint: getLocalControlEndpoint(dataDir).path,
|
|
2959
|
+
logPath: getDaemonLogPath(dataDir),
|
|
2960
|
+
topics: transport.getJoinedTopics(),
|
|
2961
|
+
connectedPeers: [...transport.getPeerSessions().values()],
|
|
2962
|
+
wallet: walletStatus,
|
|
2963
|
+
healthy: true
|
|
2964
|
+
};
|
|
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
|
+
});
|
|
2031
2980
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
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
|
+
});
|
|
2034
2994
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
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
|
+
});
|
|
2037
3008
|
}
|
|
2038
|
-
|
|
2039
|
-
|
|
3009
|
+
}
|
|
3010
|
+
return candidates;
|
|
3011
|
+
}
|
|
3012
|
+
async function runProtocolDiscoveryWatcher(transport, seenControlLengths, io) {
|
|
3013
|
+
for (const session of transport.getPeerSessions().values()) {
|
|
3014
|
+
const remoteFeed = transport.getRemoteFeed(session.remoteControlFeedKey);
|
|
3015
|
+
if (!remoteFeed) {
|
|
3016
|
+
continue;
|
|
3017
|
+
}
|
|
3018
|
+
await remoteFeed.update({ wait: false });
|
|
3019
|
+
const seenLength = seenControlLengths.get(session.remoteControlFeedKey) ?? 0;
|
|
3020
|
+
if (remoteFeed.length <= seenLength) {
|
|
3021
|
+
continue;
|
|
3022
|
+
}
|
|
3023
|
+
for (let index = seenLength; index < remoteFeed.length; index += 1) {
|
|
3024
|
+
const entry = await remoteFeed.get(index);
|
|
3025
|
+
if (Protocol.isProtocolAnnouncement(entry)) {
|
|
3026
|
+
io.stdout(`${JSON.stringify({ command: "daemon.discovery", remoteDid: session.remoteDid, announcement: entry })}\n`);
|
|
3027
|
+
}
|
|
2040
3028
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
3029
|
+
seenControlLengths.set(session.remoteControlFeedKey, remoteFeed.length);
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
async function waitForProcessSignal() {
|
|
3033
|
+
await Promise.race([
|
|
3034
|
+
once(process, "SIGINT").then(() => undefined),
|
|
3035
|
+
once(process, "SIGTERM").then(() => undefined)
|
|
3036
|
+
]);
|
|
3037
|
+
}
|
|
3038
|
+
async function handleDaemonRun(args, io) {
|
|
3039
|
+
const dataDir = requireOption(args, "data-dir");
|
|
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;
|
|
3047
|
+
let sharedContext;
|
|
3048
|
+
let daemon;
|
|
3049
|
+
let discoveryInterval;
|
|
3050
|
+
let walletPollInterval;
|
|
3051
|
+
let autoSettleInterval;
|
|
3052
|
+
let walletStatus = await walletService.daemonStatus();
|
|
3053
|
+
let walletPollRunning = false;
|
|
3054
|
+
let autoSettleRunning = false;
|
|
3055
|
+
const seenControlLengths = new Map();
|
|
3056
|
+
const startedAt = new Date().toISOString();
|
|
3057
|
+
try {
|
|
3058
|
+
transport = await AgentTransport.create(buildTransportConfigFromArgs(args));
|
|
3059
|
+
await transport.start();
|
|
3060
|
+
const activeTransport = transport;
|
|
3061
|
+
sharedContext = await buildDaemonSharedContext(dataDir, activeTransport, walletService);
|
|
3062
|
+
const topics = buildTopicsFromArgs(args, activeTransport.identity.did);
|
|
3063
|
+
startup.topics.push(...topics);
|
|
3064
|
+
for (const topic of startup.topics) {
|
|
3065
|
+
await activeTransport.joinTopic(topic);
|
|
2043
3066
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
if (commandMatches(args.commandPath, "oracle", "attest"))
|
|
2047
|
-
return await handleOracleAttest(args, io).then(() => 0);
|
|
2048
|
-
if (commandMatches(args.commandPath, "dispute", "open"))
|
|
2049
|
-
return await handleDisputeOpen(args, io).then(() => 0);
|
|
2050
|
-
if (commandMatches(args.commandPath, "dispute", "add-evidence")) {
|
|
2051
|
-
return await handleDisputeAddEvidence(args, io).then(() => 0);
|
|
3067
|
+
for (const did of startup.connectDids) {
|
|
3068
|
+
await activeTransport.connectToDid(did);
|
|
2052
3069
|
}
|
|
2053
|
-
|
|
2054
|
-
|
|
3070
|
+
for (const publicKey of startup.connectNoiseKeys) {
|
|
3071
|
+
await activeTransport.connectToNoiseKey(publicKey);
|
|
2055
3072
|
}
|
|
2056
|
-
if (
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
if (commandMatches(args.commandPath, "space", "add-member")) {
|
|
2063
|
-
return await handleSpaceMembershipAction(args, io, "space-membership.member-added").then(() => 0);
|
|
3073
|
+
if (startup.watchProtocol) {
|
|
3074
|
+
discoveryInterval = setInterval(() => {
|
|
3075
|
+
void runProtocolDiscoveryWatcher(activeTransport, seenControlLengths, io).catch((error) => {
|
|
3076
|
+
io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
3077
|
+
});
|
|
3078
|
+
}, 2_000);
|
|
2064
3079
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
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);
|
|
3119
|
+
daemon = new AgentDaemon({
|
|
3120
|
+
dataDir,
|
|
3121
|
+
statusProvider: () => buildDaemonStatus(dataDir, startedAt, activeTransport, walletStatus),
|
|
3122
|
+
commandHandler: async (request) => {
|
|
3123
|
+
if (!sharedContext) {
|
|
3124
|
+
throw new Error("Daemon context is not available");
|
|
3125
|
+
}
|
|
3126
|
+
const result = await CLI_CONTEXT_STORAGE.run(sharedContext, async () => executeCapturedInDaemon({
|
|
3127
|
+
commandPath: request.commandPath,
|
|
3128
|
+
options: daemonOptionsRecordToMap(request.options)
|
|
3129
|
+
}));
|
|
3130
|
+
walletStatus = await walletService.daemonStatus();
|
|
3131
|
+
return result;
|
|
3132
|
+
},
|
|
3133
|
+
onShutdown: async () => {
|
|
3134
|
+
if (discoveryInterval) {
|
|
3135
|
+
clearInterval(discoveryInterval);
|
|
3136
|
+
discoveryInterval = undefined;
|
|
3137
|
+
}
|
|
3138
|
+
if (walletPollInterval) {
|
|
3139
|
+
clearInterval(walletPollInterval);
|
|
3140
|
+
walletPollInterval = undefined;
|
|
3141
|
+
}
|
|
3142
|
+
if (autoSettleInterval) {
|
|
3143
|
+
clearInterval(autoSettleInterval);
|
|
3144
|
+
autoSettleInterval = undefined;
|
|
3145
|
+
}
|
|
3146
|
+
if (sharedContext) {
|
|
3147
|
+
await sharedContext.repository.close();
|
|
3148
|
+
sharedContext = undefined;
|
|
3149
|
+
}
|
|
3150
|
+
await walletService.close();
|
|
3151
|
+
await activeTransport.stop();
|
|
3152
|
+
}
|
|
3153
|
+
});
|
|
3154
|
+
await daemon.start();
|
|
3155
|
+
io.stdout(`${JSON.stringify({ command: "daemon.run", pid: process.pid, endpoint: getLocalControlEndpoint(dataDir).path })}\n`);
|
|
3156
|
+
await Promise.race([daemon.waitForShutdown(), waitForProcessSignal()]);
|
|
3157
|
+
}
|
|
3158
|
+
finally {
|
|
3159
|
+
if (daemon) {
|
|
3160
|
+
await daemon.stop();
|
|
2067
3161
|
}
|
|
2068
|
-
|
|
2069
|
-
|
|
3162
|
+
else {
|
|
3163
|
+
if (discoveryInterval) {
|
|
3164
|
+
clearInterval(discoveryInterval);
|
|
3165
|
+
}
|
|
3166
|
+
if (walletPollInterval) {
|
|
3167
|
+
clearInterval(walletPollInterval);
|
|
3168
|
+
}
|
|
3169
|
+
if (autoSettleInterval) {
|
|
3170
|
+
clearInterval(autoSettleInterval);
|
|
3171
|
+
}
|
|
3172
|
+
if (sharedContext) {
|
|
3173
|
+
await sharedContext.repository.close();
|
|
3174
|
+
}
|
|
3175
|
+
await walletService.close();
|
|
3176
|
+
if (transport) {
|
|
3177
|
+
await transport.stop();
|
|
3178
|
+
}
|
|
2070
3179
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
async function executeParsedArgs(args, io, options) {
|
|
3183
|
+
if (args.commandPath.length === 0 || hasFlag(args, "help")) {
|
|
3184
|
+
io.stdout(`${usage()}\n`);
|
|
3185
|
+
return 0;
|
|
3186
|
+
}
|
|
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);
|
|
3198
|
+
if (options.allowDaemonProxy) {
|
|
3199
|
+
const dataDir = getDataDirFromArgs(resolvedArgs);
|
|
3200
|
+
if (dataDir) {
|
|
3201
|
+
const activeDaemon = await probeDaemonStatus(dataDir, 1_000);
|
|
3202
|
+
if (activeDaemon) {
|
|
3203
|
+
return proxyParsedArgsToDaemon(withDaemonWalletKeyForwarding(resolvedArgs), io);
|
|
3204
|
+
}
|
|
2073
3205
|
}
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
3206
|
+
}
|
|
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(" ")}`);
|
|
3410
|
+
}
|
|
3411
|
+
export async function runCli(argv, io = DEFAULT_IO) {
|
|
3412
|
+
try {
|
|
3413
|
+
const args = parseArgs(argv);
|
|
3414
|
+
return await executeParsedArgs(args, io, { allowDaemonProxy: true });
|
|
2089
3415
|
}
|
|
2090
3416
|
catch (error) {
|
|
2091
3417
|
io.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
2092
3418
|
return 1;
|
|
2093
3419
|
}
|
|
2094
3420
|
}
|
|
2095
|
-
const executedPath = process.argv[1] ?
|
|
3421
|
+
const executedPath = process.argv[1] ? pathToFileURL(process.argv[1]).href : "";
|
|
2096
3422
|
if (import.meta.url === executedPath) {
|
|
2097
3423
|
void runCli(process.argv.slice(2)).then((exitCode) => {
|
|
2098
3424
|
process.exitCode = exitCode;
|