@lucid-agents/taskmarket 1.17.2 → 1.18.1
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/THIRD_PARTY_NOTICES.md +54 -27
- package/dist/agent-compatibility.json +1 -1
- package/dist/{budget-view-XKZC3GY5.js → budget-view-JPZ7HWR2.js} +1 -1
- package/dist/{channels-JF4Q5KG3.js → channels-KCDZ5REF.js} +4 -3
- package/dist/chunk-3FF6JAMK.js +868 -0
- package/dist/{chunk-52Q2DCZN.js → chunk-3LNZ766H.js} +23 -23
- package/dist/chunk-5VMWXDNO.js +7518 -0
- package/dist/{chunk-73RXOYME.js → chunk-EB6OJBF5.js} +5 -0
- package/dist/chunk-HEGWADBV.js +447 -0
- package/dist/{chunk-GJQUALXN.js → chunk-LEVAZYR5.js} +106 -29
- package/dist/{launch-2U3KFTFD.js → chunk-ONYTKAHC.js} +4977 -2385
- package/dist/chunk-RHUDL5WA.js +351 -0
- package/dist/chunk-RQTJZYFV.js +831 -0
- package/dist/chunk-YB2B5DPR.js +10320 -0
- package/dist/chunk-ZIC2YCLV.js +65 -0
- package/dist/{doctor-7TWLIJWW.js → doctor-TB3KKAZB.js} +13 -10
- package/dist/index.js +2065 -712
- package/dist/launch-ZV6OLBFM.js +6364 -0
- package/dist/pi-extensions/remote-tools.cjs +74 -3
- package/dist/pi-extensions/xgate.cjs +1039 -25
- package/dist/{status-5IMULBQQ.js → prompter-LSICEYSQ.js} +3 -12
- package/dist/reconcile-UXL65RRT.js +194 -0
- package/dist/status-FHZ3UGEB.js +28 -0
- package/dist/sync-pull-YECZ4PJA.js +409 -0
- package/package.json +1 -1
- package/dist/chunk-FRV3ZHUR.js +0 -16141
- package/dist/chunk-LDCFKFF6.js +0 -154
- package/dist/chunk-XXD7TWLP.js +0 -181
- package/dist/reconcile-XZR2UYSW.js +0 -83
package/dist/index.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename);
|
|
3
|
+
import {
|
|
4
|
+
TaskOperationError,
|
|
5
|
+
claimTask,
|
|
6
|
+
cliTaskReadContext,
|
|
7
|
+
cliTaskWriteContext,
|
|
8
|
+
getTask,
|
|
9
|
+
getTaskTerms,
|
|
10
|
+
listTaskSubmissions,
|
|
11
|
+
listTasks,
|
|
12
|
+
listWorkerSubmissions,
|
|
13
|
+
saveTaskAccessGrant,
|
|
14
|
+
signReadAuth,
|
|
15
|
+
submitTaskFiles,
|
|
16
|
+
taskAccessGrantHeaders
|
|
17
|
+
} from "./chunk-HEGWADBV.js";
|
|
3
18
|
import {
|
|
4
19
|
ComputeCreditError,
|
|
5
20
|
applyComputeCreditSetup,
|
|
@@ -20,101 +35,199 @@ import {
|
|
|
20
35
|
reconcileX402PaymentById,
|
|
21
36
|
refusedPaidWrite,
|
|
22
37
|
releasePendingComputePurchase,
|
|
23
|
-
resolvePendingComputePurchases
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
resolvePendingComputePurchases
|
|
39
|
+
} from "./chunk-3LNZ766H.js";
|
|
40
|
+
import {
|
|
41
|
+
MPP_TEMPO_DEFAULT_VALIDITY_SECONDS,
|
|
42
|
+
X402PayError,
|
|
43
|
+
X402_POLICY_JSON_SCHEMA,
|
|
44
|
+
addX402PolicyRule,
|
|
45
|
+
createWalletAccountFromKeystore,
|
|
46
|
+
fetchDeviceKey,
|
|
47
|
+
getWalletAddress,
|
|
48
|
+
getX402JournalPath,
|
|
49
|
+
getX402Payment,
|
|
50
|
+
getX402PolicyPath,
|
|
51
|
+
initializeX402Policy,
|
|
52
|
+
listX402Payments,
|
|
53
|
+
loadX402Policy,
|
|
54
|
+
removeX402PolicyRule,
|
|
55
|
+
resolveX402PaymentManually,
|
|
56
|
+
setX402PolicyRuleEnabled,
|
|
57
|
+
signMessage,
|
|
58
|
+
signSponsoredTempoTransfer,
|
|
59
|
+
signTaskmarketFeePayment,
|
|
60
|
+
signTypedData
|
|
61
|
+
} from "./chunk-5VMWXDNO.js";
|
|
26
62
|
import {
|
|
27
63
|
AgentMessageEnvelopeSchema,
|
|
28
64
|
ApiError,
|
|
65
|
+
BUG_REPORT_SEVERITIES,
|
|
66
|
+
BUG_REPORT_STATUSES,
|
|
67
|
+
DEFAULT_TERMS_BOUNDS,
|
|
68
|
+
IntentStatusResponseSchema,
|
|
29
69
|
LegalAcceptanceResponseSchema,
|
|
30
70
|
LegalBundleSchema,
|
|
31
71
|
LegalChallengeResponseSchema,
|
|
32
72
|
LegalStatusResponseSchema,
|
|
33
|
-
MPP_TEMPO_DEFAULT_VALIDITY_SECONDS,
|
|
34
73
|
NETWORK_NAMES,
|
|
74
|
+
PenaltyTo,
|
|
35
75
|
READ_AUTH_ADDRESS_HEADER,
|
|
36
76
|
READ_AUTH_SIGNATURE_HEADER,
|
|
77
|
+
REDACTED,
|
|
78
|
+
RejectOutcome,
|
|
37
79
|
SponsoredTaskRewardStateSchema,
|
|
38
80
|
SponsoredTaskWorkerRewardClaimStatusSchema,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
81
|
+
SubmissionReviewAssessmentInputSchema,
|
|
82
|
+
SubmissionReviewAssessmentOutputSchema,
|
|
83
|
+
SubmissionReviewCorrectionSchema,
|
|
84
|
+
SubmissionReviewHistoryInputSchema,
|
|
85
|
+
SubmissionReviewHistoryOutputSchema,
|
|
86
|
+
SubmissionReviewJobStatusSchema,
|
|
87
|
+
SubmissionReviewLookupInputSchema,
|
|
88
|
+
SubmissionReviewPreviewInputSchema,
|
|
89
|
+
SubmissionReviewPreviewOutputSchema,
|
|
90
|
+
SubmissionReviewProfileOutputSchema,
|
|
91
|
+
SubmissionReviewResultStateSchema,
|
|
92
|
+
SubmissionReviewResultsInputSchema,
|
|
93
|
+
SubmissionReviewResultsOutputSchema,
|
|
94
|
+
SubmissionReviewRunInputSchema,
|
|
95
|
+
SubmissionReviewRunSummarySchema,
|
|
96
|
+
SubmissionReviewStartPayloadSchema,
|
|
97
|
+
SubmissionReviewTaskInputSchema,
|
|
98
|
+
SubmitBugReportInputSchema,
|
|
99
|
+
TaskTermsError,
|
|
100
|
+
TermsPresetName,
|
|
101
|
+
WALLET_BRIDGE_ORIGIN_CHAIN_ID,
|
|
102
|
+
WALLET_BRIDGE_TEMPO_CHAIN_ID,
|
|
43
103
|
apiDelete,
|
|
104
|
+
apiErrorEnvelopeOf,
|
|
44
105
|
apiGet,
|
|
45
106
|
apiOrigin,
|
|
46
107
|
apiPost,
|
|
108
|
+
apiReadPost,
|
|
47
109
|
apiUrl,
|
|
48
|
-
buildClaimMessage,
|
|
49
110
|
buildDeviceRegisterMessage,
|
|
50
111
|
buildForfeitMessage,
|
|
51
112
|
buildLegalReceiptHeaders,
|
|
113
|
+
buildPitchMessage,
|
|
114
|
+
buildProofMessage,
|
|
52
115
|
buildReadAuthMessage,
|
|
53
116
|
buildRevealAccountRecoveryCodeMessage,
|
|
54
117
|
buildSelectWorkerMessage,
|
|
55
118
|
buildSetWithdrawalAddressMessage,
|
|
119
|
+
buildSettlementActionMessage,
|
|
56
120
|
buildSponsoredTaskVaultReviewRequestMessage,
|
|
57
|
-
|
|
121
|
+
buildSubmissionReviewActionMessage,
|
|
58
122
|
buildWalletLegalAcceptanceMessage,
|
|
59
123
|
buildWithdrawDreamsMessage,
|
|
60
124
|
chainInfoFor,
|
|
125
|
+
claimStakeToPost,
|
|
61
126
|
clientValidityWindowSeconds,
|
|
62
|
-
createWalletAccountFromKeystore,
|
|
63
127
|
decryptPrivateKey,
|
|
64
128
|
dreamsToUsd,
|
|
65
129
|
encryptPrivateKey,
|
|
66
|
-
fetchDeviceKey,
|
|
67
130
|
formatDreams,
|
|
131
|
+
formatPaymentAmount,
|
|
68
132
|
formatUsdcBaseUnits,
|
|
69
133
|
generateKeypair,
|
|
70
134
|
getTaskmarketHome,
|
|
71
|
-
getWalletAddress,
|
|
72
|
-
getX402JournalPath,
|
|
73
|
-
getX402Payment,
|
|
74
|
-
getX402PolicyPath,
|
|
75
135
|
idempotencyKeyForError,
|
|
76
|
-
initializeX402Policy,
|
|
77
136
|
isInFlightApiError,
|
|
78
137
|
isPendingApiError,
|
|
138
|
+
isRecordingPendingResponse,
|
|
139
|
+
isTerminalWalletBridgeStatus,
|
|
79
140
|
keystoreExists,
|
|
80
|
-
listX402Payments,
|
|
81
141
|
loadKeystore,
|
|
82
|
-
loadX402Policy,
|
|
83
142
|
networkToStamp,
|
|
84
143
|
paymentProtocolOf,
|
|
85
144
|
paymentTokenSymbol,
|
|
86
145
|
readFailureBody,
|
|
87
146
|
readKeystoreNetwork,
|
|
88
|
-
|
|
147
|
+
redactSecrets,
|
|
89
148
|
resolveIdempotencyKey,
|
|
90
149
|
resolveNetwork,
|
|
91
|
-
|
|
150
|
+
resolveTaskTerms,
|
|
92
151
|
saveKeystore,
|
|
93
152
|
selectedNetwork,
|
|
94
153
|
setSelectedNetwork,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
signSponsoredTempoTransfer,
|
|
98
|
-
signTaskmarketFeePayment,
|
|
99
|
-
signTypedData,
|
|
154
|
+
settlementActionExpiresAt,
|
|
155
|
+
settlementActionRequiresExpiry,
|
|
100
156
|
taskmarketChain,
|
|
101
157
|
usdcToBaseUnits,
|
|
102
158
|
withErrorContext,
|
|
103
159
|
withIdempotentWrite
|
|
104
|
-
} from "./chunk-
|
|
160
|
+
} from "./chunk-YB2B5DPR.js";
|
|
105
161
|
import {
|
|
106
162
|
channelLines
|
|
107
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-EB6OJBF5.js";
|
|
108
164
|
import "./chunk-S7SJMJ2I.js";
|
|
109
165
|
|
|
110
166
|
// src/index.ts
|
|
111
|
-
import { Command as
|
|
167
|
+
import { Command as Command103 } from "commander";
|
|
112
168
|
import { createRequire } from "module";
|
|
113
169
|
|
|
114
170
|
// src/commands/init.ts
|
|
115
171
|
import { Command as Command2 } from "commander";
|
|
116
172
|
import { privateKeyToAccount } from "viem/accounts";
|
|
117
173
|
|
|
174
|
+
// src/lib/last-error.ts
|
|
175
|
+
import fs from "fs";
|
|
176
|
+
import path from "path";
|
|
177
|
+
var REPORT_BUG_HINT = "taskmarket bug submit --include-last-error";
|
|
178
|
+
var SECRET_FLAG = /^--?(?:[\w-]*(?:key|secret|token|password|passphrase|mnemonic|seed)[\w-]*)$/i;
|
|
179
|
+
var cliVersion = "unknown";
|
|
180
|
+
function setLastErrorCliVersion(version2) {
|
|
181
|
+
cliVersion = version2;
|
|
182
|
+
}
|
|
183
|
+
function lastErrorPath() {
|
|
184
|
+
return path.join(getTaskmarketHome(), "last-error.json");
|
|
185
|
+
}
|
|
186
|
+
function redactArgv(argv) {
|
|
187
|
+
const out = [];
|
|
188
|
+
for (let i = 0; i < argv.length; i++) {
|
|
189
|
+
const arg = argv[i];
|
|
190
|
+
const eq = arg.indexOf("=");
|
|
191
|
+
if (arg.startsWith("-") && eq > 0 && SECRET_FLAG.test(arg.slice(0, eq))) {
|
|
192
|
+
out.push(`${arg.slice(0, eq)}=${REDACTED}`);
|
|
193
|
+
} else if (SECRET_FLAG.test(arg) && i + 1 < argv.length) {
|
|
194
|
+
out.push(arg, REDACTED);
|
|
195
|
+
i++;
|
|
196
|
+
} else {
|
|
197
|
+
out.push(redactSecrets(arg));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
function currentArgs() {
|
|
203
|
+
return process.argv.slice(2);
|
|
204
|
+
}
|
|
205
|
+
function recordLastError(error, argv = currentArgs()) {
|
|
206
|
+
if (argv[0] === "bug") return false;
|
|
207
|
+
const record = {
|
|
208
|
+
command: ["taskmarket", ...redactArgv(argv)].join(" "),
|
|
209
|
+
message: redactSecrets(error.message),
|
|
210
|
+
...typeof error.code === "string" ? { code: error.code } : {},
|
|
211
|
+
...error.status !== void 0 ? { status: error.status } : {},
|
|
212
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
213
|
+
cliVersion
|
|
214
|
+
};
|
|
215
|
+
try {
|
|
216
|
+
fs.mkdirSync(getTaskmarketHome(), { recursive: true, mode: 448 });
|
|
217
|
+
fs.writeFileSync(lastErrorPath(), JSON.stringify(record, null, 2) + "\n", { mode: 384 });
|
|
218
|
+
return true;
|
|
219
|
+
} catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function readLastError() {
|
|
224
|
+
try {
|
|
225
|
+
return JSON.parse(fs.readFileSync(lastErrorPath(), "utf8"));
|
|
226
|
+
} catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
118
231
|
// src/lib/output.ts
|
|
119
232
|
function printResult(data, options) {
|
|
120
233
|
const idempotencyKey = options?.idempotencyKey;
|
|
@@ -142,6 +255,13 @@ function renderFailure(error, options) {
|
|
|
142
255
|
const x402PayError = error instanceof X402PayError ? error : void 0;
|
|
143
256
|
const idempotencyKey = options?.idempotencyKey ?? apiError?.idempotencyKey ?? idempotencyKeyForError(error);
|
|
144
257
|
const envelope = apiError?.envelope;
|
|
258
|
+
const status = apiError?.status ?? x402PayError?.status;
|
|
259
|
+
const errorCode = error?.code;
|
|
260
|
+
const recorded = recordLastError({
|
|
261
|
+
message,
|
|
262
|
+
code: envelope?.reason ?? errorCode,
|
|
263
|
+
status
|
|
264
|
+
});
|
|
145
265
|
process.stderr.write(
|
|
146
266
|
JSON.stringify({
|
|
147
267
|
ok: false,
|
|
@@ -152,7 +272,8 @@ function renderFailure(error, options) {
|
|
|
152
272
|
...x402PayError?.pending !== void 0 ? { pending: x402PayError.pending } : {},
|
|
153
273
|
...x402PayError?.payment !== void 0 ? { payment: x402PayError.payment } : {},
|
|
154
274
|
...x402PayError !== void 0 ? x402FailureFields(x402PayError) : {},
|
|
155
|
-
...options?.details ?? {}
|
|
275
|
+
...options?.details ?? {},
|
|
276
|
+
...recorded ? { reportBug: REPORT_BUG_HINT } : {}
|
|
156
277
|
}) + "\n"
|
|
157
278
|
);
|
|
158
279
|
process.exitCode = 1;
|
|
@@ -171,7 +292,9 @@ async function pollAgentId(address, maxWaitMs = 6e4) {
|
|
|
171
292
|
while (Date.now() < deadline) {
|
|
172
293
|
await new Promise((r) => setTimeout(r, interval));
|
|
173
294
|
try {
|
|
174
|
-
const res = await fetch(
|
|
295
|
+
const res = await fetch(
|
|
296
|
+
`${apiUrl()}/api/identity/status?address=${address}&chainId=${selectedNetwork().chainId}`
|
|
297
|
+
);
|
|
175
298
|
if (res.ok) {
|
|
176
299
|
const data = await res.json();
|
|
177
300
|
if (data.agentId) return data.agentId;
|
|
@@ -591,7 +714,17 @@ var addressCommand = new Command3("address").description("Print the wallet addre
|
|
|
591
714
|
import { Command as Command4 } from "commander";
|
|
592
715
|
|
|
593
716
|
// src/lib/x402.ts
|
|
717
|
+
var FACILITATOR_RETRIES = 2;
|
|
718
|
+
var MAX_RETRY_AFTER_SECONDS = 60;
|
|
719
|
+
var DEFAULT_RETRY_AFTER_SECONDS = 30;
|
|
720
|
+
function retryAfterMs(res) {
|
|
721
|
+
const header = res.headers?.get?.("retry-after");
|
|
722
|
+
const seconds = header ? Number(header) : NaN;
|
|
723
|
+
const wait = Number.isFinite(seconds) && seconds >= 0 ? seconds : DEFAULT_RETRY_AFTER_SECONDS;
|
|
724
|
+
return Math.min(wait, MAX_RETRY_AFTER_SECONDS) * 1e3;
|
|
725
|
+
}
|
|
594
726
|
async function x402Post(path3, body, options) {
|
|
727
|
+
const sleep4 = options?.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
595
728
|
if (paymentProtocolOf(selectedNetwork().chainId) === "mpp")
|
|
596
729
|
return mppPost(path3, body, options);
|
|
597
730
|
const keystore = await loadKeystore();
|
|
@@ -622,16 +755,21 @@ async function x402Post(path3, body, options) {
|
|
|
622
755
|
from: keystore.walletAddress,
|
|
623
756
|
signTypedData: (typedData) => signTypedData(typedData, keystore)
|
|
624
757
|
});
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
758
|
+
for (let attempt = 0; ; attempt++) {
|
|
759
|
+
const r2 = await fetch(request.url, {
|
|
760
|
+
method: "POST",
|
|
761
|
+
redirect: "error",
|
|
762
|
+
headers: { ...request.headers, "PAYMENT-SIGNATURE": header },
|
|
763
|
+
body: request.body
|
|
764
|
+
});
|
|
765
|
+
if (r2.ok) return { data: await r2.json(), idempotencyKey };
|
|
766
|
+
const read = await readFailureBody(r2);
|
|
767
|
+
if (r2.status === 503 && apiErrorEnvelopeOf(read.body)?.reason === "facilitator_unavailable" && attempt < FACILITATOR_RETRIES) {
|
|
768
|
+
await sleep4(retryAfterMs(r2));
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
throw failedAfterPayment(path3, r2.status, read, idempotencyKey);
|
|
633
772
|
}
|
|
634
|
-
return { data: await r2.json(), idempotencyKey };
|
|
635
773
|
});
|
|
636
774
|
}
|
|
637
775
|
|
|
@@ -643,7 +781,9 @@ identityCommand.command("register").description("Register ERC-8004 agent identit
|
|
|
643
781
|
});
|
|
644
782
|
identityCommand.command("status").description("Check identity registration status").action(async () => {
|
|
645
783
|
const keystore = await loadKeystore();
|
|
646
|
-
const result = await apiGet(
|
|
784
|
+
const result = await apiGet(
|
|
785
|
+
`/api/identity/status?address=${keystore.walletAddress}&chainId=${selectedNetwork().chainId}`
|
|
786
|
+
);
|
|
647
787
|
printResult({ registered: result.registered, agentId: result.agentId });
|
|
648
788
|
});
|
|
649
789
|
|
|
@@ -698,15 +838,550 @@ var statsCommand = new Command5("stats").description("View agent statistics").op
|
|
|
698
838
|
});
|
|
699
839
|
|
|
700
840
|
// src/commands/task/index.ts
|
|
701
|
-
import { Command as
|
|
841
|
+
import { Command as Command45 } from "commander";
|
|
842
|
+
|
|
843
|
+
// src/commands/task/review.ts
|
|
844
|
+
import { readFile, stat } from "fs/promises";
|
|
845
|
+
import { Command as Command6, Option } from "commander";
|
|
846
|
+
import { z as z2 } from "zod";
|
|
847
|
+
|
|
848
|
+
// src/lib/submission-reviews.ts
|
|
849
|
+
import { z } from "zod";
|
|
850
|
+
var controlOutput = z.object({
|
|
851
|
+
runId: z.string().uuid(),
|
|
852
|
+
status: z.union([SubmissionReviewJobStatusSchema, z.literal("deleted")])
|
|
853
|
+
});
|
|
854
|
+
var correctionOutput = z.object({
|
|
855
|
+
correctionId: z.string().uuid(),
|
|
856
|
+
createdAt: z.string().datetime()
|
|
857
|
+
});
|
|
858
|
+
var query = (values) => {
|
|
859
|
+
const params = new URLSearchParams();
|
|
860
|
+
for (const [key, value] of Object.entries(values))
|
|
861
|
+
if (value !== void 0) params.set(key, String(value));
|
|
862
|
+
return params.size ? `?${params}` : "";
|
|
863
|
+
};
|
|
864
|
+
var taskPath = (taskId) => `/api/tasks/${encodeURIComponent(taskId)}`;
|
|
865
|
+
var runPath = (runId) => `/api/submission-reviews/${encodeURIComponent(runId)}`;
|
|
866
|
+
function createSubmissionReviewClient(options) {
|
|
867
|
+
const now = options.now ?? Date.now;
|
|
868
|
+
const sleep4 = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
869
|
+
let headersPromise;
|
|
870
|
+
const headers = () => headersPromise ??= (async () => {
|
|
871
|
+
const signer = await options.signer();
|
|
872
|
+
return {
|
|
873
|
+
[READ_AUTH_ADDRESS_HEADER]: signer.address,
|
|
874
|
+
[READ_AUTH_SIGNATURE_HEADER]: await signer.signMessage(
|
|
875
|
+
buildReadAuthMessage(signer.address)
|
|
876
|
+
)
|
|
877
|
+
};
|
|
878
|
+
})();
|
|
879
|
+
async function get(path3, schema) {
|
|
880
|
+
return schema.parse(await options.transport.get(path3, await headers()));
|
|
881
|
+
}
|
|
882
|
+
async function write(action, payload, chainId, path3, schema, key) {
|
|
883
|
+
const idempotencyKey = z.string().uuid().parse(resolveIdempotencyKey(key)).toLowerCase();
|
|
884
|
+
return withIdempotentWrite(idempotencyKey, async () => {
|
|
885
|
+
const signer = await options.signer();
|
|
886
|
+
const expiresAt = Math.floor(now() / 1e3) + 240;
|
|
887
|
+
const signature = await signer.signMessage(
|
|
888
|
+
buildSubmissionReviewActionMessage({
|
|
889
|
+
action,
|
|
890
|
+
payload,
|
|
891
|
+
chainId,
|
|
892
|
+
requester: signer.address,
|
|
893
|
+
idempotencyKey,
|
|
894
|
+
expiresAt
|
|
895
|
+
})
|
|
896
|
+
);
|
|
897
|
+
const body = {
|
|
898
|
+
...payload,
|
|
899
|
+
chainId,
|
|
900
|
+
requesterAddress: signer.address,
|
|
901
|
+
idempotencyKey,
|
|
902
|
+
expiresAt,
|
|
903
|
+
signature,
|
|
904
|
+
...["pause", "cancel", "delete"].includes(action) ? { action } : {}
|
|
905
|
+
};
|
|
906
|
+
const result = await options.transport.post(path3, body, idempotencyKey);
|
|
907
|
+
if (result.idempotencyKey !== idempotencyKey)
|
|
908
|
+
throw new Error(
|
|
909
|
+
"Review response has a different request key; recover the original request before retrying."
|
|
910
|
+
);
|
|
911
|
+
return { data: schema.parse(result.data), idempotencyKey };
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
const client = {
|
|
915
|
+
async profile(input) {
|
|
916
|
+
const { taskId, ...params } = SubmissionReviewTaskInputSchema.parse(input);
|
|
917
|
+
return get(
|
|
918
|
+
`${taskPath(taskId)}/submission-review-profile${query(params)}`,
|
|
919
|
+
SubmissionReviewProfileOutputSchema
|
|
920
|
+
);
|
|
921
|
+
},
|
|
922
|
+
async preview(input) {
|
|
923
|
+
const parsed = SubmissionReviewPreviewInputSchema.parse(input);
|
|
924
|
+
if (parsed.scope !== "selected" && parsed.submissionIds)
|
|
925
|
+
throw new Error("Submission IDs require selected scope.");
|
|
926
|
+
if (parsed.scope === "selected" && !parsed.submissionIds?.length)
|
|
927
|
+
throw new Error("Selected scope requires submission IDs.");
|
|
928
|
+
const { taskId, ...body } = parsed;
|
|
929
|
+
return SubmissionReviewPreviewOutputSchema.parse(
|
|
930
|
+
await options.transport.preview(
|
|
931
|
+
`${taskPath(taskId)}/submission-reviews/preview`,
|
|
932
|
+
body,
|
|
933
|
+
await headers()
|
|
934
|
+
)
|
|
935
|
+
);
|
|
936
|
+
},
|
|
937
|
+
async start(input, expectedTaskId, key) {
|
|
938
|
+
const preview = SubmissionReviewPreviewOutputSchema.parse(input);
|
|
939
|
+
SubmissionReviewRunInputSchema.shape.chainId.parse(preview.chainId);
|
|
940
|
+
if (preview.taskId !== expectedTaskId)
|
|
941
|
+
throw new Error("Preview belongs to a different task.");
|
|
942
|
+
if (!preview.canStart || !preview.profile.profileFingerprint)
|
|
943
|
+
throw new Error("This preview cannot start a review. Obtain a fresh eligible preview.");
|
|
944
|
+
const payload = SubmissionReviewStartPayloadSchema.parse({
|
|
945
|
+
taskId: preview.taskId,
|
|
946
|
+
sourceFingerprint: preview.sourceFingerprint,
|
|
947
|
+
profileFingerprint: preview.profile.profileFingerprint,
|
|
948
|
+
submissionIds: preview.submissionIds
|
|
949
|
+
});
|
|
950
|
+
return write(
|
|
951
|
+
"start",
|
|
952
|
+
payload,
|
|
953
|
+
preview.chainId,
|
|
954
|
+
`${taskPath(preview.taskId)}/submission-reviews`,
|
|
955
|
+
SubmissionReviewRunSummarySchema,
|
|
956
|
+
key
|
|
957
|
+
);
|
|
958
|
+
},
|
|
959
|
+
async status(input) {
|
|
960
|
+
const { runId, ...params } = SubmissionReviewRunInputSchema.parse(input);
|
|
961
|
+
return get(`${runPath(runId)}${query(params)}`, SubmissionReviewRunSummarySchema);
|
|
962
|
+
},
|
|
963
|
+
async lookup(input) {
|
|
964
|
+
const { idempotencyKey, ...params } = SubmissionReviewLookupInputSchema.parse(input);
|
|
965
|
+
return get(
|
|
966
|
+
`/api/submission-review-requests/${idempotencyKey}${query(params)}`,
|
|
967
|
+
SubmissionReviewRunSummarySchema
|
|
968
|
+
);
|
|
969
|
+
},
|
|
970
|
+
async control(action, input, key) {
|
|
971
|
+
z.enum(["pause", "resume", "cancel", "delete"]).parse(action);
|
|
972
|
+
const { runId, chainId } = SubmissionReviewRunInputSchema.parse(input);
|
|
973
|
+
return write(
|
|
974
|
+
action,
|
|
975
|
+
{ runId },
|
|
976
|
+
chainId,
|
|
977
|
+
`${runPath(runId)}/${action === "resume" ? "resume" : "control"}`,
|
|
978
|
+
controlOutput,
|
|
979
|
+
key
|
|
980
|
+
);
|
|
981
|
+
},
|
|
982
|
+
async results(input) {
|
|
983
|
+
const { taskId, ...params } = SubmissionReviewResultsInputSchema.parse(input);
|
|
984
|
+
return get(
|
|
985
|
+
`${taskPath(taskId)}/submission-review-results${query(params)}`,
|
|
986
|
+
SubmissionReviewResultsOutputSchema
|
|
987
|
+
);
|
|
988
|
+
},
|
|
989
|
+
async allResults(input) {
|
|
990
|
+
if (input.cursor) throw new Error("Do not combine --all and --cursor.");
|
|
991
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
992
|
+
try {
|
|
993
|
+
const first = await client.results({ ...input, limit: 100 });
|
|
994
|
+
const rows = [...first.rows];
|
|
995
|
+
let cursor = first.nextCursor;
|
|
996
|
+
const seen = /* @__PURE__ */ new Set();
|
|
997
|
+
while (cursor) {
|
|
998
|
+
if (seen.has(cursor)) throw new Error("Review pagination did not advance.");
|
|
999
|
+
seen.add(cursor);
|
|
1000
|
+
const page = await client.results({ ...input, limit: 100, cursor });
|
|
1001
|
+
if (page.viewFingerprint !== first.viewFingerprint)
|
|
1002
|
+
throw new ApiError(409, "Review changed during pagination.");
|
|
1003
|
+
rows.push(...page.rows);
|
|
1004
|
+
cursor = page.nextCursor;
|
|
1005
|
+
}
|
|
1006
|
+
return { ...first, rows, nextCursor: null };
|
|
1007
|
+
} catch (error) {
|
|
1008
|
+
if (attempt === 0 && error instanceof ApiError && error.status === 409) continue;
|
|
1009
|
+
throw error;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
throw new Error("Review changed. Read the results again.");
|
|
1013
|
+
},
|
|
1014
|
+
async history(input) {
|
|
1015
|
+
const { taskId, ...params } = SubmissionReviewHistoryInputSchema.parse(input);
|
|
1016
|
+
return get(
|
|
1017
|
+
`${taskPath(taskId)}/submission-reviews${query(params)}`,
|
|
1018
|
+
SubmissionReviewHistoryOutputSchema
|
|
1019
|
+
);
|
|
1020
|
+
},
|
|
1021
|
+
async assessment(input) {
|
|
1022
|
+
const { runId, submissionId, ...params } = SubmissionReviewAssessmentInputSchema.parse(input);
|
|
1023
|
+
return get(
|
|
1024
|
+
`${runPath(runId)}/assessments/${encodeURIComponent(submissionId)}${query(params)}`,
|
|
1025
|
+
SubmissionReviewAssessmentOutputSchema
|
|
1026
|
+
);
|
|
1027
|
+
},
|
|
1028
|
+
async correct(input, key) {
|
|
1029
|
+
const { runId, chainId } = SubmissionReviewRunInputSchema.parse({
|
|
1030
|
+
runId: input.runId,
|
|
1031
|
+
chainId: input.chainId
|
|
1032
|
+
});
|
|
1033
|
+
const payload = {
|
|
1034
|
+
runId,
|
|
1035
|
+
assessmentId: z.string().uuid().parse(input.assessmentId),
|
|
1036
|
+
correction: SubmissionReviewCorrectionSchema.parse(input.correction)
|
|
1037
|
+
};
|
|
1038
|
+
return write(
|
|
1039
|
+
"correct",
|
|
1040
|
+
payload,
|
|
1041
|
+
chainId,
|
|
1042
|
+
`${runPath(runId)}/corrections`,
|
|
1043
|
+
correctionOutput,
|
|
1044
|
+
key
|
|
1045
|
+
);
|
|
1046
|
+
},
|
|
1047
|
+
async *watch(input, settings = {}) {
|
|
1048
|
+
const { intervalSeconds, timeoutSeconds } = z.object({
|
|
1049
|
+
intervalSeconds: z.number().int().min(1).max(60).default(5),
|
|
1050
|
+
timeoutSeconds: z.number().int().min(1).max(86400).default(300)
|
|
1051
|
+
}).parse(settings);
|
|
1052
|
+
const deadline = now() + timeoutSeconds * 1e3;
|
|
1053
|
+
while (true) {
|
|
1054
|
+
const status = await client.status(input);
|
|
1055
|
+
yield status;
|
|
1056
|
+
if (!["queued", "running"].includes(status.status) || now() >= deadline) return;
|
|
1057
|
+
await sleep4(Math.min(intervalSeconds * 1e3, Math.max(0, deadline - now())));
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
return client;
|
|
1062
|
+
}
|
|
1063
|
+
function cliSubmissionReviewClient() {
|
|
1064
|
+
return createSubmissionReviewClient({
|
|
1065
|
+
signer: async () => {
|
|
1066
|
+
const keystore = await loadKeystore();
|
|
1067
|
+
return {
|
|
1068
|
+
address: keystore.walletAddress,
|
|
1069
|
+
signMessage: (message) => signMessage(message, keystore)
|
|
1070
|
+
};
|
|
1071
|
+
},
|
|
1072
|
+
transport: {
|
|
1073
|
+
get: (path3, headers) => apiGet(path3, { headers }),
|
|
1074
|
+
preview: (path3, body, headers) => apiReadPost(path3, body, { headers }),
|
|
1075
|
+
post: (path3, body, idempotencyKey) => apiPost(path3, body, { idempotencyKey })
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// src/commands/task/review.ts
|
|
1081
|
+
var integer = (value) => z2.coerce.number().int().positive().safe().parse(value);
|
|
1082
|
+
var collect = (value, values) => [...values, value];
|
|
1083
|
+
var taskCommand = (name, description) => new Command6(name).description(description).argument("<taskId>", "Task ID").option("--chain-id <id>", "Require this task chain", integer);
|
|
1084
|
+
var runCommand = (name, description) => new Command6(name).description(description).argument("<runId>", "Private review run ID").requiredOption("--chain-id <id>", "Chain recorded on the review run", integer);
|
|
1085
|
+
function createReviewCommand() {
|
|
1086
|
+
const group = new Command6("review").description(
|
|
1087
|
+
"Requester-private advisory brief review and experimental taste scoring; never awards or rejects work"
|
|
1088
|
+
);
|
|
1089
|
+
group.addCommand(
|
|
1090
|
+
taskCommand(
|
|
1091
|
+
"profile",
|
|
1092
|
+
"Show review availability, supported media and evaluator version"
|
|
1093
|
+
).action(async (taskId, options) => {
|
|
1094
|
+
printResult(await cliSubmissionReviewClient().profile({ taskId, chainId: options.chainId }));
|
|
1095
|
+
})
|
|
1096
|
+
);
|
|
1097
|
+
group.addCommand(
|
|
1098
|
+
taskCommand("preview", "Preview the exact brief and submission set without running inference").addOption(
|
|
1099
|
+
new Option("--scope <scope>", "latest versions, remaining versions, or selected IDs").choices(["latest", "remaining", "selected"]).default("latest")
|
|
1100
|
+
).option(
|
|
1101
|
+
"--submission-id <id>",
|
|
1102
|
+
"Submission ID for selected scope; repeat for multiple submissions",
|
|
1103
|
+
collect,
|
|
1104
|
+
[]
|
|
1105
|
+
).action(
|
|
1106
|
+
async (taskId, options) => {
|
|
1107
|
+
printResult(
|
|
1108
|
+
await cliSubmissionReviewClient().preview({
|
|
1109
|
+
taskId,
|
|
1110
|
+
chainId: options.chainId,
|
|
1111
|
+
scope: options.scope,
|
|
1112
|
+
...options.submissionId.length ? { submissionIds: options.submissionId } : {}
|
|
1113
|
+
})
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
)
|
|
1117
|
+
);
|
|
1118
|
+
group.addCommand(
|
|
1119
|
+
new Command6("start").description(
|
|
1120
|
+
"Sign and start the exact saved preview; obtain a fresh preview if sources changed"
|
|
1121
|
+
).argument("<taskId>", "Task ID").requiredOption("--preview-file <path>", "JSON output from task review preview").action(async (taskId, options) => {
|
|
1122
|
+
const info = await stat(options.previewFile);
|
|
1123
|
+
if (!info.isFile() || info.size > 1048576)
|
|
1124
|
+
throw new Error("Review preview must be a JSON file of at most 1 MiB.");
|
|
1125
|
+
const input = JSON.parse(await readFile(options.previewFile, "utf8"));
|
|
1126
|
+
const preview = input && typeof input === "object" && "ok" in input && input.ok === true && "data" in input ? input.data : input;
|
|
1127
|
+
const result = await cliSubmissionReviewClient().start(preview, taskId);
|
|
1128
|
+
printResult(result.data, { idempotencyKey: result.idempotencyKey });
|
|
1129
|
+
})
|
|
1130
|
+
);
|
|
1131
|
+
group.addCommand(
|
|
1132
|
+
runCommand("status", "Read saved progress; watching never starts or resumes inference").option("--watch", "Emit one JSON result per poll until stopped, completed, or timeout").option("--interval <seconds>", "Seconds between status reads (1\u201360)", integer, 5).option(
|
|
1133
|
+
"--timeout <seconds>",
|
|
1134
|
+
"Maximum polling duration (1\u201386400); the run keeps its current state",
|
|
1135
|
+
integer,
|
|
1136
|
+
300
|
|
1137
|
+
).action(
|
|
1138
|
+
async (runId, options) => {
|
|
1139
|
+
const client = cliSubmissionReviewClient();
|
|
1140
|
+
const input = { runId, chainId: options.chainId };
|
|
1141
|
+
if (!options.watch) {
|
|
1142
|
+
printResult(await client.status(input));
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
for await (const status of client.watch(input, {
|
|
1146
|
+
intervalSeconds: options.interval,
|
|
1147
|
+
timeoutSeconds: options.timeout
|
|
1148
|
+
}))
|
|
1149
|
+
printResult(status);
|
|
1150
|
+
}
|
|
1151
|
+
)
|
|
1152
|
+
);
|
|
1153
|
+
group.addCommand(
|
|
1154
|
+
new Command6("lookup").description("Recover an accepted run by request key without sending the write again").argument("<requestKey>", "Idempotency key from the start result or error").requiredOption("--chain-id <id>", "Chain from the saved preview", integer).action(async (idempotencyKey, options) => {
|
|
1155
|
+
printResult(
|
|
1156
|
+
await cliSubmissionReviewClient().lookup({ idempotencyKey, chainId: options.chainId })
|
|
1157
|
+
);
|
|
1158
|
+
})
|
|
1159
|
+
);
|
|
1160
|
+
for (const [action, description] of [
|
|
1161
|
+
["pause", "Pause before the next provider call; already-dispatched calls may finish"],
|
|
1162
|
+
["resume", "Explicitly resume an eligible paused run"],
|
|
1163
|
+
["cancel", "Cancel remaining work and retain completed assessments"],
|
|
1164
|
+
["delete", "Delete this private report, evidence and corrections; billing records remain"]
|
|
1165
|
+
]) {
|
|
1166
|
+
const command = runCommand(action, description);
|
|
1167
|
+
if (action === "delete")
|
|
1168
|
+
command.requiredOption("--confirm", "Confirm irreversible report deletion");
|
|
1169
|
+
command.action(async (runId, options) => {
|
|
1170
|
+
const result = await cliSubmissionReviewClient().control(action, {
|
|
1171
|
+
runId,
|
|
1172
|
+
chainId: options.chainId
|
|
1173
|
+
});
|
|
1174
|
+
printResult(result.data, { idempotencyKey: result.idempotencyKey });
|
|
1175
|
+
});
|
|
1176
|
+
group.addCommand(command);
|
|
1177
|
+
}
|
|
1178
|
+
group.addCommand(
|
|
1179
|
+
taskCommand(
|
|
1180
|
+
"results",
|
|
1181
|
+
"Filter and rank saved results before pagination; new versions never inherit older scores"
|
|
1182
|
+
).option("--run-id <id>", "Inspect the exact frozen cohort of a historical run").addOption(
|
|
1183
|
+
new Option("--compliance <state>", "Brief compliance").choices([
|
|
1184
|
+
"supported",
|
|
1185
|
+
"pending",
|
|
1186
|
+
"unmet"
|
|
1187
|
+
])
|
|
1188
|
+
).addOption(
|
|
1189
|
+
new Option("--quality-band <band>", "Experimental taste band").choices([
|
|
1190
|
+
"strong",
|
|
1191
|
+
"mixed",
|
|
1192
|
+
"weak"
|
|
1193
|
+
])
|
|
1194
|
+
).addOption(
|
|
1195
|
+
new Option("--state <state>", "Processing or freshness state").choices(
|
|
1196
|
+
SubmissionReviewResultStateSchema.options
|
|
1197
|
+
)
|
|
1198
|
+
).option(
|
|
1199
|
+
"--shortlist",
|
|
1200
|
+
"Only shortlist suggestions; pending verification can still be present"
|
|
1201
|
+
).addOption(
|
|
1202
|
+
new Option("--sort <sort>", "Saved ranking or submission time").choices(["rank", "newest"]).default("rank")
|
|
1203
|
+
).option("--limit <count>", "Rows per page (1\u2013100)", integer, 24).option("--cursor <cursor>", "Cursor returned by the same result view").option("--all", "Read all pages as one consistent result; no inference").action(
|
|
1204
|
+
async (taskId, options) => {
|
|
1205
|
+
const { all, ...filters } = options;
|
|
1206
|
+
const client = cliSubmissionReviewClient();
|
|
1207
|
+
const input = { taskId, ...filters };
|
|
1208
|
+
printResult(all ? await client.allResults(input) : await client.results(input));
|
|
1209
|
+
}
|
|
1210
|
+
)
|
|
1211
|
+
);
|
|
1212
|
+
group.addCommand(
|
|
1213
|
+
taskCommand("history", "List saved review runs for this task").option("--limit <count>", "Runs per page (1\u2013100)", integer, 20).option("--cursor <runId>", "Cursor returned by the preceding history page").action(async (taskId, options) => {
|
|
1214
|
+
printResult(await cliSubmissionReviewClient().history({ taskId, ...options }));
|
|
1215
|
+
})
|
|
1216
|
+
);
|
|
1217
|
+
group.addCommand(
|
|
1218
|
+
runCommand(
|
|
1219
|
+
"assessment",
|
|
1220
|
+
"Read the frozen brief, evidence, original assessment and requester corrections"
|
|
1221
|
+
).argument("<submissionId>", "Exact submission version ID").action(async (runId, submissionId, options) => {
|
|
1222
|
+
printResult(
|
|
1223
|
+
await cliSubmissionReviewClient().assessment({
|
|
1224
|
+
runId,
|
|
1225
|
+
submissionId,
|
|
1226
|
+
chainId: options.chainId
|
|
1227
|
+
})
|
|
1228
|
+
);
|
|
1229
|
+
})
|
|
1230
|
+
);
|
|
1231
|
+
group.addCommand(
|
|
1232
|
+
runCommand(
|
|
1233
|
+
"correct",
|
|
1234
|
+
"Append a signed requester correction; preserve the original model finding"
|
|
1235
|
+
).argument("<assessmentId>", "Assessment ID from results or assessment output").requiredOption("--requirement-id <id>", "Checklist requirement to correct").addOption(
|
|
1236
|
+
new Option("--status <status>", "Corrected requirement status").choices(["supported", "unmet", "pending", "not_applicable"]).makeOptionMandatory()
|
|
1237
|
+
).requiredOption("--reason <text>", "Reason for the correction").option("--evidence-id <id>", "Existing evidence ID; repeat as needed", collect, []).action(
|
|
1238
|
+
async (runId, assessmentId, options) => {
|
|
1239
|
+
const result = await cliSubmissionReviewClient().correct({
|
|
1240
|
+
runId,
|
|
1241
|
+
assessmentId,
|
|
1242
|
+
chainId: options.chainId,
|
|
1243
|
+
correction: {
|
|
1244
|
+
requirementId: options.requirementId,
|
|
1245
|
+
status: options.status,
|
|
1246
|
+
reason: options.reason.trim(),
|
|
1247
|
+
evidenceIds: options.evidenceId
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
printResult(result.data, { idempotencyKey: result.idempotencyKey });
|
|
1251
|
+
}
|
|
1252
|
+
)
|
|
1253
|
+
);
|
|
1254
|
+
return group;
|
|
1255
|
+
}
|
|
1256
|
+
var reviewCmd = createReviewCommand();
|
|
702
1257
|
|
|
703
1258
|
// src/commands/task/create.ts
|
|
704
|
-
import { Command as
|
|
1259
|
+
import { Command as Command7 } from "commander";
|
|
705
1260
|
import { parseUnits } from "viem";
|
|
1261
|
+
|
|
1262
|
+
// src/lib/settlement-terms.ts
|
|
1263
|
+
var TERM_FLAGS = {
|
|
1264
|
+
stakeRequired: "--stake-required",
|
|
1265
|
+
stakeBps: "--stake-bps",
|
|
1266
|
+
penaltyTo: "--penalty-to",
|
|
1267
|
+
reviewWindowSecs: "--review-window",
|
|
1268
|
+
decisionWindowSecs: "--decision-window",
|
|
1269
|
+
reopenExtensionSecs: "--reopen-extension",
|
|
1270
|
+
releaseAllowed: "--release",
|
|
1271
|
+
releaseGraceBps: "--release-grace-bps",
|
|
1272
|
+
rejectOutcome: "--reject-outcome",
|
|
1273
|
+
rejectFeeBps: "--reject-fee-bps",
|
|
1274
|
+
maxRevisions: "--max-revisions",
|
|
1275
|
+
resolutionWindowSecs: "--resolution-window"
|
|
1276
|
+
};
|
|
1277
|
+
function hoursToSecs(flag, value) {
|
|
1278
|
+
const hours = Number(value);
|
|
1279
|
+
if (value.trim() === "" || !Number.isFinite(hours) || hours <= 0) {
|
|
1280
|
+
return { error: `${flag} must be a positive number of hours` };
|
|
1281
|
+
}
|
|
1282
|
+
return Math.round(hours * 3600);
|
|
1283
|
+
}
|
|
1284
|
+
function integer2(flag, value, max) {
|
|
1285
|
+
if (!/^\d+$/.test(value.trim()) || Number(value) > max) {
|
|
1286
|
+
return { error: `${flag} must be an integer between 0 and ${max}` };
|
|
1287
|
+
}
|
|
1288
|
+
return Number(value);
|
|
1289
|
+
}
|
|
1290
|
+
function parseTermsFlags(opts) {
|
|
1291
|
+
const terms = {};
|
|
1292
|
+
let termsPreset;
|
|
1293
|
+
if (opts.termsPreset !== void 0) {
|
|
1294
|
+
const parsed = TermsPresetName.safeParse(opts.termsPreset);
|
|
1295
|
+
if (!parsed.success) {
|
|
1296
|
+
return { error: `--terms-preset must be one of: ${TermsPresetName.options.join(", ")}` };
|
|
1297
|
+
}
|
|
1298
|
+
termsPreset = parsed.data;
|
|
1299
|
+
}
|
|
1300
|
+
if (opts.stakeRequired !== void 0) terms.stakeRequired = opts.stakeRequired;
|
|
1301
|
+
if (opts.stakeBps !== void 0) {
|
|
1302
|
+
const bps = integer2("--stake-bps", opts.stakeBps, 1e4);
|
|
1303
|
+
if (typeof bps !== "number") return bps;
|
|
1304
|
+
terms.stakeBps = bps;
|
|
1305
|
+
if (opts.stakeRequired === void 0) terms.stakeRequired = bps > 0;
|
|
1306
|
+
} else if (opts.stakeRequired === false) {
|
|
1307
|
+
terms.stakeBps = 0;
|
|
1308
|
+
}
|
|
1309
|
+
if (opts.penaltyTo !== void 0) {
|
|
1310
|
+
const parsed = PenaltyTo.safeParse(opts.penaltyTo);
|
|
1311
|
+
if (!parsed.success) return { error: "--penalty-to must be one of: requester, protocol" };
|
|
1312
|
+
terms.penaltyTo = parsed.data;
|
|
1313
|
+
}
|
|
1314
|
+
for (const [flag, value, key] of [
|
|
1315
|
+
["--review-window", opts.reviewWindow, "reviewWindowSecs"],
|
|
1316
|
+
["--decision-window", opts.decisionWindow, "decisionWindowSecs"],
|
|
1317
|
+
["--reopen-extension", opts.reopenExtension, "reopenExtensionSecs"],
|
|
1318
|
+
["--resolution-window", opts.resolutionWindow, "resolutionWindowSecs"]
|
|
1319
|
+
]) {
|
|
1320
|
+
if (value === void 0) continue;
|
|
1321
|
+
const secs = hoursToSecs(flag, value);
|
|
1322
|
+
if (typeof secs !== "number") return secs;
|
|
1323
|
+
terms[key] = secs;
|
|
1324
|
+
}
|
|
1325
|
+
if (opts.release !== void 0) {
|
|
1326
|
+
if (opts.release !== "allowed" && opts.release !== "disallowed") {
|
|
1327
|
+
return { error: "--release must be one of: allowed, disallowed" };
|
|
1328
|
+
}
|
|
1329
|
+
terms.releaseAllowed = opts.release === "allowed";
|
|
1330
|
+
}
|
|
1331
|
+
for (const [flag, value, key, max] of [
|
|
1332
|
+
["--release-grace-bps", opts.releaseGraceBps, "releaseGraceBps", 1e4],
|
|
1333
|
+
["--reject-fee-bps", opts.rejectFeeBps, "rejectFeeBps", 1e4],
|
|
1334
|
+
["--max-revisions", opts.maxRevisions, "maxRevisions", 255]
|
|
1335
|
+
]) {
|
|
1336
|
+
if (value === void 0) continue;
|
|
1337
|
+
const n = integer2(flag, value, max);
|
|
1338
|
+
if (typeof n !== "number") return n;
|
|
1339
|
+
terms[key] = n;
|
|
1340
|
+
}
|
|
1341
|
+
if (opts.rejectOutcome !== void 0) {
|
|
1342
|
+
const parsed = RejectOutcome.safeParse(opts.rejectOutcome);
|
|
1343
|
+
if (!parsed.success) return { error: "--reject-outcome must be one of: reopen, refund" };
|
|
1344
|
+
terms.rejectOutcome = parsed.data;
|
|
1345
|
+
}
|
|
1346
|
+
return { ...termsPreset ? { termsPreset } : {}, terms };
|
|
1347
|
+
}
|
|
1348
|
+
async function fetchTermsBounds() {
|
|
1349
|
+
try {
|
|
1350
|
+
const response = await apiGet("/api/tasks/terms-bounds");
|
|
1351
|
+
return response?.bounds ?? DEFAULT_TERMS_BOUNDS;
|
|
1352
|
+
} catch {
|
|
1353
|
+
return DEFAULT_TERMS_BOUNDS;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
function resolveTermsForCreate(args) {
|
|
1357
|
+
try {
|
|
1358
|
+
return resolveTaskTerms({
|
|
1359
|
+
mode: args.mode,
|
|
1360
|
+
hasEvaluator: args.hasEvaluator,
|
|
1361
|
+
preset: args.parsed.termsPreset,
|
|
1362
|
+
overrides: args.parsed.terms,
|
|
1363
|
+
bounds: args.bounds
|
|
1364
|
+
});
|
|
1365
|
+
} catch (error) {
|
|
1366
|
+
if (error instanceof TaskTermsError) {
|
|
1367
|
+
const flag = error.term ? TERM_FLAGS[error.term] : void 0;
|
|
1368
|
+
return { error: flag ? `${flag}: ${error.message}` : error.message };
|
|
1369
|
+
}
|
|
1370
|
+
throw error;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
function termsPresetLabel(terms) {
|
|
1374
|
+
return terms.custom ? "custom" : terms.preset;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/commands/task/create.ts
|
|
706
1378
|
function parseStakeOptions(opts) {
|
|
707
1379
|
if (!opts.stakeRequired && opts.stakeBps === void 0) {
|
|
708
1380
|
return { stakeRequired: false, stakeBps: 0 };
|
|
709
1381
|
}
|
|
1382
|
+
if (opts.stakeRequired === false) {
|
|
1383
|
+
return { error: "--stake-bps cannot be combined with --no-stake-required" };
|
|
1384
|
+
}
|
|
710
1385
|
if (opts.mode !== "claim") {
|
|
711
1386
|
return { error: "--stake-required and --stake-bps are only valid with --mode claim" };
|
|
712
1387
|
}
|
|
@@ -722,7 +1397,7 @@ function parseStakeOptions(opts) {
|
|
|
722
1397
|
}
|
|
723
1398
|
return { stakeRequired: true, stakeBps };
|
|
724
1399
|
}
|
|
725
|
-
var createCmd = new
|
|
1400
|
+
var createCmd = new Command7("create").description("Create a new task (costs the reward, in the payment token)").requiredOption("--description <text>", "Task description").requiredOption("--reward <amount>", "Reward in the payment token (e.g. 5)").requiredOption("--duration <hours>", "Task duration in hours").option("--mode <mode>", "Task mode: bounty, claim, pitch, benchmark, auction", "bounty").option(
|
|
726
1401
|
"--task-visibility <mode>",
|
|
727
1402
|
"Task visibility: public (default), unlisted, or private. Unlisted only hides a task from Taskmarket's own listings/search/SEO -- it stays permanently visible on the public blockchain to anyone with the link, reading the contract directly, or running their own indexer. private is genuinely access-controlled: only the requester and invited/assigned workers can view it via listings, get, or the gated reads -- see --allowed-viewers and --access-password. Even private, the on-chain existence, reward, and participation stay publicly observable regardless.",
|
|
728
1403
|
"public"
|
|
@@ -762,13 +1437,46 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
762
1437
|
).option(
|
|
763
1438
|
"--sponsored-task-tokens <amount>",
|
|
764
1439
|
"Whole-token amount to reserve from the --sponsored-task vault (e.g. 100 for 100 tokens). Required with --sponsored-task."
|
|
1440
|
+
).option(
|
|
1441
|
+
"--terms-preset <preset>",
|
|
1442
|
+
"Settlement terms preset: standard (default), fast or flexible. Term flags below override it."
|
|
765
1443
|
).option(
|
|
766
1444
|
"--stake-required",
|
|
767
1445
|
"Require the worker who claims the task to stake a share of the reward first (claim mode only)"
|
|
768
|
-
).option(
|
|
1446
|
+
).option("--no-stake-required", "Require no stake, overriding the preset (claim mode only)").option(
|
|
769
1447
|
"--stake-bps <bps>",
|
|
770
|
-
"Stake as basis points of the reward
|
|
771
|
-
).option("--
|
|
1448
|
+
"Stake as basis points of the reward (e.g. 1000 = 10%, at most 5000). Requires --stake-required."
|
|
1449
|
+
).option("--penalty-to <recipient>", "Where a forfeited stake goes: requester or protocol").option(
|
|
1450
|
+
"--review-window <hours>",
|
|
1451
|
+
"Hours the requester has to accept, reject or ask for a revision after delivery; the worker is paid if it lapses (claim, pitch, auction without an evaluator)"
|
|
1452
|
+
).option(
|
|
1453
|
+
"--decision-window <hours>",
|
|
1454
|
+
"Hours after expiry to pick winners; after it the requester can only accept (bounty, benchmark)"
|
|
1455
|
+
).option(
|
|
1456
|
+
"--reopen-extension <hours>",
|
|
1457
|
+
"When the task reopens, its deadline moves out at least this many hours (claim, pitch)"
|
|
1458
|
+
).option(
|
|
1459
|
+
"--release <allowed|disallowed>",
|
|
1460
|
+
"Whether a worker may hand a claim back before delivery (claim mode only)"
|
|
1461
|
+
).option(
|
|
1462
|
+
"--release-grace-bps <bps>",
|
|
1463
|
+
"Share of the claim time, in bps, during which handing back is free; after it the cost rises to the full stake at expiry"
|
|
1464
|
+
).option(
|
|
1465
|
+
"--reject-outcome <outcome>",
|
|
1466
|
+
"What happens after a rejected delivery: reopen or refund (claim, pitch; auction is refund only)"
|
|
1467
|
+
).option(
|
|
1468
|
+
"--reject-fee-bps <bps>",
|
|
1469
|
+
"Share of the reward, in bps, the worker still receives on a rejected delivery"
|
|
1470
|
+
).option(
|
|
1471
|
+
"--max-revisions <n>",
|
|
1472
|
+
"How many times the requester may send work back for fixes before accepting or rejecting"
|
|
1473
|
+
).option("--evaluator <address>", "Evaluator address (optional)").option("--evaluator-fee-bps <bps>", "Evaluator fee in basis points (optional)").option(
|
|
1474
|
+
"--evaluator-stake <amount>",
|
|
1475
|
+
"Stake behind the evaluator in the payment token (e.g. 1), paid with the reward. Requires --evaluator and --yes."
|
|
1476
|
+
).option("--yes", "Confirm paying the evaluator stake on top of the reward", false).option("--evaluation-window <hours>", "Evaluation window in hours (default: 24)").option("--appeal-window <hours>", "Appeal window in hours (default: 24)").option("--dispute-resolver <address>", "Dispute resolver address (optional)").option(
|
|
1477
|
+
"--resolution-window <hours>",
|
|
1478
|
+
"When the worker appeals the evaluator's verdict, the deadline moves out at least this many hours so the dispute resolver can rule (tasks with an evaluator; default 72)"
|
|
1479
|
+
).action(
|
|
772
1480
|
async (opts) => {
|
|
773
1481
|
let rewardBaseUnits;
|
|
774
1482
|
try {
|
|
@@ -777,6 +1485,29 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
777
1485
|
renderFailure(withErrorContext(err, "Invalid --reward"));
|
|
778
1486
|
return;
|
|
779
1487
|
}
|
|
1488
|
+
let evaluatorStakeBaseUnits = "0";
|
|
1489
|
+
if (opts.evaluatorStake !== void 0) {
|
|
1490
|
+
try {
|
|
1491
|
+
evaluatorStakeBaseUnits = usdcToBaseUnits(opts.evaluatorStake, { allowZero: true });
|
|
1492
|
+
} catch (err) {
|
|
1493
|
+
renderFailure(withErrorContext(err, "Invalid --evaluator-stake"));
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
const evaluatorStaked = BigInt(evaluatorStakeBaseUnits) > 0n;
|
|
1498
|
+
if (evaluatorStaked) {
|
|
1499
|
+
if (!opts.evaluator) {
|
|
1500
|
+
return void printError("--evaluator-stake requires --evaluator");
|
|
1501
|
+
}
|
|
1502
|
+
if (opts.sponsoredTask) {
|
|
1503
|
+
return void printError("--evaluator-stake cannot be combined with --sponsored-task");
|
|
1504
|
+
}
|
|
1505
|
+
if (!opts.yes) {
|
|
1506
|
+
return void printError(
|
|
1507
|
+
`This task stakes ${opts.evaluatorStake} (${evaluatorStakeBaseUnits} base units) behind the evaluator, paid now on top of the ${opts.reward} reward (${BigInt(rewardBaseUnits) + BigInt(evaluatorStakeBaseUnits)} base units in total) and forfeitable under the task's terms. Re-run with --yes to confirm.`
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
780
1511
|
const duration = Number(opts.duration);
|
|
781
1512
|
if (!Number.isFinite(duration) || duration <= 0) {
|
|
782
1513
|
return void printError("--duration must be a positive number of hours");
|
|
@@ -844,9 +1575,9 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
844
1575
|
);
|
|
845
1576
|
}
|
|
846
1577
|
}
|
|
847
|
-
const
|
|
848
|
-
if ("error" in
|
|
849
|
-
return void printError(
|
|
1578
|
+
const stakeFlags = parseStakeOptions(opts);
|
|
1579
|
+
if ("error" in stakeFlags) {
|
|
1580
|
+
return void printError(stakeFlags.error);
|
|
850
1581
|
}
|
|
851
1582
|
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [];
|
|
852
1583
|
const body = {
|
|
@@ -856,9 +1587,7 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
856
1587
|
mode: opts.mode,
|
|
857
1588
|
taskVisibility: opts.taskVisibility,
|
|
858
1589
|
submissionVisibility: opts.submissionVisibility,
|
|
859
|
-
tags
|
|
860
|
-
stakeRequired: stake.stakeRequired,
|
|
861
|
-
stakeBps: stake.stakeBps
|
|
1590
|
+
tags
|
|
862
1591
|
};
|
|
863
1592
|
if (allowedViewers && allowedViewers.length > 0) {
|
|
864
1593
|
body.allowedViewers = allowedViewers;
|
|
@@ -915,6 +1644,27 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
915
1644
|
"--hook-data cannot be combined with --sponsored-task -- the sponsored task funding request is the hookData"
|
|
916
1645
|
);
|
|
917
1646
|
}
|
|
1647
|
+
const termsFlags = parseTermsFlags(opts);
|
|
1648
|
+
if ("error" in termsFlags) {
|
|
1649
|
+
return void printError(termsFlags.error);
|
|
1650
|
+
}
|
|
1651
|
+
const resolvedTerms = resolveTermsForCreate({
|
|
1652
|
+
mode: opts.mode,
|
|
1653
|
+
hasEvaluator: Boolean(opts.evaluator),
|
|
1654
|
+
parsed: termsFlags,
|
|
1655
|
+
bounds: await fetchTermsBounds()
|
|
1656
|
+
});
|
|
1657
|
+
if ("error" in resolvedTerms) {
|
|
1658
|
+
return void printError(resolvedTerms.error);
|
|
1659
|
+
}
|
|
1660
|
+
const stake = {
|
|
1661
|
+
stakeRequired: resolvedTerms.stakeRequired,
|
|
1662
|
+
stakeBps: resolvedTerms.stakeBps
|
|
1663
|
+
};
|
|
1664
|
+
body.stakeRequired = stake.stakeRequired;
|
|
1665
|
+
body.stakeBps = stake.stakeBps;
|
|
1666
|
+
if (termsFlags.termsPreset) body.termsPreset = termsFlags.termsPreset;
|
|
1667
|
+
if (Object.keys(termsFlags.terms).length > 0) body.terms = termsFlags.terms;
|
|
918
1668
|
const ethAddrRe = /^0x[0-9a-fA-F]{40}$/;
|
|
919
1669
|
const defaultHookAddressRe = /^0x[0-9a-f]{40}$/i;
|
|
920
1670
|
const hooks = opts.hook ?? [];
|
|
@@ -1050,371 +1800,28 @@ var createCmd = new Command6("create").description("Create a new task (costs the
|
|
|
1050
1800
|
if (opts.evaluator) {
|
|
1051
1801
|
body.evaluator = opts.evaluator;
|
|
1052
1802
|
if (feeBps !== void 0) body.evaluatorFeeBps = feeBps;
|
|
1803
|
+
if (evaluatorStaked) body.evaluatorStake = evaluatorStakeBaseUnits;
|
|
1053
1804
|
if (opts.evaluationWindow) body.evaluationWindowHours = parseFloat(opts.evaluationWindow);
|
|
1054
1805
|
if (opts.appealWindow) body.appealWindowHours = parseFloat(opts.appealWindow);
|
|
1055
1806
|
if (opts.disputeResolver) body.disputeResolver = opts.disputeResolver;
|
|
1056
1807
|
}
|
|
1057
|
-
const { data: result, idempotencyKey } = await x402Post(
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
);
|
|
1061
|
-
printResult({ taskId: result.taskId }, { idempotencyKey });
|
|
1062
|
-
}
|
|
1063
|
-
);
|
|
1064
|
-
|
|
1065
|
-
// src/commands/task/search.ts
|
|
1066
|
-
import { Command as Command7 } from "commander";
|
|
1067
|
-
|
|
1068
|
-
// src/lib/read-auth.ts
|
|
1069
|
-
async function signReadAuth() {
|
|
1070
|
-
let keystore;
|
|
1071
|
-
try {
|
|
1072
|
-
keystore = await loadKeystore();
|
|
1073
|
-
} catch {
|
|
1074
|
-
return null;
|
|
1075
|
-
}
|
|
1076
|
-
try {
|
|
1077
|
-
const account = await createWalletAccountFromKeystore(keystore);
|
|
1078
|
-
const signature = await account.signMessage({
|
|
1079
|
-
message: buildReadAuthMessage(keystore.walletAddress)
|
|
1080
|
-
});
|
|
1081
|
-
return {
|
|
1082
|
-
walletAddress: keystore.walletAddress,
|
|
1083
|
-
headers: {
|
|
1084
|
-
[READ_AUTH_ADDRESS_HEADER]: keystore.walletAddress,
|
|
1085
|
-
[READ_AUTH_SIGNATURE_HEADER]: signature
|
|
1086
|
-
}
|
|
1087
|
-
};
|
|
1088
|
-
} catch {
|
|
1089
|
-
return { walletAddress: keystore.walletAddress, headers: {} };
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
// src/lib/task-access-grants.ts
|
|
1094
|
-
import { promises as fs } from "fs";
|
|
1095
|
-
import path from "path";
|
|
1096
|
-
function getGrantsPath() {
|
|
1097
|
-
return path.join(getTaskmarketHome(), "task-access-grants.json");
|
|
1098
|
-
}
|
|
1099
|
-
async function readGrantsFile() {
|
|
1100
|
-
try {
|
|
1101
|
-
const raw = await fs.readFile(getGrantsPath(), "utf-8");
|
|
1102
|
-
return JSON.parse(raw);
|
|
1103
|
-
} catch {
|
|
1104
|
-
return {};
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
async function loadTaskAccessGrant(taskId) {
|
|
1108
|
-
const grants = await readGrantsFile();
|
|
1109
|
-
const record = grants[taskId];
|
|
1110
|
-
if (!record) return null;
|
|
1111
|
-
if (new Date(record.expiresAt).getTime() <= Date.now()) return null;
|
|
1112
|
-
return record.grant;
|
|
1113
|
-
}
|
|
1114
|
-
async function taskAccessGrantHeaders(taskId) {
|
|
1115
|
-
const grant = await loadTaskAccessGrant(taskId);
|
|
1116
|
-
return grant ? { [TASK_ACCESS_GRANT_HEADER]: grant } : {};
|
|
1117
|
-
}
|
|
1118
|
-
async function saveTaskAccessGrant(taskId, grant, expiresAt) {
|
|
1119
|
-
const grants = await readGrantsFile();
|
|
1120
|
-
grants[taskId] = { grant, expiresAt };
|
|
1121
|
-
const dir = path.dirname(getGrantsPath());
|
|
1122
|
-
await fs.mkdir(dir, { recursive: true });
|
|
1123
|
-
await fs.writeFile(getGrantsPath(), JSON.stringify(grants, null, 2), {
|
|
1124
|
-
mode: 384
|
|
1125
|
-
});
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
// src/sdk/artifact-upload.ts
|
|
1129
|
-
import { extname } from "path";
|
|
1130
|
-
import { Readable } from "stream";
|
|
1131
|
-
import https from "https";
|
|
1132
|
-
import http from "http";
|
|
1133
|
-
function mimeTypeForPath(filePath) {
|
|
1134
|
-
switch (extname(filePath).toLowerCase()) {
|
|
1135
|
-
case ".png":
|
|
1136
|
-
return "image/png";
|
|
1137
|
-
case ".jpg":
|
|
1138
|
-
case ".jpeg":
|
|
1139
|
-
return "image/jpeg";
|
|
1140
|
-
case ".webp":
|
|
1141
|
-
return "image/webp";
|
|
1142
|
-
case ".gif":
|
|
1143
|
-
return "image/gif";
|
|
1144
|
-
case ".svg":
|
|
1145
|
-
return "image/svg+xml";
|
|
1146
|
-
case ".pdf":
|
|
1147
|
-
return "application/pdf";
|
|
1148
|
-
case ".mp4":
|
|
1149
|
-
return "video/mp4";
|
|
1150
|
-
case ".webm":
|
|
1151
|
-
return "video/webm";
|
|
1152
|
-
case ".mp3":
|
|
1153
|
-
return "audio/mpeg";
|
|
1154
|
-
case ".wav":
|
|
1155
|
-
return "audio/wav";
|
|
1156
|
-
case ".md":
|
|
1157
|
-
return "text/markdown";
|
|
1158
|
-
case ".txt":
|
|
1159
|
-
return "text/plain";
|
|
1160
|
-
case ".json":
|
|
1161
|
-
return "application/json";
|
|
1162
|
-
case ".zip":
|
|
1163
|
-
return "application/zip";
|
|
1164
|
-
default:
|
|
1165
|
-
return "application/octet-stream";
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
function putArtifactBytes(uploadUrl, data, mimeType, onProgress) {
|
|
1169
|
-
return new Promise((resolve, reject) => {
|
|
1170
|
-
const url = new URL(uploadUrl);
|
|
1171
|
-
const transport = url.protocol === "https:" ? https : http;
|
|
1172
|
-
const req = transport.request(
|
|
1173
|
-
url,
|
|
1808
|
+
const { data: result, idempotencyKey } = await x402Post("/api/tasks", body);
|
|
1809
|
+
const terms = result.terms ?? resolvedTerms;
|
|
1810
|
+
printResult(
|
|
1174
1811
|
{
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
}
|
|
1812
|
+
taskId: result.taskId,
|
|
1813
|
+
terms,
|
|
1814
|
+
termsPreset: termsPresetLabel(terms),
|
|
1815
|
+
...evaluatorStaked ? { evaluatorStake: evaluatorStakeBaseUnits } : {}
|
|
1180
1816
|
},
|
|
1181
|
-
|
|
1182
|
-
const chunks = [];
|
|
1183
|
-
res.on("data", (chunk) => chunks.push(chunk));
|
|
1184
|
-
res.on("end", () => {
|
|
1185
|
-
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
1186
|
-
resolve();
|
|
1187
|
-
} else {
|
|
1188
|
-
const body = Buffer.concat(chunks).toString("utf8").slice(0, 500);
|
|
1189
|
-
reject(
|
|
1190
|
-
new Error(
|
|
1191
|
-
`Upload failed (${res.statusCode ?? "unknown"}): ${body || "no response body"}`
|
|
1192
|
-
)
|
|
1193
|
-
);
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1817
|
+
{ idempotencyKey }
|
|
1197
1818
|
);
|
|
1198
|
-
req.on("error", reject);
|
|
1199
|
-
let uploaded = 0;
|
|
1200
|
-
const stream = Readable.from([data]);
|
|
1201
|
-
stream.on("data", (chunk) => {
|
|
1202
|
-
uploaded += chunk.length;
|
|
1203
|
-
onProgress?.(Math.round(uploaded / data.length * 100));
|
|
1204
|
-
});
|
|
1205
|
-
stream.on("error", reject);
|
|
1206
|
-
stream.pipe(req);
|
|
1207
|
-
});
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
// src/lib/task-sdk.ts
|
|
1211
|
-
async function putWithProgress(upload) {
|
|
1212
|
-
process.stderr.write(` Uploading ${upload.fileName}...
|
|
1213
|
-
`);
|
|
1214
|
-
await putArtifactBytes(upload.uploadUrl, upload.data, upload.mimeType, (percent) => {
|
|
1215
|
-
process.stderr.write(`\r ${upload.fileName}: ${percent}%`);
|
|
1216
|
-
});
|
|
1217
|
-
process.stderr.write("\n");
|
|
1218
|
-
}
|
|
1219
|
-
var cliTaskTransport = {
|
|
1220
|
-
get: (path3, headers) => apiGet(path3, { headers }),
|
|
1221
|
-
// A write the caller gave no key is sent exactly as before the SDK existed, with no options,
|
|
1222
|
-
// so `apiPost` resolves its key itself (explicit, then TASKMARKET_IDEMPOTENCY_KEY, then fresh).
|
|
1223
|
-
post: (path3, body, options) => options === void 0 ? apiPost(path3, body) : apiPost(path3, body, options),
|
|
1224
|
-
feePost: (path3, body, options) => x402FeePost(path3, body, options),
|
|
1225
|
-
put: putWithProgress
|
|
1226
|
-
};
|
|
1227
|
-
function keystoreTaskSigner(keystore) {
|
|
1228
|
-
return {
|
|
1229
|
-
address: keystore.walletAddress,
|
|
1230
|
-
signMessage: (message) => signMessage(message, keystore)
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
function cliTaskReadContext() {
|
|
1234
|
-
return {
|
|
1235
|
-
transport: cliTaskTransport,
|
|
1236
|
-
readAuth: signReadAuth,
|
|
1237
|
-
accessGrantHeaders: taskAccessGrantHeaders
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
function cliTaskWriteContext(keystore) {
|
|
1241
|
-
return { ...cliTaskReadContext(), signer: keystoreTaskSigner(keystore) };
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
// src/sdk/tasks.ts
|
|
1245
|
-
import { promises as fsPromises } from "fs";
|
|
1246
|
-
import { basename } from "path";
|
|
1247
|
-
import { createHash } from "crypto";
|
|
1248
|
-
import { keccak256 } from "viem";
|
|
1249
|
-
var TaskOperationError = class extends Error {
|
|
1250
|
-
code;
|
|
1251
|
-
constructor(code, message) {
|
|
1252
|
-
super(message);
|
|
1253
|
-
this.name = "TaskOperationError";
|
|
1254
|
-
this.code = code;
|
|
1255
|
-
}
|
|
1256
|
-
};
|
|
1257
|
-
function withChainQuery(path3, chainId) {
|
|
1258
|
-
if (chainId === void 0) return path3;
|
|
1259
|
-
return `${path3}${path3.includes("?") ? "&" : "?"}chainId=${chainId}`;
|
|
1260
|
-
}
|
|
1261
|
-
function withChainBody(body, chainId) {
|
|
1262
|
-
return chainId === void 0 ? body : { ...body, chainId };
|
|
1263
|
-
}
|
|
1264
|
-
function writeOptions(idempotencyKey) {
|
|
1265
|
-
return idempotencyKey === void 0 ? void 0 : { idempotencyKey };
|
|
1266
|
-
}
|
|
1267
|
-
async function readAuthHeaders(ctx) {
|
|
1268
|
-
return (await ctx.readAuth?.())?.headers ?? {};
|
|
1269
|
-
}
|
|
1270
|
-
async function getTask(ctx, ref) {
|
|
1271
|
-
const headers = {
|
|
1272
|
-
...await readAuthHeaders(ctx),
|
|
1273
|
-
...await ctx.accessGrantHeaders?.(ref.taskId) ?? {}
|
|
1274
|
-
};
|
|
1275
|
-
const task = await ctx.transport.get(
|
|
1276
|
-
withChainQuery(`/api/tasks/${ref.taskId}`, ref.chainId),
|
|
1277
|
-
headers
|
|
1278
|
-
);
|
|
1279
|
-
return task ?? null;
|
|
1280
|
-
}
|
|
1281
|
-
async function listTasks(ctx, filter = {}) {
|
|
1282
|
-
const params = new URLSearchParams();
|
|
1283
|
-
if (filter.status) params.set("status", filter.status);
|
|
1284
|
-
if (filter.phase) params.set("phase", filter.phase);
|
|
1285
|
-
if (filter.mode) params.set("mode", filter.mode);
|
|
1286
|
-
if (filter.auctionType) params.set("auctionType", filter.auctionType);
|
|
1287
|
-
if (filter.tags) params.set("tags", filter.tags);
|
|
1288
|
-
if (filter.minReward) params.set("minReward", filter.minReward);
|
|
1289
|
-
if (filter.maxReward) params.set("maxReward", filter.maxReward);
|
|
1290
|
-
if (filter.deadlineHours) params.set("deadlineHours", filter.deadlineHours);
|
|
1291
|
-
if (filter.limit) params.set("limit", filter.limit);
|
|
1292
|
-
if (filter.cursor) params.set("cursor", filter.cursor);
|
|
1293
|
-
const result = await ctx.transport.get(
|
|
1294
|
-
`/api/tasks?${params.toString()}`,
|
|
1295
|
-
await readAuthHeaders(ctx)
|
|
1296
|
-
);
|
|
1297
|
-
return { tasks: result.tasks, hasMore: result.hasMore, nextCursor: result.nextCursor };
|
|
1298
|
-
}
|
|
1299
|
-
async function listTaskSubmissions(ctx, ref) {
|
|
1300
|
-
const headers = await readAuthHeaders(ctx);
|
|
1301
|
-
return await ctx.transport.get(
|
|
1302
|
-
withChainQuery(`/api/tasks/${ref.taskId}/submissions`, ref.chainId),
|
|
1303
|
-
headers
|
|
1304
|
-
);
|
|
1305
|
-
}
|
|
1306
|
-
async function listWorkerSubmissions(ctx, options = {}) {
|
|
1307
|
-
const auth = await ctx.readAuth?.();
|
|
1308
|
-
const address = options.address ?? auth?.walletAddress;
|
|
1309
|
-
if (!address) {
|
|
1310
|
-
throw new TaskOperationError(
|
|
1311
|
-
"no_address",
|
|
1312
|
-
"No worker address was given and there is no reading wallet to default to"
|
|
1313
|
-
);
|
|
1314
|
-
}
|
|
1315
|
-
return ctx.transport.get(`/api/submissions/mine?workerAddress=${encodeURIComponent(address)}`, {
|
|
1316
|
-
...auth?.headers ?? {}
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
async function claimTask(ctx, ref, options = {}) {
|
|
1320
|
-
const signature = await ctx.signer.signMessage(buildClaimMessage(ref.taskId));
|
|
1321
|
-
const { data, idempotencyKey } = await ctx.transport.post(
|
|
1322
|
-
`/api/tasks/${ref.taskId}/claim`,
|
|
1323
|
-
withChainBody({ workerAddress: ctx.signer.address, signature }, ref.chainId),
|
|
1324
|
-
writeOptions(options.idempotencyKey)
|
|
1325
|
-
);
|
|
1326
|
-
return { claimId: data.claimId, idempotencyKey };
|
|
1327
|
-
}
|
|
1328
|
-
async function authorizeUploads(ctx, ref) {
|
|
1329
|
-
return { signature: await ctx.signer.signMessage(buildSubmitMessage(ref.taskId)) };
|
|
1330
|
-
}
|
|
1331
|
-
async function readArtifactFile(file) {
|
|
1332
|
-
const fileName = file.fileName ?? basename(file.path);
|
|
1333
|
-
const data = await fsPromises.readFile(file.path);
|
|
1334
|
-
if (data.length === 0) {
|
|
1335
|
-
throw new TaskOperationError("empty_artifact", `File is empty: ${fileName}`);
|
|
1336
|
-
}
|
|
1337
|
-
return {
|
|
1338
|
-
data,
|
|
1339
|
-
artifact: {
|
|
1340
|
-
fileName,
|
|
1341
|
-
mimeType: file.mimeType ?? mimeTypeForPath(file.path),
|
|
1342
|
-
role: file.role,
|
|
1343
|
-
sizeBytes: data.length,
|
|
1344
|
-
sha256Hash: createHash("sha256").update(data).digest("hex"),
|
|
1345
|
-
keccak256Hash: keccak256(new Uint8Array(data))
|
|
1346
|
-
}
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
async function requestArtifactUpload(ctx, ref, artifact, authorization) {
|
|
1350
|
-
const {
|
|
1351
|
-
data: { uploadUrl, artifactKey }
|
|
1352
|
-
} = await ctx.transport.post(
|
|
1353
|
-
`/api/tasks/${ref.taskId}/submissions/request-upload-url`,
|
|
1354
|
-
withChainBody(
|
|
1355
|
-
{
|
|
1356
|
-
taskId: ref.taskId,
|
|
1357
|
-
workerAddress: ctx.signer.address,
|
|
1358
|
-
signature: authorization.signature,
|
|
1359
|
-
fileName: artifact.fileName,
|
|
1360
|
-
mimeType: artifact.mimeType,
|
|
1361
|
-
role: artifact.role,
|
|
1362
|
-
sizeBytes: artifact.sizeBytes
|
|
1363
|
-
},
|
|
1364
|
-
ref.chainId
|
|
1365
|
-
)
|
|
1366
|
-
);
|
|
1367
|
-
return { uploadUrl, artifactKey };
|
|
1368
|
-
}
|
|
1369
|
-
async function uploadArtifact(ctx, ref, file, authorization) {
|
|
1370
|
-
const { data, artifact } = await readArtifactFile(file);
|
|
1371
|
-
const { uploadUrl, artifactKey } = await requestArtifactUpload(ctx, ref, artifact, authorization);
|
|
1372
|
-
await ctx.transport.put({
|
|
1373
|
-
uploadUrl,
|
|
1374
|
-
data,
|
|
1375
|
-
mimeType: artifact.mimeType,
|
|
1376
|
-
fileName: artifact.fileName
|
|
1377
|
-
});
|
|
1378
|
-
return { artifactKey, ...artifact };
|
|
1379
|
-
}
|
|
1380
|
-
async function submitUploadedArtifacts(ctx, ref, artifacts, options = {}) {
|
|
1381
|
-
if (artifacts.length === 0) {
|
|
1382
|
-
throw new TaskOperationError("no_artifacts", "At least one artifact is required");
|
|
1383
|
-
}
|
|
1384
|
-
const signature = await ctx.signer.signMessage(
|
|
1385
|
-
buildSubmitMessage(
|
|
1386
|
-
ref.taskId,
|
|
1387
|
-
artifacts.map((artifact) => artifact.artifactKey)
|
|
1388
|
-
)
|
|
1389
|
-
);
|
|
1390
|
-
const { data, idempotencyKey } = await ctx.transport.feePost(
|
|
1391
|
-
`/api/tasks/${ref.taskId}/submissions/from-keys`,
|
|
1392
|
-
withChainBody(
|
|
1393
|
-
{
|
|
1394
|
-
taskId: ref.taskId,
|
|
1395
|
-
workerAddress: ctx.signer.address,
|
|
1396
|
-
artifacts,
|
|
1397
|
-
signature
|
|
1398
|
-
},
|
|
1399
|
-
ref.chainId
|
|
1400
|
-
),
|
|
1401
|
-
options
|
|
1402
|
-
);
|
|
1403
|
-
return { submissionId: data.submissionId, idempotencyKey };
|
|
1404
|
-
}
|
|
1405
|
-
async function submitTaskFiles(ctx, ref, files, options = {}) {
|
|
1406
|
-
if (files.length === 0) {
|
|
1407
|
-
throw new TaskOperationError("no_artifacts", "At least one file is required");
|
|
1408
1819
|
}
|
|
1409
|
-
|
|
1410
|
-
const artifacts = await Promise.all(
|
|
1411
|
-
files.map((file) => uploadArtifact(ctx, ref, file, authorization))
|
|
1412
|
-
);
|
|
1413
|
-
return submitUploadedArtifacts(ctx, ref, artifacts, options);
|
|
1414
|
-
}
|
|
1820
|
+
);
|
|
1415
1821
|
|
|
1416
1822
|
// src/commands/task/search.ts
|
|
1417
|
-
|
|
1823
|
+
import { Command as Command8 } from "commander";
|
|
1824
|
+
var listCmd = new Command8("list").alias("search").description("List available tasks").option("--status <status>", "Filter by status (e.g. open)", "open").option(
|
|
1418
1825
|
"--phase <phase>",
|
|
1419
1826
|
"Filter by derived lifecycle phase (active, in_review, awaiting_settlement, resolved) -- independent of --status, e.g. --phase awaiting_settlement finds tasks whose deadline has passed but are still open/claimed/worker_selected"
|
|
1420
1827
|
).option("--mode <mode>", "Filter by mode (bounty, claim, pitch, benchmark, auction)").option(
|
|
@@ -1440,8 +1847,8 @@ var listCmd = new Command7("list").alias("search").description("List available t
|
|
|
1440
1847
|
);
|
|
1441
1848
|
|
|
1442
1849
|
// src/commands/task/get.ts
|
|
1443
|
-
import { Command as
|
|
1444
|
-
var getCmd = new
|
|
1850
|
+
import { Command as Command9 } from "commander";
|
|
1851
|
+
var getCmd = new Command9("get").description("Get task details").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1445
1852
|
const task = await getTask(cliTaskReadContext(), { taskId });
|
|
1446
1853
|
if (!task) {
|
|
1447
1854
|
printError(
|
|
@@ -1449,16 +1856,24 @@ var getCmd = new Command8("get").description("Get task details").argument("<task
|
|
|
1449
1856
|
);
|
|
1450
1857
|
return;
|
|
1451
1858
|
}
|
|
1452
|
-
printResult(task);
|
|
1859
|
+
printResult({ ...task, ...await termsAmountsAndDeadlines(taskId) });
|
|
1453
1860
|
});
|
|
1861
|
+
async function termsAmountsAndDeadlines(taskId) {
|
|
1862
|
+
try {
|
|
1863
|
+
const detail = await getTaskTerms(cliTaskReadContext(), { taskId });
|
|
1864
|
+
return detail ? { termsAmounts: detail.amounts, termsDeadlines: detail.deadlines } : {};
|
|
1865
|
+
} catch {
|
|
1866
|
+
return {};
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1454
1869
|
|
|
1455
1870
|
// src/commands/task/submit.ts
|
|
1456
|
-
import { Command as
|
|
1871
|
+
import { Command as Command10, Option as Option2 } from "commander";
|
|
1457
1872
|
function collectFile(value, previous) {
|
|
1458
1873
|
return [...previous, value];
|
|
1459
1874
|
}
|
|
1460
|
-
var submitCmd = new
|
|
1461
|
-
new
|
|
1875
|
+
var submitCmd = new Command10("submit").description("Submit work for a task").argument("<taskId>", "Task ID (0x-prefixed hex)").option("--file <path>", "Path to a submission file (repeatable)", collectFile, []).addOption(
|
|
1876
|
+
new Option2("--role <role>", "Artifact role applied to all files").choices(["preview", "source", "final", "attachment"]).default("attachment")
|
|
1462
1877
|
).action(async (taskId, opts) => {
|
|
1463
1878
|
try {
|
|
1464
1879
|
if (!opts.file || opts.file.length === 0) {
|
|
@@ -1480,8 +1895,53 @@ var submitCmd = new Command9("submit").description("Submit work for a task").arg
|
|
|
1480
1895
|
});
|
|
1481
1896
|
|
|
1482
1897
|
// src/commands/task/accept.ts
|
|
1483
|
-
import { Command as
|
|
1484
|
-
|
|
1898
|
+
import { Command as Command11 } from "commander";
|
|
1899
|
+
|
|
1900
|
+
// src/lib/recording.ts
|
|
1901
|
+
var RECORDING_POLL_INTERVAL_MS = 3e3;
|
|
1902
|
+
var RECORDING_POLL_TIMEOUT_MS = 75e3;
|
|
1903
|
+
var sleepFor = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1904
|
+
async function settleRecording(data, idempotencyKey, options = {}) {
|
|
1905
|
+
if (!isRecordingPendingResponse(data)) return {};
|
|
1906
|
+
const { txHash, intentId } = data;
|
|
1907
|
+
const intervalMs = options.intervalMs ?? RECORDING_POLL_INTERVAL_MS;
|
|
1908
|
+
const timeoutMs = options.timeoutMs ?? RECORDING_POLL_TIMEOUT_MS;
|
|
1909
|
+
const sleep4 = options.sleep ?? sleepFor;
|
|
1910
|
+
const now = options.now ?? Date.now;
|
|
1911
|
+
const log = options.log ?? ((line) => process.stderr.write(`${line}
|
|
1912
|
+
`));
|
|
1913
|
+
log(
|
|
1914
|
+
`Transaction ${txHash ?? "(unknown)"} is confirmed on chain; recording it is pending. Waiting up to ${Math.round(timeoutMs / 1e3)}s for the backend to record it...`
|
|
1915
|
+
);
|
|
1916
|
+
const headers = (await signReadAuth())?.headers ?? {};
|
|
1917
|
+
const path3 = `/api/intents?idempotencyKey=${encodeURIComponent(idempotencyKey)}`;
|
|
1918
|
+
const deadline = now() + timeoutMs;
|
|
1919
|
+
while (now() < deadline) {
|
|
1920
|
+
await sleep4(intervalMs);
|
|
1921
|
+
let intent;
|
|
1922
|
+
try {
|
|
1923
|
+
intent = IntentStatusResponseSchema.safeParse(await apiGet(path3, { headers }));
|
|
1924
|
+
} catch {
|
|
1925
|
+
continue;
|
|
1926
|
+
}
|
|
1927
|
+
if (!intent.success) continue;
|
|
1928
|
+
if (intent.data.status === "completed") return { status: "recorded" };
|
|
1929
|
+
if (intent.data.status === "failed") {
|
|
1930
|
+
throw new Error(
|
|
1931
|
+
`Transaction ${txHash ?? "(unknown)"} confirmed, but the backend marked the write failed: ${intent.data.terminalReason ?? "no reason recorded"}`
|
|
1932
|
+
);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
return {
|
|
1936
|
+
status: "recording_pending",
|
|
1937
|
+
...txHash !== void 0 ? { txHash } : {},
|
|
1938
|
+
...intentId !== void 0 ? { intentId } : {},
|
|
1939
|
+
nextStep: `The transaction is confirmed on chain and the backend retries the recording automatically. Do not re-run this command; check later with GET /api/intents?idempotencyKey=${idempotencyKey}.`
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
// src/commands/task/accept.ts
|
|
1944
|
+
var acceptCmd = new Command11("accept").description("Accept a submission (costs 0.001 in the payment token)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <addr>", "Worker wallet address").action(async (taskId, opts) => {
|
|
1485
1945
|
const task = await getTask(cliTaskReadContext(), { taskId });
|
|
1486
1946
|
if (!task) {
|
|
1487
1947
|
printError(
|
|
@@ -1500,19 +1960,22 @@ var acceptCmd = new Command10("accept").description("Accept a submission (costs
|
|
|
1500
1960
|
(a) => a.action === "select_worker" && a.role === "requester"
|
|
1501
1961
|
);
|
|
1502
1962
|
printError(
|
|
1503
|
-
hasRefund ? "Task has expired
|
|
1963
|
+
hasRefund ? "Task has expired and can no longer be accepted. 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."
|
|
1504
1964
|
);
|
|
1505
1965
|
return;
|
|
1506
1966
|
}
|
|
1507
|
-
const { idempotencyKey } = await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
1967
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/accept`, {
|
|
1508
1968
|
taskId,
|
|
1509
1969
|
worker: opts.worker
|
|
1510
1970
|
});
|
|
1511
|
-
printResult(
|
|
1971
|
+
printResult(
|
|
1972
|
+
{ accepted: true, ...await settleRecording(result, idempotencyKey) },
|
|
1973
|
+
{ idempotencyKey }
|
|
1974
|
+
);
|
|
1512
1975
|
});
|
|
1513
1976
|
|
|
1514
1977
|
// src/commands/task/accept-submissions.ts
|
|
1515
|
-
import { Command as
|
|
1978
|
+
import { Command as Command12 } from "commander";
|
|
1516
1979
|
function parseWinner(spec) {
|
|
1517
1980
|
const parts = spec.split(":");
|
|
1518
1981
|
if (parts.length < 2 || parts.length > 3) {
|
|
@@ -1531,7 +1994,7 @@ function parseWinner(spec) {
|
|
|
1531
1994
|
const submissionId = submissionIdStr ? submissionIdStr : void 0;
|
|
1532
1995
|
return { worker, share, ...submissionId !== void 0 && { submissionId } };
|
|
1533
1996
|
}
|
|
1534
|
-
var acceptSubmissionsCmd = new
|
|
1997
|
+
var acceptSubmissionsCmd = new Command12("accept-submissions").description(
|
|
1535
1998
|
"Accept N submissions for a Bounty/Benchmark task with explicit share basis points (costs 0.001 in the payment token).\nShares must sum to 10000. The contract resolves each deliverable from on-chain submission history.\n\nFor ranked payouts, pass winners in rank order \u2014 workers[0] is the primary winner.\n\nTo pin a specific submission version, append the submission ID as a third field.\n\nExamples:\n task accept-submissions 0x\u2026 --winner 0xAlice:5000 --winner 0xBob:3000 --winner 0xCarol:2000\n task accept-submissions 0x\u2026 --winner 0xAlice:5000:sub_abc123 --winner 0xBob:5000:sub_def456"
|
|
1536
1999
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption(
|
|
1537
2000
|
"--winner <spec...>",
|
|
@@ -1550,15 +2013,22 @@ var acceptSubmissionsCmd = new Command11("accept-submissions").description(
|
|
|
1550
2013
|
winners
|
|
1551
2014
|
}
|
|
1552
2015
|
);
|
|
1553
|
-
printResult(
|
|
2016
|
+
printResult(
|
|
2017
|
+
{
|
|
2018
|
+
accepted: result.success,
|
|
2019
|
+
winners: winners.length,
|
|
2020
|
+
...await settleRecording(result, idempotencyKey)
|
|
2021
|
+
},
|
|
2022
|
+
{ idempotencyKey }
|
|
2023
|
+
);
|
|
1554
2024
|
} catch (err) {
|
|
1555
2025
|
renderFailure(err);
|
|
1556
2026
|
}
|
|
1557
2027
|
});
|
|
1558
2028
|
|
|
1559
2029
|
// src/commands/task/rate.ts
|
|
1560
|
-
import { Command as
|
|
1561
|
-
var rateCmd = new
|
|
2030
|
+
import { Command as Command13 } from "commander";
|
|
2031
|
+
var rateCmd = new Command13("rate").description("Rate a worker (costs 0.001 in the payment token)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <addr>", "Worker wallet address").requiredOption("--rating <n>", "Rating 0-100").option("--feedback <text>", "Optional feedback text").action(async (taskId, opts) => {
|
|
1562
2032
|
const rating = parseInt(opts.rating, 10);
|
|
1563
2033
|
if (rating < 0 || rating > 100) {
|
|
1564
2034
|
printError("Rating must be between 0 and 100");
|
|
@@ -1570,24 +2040,92 @@ var rateCmd = new Command12("rate").description("Rate a worker (costs 0.001 in t
|
|
|
1570
2040
|
rating,
|
|
1571
2041
|
...opts.feedback ? { feedbackText: opts.feedback } : {}
|
|
1572
2042
|
});
|
|
1573
|
-
printResult(
|
|
2043
|
+
printResult(
|
|
2044
|
+
{ feedbackId: result.feedbackId, ...await settleRecording(result, idempotencyKey) },
|
|
2045
|
+
{ idempotencyKey }
|
|
2046
|
+
);
|
|
1574
2047
|
});
|
|
1575
2048
|
|
|
1576
2049
|
// src/commands/task/claim.ts
|
|
1577
|
-
import { Command as
|
|
1578
|
-
|
|
2050
|
+
import { Command as Command14 } from "commander";
|
|
2051
|
+
|
|
2052
|
+
// src/lib/stake-confirmation.ts
|
|
2053
|
+
async function confirmStakeTerms(action, taskId, yes) {
|
|
2054
|
+
if (yes) return true;
|
|
2055
|
+
let detail;
|
|
2056
|
+
try {
|
|
2057
|
+
detail = await getTaskTerms(cliTaskReadContext(), { taskId });
|
|
2058
|
+
} catch {
|
|
2059
|
+
return true;
|
|
2060
|
+
}
|
|
2061
|
+
if (!detail?.terms.stakeRequired) return true;
|
|
2062
|
+
if (detail.amounts.enforcedStakeAmount === "0") return true;
|
|
2063
|
+
const stakeAmount = detail.amounts.enforcedStakeAmount ?? detail.amounts.stakeAmount;
|
|
2064
|
+
renderFailure(
|
|
2065
|
+
new Error(
|
|
2066
|
+
`This task requires a stake of ${stakeAmount} base units (${detail.terms.stakeBps} bps of the reward) to ${action}. Review the terms, then re-run with --yes to accept them.`
|
|
2067
|
+
),
|
|
2068
|
+
{
|
|
2069
|
+
details: {
|
|
2070
|
+
code: "stake_confirmation_required",
|
|
2071
|
+
terms: detail.terms,
|
|
2072
|
+
amounts: detail.amounts,
|
|
2073
|
+
deadlines: detail.deadlines
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
);
|
|
2077
|
+
return false;
|
|
2078
|
+
}
|
|
2079
|
+
async function confirmStakeAffordable(address, stake) {
|
|
2080
|
+
if (stake <= 0n) return true;
|
|
2081
|
+
let balance;
|
|
2082
|
+
try {
|
|
2083
|
+
const result = await apiGet(
|
|
2084
|
+
`/api/wallet/balance?address=${address}&chainId=${selectedNetwork().chainId}`
|
|
2085
|
+
);
|
|
2086
|
+
if (typeof result?.balanceBaseUnits !== "string") return true;
|
|
2087
|
+
balance = BigInt(result.balanceBaseUnits);
|
|
2088
|
+
} catch {
|
|
2089
|
+
return true;
|
|
2090
|
+
}
|
|
2091
|
+
if (balance >= stake) return true;
|
|
2092
|
+
renderFailure(
|
|
2093
|
+
new Error(
|
|
2094
|
+
`This claim needs a stake of ${stake} base units, and the wallet holds ${balance}. Fund the wallet (taskmarket deposit), then claim again.`
|
|
2095
|
+
),
|
|
2096
|
+
{
|
|
2097
|
+
details: {
|
|
2098
|
+
code: "stake_balance_short",
|
|
2099
|
+
stakeAmount: stake.toString(),
|
|
2100
|
+
balance: balance.toString()
|
|
2101
|
+
}
|
|
2102
|
+
}
|
|
2103
|
+
);
|
|
2104
|
+
return false;
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
// src/commands/task/claim.ts
|
|
2108
|
+
var claimCmd = new Command14("claim").description("Claim a task as a worker").argument("<taskId>", "Task ID (0x-prefixed hex)").option("--yes", "Accept the task's settlement terms, including paying any required stake").action(async (taskId, opts) => {
|
|
2109
|
+
if (!await confirmStakeTerms("claim", taskId, opts.yes)) return;
|
|
2110
|
+
const task = await getTask(cliTaskReadContext(), { taskId });
|
|
2111
|
+
const stake = task ? claimStakeToPost(task) : 0n;
|
|
1579
2112
|
const keystore = await loadKeystore();
|
|
2113
|
+
if (!await confirmStakeAffordable(keystore.walletAddress, stake)) return;
|
|
1580
2114
|
const { claimId, idempotencyKey } = await claimTask(cliTaskWriteContext(keystore), { taskId });
|
|
1581
|
-
printResult(
|
|
2115
|
+
printResult(
|
|
2116
|
+
{ claimId, ...stake > 0n ? { stake: stake.toString() } : {} },
|
|
2117
|
+
{ idempotencyKey }
|
|
2118
|
+
);
|
|
1582
2119
|
});
|
|
1583
2120
|
|
|
1584
2121
|
// src/commands/task/pitch.ts
|
|
1585
|
-
import { Command as
|
|
1586
|
-
var pitchCmd = new
|
|
2122
|
+
import { Command as Command15 } from "commander";
|
|
2123
|
+
var pitchCmd = new Command15("pitch").description(
|
|
1587
2124
|
"Submit a pitch for a task (costs 0.001 in the payment token, anchors hash on-chain)"
|
|
1588
|
-
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--text <text>", "Pitch text").option("--duration <hours>", "Estimated duration in hours").action(async (taskId, opts) => {
|
|
2125
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--text <text>", "Pitch text").option("--duration <hours>", "Estimated duration in hours").option("--yes", "Accept the task's settlement terms, including any required stake").action(async (taskId, opts) => {
|
|
2126
|
+
if (!await confirmStakeTerms("pitch", taskId, opts.yes)) return;
|
|
1589
2127
|
const keystore = await loadKeystore();
|
|
1590
|
-
const signature = await signMessage(
|
|
2128
|
+
const signature = await signMessage(buildPitchMessage(taskId), keystore);
|
|
1591
2129
|
const { data: result, idempotencyKey } = await x402Post(
|
|
1592
2130
|
`/api/tasks/${taskId}/pitches`,
|
|
1593
2131
|
{
|
|
@@ -1602,8 +2140,8 @@ var pitchCmd = new Command14("pitch").description(
|
|
|
1602
2140
|
});
|
|
1603
2141
|
|
|
1604
2142
|
// src/commands/task/pitches.ts
|
|
1605
|
-
import { Command as
|
|
1606
|
-
var pitchesCmd = new
|
|
2143
|
+
import { Command as Command16 } from "commander";
|
|
2144
|
+
var pitchesCmd = new Command16("pitches").description("List pitches for a task").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1607
2145
|
try {
|
|
1608
2146
|
const auth = await signReadAuth();
|
|
1609
2147
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
@@ -1614,25 +2152,28 @@ var pitchesCmd = new Command15("pitches").description("List pitches for a task")
|
|
|
1614
2152
|
});
|
|
1615
2153
|
|
|
1616
2154
|
// src/commands/task/select-worker.ts
|
|
1617
|
-
import { Command as
|
|
1618
|
-
var selectWorkerCmd = new
|
|
2155
|
+
import { Command as Command17 } from "commander";
|
|
2156
|
+
var selectWorkerCmd = new Command17("select-worker").description("Select a worker from pitches (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--pitch <pitchId>", "Pitch ID to select").requiredOption("--worker <address>", "Worker wallet address to assign").action(async (taskId, opts) => {
|
|
1619
2157
|
const keystore = await loadKeystore();
|
|
1620
2158
|
const message = buildSelectWorkerMessage(taskId, opts.pitch, opts.worker);
|
|
1621
2159
|
const signature = await signMessage(message, keystore);
|
|
1622
|
-
const { idempotencyKey } = await x402Post(`/api/tasks/${taskId}/pitches/select`, {
|
|
2160
|
+
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/pitches/select`, {
|
|
1623
2161
|
taskId,
|
|
1624
2162
|
pitchId: opts.pitch,
|
|
1625
2163
|
workerAddress: opts.worker,
|
|
1626
2164
|
signature
|
|
1627
2165
|
});
|
|
1628
|
-
printResult(
|
|
2166
|
+
printResult(
|
|
2167
|
+
{ selected: true, ...await settleRecording(result, idempotencyKey) },
|
|
2168
|
+
{ idempotencyKey }
|
|
2169
|
+
);
|
|
1629
2170
|
});
|
|
1630
2171
|
|
|
1631
2172
|
// src/commands/task/proof.ts
|
|
1632
|
-
import { Command as
|
|
1633
|
-
var proofCmd = new
|
|
2173
|
+
import { Command as Command18 } from "commander";
|
|
2174
|
+
var proofCmd = new Command18("proof").description("Submit a benchmark proof (costs 0.001 in the payment token, 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) => {
|
|
1634
2175
|
const keystore = await loadKeystore();
|
|
1635
|
-
const signature = await signMessage(
|
|
2176
|
+
const signature = await signMessage(buildProofMessage(taskId), keystore);
|
|
1636
2177
|
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/proofs`, {
|
|
1637
2178
|
taskId,
|
|
1638
2179
|
workerAddress: keystore.walletAddress,
|
|
@@ -1645,8 +2186,8 @@ var proofCmd = new Command17("proof").description("Submit a benchmark proof (cos
|
|
|
1645
2186
|
});
|
|
1646
2187
|
|
|
1647
2188
|
// src/commands/task/proofs.ts
|
|
1648
|
-
import { Command as
|
|
1649
|
-
var proofsCmd = new
|
|
2189
|
+
import { Command as Command19 } from "commander";
|
|
2190
|
+
var proofsCmd = new Command19("proofs").description("List proofs for a benchmark task").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1650
2191
|
try {
|
|
1651
2192
|
const auth = await signReadAuth();
|
|
1652
2193
|
const headers = { ...auth?.headers ?? {}, ...await taskAccessGrantHeaders(taskId) };
|
|
@@ -1657,8 +2198,8 @@ var proofsCmd = new Command18("proofs").description("List proofs for a benchmark
|
|
|
1657
2198
|
});
|
|
1658
2199
|
|
|
1659
2200
|
// src/commands/task/bid.ts
|
|
1660
|
-
import { Command as
|
|
1661
|
-
var bidCmd = new
|
|
2201
|
+
import { Command as Command20 } from "commander";
|
|
2202
|
+
var bidCmd = new Command20("bid").description("Submit a bid on an auction task").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--price <amount>", "Bid price in the payment token (e.g. 3 or 1.5)").option("--yes", "Accept the task's settlement terms, including any required stake").action(async (taskId, opts) => {
|
|
1662
2203
|
let priceBaseUnits;
|
|
1663
2204
|
try {
|
|
1664
2205
|
priceBaseUnits = usdcToBaseUnits(opts.price);
|
|
@@ -1666,6 +2207,7 @@ var bidCmd = new Command19("bid").description("Submit a bid on an auction task")
|
|
|
1666
2207
|
renderFailure(withErrorContext(err, "Invalid --price"));
|
|
1667
2208
|
return;
|
|
1668
2209
|
}
|
|
2210
|
+
if (!await confirmStakeTerms("bid", taskId, opts.yes)) return;
|
|
1669
2211
|
const { data: result, idempotencyKey } = await x402Post(
|
|
1670
2212
|
`/api/tasks/${taskId}/bids`,
|
|
1671
2213
|
{
|
|
@@ -1677,8 +2219,8 @@ var bidCmd = new Command19("bid").description("Submit a bid on an auction task")
|
|
|
1677
2219
|
});
|
|
1678
2220
|
|
|
1679
2221
|
// src/commands/task/auction-accept.ts
|
|
1680
|
-
import { Command as
|
|
1681
|
-
var auctionAcceptCmd = new
|
|
2222
|
+
import { Command as Command21 } from "commander";
|
|
2223
|
+
var auctionAcceptCmd = new Command21("auction-accept").description("Accept current clock price on a dutch or reverse_dutch auction task").argument("<taskId>", "Task ID (0x-prefixed hex)").option(
|
|
1682
2224
|
"--min-price <amount>",
|
|
1683
2225
|
"Reject if current clock price is below this value (price floor guard)"
|
|
1684
2226
|
).action(async (taskId, opts) => {
|
|
@@ -1692,19 +2234,24 @@ var auctionAcceptCmd = new Command20("auction-accept").description("Accept curre
|
|
|
1692
2234
|
}
|
|
1693
2235
|
}
|
|
1694
2236
|
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/bids/accept`, body);
|
|
2237
|
+
const { chainId } = selectedNetwork();
|
|
1695
2238
|
printResult(
|
|
1696
2239
|
{
|
|
1697
2240
|
acceptedPrice: result.acceptedPrice,
|
|
2241
|
+
// Field name kept for scripts; the number is in the selected network's payment token.
|
|
1698
2242
|
acceptedPriceUsdc: formatUsdcBaseUnits(result.acceptedPrice),
|
|
1699
|
-
|
|
2243
|
+
acceptedPriceFormatted: formatPaymentAmount(result.acceptedPrice, chainId),
|
|
2244
|
+
tokenSymbol: paymentTokenSymbol(chainId),
|
|
2245
|
+
workerAddress: result.workerAddress,
|
|
2246
|
+
...await settleRecording(result, idempotencyKey)
|
|
1700
2247
|
},
|
|
1701
2248
|
{ idempotencyKey }
|
|
1702
2249
|
);
|
|
1703
2250
|
});
|
|
1704
2251
|
|
|
1705
2252
|
// src/commands/task/submissions.ts
|
|
1706
|
-
import { Command as
|
|
1707
|
-
var submissionsCmd = new
|
|
2253
|
+
import { Command as Command22 } from "commander";
|
|
2254
|
+
var submissionsCmd = new Command22("submissions").description("List submissions for a task").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1708
2255
|
let subs;
|
|
1709
2256
|
try {
|
|
1710
2257
|
subs = await listTaskSubmissions(cliTaskReadContext(), { taskId });
|
|
@@ -1716,8 +2263,8 @@ var submissionsCmd = new Command21("submissions").description("List submissions
|
|
|
1716
2263
|
});
|
|
1717
2264
|
|
|
1718
2265
|
// src/commands/task/select-winner.ts
|
|
1719
|
-
import { Command as
|
|
1720
|
-
var selectWinnerCmd = new
|
|
2266
|
+
import { Command as Command23 } from "commander";
|
|
2267
|
+
var selectWinnerCmd = new Command23("select-winner").description("Permissionlessly finalize the lowest bidder after the auction deadline").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
1721
2268
|
let result;
|
|
1722
2269
|
let idempotencyKey;
|
|
1723
2270
|
try {
|
|
@@ -1732,13 +2279,32 @@ var selectWinnerCmd = new Command22("select-winner").description("Permissionless
|
|
|
1732
2279
|
printResult(result, { idempotencyKey });
|
|
1733
2280
|
});
|
|
1734
2281
|
|
|
2282
|
+
// src/commands/task/start-review.ts
|
|
2283
|
+
import { Command as Command24 } from "commander";
|
|
2284
|
+
var startReviewCmd = new Command24("start-review").description(
|
|
2285
|
+
"Start the review window on a delivery made before the settlement-terms upgrade that has none yet (anyone may call). Once the window lapses undecided, `task settle` pays the worker."
|
|
2286
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2287
|
+
try {
|
|
2288
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
2289
|
+
`/api/tasks/${taskId}/start-review`,
|
|
2290
|
+
{ taskId }
|
|
2291
|
+
);
|
|
2292
|
+
printResult(
|
|
2293
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2294
|
+
{ idempotencyKey }
|
|
2295
|
+
);
|
|
2296
|
+
} catch (err) {
|
|
2297
|
+
renderFailure(err);
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
2300
|
+
|
|
1735
2301
|
// src/commands/task/download.ts
|
|
1736
|
-
import { Command as
|
|
2302
|
+
import { Command as Command25 } from "commander";
|
|
1737
2303
|
import { writeFileSync } from "fs";
|
|
1738
2304
|
function sanitizeForTerminal(text) {
|
|
1739
2305
|
return text.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
1740
2306
|
}
|
|
1741
|
-
var downloadCmd = new
|
|
2307
|
+
var downloadCmd = new Command25("download").description("Download a submission file (requester or worker)").argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--submission <id>", "Submission ID (from `task submissions`)").option("--artifact <id>", "Artifact ID for multi-artifact submissions").option("--output <path>", "Save to file instead of printing to stdout").action(
|
|
1742
2308
|
async (taskId, opts) => {
|
|
1743
2309
|
const keystore = await loadKeystore();
|
|
1744
2310
|
let presignedUrl;
|
|
@@ -1786,38 +2352,90 @@ var downloadCmd = new Command23("download").description("Download a submission f
|
|
|
1786
2352
|
);
|
|
1787
2353
|
|
|
1788
2354
|
// src/commands/task/cancel.ts
|
|
1789
|
-
import { Command as
|
|
1790
|
-
|
|
2355
|
+
import { Command as Command26 } from "commander";
|
|
2356
|
+
|
|
2357
|
+
// src/lib/decision-window.ts
|
|
2358
|
+
var DECISION_WINDOW_LAPSED_CODE = "decision_window_lapsed";
|
|
2359
|
+
async function decisionWindowLapse(taskId, options) {
|
|
2360
|
+
try {
|
|
2361
|
+
const detail = await getTaskTerms(cliTaskReadContext(), { taskId });
|
|
2362
|
+
if (!detail || detail.chainSupportsTerms !== true) return null;
|
|
2363
|
+
const deadline = detail.deadlines?.decisionDeadline;
|
|
2364
|
+
if (!deadline) return null;
|
|
2365
|
+
if (Date.parse(deadline) > (options.now ?? Date.now())) return null;
|
|
2366
|
+
if (options.requireLiveSubmissions) {
|
|
2367
|
+
const submissions = await apiGet(`/api/tasks/${taskId}/submissions`);
|
|
2368
|
+
if (!Array.isArray(submissions) || !submissions.some((s) => s.rejectedAt == null)) {
|
|
2369
|
+
return null;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
return { decisionDeadline: deadline };
|
|
2373
|
+
} catch {
|
|
2374
|
+
return null;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
function renderDecisionWindowLapsed(action, lapse) {
|
|
2378
|
+
renderFailure(
|
|
2379
|
+
new Error(
|
|
2380
|
+
`The decision window closed at ${lapse.decisionDeadline} with submissions still live: ${action} would revert on chain (DecisionWindowLapsed). Accept a winner to settle the task.`
|
|
2381
|
+
),
|
|
2382
|
+
{ details: { code: DECISION_WINDOW_LAPSED_CODE, decisionDeadline: lapse.decisionDeadline } }
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
// src/commands/task/cancel.ts
|
|
2387
|
+
var cancelCmd = new Command26("cancel").description(
|
|
1791
2388
|
"Cancel an open task and refund the escrowed reward (costs 0.001 in the payment token)"
|
|
1792
2389
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2390
|
+
const lapse = await decisionWindowLapse(taskId, { requireLiveSubmissions: true });
|
|
2391
|
+
if (lapse) {
|
|
2392
|
+
renderDecisionWindowLapsed("cancel", lapse);
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
1793
2395
|
const { data: result, idempotencyKey } = await x402Post(
|
|
1794
2396
|
`/api/tasks/${taskId}/cancel`,
|
|
1795
2397
|
{ taskId }
|
|
1796
2398
|
);
|
|
1797
|
-
printResult(
|
|
2399
|
+
printResult(
|
|
2400
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2401
|
+
{ idempotencyKey }
|
|
2402
|
+
);
|
|
1798
2403
|
});
|
|
1799
2404
|
|
|
1800
2405
|
// src/commands/task/refund-expired.ts
|
|
1801
|
-
import { Command as
|
|
1802
|
-
var refundExpiredCmd = new
|
|
1803
|
-
"Refund an expired task
|
|
2406
|
+
import { Command as Command27 } from "commander";
|
|
2407
|
+
var refundExpiredCmd = new Command27("refund-expired").description(
|
|
2408
|
+
"Refund an expired task back to the requester; bounty and benchmark tasks need every submission rejected first (costs 0.001 in the payment token)"
|
|
1804
2409
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2410
|
+
const lapse = await decisionWindowLapse(taskId, { requireLiveSubmissions: true });
|
|
2411
|
+
if (lapse) {
|
|
2412
|
+
renderDecisionWindowLapsed("refund-expired", lapse);
|
|
2413
|
+
return;
|
|
2414
|
+
}
|
|
1805
2415
|
try {
|
|
1806
2416
|
const { data: result, idempotencyKey } = await x402Post(
|
|
1807
2417
|
`/api/tasks/${taskId}/refund-expired`,
|
|
1808
2418
|
{ taskId }
|
|
1809
2419
|
);
|
|
1810
|
-
printResult(
|
|
2420
|
+
printResult(
|
|
2421
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2422
|
+
{ idempotencyKey }
|
|
2423
|
+
);
|
|
1811
2424
|
} catch (err) {
|
|
1812
2425
|
renderFailure(err);
|
|
1813
2426
|
}
|
|
1814
2427
|
});
|
|
1815
2428
|
|
|
1816
2429
|
// src/commands/task/reject-submission.ts
|
|
1817
|
-
import { Command as
|
|
1818
|
-
var rejectSubmissionCmd = new
|
|
2430
|
+
import { Command as Command28 } from "commander";
|
|
2431
|
+
var rejectSubmissionCmd = new Command28("reject-submission").description(
|
|
1819
2432
|
"Reject a spam or low-quality submission (costs a 0.001 relay fee in the payment token). Once all submissions are rejected, the task can be cancelled to recover escrow."
|
|
1820
2433
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--worker <address>", "Worker address whose submission to reject").action(async (taskId, opts) => {
|
|
2434
|
+
const lapse = await decisionWindowLapse(taskId, { requireLiveSubmissions: false });
|
|
2435
|
+
if (lapse) {
|
|
2436
|
+
renderDecisionWindowLapsed("reject-submission", lapse);
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
1821
2439
|
try {
|
|
1822
2440
|
const { data: result, idempotencyKey } = await x402Post(
|
|
1823
2441
|
`/api/tasks/${taskId}/reject-submission`,
|
|
@@ -1826,14 +2444,17 @@ var rejectSubmissionCmd = new Command26("reject-submission").description(
|
|
|
1826
2444
|
worker: opts.worker
|
|
1827
2445
|
}
|
|
1828
2446
|
);
|
|
1829
|
-
printResult(
|
|
2447
|
+
printResult(
|
|
2448
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2449
|
+
{ idempotencyKey }
|
|
2450
|
+
);
|
|
1830
2451
|
} catch (err) {
|
|
1831
2452
|
renderFailure(err);
|
|
1832
2453
|
}
|
|
1833
2454
|
});
|
|
1834
2455
|
|
|
1835
2456
|
// src/commands/task/reject-all-submissions.ts
|
|
1836
|
-
import { Command as
|
|
2457
|
+
import { Command as Command29 } from "commander";
|
|
1837
2458
|
function activeSubmissionWorkers(submissions) {
|
|
1838
2459
|
const workers = /* @__PURE__ */ new Map();
|
|
1839
2460
|
for (const submission of submissions) {
|
|
@@ -1843,7 +2464,7 @@ function activeSubmissionWorkers(submissions) {
|
|
|
1843
2464
|
}
|
|
1844
2465
|
return [...workers.values()];
|
|
1845
2466
|
}
|
|
1846
|
-
var rejectAllSubmissionsCmd = new
|
|
2467
|
+
var rejectAllSubmissionsCmd = new Command29("reject-all-submissions").description(
|
|
1847
2468
|
"Reject every active submission on a bounty or benchmark task in one go. Lists active submissions, rejects each unique worker in sequence, then cancels the task. Use this to recover escrow when all submitted work is unsuitable."
|
|
1848
2469
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").option("--no-cancel", "Reject all submissions but do not cancel the task afterward").action(async (taskId, opts) => {
|
|
1849
2470
|
let submissions;
|
|
@@ -1858,6 +2479,11 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
1858
2479
|
printResult({ rejected: 0, message: "no active submissions to reject" });
|
|
1859
2480
|
return;
|
|
1860
2481
|
}
|
|
2482
|
+
const lapse = await decisionWindowLapse(taskId, { requireLiveSubmissions: false });
|
|
2483
|
+
if (lapse) {
|
|
2484
|
+
renderDecisionWindowLapsed("reject-all-submissions", lapse);
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
1861
2487
|
const results = [];
|
|
1862
2488
|
for (const worker of workers) {
|
|
1863
2489
|
try {
|
|
@@ -1916,8 +2542,8 @@ var rejectAllSubmissionsCmd = new Command27("reject-all-submissions").descriptio
|
|
|
1916
2542
|
});
|
|
1917
2543
|
|
|
1918
2544
|
// src/commands/task/my-submissions.ts
|
|
1919
|
-
import { Command as
|
|
1920
|
-
var mySubmissionsCmd = new
|
|
2545
|
+
import { Command as Command30 } from "commander";
|
|
2546
|
+
var mySubmissionsCmd = new Command30("my-submissions").description("List all submissions made by your wallet across all tasks.").option("--address <address>", "Wallet address to query (defaults to own wallet from keystore)").action(async (opts) => {
|
|
1921
2547
|
try {
|
|
1922
2548
|
const result = await listWorkerSubmissions(cliTaskReadContext(), { address: opts.address });
|
|
1923
2549
|
printResult(result);
|
|
@@ -1929,8 +2555,8 @@ var mySubmissionsCmd = new Command28("my-submissions").description("List all sub
|
|
|
1929
2555
|
});
|
|
1930
2556
|
|
|
1931
2557
|
// src/commands/task/update.ts
|
|
1932
|
-
import { Command as
|
|
1933
|
-
var updateCmd = new
|
|
2558
|
+
import { Command as Command31 } from "commander";
|
|
2559
|
+
var updateCmd = new Command31("update").description("Update an open task (costs 0.001 plus any reward increase, in the payment token)").argument("<taskId>", "Task ID (0x-prefixed hex)").option("--reward <amount>", 'New reward in the payment token (human units, e.g. "50")').option("--extend-expiry <seconds>", "Extend expiry by this many seconds").option("--bid-deadline <iso>", "New bid deadline (ISO 8601)").option("--pitch-deadline <iso>", "New pitch deadline (ISO 8601)").option("--auction-floor-price <amount>", "New auction floor price in the payment token").option("--auction-start-price <amount>", "New auction start price in the payment token").option("--description <text>", "New description").option("--tags <csv>", "New tags (comma-separated)").option("--metric-description <text>", "New metric description").action(
|
|
1934
2560
|
async (taskId, opts) => {
|
|
1935
2561
|
const body = { taskId };
|
|
1936
2562
|
if (opts.reward !== void 0) {
|
|
@@ -2018,8 +2644,8 @@ var updateCmd = new Command29("update").description("Update an open task (costs
|
|
|
2018
2644
|
);
|
|
2019
2645
|
|
|
2020
2646
|
// src/commands/task/forfeit.ts
|
|
2021
|
-
import { Command as
|
|
2022
|
-
var forfeitCmd = new
|
|
2647
|
+
import { Command as Command32 } from "commander";
|
|
2648
|
+
var forfeitCmd = new Command32("forfeit").description("Reclaim a claim-mode task whose worker's claim has expired (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2023
2649
|
try {
|
|
2024
2650
|
const keystore = await loadKeystore();
|
|
2025
2651
|
const message = buildForfeitMessage(taskId);
|
|
@@ -2032,18 +2658,24 @@ var forfeitCmd = new Command30("forfeit").description("Reclaim a claim-mode task
|
|
|
2032
2658
|
signature
|
|
2033
2659
|
}
|
|
2034
2660
|
);
|
|
2035
|
-
printResult(
|
|
2661
|
+
printResult(
|
|
2662
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2663
|
+
{ idempotencyKey }
|
|
2664
|
+
);
|
|
2036
2665
|
} catch (err) {
|
|
2037
2666
|
renderFailure(err);
|
|
2038
2667
|
}
|
|
2039
2668
|
});
|
|
2040
2669
|
|
|
2041
2670
|
// src/commands/task/assign-evaluator.ts
|
|
2042
|
-
import { Command as
|
|
2671
|
+
import { Command as Command33 } from "commander";
|
|
2043
2672
|
var ADDRESS_PATTERN = /^0x[0-9a-fA-F]{40}$/;
|
|
2044
|
-
var assignEvaluatorCmd = new
|
|
2673
|
+
var assignEvaluatorCmd = new Command33("assign-evaluator").description(
|
|
2045
2674
|
"Assign an evaluator to an open, unclaimed task you requested (costs 0.001 in the payment token). Only possible before a worker claims the task."
|
|
2046
|
-
).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").
|
|
2675
|
+
).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").option(
|
|
2676
|
+
"--evaluator-stake <amount>",
|
|
2677
|
+
"Stake behind the evaluator in the payment token (e.g. 1), paid with the action fee. Requires --yes."
|
|
2678
|
+
).option("--yes", "Confirm paying the evaluator stake", false).action(
|
|
2047
2679
|
async (taskId, opts) => {
|
|
2048
2680
|
if (!ADDRESS_PATTERN.test(opts.evaluator)) {
|
|
2049
2681
|
return void printError(`--evaluator must be a wallet address, got: ${opts.evaluator}`);
|
|
@@ -2053,7 +2685,23 @@ var assignEvaluatorCmd = new Command31("assign-evaluator").description(
|
|
|
2053
2685
|
`--dispute-resolver must be a wallet address, got: ${opts.disputeResolver}`
|
|
2054
2686
|
);
|
|
2055
2687
|
}
|
|
2688
|
+
let evaluatorStake = "0";
|
|
2689
|
+
if (opts.evaluatorStake !== void 0) {
|
|
2690
|
+
try {
|
|
2691
|
+
evaluatorStake = usdcToBaseUnits(opts.evaluatorStake, { allowZero: true });
|
|
2692
|
+
} catch (err) {
|
|
2693
|
+
renderFailure(withErrorContext(err, "Invalid --evaluator-stake"));
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
const staked = BigInt(evaluatorStake) > 0n;
|
|
2698
|
+
if (staked && !opts.yes) {
|
|
2699
|
+
return void printError(
|
|
2700
|
+
`This assignment stakes ${opts.evaluatorStake} (${evaluatorStake} base units) behind the evaluator, paid now with the action fee and forfeitable under the task's terms. Re-run with --yes to confirm.`
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2056
2703
|
const body = { taskId, evaluator: opts.evaluator };
|
|
2704
|
+
if (staked) body.evaluatorStake = evaluatorStake;
|
|
2057
2705
|
if (opts.evaluatorFeeBps !== void 0) {
|
|
2058
2706
|
const bps = Number(opts.evaluatorFeeBps);
|
|
2059
2707
|
if (!Number.isInteger(bps) || bps < 0 || bps > 1e4) {
|
|
@@ -2088,16 +2736,19 @@ var assignEvaluatorCmd = new Command31("assign-evaluator").description(
|
|
|
2088
2736
|
`/api/tasks/${taskId}/evaluator`,
|
|
2089
2737
|
body
|
|
2090
2738
|
);
|
|
2091
|
-
printResult(
|
|
2739
|
+
printResult(
|
|
2740
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
2741
|
+
{ idempotencyKey }
|
|
2742
|
+
);
|
|
2092
2743
|
}
|
|
2093
2744
|
);
|
|
2094
2745
|
|
|
2095
2746
|
// src/commands/task/evaluate.ts
|
|
2096
|
-
import { Command as
|
|
2097
|
-
var evaluateCmd = new
|
|
2747
|
+
import { Command as Command34 } from "commander";
|
|
2748
|
+
var evaluateCmd = new Command34("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(
|
|
2098
2749
|
"--award <worker:amount:rank>",
|
|
2099
2750
|
"Award entry (repeatable): worker:amount:rank",
|
|
2100
|
-
|
|
2751
|
+
collect2,
|
|
2101
2752
|
[]
|
|
2102
2753
|
).action(
|
|
2103
2754
|
async (taskId, opts) => {
|
|
@@ -2149,40 +2800,52 @@ var evaluateCmd = new Command32("evaluate").description("Submit an evaluation ve
|
|
|
2149
2800
|
`/api/tasks/${taskId}/evaluate`,
|
|
2150
2801
|
body
|
|
2151
2802
|
);
|
|
2152
|
-
printResult(
|
|
2803
|
+
printResult(
|
|
2804
|
+
{ txHash: result.txHash, ...await settleRecording(result, idempotencyKey) },
|
|
2805
|
+
{ idempotencyKey }
|
|
2806
|
+
);
|
|
2153
2807
|
}
|
|
2154
2808
|
);
|
|
2155
|
-
function
|
|
2809
|
+
function collect2(val, prev) {
|
|
2156
2810
|
return prev.concat([val]);
|
|
2157
2811
|
}
|
|
2158
2812
|
|
|
2159
2813
|
// src/commands/task/appeal.ts
|
|
2160
|
-
import { Command as
|
|
2161
|
-
var appealCmd = new
|
|
2814
|
+
import { Command as Command35 } from "commander";
|
|
2815
|
+
var appealCmd = new Command35("appeal").description("Appeal an evaluator verdict while in Appealing state").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2162
2816
|
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/appeal`, { taskId });
|
|
2163
|
-
printResult(
|
|
2817
|
+
printResult(
|
|
2818
|
+
{ txHash: result.txHash, ...await settleRecording(result, idempotencyKey) },
|
|
2819
|
+
{ idempotencyKey }
|
|
2820
|
+
);
|
|
2164
2821
|
});
|
|
2165
2822
|
|
|
2166
2823
|
// src/commands/task/evaluator-timeout.ts
|
|
2167
|
-
import { Command as
|
|
2168
|
-
var evaluatorTimeoutCmd = new
|
|
2824
|
+
import { Command as Command36 } from "commander";
|
|
2825
|
+
var evaluatorTimeoutCmd = new Command36("evaluator-timeout").description("Trigger evaluator timeout after the evaluation window expires (anyone)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2169
2826
|
const { data: result, idempotencyKey } = await x402Post(`/api/tasks/${taskId}/evaluator-timeout`, { taskId });
|
|
2170
|
-
printResult(
|
|
2827
|
+
printResult(
|
|
2828
|
+
{ txHash: result.txHash, ...await settleRecording(result, idempotencyKey) },
|
|
2829
|
+
{ idempotencyKey }
|
|
2830
|
+
);
|
|
2171
2831
|
});
|
|
2172
2832
|
|
|
2173
2833
|
// src/commands/task/finalize-verdict.ts
|
|
2174
|
-
import { Command as
|
|
2175
|
-
var finalizeVerdictCmd = new
|
|
2834
|
+
import { Command as Command37 } from "commander";
|
|
2835
|
+
var finalizeVerdictCmd = new Command37("finalize-verdict").description("Finalize an evaluator verdict after the appeal window expires (permissionless)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2176
2836
|
const { data: result, idempotencyKey } = await apiPost(`/api/tasks/${taskId}/finalize-verdict`, { taskId });
|
|
2177
|
-
printResult(
|
|
2837
|
+
printResult(
|
|
2838
|
+
{ txHash: result.txHash, ...await settleRecording(result, idempotencyKey) },
|
|
2839
|
+
{ idempotencyKey }
|
|
2840
|
+
);
|
|
2178
2841
|
});
|
|
2179
2842
|
|
|
2180
2843
|
// src/commands/task/resolve-dispute.ts
|
|
2181
|
-
import { Command as
|
|
2844
|
+
import { Command as Command38 } from "commander";
|
|
2182
2845
|
function parseAward(spec) {
|
|
2183
2846
|
const parts = spec.split(":");
|
|
2184
2847
|
if (parts.length !== 3) {
|
|
2185
|
-
throw new Error(`Invalid --award value "${spec}". Expected <addr>:<
|
|
2848
|
+
throw new Error(`Invalid --award value "${spec}". Expected <addr>:<amount>:<rank>`);
|
|
2186
2849
|
}
|
|
2187
2850
|
const [worker, amountStr, rankStr] = parts;
|
|
2188
2851
|
if (!/^0x[0-9a-fA-F]{40}$/.test(worker)) {
|
|
@@ -2199,11 +2862,11 @@ function parseAward(spec) {
|
|
|
2199
2862
|
rank
|
|
2200
2863
|
};
|
|
2201
2864
|
}
|
|
2202
|
-
var resolveDisputeCmd = new
|
|
2865
|
+
var resolveDisputeCmd = new Command38("resolve-dispute").description(
|
|
2203
2866
|
"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"
|
|
2204
2867
|
).argument("<taskId>", "Task ID (0x-prefixed hex)").requiredOption("--verdict <type>", "Verdict type: approve or partial").requiredOption(
|
|
2205
2868
|
"--award <spec...>",
|
|
2206
|
-
"Award spec <addr>:<
|
|
2869
|
+
"Award spec <addr>:<amount>:<rank>, amount in whole payment tokens (USDC on Base, OUSD on Tempo). Pass multiple times."
|
|
2207
2870
|
).action(async (taskId, opts) => {
|
|
2208
2871
|
if (opts.verdict !== "approve" && opts.verdict !== "partial") {
|
|
2209
2872
|
printError('--verdict must be "approve" or "partial"');
|
|
@@ -2224,12 +2887,15 @@ var resolveDisputeCmd = new Command36("resolve-dispute").description(
|
|
|
2224
2887
|
awards
|
|
2225
2888
|
}
|
|
2226
2889
|
);
|
|
2227
|
-
printResult(
|
|
2890
|
+
printResult(
|
|
2891
|
+
{ txHash: result.txHash, ...await settleRecording(result, idempotencyKey) },
|
|
2892
|
+
{ idempotencyKey }
|
|
2893
|
+
);
|
|
2228
2894
|
});
|
|
2229
2895
|
|
|
2230
2896
|
// src/commands/task/unlock.ts
|
|
2231
|
-
import { Command as
|
|
2232
|
-
var unlockCmd = new
|
|
2897
|
+
import { Command as Command39 } from "commander";
|
|
2898
|
+
var unlockCmd = new Command39("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) => {
|
|
2233
2899
|
let result;
|
|
2234
2900
|
let idempotencyKey;
|
|
2235
2901
|
try {
|
|
@@ -2246,8 +2912,8 @@ var unlockCmd = new Command37("unlock").description("Unlock a private task with
|
|
|
2246
2912
|
});
|
|
2247
2913
|
|
|
2248
2914
|
// src/commands/task/invite.ts
|
|
2249
|
-
import { Command as
|
|
2250
|
-
var inviteCmd = new
|
|
2915
|
+
import { Command as Command40 } from "commander";
|
|
2916
|
+
var inviteCmd = new Command40("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) => {
|
|
2251
2917
|
const auth = await signReadAuth();
|
|
2252
2918
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
2253
2919
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -2266,8 +2932,8 @@ var inviteCmd = new Command38("invite").description("Invite a wallet to view a p
|
|
|
2266
2932
|
});
|
|
2267
2933
|
|
|
2268
2934
|
// src/commands/task/uninvite.ts
|
|
2269
|
-
import { Command as
|
|
2270
|
-
var uninviteCmd = new
|
|
2935
|
+
import { Command as Command41 } from "commander";
|
|
2936
|
+
var uninviteCmd = new Command41("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) => {
|
|
2271
2937
|
const auth = await signReadAuth();
|
|
2272
2938
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
2273
2939
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -2285,8 +2951,8 @@ var uninviteCmd = new Command39("uninvite").description("Remove a wallet from a
|
|
|
2285
2951
|
});
|
|
2286
2952
|
|
|
2287
2953
|
// src/commands/task/viewers.ts
|
|
2288
|
-
import { Command as
|
|
2289
|
-
var viewersCmd = new
|
|
2954
|
+
import { Command as Command42 } from "commander";
|
|
2955
|
+
var viewersCmd = new Command42("viewers").description("List a private task's wallet allowlist (requester only)").argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2290
2956
|
const auth = await signReadAuth();
|
|
2291
2957
|
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
2292
2958
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -2302,49 +2968,174 @@ var viewersCmd = new Command40("viewers").description("List a private task's wal
|
|
|
2302
2968
|
}
|
|
2303
2969
|
});
|
|
2304
2970
|
|
|
2971
|
+
// src/commands/task/terms.ts
|
|
2972
|
+
import { Command as Command43 } from "commander";
|
|
2973
|
+
var termsCmd = new Command43("terms").description(
|
|
2974
|
+
"Show a task's settlement terms: stake, review window, reject fee and outcome, revisions, release cost now and deadlines"
|
|
2975
|
+
).argument("<taskId>", "Task ID (0x-prefixed hex)").action(async (taskId) => {
|
|
2976
|
+
const detail = await getTaskTerms(cliTaskReadContext(), { taskId });
|
|
2977
|
+
if (!detail) {
|
|
2978
|
+
printError(
|
|
2979
|
+
`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>)`
|
|
2980
|
+
);
|
|
2981
|
+
return;
|
|
2982
|
+
}
|
|
2983
|
+
printResult(detail);
|
|
2984
|
+
});
|
|
2985
|
+
|
|
2986
|
+
// src/lib/settlement-action.ts
|
|
2987
|
+
import { Command as Command44 } from "commander";
|
|
2988
|
+
async function readTerms(taskId) {
|
|
2989
|
+
try {
|
|
2990
|
+
return await getTaskTerms(cliTaskReadContext(), { taskId });
|
|
2991
|
+
} catch {
|
|
2992
|
+
return null;
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
async function confirmSettlementAction(name, confirm2, taskId, yes) {
|
|
2996
|
+
if (!confirm2 || yes) return true;
|
|
2997
|
+
const detail = await readTerms(taskId);
|
|
2998
|
+
const termsDetails = detail ? { terms: detail.terms, amounts: detail.amounts, deadlines: detail.deadlines } : {};
|
|
2999
|
+
if (confirm2 === "release-cost") {
|
|
3000
|
+
if (!detail) {
|
|
3001
|
+
renderFailure(
|
|
3002
|
+
new Error(
|
|
3003
|
+
"Could not read the task terms, so the cost of releasing now is unknown. Retry, or re-run with --yes to release whatever it costs."
|
|
3004
|
+
),
|
|
3005
|
+
{ details: { code: "release_terms_unavailable" } }
|
|
3006
|
+
);
|
|
3007
|
+
return false;
|
|
3008
|
+
}
|
|
3009
|
+
if (detail.amounts.enforcedStakeAmount === "0") return true;
|
|
3010
|
+
const cost = detail.amounts.releaseCostNow;
|
|
3011
|
+
if (!cost || BigInt(cost) <= 0n) return true;
|
|
3012
|
+
renderFailure(
|
|
3013
|
+
new Error(
|
|
3014
|
+
`Releasing this claim now forfeits ${cost} base units of the stake. Review the terms, then re-run with --yes to accept the cost.`
|
|
3015
|
+
),
|
|
3016
|
+
{
|
|
3017
|
+
details: { code: "release_confirmation_required", releaseCostNow: cost, ...termsDetails }
|
|
3018
|
+
}
|
|
3019
|
+
);
|
|
3020
|
+
return false;
|
|
3021
|
+
}
|
|
3022
|
+
renderFailure(
|
|
3023
|
+
new Error(
|
|
3024
|
+
`task ${name} cannot be undone. Review the terms, then re-run with --yes to confirm.`
|
|
3025
|
+
),
|
|
3026
|
+
{ details: { code: `${name}_confirmation_required`, ...termsDetails } }
|
|
3027
|
+
);
|
|
3028
|
+
return false;
|
|
3029
|
+
}
|
|
3030
|
+
function settlementActionCommand(spec) {
|
|
3031
|
+
const command = new Command44(spec.name).description(spec.description).argument("<taskId>", "Task ID (0x-prefixed hex)");
|
|
3032
|
+
if (spec.confirm === "release-cost") {
|
|
3033
|
+
command.option("--yes", "Accept the stake forfeited by releasing now (releaseCostNow)");
|
|
3034
|
+
} else if (spec.confirm === "always") {
|
|
3035
|
+
command.option("--yes", "Confirm the action; it cannot be undone");
|
|
3036
|
+
}
|
|
3037
|
+
return command.action(async (taskId, opts) => {
|
|
3038
|
+
try {
|
|
3039
|
+
if (!await confirmSettlementAction(spec.name, spec.confirm, taskId, opts.yes)) return;
|
|
3040
|
+
const keystore = await loadKeystore();
|
|
3041
|
+
const expiresAt = settlementActionRequiresExpiry(spec.kind) ? settlementActionExpiresAt() : void 0;
|
|
3042
|
+
const signature = await signMessage(
|
|
3043
|
+
buildSettlementActionMessage(spec.kind, taskId, expiresAt),
|
|
3044
|
+
keystore
|
|
3045
|
+
);
|
|
3046
|
+
const { data: result, idempotencyKey } = await apiPost(
|
|
3047
|
+
`/api/tasks/${taskId}/${spec.kind}`,
|
|
3048
|
+
{
|
|
3049
|
+
taskId,
|
|
3050
|
+
callerAddress: keystore.walletAddress,
|
|
3051
|
+
signature,
|
|
3052
|
+
...expiresAt === void 0 ? {} : { expiresAt }
|
|
3053
|
+
}
|
|
3054
|
+
);
|
|
3055
|
+
printResult(
|
|
3056
|
+
{ ...result, ...await settleRecording(result, idempotencyKey) },
|
|
3057
|
+
{ idempotencyKey }
|
|
3058
|
+
);
|
|
3059
|
+
} catch (err) {
|
|
3060
|
+
renderFailure(err);
|
|
3061
|
+
}
|
|
3062
|
+
});
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// src/commands/task/settlement-actions.ts
|
|
3066
|
+
var releaseCmd = settlementActionCommand({
|
|
3067
|
+
name: "release",
|
|
3068
|
+
kind: "release",
|
|
3069
|
+
confirm: "release-cost",
|
|
3070
|
+
description: "Hand a claim back before delivering (claim worker only). Free during the grace share of the claim time, then up to the full stake at expiry. Refuses without --yes when releaseCostNow is above zero."
|
|
3071
|
+
});
|
|
3072
|
+
var requestRevisionCmd = settlementActionCommand({
|
|
3073
|
+
name: "request-revision",
|
|
3074
|
+
kind: "request-revision",
|
|
3075
|
+
description: "Send a delivery under review back to the worker for fixes (requester only, while revisions remain)"
|
|
3076
|
+
});
|
|
3077
|
+
var rejectCmd = settlementActionCommand({
|
|
3078
|
+
name: "reject",
|
|
3079
|
+
kind: "reject-delivery",
|
|
3080
|
+
confirm: "always",
|
|
3081
|
+
description: "Reject a delivery under review (requester only). The worker still receives the task's reject fee, and the task reopens or refunds per its reject outcome. This cannot be undone; requires --yes."
|
|
3082
|
+
});
|
|
3083
|
+
var settleCmd = settlementActionCommand({
|
|
3084
|
+
name: "settle",
|
|
3085
|
+
kind: "settle",
|
|
3086
|
+
description: "Pay the worker for a delivery whose review window lapsed with no response (anyone may call)"
|
|
3087
|
+
});
|
|
3088
|
+
|
|
2305
3089
|
// src/commands/task/index.ts
|
|
2306
|
-
var
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
3090
|
+
var taskCommand2 = new Command45("task").description("Manage tasks");
|
|
3091
|
+
taskCommand2.addCommand(createCmd);
|
|
3092
|
+
taskCommand2.addCommand(listCmd);
|
|
3093
|
+
taskCommand2.addCommand(getCmd);
|
|
3094
|
+
taskCommand2.addCommand(submitCmd);
|
|
3095
|
+
taskCommand2.addCommand(acceptCmd);
|
|
3096
|
+
taskCommand2.addCommand(acceptSubmissionsCmd);
|
|
3097
|
+
taskCommand2.addCommand(rateCmd);
|
|
3098
|
+
taskCommand2.addCommand(claimCmd);
|
|
3099
|
+
taskCommand2.addCommand(pitchCmd);
|
|
3100
|
+
taskCommand2.addCommand(pitchesCmd);
|
|
3101
|
+
taskCommand2.addCommand(selectWorkerCmd);
|
|
3102
|
+
taskCommand2.addCommand(proofCmd);
|
|
3103
|
+
taskCommand2.addCommand(proofsCmd);
|
|
3104
|
+
taskCommand2.addCommand(bidCmd);
|
|
3105
|
+
taskCommand2.addCommand(auctionAcceptCmd);
|
|
3106
|
+
taskCommand2.addCommand(submissionsCmd);
|
|
3107
|
+
taskCommand2.addCommand(selectWinnerCmd);
|
|
3108
|
+
taskCommand2.addCommand(downloadCmd);
|
|
3109
|
+
taskCommand2.addCommand(cancelCmd);
|
|
3110
|
+
taskCommand2.addCommand(refundExpiredCmd);
|
|
3111
|
+
taskCommand2.addCommand(rejectSubmissionCmd);
|
|
3112
|
+
taskCommand2.addCommand(rejectAllSubmissionsCmd);
|
|
3113
|
+
taskCommand2.addCommand(mySubmissionsCmd);
|
|
3114
|
+
taskCommand2.addCommand(updateCmd);
|
|
3115
|
+
taskCommand2.addCommand(forfeitCmd);
|
|
3116
|
+
taskCommand2.addCommand(assignEvaluatorCmd);
|
|
3117
|
+
taskCommand2.addCommand(evaluateCmd);
|
|
3118
|
+
taskCommand2.addCommand(appealCmd);
|
|
3119
|
+
taskCommand2.addCommand(evaluatorTimeoutCmd);
|
|
3120
|
+
taskCommand2.addCommand(finalizeVerdictCmd);
|
|
3121
|
+
taskCommand2.addCommand(resolveDisputeCmd);
|
|
3122
|
+
taskCommand2.addCommand(unlockCmd);
|
|
3123
|
+
taskCommand2.addCommand(inviteCmd);
|
|
3124
|
+
taskCommand2.addCommand(uninviteCmd);
|
|
3125
|
+
taskCommand2.addCommand(viewersCmd);
|
|
3126
|
+
taskCommand2.addCommand(termsCmd);
|
|
3127
|
+
taskCommand2.addCommand(releaseCmd);
|
|
3128
|
+
taskCommand2.addCommand(requestRevisionCmd);
|
|
3129
|
+
taskCommand2.addCommand(rejectCmd);
|
|
3130
|
+
taskCommand2.addCommand(settleCmd);
|
|
3131
|
+
taskCommand2.addCommand(reviewCmd);
|
|
3132
|
+
taskCommand2.addCommand(startReviewCmd);
|
|
2342
3133
|
|
|
2343
3134
|
// src/commands/agent/index.ts
|
|
2344
|
-
import { Command as
|
|
3135
|
+
import { Command as Command48, Option as Option3 } from "commander";
|
|
2345
3136
|
|
|
2346
3137
|
// src/commands/agent/credits.ts
|
|
2347
|
-
import { Command as
|
|
3138
|
+
import { Command as Command46 } from "commander";
|
|
2348
3139
|
|
|
2349
3140
|
// src/lib/tty-confirm.ts
|
|
2350
3141
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -2397,7 +3188,7 @@ function setupLines(plan, pricing) {
|
|
|
2397
3188
|
...rateLines(pricing)
|
|
2398
3189
|
];
|
|
2399
3190
|
}
|
|
2400
|
-
var setupCommand = new
|
|
3191
|
+
var setupCommand = new Command46("setup").description(
|
|
2401
3192
|
"Approve the compute allocation that pays for sandboxes: daily and monthly caps, and optional auto-top-up"
|
|
2402
3193
|
).requiredOption("--per-day <usd>", "Most compute credit bought in one UTC day, in USD").requiredOption("--per-month <usd>", "Most compute credit bought in one UTC month, in USD").option("--total <usd>", "Most this allocation ever buys, in USD (default: 12 months)").option(
|
|
2403
3194
|
"--auto-top-up-below <credits>",
|
|
@@ -2434,7 +3225,7 @@ var setupCommand = new Command42("setup").description(
|
|
|
2434
3225
|
printResult({ config, caps: plan.caps, autoTopUp: plan.autoTopUp ?? null });
|
|
2435
3226
|
}
|
|
2436
3227
|
);
|
|
2437
|
-
var buyCommand = new
|
|
3228
|
+
var buyCommand = new Command46("buy").description("Buy compute credit over x402 from the compute allocation, after showing the rate").option("--amount <usd>", "Purchase size in whole USD (see `credits status` for the sizes)").option("--yes", "Skip the confirmation prompt (the allocation caps still apply)").action(async (options) => {
|
|
2438
3229
|
const config = await loadComputeCreditConfig();
|
|
2439
3230
|
if (!config) {
|
|
2440
3231
|
throw new ComputeCreditError(
|
|
@@ -2464,17 +3255,17 @@ var buyCommand = new Command42("buy").description("Buy compute credit over x402
|
|
|
2464
3255
|
rate: { rateCardVersion: pricing.rateCardVersion, usdPerCredit: pricing.usdPerCredit }
|
|
2465
3256
|
});
|
|
2466
3257
|
});
|
|
2467
|
-
var statusCommand2 = new
|
|
3258
|
+
var statusCommand2 = new Command46("status").description(
|
|
2468
3259
|
"Show compute credit balance, rate, recent debits and purchases, and the caps; an approved auto-top-up runs when the balance is below its threshold"
|
|
2469
3260
|
).action(async () => {
|
|
2470
3261
|
printResult(await computeCreditStatus());
|
|
2471
3262
|
});
|
|
2472
|
-
var checkCommand = new
|
|
3263
|
+
var checkCommand = new Command46("check").description(
|
|
2473
3264
|
"Check the compute credit balance and, when auto-top-up was approved and the balance is low, buy one chunk"
|
|
2474
3265
|
).action(async () => {
|
|
2475
3266
|
printResult(await checkComputeBalance());
|
|
2476
3267
|
});
|
|
2477
|
-
var reconcileCommand = new
|
|
3268
|
+
var reconcileCommand = new Command46("reconcile").description(
|
|
2478
3269
|
"Settle purchases whose outcome was lost, by their idempotency key; never pays again"
|
|
2479
3270
|
).option(
|
|
2480
3271
|
"--release <key>",
|
|
@@ -2521,10 +3312,10 @@ var reconcileCommand = new Command42("reconcile").description(
|
|
|
2521
3312
|
...recoveryError === void 0 ? {} : { recoveryError }
|
|
2522
3313
|
});
|
|
2523
3314
|
});
|
|
2524
|
-
var disableAutoTopUpCommand = new
|
|
3315
|
+
var disableAutoTopUpCommand = new Command46("disable-auto-top-up").description("Turn off auto-top-up and close its allocation").action(async () => {
|
|
2525
3316
|
printResult({ config: await disableComputeAutoTopUp() });
|
|
2526
3317
|
});
|
|
2527
|
-
var agentCreditsCommand = new
|
|
3318
|
+
var agentCreditsCommand = new Command46("credits").description("Prepaid compute credit for agent sandboxes, bought over x402").addCommand(setupCommand).addCommand(buyCommand).addCommand(statusCommand2).addCommand(checkCommand).addCommand(reconcileCommand).addCommand(disableAutoTopUpCommand);
|
|
2528
3319
|
|
|
2529
3320
|
// src/commands/agent/launch.ts
|
|
2530
3321
|
var EXPERIMENTAL_AGENT_ENV = "TASKMARKET_EXPERIMENTAL_AGENT";
|
|
@@ -2546,8 +3337,13 @@ async function runAgentCommand(options) {
|
|
|
2546
3337
|
try {
|
|
2547
3338
|
const { assertAgentCompatibility } = await import("./compatibility-KUYGZSUC.js");
|
|
2548
3339
|
const pi = assertAgentCompatibility();
|
|
2549
|
-
const { runAgent } = await import("./launch-
|
|
2550
|
-
result = await runAgent({
|
|
3340
|
+
const { runAgent } = await import("./launch-ZV6OLBFM.js");
|
|
3341
|
+
result = await runAgent({
|
|
3342
|
+
model: options.model,
|
|
3343
|
+
pi,
|
|
3344
|
+
sync: options.sync,
|
|
3345
|
+
includeSecret: options.includeSecret
|
|
3346
|
+
});
|
|
2551
3347
|
} catch (error) {
|
|
2552
3348
|
renderFailure(error, {
|
|
2553
3349
|
details: error instanceof AgentLaunchError ? { ...error.details, code: error.code } : void 0
|
|
@@ -2572,7 +3368,7 @@ async function runAgentCommand(options) {
|
|
|
2572
3368
|
}
|
|
2573
3369
|
|
|
2574
3370
|
// src/commands/agent/manage.ts
|
|
2575
|
-
import { Command as
|
|
3371
|
+
import { Command as Command47 } from "commander";
|
|
2576
3372
|
async function run(options, work, lines) {
|
|
2577
3373
|
try {
|
|
2578
3374
|
const value = await work();
|
|
@@ -2597,37 +3393,76 @@ async function requireExperimental() {
|
|
|
2597
3393
|
);
|
|
2598
3394
|
}
|
|
2599
3395
|
function agentManagementCommands() {
|
|
2600
|
-
const status = new
|
|
3396
|
+
const status = new Command47("status").description(
|
|
2601
3397
|
"Show the agent channels (locked, charged, refundable), purchases with an unknown outcome, the sandbox and compute credit. Reads only."
|
|
2602
3398
|
).option("--json", "Print the versioned JSON envelope").action(async (options) => {
|
|
2603
|
-
const { collectAgentStatus, statusLines } = await import("./status-
|
|
3399
|
+
const { collectAgentStatus, statusLines } = await import("./status-FHZ3UGEB.js");
|
|
2604
3400
|
await run(options, () => collectAgentStatus(), statusLines);
|
|
2605
3401
|
});
|
|
2606
|
-
const doctor = new
|
|
3402
|
+
const doctor = new Command47("doctor").description(
|
|
2607
3403
|
"Check that the agent can start: Node and the bundled runtime, wallet and policy, channels, API, sandbox broker, host keys, xgate and RPC. Reads only."
|
|
2608
3404
|
).option("--json", "Print the versioned JSON envelope").action(async (options) => {
|
|
2609
|
-
const { runDoctor, doctorLines } = await import("./doctor-
|
|
3405
|
+
const { runDoctor, doctorLines } = await import("./doctor-TB3KKAZB.js");
|
|
2610
3406
|
const report = await run(options, () => runDoctor(), doctorLines);
|
|
2611
3407
|
if (report && !report.ok) process.exitCode = 1;
|
|
2612
3408
|
});
|
|
2613
|
-
const reconcile = new
|
|
2614
|
-
"Decide an agent purchase whose outcome is unknown, by its invocation ID. Never sends
|
|
2615
|
-
).argument("
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
3409
|
+
const reconcile = new Command47("reconcile").description(
|
|
3410
|
+
"Decide an agent purchase whose outcome is unknown, by its invocation ID; or, with --channel or --rail, everything one channel still has open. Never sends anything again."
|
|
3411
|
+
).argument("[invocation-id]", "The purchase, as status or the agent named it").option("--rail <id>", "Reconcile the open purchases of this rail's channel").option(
|
|
3412
|
+
"--channel <channel-id>",
|
|
3413
|
+
"Reconcile the open purchases of this channel, as status lists it; also reaches retired channels"
|
|
3414
|
+
).option("--json", "Print the versioned JSON envelope").action(
|
|
3415
|
+
async (invocationId, options) => {
|
|
3416
|
+
const { reconcileChannelPurchases, reconcileInvocation } = await import("./reconcile-UXL65RRT.js");
|
|
3417
|
+
const choice = { rail: options.rail, channel: options.channel };
|
|
3418
|
+
if (invocationId !== void 0) {
|
|
3419
|
+
await run(
|
|
3420
|
+
options,
|
|
3421
|
+
() => reconcileInvocation(invocationId, { choice }),
|
|
3422
|
+
(view) => [
|
|
3423
|
+
`Purchase ${view.invocationId} on ${view.rail}: ${view.outcome}`,
|
|
3424
|
+
view.message,
|
|
3425
|
+
...view.releasedFrom.map(
|
|
3426
|
+
(rail) => `Released the lease it had left on the ${rail} channel.`
|
|
3427
|
+
)
|
|
3428
|
+
]
|
|
3429
|
+
);
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
await run(
|
|
3433
|
+
options,
|
|
3434
|
+
async () => {
|
|
3435
|
+
if (options.rail === void 0 && options.channel === void 0) {
|
|
3436
|
+
const { AgentLaunchError } = await import("./errors-2L357HGA.js");
|
|
3437
|
+
throw new AgentLaunchError(
|
|
3438
|
+
"invalid_invocation_id",
|
|
3439
|
+
"Name a purchase (taskmarket agent reconcile <invocation-id>) or a channel (--channel <id> or --rail <id>)"
|
|
3440
|
+
);
|
|
3441
|
+
}
|
|
3442
|
+
return reconcileChannelPurchases(choice);
|
|
3443
|
+
},
|
|
3444
|
+
(view) => [
|
|
3445
|
+
`Channel ${view.channelId} (${view.rail}${view.retired ? ", retired" : ""})`,
|
|
3446
|
+
...view.purchases.map(
|
|
3447
|
+
(p) => p.outcome === "failed" ? ` ${p.invocationId}: not reconciled (${p.code}): ${p.message}` : ` ${p.invocationId}: ${p.outcome}. ${p.message}`
|
|
3448
|
+
),
|
|
3449
|
+
...view.releasedLease ? [
|
|
3450
|
+
`Released the lease another channel's purchase ${view.releasedLease} had left on it.`
|
|
3451
|
+
] : [],
|
|
3452
|
+
view.message,
|
|
3453
|
+
...channelLines(view.channel)
|
|
3454
|
+
]
|
|
3455
|
+
);
|
|
3456
|
+
}
|
|
3457
|
+
);
|
|
3458
|
+
const topup = new Command47("topup").description(
|
|
2624
3459
|
"Check a channel top-up against the approved budget: within it, the channel deposits by itself with the next turn that needs funds; over it, a new approval is needed"
|
|
2625
3460
|
).requiredOption("--amount <usdc>", "Top-up in USDC, e.g. 5 or 2.50").option("--rail <id>", "The rail to top up (required when the policy has more than one)").option("--json", "Print the versioned JSON envelope").action(async (options) => {
|
|
2626
3461
|
await run(
|
|
2627
3462
|
options,
|
|
2628
3463
|
async () => {
|
|
2629
3464
|
await requireExperimental();
|
|
2630
|
-
const { usdcToAtomic, AGENT_VIEW_VERSION } = await import("./budget-view-
|
|
3465
|
+
const { usdcToAtomic, AGENT_VIEW_VERSION } = await import("./budget-view-JPZ7HWR2.js");
|
|
2631
3466
|
const { AgentLaunchError } = await import("./errors-2L357HGA.js");
|
|
2632
3467
|
const amount = usdcToAtomic(options.amount);
|
|
2633
3468
|
if (amount === void 0 || amount === "0") {
|
|
@@ -2636,7 +3471,7 @@ function agentManagementCommands() {
|
|
|
2636
3471
|
`Not a USDC amount: ${options.amount} (digits, at most 6 decimals)`
|
|
2637
3472
|
);
|
|
2638
3473
|
}
|
|
2639
|
-
const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-
|
|
3474
|
+
const { openAgentChannels, requestTopUp, selectRail, withdrawalHatch } = await import("./channels-KCDZ5REF.js");
|
|
2640
3475
|
const { rails } = await openAgentChannels();
|
|
2641
3476
|
const result = await requestTopUp(selectRail(rails, options.rail), amount);
|
|
2642
3477
|
return {
|
|
@@ -2649,7 +3484,7 @@ function agentManagementCommands() {
|
|
|
2649
3484
|
(view) => [view.note, ...channelLines(view.channel)]
|
|
2650
3485
|
);
|
|
2651
3486
|
});
|
|
2652
|
-
const close = new
|
|
3487
|
+
const close = new Command47("close").description(
|
|
2653
3488
|
"Close the agent's channel and refund its unused balance cooperatively; checks an earlier close instead of sending it again"
|
|
2654
3489
|
).option("--rail <id>", "The rail to close (required when the policy has more than one)").option(
|
|
2655
3490
|
"--channel <channel-id>",
|
|
@@ -2659,9 +3494,11 @@ function agentManagementCommands() {
|
|
|
2659
3494
|
options,
|
|
2660
3495
|
async () => {
|
|
2661
3496
|
await requireExperimental();
|
|
2662
|
-
const { AGENT_VIEW_VERSION } = await import("./budget-view-
|
|
2663
|
-
const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-
|
|
2664
|
-
const {
|
|
3497
|
+
const { AGENT_VIEW_VERSION } = await import("./budget-view-JPZ7HWR2.js");
|
|
3498
|
+
const { closeChannel, openAgentChannels, selectChannel } = await import("./channels-KCDZ5REF.js");
|
|
3499
|
+
const { reconcileLeasedPurchase } = await import("./reconcile-UXL65RRT.js");
|
|
3500
|
+
const opened = await openAgentChannels();
|
|
3501
|
+
const { rail, retired } = selectChannel(opened, options);
|
|
2665
3502
|
const result = await closeChannel(
|
|
2666
3503
|
rail,
|
|
2667
3504
|
async (lines) => {
|
|
@@ -2672,7 +3509,16 @@ function agentManagementCommands() {
|
|
|
2672
3509
|
}
|
|
2673
3510
|
return confirmAtTerminal(lines, "pass --yes to close without a prompt");
|
|
2674
3511
|
},
|
|
2675
|
-
{
|
|
3512
|
+
{
|
|
3513
|
+
retired,
|
|
3514
|
+
reconcilePurchase: (id) => reconcileLeasedPurchase(opened, id),
|
|
3515
|
+
wait: {
|
|
3516
|
+
onWait: (progress2) => process.stderr.write(
|
|
3517
|
+
`Refund ${progress2.transaction} sent; waiting for it to confirm on chain (${Math.round(progress2.waitedMs / 1e3)} s of up to ${Math.round(progress2.timeoutMs / 1e3)} s)
|
|
3518
|
+
`
|
|
3519
|
+
)
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
2676
3522
|
);
|
|
2677
3523
|
return {
|
|
2678
3524
|
version: AGENT_VIEW_VERSION,
|
|
@@ -2683,7 +3529,7 @@ function agentManagementCommands() {
|
|
|
2683
3529
|
(view) => [
|
|
2684
3530
|
{
|
|
2685
3531
|
refunded: `Closed: the unused balance of ${view.rail} was refunded to the wallet.`,
|
|
2686
|
-
pending: `The refund of ${view.rail}
|
|
3532
|
+
pending: view.operation?.transaction ? `The refund of ${view.rail} was sent (transaction ${view.operation.transaction}) and is still confirming on chain. Run taskmarket agent close again in a minute to record it; it is never sent twice.` : `The refund of ${view.rail} may have been sent, and its outcome is not known yet. Run taskmarket agent close again later to check it; it is never sent twice.`,
|
|
2687
3533
|
failed: `The router refused the refund of ${view.rail}; nothing was returned.`,
|
|
2688
3534
|
closed: `The ${view.rail} channel is already closed.`
|
|
2689
3535
|
}[view.outcome],
|
|
@@ -2696,22 +3542,85 @@ function agentManagementCommands() {
|
|
|
2696
3542
|
]
|
|
2697
3543
|
);
|
|
2698
3544
|
});
|
|
2699
|
-
|
|
3545
|
+
const pull = new Command47("pull").description(
|
|
3546
|
+
"After a session: review the changes the agent left in its sandbox (saved when the session ended; the sandbox is not resumed) and apply them to this project on approval. Conflicts with your local edits and host configuration are listed, never applied. Inside a session use /pull."
|
|
3547
|
+
).option("--diff", "Print the full diff").option("--apply", "Apply the clean changes without asking").option(
|
|
3548
|
+
"--overwrite <path>",
|
|
3549
|
+
"Overwrite this conflicting file with the sandbox version (repeatable)",
|
|
3550
|
+
(value, previous = []) => [...previous, value]
|
|
3551
|
+
).option(
|
|
3552
|
+
"--keep-local <path>",
|
|
3553
|
+
"Resolve this saved change by keeping the file as it is in this project (repeatable)",
|
|
3554
|
+
(value, previous = []) => [...previous, value]
|
|
3555
|
+
).option(
|
|
3556
|
+
"--recover",
|
|
3557
|
+
"After a failed or interrupted end-of-session save: reconnect to the sandbox the session left running, save its changes here, then stop it"
|
|
3558
|
+
).option(
|
|
3559
|
+
"--discard",
|
|
3560
|
+
"Drop the saved changes (or the record of a failed save) instead of pulling them"
|
|
3561
|
+
).option(
|
|
3562
|
+
"--force-unclaim",
|
|
3563
|
+
"Release the project from a session or pull that is not running but still holds it (refused while it is)"
|
|
3564
|
+
).option("--yes", "With --discard or --force-unclaim: skip the confirmation prompt").option("--json", "Print the versioned JSON envelope").action(
|
|
3565
|
+
async (options) => {
|
|
3566
|
+
await run(
|
|
3567
|
+
options,
|
|
3568
|
+
async () => {
|
|
3569
|
+
await requireExperimental();
|
|
3570
|
+
const { runPull } = await import("./sync-pull-YECZ4PJA.js");
|
|
3571
|
+
const { terminalPrompter } = await import("./prompter-LSICEYSQ.js");
|
|
3572
|
+
return runPull(options, {
|
|
3573
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY) && !options.json,
|
|
3574
|
+
prompter: () => terminalPrompter(),
|
|
3575
|
+
say: (lines) => {
|
|
3576
|
+
if (!options.json && lines.length > 0)
|
|
3577
|
+
process.stdout.write(`${lines.join("\n")}
|
|
3578
|
+
`);
|
|
3579
|
+
}
|
|
3580
|
+
});
|
|
3581
|
+
},
|
|
3582
|
+
(view) => {
|
|
3583
|
+
const lines = [];
|
|
3584
|
+
for (const skip of view.skipped) {
|
|
3585
|
+
lines.push(` not applied: ${skip.path} (${skip.reason.replace(/_/g, " ")})`);
|
|
3586
|
+
}
|
|
3587
|
+
lines.push(view.note);
|
|
3588
|
+
return lines;
|
|
3589
|
+
}
|
|
3590
|
+
);
|
|
3591
|
+
}
|
|
3592
|
+
);
|
|
3593
|
+
return [status, doctor, reconcile, topup, close, pull];
|
|
2700
3594
|
}
|
|
2701
3595
|
|
|
2702
3596
|
// src/commands/agent/index.ts
|
|
2703
3597
|
var experimental = agentCommandEnabled();
|
|
2704
|
-
var agentCommand = new
|
|
3598
|
+
var agentCommand = new Command48("agent").description(
|
|
2705
3599
|
experimental ? "The Taskmarket agent and the compute it runs on. Without a subcommand (experimental), open Pi's interactive coding agent in this project, with paid xgate inference from your wallet and tools in your cloud sandbox" : "The Taskmarket agent and the compute it runs on"
|
|
2706
3600
|
).addOption(
|
|
2707
|
-
new
|
|
3601
|
+
new Option3("--model <id>", "Start on one model from your approved spending policy").hideHelp(
|
|
2708
3602
|
!experimental
|
|
2709
3603
|
)
|
|
3604
|
+
).addOption(
|
|
3605
|
+
new Option3(
|
|
3606
|
+
"--sync",
|
|
3607
|
+
"Upload this project to the sandbox for this session without asking (what goes up is still shown); needed without a terminal until you approve the project once"
|
|
3608
|
+
).hideHelp(!experimental)
|
|
3609
|
+
).addOption(
|
|
3610
|
+
new Option3(
|
|
3611
|
+
"--no-sync",
|
|
3612
|
+
"Start with an empty sandbox: upload nothing from this project"
|
|
3613
|
+
).hideHelp(!experimental)
|
|
3614
|
+
).addOption(
|
|
3615
|
+
new Option3(
|
|
3616
|
+
"--include-secret <path>",
|
|
3617
|
+
"Upload this secret-like file too (a path in the project, not a pattern; repeatable)"
|
|
3618
|
+
).argParser((value, previous = []) => [...previous, value]).hideHelp(!experimental)
|
|
2710
3619
|
).allowExcessArguments(false).action(runAgentCommand);
|
|
2711
3620
|
if (experimental) {
|
|
2712
3621
|
agentCommand.addHelpText(
|
|
2713
3622
|
"after",
|
|
2714
|
-
"\nThe session offers only models your spending policy approves and xgate qualifies. Pi runs\non this machine with its configuration under TASKMARKET_HOME; every tool runs in a sandbox."
|
|
3623
|
+
"\nThe session offers only models your spending policy approves and xgate qualifies. Pi runs\non this machine with its configuration under TASKMARKET_HOME; every tool runs in a sandbox.\nThe project is uploaded with your approval (asked once per project); secret-like files stay\nhere unless you name them. /pull in the session, or taskmarket agent pull after it, shows\nwhat the agent changed and applies it only when you approve; /sync sends your local edits."
|
|
2715
3624
|
);
|
|
2716
3625
|
}
|
|
2717
3626
|
agentCommand.addCommand(agentCreditsCommand);
|
|
@@ -2720,8 +3629,8 @@ for (const command of agentManagementCommands()) {
|
|
|
2720
3629
|
}
|
|
2721
3630
|
|
|
2722
3631
|
// src/commands/agents.ts
|
|
2723
|
-
import { Command as
|
|
2724
|
-
var agentsCommand = new
|
|
3632
|
+
import { Command as Command49 } from "commander";
|
|
3633
|
+
var agentsCommand = new Command49("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) => {
|
|
2725
3634
|
const params = new URLSearchParams();
|
|
2726
3635
|
if (opts.sort) params.set("sort", opts.sort);
|
|
2727
3636
|
if (opts.skill) params.set("skill", opts.skill);
|
|
@@ -2732,8 +3641,8 @@ var agentsCommand = new Command45("agents").description("Browse the agent direct
|
|
|
2732
3641
|
});
|
|
2733
3642
|
|
|
2734
3643
|
// src/commands/inbox.ts
|
|
2735
|
-
import { Command as
|
|
2736
|
-
var inboxCommand = new
|
|
3644
|
+
import { Command as Command50 } from "commander";
|
|
3645
|
+
var inboxCommand = new Command50("inbox").description("Show tasks you created and tasks you are working on").action(async () => {
|
|
2737
3646
|
const auth = await signReadAuth();
|
|
2738
3647
|
if (!auth) {
|
|
2739
3648
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -2754,8 +3663,8 @@ var inboxCommand = new Command46("inbox").description("Show tasks you created an
|
|
|
2754
3663
|
});
|
|
2755
3664
|
|
|
2756
3665
|
// src/commands/actions.ts
|
|
2757
|
-
import { Command as
|
|
2758
|
-
var actionsCommand = new
|
|
3666
|
+
import { Command as Command51 } from "commander";
|
|
3667
|
+
var actionsCommand = new Command51("actions").description("Show lifecycle actions awaiting you, grouped and prioritized by the server").action(async () => {
|
|
2759
3668
|
const auth = await signReadAuth();
|
|
2760
3669
|
if (!auth) {
|
|
2761
3670
|
printError("No keystore found. Run `taskmarket init` first.");
|
|
@@ -2769,8 +3678,8 @@ var actionsCommand = new Command47("actions").description("Show lifecycle action
|
|
|
2769
3678
|
});
|
|
2770
3679
|
|
|
2771
3680
|
// src/commands/deposit.ts
|
|
2772
|
-
import { Command as
|
|
2773
|
-
var depositCommand = new
|
|
3681
|
+
import { Command as Command52 } from "commander";
|
|
3682
|
+
var depositCommand = new Command52("deposit").description("Show wallet address and network info for funding").action(async () => {
|
|
2774
3683
|
let address;
|
|
2775
3684
|
try {
|
|
2776
3685
|
address = await getWalletAddress();
|
|
@@ -2802,11 +3711,11 @@ var depositCommand = new Command48("deposit").description("Show wallet address a
|
|
|
2802
3711
|
});
|
|
2803
3712
|
|
|
2804
3713
|
// src/commands/wallet/index.ts
|
|
2805
|
-
import { Command as
|
|
3714
|
+
import { Command as Command63 } from "commander";
|
|
2806
3715
|
|
|
2807
3716
|
// src/commands/wallet/balance.ts
|
|
2808
|
-
import { Command as
|
|
2809
|
-
var walletBalanceCommand = new
|
|
3717
|
+
import { Command as Command53 } from "commander";
|
|
3718
|
+
var walletBalanceCommand = new Command53("balance").description("Show the wallet's payment-token balance on the selected network").option("--address <addr>", "Address to check (defaults to own wallet)").action(async (opts) => {
|
|
2810
3719
|
let address = opts.address;
|
|
2811
3720
|
if (!address) {
|
|
2812
3721
|
const keystore = await loadKeystore();
|
|
@@ -2819,7 +3728,7 @@ var walletBalanceCommand = new Command49("balance").description("Show the wallet
|
|
|
2819
3728
|
});
|
|
2820
3729
|
|
|
2821
3730
|
// src/commands/wallet/import.ts
|
|
2822
|
-
import { Command as
|
|
3731
|
+
import { Command as Command54 } from "commander";
|
|
2823
3732
|
import { createInterface as createInterface3 } from "readline";
|
|
2824
3733
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
2825
3734
|
function normalizePrivateKey(raw) {
|
|
@@ -2854,7 +3763,7 @@ function promptHiddenInput(prompt) {
|
|
|
2854
3763
|
});
|
|
2855
3764
|
});
|
|
2856
3765
|
}
|
|
2857
|
-
var walletImportCommand = new
|
|
3766
|
+
var walletImportCommand = new Command54("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(
|
|
2858
3767
|
"--yes",
|
|
2859
3768
|
"Confirm legal acceptance non-interactively after reviewing every current policy"
|
|
2860
3769
|
).action(async (opts) => {
|
|
@@ -2934,11 +3843,57 @@ var walletImportCommand = new Command50("import").description("Import an existin
|
|
|
2934
3843
|
});
|
|
2935
3844
|
|
|
2936
3845
|
// src/commands/wallet/set-withdrawal-address.ts
|
|
2937
|
-
import {
|
|
3846
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
3847
|
+
import { Command as Command55 } from "commander";
|
|
3848
|
+
|
|
3849
|
+
// src/lib/withdrawal-pin.ts
|
|
3850
|
+
var WithdrawalAddressMismatchError = class extends Error {
|
|
3851
|
+
constructor(pinned, server) {
|
|
3852
|
+
super(
|
|
3853
|
+
`Refusing to sign: the server reports withdrawal address ${server}, but this CLI has ${pinned} pinned locally. Nothing was signed or sent. If you changed the withdrawal address yourself (for example on the web with your account recovery code), accept the new address with: taskmarket wallet sync-withdrawal-address`
|
|
3854
|
+
);
|
|
3855
|
+
this.pinned = pinned;
|
|
3856
|
+
this.server = server;
|
|
3857
|
+
this.name = "WithdrawalAddressMismatchError";
|
|
3858
|
+
}
|
|
3859
|
+
};
|
|
3860
|
+
async function pinWithdrawalAddress(keystore, address) {
|
|
3861
|
+
await saveKeystore({ ...keystore, withdrawalAddress: address });
|
|
3862
|
+
}
|
|
3863
|
+
async function verifyWithdrawalAddress(keystore, serverAddress, log = (line) => process.stderr.write(line + "\n")) {
|
|
3864
|
+
const pinned = keystore.withdrawalAddress;
|
|
3865
|
+
if (!pinned) {
|
|
3866
|
+
await pinWithdrawalAddress(keystore, serverAddress);
|
|
3867
|
+
log(`Note: pinned withdrawal address ${serverAddress} in the local keystore.`);
|
|
3868
|
+
return serverAddress;
|
|
3869
|
+
}
|
|
3870
|
+
if (pinned.toLowerCase() !== serverAddress.toLowerCase()) {
|
|
3871
|
+
throw new WithdrawalAddressMismatchError(pinned, serverAddress);
|
|
3872
|
+
}
|
|
3873
|
+
return pinned;
|
|
3874
|
+
}
|
|
3875
|
+
function paymentTokenDomain(chainId) {
|
|
3876
|
+
const { payment } = taskmarketChain(chainId);
|
|
3877
|
+
const verifyingContract = payment.token ?? (chainId === 31337 ? process.env.USDC_TOKEN_ADDRESS : void 0);
|
|
3878
|
+
if (!verifyingContract) {
|
|
3879
|
+
throw new Error(
|
|
3880
|
+
`Chain ${chainId} has no known payment token address` + (chainId === 31337 ? "; set USDC_TOKEN_ADDRESS to the local mock token" : "")
|
|
3881
|
+
);
|
|
3882
|
+
}
|
|
3883
|
+
return {
|
|
3884
|
+
name: payment.domain.name,
|
|
3885
|
+
version: payment.domain.version,
|
|
3886
|
+
chainId,
|
|
3887
|
+
verifyingContract
|
|
3888
|
+
};
|
|
3889
|
+
}
|
|
3890
|
+
|
|
3891
|
+
// src/commands/wallet/set-withdrawal-address.ts
|
|
3892
|
+
var SIGNATURE_TTL_SECONDS = 5 * 60;
|
|
2938
3893
|
function isValidAddress(addr) {
|
|
2939
3894
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
2940
3895
|
}
|
|
2941
|
-
var setWithdrawalAddressCommand = new
|
|
3896
|
+
var setWithdrawalAddressCommand = new Command55("set-withdrawal-address").description("Set a withdrawal address for payment-token withdrawals (one-time, free)").argument("<address>", "Ethereum address to receive withdrawals").action(async (address) => {
|
|
2942
3897
|
if (!isValidAddress(address)) {
|
|
2943
3898
|
printError("Invalid Ethereum address: must be 0x followed by 40 hex characters");
|
|
2944
3899
|
return;
|
|
@@ -2951,13 +3906,26 @@ var setWithdrawalAddressCommand = new Command51("set-withdrawal-address").descri
|
|
|
2951
3906
|
return;
|
|
2952
3907
|
}
|
|
2953
3908
|
const walletAddress = keystore.walletAddress;
|
|
2954
|
-
const
|
|
3909
|
+
const chainId = selectedNetwork().chainId;
|
|
3910
|
+
const nonce = `0x${randomBytes2(32).toString("hex")}`;
|
|
3911
|
+
const expiresAt = Math.floor(Date.now() / 1e3) + SIGNATURE_TTL_SECONDS;
|
|
3912
|
+
const message = buildSetWithdrawalAddressMessage({
|
|
3913
|
+
walletAddress,
|
|
3914
|
+
withdrawalAddress: address,
|
|
3915
|
+
chainId,
|
|
3916
|
+
nonce,
|
|
3917
|
+
expiresAt
|
|
3918
|
+
});
|
|
2955
3919
|
const signature = await signMessage(message, keystore);
|
|
2956
3920
|
const { data: result, idempotencyKey } = await apiPost("/api/wallet/set-withdrawal-address", {
|
|
2957
3921
|
walletAddress,
|
|
2958
3922
|
withdrawalAddress: address,
|
|
2959
|
-
signature
|
|
3923
|
+
signature,
|
|
3924
|
+
nonce,
|
|
3925
|
+
expiresAt,
|
|
3926
|
+
chainId
|
|
2960
3927
|
});
|
|
3928
|
+
await pinWithdrawalAddress(keystore, result.withdrawalAddress);
|
|
2961
3929
|
printResult(
|
|
2962
3930
|
{
|
|
2963
3931
|
withdrawalAddress: result.withdrawalAddress,
|
|
@@ -2969,8 +3937,8 @@ var setWithdrawalAddressCommand = new Command51("set-withdrawal-address").descri
|
|
|
2969
3937
|
});
|
|
2970
3938
|
|
|
2971
3939
|
// src/commands/wallet/get-withdrawal-address.ts
|
|
2972
|
-
import { Command as
|
|
2973
|
-
var getWithdrawalAddressCommand = new
|
|
3940
|
+
import { Command as Command56 } from "commander";
|
|
3941
|
+
var getWithdrawalAddressCommand = new Command56("get-withdrawal-address").description("Show the currently registered withdrawal address, if any").option("--address <addr>", "Wallet address to check (defaults to own wallet)").action(async (opts) => {
|
|
2974
3942
|
let address = opts.address;
|
|
2975
3943
|
if (!address) {
|
|
2976
3944
|
const keystore = await loadKeystore();
|
|
@@ -2981,14 +3949,14 @@ var getWithdrawalAddressCommand = new Command52("get-withdrawal-address").descri
|
|
|
2981
3949
|
});
|
|
2982
3950
|
|
|
2983
3951
|
// src/commands/wallet/change-withdrawal-address.ts
|
|
2984
|
-
import { Command as
|
|
3952
|
+
import { Command as Command57 } from "commander";
|
|
2985
3953
|
function isValidAddress2(addr) {
|
|
2986
3954
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
2987
3955
|
}
|
|
2988
3956
|
function isValidRecoveryCode(code) {
|
|
2989
3957
|
return /^\d{8}$/.test(code);
|
|
2990
3958
|
}
|
|
2991
|
-
var changeWithdrawalAddressCommand = new
|
|
3959
|
+
var changeWithdrawalAddressCommand = new Command57("change-withdrawal-address").description("Change the withdrawal address using the account recovery code (RFC-0012)").argument("<recovery-code>", "The 8-digit account recovery code from set-withdrawal-address").argument("<new-address>", "New Ethereum address to receive withdrawals").action(async (recoveryCode, newAddress) => {
|
|
2992
3960
|
if (!isValidRecoveryCode(recoveryCode)) {
|
|
2993
3961
|
printError("Invalid account recovery code: must be 8 digits");
|
|
2994
3962
|
return;
|
|
@@ -3009,6 +3977,7 @@ var changeWithdrawalAddressCommand = new Command53("change-withdrawal-address").
|
|
|
3009
3977
|
accountRecoveryCode: recoveryCode,
|
|
3010
3978
|
newWithdrawalAddress: newAddress
|
|
3011
3979
|
});
|
|
3980
|
+
await pinWithdrawalAddress(keystore, result.withdrawalAddress);
|
|
3012
3981
|
printResult(
|
|
3013
3982
|
{
|
|
3014
3983
|
withdrawalAddress: result.withdrawalAddress,
|
|
@@ -3019,9 +3988,39 @@ var changeWithdrawalAddressCommand = new Command53("change-withdrawal-address").
|
|
|
3019
3988
|
);
|
|
3020
3989
|
});
|
|
3021
3990
|
|
|
3991
|
+
// src/commands/wallet/sync-withdrawal-address.ts
|
|
3992
|
+
import { Command as Command58 } from "commander";
|
|
3993
|
+
var syncWithdrawalAddressCommand = new Command58("sync-withdrawal-address").description(
|
|
3994
|
+
"Accept the withdrawal address registered on the server as the locally pinned one (after a change made elsewhere, e.g. on the web)"
|
|
3995
|
+
).action(async () => {
|
|
3996
|
+
let keystore;
|
|
3997
|
+
try {
|
|
3998
|
+
keystore = await loadKeystore();
|
|
3999
|
+
} catch {
|
|
4000
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
const { withdrawalAddress } = await apiGet(
|
|
4004
|
+
`/api/wallet/withdrawal-address?address=${keystore.walletAddress}`
|
|
4005
|
+
);
|
|
4006
|
+
if (!withdrawalAddress) {
|
|
4007
|
+
printError(
|
|
4008
|
+
"No withdrawal address set. Run: taskmarket wallet set-withdrawal-address <address>"
|
|
4009
|
+
);
|
|
4010
|
+
return;
|
|
4011
|
+
}
|
|
4012
|
+
const previous = keystore.withdrawalAddress ?? null;
|
|
4013
|
+
await pinWithdrawalAddress(keystore, withdrawalAddress);
|
|
4014
|
+
printResult({
|
|
4015
|
+
previousWithdrawalAddress: previous,
|
|
4016
|
+
withdrawalAddress,
|
|
4017
|
+
changed: previous === null || previous.toLowerCase() !== withdrawalAddress.toLowerCase()
|
|
4018
|
+
});
|
|
4019
|
+
});
|
|
4020
|
+
|
|
3022
4021
|
// src/commands/wallet/reveal-recovery-code.ts
|
|
3023
|
-
import { Command as
|
|
3024
|
-
var revealRecoveryCodeCommand = new
|
|
4022
|
+
import { Command as Command59 } from "commander";
|
|
4023
|
+
var revealRecoveryCodeCommand = new Command59("reveal-recovery-code").description("One-time reveal of your account recovery code, if one has not been generated yet").action(async () => {
|
|
3025
4024
|
let keystore;
|
|
3026
4025
|
try {
|
|
3027
4026
|
keystore = await loadKeystore();
|
|
@@ -3046,8 +4045,8 @@ var revealRecoveryCodeCommand = new Command54("reveal-recovery-code").descriptio
|
|
|
3046
4045
|
});
|
|
3047
4046
|
|
|
3048
4047
|
// src/commands/wallet/publish-key.ts
|
|
3049
|
-
import { Command as
|
|
3050
|
-
var publishKeyCommand = new
|
|
4048
|
+
import { Command as Command60 } from "commander";
|
|
4049
|
+
var publishKeyCommand = new Command60("publish-key").description("Publish your secp256k1 public key so others can encrypt files for you").action(async () => {
|
|
3051
4050
|
let keystore;
|
|
3052
4051
|
try {
|
|
3053
4052
|
keystore = await loadKeystore();
|
|
@@ -3067,13 +4066,13 @@ var publishKeyCommand = new Command55("publish-key").description("Publish your s
|
|
|
3067
4066
|
});
|
|
3068
4067
|
|
|
3069
4068
|
// src/commands/wallet/withdraw-dreams.ts
|
|
3070
|
-
import { Command as
|
|
4069
|
+
import { Command as Command61 } from "commander";
|
|
3071
4070
|
import { toHex } from "viem";
|
|
3072
4071
|
var AUTHORIZATION_VALIDITY_SECONDS = 300;
|
|
3073
4072
|
function isValidAddress3(addr) {
|
|
3074
4073
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
3075
4074
|
}
|
|
3076
|
-
var withdrawDreamsCommand = new
|
|
4075
|
+
var withdrawDreamsCommand = new Command61("withdraw-dreams").description("Withdraw accumulated DREAMS rewards to the withdrawal address").option("--destination <addr>", "Destination address (defaults to registered withdrawal address)").action(async (opts) => {
|
|
3077
4076
|
let keystore;
|
|
3078
4077
|
try {
|
|
3079
4078
|
keystore = await loadKeystore();
|
|
@@ -3097,7 +4096,12 @@ var withdrawDreamsCommand = new Command56("withdraw-dreams").description("Withdr
|
|
|
3097
4096
|
);
|
|
3098
4097
|
return;
|
|
3099
4098
|
}
|
|
3100
|
-
|
|
4099
|
+
try {
|
|
4100
|
+
destination = await verifyWithdrawalAddress(keystore, addressResponse.withdrawalAddress);
|
|
4101
|
+
} catch (err) {
|
|
4102
|
+
renderFailure(err);
|
|
4103
|
+
return;
|
|
4104
|
+
}
|
|
3101
4105
|
}
|
|
3102
4106
|
const nonce = toHex(crypto.getRandomValues(new Uint8Array(32)));
|
|
3103
4107
|
const validBefore = String(Math.floor(Date.now() / 1e3) + AUTHORIZATION_VALIDITY_SECONDS);
|
|
@@ -3126,20 +4130,196 @@ var withdrawDreamsCommand = new Command56("withdraw-dreams").description("Withdr
|
|
|
3126
4130
|
);
|
|
3127
4131
|
});
|
|
3128
4132
|
|
|
4133
|
+
// src/commands/wallet/bridge.ts
|
|
4134
|
+
import { Command as Command62 } from "commander";
|
|
4135
|
+
import { toHex as toHex2 } from "viem";
|
|
4136
|
+
var USDC_TYPES = {
|
|
4137
|
+
TransferWithAuthorization: [
|
|
4138
|
+
{ name: "from", type: "address" },
|
|
4139
|
+
{ name: "to", type: "address" },
|
|
4140
|
+
{ name: "value", type: "uint256" },
|
|
4141
|
+
{ name: "validAfter", type: "uint256" },
|
|
4142
|
+
{ name: "validBefore", type: "uint256" },
|
|
4143
|
+
{ name: "nonce", type: "bytes32" }
|
|
4144
|
+
]
|
|
4145
|
+
};
|
|
4146
|
+
var bridgeTiming = { intervalMs: 3e3, timeoutMs: 10 * 6e4 };
|
|
4147
|
+
function progress(message) {
|
|
4148
|
+
process.stderr.write(`${message}
|
|
4149
|
+
`);
|
|
4150
|
+
}
|
|
4151
|
+
function sleep(ms) {
|
|
4152
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4153
|
+
}
|
|
4154
|
+
function sameAddress(a, b) {
|
|
4155
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
4156
|
+
}
|
|
4157
|
+
async function pollBridgeStatus(requestId) {
|
|
4158
|
+
const deadline = Date.now() + bridgeTiming.timeoutMs;
|
|
4159
|
+
let last;
|
|
4160
|
+
for (; ; ) {
|
|
4161
|
+
let status = null;
|
|
4162
|
+
try {
|
|
4163
|
+
status = await apiGet(
|
|
4164
|
+
`/api/wallet/bridge-status?requestId=${encodeURIComponent(requestId)}`
|
|
4165
|
+
);
|
|
4166
|
+
} catch (err) {
|
|
4167
|
+
progress(`Could not read bridge status: ${err instanceof Error ? err.message : String(err)}`);
|
|
4168
|
+
}
|
|
4169
|
+
if (status) {
|
|
4170
|
+
if (status.status !== last) progress(`Bridge status: ${status.status}`);
|
|
4171
|
+
last = status.status;
|
|
4172
|
+
if (isTerminalWalletBridgeStatus(status.status)) return status;
|
|
4173
|
+
}
|
|
4174
|
+
if (Date.now() >= deadline) return status;
|
|
4175
|
+
await sleep(bridgeTiming.intervalMs);
|
|
4176
|
+
}
|
|
4177
|
+
}
|
|
4178
|
+
var walletBridgeCommand = new Command62("bridge").description(
|
|
4179
|
+
"Move free USDC on Base to OUSD at the same address on Tempo (gasless, through Relay)"
|
|
4180
|
+
).requiredOption("--to <chain>", 'Destination chain (only "tempo")').argument("<amount>", "Amount of USDC in whole tokens (minimum 1, e.g. 25)").action(async (amount, opts) => {
|
|
4181
|
+
if (opts.to !== "tempo") {
|
|
4182
|
+
printError('Invalid --to: the only bridge destination is "tempo"');
|
|
4183
|
+
return;
|
|
4184
|
+
}
|
|
4185
|
+
if (!/^\d+(\.\d{1,6})?$/.test(amount) || Number(amount) <= 0) {
|
|
4186
|
+
printError("Invalid amount: must be a positive number with at most 6 decimals (e.g. 25)");
|
|
4187
|
+
return;
|
|
4188
|
+
}
|
|
4189
|
+
const [whole, fraction = ""] = amount.split(".");
|
|
4190
|
+
const amountBaseUnits = (BigInt(whole) * 1000000n + BigInt(fraction.padEnd(6, "0"))).toString();
|
|
4191
|
+
let keystore;
|
|
4192
|
+
try {
|
|
4193
|
+
keystore = await loadKeystore();
|
|
4194
|
+
} catch {
|
|
4195
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
4196
|
+
return;
|
|
4197
|
+
}
|
|
4198
|
+
const from = keystore.walletAddress;
|
|
4199
|
+
let quote;
|
|
4200
|
+
try {
|
|
4201
|
+
({ data: quote } = await apiPost("/api/wallet/bridge-quote", {
|
|
4202
|
+
chainId: WALLET_BRIDGE_ORIGIN_CHAIN_ID,
|
|
4203
|
+
from,
|
|
4204
|
+
to: "tempo",
|
|
4205
|
+
amountBaseUnits
|
|
4206
|
+
}));
|
|
4207
|
+
} catch (err) {
|
|
4208
|
+
renderFailure(err);
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
if (!sameAddress(quote.recipient, from) || !sameAddress(quote.refundTo, from) || !sameAddress(quote.authorization.message.to, quote.depositAddress) || quote.amountBaseUnits !== amountBaseUnits || quote.authorization.message.value !== amountBaseUnits || quote.destinationChainId !== WALLET_BRIDGE_TEMPO_CHAIN_ID) {
|
|
4212
|
+
printError("The bridge quote does not match this request; nothing was signed");
|
|
4213
|
+
return;
|
|
4214
|
+
}
|
|
4215
|
+
let domain;
|
|
4216
|
+
try {
|
|
4217
|
+
domain = paymentTokenDomain(WALLET_BRIDGE_ORIGIN_CHAIN_ID);
|
|
4218
|
+
} catch (err) {
|
|
4219
|
+
renderFailure(err);
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4222
|
+
progress(
|
|
4223
|
+
`Bridging ${formatPaymentAmount(amountBaseUnits, WALLET_BRIDGE_ORIGIN_CHAIN_ID)}: expect ${formatPaymentAmount(quote.expectedOutBaseUnits, WALLET_BRIDGE_TEMPO_CHAIN_ID)}, at least ${formatPaymentAmount(quote.minimumOutBaseUnits, WALLET_BRIDGE_TEMPO_CHAIN_ID)} (Relay fee ${quote.fees.relayerUsd} USD)`
|
|
4224
|
+
);
|
|
4225
|
+
const authorization = {
|
|
4226
|
+
from,
|
|
4227
|
+
to: quote.depositAddress,
|
|
4228
|
+
value: amountBaseUnits,
|
|
4229
|
+
validAfter: quote.authorization.message.validAfter,
|
|
4230
|
+
validBefore: quote.authorization.message.validBefore,
|
|
4231
|
+
nonce: toHex2(crypto.getRandomValues(new Uint8Array(32)))
|
|
4232
|
+
};
|
|
4233
|
+
const signature = await signTypedData(
|
|
4234
|
+
{
|
|
4235
|
+
domain,
|
|
4236
|
+
types: USDC_TYPES,
|
|
4237
|
+
primaryType: "TransferWithAuthorization",
|
|
4238
|
+
message: authorization
|
|
4239
|
+
},
|
|
4240
|
+
keystore
|
|
4241
|
+
);
|
|
4242
|
+
let bridged;
|
|
4243
|
+
let idempotencyKey;
|
|
4244
|
+
try {
|
|
4245
|
+
({ data: bridged, idempotencyKey } = await apiPost("/api/wallet/bridge", {
|
|
4246
|
+
chainId: WALLET_BRIDGE_ORIGIN_CHAIN_ID,
|
|
4247
|
+
from,
|
|
4248
|
+
amountBaseUnits,
|
|
4249
|
+
authorization,
|
|
4250
|
+
signature
|
|
4251
|
+
}));
|
|
4252
|
+
} catch (err) {
|
|
4253
|
+
renderFailure(err);
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4256
|
+
progress(`Deposited on Base: ${bridged.txHash}. Waiting for Relay to fill on Tempo...`);
|
|
4257
|
+
const status = await pollBridgeStatus(bridged.requestId);
|
|
4258
|
+
const tempoExplorer = taskmarketChain(WALLET_BRIDGE_TEMPO_CHAIN_ID).explorerUrl;
|
|
4259
|
+
const baseExplorer = taskmarketChain(WALLET_BRIDGE_ORIGIN_CHAIN_ID).explorerUrl;
|
|
4260
|
+
const output = {
|
|
4261
|
+
status: status?.status ?? "unknown",
|
|
4262
|
+
requestId: bridged.requestId,
|
|
4263
|
+
from,
|
|
4264
|
+
recipient: bridged.recipient,
|
|
4265
|
+
amountBaseUnits,
|
|
4266
|
+
amount: formatPaymentAmount(amountBaseUnits, WALLET_BRIDGE_ORIGIN_CHAIN_ID),
|
|
4267
|
+
expectedOut: formatPaymentAmount(quote.expectedOutBaseUnits, WALLET_BRIDGE_TEMPO_CHAIN_ID),
|
|
4268
|
+
minimumOut: formatPaymentAmount(quote.minimumOutBaseUnits, WALLET_BRIDGE_TEMPO_CHAIN_ID),
|
|
4269
|
+
tokenSymbol: "OUSD",
|
|
4270
|
+
depositTxHash: bridged.txHash,
|
|
4271
|
+
depositExplorerUrl: `${baseExplorer}/tx/${bridged.txHash}`
|
|
4272
|
+
};
|
|
4273
|
+
if (status?.status === "success") {
|
|
4274
|
+
const fillTxHash = status.txHashes[0];
|
|
4275
|
+
printResult(
|
|
4276
|
+
{
|
|
4277
|
+
...output,
|
|
4278
|
+
fillTxHash: fillTxHash ?? null,
|
|
4279
|
+
explorerUrl: fillTxHash ? `${tempoExplorer}/tx/${fillTxHash}` : `${tempoExplorer}/address/${bridged.recipient}`
|
|
4280
|
+
},
|
|
4281
|
+
{ idempotencyKey }
|
|
4282
|
+
);
|
|
4283
|
+
return;
|
|
4284
|
+
}
|
|
4285
|
+
if (status?.status === "refund") {
|
|
4286
|
+
printError(
|
|
4287
|
+
`Relay refunded the bridge to ${from} on Base (minus gas)` + (status.failReason ? `: ${status.failReason}` : "") + `. Request ${bridged.requestId}.`,
|
|
4288
|
+
{ idempotencyKey }
|
|
4289
|
+
);
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
if (status?.status === "failure") {
|
|
4293
|
+
printError(
|
|
4294
|
+
`The bridge failed` + (status.failReason ? `: ${status.failReason}` : "") + `. Request ${bridged.requestId}; check taskmarket wallet balance on Base and Tempo.`,
|
|
4295
|
+
{ idempotencyKey }
|
|
4296
|
+
);
|
|
4297
|
+
return;
|
|
4298
|
+
}
|
|
4299
|
+
printResult(
|
|
4300
|
+
{ ...output, explorerUrl: `${tempoExplorer}/address/${bridged.recipient}` },
|
|
4301
|
+
{
|
|
4302
|
+
idempotencyKey
|
|
4303
|
+
}
|
|
4304
|
+
);
|
|
4305
|
+
});
|
|
4306
|
+
|
|
3129
4307
|
// src/commands/wallet/index.ts
|
|
3130
|
-
var walletCommand = new
|
|
4308
|
+
var walletCommand = new Command63("wallet").description("Wallet management commands");
|
|
3131
4309
|
walletCommand.addCommand(walletBalanceCommand);
|
|
3132
4310
|
walletCommand.addCommand(walletImportCommand);
|
|
3133
4311
|
walletCommand.addCommand(setWithdrawalAddressCommand);
|
|
3134
4312
|
walletCommand.addCommand(getWithdrawalAddressCommand);
|
|
3135
4313
|
walletCommand.addCommand(changeWithdrawalAddressCommand);
|
|
4314
|
+
walletCommand.addCommand(syncWithdrawalAddressCommand);
|
|
3136
4315
|
walletCommand.addCommand(revealRecoveryCodeCommand);
|
|
3137
4316
|
walletCommand.addCommand(publishKeyCommand);
|
|
3138
4317
|
walletCommand.addCommand(withdrawDreamsCommand);
|
|
4318
|
+
walletCommand.addCommand(walletBridgeCommand);
|
|
3139
4319
|
|
|
3140
4320
|
// src/commands/withdraw.ts
|
|
3141
|
-
import { Command as
|
|
3142
|
-
import { toHex as
|
|
4321
|
+
import { Command as Command64 } from "commander";
|
|
4322
|
+
import { toHex as toHex3 } from "viem";
|
|
3143
4323
|
var RECEIVE_POLICY_BLOCKED = "recipient_receive_policy_blocked";
|
|
3144
4324
|
async function withdrawOnTempo(input) {
|
|
3145
4325
|
const { keystore, chainId, withdrawalAddress, amountBaseUnits } = input;
|
|
@@ -3175,7 +4355,16 @@ async function withdrawOnTempo(input) {
|
|
|
3175
4355
|
throw error;
|
|
3176
4356
|
}
|
|
3177
4357
|
}
|
|
3178
|
-
|
|
4358
|
+
function withdrawOutput(result, chainId) {
|
|
4359
|
+
return {
|
|
4360
|
+
txHash: result.txHash,
|
|
4361
|
+
amountBaseUnits: result.amountBaseUnits,
|
|
4362
|
+
amount: formatPaymentAmount(result.amountBaseUnits, chainId),
|
|
4363
|
+
tokenSymbol: paymentTokenSymbol(chainId),
|
|
4364
|
+
to: result.to
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
var USDC_TYPES2 = {
|
|
3179
4368
|
TransferWithAuthorization: [
|
|
3180
4369
|
{ name: "from", type: "address" },
|
|
3181
4370
|
{ name: "to", type: "address" },
|
|
@@ -3185,7 +4374,7 @@ var USDC_TYPES = {
|
|
|
3185
4374
|
{ name: "nonce", type: "bytes32" }
|
|
3186
4375
|
]
|
|
3187
4376
|
};
|
|
3188
|
-
var withdrawCommand = new
|
|
4377
|
+
var withdrawCommand = new Command64("withdraw").description(
|
|
3189
4378
|
"Withdraw the payment token (USDC on Base, OUSD on Tempo) to the registered withdrawal address"
|
|
3190
4379
|
).argument("<amount>", "Amount in whole tokens (e.g. 5 for 5 USDC or 5 OUSD)").action(async (amount) => {
|
|
3191
4380
|
const parsed = parseFloat(amount);
|
|
@@ -3211,7 +4400,16 @@ var withdrawCommand = new Command58("withdraw").description(
|
|
|
3211
4400
|
);
|
|
3212
4401
|
return;
|
|
3213
4402
|
}
|
|
3214
|
-
|
|
4403
|
+
let withdrawalAddress;
|
|
4404
|
+
try {
|
|
4405
|
+
withdrawalAddress = await verifyWithdrawalAddress(
|
|
4406
|
+
keystore,
|
|
4407
|
+
addressResponse.withdrawalAddress
|
|
4408
|
+
);
|
|
4409
|
+
} catch (err) {
|
|
4410
|
+
renderFailure(err);
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
3215
4413
|
const { chainId } = selectedNetwork();
|
|
3216
4414
|
if (paymentProtocolOf(chainId) === "mpp") {
|
|
3217
4415
|
const { data: result2, idempotencyKey: idempotencyKey2 } = await withdrawOnTempo({
|
|
@@ -3220,10 +4418,14 @@ var withdrawCommand = new Command58("withdraw").description(
|
|
|
3220
4418
|
withdrawalAddress,
|
|
3221
4419
|
amountBaseUnits
|
|
3222
4420
|
});
|
|
3223
|
-
printResult(
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
4421
|
+
printResult(withdrawOutput(result2, chainId), { idempotencyKey: idempotencyKey2 });
|
|
4422
|
+
return;
|
|
4423
|
+
}
|
|
4424
|
+
let domain;
|
|
4425
|
+
try {
|
|
4426
|
+
domain = paymentTokenDomain(chainId);
|
|
4427
|
+
} catch (err) {
|
|
4428
|
+
renderFailure(err);
|
|
3227
4429
|
return;
|
|
3228
4430
|
}
|
|
3229
4431
|
const now = Math.floor(Date.now() / 1e3);
|
|
@@ -3233,12 +4435,12 @@ var withdrawCommand = new Command58("withdraw").description(
|
|
|
3233
4435
|
value: amountBaseUnits,
|
|
3234
4436
|
validAfter: String(now - 60),
|
|
3235
4437
|
validBefore: String(now + 300),
|
|
3236
|
-
nonce:
|
|
4438
|
+
nonce: toHex3(crypto.getRandomValues(new Uint8Array(32)))
|
|
3237
4439
|
};
|
|
3238
4440
|
const signature = await signTypedData(
|
|
3239
4441
|
{
|
|
3240
|
-
domain
|
|
3241
|
-
types:
|
|
4442
|
+
domain,
|
|
4443
|
+
types: USDC_TYPES2,
|
|
3242
4444
|
primaryType: "TransferWithAuthorization",
|
|
3243
4445
|
message: authorization
|
|
3244
4446
|
},
|
|
@@ -3253,16 +4455,13 @@ var withdrawCommand = new Command58("withdraw").description(
|
|
|
3253
4455
|
signature
|
|
3254
4456
|
}
|
|
3255
4457
|
);
|
|
3256
|
-
printResult(
|
|
3257
|
-
{ txHash: result.txHash, amountBaseUnits: result.amountBaseUnits, to: result.to },
|
|
3258
|
-
{ idempotencyKey }
|
|
3259
|
-
);
|
|
4458
|
+
printResult(withdrawOutput(result, chainId), { idempotencyKey });
|
|
3260
4459
|
});
|
|
3261
4460
|
|
|
3262
4461
|
// src/commands/encrypt.ts
|
|
3263
|
-
import { Command as
|
|
4462
|
+
import { Command as Command65 } from "commander";
|
|
3264
4463
|
import { promises as fs2 } from "fs";
|
|
3265
|
-
var encryptCommand = new
|
|
4464
|
+
var encryptCommand = new Command65("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) => {
|
|
3266
4465
|
let plaintext;
|
|
3267
4466
|
try {
|
|
3268
4467
|
plaintext = await fs2.readFile(file);
|
|
@@ -3310,9 +4509,9 @@ var encryptCommand = new Command59("encrypt").description("Encrypt a file with E
|
|
|
3310
4509
|
});
|
|
3311
4510
|
|
|
3312
4511
|
// src/commands/decrypt.ts
|
|
3313
|
-
import { Command as
|
|
4512
|
+
import { Command as Command66 } from "commander";
|
|
3314
4513
|
import { promises as fs3 } from "fs";
|
|
3315
|
-
var decryptCommand = new
|
|
4514
|
+
var decryptCommand = new Command66("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) => {
|
|
3316
4515
|
let ciphertext;
|
|
3317
4516
|
try {
|
|
3318
4517
|
ciphertext = await fs3.readFile(file);
|
|
@@ -3352,7 +4551,7 @@ var decryptCommand = new Command60("decrypt").description("Decrypt a file using
|
|
|
3352
4551
|
});
|
|
3353
4552
|
|
|
3354
4553
|
// src/commands/xmtp.ts
|
|
3355
|
-
import { Command as
|
|
4554
|
+
import { Command as Command67 } from "commander";
|
|
3356
4555
|
|
|
3357
4556
|
// src/lib/xmtp-client.ts
|
|
3358
4557
|
import path2 from "path";
|
|
@@ -3457,7 +4656,7 @@ function shouldHandleEnvelope(envelope, options) {
|
|
|
3457
4656
|
options.cache.add(key);
|
|
3458
4657
|
return true;
|
|
3459
4658
|
}
|
|
3460
|
-
function
|
|
4659
|
+
function sleep2(ms) {
|
|
3461
4660
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3462
4661
|
}
|
|
3463
4662
|
async function runStreamWithReconnect(options) {
|
|
@@ -3487,7 +4686,7 @@ async function runStreamWithReconnect(options) {
|
|
|
3487
4686
|
throw error;
|
|
3488
4687
|
}
|
|
3489
4688
|
options.onReconnect?.(reconnectAttempt, error);
|
|
3490
|
-
await
|
|
4689
|
+
await sleep2(backoffMs(reconnectAttempt));
|
|
3491
4690
|
}
|
|
3492
4691
|
}
|
|
3493
4692
|
}
|
|
@@ -3633,7 +4832,7 @@ function toTransportError(error, fallbackMessage) {
|
|
|
3633
4832
|
const message = error instanceof Error && error.message.length > 0 ? error.message : `${fallbackMessage} (${String(error)})`;
|
|
3634
4833
|
return new XmtpTransportError(message, category, error);
|
|
3635
4834
|
}
|
|
3636
|
-
function
|
|
4835
|
+
function sleep3(ms) {
|
|
3637
4836
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3638
4837
|
}
|
|
3639
4838
|
function parseRetryAttempts() {
|
|
@@ -3661,7 +4860,7 @@ async function withRetry(operation, maxAttempts) {
|
|
|
3661
4860
|
if (!mapped.retryable || attempt >= maxAttempts) {
|
|
3662
4861
|
throw mapped;
|
|
3663
4862
|
}
|
|
3664
|
-
await
|
|
4863
|
+
await sleep3(sendBackoffMs(attempt));
|
|
3665
4864
|
}
|
|
3666
4865
|
}
|
|
3667
4866
|
throw new XmtpTransportError("XMTP retry attempts exhausted", "non-retryable");
|
|
@@ -4115,7 +5314,7 @@ function getDefaultQueryTimeoutMs() {
|
|
|
4115
5314
|
}
|
|
4116
5315
|
return Math.floor(parsed);
|
|
4117
5316
|
}
|
|
4118
|
-
var xmtpCommand = new
|
|
5317
|
+
var xmtpCommand = new Command67("xmtp").description("Manage XMTP messaging for this agent");
|
|
4119
5318
|
xmtpCommand.command("init").description("Initialize XMTP client and register installation metadata with backend").action(async () => {
|
|
4120
5319
|
const keystore = await loadKeystore();
|
|
4121
5320
|
const client = await createXmtpClient({
|
|
@@ -4352,7 +5551,7 @@ xmtpCommand.command("purge").description("Revoke stale XMTP installations that h
|
|
|
4352
5551
|
});
|
|
4353
5552
|
|
|
4354
5553
|
// src/commands/daemon.ts
|
|
4355
|
-
import { Command as
|
|
5554
|
+
import { Command as Command68 } from "commander";
|
|
4356
5555
|
function diffTaskStatuses(prev, next) {
|
|
4357
5556
|
const changes = [];
|
|
4358
5557
|
for (const [taskId, newStatus] of next) {
|
|
@@ -4380,7 +5579,7 @@ function sleepOrAbort(ms, signal) {
|
|
|
4380
5579
|
});
|
|
4381
5580
|
}
|
|
4382
5581
|
var MAX_SEEN_TASK_IDS = 2e3;
|
|
4383
|
-
var daemonCommand = new
|
|
5582
|
+
var daemonCommand = new Command68("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(
|
|
4384
5583
|
"--auction-poll-interval <ms>",
|
|
4385
5584
|
"Poll interval for clock-based auction tasks (dutch/reverse_dutch) in milliseconds",
|
|
4386
5585
|
"15000"
|
|
@@ -4713,11 +5912,11 @@ var daemonCommand = new Command62("daemon").description("Long-running agent daem
|
|
|
4713
5912
|
);
|
|
4714
5913
|
|
|
4715
5914
|
// src/commands/email/index.ts
|
|
4716
|
-
import { Command as
|
|
5915
|
+
import { Command as Command77 } from "commander";
|
|
4717
5916
|
|
|
4718
5917
|
// src/commands/email/register.ts
|
|
4719
|
-
import { Command as
|
|
4720
|
-
var registerCommand = new
|
|
5918
|
+
import { Command as Command69 } from "commander";
|
|
5919
|
+
var registerCommand = new Command69("register").description("Register an email address for this agent").requiredOption("--username <name>", "Desired username (e.g. myagent)").action(async (opts) => {
|
|
4721
5920
|
const check = await apiGet(
|
|
4722
5921
|
`/api/emails/check-username?username=${encodeURIComponent(opts.username)}`
|
|
4723
5922
|
);
|
|
@@ -4738,8 +5937,8 @@ var registerCommand = new Command63("register").description("Register an email a
|
|
|
4738
5937
|
});
|
|
4739
5938
|
|
|
4740
5939
|
// src/commands/email/inbox.ts
|
|
4741
|
-
import { Command as
|
|
4742
|
-
var inboxCommand2 = new
|
|
5940
|
+
import { Command as Command70 } from "commander";
|
|
5941
|
+
var inboxCommand2 = new Command70("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) => {
|
|
4743
5942
|
const keystore = await loadKeystore();
|
|
4744
5943
|
const params = new URLSearchParams({
|
|
4745
5944
|
deviceId: keystore.deviceId,
|
|
@@ -4754,8 +5953,8 @@ var inboxCommand2 = new Command64("inbox").description("List emails in your inbo
|
|
|
4754
5953
|
});
|
|
4755
5954
|
|
|
4756
5955
|
// src/commands/email/read.ts
|
|
4757
|
-
import { Command as
|
|
4758
|
-
var readCommand = new
|
|
5956
|
+
import { Command as Command71 } from "commander";
|
|
5957
|
+
var readCommand = new Command71("read").description("Read an email by ID (marks it as read)").argument("<id>", "Email ID").action(async (id) => {
|
|
4759
5958
|
const keystore = await loadKeystore();
|
|
4760
5959
|
const params = new URLSearchParams({
|
|
4761
5960
|
deviceId: keystore.deviceId,
|
|
@@ -4767,8 +5966,8 @@ var readCommand = new Command65("read").description("Read an email by ID (marks
|
|
|
4767
5966
|
});
|
|
4768
5967
|
|
|
4769
5968
|
// src/commands/email/send.ts
|
|
4770
|
-
import { Command as
|
|
4771
|
-
var sendCommand = new
|
|
5969
|
+
import { Command as Command72 } from "commander";
|
|
5970
|
+
var sendCommand = new Command72("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) => {
|
|
4772
5971
|
const keystore = await loadKeystore();
|
|
4773
5972
|
const { data: result, idempotencyKey } = await apiPost("/api/emails/send", {
|
|
4774
5973
|
deviceId: keystore.deviceId,
|
|
@@ -4781,8 +5980,8 @@ var sendCommand = new Command66("send").description("Send an email").requiredOpt
|
|
|
4781
5980
|
});
|
|
4782
5981
|
|
|
4783
5982
|
// src/commands/email/reply.ts
|
|
4784
|
-
import { Command as
|
|
4785
|
-
var replyCommand = new
|
|
5983
|
+
import { Command as Command73 } from "commander";
|
|
5984
|
+
var replyCommand = new Command73("reply").description("Reply to an email").argument("<id>", "Email ID to reply to").requiredOption("--body <text>", "Reply body text").action(async (id, opts) => {
|
|
4786
5985
|
const keystore = await loadKeystore();
|
|
4787
5986
|
const params = new URLSearchParams({
|
|
4788
5987
|
deviceId: keystore.deviceId,
|
|
@@ -4804,8 +6003,8 @@ var replyCommand = new Command67("reply").description("Reply to an email").argum
|
|
|
4804
6003
|
});
|
|
4805
6004
|
|
|
4806
6005
|
// src/commands/email/delete.ts
|
|
4807
|
-
import { Command as
|
|
4808
|
-
var deleteCommand = new
|
|
6006
|
+
import { Command as Command74 } from "commander";
|
|
6007
|
+
var deleteCommand = new Command74("delete").description("Delete an email by ID").argument("<id>", "Email ID").action(async (id) => {
|
|
4809
6008
|
const keystore = await loadKeystore();
|
|
4810
6009
|
const { data: result, idempotencyKey } = await apiPost(
|
|
4811
6010
|
"/api/emails/delete",
|
|
@@ -4819,15 +6018,15 @@ var deleteCommand = new Command68("delete").description("Delete an email by ID")
|
|
|
4819
6018
|
});
|
|
4820
6019
|
|
|
4821
6020
|
// src/commands/email/address.ts
|
|
4822
|
-
import { Command as
|
|
4823
|
-
var addressCommand2 = new
|
|
6021
|
+
import { Command as Command75 } from "commander";
|
|
6022
|
+
var addressCommand2 = new Command75("address").description("Show your registered email address").action(async () => {
|
|
4824
6023
|
const keystore = await loadKeystore();
|
|
4825
6024
|
const result = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
4826
6025
|
printResult({ emailAddress: result.emailAddress ?? null });
|
|
4827
6026
|
});
|
|
4828
6027
|
|
|
4829
6028
|
// src/commands/email/mark-read.ts
|
|
4830
|
-
import { Command as
|
|
6029
|
+
import { Command as Command76 } from "commander";
|
|
4831
6030
|
async function setReadStatus(id, read) {
|
|
4832
6031
|
const keystore = await loadKeystore();
|
|
4833
6032
|
const { data: result, idempotencyKey } = await apiPost(
|
|
@@ -4841,12 +6040,12 @@ async function setReadStatus(id, read) {
|
|
|
4841
6040
|
);
|
|
4842
6041
|
printResult({ id: result.id, isRead: result.isRead }, { idempotencyKey });
|
|
4843
6042
|
}
|
|
4844
|
-
var markReadCommand = new
|
|
6043
|
+
var markReadCommand = new Command76("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) => {
|
|
4845
6044
|
await setReadStatus(id, !opts.unread);
|
|
4846
6045
|
});
|
|
4847
6046
|
|
|
4848
6047
|
// src/commands/email/index.ts
|
|
4849
|
-
var emailCommand = new
|
|
6048
|
+
var emailCommand = new Command77("email").description("Email management commands");
|
|
4850
6049
|
emailCommand.addCommand(registerCommand);
|
|
4851
6050
|
emailCommand.addCommand(inboxCommand2);
|
|
4852
6051
|
emailCommand.addCommand(readCommand);
|
|
@@ -4856,12 +6055,158 @@ emailCommand.addCommand(deleteCommand);
|
|
|
4856
6055
|
emailCommand.addCommand(addressCommand2);
|
|
4857
6056
|
emailCommand.addCommand(markReadCommand);
|
|
4858
6057
|
|
|
6058
|
+
// src/commands/bug/index.ts
|
|
6059
|
+
import { Command as Command81 } from "commander";
|
|
6060
|
+
|
|
6061
|
+
// src/commands/bug/list.ts
|
|
6062
|
+
import { Command as Command78 } from "commander";
|
|
6063
|
+
var listCommand = new Command78("list").description("List the bug reports you submitted and their status").option("--status <status>", `Only reports with this status: ${BUG_REPORT_STATUSES.join(", ")}`).option("--limit <n>", "Maximum reports to return (1-100)", "50").action(async (opts) => {
|
|
6064
|
+
if (opts.status && !BUG_REPORT_STATUSES.includes(opts.status)) {
|
|
6065
|
+
printError(`--status must be one of ${BUG_REPORT_STATUSES.join(", ")}`);
|
|
6066
|
+
return;
|
|
6067
|
+
}
|
|
6068
|
+
const limit = Number(opts.limit);
|
|
6069
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
6070
|
+
printError("--limit must be an integer from 1 to 100");
|
|
6071
|
+
return;
|
|
6072
|
+
}
|
|
6073
|
+
const auth = await signReadAuth();
|
|
6074
|
+
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
6075
|
+
printError("Listing bug reports needs a wallet. Run `taskmarket init` first.");
|
|
6076
|
+
return;
|
|
6077
|
+
}
|
|
6078
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
6079
|
+
if (opts.status) params.set("status", opts.status);
|
|
6080
|
+
try {
|
|
6081
|
+
printResult(
|
|
6082
|
+
await apiGet(`/api/bug-reports/mine?${params.toString()}`, { headers: auth.headers })
|
|
6083
|
+
);
|
|
6084
|
+
} catch (error) {
|
|
6085
|
+
return renderFailure(error);
|
|
6086
|
+
}
|
|
6087
|
+
});
|
|
6088
|
+
|
|
6089
|
+
// src/commands/bug/show.ts
|
|
6090
|
+
import { Command as Command79 } from "commander";
|
|
6091
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
6092
|
+
var showCommand = new Command79("show").description("Show one of your bug reports, its status and any linked GitHub issue").argument("<id>", "Bug report id").action(async (id) => {
|
|
6093
|
+
if (!UUID.test(id)) {
|
|
6094
|
+
printError("Bug report id must be a UUID");
|
|
6095
|
+
return;
|
|
6096
|
+
}
|
|
6097
|
+
const auth = await signReadAuth();
|
|
6098
|
+
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
6099
|
+
printError("Reading a bug report needs a wallet. Run `taskmarket init` first.");
|
|
6100
|
+
return;
|
|
6101
|
+
}
|
|
6102
|
+
try {
|
|
6103
|
+
printResult(await apiGet(`/api/bug-reports/${id}`, { headers: auth.headers }));
|
|
6104
|
+
} catch (error) {
|
|
6105
|
+
return renderFailure(error);
|
|
6106
|
+
}
|
|
6107
|
+
});
|
|
6108
|
+
|
|
6109
|
+
// src/commands/bug/submit.ts
|
|
6110
|
+
import { Command as Command80 } from "commander";
|
|
6111
|
+
|
|
6112
|
+
// src/commands/bug/context.ts
|
|
6113
|
+
import os from "os";
|
|
6114
|
+
function collectBugContext(cliVersion2, extra) {
|
|
6115
|
+
return {
|
|
6116
|
+
cliVersion: cliVersion2,
|
|
6117
|
+
os: `${os.platform()} ${os.release()} ${os.arch()}`,
|
|
6118
|
+
nodeVersion: process.version,
|
|
6119
|
+
network: selectedNetwork().name,
|
|
6120
|
+
...extra.taskId ? { taskId: extra.taskId } : {},
|
|
6121
|
+
...extra.txHash ? { txHash: extra.txHash } : {}
|
|
6122
|
+
};
|
|
6123
|
+
}
|
|
6124
|
+
function cliVersionOf(command) {
|
|
6125
|
+
let root = command;
|
|
6126
|
+
while (root.parent) root = root.parent;
|
|
6127
|
+
return root.version() ?? "unknown";
|
|
6128
|
+
}
|
|
6129
|
+
|
|
6130
|
+
// src/commands/bug/submit.ts
|
|
6131
|
+
async function readStdin() {
|
|
6132
|
+
const chunks = [];
|
|
6133
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
6134
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
6135
|
+
}
|
|
6136
|
+
var submitCommand = new Command80("submit").description("Report a Taskmarket bug; CLI version, OS, Node version and network are attached").requiredOption("--title <text>", "Short summary (at most 200 characters)").option(
|
|
6137
|
+
"--description <text>",
|
|
6138
|
+
'What happened and how to reproduce it; read from stdin when omitted or "-"'
|
|
6139
|
+
).option("--severity <level>", `How bad it is: ${BUG_REPORT_SEVERITIES.join(", ")}`, "medium").option("--task <id>", "Task the bug happened on").option("--tx <hash>", "Transaction hash involved").option(
|
|
6140
|
+
"--include-last-error",
|
|
6141
|
+
"Attach the last failed taskmarket command and its error (secrets already removed)"
|
|
6142
|
+
).action(async function(opts) {
|
|
6143
|
+
let description = opts.description;
|
|
6144
|
+
if (description === void 0 || description === "-") {
|
|
6145
|
+
if (process.stdin.isTTY) {
|
|
6146
|
+
printError("Pass --description or pipe the description on stdin");
|
|
6147
|
+
return;
|
|
6148
|
+
}
|
|
6149
|
+
description = await readStdin();
|
|
6150
|
+
}
|
|
6151
|
+
const context = collectBugContext(cliVersionOf(this), { taskId: opts.task, txHash: opts.tx });
|
|
6152
|
+
if (opts.includeLastError) {
|
|
6153
|
+
const lastError = readLastError();
|
|
6154
|
+
if (!lastError) {
|
|
6155
|
+
printError("No failed command is recorded yet; run without --include-last-error");
|
|
6156
|
+
return;
|
|
6157
|
+
}
|
|
6158
|
+
context.command = lastError.command;
|
|
6159
|
+
context.error = JSON.stringify({
|
|
6160
|
+
message: lastError.message,
|
|
6161
|
+
code: lastError.code,
|
|
6162
|
+
status: lastError.status,
|
|
6163
|
+
at: lastError.at,
|
|
6164
|
+
cliVersion: lastError.cliVersion
|
|
6165
|
+
});
|
|
6166
|
+
}
|
|
6167
|
+
const parsed = SubmitBugReportInputSchema.safeParse({
|
|
6168
|
+
title: opts.title,
|
|
6169
|
+
description,
|
|
6170
|
+
severity: opts.severity,
|
|
6171
|
+
source: "cli",
|
|
6172
|
+
context
|
|
6173
|
+
});
|
|
6174
|
+
if (!parsed.success) {
|
|
6175
|
+
const issue = parsed.error.issues[0];
|
|
6176
|
+
printError(`Invalid bug report: ${issue.path.join(".") || "input"}: ${issue.message}`);
|
|
6177
|
+
return;
|
|
6178
|
+
}
|
|
6179
|
+
const auth = await signReadAuth();
|
|
6180
|
+
if (!auth || Object.keys(auth.headers).length === 0) {
|
|
6181
|
+
printError("Reporting a bug needs a wallet. Run `taskmarket init` first.");
|
|
6182
|
+
return;
|
|
6183
|
+
}
|
|
6184
|
+
try {
|
|
6185
|
+
const { data, idempotencyKey } = await apiPost(
|
|
6186
|
+
"/api/bug-reports",
|
|
6187
|
+
parsed.data,
|
|
6188
|
+
{ headers: auth.headers }
|
|
6189
|
+
);
|
|
6190
|
+
printResult(data, { idempotencyKey });
|
|
6191
|
+
} catch (error) {
|
|
6192
|
+
return renderFailure(error);
|
|
6193
|
+
}
|
|
6194
|
+
});
|
|
6195
|
+
|
|
6196
|
+
// src/commands/bug/index.ts
|
|
6197
|
+
var bugCommand = new Command81("bug").description(
|
|
6198
|
+
"Report Taskmarket bugs and follow their status"
|
|
6199
|
+
);
|
|
6200
|
+
bugCommand.addCommand(submitCommand);
|
|
6201
|
+
bugCommand.addCommand(listCommand);
|
|
6202
|
+
bugCommand.addCommand(showCommand);
|
|
6203
|
+
|
|
4859
6204
|
// src/commands/requester/index.ts
|
|
4860
|
-
import { Command as
|
|
6205
|
+
import { Command as Command83 } from "commander";
|
|
4861
6206
|
|
|
4862
6207
|
// src/commands/requester/stats.ts
|
|
4863
|
-
import { Command as
|
|
4864
|
-
var requesterStatsCmd = new
|
|
6208
|
+
import { Command as Command82 } from "commander";
|
|
6209
|
+
var requesterStatsCmd = new Command82("stats").description("Get requester reputation stats for an address").argument("<address>", "Wallet address of the requester").action(async (address) => {
|
|
4865
6210
|
if (!/^0x[0-9a-fA-F]{40}$/.test(address)) {
|
|
4866
6211
|
printError("Address must be a 0x-prefixed 20-byte hex string");
|
|
4867
6212
|
return;
|
|
@@ -4875,13 +6220,13 @@ var requesterStatsCmd = new Command72("stats").description("Get requester reputa
|
|
|
4875
6220
|
});
|
|
4876
6221
|
|
|
4877
6222
|
// src/commands/requester/index.ts
|
|
4878
|
-
var requesterCmd = new
|
|
6223
|
+
var requesterCmd = new Command83("requester").description("Requester reputation commands").addCommand(requesterStatsCmd);
|
|
4879
6224
|
|
|
4880
6225
|
// src/commands/x402/index.ts
|
|
4881
|
-
import { Command as
|
|
6226
|
+
import { Command as Command87 } from "commander";
|
|
4882
6227
|
|
|
4883
6228
|
// src/commands/x402/payments.ts
|
|
4884
|
-
import { Command as
|
|
6229
|
+
import { Command as Command84, Option as Option4 } from "commander";
|
|
4885
6230
|
import { createInterface as createInterface4 } from "readline";
|
|
4886
6231
|
var PAYMENT_STATES = [
|
|
4887
6232
|
"reserved",
|
|
@@ -4907,10 +6252,10 @@ async function confirmManualResolution() {
|
|
|
4907
6252
|
readline.close();
|
|
4908
6253
|
return answer.trim().toLowerCase() === "resolve";
|
|
4909
6254
|
}
|
|
4910
|
-
var x402PaymentsCommand = new
|
|
6255
|
+
var x402PaymentsCommand = new Command84("payments").description(
|
|
4911
6256
|
"Inspect and reconcile X402 Pay payment records"
|
|
4912
6257
|
);
|
|
4913
|
-
x402PaymentsCommand.command("list").description("List current payment records").addOption(new
|
|
6258
|
+
x402PaymentsCommand.command("list").description("List current payment records").addOption(new Option4("--state <state>", "Filter by state").choices(PAYMENT_STATES)).action(async (options) => {
|
|
4914
6259
|
const payments = await listX402Payments({ state: options.state }, getX402JournalPath());
|
|
4915
6260
|
printResult({ payments });
|
|
4916
6261
|
});
|
|
@@ -4936,7 +6281,7 @@ x402PaymentsCommand.command("resolve").description("Manually record an externall
|
|
|
4936
6281
|
|
|
4937
6282
|
// src/commands/x402/policy.ts
|
|
4938
6283
|
import { promises as fs4 } from "fs";
|
|
4939
|
-
import { Command as
|
|
6284
|
+
import { Command as Command85 } from "commander";
|
|
4940
6285
|
import { createInterface as createInterface5 } from "readline";
|
|
4941
6286
|
async function confirmUnattendedRule(rule) {
|
|
4942
6287
|
if (!process.stdin.isTTY) {
|
|
@@ -4962,7 +6307,7 @@ async function confirmUnattendedRule(rule) {
|
|
|
4962
6307
|
readline.close();
|
|
4963
6308
|
return answer.trim().toLowerCase() === "authorize";
|
|
4964
6309
|
}
|
|
4965
|
-
var x402PolicyCommand = new
|
|
6310
|
+
var x402PolicyCommand = new Command85("policy").description(
|
|
4966
6311
|
"Manage local X402 Pay spending policy"
|
|
4967
6312
|
);
|
|
4968
6313
|
x402PolicyCommand.command("init").description("Create a deny-all policy file").action(async () => {
|
|
@@ -4998,17 +6343,17 @@ for (const enabled of [true, false]) {
|
|
|
4998
6343
|
}
|
|
4999
6344
|
|
|
5000
6345
|
// src/commands/x402/request.ts
|
|
5001
|
-
import { Command as
|
|
5002
|
-
function
|
|
6346
|
+
import { Command as Command86, Option as Option5 } from "commander";
|
|
6347
|
+
function collect3(value, previous) {
|
|
5003
6348
|
return [...previous, value];
|
|
5004
6349
|
}
|
|
5005
6350
|
function confirm(lines) {
|
|
5006
6351
|
return confirmAtTerminal(lines, "use --non-interactive with policy");
|
|
5007
6352
|
}
|
|
5008
|
-
var x402RequestCommand = new
|
|
6353
|
+
var x402RequestCommand = new Command86("request").description("Request and pay for a direct x402 HTTP resource (X402 Pay)").argument("<url>", "HTTPS resource URL").addOption(new Option5("--method <method>", "HTTP method").choices(["GET", "POST"]).default("GET")).option("--json <json>", "Inline JSON POST body").option("--body-file <path>", "Read JSON POST body from a file").option("--headers-file <path>", "Read request headers from an owner-only JSON file").option(
|
|
5009
6354
|
"--header-env <header=ENV_VAR>",
|
|
5010
6355
|
"Read one request header from an environment variable (repeatable)",
|
|
5011
|
-
|
|
6356
|
+
collect3,
|
|
5012
6357
|
[]
|
|
5013
6358
|
).option("--output <path>", "Write response bytes to a new file").option("--non-interactive", "Authorize only through a persistent unattended policy rule").option("--policy <ruleId>", "Restrict authorization to one policy rule").option(
|
|
5014
6359
|
"--invocation-id <id>",
|
|
@@ -5045,7 +6390,7 @@ var x402RequestCommand = new Command76("request").description("Request and pay f
|
|
|
5045
6390
|
`Asset: ${details.asset}`,
|
|
5046
6391
|
`Spender: ${details.spender}`,
|
|
5047
6392
|
`Bounded allowance: ${details.allowance} atomic units`,
|
|
5048
|
-
`Estimated maximum gas: ${details.estimatedGasWei} wei`
|
|
6393
|
+
details.estimatedGasUsd ? `Estimated maximum gas: ${details.estimatedGasUsd} (paid in the fee token)` : `Estimated maximum gas: ${details.estimatedGasWei} wei`
|
|
5049
6394
|
])
|
|
5050
6395
|
});
|
|
5051
6396
|
printResult(result);
|
|
@@ -5053,7 +6398,7 @@ var x402RequestCommand = new Command76("request").description("Request and pay f
|
|
|
5053
6398
|
);
|
|
5054
6399
|
|
|
5055
6400
|
// src/commands/x402/index.ts
|
|
5056
|
-
var x402Command = new
|
|
6401
|
+
var x402Command = new Command87("x402").description(
|
|
5057
6402
|
"Pay x402 services with local spending policies (X402 Pay)"
|
|
5058
6403
|
);
|
|
5059
6404
|
x402Command.addCommand(x402RequestCommand);
|
|
@@ -5061,11 +6406,11 @@ x402Command.addCommand(x402PolicyCommand);
|
|
|
5061
6406
|
x402Command.addCommand(x402PaymentsCommand);
|
|
5062
6407
|
|
|
5063
6408
|
// src/commands/sponsored-task/index.ts
|
|
5064
|
-
import { Command as
|
|
6409
|
+
import { Command as Command102 } from "commander";
|
|
5065
6410
|
|
|
5066
6411
|
// src/commands/sponsored-task/create.ts
|
|
5067
|
-
import { Command as
|
|
5068
|
-
import { toHex as
|
|
6412
|
+
import { Command as Command88 } from "commander";
|
|
6413
|
+
import { toHex as toHex4 } from "viem";
|
|
5069
6414
|
|
|
5070
6415
|
// ../../packages/contracts/abi/generated/SponsoredTasksVault.ts
|
|
5071
6416
|
var SponsoredTasksVaultABI = [
|
|
@@ -8186,7 +9531,7 @@ import {
|
|
|
8186
9531
|
createPublicClient,
|
|
8187
9532
|
createWalletClient,
|
|
8188
9533
|
defineChain,
|
|
8189
|
-
http
|
|
9534
|
+
http
|
|
8190
9535
|
} from "viem";
|
|
8191
9536
|
function resolveRpcUrl() {
|
|
8192
9537
|
const value = process.env["TASKMARKET_RPC_URL"]?.trim();
|
|
@@ -8205,13 +9550,13 @@ async function createSponsoredTaskVaultChainClients(keystore, chainId) {
|
|
|
8205
9550
|
nativeCurrency: { name: "Native gas token", symbol: "GAS", decimals: 18 },
|
|
8206
9551
|
rpcUrls: { default: { http: [rpcUrl] } }
|
|
8207
9552
|
});
|
|
8208
|
-
const publicClient = createPublicClient({ chain, transport:
|
|
9553
|
+
const publicClient = createPublicClient({ chain, transport: http(rpcUrl) });
|
|
8209
9554
|
const rpcChainId = await publicClient.getChainId();
|
|
8210
9555
|
if (rpcChainId !== chainId) {
|
|
8211
9556
|
throw new Error(`TASKMARKET_RPC_URL points at chain ${rpcChainId}, vault needs ${chainId}`);
|
|
8212
9557
|
}
|
|
8213
9558
|
const account = await createWalletAccountFromKeystore(keystore);
|
|
8214
|
-
const walletClient = createWalletClient({ account, chain, transport:
|
|
9559
|
+
const walletClient = createWalletClient({ account, chain, transport: http(rpcUrl) });
|
|
8215
9560
|
return { account, chain, publicClient, walletClient };
|
|
8216
9561
|
}
|
|
8217
9562
|
async function writeSponsoredTaskVaultContract(input) {
|
|
@@ -8286,7 +9631,7 @@ async function approveSponsoredTaskSpend(input) {
|
|
|
8286
9631
|
function isValidAddress4(addr) {
|
|
8287
9632
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8288
9633
|
}
|
|
8289
|
-
var sponsoredTaskCreateCommand = new
|
|
9634
|
+
var sponsoredTaskCreateCommand = new Command88("create").description("Create a new Sponsored Task vault for a project token").requiredOption("--factory <address>", "SponsoredTaskFactory contract address").requiredOption("--chain-id <id>", "Chain id the factory is deployed on").requiredOption("--token <address>", "Project ERC-20 token address to fund the vault with").option("--owner <address>", "Vault owner (defaults to your own wallet)").action(async (opts) => {
|
|
8290
9635
|
if (!isValidAddress4(opts.factory) || !isValidAddress4(opts.token)) {
|
|
8291
9636
|
printError("Invalid Ethereum address for --factory or --token");
|
|
8292
9637
|
return;
|
|
@@ -8308,7 +9653,7 @@ var sponsoredTaskCreateCommand = new Command78("create").description("Create a n
|
|
|
8308
9653
|
chainId
|
|
8309
9654
|
);
|
|
8310
9655
|
const vaultOwner = opts.owner ?? account.address;
|
|
8311
|
-
const userSalt =
|
|
9656
|
+
const userSalt = toHex4(crypto.getRandomValues(new Uint8Array(32)));
|
|
8312
9657
|
const { txHash, result } = await writeSponsoredTaskVaultContract({
|
|
8313
9658
|
account,
|
|
8314
9659
|
publicClient,
|
|
@@ -8323,11 +9668,11 @@ var sponsoredTaskCreateCommand = new Command78("create").description("Create a n
|
|
|
8323
9668
|
});
|
|
8324
9669
|
|
|
8325
9670
|
// src/commands/sponsored-task/fund.ts
|
|
8326
|
-
import { Command as
|
|
9671
|
+
import { Command as Command89 } from "commander";
|
|
8327
9672
|
function isValidAddress5(addr) {
|
|
8328
9673
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8329
9674
|
}
|
|
8330
|
-
var sponsoredTaskFundCommand = new
|
|
9675
|
+
var sponsoredTaskFundCommand = new Command89("fund").description("Fund a Sponsored Task vault with its project token (base units)").requiredOption("--vault <address>", "Vault address").requiredOption("--token <address>", "Project ERC-20 token address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to fund, in the token base units").action(async (opts) => {
|
|
8331
9676
|
if (!isValidAddress5(opts.vault) || !isValidAddress5(opts.token)) {
|
|
8332
9677
|
printError("Invalid Ethereum address for --vault or --token");
|
|
8333
9678
|
return;
|
|
@@ -8366,7 +9711,7 @@ var sponsoredTaskFundCommand = new Command79("fund").description("Fund a Sponsor
|
|
|
8366
9711
|
});
|
|
8367
9712
|
|
|
8368
9713
|
// src/commands/sponsored-task/managers.ts
|
|
8369
|
-
import { Command as
|
|
9714
|
+
import { Command as Command90 } from "commander";
|
|
8370
9715
|
function isValidAddress6(addr) {
|
|
8371
9716
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8372
9717
|
}
|
|
@@ -8412,7 +9757,7 @@ async function configure(opts) {
|
|
|
8412
9757
|
});
|
|
8413
9758
|
printResult({ txHash, manager: opts.manager, spendCap: cap.toString(), active: opts.active });
|
|
8414
9759
|
}
|
|
8415
|
-
var sponsoredTaskManagersCommand = new
|
|
9760
|
+
var sponsoredTaskManagersCommand = new Command90("managers").description(
|
|
8416
9761
|
"Manage authorized managers for a Sponsored Task vault"
|
|
8417
9762
|
);
|
|
8418
9763
|
sponsoredTaskManagersCommand.command("add").description("Authorize a manager with a token-denominated spend cap").requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--manager <address>", "Manager address to authorize").requiredOption("--cap <baseUnits>", "Spend cap, in the project token base units").action((opts) => configure({ ...opts, active: true }));
|
|
@@ -8423,8 +9768,8 @@ sponsoredTaskManagersCommand.command("list").description("List a vault authorize
|
|
|
8423
9768
|
});
|
|
8424
9769
|
|
|
8425
9770
|
// src/commands/sponsored-task/managed.ts
|
|
8426
|
-
import { Command as
|
|
8427
|
-
var sponsoredTaskManagedCommand = new
|
|
9771
|
+
import { Command as Command91 } from "commander";
|
|
9772
|
+
var sponsoredTaskManagedCommand = new Command91("managed").description(
|
|
8428
9773
|
"List the active Sponsored Task vaults an address can fund tasks from as an active manager (defaults to your wallet)"
|
|
8429
9774
|
).option("--address <address>", "Manager address (defaults to your wallet)").option("--limit <n>", "Max vaults to return (1-100)", "50").option("--cursor <vaultId>", "Pagination cursor from a previous nextCursor").action(async (opts) => {
|
|
8430
9775
|
let address = opts.address;
|
|
@@ -8454,7 +9799,7 @@ var sponsoredTaskManagedCommand = new Command81("managed").description(
|
|
|
8454
9799
|
});
|
|
8455
9800
|
|
|
8456
9801
|
// src/commands/sponsored-task/fee-bank.ts
|
|
8457
|
-
import { Command as
|
|
9802
|
+
import { Command as Command92 } from "commander";
|
|
8458
9803
|
function isValidAddress7(addr) {
|
|
8459
9804
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8460
9805
|
}
|
|
@@ -8466,7 +9811,7 @@ async function requireKeystore2() {
|
|
|
8466
9811
|
return null;
|
|
8467
9812
|
}
|
|
8468
9813
|
}
|
|
8469
|
-
var sponsoredTaskFeeBankCommand = new
|
|
9814
|
+
var sponsoredTaskFeeBankCommand = new Command92("fee-bank").description(
|
|
8470
9815
|
"Manage a manager USDC credit balance, charged by the Sponsored Task hook at task creation"
|
|
8471
9816
|
);
|
|
8472
9817
|
sponsoredTaskFeeBankCommand.command("deposit").description("Deposit USDC credit for creating sponsored tasks").requiredOption("--fee-bank <address>", "SponsoredTaskFeeBank contract address").requiredOption("--usdc <address>", "USDC token address").requiredOption("--chain-id <id>", "Chain id the fee bank is deployed on").requiredOption("--amount <baseUnits>", "Amount to deposit, in USDC base units (6 decimals)").action(async (opts) => {
|
|
@@ -8550,8 +9895,8 @@ sponsoredTaskFeeBankCommand.command("withdraw").description("Withdraw unused USD
|
|
|
8550
9895
|
);
|
|
8551
9896
|
|
|
8552
9897
|
// src/commands/sponsored-task/list.ts
|
|
8553
|
-
import { Command as
|
|
8554
|
-
var sponsoredTaskListCommand = new
|
|
9898
|
+
import { Command as Command93 } from "commander";
|
|
9899
|
+
var sponsoredTaskListCommand = new Command93("list").description("List Sponsored Task vaults").option("--limit <n>", "Max vaults to return", "50").option("--cursor <vaultId>", "Pagination cursor").option("--include-unverified", "Include vaults not yet curator-approved", false).action(async (opts) => {
|
|
8555
9900
|
const params = new URLSearchParams({ limit: opts.limit });
|
|
8556
9901
|
if (opts.cursor) params.set("cursor", opts.cursor);
|
|
8557
9902
|
if (opts.includeUnverified) params.set("includeUnverified", "true");
|
|
@@ -8560,8 +9905,8 @@ var sponsoredTaskListCommand = new Command83("list").description("List Sponsored
|
|
|
8560
9905
|
});
|
|
8561
9906
|
|
|
8562
9907
|
// src/commands/sponsored-task/settlements.ts
|
|
8563
|
-
import { Command as
|
|
8564
|
-
var sponsoredTaskSettlementsCommand = new
|
|
9908
|
+
import { Command as Command94 } from "commander";
|
|
9909
|
+
var sponsoredTaskSettlementsCommand = new Command94("settlements").description("List the settlements a Sponsored Task vault has installed, newest first").argument("<vaultId>", "Vault id").option("--limit <n>", "Max settlements to return (1-100)", "25").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(async (vaultId, opts) => {
|
|
8565
9910
|
const limit = Number(opts.limit);
|
|
8566
9911
|
if (!Number.isInteger(limit) || limit < 1 || limit > 100) {
|
|
8567
9912
|
printError("--limit must be an integer from 1 to 100");
|
|
@@ -8576,17 +9921,17 @@ var sponsoredTaskSettlementsCommand = new Command84("settlements").description("
|
|
|
8576
9921
|
});
|
|
8577
9922
|
|
|
8578
9923
|
// src/commands/sponsored-task/show.ts
|
|
8579
|
-
import { Command as
|
|
8580
|
-
var sponsoredTaskShowCommand = new
|
|
9924
|
+
import { Command as Command95 } from "commander";
|
|
9925
|
+
var sponsoredTaskShowCommand = new Command95("show").description("Show a Sponsored Task vault by id").argument("<vaultId>", "Vault id").action(async (vaultId) => {
|
|
8581
9926
|
const result = await apiGet(`/api/sponsored-task-vaults/${vaultId}`);
|
|
8582
9927
|
printResult(result);
|
|
8583
9928
|
});
|
|
8584
9929
|
|
|
8585
9930
|
// src/commands/sponsored-task/request-review.ts
|
|
8586
|
-
import { randomBytes as
|
|
8587
|
-
import { Command as
|
|
9931
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
9932
|
+
import { Command as Command96 } from "commander";
|
|
8588
9933
|
var REQUEST_TTL_SECONDS = 5 * 60;
|
|
8589
|
-
var sponsoredTaskRequestReviewCommand = new
|
|
9934
|
+
var sponsoredTaskRequestReviewCommand = new Command96("request-review").description("Ask Taskmarket curators to review a Sponsored Task vault (vault owner only)").argument("<vaultId>", "Vault id").action(async (vaultId) => {
|
|
8590
9935
|
let keystore;
|
|
8591
9936
|
try {
|
|
8592
9937
|
keystore = await loadKeystore();
|
|
@@ -8606,7 +9951,7 @@ var sponsoredTaskRequestReviewCommand = new Command86("request-review").descript
|
|
|
8606
9951
|
);
|
|
8607
9952
|
return;
|
|
8608
9953
|
}
|
|
8609
|
-
const nonce = `0x${
|
|
9954
|
+
const nonce = `0x${randomBytes3(32).toString("hex")}`;
|
|
8610
9955
|
const expiresAt = Math.floor(Date.now() / 1e3) + REQUEST_TTL_SECONDS;
|
|
8611
9956
|
const signature = await signMessage(
|
|
8612
9957
|
buildSponsoredTaskVaultReviewRequestMessage({
|
|
@@ -8643,18 +9988,18 @@ var sponsoredTaskRequestReviewCommand = new Command86("request-review").descript
|
|
|
8643
9988
|
});
|
|
8644
9989
|
|
|
8645
9990
|
// src/commands/sponsored-task/balance.ts
|
|
8646
|
-
import { Command as
|
|
8647
|
-
var sponsoredTaskBalanceCommand = new
|
|
9991
|
+
import { Command as Command97 } from "commander";
|
|
9992
|
+
var sponsoredTaskBalanceCommand = new Command97("balance").description("Show a Sponsored Task vault funded/available/reserved balances").argument("<vaultId>", "Vault id").action(async (vaultId) => {
|
|
8648
9993
|
const result = await apiGet(`/api/sponsored-task-vaults/${vaultId}/balance`);
|
|
8649
9994
|
printResult(result);
|
|
8650
9995
|
});
|
|
8651
9996
|
|
|
8652
9997
|
// src/commands/sponsored-task/withdraw.ts
|
|
8653
|
-
import { Command as
|
|
9998
|
+
import { Command as Command98 } from "commander";
|
|
8654
9999
|
function isValidAddress8(addr) {
|
|
8655
10000
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8656
10001
|
}
|
|
8657
|
-
var sponsoredTaskWithdrawCommand = new
|
|
10002
|
+
var sponsoredTaskWithdrawCommand = new Command98("withdraw").description("Withdraw unreserved project tokens from a vault (owner only)").requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").requiredOption("--amount <baseUnits>", "Amount to withdraw, in the project token base units").option("--recipient <address>", "Recipient (defaults to your own wallet)").action(async (opts) => {
|
|
8658
10003
|
if (!isValidAddress8(opts.vault) || opts.recipient && !isValidAddress8(opts.recipient)) {
|
|
8659
10004
|
printError("Invalid Ethereum address for --vault or --recipient");
|
|
8660
10005
|
return;
|
|
@@ -8684,11 +10029,11 @@ var sponsoredTaskWithdrawCommand = new Command88("withdraw").description("Withdr
|
|
|
8684
10029
|
});
|
|
8685
10030
|
|
|
8686
10031
|
// src/commands/sponsored-task/exit.ts
|
|
8687
|
-
import { Command as
|
|
10032
|
+
import { Command as Command99 } from "commander";
|
|
8688
10033
|
function isValidAddress9(addr) {
|
|
8689
10034
|
return /^0x[a-fA-F0-9]{40}$/.test(addr);
|
|
8690
10035
|
}
|
|
8691
|
-
var sponsoredTaskExitCommand = new
|
|
10036
|
+
var sponsoredTaskExitCommand = new Command99("exit").description(
|
|
8692
10037
|
"Terminally exit a vault: sweeps every reserved and unclaimed token back to you, invalidating every outstanding reservation, claim signature, and Merkle proof at once. There is no undo and no per-allocation revoke -- a worker with a pending but unclaimed entitlement gets nothing once this runs."
|
|
8693
10038
|
).requiredOption("--vault <address>", "Vault address").requiredOption("--chain-id <id>", "Chain id the vault is deployed on").option("--recipient <address>", "Recipient (defaults to your own wallet)").option("--yes", "Skip the confirmation prompt", false).action(async (opts) => {
|
|
8694
10039
|
if (!isValidAddress9(opts.vault) || opts.recipient && !isValidAddress9(opts.recipient)) {
|
|
@@ -8724,7 +10069,7 @@ var sponsoredTaskExitCommand = new Command89("exit").description(
|
|
|
8724
10069
|
});
|
|
8725
10070
|
|
|
8726
10071
|
// src/commands/sponsored-task/claim.ts
|
|
8727
|
-
import { Command as
|
|
10072
|
+
import { Command as Command100 } from "commander";
|
|
8728
10073
|
var CLAIM_TO_TYPES = {
|
|
8729
10074
|
ClaimTo: [
|
|
8730
10075
|
{ name: "vaultId", type: "bytes32" },
|
|
@@ -8745,7 +10090,7 @@ function isRetryableClaimConflict(err) {
|
|
|
8745
10090
|
return err instanceof ApiError && (err.status === 409 || err.status >= 500) && /retry/i.test(err.message);
|
|
8746
10091
|
}
|
|
8747
10092
|
async function postClaimWithRetry(path3, body, options = {}) {
|
|
8748
|
-
const
|
|
10093
|
+
const sleep4 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
8749
10094
|
const deadline = Date.now() + (options.budgetMs ?? CLAIM_RETRY_BUDGET_MS);
|
|
8750
10095
|
const idempotencyKey = resolveIdempotencyKey();
|
|
8751
10096
|
let delayMs = 500;
|
|
@@ -8754,12 +10099,12 @@ async function postClaimWithRetry(path3, body, options = {}) {
|
|
|
8754
10099
|
return await apiPost(path3, body, { idempotencyKey });
|
|
8755
10100
|
} catch (err) {
|
|
8756
10101
|
if (!isRetryableClaimConflict(err) || Date.now() + delayMs > deadline) throw err;
|
|
8757
|
-
await
|
|
10102
|
+
await sleep4(delayMs);
|
|
8758
10103
|
delayMs = Math.min(delayMs * 2, 4e3);
|
|
8759
10104
|
}
|
|
8760
10105
|
}
|
|
8761
10106
|
}
|
|
8762
|
-
var sponsoredTaskClaimCommand = new
|
|
10107
|
+
var sponsoredTaskClaimCommand = new Command100("claim").description("Claim your unclaimed Sponsored Task reward for a vault task").argument("<vaultId>", "Vault id").option(
|
|
8763
10108
|
"--task-id <id>",
|
|
8764
10109
|
"Claim the entitlement for a specific task (defaults to the first unclaimed one)"
|
|
8765
10110
|
).action(async (vaultId, opts) => {
|
|
@@ -8780,7 +10125,13 @@ var sponsoredTaskClaimCommand = new Command90("claim").description("Claim your u
|
|
|
8780
10125
|
);
|
|
8781
10126
|
return;
|
|
8782
10127
|
}
|
|
8783
|
-
|
|
10128
|
+
let destination;
|
|
10129
|
+
try {
|
|
10130
|
+
destination = await verifyWithdrawalAddress(keystore, addressResponse.withdrawalAddress);
|
|
10131
|
+
} catch (err) {
|
|
10132
|
+
renderFailure(err);
|
|
10133
|
+
return;
|
|
10134
|
+
}
|
|
8784
10135
|
const entitlements = await apiGet(
|
|
8785
10136
|
`/api/sponsored-task-vaults/${vaultId}/entitlements?workerAddress=${workerAddress}`
|
|
8786
10137
|
);
|
|
@@ -8839,10 +10190,10 @@ var sponsoredTaskClaimCommand = new Command90("claim").description("Claim your u
|
|
|
8839
10190
|
});
|
|
8840
10191
|
|
|
8841
10192
|
// src/commands/sponsored-task/rewards.ts
|
|
8842
|
-
import { Command as
|
|
10193
|
+
import { Command as Command101 } from "commander";
|
|
8843
10194
|
var REWARD_STATES = SponsoredTaskRewardStateSchema.options;
|
|
8844
10195
|
var CLAIM_STATUSES = SponsoredTaskWorkerRewardClaimStatusSchema.options;
|
|
8845
|
-
var sponsoredTaskRewardsCommand = new
|
|
10196
|
+
var sponsoredTaskRewardsCommand = new Command101("rewards").description("List Sponsored Task rewards across every vault (defaults to your wallet)").option("--address <address>", "Worker address (defaults to your wallet)").option("--state <state>", `Reward state: ${REWARD_STATES.join(", ")}`).option("--claim-status <status>", `Claim status: ${CLAIM_STATUSES.join(", ")}`).option("--limit <n>", "Max rewards to return (1-100)", "50").option("--cursor <cursor>", "Pagination cursor from a previous nextCursor").action(
|
|
8846
10197
|
async (opts) => {
|
|
8847
10198
|
let address = opts.address;
|
|
8848
10199
|
if (address === void 0) {
|
|
@@ -8882,7 +10233,7 @@ var sponsoredTaskRewardsCommand = new Command91("rewards").description("List Spo
|
|
|
8882
10233
|
);
|
|
8883
10234
|
|
|
8884
10235
|
// src/commands/sponsored-task/index.ts
|
|
8885
|
-
var sponsoredTaskCommand = new
|
|
10236
|
+
var sponsoredTaskCommand = new Command102("sponsored-task").description(
|
|
8886
10237
|
"Sponsored Task vault administration and reward claims"
|
|
8887
10238
|
);
|
|
8888
10239
|
sponsoredTaskCommand.addCommand(sponsoredTaskCreateCommand);
|
|
@@ -8903,7 +10254,8 @@ sponsoredTaskCommand.addCommand(sponsoredTaskRewardsCommand);
|
|
|
8903
10254
|
// src/index.ts
|
|
8904
10255
|
var require2 = createRequire(import.meta.url);
|
|
8905
10256
|
var { version } = require2("../package.json");
|
|
8906
|
-
var program = new
|
|
10257
|
+
var program = new Command103();
|
|
10258
|
+
setLastErrorCliVersion(version);
|
|
8907
10259
|
program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
|
|
8908
10260
|
program.option(
|
|
8909
10261
|
"--network <name>",
|
|
@@ -8923,7 +10275,7 @@ program.addCommand(walletCommand);
|
|
|
8923
10275
|
program.addCommand(addressCommand);
|
|
8924
10276
|
program.addCommand(identityCommand);
|
|
8925
10277
|
program.addCommand(statsCommand);
|
|
8926
|
-
program.addCommand(
|
|
10278
|
+
program.addCommand(taskCommand2);
|
|
8927
10279
|
program.addCommand(agentCommand);
|
|
8928
10280
|
program.addCommand(agentsCommand);
|
|
8929
10281
|
program.addCommand(inboxCommand);
|
|
@@ -8939,6 +10291,7 @@ program.addCommand(requesterCmd);
|
|
|
8939
10291
|
program.addCommand(legalCommand);
|
|
8940
10292
|
program.addCommand(x402Command);
|
|
8941
10293
|
program.addCommand(sponsoredTaskCommand);
|
|
10294
|
+
program.addCommand(bugCommand);
|
|
8942
10295
|
void (async () => {
|
|
8943
10296
|
try {
|
|
8944
10297
|
await program.parseAsync(process.argv);
|