@g0hub/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +268 -0
- package/dist/index.js +3406 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3406 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/lib/ui.ts
|
|
13
|
+
var ui_exports = {};
|
|
14
|
+
__export(ui_exports, {
|
|
15
|
+
banner: () => banner,
|
|
16
|
+
c: () => c,
|
|
17
|
+
coolGradient: () => coolGradient,
|
|
18
|
+
createTable: () => createTable,
|
|
19
|
+
formatDate: () => formatDate,
|
|
20
|
+
formatPrice: () => formatPrice,
|
|
21
|
+
formatRating: () => formatRating,
|
|
22
|
+
formatRepScore: () => formatRepScore,
|
|
23
|
+
formatStatus: () => formatStatus,
|
|
24
|
+
g0Gradient: () => g0Gradient,
|
|
25
|
+
infoBox: () => infoBox,
|
|
26
|
+
section: () => section,
|
|
27
|
+
showError: () => showError,
|
|
28
|
+
showMotd: () => showMotd,
|
|
29
|
+
showSuccess: () => showSuccess,
|
|
30
|
+
spin: () => spin
|
|
31
|
+
});
|
|
32
|
+
import chalk from "chalk";
|
|
33
|
+
import gradient from "gradient-string";
|
|
34
|
+
import figlet from "figlet";
|
|
35
|
+
import ora from "ora";
|
|
36
|
+
import Table from "cli-table3";
|
|
37
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
38
|
+
import { homedir } from "os";
|
|
39
|
+
import { join } from "path";
|
|
40
|
+
function banner() {
|
|
41
|
+
const art = figlet.textSync("g0", {
|
|
42
|
+
font: "ANSI Shadow",
|
|
43
|
+
horizontalLayout: "fitted"
|
|
44
|
+
});
|
|
45
|
+
console.log(g0Gradient.multiline(art));
|
|
46
|
+
console.log(
|
|
47
|
+
c.muted(" AI Agent Marketplace") + c.dim(" \u2014 ") + c.warm("hire agents, get things done")
|
|
48
|
+
);
|
|
49
|
+
showMotd().catch(() => {
|
|
50
|
+
});
|
|
51
|
+
console.log();
|
|
52
|
+
}
|
|
53
|
+
function ensureCacheDir() {
|
|
54
|
+
if (!existsSync(BANNER_CACHE_DIR)) {
|
|
55
|
+
mkdirSync(BANNER_CACHE_DIR, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function readBannerCache() {
|
|
59
|
+
try {
|
|
60
|
+
if (existsSync(BANNER_CACHE_FILE)) {
|
|
61
|
+
const data = JSON.parse(readFileSync(BANNER_CACHE_FILE, "utf-8"));
|
|
62
|
+
if (Date.now() - data.fetchedAt < BANNER_CACHE_TTL) return data;
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
function writeBannerCache(data) {
|
|
69
|
+
try {
|
|
70
|
+
ensureCacheDir();
|
|
71
|
+
writeFileSync(BANNER_CACHE_FILE, JSON.stringify(data));
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function renderBannerLine(data) {
|
|
76
|
+
const icon = data.style === "promo" ? "\u2728" : data.style === "update" ? "\u{1F680}" : data.style === "warning" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
|
|
77
|
+
const color = data.style === "promo" ? c.pink : data.style === "update" ? c.cool : data.style === "warning" ? c.warn : c.muted;
|
|
78
|
+
let line = ` ${icon} ${color(data.content)}`;
|
|
79
|
+
if (data.url) line += c.dim(` \u2192 ${data.url}`);
|
|
80
|
+
return line;
|
|
81
|
+
}
|
|
82
|
+
async function fetchBannerRemote(cached) {
|
|
83
|
+
try {
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timer = setTimeout(() => controller.abort(), BANNER_FETCH_TIMEOUT);
|
|
86
|
+
const headers = { "User-Agent": "@g0hub/cli/1.0.0" };
|
|
87
|
+
if (cached?.etag) headers["If-None-Match"] = cached.etag;
|
|
88
|
+
const res = await fetch(BANNER_API_URL, { signal: controller.signal, headers });
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
if (res.status === 304 && cached) {
|
|
91
|
+
const refreshed = { ...cached, fetchedAt: Date.now() };
|
|
92
|
+
writeBannerCache(refreshed);
|
|
93
|
+
return refreshed;
|
|
94
|
+
}
|
|
95
|
+
if (!res.ok) return null;
|
|
96
|
+
const body = await res.json();
|
|
97
|
+
if (!body.content) return null;
|
|
98
|
+
const banner2 = {
|
|
99
|
+
content: body.content,
|
|
100
|
+
style: body.style || "info",
|
|
101
|
+
url: body.url,
|
|
102
|
+
fetchedAt: Date.now(),
|
|
103
|
+
etag: res.headers.get("etag") || void 0
|
|
104
|
+
};
|
|
105
|
+
writeBannerCache(banner2);
|
|
106
|
+
return banner2;
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function showMotd() {
|
|
112
|
+
const cached = readBannerCache();
|
|
113
|
+
if (cached) {
|
|
114
|
+
console.log(renderBannerLine(cached));
|
|
115
|
+
}
|
|
116
|
+
fetchBannerRemote(cached).then((fresh) => {
|
|
117
|
+
if (!cached && fresh) {
|
|
118
|
+
console.log(renderBannerLine(fresh));
|
|
119
|
+
}
|
|
120
|
+
}).catch(() => {
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function spin(text) {
|
|
124
|
+
return ora({ text, color: "yellow", spinner: "dots12" }).start();
|
|
125
|
+
}
|
|
126
|
+
function createTable(head, colWidths) {
|
|
127
|
+
return new Table({
|
|
128
|
+
head: head.map((h) => c.warm.bold(h)),
|
|
129
|
+
...colWidths ? { colWidths } : {},
|
|
130
|
+
chars: {
|
|
131
|
+
top: "\u2500",
|
|
132
|
+
"top-mid": "\u252C",
|
|
133
|
+
"top-left": "\u250C",
|
|
134
|
+
"top-right": "\u2510",
|
|
135
|
+
bottom: "\u2500",
|
|
136
|
+
"bottom-mid": "\u2534",
|
|
137
|
+
"bottom-left": "\u2514",
|
|
138
|
+
"bottom-right": "\u2518",
|
|
139
|
+
left: "\u2502",
|
|
140
|
+
"left-mid": "\u251C",
|
|
141
|
+
mid: "\u2500",
|
|
142
|
+
"mid-mid": "\u253C",
|
|
143
|
+
right: "\u2502",
|
|
144
|
+
"right-mid": "\u2524",
|
|
145
|
+
middle: "\u2502"
|
|
146
|
+
},
|
|
147
|
+
style: {
|
|
148
|
+
head: [],
|
|
149
|
+
border: ["gray"],
|
|
150
|
+
compact: false
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
function formatPrice(price, currency = "USDC") {
|
|
155
|
+
const n = typeof price === "string" ? parseFloat(price) : price;
|
|
156
|
+
return c.bold(`$${n.toFixed(n % 1 === 0 ? 0 : 2)} ${c.dim(currency)}`);
|
|
157
|
+
}
|
|
158
|
+
function formatRating(rating, count) {
|
|
159
|
+
const stars = "\u2605".repeat(Math.round(rating)) + "\u2606".repeat(5 - Math.round(rating));
|
|
160
|
+
const color = rating >= 4 ? c.warm : rating >= 3 ? c.warn : c.muted;
|
|
161
|
+
return color(stars + ` ${rating.toFixed(1)}`) + (count !== void 0 ? c.dim(` (${count})`) : "");
|
|
162
|
+
}
|
|
163
|
+
function formatRepScore(score) {
|
|
164
|
+
if (score == null) return c.muted("\u2014");
|
|
165
|
+
if (score >= 90) return chalk.bgHex("#00E676").hex("#000").bold(` ${score} `);
|
|
166
|
+
if (score >= 75) return chalk.bgHex("#4CC9F0").hex("#000").bold(` ${score} `);
|
|
167
|
+
if (score >= 50) return chalk.bgHex("#FFB300").hex("#000").bold(` ${score} `);
|
|
168
|
+
return chalk.bgGray.white.bold(` ${score} `);
|
|
169
|
+
}
|
|
170
|
+
function formatStatus(status) {
|
|
171
|
+
const s = status.toUpperCase();
|
|
172
|
+
switch (s) {
|
|
173
|
+
case "ACTIVE":
|
|
174
|
+
return c.success.bold("\u25CF ACTIVE");
|
|
175
|
+
case "BUSY":
|
|
176
|
+
return c.warn.bold("\u25CF BUSY");
|
|
177
|
+
case "COMPLETED":
|
|
178
|
+
return c.success("\u2713 COMPLETED");
|
|
179
|
+
case "EXECUTING":
|
|
180
|
+
return c.cool("\u27F3 EXECUTING");
|
|
181
|
+
case "CREATED":
|
|
182
|
+
case "MATCHING":
|
|
183
|
+
return c.warn("\u25CC " + s);
|
|
184
|
+
case "DELIVERED":
|
|
185
|
+
return c.cool("\u{1F4E6} DELIVERED");
|
|
186
|
+
case "DISPUTED":
|
|
187
|
+
return c.err.bold("\u26A1 DISPUTED");
|
|
188
|
+
case "PENDING":
|
|
189
|
+
case "PENDING_VERIFICATION":
|
|
190
|
+
return c.warn("\u25CC PENDING");
|
|
191
|
+
case "OFFLINE":
|
|
192
|
+
return c.muted("\u25CF OFFLINE");
|
|
193
|
+
case "FAILED":
|
|
194
|
+
case "CANCELLED":
|
|
195
|
+
return c.err("\u2717 " + s);
|
|
196
|
+
default:
|
|
197
|
+
return c.muted(s);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function formatDate(dateStr) {
|
|
201
|
+
const d = new Date(dateStr);
|
|
202
|
+
const now = /* @__PURE__ */ new Date();
|
|
203
|
+
const diff = now.getTime() - d.getTime();
|
|
204
|
+
const mins = Math.floor(diff / 6e4);
|
|
205
|
+
if (mins < 1) return c.muted("just now");
|
|
206
|
+
if (mins < 60) return c.muted(`${mins}m ago`);
|
|
207
|
+
const hrs = Math.floor(mins / 60);
|
|
208
|
+
if (hrs < 24) return c.muted(`${hrs}h ago`);
|
|
209
|
+
const days = Math.floor(hrs / 24);
|
|
210
|
+
if (days < 7) return c.muted(`${days}d ago`);
|
|
211
|
+
return c.muted(
|
|
212
|
+
d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
function infoBox(title, lines) {
|
|
216
|
+
const width = 60;
|
|
217
|
+
const border = c.muted("\u2502");
|
|
218
|
+
console.log(c.muted("\u250C" + "\u2500".repeat(width) + "\u2510"));
|
|
219
|
+
console.log(border + " " + c.warm.bold(title).padEnd(width + 9) + border);
|
|
220
|
+
console.log(c.muted("\u251C" + "\u2500".repeat(width) + "\u2524"));
|
|
221
|
+
for (const line of lines) {
|
|
222
|
+
const stripped = line.replace(/\x1B\[\d+m/g, "");
|
|
223
|
+
const pad = width - stripped.length;
|
|
224
|
+
console.log(border + " " + line + " ".repeat(Math.max(0, pad)) + border);
|
|
225
|
+
}
|
|
226
|
+
console.log(c.muted("\u2514" + "\u2500".repeat(width) + "\u2518"));
|
|
227
|
+
}
|
|
228
|
+
function showError(err) {
|
|
229
|
+
if (err instanceof Error) {
|
|
230
|
+
console.error(c.err.bold("\n \u2717 Error: ") + chalk.white(err.message));
|
|
231
|
+
if ("status" in err) {
|
|
232
|
+
console.error(c.muted(` HTTP ${err.status}`));
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
console.error(c.err.bold("\n \u2717 ") + String(err));
|
|
236
|
+
}
|
|
237
|
+
console.log();
|
|
238
|
+
}
|
|
239
|
+
function showSuccess(msg) {
|
|
240
|
+
console.log(c.success.bold("\n \u2713 ") + chalk.white(msg) + "\n");
|
|
241
|
+
}
|
|
242
|
+
function section(title) {
|
|
243
|
+
console.log("\n" + c.warm.bold(" " + title));
|
|
244
|
+
console.log(c.muted(" " + "\u2500".repeat(title.length + 2)) + "\n");
|
|
245
|
+
}
|
|
246
|
+
var WARM, PINK, COOL, SUCCESS, WARN, ERR, c, g0Gradient, coolGradient, BANNER_CACHE_DIR, BANNER_CACHE_FILE, BANNER_CACHE_TTL, BANNER_FETCH_TIMEOUT, BANNER_API_URL;
|
|
247
|
+
var init_ui = __esm({
|
|
248
|
+
"src/lib/ui.ts"() {
|
|
249
|
+
"use strict";
|
|
250
|
+
WARM = "#FF6B35";
|
|
251
|
+
PINK = "#FF3CAC";
|
|
252
|
+
COOL = "#4CC9F0";
|
|
253
|
+
SUCCESS = "#00E676";
|
|
254
|
+
WARN = "#FFB300";
|
|
255
|
+
ERR = "#FF5252";
|
|
256
|
+
c = {
|
|
257
|
+
warm: chalk.hex(WARM),
|
|
258
|
+
pink: chalk.hex(PINK),
|
|
259
|
+
cool: chalk.hex(COOL),
|
|
260
|
+
success: chalk.hex(SUCCESS),
|
|
261
|
+
warn: chalk.hex(WARN),
|
|
262
|
+
err: chalk.hex(ERR),
|
|
263
|
+
muted: chalk.gray,
|
|
264
|
+
bold: chalk.bold,
|
|
265
|
+
dim: chalk.dim
|
|
266
|
+
};
|
|
267
|
+
g0Gradient = gradient([WARM, PINK]);
|
|
268
|
+
coolGradient = gradient([COOL, "#7B61FF"]);
|
|
269
|
+
BANNER_CACHE_DIR = join(homedir(), ".g0", "cache");
|
|
270
|
+
BANNER_CACHE_FILE = join(BANNER_CACHE_DIR, "motd.json");
|
|
271
|
+
BANNER_CACHE_TTL = 6 * 60 * 60 * 1e3;
|
|
272
|
+
BANNER_FETCH_TIMEOUT = 1500;
|
|
273
|
+
BANNER_API_URL = "https://g0hub.com/api/v1/cli/motd";
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// src/lib/config.ts
|
|
278
|
+
var config_exports = {};
|
|
279
|
+
__export(config_exports, {
|
|
280
|
+
clearAuth: () => clearAuth,
|
|
281
|
+
getAllConfig: () => getAllConfig,
|
|
282
|
+
getApiKey: () => getApiKey,
|
|
283
|
+
getApiUrl: () => getApiUrl,
|
|
284
|
+
getConfigPath: () => getConfigPath,
|
|
285
|
+
getConfigValue: () => getConfigValue,
|
|
286
|
+
getUserInfo: () => getUserInfo,
|
|
287
|
+
isAuthenticated: () => isAuthenticated,
|
|
288
|
+
setAuth: () => setAuth,
|
|
289
|
+
setConfigValue: () => setConfigValue
|
|
290
|
+
});
|
|
291
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
292
|
+
import { homedir as homedir2 } from "os";
|
|
293
|
+
import { join as join2 } from "path";
|
|
294
|
+
function ensureDir() {
|
|
295
|
+
if (!existsSync2(CONFIG_DIR)) {
|
|
296
|
+
mkdirSync2(CONFIG_DIR, { recursive: true });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function load() {
|
|
300
|
+
ensureDir();
|
|
301
|
+
try {
|
|
302
|
+
if (existsSync2(CONFIG_FILE)) {
|
|
303
|
+
return { ...DEFAULTS, ...JSON.parse(readFileSync2(CONFIG_FILE, "utf-8")) };
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
return { ...DEFAULTS };
|
|
308
|
+
}
|
|
309
|
+
function save(config) {
|
|
310
|
+
ensureDir();
|
|
311
|
+
writeFileSync2(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
312
|
+
}
|
|
313
|
+
function getApiKey() {
|
|
314
|
+
return load().apiKey;
|
|
315
|
+
}
|
|
316
|
+
function getApiUrl() {
|
|
317
|
+
return load().apiUrl;
|
|
318
|
+
}
|
|
319
|
+
function isAuthenticated() {
|
|
320
|
+
return !!load().apiKey;
|
|
321
|
+
}
|
|
322
|
+
function setAuth(data) {
|
|
323
|
+
const config = load();
|
|
324
|
+
config.apiKey = data.apiKey;
|
|
325
|
+
config.userId = data.userId;
|
|
326
|
+
config.email = data.email;
|
|
327
|
+
config.name = data.name;
|
|
328
|
+
config.accountType = data.accountType;
|
|
329
|
+
save(config);
|
|
330
|
+
}
|
|
331
|
+
function clearAuth() {
|
|
332
|
+
const config = load();
|
|
333
|
+
config.apiKey = "";
|
|
334
|
+
config.userId = "";
|
|
335
|
+
config.email = "";
|
|
336
|
+
config.name = "";
|
|
337
|
+
config.accountType = "";
|
|
338
|
+
save(config);
|
|
339
|
+
}
|
|
340
|
+
function getUserInfo() {
|
|
341
|
+
const config = load();
|
|
342
|
+
return {
|
|
343
|
+
userId: config.userId,
|
|
344
|
+
email: config.email,
|
|
345
|
+
name: config.name,
|
|
346
|
+
accountType: config.accountType
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function getConfigValue(key) {
|
|
350
|
+
return load()[key];
|
|
351
|
+
}
|
|
352
|
+
function setConfigValue(key, value) {
|
|
353
|
+
const config = load();
|
|
354
|
+
if (key in DEFAULTS) {
|
|
355
|
+
config[key] = value;
|
|
356
|
+
save(config);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function getConfigPath() {
|
|
360
|
+
return CONFIG_FILE;
|
|
361
|
+
}
|
|
362
|
+
function getAllConfig() {
|
|
363
|
+
return load();
|
|
364
|
+
}
|
|
365
|
+
var CONFIG_DIR, CONFIG_FILE, DEFAULTS;
|
|
366
|
+
var init_config = __esm({
|
|
367
|
+
"src/lib/config.ts"() {
|
|
368
|
+
"use strict";
|
|
369
|
+
CONFIG_DIR = join2(homedir2(), ".g0");
|
|
370
|
+
CONFIG_FILE = join2(CONFIG_DIR, "config.json");
|
|
371
|
+
DEFAULTS = {
|
|
372
|
+
apiKey: "",
|
|
373
|
+
apiUrl: "https://g0hub.com",
|
|
374
|
+
userId: "",
|
|
375
|
+
email: "",
|
|
376
|
+
name: "",
|
|
377
|
+
accountType: "",
|
|
378
|
+
theme: "dark"
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// src/lib/api.ts
|
|
384
|
+
async function request(path, options = {}) {
|
|
385
|
+
const { method = "GET", body, query, auth = true } = options;
|
|
386
|
+
const baseUrl = getApiUrl();
|
|
387
|
+
let url = `${baseUrl}/api/v1${path}`;
|
|
388
|
+
if (query) {
|
|
389
|
+
const params = new URLSearchParams();
|
|
390
|
+
for (const [k, v] of Object.entries(query)) {
|
|
391
|
+
if (v !== void 0 && v !== "") params.set(k, v);
|
|
392
|
+
}
|
|
393
|
+
const qs = params.toString();
|
|
394
|
+
if (qs) url += `?${qs}`;
|
|
395
|
+
}
|
|
396
|
+
const headers = {
|
|
397
|
+
"Content-Type": "application/json",
|
|
398
|
+
"User-Agent": "@g0hub/cli/1.0.0"
|
|
399
|
+
};
|
|
400
|
+
if (auth) {
|
|
401
|
+
const apiKey = getApiKey();
|
|
402
|
+
if (!apiKey) {
|
|
403
|
+
throw new ApiError(
|
|
404
|
+
401,
|
|
405
|
+
'Not authenticated. Run "g0 login" or "g0 auth:key <api-key>" first.'
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
409
|
+
}
|
|
410
|
+
const res = await fetch(url, {
|
|
411
|
+
method,
|
|
412
|
+
headers,
|
|
413
|
+
body: body ? JSON.stringify(body) : void 0
|
|
414
|
+
});
|
|
415
|
+
if (!res.ok) {
|
|
416
|
+
let errBody;
|
|
417
|
+
try {
|
|
418
|
+
errBody = await res.json();
|
|
419
|
+
} catch {
|
|
420
|
+
errBody = await res.text();
|
|
421
|
+
}
|
|
422
|
+
const msg = typeof errBody === "object" && errBody && "error" in errBody ? errBody.error : `HTTP ${res.status}`;
|
|
423
|
+
throw new ApiError(res.status, msg, errBody);
|
|
424
|
+
}
|
|
425
|
+
if (res.status === 204) return void 0;
|
|
426
|
+
return await res.json();
|
|
427
|
+
}
|
|
428
|
+
var ApiError, api;
|
|
429
|
+
var init_api = __esm({
|
|
430
|
+
"src/lib/api.ts"() {
|
|
431
|
+
"use strict";
|
|
432
|
+
init_config();
|
|
433
|
+
ApiError = class extends Error {
|
|
434
|
+
constructor(status, message, body) {
|
|
435
|
+
super(message);
|
|
436
|
+
this.status = status;
|
|
437
|
+
this.body = body;
|
|
438
|
+
this.name = "ApiError";
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
api = {
|
|
442
|
+
get: (path, query, auth = true) => request(path, { method: "GET", query, auth }),
|
|
443
|
+
post: (path, body, auth = true) => request(path, { method: "POST", body, auth }),
|
|
444
|
+
put: (path, body) => request(path, { method: "PUT", body }),
|
|
445
|
+
patch: (path, body) => request(path, { method: "PATCH", body }),
|
|
446
|
+
delete: (path) => request(path, { method: "DELETE" })
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// src/commands/auth.ts
|
|
452
|
+
var auth_exports = {};
|
|
453
|
+
__export(auth_exports, {
|
|
454
|
+
changePassword: () => changePassword,
|
|
455
|
+
forgotPassword: () => forgotPassword,
|
|
456
|
+
login: () => login,
|
|
457
|
+
logout: () => logout,
|
|
458
|
+
register: () => register,
|
|
459
|
+
resendVerification: () => resendVerification,
|
|
460
|
+
resetPassword: () => resetPassword,
|
|
461
|
+
setApiKey: () => setApiKey,
|
|
462
|
+
setConfigValue: () => setConfigValue2,
|
|
463
|
+
showConfig: () => showConfig,
|
|
464
|
+
whoami: () => whoami
|
|
465
|
+
});
|
|
466
|
+
import { input, password, select } from "@inquirer/prompts";
|
|
467
|
+
async function login() {
|
|
468
|
+
banner();
|
|
469
|
+
console.log(c.warm.bold(" Sign in to g0\n"));
|
|
470
|
+
const email = await input({
|
|
471
|
+
message: "Email",
|
|
472
|
+
validate: (v) => v.includes("@") ? true : "Enter a valid email"
|
|
473
|
+
});
|
|
474
|
+
const pass = await password({ message: "Password" });
|
|
475
|
+
const s = spin("Authenticating...");
|
|
476
|
+
try {
|
|
477
|
+
const res = await api.post("/auth/login", { email, password: pass, source: "cli" }, false);
|
|
478
|
+
if (!res.token) {
|
|
479
|
+
s.fail("Login succeeded but no API key was returned");
|
|
480
|
+
console.log(c.muted('\n Use "g0 auth:key <api-key>" to authenticate with an existing key.\n'));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
setAuth({
|
|
484
|
+
apiKey: res.token,
|
|
485
|
+
userId: res.id,
|
|
486
|
+
email: res.email,
|
|
487
|
+
name: res.name || "",
|
|
488
|
+
accountType: res.accountType
|
|
489
|
+
});
|
|
490
|
+
s.succeed(c.success("Authenticated!"));
|
|
491
|
+
showSuccess(`Welcome back, ${c.warm.bold(res.name || res.email)}!`);
|
|
492
|
+
} catch (err) {
|
|
493
|
+
s.fail("Authentication failed");
|
|
494
|
+
showError(err);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
async function register() {
|
|
498
|
+
banner();
|
|
499
|
+
console.log(c.warm.bold(" Create a g0 account\n"));
|
|
500
|
+
const name = await input({ message: "Name" });
|
|
501
|
+
const email = await input({
|
|
502
|
+
message: "Email",
|
|
503
|
+
validate: (v) => v.includes("@") ? true : "Enter a valid email"
|
|
504
|
+
});
|
|
505
|
+
const pass = await password({
|
|
506
|
+
message: "Password",
|
|
507
|
+
validate: (v) => v.length >= 8 ? true : "Password must be at least 8 characters"
|
|
508
|
+
});
|
|
509
|
+
const accountType = await select({
|
|
510
|
+
message: "Account type",
|
|
511
|
+
choices: [
|
|
512
|
+
{
|
|
513
|
+
name: "Buyer \u2014 I want to hire AI agents",
|
|
514
|
+
value: "BUYER"
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
name: "Agentrepreneur \u2014 I build and sell AI agents",
|
|
518
|
+
value: "AGENTREPRENEUR"
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
name: "Both \u2014 I hire and sell agents",
|
|
522
|
+
value: "BOTH"
|
|
523
|
+
}
|
|
524
|
+
]
|
|
525
|
+
});
|
|
526
|
+
const s = spin("Creating account...");
|
|
527
|
+
try {
|
|
528
|
+
const res = await api.post("/auth/register", { name, email, password: pass, accountType, source: "cli" }, false);
|
|
529
|
+
if (!res.token) {
|
|
530
|
+
s.fail("Account created but no API key was returned");
|
|
531
|
+
console.log(c.muted('\n Use "g0 auth:key <api-key>" to authenticate with an existing key.\n'));
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
setAuth({
|
|
535
|
+
apiKey: res.token,
|
|
536
|
+
userId: res.user.id,
|
|
537
|
+
email: res.user.email,
|
|
538
|
+
name: res.user.name || "",
|
|
539
|
+
accountType: res.user.accountType
|
|
540
|
+
});
|
|
541
|
+
s.succeed(c.success("Account created!"));
|
|
542
|
+
showSuccess(
|
|
543
|
+
`Welcome to g0, ${c.warm.bold(name)}! You're ready to ${accountType === "BUYER" ? "hire AI agents" : accountType === "AGENTREPRENEUR" ? "sell your AI agents" : "hire and sell AI agents"}.`
|
|
544
|
+
);
|
|
545
|
+
} catch (err) {
|
|
546
|
+
s.fail("Registration failed");
|
|
547
|
+
showError(err);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async function logout() {
|
|
551
|
+
if (!isAuthenticated()) {
|
|
552
|
+
console.log(c.muted("\n Not logged in.\n"));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const info = getUserInfo();
|
|
556
|
+
clearAuth();
|
|
557
|
+
showSuccess(`Signed out${info.email ? ` from ${c.muted(info.email)}` : ""}.`);
|
|
558
|
+
}
|
|
559
|
+
async function whoami() {
|
|
560
|
+
if (!isAuthenticated()) {
|
|
561
|
+
console.log(
|
|
562
|
+
c.warn("\n Not authenticated.") + c.muted(' Run "g0 login" or "g0 register" to sign in.\n')
|
|
563
|
+
);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
const info = getUserInfo();
|
|
567
|
+
const s = spin("Fetching profile...");
|
|
568
|
+
try {
|
|
569
|
+
const res = await api.get("/user/profile");
|
|
570
|
+
const profile = res.user;
|
|
571
|
+
s.stop();
|
|
572
|
+
const profileLines = [
|
|
573
|
+
`${c.muted("Name:")} ${c.bold(profile.name || "\u2014")}`,
|
|
574
|
+
`${c.muted("Email:")} ${profile.email}`
|
|
575
|
+
];
|
|
576
|
+
if (profile.bio) {
|
|
577
|
+
profileLines.push(`${c.muted("Bio:")} ${profile.bio}`);
|
|
578
|
+
}
|
|
579
|
+
profileLines.push(
|
|
580
|
+
`${c.muted("Account:")} ${c.warm(profile.accountType)}`,
|
|
581
|
+
`${c.muted("Balance:")} ${c.success.bold("$" + parseFloat(profile.creditBalance).toFixed(2))} ${c.dim("USDC")}`,
|
|
582
|
+
`${c.muted("User ID:")} ${c.dim(profile.id)}`,
|
|
583
|
+
`${c.muted("Since:")} ${new Date(profile.createdAt).toLocaleDateString()}`
|
|
584
|
+
);
|
|
585
|
+
infoBox("Your Profile", profileLines);
|
|
586
|
+
} catch {
|
|
587
|
+
s.stop();
|
|
588
|
+
infoBox("Your Profile (cached)", [
|
|
589
|
+
`${c.muted("Name:")} ${c.bold(info.name || "\u2014")}`,
|
|
590
|
+
`${c.muted("Email:")} ${info.email}`,
|
|
591
|
+
`${c.muted("Account:")} ${c.warm(info.accountType)}`,
|
|
592
|
+
`${c.muted("User ID:")} ${c.dim(info.userId)}`
|
|
593
|
+
]);
|
|
594
|
+
}
|
|
595
|
+
console.log();
|
|
596
|
+
}
|
|
597
|
+
async function forgotPassword() {
|
|
598
|
+
banner();
|
|
599
|
+
console.log(c.warm.bold(" Reset your password\n"));
|
|
600
|
+
const email = await input({
|
|
601
|
+
message: "Email",
|
|
602
|
+
validate: (v) => v.includes("@") ? true : "Enter a valid email"
|
|
603
|
+
});
|
|
604
|
+
const s = spin("Sending reset email...");
|
|
605
|
+
try {
|
|
606
|
+
const res = await api.post(
|
|
607
|
+
"/auth/forgot-password",
|
|
608
|
+
{ email },
|
|
609
|
+
false
|
|
610
|
+
);
|
|
611
|
+
s.succeed(c.success("Done"));
|
|
612
|
+
showSuccess(res.message);
|
|
613
|
+
} catch (err) {
|
|
614
|
+
s.fail("Request failed");
|
|
615
|
+
showError(err);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async function resetPassword() {
|
|
619
|
+
banner();
|
|
620
|
+
console.log(c.warm.bold(" Set a new password\n"));
|
|
621
|
+
const token = await input({ message: "Reset token" });
|
|
622
|
+
const email = await input({
|
|
623
|
+
message: "Email",
|
|
624
|
+
validate: (v) => v.includes("@") ? true : "Enter a valid email"
|
|
625
|
+
});
|
|
626
|
+
const pass = await password({
|
|
627
|
+
message: "New password",
|
|
628
|
+
validate: (v) => v.length >= 8 ? true : "Password must be at least 8 characters"
|
|
629
|
+
});
|
|
630
|
+
const s = spin("Resetting password...");
|
|
631
|
+
try {
|
|
632
|
+
const res = await api.post(
|
|
633
|
+
"/auth/reset-password",
|
|
634
|
+
{ token, email, password: pass },
|
|
635
|
+
false
|
|
636
|
+
);
|
|
637
|
+
s.succeed(c.success("Done"));
|
|
638
|
+
showSuccess(res.message);
|
|
639
|
+
} catch (err) {
|
|
640
|
+
s.fail("Reset failed");
|
|
641
|
+
showError(err);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
async function resendVerification() {
|
|
645
|
+
banner();
|
|
646
|
+
console.log(c.warm.bold(" Resend verification email\n"));
|
|
647
|
+
const email = await input({
|
|
648
|
+
message: "Email",
|
|
649
|
+
validate: (v) => v.includes("@") ? true : "Enter a valid email"
|
|
650
|
+
});
|
|
651
|
+
const s = spin("Sending verification email...");
|
|
652
|
+
try {
|
|
653
|
+
const res = await api.post(
|
|
654
|
+
"/auth/resend-verification",
|
|
655
|
+
{ email },
|
|
656
|
+
false
|
|
657
|
+
);
|
|
658
|
+
s.succeed(c.success("Done"));
|
|
659
|
+
showSuccess(res.message);
|
|
660
|
+
} catch (err) {
|
|
661
|
+
s.fail("Request failed");
|
|
662
|
+
showError(err);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
async function changePassword() {
|
|
666
|
+
banner();
|
|
667
|
+
console.log(c.warm.bold(" Change your password\n"));
|
|
668
|
+
const currentPassword = await password({ message: "Current password" });
|
|
669
|
+
const newPassword = await password({
|
|
670
|
+
message: "New password",
|
|
671
|
+
validate: (v) => v.length >= 8 ? true : "Password must be at least 8 characters"
|
|
672
|
+
});
|
|
673
|
+
const s = spin("Updating password...");
|
|
674
|
+
try {
|
|
675
|
+
await api.post("/user/profile/password", {
|
|
676
|
+
currentPassword,
|
|
677
|
+
newPassword
|
|
678
|
+
});
|
|
679
|
+
s.succeed(c.success("Done"));
|
|
680
|
+
showSuccess("Password changed successfully.");
|
|
681
|
+
} catch (err) {
|
|
682
|
+
s.fail("Password change failed");
|
|
683
|
+
showError(err);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async function setApiKey(key) {
|
|
687
|
+
if (!key) {
|
|
688
|
+
const k = await input({ message: "Paste your API key" });
|
|
689
|
+
key = k;
|
|
690
|
+
}
|
|
691
|
+
const s = spin("Validating API key...");
|
|
692
|
+
try {
|
|
693
|
+
setAuth({ apiKey: key, userId: "", email: "", name: "", accountType: "" });
|
|
694
|
+
const res = await api.get("/user/profile");
|
|
695
|
+
const profile = res.user;
|
|
696
|
+
setAuth({
|
|
697
|
+
apiKey: key,
|
|
698
|
+
userId: profile.id,
|
|
699
|
+
email: profile.email,
|
|
700
|
+
name: profile.name || "",
|
|
701
|
+
accountType: profile.accountType
|
|
702
|
+
});
|
|
703
|
+
s.succeed(c.success("API key saved!"));
|
|
704
|
+
showSuccess(`Authenticated as ${c.warm.bold(profile.name || profile.email)}`);
|
|
705
|
+
} catch (err) {
|
|
706
|
+
clearAuth();
|
|
707
|
+
s.fail("Invalid API key");
|
|
708
|
+
showError(err);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
async function showConfig() {
|
|
712
|
+
const conf = getAllConfig();
|
|
713
|
+
infoBox("Configuration", [
|
|
714
|
+
`${c.muted("API URL:")} ${conf.apiUrl}`,
|
|
715
|
+
`${c.muted("API Key:")} ${conf.apiKey ? c.success("\u25CF") + c.muted(" configured") : c.err("\u25CF") + c.muted(" not set")}`,
|
|
716
|
+
`${c.muted("Theme:")} ${conf.theme}`,
|
|
717
|
+
`${c.muted("Config path:")} ${c.dim(getConfigPath())}`
|
|
718
|
+
]);
|
|
719
|
+
console.log();
|
|
720
|
+
}
|
|
721
|
+
async function setConfigValue2(key, value) {
|
|
722
|
+
if (key === "apiUrl" || key === "theme") {
|
|
723
|
+
setConfigValue(key, value);
|
|
724
|
+
showSuccess(`${key} = ${value}`);
|
|
725
|
+
} else {
|
|
726
|
+
showError(
|
|
727
|
+
new Error(`Unknown config key "${key}". Valid keys: apiUrl, theme`)
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
var init_auth = __esm({
|
|
732
|
+
"src/commands/auth.ts"() {
|
|
733
|
+
"use strict";
|
|
734
|
+
init_api();
|
|
735
|
+
init_config();
|
|
736
|
+
init_ui();
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
// src/commands/profile.ts
|
|
741
|
+
var profile_exports = {};
|
|
742
|
+
__export(profile_exports, {
|
|
743
|
+
updateProfile: () => updateProfile,
|
|
744
|
+
viewProfile: () => viewProfile
|
|
745
|
+
});
|
|
746
|
+
import chalk2 from "chalk";
|
|
747
|
+
import { input as input2, editor } from "@inquirer/prompts";
|
|
748
|
+
function requireAuth() {
|
|
749
|
+
if (!isAuthenticated()) {
|
|
750
|
+
console.error(
|
|
751
|
+
c.err.bold("\n \u2717 Not authenticated.") + c.muted('\n Run "g0 login" or "g0 auth:key <key>" first.\n')
|
|
752
|
+
);
|
|
753
|
+
process.exit(1);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
async function viewProfile() {
|
|
757
|
+
requireAuth();
|
|
758
|
+
const s = spin("Loading profile...");
|
|
759
|
+
try {
|
|
760
|
+
const data = await api.get("/user/profile");
|
|
761
|
+
s.stop();
|
|
762
|
+
const u = data.user;
|
|
763
|
+
const lines = [
|
|
764
|
+
`${c.muted("Email")} ${u.email}`,
|
|
765
|
+
`${c.muted("Name")} ${u.name || chalk2.dim("Not set")}`,
|
|
766
|
+
`${c.muted("Bio")} ${u.bio || chalk2.dim("Not set")}`,
|
|
767
|
+
`${c.muted("Role")} ${u.role}`,
|
|
768
|
+
`${c.muted("Type")} ${u.accountType}`,
|
|
769
|
+
`${c.muted("Balance")} $${Number(u.creditBalance).toFixed(2)}`,
|
|
770
|
+
`${c.muted("Joined")} ${new Date(u.createdAt).toLocaleDateString()}`
|
|
771
|
+
];
|
|
772
|
+
if (u.profileOverview) {
|
|
773
|
+
lines.push("");
|
|
774
|
+
lines.push(`${c.muted("Overview")}`);
|
|
775
|
+
const preview = u.profileOverview.length > 200 ? u.profileOverview.slice(0, 200) + "..." : u.profileOverview;
|
|
776
|
+
lines.push(` ${preview}`);
|
|
777
|
+
}
|
|
778
|
+
infoBox("Your Profile", lines);
|
|
779
|
+
if (data.stats) {
|
|
780
|
+
console.log();
|
|
781
|
+
const statLines = [
|
|
782
|
+
`${c.muted("Tasks")} ${data.stats.taskCount}`,
|
|
783
|
+
`${c.muted("Listings")} ${data.stats.agentCount}`,
|
|
784
|
+
`${c.muted("Spent")} $${Number(data.stats.totalSpent).toFixed(2)}`
|
|
785
|
+
];
|
|
786
|
+
infoBox("Stats", statLines);
|
|
787
|
+
}
|
|
788
|
+
} catch (err) {
|
|
789
|
+
s.stop();
|
|
790
|
+
showError(err);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
async function updateProfile() {
|
|
794
|
+
requireAuth();
|
|
795
|
+
const s = spin("Loading current profile...");
|
|
796
|
+
let current;
|
|
797
|
+
try {
|
|
798
|
+
const data = await api.get("/user/profile");
|
|
799
|
+
current = data.user;
|
|
800
|
+
s.stop();
|
|
801
|
+
} catch (err) {
|
|
802
|
+
s.stop();
|
|
803
|
+
showError(err);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
console.log(chalk2.bold("\nUpdate your profile (press Enter to keep current value)\n"));
|
|
807
|
+
const name = await input2({
|
|
808
|
+
message: "Display Name",
|
|
809
|
+
default: current.name || void 0
|
|
810
|
+
});
|
|
811
|
+
const bio = await input2({
|
|
812
|
+
message: "Bio (short, max 500 chars)",
|
|
813
|
+
default: current.bio || void 0
|
|
814
|
+
});
|
|
815
|
+
const editOverview = await input2({
|
|
816
|
+
message: "Edit profile overview? (y/N)",
|
|
817
|
+
default: "n"
|
|
818
|
+
});
|
|
819
|
+
let profileOverview;
|
|
820
|
+
if (editOverview.toLowerCase() === "y") {
|
|
821
|
+
profileOverview = await editor({
|
|
822
|
+
message: "Profile Overview (detailed, max 5000 chars)",
|
|
823
|
+
default: current.profileOverview || ""
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
const updates = {};
|
|
827
|
+
if (name && name !== current.name) updates.name = name;
|
|
828
|
+
if (bio !== void 0 && bio !== current.bio) updates.bio = bio;
|
|
829
|
+
if (profileOverview !== void 0 && profileOverview !== current.profileOverview) {
|
|
830
|
+
updates.profileOverview = profileOverview;
|
|
831
|
+
}
|
|
832
|
+
if (Object.keys(updates).length === 0) {
|
|
833
|
+
console.log(chalk2.dim("\nNo changes made."));
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
const s2 = spin("Updating profile...");
|
|
837
|
+
try {
|
|
838
|
+
await api.patch("/user/profile", updates);
|
|
839
|
+
s2.stop();
|
|
840
|
+
showSuccess("Profile updated successfully!");
|
|
841
|
+
} catch (err) {
|
|
842
|
+
s2.stop();
|
|
843
|
+
showError(err);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
var init_profile = __esm({
|
|
847
|
+
"src/commands/profile.ts"() {
|
|
848
|
+
"use strict";
|
|
849
|
+
init_api();
|
|
850
|
+
init_config();
|
|
851
|
+
init_ui();
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
// src/commands/wallet.ts
|
|
856
|
+
var wallet_exports = {};
|
|
857
|
+
__export(wallet_exports, {
|
|
858
|
+
getWallet: () => getWallet
|
|
859
|
+
});
|
|
860
|
+
async function getWallet() {
|
|
861
|
+
const s = spin("Loading wallet...");
|
|
862
|
+
try {
|
|
863
|
+
const res = await api.get("/user/wallet");
|
|
864
|
+
s.stop();
|
|
865
|
+
const balance = parseFloat(res.creditBalance || "0");
|
|
866
|
+
infoBox("Your Wallet", [
|
|
867
|
+
`${c.muted("Balance:")} ${c.success.bold("$" + balance.toFixed(2))} ${c.dim("USDC")}`,
|
|
868
|
+
`${c.muted("EVM Address:")} ${c.dim(res.wallet?.evmAddress || "\u2014")}`,
|
|
869
|
+
`${c.muted("Solana Address:")} ${c.dim(res.wallet?.solanaAddress || "\u2014")}`,
|
|
870
|
+
`${c.muted("Label:")} ${res.wallet?.label || "\u2014"}`,
|
|
871
|
+
`${c.muted("Wallet ID:")} ${c.dim(res.wallet?.id || "\u2014")}`
|
|
872
|
+
]);
|
|
873
|
+
console.log();
|
|
874
|
+
} catch (err) {
|
|
875
|
+
s.fail("Failed to load wallet");
|
|
876
|
+
showError(err);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
var init_wallet = __esm({
|
|
880
|
+
"src/commands/wallet.ts"() {
|
|
881
|
+
"use strict";
|
|
882
|
+
init_api();
|
|
883
|
+
init_ui();
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// src/commands/marketplace.ts
|
|
888
|
+
var marketplace_exports = {};
|
|
889
|
+
__export(marketplace_exports, {
|
|
890
|
+
browse: () => browse,
|
|
891
|
+
search: () => search,
|
|
892
|
+
viewAgent: () => viewAgent,
|
|
893
|
+
viewAgentReviews: () => viewAgentReviews
|
|
894
|
+
});
|
|
895
|
+
import { input as input3, select as select2 } from "@inquirer/prompts";
|
|
896
|
+
async function browse() {
|
|
897
|
+
banner();
|
|
898
|
+
const categories = [
|
|
899
|
+
"ALL",
|
|
900
|
+
"CODING",
|
|
901
|
+
"WEB_DEVELOPMENT",
|
|
902
|
+
"MOBILE_DEVELOPMENT",
|
|
903
|
+
"DATA_SCIENCE",
|
|
904
|
+
"DATA_INTELLIGENCE",
|
|
905
|
+
"DIGITAL_MARKETING",
|
|
906
|
+
"SEO",
|
|
907
|
+
"CONTENT_WRITING",
|
|
908
|
+
"GRAPHIC_DESIGN",
|
|
909
|
+
"VIDEO_GENERATION",
|
|
910
|
+
"AI_ML",
|
|
911
|
+
"CLOUD_COMPUTING",
|
|
912
|
+
"DATABASE_MANAGEMENT",
|
|
913
|
+
"DEVOPS",
|
|
914
|
+
"CYBERSECURITY",
|
|
915
|
+
"PRODUCT_MANAGEMENT",
|
|
916
|
+
"BLOCKCHAIN",
|
|
917
|
+
"RESEARCH",
|
|
918
|
+
"CUSTOMER_SUPPORT",
|
|
919
|
+
"AUTOMATION",
|
|
920
|
+
"API_INTEGRATION",
|
|
921
|
+
"FULL_STACK_TEAM",
|
|
922
|
+
"SALES",
|
|
923
|
+
"HR_RECRUITMENT",
|
|
924
|
+
"VOICE_AGENTS",
|
|
925
|
+
"LEGAL_COMPLIANCE",
|
|
926
|
+
"FINANCE_ACCOUNTING",
|
|
927
|
+
"AUDIO_MUSIC",
|
|
928
|
+
"EDUCATION_TRAINING"
|
|
929
|
+
];
|
|
930
|
+
const category = await select2({
|
|
931
|
+
message: "Browse by category",
|
|
932
|
+
choices: categories.map((cat) => ({
|
|
933
|
+
name: cat === "ALL" ? "All Categories" : cat.replace(/_/g, " "),
|
|
934
|
+
value: cat
|
|
935
|
+
}))
|
|
936
|
+
});
|
|
937
|
+
const sort = await select2({
|
|
938
|
+
message: "Sort by",
|
|
939
|
+
choices: [
|
|
940
|
+
{ name: "Reputation Score", value: "reputation" },
|
|
941
|
+
{ name: "Trending", value: "trending" },
|
|
942
|
+
{ name: "Rating", value: "rating" },
|
|
943
|
+
{ name: "Most Tasks", value: "tasks_completed" },
|
|
944
|
+
{ name: "Price: Low \u2192 High", value: "price_asc" },
|
|
945
|
+
{ name: "Price: High \u2192 Low", value: "price_desc" },
|
|
946
|
+
{ name: "Newest", value: "newest" }
|
|
947
|
+
]
|
|
948
|
+
});
|
|
949
|
+
const query = { sort };
|
|
950
|
+
if (category !== "ALL") query.category = category;
|
|
951
|
+
await listAgents(query);
|
|
952
|
+
}
|
|
953
|
+
async function search(query) {
|
|
954
|
+
if (!query) {
|
|
955
|
+
query = await input3({ message: "Search agents" });
|
|
956
|
+
}
|
|
957
|
+
const s = spin(`Searching for "${query}"...`);
|
|
958
|
+
try {
|
|
959
|
+
const res = await api.get(
|
|
960
|
+
"/marketplace/search",
|
|
961
|
+
{ q: query },
|
|
962
|
+
false
|
|
963
|
+
);
|
|
964
|
+
s.stop();
|
|
965
|
+
if (res.agents.length === 0) {
|
|
966
|
+
console.log(c.warn(`
|
|
967
|
+
No agents found matching "${query}"
|
|
968
|
+
`));
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
section(`${res.agents.length} results for "${query}"`);
|
|
972
|
+
printAgentTable(res.agents);
|
|
973
|
+
} catch (err) {
|
|
974
|
+
s.fail("Search failed");
|
|
975
|
+
showError(err);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async function listAgents(query) {
|
|
979
|
+
const s = spin("Loading marketplace...");
|
|
980
|
+
try {
|
|
981
|
+
const res = await api.get(
|
|
982
|
+
"/marketplace",
|
|
983
|
+
query,
|
|
984
|
+
false
|
|
985
|
+
);
|
|
986
|
+
s.stop();
|
|
987
|
+
if (res.agents.length === 0) {
|
|
988
|
+
console.log(c.warn("\n No agents found.\n"));
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
section(`${res.agents.length} agents`);
|
|
992
|
+
printAgentTable(res.agents);
|
|
993
|
+
const choices = res.agents.map((a) => ({
|
|
994
|
+
name: `${a.name} \u2014 ${a.tagline || a.categories[0]}`,
|
|
995
|
+
value: a.slug
|
|
996
|
+
}));
|
|
997
|
+
choices.push({ name: c.muted("\u2190 Back"), value: "__back" });
|
|
998
|
+
const selected = await select2({
|
|
999
|
+
message: "View agent details",
|
|
1000
|
+
choices
|
|
1001
|
+
});
|
|
1002
|
+
if (selected !== "__back") {
|
|
1003
|
+
await viewAgent(selected);
|
|
1004
|
+
}
|
|
1005
|
+
} catch (err) {
|
|
1006
|
+
s.fail("Failed to load marketplace");
|
|
1007
|
+
showError(err);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
async function viewAgent(slugOrId) {
|
|
1011
|
+
const s = spin("Loading agent...");
|
|
1012
|
+
try {
|
|
1013
|
+
const res = await api.get(
|
|
1014
|
+
`/agents/${slugOrId}`,
|
|
1015
|
+
void 0,
|
|
1016
|
+
false
|
|
1017
|
+
);
|
|
1018
|
+
const agent = res.agent;
|
|
1019
|
+
s.stop();
|
|
1020
|
+
console.log();
|
|
1021
|
+
const verified = agent.isVerified ? c.cool(" \u2713 Verified") : "";
|
|
1022
|
+
console.log(
|
|
1023
|
+
" " + c.warm.bold(agent.name) + verified
|
|
1024
|
+
);
|
|
1025
|
+
console.log(" " + c.muted(agent.tagline || agent.description.slice(0, 100)));
|
|
1026
|
+
console.log();
|
|
1027
|
+
infoBox(agent.name, [
|
|
1028
|
+
`${c.muted("Status:")} ${formatStatus(agent.status)}`,
|
|
1029
|
+
`${c.muted("Price:")} ${formatPrice(agent.basePrice, agent.currency)}`,
|
|
1030
|
+
`${c.muted("Rating:")} ${formatRating(agent.avgRating, agent.reviewCount)}`,
|
|
1031
|
+
`${c.muted("Rep Score:")} ${formatRepScore(agent.reputationScore)}`,
|
|
1032
|
+
`${c.muted("Tasks Done:")} ${c.bold(String(agent.tasksCompleted))}`,
|
|
1033
|
+
`${c.muted("Success:")} ${agent.successRate.toFixed(1)}%`,
|
|
1034
|
+
`${c.muted("Avg Response:")} ${agent.avgResponseMs < 6e4 ? `${(agent.avgResponseMs / 1e3).toFixed(1)}s` : `${Math.round(agent.avgResponseMs / 6e4)}m`}`,
|
|
1035
|
+
`${c.muted("Categories:")} ${agent.categories.map((cat) => c.cool(cat.replace(/_/g, " "))).join(", ")}`,
|
|
1036
|
+
`${c.muted("Tags:")} ${agent.tags.length > 0 ? agent.tags.join(", ") : c.dim("none")}`
|
|
1037
|
+
]);
|
|
1038
|
+
if (agent.skills.length > 0) {
|
|
1039
|
+
section("Skills");
|
|
1040
|
+
const skillTable = createTable(["Skill", "Proficiency"]);
|
|
1041
|
+
for (const skill of agent.skills) {
|
|
1042
|
+
const bar = c.warm("\u2588".repeat(Math.round(skill.proficiency / 5))) + c.muted("\u2591".repeat(20 - Math.round(skill.proficiency / 5)));
|
|
1043
|
+
skillTable.push([skill.name, `${bar} ${skill.proficiency}%`]);
|
|
1044
|
+
}
|
|
1045
|
+
console.log(skillTable.toString());
|
|
1046
|
+
}
|
|
1047
|
+
console.log(
|
|
1048
|
+
c.muted("\n Slug: ") + c.dim(agent.slug) + c.muted(" \u2022 ID: ") + c.dim(agent.id) + "\n"
|
|
1049
|
+
);
|
|
1050
|
+
} catch (err) {
|
|
1051
|
+
s.fail("Failed to load agent");
|
|
1052
|
+
showError(err);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function printAgentTable(agents) {
|
|
1056
|
+
const table = createTable([
|
|
1057
|
+
"#",
|
|
1058
|
+
"Agent",
|
|
1059
|
+
"Category",
|
|
1060
|
+
"Score",
|
|
1061
|
+
"Rating",
|
|
1062
|
+
"Price",
|
|
1063
|
+
"Tasks"
|
|
1064
|
+
]);
|
|
1065
|
+
for (let i = 0; i < agents.length; i++) {
|
|
1066
|
+
const a = agents[i];
|
|
1067
|
+
const verified = a.isVerified ? c.cool(" \u2713") : "";
|
|
1068
|
+
table.push([
|
|
1069
|
+
c.dim(String(i + 1)),
|
|
1070
|
+
c.bold(a.name) + verified + "\n" + c.muted(truncate(a.tagline || a.description, 40)),
|
|
1071
|
+
c.cool(a.categories[0]?.replace(/_/g, " ") || "\u2014"),
|
|
1072
|
+
formatRepScore(a.reputationScore),
|
|
1073
|
+
a.avgRating > 0 ? formatRating(a.avgRating) : c.muted("\u2014"),
|
|
1074
|
+
formatPrice(a.basePrice),
|
|
1075
|
+
String(a.tasksCompleted)
|
|
1076
|
+
]);
|
|
1077
|
+
}
|
|
1078
|
+
console.log(table.toString());
|
|
1079
|
+
console.log();
|
|
1080
|
+
}
|
|
1081
|
+
async function viewAgentReviews(slug) {
|
|
1082
|
+
const s = spin("Loading reviews...");
|
|
1083
|
+
try {
|
|
1084
|
+
const res = await api.get(`/agents/${slug}`, void 0, false);
|
|
1085
|
+
s.stop();
|
|
1086
|
+
const { agent } = res;
|
|
1087
|
+
if (!agent.reviews || agent.reviews.length === 0) {
|
|
1088
|
+
console.log(c.warn(`
|
|
1089
|
+
No reviews for ${c.warm.bold(agent.name)} yet.
|
|
1090
|
+
`));
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
section(`Reviews for ${agent.name} \u2014 ${formatRating(agent.avgRating, agent.reviewCount)}`);
|
|
1094
|
+
const table = createTable(["Rating", "Reviewer", "Date", "Review"]);
|
|
1095
|
+
for (const r of agent.reviews) {
|
|
1096
|
+
const stars = formatRating(r.rating);
|
|
1097
|
+
const reviewer = r.author?.name || c.muted("Anonymous");
|
|
1098
|
+
const content = r.title ? c.bold(r.title) + "\n" + (r.content || "") : r.content || c.muted("No comment");
|
|
1099
|
+
const truncated = content.length > 80 ? content.slice(0, 77) + "..." : content;
|
|
1100
|
+
table.push([stars, reviewer, formatDate(r.createdAt), truncated]);
|
|
1101
|
+
}
|
|
1102
|
+
console.log(table.toString());
|
|
1103
|
+
console.log();
|
|
1104
|
+
} catch (err) {
|
|
1105
|
+
s.fail("Failed to load reviews");
|
|
1106
|
+
showError(err);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
function truncate(s, len) {
|
|
1110
|
+
return s.length > len ? s.slice(0, len - 1) + "\u2026" : s;
|
|
1111
|
+
}
|
|
1112
|
+
var init_marketplace = __esm({
|
|
1113
|
+
"src/commands/marketplace.ts"() {
|
|
1114
|
+
"use strict";
|
|
1115
|
+
init_api();
|
|
1116
|
+
init_ui();
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
// src/commands/tasks.ts
|
|
1121
|
+
var tasks_exports = {};
|
|
1122
|
+
__export(tasks_exports, {
|
|
1123
|
+
acceptTaskProposal: () => acceptTaskProposal,
|
|
1124
|
+
hire: () => hire,
|
|
1125
|
+
listTaskProposals: () => listTaskProposals,
|
|
1126
|
+
listTasks: () => listTasks,
|
|
1127
|
+
review: () => review,
|
|
1128
|
+
sendMessage: () => sendMessage,
|
|
1129
|
+
viewTask: () => viewTask
|
|
1130
|
+
});
|
|
1131
|
+
import { input as input4, select as select3, number as numPrompt, editor as editor2 } from "@inquirer/prompts";
|
|
1132
|
+
async function hire(agentSlug) {
|
|
1133
|
+
if (!agentSlug) {
|
|
1134
|
+
agentSlug = await input4({ message: "Agent slug or ID" });
|
|
1135
|
+
}
|
|
1136
|
+
const s = spin("Loading agent...");
|
|
1137
|
+
let agent;
|
|
1138
|
+
try {
|
|
1139
|
+
const agentRes = await api.get(`/agents/${agentSlug}`, void 0, false);
|
|
1140
|
+
agent = agentRes.agent;
|
|
1141
|
+
s.stop();
|
|
1142
|
+
} catch (err) {
|
|
1143
|
+
s.fail("Agent not found");
|
|
1144
|
+
showError(err);
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
console.log(
|
|
1148
|
+
`
|
|
1149
|
+
Hiring ${c.warm.bold(agent.name)} ${c.muted(`(starting at ${formatPrice(agent.basePrice, agent.currency)})`)}
|
|
1150
|
+
`
|
|
1151
|
+
);
|
|
1152
|
+
const title = await input4({
|
|
1153
|
+
message: "Task title",
|
|
1154
|
+
validate: (v) => v.length > 3 ? true : "Title must be at least 4 characters"
|
|
1155
|
+
});
|
|
1156
|
+
const description = await editor2({
|
|
1157
|
+
message: "Task description (opens editor)",
|
|
1158
|
+
default: "Describe what you need done...",
|
|
1159
|
+
waitForUseInput: false
|
|
1160
|
+
});
|
|
1161
|
+
const category = await select3({
|
|
1162
|
+
message: "Category",
|
|
1163
|
+
choices: agent.categories.map((cat) => ({
|
|
1164
|
+
name: cat.replace(/_/g, " "),
|
|
1165
|
+
value: cat
|
|
1166
|
+
})),
|
|
1167
|
+
default: agent.categories[0]
|
|
1168
|
+
});
|
|
1169
|
+
const budget = await numPrompt({
|
|
1170
|
+
message: `Budget (${agent.currency})`,
|
|
1171
|
+
default: parseFloat(agent.basePrice),
|
|
1172
|
+
min: 0.01
|
|
1173
|
+
});
|
|
1174
|
+
const priority = await select3({
|
|
1175
|
+
message: "Priority",
|
|
1176
|
+
choices: [
|
|
1177
|
+
{ name: "Normal", value: "NORMAL" },
|
|
1178
|
+
{ name: "Low", value: "LOW" },
|
|
1179
|
+
{ name: "High", value: "HIGH" },
|
|
1180
|
+
{ name: "Urgent", value: "URGENT" }
|
|
1181
|
+
],
|
|
1182
|
+
default: "NORMAL"
|
|
1183
|
+
});
|
|
1184
|
+
const s2 = spin("Creating task...");
|
|
1185
|
+
try {
|
|
1186
|
+
const res = await api.post("/tasks", {
|
|
1187
|
+
title,
|
|
1188
|
+
description,
|
|
1189
|
+
category,
|
|
1190
|
+
budget: budget ?? parseFloat(agent.basePrice),
|
|
1191
|
+
currency: agent.currency,
|
|
1192
|
+
agentId: agent.id,
|
|
1193
|
+
priority
|
|
1194
|
+
});
|
|
1195
|
+
s2.succeed(c.success("Task created!"));
|
|
1196
|
+
showSuccess(
|
|
1197
|
+
`Task ${c.warm.bold(res.taskId.slice(0, 8))} created for ${c.warm(res.agent?.name || agent.name)}`
|
|
1198
|
+
);
|
|
1199
|
+
console.log(c.muted(` Track: g0 task ${res.taskId}
|
|
1200
|
+
`));
|
|
1201
|
+
} catch (err) {
|
|
1202
|
+
s2.fail("Failed to create task");
|
|
1203
|
+
showError(err);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
async function listTasks(opts) {
|
|
1207
|
+
const s = spin("Loading tasks...");
|
|
1208
|
+
try {
|
|
1209
|
+
const query = {};
|
|
1210
|
+
if (opts.status) query.status = opts.status;
|
|
1211
|
+
if (opts.limit) query.limit = opts.limit;
|
|
1212
|
+
const res = await api.get("/tasks", query);
|
|
1213
|
+
s.stop();
|
|
1214
|
+
if (res.tasks.length === 0) {
|
|
1215
|
+
console.log(c.warn("\n No tasks found.\n"));
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
section(`Your Tasks (${res.tasks.length})`);
|
|
1219
|
+
const table = createTable(["ID", "Title", "Agent", "Status", "Budget", "Created"]);
|
|
1220
|
+
for (const t of res.tasks) {
|
|
1221
|
+
table.push([
|
|
1222
|
+
c.dim(t.id.slice(0, 8)),
|
|
1223
|
+
c.bold(t.title),
|
|
1224
|
+
t.agent ? c.warm(t.agent.name) : c.muted("unassigned"),
|
|
1225
|
+
formatStatus(t.status),
|
|
1226
|
+
formatPrice(t.budget, t.currency),
|
|
1227
|
+
formatDate(t.createdAt)
|
|
1228
|
+
]);
|
|
1229
|
+
}
|
|
1230
|
+
console.log(table.toString());
|
|
1231
|
+
console.log();
|
|
1232
|
+
} catch (err) {
|
|
1233
|
+
s.fail("Failed to load tasks");
|
|
1234
|
+
showError(err);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
async function viewTask(taskId) {
|
|
1238
|
+
const s = spin("Loading task...");
|
|
1239
|
+
try {
|
|
1240
|
+
const res = await api.get(`/tasks/${taskId}`);
|
|
1241
|
+
const task = res.task;
|
|
1242
|
+
s.stop();
|
|
1243
|
+
infoBox(`Task: ${task.title}`, [
|
|
1244
|
+
`${c.muted("ID:")} ${c.dim(task.id)}`,
|
|
1245
|
+
`${c.muted("Status:")} ${formatStatus(task.status)}`,
|
|
1246
|
+
`${c.muted("Agent:")} ${task.agent ? c.warm.bold(task.agent.name) : c.muted("unassigned")}`,
|
|
1247
|
+
`${c.muted("Category:")} ${c.cool(task.category.replace(/_/g, " "))}`,
|
|
1248
|
+
`${c.muted("Priority:")} ${task.priority}`,
|
|
1249
|
+
`${c.muted("Budget:")} ${formatPrice(task.budget, task.currency)}`,
|
|
1250
|
+
`${c.muted("Progress:")} ${progressBar(task.progress)} ${task.progress}%`,
|
|
1251
|
+
`${c.muted("Created:")} ${formatDate(task.createdAt)}`,
|
|
1252
|
+
...task.startedAt ? [`${c.muted("Started:")} ${formatDate(task.startedAt)}`] : [],
|
|
1253
|
+
...task.completedAt ? [`${c.muted("Completed:")} ${formatDate(task.completedAt)}`] : []
|
|
1254
|
+
]);
|
|
1255
|
+
if (task.progressMessage) {
|
|
1256
|
+
console.log(c.muted("\n Latest update: ") + task.progressMessage);
|
|
1257
|
+
}
|
|
1258
|
+
if (task.resultSummary) {
|
|
1259
|
+
section("Result");
|
|
1260
|
+
console.log(" " + task.resultSummary + "\n");
|
|
1261
|
+
}
|
|
1262
|
+
console.log(c.muted("\n Description:"));
|
|
1263
|
+
console.log(" " + task.description.split("\n").join("\n ") + "\n");
|
|
1264
|
+
const messages = task.messages || [];
|
|
1265
|
+
if (messages.length > 0) {
|
|
1266
|
+
section("Messages");
|
|
1267
|
+
for (const msg of messages) {
|
|
1268
|
+
const sender = msg.senderType === "BUYER" ? c.cool("You") : msg.senderType === "AGENT" ? c.warm("Agent") : c.muted("System");
|
|
1269
|
+
console.log(` ${sender} ${c.dim(formatDate(msg.createdAt))}`);
|
|
1270
|
+
console.log(` ${msg.content}
|
|
1271
|
+
`);
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
s.fail("Failed to load task");
|
|
1276
|
+
showError(err);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
async function sendMessage(taskId) {
|
|
1280
|
+
const content = await input4({
|
|
1281
|
+
message: "Message",
|
|
1282
|
+
validate: (v) => v.length > 0 ? true : "Message cannot be empty"
|
|
1283
|
+
});
|
|
1284
|
+
const s = spin("Sending...");
|
|
1285
|
+
try {
|
|
1286
|
+
await api.post(`/tasks/${taskId}/messages`, { content });
|
|
1287
|
+
s.succeed(c.success("Message sent!"));
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
s.fail("Failed to send message");
|
|
1290
|
+
showError(err);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
async function review(taskId) {
|
|
1294
|
+
const rating = await select3({
|
|
1295
|
+
message: "Overall rating",
|
|
1296
|
+
choices: [5, 4, 3, 2, 1].map((n) => ({
|
|
1297
|
+
name: "\u2605".repeat(n) + "\u2606".repeat(5 - n) + ` (${n})`,
|
|
1298
|
+
value: n
|
|
1299
|
+
}))
|
|
1300
|
+
});
|
|
1301
|
+
const title = await input4({ message: "Review title (optional)" });
|
|
1302
|
+
const content = await input4({ message: "Review comment (optional)" });
|
|
1303
|
+
const s = spin("Submitting review...");
|
|
1304
|
+
try {
|
|
1305
|
+
await api.post(`/tasks/${taskId}/review`, {
|
|
1306
|
+
rating,
|
|
1307
|
+
title: title || void 0,
|
|
1308
|
+
content: content || void 0
|
|
1309
|
+
});
|
|
1310
|
+
s.succeed(c.success("Review submitted!"));
|
|
1311
|
+
showSuccess("Thank you for your feedback!");
|
|
1312
|
+
} catch (err) {
|
|
1313
|
+
s.fail("Failed to submit review");
|
|
1314
|
+
showError(err);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
async function listTaskProposals(taskId) {
|
|
1318
|
+
const s = spin("Loading proposals...");
|
|
1319
|
+
try {
|
|
1320
|
+
const res = await api.get(`/tasks/${taskId}/proposals`);
|
|
1321
|
+
s.stop();
|
|
1322
|
+
if (res.proposals.length === 0) {
|
|
1323
|
+
console.log(c.warn("\n No proposals received yet.\n"));
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
section(`Proposals (${res.count})`);
|
|
1327
|
+
const table = createTable(["#", "Agent", "Price", "Rating", "Score", "Est. Time", "Approach"]);
|
|
1328
|
+
for (let i = 0; i < res.proposals.length; i++) {
|
|
1329
|
+
const p = res.proposals[i];
|
|
1330
|
+
const estTime = p.estimatedMinutes < 60 ? `${p.estimatedMinutes}m` : `${Math.round(p.estimatedMinutes / 60)}h`;
|
|
1331
|
+
const approach = p.approach.length > 50 ? p.approach.slice(0, 47) + "..." : p.approach;
|
|
1332
|
+
table.push([
|
|
1333
|
+
c.dim(String(i + 1)),
|
|
1334
|
+
c.warm.bold(p.agentName) + "\n" + c.dim(p.agentSlug),
|
|
1335
|
+
formatPrice(p.price, p.currency),
|
|
1336
|
+
p.avgRating > 0 ? formatRating(p.avgRating) : c.muted("\u2014"),
|
|
1337
|
+
formatRepScore(p.reputationScore),
|
|
1338
|
+
c.cool(estTime),
|
|
1339
|
+
approach
|
|
1340
|
+
]);
|
|
1341
|
+
}
|
|
1342
|
+
console.log(table.toString());
|
|
1343
|
+
console.log(c.muted(`
|
|
1344
|
+
Accept a proposal: g0 task:accept-proposal ${taskId}
|
|
1345
|
+
`));
|
|
1346
|
+
} catch (err) {
|
|
1347
|
+
s.fail("Failed to load proposals");
|
|
1348
|
+
showError(err);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
async function acceptTaskProposal(taskId) {
|
|
1352
|
+
const s = spin("Loading proposals...");
|
|
1353
|
+
try {
|
|
1354
|
+
const res = await api.get(`/tasks/${taskId}/proposals`);
|
|
1355
|
+
s.stop();
|
|
1356
|
+
if (res.proposals.length === 0) {
|
|
1357
|
+
console.log(c.warn("\n No proposals to accept.\n"));
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
const { select: select12 } = await import("@inquirer/prompts");
|
|
1361
|
+
const proposalId = await select12({
|
|
1362
|
+
message: "Select a proposal to accept",
|
|
1363
|
+
choices: res.proposals.map((p) => ({
|
|
1364
|
+
name: `${p.agentName} \u2014 ${formatPrice(p.price, p.currency)} \u2014 ${p.approach.slice(0, 50)}`,
|
|
1365
|
+
value: p.proposalId
|
|
1366
|
+
}))
|
|
1367
|
+
});
|
|
1368
|
+
const s2 = spin("Accepting proposal...");
|
|
1369
|
+
const acceptRes = await api.post(`/tasks/${taskId}/proposals`, { proposalId });
|
|
1370
|
+
s2.succeed(c.success("Proposal accepted!"));
|
|
1371
|
+
showSuccess(acceptRes.message);
|
|
1372
|
+
if (acceptRes.task?.agent) {
|
|
1373
|
+
console.log(c.muted(` Agent: ${c.warm(acceptRes.task.agent.name)}`));
|
|
1374
|
+
}
|
|
1375
|
+
console.log(c.muted(` Track: g0 task ${taskId}
|
|
1376
|
+
`));
|
|
1377
|
+
} catch (err) {
|
|
1378
|
+
showError(err);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
function progressBar(pct) {
|
|
1382
|
+
const filled = Math.round(pct / 5);
|
|
1383
|
+
return c.warm("\u2588".repeat(filled)) + c.muted("\u2591".repeat(20 - filled));
|
|
1384
|
+
}
|
|
1385
|
+
var init_tasks = __esm({
|
|
1386
|
+
"src/commands/tasks.ts"() {
|
|
1387
|
+
"use strict";
|
|
1388
|
+
init_api();
|
|
1389
|
+
init_ui();
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1393
|
+
// src/commands/orders.ts
|
|
1394
|
+
var orders_exports = {};
|
|
1395
|
+
__export(orders_exports, {
|
|
1396
|
+
createOrder: () => createOrder,
|
|
1397
|
+
listOrders: () => listOrders
|
|
1398
|
+
});
|
|
1399
|
+
import { input as input5, select as select4, number as numPrompt2 } from "@inquirer/prompts";
|
|
1400
|
+
async function createOrder() {
|
|
1401
|
+
const agentId = await input5({ message: "Agent ID or slug", validate: (v) => v.length > 0 || "Required" });
|
|
1402
|
+
const title = await input5({ message: "Task title", validate: (v) => v.length > 3 || "Min 4 chars" });
|
|
1403
|
+
const description = await input5({ message: "Task description", validate: (v) => v.length > 10 || "Min 10 chars" });
|
|
1404
|
+
const category = await select4({
|
|
1405
|
+
message: "Category",
|
|
1406
|
+
choices: [
|
|
1407
|
+
{ name: "Coding", value: "CODING" },
|
|
1408
|
+
{ name: "Web Development", value: "WEB_DEVELOPMENT" },
|
|
1409
|
+
{ name: "Data Science", value: "DATA_SCIENCE" },
|
|
1410
|
+
{ name: "AI/ML", value: "AI_ML" },
|
|
1411
|
+
{ name: "Content Writing", value: "CONTENT_WRITING" },
|
|
1412
|
+
{ name: "Digital Marketing", value: "DIGITAL_MARKETING" },
|
|
1413
|
+
{ name: "Graphic Design", value: "GRAPHIC_DESIGN" },
|
|
1414
|
+
{ name: "Other", value: "OTHER" }
|
|
1415
|
+
]
|
|
1416
|
+
});
|
|
1417
|
+
const budget = await numPrompt2({ message: "Budget (USDC)", min: 0.01, default: 5 });
|
|
1418
|
+
const s = spin("Creating order...");
|
|
1419
|
+
try {
|
|
1420
|
+
const res = await api.post("/orders", {
|
|
1421
|
+
agentId,
|
|
1422
|
+
title,
|
|
1423
|
+
description,
|
|
1424
|
+
category,
|
|
1425
|
+
budget: budget ?? 5
|
|
1426
|
+
});
|
|
1427
|
+
s.succeed(c.success("Order created!"));
|
|
1428
|
+
showSuccess(`Task ${c.dim(res.taskId.slice(0, 8))} created. Status: ${formatStatus(res.status)}`);
|
|
1429
|
+
console.log(c.muted(` Charged: ${formatPrice(res.totalEscrow)}`));
|
|
1430
|
+
console.log(c.muted(` Track: g0 task ${res.taskId}
|
|
1431
|
+
`));
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
s.fail("Failed to create order");
|
|
1434
|
+
showError(err);
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
async function listOrders() {
|
|
1438
|
+
const s = spin("Loading orders...");
|
|
1439
|
+
try {
|
|
1440
|
+
const res = await api.get("/orders");
|
|
1441
|
+
s.stop();
|
|
1442
|
+
if (res.orders.length === 0) {
|
|
1443
|
+
console.log(c.warn("\n No orders found.\n"));
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
section(`Your Orders (${res.orders.length})`);
|
|
1447
|
+
const table = createTable(["ID", "Title", "Agent", "Status", "Amount", "Date"]);
|
|
1448
|
+
for (const o of res.orders) {
|
|
1449
|
+
table.push([c.dim(o.id.slice(0, 8)), c.bold(o.title), c.warm(o.agent?.name || "\u2014"), formatStatus(o.status), formatPrice(o.budget, o.currency), formatDate(o.createdAt)]);
|
|
1450
|
+
}
|
|
1451
|
+
console.log(table.toString() + "\n");
|
|
1452
|
+
} catch (err) {
|
|
1453
|
+
s.fail("Failed to load orders");
|
|
1454
|
+
showError(err);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
var init_orders = __esm({
|
|
1458
|
+
"src/commands/orders.ts"() {
|
|
1459
|
+
"use strict";
|
|
1460
|
+
init_api();
|
|
1461
|
+
init_ui();
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
// src/commands/jobs.ts
|
|
1466
|
+
var jobs_exports = {};
|
|
1467
|
+
__export(jobs_exports, {
|
|
1468
|
+
acceptJobProposal: () => acceptJobProposal,
|
|
1469
|
+
createJob: () => createJob,
|
|
1470
|
+
listJobProposals: () => listJobProposals,
|
|
1471
|
+
listJobs: () => listJobs
|
|
1472
|
+
});
|
|
1473
|
+
import { input as input6, select as select5, number as numPrompt3, editor as editor3 } from "@inquirer/prompts";
|
|
1474
|
+
async function createJob() {
|
|
1475
|
+
const title = await input6({ message: "Job title", validate: (v) => v.length > 3 || "Min 4 chars" });
|
|
1476
|
+
const description = await editor3({ message: "Job description (opens editor)", default: "Describe the job requirements..." });
|
|
1477
|
+
const category = await select5({
|
|
1478
|
+
message: "Category",
|
|
1479
|
+
choices: [
|
|
1480
|
+
{ name: "Coding", value: "CODING" },
|
|
1481
|
+
{ name: "Web Development", value: "WEB_DEVELOPMENT" },
|
|
1482
|
+
{ name: "Data Science", value: "DATA_SCIENCE" },
|
|
1483
|
+
{ name: "AI/ML", value: "AI_ML" },
|
|
1484
|
+
{ name: "Content Writing", value: "CONTENT_WRITING" },
|
|
1485
|
+
{ name: "Digital Marketing", value: "DIGITAL_MARKETING" },
|
|
1486
|
+
{ name: "Graphic Design", value: "GRAPHIC_DESIGN" },
|
|
1487
|
+
{ name: "Other", value: "OTHER" }
|
|
1488
|
+
]
|
|
1489
|
+
});
|
|
1490
|
+
const budget = await numPrompt3({ message: "Budget (USDC)", min: 0.01, default: 10 });
|
|
1491
|
+
const priority = await select5({
|
|
1492
|
+
message: "Priority",
|
|
1493
|
+
choices: [{ name: "Normal", value: "NORMAL" }, { name: "Low", value: "LOW" }, { name: "High", value: "HIGH" }, { name: "Urgent", value: "URGENT" }],
|
|
1494
|
+
default: "NORMAL"
|
|
1495
|
+
});
|
|
1496
|
+
const s = spin("Posting job...");
|
|
1497
|
+
try {
|
|
1498
|
+
const res = await api.post("/jobs", { title, description, category, budgetMin: 1, budgetMax: budget ?? 10, requiredSkills: [], proposalDeadlineDays: 14 });
|
|
1499
|
+
s.succeed(c.success("Job posted!"));
|
|
1500
|
+
showSuccess(`Job ${c.warm.bold(res.job.title)} is live. Agents can now submit proposals.`);
|
|
1501
|
+
console.log(c.muted(` Job ID: ${res.job.id}`));
|
|
1502
|
+
console.log(c.muted(` View proposals: g0 jobs:proposals ${res.job.id}
|
|
1503
|
+
`));
|
|
1504
|
+
} catch (err) {
|
|
1505
|
+
s.fail("Failed to post job");
|
|
1506
|
+
showError(err);
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
async function listJobs() {
|
|
1510
|
+
const s = spin("Loading jobs...");
|
|
1511
|
+
try {
|
|
1512
|
+
const res = await api.get("/jobs");
|
|
1513
|
+
s.stop();
|
|
1514
|
+
if (res.jobs.length === 0) {
|
|
1515
|
+
console.log(c.warn("\n No jobs found.\n"));
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
section(`Your Jobs (${res.jobs.length})`);
|
|
1519
|
+
const table = createTable(["ID", "Title", "Category", "Budget", "Proposals", "Status", "Posted"]);
|
|
1520
|
+
for (const j of res.jobs) {
|
|
1521
|
+
const budgetStr = j.budgetMin && j.budgetMax ? `${formatPrice(j.budgetMin, j.currency)} - ${formatPrice(j.budgetMax, j.currency)}` : formatPrice(j.budgetMax || "0", j.currency);
|
|
1522
|
+
table.push([c.dim(j.id.slice(0, 8)), c.bold(j.title), c.cool(j.category.replace(/_/g, " ")), budgetStr, c.warm(String(j.proposalCount)), formatStatus(j.status), formatDate(j.createdAt)]);
|
|
1523
|
+
}
|
|
1524
|
+
console.log(table.toString() + "\n");
|
|
1525
|
+
} catch (err) {
|
|
1526
|
+
s.fail("Failed to load jobs");
|
|
1527
|
+
showError(err);
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
async function listJobProposals(taskId) {
|
|
1531
|
+
const s = spin("Loading proposals...");
|
|
1532
|
+
try {
|
|
1533
|
+
const res = await api.get(`/jobs/${taskId}/proposals`);
|
|
1534
|
+
s.stop();
|
|
1535
|
+
if (res.proposals.length === 0) {
|
|
1536
|
+
console.log(c.warn("\n No proposals yet.\n"));
|
|
1537
|
+
return;
|
|
1538
|
+
}
|
|
1539
|
+
section(`Proposals (${res.proposals.length})`);
|
|
1540
|
+
const table = createTable(["#", "Agent", "Price", "Time Est.", "Status", "Submitted"]);
|
|
1541
|
+
res.proposals.forEach((p, i) => {
|
|
1542
|
+
table.push([c.dim(String(i + 1)), c.warm.bold(p.agent.name), formatPrice(p.price, p.currency), c.muted(`${p.estimatedHours}h`), formatStatus(p.status), formatDate(p.createdAt)]);
|
|
1543
|
+
});
|
|
1544
|
+
console.log(table.toString());
|
|
1545
|
+
for (const p of res.proposals) {
|
|
1546
|
+
if (p.approach) {
|
|
1547
|
+
console.log(`
|
|
1548
|
+
${c.warm.bold(p.agent.name)}: ${c.muted(p.approach)}`);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
console.log();
|
|
1552
|
+
} catch (err) {
|
|
1553
|
+
s.fail("Failed to load proposals");
|
|
1554
|
+
showError(err);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
async function acceptJobProposal(taskId) {
|
|
1558
|
+
const s = spin("Loading proposals...");
|
|
1559
|
+
try {
|
|
1560
|
+
const res = await api.get(`/jobs/${taskId}/proposals`);
|
|
1561
|
+
s.stop();
|
|
1562
|
+
if (res.proposals.length === 0) {
|
|
1563
|
+
console.log(c.warn("\n No proposals to accept.\n"));
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
const proposalId = await select5({
|
|
1567
|
+
message: "Select proposal to accept",
|
|
1568
|
+
choices: res.proposals.map((p) => ({
|
|
1569
|
+
name: `${p.agent.name} \u2014 ${formatPrice(p.price, p.currency)}`,
|
|
1570
|
+
value: p.id
|
|
1571
|
+
}))
|
|
1572
|
+
});
|
|
1573
|
+
const s2 = spin("Accepting proposal...");
|
|
1574
|
+
try {
|
|
1575
|
+
await api.post(`/jobs/${taskId}/accept`, { proposalId });
|
|
1576
|
+
s2.succeed(c.success("Proposal accepted!"));
|
|
1577
|
+
showSuccess("Task created from accepted proposal. Escrow has been charged.");
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
s2.fail("Failed to accept proposal");
|
|
1580
|
+
showError(err);
|
|
1581
|
+
}
|
|
1582
|
+
} catch (err) {
|
|
1583
|
+
s.fail("Failed to load proposals");
|
|
1584
|
+
showError(err);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
var init_jobs = __esm({
|
|
1588
|
+
"src/commands/jobs.ts"() {
|
|
1589
|
+
"use strict";
|
|
1590
|
+
init_api();
|
|
1591
|
+
init_ui();
|
|
1592
|
+
}
|
|
1593
|
+
});
|
|
1594
|
+
|
|
1595
|
+
// src/commands/hire.ts
|
|
1596
|
+
var hire_exports = {};
|
|
1597
|
+
__export(hire_exports, {
|
|
1598
|
+
createHireRequest: () => createHireRequest,
|
|
1599
|
+
listHireRequests: () => listHireRequests,
|
|
1600
|
+
payHireRequest: () => payHireRequest,
|
|
1601
|
+
respondToHireRequest: () => respondToHireRequest,
|
|
1602
|
+
viewHireRequest: () => viewHireRequest
|
|
1603
|
+
});
|
|
1604
|
+
import { input as input7, select as select6, number as numPrompt4, confirm } from "@inquirer/prompts";
|
|
1605
|
+
async function createHireRequest() {
|
|
1606
|
+
const agentId = await input7({ message: "Agent ID or slug", validate: (v) => v.length > 0 || "Required" });
|
|
1607
|
+
const title = await input7({ message: "Project title", validate: (v) => v.length > 3 || "Min 4 chars" });
|
|
1608
|
+
const description = await input7({ message: "Describe what you need", validate: (v) => v.length > 10 || "Min 10 chars" });
|
|
1609
|
+
const budget = await numPrompt4({ message: "Proposed budget (USDC)", min: 0.01, default: 10 });
|
|
1610
|
+
const s = spin("Sending hire request...");
|
|
1611
|
+
try {
|
|
1612
|
+
const res = await api.post("/hire-requests", {
|
|
1613
|
+
agentId,
|
|
1614
|
+
title,
|
|
1615
|
+
description,
|
|
1616
|
+
deliverables: [{ item: title }],
|
|
1617
|
+
price: budget ?? 10
|
|
1618
|
+
});
|
|
1619
|
+
s.succeed(c.success("Hire request sent!"));
|
|
1620
|
+
showSuccess(`Request ${c.dim(res.hireRequest.id.slice(0, 8))} sent. The agent will review and respond.`);
|
|
1621
|
+
} catch (err) {
|
|
1622
|
+
s.fail("Failed to send hire request");
|
|
1623
|
+
showError(err);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
async function listHireRequests() {
|
|
1627
|
+
const s = spin("Loading hire requests...");
|
|
1628
|
+
try {
|
|
1629
|
+
const res = await api.get("/hire-requests");
|
|
1630
|
+
s.stop();
|
|
1631
|
+
if (res.hireRequests.length === 0) {
|
|
1632
|
+
console.log(c.warn("\n No hire requests found.\n"));
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
section(`Hire Requests (${res.hireRequests.length})`);
|
|
1636
|
+
const table = createTable(["ID", "Title", "Agent", "Budget", "Status", "Sent"]);
|
|
1637
|
+
for (const r of res.hireRequests) {
|
|
1638
|
+
table.push([c.dim(r.id.slice(0, 8)), c.bold(r.title), c.warm(r.agent?.name || "\u2014"), formatPrice(r.price, r.currency), formatStatus(r.status), formatDate(r.createdAt)]);
|
|
1639
|
+
}
|
|
1640
|
+
console.log(table.toString() + "\n");
|
|
1641
|
+
} catch (err) {
|
|
1642
|
+
s.fail("Failed to load hire requests");
|
|
1643
|
+
showError(err);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
async function viewHireRequest(requestId) {
|
|
1647
|
+
const s = spin("Loading hire request...");
|
|
1648
|
+
try {
|
|
1649
|
+
const res = await api.get(`/hire-requests/${requestId}`);
|
|
1650
|
+
const r = res.hireRequest;
|
|
1651
|
+
s.stop();
|
|
1652
|
+
infoBox(`Hire Request: ${r.title}`, [
|
|
1653
|
+
`${c.muted("ID:")} ${c.dim(r.id)}`,
|
|
1654
|
+
`${c.muted("Agent:")} ${c.warm.bold(r.agent?.name || "\u2014")}`,
|
|
1655
|
+
`${c.muted("Budget:")} ${formatPrice(r.price, r.currency)}`,
|
|
1656
|
+
`${c.muted("Status:")} ${formatStatus(r.status)}`,
|
|
1657
|
+
...r.counterPrice ? [`${c.muted("Counter:")} ${formatPrice(r.counterPrice, r.currency)}`] : [],
|
|
1658
|
+
...r.responseNote ? [`${c.muted("Message:")} ${r.responseNote}`] : [],
|
|
1659
|
+
`${c.muted("Sent:")} ${formatDate(r.createdAt)}`
|
|
1660
|
+
]);
|
|
1661
|
+
if (r.description) {
|
|
1662
|
+
console.log(c.muted("\n Description:"));
|
|
1663
|
+
console.log(" " + r.description + "\n");
|
|
1664
|
+
}
|
|
1665
|
+
} catch (err) {
|
|
1666
|
+
s.fail("Failed to load hire request");
|
|
1667
|
+
showError(err);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
async function respondToHireRequest(requestId) {
|
|
1671
|
+
const action = await select6({
|
|
1672
|
+
message: "How do you want to respond?",
|
|
1673
|
+
choices: [
|
|
1674
|
+
{ name: "Accept \u2014 agree to the hire request", value: "accept" },
|
|
1675
|
+
{ name: "Reject \u2014 decline the hire request", value: "reject" },
|
|
1676
|
+
{ name: "Negotiate \u2014 propose a counter price", value: "negotiate" }
|
|
1677
|
+
]
|
|
1678
|
+
});
|
|
1679
|
+
let note;
|
|
1680
|
+
let counterPrice;
|
|
1681
|
+
if (action === "negotiate") {
|
|
1682
|
+
counterPrice = await numPrompt4({ message: "Counter price (USDC)", min: 0.01 }) ?? void 0;
|
|
1683
|
+
if (!counterPrice) {
|
|
1684
|
+
console.log(c.err("\n Counter price is required for negotiation.\n"));
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
note = await input7({ message: "Note (optional)" }) || void 0;
|
|
1689
|
+
const s = spin("Sending response...");
|
|
1690
|
+
try {
|
|
1691
|
+
const body = { action };
|
|
1692
|
+
if (note) body.note = note;
|
|
1693
|
+
if (counterPrice) body.counterPrice = counterPrice;
|
|
1694
|
+
const res = await api.post(`/hire-requests/${requestId}`, body);
|
|
1695
|
+
s.succeed(c.success("Response sent!"));
|
|
1696
|
+
if (action === "accept" && res.taskId) {
|
|
1697
|
+
showSuccess(`Hire request accepted. Task ${c.dim(res.taskId.slice(0, 8))} created.`);
|
|
1698
|
+
if (res.totalEscrow) console.log(c.muted(` Escrow: ${formatPrice(res.totalEscrow)}`));
|
|
1699
|
+
if (res.newBalance) console.log(c.muted(` New balance: ${formatPrice(res.newBalance)}`));
|
|
1700
|
+
} else if (action === "accept") {
|
|
1701
|
+
showSuccess("Hire request accepted.");
|
|
1702
|
+
} else if (action === "reject") {
|
|
1703
|
+
showSuccess("Hire request rejected.");
|
|
1704
|
+
} else {
|
|
1705
|
+
showSuccess(`Counter-offer sent: ${formatPrice(counterPrice)}`);
|
|
1706
|
+
}
|
|
1707
|
+
console.log();
|
|
1708
|
+
} catch (err) {
|
|
1709
|
+
s.fail("Failed to respond");
|
|
1710
|
+
showError(err);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
async function payHireRequest(requestId) {
|
|
1714
|
+
const yes = await confirm({ message: "Confirm payment? Funds will be held in escrow.", default: true });
|
|
1715
|
+
if (!yes) {
|
|
1716
|
+
console.log(c.muted("\n Cancelled.\n"));
|
|
1717
|
+
return;
|
|
1718
|
+
}
|
|
1719
|
+
const s = spin("Processing payment...");
|
|
1720
|
+
try {
|
|
1721
|
+
const res = await api.post(`/hire-requests/${requestId}/pay`);
|
|
1722
|
+
s.succeed(c.success("Payment processed!"));
|
|
1723
|
+
showSuccess(`Escrow funded. Task ${c.dim(res.taskId.slice(0, 8))} created.`);
|
|
1724
|
+
console.log(c.muted(` Charged: ${formatPrice(res.totalEscrow)}`));
|
|
1725
|
+
console.log(c.muted(` Track: g0 task ${res.taskId}
|
|
1726
|
+
`));
|
|
1727
|
+
} catch (err) {
|
|
1728
|
+
s.fail("Payment failed");
|
|
1729
|
+
showError(err);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
var init_hire = __esm({
|
|
1733
|
+
"src/commands/hire.ts"() {
|
|
1734
|
+
"use strict";
|
|
1735
|
+
init_api();
|
|
1736
|
+
init_ui();
|
|
1737
|
+
}
|
|
1738
|
+
});
|
|
1739
|
+
|
|
1740
|
+
// src/commands/inquiries.ts
|
|
1741
|
+
var inquiries_exports = {};
|
|
1742
|
+
__export(inquiries_exports, {
|
|
1743
|
+
convertInquiryToTask: () => convertInquiryToTask,
|
|
1744
|
+
createInquiry: () => createInquiry,
|
|
1745
|
+
listInquiries: () => listInquiries,
|
|
1746
|
+
sendInquiryMessage: () => sendInquiryMessage,
|
|
1747
|
+
viewInquiry: () => viewInquiry
|
|
1748
|
+
});
|
|
1749
|
+
import { input as input8, select as select7 } from "@inquirer/prompts";
|
|
1750
|
+
async function createInquiry() {
|
|
1751
|
+
const agentId = await input8({ message: "Agent ID or slug", validate: (v) => v.length > 0 || "Required" });
|
|
1752
|
+
const subject = await input8({ message: "Subject", validate: (v) => v.length > 0 || "Subject required" });
|
|
1753
|
+
const message = await input8({ message: "Your message", validate: (v) => v.length > 0 || "Message required" });
|
|
1754
|
+
const s = spin("Starting inquiry...");
|
|
1755
|
+
try {
|
|
1756
|
+
const res = await api.post("/inquiries", { agentId, subject, message });
|
|
1757
|
+
s.succeed(c.success("Inquiry started!"));
|
|
1758
|
+
showSuccess(`Inquiry ${c.dim(res.inquiry.id.slice(0, 8))} created. The agent owner will respond.`);
|
|
1759
|
+
console.log(c.muted(` Continue: g0 inquiries:view ${res.inquiry.id}
|
|
1760
|
+
`));
|
|
1761
|
+
} catch (err) {
|
|
1762
|
+
s.fail("Failed to start inquiry");
|
|
1763
|
+
showError(err);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
async function listInquiries() {
|
|
1767
|
+
const s = spin("Loading inquiries...");
|
|
1768
|
+
try {
|
|
1769
|
+
const res = await api.get("/inquiries");
|
|
1770
|
+
s.stop();
|
|
1771
|
+
if (res.inquiries.length === 0) {
|
|
1772
|
+
console.log(c.warn("\n No inquiries found.\n"));
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
section(`Your Inquiries (${res.inquiries.length})`);
|
|
1776
|
+
const table = createTable(["ID", "Subject", "With", "Status", "Messages", "Last Message", "Updated"]);
|
|
1777
|
+
for (const i of res.inquiries) {
|
|
1778
|
+
const lastContent = i.lastMessage?.content || "";
|
|
1779
|
+
const preview = lastContent ? lastContent.length > 30 ? lastContent.slice(0, 30) + "..." : lastContent : c.muted("--");
|
|
1780
|
+
table.push([c.dim(i.id.slice(0, 8)), c.bold(i.subject || "\u2014"), c.warm(i.counterparty?.name || "\u2014"), formatStatus(i.status), String(i.messageCount), preview, formatDate(i.updatedAt)]);
|
|
1781
|
+
}
|
|
1782
|
+
console.log(table.toString() + "\n");
|
|
1783
|
+
} catch (err) {
|
|
1784
|
+
s.fail("Failed to load inquiries");
|
|
1785
|
+
showError(err);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
async function viewInquiry(inquiryId) {
|
|
1789
|
+
const s = spin("Loading inquiry...");
|
|
1790
|
+
try {
|
|
1791
|
+
const res = await api.get(`/inquiries/${inquiryId}`);
|
|
1792
|
+
s.stop();
|
|
1793
|
+
console.log(`
|
|
1794
|
+
${c.warm.bold("Inquiry")} with ${c.cool(res.counterparty?.name || "Agent")} ${c.dim(`(${formatStatus(res.inquiry.status)})`)}
|
|
1795
|
+
`);
|
|
1796
|
+
for (const msg of res.messages) {
|
|
1797
|
+
const sender = msg.senderType === "BUYER" ? c.cool("You") : c.warm("Agent");
|
|
1798
|
+
console.log(` ${sender} ${c.dim(formatDate(msg.createdAt))}`);
|
|
1799
|
+
console.log(` ${msg.content}
|
|
1800
|
+
`);
|
|
1801
|
+
}
|
|
1802
|
+
} catch (err) {
|
|
1803
|
+
s.fail("Failed to load inquiry");
|
|
1804
|
+
showError(err);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
async function sendInquiryMessage(inquiryId) {
|
|
1808
|
+
const content = await input8({ message: "Message", validate: (v) => v.length > 0 || "Message required" });
|
|
1809
|
+
const s = spin("Sending...");
|
|
1810
|
+
try {
|
|
1811
|
+
await api.post(`/inquiries/${inquiryId}`, { content });
|
|
1812
|
+
s.succeed(c.success("Message sent!"));
|
|
1813
|
+
} catch (err) {
|
|
1814
|
+
s.fail("Failed to send message");
|
|
1815
|
+
showError(err);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
async function convertInquiryToTask(inquiryId) {
|
|
1819
|
+
const title = await input8({ message: "Task title", validate: (v) => v.length > 3 || "Min 4 chars" });
|
|
1820
|
+
const description = await input8({ message: "Task description", validate: (v) => v.length > 10 || "Min 10 chars" });
|
|
1821
|
+
const category = await select7({
|
|
1822
|
+
message: "Category",
|
|
1823
|
+
choices: [
|
|
1824
|
+
{ name: "Coding", value: "CODING" },
|
|
1825
|
+
{ name: "Web Development", value: "WEB_DEVELOPMENT" },
|
|
1826
|
+
{ name: "Data Science", value: "DATA_SCIENCE" },
|
|
1827
|
+
{ name: "AI/ML", value: "AI_ML" },
|
|
1828
|
+
{ name: "Content Writing", value: "CONTENT_WRITING" },
|
|
1829
|
+
{ name: "Other", value: "OTHER" }
|
|
1830
|
+
]
|
|
1831
|
+
});
|
|
1832
|
+
const price = await input8({ message: "Agreed price (USDC)", validate: (v) => !isNaN(parseFloat(v)) || "Must be a number" });
|
|
1833
|
+
const s = spin("Converting to task...");
|
|
1834
|
+
try {
|
|
1835
|
+
const res = await api.post(`/inquiries/${inquiryId}/hire`, {
|
|
1836
|
+
title,
|
|
1837
|
+
description,
|
|
1838
|
+
category,
|
|
1839
|
+
agreedPrice: parseFloat(price)
|
|
1840
|
+
});
|
|
1841
|
+
s.succeed(c.success("Task created!"));
|
|
1842
|
+
showSuccess(`Inquiry converted to task ${c.dim(res.taskId.slice(0, 8))}. Escrow charged.`);
|
|
1843
|
+
console.log(c.muted(` New balance: $${parseFloat(res.newBalance).toFixed(2)} USDC
|
|
1844
|
+
`));
|
|
1845
|
+
} catch (err) {
|
|
1846
|
+
s.fail("Failed to convert inquiry");
|
|
1847
|
+
showError(err);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
var init_inquiries = __esm({
|
|
1851
|
+
"src/commands/inquiries.ts"() {
|
|
1852
|
+
"use strict";
|
|
1853
|
+
init_api();
|
|
1854
|
+
init_ui();
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
// src/commands/dashboard.ts
|
|
1859
|
+
var dashboard_exports = {};
|
|
1860
|
+
__export(dashboard_exports, {
|
|
1861
|
+
completeTask: () => completeTask,
|
|
1862
|
+
dashboardStats: () => dashboardStats,
|
|
1863
|
+
disputeTask: () => disputeTask,
|
|
1864
|
+
submitBuyerEvidence: () => submitBuyerEvidence
|
|
1865
|
+
});
|
|
1866
|
+
import { input as input9, confirm as confirm2 } from "@inquirer/prompts";
|
|
1867
|
+
async function dashboardStats() {
|
|
1868
|
+
const s = spin("Loading dashboard...");
|
|
1869
|
+
try {
|
|
1870
|
+
const res = await api.get("/dashboard/stats");
|
|
1871
|
+
s.stop();
|
|
1872
|
+
infoBox("Dashboard", [
|
|
1873
|
+
`${c.muted("Total Tasks:")} ${c.bold(String(res.totalTasks))}`,
|
|
1874
|
+
`${c.muted("Completed:")} ${c.success(String(res.completedTasks))}`,
|
|
1875
|
+
`${c.muted("Active:")} ${c.cool(String(res.activeTasks))}`,
|
|
1876
|
+
`${c.muted("Total Spent:")} ${formatPrice(res.totalSpent)}`,
|
|
1877
|
+
`${c.muted("Active Agents:")} ${c.warm(String(res.activeAgents))}`,
|
|
1878
|
+
`${c.muted("Active Listings:")} ${String(res.activeListings)}`,
|
|
1879
|
+
`${c.muted("Avg Rating:")} ${res.avgRating > 0 ? `\u2605 ${res.avgRating.toFixed(1)}` : c.muted("\u2014")}`
|
|
1880
|
+
]);
|
|
1881
|
+
console.log();
|
|
1882
|
+
} catch (err) {
|
|
1883
|
+
s.fail("Failed to load dashboard");
|
|
1884
|
+
showError(err);
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
async function completeTask(taskId) {
|
|
1888
|
+
const yes = await confirm2({ message: "Approve delivery and release escrow to the agent?", default: true });
|
|
1889
|
+
if (!yes) {
|
|
1890
|
+
console.log(c.muted("\n Cancelled.\n"));
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
const s = spin("Completing task...");
|
|
1894
|
+
try {
|
|
1895
|
+
await api.post(`/dashboard/tasks/${taskId}/complete`);
|
|
1896
|
+
s.succeed(c.success("Task completed!"));
|
|
1897
|
+
showSuccess("Escrow released to the agent. You can now leave a review.");
|
|
1898
|
+
console.log(c.muted(` Leave review: g0 review ${taskId}
|
|
1899
|
+
`));
|
|
1900
|
+
} catch (err) {
|
|
1901
|
+
s.fail("Failed to complete task");
|
|
1902
|
+
showError(err);
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
async function disputeTask(taskId) {
|
|
1906
|
+
const reason = await input9({ message: "Reason for dispute", validate: (v) => v.length > 10 || "Min 10 chars" });
|
|
1907
|
+
const s = spin("Filing dispute...");
|
|
1908
|
+
try {
|
|
1909
|
+
await api.post(`/dashboard/tasks/${taskId}/dispute`, { message: reason });
|
|
1910
|
+
s.succeed(c.success("Dispute filed."));
|
|
1911
|
+
showSuccess("The agent will be notified and can respond or redeliver.");
|
|
1912
|
+
console.log(c.muted(` Submit evidence: g0 dashboard:evidence ${taskId}
|
|
1913
|
+
`));
|
|
1914
|
+
} catch (err) {
|
|
1915
|
+
s.fail("Failed to file dispute");
|
|
1916
|
+
showError(err);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
async function submitBuyerEvidence(taskId) {
|
|
1920
|
+
const argument = await input9({ message: "Your argument / evidence description", validate: (v) => v.length > 10 || "Min 10 chars" });
|
|
1921
|
+
const docUrl = await input9({ message: "Document URL (link to evidence)", validate: (v) => v.length > 0 || "At least one document URL required" });
|
|
1922
|
+
const s = spin("Submitting evidence...");
|
|
1923
|
+
try {
|
|
1924
|
+
await api.post(`/dashboard/tasks/${taskId}/evidence`, {
|
|
1925
|
+
argument,
|
|
1926
|
+
documents: [docUrl]
|
|
1927
|
+
});
|
|
1928
|
+
s.succeed(c.success("Evidence submitted!"));
|
|
1929
|
+
showSuccess("Your evidence has been recorded for arbitration.");
|
|
1930
|
+
} catch (err) {
|
|
1931
|
+
s.fail("Failed to submit evidence");
|
|
1932
|
+
showError(err);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
var init_dashboard = __esm({
|
|
1936
|
+
"src/commands/dashboard.ts"() {
|
|
1937
|
+
"use strict";
|
|
1938
|
+
init_api();
|
|
1939
|
+
init_ui();
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
// src/commands/messages.ts
|
|
1944
|
+
var messages_exports = {};
|
|
1945
|
+
__export(messages_exports, {
|
|
1946
|
+
listConversations: () => listConversations,
|
|
1947
|
+
markConversationRead: () => markConversationRead,
|
|
1948
|
+
searchMessages: () => searchMessages,
|
|
1949
|
+
sendConversationMessage: () => sendConversationMessage,
|
|
1950
|
+
viewConversation: () => viewConversation
|
|
1951
|
+
});
|
|
1952
|
+
import { input as input10 } from "@inquirer/prompts";
|
|
1953
|
+
async function listConversations() {
|
|
1954
|
+
const s = spin("Loading conversations...");
|
|
1955
|
+
try {
|
|
1956
|
+
const res = await api.get("/dashboard/messages");
|
|
1957
|
+
s.stop();
|
|
1958
|
+
if (res.conversations.length === 0) {
|
|
1959
|
+
console.log(c.warn("\n No conversations.\n"));
|
|
1960
|
+
return;
|
|
1961
|
+
}
|
|
1962
|
+
section(`Conversations (${res.conversations.length})`);
|
|
1963
|
+
const table = createTable(["Task", "With", "Last Message", "Messages", "Updated"]);
|
|
1964
|
+
for (const conv of res.conversations) {
|
|
1965
|
+
const lastContent = conv.lastMessage?.content || "";
|
|
1966
|
+
const preview = lastContent ? lastContent.length > 35 ? lastContent.slice(0, 35) + "..." : lastContent : c.muted("--");
|
|
1967
|
+
table.push([c.bold(conv.title || conv.taskId.slice(0, 8)), c.cool(conv.counterparty?.name || "\u2014"), preview, c.muted(String(conv.messageCount)), formatDate(conv.updatedAt)]);
|
|
1968
|
+
}
|
|
1969
|
+
console.log(table.toString() + "\n");
|
|
1970
|
+
} catch (err) {
|
|
1971
|
+
s.fail("Failed to load conversations");
|
|
1972
|
+
showError(err);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
async function viewConversation(taskId) {
|
|
1976
|
+
const s = spin("Loading messages...");
|
|
1977
|
+
try {
|
|
1978
|
+
const res = await api.get(`/dashboard/messages/${taskId}`);
|
|
1979
|
+
s.stop();
|
|
1980
|
+
if (res.messages.length === 0) {
|
|
1981
|
+
console.log(c.muted("\n No messages yet.\n"));
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
section(`Messages \u2014 ${res.task?.title || taskId.slice(0, 8)}`);
|
|
1985
|
+
for (const msg of res.messages) {
|
|
1986
|
+
const sender = msg.senderType === "BUYER" ? c.cool("You") : msg.senderType === "AGENT" ? c.warm(res.counterparty?.name || "Agent") : c.muted("System");
|
|
1987
|
+
console.log(` ${sender} ${c.dim(formatDate(msg.createdAt))}`);
|
|
1988
|
+
console.log(` ${msg.content}
|
|
1989
|
+
`);
|
|
1990
|
+
}
|
|
1991
|
+
try {
|
|
1992
|
+
await api.post(`/dashboard/messages/${taskId}/read`);
|
|
1993
|
+
} catch {
|
|
1994
|
+
}
|
|
1995
|
+
} catch (err) {
|
|
1996
|
+
s.fail("Failed to load messages");
|
|
1997
|
+
showError(err);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
async function sendConversationMessage(taskId) {
|
|
2001
|
+
const content = await input10({ message: "Message", validate: (v) => v.length > 0 || "Required" });
|
|
2002
|
+
const s = spin("Sending...");
|
|
2003
|
+
try {
|
|
2004
|
+
await api.post(`/dashboard/messages/${taskId}`, { content });
|
|
2005
|
+
s.succeed(c.success("Message sent!"));
|
|
2006
|
+
} catch (err) {
|
|
2007
|
+
s.fail("Failed to send message");
|
|
2008
|
+
showError(err);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
async function markConversationRead(taskId) {
|
|
2012
|
+
const s = spin("Marking messages as read...");
|
|
2013
|
+
try {
|
|
2014
|
+
const res = await api.post(`/dashboard/messages/${taskId}/read`, {});
|
|
2015
|
+
s.succeed(c.success("Messages marked as read!"));
|
|
2016
|
+
showSuccess(`${res.marked} message${res.marked !== 1 ? "s" : ""} marked as read.`);
|
|
2017
|
+
console.log();
|
|
2018
|
+
} catch (err) {
|
|
2019
|
+
s.fail("Failed to mark messages as read");
|
|
2020
|
+
showError(err);
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
async function searchMessages(query) {
|
|
2024
|
+
if (!query) {
|
|
2025
|
+
query = await input10({ message: "Search messages", validate: (v) => v.length > 0 || "Required" });
|
|
2026
|
+
}
|
|
2027
|
+
const s = spin(`Searching "${query}"...`);
|
|
2028
|
+
try {
|
|
2029
|
+
const res = await api.get("/dashboard/messages/search", { q: query });
|
|
2030
|
+
s.stop();
|
|
2031
|
+
if (res.results.length === 0) {
|
|
2032
|
+
console.log(c.warn(`
|
|
2033
|
+
No messages matching "${query}"
|
|
2034
|
+
`));
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
section(`${res.results.length} results for "${query}"`);
|
|
2038
|
+
for (const r of res.results) {
|
|
2039
|
+
const senderLabel = r.matchSenderType === "BUYER" ? "You" : r.matchSenderType === "AGENT" ? r.counterparty?.name || "Agent" : "System";
|
|
2040
|
+
console.log(` ${c.warm.bold(r.title || r.taskId.slice(0, 8))} ${c.dim(formatDate(r.matchCreatedAt))}`);
|
|
2041
|
+
console.log(` ${c.muted(senderLabel + ":")} ${r.matchSnippet}
|
|
2042
|
+
`);
|
|
2043
|
+
}
|
|
2044
|
+
} catch (err) {
|
|
2045
|
+
s.fail("Search failed");
|
|
2046
|
+
showError(err);
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2049
|
+
var init_messages = __esm({
|
|
2050
|
+
"src/commands/messages.ts"() {
|
|
2051
|
+
"use strict";
|
|
2052
|
+
init_api();
|
|
2053
|
+
init_ui();
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
// src/commands/agents.ts
|
|
2058
|
+
var agents_exports = {};
|
|
2059
|
+
__export(agents_exports, {
|
|
2060
|
+
acceptTask: () => acceptTask,
|
|
2061
|
+
agentStats: () => agentStats,
|
|
2062
|
+
createAgentHireRequest: () => createAgentHireRequest,
|
|
2063
|
+
deleteAgent: () => deleteAgent,
|
|
2064
|
+
deliverTask: () => deliverTask,
|
|
2065
|
+
inbox: () => inbox,
|
|
2066
|
+
listAgentHireRequests: () => listAgentHireRequests,
|
|
2067
|
+
listMyAgents: () => listMyAgents,
|
|
2068
|
+
manageImages: () => manageImages,
|
|
2069
|
+
registerAgent: () => registerAgent,
|
|
2070
|
+
respondAgentHireRequest: () => respondAgentHireRequest,
|
|
2071
|
+
respondToDispute: () => respondToDispute,
|
|
2072
|
+
submitEvidence: () => submitEvidence,
|
|
2073
|
+
updateAgent: () => updateAgent,
|
|
2074
|
+
updateProgress: () => updateProgress,
|
|
2075
|
+
verifyListing: () => verifyListing,
|
|
2076
|
+
viewAgentHireRequest: () => viewAgentHireRequest
|
|
2077
|
+
});
|
|
2078
|
+
import chalk3 from "chalk";
|
|
2079
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
2080
|
+
import { basename, extname } from "path";
|
|
2081
|
+
import { input as input11, select as select10, number as numPrompt5, checkbox } from "@inquirer/prompts";
|
|
2082
|
+
async function listMyAgents() {
|
|
2083
|
+
const s = spin("Loading your listings...");
|
|
2084
|
+
try {
|
|
2085
|
+
const res = await api.get("/dashboard/agents");
|
|
2086
|
+
s.stop();
|
|
2087
|
+
if (res.agents.length === 0) {
|
|
2088
|
+
console.log(
|
|
2089
|
+
c.warn("\n You haven't created any listings yet.") + c.muted('\n Run "g0 listings:create" to create one.\n')
|
|
2090
|
+
);
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
section(`Your Listings (${res.agents.length})`);
|
|
2094
|
+
const table = createTable([
|
|
2095
|
+
"Listing",
|
|
2096
|
+
"Status",
|
|
2097
|
+
"Score",
|
|
2098
|
+
"Rating",
|
|
2099
|
+
"Tasks",
|
|
2100
|
+
"Images",
|
|
2101
|
+
"Earnings"
|
|
2102
|
+
]);
|
|
2103
|
+
for (const a of res.agents) {
|
|
2104
|
+
const imgCount = a.gallery?.length ?? 0;
|
|
2105
|
+
table.push([
|
|
2106
|
+
c.warm.bold(a.name) + "\n" + c.dim(a.slug) + (a.isVerified ? c.cool(" \u2713") : ""),
|
|
2107
|
+
formatStatus(a.status),
|
|
2108
|
+
formatRepScore(a.stats.reputationScore),
|
|
2109
|
+
a.stats.avgRating > 0 ? formatRating(a.stats.avgRating, a.stats.reviewCount) : c.muted("\u2014"),
|
|
2110
|
+
`${a.stats.tasksCompleted} ${c.dim("done")}
|
|
2111
|
+
${c.cool(String(a.stats.activeTasks))} ${c.dim("active")}`,
|
|
2112
|
+
imgCount > 0 ? `${imgCount} ${c.dim("image" + (imgCount !== 1 ? "s" : ""))}` : c.muted("none"),
|
|
2113
|
+
formatPrice(String(a.stats.totalEarnings), a.currency)
|
|
2114
|
+
]);
|
|
2115
|
+
}
|
|
2116
|
+
console.log(table.toString());
|
|
2117
|
+
console.log();
|
|
2118
|
+
} catch (err) {
|
|
2119
|
+
s.fail("Failed to load listings");
|
|
2120
|
+
showError(err);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
async function registerAgent() {
|
|
2124
|
+
console.log(c.warm.bold("\n Create a New Listing\n"));
|
|
2125
|
+
const name = await input11({
|
|
2126
|
+
message: "Listing title",
|
|
2127
|
+
validate: (v) => v.length >= 2 ? true : "Name must be at least 2 characters"
|
|
2128
|
+
});
|
|
2129
|
+
const slug = await input11({
|
|
2130
|
+
message: "Listing slug (e.g. my-coding-agent)",
|
|
2131
|
+
default: name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, ""),
|
|
2132
|
+
validate: (v) => /^[a-z0-9-]+$/.test(v) ? true : "Only lowercase letters, numbers, and hyphens"
|
|
2133
|
+
});
|
|
2134
|
+
const tagline = await input11({
|
|
2135
|
+
message: "Listing tagline (short description)",
|
|
2136
|
+
validate: (v) => v.length >= 5 ? true : "At least 5 characters"
|
|
2137
|
+
});
|
|
2138
|
+
const description = await input11({
|
|
2139
|
+
message: "Listing description",
|
|
2140
|
+
validate: (v) => v.length >= 20 ? true : "At least 20 characters"
|
|
2141
|
+
});
|
|
2142
|
+
console.log(chalk3.bold("\nSelect subcategories for your listing:"));
|
|
2143
|
+
const categoryChoices = [
|
|
2144
|
+
"Python",
|
|
2145
|
+
"JavaScript",
|
|
2146
|
+
"TypeScript",
|
|
2147
|
+
"React",
|
|
2148
|
+
"Next.js",
|
|
2149
|
+
"Vue",
|
|
2150
|
+
"Node.js",
|
|
2151
|
+
"Django",
|
|
2152
|
+
"Flask",
|
|
2153
|
+
"REST APIs",
|
|
2154
|
+
"GraphQL",
|
|
2155
|
+
"AI/ML",
|
|
2156
|
+
"LLM Fine-tuning",
|
|
2157
|
+
"Data Analysis",
|
|
2158
|
+
"Web Scraping",
|
|
2159
|
+
"SEO",
|
|
2160
|
+
"Content Writing",
|
|
2161
|
+
"Digital Marketing",
|
|
2162
|
+
"UI/UX Design",
|
|
2163
|
+
"Logo Design",
|
|
2164
|
+
"Video Editing",
|
|
2165
|
+
"Smart Contracts",
|
|
2166
|
+
"Solidity",
|
|
2167
|
+
"DevOps",
|
|
2168
|
+
"Docker",
|
|
2169
|
+
"AWS",
|
|
2170
|
+
"Customer Support",
|
|
2171
|
+
"Sales Automation",
|
|
2172
|
+
"Cold Calling"
|
|
2173
|
+
].map((s2) => ({ name: s2, value: s2 }));
|
|
2174
|
+
const selectedSubs = await checkbox({
|
|
2175
|
+
message: "Pick subcategories (space to select, enter to confirm)",
|
|
2176
|
+
choices: categoryChoices
|
|
2177
|
+
});
|
|
2178
|
+
if (selectedSubs.length === 0) {
|
|
2179
|
+
showError(new Error("At least one subcategory is required"));
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
const pricingModel = await select10({
|
|
2183
|
+
message: "Pricing model",
|
|
2184
|
+
choices: [
|
|
2185
|
+
{ name: "Per Task", value: "PER_TASK" },
|
|
2186
|
+
{ name: "Hourly", value: "HOURLY" },
|
|
2187
|
+
{ name: "Per Token", value: "PER_TOKEN" },
|
|
2188
|
+
{ name: "Subscription", value: "SUBSCRIPTION" },
|
|
2189
|
+
{ name: "Custom", value: "CUSTOM" }
|
|
2190
|
+
]
|
|
2191
|
+
});
|
|
2192
|
+
const basePrice = await numPrompt5({
|
|
2193
|
+
message: "Base price (USDC)",
|
|
2194
|
+
default: 5,
|
|
2195
|
+
min: 0.01
|
|
2196
|
+
});
|
|
2197
|
+
if (basePrice && basePrice > 0) {
|
|
2198
|
+
const bp = basePrice;
|
|
2199
|
+
const pFee = bp * 0.1;
|
|
2200
|
+
const fFee = 0.5;
|
|
2201
|
+
const receive = bp - pFee - fFee;
|
|
2202
|
+
console.log("");
|
|
2203
|
+
console.log(c.warm.bold(" \u{1F4B0} Fee Breakdown:"));
|
|
2204
|
+
console.log(` List Price: ${c.bold("$" + bp.toFixed(2))}`);
|
|
2205
|
+
console.log(` Platform Fee (10%): ${chalk3.red("-$" + pFee.toFixed(2))}`);
|
|
2206
|
+
console.log(` Facilitation Fee: ${chalk3.red("-$0.50")}`);
|
|
2207
|
+
console.log(c.dim(" \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"));
|
|
2208
|
+
console.log(` You Receive: ${c.success.bold("$" + receive.toFixed(2))}`);
|
|
2209
|
+
console.log("");
|
|
2210
|
+
console.log(c.muted(` \u2139 Buyers pay $${bp.toFixed(2)} (no added fees \u2014 platform fee waived during launch)`));
|
|
2211
|
+
console.log("");
|
|
2212
|
+
}
|
|
2213
|
+
const webhookUrl = await input11({
|
|
2214
|
+
message: "Webhook URL (for receiving tasks)",
|
|
2215
|
+
validate: (v) => v.startsWith("http") ? true : "Must be a valid URL"
|
|
2216
|
+
});
|
|
2217
|
+
const apiEndpoint = await input11({
|
|
2218
|
+
message: "API endpoint (optional)"
|
|
2219
|
+
});
|
|
2220
|
+
const s = spin("Creating listing...");
|
|
2221
|
+
try {
|
|
2222
|
+
const res = await api.post("/agents/register", {
|
|
2223
|
+
name,
|
|
2224
|
+
slug,
|
|
2225
|
+
tagline,
|
|
2226
|
+
description,
|
|
2227
|
+
subcategories: selectedSubs,
|
|
2228
|
+
tags: selectedSubs,
|
|
2229
|
+
pricingModel,
|
|
2230
|
+
basePrice: basePrice ?? 5,
|
|
2231
|
+
executionMode: "REMOTE",
|
|
2232
|
+
webhookUrl: webhookUrl || void 0,
|
|
2233
|
+
apiEndpoint: apiEndpoint || void 0
|
|
2234
|
+
});
|
|
2235
|
+
s.succeed(c.success("Listing created!"));
|
|
2236
|
+
showSuccess(
|
|
2237
|
+
`${c.warm.bold(res.listing.name)} is live at ${c.cool(`/marketplace/${res.listing.slug}`)}`
|
|
2238
|
+
);
|
|
2239
|
+
console.log(c.muted(` Listing ID: ${res.listing.id}
|
|
2240
|
+
`));
|
|
2241
|
+
if (res.fees) {
|
|
2242
|
+
console.log(c.warm.bold(" Fee Summary:"));
|
|
2243
|
+
console.log(` Platform Fee: ${res.fees.platformFeePercent}% of base price`);
|
|
2244
|
+
console.log(` Facilitation Fee: $${res.fees.facilitationFee.toFixed(2)} per task`);
|
|
2245
|
+
console.log(` You Receive: ${c.success.bold("$" + res.fees.youReceive.toFixed(2))} per task`);
|
|
2246
|
+
console.log(` Buyer Fees: ${c.cool(res.fees.buyerFees)}`);
|
|
2247
|
+
console.log("");
|
|
2248
|
+
}
|
|
2249
|
+
if (res.verified) {
|
|
2250
|
+
showSuccess("Listing created and verified! Your agent responded to the heartbeat check.");
|
|
2251
|
+
} else {
|
|
2252
|
+
console.log(chalk3.yellow("\n\u26A0 Listing created but NOT verified."));
|
|
2253
|
+
console.log(chalk3.dim(" Your agent did not respond to the heartbeat check."));
|
|
2254
|
+
console.log(chalk3.dim(" Check your webhook/API endpoint configuration."));
|
|
2255
|
+
}
|
|
2256
|
+
console.log(c.cool(`
|
|
2257
|
+
Upload images with: g0 listings:images ${res.listing?.id ?? "<id>"}
|
|
2258
|
+
`));
|
|
2259
|
+
} catch (err) {
|
|
2260
|
+
s.fail("Failed to create listing");
|
|
2261
|
+
showError(err);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
async function agentStats(agentId) {
|
|
2265
|
+
const s = spin("Loading stats...");
|
|
2266
|
+
try {
|
|
2267
|
+
if (agentId) {
|
|
2268
|
+
const res = await api.get(`/agents/${agentId}`);
|
|
2269
|
+
s.stop();
|
|
2270
|
+
printAgentStats(res.agent);
|
|
2271
|
+
} else {
|
|
2272
|
+
const [statsRes, agentsRes] = await Promise.all([
|
|
2273
|
+
api.get("/dashboard/stats"),
|
|
2274
|
+
api.get("/dashboard/agents")
|
|
2275
|
+
]);
|
|
2276
|
+
s.stop();
|
|
2277
|
+
section("Dashboard Overview");
|
|
2278
|
+
if (agentsRes.agents) {
|
|
2279
|
+
for (const a of agentsRes.agents) {
|
|
2280
|
+
const agent = {
|
|
2281
|
+
...a,
|
|
2282
|
+
basePrice: String(a.basePrice),
|
|
2283
|
+
description: "",
|
|
2284
|
+
tags: [],
|
|
2285
|
+
tasksCompleted: a.stats.tasksCompleted,
|
|
2286
|
+
totalEarnings: String(a.stats.totalEarnings),
|
|
2287
|
+
avgRating: a.stats.avgRating,
|
|
2288
|
+
reviewCount: a.stats.reviewCount,
|
|
2289
|
+
reputationScore: a.stats.reputationScore,
|
|
2290
|
+
successRate: a.stats.successRate,
|
|
2291
|
+
activeTasks: a.stats.activeTasks,
|
|
2292
|
+
maxConcurrent: a.stats.maxConcurrent
|
|
2293
|
+
};
|
|
2294
|
+
printAgentStats(agent);
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
} catch (err) {
|
|
2299
|
+
s.fail("Failed to load stats");
|
|
2300
|
+
showError(err);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
function printAgentStats(agent) {
|
|
2304
|
+
infoBox(`${agent.name} \u2014 Listing Stats`, [
|
|
2305
|
+
`${c.muted("Status:")} ${formatStatus(agent.status)}`,
|
|
2306
|
+
`${c.muted("Rep Score:")} ${formatRepScore(agent.reputationScore)}`,
|
|
2307
|
+
`${c.muted("Rating:")} ${formatRating(agent.avgRating, agent.reviewCount)}`,
|
|
2308
|
+
`${c.muted("Tasks Done:")} ${c.bold(String(agent.tasksCompleted))}`,
|
|
2309
|
+
`${c.muted("Active Tasks:")} ${c.cool(String(agent.activeTasks))} / ${agent.maxConcurrent}`,
|
|
2310
|
+
`${c.muted("Success Rate:")} ${agent.successRate.toFixed(1)}%`,
|
|
2311
|
+
`${c.muted("Total Earned:")} ${c.success.bold("$" + parseFloat(agent.totalEarnings).toFixed(2))} ${c.dim(agent.currency)}`,
|
|
2312
|
+
`${c.muted("Price:")} ${formatPrice(agent.basePrice, agent.currency)} ${c.dim(`(${agent.pricingModel.replace(/_/g, " ").toLowerCase()})`)}`,
|
|
2313
|
+
`${c.muted("Since:")} ${formatDate(agent.createdAt)}`
|
|
2314
|
+
]);
|
|
2315
|
+
console.log();
|
|
2316
|
+
}
|
|
2317
|
+
async function inbox(agentId) {
|
|
2318
|
+
const s = spin("Loading inbox...");
|
|
2319
|
+
try {
|
|
2320
|
+
const res = await api.get(`/agents/${agentId}/inbox`);
|
|
2321
|
+
s.stop();
|
|
2322
|
+
if (res.tasks.length === 0) {
|
|
2323
|
+
console.log(c.muted("\n No pending tasks in inbox.\n"));
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
section(`Listing Inbox (${res.tasks.length} tasks)`);
|
|
2327
|
+
const table = createTable([
|
|
2328
|
+
"ID",
|
|
2329
|
+
"Title",
|
|
2330
|
+
"Buyer",
|
|
2331
|
+
"Budget",
|
|
2332
|
+
"Priority",
|
|
2333
|
+
"Status",
|
|
2334
|
+
"Received"
|
|
2335
|
+
]);
|
|
2336
|
+
for (const t of res.tasks) {
|
|
2337
|
+
table.push([
|
|
2338
|
+
c.dim(t.id.slice(0, 8)),
|
|
2339
|
+
c.bold(t.title),
|
|
2340
|
+
t.buyer?.name || c.muted("\u2014"),
|
|
2341
|
+
formatPrice(t.budget, t.currency),
|
|
2342
|
+
t.priority === "URGENT" ? c.err.bold(t.priority) : t.priority === "HIGH" ? c.warn(t.priority) : c.muted(t.priority),
|
|
2343
|
+
formatStatus(t.status),
|
|
2344
|
+
formatDate(t.createdAt)
|
|
2345
|
+
]);
|
|
2346
|
+
}
|
|
2347
|
+
console.log(table.toString());
|
|
2348
|
+
console.log();
|
|
2349
|
+
} catch (err) {
|
|
2350
|
+
s.fail("Failed to load inbox");
|
|
2351
|
+
showError(err);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
async function verifyListing(agentId) {
|
|
2355
|
+
const s = spin("Sending heartbeat verification...");
|
|
2356
|
+
try {
|
|
2357
|
+
const data = await api.post(`/agents/${agentId}/verify`);
|
|
2358
|
+
s.stop();
|
|
2359
|
+
if (data.verified) {
|
|
2360
|
+
showSuccess(data.message);
|
|
2361
|
+
} else {
|
|
2362
|
+
console.log(chalk3.yellow(`
|
|
2363
|
+
\u26A0 ${data.message}`));
|
|
2364
|
+
}
|
|
2365
|
+
} catch (err) {
|
|
2366
|
+
s.stop();
|
|
2367
|
+
showError(err);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
async function acceptTask(agentId, taskId) {
|
|
2371
|
+
const price = await numPrompt5({
|
|
2372
|
+
message: "Your proposed price (USDC)",
|
|
2373
|
+
min: 0.01
|
|
2374
|
+
});
|
|
2375
|
+
const estimatedMs = await numPrompt5({
|
|
2376
|
+
message: "Estimated time (minutes)",
|
|
2377
|
+
default: 60,
|
|
2378
|
+
min: 1
|
|
2379
|
+
});
|
|
2380
|
+
const s = spin("Accepting task...");
|
|
2381
|
+
try {
|
|
2382
|
+
await api.post(`/agents/${agentId}/propose`, {
|
|
2383
|
+
taskId,
|
|
2384
|
+
proposedPrice: price,
|
|
2385
|
+
estimatedMs: (estimatedMs ?? 60) * 6e4,
|
|
2386
|
+
message: "Task accepted via g0 CLI"
|
|
2387
|
+
});
|
|
2388
|
+
s.succeed(c.success("Task accepted!"));
|
|
2389
|
+
showSuccess(`You've accepted task ${c.dim(taskId.slice(0, 8))}`);
|
|
2390
|
+
} catch (err) {
|
|
2391
|
+
s.fail("Failed to accept task");
|
|
2392
|
+
showError(err);
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
async function updateProgress(taskId) {
|
|
2396
|
+
const progress = await numPrompt5({
|
|
2397
|
+
message: "Progress (%)",
|
|
2398
|
+
min: 0,
|
|
2399
|
+
max: 100
|
|
2400
|
+
});
|
|
2401
|
+
const message = await input11({
|
|
2402
|
+
message: "Progress update message"
|
|
2403
|
+
});
|
|
2404
|
+
const s = spin("Updating...");
|
|
2405
|
+
try {
|
|
2406
|
+
await api.patch(`/tasks/${taskId}/progress`, {
|
|
2407
|
+
progress: progress ?? 0,
|
|
2408
|
+
progressMessage: message || void 0
|
|
2409
|
+
});
|
|
2410
|
+
s.succeed(c.success("Progress updated!"));
|
|
2411
|
+
} catch (err) {
|
|
2412
|
+
s.fail("Failed to update progress");
|
|
2413
|
+
showError(err);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
async function deliverTask(agentId, taskId) {
|
|
2417
|
+
const summary = await input11({
|
|
2418
|
+
message: "Delivery summary",
|
|
2419
|
+
validate: (v) => v.length > 0 ? true : "Summary required"
|
|
2420
|
+
});
|
|
2421
|
+
const completionMessage = await input11({
|
|
2422
|
+
message: "Completion message to buyer (optional)"
|
|
2423
|
+
});
|
|
2424
|
+
const s = spin("Delivering task...");
|
|
2425
|
+
try {
|
|
2426
|
+
const body = { summary };
|
|
2427
|
+
if (completionMessage) body.completionMessage = completionMessage;
|
|
2428
|
+
const res = await api.post(`/agents/${agentId}/tasks/${taskId}/deliver`, body);
|
|
2429
|
+
s.succeed(c.success("Task delivered!"));
|
|
2430
|
+
showSuccess("The buyer will review your delivery.");
|
|
2431
|
+
if (res.task?.autoConfirmAt) {
|
|
2432
|
+
console.log(c.muted(` Auto-confirms: ${formatDate(res.task.autoConfirmAt)}`));
|
|
2433
|
+
}
|
|
2434
|
+
console.log();
|
|
2435
|
+
} catch (err) {
|
|
2436
|
+
s.fail("Failed to deliver task");
|
|
2437
|
+
showError(err);
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
async function respondToDispute(agentId, taskId) {
|
|
2441
|
+
const action = await select10({
|
|
2442
|
+
message: "How do you want to respond?",
|
|
2443
|
+
choices: [
|
|
2444
|
+
{ name: "Accept & Redeliver \u2014 fix and redeliver the work", value: "accept" },
|
|
2445
|
+
{ name: "Reject \u2014 escalate to platform arbitration", value: "reject" }
|
|
2446
|
+
]
|
|
2447
|
+
});
|
|
2448
|
+
let message = "";
|
|
2449
|
+
if (action === "accept") {
|
|
2450
|
+
message = await input11({ message: "Message to buyer (what you'll fix)", validate: (v) => v.length > 0 ? true : "Required" });
|
|
2451
|
+
} else {
|
|
2452
|
+
message = await input11({ message: "Reason for rejecting the dispute", validate: (v) => v.length > 0 ? true : "Required" });
|
|
2453
|
+
}
|
|
2454
|
+
const s = spin("Submitting response...");
|
|
2455
|
+
try {
|
|
2456
|
+
await api.post(`/agents/${agentId}/tasks/${taskId}/dispute`, { action, message });
|
|
2457
|
+
s.succeed(c.success("Dispute response submitted!"));
|
|
2458
|
+
if (action === "accept") {
|
|
2459
|
+
showSuccess("Task moved back to EXECUTING. Redeliver when ready.");
|
|
2460
|
+
} else {
|
|
2461
|
+
showSuccess("Escalated to arbitration. Submit evidence to support your case.");
|
|
2462
|
+
console.log(c.muted(` Submit evidence: g0 agents:evidence ${agentId} ${taskId}
|
|
2463
|
+
`));
|
|
2464
|
+
}
|
|
2465
|
+
} catch (err) {
|
|
2466
|
+
s.fail("Failed to respond to dispute");
|
|
2467
|
+
showError(err);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
async function submitEvidence(agentId, taskId) {
|
|
2471
|
+
const description = await input11({ message: "Evidence description", validate: (v) => v.length > 5 ? true : "Min 5 chars" });
|
|
2472
|
+
const details = await input11({ message: "Supporting details (optional)" });
|
|
2473
|
+
const s = spin("Submitting evidence...");
|
|
2474
|
+
try {
|
|
2475
|
+
await api.post(`/agents/${agentId}/tasks/${taskId}/evidence`, {
|
|
2476
|
+
description,
|
|
2477
|
+
details: details || void 0
|
|
2478
|
+
});
|
|
2479
|
+
s.succeed(c.success("Evidence submitted!"));
|
|
2480
|
+
showSuccess("Your evidence has been recorded for arbitration review.");
|
|
2481
|
+
} catch (err) {
|
|
2482
|
+
s.fail("Failed to submit evidence");
|
|
2483
|
+
showError(err);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
async function updateAgent(agentId) {
|
|
2487
|
+
const s = spin("Loading current listing...");
|
|
2488
|
+
let agent;
|
|
2489
|
+
try {
|
|
2490
|
+
const res = await api.get(`/agents/${agentId}`);
|
|
2491
|
+
agent = res.agent;
|
|
2492
|
+
s.stop();
|
|
2493
|
+
} catch (err) {
|
|
2494
|
+
s.fail("Failed to load listing");
|
|
2495
|
+
showError(err);
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2498
|
+
console.log(c.warm.bold(`
|
|
2499
|
+
Update: ${agent.name}
|
|
2500
|
+
`));
|
|
2501
|
+
console.log(c.muted(" Press Enter to keep current value.\n"));
|
|
2502
|
+
const name = await input11({ message: "Name", default: agent.name });
|
|
2503
|
+
const tagline = await input11({ message: "Tagline", default: agent.tagline });
|
|
2504
|
+
const description = await input11({ message: "Description", default: agent.description });
|
|
2505
|
+
const basePrice = await numPrompt5({ message: "Base price (USDC)", default: parseFloat(agent.basePrice), min: 0.01 });
|
|
2506
|
+
const updates = {};
|
|
2507
|
+
if (name !== agent.name) updates.name = name;
|
|
2508
|
+
if (tagline !== agent.tagline) updates.tagline = tagline;
|
|
2509
|
+
if (description !== agent.description) updates.description = description;
|
|
2510
|
+
if (basePrice !== void 0 && basePrice !== parseFloat(agent.basePrice)) updates.basePrice = basePrice;
|
|
2511
|
+
if (Object.keys(updates).length === 0) {
|
|
2512
|
+
console.log(c.muted("\n No changes made.\n"));
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2515
|
+
const s2 = spin("Updating listing...");
|
|
2516
|
+
try {
|
|
2517
|
+
await api.patch(`/agents/${agentId}`, updates);
|
|
2518
|
+
s2.succeed(c.success("Listing updated!"));
|
|
2519
|
+
} catch (err) {
|
|
2520
|
+
s2.fail("Failed to update listing");
|
|
2521
|
+
showError(err);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
async function deleteAgent(agentId) {
|
|
2525
|
+
const { confirm: confirm4 } = await import("@inquirer/prompts");
|
|
2526
|
+
const yes = await confirm4({ message: "Are you sure? This permanently deletes the listing and all data.", default: false });
|
|
2527
|
+
if (!yes) {
|
|
2528
|
+
console.log(c.muted("\n Cancelled.\n"));
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
const s = spin("Deleting listing...");
|
|
2532
|
+
try {
|
|
2533
|
+
await api.delete(`/agents/${agentId}`);
|
|
2534
|
+
s.succeed(c.success("Listing deleted."));
|
|
2535
|
+
} catch (err) {
|
|
2536
|
+
s.fail("Failed to delete listing");
|
|
2537
|
+
showError(err);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
async function manageImages(agentId) {
|
|
2541
|
+
const s = spin("Loading listing images...");
|
|
2542
|
+
let current;
|
|
2543
|
+
try {
|
|
2544
|
+
current = await api.get(`/agents/${agentId}/images`);
|
|
2545
|
+
s.stop();
|
|
2546
|
+
} catch (err) {
|
|
2547
|
+
s.fail("Failed to load images");
|
|
2548
|
+
showError(err);
|
|
2549
|
+
return;
|
|
2550
|
+
}
|
|
2551
|
+
const showStatus = (data) => {
|
|
2552
|
+
const count = data.gallery.length;
|
|
2553
|
+
console.log();
|
|
2554
|
+
section(`Listing Images (${count}/5)`);
|
|
2555
|
+
if (count === 0) {
|
|
2556
|
+
console.log(c.muted(" No images uploaded yet.\n"));
|
|
2557
|
+
} else {
|
|
2558
|
+
for (let i = 0; i < data.gallery.length; i++) {
|
|
2559
|
+
const isPrimary = data.coverImage === data.gallery[i];
|
|
2560
|
+
const label = isPrimary ? c.cool(" [PRIMARY]") : "";
|
|
2561
|
+
console.log(` ${c.dim(`[${i}]`)} ${c.bold(basename(data.gallery[i]))}${label}`);
|
|
2562
|
+
}
|
|
2563
|
+
console.log();
|
|
2564
|
+
}
|
|
2565
|
+
};
|
|
2566
|
+
showStatus(current);
|
|
2567
|
+
let running = true;
|
|
2568
|
+
while (running) {
|
|
2569
|
+
const action = await select10({
|
|
2570
|
+
message: "What would you like to do?",
|
|
2571
|
+
choices: [
|
|
2572
|
+
{ name: "Upload image", value: "upload" },
|
|
2573
|
+
{ name: "Remove image", value: "remove" },
|
|
2574
|
+
{ name: "Set primary image", value: "primary" },
|
|
2575
|
+
{ name: "Back", value: "back" }
|
|
2576
|
+
]
|
|
2577
|
+
});
|
|
2578
|
+
switch (action) {
|
|
2579
|
+
case "upload": {
|
|
2580
|
+
if (current.gallery.length >= 5) {
|
|
2581
|
+
console.log(c.warn("\n Maximum 5 images reached. Remove one first.\n"));
|
|
2582
|
+
break;
|
|
2583
|
+
}
|
|
2584
|
+
const filePath = await input11({
|
|
2585
|
+
message: "Path to image file",
|
|
2586
|
+
validate: (v) => {
|
|
2587
|
+
if (!v.trim()) return "File path required";
|
|
2588
|
+
const ext2 = extname(v).toLowerCase();
|
|
2589
|
+
if (!SUPPORTED_IMAGE_FORMATS.includes(ext2)) {
|
|
2590
|
+
return `Unsupported format. Use: ${SUPPORTED_IMAGE_FORMATS.join(", ")}`;
|
|
2591
|
+
}
|
|
2592
|
+
return true;
|
|
2593
|
+
}
|
|
2594
|
+
});
|
|
2595
|
+
let fileBuffer;
|
|
2596
|
+
try {
|
|
2597
|
+
fileBuffer = readFileSync3(filePath.trim());
|
|
2598
|
+
} catch {
|
|
2599
|
+
console.log(c.err("\n Could not read file. Check the path and try again.\n"));
|
|
2600
|
+
break;
|
|
2601
|
+
}
|
|
2602
|
+
if (fileBuffer.length > MAX_IMAGE_SIZE) {
|
|
2603
|
+
console.log(c.err(`
|
|
2604
|
+
File too large (${(fileBuffer.length / 1024 / 1024).toFixed(1)}MB). Max is 5MB.
|
|
2605
|
+
`));
|
|
2606
|
+
break;
|
|
2607
|
+
}
|
|
2608
|
+
const ext = extname(filePath.trim()).toLowerCase();
|
|
2609
|
+
const mimeMap = {
|
|
2610
|
+
".jpg": "image/jpeg",
|
|
2611
|
+
".jpeg": "image/jpeg",
|
|
2612
|
+
".png": "image/png",
|
|
2613
|
+
".webp": "image/webp",
|
|
2614
|
+
".gif": "image/gif"
|
|
2615
|
+
};
|
|
2616
|
+
const mimeType = mimeMap[ext] ?? "application/octet-stream";
|
|
2617
|
+
const base64Data = fileBuffer.toString("base64");
|
|
2618
|
+
const us = spin("Uploading image...");
|
|
2619
|
+
try {
|
|
2620
|
+
current = await api.post(`/agents/${agentId}/images`, {
|
|
2621
|
+
image: base64Data,
|
|
2622
|
+
filename: basename(filePath.trim()),
|
|
2623
|
+
mimeType
|
|
2624
|
+
});
|
|
2625
|
+
us.succeed(c.success("Image uploaded!"));
|
|
2626
|
+
showStatus(current);
|
|
2627
|
+
} catch (err) {
|
|
2628
|
+
us.fail("Failed to upload image");
|
|
2629
|
+
showError(err);
|
|
2630
|
+
}
|
|
2631
|
+
break;
|
|
2632
|
+
}
|
|
2633
|
+
case "remove": {
|
|
2634
|
+
if (current.gallery.length === 0) {
|
|
2635
|
+
console.log(c.muted("\n No images to remove.\n"));
|
|
2636
|
+
break;
|
|
2637
|
+
}
|
|
2638
|
+
const removeIdx = await select10({
|
|
2639
|
+
message: "Which image to remove?",
|
|
2640
|
+
choices: current.gallery.map((url, i) => {
|
|
2641
|
+
const isPrimary = current.coverImage === url;
|
|
2642
|
+
return {
|
|
2643
|
+
name: `[${i}] ${basename(url)}${isPrimary ? " (primary)" : ""}`,
|
|
2644
|
+
value: i
|
|
2645
|
+
};
|
|
2646
|
+
})
|
|
2647
|
+
});
|
|
2648
|
+
const ds = spin("Removing image...");
|
|
2649
|
+
try {
|
|
2650
|
+
const { getApiKey: getApiKey2, getApiUrl: getApiUrl2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2651
|
+
const baseUrl = getApiUrl2();
|
|
2652
|
+
const apiKey = getApiKey2();
|
|
2653
|
+
const res = await fetch(`${baseUrl}/api/v1/agents/${agentId}/images`, {
|
|
2654
|
+
method: "DELETE",
|
|
2655
|
+
headers: {
|
|
2656
|
+
"Content-Type": "application/json",
|
|
2657
|
+
"User-Agent": "@g0hub/cli/1.0.0",
|
|
2658
|
+
Authorization: `Bearer ${apiKey}`
|
|
2659
|
+
},
|
|
2660
|
+
body: JSON.stringify({ index: removeIdx })
|
|
2661
|
+
});
|
|
2662
|
+
if (!res.ok) {
|
|
2663
|
+
const errBody = await res.json().catch(() => ({}));
|
|
2664
|
+
throw new Error(errBody.error ?? `HTTP ${res.status}`);
|
|
2665
|
+
}
|
|
2666
|
+
current = await res.json();
|
|
2667
|
+
ds.succeed(c.success("Image removed!"));
|
|
2668
|
+
showStatus(current);
|
|
2669
|
+
} catch (err) {
|
|
2670
|
+
ds.fail("Failed to remove image");
|
|
2671
|
+
showError(err);
|
|
2672
|
+
}
|
|
2673
|
+
break;
|
|
2674
|
+
}
|
|
2675
|
+
case "primary": {
|
|
2676
|
+
if (current.gallery.length === 0) {
|
|
2677
|
+
console.log(c.muted("\n No images to set as primary.\n"));
|
|
2678
|
+
break;
|
|
2679
|
+
}
|
|
2680
|
+
const primaryIdx = await select10({
|
|
2681
|
+
message: "Which image to set as primary?",
|
|
2682
|
+
choices: current.gallery.map((url, i) => {
|
|
2683
|
+
const isPrimary = current.coverImage === url;
|
|
2684
|
+
return {
|
|
2685
|
+
name: `[${i}] ${basename(url)}${isPrimary ? " (current primary)" : ""}`,
|
|
2686
|
+
value: i
|
|
2687
|
+
};
|
|
2688
|
+
})
|
|
2689
|
+
});
|
|
2690
|
+
const ps = spin("Setting primary image...");
|
|
2691
|
+
try {
|
|
2692
|
+
current = await api.patch(`/agents/${agentId}/images`, {
|
|
2693
|
+
primaryIndex: primaryIdx
|
|
2694
|
+
});
|
|
2695
|
+
ps.succeed(c.success("Primary image updated!"));
|
|
2696
|
+
showStatus(current);
|
|
2697
|
+
} catch (err) {
|
|
2698
|
+
ps.fail("Failed to set primary image");
|
|
2699
|
+
showError(err);
|
|
2700
|
+
}
|
|
2701
|
+
break;
|
|
2702
|
+
}
|
|
2703
|
+
case "back":
|
|
2704
|
+
running = false;
|
|
2705
|
+
break;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
async function listAgentHireRequests(agentId) {
|
|
2710
|
+
const s = spin("Loading hire requests...");
|
|
2711
|
+
try {
|
|
2712
|
+
const res = await api.get(`/agents/${agentId}/hire-requests`);
|
|
2713
|
+
s.stop();
|
|
2714
|
+
if (res.hireRequests.length === 0) {
|
|
2715
|
+
console.log(c.muted("\n No hire requests for this agent.\n"));
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2718
|
+
section(`Agent Hire Requests (${res.hireRequests.length})`);
|
|
2719
|
+
const table = createTable(["ID", "Title", "Buyer", "Price", "From", "Status", "Date"]);
|
|
2720
|
+
for (const r of res.hireRequests) {
|
|
2721
|
+
table.push([
|
|
2722
|
+
c.dim(r.id.slice(0, 8)),
|
|
2723
|
+
c.bold(r.title),
|
|
2724
|
+
r.buyer?.name || c.muted("\u2014"),
|
|
2725
|
+
formatPrice(r.price, r.currency),
|
|
2726
|
+
r.initiatedBy === "BUYER" ? c.cool("Buyer") : c.warm("Agent"),
|
|
2727
|
+
formatStatus(r.status),
|
|
2728
|
+
formatDate(r.createdAt)
|
|
2729
|
+
]);
|
|
2730
|
+
}
|
|
2731
|
+
console.log(table.toString());
|
|
2732
|
+
console.log();
|
|
2733
|
+
} catch (err) {
|
|
2734
|
+
s.fail("Failed to load hire requests");
|
|
2735
|
+
showError(err);
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
async function createAgentHireRequest(agentId) {
|
|
2739
|
+
const { number: numPrompt6 } = await import("@inquirer/prompts");
|
|
2740
|
+
const taskId = await input11({
|
|
2741
|
+
message: "Task ID (existing conversation)",
|
|
2742
|
+
validate: (v) => v.length > 0 || "Required"
|
|
2743
|
+
});
|
|
2744
|
+
const title = await input11({
|
|
2745
|
+
message: "Hire request title",
|
|
2746
|
+
validate: (v) => v.length > 0 || "Required"
|
|
2747
|
+
});
|
|
2748
|
+
const description = await input11({
|
|
2749
|
+
message: "Description of the work",
|
|
2750
|
+
validate: (v) => v.length > 0 || "Required"
|
|
2751
|
+
});
|
|
2752
|
+
const deliverableItem = await input11({
|
|
2753
|
+
message: "Primary deliverable",
|
|
2754
|
+
validate: (v) => v.length > 0 || "Required"
|
|
2755
|
+
});
|
|
2756
|
+
const price = await numPrompt6({
|
|
2757
|
+
message: "Price (USDC)",
|
|
2758
|
+
min: 0.01,
|
|
2759
|
+
default: 10
|
|
2760
|
+
});
|
|
2761
|
+
const estimatedDays = await numPrompt6({
|
|
2762
|
+
message: "Estimated days to complete (optional)",
|
|
2763
|
+
min: 1
|
|
2764
|
+
});
|
|
2765
|
+
const s = spin("Creating hire request...");
|
|
2766
|
+
try {
|
|
2767
|
+
const body = {
|
|
2768
|
+
taskId,
|
|
2769
|
+
title,
|
|
2770
|
+
description,
|
|
2771
|
+
deliverables: [{ item: deliverableItem }],
|
|
2772
|
+
price: price ?? 10
|
|
2773
|
+
};
|
|
2774
|
+
if (estimatedDays) body.estimatedDays = estimatedDays;
|
|
2775
|
+
const res = await api.post(`/agents/${agentId}/hire-requests`, body);
|
|
2776
|
+
s.succeed(c.success("Hire request created!"));
|
|
2777
|
+
showSuccess(`Request ${c.dim(res.hireRequest.id.slice(0, 8))} sent to buyer.`);
|
|
2778
|
+
console.log();
|
|
2779
|
+
} catch (err) {
|
|
2780
|
+
s.fail("Failed to create hire request");
|
|
2781
|
+
showError(err);
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
async function viewAgentHireRequest(agentId, requestId) {
|
|
2785
|
+
const s = spin("Loading hire request...");
|
|
2786
|
+
try {
|
|
2787
|
+
const res = await api.get(`/agents/${agentId}/hire-requests/${requestId}`);
|
|
2788
|
+
const r = res.hireRequest;
|
|
2789
|
+
s.stop();
|
|
2790
|
+
infoBox(`Hire Request: ${r.title}`, [
|
|
2791
|
+
`${c.muted("ID:")} ${c.dim(r.id)}`,
|
|
2792
|
+
`${c.muted("Buyer:")} ${r.buyer?.name || c.muted("\u2014")}`,
|
|
2793
|
+
`${c.muted("Price:")} ${formatPrice(r.price, r.currency)}`,
|
|
2794
|
+
`${c.muted("Status:")} ${formatStatus(r.status)}`,
|
|
2795
|
+
`${c.muted("Initiated By:")} ${r.initiatedBy === "BUYER" ? c.cool("Buyer") : c.warm("Agent")}`,
|
|
2796
|
+
...r.counterPrice ? [`${c.muted("Counter:")} ${formatPrice(r.counterPrice, r.currency)}`] : [],
|
|
2797
|
+
...r.counterNote ? [`${c.muted("Counter Note:")} ${r.counterNote}`] : [],
|
|
2798
|
+
...r.responseNote ? [`${c.muted("Response:")} ${r.responseNote}`] : [],
|
|
2799
|
+
...r.estimatedDays ? [`${c.muted("Est. Days:")} ${r.estimatedDays}`] : [],
|
|
2800
|
+
`${c.muted("Created:")} ${formatDate(r.createdAt)}`,
|
|
2801
|
+
...r.respondedAt ? [`${c.muted("Responded:")} ${formatDate(r.respondedAt)}`] : [],
|
|
2802
|
+
...r.task ? [`${c.muted("Task:")} ${c.dim(r.task.id.slice(0, 8))} \u2014 ${formatStatus(r.task.status)}`] : []
|
|
2803
|
+
]);
|
|
2804
|
+
if (r.description) {
|
|
2805
|
+
console.log(c.muted("\n Description:"));
|
|
2806
|
+
console.log(" " + r.description + "\n");
|
|
2807
|
+
}
|
|
2808
|
+
} catch (err) {
|
|
2809
|
+
s.fail("Failed to load hire request");
|
|
2810
|
+
showError(err);
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
async function respondAgentHireRequest(agentId, requestId) {
|
|
2814
|
+
const { number: numPrompt6 } = await import("@inquirer/prompts");
|
|
2815
|
+
const action = await select10({
|
|
2816
|
+
message: "How do you want to respond?",
|
|
2817
|
+
choices: [
|
|
2818
|
+
{ name: "Accept \u2014 agree to the hire request", value: "accept" },
|
|
2819
|
+
{ name: "Reject \u2014 decline the hire request", value: "reject" },
|
|
2820
|
+
{ name: "Negotiate \u2014 propose a counter price", value: "negotiate" }
|
|
2821
|
+
]
|
|
2822
|
+
});
|
|
2823
|
+
let note;
|
|
2824
|
+
let counterPrice;
|
|
2825
|
+
if (action === "negotiate") {
|
|
2826
|
+
counterPrice = await numPrompt6({ message: "Counter price (USDC)", min: 0.01 }) ?? void 0;
|
|
2827
|
+
if (!counterPrice) {
|
|
2828
|
+
console.log(c.err("\n Counter price is required for negotiation.\n"));
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
note = await input11({ message: "Note (optional)" }) || void 0;
|
|
2833
|
+
const s = spin("Sending response...");
|
|
2834
|
+
try {
|
|
2835
|
+
const body = { action };
|
|
2836
|
+
if (note) body.note = note;
|
|
2837
|
+
if (counterPrice) body.counterPrice = counterPrice;
|
|
2838
|
+
const res = await api.post(
|
|
2839
|
+
`/agents/${agentId}/hire-requests/${requestId}`,
|
|
2840
|
+
body
|
|
2841
|
+
);
|
|
2842
|
+
s.succeed(c.success("Response sent!"));
|
|
2843
|
+
if (action === "accept") {
|
|
2844
|
+
showSuccess("Hire request accepted. Buyer will be notified to complete payment.");
|
|
2845
|
+
} else if (action === "reject") {
|
|
2846
|
+
showSuccess("Hire request declined.");
|
|
2847
|
+
} else {
|
|
2848
|
+
showSuccess(`Counter-offer of ${formatPrice(counterPrice)} sent.`);
|
|
2849
|
+
}
|
|
2850
|
+
console.log();
|
|
2851
|
+
} catch (err) {
|
|
2852
|
+
s.fail("Failed to respond");
|
|
2853
|
+
showError(err);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
var SUPPORTED_IMAGE_FORMATS, MAX_IMAGE_SIZE;
|
|
2857
|
+
var init_agents = __esm({
|
|
2858
|
+
"src/commands/agents.ts"() {
|
|
2859
|
+
"use strict";
|
|
2860
|
+
init_api();
|
|
2861
|
+
init_ui();
|
|
2862
|
+
SUPPORTED_IMAGE_FORMATS = [".jpg", ".jpeg", ".png", ".webp", ".gif"];
|
|
2863
|
+
MAX_IMAGE_SIZE = 5 * 1024 * 1024;
|
|
2864
|
+
}
|
|
2865
|
+
});
|
|
2866
|
+
|
|
2867
|
+
// src/commands/keys.ts
|
|
2868
|
+
var keys_exports = {};
|
|
2869
|
+
__export(keys_exports, {
|
|
2870
|
+
createKey: () => createKey,
|
|
2871
|
+
listKeys: () => listKeys,
|
|
2872
|
+
revokeKey: () => revokeKey
|
|
2873
|
+
});
|
|
2874
|
+
import { input as input12, select as select11, confirm as confirm3 } from "@inquirer/prompts";
|
|
2875
|
+
async function listKeys() {
|
|
2876
|
+
const s = spin("Loading API keys...");
|
|
2877
|
+
try {
|
|
2878
|
+
const res = await api.get("/user/api-keys");
|
|
2879
|
+
s.stop();
|
|
2880
|
+
if (res.apiKeys.length === 0) {
|
|
2881
|
+
console.log(
|
|
2882
|
+
c.warn("\n No API keys.") + c.muted(' Run "g0 keys:create" to generate one.\n')
|
|
2883
|
+
);
|
|
2884
|
+
return;
|
|
2885
|
+
}
|
|
2886
|
+
section(`API Keys (${res.apiKeys.length})`);
|
|
2887
|
+
const table = createTable([
|
|
2888
|
+
"Name",
|
|
2889
|
+
"Prefix",
|
|
2890
|
+
"Status",
|
|
2891
|
+
"Permissions",
|
|
2892
|
+
"Requests",
|
|
2893
|
+
"Last Used"
|
|
2894
|
+
]);
|
|
2895
|
+
for (const key of res.apiKeys) {
|
|
2896
|
+
table.push([
|
|
2897
|
+
c.bold(key.name),
|
|
2898
|
+
c.dim(key.keyPrefix + "..."),
|
|
2899
|
+
key.isActive ? c.success("active") : c.err("revoked"),
|
|
2900
|
+
key.permissions.length > 0 ? key.permissions.join(", ") : c.muted("all"),
|
|
2901
|
+
String(key.requestCount),
|
|
2902
|
+
key.lastUsedAt ? formatDate(key.lastUsedAt) : c.muted("never")
|
|
2903
|
+
]);
|
|
2904
|
+
}
|
|
2905
|
+
console.log(table.toString());
|
|
2906
|
+
console.log();
|
|
2907
|
+
} catch (err) {
|
|
2908
|
+
s.fail("Failed to load keys");
|
|
2909
|
+
showError(err);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
async function createKey() {
|
|
2913
|
+
const name = await input12({
|
|
2914
|
+
message: "Key name (e.g. 'production', 'my-bot')",
|
|
2915
|
+
validate: (v) => v.length > 0 ? true : "Name required"
|
|
2916
|
+
});
|
|
2917
|
+
const permissions = await select11({
|
|
2918
|
+
message: "Permissions",
|
|
2919
|
+
choices: [
|
|
2920
|
+
{ name: "Full access (all permissions)", value: "all" },
|
|
2921
|
+
{ name: "Read only (marketplace, agents)", value: "read" },
|
|
2922
|
+
{ name: "Agent management only", value: "agent" },
|
|
2923
|
+
{ name: "Task management only", value: "task" }
|
|
2924
|
+
]
|
|
2925
|
+
});
|
|
2926
|
+
const permList = permissions === "all" ? ["tasks:read", "tasks:write", "agents:read", "agents:write", "billing:read"] : permissions === "read" ? ["tasks:read", "agents:read", "billing:read"] : permissions === "agent" ? ["agents:read", "agents:write"] : ["tasks:read", "tasks:write"];
|
|
2927
|
+
const s = spin("Creating API key...");
|
|
2928
|
+
try {
|
|
2929
|
+
const res = await api.post(
|
|
2930
|
+
"/user/api-keys",
|
|
2931
|
+
{ name, permissions: permList }
|
|
2932
|
+
);
|
|
2933
|
+
s.succeed(c.success("API key created!"));
|
|
2934
|
+
console.log();
|
|
2935
|
+
console.log(c.warn.bold(" \u26A0 Save this key \u2014 it won't be shown again:\n"));
|
|
2936
|
+
console.log(" " + c.warm.bold(res.key));
|
|
2937
|
+
console.log();
|
|
2938
|
+
console.log(c.muted(" Use with: g0 auth:key " + res.key));
|
|
2939
|
+
console.log(c.muted(" Or set: Authorization: Bearer " + res.key));
|
|
2940
|
+
console.log();
|
|
2941
|
+
} catch (err) {
|
|
2942
|
+
s.fail("Failed to create key");
|
|
2943
|
+
showError(err);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
async function revokeKey(keyId) {
|
|
2947
|
+
if (!keyId) {
|
|
2948
|
+
const s = spin("Loading keys...");
|
|
2949
|
+
try {
|
|
2950
|
+
const res = await api.get("/user/api-keys");
|
|
2951
|
+
s.stop();
|
|
2952
|
+
const activeKeys = res.apiKeys.filter((k) => k.isActive);
|
|
2953
|
+
if (activeKeys.length === 0) {
|
|
2954
|
+
console.log(c.muted("\n No active keys to revoke.\n"));
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2957
|
+
keyId = await select11({
|
|
2958
|
+
message: "Select key to revoke",
|
|
2959
|
+
choices: activeKeys.map((k) => ({
|
|
2960
|
+
name: `${k.name} (${k.keyPrefix}...)`,
|
|
2961
|
+
value: k.id
|
|
2962
|
+
}))
|
|
2963
|
+
});
|
|
2964
|
+
} catch (err) {
|
|
2965
|
+
s.fail("Failed to load keys");
|
|
2966
|
+
showError(err);
|
|
2967
|
+
return;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
const yes = await confirm3({
|
|
2971
|
+
message: "Are you sure? This cannot be undone.",
|
|
2972
|
+
default: false
|
|
2973
|
+
});
|
|
2974
|
+
if (!yes) {
|
|
2975
|
+
console.log(c.muted("\n Cancelled.\n"));
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
const s2 = spin("Revoking key...");
|
|
2979
|
+
try {
|
|
2980
|
+
await api.delete(`/user/api-keys/${keyId}`);
|
|
2981
|
+
s2.succeed(c.success("Key revoked!"));
|
|
2982
|
+
} catch (err) {
|
|
2983
|
+
s2.fail("Failed to revoke key");
|
|
2984
|
+
showError(err);
|
|
2985
|
+
}
|
|
2986
|
+
}
|
|
2987
|
+
var init_keys = __esm({
|
|
2988
|
+
"src/commands/keys.ts"() {
|
|
2989
|
+
"use strict";
|
|
2990
|
+
init_api();
|
|
2991
|
+
init_ui();
|
|
2992
|
+
}
|
|
2993
|
+
});
|
|
2994
|
+
|
|
2995
|
+
// src/index.ts
|
|
2996
|
+
init_ui();
|
|
2997
|
+
init_config();
|
|
2998
|
+
import { Command } from "commander";
|
|
2999
|
+
var program = new Command();
|
|
3000
|
+
program.name("g0").description(
|
|
3001
|
+
"CLI for the g0 AI Agent Marketplace \u2014 hire agents, manage tasks, deploy services, and earn money."
|
|
3002
|
+
).version("0.1.0");
|
|
3003
|
+
program.command("login").description("Sign in to your g0 account").action(async () => {
|
|
3004
|
+
const { login: login2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3005
|
+
await login2();
|
|
3006
|
+
});
|
|
3007
|
+
program.command("register").description("Create a new g0 account").action(async () => {
|
|
3008
|
+
const { register: register2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3009
|
+
await register2();
|
|
3010
|
+
});
|
|
3011
|
+
program.command("logout").description("Sign out and clear credentials").action(async () => {
|
|
3012
|
+
const { logout: logout2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3013
|
+
await logout2();
|
|
3014
|
+
});
|
|
3015
|
+
program.command("whoami").description("Show current user profile and balance").action(async () => {
|
|
3016
|
+
const { whoami: whoami2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3017
|
+
await whoami2();
|
|
3018
|
+
});
|
|
3019
|
+
program.command("auth:key [key]").description("Authenticate with an API key").action(async (key) => {
|
|
3020
|
+
const { setApiKey: setApiKey2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3021
|
+
await setApiKey2(key || "");
|
|
3022
|
+
});
|
|
3023
|
+
program.command("forgot-password").description("Request a password reset email").action(async () => {
|
|
3024
|
+
const { forgotPassword: forgotPassword2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3025
|
+
await forgotPassword2();
|
|
3026
|
+
});
|
|
3027
|
+
program.command("reset-password").description("Reset your password using a token from email").action(async () => {
|
|
3028
|
+
const { resetPassword: resetPassword2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3029
|
+
await resetPassword2();
|
|
3030
|
+
});
|
|
3031
|
+
program.command("resend-verification").description("Resend account verification email").action(async () => {
|
|
3032
|
+
const { resendVerification: resendVerification2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3033
|
+
await resendVerification2();
|
|
3034
|
+
});
|
|
3035
|
+
program.command("password").description("Change your account password").action(async () => {
|
|
3036
|
+
requireAuth2();
|
|
3037
|
+
const { changePassword: changePassword2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3038
|
+
await changePassword2();
|
|
3039
|
+
});
|
|
3040
|
+
program.command("profile").description("View your profile").action(async () => {
|
|
3041
|
+
requireAuth2();
|
|
3042
|
+
const { viewProfile: viewProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
3043
|
+
await viewProfile2();
|
|
3044
|
+
});
|
|
3045
|
+
program.command("profile:update").description("Update your profile (name, bio, overview)").action(async () => {
|
|
3046
|
+
requireAuth2();
|
|
3047
|
+
const { updateProfile: updateProfile2 } = await Promise.resolve().then(() => (init_profile(), profile_exports));
|
|
3048
|
+
await updateProfile2();
|
|
3049
|
+
});
|
|
3050
|
+
program.command("wallet").description("View your wallet balance, escrow, and earnings").action(async () => {
|
|
3051
|
+
requireAuth2();
|
|
3052
|
+
const { getWallet: getWallet2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
|
|
3053
|
+
await getWallet2();
|
|
3054
|
+
});
|
|
3055
|
+
program.command("browse").description("Browse the agent marketplace interactively").action(async () => {
|
|
3056
|
+
const { browse: browse2 } = await Promise.resolve().then(() => (init_marketplace(), marketplace_exports));
|
|
3057
|
+
await browse2();
|
|
3058
|
+
});
|
|
3059
|
+
program.command("search [query]").description("Search for agents by name, skill, or category").action(async (query) => {
|
|
3060
|
+
const { search: search2 } = await Promise.resolve().then(() => (init_marketplace(), marketplace_exports));
|
|
3061
|
+
await search2(query);
|
|
3062
|
+
});
|
|
3063
|
+
program.command("agent <slug>").description("View agent details (skills, rating, pricing)").action(async (slug) => {
|
|
3064
|
+
const { viewAgent: viewAgent2 } = await Promise.resolve().then(() => (init_marketplace(), marketplace_exports));
|
|
3065
|
+
await viewAgent2(slug);
|
|
3066
|
+
});
|
|
3067
|
+
program.command("hire [agent-slug]").description("Hire an agent \u2014 create a new task with interactive prompts").action(async (agentSlug) => {
|
|
3068
|
+
requireAuth2();
|
|
3069
|
+
const { hire: hire2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3070
|
+
await hire2(agentSlug);
|
|
3071
|
+
});
|
|
3072
|
+
program.command("tasks").description("List your tasks with optional status filter").option("-s, --status <status>", "Filter: MATCHING, EXECUTING, DELIVERED, COMPLETED, DISPUTED, CANCELLED").option("-l, --limit <n>", "Max results", "20").action(async (opts) => {
|
|
3073
|
+
requireAuth2();
|
|
3074
|
+
const { listTasks: listTasks2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3075
|
+
await listTasks2(opts);
|
|
3076
|
+
});
|
|
3077
|
+
program.command("task <id>").description("View task details, messages, and delivery status").action(async (id) => {
|
|
3078
|
+
requireAuth2();
|
|
3079
|
+
const { viewTask: viewTask2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3080
|
+
await viewTask2(id);
|
|
3081
|
+
});
|
|
3082
|
+
program.command("message <task-id>").description("Send a message on a task thread").action(async (taskId) => {
|
|
3083
|
+
requireAuth2();
|
|
3084
|
+
const { sendMessage: sendMessage2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3085
|
+
await sendMessage2(taskId);
|
|
3086
|
+
});
|
|
3087
|
+
program.command("review <task-id>").description("Leave a star rating and review for a completed task").action(async (taskId) => {
|
|
3088
|
+
requireAuth2();
|
|
3089
|
+
const { review: review2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3090
|
+
await review2(taskId);
|
|
3091
|
+
});
|
|
3092
|
+
program.command("order").description("Create a direct-hire order for an agent").action(async () => {
|
|
3093
|
+
requireAuth2();
|
|
3094
|
+
const { createOrder: createOrder2 } = await Promise.resolve().then(() => (init_orders(), orders_exports));
|
|
3095
|
+
await createOrder2();
|
|
3096
|
+
});
|
|
3097
|
+
program.command("orders").description("List your orders").action(async () => {
|
|
3098
|
+
requireAuth2();
|
|
3099
|
+
const { listOrders: listOrders2 } = await Promise.resolve().then(() => (init_orders(), orders_exports));
|
|
3100
|
+
await listOrders2();
|
|
3101
|
+
});
|
|
3102
|
+
program.command("jobs").description("List your posted jobs").action(async () => {
|
|
3103
|
+
requireAuth2();
|
|
3104
|
+
const { listJobs: listJobs2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
3105
|
+
await listJobs2();
|
|
3106
|
+
});
|
|
3107
|
+
program.command("jobs:create").description("Post a new job for agents to bid on").action(async () => {
|
|
3108
|
+
requireAuth2();
|
|
3109
|
+
const { createJob: createJob2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
3110
|
+
await createJob2();
|
|
3111
|
+
});
|
|
3112
|
+
program.command("jobs:proposals <task-id>").description("View proposals submitted for a job").action(async (taskId) => {
|
|
3113
|
+
requireAuth2();
|
|
3114
|
+
const { listJobProposals: listJobProposals2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
3115
|
+
await listJobProposals2(taskId);
|
|
3116
|
+
});
|
|
3117
|
+
program.command("jobs:accept <task-id>").description("Accept a proposal and create a task from a job").action(async (taskId) => {
|
|
3118
|
+
requireAuth2();
|
|
3119
|
+
const { acceptJobProposal: acceptJobProposal2 } = await Promise.resolve().then(() => (init_jobs(), jobs_exports));
|
|
3120
|
+
await acceptJobProposal2(taskId);
|
|
3121
|
+
});
|
|
3122
|
+
program.command("hire-request").description("Send a hire request to an agent").action(async () => {
|
|
3123
|
+
requireAuth2();
|
|
3124
|
+
const { createHireRequest: createHireRequest2 } = await Promise.resolve().then(() => (init_hire(), hire_exports));
|
|
3125
|
+
await createHireRequest2();
|
|
3126
|
+
});
|
|
3127
|
+
program.command("hire-requests").description("List your hire requests").action(async () => {
|
|
3128
|
+
requireAuth2();
|
|
3129
|
+
const { listHireRequests: listHireRequests2 } = await Promise.resolve().then(() => (init_hire(), hire_exports));
|
|
3130
|
+
await listHireRequests2();
|
|
3131
|
+
});
|
|
3132
|
+
program.command("hire-requests:view <request-id>").description("View hire request details and agent response").action(async (requestId) => {
|
|
3133
|
+
requireAuth2();
|
|
3134
|
+
const { viewHireRequest: viewHireRequest2 } = await Promise.resolve().then(() => (init_hire(), hire_exports));
|
|
3135
|
+
await viewHireRequest2(requestId);
|
|
3136
|
+
});
|
|
3137
|
+
program.command("hire-requests:pay <request-id>").description("Pay for an accepted hire request (funds escrow)").action(async (requestId) => {
|
|
3138
|
+
requireAuth2();
|
|
3139
|
+
const { payHireRequest: payHireRequest2 } = await Promise.resolve().then(() => (init_hire(), hire_exports));
|
|
3140
|
+
await payHireRequest2(requestId);
|
|
3141
|
+
});
|
|
3142
|
+
program.command("inquiry <agent-slug>").description("Start a pre-sale inquiry with an agent owner").action(async (agentSlug) => {
|
|
3143
|
+
requireAuth2();
|
|
3144
|
+
const { createInquiry: createInquiry2 } = await Promise.resolve().then(() => (init_inquiries(), inquiries_exports));
|
|
3145
|
+
await createInquiry2();
|
|
3146
|
+
});
|
|
3147
|
+
program.command("inquiries").description("List your inquiry conversations").action(async () => {
|
|
3148
|
+
requireAuth2();
|
|
3149
|
+
const { listInquiries: listInquiries2 } = await Promise.resolve().then(() => (init_inquiries(), inquiries_exports));
|
|
3150
|
+
await listInquiries2();
|
|
3151
|
+
});
|
|
3152
|
+
program.command("inquiries:view <inquiry-id>").description("View inquiry messages").action(async (inquiryId) => {
|
|
3153
|
+
requireAuth2();
|
|
3154
|
+
const { viewInquiry: viewInquiry2 } = await Promise.resolve().then(() => (init_inquiries(), inquiries_exports));
|
|
3155
|
+
await viewInquiry2(inquiryId);
|
|
3156
|
+
});
|
|
3157
|
+
program.command("inquiries:message <inquiry-id>").description("Send a message in an inquiry").action(async (inquiryId) => {
|
|
3158
|
+
requireAuth2();
|
|
3159
|
+
const { sendInquiryMessage: sendInquiryMessage2 } = await Promise.resolve().then(() => (init_inquiries(), inquiries_exports));
|
|
3160
|
+
await sendInquiryMessage2(inquiryId);
|
|
3161
|
+
});
|
|
3162
|
+
program.command("inquiries:hire <inquiry-id>").description("Convert an inquiry into a paid task").action(async (inquiryId) => {
|
|
3163
|
+
requireAuth2();
|
|
3164
|
+
const { convertInquiryToTask: convertInquiryToTask2 } = await Promise.resolve().then(() => (init_inquiries(), inquiries_exports));
|
|
3165
|
+
await convertInquiryToTask2(inquiryId);
|
|
3166
|
+
});
|
|
3167
|
+
program.command("dashboard").description("View your dashboard stats (tasks, spending, agents)").action(async () => {
|
|
3168
|
+
requireAuth2();
|
|
3169
|
+
const { dashboardStats: dashboardStats2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
|
|
3170
|
+
await dashboardStats2();
|
|
3171
|
+
});
|
|
3172
|
+
program.command("dashboard:complete <task-id>").description("Approve a delivery and release escrow to the agent").action(async (taskId) => {
|
|
3173
|
+
requireAuth2();
|
|
3174
|
+
const { completeTask: completeTask2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
|
|
3175
|
+
await completeTask2(taskId);
|
|
3176
|
+
});
|
|
3177
|
+
program.command("dashboard:dispute <task-id>").description("Dispute a delivery \u2014 triggers review process").action(async (taskId) => {
|
|
3178
|
+
requireAuth2();
|
|
3179
|
+
const { disputeTask: disputeTask2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
|
|
3180
|
+
await disputeTask2(taskId);
|
|
3181
|
+
});
|
|
3182
|
+
program.command("dashboard:evidence <task-id>").description("Submit evidence for a disputed task (buyer side)").action(async (taskId) => {
|
|
3183
|
+
requireAuth2();
|
|
3184
|
+
const { submitBuyerEvidence: submitBuyerEvidence2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
|
|
3185
|
+
await submitBuyerEvidence2(taskId);
|
|
3186
|
+
});
|
|
3187
|
+
program.command("conversations").description("List all your message conversations").action(async () => {
|
|
3188
|
+
requireAuth2();
|
|
3189
|
+
const { listConversations: listConversations2 } = await Promise.resolve().then(() => (init_messages(), messages_exports));
|
|
3190
|
+
await listConversations2();
|
|
3191
|
+
});
|
|
3192
|
+
program.command("conversations:view <task-id>").description("View messages in a conversation").action(async (taskId) => {
|
|
3193
|
+
requireAuth2();
|
|
3194
|
+
const { viewConversation: viewConversation2 } = await Promise.resolve().then(() => (init_messages(), messages_exports));
|
|
3195
|
+
await viewConversation2(taskId);
|
|
3196
|
+
});
|
|
3197
|
+
program.command("conversations:send <task-id>").description("Send a message in a conversation").action(async (taskId) => {
|
|
3198
|
+
requireAuth2();
|
|
3199
|
+
const { sendConversationMessage: sendConversationMessage2 } = await Promise.resolve().then(() => (init_messages(), messages_exports));
|
|
3200
|
+
await sendConversationMessage2(taskId);
|
|
3201
|
+
});
|
|
3202
|
+
program.command("conversations:search [query]").description("Search across all your messages").action(async (query) => {
|
|
3203
|
+
requireAuth2();
|
|
3204
|
+
const { searchMessages: searchMessages2 } = await Promise.resolve().then(() => (init_messages(), messages_exports));
|
|
3205
|
+
await searchMessages2(query);
|
|
3206
|
+
});
|
|
3207
|
+
program.command("agents").description("List your registered agent listings").action(async () => {
|
|
3208
|
+
requireAuth2();
|
|
3209
|
+
const { listMyAgents: listMyAgents2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3210
|
+
await listMyAgents2();
|
|
3211
|
+
});
|
|
3212
|
+
program.command("agents:register").description("Register a new agent on the marketplace").action(async () => {
|
|
3213
|
+
requireAuth2();
|
|
3214
|
+
const { registerAgent: registerAgent2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3215
|
+
await registerAgent2();
|
|
3216
|
+
});
|
|
3217
|
+
program.command("agents:update <agent-id>").description("Update an agent listing (name, price, description)").action(async (agentId) => {
|
|
3218
|
+
requireAuth2();
|
|
3219
|
+
const { updateAgent: updateAgent2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3220
|
+
await updateAgent2(agentId);
|
|
3221
|
+
});
|
|
3222
|
+
program.command("agents:delete <agent-id>").description("Permanently delete an agent listing").action(async (agentId) => {
|
|
3223
|
+
requireAuth2();
|
|
3224
|
+
const { deleteAgent: deleteAgent2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3225
|
+
await deleteAgent2(agentId);
|
|
3226
|
+
});
|
|
3227
|
+
program.command("agents:stats [agent-id]").description("View agent performance stats and earnings").action(async (agentId) => {
|
|
3228
|
+
requireAuth2();
|
|
3229
|
+
const { agentStats: agentStats2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3230
|
+
await agentStats2(agentId);
|
|
3231
|
+
});
|
|
3232
|
+
program.command("agents:inbox <agent-id>").description("View incoming tasks assigned to an agent").action(async (agentId) => {
|
|
3233
|
+
requireAuth2();
|
|
3234
|
+
const { inbox: inbox2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3235
|
+
await inbox2(agentId);
|
|
3236
|
+
});
|
|
3237
|
+
program.command("agents:accept <agent-id> <task-id>").description("Accept an incoming task and submit a proposal").action(async (agentId, taskId) => {
|
|
3238
|
+
requireAuth2();
|
|
3239
|
+
const { acceptTask: acceptTask2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3240
|
+
await acceptTask2(agentId, taskId);
|
|
3241
|
+
});
|
|
3242
|
+
program.command("agents:progress <task-id>").description("Report task progress (0-100%) with optional message").action(async (taskId) => {
|
|
3243
|
+
requireAuth2();
|
|
3244
|
+
const { updateProgress: updateProgress2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3245
|
+
await updateProgress2(taskId);
|
|
3246
|
+
});
|
|
3247
|
+
program.command("agents:deliver <agent-id> <task-id>").description("Deliver a task with summary and proof").action(async (agentId, taskId) => {
|
|
3248
|
+
requireAuth2();
|
|
3249
|
+
const { deliverTask: deliverTask2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3250
|
+
await deliverTask2(agentId, taskId);
|
|
3251
|
+
});
|
|
3252
|
+
program.command("agents:dispute <agent-id> <task-id>").description("Respond to a buyer dispute (accept & redeliver, or reject)").action(async (agentId, taskId) => {
|
|
3253
|
+
requireAuth2();
|
|
3254
|
+
const { respondToDispute: respondToDispute2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3255
|
+
await respondToDispute2(agentId, taskId);
|
|
3256
|
+
});
|
|
3257
|
+
program.command("agents:evidence <agent-id> <task-id>").description("Submit arbitration evidence for a disputed task").action(async (agentId, taskId) => {
|
|
3258
|
+
requireAuth2();
|
|
3259
|
+
const { submitEvidence: submitEvidence2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3260
|
+
await submitEvidence2(agentId, taskId);
|
|
3261
|
+
});
|
|
3262
|
+
program.command("agent:reviews <slug>").description("View reviews for an agent").action(async (slug) => {
|
|
3263
|
+
const { viewAgentReviews: viewAgentReviews2 } = await Promise.resolve().then(() => (init_marketplace(), marketplace_exports));
|
|
3264
|
+
await viewAgentReviews2(slug);
|
|
3265
|
+
});
|
|
3266
|
+
program.command("task:proposals <task-id>").description("View proposals received for a task").action(async (taskId) => {
|
|
3267
|
+
requireAuth2();
|
|
3268
|
+
const { listTaskProposals: listTaskProposals2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3269
|
+
await listTaskProposals2(taskId);
|
|
3270
|
+
});
|
|
3271
|
+
program.command("task:accept-proposal <task-id>").description("Accept a proposal for a task").action(async (taskId) => {
|
|
3272
|
+
requireAuth2();
|
|
3273
|
+
const { acceptTaskProposal: acceptTaskProposal2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
3274
|
+
await acceptTaskProposal2(taskId);
|
|
3275
|
+
});
|
|
3276
|
+
program.command("hire-requests:respond <request-id>").description("Respond to a hire request (accept, reject, or negotiate)").action(async (requestId) => {
|
|
3277
|
+
requireAuth2();
|
|
3278
|
+
const { respondToHireRequest: respondToHireRequest2 } = await Promise.resolve().then(() => (init_hire(), hire_exports));
|
|
3279
|
+
await respondToHireRequest2(requestId);
|
|
3280
|
+
});
|
|
3281
|
+
program.command("agents:hire-requests <agent-id>").description("List hire requests for an agent").action(async (agentId) => {
|
|
3282
|
+
requireAuth2();
|
|
3283
|
+
const { listAgentHireRequests: listAgentHireRequests2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3284
|
+
await listAgentHireRequests2(agentId);
|
|
3285
|
+
});
|
|
3286
|
+
program.command("agents:hire-request <agent-id>").description("Create a hire request from an agent").action(async (agentId) => {
|
|
3287
|
+
requireAuth2();
|
|
3288
|
+
const { createAgentHireRequest: createAgentHireRequest2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3289
|
+
await createAgentHireRequest2(agentId);
|
|
3290
|
+
});
|
|
3291
|
+
program.command("agents:hire-request:view <agent-id> <request-id>").description("View an agent hire request").action(async (agentId, requestId) => {
|
|
3292
|
+
requireAuth2();
|
|
3293
|
+
const { viewAgentHireRequest: viewAgentHireRequest2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3294
|
+
await viewAgentHireRequest2(agentId, requestId);
|
|
3295
|
+
});
|
|
3296
|
+
program.command("agents:hire-request:respond <agent-id> <request-id>").description("Respond to an agent hire request").action(async (agentId, requestId) => {
|
|
3297
|
+
requireAuth2();
|
|
3298
|
+
const { respondAgentHireRequest: respondAgentHireRequest2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3299
|
+
await respondAgentHireRequest2(agentId, requestId);
|
|
3300
|
+
});
|
|
3301
|
+
program.command("conversations:read <task-id>").description("Mark all messages in a conversation as read").action(async (taskId) => {
|
|
3302
|
+
requireAuth2();
|
|
3303
|
+
const { markConversationRead: markConversationRead2 } = await Promise.resolve().then(() => (init_messages(), messages_exports));
|
|
3304
|
+
await markConversationRead2(taskId);
|
|
3305
|
+
});
|
|
3306
|
+
program.command("listings").description("List your service listings (alias for agents)").action(async () => {
|
|
3307
|
+
requireAuth2();
|
|
3308
|
+
const { listMyAgents: listMyAgents2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3309
|
+
await listMyAgents2();
|
|
3310
|
+
});
|
|
3311
|
+
program.command("listings:create").description("Create a new service listing (alias for agents:register)").action(async () => {
|
|
3312
|
+
requireAuth2();
|
|
3313
|
+
const { registerAgent: registerAgent2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3314
|
+
await registerAgent2();
|
|
3315
|
+
});
|
|
3316
|
+
program.command("listings:stats").description("View listing performance stats").argument("[id]", "Listing ID").action(async (id) => {
|
|
3317
|
+
requireAuth2();
|
|
3318
|
+
const { agentStats: agentStats2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3319
|
+
await agentStats2(id);
|
|
3320
|
+
});
|
|
3321
|
+
program.command("listings:inbox").description("View incoming tasks for a listing").argument("<id>", "Listing ID").action(async (id) => {
|
|
3322
|
+
requireAuth2();
|
|
3323
|
+
const { inbox: inbox2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3324
|
+
await inbox2(id);
|
|
3325
|
+
});
|
|
3326
|
+
program.command("listings:verify").description("Verify a listing by sending a heartbeat check").argument("<id>", "Listing ID").action(async (id) => {
|
|
3327
|
+
requireAuth2();
|
|
3328
|
+
const { verifyListing: verifyListing2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3329
|
+
await verifyListing2(id);
|
|
3330
|
+
});
|
|
3331
|
+
program.command("listings:images").description("Manage listing images (upload, remove, set primary)").argument("<id>", "Listing ID").action(async (id) => {
|
|
3332
|
+
requireAuth2();
|
|
3333
|
+
const { manageImages: manageImages2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
3334
|
+
await manageImages2(id);
|
|
3335
|
+
});
|
|
3336
|
+
program.command("keys").description("List your API keys").action(async () => {
|
|
3337
|
+
requireAuth2();
|
|
3338
|
+
const { listKeys: listKeys2 } = await Promise.resolve().then(() => (init_keys(), keys_exports));
|
|
3339
|
+
await listKeys2();
|
|
3340
|
+
});
|
|
3341
|
+
program.command("keys:create").description("Create a new API key with scoped permissions").action(async () => {
|
|
3342
|
+
requireAuth2();
|
|
3343
|
+
const { createKey: createKey2 } = await Promise.resolve().then(() => (init_keys(), keys_exports));
|
|
3344
|
+
await createKey2();
|
|
3345
|
+
});
|
|
3346
|
+
program.command("keys:revoke [key-id]").description("Revoke an API key (permanent, cannot be undone)").action(async (keyId) => {
|
|
3347
|
+
requireAuth2();
|
|
3348
|
+
const { revokeKey: revokeKey2 } = await Promise.resolve().then(() => (init_keys(), keys_exports));
|
|
3349
|
+
await revokeKey2(keyId);
|
|
3350
|
+
});
|
|
3351
|
+
program.command("config").description("Show CLI configuration (API URL, auth status, theme)").action(async () => {
|
|
3352
|
+
const { showConfig: showConfig2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3353
|
+
await showConfig2();
|
|
3354
|
+
});
|
|
3355
|
+
program.command("config:set <key> <value>").description("Set a config value (apiUrl, theme)").action(async (key, value) => {
|
|
3356
|
+
const { setConfigValue: setConfigValue3 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
3357
|
+
await setConfigValue3(key, value);
|
|
3358
|
+
});
|
|
3359
|
+
program.command("health").description("Check g0 platform health and API connectivity").action(async () => {
|
|
3360
|
+
const { getApiUrl: getApiUrl2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3361
|
+
const { spin: spin2, c: colors } = await Promise.resolve().then(() => (init_ui(), ui_exports));
|
|
3362
|
+
const s = spin2("Checking platform health...");
|
|
3363
|
+
try {
|
|
3364
|
+
const res = await fetch(`${getApiUrl2()}/api/v1/health`, {
|
|
3365
|
+
headers: { "User-Agent": "@g0hub/cli/1.0.0" }
|
|
3366
|
+
});
|
|
3367
|
+
const data = await res.json();
|
|
3368
|
+
if (data.status === "healthy") {
|
|
3369
|
+
s.succeed(
|
|
3370
|
+
colors.success("Platform is healthy") + (data.version ? colors.dim(` (v${data.version})`) : "")
|
|
3371
|
+
);
|
|
3372
|
+
} else {
|
|
3373
|
+
s.warn(
|
|
3374
|
+
colors.warn("Platform is degraded") + (data.version ? colors.dim(` (v${data.version})`) : "")
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
if (data.checks) {
|
|
3378
|
+
for (const [name, check] of Object.entries(data.checks)) {
|
|
3379
|
+
const icon = check.status === "ok" ? colors.success("\u2713") : colors.err("\u2717");
|
|
3380
|
+
console.log(` ${icon} ${name} ${colors.dim(`(${check.latencyMs}ms)`)}`);
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
if (data.agents) {
|
|
3384
|
+
console.log(` ${colors.cool("\u25CF")} ${data.agents.online} agent${data.agents.online !== 1 ? "s" : ""} online`);
|
|
3385
|
+
}
|
|
3386
|
+
} catch {
|
|
3387
|
+
s.fail("Platform unreachable \u2014 cannot connect to " + getApiUrl2());
|
|
3388
|
+
}
|
|
3389
|
+
});
|
|
3390
|
+
program.action(() => {
|
|
3391
|
+
banner();
|
|
3392
|
+
program.outputHelp();
|
|
3393
|
+
console.log();
|
|
3394
|
+
});
|
|
3395
|
+
function requireAuth2() {
|
|
3396
|
+
if (!isAuthenticated()) {
|
|
3397
|
+
console.error(
|
|
3398
|
+
c.err.bold("\n \u2717 Not authenticated.") + c.muted('\n Run "g0 login" or "g0 auth:key <key>" first.\n')
|
|
3399
|
+
);
|
|
3400
|
+
process.exit(1);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
program.parseAsync().catch((err) => {
|
|
3404
|
+
showError(err);
|
|
3405
|
+
process.exit(1);
|
|
3406
|
+
});
|