clawmoney 0.5.0 → 0.6.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,11 @@
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;
7
8
  }
8
9
  export declare function hireSubmitCommand(taskId: string, options: SubmitOptions): Promise<void>;
9
- export declare function hireVerifyCommand(taskId: string, options: VerifyOptions): Promise<void>;
10
+ export declare function hireVerifyCommand(submissionId: string, options: VerifyOptions): Promise<void>;
10
11
  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,112 @@ 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 verifySpinner = ora('Submitting witness verification...').start();
104
+ try {
105
+ const resp = await apiPost(`/api/v1/hire/submissions/${submissionId}/verify`, {
106
+ vote: 'approve',
107
+ relevance_score: 8,
108
+ quality_score: 7,
109
+ tweet_proof: {
110
+ payload: proof.payload,
111
+ signature: proof.signature,
112
+ signer: proof.signer,
113
+ timestamp: proof.timestamp,
114
+ },
70
115
  }, config.api_key);
71
116
  if (!resp.ok) {
72
- submitSpinner.fail('Witness verification submission failed');
73
- console.error(chalk.red(JSON.stringify(resp.data)));
117
+ verifySpinner.fail('Verification failed');
118
+ const detail = typeof resp.data === 'object' ? (resp.data.detail || JSON.stringify(resp.data)) : String(resp.data);
119
+ console.error(chalk.red(` ${detail}`));
74
120
  }
75
121
  else {
76
- submitSpinner.succeed('Witness verification submitted');
122
+ verifySpinner.succeed('Witness verification submitted');
123
+ if (resp.data.id) {
124
+ console.log(chalk.dim(` Verification ID: ${resp.data.id}`));
125
+ }
77
126
  }
78
127
  }
79
128
  catch (err) {
80
- witnessSpinner.fail('Witness verification failed');
129
+ verifySpinner.fail('Verification failed');
81
130
  console.error(chalk.red(err.message));
82
131
  }
83
132
  }
84
133
  else {
85
134
  // 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();
135
+ const spinner = ora('Submitting manual verification...').start();
90
136
  try {
91
- const resp = await apiPost(`/api/v1/hire/${taskId}/verify`, {
92
- type: 'manual',
93
- approved,
137
+ const resp = await apiPost(`/api/v1/hire/submissions/${submissionId}/verify`, {
138
+ vote: 'approve',
139
+ relevance_score: 7,
140
+ quality_score: 7,
141
+ views: 0,
142
+ likes: 0,
143
+ comments: 0,
94
144
  }, config.api_key);
95
145
  if (!resp.ok) {
96
- spinner.fail('Verification submission failed');
97
- console.error(chalk.red(JSON.stringify(resp.data)));
146
+ spinner.fail('Verification failed');
147
+ const detail = typeof resp.data === 'object' ? (resp.data.detail || JSON.stringify(resp.data)) : String(resp.data);
148
+ console.error(chalk.red(` ${detail}`));
98
149
  }
99
150
  else {
100
- spinner.succeed(`Verification submitted: ${approved ? 'APPROVED' : 'REJECTED'}`);
151
+ spinner.succeed('Manual verification submitted');
152
+ if (resp.data.id) {
153
+ console.log(chalk.dim(` Verification ID: ${resp.data.id}`));
154
+ }
101
155
  }
102
156
  }
103
157
  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,9 @@ 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)')
62
63
  .action(async (taskId, options) => {
63
64
  try {
64
65
  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.6.0",
4
4
  "description": "ClawMoney CLI -- Earn crypto with your AI agent",
5
5
  "type": "module",
6
6
  "bin": {