@bountyagents/bountyagents-task 2026.2.2715 → 2026.3.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +221 -102
- package/index.ts +36 -43
- package/package.json +1 -1
- package/src/helper.ts +17 -0
- package/src/index.ts +15 -8
- package/src/publisher.ts +47 -6
- package/src/task-db-types.ts +1 -1
- package/src/types.ts +0 -3
- package/src/worker.ts +41 -4
- package/test-response.ts +43 -0
package/dist/index.js
CHANGED
|
@@ -9841,14 +9841,14 @@ var require_util = __commonJS((exports, module) => {
|
|
|
9841
9841
|
}
|
|
9842
9842
|
const port = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80;
|
|
9843
9843
|
let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port}`;
|
|
9844
|
-
let
|
|
9844
|
+
let path2 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`;
|
|
9845
9845
|
if (origin[origin.length - 1] === "/") {
|
|
9846
9846
|
origin = origin.slice(0, origin.length - 1);
|
|
9847
9847
|
}
|
|
9848
|
-
if (
|
|
9849
|
-
|
|
9848
|
+
if (path2 && path2[0] !== "/") {
|
|
9849
|
+
path2 = `/${path2}`;
|
|
9850
9850
|
}
|
|
9851
|
-
return new URL(`${origin}${
|
|
9851
|
+
return new URL(`${origin}${path2}`);
|
|
9852
9852
|
}
|
|
9853
9853
|
if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) {
|
|
9854
9854
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -10602,9 +10602,9 @@ var require_diagnostics = __commonJS((exports, module) => {
|
|
|
10602
10602
|
});
|
|
10603
10603
|
diagnosticsChannel.subscribe("undici:client:sendHeaders", (evt) => {
|
|
10604
10604
|
const {
|
|
10605
|
-
request: { method, path, origin }
|
|
10605
|
+
request: { method, path: path2, origin }
|
|
10606
10606
|
} = evt;
|
|
10607
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
10607
|
+
debugLog("sending request to %s %s%s", method, origin, path2);
|
|
10608
10608
|
});
|
|
10609
10609
|
}
|
|
10610
10610
|
var isTrackingRequestEvents = false;
|
|
@@ -10619,23 +10619,23 @@ var require_diagnostics = __commonJS((exports, module) => {
|
|
|
10619
10619
|
isTrackingRequestEvents = true;
|
|
10620
10620
|
diagnosticsChannel.subscribe("undici:request:headers", (evt) => {
|
|
10621
10621
|
const {
|
|
10622
|
-
request: { method, path, origin },
|
|
10622
|
+
request: { method, path: path2, origin },
|
|
10623
10623
|
response: { statusCode }
|
|
10624
10624
|
} = evt;
|
|
10625
|
-
debugLog("received response to %s %s%s - HTTP %d", method, origin,
|
|
10625
|
+
debugLog("received response to %s %s%s - HTTP %d", method, origin, path2, statusCode);
|
|
10626
10626
|
});
|
|
10627
10627
|
diagnosticsChannel.subscribe("undici:request:trailers", (evt) => {
|
|
10628
10628
|
const {
|
|
10629
|
-
request: { method, path, origin }
|
|
10629
|
+
request: { method, path: path2, origin }
|
|
10630
10630
|
} = evt;
|
|
10631
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
10631
|
+
debugLog("trailers received from %s %s%s", method, origin, path2);
|
|
10632
10632
|
});
|
|
10633
10633
|
diagnosticsChannel.subscribe("undici:request:error", (evt) => {
|
|
10634
10634
|
const {
|
|
10635
|
-
request: { method, path, origin },
|
|
10635
|
+
request: { method, path: path2, origin },
|
|
10636
10636
|
error
|
|
10637
10637
|
} = evt;
|
|
10638
|
-
debugLog("request to %s %s%s errored - %s", method, origin,
|
|
10638
|
+
debugLog("request to %s %s%s errored - %s", method, origin, path2, error.message);
|
|
10639
10639
|
});
|
|
10640
10640
|
}
|
|
10641
10641
|
var isTrackingWebSocketEvents = false;
|
|
@@ -10710,7 +10710,7 @@ var require_request = __commonJS((exports, module) => {
|
|
|
10710
10710
|
|
|
10711
10711
|
class Request2 {
|
|
10712
10712
|
constructor(origin, {
|
|
10713
|
-
path,
|
|
10713
|
+
path: path2,
|
|
10714
10714
|
method,
|
|
10715
10715
|
body,
|
|
10716
10716
|
headers,
|
|
@@ -10726,11 +10726,11 @@ var require_request = __commonJS((exports, module) => {
|
|
|
10726
10726
|
throwOnError,
|
|
10727
10727
|
maxRedirections
|
|
10728
10728
|
}, handler) {
|
|
10729
|
-
if (typeof
|
|
10729
|
+
if (typeof path2 !== "string") {
|
|
10730
10730
|
throw new InvalidArgumentError("path must be a string");
|
|
10731
|
-
} else if (
|
|
10731
|
+
} else if (path2[0] !== "/" && !(path2.startsWith("http://") || path2.startsWith("https://")) && method !== "CONNECT") {
|
|
10732
10732
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
10733
|
-
} else if (invalidPathRegex.test(
|
|
10733
|
+
} else if (invalidPathRegex.test(path2)) {
|
|
10734
10734
|
throw new InvalidArgumentError("invalid request path");
|
|
10735
10735
|
}
|
|
10736
10736
|
if (typeof method !== "string") {
|
|
@@ -10798,7 +10798,7 @@ var require_request = __commonJS((exports, module) => {
|
|
|
10798
10798
|
this.completed = false;
|
|
10799
10799
|
this.aborted = false;
|
|
10800
10800
|
this.upgrade = upgrade || null;
|
|
10801
|
-
this.path = query ? serializePathWithQuery(
|
|
10801
|
+
this.path = query ? serializePathWithQuery(path2, query) : path2;
|
|
10802
10802
|
this.origin = origin;
|
|
10803
10803
|
this.protocol = getProtocolFromUrlString(origin);
|
|
10804
10804
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -15332,7 +15332,7 @@ var require_client_h1 = __commonJS((exports, module) => {
|
|
|
15332
15332
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
15333
15333
|
}
|
|
15334
15334
|
function writeH1(client, request) {
|
|
15335
|
-
const { method, path, host, upgrade, blocking, reset } = request;
|
|
15335
|
+
const { method, path: path2, host, upgrade, blocking, reset } = request;
|
|
15336
15336
|
let { body, headers, contentLength } = request;
|
|
15337
15337
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
15338
15338
|
if (util.isFormDataLike(body)) {
|
|
@@ -15398,7 +15398,7 @@ var require_client_h1 = __commonJS((exports, module) => {
|
|
|
15398
15398
|
if (blocking) {
|
|
15399
15399
|
socket[kBlocking] = true;
|
|
15400
15400
|
}
|
|
15401
|
-
let header = `${method} ${
|
|
15401
|
+
let header = `${method} ${path2} HTTP/1.1\r
|
|
15402
15402
|
`;
|
|
15403
15403
|
if (typeof host === "string") {
|
|
15404
15404
|
header += `host: ${host}\r
|
|
@@ -16015,7 +16015,7 @@ var require_client_h2 = __commonJS((exports, module) => {
|
|
|
16015
16015
|
function writeH2(client, request) {
|
|
16016
16016
|
const requestTimeout = request.bodyTimeout ?? client[kBodyTimeout];
|
|
16017
16017
|
const session = client[kHTTP2Session];
|
|
16018
|
-
const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
|
|
16018
|
+
const { method, path: path2, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
|
|
16019
16019
|
let { body } = request;
|
|
16020
16020
|
if (upgrade != null && upgrade !== "websocket") {
|
|
16021
16021
|
util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -16083,7 +16083,7 @@ var require_client_h2 = __commonJS((exports, module) => {
|
|
|
16083
16083
|
}
|
|
16084
16084
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
16085
16085
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
16086
|
-
headers[HTTP2_HEADER_PATH] =
|
|
16086
|
+
headers[HTTP2_HEADER_PATH] = path2;
|
|
16087
16087
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
16088
16088
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
16089
16089
|
} else {
|
|
@@ -16126,7 +16126,7 @@ var require_client_h2 = __commonJS((exports, module) => {
|
|
|
16126
16126
|
stream.setTimeout(requestTimeout);
|
|
16127
16127
|
return true;
|
|
16128
16128
|
}
|
|
16129
|
-
headers[HTTP2_HEADER_PATH] =
|
|
16129
|
+
headers[HTTP2_HEADER_PATH] = path2;
|
|
16130
16130
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
16131
16131
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
16132
16132
|
if (body && typeof body.read === "function") {
|
|
@@ -17654,10 +17654,10 @@ var require_proxy_agent = __commonJS((exports, module) => {
|
|
|
17654
17654
|
};
|
|
17655
17655
|
const {
|
|
17656
17656
|
origin,
|
|
17657
|
-
path = "/",
|
|
17657
|
+
path: path2 = "/",
|
|
17658
17658
|
headers = {}
|
|
17659
17659
|
} = opts;
|
|
17660
|
-
opts.path = origin +
|
|
17660
|
+
opts.path = origin + path2;
|
|
17661
17661
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
17662
17662
|
const { host } = new URL(origin);
|
|
17663
17663
|
headers.host = host;
|
|
@@ -19519,20 +19519,20 @@ var require_mock_utils = __commonJS((exports, module) => {
|
|
|
19519
19519
|
}
|
|
19520
19520
|
return normalizedQp;
|
|
19521
19521
|
}
|
|
19522
|
-
function safeUrl(
|
|
19523
|
-
if (typeof
|
|
19524
|
-
return
|
|
19522
|
+
function safeUrl(path2) {
|
|
19523
|
+
if (typeof path2 !== "string") {
|
|
19524
|
+
return path2;
|
|
19525
19525
|
}
|
|
19526
|
-
const pathSegments =
|
|
19526
|
+
const pathSegments = path2.split("?", 3);
|
|
19527
19527
|
if (pathSegments.length !== 2) {
|
|
19528
|
-
return
|
|
19528
|
+
return path2;
|
|
19529
19529
|
}
|
|
19530
19530
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
19531
19531
|
qp.sort();
|
|
19532
19532
|
return [...pathSegments, qp.toString()].join("?");
|
|
19533
19533
|
}
|
|
19534
|
-
function matchKey(mockDispatch2, { path, method, body, headers }) {
|
|
19535
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
19534
|
+
function matchKey(mockDispatch2, { path: path2, method, body, headers }) {
|
|
19535
|
+
const pathMatch = matchValue(mockDispatch2.path, path2);
|
|
19536
19536
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
19537
19537
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
19538
19538
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -19557,8 +19557,8 @@ var require_mock_utils = __commonJS((exports, module) => {
|
|
|
19557
19557
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
19558
19558
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
19559
19559
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
19560
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path, ignoreTrailingSlash }) => {
|
|
19561
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
19560
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path2, ignoreTrailingSlash }) => {
|
|
19561
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path2)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path2), resolvedPath);
|
|
19562
19562
|
});
|
|
19563
19563
|
if (matchedMockDispatches.length === 0) {
|
|
19564
19564
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -19596,19 +19596,19 @@ var require_mock_utils = __commonJS((exports, module) => {
|
|
|
19596
19596
|
mockDispatches.splice(index2, 1);
|
|
19597
19597
|
}
|
|
19598
19598
|
}
|
|
19599
|
-
function removeTrailingSlash(
|
|
19600
|
-
while (
|
|
19601
|
-
|
|
19599
|
+
function removeTrailingSlash(path2) {
|
|
19600
|
+
while (path2.endsWith("/")) {
|
|
19601
|
+
path2 = path2.slice(0, -1);
|
|
19602
19602
|
}
|
|
19603
|
-
if (
|
|
19604
|
-
|
|
19603
|
+
if (path2.length === 0) {
|
|
19604
|
+
path2 = "/";
|
|
19605
19605
|
}
|
|
19606
|
-
return
|
|
19606
|
+
return path2;
|
|
19607
19607
|
}
|
|
19608
19608
|
function buildKey(opts) {
|
|
19609
|
-
const { path, method, body, headers, query } = opts;
|
|
19609
|
+
const { path: path2, method, body, headers, query } = opts;
|
|
19610
19610
|
return {
|
|
19611
|
-
path,
|
|
19611
|
+
path: path2,
|
|
19612
19612
|
method,
|
|
19613
19613
|
body,
|
|
19614
19614
|
headers,
|
|
@@ -20246,10 +20246,10 @@ var require_pending_interceptors_formatter = __commonJS((exports, module) => {
|
|
|
20246
20246
|
});
|
|
20247
20247
|
}
|
|
20248
20248
|
format(pendingInterceptors) {
|
|
20249
|
-
const withPrettyHeaders = pendingInterceptors.map(({ method, path, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
20249
|
+
const withPrettyHeaders = pendingInterceptors.map(({ method, path: path2, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
20250
20250
|
Method: method,
|
|
20251
20251
|
Origin: origin,
|
|
20252
|
-
Path:
|
|
20252
|
+
Path: path2,
|
|
20253
20253
|
"Status code": statusCode,
|
|
20254
20254
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
20255
20255
|
Invocations: timesInvoked,
|
|
@@ -20328,9 +20328,9 @@ var require_mock_agent = __commonJS((exports, module) => {
|
|
|
20328
20328
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
20329
20329
|
const dispatchOpts = { ...opts };
|
|
20330
20330
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
20331
|
-
const [
|
|
20331
|
+
const [path2, searchParams] = dispatchOpts.path.split("?");
|
|
20332
20332
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
20333
|
-
dispatchOpts.path = `${
|
|
20333
|
+
dispatchOpts.path = `${path2}?${normalizedSearchParams}`;
|
|
20334
20334
|
}
|
|
20335
20335
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
20336
20336
|
}
|
|
@@ -20689,12 +20689,12 @@ var require_snapshot_recorder = __commonJS((exports, module) => {
|
|
|
20689
20689
|
};
|
|
20690
20690
|
}
|
|
20691
20691
|
async loadSnapshots(filePath) {
|
|
20692
|
-
const
|
|
20693
|
-
if (!
|
|
20692
|
+
const path2 = filePath || this.#snapshotPath;
|
|
20693
|
+
if (!path2) {
|
|
20694
20694
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
20695
20695
|
}
|
|
20696
20696
|
try {
|
|
20697
|
-
const data = await readFile(resolve(
|
|
20697
|
+
const data = await readFile(resolve(path2), "utf8");
|
|
20698
20698
|
const parsed = JSON.parse(data);
|
|
20699
20699
|
if (Array.isArray(parsed)) {
|
|
20700
20700
|
this.#snapshots.clear();
|
|
@@ -20708,16 +20708,16 @@ var require_snapshot_recorder = __commonJS((exports, module) => {
|
|
|
20708
20708
|
if (error.code === "ENOENT") {
|
|
20709
20709
|
this.#snapshots.clear();
|
|
20710
20710
|
} else {
|
|
20711
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
20711
|
+
throw new UndiciError(`Failed to load snapshots from ${path2}`, { cause: error });
|
|
20712
20712
|
}
|
|
20713
20713
|
}
|
|
20714
20714
|
}
|
|
20715
20715
|
async saveSnapshots(filePath) {
|
|
20716
|
-
const
|
|
20717
|
-
if (!
|
|
20716
|
+
const path2 = filePath || this.#snapshotPath;
|
|
20717
|
+
if (!path2) {
|
|
20718
20718
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
20719
20719
|
}
|
|
20720
|
-
const resolvedPath = resolve(
|
|
20720
|
+
const resolvedPath = resolve(path2);
|
|
20721
20721
|
await mkdir(dirname(resolvedPath), { recursive: true });
|
|
20722
20722
|
const data = Array.from(this.#snapshots.entries()).map(([hash3, snapshot]) => ({
|
|
20723
20723
|
hash: hash3,
|
|
@@ -21195,15 +21195,15 @@ var require_redirect_handler = __commonJS((exports, module) => {
|
|
|
21195
21195
|
return;
|
|
21196
21196
|
}
|
|
21197
21197
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
21198
|
-
const
|
|
21199
|
-
const redirectUrlString = `${origin}${
|
|
21198
|
+
const path2 = search ? `${pathname}${search}` : pathname;
|
|
21199
|
+
const redirectUrlString = `${origin}${path2}`;
|
|
21200
21200
|
for (const historyUrl of this.history) {
|
|
21201
21201
|
if (historyUrl.toString() === redirectUrlString) {
|
|
21202
21202
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
21203
21203
|
}
|
|
21204
21204
|
}
|
|
21205
21205
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
21206
|
-
this.opts.path =
|
|
21206
|
+
this.opts.path = path2;
|
|
21207
21207
|
this.opts.origin = origin;
|
|
21208
21208
|
this.opts.query = null;
|
|
21209
21209
|
}
|
|
@@ -27251,9 +27251,9 @@ var require_util4 = __commonJS((exports, module) => {
|
|
|
27251
27251
|
}
|
|
27252
27252
|
}
|
|
27253
27253
|
}
|
|
27254
|
-
function validateCookiePath(
|
|
27255
|
-
for (let i = 0;i <
|
|
27256
|
-
const code =
|
|
27254
|
+
function validateCookiePath(path2) {
|
|
27255
|
+
for (let i = 0;i < path2.length; ++i) {
|
|
27256
|
+
const code = path2.charCodeAt(i);
|
|
27257
27257
|
if (code < 32 || code === 127 || code === 59) {
|
|
27258
27258
|
throw new Error("Invalid cookie path");
|
|
27259
27259
|
}
|
|
@@ -30026,6 +30026,27 @@ var require_eventsource = __commonJS((exports, module) => {
|
|
|
30026
30026
|
};
|
|
30027
30027
|
});
|
|
30028
30028
|
|
|
30029
|
+
// src/helper.ts
|
|
30030
|
+
import * as fs from "fs";
|
|
30031
|
+
import * as path from "path";
|
|
30032
|
+
import * as os from "os";
|
|
30033
|
+
function json(data) {
|
|
30034
|
+
return {
|
|
30035
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
30036
|
+
details: data
|
|
30037
|
+
};
|
|
30038
|
+
}
|
|
30039
|
+
var KEY_PATH = path.join(os.homedir(), ".bountyagents_key");
|
|
30040
|
+
function getPrivateKey() {
|
|
30041
|
+
if (fs.existsSync(KEY_PATH)) {
|
|
30042
|
+
const key = fs.readFileSync(KEY_PATH, "utf-8").trim();
|
|
30043
|
+
if (key.startsWith("0x")) {
|
|
30044
|
+
return key;
|
|
30045
|
+
}
|
|
30046
|
+
}
|
|
30047
|
+
return "0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
30048
|
+
}
|
|
30049
|
+
|
|
30029
30050
|
// ../node_modules/.pnpm/@sinclair+typebox@0.34.48/node_modules/@sinclair/typebox/build/esm/type/guard/value.mjs
|
|
30030
30051
|
var exports_value = {};
|
|
30031
30052
|
__export(exports_value, {
|
|
@@ -41198,6 +41219,12 @@ init_getAddress();
|
|
|
41198
41219
|
init_isAddress();
|
|
41199
41220
|
init_toBytes();
|
|
41200
41221
|
init_keccak256();
|
|
41222
|
+
// ../node_modules/.pnpm/viem@2.46.2_typescript@5.9.3_zod@4.3.6/node_modules/viem/_esm/accounts/generatePrivateKey.js
|
|
41223
|
+
init_secp256k1();
|
|
41224
|
+
init_toHex();
|
|
41225
|
+
function generatePrivateKey() {
|
|
41226
|
+
return toHex(secp256k1.utils.randomPrivateKey());
|
|
41227
|
+
}
|
|
41201
41228
|
// ../node_modules/.pnpm/viem@2.46.2_typescript@5.9.3_zod@4.3.6/node_modules/viem/_esm/accounts/privateKeyToAccount.js
|
|
41202
41229
|
init_secp256k1();
|
|
41203
41230
|
init_toHex();
|
|
@@ -41376,14 +41403,6 @@ var buildSettleDataHash = (contractAddress, key, owner, token, worker, amount) =
|
|
|
41376
41403
|
]));
|
|
41377
41404
|
};
|
|
41378
41405
|
|
|
41379
|
-
// src/helper.ts
|
|
41380
|
-
function json(data) {
|
|
41381
|
-
return {
|
|
41382
|
-
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
41383
|
-
details: data
|
|
41384
|
-
};
|
|
41385
|
-
}
|
|
41386
|
-
|
|
41387
41406
|
// node_modules/undici/index.js
|
|
41388
41407
|
var __filename = "/Users/amigo/Develop/mizu/bountyagents/plugin/node_modules/undici/index.js";
|
|
41389
41408
|
var Client = require_client();
|
|
@@ -41447,11 +41466,11 @@ function makeDispatcher(fn) {
|
|
|
41447
41466
|
if (typeof opts.path !== "string") {
|
|
41448
41467
|
throw new InvalidArgumentError("invalid opts.path");
|
|
41449
41468
|
}
|
|
41450
|
-
let
|
|
41469
|
+
let path2 = opts.path;
|
|
41451
41470
|
if (!opts.path.startsWith("/")) {
|
|
41452
|
-
|
|
41471
|
+
path2 = `/${path2}`;
|
|
41453
41472
|
}
|
|
41454
|
-
url = new URL(util.parseOrigin(url).origin +
|
|
41473
|
+
url = new URL(util.parseOrigin(url).origin + path2);
|
|
41455
41474
|
} else {
|
|
41456
41475
|
if (!opts) {
|
|
41457
41476
|
opts = typeof url === "object" ? url : {};
|
|
@@ -42288,10 +42307,10 @@ function mergeDefs(...defs) {
|
|
|
42288
42307
|
function cloneDef(schema) {
|
|
42289
42308
|
return mergeDefs(schema._zod.def);
|
|
42290
42309
|
}
|
|
42291
|
-
function getElementAtPath(obj,
|
|
42292
|
-
if (!
|
|
42310
|
+
function getElementAtPath(obj, path2) {
|
|
42311
|
+
if (!path2)
|
|
42293
42312
|
return obj;
|
|
42294
|
-
return
|
|
42313
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
42295
42314
|
}
|
|
42296
42315
|
function promiseAllObject(promisesObj) {
|
|
42297
42316
|
const keys = Object.keys(promisesObj);
|
|
@@ -42672,11 +42691,11 @@ function aborted(x, startIndex = 0) {
|
|
|
42672
42691
|
}
|
|
42673
42692
|
return false;
|
|
42674
42693
|
}
|
|
42675
|
-
function prefixIssues(
|
|
42694
|
+
function prefixIssues(path2, issues) {
|
|
42676
42695
|
return issues.map((iss) => {
|
|
42677
42696
|
var _a;
|
|
42678
42697
|
(_a = iss).path ?? (_a.path = []);
|
|
42679
|
-
iss.path.unshift(
|
|
42698
|
+
iss.path.unshift(path2);
|
|
42680
42699
|
return iss;
|
|
42681
42700
|
});
|
|
42682
42701
|
}
|
|
@@ -42859,7 +42878,7 @@ function formatError(error, mapper = (issue2) => issue2.message) {
|
|
|
42859
42878
|
}
|
|
42860
42879
|
function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
42861
42880
|
const result = { errors: [] };
|
|
42862
|
-
const processError = (error2,
|
|
42881
|
+
const processError = (error2, path2 = []) => {
|
|
42863
42882
|
var _a, _b;
|
|
42864
42883
|
for (const issue2 of error2.issues) {
|
|
42865
42884
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -42869,7 +42888,7 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
42869
42888
|
} else if (issue2.code === "invalid_element") {
|
|
42870
42889
|
processError({ issues: issue2.issues }, issue2.path);
|
|
42871
42890
|
} else {
|
|
42872
|
-
const fullpath = [...
|
|
42891
|
+
const fullpath = [...path2, ...issue2.path];
|
|
42873
42892
|
if (fullpath.length === 0) {
|
|
42874
42893
|
result.errors.push(mapper(issue2));
|
|
42875
42894
|
continue;
|
|
@@ -42901,8 +42920,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
42901
42920
|
}
|
|
42902
42921
|
function toDotPath(_path) {
|
|
42903
42922
|
const segs = [];
|
|
42904
|
-
const
|
|
42905
|
-
for (const seg of
|
|
42923
|
+
const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
42924
|
+
for (const seg of path2) {
|
|
42906
42925
|
if (typeof seg === "number")
|
|
42907
42926
|
segs.push(`[${seg}]`);
|
|
42908
42927
|
else if (typeof seg === "symbol")
|
|
@@ -54649,13 +54668,13 @@ function resolveRef(ref, ctx) {
|
|
|
54649
54668
|
if (!ref.startsWith("#")) {
|
|
54650
54669
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
54651
54670
|
}
|
|
54652
|
-
const
|
|
54653
|
-
if (
|
|
54671
|
+
const path2 = ref.slice(1).split("/").filter(Boolean);
|
|
54672
|
+
if (path2.length === 0) {
|
|
54654
54673
|
return ctx.rootSchema;
|
|
54655
54674
|
}
|
|
54656
54675
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
54657
|
-
if (
|
|
54658
|
-
const key =
|
|
54676
|
+
if (path2[0] === defsKey) {
|
|
54677
|
+
const key = path2[1];
|
|
54659
54678
|
if (!key || !ctx.defs[key]) {
|
|
54660
54679
|
throw new Error(`Reference not found: ${ref}`);
|
|
54661
54680
|
}
|
|
@@ -55056,7 +55075,7 @@ function date4(params) {
|
|
|
55056
55075
|
// ../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
55057
55076
|
config(en_default());
|
|
55058
55077
|
// src/task-db-types.ts
|
|
55059
|
-
var taskStatusSchema = exports_external.enum(["finished", "draft", "active", "closed"]);
|
|
55078
|
+
var taskStatusSchema = exports_external.enum(["finished", "draft", "active", "closed", "pending_review"]);
|
|
55060
55079
|
var responseStatusSchema = exports_external.enum(["pending", "approved", "rejected"]);
|
|
55061
55080
|
var taskRecordSchema = exports_external.object({
|
|
55062
55081
|
id: exports_external.string().uuid(),
|
|
@@ -55111,8 +55130,6 @@ var decisionPayloadSchema = exports_external.object({
|
|
|
55111
55130
|
settlementSignature: signatureSchema.optional()
|
|
55112
55131
|
}).refine((value) => value.status !== "pending", {
|
|
55113
55132
|
message: "Status must be approved or rejected"
|
|
55114
|
-
}).refine((value) => value.status === "approved" ? Boolean(value.settlementSignature) : true, {
|
|
55115
|
-
message: "settlementSignature required when approving"
|
|
55116
55133
|
});
|
|
55117
55134
|
var cancelTaskPayloadSchema = exports_external.object({
|
|
55118
55135
|
taskId: exports_external.string().uuid()
|
|
@@ -55269,8 +55286,8 @@ class BaseBountyPlugin {
|
|
|
55269
55286
|
execute: (rawInput) => executor(schema.parse(rawInput))
|
|
55270
55287
|
});
|
|
55271
55288
|
}
|
|
55272
|
-
async request(
|
|
55273
|
-
const response = await $fetch(`${this.baseUrl}${
|
|
55289
|
+
async request(path2, body, method = "POST") {
|
|
55290
|
+
const response = await $fetch(`${this.baseUrl}${path2}`, {
|
|
55274
55291
|
method,
|
|
55275
55292
|
headers: {
|
|
55276
55293
|
"content-type": "application/json"
|
|
@@ -55335,25 +55352,29 @@ class BountyAgentsPublisherPlugin extends BaseBountyPlugin {
|
|
|
55335
55352
|
if (!task.token || task.price === "0") {
|
|
55336
55353
|
throw new Error("Task is not funded yet");
|
|
55337
55354
|
}
|
|
55338
|
-
|
|
55339
|
-
|
|
55355
|
+
const taskPrice = task.price;
|
|
55356
|
+
if (payload.price !== taskPrice) {
|
|
55357
|
+
throw new Error(`Price mismatch: payload price ${payload.price} does not match task price ${taskPrice}`);
|
|
55340
55358
|
}
|
|
55341
55359
|
const workerAddress = getAddress(payload.workerAddress);
|
|
55342
55360
|
if (workerAddress !== getAddress(responseRecord.worker)) {
|
|
55343
55361
|
throw new Error("Worker address mismatch");
|
|
55344
55362
|
}
|
|
55345
|
-
const settlementSignature = payload.status === "approved" ? await this.createSettlementSignature(responseRecord.task_id, workerAddress,
|
|
55346
|
-
const
|
|
55363
|
+
const settlementSignature = payload.status === "approved" ? await this.createSettlementSignature(responseRecord.task_id, workerAddress, taskPrice, task.token) : undefined;
|
|
55364
|
+
const body = {
|
|
55347
55365
|
responseId: payload.responseId,
|
|
55348
55366
|
workerAddress,
|
|
55349
55367
|
price: payload.price,
|
|
55350
55368
|
status: payload.status,
|
|
55351
|
-
settlementSignature
|
|
55352
|
-
};
|
|
55353
|
-
const body = {
|
|
55354
|
-
...canonicalPayload,
|
|
55369
|
+
settlementSignature,
|
|
55355
55370
|
ownerAddress: this.signer.address,
|
|
55356
|
-
signature: await this.signPayload(decisionSignaturePayload(
|
|
55371
|
+
signature: await this.signPayload(decisionSignaturePayload({
|
|
55372
|
+
responseId: payload.responseId,
|
|
55373
|
+
workerAddress,
|
|
55374
|
+
price: payload.price,
|
|
55375
|
+
status: payload.status,
|
|
55376
|
+
settlementSignature
|
|
55377
|
+
}))
|
|
55357
55378
|
};
|
|
55358
55379
|
const response = await this.request(`/responses/${payload.responseId}/decision`, body);
|
|
55359
55380
|
return submissionResponseSchema.parse(response).response;
|
|
@@ -55495,7 +55516,6 @@ class PrivateKeySigner {
|
|
|
55495
55516
|
// src/publisher.ts
|
|
55496
55517
|
var SERVICE_URL = "http://localhost:3000";
|
|
55497
55518
|
var CONTRACT_ADDRESS = "0x55D45aFA265d0381C8A81328FfeA408D2Dd45F40";
|
|
55498
|
-
var PRIVATE_KEY = "0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
55499
55519
|
var TEST_TOKEN_ADDRESS = "0x56DA32693A4e6dDd0eDC932b295cb00372f37f8b";
|
|
55500
55520
|
var AGENT_ESCROW_ABI = [
|
|
55501
55521
|
{
|
|
@@ -55548,7 +55568,7 @@ var ERC20_ABI = [
|
|
|
55548
55568
|
}
|
|
55549
55569
|
];
|
|
55550
55570
|
async function createBountyTask(params) {
|
|
55551
|
-
const signer = new PrivateKeySigner(
|
|
55571
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
55552
55572
|
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
55553
55573
|
serviceUrl: SERVICE_URL,
|
|
55554
55574
|
contractAddress: CONTRACT_ADDRESS
|
|
@@ -55561,7 +55581,7 @@ async function createBountyTask(params) {
|
|
|
55561
55581
|
return task;
|
|
55562
55582
|
}
|
|
55563
55583
|
async function fundBountyTask(params) {
|
|
55564
|
-
const signer = new PrivateKeySigner(
|
|
55584
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
55565
55585
|
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
55566
55586
|
serviceUrl: SERVICE_URL,
|
|
55567
55587
|
contractAddress: CONTRACT_ADDRESS
|
|
@@ -55573,7 +55593,7 @@ async function fundBountyTask(params) {
|
|
|
55573
55593
|
return task;
|
|
55574
55594
|
}
|
|
55575
55595
|
async function depositToken(params) {
|
|
55576
|
-
const account = privateKeyToAccount(
|
|
55596
|
+
const account = privateKeyToAccount(getPrivateKey());
|
|
55577
55597
|
const chain = bscTestnet;
|
|
55578
55598
|
const transport = http();
|
|
55579
55599
|
const walletClient = createWalletClient({
|
|
@@ -55630,6 +55650,15 @@ async function depositToken(params) {
|
|
|
55630
55650
|
rawLockedAmount: depositInfo.amountLocked.toString()
|
|
55631
55651
|
};
|
|
55632
55652
|
}
|
|
55653
|
+
async function decideOnResponse(params) {
|
|
55654
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
55655
|
+
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
55656
|
+
serviceUrl: SERVICE_URL,
|
|
55657
|
+
contractAddress: CONTRACT_ADDRESS
|
|
55658
|
+
});
|
|
55659
|
+
const response = await plugin.executeTool("bountyagents.publisher.task.decision", params);
|
|
55660
|
+
return response;
|
|
55661
|
+
}
|
|
55633
55662
|
function registerPublisherTools(api3) {
|
|
55634
55663
|
api3.registerTool({
|
|
55635
55664
|
name: "create_bounty_task",
|
|
@@ -55686,14 +55715,36 @@ function registerPublisherTools(api3) {
|
|
|
55686
55715
|
}
|
|
55687
55716
|
}
|
|
55688
55717
|
});
|
|
55718
|
+
api3.registerTool({
|
|
55719
|
+
name: "decide_on_response",
|
|
55720
|
+
description: "Approve or reject a task response.",
|
|
55721
|
+
parameters: Type.Object({
|
|
55722
|
+
responseId: Type.String(),
|
|
55723
|
+
workerAddress: Type.String(),
|
|
55724
|
+
price: Type.String(),
|
|
55725
|
+
status: Type.Union([
|
|
55726
|
+
Type.Literal("approved"),
|
|
55727
|
+
Type.Literal("rejected")
|
|
55728
|
+
])
|
|
55729
|
+
}),
|
|
55730
|
+
async execute(_id, params) {
|
|
55731
|
+
try {
|
|
55732
|
+
const result = await decideOnResponse(params);
|
|
55733
|
+
return json(result);
|
|
55734
|
+
} catch (error48) {
|
|
55735
|
+
return json({
|
|
55736
|
+
error: error48 instanceof Error ? error48.message : String(error48)
|
|
55737
|
+
});
|
|
55738
|
+
}
|
|
55739
|
+
}
|
|
55740
|
+
});
|
|
55689
55741
|
}
|
|
55690
55742
|
|
|
55691
55743
|
// src/worker.ts
|
|
55692
55744
|
var SERVICE_URL2 = "http://localhost:3000";
|
|
55693
55745
|
var CONTRACT_ADDRESS2 = "0x55D45aFA265d0381C8A81328FfeA408D2Dd45F40";
|
|
55694
|
-
var PRIVATE_KEY2 = "0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
55695
55746
|
async function getAvailableTask(params) {
|
|
55696
|
-
const signer = new PrivateKeySigner(
|
|
55747
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
55697
55748
|
const plugin = new BountyAgentsWorkerPlugin(signer, {
|
|
55698
55749
|
serviceUrl: SERVICE_URL2,
|
|
55699
55750
|
contractAddress: CONTRACT_ADDRESS2
|
|
@@ -55710,6 +55761,18 @@ async function getAvailableTask(params) {
|
|
|
55710
55761
|
}
|
|
55711
55762
|
return tasks[0];
|
|
55712
55763
|
}
|
|
55764
|
+
async function submitResponse(params) {
|
|
55765
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
55766
|
+
const plugin = new BountyAgentsWorkerPlugin(signer, {
|
|
55767
|
+
serviceUrl: SERVICE_URL2,
|
|
55768
|
+
contractAddress: CONTRACT_ADDRESS2
|
|
55769
|
+
});
|
|
55770
|
+
const response = await plugin.executeTool("bountyagents.worker.task.respond", {
|
|
55771
|
+
taskId: params.taskId,
|
|
55772
|
+
payload: params.payload
|
|
55773
|
+
});
|
|
55774
|
+
return response;
|
|
55775
|
+
}
|
|
55713
55776
|
function registerWorkerTools(api3) {
|
|
55714
55777
|
api3.registerTool({
|
|
55715
55778
|
name: "get_available_task",
|
|
@@ -55732,10 +55795,66 @@ function registerWorkerTools(api3) {
|
|
|
55732
55795
|
}
|
|
55733
55796
|
}
|
|
55734
55797
|
});
|
|
55798
|
+
api3.registerTool({
|
|
55799
|
+
name: "submit_task_response",
|
|
55800
|
+
description: "Submit a response for an active bounty task.",
|
|
55801
|
+
parameters: Type.Object({
|
|
55802
|
+
taskId: Type.String(),
|
|
55803
|
+
content: Type.String()
|
|
55804
|
+
}),
|
|
55805
|
+
async execute(_id, params) {
|
|
55806
|
+
try {
|
|
55807
|
+
const result = await submitResponse({
|
|
55808
|
+
taskId: params.taskId,
|
|
55809
|
+
payload: params.content
|
|
55810
|
+
});
|
|
55811
|
+
return json(result);
|
|
55812
|
+
} catch (error48) {
|
|
55813
|
+
return json({
|
|
55814
|
+
error: error48 instanceof Error ? error48.message : String(error48)
|
|
55815
|
+
});
|
|
55816
|
+
}
|
|
55817
|
+
}
|
|
55818
|
+
});
|
|
55735
55819
|
}
|
|
55736
55820
|
|
|
55737
55821
|
// index.ts
|
|
55822
|
+
import * as fs2 from "fs";
|
|
55738
55823
|
function register(api3) {
|
|
55824
|
+
api3.registerCommand({
|
|
55825
|
+
name: "upclaw-task",
|
|
55826
|
+
description: "UpClaw Bounty Agents Task commands",
|
|
55827
|
+
acceptsArgs: true,
|
|
55828
|
+
handler: async (ctx) => {
|
|
55829
|
+
const args = ctx.args?.trim() ?? "";
|
|
55830
|
+
const tokens = args.split(/\s+/).filter(Boolean);
|
|
55831
|
+
const action = (tokens[0] ?? "status").toLowerCase();
|
|
55832
|
+
if (action === "init") {
|
|
55833
|
+
try {
|
|
55834
|
+
if (!fs2.existsSync(KEY_PATH)) {
|
|
55835
|
+
const pk = generatePrivateKey();
|
|
55836
|
+
fs2.writeFileSync(KEY_PATH, pk, "utf-8");
|
|
55837
|
+
return json({
|
|
55838
|
+
text: `Initialized new EVM private key and saved to ${KEY_PATH}`
|
|
55839
|
+
});
|
|
55840
|
+
} else {
|
|
55841
|
+
return json({
|
|
55842
|
+
text: `EVM private key already exists at ${KEY_PATH}`
|
|
55843
|
+
});
|
|
55844
|
+
}
|
|
55845
|
+
} catch (error48) {
|
|
55846
|
+
return json({
|
|
55847
|
+
text: "Failed to initialize key:",
|
|
55848
|
+
error: error48.message
|
|
55849
|
+
});
|
|
55850
|
+
}
|
|
55851
|
+
}
|
|
55852
|
+
return json({
|
|
55853
|
+
text: ["UpClaw Bounty Agents Task commands:", "", "/upclaw-task init"].join(`
|
|
55854
|
+
`)
|
|
55855
|
+
});
|
|
55856
|
+
}
|
|
55857
|
+
});
|
|
55739
55858
|
registerPublisherTools(api3);
|
|
55740
55859
|
registerWorkerTools(api3);
|
|
55741
55860
|
}
|
package/index.ts
CHANGED
|
@@ -1,52 +1,45 @@
|
|
|
1
|
+
import { json, KEY_PATH } from "./src/helper.js";
|
|
1
2
|
import { registerPublisherTools } from "./src/publisher.js";
|
|
2
3
|
import { registerWorkerTools } from "./src/worker.js";
|
|
4
|
+
import { generatePrivateKey } from "viem/accounts";
|
|
5
|
+
import * as fs from "fs";
|
|
3
6
|
|
|
4
7
|
export default function register(api: any) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
api.registerCommand({
|
|
9
|
+
name: "upclaw-task",
|
|
10
|
+
description: "UpClaw Bounty Agents Task commands",
|
|
11
|
+
acceptsArgs: true,
|
|
12
|
+
handler: async (ctx: any) => {
|
|
13
|
+
const args = ctx.args?.trim() ?? "";
|
|
14
|
+
const tokens = args.split(/\s+/).filter(Boolean);
|
|
15
|
+
const action = (tokens[0] ?? "status").toLowerCase();
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
if (action === "init") {
|
|
18
|
+
try {
|
|
19
|
+
if (!fs.existsSync(KEY_PATH)) {
|
|
20
|
+
const pk = generatePrivateKey();
|
|
21
|
+
fs.writeFileSync(KEY_PATH, pk, "utf-8");
|
|
22
|
+
return json({
|
|
23
|
+
text: `Initialized new EVM private key and saved to ${KEY_PATH}`,
|
|
24
|
+
});
|
|
25
|
+
} else {
|
|
26
|
+
return json({
|
|
27
|
+
text: `EVM private key already exists at ${KEY_PATH}`,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
} catch (error: any) {
|
|
31
|
+
return json({
|
|
32
|
+
text: "Failed to initialize key:",
|
|
33
|
+
error: error.message,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// title: "Test Task from CLI",
|
|
29
|
-
// content: "This is a test task created via the CLI tool.",
|
|
30
|
-
// }
|
|
31
|
-
// )) as any;
|
|
32
|
-
// console.log("Task created successfully:", task);
|
|
33
|
-
// return {
|
|
34
|
-
// text: `Task created successfully: ${task.id}`,
|
|
35
|
-
// };
|
|
36
|
-
// } catch (error) {
|
|
37
|
-
// console.error("Failed to create task:", error);
|
|
38
|
-
// return {
|
|
39
|
-
// text: "Failed to create task:",
|
|
40
|
-
// error: error,
|
|
41
|
-
// };
|
|
42
|
-
// }
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
|
-
// return {
|
|
46
|
-
// text: ["Bounty Agents Task commands:", "", "/task create"].join("\n"),
|
|
47
|
-
// };
|
|
48
|
-
// },
|
|
49
|
-
// });
|
|
38
|
+
return json({
|
|
39
|
+
text: ["UpClaw Bounty Agents Task commands:", "", "/upclaw-task init"].join("\n"),
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
});
|
|
50
43
|
|
|
51
44
|
registerPublisherTools(api);
|
|
52
45
|
registerWorkerTools(api);
|
package/package.json
CHANGED
package/src/helper.ts
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as os from "os";
|
|
4
|
+
|
|
1
5
|
export function json(data: unknown) {
|
|
2
6
|
return {
|
|
3
7
|
content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
|
|
4
8
|
details: data,
|
|
5
9
|
};
|
|
6
10
|
}
|
|
11
|
+
|
|
12
|
+
export const KEY_PATH = path.join(os.homedir(), ".bountyagents_key");
|
|
13
|
+
|
|
14
|
+
export function getPrivateKey(): `0x${string}` {
|
|
15
|
+
if (fs.existsSync(KEY_PATH)) {
|
|
16
|
+
const key = fs.readFileSync(KEY_PATH, "utf-8").trim();
|
|
17
|
+
if (key.startsWith("0x")) {
|
|
18
|
+
return key as `0x${string}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Fallback to the default one if the file doesn't exist to not break existing functionality directly, but throw error if user wants to use init
|
|
22
|
+
return "0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -214,8 +214,12 @@ export class BountyAgentsPublisherPlugin extends BaseBountyPlugin {
|
|
|
214
214
|
if (!task.token || task.price === "0") {
|
|
215
215
|
throw new Error("Task is not funded yet");
|
|
216
216
|
}
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
|
|
218
|
+
// Use the price from the task record for the settlement signature
|
|
219
|
+
const taskPrice = task.price;
|
|
220
|
+
|
|
221
|
+
if (payload.price !== taskPrice) {
|
|
222
|
+
throw new Error(`Price mismatch: payload price ${payload.price} does not match task price ${taskPrice}`);
|
|
219
223
|
}
|
|
220
224
|
const workerAddress = getAddress(payload.workerAddress as `0x${string}`);
|
|
221
225
|
if (workerAddress !== getAddress(responseRecord.worker as `0x${string}`)) {
|
|
@@ -227,23 +231,26 @@ export class BountyAgentsPublisherPlugin extends BaseBountyPlugin {
|
|
|
227
231
|
? await this.createSettlementSignature(
|
|
228
232
|
responseRecord.task_id,
|
|
229
233
|
workerAddress,
|
|
230
|
-
|
|
234
|
+
taskPrice,
|
|
231
235
|
task.token
|
|
232
236
|
)
|
|
233
237
|
: undefined;
|
|
234
238
|
|
|
235
|
-
const
|
|
239
|
+
const body = {
|
|
236
240
|
responseId: payload.responseId,
|
|
237
241
|
workerAddress,
|
|
238
242
|
price: payload.price,
|
|
239
243
|
status: payload.status,
|
|
240
244
|
settlementSignature,
|
|
241
|
-
};
|
|
242
|
-
const body = {
|
|
243
|
-
...canonicalPayload,
|
|
244
245
|
ownerAddress: this.signer.address,
|
|
245
246
|
signature: await this.signPayload(
|
|
246
|
-
decisionSignaturePayload(
|
|
247
|
+
decisionSignaturePayload({
|
|
248
|
+
responseId: payload.responseId,
|
|
249
|
+
workerAddress,
|
|
250
|
+
price: payload.price,
|
|
251
|
+
status: payload.status,
|
|
252
|
+
settlementSignature,
|
|
253
|
+
})
|
|
247
254
|
),
|
|
248
255
|
};
|
|
249
256
|
const response = await this.request(
|
package/src/publisher.ts
CHANGED
|
@@ -3,14 +3,12 @@ import { createPublicClient, createWalletClient, http, parseUnits } from "viem";
|
|
|
3
3
|
import { privateKeyToAccount } from "viem/accounts";
|
|
4
4
|
import { bscTestnet } from "viem/chains";
|
|
5
5
|
import { taskDepositKey } from "./escrow.js";
|
|
6
|
-
import { json } from "./helper.js";
|
|
6
|
+
import { json, getPrivateKey } from "./helper.js";
|
|
7
7
|
import { BountyAgentsPublisherPlugin } from "./index.js";
|
|
8
8
|
import { PrivateKeySigner } from "./signers.js";
|
|
9
9
|
|
|
10
10
|
const SERVICE_URL = "http://localhost:3000";
|
|
11
11
|
const CONTRACT_ADDRESS = "0x55D45aFA265d0381C8A81328FfeA408D2Dd45F40";
|
|
12
|
-
const PRIVATE_KEY =
|
|
13
|
-
"0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
14
12
|
const TEST_TOKEN_ADDRESS = "0x56DA32693A4e6dDd0eDC932b295cb00372f37f8b";
|
|
15
13
|
|
|
16
14
|
const AGENT_ESCROW_ABI = [
|
|
@@ -69,7 +67,7 @@ export async function createBountyTask(params: {
|
|
|
69
67
|
title: string;
|
|
70
68
|
content: string;
|
|
71
69
|
}) {
|
|
72
|
-
const signer = new PrivateKeySigner(
|
|
70
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
73
71
|
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
74
72
|
serviceUrl: SERVICE_URL,
|
|
75
73
|
contractAddress: CONTRACT_ADDRESS,
|
|
@@ -87,7 +85,7 @@ export async function fundBountyTask(params: {
|
|
|
87
85
|
taskId: string;
|
|
88
86
|
token: string;
|
|
89
87
|
}) {
|
|
90
|
-
const signer = new PrivateKeySigner(
|
|
88
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
91
89
|
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
92
90
|
serviceUrl: SERVICE_URL,
|
|
93
91
|
contractAddress: CONTRACT_ADDRESS,
|
|
@@ -104,7 +102,7 @@ export async function depositToken(params: {
|
|
|
104
102
|
taskId: string;
|
|
105
103
|
amount?: string;
|
|
106
104
|
}) {
|
|
107
|
-
const account = privateKeyToAccount(
|
|
105
|
+
const account = privateKeyToAccount(getPrivateKey());
|
|
108
106
|
const chain = bscTestnet;
|
|
109
107
|
const transport = http();
|
|
110
108
|
|
|
@@ -175,6 +173,25 @@ export async function depositToken(params: {
|
|
|
175
173
|
};
|
|
176
174
|
}
|
|
177
175
|
|
|
176
|
+
export async function decideOnResponse(params: {
|
|
177
|
+
responseId: string;
|
|
178
|
+
workerAddress: string;
|
|
179
|
+
price: string;
|
|
180
|
+
status: "approved" | "rejected";
|
|
181
|
+
}) {
|
|
182
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
183
|
+
const plugin = new BountyAgentsPublisherPlugin(signer, {
|
|
184
|
+
serviceUrl: SERVICE_URL,
|
|
185
|
+
contractAddress: CONTRACT_ADDRESS,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const response = (await plugin.executeTool(
|
|
189
|
+
"bountyagents.publisher.task.decision",
|
|
190
|
+
params
|
|
191
|
+
)) as any;
|
|
192
|
+
return response;
|
|
193
|
+
}
|
|
194
|
+
|
|
178
195
|
export function registerPublisherTools(api: any) {
|
|
179
196
|
api.registerTool({
|
|
180
197
|
name: "create_bounty_task",
|
|
@@ -236,4 +253,28 @@ export function registerPublisherTools(api: any) {
|
|
|
236
253
|
}
|
|
237
254
|
},
|
|
238
255
|
});
|
|
256
|
+
|
|
257
|
+
api.registerTool({
|
|
258
|
+
name: "decide_on_response",
|
|
259
|
+
description: "Approve or reject a task response.",
|
|
260
|
+
parameters: Type.Object({
|
|
261
|
+
responseId: Type.String(),
|
|
262
|
+
workerAddress: Type.String(),
|
|
263
|
+
price: Type.String(),
|
|
264
|
+
status: Type.Union([
|
|
265
|
+
Type.Literal("approved"),
|
|
266
|
+
Type.Literal("rejected"),
|
|
267
|
+
]),
|
|
268
|
+
}),
|
|
269
|
+
async execute(_id: string, params: any) {
|
|
270
|
+
try {
|
|
271
|
+
const result = await decideOnResponse(params);
|
|
272
|
+
return json(result);
|
|
273
|
+
} catch (error: any) {
|
|
274
|
+
return json({
|
|
275
|
+
error: error instanceof Error ? error.message : String(error),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
});
|
|
239
280
|
}
|
package/src/task-db-types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
|
-
export const taskStatusSchema = z.enum(["finished", "draft", "active", "closed"]);
|
|
3
|
+
export const taskStatusSchema = z.enum(["finished", "draft", "active", "closed", "pending_review"]);
|
|
4
4
|
export type TaskStatus = z.infer<typeof taskStatusSchema>;
|
|
5
5
|
|
|
6
6
|
export const responseStatusSchema = z.enum(["pending", "approved", "rejected"]);
|
package/src/types.ts
CHANGED
|
@@ -44,9 +44,6 @@ export const decisionPayloadSchema = z
|
|
|
44
44
|
})
|
|
45
45
|
.refine((value) => value.status !== 'pending', {
|
|
46
46
|
message: 'Status must be approved or rejected'
|
|
47
|
-
})
|
|
48
|
-
.refine((value) => (value.status === 'approved' ? Boolean(value.settlementSignature) : true), {
|
|
49
|
-
message: 'settlementSignature required when approving'
|
|
50
47
|
});
|
|
51
48
|
|
|
52
49
|
export const cancelTaskPayloadSchema = z.object({
|
package/src/worker.ts
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { PrivateKeySigner } from "./signers.js";
|
|
3
3
|
import { BountyAgentsWorkerPlugin } from "./index.js";
|
|
4
|
-
import { json } from "./helper.js";
|
|
4
|
+
import { json, getPrivateKey } from "./helper.js";
|
|
5
5
|
|
|
6
6
|
const SERVICE_URL = "http://localhost:3000";
|
|
7
7
|
const CONTRACT_ADDRESS = "0x55D45aFA265d0381C8A81328FfeA408D2Dd45F40";
|
|
8
|
-
const PRIVATE_KEY =
|
|
9
|
-
"0x289f92dd30c36ff24b75b48623c70dea2b428dabac7a52c5ca810bcda64d861b";
|
|
10
8
|
|
|
11
9
|
export async function getAvailableTask(params: {
|
|
12
10
|
keyword?: string;
|
|
13
11
|
pageSize?: number;
|
|
14
12
|
pageNum?: number;
|
|
15
13
|
}) {
|
|
16
|
-
const signer = new PrivateKeySigner(
|
|
14
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
17
15
|
const plugin = new BountyAgentsWorkerPlugin(signer, {
|
|
18
16
|
serviceUrl: SERVICE_URL,
|
|
19
17
|
contractAddress: CONTRACT_ADDRESS,
|
|
@@ -32,6 +30,23 @@ export async function getAvailableTask(params: {
|
|
|
32
30
|
return tasks[0];
|
|
33
31
|
}
|
|
34
32
|
|
|
33
|
+
export async function submitResponse(params: {
|
|
34
|
+
taskId: string;
|
|
35
|
+
payload: string;
|
|
36
|
+
}) {
|
|
37
|
+
const signer = new PrivateKeySigner(getPrivateKey());
|
|
38
|
+
const plugin = new BountyAgentsWorkerPlugin(signer, {
|
|
39
|
+
serviceUrl: SERVICE_URL,
|
|
40
|
+
contractAddress: CONTRACT_ADDRESS,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const response = (await plugin.executeTool("bountyagents.worker.task.respond", {
|
|
44
|
+
taskId: params.taskId,
|
|
45
|
+
payload: params.payload,
|
|
46
|
+
})) as any;
|
|
47
|
+
return response;
|
|
48
|
+
}
|
|
49
|
+
|
|
35
50
|
export function registerWorkerTools(api: any) {
|
|
36
51
|
api.registerTool({
|
|
37
52
|
name: "get_available_task",
|
|
@@ -55,4 +70,26 @@ export function registerWorkerTools(api: any) {
|
|
|
55
70
|
}
|
|
56
71
|
},
|
|
57
72
|
});
|
|
73
|
+
|
|
74
|
+
api.registerTool({
|
|
75
|
+
name: "submit_task_response",
|
|
76
|
+
description: "Submit a response for an active bounty task.",
|
|
77
|
+
parameters: Type.Object({
|
|
78
|
+
taskId: Type.String(),
|
|
79
|
+
content: Type.String(),
|
|
80
|
+
}),
|
|
81
|
+
async execute(_id: string, params: any) {
|
|
82
|
+
try {
|
|
83
|
+
const result = await submitResponse({
|
|
84
|
+
taskId: params.taskId,
|
|
85
|
+
payload: params.content,
|
|
86
|
+
});
|
|
87
|
+
return json(result);
|
|
88
|
+
} catch (error: any) {
|
|
89
|
+
return json({
|
|
90
|
+
error: error instanceof Error ? error.message : String(error),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
});
|
|
58
95
|
}
|
package/test-response.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { submitResponse } from "./src/worker.js";
|
|
2
|
+
import { decideOnResponse } from "./src/publisher.js";
|
|
3
|
+
|
|
4
|
+
async function testResponseFlow() {
|
|
5
|
+
const taskId = "c5fc8fd0-e7db-4ec8-8fb9-86314cb6a5e7";
|
|
6
|
+
console.log(`\n--- Testing Response Flow for taskId: ${taskId} ---`);
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
// 1. Submit Response
|
|
10
|
+
console.log("\n1. Submitting response as worker...");
|
|
11
|
+
const responseResult = await submitResponse({
|
|
12
|
+
taskId,
|
|
13
|
+
payload: "This is a test response content submitted via standalone function."
|
|
14
|
+
});
|
|
15
|
+
console.log("Response submission successful!");
|
|
16
|
+
console.log(JSON.stringify(responseResult, null, 2));
|
|
17
|
+
|
|
18
|
+
const responseId = responseResult.id;
|
|
19
|
+
const workerAddress = responseResult.worker;
|
|
20
|
+
// Note: In a real scenario, we might need to fetch the task to get the price,
|
|
21
|
+
// but for testing we'll assume a value or use what's in the response if available.
|
|
22
|
+
// Based on the schema, price is on the task, not the response.
|
|
23
|
+
|
|
24
|
+
// 2. Decide on Response (Approve)
|
|
25
|
+
console.log(`\n2. Deciding on response (approving) as publisher...`);
|
|
26
|
+
// We'll use the price from the task. Since the task was funded with 100 tokens,
|
|
27
|
+
// we use the same value.
|
|
28
|
+
const decisionResult = await decideOnResponse({
|
|
29
|
+
responseId,
|
|
30
|
+
workerAddress,
|
|
31
|
+
price: "142500000",
|
|
32
|
+
status: "approved"
|
|
33
|
+
});
|
|
34
|
+
console.log("Decision (approval) successful!");
|
|
35
|
+
console.log(JSON.stringify(decisionResult, null, 2));
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error("Test flow failed:");
|
|
39
|
+
console.error(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
testResponseFlow();
|