@ixo/asks-mcp 1.6.0-dev.6 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/asks-mcp.mjs +278 -158
- package/package.json +1 -1
package/dist/asks-mcp.mjs
CHANGED
|
@@ -8468,24 +8468,24 @@ function blockOf(raw) {
|
|
|
8468
8468
|
return null;
|
|
8469
8469
|
}
|
|
8470
8470
|
function callOf(raw) {
|
|
8471
|
-
const
|
|
8472
|
-
if (!
|
|
8471
|
+
const call2 = raw;
|
|
8472
|
+
if (!call2 || typeof call2 !== "object") return null;
|
|
8473
8473
|
const L4 = CALL_LIMITS;
|
|
8474
|
-
if (typeof
|
|
8475
|
-
if (!CALL_LEGS.includes(
|
|
8476
|
-
if (!line(
|
|
8477
|
-
if (!Array.isArray(
|
|
8478
|
-
const money2 =
|
|
8474
|
+
if (typeof call2.slug !== "string" || !CALL_SLUG.test(call2.slug)) return null;
|
|
8475
|
+
if (!CALL_LEGS.includes(call2.leg)) return null;
|
|
8476
|
+
if (!line(call2.title, L4.title) || !line(call2.lede, L4.lede) || !line(call2.poster, L4.poster)) return null;
|
|
8477
|
+
if (!Array.isArray(call2.points) || call2.points.length === 0 || call2.points.length > L4.lines || !call2.points.every((one) => finite(one) && one >= 0 && one <= 100)) return null;
|
|
8478
|
+
const money2 = call2.money;
|
|
8479
8479
|
if (!money2 || typeof money2 !== "object") return null;
|
|
8480
8480
|
if (!amount(money2.prize) || !whole(money2.runnersN, 0, 5) || !amount(money2.runnersEach) || !amount(money2.entryEach) || !whole(money2.entryUpTo, 1, 1e4)) return null;
|
|
8481
|
-
const share =
|
|
8481
|
+
const share = call2.share;
|
|
8482
8482
|
if (share !== void 0 && (!share || typeof share !== "object" || !nonNegative(share.network) || !nonNegative(share.node) || share.network + share.node >= 100)) return null;
|
|
8483
|
-
const sponsor =
|
|
8483
|
+
const sponsor = call2.sponsor;
|
|
8484
8484
|
if (sponsor !== void 0 && (!sponsor || typeof sponsor !== "object" || typeof sponsor.slug !== "string" || !CALL_SLUG.test(sponsor.slug) || !line(sponsor.name, L4.sponsorName) || typeof sponsor.node !== "string" || !ENTITY_DID.test(sponsor.node))) return null;
|
|
8485
|
-
if (!date5(
|
|
8485
|
+
if (!date5(call2.closes) || !date5(call2.drop) || !date5(call2.pick)) return null;
|
|
8486
8486
|
let legs;
|
|
8487
|
-
if (
|
|
8488
|
-
const raw2 =
|
|
8487
|
+
if (call2.legs !== void 0) {
|
|
8488
|
+
const raw2 = call2.legs;
|
|
8489
8489
|
if (!raw2 || typeof raw2 !== "object") return null;
|
|
8490
8490
|
legs = {};
|
|
8491
8491
|
for (const name8 of CALL_LEGS) {
|
|
@@ -8495,42 +8495,42 @@ function callOf(raw) {
|
|
|
8495
8495
|
legs[name8] = id;
|
|
8496
8496
|
}
|
|
8497
8497
|
}
|
|
8498
|
-
if (!Array.isArray(
|
|
8499
|
-
const blocks =
|
|
8498
|
+
if (!Array.isArray(call2.blocks) || call2.blocks.length > L4.blocks) return null;
|
|
8499
|
+
const blocks = call2.blocks.map(blockOf);
|
|
8500
8500
|
if (blocks.some((block2) => block2 === null)) return null;
|
|
8501
8501
|
let review = null;
|
|
8502
|
-
if (
|
|
8503
|
-
if (
|
|
8504
|
-
const subject =
|
|
8502
|
+
if (call2.kind !== void 0) {
|
|
8503
|
+
if (call2.kind !== "review" || call2.mode !== "hire") return null;
|
|
8504
|
+
const subject = call2.subject;
|
|
8505
8505
|
if (subject !== void 0) {
|
|
8506
8506
|
if (!subject || typeof subject !== "object" || !line(subject.name, L4.subjectName)) return null;
|
|
8507
8507
|
if (subject.version !== void 0 && !line(subject.version, L4.version)) return null;
|
|
8508
8508
|
if (subject.where !== void 0 && !line(subject.where, L4.where)) return null;
|
|
8509
8509
|
}
|
|
8510
|
-
if (
|
|
8510
|
+
if (call2.scenarios !== void 0 && (!Array.isArray(call2.scenarios) || call2.scenarios.length === 0 || call2.scenarios.length > L4.scenarios || !call2.scenarios.every((one) => line(one, L4.scenario)))) return null;
|
|
8511
8511
|
review = {
|
|
8512
8512
|
kind: "review",
|
|
8513
8513
|
...subject ? { subject: { name: subject.name, ...subject.version !== void 0 ? { version: subject.version } : {}, ...subject.where !== void 0 ? { where: subject.where } : {} } } : {},
|
|
8514
|
-
...
|
|
8514
|
+
...call2.scenarios !== void 0 ? { scenarios: [...call2.scenarios] } : {}
|
|
8515
8515
|
};
|
|
8516
8516
|
}
|
|
8517
8517
|
return {
|
|
8518
8518
|
call: {
|
|
8519
|
-
slug:
|
|
8520
|
-
leg:
|
|
8519
|
+
slug: call2.slug,
|
|
8520
|
+
leg: call2.leg,
|
|
8521
8521
|
/* The one literal: anything else is a competition, as every call before it was. */
|
|
8522
|
-
...
|
|
8522
|
+
...call2.mode === "hire" ? { mode: "hire" } : {},
|
|
8523
8523
|
...review ?? {},
|
|
8524
|
-
title:
|
|
8525
|
-
lede:
|
|
8526
|
-
poster:
|
|
8527
|
-
points: [...
|
|
8524
|
+
title: call2.title,
|
|
8525
|
+
lede: call2.lede,
|
|
8526
|
+
poster: call2.poster,
|
|
8527
|
+
points: [...call2.points],
|
|
8528
8528
|
money: { prize: money2.prize, runnersN: money2.runnersN, runnersEach: money2.runnersEach, entryEach: money2.entryEach, entryUpTo: money2.entryUpTo },
|
|
8529
8529
|
...share ? { share: { network: share.network, node: share.node } } : {},
|
|
8530
8530
|
...sponsor ? { sponsor: { slug: sponsor.slug, name: sponsor.name, node: sponsor.node } } : {},
|
|
8531
|
-
closes:
|
|
8532
|
-
drop:
|
|
8533
|
-
pick:
|
|
8531
|
+
closes: call2.closes,
|
|
8532
|
+
drop: call2.drop,
|
|
8533
|
+
pick: call2.pick,
|
|
8534
8534
|
...legs ? { legs } : {},
|
|
8535
8535
|
blocks
|
|
8536
8536
|
}
|
|
@@ -9470,7 +9470,7 @@ var init_docPath = __esm({
|
|
|
9470
9470
|
});
|
|
9471
9471
|
|
|
9472
9472
|
// ../../packages/openhands-sdk/src/data/docUrls.ts
|
|
9473
|
-
var VFS_BY_NETWORK, vfsUrlFor, DEFAULT_IPFS_GATEWAY_URL, vfsUrl, laneVfsUrl, ipfsGatewayUrl, vfsDocUrl, ipfsDocUrl, docUrlBeside, docUrls, docHosts;
|
|
9473
|
+
var VFS_BY_NETWORK, vfsUrlFor, SUBSCRIPTIONS_BY_NETWORK, subscriptionsUrlFor, DEFAULT_IPFS_GATEWAY_URL, vfsUrl, laneVfsUrl, ipfsGatewayUrl, vfsDocUrl, ipfsDocUrl, docUrlBeside, docUrls, docHosts;
|
|
9474
9474
|
var init_docUrls = __esm({
|
|
9475
9475
|
"../../packages/openhands-sdk/src/data/docUrls.ts"() {
|
|
9476
9476
|
"use strict";
|
|
@@ -9484,6 +9484,12 @@ var init_docUrls = __esm({
|
|
|
9484
9484
|
mainnet: "https://vfs.ixo.earth"
|
|
9485
9485
|
};
|
|
9486
9486
|
vfsUrlFor = (net) => VFS_BY_NETWORK[net];
|
|
9487
|
+
SUBSCRIPTIONS_BY_NETWORK = {
|
|
9488
|
+
devnet: "https://subscriptions-api.ixo-api.workers.dev",
|
|
9489
|
+
testnet: "https://subscriptions-api-testnet.ixo-api.workers.dev",
|
|
9490
|
+
mainnet: "https://subscriptions-api-mainnet.ixo-api.workers.dev"
|
|
9491
|
+
};
|
|
9492
|
+
subscriptionsUrlFor = (net) => SUBSCRIPTIONS_BY_NETWORK[net];
|
|
9487
9493
|
DEFAULT_IPFS_GATEWAY_URL = "https://ipfs.gateway.ixo.world";
|
|
9488
9494
|
vfsUrl = () => (givenConfig().vfsUrl ?? (hasEnv() ? firstSet(process.env.NEXT_PUBLIC_VFS_URL) : void 0) ?? VFS_BY_NETWORK[network()]).replace(/\/+$/, "");
|
|
9489
9495
|
laneVfsUrl = () => ((hasEnv() ? firstSet(process.env.NEXT_PUBLIC_LANE_VFS_URL) : void 0) ?? vfsUrl()).replace(/\/+$/, "");
|
|
@@ -28378,18 +28384,18 @@ function waysIn(org, oracle, sourceId) {
|
|
|
28378
28384
|
`In Claude Code: eval-oracle api review-billing enable --source ${sourceId ?? "<source id>"} --kit ${oracle.url.replace(/\/$/, "")} --cap <dollars> (it previews first; add --yes to sign).`
|
|
28379
28385
|
];
|
|
28380
28386
|
}
|
|
28381
|
-
async function sourceCall(oracleUrl2, audience, mint,
|
|
28387
|
+
async function sourceCall(oracleUrl2, audience, mint, call2, options = {}) {
|
|
28382
28388
|
try {
|
|
28383
|
-
const response = await (options.fetch ?? fetch)(`${base3(oracleUrl2)}${
|
|
28384
|
-
method:
|
|
28389
|
+
const response = await (options.fetch ?? fetch)(`${base3(oracleUrl2)}${call2.path}`, {
|
|
28390
|
+
method: call2.method ?? "GET",
|
|
28385
28391
|
headers: {
|
|
28386
28392
|
accept: "application/json",
|
|
28387
|
-
authorization: `Bearer ${await mint(audience,
|
|
28393
|
+
authorization: `Bearer ${await mint(audience, call2.can, call2.sourceId)}`,
|
|
28388
28394
|
"x-auth-type": "ucan",
|
|
28389
|
-
...
|
|
28390
|
-
...
|
|
28395
|
+
...call2.sourceId ? { "x-source-id": call2.sourceId } : {},
|
|
28396
|
+
...call2.body !== void 0 ? { "content-type": "application/json" } : {}
|
|
28391
28397
|
},
|
|
28392
|
-
...
|
|
28398
|
+
...call2.body !== void 0 ? { body: JSON.stringify(call2.body) } : {},
|
|
28393
28399
|
signal: AbortSignal.timeout(TIMEOUT2)
|
|
28394
28400
|
});
|
|
28395
28401
|
const body = await response.json().catch(() => null);
|
|
@@ -28901,6 +28907,7 @@ __export(docs_exports, {
|
|
|
28901
28907
|
readDocJson: () => readDocJson,
|
|
28902
28908
|
rememberDocStore: () => rememberDocStore,
|
|
28903
28909
|
resolveDocUrl: () => resolveDocUrl,
|
|
28910
|
+
subscriptionsUrlFor: () => subscriptionsUrlFor,
|
|
28904
28911
|
vfsDocUrl: () => vfsDocUrl,
|
|
28905
28912
|
vfsUrl: () => vfsUrl,
|
|
28906
28913
|
vfsUrlFor: () => vfsUrlFor
|
|
@@ -250689,10 +250696,10 @@ var require_get_proto = __commonJS({
|
|
|
250689
250696
|
var require_hasown = __commonJS({
|
|
250690
250697
|
"../../node_modules/.pnpm/hasown@2.0.4/node_modules/hasown/index.js"(exports, module) {
|
|
250691
250698
|
"use strict";
|
|
250692
|
-
var
|
|
250699
|
+
var call2 = Function.prototype.call;
|
|
250693
250700
|
var $hasOwn = Object.prototype.hasOwnProperty;
|
|
250694
250701
|
var bind2 = require_function_bind();
|
|
250695
|
-
module.exports = bind2.call(
|
|
250702
|
+
module.exports = bind2.call(call2, $hasOwn);
|
|
250696
250703
|
}
|
|
250697
250704
|
});
|
|
250698
250705
|
|
|
@@ -260281,7 +260288,7 @@ var init_privateLane = __esm({
|
|
|
260281
260288
|
"use strict";
|
|
260282
260289
|
init_cid4();
|
|
260283
260290
|
init_lane();
|
|
260284
|
-
workerUrl = (network2, env = process.env) => (env.OPENHANDS_WORKER_URL?.trim() || (network2 === "mainnet" ? "https://api.
|
|
260291
|
+
workerUrl = (network2, env = process.env) => (env.OPENHANDS_WORKER_URL?.trim() || (network2 === "mainnet" ? "https://api.asks.world" : "https://test.api.asks.world")).replace(/\/+$/, "");
|
|
260285
260292
|
passLink = (site, id, agentDid, collectionId, can, exp) => `${site.replace(/\/+$/, "")}/pass?${new URLSearchParams({ id, agent: agentDid, ask: collectionId, can: can === "fs/write" ? "write" : "read", exp: String(Math.floor(exp)) })}`;
|
|
260286
260293
|
shareLink = (site, collectionId, approver, exp = Math.floor((Date.now() + BOX_TTL_MS) / 1e3)) => `${site.replace(/\/+$/, "")}/pass?${new URLSearchParams({ ask: collectionId, can: "share", to: approver, exp: String(Math.floor(exp)) })}`;
|
|
260287
260294
|
shareLine = (site, collectionId, isPrivate, approver, poster) => isPrivate && approver && poster && approver !== poster ? `The answers are private. So the person giving final approval can read them, open this link and tap Allow:
|
|
@@ -261302,13 +261309,16 @@ function prepareAsk(poster, entityDid, adminAccount, terms, now3 = Date.now(), s
|
|
|
261302
261309
|
if (shape?.org && !isEntityDid(shape.org)) throw new Error(`the org must be an entity DID, got ${JSON.stringify(shape.org)}`);
|
|
261303
261310
|
const offChain = Boolean(shape?.offChain);
|
|
261304
261311
|
if (offChain && !shape?.org) throw new Error("an ask paid off chain is posted for an organisation: pass org");
|
|
261312
|
+
const card = shape?.fundedBy === "card";
|
|
261313
|
+
if (card && (shape?.org || offChain)) throw new Error("a card pays a person's ask on chain: not an organisation's, not off chain");
|
|
261314
|
+
if (card && (terms.denom ?? askDenom()) !== "upay") throw new Error("a card-funded reward is PAY: IXO's card service sends PAY");
|
|
261305
261315
|
const checkReward = terms.checker && terms.checkRewardUixo ? BigInt(terms.checkRewardUixo) : 0n;
|
|
261306
261316
|
const spots = BigInt(Math.max(1, terms.quota));
|
|
261307
261317
|
const denom = terms.denom ?? askDenom();
|
|
261308
|
-
if (denom === "upay" && !offChain && network() === "mainnet" && askDenom() !== "upay") throw new Error("PAY is not a reward coin on mainnet: post the reward in USDC");
|
|
261318
|
+
if (denom === "upay" && !offChain && !card && network() === "mainnet" && askDenom() !== "upay") throw new Error("PAY is not a reward coin on mainnet: post the reward in USDC");
|
|
261309
261319
|
const feeDenom = terms.feeDenom ?? checkerFeeDenom(network());
|
|
261310
|
-
const rewardEscrow = offChain ? 0n : BigInt(terms.amountUixo) * spots;
|
|
261311
|
-
const feeEscrow = checkReward * spots;
|
|
261320
|
+
const rewardEscrow = offChain || card ? 0n : BigInt(terms.amountUixo) * spots;
|
|
261321
|
+
const feeEscrow = card && feeDenom === "upay" ? 0n : checkReward * spots;
|
|
261312
261322
|
const coins = coinsOf([[denom, rewardEscrow], [feeDenom, feeEscrow]]);
|
|
261313
261323
|
const orgFunds = Boolean(shape?.org) && coins.length > 0;
|
|
261314
261324
|
const orgAdmin = shape?.orgAdmin ?? null;
|
|
@@ -261368,7 +261378,7 @@ function prepareAsk(poster, entityDid, adminAccount, terms, now3 = Date.now(), s
|
|
|
261368
261378
|
poster,
|
|
261369
261379
|
escrow: { denom: recorded, amount: coins.find((coin) => coin.denom === recorded)?.amount ?? "0" },
|
|
261370
261380
|
...feeEscrow > 0n && feeDenom !== recorded ? { fee: { denom: feeDenom, amount: String(feeEscrow), from: orgFunds ? "org" : "poster" } } : {},
|
|
261371
|
-
...orgFunds ? { fundedBy: "org" } : {},
|
|
261381
|
+
...orgFunds ? { fundedBy: "org" } : card ? { fundedBy: "card" } : {},
|
|
261372
261382
|
preparedAt: new Date(now3).toISOString(),
|
|
261373
261383
|
txHash: null,
|
|
261374
261384
|
...shape ? { claimProtocolDid: shape.claimProtocolDid } : {}
|
|
@@ -263381,8 +263391,8 @@ function lineSentence(line2) {
|
|
|
263381
263391
|
if (sentence4.length > 300) throw new Error(`a judged line is ${sentence4.length} characters with its failure; the jury reads 300 at most`);
|
|
263382
263392
|
return sentence4;
|
|
263383
263393
|
}
|
|
263384
|
-
function legCall(
|
|
263385
|
-
const read9 = callOf({ ...
|
|
263394
|
+
function legCall(call2, leg) {
|
|
263395
|
+
const read9 = callOf({ ...call2, leg });
|
|
263386
263396
|
if (!read9) throw new Error("the call does not read back: a field is missing, too long, or not an https address");
|
|
263387
263397
|
return read9.call;
|
|
263388
263398
|
}
|
|
@@ -263394,10 +263404,10 @@ function taskFor(title, leg, kind) {
|
|
|
263394
263404
|
function callEntriesTerms(input) {
|
|
263395
263405
|
if (input.lines.length !== CALL_LIMITS.lines) throw new Error(`a call is judged on exactly ${CALL_LIMITS.lines} lines`);
|
|
263396
263406
|
if (input.judge.kind !== "oracle" || !input.judge.address) throw new Error("the entries are judged by the oracle, and it has to be named");
|
|
263397
|
-
const
|
|
263398
|
-
if (
|
|
263399
|
-
if (
|
|
263400
|
-
if (
|
|
263407
|
+
const call2 = legCall(input.call, "entries");
|
|
263408
|
+
if (call2.points.length !== CALL_LIMITS.lines) throw new Error("one score per judged line");
|
|
263409
|
+
if (call2.kind === "review" && !input.report) throw new Error("a review call's entries are reports: say report (the extra sections, or none)");
|
|
263410
|
+
if (call2.kind !== "review" && input.report) throw new Error("only a review call is answered as a report");
|
|
263401
263411
|
if (input.approver !== void 0 && !/^ixo1[a-z0-9]{38,64}$/.test(input.approver)) throw new Error("approver is an ixo1 address");
|
|
263402
263412
|
const criteria = [
|
|
263403
263413
|
{ id: "present", kind: "measure", gate: { id: "non-empty" } },
|
|
@@ -263406,11 +263416,11 @@ function callEntriesTerms(input) {
|
|
|
263406
263416
|
];
|
|
263407
263417
|
const terms = {
|
|
263408
263418
|
v: 2,
|
|
263409
|
-
task: taskFor(
|
|
263419
|
+
task: taskFor(call2.title, "entries", call2.kind),
|
|
263410
263420
|
deliverable: { type: "text", prompt: input.report ? REVIEW_DELIVERABLE_PROMPT : "One page, in your own words, covering all five requirements" },
|
|
263411
|
-
campaign: callTag(
|
|
263421
|
+
campaign: callTag(call2.slug),
|
|
263412
263422
|
...input.access ? { access: input.access } : {},
|
|
263413
|
-
call,
|
|
263423
|
+
call: call2,
|
|
263414
263424
|
criteria,
|
|
263415
263425
|
judge: input.judge,
|
|
263416
263426
|
...input.approver ? { approver: input.approver } : {}
|
|
@@ -263418,17 +263428,17 @@ function callEntriesTerms(input) {
|
|
|
263418
263428
|
return input.report ? withReport(terms, input.report, input.approver ? { v: 2 } : void 0) : terms;
|
|
263419
263429
|
}
|
|
263420
263430
|
function callPickTerms(input) {
|
|
263421
|
-
const
|
|
263422
|
-
if (
|
|
263431
|
+
const call2 = legCall(input.call, input.leg);
|
|
263432
|
+
if (call2.mode === "hire") throw new Error("a hiring call has no pick: the entries are the whole call");
|
|
263423
263433
|
const which = input.leg === "prize" ? "the pick" : "a runner-up";
|
|
263424
263434
|
return {
|
|
263425
263435
|
v: 2,
|
|
263426
|
-
task: taskFor(
|
|
263436
|
+
task: taskFor(call2.title, input.leg),
|
|
263427
263437
|
deliverable: { type: "text", prompt: "Quote the number of your entry, nothing else" },
|
|
263428
|
-
campaign: callTag(
|
|
263438
|
+
campaign: callTag(call2.slug),
|
|
263429
263439
|
...input.access ? { access: input.access } : {},
|
|
263430
|
-
call,
|
|
263431
|
-
criteria: [{ id: "picked", kind: "attest", text: `The poster chose this entry as ${which} of call ${
|
|
263440
|
+
call: call2,
|
|
263441
|
+
criteria: [{ id: "picked", kind: "attest", text: `The poster chose this entry as ${which} of call ${call2.slug}` }],
|
|
263432
263442
|
judge: { kind: "poster" }
|
|
263433
263443
|
};
|
|
263434
263444
|
}
|
|
@@ -263440,8 +263450,8 @@ function callDates(openDays, now3 = Date.now(), mode) {
|
|
|
263440
263450
|
}
|
|
263441
263451
|
return { closes: new Date(closes).toISOString(), drop: new Date(closes + DAY_MS2).toISOString(), pick: new Date(closes + 4 * DAY_MS2).toISOString() };
|
|
263442
263452
|
}
|
|
263443
|
-
function legDays(
|
|
263444
|
-
const until = leg === "entries" ? Date.parse(
|
|
263453
|
+
function legDays(call2, leg, now3 = Date.now()) {
|
|
263454
|
+
const until = leg === "entries" ? Date.parse(call2.closes) : Date.parse(call2.pick) + 7 * DAY_MS2;
|
|
263445
263455
|
return Math.max(1, Math.ceil((until - now3) / DAY_MS2));
|
|
263446
263456
|
}
|
|
263447
263457
|
var ENTRY_MIN_CHARS, REVIEW_LINES, REVIEW_DELIVERABLE_PROMPT, DAY_MS2, legsOf, pickQuota;
|
|
@@ -263461,7 +263471,7 @@ var init_call = __esm({
|
|
|
263461
263471
|
];
|
|
263462
263472
|
REVIEW_DELIVERABLE_PROMPT = "A review report: what you tested, your steps per scenario, each finding with its evidence, how to reproduce it and its severity, what to change, and the limitations";
|
|
263463
263473
|
DAY_MS2 = 24 * 3600 * 1e3;
|
|
263464
|
-
legsOf = (
|
|
263474
|
+
legsOf = (call2) => call2.mode === "hire" ? ["entries"] : ["prize", ...call2.money.runnersN > 0 ? ["runnersUp"] : [], "entries"];
|
|
263465
263475
|
pickQuota = (winners) => winners + 2;
|
|
263466
263476
|
}
|
|
263467
263477
|
});
|
|
@@ -263534,12 +263544,12 @@ __export(callRead_exports, {
|
|
|
263534
263544
|
sharedPay: () => sharedPay,
|
|
263535
263545
|
stageWords: () => stageWords
|
|
263536
263546
|
});
|
|
263537
|
-
function stageWords(
|
|
263538
|
-
if (now3 < Date.parse(
|
|
263539
|
-
if (
|
|
263540
|
-
if (now3 < Date.parse(
|
|
263541
|
-
if (now3 < Date.parse(
|
|
263542
|
-
return `closed; the pick was due ${day(
|
|
263547
|
+
function stageWords(call2, now3 = Date.now()) {
|
|
263548
|
+
if (now3 < Date.parse(call2.closes)) return `open until ${day(call2.closes)}`;
|
|
263549
|
+
if (call2.mode === "hire") return `closed ${day(call2.closes)}; every entry that passed is paid as it is judged`;
|
|
263550
|
+
if (now3 < Date.parse(call2.drop)) return `closed ${day(call2.closes)}; the shortlist shows ${day(call2.drop)}`;
|
|
263551
|
+
if (now3 < Date.parse(call2.pick)) return `closed; the shortlist is out; the pick by ${day(call2.pick)}`;
|
|
263552
|
+
return `closed; the pick was due ${day(call2.pick)}`;
|
|
263543
263553
|
}
|
|
263544
263554
|
function sharedPay(quote, share) {
|
|
263545
263555
|
const leg = grossFor(Math.round(quote * 1e6), share);
|
|
@@ -263572,36 +263582,36 @@ ${block2.prompt}`;
|
|
|
263572
263582
|
}
|
|
263573
263583
|
function callReadout(terms, ctx) {
|
|
263574
263584
|
const amount3 = (value, symbol2) => dollarsOfValue(value, symbol2, ctx.network ?? "mainnet");
|
|
263575
|
-
const
|
|
263576
|
-
const m =
|
|
263577
|
-
const hire =
|
|
263585
|
+
const call2 = terms.call;
|
|
263586
|
+
const m = call2.money;
|
|
263587
|
+
const hire = call2.mode === "hire";
|
|
263578
263588
|
const lines2 = terms.criteria.filter((one) => one.kind === "judge").map((one) => one.text);
|
|
263579
263589
|
const n = countWords(lines2.length || 5);
|
|
263580
|
-
const entriesId =
|
|
263590
|
+
const entriesId = call2.leg === "entries" ? ctx.id : call2.legs?.entries;
|
|
263581
263591
|
const money2 = hire ? [`every entry that passes all ${n} lines is paid ${amount3(m.entryEach, ctx.symbol)}, up to ${m.entryUpTo} ${m.entryUpTo === 1 ? "entry" : "entries"}; there is no pick`] : [
|
|
263582
263592
|
`the pick gets ${amount3(m.prize, ctx.symbol)}`,
|
|
263583
263593
|
m.runnersN > 0 ? `${m.runnersN} runner${m.runnersN === 1 ? "-up gets" : "s-up get"} ${amount3(m.runnersEach, ctx.symbol)} each` : "",
|
|
263584
263594
|
`every entry that passes all ${n} lines is paid ${amount3(m.entryEach, ctx.symbol)}, up to ${m.entryUpTo}`
|
|
263585
263595
|
].filter(Boolean);
|
|
263586
263596
|
const who = terms.access === "invite" ? "By invitation: only the people the poster put on the list can enter. If you were sent a link, pass it as submit_work's `invite`; if your address or page was named, nothing more is needed." : terms.access === "apply" ? "By application: apply_to_call first, with a short note; when the poster says yes, submit_work is admitted." : "Open to anyone.";
|
|
263587
|
-
const review =
|
|
263588
|
-
const shared =
|
|
263589
|
-
const shareLine2 = shared &&
|
|
263590
|
-
const proMoney =
|
|
263597
|
+
const review = call2.kind === "review";
|
|
263598
|
+
const shared = call2.share ? sharedPay(m.entryEach, call2.share) : null;
|
|
263599
|
+
const shareLine2 = shared && call2.share ? `each ${review ? "pro" : hire ? "hired person" : "entry paid"} receives ${amount3(shared.receives, ctx.symbol)} (the leg is ${amount3(shared.leg, ctx.symbol)}; the network keeps ${amount3(shared.keeps, ctx.symbol)}: ${shareWords(call2.share, "as posted")})${hire ? "" : "; the pick's and the runners-up's legs carry the same share on top of theirs"}` : "";
|
|
263600
|
+
const proMoney = call2.sponsor && call2.share && hire ? `Money: ${feeLine({ split: call2.share, sponsorName: call2.sponsor.name, net: m.entryEach, symbol: ctx.symbol, network: ctx.network ?? "mainnet" })} Up to ${m.entryUpTo} ${m.entryUpTo === 1 ? "report is" : "reports are"} paid, each one that passes all ${n} lines; there is no pick. Held on the ask's own account before anyone enters.` : null;
|
|
263591
263601
|
const out = [
|
|
263592
|
-
`${review ? "Pro ask" : hire ? "Hiring call" : "Open call"} "${
|
|
263602
|
+
`${review ? "Pro ask" : hire ? "Hiring call" : "Open call"} "${call2.slug}" \xB7 posted by ${call2.poster} \xB7 ${stageWords(call2, ctx.now)}`,
|
|
263593
263603
|
...review && ctx.site ? [`Its page: ${proOrigin(ctx.site)}/pro/reviews/${ctx.id}`] : [],
|
|
263594
|
-
...
|
|
263595
|
-
|
|
263596
|
-
|
|
263597
|
-
...review &&
|
|
263598
|
-
...review &&
|
|
263604
|
+
...call2.sponsor ? [`Marketplace: ${call2.sponsor.name} (sponsor "${call2.sponsor.slug}"), which verifies the pros on this pro ask and stands behind them.`] : [],
|
|
263605
|
+
call2.title,
|
|
263606
|
+
call2.lede,
|
|
263607
|
+
...review && call2.subject ? [`Reviewing: ${call2.subject.name}${call2.subject.version ? ` ${call2.subject.version}` : ""}${call2.subject.where ? ` \xB7 ${call2.subject.where}` : ""}. Access details, if any, are in your invitation.`] : [],
|
|
263608
|
+
...review && call2.scenarios?.length ? ["Scenarios, each one a step in your report:", ...call2.scenarios.map((one, index) => ` S${index + 1}. ${one}`)] : [],
|
|
263599
263609
|
proMoney ?? `Money: ${[...money2, shareLine2].filter(Boolean).join("; ")}. Locked in ${hire ? "the ask's own account" : "each leg's own account"} before anyone enters.`,
|
|
263600
263610
|
who,
|
|
263601
|
-
|
|
263611
|
+
call2.leg === "entries" ? review ? `Enter: a review report with screenshots, as submit_work's report and files, collectionId "${ctx.id}"${terms.approver ? `; the AI checks it against the requirements, then ${terms.approver} gives final approval to release payment` : "; the AI checks it against the requirements and a passing report is paid"}. One report per account.` : `Enter: one page of text, in your own words: submit_work collectionId "${ctx.id}". One entry per account.` : `The pick's leg: only the entry the poster picked may claim here, with one line naming it. ${entriesId ? `The entries are ask ${entriesId}.` : "The entries are the call's own ask."}`,
|
|
263602
263612
|
hire ? `Judged: ${n} requirements that every entry must meet. Pass all ${n} and the entry is paid on approval; nobody is picked.` : `Judged: ${n} requirements that every entry must meet. Pass all ${n} and the entry is paid; how clearly it meets each requirement ranks the entries for the pick.`,
|
|
263603
263613
|
"",
|
|
263604
|
-
...
|
|
263614
|
+
...call2.blocks.map(blockText).flatMap((text4) => [text4, ""]),
|
|
263605
263615
|
`The ${n} requirements:`,
|
|
263606
263616
|
...lines2.length ? lines2.map((text4, index) => `${index + 1}. ${text4}`) : ["(on the entries ask)"]
|
|
263607
263617
|
];
|
|
@@ -264483,6 +264493,74 @@ var init_call2 = __esm({
|
|
|
264483
264493
|
}
|
|
264484
264494
|
});
|
|
264485
264495
|
|
|
264496
|
+
// src/payDraft.ts
|
|
264497
|
+
var payDraft_exports = {};
|
|
264498
|
+
__export(payDraft_exports, {
|
|
264499
|
+
DRAFT_ID: () => DRAFT_ID,
|
|
264500
|
+
cardPreview: () => cardPreview,
|
|
264501
|
+
confirmToken: () => confirmToken,
|
|
264502
|
+
draftStatus: () => draftStatus,
|
|
264503
|
+
quoteOf: () => quoteOf,
|
|
264504
|
+
saveDraft: () => saveDraft
|
|
264505
|
+
});
|
|
264506
|
+
function quoteOf(rewardBase, feeBase) {
|
|
264507
|
+
const proReceivesCents = Math.round(rewardBase / 1e4);
|
|
264508
|
+
const feeCents = Math.round(feeBase / 1e4);
|
|
264509
|
+
return { proReceivesCents, feeCents, youPayCents: proReceivesCents + feeCents };
|
|
264510
|
+
}
|
|
264511
|
+
function cardPreview(quote) {
|
|
264512
|
+
if (quote.youPayCents < MIN_CENTS || quote.youPayCents > MAX_CENTS) return { refused: `a card payment is ${dollars3(MIN_CENTS)} to ${dollars3(MAX_CENTS)}, and this is ${dollars3(quote.youPayCents)}` };
|
|
264513
|
+
return [
|
|
264514
|
+
`Pro receives ${dollars3(quote.proReceivesCents)} \xB7 Fee ${dollars3(quote.feeCents)} \xB7 You pay ${dollars3(quote.youPayCents)}`,
|
|
264515
|
+
"Paid by card: I'll give you a link where the person pays and posts it from their own account. Nothing is signed or spent here.",
|
|
264516
|
+
"",
|
|
264517
|
+
`To go ahead, call again with confirm: "${confirmToken(quote)}".`
|
|
264518
|
+
].join("\n");
|
|
264519
|
+
}
|
|
264520
|
+
async function call(site, path, body, fetchImpl) {
|
|
264521
|
+
const response = await fetchImpl(`${site.replace(/\/+$/, "")}${path}`, {
|
|
264522
|
+
method: body === null ? "GET" : "POST",
|
|
264523
|
+
headers: { accept: "application/json", ...body === null ? {} : { "content-type": "application/json" } },
|
|
264524
|
+
...body === null ? {} : { body: JSON.stringify(body) },
|
|
264525
|
+
signal: AbortSignal.timeout(2e4)
|
|
264526
|
+
});
|
|
264527
|
+
const parsed = await response.json().catch(() => ({}));
|
|
264528
|
+
return { status: response.status, body: parsed };
|
|
264529
|
+
}
|
|
264530
|
+
async function saveDraft(site, draft, fetchImpl = fetch) {
|
|
264531
|
+
const saved = await call(site, "/api/pay-drafts", draft, fetchImpl).catch((error54) => ({ status: 0, body: { error: error54 instanceof Error ? error54.message : String(error54) } }));
|
|
264532
|
+
const id = saved.body.id;
|
|
264533
|
+
if (saved.status !== 201 || typeof id !== "string" || !DRAFT_ID.test(id)) return `The pay link could not be made (${String(saved.body.error ?? saved.status)}). Nothing was posted and nothing was spent. Try again shortly.`;
|
|
264534
|
+
return [
|
|
264535
|
+
`Saved. The person pays ${confirmToken(draft.quote)} by card and posts it here, within 24 hours:`,
|
|
264536
|
+
`${site.replace(/\/+$/, "")}/pay/${id}`,
|
|
264537
|
+
`Nothing was posted or spent yet. read_ask "${id}" says whether it is paid and live.`
|
|
264538
|
+
].join("\n");
|
|
264539
|
+
}
|
|
264540
|
+
async function draftStatus(site, id, fetchImpl = fetch) {
|
|
264541
|
+
const read9 = await call(site, `/api/pay-drafts/${id}`, null, fetchImpl).catch(() => ({ status: 0, body: {} }));
|
|
264542
|
+
const link5 = `${site.replace(/\/+$/, "")}/pay/${id}`;
|
|
264543
|
+
if (read9.status === 404) return `No pay link "${id}" on this network.`;
|
|
264544
|
+
if (read9.status === 410) return "That pay link expired unpaid (links last 24 hours). Nothing was paid or posted: post it again for a new link.";
|
|
264545
|
+
if (read9.status !== 200) return "The pay link could not be read just now. Ask me again in a minute.";
|
|
264546
|
+
const { state, collection, quote } = read9.body;
|
|
264547
|
+
if (state === "posted" && collection) return `Live as ask #${collection}: ${site.replace(/\/+$/, "")}/t/${collection}`;
|
|
264548
|
+
const pays = quote ? ` (${confirmToken(quote)})` : "";
|
|
264549
|
+
if (state === "paying") return `Paying${pays}: the card payment has started at ${link5}. It goes live once the money reaches the ask.`;
|
|
264550
|
+
return `Waiting for payment${pays}: nobody has paid at ${link5} yet.`;
|
|
264551
|
+
}
|
|
264552
|
+
var DRAFT_ID, MIN_CENTS, MAX_CENTS, dollars3, confirmToken;
|
|
264553
|
+
var init_payDraft = __esm({
|
|
264554
|
+
"src/payDraft.ts"() {
|
|
264555
|
+
"use strict";
|
|
264556
|
+
DRAFT_ID = /^[A-Za-z0-9_-]{22}$/;
|
|
264557
|
+
MIN_CENTS = 500;
|
|
264558
|
+
MAX_CENTS = 5e4;
|
|
264559
|
+
dollars3 = (cents2) => `$${(cents2 / 100).toFixed(2)}`;
|
|
264560
|
+
confirmToken = (quote) => dollars3(quote.youPayCents);
|
|
264561
|
+
}
|
|
264562
|
+
});
|
|
264563
|
+
|
|
264486
264564
|
// ../../packages/openhands-sdk/src/chain/inviteMessages.ts
|
|
264487
264565
|
async function inviteOpWords(op, collectionId, issuer, body, now3 = Date.now()) {
|
|
264488
264566
|
return inviteOpMessage(op, collectionId, issuer, now3, INVITE_WRITES.includes(op) ? await digestOf(inviteOpBody(op, body)) : void 0);
|
|
@@ -266264,10 +266342,10 @@ function clean5(raw) {
|
|
|
266264
266342
|
return text4.length <= MAX_LENGTH ? text4 : `${text4.slice(0, MAX_LENGTH - 1).trimEnd()}\u2026`;
|
|
266265
266343
|
}
|
|
266266
266344
|
async function placeName(point, zoom, reach = {}) {
|
|
266267
|
-
const
|
|
266345
|
+
const call2 = reach.fetch ?? globalThis.fetch;
|
|
266268
266346
|
const url4 = `${ENDPOINT}?lat=${encodeURIComponent(point.lat)}&lon=${encodeURIComponent(point.lon)}&format=jsonv2&zoom=${encodeURIComponent(zoom)}`;
|
|
266269
266347
|
try {
|
|
266270
|
-
const response = await
|
|
266348
|
+
const response = await call2(url4, {
|
|
266271
266349
|
headers: { "user-agent": USER_AGENT, accept: "application/json" },
|
|
266272
266350
|
signal: AbortSignal.timeout(TIMEOUT_MS6)
|
|
266273
266351
|
});
|
|
@@ -267521,8 +267599,8 @@ function readKalshiEvent(body, url4) {
|
|
|
267521
267599
|
const markets = event.markets ?? body.markets ?? [];
|
|
267522
267600
|
const first = markets[0];
|
|
267523
267601
|
const priceOf2 = (m) => {
|
|
267524
|
-
const
|
|
267525
|
-
if (Number.isFinite(
|
|
267602
|
+
const dollars4 = Number(m.last_price_dollars);
|
|
267603
|
+
if (Number.isFinite(dollars4) && m.last_price_dollars !== void 0) return dollars4;
|
|
267526
267604
|
return typeof m.last_price === "number" ? m.last_price / 100 : null;
|
|
267527
267605
|
};
|
|
267528
267606
|
const question = event.sub_title ? `${event.title} (${event.sub_title})` : event.title;
|
|
@@ -267554,7 +267632,7 @@ var HEADERS, rulesOf2, jsonList;
|
|
|
267554
267632
|
var init_market = __esm({
|
|
267555
267633
|
"src/market.ts"() {
|
|
267556
267634
|
"use strict";
|
|
267557
|
-
HEADERS = { "user-agent": "Mozilla/5.0 (compatible; asks-mcp; +https://
|
|
267635
|
+
HEADERS = { "user-agent": "Mozilla/5.0 (compatible; asks-mcp; +https://asks.world)", accept: "application/json" };
|
|
267558
267636
|
rulesOf2 = (text4) => {
|
|
267559
267637
|
if (typeof text4 !== "string" || !text4.trim()) return void 0;
|
|
267560
267638
|
const clean6 = text4.replace(/\s+/g, " ").trim();
|
|
@@ -292028,7 +292106,7 @@ import { randomBytes as randomBytes7 } from "node:crypto";
|
|
|
292028
292106
|
// package.json
|
|
292029
292107
|
var package_default = {
|
|
292030
292108
|
name: "@ixo/asks-mcp",
|
|
292031
|
-
version: "1.6.0
|
|
292109
|
+
version: "1.6.0",
|
|
292032
292110
|
description: "The Openhands Network MCP server: read the board, answer asks, post work and get paid on the ixo chain, with a key of its own on your machine.",
|
|
292033
292111
|
license: "Apache-2.0",
|
|
292034
292112
|
repository: {
|
|
@@ -292187,7 +292265,7 @@ var TOOLS = {
|
|
|
292187
292265
|
},
|
|
292188
292266
|
read_ask: {
|
|
292189
292267
|
title: "Read one ask",
|
|
292190
|
-
description:
|
|
292268
|
+
description: `The full terms of one ask. What would count as done, what it pays, who posted it. Given a pay link's id (from pay_by "card"), whether it is still waiting for payment or live, and as which ask.`,
|
|
292191
292269
|
spends: false,
|
|
292192
292270
|
hosted: true,
|
|
292193
292271
|
annotations: reads
|
|
@@ -292208,9 +292286,9 @@ var TOOLS = {
|
|
|
292208
292286
|
},
|
|
292209
292287
|
post_ask: {
|
|
292210
292288
|
title: "Post an ask (spends money)",
|
|
292211
|
-
description: `Escrow money against a task for somebody else to do. Money moves. Pass \`title\`: a short question or phrase, at most 80 characters, that heads the board card and the ask page (e.g. "Is Red Harbor Ketchup on the shelf at Pick n Pay?"); \`task\` is everything whoever answers must do. Requires \`confirm\` to restate the exact total you were shown. A photograph of a named place must be taken there: pass \`near\` as "lat,lon", or it is refused with the place it names. Private asks: pass \`access\` "invite" (only people you invite can answer; not on the public board) or "apply" (people apply, you say yes), with \`invite\` (addresses, @handles, or "link" per single-use link). Default: anyone can answer. The board marks it as an agent's ask. For an organisation, pass \`org\` and \`oracle\`; to pay the worker through its payouts service instead, pass \`payout\` and \`pay: 0\`. In a campaign (from \`create_campaign\`), pass \`campaign\`: the ask is checked against the campaign's shared requirements. \`image\` (png, jpg or webp, at most 5 MB) is the ask's picture. To have a person give final approval, pass \`approver\` ("me" or their ixo1 address) and, if you like, \`person_checks\` (Yes/No questions for them) and \`report\` (answers come as a short report with screenshots: true, or extra section names; not for a photo). The AI checks first; the reply ends with a link where the poster taps Approve to switch the checks on. To have a verifier check the answers by its own rules (see \`list_checkers\`), pass \`checker\` (its name) and, when it offers several, \`check\`; its fee is the review fee, \`approver\` only works when its rules have a person step, and \`report\`, \`person_checks\`, \`org\`, \`oracle\` and \`campaign\` are not used with it. ${ASK_RULES}`,
|
|
292289
|
+
description: `Escrow money against a task for somebody else to do. Money moves. Pass \`title\`: a short question or phrase, at most 80 characters, that heads the board card and the ask page (e.g. "Is Red Harbor Ketchup on the shelf at Pick n Pay?"); \`task\` is everything whoever answers must do. Requires \`confirm\` to restate the exact total you were shown. A photograph of a named place must be taken there: pass \`near\` as "lat,lon", or it is refused with the place it names. Private asks: pass \`access\` "invite" (only people you invite can answer; not on the public board) or "apply" (people apply, you say yes), with \`invite\` (addresses, @handles, or "link" per single-use link). Default: anyone can answer. The board marks it as an agent's ask. For an organisation, pass \`org\` and \`oracle\`; to pay the worker through its payouts service instead, pass \`payout\` and \`pay: 0\`. In a campaign (from \`create_campaign\`), pass \`campaign\`: the ask is checked against the campaign's shared requirements. \`image\` (png, jpg or webp, at most 5 MB) is the ask's picture. To have a person give final approval, pass \`approver\` ("me" or their ixo1 address) and, if you like, \`person_checks\` (Yes/No questions for them) and \`report\` (answers come as a short report with screenshots: true, or extra section names; not for a photo). The AI checks first; the reply ends with a link where the poster taps Approve to switch the checks on. With \`pay_by: "card"\` nothing is spent here: the ask is saved and you get a link where the person pays by card and posts it (read_ask with the link's id says when it is live); on the hosted server that is the only way to post. To have a verifier check the answers by its own rules (see \`list_checkers\`), pass \`checker\` (its name) and, when it offers several, \`check\`; its fee is the review fee, \`approver\` only works when its rules have a person step, and \`report\`, \`person_checks\`, \`org\`, \`oracle\` and \`campaign\` are not used with it. ${ASK_RULES}`,
|
|
292212
292290
|
spends: true,
|
|
292213
|
-
hosted:
|
|
292291
|
+
hosted: true,
|
|
292214
292292
|
annotations: acts
|
|
292215
292293
|
},
|
|
292216
292294
|
ask_the_world: {
|
|
@@ -292312,7 +292390,7 @@ var TOOLS = {
|
|
|
292312
292390
|
},
|
|
292313
292391
|
post_call: {
|
|
292314
292392
|
title: "Post an open call or a pro ask (spends money)",
|
|
292315
|
-
description: `Post a drafted open call or pro ask as the account you act for: a competition is three asks under one tag (the prize, the runners-up, the entries), a hire (every pro ask is one) is the entries alone; each holds its money until approval. One leg per call; call again until it says everything is posted. A pro ask confirms its marketplace (\`sponsor\`) with the registry first: the marketplace is written into its terms and earns its share of each approved report; a pro ask that names none, or one whose marketplace is paused or not set up here, is refused before anything moves. A call by invitation writes its list the moment the entries post, and prints the invite links. Pays in this network's own coin, said in dollars. Requires \`confirm\` to restate the exact total from the preview. ${ASK_RULES}`,
|
|
292393
|
+
description: `Post a drafted open call or pro ask as the account you act for: a competition is three asks under one tag (the prize, the runners-up, the entries), a hire (every pro ask is one) is the entries alone; each holds its money until approval. One leg per call; call again until it says everything is posted. A pro ask confirms its marketplace (\`sponsor\`) with the registry first: the marketplace is written into its terms and earns its share of each approved report; a pro ask that names none, or one whose marketplace is paused or not set up here, is refused before anything moves. A call by invitation writes its list the moment the entries post, and prints the invite links. Pays in this network's own coin, said in dollars. With \`pay_by: "card"\` nothing is spent here: the whole call is saved and you get a link where the person pays by card and posts it. Requires \`confirm\` to restate the exact total from the preview. ${ASK_RULES}`,
|
|
292316
292394
|
spends: true,
|
|
292317
292395
|
hosted: false,
|
|
292318
292396
|
annotations: acts
|
|
@@ -292496,7 +292574,7 @@ var PLAN_TOOLS = ["scope_market", "draft_plan", "fund_plan", "close_plan", "plan
|
|
|
292496
292574
|
var WHERE_TO_ACT_NAME = "where_to_act";
|
|
292497
292575
|
var WHERE_TO_ACT = {
|
|
292498
292576
|
title: "Where to post, submit or connect from here",
|
|
292499
|
-
description: "This connector
|
|
292577
|
+
description: "This connector holds no key: it reads, and posts an ask only as a pay link (post_ask with pay_by \"card\"). Anything else that needs signing (posting asks, campaigns, payout settings, Pay for reviews, submitting work, getting paid, company onboarding and deploys) is done in Claude Code with the asks.world plugin (`/plugin install asks@ixo-plugins`), which runs on the user's computer so keys and data stay local. Call this and say so plainly to the user. Posting an ask, submitting work, connecting a person's account, sending earnings home and checking one key's standing need the local server, which holds its own key on the user's machine. This answers with the site's page for the action and the install lines for the local plugin and package.",
|
|
292500
292578
|
spends: false,
|
|
292501
292579
|
hosted: true,
|
|
292502
292580
|
/* Pure: it renders links and install lines and reaches nothing. */
|
|
@@ -292764,7 +292842,7 @@ var RESOURCE_PACKAGES = [
|
|
|
292764
292842
|
{ name: "@ixo/decision-oracle", range: "0.2", what: `company setup: the organisation, its verifier and Pay for reviews (used by ${PLUGIN_NAME})` },
|
|
292765
292843
|
{ name: "@ixo/payouts-facilitator", range: "0.1", what: `a company's own payouts service, for paying workers in USD Coin on Base (used by ${PLUGIN_NAME})` }
|
|
292766
292844
|
];
|
|
292767
|
-
var READ_ONLY_LINE =
|
|
292845
|
+
var READ_ONLY_LINE = 'This connector holds no key: it reads, and posts an ask only as a pay link (post_ask with pay_by "card"), where the person pays by card and posts it on asks.world. To post from your own money, set up payouts, pay for reviews or get paid, use Claude Code with an asks.world plugin (asks): it runs on your computer, so your keys and data stay with you.';
|
|
292768
292846
|
var CLAUDE_CODE_ONE_STEP = "2.1.275";
|
|
292769
292847
|
var PLUGIN_INSTALLS = ["claude-code", "claude-code-older", "codex"];
|
|
292770
292848
|
function pluginLines(install, name8 = PLUGIN_NAME) {
|
|
@@ -294024,7 +294102,7 @@ async function createServer(options) {
|
|
|
294024
294102
|
const server2 = new McpServer(
|
|
294025
294103
|
{ name: MCP_SERVER, version: VERSION6 },
|
|
294026
294104
|
local ? void 0 : {
|
|
294027
|
-
instructions: `asks.world (${NETWORK2}), hosted
|
|
294105
|
+
instructions: `asks.world (${NETWORK2}), hosted, holding no key. List and read asks, collect a verified answer, check how an answer was judged, and save an ask as a pay link the person pays by card (post_ask with pay_by "card"; read_ask with the link's id says when it is live). ${READ_ONLY_LINE} Install inside Claude Code: ${pluginLines("claude-code-older", plugin).replace("\n", " then ")} (plugin ${plugin}). Company onboarding and deploys run in the same plugin. Whenever a user asks for anything that needs signing, say this plainly, then call where_to_act for the website page they can use for a one-off action.`
|
|
294028
294106
|
}
|
|
294029
294107
|
);
|
|
294030
294108
|
const parts = local ? await localParts() : null;
|
|
@@ -294114,7 +294192,7 @@ async function build2(options, server2, parts) {
|
|
|
294114
294192
|
throw new BootError(`refusing to start. ${error54 instanceof Error ? error54.message : String(error54)}`);
|
|
294115
294193
|
}
|
|
294116
294194
|
})() : (
|
|
294117
|
-
/* No tool
|
|
294195
|
+
/* No tool spends in hosted mode (post_ask there only saves a card's pay draft), so nothing reads these. */
|
|
294118
294196
|
{ perAsk: 0, perDay: 0, total: 0, perPlan: 0 }
|
|
294119
294197
|
);
|
|
294120
294198
|
let DEPLOYMENT = options.deployment ?? await deployment().catch((error54) => {
|
|
@@ -294425,18 +294503,18 @@ Each is its own ask and pays on its own. Read one with read_ask before deciding.
|
|
|
294425
294503
|
calls.set(tag, { slug, entries: entries2, shared });
|
|
294426
294504
|
})
|
|
294427
294505
|
);
|
|
294428
|
-
const callLine = (row,
|
|
294506
|
+
const callLine = (row, call2) => {
|
|
294429
294507
|
const summary = row.campaignSummary;
|
|
294430
|
-
const review = isReviewTitle(
|
|
294431
|
-
const title =
|
|
294508
|
+
const review = isReviewTitle(call2.entries?.title);
|
|
294509
|
+
const title = call2.entries?.title.replace(/^(Open call|Expert review): /, "") ?? null;
|
|
294432
294510
|
if (title) taint2(title);
|
|
294433
294511
|
const facts = row.callSummary;
|
|
294434
|
-
const shares =
|
|
294435
|
-
const entryPays = shares && facts?.entryEach !== void 0 &&
|
|
294512
|
+
const shares = call2.shared;
|
|
294513
|
+
const entryPays = shares && facts?.entryEach !== void 0 && call2.entries?.pays ? `${faceOf2({ value: facts.entryEach, symbol: call2.entries.pays.symbol }, SANDBOX)?.text} (the network's share is on top of it)` : call2.entries?.pays ? `${faceOf2(call2.entries.pays, SANDBOX)?.text}${shares ? ", less the network's share" : ""}` : void 0;
|
|
294436
294514
|
return [
|
|
294437
|
-
`${review ? "Expert review" : "Open call"} "${
|
|
294515
|
+
`${review ? "Expert review" : "Open call"} "${call2.slug}" \xB7 ${summary.open} of ${summary.places} legs open${entryPays ? ` \xB7 every ${review ? "report" : "entry"} that meets the bar is paid ${entryPays}` : ""} \xB7 needs-a-human`,
|
|
294438
294516
|
title ? asData("ask-title", title) : "",
|
|
294439
|
-
`${review ? "A specialist's report on the review's scenarios, assessed against its requirements. A report that meets them qualifies for payment, after the builder's final approval when they give one." : "A written entry assessed against five requirements. Entries that meet all five qualify for payment. For competitions, the poster also chooses a prize winner."} ${
|
|
294517
|
+
`${review ? "A specialist's report on the review's scenarios, assessed against its requirements. A report that meets them qualifies for payment, after the builder's final approval when they give one." : "A written entry assessed against five requirements. Entries that meet all five qualify for payment. For competitions, the poster also chooses a prize winner."} ${call2.entries ? `Read it with read_ask "${call2.entries.id}"; the page is` : "Read its legs on the page:"} ${review ? `${EXPERT_SITE}/pro/reviews/${call2.entries?.id ?? call2.slug}` : `${SITE}/opencall/${call2.slug}`}`
|
|
294440
294518
|
].filter(Boolean).join("\n");
|
|
294441
294519
|
};
|
|
294442
294520
|
const lines2 = board.rows.filter(within2).map((row) => {
|
|
@@ -294454,8 +294532,8 @@ Each is its own ask and pays on its own. Read one with read_ask before deciding.
|
|
|
294454
294532
|
}
|
|
294455
294533
|
if ((row.card === "campaign" || row.card === "call") && row.campaignSummary) {
|
|
294456
294534
|
const summary = row.campaignSummary;
|
|
294457
|
-
const
|
|
294458
|
-
if (
|
|
294535
|
+
const call2 = calls.get(summary.tag);
|
|
294536
|
+
if (call2) return callLine(row, call2);
|
|
294459
294537
|
const low = summary.low ? faceOf2(summary.low, SANDBOX)?.text : void 0;
|
|
294460
294538
|
const high = summary.high ? faceOf2(summary.high, SANDBOX)?.text : void 0;
|
|
294461
294539
|
const range = summary.pool || !low ? "paid from pools" : high && high !== low ? `${low} to ${high} a place` : `${low} a place`;
|
|
@@ -294569,9 +294647,10 @@ ${reviewReportTemplate({ fields: true })}`] : []
|
|
|
294569
294647
|
"read_ask",
|
|
294570
294648
|
{
|
|
294571
294649
|
...meta3("read_ask"),
|
|
294572
|
-
inputSchema: { collectionId: external_exports.string().regex(
|
|
294650
|
+
inputSchema: { collectionId: external_exports.string().regex(/^(\d+|[A-Za-z0-9_-]{22})$/).describe(`The ask's number, or a pay link's id from post_ask/post_call with pay_by "card".`) }
|
|
294573
294651
|
},
|
|
294574
294652
|
async ({ collectionId }) => {
|
|
294653
|
+
if (!/^\d+$/.test(collectionId)) return text4(await (await Promise.resolve().then(() => (init_payDraft(), payDraft_exports))).draftStatus(SITE, collectionId, fetch2));
|
|
294575
294654
|
const mine = await address2();
|
|
294576
294655
|
const acting = (await actingOrWhy2(mine)).acting ?? null;
|
|
294577
294656
|
const ours = [mine, ...[acting?.principal].filter((one) => Boolean(one))];
|
|
@@ -294591,11 +294670,11 @@ ${reviewReportTemplate({ fields: true })}`] : []
|
|
|
294591
294670
|
{
|
|
294592
294671
|
...meta3("read_ask"),
|
|
294593
294672
|
inputSchema: {
|
|
294594
|
-
collectionId: external_exports.string().regex(
|
|
294673
|
+
collectionId: external_exports.string().regex(/^(\d+|[A-Za-z0-9_-]{22})$/).describe(`The ask's number, or a pay link's id from post_ask with pay_by "card".`),
|
|
294595
294674
|
address: external_exports.string().regex(ADDRESS3).optional().describe("Your own ixo address, if you have one: the answer then says whether that address has already answered. This hosted server holds no key, so it cannot know otherwise.")
|
|
294596
294675
|
}
|
|
294597
294676
|
},
|
|
294598
|
-
async ({ collectionId, address: given2 }) => readAsk(collectionId, given2 ? [given2] : [])
|
|
294677
|
+
async ({ collectionId, address: given2 }) => /^\d+$/.test(collectionId) ? readAsk(collectionId, given2 ? [given2] : []) : text4(await (await Promise.resolve().then(() => (init_payDraft(), payDraft_exports))).draftStatus(SITE, collectionId, fetch2))
|
|
294599
294678
|
);
|
|
294600
294679
|
}
|
|
294601
294680
|
if (offered("submit_work")) server2.registerTool(
|
|
@@ -294863,18 +294942,22 @@ Never open it yourself.`
|
|
|
294863
294942
|
invite: external_exports.array(external_exports.string().max(64)).max(50).optional().describe('With access "invite" (or "apply", to let some in at once): ixo1 addresses, @handles of people with a page, and "link" once per single-use link you want (each admits one new person).'),
|
|
294864
294943
|
...approverInput,
|
|
294865
294944
|
...checkerInput,
|
|
294945
|
+
pay_by: external_exports.enum(["card"]).optional().describe('"card": spend nothing from this key. The ask is saved and you get a link where the person pays by card and posts it from their own account. Not with org, oracle, payout, campaign or image. The only way to post from the hosted server.'),
|
|
294866
294946
|
confirm: external_exports.string().optional().describe("The exact total from the preview, e.g. '$1.50'. Omit to preview.")
|
|
294867
294947
|
}
|
|
294868
294948
|
},
|
|
294869
|
-
async ({ task, title, pay, quota, days, near, within_m, place, series, org, oracle, payout, campaign, image, access: access2, invite, approver, person_checks, report, checker, check: check2, confirm }) => {
|
|
294949
|
+
async ({ task, title, pay, quota, days, near, within_m, place, series, org, oracle, payout, campaign, image, access: access2, invite, approver, person_checks, report, checker, check: check2, pay_by, confirm }) => {
|
|
294950
|
+
const card = pay_by === "card";
|
|
294951
|
+
if (!local && !card) return text4(`This hosted server holds no key, so it posts only by card: pass pay_by: "card" for a link where the person pays and posts it. Nothing was posted.`);
|
|
294952
|
+
if (card && (org || oracle || payout || campaign || image)) return text4("Refused: an ask paid by card is the person's own: leave `org`, `oracle`, `payout`, `campaign` and `image` out. Nothing was posted and nothing was spent.");
|
|
294870
294953
|
if (isTainted(task) || title && isTainted(title)) return text4(TAINT_REFUSAL);
|
|
294871
294954
|
const door2 = (await Promise.resolve().then(() => (init_call2(), call_exports2))).doorOf(access2, invite);
|
|
294872
294955
|
if ("refused" in door2) return text4(`Refused: ${door2.refused}. Nothing was posted and nothing was spent.`);
|
|
294873
294956
|
const cannot = await unjudged();
|
|
294874
294957
|
if (cannot) return text4(cannot);
|
|
294875
|
-
const acting = await principal2();
|
|
294958
|
+
const acting = card ? null : await principal2();
|
|
294876
294959
|
const { hqPlan: hqPlan2, evaluationPrice: evaluationPrice2, oracleSigner: oracleSigner2, orgDefaultOracle: orgDefaultOracle2, orgFundsRefusal: orgFundsRefusal2, rewardCoin: rewardCoin2 } = await Promise.resolve().then(() => (init_hq(), hq_exports));
|
|
294877
|
-
const coin = rewardCoin2(void 0, NETWORK2);
|
|
294960
|
+
const coin = card ? FEE_DENOM : rewardCoin2(void 0, NETWORK2);
|
|
294878
294961
|
if (typeof coin !== "string") return text4(`Refused: ${coin.refused}. Nothing was posted and nothing was spent.`);
|
|
294879
294962
|
let expert = null;
|
|
294880
294963
|
if (checker) {
|
|
@@ -295030,10 +295113,32 @@ Never open it yourself.`
|
|
|
295030
295113
|
const { total, what: preview, details: costDetails } = orgAsk ? { total: 0, what: `nothing from this key (${orgName} pays)`, details: `What this costs ${orgName}:
|
|
295031
295114
|
${orgCosts}` } : { total: onChain.total, what: perCheck ? `${onChain.what}. Review fee: ${billing.creditsCopy(null, feeWords(perCheck.price))}` : onChain.what, details: "" };
|
|
295032
295115
|
const orgToken = orgAsk ? (await Promise.resolve().then(() => (init_hq(), hq_exports))).orgConfirmToken({ offChainTotal: offChain ? `${(Number(offChain.amount) * spots).toFixed(2)} ${offChain.currency}` : null, rewards: rewardsFace, feesSetAside: !perCheck && legBase > 0 ? feeWords(legBase * spots) : null }) : void 0;
|
|
295033
|
-
const
|
|
295116
|
+
const payDraft = card ? await Promise.resolve().then(() => (init_payDraft(), payDraft_exports)) : null;
|
|
295117
|
+
const quote = payDraft?.quoteOf(Number(baseFromPay2(pay)) * spots, legBase * spots);
|
|
295118
|
+
const cardWords = payDraft && quote ? payDraft.cardPreview(quote) : null;
|
|
295119
|
+
if (cardWords && typeof cardWords !== "string") return text4(`Refused: ${cardWords.refused}. Nothing was posted and nothing was spent.`);
|
|
295120
|
+
if (payDraft && quote && confirm) {
|
|
295121
|
+
if (confirm.trim() !== payDraft.confirmToken(quote)) return text4(`Refused: confirm said "${confirm}" but the person pays ${payDraft.confirmToken(quote)}. Preview it again.`);
|
|
295122
|
+
const draftTerms = {
|
|
295123
|
+
title: name8,
|
|
295124
|
+
terms,
|
|
295125
|
+
amountUixo: String(baseFromPay2(pay)),
|
|
295126
|
+
quota: spots,
|
|
295127
|
+
days: days ?? 7,
|
|
295128
|
+
denom: coin,
|
|
295129
|
+
...reviewer ? { checker: reviewer, checkRewardUixo: legBase } : {},
|
|
295130
|
+
...expert ? { protocol: expert.check.did, feeDenom: expert.feeDenom } : {},
|
|
295131
|
+
...perCheck ? { perCheck } : {},
|
|
295132
|
+
...series ? { series } : {},
|
|
295133
|
+
...door2.access ? { access: door2.access, invite: door2.invite } : {}
|
|
295134
|
+
};
|
|
295135
|
+
return text4(await payDraft.saveDraft(SITE, { kind: "ask", terms: draftTerms, quote, network: NETWORK2 }, fetch2));
|
|
295136
|
+
}
|
|
295137
|
+
const guard = cardWords ?? spendGuard({ bucket: "post", task, total, ...confirm ? { confirm } : {}, what: preview, details: costDetails, symbol: symbol2, ...orgToken ? { token: orgToken } : {} });
|
|
295034
295138
|
if (guard) {
|
|
295035
295139
|
const notes = confirm ? [] : [
|
|
295036
|
-
|
|
295140
|
+
/* By card the person posts as themselves at the link; and a hosted server has no connection to name. */
|
|
295141
|
+
card ? null : actingNote(acting),
|
|
295037
295142
|
expert ? expertNote(expert) : checkingNote(terms, acting?.principal ?? null),
|
|
295038
295143
|
expert ? null : orgAsk ? `Reviewed by ${await oracleWordsFor({ did: orgAsk.oracle.did, address: orgAsk.oracle.address })}.` : reviewer && reviewer !== CHECKER ? `Reviewed by ${await oracleWordsFor({ address: reviewer })}.` : null,
|
|
295039
295144
|
doorWords(door2.access, door2.invite.length),
|
|
@@ -296269,16 +296374,16 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296269
296374
|
}
|
|
296270
296375
|
},
|
|
296271
296376
|
async ({ slug: named, clear, ...input }) => {
|
|
296272
|
-
const
|
|
296377
|
+
const call2 = await Promise.resolve().then(() => (init_call2(), call_exports2));
|
|
296273
296378
|
const { CALL_SLUG: CALL_SLUG2 } = await Promise.resolve().then(() => (init_terms(), terms_exports));
|
|
296274
|
-
if (
|
|
296275
|
-
const slug = named?.trim() ||
|
|
296379
|
+
if (call2.typedText(input).some((one) => isTainted(one))) return text4(TAINT_REFUSAL);
|
|
296380
|
+
const slug = named?.trim() || call2.nextSlug();
|
|
296276
296381
|
if (!CALL_SLUG2.test(slug)) return text4(`"${slug}" cannot name a call: lowercase letters, digits and dashes, starting with a letter, 3 to 40 long. Nothing was saved.`);
|
|
296277
|
-
const existing =
|
|
296382
|
+
const existing = call2.readDraft(slug);
|
|
296278
296383
|
const posted = existing ? Object.values(existing.posted).some(Boolean) || Boolean(existing.inFlight) : false;
|
|
296279
296384
|
const changing = clear || Object.values(input).some((value) => value !== void 0);
|
|
296280
296385
|
if (posted && changing) return text4(`Call "${slug}" is already posted: its terms were frozen with the money. Start a new call with another slug.`);
|
|
296281
|
-
const start = clear || !existing ?
|
|
296386
|
+
const start = clear || !existing ? call2.freshDraft(slug) : existing;
|
|
296282
296387
|
const marketplaces = await Promise.resolve().then(() => (init_marketplaces(), marketplaces_exports));
|
|
296283
296388
|
let given2 = input;
|
|
296284
296389
|
const notTaken = [];
|
|
@@ -296290,18 +296395,18 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296290
296395
|
given2 = { ...input, sponsor: void 0 };
|
|
296291
296396
|
}
|
|
296292
296397
|
}
|
|
296293
|
-
const merged =
|
|
296294
|
-
const coin =
|
|
296398
|
+
const merged = call2.mergeDraft(start, given2);
|
|
296399
|
+
const coin = call2.callCoin(merged.draft, NETWORK2, ASK_DENOM);
|
|
296295
296400
|
if (typeof coin !== "string") return text4(`Refused: ${coin.refused}. Nothing was saved.`);
|
|
296296
296401
|
const refused2 = [...notTaken, ...merged.refused];
|
|
296297
296402
|
const draft = coin !== ASK_DENOM ? { ...merged.draft, coin } : merged.draft;
|
|
296298
|
-
|
|
296403
|
+
call2.writeDraft(draft);
|
|
296299
296404
|
const coinSymbol = symbolOf(coin);
|
|
296300
296405
|
const acting = await principal2();
|
|
296301
296406
|
const held = await heldBy(acting, coin);
|
|
296302
296407
|
const holds = held === null ? null : pays(held.reward, coinSymbol);
|
|
296303
296408
|
const choices = draft.fields.kind === "review" && !draft.fields.sponsor ? await marketplaces.readMarketplaces(SITE, fetch2) : null;
|
|
296304
|
-
const missing2 =
|
|
296409
|
+
const missing2 = call2.missingOf(draft.fields, { symbol: coinSymbol, holds, marketplaces: choices && "sponsors" in choices ? marketplaces.marketplaceChoices(choices.sponsors) : null });
|
|
296305
296410
|
const out = [`Draft "${slug}" saved${posted ? " (posted)" : ""}.`];
|
|
296306
296411
|
if (refused2.length) out.push("", "Not taken:", ...refused2.map((one) => ` - ${one}`));
|
|
296307
296412
|
if (missing2.length) {
|
|
@@ -296310,7 +296415,7 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296310
296415
|
"Still needed, in this order. Ask the person, a group at a time, in their words; never write the brief for them:",
|
|
296311
296416
|
...missing2.flatMap((one, index) => [` ${index + 1}. ${one.field}: ${one.question}`, ` e.g. ${one.example}`])
|
|
296312
296417
|
);
|
|
296313
|
-
const optional5 =
|
|
296418
|
+
const optional5 = call2.optionalOf(draft.fields, originOf(NETWORK2));
|
|
296314
296419
|
if (optional5.length) out.push("", "Optional, not given yet:", ...optional5.map((one) => ` - ${one}`));
|
|
296315
296420
|
return text4(out.join("\n"));
|
|
296316
296421
|
}
|
|
@@ -296320,7 +296425,7 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296320
296425
|
const checker = await callChecker2(draft.fields.kind === "review");
|
|
296321
296426
|
if (checker.fee && checker.fee.denom !== coin) return text4(`Refused: ${checker.name} is paid in another coin than this call pays in, and a review pays in its verifier's coin. Start a new review.`);
|
|
296322
296427
|
const perCheck = checker.fee ? false : await callPerCheck(checker.address);
|
|
296323
|
-
const priced =
|
|
296428
|
+
const priced = call2.callShare(draft.fields, call2.callShares(draft.fields) ? await callSplit() : null);
|
|
296324
296429
|
if ("unread" in priced) {
|
|
296325
296430
|
out.push("", "Not priced yet: this call is a hire by invitation or application, which carries the network's share, and the fee split could not be read just now. The draft is saved; call draft_call again in a minute.");
|
|
296326
296431
|
return text4(out.join("\n"));
|
|
@@ -296329,14 +296434,14 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296329
296434
|
const resolved = proAsk && draft.fields.sponsor ? await marketplaces.resolveMarketplace(SITE, draft.fields.sponsor, NETWORK2, fetch2) : null;
|
|
296330
296435
|
const sponsor = resolved && "sponsor" in resolved ? resolved.sponsor : null;
|
|
296331
296436
|
const sponsorProblem = resolved && "refused" in resolved ? resolved : null;
|
|
296332
|
-
const plan =
|
|
296437
|
+
const plan = call2.callPlan(draft, { poster: shortPoster, checkerLegBase: (terms) => checker.fee ? checker.fee.base : perCheck ? 0 : checkerLegBase2(FEE_DENOM, terms, CHECK_REWARD), oracle: checker.address || "the verifier", share: priced.share, feeInReward: Boolean(checker.fee) || coin === FEE_DENOM, sponsor });
|
|
296333
296438
|
const feeTotal = plan.legs.reduce((sum, one) => sum + one.feeBase, 0);
|
|
296334
296439
|
const finalOk = draft.fields.kind === "review" ? acting?.principal ?? null : null;
|
|
296335
|
-
const preview =
|
|
296336
|
-
const twoCoins = acting && feeTotal > 0 ? `Can't post as ${acting.principal}: ${
|
|
296440
|
+
const preview = call2.legTerms(draft, "entries", { poster: shortPoster, dates: plan.dates, oracle: { kind: "oracle", address: checker.address || "the verifier" }, approver: finalOk, share: plan.share, sponsor });
|
|
296441
|
+
const twoCoins = acting && feeTotal > 0 ? `Can't post as ${acting.principal}: ${call2.callTwoCoins}.` : null;
|
|
296337
296442
|
const { capCoinRefusal: capCoinRefusal2, capIn: capIn2 } = await Promise.resolve().then(() => (init_hq(), hq_exports));
|
|
296338
296443
|
const otherCoin = capCoinRefusal2(acting, coin, checker.fee ? `${SITE}/connect` : void 0);
|
|
296339
|
-
const capped3 =
|
|
296444
|
+
const capped3 = call2.capWords(plan.legs, CAP_BASE, coinSymbol, NETWORK2);
|
|
296340
296445
|
const keyOnly = !acting && feeTotal > 0;
|
|
296341
296446
|
const blocked = capped3.length > 0 || Boolean(otherCoin) || Boolean(twoCoins) && draft.fields.kind !== "review" || Boolean(sponsorProblem && !sponsorProblem.unavailable);
|
|
296342
296447
|
const m = draft.fields.money;
|
|
@@ -296357,15 +296462,15 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296357
296462
|
sponsorProblem ? sponsorProblem.unavailable ? `${sponsorProblem.refused} post_call confirms the marketplace again before anything moves.` : `Can't post as it stands: ${sponsorProblem.refused}` : "",
|
|
296358
296463
|
draft.fields.access === "invite" && !draft.fields.invite?.length ? proAsk ? `Nobody invited yet: find_pro${draft.fields.sponsor ? ` with sponsor: "${draft.fields.sponsor}"` : ""} suggests pros from ${sponsor ? `${sponsor.name}'s` : "the marketplace's"} roster; add them with invite now, or invite_to_call after it posts.` : 'By invitation, and nobody invited yet: add invite (addresses, @handles, "link") now, or invite_to_call after it posts.' : "",
|
|
296359
296464
|
draft.fields.access === "apply" ? "By application: people apply on the call's page or with apply_to_call; you say yes with decide_application before they can enter." : "",
|
|
296360
|
-
...
|
|
296465
|
+
...call2.balanceWarnings(held, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords }),
|
|
296361
296466
|
acting?.cap && !otherCoin && Number(capIn2(acting, coin)?.remainingBase ?? 0) < plan.totalBase ? `Their cap has ${pays(Number(capIn2(acting, coin)?.remainingBase ?? 0), coinSymbol)} left; the call locks ${pays(plan.totalBase, coinSymbol)}. They raise it at ${SITE}/connect.` : "",
|
|
296362
|
-
keyOnly ? `Not connected, and a connection would not carry this call: ${
|
|
296467
|
+
keyOnly ? `Not connected, and a connection would not carry this call: ${call2.callTwoCoins}. With plain_key: true it posts as this key itself, ${await address2()}, from its own money.` : !acting ? `Not connected: post_call refuses until the person connects this key (connect_account gives them the link). For a rehearsal, plain_key: true posts as this key itself, ${await address2()}, from its own money.` : ""
|
|
296363
296468
|
].filter(Boolean);
|
|
296364
296469
|
out.push(
|
|
296365
296470
|
"",
|
|
296366
296471
|
blocked ? "Drafted, but post_call would refuse it as it stands (the warnings say why). This is the call as an entrant's AI will read it:" : "Ready. This is the call as an entrant's AI will read it:",
|
|
296367
296472
|
"",
|
|
296368
|
-
|
|
296473
|
+
call2.callReadout(preview, { id: "(the entries ask, once posted)", symbol: coinSymbol, network: NETWORK2 }),
|
|
296369
296474
|
"",
|
|
296370
296475
|
"What each leg locks:",
|
|
296371
296476
|
...legRows,
|
|
@@ -296396,21 +296501,23 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296396
296501
|
inputSchema: {
|
|
296397
296502
|
slug: external_exports.string().max(40).describe("The call's name, as draft_call gave it."),
|
|
296398
296503
|
confirm: external_exports.string().optional().describe("The exact total from the preview, e.g. '$4.70'. Omit to preview."),
|
|
296504
|
+
pay_by: external_exports.enum(["card"]).optional().describe('"card": spend nothing from this key. The whole call is saved and you get a link where the person pays by card and posts it from their own account.'),
|
|
296399
296505
|
plain_key: external_exports.boolean().optional().describe("Post as this key itself, from its own money. Without a connection: a rehearsal. With one, only a review honours it, and only after the person said yes to this: the review posts from your own account (this key), which they fund, not from their account, and the AI decides each report alone, with no final OK from them. Any other call posts as the person who connected the key, and without either it is refused.")
|
|
296400
296506
|
}
|
|
296401
296507
|
},
|
|
296402
|
-
async ({ slug, confirm, plain_key }) => {
|
|
296403
|
-
const
|
|
296404
|
-
const
|
|
296508
|
+
async ({ slug, confirm, plain_key, pay_by }) => {
|
|
296509
|
+
const card = pay_by === "card";
|
|
296510
|
+
const call2 = await Promise.resolve().then(() => (init_call2(), call_exports2));
|
|
296511
|
+
const found = call2.readDraft(slug);
|
|
296405
296512
|
if (!found) return text4(`No draft called "${slug}". Start one with draft_call.`);
|
|
296406
296513
|
const review = found.fields.kind === "review";
|
|
296407
296514
|
const checker = await callChecker2(review);
|
|
296408
296515
|
const linkOf = (posted2) => review ? `${EXPERT_SITE}/pro/reviews/${posted2.entries?.id ?? slug}` : `${SITE}/opencall/${slug}`;
|
|
296409
|
-
const settled = found.inFlight ? await
|
|
296516
|
+
const settled = found.inFlight ? await call2.settleInFlight(slug, call2.indexLookup) : null;
|
|
296410
296517
|
if (settled?.state === "pending") return text4(settled.words);
|
|
296411
296518
|
if (settled?.state === "landed") {
|
|
296412
296519
|
nudge("hire", settled.id, checker.at);
|
|
296413
|
-
const after2 =
|
|
296520
|
+
const after2 = call2.nextLeg(settled.draft);
|
|
296414
296521
|
return text4(
|
|
296415
296522
|
[
|
|
296416
296523
|
`The earlier post landed: ${LEG_WORDS[settled.leg]} is #${settled.id}. It is recorded, and nothing was posted twice.`,
|
|
@@ -296419,23 +296526,23 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296419
296526
|
);
|
|
296420
296527
|
}
|
|
296421
296528
|
const draft = settled?.draft ?? found;
|
|
296422
|
-
const coin =
|
|
296529
|
+
const coin = call2.callCoin(draft, NETWORK2, ASK_DENOM);
|
|
296423
296530
|
if (typeof coin !== "string") return text4(`Refused: ${coin.refused}. Nothing was posted.`);
|
|
296424
296531
|
const coinSymbol = symbolOf(coin);
|
|
296425
|
-
const next =
|
|
296532
|
+
const next = call2.nextLeg(draft);
|
|
296426
296533
|
const ids = ["prize", "runnersUp", "entries"].flatMap((leg2) => draft.posted[leg2] ? [`${LEG_WORDS[leg2]} #${draft.posted[leg2].id}`] : []);
|
|
296427
296534
|
if (!next) return text4(`Everything is posted: ${ids.join(", ")}.
|
|
296428
296535
|
The call: ${linkOf(draft.posted)}`);
|
|
296429
|
-
if (review && !draft.fields.sponsor) return text4(`${
|
|
296430
|
-
if (!
|
|
296536
|
+
if (review && !draft.fields.sponsor) return text4(`${call2.PRO_ASK_NEEDS_MARKETPLACE} Nothing was posted.`);
|
|
296537
|
+
if (!call2.isReady(draft.fields)) return text4(`"${slug}" is not ready: ${call2.missingOf(draft.fields, { symbol: coinSymbol, holds: null }).map((one) => one.field).join(", ")} still missing. Finish it with draft_call.`);
|
|
296431
296538
|
const cannot = await unjudged();
|
|
296432
296539
|
if (cannot) return text4(cannot);
|
|
296433
296540
|
if (!checker.address) return text4("No verifier is configured on this deployment, so nothing could judge the entries. Refusing rather than posting a call nobody can settle.");
|
|
296434
296541
|
const marketplace = review ? await (await Promise.resolve().then(() => (init_marketplaces(), marketplaces_exports))).resolveMarketplace(SITE, draft.fields.sponsor, NETWORK2, fetch2) : null;
|
|
296435
296542
|
if (marketplace && "refused" in marketplace) return text4(`Refused: ${marketplace.refused} Nothing was posted.`);
|
|
296436
296543
|
const sponsor = marketplace?.sponsor ?? null;
|
|
296437
|
-
const acting = plain_key && review ? null : await principal2();
|
|
296438
|
-
if (!acting && !plain_key) {
|
|
296544
|
+
const acting = card || plain_key && review ? null : await principal2();
|
|
296545
|
+
if (!acting && !plain_key && !card) {
|
|
296439
296546
|
return text4(`Not connected. A call uses the connected account as its poster and funding source. Ask them to connect this key first:
|
|
296440
296547
|
${connectLink2(review ? `${EXPERT_SITE}/pro` : SITE, await address2())}
|
|
296441
296548
|
Then call post_call again. Nothing was posted.`);
|
|
@@ -296444,15 +296551,15 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296444
296551
|
const poster = acting?.principal ?? await address2();
|
|
296445
296552
|
if (checker.fee && checker.fee.denom !== coin) return text4(`Refused: ${checker.name} is paid in another coin than this call pays in, and a review pays in its verifier's coin. Start a new review. Nothing was posted.`);
|
|
296446
296553
|
const perCheck = checker.fee ? false : await callPerCheck(checker.address);
|
|
296447
|
-
const split3 =
|
|
296448
|
-
const priced =
|
|
296449
|
-
if ("unread" in priced) return text4(
|
|
296450
|
-
const plan =
|
|
296554
|
+
const split3 = call2.callShares(draft.fields) ? await callSplit() : null;
|
|
296555
|
+
const priced = call2.callShare(draft.fields, split3);
|
|
296556
|
+
if ("unread" in priced) return text4(call2.SHARE_UNREAD);
|
|
296557
|
+
const plan = call2.callPlan(draft, { poster: `${poster.slice(0, 10)}\u2026${poster.slice(-4)}`, checkerLegBase: (terms) => checker.fee ? checker.fee.base : perCheck ? 0 : checkerLegBase2(FEE_DENOM, terms, CHECK_REWARD), oracle: checker.address, share: priced.share, feeInReward: Boolean(checker.fee) || coin === FEE_DENOM, sponsor });
|
|
296451
296558
|
const feeTotal = plan.legs.reduce((sum, one) => sum + one.feeBase, 0);
|
|
296452
296559
|
const total = pays(plan.totalBase, coinSymbol);
|
|
296453
296560
|
const { feeLine: feeLine2 } = await Promise.resolve().then(() => (init_feeLine(), feeLine_exports));
|
|
296454
296561
|
const moneySentence = sponsor && plan.share ? feeLine2({ split: plan.share, sponsorName: sponsor.name, net: draft.fields.money.entryEach, symbol: coinSymbol, network: NETWORK2 }) : null;
|
|
296455
|
-
if (acting && feeTotal > 0) return text4(`Refused: ${
|
|
296562
|
+
if (acting && feeTotal > 0) return text4(`Refused: ${call2.callTwoCoins}.${review ? ` ${PLAIN_REVIEW}` : ""} Nothing was posted.`);
|
|
296456
296563
|
const approver = review && acting ? acting.principal : null;
|
|
296457
296564
|
if (approver) {
|
|
296458
296565
|
const notReady = await approverRefusal(approver, async (who) => (await Promise.resolve().then(() => (init_personReview(), personReview_exports))).approverReady(who, { self: true }));
|
|
@@ -296460,6 +296567,19 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296460
296567
|
}
|
|
296461
296568
|
const leg = plan.legs.find((one) => one.leg === next);
|
|
296462
296569
|
const order2 = plan.legs.map((one) => one.leg);
|
|
296570
|
+
if (card) {
|
|
296571
|
+
if (coin !== FEE_DENOM) return text4(`Refused: a card pays in ${FEE_SYMBOL}, and this call pays in ${coinSymbol}. Nothing was posted.`);
|
|
296572
|
+
if (ids.length) return text4(`Refused: part of "${slug}" is posted already (${ids.join(", ")}); finish it with post_call. Nothing was posted.`);
|
|
296573
|
+
const payDraft = await Promise.resolve().then(() => (init_payDraft(), payDraft_exports));
|
|
296574
|
+
const rewardBase = plan.legs.reduce((sum, one) => sum + one.payBase * one.escrowSpots, 0);
|
|
296575
|
+
const quote = payDraft.quoteOf(rewardBase, plan.totalBase + feeTotal - rewardBase);
|
|
296576
|
+
const words5 = payDraft.cardPreview(quote);
|
|
296577
|
+
if (typeof words5 !== "string") return text4(`Refused: ${words5.refused}. Nothing was posted.`);
|
|
296578
|
+
if (!confirm) return text4([`Call "${slug}" is ${order2.length} asks: ${order2.map((one) => LEG_WORDS[one]).join(", then ")}.`, ...moneySentence ? [moneySentence] : [], words5].join("\n"));
|
|
296579
|
+
if (confirm.trim() !== payDraft.confirmToken(quote)) return text4(`Refused: confirm said "${confirm}" but the person pays ${payDraft.confirmToken(quote)}. Preview it again.`);
|
|
296580
|
+
const terms = { slug, fields: draft.fields, dates: plan.dates, legs: plan.legs, checker: checker.address, perCheck, ...sponsor ? { sponsor } : {} };
|
|
296581
|
+
return text4(await payDraft.saveDraft(SITE, { kind: "call", terms, quote, network: NETWORK2 }, fetch2));
|
|
296582
|
+
}
|
|
296463
296583
|
if (!confirm) {
|
|
296464
296584
|
const { shareWords: shareWords2 } = await Promise.resolve().then(() => (init_callRead(), callRead_exports));
|
|
296465
296585
|
const shareTotal = plan.legs.reduce((sum, one) => sum + one.shareBase * one.escrowSpots, 0);
|
|
@@ -296472,21 +296592,21 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296472
296592
|
`Next: ${LEG_WORDS[next]}, locking ${callLocks(leg.escrowBase, leg.feeBase, coinSymbol)}, plus a small network fee.`,
|
|
296473
296593
|
actingNote(acting) ?? (review ? "Posting from your own account (this key), not the person's account; the AI decides each report alone, with no final OK from the person." : `Posting as this key, ${poster}.`),
|
|
296474
296594
|
`Spent today (call): ${spentWords("call", coinSymbol)}. Every tool together: ${spentAllWords()}.`,
|
|
296475
|
-
...
|
|
296476
|
-
...
|
|
296595
|
+
...call2.capWords(plan.legs.filter((one) => !draft.posted[one.leg]), CAP_BASE, coinSymbol, NETWORK2),
|
|
296596
|
+
...call2.balanceWarnings(held2, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords }),
|
|
296477
296597
|
"",
|
|
296478
296598
|
`To go ahead, call again with confirm: "${total}".`
|
|
296479
296599
|
].join("\n")
|
|
296480
296600
|
);
|
|
296481
296601
|
}
|
|
296482
|
-
if (!
|
|
296483
|
-
if (
|
|
296602
|
+
if (!call2.confirms(confirm, plan.totalBase, coinSymbol)) return text4(`Refused: confirm said "${confirm}" but the call locks ${total}. Preview it again.`);
|
|
296603
|
+
if (call2.overCap(leg, CAP_BASE)) return text4(`Refused: this leg locks ${pays(leg.escrowBase, coinSymbol)}, over this server's ${face(MAX_PER_ASK, coinSymbol)} per-ask cap (OPENHANDS_MAX_PER_ASK_USD).`);
|
|
296484
296604
|
if (ids.length === 0) {
|
|
296485
|
-
const taken = await fetch2(`${SITE}/api/board?campaign=${encodeURIComponent(
|
|
296605
|
+
const taken = await fetch2(`${SITE}/api/board?campaign=${encodeURIComponent(call2.tagOf(draft))}&size=5`, { signal: AbortSignal.timeout(15e3) }).then((response) => response.ok ? response.json() : null).catch(() => null);
|
|
296486
296606
|
if (taken?.rows?.length) return text4(`Refused: "${slug}" already names a call with open asks on this board. Draft it under another slug with draft_call. Nothing was posted.`);
|
|
296487
296607
|
}
|
|
296488
296608
|
const { balancesOfStrict: balancesOfStrict2 } = await Promise.resolve().then(() => (init_balance(), balance_exports));
|
|
296489
|
-
const refusedBefore = await
|
|
296609
|
+
const refusedBefore = await call2.preCheck(leg, {
|
|
296490
296610
|
acting,
|
|
296491
296611
|
poster,
|
|
296492
296612
|
askDenom: coin,
|
|
@@ -296503,7 +296623,7 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296503
296623
|
const key = await loadKey2();
|
|
296504
296624
|
let posted;
|
|
296505
296625
|
try {
|
|
296506
|
-
posted = await
|
|
296626
|
+
posted = await call2.postNextLeg(slug, {
|
|
296507
296627
|
site: SITE,
|
|
296508
296628
|
askDenom: coin,
|
|
296509
296629
|
checker: checker.address,
|
|
@@ -296520,7 +296640,7 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296520
296640
|
sponsor
|
|
296521
296641
|
});
|
|
296522
296642
|
} catch (error54) {
|
|
296523
|
-
if (error54 instanceof
|
|
296643
|
+
if (error54 instanceof call2.InFlightError || error54 instanceof call2.PostRefused) return text4(error54.message);
|
|
296524
296644
|
if (isUnanchored(error54)) return text4(unanchoredWords(error54));
|
|
296525
296645
|
if (error54 instanceof Error && error54.name === "TxFailed") {
|
|
296526
296646
|
return text4(`The network refused ${LEG_WORDS[next]}: ${error54.message}. Nothing moved. Fix that (often the account's balance or cap) and call post_call again.`);
|
|
@@ -296532,7 +296652,7 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296532
296652
|
if ("done" in posted) return text4(`Everything is posted.
|
|
296533
296653
|
The call: ${linkOf(posted.draft.posted)}`);
|
|
296534
296654
|
const done = order2.filter((one) => posted.draft.posted[one]).length;
|
|
296535
|
-
const after =
|
|
296655
|
+
const after = call2.nextLeg(posted.draft);
|
|
296536
296656
|
const hire = posted.draft.fields.mode === "hire";
|
|
296537
296657
|
const held = posted.screen?.verdict === "hold" ? heldWords(posted.screen.reason) : null;
|
|
296538
296658
|
const invited = !after && posted.draft.fields.access && posted.draft.fields.access !== "public" ? await writeDraftInvites(posted.draft, posted.id, acting) : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixo/asks-mcp",
|
|
3
|
-
"version": "1.6.0
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "The Openhands Network MCP server: read the board, answer asks, post work and get paid on the ixo chain, with a key of its own on your machine.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|