@countersign-hub/cli 0.1.0 → 0.1.2
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/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/bin.js +1078 -129
- package/dist/child-entry.js +3 -1
- package/package.json +22 -2
package/dist/bin.js
CHANGED
|
@@ -20231,6 +20231,7 @@ var init__esm = __esm(() => {
|
|
|
20231
20231
|
init_createPublicClient();
|
|
20232
20232
|
init_createWalletClient();
|
|
20233
20233
|
init_http3();
|
|
20234
|
+
init_abis();
|
|
20234
20235
|
init_base();
|
|
20235
20236
|
init_contract();
|
|
20236
20237
|
init_decodeFunctionResult();
|
|
@@ -20247,6 +20248,7 @@ var init__esm = __esm(() => {
|
|
|
20247
20248
|
init_parseSignature();
|
|
20248
20249
|
init_recoverMessageAddress();
|
|
20249
20250
|
init_recoverTypedDataAddress();
|
|
20251
|
+
init_formatUnits();
|
|
20250
20252
|
});
|
|
20251
20253
|
|
|
20252
20254
|
// packages/core/src/canonical.ts
|
|
@@ -30237,7 +30239,9 @@ var init_known_escrows = __esm(() => {
|
|
|
30237
30239
|
KNOWN_ESCROWS = [
|
|
30238
30240
|
{ chainId: 5042002, escrow: "0x19c27d770969291e6a0a305dc1be1a845e7c1b76", name: "Arc testnet, deployed through Arc Studio" },
|
|
30239
30241
|
{ chainId: 5042002, escrow: "0x44d11b8909485e3f575F6628b689383E4420f54a", name: "Arc testnet, forge deployment" },
|
|
30240
|
-
{ chainId:
|
|
30242
|
+
{ chainId: 5042002, escrow: "0x10A3c07cc6A519C0106e315D2C42010eCbEFF3CE", name: "Arc testnet, escrow v2" },
|
|
30243
|
+
{ chainId: 1874, escrow: "0x9279D3edeef4c3738a0b200D762e2985Ff3B7eb4", name: "Whitechain Sepolia" },
|
|
30244
|
+
{ chainId: 1874, escrow: "0x55b3d98C17Ba0878DC93fB1521c76c9a10778391", name: "Whitechain Sepolia, escrow v2" }
|
|
30241
30245
|
];
|
|
30242
30246
|
});
|
|
30243
30247
|
|
|
@@ -30698,6 +30702,7 @@ var init_privateKeyToAccount = __esm(() => {
|
|
|
30698
30702
|
// node_modules/viem/_esm/accounts/index.js
|
|
30699
30703
|
var init_accounts = __esm(() => {
|
|
30700
30704
|
init_privateKeyToAccount();
|
|
30705
|
+
init_toAccount();
|
|
30701
30706
|
});
|
|
30702
30707
|
|
|
30703
30708
|
// node_modules/zod/v3/helpers/util.js
|
|
@@ -59072,6 +59077,28 @@ var init_known_rails = __esm(() => {
|
|
|
59072
59077
|
tokenName: "Tether USD",
|
|
59073
59078
|
tokenVersion: "1",
|
|
59074
59079
|
rpcUrl: "https://rpc.testnet.whitechain.io"
|
|
59080
|
+
},
|
|
59081
|
+
{
|
|
59082
|
+
network: "eip155:5042002",
|
|
59083
|
+
scheme: "countersign",
|
|
59084
|
+
chainId: 5042002,
|
|
59085
|
+
escrow: "0x10A3c07cc6A519C0106e315D2C42010eCbEFF3CE",
|
|
59086
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
59087
|
+
tokenName: "USDC",
|
|
59088
|
+
tokenVersion: "2",
|
|
59089
|
+
rpcUrl: "https://rpc.testnet.arc.network",
|
|
59090
|
+
version: 2
|
|
59091
|
+
},
|
|
59092
|
+
{
|
|
59093
|
+
network: "eip155:1874",
|
|
59094
|
+
scheme: "countersign",
|
|
59095
|
+
chainId: 1874,
|
|
59096
|
+
escrow: "0x55b3d98C17Ba0878DC93fB1521c76c9a10778391",
|
|
59097
|
+
token: "0xcedfB56113143d55b2358b8CFbB0dEB5Ad2f55a7",
|
|
59098
|
+
tokenName: "Tether USD",
|
|
59099
|
+
tokenVersion: "1",
|
|
59100
|
+
rpcUrl: "https://rpc.testnet.whitechain.io",
|
|
59101
|
+
version: 2
|
|
59075
59102
|
}
|
|
59076
59103
|
];
|
|
59077
59104
|
KNOWN_DIRECTS = [
|
|
@@ -59642,7 +59669,7 @@ var init_hub_client = __esm(() => {
|
|
|
59642
59669
|
});
|
|
59643
59670
|
|
|
59644
59671
|
// packages/buyer/src/journal.ts
|
|
59645
|
-
import { appendFileSync, closeSync, existsSync as
|
|
59672
|
+
import { appendFileSync, closeSync as closeSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, openSync as openSync2, readFileSync as readFileSync5, unlinkSync, writeSync as writeSync2 } from "node:fs";
|
|
59646
59673
|
import { dirname as dirname2 } from "node:path";
|
|
59647
59674
|
|
|
59648
59675
|
class Journal {
|
|
@@ -59654,14 +59681,14 @@ class Journal {
|
|
|
59654
59681
|
return `${this.path}.lock`;
|
|
59655
59682
|
}
|
|
59656
59683
|
append(entry) {
|
|
59657
|
-
|
|
59684
|
+
mkdirSync3(dirname2(this.path), { recursive: true });
|
|
59658
59685
|
appendFileSync(this.path, `${JSON.stringify(entry)}
|
|
59659
59686
|
`);
|
|
59660
59687
|
}
|
|
59661
59688
|
entries() {
|
|
59662
|
-
if (!
|
|
59689
|
+
if (!existsSync4(this.path))
|
|
59663
59690
|
return [];
|
|
59664
|
-
return
|
|
59691
|
+
return readFileSync5(this.path, "utf8").split(`
|
|
59665
59692
|
`).filter((l) => l.trim() !== "").map((l) => JSON.parse(l));
|
|
59666
59693
|
}
|
|
59667
59694
|
reserve(entry, decide) {
|
|
@@ -59672,19 +59699,19 @@ class Journal {
|
|
|
59672
59699
|
this.append({ ...entry, kind: "countersigned" });
|
|
59673
59700
|
return decision;
|
|
59674
59701
|
} finally {
|
|
59675
|
-
|
|
59702
|
+
closeSync2(fd);
|
|
59676
59703
|
try {
|
|
59677
59704
|
unlinkSync(this.lockPath);
|
|
59678
59705
|
} catch {}
|
|
59679
59706
|
}
|
|
59680
59707
|
}
|
|
59681
59708
|
acquire() {
|
|
59682
|
-
|
|
59709
|
+
mkdirSync3(dirname2(this.path), { recursive: true });
|
|
59683
59710
|
const deadline = Date.now() + 5000;
|
|
59684
59711
|
for (;; ) {
|
|
59685
59712
|
try {
|
|
59686
|
-
const fd =
|
|
59687
|
-
|
|
59713
|
+
const fd = openSync2(this.lockPath, "wx");
|
|
59714
|
+
writeSync2(fd, String(process.pid));
|
|
59688
59715
|
return fd;
|
|
59689
59716
|
} catch (e) {
|
|
59690
59717
|
if (e.code !== "EEXIST")
|
|
@@ -59704,7 +59731,7 @@ class Journal {
|
|
|
59704
59731
|
ownerIsGone() {
|
|
59705
59732
|
let pid;
|
|
59706
59733
|
try {
|
|
59707
|
-
pid = Number(
|
|
59734
|
+
pid = Number(readFileSync5(this.lockPath, "utf8").trim());
|
|
59708
59735
|
} catch {
|
|
59709
59736
|
return false;
|
|
59710
59737
|
}
|
|
@@ -61269,6 +61296,175 @@ var init_payer2 = __esm(() => {
|
|
|
61269
61296
|
init_known_rails();
|
|
61270
61297
|
});
|
|
61271
61298
|
|
|
61299
|
+
// packages/buyer/src/price-label.ts
|
|
61300
|
+
function railToken(rail2) {
|
|
61301
|
+
return RAIL_TOKENS[rail2] ?? "USDC";
|
|
61302
|
+
}
|
|
61303
|
+
function priceLabel(price, rails) {
|
|
61304
|
+
const tokens = [...new Set(rails.map(railToken))];
|
|
61305
|
+
return `${formatUnits3(BigInt(price), 6)} ${(tokens.length > 0 ? tokens : ["USDC"]).join("/")}`;
|
|
61306
|
+
}
|
|
61307
|
+
var RAIL_TOKENS;
|
|
61308
|
+
var init_price_label = __esm(() => {
|
|
61309
|
+
init__esm();
|
|
61310
|
+
RAIL_TOKENS = { whitechain: "USDT" };
|
|
61311
|
+
});
|
|
61312
|
+
|
|
61313
|
+
// packages/buyer/src/remote-signer.ts
|
|
61314
|
+
function assertHubOrigin(hub) {
|
|
61315
|
+
let url2;
|
|
61316
|
+
try {
|
|
61317
|
+
url2 = new URL(hub);
|
|
61318
|
+
} catch {
|
|
61319
|
+
throw new Error(HTTPS_ONLY);
|
|
61320
|
+
}
|
|
61321
|
+
if (url2.protocol === "https:")
|
|
61322
|
+
return;
|
|
61323
|
+
if (url2.protocol === "http:" && LOCAL_HOSTS.has(url2.hostname))
|
|
61324
|
+
return;
|
|
61325
|
+
throw new Error(HTTPS_ONLY);
|
|
61326
|
+
}
|
|
61327
|
+
function decimalStrings(value) {
|
|
61328
|
+
if (typeof value === "bigint")
|
|
61329
|
+
return value.toString(10);
|
|
61330
|
+
if (Array.isArray(value))
|
|
61331
|
+
return value.map((entry) => decimalStrings(entry));
|
|
61332
|
+
if (value !== null && typeof value === "object") {
|
|
61333
|
+
const copy = {};
|
|
61334
|
+
for (const [key, entry] of Object.entries(value))
|
|
61335
|
+
copy[key] = decimalStrings(entry);
|
|
61336
|
+
return copy;
|
|
61337
|
+
}
|
|
61338
|
+
return value;
|
|
61339
|
+
}
|
|
61340
|
+
function messageOf4(body) {
|
|
61341
|
+
if (body === null || typeof body !== "object")
|
|
61342
|
+
return;
|
|
61343
|
+
const message = body.message;
|
|
61344
|
+
return typeof message === "string" ? message : undefined;
|
|
61345
|
+
}
|
|
61346
|
+
function remoteAccount(session, opts = {}) {
|
|
61347
|
+
assertHubOrigin(session.hub);
|
|
61348
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
61349
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
61350
|
+
const signTypedData4 = async (parameters) => {
|
|
61351
|
+
const typedData = parameters;
|
|
61352
|
+
const types3 = {};
|
|
61353
|
+
for (const [name, fields] of Object.entries(typedData.types)) {
|
|
61354
|
+
if (name !== "EIP712Domain")
|
|
61355
|
+
types3[name] = fields;
|
|
61356
|
+
}
|
|
61357
|
+
const requestBody = JSON.stringify({
|
|
61358
|
+
kind: "typed-data",
|
|
61359
|
+
typedData: {
|
|
61360
|
+
domain: decimalStrings(typedData.domain),
|
|
61361
|
+
types: decimalStrings(types3),
|
|
61362
|
+
primaryType: typedData.primaryType,
|
|
61363
|
+
message: decimalStrings(typedData.message)
|
|
61364
|
+
}
|
|
61365
|
+
});
|
|
61366
|
+
const controller = new AbortController;
|
|
61367
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
61368
|
+
let status;
|
|
61369
|
+
let body;
|
|
61370
|
+
try {
|
|
61371
|
+
const response = await fetchImpl(`${session.hub.replace(/\/+$/, "")}/cli/sign`, {
|
|
61372
|
+
method: "POST",
|
|
61373
|
+
headers: {
|
|
61374
|
+
authorization: `Bearer ${session.token}`,
|
|
61375
|
+
"content-type": "application/json"
|
|
61376
|
+
},
|
|
61377
|
+
body: requestBody,
|
|
61378
|
+
signal: controller.signal
|
|
61379
|
+
});
|
|
61380
|
+
status = response.status;
|
|
61381
|
+
body = await response.json().catch(() => {
|
|
61382
|
+
return;
|
|
61383
|
+
});
|
|
61384
|
+
} catch {
|
|
61385
|
+
throw new Error(NOT_REACHED);
|
|
61386
|
+
} finally {
|
|
61387
|
+
clearTimeout(timer);
|
|
61388
|
+
}
|
|
61389
|
+
if (status === 200) {
|
|
61390
|
+
const result = body;
|
|
61391
|
+
if (typeof result?.address !== "string" || result.address.toLowerCase() !== session.address.toLowerCase()) {
|
|
61392
|
+
throw new Error("The hub signed with another wallet.");
|
|
61393
|
+
}
|
|
61394
|
+
const signature = result.signature;
|
|
61395
|
+
if (typeof signature !== "string" || !SIGNATURE2.test(signature)) {
|
|
61396
|
+
throw new Error(`The hub could not sign (${status}).`);
|
|
61397
|
+
}
|
|
61398
|
+
const signer = await recoverTypedDataAddress2({
|
|
61399
|
+
...parameters,
|
|
61400
|
+
signature
|
|
61401
|
+
});
|
|
61402
|
+
if (signer.toLowerCase() !== session.address.toLowerCase()) {
|
|
61403
|
+
throw new Error("The hub signed with another wallet.");
|
|
61404
|
+
}
|
|
61405
|
+
return signature;
|
|
61406
|
+
}
|
|
61407
|
+
if (status === 401)
|
|
61408
|
+
throw new Error(NOT_SIGNED_IN3);
|
|
61409
|
+
if (status === 403) {
|
|
61410
|
+
const message = messageOf4(body) ?? "the hub refused the request.";
|
|
61411
|
+
throw new Error(`Refused by the hub: ${message}`);
|
|
61412
|
+
}
|
|
61413
|
+
if (status === 502)
|
|
61414
|
+
throw new Error("The hub could not sign (privy-failed).");
|
|
61415
|
+
throw new Error(`The hub could not sign (${status}).`);
|
|
61416
|
+
};
|
|
61417
|
+
const unsupported = async () => {
|
|
61418
|
+
throw new Error(TYPED_DATA_ONLY);
|
|
61419
|
+
};
|
|
61420
|
+
const source = {
|
|
61421
|
+
address: session.address,
|
|
61422
|
+
signMessage: unsupported,
|
|
61423
|
+
signTransaction: unsupported,
|
|
61424
|
+
signTypedData: signTypedData4
|
|
61425
|
+
};
|
|
61426
|
+
return toAccount(source);
|
|
61427
|
+
}
|
|
61428
|
+
async function sessionFromEnv(env = process.env, opts = {}) {
|
|
61429
|
+
const token = env.CS_SESSION;
|
|
61430
|
+
if (token === undefined || token === "")
|
|
61431
|
+
return;
|
|
61432
|
+
const hub = env.CS_HUB ?? DEFAULT_HUB;
|
|
61433
|
+
delete env.CS_SESSION;
|
|
61434
|
+
assertHubOrigin(hub);
|
|
61435
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
61436
|
+
let status;
|
|
61437
|
+
let body;
|
|
61438
|
+
try {
|
|
61439
|
+
const response = await fetchImpl(`${hub.replace(/\/+$/, "")}/cli/session`, {
|
|
61440
|
+
method: "GET",
|
|
61441
|
+
headers: { authorization: `Bearer ${token}` }
|
|
61442
|
+
});
|
|
61443
|
+
status = response.status;
|
|
61444
|
+
body = await response.json().catch(() => {
|
|
61445
|
+
return;
|
|
61446
|
+
});
|
|
61447
|
+
} catch {
|
|
61448
|
+
throw new Error("Could not read the countersign session (no response).");
|
|
61449
|
+
}
|
|
61450
|
+
if (status === 401)
|
|
61451
|
+
return;
|
|
61452
|
+
if (status !== 200)
|
|
61453
|
+
throw new Error(`Could not read the countersign session (${status}).`);
|
|
61454
|
+
const address = body?.address;
|
|
61455
|
+
if (typeof address !== "string" || !isAddress(address)) {
|
|
61456
|
+
throw new Error("The hub returned no valid wallet address.");
|
|
61457
|
+
}
|
|
61458
|
+
return { hub, token, address };
|
|
61459
|
+
}
|
|
61460
|
+
var NOT_SIGNED_IN3 = "Not signed in. Run: npx -y @countersign-hub/cli login", SIGNATURE2, DEFAULT_TIMEOUT_MS = 30000, DEFAULT_HUB = "https://hub-production-e85e.up.railway.app", NOT_REACHED = "The hub could not be reached to sign.", TYPED_DATA_ONLY = "This wallet signs only through the hub's typed-data route.", HTTPS_ONLY = "Refused: the countersign hub must be https.", LOCAL_HOSTS;
|
|
61461
|
+
var init_remote_signer = __esm(() => {
|
|
61462
|
+
init__esm();
|
|
61463
|
+
init_accounts();
|
|
61464
|
+
SIGNATURE2 = /^0x[0-9a-fA-F]{130}$/;
|
|
61465
|
+
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
61466
|
+
});
|
|
61467
|
+
|
|
61272
61468
|
// packages/buyer/src/resume.ts
|
|
61273
61469
|
async function readJobStatus(rail2, jobId) {
|
|
61274
61470
|
const client = createPublicClient({ transport: http(rail2.rpcUrl) });
|
|
@@ -61406,27 +61602,27 @@ async function acceptJob(a) {
|
|
|
61406
61602
|
const slip2 = heldSlip(a, jobId);
|
|
61407
61603
|
const known = a.known ?? KNOWN_RAILS;
|
|
61408
61604
|
if (slip2.hash.toLowerCase() !== slipHash(slip2.body).toLowerCase())
|
|
61409
|
-
|
|
61605
|
+
refuse2("The slip's hash does not match its body.");
|
|
61410
61606
|
let seller;
|
|
61411
61607
|
try {
|
|
61412
61608
|
seller = await slipSigner(slip2);
|
|
61413
61609
|
} catch {
|
|
61414
|
-
|
|
61610
|
+
refuse2("The slip's seller signature does not parse.");
|
|
61415
61611
|
}
|
|
61416
61612
|
if (getAddress(seller) !== getAddress(slip2.body.seller))
|
|
61417
|
-
|
|
61613
|
+
refuse2("The slip is not signed by its seller.");
|
|
61418
61614
|
if (slip2.body.jobId.toLowerCase() !== jobId)
|
|
61419
|
-
|
|
61615
|
+
refuse2("The slip is for another job.");
|
|
61420
61616
|
if (getAddress(slip2.body.buyer) !== getAddress(a.signer.address))
|
|
61421
|
-
|
|
61617
|
+
refuse2("The slip names another buyer.");
|
|
61422
61618
|
if (!slip2.body.escrow || slip2.body.chainId === undefined)
|
|
61423
|
-
|
|
61619
|
+
refuse2("The slip is not for an escrow job.");
|
|
61424
61620
|
const rail2 = pinned(known, slip2.body.chainId, slip2.body.escrow);
|
|
61425
61621
|
if (!rail2)
|
|
61426
|
-
|
|
61622
|
+
refuse2("The slip's escrow is not one this agent pins.");
|
|
61427
61623
|
const terms = slip2.payment?.payload?.terms;
|
|
61428
61624
|
if (!terms || jobIdOf(terms, rail2.chainId, rail2.escrow).toLowerCase() !== jobId) {
|
|
61429
|
-
|
|
61625
|
+
refuse2("The slip's countersigned terms do not derive this job on that escrow.");
|
|
61430
61626
|
}
|
|
61431
61627
|
const signature = await a.signer.signTypedData(acceptTypedData(rail2.chainId, rail2.escrow, jobId, slip2.hash));
|
|
61432
61628
|
await a.hub.acceptJob(jobId, signature);
|
|
@@ -61438,7 +61634,7 @@ async function disputeJob(a) {
|
|
|
61438
61634
|
const known = a.known ?? KNOWN_RAILS;
|
|
61439
61635
|
const entries = entriesFor(a.journal, jobId);
|
|
61440
61636
|
if (entries.length === 0)
|
|
61441
|
-
|
|
61637
|
+
refuse2("This agent's journal has no such job.");
|
|
61442
61638
|
const { rail: rail2, status } = await fundedOn(a, jobId, entries, known);
|
|
61443
61639
|
const signature = await a.signer.signTypedData(disputeTypedData(rail2.chainId, rail2.escrow, jobId, status));
|
|
61444
61640
|
let transaction;
|
|
@@ -61465,7 +61661,7 @@ async function disputeJob(a) {
|
|
|
61465
61661
|
async function submitDispute(a, rail2, jobId, status) {
|
|
61466
61662
|
const account = a.account;
|
|
61467
61663
|
if (!account)
|
|
61468
|
-
|
|
61664
|
+
refuse2("The agent key is not available to send the dispute itself.");
|
|
61469
61665
|
return sendDispute(rail2, jobId, status, account, a.transport);
|
|
61470
61666
|
}
|
|
61471
61667
|
async function sendDispute(rail2, jobId, status, account, transport) {
|
|
@@ -61497,7 +61693,7 @@ async function fundedOn(a, jobId, entries, known) {
|
|
|
61497
61693
|
if (recorded) {
|
|
61498
61694
|
const rail2 = pinned(known, recorded.chainId, recorded.escrow);
|
|
61499
61695
|
if (!rail2)
|
|
61500
|
-
|
|
61696
|
+
refuse2("The job's escrow is not one this agent pins.");
|
|
61501
61697
|
return { rail: rail2, status: await disputeStatus(a, rail2, jobId, entries) };
|
|
61502
61698
|
}
|
|
61503
61699
|
const network = entries.find((e) => e.network)?.network;
|
|
@@ -61513,7 +61709,7 @@ async function fundedOn(a, jobId, entries, known) {
|
|
|
61513
61709
|
} catch {}
|
|
61514
61710
|
}
|
|
61515
61711
|
if (holding.length !== 1)
|
|
61516
|
-
|
|
61712
|
+
refuse2("No single pinned escrow holds this job open for this agent.");
|
|
61517
61713
|
return holding[0];
|
|
61518
61714
|
}
|
|
61519
61715
|
async function disputeStatus(a, rail2, jobId, entries) {
|
|
@@ -61529,11 +61725,11 @@ async function disputeStatus(a, rail2, jobId, entries) {
|
|
|
61529
61725
|
function heldSlip(a, jobId) {
|
|
61530
61726
|
const entry = [...entriesFor(a.journal, jobId)].reverse().find((e) => e.slipHash);
|
|
61531
61727
|
if (!entry?.slipHash)
|
|
61532
|
-
|
|
61728
|
+
refuse2("This agent holds no slip for this job.");
|
|
61533
61729
|
try {
|
|
61534
61730
|
return a.state.loadSlip(entry.slipHash);
|
|
61535
61731
|
} catch {
|
|
61536
|
-
|
|
61732
|
+
refuse2("This agent holds no slip for this job.");
|
|
61537
61733
|
}
|
|
61538
61734
|
}
|
|
61539
61735
|
function entriesFor(journal, jobId) {
|
|
@@ -61554,7 +61750,7 @@ function record3(a, jobId, entries) {
|
|
|
61554
61750
|
function pinned(known, chainId, escrow2) {
|
|
61555
61751
|
return known.find((rail2) => rail2.chainId === chainId && rail2.escrow.toLowerCase() === escrow2.toLowerCase());
|
|
61556
61752
|
}
|
|
61557
|
-
function
|
|
61753
|
+
function refuse2(message) {
|
|
61558
61754
|
throw new ReviewError(`Refused. ${message}`);
|
|
61559
61755
|
}
|
|
61560
61756
|
var ReviewError, DISPUTE_ABI, DISPUTABLE;
|
|
@@ -61584,65 +61780,65 @@ var init_review = __esm(() => {
|
|
|
61584
61780
|
|
|
61585
61781
|
// packages/buyer/src/state.ts
|
|
61586
61782
|
import {
|
|
61587
|
-
chmodSync,
|
|
61588
|
-
closeSync as
|
|
61589
|
-
existsSync as
|
|
61590
|
-
mkdirSync as
|
|
61591
|
-
openSync as
|
|
61592
|
-
readFileSync as
|
|
61783
|
+
chmodSync as chmodSync2,
|
|
61784
|
+
closeSync as closeSync3,
|
|
61785
|
+
existsSync as existsSync5,
|
|
61786
|
+
mkdirSync as mkdirSync4,
|
|
61787
|
+
openSync as openSync3,
|
|
61788
|
+
readFileSync as readFileSync6,
|
|
61593
61789
|
unlinkSync as unlinkSync2,
|
|
61594
61790
|
writeFileSync as writeFileSync2,
|
|
61595
|
-
writeSync as
|
|
61791
|
+
writeSync as writeSync3
|
|
61596
61792
|
} from "node:fs";
|
|
61597
|
-
import { homedir as
|
|
61598
|
-
import { join as
|
|
61793
|
+
import { homedir as homedir3 } from "node:os";
|
|
61794
|
+
import { join as join4 } from "node:path";
|
|
61599
61795
|
|
|
61600
61796
|
class State {
|
|
61601
61797
|
dir;
|
|
61602
61798
|
constructor(dir) {
|
|
61603
|
-
this.dir = dir ??
|
|
61799
|
+
this.dir = dir ?? join4(homedir3(), ".countersign");
|
|
61604
61800
|
}
|
|
61605
61801
|
get envelopePath() {
|
|
61606
|
-
return
|
|
61802
|
+
return join4(this.dir, "envelope.json");
|
|
61607
61803
|
}
|
|
61608
61804
|
get journalPath() {
|
|
61609
|
-
return
|
|
61805
|
+
return join4(this.dir, "journal.jsonl");
|
|
61610
61806
|
}
|
|
61611
61807
|
get railsPath() {
|
|
61612
|
-
return
|
|
61808
|
+
return join4(this.dir, "rails.json");
|
|
61613
61809
|
}
|
|
61614
61810
|
get consumedApprovalsPath() {
|
|
61615
|
-
return
|
|
61811
|
+
return join4(this.dir, "approvals-consumed.json");
|
|
61616
61812
|
}
|
|
61617
61813
|
slipPath(hash4) {
|
|
61618
|
-
return
|
|
61814
|
+
return join4(this.dir, "slips", `${hash4}.json`);
|
|
61619
61815
|
}
|
|
61620
61816
|
loadEnvelope() {
|
|
61621
|
-
if (!
|
|
61817
|
+
if (!existsSync5(this.envelopePath)) {
|
|
61622
61818
|
throw new Error(`No envelope at ${this.envelopePath}. Create one with: countersign envelope set --cap <usd> --per-merchant <usd>`);
|
|
61623
61819
|
}
|
|
61624
|
-
return JSON.parse(
|
|
61820
|
+
return JSON.parse(readFileSync6(this.envelopePath, "utf8"));
|
|
61625
61821
|
}
|
|
61626
61822
|
saveEnvelope(env) {
|
|
61627
|
-
|
|
61823
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
61628
61824
|
writeFileSync2(this.envelopePath, `${JSON.stringify(env, null, 2)}
|
|
61629
61825
|
`);
|
|
61630
61826
|
}
|
|
61631
61827
|
loadRails() {
|
|
61632
|
-
if (!
|
|
61828
|
+
if (!existsSync5(this.railsPath))
|
|
61633
61829
|
return [];
|
|
61634
|
-
const value = JSON.parse(
|
|
61830
|
+
const value = JSON.parse(readFileSync6(this.railsPath, "utf8"));
|
|
61635
61831
|
if (!Array.isArray(value))
|
|
61636
61832
|
throw new Error(`${this.railsPath} must hold a JSON array of known rails.`);
|
|
61637
61833
|
return value;
|
|
61638
61834
|
}
|
|
61639
61835
|
loadSlip(hash4) {
|
|
61640
|
-
return JSON.parse(
|
|
61836
|
+
return JSON.parse(readFileSync6(this.slipPath(hash4), "utf8"));
|
|
61641
61837
|
}
|
|
61642
61838
|
loadConsumedApprovals() {
|
|
61643
|
-
if (!
|
|
61839
|
+
if (!existsSync5(this.consumedApprovalsPath))
|
|
61644
61840
|
return [];
|
|
61645
|
-
const value = JSON.parse(
|
|
61841
|
+
const value = JSON.parse(readFileSync6(this.consumedApprovalsPath, "utf8"));
|
|
61646
61842
|
if (!Array.isArray(value)) {
|
|
61647
61843
|
throw new Error(`${this.consumedApprovalsPath} must hold a JSON array of approval ids.`);
|
|
61648
61844
|
}
|
|
@@ -61660,10 +61856,10 @@ class State {
|
|
|
61660
61856
|
ids.push(id);
|
|
61661
61857
|
writeFileSync2(this.consumedApprovalsPath, `${JSON.stringify(ids, null, 2)}
|
|
61662
61858
|
`, { mode: 384 });
|
|
61663
|
-
|
|
61859
|
+
chmodSync2(this.consumedApprovalsPath, 384);
|
|
61664
61860
|
return true;
|
|
61665
61861
|
} finally {
|
|
61666
|
-
|
|
61862
|
+
closeSync3(fd);
|
|
61667
61863
|
try {
|
|
61668
61864
|
unlinkSync2(this.consumedLockPath);
|
|
61669
61865
|
} catch {}
|
|
@@ -61673,12 +61869,12 @@ class State {
|
|
|
61673
61869
|
return `${this.consumedApprovalsPath}.lock`;
|
|
61674
61870
|
}
|
|
61675
61871
|
acquireConsumedLock() {
|
|
61676
|
-
|
|
61872
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
61677
61873
|
const deadline = Date.now() + 5000;
|
|
61678
61874
|
for (;; ) {
|
|
61679
61875
|
try {
|
|
61680
|
-
const fd =
|
|
61681
|
-
|
|
61876
|
+
const fd = openSync3(this.consumedLockPath, "wx");
|
|
61877
|
+
writeSync3(fd, String(process.pid));
|
|
61682
61878
|
return fd;
|
|
61683
61879
|
} catch (e) {
|
|
61684
61880
|
if (e.code !== "EEXIST")
|
|
@@ -61699,7 +61895,7 @@ class State {
|
|
|
61699
61895
|
consumedLockOwnerIsGone() {
|
|
61700
61896
|
let pid;
|
|
61701
61897
|
try {
|
|
61702
|
-
pid = Number(
|
|
61898
|
+
pid = Number(readFileSync6(this.consumedLockPath, "utf8").trim());
|
|
61703
61899
|
} catch {
|
|
61704
61900
|
return false;
|
|
61705
61901
|
}
|
|
@@ -61713,7 +61909,7 @@ class State {
|
|
|
61713
61909
|
}
|
|
61714
61910
|
}
|
|
61715
61911
|
saveSlip(slip2) {
|
|
61716
|
-
|
|
61912
|
+
mkdirSync4(join4(this.dir, "slips"), { recursive: true });
|
|
61717
61913
|
writeFileSync2(this.slipPath(slip2.hash), `${JSON.stringify(slip2, null, 2)}
|
|
61718
61914
|
`);
|
|
61719
61915
|
}
|
|
@@ -61725,10 +61921,13 @@ var init_state = __esm(() => {
|
|
|
61725
61921
|
|
|
61726
61922
|
// packages/buyer/src/cli.ts
|
|
61727
61923
|
var exports_cli = {};
|
|
61924
|
+
__export(exports_cli, {
|
|
61925
|
+
agentAccount: () => agentAccount
|
|
61926
|
+
});
|
|
61728
61927
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
61729
|
-
import { chmodSync as
|
|
61730
|
-
import { join as
|
|
61731
|
-
function
|
|
61928
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
61929
|
+
import { join as join5 } from "node:path";
|
|
61930
|
+
function parse7(argv) {
|
|
61732
61931
|
const pos = [];
|
|
61733
61932
|
const flags = new Map;
|
|
61734
61933
|
for (let i = 0;i < argv.length; i++) {
|
|
@@ -61750,14 +61949,21 @@ function parse6(argv) {
|
|
|
61750
61949
|
}
|
|
61751
61950
|
return { pos, flags };
|
|
61752
61951
|
}
|
|
61753
|
-
function agentAccount() {
|
|
61952
|
+
async function agentAccount() {
|
|
61953
|
+
cachedAccount ??= resolveAccount();
|
|
61954
|
+
return await cachedAccount;
|
|
61955
|
+
}
|
|
61956
|
+
async function resolveAccount() {
|
|
61754
61957
|
const key = process.env.CS_BUYER_KEY;
|
|
61755
|
-
if (
|
|
61756
|
-
|
|
61757
|
-
|
|
61958
|
+
if (key)
|
|
61959
|
+
return privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`);
|
|
61960
|
+
const session = await sessionFromEnv(process.env);
|
|
61961
|
+
if (session !== undefined)
|
|
61962
|
+
return remoteAccount(session);
|
|
61963
|
+
throw new Error(NOT_SIGNED_IN3);
|
|
61758
61964
|
}
|
|
61759
61965
|
async function main2() {
|
|
61760
|
-
const { pos, flags } =
|
|
61966
|
+
const { pos, flags } = parse7(process.argv.slice(2));
|
|
61761
61967
|
const one = (n) => flags.get(n)?.[0];
|
|
61762
61968
|
let hub = new HubClient(one("hub") ?? "http://127.0.0.1:8787");
|
|
61763
61969
|
const state = new State(one("state"));
|
|
@@ -61789,7 +61995,7 @@ async function main2() {
|
|
|
61789
61995
|
console.log(`${page.items.length} of ${page.total} listed, ${payable} payable by this agent.`);
|
|
61790
61996
|
} else if (cmd === "discover") {
|
|
61791
61997
|
for (const l of await hub.listOffers()) {
|
|
61792
|
-
console.log([l.offerHash.slice(0, 10), l.offer.title,
|
|
61998
|
+
console.log([l.offerHash.slice(0, 10), l.offer.title, priceLabel(l.offer.price, l.offer.rails), l.offer.rails.join(","), l.online ? "online" : "offline"].join(" "));
|
|
61793
61999
|
}
|
|
61794
62000
|
} else if (cmd === "buy") {
|
|
61795
62001
|
const fromUrl = pos[1] !== undefined ? hubCallOf(pos[1]) : undefined;
|
|
@@ -61801,7 +62007,7 @@ async function main2() {
|
|
|
61801
62007
|
throw new Error("Usage: buy <offerHash|callUrl> --input '<json>' [--approve] [--rail <id>] [--approvals hub]");
|
|
61802
62008
|
const rail2 = parseRail(one("rail"));
|
|
61803
62009
|
const approvals = parseApprovals(one("approvals"));
|
|
61804
|
-
const account = agentAccount();
|
|
62010
|
+
const account = await agentAccount();
|
|
61805
62011
|
const result = await buy({
|
|
61806
62012
|
hub,
|
|
61807
62013
|
offerHash: hash4,
|
|
@@ -61830,9 +62036,9 @@ async function main2() {
|
|
|
61830
62036
|
try {
|
|
61831
62037
|
env = state.loadEnvelope();
|
|
61832
62038
|
} catch {
|
|
61833
|
-
env = { v: 1, agent: agentAccount().address, cap: "0", perMerchant: "0", allowlist: [], revoked: false };
|
|
62039
|
+
env = { v: 1, agent: (await agentAccount()).address, cap: "0", perMerchant: "0", allowlist: [], revoked: false };
|
|
61834
62040
|
}
|
|
61835
|
-
env.agent = agentAccount().address;
|
|
62041
|
+
env.agent = (await agentAccount()).address;
|
|
61836
62042
|
const cap = one("cap");
|
|
61837
62043
|
if (cap !== undefined)
|
|
61838
62044
|
env.cap = parseUnits(cap, 6).toString(10);
|
|
@@ -61854,7 +62060,7 @@ async function main2() {
|
|
|
61854
62060
|
} else if ((cmd === "accept" || cmd === "dispute") && pos[1] !== undefined) {
|
|
61855
62061
|
if (!/^0x[0-9a-fA-F]{64}$/.test(pos[1]))
|
|
61856
62062
|
throw new Error(`Usage: ${cmd} <jobId>`);
|
|
61857
|
-
const account = agentAccount();
|
|
62063
|
+
const account = await agentAccount();
|
|
61858
62064
|
const args = { hub, journal, state, known, signer: account, jobId: pos[1], now: Math.floor(Date.now() / 1000) };
|
|
61859
62065
|
if (cmd === "accept") {
|
|
61860
62066
|
const done = await acceptJob(args);
|
|
@@ -61870,7 +62076,7 @@ async function main2() {
|
|
|
61870
62076
|
for (const e of journal.entries())
|
|
61871
62077
|
console.log(JSON.stringify(e));
|
|
61872
62078
|
} else if (cmd === "publish-envelope") {
|
|
61873
|
-
const account = agentAccount();
|
|
62079
|
+
const account = await agentAccount();
|
|
61874
62080
|
const ok2 = await publishEnvelope({
|
|
61875
62081
|
hub,
|
|
61876
62082
|
account,
|
|
@@ -61880,12 +62086,12 @@ async function main2() {
|
|
|
61880
62086
|
});
|
|
61881
62087
|
console.log(ok2 ? "Envelope published." : "Envelope publish failed.");
|
|
61882
62088
|
} else if (cmd === "openai") {
|
|
61883
|
-
const account = agentAccount();
|
|
62089
|
+
const account = await agentAccount();
|
|
61884
62090
|
const token = randomBytes2(32).toString("hex");
|
|
61885
|
-
|
|
61886
|
-
const tokenPath =
|
|
62091
|
+
mkdirSync5(state.dir, { recursive: true });
|
|
62092
|
+
const tokenPath = join5(state.dir, "openai.token");
|
|
61887
62093
|
writeFileSync3(tokenPath, token, { mode: 384 });
|
|
61888
|
-
|
|
62094
|
+
chmodSync3(tokenPath, 384);
|
|
61889
62095
|
const server = startOpenAIServer({
|
|
61890
62096
|
hub,
|
|
61891
62097
|
account,
|
|
@@ -61900,7 +62106,7 @@ async function main2() {
|
|
|
61900
62106
|
console.log(`${server.url}/v1`);
|
|
61901
62107
|
console.log(tokenPath);
|
|
61902
62108
|
} else if (cmd === "resume") {
|
|
61903
|
-
const mirror = flags.has("hub") ? { account: agentAccount(), envelope: state.loadEnvelope() } : undefined;
|
|
62109
|
+
const mirror = flags.has("hub") ? { account: await agentAccount(), envelope: state.loadEnvelope() } : undefined;
|
|
61904
62110
|
const rows = await resume({
|
|
61905
62111
|
hub,
|
|
61906
62112
|
journal,
|
|
@@ -61914,7 +62120,7 @@ async function main2() {
|
|
|
61914
62120
|
console.log(`${r.jobId} ${r.status}${r.appended ? ` -> ${r.appended}` : ""}`);
|
|
61915
62121
|
} else {
|
|
61916
62122
|
console.log("Usage: cli.ts discover [--catalogue <url|circle> [query] [--category <c>] [--limit <n>]] | buy <offerHash|callUrl> --input '<json>' [--approve] [--rail <id>] [--approvals hub] | accept <jobId> | dispute <jobId> [--direct] | envelope show|set | publish-envelope | journal | resume | openai [--port <n>]");
|
|
61917
|
-
console.log("Flags: --hub <url> --state <dir>.
|
|
62123
|
+
console.log("Flags: --hub <url> --state <dir>. Sign in once with: countersign login.");
|
|
61918
62124
|
}
|
|
61919
62125
|
}
|
|
61920
62126
|
function parseApprovals(raw) {
|
|
@@ -61943,7 +62149,7 @@ function parseRail(raw) {
|
|
|
61943
62149
|
throw new Error(`Unknown rail ${raw}.`);
|
|
61944
62150
|
return raw;
|
|
61945
62151
|
}
|
|
61946
|
-
var BOOLEAN, usd2 = (atomic) => formatUnits(BigInt(atomic), 6);
|
|
62152
|
+
var BOOLEAN, cachedAccount, usd2 = (atomic) => formatUnits(BigInt(atomic), 6);
|
|
61947
62153
|
var init_cli = __esm(() => {
|
|
61948
62154
|
init_accounts();
|
|
61949
62155
|
init_src();
|
|
@@ -61955,6 +62161,8 @@ var init_cli = __esm(() => {
|
|
|
61955
62161
|
init_mirror();
|
|
61956
62162
|
init_server();
|
|
61957
62163
|
init_payer2();
|
|
62164
|
+
init_price_label();
|
|
62165
|
+
init_remote_signer();
|
|
61958
62166
|
init_resume();
|
|
61959
62167
|
init_review();
|
|
61960
62168
|
init_state();
|
|
@@ -61967,7 +62175,7 @@ var init_cli = __esm(() => {
|
|
|
61967
62175
|
|
|
61968
62176
|
// packages/verify/src/cli.ts
|
|
61969
62177
|
var exports_cli2 = {};
|
|
61970
|
-
import { readFileSync as
|
|
62178
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
61971
62179
|
var args, file2, rpcAt, rpcUrl, mirrorAt, mirrorUrl, slip2, verdict, verdictLine;
|
|
61972
62180
|
var init_cli2 = __esm(async () => {
|
|
61973
62181
|
init_verify();
|
|
@@ -61982,7 +62190,7 @@ var init_cli2 = __esm(async () => {
|
|
|
61982
62190
|
process.exit(2);
|
|
61983
62191
|
}
|
|
61984
62192
|
try {
|
|
61985
|
-
slip2 = JSON.parse(
|
|
62193
|
+
slip2 = JSON.parse(readFileSync7(file2, "utf8"));
|
|
61986
62194
|
} catch (e) {
|
|
61987
62195
|
console.error(`cannot read ${file2}: ${e.message}`);
|
|
61988
62196
|
process.exit(2);
|
|
@@ -62079,6 +62287,7 @@ var init_src4 = __esm(() => {
|
|
|
62079
62287
|
init_mirror();
|
|
62080
62288
|
init_payer2();
|
|
62081
62289
|
init_resume();
|
|
62290
|
+
init_remote_signer();
|
|
62082
62291
|
init_review();
|
|
62083
62292
|
init_state();
|
|
62084
62293
|
init_terms();
|
|
@@ -63381,7 +63590,7 @@ var init_mcp = __esm(() => {
|
|
|
63381
63590
|
});
|
|
63382
63591
|
|
|
63383
63592
|
// packages/mcp/src/server.ts
|
|
63384
|
-
import { existsSync as
|
|
63593
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
63385
63594
|
function assertHash(value, what) {
|
|
63386
63595
|
if (!HASH.test(value))
|
|
63387
63596
|
throw new Error(`Refused. ${what} must be 0x followed by 64 hex characters.`);
|
|
@@ -63408,11 +63617,16 @@ function searchText(offer2) {
|
|
|
63408
63617
|
`).toLowerCase();
|
|
63409
63618
|
}
|
|
63410
63619
|
function createCountersignMcpServer(deps) {
|
|
63411
|
-
const server = new McpServer({ name: "countersign", version: "0.1.
|
|
63620
|
+
const server = new McpServer({ name: "countersign", version: "0.1.1" });
|
|
63412
63621
|
const clock = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
63413
63622
|
const verify2 = deps.verify ?? verifySlip;
|
|
63623
|
+
const gate = () => {
|
|
63624
|
+
if (deps.account !== undefined)
|
|
63625
|
+
return;
|
|
63626
|
+
return failure3(new Error(deps.problem === undefined ? NOT_SIGNED_IN3 : `${NOT_SIGNED_IN3} (${deps.problem})`));
|
|
63627
|
+
};
|
|
63414
63628
|
const loadSlip = async (hash4) => {
|
|
63415
|
-
if (
|
|
63629
|
+
if (existsSync6(deps.state.slipPath(hash4)))
|
|
63416
63630
|
return deps.state.loadSlip(hash4);
|
|
63417
63631
|
const base2 = deps.hubUrl.replace(/\/+$/, "");
|
|
63418
63632
|
const response = await fetch(`${base2}/slips/${hash4}`);
|
|
@@ -63428,6 +63642,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63428
63642
|
limit: exports_external.number().int().optional()
|
|
63429
63643
|
}
|
|
63430
63644
|
}, async ({ query, limit }) => {
|
|
63645
|
+
const refused = gate();
|
|
63646
|
+
if (refused !== undefined)
|
|
63647
|
+
return refused;
|
|
63431
63648
|
try {
|
|
63432
63649
|
const listings = await deps.hub.listOffers();
|
|
63433
63650
|
const needle = query?.toLowerCase();
|
|
@@ -63462,6 +63679,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63462
63679
|
offerHash: exports_external.string()
|
|
63463
63680
|
}
|
|
63464
63681
|
}, async ({ offerHash: offerHash2 }) => {
|
|
63682
|
+
const refused = gate();
|
|
63683
|
+
if (refused !== undefined)
|
|
63684
|
+
return refused;
|
|
63465
63685
|
try {
|
|
63466
63686
|
assertHash(offerHash2, "offerHash");
|
|
63467
63687
|
const listing = await deps.hub.getOffer(offerHash2);
|
|
@@ -63479,16 +63699,17 @@ function createCountersignMcpServer(deps) {
|
|
|
63479
63699
|
});
|
|
63480
63700
|
server.registerTool("buy", {
|
|
63481
63701
|
title: "Buy an offer",
|
|
63482
|
-
description: "Buy an offer under the agent's envelope and return the seller's output and slip. Requires
|
|
63702
|
+
description: "Buy an offer under the agent's envelope and return the seller's output and slip. Requires sign-in: npx -y @countersign-hub/cli login.",
|
|
63483
63703
|
inputSchema: {
|
|
63484
63704
|
offerHash: exports_external.string(),
|
|
63485
63705
|
input: exports_external.unknown(),
|
|
63486
63706
|
rail: exports_external.string().optional()
|
|
63487
63707
|
}
|
|
63488
63708
|
}, async ({ offerHash: offerHash2, input: input2, rail: rail2 }) => {
|
|
63709
|
+
const refused = gate();
|
|
63710
|
+
if (refused !== undefined)
|
|
63711
|
+
return refused;
|
|
63489
63712
|
const account = deps.account;
|
|
63490
|
-
if (account === undefined)
|
|
63491
|
-
return failure3(new Error(NO_KEY));
|
|
63492
63713
|
if (rail2 !== undefined && !RAIL_IDS.includes(rail2)) {
|
|
63493
63714
|
return failure3(new Error(`Unknown rail ${rail2}.`));
|
|
63494
63715
|
}
|
|
@@ -63529,6 +63750,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63529
63750
|
slipHash: exports_external.string().optional()
|
|
63530
63751
|
}
|
|
63531
63752
|
}, async ({ slip: slip3, slipHash: slipHash2 }) => {
|
|
63753
|
+
const refused = gate();
|
|
63754
|
+
if (refused !== undefined)
|
|
63755
|
+
return refused;
|
|
63532
63756
|
if (slip3 === undefined === (slipHash2 === undefined)) {
|
|
63533
63757
|
return failure3(new Error("Pass exactly one of slip or slipHash."));
|
|
63534
63758
|
}
|
|
@@ -63546,6 +63770,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63546
63770
|
description: "Read the agent's envelope and what the journal says it has spent.",
|
|
63547
63771
|
inputSchema: {}
|
|
63548
63772
|
}, async () => {
|
|
63773
|
+
const refused = gate();
|
|
63774
|
+
if (refused !== undefined)
|
|
63775
|
+
return refused;
|
|
63549
63776
|
try {
|
|
63550
63777
|
return text({ envelope: deps.state.loadEnvelope(), spent: deps.journal.spend() });
|
|
63551
63778
|
} catch (error62) {
|
|
@@ -63559,6 +63786,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63559
63786
|
limit: exports_external.number().int().optional()
|
|
63560
63787
|
}
|
|
63561
63788
|
}, async ({ limit }) => {
|
|
63789
|
+
const refused = gate();
|
|
63790
|
+
if (refused !== undefined)
|
|
63791
|
+
return refused;
|
|
63562
63792
|
try {
|
|
63563
63793
|
const entries = deps.journal.entries();
|
|
63564
63794
|
const count = limit ?? 20;
|
|
@@ -63569,7 +63799,7 @@ function createCountersignMcpServer(deps) {
|
|
|
63569
63799
|
});
|
|
63570
63800
|
return server;
|
|
63571
63801
|
}
|
|
63572
|
-
var HASH_MISMATCH = "Refused. The hub served an offer that does not match the hash asked for.",
|
|
63802
|
+
var HASH_MISMATCH = "Refused. The hub served an offer that does not match the hash asked for.", HASH;
|
|
63573
63803
|
var init_server6 = __esm(() => {
|
|
63574
63804
|
init_mcp();
|
|
63575
63805
|
init_zod();
|
|
@@ -63582,14 +63812,15 @@ var init_server6 = __esm(() => {
|
|
|
63582
63812
|
// packages/mcp/src/main.ts
|
|
63583
63813
|
var exports_main = {};
|
|
63584
63814
|
__export(exports_main, {
|
|
63815
|
+
resolveAccount: () => resolveAccount2,
|
|
63585
63816
|
main: () => main3
|
|
63586
63817
|
});
|
|
63587
63818
|
function fail(message) {
|
|
63588
63819
|
console.error(message);
|
|
63589
63820
|
process.exit(1);
|
|
63590
63821
|
}
|
|
63591
|
-
function
|
|
63592
|
-
const config2 = { hub: process.env.CS_HUB ??
|
|
63822
|
+
function parse8(argv) {
|
|
63823
|
+
const config2 = { hub: process.env.CS_HUB ?? DEFAULT_HUB2 };
|
|
63593
63824
|
if (process.env.CS_RPC_URL !== undefined)
|
|
63594
63825
|
config2.rpcUrl = process.env.CS_RPC_URL;
|
|
63595
63826
|
let help = false;
|
|
@@ -63615,18 +63846,45 @@ function parse7(argv) {
|
|
|
63615
63846
|
}
|
|
63616
63847
|
return { help, config: config2 };
|
|
63617
63848
|
}
|
|
63618
|
-
function
|
|
63619
|
-
const key =
|
|
63849
|
+
function ciAccount(env) {
|
|
63850
|
+
const key = env.CS_BUYER_KEY;
|
|
63620
63851
|
if (!key)
|
|
63621
|
-
return;
|
|
63852
|
+
return {};
|
|
63622
63853
|
try {
|
|
63623
|
-
return privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`);
|
|
63854
|
+
return { account: privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`) };
|
|
63624
63855
|
} catch {
|
|
63625
|
-
return
|
|
63856
|
+
return { problem: "The configured signer is not valid." };
|
|
63626
63857
|
}
|
|
63627
63858
|
}
|
|
63628
|
-
|
|
63629
|
-
const
|
|
63859
|
+
function sessionProblem(error62) {
|
|
63860
|
+
const message = error62 instanceof Error ? error62.message : String(error62);
|
|
63861
|
+
const firstLine3 = message.split(`
|
|
63862
|
+
`)[0] ?? "";
|
|
63863
|
+
return { problem: `Could not load the countersign session: ${firstLine3}` };
|
|
63864
|
+
}
|
|
63865
|
+
async function resolveAccount2(options, env) {
|
|
63866
|
+
const sessionEnv = { CS_SESSION: env.CS_SESSION, CS_HUB: env.CS_HUB };
|
|
63867
|
+
delete env.CS_SESSION;
|
|
63868
|
+
if (options.loadAccount !== undefined) {
|
|
63869
|
+
try {
|
|
63870
|
+
const account = await options.loadAccount();
|
|
63871
|
+
return account === undefined ? {} : { account };
|
|
63872
|
+
} catch (error62) {
|
|
63873
|
+
return sessionProblem(error62);
|
|
63874
|
+
}
|
|
63875
|
+
}
|
|
63876
|
+
let session;
|
|
63877
|
+
try {
|
|
63878
|
+
session = await sessionFromEnv(sessionEnv);
|
|
63879
|
+
} catch (error62) {
|
|
63880
|
+
return sessionProblem(error62);
|
|
63881
|
+
}
|
|
63882
|
+
if (session !== undefined)
|
|
63883
|
+
return { account: remoteAccount(session) };
|
|
63884
|
+
return ciAccount(env);
|
|
63885
|
+
}
|
|
63886
|
+
async function main3(argv, options = {}) {
|
|
63887
|
+
const { help, config: config2 } = parse8(argv);
|
|
63630
63888
|
if (help) {
|
|
63631
63889
|
console.log(USAGE);
|
|
63632
63890
|
return;
|
|
@@ -63639,11 +63897,16 @@ async function main3(argv) {
|
|
|
63639
63897
|
const state2 = new State(config2.state);
|
|
63640
63898
|
const journal2 = new Journal(state2.journalPath);
|
|
63641
63899
|
const hub = new HubClient(config2.hub);
|
|
63642
|
-
const account =
|
|
63643
|
-
console.error(`countersign
|
|
63644
|
-
console.error(`countersign
|
|
63645
|
-
if (account !== undefined)
|
|
63646
|
-
console.error(`countersign
|
|
63900
|
+
const { account, problem } = await resolveAccount2(options, process.env);
|
|
63901
|
+
console.error(`countersign mcp: hub ${hub.url}`);
|
|
63902
|
+
console.error(`countersign mcp: state ${state2.dir}`);
|
|
63903
|
+
if (account !== undefined) {
|
|
63904
|
+
console.error(`countersign mcp: agent ${account.address}`);
|
|
63905
|
+
} else {
|
|
63906
|
+
console.error("countersign mcp: not signed in. Run: npx -y @countersign-hub/cli login");
|
|
63907
|
+
if (problem !== undefined)
|
|
63908
|
+
console.error(`countersign mcp: ${problem}`);
|
|
63909
|
+
}
|
|
63647
63910
|
const server = createCountersignMcpServer({
|
|
63648
63911
|
hub,
|
|
63649
63912
|
state: state2,
|
|
@@ -63651,11 +63914,12 @@ async function main3(argv) {
|
|
|
63651
63914
|
hubUrl: config2.hub,
|
|
63652
63915
|
now: () => Math.floor(Date.now() / 1000),
|
|
63653
63916
|
...account !== undefined ? { account } : {},
|
|
63917
|
+
...problem !== undefined ? { problem } : {},
|
|
63654
63918
|
...config2.rpcUrl !== undefined ? { rpcUrl: config2.rpcUrl } : {}
|
|
63655
63919
|
});
|
|
63656
63920
|
await server.connect(new StdioServerTransport);
|
|
63657
63921
|
}
|
|
63658
|
-
var
|
|
63922
|
+
var DEFAULT_HUB2 = "https://hub-production-e85e.up.railway.app", USAGE;
|
|
63659
63923
|
var init_main = __esm(() => {
|
|
63660
63924
|
init_accounts();
|
|
63661
63925
|
init_stdio2();
|
|
@@ -63666,17 +63930,18 @@ var init_main = __esm(() => {
|
|
|
63666
63930
|
Usage: countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
63667
63931
|
|
|
63668
63932
|
Options:
|
|
63669
|
-
--hub <url> The countersign hub (env CS_HUB; default ${
|
|
63933
|
+
--hub <url> The countersign hub (env CS_HUB; default ${DEFAULT_HUB2})
|
|
63670
63934
|
--state <dir> Where the envelope, journal and slips live (default ~/.countersign)
|
|
63671
63935
|
--rpc <url> The RPC verify_slip reads the chain from (env CS_RPC_URL), e.g. https://rpc.testnet.arc.network
|
|
63672
63936
|
--help Print this usage and exit
|
|
63673
63937
|
|
|
63674
|
-
|
|
63675
|
-
|
|
63676
|
-
|
|
63938
|
+
Sign in once: npx -y @countersign-hub/cli login. Your agent's wallet is a Privy server wallet that the countersign app controls;
|
|
63939
|
+
this server signs through the hub with your session, and no key is ever on this machine or in any config.
|
|
63940
|
+
|
|
63941
|
+
CS_NETWORK must be unset or testnet.
|
|
63677
63942
|
|
|
63678
|
-
Install
|
|
63679
|
-
countersign and countersign-mcp belong to other projects: never npx or npm install them.`;
|
|
63943
|
+
Install: npm i -g @countersign-hub/cli, then countersign mcp (or npx -y @countersign-hub/cli mcp).
|
|
63944
|
+
The npm packages named @countersign/*, countersign and countersign-mcp belong to other projects: never npx or npm install them.`;
|
|
63680
63945
|
});
|
|
63681
63946
|
|
|
63682
63947
|
// packages/runner/src/cli.ts
|
|
@@ -63957,8 +64222,11 @@ function setTermsArgs(command) {
|
|
|
63957
64222
|
}
|
|
63958
64223
|
async function bondFromEnv(args, log = console.log) {
|
|
63959
64224
|
const key = process.env.CS_SELLER_KEY;
|
|
63960
|
-
if (!key
|
|
63961
|
-
throw new Error("
|
|
64225
|
+
if (!key) {
|
|
64226
|
+
throw new Error("Bond commands are not available from a signed-in session yet: they send transactions, and the hub only signs.");
|
|
64227
|
+
}
|
|
64228
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
64229
|
+
throw new Error("The CI signing override in this environment is malformed.");
|
|
63962
64230
|
}
|
|
63963
64231
|
await runBond(parseBondArgs(args), key, log);
|
|
63964
64232
|
}
|
|
@@ -65153,12 +65421,183 @@ function isRecord3(value) {
|
|
|
65153
65421
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65154
65422
|
}
|
|
65155
65423
|
|
|
65424
|
+
// packages/runner/src/remote-signer.ts
|
|
65425
|
+
init__esm();
|
|
65426
|
+
var NOT_SIGNED_IN = "Not signed in. Run: npx -y @countersign-hub/cli login";
|
|
65427
|
+
var BONDED_REMOTE_REFUSAL = "A bonded offer cannot be served from a signed-in session yet: the hub does not sign Lock for it.";
|
|
65428
|
+
var SIGNATURE = /^0x[0-9a-fA-F]{130}$/;
|
|
65429
|
+
var ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
65430
|
+
function hubFailure(reason) {
|
|
65431
|
+
return new Error(`The hub could not sign right now (${reason}).`);
|
|
65432
|
+
}
|
|
65433
|
+
var WRONG_WALLET = "The hub signed with a different wallet.";
|
|
65434
|
+
function safeHub(hubUrl) {
|
|
65435
|
+
let url2;
|
|
65436
|
+
try {
|
|
65437
|
+
url2 = new URL(hubUrl);
|
|
65438
|
+
} catch {
|
|
65439
|
+
throw new Error("The hub address is not a URL.");
|
|
65440
|
+
}
|
|
65441
|
+
const local = url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]";
|
|
65442
|
+
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && local)) {
|
|
65443
|
+
throw new Error("The session is sent only to an https hub.");
|
|
65444
|
+
}
|
|
65445
|
+
return hubUrl.replace(/\/+$/, "");
|
|
65446
|
+
}
|
|
65447
|
+
function decimalString(_key, value) {
|
|
65448
|
+
return typeof value === "bigint" ? value.toString(10) : value;
|
|
65449
|
+
}
|
|
65450
|
+
function recordOf(value) {
|
|
65451
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
65452
|
+
}
|
|
65453
|
+
function messageOf2(body) {
|
|
65454
|
+
const message = recordOf(body)?.message;
|
|
65455
|
+
return typeof message === "string" && message.length > 0 ? message : null;
|
|
65456
|
+
}
|
|
65457
|
+
function codeOf(body) {
|
|
65458
|
+
const code = recordOf(body)?.code;
|
|
65459
|
+
return typeof code === "string" && code.length > 0 ? code : null;
|
|
65460
|
+
}
|
|
65461
|
+
async function readJson(response) {
|
|
65462
|
+
try {
|
|
65463
|
+
return await response.json();
|
|
65464
|
+
} catch {
|
|
65465
|
+
return;
|
|
65466
|
+
}
|
|
65467
|
+
}
|
|
65468
|
+
function remoteRunnerAccount(options) {
|
|
65469
|
+
const hub = safeHub(options.hubUrl);
|
|
65470
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
65471
|
+
const sign3 = async (payload, recover) => {
|
|
65472
|
+
let response;
|
|
65473
|
+
try {
|
|
65474
|
+
response = await fetchImpl(`${hub}/cli/sign`, {
|
|
65475
|
+
method: "POST",
|
|
65476
|
+
headers: {
|
|
65477
|
+
authorization: `Bearer ${options.session}`,
|
|
65478
|
+
"content-type": "application/json"
|
|
65479
|
+
},
|
|
65480
|
+
body: JSON.stringify(payload, decimalString)
|
|
65481
|
+
});
|
|
65482
|
+
} catch {
|
|
65483
|
+
throw hubFailure("unreachable");
|
|
65484
|
+
}
|
|
65485
|
+
const body = await readJson(response);
|
|
65486
|
+
if (response.status === 200) {
|
|
65487
|
+
const signed2 = recordOf(body);
|
|
65488
|
+
const signature = signed2?.signature;
|
|
65489
|
+
const address = signed2?.address;
|
|
65490
|
+
if (typeof signature !== "string" || !SIGNATURE.test(signature) || typeof address !== "string" || address.toLowerCase() !== options.address.toLowerCase()) {
|
|
65491
|
+
throw new Error(WRONG_WALLET);
|
|
65492
|
+
}
|
|
65493
|
+
let signer;
|
|
65494
|
+
try {
|
|
65495
|
+
signer = await recover(signature);
|
|
65496
|
+
} catch {
|
|
65497
|
+
throw new Error(WRONG_WALLET);
|
|
65498
|
+
}
|
|
65499
|
+
if (signer.toLowerCase() !== options.address.toLowerCase())
|
|
65500
|
+
throw new Error(WRONG_WALLET);
|
|
65501
|
+
return signature;
|
|
65502
|
+
}
|
|
65503
|
+
if (response.status === 401)
|
|
65504
|
+
throw new Error(messageOf2(body) ?? NOT_SIGNED_IN);
|
|
65505
|
+
if (response.status === 403) {
|
|
65506
|
+
throw new Error(`The hub refused to sign this: ${codeOf(body) ?? "not-allowed"}`);
|
|
65507
|
+
}
|
|
65508
|
+
if (response.status === 502) {
|
|
65509
|
+
throw new Error("The hub could not sign right now (privy-failed).");
|
|
65510
|
+
}
|
|
65511
|
+
throw hubFailure(response.status);
|
|
65512
|
+
};
|
|
65513
|
+
return {
|
|
65514
|
+
kind: "remote",
|
|
65515
|
+
address: options.address,
|
|
65516
|
+
signMessage: (args) => sign3({ kind: "message", message: args.message }, (signature) => recoverMessageAddress2({ message: args.message, signature })),
|
|
65517
|
+
signTypedData: (typedData) => sign3({ kind: "typed-data", typedData }, (signature) => recoverTypedDataAddress2({ ...typedData, signature }))
|
|
65518
|
+
};
|
|
65519
|
+
}
|
|
65520
|
+
async function remoteAccountFromSession(options) {
|
|
65521
|
+
const hub = safeHub(options.hubUrl);
|
|
65522
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
65523
|
+
let response;
|
|
65524
|
+
try {
|
|
65525
|
+
response = await fetchImpl(`${hub}/cli/session`, {
|
|
65526
|
+
headers: { authorization: `Bearer ${options.session}` }
|
|
65527
|
+
});
|
|
65528
|
+
} catch {
|
|
65529
|
+
throw hubFailure("unreachable");
|
|
65530
|
+
}
|
|
65531
|
+
const body = await readJson(response);
|
|
65532
|
+
if (response.status === 200) {
|
|
65533
|
+
const address = recordOf(body)?.address;
|
|
65534
|
+
if (typeof address !== "string" || !ADDRESS.test(address)) {
|
|
65535
|
+
throw hubFailure("invalid-address");
|
|
65536
|
+
}
|
|
65537
|
+
return remoteRunnerAccount({ ...options, address });
|
|
65538
|
+
}
|
|
65539
|
+
if (response.status === 401)
|
|
65540
|
+
throw new Error(messageOf2(body) ?? NOT_SIGNED_IN);
|
|
65541
|
+
throw hubFailure(response.status);
|
|
65542
|
+
}
|
|
65543
|
+
function assertRemoteCanServe(account, offer2) {
|
|
65544
|
+
if (account.kind !== "remote")
|
|
65545
|
+
return;
|
|
65546
|
+
let bonded = false;
|
|
65547
|
+
try {
|
|
65548
|
+
bonded = BigInt(offer2.bond) > 0n;
|
|
65549
|
+
} catch {
|
|
65550
|
+
bonded = false;
|
|
65551
|
+
}
|
|
65552
|
+
if (bonded)
|
|
65553
|
+
throw new Error(BONDED_REMOTE_REFUSAL);
|
|
65554
|
+
}
|
|
65555
|
+
|
|
65156
65556
|
// packages/runner/src/daemon.ts
|
|
65157
65557
|
var RECONNECT_DELAYS = [1, 2, 4, 8, 16, 30];
|
|
65558
|
+
var ATOMIC = /^(0|[1-9][0-9]*)$/;
|
|
65559
|
+
var ADDRESS2 = /^0x[0-9a-fA-F]{40}$/;
|
|
65560
|
+
function readLockTerms(value) {
|
|
65561
|
+
if (value === null || typeof value !== "object")
|
|
65562
|
+
return null;
|
|
65563
|
+
const raw = value;
|
|
65564
|
+
const buyer = raw.buyer;
|
|
65565
|
+
const payee = raw.payee;
|
|
65566
|
+
const amount2 = raw.amount;
|
|
65567
|
+
const deadline = raw.deadline;
|
|
65568
|
+
const salt = raw.salt;
|
|
65569
|
+
const bond = raw.bond;
|
|
65570
|
+
const reviewWindow = raw.reviewWindow;
|
|
65571
|
+
if (typeof buyer !== "string" || !ADDRESS2.test(buyer))
|
|
65572
|
+
return null;
|
|
65573
|
+
if (typeof payee !== "string" || !ADDRESS2.test(payee))
|
|
65574
|
+
return null;
|
|
65575
|
+
if (typeof amount2 !== "string" || !ATOMIC.test(amount2))
|
|
65576
|
+
return null;
|
|
65577
|
+
if (typeof deadline !== "number" || !Number.isSafeInteger(deadline))
|
|
65578
|
+
return null;
|
|
65579
|
+
if (typeof salt !== "string" || !ATOMIC.test(salt))
|
|
65580
|
+
return null;
|
|
65581
|
+
if (typeof bond !== "string" || !ATOMIC.test(bond))
|
|
65582
|
+
return null;
|
|
65583
|
+
if (typeof reviewWindow !== "number" || !Number.isSafeInteger(reviewWindow))
|
|
65584
|
+
return null;
|
|
65585
|
+
return {
|
|
65586
|
+
buyer,
|
|
65587
|
+
payee,
|
|
65588
|
+
amount: amount2,
|
|
65589
|
+
deadline,
|
|
65590
|
+
salt,
|
|
65591
|
+
bond,
|
|
65592
|
+
reviewWindow
|
|
65593
|
+
};
|
|
65594
|
+
}
|
|
65158
65595
|
function startRunner(cfg) {
|
|
65159
65596
|
const clock = cfg.now ?? (() => Math.floor(Date.now() / 1000));
|
|
65160
65597
|
const timeMs = cfg.limits?.timeMs ?? 30000;
|
|
65161
65598
|
const maxOutputBytes = cfg.limits?.maxOutputBytes ?? 1e6;
|
|
65599
|
+
for (const entry of cfg.served)
|
|
65600
|
+
assertRemoteCanServe(cfg.account, entry.offer);
|
|
65162
65601
|
const served = cfg.served.map((entry) => ({ ...entry, hash: offerHash(entry.offer) }));
|
|
65163
65602
|
const url2 = connectUrl(cfg.hubUrl);
|
|
65164
65603
|
const funding = cfg.funding === undefined ? null : { ...cfg.funding, read: fundingReader(cfg.funding) };
|
|
@@ -65215,9 +65654,51 @@ function startRunner(cfg) {
|
|
|
65215
65654
|
});
|
|
65216
65655
|
return;
|
|
65217
65656
|
}
|
|
65657
|
+
const refuse = (reason) => {
|
|
65658
|
+
send(target, { t: "lock-refused", jobId: frame.jobId, reason });
|
|
65659
|
+
};
|
|
65660
|
+
const terms = readLockTerms(frame.terms);
|
|
65661
|
+
if (terms === null) {
|
|
65662
|
+
refuse("bad-terms");
|
|
65663
|
+
return;
|
|
65664
|
+
}
|
|
65665
|
+
if (terms.payee.toLowerCase() !== cfg.account.address.toLowerCase()) {
|
|
65666
|
+
refuse("not-payee");
|
|
65667
|
+
return;
|
|
65668
|
+
}
|
|
65669
|
+
let bondAbove = false;
|
|
65670
|
+
try {
|
|
65671
|
+
bondAbove = BigInt(terms.bond) > 0n;
|
|
65672
|
+
} catch {
|
|
65673
|
+
bondAbove = false;
|
|
65674
|
+
}
|
|
65675
|
+
if (terms.amount !== entry.offer.price || terms.bond !== entry.offer.bond || !bondAbove || terms.reviewWindow !== (entry.offer.reviewWindow ?? 0)) {
|
|
65676
|
+
refuse("terms-mismatch");
|
|
65677
|
+
return;
|
|
65678
|
+
}
|
|
65679
|
+
if (terms.deadline - clock() < 60) {
|
|
65680
|
+
refuse("deadline-too-near");
|
|
65681
|
+
return;
|
|
65682
|
+
}
|
|
65683
|
+
const escrow = frame.escrow;
|
|
65684
|
+
const pinned = funding !== null && typeof escrow === "string" && funding.known.some((pin) => pin.chainId === frame.chainId && pin.escrow.toLowerCase() === escrow.toLowerCase());
|
|
65685
|
+
if (!pinned) {
|
|
65686
|
+
refuse("unknown-escrow");
|
|
65687
|
+
return;
|
|
65688
|
+
}
|
|
65689
|
+
let rebuilt;
|
|
65690
|
+
try {
|
|
65691
|
+
rebuilt = jobIdOf({ offerHash: frame.offerHash, ...terms }, frame.chainId, frame.escrow);
|
|
65692
|
+
} catch {
|
|
65693
|
+
refuse("job-mismatch");
|
|
65694
|
+
return;
|
|
65695
|
+
}
|
|
65696
|
+
if (typeof frame.jobId !== "string" || rebuilt.toLowerCase() !== frame.jobId.toLowerCase()) {
|
|
65697
|
+
refuse("job-mismatch");
|
|
65698
|
+
return;
|
|
65699
|
+
}
|
|
65218
65700
|
try {
|
|
65219
|
-
const
|
|
65220
|
-
const sig = await cfg.account.signTypedData(typed);
|
|
65701
|
+
const sig = await cfg.account.signTypedData(lockTypedData(frame.chainId, frame.escrow, frame.jobId, frame.funder));
|
|
65221
65702
|
send(target, { t: "locked", jobId: frame.jobId, sig });
|
|
65222
65703
|
} catch {
|
|
65223
65704
|
send(target, {
|
|
@@ -65272,7 +65753,7 @@ function startRunner(cfg) {
|
|
|
65272
65753
|
try {
|
|
65273
65754
|
output2 = await runInChild(substituteBuyer(entry.spec, order.buyer), order.input, { timeMs, maxOutputBytes }, [...order.lineage, order.jobId].join(","));
|
|
65274
65755
|
} catch (error62) {
|
|
65275
|
-
const reason =
|
|
65756
|
+
const reason = messageOf3(error62);
|
|
65276
65757
|
notify(order, entry.offer.title, false, reason);
|
|
65277
65758
|
return fail(target, order, reason);
|
|
65278
65759
|
}
|
|
@@ -65308,7 +65789,7 @@ function startRunner(cfg) {
|
|
|
65308
65789
|
});
|
|
65309
65790
|
notify(order, entry.offer.title, true);
|
|
65310
65791
|
} catch (error62) {
|
|
65311
|
-
const reason =
|
|
65792
|
+
const reason = messageOf3(error62);
|
|
65312
65793
|
notify(order, entry.offer.title, false, reason);
|
|
65313
65794
|
fail(target, order, reason);
|
|
65314
65795
|
}
|
|
@@ -65394,7 +65875,7 @@ function startRunner(cfg) {
|
|
|
65394
65875
|
}
|
|
65395
65876
|
handleMessage(target, message).catch((error62) => {
|
|
65396
65877
|
if (message.t === "job")
|
|
65397
|
-
fail(target, message.order,
|
|
65878
|
+
fail(target, message.order, messageOf3(error62));
|
|
65398
65879
|
});
|
|
65399
65880
|
});
|
|
65400
65881
|
target.addEventListener("close", () => {
|
|
@@ -65487,7 +65968,7 @@ function connectUrl(hubUrl) {
|
|
|
65487
65968
|
url2.pathname = `${url2.pathname.replace(/\/+$/, "")}${RUNNER_PATH}`;
|
|
65488
65969
|
return url2.toString();
|
|
65489
65970
|
}
|
|
65490
|
-
function
|
|
65971
|
+
function messageOf3(error62) {
|
|
65491
65972
|
return error62 instanceof Error ? error62.message : String(error62);
|
|
65492
65973
|
}
|
|
65493
65974
|
|
|
@@ -66127,6 +66608,7 @@ async function publishCommand(options) {
|
|
|
66127
66608
|
console.log(offerHash2);
|
|
66128
66609
|
}
|
|
66129
66610
|
function publishWithState(options, account, offer2, skillSha256) {
|
|
66611
|
+
assertRemoteCanServe(account, offer2);
|
|
66130
66612
|
return publishOffer(options.hub, account, offer2, {
|
|
66131
66613
|
...options.state !== undefined ? { stateDir: options.state } : {},
|
|
66132
66614
|
skillSha256
|
|
@@ -66229,11 +66711,22 @@ function makeOffer(seller, skill, options) {
|
|
|
66229
66711
|
});
|
|
66230
66712
|
}
|
|
66231
66713
|
async function sellerAccount() {
|
|
66714
|
+
const session = process.env.CS_SESSION;
|
|
66715
|
+
delete process.env.CS_SESSION;
|
|
66232
66716
|
const key = process.env.CS_SELLER_KEY;
|
|
66233
|
-
if (
|
|
66234
|
-
|
|
66717
|
+
if (key) {
|
|
66718
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
66719
|
+
throw new Error("The CI signing override in this environment is malformed.");
|
|
66720
|
+
}
|
|
66721
|
+
return privateKeyToAccount(key);
|
|
66235
66722
|
}
|
|
66236
|
-
|
|
66723
|
+
if (session) {
|
|
66724
|
+
const issuer = process.env.CS_HUB;
|
|
66725
|
+
if (!issuer)
|
|
66726
|
+
throw new Error(NOT_SIGNED_IN);
|
|
66727
|
+
return remoteAccountFromSession({ hubUrl: issuer, session });
|
|
66728
|
+
}
|
|
66729
|
+
throw new Error(NOT_SIGNED_IN);
|
|
66237
66730
|
}
|
|
66238
66731
|
function parseOptions(args) {
|
|
66239
66732
|
const skills = [];
|
|
@@ -66449,30 +66942,458 @@ function parseRails(raw) {
|
|
|
66449
66942
|
}
|
|
66450
66943
|
if (false) {}
|
|
66451
66944
|
|
|
66945
|
+
// packages/cli/src/login.ts
|
|
66946
|
+
init__esm();
|
|
66947
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
66948
|
+
|
|
66949
|
+
// packages/cli/src/session.ts
|
|
66950
|
+
import { execFileSync } from "node:child_process";
|
|
66951
|
+
import {
|
|
66952
|
+
chmodSync,
|
|
66953
|
+
closeSync,
|
|
66954
|
+
existsSync as existsSync3,
|
|
66955
|
+
lstatSync,
|
|
66956
|
+
mkdirSync as mkdirSync2,
|
|
66957
|
+
openSync,
|
|
66958
|
+
readFileSync as readFileSync4,
|
|
66959
|
+
renameSync,
|
|
66960
|
+
rmSync,
|
|
66961
|
+
writeSync
|
|
66962
|
+
} from "node:fs";
|
|
66963
|
+
import { homedir as homedir2 } from "node:os";
|
|
66964
|
+
import { join as join3 } from "node:path";
|
|
66965
|
+
var NOT_SIGNED_IN2 = "Not signed in. Run: npx -y @countersign-hub/cli login";
|
|
66966
|
+
var securityRun = (args, input2) => execFileSync("/usr/bin/security", args, { input: input2, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
66967
|
+
function parse6(text) {
|
|
66968
|
+
try {
|
|
66969
|
+
const value = JSON.parse(text);
|
|
66970
|
+
if (typeof value.token === "string" && typeof value.hub === "string" && typeof value.address === "string" && typeof value.expiresAt === "number") {
|
|
66971
|
+
return value;
|
|
66972
|
+
}
|
|
66973
|
+
} catch {}
|
|
66974
|
+
return null;
|
|
66975
|
+
}
|
|
66976
|
+
function refuse(path) {
|
|
66977
|
+
process.stderr.write(`countersign: refusing the session at ${path}: symlink, non-regular file or unsafe permissions.
|
|
66978
|
+
`);
|
|
66979
|
+
return null;
|
|
66980
|
+
}
|
|
66981
|
+
function fileSessionBackend(dir = join3(homedir2(), ".config", "countersign"), platform = process.platform) {
|
|
66982
|
+
const path = join3(dir, "session.json");
|
|
66983
|
+
return {
|
|
66984
|
+
kind: "file",
|
|
66985
|
+
where: () => path,
|
|
66986
|
+
read() {
|
|
66987
|
+
try {
|
|
66988
|
+
if (lstatSync(dir).isSymbolicLink())
|
|
66989
|
+
return refuse(dir);
|
|
66990
|
+
} catch {
|
|
66991
|
+
return null;
|
|
66992
|
+
}
|
|
66993
|
+
try {
|
|
66994
|
+
const info = lstatSync(path);
|
|
66995
|
+
const unsafeMode = platform !== "win32" && (info.mode & 63) !== 0;
|
|
66996
|
+
if (info.isSymbolicLink() || !info.isFile() || unsafeMode)
|
|
66997
|
+
return refuse(path);
|
|
66998
|
+
} catch {
|
|
66999
|
+
return null;
|
|
67000
|
+
}
|
|
67001
|
+
try {
|
|
67002
|
+
return parse6(readFileSync4(path, "utf8"));
|
|
67003
|
+
} catch {
|
|
67004
|
+
return null;
|
|
67005
|
+
}
|
|
67006
|
+
},
|
|
67007
|
+
write(session) {
|
|
67008
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
67009
|
+
chmodSync(dir, 448);
|
|
67010
|
+
const tmp = `${path}.tmp`;
|
|
67011
|
+
rmSync(tmp, { force: true });
|
|
67012
|
+
const fd = openSync(tmp, "wx", 384);
|
|
67013
|
+
try {
|
|
67014
|
+
writeSync(fd, `${JSON.stringify(session)}
|
|
67015
|
+
`);
|
|
67016
|
+
} finally {
|
|
67017
|
+
closeSync(fd);
|
|
67018
|
+
}
|
|
67019
|
+
renameSync(tmp, path);
|
|
67020
|
+
},
|
|
67021
|
+
clear() {
|
|
67022
|
+
rmSync(path, { force: true });
|
|
67023
|
+
}
|
|
67024
|
+
};
|
|
67025
|
+
}
|
|
67026
|
+
function keychainSessionBackend(run = securityRun) {
|
|
67027
|
+
return {
|
|
67028
|
+
kind: "keychain",
|
|
67029
|
+
where: () => "the macOS login Keychain (service countersign, account session)",
|
|
67030
|
+
read() {
|
|
67031
|
+
try {
|
|
67032
|
+
const hex3 = run(["find-generic-password", "-s", "countersign", "-a", "session", "-w"]).trim();
|
|
67033
|
+
return hex3 === "" ? null : parse6(Buffer.from(hex3, "hex").toString("utf8"));
|
|
67034
|
+
} catch {
|
|
67035
|
+
return null;
|
|
67036
|
+
}
|
|
67037
|
+
},
|
|
67038
|
+
write(session) {
|
|
67039
|
+
const hex3 = Buffer.from(JSON.stringify(session), "utf8").toString("hex");
|
|
67040
|
+
run(["-i"], `add-generic-password -U -s countersign -a session -w ${hex3}
|
|
67041
|
+
`);
|
|
67042
|
+
},
|
|
67043
|
+
clear() {
|
|
67044
|
+
try {
|
|
67045
|
+
run(["delete-generic-password", "-s", "countersign", "-a", "session"]);
|
|
67046
|
+
} catch {}
|
|
67047
|
+
}
|
|
67048
|
+
};
|
|
67049
|
+
}
|
|
67050
|
+
function defaultSessionBackend(env = process.env) {
|
|
67051
|
+
if (env.COUNTERSIGN_KEYSTORE === "file")
|
|
67052
|
+
return fileSessionBackend();
|
|
67053
|
+
if (process.platform === "darwin" && existsSync3("/usr/bin/security"))
|
|
67054
|
+
return keychainSessionBackend();
|
|
67055
|
+
return fileSessionBackend();
|
|
67056
|
+
}
|
|
67057
|
+
function loadSession(backend = defaultSessionBackend(), now = Math.floor(Date.now() / 1000)) {
|
|
67058
|
+
const session = backend.read();
|
|
67059
|
+
return session !== null && session.expiresAt > now ? session : null;
|
|
67060
|
+
}
|
|
67061
|
+
|
|
67062
|
+
// packages/cli/src/login.ts
|
|
67063
|
+
var EXPIRED = `The login expired. Run countersign login again.
|
|
67064
|
+
`;
|
|
67065
|
+
var CONSOLE_ORIGIN = "https://web-production-a58de.up.railway.app";
|
|
67066
|
+
var UNSAFE_URL_CHARACTERS = /[&|^<>"%`;\s]/;
|
|
67067
|
+
var HUB_REFUSED = "Refused: the countersign hub must be https.";
|
|
67068
|
+
function safeConsoleUrl(url2, consoleOrigin = CONSOLE_ORIGIN) {
|
|
67069
|
+
if (UNSAFE_URL_CHARACTERS.test(url2))
|
|
67070
|
+
return null;
|
|
67071
|
+
let parsed;
|
|
67072
|
+
try {
|
|
67073
|
+
parsed = new URL(url2);
|
|
67074
|
+
} catch {
|
|
67075
|
+
return null;
|
|
67076
|
+
}
|
|
67077
|
+
if (parsed.protocol !== "https:")
|
|
67078
|
+
return null;
|
|
67079
|
+
if (parsed.origin !== consoleOrigin)
|
|
67080
|
+
return null;
|
|
67081
|
+
return url2;
|
|
67082
|
+
}
|
|
67083
|
+
function assertHubUrl(hub) {
|
|
67084
|
+
let parsed;
|
|
67085
|
+
try {
|
|
67086
|
+
parsed = new URL(hub);
|
|
67087
|
+
} catch {
|
|
67088
|
+
throw new Error(HUB_REFUSED);
|
|
67089
|
+
}
|
|
67090
|
+
const local = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]");
|
|
67091
|
+
if (parsed.protocol !== "https:" && !local)
|
|
67092
|
+
throw new Error(HUB_REFUSED);
|
|
67093
|
+
return parsed.origin;
|
|
67094
|
+
}
|
|
67095
|
+
function defaultOpen(url2) {
|
|
67096
|
+
const windows = process.platform === "win32";
|
|
67097
|
+
const command = windows ? "rundll32" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
67098
|
+
const args = windows ? ["url.dll,FileProtocolHandler", url2] : [url2];
|
|
67099
|
+
const child = spawn3(command, args, { detached: true, stdio: "ignore", shell: false });
|
|
67100
|
+
child.on("error", () => {});
|
|
67101
|
+
child.unref();
|
|
67102
|
+
}
|
|
67103
|
+
function hubOrRefuse(hub) {
|
|
67104
|
+
try {
|
|
67105
|
+
return assertHubUrl(hub);
|
|
67106
|
+
} catch (error62) {
|
|
67107
|
+
process.stderr.write(`${error62 instanceof Error ? error62.message : String(error62)}
|
|
67108
|
+
`);
|
|
67109
|
+
process.exitCode = 1;
|
|
67110
|
+
return null;
|
|
67111
|
+
}
|
|
67112
|
+
}
|
|
67113
|
+
function expired() {
|
|
67114
|
+
process.stderr.write(EXPIRED);
|
|
67115
|
+
process.exitCode = 1;
|
|
67116
|
+
}
|
|
67117
|
+
async function runLogin(_args, deps) {
|
|
67118
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67119
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
67120
|
+
const now = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
67121
|
+
const open2 = deps.open ?? defaultOpen;
|
|
67122
|
+
const hub = hubOrRefuse(deps.hub);
|
|
67123
|
+
if (hub === null)
|
|
67124
|
+
return;
|
|
67125
|
+
let start;
|
|
67126
|
+
try {
|
|
67127
|
+
const response = await fetchImpl(`${hub}/cli/login/start`, { method: "POST" });
|
|
67128
|
+
if (!response.ok)
|
|
67129
|
+
throw new Error("start refused");
|
|
67130
|
+
start = await response.json();
|
|
67131
|
+
} catch {
|
|
67132
|
+
process.stderr.write(`The login could not start. Run countersign login again.
|
|
67133
|
+
`);
|
|
67134
|
+
process.exitCode = 1;
|
|
67135
|
+
return;
|
|
67136
|
+
}
|
|
67137
|
+
deps.write(`Open this link and sign in: ${start.verifyUrl}
|
|
67138
|
+
`);
|
|
67139
|
+
deps.write(`The page will show this code: ${start.code}
|
|
67140
|
+
`);
|
|
67141
|
+
const safeUrl = safeConsoleUrl(start.verifyUrl);
|
|
67142
|
+
if (safeUrl !== null) {
|
|
67143
|
+
try {
|
|
67144
|
+
open2(safeUrl);
|
|
67145
|
+
} catch {}
|
|
67146
|
+
}
|
|
67147
|
+
const interval = Number.isFinite(start.interval) && start.interval > 0 ? start.interval : 5;
|
|
67148
|
+
while (now() < start.expiresAt) {
|
|
67149
|
+
await sleep(interval * 1000);
|
|
67150
|
+
if (now() >= start.expiresAt)
|
|
67151
|
+
break;
|
|
67152
|
+
let poll2;
|
|
67153
|
+
try {
|
|
67154
|
+
const response = await fetchImpl(`${hub}/cli/login/poll`, {
|
|
67155
|
+
method: "POST",
|
|
67156
|
+
headers: { "content-type": "application/json" },
|
|
67157
|
+
body: JSON.stringify({ deviceSecret: start.deviceSecret })
|
|
67158
|
+
});
|
|
67159
|
+
if (response.status === 410)
|
|
67160
|
+
return expired();
|
|
67161
|
+
if (!response.ok)
|
|
67162
|
+
return expired();
|
|
67163
|
+
poll2 = await response.json();
|
|
67164
|
+
} catch {
|
|
67165
|
+
continue;
|
|
67166
|
+
}
|
|
67167
|
+
if (poll2.status === "approved") {
|
|
67168
|
+
const session = {
|
|
67169
|
+
token: poll2.sessionToken,
|
|
67170
|
+
hub,
|
|
67171
|
+
address: poll2.address,
|
|
67172
|
+
expiresAt: poll2.expiresAt
|
|
67173
|
+
};
|
|
67174
|
+
deps.backend.write(session);
|
|
67175
|
+
deps.write(`Signed in. Your agent wallet: ${poll2.address}
|
|
67176
|
+
`);
|
|
67177
|
+
deps.write(`Fund it: send testnet USDC to ${poll2.address} (Circle faucet: https://faucet.circle.com).
|
|
67178
|
+
`);
|
|
67179
|
+
deps.write(`For Whitechain, get test WBT for gas at https://faucet.testnet.whitechain.io.
|
|
67180
|
+
`);
|
|
67181
|
+
deps.write(`The session lasts 7 days; countersign logout ends it.
|
|
67182
|
+
`);
|
|
67183
|
+
return;
|
|
67184
|
+
}
|
|
67185
|
+
if (poll2.status !== "pending")
|
|
67186
|
+
return expired();
|
|
67187
|
+
}
|
|
67188
|
+
expired();
|
|
67189
|
+
}
|
|
67190
|
+
async function runLogout(_args, deps) {
|
|
67191
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67192
|
+
const session = loadSession(deps.backend);
|
|
67193
|
+
if (session === null) {
|
|
67194
|
+
deps.backend.clear();
|
|
67195
|
+
deps.write(`Not signed in.
|
|
67196
|
+
`);
|
|
67197
|
+
return;
|
|
67198
|
+
}
|
|
67199
|
+
let confirmed = false;
|
|
67200
|
+
try {
|
|
67201
|
+
assertHubUrl(session.hub);
|
|
67202
|
+
const response = await fetchImpl(`${session.hub}/cli/logout`, {
|
|
67203
|
+
method: "POST",
|
|
67204
|
+
headers: { Authorization: `Bearer ${session.token}` }
|
|
67205
|
+
});
|
|
67206
|
+
confirmed = response.ok;
|
|
67207
|
+
} catch {}
|
|
67208
|
+
deps.backend.clear();
|
|
67209
|
+
if (confirmed) {
|
|
67210
|
+
deps.write(`Signed out.
|
|
67211
|
+
`);
|
|
67212
|
+
} else {
|
|
67213
|
+
const expiry = new Date(session.expiresAt * 1000).toISOString();
|
|
67214
|
+
deps.write(`Signed out here; the hub did not confirm, so the session stays valid until ${expiry}.
|
|
67215
|
+
`);
|
|
67216
|
+
}
|
|
67217
|
+
}
|
|
67218
|
+
async function runWhoami(_args, deps) {
|
|
67219
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67220
|
+
const readBalances = deps.balances ?? defaultBalances;
|
|
67221
|
+
const session = loadSession(deps.backend);
|
|
67222
|
+
if (session === null) {
|
|
67223
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67224
|
+
`);
|
|
67225
|
+
process.exitCode = 1;
|
|
67226
|
+
return;
|
|
67227
|
+
}
|
|
67228
|
+
try {
|
|
67229
|
+
assertHubUrl(session.hub);
|
|
67230
|
+
} catch {
|
|
67231
|
+
deps.backend.clear();
|
|
67232
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67233
|
+
`);
|
|
67234
|
+
process.exitCode = 1;
|
|
67235
|
+
return;
|
|
67236
|
+
}
|
|
67237
|
+
let response;
|
|
67238
|
+
try {
|
|
67239
|
+
response = await fetchImpl(`${session.hub}/cli/session`, {
|
|
67240
|
+
headers: { Authorization: `Bearer ${session.token}` }
|
|
67241
|
+
});
|
|
67242
|
+
} catch {
|
|
67243
|
+
process.stderr.write(`countersign whoami could not reach the hub.
|
|
67244
|
+
`);
|
|
67245
|
+
process.exitCode = 1;
|
|
67246
|
+
return;
|
|
67247
|
+
}
|
|
67248
|
+
if (response.status === 401) {
|
|
67249
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67250
|
+
`);
|
|
67251
|
+
process.exitCode = 1;
|
|
67252
|
+
return;
|
|
67253
|
+
}
|
|
67254
|
+
if (!response.ok) {
|
|
67255
|
+
process.stderr.write(`countersign whoami could not read the session.
|
|
67256
|
+
`);
|
|
67257
|
+
process.exitCode = 1;
|
|
67258
|
+
return;
|
|
67259
|
+
}
|
|
67260
|
+
const body = await response.json();
|
|
67261
|
+
deps.write(`Signed in as ${body.address} until ${new Date(body.expiresAt * 1000).toISOString()}
|
|
67262
|
+
`);
|
|
67263
|
+
deps.write(`${await readBalances(body.address)}
|
|
67264
|
+
`);
|
|
67265
|
+
}
|
|
67266
|
+
var BALANCE_CHAINS = [
|
|
67267
|
+
{
|
|
67268
|
+
name: "Arc",
|
|
67269
|
+
symbol: "USDC",
|
|
67270
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
67271
|
+
rpc: "https://rpc.testnet.arc.network"
|
|
67272
|
+
},
|
|
67273
|
+
{
|
|
67274
|
+
name: "Whitechain",
|
|
67275
|
+
symbol: "USDT",
|
|
67276
|
+
token: "0xcedfB56113143d55b2358b8CFbB0dEB5Ad2f55a7",
|
|
67277
|
+
rpc: "https://rpc.ankr.com/whitechain_testnet"
|
|
67278
|
+
}
|
|
67279
|
+
];
|
|
67280
|
+
async function defaultBalances(address) {
|
|
67281
|
+
const parts = await Promise.all(BALANCE_CHAINS.map(async (chain) => {
|
|
67282
|
+
try {
|
|
67283
|
+
const client = createPublicClient({ transport: http(chain.rpc) });
|
|
67284
|
+
const balance = await client.readContract({
|
|
67285
|
+
address: chain.token,
|
|
67286
|
+
abi: erc20Abi,
|
|
67287
|
+
functionName: "balanceOf",
|
|
67288
|
+
args: [address]
|
|
67289
|
+
});
|
|
67290
|
+
return `${formatUnits3(balance, 6)} ${chain.symbol} on ${chain.name}`;
|
|
67291
|
+
} catch {
|
|
67292
|
+
return `unavailable ${chain.symbol} on ${chain.name}`;
|
|
67293
|
+
}
|
|
67294
|
+
}));
|
|
67295
|
+
return parts.join(", ");
|
|
67296
|
+
}
|
|
67297
|
+
|
|
66452
67298
|
// packages/cli/src/cli.ts
|
|
66453
|
-
var VERSION = "0.1.
|
|
67299
|
+
var VERSION = "0.1.2";
|
|
67300
|
+
var DEFAULT_HUB3 = "https://hub-production-e85e.up.railway.app";
|
|
66454
67301
|
var USAGE2 = `countersign ${VERSION}
|
|
66455
67302
|
|
|
66456
|
-
Sell. The runner dials out to the hub, so you open no port.
|
|
67303
|
+
Sell. The runner dials out to the hub, so you open no port.
|
|
66457
67304
|
countersign sell skill <SKILL.md> --hub <url> --price <atomic> [runner flags]
|
|
66458
67305
|
countersign sell openapi --spec <spec.json> --operation <id> --hub <url> --price <atomic> [--base-url <url>] [runner flags]
|
|
66459
67306
|
Add --publish-only to list the offer without serving it.
|
|
66460
67307
|
|
|
66461
|
-
Buy.
|
|
67308
|
+
Buy.
|
|
66462
67309
|
countersign discover|buy|envelope|journal [--hub <url>] [--state <dir>] ...
|
|
66463
67310
|
|
|
67311
|
+
Sign in, and check the session:
|
|
67312
|
+
countersign login|logout|whoami
|
|
67313
|
+
|
|
66464
67314
|
Verify a slip offline:
|
|
66465
67315
|
countersign verify <slip.json> [--rpc <url>]
|
|
66466
67316
|
|
|
66467
67317
|
The buyer MCP server over stdio:
|
|
66468
67318
|
countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
67319
|
+
|
|
67320
|
+
Start here: countersign login, then fund the printed address, then buy or sell.
|
|
67321
|
+
The default hub is ${DEFAULT_HUB3}.
|
|
66469
67322
|
`;
|
|
67323
|
+
var COMMAND_USAGE = {
|
|
67324
|
+
login: `Usage: countersign login
|
|
67325
|
+
Opens a sign-in link; your agent wallet is a Privy server wallet, so no key is ever on this machine.
|
|
67326
|
+
`,
|
|
67327
|
+
logout: `Usage: countersign logout
|
|
67328
|
+
Ends the session on the hub and removes the stored token.
|
|
67329
|
+
`,
|
|
67330
|
+
whoami: `Usage: countersign whoami
|
|
67331
|
+
Shows the signed-in address, the session expiry and testnet balances.
|
|
67332
|
+
`,
|
|
67333
|
+
sell: `Usage: countersign sell skill <SKILL.md> --hub <url> --price <atomic> [runner flags]
|
|
67334
|
+
countersign sell openapi --spec <spec.json> --operation <id> --hub <url> --price <atomic> [--base-url <url>] [runner flags]
|
|
67335
|
+
Add --publish-only to list the offer without serving it.
|
|
67336
|
+
`,
|
|
67337
|
+
discover: `Usage: countersign discover [--hub <url>] [--state <dir>] [--catalogue <url|circle> [query] [--category <c>] [--limit <n>]]
|
|
67338
|
+
`,
|
|
67339
|
+
buy: `Usage: countersign buy <offerHash|callUrl> --input '<json>' [--approve] [--rail <id>] [--approvals hub] [--hub <url>] [--state <dir>]
|
|
67340
|
+
`,
|
|
67341
|
+
envelope: `Usage: countersign envelope show|set [--hub <url>] [--state <dir>]
|
|
67342
|
+
`,
|
|
67343
|
+
journal: `Usage: countersign journal [--hub <url>] [--state <dir>]
|
|
67344
|
+
`,
|
|
67345
|
+
verify: `Usage: countersign verify <slip.json> [--rpc <url>] [--mirror <url>]
|
|
67346
|
+
`,
|
|
67347
|
+
mcp: `Usage: countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
67348
|
+
`
|
|
67349
|
+
};
|
|
66470
67350
|
var BUYER_COMMANDS = new Set(["discover", "buy", "envelope", "journal"]);
|
|
67351
|
+
function withHub(args2, env = process.env) {
|
|
67352
|
+
for (const arg of args2) {
|
|
67353
|
+
if (arg === "--hub" || arg.startsWith("--hub="))
|
|
67354
|
+
return args2;
|
|
67355
|
+
}
|
|
67356
|
+
const hub = env.CS_HUB !== undefined && env.CS_HUB !== "" ? env.CS_HUB : DEFAULT_HUB3;
|
|
67357
|
+
return [...args2, "--hub", hub];
|
|
67358
|
+
}
|
|
67359
|
+
function hubValue(args2, env = process.env) {
|
|
67360
|
+
const settled = withHub(args2, env);
|
|
67361
|
+
const last = settled.at(-1) ?? DEFAULT_HUB3;
|
|
67362
|
+
return last.startsWith("--hub=") ? last.slice("--hub=".length) : last;
|
|
67363
|
+
}
|
|
67364
|
+
function useSession(env = process.env) {
|
|
67365
|
+
if (env.CS_BUYER_KEY !== undefined || env.CS_SELLER_KEY !== undefined)
|
|
67366
|
+
return true;
|
|
67367
|
+
const session = loadSession();
|
|
67368
|
+
if (session === null)
|
|
67369
|
+
return false;
|
|
67370
|
+
let hub;
|
|
67371
|
+
try {
|
|
67372
|
+
hub = assertHubUrl(session.hub);
|
|
67373
|
+
} catch {
|
|
67374
|
+
return false;
|
|
67375
|
+
}
|
|
67376
|
+
env.CS_SESSION = session.token;
|
|
67377
|
+
env.CS_HUB = hub;
|
|
67378
|
+
return true;
|
|
67379
|
+
}
|
|
66471
67380
|
var DEFAULT_DEPS = {
|
|
66472
|
-
runner: (argv) =>
|
|
66473
|
-
|
|
67381
|
+
runner: async (argv) => {
|
|
67382
|
+
if (!useSession())
|
|
67383
|
+
return requireLogin();
|
|
67384
|
+
await main(withHub(argv));
|
|
67385
|
+
},
|
|
67386
|
+
loadBuyer: async () => {
|
|
67387
|
+
if (!useSession() && needsSession())
|
|
67388
|
+
return requireLogin();
|
|
67389
|
+
setArgv(withHub(process.argv.slice(2)));
|
|
67390
|
+
await Promise.resolve().then(() => (init_cli(), exports_cli));
|
|
67391
|
+
},
|
|
66474
67392
|
loadVerify: () => init_cli2().then(() => exports_cli2),
|
|
66475
|
-
loadMcp:
|
|
67393
|
+
loadMcp: async () => {
|
|
67394
|
+
useSession();
|
|
67395
|
+
return Promise.resolve().then(() => (init_main(), exports_main));
|
|
67396
|
+
}
|
|
66476
67397
|
};
|
|
66477
67398
|
function runnerArgs(rest) {
|
|
66478
67399
|
const publishOnly = rest.includes("--publish-only");
|
|
@@ -66514,10 +67435,29 @@ async function run(argv, deps = DEFAULT_DEPS) {
|
|
|
66514
67435
|
`);
|
|
66515
67436
|
return;
|
|
66516
67437
|
}
|
|
67438
|
+
const commandUsage = COMMAND_USAGE[command];
|
|
67439
|
+
if (commandUsage !== undefined && (rest.includes("--help") || rest.includes("-h"))) {
|
|
67440
|
+
process.stdout.write(commandUsage);
|
|
67441
|
+
return;
|
|
67442
|
+
}
|
|
67443
|
+
if (command === "login" || command === "logout" || command === "whoami") {
|
|
67444
|
+
const loginDeps = {
|
|
67445
|
+
backend: defaultSessionBackend(),
|
|
67446
|
+
hub: hubValue(rest),
|
|
67447
|
+
write: (t) => process.stdout.write(t)
|
|
67448
|
+
};
|
|
67449
|
+
if (command === "login")
|
|
67450
|
+
await runLogin(rest, loginDeps);
|
|
67451
|
+
else if (command === "logout")
|
|
67452
|
+
await runLogout(rest, loginDeps);
|
|
67453
|
+
else
|
|
67454
|
+
await runWhoami(rest, loginDeps);
|
|
67455
|
+
return;
|
|
67456
|
+
}
|
|
66517
67457
|
if (command === "sell") {
|
|
66518
67458
|
const mapped = runnerArgs(rest);
|
|
66519
67459
|
if (!mapped.ok)
|
|
66520
|
-
return
|
|
67460
|
+
return refuse3(mapped.error);
|
|
66521
67461
|
await deps.runner(mapped.args);
|
|
66522
67462
|
return;
|
|
66523
67463
|
}
|
|
@@ -66536,20 +67476,29 @@ async function run(argv, deps = DEFAULT_DEPS) {
|
|
|
66536
67476
|
try {
|
|
66537
67477
|
loaded = await deps.loadMcp();
|
|
66538
67478
|
} catch {
|
|
66539
|
-
return
|
|
67479
|
+
return refuse3("countersign mcp could not load its MCP server.");
|
|
66540
67480
|
}
|
|
66541
67481
|
const main4 = isRecord10(loaded) ? loaded.main : undefined;
|
|
66542
67482
|
if (typeof main4 !== "function")
|
|
66543
|
-
return
|
|
67483
|
+
return refuse3("The MCP server has no main(argv) export.");
|
|
66544
67484
|
await main4(rest);
|
|
66545
67485
|
return;
|
|
66546
67486
|
}
|
|
66547
|
-
return
|
|
67487
|
+
return refuse3(`countersign: unknown command '${command}'.`);
|
|
66548
67488
|
}
|
|
66549
67489
|
function setArgv(args2) {
|
|
66550
67490
|
process.argv = [process.argv[0] ?? "node", "countersign", ...args2];
|
|
66551
67491
|
}
|
|
66552
|
-
function
|
|
67492
|
+
function needsSession() {
|
|
67493
|
+
const [command, verb] = process.argv.slice(2);
|
|
67494
|
+
return command === "buy" || command === "journal" || command === "envelope" && verb === "set";
|
|
67495
|
+
}
|
|
67496
|
+
function requireLogin() {
|
|
67497
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67498
|
+
`);
|
|
67499
|
+
process.exitCode = 1;
|
|
67500
|
+
}
|
|
67501
|
+
function refuse3(message) {
|
|
66553
67502
|
process.stderr.write(`${message}
|
|
66554
67503
|
|
|
66555
67504
|
${USAGE2}`);
|
|
@@ -66566,4 +67515,4 @@ run(process.argv.slice(2)).catch((error62) => {
|
|
|
66566
67515
|
process.exitCode = 1;
|
|
66567
67516
|
});
|
|
66568
67517
|
|
|
66569
|
-
//# debugId=
|
|
67518
|
+
//# debugId=2C47F561789D7EFC64756E2164756E21
|