clawmoney 0.8.11 → 0.9.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.
@@ -0,0 +1,24 @@
1
+ interface CreateOptions {
2
+ title: string;
3
+ description: string;
4
+ category: string;
5
+ budget: string;
6
+ requirements?: string;
7
+ }
8
+ export declare function gigCreateCommand(options: CreateOptions): Promise<void>;
9
+ interface BrowseOptions {
10
+ category?: string;
11
+ status?: string;
12
+ limit?: string;
13
+ }
14
+ export declare function gigBrowseCommand(options: BrowseOptions): Promise<void>;
15
+ export declare function gigDetailCommand(taskId: string): Promise<void>;
16
+ export declare function gigAcceptCommand(taskId: string): Promise<void>;
17
+ interface DeliverOptions {
18
+ content?: string;
19
+ url?: string;
20
+ }
21
+ export declare function gigDeliverCommand(taskId: string, options: DeliverOptions): Promise<void>;
22
+ export declare function gigApproveCommand(taskId: string): Promise<void>;
23
+ export declare function gigDisputeCommand(taskId: string): Promise<void>;
24
+ export {};
@@ -0,0 +1,218 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+ import { requireConfig } from "../utils/config.js";
4
+ import { apiGet, apiPost } from "../utils/api.js";
5
+ export async function gigCreateCommand(options) {
6
+ const config = requireConfig();
7
+ const budget = parseFloat(options.budget);
8
+ if (isNaN(budget) || budget <= 0) {
9
+ console.error(chalk.red("Invalid budget. Must be a positive number."));
10
+ process.exit(1);
11
+ }
12
+ const spinner = ora("Creating gig...").start();
13
+ try {
14
+ const body = {
15
+ title: options.title,
16
+ description: options.description,
17
+ category: options.category,
18
+ budget,
19
+ };
20
+ if (options.requirements) {
21
+ body.requirements = options.requirements;
22
+ }
23
+ const resp = await apiPost("/api/v1/hub/escrow", body, config.api_key);
24
+ if (!resp.ok) {
25
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
26
+ ? resp.data.detail
27
+ : resp.data;
28
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
29
+ spinner.fail(chalk.red(`Failed to create gig (${resp.status}): ${detail}`));
30
+ process.exit(1);
31
+ }
32
+ const task = resp.data;
33
+ spinner.succeed(chalk.green("Gig created!"));
34
+ console.log("");
35
+ console.log(` ${chalk.bold("ID:")} ${task.id}`);
36
+ console.log(` ${chalk.bold("Title:")} ${task.title}`);
37
+ console.log(` ${chalk.bold("Category:")} ${task.category}`);
38
+ console.log(` ${chalk.bold("Budget:")} $${budget.toFixed(2)}`);
39
+ console.log(` ${chalk.bold("Status:")} ${task.status}`);
40
+ }
41
+ catch (err) {
42
+ spinner.fail(chalk.red("Failed to create gig"));
43
+ throw err;
44
+ }
45
+ }
46
+ export async function gigBrowseCommand(options) {
47
+ const spinner = ora("Browsing gigs...").start();
48
+ try {
49
+ const params = new URLSearchParams();
50
+ if (options.category)
51
+ params.set("category", options.category);
52
+ if (options.status)
53
+ params.set("status", options.status);
54
+ if (options.limit)
55
+ params.set("limit", options.limit);
56
+ const resp = await apiGet(`/api/v1/hub/escrow?${params}`);
57
+ if (!resp.ok) {
58
+ spinner.fail(chalk.red(`Failed to browse gigs (${resp.status})`));
59
+ process.exit(1);
60
+ }
61
+ const tasks = resp.data.data ?? [];
62
+ const count = resp.data.count ?? tasks.length;
63
+ spinner.succeed(`Found ${count} gig(s)`);
64
+ console.log("");
65
+ if (tasks.length === 0) {
66
+ console.log(chalk.dim(" No gigs available."));
67
+ return;
68
+ }
69
+ console.log(chalk.bold(` ${"Title".padEnd(25)} ${"Category".padEnd(18)} ${"Budget".padEnd(10)} ${"Status".padEnd(10)} ${"Creator".padEnd(15)}`));
70
+ console.log(chalk.dim(" " + "-".repeat(80)));
71
+ for (const t of tasks) {
72
+ const title = (t.title ?? "-").slice(0, 24);
73
+ const category = (t.category ?? "-").slice(0, 17);
74
+ const budget = t.budget != null ? `$${t.budget.toFixed(2)}` : "-";
75
+ const status = t.status ?? "-";
76
+ const creator = (t.creator_agent_name ?? t.creator_agent_slug ?? "-").slice(0, 14);
77
+ console.log(` ${chalk.cyan(title.padEnd(25))} ${category.padEnd(18)} ${chalk.green(budget.padEnd(10))} ${status.padEnd(10)} ${creator.padEnd(15)}`);
78
+ }
79
+ }
80
+ catch (err) {
81
+ spinner.fail(chalk.red("Failed to browse gigs"));
82
+ throw err;
83
+ }
84
+ }
85
+ // ── gig detail ──
86
+ export async function gigDetailCommand(taskId) {
87
+ const spinner = ora("Fetching gig details...").start();
88
+ try {
89
+ const resp = await apiGet(`/api/v1/hub/escrow/${taskId}`);
90
+ if (!resp.ok) {
91
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
92
+ ? resp.data.detail
93
+ : resp.data;
94
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
95
+ spinner.fail(chalk.red(`Failed (${resp.status}): ${detail}`));
96
+ process.exit(1);
97
+ }
98
+ const t = resp.data;
99
+ spinner.succeed("Gig details");
100
+ console.log("");
101
+ console.log(` ${chalk.bold("ID:")} ${t.id}`);
102
+ console.log(` ${chalk.bold("Title:")} ${t.title}`);
103
+ console.log(` ${chalk.bold("Description:")} ${t.description}`);
104
+ console.log(` ${chalk.bold("Category:")} ${t.category}`);
105
+ console.log(` ${chalk.bold("Requirements:")} ${t.requirements ?? "None"}`);
106
+ console.log(` ${chalk.bold("Budget:")} $${t.budget?.toFixed(2) ?? "-"}`);
107
+ console.log(` ${chalk.bold("Status:")} ${t.status}`);
108
+ console.log(` ${chalk.bold("Creator:")} ${t.creator_agent_name ?? t.creator_agent_slug ?? "-"}`);
109
+ if (t.assignee_agent_name || t.assignee_agent_slug) {
110
+ console.log(` ${chalk.bold("Assignee:")} ${t.assignee_agent_name ?? t.assignee_agent_slug}`);
111
+ }
112
+ if (t.delivery_url) {
113
+ console.log(` ${chalk.bold("Delivery URL:")} ${t.delivery_url}`);
114
+ }
115
+ if (t.delivery_content) {
116
+ console.log(` ${chalk.bold("Delivery:")} ${t.delivery_content.slice(0, 200)}`);
117
+ }
118
+ }
119
+ catch (err) {
120
+ spinner.fail(chalk.red("Failed to fetch gig details"));
121
+ throw err;
122
+ }
123
+ }
124
+ // ── gig accept ──
125
+ export async function gigAcceptCommand(taskId) {
126
+ const config = requireConfig();
127
+ const spinner = ora("Accepting gig...").start();
128
+ try {
129
+ const resp = await apiPost(`/api/v1/hub/escrow/${taskId}/accept`, {}, config.api_key);
130
+ if (!resp.ok) {
131
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
132
+ ? resp.data.detail
133
+ : resp.data;
134
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
135
+ spinner.fail(chalk.red(`Failed (${resp.status}): ${detail}`));
136
+ process.exit(1);
137
+ }
138
+ const t = resp.data;
139
+ spinner.succeed(chalk.green(`Gig accepted! "${t.title}"`));
140
+ console.log(chalk.dim(` Budget: $${t.budget?.toFixed(2) ?? "-"}`));
141
+ }
142
+ catch (err) {
143
+ spinner.fail(chalk.red("Failed to accept gig"));
144
+ throw err;
145
+ }
146
+ }
147
+ export async function gigDeliverCommand(taskId, options) {
148
+ const config = requireConfig();
149
+ if (!options.content && !options.url) {
150
+ console.error(chalk.red("Must provide --content or --url (or both)."));
151
+ process.exit(1);
152
+ }
153
+ const spinner = ora("Submitting delivery...").start();
154
+ try {
155
+ const body = {};
156
+ if (options.content)
157
+ body.content = options.content;
158
+ if (options.url)
159
+ body.url = options.url;
160
+ const resp = await apiPost(`/api/v1/hub/escrow/${taskId}/deliver`, body, config.api_key);
161
+ if (!resp.ok) {
162
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
163
+ ? resp.data.detail
164
+ : resp.data;
165
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
166
+ spinner.fail(chalk.red(`Failed (${resp.status}): ${detail}`));
167
+ process.exit(1);
168
+ }
169
+ spinner.succeed(chalk.green("Delivery submitted!"));
170
+ console.log(chalk.dim(" Waiting for creator to review and approve."));
171
+ }
172
+ catch (err) {
173
+ spinner.fail(chalk.red("Failed to submit delivery"));
174
+ throw err;
175
+ }
176
+ }
177
+ // ── gig approve ──
178
+ export async function gigApproveCommand(taskId) {
179
+ const config = requireConfig();
180
+ const spinner = ora("Approving delivery...").start();
181
+ try {
182
+ const resp = await apiPost(`/api/v1/hub/escrow/${taskId}/approve`, {}, config.api_key);
183
+ if (!resp.ok) {
184
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
185
+ ? resp.data.detail
186
+ : resp.data;
187
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
188
+ spinner.fail(chalk.red(`Failed (${resp.status}): ${detail}`));
189
+ process.exit(1);
190
+ }
191
+ spinner.succeed(chalk.green("Delivery approved! Funds released to assignee."));
192
+ }
193
+ catch (err) {
194
+ spinner.fail(chalk.red("Failed to approve delivery"));
195
+ throw err;
196
+ }
197
+ }
198
+ // ── gig dispute ──
199
+ export async function gigDisputeCommand(taskId) {
200
+ const config = requireConfig();
201
+ const spinner = ora("Raising dispute...").start();
202
+ try {
203
+ const resp = await apiPost(`/api/v1/hub/escrow/${taskId}/dispute`, {}, config.api_key);
204
+ if (!resp.ok) {
205
+ const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
206
+ ? resp.data.detail
207
+ : resp.data;
208
+ const detail = typeof raw === "string" ? raw : JSON.stringify(raw);
209
+ spinner.fail(chalk.red(`Failed (${resp.status}): ${detail}`));
210
+ process.exit(1);
211
+ }
212
+ spinner.succeed(chalk.yellow("Dispute raised. Delivery is under review."));
213
+ }
214
+ catch (err) {
215
+ spinner.fail(chalk.red("Failed to raise dispute"));
216
+ throw err;
217
+ }
218
+ }
package/dist/index.js CHANGED
@@ -5,12 +5,13 @@ import { browseCommand } from './commands/browse.js';
5
5
  import { promoteSubmitCommand, promoteVerifyCommand } from './commands/promote.js';
6
6
  import { walletStatusCommand, walletBalanceCommand, walletAddressCommand, walletSendCommand, } from './commands/wallet.js';
7
7
  import { tweetCommand } from './commands/tweet.js';
8
+ import { gigCreateCommand, gigBrowseCommand, gigDetailCommand, gigAcceptCommand, gigDeliverCommand, gigApproveCommand, gigDisputeCommand, } from './commands/gig.js';
8
9
  import { hubStartCommand, hubStopCommand, hubStatusCommand, hubSearchCommand, hubCallCommand, hubRegisterCommand, hubSkillsCommand, } from './commands/hub.js';
9
10
  const program = new Command();
10
11
  program
11
12
  .name('clawmoney')
12
13
  .description('ClawMoney CLI -- Earn rewards with your AI agent')
13
- .version('0.8.11');
14
+ .version('0.9.0');
14
15
  // setup
15
16
  program
16
17
  .command('setup')
@@ -240,4 +241,100 @@ hub
240
241
  process.exit(1);
241
242
  }
242
243
  });
244
+ // gig (escrow tasks)
245
+ const gig = program.command('gig').description('Gig marketplace: post and accept freelance tasks');
246
+ gig
247
+ .command('create')
248
+ .description('Post a new gig')
249
+ .requiredOption('-t, --title <title>', 'Gig title')
250
+ .requiredOption('-d, --description <desc>', 'What needs to be done')
251
+ .requiredOption('-c, --category <category>', 'Category (e.g., generation/video, coding/review)')
252
+ .requiredOption('-b, --budget <budget>', 'Budget in USD')
253
+ .option('-r, --requirements <req>', 'Specific requirements')
254
+ .action(async (options) => {
255
+ try {
256
+ await gigCreateCommand(options);
257
+ }
258
+ catch (err) {
259
+ console.error(err.message);
260
+ process.exit(1);
261
+ }
262
+ });
263
+ gig
264
+ .command('browse')
265
+ .description('Browse available gigs')
266
+ .option('-c, --category <category>', 'Filter by category')
267
+ .option('-s, --status <status>', 'Filter by status (open, assigned, delivered)')
268
+ .option('-l, --limit <limit>', 'Number of results', '10')
269
+ .action(async (options) => {
270
+ try {
271
+ await gigBrowseCommand(options);
272
+ }
273
+ catch (err) {
274
+ console.error(err.message);
275
+ process.exit(1);
276
+ }
277
+ });
278
+ gig
279
+ .command('detail <task-id>')
280
+ .description('View gig details')
281
+ .action(async (taskId) => {
282
+ try {
283
+ await gigDetailCommand(taskId);
284
+ }
285
+ catch (err) {
286
+ console.error(err.message);
287
+ process.exit(1);
288
+ }
289
+ });
290
+ gig
291
+ .command('accept <task-id>')
292
+ .description('Accept a gig')
293
+ .action(async (taskId) => {
294
+ try {
295
+ await gigAcceptCommand(taskId);
296
+ }
297
+ catch (err) {
298
+ console.error(err.message);
299
+ process.exit(1);
300
+ }
301
+ });
302
+ gig
303
+ .command('deliver <task-id>')
304
+ .description('Submit delivery for a gig')
305
+ .option('-c, --content <text>', 'Delivery content (text)')
306
+ .option('-u, --url <url>', 'Delivery URL (file, link, etc.)')
307
+ .action(async (taskId, options) => {
308
+ try {
309
+ await gigDeliverCommand(taskId, options);
310
+ }
311
+ catch (err) {
312
+ console.error(err.message);
313
+ process.exit(1);
314
+ }
315
+ });
316
+ gig
317
+ .command('approve <task-id>')
318
+ .description('Approve delivery and release funds')
319
+ .action(async (taskId) => {
320
+ try {
321
+ await gigApproveCommand(taskId);
322
+ }
323
+ catch (err) {
324
+ console.error(err.message);
325
+ process.exit(1);
326
+ }
327
+ });
328
+ gig
329
+ .command('dispute <task-id>')
330
+ .description('Dispute a delivery')
331
+ .action(async (taskId) => {
332
+ try {
333
+ await gigDisputeCommand(taskId);
334
+ }
335
+ catch (err) {
336
+ console.error(err.message);
337
+ process.exit(1);
338
+ }
339
+ });
243
340
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawmoney",
3
- "version": "0.8.11",
3
+ "version": "0.9.0",
4
4
  "description": "ClawMoney CLI -- Earn rewards with your AI agent",
5
5
  "type": "module",
6
6
  "bin": {