@lucid-agents/taskmarket 1.7.2 → 1.8.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 +1044 -432
- 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 Command67 } 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(),
|
|
@@ -4492,7 +4503,11 @@ var TaskDetailResponseSchema = TaskResponseSchema.extend({
|
|
|
4492
4503
|
pendingActions: PendingActionSchema.array(),
|
|
4493
4504
|
awards: TaskAwardSchema.array().optional(),
|
|
4494
4505
|
dreamsPerUsdc: external_exports.string().optional(),
|
|
4495
|
-
|
|
4506
|
+
// Optional as a set, not individually: the router emits `dreamsPerUsdc`, `bonusBps` and every
|
|
4507
|
+
// `estimated*` field together or not at all, depending on whether the task carries the DREAMS
|
|
4508
|
+
// hook. No client multiplies this by a split of its own -- the worker/requester estimates are
|
|
4509
|
+
// computed server-side -- so the absent case needs no fallback multiplier anywhere.
|
|
4510
|
+
bonusBps: external_exports.number().int().min(0).max(1e4).optional(),
|
|
4496
4511
|
estimatedUsdBonusValue: external_exports.string().optional(),
|
|
4497
4512
|
estimatedWorkerUsdBonusValue: external_exports.string().optional(),
|
|
4498
4513
|
estimatedRequesterUsdBonusValue: external_exports.string().optional(),
|
|
@@ -4506,6 +4521,16 @@ var RejectSubmissionInputSchema = external_exports.object({
|
|
|
4506
4521
|
taskId: external_exports.string(),
|
|
4507
4522
|
worker: external_exports.string()
|
|
4508
4523
|
});
|
|
4524
|
+
var AssignEvaluatorInputSchema = external_exports.object({
|
|
4525
|
+
taskId: external_exports.string(),
|
|
4526
|
+
evaluator: external_exports.string(),
|
|
4527
|
+
// Integral: same field, same `uint16`, and the two request-side schemas must not disagree
|
|
4528
|
+
// about what a caller may send.
|
|
4529
|
+
evaluatorFeeBps: external_exports.number().int().min(0).max(1e4).optional(),
|
|
4530
|
+
evaluationWindowHours: external_exports.number().positive().optional(),
|
|
4531
|
+
appealWindowHours: external_exports.number().positive().optional(),
|
|
4532
|
+
disputeResolver: external_exports.string().optional()
|
|
4533
|
+
});
|
|
4509
4534
|
var RefundExpiredInputSchema = external_exports.object({
|
|
4510
4535
|
taskId: external_exports.string()
|
|
4511
4536
|
});
|
|
@@ -4714,7 +4739,47 @@ var FeedbackSchema = external_exports.object({
|
|
|
4714
4739
|
var HealthResponseSchema = external_exports.object({
|
|
4715
4740
|
status: external_exports.literal("ok"),
|
|
4716
4741
|
timestamp: external_exports.string(),
|
|
4717
|
-
environment: external_exports.string()
|
|
4742
|
+
environment: external_exports.string(),
|
|
4743
|
+
/**
|
|
4744
|
+
* The submission limits this process is actually enforcing, after any environment
|
|
4745
|
+
* override. Reported because a limit a caller cannot observe is a limit a test can only
|
|
4746
|
+
* guess at: smoke-rate-limit.ts asserted against its own copy of the ceiling and had no
|
|
4747
|
+
* way to notice the backend was started with a different one, so it failed with a
|
|
4748
|
+
* confusing boundary error instead of saying the two disagreed.
|
|
4749
|
+
*/
|
|
4750
|
+
limits: external_exports.object({
|
|
4751
|
+
freeSubmissionAllowance: external_exports.number().int().positive(),
|
|
4752
|
+
hardSubmissionCeiling: external_exports.number().int().positive()
|
|
4753
|
+
}),
|
|
4754
|
+
/**
|
|
4755
|
+
* Relayed-intent facts a caller can poll for, in the same spirit as `limits`: a queryable
|
|
4756
|
+
* number, not an alert (ADR-0053).
|
|
4757
|
+
*
|
|
4758
|
+
* Optional because health is what tells you the service is up. If no count is available the
|
|
4759
|
+
* object is omitted rather than reported as a sentinel -- absence under an optional field is
|
|
4760
|
+
* unambiguous, whereas a `-1` or an `"unknown"` string is a value every consumer has to learn
|
|
4761
|
+
* not to plot, and it is also exactly how this endpoint already reads to a caller running
|
|
4762
|
+
* against a build from before the field existed.
|
|
4763
|
+
*
|
|
4764
|
+
* Absent means "no answer here", and it covers a process whose sweep has not run yet as well
|
|
4765
|
+
* as one that does not sweep at all. It never means zero.
|
|
4766
|
+
*/
|
|
4767
|
+
intents: external_exports.object({
|
|
4768
|
+
/**
|
|
4769
|
+
* When the count below was computed, not when it was served.
|
|
4770
|
+
*
|
|
4771
|
+
* These numbers come from a periodic sweep rather than from the request, so the response
|
|
4772
|
+
* is a cache and says so. Without this a consumer cannot tell a live zero from a zero
|
|
4773
|
+
* left behind by a worker that stopped running -- and the second is the more urgent of
|
|
4774
|
+
* the two, because a sweep that is not running is a queue nothing is draining.
|
|
4775
|
+
*/
|
|
4776
|
+
measuredAt: external_exports.string(),
|
|
4777
|
+
/**
|
|
4778
|
+
* Intents that are neither completed nor failed and have not been touched for well past
|
|
4779
|
+
* normal settlement. A count only -- the endpoint is public.
|
|
4780
|
+
*/
|
|
4781
|
+
staleNonTerminal: external_exports.number().int().nonnegative()
|
|
4782
|
+
}).optional()
|
|
4718
4783
|
});
|
|
4719
4784
|
|
|
4720
4785
|
// ../../packages/shared/dist/schemas/pitch.schemas.js
|
|
@@ -4873,8 +4938,12 @@ var WithdrawDreamsOutputSchema = external_exports.object({
|
|
|
4873
4938
|
});
|
|
4874
4939
|
var ExchangeRateOutputSchema = external_exports.object({
|
|
4875
4940
|
dreamsPerUsdc: external_exports.string(),
|
|
4876
|
-
|
|
4877
|
-
|
|
4941
|
+
// Both are read straight off `TaskTokenRewardHook`, which rejects either above 10000
|
|
4942
|
+
// (`InvalidBps`), and both are required here rather than optional: a client that had to
|
|
4943
|
+
// default the split would default it to the whole reward, and one that had to default the
|
|
4944
|
+
// bonus would report no bonus at all. Neither is a fact this endpoint may leave to the reader.
|
|
4945
|
+
workerSplitBps: external_exports.number().int().min(0).max(1e4),
|
|
4946
|
+
bonusBps: external_exports.number().int().min(0).max(1e4)
|
|
4878
4947
|
});
|
|
4879
4948
|
|
|
4880
4949
|
// ../../packages/shared/dist/schemas/xmtp.schemas.js
|
|
@@ -5204,6 +5273,225 @@ var AllowedViewerResponseSchema = external_exports.object({
|
|
|
5204
5273
|
});
|
|
5205
5274
|
var ListAllowedViewersResponseSchema = external_exports.array(AllowedViewerResponseSchema);
|
|
5206
5275
|
|
|
5276
|
+
// ../../packages/shared/dist/schemas/api-error.schemas.js
|
|
5277
|
+
var API_ERROR_REASONS = [
|
|
5278
|
+
/**
|
|
5279
|
+
* No terminal outcome has been established. The write is owned by the settlement path and
|
|
5280
|
+
* may still succeed. **This is not a failure and not a success**, and it makes no claim about
|
|
5281
|
+
* whether the payment moved (ADR-0049 point 3). Never resubmit; poll `intents.get`.
|
|
5282
|
+
*/
|
|
5283
|
+
"intent_in_flight",
|
|
5284
|
+
/**
|
|
5285
|
+
* A write carrying this idempotency key already exists, and this request neither charged the
|
|
5286
|
+
* caller nor submitted anything a second time. Idempotency working, reported as a conflict --
|
|
5287
|
+
* see ADR-0058 for why this is not a 200 carrying the original result.
|
|
5288
|
+
*/
|
|
5289
|
+
"idempotency_key_reused",
|
|
5290
|
+
/**
|
|
5291
|
+
* The request arrived with no `X-Taskmarket-Idempotency-Key` header (the value of
|
|
5292
|
+
* `IDEMPOTENCY_KEY_HEADER`), or one that is not a UUID. Rejected before the 402 challenge,
|
|
5293
|
+
* so nothing was charged (ADR-0052).
|
|
5294
|
+
*/
|
|
5295
|
+
"idempotency_key_required",
|
|
5296
|
+
/**
|
|
5297
|
+
* The key is already bound to a *different* operation, or to a different caller's write. Not
|
|
5298
|
+
* the benign repeat: nothing here can be waited on, and the caller must generate a fresh key.
|
|
5299
|
+
* Distinguished from `idempotency_key_reused` because the correct client response is opposite
|
|
5300
|
+
* -- poll there, resubmit under a new key here.
|
|
5301
|
+
*/
|
|
5302
|
+
"idempotency_key_conflict",
|
|
5303
|
+
/**
|
|
5304
|
+
* The key names the *same* operation by the *same* caller, but with different arguments. One
|
|
5305
|
+
* level finer than `idempotency_key_conflict`, and a distinct reason because the caller's
|
|
5306
|
+
* mistake is distinct: they reused a key while changing what they were asking for, so the
|
|
5307
|
+
* write they just described never happened and the one the key already names is not it
|
|
5308
|
+
* (ADR-0061). Re-send the original arguments to retry the original write, or generate a fresh
|
|
5309
|
+
* key for the new one.
|
|
5310
|
+
*/
|
|
5311
|
+
"idempotency_key_payload_mismatch",
|
|
5312
|
+
/**
|
|
5313
|
+
* The settled payment behind this request has already funded another intent. A retry that
|
|
5314
|
+
* failed to reuse its key, or a replayed payment. The money is spent and this write did not
|
|
5315
|
+
* happen; the caller reads the intent that did consume it from `intents.get`.
|
|
5316
|
+
*/
|
|
5317
|
+
"payment_already_spent",
|
|
5318
|
+
/**
|
|
5319
|
+
* The idempotency precondition could not be read, so the request was refused rather than
|
|
5320
|
+
* risking a double charge on an unverified assumption. Safe to retry with the same key.
|
|
5321
|
+
*/
|
|
5322
|
+
"idempotency_check_unavailable",
|
|
5323
|
+
/**
|
|
5324
|
+
* The chain call is confirmed and the work happened, but recording it did not finish. There
|
|
5325
|
+
* is nothing to refund and nothing to resubmit; the intent is retried automatically.
|
|
5326
|
+
*/
|
|
5327
|
+
"intent_completion_deferred",
|
|
5328
|
+
/**
|
|
5329
|
+
* No intent answers to that id or key *for this caller*. Deliberately one reason for both "no
|
|
5330
|
+
* such intent" and "not yours": telling them apart would make this surface an oracle for which
|
|
5331
|
+
* intent ids and idempotency keys exist (ADR-0049 point 6).
|
|
5332
|
+
*/
|
|
5333
|
+
"intent_not_found",
|
|
5334
|
+
/** The x402 exchange did not produce a settled payment. Nothing was charged. */
|
|
5335
|
+
"payment_rejected",
|
|
5336
|
+
/** A pre-settlement check on the request's own inputs or on task state rejected it. */
|
|
5337
|
+
"payment_preflight_rejected",
|
|
5338
|
+
/**
|
|
5339
|
+
* The settled payment came from an address other than the one the request is authenticated as
|
|
5340
|
+
* acting for. The write was refused; the payment had already settled when the mismatch was
|
|
5341
|
+
* seen, so the fee is not returned by this path.
|
|
5342
|
+
*/
|
|
5343
|
+
"payment_payer_mismatch",
|
|
5344
|
+
/**
|
|
5345
|
+
* The error carries no more specific classification. Present so that every error has a
|
|
5346
|
+
* reason field and a client's switch is total; not a licence to leave one here.
|
|
5347
|
+
*/
|
|
5348
|
+
"unclassified"
|
|
5349
|
+
];
|
|
5350
|
+
var ApiErrorReasonSchema = external_exports.enum(API_ERROR_REASONS);
|
|
5351
|
+
var ApiErrorIntentStatusSchema = external_exports.enum([
|
|
5352
|
+
"reserved",
|
|
5353
|
+
"recorded",
|
|
5354
|
+
"broadcast",
|
|
5355
|
+
"completed",
|
|
5356
|
+
"failed"
|
|
5357
|
+
]);
|
|
5358
|
+
var REASONS_WITHOUT_REQUIRED_INTENT_STATUS = API_ERROR_REASONS.filter((reason) => reason !== "idempotency_key_reused");
|
|
5359
|
+
var ENVELOPE_FIELDS = {
|
|
5360
|
+
/** The durable handle to the write, where one was recorded. Key on this, not on `txHash`. */
|
|
5361
|
+
intentId: external_exports.string().optional(),
|
|
5362
|
+
/** The operation the intent stands for, e.g. `tasks.create`. */
|
|
5363
|
+
operation: external_exports.string().optional(),
|
|
5364
|
+
/** The caller's own key for the operation, echoed so a dropped response is still traceable. */
|
|
5365
|
+
idempotencyKey: external_exports.string().optional(),
|
|
5366
|
+
/**
|
|
5367
|
+
* Known once something has been broadcast, and explicitly not the handle: the reconciler may
|
|
5368
|
+
* land a replacement at the same nonce, which is a different hash for the same intent.
|
|
5369
|
+
*/
|
|
5370
|
+
txHash: external_exports.string().optional()
|
|
5371
|
+
};
|
|
5372
|
+
var ApiErrorEnvelopeSchema = external_exports.discriminatedUnion("reason", [
|
|
5373
|
+
external_exports.object({
|
|
5374
|
+
reason: external_exports.literal("idempotency_key_reused"),
|
|
5375
|
+
/** Required here: the reason means an intent under this key exists, so it has a status. */
|
|
5376
|
+
intentStatus: ApiErrorIntentStatusSchema,
|
|
5377
|
+
...ENVELOPE_FIELDS
|
|
5378
|
+
}),
|
|
5379
|
+
external_exports.object({
|
|
5380
|
+
reason: external_exports.enum(REASONS_WITHOUT_REQUIRED_INTENT_STATUS),
|
|
5381
|
+
/** The intent's status at the moment this answer was produced, where there is an intent. */
|
|
5382
|
+
intentStatus: ApiErrorIntentStatusSchema.optional(),
|
|
5383
|
+
...ENVELOPE_FIELDS
|
|
5384
|
+
})
|
|
5385
|
+
]);
|
|
5386
|
+
var IN_FLIGHT_REASONS = /* @__PURE__ */ new Set([
|
|
5387
|
+
"intent_in_flight",
|
|
5388
|
+
"idempotency_key_reused",
|
|
5389
|
+
// Not "may still succeed" but "already succeeded, still being written down". Both are
|
|
5390
|
+
// answered the same way -- poll, never resubmit -- and reporting this one as settled told a
|
|
5391
|
+
// script following the documented rule that re-running it was an ordinary retry. It is not:
|
|
5392
|
+
// the chain call is confirmed, so a re-run is a second paid action for work already done.
|
|
5393
|
+
"intent_completion_deferred"
|
|
5394
|
+
]);
|
|
5395
|
+
function isInFlightApiError(envelope) {
|
|
5396
|
+
if (!envelope || !IN_FLIGHT_REASONS.has(envelope.reason))
|
|
5397
|
+
return false;
|
|
5398
|
+
if (envelope.reason !== "idempotency_key_reused")
|
|
5399
|
+
return true;
|
|
5400
|
+
return envelope.intentStatus !== "completed" && envelope.intentStatus !== "failed";
|
|
5401
|
+
}
|
|
5402
|
+
function apiErrorEnvelopeOf(value) {
|
|
5403
|
+
if (!value || typeof value !== "object")
|
|
5404
|
+
return null;
|
|
5405
|
+
const at = (source, key) => source && typeof source === "object" ? source[key] : void 0;
|
|
5406
|
+
const candidate = at(value, "taskmarket") ?? at(at(value, "data"), "taskmarket") ?? at(at(at(value, "error"), "data"), "taskmarket") ?? value;
|
|
5407
|
+
const parsed = ApiErrorEnvelopeSchema.safeParse(candidate);
|
|
5408
|
+
return parsed.success ? parsed.data : null;
|
|
5409
|
+
}
|
|
5410
|
+
|
|
5411
|
+
// ../../packages/shared/dist/schemas/intent.schemas.js
|
|
5412
|
+
var IntentStatusInputSchema = external_exports.object({
|
|
5413
|
+
intentId: external_exports.string().min(1).optional(),
|
|
5414
|
+
idempotencyKey: external_exports.string().min(1).optional()
|
|
5415
|
+
}).refine((value) => Boolean(value.intentId) !== Boolean(value.idempotencyKey), {
|
|
5416
|
+
message: "Provide exactly one of intentId or idempotencyKey"
|
|
5417
|
+
});
|
|
5418
|
+
var IntentRefundStateSchema = external_exports.object({
|
|
5419
|
+
status: external_exports.enum(["pending", "refunding", "refunded", "failed"]),
|
|
5420
|
+
txHash: external_exports.string().nullable()
|
|
5421
|
+
});
|
|
5422
|
+
var IntentStatusResponseSchema = external_exports.object({
|
|
5423
|
+
intentId: external_exports.string(),
|
|
5424
|
+
idempotencyKey: external_exports.string(),
|
|
5425
|
+
/** The operation kind, e.g. `tasks.create`. */
|
|
5426
|
+
operation: external_exports.string(),
|
|
5427
|
+
/**
|
|
5428
|
+
* `reserved` is the pre-payment state (ADR-0067): the key is claimed and the caller has been
|
|
5429
|
+
* challenged, but no payment has landed and nothing has been sent to the chain. It is
|
|
5430
|
+
* non-terminal, it is never broadcastable, and it expires if it is never filled.
|
|
5431
|
+
*/
|
|
5432
|
+
status: external_exports.enum(["reserved", "recorded", "broadcast", "completed", "failed"]),
|
|
5433
|
+
/**
|
|
5434
|
+
* Known once something has been broadcast, and explicitly not the handle: the reconciler
|
|
5435
|
+
* may land a replacement at the same nonce, which is a different hash for the same intent.
|
|
5436
|
+
*/
|
|
5437
|
+
txHash: external_exports.string().nullable(),
|
|
5438
|
+
/** Why it failed, where it did. Null on every non-terminal status. */
|
|
5439
|
+
terminalReason: external_exports.string().nullable(),
|
|
5440
|
+
/**
|
|
5441
|
+
* The task a completed `tasks.create` produced.
|
|
5442
|
+
*
|
|
5443
|
+
* This is where a caller whose creation went in flight learns the id. The id does not
|
|
5444
|
+
* exist until the transaction runs -- the contract derives it from a requester nonce it
|
|
5445
|
+
* increments as it goes -- so an in-flight creation has no id to report, and reporting one
|
|
5446
|
+
* would be a guess of the kind that made concurrent creates overwrite each other. Null
|
|
5447
|
+
* until the intent completes, and null for every other operation.
|
|
5448
|
+
*/
|
|
5449
|
+
taskId: external_exports.string().nullable(),
|
|
5450
|
+
/**
|
|
5451
|
+
* Only present where the intent carried a payment and that payment has been written off.
|
|
5452
|
+
* Null means no refund has been decided -- which is not the same as "no refund is coming"
|
|
5453
|
+
* while the intent is still in flight.
|
|
5454
|
+
*/
|
|
5455
|
+
refund: IntentRefundStateSchema.nullable()
|
|
5456
|
+
}).superRefine((value, ctx) => {
|
|
5457
|
+
if (value.status === "reserved") {
|
|
5458
|
+
for (const field of ["txHash", "terminalReason", "taskId"]) {
|
|
5459
|
+
if (value[field] !== null) {
|
|
5460
|
+
ctx.addIssue({
|
|
5461
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5462
|
+
path: [field],
|
|
5463
|
+
message: `A reserved intent has not been sent to the chain, so ${field} must be null`
|
|
5464
|
+
});
|
|
5465
|
+
}
|
|
5466
|
+
}
|
|
5467
|
+
return;
|
|
5468
|
+
}
|
|
5469
|
+
if (value.terminalReason !== null && value.status !== "failed") {
|
|
5470
|
+
ctx.addIssue({
|
|
5471
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5472
|
+
path: ["terminalReason"],
|
|
5473
|
+
message: "Only a failed intent has a terminal reason"
|
|
5474
|
+
});
|
|
5475
|
+
}
|
|
5476
|
+
if (value.taskId === null)
|
|
5477
|
+
return;
|
|
5478
|
+
if (value.status !== "completed") {
|
|
5479
|
+
ctx.addIssue({
|
|
5480
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5481
|
+
path: ["taskId"],
|
|
5482
|
+
message: "taskId is only known once the intent has completed"
|
|
5483
|
+
});
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
if (value.operation !== "tasks.create") {
|
|
5487
|
+
ctx.addIssue({
|
|
5488
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5489
|
+
path: ["taskId"],
|
|
5490
|
+
message: "Only a tasks.create intent produces a taskId"
|
|
5491
|
+
});
|
|
5492
|
+
}
|
|
5493
|
+
});
|
|
5494
|
+
|
|
5207
5495
|
// ../../packages/shared/dist/platform.constants.js
|
|
5208
5496
|
var USDC_DECIMALS = 6;
|
|
5209
5497
|
|
|
@@ -5508,6 +5796,7 @@ function buildReadAuthMessage(address) {
|
|
|
5508
5796
|
var READ_AUTH_ADDRESS_HEADER = "X-Taskmarket-Caller-Address";
|
|
5509
5797
|
var READ_AUTH_SIGNATURE_HEADER = "X-Taskmarket-Caller-Signature";
|
|
5510
5798
|
var TASK_ACCESS_GRANT_HEADER = "X-Taskmarket-Task-Access-Grant";
|
|
5799
|
+
var IDEMPOTENCY_KEY_HEADER = "X-Taskmarket-Idempotency-Key";
|
|
5511
5800
|
function buildSubmitMessage(taskId, contentBindings) {
|
|
5512
5801
|
return contentBindings ? `taskmarket:submit:${taskId}:${contentBindings.join(",")}` : `taskmarket:submit:${taskId}`;
|
|
5513
5802
|
}
|
|
@@ -6035,9 +6324,103 @@ async function keystoreExists(keystorePath) {
|
|
|
6035
6324
|
}
|
|
6036
6325
|
}
|
|
6037
6326
|
|
|
6327
|
+
// src/lib/idempotency.ts
|
|
6328
|
+
import { randomUUID } from "crypto";
|
|
6329
|
+
var pendingEnvKey = process.env.TASKMARKET_IDEMPOTENCY_KEY?.trim() || void 0;
|
|
6330
|
+
var keyByError = /* @__PURE__ */ new WeakMap();
|
|
6331
|
+
function rememberIdempotencyKeyFor(error, key) {
|
|
6332
|
+
if (error === null || typeof error !== "object" && typeof error !== "function") return;
|
|
6333
|
+
if (keyByError.has(error)) return;
|
|
6334
|
+
keyByError.set(error, key);
|
|
6335
|
+
}
|
|
6336
|
+
function idempotencyKeyForError(error) {
|
|
6337
|
+
if (error === null || typeof error !== "object" && typeof error !== "function")
|
|
6338
|
+
return void 0;
|
|
6339
|
+
return keyByError.get(error);
|
|
6340
|
+
}
|
|
6341
|
+
function newIdempotencyKey() {
|
|
6342
|
+
return randomUUID();
|
|
6343
|
+
}
|
|
6344
|
+
function resolveIdempotencyKey(explicit) {
|
|
6345
|
+
if (explicit !== void 0) {
|
|
6346
|
+
return explicit;
|
|
6347
|
+
}
|
|
6348
|
+
if (pendingEnvKey !== void 0) {
|
|
6349
|
+
const fromEnv = pendingEnvKey;
|
|
6350
|
+
pendingEnvKey = void 0;
|
|
6351
|
+
return fromEnv;
|
|
6352
|
+
}
|
|
6353
|
+
return newIdempotencyKey();
|
|
6354
|
+
}
|
|
6355
|
+
async function withIdempotentWrite(key, fn) {
|
|
6356
|
+
try {
|
|
6357
|
+
return await fn();
|
|
6358
|
+
} catch (error) {
|
|
6359
|
+
rememberIdempotencyKeyFor(error, key);
|
|
6360
|
+
throw error;
|
|
6361
|
+
}
|
|
6362
|
+
}
|
|
6363
|
+
function idempotencyHeaders(key) {
|
|
6364
|
+
return { [IDEMPOTENCY_KEY_HEADER]: key };
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6038
6367
|
// src/lib/api.ts
|
|
6039
6368
|
var API_URL = process.env.TASKMARKET_API_URL ?? "https://api.taskmarket.dev";
|
|
6040
6369
|
var API_ORIGIN = new URL(API_URL).origin;
|
|
6370
|
+
var ApiError = class extends Error {
|
|
6371
|
+
status;
|
|
6372
|
+
/**
|
|
6373
|
+
* The idempotency key the failed write was sent under, when the request was a write. This is
|
|
6374
|
+
* the only identifier the caller can still hold after a failure -- the intent id is minted by
|
|
6375
|
+
* the backend and reaches the caller only in the response the failure destroyed -- so it
|
|
6376
|
+
* travels on the error rather than being recoverable from the response. See
|
|
6377
|
+
* apps/cli/src/index.ts and lib/output.ts, which surface it on the CLI's JSON envelope.
|
|
6378
|
+
*/
|
|
6379
|
+
idempotencyKey;
|
|
6380
|
+
/**
|
|
6381
|
+
* The backend's machine-readable classification of the failure (ADR-0058).
|
|
6382
|
+
*
|
|
6383
|
+
* Before it existed the CLI rendered every failure identically, which is why
|
|
6384
|
+
* `docs/CLI_GUIDE.md` had to tell script authors never to auto-retry a paid command: there was
|
|
6385
|
+
* no way to tell a write that is still landing from one that was definitively rejected, and
|
|
6386
|
+
* retrying the first is a second payment. `reason` is that way.
|
|
6387
|
+
*
|
|
6388
|
+
* Absent when the backend answered with no envelope -- an older deployment, or a failure that
|
|
6389
|
+
* never reached the API at all -- in which case a caller must fall back to the old rule and
|
|
6390
|
+
* treat the outcome as unknown rather than as safe to retry.
|
|
6391
|
+
*/
|
|
6392
|
+
envelope;
|
|
6393
|
+
constructor(status, message, idempotencyKey, envelope) {
|
|
6394
|
+
super(message);
|
|
6395
|
+
this.name = "ApiError";
|
|
6396
|
+
this.status = status;
|
|
6397
|
+
this.idempotencyKey = idempotencyKey;
|
|
6398
|
+
this.envelope = envelope;
|
|
6399
|
+
}
|
|
6400
|
+
};
|
|
6401
|
+
async function readFailureBody(res) {
|
|
6402
|
+
const text = await res.text().catch(() => "");
|
|
6403
|
+
try {
|
|
6404
|
+
return { body: JSON.parse(text), text };
|
|
6405
|
+
} catch {
|
|
6406
|
+
return { body: void 0, text };
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6409
|
+
function failureMessage(prefix, status, read) {
|
|
6410
|
+
return `${prefix} (${status}): ${read.body !== void 0 ? JSON.stringify(read.body) : read.text}`;
|
|
6411
|
+
}
|
|
6412
|
+
function withErrorContext(error, context) {
|
|
6413
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6414
|
+
const wrapped = error instanceof ApiError ? new ApiError(error.status, `${context}: ${message}`, error.idempotencyKey, error.envelope) : new Error(`${context}: ${message}`);
|
|
6415
|
+
const key = idempotencyKeyForError(error);
|
|
6416
|
+
if (key !== void 0) {
|
|
6417
|
+
rememberIdempotencyKeyFor(wrapped, key);
|
|
6418
|
+
}
|
|
6419
|
+
return wrapped;
|
|
6420
|
+
}
|
|
6421
|
+
function isPendingApiError(error) {
|
|
6422
|
+
return error instanceof ApiError && isInFlightApiError(error.envelope);
|
|
6423
|
+
}
|
|
6041
6424
|
function legalReceiptHeadersForKeystore(keystore, path4, method) {
|
|
6042
6425
|
const canSend = keystore.legalAcceptanceApiOrigin === API_ORIGIN && (method === "POST" || path4 === "/api/legal/status");
|
|
6043
6426
|
return canSend ? buildLegalReceiptHeaders(keystore.legalAcceptanceReceipt) : {};
|
|
@@ -6061,55 +6444,100 @@ async function apiGet(path4, options) {
|
|
|
6061
6444
|
...options?.headers ?? {}
|
|
6062
6445
|
}
|
|
6063
6446
|
});
|
|
6064
|
-
const body = await res.json();
|
|
6065
6447
|
if (!res.ok) {
|
|
6066
|
-
|
|
6448
|
+
const read = await readFailureBody(res);
|
|
6449
|
+
throw new ApiError(
|
|
6450
|
+
res.status,
|
|
6451
|
+
failureMessage(`GET ${path4} failed`, res.status, read),
|
|
6452
|
+
void 0,
|
|
6453
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6454
|
+
);
|
|
6067
6455
|
}
|
|
6068
|
-
return
|
|
6456
|
+
return res.json();
|
|
6069
6457
|
}
|
|
6070
6458
|
async function apiPost(path4, body, options) {
|
|
6071
6459
|
const legalHeaders = await legalReceiptHeaders(path4, "POST");
|
|
6072
|
-
const
|
|
6073
|
-
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6460
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
6461
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
6462
|
+
const res = await fetch(`${API_URL}${path4}`, {
|
|
6463
|
+
method: "POST",
|
|
6464
|
+
redirect: "error",
|
|
6465
|
+
headers: {
|
|
6466
|
+
"Content-Type": "application/json",
|
|
6467
|
+
...legalHeaders,
|
|
6468
|
+
...idempotencyHeaders(idempotencyKey),
|
|
6469
|
+
...options?.headers ?? {}
|
|
6470
|
+
},
|
|
6471
|
+
body: JSON.stringify(body)
|
|
6472
|
+
});
|
|
6473
|
+
if (!res.ok) {
|
|
6474
|
+
const read = await readFailureBody(res);
|
|
6475
|
+
throw new ApiError(
|
|
6476
|
+
res.status,
|
|
6477
|
+
failureMessage(`POST ${path4} failed`, res.status, read),
|
|
6478
|
+
idempotencyKey,
|
|
6479
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6480
|
+
);
|
|
6481
|
+
}
|
|
6482
|
+
return { data: await res.json(), idempotencyKey };
|
|
6081
6483
|
});
|
|
6082
|
-
const result = await res.json();
|
|
6083
|
-
if (!res.ok) {
|
|
6084
|
-
throw new Error(`POST ${path4} failed (${res.status}): ${JSON.stringify(result)}`);
|
|
6085
|
-
}
|
|
6086
|
-
return result;
|
|
6087
6484
|
}
|
|
6088
6485
|
async function apiDelete(path4, options) {
|
|
6089
6486
|
const legalHeaders = await legalReceiptHeaders(path4, "POST");
|
|
6090
|
-
const
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6487
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
6488
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
6489
|
+
const res = await fetch(`${API_URL}${path4}`, {
|
|
6490
|
+
method: "DELETE",
|
|
6491
|
+
redirect: "error",
|
|
6492
|
+
headers: {
|
|
6493
|
+
"Content-Type": "application/json",
|
|
6494
|
+
...legalHeaders,
|
|
6495
|
+
...idempotencyHeaders(idempotencyKey),
|
|
6496
|
+
...options?.headers ?? {}
|
|
6497
|
+
}
|
|
6498
|
+
});
|
|
6499
|
+
if (!res.ok) {
|
|
6500
|
+
const read = await readFailureBody(res);
|
|
6501
|
+
throw new ApiError(
|
|
6502
|
+
res.status,
|
|
6503
|
+
failureMessage(`DELETE ${path4} failed`, res.status, read),
|
|
6504
|
+
idempotencyKey,
|
|
6505
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
6506
|
+
);
|
|
6097
6507
|
}
|
|
6508
|
+
return { data: await res.json(), idempotencyKey };
|
|
6098
6509
|
});
|
|
6099
|
-
const result = await res.json();
|
|
6100
|
-
if (!res.ok) {
|
|
6101
|
-
throw new Error(`DELETE ${path4} failed (${res.status}): ${JSON.stringify(result)}`);
|
|
6102
|
-
}
|
|
6103
|
-
return result;
|
|
6104
6510
|
}
|
|
6105
6511
|
|
|
6106
6512
|
// src/lib/output.ts
|
|
6107
|
-
function printResult(data) {
|
|
6108
|
-
|
|
6513
|
+
function printResult(data, options) {
|
|
6514
|
+
const idempotencyKey = options?.idempotencyKey;
|
|
6515
|
+
console.log(
|
|
6516
|
+
JSON.stringify({ ok: true, data, ...idempotencyKey !== void 0 ? { idempotencyKey } : {} })
|
|
6517
|
+
);
|
|
6518
|
+
}
|
|
6519
|
+
function renderFailure(error, options) {
|
|
6520
|
+
const message = error instanceof Error ? error.message : options?.fallback ?? String(error);
|
|
6521
|
+
const apiError = error instanceof ApiError ? error : void 0;
|
|
6522
|
+
const idempotencyKey = options?.idempotencyKey ?? apiError?.idempotencyKey ?? idempotencyKeyForError(error);
|
|
6523
|
+
const envelope = apiError?.envelope;
|
|
6524
|
+
process.stderr.write(
|
|
6525
|
+
JSON.stringify({
|
|
6526
|
+
ok: false,
|
|
6527
|
+
error: message,
|
|
6528
|
+
...apiError !== void 0 ? { status: apiError.status } : {},
|
|
6529
|
+
...idempotencyKey !== void 0 ? { idempotencyKey } : {},
|
|
6530
|
+
...envelope !== void 0 ? { ...envelope, pending: isInFlightApiError(envelope) } : {},
|
|
6531
|
+
...options?.details ?? {}
|
|
6532
|
+
}) + "\n"
|
|
6533
|
+
);
|
|
6534
|
+
process.exitCode = 1;
|
|
6109
6535
|
}
|
|
6110
|
-
function printError(message) {
|
|
6536
|
+
function printError(message, options) {
|
|
6537
|
+
return renderFailure(new Error(message), options);
|
|
6538
|
+
}
|
|
6539
|
+
function printWarning(message) {
|
|
6111
6540
|
process.stderr.write(JSON.stringify({ ok: false, error: message }) + "\n");
|
|
6112
|
-
process.exit(1);
|
|
6113
6541
|
}
|
|
6114
6542
|
|
|
6115
6543
|
// src/lib/agent.ts
|
|
@@ -6358,21 +6786,21 @@ async function acceptLegalBundle(options) {
|
|
|
6358
6786
|
}
|
|
6359
6787
|
await confirmAcceptance(bundle, options.assumeYes);
|
|
6360
6788
|
const challenge = LegalChallengeResponseSchema.parse(
|
|
6361
|
-
await apiPost("/api/legal/challenge", {
|
|
6789
|
+
(await apiPost("/api/legal/challenge", {
|
|
6362
6790
|
walletAddress: options.walletAddress
|
|
6363
|
-
})
|
|
6791
|
+
})).data
|
|
6364
6792
|
);
|
|
6365
6793
|
validateLegalChallenge(bundle, challenge, options.walletAddress);
|
|
6366
6794
|
const signature = await options.signMessage(challenge.message);
|
|
6367
6795
|
const result = LegalAcceptanceResponseSchema.parse(
|
|
6368
|
-
await apiPost("/api/legal/accept/wallet", {
|
|
6796
|
+
(await apiPost("/api/legal/accept/wallet", {
|
|
6369
6797
|
...affirmations,
|
|
6370
6798
|
bundleDigest: bundle.bundleDigest,
|
|
6371
6799
|
bundleVersion: bundle.version,
|
|
6372
6800
|
nonce: challenge.nonce,
|
|
6373
6801
|
signature,
|
|
6374
6802
|
walletAddress: options.walletAddress
|
|
6375
|
-
})
|
|
6803
|
+
})).data
|
|
6376
6804
|
);
|
|
6377
6805
|
if (result.bundleDigest !== bundle.bundleDigest || result.bundleVersion !== bundle.version) {
|
|
6378
6806
|
throw new Error("The server returned a receipt for a different legal bundle.");
|
|
@@ -6444,7 +6872,7 @@ function sanitizeEmailUsername(agentId, suffix) {
|
|
|
6444
6872
|
}
|
|
6445
6873
|
async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
6446
6874
|
try {
|
|
6447
|
-
const reg = await apiPost("/api/emails/register", {
|
|
6875
|
+
const { data: reg } = await apiPost("/api/emails/register", {
|
|
6448
6876
|
deviceId,
|
|
6449
6877
|
apiToken,
|
|
6450
6878
|
username
|
|
@@ -6453,11 +6881,8 @@ async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
|
6453
6881
|
} catch (err) {
|
|
6454
6882
|
if (explicit) {
|
|
6455
6883
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
ok: false,
|
|
6459
|
-
error: `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
6460
|
-
}) + "\n"
|
|
6884
|
+
printWarning(
|
|
6885
|
+
`Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
6461
6886
|
);
|
|
6462
6887
|
}
|
|
6463
6888
|
return null;
|
|
@@ -6476,6 +6901,7 @@ var initCommand = new Command2("init").description("Create and register a new ag
|
|
|
6476
6901
|
);
|
|
6477
6902
|
if (!check.available) {
|
|
6478
6903
|
printError(`Email username "${opts.email}" is not available.`);
|
|
6904
|
+
return;
|
|
6479
6905
|
}
|
|
6480
6906
|
}
|
|
6481
6907
|
if (await keystoreExists()) {
|
|
@@ -6592,65 +7018,80 @@ var addressCommand = new Command3("address").description("Print the wallet addre
|
|
|
6592
7018
|
import { Command as Command4 } from "commander";
|
|
6593
7019
|
|
|
6594
7020
|
// src/lib/x402.ts
|
|
6595
|
-
async function x402Post(path4, body) {
|
|
7021
|
+
async function x402Post(path4, body, options) {
|
|
6596
7022
|
const url = `${API_URL}${path4}`;
|
|
6597
7023
|
const keystore = await loadKeystore();
|
|
6598
7024
|
const legalHeaders = legalReceiptHeadersForKeystore(keystore, path4, "POST");
|
|
6599
|
-
const
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
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
|
-
|
|
7025
|
+
const idempotencyKey = resolveIdempotencyKey(options?.idempotencyKey);
|
|
7026
|
+
const idempotency = idempotencyHeaders(idempotencyKey);
|
|
7027
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
7028
|
+
const r1 = await fetch(url, {
|
|
7029
|
+
method: "POST",
|
|
7030
|
+
redirect: "error",
|
|
7031
|
+
headers: { "Content-Type": "application/json", ...legalHeaders, ...idempotency },
|
|
7032
|
+
body: JSON.stringify(body)
|
|
7033
|
+
});
|
|
7034
|
+
if (r1.status !== 402) {
|
|
7035
|
+
if (r1.ok) {
|
|
7036
|
+
return { data: await r1.json(), idempotencyKey };
|
|
7037
|
+
}
|
|
7038
|
+
const read = await readFailureBody(r1);
|
|
7039
|
+
throw new ApiError(
|
|
7040
|
+
r1.status,
|
|
7041
|
+
`POST ${path4} failed (${r1.status}): ${read.text}`,
|
|
7042
|
+
idempotencyKey,
|
|
7043
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
7044
|
+
);
|
|
7045
|
+
}
|
|
7046
|
+
const requirements = await r1.json();
|
|
7047
|
+
if (!requirements.accepts || requirements.accepts.length === 0) {
|
|
7048
|
+
throw new Error("No payment methods accepted by server");
|
|
7049
|
+
}
|
|
7050
|
+
const accept = requirements.accepts[0];
|
|
7051
|
+
const { authorization, signature } = await createTransferAuthorization(accept, keystore);
|
|
7052
|
+
const paymentPayload = {
|
|
7053
|
+
x402Version: 2,
|
|
7054
|
+
resource: requirements.resource,
|
|
7055
|
+
accepted: {
|
|
7056
|
+
scheme: accept.scheme,
|
|
7057
|
+
network: accept.network,
|
|
7058
|
+
amount: accept.amount,
|
|
7059
|
+
asset: accept.asset,
|
|
7060
|
+
payTo: accept.payTo,
|
|
7061
|
+
maxTimeoutSeconds: accept.maxTimeoutSeconds,
|
|
7062
|
+
extra: accept.extra
|
|
7063
|
+
},
|
|
7064
|
+
payload: { authorization, signature }
|
|
7065
|
+
};
|
|
7066
|
+
const r2 = await fetch(url, {
|
|
7067
|
+
method: "POST",
|
|
7068
|
+
redirect: "error",
|
|
7069
|
+
headers: {
|
|
7070
|
+
"Content-Type": "application/json",
|
|
7071
|
+
...legalHeaders,
|
|
7072
|
+
...idempotency,
|
|
7073
|
+
"PAYMENT-SIGNATURE": Buffer.from(JSON.stringify(paymentPayload)).toString("base64")
|
|
7074
|
+
},
|
|
7075
|
+
body: JSON.stringify(body)
|
|
7076
|
+
});
|
|
7077
|
+
if (!r2.ok) {
|
|
7078
|
+
const read = await readFailureBody(r2);
|
|
7079
|
+
throw new ApiError(
|
|
7080
|
+
r2.status,
|
|
7081
|
+
failureMessage(`POST ${path4} failed after payment`, r2.status, read),
|
|
7082
|
+
idempotencyKey,
|
|
7083
|
+
apiErrorEnvelopeOf(read.body) ?? void 0
|
|
7084
|
+
);
|
|
7085
|
+
}
|
|
7086
|
+
return { data: await r2.json(), idempotencyKey };
|
|
6641
7087
|
});
|
|
6642
|
-
const result = await r2.json();
|
|
6643
|
-
if (!r2.ok) {
|
|
6644
|
-
throw new Error(`POST ${path4} failed after payment (${r2.status}): ${JSON.stringify(result)}`);
|
|
6645
|
-
}
|
|
6646
|
-
return result;
|
|
6647
7088
|
}
|
|
6648
7089
|
|
|
6649
7090
|
// src/commands/identity.ts
|
|
6650
7091
|
var identityCommand = new Command4("identity").description("Manage agent identity");
|
|
6651
7092
|
identityCommand.command("register").description("Register ERC-8004 agent identity (costs 0.001 USDC)").action(async () => {
|
|
6652
|
-
const result = await x402Post("/api/identity/register", {});
|
|
6653
|
-
printResult({ agentId: result.agentId });
|
|
7093
|
+
const { data: result, idempotencyKey } = await x402Post("/api/identity/register", {});
|
|
7094
|
+
printResult({ agentId: result.agentId }, { idempotencyKey });
|
|
6654
7095
|
});
|
|
6655
7096
|
identityCommand.command("status").description("Check identity registration status").action(async () => {
|
|
6656
7097
|
const keystore = await loadKeystore();
|
|
@@ -6706,7 +7147,7 @@ var statsCommand = new Command5("stats").description("View agent statistics").op
|
|
|
6706
7147
|
});
|
|
6707
7148
|
|
|
6708
7149
|
// src/commands/task/index.ts
|
|
6709
|
-
import { Command as
|
|
7150
|
+
import { Command as Command41 } from "commander";
|
|
6710
7151
|
|
|
6711
7152
|
// src/commands/task/create.ts
|
|
6712
7153
|
import { Command as Command6 } from "commander";
|
|
@@ -6742,9 +7183,8 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6742
7183
|
try {
|
|
6743
7184
|
rewardBaseUnits = usdcToBaseUnits(opts.reward);
|
|
6744
7185
|
} catch (err) {
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
);
|
|
7186
|
+
renderFailure(withErrorContext(err, "Invalid --reward"));
|
|
7187
|
+
return;
|
|
6748
7188
|
}
|
|
6749
7189
|
const duration = Number(opts.duration);
|
|
6750
7190
|
if (!Number.isFinite(duration) || duration <= 0) {
|
|
@@ -6804,9 +7244,8 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6804
7244
|
try {
|
|
6805
7245
|
maxPriceBaseUnits = usdcToBaseUnits(opts.maxPrice);
|
|
6806
7246
|
} catch (err) {
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
);
|
|
7247
|
+
renderFailure(withErrorContext(err, "Invalid --max-price"));
|
|
7248
|
+
return;
|
|
6810
7249
|
}
|
|
6811
7250
|
if (maxPriceBaseUnits !== rewardBaseUnits) {
|
|
6812
7251
|
return void printError(
|
|
@@ -6848,18 +7287,16 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6848
7287
|
try {
|
|
6849
7288
|
body.auctionStartPrice = usdcToBaseUnits(opts.auctionStartPrice, { allowZero: true });
|
|
6850
7289
|
} catch (err) {
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
);
|
|
7290
|
+
renderFailure(withErrorContext(err, "Invalid --auction-start-price"));
|
|
7291
|
+
return;
|
|
6854
7292
|
}
|
|
6855
7293
|
}
|
|
6856
7294
|
if (opts.auctionFloorPrice) {
|
|
6857
7295
|
try {
|
|
6858
7296
|
body.auctionFloorPrice = usdcToBaseUnits(opts.auctionFloorPrice, { allowZero: true });
|
|
6859
7297
|
} catch (err) {
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
);
|
|
7298
|
+
renderFailure(withErrorContext(err, "Invalid --auction-floor-price"));
|
|
7299
|
+
return;
|
|
6863
7300
|
}
|
|
6864
7301
|
}
|
|
6865
7302
|
for (const [flag, value] of [
|
|
@@ -6907,8 +7344,11 @@ var createCmd = new Command6("create").description("Create a new task (costs rew
|
|
|
6907
7344
|
if (opts.appealWindow) body.appealWindowHours = parseFloat(opts.appealWindow);
|
|
6908
7345
|
if (opts.disputeResolver) body.disputeResolver = opts.disputeResolver;
|
|
6909
7346
|
}
|
|
6910
|
-
const result = await x402Post(
|
|
6911
|
-
|
|
7347
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7348
|
+
"/api/tasks",
|
|
7349
|
+
body
|
|
7350
|
+
);
|
|
7351
|
+
printResult({ taskId: result.taskId }, { idempotencyKey });
|
|
6912
7352
|
}
|
|
6913
7353
|
);
|
|
6914
7354
|
|
|
@@ -7019,6 +7459,7 @@ var getCmd = new Command8("get").description("Get task details").argument("<task
|
|
|
7019
7459
|
printError(
|
|
7020
7460
|
`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>)`
|
|
7021
7461
|
);
|
|
7462
|
+
return;
|
|
7022
7463
|
}
|
|
7023
7464
|
printResult(task);
|
|
7024
7465
|
});
|
|
@@ -7119,6 +7560,7 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7119
7560
|
try {
|
|
7120
7561
|
if (!opts.file || opts.file.length === 0) {
|
|
7121
7562
|
printError("--file is required");
|
|
7563
|
+
return;
|
|
7122
7564
|
}
|
|
7123
7565
|
const keystore = await loadKeystore();
|
|
7124
7566
|
const signature = await signMessage(buildSubmitMessage(taskId), keystore);
|
|
@@ -7127,9 +7569,11 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7127
7569
|
const mimeType = mimeTypeForPath(filePath);
|
|
7128
7570
|
const data = await fsPromises.readFile(filePath);
|
|
7129
7571
|
if (data.length === 0) {
|
|
7130
|
-
|
|
7572
|
+
throw new Error(`File is empty: ${basename(filePath)}`);
|
|
7131
7573
|
}
|
|
7132
|
-
const {
|
|
7574
|
+
const {
|
|
7575
|
+
data: { uploadUrl, artifactKey }
|
|
7576
|
+
} = await apiPost(
|
|
7133
7577
|
`/api/tasks/${taskId}/submissions/request-upload-url`,
|
|
7134
7578
|
{
|
|
7135
7579
|
taskId,
|
|
@@ -7164,13 +7608,16 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
7164
7608
|
),
|
|
7165
7609
|
keystore
|
|
7166
7610
|
);
|
|
7167
|
-
const result = await
|
|
7168
|
-
taskId
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7611
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7612
|
+
`/api/tasks/${taskId}/submissions/from-keys`,
|
|
7613
|
+
{
|
|
7614
|
+
taskId,
|
|
7615
|
+
workerAddress: keystore.walletAddress,
|
|
7616
|
+
artifacts: artifactInputs,
|
|
7617
|
+
signature: submitSignature
|
|
7618
|
+
}
|
|
7619
|
+
);
|
|
7620
|
+
printResult({ submissionId: result.submissionId }, { idempotencyKey });
|
|
7174
7621
|
} finally {
|
|
7175
7622
|
submitCmd.setOptionValue("file", []);
|
|
7176
7623
|
}
|
|
@@ -7182,7 +7629,6 @@ var acceptCmd = new Command10("accept").description("Accept a submission (costs
|
|
|
7182
7629
|
const task = await apiGet(`/api/tasks/${taskId}`);
|
|
7183
7630
|
if (!task) {
|
|
7184
7631
|
printError("Task not found");
|
|
7185
|
-
process.exit(1);
|
|
7186
7632
|
return;
|
|
7187
7633
|
}
|
|
7188
7634
|
const canAccept = task.pendingActions?.some(
|
|
@@ -7198,14 +7644,13 @@ var acceptCmd = new Command10("accept").description("Accept a submission (costs
|
|
|
7198
7644
|
printError(
|
|
7199
7645
|
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."
|
|
7200
7646
|
);
|
|
7201
|
-
process.exit(1);
|
|
7202
7647
|
return;
|
|
7203
7648
|
}
|
|
7204
|
-
await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
7649
|
+
const { idempotencyKey } = await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
7205
7650
|
taskId,
|
|
7206
7651
|
worker: opts.worker
|
|
7207
7652
|
});
|
|
7208
|
-
printResult({ accepted: true });
|
|
7653
|
+
printResult({ accepted: true }, { idempotencyKey });
|
|
7209
7654
|
});
|
|
7210
7655
|
|
|
7211
7656
|
// src/commands/task/accept-submissions.ts
|
|
@@ -7240,13 +7685,16 @@ var acceptSubmissionsCmd = new Command11("accept-submissions").description(
|
|
|
7240
7685
|
if (sum !== 1e4) {
|
|
7241
7686
|
throw new Error(`Winner shares must sum to 10000 basis points (got ${sum})`);
|
|
7242
7687
|
}
|
|
7243
|
-
const result = await x402Post(
|
|
7244
|
-
taskId
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7688
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7689
|
+
`/api/tasks/${taskId}/accept-submissions`,
|
|
7690
|
+
{
|
|
7691
|
+
taskId,
|
|
7692
|
+
winners
|
|
7693
|
+
}
|
|
7694
|
+
);
|
|
7695
|
+
printResult({ accepted: result.success, winners: winners.length }, { idempotencyKey });
|
|
7248
7696
|
} catch (err) {
|
|
7249
|
-
|
|
7697
|
+
renderFailure(err);
|
|
7250
7698
|
}
|
|
7251
7699
|
});
|
|
7252
7700
|
|
|
@@ -7256,14 +7704,15 @@ var rateCmd = new Command12("rate").description("Rate a worker (costs 0.001 USDC
|
|
|
7256
7704
|
const rating = parseInt(opts.rating, 10);
|
|
7257
7705
|
if (rating < 0 || rating > 100) {
|
|
7258
7706
|
printError("Rating must be between 0 and 100");
|
|
7707
|
+
return;
|
|
7259
7708
|
}
|
|
7260
|
-
const result = await x402Post(`/api/tasks/${taskId}/rate`, {
|
|
7709
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/rate`, {
|
|
7261
7710
|
taskId,
|
|
7262
7711
|
worker: opts.worker,
|
|
7263
7712
|
rating,
|
|
7264
7713
|
...opts.feedback ? { feedbackText: opts.feedback } : {}
|
|
7265
7714
|
});
|
|
7266
|
-
printResult({ feedbackId: result.feedbackId });
|
|
7715
|
+
printResult({ feedbackId: result.feedbackId }, { idempotencyKey });
|
|
7267
7716
|
});
|
|
7268
7717
|
|
|
7269
7718
|
// src/commands/task/claim.ts
|
|
@@ -7272,11 +7721,14 @@ var claimCmd = new Command13("claim").description("Claim a task as a worker").ar
|
|
|
7272
7721
|
const keystore = await loadKeystore();
|
|
7273
7722
|
const message = buildClaimMessage(taskId);
|
|
7274
7723
|
const signature = await signMessage(message, keystore);
|
|
7275
|
-
const result = await apiPost(
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7724
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
7725
|
+
`/api/tasks/${taskId}/claim`,
|
|
7726
|
+
{
|
|
7727
|
+
workerAddress: keystore.walletAddress,
|
|
7728
|
+
signature
|
|
7729
|
+
}
|
|
7730
|
+
);
|
|
7731
|
+
printResult({ claimId: result.claimId }, { idempotencyKey });
|
|
7280
7732
|
});
|
|
7281
7733
|
|
|
7282
7734
|
// src/commands/task/pitch.ts
|
|
@@ -7284,14 +7736,17 @@ import { Command as Command14 } from "commander";
|
|
|
7284
7736
|
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) => {
|
|
7285
7737
|
const keystore = await loadKeystore();
|
|
7286
7738
|
const signature = await signMessage(`taskmarket:pitch:${taskId}`, keystore);
|
|
7287
|
-
const result = await x402Post(
|
|
7288
|
-
taskId
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7739
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7740
|
+
`/api/tasks/${taskId}/pitches`,
|
|
7741
|
+
{
|
|
7742
|
+
taskId,
|
|
7743
|
+
workerAddress: keystore.walletAddress,
|
|
7744
|
+
pitchText: opts.text,
|
|
7745
|
+
...opts.duration ? { estimatedDuration: parseInt(opts.duration, 10) } : {},
|
|
7746
|
+
signature
|
|
7747
|
+
}
|
|
7748
|
+
);
|
|
7749
|
+
printResult({ pitchId: result.pitchId }, { idempotencyKey });
|
|
7295
7750
|
});
|
|
7296
7751
|
|
|
7297
7752
|
// src/commands/task/pitches.ts
|
|
@@ -7302,7 +7757,7 @@ var pitchesCmd = new Command15("pitches").description("List pitches for a task")
|
|
|
7302
7757
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
7303
7758
|
printResult(await apiGet(`/api/tasks/${taskId}/pitches`, { headers }));
|
|
7304
7759
|
} catch (err) {
|
|
7305
|
-
|
|
7760
|
+
renderFailure(err);
|
|
7306
7761
|
}
|
|
7307
7762
|
});
|
|
7308
7763
|
|
|
@@ -7312,13 +7767,13 @@ var selectWorkerCmd = new Command16("select-worker").description("Select a worke
|
|
|
7312
7767
|
const keystore = await loadKeystore();
|
|
7313
7768
|
const message = buildSelectWorkerMessage(taskId, opts.pitch, opts.worker);
|
|
7314
7769
|
const signature = await signMessage(message, keystore);
|
|
7315
|
-
await apiPost(`/api/tasks/${taskId}/pitches/select`, {
|
|
7770
|
+
const { idempotencyKey } = await apiPost(`/api/tasks/${taskId}/pitches/select`, {
|
|
7316
7771
|
taskId,
|
|
7317
7772
|
pitchId: opts.pitch,
|
|
7318
7773
|
workerAddress: opts.worker,
|
|
7319
7774
|
signature
|
|
7320
7775
|
});
|
|
7321
|
-
printResult({ selected: true });
|
|
7776
|
+
printResult({ selected: true }, { idempotencyKey });
|
|
7322
7777
|
});
|
|
7323
7778
|
|
|
7324
7779
|
// src/commands/task/proof.ts
|
|
@@ -7326,7 +7781,7 @@ import { Command as Command17 } from "commander";
|
|
|
7326
7781
|
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) => {
|
|
7327
7782
|
const keystore = await loadKeystore();
|
|
7328
7783
|
const signature = await signMessage(`taskmarket:proof:${taskId}`, keystore);
|
|
7329
|
-
const result = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
7784
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
7330
7785
|
taskId,
|
|
7331
7786
|
workerAddress: keystore.walletAddress,
|
|
7332
7787
|
proofData: opts.data,
|
|
@@ -7334,7 +7789,7 @@ var proofCmd = new Command17("proof").description("Submit a benchmark proof (cos
|
|
|
7334
7789
|
...opts.metric ? { metricValue: opts.metric } : {},
|
|
7335
7790
|
signature
|
|
7336
7791
|
});
|
|
7337
|
-
printResult({ proofId: result.proofId, submissionId: result.submissionId });
|
|
7792
|
+
printResult({ proofId: result.proofId, submissionId: result.submissionId }, { idempotencyKey });
|
|
7338
7793
|
});
|
|
7339
7794
|
|
|
7340
7795
|
// src/commands/task/proofs.ts
|
|
@@ -7345,7 +7800,7 @@ var proofsCmd = new Command18("proofs").description("List proofs for a benchmark
|
|
|
7345
7800
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
7346
7801
|
printResult(await apiGet(`/api/tasks/${taskId}/proofs`, { headers }));
|
|
7347
7802
|
} catch (err) {
|
|
7348
|
-
|
|
7803
|
+
renderFailure(err);
|
|
7349
7804
|
}
|
|
7350
7805
|
});
|
|
7351
7806
|
|
|
@@ -7356,15 +7811,17 @@ var bidCmd = new Command19("bid").description("Submit a bid on an auction task")
|
|
|
7356
7811
|
try {
|
|
7357
7812
|
priceBaseUnits = usdcToBaseUnits(opts.price);
|
|
7358
7813
|
} catch (err) {
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
);
|
|
7814
|
+
renderFailure(withErrorContext(err, "Invalid --price"));
|
|
7815
|
+
return;
|
|
7362
7816
|
}
|
|
7363
|
-
const result = await x402Post(
|
|
7364
|
-
taskId
|
|
7365
|
-
|
|
7366
|
-
|
|
7367
|
-
|
|
7817
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7818
|
+
`/api/tasks/${taskId}/bids`,
|
|
7819
|
+
{
|
|
7820
|
+
taskId,
|
|
7821
|
+
price: priceBaseUnits
|
|
7822
|
+
}
|
|
7823
|
+
);
|
|
7824
|
+
printResult({ bidId: result.bidId }, { idempotencyKey });
|
|
7368
7825
|
});
|
|
7369
7826
|
|
|
7370
7827
|
// src/commands/task/auction-accept.ts
|
|
@@ -7378,17 +7835,19 @@ var auctionAcceptCmd = new Command20("auction-accept").description("Accept curre
|
|
|
7378
7835
|
try {
|
|
7379
7836
|
body.minPrice = usdcToBaseUnits(opts.minPrice, { allowZero: true });
|
|
7380
7837
|
} catch (error) {
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
);
|
|
7838
|
+
renderFailure(withErrorContext(error, "Invalid --min-price"));
|
|
7839
|
+
return;
|
|
7384
7840
|
}
|
|
7385
7841
|
}
|
|
7386
|
-
const result = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
7387
|
-
printResult(
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7842
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
7843
|
+
printResult(
|
|
7844
|
+
{
|
|
7845
|
+
acceptedPrice: result.acceptedPrice,
|
|
7846
|
+
acceptedPriceUsdc: formatUsdcBaseUnits(result.acceptedPrice),
|
|
7847
|
+
workerAddress: result.workerAddress
|
|
7848
|
+
},
|
|
7849
|
+
{ idempotencyKey }
|
|
7850
|
+
);
|
|
7392
7851
|
});
|
|
7393
7852
|
|
|
7394
7853
|
// src/commands/task/submissions.ts
|
|
@@ -7399,8 +7858,8 @@ var submissionsCmd = new Command21("submissions").description("List submissions
|
|
|
7399
7858
|
try {
|
|
7400
7859
|
subs = await apiGet(`/api/tasks/${taskId}/submissions`, { headers: auth?.headers ?? {} });
|
|
7401
7860
|
} catch (err) {
|
|
7402
|
-
|
|
7403
|
-
|
|
7861
|
+
renderFailure(err, { fallback: "Failed to fetch submissions." });
|
|
7862
|
+
return;
|
|
7404
7863
|
}
|
|
7405
7864
|
printResult(subs);
|
|
7406
7865
|
});
|
|
@@ -7409,15 +7868,17 @@ var submissionsCmd = new Command21("submissions").description("List submissions
|
|
|
7409
7868
|
import { Command as Command22 } from "commander";
|
|
7410
7869
|
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) => {
|
|
7411
7870
|
let result;
|
|
7871
|
+
let idempotencyKey;
|
|
7412
7872
|
try {
|
|
7413
|
-
result = await apiPost(
|
|
7414
|
-
taskId
|
|
7415
|
-
|
|
7873
|
+
({ data: result, idempotencyKey } = await apiPost(
|
|
7874
|
+
`/api/tasks/${taskId}/bids/select-winner`,
|
|
7875
|
+
{ taskId }
|
|
7876
|
+
));
|
|
7416
7877
|
} catch (err) {
|
|
7417
|
-
|
|
7418
|
-
|
|
7878
|
+
renderFailure(err, { fallback: "Failed to select winner." });
|
|
7879
|
+
return;
|
|
7419
7880
|
}
|
|
7420
|
-
printResult(result);
|
|
7881
|
+
printResult(result, { idempotencyKey });
|
|
7421
7882
|
});
|
|
7422
7883
|
|
|
7423
7884
|
// src/commands/task/download.ts
|
|
@@ -7440,18 +7901,19 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7440
7901
|
if (opts.artifact) {
|
|
7441
7902
|
body.artifactId = opts.artifact;
|
|
7442
7903
|
}
|
|
7443
|
-
const result = await apiPost(
|
|
7904
|
+
const { data: result } = await apiPost(
|
|
7444
7905
|
`/api/tasks/${taskId}/submissions/${opts.submission}/preview`,
|
|
7445
7906
|
body
|
|
7446
7907
|
);
|
|
7447
7908
|
presignedUrl = result.presignedUrl;
|
|
7448
7909
|
} catch (err) {
|
|
7449
|
-
|
|
7450
|
-
|
|
7910
|
+
renderFailure(err, { fallback: "Failed to get download URL." });
|
|
7911
|
+
return;
|
|
7451
7912
|
}
|
|
7452
7913
|
const res = await fetch(presignedUrl);
|
|
7453
7914
|
if (!res.ok) {
|
|
7454
7915
|
printError(`Failed to download file: ${res.status}`);
|
|
7916
|
+
return;
|
|
7455
7917
|
}
|
|
7456
7918
|
const content = Buffer.from(await res.arrayBuffer());
|
|
7457
7919
|
if (opts.output) {
|
|
@@ -7465,6 +7927,7 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7465
7927
|
printError(
|
|
7466
7928
|
"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."
|
|
7467
7929
|
);
|
|
7930
|
+
return;
|
|
7468
7931
|
}
|
|
7469
7932
|
process.stdout.write(sanitizeForTerminal(decoded));
|
|
7470
7933
|
}
|
|
@@ -7474,8 +7937,11 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
7474
7937
|
// src/commands/task/cancel.ts
|
|
7475
7938
|
import { Command as Command24 } from "commander";
|
|
7476
7939
|
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) => {
|
|
7477
|
-
const result = await x402Post(
|
|
7478
|
-
|
|
7940
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7941
|
+
`/api/tasks/${taskId}/cancel`,
|
|
7942
|
+
{ taskId }
|
|
7943
|
+
);
|
|
7944
|
+
printResult(result, { idempotencyKey });
|
|
7479
7945
|
});
|
|
7480
7946
|
|
|
7481
7947
|
// src/commands/task/refund-expired.ts
|
|
@@ -7484,11 +7950,13 @@ var refundExpiredCmd = new Command25("refund-expired").description(
|
|
|
7484
7950
|
"Refund an expired task with no submissions back to the requester (costs 0.001 USDC)"
|
|
7485
7951
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
7486
7952
|
try {
|
|
7487
|
-
const result = await x402Post(
|
|
7488
|
-
|
|
7953
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7954
|
+
`/api/tasks/${taskId}/refund-expired`,
|
|
7955
|
+
{ taskId }
|
|
7956
|
+
);
|
|
7957
|
+
printResult(result, { idempotencyKey });
|
|
7489
7958
|
} catch (err) {
|
|
7490
|
-
|
|
7491
|
-
process.exit(1);
|
|
7959
|
+
renderFailure(err);
|
|
7492
7960
|
}
|
|
7493
7961
|
});
|
|
7494
7962
|
|
|
@@ -7498,14 +7966,16 @@ var rejectSubmissionCmd = new Command26("reject-submission").description(
|
|
|
7498
7966
|
"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."
|
|
7499
7967
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <address>", "Worker address whose submission to reject").action(async (taskId, opts) => {
|
|
7500
7968
|
try {
|
|
7501
|
-
const result = await x402Post(
|
|
7502
|
-
taskId
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7969
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
7970
|
+
`/api/tasks/${taskId}/reject-submission`,
|
|
7971
|
+
{
|
|
7972
|
+
taskId,
|
|
7973
|
+
worker: opts.worker
|
|
7974
|
+
}
|
|
7975
|
+
);
|
|
7976
|
+
printResult(result, { idempotencyKey });
|
|
7506
7977
|
} catch (err) {
|
|
7507
|
-
|
|
7508
|
-
process.exit(1);
|
|
7978
|
+
renderFailure(err);
|
|
7509
7979
|
}
|
|
7510
7980
|
});
|
|
7511
7981
|
|
|
@@ -7527,7 +7997,8 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7527
7997
|
try {
|
|
7528
7998
|
submissions = await apiGet(`/api/tasks/${taskId}/submissions`);
|
|
7529
7999
|
} catch (err) {
|
|
7530
|
-
|
|
8000
|
+
renderFailure(err);
|
|
8001
|
+
return;
|
|
7531
8002
|
}
|
|
7532
8003
|
const workers = activeSubmissionWorkers(submissions);
|
|
7533
8004
|
if (workers.length === 0) {
|
|
@@ -7537,20 +8008,40 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7537
8008
|
const results = [];
|
|
7538
8009
|
for (const worker of workers) {
|
|
7539
8010
|
try {
|
|
7540
|
-
const res = await x402Post(
|
|
7541
|
-
taskId
|
|
7542
|
-
worker
|
|
7543
|
-
|
|
7544
|
-
results.push({ worker, txHash: res.txHash });
|
|
8011
|
+
const { data: res, idempotencyKey } = await x402Post(
|
|
8012
|
+
`/api/tasks/${taskId}/reject-submission`,
|
|
8013
|
+
{ taskId, worker }
|
|
8014
|
+
);
|
|
8015
|
+
results.push({ worker, txHash: res.txHash, idempotencyKey });
|
|
7545
8016
|
} catch (err) {
|
|
7546
|
-
results.push({
|
|
8017
|
+
results.push({
|
|
8018
|
+
worker,
|
|
8019
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8020
|
+
idempotencyKey: idempotencyKeyForError(err),
|
|
8021
|
+
cause: err
|
|
8022
|
+
});
|
|
7547
8023
|
}
|
|
7548
8024
|
}
|
|
7549
|
-
const failed = results.filter((r) => r.error);
|
|
8025
|
+
const failed = results.filter((r) => r.error !== void 0);
|
|
7550
8026
|
if (failed.length > 0) {
|
|
7551
|
-
|
|
7552
|
-
|
|
8027
|
+
const representative = failed.find((r) => isPendingApiError(r.cause)) ?? failed[0];
|
|
8028
|
+
renderFailure(
|
|
8029
|
+
withErrorContext(
|
|
8030
|
+
representative.cause,
|
|
8031
|
+
`${failed.length} of ${results.length} rejection(s) failed`
|
|
8032
|
+
),
|
|
8033
|
+
{
|
|
8034
|
+
details: {
|
|
8035
|
+
results: results.map(({ worker, txHash, idempotencyKey, error }) => ({
|
|
8036
|
+
worker,
|
|
8037
|
+
txHash,
|
|
8038
|
+
idempotencyKey,
|
|
8039
|
+
error
|
|
8040
|
+
}))
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
7553
8043
|
);
|
|
8044
|
+
return;
|
|
7554
8045
|
}
|
|
7555
8046
|
if (!opts.cancel) {
|
|
7556
8047
|
printResult({ rejected: results.length, results });
|
|
@@ -7558,11 +8049,15 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
7558
8049
|
}
|
|
7559
8050
|
let cancelRes;
|
|
7560
8051
|
try {
|
|
7561
|
-
cancelRes = await x402Post(
|
|
8052
|
+
({ data: cancelRes } = await x402Post(
|
|
8053
|
+
`/api/tasks/${taskId}/cancel`,
|
|
8054
|
+
{ taskId }
|
|
8055
|
+
));
|
|
7562
8056
|
} catch (err) {
|
|
7563
|
-
|
|
7564
|
-
`All ${results.length} submission(s) rejected but cancel failed
|
|
8057
|
+
renderFailure(
|
|
8058
|
+
withErrorContext(err, `All ${results.length} submission(s) rejected but cancel failed`)
|
|
7565
8059
|
);
|
|
8060
|
+
return;
|
|
7566
8061
|
}
|
|
7567
8062
|
printResult({ rejected: results.length, results, cancelTxHash: cancelRes.txHash });
|
|
7568
8063
|
});
|
|
@@ -7582,8 +8077,7 @@ var mySubmissionsCmd = new Command28("my-submissions").description("List all sub
|
|
|
7582
8077
|
);
|
|
7583
8078
|
printResult(result);
|
|
7584
8079
|
} catch (err) {
|
|
7585
|
-
|
|
7586
|
-
process.exit(1);
|
|
8080
|
+
renderFailure(err);
|
|
7587
8081
|
}
|
|
7588
8082
|
});
|
|
7589
8083
|
|
|
@@ -7596,9 +8090,8 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7596
8090
|
try {
|
|
7597
8091
|
body.reward = usdcToBaseUnits(opts.reward);
|
|
7598
8092
|
} catch (err) {
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
);
|
|
8093
|
+
renderFailure(withErrorContext(err, "Invalid --reward"));
|
|
8094
|
+
return;
|
|
7602
8095
|
}
|
|
7603
8096
|
}
|
|
7604
8097
|
if (opts.extendExpiry !== void 0) {
|
|
@@ -7607,10 +8100,12 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7607
8100
|
printError(
|
|
7608
8101
|
`--extend-expiry must be a positive integer (seconds), got: ${opts.extendExpiry}`
|
|
7609
8102
|
);
|
|
8103
|
+
return;
|
|
7610
8104
|
}
|
|
7611
8105
|
const task = await apiGet(`/api/tasks/${taskId}`);
|
|
7612
8106
|
if (!task) {
|
|
7613
8107
|
printError(`Task not found: ${taskId}`);
|
|
8108
|
+
return;
|
|
7614
8109
|
}
|
|
7615
8110
|
const currentExpiry = Math.floor(new Date(task.expiryTime).getTime() / 1e3);
|
|
7616
8111
|
const newExpiry = currentExpiry + delta;
|
|
@@ -7620,6 +8115,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7620
8115
|
printError(
|
|
7621
8116
|
`--extend-expiry would set expiry in the past. Task expired ${expiredAgo}s ago; pass at least ${expiredAgo + 1} seconds to extend beyond now.`
|
|
7622
8117
|
);
|
|
8118
|
+
return;
|
|
7623
8119
|
}
|
|
7624
8120
|
body.expiryTime = newExpiry;
|
|
7625
8121
|
}
|
|
@@ -7627,6 +8123,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7627
8123
|
const ts = Math.floor(new Date(opts.bidDeadline).getTime() / 1e3);
|
|
7628
8124
|
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
7629
8125
|
printError("--bid-deadline must be in the future");
|
|
8126
|
+
return;
|
|
7630
8127
|
} else {
|
|
7631
8128
|
body.bidDeadline = ts;
|
|
7632
8129
|
}
|
|
@@ -7635,6 +8132,7 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7635
8132
|
const ts = Math.floor(new Date(opts.pitchDeadline).getTime() / 1e3);
|
|
7636
8133
|
if (ts <= Math.floor(Date.now() / 1e3)) {
|
|
7637
8134
|
printError("--pitch-deadline must be in the future");
|
|
8135
|
+
return;
|
|
7638
8136
|
} else {
|
|
7639
8137
|
body.pitchDeadline = ts;
|
|
7640
8138
|
}
|
|
@@ -7643,18 +8141,16 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7643
8141
|
try {
|
|
7644
8142
|
body.auctionFloorPrice = usdcToBaseUnits(opts.auctionFloorPrice, { allowZero: true });
|
|
7645
8143
|
} catch (err) {
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
);
|
|
8144
|
+
renderFailure(withErrorContext(err, "Invalid --auction-floor-price"));
|
|
8145
|
+
return;
|
|
7649
8146
|
}
|
|
7650
8147
|
}
|
|
7651
8148
|
if (opts.auctionStartPrice !== void 0) {
|
|
7652
8149
|
try {
|
|
7653
8150
|
body.auctionStartPrice = usdcToBaseUnits(opts.auctionStartPrice, { allowZero: true });
|
|
7654
8151
|
} catch (err) {
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
);
|
|
8152
|
+
renderFailure(withErrorContext(err, "Invalid --auction-start-price"));
|
|
8153
|
+
return;
|
|
7658
8154
|
}
|
|
7659
8155
|
}
|
|
7660
8156
|
if (opts.description !== void 0) {
|
|
@@ -7666,8 +8162,11 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
7666
8162
|
if (opts.metricDescription !== void 0) {
|
|
7667
8163
|
body.metricDescription = opts.metricDescription;
|
|
7668
8164
|
}
|
|
7669
|
-
const result = await x402Post(
|
|
7670
|
-
|
|
8165
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8166
|
+
`/api/tasks/${taskId}/update`,
|
|
8167
|
+
body
|
|
8168
|
+
);
|
|
8169
|
+
printResult(result, { idempotencyKey });
|
|
7671
8170
|
}
|
|
7672
8171
|
);
|
|
7673
8172
|
|
|
@@ -7678,20 +8177,77 @@ var forfeitCmd = new Command30("forfeit").description("Reclaim a claim-mode task
|
|
|
7678
8177
|
const keystore = await loadKeystore();
|
|
7679
8178
|
const message = buildForfeitMessage(taskId);
|
|
7680
8179
|
const signature = await signMessage(message, keystore);
|
|
7681
|
-
const result = await apiPost(
|
|
7682
|
-
taskId
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
8180
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8181
|
+
`/api/tasks/${taskId}/forfeit`,
|
|
8182
|
+
{
|
|
8183
|
+
taskId,
|
|
8184
|
+
requesterAddress: keystore.walletAddress,
|
|
8185
|
+
signature
|
|
8186
|
+
}
|
|
8187
|
+
);
|
|
8188
|
+
printResult(result, { idempotencyKey });
|
|
7687
8189
|
} catch (err) {
|
|
7688
|
-
|
|
8190
|
+
renderFailure(err);
|
|
7689
8191
|
}
|
|
7690
8192
|
});
|
|
7691
8193
|
|
|
7692
|
-
// src/commands/task/
|
|
8194
|
+
// src/commands/task/assign-evaluator.ts
|
|
7693
8195
|
import { Command as Command31 } from "commander";
|
|
7694
|
-
var
|
|
8196
|
+
var ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
8197
|
+
var assignEvaluatorCmd = new Command31("assign-evaluator").description(
|
|
8198
|
+
"Assign an evaluator to an open, unclaimed task you requested (costs 0.001 USDC). Only possible before a worker claims the task."
|
|
8199
|
+
).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(
|
|
8200
|
+
async (taskId, opts) => {
|
|
8201
|
+
if (!ADDRESS_PATTERN.test(opts.evaluator)) {
|
|
8202
|
+
return void printError(`--evaluator must be a wallet address, got: ${opts.evaluator}`);
|
|
8203
|
+
}
|
|
8204
|
+
if (opts.disputeResolver !== void 0 && !ADDRESS_PATTERN.test(opts.disputeResolver)) {
|
|
8205
|
+
return void printError(
|
|
8206
|
+
`--dispute-resolver must be a wallet address, got: ${opts.disputeResolver}`
|
|
8207
|
+
);
|
|
8208
|
+
}
|
|
8209
|
+
const body = { taskId, evaluator: opts.evaluator };
|
|
8210
|
+
if (opts.evaluatorFeeBps !== void 0) {
|
|
8211
|
+
const bps = Number(opts.evaluatorFeeBps);
|
|
8212
|
+
if (!Number.isInteger(bps) || bps < 0 || bps > 1e4) {
|
|
8213
|
+
return void printError(
|
|
8214
|
+
`--evaluator-fee-bps must be an integer between 0 and 10000, got: ${opts.evaluatorFeeBps}`
|
|
8215
|
+
);
|
|
8216
|
+
}
|
|
8217
|
+
body.evaluatorFeeBps = bps;
|
|
8218
|
+
}
|
|
8219
|
+
if (opts.evaluationWindow !== void 0) {
|
|
8220
|
+
const hours = Number(opts.evaluationWindow);
|
|
8221
|
+
if (!Number.isFinite(hours) || hours <= 0) {
|
|
8222
|
+
return void printError(
|
|
8223
|
+
`--evaluation-window must be a positive number of hours, got: ${opts.evaluationWindow}`
|
|
8224
|
+
);
|
|
8225
|
+
}
|
|
8226
|
+
body.evaluationWindowHours = hours;
|
|
8227
|
+
}
|
|
8228
|
+
if (opts.appealWindow !== void 0) {
|
|
8229
|
+
const hours = Number(opts.appealWindow);
|
|
8230
|
+
if (!Number.isFinite(hours) || hours <= 0) {
|
|
8231
|
+
return void printError(
|
|
8232
|
+
`--appeal-window must be a positive number of hours, got: ${opts.appealWindow}`
|
|
8233
|
+
);
|
|
8234
|
+
}
|
|
8235
|
+
body.appealWindowHours = hours;
|
|
8236
|
+
}
|
|
8237
|
+
if (opts.disputeResolver !== void 0) {
|
|
8238
|
+
body.disputeResolver = opts.disputeResolver;
|
|
8239
|
+
}
|
|
8240
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8241
|
+
`/api/tasks/${taskId}/evaluator`,
|
|
8242
|
+
body
|
|
8243
|
+
);
|
|
8244
|
+
printResult(result, { idempotencyKey });
|
|
8245
|
+
}
|
|
8246
|
+
);
|
|
8247
|
+
|
|
8248
|
+
// src/commands/task/evaluate.ts
|
|
8249
|
+
import { Command as Command32 } from "commander";
|
|
8250
|
+
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(
|
|
7695
8251
|
"--award <worker:amount:rank>",
|
|
7696
8252
|
"Award entry (repeatable): worker:amountUSDC:rank",
|
|
7697
8253
|
collect,
|
|
@@ -7720,9 +8276,8 @@ var evaluateCmd = new Command31("evaluate").description("Submit an evaluation ve
|
|
|
7720
8276
|
try {
|
|
7721
8277
|
microUnits = usdcToBaseUnits(amountUSDC);
|
|
7722
8278
|
} catch (err) {
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
);
|
|
8279
|
+
renderFailure(withErrorContext(err, `Invalid amount in '${entry}'`));
|
|
8280
|
+
return;
|
|
7726
8281
|
}
|
|
7727
8282
|
const parsedRank = Number(rankStr);
|
|
7728
8283
|
if (!Number.isInteger(parsedRank) || parsedRank < 1) {
|
|
@@ -7745,8 +8300,11 @@ var evaluateCmd = new Command31("evaluate").description("Submit an evaluation ve
|
|
|
7745
8300
|
}
|
|
7746
8301
|
body.evidenceHash = opts.evidenceHash;
|
|
7747
8302
|
}
|
|
7748
|
-
const result = await x402Post(
|
|
7749
|
-
|
|
8303
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8304
|
+
`/api/tasks/${taskId}/evaluate`,
|
|
8305
|
+
body
|
|
8306
|
+
);
|
|
8307
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7750
8308
|
}
|
|
7751
8309
|
);
|
|
7752
8310
|
function collect(val, prev) {
|
|
@@ -7754,28 +8312,28 @@ function collect(val, prev) {
|
|
|
7754
8312
|
}
|
|
7755
8313
|
|
|
7756
8314
|
// src/commands/task/appeal.ts
|
|
7757
|
-
import { Command as
|
|
7758
|
-
var appealCmd = new
|
|
7759
|
-
const result = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
7760
|
-
printResult({ txHash: result.txHash });
|
|
8315
|
+
import { Command as Command33 } from "commander";
|
|
8316
|
+
var appealCmd = new Command33("appeal").description("Appeal an evaluator verdict while in Appealing state").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
8317
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
8318
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7761
8319
|
});
|
|
7762
8320
|
|
|
7763
8321
|
// src/commands/task/evaluator-timeout.ts
|
|
7764
|
-
import { Command as
|
|
7765
|
-
var evaluatorTimeoutCmd = new
|
|
7766
|
-
const result = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
7767
|
-
printResult({ txHash: result.txHash });
|
|
8322
|
+
import { Command as Command34 } from "commander";
|
|
8323
|
+
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) => {
|
|
8324
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
8325
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7768
8326
|
});
|
|
7769
8327
|
|
|
7770
8328
|
// src/commands/task/finalize-verdict.ts
|
|
7771
|
-
import { Command as
|
|
7772
|
-
var finalizeVerdictCmd = new
|
|
7773
|
-
const result = await apiPost(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
7774
|
-
printResult({ txHash: result.txHash });
|
|
8329
|
+
import { Command as Command35 } from "commander";
|
|
8330
|
+
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) => {
|
|
8331
|
+
const { data: result, idempotencyKey } = await apiPost(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
8332
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7775
8333
|
});
|
|
7776
8334
|
|
|
7777
8335
|
// src/commands/task/resolve-dispute.ts
|
|
7778
|
-
import { Command as
|
|
8336
|
+
import { Command as Command36 } from "commander";
|
|
7779
8337
|
function parseAward(spec) {
|
|
7780
8338
|
const parts = spec.split(":");
|
|
7781
8339
|
if (parts.length !== 3) {
|
|
@@ -7796,7 +8354,7 @@ function parseAward(spec) {
|
|
|
7796
8354
|
rank
|
|
7797
8355
|
};
|
|
7798
8356
|
}
|
|
7799
|
-
var resolveDisputeCmd = new
|
|
8357
|
+
var resolveDisputeCmd = new Command36("resolve-dispute").description(
|
|
7800
8358
|
"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"
|
|
7801
8359
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict type: approve or partial").requiredOption(
|
|
7802
8360
|
"--award <spec...>",
|
|
@@ -7810,76 +8368,80 @@ var resolveDisputeCmd = new Command35("resolve-dispute").description(
|
|
|
7810
8368
|
try {
|
|
7811
8369
|
awards = opts.award.map(parseAward);
|
|
7812
8370
|
} catch (err) {
|
|
7813
|
-
|
|
8371
|
+
renderFailure(err);
|
|
7814
8372
|
return;
|
|
7815
8373
|
}
|
|
7816
|
-
const result = await x402Post(
|
|
7817
|
-
taskId
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
8374
|
+
const { data: result, idempotencyKey } = await x402Post(
|
|
8375
|
+
`/api/tasks/${taskId}/resolve-dispute`,
|
|
8376
|
+
{
|
|
8377
|
+
taskId,
|
|
8378
|
+
verdict: opts.verdict,
|
|
8379
|
+
awards
|
|
8380
|
+
}
|
|
8381
|
+
);
|
|
8382
|
+
printResult({ txHash: result.txHash }, { idempotencyKey });
|
|
7822
8383
|
});
|
|
7823
8384
|
|
|
7824
8385
|
// src/commands/task/unlock.ts
|
|
7825
|
-
import { Command as
|
|
7826
|
-
var unlockCmd = new
|
|
8386
|
+
import { Command as Command37 } from "commander";
|
|
8387
|
+
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) => {
|
|
7827
8388
|
let result;
|
|
8389
|
+
let idempotencyKey;
|
|
7828
8390
|
try {
|
|
7829
|
-
result = await apiPost(
|
|
7830
|
-
taskId
|
|
7831
|
-
password: opts.password
|
|
7832
|
-
|
|
8391
|
+
({ data: result, idempotencyKey } = await apiPost(
|
|
8392
|
+
`/api/tasks/${taskId}/private-access/verify`,
|
|
8393
|
+
{ taskId, password: opts.password }
|
|
8394
|
+
));
|
|
7833
8395
|
} catch (err) {
|
|
7834
|
-
|
|
8396
|
+
renderFailure(err, { fallback: "Failed to unlock task." });
|
|
7835
8397
|
return;
|
|
7836
8398
|
}
|
|
7837
8399
|
await saveTaskAccessGrant(taskId, result.grant, result.expiresAt);
|
|
7838
|
-
printResult({ taskId, expiresAt: result.expiresAt });
|
|
8400
|
+
printResult({ taskId, expiresAt: result.expiresAt }, { idempotencyKey });
|
|
7839
8401
|
});
|
|
7840
8402
|
|
|
7841
8403
|
// src/commands/task/invite.ts
|
|
7842
|
-
import { Command as
|
|
7843
|
-
var inviteCmd = new
|
|
8404
|
+
import { Command as Command38 } from "commander";
|
|
8405
|
+
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) => {
|
|
7844
8406
|
const auth = await signReadAuth();
|
|
7845
8407
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7846
8408
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
7847
8409
|
return;
|
|
7848
8410
|
}
|
|
7849
8411
|
try {
|
|
7850
|
-
const result = await apiPost(
|
|
8412
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
7851
8413
|
`/api/tasks/${taskId}/private-access/viewers`,
|
|
7852
8414
|
{ taskId, viewerAddress: address },
|
|
7853
8415
|
{ headers: auth.headers }
|
|
7854
8416
|
);
|
|
7855
|
-
printResult(result);
|
|
8417
|
+
printResult(result, { idempotencyKey });
|
|
7856
8418
|
} catch (err) {
|
|
7857
|
-
|
|
8419
|
+
renderFailure(err, { fallback: "Failed to invite viewer." });
|
|
7858
8420
|
}
|
|
7859
8421
|
});
|
|
7860
8422
|
|
|
7861
8423
|
// src/commands/task/uninvite.ts
|
|
7862
|
-
import { Command as
|
|
7863
|
-
var uninviteCmd = new
|
|
8424
|
+
import { Command as Command39 } from "commander";
|
|
8425
|
+
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) => {
|
|
7864
8426
|
const auth = await signReadAuth();
|
|
7865
8427
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7866
8428
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
7867
8429
|
return;
|
|
7868
8430
|
}
|
|
7869
8431
|
try {
|
|
7870
|
-
const result = await apiDelete(
|
|
8432
|
+
const { data: result, idempotencyKey } = await apiDelete(
|
|
7871
8433
|
`/api/tasks/${taskId}/private-access/viewers/${encodeURIComponent(address)}`,
|
|
7872
8434
|
{ headers: auth.headers }
|
|
7873
8435
|
);
|
|
7874
|
-
printResult(result);
|
|
8436
|
+
printResult(result, { idempotencyKey });
|
|
7875
8437
|
} catch (err) {
|
|
7876
|
-
|
|
8438
|
+
renderFailure(err, { fallback: "Failed to remove viewer." });
|
|
7877
8439
|
}
|
|
7878
8440
|
});
|
|
7879
8441
|
|
|
7880
8442
|
// src/commands/task/viewers.ts
|
|
7881
|
-
import { Command as
|
|
7882
|
-
var viewersCmd = new
|
|
8443
|
+
import { Command as Command40 } from "commander";
|
|
8444
|
+
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) => {
|
|
7883
8445
|
const auth = await signReadAuth();
|
|
7884
8446
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
7885
8447
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -7891,12 +8453,12 @@ var viewersCmd = new Command39("viewers").description("List a private task's wal
|
|
|
7891
8453
|
});
|
|
7892
8454
|
printResult(result);
|
|
7893
8455
|
} catch (err) {
|
|
7894
|
-
|
|
8456
|
+
renderFailure(err, { fallback: "Failed to list viewers." });
|
|
7895
8457
|
}
|
|
7896
8458
|
});
|
|
7897
8459
|
|
|
7898
8460
|
// src/commands/task/index.ts
|
|
7899
|
-
var taskCommand = new
|
|
8461
|
+
var taskCommand = new Command41("task").description("Manage tasks");
|
|
7900
8462
|
taskCommand.addCommand(createCmd);
|
|
7901
8463
|
taskCommand.addCommand(listCmd);
|
|
7902
8464
|
taskCommand.addCommand(getCmd);
|
|
@@ -7922,6 +8484,7 @@ taskCommand.addCommand(rejectAllSubmissionsCmd);
|
|
|
7922
8484
|
taskCommand.addCommand(mySubmissionsCmd);
|
|
7923
8485
|
taskCommand.addCommand(updateCmd);
|
|
7924
8486
|
taskCommand.addCommand(forfeitCmd);
|
|
8487
|
+
taskCommand.addCommand(assignEvaluatorCmd);
|
|
7925
8488
|
taskCommand.addCommand(evaluateCmd);
|
|
7926
8489
|
taskCommand.addCommand(appealCmd);
|
|
7927
8490
|
taskCommand.addCommand(evaluatorTimeoutCmd);
|
|
@@ -7933,8 +8496,8 @@ taskCommand.addCommand(uninviteCmd);
|
|
|
7933
8496
|
taskCommand.addCommand(viewersCmd);
|
|
7934
8497
|
|
|
7935
8498
|
// src/commands/agents.ts
|
|
7936
|
-
import { Command as
|
|
7937
|
-
var agentsCommand = new
|
|
8499
|
+
import { Command as Command42 } from "commander";
|
|
8500
|
+
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) => {
|
|
7938
8501
|
const params = new URLSearchParams();
|
|
7939
8502
|
if (opts.sort) params.set("sort", opts.sort);
|
|
7940
8503
|
if (opts.skill) params.set("skill", opts.skill);
|
|
@@ -7945,11 +8508,12 @@ var agentsCommand = new Command41("agents").description("Browse the agent direct
|
|
|
7945
8508
|
});
|
|
7946
8509
|
|
|
7947
8510
|
// src/commands/inbox.ts
|
|
7948
|
-
import { Command as
|
|
7949
|
-
var inboxCommand = new
|
|
8511
|
+
import { Command as Command43 } from "commander";
|
|
8512
|
+
var inboxCommand = new Command43("inbox").description("Show tasks you created and tasks you are working on").action(async () => {
|
|
7950
8513
|
const auth = await signReadAuth();
|
|
7951
8514
|
if (!auth) {
|
|
7952
8515
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8516
|
+
return;
|
|
7953
8517
|
}
|
|
7954
8518
|
const address = auth.walletAddress;
|
|
7955
8519
|
const hasReadAuth = Object.keys(auth.headers).length > 0;
|
|
@@ -7966,22 +8530,22 @@ var inboxCommand = new Command42("inbox").description("Show tasks you created an
|
|
|
7966
8530
|
});
|
|
7967
8531
|
|
|
7968
8532
|
// src/commands/deposit.ts
|
|
7969
|
-
import { Command as
|
|
7970
|
-
var depositCommand = new
|
|
8533
|
+
import { Command as Command44 } from "commander";
|
|
8534
|
+
var depositCommand = new Command44("deposit").description("Show wallet address and network info for funding").action(async () => {
|
|
7971
8535
|
let address;
|
|
7972
8536
|
try {
|
|
7973
8537
|
address = await getWalletAddress();
|
|
7974
8538
|
} catch (err) {
|
|
7975
|
-
|
|
7976
|
-
|
|
8539
|
+
renderFailure(err, { fallback: "No keystore found. Run `taskmarket init` first." });
|
|
8540
|
+
return;
|
|
7977
8541
|
}
|
|
7978
8542
|
let networkInfo;
|
|
7979
8543
|
try {
|
|
7980
8544
|
const response = await apiGet("/trpc/network.info");
|
|
7981
8545
|
networkInfo = response.result.data;
|
|
7982
8546
|
} catch (err) {
|
|
7983
|
-
|
|
7984
|
-
|
|
8547
|
+
renderFailure(err, { fallback: "Failed to fetch network info from backend." });
|
|
8548
|
+
return;
|
|
7985
8549
|
}
|
|
7986
8550
|
const data = {
|
|
7987
8551
|
address,
|
|
@@ -7994,11 +8558,11 @@ var depositCommand = new Command43("deposit").description("Show wallet address a
|
|
|
7994
8558
|
});
|
|
7995
8559
|
|
|
7996
8560
|
// src/commands/wallet/index.ts
|
|
7997
|
-
import { Command as
|
|
8561
|
+
import { Command as Command50 } from "commander";
|
|
7998
8562
|
|
|
7999
8563
|
// src/commands/wallet/balance.ts
|
|
8000
|
-
import { Command as
|
|
8001
|
-
var walletBalanceCommand = new
|
|
8564
|
+
import { Command as Command45 } from "commander";
|
|
8565
|
+
var walletBalanceCommand = new Command45("balance").description("Show USDC balance").option("--address <addr>", "Address to check (defaults to own wallet)").action(async (opts) => {
|
|
8002
8566
|
let address = opts.address;
|
|
8003
8567
|
if (!address) {
|
|
8004
8568
|
const keystore = await loadKeystore();
|
|
@@ -8009,7 +8573,7 @@ var walletBalanceCommand = new Command44("balance").description("Show USDC balan
|
|
|
8009
8573
|
});
|
|
8010
8574
|
|
|
8011
8575
|
// src/commands/wallet/import.ts
|
|
8012
|
-
import { Command as
|
|
8576
|
+
import { Command as Command46 } from "commander";
|
|
8013
8577
|
import { createInterface as createInterface2 } from "readline";
|
|
8014
8578
|
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
8015
8579
|
function normalizePrivateKey(raw) {
|
|
@@ -8044,7 +8608,7 @@ function promptHiddenInput(prompt) {
|
|
|
8044
8608
|
});
|
|
8045
8609
|
});
|
|
8046
8610
|
}
|
|
8047
|
-
var walletImportCommand = new
|
|
8611
|
+
var walletImportCommand = new Command46("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(
|
|
8048
8612
|
"--yes",
|
|
8049
8613
|
"Confirm legal acceptance non-interactively after reviewing every current policy"
|
|
8050
8614
|
).action(async (opts) => {
|
|
@@ -8123,69 +8687,77 @@ var walletImportCommand = new Command45("import").description("Import an existin
|
|
|
8123
8687
|
});
|
|
8124
8688
|
|
|
8125
8689
|
// src/commands/wallet/set-withdrawal-address.ts
|
|
8126
|
-
import { Command as
|
|
8690
|
+
import { Command as Command47 } from "commander";
|
|
8127
8691
|
function isValidAddress(addr) {
|
|
8128
8692
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8129
8693
|
}
|
|
8130
|
-
var setWithdrawalAddressCommand = new
|
|
8694
|
+
var setWithdrawalAddressCommand = new Command47("set-withdrawal-address").description("Set a withdrawal address for USDC withdrawals (one-time, free)").argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
|
|
8131
8695
|
if (!isValidAddress(address)) {
|
|
8132
8696
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
8697
|
+
return;
|
|
8133
8698
|
}
|
|
8134
8699
|
let keystore;
|
|
8135
8700
|
try {
|
|
8136
8701
|
keystore = await loadKeystore();
|
|
8137
8702
|
} catch {
|
|
8138
8703
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8704
|
+
return;
|
|
8139
8705
|
}
|
|
8140
8706
|
const walletAddress = keystore.walletAddress;
|
|
8141
8707
|
const message = buildSetWithdrawalAddressMessage(address);
|
|
8142
8708
|
const signature = await signMessage(message, keystore);
|
|
8143
|
-
const result = await apiPost(
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8709
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8710
|
+
"/api/wallet/set-withdrawal-address",
|
|
8711
|
+
{
|
|
8712
|
+
walletAddress,
|
|
8713
|
+
withdrawalAddress: address,
|
|
8714
|
+
signature
|
|
8715
|
+
}
|
|
8716
|
+
);
|
|
8717
|
+
printResult({ withdrawalAddress: result.withdrawalAddress }, { idempotencyKey });
|
|
8149
8718
|
});
|
|
8150
8719
|
|
|
8151
8720
|
// src/commands/wallet/publish-key.ts
|
|
8152
|
-
import { Command as
|
|
8153
|
-
var publishKeyCommand = new
|
|
8721
|
+
import { Command as Command48 } from "commander";
|
|
8722
|
+
var publishKeyCommand = new Command48("publish-key").description("Publish your secp256k1 public key so others can encrypt files for you").action(async () => {
|
|
8154
8723
|
let keystore;
|
|
8155
8724
|
try {
|
|
8156
8725
|
keystore = await loadKeystore();
|
|
8157
8726
|
} catch {
|
|
8158
8727
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8728
|
+
return;
|
|
8159
8729
|
}
|
|
8160
8730
|
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
8161
8731
|
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
8162
8732
|
const publicKey = deriveCompressedPublicKey(privateKey);
|
|
8163
|
-
const result = await apiPost("/trpc/agents.setPublicKey", {
|
|
8733
|
+
const { data: result, idempotencyKey } = await apiPost("/trpc/agents.setPublicKey", {
|
|
8164
8734
|
deviceId: keystore.deviceId,
|
|
8165
8735
|
apiToken: keystore.apiToken,
|
|
8166
8736
|
publicKey
|
|
8167
8737
|
});
|
|
8168
|
-
printResult({ publicKey: result.result.data.publicKey });
|
|
8738
|
+
printResult({ publicKey: result.result.data.publicKey }, { idempotencyKey });
|
|
8169
8739
|
});
|
|
8170
8740
|
|
|
8171
8741
|
// src/commands/wallet/withdraw-dreams.ts
|
|
8172
|
-
import { Command as
|
|
8742
|
+
import { Command as Command49 } from "commander";
|
|
8173
8743
|
import { toHex as toHex2 } from "viem";
|
|
8174
8744
|
var AUTHORIZATION_VALIDITY_SECONDS = 300;
|
|
8175
8745
|
function isValidAddress2(addr) {
|
|
8176
8746
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8177
8747
|
}
|
|
8178
|
-
var withdrawDreamsCommand = new
|
|
8748
|
+
var withdrawDreamsCommand = new Command49("withdraw-dreams").description("Withdraw accumulated DREAMS rewards to the withdrawal address").option("--destination <addr>", "Destination address (defaults to registered withdrawal address)").action(async (opts) => {
|
|
8179
8749
|
let keystore;
|
|
8180
8750
|
try {
|
|
8181
8751
|
keystore = await loadKeystore();
|
|
8182
8752
|
} catch {
|
|
8183
8753
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8754
|
+
return;
|
|
8184
8755
|
}
|
|
8185
8756
|
const workerAddress = keystore.walletAddress;
|
|
8186
8757
|
let destination = opts.destination;
|
|
8187
8758
|
if (destination !== void 0 && !isValidAddress2(destination)) {
|
|
8188
8759
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
8760
|
+
return;
|
|
8189
8761
|
}
|
|
8190
8762
|
if (!destination) {
|
|
8191
8763
|
const addressResponse = await apiGet(
|
|
@@ -8195,6 +8767,7 @@ var withdrawDreamsCommand = new Command48("withdraw-dreams").description("Withdr
|
|
|
8195
8767
|
printError(
|
|
8196
8768
|
"No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
|
|
8197
8769
|
);
|
|
8770
|
+
return;
|
|
8198
8771
|
}
|
|
8199
8772
|
destination = addressResponse.withdrawalAddress;
|
|
8200
8773
|
}
|
|
@@ -8202,25 +8775,31 @@ var withdrawDreamsCommand = new Command48("withdraw-dreams").description("Withdr
|
|
|
8202
8775
|
const validBefore = String(Math.floor(Date.now() / 1e3) + AUTHORIZATION_VALIDITY_SECONDS);
|
|
8203
8776
|
const message = buildWithdrawDreamsMessage(destination, nonce, validBefore);
|
|
8204
8777
|
const signature = await signMessage(message, keystore);
|
|
8205
|
-
const result = await apiPost(
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8778
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8779
|
+
"/api/wallet/withdraw-dreams",
|
|
8780
|
+
{
|
|
8781
|
+
workerAddress,
|
|
8782
|
+
destination,
|
|
8783
|
+
nonce,
|
|
8784
|
+
validBefore,
|
|
8785
|
+
signature
|
|
8786
|
+
}
|
|
8787
|
+
);
|
|
8788
|
+
printResult(
|
|
8789
|
+
{
|
|
8790
|
+
txHash: result.txHash,
|
|
8791
|
+
destination: result.destination,
|
|
8792
|
+
claimedBaseUnits: result.claimedBaseUnits,
|
|
8793
|
+
claimedDreams: formatDreams(result.claimedBaseUnits),
|
|
8794
|
+
dreamsPerUsdc: result.dreamsPerUsdc,
|
|
8795
|
+
usdEquivalent: result.usdEquivalent
|
|
8796
|
+
},
|
|
8797
|
+
{ idempotencyKey }
|
|
8798
|
+
);
|
|
8220
8799
|
});
|
|
8221
8800
|
|
|
8222
8801
|
// src/commands/wallet/index.ts
|
|
8223
|
-
var walletCommand = new
|
|
8802
|
+
var walletCommand = new Command50("wallet").description("Wallet management commands");
|
|
8224
8803
|
walletCommand.addCommand(walletBalanceCommand);
|
|
8225
8804
|
walletCommand.addCommand(walletImportCommand);
|
|
8226
8805
|
walletCommand.addCommand(setWithdrawalAddressCommand);
|
|
@@ -8228,7 +8807,7 @@ walletCommand.addCommand(publishKeyCommand);
|
|
|
8228
8807
|
walletCommand.addCommand(withdrawDreamsCommand);
|
|
8229
8808
|
|
|
8230
8809
|
// src/commands/withdraw.ts
|
|
8231
|
-
import { Command as
|
|
8810
|
+
import { Command as Command51 } from "commander";
|
|
8232
8811
|
import { toHex as toHex3 } from "viem";
|
|
8233
8812
|
var USDC_TYPES = {
|
|
8234
8813
|
TransferWithAuthorization: [
|
|
@@ -8240,10 +8819,11 @@ var USDC_TYPES = {
|
|
|
8240
8819
|
{ name: "nonce", type: "bytes32" }
|
|
8241
8820
|
]
|
|
8242
8821
|
};
|
|
8243
|
-
var withdrawCommand = new
|
|
8822
|
+
var withdrawCommand = new Command51("withdraw").description("Withdraw USDC to the registered withdrawal address").argument("<amount>", "Amount in USDC (e.g. 5 for 5 USDC)").action(async (amount) => {
|
|
8244
8823
|
const parsed = parseFloat(amount);
|
|
8245
8824
|
if (isNaN(parsed) || parsed <= 0) {
|
|
8246
8825
|
printError("Invalid amount: must be a positive number (e.g. 5 for 5 USDC)");
|
|
8826
|
+
return;
|
|
8247
8827
|
}
|
|
8248
8828
|
const amountBaseUnits = String(Math.round(parsed * 1e6));
|
|
8249
8829
|
let keystore;
|
|
@@ -8251,6 +8831,7 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8251
8831
|
keystore = await loadKeystore();
|
|
8252
8832
|
} catch {
|
|
8253
8833
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8834
|
+
return;
|
|
8254
8835
|
}
|
|
8255
8836
|
const from = keystore.walletAddress;
|
|
8256
8837
|
const addressResponse = await apiGet(
|
|
@@ -8260,6 +8841,7 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8260
8841
|
printError(
|
|
8261
8842
|
"No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
|
|
8262
8843
|
);
|
|
8844
|
+
return;
|
|
8263
8845
|
}
|
|
8264
8846
|
const { withdrawalAddress, usdcDomain } = addressResponse;
|
|
8265
8847
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -8280,30 +8862,38 @@ var withdrawCommand = new Command50("withdraw").description("Withdraw USDC to th
|
|
|
8280
8862
|
},
|
|
8281
8863
|
keystore
|
|
8282
8864
|
);
|
|
8283
|
-
const result = await apiPost(
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8865
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
8866
|
+
"/api/wallet/withdraw",
|
|
8867
|
+
{
|
|
8868
|
+
from,
|
|
8869
|
+
amountBaseUnits,
|
|
8870
|
+
authorization,
|
|
8871
|
+
signature
|
|
8872
|
+
}
|
|
8873
|
+
);
|
|
8874
|
+
printResult(
|
|
8875
|
+
{ txHash: result.txHash, amountBaseUnits: result.amountBaseUnits, to: result.to },
|
|
8876
|
+
{ idempotencyKey }
|
|
8877
|
+
);
|
|
8290
8878
|
});
|
|
8291
8879
|
|
|
8292
8880
|
// src/commands/encrypt.ts
|
|
8293
|
-
import { Command as
|
|
8881
|
+
import { Command as Command52 } from "commander";
|
|
8294
8882
|
import { promises as fs3 } from "fs";
|
|
8295
|
-
var encryptCommand = new
|
|
8883
|
+
var encryptCommand = new Command52("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) => {
|
|
8296
8884
|
let plaintext;
|
|
8297
8885
|
try {
|
|
8298
8886
|
plaintext = await fs3.readFile(file);
|
|
8299
8887
|
} catch {
|
|
8300
8888
|
printError(`Cannot read file: ${file}`);
|
|
8889
|
+
return;
|
|
8301
8890
|
}
|
|
8302
8891
|
let keystore;
|
|
8303
8892
|
try {
|
|
8304
8893
|
keystore = await loadKeystore();
|
|
8305
8894
|
} catch {
|
|
8306
8895
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8896
|
+
return;
|
|
8307
8897
|
}
|
|
8308
8898
|
let recipientPubKey;
|
|
8309
8899
|
let recipientAddress;
|
|
@@ -8316,12 +8906,9 @@ var encryptCommand = new Command51("encrypt").description("Encrypt a file with E
|
|
|
8316
8906
|
);
|
|
8317
8907
|
} catch (err) {
|
|
8318
8908
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
);
|
|
8323
|
-
}
|
|
8324
|
-
printError(`Failed to fetch recipient public key: ${msg}`);
|
|
8909
|
+
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";
|
|
8910
|
+
renderFailure(withErrorContext(err, context));
|
|
8911
|
+
return;
|
|
8325
8912
|
}
|
|
8326
8913
|
recipientPubKey = result.result.data.publicKey;
|
|
8327
8914
|
} else {
|
|
@@ -8341,20 +8928,22 @@ var encryptCommand = new Command51("encrypt").description("Encrypt a file with E
|
|
|
8341
8928
|
});
|
|
8342
8929
|
|
|
8343
8930
|
// src/commands/decrypt.ts
|
|
8344
|
-
import { Command as
|
|
8931
|
+
import { Command as Command53 } from "commander";
|
|
8345
8932
|
import { promises as fs4 } from "fs";
|
|
8346
|
-
var decryptCommand = new
|
|
8933
|
+
var decryptCommand = new Command53("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) => {
|
|
8347
8934
|
let ciphertext;
|
|
8348
8935
|
try {
|
|
8349
8936
|
ciphertext = await fs4.readFile(file);
|
|
8350
8937
|
} catch {
|
|
8351
8938
|
printError(`Cannot read file: ${file}`);
|
|
8939
|
+
return;
|
|
8352
8940
|
}
|
|
8353
8941
|
let keystore;
|
|
8354
8942
|
try {
|
|
8355
8943
|
keystore = await loadKeystore();
|
|
8356
8944
|
} catch {
|
|
8357
8945
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
8946
|
+
return;
|
|
8358
8947
|
}
|
|
8359
8948
|
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
8360
8949
|
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
@@ -8362,8 +8951,8 @@ var decryptCommand = new Command52("decrypt").description("Decrypt a file using
|
|
|
8362
8951
|
try {
|
|
8363
8952
|
plaintext = decryptWithPrivateKey(ciphertext, privateKey);
|
|
8364
8953
|
} catch (err) {
|
|
8365
|
-
|
|
8366
|
-
|
|
8954
|
+
renderFailure(err);
|
|
8955
|
+
return;
|
|
8367
8956
|
}
|
|
8368
8957
|
let outputPath;
|
|
8369
8958
|
if (opts.output) {
|
|
@@ -8381,21 +8970,21 @@ var decryptCommand = new Command52("decrypt").description("Decrypt a file using
|
|
|
8381
8970
|
});
|
|
8382
8971
|
|
|
8383
8972
|
// src/commands/xmtp.ts
|
|
8384
|
-
import { Command as
|
|
8973
|
+
import { Command as Command54 } from "commander";
|
|
8385
8974
|
|
|
8386
8975
|
// src/lib/xmtp-client.ts
|
|
8387
8976
|
import os3 from "os";
|
|
8388
8977
|
import path3 from "path";
|
|
8389
|
-
import { randomUUID as
|
|
8978
|
+
import { randomUUID as randomUUID3, hkdfSync as hkdfSync2 } from "crypto";
|
|
8390
8979
|
import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
|
|
8391
8980
|
|
|
8392
8981
|
// src/lib/xmtp-envelope.ts
|
|
8393
|
-
import { randomUUID } from "crypto";
|
|
8982
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
8394
8983
|
function buildEnvelope(input) {
|
|
8395
8984
|
return AgentMessageEnvelopeSchema.parse({
|
|
8396
8985
|
schemaVersion: 1,
|
|
8397
8986
|
type: input.type,
|
|
8398
|
-
requestId: input.requestId ??
|
|
8987
|
+
requestId: input.requestId ?? randomUUID2(),
|
|
8399
8988
|
replyToRequestId: input.replyToRequestId,
|
|
8400
8989
|
senderInboxId: input.senderInboxId,
|
|
8401
8990
|
senderAddress: input.senderAddress,
|
|
@@ -8548,7 +9137,7 @@ function defaultDbPath(walletAddress) {
|
|
|
8548
9137
|
}
|
|
8549
9138
|
async function createDevClient(input) {
|
|
8550
9139
|
const inboxId = input.existingInboxId ?? `dev-inbox-${input.walletAddress.slice(2, 10).toLowerCase()}`;
|
|
8551
|
-
const installationId = input.existingInstallationId ??
|
|
9140
|
+
const installationId = input.existingInstallationId ?? randomUUID3();
|
|
8552
9141
|
const dbPath = input.existingDbPath ?? defaultDbPath(input.walletAddress);
|
|
8553
9142
|
return {
|
|
8554
9143
|
inboxId,
|
|
@@ -8977,7 +9566,7 @@ async function createProductionClient(input) {
|
|
|
8977
9566
|
"non-retryable"
|
|
8978
9567
|
);
|
|
8979
9568
|
}
|
|
8980
|
-
const installationId = extractString(client, ["installationId", "installationID"]) ?? extractString(asObject(client)?.installation, ["id", "installationId"]) ?? input.existingInstallationId ??
|
|
9569
|
+
const installationId = extractString(client, ["installationId", "installationID"]) ?? extractString(asObject(client)?.installation, ["id", "installationId"]) ?? input.existingInstallationId ?? randomUUID3();
|
|
8981
9570
|
return {
|
|
8982
9571
|
inboxId,
|
|
8983
9572
|
installationId,
|
|
@@ -9145,7 +9734,7 @@ function getDefaultQueryTimeoutMs() {
|
|
|
9145
9734
|
}
|
|
9146
9735
|
return Math.floor(parsed);
|
|
9147
9736
|
}
|
|
9148
|
-
var xmtpCommand = new
|
|
9737
|
+
var xmtpCommand = new Command54("xmtp").description("Manage XMTP messaging for this agent");
|
|
9149
9738
|
xmtpCommand.command("init").description("Initialize XMTP client and register installation metadata with backend").action(async () => {
|
|
9150
9739
|
const keystore = await loadKeystore();
|
|
9151
9740
|
const client = await createXmtpClient({
|
|
@@ -9155,7 +9744,7 @@ xmtpCommand.command("init").description("Initialize XMTP client and register ins
|
|
|
9155
9744
|
existingDbPath: keystore.xmtpDbPath,
|
|
9156
9745
|
keystore
|
|
9157
9746
|
});
|
|
9158
|
-
const status = await apiPost("/api/xmtp/bootstrap", {
|
|
9747
|
+
const { data: status, idempotencyKey } = await apiPost("/api/xmtp/bootstrap", {
|
|
9159
9748
|
deviceId: keystore.deviceId,
|
|
9160
9749
|
apiToken: keystore.apiToken,
|
|
9161
9750
|
inboxId: client.inboxId,
|
|
@@ -9169,7 +9758,7 @@ xmtpCommand.command("init").description("Initialize XMTP client and register ins
|
|
|
9169
9758
|
xmtpInstallationId: status.installationId,
|
|
9170
9759
|
xmtpDbPath: client.dbPath
|
|
9171
9760
|
});
|
|
9172
|
-
printResult({ policyMode: status.policyMode });
|
|
9761
|
+
printResult({ policyMode: status.policyMode }, { idempotencyKey });
|
|
9173
9762
|
});
|
|
9174
9763
|
xmtpCommand.command("status").description("Check XMTP status and active installation state").action(async () => {
|
|
9175
9764
|
const keystore = await loadKeystore();
|
|
@@ -9282,12 +9871,15 @@ xmtpCommand.command("heartbeat").description("Send a one-shot heartbeat to keep
|
|
|
9282
9871
|
if (!keystore.xmtpInstallationId) {
|
|
9283
9872
|
throw new Error("XMTP not initialized. Run `taskmarket xmtp init` first.");
|
|
9284
9873
|
}
|
|
9285
|
-
const result = await apiPost(
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9874
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
9875
|
+
"/api/xmtp/heartbeat",
|
|
9876
|
+
{
|
|
9877
|
+
deviceId: keystore.deviceId,
|
|
9878
|
+
apiToken: keystore.apiToken,
|
|
9879
|
+
installationId: keystore.xmtpInstallationId
|
|
9880
|
+
}
|
|
9881
|
+
);
|
|
9882
|
+
printResult(result, { idempotencyKey });
|
|
9291
9883
|
});
|
|
9292
9884
|
var peersCommand = xmtpCommand.command("peers").description("Manage taskmarket peer messaging policies");
|
|
9293
9885
|
peersCommand.command("list").description("List per-peer messaging policies stored on the backend").action(async () => {
|
|
@@ -9305,14 +9897,17 @@ peersCommand.command("set").description("Set messaging policy for a specific pee
|
|
|
9305
9897
|
}
|
|
9306
9898
|
const keystore = await loadKeystore();
|
|
9307
9899
|
const peerInboxId = await resolveInboxId(options.to);
|
|
9308
|
-
const result = await apiPost(
|
|
9309
|
-
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9900
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
9901
|
+
"/api/xmtp/peers",
|
|
9902
|
+
{
|
|
9903
|
+
deviceId: keystore.deviceId,
|
|
9904
|
+
apiToken: keystore.apiToken,
|
|
9905
|
+
peerInboxId,
|
|
9906
|
+
policy: options.policy,
|
|
9907
|
+
reason: options.reason
|
|
9908
|
+
}
|
|
9909
|
+
);
|
|
9910
|
+
printResult(result, { idempotencyKey });
|
|
9316
9911
|
});
|
|
9317
9912
|
var allowlistCommand = xmtpCommand.command("allowlist").description("Manage XMTP SDK consent allowlist (protocol-level)");
|
|
9318
9913
|
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) => {
|
|
@@ -9365,15 +9960,18 @@ allowlistCommand.command("check").description("Check the XMTP SDK consent state
|
|
|
9365
9960
|
});
|
|
9366
9961
|
xmtpCommand.command("purge").description("Revoke stale XMTP installations that have missed heartbeats").action(async () => {
|
|
9367
9962
|
const keystore = await loadKeystore();
|
|
9368
|
-
const result = await apiPost(
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9963
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
9964
|
+
"/api/xmtp/purge",
|
|
9965
|
+
{
|
|
9966
|
+
deviceId: keystore.deviceId,
|
|
9967
|
+
apiToken: keystore.apiToken
|
|
9968
|
+
}
|
|
9969
|
+
);
|
|
9970
|
+
printResult(result, { idempotencyKey });
|
|
9373
9971
|
});
|
|
9374
9972
|
|
|
9375
9973
|
// src/commands/daemon.ts
|
|
9376
|
-
import { Command as
|
|
9974
|
+
import { Command as Command55 } from "commander";
|
|
9377
9975
|
function diffTaskStatuses(prev, next) {
|
|
9378
9976
|
const changes = [];
|
|
9379
9977
|
for (const [taskId, newStatus] of next) {
|
|
@@ -9401,7 +9999,7 @@ function sleepOrAbort(ms, signal) {
|
|
|
9401
9999
|
});
|
|
9402
10000
|
}
|
|
9403
10001
|
var MAX_SEEN_TASK_IDS = 2e3;
|
|
9404
|
-
var daemonCommand = new
|
|
10002
|
+
var daemonCommand = new Command55("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(
|
|
9405
10003
|
"--auction-poll-interval <ms>",
|
|
9406
10004
|
"Poll interval for clock-based auction tasks (dutch/reverse_dutch) in milliseconds",
|
|
9407
10005
|
"15000"
|
|
@@ -9485,12 +10083,15 @@ var daemonCommand = new Command54("daemon").description("Long-running agent daem
|
|
|
9485
10083
|
await sleepOrAbort(heartbeatIntervalMs, abortController.signal);
|
|
9486
10084
|
if (stopped) break;
|
|
9487
10085
|
try {
|
|
9488
|
-
await apiPost("/trpc/xmtp.heartbeat", {
|
|
10086
|
+
const { idempotencyKey } = await apiPost("/trpc/xmtp.heartbeat", {
|
|
9489
10087
|
deviceId: keystore.deviceId,
|
|
9490
10088
|
apiToken: keystore.apiToken,
|
|
9491
10089
|
installationId: client.installationId
|
|
9492
10090
|
});
|
|
9493
|
-
printResult(
|
|
10091
|
+
printResult(
|
|
10092
|
+
{ event: "xmtp.heartbeat", installationId: client.installationId },
|
|
10093
|
+
{ idempotencyKey }
|
|
10094
|
+
);
|
|
9494
10095
|
} catch (err) {
|
|
9495
10096
|
process.stderr.write(
|
|
9496
10097
|
`Heartbeat failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -9722,29 +10323,33 @@ var daemonCommand = new Command54("daemon").description("Long-running agent daem
|
|
|
9722
10323
|
);
|
|
9723
10324
|
|
|
9724
10325
|
// src/commands/email/index.ts
|
|
9725
|
-
import { Command as
|
|
10326
|
+
import { Command as Command64 } from "commander";
|
|
9726
10327
|
|
|
9727
10328
|
// src/commands/email/register.ts
|
|
9728
|
-
import { Command as
|
|
9729
|
-
var registerCommand = new
|
|
10329
|
+
import { Command as Command56 } from "commander";
|
|
10330
|
+
var registerCommand = new Command56("register").description("Register an email address for this agent").requiredOption("--username <name>", "Desired username (e.g. myagent)").action(async (opts) => {
|
|
9730
10331
|
const check = await apiGet(
|
|
9731
10332
|
`/api/emails/check-username?username=${encodeURIComponent(opts.username)}`
|
|
9732
10333
|
);
|
|
9733
10334
|
if (!check.available) {
|
|
9734
10335
|
printError(`Username "${opts.username}" is not available.`);
|
|
10336
|
+
return;
|
|
9735
10337
|
}
|
|
9736
10338
|
const keystore = await loadKeystore();
|
|
9737
|
-
const result = await apiPost(
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
10339
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10340
|
+
"/api/emails/register",
|
|
10341
|
+
{
|
|
10342
|
+
deviceId: keystore.deviceId,
|
|
10343
|
+
apiToken: keystore.apiToken,
|
|
10344
|
+
username: opts.username
|
|
10345
|
+
}
|
|
10346
|
+
);
|
|
10347
|
+
printResult({ emailAddress: result.emailAddress }, { idempotencyKey });
|
|
9743
10348
|
});
|
|
9744
10349
|
|
|
9745
10350
|
// src/commands/email/inbox.ts
|
|
9746
|
-
import { Command as
|
|
9747
|
-
var inboxCommand2 = new
|
|
10351
|
+
import { Command as Command57 } from "commander";
|
|
10352
|
+
var inboxCommand2 = new Command57("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) => {
|
|
9748
10353
|
const keystore = await loadKeystore();
|
|
9749
10354
|
const params = new URLSearchParams({
|
|
9750
10355
|
deviceId: keystore.deviceId,
|
|
@@ -9759,8 +10364,8 @@ var inboxCommand2 = new Command56("inbox").description("List emails in your inbo
|
|
|
9759
10364
|
});
|
|
9760
10365
|
|
|
9761
10366
|
// src/commands/email/read.ts
|
|
9762
|
-
import { Command as
|
|
9763
|
-
var readCommand = new
|
|
10367
|
+
import { Command as Command58 } from "commander";
|
|
10368
|
+
var readCommand = new Command58("read").description("Read an email by ID (marks it as read)").argument("<id>", "Email ID").action(async (id) => {
|
|
9764
10369
|
const keystore = await loadKeystore();
|
|
9765
10370
|
const params = new URLSearchParams({
|
|
9766
10371
|
deviceId: keystore.deviceId,
|
|
@@ -9772,22 +10377,22 @@ var readCommand = new Command57("read").description("Read an email by ID (marks
|
|
|
9772
10377
|
});
|
|
9773
10378
|
|
|
9774
10379
|
// src/commands/email/send.ts
|
|
9775
|
-
import { Command as
|
|
9776
|
-
var sendCommand = new
|
|
10380
|
+
import { Command as Command59 } from "commander";
|
|
10381
|
+
var sendCommand = new Command59("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) => {
|
|
9777
10382
|
const keystore = await loadKeystore();
|
|
9778
|
-
const result = await apiPost("/api/emails/send", {
|
|
10383
|
+
const { data: result, idempotencyKey } = await apiPost("/api/emails/send", {
|
|
9779
10384
|
deviceId: keystore.deviceId,
|
|
9780
10385
|
apiToken: keystore.apiToken,
|
|
9781
10386
|
to: opts.to,
|
|
9782
10387
|
subject: opts.subject,
|
|
9783
10388
|
bodyText: opts.body
|
|
9784
10389
|
});
|
|
9785
|
-
printResult({ sent: result.sent });
|
|
10390
|
+
printResult({ sent: result.sent }, { idempotencyKey });
|
|
9786
10391
|
});
|
|
9787
10392
|
|
|
9788
10393
|
// src/commands/email/reply.ts
|
|
9789
|
-
import { Command as
|
|
9790
|
-
var replyCommand = new
|
|
10394
|
+
import { Command as Command60 } from "commander";
|
|
10395
|
+
var replyCommand = new Command60("reply").description("Reply to an email").argument("<id>", "Email ID to reply to").requiredOption("--body <text>", "Reply body text").action(async (id, opts) => {
|
|
9791
10396
|
const keystore = await loadKeystore();
|
|
9792
10397
|
const params = new URLSearchParams({
|
|
9793
10398
|
deviceId: keystore.deviceId,
|
|
@@ -9798,54 +10403,60 @@ var replyCommand = new Command59("reply").description("Reply to an email").argum
|
|
|
9798
10403
|
const to = original.fromAddress;
|
|
9799
10404
|
const rawSubject = original.subject ?? "";
|
|
9800
10405
|
const subject = rawSubject.startsWith("Re: ") ? rawSubject : `Re: ${rawSubject}`;
|
|
9801
|
-
const result = await apiPost("/api/emails/send", {
|
|
10406
|
+
const { data: result, idempotencyKey } = await apiPost("/api/emails/send", {
|
|
9802
10407
|
deviceId: keystore.deviceId,
|
|
9803
10408
|
apiToken: keystore.apiToken,
|
|
9804
10409
|
to,
|
|
9805
10410
|
subject,
|
|
9806
10411
|
bodyText: opts.body
|
|
9807
10412
|
});
|
|
9808
|
-
printResult({ sent: result.sent });
|
|
10413
|
+
printResult({ sent: result.sent }, { idempotencyKey });
|
|
9809
10414
|
});
|
|
9810
10415
|
|
|
9811
10416
|
// src/commands/email/delete.ts
|
|
9812
|
-
import { Command as
|
|
9813
|
-
var deleteCommand = new
|
|
10417
|
+
import { Command as Command61 } from "commander";
|
|
10418
|
+
var deleteCommand = new Command61("delete").description("Delete an email by ID").argument("<id>", "Email ID").action(async (id) => {
|
|
9814
10419
|
const keystore = await loadKeystore();
|
|
9815
|
-
const result = await apiPost(
|
|
9816
|
-
|
|
9817
|
-
|
|
9818
|
-
|
|
9819
|
-
|
|
9820
|
-
|
|
10420
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10421
|
+
"/api/emails/delete",
|
|
10422
|
+
{
|
|
10423
|
+
deviceId: keystore.deviceId,
|
|
10424
|
+
apiToken: keystore.apiToken,
|
|
10425
|
+
id
|
|
10426
|
+
}
|
|
10427
|
+
);
|
|
10428
|
+
printResult({ deleted: result.deleted }, { idempotencyKey });
|
|
9821
10429
|
});
|
|
9822
10430
|
|
|
9823
10431
|
// src/commands/email/address.ts
|
|
9824
|
-
import { Command as
|
|
9825
|
-
var addressCommand2 = new
|
|
10432
|
+
import { Command as Command62 } from "commander";
|
|
10433
|
+
var addressCommand2 = new Command62("address").description("Show your registered email address").action(async () => {
|
|
9826
10434
|
const keystore = await loadKeystore();
|
|
9827
10435
|
const result = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
9828
10436
|
printResult({ emailAddress: result.emailAddress ?? null });
|
|
9829
10437
|
});
|
|
9830
10438
|
|
|
9831
10439
|
// src/commands/email/mark-read.ts
|
|
9832
|
-
import { Command as
|
|
10440
|
+
import { Command as Command63 } from "commander";
|
|
9833
10441
|
async function setReadStatus(id, read) {
|
|
9834
10442
|
const keystore = await loadKeystore();
|
|
9835
|
-
const result = await apiPost(
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
10443
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
10444
|
+
"/api/emails/mark-read",
|
|
10445
|
+
{
|
|
10446
|
+
deviceId: keystore.deviceId,
|
|
10447
|
+
apiToken: keystore.apiToken,
|
|
10448
|
+
id,
|
|
10449
|
+
read
|
|
10450
|
+
}
|
|
10451
|
+
);
|
|
10452
|
+
printResult({ id: result.id, isRead: result.isRead }, { idempotencyKey });
|
|
9842
10453
|
}
|
|
9843
|
-
var markReadCommand = new
|
|
10454
|
+
var markReadCommand = new Command63("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) => {
|
|
9844
10455
|
await setReadStatus(id, !opts.unread);
|
|
9845
10456
|
});
|
|
9846
10457
|
|
|
9847
10458
|
// src/commands/email/index.ts
|
|
9848
|
-
var emailCommand = new
|
|
10459
|
+
var emailCommand = new Command64("email").description("Email management commands");
|
|
9849
10460
|
emailCommand.addCommand(registerCommand);
|
|
9850
10461
|
emailCommand.addCommand(inboxCommand2);
|
|
9851
10462
|
emailCommand.addCommand(readCommand);
|
|
@@ -9856,32 +10467,30 @@ emailCommand.addCommand(addressCommand2);
|
|
|
9856
10467
|
emailCommand.addCommand(markReadCommand);
|
|
9857
10468
|
|
|
9858
10469
|
// src/commands/requester/index.ts
|
|
9859
|
-
import { Command as
|
|
10470
|
+
import { Command as Command66 } from "commander";
|
|
9860
10471
|
|
|
9861
10472
|
// src/commands/requester/stats.ts
|
|
9862
|
-
import { Command as
|
|
9863
|
-
var requesterStatsCmd = new
|
|
10473
|
+
import { Command as Command65 } from "commander";
|
|
10474
|
+
var requesterStatsCmd = new Command65("stats").description("Get requester reputation stats for an address").argument("<address>", "Wallet address of the requester").action(async (address) => {
|
|
9864
10475
|
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
9865
10476
|
printError("Address must be a 0x-prefixed 20-byte hex string");
|
|
9866
|
-
process.exit(1);
|
|
9867
10477
|
return;
|
|
9868
10478
|
}
|
|
9869
10479
|
const data = await apiGet(`/api/requester/${address}/stats`);
|
|
9870
10480
|
if (!data) {
|
|
9871
10481
|
printError("No stats found for address");
|
|
9872
|
-
process.exit(1);
|
|
9873
10482
|
return;
|
|
9874
10483
|
}
|
|
9875
10484
|
printResult(data);
|
|
9876
10485
|
});
|
|
9877
10486
|
|
|
9878
10487
|
// src/commands/requester/index.ts
|
|
9879
|
-
var requesterCmd = new
|
|
10488
|
+
var requesterCmd = new Command66("requester").description("Requester reputation commands").addCommand(requesterStatsCmd);
|
|
9880
10489
|
|
|
9881
10490
|
// src/index.ts
|
|
9882
10491
|
var require2 = createRequire(import.meta.url);
|
|
9883
10492
|
var { version } = require2("../package.json");
|
|
9884
|
-
var program = new
|
|
10493
|
+
var program = new Command67();
|
|
9885
10494
|
program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
|
|
9886
10495
|
program.addCommand(initCommand);
|
|
9887
10496
|
program.addCommand(walletCommand);
|
|
@@ -9900,7 +10509,10 @@ program.addCommand(daemonCommand);
|
|
|
9900
10509
|
program.addCommand(emailCommand);
|
|
9901
10510
|
program.addCommand(requesterCmd);
|
|
9902
10511
|
program.addCommand(legalCommand);
|
|
9903
|
-
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
})
|
|
10512
|
+
void (async () => {
|
|
10513
|
+
try {
|
|
10514
|
+
await program.parseAsync(process.argv);
|
|
10515
|
+
} catch (err) {
|
|
10516
|
+
renderFailure(err);
|
|
10517
|
+
}
|
|
10518
|
+
})();
|