@lucid-agents/taskmarket 1.7.3 → 1.9.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/dist/index.js +1104 -445
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
9
|
+
import { Command as Command68 } from "commander";
|
|
10
10
|
import { createRequire } from "module";
|
|
11
11
|
|
|
12
12
|
// src/commands/init.ts
|
|
@@ -4271,7 +4271,10 @@ var TaskCreateSchema = external_exports.object({
|
|
|
4271
4271
|
taskVisibility: TaskVisibility.optional().default("public"),
|
|
4272
4272
|
submissionVisibility: SubmissionVisibility.optional().default("public"),
|
|
4273
4273
|
stakeRequired: external_exports.boolean().optional().default(false),
|
|
4274
|
-
|
|
4274
|
+
// Integral: this is client-supplied and lands in a `uint16` on chain, where a fraction is
|
|
4275
|
+
// not representable at all. Without `.int()` a 12.5 was accepted here and silently became
|
|
4276
|
+
// something else by the time it reached the contract (ADR-0069).
|
|
4277
|
+
stakeBps: external_exports.number().int().min(0).max(1e4).optional().default(0),
|
|
4275
4278
|
pitchDeadline: external_exports.number().positive().optional(),
|
|
4276
4279
|
bidDeadline: external_exports.number().positive().optional(),
|
|
4277
4280
|
maxPrice: PositiveUsdcBaseUnitsSchema.optional(),
|
|
@@ -4283,7 +4286,8 @@ var TaskCreateSchema = external_exports.object({
|
|
|
4283
4286
|
hookContract: external_exports.string().optional(),
|
|
4284
4287
|
hookData: external_exports.string().regex(/^0x(?:[0-9a-fA-F]{2})*$/, "hookData must be hex-encoded bytes (0x followed by pairs of hex digits)").optional(),
|
|
4285
4288
|
evaluator: external_exports.string().optional(),
|
|
4286
|
-
|
|
4289
|
+
// Integral for the same reason as `stakeBps` above: client-supplied, `uint16` on chain.
|
|
4290
|
+
evaluatorFeeBps: external_exports.number().int().min(0).max(1e4).optional(),
|
|
4287
4291
|
evaluationWindowHours: external_exports.number().positive().optional(),
|
|
4288
4292
|
appealWindowHours: external_exports.number().positive().optional(),
|
|
4289
4293
|
disputeResolver: external_exports.string().optional(),
|
|
@@ -4399,7 +4403,9 @@ var TaskResponseSchema = external_exports.object({
|
|
|
4399
4403
|
// never the hash itself, and never returned for a non-private task.
|
|
4400
4404
|
hasAccessPassword: external_exports.boolean().optional(),
|
|
4401
4405
|
stakeRequired: external_exports.boolean(),
|
|
4402
|
-
|
|
4406
|
+
// Same shape the request side already enforces (ADR-0069): a `uint16` fraction of the escrow,
|
|
4407
|
+
// so the response cannot describe a stake the contract could not have held.
|
|
4408
|
+
stakeBps: external_exports.number().int().min(0).max(1e4),
|
|
4403
4409
|
pitchDeadline: external_exports.string().nullable(),
|
|
4404
4410
|
bidDeadline: external_exports.string().nullable(),
|
|
4405
4411
|
maxPrice: external_exports.string().nullable(),
|
|
@@ -4407,7 +4413,10 @@ var TaskResponseSchema = external_exports.object({
|
|
|
4407
4413
|
metricTarget: external_exports.string().nullable(),
|
|
4408
4414
|
claimedBy: external_exports.string().nullable(),
|
|
4409
4415
|
claimedAt: external_exports.string().nullable(),
|
|
4410
|
-
|
|
4416
|
+
// Required, never optional: this is the multiplier every net-reward figure a client shows is
|
|
4417
|
+
// derived from, and the column behind it has been `NOT NULL` since the first migration. A
|
|
4418
|
+
// reader that had to supply its own value on absence would be guessing at money.
|
|
4419
|
+
platformFeeBps: external_exports.number().int().min(0).max(1e4),
|
|
4411
4420
|
submissionCount: external_exports.number().optional().default(0),
|
|
4412
4421
|
awardCount: external_exports.number().int().nonnegative().optional(),
|
|
4413
4422
|
// Read-time projection of the rank-1 task_awards row -- not a separately
|
|
@@ -4433,7 +4442,9 @@ var TaskResponseSchema = external_exports.object({
|
|
|
4433
4442
|
hookContract: external_exports.string().nullable().optional(),
|
|
4434
4443
|
evaluator: external_exports.string().nullable().optional(),
|
|
4435
4444
|
evaluatorStake: external_exports.string().nullable().optional(),
|
|
4436
|
-
|
|
4445
|
+
// Genuinely absent when no evaluator is configured -- unlike `platformFeeBps`, null here means
|
|
4446
|
+
// "no evaluator fee", which is the same thing as zero, so a reader coalescing to 0 is right.
|
|
4447
|
+
evaluatorFeeBps: external_exports.number().int().min(0).max(1e4).nullable().optional(),
|
|
4437
4448
|
evaluationWindow: external_exports.number().nullable().optional(),
|
|
4438
4449
|
appealWindow: external_exports.number().nullable().optional(),
|
|
4439
4450
|
disputeResolver: external_exports.string().nullable().optional(),
|
|
@@ -4488,11 +4499,66 @@ var TaskInboxResponseSchema = external_exports.object({
|
|
|
4488
4499
|
// than a separate notification-center feature.
|
|
4489
4500
|
invitedPrivateTasks: external_exports.array(TaskResponseSchema).optional().default([])
|
|
4490
4501
|
});
|
|
4502
|
+
var TaskActionIntent = external_exports.enum([
|
|
4503
|
+
"review_work",
|
|
4504
|
+
"select_worker",
|
|
4505
|
+
"submit_work",
|
|
4506
|
+
"settle_expired",
|
|
4507
|
+
"evaluate_work",
|
|
4508
|
+
"appeal_verdict",
|
|
4509
|
+
"resolve_dispute",
|
|
4510
|
+
"finalize_verdict",
|
|
4511
|
+
"rate_workers",
|
|
4512
|
+
"select_auction_winner"
|
|
4513
|
+
]);
|
|
4514
|
+
var TaskActionPriority = external_exports.enum(["urgent", "required", "follow_up"]);
|
|
4515
|
+
var TaskActionProgressSchema = external_exports.object({
|
|
4516
|
+
completed: external_exports.number().int().nonnegative(),
|
|
4517
|
+
total: external_exports.number().int().positive()
|
|
4518
|
+
}).refine(({ completed, total }) => completed <= total, {
|
|
4519
|
+
message: "Completed progress cannot exceed the target total",
|
|
4520
|
+
path: ["completed"]
|
|
4521
|
+
});
|
|
4522
|
+
var TaskActionQueueItemSchema = external_exports.object({
|
|
4523
|
+
id: external_exports.string(),
|
|
4524
|
+
task: TaskResponseSchema,
|
|
4525
|
+
role: PendingActionSchema.shape.role,
|
|
4526
|
+
intent: TaskActionIntent,
|
|
4527
|
+
actions: PendingActionSchema.array().min(1),
|
|
4528
|
+
priority: TaskActionPriority,
|
|
4529
|
+
dueAt: external_exports.string().nullable(),
|
|
4530
|
+
progress: TaskActionProgressSchema.nullable().optional()
|
|
4531
|
+
});
|
|
4532
|
+
var TaskActionWaitingReason = external_exports.enum([
|
|
4533
|
+
"waiting_for_submissions",
|
|
4534
|
+
"waiting_for_worker",
|
|
4535
|
+
"waiting_for_review",
|
|
4536
|
+
"waiting_for_evaluator",
|
|
4537
|
+
"waiting_for_appeal_window",
|
|
4538
|
+
"waiting_for_settlement"
|
|
4539
|
+
]);
|
|
4540
|
+
var TaskActionWaitingItemSchema = external_exports.object({
|
|
4541
|
+
id: external_exports.string(),
|
|
4542
|
+
task: TaskResponseSchema,
|
|
4543
|
+
role: PendingActionSchema.shape.role,
|
|
4544
|
+
reason: TaskActionWaitingReason,
|
|
4545
|
+
dueAt: external_exports.string().nullable()
|
|
4546
|
+
});
|
|
4547
|
+
var TaskActionQueueResponseSchema = external_exports.object({
|
|
4548
|
+
items: TaskActionQueueItemSchema.array(),
|
|
4549
|
+
total: external_exports.number().int().nonnegative(),
|
|
4550
|
+
urgentTotal: external_exports.number().int().nonnegative(),
|
|
4551
|
+
waiting: TaskActionWaitingItemSchema.array()
|
|
4552
|
+
});
|
|
4491
4553
|
var TaskDetailResponseSchema = TaskResponseSchema.extend({
|
|
4492
4554
|
pendingActions: PendingActionSchema.array(),
|
|
4493
4555
|
awards: TaskAwardSchema.array().optional(),
|
|
4494
4556
|
dreamsPerUsdc: external_exports.string().optional(),
|
|
4495
|
-
|
|
4557
|
+
// Optional as a set, not individually: the router emits `dreamsPerUsdc`, `bonusBps` and every
|
|
4558
|
+
// `estimated*` field together or not at all, depending on whether the task carries the DREAMS
|
|
4559
|
+
// hook. No client multiplies this by a split of its own -- the worker/requester estimates are
|
|
4560
|
+
// computed server-side -- so the absent case needs no fallback multiplier anywhere.
|
|
4561
|
+
bonusBps: external_exports.number().int().min(0).max(1e4).optional(),
|
|
4496
4562
|
estimatedUsdBonusValue: external_exports.string().optional(),
|
|
4497
4563
|
estimatedWorkerUsdBonusValue: external_exports.string().optional(),
|
|
4498
4564
|
estimatedRequesterUsdBonusValue: external_exports.string().optional(),
|
|
@@ -4506,6 +4572,16 @@ var RejectSubmissionInputSchema = external_exports.object({
|
|
|
4506
4572
|
taskId: external_exports.string(),
|
|
4507
4573
|
worker: external_exports.string()
|
|
4508
4574
|
});
|
|
4575
|
+
var AssignEvaluatorInputSchema = external_exports.object({
|
|
4576
|
+
taskId: external_exports.string(),
|
|
4577
|
+
evaluator: external_exports.string(),
|
|
4578
|
+
// Integral: same field, same `uint16`, and the two request-side schemas must not disagree
|
|
4579
|
+
// about what a caller may send.
|
|
4580
|
+
evaluatorFeeBps: external_exports.number().int().min(0).max(1e4).optional(),
|
|
4581
|
+
evaluationWindowHours: external_exports.number().positive().optional(),
|
|
4582
|
+
appealWindowHours: external_exports.number().positive().optional(),
|
|
4583
|
+
disputeResolver: external_exports.string().optional()
|
|
4584
|
+
});
|
|
4509
4585
|
var RefundExpiredInputSchema = external_exports.object({
|
|
4510
4586
|
taskId: external_exports.string()
|
|
4511
4587
|
});
|
|
@@ -4714,7 +4790,47 @@ var FeedbackSchema = external_exports.object({
|
|
|
4714
4790
|
var HealthResponseSchema = external_exports.object({
|
|
4715
4791
|
status: external_exports.literal("ok"),
|
|
4716
4792
|
timestamp: external_exports.string(),
|
|
4717
|
-
environment: external_exports.string()
|
|
4793
|
+
environment: external_exports.string(),
|
|
4794
|
+
/**
|
|
4795
|
+
* The submission limits this process is actually enforcing, after any environment
|
|
4796
|
+
* override. Reported because a limit a caller cannot observe is a limit a test can only
|
|
4797
|
+
* guess at: smoke-rate-limit.ts asserted against its own copy of the ceiling and had no
|
|
4798
|
+
* way to notice the backend was started with a different one, so it failed with a
|
|
4799
|
+
* confusing boundary error instead of saying the two disagreed.
|
|
4800
|
+
*/
|
|
4801
|
+
limits: external_exports.object({
|
|
4802
|
+
freeSubmissionAllowance: external_exports.number().int().positive(),
|
|
4803
|
+
hardSubmissionCeiling: external_exports.number().int().positive()
|
|
4804
|
+
}),
|
|
4805
|
+
/**
|
|
4806
|
+
* Relayed-intent facts a caller can poll for, in the same spirit as `limits`: a queryable
|
|
4807
|
+
* number, not an alert (ADR-0053).
|
|
4808
|
+
*
|
|
4809
|
+
* Optional because health is what tells you the service is up. If no count is available the
|
|
4810
|
+
* object is omitted rather than reported as a sentinel -- absence under an optional field is
|
|
4811
|
+
* unambiguous, whereas a `-1` or an `"unknown"` string is a value every consumer has to learn
|
|
4812
|
+
* not to plot, and it is also exactly how this endpoint already reads to a caller running
|
|
4813
|
+
* against a build from before the field existed.
|
|
4814
|
+
*
|
|
4815
|
+
* Absent means "no answer here", and it covers a process whose sweep has not run yet as well
|
|
4816
|
+
* as one that does not sweep at all. It never means zero.
|
|
4817
|
+
*/
|
|
4818
|
+
intents: external_exports.object({
|
|
4819
|
+
/**
|
|
4820
|
+
* When the count below was computed, not when it was served.
|
|
4821
|
+
*
|
|
4822
|
+
* These numbers come from a periodic sweep rather than from the request, so the response
|
|
4823
|
+
* is a cache and says so. Without this a consumer cannot tell a live zero from a zero
|
|
4824
|
+
* left behind by a worker that stopped running -- and the second is the more urgent of
|
|
4825
|
+
* the two, because a sweep that is not running is a queue nothing is draining.
|
|
4826
|
+
*/
|
|
4827
|
+
measuredAt: external_exports.string(),
|
|
4828
|
+
/**
|
|
4829
|
+
* Intents that are neither completed nor failed and have not been touched for well past
|
|
4830
|
+
* normal settlement. A count only -- the endpoint is public.
|
|
4831
|
+
*/
|
|
4832
|
+
staleNonTerminal: external_exports.number().int().nonnegative()
|
|
4833
|
+
}).optional()
|
|
4718
4834
|
});
|
|
4719
4835
|
|
|
4720
4836
|
// ../../packages/shared/dist/schemas/pitch.schemas.js
|
|
@@ -4873,8 +4989,12 @@ var WithdrawDreamsOutputSchema = external_exports.object({
|
|
|
4873
4989
|
});
|
|
4874
4990
|
var ExchangeRateOutputSchema = external_exports.object({
|
|
4875
4991
|
dreamsPerUsdc: external_exports.string(),
|
|
4876
|
-
|
|
4877
|
-
|
|
4992
|
+
// Both are read straight off `TaskTokenRewardHook`, which rejects either above 10000
|
|
4993
|
+
// (`InvalidBps`), and both are required here rather than optional: a client that had to
|
|
4994
|
+
// default the split would default it to the whole reward, and one that had to default the
|
|
4995
|
+
// bonus would report no bonus at all. Neither is a fact this endpoint may leave to the reader.
|
|
4996
|
+
workerSplitBps: external_exports.number().int().min(0).max(1e4),
|
|
4997
|
+
bonusBps: external_exports.number().int().min(0).max(1e4)
|
|
4878
4998
|
});
|
|
4879
4999
|
|
|
4880
5000
|
// ../../packages/shared/dist/schemas/xmtp.schemas.js
|
|
@@ -5204,6 +5324,225 @@ var AllowedViewerResponseSchema = external_exports.object({
|
|
|
5204
5324
|
});
|
|
5205
5325
|
var ListAllowedViewersResponseSchema = external_exports.array(AllowedViewerResponseSchema);
|
|
5206
5326
|
|
|
5327
|
+
// ../../packages/shared/dist/schemas/api-error.schemas.js
|
|
5328
|
+
var API_ERROR_REASONS = [
|
|
5329
|
+
/**
|
|
5330
|
+
* No terminal outcome has been established. The write is owned by the settlement path and
|
|
5331
|
+
* may still succeed. **This is not a failure and not a success**, and it makes no claim about
|
|
5332
|
+
* whether the payment moved (ADR-0049 point 3). Never resubmit; poll `intents.get`.
|
|
5333
|
+
*/
|
|
5334
|
+
"intent_in_flight",
|
|
5335
|
+
/**
|
|
5336
|
+
* A write carrying this idempotency key already exists, and this request neither charged the
|
|
5337
|
+
* caller nor submitted anything a second time. Idempotency working, reported as a conflict --
|
|
5338
|
+
* see ADR-0058 for why this is not a 200 carrying the original result.
|
|
5339
|
+
*/
|
|
5340
|
+
"idempotency_key_reused",
|
|
5341
|
+
/**
|
|
5342
|
+
* The request arrived with no `X-Taskmarket-Idempotency-Key` header (the value of
|
|
5343
|
+
* `IDEMPOTENCY_KEY_HEADER`), or one that is not a UUID. Rejected before the 402 challenge,
|
|
5344
|
+
* so nothing was charged (ADR-0052).
|
|
5345
|
+
*/
|
|
5346
|
+
"idempotency_key_required",
|
|
5347
|
+
/**
|
|
5348
|
+
* The key is already bound to a *different* operation, or to a different caller's write. Not
|
|
5349
|
+
* the benign repeat: nothing here can be waited on, and the caller must generate a fresh key.
|
|
5350
|
+
* Distinguished from `idempotency_key_reused` because the correct client response is opposite
|
|
5351
|
+
* -- poll there, resubmit under a new key here.
|
|
5352
|
+
*/
|
|
5353
|
+
"idempotency_key_conflict",
|
|
5354
|
+
/**
|
|
5355
|
+
* The key names the *same* operation by the *same* caller, but with different arguments. One
|
|
5356
|
+
* level finer than `idempotency_key_conflict`, and a distinct reason because the caller's
|
|
5357
|
+
* mistake is distinct: they reused a key while changing what they were asking for, so the
|
|
5358
|
+
* write they just described never happened and the one the key already names is not it
|
|
5359
|
+
* (ADR-0061). Re-send the original arguments to retry the original write, or generate a fresh
|
|
5360
|
+
* key for the new one.
|
|
5361
|
+
*/
|
|
5362
|
+
"idempotency_key_payload_mismatch",
|
|
5363
|
+
/**
|
|
5364
|
+
* The settled payment behind this request has already funded another intent. A retry that
|
|
5365
|
+
* failed to reuse its key, or a replayed payment. The money is spent and this write did not
|
|
5366
|
+
* happen; the caller reads the intent that did consume it from `intents.get`.
|
|
5367
|
+
*/
|
|
5368
|
+
"payment_already_spent",
|
|
5369
|
+
/**
|
|
5370
|
+
* The idempotency precondition could not be read, so the request was refused rather than
|
|
5371
|
+
* risking a double charge on an unverified assumption. Safe to retry with the same key.
|
|
5372
|
+
*/
|
|
5373
|
+
"idempotency_check_unavailable",
|
|
5374
|
+
/**
|
|
5375
|
+
* The chain call is confirmed and the work happened, but recording it did not finish. There
|
|
5376
|
+
* is nothing to refund and nothing to resubmit; the intent is retried automatically.
|
|
5377
|
+
*/
|
|
5378
|
+
"intent_completion_deferred",
|
|
5379
|
+
/**
|
|
5380
|
+
* No intent answers to that id or key *for this caller*. Deliberately one reason for both "no
|
|
5381
|
+
* such intent" and "not yours": telling them apart would make this surface an oracle for which
|
|
5382
|
+
* intent ids and idempotency keys exist (ADR-0049 point 6).
|
|
5383
|
+
*/
|
|
5384
|
+
"intent_not_found",
|
|
5385
|
+
/** The x402 exchange did not produce a settled payment. Nothing was charged. */
|
|
5386
|
+
"payment_rejected",
|
|
5387
|
+
/** A pre-settlement check on the request's own inputs or on task state rejected it. */
|
|
5388
|
+
"payment_preflight_rejected",
|
|
5389
|
+
/**
|
|
5390
|
+
* The settled payment came from an address other than the one the request is authenticated as
|
|
5391
|
+
* acting for. The write was refused; the payment had already settled when the mismatch was
|
|
5392
|
+
* seen, so the fee is not returned by this path.
|
|
5393
|
+
*/
|
|
5394
|
+
"payment_payer_mismatch",
|
|
5395
|
+
/**
|
|
5396
|
+
* The error carries no more specific classification. Present so that every error has a
|
|
5397
|
+
* reason field and a client's switch is total; not a licence to leave one here.
|
|
5398
|
+
*/
|
|
5399
|
+
"unclassified"
|
|
5400
|
+
];
|
|
5401
|
+
var ApiErrorReasonSchema = external_exports.enum(API_ERROR_REASONS);
|
|
5402
|
+
var ApiErrorIntentStatusSchema = external_exports.enum([
|
|
5403
|
+
"reserved",
|
|
5404
|
+
"recorded",
|
|
5405
|
+
"broadcast",
|
|
5406
|
+
"completed",
|
|
5407
|
+
"failed"
|
|
5408
|
+
]);
|
|
5409
|
+
var REASONS_WITHOUT_REQUIRED_INTENT_STATUS = API_ERROR_REASONS.filter((reason) => reason !== "idempotency_key_reused");
|
|
5410
|
+
var ENVELOPE_FIELDS = {
|
|
5411
|
+
/** The durable handle to the write, where one was recorded. Key on this, not on `txHash`. */
|
|
5412
|
+
intentId: external_exports.string().optional(),
|
|
5413
|
+
/** The operation the intent stands for, e.g. `tasks.create`. */
|
|
5414
|
+
operation: external_exports.string().optional(),
|
|
5415
|
+
/** The caller's own key for the operation, echoed so a dropped response is still traceable. */
|
|
5416
|
+
idempotencyKey: external_exports.string().optional(),
|
|
5417
|
+
/**
|
|
5418
|
+
* Known once something has been broadcast, and explicitly not the handle: the reconciler may
|
|
5419
|
+
* land a replacement at the same nonce, which is a different hash for the same intent.
|
|
5420
|
+
*/
|
|
5421
|
+
txHash: external_exports.string().optional()
|
|
5422
|
+
};
|
|
5423
|
+
var ApiErrorEnvelopeSchema = external_exports.discriminatedUnion("reason", [
|
|
5424
|
+
external_exports.object({
|
|
5425
|
+
reason: external_exports.literal("idempotency_key_reused"),
|
|
5426
|
+
/** Required here: the reason means an intent under this key exists, so it has a status. */
|
|
5427
|
+
intentStatus: ApiErrorIntentStatusSchema,
|
|
5428
|
+
...ENVELOPE_FIELDS
|
|
5429
|
+
}),
|
|
5430
|
+
external_exports.object({
|
|
5431
|
+
reason: external_exports.enum(REASONS_WITHOUT_REQUIRED_INTENT_STATUS),
|
|
5432
|
+
/** The intent's status at the moment this answer was produced, where there is an intent. */
|
|
5433
|
+
intentStatus: ApiErrorIntentStatusSchema.optional(),
|
|
5434
|
+
...ENVELOPE_FIELDS
|
|
5435
|
+
})
|
|
5436
|
+
]);
|
|
5437
|
+
var IN_FLIGHT_REASONS = /* @__PURE__ */ new Set([
|
|
5438
|
+
"intent_in_flight",
|
|
5439
|
+
"idempotency_key_reused",
|
|
5440
|
+
// Not "may still succeed" but "already succeeded, still being written down". Both are
|
|
5441
|
+
// answered the same way -- poll, never resubmit -- and reporting this one as settled told a
|
|
5442
|
+
// script following the documented rule that re-running it was an ordinary retry. It is not:
|
|
5443
|
+
// the chain call is confirmed, so a re-run is a second paid action for work already done.
|
|
5444
|
+
"intent_completion_deferred"
|
|
5445
|
+
]);
|
|
5446
|
+
function isInFlightApiError(envelope) {
|
|
5447
|
+
if (!envelope || !IN_FLIGHT_REASONS.has(envelope.reason))
|
|
5448
|
+
return false;
|
|
5449
|
+
if (envelope.reason !== "idempotency_key_reused")
|
|
5450
|
+
return true;
|
|
5451
|
+
return envelope.intentStatus !== "completed" && envelope.intentStatus !== "failed";
|
|
5452
|
+
}
|
|
5453
|
+
function apiErrorEnvelopeOf(value) {
|
|
5454
|
+
if (!value || typeof value !== "object")
|
|
5455
|
+
return null;
|
|
5456
|
+
const at = (source, key) => source && typeof source === "object" ? source[key] : void 0;
|
|
5457
|
+
const candidate = at(value, "taskmarket") ?? at(at(value, "data"), "taskmarket") ?? at(at(at(value, "error"), "data"), "taskmarket") ?? value;
|
|
5458
|
+
const parsed = ApiErrorEnvelopeSchema.safeParse(candidate);
|
|
5459
|
+
return parsed.success ? parsed.data : null;
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5462
|
+
// ../../packages/shared/dist/schemas/intent.schemas.js
|
|
5463
|
+
var IntentStatusInputSchema = external_exports.object({
|
|
5464
|
+
intentId: external_exports.string().min(1).optional(),
|
|
5465
|
+
idempotencyKey: external_exports.string().min(1).optional()
|
|
5466
|
+
}).refine((value) => Boolean(value.intentId) !== Boolean(value.idempotencyKey), {
|
|
5467
|
+
message: "Provide exactly one of intentId or idempotencyKey"
|
|
5468
|
+
});
|
|
5469
|
+
var IntentRefundStateSchema = external_exports.object({
|
|
5470
|
+
status: external_exports.enum(["pending", "refunding", "refunded", "failed"]),
|
|
5471
|
+
txHash: external_exports.string().nullable()
|
|
5472
|
+
});
|
|
5473
|
+
var IntentStatusResponseSchema = external_exports.object({
|
|
5474
|
+
intentId: external_exports.string(),
|
|
5475
|
+
idempotencyKey: external_exports.string(),
|
|
5476
|
+
/** The operation kind, e.g. `tasks.create`. */
|
|
5477
|
+
operation: external_exports.string(),
|
|
5478
|
+
/**
|
|
5479
|
+
* `reserved` is the pre-payment state (ADR-0067): the key is claimed and the caller has been
|
|
5480
|
+
* challenged, but no payment has landed and nothing has been sent to the chain. It is
|
|
5481
|
+
* non-terminal, it is never broadcastable, and it expires if it is never filled.
|
|
5482
|
+
*/
|
|
5483
|
+
status: external_exports.enum(["reserved", "recorded", "broadcast", "completed", "failed"]),
|
|
5484
|
+
/**
|
|
5485
|
+
* Known once something has been broadcast, and explicitly not the handle: the reconciler
|
|
5486
|
+
* may land a replacement at the same nonce, which is a different hash for the same intent.
|
|
5487
|
+
*/
|
|
5488
|
+
txHash: external_exports.string().nullable(),
|
|
5489
|
+
/** Why it failed, where it did. Null on every non-terminal status. */
|
|
5490
|
+
terminalReason: external_exports.string().nullable(),
|
|
5491
|
+
/**
|
|
5492
|
+
* The task a completed `tasks.create` produced.
|
|
5493
|
+
*
|
|
5494
|
+
* This is where a caller whose creation went in flight learns the id. The id does not
|
|
5495
|
+
* exist until the transaction runs -- the contract derives it from a requester nonce it
|
|
5496
|
+
* increments as it goes -- so an in-flight creation has no id to report, and reporting one
|
|
5497
|
+
* would be a guess of the kind that made concurrent creates overwrite each other. Null
|
|
5498
|
+
* until the intent completes, and null for every other operation.
|
|
5499
|
+
*/
|
|
5500
|
+
taskId: external_exports.string().nullable(),
|
|
5501
|
+
/**
|
|
5502
|
+
* Only present where the intent carried a payment and that payment has been written off.
|
|
5503
|
+
* Null means no refund has been decided -- which is not the same as "no refund is coming"
|
|
5504
|
+
* while the intent is still in flight.
|
|
5505
|
+
*/
|
|
5506
|
+
refund: IntentRefundStateSchema.nullable()
|
|
5507
|
+
}).superRefine((value, ctx) => {
|
|
5508
|
+
if (value.status === "reserved") {
|
|
5509
|
+
for (const field of ["txHash", "terminalReason", "taskId"]) {
|
|
5510
|
+
if (value[field] !== null) {
|
|
5511
|
+
ctx.addIssue({
|
|
5512
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5513
|
+
path: [field],
|
|
5514
|
+
message: `A reserved intent has not been sent to the chain, so ${field} must be null`
|
|
5515
|
+
});
|
|
5516
|
+
}
|
|
5517
|
+
}
|
|
5518
|
+
return;
|
|
5519
|
+
}
|
|
5520
|
+
if (value.terminalReason !== null && value.status !== "failed") {
|
|
5521
|
+
ctx.addIssue({
|
|
5522
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5523
|
+
path: ["terminalReason"],
|
|
5524
|
+
message: "Only a failed intent has a terminal reason"
|
|
5525
|
+
});
|
|
5526
|
+
}
|
|
5527
|
+
if (value.taskId === null)
|
|
5528
|
+
return;
|
|
5529
|
+
if (value.status !== "completed") {
|
|
5530
|
+
ctx.addIssue({
|
|
5531
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5532
|
+
path: ["taskId"],
|
|
5533
|
+
message: "taskId is only known once the intent has completed"
|
|
5534
|
+
});
|
|
5535
|
+
return;
|
|
5536
|
+
}
|
|
5537
|
+
if (value.operation !== "tasks.create") {
|
|
5538
|
+
ctx.addIssue({
|
|
5539
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5540
|
+
path: ["taskId"],
|
|
5541
|
+
message: "Only a tasks.create intent produces a taskId"
|
|
5542
|
+
});
|
|
5543
|
+
}
|
|
5544
|
+
});
|
|
5545
|
+
|
|
5207
5546
|
// ../../packages/shared/dist/platform.constants.js
|
|
5208
5547
|
var USDC_DECIMALS = 6;
|
|
5209
5548
|
|
|
@@ -5508,6 +5847,7 @@ function buildReadAuthMessage(address) {
|
|
|
5508
5847
|
var READ_AUTH_ADDRESS_HEADER = "X-Taskmarket-Caller-Address";
|
|
5509
5848
|
var READ_AUTH_SIGNATURE_HEADER = "X-Taskmarket-Caller-Signature";
|
|
5510
5849
|
var TASK_ACCESS_GRANT_HEADER = "X-Taskmarket-Task-Access-Grant";
|
|
5850
|
+
var IDEMPOTENCY_KEY_HEADER = "X-Taskmarket-Idempotency-Key";
|
|
5511
5851
|
function buildSubmitMessage(taskId, contentBindings) {
|
|
5512
5852
|
return contentBindings ? `taskmarket:submit:${taskId}:${contentBindings.join(",")}` : `taskmarket:submit:${taskId}`;
|
|
5513
5853
|
}
|
|
@@ -6035,17 +6375,103 @@ async function keystoreExists(keystorePath) {
|
|
|
6035
6375
|
}
|
|
6036
6376
|
}
|
|
6037
6377
|
|
|
6378
|
+
// src/lib/idempotency.ts
|
|
6379
|
+
import { randomUUID } from "crypto";
|
|
6380
|
+
var pendingEnvKey = process.env.TASKMARKET_IDEMPOTENCY_KEY?.trim() || void 0;
|
|
6381
|
+
var keyByError = /* @__PURE__ */ new WeakMap();
|
|
6382
|
+
function rememberIdempotencyKeyFor(error, key) {
|
|
6383
|
+
if (error === null || typeof error !== "object" && typeof error !== "function") return;
|
|
6384
|
+
if (keyByError.has(error)) return;
|
|
6385
|
+
keyByError.set(error, key);
|
|
6386
|
+
}
|
|
6387
|
+
function idempotencyKeyForError(error) {
|
|
6388
|
+
if (error === null || typeof error !== "object" && typeof error !== "function")
|
|
6389
|
+
return void 0;
|
|
6390
|
+
return keyByError.get(error);
|
|
6391
|
+
}
|
|
6392
|
+
function newIdempotencyKey() {
|
|
6393
|
+
return randomUUID();
|
|
6394
|
+
}
|
|
6395
|
+
function resolveIdempotencyKey(explicit) {
|
|
6396
|
+
if (explicit !== void 0) {
|
|
6397
|
+
return explicit;
|
|
6398
|
+
}
|
|
6399
|
+
if (pendingEnvKey !== void 0) {
|
|
6400
|
+
const fromEnv = pendingEnvKey;
|
|
6401
|
+
pendingEnvKey = void 0;
|
|
6402
|
+
return fromEnv;
|
|
6403
|
+
}
|
|
6404
|
+
return newIdempotencyKey();
|
|
6405
|
+
}
|
|
6406
|
+
async function withIdempotentWrite(key, fn) {
|
|
6407
|
+
try {
|
|
6408
|
+
return await fn();
|
|
6409
|
+
} catch (error) {
|
|
6410
|
+
rememberIdempotencyKeyFor(error, key);
|
|
6411
|
+
throw error;
|
|
6412
|
+
}
|
|
6413
|
+
}
|
|
6414
|
+
function idempotencyHeaders(key) {
|
|
6415
|
+
return { [IDEMPOTENCY_KEY_HEADER]: key };
|
|
6416
|
+
}
|
|
6417
|
+
|
|
6038
6418
|
// src/lib/api.ts
|
|
6039
6419
|
var API_URL = process.env.TASKMARKET_API_URL ?? "https://api.taskmarket.dev";
|
|
6040
6420
|
var API_ORIGIN = new URL(API_URL).origin;
|
|
6041
6421
|
var ApiError = class extends Error {
|
|
6042
6422
|
status;
|
|
6043
|
-
|
|
6423
|
+
/**
|
|
6424
|
+
* The idempotency key the failed write was sent under, when the request was a write. This is
|
|
6425
|
+
* the only identifier the caller can still hold after a failure -- the intent id is minted by
|
|
6426
|
+
* the backend and reaches the caller only in the response the failure destroyed -- so it
|
|
6427
|
+
* travels on the error rather than being recoverable from the response. See
|
|
6428
|
+
* apps/cli/src/index.ts and lib/output.ts, which surface it on the CLI's JSON envelope.
|
|
6429
|
+
*/
|
|
6430
|
+
idempotencyKey;
|
|
6431
|
+
/**
|
|
6432
|
+
* The backend's machine-readable classification of the failure (ADR-0058).
|
|
6433
|
+
*
|
|
6434
|
+
* Before it existed the CLI rendered every failure identically, which is why
|
|
6435
|
+
* `docs/CLI_GUIDE.md` had to tell script authors never to auto-retry a paid command: there was
|
|
6436
|
+
* no way to tell a write that is still landing from one that was definitively rejected, and
|
|
6437
|
+
* retrying the first is a second payment. `reason` is that way.
|
|
6438
|
+
*
|
|
6439
|
+
* Absent when the backend answered with no envelope -- an older deployment, or a failure that
|
|
6440
|
+
* never reached the API at all -- in which case a caller must fall back to the old rule and
|
|
6441
|
+
* treat the outcome as unknown rather than as safe to retry.
|
|
6442
|
+
*/
|
|
6443
|
+
envelope;
|
|
6444
|
+
constructor(status, message, idempotencyKey, envelope) {
|
|
6044
6445
|
super(message);
|
|
6045
6446
|
this.name = "ApiError";
|
|
6046
6447
|
this.status = status;
|
|
6448
|
+
this.idempotencyKey = idempotencyKey;
|
|
6449
|
+
this.envelope = envelope;
|
|
6047
6450
|
}
|
|
6048
6451
|
};
|
|
6452
|
+
async function readFailureBody(res) {
|
|
6453
|
+
const text = await res.text().catch(() => "");
|
|
6454
|
+
try {
|
|
6455
|
+
return { body: JSON.parse(text), text };
|
|
6456
|
+
} catch {
|
|
6457
|
+
return { body: void 0, text };
|
|
6458
|
+
}
|
|
6459
|
+
}
|
|
6460
|
+
function failureMessage(prefix, status, read) {
|
|
6461
|
+
return `${prefix} (${status}): ${read.body !== void 0 ? JSON.stringify(read.body) : read.text}`;
|
|
6462
|
+
}
|
|
6463
|
+
function withErrorContext(error, context) {
|
|
6464
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6465
|
+
const wrapped = error instanceof ApiError ? new ApiError(error.status, `${context}: ${message}`, error.idempotencyKey, error.envelope) : new Error(`${context}: ${message}`);
|
|
6466
|
+
const key = idempotencyKeyForError(error);
|
|
6467
|
+
if (key !== void 0) {
|
|
6468
|
+
rememberIdempotencyKeyFor(wrapped, key);
|
|
6469
|
+
}
|
|
6470
|
+
return wrapped;
|
|
6471
|
+
}
|
|
6472
|
+
function isPendingApiError(error) {
|
|
6473
|
+
return error instanceof ApiError && isInFlightApiError(error.envelope);
|
|
6474
|
+
}
|
|
6049
6475
|
function legalReceiptHeadersForKeystore(keystore, path4, method) {
|
|
6050
6476
|
const canSend = keystore.legalAcceptanceApiOrigin === API_ORIGIN && (method === "POST" || path4 === "/api/legal/status");
|
|
6051
6477
|
return canSend ? buildLegalReceiptHeaders(keystore.legalAcceptanceReceipt) : {};
|
|
@@ -6069,61 +6495,100 @@ async function apiGet(path4, options) {
|
|
|
6069
6495
|
...options?.headers ?? {}
|
|
6070
6496
|
}
|
|
6071
6497
|
});
|
|
6072
|
-
const body = await res.json();
|
|
6073
6498
|
if (!res.ok) {
|
|
6074
|
-
|
|
6499
|
+
const read = await readFailureBody(res);
|
|
6500
|
+
throw new ApiError(
|
|
6501
|
+
res.status,
|
|
6502
|
+
failureMessage(`GET ${path4} failed`, res.status, read),
|
|
6503
|
+
void 0,
|
|
6504
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6505
|
+
);
|
|
6075
6506
|
}
|
|
6076
|
-
return
|
|
6507
|
+
return res.json();
|
|
6077
6508
|
}
|
|
6078
6509
|
async function apiPost(path4, body, options) {
|
|
6079
6510
|
const legalHeaders = await legalReceiptHeaders(path4, "POST");
|
|
6080
|
-
const
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6511
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
6512
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
6513
|
+
const res = await fetch(`${API_URL}${path4}`, {
|
|
6514
|
+
method: "POST",
|
|
6515
|
+
redirect: "error",
|
|
6516
|
+
headers: {
|
|
6517
|
+
"Content-Type": "application/json",
|
|
6518
|
+
...legalHeaders,
|
|
6519
|
+
...idempotencyHeaders(idempotencyKey),
|
|
6520
|
+
...options?.headers ?? {}
|
|
6521
|
+
},
|
|
6522
|
+
body: JSON.stringify(body)
|
|
6523
|
+
});
|
|
6524
|
+
if (!res.ok) {
|
|
6525
|
+
const read = await readFailureBody(res);
|
|
6526
|
+
throw new ApiError(
|
|
6527
|
+
res.status,
|
|
6528
|
+
failureMessage(`POST ${path4} failed`, res.status, read),
|
|
6529
|
+
idempotencyKey,
|
|
6530
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6531
|
+
);
|
|
6532
|
+
}
|
|
6533
|
+
return { data: await res.json(), idempotencyKey };
|
|
6089
6534
|
});
|
|
6090
|
-
const result = await res.json();
|
|
6091
|
-
if (!res.ok) {
|
|
6092
|
-
throw new ApiError(
|
|
6093
|
-
res.status,
|
|
6094
|
-
`POST ${path4} failed (${res.status}): ${JSON.stringify(result)}`
|
|
6095
|
-
);
|
|
6096
|
-
}
|
|
6097
|
-
return result;
|
|
6098
6535
|
}
|
|
6099
6536
|
async function apiDelete(path4, options) {
|
|
6100
6537
|
const legalHeaders = await legalReceiptHeaders(path4, "POST");
|
|
6101
|
-
const
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6538
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
6539
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
6540
|
+
const res = await fetch(`${API_URL}${path4}`, {
|
|
6541
|
+
method: "DELETE",
|
|
6542
|
+
redirect: "error",
|
|
6543
|
+
headers: {
|
|
6544
|
+
"Content-Type": "application/json",
|
|
6545
|
+
...legalHeaders,
|
|
6546
|
+
...idempotencyHeaders(idempotencyKey),
|
|
6547
|
+
...options?.headers ?? {}
|
|
6548
|
+
}
|
|
6549
|
+
});
|
|
6550
|
+
if (!res.ok) {
|
|
6551
|
+
const read = await readFailureBody(res);
|
|
6552
|
+
throw new ApiError(
|
|
6553
|
+
res.status,
|
|
6554
|
+
failureMessage(`DELETE ${path4} failed`, res.status, read),
|
|
6555
|
+
idempotencyKey,
|
|
6556
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6557
|
+
);
|
|
6108
6558
|
}
|
|
6559
|
+
return { data: await res.json(), idempotencyKey };
|
|
6109
6560
|
});
|
|
6110
|
-
const result = await res.json();
|
|
6111
|
-
if (!res.ok) {
|
|
6112
|
-
throw new ApiError(
|
|
6113
|
-
res.status,
|
|
6114
|
-
`DELETE ${path4} failed (${res.status}): ${JSON.stringify(result)}`
|
|
6115
|
-
);
|
|
6116
|
-
}
|
|
6117
|
-
return result;
|
|
6118
6561
|
}
|
|
6119
6562
|
|
|
6120
6563
|
// src/lib/output.ts
|
|
6121
|
-
function printResult(data) {
|
|
6122
|
-
|
|
6564
|
+
function printResult(data, options) {
|
|
6565
|
+
const idempotencyKey = options?.idempotencyKey;
|
|
6566
|
+
console.log(
|
|
6567
|
+
JSON.stringify({ ok: true, data, ...idempotencyKey !== void 0 ? { idempotencyKey } : {} })
|
|
6568
|
+
);
|
|
6569
|
+
}
|
|
6570
|
+
function renderFailure(error, options) {
|
|
6571
|
+
const message = error instanceof Error ? error.message : options?.fallback ?? String(error);
|
|
6572
|
+
const apiError = error instanceof ApiError ? error : void 0;
|
|
6573
|
+
const idempotencyKey = options?.idempotencyKey ?? apiError?.idempotencyKey ?? idempotencyKeyForError(error);
|
|
6574
|
+
const envelope = apiError?.envelope;
|
|
6575
|
+
process.stderr.write(
|
|
6576
|
+
JSON.stringify({
|
|
6577
|
+
ok: false,
|
|
6578
|
+
error: message,
|
|
6579
|
+
...apiError !== void 0 ? { status: apiError.status } : {},
|
|
6580
|
+
...idempotencyKey !== void 0 ? { idempotencyKey } : {},
|
|
6581
|
+
...envelope !== void 0 ? { ...envelope, pending: isInFlightApiError(envelope) } : {},
|
|
6582
|
+
...options?.details ?? {}
|
|
6583
|
+
}) + "\n"
|
|
6584
|
+
);
|
|
6585
|
+
process.exitCode = 1;
|
|
6123
6586
|
}
|
|
6124
|
-
function printError(message) {
|
|
6587
|
+
function printError(message, options) {
|
|
6588
|
+
return renderFailure(new Error(message), options);
|
|
6589
|
+
}
|
|
6590
|
+
function printWarning(message) {
|
|
6125
6591
|
process.stderr.write(JSON.stringify({ ok: false, error: message }) + "\n");
|
|
6126
|
-
process.exit(1);
|
|
6127
6592
|
}
|
|
6128
6593
|
|
|
6129
6594
|
// src/lib/agent.ts
|
|
@@ -6372,21 +6837,21 @@ async function acceptLegalBundle(options) {
|
|
|
6372
6837
|
}
|
|
6373
6838
|
await confirmAcceptance(bundle, options.assumeYes);
|
|
6374
6839
|
const challenge = LegalChallengeResponseSchema.parse(
|
|
6375
|
-
await apiPost("/api/legal/challenge", {
|
|
6840
|
+
(await apiPost("/api/legal/challenge", {
|
|
6376
6841
|
walletAddress: options.walletAddress
|
|
6377
|
-
})
|
|
6842
|
+
})).data
|
|
6378
6843
|
);
|
|
6379
6844
|
validateLegalChallenge(bundle, challenge, options.walletAddress);
|
|
6380
6845
|
const signature = await options.signMessage(challenge.message);
|
|
6381
6846
|
const result = LegalAcceptanceResponseSchema.parse(
|
|
6382
|
-
await apiPost("/api/legal/accept/wallet", {
|
|
6847
|
+
(await apiPost("/api/legal/accept/wallet", {
|
|
6383
6848
|
...affirmations,
|
|
6384
6849
|
bundleDigest: bundle.bundleDigest,
|
|
6385
6850
|
bundleVersion: bundle.version,
|
|
6386
6851
|
nonce: challenge.nonce,
|
|
6387
6852
|
signature,
|
|
6388
6853
|
walletAddress: options.walletAddress
|
|
6389
|
-
})
|
|
6854
|
+
})).data
|
|
6390
6855
|
);
|
|
6391
6856
|
if (result.bundleDigest !== bundle.bundleDigest || result.bundleVersion !== bundle.version) {
|
|
6392
6857
|
throw new Error("The server returned a receipt for a different legal bundle.");
|
|
@@ -6458,7 +6923,7 @@ function sanitizeEmailUsername(agentId, suffix) {
|
|
|
6458
6923
|
}
|
|
6459
6924
|
async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
6460
6925
|
try {
|
|
6461
|
-
const reg = await apiPost("/api/emails/register", {
|
|
6926
|
+
const { data: reg } = await apiPost("/api/emails/register", {
|
|
6462
6927
|
deviceId,
|
|
6463
6928
|
apiToken,
|
|
6464
6929
|
username
|
|
@@ -6467,11 +6932,8 @@ async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
|
6467
6932
|
} catch (err) {
|
|
6468
6933
|
if (explicit) {
|
|
6469
6934
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
ok: false,
|
|
6473
|
-
error: `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
6474
|
-
}) + "\n"
|
|
6935
|
+
printWarning(
|
|
6936
|
+
`Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
6475
6937
|
);
|
|
6476
6938
|
}
|
|
6477
6939
|
return null;
|
|
@@ -6490,6 +6952,7 @@ var initCommand = new Command2("init").description("Create and register a new ag
|
|
|
6490
6952
|
);
|
|
6491
6953
|
if (!check.available) {
|
|
6492
6954
|
printError(`Email username "${opts.email}" is not available.`);
|
|
6955
|
+
return;
|
|
6493
6956
|
}
|
|
6494
6957
|
}
|
|
6495
6958
|
if (await keystoreExists()) {
|
|
@@ -6606,68 +7069,80 @@ var addressCommand = new Command3("address").description("Print the wallet addre
|
|
|
6606
7069
|
import { Command as Command4 } from "commander";
|
|
6607
7070
|
|
|
6608
7071
|
// src/lib/x402.ts
|
|
6609
|
-
async function x402Post(path4, body) {
|
|
7072
|
+
async function x402Post(path4, body, options) {
|
|
6610
7073
|
const url = `${API_URL}${path4}`;
|
|
6611
7074
|
const keystore = await loadKeystore();
|
|
6612
7075
|
const legalHeaders = legalReceiptHeadersForKeystore(keystore, path4, "POST");
|
|
6613
|
-
const
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
}
|
|
6654
|
-
|
|
7076
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
7077
|
+
const idempotency = idempotencyHeaders(idempotencyKey);
|
|
7078
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
7079
|
+
const r1 = await fetch(url, {
|
|
7080
|
+
method: "POST",
|
|
7081
|
+
redirect: "error",
|
|
7082
|
+
headers: { "Content-Type": "application/json", ...legalHeaders, ...idempotency },
|
|
7083
|
+
body: JSON.stringify(body)
|
|
7084
|
+
});
|
|
7085
|
+
if (r1.status !== 402) {
|
|
7086
|
+
if (r1.ok) {
|
|
7087
|
+
return { data: await r1.json(), idempotencyKey };
|
|
7088
|
+
}
|
|
7089
|
+
const read = await readFailureBody(r1);
|
|
7090
|
+
throw new ApiError(
|
|
7091
|
+
r1.status,
|
|
7092
|
+
`POST ${path4} failed (${r1.status}): ${read.text}`,
|
|
7093
|
+
idempotencyKey,
|
|
7094
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
7095
|
+
);
|
|
7096
|
+
}
|
|
7097
|
+
const requirements = await r1.json();
|
|
7098
|
+
if (!requirements.accepts || requirements.accepts.length === 0) {
|
|
7099
|
+
throw new Error("No payment methods accepted by server");
|
|
7100
|
+
}
|
|
7101
|
+
const accept = requirements.accepts[0];
|
|
7102
|
+
const { authorization, signature } = await createTransferAuthorization(accept, keystore);
|
|
7103
|
+
const paymentPayload = {
|
|
7104
|
+
x402Version: 2,
|
|
7105
|
+
resource: requirements.resource,
|
|
7106
|
+
accepted: {
|
|
7107
|
+
scheme: accept.scheme,
|
|
7108
|
+
network: accept.network,
|
|
7109
|
+
amount: accept.amount,
|
|
7110
|
+
asset: accept.asset,
|
|
7111
|
+
payTo: accept.payTo,
|
|
7112
|
+
maxTimeoutSeconds: accept.maxTimeoutSeconds,
|
|
7113
|
+
extra: accept.extra
|
|
7114
|
+
},
|
|
7115
|
+
payload: { authorization, signature }
|
|
7116
|
+
};
|
|
7117
|
+
const r2 = await fetch(url, {
|
|
7118
|
+
method: "POST",
|
|
7119
|
+
redirect: "error",
|
|
7120
|
+
headers: {
|
|
7121
|
+
"Content-Type": "application/json",
|
|
7122
|
+
...legalHeaders,
|
|
7123
|
+
...idempotency,
|
|
7124
|
+
"PAYMENT-SIGNATURE": Buffer.from(JSON.stringify(paymentPayload)).toString("base64")
|
|
7125
|
+
},
|
|
7126
|
+
body: JSON.stringify(body)
|
|
7127
|
+
});
|
|
7128
|
+
if (!r2.ok) {
|
|
7129
|
+
const read = await readFailureBody(r2);
|
|
7130
|
+
throw new ApiError(
|
|
7131
|
+
r2.status,
|
|
7132
|
+
failureMessage(`POST ${path4} failed after payment`, r2.status, read),
|
|
7133
|
+
idempotencyKey,
|
|
7134
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
7135
|
+
);
|
|
7136
|
+
}
|
|
7137
|
+
return { data: await r2.json(), idempotencyKey };
|
|
6655
7138
|
});
|
|
6656
|
-
const result = await r2.json();
|
|
6657
|
-
if (!r2.ok) {
|
|
6658
|
-
throw new ApiError(
|
|
6659
|
-
r2.status,
|
|
6660
|
-
`POST ${path4} failed after payment (${r2.status}): ${JSON.stringify(result)}`
|
|
6661
|
-
);
|
|
6662
|
-
}
|
|
6663
|
-
return result;
|
|
6664
7139
|
}
|
|
6665
7140
|
|
|
6666
7141
|
// src/commands/identity.ts
|
|
6667
7142
|
var identityCommand = new Command4("identity").description("Manage agent identity");
|
|
6668
7143
|
identityCommand.command("register").description("Register ERC-8004 agent identity (costs 0.001 USDC)").action(async () => {
|
|
6669
|
-
const result = await x402Post("/api/identity/register", {});
|
|
6670
|
-
printResult({ agentId: result.agentId });
|
|
7144
|
+
const { data: result, idempotencyKey } = await x402Post("/api/identity/register", {});
|
|
7145
|
+
printResult({ agentId: result.agentId }, { idempotencyKey });
|
|
6671
7146
|
});
|
|
6672
7147
|
identityCommand.command("status").description("Check identity registration status").action(async () => {
|
|
6673
7148
|
const keystore = await loadKeystore();
|
|
@@ -6723,7 +7198,7 @@ var statsCommand = new Command5("stats").description("View agent statistics").op
|
|
|
6723
7198
|
});
|
|
6724
7199
|
|
|
6725
7200
|
// src/commands/task/index.ts
|
|
6726
|
-
import { Command as
|
|
7201
|
+
import { Command as Command41 } from "commander";
|
|
6727
7202
|
|
|
6728
7203
|
// src/commands/task/create.ts
|
|
6729
7204
|
import { Command as Command6 } from "commander";
|
|
@@ -6759,9 +7234,8 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6759
7234
|
try {
|
|
6760
7235
|
rewardBaseUnits = usdcToBaseUnits(opts.reward);
|
|
6761
7236
|
} catch (err) {
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
);
|
|
7237
|
+
renderFailure(withErrorContext(err, "Invalid --reward"));
|
|
7238
|
+
return;
|
|
6765
7239
|
}
|
|
6766
7240
|
const duration = Number(opts.duration);
|
|
6767
7241
|
if (!Number.isFinite(duration) || duration <= 0) {
|
|
@@ -6821,9 +7295,8 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6821
7295
|
try {
|
|
6822
7296
|
maxPriceBaseUnits = usdcToBaseUnits(opts.maxPrice);
|
|
6823
7297
|
} catch (err) {
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
);
|
|
7298
|
+
renderFailure(withErrorContext(err, "Invalid --max-price"));
|
|
7299
|
+
return;
|
|
6827
7300
|
}
|
|
6828
7301
|
if (maxPriceBaseUnits !== rewardBaseUnits) {
|
|
6829
7302
|
return void printError(
|
|
@@ -6865,18 +7338,16 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6865
7338
|
try {
|
|
6866
7339
|
body.auctionStartPrice = usdcToBaseUnits(opts.auctionStartPrice, { allowZero: true });
|
|
6867
7340
|
} catch (err) {
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
);
|
|
7341
|
+
renderFailure(withErrorContext(err, "Invalid --auction-start-price"));
|
|
7342
|
+
return;
|
|
6871
7343
|
}
|
|
6872
7344
|
}
|
|
6873
7345
|
if (opts.auctionFloorPrice) {
|
|
6874
7346
|
try {
|
|
6875
7347
|
body.auctionFloorPrice = usdcToBaseUnits(opts.auctionFloorPrice, { allowZero: true });
|
|
6876
7348
|
} catch (err) {
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
);
|
|
7349
|
+
renderFailure(withErrorContext(err, "Invalid --auction-floor-price"));
|
|
7350
|
+
return;
|
|
6880
7351
|
}
|
|
6881
7352
|
}
|
|
6882
7353
|
for (const [flag, value] of [
|
|
@@ -6924,8 +7395,11 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6924
7395
|
if (opts.appealWindow) body.appealWindowHours = parseFloat(opts.appealWindow);
|
|
6925
7396
|
if (opts.disputeResolver) body.disputeResolver = opts.disputeResolver;
|
|
6926
7397
|
}
|
|
6927
|
-
const result = await x402Post(
|
|
6928
|
-
|
|
7398
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7399
|
+
"/api/tasks",
|
|
7400
|
+
body
|
|
7401
|
+
);
|
|
7402
|
+
printResult({ taskId: result.taskId }, { idempotencyKey });
|
|
6929
7403
|
}
|
|
6930
7404
|
);
|
|
6931
7405
|
|
|
@@ -7036,6 +7510,7 @@ var getCmd = new Command8("get").description("Get task details").argument("<task
|
|
|
7036
7510
|
printError(
|
|
7037
7511
|
`Task not found: ${taskId} (or this is a private task you don't have access to -- if you have a password for it, run: taskmarket task unlock ${taskId} --password <password>)`
|
|
7038
7512
|
);
|
|
7513
|
+
return;
|
|
7039
7514
|
}
|
|
7040
7515
|
printResult(task);
|
|
7041
7516
|
});
|
|
@@ -7136,6 +7611,7 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7136
7611
|
try {
|
|
7137
7612
|
if (!opts.file || opts.file.length === 0) {
|
|
7138
7613
|
printError("--file is required");
|
|
7614
|
+
return;
|
|
7139
7615
|
}
|
|
7140
7616
|
const keystore = await loadKeystore();
|
|
7141
7617
|
const signature = await signMessage(buildSubmitMessage(taskId), keystore);
|
|
@@ -7144,9 +7620,11 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7144
7620
|
const mimeType = mimeTypeForPath(filePath);
|
|
7145
7621
|
const data = await fsPromises.readFile(filePath);
|
|
7146
7622
|
if (data.length === 0) {
|
|
7147
|
-
|
|
7623
|
+
throw new Error(`File is empty: ${basename(filePath)}`);
|
|
7148
7624
|
}
|
|
7149
|
-
const {
|
|
7625
|
+
const {
|
|
7626
|
+
data: { uploadUrl, artifactKey }
|
|
7627
|
+
} = await apiPost(
|
|
7150
7628
|
`/api/tasks/${taskId}/submissions/request-upload-url`,
|
|
7151
7629
|
{
|
|
7152
7630
|
taskId,
|
|
@@ -7181,13 +7659,16 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7181
7659
|
),
|
|
7182
7660
|
keystore
|
|
7183
7661
|
);
|
|
7184
|
-
const result = await x402Post(
|
|
7185
|
-
taskId
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7662
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7663
|
+
`/api/tasks/${taskId}/submissions/from-keys`,
|
|
7664
|
+
{
|
|
7665
|
+
taskId,
|
|
7666
|
+
workerAddress: keystore.walletAddress,
|
|
7667
|
+
artifacts: artifactInputs,
|
|
7668
|
+
signature: submitSignature
|
|
7669
|
+
}
|
|
7670
|
+
);
|
|
7671
|
+
printResult({ submissionId: result.submissionId }, { idempotencyKey });
|
|
7191
7672
|
} finally {
|
|
7192
7673
|
submitCmd.setOptionValue("file", []);
|
|
7193
7674
|
}
|
|
@@ -7199,7 +7680,6 @@ var acceptCmd = new Command10("accept").description("Accept a submission (costs
|
|
|
7199
7680
|
const task = await apiGet(`/api/tasks/${taskId}`);
|
|
7200
7681
|
if (!task) {
|
|
7201
7682
|
printError("Task not found");
|
|
7202
|
-
process.exit(1);
|
|
7203
7683
|
return;
|
|
7204
7684
|
}
|
|
7205
7685
|
const canAccept = task.pendingActions?.some(
|
|
@@ -7215,14 +7695,13 @@ var acceptCmd = new Command10("accept").description("Accept a submission (costs
|
|
|
7215
7695
|
printError(
|
|
7216
7696
|
hasRefund ? "Task has expired with no submissions. Use taskmarket task refund-expired to recover escrow." : hasSelectWorker ? "Pitch window has closed. Use taskmarket task select-worker to pick from received pitches, or cancel the task." : "Accept is not available for this task in its current state."
|
|
7217
7697
|
);
|
|
7218
|
-
process.exit(1);
|
|
7219
7698
|
return;
|
|
7220
7699
|
}
|
|
7221
|
-
await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
7700
|
+
const { idempotencyKey } = await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
7222
7701
|
taskId,
|
|
7223
7702
|
worker: opts.worker
|
|
7224
7703
|
});
|
|
7225
|
-
printResult({ accepted: true });
|
|
7704
|
+
printResult({ accepted: true }, { idempotencyKey });
|
|
7226
7705
|
});
|
|
7227
7706
|
|
|
7228
7707
|
// src/commands/task/accept-submissions.ts
|
|
@@ -7257,13 +7736,16 @@ var acceptSubmissionsCmd = new Command11("accept-submissions").description(
|
|
|
7257
7736
|
if (sum !== 1e4) {
|
|
7258
7737
|
throw new Error(`Winner shares must sum to 10000 basis points (got ${sum})`);
|
|
7259
7738
|
}
|
|
7260
|
-
const result = await x402Post(
|
|
7261
|
-
taskId
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7739
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7740
|
+
`/api/tasks/${taskId}/accept-submissions`,
|
|
7741
|
+
{
|
|
7742
|
+
taskId,
|
|
7743
|
+
winners
|
|
7744
|
+
}
|
|
7745
|
+
);
|
|
7746
|
+
printResult({ accepted: result.success, winners: winners.length }, { idempotencyKey });
|
|
7265
7747
|
} catch (err) {
|
|
7266
|
-
|
|
7748
|
+
renderFailure(err);
|
|
7267
7749
|
}
|
|
7268
7750
|
});
|
|
7269
7751
|
|
|
@@ -7273,14 +7755,15 @@ var rateCmd = new Command12("rate").description("Rate a worker (costs 0.001 USDC
|
|
|
7273
7755
|
const rating = parseInt(opts.rating, 10);
|
|
7274
7756
|
if (rating < 0 || rating > 100) {
|
|
7275
7757
|
printError("Rating must be between 0 and 100");
|
|
7758
|
+
return;
|
|
7276
7759
|
}
|
|
7277
|
-
const result = await x402Post(`/api/tasks/${taskId}/rate`, {
|
|
7760
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/rate`, {
|
|
7278
7761
|
taskId,
|
|
7279
7762
|
worker: opts.worker,
|
|
7280
7763
|
rating,
|
|
7281
7764
|
...opts.feedback ? { feedbackText: opts.feedback } : {}
|
|
7282
7765
|
});
|
|
7283
|
-
printResult({ feedbackId: result.feedbackId });
|
|
7766
|
+
printResult({ feedbackId: result.feedbackId }, { idempotencyKey });
|
|
7284
7767
|
});
|
|
7285
7768
|
|
|
7286
7769
|
// src/commands/task/claim.ts
|
|
@@ -7289,11 +7772,14 @@ var claimCmd = new Command13("claim").description("Claim a task as a worker").ar
|
|
|
7289
7772
|
const keystore = await loadKeystore();
|
|
7290
7773
|
const message = buildClaimMessage(taskId);
|
|
7291
7774
|
const signature = await signMessage(message, keystore);
|
|
7292
|
-
const result = await apiPost(
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7775
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
7776
|
+
`/api/tasks/${taskId}/claim`,
|
|
7777
|
+
{
|
|
7778
|
+
workerAddress: keystore.walletAddress,
|
|
7779
|
+
signature
|
|
7780
|
+
}
|
|
7781
|
+
);
|
|
7782
|
+
printResult({ claimId: result.claimId }, { idempotencyKey });
|
|
7297
7783
|
});
|
|
7298
7784
|
|
|
7299
7785
|
// src/commands/task/pitch.ts
|
|
@@ -7301,14 +7787,17 @@ import { Command as Command14 } from "commander";
|
|
|
7301
7787
|
var pitchCmd = new Command14("pitch").description("Submit a pitch for a task (costs 0.001 USDC, anchors hash on-chain)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--text <text>", "Pitch text").option("--duration <hours>", "Estimated duration in hours").action(async (taskId, opts) => {
|
|
7302
7788
|
const keystore = await loadKeystore();
|
|
7303
7789
|
const signature = await signMessage(`taskmarket:pitch:${taskId}`, keystore);
|
|
7304
|
-
const result = await x402Post(
|
|
7305
|
-
taskId
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7790
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7791
|
+
`/api/tasks/${taskId}/pitches`,
|
|
7792
|
+
{
|
|
7793
|
+
taskId,
|
|
7794
|
+
workerAddress: keystore.walletAddress,
|
|
7795
|
+
pitchText: opts.text,
|
|
7796
|
+
...opts.duration ? { estimatedDuration: parseInt(opts.duration, 10) } : {},
|
|
7797
|
+
signature
|
|
7798
|
+
}
|
|
7799
|
+
);
|
|
7800
|
+
printResult({ pitchId: result.pitchId }, { idempotencyKey });
|
|
7312
7801
|
});
|
|
7313
7802
|
|
|
7314
7803
|
// src/commands/task/pitches.ts
|
|
@@ -7319,7 +7808,7 @@ var pitchesCmd = new Command15("pitches").description("List pitches for a task")
|
|
|
7319
7808
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
7320
7809
|
printResult(await apiGet(`/api/tasks/${taskId}/pitches`, { headers }));
|
|
7321
7810
|
} catch (err) {
|
|
7322
|
-
|
|
7811
|
+
renderFailure(err);
|
|
7323
7812
|
}
|
|
7324
7813
|
});
|
|
7325
7814
|
|
|
@@ -7329,13 +7818,13 @@ var selectWorkerCmd = new Command16("select-worker").description("Select a worke
|
|
|
7329
7818
|
const keystore = await loadKeystore();
|
|
7330
7819
|
const message = buildSelectWorkerMessage(taskId, opts.pitch, opts.worker);
|
|
7331
7820
|
const signature = await signMessage(message, keystore);
|
|
7332
|
-
await apiPost(`/api/tasks/${taskId}/pitches/select`, {
|
|
7821
|
+
const { idempotencyKey } = await apiPost(`/api/tasks/${taskId}/pitches/select`, {
|
|
7333
7822
|
taskId,
|
|
7334
7823
|
pitchId: opts.pitch,
|
|
7335
7824
|
workerAddress: opts.worker,
|
|
7336
7825
|
signature
|
|
7337
7826
|
});
|
|
7338
|
-
printResult({ selected: true });
|
|
7827
|
+
printResult({ selected: true }, { idempotencyKey });
|
|
7339
7828
|
});
|
|
7340
7829
|
|
|
7341
7830
|
// src/commands/task/proof.ts
|
|
@@ -7343,7 +7832,7 @@ import { Command as Command17 } from "commander";
|
|
|
7343
7832
|
var proofCmd = new Command17("proof").description("Submit a benchmark proof (costs 0.001 USDC, anchors hash on-chain)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--data <data>", "Proof data").requiredOption("--type <type>", "Proof type").option("--metric <val>", "Metric value").action(async (taskId, opts) => {
|
|
7344
7833
|
const keystore = await loadKeystore();
|
|
7345
7834
|
const signature = await signMessage(`taskmarket:proof:${taskId}`, keystore);
|
|
7346
|
-
const result = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
7835
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
7347
7836
|
taskId,
|
|
7348
7837
|
workerAddress: keystore.walletAddress,
|
|
7349
7838
|
proofData: opts.data,
|
|
@@ -7351,7 +7840,7 @@ var proofCmd = new Command17("proof").description("Submit a benchmark proof (cos
|
|
|
7351
7840
|
...opts.metric ? { metricValue: opts.metric } : {},
|
|
7352
7841
|
signature
|
|
7353
7842
|
});
|
|
7354
|
-
printResult({ proofId: result.proofId, submissionId: result.submissionId });
|
|
7843
|
+
printResult({ proofId: result.proofId, submissionId: result.submissionId }, { idempotencyKey });
|
|
7355
7844
|
});
|
|
7356
7845
|
|
|
7357
7846
|
// src/commands/task/proofs.ts
|
|
@@ -7362,7 +7851,7 @@ var proofsCmd = new Command18("proofs").description("List proofs for a benchmark
|
|
|
7362
7851
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
7363
7852
|
printResult(await apiGet(`/api/tasks/${taskId}/proofs`, { headers }));
|
|
7364
7853
|
} catch (err) {
|
|
7365
|
-
|
|
7854
|
+
renderFailure(err);
|
|
7366
7855
|
}
|
|
7367
7856
|
});
|
|
7368
7857
|
|
|
@@ -7373,15 +7862,17 @@ var bidCmd = new Command19("bid").description("Submit a bid on an auction task")
|
|
|
7373
7862
|
try {
|
|
7374
7863
|
priceBaseUnits = usdcToBaseUnits(opts.price);
|
|
7375
7864
|
} catch (err) {
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
);
|
|
7865
|
+
renderFailure(withErrorContext(err, "Invalid --price"));
|
|
7866
|
+
return;
|
|
7379
7867
|
}
|
|
7380
|
-
const result = await x402Post(
|
|
7381
|
-
taskId
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
|
|
7868
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7869
|
+
`/api/tasks/${taskId}/bids`,
|
|
7870
|
+
{
|
|
7871
|
+
taskId,
|
|
7872
|
+
price: priceBaseUnits
|
|
7873
|
+
}
|
|
7874
|
+
);
|
|
7875
|
+
printResult({ bidId: result.bidId }, { idempotencyKey });
|
|
7385
7876
|
});
|
|
7386
7877
|
|
|
7387
7878
|
// src/commands/task/auction-accept.ts
|
|
@@ -7395,17 +7886,19 @@ var auctionAcceptCmd = new Command20("auction-accept").description("Accept curre
|
|
|
7395
7886
|
try {
|
|
7396
7887
|
body.minPrice = usdcToBaseUnits(opts.minPrice, { allowZero: true });
|
|
7397
7888
|
} catch (error) {
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
);
|
|
7889
|
+
renderFailure(withErrorContext(error, "Invalid --min-price"));
|
|
7890
|
+
return;
|
|
7401
7891
|
}
|
|
7402
7892
|
}
|
|
7403
|
-
const result = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
7404
|
-
printResult(
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7893
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
7894
|
+
printResult(
|
|
7895
|
+
{
|
|
7896
|
+
acceptedPrice: result.acceptedPrice,
|
|
7897
|
+
acceptedPriceUsdc: formatUsdcBaseUnits(result.acceptedPrice),
|
|
7898
|
+
workerAddress: result.workerAddress
|
|
7899
|
+
},
|
|
7900
|
+
{ idempotencyKey }
|
|
7901
|
+
);
|
|
7409
7902
|
});
|
|
7410
7903
|
|
|
7411
7904
|
// src/commands/task/submissions.ts
|
|
@@ -7416,8 +7909,8 @@ var submissionsCmd = new Command21("submissions").description("List submissions
|
|
|
7416
7909
|
try {
|
|
7417
7910
|
subs = await apiGet(`/api/tasks/${taskId}/submissions`, { headers: auth?.headers ?? {} });
|
|
7418
7911
|
} catch (err) {
|
|
7419
|
-
|
|
7420
|
-
|
|
7912
|
+
renderFailure(err, { fallback: "Failed to fetch submissions." });
|
|
7913
|
+
return;
|
|
7421
7914
|
}
|
|
7422
7915
|
printResult(subs);
|
|
7423
7916
|
});
|
|
@@ -7426,15 +7919,17 @@ var submissionsCmd = new Command21("submissions").description("List submissions
|
|
|
7426
7919
|
import { Command as Command22 } from "commander";
|
|
7427
7920
|
var selectWinnerCmd = new Command22("select-winner").description("Permissionlessly finalize the lowest bidder after the auction deadline").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
7428
7921
|
let result;
|
|
7922
|
+
let idempotencyKey;
|
|
7429
7923
|
try {
|
|
7430
|
-
result = await apiPost(
|
|
7431
|
-
taskId
|
|
7432
|
-
|
|
7924
|
+
({ data: result, idempotencyKey } = await apiPost(
|
|
7925
|
+
`/api/tasks/${taskId}/bids/select-winner`,
|
|
7926
|
+
{ taskId }
|
|
7927
|
+
));
|
|
7433
7928
|
} catch (err) {
|
|
7434
|
-
|
|
7435
|
-
|
|
7929
|
+
renderFailure(err, { fallback: "Failed to select winner." });
|
|
7930
|
+
return;
|
|
7436
7931
|
}
|
|
7437
|
-
printResult(result);
|
|
7932
|
+
printResult(result, { idempotencyKey });
|
|
7438
7933
|
});
|
|
7439
7934
|
|
|
7440
7935
|
// src/commands/task/download.ts
|
|
@@ -7457,18 +7952,19 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7457
7952
|
if (opts.artifact) {
|
|
7458
7953
|
body.artifactId = opts.artifact;
|
|
7459
7954
|
}
|
|
7460
|
-
const result = await apiPost(
|
|
7955
|
+
const { data: result } = await apiPost(
|
|
7461
7956
|
`/api/tasks/${taskId}/submissions/${opts.submission}/preview`,
|
|
7462
7957
|
body
|
|
7463
7958
|
);
|
|
7464
7959
|
presignedUrl = result.presignedUrl;
|
|
7465
7960
|
} catch (err) {
|
|
7466
|
-
|
|
7467
|
-
|
|
7961
|
+
renderFailure(err, { fallback: "Failed to get download URL." });
|
|
7962
|
+
return;
|
|
7468
7963
|
}
|
|
7469
7964
|
const res = await fetch(presignedUrl);
|
|
7470
7965
|
if (!res.ok) {
|
|
7471
7966
|
printError(`Failed to download file: ${res.status}`);
|
|
7967
|
+
return;
|
|
7472
7968
|
}
|
|
7473
7969
|
const content = Buffer.from(await res.arrayBuffer());
|
|
7474
7970
|
if (opts.output) {
|
|
@@ -7482,6 +7978,7 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7482
7978
|
printError(
|
|
7483
7979
|
"Downloaded content is not valid UTF-8 text and cannot be safely printed to the terminal. Use --output <path> to save it to a file instead."
|
|
7484
7980
|
);
|
|
7981
|
+
return;
|
|
7485
7982
|
}
|
|
7486
7983
|
process.stdout.write(sanitizeForTerminal(decoded));
|
|
7487
7984
|
}
|
|
@@ -7491,8 +7988,11 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7491
7988
|
// src/commands/task/cancel.ts
|
|
7492
7989
|
import { Command as Command24 } from "commander";
|
|
7493
7990
|
var cancelCmd = new Command24("cancel").description("Cancel an open task and refund the escrowed reward (costs 0.001 USDC)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
7494
|
-
const result = await x402Post(
|
|
7495
|
-
|
|
7991
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7992
|
+
`/api/tasks/${taskId}/cancel`,
|
|
7993
|
+
{ taskId }
|
|
7994
|
+
);
|
|
7995
|
+
printResult(result, { idempotencyKey });
|
|
7496
7996
|
});
|
|
7497
7997
|
|
|
7498
7998
|
// src/commands/task/refund-expired.ts
|
|
@@ -7501,11 +8001,13 @@ var refundExpiredCmd = new Command25("refund-expired").description(
|
|
|
7501
8001
|
"Refund an expired task with no submissions back to the requester (costs 0.001 USDC)"
|
|
7502
8002
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
7503
8003
|
try {
|
|
7504
|
-
const result = await x402Post(
|
|
7505
|
-
|
|
8004
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8005
|
+
`/api/tasks/${taskId}/refund-expired`,
|
|
8006
|
+
{ taskId }
|
|
8007
|
+
);
|
|
8008
|
+
printResult(result, { idempotencyKey });
|
|
7506
8009
|
} catch (err) {
|
|
7507
|
-
|
|
7508
|
-
process.exit(1);
|
|
8010
|
+
renderFailure(err);
|
|
7509
8011
|
}
|
|
7510
8012
|
});
|
|
7511
8013
|
|
|
@@ -7515,14 +8017,16 @@ var rejectSubmissionCmd = new Command26("reject-submission").description(
|
|
|
7515
8017
|
"Reject a spam or low-quality submission (costs 0.001 USDC relay fee). Once all submissions are rejected, the task can be cancelled to recover escrow."
|
|
7516
8018
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <address>", "Worker address whose submission to reject").action(async (taskId, opts) => {
|
|
7517
8019
|
try {
|
|
7518
|
-
const result = await x402Post(
|
|
7519
|
-
taskId
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
8020
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8021
|
+
`/api/tasks/${taskId}/reject-submission`,
|
|
8022
|
+
{
|
|
8023
|
+
taskId,
|
|
8024
|
+
worker: opts.worker
|
|
8025
|
+
}
|
|
8026
|
+
);
|
|
8027
|
+
printResult(result, { idempotencyKey });
|
|
7523
8028
|
} catch (err) {
|
|
7524
|
-
|
|
7525
|
-
process.exit(1);
|
|
8029
|
+
renderFailure(err);
|
|
7526
8030
|
}
|
|
7527
8031
|
});
|
|
7528
8032
|
|
|
@@ -7544,7 +8048,8 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7544
8048
|
try {
|
|
7545
8049
|
submissions = await apiGet(`/api/tasks/${taskId}/submissions`);
|
|
7546
8050
|
} catch (err) {
|
|
7547
|
-
|
|
8051
|
+
renderFailure(err);
|
|
8052
|
+
return;
|
|
7548
8053
|
}
|
|
7549
8054
|
const workers = activeSubmissionWorkers(submissions);
|
|
7550
8055
|
if (workers.length === 0) {
|
|
@@ -7554,20 +8059,40 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7554
8059
|
const results = [];
|
|
7555
8060
|
for (const worker of workers) {
|
|
7556
8061
|
try {
|
|
7557
|
-
const res = await x402Post(
|
|
7558
|
-
taskId
|
|
7559
|
-
worker
|
|
7560
|
-
|
|
7561
|
-
results.push({ worker, txHash: res.txHash });
|
|
8062
|
+
const { data: res, idempotencyKey } = await x402Post(
|
|
8063
|
+
`/api/tasks/${taskId}/reject-submission`,
|
|
8064
|
+
{ taskId, worker }
|
|
8065
|
+
);
|
|
8066
|
+
results.push({ worker, txHash: res.txHash, idempotencyKey });
|
|
7562
8067
|
} catch (err) {
|
|
7563
|
-
results.push({
|
|
8068
|
+
results.push({
|
|
8069
|
+
worker,
|
|
8070
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8071
|
+
idempotencyKey: idempotencyKeyForError(err),
|
|
8072
|
+
cause: err
|
|
8073
|
+
});
|
|
7564
8074
|
}
|
|
7565
8075
|
}
|
|
7566
|
-
const failed = results.filter((r) => r.error);
|
|
8076
|
+
const failed = results.filter((r) => r.error !== void 0);
|
|
7567
8077
|
if (failed.length > 0) {
|
|
7568
|
-
|
|
7569
|
-
|
|
8078
|
+
const representative = failed.find((r) => isPendingApiError(r.cause)) ?? failed[0];
|
|
8079
|
+
renderFailure(
|
|
8080
|
+
withErrorContext(
|
|
8081
|
+
representative.cause,
|
|
8082
|
+
`${failed.length} of ${results.length} rejection(s) failed`
|
|
8083
|
+
),
|
|
8084
|
+
{
|
|
8085
|
+
details: {
|
|
8086
|
+
results: results.map(({ worker, txHash, idempotencyKey, error }) => ({
|
|
8087
|
+
worker,
|
|
8088
|
+
txHash,
|
|
8089
|
+
idempotencyKey,
|
|
8090
|
+
error
|
|
8091
|
+
}))
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
7570
8094
|
);
|
|
8095
|
+
return;
|
|
7571
8096
|
}
|
|
7572
8097
|
if (!opts.cancel) {
|
|
7573
8098
|
printResult({ rejected: results.length, results });
|
|
@@ -7575,11 +8100,15 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7575
8100
|
}
|
|
7576
8101
|
let cancelRes;
|
|
7577
8102
|
try {
|
|
7578
|
-
cancelRes = await x402Post(
|
|
8103
|
+
({ data: cancelRes } = await x402Post(
|
|
8104
|
+
`/api/tasks/${taskId}/cancel`,
|
|
8105
|
+
{ taskId }
|
|
8106
|
+
));
|
|
7579
8107
|
} catch (err) {
|
|
7580
|
-
|
|
7581
|
-
`All ${results.length} submission(s) rejected but cancel failed
|
|
8108
|
+
renderFailure(
|
|
8109
|
+
withErrorContext(err, `All ${results.length} submission(s) rejected but cancel failed`)
|
|
7582
8110
|
);
|
|
8111
|
+
return;
|
|
7583
8112
|
}
|
|
7584
8113
|
printResult({ rejected: results.length, results, cancelTxHash: cancelRes.txHash });
|
|
7585
8114
|
});
|
|
@@ -7599,8 +8128,7 @@ var mySubmissionsCmd = new Command28("my-submissions").description("List all sub
|
|
|
7599
8128
|
);
|
|
7600
8129
|
printResult(result);
|
|
7601
8130
|
} catch (err) {
|
|
7602
|
-
|
|
7603
|
-
process.exit(1);
|
|
8131
|
+
renderFailure(err);
|
|
7604
8132
|
}
|
|
7605
8133
|
});
|
|
7606
8134
|
|
|
@@ -7613,9 +8141,8 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7613
8141
|
try {
|
|
7614
8142
|
body.reward = usdcToBaseUnits(opts.reward);
|
|
7615
8143
|
} catch (err) {
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
);
|
|
8144
|
+
renderFailure(withErrorContext(err, "Invalid --reward"));
|
|
8145
|
+
return;
|
|
7619
8146
|
}
|
|
7620
8147
|
}
|
|
7621
8148
|
if (opts.extendExpiry !== void 0) {
|
|
@@ -7624,10 +8151,12 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7624
8151
|
printError(
|
|
7625
8152
|
`--extend-expiry must be a positive integer (seconds), got: ${opts.extendExpiry}`
|
|
7626
8153
|
);
|
|
8154
|
+
return;
|
|
7627
8155
|
}
|
|
7628
8156
|
const task = await apiGet(`/api/tasks/${taskId}`);
|
|
7629
8157
|
if (!task) {
|
|
7630
8158
|
printError(`Task not found: ${taskId}`);
|
|
8159
|
+
return;
|
|
7631
8160
|
}
|
|
7632
8161
|
const currentExpiry = Math.floor(new Date(task.expiryTime).getTime() / 1e3);
|
|
7633
8162
|
const newExpiry = currentExpiry + delta;
|
|
@@ -7637,6 +8166,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7637
8166
|
printError(
|
|
7638
8167
|
`--extend-expiry would set expiry in the past. Task expired ${expiredAgo}s ago; pass at least ${expiredAgo + 1} seconds to extend beyond now.`
|
|
7639
8168
|
);
|
|
8169
|
+
return;
|
|
7640
8170
|
}
|
|
7641
8171
|
body.expiryTime = newExpiry;
|
|
7642
8172
|
}
|
|
@@ -7644,6 +8174,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7644
8174
|
const ts = Math.floor(new Date(opts.bidDeadline).getTime() / 1e3);
|
|
7645
8175
|
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
7646
8176
|
printError("--bid-deadline must be in the future");
|
|
8177
|
+
return;
|
|
7647
8178
|
} else {
|
|
7648
8179
|
body.bidDeadline = ts;
|
|
7649
8180
|
}
|
|
@@ -7652,6 +8183,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7652
8183
|
const ts = Math.floor(new Date(opts.pitchDeadline).getTime() / 1e3);
|
|
7653
8184
|
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
7654
8185
|
printError("--pitch-deadline must be in the future");
|
|
8186
|
+
return;
|
|
7655
8187
|
} else {
|
|
7656
8188
|
body.pitchDeadline = ts;
|
|
7657
8189
|
}
|
|
@@ -7660,18 +8192,16 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7660
8192
|
try {
|
|
7661
8193
|
body.auctionFloorPrice = usdcToBaseUnits(opts.auctionFloorPrice, { allowZero: true });
|
|
7662
8194
|
} catch (err) {
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
);
|
|
8195
|
+
renderFailure(withErrorContext(err, "Invalid --auction-floor-price"));
|
|
8196
|
+
return;
|
|
7666
8197
|
}
|
|
7667
8198
|
}
|
|
7668
8199
|
if (opts.auctionStartPrice !== void 0) {
|
|
7669
8200
|
try {
|
|
7670
8201
|
body.auctionStartPrice = usdcToBaseUnits(opts.auctionStartPrice, { allowZero: true });
|
|
7671
8202
|
} catch (err) {
|
|
7672
|
-
|
|
7673
|
-
|
|
7674
|
-
);
|
|
8203
|
+
renderFailure(withErrorContext(err, "Invalid --auction-start-price"));
|
|
8204
|
+
return;
|
|
7675
8205
|
}
|
|
7676
8206
|
}
|
|
7677
8207
|
if (opts.description !== void 0) {
|
|
@@ -7683,8 +8213,11 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7683
8213
|
if (opts.metricDescription !== void 0) {
|
|
7684
8214
|
body.metricDescription = opts.metricDescription;
|
|
7685
8215
|
}
|
|
7686
|
-
const result = await x402Post(
|
|
7687
|
-
|
|
8216
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8217
|
+
`/api/tasks/${taskId}/update`,
|
|
8218
|
+
body
|
|
8219
|
+
);
|
|
8220
|
+
printResult(result, { idempotencyKey });
|
|
7688
8221
|
}
|
|
7689
8222
|
);
|
|
7690
8223
|
|
|
@@ -7695,20 +8228,77 @@ var forfeitCmd = new Command30("forfeit").description("Reclaim a claim-mode task
|
|
|
7695
8228
|
const keystore = await loadKeystore();
|
|
7696
8229
|
const message = buildForfeitMessage(taskId);
|
|
7697
8230
|
const signature = await signMessage(message, keystore);
|
|
7698
|
-
const result = await apiPost(
|
|
7699
|
-
taskId
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
8231
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8232
|
+
`/api/tasks/${taskId}/forfeit`,
|
|
8233
|
+
{
|
|
8234
|
+
taskId,
|
|
8235
|
+
requesterAddress: keystore.walletAddress,
|
|
8236
|
+
signature
|
|
8237
|
+
}
|
|
8238
|
+
);
|
|
8239
|
+
printResult(result, { idempotencyKey });
|
|
7704
8240
|
} catch (err) {
|
|
7705
|
-
|
|
8241
|
+
renderFailure(err);
|
|
7706
8242
|
}
|
|
7707
8243
|
});
|
|
7708
8244
|
|
|
7709
|
-
// src/commands/task/
|
|
8245
|
+
// src/commands/task/assign-evaluator.ts
|
|
7710
8246
|
import { Command as Command31 } from "commander";
|
|
7711
|
-
var
|
|
8247
|
+
var ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
8248
|
+
var assignEvaluatorCmd = new Command31("assign-evaluator").description(
|
|
8249
|
+
"Assign an evaluator to an open, unclaimed task you requested (costs 0.001 USDC). Only possible before a worker claims the task."
|
|
8250
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--evaluator <address>", "Evaluator wallet address").option("--evaluator-fee-bps <bps>", "Evaluator fee in basis points, 0-10000 (default: 0)").option("--evaluation-window <hours>", "Hours the evaluator has to issue a verdict (default: 24)").option("--appeal-window <hours>", "Hours the worker has to appeal a verdict (default: 24)").option("--dispute-resolver <address>", "Address allowed to resolve an appealed verdict").action(
|
|
8251
|
+
async (taskId, opts) => {
|
|
8252
|
+
if (!ADDRESS_PATTERN.test(opts.evaluator)) {
|
|
8253
|
+
return void printError(`--evaluator must be a wallet address, got: ${opts.evaluator}`);
|
|
8254
|
+
}
|
|
8255
|
+
if (opts.disputeResolver !== void 0 && !ADDRESS_PATTERN.test(opts.disputeResolver)) {
|
|
8256
|
+
return void printError(
|
|
8257
|
+
`--dispute-resolver must be a wallet address, got: ${opts.disputeResolver}`
|
|
8258
|
+
);
|
|
8259
|
+
}
|
|
8260
|
+
const body = { taskId, evaluator: opts.evaluator };
|
|
8261
|
+
if (opts.evaluatorFeeBps !== void 0) {
|
|
8262
|
+
const bps = Number(opts.evaluatorFeeBps);
|
|
8263
|
+
if (!Number.isInteger(bps) || bps < 0 || bps > 1e4) {
|
|
8264
|
+
return void printError(
|
|
8265
|
+
`--evaluator-fee-bps must be an integer between 0 and 10000, got: ${opts.evaluatorFeeBps}`
|
|
8266
|
+
);
|
|
8267
|
+
}
|
|
8268
|
+
body.evaluatorFeeBps = bps;
|
|
8269
|
+
}
|
|
8270
|
+
if (opts.evaluationWindow !== void 0) {
|
|
8271
|
+
const hours = Number(opts.evaluationWindow);
|
|
8272
|
+
if (!Number.isFinite(hours) || hours <= 0) {
|
|
8273
|
+
return void printError(
|
|
8274
|
+
`--evaluation-window must be a positive number of hours, got: ${opts.evaluationWindow}`
|
|
8275
|
+
);
|
|
8276
|
+
}
|
|
8277
|
+
body.evaluationWindowHours = hours;
|
|
8278
|
+
}
|
|
8279
|
+
if (opts.appealWindow !== void 0) {
|
|
8280
|
+
const hours = Number(opts.appealWindow);
|
|
8281
|
+
if (!Number.isFinite(hours) || hours <= 0) {
|
|
8282
|
+
return void printError(
|
|
8283
|
+
`--appeal-window must be a positive number of hours, got: ${opts.appealWindow}`
|
|
8284
|
+
);
|
|
8285
|
+
}
|
|
8286
|
+
body.appealWindowHours = hours;
|
|
8287
|
+
}
|
|
8288
|
+
if (opts.disputeResolver !== void 0) {
|
|
8289
|
+
body.disputeResolver = opts.disputeResolver;
|
|
8290
|
+
}
|
|
8291
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8292
|
+
`/api/tasks/${taskId}/evaluator`,
|
|
8293
|
+
body
|
|
8294
|
+
);
|
|
8295
|
+
printResult(result, { idempotencyKey });
|
|
8296
|
+
}
|
|
8297
|
+
);
|
|
8298
|
+
|
|
8299
|
+
// src/commands/task/evaluate.ts
|
|
8300
|
+
import { Command as Command32 } from "commander";
|
|
8301
|
+
var evaluateCmd = new Command32("evaluate").description("Submit an evaluation verdict for a task in Review state").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict: approve, reject, or partial").option("--score <n>", "Score 0-1000 (default: 1000)", "1000").option("--confidence <n>", "Confidence 0-1000 (default: 1000)", "1000").option("--evidence-hash <hash>", "Evidence hash (32-byte hex)").option(
|
|
7712
8302
|
"--award <worker:amount:rank>",
|
|
7713
8303
|
"Award entry (repeatable): worker:amountUSDC:rank",
|
|
7714
8304
|
collect,
|
|
@@ -7737,9 +8327,8 @@ var evaluateCmd = new Command31("evaluate").description("Submit an evaluation ve
|
|
|
7737
8327
|
try {
|
|
7738
8328
|
microUnits = usdcToBaseUnits(amountUSDC);
|
|
7739
8329
|
} catch (err) {
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
);
|
|
8330
|
+
renderFailure(withErrorContext(err, `Invalid amount in '${entry}'`));
|
|
8331
|
+
return;
|
|
7743
8332
|
}
|
|
7744
8333
|
const parsedRank = Number(rankStr);
|
|
7745
8334
|
if (!Number.isInteger(parsedRank) || parsedRank < 1) {
|
|
@@ -7762,8 +8351,11 @@ var evaluateCmd = new Command31("evaluate").description("Submit an evaluation ve
|
|
|
7762
8351
|
}
|
|
7763
8352
|
body.evidenceHash = opts.evidenceHash;
|
|
7764
8353
|
}
|
|
7765
|
-
const result = await x402Post(
|
|
7766
|
-
|
|
8354
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8355
|
+
`/api/tasks/${taskId}/evaluate`,
|
|
8356
|
+
body
|
|
8357
|
+
);
|
|
8358
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7767
8359
|
}
|
|
7768
8360
|
);
|
|
7769
8361
|
function collect(val, prev) {
|
|
@@ -7771,28 +8363,28 @@ function collect(val, prev) {
|
|
|
7771
8363
|
}
|
|
7772
8364
|
|
|
7773
8365
|
// src/commands/task/appeal.ts
|
|
7774
|
-
import { Command as
|
|
7775
|
-
var appealCmd = new
|
|
7776
|
-
const result = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
7777
|
-
printResult({ txHash: result.txHash });
|
|
8366
|
+
import { Command as Command33 } from "commander";
|
|
8367
|
+
var appealCmd = new Command33("appeal").description("Appeal an evaluator verdict while in Appealing state").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
8368
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
8369
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7778
8370
|
});
|
|
7779
8371
|
|
|
7780
8372
|
// src/commands/task/evaluator-timeout.ts
|
|
7781
|
-
import { Command as
|
|
7782
|
-
var evaluatorTimeoutCmd = new
|
|
7783
|
-
const result = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
7784
|
-
printResult({ txHash: result.txHash });
|
|
8373
|
+
import { Command as Command34 } from "commander";
|
|
8374
|
+
var evaluatorTimeoutCmd = new Command34("evaluator-timeout").description("Trigger evaluator timeout after the evaluation window expires (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
8375
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
8376
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7785
8377
|
});
|
|
7786
8378
|
|
|
7787
8379
|
// src/commands/task/finalize-verdict.ts
|
|
7788
|
-
import { Command as
|
|
7789
|
-
var finalizeVerdictCmd = new
|
|
7790
|
-
const result = await apiPost(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
7791
|
-
printResult({ txHash: result.txHash });
|
|
8380
|
+
import { Command as Command35 } from "commander";
|
|
8381
|
+
var finalizeVerdictCmd = new Command35("finalize-verdict").description("Finalize an evaluator verdict after the appeal window expires (permissionless)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
8382
|
+
const { data: result, idempotencyKey } = await apiPost(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
8383
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7792
8384
|
});
|
|
7793
8385
|
|
|
7794
8386
|
// src/commands/task/resolve-dispute.ts
|
|
7795
|
-
import { Command as
|
|
8387
|
+
import { Command as Command36 } from "commander";
|
|
7796
8388
|
function parseAward(spec) {
|
|
7797
8389
|
const parts = spec.split(":");
|
|
7798
8390
|
if (parts.length !== 3) {
|
|
@@ -7813,7 +8405,7 @@ function parseAward(spec) {
|
|
|
7813
8405
|
rank
|
|
7814
8406
|
};
|
|
7815
8407
|
}
|
|
7816
|
-
var resolveDisputeCmd = new
|
|
8408
|
+
var resolveDisputeCmd = new Command36("resolve-dispute").description(
|
|
7817
8409
|
"Resolve a disputed task as the designated dispute resolver (X402 required).\n\nExamples:\n task resolve-dispute 0x\u2026 --verdict approve --award 0xAlice:5:1\n task resolve-dispute 0x\u2026 --verdict partial --award 0xAlice:3:1 --award 0xBob:2:2"
|
|
7818
8410
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict type: approve or partial").requiredOption(
|
|
7819
8411
|
"--award <spec...>",
|
|
@@ -7827,76 +8419,80 @@ var resolveDisputeCmd = new Command35("resolve-dispute").description(
|
|
|
7827
8419
|
try {
|
|
7828
8420
|
awards = opts.award.map(parseAward);
|
|
7829
8421
|
} catch (err) {
|
|
7830
|
-
|
|
8422
|
+
renderFailure(err);
|
|
7831
8423
|
return;
|
|
7832
8424
|
}
|
|
7833
|
-
const result = await x402Post(
|
|
7834
|
-
taskId
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
|
|
8425
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8426
|
+
`/api/tasks/${taskId}/resolve-dispute`,
|
|
8427
|
+
{
|
|
8428
|
+
taskId,
|
|
8429
|
+
verdict: opts.verdict,
|
|
8430
|
+
awards
|
|
8431
|
+
}
|
|
8432
|
+
);
|
|
8433
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7839
8434
|
});
|
|
7840
8435
|
|
|
7841
8436
|
// src/commands/task/unlock.ts
|
|
7842
|
-
import { Command as
|
|
7843
|
-
var unlockCmd = new
|
|
8437
|
+
import { Command as Command37 } from "commander";
|
|
8438
|
+
var unlockCmd = new Command37("unlock").description("Unlock a private task with its password, caching a task-scoped access grant").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--password <password>", "The private task's password").action(async (taskId, opts) => {
|
|
7844
8439
|
let result;
|
|
8440
|
+
let idempotencyKey;
|
|
7845
8441
|
try {
|
|
7846
|
-
result = await apiPost(
|
|
7847
|
-
taskId
|
|
7848
|
-
password: opts.password
|
|
7849
|
-
|
|
8442
|
+
({ data: result, idempotencyKey } = await apiPost(
|
|
8443
|
+
`/api/tasks/${taskId}/private-access/verify`,
|
|
8444
|
+
{ taskId, password: opts.password }
|
|
8445
|
+
));
|
|
7850
8446
|
} catch (err) {
|
|
7851
|
-
|
|
8447
|
+
renderFailure(err, { fallback: "Failed to unlock task." });
|
|
7852
8448
|
return;
|
|
7853
8449
|
}
|
|
7854
8450
|
await saveTaskAccessGrant(taskId, result.grant, result.expiresAt);
|
|
7855
|
-
printResult({ taskId, expiresAt: result.expiresAt });
|
|
8451
|
+
printResult({ taskId, expiresAt: result.expiresAt }, { idempotencyKey });
|
|
7856
8452
|
});
|
|
7857
8453
|
|
|
7858
8454
|
// src/commands/task/invite.ts
|
|
7859
|
-
import { Command as
|
|
7860
|
-
var inviteCmd = new
|
|
8455
|
+
import { Command as Command38 } from "commander";
|
|
8456
|
+
var inviteCmd = new Command38("invite").description("Invite a wallet to view a private task (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").argument("<address>", "Wallet address to invite").action(async (taskId, address) => {
|
|
7861
8457
|
const auth = await signReadAuth();
|
|
7862
8458
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7863
8459
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
7864
8460
|
return;
|
|
7865
8461
|
}
|
|
7866
8462
|
try {
|
|
7867
|
-
const result = await apiPost(
|
|
8463
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
7868
8464
|
`/api/tasks/${taskId}/private-access/viewers`,
|
|
7869
8465
|
{ taskId, viewerAddress: address },
|
|
7870
8466
|
{ headers: auth.headers }
|
|
7871
8467
|
);
|
|
7872
|
-
printResult(result);
|
|
8468
|
+
printResult(result, { idempotencyKey });
|
|
7873
8469
|
} catch (err) {
|
|
7874
|
-
|
|
8470
|
+
renderFailure(err, { fallback: "Failed to invite viewer." });
|
|
7875
8471
|
}
|
|
7876
8472
|
});
|
|
7877
8473
|
|
|
7878
8474
|
// src/commands/task/uninvite.ts
|
|
7879
|
-
import { Command as
|
|
7880
|
-
var uninviteCmd = new
|
|
8475
|
+
import { Command as Command39 } from "commander";
|
|
8476
|
+
var uninviteCmd = new Command39("uninvite").description("Remove a wallet from a private task's allowlist (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").argument("<address>", "Wallet address to remove").action(async (taskId, address) => {
|
|
7881
8477
|
const auth = await signReadAuth();
|
|
7882
8478
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7883
8479
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
7884
8480
|
return;
|
|
7885
8481
|
}
|
|
7886
8482
|
try {
|
|
7887
|
-
const result = await apiDelete(
|
|
8483
|
+
const { data: result, idempotencyKey } = await apiDelete(
|
|
7888
8484
|
`/api/tasks/${taskId}/private-access/viewers/${encodeURIComponent(address)}`,
|
|
7889
8485
|
{ headers: auth.headers }
|
|
7890
8486
|
);
|
|
7891
|
-
printResult(result);
|
|
8487
|
+
printResult(result, { idempotencyKey });
|
|
7892
8488
|
} catch (err) {
|
|
7893
|
-
|
|
8489
|
+
renderFailure(err, { fallback: "Failed to remove viewer." });
|
|
7894
8490
|
}
|
|
7895
8491
|
});
|
|
7896
8492
|
|
|
7897
8493
|
// src/commands/task/viewers.ts
|
|
7898
|
-
import { Command as
|
|
7899
|
-
var viewersCmd = new
|
|
8494
|
+
import { Command as Command40 } from "commander";
|
|
8495
|
+
var viewersCmd = new Command40("viewers").description("List a private task's wallet allowlist (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
7900
8496
|
const auth = await signReadAuth();
|
|
7901
8497
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7902
8498
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -7908,12 +8504,12 @@ var viewersCmd = new Command39("viewers").description("List a private task's wal
|
|
|
7908
8504
|
});
|
|
7909
8505
|
printResult(result);
|
|
7910
8506
|
} catch (err) {
|
|
7911
|
-
|
|
8507
|
+
renderFailure(err, { fallback: "Failed to list viewers." });
|
|
7912
8508
|
}
|
|
7913
8509
|
});
|
|
7914
8510
|
|
|
7915
8511
|
// src/commands/task/index.ts
|
|
7916
|
-
var taskCommand = new
|
|
8512
|
+
var taskCommand = new Command41("task").description("Manage tasks");
|
|
7917
8513
|
taskCommand.addCommand(createCmd);
|
|
7918
8514
|
taskCommand.addCommand(listCmd);
|
|
7919
8515
|
taskCommand.addCommand(getCmd);
|
|
@@ -7939,6 +8535,7 @@ taskCommand.addCommand(rejectAllSubmissionsCmd);
|
|
|
7939
8535
|
taskCommand.addCommand(mySubmissionsCmd);
|
|
7940
8536
|
taskCommand.addCommand(updateCmd);
|
|
7941
8537
|
taskCommand.addCommand(forfeitCmd);
|
|
8538
|
+
taskCommand.addCommand(assignEvaluatorCmd);
|
|
7942
8539
|
taskCommand.addCommand(evaluateCmd);
|
|
7943
8540
|
taskCommand.addCommand(appealCmd);
|
|
7944
8541
|
taskCommand.addCommand(evaluatorTimeoutCmd);
|
|
@@ -7950,8 +8547,8 @@ taskCommand.addCommand(uninviteCmd);
|
|
|
7950
8547
|
taskCommand.addCommand(viewersCmd);
|
|
7951
8548
|
|
|
7952
8549
|
// src/commands/agents.ts
|
|
7953
|
-
import { Command as
|
|
7954
|
-
var agentsCommand = new
|
|
8550
|
+
import { Command as Command42 } from "commander";
|
|
8551
|
+
var agentsCommand = new Command42("agents").description("Browse the agent directory").option("--sort <order>", "Sort order: reputation or tasks", "reputation").option("--skill <tag>", "Filter by skill tag").option("--search <query>", "Search by agentId or wallet address").option("--limit <n>", "Maximum results to return", "20").action(async (opts) => {
|
|
7955
8552
|
const params = new URLSearchParams();
|
|
7956
8553
|
if (opts.sort) params.set("sort", opts.sort);
|
|
7957
8554
|
if (opts.skill) params.set("skill", opts.skill);
|
|
@@ -7962,11 +8559,12 @@ var agentsCommand = new Command41("agents").description("Browse the agent direct
|
|
|
7962
8559
|
});
|
|
7963
8560
|
|
|
7964
8561
|
// src/commands/inbox.ts
|
|
7965
|
-
import { Command as
|
|
7966
|
-
var inboxCommand = new
|
|
8562
|
+
import { Command as Command43 } from "commander";
|
|
8563
|
+
var inboxCommand = new Command43("inbox").description("Show tasks you created and tasks you are working on").action(async () => {
|
|
7967
8564
|
const auth = await signReadAuth();
|
|
7968
8565
|
if (!auth) {
|
|
7969
8566
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8567
|
+
return;
|
|
7970
8568
|
}
|
|
7971
8569
|
const address = auth.walletAddress;
|
|
7972
8570
|
const hasReadAuth = Object.keys(auth.headers).length > 0;
|
|
@@ -7982,23 +8580,38 @@ var inboxCommand = new Command42("inbox").description("Show tasks you created an
|
|
|
7982
8580
|
printResult({ ...taskResult, pendingBids });
|
|
7983
8581
|
});
|
|
7984
8582
|
|
|
8583
|
+
// src/commands/actions.ts
|
|
8584
|
+
import { Command as Command44 } from "commander";
|
|
8585
|
+
var actionsCommand = new Command44("actions").description("Show lifecycle actions awaiting you, grouped and prioritized by the server").action(async () => {
|
|
8586
|
+
const auth = await signReadAuth();
|
|
8587
|
+
if (!auth) {
|
|
8588
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
8589
|
+
return;
|
|
8590
|
+
}
|
|
8591
|
+
const params = new URLSearchParams({ address: auth.walletAddress });
|
|
8592
|
+
const queue = await apiGet(`/api/agents/action-queue?${params.toString()}`, {
|
|
8593
|
+
headers: auth.headers
|
|
8594
|
+
});
|
|
8595
|
+
printResult(queue);
|
|
8596
|
+
});
|
|
8597
|
+
|
|
7985
8598
|
// src/commands/deposit.ts
|
|
7986
|
-
import { Command as
|
|
7987
|
-
var depositCommand = new
|
|
8599
|
+
import { Command as Command45 } from "commander";
|
|
8600
|
+
var depositCommand = new Command45("deposit").description("Show wallet address and network info for funding").action(async () => {
|
|
7988
8601
|
let address;
|
|
7989
8602
|
try {
|
|
7990
8603
|
address = await getWalletAddress();
|
|
7991
8604
|
} catch (err) {
|
|
7992
|
-
|
|
7993
|
-
|
|
8605
|
+
renderFailure(err, { fallback: "No keystore found. Run `taskmarket init` first." });
|
|
8606
|
+
return;
|
|
7994
8607
|
}
|
|
7995
8608
|
let networkInfo;
|
|
7996
8609
|
try {
|
|
7997
8610
|
const response = await apiGet("/trpc/network.info");
|
|
7998
8611
|
networkInfo = response.result.data;
|
|
7999
8612
|
} catch (err) {
|
|
8000
|
-
|
|
8001
|
-
|
|
8613
|
+
renderFailure(err, { fallback: "Failed to fetch network info from backend." });
|
|
8614
|
+
return;
|
|
8002
8615
|
}
|
|
8003
8616
|
const data = {
|
|
8004
8617
|
address,
|
|
@@ -8011,11 +8624,11 @@ var depositCommand = new Command43("deposit").description("Show wallet address a
|
|
|
8011
8624
|
});
|
|
8012
8625
|
|
|
8013
8626
|
// src/commands/wallet/index.ts
|
|
8014
|
-
import { Command as
|
|
8627
|
+
import { Command as Command51 } from "commander";
|
|
8015
8628
|
|
|
8016
8629
|
// src/commands/wallet/balance.ts
|
|
8017
|
-
import { Command as
|
|
8018
|
-
var walletBalanceCommand = new
|
|
8630
|
+
import { Command as Command46 } from "commander";
|
|
8631
|
+
var walletBalanceCommand = new Command46("balance").description("Show USDC balance").option("--address <addr>", "Address to check (defaults to own wallet)").action(async (opts) => {
|
|
8019
8632
|
let address = opts.address;
|
|
8020
8633
|
if (!address) {
|
|
8021
8634
|
const keystore = await loadKeystore();
|
|
@@ -8026,7 +8639,7 @@ var walletBalanceCommand = new Command44("balance").description("Show USDC balan
|
|
|
8026
8639
|
});
|
|
8027
8640
|
|
|
8028
8641
|
// src/commands/wallet/import.ts
|
|
8029
|
-
import { Command as
|
|
8642
|
+
import { Command as Command47 } from "commander";
|
|
8030
8643
|
import { createInterface as createInterface2 } from "readline";
|
|
8031
8644
|
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
8032
8645
|
function normalizePrivateKey(raw) {
|
|
@@ -8061,7 +8674,7 @@ function promptHiddenInput(prompt) {
|
|
|
8061
8674
|
});
|
|
8062
8675
|
});
|
|
8063
8676
|
}
|
|
8064
|
-
var walletImportCommand = new
|
|
8677
|
+
var walletImportCommand = new Command47("import").description("Import an existing private key as the agent wallet").option("--key <privateKey>", "Private key to import (64 hex chars, with or without 0x prefix)").option(
|
|
8065
8678
|
"--yes",
|
|
8066
8679
|
"Confirm legal acceptance non-interactively after reviewing every current policy"
|
|
8067
8680
|
).action(async (opts) => {
|
|
@@ -8140,69 +8753,77 @@ var walletImportCommand = new Command45("import").description("Import an existin
|
|
|
8140
8753
|
});
|
|
8141
8754
|
|
|
8142
8755
|
// src/commands/wallet/set-withdrawal-address.ts
|
|
8143
|
-
import { Command as
|
|
8756
|
+
import { Command as Command48 } from "commander";
|
|
8144
8757
|
function isValidAddress(addr) {
|
|
8145
8758
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8146
8759
|
}
|
|
8147
|
-
var setWithdrawalAddressCommand = new
|
|
8760
|
+
var setWithdrawalAddressCommand = new Command48("set-withdrawal-address").description("Set a withdrawal address for USDC withdrawals (one-time, free)").argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
|
|
8148
8761
|
if (!isValidAddress(address)) {
|
|
8149
8762
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
8763
|
+
return;
|
|
8150
8764
|
}
|
|
8151
8765
|
let keystore;
|
|
8152
8766
|
try {
|
|
8153
8767
|
keystore = await loadKeystore();
|
|
8154
8768
|
} catch {
|
|
8155
8769
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8770
|
+
return;
|
|
8156
8771
|
}
|
|
8157
8772
|
const walletAddress = keystore.walletAddress;
|
|
8158
8773
|
const message = buildSetWithdrawalAddressMessage(address);
|
|
8159
8774
|
const signature = await signMessage(message, keystore);
|
|
8160
|
-
const result = await apiPost(
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8775
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8776
|
+
"/api/wallet/set-withdrawal-address",
|
|
8777
|
+
{
|
|
8778
|
+
walletAddress,
|
|
8779
|
+
withdrawalAddress: address,
|
|
8780
|
+
signature
|
|
8781
|
+
}
|
|
8782
|
+
);
|
|
8783
|
+
printResult({ withdrawalAddress: result.withdrawalAddress }, { idempotencyKey });
|
|
8166
8784
|
});
|
|
8167
8785
|
|
|
8168
8786
|
// src/commands/wallet/publish-key.ts
|
|
8169
|
-
import { Command as
|
|
8170
|
-
var publishKeyCommand = new
|
|
8787
|
+
import { Command as Command49 } from "commander";
|
|
8788
|
+
var publishKeyCommand = new Command49("publish-key").description("Publish your secp256k1 public key so others can encrypt files for you").action(async () => {
|
|
8171
8789
|
let keystore;
|
|
8172
8790
|
try {
|
|
8173
8791
|
keystore = await loadKeystore();
|
|
8174
8792
|
} catch {
|
|
8175
8793
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8794
|
+
return;
|
|
8176
8795
|
}
|
|
8177
8796
|
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
8178
8797
|
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
8179
8798
|
const publicKey = deriveCompressedPublicKey(privateKey);
|
|
8180
|
-
const result = await apiPost("/trpc/agents.setPublicKey", {
|
|
8799
|
+
const { data: result, idempotencyKey } = await apiPost("/trpc/agents.setPublicKey", {
|
|
8181
8800
|
deviceId: keystore.deviceId,
|
|
8182
8801
|
apiToken: keystore.apiToken,
|
|
8183
8802
|
publicKey
|
|
8184
8803
|
});
|
|
8185
|
-
printResult({ publicKey: result.result.data.publicKey });
|
|
8804
|
+
printResult({ publicKey: result.result.data.publicKey }, { idempotencyKey });
|
|
8186
8805
|
});
|
|
8187
8806
|
|
|
8188
8807
|
// src/commands/wallet/withdraw-dreams.ts
|
|
8189
|
-
import { Command as
|
|
8808
|
+
import { Command as Command50 } from "commander";
|
|
8190
8809
|
import { toHex as toHex2 } from "viem";
|
|
8191
8810
|
var AUTHORIZATION_VALIDITY_SECONDS = 300;
|
|
8192
8811
|
function isValidAddress2(addr) {
|
|
8193
8812
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8194
8813
|
}
|
|
8195
|
-
var withdrawDreamsCommand = new
|
|
8814
|
+
var withdrawDreamsCommand = new Command50("withdraw-dreams").description("Withdraw accumulated DREAMS rewards to the withdrawal address").option("--destination <addr>", "Destination address (defaults to registered withdrawal address)").action(async (opts) => {
|
|
8196
8815
|
let keystore;
|
|
8197
8816
|
try {
|
|
8198
8817
|
keystore = await loadKeystore();
|
|
8199
8818
|
} catch {
|
|
8200
8819
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8820
|
+
return;
|
|
8201
8821
|
}
|
|
8202
8822
|
const workerAddress = keystore.walletAddress;
|
|
8203
8823
|
let destination = opts.destination;
|
|
8204
8824
|
if (destination !== void 0 && !isValidAddress2(destination)) {
|
|
8205
8825
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
8826
|
+
return;
|
|
8206
8827
|
}
|
|
8207
8828
|
if (!destination) {
|
|
8208
8829
|
const addressResponse = await apiGet(
|
|
@@ -8212,6 +8833,7 @@ var withdrawDreamsCommand = new Command48("withdraw-dreams").description("Withdr
|
|
|
8212
8833
|
printError(
|
|
8213
8834
|
"No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
|
|
8214
8835
|
);
|
|
8836
|
+
return;
|
|
8215
8837
|
}
|
|
8216
8838
|
destination = addressResponse.withdrawalAddress;
|
|
8217
8839
|
}
|
|
@@ -8219,25 +8841,31 @@ var withdrawDreamsCommand = new Command48("withdraw-dreams").description("Withdr
|
|
|
8219
8841
|
const validBefore = String(Math.floor(Date.now() / 1e3) + AUTHORIZATION_VALIDITY_SECONDS);
|
|
8220
8842
|
const message = buildWithdrawDreamsMessage(destination, nonce, validBefore);
|
|
8221
8843
|
const signature = await signMessage(message, keystore);
|
|
8222
|
-
const result = await apiPost(
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8844
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8845
|
+
"/api/wallet/withdraw-dreams",
|
|
8846
|
+
{
|
|
8847
|
+
workerAddress,
|
|
8848
|
+
destination,
|
|
8849
|
+
nonce,
|
|
8850
|
+
validBefore,
|
|
8851
|
+
signature
|
|
8852
|
+
}
|
|
8853
|
+
);
|
|
8854
|
+
printResult(
|
|
8855
|
+
{
|
|
8856
|
+
txHash: result.txHash,
|
|
8857
|
+
destination: result.destination,
|
|
8858
|
+
claimedBaseUnits: result.claimedBaseUnits,
|
|
8859
|
+
claimedDreams: formatDreams(result.claimedBaseUnits),
|
|
8860
|
+
dreamsPerUsdc: result.dreamsPerUsdc,
|
|
8861
|
+
usdEquivalent: result.usdEquivalent
|
|
8862
|
+
},
|
|
8863
|
+
{ idempotencyKey }
|
|
8864
|
+
);
|
|
8237
8865
|
});
|
|
8238
8866
|
|
|
8239
8867
|
// src/commands/wallet/index.ts
|
|
8240
|
-
var walletCommand = new
|
|
8868
|
+
var walletCommand = new Command51("wallet").description("Wallet management commands");
|
|
8241
8869
|
walletCommand.addCommand(walletBalanceCommand);
|
|
8242
8870
|
walletCommand.addCommand(walletImportCommand);
|
|
8243
8871
|
walletCommand.addCommand(setWithdrawalAddressCommand);
|
|
@@ -8245,7 +8873,7 @@ walletCommand.addCommand(publishKeyCommand);
|
|
|
8245
8873
|
walletCommand.addCommand(withdrawDreamsCommand);
|
|
8246
8874
|
|
|
8247
8875
|
// src/commands/withdraw.ts
|
|
8248
|
-
import { Command as
|
|
8876
|
+
import { Command as Command52 } from "commander";
|
|
8249
8877
|
import { toHex as toHex3 } from "viem";
|
|
8250
8878
|
var USDC_TYPES = {
|
|
8251
8879
|
TransferWithAuthorization: [
|
|
@@ -8257,10 +8885,11 @@ var USDC_TYPES = {
|
|
|
8257
8885
|
{ name: "nonce", type: "bytes32" }
|
|
8258
8886
|
]
|
|
8259
8887
|
};
|
|
8260
|
-
var withdrawCommand = new
|
|
8888
|
+
var withdrawCommand = new Command52("withdraw").description("Withdraw USDC to the registered withdrawal address").argument("<amount>", "Amount in USDC (e.g. 5 for 5 USDC)").action(async (amount) => {
|
|
8261
8889
|
const parsed = parseFloat(amount);
|
|
8262
8890
|
if (isNaN(parsed) || parsed <= 0) {
|
|
8263
8891
|
printError("Invalid amount: must be a positive number (e.g. 5 for 5 USDC)");
|
|
8892
|
+
return;
|
|
8264
8893
|
}
|
|
8265
8894
|
const amountBaseUnits = String(Math.round(parsed * 1e6));
|
|
8266
8895
|
let keystore;
|
|
@@ -8268,6 +8897,7 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8268
8897
|
keystore = await loadKeystore();
|
|
8269
8898
|
} catch {
|
|
8270
8899
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8900
|
+
return;
|
|
8271
8901
|
}
|
|
8272
8902
|
const from = keystore.walletAddress;
|
|
8273
8903
|
const addressResponse = await apiGet(
|
|
@@ -8277,6 +8907,7 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8277
8907
|
printError(
|
|
8278
8908
|
"No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
|
|
8279
8909
|
);
|
|
8910
|
+
return;
|
|
8280
8911
|
}
|
|
8281
8912
|
const { withdrawalAddress, usdcDomain } = addressResponse;
|
|
8282
8913
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -8297,30 +8928,38 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8297
8928
|
},
|
|
8298
8929
|
keystore
|
|
8299
8930
|
);
|
|
8300
|
-
const result = await apiPost(
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8931
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8932
|
+
"/api/wallet/withdraw",
|
|
8933
|
+
{
|
|
8934
|
+
from,
|
|
8935
|
+
amountBaseUnits,
|
|
8936
|
+
authorization,
|
|
8937
|
+
signature
|
|
8938
|
+
}
|
|
8939
|
+
);
|
|
8940
|
+
printResult(
|
|
8941
|
+
{ txHash: result.txHash, amountBaseUnits: result.amountBaseUnits, to: result.to },
|
|
8942
|
+
{ idempotencyKey }
|
|
8943
|
+
);
|
|
8307
8944
|
});
|
|
8308
8945
|
|
|
8309
8946
|
// src/commands/encrypt.ts
|
|
8310
|
-
import { Command as
|
|
8947
|
+
import { Command as Command53 } from "commander";
|
|
8311
8948
|
import { promises as fs3 } from "fs";
|
|
8312
|
-
var encryptCommand = new
|
|
8949
|
+
var encryptCommand = new Command53("encrypt").description("Encrypt a file with ECIES using wallet keys").argument("<file>", "Path to the file to encrypt").option("--recipient <address>", "Recipient wallet address (default: self)").option("--output <path>", "Output path (default: <file>.enc)").action(async (file, opts) => {
|
|
8313
8950
|
let plaintext;
|
|
8314
8951
|
try {
|
|
8315
8952
|
plaintext = await fs3.readFile(file);
|
|
8316
8953
|
} catch {
|
|
8317
8954
|
printError(`Cannot read file: ${file}`);
|
|
8955
|
+
return;
|
|
8318
8956
|
}
|
|
8319
8957
|
let keystore;
|
|
8320
8958
|
try {
|
|
8321
8959
|
keystore = await loadKeystore();
|
|
8322
8960
|
} catch {
|
|
8323
8961
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8962
|
+
return;
|
|
8324
8963
|
}
|
|
8325
8964
|
let recipientPubKey;
|
|
8326
8965
|
let recipientAddress;
|
|
@@ -8333,12 +8972,9 @@ var encryptCommand = new Command51("encrypt").description("Encrypt a file with E
|
|
|
8333
8972
|
);
|
|
8334
8973
|
} catch (err) {
|
|
8335
8974
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
);
|
|
8340
|
-
}
|
|
8341
|
-
printError(`Failed to fetch recipient public key: ${msg}`);
|
|
8975
|
+
const context = msg.includes("publish their public key") || msg.includes("NOT_FOUND") ? "Recipient has not published their public key. Ask them to run: taskmarket wallet publish-key" : "Failed to fetch recipient public key";
|
|
8976
|
+
renderFailure(withErrorContext(err, context));
|
|
8977
|
+
return;
|
|
8342
8978
|
}
|
|
8343
8979
|
recipientPubKey = result.result.data.publicKey;
|
|
8344
8980
|
} else {
|
|
@@ -8358,20 +8994,22 @@ var encryptCommand = new Command51("encrypt").description("Encrypt a file with E
|
|
|
8358
8994
|
});
|
|
8359
8995
|
|
|
8360
8996
|
// src/commands/decrypt.ts
|
|
8361
|
-
import { Command as
|
|
8997
|
+
import { Command as Command54 } from "commander";
|
|
8362
8998
|
import { promises as fs4 } from "fs";
|
|
8363
|
-
var decryptCommand = new
|
|
8999
|
+
var decryptCommand = new Command54("decrypt").description("Decrypt a file using your wallet key").argument("<file>", "Path to the encrypted file").option("--output <path>", "Output path (default: strips .enc, otherwise appends .dec)").action(async (file, opts) => {
|
|
8364
9000
|
let ciphertext;
|
|
8365
9001
|
try {
|
|
8366
9002
|
ciphertext = await fs4.readFile(file);
|
|
8367
9003
|
} catch {
|
|
8368
9004
|
printError(`Cannot read file: ${file}`);
|
|
9005
|
+
return;
|
|
8369
9006
|
}
|
|
8370
9007
|
let keystore;
|
|
8371
9008
|
try {
|
|
8372
9009
|
keystore = await loadKeystore();
|
|
8373
9010
|
} catch {
|
|
8374
9011
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
9012
|
+
return;
|
|
8375
9013
|
}
|
|
8376
9014
|
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
8377
9015
|
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
@@ -8379,8 +9017,8 @@ var decryptCommand = new Command52("decrypt").description("Decrypt a file using
|
|
|
8379
9017
|
try {
|
|
8380
9018
|
plaintext = decryptWithPrivateKey(ciphertext, privateKey);
|
|
8381
9019
|
} catch (err) {
|
|
8382
|
-
|
|
8383
|
-
|
|
9020
|
+
renderFailure(err);
|
|
9021
|
+
return;
|
|
8384
9022
|
}
|
|
8385
9023
|
let outputPath;
|
|
8386
9024
|
if (opts.output) {
|
|
@@ -8398,21 +9036,21 @@ var decryptCommand = new Command52("decrypt").description("Decrypt a file using
|
|
|
8398
9036
|
});
|
|
8399
9037
|
|
|
8400
9038
|
// src/commands/xmtp.ts
|
|
8401
|
-
import { Command as
|
|
9039
|
+
import { Command as Command55 } from "commander";
|
|
8402
9040
|
|
|
8403
9041
|
// src/lib/xmtp-client.ts
|
|
8404
9042
|
import os3 from "os";
|
|
8405
9043
|
import path3 from "path";
|
|
8406
|
-
import { randomUUID as
|
|
9044
|
+
import { randomUUID as randomUUID3, hkdfSync as hkdfSync2 } from "crypto";
|
|
8407
9045
|
import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
|
|
8408
9046
|
|
|
8409
9047
|
// src/lib/xmtp-envelope.ts
|
|
8410
|
-
import { randomUUID } from "crypto";
|
|
9048
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
8411
9049
|
function buildEnvelope(input) {
|
|
8412
9050
|
return AgentMessageEnvelopeSchema.parse({
|
|
8413
9051
|
schemaVersion: 1,
|
|
8414
9052
|
type: input.type,
|
|
8415
|
-
requestId: input.requestId ??
|
|
9053
|
+
requestId: input.requestId ?? randomUUID2(),
|
|
8416
9054
|
replyToRequestId: input.replyToRequestId,
|
|
8417
9055
|
senderInboxId: input.senderInboxId,
|
|
8418
9056
|
senderAddress: input.senderAddress,
|
|
@@ -8565,7 +9203,7 @@ function defaultDbPath(walletAddress) {
|
|
|
8565
9203
|
}
|
|
8566
9204
|
async function createDevClient(input) {
|
|
8567
9205
|
const inboxId = input.existingInboxId ?? `dev-inbox-${input.walletAddress.slice(2, 10).toLowerCase()}`;
|
|
8568
|
-
const installationId = input.existingInstallationId ??
|
|
9206
|
+
const installationId = input.existingInstallationId ?? randomUUID3();
|
|
8569
9207
|
const dbPath = input.existingDbPath ?? defaultDbPath(input.walletAddress);
|
|
8570
9208
|
return {
|
|
8571
9209
|
inboxId,
|
|
@@ -8994,7 +9632,7 @@ async function createProductionClient(input) {
|
|
|
8994
9632
|
"non-retryable"
|
|
8995
9633
|
);
|
|
8996
9634
|
}
|
|
8997
|
-
const installationId = extractString(client, ["installationId", "installationID"]) ?? extractString(asObject(client)?.installation, ["id", "installationId"]) ?? input.existingInstallationId ??
|
|
9635
|
+
const installationId = extractString(client, ["installationId", "installationID"]) ?? extractString(asObject(client)?.installation, ["id", "installationId"]) ?? input.existingInstallationId ?? randomUUID3();
|
|
8998
9636
|
return {
|
|
8999
9637
|
inboxId,
|
|
9000
9638
|
installationId,
|
|
@@ -9162,7 +9800,7 @@ function getDefaultQueryTimeoutMs() {
|
|
|
9162
9800
|
}
|
|
9163
9801
|
return Math.floor(parsed);
|
|
9164
9802
|
}
|
|
9165
|
-
var xmtpCommand = new
|
|
9803
|
+
var xmtpCommand = new Command55("xmtp").description("Manage XMTP messaging for this agent");
|
|
9166
9804
|
xmtpCommand.command("init").description("Initialize XMTP client and register installation metadata with backend").action(async () => {
|
|
9167
9805
|
const keystore = await loadKeystore();
|
|
9168
9806
|
const client = await createXmtpClient({
|
|
@@ -9172,7 +9810,7 @@ xmtpCommand.command("init").description("Initialize XMTP client and register ins
|
|
|
9172
9810
|
existingDbPath: keystore.xmtpDbPath,
|
|
9173
9811
|
keystore
|
|
9174
9812
|
});
|
|
9175
|
-
const status = await apiPost("/api/xmtp/bootstrap", {
|
|
9813
|
+
const { data: status, idempotencyKey } = await apiPost("/api/xmtp/bootstrap", {
|
|
9176
9814
|
deviceId: keystore.deviceId,
|
|
9177
9815
|
apiToken: keystore.apiToken,
|
|
9178
9816
|
inboxId: client.inboxId,
|
|
@@ -9186,7 +9824,7 @@ xmtpCommand.command("init").description("Initialize XMTP client and register ins
|
|
|
9186
9824
|
xmtpInstallationId: status.installationId,
|
|
9187
9825
|
xmtpDbPath: client.dbPath
|
|
9188
9826
|
});
|
|
9189
|
-
printResult({ policyMode: status.policyMode });
|
|
9827
|
+
printResult({ policyMode: status.policyMode }, { idempotencyKey });
|
|
9190
9828
|
});
|
|
9191
9829
|
xmtpCommand.command("status").description("Check XMTP status and active installation state").action(async () => {
|
|
9192
9830
|
const keystore = await loadKeystore();
|
|
@@ -9299,12 +9937,15 @@ xmtpCommand.command("heartbeat").description("Send a one-shot heartbeat to keep
|
|
|
9299
9937
|
if (!keystore.xmtpInstallationId) {
|
|
9300
9938
|
throw new Error("XMTP not initialized. Run `taskmarket xmtp init` first.");
|
|
9301
9939
|
}
|
|
9302
|
-
const result = await apiPost(
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9940
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
9941
|
+
"/api/xmtp/heartbeat",
|
|
9942
|
+
{
|
|
9943
|
+
deviceId: keystore.deviceId,
|
|
9944
|
+
apiToken: keystore.apiToken,
|
|
9945
|
+
installationId: keystore.xmtpInstallationId
|
|
9946
|
+
}
|
|
9947
|
+
);
|
|
9948
|
+
printResult(result, { idempotencyKey });
|
|
9308
9949
|
});
|
|
9309
9950
|
var peersCommand = xmtpCommand.command("peers").description("Manage taskmarket peer messaging policies");
|
|
9310
9951
|
peersCommand.command("list").description("List per-peer messaging policies stored on the backend").action(async () => {
|
|
@@ -9322,14 +9963,17 @@ peersCommand.command("set").description("Set messaging policy for a specific pee
|
|
|
9322
9963
|
}
|
|
9323
9964
|
const keystore = await loadKeystore();
|
|
9324
9965
|
const peerInboxId = await resolveInboxId(options.to);
|
|
9325
|
-
const result = await apiPost(
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9966
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
9967
|
+
"/api/xmtp/peers",
|
|
9968
|
+
{
|
|
9969
|
+
deviceId: keystore.deviceId,
|
|
9970
|
+
apiToken: keystore.apiToken,
|
|
9971
|
+
peerInboxId,
|
|
9972
|
+
policy: options.policy,
|
|
9973
|
+
reason: options.reason
|
|
9974
|
+
}
|
|
9975
|
+
);
|
|
9976
|
+
printResult(result, { idempotencyKey });
|
|
9333
9977
|
});
|
|
9334
9978
|
var allowlistCommand = xmtpCommand.command("allowlist").description("Manage XMTP SDK consent allowlist (protocol-level)");
|
|
9335
9979
|
allowlistCommand.command("add").description("Allow messages from a peer inbox (XMTP SDK consent)").requiredOption("--to <agentIdOrAddrOrInboxId>", "Target agent ID, wallet address, or inboxId").action(async (options) => {
|
|
@@ -9382,15 +10026,18 @@ allowlistCommand.command("check").description("Check the XMTP SDK consent state
|
|
|
9382
10026
|
});
|
|
9383
10027
|
xmtpCommand.command("purge").description("Revoke stale XMTP installations that have missed heartbeats").action(async () => {
|
|
9384
10028
|
const keystore = await loadKeystore();
|
|
9385
|
-
const result = await apiPost(
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
|
|
10029
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10030
|
+
"/api/xmtp/purge",
|
|
10031
|
+
{
|
|
10032
|
+
deviceId: keystore.deviceId,
|
|
10033
|
+
apiToken: keystore.apiToken
|
|
10034
|
+
}
|
|
10035
|
+
);
|
|
10036
|
+
printResult(result, { idempotencyKey });
|
|
9390
10037
|
});
|
|
9391
10038
|
|
|
9392
10039
|
// src/commands/daemon.ts
|
|
9393
|
-
import { Command as
|
|
10040
|
+
import { Command as Command56 } from "commander";
|
|
9394
10041
|
function diffTaskStatuses(prev, next) {
|
|
9395
10042
|
const changes = [];
|
|
9396
10043
|
for (const [taskId, newStatus] of next) {
|
|
@@ -9418,7 +10065,7 @@ function sleepOrAbort(ms, signal) {
|
|
|
9418
10065
|
});
|
|
9419
10066
|
}
|
|
9420
10067
|
var MAX_SEEN_TASK_IDS = 2e3;
|
|
9421
|
-
var daemonCommand = new
|
|
10068
|
+
var daemonCommand = new Command56("daemon").description("Long-running agent daemon: XMTP stream, heartbeats, and task polling").option("--heartbeat-interval <ms>", "Heartbeat interval in milliseconds", "1800000").option("--inbox-interval <ms>", "Inbox poll interval in milliseconds", "15000").option("--task-interval <ms>", "New task poll interval in milliseconds", "15000").option(
|
|
9422
10069
|
"--auction-poll-interval <ms>",
|
|
9423
10070
|
"Poll interval for clock-based auction tasks (dutch/reverse_dutch) in milliseconds",
|
|
9424
10071
|
"15000"
|
|
@@ -9502,12 +10149,15 @@ var daemonCommand = new Command54("daemon").description("Long-running agent daem
|
|
|
9502
10149
|
await sleepOrAbort(heartbeatIntervalMs, abortController.signal);
|
|
9503
10150
|
if (stopped) break;
|
|
9504
10151
|
try {
|
|
9505
|
-
await apiPost("/trpc/xmtp.heartbeat", {
|
|
10152
|
+
const { idempotencyKey } = await apiPost("/trpc/xmtp.heartbeat", {
|
|
9506
10153
|
deviceId: keystore.deviceId,
|
|
9507
10154
|
apiToken: keystore.apiToken,
|
|
9508
10155
|
installationId: client.installationId
|
|
9509
10156
|
});
|
|
9510
|
-
printResult(
|
|
10157
|
+
printResult(
|
|
10158
|
+
{ event: "xmtp.heartbeat", installationId: client.installationId },
|
|
10159
|
+
{ idempotencyKey }
|
|
10160
|
+
);
|
|
9511
10161
|
} catch (err) {
|
|
9512
10162
|
process.stderr.write(
|
|
9513
10163
|
`Heartbeat failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -9739,29 +10389,33 @@ var daemonCommand = new Command54("daemon").description("Long-running agent daem
|
|
|
9739
10389
|
);
|
|
9740
10390
|
|
|
9741
10391
|
// src/commands/email/index.ts
|
|
9742
|
-
import { Command as
|
|
10392
|
+
import { Command as Command65 } from "commander";
|
|
9743
10393
|
|
|
9744
10394
|
// src/commands/email/register.ts
|
|
9745
|
-
import { Command as
|
|
9746
|
-
var registerCommand = new
|
|
10395
|
+
import { Command as Command57 } from "commander";
|
|
10396
|
+
var registerCommand = new Command57("register").description("Register an email address for this agent").requiredOption("--username <name>", "Desired username (e.g. myagent)").action(async (opts) => {
|
|
9747
10397
|
const check = await apiGet(
|
|
9748
10398
|
`/api/emails/check-username?username=${encodeURIComponent(opts.username)}`
|
|
9749
10399
|
);
|
|
9750
10400
|
if (!check.available) {
|
|
9751
10401
|
printError(`Username "${opts.username}" is not available.`);
|
|
10402
|
+
return;
|
|
9752
10403
|
}
|
|
9753
10404
|
const keystore = await loadKeystore();
|
|
9754
|
-
const result = await apiPost(
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
10405
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10406
|
+
"/api/emails/register",
|
|
10407
|
+
{
|
|
10408
|
+
deviceId: keystore.deviceId,
|
|
10409
|
+
apiToken: keystore.apiToken,
|
|
10410
|
+
username: opts.username
|
|
10411
|
+
}
|
|
10412
|
+
);
|
|
10413
|
+
printResult({ emailAddress: result.emailAddress }, { idempotencyKey });
|
|
9760
10414
|
});
|
|
9761
10415
|
|
|
9762
10416
|
// src/commands/email/inbox.ts
|
|
9763
|
-
import { Command as
|
|
9764
|
-
var inboxCommand2 = new
|
|
10417
|
+
import { Command as Command58 } from "commander";
|
|
10418
|
+
var inboxCommand2 = new Command58("inbox").description("List emails in your inbox").option("--limit <n>", "Number of emails to return", "20").option("--unread", "Show only unread emails").action(async (opts) => {
|
|
9765
10419
|
const keystore = await loadKeystore();
|
|
9766
10420
|
const params = new URLSearchParams({
|
|
9767
10421
|
deviceId: keystore.deviceId,
|
|
@@ -9776,8 +10430,8 @@ var inboxCommand2 = new Command56("inbox").description("List emails in your inbo
|
|
|
9776
10430
|
});
|
|
9777
10431
|
|
|
9778
10432
|
// src/commands/email/read.ts
|
|
9779
|
-
import { Command as
|
|
9780
|
-
var readCommand = new
|
|
10433
|
+
import { Command as Command59 } from "commander";
|
|
10434
|
+
var readCommand = new Command59("read").description("Read an email by ID (marks it as read)").argument("<id>", "Email ID").action(async (id) => {
|
|
9781
10435
|
const keystore = await loadKeystore();
|
|
9782
10436
|
const params = new URLSearchParams({
|
|
9783
10437
|
deviceId: keystore.deviceId,
|
|
@@ -9789,22 +10443,22 @@ var readCommand = new Command57("read").description("Read an email by ID (marks
|
|
|
9789
10443
|
});
|
|
9790
10444
|
|
|
9791
10445
|
// src/commands/email/send.ts
|
|
9792
|
-
import { Command as
|
|
9793
|
-
var sendCommand = new
|
|
10446
|
+
import { Command as Command60 } from "commander";
|
|
10447
|
+
var sendCommand = new Command60("send").description("Send an email").requiredOption("--to <address>", "Recipient email address").requiredOption("--subject <subject>", "Email subject").requiredOption("--body <text>", "Email body text").action(async (opts) => {
|
|
9794
10448
|
const keystore = await loadKeystore();
|
|
9795
|
-
const result = await apiPost("/api/emails/send", {
|
|
10449
|
+
const { data: result, idempotencyKey } = await apiPost("/api/emails/send", {
|
|
9796
10450
|
deviceId: keystore.deviceId,
|
|
9797
10451
|
apiToken: keystore.apiToken,
|
|
9798
10452
|
to: opts.to,
|
|
9799
10453
|
subject: opts.subject,
|
|
9800
10454
|
bodyText: opts.body
|
|
9801
10455
|
});
|
|
9802
|
-
printResult({ sent: result.sent });
|
|
10456
|
+
printResult({ sent: result.sent }, { idempotencyKey });
|
|
9803
10457
|
});
|
|
9804
10458
|
|
|
9805
10459
|
// src/commands/email/reply.ts
|
|
9806
|
-
import { Command as
|
|
9807
|
-
var replyCommand = new
|
|
10460
|
+
import { Command as Command61 } from "commander";
|
|
10461
|
+
var replyCommand = new Command61("reply").description("Reply to an email").argument("<id>", "Email ID to reply to").requiredOption("--body <text>", "Reply body text").action(async (id, opts) => {
|
|
9808
10462
|
const keystore = await loadKeystore();
|
|
9809
10463
|
const params = new URLSearchParams({
|
|
9810
10464
|
deviceId: keystore.deviceId,
|
|
@@ -9815,54 +10469,60 @@ var replyCommand = new Command59("reply").description("Reply to an email").argum
|
|
|
9815
10469
|
const to = original.fromAddress;
|
|
9816
10470
|
const rawSubject = original.subject ?? "";
|
|
9817
10471
|
const subject = rawSubject.startsWith("Re: ") ? rawSubject : `Re: ${rawSubject}`;
|
|
9818
|
-
const result = await apiPost("/api/emails/send", {
|
|
10472
|
+
const { data: result, idempotencyKey } = await apiPost("/api/emails/send", {
|
|
9819
10473
|
deviceId: keystore.deviceId,
|
|
9820
10474
|
apiToken: keystore.apiToken,
|
|
9821
10475
|
to,
|
|
9822
10476
|
subject,
|
|
9823
10477
|
bodyText: opts.body
|
|
9824
10478
|
});
|
|
9825
|
-
printResult({ sent: result.sent });
|
|
10479
|
+
printResult({ sent: result.sent }, { idempotencyKey });
|
|
9826
10480
|
});
|
|
9827
10481
|
|
|
9828
10482
|
// src/commands/email/delete.ts
|
|
9829
|
-
import { Command as
|
|
9830
|
-
var deleteCommand = new
|
|
10483
|
+
import { Command as Command62 } from "commander";
|
|
10484
|
+
var deleteCommand = new Command62("delete").description("Delete an email by ID").argument("<id>", "Email ID").action(async (id) => {
|
|
9831
10485
|
const keystore = await loadKeystore();
|
|
9832
|
-
const result = await apiPost(
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
10486
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10487
|
+
"/api/emails/delete",
|
|
10488
|
+
{
|
|
10489
|
+
deviceId: keystore.deviceId,
|
|
10490
|
+
apiToken: keystore.apiToken,
|
|
10491
|
+
id
|
|
10492
|
+
}
|
|
10493
|
+
);
|
|
10494
|
+
printResult({ deleted: result.deleted }, { idempotencyKey });
|
|
9838
10495
|
});
|
|
9839
10496
|
|
|
9840
10497
|
// src/commands/email/address.ts
|
|
9841
|
-
import { Command as
|
|
9842
|
-
var addressCommand2 = new
|
|
10498
|
+
import { Command as Command63 } from "commander";
|
|
10499
|
+
var addressCommand2 = new Command63("address").description("Show your registered email address").action(async () => {
|
|
9843
10500
|
const keystore = await loadKeystore();
|
|
9844
10501
|
const result = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
9845
10502
|
printResult({ emailAddress: result.emailAddress ?? null });
|
|
9846
10503
|
});
|
|
9847
10504
|
|
|
9848
10505
|
// src/commands/email/mark-read.ts
|
|
9849
|
-
import { Command as
|
|
10506
|
+
import { Command as Command64 } from "commander";
|
|
9850
10507
|
async function setReadStatus(id, read) {
|
|
9851
10508
|
const keystore = await loadKeystore();
|
|
9852
|
-
const result = await apiPost(
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
|
|
9856
|
-
|
|
9857
|
-
|
|
9858
|
-
|
|
10509
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10510
|
+
"/api/emails/mark-read",
|
|
10511
|
+
{
|
|
10512
|
+
deviceId: keystore.deviceId,
|
|
10513
|
+
apiToken: keystore.apiToken,
|
|
10514
|
+
id,
|
|
10515
|
+
read
|
|
10516
|
+
}
|
|
10517
|
+
);
|
|
10518
|
+
printResult({ id: result.id, isRead: result.isRead }, { idempotencyKey });
|
|
9859
10519
|
}
|
|
9860
|
-
var markReadCommand = new
|
|
10520
|
+
var markReadCommand = new Command64("mark-read").description("Mark an email as read or unread").argument("<id>", "Email ID").option("--unread", "Mark as unread instead of read").action(async (id, opts) => {
|
|
9861
10521
|
await setReadStatus(id, !opts.unread);
|
|
9862
10522
|
});
|
|
9863
10523
|
|
|
9864
10524
|
// src/commands/email/index.ts
|
|
9865
|
-
var emailCommand = new
|
|
10525
|
+
var emailCommand = new Command65("email").description("Email management commands");
|
|
9866
10526
|
emailCommand.addCommand(registerCommand);
|
|
9867
10527
|
emailCommand.addCommand(inboxCommand2);
|
|
9868
10528
|
emailCommand.addCommand(readCommand);
|
|
@@ -9873,32 +10533,30 @@ emailCommand.addCommand(addressCommand2);
|
|
|
9873
10533
|
emailCommand.addCommand(markReadCommand);
|
|
9874
10534
|
|
|
9875
10535
|
// src/commands/requester/index.ts
|
|
9876
|
-
import { Command as
|
|
10536
|
+
import { Command as Command67 } from "commander";
|
|
9877
10537
|
|
|
9878
10538
|
// src/commands/requester/stats.ts
|
|
9879
|
-
import { Command as
|
|
9880
|
-
var requesterStatsCmd = new
|
|
10539
|
+
import { Command as Command66 } from "commander";
|
|
10540
|
+
var requesterStatsCmd = new Command66("stats").description("Get requester reputation stats for an address").argument("<address>", "Wallet address of the requester").action(async (address) => {
|
|
9881
10541
|
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
9882
10542
|
printError("Address must be a 0x-prefixed 20-byte hex string");
|
|
9883
|
-
process.exit(1);
|
|
9884
10543
|
return;
|
|
9885
10544
|
}
|
|
9886
10545
|
const data = await apiGet(`/api/requester/${address}/stats`);
|
|
9887
10546
|
if (!data) {
|
|
9888
10547
|
printError("No stats found for address");
|
|
9889
|
-
process.exit(1);
|
|
9890
10548
|
return;
|
|
9891
10549
|
}
|
|
9892
10550
|
printResult(data);
|
|
9893
10551
|
});
|
|
9894
10552
|
|
|
9895
10553
|
// src/commands/requester/index.ts
|
|
9896
|
-
var requesterCmd = new
|
|
10554
|
+
var requesterCmd = new Command67("requester").description("Requester reputation commands").addCommand(requesterStatsCmd);
|
|
9897
10555
|
|
|
9898
10556
|
// src/index.ts
|
|
9899
10557
|
var require2 = createRequire(import.meta.url);
|
|
9900
10558
|
var { version } = require2("../package.json");
|
|
9901
|
-
var program = new
|
|
10559
|
+
var program = new Command68();
|
|
9902
10560
|
program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
|
|
9903
10561
|
program.addCommand(initCommand);
|
|
9904
10562
|
program.addCommand(walletCommand);
|
|
@@ -9908,6 +10566,7 @@ program.addCommand(statsCommand);
|
|
|
9908
10566
|
program.addCommand(taskCommand);
|
|
9909
10567
|
program.addCommand(agentsCommand);
|
|
9910
10568
|
program.addCommand(inboxCommand);
|
|
10569
|
+
program.addCommand(actionsCommand);
|
|
9911
10570
|
program.addCommand(depositCommand);
|
|
9912
10571
|
program.addCommand(withdrawCommand);
|
|
9913
10572
|
program.addCommand(encryptCommand);
|
|
@@ -9917,10 +10576,10 @@ program.addCommand(daemonCommand);
|
|
|
9917
10576
|
program.addCommand(emailCommand);
|
|
9918
10577
|
program.addCommand(requesterCmd);
|
|
9919
10578
|
program.addCommand(legalCommand);
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
});
|
|
10579
|
+
void (async () => {
|
|
10580
|
+
try {
|
|
10581
|
+
await program.parseAsync(process.argv);
|
|
10582
|
+
} catch (err) {
|
|
10583
|
+
renderFailure(err);
|
|
10584
|
+
}
|
|
10585
|
+
})();
|