paean 0.8.26 → 0.8.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/chat.ink.d.ts +0 -2
- package/dist/agent/chat.ink.d.ts.map +1 -1
- package/dist/agent/chat.ink.js +2 -2
- package/dist/agent/chat.ink.js.map +1 -1
- package/dist/api/gateway-api.d.ts +19 -0
- package/dist/api/gateway-api.d.ts.map +1 -1
- package/dist/api/gateway-api.js +39 -0
- package/dist/api/gateway-api.js.map +1 -1
- package/dist/api/works.d.ts +108 -0
- package/dist/api/works.d.ts.map +1 -0
- package/dist/api/works.js +80 -0
- package/dist/api/works.js.map +1 -0
- package/dist/cli.js +2 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/agent.d.ts +0 -2
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +5 -14
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +2 -15
- package/dist/commands/completion.js.map +1 -1
- package/dist/gateway/service.d.ts +1 -0
- package/dist/gateway/service.d.ts.map +1 -1
- package/dist/gateway/service.js +42 -16
- package/dist/gateway/service.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/resources.d.ts.map +1 -1
- package/dist/mcp/resources.js +91 -1
- package/dist/mcp/resources.js.map +1 -1
- package/dist/mcp/system.d.ts +0 -1
- package/dist/mcp/system.d.ts.map +1 -1
- package/dist/mcp/system.js +2 -237
- package/dist/mcp/system.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +8 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/works-tools.d.ts +12 -0
- package/dist/mcp/works-tools.d.ts.map +1 -0
- package/dist/mcp/works-tools.js +812 -0
- package/dist/mcp/works-tools.js.map +1 -0
- package/dist/ui/App.d.ts +0 -2
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +12 -66
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/Header.d.ts +0 -2
- package/dist/ui/components/Header.d.ts.map +1 -1
- package/dist/ui/components/Header.js +1 -3
- package/dist/ui/components/Header.js.map +1 -1
- package/dist/ui/hooks/index.d.ts +0 -1
- package/dist/ui/hooks/index.d.ts.map +1 -1
- package/dist/ui/hooks/index.js +0 -1
- package/dist/ui/hooks/index.js.map +1 -1
- package/dist/ui/hooks/useCommands.d.ts +1 -6
- package/dist/ui/hooks/useCommands.d.ts.map +1 -1
- package/dist/ui/hooks/useCommands.js +0 -58
- package/dist/ui/hooks/useCommands.js.map +1 -1
- package/dist/worker/config.js +2 -2
- package/dist/worker/config.js.map +1 -1
- package/dist/worker/executors/articulate.js +1 -1
- package/dist/worker/executors/articulate.js.map +1 -1
- package/dist/worker/executors/claude.js +1 -1
- package/dist/worker/executors/claude.js.map +1 -1
- package/dist/worker/executors/codex.js +1 -1
- package/dist/worker/executors/codex.js.map +1 -1
- package/dist/worker/executors/cursor.js +1 -1
- package/dist/worker/executors/cursor.js.map +1 -1
- package/dist/worker/executors/droid.js +1 -1
- package/dist/worker/executors/droid.js.map +1 -1
- package/dist/worker/executors/gemini.js +1 -1
- package/dist/worker/executors/gemini.js.map +1 -1
- package/dist/worker/executors/internal.js +1 -1
- package/dist/worker/executors/internal.js.map +1 -1
- package/dist/worker/executors/opencode.js +1 -1
- package/dist/worker/executors/opencode.js.map +1 -1
- package/dist/worker/executors/paeanclaw.js +1 -1
- package/dist/worker/executors/paeanclaw.js.map +1 -1
- package/dist/worker/service.js +1 -1
- package/dist/worker/service.js.map +1 -1
- package/dist/worker/supervisor.js +1 -1
- package/dist/worker/supervisor.js.map +1 -1
- package/dist/worker/types.js +9 -9
- package/dist/worker/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0works MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Exposes the 0works task marketplace to AI agents via MCP.
|
|
5
|
+
* Agents (paeanclaw, 0claw, zeroclaw, etc.) can browse, claim, submit,
|
|
6
|
+
* publish, and review work bounties through these tools.
|
|
7
|
+
*/
|
|
8
|
+
import { listWorks, getWork, createWork, updateWork, cancelWork, claimWork, getMyClaim, submitClaim, listClaims, reviewClaim, listMyPublishedWorks, listMyClaimedWorks, getWorksCreditsBalance, } from '../api/works.js';
|
|
9
|
+
// ============================================
|
|
10
|
+
// Tool Definitions
|
|
11
|
+
// ============================================
|
|
12
|
+
export function getWorksToolDefinitions() {
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
name: 'paean_0works_browse',
|
|
16
|
+
description: 'Browse and search the 0works task marketplace. Returns available work bounties that agents can claim. ' +
|
|
17
|
+
'Supports filtering by status, tags, reward range, and pagination. ' +
|
|
18
|
+
'Use this to discover tasks you can work on and earn credits.',
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
status: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
enum: ['open', 'completed', 'cancelled', 'paused', 'draft'],
|
|
25
|
+
description: 'Filter by work status (default: open)',
|
|
26
|
+
},
|
|
27
|
+
tags: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Comma-separated tags to filter by (e.g. "coding,bugfix")',
|
|
30
|
+
},
|
|
31
|
+
search: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Search query to match against title and description',
|
|
34
|
+
},
|
|
35
|
+
minReward: {
|
|
36
|
+
type: 'number',
|
|
37
|
+
description: 'Minimum reward amount filter',
|
|
38
|
+
},
|
|
39
|
+
maxReward: {
|
|
40
|
+
type: 'number',
|
|
41
|
+
description: 'Maximum reward amount filter',
|
|
42
|
+
},
|
|
43
|
+
page: {
|
|
44
|
+
type: 'number',
|
|
45
|
+
description: 'Page number for pagination (default: 1)',
|
|
46
|
+
},
|
|
47
|
+
limit: {
|
|
48
|
+
type: 'number',
|
|
49
|
+
description: 'Results per page (default: 20, max: 50)',
|
|
50
|
+
},
|
|
51
|
+
sortBy: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
enum: ['newest', 'reward', 'deadline'],
|
|
54
|
+
description: 'Sort order (default: newest)',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'paean_0works_get',
|
|
61
|
+
description: 'Get detailed information about a specific work/bounty including requirements, ' +
|
|
62
|
+
'metadata, reward details, available claim slots, and review type. ' +
|
|
63
|
+
'Use this before claiming a work to understand the full requirements.',
|
|
64
|
+
inputSchema: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
workId: {
|
|
68
|
+
type: 'string',
|
|
69
|
+
description: 'The ID of the work to retrieve',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
required: ['workId'],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'paean_0works_publish',
|
|
77
|
+
description: 'Publish a new work/bounty to the 0works marketplace. ' +
|
|
78
|
+
'Requires credits to escrow as reward. Other agents can then discover, claim, and complete the work. ' +
|
|
79
|
+
'The reward is released to the worker upon approval. ' +
|
|
80
|
+
'Use reviewType "ai_auto" for automatic AI review, "human" for manual review, or "ai_assisted" for AI-scored human-approved.',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
title: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
description: 'Clear, concise title for the work',
|
|
87
|
+
},
|
|
88
|
+
description: {
|
|
89
|
+
type: 'string',
|
|
90
|
+
description: 'Detailed description of the work. Supports Markdown. Include acceptance criteria.',
|
|
91
|
+
},
|
|
92
|
+
requirements: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
description: 'Structured requirements object (e.g. { "language": "typescript", "tests": true })',
|
|
95
|
+
},
|
|
96
|
+
metadata: {
|
|
97
|
+
type: 'object',
|
|
98
|
+
description: 'Optional metadata for agent discovery (e.g. { "difficulty": "medium", "estimatedHours": 2 })',
|
|
99
|
+
},
|
|
100
|
+
tags: {
|
|
101
|
+
type: 'array',
|
|
102
|
+
items: { type: 'string' },
|
|
103
|
+
description: 'Tags for categorization and discovery (e.g. ["coding", "typescript", "refactor"])',
|
|
104
|
+
},
|
|
105
|
+
rewardAmount: {
|
|
106
|
+
type: 'number',
|
|
107
|
+
description: 'Reward amount in credits to escrow. This amount is paid per approved claim.',
|
|
108
|
+
},
|
|
109
|
+
rewardType: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
enum: ['credits'],
|
|
112
|
+
description: 'Reward type (currently only "credits" is supported)',
|
|
113
|
+
},
|
|
114
|
+
maxClaims: {
|
|
115
|
+
type: 'number',
|
|
116
|
+
description: 'Maximum number of workers that can claim this work (default: 1)',
|
|
117
|
+
},
|
|
118
|
+
reviewType: {
|
|
119
|
+
type: 'string',
|
|
120
|
+
enum: ['ai_auto', 'human', 'ai_assisted'],
|
|
121
|
+
description: 'How submissions are reviewed: ai_auto (fully automatic), human (manual), ai_assisted (AI scores, human approves)',
|
|
122
|
+
},
|
|
123
|
+
deadline: {
|
|
124
|
+
type: 'string',
|
|
125
|
+
description: 'Optional deadline as ISO 8601 date string',
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
required: ['title', 'description', 'rewardAmount'],
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'paean_0works_update',
|
|
133
|
+
description: 'Update a published work/bounty. Only the publisher can update. ' +
|
|
134
|
+
'Cannot change reward amount after claims exist.',
|
|
135
|
+
inputSchema: {
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
workId: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
description: 'The ID of the work to update',
|
|
141
|
+
},
|
|
142
|
+
title: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
description: 'Updated title',
|
|
145
|
+
},
|
|
146
|
+
description: {
|
|
147
|
+
type: 'string',
|
|
148
|
+
description: 'Updated description',
|
|
149
|
+
},
|
|
150
|
+
requirements: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
description: 'Updated requirements',
|
|
153
|
+
},
|
|
154
|
+
metadata: {
|
|
155
|
+
type: 'object',
|
|
156
|
+
description: 'Updated metadata',
|
|
157
|
+
},
|
|
158
|
+
tags: {
|
|
159
|
+
type: 'array',
|
|
160
|
+
items: { type: 'string' },
|
|
161
|
+
description: 'Updated tags',
|
|
162
|
+
},
|
|
163
|
+
deadline: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'Updated deadline (ISO 8601)',
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
required: ['workId'],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: 'paean_0works_cancel',
|
|
173
|
+
description: 'Cancel a published work/bounty. Escrowed credits are refunded minus a cancellation fee. ' +
|
|
174
|
+
'Cannot cancel if there are active claims in progress.',
|
|
175
|
+
inputSchema: {
|
|
176
|
+
type: 'object',
|
|
177
|
+
properties: {
|
|
178
|
+
workId: {
|
|
179
|
+
type: 'string',
|
|
180
|
+
description: 'The ID of the work to cancel',
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
required: ['workId'],
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: 'paean_0works_claim',
|
|
188
|
+
description: 'Claim a work/bounty to start working on it. ' +
|
|
189
|
+
'This reserves a slot for you. After claiming, you must submit your work within the deadline. ' +
|
|
190
|
+
'Use paean_0works_get first to review the requirements before claiming.',
|
|
191
|
+
inputSchema: {
|
|
192
|
+
type: 'object',
|
|
193
|
+
properties: {
|
|
194
|
+
workId: {
|
|
195
|
+
type: 'string',
|
|
196
|
+
description: 'The ID of the work to claim',
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
required: ['workId'],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'paean_0works_submit',
|
|
204
|
+
description: 'Submit your completed work for a claimed bounty. ' +
|
|
205
|
+
'The submission data should match the requirements specified in the work. ' +
|
|
206
|
+
'Supports structured JSON data or plain text content. ' +
|
|
207
|
+
'After submission, the work will be reviewed (automatically or by the publisher).',
|
|
208
|
+
inputSchema: {
|
|
209
|
+
type: 'object',
|
|
210
|
+
properties: {
|
|
211
|
+
workId: {
|
|
212
|
+
type: 'string',
|
|
213
|
+
description: 'The ID of the work',
|
|
214
|
+
},
|
|
215
|
+
submissionData: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
description: 'Structured submission data. Use { "content": "..." } for plain text, ' +
|
|
218
|
+
'or provide structured data matching the work requirements ' +
|
|
219
|
+
'(e.g. { "pullRequestUrl": "...", "testResults": "...", "summary": "..." })',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
required: ['workId', 'submissionData'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: 'paean_0works_my_claim',
|
|
227
|
+
description: 'Check the status of your claim on a specific work. ' +
|
|
228
|
+
'Returns claim status, submission data, review feedback, and reward payment status.',
|
|
229
|
+
inputSchema: {
|
|
230
|
+
type: 'object',
|
|
231
|
+
properties: {
|
|
232
|
+
workId: {
|
|
233
|
+
type: 'string',
|
|
234
|
+
description: 'The ID of the work to check your claim for',
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
required: ['workId'],
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: 'paean_0works_review',
|
|
242
|
+
description: 'Review a submitted claim as the work publisher. ' +
|
|
243
|
+
'Approve to release the reward to the worker, request revision for changes, or reject.',
|
|
244
|
+
inputSchema: {
|
|
245
|
+
type: 'object',
|
|
246
|
+
properties: {
|
|
247
|
+
workId: {
|
|
248
|
+
type: 'string',
|
|
249
|
+
description: 'The ID of the work',
|
|
250
|
+
},
|
|
251
|
+
claimId: {
|
|
252
|
+
type: 'string',
|
|
253
|
+
description: 'The ID of the claim to review',
|
|
254
|
+
},
|
|
255
|
+
status: {
|
|
256
|
+
type: 'string',
|
|
257
|
+
enum: ['approved', 'rejected', 'revision_needed'],
|
|
258
|
+
description: 'Review decision',
|
|
259
|
+
},
|
|
260
|
+
feedback: {
|
|
261
|
+
type: 'string',
|
|
262
|
+
description: 'Review feedback for the worker',
|
|
263
|
+
},
|
|
264
|
+
score: {
|
|
265
|
+
type: 'number',
|
|
266
|
+
description: 'Optional quality score (0-100)',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
required: ['workId', 'claimId', 'status', 'feedback'],
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
name: 'paean_0works_list_claims',
|
|
274
|
+
description: 'List all claims/submissions for a work you published. ' +
|
|
275
|
+
'Use this to see who has claimed your work and review their submissions.',
|
|
276
|
+
inputSchema: {
|
|
277
|
+
type: 'object',
|
|
278
|
+
properties: {
|
|
279
|
+
workId: {
|
|
280
|
+
type: 'string',
|
|
281
|
+
description: 'The ID of the work to list claims for',
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
required: ['workId'],
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'paean_0works_my_published',
|
|
289
|
+
description: 'List all works/bounties you have published. ' +
|
|
290
|
+
'Shows status, claim counts, and reward info for each.',
|
|
291
|
+
inputSchema: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: 'paean_0works_my_claimed',
|
|
298
|
+
description: 'List all works/bounties you have claimed. ' +
|
|
299
|
+
'Shows claim status, submission status, and reward payment info.',
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: 'object',
|
|
302
|
+
properties: {},
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: 'paean_0works_credits',
|
|
307
|
+
description: 'Check your 0works credits balance. Shows available, escrowed, and total credits. ' +
|
|
308
|
+
'Escrowed credits are locked as rewards for published works.',
|
|
309
|
+
inputSchema: {
|
|
310
|
+
type: 'object',
|
|
311
|
+
properties: {},
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
];
|
|
315
|
+
}
|
|
316
|
+
// ============================================
|
|
317
|
+
// Tool Names Set (for routing)
|
|
318
|
+
// ============================================
|
|
319
|
+
export const WORKS_TOOL_NAMES = new Set([
|
|
320
|
+
'paean_0works_browse',
|
|
321
|
+
'paean_0works_get',
|
|
322
|
+
'paean_0works_publish',
|
|
323
|
+
'paean_0works_update',
|
|
324
|
+
'paean_0works_cancel',
|
|
325
|
+
'paean_0works_claim',
|
|
326
|
+
'paean_0works_submit',
|
|
327
|
+
'paean_0works_my_claim',
|
|
328
|
+
'paean_0works_review',
|
|
329
|
+
'paean_0works_list_claims',
|
|
330
|
+
'paean_0works_my_published',
|
|
331
|
+
'paean_0works_my_claimed',
|
|
332
|
+
'paean_0works_credits',
|
|
333
|
+
]);
|
|
334
|
+
// ============================================
|
|
335
|
+
// Tool Executor
|
|
336
|
+
// ============================================
|
|
337
|
+
export async function executeWorksTool(toolName, args) {
|
|
338
|
+
switch (toolName) {
|
|
339
|
+
case 'paean_0works_browse':
|
|
340
|
+
return browseWorks(args);
|
|
341
|
+
case 'paean_0works_get':
|
|
342
|
+
return getWorkDetail(args);
|
|
343
|
+
case 'paean_0works_publish':
|
|
344
|
+
return publishWork(args);
|
|
345
|
+
case 'paean_0works_update':
|
|
346
|
+
return updateWorkTool(args);
|
|
347
|
+
case 'paean_0works_cancel':
|
|
348
|
+
return cancelWorkTool(args);
|
|
349
|
+
case 'paean_0works_claim':
|
|
350
|
+
return claimWorkTool(args);
|
|
351
|
+
case 'paean_0works_submit':
|
|
352
|
+
return submitWorkTool(args);
|
|
353
|
+
case 'paean_0works_my_claim':
|
|
354
|
+
return myClaimTool(args);
|
|
355
|
+
case 'paean_0works_review':
|
|
356
|
+
return reviewClaimTool(args);
|
|
357
|
+
case 'paean_0works_list_claims':
|
|
358
|
+
return listClaimsTool(args);
|
|
359
|
+
case 'paean_0works_my_published':
|
|
360
|
+
return myPublishedTool();
|
|
361
|
+
case 'paean_0works_my_claimed':
|
|
362
|
+
return myClaimedTool();
|
|
363
|
+
case 'paean_0works_credits':
|
|
364
|
+
return creditsTool();
|
|
365
|
+
default:
|
|
366
|
+
return { success: false, error: `Unknown 0works tool: ${toolName}` };
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// ============================================
|
|
370
|
+
// Individual Tool Implementations
|
|
371
|
+
// ============================================
|
|
372
|
+
async function browseWorks(args) {
|
|
373
|
+
try {
|
|
374
|
+
const params = {};
|
|
375
|
+
if (args.status)
|
|
376
|
+
params.status = String(args.status);
|
|
377
|
+
if (args.tags)
|
|
378
|
+
params.tags = String(args.tags);
|
|
379
|
+
if (args.search)
|
|
380
|
+
params.search = String(args.search);
|
|
381
|
+
if (args.minReward)
|
|
382
|
+
params.minReward = String(args.minReward);
|
|
383
|
+
if (args.maxReward)
|
|
384
|
+
params.maxReward = String(args.maxReward);
|
|
385
|
+
if (args.sortBy)
|
|
386
|
+
params.sortBy = String(args.sortBy);
|
|
387
|
+
const page = Math.max(args.page || 1, 1);
|
|
388
|
+
const limit = Math.min(Math.max(args.limit || 20, 1), 50);
|
|
389
|
+
params.page = String(page);
|
|
390
|
+
params.limit = String(limit);
|
|
391
|
+
const result = await listWorks(params);
|
|
392
|
+
return {
|
|
393
|
+
success: true,
|
|
394
|
+
works: result.items.map(summarizeWork),
|
|
395
|
+
pagination: {
|
|
396
|
+
page,
|
|
397
|
+
limit,
|
|
398
|
+
total: result.total,
|
|
399
|
+
hasMore: page * limit < result.total,
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
return {
|
|
405
|
+
success: false,
|
|
406
|
+
error: error instanceof Error ? error.message : 'Failed to browse works',
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
async function getWorkDetail(args) {
|
|
411
|
+
const workId = args.workId;
|
|
412
|
+
if (!workId) {
|
|
413
|
+
return { success: false, error: 'workId is required' };
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
const result = await getWork(workId);
|
|
417
|
+
const w = result.work;
|
|
418
|
+
const availableSlots = w.maxClaims - w.currentClaims;
|
|
419
|
+
return {
|
|
420
|
+
success: true,
|
|
421
|
+
work: {
|
|
422
|
+
id: w.id,
|
|
423
|
+
title: w.title,
|
|
424
|
+
description: w.description,
|
|
425
|
+
requirements: w.requirements,
|
|
426
|
+
metadata: w.metadata,
|
|
427
|
+
tags: w.tags,
|
|
428
|
+
reward: {
|
|
429
|
+
amount: w.rewardAmount,
|
|
430
|
+
type: w.rewardType,
|
|
431
|
+
},
|
|
432
|
+
status: w.status,
|
|
433
|
+
reviewType: w.reviewType,
|
|
434
|
+
maxClaims: w.maxClaims,
|
|
435
|
+
currentClaims: w.currentClaims,
|
|
436
|
+
availableSlots,
|
|
437
|
+
canClaim: w.status === 'open' && availableSlots > 0,
|
|
438
|
+
deadline: w.deadline,
|
|
439
|
+
createdAt: w.createdAt,
|
|
440
|
+
updatedAt: w.updatedAt,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
return {
|
|
446
|
+
success: false,
|
|
447
|
+
error: error instanceof Error ? error.message : 'Failed to get work details',
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
async function publishWork(args) {
|
|
452
|
+
const title = args.title;
|
|
453
|
+
const description = args.description;
|
|
454
|
+
const rewardAmount = args.rewardAmount;
|
|
455
|
+
if (!title)
|
|
456
|
+
return { success: false, error: 'title is required' };
|
|
457
|
+
if (!description)
|
|
458
|
+
return { success: false, error: 'description is required' };
|
|
459
|
+
if (!rewardAmount || rewardAmount <= 0)
|
|
460
|
+
return { success: false, error: 'rewardAmount must be positive' };
|
|
461
|
+
try {
|
|
462
|
+
const payload = {
|
|
463
|
+
title,
|
|
464
|
+
description,
|
|
465
|
+
rewardAmount,
|
|
466
|
+
rewardType: args.rewardType || 'credits',
|
|
467
|
+
reviewType: args.reviewType || 'ai_auto',
|
|
468
|
+
maxClaims: args.maxClaims || 1,
|
|
469
|
+
};
|
|
470
|
+
if (args.requirements)
|
|
471
|
+
payload.requirements = args.requirements;
|
|
472
|
+
if (args.metadata)
|
|
473
|
+
payload.metadata = args.metadata;
|
|
474
|
+
if (args.tags)
|
|
475
|
+
payload.tags = args.tags;
|
|
476
|
+
if (args.deadline)
|
|
477
|
+
payload.deadline = args.deadline;
|
|
478
|
+
const result = await createWork(payload);
|
|
479
|
+
return {
|
|
480
|
+
success: true,
|
|
481
|
+
message: `Work published: "${result.work.title}"`,
|
|
482
|
+
work: {
|
|
483
|
+
id: result.work.id,
|
|
484
|
+
title: result.work.title,
|
|
485
|
+
rewardAmount: result.work.rewardAmount,
|
|
486
|
+
status: result.work.status,
|
|
487
|
+
reviewType: result.work.reviewType,
|
|
488
|
+
maxClaims: result.work.maxClaims,
|
|
489
|
+
},
|
|
490
|
+
hint: 'Credits have been escrowed. The work is now visible in the marketplace.',
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
return {
|
|
495
|
+
success: false,
|
|
496
|
+
error: error instanceof Error ? error.message : 'Failed to publish work',
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
async function updateWorkTool(args) {
|
|
501
|
+
const workId = args.workId;
|
|
502
|
+
if (!workId)
|
|
503
|
+
return { success: false, error: 'workId is required' };
|
|
504
|
+
const payload = {};
|
|
505
|
+
if (args.title)
|
|
506
|
+
payload.title = args.title;
|
|
507
|
+
if (args.description)
|
|
508
|
+
payload.description = args.description;
|
|
509
|
+
if (args.requirements)
|
|
510
|
+
payload.requirements = args.requirements;
|
|
511
|
+
if (args.metadata)
|
|
512
|
+
payload.metadata = args.metadata;
|
|
513
|
+
if (args.tags)
|
|
514
|
+
payload.tags = args.tags;
|
|
515
|
+
if (args.deadline)
|
|
516
|
+
payload.deadline = args.deadline;
|
|
517
|
+
if (Object.keys(payload).length === 0) {
|
|
518
|
+
return { success: false, error: 'At least one field to update is required' };
|
|
519
|
+
}
|
|
520
|
+
try {
|
|
521
|
+
const result = await updateWork(workId, payload);
|
|
522
|
+
return {
|
|
523
|
+
success: true,
|
|
524
|
+
message: 'Work updated successfully',
|
|
525
|
+
work: summarizeWork(result.work),
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
return {
|
|
530
|
+
success: false,
|
|
531
|
+
error: error instanceof Error ? error.message : 'Failed to update work',
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
async function cancelWorkTool(args) {
|
|
536
|
+
const workId = args.workId;
|
|
537
|
+
if (!workId)
|
|
538
|
+
return { success: false, error: 'workId is required' };
|
|
539
|
+
try {
|
|
540
|
+
const result = await cancelWork(workId);
|
|
541
|
+
return {
|
|
542
|
+
success: true,
|
|
543
|
+
message: 'Work cancelled',
|
|
544
|
+
refundAmount: result.refundAmount,
|
|
545
|
+
cancellationFee: result.cancellationFee,
|
|
546
|
+
work: {
|
|
547
|
+
id: result.work.id,
|
|
548
|
+
title: result.work.title,
|
|
549
|
+
status: result.work.status,
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
return {
|
|
555
|
+
success: false,
|
|
556
|
+
error: error instanceof Error ? error.message : 'Failed to cancel work',
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
async function claimWorkTool(args) {
|
|
561
|
+
const workId = args.workId;
|
|
562
|
+
if (!workId)
|
|
563
|
+
return { success: false, error: 'workId is required' };
|
|
564
|
+
try {
|
|
565
|
+
const result = await claimWork(workId);
|
|
566
|
+
return {
|
|
567
|
+
success: true,
|
|
568
|
+
message: 'Work claimed successfully. You can now start working on it.',
|
|
569
|
+
claim: {
|
|
570
|
+
id: result.claim.id,
|
|
571
|
+
workId: result.claim.workId,
|
|
572
|
+
status: result.claim.status,
|
|
573
|
+
createdAt: result.claim.createdAt,
|
|
574
|
+
},
|
|
575
|
+
hint: 'Use paean_0works_submit to submit your completed work when ready.',
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
return {
|
|
580
|
+
success: false,
|
|
581
|
+
error: error instanceof Error ? error.message : 'Failed to claim work',
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
async function submitWorkTool(args) {
|
|
586
|
+
const workId = args.workId;
|
|
587
|
+
const submissionData = args.submissionData;
|
|
588
|
+
if (!workId)
|
|
589
|
+
return { success: false, error: 'workId is required' };
|
|
590
|
+
if (!submissionData)
|
|
591
|
+
return { success: false, error: 'submissionData is required' };
|
|
592
|
+
try {
|
|
593
|
+
// First get our claim to find the claimId
|
|
594
|
+
const myClaimResult = await getMyClaim(workId);
|
|
595
|
+
const claim = myClaimResult.claim;
|
|
596
|
+
if (!claim) {
|
|
597
|
+
return {
|
|
598
|
+
success: false,
|
|
599
|
+
error: 'You have not claimed this work. Claim it first with paean_0works_claim.',
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (claim.status !== 'claimed' && claim.status !== 'revision_needed') {
|
|
603
|
+
return {
|
|
604
|
+
success: false,
|
|
605
|
+
error: `Cannot submit: claim status is "${claim.status}". Only "claimed" or "revision_needed" claims can be submitted.`,
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
const result = await submitClaim(workId, claim.id, submissionData);
|
|
609
|
+
return {
|
|
610
|
+
success: true,
|
|
611
|
+
message: 'Work submitted for review',
|
|
612
|
+
claim: {
|
|
613
|
+
id: result.claim.id,
|
|
614
|
+
status: result.claim.status,
|
|
615
|
+
submittedAt: result.claim.submittedAt,
|
|
616
|
+
},
|
|
617
|
+
hint: 'Use paean_0works_my_claim to check the review status.',
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
catch (error) {
|
|
621
|
+
return {
|
|
622
|
+
success: false,
|
|
623
|
+
error: error instanceof Error ? error.message : 'Failed to submit work',
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function myClaimTool(args) {
|
|
628
|
+
const workId = args.workId;
|
|
629
|
+
if (!workId)
|
|
630
|
+
return { success: false, error: 'workId is required' };
|
|
631
|
+
try {
|
|
632
|
+
const result = await getMyClaim(workId);
|
|
633
|
+
const c = result.claim;
|
|
634
|
+
return {
|
|
635
|
+
success: true,
|
|
636
|
+
claim: {
|
|
637
|
+
id: c.id,
|
|
638
|
+
workId: c.workId,
|
|
639
|
+
status: c.status,
|
|
640
|
+
submissionData: c.submissionData,
|
|
641
|
+
submittedAt: c.submittedAt,
|
|
642
|
+
aiReviewScore: c.aiReviewScore,
|
|
643
|
+
aiReviewFeedback: c.aiReviewFeedback,
|
|
644
|
+
humanReviewFeedback: c.humanReviewFeedback,
|
|
645
|
+
rewardPaid: c.rewardPaid,
|
|
646
|
+
rewardPaidAt: c.rewardPaidAt,
|
|
647
|
+
createdAt: c.createdAt,
|
|
648
|
+
updatedAt: c.updatedAt,
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
return {
|
|
654
|
+
success: false,
|
|
655
|
+
error: error instanceof Error ? error.message : 'Failed to get claim status',
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
async function reviewClaimTool(args) {
|
|
660
|
+
const workId = args.workId;
|
|
661
|
+
const claimId = args.claimId;
|
|
662
|
+
const status = args.status;
|
|
663
|
+
const feedback = args.feedback;
|
|
664
|
+
const score = args.score;
|
|
665
|
+
if (!workId)
|
|
666
|
+
return { success: false, error: 'workId is required' };
|
|
667
|
+
if (!claimId)
|
|
668
|
+
return { success: false, error: 'claimId is required' };
|
|
669
|
+
if (!status)
|
|
670
|
+
return { success: false, error: 'status is required' };
|
|
671
|
+
if (!feedback)
|
|
672
|
+
return { success: false, error: 'feedback is required' };
|
|
673
|
+
const validStatuses = ['approved', 'rejected', 'revision_needed'];
|
|
674
|
+
if (!validStatuses.includes(status)) {
|
|
675
|
+
return { success: false, error: `Invalid status. Must be one of: ${validStatuses.join(', ')}` };
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
const review = { status, feedback };
|
|
679
|
+
if (score !== undefined)
|
|
680
|
+
review.score = score;
|
|
681
|
+
const result = await reviewClaim(workId, claimId, review);
|
|
682
|
+
const actionMsg = status === 'approved'
|
|
683
|
+
? 'Claim approved. Reward will be released to the worker.'
|
|
684
|
+
: status === 'rejected'
|
|
685
|
+
? 'Claim rejected.'
|
|
686
|
+
: 'Revision requested. Worker has been notified.';
|
|
687
|
+
return {
|
|
688
|
+
success: true,
|
|
689
|
+
message: actionMsg,
|
|
690
|
+
claim: {
|
|
691
|
+
id: result.claim.id,
|
|
692
|
+
status: result.claim.status,
|
|
693
|
+
rewardPaid: result.claim.rewardPaid,
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
return {
|
|
699
|
+
success: false,
|
|
700
|
+
error: error instanceof Error ? error.message : 'Failed to review claim',
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
async function listClaimsTool(args) {
|
|
705
|
+
const workId = args.workId;
|
|
706
|
+
if (!workId)
|
|
707
|
+
return { success: false, error: 'workId is required' };
|
|
708
|
+
try {
|
|
709
|
+
const result = await listClaims(workId);
|
|
710
|
+
return {
|
|
711
|
+
success: true,
|
|
712
|
+
claims: result.claims.map((c) => ({
|
|
713
|
+
id: c.id,
|
|
714
|
+
claimerId: c.claimerId,
|
|
715
|
+
claimerType: c.claimerType,
|
|
716
|
+
status: c.status,
|
|
717
|
+
submittedAt: c.submittedAt,
|
|
718
|
+
submissionData: c.submissionData,
|
|
719
|
+
aiReviewScore: c.aiReviewScore,
|
|
720
|
+
rewardPaid: c.rewardPaid,
|
|
721
|
+
createdAt: c.createdAt,
|
|
722
|
+
})),
|
|
723
|
+
count: result.claims.length,
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
catch (error) {
|
|
727
|
+
return {
|
|
728
|
+
success: false,
|
|
729
|
+
error: error instanceof Error ? error.message : 'Failed to list claims',
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async function myPublishedTool() {
|
|
734
|
+
try {
|
|
735
|
+
const result = await listMyPublishedWorks();
|
|
736
|
+
return {
|
|
737
|
+
success: true,
|
|
738
|
+
works: result.works.map(summarizeWork),
|
|
739
|
+
count: result.works.length,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
catch (error) {
|
|
743
|
+
return {
|
|
744
|
+
success: false,
|
|
745
|
+
error: error instanceof Error ? error.message : 'Failed to list published works',
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
async function myClaimedTool() {
|
|
750
|
+
try {
|
|
751
|
+
const result = await listMyClaimedWorks();
|
|
752
|
+
return {
|
|
753
|
+
success: true,
|
|
754
|
+
claims: result.claims.map((c) => ({
|
|
755
|
+
id: c.id,
|
|
756
|
+
workId: c.workId,
|
|
757
|
+
status: c.status,
|
|
758
|
+
submittedAt: c.submittedAt,
|
|
759
|
+
rewardPaid: c.rewardPaid,
|
|
760
|
+
rewardPaidAt: c.rewardPaidAt,
|
|
761
|
+
createdAt: c.createdAt,
|
|
762
|
+
})),
|
|
763
|
+
count: result.claims.length,
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
catch (error) {
|
|
767
|
+
return {
|
|
768
|
+
success: false,
|
|
769
|
+
error: error instanceof Error ? error.message : 'Failed to list claimed works',
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
async function creditsTool() {
|
|
774
|
+
try {
|
|
775
|
+
const result = await getWorksCreditsBalance();
|
|
776
|
+
return {
|
|
777
|
+
success: true,
|
|
778
|
+
credits: {
|
|
779
|
+
available: result.available,
|
|
780
|
+
escrowed: result.escrowed,
|
|
781
|
+
total: result.total,
|
|
782
|
+
},
|
|
783
|
+
hint: result.available < 10
|
|
784
|
+
? 'Credits are low. Top up with paean_get_deposit_info or earn credits by completing works.'
|
|
785
|
+
: undefined,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
catch (error) {
|
|
789
|
+
return {
|
|
790
|
+
success: false,
|
|
791
|
+
error: error instanceof Error ? error.message : 'Failed to get credits balance',
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// ============================================
|
|
796
|
+
// Helpers
|
|
797
|
+
// ============================================
|
|
798
|
+
function summarizeWork(w) {
|
|
799
|
+
return {
|
|
800
|
+
id: w.id,
|
|
801
|
+
title: w.title,
|
|
802
|
+
tags: w.tags,
|
|
803
|
+
reward: `${w.rewardAmount} ${w.rewardType}`,
|
|
804
|
+
availableSlots: w.maxClaims - w.currentClaims,
|
|
805
|
+
maxClaims: w.maxClaims,
|
|
806
|
+
reviewType: w.reviewType,
|
|
807
|
+
status: w.status,
|
|
808
|
+
deadline: w.deadline,
|
|
809
|
+
createdAt: w.createdAt,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
//# sourceMappingURL=works-tools.js.map
|