clawmoney 0.5.0 → 0.7.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.
@@ -1,10 +1,14 @@
1
1
  interface SubmitOptions {
2
2
  url: string;
3
+ platform?: string;
3
4
  text?: string;
4
5
  }
5
6
  interface VerifyOptions {
6
7
  witness?: boolean;
8
+ relevance: string;
9
+ quality: string;
10
+ vote?: string;
7
11
  }
8
12
  export declare function hireSubmitCommand(taskId: string, options: SubmitOptions): Promise<void>;
9
- export declare function hireVerifyCommand(taskId: string, options: VerifyOptions): Promise<void>;
13
+ export declare function hireVerifyCommand(submissionId: string, options: VerifyOptions): Promise<void>;
10
14
  export {};
@@ -1,33 +1,44 @@
1
1
  import chalk from 'chalk';
2
2
  import ora from 'ora';
3
- import { apiPost } from '../utils/api.js';
3
+ import { apiGet, apiPost } from '../utils/api.js';
4
4
  import { awalExec } from '../utils/awal.js';
5
5
  import { requireConfig } from '../utils/config.js';
6
- import { prompt, confirm } from '../utils/prompt.js';
7
6
  export async function hireSubmitCommand(taskId, options) {
8
7
  const config = requireConfig();
8
+ // 自动检测平台(从 task 获取)
9
+ let platform = options.platform;
10
+ if (!platform) {
11
+ try {
12
+ const taskResp = await apiGet(`/api/v1/hire/${taskId}`, config.api_key);
13
+ if (taskResp.ok && taskResp.data.platform) {
14
+ platform = taskResp.data.platform;
15
+ }
16
+ }
17
+ catch { /* ignore */ }
18
+ }
19
+ if (!platform)
20
+ platform = 'twitter';
9
21
  console.log('');
10
- const spinner = ora(`Submitting proof for task ${taskId}...`).start();
22
+ const spinner = ora(`Submitting proof for task ${taskId.slice(0, 8)}...`).start();
11
23
  try {
12
24
  const body = {
25
+ platform,
13
26
  proof_url: options.url,
14
27
  };
15
28
  if (options.text) {
16
- body.content = options.text;
29
+ body.content_text = options.text;
17
30
  }
18
31
  const resp = await apiPost(`/api/v1/hire/${taskId}/submit`, body, config.api_key);
19
32
  if (!resp.ok) {
20
33
  spinner.fail('Submission failed');
21
- console.error(chalk.red(JSON.stringify(resp.data)));
34
+ const detail = typeof resp.data === 'object' ? (resp.data.detail || JSON.stringify(resp.data)) : String(resp.data);
35
+ console.error(chalk.red(` ${detail}`));
22
36
  return;
23
37
  }
24
- spinner.succeed('Proof submitted successfully');
38
+ spinner.succeed('Proof submitted');
25
39
  if (resp.data.id) {
26
40
  console.log(chalk.dim(` Submission ID: ${resp.data.id}`));
27
41
  }
28
- if (resp.data.message) {
29
- console.log(chalk.dim(` ${resp.data.message}`));
30
- }
31
42
  }
32
43
  catch (err) {
33
44
  spinner.fail('Submission failed');
@@ -35,69 +46,118 @@ export async function hireSubmitCommand(taskId, options) {
35
46
  }
36
47
  console.log('');
37
48
  }
38
- export async function hireVerifyCommand(taskId, options) {
49
+ export async function hireVerifyCommand(submissionId, options) {
39
50
  const config = requireConfig();
40
51
  console.log('');
41
52
  if (options.witness) {
42
- // Witness verification via x402
43
- const tweetUrl = await prompt(chalk.cyan('? ') + 'Enter the tweet URL to verify: ');
44
- if (!tweetUrl) {
45
- console.log(chalk.red('Tweet URL is required for witness verification.'));
46
- return;
53
+ // Get submission to extract proof_url
54
+ const subSpinner = ora('Fetching submission...').start();
55
+ let proofUrl = '';
56
+ try {
57
+ // Try to get submission details - submissionId might be used directly
58
+ const resp = await apiGet(`/api/v1/hire/submissions/${submissionId}`, config.api_key);
59
+ if (resp.ok && resp.data.proof_url) {
60
+ proofUrl = resp.data.proof_url;
61
+ subSpinner.succeed(`Proof URL: ${proofUrl}`);
62
+ }
63
+ else {
64
+ subSpinner.warn('Could not fetch submission, will need tweet ID');
65
+ }
47
66
  }
48
- // Extract tweet ID from URL
49
- const tweetIdMatch = tweetUrl.match(/status\/(\d+)/);
50
- if (!tweetIdMatch) {
51
- console.log(chalk.red('Could not extract tweet ID from URL.'));
67
+ catch {
68
+ subSpinner.warn('Could not fetch submission');
69
+ }
70
+ // Extract tweet ID
71
+ let tweetId = '';
72
+ if (proofUrl) {
73
+ const match = proofUrl.match(/status\/(\d+)/);
74
+ if (match)
75
+ tweetId = match[1];
76
+ }
77
+ if (!tweetId) {
78
+ console.error(chalk.red(' Could not extract tweet ID from proof URL'));
52
79
  return;
53
80
  }
54
- const tweetId = tweetIdMatch[1];
55
- const witnessSpinner = ora('Paying for witness verification via x402...').start();
81
+ // Fetch witness proof via x402
82
+ const witnessSpinner = ora('Fetching witness proof via x402 ($0.01)...').start();
83
+ let witnessData;
56
84
  try {
57
- const witnessResult = await awalExec([
58
- 'x402',
59
- 'pay',
60
- `https://witness.bnbot.ai/x/${tweetId}`,
85
+ witnessData = await awalExec([
86
+ 'x402', 'pay', `https://witness.bnbot.ai/x/${tweetId}`,
61
87
  ]);
62
- witnessSpinner.succeed('Witness verification paid');
63
- console.log(chalk.dim(` Response: ${JSON.stringify(witnessResult.data)}`));
64
- // Submit the witness proof
65
- const submitSpinner = ora('Submitting witness proof...').start();
66
- const resp = await apiPost(`/api/v1/hire/${taskId}/verify`, {
67
- type: 'witness',
68
- tweet_id: tweetId,
69
- witness_data: witnessResult.data,
88
+ witnessSpinner.succeed('Witness proof obtained');
89
+ }
90
+ catch (err) {
91
+ witnessSpinner.fail('Witness fetch failed');
92
+ console.error(chalk.red(err.message));
93
+ return;
94
+ }
95
+ // Parse witness response
96
+ const proof = witnessData?.data?.proof || witnessData?.proof;
97
+ if (!proof) {
98
+ console.error(chalk.red(' No proof in witness response'));
99
+ console.log(chalk.dim(` Raw: ${JSON.stringify(witnessData).slice(0, 200)}`));
100
+ return;
101
+ }
102
+ // Submit witness verification
103
+ const vote = options.vote || 'approve';
104
+ const relevanceScore = parseInt(options.relevance, 10);
105
+ const qualityScore = parseInt(options.quality, 10);
106
+ const verifySpinner = ora(`Submitting witness verification (${vote}, R:${relevanceScore} Q:${qualityScore})...`).start();
107
+ try {
108
+ const resp = await apiPost(`/api/v1/hire/submissions/${submissionId}/verify`, {
109
+ vote,
110
+ relevance_score: relevanceScore,
111
+ quality_score: qualityScore,
112
+ tweet_proof: {
113
+ payload: proof.payload,
114
+ signature: proof.signature,
115
+ signer: proof.signer,
116
+ timestamp: proof.timestamp,
117
+ },
70
118
  }, config.api_key);
71
119
  if (!resp.ok) {
72
- submitSpinner.fail('Witness verification submission failed');
73
- console.error(chalk.red(JSON.stringify(resp.data)));
120
+ verifySpinner.fail('Verification failed');
121
+ const detail = typeof resp.data === 'object' ? (resp.data.detail || JSON.stringify(resp.data)) : String(resp.data);
122
+ console.error(chalk.red(` ${detail}`));
74
123
  }
75
124
  else {
76
- submitSpinner.succeed('Witness verification submitted');
125
+ verifySpinner.succeed('Witness verification submitted');
126
+ if (resp.data.id) {
127
+ console.log(chalk.dim(` Verification ID: ${resp.data.id}`));
128
+ }
77
129
  }
78
130
  }
79
131
  catch (err) {
80
- witnessSpinner.fail('Witness verification failed');
132
+ verifySpinner.fail('Verification failed');
81
133
  console.error(chalk.red(err.message));
82
134
  }
83
135
  }
84
136
  else {
85
137
  // Manual verification
86
- console.log(chalk.bold(` Manual verification for task ${taskId}`));
87
- console.log('');
88
- const approved = await confirm('Approve this submission?', false);
89
- const spinner = ora('Submitting verification...').start();
138
+ const vote = options.vote || 'approve';
139
+ const relevanceScore = parseInt(options.relevance, 10);
140
+ const qualityScore = parseInt(options.quality, 10);
141
+ const spinner = ora(`Submitting manual verification (${vote}, R:${relevanceScore} Q:${qualityScore})...`).start();
90
142
  try {
91
- const resp = await apiPost(`/api/v1/hire/${taskId}/verify`, {
92
- type: 'manual',
93
- approved,
143
+ const resp = await apiPost(`/api/v1/hire/submissions/${submissionId}/verify`, {
144
+ vote,
145
+ relevance_score: relevanceScore,
146
+ quality_score: qualityScore,
147
+ views: 0,
148
+ likes: 0,
149
+ comments: 0,
94
150
  }, config.api_key);
95
151
  if (!resp.ok) {
96
- spinner.fail('Verification submission failed');
97
- console.error(chalk.red(JSON.stringify(resp.data)));
152
+ spinner.fail('Verification failed');
153
+ const detail = typeof resp.data === 'object' ? (resp.data.detail || JSON.stringify(resp.data)) : String(resp.data);
154
+ console.error(chalk.red(` ${detail}`));
98
155
  }
99
156
  else {
100
- spinner.succeed(`Verification submitted: ${approved ? 'APPROVED' : 'REJECTED'}`);
157
+ spinner.succeed('Manual verification submitted');
158
+ if (resp.data.id) {
159
+ console.log(chalk.dim(` Verification ID: ${resp.data.id}`));
160
+ }
101
161
  }
102
162
  }
103
163
  catch (err) {
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ hire
45
45
  .command('submit <task-id>')
46
46
  .description('Submit a proof for a hire task')
47
47
  .requiredOption('-u, --url <url>', 'Proof URL (tweet, post, etc.)')
48
+ .option('-p, --platform <platform>', 'Platform (auto-detected from task)')
48
49
  .option('--text <content>', 'Optional text content')
49
50
  .action(async (taskId, options) => {
50
51
  try {
@@ -56,9 +57,12 @@ hire
56
57
  }
57
58
  });
58
59
  hire
59
- .command('verify <task-id>')
60
- .description('Verify a hire task submission')
61
- .option('-w, --witness', 'Use x402 witness verification')
60
+ .command('verify <submission-id>')
61
+ .description('Verify a hire submission')
62
+ .option('-w, --witness', 'Use x402 witness verification ($0.01)')
63
+ .requiredOption('-r, --relevance <score>', 'Relevance score (1-10)')
64
+ .requiredOption('-q, --quality <score>', 'Quality score (1-10)')
65
+ .option('-v, --vote <vote>', 'Vote: approve or reject', 'approve')
62
66
  .action(async (taskId, options) => {
63
67
  try {
64
68
  await hireVerifyCommand(taskId, options);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawmoney",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "ClawMoney CLI -- Earn crypto with your AI agent",
5
5
  "type": "module",
6
6
  "bin": {