@myvillage/cli 1.10.2 → 1.17.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/package.json +1 -1
- package/src/agent-runtime/loop.js +81 -3
- package/src/commands/agent-client.js +435 -0
- package/src/commands/agent-grant.js +131 -0
- package/src/commands/agent-local.js +354 -1
- package/src/commands/create-app.js +61 -1
- package/src/commands/media.js +185 -187
- package/src/commands/wisdom.js +185 -0
- package/src/index.js +199 -0
- package/src/utils/agentic-templates.js +10 -2
- package/src/utils/api.js +157 -0
- package/src/utils/formatters.js +72 -0
- package/src/utils/wisdom.js +102 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join, basename } from 'path';
|
|
4
|
+
import { isAuthenticated } from '../utils/auth.js';
|
|
5
|
+
import { brand, villageSpinner } from '../utils/brand.js';
|
|
6
|
+
import { agentExists } from '../utils/local-agent.js';
|
|
7
|
+
import {
|
|
8
|
+
listVillageBooks,
|
|
9
|
+
exportVillageBook,
|
|
10
|
+
importVillageBook,
|
|
11
|
+
} from '../utils/api.js';
|
|
12
|
+
import {
|
|
13
|
+
parseWisdom,
|
|
14
|
+
serializeWisdom,
|
|
15
|
+
slugify,
|
|
16
|
+
getAgentWisdomDir,
|
|
17
|
+
ensureWisdomDir,
|
|
18
|
+
readAgentWisdom,
|
|
19
|
+
writeWisdomFile,
|
|
20
|
+
} from '../utils/wisdom.js';
|
|
21
|
+
|
|
22
|
+
function requireAuth() {
|
|
23
|
+
if (!isAuthenticated()) {
|
|
24
|
+
console.log(chalk.red(' ✗ Authentication required. Run \'myvillage login\' first.'));
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function resolveAgentName(name, action) {
|
|
31
|
+
if (!name) {
|
|
32
|
+
console.log(chalk.red(` ✗ Specify an agent: myvillage wisdom ${action} --agent <name>\n`));
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (!agentExists(name)) {
|
|
36
|
+
console.log(chalk.red(` ✗ Agent "${name}" not found.\n`));
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return name;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ── list ────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
export async function wisdomListCommand(options = {}) {
|
|
45
|
+
if (options.remote) {
|
|
46
|
+
if (!requireAuth()) return;
|
|
47
|
+
try {
|
|
48
|
+
const result = await listVillageBooks({ bookTypeId: 'wisdom' });
|
|
49
|
+
// The API can return either an array directly or wrapped in { data }
|
|
50
|
+
const books = Array.isArray(result) ? result : result?.data || [];
|
|
51
|
+
const wisdom = books.filter(b => b.bookType?.name === 'wisdom' || !b.bookType);
|
|
52
|
+
if (wisdom.length === 0) {
|
|
53
|
+
console.log(brand.teal(' No community wisdom files published yet.\n'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
console.log(brand.teal(` ${wisdom.length} wisdom file(s) on the network:\n`));
|
|
57
|
+
for (const w of wisdom) {
|
|
58
|
+
console.log(` ${brand.gold(w.id)} ${chalk.bold(w.name)}`);
|
|
59
|
+
if (w.description) console.log(` ${chalk.dim(w.description)}`);
|
|
60
|
+
}
|
|
61
|
+
console.log('');
|
|
62
|
+
} catch (err) {
|
|
63
|
+
const msg = err.response?.data?.error || err.message;
|
|
64
|
+
console.log(chalk.red(` ✗ Failed to list remote wisdom: ${msg}\n`));
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Local mode: list every wisdom file across every agent on disk
|
|
70
|
+
if (!options.agent) {
|
|
71
|
+
console.log(chalk.yellow(' Hint: pass --agent <name> to list one agent\'s wisdom, or --remote to list community-published wisdom.\n'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!resolveAgentName(options.agent, 'list')) return;
|
|
75
|
+
const files = readAgentWisdom(options.agent);
|
|
76
|
+
if (files.length === 0) {
|
|
77
|
+
console.log(brand.teal(` Agent "${options.agent}" has no wisdom files yet.\n`));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
console.log(brand.teal(` ${files.length} local wisdom file(s) for "${options.agent}":\n`));
|
|
81
|
+
for (const w of files) {
|
|
82
|
+
const linked = w.villageBookId ? brand.gold(` (synced ${w.villageBookId})`) : chalk.dim(' (local-only)');
|
|
83
|
+
console.log(` ${chalk.bold(w.name)}${linked}`);
|
|
84
|
+
if (w.description) console.log(` ${chalk.dim(w.description)}`);
|
|
85
|
+
console.log(` ${chalk.dim(w.path)}`);
|
|
86
|
+
}
|
|
87
|
+
console.log('');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── pull ────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
export async function wisdomPullCommand(id, options = {}) {
|
|
93
|
+
if (!requireAuth()) return;
|
|
94
|
+
if (!id) {
|
|
95
|
+
console.log(chalk.red(' ✗ Specify a village book id: myvillage wisdom pull <id> --into <agent>\n'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!options.into) {
|
|
99
|
+
console.log(chalk.red(' ✗ Specify a target agent: myvillage wisdom pull <id> --into <agent>\n'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!resolveAgentName(options.into, 'pull')) return;
|
|
103
|
+
|
|
104
|
+
const spinner = villageSpinner('Fetching wisdom from the network...').start();
|
|
105
|
+
try {
|
|
106
|
+
const text = await exportVillageBook(id);
|
|
107
|
+
const { frontmatter } = parseWisdom(text);
|
|
108
|
+
const slug = slugify(frontmatter.name || id);
|
|
109
|
+
const dir = ensureWisdomDir(options.into);
|
|
110
|
+
const filePath = join(dir, `${slug}.wisdom`);
|
|
111
|
+
writeWisdomFile(filePath, parseWisdom(text)); // re-serialize for consistent formatting
|
|
112
|
+
spinner.succeed(`Wisdom "${frontmatter.name || id}" saved to ${filePath}`);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
const msg = err.response?.data?.error || err.message;
|
|
115
|
+
spinner.fail(`Failed to pull wisdom: ${msg}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── push ────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
export async function wisdomPushCommand(filePath) {
|
|
122
|
+
if (!requireAuth()) return;
|
|
123
|
+
if (!filePath) {
|
|
124
|
+
console.log(chalk.red(' ✗ Specify a .wisdom file: myvillage wisdom push <file>\n'));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!existsSync(filePath)) {
|
|
128
|
+
console.log(chalk.red(` ✗ File not found: ${filePath}\n`));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
133
|
+
const spinner = villageSpinner('Publishing wisdom to the network...').start();
|
|
134
|
+
try {
|
|
135
|
+
const result = await importVillageBook({ content });
|
|
136
|
+
const book = result?.data || result;
|
|
137
|
+
if (book?.id) {
|
|
138
|
+
// Save the assigned id back into the local file so future pushes update
|
|
139
|
+
// the same row instead of creating duplicates.
|
|
140
|
+
const parsed = parseWisdom(content);
|
|
141
|
+
parsed.frontmatter.villageBookId = book.id;
|
|
142
|
+
writeWisdomFile(filePath, parsed);
|
|
143
|
+
spinner.succeed(`Published as ${book.id}`);
|
|
144
|
+
} else {
|
|
145
|
+
spinner.succeed('Published.');
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
const msg = err.response?.data?.error || err.message;
|
|
149
|
+
spinner.fail(`Failed to push wisdom: ${msg}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ── new ─────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
export async function wisdomNewCommand(name, options = {}) {
|
|
156
|
+
if (!name) {
|
|
157
|
+
console.log(chalk.red(' ✗ Specify a name: myvillage wisdom new <name> --agent <agent>\n'));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!options.agent) {
|
|
161
|
+
console.log(chalk.red(' ✗ Specify a target agent: myvillage wisdom new <name> --agent <agent>\n'));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (!resolveAgentName(options.agent, 'new')) return;
|
|
165
|
+
|
|
166
|
+
const slug = slugify(name);
|
|
167
|
+
const dir = ensureWisdomDir(options.agent);
|
|
168
|
+
const filePath = join(dir, `${slug}.wisdom`);
|
|
169
|
+
if (existsSync(filePath)) {
|
|
170
|
+
console.log(chalk.yellow(` ${filePath} already exists; edit it instead.\n`));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const template = serializeWisdom({
|
|
175
|
+
frontmatter: {
|
|
176
|
+
name: slug,
|
|
177
|
+
description: options.description || 'Describe what this skill does and when to apply it.',
|
|
178
|
+
trigger: options.trigger || 'Describe the condition that should activate this skill.',
|
|
179
|
+
},
|
|
180
|
+
body: '<!-- The body of this wisdom file. Write it as a short skill: tone, structure, examples. The agent loads it into its system prompt every iteration. -->\n',
|
|
181
|
+
});
|
|
182
|
+
writeWisdomFile(filePath, parseWisdom(template));
|
|
183
|
+
console.log(brand.green(` ✓ Wisdom scaffolded at ${filePath}`));
|
|
184
|
+
console.log(brand.teal(` Edit the body, then publish with: myvillage wisdom push ${filePath}\n`));
|
|
185
|
+
}
|
package/src/index.js
CHANGED
|
@@ -2,6 +2,12 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import updateNotifier from 'update-notifier';
|
|
4
4
|
import { loginCommand } from './commands/login.js';
|
|
5
|
+
import {
|
|
6
|
+
mediaDraftCreateCommand,
|
|
7
|
+
mediaDraftEditCommand,
|
|
8
|
+
mediaDraftListCommand,
|
|
9
|
+
mediaDraftStatusCommand,
|
|
10
|
+
} from './commands/media.js';
|
|
5
11
|
import { logoutCommand } from './commands/logout.js';
|
|
6
12
|
import { createGameCommand } from './commands/create-game.js';
|
|
7
13
|
import { createCommand } from './commands/create-app.js';
|
|
@@ -45,7 +51,25 @@ import {
|
|
|
45
51
|
agentLogsCommand,
|
|
46
52
|
agentAddToolCommand,
|
|
47
53
|
agentRemoveToolCommand,
|
|
54
|
+
agentTaskListCommand,
|
|
55
|
+
agentTaskAssignCommand,
|
|
56
|
+
agentMemoryCommand,
|
|
57
|
+
agentRecallCommand,
|
|
58
|
+
agentRememberCommand,
|
|
48
59
|
} from './commands/agent-local.js';
|
|
60
|
+
import {
|
|
61
|
+
agentGrantCommand,
|
|
62
|
+
agentRevokeCommand,
|
|
63
|
+
agentGrantsCommand,
|
|
64
|
+
} from './commands/agent-grant.js';
|
|
65
|
+
import {
|
|
66
|
+
agentRegisterClientCommand,
|
|
67
|
+
agentListClientsCommand,
|
|
68
|
+
agentViewClientCommand,
|
|
69
|
+
agentEditClientCommand,
|
|
70
|
+
agentDeactivateClientCommand,
|
|
71
|
+
agentRotateClientKeyCommand,
|
|
72
|
+
} from './commands/agent-client.js';
|
|
49
73
|
import {
|
|
50
74
|
bizreqsNewCommand,
|
|
51
75
|
bizreqsSpecCommand,
|
|
@@ -69,6 +93,12 @@ import { checkinCommand } from './commands/checkin.js';
|
|
|
69
93
|
import { discoverCommand } from './commands/discover.js';
|
|
70
94
|
import { logCommand } from './commands/log.js';
|
|
71
95
|
import { storyCommand } from './commands/story.js';
|
|
96
|
+
import {
|
|
97
|
+
wisdomListCommand,
|
|
98
|
+
wisdomPullCommand,
|
|
99
|
+
wisdomPushCommand,
|
|
100
|
+
wisdomNewCommand,
|
|
101
|
+
} from './commands/wisdom.js';
|
|
72
102
|
import {
|
|
73
103
|
soulprintInitCommand,
|
|
74
104
|
soulprintIngestCommand,
|
|
@@ -408,6 +438,98 @@ export function run() {
|
|
|
408
438
|
.description('Remove an MCP server tool from a local agent')
|
|
409
439
|
.action(agentRemoveToolCommand);
|
|
410
440
|
|
|
441
|
+
// Task queue commands — assign and inspect work for a developer's agent
|
|
442
|
+
agentCmd
|
|
443
|
+
.command('task-list <name>')
|
|
444
|
+
.description('List tasks queued for a local agent')
|
|
445
|
+
.option('--status <status>', 'Filter by status (PENDING|IN_PROGRESS|COMPLETED|FAILED|CANCELLED)')
|
|
446
|
+
.option('--limit <n>', 'Max number of tasks to show', '20')
|
|
447
|
+
.action(agentTaskListCommand);
|
|
448
|
+
|
|
449
|
+
agentCmd
|
|
450
|
+
.command('task-assign <name>')
|
|
451
|
+
.description('Assign a task to a local agent (it will pick it up on next poll)')
|
|
452
|
+
.option('--type <type>', 'Task type (e.g., CLIENT_TASK, GENERATE_POST, SHARE_KNOWLEDGE)')
|
|
453
|
+
.option('--instruction <text>', 'Free-text instruction (required for CLIENT_TASK)')
|
|
454
|
+
.option('--input <json>', 'JSON-encoded structured input payload')
|
|
455
|
+
.option('--priority <n>', 'Priority 1-10 (lower runs first)', '5')
|
|
456
|
+
.action(agentTaskAssignCommand);
|
|
457
|
+
|
|
458
|
+
// Agent memory (short-term KV state) and recall (long-term searchable memory)
|
|
459
|
+
agentCmd
|
|
460
|
+
.command('memory <name> <action> [args...]')
|
|
461
|
+
.description('Read/write an agent\'s short-term memory: list | get <key> | set <key> <value> | delete <key>')
|
|
462
|
+
.action((name, action, args = []) => agentMemoryCommand(name, action, ...args));
|
|
463
|
+
|
|
464
|
+
agentCmd
|
|
465
|
+
.command('recall <name> <query>')
|
|
466
|
+
.description('Search this agent\'s long-term memory (Knowledge submissions it authored)')
|
|
467
|
+
.option('--limit <n>', 'Max results to show', '10')
|
|
468
|
+
.action(agentRecallCommand);
|
|
469
|
+
|
|
470
|
+
agentCmd
|
|
471
|
+
.command('remember <name> <text>')
|
|
472
|
+
.description('Save a memory to this agent\'s long-term store (Knowledge submission with source=AI_AGENT)')
|
|
473
|
+
.option('--summary <text>', 'Short summary of the memory')
|
|
474
|
+
.option('--themes <list>', 'Comma-separated tags')
|
|
475
|
+
.option('--sharing <option>', 'PRIVATE | VILLAGE_ONLY | PUBLIC', 'PRIVATE')
|
|
476
|
+
.action(agentRememberCommand);
|
|
477
|
+
|
|
478
|
+
// Per-agent OAuth credential grants
|
|
479
|
+
agentCmd
|
|
480
|
+
.command('grants <name>')
|
|
481
|
+
.description('List active OAuth credential grants for a local agent')
|
|
482
|
+
.action(agentGrantsCommand);
|
|
483
|
+
|
|
484
|
+
agentCmd
|
|
485
|
+
.command('grant <name> <provider>')
|
|
486
|
+
.description('Grant the agent access to a connected OAuth provider (google|microsoft|zoom)')
|
|
487
|
+
.action(agentGrantCommand);
|
|
488
|
+
|
|
489
|
+
agentCmd
|
|
490
|
+
.command('revoke <name> <provider>')
|
|
491
|
+
.description('Revoke an OAuth provider grant from the agent')
|
|
492
|
+
.action(agentRevokeCommand);
|
|
493
|
+
|
|
494
|
+
// Client agent registration commands
|
|
495
|
+
agentCmd
|
|
496
|
+
.command('register-client')
|
|
497
|
+
.description('Register a client application for agent automation')
|
|
498
|
+
.option('--agent <handle>', 'Agent handle')
|
|
499
|
+
.option('--client-id <id>', 'Client identifier (lowercase)')
|
|
500
|
+
.option('--name <name>', 'Client display name')
|
|
501
|
+
.option('--url <url>', 'Client base URL')
|
|
502
|
+
.option('--workflow <type>', 'Workflow type (e.g., submission_processor)')
|
|
503
|
+
.option('--schedule <cron>', 'Cron schedule expression')
|
|
504
|
+
.option('--timezone <tz>', 'Timezone (default: America/Chicago)')
|
|
505
|
+
.option('--env-file <path>', 'Write API key to this .env file')
|
|
506
|
+
.action(agentRegisterClientCommand);
|
|
507
|
+
|
|
508
|
+
agentCmd
|
|
509
|
+
.command('list-clients')
|
|
510
|
+
.description('List all registered client agent configs')
|
|
511
|
+
.action(agentListClientsCommand);
|
|
512
|
+
|
|
513
|
+
agentCmd
|
|
514
|
+
.command('view-client <configId>')
|
|
515
|
+
.description('View a client agent config')
|
|
516
|
+
.action(agentViewClientCommand);
|
|
517
|
+
|
|
518
|
+
agentCmd
|
|
519
|
+
.command('edit-client <configId>')
|
|
520
|
+
.description('Edit a client agent config')
|
|
521
|
+
.action(agentEditClientCommand);
|
|
522
|
+
|
|
523
|
+
agentCmd
|
|
524
|
+
.command('deactivate-client <configId>')
|
|
525
|
+
.description('Deactivate a client agent config')
|
|
526
|
+
.action(agentDeactivateClientCommand);
|
|
527
|
+
|
|
528
|
+
agentCmd
|
|
529
|
+
.command('rotate-client-key <configId>')
|
|
530
|
+
.description('Rotate the API key for a client agent config')
|
|
531
|
+
.action(agentRotateClientKeyCommand);
|
|
532
|
+
|
|
411
533
|
// ── Village Content Pipeline ───────────────────────────
|
|
412
534
|
|
|
413
535
|
program
|
|
@@ -432,6 +554,49 @@ export function run() {
|
|
|
432
554
|
.description('Share a story or wisdom with the network')
|
|
433
555
|
.action(storyCommand);
|
|
434
556
|
|
|
557
|
+
// ── Media: Soulprint Reels (mobile-app posts) ──────────
|
|
558
|
+
|
|
559
|
+
const mediaCmd = program
|
|
560
|
+
.command('media')
|
|
561
|
+
.description('Manage Soulprint Reels (internal social posts shown in the mobile app)');
|
|
562
|
+
|
|
563
|
+
const mediaDraftCmd = mediaCmd
|
|
564
|
+
.command('draft')
|
|
565
|
+
.description('Reel draft commands');
|
|
566
|
+
|
|
567
|
+
mediaDraftCmd
|
|
568
|
+
.command('create')
|
|
569
|
+
.description('Create a new reel draft (video, photo, carousel, audio, text)')
|
|
570
|
+
.option('-f, --file <path>', 'Attach a media file (repeatable)', (v, prev) => prev ? [...prev, v] : [v])
|
|
571
|
+
.option('-a, --asset-type <type>', 'Asset type when --file is given (IMAGE, VIDEO, THUMBNAIL, DOCUMENT)')
|
|
572
|
+
.option('--submit', 'Auto-submit the draft for review after creation')
|
|
573
|
+
.action(mediaDraftCreateCommand);
|
|
574
|
+
|
|
575
|
+
mediaDraftCmd
|
|
576
|
+
.command('edit <id>')
|
|
577
|
+
.description('Edit a DRAFT or REJECTED reel draft')
|
|
578
|
+
.action(mediaDraftEditCommand);
|
|
579
|
+
|
|
580
|
+
mediaDraftCmd
|
|
581
|
+
.command('list')
|
|
582
|
+
.description('List reel drafts')
|
|
583
|
+
.option('--status <status>', 'Filter by status (DRAFT, SUBMITTED, IN_REVIEW, APPROVED, REJECTED, PUBLISHED)')
|
|
584
|
+
.option('--content-type <type>', 'Filter by content type (VIDEO, PHOTO, CAROUSEL, AUDIO, TEXT)')
|
|
585
|
+
.option('--platform <platform>', '[Deprecated] Legacy platform alias — maps forward to content type')
|
|
586
|
+
.option('--visibility <visibility>', 'Filter by visibility (PUBLIC, COMMUNITY, PRIVATE)')
|
|
587
|
+
.option('--community-id <id>', 'Filter by community')
|
|
588
|
+
.option('--search <query>', 'Search captions / titles / quotes')
|
|
589
|
+
.option('-n, --limit <number>', 'Number of drafts', '20')
|
|
590
|
+
.option('--offset <number>', 'Pagination offset', '0')
|
|
591
|
+
.option('--sort <sort>', 'Sort: newest, oldest, publish_date', 'newest')
|
|
592
|
+
.option('--json', 'Output raw JSON')
|
|
593
|
+
.action(mediaDraftListCommand);
|
|
594
|
+
|
|
595
|
+
mediaDraftCmd
|
|
596
|
+
.command('status <id>')
|
|
597
|
+
.description('Show status of a reel draft')
|
|
598
|
+
.action(mediaDraftStatusCommand);
|
|
599
|
+
|
|
435
600
|
// ── BizReqs: Business Requirements Pipeline ───────────
|
|
436
601
|
|
|
437
602
|
const bizreqsCmd = program
|
|
@@ -483,6 +648,40 @@ export function run() {
|
|
|
483
648
|
|
|
484
649
|
// ── SoulPrint Studio: Model Training Pipeline ───────────
|
|
485
650
|
|
|
651
|
+
// \u2500\u2500 Wisdom: agent skill packs (Books of Wisdom) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
652
|
+
|
|
653
|
+
const wisdomCmd = program
|
|
654
|
+
.command('wisdom')
|
|
655
|
+
.description('Manage .wisdom files \u2014 agent skill packs backed by the network\'s Books of Wisdom');
|
|
656
|
+
|
|
657
|
+
wisdomCmd
|
|
658
|
+
.command('list')
|
|
659
|
+
.description('List wisdom files (use --remote for community-published, --agent for local)')
|
|
660
|
+
.option('--remote', 'List community-published wisdom on the network')
|
|
661
|
+
.option('--agent <name>', 'List a local agent\'s wisdom files')
|
|
662
|
+
.action(wisdomListCommand);
|
|
663
|
+
|
|
664
|
+
wisdomCmd
|
|
665
|
+
.command('pull <id>')
|
|
666
|
+
.description('Fetch a community wisdom file and save it into a local agent')
|
|
667
|
+
.requiredOption('--into <agent>', 'Local agent to save the wisdom file into')
|
|
668
|
+
.action(wisdomPullCommand);
|
|
669
|
+
|
|
670
|
+
wisdomCmd
|
|
671
|
+
.command('push <file>')
|
|
672
|
+
.description('Publish a .wisdom file to the network so other agents can use it')
|
|
673
|
+
.action(wisdomPushCommand);
|
|
674
|
+
|
|
675
|
+
wisdomCmd
|
|
676
|
+
.command('new <name>')
|
|
677
|
+
.description('Scaffold a new local .wisdom file for an agent')
|
|
678
|
+
.requiredOption('--agent <name>', 'Local agent to add the wisdom file to')
|
|
679
|
+
.option('--description <text>', 'Short description shown in the agent\'s skill list')
|
|
680
|
+
.option('--trigger <text>', 'Condition that should activate this skill')
|
|
681
|
+
.action(wisdomNewCommand);
|
|
682
|
+
|
|
683
|
+
// \u2500\u2500 SoulPrint Studio (legacy): training pipeline \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
684
|
+
|
|
486
685
|
const soulprintCmd = program
|
|
487
686
|
.command('soulprint')
|
|
488
687
|
.description('SoulPrint Studio \u2014 datasets, training, and model publishing');
|
|
@@ -40,6 +40,7 @@ export function createAgenticAppProject(targetDir, options) {
|
|
|
40
40
|
includeRestApi = true,
|
|
41
41
|
mcpToolGroups = [],
|
|
42
42
|
oauthCredentials = null,
|
|
43
|
+
agentConfig = null,
|
|
43
44
|
} = options;
|
|
44
45
|
|
|
45
46
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
@@ -88,7 +89,7 @@ export function createAgenticAppProject(targetDir, options) {
|
|
|
88
89
|
writeFileSync(join(targetDir, 'package.json'), generatePackageJson(slug, description, includeMcp));
|
|
89
90
|
writeFileSync(join(targetDir, 'next.config.mjs'), generateNextConfig());
|
|
90
91
|
writeFileSync(join(targetDir, '.gitignore'), generateGitignore());
|
|
91
|
-
writeFileSync(join(targetDir, '.env.local'), generateEnv(oauthCredentials, hasOAuth, includeMcp));
|
|
92
|
+
writeFileSync(join(targetDir, '.env.local'), generateEnv(oauthCredentials, hasOAuth, includeMcp, agentConfig));
|
|
92
93
|
writeFileSync(join(targetDir, '.env.example'), generateEnvExample(hasOAuth, includeMcp));
|
|
93
94
|
writeFileSync(join(targetDir, 'README.md'), generateReadme(name, description, hasOAuth, includeMcp, includeRestApi, features));
|
|
94
95
|
writeFileSync(join(targetDir, 'jsconfig.json'), generateJsConfig());
|
|
@@ -214,7 +215,7 @@ out/
|
|
|
214
215
|
`;
|
|
215
216
|
}
|
|
216
217
|
|
|
217
|
-
function generateEnv(oauthCredentials, hasOAuth, includeMcp) {
|
|
218
|
+
function generateEnv(oauthCredentials, hasOAuth, includeMcp, agentConfig = null) {
|
|
218
219
|
const lines = [];
|
|
219
220
|
|
|
220
221
|
if (hasOAuth) {
|
|
@@ -233,6 +234,11 @@ function generateEnv(oauthCredentials, hasOAuth, includeMcp) {
|
|
|
233
234
|
lines.push('MYVILLAGEOS_MCP_URL=https://mcp.myvillageproject.ai');
|
|
234
235
|
}
|
|
235
236
|
|
|
237
|
+
if (agentConfig?.apiKey) {
|
|
238
|
+
lines.push(`MYVILLAGE_AGENT_API_KEY=${agentConfig.apiKey}`);
|
|
239
|
+
lines.push(`MYVILLAGE_AGENT_CLIENT_ID=${agentConfig.clientId}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
236
242
|
lines.push('ANTHROPIC_API_KEY=');
|
|
237
243
|
|
|
238
244
|
return lines.join('\n') + '\n';
|
|
@@ -254,6 +260,8 @@ function generateEnvExample(hasOAuth, includeMcp) {
|
|
|
254
260
|
lines.push('MYVILLAGEOS_MCP_URL=https://mcp.myvillageproject.ai');
|
|
255
261
|
}
|
|
256
262
|
|
|
263
|
+
lines.push('MYVILLAGE_AGENT_API_KEY=');
|
|
264
|
+
lines.push('MYVILLAGE_AGENT_CLIENT_ID=');
|
|
257
265
|
lines.push('ANTHROPIC_API_KEY=');
|
|
258
266
|
|
|
259
267
|
return lines.join('\n') + '\n';
|
package/src/utils/api.js
CHANGED
|
@@ -418,6 +418,44 @@ export async function listPostsByFilters(params = {}) {
|
|
|
418
418
|
return response.data;
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// ── Client Agent Configs API (/api/client-agents/configs) ──
|
|
422
|
+
|
|
423
|
+
export async function registerClientAgent(data) {
|
|
424
|
+
const client = getPlatformClient();
|
|
425
|
+
const response = await client.post('/client-agents/configs', data);
|
|
426
|
+
return response.data;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export async function listClientAgentConfigs() {
|
|
430
|
+
const client = getPlatformClient();
|
|
431
|
+
const response = await client.get('/client-agents/configs');
|
|
432
|
+
return response.data;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export async function getClientAgentConfig(configId) {
|
|
436
|
+
const client = getPlatformClient();
|
|
437
|
+
const response = await client.get(`/client-agents/configs/${encodeURIComponent(configId)}`);
|
|
438
|
+
return response.data;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export async function updateClientAgentConfig(configId, data) {
|
|
442
|
+
const client = getPlatformClient();
|
|
443
|
+
const response = await client.patch(`/client-agents/configs/${encodeURIComponent(configId)}`, data);
|
|
444
|
+
return response.data;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export async function deactivateClientAgent(configId) {
|
|
448
|
+
const client = getPlatformClient();
|
|
449
|
+
const response = await client.delete(`/client-agents/configs/${encodeURIComponent(configId)}`);
|
|
450
|
+
return response.data;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
export async function rotateClientAgentKey(configId) {
|
|
454
|
+
const client = getPlatformClient();
|
|
455
|
+
const response = await client.post(`/client-agents/configs/${encodeURIComponent(configId)}/rotate-key`);
|
|
456
|
+
return response.data;
|
|
457
|
+
}
|
|
458
|
+
|
|
421
459
|
// ── BizReqs API Client (/api/bizreqs) ───────────────────
|
|
422
460
|
|
|
423
461
|
export function getBizReqsClient() {
|
|
@@ -564,3 +602,122 @@ export async function submitGameForReview(gameId) {
|
|
|
564
602
|
const response = await client.put(`/games/${encodeURIComponent(gameId)}`, { status: 'SUBMITTED' });
|
|
565
603
|
return response.data;
|
|
566
604
|
}
|
|
605
|
+
|
|
606
|
+
// ── Village Agents (developer agents) ───────────────────
|
|
607
|
+
|
|
608
|
+
// AgentProfiles owned by the caller that aren't yet linked to a VillageAgent.
|
|
609
|
+
// Used by the CLI "attach existing network identity" picker.
|
|
610
|
+
export async function listMyUnlinkedAgentProfiles() {
|
|
611
|
+
const client = getNetworkClient();
|
|
612
|
+
const response = await client.get('/agents/my', { params: { unlinked: 'true' } });
|
|
613
|
+
return response.data;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Create a VillageAgent. Optionally either:
|
|
617
|
+
// - link to an existing AgentProfile via `agentProfileId`
|
|
618
|
+
// - auto-create a fresh AgentProfile via `createNetworkIdentity: true`
|
|
619
|
+
export async function createVillageAgent(data) {
|
|
620
|
+
const client = getPlatformClient();
|
|
621
|
+
const response = await client.post('/village-agents', data);
|
|
622
|
+
return response.data;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export async function listVillageAgents() {
|
|
626
|
+
const client = getPlatformClient();
|
|
627
|
+
const response = await client.get('/village-agents');
|
|
628
|
+
return response.data;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export async function getVillageAgent(id) {
|
|
632
|
+
const client = getPlatformClient();
|
|
633
|
+
const response = await client.get(`/village-agents/${encodeURIComponent(id)}`);
|
|
634
|
+
return response.data;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export async function updateVillageAgent(id, data) {
|
|
638
|
+
const client = getPlatformClient();
|
|
639
|
+
const response = await client.patch(`/village-agents/${encodeURIComponent(id)}`, data);
|
|
640
|
+
return response.data;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// ── Agent Task Queue ────────────────────────────────────
|
|
644
|
+
|
|
645
|
+
export async function listAgentTasks(villageAgentId, params = {}) {
|
|
646
|
+
const client = getPlatformClient();
|
|
647
|
+
const response = await client.get(
|
|
648
|
+
`/village-agents/${encodeURIComponent(villageAgentId)}/tasks`,
|
|
649
|
+
{ params },
|
|
650
|
+
);
|
|
651
|
+
return response.data;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
export async function assignAgentTask(villageAgentId, data) {
|
|
655
|
+
const client = getPlatformClient();
|
|
656
|
+
const response = await client.post(
|
|
657
|
+
`/village-agents/${encodeURIComponent(villageAgentId)}/tasks`,
|
|
658
|
+
data,
|
|
659
|
+
);
|
|
660
|
+
return response.data;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export async function claimAgentTask(villageAgentId, taskId) {
|
|
664
|
+
const client = getPlatformClient();
|
|
665
|
+
const response = await client.post(
|
|
666
|
+
`/village-agents/${encodeURIComponent(villageAgentId)}/tasks/${encodeURIComponent(taskId)}/claim`,
|
|
667
|
+
);
|
|
668
|
+
return response.data;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// completeAgentTask is also used for "fail" — pass `errorMessage` to mark FAILED,
|
|
672
|
+
// otherwise the task is marked COMPLETED with the given `output`.
|
|
673
|
+
export async function completeAgentTask(villageAgentId, taskId, data = {}) {
|
|
674
|
+
const client = getPlatformClient();
|
|
675
|
+
const response = await client.post(
|
|
676
|
+
`/village-agents/${encodeURIComponent(villageAgentId)}/tasks/${encodeURIComponent(taskId)}/complete`,
|
|
677
|
+
data,
|
|
678
|
+
);
|
|
679
|
+
return response.data;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// ── Wisdom (VillageBooks repurposed as agent skill packs) ──────────
|
|
683
|
+
|
|
684
|
+
export async function listVillageBooks(params = {}) {
|
|
685
|
+
const client = getPlatformClient();
|
|
686
|
+
const response = await client.get('/village-books', { params });
|
|
687
|
+
return response.data;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// Returns the raw .wisdom file text (YAML frontmatter + markdown body).
|
|
691
|
+
export async function exportVillageBook(id) {
|
|
692
|
+
const client = getPlatformClient();
|
|
693
|
+
const response = await client.get(
|
|
694
|
+
`/village-books/${encodeURIComponent(id)}/export`,
|
|
695
|
+
{ responseType: 'text', transformResponse: (data) => data },
|
|
696
|
+
);
|
|
697
|
+
return response.data;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
export async function importVillageBook(payload) {
|
|
701
|
+
const client = getPlatformClient();
|
|
702
|
+
const response = await client.post('/village-books/import', payload);
|
|
703
|
+
return response.data;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// ── Knowledge (long-term agent memory) ──────────────────
|
|
707
|
+
|
|
708
|
+
// Filter / search knowledge submissions. Pass `createdByAgentId` to narrow
|
|
709
|
+
// to a specific agent's own memories.
|
|
710
|
+
export async function listKnowledgeFiltered(params = {}) {
|
|
711
|
+
const client = getPlatformClient();
|
|
712
|
+
const response = await client.get('/knowledge/filtered', { params });
|
|
713
|
+
return response.data;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Write a memory by submitting a Knowledge entry attributed to the agent.
|
|
717
|
+
// Backed by /api/agent-tools/share-knowledge — the agent_profile_id override
|
|
718
|
+
// makes the entry appear in this specific agent's recall results.
|
|
719
|
+
export async function shareKnowledgeAsAgent(data) {
|
|
720
|
+
const client = getPlatformClient();
|
|
721
|
+
const response = await client.post('/agent-tools/share-knowledge', data);
|
|
722
|
+
return response.data;
|
|
723
|
+
}
|