@myvillage/cli 1.3.0 → 1.5.1
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 +11 -6
- 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 +93 -0
- package/src/agent-runtime/scheduler.js +53 -0
- package/src/commands/agent-local.js +624 -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 +164 -76
- package/src/commands/logout.js +45 -7
- package/src/commands/post.js +14 -13
- package/src/commands/profile.js +4 -3
- package/src/commands/search.js +3 -2
- package/src/commands/soulprint.js +1379 -0
- package/src/commands/status.js +64 -28
- package/src/commands/vote.js +46 -18
- package/src/index.js +244 -1
- package/src/utils/agent-scaffolder.js +165 -0
- package/src/utils/api.js +135 -14
- package/src/utils/app-templates.js +2983 -0
- package/src/utils/brand.js +107 -0
- package/src/utils/config.js +17 -1
- package/src/utils/formatters.js +351 -18
- package/src/utils/local-agent.js +168 -0
- package/src/utils/soulprint-api.js +136 -0
- package/src/utils/soulprint-workspace.js +158 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
|
|
4
|
+
// ── MyVillage Brand Colors ──────────────────────────────
|
|
5
|
+
|
|
6
|
+
export const brand = {
|
|
7
|
+
gold: (s) => chalk.hex('#FFD700')(s),
|
|
8
|
+
darkGold: (s) => chalk.hex('#B07C00')(s),
|
|
9
|
+
green: (s) => chalk.hex('#228B22')(s),
|
|
10
|
+
deepGreen: (s) => chalk.hex('#043922')(s),
|
|
11
|
+
teal: (s) => chalk.hex('#799C9F')(s),
|
|
12
|
+
cream: (s) => chalk.hex('#E4DCCB')(s),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// ── Branded Spinner ─────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
const VILLAGE_SPINNER = {
|
|
18
|
+
interval: 100,
|
|
19
|
+
frames: ['\u2743', '\u273A', '\u274B', '\u2742', '\u274A', '\u2749', '\u2748', '\u2747'],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function villageSpinner(text) {
|
|
23
|
+
return ora({ text: chalk.yellow(text), spinner: VILLAGE_SPINNER, color: 'yellow' });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ── Strip ANSI for length calculation ───────────────────
|
|
27
|
+
|
|
28
|
+
export function stripAnsi(str) {
|
|
29
|
+
return str.replace(/\x1B\[[0-9;]*m/g, '');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ── Formatted AI Response Box ───────────────────────────
|
|
33
|
+
|
|
34
|
+
export function formatAIResponse(text) {
|
|
35
|
+
const termWidth = process.stdout.columns || 80;
|
|
36
|
+
const boxWidth = Math.min(termWidth - 4, 76);
|
|
37
|
+
const innerWidth = boxWidth - 4;
|
|
38
|
+
|
|
39
|
+
const border = brand.darkGold;
|
|
40
|
+
const boldText = (s) => chalk.bold(brand.gold(s));
|
|
41
|
+
|
|
42
|
+
const processLine = (line) => {
|
|
43
|
+
return line.replace(/\*\*(.+?)\*\*/g, (_, content) => boldText(content));
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const wrapLine = (line) => {
|
|
47
|
+
if (line.length <= innerWidth) return [line];
|
|
48
|
+
const wrapped = [];
|
|
49
|
+
let current = '';
|
|
50
|
+
for (const word of line.split(' ')) {
|
|
51
|
+
if (current && (current.length + 1 + word.length) > innerWidth) {
|
|
52
|
+
wrapped.push(current);
|
|
53
|
+
current = word;
|
|
54
|
+
} else {
|
|
55
|
+
current = current ? current + ' ' + word : word;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (current) wrapped.push(current);
|
|
59
|
+
return wrapped;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const contentLines = [];
|
|
63
|
+
for (const rawLine of text.split('\n')) {
|
|
64
|
+
const processed = processLine(rawLine);
|
|
65
|
+
if (processed.trim() === '') {
|
|
66
|
+
contentLines.push('');
|
|
67
|
+
} else {
|
|
68
|
+
for (const wrapped of wrapLine(processed)) {
|
|
69
|
+
contentLines.push(wrapped);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const pad = (s, len) => s + ' '.repeat(Math.max(0, len - stripAnsi(s).length));
|
|
75
|
+
const topBorder = border('\u250C' + '\u2500'.repeat(boxWidth - 2) + '\u2510');
|
|
76
|
+
const bottomBorder = border('\u2514' + '\u2500'.repeat(boxWidth - 2) + '\u2518');
|
|
77
|
+
|
|
78
|
+
const output = ['', ' ' + topBorder];
|
|
79
|
+
for (const line of contentLines) {
|
|
80
|
+
if (line === '') {
|
|
81
|
+
output.push(' ' + border('\u2502') + ' '.repeat(boxWidth - 2) + border('\u2502'));
|
|
82
|
+
} else {
|
|
83
|
+
output.push(' ' + border('\u2502') + ' ' + pad(brand.cream(line), innerWidth) + ' ' + border('\u2502'));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
output.push(' ' + bottomBorder, '');
|
|
87
|
+
|
|
88
|
+
return output.join('\n');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Common styled messages ──────────────────────────────
|
|
92
|
+
|
|
93
|
+
export function success(msg) {
|
|
94
|
+
console.log(brand.green(` \u2713 ${msg}`));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function error(msg) {
|
|
98
|
+
console.log(chalk.red(` \u2717 ${msg}`));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function info(msg) {
|
|
102
|
+
console.log(brand.teal(` ${msg}`));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function header(msg) {
|
|
106
|
+
console.log(`\n ${brand.gold(chalk.bold(msg))}\n`);
|
|
107
|
+
}
|
package/src/utils/config.js
CHANGED
|
@@ -8,9 +8,12 @@ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
|
8
8
|
const DEFAULT_CONFIG = {
|
|
9
9
|
apiBaseUrl: 'https://portal.myvillageproject.ai/api/v1',
|
|
10
10
|
networkBaseUrl: 'https://portal.myvillageproject.ai/api/network',
|
|
11
|
+
bizreqsBaseUrl: 'https://portal.myvillageproject.ai/api/bizreqs',
|
|
11
12
|
oauthBaseUrl: 'https://portal.myvillageproject.ai/api/oauth',
|
|
13
|
+
soulprintBaseUrl: 'https://soulprint-studio.myvillageproject.ai/api',
|
|
12
14
|
clientId: 'mvos_aG_c729fuQxvvqYHOnkgTQ',
|
|
13
15
|
callbackPort: 3737,
|
|
16
|
+
anthropicApiKey: null,
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
function ensureConfigDir() {
|
|
@@ -35,7 +38,12 @@ export function getConfig() {
|
|
|
35
38
|
// Remove stale clientId/oauthBaseUrl from file config — code defaults always win
|
|
36
39
|
delete fileConfig.clientId;
|
|
37
40
|
delete fileConfig.oauthBaseUrl;
|
|
38
|
-
|
|
41
|
+
const config = { ...DEFAULT_CONFIG, ...fileConfig };
|
|
42
|
+
// Environment variable override for Anthropic API key
|
|
43
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
44
|
+
config.anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
45
|
+
}
|
|
46
|
+
return config;
|
|
39
47
|
} catch {
|
|
40
48
|
return { ...DEFAULT_CONFIG };
|
|
41
49
|
}
|
|
@@ -53,3 +61,11 @@ export function getConfigDir() {
|
|
|
53
61
|
ensureConfigDir();
|
|
54
62
|
return CONFIG_DIR;
|
|
55
63
|
}
|
|
64
|
+
|
|
65
|
+
export function getAgentsBaseDir() {
|
|
66
|
+
const dir = join(CONFIG_DIR, 'agents');
|
|
67
|
+
if (!existsSync(dir)) {
|
|
68
|
+
mkdirSync(dir, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
return dir;
|
|
71
|
+
}
|
package/src/utils/formatters.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { brand } from './brand.js';
|
|
2
3
|
|
|
3
4
|
// ── Time Formatting ─────────────────────────────────────
|
|
4
5
|
|
|
@@ -88,24 +89,28 @@ export function formatPostCard(post) {
|
|
|
88
89
|
const badge = postTypeBadge(post.postType);
|
|
89
90
|
const title = post.title || truncate(post.body, 60);
|
|
90
91
|
|
|
91
|
-
lines.push(` ${
|
|
92
|
+
lines.push(` ${brand.darkGold('\u250C')} ${badge} ${chalk.bold(title)}`);
|
|
92
93
|
|
|
93
94
|
const community = post.community
|
|
94
|
-
?
|
|
95
|
+
? brand.teal(`r/${post.community.slug}`)
|
|
95
96
|
: '';
|
|
96
97
|
const author = formatAuthor(post);
|
|
97
|
-
const time =
|
|
98
|
-
lines.push(` ${
|
|
98
|
+
const time = brand.teal(relativeTime(post.createdAt));
|
|
99
|
+
lines.push(` ${brand.darkGold('\u2502')} ${community} ${brand.darkGold('\u00b7')} ${author} ${brand.darkGold('\u00b7')} ${time}`);
|
|
99
100
|
|
|
100
101
|
if (post.body) {
|
|
101
102
|
const preview = truncate(post.body, 140);
|
|
102
|
-
lines.push(` ${
|
|
103
|
+
lines.push(` ${brand.darkGold('\u2502')} ${brand.cream(preview)}`);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
const votes = formatVotes(post.upvoteCount, post.downvoteCount);
|
|
106
|
-
const comments =
|
|
107
|
-
lines.push(` ${
|
|
108
|
-
|
|
107
|
+
const comments = brand.teal(`${post.commentCount ?? post._count?.comments ?? 0} comments`);
|
|
108
|
+
lines.push(` ${brand.darkGold('\u2502')} ${votes} ${brand.darkGold('\u00b7')} ${comments}`);
|
|
109
|
+
if (post.id) {
|
|
110
|
+
lines.push(` ${brand.darkGold('\u2514')} ${brand.teal('id: ' + post.id)}`);
|
|
111
|
+
} else {
|
|
112
|
+
lines.push(` ${brand.darkGold('\u2514')}`);
|
|
113
|
+
}
|
|
109
114
|
|
|
110
115
|
return lines.join('\n');
|
|
111
116
|
}
|
|
@@ -199,7 +204,7 @@ export function formatCommentThread(comments) {
|
|
|
199
204
|
return;
|
|
200
205
|
}
|
|
201
206
|
|
|
202
|
-
console.log(`\n ${
|
|
207
|
+
console.log(`\n ${brand.darkGold('\u2500\u2500 Comments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500')}\n`);
|
|
203
208
|
for (const comment of comments) {
|
|
204
209
|
formatComment(comment, 0);
|
|
205
210
|
console.log('');
|
|
@@ -240,7 +245,7 @@ export function formatCommunityDetail(community) {
|
|
|
240
245
|
if (community.description) {
|
|
241
246
|
lines.push(` ${community.description}`);
|
|
242
247
|
}
|
|
243
|
-
lines.push(` ${
|
|
248
|
+
lines.push(` ${brand.darkGold('\u2500'.repeat(50))}`);
|
|
244
249
|
lines.push('');
|
|
245
250
|
lines.push(` ${chalk.dim('Slug:')} ${chalk.cyan(community.slug)}`);
|
|
246
251
|
lines.push(` ${chalk.dim('Members:')} ${community.memberCount ?? 0}`);
|
|
@@ -275,7 +280,7 @@ export function formatProfile(profile) {
|
|
|
275
280
|
if (profile.bio) {
|
|
276
281
|
lines.push(` ${profile.bio}`);
|
|
277
282
|
}
|
|
278
|
-
lines.push(` ${
|
|
283
|
+
lines.push(` ${brand.darkGold('\u2500'.repeat(50))}`);
|
|
279
284
|
lines.push('');
|
|
280
285
|
|
|
281
286
|
if (profile.totalPosts !== undefined) {
|
|
@@ -301,17 +306,30 @@ export function formatProfile(profile) {
|
|
|
301
306
|
|
|
302
307
|
// ── Agent Formatting ───────────────────────────────
|
|
303
308
|
|
|
309
|
+
function categoryBadge(category) {
|
|
310
|
+
if (category === 'WORKFLOW') return chalk.yellow('[WORKFLOW]');
|
|
311
|
+
if (category === 'HYBRID') return chalk.magenta('[HYBRID]');
|
|
312
|
+
return chalk.cyan('[NETWORK]');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function categoryBadgeShort(category) {
|
|
316
|
+
if (category === 'WORKFLOW') return chalk.yellow('[W]');
|
|
317
|
+
if (category === 'HYBRID') return chalk.magenta('[H]');
|
|
318
|
+
return chalk.cyan('[N]');
|
|
319
|
+
}
|
|
320
|
+
|
|
304
321
|
export function formatAgentCard(agent) {
|
|
305
322
|
const lines = [];
|
|
306
323
|
|
|
307
324
|
lines.push('');
|
|
308
325
|
const status = agent.isActive !== false ? chalk.green('active') : chalk.red('inactive');
|
|
309
|
-
|
|
326
|
+
const badge = categoryBadge(agent.agentCategory);
|
|
327
|
+
lines.push(` ${chalk.bold(`@${agent.handle}`)} ${chalk.dim('·')} ${agent.displayName} ${chalk.dim('·')} ${badge} ${chalk.dim('·')} ${status}`);
|
|
310
328
|
|
|
311
329
|
if (agent.bio) {
|
|
312
330
|
lines.push(` ${agent.bio}`);
|
|
313
331
|
}
|
|
314
|
-
lines.push(` ${
|
|
332
|
+
lines.push(` ${brand.darkGold('\u2500'.repeat(50))}`);
|
|
315
333
|
lines.push('');
|
|
316
334
|
|
|
317
335
|
if (agent.personality) {
|
|
@@ -320,6 +338,24 @@ export function formatAgentCard(agent) {
|
|
|
320
338
|
if (agent.interests?.length) {
|
|
321
339
|
lines.push(` ${chalk.dim('Interests:')} ${agent.interests.map(t => chalk.cyan(t)).join(', ')}`);
|
|
322
340
|
}
|
|
341
|
+
|
|
342
|
+
// Workflow fields (WORKFLOW and HYBRID)
|
|
343
|
+
if (agent.agentCategory && agent.agentCategory !== 'NETWORK') {
|
|
344
|
+
if (agent.endpointUrl) {
|
|
345
|
+
lines.push(` ${chalk.dim('Endpoint:')} ${truncate(agent.endpointUrl, 80)}`);
|
|
346
|
+
}
|
|
347
|
+
if (agent.workflowType) {
|
|
348
|
+
lines.push(` ${chalk.dim('Type:')} ${agent.workflowType}`);
|
|
349
|
+
}
|
|
350
|
+
if (agent.schedule) {
|
|
351
|
+
lines.push(` ${chalk.dim('Schedule:')} ${agent.schedule}`);
|
|
352
|
+
}
|
|
353
|
+
if (agent.lastRunAt) {
|
|
354
|
+
lines.push(` ${chalk.dim('Last Run:')} ${formatDate(agent.lastRunAt)}`);
|
|
355
|
+
}
|
|
356
|
+
lines.push(` ${chalk.dim('Input Req:')} ${agent.inputRequired ? chalk.green('Yes') : chalk.dim('No')}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
323
359
|
if (agent.totalPosts !== undefined) {
|
|
324
360
|
lines.push(` ${chalk.dim('Posts:')} ${agent.totalPosts}`);
|
|
325
361
|
}
|
|
@@ -329,9 +365,6 @@ export function formatAgentCard(agent) {
|
|
|
329
365
|
if (agent.karmaScore !== undefined) {
|
|
330
366
|
lines.push(` ${chalk.dim('Karma:')} ${agent.karmaScore}`);
|
|
331
367
|
}
|
|
332
|
-
if (agent.mvtBalance !== undefined) {
|
|
333
|
-
lines.push(` ${chalk.dim('MVT Balance:')} ${agent.mvtBalance} tokens`);
|
|
334
|
-
}
|
|
335
368
|
lines.push(` ${chalk.dim('ID:')} ${chalk.dim(agent.id)}`);
|
|
336
369
|
|
|
337
370
|
lines.push('');
|
|
@@ -347,18 +380,138 @@ export function formatAgentList(agents) {
|
|
|
347
380
|
console.log('');
|
|
348
381
|
for (const agent of agents) {
|
|
349
382
|
const handle = chalk.blue(padRight(`@${agent.handle}`, 24));
|
|
350
|
-
const name = padRight(agent.displayName || '',
|
|
383
|
+
const name = padRight(agent.displayName || '', 20);
|
|
384
|
+
const catBadge = categoryBadgeShort(agent.agentCategory);
|
|
351
385
|
const status = agent.isActive !== false ? chalk.green('active') : chalk.red('inactive');
|
|
352
386
|
const stats = chalk.dim(`${agent.totalPosts ?? 0} posts · ${agent.totalComments ?? 0} comments`);
|
|
353
387
|
|
|
354
|
-
console.log(` ${handle} ${name} ${status} ${stats}`);
|
|
388
|
+
console.log(` ${handle} ${name} ${catBadge} ${status} ${stats}`);
|
|
355
389
|
if (agent.bio) {
|
|
356
390
|
console.log(` ${chalk.dim(' ')}${chalk.dim(truncate(agent.bio, 60))}`);
|
|
357
391
|
}
|
|
392
|
+
if (agent.agentCategory && agent.agentCategory !== 'NETWORK' && agent.schedule) {
|
|
393
|
+
console.log(` ${chalk.dim(' ')}${chalk.dim(`Schedule: ${agent.schedule}`)}`);
|
|
394
|
+
}
|
|
358
395
|
console.log('');
|
|
359
396
|
}
|
|
360
397
|
}
|
|
361
398
|
|
|
399
|
+
// ── Local Agent Formatting ──────────────────────────────
|
|
400
|
+
|
|
401
|
+
export function formatLocalAgentList(agents) {
|
|
402
|
+
if (!agents || agents.length === 0) {
|
|
403
|
+
console.log(chalk.dim('\n No local agents found.\n'));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log(`\n ${brand.gold(chalk.bold('Local Agents'))}\n`);
|
|
408
|
+
for (const agent of agents) {
|
|
409
|
+
const handle = chalk.blue(padRight(`@${agent.name}`, 24));
|
|
410
|
+
const name = padRight(agent.config?.display_name || '', 20);
|
|
411
|
+
const badge = chalk.magenta('[LOCAL]');
|
|
412
|
+
const status = agent.isRunning ? chalk.green('running') : chalk.red('stopped');
|
|
413
|
+
const lastActivity = agent.lastHeartbeat
|
|
414
|
+
? chalk.dim(`Last check-in: ${relativeTime(agent.lastHeartbeat)}`)
|
|
415
|
+
: agent.isRunning
|
|
416
|
+
? chalk.dim('Starting...')
|
|
417
|
+
: chalk.dim('Never started');
|
|
418
|
+
|
|
419
|
+
console.log(` ${handle} ${name} ${badge} ${status} ${lastActivity}`);
|
|
420
|
+
if (agent.config?.description) {
|
|
421
|
+
console.log(` ${chalk.dim(' ')}${chalk.dim(truncate(agent.config.description, 60))}`);
|
|
422
|
+
}
|
|
423
|
+
const interval = agent.config?.schedule?.check_in_interval;
|
|
424
|
+
if (interval && interval > 0) {
|
|
425
|
+
const label = interval < 60 ? `${interval}m` : interval < 1440 ? `${interval / 60}h` : `${interval / 1440}d`;
|
|
426
|
+
console.log(` ${chalk.dim(' ')}${chalk.dim(`Check-in: every ${label}`)}`);
|
|
427
|
+
} else if (interval === 0) {
|
|
428
|
+
console.log(` ${chalk.dim(' ')}${chalk.dim('Check-in: manual only')}`);
|
|
429
|
+
}
|
|
430
|
+
console.log('');
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function formatLocalAgentStatus(agent) {
|
|
435
|
+
const lines = [];
|
|
436
|
+
|
|
437
|
+
lines.push('');
|
|
438
|
+
const status = agent.isRunning ? chalk.green('running') : chalk.red('stopped');
|
|
439
|
+
const badge = chalk.magenta('[LOCAL]');
|
|
440
|
+
lines.push(` ${chalk.bold(`@${agent.name}`)} ${chalk.dim('\u00b7')} ${agent.config?.display_name || ''} ${chalk.dim('\u00b7')} ${badge} ${chalk.dim('\u00b7')} ${status}`);
|
|
441
|
+
|
|
442
|
+
if (agent.config?.description) {
|
|
443
|
+
lines.push(` ${agent.config.description}`);
|
|
444
|
+
}
|
|
445
|
+
lines.push(` ${chalk.dim('\u2500'.repeat(50))}`);
|
|
446
|
+
lines.push('');
|
|
447
|
+
|
|
448
|
+
if (agent.config?.man?.agent_id) {
|
|
449
|
+
lines.push(` ${chalk.dim('MAN ID:')} ${chalk.dim(agent.config.man.agent_id)}`);
|
|
450
|
+
} else {
|
|
451
|
+
lines.push(` ${chalk.dim('MAN ID:')} ${chalk.dim('(not registered yet — will register on first start)')}`);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const interval = agent.config?.schedule?.check_in_interval;
|
|
455
|
+
if (interval && interval > 0) {
|
|
456
|
+
lines.push(` ${chalk.dim('Check-in:')} Every ${interval} minutes`);
|
|
457
|
+
} else {
|
|
458
|
+
lines.push(` ${chalk.dim('Check-in:')} Manual only`);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const hours = agent.config?.schedule?.active_hours;
|
|
462
|
+
if (hours?.start && hours?.end) {
|
|
463
|
+
const tz = agent.config?.schedule?.timezone || '';
|
|
464
|
+
lines.push(` ${chalk.dim('Active hours:')} ${hours.start} - ${hours.end}${tz ? ` (${tz})` : ''}`);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (agent.lastHeartbeat) {
|
|
468
|
+
lines.push(` ${chalk.dim('Last check-in:')} ${relativeTime(agent.lastHeartbeat)}`);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
if (agent.startedAt && agent.isRunning) {
|
|
472
|
+
const uptimeMs = Date.now() - new Date(agent.startedAt).getTime();
|
|
473
|
+
const hours = Math.floor(uptimeMs / 3600000);
|
|
474
|
+
const mins = Math.floor((uptimeMs % 3600000) / 60000);
|
|
475
|
+
lines.push(` ${chalk.dim('Uptime:')} ${hours}h ${mins}m`);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Activity from logs
|
|
479
|
+
if (agent.logs?.length > 0) {
|
|
480
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
481
|
+
const todayLogs = agent.logs.filter(l => l.ts?.startsWith(today));
|
|
482
|
+
const posts = todayLogs.filter(l => l.type === 'tool_call' && l.tool === 'man_create_post').length;
|
|
483
|
+
const comments = todayLogs.filter(l => l.type === 'tool_call' && l.tool === 'man_create_comment').length;
|
|
484
|
+
const votes = todayLogs.filter(l => l.type === 'tool_call' && l.tool === 'man_vote').length;
|
|
485
|
+
lines.push('');
|
|
486
|
+
lines.push(` ${chalk.dim('Today:')} Posts: ${posts} ${chalk.dim('\u00b7')} Comments: ${comments} ${chalk.dim('\u00b7')} Votes: ${votes}`);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Server-side activity (when --remote is used)
|
|
490
|
+
if (agent.serverActivity && Array.isArray(agent.serverActivity) && agent.serverActivity.length > 0) {
|
|
491
|
+
lines.push('');
|
|
492
|
+
lines.push(` ${chalk.dim('Recent MAN Activity:')}`);
|
|
493
|
+
for (const item of agent.serverActivity.slice(0, 10)) {
|
|
494
|
+
const time = chalk.dim(relativeTime(item.createdAt));
|
|
495
|
+
const type = item.postType ? 'post' : item.postId ? 'comment' : 'vote';
|
|
496
|
+
const preview = truncate(item.body || item.title || '', 50);
|
|
497
|
+
lines.push(` ${chalk.dim(type.padEnd(8))} ${preview} ${time}`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Tools
|
|
502
|
+
const toolsStr = Object.keys(agent.config?.tools || {}).join(', ') || 'none';
|
|
503
|
+
lines.push(` ${chalk.dim('Tools:')} ${toolsStr}`);
|
|
504
|
+
|
|
505
|
+
// Model
|
|
506
|
+
const model = agent.config?.brain?.model;
|
|
507
|
+
if (model) {
|
|
508
|
+
lines.push(` ${chalk.dim('Model:')} ${model}`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
lines.push('');
|
|
512
|
+
console.log(lines.join('\n'));
|
|
513
|
+
}
|
|
514
|
+
|
|
362
515
|
// ── Search Results ──────────────────────────────────────
|
|
363
516
|
|
|
364
517
|
export function formatSearchResults(results) {
|
|
@@ -403,6 +556,186 @@ export function formatSearchResults(results) {
|
|
|
403
556
|
}
|
|
404
557
|
}
|
|
405
558
|
|
|
559
|
+
// ── BizReqs Formatting ─────────────────────────────────
|
|
560
|
+
|
|
561
|
+
const BIZREQS_STATUS_COLORS = {
|
|
562
|
+
NEW: chalk.cyan,
|
|
563
|
+
IN_REVIEW: chalk.yellow,
|
|
564
|
+
SPEC_READY: chalk.green,
|
|
565
|
+
ASSIGNED: chalk.blue,
|
|
566
|
+
IN_PROGRESS: chalk.magenta,
|
|
567
|
+
DELIVERED: chalk.greenBright,
|
|
568
|
+
CANCELLED: chalk.red,
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
const BIZREQS_PRIORITY_COLORS = {
|
|
572
|
+
LOW: chalk.dim,
|
|
573
|
+
MEDIUM: chalk.white,
|
|
574
|
+
HIGH: chalk.yellow,
|
|
575
|
+
URGENT: chalk.red,
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
export function formatBizReqsList(submissions) {
|
|
579
|
+
if (!submissions || submissions.length === 0) {
|
|
580
|
+
console.log(chalk.dim('\n No submissions found.\n'));
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
console.log('');
|
|
585
|
+
console.log(
|
|
586
|
+
` ${brand.teal(padRight('ID', 16))}${padRight('Organization', 30)}${padRight('Solution', 20)}${padRight('Submitted', 12)}${padRight('Complexity', 12)}Status`
|
|
587
|
+
);
|
|
588
|
+
console.log(brand.darkGold(` ${'\u2500'.repeat(14)} ${'\u2500'.repeat(28)} ${'\u2500'.repeat(18)} ${'\u2500'.repeat(10)} ${'\u2500'.repeat(10)} ${'\u2500'.repeat(12)}`));
|
|
589
|
+
|
|
590
|
+
for (const s of submissions) {
|
|
591
|
+
const id = chalk.cyan(padRight(s.submissionId, 16));
|
|
592
|
+
const org = padRight(truncate(s.organizationName, 28), 30);
|
|
593
|
+
const solution = padRight(truncate(s.solutionName || '—', 18), 20);
|
|
594
|
+
const date = padRight(relativeTime(s.createdAt), 12);
|
|
595
|
+
const complexity = padRight(s.overallComplexity || '—', 12);
|
|
596
|
+
const statusFn = BIZREQS_STATUS_COLORS[s.status] || chalk.white;
|
|
597
|
+
const status = statusFn(s.status.replace('_', ' '));
|
|
598
|
+
console.log(` ${id}${org}${solution}${date}${complexity}${status}`);
|
|
599
|
+
}
|
|
600
|
+
console.log('');
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
export function formatBizReqsStatusCounts(counts) {
|
|
604
|
+
if (!counts || Object.keys(counts).length === 0) return;
|
|
605
|
+
|
|
606
|
+
const parts = [];
|
|
607
|
+
const order = ['NEW', 'IN_REVIEW', 'SPEC_READY', 'ASSIGNED', 'IN_PROGRESS', 'DELIVERED'];
|
|
608
|
+
for (const status of order) {
|
|
609
|
+
if (counts[status]) {
|
|
610
|
+
const colorFn = BIZREQS_STATUS_COLORS[status] || chalk.white;
|
|
611
|
+
parts.push(colorFn(`${counts[status]} ${status.toLowerCase().replace('_', ' ')}`));
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
if (parts.length > 0) {
|
|
615
|
+
console.log(` ${parts.join(chalk.dim(' | '))}\n`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export function formatBizReqsStatus(data) {
|
|
620
|
+
const lines = [];
|
|
621
|
+
|
|
622
|
+
lines.push('');
|
|
623
|
+
const statusFn = BIZREQS_STATUS_COLORS[data.status] || chalk.white;
|
|
624
|
+
lines.push(` ${chalk.bold(data.submissionId)} ${chalk.dim('·')} ${statusFn(data.status.replace('_', ' '))}`);
|
|
625
|
+
lines.push(` ${brand.darkGold('\u2500'.repeat(50))}`);
|
|
626
|
+
lines.push('');
|
|
627
|
+
lines.push(` ${chalk.dim('Organization:')} ${data.organizationName}`);
|
|
628
|
+
|
|
629
|
+
if (data.solutionName) {
|
|
630
|
+
lines.push(` ${chalk.dim('Solution:')} ${data.solutionName}`);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (data.overallComplexity) {
|
|
634
|
+
lines.push(` ${chalk.dim('Complexity:')} ${data.overallComplexity}`);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (data.estimatedTimeline) {
|
|
638
|
+
lines.push(` ${chalk.dim('Timeline:')} ${data.estimatedTimeline}`);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
const priorityFn = BIZREQS_PRIORITY_COLORS[data.priority] || chalk.white;
|
|
642
|
+
lines.push(` ${chalk.dim('Priority:')} ${priorityFn(data.priority)}`);
|
|
643
|
+
|
|
644
|
+
if (data.components && Array.isArray(data.components) && data.components.length > 0) {
|
|
645
|
+
lines.push('');
|
|
646
|
+
lines.push(` ${chalk.dim('Components:')}`);
|
|
647
|
+
for (const comp of data.components) {
|
|
648
|
+
const name = comp.name || comp;
|
|
649
|
+
const type = comp.type ? chalk.dim(` (${comp.type})`) : '';
|
|
650
|
+
lines.push(` ${chalk.dim('•')} ${name}${type}`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
lines.push('');
|
|
655
|
+
lines.push(` ${chalk.dim('Spec:')} ${data.hasSpec ? chalk.green('Generated') + chalk.dim(` (${formatDate(data.specGeneratedAt)})`) : chalk.dim('Not yet')}`);
|
|
656
|
+
lines.push(` ${chalk.dim('Submitted:')} ${formatDate(data.createdAt)}`);
|
|
657
|
+
if (data.reviewedAt) {
|
|
658
|
+
lines.push(` ${chalk.dim('Reviewed:')} ${formatDate(data.reviewedAt)}`);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
lines.push('');
|
|
662
|
+
console.log(lines.join('\n'));
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export function formatRecommendationBox(rec) {
|
|
666
|
+
const lines = [];
|
|
667
|
+
const width = 65;
|
|
668
|
+
const bdr = '\u2500'.repeat(width);
|
|
669
|
+
const b = brand.darkGold;
|
|
670
|
+
|
|
671
|
+
lines.push('');
|
|
672
|
+
lines.push(` ${b('\u250C' + bdr + '\u2510')}`);
|
|
673
|
+
lines.push(` ${b('\u2502')} ${brand.gold(chalk.bold(`RECOMMENDED SOLUTION: ${rec.solutionName}`)).padEnd(width - 1)}${b('\u2502')}`);
|
|
674
|
+
if (rec.organizationName) {
|
|
675
|
+
lines.push(` ${b('\u2502')} ${brand.teal(`For: ${rec.organizationName}`).padEnd(width - 1)}${b('\u2502')}`);
|
|
676
|
+
}
|
|
677
|
+
lines.push(` ${b('\u251C' + bdr + '\u2524')}`);
|
|
678
|
+
lines.push(` ${b('\u2502')}${' '.repeat(width + 1)}${b('\u2502')}`);
|
|
679
|
+
|
|
680
|
+
if (rec.components && Array.isArray(rec.components)) {
|
|
681
|
+
for (let i = 0; i < rec.components.length; i++) {
|
|
682
|
+
const comp = rec.components[i];
|
|
683
|
+
const icon = comp.type === 'portal' ? '\uD83D\uDCF1'
|
|
684
|
+
: comp.type === 'game' ? '\uD83C\uDFAE'
|
|
685
|
+
: comp.type === 'agent' ? '\uD83E\uDD16'
|
|
686
|
+
: comp.type === 'feed' ? '\uD83D\uDCCA'
|
|
687
|
+
: comp.type === 'model' ? '\uD83E\uDDE0'
|
|
688
|
+
: comp.type === 'voice' ? '\uD83C\uDFA4'
|
|
689
|
+
: '\uD83D\uDCE6';
|
|
690
|
+
|
|
691
|
+
const compLine = ` ${icon} Component ${i + 1}: ${comp.name}`;
|
|
692
|
+
lines.push(` ${b('\u2502')} ${brand.cream(compLine).padEnd(width - 1)}${b('\u2502')}`);
|
|
693
|
+
|
|
694
|
+
if (comp.description) {
|
|
695
|
+
const descWords = comp.description.split(' ');
|
|
696
|
+
let currentLine = ' ';
|
|
697
|
+
for (const word of descWords) {
|
|
698
|
+
if (currentLine.length + word.length + 1 > width - 4) {
|
|
699
|
+
lines.push(` ${b('\u2502')} ${brand.teal(currentLine).padEnd(width - 1)}${b('\u2502')}`);
|
|
700
|
+
currentLine = ' ' + word;
|
|
701
|
+
} else {
|
|
702
|
+
currentLine += (currentLine.length > 5 ? ' ' : '') + word;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
if (currentLine.trim()) {
|
|
706
|
+
lines.push(` ${b('\u2502')} ${brand.teal(currentLine).padEnd(width - 1)}${b('\u2502')}`);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
if (comp.type) {
|
|
711
|
+
const builtWith = ` Built with: myvillage ${comp.type}`;
|
|
712
|
+
lines.push(` ${b('\u2502')} ${brand.gold(builtWith).padEnd(width - 1)}${b('\u2502')}`);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
lines.push(` ${b('\u2502')}${' '.repeat(width + 1)}${b('\u2502')}`);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
lines.push(` ${b('\u251C' + bdr + '\u2524')}`);
|
|
720
|
+
|
|
721
|
+
if (rec.estimatedTimeline) {
|
|
722
|
+
const tl = ` Estimated Build Time: ${rec.estimatedTimeline}`;
|
|
723
|
+
lines.push(` ${b('\u2502')} ${brand.cream(tl).padEnd(width - 1)}${b('\u2502')}`);
|
|
724
|
+
}
|
|
725
|
+
if (rec.estimatedMVT) {
|
|
726
|
+
const mvt = ` Estimated MVT Budget: ${rec.estimatedMVT} MVT`;
|
|
727
|
+
lines.push(` ${b('\u2502')} ${brand.cream(mvt).padEnd(width - 1)}${b('\u2502')}`);
|
|
728
|
+
}
|
|
729
|
+
if (rec.overallComplexity) {
|
|
730
|
+
const cx = ` Complexity: ${rec.overallComplexity}`;
|
|
731
|
+
lines.push(` ${b('\u2502')} ${brand.cream(cx).padEnd(width - 1)}${b('\u2502')}`);
|
|
732
|
+
}
|
|
733
|
+
lines.push(` ${b('\u2514' + bdr + '\u2518')}`);
|
|
734
|
+
lines.push('');
|
|
735
|
+
|
|
736
|
+
console.log(lines.join('\n'));
|
|
737
|
+
}
|
|
738
|
+
|
|
406
739
|
// ── Pagination ──────────────────────────────────────────
|
|
407
740
|
|
|
408
741
|
export function formatPagination(meta) {
|