@zeroxyz/cli 0.0.22 → 0.0.24
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 +661 -311
- package/package.json +1 -1
- package/skills/zero/SKILL.md +19 -3
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/app.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command10 } from "commander";
|
|
5
5
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@zeroxyz/cli",
|
|
9
|
-
version: "0.0.
|
|
9
|
+
version: "0.0.24",
|
|
10
10
|
type: "module",
|
|
11
11
|
bin: {
|
|
12
12
|
zero: "dist/index.js",
|
|
@@ -59,21 +59,477 @@ var package_default = {
|
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
+
// src/commands/bug-report-command.ts
|
|
63
|
+
import { createHash as createHash2 } from "crypto";
|
|
64
|
+
import { readFileSync } from "fs";
|
|
65
|
+
import { Command } from "commander";
|
|
66
|
+
import { z as z2 } from "zod";
|
|
67
|
+
|
|
68
|
+
// src/services/api-service.ts
|
|
69
|
+
import { createHash } from "crypto";
|
|
70
|
+
import z from "zod";
|
|
71
|
+
var searchResultSchema = z.object({
|
|
72
|
+
id: z.string(),
|
|
73
|
+
position: z.number(),
|
|
74
|
+
slug: z.string(),
|
|
75
|
+
name: z.string(),
|
|
76
|
+
canonicalName: z.string().nullable().optional(),
|
|
77
|
+
description: z.string(),
|
|
78
|
+
whatItDoes: z.string().nullable().optional(),
|
|
79
|
+
url: z.string(),
|
|
80
|
+
cost: z.object({ amount: z.string(), asset: z.string() }),
|
|
81
|
+
rating: z.object({
|
|
82
|
+
score: z.string(),
|
|
83
|
+
successRate: z.string(),
|
|
84
|
+
reviews: z.number(),
|
|
85
|
+
stars: z.string().nullable().optional(),
|
|
86
|
+
state: z.enum(["unrated", "rated"]).optional()
|
|
87
|
+
}),
|
|
88
|
+
trustScore: z.number().nullable().optional(),
|
|
89
|
+
trustSignalCount: z.number().optional(),
|
|
90
|
+
availabilityStatus: z.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional(),
|
|
91
|
+
relevanceScore: z.number().optional()
|
|
92
|
+
});
|
|
93
|
+
var searchResponseSchema = z.object({
|
|
94
|
+
searchId: z.string(),
|
|
95
|
+
total: z.number().optional().default(0),
|
|
96
|
+
offset: z.number().optional().default(0),
|
|
97
|
+
hasMore: z.boolean().optional().default(false),
|
|
98
|
+
capabilities: z.array(searchResultSchema)
|
|
99
|
+
});
|
|
100
|
+
var capabilityResponseSchema = z.object({
|
|
101
|
+
uid: z.string(),
|
|
102
|
+
slug: z.string(),
|
|
103
|
+
name: z.string(),
|
|
104
|
+
description: z.string(),
|
|
105
|
+
url: z.string(),
|
|
106
|
+
method: z.string(),
|
|
107
|
+
headers: z.record(z.string(), z.string()).nullable(),
|
|
108
|
+
bodySchema: z.record(z.string(), z.unknown()).nullable(),
|
|
109
|
+
responseSchema: z.record(z.string(), z.unknown()).nullable(),
|
|
110
|
+
example: z.object({ request: z.unknown(), response: z.unknown() }).nullable(),
|
|
111
|
+
tags: z.array(z.string()).nullable(),
|
|
112
|
+
displayCostAmount: z.string(),
|
|
113
|
+
displayCostAsset: z.string(),
|
|
114
|
+
rating: z.object({
|
|
115
|
+
score: z.string(),
|
|
116
|
+
successRate: z.string(),
|
|
117
|
+
reviews: z.number(),
|
|
118
|
+
stars: z.string().nullable().optional(),
|
|
119
|
+
state: z.enum(["unrated", "rated"]).optional()
|
|
120
|
+
}),
|
|
121
|
+
priceObserved: z.object({
|
|
122
|
+
medianCents: z.string(),
|
|
123
|
+
p95Cents: z.string(),
|
|
124
|
+
sampleCount: z.number(),
|
|
125
|
+
varies: z.boolean()
|
|
126
|
+
}).nullable().optional(),
|
|
127
|
+
paymentMethods: z.array(
|
|
128
|
+
z.object({
|
|
129
|
+
uid: z.string(),
|
|
130
|
+
protocol: z.string(),
|
|
131
|
+
methodType: z.string(),
|
|
132
|
+
chain: z.string().nullable(),
|
|
133
|
+
mode: z.string(),
|
|
134
|
+
costAmount: z.string(),
|
|
135
|
+
costPer: z.string(),
|
|
136
|
+
priority: z.number()
|
|
137
|
+
})
|
|
138
|
+
).nullable(),
|
|
139
|
+
trustScore: z.number().nullable().optional(),
|
|
140
|
+
trustComponents: z.object({
|
|
141
|
+
apiQuality: z.number().nullable(),
|
|
142
|
+
blockchainActivity: z.number().nullable(),
|
|
143
|
+
performance: z.number().nullable()
|
|
144
|
+
}).nullable().optional(),
|
|
145
|
+
availabilityStatus: z.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional()
|
|
146
|
+
});
|
|
147
|
+
var createRunResponseSchema = z.object({
|
|
148
|
+
runId: z.string()
|
|
149
|
+
});
|
|
150
|
+
var createReviewResponseSchema = z.object({
|
|
151
|
+
reviewId: z.string(),
|
|
152
|
+
recorded: z.boolean()
|
|
153
|
+
});
|
|
154
|
+
var BUG_REPORT_CATEGORIES = [
|
|
155
|
+
"search_relevance",
|
|
156
|
+
"ranking_issue",
|
|
157
|
+
"missing_capability",
|
|
158
|
+
"wrong_schema",
|
|
159
|
+
"misleading_description",
|
|
160
|
+
"broken_execution",
|
|
161
|
+
"payment_failure",
|
|
162
|
+
"billing_anomaly",
|
|
163
|
+
"cli_bug",
|
|
164
|
+
"security",
|
|
165
|
+
"other"
|
|
166
|
+
];
|
|
167
|
+
var createBugReportResponseSchema = z.object({
|
|
168
|
+
bugReportId: z.string(),
|
|
169
|
+
status: z.string(),
|
|
170
|
+
deduped: z.boolean(),
|
|
171
|
+
category: z.enum(BUG_REPORT_CATEGORIES).nullable(),
|
|
172
|
+
title: z.string().nullable(),
|
|
173
|
+
attached: z.object({
|
|
174
|
+
capabilityId: z.number().nullable(),
|
|
175
|
+
runId: z.number().nullable(),
|
|
176
|
+
searchId: z.number().nullable()
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
var runListItemSchema = z.object({
|
|
180
|
+
uid: z.string(),
|
|
181
|
+
capabilityUid: z.string(),
|
|
182
|
+
capabilitySlug: z.string(),
|
|
183
|
+
capabilityName: z.string(),
|
|
184
|
+
status: z.number().nullable(),
|
|
185
|
+
latencyMs: z.number().nullable(),
|
|
186
|
+
cost: z.object({ amount: z.string(), asset: z.string().nullable() }).nullable(),
|
|
187
|
+
payment: z.object({
|
|
188
|
+
protocol: z.string(),
|
|
189
|
+
chain: z.string().nullable(),
|
|
190
|
+
txHash: z.string().nullable(),
|
|
191
|
+
mode: z.string().nullable()
|
|
192
|
+
}).nullable(),
|
|
193
|
+
createdAt: z.coerce.date(),
|
|
194
|
+
reviewed: z.boolean()
|
|
195
|
+
});
|
|
196
|
+
var listRunsResponseSchema = z.object({
|
|
197
|
+
runs: z.array(runListItemSchema),
|
|
198
|
+
nextCursor: z.string().nullable()
|
|
199
|
+
});
|
|
200
|
+
var buildCanonicalMessage = (method, path, body, timestamp, nonce) => {
|
|
201
|
+
const bodyHash = createHash("sha256").update(body ?? "").digest("hex");
|
|
202
|
+
return `${method}:${path}:${bodyHash}:${timestamp}:${nonce}`;
|
|
203
|
+
};
|
|
204
|
+
var ApiService = class {
|
|
205
|
+
constructor(baseUrl, account) {
|
|
206
|
+
this.baseUrl = baseUrl;
|
|
207
|
+
this.account = account;
|
|
208
|
+
this.walletAddress = this.account?.address ?? null;
|
|
209
|
+
}
|
|
210
|
+
walletAddress;
|
|
211
|
+
account;
|
|
212
|
+
signRequest = async (method, path, body) => {
|
|
213
|
+
if (!this.account) throw new Error("No private key configured");
|
|
214
|
+
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
215
|
+
const nonce = crypto.randomUUID();
|
|
216
|
+
const message = buildCanonicalMessage(method, path, body, timestamp, nonce);
|
|
217
|
+
const signature = await this.account.signMessage({ message });
|
|
218
|
+
return {
|
|
219
|
+
"x-zero-address": this.account.address,
|
|
220
|
+
"x-zero-timestamp": timestamp,
|
|
221
|
+
"x-zero-nonce": nonce,
|
|
222
|
+
"x-zero-signature": signature
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
request = async (method, path, body) => {
|
|
226
|
+
const url = `${this.baseUrl}${path}`;
|
|
227
|
+
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
228
|
+
const headers = {
|
|
229
|
+
"content-type": "application/json"
|
|
230
|
+
};
|
|
231
|
+
if (this.account) {
|
|
232
|
+
const walletHeaders = await this.signRequest(method, path, bodyStr);
|
|
233
|
+
Object.assign(headers, walletHeaders);
|
|
234
|
+
}
|
|
235
|
+
const response = await fetch(url, {
|
|
236
|
+
method,
|
|
237
|
+
headers,
|
|
238
|
+
body: bodyStr
|
|
239
|
+
});
|
|
240
|
+
if (!response.ok) {
|
|
241
|
+
const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
242
|
+
throw new Error(
|
|
243
|
+
errorBody.error ?? `HTTP ${response.status}`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
return response.json();
|
|
247
|
+
};
|
|
248
|
+
search = async (options) => {
|
|
249
|
+
const json = await this.request("POST", "/v1/search", options);
|
|
250
|
+
return searchResponseSchema.parse(json);
|
|
251
|
+
};
|
|
252
|
+
getCapability = async (id, searchId) => {
|
|
253
|
+
const qs = searchId ? `?searchId=${encodeURIComponent(searchId)}` : "";
|
|
254
|
+
const json = await this.request(
|
|
255
|
+
"GET",
|
|
256
|
+
`/v1/capabilities/${encodeURIComponent(id)}${qs}`
|
|
257
|
+
);
|
|
258
|
+
return capabilityResponseSchema.parse(json);
|
|
259
|
+
};
|
|
260
|
+
createRun = async (data) => {
|
|
261
|
+
const json = await this.request("POST", "/v1/runs", data);
|
|
262
|
+
return createRunResponseSchema.parse(json);
|
|
263
|
+
};
|
|
264
|
+
listRuns = async (params = {}) => {
|
|
265
|
+
const qs = new URLSearchParams();
|
|
266
|
+
if (params.capabilityId) qs.set("capabilityId", params.capabilityId);
|
|
267
|
+
if (params.unreviewed) qs.set("unreviewed", "true");
|
|
268
|
+
if (params.limit) qs.set("limit", String(params.limit));
|
|
269
|
+
if (params.cursor) qs.set("cursor", params.cursor);
|
|
270
|
+
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
271
|
+
const json = await this.request("GET", `/v1/runs${suffix}`);
|
|
272
|
+
return listRunsResponseSchema.parse(json);
|
|
273
|
+
};
|
|
274
|
+
createReview = async (data) => {
|
|
275
|
+
const json = await this.request("POST", "/v1/reviews", data);
|
|
276
|
+
return createReviewResponseSchema.parse(json);
|
|
277
|
+
};
|
|
278
|
+
createBugReport = async (data) => {
|
|
279
|
+
const json = await this.request("POST", "/v1/bug-reports", data);
|
|
280
|
+
return createBugReportResponseSchema.parse(json);
|
|
281
|
+
};
|
|
282
|
+
getFundingUrl = async (amount) => {
|
|
283
|
+
try {
|
|
284
|
+
const qs = amount ? `?amount=${encodeURIComponent(amount)}` : "";
|
|
285
|
+
const json = await this.request("GET", `/v1/wallet/fund-url${qs}`);
|
|
286
|
+
const parsed = z.object({ url: z.string() }).parse(json);
|
|
287
|
+
return parsed.url;
|
|
288
|
+
} catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// src/commands/bug-report-command.ts
|
|
295
|
+
var bulkEntrySchema = z2.object({
|
|
296
|
+
description: z2.string().min(1),
|
|
297
|
+
category: z2.enum(BUG_REPORT_CATEGORIES).optional(),
|
|
298
|
+
title: z2.string().min(1).max(200).optional(),
|
|
299
|
+
severity: z2.number().int().min(1).max(3).optional(),
|
|
300
|
+
reproduction: z2.string().optional(),
|
|
301
|
+
capabilityId: z2.string().optional(),
|
|
302
|
+
runId: z2.string().optional(),
|
|
303
|
+
searchId: z2.string().optional(),
|
|
304
|
+
idempotencyKey: z2.string().min(1).max(200).optional()
|
|
305
|
+
});
|
|
306
|
+
var buildCliContext = () => ({
|
|
307
|
+
cliVersion: package_default.version,
|
|
308
|
+
os: process.platform,
|
|
309
|
+
node: process.version
|
|
310
|
+
});
|
|
311
|
+
var TEN_MIN_MS = 10 * 60 * 1e3;
|
|
312
|
+
var autoIdempotencyKey = (description, contextSeed) => {
|
|
313
|
+
const bucket = Math.floor(Date.now() / TEN_MIN_MS);
|
|
314
|
+
const seed = `${description}|${contextSeed ?? ""}|${bucket}`;
|
|
315
|
+
return `auto-${createHash2("sha256").update(seed).digest("hex").slice(0, 16)}`;
|
|
316
|
+
};
|
|
317
|
+
var bugReportCommand = (appContext) => new Command("bug-report").description(
|
|
318
|
+
"Report a Zero platform bug \u2014 bad search ranking, wrong indexed URL, CLI bugs, billing issues. The CLI auto-attaches your most recent context (last search + last run), auto-derives a title, and lets the server classify the category. For 'this capability returned a bad result', use `zero review` instead."
|
|
319
|
+
).addHelpText(
|
|
320
|
+
"after",
|
|
321
|
+
`
|
|
322
|
+
Minimum surface \u2014 just describe the bug:
|
|
323
|
+
zero bug-report "Search ranked generic crypto API above exact match for BTC price"
|
|
324
|
+
|
|
325
|
+
The CLI will:
|
|
326
|
+
- Attach your most recent search + run as context (use --no-context to skip)
|
|
327
|
+
- Auto-derive a title from your description
|
|
328
|
+
- Generate an idempotency key so accidental retries dedupe within 10 minutes
|
|
329
|
+
- Capture cliContext (cli version, os, node)
|
|
330
|
+
|
|
331
|
+
The server will:
|
|
332
|
+
- Pick a category from your description (override with --category if it gets it wrong)
|
|
333
|
+
- Default severity to 2 (override with --severity)
|
|
334
|
+
- Echo back what it picked + attached so you can verify
|
|
335
|
+
|
|
336
|
+
Overrides (only when needed):
|
|
337
|
+
--capability cap_xyz Attach a specific capability (overrides auto-context)
|
|
338
|
+
--run run_xyz Attach a specific run
|
|
339
|
+
--search sea_xyz Attach a specific search
|
|
340
|
+
--no-context Skip auto-attached context (file a standalone platform bug)
|
|
341
|
+
--category <c> Force a category (otherwise classifier picks)
|
|
342
|
+
--severity 1|2|3 Override default severity 2
|
|
343
|
+
--title "..." Override auto-derived title
|
|
344
|
+
--reproduction "..." Add reproduction notes
|
|
345
|
+
--idempotency-key <k> Override auto-key (e.g. for explicit retries)
|
|
346
|
+
--json Machine-readable output
|
|
347
|
+
--from-file <path> Bulk submit from JSONL (each line: {description, ...overrides})
|
|
348
|
+
|
|
349
|
+
Categories the classifier picks from:
|
|
350
|
+
search & discovery: search_relevance, ranking_issue, missing_capability
|
|
351
|
+
indexed-data quality: wrong_schema, misleading_description, broken_execution
|
|
352
|
+
platform infra: payment_failure, billing_anomaly, cli_bug
|
|
353
|
+
cross-cutting: security, other`
|
|
354
|
+
).argument(
|
|
355
|
+
"[description]",
|
|
356
|
+
"What broke (free-form text). Required unless --from-file is used."
|
|
357
|
+
).option(
|
|
358
|
+
"--capability <id>",
|
|
359
|
+
"Attach this capability uid (cap_*) or slug as context, overriding auto-context"
|
|
360
|
+
).option(
|
|
361
|
+
"--run <runId>",
|
|
362
|
+
"Attach this run uid (run_*) as context, overriding auto-context"
|
|
363
|
+
).option(
|
|
364
|
+
"--search <searchId>",
|
|
365
|
+
"Attach this search uid (sea_*) as context, overriding auto-context"
|
|
366
|
+
).option("--no-context", "Skip auto-attached context entirely").option(
|
|
367
|
+
"--category <category>",
|
|
368
|
+
`Force a category (skips classifier). One of: ${BUG_REPORT_CATEGORIES.join(", ")}`
|
|
369
|
+
).option(
|
|
370
|
+
"--severity <n>",
|
|
371
|
+
"Severity 1 (low), 2 (med, default), 3 (high)",
|
|
372
|
+
Number.parseInt
|
|
373
|
+
).option("--title <text>", "Override auto-derived title (\u2264200 chars)").option(
|
|
374
|
+
"--reproduction <text>",
|
|
375
|
+
"Optional reproduction steps (e.g. equivalent curl)"
|
|
376
|
+
).option("--idempotency-key <key>", "Override the auto-generated dedup key").option(
|
|
377
|
+
"--from-file <path>",
|
|
378
|
+
"Submit bug reports in bulk from a JSONL file (one report per line)"
|
|
379
|
+
).option("--json", "Emit the API result as JSON on stdout (for batch use)").action(
|
|
380
|
+
async (description, options) => {
|
|
381
|
+
try {
|
|
382
|
+
const { analyticsService, apiService, stateService } = appContext.services;
|
|
383
|
+
if (!apiService.walletAddress) {
|
|
384
|
+
console.error(
|
|
385
|
+
"Wallet auth required \u2014 run `zero wallet import` or set ZERO_PRIVATE_KEY."
|
|
386
|
+
);
|
|
387
|
+
process.exitCode = 1;
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (options.fromFile) {
|
|
391
|
+
const contents = readFileSync(options.fromFile, "utf8");
|
|
392
|
+
const lines = contents.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
393
|
+
let ok = 0;
|
|
394
|
+
let failed = 0;
|
|
395
|
+
const cliContext = buildCliContext();
|
|
396
|
+
for (const [idx, line] of lines.entries()) {
|
|
397
|
+
const lineNum = idx + 1;
|
|
398
|
+
try {
|
|
399
|
+
const parsed = bulkEntrySchema.parse(JSON.parse(line));
|
|
400
|
+
const result2 = await apiService.createBugReport({
|
|
401
|
+
description: parsed.description,
|
|
402
|
+
category: parsed.category,
|
|
403
|
+
severity: parsed.severity,
|
|
404
|
+
title: parsed.title,
|
|
405
|
+
reproduction: parsed.reproduction,
|
|
406
|
+
capabilityId: parsed.capabilityId,
|
|
407
|
+
runId: parsed.runId,
|
|
408
|
+
searchId: parsed.searchId,
|
|
409
|
+
cliContext,
|
|
410
|
+
idempotencyKey: parsed.idempotencyKey ?? autoIdempotencyKey(parsed.description, parsed.runId)
|
|
411
|
+
});
|
|
412
|
+
ok += 1;
|
|
413
|
+
console.log(
|
|
414
|
+
`[${lineNum}] ${result2.bugReportId} category=${result2.category ?? "unclassified"}${result2.deduped ? " (deduped)" : ""}`
|
|
415
|
+
);
|
|
416
|
+
analyticsService.capture("bug_report_submitted", {
|
|
417
|
+
category: result2.category,
|
|
418
|
+
severity: parsed.severity ?? 2,
|
|
419
|
+
bulk: true,
|
|
420
|
+
deduped: result2.deduped
|
|
421
|
+
});
|
|
422
|
+
} catch (err) {
|
|
423
|
+
failed += 1;
|
|
424
|
+
console.error(
|
|
425
|
+
`[${lineNum}] FAILED: ${err instanceof Error ? err.message : String(err)}`
|
|
426
|
+
);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
console.log(
|
|
430
|
+
`
|
|
431
|
+
Bulk bug-report complete: ${ok} ok, ${failed} failed`
|
|
432
|
+
);
|
|
433
|
+
if (failed > 0) process.exitCode = 1;
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
if (!description || description.trim().length === 0) {
|
|
437
|
+
console.error(
|
|
438
|
+
'Provide a description: zero bug-report "what broke"'
|
|
439
|
+
);
|
|
440
|
+
process.exitCode = 1;
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (options.category && !BUG_REPORT_CATEGORIES.includes(
|
|
444
|
+
options.category
|
|
445
|
+
)) {
|
|
446
|
+
console.error(
|
|
447
|
+
`Invalid --category. Valid: ${BUG_REPORT_CATEGORIES.join(", ")}`
|
|
448
|
+
);
|
|
449
|
+
process.exitCode = 1;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (options.severity !== void 0 && (Number.isNaN(options.severity) || options.severity < 1 || options.severity > 3)) {
|
|
453
|
+
console.error("--severity must be 1, 2, or 3");
|
|
454
|
+
process.exitCode = 1;
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
let { capability, run, search } = options;
|
|
458
|
+
const useAutoContext = options.context !== false;
|
|
459
|
+
if (useAutoContext) {
|
|
460
|
+
const lastSearch = stateService.loadLastSearch();
|
|
461
|
+
if (lastSearch) {
|
|
462
|
+
search = search ?? lastSearch.searchId;
|
|
463
|
+
const recent = lastSearch.capabilities[0];
|
|
464
|
+
capability = capability ?? recent?.id;
|
|
465
|
+
}
|
|
466
|
+
if (!run) {
|
|
467
|
+
try {
|
|
468
|
+
const list = await apiService.listRuns({ limit: 1 });
|
|
469
|
+
const [latest] = list.runs;
|
|
470
|
+
if (latest) {
|
|
471
|
+
run = latest.uid;
|
|
472
|
+
capability = capability ?? latest.capabilityUid;
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const idempotencyKey = options.idempotencyKey ?? autoIdempotencyKey(description, run ?? capability ?? null);
|
|
479
|
+
const result = await apiService.createBugReport({
|
|
480
|
+
description,
|
|
481
|
+
category: options.category,
|
|
482
|
+
severity: options.severity,
|
|
483
|
+
title: options.title,
|
|
484
|
+
reproduction: options.reproduction,
|
|
485
|
+
capabilityId: capability,
|
|
486
|
+
runId: run,
|
|
487
|
+
searchId: search,
|
|
488
|
+
cliContext: buildCliContext(),
|
|
489
|
+
idempotencyKey
|
|
490
|
+
});
|
|
491
|
+
if (options.json) {
|
|
492
|
+
console.log(JSON.stringify(result));
|
|
493
|
+
} else {
|
|
494
|
+
const cat = result.category ?? "unclassified";
|
|
495
|
+
const dedupeNote = result.deduped ? " (deduped \u2014 same description within 10 min)" : "";
|
|
496
|
+
console.log(
|
|
497
|
+
`Bug report filed: ${result.bugReportId}${dedupeNote}
|
|
498
|
+
category: ${cat}
|
|
499
|
+
title: ${result.title ?? "(none)"}
|
|
500
|
+
attached: capability=${result.attached.capabilityId ?? "\u2014"} run=${result.attached.runId ?? "\u2014"} search=${result.attached.searchId ?? "\u2014"}`
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
analyticsService.capture("bug_report_submitted", {
|
|
504
|
+
category: result.category,
|
|
505
|
+
severity: options.severity ?? 2,
|
|
506
|
+
deduped: result.deduped,
|
|
507
|
+
autoContext: useAutoContext
|
|
508
|
+
});
|
|
509
|
+
} catch (err) {
|
|
510
|
+
console.error(
|
|
511
|
+
err instanceof Error ? err.message : "Bug report failed"
|
|
512
|
+
);
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
|
|
62
518
|
// src/commands/config-command.ts
|
|
63
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
519
|
+
import { existsSync, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
64
520
|
import { homedir } from "os";
|
|
65
521
|
import { join } from "path";
|
|
66
|
-
import { Command } from "commander";
|
|
522
|
+
import { Command as Command2 } from "commander";
|
|
67
523
|
var VALID_KEYS = ["lowBalanceWarning", "auth", "telemetry"];
|
|
68
524
|
var loadConfig = (configPath) => {
|
|
69
525
|
try {
|
|
70
526
|
if (!existsSync(configPath)) return {};
|
|
71
|
-
return JSON.parse(
|
|
527
|
+
return JSON.parse(readFileSync2(configPath, "utf8"));
|
|
72
528
|
} catch {
|
|
73
529
|
return {};
|
|
74
530
|
}
|
|
75
531
|
};
|
|
76
|
-
var configCommand = (_appContext) => new
|
|
532
|
+
var configCommand = (_appContext) => new Command2("config").description("View or update CLI configuration").option("--set <keyValue>", "Set a config value (key=value)").action((options) => {
|
|
77
533
|
const configPath = join(homedir(), ".zero", "config.json");
|
|
78
534
|
if (!options.set) {
|
|
79
535
|
const config2 = loadConfig(configPath);
|
|
@@ -110,7 +566,7 @@ var configCommand = (_appContext) => new Command("config").description("View or
|
|
|
110
566
|
});
|
|
111
567
|
|
|
112
568
|
// src/commands/fetch-command.ts
|
|
113
|
-
import { Command as
|
|
569
|
+
import { Command as Command3 } from "commander";
|
|
114
570
|
|
|
115
571
|
// src/util/infer-schema.ts
|
|
116
572
|
var inferSchema = (value, depth = 0) => {
|
|
@@ -168,7 +624,10 @@ var detectPaymentRequirement = (headers, status) => {
|
|
|
168
624
|
}
|
|
169
625
|
return { protocol: "unknown", raw: {} };
|
|
170
626
|
};
|
|
171
|
-
var fetchCommand = (appContext) => new
|
|
627
|
+
var fetchCommand = (appContext) => new Command3("fetch").description("Fetch a capability URL with automatic payment handling").argument("<url>", "URL to fetch").option(
|
|
628
|
+
"-X, --method <method>",
|
|
629
|
+
"HTTP method (GET, POST, PUT, PATCH, DELETE). Defaults to POST when -d is set, otherwise GET"
|
|
630
|
+
).option("-d, --data <body>", "Request body (JSON string)").option("-H, --header <header...>", "Headers in Key:Value format").option("--max-pay <amount>", "Maximum amount willing to pay (USDC)").option(
|
|
172
631
|
"--capability <id>",
|
|
173
632
|
"Bind this fetch to a capability (uid or slug) so a reviewable run is recorded even without a prior `zero search`"
|
|
174
633
|
).option(
|
|
@@ -201,55 +660,80 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
201
660
|
headers["content-type"] = "application/json";
|
|
202
661
|
}
|
|
203
662
|
const log = (msg) => console.error(` ${msg}`);
|
|
663
|
+
const method = options.method ? options.method.toUpperCase() : options.data ? "POST" : "GET";
|
|
204
664
|
const requestInit = {
|
|
205
|
-
method
|
|
665
|
+
method,
|
|
206
666
|
headers,
|
|
207
667
|
body: options.data
|
|
208
668
|
};
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
response.headers,
|
|
213
|
-
response.status
|
|
669
|
+
const lastSearch = stateService.loadLastSearch();
|
|
670
|
+
const matchedCapability = lastSearch?.capabilities.find(
|
|
671
|
+
(c) => url.startsWith(c.url)
|
|
214
672
|
);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
673
|
+
const capabilityId = options.capability ?? matchedCapability?.id ?? null;
|
|
674
|
+
const searchId = matchedCapability ? lastSearch?.searchId : void 0;
|
|
675
|
+
const skipReasons = [];
|
|
676
|
+
if (!apiService.walletAddress) {
|
|
677
|
+
skipReasons.push(
|
|
678
|
+
"no wallet configured (run `zero wallet import` / set ZERO_PRIVATE_KEY)"
|
|
220
679
|
);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
options.maxPay,
|
|
226
|
-
log
|
|
680
|
+
}
|
|
681
|
+
if (!capabilityId) {
|
|
682
|
+
skipReasons.push(
|
|
683
|
+
"no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
|
|
227
684
|
);
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
685
|
+
}
|
|
686
|
+
let finalResponse;
|
|
687
|
+
let body = "";
|
|
688
|
+
let paymentMeta;
|
|
689
|
+
let fetchError;
|
|
690
|
+
try {
|
|
691
|
+
log(`Calling ${url}...`);
|
|
692
|
+
const response = await fetch(url, requestInit);
|
|
693
|
+
const paymentReq = detectPaymentRequirement(
|
|
694
|
+
response.headers,
|
|
695
|
+
response.status
|
|
238
696
|
);
|
|
239
|
-
|
|
240
|
-
|
|
697
|
+
if (paymentReq) {
|
|
698
|
+
log(
|
|
699
|
+
`Payment required (${paymentReq.protocol}) \u2014 preparing payment...`
|
|
700
|
+
);
|
|
701
|
+
const result = await paymentService.handlePayment(
|
|
702
|
+
url,
|
|
703
|
+
requestInit,
|
|
704
|
+
paymentReq,
|
|
705
|
+
options.maxPay,
|
|
706
|
+
log
|
|
707
|
+
);
|
|
708
|
+
finalResponse = result.response;
|
|
709
|
+
paymentMeta = {
|
|
710
|
+
protocol: result.protocol,
|
|
711
|
+
chain: result.chain,
|
|
712
|
+
txHash: result.txHash,
|
|
713
|
+
amount: result.amount,
|
|
714
|
+
asset: result.asset
|
|
715
|
+
};
|
|
716
|
+
log(
|
|
717
|
+
`Paid ${result.amount} ${result.asset} via ${result.protocol} on ${result.chain}`
|
|
718
|
+
);
|
|
719
|
+
} else {
|
|
720
|
+
finalResponse = response;
|
|
721
|
+
}
|
|
722
|
+
body = await finalResponse.text();
|
|
723
|
+
} catch (err) {
|
|
724
|
+
fetchError = err instanceof Error ? err : new Error(String(err));
|
|
241
725
|
}
|
|
242
726
|
const latencyMs = Date.now() - startTime;
|
|
243
|
-
|
|
244
|
-
if (!options.json) {
|
|
727
|
+
if (finalResponse && !options.json) {
|
|
245
728
|
console.log(body);
|
|
246
729
|
}
|
|
247
730
|
analyticsService.capture("fetch_executed", {
|
|
248
731
|
url,
|
|
249
|
-
status: finalResponse
|
|
732
|
+
status: finalResponse?.status,
|
|
250
733
|
hasPayment: !!paymentMeta,
|
|
251
734
|
paymentProtocol: paymentMeta?.protocol,
|
|
252
|
-
paymentAmount: paymentMeta?.amount
|
|
735
|
+
paymentAmount: paymentMeta?.amount,
|
|
736
|
+
...fetchError && { error: fetchError.message }
|
|
253
737
|
});
|
|
254
738
|
if (paymentMeta) {
|
|
255
739
|
try {
|
|
@@ -268,24 +752,7 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
268
752
|
} catch {
|
|
269
753
|
}
|
|
270
754
|
}
|
|
271
|
-
const lastSearch = stateService.loadLastSearch();
|
|
272
|
-
const matchedCapability = lastSearch?.capabilities.find(
|
|
273
|
-
(c) => url.startsWith(c.url)
|
|
274
|
-
);
|
|
275
|
-
const capabilityId = options.capability ?? matchedCapability?.id ?? null;
|
|
276
|
-
const searchId = matchedCapability ? lastSearch?.searchId : void 0;
|
|
277
755
|
let runId = null;
|
|
278
|
-
const skipReasons = [];
|
|
279
|
-
if (!apiService.walletAddress) {
|
|
280
|
-
skipReasons.push(
|
|
281
|
-
"no wallet configured (run `zero wallet import` / set ZERO_PRIVATE_KEY)"
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
if (!capabilityId) {
|
|
285
|
-
skipReasons.push(
|
|
286
|
-
"no capability resolved \u2014 pass --capability <uid|slug> or run `zero search` first so the URL can be matched"
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
756
|
if (capabilityId && apiService.walletAddress) {
|
|
290
757
|
let requestSchema;
|
|
291
758
|
let responseSchema;
|
|
@@ -305,7 +772,7 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
305
772
|
const runResult = await apiService.createRun({
|
|
306
773
|
capabilityId,
|
|
307
774
|
searchId,
|
|
308
|
-
status: finalResponse
|
|
775
|
+
status: finalResponse?.status,
|
|
309
776
|
latencyMs,
|
|
310
777
|
requestSchema,
|
|
311
778
|
responseSchema,
|
|
@@ -325,14 +792,18 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
325
792
|
);
|
|
326
793
|
}
|
|
327
794
|
}
|
|
795
|
+
if (fetchError && !options.json) {
|
|
796
|
+
console.error(` Fetch failed: ${fetchError.message}`);
|
|
797
|
+
}
|
|
328
798
|
if (options.json) {
|
|
329
799
|
console.log(
|
|
330
800
|
JSON.stringify({
|
|
331
801
|
runId,
|
|
332
|
-
status: finalResponse
|
|
802
|
+
status: finalResponse?.status ?? null,
|
|
333
803
|
latencyMs,
|
|
334
804
|
payment: paymentMeta ?? null,
|
|
335
|
-
body,
|
|
805
|
+
body: finalResponse ? body : null,
|
|
806
|
+
...fetchError && { error: fetchError.message },
|
|
336
807
|
...skipReasons.length > 0 && {
|
|
337
808
|
runTrackingSkipped: skipReasons
|
|
338
809
|
}
|
|
@@ -365,6 +836,9 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
365
836
|
Note: this run was NOT recorded for review \u2014 ${skipReasons.join("; ")}.`
|
|
366
837
|
);
|
|
367
838
|
}
|
|
839
|
+
if (fetchError) {
|
|
840
|
+
process.exitCode = 1;
|
|
841
|
+
}
|
|
368
842
|
} catch (err) {
|
|
369
843
|
console.error(err instanceof Error ? err.message : "Fetch failed");
|
|
370
844
|
process.exitCode = 1;
|
|
@@ -373,7 +847,7 @@ var fetchCommand = (appContext) => new Command2("fetch").description("Fetch a ca
|
|
|
373
847
|
);
|
|
374
848
|
|
|
375
849
|
// src/commands/get-command.ts
|
|
376
|
-
import { Command as
|
|
850
|
+
import { Command as Command4 } from "commander";
|
|
377
851
|
var formatReviewCount = (count) => {
|
|
378
852
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
|
|
379
853
|
return count.toString();
|
|
@@ -428,7 +902,7 @@ var formatCapability = (capability) => {
|
|
|
428
902
|
lines.push(` Method: ${capability.method}`);
|
|
429
903
|
return lines.join("\n");
|
|
430
904
|
};
|
|
431
|
-
var getCommand = (appContext) => new
|
|
905
|
+
var getCommand = (appContext) => new Command4("get").description(
|
|
432
906
|
"Get details for a capability by position from last search, or by slug"
|
|
433
907
|
).argument(
|
|
434
908
|
"<identifier>",
|
|
@@ -482,20 +956,21 @@ var getCommand = (appContext) => new Command3("get").description(
|
|
|
482
956
|
});
|
|
483
957
|
|
|
484
958
|
// src/commands/init-command.ts
|
|
485
|
-
import { createHash } from "crypto";
|
|
959
|
+
import { createHash as createHash3 } from "crypto";
|
|
486
960
|
import {
|
|
487
961
|
chmodSync,
|
|
488
962
|
cpSync,
|
|
489
963
|
existsSync as existsSync2,
|
|
490
964
|
mkdirSync as mkdirSync2,
|
|
491
965
|
readdirSync,
|
|
492
|
-
readFileSync as
|
|
966
|
+
readFileSync as readFileSync3,
|
|
967
|
+
rmSync,
|
|
493
968
|
writeFileSync as writeFileSync2
|
|
494
969
|
} from "fs";
|
|
495
970
|
import { homedir as homedir2 } from "os";
|
|
496
971
|
import { dirname, join as join2, relative } from "path";
|
|
497
972
|
import { fileURLToPath } from "url";
|
|
498
|
-
import { Command as
|
|
973
|
+
import { Command as Command5 } from "commander";
|
|
499
974
|
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
500
975
|
var AGENT_TOOLS = [
|
|
501
976
|
{ name: "Claude Code", configDir: ".claude" },
|
|
@@ -517,7 +992,7 @@ var getPackageRoot = () => {
|
|
|
517
992
|
}
|
|
518
993
|
return dir;
|
|
519
994
|
};
|
|
520
|
-
var sha256File = (filePath) =>
|
|
995
|
+
var sha256File = (filePath) => createHash3("sha256").update(readFileSync3(filePath)).digest("hex");
|
|
521
996
|
var verifyFileCopy = (src, dest) => {
|
|
522
997
|
if (!existsSync2(dest)) return false;
|
|
523
998
|
return sha256File(src) === sha256File(dest);
|
|
@@ -559,7 +1034,7 @@ var installHook = (home) => {
|
|
|
559
1034
|
let settings = {};
|
|
560
1035
|
if (existsSync2(settingsPath)) {
|
|
561
1036
|
try {
|
|
562
|
-
settings = JSON.parse(
|
|
1037
|
+
settings = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
563
1038
|
} catch {
|
|
564
1039
|
}
|
|
565
1040
|
}
|
|
@@ -636,6 +1111,36 @@ var installHook = (home) => {
|
|
|
636
1111
|
`);
|
|
637
1112
|
return true;
|
|
638
1113
|
};
|
|
1114
|
+
var CONFLICTING_SKILL_PATTERNS = ["zam", "tempo"];
|
|
1115
|
+
var findConflictingSkills = (home) => {
|
|
1116
|
+
const found = [];
|
|
1117
|
+
for (const tool of AGENT_TOOLS) {
|
|
1118
|
+
const toolSkillsPath = join2(home, tool.configDir, "skills");
|
|
1119
|
+
if (!existsSync2(toolSkillsPath)) continue;
|
|
1120
|
+
const entries = readdirSync(toolSkillsPath, { withFileTypes: true });
|
|
1121
|
+
for (const entry of entries) {
|
|
1122
|
+
if (!entry.isDirectory()) continue;
|
|
1123
|
+
const lower = entry.name.toLowerCase();
|
|
1124
|
+
if (CONFLICTING_SKILL_PATTERNS.some((p) => lower.includes(p))) {
|
|
1125
|
+
found.push({
|
|
1126
|
+
tool: tool.name,
|
|
1127
|
+
skillPath: join2(toolSkillsPath, entry.name),
|
|
1128
|
+
skillName: entry.name
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
return found;
|
|
1134
|
+
};
|
|
1135
|
+
var removeConflictingSkills = (home) => {
|
|
1136
|
+
const conflicts = findConflictingSkills(home);
|
|
1137
|
+
const removed = [];
|
|
1138
|
+
for (const { skillPath, tool, skillName } of conflicts) {
|
|
1139
|
+
rmSync(skillPath, { recursive: true, force: true });
|
|
1140
|
+
removed.push(`${tool}: ${skillName}`);
|
|
1141
|
+
}
|
|
1142
|
+
return removed;
|
|
1143
|
+
};
|
|
639
1144
|
var installSkills = (home) => {
|
|
640
1145
|
const skillsSourceDir = join2(getPackageRoot(), "skills");
|
|
641
1146
|
const skillDirs = readdirSync(skillsSourceDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -665,7 +1170,7 @@ var installSkills = (home) => {
|
|
|
665
1170
|
}
|
|
666
1171
|
return installed;
|
|
667
1172
|
};
|
|
668
|
-
var initCommand = (appContext) => new
|
|
1173
|
+
var initCommand = (appContext) => new Command5("init").description("Initialize Zero CLI for usage").option("--force", "Overwrite existing configuration").action(async (options) => {
|
|
669
1174
|
const home = homedir2();
|
|
670
1175
|
const zeroDir = join2(home, ".zero");
|
|
671
1176
|
const configPath = join2(zeroDir, "config.json");
|
|
@@ -674,7 +1179,7 @@ var initCommand = (appContext) => new Command4("init").description("Initialize Z
|
|
|
674
1179
|
const walletExists = (() => {
|
|
675
1180
|
if (!existsSync2(configPath)) return false;
|
|
676
1181
|
try {
|
|
677
|
-
const existing = JSON.parse(
|
|
1182
|
+
const existing = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
678
1183
|
return !!existing.privateKey;
|
|
679
1184
|
} catch {
|
|
680
1185
|
return false;
|
|
@@ -684,7 +1189,7 @@ var initCommand = (appContext) => new Command4("init").description("Initialize Z
|
|
|
684
1189
|
const privateKey = generatePrivateKey();
|
|
685
1190
|
const account = privateKeyToAccount(privateKey);
|
|
686
1191
|
mkdirSync2(zeroDir, { recursive: true });
|
|
687
|
-
const existing = existsSync2(configPath) ? JSON.parse(
|
|
1192
|
+
const existing = existsSync2(configPath) ? JSON.parse(readFileSync3(configPath, "utf8")) : {};
|
|
688
1193
|
writeFileSync2(
|
|
689
1194
|
configPath,
|
|
690
1195
|
JSON.stringify(
|
|
@@ -698,7 +1203,7 @@ var initCommand = (appContext) => new Command4("init").description("Initialize Z
|
|
|
698
1203
|
console.log(`Wallet address: ${account.address}`);
|
|
699
1204
|
} else {
|
|
700
1205
|
try {
|
|
701
|
-
const existing = JSON.parse(
|
|
1206
|
+
const existing = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
702
1207
|
const account = privateKeyToAccount(existing.privateKey);
|
|
703
1208
|
walletAddress = account.address;
|
|
704
1209
|
} catch {
|
|
@@ -730,6 +1235,17 @@ var initCommand = (appContext) => new Command4("init").description("Initialize Z
|
|
|
730
1235
|
} catch (err) {
|
|
731
1236
|
hookError = err instanceof Error ? err.message : "unknown hook error";
|
|
732
1237
|
}
|
|
1238
|
+
const conflictingSkills = findConflictingSkills(home);
|
|
1239
|
+
if (conflictingSkills.length > 0) {
|
|
1240
|
+
const skillList = conflictingSkills.map((s) => ` - ${s.tool}: ${s.skillName}`).join("\n");
|
|
1241
|
+
console.error(
|
|
1242
|
+
`
|
|
1243
|
+
Found deprecated skills that may conflict with Zero:
|
|
1244
|
+
${skillList}
|
|
1245
|
+
|
|
1246
|
+
To remove them, run: zero init cleanup`
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
733
1249
|
console.error(
|
|
734
1250
|
'Zero is ready! Run `zero search` to find capabilities.\n\nTry:\n zero search "translate text to Spanish"\n zero search "generate an image"\n zero search "weather forecast"'
|
|
735
1251
|
);
|
|
@@ -752,23 +1268,45 @@ var initCommand = (appContext) => new Command4("init").description("Initialize Z
|
|
|
752
1268
|
hook_installed: hookInstalled,
|
|
753
1269
|
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
754
1270
|
hook_error: hookError,
|
|
1271
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
1272
|
+
conflicting_skills_found: conflictingSkills.length,
|
|
755
1273
|
force: options.force ?? false
|
|
756
1274
|
});
|
|
757
|
-
})
|
|
1275
|
+
}).addCommand(
|
|
1276
|
+
new Command5("cleanup").description(
|
|
1277
|
+
"Remove deprecated skills (zam, tempo) that conflict with Zero"
|
|
1278
|
+
).action(() => {
|
|
1279
|
+
const home = homedir2();
|
|
1280
|
+
const removed = removeConflictingSkills(home);
|
|
1281
|
+
if (removed.length === 0) {
|
|
1282
|
+
console.error("No conflicting skills found. Nothing to remove.");
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
const removedList = removed.map((s) => ` - ${s}`).join("\n");
|
|
1286
|
+
console.error(`Removed deprecated skills:
|
|
1287
|
+
${removedList}`);
|
|
1288
|
+
appContext.services.analyticsService.capture("skills_cleanup", {
|
|
1289
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
1290
|
+
skills_removed: removed,
|
|
1291
|
+
// biome-ignore lint/style/useNamingConvention: snake_case for analytics
|
|
1292
|
+
skills_removed_count: removed.length
|
|
1293
|
+
});
|
|
1294
|
+
})
|
|
1295
|
+
);
|
|
758
1296
|
|
|
759
1297
|
// src/commands/review-command.ts
|
|
760
|
-
import { readFileSync as
|
|
761
|
-
import { Command as
|
|
762
|
-
import { z } from "zod";
|
|
763
|
-
var
|
|
764
|
-
runId:
|
|
765
|
-
success:
|
|
766
|
-
accuracy:
|
|
767
|
-
value:
|
|
768
|
-
reliability:
|
|
769
|
-
content:
|
|
1298
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
1299
|
+
import { Command as Command6 } from "commander";
|
|
1300
|
+
import { z as z3 } from "zod";
|
|
1301
|
+
var bulkEntrySchema2 = z3.object({
|
|
1302
|
+
runId: z3.string(),
|
|
1303
|
+
success: z3.boolean(),
|
|
1304
|
+
accuracy: z3.number().int().min(1).max(5),
|
|
1305
|
+
value: z3.number().int().min(1).max(5),
|
|
1306
|
+
reliability: z3.number().int().min(1).max(5),
|
|
1307
|
+
content: z3.string().optional()
|
|
770
1308
|
});
|
|
771
|
-
var reviewCommand = (appContext) => new
|
|
1309
|
+
var reviewCommand = (appContext) => new Command6("review").description("Submit a review for a capability run").addHelpText(
|
|
772
1310
|
"after",
|
|
773
1311
|
`
|
|
774
1312
|
Tips for a great review:
|
|
@@ -796,14 +1334,14 @@ Examples:
|
|
|
796
1334
|
try {
|
|
797
1335
|
const { analyticsService, apiService } = appContext.services;
|
|
798
1336
|
if (options.fromFile) {
|
|
799
|
-
const contents =
|
|
1337
|
+
const contents = readFileSync4(options.fromFile, "utf8");
|
|
800
1338
|
const lines = contents.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
801
1339
|
let ok = 0;
|
|
802
1340
|
let failed = 0;
|
|
803
1341
|
for (const [idx, line] of lines.entries()) {
|
|
804
1342
|
const lineNum = idx + 1;
|
|
805
1343
|
try {
|
|
806
|
-
const parsed =
|
|
1344
|
+
const parsed = bulkEntrySchema2.parse(JSON.parse(line));
|
|
807
1345
|
const result2 = await apiService.createReview(parsed);
|
|
808
1346
|
ok += 1;
|
|
809
1347
|
console.log(
|
|
@@ -904,8 +1442,8 @@ Bulk review complete: ${ok} ok, ${failed} failed`);
|
|
|
904
1442
|
);
|
|
905
1443
|
|
|
906
1444
|
// src/commands/runs-command.ts
|
|
907
|
-
import { Command as
|
|
908
|
-
var runsCommand = (appContext) => new
|
|
1445
|
+
import { Command as Command7 } from "commander";
|
|
1446
|
+
var runsCommand = (appContext) => new Command7("runs").description("List your recent capability runs").addHelpText(
|
|
909
1447
|
"after",
|
|
910
1448
|
`
|
|
911
1449
|
View your recent capability runs \u2014 status, latency, cost, and payment info.
|
|
@@ -953,7 +1491,7 @@ Examples:
|
|
|
953
1491
|
);
|
|
954
1492
|
|
|
955
1493
|
// src/commands/search-command.ts
|
|
956
|
-
import { Command as
|
|
1494
|
+
import { Command as Command8 } from "commander";
|
|
957
1495
|
var formatReviewCount2 = (count) => {
|
|
958
1496
|
if (count >= 1e3) return `${(count / 1e3).toFixed(1)}k`;
|
|
959
1497
|
return count.toString();
|
|
@@ -991,10 +1529,16 @@ var formatSearchResults = (results) => {
|
|
|
991
1529
|
"${displayDescription}"`;
|
|
992
1530
|
}).join("\n");
|
|
993
1531
|
};
|
|
994
|
-
var searchCommand = (appContext) => new
|
|
1532
|
+
var searchCommand = (appContext) => new Command8("search").description("Search for capabilities").argument("<query>", "Search query").option("--json", "Output raw JSON to stdout").option("--offset <n>", "Pagination offset", Number).option("--limit <n>", "Results per page", Number).option("--free", "Only show free capabilities").option("--max-cost <amount>", "Maximum cost per call").option("--min-rating <stars>", "Minimum star rating (1-5)", Number).option("--protocol <protocol>", "Payment protocol (x402 or mpp)").option("--min-trust <n>", "Minimum trust score (0-100)", Number).option(
|
|
995
1533
|
"--status <status>",
|
|
996
1534
|
"Filter by availability (healthy, degraded, down)"
|
|
997
|
-
).option("--all", "Show all results (no trust or health filtering)").
|
|
1535
|
+
).option("--all", "Show all results (no trust or health filtering)").option(
|
|
1536
|
+
"--source <source>",
|
|
1537
|
+
"Only show results from this crawl source (e.g. mpp, bazaar)"
|
|
1538
|
+
).option(
|
|
1539
|
+
"--exclude-source <source>",
|
|
1540
|
+
"Exclude results from this crawl source"
|
|
1541
|
+
).action(
|
|
998
1542
|
async (query, options) => {
|
|
999
1543
|
try {
|
|
1000
1544
|
const { analyticsService, apiService, stateService } = appContext.services;
|
|
@@ -1023,7 +1567,9 @@ var searchCommand = (appContext) => new Command7("search").description("Search f
|
|
|
1023
1567
|
protocol: options.protocol,
|
|
1024
1568
|
minTrust: options.minTrust,
|
|
1025
1569
|
availabilityStatus: options.status,
|
|
1026
|
-
includeAll: options.all
|
|
1570
|
+
includeAll: options.all,
|
|
1571
|
+
source: options.source,
|
|
1572
|
+
excludeSource: options.excludeSource
|
|
1027
1573
|
});
|
|
1028
1574
|
analyticsService.capture("search_executed", {
|
|
1029
1575
|
query,
|
|
@@ -1061,13 +1607,13 @@ var searchCommand = (appContext) => new Command7("search").description("Search f
|
|
|
1061
1607
|
);
|
|
1062
1608
|
|
|
1063
1609
|
// src/commands/wallet-command.ts
|
|
1064
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as
|
|
1610
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
1065
1611
|
import { homedir as homedir3 } from "os";
|
|
1066
1612
|
import { join as join3 } from "path";
|
|
1067
|
-
import { Command as
|
|
1613
|
+
import { Command as Command9 } from "commander";
|
|
1068
1614
|
import open from "open";
|
|
1069
1615
|
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
1070
|
-
var walletBalanceCommand = (appContext) => new
|
|
1616
|
+
var walletBalanceCommand = (appContext) => new Command9("balance").description("Show wallet balance").action(async () => {
|
|
1071
1617
|
const { walletService } = appContext.services;
|
|
1072
1618
|
const balance = await walletService.getBalance();
|
|
1073
1619
|
if (balance === null) {
|
|
@@ -1082,7 +1628,7 @@ var walletBalanceCommand = (appContext) => new Command8("balance").description("
|
|
|
1082
1628
|
}
|
|
1083
1629
|
console.log(`${balance.amount} ${balance.asset}`);
|
|
1084
1630
|
});
|
|
1085
|
-
var walletFundCommand = (appContext) => new
|
|
1631
|
+
var walletFundCommand = (appContext) => new Command9("fund").description("Fund your wallet").argument("[amount]", "Amount to fund in USDC").option("--manual", "Show wallet address for manual transfer").action(
|
|
1086
1632
|
async (amount, options) => {
|
|
1087
1633
|
const { analyticsService, walletService } = appContext.services;
|
|
1088
1634
|
const address = walletService.getAddress();
|
|
@@ -1119,7 +1665,7 @@ ${address}`);
|
|
|
1119
1665
|
}
|
|
1120
1666
|
}
|
|
1121
1667
|
);
|
|
1122
|
-
var walletAddressCommand = (appContext) => new
|
|
1668
|
+
var walletAddressCommand = (appContext) => new Command9("address").description("Show wallet address").action(() => {
|
|
1123
1669
|
const { walletService } = appContext.services;
|
|
1124
1670
|
const address = walletService.getAddress();
|
|
1125
1671
|
if (!address) {
|
|
@@ -1129,7 +1675,7 @@ var walletAddressCommand = (appContext) => new Command8("address").description("
|
|
|
1129
1675
|
}
|
|
1130
1676
|
console.log(address);
|
|
1131
1677
|
});
|
|
1132
|
-
var walletSetCommand = (appContext) => new
|
|
1678
|
+
var walletSetCommand = (appContext) => new Command9("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) => {
|
|
1133
1679
|
const { analyticsService } = appContext.services;
|
|
1134
1680
|
if (!privateKey.startsWith("0x")) {
|
|
1135
1681
|
console.error("Private key must be 0x-prefixed hex string.");
|
|
@@ -1148,7 +1694,7 @@ var walletSetCommand = (appContext) => new Command8("set").description("Set wall
|
|
|
1148
1694
|
const configPath = join3(zeroDir, "config.json");
|
|
1149
1695
|
if (!options.force && existsSync3(configPath)) {
|
|
1150
1696
|
try {
|
|
1151
|
-
const existing2 = JSON.parse(
|
|
1697
|
+
const existing2 = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
1152
1698
|
if (existing2.privateKey) {
|
|
1153
1699
|
console.error(
|
|
1154
1700
|
"Wallet already configured. Use --force to overwrite."
|
|
@@ -1160,7 +1706,7 @@ var walletSetCommand = (appContext) => new Command8("set").description("Set wall
|
|
|
1160
1706
|
}
|
|
1161
1707
|
}
|
|
1162
1708
|
mkdirSync3(zeroDir, { recursive: true });
|
|
1163
|
-
const existing = existsSync3(configPath) ? JSON.parse(
|
|
1709
|
+
const existing = existsSync3(configPath) ? JSON.parse(readFileSync5(configPath, "utf8")) : {};
|
|
1164
1710
|
writeFileSync3(
|
|
1165
1711
|
configPath,
|
|
1166
1712
|
JSON.stringify(
|
|
@@ -1181,7 +1727,7 @@ var walletSetCommand = (appContext) => new Command8("set").description("Set wall
|
|
|
1181
1727
|
});
|
|
1182
1728
|
});
|
|
1183
1729
|
var walletCommand = (appContext) => {
|
|
1184
|
-
const cmd = new
|
|
1730
|
+
const cmd = new Command9("wallet").description("Manage your wallet");
|
|
1185
1731
|
cmd.addCommand(walletBalanceCommand(appContext));
|
|
1186
1732
|
cmd.addCommand(walletFundCommand(appContext));
|
|
1187
1733
|
cmd.addCommand(walletAddressCommand(appContext));
|
|
@@ -1192,7 +1738,7 @@ var walletCommand = (appContext) => {
|
|
|
1192
1738
|
// src/app.ts
|
|
1193
1739
|
var createApp = (appContext) => {
|
|
1194
1740
|
const { analyticsService } = appContext.services;
|
|
1195
|
-
const program = new
|
|
1741
|
+
const program = new Command10().name("zero").description("Zero CLI \u2014 Search engine and payment platform for AI agents").version(package_default.version, "-v, --version").exitOverride().hook("preAction", (_thisCommand, actionCommand) => {
|
|
1196
1742
|
analyticsService.capture("command_executed", {
|
|
1197
1743
|
command: actionCommand.name()
|
|
1198
1744
|
});
|
|
@@ -1203,16 +1749,17 @@ var createApp = (appContext) => {
|
|
|
1203
1749
|
program.addCommand(fetchCommand(appContext));
|
|
1204
1750
|
program.addCommand(reviewCommand(appContext));
|
|
1205
1751
|
program.addCommand(runsCommand(appContext));
|
|
1752
|
+
program.addCommand(bugReportCommand(appContext));
|
|
1206
1753
|
program.addCommand(walletCommand(appContext));
|
|
1207
1754
|
program.addCommand(configCommand(appContext));
|
|
1208
1755
|
return program;
|
|
1209
1756
|
};
|
|
1210
1757
|
|
|
1211
1758
|
// src/app/app-env.ts
|
|
1212
|
-
import
|
|
1213
|
-
var envSchema =
|
|
1214
|
-
ZERO_API_URL:
|
|
1215
|
-
ZERO_PRIVATE_KEY:
|
|
1759
|
+
import z4 from "zod";
|
|
1760
|
+
var envSchema = z4.object({
|
|
1761
|
+
ZERO_API_URL: z4.string().default("https://api.zero.xyz"),
|
|
1762
|
+
ZERO_PRIVATE_KEY: z4.string().optional()
|
|
1216
1763
|
});
|
|
1217
1764
|
var getEnv = () => {
|
|
1218
1765
|
try {
|
|
@@ -1225,14 +1772,14 @@ var getEnv = () => {
|
|
|
1225
1772
|
};
|
|
1226
1773
|
|
|
1227
1774
|
// src/app/app-services.ts
|
|
1228
|
-
import { existsSync as existsSync6, readFileSync as
|
|
1775
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8 } from "fs";
|
|
1229
1776
|
import { homedir as homedir4 } from "os";
|
|
1230
1777
|
import { join as join5 } from "path";
|
|
1231
1778
|
import { privateKeyToAccount as privateKeyToAccount3 } from "viem/accounts";
|
|
1232
1779
|
|
|
1233
1780
|
// src/services/analytics-service.ts
|
|
1234
1781
|
import { randomUUID } from "crypto";
|
|
1235
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as
|
|
1782
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
1236
1783
|
import { dirname as dirname2 } from "path";
|
|
1237
1784
|
import { PostHog } from "posthog-node";
|
|
1238
1785
|
var POSTHOG_API_KEY = "phc_B2vLyNxAf2mnqvdPQajf4d4b2iXc35dep2ZrvebMJLuX";
|
|
@@ -1247,7 +1794,7 @@ var AnalyticsService = class {
|
|
|
1247
1794
|
let persistedAnonId;
|
|
1248
1795
|
try {
|
|
1249
1796
|
if (existsSync4(opts.configPath)) {
|
|
1250
|
-
const config = JSON.parse(
|
|
1797
|
+
const config = JSON.parse(readFileSync6(opts.configPath, "utf8"));
|
|
1251
1798
|
if (config.telemetry === false) {
|
|
1252
1799
|
telemetryEnabled = false;
|
|
1253
1800
|
}
|
|
@@ -1272,7 +1819,7 @@ var AnalyticsService = class {
|
|
|
1272
1819
|
try {
|
|
1273
1820
|
const dir = dirname2(opts.configPath);
|
|
1274
1821
|
mkdirSync4(dir, { recursive: true });
|
|
1275
|
-
const existing = existsSync4(opts.configPath) ? JSON.parse(
|
|
1822
|
+
const existing = existsSync4(opts.configPath) ? JSON.parse(readFileSync6(opts.configPath, "utf8")) : {};
|
|
1276
1823
|
writeFileSync4(
|
|
1277
1824
|
opts.configPath,
|
|
1278
1825
|
JSON.stringify({ ...existing, anonId: newAnonId }, null, 2)
|
|
@@ -1318,203 +1865,6 @@ var AnalyticsService = class {
|
|
|
1318
1865
|
}
|
|
1319
1866
|
};
|
|
1320
1867
|
|
|
1321
|
-
// src/services/api-service.ts
|
|
1322
|
-
import { createHash as createHash2 } from "crypto";
|
|
1323
|
-
import z3 from "zod";
|
|
1324
|
-
var searchResultSchema = z3.object({
|
|
1325
|
-
id: z3.string(),
|
|
1326
|
-
position: z3.number(),
|
|
1327
|
-
slug: z3.string(),
|
|
1328
|
-
name: z3.string(),
|
|
1329
|
-
canonicalName: z3.string().nullable().optional(),
|
|
1330
|
-
description: z3.string(),
|
|
1331
|
-
whatItDoes: z3.string().nullable().optional(),
|
|
1332
|
-
url: z3.string(),
|
|
1333
|
-
cost: z3.object({ amount: z3.string(), asset: z3.string() }),
|
|
1334
|
-
rating: z3.object({
|
|
1335
|
-
score: z3.string(),
|
|
1336
|
-
successRate: z3.string(),
|
|
1337
|
-
reviews: z3.number(),
|
|
1338
|
-
stars: z3.string().nullable().optional(),
|
|
1339
|
-
state: z3.enum(["unrated", "rated"]).optional()
|
|
1340
|
-
}),
|
|
1341
|
-
trustScore: z3.number().nullable().optional(),
|
|
1342
|
-
trustSignalCount: z3.number().optional(),
|
|
1343
|
-
availabilityStatus: z3.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional(),
|
|
1344
|
-
relevanceScore: z3.number().optional()
|
|
1345
|
-
});
|
|
1346
|
-
var searchResponseSchema = z3.object({
|
|
1347
|
-
searchId: z3.string(),
|
|
1348
|
-
total: z3.number().optional().default(0),
|
|
1349
|
-
offset: z3.number().optional().default(0),
|
|
1350
|
-
hasMore: z3.boolean().optional().default(false),
|
|
1351
|
-
capabilities: z3.array(searchResultSchema)
|
|
1352
|
-
});
|
|
1353
|
-
var capabilityResponseSchema = z3.object({
|
|
1354
|
-
uid: z3.string(),
|
|
1355
|
-
slug: z3.string(),
|
|
1356
|
-
name: z3.string(),
|
|
1357
|
-
description: z3.string(),
|
|
1358
|
-
url: z3.string(),
|
|
1359
|
-
method: z3.string(),
|
|
1360
|
-
headers: z3.record(z3.string(), z3.string()).nullable(),
|
|
1361
|
-
bodySchema: z3.record(z3.string(), z3.unknown()).nullable(),
|
|
1362
|
-
responseSchema: z3.record(z3.string(), z3.unknown()).nullable(),
|
|
1363
|
-
example: z3.object({ request: z3.unknown(), response: z3.unknown() }).nullable(),
|
|
1364
|
-
tags: z3.array(z3.string()).nullable(),
|
|
1365
|
-
displayCostAmount: z3.string(),
|
|
1366
|
-
displayCostAsset: z3.string(),
|
|
1367
|
-
rating: z3.object({
|
|
1368
|
-
score: z3.string(),
|
|
1369
|
-
successRate: z3.string(),
|
|
1370
|
-
reviews: z3.number(),
|
|
1371
|
-
stars: z3.string().nullable().optional(),
|
|
1372
|
-
state: z3.enum(["unrated", "rated"]).optional()
|
|
1373
|
-
}),
|
|
1374
|
-
priceObserved: z3.object({
|
|
1375
|
-
medianCents: z3.string(),
|
|
1376
|
-
p95Cents: z3.string(),
|
|
1377
|
-
sampleCount: z3.number(),
|
|
1378
|
-
varies: z3.boolean()
|
|
1379
|
-
}).nullable().optional(),
|
|
1380
|
-
paymentMethods: z3.array(
|
|
1381
|
-
z3.object({
|
|
1382
|
-
uid: z3.string(),
|
|
1383
|
-
protocol: z3.string(),
|
|
1384
|
-
methodType: z3.string(),
|
|
1385
|
-
chain: z3.string().nullable(),
|
|
1386
|
-
mode: z3.string(),
|
|
1387
|
-
costAmount: z3.string(),
|
|
1388
|
-
costPer: z3.string(),
|
|
1389
|
-
priority: z3.number()
|
|
1390
|
-
})
|
|
1391
|
-
).nullable(),
|
|
1392
|
-
trustScore: z3.number().nullable().optional(),
|
|
1393
|
-
trustComponents: z3.object({
|
|
1394
|
-
apiQuality: z3.number().nullable(),
|
|
1395
|
-
blockchainActivity: z3.number().nullable(),
|
|
1396
|
-
performance: z3.number().nullable()
|
|
1397
|
-
}).nullable().optional(),
|
|
1398
|
-
availabilityStatus: z3.enum(["healthy", "degraded", "down", "unknown"]).nullable().optional()
|
|
1399
|
-
});
|
|
1400
|
-
var createRunResponseSchema = z3.object({
|
|
1401
|
-
runId: z3.string()
|
|
1402
|
-
});
|
|
1403
|
-
var createReviewResponseSchema = z3.object({
|
|
1404
|
-
reviewId: z3.string(),
|
|
1405
|
-
recorded: z3.boolean()
|
|
1406
|
-
});
|
|
1407
|
-
var runListItemSchema = z3.object({
|
|
1408
|
-
uid: z3.string(),
|
|
1409
|
-
capabilityUid: z3.string(),
|
|
1410
|
-
capabilitySlug: z3.string(),
|
|
1411
|
-
capabilityName: z3.string(),
|
|
1412
|
-
status: z3.number().nullable(),
|
|
1413
|
-
latencyMs: z3.number().nullable(),
|
|
1414
|
-
cost: z3.object({ amount: z3.string(), asset: z3.string().nullable() }).nullable(),
|
|
1415
|
-
payment: z3.object({
|
|
1416
|
-
protocol: z3.string(),
|
|
1417
|
-
chain: z3.string().nullable(),
|
|
1418
|
-
txHash: z3.string().nullable(),
|
|
1419
|
-
mode: z3.string().nullable()
|
|
1420
|
-
}).nullable(),
|
|
1421
|
-
createdAt: z3.coerce.date(),
|
|
1422
|
-
reviewed: z3.boolean()
|
|
1423
|
-
});
|
|
1424
|
-
var listRunsResponseSchema = z3.object({
|
|
1425
|
-
runs: z3.array(runListItemSchema),
|
|
1426
|
-
nextCursor: z3.string().nullable()
|
|
1427
|
-
});
|
|
1428
|
-
var buildCanonicalMessage = (method, path, body, timestamp, nonce) => {
|
|
1429
|
-
const bodyHash = createHash2("sha256").update(body ?? "").digest("hex");
|
|
1430
|
-
return `${method}:${path}:${bodyHash}:${timestamp}:${nonce}`;
|
|
1431
|
-
};
|
|
1432
|
-
var ApiService = class {
|
|
1433
|
-
constructor(baseUrl, account) {
|
|
1434
|
-
this.baseUrl = baseUrl;
|
|
1435
|
-
this.account = account;
|
|
1436
|
-
this.walletAddress = this.account?.address ?? null;
|
|
1437
|
-
}
|
|
1438
|
-
walletAddress;
|
|
1439
|
-
account;
|
|
1440
|
-
signRequest = async (method, path, body) => {
|
|
1441
|
-
if (!this.account) throw new Error("No private key configured");
|
|
1442
|
-
const timestamp = Math.floor(Date.now() / 1e3).toString();
|
|
1443
|
-
const nonce = crypto.randomUUID();
|
|
1444
|
-
const message = buildCanonicalMessage(method, path, body, timestamp, nonce);
|
|
1445
|
-
const signature = await this.account.signMessage({ message });
|
|
1446
|
-
return {
|
|
1447
|
-
"x-zero-address": this.account.address,
|
|
1448
|
-
"x-zero-timestamp": timestamp,
|
|
1449
|
-
"x-zero-nonce": nonce,
|
|
1450
|
-
"x-zero-signature": signature
|
|
1451
|
-
};
|
|
1452
|
-
};
|
|
1453
|
-
request = async (method, path, body) => {
|
|
1454
|
-
const url = `${this.baseUrl}${path}`;
|
|
1455
|
-
const bodyStr = body ? JSON.stringify(body) : void 0;
|
|
1456
|
-
const headers = {
|
|
1457
|
-
"content-type": "application/json"
|
|
1458
|
-
};
|
|
1459
|
-
if (this.account) {
|
|
1460
|
-
const walletHeaders = await this.signRequest(method, path, bodyStr);
|
|
1461
|
-
Object.assign(headers, walletHeaders);
|
|
1462
|
-
}
|
|
1463
|
-
const response = await fetch(url, {
|
|
1464
|
-
method,
|
|
1465
|
-
headers,
|
|
1466
|
-
body: bodyStr
|
|
1467
|
-
});
|
|
1468
|
-
if (!response.ok) {
|
|
1469
|
-
const errorBody = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
1470
|
-
throw new Error(
|
|
1471
|
-
errorBody.error ?? `HTTP ${response.status}`
|
|
1472
|
-
);
|
|
1473
|
-
}
|
|
1474
|
-
return response.json();
|
|
1475
|
-
};
|
|
1476
|
-
search = async (options) => {
|
|
1477
|
-
const json = await this.request("POST", "/v1/search", options);
|
|
1478
|
-
return searchResponseSchema.parse(json);
|
|
1479
|
-
};
|
|
1480
|
-
getCapability = async (id, searchId) => {
|
|
1481
|
-
const qs = searchId ? `?searchId=${encodeURIComponent(searchId)}` : "";
|
|
1482
|
-
const json = await this.request(
|
|
1483
|
-
"GET",
|
|
1484
|
-
`/v1/capabilities/${encodeURIComponent(id)}${qs}`
|
|
1485
|
-
);
|
|
1486
|
-
return capabilityResponseSchema.parse(json);
|
|
1487
|
-
};
|
|
1488
|
-
createRun = async (data) => {
|
|
1489
|
-
const json = await this.request("POST", "/v1/runs", data);
|
|
1490
|
-
return createRunResponseSchema.parse(json);
|
|
1491
|
-
};
|
|
1492
|
-
listRuns = async (params = {}) => {
|
|
1493
|
-
const qs = new URLSearchParams();
|
|
1494
|
-
if (params.capabilityId) qs.set("capabilityId", params.capabilityId);
|
|
1495
|
-
if (params.unreviewed) qs.set("unreviewed", "true");
|
|
1496
|
-
if (params.limit) qs.set("limit", String(params.limit));
|
|
1497
|
-
if (params.cursor) qs.set("cursor", params.cursor);
|
|
1498
|
-
const suffix = qs.toString() ? `?${qs.toString()}` : "";
|
|
1499
|
-
const json = await this.request("GET", `/v1/runs${suffix}`);
|
|
1500
|
-
return listRunsResponseSchema.parse(json);
|
|
1501
|
-
};
|
|
1502
|
-
createReview = async (data) => {
|
|
1503
|
-
const json = await this.request("POST", "/v1/reviews", data);
|
|
1504
|
-
return createReviewResponseSchema.parse(json);
|
|
1505
|
-
};
|
|
1506
|
-
getFundingUrl = async (amount) => {
|
|
1507
|
-
try {
|
|
1508
|
-
const qs = amount ? `?amount=${encodeURIComponent(amount)}` : "";
|
|
1509
|
-
const json = await this.request("GET", `/v1/wallet/fund-url${qs}`);
|
|
1510
|
-
const parsed = z3.object({ url: z3.string() }).parse(json);
|
|
1511
|
-
return parsed.url;
|
|
1512
|
-
} catch {
|
|
1513
|
-
return null;
|
|
1514
|
-
}
|
|
1515
|
-
};
|
|
1516
|
-
};
|
|
1517
|
-
|
|
1518
1868
|
// src/services/payment-service.ts
|
|
1519
1869
|
import {
|
|
1520
1870
|
adaptViemWallet,
|
|
@@ -1821,7 +2171,7 @@ var PaymentService = class {
|
|
|
1821
2171
|
};
|
|
1822
2172
|
|
|
1823
2173
|
// src/services/state-service.ts
|
|
1824
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as
|
|
2174
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
1825
2175
|
import { join as join4 } from "path";
|
|
1826
2176
|
var StateService = class {
|
|
1827
2177
|
constructor(zeroDir) {
|
|
@@ -1836,7 +2186,7 @@ var StateService = class {
|
|
|
1836
2186
|
loadLastSearch = () => {
|
|
1837
2187
|
try {
|
|
1838
2188
|
if (!existsSync5(this.lastSearchPath)) return null;
|
|
1839
|
-
const raw =
|
|
2189
|
+
const raw = readFileSync7(this.lastSearchPath, "utf8");
|
|
1840
2190
|
return JSON.parse(raw);
|
|
1841
2191
|
} catch {
|
|
1842
2192
|
return null;
|
|
@@ -1880,7 +2230,7 @@ var getServices = (env) => {
|
|
|
1880
2230
|
if (!privateKey) {
|
|
1881
2231
|
try {
|
|
1882
2232
|
if (existsSync6(configPath)) {
|
|
1883
|
-
const config = JSON.parse(
|
|
2233
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1884
2234
|
if (typeof config.privateKey === "string") {
|
|
1885
2235
|
privateKey = config.privateKey;
|
|
1886
2236
|
}
|
|
@@ -1892,7 +2242,7 @@ var getServices = (env) => {
|
|
|
1892
2242
|
let lowBalanceWarning = 1;
|
|
1893
2243
|
try {
|
|
1894
2244
|
if (existsSync6(configPath)) {
|
|
1895
|
-
const config = JSON.parse(
|
|
2245
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
1896
2246
|
if (typeof config.lowBalanceWarning === "number") {
|
|
1897
2247
|
lowBalanceWarning = config.lowBalanceWarning;
|
|
1898
2248
|
}
|