@myvillage/cli 1.3.0 → 1.5.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 +14 -199
- package/package.json +6 -2
- package/src/agent-runtime/context.js +99 -0
- package/src/agent-runtime/daemon-entry.js +66 -0
- package/src/agent-runtime/daemon.js +65 -0
- package/src/agent-runtime/loop.js +281 -0
- package/src/agent-runtime/mcp-client.js +400 -0
- package/src/agent-runtime/scheduler.js +53 -0
- package/src/commands/agent-local.js +607 -0
- package/src/commands/agent.js +274 -42
- package/src/commands/bizreqs.js +965 -0
- package/src/commands/comment.js +5 -4
- package/src/commands/community.js +13 -12
- package/src/commands/create-app.js +253 -0
- package/src/commands/create-game.js +9 -8
- package/src/commands/deploy.js +101 -23
- package/src/commands/feed.js +4 -3
- package/src/commands/login.js +7 -6
- package/src/commands/logout.js +3 -2
- package/src/commands/post.js +14 -13
- package/src/commands/profile.js +4 -3
- package/src/commands/search.js +3 -2
- package/src/commands/status.js +64 -28
- package/src/commands/vote.js +46 -18
- package/src/index.js +131 -1
- package/src/utils/agent-scaffolder.js +165 -0
- package/src/utils/api.js +134 -13
- package/src/utils/app-templates.js +2983 -0
- package/src/utils/brand.js +107 -0
- package/src/utils/config.js +16 -1
- package/src/utils/formatters.js +351 -18
- package/src/utils/local-agent.js +168 -0
package/src/commands/login.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createServer } from 'http';
|
|
|
2
2
|
import { randomBytes, createHash } from 'crypto';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
5
6
|
import open from 'open';
|
|
6
7
|
import axios from 'axios';
|
|
7
8
|
import { getConfig } from '../utils/config.js';
|
|
@@ -27,11 +28,11 @@ export async function loginCommand() {
|
|
|
27
28
|
const existing = loadCredentials();
|
|
28
29
|
if (existing?.access_token) {
|
|
29
30
|
console.log(chalk.yellow('You are already logged in.'));
|
|
30
|
-
console.log(
|
|
31
|
+
console.log(brand.teal('Run "myvillage logout" first to log in with a different account.'));
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const spinner =
|
|
35
|
+
const spinner = villageSpinner('Preparing authentication...').start();
|
|
35
36
|
|
|
36
37
|
// Generate PKCE values and state token
|
|
37
38
|
const state = randomBytes(16).toString('hex');
|
|
@@ -117,8 +118,8 @@ export async function loginCommand() {
|
|
|
117
118
|
open(authUrl).catch(() => {
|
|
118
119
|
spinner.stop();
|
|
119
120
|
console.log(chalk.yellow('\nCould not open browser automatically.'));
|
|
120
|
-
console.log(
|
|
121
|
-
console.log(
|
|
121
|
+
console.log(brand.teal('Please open this URL in your browser:'));
|
|
122
|
+
console.log(brand.gold(authUrl));
|
|
122
123
|
});
|
|
123
124
|
|
|
124
125
|
spinner.text = 'Waiting for authentication in browser...';
|
|
@@ -184,12 +185,12 @@ export async function loginCommand() {
|
|
|
184
185
|
|
|
185
186
|
spinner.succeed('Authentication complete!');
|
|
186
187
|
console.log();
|
|
187
|
-
console.log(
|
|
188
|
+
console.log(brand.green(` \u2713 Successfully logged in as ${userInfo.email}`));
|
|
188
189
|
|
|
189
190
|
if (userInfo.villager) {
|
|
190
191
|
const v = userInfo.villager;
|
|
191
192
|
if (v.mvtBalance !== undefined) {
|
|
192
|
-
console.log(
|
|
193
|
+
console.log(brand.teal(` MVT Balance: ${v.mvtBalance} tokens`));
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
|
package/src/commands/logout.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { brand } from '../utils/brand.js';
|
|
2
3
|
import { clearCredentials } from '../utils/auth.js';
|
|
3
4
|
|
|
4
5
|
export async function logoutCommand() {
|
|
5
6
|
const removed = clearCredentials();
|
|
6
7
|
|
|
7
8
|
if (removed) {
|
|
8
|
-
console.log(
|
|
9
|
+
console.log(brand.green(' \u2713 Successfully logged out.'));
|
|
9
10
|
} else {
|
|
10
|
-
console.log(
|
|
11
|
+
console.log(brand.teal(' No stored credentials found. You are not logged in.'));
|
|
11
12
|
}
|
|
12
13
|
}
|
package/src/commands/post.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
3
4
|
import inquirer from 'inquirer';
|
|
4
5
|
import { isAuthenticated } from '../utils/auth.js';
|
|
5
6
|
import {
|
|
@@ -38,7 +39,7 @@ export async function postViewCommand(id) {
|
|
|
38
39
|
return;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const spinner =
|
|
42
|
+
const spinner = villageSpinner('Loading post...').start();
|
|
42
43
|
|
|
43
44
|
try {
|
|
44
45
|
const result = await getPost(id);
|
|
@@ -64,7 +65,7 @@ export async function postCreateCommand(options = {}) {
|
|
|
64
65
|
|
|
65
66
|
try {
|
|
66
67
|
// Fetch communities for selection
|
|
67
|
-
const commSpinner =
|
|
68
|
+
const commSpinner = villageSpinner('Loading your communities...').start();
|
|
68
69
|
let communities = [];
|
|
69
70
|
try {
|
|
70
71
|
const result = await listCommunities({ pageSize: 50 });
|
|
@@ -79,7 +80,7 @@ export async function postCreateCommand(options = {}) {
|
|
|
79
80
|
|
|
80
81
|
if (options.as) {
|
|
81
82
|
// --as flag provided: resolve handle to agent ID
|
|
82
|
-
const agentsSpinner =
|
|
83
|
+
const agentsSpinner = villageSpinner('Resolving agent...').start();
|
|
83
84
|
try {
|
|
84
85
|
const agentsResult = await listMyAgents();
|
|
85
86
|
const agents = agentsResult.data || agentsResult;
|
|
@@ -91,7 +92,7 @@ export async function postCreateCommand(options = {}) {
|
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
93
94
|
agentProfileId = agent.id;
|
|
94
|
-
console.log(
|
|
95
|
+
console.log(brand.teal(` Posting as agent @${agent.handle}\n`));
|
|
95
96
|
} catch {
|
|
96
97
|
agentsSpinner.stop();
|
|
97
98
|
}
|
|
@@ -171,7 +172,7 @@ export async function postCreateCommand(options = {}) {
|
|
|
171
172
|
},
|
|
172
173
|
]);
|
|
173
174
|
|
|
174
|
-
const spinner =
|
|
175
|
+
const spinner = villageSpinner('Creating post...').start();
|
|
175
176
|
|
|
176
177
|
const data = {
|
|
177
178
|
communitySlug: answers.communitySlug.trim(),
|
|
@@ -191,11 +192,11 @@ export async function postCreateCommand(options = {}) {
|
|
|
191
192
|
|
|
192
193
|
const post = result.data || result;
|
|
193
194
|
if (agentProfileId) {
|
|
194
|
-
console.log(
|
|
195
|
+
console.log(brand.green(` ✓ Post published in r/${answers.communitySlug} as agent`));
|
|
195
196
|
} else {
|
|
196
|
-
console.log(
|
|
197
|
+
console.log(brand.green(` ✓ Post published in r/${answers.communitySlug}`));
|
|
197
198
|
}
|
|
198
|
-
console.log(
|
|
199
|
+
console.log(brand.teal(` ID: ${post.id}\n`));
|
|
199
200
|
} catch (err) {
|
|
200
201
|
if (err.isTtyError) {
|
|
201
202
|
console.log(chalk.red(' ✗ Prompts cannot be rendered in this environment.\n'));
|
|
@@ -212,7 +213,7 @@ export async function postListCommand(options) {
|
|
|
212
213
|
return;
|
|
213
214
|
}
|
|
214
215
|
|
|
215
|
-
const spinner =
|
|
216
|
+
const spinner = villageSpinner('Loading posts...').start();
|
|
216
217
|
|
|
217
218
|
try {
|
|
218
219
|
const params = {
|
|
@@ -248,7 +249,7 @@ export async function postEditCommand(id) {
|
|
|
248
249
|
return;
|
|
249
250
|
}
|
|
250
251
|
|
|
251
|
-
const loadSpinner =
|
|
252
|
+
const loadSpinner = villageSpinner('Loading post...').start();
|
|
252
253
|
|
|
253
254
|
try {
|
|
254
255
|
const result = await getPost(id);
|
|
@@ -266,7 +267,7 @@ export async function postEditCommand(id) {
|
|
|
266
267
|
},
|
|
267
268
|
]);
|
|
268
269
|
|
|
269
|
-
const spinner =
|
|
270
|
+
const spinner = villageSpinner('Saving changes...').start();
|
|
270
271
|
await apiEditPost(id, { body: answers.body.trim() });
|
|
271
272
|
spinner.succeed('Post updated!');
|
|
272
273
|
} catch (err) {
|
|
@@ -293,11 +294,11 @@ export async function postDeleteCommand(id) {
|
|
|
293
294
|
]);
|
|
294
295
|
|
|
295
296
|
if (!confirm) {
|
|
296
|
-
console.log(
|
|
297
|
+
console.log(brand.teal(' Cancelled.\n'));
|
|
297
298
|
return;
|
|
298
299
|
}
|
|
299
300
|
|
|
300
|
-
const spinner =
|
|
301
|
+
const spinner = villageSpinner('Deleting post...').start();
|
|
301
302
|
await apiDeletePost(id);
|
|
302
303
|
spinner.succeed('Post deleted.');
|
|
303
304
|
} catch (err) {
|
package/src/commands/profile.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
3
4
|
import { isAuthenticated, loadCredentials } from '../utils/auth.js';
|
|
4
5
|
import { getProfile, getProfilePosts } from '../utils/api.js';
|
|
5
6
|
import { formatProfile, formatPostList, formatPagination } from '../utils/formatters.js';
|
|
@@ -20,7 +21,7 @@ export async function profileCommand(handle, options) {
|
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
const spinner =
|
|
24
|
+
const spinner = villageSpinner('Loading profile...').start();
|
|
24
25
|
|
|
25
26
|
try {
|
|
26
27
|
const result = await getProfile(target);
|
|
@@ -37,7 +38,7 @@ export async function profileCommand(handle, options) {
|
|
|
37
38
|
|
|
38
39
|
// If --posts flag, also fetch posts
|
|
39
40
|
if (options.posts) {
|
|
40
|
-
const postsSpinner =
|
|
41
|
+
const postsSpinner = villageSpinner('Loading posts...').start();
|
|
41
42
|
const postsResult = await getProfilePosts(target, { pageSize: 10 });
|
|
42
43
|
postsSpinner.stop();
|
|
43
44
|
|
|
@@ -47,7 +48,7 @@ export async function profileCommand(handle, options) {
|
|
|
47
48
|
formatPostList(posts);
|
|
48
49
|
formatPagination(postsResult.meta);
|
|
49
50
|
} else {
|
|
50
|
-
console.log(
|
|
51
|
+
console.log(brand.teal(' No posts yet.\n'));
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
} catch (err) {
|
package/src/commands/search.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
3
4
|
import { isAuthenticated } from '../utils/auth.js';
|
|
4
5
|
import { searchNetwork } from '../utils/api.js';
|
|
5
6
|
import { formatSearchResults, formatPagination } from '../utils/formatters.js';
|
|
@@ -10,7 +11,7 @@ export async function searchCommand(query, options) {
|
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const spinner =
|
|
14
|
+
const spinner = villageSpinner(`Searching "${query}"...`).start();
|
|
14
15
|
|
|
15
16
|
try {
|
|
16
17
|
const params = {
|
|
@@ -30,7 +31,7 @@ export async function searchCommand(query, options) {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const total = result.meta?.total ?? '';
|
|
33
|
-
console.log(`\n ${chalk.bold(`Search results for "${query}"`)}${total ?
|
|
34
|
+
console.log(`\n ${chalk.bold(`Search results for "${query}"`)}${total ? brand.teal(` (${total} results)`) : ''}\n`);
|
|
34
35
|
|
|
35
36
|
formatSearchResults(data);
|
|
36
37
|
formatPagination(result.meta);
|
package/src/commands/status.js
CHANGED
|
@@ -2,8 +2,9 @@ import { existsSync, readFileSync } from 'fs';
|
|
|
2
2
|
import { join, resolve } from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
5
6
|
import { isAuthenticated } from '../utils/auth.js';
|
|
6
|
-
import { getMyGames,
|
|
7
|
+
import { getMyGames, getGameStatus } from '../utils/api.js';
|
|
7
8
|
|
|
8
9
|
function readPackageJson(dir) {
|
|
9
10
|
const pkgPath = join(dir, 'package.json');
|
|
@@ -48,33 +49,49 @@ export async function statusCommand() {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
async function showGameStatus(gameId) {
|
|
51
|
-
const spinner =
|
|
52
|
+
const spinner = villageSpinner('Fetching game status...').start();
|
|
52
53
|
|
|
53
54
|
try {
|
|
54
|
-
const
|
|
55
|
+
const data = await getGameStatus(gameId);
|
|
56
|
+
const game = data.game || data;
|
|
55
57
|
|
|
56
58
|
spinner.stop();
|
|
57
59
|
|
|
58
60
|
console.log();
|
|
59
|
-
console.log(chalk.bold(` ${
|
|
61
|
+
console.log(chalk.bold(` ${game.title || game.name || gameId}`));
|
|
60
62
|
console.log();
|
|
61
|
-
console.log(` Status: ${formatStatus(
|
|
62
|
-
console.log(` Play Count: ${
|
|
63
|
-
console.log(` MVT Earned: ${chalk.yellow(
|
|
64
|
-
console.log(` Last Updated: ${
|
|
63
|
+
console.log(` Status: ${formatStatus(game.status)}`);
|
|
64
|
+
console.log(` Play Count: ${brand.gold(game.playCount ?? 0)}`);
|
|
65
|
+
console.log(` MVT Earned: ${chalk.yellow(game.mvtAwarded ?? 0)} tokens`);
|
|
66
|
+
console.log(` Last Updated: ${brand.teal(formatDate(game.updatedAt || game.lastUpdated))}`);
|
|
65
67
|
|
|
66
|
-
if (
|
|
67
|
-
console.log(`
|
|
68
|
+
if (game.slug) {
|
|
69
|
+
console.log(` Slug: ${brand.teal(game.slug)}`);
|
|
68
70
|
}
|
|
71
|
+
|
|
72
|
+
// Show review history if available
|
|
73
|
+
if (game.reviews?.length > 0) {
|
|
74
|
+
console.log();
|
|
75
|
+
console.log(chalk.bold(' Review History:'));
|
|
76
|
+
for (const review of game.reviews) {
|
|
77
|
+
const action = formatReviewAction(review.action);
|
|
78
|
+
const date = formatDate(review.createdAt);
|
|
79
|
+
console.log(` ${action} - ${brand.teal(date)}`);
|
|
80
|
+
if (review.notes) {
|
|
81
|
+
console.log(` ${brand.teal(review.notes)}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
console.log();
|
|
70
87
|
} catch (err) {
|
|
71
|
-
const message = err.response?.data?.message || err.message;
|
|
88
|
+
const message = err.response?.data?.error || err.response?.data?.message || err.message;
|
|
72
89
|
spinner.fail(`Failed to fetch game status: ${message}`);
|
|
73
90
|
}
|
|
74
91
|
}
|
|
75
92
|
|
|
76
93
|
async function showAllGames() {
|
|
77
|
-
const spinner =
|
|
94
|
+
const spinner = villageSpinner('Fetching your games...').start();
|
|
78
95
|
|
|
79
96
|
try {
|
|
80
97
|
const data = await getMyGames();
|
|
@@ -84,8 +101,8 @@ async function showAllGames() {
|
|
|
84
101
|
|
|
85
102
|
if (!games.length) {
|
|
86
103
|
console.log();
|
|
87
|
-
console.log(
|
|
88
|
-
console.log(
|
|
104
|
+
console.log(brand.teal(' No deployed games found.'));
|
|
105
|
+
console.log(brand.teal(' Create a game with "myvillage create-game" and deploy it!'));
|
|
89
106
|
console.log();
|
|
90
107
|
return;
|
|
91
108
|
}
|
|
@@ -95,32 +112,51 @@ async function showAllGames() {
|
|
|
95
112
|
console.log();
|
|
96
113
|
|
|
97
114
|
for (const game of games) {
|
|
98
|
-
console.log(` ${chalk.yellow(game.name || game.
|
|
99
|
-
console.log(` Status: ${formatStatus(game.status)} | Plays: ${
|
|
115
|
+
console.log(` ${chalk.yellow(game.title || game.name || game.id)}`);
|
|
116
|
+
console.log(` Status: ${formatStatus(game.status)} | Plays: ${brand.gold(game.playCount ?? 0)} | MVT: ${chalk.yellow(game.mvtAwarded ?? 0)}`);
|
|
100
117
|
|
|
101
|
-
if (game.
|
|
102
|
-
console.log(` ${
|
|
118
|
+
if (game.slug) {
|
|
119
|
+
console.log(` ${brand.teal(game.slug)}`);
|
|
103
120
|
}
|
|
104
121
|
|
|
105
122
|
console.log();
|
|
106
123
|
}
|
|
107
124
|
} catch (err) {
|
|
108
|
-
const message = err.response?.data?.message || err.message;
|
|
125
|
+
const message = err.response?.data?.error || err.response?.data?.message || err.message;
|
|
109
126
|
spinner.fail(`Failed to fetch games: ${message}`);
|
|
110
127
|
}
|
|
111
128
|
}
|
|
112
129
|
|
|
113
130
|
function formatStatus(status) {
|
|
114
131
|
switch (status) {
|
|
115
|
-
case '
|
|
116
|
-
return
|
|
117
|
-
case '
|
|
118
|
-
return chalk.yellow('
|
|
119
|
-
case '
|
|
120
|
-
return chalk.
|
|
121
|
-
case '
|
|
122
|
-
return chalk.
|
|
132
|
+
case 'DRAFT':
|
|
133
|
+
return brand.teal('Draft');
|
|
134
|
+
case 'SUBMITTED':
|
|
135
|
+
return chalk.yellow('Submitted');
|
|
136
|
+
case 'UNDER_REVIEW':
|
|
137
|
+
return chalk.yellow('Under Review');
|
|
138
|
+
case 'APPROVED':
|
|
139
|
+
return chalk.green('Approved');
|
|
140
|
+
case 'REJECTED':
|
|
141
|
+
return chalk.red('Rejected');
|
|
142
|
+
case 'PUBLISHED':
|
|
143
|
+
return chalk.green('Published');
|
|
144
|
+
case 'ARCHIVED':
|
|
145
|
+
return brand.teal('Archived');
|
|
146
|
+
default:
|
|
147
|
+
return brand.teal(status || 'Unknown');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function formatReviewAction(action) {
|
|
152
|
+
switch (action) {
|
|
153
|
+
case 'APPROVE':
|
|
154
|
+
return chalk.green('Approved');
|
|
155
|
+
case 'REJECT':
|
|
156
|
+
return chalk.red('Rejected');
|
|
157
|
+
case 'REQUEST_CHANGES':
|
|
158
|
+
return chalk.yellow('Changes Requested');
|
|
123
159
|
default:
|
|
124
|
-
return
|
|
160
|
+
return brand.teal(action || 'Unknown');
|
|
125
161
|
}
|
|
126
162
|
}
|
package/src/commands/vote.js
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
+
import { villageSpinner, brand } from '../utils/brand.js';
|
|
3
4
|
import { isAuthenticated } from '../utils/auth.js';
|
|
4
|
-
import { castVote,
|
|
5
|
+
import { castVote, listMyAgents } from '../utils/api.js';
|
|
5
6
|
|
|
6
7
|
export async function voteCommand(options) {
|
|
7
8
|
if (!isAuthenticated()) {
|
|
8
|
-
console.log(chalk.red('
|
|
9
|
+
console.log(chalk.red(' \u2717 Authentication required. Run \'myvillage login\' first.'));
|
|
9
10
|
return;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// Resolve agent identity if --as flag provided
|
|
14
|
+
let agentProfileId = null;
|
|
15
|
+
|
|
16
|
+
if (options.as) {
|
|
15
17
|
try {
|
|
16
|
-
await
|
|
17
|
-
|
|
18
|
+
const agentsResult = await listMyAgents();
|
|
19
|
+
const agents = agentsResult.data || agentsResult;
|
|
20
|
+
const agent = Array.isArray(agents) ? agents.find(a => a.handle === options.as) : null;
|
|
21
|
+
|
|
22
|
+
if (!agent) {
|
|
23
|
+
console.log(chalk.red(` \u2717 Agent @${options.as} not found. Run 'myvillage agent' to see your agents.\n`));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
agentProfileId = agent.id;
|
|
27
|
+
console.log(brand.teal(` Voting as agent @${agent.handle}\n`));
|
|
18
28
|
} catch (err) {
|
|
19
29
|
const message = err.response?.data?.error || err.response?.data?.message || err.message;
|
|
20
|
-
|
|
30
|
+
console.log(chalk.red(` \u2717 Failed to resolve agent: ${message}\n`));
|
|
31
|
+
return;
|
|
21
32
|
}
|
|
22
|
-
return;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
35
|
// Determine target
|
|
@@ -27,21 +37,39 @@ export async function voteCommand(options) {
|
|
|
27
37
|
const targetId = options.post || options.comment;
|
|
28
38
|
|
|
29
39
|
if (!targetType || !targetId) {
|
|
30
|
-
console.log(chalk.red('
|
|
31
|
-
console.log(
|
|
32
|
-
console.log(
|
|
40
|
+
console.log(chalk.red(' \u2717 Specify a target: --post <id> or --comment <id>'));
|
|
41
|
+
console.log(brand.teal(' Example: myvillage vote --post abc123'));
|
|
42
|
+
console.log(brand.teal(' Example: myvillage vote --comment xyz789 --down\n'));
|
|
33
43
|
return;
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
const value = options.down ? -1 : 1;
|
|
37
|
-
const action = value === 1 ? 'Upvoting' : 'Downvoting';
|
|
38
|
-
const spinner =
|
|
47
|
+
const action = options.undo ? 'Removing vote from' : (value === 1 ? 'Upvoting' : 'Downvoting');
|
|
48
|
+
const spinner = villageSpinner(`${action} ${targetType.toLowerCase()}...`).start();
|
|
39
49
|
|
|
40
50
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
const data = { targetType, targetId, value };
|
|
52
|
+
if (agentProfileId) {
|
|
53
|
+
data.agentProfileId = agentProfileId;
|
|
54
|
+
}
|
|
55
|
+
const result = await castVote(data);
|
|
56
|
+
const resultAction = result?.data?.action;
|
|
57
|
+
|
|
58
|
+
if (options.undo) {
|
|
59
|
+
if (resultAction === 'removed') {
|
|
60
|
+
spinner.succeed(`Vote removed from ${targetType.toLowerCase()} ${targetId}`);
|
|
61
|
+
} else {
|
|
62
|
+
spinner.warn(`No existing vote to remove (${resultAction || 'created'}). A new vote was cast instead.`);
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
const emoji = value === 1 ? chalk.green('\u25b2') : chalk.red('\u25bc');
|
|
66
|
+
if (resultAction === 'removed') {
|
|
67
|
+
spinner.succeed(`Vote toggled off for ${targetType.toLowerCase()} ${targetId}`);
|
|
68
|
+
} else {
|
|
69
|
+
const word = value === 1 ? 'Upvoted' : 'Downvoted';
|
|
70
|
+
spinner.succeed(`${word} ${targetType.toLowerCase()} ${targetId} ${emoji}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
45
73
|
} catch (err) {
|
|
46
74
|
const message = err.response?.data?.error || err.response?.data?.message || err.message;
|
|
47
75
|
spinner.fail(`Failed to vote: ${message}`);
|
package/src/index.js
CHANGED
|
@@ -4,6 +4,9 @@ import updateNotifier from 'update-notifier';
|
|
|
4
4
|
import { loginCommand } from './commands/login.js';
|
|
5
5
|
import { logoutCommand } from './commands/logout.js';
|
|
6
6
|
import { createGameCommand } from './commands/create-game.js';
|
|
7
|
+
import { createCommand } from './commands/create-app.js';
|
|
8
|
+
import { deployCommand } from './commands/deploy.js';
|
|
9
|
+
import { statusCommand } from './commands/status.js';
|
|
7
10
|
import { feedCommand } from './commands/feed.js';
|
|
8
11
|
import {
|
|
9
12
|
communityCommand,
|
|
@@ -15,6 +18,7 @@ import {
|
|
|
15
18
|
} from './commands/community.js';
|
|
16
19
|
import {
|
|
17
20
|
postCommand,
|
|
21
|
+
postViewCommand,
|
|
18
22
|
postCreateCommand,
|
|
19
23
|
postListCommand,
|
|
20
24
|
postEditCommand,
|
|
@@ -32,7 +36,23 @@ import {
|
|
|
32
36
|
agentDeleteCommand,
|
|
33
37
|
agentJoinCommand,
|
|
34
38
|
agentLeaveCommand,
|
|
39
|
+
agentRunCommand,
|
|
35
40
|
} from './commands/agent.js';
|
|
41
|
+
import {
|
|
42
|
+
agentStartCommand,
|
|
43
|
+
agentStopCommand,
|
|
44
|
+
agentStatusCommand,
|
|
45
|
+
agentLogsCommand,
|
|
46
|
+
agentAddToolCommand,
|
|
47
|
+
agentRemoveToolCommand,
|
|
48
|
+
} from './commands/agent-local.js';
|
|
49
|
+
import {
|
|
50
|
+
bizreqsNewCommand,
|
|
51
|
+
bizreqsSpecCommand,
|
|
52
|
+
bizreqsListCommand,
|
|
53
|
+
bizreqsStatusCommand,
|
|
54
|
+
bizreqsImportCommand,
|
|
55
|
+
} from './commands/bizreqs.js';
|
|
36
56
|
|
|
37
57
|
const require = createRequire(import.meta.url);
|
|
38
58
|
const pkg = require('../package.json');
|
|
@@ -65,6 +85,21 @@ export function run() {
|
|
|
65
85
|
.description('Create a new game project with interactive wizard')
|
|
66
86
|
.action(createGameCommand);
|
|
67
87
|
|
|
88
|
+
program
|
|
89
|
+
.command('create')
|
|
90
|
+
.description('Create a new project (portal, data labeling app, or game)')
|
|
91
|
+
.action(createCommand);
|
|
92
|
+
|
|
93
|
+
program
|
|
94
|
+
.command('deploy')
|
|
95
|
+
.description('Build and deploy your game to MyVillageOS')
|
|
96
|
+
.action(deployCommand);
|
|
97
|
+
|
|
98
|
+
program
|
|
99
|
+
.command('status')
|
|
100
|
+
.description('Check deployment status of your games')
|
|
101
|
+
.action(statusCommand);
|
|
102
|
+
|
|
68
103
|
// ── Network: Feed ───────────────────────────────────
|
|
69
104
|
|
|
70
105
|
program
|
|
@@ -85,6 +120,11 @@ export function run() {
|
|
|
85
120
|
.description('View a post by ID, or create one interactively')
|
|
86
121
|
.action(postCommand);
|
|
87
122
|
|
|
123
|
+
postCmd
|
|
124
|
+
.command('view <id>')
|
|
125
|
+
.description('View a post by ID')
|
|
126
|
+
.action(postViewCommand);
|
|
127
|
+
|
|
88
128
|
postCmd
|
|
89
129
|
.command('create')
|
|
90
130
|
.description('Create a new post (interactive)')
|
|
@@ -168,7 +208,8 @@ export function run() {
|
|
|
168
208
|
.option('--post <id>', 'Vote on a post')
|
|
169
209
|
.option('--comment <id>', 'Vote on a comment')
|
|
170
210
|
.option('-d, --down', 'Downvote instead of upvote')
|
|
171
|
-
.option('--undo
|
|
211
|
+
.option('--undo', 'Remove your existing vote (re-posts to toggle off)')
|
|
212
|
+
.option('--as <agent-handle>', 'Vote as one of your agents')
|
|
172
213
|
.action(voteCommand);
|
|
173
214
|
|
|
174
215
|
// ── Network: Search ─────────────────────────────────
|
|
@@ -227,5 +268,94 @@ export function run() {
|
|
|
227
268
|
.description('Leave a community as an agent')
|
|
228
269
|
.action(agentLeaveCommand);
|
|
229
270
|
|
|
271
|
+
agentCmd
|
|
272
|
+
.command('run <handle>')
|
|
273
|
+
.description('Run a workflow agent (WORKFLOW or HYBRID only)')
|
|
274
|
+
.option('--input <text>', 'Input data for the agent')
|
|
275
|
+
.action(agentRunCommand);
|
|
276
|
+
|
|
277
|
+
// Local agent lifecycle commands
|
|
278
|
+
agentCmd
|
|
279
|
+
.command('start <name>')
|
|
280
|
+
.description('Start a local agent daemon')
|
|
281
|
+
.action(agentStartCommand);
|
|
282
|
+
|
|
283
|
+
agentCmd
|
|
284
|
+
.command('stop <name>')
|
|
285
|
+
.description('Stop a local agent daemon')
|
|
286
|
+
.action(agentStopCommand);
|
|
287
|
+
|
|
288
|
+
agentCmd
|
|
289
|
+
.command('status [name]')
|
|
290
|
+
.description('Show local agent status')
|
|
291
|
+
.option('--remote', 'Include server-side activity from MAN')
|
|
292
|
+
.action(agentStatusCommand);
|
|
293
|
+
|
|
294
|
+
agentCmd
|
|
295
|
+
.command('logs <name>')
|
|
296
|
+
.description('View agent activity logs')
|
|
297
|
+
.option('--follow', 'Follow log output in real-time')
|
|
298
|
+
.option('--since <time>', 'Show logs since timestamp')
|
|
299
|
+
.action(agentLogsCommand);
|
|
300
|
+
|
|
301
|
+
agentCmd
|
|
302
|
+
.command('add-tool <name> <tool>')
|
|
303
|
+
.description('Add an MCP server tool to a local agent')
|
|
304
|
+
.action(agentAddToolCommand);
|
|
305
|
+
|
|
306
|
+
agentCmd
|
|
307
|
+
.command('remove-tool <name> <tool>')
|
|
308
|
+
.description('Remove an MCP server tool from a local agent')
|
|
309
|
+
.action(agentRemoveToolCommand);
|
|
310
|
+
|
|
311
|
+
// ── BizReqs: Business Requirements Pipeline ───────────
|
|
312
|
+
|
|
313
|
+
const bizreqsCmd = program
|
|
314
|
+
.command('bizreqs')
|
|
315
|
+
.description('Business requirements intake and project pipeline');
|
|
316
|
+
|
|
317
|
+
bizreqsCmd
|
|
318
|
+
.command('new')
|
|
319
|
+
.description('Start a new AI-guided business intake session')
|
|
320
|
+
.option('--org <name>', 'Organization name')
|
|
321
|
+
.option('--contact <name>', 'Contact name')
|
|
322
|
+
.option('--from-file <path>', 'Path to a text file with initial context')
|
|
323
|
+
.option('--from-url <url>', 'URL to the organization\'s website')
|
|
324
|
+
.option('--quick', 'Shortened flow (skip dream state, fewer exchanges)')
|
|
325
|
+
.action(bizreqsNewCommand);
|
|
326
|
+
|
|
327
|
+
bizreqsCmd
|
|
328
|
+
.command('spec <id>')
|
|
329
|
+
.description('Generate full project specification from an intake')
|
|
330
|
+
.option('--detail <level>', 'Detail level: brief, standard, comprehensive', 'standard')
|
|
331
|
+
.option('--output <dir>', 'Output directory for spec file', './specs')
|
|
332
|
+
.action(bizreqsSpecCommand);
|
|
333
|
+
|
|
334
|
+
bizreqsCmd
|
|
335
|
+
.command('list')
|
|
336
|
+
.description('List pipeline submissions')
|
|
337
|
+
.option('--status <status>', 'Filter: new, in-review, spec-ready, assigned, in-progress, delivered')
|
|
338
|
+
.option('--city <city>', 'Filter by city')
|
|
339
|
+
.option('--search <query>', 'Search by org name, solution, or ID')
|
|
340
|
+
.option('--sort <sort>', 'Sort: newest, oldest, priority', 'newest')
|
|
341
|
+
.option('-n, --limit <number>', 'Number of results', '50')
|
|
342
|
+
.option('--offset <number>', 'Pagination offset', '0')
|
|
343
|
+
.option('--json', 'Output raw JSON')
|
|
344
|
+
.action(bizreqsListCommand);
|
|
345
|
+
|
|
346
|
+
bizreqsCmd
|
|
347
|
+
.command('status <id>')
|
|
348
|
+
.description('Check project status')
|
|
349
|
+
.action(bizreqsStatusCommand);
|
|
350
|
+
|
|
351
|
+
bizreqsCmd
|
|
352
|
+
.command('import')
|
|
353
|
+
.description('Import requirements from a file or URL')
|
|
354
|
+
.option('--file <path>', 'Path to .txt or .md file')
|
|
355
|
+
.option('--url <url>', 'URL to fetch content from')
|
|
356
|
+
.option('--org <name>', 'Organization name')
|
|
357
|
+
.option('--contact <name>', 'Contact name')
|
|
358
|
+
.action(bizreqsImportCommand);
|
|
359
|
+
|
|
230
360
|
program.parse();
|
|
231
361
|
}
|