@wenrwa/marketplace-cli 0.1.0 → 0.3.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/README.md +18 -1
- package/dist/__tests__/agent.test.d.ts +1 -0
- package/dist/__tests__/agent.test.js +138 -0
- package/dist/__tests__/apps.test.d.ts +1 -0
- package/dist/__tests__/apps.test.js +160 -0
- package/dist/__tests__/auth.test.d.ts +1 -0
- package/dist/__tests__/auth.test.js +94 -0
- package/dist/__tests__/bounty.test.d.ts +1 -0
- package/dist/__tests__/bounty.test.js +185 -0
- package/dist/__tests__/client.test.d.ts +1 -0
- package/dist/__tests__/client.test.js +106 -0
- package/dist/__tests__/config.test.d.ts +1 -0
- package/dist/__tests__/config.test.js +99 -0
- package/dist/__tests__/dashboard-helpers.test.d.ts +1 -0
- package/dist/__tests__/dashboard-helpers.test.js +123 -0
- package/dist/__tests__/format.test.d.ts +1 -0
- package/dist/__tests__/format.test.js +144 -0
- package/dist/__tests__/helpers.d.ts +7 -0
- package/dist/__tests__/helpers.js +12 -0
- package/dist/__tests__/treasury.test.d.ts +1 -0
- package/dist/__tests__/treasury.test.js +122 -0
- package/dist/__tests__/websocket.test.d.ts +1 -0
- package/dist/__tests__/websocket.test.js +61 -0
- package/dist/__tests__/workspace.test.d.ts +1 -0
- package/dist/__tests__/workspace.test.js +105 -0
- package/dist/commands/agent.d.ts +0 -0
- package/dist/commands/agent.js +0 -0
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +200 -0
- package/dist/commands/auth.d.ts +0 -0
- package/dist/commands/auth.js +0 -0
- package/dist/commands/bounty.d.ts +0 -0
- package/dist/commands/bounty.js +128 -7
- package/dist/commands/dashboard.d.ts +31 -0
- package/dist/commands/dashboard.js +5 -0
- package/dist/commands/keys.d.ts +2 -0
- package/dist/commands/keys.js +72 -0
- package/dist/commands/treasury.d.ts +0 -0
- package/dist/commands/treasury.js +2 -2
- package/dist/commands/webhook.d.ts +2 -0
- package/dist/commands/webhook.js +131 -0
- package/dist/commands/workspace.d.ts +1 -0
- package/dist/commands/workspace.js +293 -14
- package/dist/index.d.ts +0 -0
- package/dist/index.js +8 -1
- package/dist/utils/client.d.ts +1 -0
- package/dist/utils/client.js +3 -0
- package/dist/utils/config.d.ts +0 -0
- package/dist/utils/config.js +0 -0
- package/dist/utils/format.d.ts +0 -1
- package/dist/utils/format.js +2 -11
- package/dist/utils/websocket.d.ts +0 -0
- package/dist/utils/websocket.js +0 -0
- package/package.json +5 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
+
const websocket_1 = require("../utils/websocket");
|
|
8
|
+
beforeAll(() => {
|
|
9
|
+
chalk_1.default.level = 0;
|
|
10
|
+
});
|
|
11
|
+
function makeEvent(event, data, timestamp) {
|
|
12
|
+
return { event, data, timestamp: timestamp || '2024-06-15T14:30:00.000Z' };
|
|
13
|
+
}
|
|
14
|
+
describe('formatEventPretty()', () => {
|
|
15
|
+
it('formats bounty:created', () => {
|
|
16
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('bounty:created', { title: 'Build API', rewardAmount: '100', rewardSymbol: 'USDC' }));
|
|
17
|
+
expect(result).toContain('[new]');
|
|
18
|
+
expect(result).toContain('Build API');
|
|
19
|
+
});
|
|
20
|
+
it('formats bounty:bid', () => {
|
|
21
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('bounty:bid', { agentWallet: 'abcdefghijklmnop', bidAmount: '50', bountyId: 'bounty123456789' }));
|
|
22
|
+
expect(result).toContain('[bid]');
|
|
23
|
+
});
|
|
24
|
+
it('formats bounty:assigned', () => {
|
|
25
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('bounty:assigned', { bountyId: 'bounty123456789', assigneeWallet: 'wallet12345678' }));
|
|
26
|
+
expect(result).toContain('[assigned]');
|
|
27
|
+
});
|
|
28
|
+
it('formats bounty:progress', () => {
|
|
29
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('bounty:progress', { percentage: 50, bountyId: 'bounty123456789', message: 'Half done' }));
|
|
30
|
+
expect(result).toContain('[progress]');
|
|
31
|
+
expect(result).toContain('50%');
|
|
32
|
+
});
|
|
33
|
+
it('formats bounty:completed', () => {
|
|
34
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('bounty:completed', { bountyId: 'bounty123456789' }));
|
|
35
|
+
expect(result).toContain('[complete]');
|
|
36
|
+
});
|
|
37
|
+
it('formats unknown event as fallback', () => {
|
|
38
|
+
const result = (0, websocket_1.formatEventPretty)(makeEvent('custom:event', { key: 'value' }));
|
|
39
|
+
expect(result).toContain('[custom:event]');
|
|
40
|
+
});
|
|
41
|
+
it('uses current time when timestamp is missing', () => {
|
|
42
|
+
const event = { event: 'bounty:completed', data: { bountyId: 'b1' } };
|
|
43
|
+
const result = (0, websocket_1.formatEventPretty)(event);
|
|
44
|
+
expect(result).toContain('[complete]');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('formatEventJson()', () => {
|
|
48
|
+
it('returns JSON with ts, event, and data', () => {
|
|
49
|
+
const event = makeEvent('bounty:created', { title: 'Test' });
|
|
50
|
+
const result = JSON.parse((0, websocket_1.formatEventJson)(event));
|
|
51
|
+
expect(result.ts).toBe('2024-06-15T14:30:00.000Z');
|
|
52
|
+
expect(result.event).toBe('bounty:created');
|
|
53
|
+
expect(result.data).toEqual({ title: 'Test' });
|
|
54
|
+
});
|
|
55
|
+
it('uses current time when timestamp missing', () => {
|
|
56
|
+
const event = { event: 'test', data: {} };
|
|
57
|
+
const result = JSON.parse((0, websocket_1.formatEventJson)(event));
|
|
58
|
+
expect(result.ts).toBeDefined();
|
|
59
|
+
expect(result.event).toBe('test');
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
+
const helpers_1 = require("./helpers");
|
|
8
|
+
const mockClient = (0, helpers_1.createMockClient)();
|
|
9
|
+
jest.mock('../utils/client', () => ({
|
|
10
|
+
getClient: () => mockClient,
|
|
11
|
+
}));
|
|
12
|
+
// Mock websocket to prevent import issues
|
|
13
|
+
jest.mock('../utils/websocket', () => ({
|
|
14
|
+
connectWebSocket: jest.fn(),
|
|
15
|
+
formatEventPretty: jest.fn(),
|
|
16
|
+
formatEventJson: jest.fn(),
|
|
17
|
+
}));
|
|
18
|
+
const workspace_1 = require("../commands/workspace");
|
|
19
|
+
beforeAll(() => {
|
|
20
|
+
chalk_1.default.level = 0;
|
|
21
|
+
});
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
jest.clearAllMocks();
|
|
24
|
+
});
|
|
25
|
+
async function runCommand(...args) {
|
|
26
|
+
await workspace_1.workspaceCommand.parseAsync(args, { from: 'user' });
|
|
27
|
+
}
|
|
28
|
+
describe('workspace list', () => {
|
|
29
|
+
it('renders a table of workspaces', async () => {
|
|
30
|
+
mockClient.get.mockResolvedValue({
|
|
31
|
+
workspaces: [
|
|
32
|
+
{ id: 'ws-abc-12345678', name: 'Test Workspace', mode: 'open', bounty_count: 5, agent_count: 2, created_at: '2024-01-01' },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
const spy = jest.spyOn(console, 'log').mockImplementation();
|
|
36
|
+
await runCommand('list');
|
|
37
|
+
expect(mockClient.get).toHaveBeenCalledWith('/workspaces');
|
|
38
|
+
const output = spy.mock.calls.map(c => c[0]).join('\n');
|
|
39
|
+
expect(output).toContain('Test Workspace');
|
|
40
|
+
spy.mockRestore();
|
|
41
|
+
});
|
|
42
|
+
it('handles empty workspace list', async () => {
|
|
43
|
+
mockClient.get.mockResolvedValue({ workspaces: [] });
|
|
44
|
+
const spy = jest.spyOn(console, 'log').mockImplementation();
|
|
45
|
+
await runCommand('list');
|
|
46
|
+
expect(spy).toHaveBeenCalledWith('No workspaces found.');
|
|
47
|
+
spy.mockRestore();
|
|
48
|
+
});
|
|
49
|
+
it('handles API error', async () => {
|
|
50
|
+
mockClient.get.mockRejectedValue(new Error('Network error'));
|
|
51
|
+
const errSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
52
|
+
await runCommand('list');
|
|
53
|
+
expect(errSpy).toHaveBeenCalledWith(expect.stringContaining('Network error'));
|
|
54
|
+
errSpy.mockRestore();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe('workspace status', () => {
|
|
58
|
+
it('displays workspace details with bounties and treasury', async () => {
|
|
59
|
+
mockClient.get.mockImplementation((path) => {
|
|
60
|
+
if (path.includes('/treasury')) {
|
|
61
|
+
return Promise.resolve({ balance: '1000', total_funded: '5000', total_paid: '4000' });
|
|
62
|
+
}
|
|
63
|
+
if (path.includes('/bounties')) {
|
|
64
|
+
return Promise.resolve({
|
|
65
|
+
bounties: [{ title: 'Build Feature', status: 'open', assignee_wallet: null, reward_amount: '100', reward_symbol: 'USDC', blocked_by: [] }],
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return Promise.resolve({
|
|
69
|
+
workspace: { id: 'ws1', name: 'Main', mode: 'open', use_escrow: true, created_at: '2024-01-01' },
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
const spy = jest.spyOn(console, 'log').mockImplementation();
|
|
73
|
+
await runCommand('status', 'ws1');
|
|
74
|
+
const output = spy.mock.calls.map(c => c[0]).join('\n');
|
|
75
|
+
expect(output).toContain('Main');
|
|
76
|
+
expect(output).toContain('Build Feature');
|
|
77
|
+
expect(output).toContain('Treasury');
|
|
78
|
+
spy.mockRestore();
|
|
79
|
+
});
|
|
80
|
+
it('handles missing treasury gracefully', async () => {
|
|
81
|
+
mockClient.get.mockImplementation((path) => {
|
|
82
|
+
if (path.includes('/treasury'))
|
|
83
|
+
return Promise.reject(new Error('Not found'));
|
|
84
|
+
if (path.includes('/bounties'))
|
|
85
|
+
return Promise.resolve({ bounties: [] });
|
|
86
|
+
return Promise.resolve({
|
|
87
|
+
workspace: { id: 'ws1', name: 'Test WS', mode: 'open', use_escrow: false, created_at: '2024-01-01' },
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
const spy = jest.spyOn(console, 'log').mockImplementation();
|
|
91
|
+
await runCommand('status', 'ws1');
|
|
92
|
+
const output = spy.mock.calls.map(c => c[0]).join('\n');
|
|
93
|
+
expect(output).toContain('Test WS');
|
|
94
|
+
// Treasury heading should NOT appear since the endpoint rejects
|
|
95
|
+
expect(output).not.toContain('Balance:');
|
|
96
|
+
spy.mockRestore();
|
|
97
|
+
});
|
|
98
|
+
it('handles workspace fetch error', async () => {
|
|
99
|
+
mockClient.get.mockRejectedValue(new Error('Workspace not found'));
|
|
100
|
+
const errSpy = jest.spyOn(console, 'error').mockImplementation();
|
|
101
|
+
await runCommand('status', 'ws-bad');
|
|
102
|
+
expect(errSpy).toHaveBeenCalledWith(expect.stringContaining('Workspace not found'));
|
|
103
|
+
errSpy.mockRestore();
|
|
104
|
+
});
|
|
105
|
+
});
|
package/dist/commands/agent.d.ts
CHANGED
|
File without changes
|
package/dist/commands/agent.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.appsCommand = void 0;
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const client_1 = require("../utils/client");
|
|
10
|
+
const format_1 = require("../utils/format");
|
|
11
|
+
const fs_1 = require("fs");
|
|
12
|
+
exports.appsCommand = new commander_1.Command('apps').description('Hosted apps management');
|
|
13
|
+
exports.appsCommand
|
|
14
|
+
.command('list')
|
|
15
|
+
.description('List your hosted apps')
|
|
16
|
+
.option('--status <status>', 'Filter by status (pending, building, deployed, failed)')
|
|
17
|
+
.option('--limit <n>', 'Max results', '20')
|
|
18
|
+
.action(async (opts) => {
|
|
19
|
+
try {
|
|
20
|
+
const client = (0, client_1.getClient)();
|
|
21
|
+
const params = new URLSearchParams();
|
|
22
|
+
params.set('ownerWallet', client.getApiKey());
|
|
23
|
+
if (opts.status)
|
|
24
|
+
params.set('status', opts.status);
|
|
25
|
+
params.set('limit', opts.limit);
|
|
26
|
+
const data = await client.get(`/projects?${params}`);
|
|
27
|
+
const projects = data.projects || [];
|
|
28
|
+
if (projects.length === 0) {
|
|
29
|
+
console.log('No apps found. Create one with: wen-market apps create');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
console.log(`${chalk_1.default.dim(`Showing ${projects.length} of ${data.total || projects.length} apps`)}\n`);
|
|
33
|
+
console.log((0, format_1.makeTable)(['ID', 'Title', 'Slug', 'Status', 'URL', 'Created'], projects.map((p) => [
|
|
34
|
+
(0, format_1.shorten)(p.id),
|
|
35
|
+
p.title.slice(0, 30),
|
|
36
|
+
`${p.slug}.wenrwa.app`,
|
|
37
|
+
(0, format_1.statusColor)(p.status),
|
|
38
|
+
p.deployed_url || p.preview_url || '—',
|
|
39
|
+
p.created_at ? (0, format_1.formatTimeAgo)(p.created_at) : '—',
|
|
40
|
+
])));
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
(0, format_1.error)(err.message);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
exports.appsCommand
|
|
47
|
+
.command('create')
|
|
48
|
+
.description('Create a new hosted app')
|
|
49
|
+
.requiredOption('--title <title>', 'App title')
|
|
50
|
+
.requiredOption('--reward <amount>', 'Reward amount in USDC')
|
|
51
|
+
.requiredOption('--deadline <date>', 'Deadline (ISO 8601)')
|
|
52
|
+
.option('--description <desc>', 'App description')
|
|
53
|
+
.option('--framework <fw>', 'Framework (react, nextjs, vue, svelte, vanilla)', 'react')
|
|
54
|
+
.option('--visibility <vis>', 'Visibility (public, unlisted)', 'public')
|
|
55
|
+
.action(async (opts) => {
|
|
56
|
+
try {
|
|
57
|
+
const client = (0, client_1.getClient)();
|
|
58
|
+
const amountMicro = String(Math.round(parseFloat(opts.reward) * 1e6));
|
|
59
|
+
const data = await client.post('/projects', {
|
|
60
|
+
title: opts.title,
|
|
61
|
+
description: opts.description || opts.title,
|
|
62
|
+
framework: opts.framework,
|
|
63
|
+
visibility: opts.visibility,
|
|
64
|
+
rewardAmount: amountMicro,
|
|
65
|
+
deadline: new Date(opts.deadline).toISOString(),
|
|
66
|
+
});
|
|
67
|
+
(0, format_1.heading)('App Created');
|
|
68
|
+
console.log(` Project ID: ${data.project.id}`);
|
|
69
|
+
console.log(` Bounty ID: ${data.bountyId}`);
|
|
70
|
+
console.log(` Slug: ${data.project.slug}.wenrwa.app`);
|
|
71
|
+
console.log(` Status: ${(0, format_1.statusColor)(data.project.status)}`);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
(0, format_1.error)(err.message);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
exports.appsCommand
|
|
78
|
+
.command('edit')
|
|
79
|
+
.description('Request an edit to an existing app (creates a new bounty)')
|
|
80
|
+
.requiredOption('--project <id>', 'Project ID to edit')
|
|
81
|
+
.requiredOption('--description <desc>', 'Description of the changes')
|
|
82
|
+
.requiredOption('--reward <amount>', 'Reward amount in USDC')
|
|
83
|
+
.requiredOption('--deadline <date>', 'Deadline (ISO 8601)')
|
|
84
|
+
.action(async (opts) => {
|
|
85
|
+
try {
|
|
86
|
+
const client = (0, client_1.getClient)();
|
|
87
|
+
const amountMicro = String(Math.round(parseFloat(opts.reward) * 1e6));
|
|
88
|
+
const data = await client.post(`/projects/${opts.project}/bounties`, {
|
|
89
|
+
description: opts.description,
|
|
90
|
+
rewardAmount: amountMicro,
|
|
91
|
+
deadline: new Date(opts.deadline).toISOString(),
|
|
92
|
+
});
|
|
93
|
+
(0, format_1.heading)('Edit Bounty Created');
|
|
94
|
+
console.log(` Project ID: ${opts.project}`);
|
|
95
|
+
console.log(` Bounty ID: ${data.bountyId}`);
|
|
96
|
+
console.log('');
|
|
97
|
+
console.log(chalk_1.default.dim('An agent will pick this up, download the existing source, apply your changes, and redeploy.'));
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
(0, format_1.error)(err.message);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
exports.appsCommand
|
|
104
|
+
.command('status')
|
|
105
|
+
.argument('<id>', 'Project ID')
|
|
106
|
+
.description('Show app details')
|
|
107
|
+
.action(async (id) => {
|
|
108
|
+
try {
|
|
109
|
+
const client = (0, client_1.getClient)();
|
|
110
|
+
const data = await client.get(`/projects/${id}`);
|
|
111
|
+
const p = data.project;
|
|
112
|
+
(0, format_1.heading)(`App: ${p.title}`);
|
|
113
|
+
console.log(` ID: ${p.id}`);
|
|
114
|
+
console.log(` Slug: ${p.slug}.wenrwa.app`);
|
|
115
|
+
console.log(` Status: ${(0, format_1.statusColor)(p.status)}`);
|
|
116
|
+
console.log(` Framework: ${p.framework || '—'}`);
|
|
117
|
+
console.log(` Visibility: ${p.visibility}`);
|
|
118
|
+
console.log(` Preview URL: ${p.preview_url || '—'}`);
|
|
119
|
+
console.log(` Deployed URL: ${p.deployed_url || '—'}`);
|
|
120
|
+
console.log(` Created: ${p.created_at}`);
|
|
121
|
+
if (p.deployed_at)
|
|
122
|
+
console.log(` Deployed: ${p.deployed_at}`);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
(0, format_1.error)(err.message);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
exports.appsCommand
|
|
129
|
+
.command('download')
|
|
130
|
+
.argument('<id>', 'Project ID')
|
|
131
|
+
.option('-o, --output <path>', 'Output file path', 'source.zip')
|
|
132
|
+
.description('Download source.zip')
|
|
133
|
+
.action(async (id, opts) => {
|
|
134
|
+
try {
|
|
135
|
+
const client = (0, client_1.getClient)();
|
|
136
|
+
const url = `${client.getApiUrl()}/projects/${id}/source`;
|
|
137
|
+
const res = await fetch(url, {
|
|
138
|
+
headers: { 'X-Wallet-Pubkey': client.getApiKey() },
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
const data = await res.json().catch(() => ({}));
|
|
142
|
+
throw new Error(data?.error?.message || `HTTP ${res.status}`);
|
|
143
|
+
}
|
|
144
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
145
|
+
(0, fs_1.writeFileSync)(opts.output, buffer);
|
|
146
|
+
console.log(chalk_1.default.green(`Downloaded to ${opts.output} (${buffer.length} bytes)`));
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
(0, format_1.error)(err.message);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
exports.appsCommand
|
|
153
|
+
.command('export-github')
|
|
154
|
+
.argument('<id>', 'Project ID')
|
|
155
|
+
.option('--repo <name>', 'GitHub repo name')
|
|
156
|
+
.option('--private', 'Create private repo')
|
|
157
|
+
.description('Export source to GitHub')
|
|
158
|
+
.action(async (id, opts) => {
|
|
159
|
+
try {
|
|
160
|
+
const client = (0, client_1.getClient)();
|
|
161
|
+
const data = await client.post(`/projects/${id}/export-github`, {
|
|
162
|
+
repoName: opts.repo,
|
|
163
|
+
isPrivate: opts.private ?? false,
|
|
164
|
+
});
|
|
165
|
+
console.log(chalk_1.default.green(`Exported to GitHub: ${data.repoUrl}`));
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
if (err.message?.includes('not connected')) {
|
|
169
|
+
console.log(chalk_1.default.yellow('GitHub not connected. Visit the web app to complete OAuth.'));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
(0, format_1.error)(err.message);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
exports.appsCommand
|
|
177
|
+
.command('deployments')
|
|
178
|
+
.argument('<id>', 'Project ID')
|
|
179
|
+
.description('List deployment history')
|
|
180
|
+
.action(async (id) => {
|
|
181
|
+
try {
|
|
182
|
+
const client = (0, client_1.getClient)();
|
|
183
|
+
const data = await client.get(`/projects/${id}/deployments`);
|
|
184
|
+
const deployments = data.deployments || [];
|
|
185
|
+
if (deployments.length === 0) {
|
|
186
|
+
console.log('No deployments yet.');
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
console.log((0, format_1.makeTable)(['ID', 'Status', 'URL', 'Initiated By', 'Created'], deployments.map((d) => [
|
|
190
|
+
(0, format_1.shorten)(d.id),
|
|
191
|
+
(0, format_1.statusColor)(d.status),
|
|
192
|
+
d.deployed_url || '—',
|
|
193
|
+
(0, format_1.shorten)(d.initiated_by),
|
|
194
|
+
d.created_at ? (0, format_1.formatTimeAgo)(d.created_at) : '—',
|
|
195
|
+
])));
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
(0, format_1.error)(err.message);
|
|
199
|
+
}
|
|
200
|
+
});
|
package/dist/commands/auth.d.ts
CHANGED
|
File without changes
|
package/dist/commands/auth.js
CHANGED
|
File without changes
|
|
File without changes
|
package/dist/commands/bounty.js
CHANGED
|
@@ -65,9 +65,20 @@ exports.bountyCommand
|
|
|
65
65
|
console.log(` Assignee: ${b.assignee_wallet || '—'}`);
|
|
66
66
|
console.log(` Assignment: ${b.assignment_mode}`);
|
|
67
67
|
console.log(` Verification: ${b.verification_mode}`);
|
|
68
|
+
if (b.expected_deliverable_type && b.expected_deliverable_type !== 'generic') {
|
|
69
|
+
const labels = { pr: 'Pull Request', document: 'Document', report: 'Report' };
|
|
70
|
+
console.log(` Deliverable: ${labels[b.expected_deliverable_type] || b.expected_deliverable_type}`);
|
|
71
|
+
}
|
|
68
72
|
console.log(` Deadline: ${b.deadline || '—'}`);
|
|
73
|
+
if (b.bidding_ends_at) {
|
|
74
|
+
const biddingEnd = new Date(b.bidding_ends_at);
|
|
75
|
+
const isOpen = biddingEnd > new Date();
|
|
76
|
+
console.log(` Bidding ends: ${b.bidding_ends_at} ${isOpen ? chalk_1.default.green('(open)') : chalk_1.default.dim('(closed)')}`);
|
|
77
|
+
}
|
|
69
78
|
console.log(` Max retries: ${b.max_retries ?? 0}`);
|
|
70
79
|
console.log(` Retry count: ${b.retry_count ?? 0}`);
|
|
80
|
+
console.log(` Max revisions: ${b.max_revisions ?? 2}`);
|
|
81
|
+
console.log(` Revision count: ${b.revision_count ?? 0}`);
|
|
71
82
|
console.log(` Created: ${b.created_at}`);
|
|
72
83
|
if (b.blocked_by?.length) {
|
|
73
84
|
console.log(` Blocked by: ${b.blocked_by.join(', ')}`);
|
|
@@ -75,6 +86,10 @@ exports.bountyCommand
|
|
|
75
86
|
if (b.result_url) {
|
|
76
87
|
console.log(` Result URL: ${b.result_url}`);
|
|
77
88
|
}
|
|
89
|
+
// Show PR URL from latest submission if available
|
|
90
|
+
if (b.pr_url) {
|
|
91
|
+
console.log(` PR URL: ${b.pr_url}`);
|
|
92
|
+
}
|
|
78
93
|
if (b.task_schema) {
|
|
79
94
|
(0, format_1.heading)('Task Schema');
|
|
80
95
|
console.log(JSON.stringify(b.task_schema, null, 2));
|
|
@@ -84,13 +99,32 @@ exports.bountyCommand
|
|
|
84
99
|
const bidData = await client.get(`/bounties/${bountyId}/bids`);
|
|
85
100
|
const bids = bidData.bids || [];
|
|
86
101
|
if (bids.length > 0) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
102
|
+
const hasBidding = !!b.bidding_ends_at;
|
|
103
|
+
(0, format_1.heading)(hasBidding ? `Bids (${bids.length}) — Ranked by value score` : 'Bids');
|
|
104
|
+
const headers = hasBidding
|
|
105
|
+
? ['#', 'Agent', 'Amount', 'Score', 'Rep', 'Status', 'Message']
|
|
106
|
+
: ['Agent', 'Amount', 'Status', 'Message'];
|
|
107
|
+
const rows = bids.map((bid, i) => {
|
|
108
|
+
const agent = bid.agent_name || (0, format_1.shorten)(bid.agent_wallet);
|
|
109
|
+
if (hasBidding) {
|
|
110
|
+
return [
|
|
111
|
+
String(i + 1),
|
|
112
|
+
agent,
|
|
113
|
+
(0, format_1.formatReward)(bid.amount || bid.bid_amount, b.reward_symbol),
|
|
114
|
+
bid.value_score != null ? bid.value_score.toFixed(1) : '—',
|
|
115
|
+
bid.weighted_reputation != null ? `${bid.weighted_reputation.toFixed(1)}/5` : '—',
|
|
116
|
+
(0, format_1.statusColor)(bid.status || 'pending'),
|
|
117
|
+
(bid.message || '').slice(0, 30),
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
return [
|
|
121
|
+
agent,
|
|
122
|
+
(0, format_1.formatReward)(bid.amount || bid.bid_amount, b.reward_symbol),
|
|
123
|
+
(0, format_1.statusColor)(bid.status || 'pending'),
|
|
124
|
+
(bid.message || '').slice(0, 40),
|
|
125
|
+
];
|
|
126
|
+
});
|
|
127
|
+
console.log((0, format_1.makeTable)(headers, rows));
|
|
94
128
|
}
|
|
95
129
|
}
|
|
96
130
|
catch {
|
|
@@ -101,6 +135,61 @@ exports.bountyCommand
|
|
|
101
135
|
(0, format_1.error)(err.message);
|
|
102
136
|
}
|
|
103
137
|
});
|
|
138
|
+
exports.bountyCommand
|
|
139
|
+
.command('bids')
|
|
140
|
+
.argument('<bounty-id>', 'Bounty ID')
|
|
141
|
+
.description('List bids on a bounty with agent stats and value scores')
|
|
142
|
+
.action(async (bountyId) => {
|
|
143
|
+
try {
|
|
144
|
+
const client = (0, client_1.getClient)();
|
|
145
|
+
const [bountyData, bidData] = await Promise.all([
|
|
146
|
+
client.get(`/bounties/${bountyId}`),
|
|
147
|
+
client.get(`/bounties/${bountyId}/bids`),
|
|
148
|
+
]);
|
|
149
|
+
const b = bountyData.bounty;
|
|
150
|
+
const bids = bidData.bids || [];
|
|
151
|
+
if (bids.length === 0) {
|
|
152
|
+
console.log('No bids yet.');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const hasBidding = !!b.bidding_ends_at;
|
|
156
|
+
if (hasBidding) {
|
|
157
|
+
const biddingEnd = new Date(b.bidding_ends_at);
|
|
158
|
+
const isOpen = biddingEnd > new Date();
|
|
159
|
+
console.log(`${chalk_1.default.dim('Bidding deadline:')} ${b.bidding_ends_at} ${isOpen ? chalk_1.default.green('(open)') : chalk_1.default.dim('(closed)')}`);
|
|
160
|
+
console.log(`${chalk_1.default.dim('Reward (max budget):')} ${(0, format_1.formatReward)(b.reward_amount, b.reward_symbol)}\n`);
|
|
161
|
+
}
|
|
162
|
+
(0, format_1.heading)(`Bids (${bids.length})${hasBidding ? ' — Ranked by value score' : ''}`);
|
|
163
|
+
const headers = hasBidding
|
|
164
|
+
? ['#', 'Agent', 'Amount', 'Score', 'Reputation', 'Completed', 'Status', 'Message']
|
|
165
|
+
: ['Agent', 'Amount', 'Status', 'Message'];
|
|
166
|
+
const rows = bids.map((bid, i) => {
|
|
167
|
+
const agent = bid.agent_name || (0, format_1.shorten)(bid.agent_wallet);
|
|
168
|
+
if (hasBidding) {
|
|
169
|
+
return [
|
|
170
|
+
String(i + 1),
|
|
171
|
+
agent,
|
|
172
|
+
(0, format_1.formatReward)(bid.bid_amount || bid.amount, b.reward_symbol),
|
|
173
|
+
bid.value_score != null ? bid.value_score.toFixed(1) : '—',
|
|
174
|
+
bid.weighted_reputation != null ? `${bid.weighted_reputation.toFixed(1)}/5` : '—',
|
|
175
|
+
bid.completed_count != null ? String(bid.completed_count) : '—',
|
|
176
|
+
(0, format_1.statusColor)(bid.status || 'pending'),
|
|
177
|
+
(bid.message || '').slice(0, 35),
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
return [
|
|
181
|
+
agent,
|
|
182
|
+
(0, format_1.formatReward)(bid.bid_amount || bid.amount, b.reward_symbol),
|
|
183
|
+
(0, format_1.statusColor)(bid.status || 'pending'),
|
|
184
|
+
(bid.message || '').slice(0, 45),
|
|
185
|
+
];
|
|
186
|
+
});
|
|
187
|
+
console.log((0, format_1.makeTable)(headers, rows));
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
(0, format_1.error)(err.message);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
104
193
|
exports.bountyCommand
|
|
105
194
|
.command('progress')
|
|
106
195
|
.argument('<bounty-id>', 'Bounty ID')
|
|
@@ -180,6 +269,38 @@ exports.bountyCommand
|
|
|
180
269
|
(0, format_1.error)(err.message);
|
|
181
270
|
}
|
|
182
271
|
});
|
|
272
|
+
exports.bountyCommand
|
|
273
|
+
.command('estimate')
|
|
274
|
+
.description('Get an AI-powered USDC price estimate for a bounty description')
|
|
275
|
+
.requiredOption('--description <text>', 'Bounty description (min 50 chars)')
|
|
276
|
+
.option('--title <title>', 'Bounty title')
|
|
277
|
+
.option('--flow-type <type>', 'Flow type: hosted-app, code, or document')
|
|
278
|
+
.option('--framework <framework>', 'Framework (e.g. next, react, express)')
|
|
279
|
+
.action(async (opts) => {
|
|
280
|
+
try {
|
|
281
|
+
if (opts.description.length < 50) {
|
|
282
|
+
(0, format_1.error)('Description must be at least 50 characters');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
const client = (0, client_1.getClient)();
|
|
286
|
+
const body = { description: opts.description };
|
|
287
|
+
if (opts.title)
|
|
288
|
+
body.title = opts.title;
|
|
289
|
+
if (opts.flowType)
|
|
290
|
+
body.flowType = opts.flowType;
|
|
291
|
+
if (opts.framework)
|
|
292
|
+
body.framework = opts.framework;
|
|
293
|
+
const data = await client.post('/bounties/estimate', body);
|
|
294
|
+
(0, format_1.heading)('Bounty Price Estimate');
|
|
295
|
+
const dots = '●'.repeat(data.complexity) + '○'.repeat(5 - data.complexity);
|
|
296
|
+
console.log(` Range: ${chalk_1.default.green(`$${data.low}`)} – ${chalk_1.default.green(`$${data.high}`)} USDC`);
|
|
297
|
+
console.log(` Complexity: ${dots} (${data.complexity}/5)`);
|
|
298
|
+
console.log(` Reasoning: ${chalk_1.default.dim(data.reasoning)}`);
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
(0, format_1.error)(err.message);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
183
304
|
function progressBar(pct) {
|
|
184
305
|
const filled = Math.round(pct / 5);
|
|
185
306
|
const empty = 20 - filled;
|
|
@@ -1,2 +1,33 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { WsEvent } from '../utils/websocket';
|
|
3
|
+
export interface BountyRow {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: string;
|
|
7
|
+
assignee_wallet?: string;
|
|
8
|
+
percentage?: number;
|
|
9
|
+
last_heartbeat?: string;
|
|
10
|
+
reward_amount: string;
|
|
11
|
+
reward_symbol: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DashboardState {
|
|
14
|
+
workspace: {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
mode: string;
|
|
18
|
+
};
|
|
19
|
+
bounties: BountyRow[];
|
|
20
|
+
treasury: {
|
|
21
|
+
balance: string;
|
|
22
|
+
total_funded: string;
|
|
23
|
+
total_paid: string;
|
|
24
|
+
};
|
|
25
|
+
events: string[];
|
|
26
|
+
startTime: number;
|
|
27
|
+
}
|
|
2
28
|
export declare const dashboardCommand: Command;
|
|
29
|
+
export declare function updateBountyFromEvent(state: DashboardState, event: WsEvent): void;
|
|
30
|
+
export declare function pad(s: string, len: number, right?: boolean): string;
|
|
31
|
+
export declare function colorOverhead(status: string): number;
|
|
32
|
+
export declare function heartbeatColor(hb: string): string;
|
|
33
|
+
export declare function formatUptime(ms: number): string;
|
|
@@ -4,6 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.dashboardCommand = void 0;
|
|
7
|
+
exports.updateBountyFromEvent = updateBountyFromEvent;
|
|
8
|
+
exports.pad = pad;
|
|
9
|
+
exports.colorOverhead = colorOverhead;
|
|
10
|
+
exports.heartbeatColor = heartbeatColor;
|
|
11
|
+
exports.formatUptime = formatUptime;
|
|
7
12
|
const commander_1 = require("commander");
|
|
8
13
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
14
|
const client_1 = require("../utils/client");
|