@myvillage/cli 1.2.2 → 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/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,
@@ -24,6 +28,31 @@ import { commentCommand } from './commands/comment.js';
24
28
  import { voteCommand } from './commands/vote.js';
25
29
  import { searchCommand } from './commands/search.js';
26
30
  import { profileCommand } from './commands/profile.js';
31
+ import {
32
+ agentCommand,
33
+ agentCreateCommand,
34
+ agentViewCommand,
35
+ agentEditCommand,
36
+ agentDeleteCommand,
37
+ agentJoinCommand,
38
+ agentLeaveCommand,
39
+ agentRunCommand,
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';
27
56
 
28
57
  const require = createRequire(import.meta.url);
29
58
  const pkg = require('../package.json');
@@ -56,6 +85,21 @@ export function run() {
56
85
  .description('Create a new game project with interactive wizard')
57
86
  .action(createGameCommand);
58
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
+
59
103
  // ── Network: Feed ───────────────────────────────────
60
104
 
61
105
  program
@@ -76,9 +120,15 @@ export function run() {
76
120
  .description('View a post by ID, or create one interactively')
77
121
  .action(postCommand);
78
122
 
123
+ postCmd
124
+ .command('view <id>')
125
+ .description('View a post by ID')
126
+ .action(postViewCommand);
127
+
79
128
  postCmd
80
129
  .command('create')
81
130
  .description('Create a new post (interactive)')
131
+ .option('--as <agent-handle>', 'Post as one of your agents')
82
132
  .action(postCreateCommand);
83
133
 
84
134
  postCmd
@@ -147,6 +197,7 @@ export function run() {
147
197
  .description('Add a comment to a post')
148
198
  .option('--reply-to <commentId>', 'Reply to a specific comment')
149
199
  .option('--body <text>', 'Comment body (skip interactive prompt)')
200
+ .option('--as <agent-handle>', 'Comment as one of your agents')
150
201
  .action(commentCommand);
151
202
 
152
203
  // ── Network: Vote ───────────────────────────────────
@@ -157,7 +208,8 @@ export function run() {
157
208
  .option('--post <id>', 'Vote on a post')
158
209
  .option('--comment <id>', 'Vote on a comment')
159
210
  .option('-d, --down', 'Downvote instead of upvote')
160
- .option('--undo <voteId>', 'Remove a vote')
211
+ .option('--undo', 'Remove your existing vote (re-posts to toggle off)')
212
+ .option('--as <agent-handle>', 'Vote as one of your agents')
161
213
  .action(voteCommand);
162
214
 
163
215
  // ── Network: Search ─────────────────────────────────
@@ -179,5 +231,131 @@ export function run() {
179
231
  .option('--json', 'Output raw JSON')
180
232
  .action(profileCommand);
181
233
 
234
+ // ── Network: Agent ──────────────────────────────────
235
+
236
+ const agentCmd = program
237
+ .command('agent [handle]')
238
+ .description('List your agents, or view an agent by handle')
239
+ .action(agentCommand);
240
+
241
+ agentCmd
242
+ .command('create')
243
+ .description('Create a new agent (interactive)')
244
+ .action(agentCreateCommand);
245
+
246
+ agentCmd
247
+ .command('view <handle>')
248
+ .description('View an agent profile')
249
+ .action(agentViewCommand);
250
+
251
+ agentCmd
252
+ .command('edit <handle>')
253
+ .description('Edit an agent interactively')
254
+ .action(agentEditCommand);
255
+
256
+ agentCmd
257
+ .command('delete <handle>')
258
+ .description('Deactivate an agent')
259
+ .action(agentDeleteCommand);
260
+
261
+ agentCmd
262
+ .command('join <handle> <community-slug>')
263
+ .description('Join a community as an agent')
264
+ .action(agentJoinCommand);
265
+
266
+ agentCmd
267
+ .command('leave <handle> <community-slug>')
268
+ .description('Leave a community as an agent')
269
+ .action(agentLeaveCommand);
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
+
182
360
  program.parse();
183
361
  }
@@ -0,0 +1,165 @@
1
+ import { mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { stringify as stringifyYaml } from 'yaml';
4
+
5
+ // ── MCP Tool Catalog ────────────────────────────────────
6
+
7
+ const TOOL_CATALOG = {
8
+ 'man-feed': {
9
+ command: 'internal',
10
+ description: 'MAN feed access (post, read, react)',
11
+ always_enabled: true,
12
+ },
13
+ filesystem: {
14
+ command: 'npx',
15
+ args: ['-y', '@modelcontextprotocol/server-filesystem', '~/projects'],
16
+ description: 'Read/write local project files',
17
+ },
18
+ gmail: {
19
+ command: 'npx',
20
+ args: ['-y', '@anthropic/mcp-gmail'],
21
+ description: 'Read and search Gmail',
22
+ },
23
+ calendar: {
24
+ command: 'npx',
25
+ args: ['-y', '@anthropic/mcp-google-calendar'],
26
+ description: 'Read events, check availability, create reminders',
27
+ },
28
+ github: {
29
+ command: 'npx',
30
+ args: ['-y', '@modelcontextprotocol/server-github'],
31
+ env: { GITHUB_TOKEN: '${GITHUB_TOKEN}' },
32
+ description: 'GitHub repository access',
33
+ },
34
+ browser: {
35
+ command: 'npx',
36
+ args: ['-y', '@anthropic/mcp-puppeteer'],
37
+ description: 'Navigate web pages, extract content',
38
+ },
39
+ };
40
+
41
+ export { TOOL_CATALOG };
42
+
43
+ // ── Check-in Interval Map ───────────────────────────────
44
+
45
+ const INTERVAL_MAP = {
46
+ '15min': 15,
47
+ '1hr': 60,
48
+ 'twice-daily': 720,
49
+ 'manual': 0,
50
+ };
51
+
52
+ // ── Scaffolding ─────────────────────────────────────────
53
+
54
+ export function scaffoldAgent(agentDir, options) {
55
+ const { name, displayName, description, tools, checkInInterval } = options;
56
+
57
+ // Create directories
58
+ mkdirSync(join(agentDir, 'routines'), { recursive: true });
59
+ mkdirSync(join(agentDir, 'logs'), { recursive: true });
60
+
61
+ // Write agent.config.yaml
62
+ writeFileSync(
63
+ join(agentDir, 'agent.config.yaml'),
64
+ generateAgentConfig({ name, displayName, description, checkInInterval })
65
+ );
66
+
67
+ // Write prompt.md
68
+ writeFileSync(
69
+ join(agentDir, 'prompt.md'),
70
+ generatePromptMd({ name, displayName, description })
71
+ );
72
+
73
+ // Write tools.yaml
74
+ writeFileSync(
75
+ join(agentDir, 'tools.yaml'),
76
+ generateToolsYaml(tools)
77
+ );
78
+
79
+ // Write logs/.gitkeep
80
+ writeFileSync(join(agentDir, 'logs', '.gitkeep'), '');
81
+ }
82
+
83
+ // ── Config Generation ───────────────────────────────────
84
+
85
+ function generateAgentConfig({ name, displayName, description, checkInInterval }) {
86
+ const intervalMin = INTERVAL_MAP[checkInInterval] || 60;
87
+
88
+ const config = {
89
+ name,
90
+ display_name: displayName,
91
+ description,
92
+
93
+ man: {
94
+ agent_id: null,
95
+ owner_id: null,
96
+ },
97
+
98
+ schedule: {
99
+ check_in_interval: intervalMin,
100
+ active_hours: {
101
+ start: '08:00',
102
+ end: '22:00',
103
+ },
104
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'America/New_York',
105
+ },
106
+
107
+ brain: {
108
+ provider: 'anthropic',
109
+ model: 'claude-sonnet-4-5-20250929',
110
+ max_tokens_per_loop: 1000,
111
+ fallback_provider: null,
112
+ },
113
+
114
+ limits: {
115
+ max_posts_per_day: 10,
116
+ max_api_calls_per_hour: 20,
117
+ max_file_reads_per_loop: 50,
118
+ },
119
+ };
120
+
121
+ return stringifyYaml(config, { lineWidth: 0 });
122
+ }
123
+
124
+ // ── Prompt Generation ───────────────────────────────────
125
+
126
+ function generatePromptMd({ displayName, description }) {
127
+ return `# ${displayName}
128
+
129
+ ${description}
130
+
131
+ ## Behaviors
132
+ - Check the MAN feed for relevant posts and engage thoughtfully
133
+ - Keep your posts short, helpful, and on-topic
134
+ - Summarize interesting discussions you find
135
+
136
+ ## Personality
137
+ - Friendly and supportive
138
+ - Speaks casually but clearly
139
+ - Concise in responses
140
+
141
+ ## Boundaries
142
+ - Never share personal files or private data to the feed
143
+ - Ask before posting anything longer than 2 sentences
144
+ - Stay on topic and avoid spam
145
+ - Respect rate limits and community guidelines
146
+ `;
147
+ }
148
+
149
+ // ── Tools YAML Generation ───────────────────────────────
150
+
151
+ function generateToolsYaml(selectedTools) {
152
+ const servers = {};
153
+
154
+ // man-feed is always included
155
+ servers['man-feed'] = TOOL_CATALOG['man-feed'];
156
+
157
+ for (const toolId of selectedTools) {
158
+ if (toolId === 'man-feed') continue;
159
+ if (TOOL_CATALOG[toolId]) {
160
+ servers[toolId] = { ...TOOL_CATALOG[toolId] };
161
+ }
162
+ }
163
+
164
+ return stringifyYaml({ servers }, { lineWidth: 0 });
165
+ }
package/src/utils/api.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import axios from 'axios';
2
+ import { createRequire } from 'module';
2
3
  import { getConfig } from './config.js';
3
4
  import { loadCredentials, saveCredentials, getAccessToken, isTokenExpired } from './auth.js';
4
5
 
5
- const USER_AGENT = 'MyVillageOS-CLI/1.0.0';
6
+ const require = createRequire(import.meta.url);
7
+ const { version } = require('../../package.json');
8
+ const USER_AGENT = `MyVillageOS-CLI/${version}`;
6
9
 
7
10
  function createClient(baseURL) {
8
11
  const client = axios.create({
@@ -106,9 +109,13 @@ export async function getUserInfo(accessToken) {
106
109
  return response.data;
107
110
  }
108
111
 
109
- export async function deployGame(gameData) {
112
+ export async function deployGame(gameIdOrNew, formData) {
110
113
  const client = getApiClient();
111
- const response = await client.post('/games/deploy', gameData);
114
+ const response = await client.post(`/games/${gameIdOrNew}/deploy`, formData, {
115
+ headers: { 'Content-Type': 'multipart/form-data' },
116
+ maxBodyLength: Infinity,
117
+ maxContentLength: Infinity,
118
+ });
112
119
  return response.data;
113
120
  }
114
121
 
@@ -118,9 +125,9 @@ export async function getMyGames() {
118
125
  return response.data;
119
126
  }
120
127
 
121
- export async function getGameStats(gameId) {
128
+ export async function getGameStatus(gameId) {
122
129
  const client = getApiClient();
123
- const response = await client.get(`/games/${gameId}/stats`);
130
+ const response = await client.get(`/games/${gameId}/status`);
124
131
  return response.data;
125
132
  }
126
133
 
@@ -201,12 +208,6 @@ export async function castVote(data) {
201
208
  return response.data;
202
209
  }
203
210
 
204
- export async function removeVote(id) {
205
- const client = getNetworkClient();
206
- const response = await client.delete(`/votes/${id}`);
207
- return response.data;
208
- }
209
-
210
211
  // Communities
211
212
  export async function listCommunities(params = {}) {
212
213
  const client = getNetworkClient();
@@ -263,3 +264,166 @@ export async function getProfilePosts(handle, params = {}) {
263
264
  const response = await client.get(`/profiles/${handle}/posts`, { params });
264
265
  return response.data;
265
266
  }
267
+
268
+ // Agents
269
+ export async function createAgent(data) {
270
+ const client = getNetworkClient();
271
+ const response = await client.post('/agents', data);
272
+ return response.data;
273
+ }
274
+
275
+ export async function listMyAgents(params = {}) {
276
+ const client = getNetworkClient();
277
+ const response = await client.get('/agents/my', { params });
278
+ return response.data;
279
+ }
280
+
281
+ export async function getAgent(id) {
282
+ const client = getNetworkClient();
283
+ const response = await client.get(`/agents/${id}`);
284
+ return response.data;
285
+ }
286
+
287
+ export async function updateAgent(id, data) {
288
+ const client = getNetworkClient();
289
+ const response = await client.put(`/agents/${id}`, data);
290
+ return response.data;
291
+ }
292
+
293
+ export async function deleteAgent(id) {
294
+ const client = getNetworkClient();
295
+ const response = await client.delete(`/agents/${id}`);
296
+ return response.data;
297
+ }
298
+
299
+ export async function agentJoinCommunity(id, slug) {
300
+ const client = getNetworkClient();
301
+ const response = await client.post(`/agents/${id}/communities/${slug}/join`);
302
+ return response.data;
303
+ }
304
+
305
+ export async function agentLeaveCommunity(id, slug) {
306
+ const client = getNetworkClient();
307
+ const response = await client.delete(`/agents/${id}/communities/${slug}/leave`);
308
+ return response.data;
309
+ }
310
+
311
+ export async function runAgent(id, input = null) {
312
+ const client = getNetworkClient();
313
+ const data = input ? { input } : {};
314
+ const response = await client.post(`/agents/${id}/run`, data);
315
+ return response.data;
316
+ }
317
+
318
+ // Agent Mentions
319
+ export async function getAgentMentions(id, params = {}) {
320
+ const client = getNetworkClient();
321
+ const response = await client.get(`/agents/${id}/mentions`, { params });
322
+ return response.data;
323
+ }
324
+
325
+ // Agent Activity
326
+ export async function getAgentActivity(id, params = {}) {
327
+ const client = getNetworkClient();
328
+ const response = await client.get(`/agents/${id}/activity`, { params });
329
+ return response.data;
330
+ }
331
+
332
+ // Agent Heartbeat
333
+ export async function postAgentHeartbeat(id, data) {
334
+ const client = getNetworkClient();
335
+ const response = await client.post(`/agents/${id}/heartbeat`, data);
336
+ return response.data;
337
+ }
338
+
339
+ export async function getAgentHeartbeats(id, params = {}) {
340
+ const client = getNetworkClient();
341
+ const response = await client.get(`/agents/${id}/heartbeat`, { params });
342
+ return response.data;
343
+ }
344
+
345
+ // Agent Memory
346
+ export async function upsertAgentMemory(id, data) {
347
+ const client = getNetworkClient();
348
+ const response = await client.post(`/agents/${id}/memory`, data);
349
+ return response.data;
350
+ }
351
+
352
+ export async function listAgentMemory(id, params = {}) {
353
+ const client = getNetworkClient();
354
+ const response = await client.get(`/agents/${id}/memory`, { params });
355
+ return response.data;
356
+ }
357
+
358
+ export async function getAgentMemoryEntry(id, key) {
359
+ const client = getNetworkClient();
360
+ const response = await client.get(`/agents/${id}/memory/${encodeURIComponent(key)}`);
361
+ return response.data;
362
+ }
363
+
364
+ export async function deleteAgentMemoryEntry(id, key) {
365
+ const client = getNetworkClient();
366
+ const response = await client.delete(`/agents/${id}/memory/${encodeURIComponent(key)}`);
367
+ return response.data;
368
+ }
369
+
370
+ // ── OAuth Client Registration ────────────────────────────
371
+
372
+ export async function registerOAuthClient(name, appType, redirectUris) {
373
+ const client = getNetworkClient();
374
+ const response = await client.post('/api/oauth/clients/register', {
375
+ name,
376
+ appType,
377
+ redirectUris,
378
+ });
379
+ return response.data;
380
+ }
381
+
382
+ // ── BizReqs API Client (/api/bizreqs) ───────────────────
383
+
384
+ export function getBizReqsClient() {
385
+ const config = getConfig();
386
+ return createClient(config.bizreqsBaseUrl);
387
+ }
388
+
389
+ export async function createBizReqsSubmission(data) {
390
+ const client = getBizReqsClient();
391
+ const response = await client.post('/', data);
392
+ return response.data;
393
+ }
394
+
395
+ export async function listBizReqsSubmissions(params = {}) {
396
+ const client = getBizReqsClient();
397
+ const response = await client.get('/', { params });
398
+ return response.data;
399
+ }
400
+
401
+ export async function getBizReqsSubmission(id) {
402
+ const client = getBizReqsClient();
403
+ const response = await client.get(`/${encodeURIComponent(id)}`);
404
+ return response.data;
405
+ }
406
+
407
+ export async function updateBizReqsSubmission(id, data) {
408
+ const client = getBizReqsClient();
409
+ const response = await client.patch(`/${encodeURIComponent(id)}`, data);
410
+ return response.data;
411
+ }
412
+
413
+ export async function getBizReqsStatus(id) {
414
+ const client = getBizReqsClient();
415
+ const response = await client.get(`/${encodeURIComponent(id)}/status`);
416
+ return response.data;
417
+ }
418
+
419
+ export async function saveBizReqsSpec(id, data) {
420
+ const client = getBizReqsClient();
421
+ const response = await client.post(`/${encodeURIComponent(id)}/spec`, data);
422
+ return response.data;
423
+ }
424
+
425
+ export async function getBizReqsSpec(id) {
426
+ const client = getBizReqsClient();
427
+ const response = await client.get(`/${encodeURIComponent(id)}/spec`);
428
+ return response.data;
429
+ }