@countersign-hub/cli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +97 -0
- package/dist/bin.js +1062 -128
- 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,161 @@ var init_payer2 = __esm(() => {
|
|
|
61269
61296
|
init_known_rails();
|
|
61270
61297
|
});
|
|
61271
61298
|
|
|
61299
|
+
// packages/buyer/src/remote-signer.ts
|
|
61300
|
+
function assertHubOrigin(hub) {
|
|
61301
|
+
let url2;
|
|
61302
|
+
try {
|
|
61303
|
+
url2 = new URL(hub);
|
|
61304
|
+
} catch {
|
|
61305
|
+
throw new Error(HTTPS_ONLY);
|
|
61306
|
+
}
|
|
61307
|
+
if (url2.protocol === "https:")
|
|
61308
|
+
return;
|
|
61309
|
+
if (url2.protocol === "http:" && LOCAL_HOSTS.has(url2.hostname))
|
|
61310
|
+
return;
|
|
61311
|
+
throw new Error(HTTPS_ONLY);
|
|
61312
|
+
}
|
|
61313
|
+
function decimalStrings(value) {
|
|
61314
|
+
if (typeof value === "bigint")
|
|
61315
|
+
return value.toString(10);
|
|
61316
|
+
if (Array.isArray(value))
|
|
61317
|
+
return value.map((entry) => decimalStrings(entry));
|
|
61318
|
+
if (value !== null && typeof value === "object") {
|
|
61319
|
+
const copy = {};
|
|
61320
|
+
for (const [key, entry] of Object.entries(value))
|
|
61321
|
+
copy[key] = decimalStrings(entry);
|
|
61322
|
+
return copy;
|
|
61323
|
+
}
|
|
61324
|
+
return value;
|
|
61325
|
+
}
|
|
61326
|
+
function messageOf4(body) {
|
|
61327
|
+
if (body === null || typeof body !== "object")
|
|
61328
|
+
return;
|
|
61329
|
+
const message = body.message;
|
|
61330
|
+
return typeof message === "string" ? message : undefined;
|
|
61331
|
+
}
|
|
61332
|
+
function remoteAccount(session, opts = {}) {
|
|
61333
|
+
assertHubOrigin(session.hub);
|
|
61334
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
61335
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
61336
|
+
const signTypedData4 = async (parameters) => {
|
|
61337
|
+
const typedData = parameters;
|
|
61338
|
+
const types3 = {};
|
|
61339
|
+
for (const [name, fields] of Object.entries(typedData.types)) {
|
|
61340
|
+
if (name !== "EIP712Domain")
|
|
61341
|
+
types3[name] = fields;
|
|
61342
|
+
}
|
|
61343
|
+
const requestBody = JSON.stringify({
|
|
61344
|
+
kind: "typed-data",
|
|
61345
|
+
typedData: {
|
|
61346
|
+
domain: decimalStrings(typedData.domain),
|
|
61347
|
+
types: decimalStrings(types3),
|
|
61348
|
+
primaryType: typedData.primaryType,
|
|
61349
|
+
message: decimalStrings(typedData.message)
|
|
61350
|
+
}
|
|
61351
|
+
});
|
|
61352
|
+
const controller = new AbortController;
|
|
61353
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
61354
|
+
let status;
|
|
61355
|
+
let body;
|
|
61356
|
+
try {
|
|
61357
|
+
const response = await fetchImpl(`${session.hub.replace(/\/+$/, "")}/cli/sign`, {
|
|
61358
|
+
method: "POST",
|
|
61359
|
+
headers: {
|
|
61360
|
+
authorization: `Bearer ${session.token}`,
|
|
61361
|
+
"content-type": "application/json"
|
|
61362
|
+
},
|
|
61363
|
+
body: requestBody,
|
|
61364
|
+
signal: controller.signal
|
|
61365
|
+
});
|
|
61366
|
+
status = response.status;
|
|
61367
|
+
body = await response.json().catch(() => {
|
|
61368
|
+
return;
|
|
61369
|
+
});
|
|
61370
|
+
} catch {
|
|
61371
|
+
throw new Error(NOT_REACHED);
|
|
61372
|
+
} finally {
|
|
61373
|
+
clearTimeout(timer);
|
|
61374
|
+
}
|
|
61375
|
+
if (status === 200) {
|
|
61376
|
+
const result = body;
|
|
61377
|
+
if (typeof result?.address !== "string" || result.address.toLowerCase() !== session.address.toLowerCase()) {
|
|
61378
|
+
throw new Error("The hub signed with another wallet.");
|
|
61379
|
+
}
|
|
61380
|
+
const signature = result.signature;
|
|
61381
|
+
if (typeof signature !== "string" || !SIGNATURE2.test(signature)) {
|
|
61382
|
+
throw new Error(`The hub could not sign (${status}).`);
|
|
61383
|
+
}
|
|
61384
|
+
const signer = await recoverTypedDataAddress2({
|
|
61385
|
+
...parameters,
|
|
61386
|
+
signature
|
|
61387
|
+
});
|
|
61388
|
+
if (signer.toLowerCase() !== session.address.toLowerCase()) {
|
|
61389
|
+
throw new Error("The hub signed with another wallet.");
|
|
61390
|
+
}
|
|
61391
|
+
return signature;
|
|
61392
|
+
}
|
|
61393
|
+
if (status === 401)
|
|
61394
|
+
throw new Error(NOT_SIGNED_IN3);
|
|
61395
|
+
if (status === 403) {
|
|
61396
|
+
const message = messageOf4(body) ?? "the hub refused the request.";
|
|
61397
|
+
throw new Error(`Refused by the hub: ${message}`);
|
|
61398
|
+
}
|
|
61399
|
+
if (status === 502)
|
|
61400
|
+
throw new Error("The hub could not sign (privy-failed).");
|
|
61401
|
+
throw new Error(`The hub could not sign (${status}).`);
|
|
61402
|
+
};
|
|
61403
|
+
const unsupported = async () => {
|
|
61404
|
+
throw new Error(TYPED_DATA_ONLY);
|
|
61405
|
+
};
|
|
61406
|
+
const source = {
|
|
61407
|
+
address: session.address,
|
|
61408
|
+
signMessage: unsupported,
|
|
61409
|
+
signTransaction: unsupported,
|
|
61410
|
+
signTypedData: signTypedData4
|
|
61411
|
+
};
|
|
61412
|
+
return toAccount(source);
|
|
61413
|
+
}
|
|
61414
|
+
async function sessionFromEnv(env = process.env, opts = {}) {
|
|
61415
|
+
const token = env.CS_SESSION;
|
|
61416
|
+
if (token === undefined || token === "")
|
|
61417
|
+
return;
|
|
61418
|
+
const hub = env.CS_HUB ?? DEFAULT_HUB;
|
|
61419
|
+
delete env.CS_SESSION;
|
|
61420
|
+
assertHubOrigin(hub);
|
|
61421
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
61422
|
+
let status;
|
|
61423
|
+
let body;
|
|
61424
|
+
try {
|
|
61425
|
+
const response = await fetchImpl(`${hub.replace(/\/+$/, "")}/cli/session`, {
|
|
61426
|
+
method: "GET",
|
|
61427
|
+
headers: { authorization: `Bearer ${token}` }
|
|
61428
|
+
});
|
|
61429
|
+
status = response.status;
|
|
61430
|
+
body = await response.json().catch(() => {
|
|
61431
|
+
return;
|
|
61432
|
+
});
|
|
61433
|
+
} catch {
|
|
61434
|
+
throw new Error("Could not read the countersign session (no response).");
|
|
61435
|
+
}
|
|
61436
|
+
if (status === 401)
|
|
61437
|
+
return;
|
|
61438
|
+
if (status !== 200)
|
|
61439
|
+
throw new Error(`Could not read the countersign session (${status}).`);
|
|
61440
|
+
const address = body?.address;
|
|
61441
|
+
if (typeof address !== "string" || !isAddress(address)) {
|
|
61442
|
+
throw new Error("The hub returned no valid wallet address.");
|
|
61443
|
+
}
|
|
61444
|
+
return { hub, token, address };
|
|
61445
|
+
}
|
|
61446
|
+
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;
|
|
61447
|
+
var init_remote_signer = __esm(() => {
|
|
61448
|
+
init__esm();
|
|
61449
|
+
init_accounts();
|
|
61450
|
+
SIGNATURE2 = /^0x[0-9a-fA-F]{130}$/;
|
|
61451
|
+
LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
61452
|
+
});
|
|
61453
|
+
|
|
61272
61454
|
// packages/buyer/src/resume.ts
|
|
61273
61455
|
async function readJobStatus(rail2, jobId) {
|
|
61274
61456
|
const client = createPublicClient({ transport: http(rail2.rpcUrl) });
|
|
@@ -61406,27 +61588,27 @@ async function acceptJob(a) {
|
|
|
61406
61588
|
const slip2 = heldSlip(a, jobId);
|
|
61407
61589
|
const known = a.known ?? KNOWN_RAILS;
|
|
61408
61590
|
if (slip2.hash.toLowerCase() !== slipHash(slip2.body).toLowerCase())
|
|
61409
|
-
|
|
61591
|
+
refuse2("The slip's hash does not match its body.");
|
|
61410
61592
|
let seller;
|
|
61411
61593
|
try {
|
|
61412
61594
|
seller = await slipSigner(slip2);
|
|
61413
61595
|
} catch {
|
|
61414
|
-
|
|
61596
|
+
refuse2("The slip's seller signature does not parse.");
|
|
61415
61597
|
}
|
|
61416
61598
|
if (getAddress(seller) !== getAddress(slip2.body.seller))
|
|
61417
|
-
|
|
61599
|
+
refuse2("The slip is not signed by its seller.");
|
|
61418
61600
|
if (slip2.body.jobId.toLowerCase() !== jobId)
|
|
61419
|
-
|
|
61601
|
+
refuse2("The slip is for another job.");
|
|
61420
61602
|
if (getAddress(slip2.body.buyer) !== getAddress(a.signer.address))
|
|
61421
|
-
|
|
61603
|
+
refuse2("The slip names another buyer.");
|
|
61422
61604
|
if (!slip2.body.escrow || slip2.body.chainId === undefined)
|
|
61423
|
-
|
|
61605
|
+
refuse2("The slip is not for an escrow job.");
|
|
61424
61606
|
const rail2 = pinned(known, slip2.body.chainId, slip2.body.escrow);
|
|
61425
61607
|
if (!rail2)
|
|
61426
|
-
|
|
61608
|
+
refuse2("The slip's escrow is not one this agent pins.");
|
|
61427
61609
|
const terms = slip2.payment?.payload?.terms;
|
|
61428
61610
|
if (!terms || jobIdOf(terms, rail2.chainId, rail2.escrow).toLowerCase() !== jobId) {
|
|
61429
|
-
|
|
61611
|
+
refuse2("The slip's countersigned terms do not derive this job on that escrow.");
|
|
61430
61612
|
}
|
|
61431
61613
|
const signature = await a.signer.signTypedData(acceptTypedData(rail2.chainId, rail2.escrow, jobId, slip2.hash));
|
|
61432
61614
|
await a.hub.acceptJob(jobId, signature);
|
|
@@ -61438,7 +61620,7 @@ async function disputeJob(a) {
|
|
|
61438
61620
|
const known = a.known ?? KNOWN_RAILS;
|
|
61439
61621
|
const entries = entriesFor(a.journal, jobId);
|
|
61440
61622
|
if (entries.length === 0)
|
|
61441
|
-
|
|
61623
|
+
refuse2("This agent's journal has no such job.");
|
|
61442
61624
|
const { rail: rail2, status } = await fundedOn(a, jobId, entries, known);
|
|
61443
61625
|
const signature = await a.signer.signTypedData(disputeTypedData(rail2.chainId, rail2.escrow, jobId, status));
|
|
61444
61626
|
let transaction;
|
|
@@ -61465,7 +61647,7 @@ async function disputeJob(a) {
|
|
|
61465
61647
|
async function submitDispute(a, rail2, jobId, status) {
|
|
61466
61648
|
const account = a.account;
|
|
61467
61649
|
if (!account)
|
|
61468
|
-
|
|
61650
|
+
refuse2("The agent key is not available to send the dispute itself.");
|
|
61469
61651
|
return sendDispute(rail2, jobId, status, account, a.transport);
|
|
61470
61652
|
}
|
|
61471
61653
|
async function sendDispute(rail2, jobId, status, account, transport) {
|
|
@@ -61497,7 +61679,7 @@ async function fundedOn(a, jobId, entries, known) {
|
|
|
61497
61679
|
if (recorded) {
|
|
61498
61680
|
const rail2 = pinned(known, recorded.chainId, recorded.escrow);
|
|
61499
61681
|
if (!rail2)
|
|
61500
|
-
|
|
61682
|
+
refuse2("The job's escrow is not one this agent pins.");
|
|
61501
61683
|
return { rail: rail2, status: await disputeStatus(a, rail2, jobId, entries) };
|
|
61502
61684
|
}
|
|
61503
61685
|
const network = entries.find((e) => e.network)?.network;
|
|
@@ -61513,7 +61695,7 @@ async function fundedOn(a, jobId, entries, known) {
|
|
|
61513
61695
|
} catch {}
|
|
61514
61696
|
}
|
|
61515
61697
|
if (holding.length !== 1)
|
|
61516
|
-
|
|
61698
|
+
refuse2("No single pinned escrow holds this job open for this agent.");
|
|
61517
61699
|
return holding[0];
|
|
61518
61700
|
}
|
|
61519
61701
|
async function disputeStatus(a, rail2, jobId, entries) {
|
|
@@ -61529,11 +61711,11 @@ async function disputeStatus(a, rail2, jobId, entries) {
|
|
|
61529
61711
|
function heldSlip(a, jobId) {
|
|
61530
61712
|
const entry = [...entriesFor(a.journal, jobId)].reverse().find((e) => e.slipHash);
|
|
61531
61713
|
if (!entry?.slipHash)
|
|
61532
|
-
|
|
61714
|
+
refuse2("This agent holds no slip for this job.");
|
|
61533
61715
|
try {
|
|
61534
61716
|
return a.state.loadSlip(entry.slipHash);
|
|
61535
61717
|
} catch {
|
|
61536
|
-
|
|
61718
|
+
refuse2("This agent holds no slip for this job.");
|
|
61537
61719
|
}
|
|
61538
61720
|
}
|
|
61539
61721
|
function entriesFor(journal, jobId) {
|
|
@@ -61554,7 +61736,7 @@ function record3(a, jobId, entries) {
|
|
|
61554
61736
|
function pinned(known, chainId, escrow2) {
|
|
61555
61737
|
return known.find((rail2) => rail2.chainId === chainId && rail2.escrow.toLowerCase() === escrow2.toLowerCase());
|
|
61556
61738
|
}
|
|
61557
|
-
function
|
|
61739
|
+
function refuse2(message) {
|
|
61558
61740
|
throw new ReviewError(`Refused. ${message}`);
|
|
61559
61741
|
}
|
|
61560
61742
|
var ReviewError, DISPUTE_ABI, DISPUTABLE;
|
|
@@ -61584,65 +61766,65 @@ var init_review = __esm(() => {
|
|
|
61584
61766
|
|
|
61585
61767
|
// packages/buyer/src/state.ts
|
|
61586
61768
|
import {
|
|
61587
|
-
chmodSync,
|
|
61588
|
-
closeSync as
|
|
61589
|
-
existsSync as
|
|
61590
|
-
mkdirSync as
|
|
61591
|
-
openSync as
|
|
61592
|
-
readFileSync as
|
|
61769
|
+
chmodSync as chmodSync2,
|
|
61770
|
+
closeSync as closeSync3,
|
|
61771
|
+
existsSync as existsSync5,
|
|
61772
|
+
mkdirSync as mkdirSync4,
|
|
61773
|
+
openSync as openSync3,
|
|
61774
|
+
readFileSync as readFileSync6,
|
|
61593
61775
|
unlinkSync as unlinkSync2,
|
|
61594
61776
|
writeFileSync as writeFileSync2,
|
|
61595
|
-
writeSync as
|
|
61777
|
+
writeSync as writeSync3
|
|
61596
61778
|
} from "node:fs";
|
|
61597
|
-
import { homedir as
|
|
61598
|
-
import { join as
|
|
61779
|
+
import { homedir as homedir3 } from "node:os";
|
|
61780
|
+
import { join as join4 } from "node:path";
|
|
61599
61781
|
|
|
61600
61782
|
class State {
|
|
61601
61783
|
dir;
|
|
61602
61784
|
constructor(dir) {
|
|
61603
|
-
this.dir = dir ??
|
|
61785
|
+
this.dir = dir ?? join4(homedir3(), ".countersign");
|
|
61604
61786
|
}
|
|
61605
61787
|
get envelopePath() {
|
|
61606
|
-
return
|
|
61788
|
+
return join4(this.dir, "envelope.json");
|
|
61607
61789
|
}
|
|
61608
61790
|
get journalPath() {
|
|
61609
|
-
return
|
|
61791
|
+
return join4(this.dir, "journal.jsonl");
|
|
61610
61792
|
}
|
|
61611
61793
|
get railsPath() {
|
|
61612
|
-
return
|
|
61794
|
+
return join4(this.dir, "rails.json");
|
|
61613
61795
|
}
|
|
61614
61796
|
get consumedApprovalsPath() {
|
|
61615
|
-
return
|
|
61797
|
+
return join4(this.dir, "approvals-consumed.json");
|
|
61616
61798
|
}
|
|
61617
61799
|
slipPath(hash4) {
|
|
61618
|
-
return
|
|
61800
|
+
return join4(this.dir, "slips", `${hash4}.json`);
|
|
61619
61801
|
}
|
|
61620
61802
|
loadEnvelope() {
|
|
61621
|
-
if (!
|
|
61803
|
+
if (!existsSync5(this.envelopePath)) {
|
|
61622
61804
|
throw new Error(`No envelope at ${this.envelopePath}. Create one with: countersign envelope set --cap <usd> --per-merchant <usd>`);
|
|
61623
61805
|
}
|
|
61624
|
-
return JSON.parse(
|
|
61806
|
+
return JSON.parse(readFileSync6(this.envelopePath, "utf8"));
|
|
61625
61807
|
}
|
|
61626
61808
|
saveEnvelope(env) {
|
|
61627
|
-
|
|
61809
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
61628
61810
|
writeFileSync2(this.envelopePath, `${JSON.stringify(env, null, 2)}
|
|
61629
61811
|
`);
|
|
61630
61812
|
}
|
|
61631
61813
|
loadRails() {
|
|
61632
|
-
if (!
|
|
61814
|
+
if (!existsSync5(this.railsPath))
|
|
61633
61815
|
return [];
|
|
61634
|
-
const value = JSON.parse(
|
|
61816
|
+
const value = JSON.parse(readFileSync6(this.railsPath, "utf8"));
|
|
61635
61817
|
if (!Array.isArray(value))
|
|
61636
61818
|
throw new Error(`${this.railsPath} must hold a JSON array of known rails.`);
|
|
61637
61819
|
return value;
|
|
61638
61820
|
}
|
|
61639
61821
|
loadSlip(hash4) {
|
|
61640
|
-
return JSON.parse(
|
|
61822
|
+
return JSON.parse(readFileSync6(this.slipPath(hash4), "utf8"));
|
|
61641
61823
|
}
|
|
61642
61824
|
loadConsumedApprovals() {
|
|
61643
|
-
if (!
|
|
61825
|
+
if (!existsSync5(this.consumedApprovalsPath))
|
|
61644
61826
|
return [];
|
|
61645
|
-
const value = JSON.parse(
|
|
61827
|
+
const value = JSON.parse(readFileSync6(this.consumedApprovalsPath, "utf8"));
|
|
61646
61828
|
if (!Array.isArray(value)) {
|
|
61647
61829
|
throw new Error(`${this.consumedApprovalsPath} must hold a JSON array of approval ids.`);
|
|
61648
61830
|
}
|
|
@@ -61660,10 +61842,10 @@ class State {
|
|
|
61660
61842
|
ids.push(id);
|
|
61661
61843
|
writeFileSync2(this.consumedApprovalsPath, `${JSON.stringify(ids, null, 2)}
|
|
61662
61844
|
`, { mode: 384 });
|
|
61663
|
-
|
|
61845
|
+
chmodSync2(this.consumedApprovalsPath, 384);
|
|
61664
61846
|
return true;
|
|
61665
61847
|
} finally {
|
|
61666
|
-
|
|
61848
|
+
closeSync3(fd);
|
|
61667
61849
|
try {
|
|
61668
61850
|
unlinkSync2(this.consumedLockPath);
|
|
61669
61851
|
} catch {}
|
|
@@ -61673,12 +61855,12 @@ class State {
|
|
|
61673
61855
|
return `${this.consumedApprovalsPath}.lock`;
|
|
61674
61856
|
}
|
|
61675
61857
|
acquireConsumedLock() {
|
|
61676
|
-
|
|
61858
|
+
mkdirSync4(this.dir, { recursive: true });
|
|
61677
61859
|
const deadline = Date.now() + 5000;
|
|
61678
61860
|
for (;; ) {
|
|
61679
61861
|
try {
|
|
61680
|
-
const fd =
|
|
61681
|
-
|
|
61862
|
+
const fd = openSync3(this.consumedLockPath, "wx");
|
|
61863
|
+
writeSync3(fd, String(process.pid));
|
|
61682
61864
|
return fd;
|
|
61683
61865
|
} catch (e) {
|
|
61684
61866
|
if (e.code !== "EEXIST")
|
|
@@ -61699,7 +61881,7 @@ class State {
|
|
|
61699
61881
|
consumedLockOwnerIsGone() {
|
|
61700
61882
|
let pid;
|
|
61701
61883
|
try {
|
|
61702
|
-
pid = Number(
|
|
61884
|
+
pid = Number(readFileSync6(this.consumedLockPath, "utf8").trim());
|
|
61703
61885
|
} catch {
|
|
61704
61886
|
return false;
|
|
61705
61887
|
}
|
|
@@ -61713,7 +61895,7 @@ class State {
|
|
|
61713
61895
|
}
|
|
61714
61896
|
}
|
|
61715
61897
|
saveSlip(slip2) {
|
|
61716
|
-
|
|
61898
|
+
mkdirSync4(join4(this.dir, "slips"), { recursive: true });
|
|
61717
61899
|
writeFileSync2(this.slipPath(slip2.hash), `${JSON.stringify(slip2, null, 2)}
|
|
61718
61900
|
`);
|
|
61719
61901
|
}
|
|
@@ -61725,10 +61907,13 @@ var init_state = __esm(() => {
|
|
|
61725
61907
|
|
|
61726
61908
|
// packages/buyer/src/cli.ts
|
|
61727
61909
|
var exports_cli = {};
|
|
61910
|
+
__export(exports_cli, {
|
|
61911
|
+
agentAccount: () => agentAccount
|
|
61912
|
+
});
|
|
61728
61913
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
61729
|
-
import { chmodSync as
|
|
61730
|
-
import { join as
|
|
61731
|
-
function
|
|
61914
|
+
import { chmodSync as chmodSync3, mkdirSync as mkdirSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
61915
|
+
import { join as join5 } from "node:path";
|
|
61916
|
+
function parse7(argv) {
|
|
61732
61917
|
const pos = [];
|
|
61733
61918
|
const flags = new Map;
|
|
61734
61919
|
for (let i = 0;i < argv.length; i++) {
|
|
@@ -61750,14 +61935,21 @@ function parse6(argv) {
|
|
|
61750
61935
|
}
|
|
61751
61936
|
return { pos, flags };
|
|
61752
61937
|
}
|
|
61753
|
-
function agentAccount() {
|
|
61938
|
+
async function agentAccount() {
|
|
61939
|
+
cachedAccount ??= resolveAccount();
|
|
61940
|
+
return await cachedAccount;
|
|
61941
|
+
}
|
|
61942
|
+
async function resolveAccount() {
|
|
61754
61943
|
const key = process.env.CS_BUYER_KEY;
|
|
61755
|
-
if (
|
|
61756
|
-
|
|
61757
|
-
|
|
61944
|
+
if (key)
|
|
61945
|
+
return privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`);
|
|
61946
|
+
const session = await sessionFromEnv(process.env);
|
|
61947
|
+
if (session !== undefined)
|
|
61948
|
+
return remoteAccount(session);
|
|
61949
|
+
throw new Error(NOT_SIGNED_IN3);
|
|
61758
61950
|
}
|
|
61759
61951
|
async function main2() {
|
|
61760
|
-
const { pos, flags } =
|
|
61952
|
+
const { pos, flags } = parse7(process.argv.slice(2));
|
|
61761
61953
|
const one = (n) => flags.get(n)?.[0];
|
|
61762
61954
|
let hub = new HubClient(one("hub") ?? "http://127.0.0.1:8787");
|
|
61763
61955
|
const state = new State(one("state"));
|
|
@@ -61801,7 +61993,7 @@ async function main2() {
|
|
|
61801
61993
|
throw new Error("Usage: buy <offerHash|callUrl> --input '<json>' [--approve] [--rail <id>] [--approvals hub]");
|
|
61802
61994
|
const rail2 = parseRail(one("rail"));
|
|
61803
61995
|
const approvals = parseApprovals(one("approvals"));
|
|
61804
|
-
const account = agentAccount();
|
|
61996
|
+
const account = await agentAccount();
|
|
61805
61997
|
const result = await buy({
|
|
61806
61998
|
hub,
|
|
61807
61999
|
offerHash: hash4,
|
|
@@ -61830,9 +62022,9 @@ async function main2() {
|
|
|
61830
62022
|
try {
|
|
61831
62023
|
env = state.loadEnvelope();
|
|
61832
62024
|
} catch {
|
|
61833
|
-
env = { v: 1, agent: agentAccount().address, cap: "0", perMerchant: "0", allowlist: [], revoked: false };
|
|
62025
|
+
env = { v: 1, agent: (await agentAccount()).address, cap: "0", perMerchant: "0", allowlist: [], revoked: false };
|
|
61834
62026
|
}
|
|
61835
|
-
env.agent = agentAccount().address;
|
|
62027
|
+
env.agent = (await agentAccount()).address;
|
|
61836
62028
|
const cap = one("cap");
|
|
61837
62029
|
if (cap !== undefined)
|
|
61838
62030
|
env.cap = parseUnits(cap, 6).toString(10);
|
|
@@ -61854,7 +62046,7 @@ async function main2() {
|
|
|
61854
62046
|
} else if ((cmd === "accept" || cmd === "dispute") && pos[1] !== undefined) {
|
|
61855
62047
|
if (!/^0x[0-9a-fA-F]{64}$/.test(pos[1]))
|
|
61856
62048
|
throw new Error(`Usage: ${cmd} <jobId>`);
|
|
61857
|
-
const account = agentAccount();
|
|
62049
|
+
const account = await agentAccount();
|
|
61858
62050
|
const args = { hub, journal, state, known, signer: account, jobId: pos[1], now: Math.floor(Date.now() / 1000) };
|
|
61859
62051
|
if (cmd === "accept") {
|
|
61860
62052
|
const done = await acceptJob(args);
|
|
@@ -61870,7 +62062,7 @@ async function main2() {
|
|
|
61870
62062
|
for (const e of journal.entries())
|
|
61871
62063
|
console.log(JSON.stringify(e));
|
|
61872
62064
|
} else if (cmd === "publish-envelope") {
|
|
61873
|
-
const account = agentAccount();
|
|
62065
|
+
const account = await agentAccount();
|
|
61874
62066
|
const ok2 = await publishEnvelope({
|
|
61875
62067
|
hub,
|
|
61876
62068
|
account,
|
|
@@ -61880,12 +62072,12 @@ async function main2() {
|
|
|
61880
62072
|
});
|
|
61881
62073
|
console.log(ok2 ? "Envelope published." : "Envelope publish failed.");
|
|
61882
62074
|
} else if (cmd === "openai") {
|
|
61883
|
-
const account = agentAccount();
|
|
62075
|
+
const account = await agentAccount();
|
|
61884
62076
|
const token = randomBytes2(32).toString("hex");
|
|
61885
|
-
|
|
61886
|
-
const tokenPath =
|
|
62077
|
+
mkdirSync5(state.dir, { recursive: true });
|
|
62078
|
+
const tokenPath = join5(state.dir, "openai.token");
|
|
61887
62079
|
writeFileSync3(tokenPath, token, { mode: 384 });
|
|
61888
|
-
|
|
62080
|
+
chmodSync3(tokenPath, 384);
|
|
61889
62081
|
const server = startOpenAIServer({
|
|
61890
62082
|
hub,
|
|
61891
62083
|
account,
|
|
@@ -61900,7 +62092,7 @@ async function main2() {
|
|
|
61900
62092
|
console.log(`${server.url}/v1`);
|
|
61901
62093
|
console.log(tokenPath);
|
|
61902
62094
|
} else if (cmd === "resume") {
|
|
61903
|
-
const mirror = flags.has("hub") ? { account: agentAccount(), envelope: state.loadEnvelope() } : undefined;
|
|
62095
|
+
const mirror = flags.has("hub") ? { account: await agentAccount(), envelope: state.loadEnvelope() } : undefined;
|
|
61904
62096
|
const rows = await resume({
|
|
61905
62097
|
hub,
|
|
61906
62098
|
journal,
|
|
@@ -61914,7 +62106,7 @@ async function main2() {
|
|
|
61914
62106
|
console.log(`${r.jobId} ${r.status}${r.appended ? ` -> ${r.appended}` : ""}`);
|
|
61915
62107
|
} else {
|
|
61916
62108
|
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>.
|
|
62109
|
+
console.log("Flags: --hub <url> --state <dir>. Sign in once with: countersign login.");
|
|
61918
62110
|
}
|
|
61919
62111
|
}
|
|
61920
62112
|
function parseApprovals(raw) {
|
|
@@ -61943,7 +62135,7 @@ function parseRail(raw) {
|
|
|
61943
62135
|
throw new Error(`Unknown rail ${raw}.`);
|
|
61944
62136
|
return raw;
|
|
61945
62137
|
}
|
|
61946
|
-
var BOOLEAN, usd2 = (atomic) => formatUnits(BigInt(atomic), 6);
|
|
62138
|
+
var BOOLEAN, cachedAccount, usd2 = (atomic) => formatUnits(BigInt(atomic), 6);
|
|
61947
62139
|
var init_cli = __esm(() => {
|
|
61948
62140
|
init_accounts();
|
|
61949
62141
|
init_src();
|
|
@@ -61955,6 +62147,7 @@ var init_cli = __esm(() => {
|
|
|
61955
62147
|
init_mirror();
|
|
61956
62148
|
init_server();
|
|
61957
62149
|
init_payer2();
|
|
62150
|
+
init_remote_signer();
|
|
61958
62151
|
init_resume();
|
|
61959
62152
|
init_review();
|
|
61960
62153
|
init_state();
|
|
@@ -61967,7 +62160,7 @@ var init_cli = __esm(() => {
|
|
|
61967
62160
|
|
|
61968
62161
|
// packages/verify/src/cli.ts
|
|
61969
62162
|
var exports_cli2 = {};
|
|
61970
|
-
import { readFileSync as
|
|
62163
|
+
import { readFileSync as readFileSync7 } from "node:fs";
|
|
61971
62164
|
var args, file2, rpcAt, rpcUrl, mirrorAt, mirrorUrl, slip2, verdict, verdictLine;
|
|
61972
62165
|
var init_cli2 = __esm(async () => {
|
|
61973
62166
|
init_verify();
|
|
@@ -61982,7 +62175,7 @@ var init_cli2 = __esm(async () => {
|
|
|
61982
62175
|
process.exit(2);
|
|
61983
62176
|
}
|
|
61984
62177
|
try {
|
|
61985
|
-
slip2 = JSON.parse(
|
|
62178
|
+
slip2 = JSON.parse(readFileSync7(file2, "utf8"));
|
|
61986
62179
|
} catch (e) {
|
|
61987
62180
|
console.error(`cannot read ${file2}: ${e.message}`);
|
|
61988
62181
|
process.exit(2);
|
|
@@ -62079,6 +62272,7 @@ var init_src4 = __esm(() => {
|
|
|
62079
62272
|
init_mirror();
|
|
62080
62273
|
init_payer2();
|
|
62081
62274
|
init_resume();
|
|
62275
|
+
init_remote_signer();
|
|
62082
62276
|
init_review();
|
|
62083
62277
|
init_state();
|
|
62084
62278
|
init_terms();
|
|
@@ -63381,7 +63575,7 @@ var init_mcp = __esm(() => {
|
|
|
63381
63575
|
});
|
|
63382
63576
|
|
|
63383
63577
|
// packages/mcp/src/server.ts
|
|
63384
|
-
import { existsSync as
|
|
63578
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
63385
63579
|
function assertHash(value, what) {
|
|
63386
63580
|
if (!HASH.test(value))
|
|
63387
63581
|
throw new Error(`Refused. ${what} must be 0x followed by 64 hex characters.`);
|
|
@@ -63408,11 +63602,16 @@ function searchText(offer2) {
|
|
|
63408
63602
|
`).toLowerCase();
|
|
63409
63603
|
}
|
|
63410
63604
|
function createCountersignMcpServer(deps) {
|
|
63411
|
-
const server = new McpServer({ name: "countersign", version: "0.1.
|
|
63605
|
+
const server = new McpServer({ name: "countersign", version: "0.1.1" });
|
|
63412
63606
|
const clock = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
63413
63607
|
const verify2 = deps.verify ?? verifySlip;
|
|
63608
|
+
const gate = () => {
|
|
63609
|
+
if (deps.account !== undefined)
|
|
63610
|
+
return;
|
|
63611
|
+
return failure3(new Error(deps.problem === undefined ? NOT_SIGNED_IN3 : `${NOT_SIGNED_IN3} (${deps.problem})`));
|
|
63612
|
+
};
|
|
63414
63613
|
const loadSlip = async (hash4) => {
|
|
63415
|
-
if (
|
|
63614
|
+
if (existsSync6(deps.state.slipPath(hash4)))
|
|
63416
63615
|
return deps.state.loadSlip(hash4);
|
|
63417
63616
|
const base2 = deps.hubUrl.replace(/\/+$/, "");
|
|
63418
63617
|
const response = await fetch(`${base2}/slips/${hash4}`);
|
|
@@ -63428,6 +63627,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63428
63627
|
limit: exports_external.number().int().optional()
|
|
63429
63628
|
}
|
|
63430
63629
|
}, async ({ query, limit }) => {
|
|
63630
|
+
const refused = gate();
|
|
63631
|
+
if (refused !== undefined)
|
|
63632
|
+
return refused;
|
|
63431
63633
|
try {
|
|
63432
63634
|
const listings = await deps.hub.listOffers();
|
|
63433
63635
|
const needle = query?.toLowerCase();
|
|
@@ -63462,6 +63664,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63462
63664
|
offerHash: exports_external.string()
|
|
63463
63665
|
}
|
|
63464
63666
|
}, async ({ offerHash: offerHash2 }) => {
|
|
63667
|
+
const refused = gate();
|
|
63668
|
+
if (refused !== undefined)
|
|
63669
|
+
return refused;
|
|
63465
63670
|
try {
|
|
63466
63671
|
assertHash(offerHash2, "offerHash");
|
|
63467
63672
|
const listing = await deps.hub.getOffer(offerHash2);
|
|
@@ -63479,16 +63684,17 @@ function createCountersignMcpServer(deps) {
|
|
|
63479
63684
|
});
|
|
63480
63685
|
server.registerTool("buy", {
|
|
63481
63686
|
title: "Buy an offer",
|
|
63482
|
-
description: "Buy an offer under the agent's envelope and return the seller's output and slip. Requires
|
|
63687
|
+
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
63688
|
inputSchema: {
|
|
63484
63689
|
offerHash: exports_external.string(),
|
|
63485
63690
|
input: exports_external.unknown(),
|
|
63486
63691
|
rail: exports_external.string().optional()
|
|
63487
63692
|
}
|
|
63488
63693
|
}, async ({ offerHash: offerHash2, input: input2, rail: rail2 }) => {
|
|
63694
|
+
const refused = gate();
|
|
63695
|
+
if (refused !== undefined)
|
|
63696
|
+
return refused;
|
|
63489
63697
|
const account = deps.account;
|
|
63490
|
-
if (account === undefined)
|
|
63491
|
-
return failure3(new Error(NO_KEY));
|
|
63492
63698
|
if (rail2 !== undefined && !RAIL_IDS.includes(rail2)) {
|
|
63493
63699
|
return failure3(new Error(`Unknown rail ${rail2}.`));
|
|
63494
63700
|
}
|
|
@@ -63529,6 +63735,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63529
63735
|
slipHash: exports_external.string().optional()
|
|
63530
63736
|
}
|
|
63531
63737
|
}, async ({ slip: slip3, slipHash: slipHash2 }) => {
|
|
63738
|
+
const refused = gate();
|
|
63739
|
+
if (refused !== undefined)
|
|
63740
|
+
return refused;
|
|
63532
63741
|
if (slip3 === undefined === (slipHash2 === undefined)) {
|
|
63533
63742
|
return failure3(new Error("Pass exactly one of slip or slipHash."));
|
|
63534
63743
|
}
|
|
@@ -63546,6 +63755,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63546
63755
|
description: "Read the agent's envelope and what the journal says it has spent.",
|
|
63547
63756
|
inputSchema: {}
|
|
63548
63757
|
}, async () => {
|
|
63758
|
+
const refused = gate();
|
|
63759
|
+
if (refused !== undefined)
|
|
63760
|
+
return refused;
|
|
63549
63761
|
try {
|
|
63550
63762
|
return text({ envelope: deps.state.loadEnvelope(), spent: deps.journal.spend() });
|
|
63551
63763
|
} catch (error62) {
|
|
@@ -63559,6 +63771,9 @@ function createCountersignMcpServer(deps) {
|
|
|
63559
63771
|
limit: exports_external.number().int().optional()
|
|
63560
63772
|
}
|
|
63561
63773
|
}, async ({ limit }) => {
|
|
63774
|
+
const refused = gate();
|
|
63775
|
+
if (refused !== undefined)
|
|
63776
|
+
return refused;
|
|
63562
63777
|
try {
|
|
63563
63778
|
const entries = deps.journal.entries();
|
|
63564
63779
|
const count = limit ?? 20;
|
|
@@ -63569,7 +63784,7 @@ function createCountersignMcpServer(deps) {
|
|
|
63569
63784
|
});
|
|
63570
63785
|
return server;
|
|
63571
63786
|
}
|
|
63572
|
-
var HASH_MISMATCH = "Refused. The hub served an offer that does not match the hash asked for.",
|
|
63787
|
+
var HASH_MISMATCH = "Refused. The hub served an offer that does not match the hash asked for.", HASH;
|
|
63573
63788
|
var init_server6 = __esm(() => {
|
|
63574
63789
|
init_mcp();
|
|
63575
63790
|
init_zod();
|
|
@@ -63582,14 +63797,15 @@ var init_server6 = __esm(() => {
|
|
|
63582
63797
|
// packages/mcp/src/main.ts
|
|
63583
63798
|
var exports_main = {};
|
|
63584
63799
|
__export(exports_main, {
|
|
63800
|
+
resolveAccount: () => resolveAccount2,
|
|
63585
63801
|
main: () => main3
|
|
63586
63802
|
});
|
|
63587
63803
|
function fail(message) {
|
|
63588
63804
|
console.error(message);
|
|
63589
63805
|
process.exit(1);
|
|
63590
63806
|
}
|
|
63591
|
-
function
|
|
63592
|
-
const config2 = { hub: process.env.CS_HUB ??
|
|
63807
|
+
function parse8(argv) {
|
|
63808
|
+
const config2 = { hub: process.env.CS_HUB ?? DEFAULT_HUB2 };
|
|
63593
63809
|
if (process.env.CS_RPC_URL !== undefined)
|
|
63594
63810
|
config2.rpcUrl = process.env.CS_RPC_URL;
|
|
63595
63811
|
let help = false;
|
|
@@ -63615,18 +63831,45 @@ function parse7(argv) {
|
|
|
63615
63831
|
}
|
|
63616
63832
|
return { help, config: config2 };
|
|
63617
63833
|
}
|
|
63618
|
-
function
|
|
63619
|
-
const key =
|
|
63834
|
+
function ciAccount(env) {
|
|
63835
|
+
const key = env.CS_BUYER_KEY;
|
|
63620
63836
|
if (!key)
|
|
63621
|
-
return;
|
|
63837
|
+
return {};
|
|
63622
63838
|
try {
|
|
63623
|
-
return privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`);
|
|
63839
|
+
return { account: privateKeyToAccount(key.startsWith("0x") ? key : `0x${key}`) };
|
|
63624
63840
|
} catch {
|
|
63625
|
-
return
|
|
63841
|
+
return { problem: "The configured signer is not valid." };
|
|
63626
63842
|
}
|
|
63627
63843
|
}
|
|
63628
|
-
|
|
63629
|
-
const
|
|
63844
|
+
function sessionProblem(error62) {
|
|
63845
|
+
const message = error62 instanceof Error ? error62.message : String(error62);
|
|
63846
|
+
const firstLine3 = message.split(`
|
|
63847
|
+
`)[0] ?? "";
|
|
63848
|
+
return { problem: `Could not load the countersign session: ${firstLine3}` };
|
|
63849
|
+
}
|
|
63850
|
+
async function resolveAccount2(options, env) {
|
|
63851
|
+
const sessionEnv = { CS_SESSION: env.CS_SESSION, CS_HUB: env.CS_HUB };
|
|
63852
|
+
delete env.CS_SESSION;
|
|
63853
|
+
if (options.loadAccount !== undefined) {
|
|
63854
|
+
try {
|
|
63855
|
+
const account = await options.loadAccount();
|
|
63856
|
+
return account === undefined ? {} : { account };
|
|
63857
|
+
} catch (error62) {
|
|
63858
|
+
return sessionProblem(error62);
|
|
63859
|
+
}
|
|
63860
|
+
}
|
|
63861
|
+
let session;
|
|
63862
|
+
try {
|
|
63863
|
+
session = await sessionFromEnv(sessionEnv);
|
|
63864
|
+
} catch (error62) {
|
|
63865
|
+
return sessionProblem(error62);
|
|
63866
|
+
}
|
|
63867
|
+
if (session !== undefined)
|
|
63868
|
+
return { account: remoteAccount(session) };
|
|
63869
|
+
return ciAccount(env);
|
|
63870
|
+
}
|
|
63871
|
+
async function main3(argv, options = {}) {
|
|
63872
|
+
const { help, config: config2 } = parse8(argv);
|
|
63630
63873
|
if (help) {
|
|
63631
63874
|
console.log(USAGE);
|
|
63632
63875
|
return;
|
|
@@ -63639,11 +63882,16 @@ async function main3(argv) {
|
|
|
63639
63882
|
const state2 = new State(config2.state);
|
|
63640
63883
|
const journal2 = new Journal(state2.journalPath);
|
|
63641
63884
|
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
|
|
63885
|
+
const { account, problem } = await resolveAccount2(options, process.env);
|
|
63886
|
+
console.error(`countersign mcp: hub ${hub.url}`);
|
|
63887
|
+
console.error(`countersign mcp: state ${state2.dir}`);
|
|
63888
|
+
if (account !== undefined) {
|
|
63889
|
+
console.error(`countersign mcp: agent ${account.address}`);
|
|
63890
|
+
} else {
|
|
63891
|
+
console.error("countersign mcp: not signed in. Run: npx -y @countersign-hub/cli login");
|
|
63892
|
+
if (problem !== undefined)
|
|
63893
|
+
console.error(`countersign mcp: ${problem}`);
|
|
63894
|
+
}
|
|
63647
63895
|
const server = createCountersignMcpServer({
|
|
63648
63896
|
hub,
|
|
63649
63897
|
state: state2,
|
|
@@ -63651,11 +63899,12 @@ async function main3(argv) {
|
|
|
63651
63899
|
hubUrl: config2.hub,
|
|
63652
63900
|
now: () => Math.floor(Date.now() / 1000),
|
|
63653
63901
|
...account !== undefined ? { account } : {},
|
|
63902
|
+
...problem !== undefined ? { problem } : {},
|
|
63654
63903
|
...config2.rpcUrl !== undefined ? { rpcUrl: config2.rpcUrl } : {}
|
|
63655
63904
|
});
|
|
63656
63905
|
await server.connect(new StdioServerTransport);
|
|
63657
63906
|
}
|
|
63658
|
-
var
|
|
63907
|
+
var DEFAULT_HUB2 = "https://hub-production-e85e.up.railway.app", USAGE;
|
|
63659
63908
|
var init_main = __esm(() => {
|
|
63660
63909
|
init_accounts();
|
|
63661
63910
|
init_stdio2();
|
|
@@ -63666,17 +63915,18 @@ var init_main = __esm(() => {
|
|
|
63666
63915
|
Usage: countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
63667
63916
|
|
|
63668
63917
|
Options:
|
|
63669
|
-
--hub <url> The countersign hub (env CS_HUB; default ${
|
|
63918
|
+
--hub <url> The countersign hub (env CS_HUB; default ${DEFAULT_HUB2})
|
|
63670
63919
|
--state <dir> Where the envelope, journal and slips live (default ~/.countersign)
|
|
63671
63920
|
--rpc <url> The RPC verify_slip reads the chain from (env CS_RPC_URL), e.g. https://rpc.testnet.arc.network
|
|
63672
63921
|
--help Print this usage and exit
|
|
63673
63922
|
|
|
63674
|
-
|
|
63675
|
-
|
|
63676
|
-
|
|
63923
|
+
Sign in once: npx -y @countersign-hub/cli login. Your agent's wallet is a Privy server wallet that the countersign app controls;
|
|
63924
|
+
this server signs through the hub with your session, and no key is ever on this machine or in any config.
|
|
63925
|
+
|
|
63926
|
+
CS_NETWORK must be unset or testnet.
|
|
63677
63927
|
|
|
63678
|
-
Install
|
|
63679
|
-
countersign and countersign-mcp belong to other projects: never npx or npm install them.`;
|
|
63928
|
+
Install: npm i -g @countersign-hub/cli, then countersign mcp (or npx -y @countersign-hub/cli mcp).
|
|
63929
|
+
The npm packages named @countersign/*, countersign and countersign-mcp belong to other projects: never npx or npm install them.`;
|
|
63680
63930
|
});
|
|
63681
63931
|
|
|
63682
63932
|
// packages/runner/src/cli.ts
|
|
@@ -63957,8 +64207,11 @@ function setTermsArgs(command) {
|
|
|
63957
64207
|
}
|
|
63958
64208
|
async function bondFromEnv(args, log = console.log) {
|
|
63959
64209
|
const key = process.env.CS_SELLER_KEY;
|
|
63960
|
-
if (!key
|
|
63961
|
-
throw new Error("
|
|
64210
|
+
if (!key) {
|
|
64211
|
+
throw new Error("Bond commands are not available from a signed-in session yet: they send transactions, and the hub only signs.");
|
|
64212
|
+
}
|
|
64213
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
64214
|
+
throw new Error("The CI signing override in this environment is malformed.");
|
|
63962
64215
|
}
|
|
63963
64216
|
await runBond(parseBondArgs(args), key, log);
|
|
63964
64217
|
}
|
|
@@ -65153,12 +65406,183 @@ function isRecord3(value) {
|
|
|
65153
65406
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
65154
65407
|
}
|
|
65155
65408
|
|
|
65409
|
+
// packages/runner/src/remote-signer.ts
|
|
65410
|
+
init__esm();
|
|
65411
|
+
var NOT_SIGNED_IN = "Not signed in. Run: npx -y @countersign-hub/cli login";
|
|
65412
|
+
var BONDED_REMOTE_REFUSAL = "A bonded offer cannot be served from a signed-in session yet: the hub does not sign Lock for it.";
|
|
65413
|
+
var SIGNATURE = /^0x[0-9a-fA-F]{130}$/;
|
|
65414
|
+
var ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
65415
|
+
function hubFailure(reason) {
|
|
65416
|
+
return new Error(`The hub could not sign right now (${reason}).`);
|
|
65417
|
+
}
|
|
65418
|
+
var WRONG_WALLET = "The hub signed with a different wallet.";
|
|
65419
|
+
function safeHub(hubUrl) {
|
|
65420
|
+
let url2;
|
|
65421
|
+
try {
|
|
65422
|
+
url2 = new URL(hubUrl);
|
|
65423
|
+
} catch {
|
|
65424
|
+
throw new Error("The hub address is not a URL.");
|
|
65425
|
+
}
|
|
65426
|
+
const local = url2.hostname === "localhost" || url2.hostname === "127.0.0.1" || url2.hostname === "[::1]";
|
|
65427
|
+
if (url2.protocol !== "https:" && !(url2.protocol === "http:" && local)) {
|
|
65428
|
+
throw new Error("The session is sent only to an https hub.");
|
|
65429
|
+
}
|
|
65430
|
+
return hubUrl.replace(/\/+$/, "");
|
|
65431
|
+
}
|
|
65432
|
+
function decimalString(_key, value) {
|
|
65433
|
+
return typeof value === "bigint" ? value.toString(10) : value;
|
|
65434
|
+
}
|
|
65435
|
+
function recordOf(value) {
|
|
65436
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
65437
|
+
}
|
|
65438
|
+
function messageOf2(body) {
|
|
65439
|
+
const message = recordOf(body)?.message;
|
|
65440
|
+
return typeof message === "string" && message.length > 0 ? message : null;
|
|
65441
|
+
}
|
|
65442
|
+
function codeOf(body) {
|
|
65443
|
+
const code = recordOf(body)?.code;
|
|
65444
|
+
return typeof code === "string" && code.length > 0 ? code : null;
|
|
65445
|
+
}
|
|
65446
|
+
async function readJson(response) {
|
|
65447
|
+
try {
|
|
65448
|
+
return await response.json();
|
|
65449
|
+
} catch {
|
|
65450
|
+
return;
|
|
65451
|
+
}
|
|
65452
|
+
}
|
|
65453
|
+
function remoteRunnerAccount(options) {
|
|
65454
|
+
const hub = safeHub(options.hubUrl);
|
|
65455
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
65456
|
+
const sign3 = async (payload, recover) => {
|
|
65457
|
+
let response;
|
|
65458
|
+
try {
|
|
65459
|
+
response = await fetchImpl(`${hub}/cli/sign`, {
|
|
65460
|
+
method: "POST",
|
|
65461
|
+
headers: {
|
|
65462
|
+
authorization: `Bearer ${options.session}`,
|
|
65463
|
+
"content-type": "application/json"
|
|
65464
|
+
},
|
|
65465
|
+
body: JSON.stringify(payload, decimalString)
|
|
65466
|
+
});
|
|
65467
|
+
} catch {
|
|
65468
|
+
throw hubFailure("unreachable");
|
|
65469
|
+
}
|
|
65470
|
+
const body = await readJson(response);
|
|
65471
|
+
if (response.status === 200) {
|
|
65472
|
+
const signed2 = recordOf(body);
|
|
65473
|
+
const signature = signed2?.signature;
|
|
65474
|
+
const address = signed2?.address;
|
|
65475
|
+
if (typeof signature !== "string" || !SIGNATURE.test(signature) || typeof address !== "string" || address.toLowerCase() !== options.address.toLowerCase()) {
|
|
65476
|
+
throw new Error(WRONG_WALLET);
|
|
65477
|
+
}
|
|
65478
|
+
let signer;
|
|
65479
|
+
try {
|
|
65480
|
+
signer = await recover(signature);
|
|
65481
|
+
} catch {
|
|
65482
|
+
throw new Error(WRONG_WALLET);
|
|
65483
|
+
}
|
|
65484
|
+
if (signer.toLowerCase() !== options.address.toLowerCase())
|
|
65485
|
+
throw new Error(WRONG_WALLET);
|
|
65486
|
+
return signature;
|
|
65487
|
+
}
|
|
65488
|
+
if (response.status === 401)
|
|
65489
|
+
throw new Error(messageOf2(body) ?? NOT_SIGNED_IN);
|
|
65490
|
+
if (response.status === 403) {
|
|
65491
|
+
throw new Error(`The hub refused to sign this: ${codeOf(body) ?? "not-allowed"}`);
|
|
65492
|
+
}
|
|
65493
|
+
if (response.status === 502) {
|
|
65494
|
+
throw new Error("The hub could not sign right now (privy-failed).");
|
|
65495
|
+
}
|
|
65496
|
+
throw hubFailure(response.status);
|
|
65497
|
+
};
|
|
65498
|
+
return {
|
|
65499
|
+
kind: "remote",
|
|
65500
|
+
address: options.address,
|
|
65501
|
+
signMessage: (args) => sign3({ kind: "message", message: args.message }, (signature) => recoverMessageAddress2({ message: args.message, signature })),
|
|
65502
|
+
signTypedData: (typedData) => sign3({ kind: "typed-data", typedData }, (signature) => recoverTypedDataAddress2({ ...typedData, signature }))
|
|
65503
|
+
};
|
|
65504
|
+
}
|
|
65505
|
+
async function remoteAccountFromSession(options) {
|
|
65506
|
+
const hub = safeHub(options.hubUrl);
|
|
65507
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
65508
|
+
let response;
|
|
65509
|
+
try {
|
|
65510
|
+
response = await fetchImpl(`${hub}/cli/session`, {
|
|
65511
|
+
headers: { authorization: `Bearer ${options.session}` }
|
|
65512
|
+
});
|
|
65513
|
+
} catch {
|
|
65514
|
+
throw hubFailure("unreachable");
|
|
65515
|
+
}
|
|
65516
|
+
const body = await readJson(response);
|
|
65517
|
+
if (response.status === 200) {
|
|
65518
|
+
const address = recordOf(body)?.address;
|
|
65519
|
+
if (typeof address !== "string" || !ADDRESS.test(address)) {
|
|
65520
|
+
throw hubFailure("invalid-address");
|
|
65521
|
+
}
|
|
65522
|
+
return remoteRunnerAccount({ ...options, address });
|
|
65523
|
+
}
|
|
65524
|
+
if (response.status === 401)
|
|
65525
|
+
throw new Error(messageOf2(body) ?? NOT_SIGNED_IN);
|
|
65526
|
+
throw hubFailure(response.status);
|
|
65527
|
+
}
|
|
65528
|
+
function assertRemoteCanServe(account, offer2) {
|
|
65529
|
+
if (account.kind !== "remote")
|
|
65530
|
+
return;
|
|
65531
|
+
let bonded = false;
|
|
65532
|
+
try {
|
|
65533
|
+
bonded = BigInt(offer2.bond) > 0n;
|
|
65534
|
+
} catch {
|
|
65535
|
+
bonded = false;
|
|
65536
|
+
}
|
|
65537
|
+
if (bonded)
|
|
65538
|
+
throw new Error(BONDED_REMOTE_REFUSAL);
|
|
65539
|
+
}
|
|
65540
|
+
|
|
65156
65541
|
// packages/runner/src/daemon.ts
|
|
65157
65542
|
var RECONNECT_DELAYS = [1, 2, 4, 8, 16, 30];
|
|
65543
|
+
var ATOMIC = /^(0|[1-9][0-9]*)$/;
|
|
65544
|
+
var ADDRESS2 = /^0x[0-9a-fA-F]{40}$/;
|
|
65545
|
+
function readLockTerms(value) {
|
|
65546
|
+
if (value === null || typeof value !== "object")
|
|
65547
|
+
return null;
|
|
65548
|
+
const raw = value;
|
|
65549
|
+
const buyer = raw.buyer;
|
|
65550
|
+
const payee = raw.payee;
|
|
65551
|
+
const amount2 = raw.amount;
|
|
65552
|
+
const deadline = raw.deadline;
|
|
65553
|
+
const salt = raw.salt;
|
|
65554
|
+
const bond = raw.bond;
|
|
65555
|
+
const reviewWindow = raw.reviewWindow;
|
|
65556
|
+
if (typeof buyer !== "string" || !ADDRESS2.test(buyer))
|
|
65557
|
+
return null;
|
|
65558
|
+
if (typeof payee !== "string" || !ADDRESS2.test(payee))
|
|
65559
|
+
return null;
|
|
65560
|
+
if (typeof amount2 !== "string" || !ATOMIC.test(amount2))
|
|
65561
|
+
return null;
|
|
65562
|
+
if (typeof deadline !== "number" || !Number.isSafeInteger(deadline))
|
|
65563
|
+
return null;
|
|
65564
|
+
if (typeof salt !== "string" || !ATOMIC.test(salt))
|
|
65565
|
+
return null;
|
|
65566
|
+
if (typeof bond !== "string" || !ATOMIC.test(bond))
|
|
65567
|
+
return null;
|
|
65568
|
+
if (typeof reviewWindow !== "number" || !Number.isSafeInteger(reviewWindow))
|
|
65569
|
+
return null;
|
|
65570
|
+
return {
|
|
65571
|
+
buyer,
|
|
65572
|
+
payee,
|
|
65573
|
+
amount: amount2,
|
|
65574
|
+
deadline,
|
|
65575
|
+
salt,
|
|
65576
|
+
bond,
|
|
65577
|
+
reviewWindow
|
|
65578
|
+
};
|
|
65579
|
+
}
|
|
65158
65580
|
function startRunner(cfg) {
|
|
65159
65581
|
const clock = cfg.now ?? (() => Math.floor(Date.now() / 1000));
|
|
65160
65582
|
const timeMs = cfg.limits?.timeMs ?? 30000;
|
|
65161
65583
|
const maxOutputBytes = cfg.limits?.maxOutputBytes ?? 1e6;
|
|
65584
|
+
for (const entry of cfg.served)
|
|
65585
|
+
assertRemoteCanServe(cfg.account, entry.offer);
|
|
65162
65586
|
const served = cfg.served.map((entry) => ({ ...entry, hash: offerHash(entry.offer) }));
|
|
65163
65587
|
const url2 = connectUrl(cfg.hubUrl);
|
|
65164
65588
|
const funding = cfg.funding === undefined ? null : { ...cfg.funding, read: fundingReader(cfg.funding) };
|
|
@@ -65215,9 +65639,51 @@ function startRunner(cfg) {
|
|
|
65215
65639
|
});
|
|
65216
65640
|
return;
|
|
65217
65641
|
}
|
|
65642
|
+
const refuse = (reason) => {
|
|
65643
|
+
send(target, { t: "lock-refused", jobId: frame.jobId, reason });
|
|
65644
|
+
};
|
|
65645
|
+
const terms = readLockTerms(frame.terms);
|
|
65646
|
+
if (terms === null) {
|
|
65647
|
+
refuse("bad-terms");
|
|
65648
|
+
return;
|
|
65649
|
+
}
|
|
65650
|
+
if (terms.payee.toLowerCase() !== cfg.account.address.toLowerCase()) {
|
|
65651
|
+
refuse("not-payee");
|
|
65652
|
+
return;
|
|
65653
|
+
}
|
|
65654
|
+
let bondAbove = false;
|
|
65218
65655
|
try {
|
|
65219
|
-
|
|
65220
|
-
|
|
65656
|
+
bondAbove = BigInt(terms.bond) > 0n;
|
|
65657
|
+
} catch {
|
|
65658
|
+
bondAbove = false;
|
|
65659
|
+
}
|
|
65660
|
+
if (terms.amount !== entry.offer.price || terms.bond !== entry.offer.bond || !bondAbove || terms.reviewWindow !== (entry.offer.reviewWindow ?? 0)) {
|
|
65661
|
+
refuse("terms-mismatch");
|
|
65662
|
+
return;
|
|
65663
|
+
}
|
|
65664
|
+
if (terms.deadline - clock() < 60) {
|
|
65665
|
+
refuse("deadline-too-near");
|
|
65666
|
+
return;
|
|
65667
|
+
}
|
|
65668
|
+
const escrow = frame.escrow;
|
|
65669
|
+
const pinned = funding !== null && typeof escrow === "string" && funding.known.some((pin) => pin.chainId === frame.chainId && pin.escrow.toLowerCase() === escrow.toLowerCase());
|
|
65670
|
+
if (!pinned) {
|
|
65671
|
+
refuse("unknown-escrow");
|
|
65672
|
+
return;
|
|
65673
|
+
}
|
|
65674
|
+
let rebuilt;
|
|
65675
|
+
try {
|
|
65676
|
+
rebuilt = jobIdOf({ offerHash: frame.offerHash, ...terms }, frame.chainId, frame.escrow);
|
|
65677
|
+
} catch {
|
|
65678
|
+
refuse("job-mismatch");
|
|
65679
|
+
return;
|
|
65680
|
+
}
|
|
65681
|
+
if (typeof frame.jobId !== "string" || rebuilt.toLowerCase() !== frame.jobId.toLowerCase()) {
|
|
65682
|
+
refuse("job-mismatch");
|
|
65683
|
+
return;
|
|
65684
|
+
}
|
|
65685
|
+
try {
|
|
65686
|
+
const sig = await cfg.account.signTypedData(lockTypedData(frame.chainId, frame.escrow, frame.jobId, frame.funder));
|
|
65221
65687
|
send(target, { t: "locked", jobId: frame.jobId, sig });
|
|
65222
65688
|
} catch {
|
|
65223
65689
|
send(target, {
|
|
@@ -65272,7 +65738,7 @@ function startRunner(cfg) {
|
|
|
65272
65738
|
try {
|
|
65273
65739
|
output2 = await runInChild(substituteBuyer(entry.spec, order.buyer), order.input, { timeMs, maxOutputBytes }, [...order.lineage, order.jobId].join(","));
|
|
65274
65740
|
} catch (error62) {
|
|
65275
|
-
const reason =
|
|
65741
|
+
const reason = messageOf3(error62);
|
|
65276
65742
|
notify(order, entry.offer.title, false, reason);
|
|
65277
65743
|
return fail(target, order, reason);
|
|
65278
65744
|
}
|
|
@@ -65308,7 +65774,7 @@ function startRunner(cfg) {
|
|
|
65308
65774
|
});
|
|
65309
65775
|
notify(order, entry.offer.title, true);
|
|
65310
65776
|
} catch (error62) {
|
|
65311
|
-
const reason =
|
|
65777
|
+
const reason = messageOf3(error62);
|
|
65312
65778
|
notify(order, entry.offer.title, false, reason);
|
|
65313
65779
|
fail(target, order, reason);
|
|
65314
65780
|
}
|
|
@@ -65394,7 +65860,7 @@ function startRunner(cfg) {
|
|
|
65394
65860
|
}
|
|
65395
65861
|
handleMessage(target, message).catch((error62) => {
|
|
65396
65862
|
if (message.t === "job")
|
|
65397
|
-
fail(target, message.order,
|
|
65863
|
+
fail(target, message.order, messageOf3(error62));
|
|
65398
65864
|
});
|
|
65399
65865
|
});
|
|
65400
65866
|
target.addEventListener("close", () => {
|
|
@@ -65487,7 +65953,7 @@ function connectUrl(hubUrl) {
|
|
|
65487
65953
|
url2.pathname = `${url2.pathname.replace(/\/+$/, "")}${RUNNER_PATH}`;
|
|
65488
65954
|
return url2.toString();
|
|
65489
65955
|
}
|
|
65490
|
-
function
|
|
65956
|
+
function messageOf3(error62) {
|
|
65491
65957
|
return error62 instanceof Error ? error62.message : String(error62);
|
|
65492
65958
|
}
|
|
65493
65959
|
|
|
@@ -66127,6 +66593,7 @@ async function publishCommand(options) {
|
|
|
66127
66593
|
console.log(offerHash2);
|
|
66128
66594
|
}
|
|
66129
66595
|
function publishWithState(options, account, offer2, skillSha256) {
|
|
66596
|
+
assertRemoteCanServe(account, offer2);
|
|
66130
66597
|
return publishOffer(options.hub, account, offer2, {
|
|
66131
66598
|
...options.state !== undefined ? { stateDir: options.state } : {},
|
|
66132
66599
|
skillSha256
|
|
@@ -66229,11 +66696,22 @@ function makeOffer(seller, skill, options) {
|
|
|
66229
66696
|
});
|
|
66230
66697
|
}
|
|
66231
66698
|
async function sellerAccount() {
|
|
66699
|
+
const session = process.env.CS_SESSION;
|
|
66700
|
+
delete process.env.CS_SESSION;
|
|
66232
66701
|
const key = process.env.CS_SELLER_KEY;
|
|
66233
|
-
if (
|
|
66234
|
-
|
|
66702
|
+
if (key) {
|
|
66703
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(key)) {
|
|
66704
|
+
throw new Error("The CI signing override in this environment is malformed.");
|
|
66705
|
+
}
|
|
66706
|
+
return privateKeyToAccount(key);
|
|
66235
66707
|
}
|
|
66236
|
-
|
|
66708
|
+
if (session) {
|
|
66709
|
+
const issuer = process.env.CS_HUB;
|
|
66710
|
+
if (!issuer)
|
|
66711
|
+
throw new Error(NOT_SIGNED_IN);
|
|
66712
|
+
return remoteAccountFromSession({ hubUrl: issuer, session });
|
|
66713
|
+
}
|
|
66714
|
+
throw new Error(NOT_SIGNED_IN);
|
|
66237
66715
|
}
|
|
66238
66716
|
function parseOptions(args) {
|
|
66239
66717
|
const skills = [];
|
|
@@ -66449,30 +66927,458 @@ function parseRails(raw) {
|
|
|
66449
66927
|
}
|
|
66450
66928
|
if (false) {}
|
|
66451
66929
|
|
|
66930
|
+
// packages/cli/src/login.ts
|
|
66931
|
+
init__esm();
|
|
66932
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
66933
|
+
|
|
66934
|
+
// packages/cli/src/session.ts
|
|
66935
|
+
import { execFileSync } from "node:child_process";
|
|
66936
|
+
import {
|
|
66937
|
+
chmodSync,
|
|
66938
|
+
closeSync,
|
|
66939
|
+
existsSync as existsSync3,
|
|
66940
|
+
lstatSync,
|
|
66941
|
+
mkdirSync as mkdirSync2,
|
|
66942
|
+
openSync,
|
|
66943
|
+
readFileSync as readFileSync4,
|
|
66944
|
+
renameSync,
|
|
66945
|
+
rmSync,
|
|
66946
|
+
writeSync
|
|
66947
|
+
} from "node:fs";
|
|
66948
|
+
import { homedir as homedir2 } from "node:os";
|
|
66949
|
+
import { join as join3 } from "node:path";
|
|
66950
|
+
var NOT_SIGNED_IN2 = "Not signed in. Run: npx -y @countersign-hub/cli login";
|
|
66951
|
+
var securityRun = (args, input2) => execFileSync("/usr/bin/security", args, { input: input2, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
66952
|
+
function parse6(text) {
|
|
66953
|
+
try {
|
|
66954
|
+
const value = JSON.parse(text);
|
|
66955
|
+
if (typeof value.token === "string" && typeof value.hub === "string" && typeof value.address === "string" && typeof value.expiresAt === "number") {
|
|
66956
|
+
return value;
|
|
66957
|
+
}
|
|
66958
|
+
} catch {}
|
|
66959
|
+
return null;
|
|
66960
|
+
}
|
|
66961
|
+
function refuse(path) {
|
|
66962
|
+
process.stderr.write(`countersign: refusing the session at ${path}: symlink, non-regular file or unsafe permissions.
|
|
66963
|
+
`);
|
|
66964
|
+
return null;
|
|
66965
|
+
}
|
|
66966
|
+
function fileSessionBackend(dir = join3(homedir2(), ".config", "countersign"), platform = process.platform) {
|
|
66967
|
+
const path = join3(dir, "session.json");
|
|
66968
|
+
return {
|
|
66969
|
+
kind: "file",
|
|
66970
|
+
where: () => path,
|
|
66971
|
+
read() {
|
|
66972
|
+
try {
|
|
66973
|
+
if (lstatSync(dir).isSymbolicLink())
|
|
66974
|
+
return refuse(dir);
|
|
66975
|
+
} catch {
|
|
66976
|
+
return null;
|
|
66977
|
+
}
|
|
66978
|
+
try {
|
|
66979
|
+
const info = lstatSync(path);
|
|
66980
|
+
const unsafeMode = platform !== "win32" && (info.mode & 63) !== 0;
|
|
66981
|
+
if (info.isSymbolicLink() || !info.isFile() || unsafeMode)
|
|
66982
|
+
return refuse(path);
|
|
66983
|
+
} catch {
|
|
66984
|
+
return null;
|
|
66985
|
+
}
|
|
66986
|
+
try {
|
|
66987
|
+
return parse6(readFileSync4(path, "utf8"));
|
|
66988
|
+
} catch {
|
|
66989
|
+
return null;
|
|
66990
|
+
}
|
|
66991
|
+
},
|
|
66992
|
+
write(session) {
|
|
66993
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
66994
|
+
chmodSync(dir, 448);
|
|
66995
|
+
const tmp = `${path}.tmp`;
|
|
66996
|
+
rmSync(tmp, { force: true });
|
|
66997
|
+
const fd = openSync(tmp, "wx", 384);
|
|
66998
|
+
try {
|
|
66999
|
+
writeSync(fd, `${JSON.stringify(session)}
|
|
67000
|
+
`);
|
|
67001
|
+
} finally {
|
|
67002
|
+
closeSync(fd);
|
|
67003
|
+
}
|
|
67004
|
+
renameSync(tmp, path);
|
|
67005
|
+
},
|
|
67006
|
+
clear() {
|
|
67007
|
+
rmSync(path, { force: true });
|
|
67008
|
+
}
|
|
67009
|
+
};
|
|
67010
|
+
}
|
|
67011
|
+
function keychainSessionBackend(run = securityRun) {
|
|
67012
|
+
return {
|
|
67013
|
+
kind: "keychain",
|
|
67014
|
+
where: () => "the macOS login Keychain (service countersign, account session)",
|
|
67015
|
+
read() {
|
|
67016
|
+
try {
|
|
67017
|
+
const hex3 = run(["find-generic-password", "-s", "countersign", "-a", "session", "-w"]).trim();
|
|
67018
|
+
return hex3 === "" ? null : parse6(Buffer.from(hex3, "hex").toString("utf8"));
|
|
67019
|
+
} catch {
|
|
67020
|
+
return null;
|
|
67021
|
+
}
|
|
67022
|
+
},
|
|
67023
|
+
write(session) {
|
|
67024
|
+
const hex3 = Buffer.from(JSON.stringify(session), "utf8").toString("hex");
|
|
67025
|
+
run(["-i"], `add-generic-password -U -s countersign -a session -w ${hex3}
|
|
67026
|
+
`);
|
|
67027
|
+
},
|
|
67028
|
+
clear() {
|
|
67029
|
+
try {
|
|
67030
|
+
run(["delete-generic-password", "-s", "countersign", "-a", "session"]);
|
|
67031
|
+
} catch {}
|
|
67032
|
+
}
|
|
67033
|
+
};
|
|
67034
|
+
}
|
|
67035
|
+
function defaultSessionBackend(env = process.env) {
|
|
67036
|
+
if (env.COUNTERSIGN_KEYSTORE === "file")
|
|
67037
|
+
return fileSessionBackend();
|
|
67038
|
+
if (process.platform === "darwin" && existsSync3("/usr/bin/security"))
|
|
67039
|
+
return keychainSessionBackend();
|
|
67040
|
+
return fileSessionBackend();
|
|
67041
|
+
}
|
|
67042
|
+
function loadSession(backend = defaultSessionBackend(), now = Math.floor(Date.now() / 1000)) {
|
|
67043
|
+
const session = backend.read();
|
|
67044
|
+
return session !== null && session.expiresAt > now ? session : null;
|
|
67045
|
+
}
|
|
67046
|
+
|
|
67047
|
+
// packages/cli/src/login.ts
|
|
67048
|
+
var EXPIRED = `The login expired. Run countersign login again.
|
|
67049
|
+
`;
|
|
67050
|
+
var CONSOLE_ORIGIN = "https://web-production-a58de.up.railway.app";
|
|
67051
|
+
var UNSAFE_URL_CHARACTERS = /[&|^<>"%`;\s]/;
|
|
67052
|
+
var HUB_REFUSED = "Refused: the countersign hub must be https.";
|
|
67053
|
+
function safeConsoleUrl(url2, consoleOrigin = CONSOLE_ORIGIN) {
|
|
67054
|
+
if (UNSAFE_URL_CHARACTERS.test(url2))
|
|
67055
|
+
return null;
|
|
67056
|
+
let parsed;
|
|
67057
|
+
try {
|
|
67058
|
+
parsed = new URL(url2);
|
|
67059
|
+
} catch {
|
|
67060
|
+
return null;
|
|
67061
|
+
}
|
|
67062
|
+
if (parsed.protocol !== "https:")
|
|
67063
|
+
return null;
|
|
67064
|
+
if (parsed.origin !== consoleOrigin)
|
|
67065
|
+
return null;
|
|
67066
|
+
return url2;
|
|
67067
|
+
}
|
|
67068
|
+
function assertHubUrl(hub) {
|
|
67069
|
+
let parsed;
|
|
67070
|
+
try {
|
|
67071
|
+
parsed = new URL(hub);
|
|
67072
|
+
} catch {
|
|
67073
|
+
throw new Error(HUB_REFUSED);
|
|
67074
|
+
}
|
|
67075
|
+
const local = parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]");
|
|
67076
|
+
if (parsed.protocol !== "https:" && !local)
|
|
67077
|
+
throw new Error(HUB_REFUSED);
|
|
67078
|
+
return parsed.origin;
|
|
67079
|
+
}
|
|
67080
|
+
function defaultOpen(url2) {
|
|
67081
|
+
const windows = process.platform === "win32";
|
|
67082
|
+
const command = windows ? "rundll32" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
67083
|
+
const args = windows ? ["url.dll,FileProtocolHandler", url2] : [url2];
|
|
67084
|
+
const child = spawn3(command, args, { detached: true, stdio: "ignore", shell: false });
|
|
67085
|
+
child.on("error", () => {});
|
|
67086
|
+
child.unref();
|
|
67087
|
+
}
|
|
67088
|
+
function hubOrRefuse(hub) {
|
|
67089
|
+
try {
|
|
67090
|
+
return assertHubUrl(hub);
|
|
67091
|
+
} catch (error62) {
|
|
67092
|
+
process.stderr.write(`${error62 instanceof Error ? error62.message : String(error62)}
|
|
67093
|
+
`);
|
|
67094
|
+
process.exitCode = 1;
|
|
67095
|
+
return null;
|
|
67096
|
+
}
|
|
67097
|
+
}
|
|
67098
|
+
function expired() {
|
|
67099
|
+
process.stderr.write(EXPIRED);
|
|
67100
|
+
process.exitCode = 1;
|
|
67101
|
+
}
|
|
67102
|
+
async function runLogin(_args, deps) {
|
|
67103
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67104
|
+
const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
67105
|
+
const now = deps.now ?? (() => Math.floor(Date.now() / 1000));
|
|
67106
|
+
const open2 = deps.open ?? defaultOpen;
|
|
67107
|
+
const hub = hubOrRefuse(deps.hub);
|
|
67108
|
+
if (hub === null)
|
|
67109
|
+
return;
|
|
67110
|
+
let start;
|
|
67111
|
+
try {
|
|
67112
|
+
const response = await fetchImpl(`${hub}/cli/login/start`, { method: "POST" });
|
|
67113
|
+
if (!response.ok)
|
|
67114
|
+
throw new Error("start refused");
|
|
67115
|
+
start = await response.json();
|
|
67116
|
+
} catch {
|
|
67117
|
+
process.stderr.write(`The login could not start. Run countersign login again.
|
|
67118
|
+
`);
|
|
67119
|
+
process.exitCode = 1;
|
|
67120
|
+
return;
|
|
67121
|
+
}
|
|
67122
|
+
deps.write(`Open this link and sign in: ${start.verifyUrl}
|
|
67123
|
+
`);
|
|
67124
|
+
deps.write(`The page will show this code: ${start.code}
|
|
67125
|
+
`);
|
|
67126
|
+
const safeUrl = safeConsoleUrl(start.verifyUrl);
|
|
67127
|
+
if (safeUrl !== null) {
|
|
67128
|
+
try {
|
|
67129
|
+
open2(safeUrl);
|
|
67130
|
+
} catch {}
|
|
67131
|
+
}
|
|
67132
|
+
const interval = Number.isFinite(start.interval) && start.interval > 0 ? start.interval : 5;
|
|
67133
|
+
while (now() < start.expiresAt) {
|
|
67134
|
+
await sleep(interval * 1000);
|
|
67135
|
+
if (now() >= start.expiresAt)
|
|
67136
|
+
break;
|
|
67137
|
+
let poll2;
|
|
67138
|
+
try {
|
|
67139
|
+
const response = await fetchImpl(`${hub}/cli/login/poll`, {
|
|
67140
|
+
method: "POST",
|
|
67141
|
+
headers: { "content-type": "application/json" },
|
|
67142
|
+
body: JSON.stringify({ deviceSecret: start.deviceSecret })
|
|
67143
|
+
});
|
|
67144
|
+
if (response.status === 410)
|
|
67145
|
+
return expired();
|
|
67146
|
+
if (!response.ok)
|
|
67147
|
+
return expired();
|
|
67148
|
+
poll2 = await response.json();
|
|
67149
|
+
} catch {
|
|
67150
|
+
continue;
|
|
67151
|
+
}
|
|
67152
|
+
if (poll2.status === "approved") {
|
|
67153
|
+
const session = {
|
|
67154
|
+
token: poll2.sessionToken,
|
|
67155
|
+
hub,
|
|
67156
|
+
address: poll2.address,
|
|
67157
|
+
expiresAt: poll2.expiresAt
|
|
67158
|
+
};
|
|
67159
|
+
deps.backend.write(session);
|
|
67160
|
+
deps.write(`Signed in. Your agent wallet: ${poll2.address}
|
|
67161
|
+
`);
|
|
67162
|
+
deps.write(`Fund it: send testnet USDC to ${poll2.address} (Circle faucet: https://faucet.circle.com).
|
|
67163
|
+
`);
|
|
67164
|
+
deps.write(`For Whitechain, get test WBT for gas at https://faucet.testnet.whitechain.io.
|
|
67165
|
+
`);
|
|
67166
|
+
deps.write(`The session lasts 7 days; countersign logout ends it.
|
|
67167
|
+
`);
|
|
67168
|
+
return;
|
|
67169
|
+
}
|
|
67170
|
+
if (poll2.status !== "pending")
|
|
67171
|
+
return expired();
|
|
67172
|
+
}
|
|
67173
|
+
expired();
|
|
67174
|
+
}
|
|
67175
|
+
async function runLogout(_args, deps) {
|
|
67176
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67177
|
+
const session = loadSession(deps.backend);
|
|
67178
|
+
if (session === null) {
|
|
67179
|
+
deps.backend.clear();
|
|
67180
|
+
deps.write(`Not signed in.
|
|
67181
|
+
`);
|
|
67182
|
+
return;
|
|
67183
|
+
}
|
|
67184
|
+
let confirmed = false;
|
|
67185
|
+
try {
|
|
67186
|
+
assertHubUrl(session.hub);
|
|
67187
|
+
const response = await fetchImpl(`${session.hub}/cli/logout`, {
|
|
67188
|
+
method: "POST",
|
|
67189
|
+
headers: { Authorization: `Bearer ${session.token}` }
|
|
67190
|
+
});
|
|
67191
|
+
confirmed = response.ok;
|
|
67192
|
+
} catch {}
|
|
67193
|
+
deps.backend.clear();
|
|
67194
|
+
if (confirmed) {
|
|
67195
|
+
deps.write(`Signed out.
|
|
67196
|
+
`);
|
|
67197
|
+
} else {
|
|
67198
|
+
const expiry = new Date(session.expiresAt * 1000).toISOString();
|
|
67199
|
+
deps.write(`Signed out here; the hub did not confirm, so the session stays valid until ${expiry}.
|
|
67200
|
+
`);
|
|
67201
|
+
}
|
|
67202
|
+
}
|
|
67203
|
+
async function runWhoami(_args, deps) {
|
|
67204
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
67205
|
+
const readBalances = deps.balances ?? defaultBalances;
|
|
67206
|
+
const session = loadSession(deps.backend);
|
|
67207
|
+
if (session === null) {
|
|
67208
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67209
|
+
`);
|
|
67210
|
+
process.exitCode = 1;
|
|
67211
|
+
return;
|
|
67212
|
+
}
|
|
67213
|
+
try {
|
|
67214
|
+
assertHubUrl(session.hub);
|
|
67215
|
+
} catch {
|
|
67216
|
+
deps.backend.clear();
|
|
67217
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67218
|
+
`);
|
|
67219
|
+
process.exitCode = 1;
|
|
67220
|
+
return;
|
|
67221
|
+
}
|
|
67222
|
+
let response;
|
|
67223
|
+
try {
|
|
67224
|
+
response = await fetchImpl(`${session.hub}/cli/session`, {
|
|
67225
|
+
headers: { Authorization: `Bearer ${session.token}` }
|
|
67226
|
+
});
|
|
67227
|
+
} catch {
|
|
67228
|
+
process.stderr.write(`countersign whoami could not reach the hub.
|
|
67229
|
+
`);
|
|
67230
|
+
process.exitCode = 1;
|
|
67231
|
+
return;
|
|
67232
|
+
}
|
|
67233
|
+
if (response.status === 401) {
|
|
67234
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67235
|
+
`);
|
|
67236
|
+
process.exitCode = 1;
|
|
67237
|
+
return;
|
|
67238
|
+
}
|
|
67239
|
+
if (!response.ok) {
|
|
67240
|
+
process.stderr.write(`countersign whoami could not read the session.
|
|
67241
|
+
`);
|
|
67242
|
+
process.exitCode = 1;
|
|
67243
|
+
return;
|
|
67244
|
+
}
|
|
67245
|
+
const body = await response.json();
|
|
67246
|
+
deps.write(`Signed in as ${body.address} until ${new Date(body.expiresAt * 1000).toISOString()}
|
|
67247
|
+
`);
|
|
67248
|
+
deps.write(`${await readBalances(body.address)}
|
|
67249
|
+
`);
|
|
67250
|
+
}
|
|
67251
|
+
var BALANCE_CHAINS = [
|
|
67252
|
+
{
|
|
67253
|
+
name: "Arc",
|
|
67254
|
+
symbol: "USDC",
|
|
67255
|
+
token: "0x3600000000000000000000000000000000000000",
|
|
67256
|
+
rpc: "https://rpc.testnet.arc.network"
|
|
67257
|
+
},
|
|
67258
|
+
{
|
|
67259
|
+
name: "Whitechain",
|
|
67260
|
+
symbol: "USDT",
|
|
67261
|
+
token: "0xcedfB56113143d55b2358b8CFbB0dEB5Ad2f55a7",
|
|
67262
|
+
rpc: "https://rpc.ankr.com/whitechain_testnet"
|
|
67263
|
+
}
|
|
67264
|
+
];
|
|
67265
|
+
async function defaultBalances(address) {
|
|
67266
|
+
const parts = await Promise.all(BALANCE_CHAINS.map(async (chain) => {
|
|
67267
|
+
try {
|
|
67268
|
+
const client = createPublicClient({ transport: http(chain.rpc) });
|
|
67269
|
+
const balance = await client.readContract({
|
|
67270
|
+
address: chain.token,
|
|
67271
|
+
abi: erc20Abi,
|
|
67272
|
+
functionName: "balanceOf",
|
|
67273
|
+
args: [address]
|
|
67274
|
+
});
|
|
67275
|
+
return `${formatUnits3(balance, 6)} ${chain.symbol} on ${chain.name}`;
|
|
67276
|
+
} catch {
|
|
67277
|
+
return `unavailable ${chain.symbol} on ${chain.name}`;
|
|
67278
|
+
}
|
|
67279
|
+
}));
|
|
67280
|
+
return parts.join(", ");
|
|
67281
|
+
}
|
|
67282
|
+
|
|
66452
67283
|
// packages/cli/src/cli.ts
|
|
66453
|
-
var VERSION = "0.1.
|
|
67284
|
+
var VERSION = "0.1.1";
|
|
67285
|
+
var DEFAULT_HUB3 = "https://hub-production-e85e.up.railway.app";
|
|
66454
67286
|
var USAGE2 = `countersign ${VERSION}
|
|
66455
67287
|
|
|
66456
|
-
Sell. The runner dials out to the hub, so you open no port.
|
|
67288
|
+
Sell. The runner dials out to the hub, so you open no port.
|
|
66457
67289
|
countersign sell skill <SKILL.md> --hub <url> --price <atomic> [runner flags]
|
|
66458
67290
|
countersign sell openapi --spec <spec.json> --operation <id> --hub <url> --price <atomic> [--base-url <url>] [runner flags]
|
|
66459
67291
|
Add --publish-only to list the offer without serving it.
|
|
66460
67292
|
|
|
66461
|
-
Buy.
|
|
67293
|
+
Buy.
|
|
66462
67294
|
countersign discover|buy|envelope|journal [--hub <url>] [--state <dir>] ...
|
|
66463
67295
|
|
|
67296
|
+
Sign in, and check the session:
|
|
67297
|
+
countersign login|logout|whoami
|
|
67298
|
+
|
|
66464
67299
|
Verify a slip offline:
|
|
66465
67300
|
countersign verify <slip.json> [--rpc <url>]
|
|
66466
67301
|
|
|
66467
67302
|
The buyer MCP server over stdio:
|
|
66468
67303
|
countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
67304
|
+
|
|
67305
|
+
Start here: countersign login, then fund the printed address, then buy or sell.
|
|
67306
|
+
The default hub is ${DEFAULT_HUB3}.
|
|
66469
67307
|
`;
|
|
67308
|
+
var COMMAND_USAGE = {
|
|
67309
|
+
login: `Usage: countersign login
|
|
67310
|
+
Opens a sign-in link; your agent wallet is a Privy server wallet, so no key is ever on this machine.
|
|
67311
|
+
`,
|
|
67312
|
+
logout: `Usage: countersign logout
|
|
67313
|
+
Ends the session on the hub and removes the stored token.
|
|
67314
|
+
`,
|
|
67315
|
+
whoami: `Usage: countersign whoami
|
|
67316
|
+
Shows the signed-in address, the session expiry and testnet balances.
|
|
67317
|
+
`,
|
|
67318
|
+
sell: `Usage: countersign sell skill <SKILL.md> --hub <url> --price <atomic> [runner flags]
|
|
67319
|
+
countersign sell openapi --spec <spec.json> --operation <id> --hub <url> --price <atomic> [--base-url <url>] [runner flags]
|
|
67320
|
+
Add --publish-only to list the offer without serving it.
|
|
67321
|
+
`,
|
|
67322
|
+
discover: `Usage: countersign discover [--hub <url>] [--state <dir>] [--catalogue <url|circle> [query] [--category <c>] [--limit <n>]]
|
|
67323
|
+
`,
|
|
67324
|
+
buy: `Usage: countersign buy <offerHash|callUrl> --input '<json>' [--approve] [--rail <id>] [--approvals hub] [--hub <url>] [--state <dir>]
|
|
67325
|
+
`,
|
|
67326
|
+
envelope: `Usage: countersign envelope show|set [--hub <url>] [--state <dir>]
|
|
67327
|
+
`,
|
|
67328
|
+
journal: `Usage: countersign journal [--hub <url>] [--state <dir>]
|
|
67329
|
+
`,
|
|
67330
|
+
verify: `Usage: countersign verify <slip.json> [--rpc <url>] [--mirror <url>]
|
|
67331
|
+
`,
|
|
67332
|
+
mcp: `Usage: countersign mcp [--hub <url>] [--state <dir>] [--rpc <url>]
|
|
67333
|
+
`
|
|
67334
|
+
};
|
|
66470
67335
|
var BUYER_COMMANDS = new Set(["discover", "buy", "envelope", "journal"]);
|
|
67336
|
+
function withHub(args2, env = process.env) {
|
|
67337
|
+
for (const arg of args2) {
|
|
67338
|
+
if (arg === "--hub" || arg.startsWith("--hub="))
|
|
67339
|
+
return args2;
|
|
67340
|
+
}
|
|
67341
|
+
const hub = env.CS_HUB !== undefined && env.CS_HUB !== "" ? env.CS_HUB : DEFAULT_HUB3;
|
|
67342
|
+
return [...args2, "--hub", hub];
|
|
67343
|
+
}
|
|
67344
|
+
function hubValue(args2, env = process.env) {
|
|
67345
|
+
const settled = withHub(args2, env);
|
|
67346
|
+
const last = settled.at(-1) ?? DEFAULT_HUB3;
|
|
67347
|
+
return last.startsWith("--hub=") ? last.slice("--hub=".length) : last;
|
|
67348
|
+
}
|
|
67349
|
+
function useSession(env = process.env) {
|
|
67350
|
+
if (env.CS_BUYER_KEY !== undefined || env.CS_SELLER_KEY !== undefined)
|
|
67351
|
+
return true;
|
|
67352
|
+
const session = loadSession();
|
|
67353
|
+
if (session === null)
|
|
67354
|
+
return false;
|
|
67355
|
+
let hub;
|
|
67356
|
+
try {
|
|
67357
|
+
hub = assertHubUrl(session.hub);
|
|
67358
|
+
} catch {
|
|
67359
|
+
return false;
|
|
67360
|
+
}
|
|
67361
|
+
env.CS_SESSION = session.token;
|
|
67362
|
+
env.CS_HUB = hub;
|
|
67363
|
+
return true;
|
|
67364
|
+
}
|
|
66471
67365
|
var DEFAULT_DEPS = {
|
|
66472
|
-
runner: (argv) =>
|
|
66473
|
-
|
|
67366
|
+
runner: async (argv) => {
|
|
67367
|
+
if (!useSession())
|
|
67368
|
+
return requireLogin();
|
|
67369
|
+
await main(withHub(argv));
|
|
67370
|
+
},
|
|
67371
|
+
loadBuyer: async () => {
|
|
67372
|
+
if (!useSession() && needsSession())
|
|
67373
|
+
return requireLogin();
|
|
67374
|
+
setArgv(withHub(process.argv.slice(2)));
|
|
67375
|
+
await Promise.resolve().then(() => (init_cli(), exports_cli));
|
|
67376
|
+
},
|
|
66474
67377
|
loadVerify: () => init_cli2().then(() => exports_cli2),
|
|
66475
|
-
loadMcp:
|
|
67378
|
+
loadMcp: async () => {
|
|
67379
|
+
useSession();
|
|
67380
|
+
return Promise.resolve().then(() => (init_main(), exports_main));
|
|
67381
|
+
}
|
|
66476
67382
|
};
|
|
66477
67383
|
function runnerArgs(rest) {
|
|
66478
67384
|
const publishOnly = rest.includes("--publish-only");
|
|
@@ -66514,10 +67420,29 @@ async function run(argv, deps = DEFAULT_DEPS) {
|
|
|
66514
67420
|
`);
|
|
66515
67421
|
return;
|
|
66516
67422
|
}
|
|
67423
|
+
const commandUsage = COMMAND_USAGE[command];
|
|
67424
|
+
if (commandUsage !== undefined && (rest.includes("--help") || rest.includes("-h"))) {
|
|
67425
|
+
process.stdout.write(commandUsage);
|
|
67426
|
+
return;
|
|
67427
|
+
}
|
|
67428
|
+
if (command === "login" || command === "logout" || command === "whoami") {
|
|
67429
|
+
const loginDeps = {
|
|
67430
|
+
backend: defaultSessionBackend(),
|
|
67431
|
+
hub: hubValue(rest),
|
|
67432
|
+
write: (t) => process.stdout.write(t)
|
|
67433
|
+
};
|
|
67434
|
+
if (command === "login")
|
|
67435
|
+
await runLogin(rest, loginDeps);
|
|
67436
|
+
else if (command === "logout")
|
|
67437
|
+
await runLogout(rest, loginDeps);
|
|
67438
|
+
else
|
|
67439
|
+
await runWhoami(rest, loginDeps);
|
|
67440
|
+
return;
|
|
67441
|
+
}
|
|
66517
67442
|
if (command === "sell") {
|
|
66518
67443
|
const mapped = runnerArgs(rest);
|
|
66519
67444
|
if (!mapped.ok)
|
|
66520
|
-
return
|
|
67445
|
+
return refuse3(mapped.error);
|
|
66521
67446
|
await deps.runner(mapped.args);
|
|
66522
67447
|
return;
|
|
66523
67448
|
}
|
|
@@ -66536,20 +67461,29 @@ async function run(argv, deps = DEFAULT_DEPS) {
|
|
|
66536
67461
|
try {
|
|
66537
67462
|
loaded = await deps.loadMcp();
|
|
66538
67463
|
} catch {
|
|
66539
|
-
return
|
|
67464
|
+
return refuse3("countersign mcp could not load its MCP server.");
|
|
66540
67465
|
}
|
|
66541
67466
|
const main4 = isRecord10(loaded) ? loaded.main : undefined;
|
|
66542
67467
|
if (typeof main4 !== "function")
|
|
66543
|
-
return
|
|
67468
|
+
return refuse3("The MCP server has no main(argv) export.");
|
|
66544
67469
|
await main4(rest);
|
|
66545
67470
|
return;
|
|
66546
67471
|
}
|
|
66547
|
-
return
|
|
67472
|
+
return refuse3(`countersign: unknown command '${command}'.`);
|
|
66548
67473
|
}
|
|
66549
67474
|
function setArgv(args2) {
|
|
66550
67475
|
process.argv = [process.argv[0] ?? "node", "countersign", ...args2];
|
|
66551
67476
|
}
|
|
66552
|
-
function
|
|
67477
|
+
function needsSession() {
|
|
67478
|
+
const [command, verb] = process.argv.slice(2);
|
|
67479
|
+
return command === "buy" || command === "journal" || command === "envelope" && verb === "set";
|
|
67480
|
+
}
|
|
67481
|
+
function requireLogin() {
|
|
67482
|
+
process.stderr.write(`${NOT_SIGNED_IN2}
|
|
67483
|
+
`);
|
|
67484
|
+
process.exitCode = 1;
|
|
67485
|
+
}
|
|
67486
|
+
function refuse3(message) {
|
|
66553
67487
|
process.stderr.write(`${message}
|
|
66554
67488
|
|
|
66555
67489
|
${USAGE2}`);
|
|
@@ -66566,4 +67500,4 @@ run(process.argv.slice(2)).catch((error62) => {
|
|
|
66566
67500
|
process.exitCode = 1;
|
|
66567
67501
|
});
|
|
66568
67502
|
|
|
66569
|
-
//# debugId=
|
|
67503
|
+
//# debugId=086E31B6AC676B0A64756E2164756E21
|