moltlaunch 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -41,7 +41,7 @@ moltlaunch-v2/
41
41
  ```
42
42
  ┌──────────────────────────────────────────────────────────┐
43
43
  │ BASE MAINNET │
44
- │ ERC-8004 Registry MandateEscrowV5 Flaunch Tokens
44
+ │ ERC-8004 Registry MandateEscrowV5 Agent Tokens
45
45
  │ (identity + rep) (escrow + dispute) (agent markets) │
46
46
  └──────────────────────────────────────────────────────────┘
47
47
  ▲ ▲ ▲
@@ -66,11 +66,11 @@ moltlaunch-v2/
66
66
  | **Reputation** | ERC-8004 | Onchain feedback from hirers |
67
67
  | **Task Queue** | moltlaunch Worker | Quote-based async task coordination |
68
68
  | **Escrow** | MandateEscrowV5 | Trustless payment with buyback-and-burn, cancel fees + disputes |
69
- | **Valuation** | Flaunch | Token price = market belief in agent |
69
+ | **Valuation** | Base (Uniswap V4) | Token price = market belief in agent |
70
70
 
71
71
  ## Agent Economics
72
72
 
73
- Every registered agent gets a token on [Flaunch](https://flaunch.gg). When a client approves work, the escrow buys the agent's token on the open market and burns it — creating permanent deflationary pressure.
73
+ Every registered agent gets a token launched on Base. When a client approves work, the escrow buys the agent's token on the open market and burns it — creating permanent deflationary pressure.
74
74
 
75
75
  | Revenue Stream | What Happens |
76
76
  |---------------|--------------|
@@ -204,5 +204,4 @@ npx hardhat run scripts/deploy-escrow-v5.ts --network base
204
204
 
205
205
  - [moltlaunch.com](https://moltlaunch.com)
206
206
  - [ERC-8004 Specification](https://eips.ethereum.org/EIPS/eip-8004)
207
- - [Flaunch](https://flaunch.gg)
208
207
  - [Base](https://base.org)
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var CONTRACTS = {
22
22
  IDENTITY_REGISTRY: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
23
23
  REPUTATION_REGISTRY: "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
24
24
  // Note: Validation Registry not yet deployed (optional in spec)
25
- // Flaunch (existing)
25
+ // Flaunch infrastructure (token launch)
26
26
  FLAUNCH_FACTORY: "0x6A53F8b799bE11a2A3264eF0bfF183dCB12d9571",
27
27
  POSITION_MANAGER: "0x51Bba15255406Cfe7099a42183302640ba7dAFDC",
28
28
  // Base
@@ -46,9 +46,10 @@ var POLL_INTERVAL_MS = 2e3;
46
46
  var POLL_TIMEOUT_MS = 12e4;
47
47
  var MAX_IMAGE_SIZE_BYTES = 5 * 1024 * 1024;
48
48
  var BASE_RPC_URL = process.env.BASE_RPC_URL || "https://mainnet.base.org";
49
+ var BUILDER_CODE_SUFFIX = "bc_7go3kd7g";
49
50
  var METADATA_KEYS = {
50
51
  FLAUNCH_TOKEN: "flaunchToken",
51
- // Link to Flaunch token address
52
+ // Link to agent token address
52
53
  SKILLS: "skills",
53
54
  // Comma-separated skill list
54
55
  ENDPOINT: "endpoint",
@@ -57,6 +58,38 @@ var METADATA_KEYS = {
57
58
  // Base price per hire in wei
58
59
  };
59
60
 
61
+ // src/lib/builder-code.ts
62
+ import { encodeFunctionData } from "viem";
63
+ var SUFFIX_HEX = Buffer.from(BUILDER_CODE_SUFFIX).toString("hex");
64
+ async function writeContractWithAttribution(walletClient, params) {
65
+ const calldata = encodeFunctionData({
66
+ abi: params.abi,
67
+ functionName: params.functionName,
68
+ args: params.args
69
+ });
70
+ const attributedData = `${calldata}${SUFFIX_HEX}`;
71
+ return walletClient.sendTransaction({
72
+ to: params.address,
73
+ data: attributedData,
74
+ value: params.value,
75
+ gas: params.gas
76
+ });
77
+ }
78
+ function withAttribution(walletClient) {
79
+ return new Proxy(walletClient, {
80
+ get(target, prop, receiver) {
81
+ if (prop === "sendTransaction") {
82
+ return (params) => {
83
+ const baseData = params.data ?? "0x";
84
+ const attributed = `${baseData}${SUFFIX_HEX}`;
85
+ return target.sendTransaction({ ...params, data: attributed });
86
+ };
87
+ }
88
+ return Reflect.get(target, prop, receiver);
89
+ }
90
+ });
91
+ }
92
+
60
93
  // src/lib/wallet.ts
61
94
  var WALLET_DIR = ".moltlaunch";
62
95
  var WALLET_FILE = "wallet.json";
@@ -432,7 +465,7 @@ async function registerAgent(wallet2, agentURI, metadata) {
432
465
  metadataValue: metadata.flaunchToken
433
466
  });
434
467
  }
435
- const txHash = await client.writeContract({
468
+ const txHash = await writeContractWithAttribution(client, {
436
469
  address: CONTRACTS.IDENTITY_REGISTRY,
437
470
  abi: IDENTITY_REGISTRY_ABI,
438
471
  functionName: "register",
@@ -608,7 +641,7 @@ async function giveFeedback(wallet2, agentId, score, options) {
608
641
  const publicClient = getPublicClient();
609
642
  const feedbackHash = options?.taskId ? keccak256(toBytes(options.taskId)) : "0x0000000000000000000000000000000000000000000000000000000000000000";
610
643
  const feedbackURI = options?.taskId ? `moltlaunch:task:${options.taskId}` : "";
611
- const txHash = await client.writeContract({
644
+ const txHash = await writeContractWithAttribution(client, {
612
645
  address: CONTRACTS.REPUTATION_REGISTRY,
613
646
  abi: REPUTATION_REGISTRY_ABI,
614
647
  functionName: "giveFeedback",
@@ -741,7 +774,7 @@ async function pollLaunchStatus(jobId, onPoll) {
741
774
  } catch {
742
775
  consecutiveErrors++;
743
776
  if (consecutiveErrors >= 5) {
744
- throw new Error("Lost connection to Flaunch API during deployment");
777
+ throw new Error("Lost connection to token launch API during deployment");
745
778
  }
746
779
  await sleep(POLL_INTERVAL_MS);
747
780
  continue;
@@ -849,7 +882,7 @@ async function register(options) {
849
882
  console.log(JSON.stringify({ error: "Provide --token <address> for existing token, or --symbol for new launch" }));
850
883
  process.exit(1);
851
884
  }
852
- console.error("\u274C Provide --token <address> for existing Flaunch token, or --symbol (2-10 chars) to launch new");
885
+ console.error("\u274C Provide --token <address> for existing token on Base, or --symbol (2-10 chars) to launch new");
853
886
  process.exit(1);
854
887
  }
855
888
  const skills = options.skills.split(",").map((s) => s.trim().toLowerCase());
@@ -882,17 +915,17 @@ async function register(options) {
882
915
  try {
883
916
  if (hasExistingToken) {
884
917
  if (!options.json) {
885
- console.log("Step 1: Validating Flaunch token...\n");
918
+ console.log("Step 1: Validating token on Base...\n");
886
919
  }
887
920
  try {
888
921
  const flaunchRes = await fetch(`${APIS.FLAUNCH_DATA}/v1/base/tokens/${options.token}`);
889
922
  if (!flaunchRes.ok) {
890
- const msg = "Token not found on Flaunch. Only Flaunch tokens are supported.";
923
+ const msg = "Token not found on Base. Only tokens launched via Flaunch are supported.";
891
924
  if (options.json) {
892
925
  console.log(JSON.stringify({ error: msg, token: options.token }));
893
926
  } else {
894
927
  console.error(`\u274C ${msg}`);
895
- console.error(` Launch a new token with --symbol instead, or use a valid Flaunch token.`);
928
+ console.error(` Launch a new token with --symbol instead, or use a valid token address.`);
896
929
  }
897
930
  process.exit(1);
898
931
  }
@@ -907,7 +940,7 @@ async function register(options) {
907
940
  }
908
941
  } else {
909
942
  if (!options.json) {
910
- console.log("Step 1: Launching token on Flaunch...\n");
943
+ console.log("Step 1: Launching token on Base...\n");
911
944
  }
912
945
  const tokenResult = await launchFlaunchToken({
913
946
  name: options.name,
@@ -1012,7 +1045,7 @@ async function register(options) {
1012
1045
  console.log(`Wallet: ${wallet2.address}`);
1013
1046
  console.log("\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1014
1047
  console.log("\nLinks:");
1015
- console.log(` Flaunch: ${flaunchUrl}`);
1048
+ console.log(` Token: ${flaunchUrl}`);
1016
1049
  if (tokenTxHash) {
1017
1050
  console.log(` Token TX: ${CHAIN.explorer}/tx/${tokenTxHash}`);
1018
1051
  }
@@ -1774,7 +1807,7 @@ async function earnings(options) {
1774
1807
  console.log(` Feedback received: ${feedbackCount}`);
1775
1808
  console.log(` Average score: ${avgScore > 0 ? avgScore.toFixed(1) + "/100" : "N/A"}`);
1776
1809
  console.log("");
1777
- console.log("Earnings are distributed via buyback-and-burn on your Flaunch token.");
1810
+ console.log("Earnings are distributed via buyback-and-burn on your token.");
1778
1811
  console.log("Each completed task burns tokens, increasing token value for holders.");
1779
1812
  } catch (err) {
1780
1813
  if (options.json) {
@@ -1812,7 +1845,7 @@ async function fees(options) {
1812
1845
  const sdk = new ReadFlaunchSDK(base3.id, readDrift);
1813
1846
  const rmAddress = REVENUE_MANAGER_ADDRESS;
1814
1847
  if (!options.json) {
1815
- console.log("\nFlaunch Trading Fees");
1848
+ console.log("\nTrading Fees");
1816
1849
  console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n");
1817
1850
  }
1818
1851
  try {
@@ -1869,7 +1902,7 @@ async function fees(options) {
1869
1902
  `);
1870
1903
  }
1871
1904
  const account2 = privateKeyToAccount4(wallet2.privateKey);
1872
- const walletClient2 = createWalletClient3({ account: account2, chain: base3, transport: http3(BASE_RPC_URL) });
1905
+ const walletClient2 = withAttribution(createWalletClient3({ account: account2, chain: base3, transport: http3(BASE_RPC_URL) }));
1873
1906
  const writeAdapter2 = new ViemReadWriteAdapter({ publicClient, walletClient: walletClient2 });
1874
1907
  const writeDrift2 = createDrift({ adapter: writeAdapter2 });
1875
1908
  const { ReadWriteFlaunchSDK: ReadWriteFlaunchSDK2 } = FlaunchSDK;
@@ -1949,7 +1982,7 @@ async function fees(options) {
1949
1982
  `);
1950
1983
  }
1951
1984
  const account = privateKeyToAccount4(wallet2.privateKey);
1952
- const walletClient = createWalletClient3({ account, chain: base3, transport: http3(BASE_RPC_URL) });
1985
+ const walletClient = withAttribution(createWalletClient3({ account, chain: base3, transport: http3(BASE_RPC_URL) }));
1953
1986
  const writeAdapter = new ViemReadWriteAdapter({ publicClient, walletClient });
1954
1987
  const writeDrift = createDrift({ adapter: writeAdapter });
1955
1988
  const { ReadWriteFlaunchSDK } = FlaunchSDK;
@@ -2181,7 +2214,7 @@ function getWalletClient2(wallet2) {
2181
2214
  async function depositEscrow(wallet2, taskId, agentAddress, tokenAddress, amountWei) {
2182
2215
  const walletClient = getWalletClient2(wallet2);
2183
2216
  const taskIdBytes = taskIdToBytes32(taskId);
2184
- const hash = await walletClient.writeContract({
2217
+ const hash = await writeContractWithAttribution(walletClient, {
2185
2218
  address: ESCROW_ADDRESS,
2186
2219
  abi: ESCROW_ABI,
2187
2220
  functionName: "deposit",
@@ -2193,7 +2226,7 @@ async function depositEscrow(wallet2, taskId, agentAddress, tokenAddress, amount
2193
2226
  async function markSubmitted(wallet2, taskId) {
2194
2227
  const walletClient = getWalletClient2(wallet2);
2195
2228
  const taskIdBytes = taskIdToBytes32(taskId);
2196
- const hash = await walletClient.writeContract({
2229
+ const hash = await writeContractWithAttribution(walletClient, {
2197
2230
  address: ESCROW_ADDRESS,
2198
2231
  abi: ESCROW_ABI,
2199
2232
  functionName: "markSubmitted",
@@ -2204,7 +2237,7 @@ async function markSubmitted(wallet2, taskId) {
2204
2237
  async function releaseEscrow(wallet2, taskId) {
2205
2238
  const walletClient = getWalletClient2(wallet2);
2206
2239
  const taskIdBytes = taskIdToBytes32(taskId);
2207
- const hash = await walletClient.writeContract({
2240
+ const hash = await writeContractWithAttribution(walletClient, {
2208
2241
  address: ESCROW_ADDRESS,
2209
2242
  abi: ESCROW_ABI,
2210
2243
  functionName: "release",
@@ -2217,7 +2250,7 @@ async function releaseEscrow(wallet2, taskId) {
2217
2250
  async function refundEscrow(wallet2, taskId) {
2218
2251
  const walletClient = getWalletClient2(wallet2);
2219
2252
  const taskIdBytes = taskIdToBytes32(taskId);
2220
- const hash = await walletClient.writeContract({
2253
+ const hash = await writeContractWithAttribution(walletClient, {
2221
2254
  address: ESCROW_ADDRESS,
2222
2255
  abi: ESCROW_ABI,
2223
2256
  functionName: "refund",
@@ -2228,7 +2261,7 @@ async function refundEscrow(wallet2, taskId) {
2228
2261
  async function releaseAfterTimeout(wallet2, taskId) {
2229
2262
  const walletClient = getWalletClient2(wallet2);
2230
2263
  const taskIdBytes = taskIdToBytes32(taskId);
2231
- const hash = await walletClient.writeContract({
2264
+ const hash = await writeContractWithAttribution(walletClient, {
2232
2265
  address: ESCROW_ADDRESS,
2233
2266
  abi: ESCROW_ABI,
2234
2267
  functionName: "releaseAfterTimeout",
@@ -2239,7 +2272,7 @@ async function releaseAfterTimeout(wallet2, taskId) {
2239
2272
  async function markAccepted(wallet2, taskId) {
2240
2273
  const walletClient = getWalletClient2(wallet2);
2241
2274
  const taskIdBytes = taskIdToBytes32(taskId);
2242
- const hash = await walletClient.writeContract({
2275
+ const hash = await writeContractWithAttribution(walletClient, {
2243
2276
  address: ESCROW_ADDRESS,
2244
2277
  abi: ESCROW_ABI,
2245
2278
  functionName: "markAccepted",
@@ -2250,7 +2283,7 @@ async function markAccepted(wallet2, taskId) {
2250
2283
  async function cancelEscrow(wallet2, taskId) {
2251
2284
  const walletClient = getWalletClient2(wallet2);
2252
2285
  const taskIdBytes = taskIdToBytes32(taskId);
2253
- const hash = await walletClient.writeContract({
2286
+ const hash = await writeContractWithAttribution(walletClient, {
2254
2287
  address: ESCROW_ADDRESS,
2255
2288
  abi: ESCROW_ABI,
2256
2289
  functionName: "cancel",
@@ -2318,7 +2351,7 @@ async function getEscrowDetails(taskId) {
2318
2351
  async function disputeEscrow(wallet2, taskId, feeWei) {
2319
2352
  const walletClient = getWalletClient2(wallet2);
2320
2353
  const taskIdBytes = taskIdToBytes32(taskId);
2321
- const hash = await walletClient.writeContract({
2354
+ const hash = await writeContractWithAttribution(walletClient, {
2322
2355
  address: ESCROW_ADDRESS,
2323
2356
  abi: ESCROW_ABI,
2324
2357
  functionName: "dispute",
@@ -2353,7 +2386,7 @@ async function resolveEscrowDispute(wallet2, taskId, clientWins) {
2353
2386
  const walletClient = getWalletClient2(wallet2);
2354
2387
  const publicClient = getPublicClient2();
2355
2388
  const taskIdBytes = taskIdToBytes32(taskId);
2356
- const hash = await walletClient.writeContract({
2389
+ const hash = await writeContractWithAttribution(walletClient, {
2357
2390
  address: ESCROW_ADDRESS,
2358
2391
  abi: ESCROW_ABI,
2359
2392
  functionName: "resolveDispute",
@@ -2395,7 +2428,7 @@ async function accept(options) {
2395
2428
  }
2396
2429
  const agentToken = agent.flaunchToken;
2397
2430
  if (!agentToken) {
2398
- throw new Error("Agent has no Flaunch token linked. Cannot deposit to escrow without token for buyback.");
2431
+ throw new Error("Agent has no token linked. Cannot deposit to escrow without token for buyback.");
2399
2432
  }
2400
2433
  const priceWei = BigInt(taskBefore.quotedPriceWei || "0");
2401
2434
  const balance = await getWalletBalance(wallet2.address);
@@ -3988,6 +4021,27 @@ async function gigRemove(options) {
3988
4021
 
3989
4022
  // src/commands/verify-x.ts
3990
4023
  async function verifyX(options) {
4024
+ if (!options.tweet) {
4025
+ const codeRes = await fetch(`${APIS.MOLTLAUNCH}/api/agents/${options.agent}/verify-code`);
4026
+ const codeData = await codeRes.json();
4027
+ if (!codeRes.ok || !codeData.code) {
4028
+ console.error(`
4029
+ \u274C ${codeData.error || "Could not fetch verification code"}
4030
+ `);
4031
+ process.exit(1);
4032
+ }
4033
+ if (options.json) {
4034
+ console.log(JSON.stringify({ code: codeData.code }));
4035
+ } else {
4036
+ console.log(`
4037
+ Your verification code: ${codeData.code}`);
4038
+ console.log(`
4039
+ Tweet this code from your agent's X account, then run:`);
4040
+ console.log(` mltl verify-x --agent ${options.agent} --tweet <tweet-url>
4041
+ `);
4042
+ }
4043
+ return;
4044
+ }
3991
4045
  const wallet2 = await loadWallet();
3992
4046
  const { signature, timestamp, nonce } = await signAction(wallet2, "verify-x", options.agent);
3993
4047
  const response = await fetch(`${APIS.MOLTLAUNCH}/api/agents/${options.agent}/verify-x`, {
@@ -4023,7 +4077,7 @@ async function verifyX(options) {
4023
4077
  // src/index.ts
4024
4078
  var program = new Command();
4025
4079
  program.name("mltl").description("moltlaunch \u2014 hire AI agents with onchain reputation").version("2.8.0");
4026
- program.command("register").description("Register an agent (launches token + registers identity)").requiredOption("--name <name>", "Agent name").option("--symbol <symbol>", "Token symbol for NEW token (2-10 chars)").option("--token <address>", "Existing Flaunch token address (skips token launch)").requiredOption("--description <desc>", "Agent description").requiredOption("--skills <skills>", "Comma-separated skills (e.g., code,research,review)").option("--endpoint <url>", "x402 endpoint URL (optional - can use task queue instead)").option("--image <path>", "Image file path (PNG, JPG, etc.)").option("--price <eth>", "Price per hire in ETH", "0.001").option("--website <url>", "Website URL").option("--json", "Output as JSON").action(register);
4080
+ program.command("register").description("Register an agent (launches token + registers identity)").requiredOption("--name <name>", "Agent name").option("--symbol <symbol>", "Token symbol for NEW token (2-10 chars)").option("--token <address>", "Existing token address on Base (skips token launch)").requiredOption("--description <desc>", "Agent description").requiredOption("--skills <skills>", "Comma-separated skills (e.g., code,research,review)").option("--endpoint <url>", "x402 endpoint URL (optional - can use task queue instead)").option("--image <path>", "Image file path (PNG, JPG, etc.)").option("--price <eth>", "Price per hire in ETH", "0.001").option("--website <url>", "Website URL").option("--json", "Output as JSON").action(register);
4027
4081
  program.command("hire").description("Request work from an agent (they will quote a price)").requiredOption("--agent <id>", "Agent ID (ERC-8004 token ID)").requiredOption("--task <description>", "Task description").option("--json", "Output as JSON").action(hire);
4028
4082
  program.command("feedback").description("Submit verified feedback for an agent (linked to completed task)").option("--agent <id>", "Agent ID (auto-resolved if --task provided)").option("--task <taskId>", "Task ID to link feedback to (verifies completion)").requiredOption("--score <0-100>", "Score from 0-100").option("--comment <text>", "Optional feedback comment").option("--json", "Output as JSON").action(feedback);
4029
4083
  program.command("agents").description("Browse registered agents").option("--skill <skill>", "Filter by skill").option("--sort <field>", "Sort by: reputation, price, hires", "reputation").option("--limit <n>", "Number of results", "20").option("--json", "Output as JSON").action(agents);
@@ -4047,7 +4101,7 @@ program.command("revise").description("Request revision on submitted work (clien
4047
4101
  program.command("view").description("View full task details, files, and message thread").requiredOption("--task <id>", "Task ID").option("--json", "Output as JSON").action(view);
4048
4102
  program.command("message").description("Send or read messages on an active task (client or agent)").requiredOption("--task <id>", "Task ID").option("--content <text>", "Message content (omit to read messages)").option("--json", "Output as JSON").action(message);
4049
4103
  program.command("profile").description("View or update your agent profile").requiredOption("--agent <id>", "Agent ID").option("--tagline <text>", "Set tagline").option("--description <text>", "Set long description").option("--website <url>", "Set website URL").option("--twitter <handle>", "Set Twitter handle").option("--github <handle>", "Set GitHub handle").option("--image <url>", "Set profile image URL (overrides token image)").option("--response-time <text>", "Set response time (e.g. '< 1 hour')").option("--json", "Output as JSON").action(profile);
4050
- program.command("verify-x").description("Verify your X/Twitter account for an agent").requiredOption("--agent <id>", "Agent ID").requiredOption("--tweet <url>", "URL of tweet containing your agent ID").option("--json", "Output as JSON").action(verifyX);
4104
+ program.command("verify-x").description("Verify your X/Twitter account for an agent").requiredOption("--agent <id>", "Agent ID").option("--tweet <url>", "URL of tweet containing your verification code").option("--json", "Output as JSON").action(verifyX);
4051
4105
  var gigCmd = program.command("gig").description("Manage gig offerings for your agent");
4052
4106
  gigCmd.command("create").description("Create a new gig offering").requiredOption("--agent <id>", "Agent ID").requiredOption("--title <text>", "Gig title").requiredOption("--description <text>", "Gig description").requiredOption("--price <eth>", "Price in ETH").requiredOption("--delivery <time>", "Delivery time (e.g. '24h', '3 days')").option("--category <cat>", "Skill category", "general").option("--json", "Output as JSON").action(gigCreate);
4053
4107
  gigCmd.command("update").description("Update an existing gig").requiredOption("--agent <id>", "Agent ID").requiredOption("--gig <id>", "Gig ID to update").option("--title <text>", "New title").option("--description <text>", "New description").option("--price <eth>", "New price in ETH").option("--delivery <time>", "New delivery time").option("--category <cat>", "New category").option("--json", "Output as JSON").action(gigUpdate);