@ixo/asks-mcp 2.0.0-dev.2 → 2.0.0-dev.4
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 +264 -99
- package/package.json +1 -1
package/dist/asks-mcp.mjs
CHANGED
|
@@ -7508,7 +7508,7 @@ function reviewSlugOf(facts) {
|
|
|
7508
7508
|
function askPage(site, collectionId, facts) {
|
|
7509
7509
|
const base6 = site.replace(/\/+$/, "");
|
|
7510
7510
|
const review = reviewSlugOf(facts);
|
|
7511
|
-
if (review) return `${base6}/pro
|
|
7511
|
+
if (review) return `${base6}/me/pro-asks/${collectionId}`;
|
|
7512
7512
|
const slug = facts.slug ?? (facts.campaign ? slugOfTag(facts.campaign) : null);
|
|
7513
7513
|
return slug ? `${base6}/opencall/${slug}` : `${base6}/t/${collectionId}`;
|
|
7514
7514
|
}
|
|
@@ -7518,7 +7518,10 @@ function answerPage(site, collectionId, claimId, facts) {
|
|
|
7518
7518
|
return review ? `${base6}/pro/reviews/${collectionId}/report/${encodeURIComponent(claimId)}` : `${base6}/r/${collectionId}/trace/${encodeURIComponent(claimId)}`;
|
|
7519
7519
|
}
|
|
7520
7520
|
function inviteLink(site, token, review) {
|
|
7521
|
-
return review ? `${site.replace(/\/+$/, "")}/
|
|
7521
|
+
return review ? `${site.replace(/\/+$/, "")}/i/${token}` : `${site.replace(/\/+$/, "")}/opencall/i/${token}`;
|
|
7522
|
+
}
|
|
7523
|
+
function sitePath(path) {
|
|
7524
|
+
return path.replace(/^\/pro\/reviews\/([^/?#]+)\/with\//, "/me/pro-asks/$1/with/").replace(/^\/pro\/reviews\/([^/?#]+)$/, "/me/pro-asks/$1").replace(/^\/pro\/work(?=\/|$)/, "/me/work").replace(/^\/pro\/i\//, "/i/").replace(/^\/pro\/pros(?=\/|$)/, "/pros");
|
|
7522
7525
|
}
|
|
7523
7526
|
var isReviewTitle, proPage, roomPage;
|
|
7524
7527
|
var init_world = __esm({
|
|
@@ -7526,8 +7529,8 @@ var init_world = __esm({
|
|
|
7526
7529
|
"use strict";
|
|
7527
7530
|
init_callTag();
|
|
7528
7531
|
isReviewTitle = (title) => /^Expert review:/.test(title ?? "");
|
|
7529
|
-
proPage = (site, handle2) => `${site.replace(/\/+$/, "")}/
|
|
7530
|
-
roomPage = (site, collectionId, pro) => `${site.replace(/\/+$/, "")}/pro
|
|
7532
|
+
proPage = (site, handle2) => `${site.replace(/\/+$/, "")}/pros/${handle2}`;
|
|
7533
|
+
roomPage = (site, collectionId, pro) => `${site.replace(/\/+$/, "")}/me/pro-asks/${collectionId}/with/${encodeURIComponent(pro.replace(/^@/, ""))}`;
|
|
7531
7534
|
}
|
|
7532
7535
|
});
|
|
7533
7536
|
|
|
@@ -9812,6 +9815,13 @@ var init_gateMet = __esm({
|
|
|
9812
9815
|
});
|
|
9813
9816
|
|
|
9814
9817
|
// ../../packages/openhands-sdk/src/data/engineUrl.ts
|
|
9818
|
+
var engineUrl_exports = {};
|
|
9819
|
+
__export(engineUrl_exports, {
|
|
9820
|
+
engineConfigured: () => engineConfigured,
|
|
9821
|
+
engineIssuerKeysUrl: () => engineIssuerKeysUrl,
|
|
9822
|
+
engineReceiptUrl: () => engineReceiptUrl,
|
|
9823
|
+
engineUrl: () => engineUrl
|
|
9824
|
+
});
|
|
9815
9825
|
var engineUrl, engineConfigured, engineReceiptUrl, engineIssuerKeysUrl;
|
|
9816
9826
|
var init_engineUrl = __esm({
|
|
9817
9827
|
"../../packages/openhands-sdk/src/data/engineUrl.ts"() {
|
|
@@ -29605,8 +29615,8 @@ function fileAnswers(files, urlOf = ipfsDocUrl) {
|
|
|
29605
29615
|
};
|
|
29606
29616
|
}
|
|
29607
29617
|
function extensionOf(type) {
|
|
29608
|
-
const
|
|
29609
|
-
switch (
|
|
29618
|
+
const bare2 = (type ?? "").toLowerCase().split(";")[0]?.trim() ?? "";
|
|
29619
|
+
switch (bare2) {
|
|
29610
29620
|
case "image/jpeg":
|
|
29611
29621
|
return ".jpg";
|
|
29612
29622
|
case "image/png":
|
|
@@ -259526,10 +259536,10 @@ __export(connect_exports, {
|
|
|
259526
259536
|
workOf: () => workOf
|
|
259527
259537
|
});
|
|
259528
259538
|
function noteIgnored(agent, pinned, others, log) {
|
|
259529
|
-
const
|
|
259530
|
-
if (!
|
|
259531
|
-
for (const one of
|
|
259532
|
-
log(`asks-mcp: ignoring ${
|
|
259539
|
+
const fresh3 = others.filter((one) => !told.has(`${agent}:${pinned}:${one}`));
|
|
259540
|
+
if (!fresh3.length) return;
|
|
259541
|
+
for (const one of fresh3) told.add(`${agent}:${pinned}:${one}`);
|
|
259542
|
+
log(`asks-mcp: ignoring ${fresh3.length === 1 ? "a connection" : "connections"} to this key from ${fresh3.join(", ")}: it is pinned to ${pinned === SELF ? "itself" : pinned}, and only connect_account changes that.`);
|
|
259533
259543
|
}
|
|
259534
259544
|
async function actingFor(agent, reads2 = chainReads, pins2 = keyPins) {
|
|
259535
259545
|
const pinned = pinOf(agent, pins2);
|
|
@@ -260179,17 +260189,17 @@ function laneStore(deps) {
|
|
|
260179
260189
|
const bearer = (can) => laneInvocation({ agent: deps.agent, pass: deps.pass, entityDid: deps.entityDid, collectionId: deps.collectionId, can });
|
|
260180
260190
|
async function put(bytes3, mediaType, name8) {
|
|
260181
260191
|
const deadline = Date.now() + (deps.settleMs ?? 6e4);
|
|
260182
|
-
let
|
|
260192
|
+
let fresh3 = false;
|
|
260183
260193
|
for (let pause2 = 2e3; ; pause2 = Math.min(pause2 * 2, 8e3)) {
|
|
260184
260194
|
try {
|
|
260185
|
-
return await uploadToLane(bytes3, mediaType, { bearer: await bearer("fs/write"), entityDid: deps.entityDid, collectionId: deps.collectionId, name: laneName(deps.person, bytes3, name8,
|
|
260195
|
+
return await uploadToLane(bytes3, mediaType, { bearer: await bearer("fs/write"), entityDid: deps.entityDid, collectionId: deps.collectionId, name: laneName(deps.person, bytes3, name8, fresh3) });
|
|
260186
260196
|
} catch (error54) {
|
|
260187
|
-
if (error54 instanceof LaneRefused && error54.status === 409 && !
|
|
260197
|
+
if (error54 instanceof LaneRefused && error54.status === 409 && !fresh3) {
|
|
260188
260198
|
if (bytes3.byteLength <= RAW_CID_MAX) {
|
|
260189
260199
|
const cid = cidOfBytes(bytes3);
|
|
260190
260200
|
return { cid, url: laneCidUrl(cid) };
|
|
260191
260201
|
}
|
|
260192
|
-
|
|
260202
|
+
fresh3 = true;
|
|
260193
260203
|
continue;
|
|
260194
260204
|
}
|
|
260195
260205
|
if (!passing(error54) || Date.now() + pause2 > deadline) return null;
|
|
@@ -260266,7 +260276,7 @@ ${shareLink(site, collectionId, approver)}` : "";
|
|
|
260266
260276
|
BOX_TTL_MS = 10 * 6e4;
|
|
260267
260277
|
newBoxId = () => randomBytes5(16).toString("hex");
|
|
260268
260278
|
safeName = (name8) => name8.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^[.-]+/, "").slice(-80) || "file";
|
|
260269
|
-
laneName = (person, bytes3, name8,
|
|
260279
|
+
laneName = (person, bytes3, name8, fresh3 = false) => `${person}/${createHash5("sha256").update(bytes3).digest("hex").slice(0, 24)}${fresh3 ? `-${randomBytes5(3).toString("hex")}` : ""}-${safeName(name8)}`;
|
|
260270
260280
|
RAW_CID_MAX = 1024 * 1024;
|
|
260271
260281
|
passing = (error54) => !(error54 instanceof LaneRefused) || error54.status === 403 || error54.status === 429 || error54.status >= 500;
|
|
260272
260282
|
ENVELOPE_LIMIT = 200 * 1024;
|
|
@@ -261821,8 +261831,8 @@ function senderFor(deps) {
|
|
|
261821
261831
|
let signerData = deps.signerData ? await deps.signerData() : void 0;
|
|
261822
261832
|
let fee = "auto";
|
|
261823
261833
|
try {
|
|
261824
|
-
const simulated = await simulateWithChainSequence({ client: client2, address: address2, messages, memo, signerData, warn, onCorrected: (
|
|
261825
|
-
signerData =
|
|
261834
|
+
const simulated = await simulateWithChainSequence({ client: client2, address: address2, messages, memo, signerData, warn, onCorrected: (fresh3) => {
|
|
261835
|
+
signerData = fresh3;
|
|
261826
261836
|
} });
|
|
261827
261837
|
const priced = (0, import_stargate7.calculateFee)(Math.round(simulated.gas * 1.8), GAS_PRICE2);
|
|
261828
261838
|
const granter = await deps.granterFor(messages.map((one) => one.typeUrl), Number(priced.amount[0]?.amount ?? 0));
|
|
@@ -263676,7 +263686,9 @@ var init_callTerms = __esm({
|
|
|
263676
263686
|
var feeLine_exports = {};
|
|
263677
263687
|
__export(feeLine_exports, {
|
|
263678
263688
|
MAINNET_SPLIT: () => MAINNET_SPLIT,
|
|
263679
|
-
feeLine: () => feeLine
|
|
263689
|
+
feeLine: () => feeLine,
|
|
263690
|
+
feeSentence: () => feeSentence,
|
|
263691
|
+
feeWords: () => feeWords
|
|
263680
263692
|
});
|
|
263681
263693
|
function feeLine(args) {
|
|
263682
263694
|
const { split: split3, symbol: symbol2 } = args;
|
|
@@ -263684,12 +263696,12 @@ function feeLine(args) {
|
|
|
263684
263696
|
const receives = `Each pro receives ${amountWords(args.net, symbol2)}.`;
|
|
263685
263697
|
const locked2 = `${amountWords(leg / 1e6, symbol2)} is locked per report`;
|
|
263686
263698
|
if (split3.network + split3.node === 0) {
|
|
263687
|
-
if (args.network === "mainnet") return `${receives} Nothing is taken
|
|
263688
|
-
return `${receives} In the sandbox nothing is added: ${amountWords(leg / 1e6, symbol2)} is held per report
|
|
263699
|
+
if (args.network === "mainnet") return `${receives} Nothing is taken: ${locked2}.`;
|
|
263700
|
+
return `${receives} In the sandbox nothing is added: ${amountWords(leg / 1e6, symbol2)} is held per report. On the real network, ${feeWords(MAINNET_SPLIT)}`;
|
|
263689
263701
|
}
|
|
263690
|
-
return `${receives} ${locked2}
|
|
263702
|
+
return `${receives} ${locked2}. ${feeWords(split3)}`;
|
|
263691
263703
|
}
|
|
263692
|
-
var MAINNET_SPLIT, percentWords, amountWords;
|
|
263704
|
+
var MAINNET_SPLIT, percentWords, feeWords, feeSentence, amountWords;
|
|
263693
263705
|
var init_feeLine = __esm({
|
|
263694
263706
|
"../../packages/openhands-sdk/src/rubric/feeLine.ts"() {
|
|
263695
263707
|
"use strict";
|
|
@@ -263697,6 +263709,8 @@ var init_feeLine = __esm({
|
|
|
263697
263709
|
init_share();
|
|
263698
263710
|
MAINNET_SPLIT = { network: 10, node: 10 };
|
|
263699
263711
|
percentWords = (value) => `${Number(value.toFixed(6))} %`;
|
|
263712
|
+
feeWords = (split3, who = "The pro") => `${percentWords(split3.network + split3.node)} of what you pay runs asks.world. ${who} gets the rest.`;
|
|
263713
|
+
feeSentence = (split3, network2, who = "The pro") => split3.network + split3.node === 0 && network2 !== "mainnet" ? `In the sandbox nothing is added. On the real network, ${feeWords(MAINNET_SPLIT, who)}` : feeWords(split3, who);
|
|
263700
263714
|
amountWords = (value, symbol2) => ["USDC", "USD", "PAY", "$"].includes(symbol2) ? dollars(value) : `${Number(value.toFixed(6))} ${symbol2}`;
|
|
263701
263715
|
}
|
|
263702
263716
|
});
|
|
@@ -263763,11 +263777,12 @@ function callReadout(terms, ctx) {
|
|
|
263763
263777
|
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.";
|
|
263764
263778
|
const review = call3.kind === "review";
|
|
263765
263779
|
const shared = call3.share ? sharedPay(m.entryEach, call3.share) : null;
|
|
263766
|
-
const shareLine2 = shared && call3.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(call3.share, "as posted")})${hire ? "" : "; the pick's and the runners-up's legs carry the same share
|
|
263780
|
+
const shareLine2 = shared && call3.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(call3.share, "as posted")})${hire ? "" : "; the pick's and the runners-up's legs carry the same share"}` : "";
|
|
263767
263781
|
const proMoney = review && call3.share && hire ? `Money: ${feeLine({ split: call3.share, 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;
|
|
263768
263782
|
const out = [
|
|
263769
263783
|
`${review ? "Pro ask" : hire ? "Hiring call" : "Open call"} "${call3.slug}" \xB7 posted by ${call3.poster} \xB7 ${stageWords(call3, ctx.now)}`,
|
|
263770
|
-
|
|
263784
|
+
/* A pro ask's page is its poster's alone (2026-10-29); an invited pro reads the same ask as their job, under Work. */
|
|
263785
|
+
...review && ctx.site ? [`Its pages: the poster's ${ctx.site.replace(/\/+$/, "")}/me/pro-asks/${ctx.id}; an invited pro's job ${ctx.site.replace(/\/+$/, "")}/me/work/${ctx.id}`] : [],
|
|
263771
263786
|
call3.title,
|
|
263772
263787
|
call3.lede,
|
|
263773
263788
|
...review && call3.subject ? [`Reviewing: ${call3.subject.name}${call3.subject.version ? ` ${call3.subject.version}` : ""}${call3.subject.where ? ` \xB7 ${call3.subject.where}` : ""}. Access details, if any, are in your invitation.`] : [],
|
|
@@ -264274,7 +264289,7 @@ async function postNextLegNow(slug, ctx) {
|
|
|
264274
264289
|
tag: tagOf(draft),
|
|
264275
264290
|
...draft.fields.cover?.url ? { cover: draft.fields.cover.url } : {},
|
|
264276
264291
|
/* A review's page is in its world (world.ts); every other call's on Open Call. */
|
|
264277
|
-
url: draft.fields.kind === "review" ? `${ctx.site.replace(/\/+$/, "")}/pro
|
|
264292
|
+
url: draft.fields.kind === "review" ? `${ctx.site.replace(/\/+$/, "")}/me/pro-asks/${slug}` : `${ctx.site.replace(/\/+$/, "")}/opencall/${slug}`,
|
|
264278
264293
|
...dates?.closes ? { endsAt: new Date(new Date(dates.pick ?? dates.closes).getTime() + 30 * 24 * 3600 * 1e3) } : {}
|
|
264279
264294
|
},
|
|
264280
264295
|
{ onMinted: remember2 }
|
|
@@ -265126,6 +265141,7 @@ __export(invites_exports, {
|
|
|
265126
265141
|
inviteItemsOf: () => inviteItemsOf,
|
|
265127
265142
|
linkedinStatus: () => linkedinStatus,
|
|
265128
265143
|
markNoticesRead: () => markNoticesRead,
|
|
265144
|
+
myCalls: () => myCalls,
|
|
265129
265145
|
myInvitations: () => myInvitations,
|
|
265130
265146
|
noticeWords: () => noticeWords,
|
|
265131
265147
|
pageWords: () => pageWords,
|
|
@@ -265268,6 +265284,23 @@ async function myInvitations(site, signer2, fetchImpl) {
|
|
|
265268
265284
|
}
|
|
265269
265285
|
return { invited };
|
|
265270
265286
|
}
|
|
265287
|
+
async function myCalls(site, signer2, fetchImpl) {
|
|
265288
|
+
const calls = [];
|
|
265289
|
+
const person = signer2.principal && signer2.principal !== signer2.address ? signer2.principal : null;
|
|
265290
|
+
for (const onBehalfOf of [null, ...person ? [person] : []]) {
|
|
265291
|
+
const message = callsMessage(signer2.address);
|
|
265292
|
+
const answer = await post(site, "/api/invites/calls", { address: signer2.address, ...onBehalfOf ? { onBehalfOf } : {}, closed: true, proof: { kind: "adr36", message, ...await signWords(signer2.mnemonic, message) } }, fetchImpl);
|
|
265293
|
+
const missed = (why) => ({ calls, missed: `the pro asks of ${onBehalfOf}, the account you act for, could not be read just now (${why})` });
|
|
265294
|
+
if (!answer.ok) {
|
|
265295
|
+
if (!onBehalfOf) return { refused: refusalOf(answer) };
|
|
265296
|
+
return missed(refusalOf(answer));
|
|
265297
|
+
}
|
|
265298
|
+
const rows2 = answer.body.calls ?? [];
|
|
265299
|
+
if (onBehalfOf && rows2.some((one) => one.owner && one.owner !== onBehalfOf)) return missed("the site does not read them for an agent yet");
|
|
265300
|
+
for (const one of rows2) if (!calls.some((seen2) => seen2.collectionId === one.collectionId)) calls.push(one);
|
|
265301
|
+
}
|
|
265302
|
+
return { calls };
|
|
265303
|
+
}
|
|
265271
265304
|
async function readNotices(site, signer2, options = {}, fetchImpl) {
|
|
265272
265305
|
const message = noticesMessage(signer2.address);
|
|
265273
265306
|
const answer = await post(site, "/api/invites/notices", { address: signer2.address, ...signer2.principal ? { onBehalfOf: signer2.principal } : {}, ...options, proof: { kind: "adr36", message, ...await signWords(signer2.mnemonic, message) } }, fetchImpl);
|
|
@@ -265284,7 +265317,7 @@ function noticeWords(notices, site) {
|
|
|
265284
265317
|
return notices.map((one) => {
|
|
265285
265318
|
const room = one.kind === "message" ? /\/with\/([^/?#]+)$/.exec(one.href)?.[1] : void 0;
|
|
265286
265319
|
const next = one.kind === "message" ? `read_messages collectionId "${one.collectionId}"${room ? ` with "${decodeURIComponent(room)}"` : ""}` : one.kind === "application" ? `decide_application "${one.collectionId}"` : one.kind === "link-opened" || one.kind === "invite-accepted" ? `call_invites "${one.collectionId}"` : one.kind === "invite-declined" ? `invite_to_call "${one.collectionId}" (someone else)` : one.kind === "invited" && isReviewTitle(one.title) ? `accept_invitation "${one.collectionId}" or decline_invitation` : one.kind === "declined" ? "" : `read_ask "${one.collectionId}"`;
|
|
265287
|
-
const href = isReviewTitle(one.title) ? one.href.replace(/^\/opencall\/(?!i\/)([a-z][a-z0-9-]{2,39})$/, "/pro
|
|
265320
|
+
const href = sitePath(isReviewTitle(one.title) ? one.href.replace(/^\/opencall\/(?!i\/)([a-z][a-z0-9-]{2,39})$/, one.kind === "invited" ? `/me/work/${one.collectionId}` : "/me/pro-asks/$1") : one.href);
|
|
265288
265321
|
return ` \xB7 ${one.headline}: ${one.line}${/["”.]$/.test(one.line) ? "" : "."} ${base6}${href}${next ? ` \xB7 ${next}` : ""}`;
|
|
265289
265322
|
});
|
|
265290
265323
|
}
|
|
@@ -267013,7 +267046,7 @@ var init_pairing = __esm({
|
|
|
267013
267046
|
CODE = /^[a-f0-9]{16}$/;
|
|
267014
267047
|
memoFor = (code10) => `openhands-connect:${code10}`;
|
|
267015
267048
|
connectLinkWithCode = (site, agent, code10) => `${site}/connect?agent=${encodeURIComponent(agent)}&code=${code10}`;
|
|
267016
|
-
pairingSite = (site,
|
|
267049
|
+
pairingSite = (site, _pairing) => site;
|
|
267017
267050
|
}
|
|
267018
267051
|
});
|
|
267019
267052
|
|
|
@@ -267088,12 +267121,14 @@ function roomRows(counts) {
|
|
|
267088
267121
|
switch (room.key) {
|
|
267089
267122
|
case "page":
|
|
267090
267123
|
return { ...room, figure: null, after: null, ...counts.page === "listed" ? { chip: "Listed" } : counts.page === "private" ? { chip: "Private" } : counts.page === "verify" ? { verify: true } : {} };
|
|
267124
|
+
case "proAsks":
|
|
267125
|
+
return { ...room, ...counted(counts.proAsks ?? null, null) };
|
|
267091
267126
|
case "work":
|
|
267092
|
-
return { ...room, ...
|
|
267127
|
+
return { ...room, ...fresh2(counts.work, "waiting") };
|
|
267093
267128
|
case "messages":
|
|
267094
|
-
return { ...room, ...
|
|
267129
|
+
return { ...room, ...fresh2(counts.unread, "unread") };
|
|
267095
267130
|
case "inbox":
|
|
267096
|
-
return { ...room, ...
|
|
267131
|
+
return { ...room, ...fresh2(counts.inbox, "new") };
|
|
267097
267132
|
case "money":
|
|
267098
267133
|
return { ...room, figure: counts.money.available, money: true, after: counts.money.onAsks ? `${counts.money.onAsks} on asks` : null };
|
|
267099
267134
|
case "agents":
|
|
@@ -267103,12 +267138,13 @@ function roomRows(counts) {
|
|
|
267103
267138
|
}
|
|
267104
267139
|
});
|
|
267105
267140
|
}
|
|
267106
|
-
var ROOMS, counted, roomLines;
|
|
267141
|
+
var ROOMS, counted, fresh2, roomLines;
|
|
267107
267142
|
var init_meRooms = __esm({
|
|
267108
267143
|
"../../app/lib/meRooms.ts"() {
|
|
267109
267144
|
"use strict";
|
|
267110
267145
|
ROOMS = [
|
|
267111
267146
|
{ key: "page", word: "Your page", href: "/me/page" },
|
|
267147
|
+
{ key: "proAsks", word: "Pro asks", href: "/me/pro-asks" },
|
|
267112
267148
|
{ key: "work", word: "Work", href: "/me/work" },
|
|
267113
267149
|
{ key: "messages", word: "Messages", href: "/me/messages" },
|
|
267114
267150
|
{ key: "inbox", word: "Inbox", href: "/me/check" },
|
|
@@ -267117,10 +267153,58 @@ var init_meRooms = __esm({
|
|
|
267117
267153
|
{ key: "settings", word: "Settings", href: "/me/settings" }
|
|
267118
267154
|
];
|
|
267119
267155
|
counted = (value, after) => value ? { figure: String(value), after } : { figure: null, after: null };
|
|
267156
|
+
fresh2 = (value, after) => ({ ...counted(value, after), ...value ? { fresh: true } : {} });
|
|
267120
267157
|
roomLines = (counts) => roomRows(counts).map((row) => `${row.word}: ${row.chip ?? (row.verify ? "not verified yet" : [row.figure, row.after].filter(Boolean).join(row.money ? " \xB7 " : " ") || (row.key === "settings" ? "sign-in, recovery, currency, identity" : "nothing waiting"))}`);
|
|
267121
267158
|
}
|
|
267122
267159
|
});
|
|
267123
267160
|
|
|
267161
|
+
// src/proAsks.ts
|
|
267162
|
+
var proAsks_exports = {};
|
|
267163
|
+
__export(proAsks_exports, {
|
|
267164
|
+
approvePreview: () => approvePreview,
|
|
267165
|
+
handOver: () => handOver,
|
|
267166
|
+
proAskLines: () => proAskLines,
|
|
267167
|
+
proAsksOf: () => proAsksOf,
|
|
267168
|
+
reportPage: () => reportPage,
|
|
267169
|
+
shortDate: () => shortDate
|
|
267170
|
+
});
|
|
267171
|
+
function proAskLines(site, calls, options = {}) {
|
|
267172
|
+
const now3 = options.now ?? Date.now();
|
|
267173
|
+
const base6 = site.replace(/\/+$/, "");
|
|
267174
|
+
return proAsksOf(calls).flatMap((one) => {
|
|
267175
|
+
const open = isOpen2(one, now3);
|
|
267176
|
+
const parts = [open ? "Open" : "Closed", `${one.count} of ${one.quota} reports`];
|
|
267177
|
+
const closes = open ? shortDate(one.end_date) : "";
|
|
267178
|
+
if (closes) parts.push(`closes ${closes}`);
|
|
267179
|
+
const held = options.held?.get(one.collectionId);
|
|
267180
|
+
if (held) parts.push(`holds ${held}`);
|
|
267181
|
+
const toApprove = options.waiting?.filter((item) => item.collectionId === one.collectionId).length ?? 0;
|
|
267182
|
+
if (toApprove) parts.push(`${toApprove} ${toApprove === 1 ? "report" : "reports"} to approve`);
|
|
267183
|
+
return [`#${one.collectionId} ${bare(one.title)} \xB7 ${parts.join(" \xB7 ")}`, ` ${base6}/me/pro-asks/${one.collectionId}`];
|
|
267184
|
+
});
|
|
267185
|
+
}
|
|
267186
|
+
function approvePreview(site, input) {
|
|
267187
|
+
const page = reportPage(site, input.collectionId, input.claimId);
|
|
267188
|
+
const what = `Approving report ${input.claimId} on pro ask #${input.collectionId} pays ${input.pro}${input.pays ? ` ${input.pays}` : ""} from what the ask holds. Approval is final.`;
|
|
267189
|
+
return input.canSign ? [what, `The report: ${page}`, "", "To approve, call approve_report again with confirm: true."].join("\n") : [what, handOver(site, input), "Nothing was sent."].join("\n");
|
|
267190
|
+
}
|
|
267191
|
+
var bare, shortDate, isOpen2, proAsksOf, reportPage, handOver;
|
|
267192
|
+
var init_proAsks = __esm({
|
|
267193
|
+
"src/proAsks.ts"() {
|
|
267194
|
+
"use strict";
|
|
267195
|
+
init_world();
|
|
267196
|
+
bare = (title) => (title ?? "").replace(/^Expert review:\s*/, "") || "A pro ask";
|
|
267197
|
+
shortDate = (iso) => {
|
|
267198
|
+
const at = iso ? new Date(iso) : null;
|
|
267199
|
+
return at && !Number.isNaN(at.getTime()) ? at.toLocaleDateString("en-GB", { day: "numeric", month: "short", timeZone: "UTC" }) : "";
|
|
267200
|
+
};
|
|
267201
|
+
isOpen2 = (one, now3) => one.state === 0 && (!one.end_date || Date.parse(one.end_date) > now3);
|
|
267202
|
+
proAsksOf = (calls) => calls.filter((one) => isReviewTitle(one.title)).sort((a, b) => Number(b.collectionId) - Number(a.collectionId));
|
|
267203
|
+
reportPage = (site, collectionId, claimId) => `${site.replace(/\/+$/, "")}/pro/reviews/${collectionId}/report/${encodeURIComponent(claimId)}`;
|
|
267204
|
+
handOver = (site, input) => `Only ${input.approver} can give this OK, signed in as themselves: the Approve button on the report's page, ${reportPage(site, input.collectionId, input.claimId)}#decide. This key acts for them but cannot sign their OK at the verifier.`;
|
|
267205
|
+
}
|
|
267206
|
+
});
|
|
267207
|
+
|
|
267124
267208
|
// src/verdictSource.ts
|
|
267125
267209
|
var verdictSource_exports = {};
|
|
267126
267210
|
__export(verdictSource_exports, {
|
|
@@ -292281,7 +292365,7 @@ import { randomBytes as randomBytes7 } from "node:crypto";
|
|
|
292281
292365
|
// package.json
|
|
292282
292366
|
var package_default = {
|
|
292283
292367
|
name: "@ixo/asks-mcp",
|
|
292284
|
-
version: "2.0.0-dev.
|
|
292368
|
+
version: "2.0.0-dev.4",
|
|
292285
292369
|
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.",
|
|
292286
292370
|
license: "Apache-2.0",
|
|
292287
292371
|
repository: {
|
|
@@ -292571,7 +292655,7 @@ var TOOLS = {
|
|
|
292571
292655
|
},
|
|
292572
292656
|
draft_call: {
|
|
292573
292657
|
title: "Set up an open call or a pro ask",
|
|
292574
|
-
description: 'Draft an open call or a pro ask. An open call is a brief people answer with their own AI, checked against five requirements: a competition picks a winner; a hire pays every entry that passes, up to a number, and picks nobody; open to anyone, by application (you say yes to each), or by invitation (your list: addresses, @handles, single-use links). A software-review Ask (`kind: "review"`) is one specialised work type on Pro Asks: verified pros you invite try the scenarios and send reports; always a hire, by invitation only; Asky Pro Checker, the verifier, checks each report. Interviews in order: give what the person said, and the answer lists what is still missing, each with the question to ask them. Kept on disk between calls, so never re-send what was already taken. When nothing is missing it shows the whole call, what each leg holds (a pro ask\'s money in one sentence: what each pro receives, what is held per report, and the fee: 20 %
|
|
292658
|
+
description: 'Draft an open call or a pro ask. An open call is a brief people answer with their own AI, checked against five requirements: a competition picks a winner; a hire pays every entry that passes, up to a number, and picks nobody; open to anyone, by application (you say yes to each), or by invitation (your list: addresses, @handles, single-use links). A software-review Ask (`kind: "review"`) is one specialised work type on Pro Asks: verified pros you invite try the scenarios and send reports; always a hire, by invitation only; Asky Pro Checker, the verifier, checks each report. Interviews in order: give what the person said, and the answer lists what is still missing, each with the question to ask them. Kept on disk between calls, so never re-send what was already taken. When nothing is missing it shows the whole call, what each leg holds (a pro ask\'s money in one sentence: what each pro receives, what is held per report, and the fee: 20 % of what you pay runs asks.world, the pro gets the rest) and the clock, for the person to approve. Spends nothing.',
|
|
292575
292659
|
spends: false,
|
|
292576
292660
|
hosted: false,
|
|
292577
292661
|
/* It writes the draft file, and nothing else anywhere. */
|
|
@@ -292627,6 +292711,20 @@ var TOOLS = {
|
|
|
292627
292711
|
hosted: false,
|
|
292628
292712
|
annotations: { ...reads, readOnlyHint: true }
|
|
292629
292713
|
},
|
|
292714
|
+
my_pro_asks: {
|
|
292715
|
+
title: "List the pro asks the person posted",
|
|
292716
|
+
description: `The pro asks this key posted, and those of the person it acts for, newest first, one line each as the site's Pro asks room says them: Open or Closed, how many reports of how many, when it closes, what it holds, and what waits for them ("1 report to approve"), with its page, which only they can open. The next step on each is a tool: invite_to_call, collect_answer (reads its reports), approve_report, close_ask. Spends nothing.`,
|
|
292717
|
+
spends: false,
|
|
292718
|
+
hosted: false,
|
|
292719
|
+
annotations: { ...reads, readOnlyHint: true }
|
|
292720
|
+
},
|
|
292721
|
+
approve_report: {
|
|
292722
|
+
title: "Approve a report on a pro ask (spends money)",
|
|
292723
|
+
description: "Give the final OK on one report a pro sent to a pro ask: the verifier records it and the pro is paid from what the ask holds. Approval is final. Call without confirm first: it says the report, who sent it, what approving pays and whose OK it is; then again with confirm: true, which approves when this key is the one the ask names to give the OK. When the OK is the person's own (a pro ask posted for them), it hands them the report's Approve button on the site instead, and sends nothing.",
|
|
292724
|
+
spends: true,
|
|
292725
|
+
hosted: false,
|
|
292726
|
+
annotations: acts
|
|
292727
|
+
},
|
|
292630
292728
|
accept_invitation: {
|
|
292631
292729
|
title: "Accept an invitation to a pro ask",
|
|
292632
292730
|
description: "Accept an invitation to a pro ask: a link or the ask's number. As the account you act for when connected, else as this key. The builder hears you accepted, and your room with them opens with their note first; a link becomes yours, so nobody else can use it. Someone who is not a verified pro is refused, and the link stays open. Previews; `confirm: true` accepts, once the person says yes. Spends nothing.",
|
|
@@ -293249,8 +293347,8 @@ function whyFromReceipt(receipt, rubric) {
|
|
|
293249
293347
|
const push = (r) => {
|
|
293250
293348
|
const clean6 = { ...r, label: scrub(r.label, 200), detail: scrub(r.detail) };
|
|
293251
293349
|
const key = `${clean6.result}|${clean6.label}`;
|
|
293252
|
-
const
|
|
293253
|
-
if (seen2.has(`${key}|${clean6.detail}`) ||
|
|
293350
|
+
const bare2 = clean6.detail === "Passed" || clean6.detail === "Did not pass";
|
|
293351
|
+
if (seen2.has(`${key}|${clean6.detail}`) || bare2 && seen2.has(key)) return;
|
|
293254
293352
|
seen2.add(key).add(`${key}|${clean6.detail}`);
|
|
293255
293353
|
reasons.push(clean6);
|
|
293256
293354
|
};
|
|
@@ -294400,18 +294498,18 @@ async function build2(options, server2, parts) {
|
|
|
294400
294498
|
const refreshDeployment = async () => {
|
|
294401
294499
|
if (!local || options.deployment || Date.now() - siteReadAt < (CLAIM_FORM && !DEPLOYMENT.note ? SITE_REREAD_MS : 1e4)) return;
|
|
294402
294500
|
siteReadAt = Date.now();
|
|
294403
|
-
const
|
|
294404
|
-
if (!
|
|
294405
|
-
DEPLOYMENT =
|
|
294406
|
-
adoptRelayer(
|
|
294407
|
-
adoptAskProtocol(
|
|
294408
|
-
adoptReviewBilling(
|
|
294409
|
-
adoptOracleUrl(
|
|
294410
|
-
adoptFeeSplit(
|
|
294411
|
-
adoptAskDenom(
|
|
294412
|
-
adoptClaimForm(
|
|
294413
|
-
CLAIM_FORM =
|
|
294414
|
-
applyDeployment(
|
|
294501
|
+
const fresh3 = await deployment().catch(() => null);
|
|
294502
|
+
if (!fresh3 || fresh3.note) return;
|
|
294503
|
+
DEPLOYMENT = fresh3;
|
|
294504
|
+
adoptRelayer(fresh3);
|
|
294505
|
+
adoptAskProtocol(fresh3);
|
|
294506
|
+
adoptReviewBilling(fresh3);
|
|
294507
|
+
adoptOracleUrl(fresh3);
|
|
294508
|
+
adoptFeeSplit(fresh3);
|
|
294509
|
+
adoptAskDenom(fresh3);
|
|
294510
|
+
adoptClaimForm(fresh3);
|
|
294511
|
+
CLAIM_FORM = fresh3.claimForm;
|
|
294512
|
+
applyDeployment(fresh3);
|
|
294415
294513
|
};
|
|
294416
294514
|
const unjudged = async () => {
|
|
294417
294515
|
await refreshDeployment();
|
|
@@ -294442,7 +294540,7 @@ async function build2(options, server2, parts) {
|
|
|
294442
294540
|
const cap = capCoinRefusal2(acting, coin);
|
|
294443
294541
|
return cap ? { refused: cap } : coin;
|
|
294444
294542
|
};
|
|
294445
|
-
const
|
|
294543
|
+
const feeWords2 = (base6, symbol2 = FEE_SYMBOL) => dollarsOf(base6, symbol2, NETWORK2);
|
|
294446
294544
|
const FUNDER = ownEnv().OPENHANDS_FUNDER?.trim() || void 0;
|
|
294447
294545
|
const FOLLOW_PAY_MAX = 10;
|
|
294448
294546
|
const MAX_PER_ASK = CAPS.perAsk;
|
|
@@ -294698,11 +294796,11 @@ Each is its own ask and pays on its own. Read one with read_ask before deciding.
|
|
|
294698
294796
|
if (title) taint2(title);
|
|
294699
294797
|
const facts = row.callSummary;
|
|
294700
294798
|
const shares = call3.shared;
|
|
294701
|
-
const entryPays = shares && facts?.entryEach !== void 0 && call3.entries?.pays ?
|
|
294799
|
+
const entryPays = shares && facts?.entryEach !== void 0 && call3.entries?.pays ? faceOf2({ value: facts.entryEach, symbol: call3.entries.pays.symbol }, SANDBOX)?.text : call3.entries?.pays ? `${faceOf2(call3.entries.pays, SANDBOX)?.text}${shares ? ", less the network's share" : ""}` : void 0;
|
|
294702
294800
|
return [
|
|
294703
294801
|
`${review ? "Expert review" : "Open call"} "${call3.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`,
|
|
294704
294802
|
title ? asData("ask-title", title) : "",
|
|
294705
|
-
`${review ? "A specialist's report on the review's scenarios, assessed against its requirements. A report that meets them is paid, after the builder's final approval when they give one." : "A written entry assessed against five requirements. Entries that meet all five are paid. For competitions, the poster also chooses a prize winner."} ${call3.entries ? `Read it with read_ask "${call3.entries.id}"; the page is` : "Read its legs on the page:"} ${review ? `${EXPERT_SITE}/pro
|
|
294803
|
+
`${review ? "A specialist's report on the review's scenarios, assessed against its requirements. A report that meets them is paid, after the builder's final approval when they give one." : "A written entry assessed against five requirements. Entries that meet all five are paid. For competitions, the poster also chooses a prize winner."} ${call3.entries ? `Read it with read_ask "${call3.entries.id}"; the page is` : "Read its legs on the page:"} ${review ? `${EXPERT_SITE}/me/pro-asks/${call3.entries?.id ?? call3.slug}` : `${SITE}/opencall/${call3.slug}`}`
|
|
294706
294804
|
].filter(Boolean).join("\n");
|
|
294707
294805
|
};
|
|
294708
294806
|
const lines2 = board.rows.filter(within2).map((row) => {
|
|
@@ -295305,15 +295403,15 @@ Never open it yourself.`);
|
|
|
295305
295403
|
amount: offChain ? `${offChain.amount} ${offChain.currency}` : face(pay, symbol2),
|
|
295306
295404
|
quota: spots,
|
|
295307
295405
|
total: offChain ? `${(Number(offChain.amount) * spots).toFixed(2)} ${offChain.currency}` : rewardsFace,
|
|
295308
|
-
fee:
|
|
295309
|
-
feeTotal:
|
|
295406
|
+
fee: feeWords2(perCheck ? perCheck.price : legBase),
|
|
295407
|
+
feeTotal: feeWords2(legBase * spots),
|
|
295310
295408
|
perReview: Boolean(perCheck),
|
|
295311
295409
|
own: !perCheck && legBase === 0 && !orgAsk.oracle.url,
|
|
295312
295410
|
free: !perCheck && legBase === 0 && Boolean(orgAsk.oracle.url)
|
|
295313
295411
|
}).map((line2) => `- ${line2.label}: ${line2.text}`).join("\n") : "";
|
|
295314
295412
|
const { total, what: preview, details: costDetails } = orgAsk ? { total: 0, what: `nothing from this key (${orgName} pays)`, details: `What this costs ${orgName}:
|
|
295315
|
-
${orgCosts}` } : { total: onChain.total, what: perCheck ? `${onChain.what}. Review fee: ${billing.creditsCopy(null,
|
|
295316
|
-
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 ?
|
|
295413
|
+
${orgCosts}` } : { total: onChain.total, what: perCheck ? `${onChain.what}. Review fee: ${billing.creditsCopy(null, feeWords2(perCheck.price))}` : onChain.what, details: "" };
|
|
295414
|
+
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 ? feeWords2(legBase * spots) : null }) : void 0;
|
|
295317
295415
|
const payDraft = card ? await Promise.resolve().then(() => (init_payDraft(), payDraft_exports)) : null;
|
|
295318
295416
|
const quote = payDraft?.quoteOf(Number(baseFromPay2(pay)) * spots, legBase * spots);
|
|
295319
295417
|
const cardWords = payDraft && quote ? payDraft.cardPreview(quote) : null;
|
|
@@ -295342,7 +295440,7 @@ ${orgCosts}` } : { total: onChain.total, what: perCheck ? `${onChain.what}. Revi
|
|
|
295342
295440
|
card ? null : actingNote(acting),
|
|
295343
295441
|
pick2,
|
|
295344
295442
|
expert ? expertNote(expert) : checkingNote(terms, acting?.principal ?? null),
|
|
295345
|
-
expert ? null : orgAsk ? `Reviewed by ${await oracleWordsFor({ did: orgAsk.oracle.did, address: orgAsk.oracle.address })}.` : reviewer && reviewer !== CHECKER ? `Reviewed by ${await oracleWordsFor({ address: reviewer })}.` : reviewer ? `Checked by asks.world verifier, ${
|
|
295443
|
+
expert ? null : orgAsk ? `Reviewed by ${await oracleWordsFor({ did: orgAsk.oracle.did, address: orgAsk.oracle.address })}.` : reviewer && reviewer !== CHECKER ? `Reviewed by ${await oracleWordsFor({ address: reviewer })}.` : reviewer ? `Checked by asks.world verifier, ${feeWords2(perCheck ? perCheck.price : legBase)} per check.` : null,
|
|
295346
295444
|
doorWords(door2.access, door2.invite.length),
|
|
295347
295445
|
inCampaign ? `In campaign ${inCampaign.protocolDid}, checked by its shared rules (${inCampaign.claimProtocolDid}).` : null,
|
|
295348
295446
|
picture2 && !("refused" in picture2) ? `Picture: ${picture2.contentType.slice(6)}, ${Math.ceil(picture2.bytes.byteLength / 1024)} KB, uploaded through your account connection with the ask.` : null,
|
|
@@ -295429,7 +295527,7 @@ ${SITE}/t/${earlier.id}`);
|
|
|
295429
295527
|
const callPerCheck = async (checker = CHECKER) => (await Promise.resolve().then(() => (init_reviewBilling(), reviewBilling_exports))).deploymentBillsPerCheck(checker).catch(() => false);
|
|
295430
295528
|
const callChecker2 = async (review) => (await Promise.resolve().then(() => (init_call2(), call_exports2))).callChecker(NETWORK2, review, CHECKER);
|
|
295431
295529
|
const callSplit = async () => (await Promise.resolve().then(() => (init_query43(), query_exports43))).feeSplitOrNull();
|
|
295432
|
-
async function sharedPays(leg, posted,
|
|
295530
|
+
async function sharedPays(leg, posted, bare2 = false) {
|
|
295433
295531
|
if (leg?.is_oracle_payment !== true || !leg.amount?.[0]) return null;
|
|
295434
295532
|
const { coinDisplay: coinDisplay2, faceOf: faceOf2 } = await Promise.resolve().then(() => (init_format(), format_exports));
|
|
295435
295533
|
const { netOf: netOf2 } = await Promise.resolve().then(() => (init_share(), share_exports));
|
|
@@ -295439,15 +295537,15 @@ ${SITE}/t/${earlier.id}`);
|
|
|
295439
295537
|
const split3 = posted ?? await callSplit();
|
|
295440
295538
|
if (!split3) return `${said4(Number(amount3))} less the network's share (the fee split could not be read just now)`;
|
|
295441
295539
|
const receives = netOf2(Number(amount3), split3);
|
|
295442
|
-
if (
|
|
295540
|
+
if (bare2) return said4(receives);
|
|
295443
295541
|
return `${said4(receives)} (the leg is ${said4(Number(amount3))}; the network keeps ${said4(Number(amount3) - receives)}: ${shareWords2(split3, posted ? "as posted" : "today")})`;
|
|
295444
295542
|
}
|
|
295445
|
-
const callLocks = (rewardBase, feeBase, symbol2 = ASK_SYMBOL) => `${pays(rewardBase, symbol2)}${feeBase > 0 ? ` and ${
|
|
295543
|
+
const callLocks = (rewardBase, feeBase, symbol2 = ASK_SYMBOL) => `${pays(rewardBase, symbol2)}${feeBase > 0 ? ` and ${feeWords2(feeBase)} for reviews` : ""}`;
|
|
295446
295544
|
function escrowTotal(pay, spots, legBase, symbol2 = ASK_SYMBOL, sameCoin = true, feeSymbol = FEE_SYMBOL) {
|
|
295447
295545
|
const leg = legBase / MICRO6;
|
|
295448
295546
|
if (!sameCoin && leg > 0) {
|
|
295449
295547
|
const total2 = pay * spots;
|
|
295450
|
-
return { total: total2, what: `${face(total2, symbol2)} and ${
|
|
295548
|
+
return { total: total2, what: `${face(total2, symbol2)} and ${feeWords2(legBase * spots, feeSymbol)}. A ${face(pay, symbol2)} reward for each of ${spots} ${spots === 1 ? "answer" : "answers"}, plus ${feeWords2(legBase, feeSymbol)} for each review. Held now` };
|
|
295451
295549
|
}
|
|
295452
295550
|
const total = (pay + leg) * spots;
|
|
295453
295551
|
return {
|
|
@@ -295554,7 +295652,7 @@ ${SITE}/t/${earlier.id}`);
|
|
|
295554
295652
|
const billing = await Promise.resolve().then(() => (init_reviewBilling(), reviewBilling_exports));
|
|
295555
295653
|
const escrowed = escrowTotal(pay, spots, legBase, coinSymbol, coin === (expert?.feeDenom ?? FEE_DENOM), symbolOf(expert?.feeDenom ?? FEE_DENOM));
|
|
295556
295654
|
const total = escrowed.total;
|
|
295557
|
-
const what = perCheck ? `${escrowed.what}. Review fee: ${billing.creditsCopy(null,
|
|
295655
|
+
const what = perCheck ? `${escrowed.what}. Review fee: ${billing.creditsCopy(null, feeWords2(perCheck.price))}` : escrowed.what;
|
|
295558
295656
|
const guard = spendGuard({
|
|
295559
295657
|
bucket: "world",
|
|
295560
295658
|
task: question,
|
|
@@ -296356,10 +296454,11 @@ ${pending.link}`);
|
|
|
296356
296454
|
})();
|
|
296357
296455
|
const rooms = await (async () => {
|
|
296358
296456
|
try {
|
|
296359
|
-
const [{ roomLines: roomLines2 }, invitesModule, roomsModule] = await Promise.all([Promise.resolve().then(() => (init_meRooms(), meRooms_exports)), Promise.resolve().then(() => (init_invites(), invites_exports)), Promise.resolve().then(() => (init_rooms(), rooms_exports))]);
|
|
296457
|
+
const [{ roomLines: roomLines2 }, invitesModule, roomsModule, { proAsksOf: proAsksOf2 }] = await Promise.all([Promise.resolve().then(() => (init_meRooms(), meRooms_exports)), Promise.resolve().then(() => (init_invites(), invites_exports)), Promise.resolve().then(() => (init_rooms(), rooms_exports)), Promise.resolve().then(() => (init_proAsks(), proAsks_exports))]);
|
|
296360
296458
|
const signer3 = await inviteSigner(await principal2());
|
|
296361
|
-
const [page, invited, mineRooms, waiting, agents] = await Promise.all([
|
|
296459
|
+
const [page, calls, invited, mineRooms, waiting, agents] = await Promise.all([
|
|
296362
296460
|
invitesModule.readMyPage(SITE, signer3).catch(() => void 0),
|
|
296461
|
+
invitesModule.myCalls(SITE, signer3).catch(() => null),
|
|
296363
296462
|
invitesModule.myInvitations(SITE, signer3).catch(() => null),
|
|
296364
296463
|
roomsModule.myRooms(SITE, signer3).catch(() => null),
|
|
296365
296464
|
fetch2(`${SITE}/api/waiting?address=${encodeURIComponent(signer3.address)}`, { signal: AbortSignal.timeout(2e4) }).then((r) => r.ok ? r.json() : null).catch(() => null),
|
|
@@ -296370,6 +296469,7 @@ ${pending.link}`);
|
|
|
296370
296469
|
"You, as the account area says it:",
|
|
296371
296470
|
...roomLines2({
|
|
296372
296471
|
page: page === void 0 ? null : page === null ? "none" : !verified ? "verify" : page.profile.listed === false ? "private" : "listed",
|
|
296472
|
+
proAsks: calls && "calls" in calls ? proAsksOf2(calls.calls).length : null,
|
|
296373
296473
|
work: invited && "invited" in invited ? invited.invited.filter((one) => one.answer === "sent").length : null,
|
|
296374
296474
|
unread: mineRooms && "rooms" in mineRooms ? mineRooms.rooms.reduce((sum2, one) => sum2 + one.unread, 0) : null,
|
|
296375
296475
|
inbox: Array.isArray(waiting?.waiting) ? waiting.waiting.length : null,
|
|
@@ -296393,7 +296493,7 @@ ${pending.link}`);
|
|
|
296393
296493
|
The review fee's coin, where it is not the reward's (mainnet: USDC rewards, PAY fees), is what covers the next
|
|
296394
296494
|
ask's checks, so it is said when there is any. In dollars, as every amount. The network fee is the gate's to
|
|
296395
296495
|
cover for an account that holds money, so it is not a line here. */
|
|
296396
|
-
`Available: ${pays(Number(held[ASK_DENOM] ?? 0), ASK_DENOM)} \xB7 On your asks ${onAsks === null ? "(could not be read just now)" : pays(onAsks, "upay")}${ASK_DENOM !== FEE_DENOM && Number(held[FEE_DENOM] ?? 0) > 0 ? ` \xB7 ${
|
|
296496
|
+
`Available: ${pays(Number(held[ASK_DENOM] ?? 0), ASK_DENOM)} \xB7 On your asks ${onAsks === null ? "(could not be read just now)" : pays(onAsks, "upay")}${ASK_DENOM !== FEE_DENOM && Number(held[FEE_DENOM] ?? 0) > 0 ? ` \xB7 ${feeWords2(Number(held[FEE_DENOM]))} set aside for checks` : ""}`,
|
|
296397
296497
|
done ? `Work: ${done.submitted ?? 0} answers \xB7 ${done.approved ?? 0} approved${done.earned ? ` \xB7 ${face(done.earned.value, done.earned.symbol)} earned` : ""}` : "",
|
|
296398
296498
|
/* Whose money this would spend, and how much of it is left. An agent
|
|
296399
296499
|
funded by somebody's allowance should be able to say so — and an
|
|
@@ -296559,7 +296659,7 @@ ${settings}`
|
|
|
296559
296659
|
const unread = await unreadable(terms);
|
|
296560
296660
|
if (unread) return text4(unread);
|
|
296561
296661
|
const { total } = escrowTotal(pin_pay, pins2, legBase, coinSymbol, coin === FEE_DENOM);
|
|
296562
|
-
const preview = `${face(total, coinSymbol)} to open "${name8}". ${pins2} ${pins2 === 1 ? "report" : "reports"} at ${face(pin_pay, coinSymbol)} each, plus ${
|
|
296662
|
+
const preview = `${face(total, coinSymbol)} to open "${name8}". ${pins2} ${pins2 === 1 ? "report" : "reports"} at ${face(pin_pay, coinSymbol)} each, plus ${feeWords2(legBase)} to whoever checks each one. Mapping stays open ${open} days, and two pins closer than ${apart} m are the same mess`;
|
|
296563
296663
|
const guard = spendGuard({ bucket: "organise", task: `campaign ${tag}`, total, ...confirm ? { confirm } : {}, what: preview, symbol: coinSymbol });
|
|
296564
296664
|
if (guard) {
|
|
296565
296665
|
return text4(
|
|
@@ -296706,12 +296806,12 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296706
296806
|
const keyOnly = !acting && feeTotal > 0;
|
|
296707
296807
|
const blocked = capped4.length > 0 || Boolean(otherCoin) || Boolean(twoCoins) && draft.fields.kind !== "review";
|
|
296708
296808
|
const m = draft.fields.money;
|
|
296709
|
-
const {
|
|
296809
|
+
const { feeSentence: feeSentence2 } = await Promise.resolve().then(() => (init_feeLine(), feeLine_exports));
|
|
296710
296810
|
const proMoney = proAsk && Boolean(plan.share);
|
|
296711
296811
|
const who = draft.fields.kind === "review" ? "pro" : "hired person";
|
|
296712
|
-
const
|
|
296812
|
+
const legPays = (leg) => plan.share && !proMoney ? `, so the leg pays ${pays(leg.legBase, coinSymbol)}` : "";
|
|
296713
296813
|
const legRows = plan.legs.map(
|
|
296714
|
-
(leg) => leg.leg === "prize" ? ` The pick ${pays(leg.payBase, coinSymbol)} to one entry${
|
|
296814
|
+
(leg) => leg.leg === "prize" ? ` The pick ${pays(leg.payBase, coinSymbol)} to one entry${legPays(leg)}; its ask takes ${leg.quota} claims (the pick and two spare) \xB7 locks ${pays(leg.escrowBase, coinSymbol)}` : leg.leg === "runnersUp" ? ` Runners-up ${pays(leg.payBase, coinSymbol)} to each of ${m.runnersN}${legPays(leg)} \xB7 locks ${pays(leg.escrowBase, coinSymbol)}` : plan.share ? ` Entries each ${who} receives ${pays(leg.payBase, coinSymbol)} for an entry that passes all ${draft.fields.kind === "review" ? "six" : "five"} lines${legPays(leg)} \xB7 up to ${leg.quota}${checker.fee ? `, plus ${pays(leg.checkBase, coinSymbol)} per check to ${checker.name}` : leg.checkBase > 0 ? `, plus the verifier's ${feeWords2(leg.checkBase)} per ruling` : ", the verifier billed per check from credits"} \xB7 locks ${callLocks(leg.escrowBase, leg.feeBase, coinSymbol)}` : ` Entries ${pays(leg.payBase, coinSymbol)} to each entry that passes all ${draft.fields.kind === "review" ? "six" : "five"} lines, up to ${leg.quota}${checker.fee ? `, plus ${pays(leg.checkBase, coinSymbol)} per check to ${checker.name}` : leg.checkBase > 0 ? `, plus the verifier's ${feeWords2(leg.checkBase)} per ruling` : ", the verifier billed per check from credits"} \xB7 locks ${callLocks(leg.escrowBase, leg.feeBase, coinSymbol)}`
|
|
296715
296815
|
);
|
|
296716
296816
|
const shareTotal = plan.legs.reduce((sum2, one) => sum2 + one.shareBase * one.escrowSpots, 0);
|
|
296717
296817
|
const hire = draft.fields.mode === "hire";
|
|
@@ -296722,7 +296822,7 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296722
296822
|
!hire && m.prize < m.entryEach ? `The prize (${face(m.prize, coinSymbol)}) is less than one entry earns (${face(m.entryEach, coinSymbol)}).` : "",
|
|
296723
296823
|
draft.fields.access === "invite" && !draft.fields.invite?.length ? proAsk ? "Nobody invited yet: find_pro suggests verified pros; 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.' : "",
|
|
296724
296824
|
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." : "",
|
|
296725
|
-
...call3.balanceWarnings(held, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords }),
|
|
296825
|
+
...call3.balanceWarnings(held, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords: feeWords2 }),
|
|
296726
296826
|
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.` : "",
|
|
296727
296827
|
keyOnly ? `Not connected, and a connection would not carry this call: ${call3.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.` : ""
|
|
296728
296828
|
].filter(Boolean);
|
|
@@ -296736,15 +296836,15 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296736
296836
|
...legRows,
|
|
296737
296837
|
` Total ${callLocks(plan.totalBase, feeTotal, coinSymbol)}`,
|
|
296738
296838
|
...plan.share && !proMoney ? [
|
|
296739
|
-
` Network's share ${pays(shareTotal, coinSymbol)} of that, if every spot is paid
|
|
296839
|
+
` Network's share ${pays(shareTotal, coinSymbol)} of that, if every spot is paid. ${feeSentence2(plan.share, NETWORK2, "Each hired person")} Asks and public calls carry no share.`
|
|
296740
296840
|
] : [],
|
|
296741
296841
|
"",
|
|
296742
|
-
`${actingNote(acting) ?? `Not connected; with plain_key this key posts as itself, ${await address2()}.`} The account holds ${holds ?? "an amount nobody could read"}${held !== null && feeTotal > 0 ? ` and ${
|
|
296842
|
+
`${actingNote(acting) ?? `Not connected; with plain_key this key posts as itself, ${await address2()}.`} The account holds ${holds ?? "an amount nobody could read"}${held !== null && feeTotal > 0 ? ` and ${feeWords2(held.fee)}` : ""}; this call locks ${callLocks(plan.totalBase, feeTotal, coinSymbol)}.`,
|
|
296743
296843
|
hire ? `The clock: entries close ${new Date(plan.dates.closes).toUTCString()}; ${finalOk ? `every passing report is paid once ${finalOk} gives the final OK` : "every passing entry is paid as it is judged"}, and nothing waits for a pick.` : `The clock: entries close ${new Date(plan.dates.closes).toUTCString()}; the shortlist shows ${new Date(plan.dates.drop).toUTCString()}; the pick by ${new Date(plan.dates.pick).toUTCString()}.`,
|
|
296744
296844
|
`Who may enter: ${draft.fields.access === "invite" ? `by invitation only${draft.fields.invite?.length ? `. ${draft.fields.invite.length} people will be invited when the Ask is posted${draft.fields.inviteNote ? ", each with your private note" : ""}` : ""}` : draft.fields.access === "apply" ? "by application, listed on the board" : "anyone, listed on the board"}.`,
|
|
296745
296845
|
...draft.fields.kind === "review" ? [
|
|
296746
296846
|
`A pro ask: every entry is a review report with screenshots (submit_work's report and files), checked by ${checker.name ?? "the AI"} on the lines${acting ? `, then ${acting.principal} gives final approval before anyone is paid` : `; posted from this key itself, ${checker.name ?? "the AI"} decides alone and passing reports are paid as they are judged`}.`,
|
|
296747
|
-
draft.posted.entries ? `Its page: ${EXPERT_SITE}/pro
|
|
296847
|
+
draft.posted.entries ? `Its page: ${EXPERT_SITE}/me/pro-asks/${draft.posted.entries.id}` : "Its page is named by the pro ask's number, given once it posts."
|
|
296748
296848
|
] : [],
|
|
296749
296849
|
...warnings2.length ? ["", "Warnings:", ...warnings2.map((one) => ` - ${one}`)] : [],
|
|
296750
296850
|
"",
|
|
@@ -296772,7 +296872,7 @@ Mapping pays for the report. What happens to a mapped pin afterwards is a separa
|
|
|
296772
296872
|
if (!found) return text4(`No draft called "${slug}". Start one with draft_call.`);
|
|
296773
296873
|
const review = found.fields.kind === "review";
|
|
296774
296874
|
const checker = await callChecker2(review);
|
|
296775
|
-
const linkOf = (posted2) => review ? `${EXPERT_SITE}/pro
|
|
296875
|
+
const linkOf = (posted2) => review ? `${EXPERT_SITE}/me/pro-asks/${posted2.entries?.id ?? slug}` : `${SITE}/opencall/${slug}`;
|
|
296776
296876
|
const settled = found.inFlight ? await call3.settleInFlight(slug, call3.indexLookup) : null;
|
|
296777
296877
|
if (settled?.state === "pending") return text4(settled.words);
|
|
296778
296878
|
if (settled?.state === "landed") {
|
|
@@ -296838,20 +296938,19 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296838
296938
|
return text4(await payDraft.saveDraft(SITE, { kind: "call", terms, quote, network: NETWORK2 }, fetch2));
|
|
296839
296939
|
}
|
|
296840
296940
|
if (!confirm) {
|
|
296841
|
-
const {
|
|
296842
|
-
const shareTotal = plan.legs.reduce((sum2, one) => sum2 + one.shareBase * one.escrowSpots, 0);
|
|
296941
|
+
const { feeSentence: feeSentence2 } = await Promise.resolve().then(() => (init_feeLine(), feeLine_exports));
|
|
296843
296942
|
const held2 = await heldBy(acting, coin);
|
|
296844
296943
|
return text4(
|
|
296845
296944
|
[
|
|
296846
296945
|
`Call "${slug}" locks ${callLocks(plan.totalBase, feeTotal, coinSymbol)} in ${order2.length} ${order2.length === 1 ? "Ask" : "Asks"}, posted one per call: ${order2.map((one) => LEG_WORDS[one]).join(", then ")}.${ids.length ? ` Posted already: ${ids.join(", ")}.` : ""}`,
|
|
296847
|
-
/* A private call: the
|
|
296848
|
-
...moneySentence ? [moneySentence] : plan.share ? [`
|
|
296946
|
+
/* A private call: the fee is in that total, said before the yes in one figure of what the poster pays; a pro ask says it in its one sentence. */
|
|
296947
|
+
...moneySentence ? [moneySentence] : plan.share ? [`Each hired person receives ${pays(plan.legs.find((one) => one.leg === "entries").payBase, coinSymbol)} for each passing entry. ${feeSentence2(plan.share, NETWORK2, "Each hired person")}`] : [],
|
|
296849
296948
|
`Next: ${LEG_WORDS[next]}, locking ${callLocks(leg.escrowBase, leg.feeBase, coinSymbol)}, plus a small network fee.`,
|
|
296850
296949
|
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}.`),
|
|
296851
296950
|
...pick2 ? [pick2] : [],
|
|
296852
296951
|
`Spent today (call): ${spentWords("call", coinSymbol)}. Every tool together: ${spentAllWords()}.`,
|
|
296853
296952
|
...call3.capWords(plan.legs.filter((one) => !draft.posted[one.leg]), CAP_BASE, coinSymbol, NETWORK2),
|
|
296854
|
-
...call3.balanceWarnings(held2, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords }),
|
|
296953
|
+
...call3.balanceWarnings(held2, { totalBase: plan.totalBase, feeTotal, symbol: coinSymbol, network: NETWORK2, feeWords: feeWords2 }),
|
|
296855
296954
|
"",
|
|
296856
296955
|
`To go ahead, call again with confirm: "${total}".`
|
|
296857
296956
|
].join("\n")
|
|
@@ -296871,7 +296970,7 @@ Then call post_call again. Nothing was posted.`);
|
|
|
296871
296970
|
feeDenom: FEE_DENOM,
|
|
296872
296971
|
balanceBase: async (who, denom) => Number((await balancesOfStrict2(who))[denom] ?? 0),
|
|
296873
296972
|
face: (base6) => pays(base6, coinSymbol),
|
|
296874
|
-
feeFace:
|
|
296973
|
+
feeFace: feeWords2,
|
|
296875
296974
|
coinFixed: Boolean(checker.fee),
|
|
296876
296975
|
site: SITE
|
|
296877
296976
|
});
|
|
@@ -297133,7 +297232,7 @@ ${allowLine(SITE, posted.id, approver, acting?.principal ?? null)}` : `Every rep
|
|
|
297133
297232
|
const answer = await invitesModule.myInvitations(SITE, signer3);
|
|
297134
297233
|
if ("refused" in answer) return text4(`Refused: ${answer.refused}`);
|
|
297135
297234
|
const missed = answer.missed ? `Not shown: ${answer.missed}.` : "";
|
|
297136
|
-
if (answer.invited.length === 0) return text4([`Nothing yet: no poster has put this key${signer3.principal && signer3.principal !== signer3.address ? ", or the person it acts for," : ""} on a list. A person's own invitations are also on the site, signed in: ${EXPERT_SITE}/
|
|
297235
|
+
if (answer.invited.length === 0) return text4([`Nothing yet: no poster has put this key${signer3.principal && signer3.principal !== signer3.address ? ", or the person it acts for," : ""} on a list. A person's own invitations are also on the site, signed in: ${EXPERT_SITE}/me/work for pro asks, ${SITE}/opencall for other calls.`, missed].filter(Boolean).join("\n"));
|
|
297137
297236
|
const rooms = await roomsModule.myRooms(SITE, signer3).catch(() => ({ refused: "unreachable" }));
|
|
297138
297237
|
const roomOf = "refused" in rooms ? null : new Map(rooms.rooms.filter((one) => one.role === "pro").map((one) => [one.collectionId, one]));
|
|
297139
297238
|
const me = roomsModule.actorOf(signer3);
|
|
@@ -297141,7 +297240,7 @@ ${allowLine(SITE, posted.id, approver, acting?.principal ?? null)}` : `Every rep
|
|
|
297141
297240
|
[
|
|
297142
297241
|
"Invited to:",
|
|
297143
297242
|
...answer.invited.flatMap((one) => [
|
|
297144
|
-
` #${one.collectionId}${one.title ? ` \xB7 ${one.title}` : ""}${one.answer ? ` \xB7 ${invitesModule.answerLine(one)}` : ""}${one.campaign?.startsWith("call-") ? ` \xB7 ${isReviewTitle(one.title) ? `${EXPERT_SITE}/
|
|
297243
|
+
` #${one.collectionId}${one.title ? ` \xB7 ${one.title}` : ""}${one.answer ? ` \xB7 ${invitesModule.answerLine(one)}` : ""}${one.campaign?.startsWith("call-") ? ` \xB7 ${isReviewTitle(one.title) ? `${EXPERT_SITE}/me/work/${one.collectionId}` : askPage(SITE, one.collectionId, { campaign: one.campaign, title: one.title })}` : ""} \xB7 ${one.answer === "sent" ? `accept_invitation "${one.collectionId}" or decline_invitation` : `read_ask "${one.collectionId}"`}`,
|
|
297145
297244
|
...one.note ? [` The poster's note to you: ${asData("invitation-note", one.note)}`] : [],
|
|
297146
297245
|
...roomOf ? [roomsModule.invitationRoomLine(one, roomOf.get(one.collectionId) ?? null, { site: SITE, me })].filter((line2) => Boolean(line2)) : []
|
|
297147
297246
|
]),
|
|
@@ -297155,12 +297254,78 @@ ${allowLine(SITE, posted.id, approver, acting?.principal ?? null)}` : `Every rep
|
|
|
297155
297254
|
const peeked = await invitesModule.peekInvitation(SITE, which.token).catch(() => null);
|
|
297156
297255
|
return peeked ? `pro ask #${peeked.collectionId}${peeked.title ? ` (${peeked.title.replace(/^Expert review:\s*/, "")})` : ""}` : "the pro ask this link names";
|
|
297157
297256
|
};
|
|
297257
|
+
if (offered("my_pro_asks")) server2.registerTool("my_pro_asks", { ...meta3("my_pro_asks"), inputSchema: {} }, async () => {
|
|
297258
|
+
const [invitesModule, proAsksModule] = await Promise.all([Promise.resolve().then(() => (init_invites(), invites_exports)), Promise.resolve().then(() => (init_proAsks(), proAsks_exports))]);
|
|
297259
|
+
const signer3 = await inviteSigner(await principal2());
|
|
297260
|
+
const answer = await invitesModule.myCalls(SITE, signer3);
|
|
297261
|
+
if ("refused" in answer) return text4(`Refused: ${answer.refused}`);
|
|
297262
|
+
const missed = answer.missed ? `Not shown: ${answer.missed}.` : "";
|
|
297263
|
+
const asks = proAsksModule.proAsksOf(answer.calls);
|
|
297264
|
+
if (asks.length === 0) return text4([`No pro asks yet${signer3.principal && signer3.principal !== signer3.address ? " from this key or the person it acts for" : ""}. draft_call with kind "review" sets one up.`, missed].filter(Boolean).join("\n"));
|
|
297265
|
+
const owners = [...new Set(asks.map((one) => one.owner ?? signer3.address))];
|
|
297266
|
+
const [held, waiting] = await Promise.all([
|
|
297267
|
+
(async () => {
|
|
297268
|
+
const { asksHolding: asksHolding2 } = await Promise.resolve().then(() => (init_onAsks(), onAsks_exports));
|
|
297269
|
+
const { graphqlUrl: graphqlUrl4, restUrl: restUrl2 } = await Promise.resolve().then(() => (init_env(), env_exports));
|
|
297270
|
+
const lists = await Promise.all(owners.map((who) => asksHolding2(who, { graphqlUrl: graphqlUrl4(), restUrl: restUrl2() })));
|
|
297271
|
+
return new Map(lists.flat().map((one) => [one.collectionId, pays(one.held, "upay")]));
|
|
297272
|
+
})().catch(() => null),
|
|
297273
|
+
Promise.all(owners.map((who) => fetch2(`${SITE}/api/waiting?address=${encodeURIComponent(who)}`, { signal: AbortSignal.timeout(2e4) }).then((r) => r.ok ? r.json() : null))).then((answers) => answers.flatMap((one) => one?.waiting ?? [])).catch(() => null)
|
|
297274
|
+
]);
|
|
297275
|
+
return text4([`Pro asks (${asks.length}):`, ...proAsksModule.proAskLines(EXPERT_SITE, asks, { held, waiting }), missed].filter(Boolean).join("\n"));
|
|
297276
|
+
});
|
|
297277
|
+
if (offered("approve_report")) server2.registerTool(
|
|
297278
|
+
"approve_report",
|
|
297279
|
+
{
|
|
297280
|
+
...meta3("approve_report"),
|
|
297281
|
+
inputSchema: {
|
|
297282
|
+
collectionId: external_exports.string().regex(/^\d+$/).describe("The pro ask's number (my_pro_asks shows it)."),
|
|
297283
|
+
claimId: external_exports.string().min(1).max(128).describe("The report's id: the claim my_pro_asks or the ask's page names."),
|
|
297284
|
+
confirm: external_exports.boolean().optional().describe("Leave out to see what approving pays and whose OK it is. true approves.")
|
|
297285
|
+
}
|
|
297286
|
+
},
|
|
297287
|
+
async ({ collectionId, claimId, confirm }) => {
|
|
297288
|
+
const proAsksModule = await Promise.resolve().then(() => (init_proAsks(), proAsks_exports));
|
|
297289
|
+
const mine = await address2();
|
|
297290
|
+
const acting = await principal2();
|
|
297291
|
+
const who = acting?.principal ?? mine;
|
|
297292
|
+
const queue = await fetch2(`${SITE}/api/waiting?address=${encodeURIComponent(who)}`, { signal: AbortSignal.timeout(2e4) }).then((r) => r.ok ? r.json() : null).catch(() => null);
|
|
297293
|
+
if (!queue || queue.unavailable) return text4("Refused: the reports waiting for an OK could not be read just now. Nothing was sent; try again in a minute.");
|
|
297294
|
+
const item = (queue.waiting ?? []).find((one) => one.collectionId === collectionId && one.claimId === claimId);
|
|
297295
|
+
if (!item) return text4(`Nothing to approve: report ${claimId} on pro ask #${collectionId} is not waiting for ${who === mine ? "this key's" : `${who}'s`} OK. It may be approved already, still being checked, or another account's to approve. The report: ${proAsksModule.reportPage(EXPERT_SITE, collectionId, claimId)}`);
|
|
297296
|
+
const approver = item.approver ?? who;
|
|
297297
|
+
const canSign = approver === mine;
|
|
297298
|
+
const paid = item.pays ? face(item.pays.value, item.pays.symbol) : null;
|
|
297299
|
+
const facts = { collectionId, claimId, pro: item.agentAddress, pays: paid, approver, canSign };
|
|
297300
|
+
if (!confirm || !canSign) return text4(proAsksModule.approvePreview(EXPERT_SITE, facts));
|
|
297301
|
+
const ask = await readJson3(`${SITE}/api/oracle/${encodeURIComponent(collectionId)}`).catch(() => null);
|
|
297302
|
+
if (!ask?.oracle?.url) return text4("Refused: the verifier for this pro ask could not be reached. Nothing was sent; try again in a minute.");
|
|
297303
|
+
const review = await Promise.resolve().then(() => (init_personReview(), personReview_exports));
|
|
297304
|
+
const key = { address: mine, mnemonic: (await loadKey2()).mnemonic };
|
|
297305
|
+
const held = await review.readHeldClaim(ask.oracle.url, key, claimId);
|
|
297306
|
+
if (!held?.decision || held.decision.status !== "pending_review") return text4(`Nothing to approve: the verifier has no decision waiting on report ${claimId}${held?.decision?.status ? ` (it is ${held.decision.status.replace(/_/g, " ")})` : ""}. Nothing was sent.`);
|
|
297307
|
+
const protocol = item.protocol ?? ask.protocol ?? null;
|
|
297308
|
+
const { engineUrl: engineUrl2 } = await Promise.resolve().then(() => (init_engineUrl(), engineUrl_exports));
|
|
297309
|
+
const questions = protocol && engineUrl2() ? await review.reviewQuestions(engineUrl2(), protocol, held.decision.pendingTasks).catch(() => null) : null;
|
|
297310
|
+
if (questions?.some((one) => one.answer.type !== "boolean")) return text4(`Not approved: this report has a question that is not a yes or no, so its OK is given on the report's page: ${proAsksModule.reportPage(EXPERT_SITE, collectionId, claimId)}#decide. Nothing was sent.`);
|
|
297311
|
+
const answers = Object.fromEntries(held.decision.pendingTasks.map((task) => [task, true]));
|
|
297312
|
+
const receipt = await askReceipt(collectionId);
|
|
297313
|
+
if (receipt?.owner === mine) {
|
|
297314
|
+
const ends = ask.endsAt ? Math.floor(Date.parse(ask.endsAt) / 1e3) : null;
|
|
297315
|
+
await review.ensureReviewing({ owner: key, oracleUrl: ask.oracle.url, collectionId, reviewer: mine, endsAt: Number.isFinite(ends) ? ends : null }).catch(() => null);
|
|
297316
|
+
}
|
|
297317
|
+
const sent = await review.sendReview({ reviewer: key, oracleUrl: ask.oracle.url, collectionId, claimId, answers });
|
|
297318
|
+
if (!sent.ok) return text4(`Not approved: ${sent.why}${sent.detail ? ` (${sent.detail})` : ""}. Nothing was paid.`);
|
|
297319
|
+
return text4(`Approved report ${claimId} on pro ask #${collectionId}. The verifier records the OK and pays ${item.agentAddress}${paid ? ` ${paid}` : ""} on the ledger in a minute or two.
|
|
297320
|
+
The report: ${proAsksModule.reportPage(EXPERT_SITE, collectionId, claimId)}`);
|
|
297321
|
+
}
|
|
297322
|
+
);
|
|
297158
297323
|
if (offered("accept_invitation")) server2.registerTool(
|
|
297159
297324
|
"accept_invitation",
|
|
297160
297325
|
{
|
|
297161
297326
|
...meta3("accept_invitation"),
|
|
297162
297327
|
inputSchema: {
|
|
297163
|
-
invitation: external_exports.string().min(1).max(512).describe("The invitation: its link (\u2026/
|
|
297328
|
+
invitation: external_exports.string().min(1).max(512).describe("The invitation: its link (\u2026/i/\u2026), or the pro ask's number (my_invitations shows it)."),
|
|
297164
297329
|
confirm: external_exports.boolean().optional().describe("false (the default) previews; true accepts, once the person has said yes.")
|
|
297165
297330
|
}
|
|
297166
297331
|
},
|
|
@@ -297184,7 +297349,7 @@ ${allowLine(SITE, posted.id, approver, acting?.principal ?? null)}` : `Every rep
|
|
|
297184
297349
|
return text4(
|
|
297185
297350
|
[
|
|
297186
297351
|
done.state === "already" ? `Already accepted #${id}.` : `Accepted #${id}${acting ? ` as ${acting.principal}` : ""}. The builder knows.`,
|
|
297187
|
-
`Your job page: ${EXPERT_SITE}/
|
|
297352
|
+
`Your job page: ${EXPERT_SITE}/me/work/${id}`,
|
|
297188
297353
|
`Next: read_ask "${id}" for the brief, read_messages collectionId "${id}" for the builder's note, then submit_work when the person says so.`
|
|
297189
297354
|
].join("\n")
|
|
297190
297355
|
);
|
|
@@ -297195,7 +297360,7 @@ ${allowLine(SITE, posted.id, approver, acting?.principal ?? null)}` : `Every rep
|
|
|
297195
297360
|
{
|
|
297196
297361
|
...meta3("decline_invitation"),
|
|
297197
297362
|
inputSchema: {
|
|
297198
|
-
invitation: external_exports.string().min(1).max(512).describe("The invitation: its link (\u2026/
|
|
297363
|
+
invitation: external_exports.string().min(1).max(512).describe("The invitation: its link (\u2026/i/\u2026), or the pro ask's number (my_invitations shows it)."),
|
|
297199
297364
|
note: external_exports.string().max(200).optional().describe("A line for the builder, in the person's words: only they read it. Optional."),
|
|
297200
297365
|
confirm: external_exports.boolean().optional().describe("false (the default) previews; true declines, once the person has said yes.")
|
|
297201
297366
|
}
|
|
@@ -297287,7 +297452,7 @@ The room's page: ${roomPage(SITE, collectionId, page?.profile.handle ?? sent.pro
|
|
|
297287
297452
|
const pageInput = external_exports.object({
|
|
297288
297453
|
verificationServices: external_exports.array(verificationServiceSchema).max(6).optional(),
|
|
297289
297454
|
verificationCredentials: external_exports.array(credentialReferenceSchema).max(12).optional(),
|
|
297290
|
-
handle: external_exports.string().max(30).describe("Lowercase letters, digits and dashes, 3 to 30, starting with a letter. The page's address: /
|
|
297455
|
+
handle: external_exports.string().max(30).describe("Lowercase letters, digits and dashes, 3 to 30, starting with a letter. The page's address: /pros/<handle>."),
|
|
297291
297456
|
name: external_exports.string().max(80),
|
|
297292
297457
|
headline: external_exports.string().max(160).optional().describe("One line: what they do, in their words."),
|
|
297293
297458
|
about: external_exports.string().max(2e3).optional().describe("The summary, a few sentences in their words."),
|
|
@@ -297391,12 +297556,12 @@ No private link was made: ${link5.refused}.`;
|
|
|
297391
297556
|
const page = await invitesModule.readMyPage(SITE, await inviteSigner(acting));
|
|
297392
297557
|
if (!page) return text4("No pro page yet. Next: connect_linkedin (about a minute).");
|
|
297393
297558
|
return text4(`${invitesModule.pageWords(page, SITE)}
|
|
297394
|
-
${page.profile.listed === false ? `Your page is private. Preview it at ${EXPERT_SITE}/
|
|
297559
|
+
${page.profile.listed === false ? `Your page is private. Preview it at ${EXPERT_SITE}/me/page/preview (only you can see it), or ask me for your private link.
|
|
297395
297560
|
` : ""}${page.shared ? 'Private link: there is one (it is shown only when made; set_my_page with share_link: "replace" gives a new one and switches the old one off).' : 'Private link: none (set_my_page with share_link: "create" makes one).'}
|
|
297396
297561
|
|
|
297397
297562
|
${page.linkedin?.credentialUrl || page.linkedin?.credential ? `${credentialWords(page.linkedin, page.profile.listed !== false)}
|
|
297398
297563
|
|
|
297399
|
-
` : ""}Edit the profile at ${EXPERT_SITE}/
|
|
297564
|
+
` : ""}Edit the profile at ${EXPERT_SITE}/me/page/edit.${page.linkedin ? "" : " Next: connect_linkedin verifies it, so you can be invited to pro asks."}`);
|
|
297400
297565
|
});
|
|
297401
297566
|
if (offered("find_pro")) server2.registerTool(
|
|
297402
297567
|
"find_pro",
|
|
@@ -297426,7 +297591,7 @@ ${page.linkedin?.credentialUrl || page.linkedin?.credential ? `${credentialWords
|
|
|
297426
297591
|
return text4(pros.prosWords(found, { site: SITE, q, available }));
|
|
297427
297592
|
}
|
|
297428
297593
|
);
|
|
297429
|
-
const credentialWords = (linkedin, listed) => linkedin?.credentialUrl && listed ? `You also have a LinkedIn credential: it shows you logged in to this LinkedIn account, and any app can check it. Its public link: ${linkedin.credentialUrl}. Download it at ${EXPERT_SITE}/
|
|
297594
|
+
const credentialWords = (linkedin, listed) => linkedin?.credentialUrl && listed ? `You also have a LinkedIn credential: it shows you logged in to this LinkedIn account, and any app can check it. Its public link: ${linkedin.credentialUrl}. Download it at ${EXPERT_SITE}/me/page/edit.` : `You also have a LinkedIn credential: it shows you logged in to this LinkedIn account, and any app can check it. ${listed && !linkedin?.credential && !linkedin?.credentialUrl ? "It appears on your page once the page is published." : "Only you can see it while your page is private; it goes public when the page does."} Download it at ${EXPERT_SITE}/me/page/edit.`;
|
|
297430
297595
|
if (offered("connect_linkedin")) server2.registerTool(
|
|
297431
297596
|
"connect_linkedin",
|
|
297432
297597
|
{
|
|
@@ -297475,7 +297640,7 @@ ${asData("linkedin", JSON.stringify(prefill, null, 2))}`
|
|
|
297475
297640
|
const owner = acting?.principal ?? await address2();
|
|
297476
297641
|
const page = await invitesModule.readMyPage(SITE, await inviteSigner(acting));
|
|
297477
297642
|
if (!page) return text4(`${owner} has no page. Nothing to remove.`);
|
|
297478
|
-
const where2 = `${SITE.replace(/\/+$/, "")}/
|
|
297643
|
+
const where2 = `${SITE.replace(/\/+$/, "")}/pros/${page.profile.handle}`;
|
|
297479
297644
|
if (!confirm)
|
|
297480
297645
|
return text4(
|
|
297481
297646
|
[
|
|
@@ -297516,15 +297681,15 @@ ${asData("linkedin", JSON.stringify(prefill, null, 2))}`
|
|
|
297516
297681
|
}
|
|
297517
297682
|
};
|
|
297518
297683
|
let PLANS = DEPLOYMENT.plans;
|
|
297519
|
-
function applyDeployment(
|
|
297520
|
-
ASK_DENOM =
|
|
297684
|
+
function applyDeployment(fresh3) {
|
|
297685
|
+
ASK_DENOM = fresh3.askDenom;
|
|
297521
297686
|
ASK_SYMBOL = symbolOf(ASK_DENOM);
|
|
297522
|
-
CHECKER =
|
|
297523
|
-
GATE =
|
|
297524
|
-
CHECK_REWARD =
|
|
297525
|
-
ENGINE_ORACLE =
|
|
297526
|
-
ENGINE_MODE =
|
|
297527
|
-
PLANS =
|
|
297687
|
+
CHECKER = fresh3.checker;
|
|
297688
|
+
GATE = fresh3.gate;
|
|
297689
|
+
CHECK_REWARD = fresh3.checkRewardBase;
|
|
297690
|
+
ENGINE_ORACLE = fresh3.engine.oracle;
|
|
297691
|
+
ENGINE_MODE = fresh3.engine.live;
|
|
297692
|
+
PLANS = fresh3.plans;
|
|
297528
297693
|
}
|
|
297529
297694
|
const MAX_PER_PLAN = CAPS.perPlan;
|
|
297530
297695
|
const PLAN_CAPS = { perAsk: MAX_PER_ASK, perPlan: MAX_PER_PLAN, perDayTotal: MAX_PER_DAY_TOTAL };
|
|
@@ -297535,8 +297700,8 @@ ${asData("linkedin", JSON.stringify(prefill, null, 2))}`
|
|
|
297535
297700
|
return { cost: planCost2(plan, { reviewUsd: sameCoin ? world.leg / MICRO6 : 0, feeRate: 0 }), reviewsBase: sameCoin ? 0 : world.leg * planAnswerCount2(plan) };
|
|
297536
297701
|
}
|
|
297537
297702
|
async function reviewWords(world, reviewsBase) {
|
|
297538
|
-
if (world.perCheck) return `Review fee: ${(await Promise.resolve().then(() => (init_reviewBilling(), reviewBilling_exports))).creditsCopy(null,
|
|
297539
|
-
return reviewsBase > 0 ? `Reviews: ${
|
|
297703
|
+
if (world.perCheck) return `Review fee: ${(await Promise.resolve().then(() => (init_reviewBilling(), reviewBilling_exports))).creditsCopy(null, feeWords2(world.perCheck.price))}`;
|
|
297704
|
+
return reviewsBase > 0 ? `Reviews: ${feeWords2(reviewsBase)} on top, ${feeWords2(world.leg)} for each answer, escrowed beside the rewards.` : "";
|
|
297540
297705
|
}
|
|
297541
297706
|
const UNPRICED = "The verifier could not be priced just now, so no plan can be bought. Try again shortly. Nothing was posted.";
|
|
297542
297707
|
async function registerPlan(cid, poster) {
|
|
@@ -297734,7 +297899,7 @@ ${asData("linkedin", JSON.stringify(prefill, null, 2))}`
|
|
|
297734
297899
|
}
|
|
297735
297900
|
if (confirm.trim() !== money3(cost.totalUsd)) return text4(`Refused: confirm said "${confirm}" but the total is ${money3(cost.totalUsd)}. Preview it again.`);
|
|
297736
297901
|
if (!resuming) {
|
|
297737
|
-
if (acting && reviewsBase > 0) return text4(`Refused: this plan's reviews escrow ${
|
|
297902
|
+
if (acting && reviewsBase > 0) return text4(`Refused: this plan's reviews escrow ${feeWords2(reviewsBase)} beside its ${coinSymbol} rewards, and ${acting.principal}'s allowance covers ${coinSymbol} only. Use a verifier that bills per check (Pay for reviews), or post from this key. Nothing was posted.`);
|
|
297738
297903
|
const otherCoin = (await Promise.resolve().then(() => (init_hq(), hq_exports))).capCoinRefusal(acting, coin);
|
|
297739
297904
|
if (otherCoin) return text4(`Refused: ${otherCoin}. Draft the plan again with draft_plan in that coin. Nothing was posted.`);
|
|
297740
297905
|
if (acting) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ixo/asks-mcp",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.4",
|
|
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": {
|