@zeroxyz/cli 0.0.41 → 0.0.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +432 -110
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { homedir as
|
|
5
|
-
import { join as
|
|
4
|
+
import { homedir as homedir9 } from "os";
|
|
5
|
+
import { join as join11 } from "path";
|
|
6
6
|
|
|
7
7
|
// package.json
|
|
8
8
|
var package_default = {
|
|
9
9
|
name: "@zeroxyz/cli",
|
|
10
|
-
version: "0.0.
|
|
10
|
+
version: "0.0.43",
|
|
11
11
|
type: "module",
|
|
12
12
|
bin: {
|
|
13
13
|
zero: "dist/index.js",
|
|
@@ -61,7 +61,7 @@ var package_default = {
|
|
|
61
61
|
};
|
|
62
62
|
|
|
63
63
|
// src/app.ts
|
|
64
|
-
import { Command as
|
|
64
|
+
import { Command as Command14 } from "commander";
|
|
65
65
|
|
|
66
66
|
// src/commands/auth-command.ts
|
|
67
67
|
import { homedir } from "os";
|
|
@@ -204,8 +204,7 @@ var searchResultSchema = z.object({
|
|
|
204
204
|
cost: z.object({ amount: z.string(), asset: z.string() }),
|
|
205
205
|
reviewCount: z.number().optional(),
|
|
206
206
|
rating: ratingSchema,
|
|
207
|
-
availabilityStatus: z.enum(["healthy", "
|
|
208
|
-
displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
|
|
207
|
+
availabilityStatus: z.enum(["healthy", "unknown", "down"]).nullable().optional(),
|
|
209
208
|
// Pass-through: API stamps this on Zero-published / withzero.{ai,xyz}
|
|
210
209
|
// services so `zero search --json` consumers can render their own
|
|
211
210
|
// provenance UI. CLI doesn't render a badge today.
|
|
@@ -258,8 +257,7 @@ var capabilityResponseSchema = z.object({
|
|
|
258
257
|
priority: z.number()
|
|
259
258
|
})
|
|
260
259
|
).nullable(),
|
|
261
|
-
availabilityStatus: z.enum(["healthy", "
|
|
262
|
-
displayStatus: z.enum(["healthy", "stable", "degraded", "unhealthy", "unknown"]).optional(),
|
|
260
|
+
availabilityStatus: z.enum(["healthy", "unknown", "down"]).nullable().optional(),
|
|
263
261
|
activationCount: z.number().optional(),
|
|
264
262
|
lastUsedAt: z.string().nullable().optional(),
|
|
265
263
|
lastSuccessfullyRanAt: z.string().nullable().optional(),
|
|
@@ -586,16 +584,37 @@ var ApiService = class _ApiService {
|
|
|
586
584
|
});
|
|
587
585
|
return createBugReportResponseSchema.parse(json);
|
|
588
586
|
};
|
|
587
|
+
// Mints a one-time onramp URL for the caller's wallet. Two paths, picked by
|
|
588
|
+
// which identity is available:
|
|
589
|
+
// • BYO key present (this.account) → /v1/wallet/fund-url, proving ownership
|
|
590
|
+
// with an EIP-191 signature.
|
|
591
|
+
// • No key but a session (managed/runner) → /v1/users/me/fund-url, which
|
|
592
|
+
// resolves the user's managed wallet server-side from the Bearer.
|
|
593
|
+
// Both honor the `provider` choice. Returns null on any failure so callers
|
|
594
|
+
// can fall back to manual transfer.
|
|
589
595
|
getFundingUrl = async (amount, provider = "coinbase") => {
|
|
590
596
|
try {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
597
|
+
if (this.account) {
|
|
598
|
+
const params = new URLSearchParams({ provider });
|
|
599
|
+
if (amount) params.set("amount", amount);
|
|
600
|
+
const json = await this.request(
|
|
601
|
+
"GET",
|
|
602
|
+
`/v1/wallet/fund-url?${params.toString()}`,
|
|
603
|
+
void 0,
|
|
604
|
+
{ auth: "wallet-attributed" }
|
|
605
|
+
);
|
|
606
|
+
return z.object({ url: z.string() }).parse(json).url;
|
|
607
|
+
}
|
|
608
|
+
if (this.credentials.kind === "session") {
|
|
609
|
+
const params = new URLSearchParams({ provider });
|
|
610
|
+
if (amount) params.set("amount", amount);
|
|
611
|
+
const json = await this.request(
|
|
612
|
+
"GET",
|
|
613
|
+
`/v1/users/me/fund-url?${params.toString()}`
|
|
614
|
+
);
|
|
615
|
+
return z.object({ url: z.string(), walletAddress: z.string() }).parse(json).url;
|
|
616
|
+
}
|
|
617
|
+
return null;
|
|
599
618
|
} catch {
|
|
600
619
|
return null;
|
|
601
620
|
}
|
|
@@ -965,6 +984,61 @@ import {
|
|
|
965
984
|
http
|
|
966
985
|
} from "viem";
|
|
967
986
|
import { base, baseSepolia, tempo as viemTempoChain } from "viem/chains";
|
|
987
|
+
|
|
988
|
+
// src/services/x402-challenge.ts
|
|
989
|
+
import { encodePaymentRequiredHeader } from "@x402/core/http";
|
|
990
|
+
var looksLikeX402Body = (body) => {
|
|
991
|
+
if (!body || typeof body !== "object") return false;
|
|
992
|
+
const b = body;
|
|
993
|
+
return typeof b.x402Version === "number" && Array.isArray(b.accepts) && b.accepts.length > 0;
|
|
994
|
+
};
|
|
995
|
+
var isV1ShapedAccept = (accept) => {
|
|
996
|
+
if (!accept || typeof accept !== "object") return false;
|
|
997
|
+
const a = accept;
|
|
998
|
+
const network = typeof a.network === "string" ? a.network : "";
|
|
999
|
+
const bareNetwork = network !== "" && !network.includes(":");
|
|
1000
|
+
const v1AmountField = a.maxAmountRequired != null && a.amount == null;
|
|
1001
|
+
return bareNetwork || v1AmountField;
|
|
1002
|
+
};
|
|
1003
|
+
var coerceX402BodyVersion = (challenge) => {
|
|
1004
|
+
const accepts = Array.isArray(challenge.accepts) ? challenge.accepts : [];
|
|
1005
|
+
return { ...challenge, x402Version: accepts.some(isV1ShapedAccept) ? 1 : 2 };
|
|
1006
|
+
};
|
|
1007
|
+
var withSynthesizedX402Header = (baseFetch) => async (input, init) => {
|
|
1008
|
+
const response = await baseFetch(input, init);
|
|
1009
|
+
if (response.status !== 402) return response;
|
|
1010
|
+
if (response.headers.get("payment-required") ?? response.headers.get("x-payment-required")) {
|
|
1011
|
+
return response;
|
|
1012
|
+
}
|
|
1013
|
+
const text = await response.clone().text();
|
|
1014
|
+
let parsed;
|
|
1015
|
+
try {
|
|
1016
|
+
parsed = JSON.parse(text);
|
|
1017
|
+
} catch {
|
|
1018
|
+
return response;
|
|
1019
|
+
}
|
|
1020
|
+
if (!looksLikeX402Body(parsed) || parsed.x402Version === 1) {
|
|
1021
|
+
return response;
|
|
1022
|
+
}
|
|
1023
|
+
const challenge = coerceX402BodyVersion(parsed);
|
|
1024
|
+
const headers = new Headers(response.headers);
|
|
1025
|
+
headers.set(
|
|
1026
|
+
"PAYMENT-REQUIRED",
|
|
1027
|
+
// Validated as an x402 body above; encoder wants the concrete type.
|
|
1028
|
+
encodePaymentRequiredHeader(
|
|
1029
|
+
challenge
|
|
1030
|
+
)
|
|
1031
|
+
);
|
|
1032
|
+
headers.delete("content-length");
|
|
1033
|
+
headers.delete("content-encoding");
|
|
1034
|
+
return new Response(text, {
|
|
1035
|
+
status: response.status,
|
|
1036
|
+
statusText: response.statusText,
|
|
1037
|
+
headers
|
|
1038
|
+
});
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
// src/services/payment-service.ts
|
|
968
1042
|
var SessionCloseFailedError = class extends Error {
|
|
969
1043
|
session;
|
|
970
1044
|
response;
|
|
@@ -1208,7 +1282,10 @@ var PaymentService = class {
|
|
|
1208
1282
|
const httpClient = new x402HTTPClient(client).onPaymentRequired(
|
|
1209
1283
|
createSIWxClientHook(this.account)
|
|
1210
1284
|
);
|
|
1211
|
-
const wrappedFetch = wrapFetchWithPayment(
|
|
1285
|
+
const wrappedFetch = wrapFetchWithPayment(
|
|
1286
|
+
withSynthesizedX402Header(fetch),
|
|
1287
|
+
httpClient
|
|
1288
|
+
);
|
|
1212
1289
|
const response = await wrappedFetch(url, {
|
|
1213
1290
|
method: request.method,
|
|
1214
1291
|
headers: request.headers,
|
|
@@ -1772,11 +1849,6 @@ var resolveRequestBody = (rawData, readStdin2) => {
|
|
|
1772
1849
|
}
|
|
1773
1850
|
return body;
|
|
1774
1851
|
};
|
|
1775
|
-
var looksLikeX402V1Body = (body) => {
|
|
1776
|
-
if (!body || typeof body !== "object") return false;
|
|
1777
|
-
const b = body;
|
|
1778
|
-
return b.x402Version === 1 && Array.isArray(b.accepts) && b.accepts.length > 0;
|
|
1779
|
-
};
|
|
1780
1852
|
var detectPaymentRequirement = async (response) => {
|
|
1781
1853
|
if (response.status !== 402) return null;
|
|
1782
1854
|
const x402Header = response.headers.get("payment-required") ?? response.headers.get("x-payment-required");
|
|
@@ -1798,7 +1870,7 @@ var detectPaymentRequirement = async (response) => {
|
|
|
1798
1870
|
const text = await response.clone().text();
|
|
1799
1871
|
if (text) {
|
|
1800
1872
|
const parsed = JSON.parse(text);
|
|
1801
|
-
if (
|
|
1873
|
+
if (looksLikeX402Body(parsed)) {
|
|
1802
1874
|
return { protocol: "x402", raw: parsed };
|
|
1803
1875
|
}
|
|
1804
1876
|
}
|
|
@@ -2403,7 +2475,7 @@ var formatCapability = (capability) => {
|
|
|
2403
2475
|
const lines = [];
|
|
2404
2476
|
lines.push(capability.name);
|
|
2405
2477
|
lines.push(` Rating: ${formatRating(capability.rating)}`);
|
|
2406
|
-
lines.push(` Status: ${capability.
|
|
2478
|
+
lines.push(` Status: ${capability.availabilityStatus ?? "unknown"}`);
|
|
2407
2479
|
lines.push(...formatCost(capability));
|
|
2408
2480
|
lines.push(` URL: ${capability.url}`);
|
|
2409
2481
|
lines.push(` Method: ${capability.method}`);
|
|
@@ -2645,6 +2717,8 @@ var AGENT_TOOLS = [
|
|
|
2645
2717
|
},
|
|
2646
2718
|
{ name: "Cursor", detectDir: ".cursor", skillsDir: ".cursor/skills" }
|
|
2647
2719
|
];
|
|
2720
|
+
var HOOK_FILES = ["auto-approve-zero.sh", "zero-context.sh"];
|
|
2721
|
+
var ZERO_SANDBOX_DOMAIN = "*.zero.xyz";
|
|
2648
2722
|
var findResourceDir = (startDir, resourceName) => {
|
|
2649
2723
|
let current = startDir;
|
|
2650
2724
|
while (true) {
|
|
@@ -2714,10 +2788,9 @@ var installHook = (home, verbose = false) => {
|
|
|
2714
2788
|
const zeroHooksDir = join3(home, ".zero", "hooks");
|
|
2715
2789
|
mkdirSync3(zeroHooksDir, { recursive: true });
|
|
2716
2790
|
if (verbose) stepInfo(`staged hook dir at ${zeroHooksDir}`);
|
|
2717
|
-
const hookFiles = ["auto-approve-zero.sh", "zero-context.sh"];
|
|
2718
2791
|
const hookDests = {};
|
|
2719
2792
|
const hooksSourceDir = findResourceDir(getCliModuleDir(), "hooks");
|
|
2720
|
-
for (const hookFile of
|
|
2793
|
+
for (const hookFile of HOOK_FILES) {
|
|
2721
2794
|
const hookSource = join3(hooksSourceDir, hookFile);
|
|
2722
2795
|
const hookDest = join3(zeroHooksDir, hookFile);
|
|
2723
2796
|
copyFile(hookSource, hookDest);
|
|
@@ -2820,12 +2893,15 @@ var installHook = (home, verbose = false) => {
|
|
|
2820
2893
|
network.allowedDomains = [];
|
|
2821
2894
|
}
|
|
2822
2895
|
const allowedDomains = network.allowedDomains;
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2896
|
+
if (!allowedDomains.includes(ZERO_SANDBOX_DOMAIN)) {
|
|
2897
|
+
allowedDomains.push(ZERO_SANDBOX_DOMAIN);
|
|
2898
|
+
if (verbose) {
|
|
2899
|
+
stepInfo(`sandbox.network.allowedDomains += ${ZERO_SANDBOX_DOMAIN}`);
|
|
2900
|
+
}
|
|
2827
2901
|
} else if (verbose) {
|
|
2828
|
-
stepInfo(
|
|
2902
|
+
stepInfo(
|
|
2903
|
+
`${ZERO_SANDBOX_DOMAIN} already in sandbox allowlist \u2014 not modified`
|
|
2904
|
+
);
|
|
2829
2905
|
}
|
|
2830
2906
|
writeFileSync3(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
2831
2907
|
`);
|
|
@@ -2861,6 +2937,14 @@ var removeConflictingSkills = (home) => {
|
|
|
2861
2937
|
}
|
|
2862
2938
|
return removed;
|
|
2863
2939
|
};
|
|
2940
|
+
var getBundledSkillNames = () => {
|
|
2941
|
+
try {
|
|
2942
|
+
const skillsSourceDir = findResourceDir(getCliModuleDir(), "skills");
|
|
2943
|
+
return readdirSync(skillsSourceDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
2944
|
+
} catch {
|
|
2945
|
+
return ["zero"];
|
|
2946
|
+
}
|
|
2947
|
+
};
|
|
2864
2948
|
var installSkills = (home, verbose = false) => {
|
|
2865
2949
|
const skillsSourceDir = findResourceDir(getCliModuleDir(), "skills");
|
|
2866
2950
|
const skillDirs = readdirSync(skillsSourceDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -3404,8 +3488,16 @@ var formatRatingBadge = (rating) => {
|
|
|
3404
3488
|
return `${successPct} success \xB7 ${reviews} reviews`;
|
|
3405
3489
|
};
|
|
3406
3490
|
var formatStatusBadge = (status) => {
|
|
3407
|
-
|
|
3408
|
-
|
|
3491
|
+
switch (status) {
|
|
3492
|
+
case "healthy":
|
|
3493
|
+
return ` \u2014 ${color.green("\u2713 healthy")}`;
|
|
3494
|
+
case "down":
|
|
3495
|
+
return ` \u2014 ${color.red("\u2717 down")}`;
|
|
3496
|
+
case "unknown":
|
|
3497
|
+
return ` \u2014 ${color.yellow("? unknown")}`;
|
|
3498
|
+
default:
|
|
3499
|
+
return "";
|
|
3500
|
+
}
|
|
3409
3501
|
};
|
|
3410
3502
|
var formatSearchResults = (results) => {
|
|
3411
3503
|
if (results.length === 0) return "No capabilities found.";
|
|
@@ -3414,7 +3506,7 @@ var formatSearchResults = (results) => {
|
|
|
3414
3506
|
const displayName = r.brandName ? `${r.brandName} ${baseName}` : baseName;
|
|
3415
3507
|
const displayDescription = r.whatItDoes ?? r.description;
|
|
3416
3508
|
const ratingBadge = formatRatingBadge(r.rating);
|
|
3417
|
-
const statusBadge = formatStatusBadge(r.
|
|
3509
|
+
const statusBadge = formatStatusBadge(r.availabilityStatus);
|
|
3418
3510
|
const costLabel = r.cost.amount === "0" ? "Free" : r.cost.amount === "unknown" ? "variable pricing" : `$${r.cost.amount}/call`;
|
|
3419
3511
|
return ` ${r.position}. ${displayName} \u2014 ${costLabel} \u2014 ${ratingBadge}${statusBadge}
|
|
3420
3512
|
"${displayDescription}"`;
|
|
@@ -3425,7 +3517,7 @@ var searchCommand = (appContext) => new Command9("search").description("Search f
|
|
|
3425
3517
|
`Maximum cost per call in USD (default: ${DEFAULT_MAX_COST_USD})`
|
|
3426
3518
|
).option("--protocol <protocol>", "Payment protocol (x402 or mpp)").option(
|
|
3427
3519
|
"--status <status>",
|
|
3428
|
-
"Filter by availability (healthy, unknown, down).
|
|
3520
|
+
"Filter by availability (healthy, unknown, down). Default (unset) returns healthy + unknown with healthy first; pass 'healthy' for only-healthy, or --all to include everything."
|
|
3429
3521
|
).option("--all", "Disable default quality filtering").option(
|
|
3430
3522
|
"--source <source>",
|
|
3431
3523
|
"Only show results from this crawl source (e.g. mpp, bazaar)"
|
|
@@ -3460,12 +3552,8 @@ var searchCommand = (appContext) => new Command9("search").description("Search f
|
|
|
3460
3552
|
process.exitCode = 1;
|
|
3461
3553
|
return;
|
|
3462
3554
|
}
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
if (effectiveStatus === void 0 && !options.all) {
|
|
3466
|
-
effectiveStatus = "healthy";
|
|
3467
|
-
appliedDefaultStatus = true;
|
|
3468
|
-
}
|
|
3555
|
+
const effectiveStatus = options.status;
|
|
3556
|
+
const appliedDefaultStatus = effectiveStatus === void 0 && !options.all;
|
|
3469
3557
|
const result = await apiService.search({
|
|
3470
3558
|
query,
|
|
3471
3559
|
offset: options.offset,
|
|
@@ -3562,23 +3650,256 @@ Read the full terms at: ${TERMS_URL}
|
|
|
3562
3650
|
}
|
|
3563
3651
|
});
|
|
3564
3652
|
|
|
3565
|
-
// src/commands/
|
|
3566
|
-
import {
|
|
3653
|
+
// src/commands/uninstall-command.ts
|
|
3654
|
+
import {
|
|
3655
|
+
existsSync as existsSync3,
|
|
3656
|
+
readdirSync as readdirSync2,
|
|
3657
|
+
readFileSync as readFileSync7,
|
|
3658
|
+
rmSync as rmSync2,
|
|
3659
|
+
writeFileSync as writeFileSync4
|
|
3660
|
+
} from "fs";
|
|
3567
3661
|
import { homedir as homedir4 } from "os";
|
|
3568
|
-
import { join as
|
|
3569
|
-
import { confirm, isCancel } from "@clack/prompts";
|
|
3662
|
+
import { join as join4 } from "path";
|
|
3570
3663
|
import { Command as Command11 } from "commander";
|
|
3664
|
+
var removeSkills = (home, verbose = false) => {
|
|
3665
|
+
const skillNames = getBundledSkillNames();
|
|
3666
|
+
const removed = [];
|
|
3667
|
+
for (const tool of AGENT_TOOLS) {
|
|
3668
|
+
const toolSkillsPath = join4(home, tool.skillsDir);
|
|
3669
|
+
if (!existsSync3(toolSkillsPath)) {
|
|
3670
|
+
if (verbose) {
|
|
3671
|
+
stepInfo(
|
|
3672
|
+
`${tool.name}: ~/${tool.skillsDir} not found \u2014 nothing to remove`
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
continue;
|
|
3676
|
+
}
|
|
3677
|
+
for (const skillName of skillNames) {
|
|
3678
|
+
const skillPath = join4(toolSkillsPath, skillName);
|
|
3679
|
+
if (!existsSync3(skillPath)) continue;
|
|
3680
|
+
rmSync2(skillPath, { recursive: true, force: true });
|
|
3681
|
+
removed.push(`${tool.name}: ${skillPath}`);
|
|
3682
|
+
if (verbose) stepInfo(`${tool.name}: removed skill '${skillName}'`);
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
return removed;
|
|
3686
|
+
};
|
|
3687
|
+
var removeHooks = (home, verbose = false) => {
|
|
3688
|
+
let settingsChanged = false;
|
|
3689
|
+
const settingsPath = join4(home, ".claude", "settings.json");
|
|
3690
|
+
if (!existsSync3(settingsPath)) {
|
|
3691
|
+
if (verbose) stepInfo(`${settingsPath} not found \u2014 no settings to clean`);
|
|
3692
|
+
} else {
|
|
3693
|
+
let settings = null;
|
|
3694
|
+
try {
|
|
3695
|
+
settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
|
|
3696
|
+
} catch {
|
|
3697
|
+
if (verbose) {
|
|
3698
|
+
stepInfo(`${settingsPath} was unparseable JSON \u2014 leaving it untouched`);
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
if (settings) {
|
|
3702
|
+
settingsChanged = stripZeroFromSettings(settings, verbose);
|
|
3703
|
+
if (settingsChanged) {
|
|
3704
|
+
writeFileSync4(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
3705
|
+
`);
|
|
3706
|
+
if (verbose) stepInfo(`rewrote ${settingsPath} without Zero entries`);
|
|
3707
|
+
} else if (verbose) {
|
|
3708
|
+
stepInfo(`no Zero entries found in ${settingsPath}`);
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
let scriptsRemoved = 0;
|
|
3713
|
+
const zeroHooksDir = join4(home, ".zero", "hooks");
|
|
3714
|
+
if (existsSync3(zeroHooksDir)) {
|
|
3715
|
+
for (const hookFile of HOOK_FILES) {
|
|
3716
|
+
const hookPath = join4(zeroHooksDir, hookFile);
|
|
3717
|
+
if (!existsSync3(hookPath)) continue;
|
|
3718
|
+
rmSync2(hookPath, { force: true });
|
|
3719
|
+
scriptsRemoved++;
|
|
3720
|
+
if (verbose) stepInfo(`removed ${hookPath}`);
|
|
3721
|
+
}
|
|
3722
|
+
if (readdirSync2(zeroHooksDir).length === 0) {
|
|
3723
|
+
rmSync2(zeroHooksDir, { recursive: true, force: true });
|
|
3724
|
+
if (verbose) stepInfo(`removed empty ${zeroHooksDir}`);
|
|
3725
|
+
}
|
|
3726
|
+
} else if (verbose) {
|
|
3727
|
+
stepInfo(`${zeroHooksDir} not found \u2014 no hook scripts to remove`);
|
|
3728
|
+
}
|
|
3729
|
+
return { settingsChanged, scriptsRemoved };
|
|
3730
|
+
};
|
|
3731
|
+
var stripZeroFromSettings = (settings, verbose) => {
|
|
3732
|
+
let changed = false;
|
|
3733
|
+
const hooks = settings.hooks && typeof settings.hooks === "object" ? settings.hooks : null;
|
|
3734
|
+
if (hooks) {
|
|
3735
|
+
changed = removeHookEntries(hooks, "PreToolUse", "auto-approve-zero", verbose) || changed;
|
|
3736
|
+
changed = removeHookEntries(hooks, "UserPromptSubmit", "zero-context", verbose) || changed;
|
|
3737
|
+
for (const key of ["PreToolUse", "UserPromptSubmit"]) {
|
|
3738
|
+
const arr = hooks[key];
|
|
3739
|
+
if (Array.isArray(arr) && arr.length === 0) delete hooks[key];
|
|
3740
|
+
}
|
|
3741
|
+
if (Object.keys(hooks).length === 0) delete settings.hooks;
|
|
3742
|
+
}
|
|
3743
|
+
const sandbox = settings.sandbox && typeof settings.sandbox === "object" ? settings.sandbox : null;
|
|
3744
|
+
const network = sandbox?.network && typeof sandbox.network === "object" ? sandbox.network : null;
|
|
3745
|
+
if (network && Array.isArray(network.allowedDomains)) {
|
|
3746
|
+
const domains = network.allowedDomains;
|
|
3747
|
+
const next = domains.filter((d) => d !== ZERO_SANDBOX_DOMAIN);
|
|
3748
|
+
if (next.length !== domains.length) {
|
|
3749
|
+
changed = true;
|
|
3750
|
+
if (verbose) {
|
|
3751
|
+
stepInfo(`sandbox.network.allowedDomains -= ${ZERO_SANDBOX_DOMAIN}`);
|
|
3752
|
+
}
|
|
3753
|
+
if (next.length === 0) {
|
|
3754
|
+
delete network.allowedDomains;
|
|
3755
|
+
if (sandbox && Object.keys(network).length === 0)
|
|
3756
|
+
delete sandbox.network;
|
|
3757
|
+
if (sandbox && Object.keys(sandbox).length === 0)
|
|
3758
|
+
delete settings.sandbox;
|
|
3759
|
+
} else {
|
|
3760
|
+
network.allowedDomains = next;
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
return changed;
|
|
3765
|
+
};
|
|
3766
|
+
var removeHookEntries = (hooks, hookType, commandSubstring, verbose) => {
|
|
3767
|
+
const entries = hooks[hookType];
|
|
3768
|
+
if (!Array.isArray(entries)) return false;
|
|
3769
|
+
const next = entries.filter((entry) => {
|
|
3770
|
+
const entryHooks = entry?.hooks;
|
|
3771
|
+
if (!Array.isArray(entryHooks)) return true;
|
|
3772
|
+
return !entryHooks.some(
|
|
3773
|
+
(h) => typeof h.command === "string" && h.command.includes(commandSubstring)
|
|
3774
|
+
);
|
|
3775
|
+
});
|
|
3776
|
+
if (next.length === entries.length) return false;
|
|
3777
|
+
hooks[hookType] = next;
|
|
3778
|
+
if (verbose) stepInfo(`removed ${hookType} entry (${commandSubstring})`);
|
|
3779
|
+
return true;
|
|
3780
|
+
};
|
|
3781
|
+
var removeWallet = (home, verbose = false) => {
|
|
3782
|
+
const zeroDir = join4(home, ".zero");
|
|
3783
|
+
const configPath = join4(zeroDir, "config.json");
|
|
3784
|
+
let removed = false;
|
|
3785
|
+
if (existsSync3(configPath)) {
|
|
3786
|
+
rmSync2(configPath, { force: true });
|
|
3787
|
+
removed = true;
|
|
3788
|
+
if (verbose) stepInfo(`removed ${configPath}`);
|
|
3789
|
+
}
|
|
3790
|
+
if (existsSync3(zeroDir) && readdirSync2(zeroDir).length === 0) {
|
|
3791
|
+
rmSync2(zeroDir, { recursive: true, force: true });
|
|
3792
|
+
if (verbose) stepInfo(`removed empty ${zeroDir}`);
|
|
3793
|
+
}
|
|
3794
|
+
return removed;
|
|
3795
|
+
};
|
|
3796
|
+
var runUninstall = async (appContext, options = {}) => {
|
|
3797
|
+
const verbose = options.verbose ?? false;
|
|
3798
|
+
const purge = options.purge ?? false;
|
|
3799
|
+
appContext.services.analyticsService.capture("uninstall_started", { purge });
|
|
3800
|
+
let currentStep = "skills";
|
|
3801
|
+
try {
|
|
3802
|
+
console.log("");
|
|
3803
|
+
console.log(` ${color.boldCyan("Uninstalling Zero")}`);
|
|
3804
|
+
console.log("");
|
|
3805
|
+
console.log(color.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
3806
|
+
console.log("");
|
|
3807
|
+
const home = homedir4();
|
|
3808
|
+
currentStep = "skills";
|
|
3809
|
+
const skillsRemoved = removeSkills(home, verbose);
|
|
3810
|
+
if (skillsRemoved.length > 0) {
|
|
3811
|
+
stepSuccess("Skills removed", `${skillsRemoved.length} removed`);
|
|
3812
|
+
} else {
|
|
3813
|
+
stepSkip("No Zero skills found");
|
|
3814
|
+
}
|
|
3815
|
+
currentStep = "hooks";
|
|
3816
|
+
const { settingsChanged, scriptsRemoved } = removeHooks(home, verbose);
|
|
3817
|
+
if (settingsChanged || scriptsRemoved > 0) {
|
|
3818
|
+
stepSuccess("Hooks removed");
|
|
3819
|
+
} else {
|
|
3820
|
+
stepSkip("No Zero hooks found");
|
|
3821
|
+
}
|
|
3822
|
+
currentStep = "wallet";
|
|
3823
|
+
let walletRemoved = false;
|
|
3824
|
+
if (purge) {
|
|
3825
|
+
walletRemoved = removeWallet(home, verbose);
|
|
3826
|
+
if (walletRemoved) {
|
|
3827
|
+
stepWarn("Wallet config deleted", "~/.zero/config.json");
|
|
3828
|
+
} else {
|
|
3829
|
+
stepSkip("No wallet config to delete");
|
|
3830
|
+
}
|
|
3831
|
+
} else {
|
|
3832
|
+
stepSkip(
|
|
3833
|
+
"Wallet preserved",
|
|
3834
|
+
"run `zero uninstall --purge` to also delete ~/.zero"
|
|
3835
|
+
);
|
|
3836
|
+
}
|
|
3837
|
+
currentStep = "complete";
|
|
3838
|
+
appContext.services.analyticsService.capture("uninstall_completed", {
|
|
3839
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
3840
|
+
skills_removed: skillsRemoved,
|
|
3841
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
3842
|
+
skills_removed_count: skillsRemoved.length,
|
|
3843
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
3844
|
+
hooks_removed: settingsChanged,
|
|
3845
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
3846
|
+
hook_scripts_removed: scriptsRemoved,
|
|
3847
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
3848
|
+
wallet_removed: walletRemoved,
|
|
3849
|
+
purge
|
|
3850
|
+
});
|
|
3851
|
+
sectionDivider();
|
|
3852
|
+
console.log(` ${color.boldGreen("Zero uninstalled.")}`);
|
|
3853
|
+
if (!purge) {
|
|
3854
|
+
console.log(
|
|
3855
|
+
` ${color.dim("Your wallet is kept at ~/.zero \u2014 reinstall anytime with `zero init`.")}`
|
|
3856
|
+
);
|
|
3857
|
+
}
|
|
3858
|
+
console.log("");
|
|
3859
|
+
return {
|
|
3860
|
+
skillsRemoved,
|
|
3861
|
+
hooksRemoved: settingsChanged,
|
|
3862
|
+
hookScriptsRemoved: scriptsRemoved,
|
|
3863
|
+
walletRemoved
|
|
3864
|
+
};
|
|
3865
|
+
} catch (err) {
|
|
3866
|
+
appContext.services.analyticsService.capture("uninstall_failed", {
|
|
3867
|
+
step: currentStep,
|
|
3868
|
+
error: truncateError(err instanceof Error ? err.message : String(err)),
|
|
3869
|
+
purge
|
|
3870
|
+
});
|
|
3871
|
+
throw err;
|
|
3872
|
+
}
|
|
3873
|
+
};
|
|
3874
|
+
var uninstallCommand = (appContext) => new Command11("uninstall").description(
|
|
3875
|
+
"Remove Zero skills and hooks installed by `zero init` (keeps your wallet)"
|
|
3876
|
+
).option(
|
|
3877
|
+
"--purge",
|
|
3878
|
+
"Also delete the wallet config at ~/.zero (irreversible \u2014 destroys the private key)"
|
|
3879
|
+
).option(
|
|
3880
|
+
"-v, --verbose",
|
|
3881
|
+
"Explain why each removal step was taken or skipped"
|
|
3882
|
+
).action(async (options) => {
|
|
3883
|
+
await runUninstall(appContext, options);
|
|
3884
|
+
});
|
|
3885
|
+
|
|
3886
|
+
// src/commands/wallet-command.ts
|
|
3887
|
+
import { existsSync as existsSync4, readFileSync as readFileSync9 } from "fs";
|
|
3888
|
+
import { homedir as homedir5 } from "os";
|
|
3889
|
+
import { join as join6 } from "path";
|
|
3890
|
+
import { confirm, isCancel } from "@clack/prompts";
|
|
3891
|
+
import { Command as Command12 } from "commander";
|
|
3571
3892
|
import open2 from "open";
|
|
3572
3893
|
import { isAddress } from "viem";
|
|
3573
3894
|
import { generatePrivateKey as generatePrivateKey2, privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
3574
3895
|
|
|
3575
3896
|
// src/util/migrate-config.ts
|
|
3576
|
-
import { readFileSync as
|
|
3577
|
-
import { join as
|
|
3897
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
3898
|
+
import { join as join5 } from "path";
|
|
3578
3899
|
var backupAndStripPrivateKey = (zeroDir) => {
|
|
3579
|
-
const configPath =
|
|
3580
|
-
const backupPath =
|
|
3581
|
-
const raw =
|
|
3900
|
+
const configPath = join5(zeroDir, "config.json");
|
|
3901
|
+
const backupPath = join5(zeroDir, "config.backup.json");
|
|
3902
|
+
const raw = readFileSync8(configPath, "utf8");
|
|
3582
3903
|
ensureSecureDir(zeroDir);
|
|
3583
3904
|
writeSecureFile(backupPath, raw);
|
|
3584
3905
|
const parsed = JSON.parse(raw);
|
|
@@ -3599,7 +3920,7 @@ var readStdin = async () => {
|
|
|
3599
3920
|
// src/commands/wallet-command.ts
|
|
3600
3921
|
var PRIVATE_KEY_PATTERN = /^0x[0-9a-fA-F]{64}$/;
|
|
3601
3922
|
var parseProvider = (raw) => raw === "stripe" ? "stripe" : "coinbase";
|
|
3602
|
-
var walletBalanceCommand = (appContext) => new
|
|
3923
|
+
var walletBalanceCommand = (appContext) => new Command12("balance").description("Show wallet balance").option(
|
|
3603
3924
|
"--address <address>",
|
|
3604
3925
|
"Check balance for an arbitrary address (no key needed). Useful with `zero wallet generate` \u2014 verify funds arrived without setting the wallet as your default."
|
|
3605
3926
|
).action(async (options) => {
|
|
@@ -3648,7 +3969,7 @@ var readPrivateKeyFromStdin = async () => {
|
|
|
3648
3969
|
}
|
|
3649
3970
|
return raw;
|
|
3650
3971
|
};
|
|
3651
|
-
var walletFundCommand = (appContext) => new
|
|
3972
|
+
var walletFundCommand = (appContext) => new Command12("fund").description("Fund your wallet").argument("[amount]", "Amount to fund in USDC").option("--manual", "Show wallet address for manual transfer").option(
|
|
3652
3973
|
"--no-open",
|
|
3653
3974
|
"Print the funding URL instead of opening a browser (for agents \u2014 funding links are one-time use, hand the URL to the user)"
|
|
3654
3975
|
).option(
|
|
@@ -3745,7 +4066,7 @@ ${address}`);
|
|
|
3745
4066
|
}
|
|
3746
4067
|
}
|
|
3747
4068
|
);
|
|
3748
|
-
var walletAddressCommand = (appContext) => new
|
|
4069
|
+
var walletAddressCommand = (appContext) => new Command12("address").description("Show wallet address").action(() => {
|
|
3749
4070
|
const { walletService } = appContext.services;
|
|
3750
4071
|
const address = walletService.getAddress();
|
|
3751
4072
|
if (!address) {
|
|
@@ -3755,7 +4076,7 @@ var walletAddressCommand = (appContext) => new Command11("address").description(
|
|
|
3755
4076
|
}
|
|
3756
4077
|
console.log(address);
|
|
3757
4078
|
});
|
|
3758
|
-
var walletSetCommand = (appContext) => new
|
|
4079
|
+
var walletSetCommand = (appContext) => new Command12("set").description("Set wallet from an existing private key").argument("<privateKey>", "Hex-encoded private key (0x-prefixed)").option("--force", "Overwrite existing wallet without prompting").action(async (privateKey, options) => {
|
|
3759
4080
|
const { analyticsService } = appContext.services;
|
|
3760
4081
|
if (!privateKey.startsWith("0x")) {
|
|
3761
4082
|
console.error("Private key must be 0x-prefixed hex string.");
|
|
@@ -3770,11 +4091,11 @@ var walletSetCommand = (appContext) => new Command11("set").description("Set wal
|
|
|
3770
4091
|
process.exitCode = 1;
|
|
3771
4092
|
return;
|
|
3772
4093
|
}
|
|
3773
|
-
const zeroDir =
|
|
3774
|
-
const configPath =
|
|
3775
|
-
if (!options.force &&
|
|
4094
|
+
const zeroDir = join6(homedir5(), ".zero");
|
|
4095
|
+
const configPath = join6(zeroDir, "config.json");
|
|
4096
|
+
if (!options.force && existsSync4(configPath)) {
|
|
3776
4097
|
try {
|
|
3777
|
-
const existing2 = JSON.parse(
|
|
4098
|
+
const existing2 = JSON.parse(readFileSync9(configPath, "utf8"));
|
|
3778
4099
|
if (existing2.privateKey) {
|
|
3779
4100
|
console.error(
|
|
3780
4101
|
"Wallet already configured. Use --force to overwrite."
|
|
@@ -3786,7 +4107,7 @@ var walletSetCommand = (appContext) => new Command11("set").description("Set wal
|
|
|
3786
4107
|
}
|
|
3787
4108
|
}
|
|
3788
4109
|
ensureSecureDir(zeroDir);
|
|
3789
|
-
const existing =
|
|
4110
|
+
const existing = existsSync4(configPath) ? JSON.parse(readFileSync9(configPath, "utf8")) : {};
|
|
3790
4111
|
writeSecureFile(
|
|
3791
4112
|
configPath,
|
|
3792
4113
|
JSON.stringify(
|
|
@@ -3805,7 +4126,7 @@ var walletSetCommand = (appContext) => new Command11("set").description("Set wal
|
|
|
3805
4126
|
force: options.force ?? false
|
|
3806
4127
|
});
|
|
3807
4128
|
});
|
|
3808
|
-
var walletGenerateCommand = (appContext) => new
|
|
4129
|
+
var walletGenerateCommand = (appContext) => new Command12("generate").description(
|
|
3809
4130
|
"Generate a fresh wallet (address + private key) without touching your configured wallet"
|
|
3810
4131
|
).option("--json", "Emit { address, privateKey } as JSON").option(
|
|
3811
4132
|
"--fund",
|
|
@@ -3895,13 +4216,13 @@ var resolveZeroWalletAddress = async (apiService) => {
|
|
|
3895
4216
|
return null;
|
|
3896
4217
|
}
|
|
3897
4218
|
};
|
|
3898
|
-
var walletMigrateCommand = (appContext) => new
|
|
4219
|
+
var walletMigrateCommand = (appContext) => new Command12("migrate").description(
|
|
3899
4220
|
"Sweep all USDC from your private-key wallet into your Zero wallet"
|
|
3900
4221
|
).option("--json", "Emit the migration result as JSON").option("-y, --yes", "Skip the confirmation prompt").action(async (options) => {
|
|
3901
4222
|
const { apiService, paymentService } = appContext.services;
|
|
3902
|
-
const zeroDir =
|
|
3903
|
-
const configPath =
|
|
3904
|
-
const config =
|
|
4223
|
+
const zeroDir = join6(homedir5(), ".zero");
|
|
4224
|
+
const configPath = join6(zeroDir, "config.json");
|
|
4225
|
+
const config = existsSync4(configPath) ? readConfig(configPath) : {};
|
|
3905
4226
|
const privateKey = appContext.env.ZERO_PRIVATE_KEY ?? config.privateKey;
|
|
3906
4227
|
if (!privateKey) {
|
|
3907
4228
|
console.error(
|
|
@@ -4019,7 +4340,7 @@ var walletMigrateCommand = (appContext) => new Command11("migrate").description(
|
|
|
4019
4340
|
if (anyFailed) process.exitCode = 1;
|
|
4020
4341
|
});
|
|
4021
4342
|
var walletCommand = (appContext) => {
|
|
4022
|
-
const cmd = new
|
|
4343
|
+
const cmd = new Command12("wallet").description("Manage your wallet");
|
|
4023
4344
|
cmd.addCommand(walletBalanceCommand(appContext));
|
|
4024
4345
|
cmd.addCommand(walletFundCommand(appContext));
|
|
4025
4346
|
cmd.addCommand(walletAddressCommand(appContext));
|
|
@@ -4030,18 +4351,18 @@ var walletCommand = (appContext) => {
|
|
|
4030
4351
|
};
|
|
4031
4352
|
|
|
4032
4353
|
// src/commands/welcome-command.ts
|
|
4033
|
-
import { existsSync as
|
|
4034
|
-
import { homedir as
|
|
4035
|
-
import { join as
|
|
4036
|
-
import { Command as
|
|
4354
|
+
import { existsSync as existsSync5, readFileSync as readFileSync10 } from "fs";
|
|
4355
|
+
import { homedir as homedir6 } from "os";
|
|
4356
|
+
import { join as join7 } from "path";
|
|
4357
|
+
import { Command as Command13 } from "commander";
|
|
4037
4358
|
import open3 from "open";
|
|
4038
4359
|
import { getAddress } from "viem";
|
|
4039
4360
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
4040
4361
|
var readPrivateKey = () => {
|
|
4041
|
-
const configPath =
|
|
4042
|
-
if (!
|
|
4362
|
+
const configPath = join7(homedir6(), ".zero", "config.json");
|
|
4363
|
+
if (!existsSync5(configPath)) return null;
|
|
4043
4364
|
try {
|
|
4044
|
-
const config = JSON.parse(
|
|
4365
|
+
const config = JSON.parse(readFileSync10(configPath, "utf8"));
|
|
4045
4366
|
if (typeof config.privateKey === "string") {
|
|
4046
4367
|
return config.privateKey;
|
|
4047
4368
|
}
|
|
@@ -4076,7 +4397,7 @@ var printManualFallback = (url) => {
|
|
|
4076
4397
|
}
|
|
4077
4398
|
console.log(lines.join("\n"));
|
|
4078
4399
|
};
|
|
4079
|
-
var welcomeCommand = (appContext) => new
|
|
4400
|
+
var welcomeCommand = (appContext) => new Command13("welcome").description("Claim your $5 welcome bonus.").action(async () => {
|
|
4080
4401
|
const { analyticsService } = appContext.services;
|
|
4081
4402
|
analyticsService.capture("welcome_started", {});
|
|
4082
4403
|
let walletAddress;
|
|
@@ -4136,7 +4457,7 @@ If your browser didn't open, paste the URL above.`
|
|
|
4136
4457
|
// src/app.ts
|
|
4137
4458
|
var createApp = (appContext) => {
|
|
4138
4459
|
const { analyticsService } = appContext.services;
|
|
4139
|
-
const program = new
|
|
4460
|
+
const program = new Command14().name("zero").description("Zero CLI \u2014 Search engine for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", async (_thisCommand, actionCommand) => {
|
|
4140
4461
|
const agentFlag = actionCommand.opts().agent;
|
|
4141
4462
|
if (typeof agentFlag === "string" && agentFlag.trim().length > 0) {
|
|
4142
4463
|
analyticsService.setAgentHost(agentFlag.trim());
|
|
@@ -4150,6 +4471,7 @@ var createApp = (appContext) => {
|
|
|
4150
4471
|
});
|
|
4151
4472
|
});
|
|
4152
4473
|
program.addCommand(initCommand(appContext));
|
|
4474
|
+
program.addCommand(uninstallCommand(appContext));
|
|
4153
4475
|
program.addCommand(searchCommand(appContext));
|
|
4154
4476
|
program.addCommand(getCommand(appContext));
|
|
4155
4477
|
program.addCommand(fetchCommand(appContext));
|
|
@@ -4185,14 +4507,14 @@ var getEnv = () => {
|
|
|
4185
4507
|
|
|
4186
4508
|
// src/app/app-services.ts
|
|
4187
4509
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4188
|
-
import { existsSync as
|
|
4189
|
-
import { homedir as
|
|
4190
|
-
import { join as
|
|
4510
|
+
import { existsSync as existsSync8 } from "fs";
|
|
4511
|
+
import { homedir as homedir7 } from "os";
|
|
4512
|
+
import { join as join9 } from "path";
|
|
4191
4513
|
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
4192
4514
|
|
|
4193
4515
|
// src/services/analytics-service.ts
|
|
4194
4516
|
import { randomUUID } from "crypto";
|
|
4195
|
-
import { existsSync as
|
|
4517
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
|
|
4196
4518
|
import { dirname as dirname2 } from "path";
|
|
4197
4519
|
import { PostHog } from "posthog-node";
|
|
4198
4520
|
var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
|
|
@@ -4214,8 +4536,8 @@ var AnalyticsService = class {
|
|
|
4214
4536
|
let telemetryEnabled = true;
|
|
4215
4537
|
let persistedAnonId;
|
|
4216
4538
|
try {
|
|
4217
|
-
if (
|
|
4218
|
-
const config = JSON.parse(
|
|
4539
|
+
if (existsSync6(opts.configPath)) {
|
|
4540
|
+
const config = JSON.parse(readFileSync11(opts.configPath, "utf8"));
|
|
4219
4541
|
if (config.telemetry === false) {
|
|
4220
4542
|
telemetryEnabled = false;
|
|
4221
4543
|
}
|
|
@@ -4241,8 +4563,8 @@ var AnalyticsService = class {
|
|
|
4241
4563
|
try {
|
|
4242
4564
|
const dir = dirname2(opts.configPath);
|
|
4243
4565
|
mkdirSync4(dir, { recursive: true });
|
|
4244
|
-
const existing =
|
|
4245
|
-
|
|
4566
|
+
const existing = existsSync6(opts.configPath) ? JSON.parse(readFileSync11(opts.configPath, "utf8")) : {};
|
|
4567
|
+
writeFileSync5(
|
|
4246
4568
|
opts.configPath,
|
|
4247
4569
|
JSON.stringify({ ...existing, anonId: newAnonId }, null, 2)
|
|
4248
4570
|
);
|
|
@@ -4282,7 +4604,7 @@ var AnalyticsService = class {
|
|
|
4282
4604
|
if (anonId === walletAddress) return;
|
|
4283
4605
|
let aliasedTo;
|
|
4284
4606
|
try {
|
|
4285
|
-
const config = JSON.parse(
|
|
4607
|
+
const config = JSON.parse(readFileSync11(configPath, "utf8"));
|
|
4286
4608
|
if (typeof config.aliasedTo === "string") {
|
|
4287
4609
|
aliasedTo = config.aliasedTo;
|
|
4288
4610
|
}
|
|
@@ -4292,8 +4614,8 @@ var AnalyticsService = class {
|
|
|
4292
4614
|
this.posthog.alias({ distinctId: walletAddress, alias: anonId });
|
|
4293
4615
|
if (process.env.VITEST) return;
|
|
4294
4616
|
try {
|
|
4295
|
-
const config =
|
|
4296
|
-
|
|
4617
|
+
const config = existsSync6(configPath) ? JSON.parse(readFileSync11(configPath, "utf8")) : {};
|
|
4618
|
+
writeFileSync5(
|
|
4297
4619
|
configPath,
|
|
4298
4620
|
JSON.stringify({ ...config, aliasedTo: walletAddress }, null, 2)
|
|
4299
4621
|
);
|
|
@@ -4396,34 +4718,34 @@ var createApiAccount = (walletAddress, api) => toAccount({
|
|
|
4396
4718
|
});
|
|
4397
4719
|
|
|
4398
4720
|
// src/services/state-service.ts
|
|
4399
|
-
import { existsSync as
|
|
4400
|
-
import { join as
|
|
4721
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "fs";
|
|
4722
|
+
import { join as join8 } from "path";
|
|
4401
4723
|
var RECENT_SEARCH_LIMIT = 10;
|
|
4402
4724
|
var StateService = class {
|
|
4403
4725
|
constructor(zeroDir) {
|
|
4404
4726
|
this.zeroDir = zeroDir;
|
|
4405
|
-
this.lastSearchPath =
|
|
4406
|
-
this.recentSearchesPath =
|
|
4727
|
+
this.lastSearchPath = join8(zeroDir, "last_search.json");
|
|
4728
|
+
this.recentSearchesPath = join8(zeroDir, "recent_searches.json");
|
|
4407
4729
|
}
|
|
4408
4730
|
lastSearchPath;
|
|
4409
4731
|
recentSearchesPath;
|
|
4410
4732
|
saveLastSearch = (data) => {
|
|
4411
4733
|
mkdirSync5(this.zeroDir, { recursive: true });
|
|
4412
|
-
|
|
4734
|
+
writeFileSync6(this.lastSearchPath, JSON.stringify(data, null, 2));
|
|
4413
4735
|
const recent = this.loadRecentSearches();
|
|
4414
4736
|
const filtered = recent.searches.filter(
|
|
4415
4737
|
(s) => s.searchId !== data.searchId
|
|
4416
4738
|
);
|
|
4417
4739
|
const next = [data, ...filtered].slice(0, RECENT_SEARCH_LIMIT);
|
|
4418
|
-
|
|
4740
|
+
writeFileSync6(
|
|
4419
4741
|
this.recentSearchesPath,
|
|
4420
4742
|
JSON.stringify({ searches: next }, null, 2)
|
|
4421
4743
|
);
|
|
4422
4744
|
};
|
|
4423
4745
|
loadLastSearch = () => {
|
|
4424
4746
|
try {
|
|
4425
|
-
if (!
|
|
4426
|
-
const raw =
|
|
4747
|
+
if (!existsSync7(this.lastSearchPath)) return null;
|
|
4748
|
+
const raw = readFileSync12(this.lastSearchPath, "utf8");
|
|
4427
4749
|
return JSON.parse(raw);
|
|
4428
4750
|
} catch {
|
|
4429
4751
|
return null;
|
|
@@ -4431,11 +4753,11 @@ var StateService = class {
|
|
|
4431
4753
|
};
|
|
4432
4754
|
loadRecentSearches = () => {
|
|
4433
4755
|
try {
|
|
4434
|
-
if (!
|
|
4756
|
+
if (!existsSync7(this.recentSearchesPath)) {
|
|
4435
4757
|
const last = this.loadLastSearch();
|
|
4436
4758
|
return { searches: last ? [last] : [] };
|
|
4437
4759
|
}
|
|
4438
|
-
const raw =
|
|
4760
|
+
const raw = readFileSync12(this.recentSearchesPath, "utf8");
|
|
4439
4761
|
const parsed = JSON.parse(raw);
|
|
4440
4762
|
return { searches: parsed.searches ?? [] };
|
|
4441
4763
|
} catch {
|
|
@@ -4563,9 +4885,9 @@ var buildOnSessionRefreshed = (configPath) => async (tokens) => {
|
|
|
4563
4885
|
writeSecureFile(configPath, JSON.stringify(next, null, 2));
|
|
4564
4886
|
};
|
|
4565
4887
|
var getServices = async (env) => {
|
|
4566
|
-
const zeroDir =
|
|
4567
|
-
const configPath =
|
|
4568
|
-
const config =
|
|
4888
|
+
const zeroDir = join9(homedir7(), ".zero");
|
|
4889
|
+
const configPath = join9(zeroDir, "config.json");
|
|
4890
|
+
const config = existsSync8(configPath) ? readConfig(configPath) : {};
|
|
4569
4891
|
const { credentials, privateKey } = resolveCredentials(env, config);
|
|
4570
4892
|
const lowBalanceWarning = typeof config.lowBalanceWarning === "number" ? config.lowBalanceWarning : 1;
|
|
4571
4893
|
const apiService = new ApiService(
|
|
@@ -4638,15 +4960,15 @@ var createAppContext = async () => {
|
|
|
4638
4960
|
|
|
4639
4961
|
// src/util/update-check.ts
|
|
4640
4962
|
import {
|
|
4641
|
-
existsSync as
|
|
4963
|
+
existsSync as existsSync9,
|
|
4642
4964
|
lstatSync,
|
|
4643
4965
|
mkdirSync as mkdirSync6,
|
|
4644
|
-
readFileSync as
|
|
4966
|
+
readFileSync as readFileSync13,
|
|
4645
4967
|
readlinkSync,
|
|
4646
|
-
writeFileSync as
|
|
4968
|
+
writeFileSync as writeFileSync7
|
|
4647
4969
|
} from "fs";
|
|
4648
|
-
import { homedir as
|
|
4649
|
-
import { dirname as dirname3, join as
|
|
4970
|
+
import { homedir as homedir8 } from "os";
|
|
4971
|
+
import { dirname as dirname3, join as join10, resolve } from "path";
|
|
4650
4972
|
var CACHE_FILENAME = "update_check.json";
|
|
4651
4973
|
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@zeroxyz/cli/latest";
|
|
4652
4974
|
var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
|
|
@@ -4670,10 +4992,10 @@ var resolveExecPath = (execPath) => {
|
|
|
4670
4992
|
var detectInstallMethod = (opts = {}) => {
|
|
4671
4993
|
const execPath = opts.execPath ?? process.execPath;
|
|
4672
4994
|
const pkg = opts.pkg ?? process.pkg;
|
|
4673
|
-
const home = opts.home ??
|
|
4995
|
+
const home = opts.home ?? homedir8();
|
|
4674
4996
|
if (pkg) return "binary";
|
|
4675
4997
|
const resolved = resolveExecPath(execPath);
|
|
4676
|
-
const zeroBin =
|
|
4998
|
+
const zeroBin = join10(home, ".zero", "bin");
|
|
4677
4999
|
if (resolved.startsWith(zeroBin)) return "binary";
|
|
4678
5000
|
return "npm";
|
|
4679
5001
|
};
|
|
@@ -4698,12 +5020,12 @@ var compareVersions = (a, b) => {
|
|
|
4698
5020
|
if (pb.pre === null) return -1;
|
|
4699
5021
|
return pa.pre < pb.pre ? -1 : 1;
|
|
4700
5022
|
};
|
|
4701
|
-
var cachePath = (zeroDir) =>
|
|
5023
|
+
var cachePath = (zeroDir) => join10(zeroDir, CACHE_FILENAME);
|
|
4702
5024
|
var readCache = (zeroDir) => {
|
|
4703
5025
|
try {
|
|
4704
5026
|
const path = cachePath(zeroDir);
|
|
4705
|
-
if (!
|
|
4706
|
-
const raw =
|
|
5027
|
+
if (!existsSync9(path)) return emptyCache;
|
|
5028
|
+
const raw = readFileSync13(path, "utf8");
|
|
4707
5029
|
const parsed = JSON.parse(raw);
|
|
4708
5030
|
return {
|
|
4709
5031
|
lastCheckedMs: typeof parsed.lastCheckedMs === "number" ? parsed.lastCheckedMs : 0,
|
|
@@ -4717,7 +5039,7 @@ var readCache = (zeroDir) => {
|
|
|
4717
5039
|
var writeCache = (zeroDir, cache) => {
|
|
4718
5040
|
try {
|
|
4719
5041
|
mkdirSync6(zeroDir, { recursive: true });
|
|
4720
|
-
|
|
5042
|
+
writeFileSync7(cachePath(zeroDir), JSON.stringify(cache, null, 2));
|
|
4721
5043
|
} catch {
|
|
4722
5044
|
}
|
|
4723
5045
|
};
|
|
@@ -4792,7 +5114,7 @@ var main = async () => {
|
|
|
4792
5114
|
console.error("Failed to create app context");
|
|
4793
5115
|
process.exit(1);
|
|
4794
5116
|
}
|
|
4795
|
-
const zeroDir =
|
|
5117
|
+
const zeroDir = join11(homedir9(), ".zero");
|
|
4796
5118
|
maybePrintUpdateBanner(zeroDir, package_default.version);
|
|
4797
5119
|
const app = createApp(appContext);
|
|
4798
5120
|
let caughtError = null;
|