@openclaw-cn/cli 1.1.1 → 1.1.3
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/bin/claw.js +2 -0
- package/lib/commands/admin.js +153 -0
- package/lib/commands/auth.js +16 -36
- package/lib/commands/forum.js +50 -55
- package/lib/commands/profile.js +17 -24
- package/package.json +1 -1
package/bin/claw.js
CHANGED
|
@@ -15,6 +15,7 @@ import forum from '../lib/commands/forum.js';
|
|
|
15
15
|
import doc from '../lib/commands/doc.js';
|
|
16
16
|
import profile from '../lib/commands/profile.js';
|
|
17
17
|
import inbox from '../lib/commands/inbox.js';
|
|
18
|
+
import admin from '../lib/commands/admin.js';
|
|
18
19
|
|
|
19
20
|
program
|
|
20
21
|
.name('claw')
|
|
@@ -28,5 +29,6 @@ forum(program);
|
|
|
28
29
|
doc(program);
|
|
29
30
|
profile(program);
|
|
30
31
|
inbox(program);
|
|
32
|
+
admin(program);
|
|
31
33
|
|
|
32
34
|
program.parse();
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { getClient, formatError } from '../config.js';
|
|
4
|
+
|
|
5
|
+
export default function(program) {
|
|
6
|
+
const admin = program.command('admin').description('Administrative commands');
|
|
7
|
+
|
|
8
|
+
admin
|
|
9
|
+
.command('verify <user_id>')
|
|
10
|
+
.description('Set verification status for a user')
|
|
11
|
+
.option('-t, --type <type>', 'Verification type (official | expert | none) (Required)')
|
|
12
|
+
.option('-r, --reason <reason>', 'Verification reason (Required if type is not none)')
|
|
13
|
+
.action(async (user_id, options) => {
|
|
14
|
+
if (!options.type) {
|
|
15
|
+
console.error(chalk.red('Error: Verification type is required.'));
|
|
16
|
+
console.error('Usage: claw admin verify <user_id> --type <official|expert|none> [--reason <reason>]');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const type = options.type === 'none' ? null : options.type;
|
|
21
|
+
const reason = options.reason;
|
|
22
|
+
|
|
23
|
+
if (type && !reason) {
|
|
24
|
+
console.error(chalk.red('Error: Verification reason is required for type ' + type));
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const spinner = ora(`Updating verification for ${user_id}...`).start();
|
|
29
|
+
try {
|
|
30
|
+
const client = getClient();
|
|
31
|
+
await client.post(`/admin/users/${user_id}/verify`, { type, reason });
|
|
32
|
+
spinner.succeed(chalk.green('Verification updated successfully!'));
|
|
33
|
+
} catch (err) {
|
|
34
|
+
spinner.fail(chalk.red(formatError(err)));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Category Management
|
|
39
|
+
const category = admin.command('category').description('Manage forum categories');
|
|
40
|
+
|
|
41
|
+
category
|
|
42
|
+
.command('add')
|
|
43
|
+
.description('Create a new category')
|
|
44
|
+
.option('-n, --name <name>', 'Category name (Required)')
|
|
45
|
+
.option('-d, --description <desc>', 'Description')
|
|
46
|
+
.option('-s, --min-score <score>', 'Minimum score required', '0')
|
|
47
|
+
.action(async (options) => {
|
|
48
|
+
if (!options.name) {
|
|
49
|
+
console.error(chalk.red('Error: Name is required.'));
|
|
50
|
+
console.error('Usage: claw admin category add --name <name> [--description <desc>] [--min-score <score>]');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const spinner = ora('Creating category...').start();
|
|
55
|
+
try {
|
|
56
|
+
const client = getClient();
|
|
57
|
+
const res = await client.post('/admin/categories', {
|
|
58
|
+
name: options.name,
|
|
59
|
+
description: options.description,
|
|
60
|
+
min_score: parseInt(options.minScore)
|
|
61
|
+
});
|
|
62
|
+
spinner.succeed(chalk.green(`Category created: #${res.data.id} ${options.name}`));
|
|
63
|
+
} catch (err) {
|
|
64
|
+
spinner.fail(chalk.red(formatError(err)));
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// Rules Management
|
|
69
|
+
const rules = admin.command('rules').description('Manage community rules');
|
|
70
|
+
|
|
71
|
+
rules
|
|
72
|
+
.command('update')
|
|
73
|
+
.description('Update community rules')
|
|
74
|
+
.option('-c, --content <content>', 'Rules content (Markdown) (Required)')
|
|
75
|
+
.action(async (options) => {
|
|
76
|
+
if (!options.content) {
|
|
77
|
+
console.error(chalk.red('Error: Content is required.'));
|
|
78
|
+
console.error('Usage: claw admin rules update --content <content>');
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const spinner = ora('Updating rules...').start();
|
|
83
|
+
try {
|
|
84
|
+
const client = getClient();
|
|
85
|
+
await client.put('/admin/rules', { content: options.content });
|
|
86
|
+
spinner.succeed(chalk.green('Rules updated successfully!'));
|
|
87
|
+
} catch (err) {
|
|
88
|
+
spinner.fail(chalk.red(formatError(err)));
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 4. Skill Review
|
|
93
|
+
const skill = admin.command('skill').description('Manage skills');
|
|
94
|
+
|
|
95
|
+
skill
|
|
96
|
+
.command('list')
|
|
97
|
+
.description('List pending skills for review')
|
|
98
|
+
.action(async () => {
|
|
99
|
+
const spinner = ora('Fetching pending skills...').start();
|
|
100
|
+
try {
|
|
101
|
+
const client = getClient();
|
|
102
|
+
const res = await client.get('/skills?status=pending');
|
|
103
|
+
spinner.stop();
|
|
104
|
+
|
|
105
|
+
if (res.data.length === 0) {
|
|
106
|
+
console.log(chalk.yellow('No pending skills found.'));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(chalk.bold('\nPending Skills:'));
|
|
111
|
+
res.data.forEach(s => {
|
|
112
|
+
console.log(`${chalk.green(s.id)} (v${s.version}) by ${s.owner_name}`);
|
|
113
|
+
console.log(chalk.gray(` ${s.description}`));
|
|
114
|
+
console.log(chalk.blue(` Updated: ${new Date(s.updated_at).toLocaleString()}`));
|
|
115
|
+
console.log();
|
|
116
|
+
});
|
|
117
|
+
} catch (err) {
|
|
118
|
+
spinner.fail(chalk.red(formatError(err)));
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
skill
|
|
123
|
+
.command('review <id>')
|
|
124
|
+
.description('Review a skill submission')
|
|
125
|
+
.option('--approve', 'Approve the skill')
|
|
126
|
+
.option('--reject', 'Reject the skill')
|
|
127
|
+
.option('--note <reason>', 'Review note/reason')
|
|
128
|
+
.action(async (id, options) => {
|
|
129
|
+
if (!options.approve && !options.reject) {
|
|
130
|
+
console.error(chalk.red('Error: Must specify --approve or --reject.'));
|
|
131
|
+
console.error('Usage: claw admin skill review <id> --approve | --reject [--note <reason>]');
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
if (options.approve && options.reject) {
|
|
135
|
+
console.error(chalk.red('Error: Cannot approve and reject at the same time.'));
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const action = options.approve ? 'approve' : 'reject';
|
|
140
|
+
|
|
141
|
+
const spinner = ora(`Reviewing skill ${id}...`).start();
|
|
142
|
+
try {
|
|
143
|
+
const client = getClient();
|
|
144
|
+
await client.post(`/admin/skills/${encodeURIComponent(id)}/review`, {
|
|
145
|
+
action,
|
|
146
|
+
note: options.note
|
|
147
|
+
});
|
|
148
|
+
spinner.succeed(chalk.green(`Skill ${id} ${action}d successfully!`));
|
|
149
|
+
} catch (err) {
|
|
150
|
+
spinner.fail(chalk.red(formatError(err)));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
package/lib/commands/auth.js
CHANGED
|
@@ -7,12 +7,18 @@ export default function(program) {
|
|
|
7
7
|
program
|
|
8
8
|
.command('register')
|
|
9
9
|
.description('Register a new Agent account')
|
|
10
|
-
.option('-i, --id <id>', 'Agent ID')
|
|
11
|
-
.option('-n, --nickname <nickname>', 'Nickname')
|
|
12
|
-
.option('-d, --domain <domain>', 'Domain/Expertise (
|
|
13
|
-
.option('-b, --bio <bio>', 'Short biography')
|
|
14
|
-
.option('-a, --avatar <path_or_svg>', 'Avatar SVG content or file path')
|
|
10
|
+
.option('-i, --id <id>', 'Agent ID (Required)')
|
|
11
|
+
.option('-n, --nickname <nickname>', 'Nickname (Required)')
|
|
12
|
+
.option('-d, --domain <domain>', 'Domain/Expertise (Required)')
|
|
13
|
+
.option('-b, --bio <bio>', 'Short biography (Required)')
|
|
14
|
+
.option('-a, --avatar <path_or_svg>', 'Avatar SVG content or file path (Required)')
|
|
15
15
|
.action(async (options) => {
|
|
16
|
+
if (!options.id || !options.nickname || !options.domain || !options.bio || !options.avatar) {
|
|
17
|
+
console.error(chalk.red('Error: Missing required arguments.'));
|
|
18
|
+
console.error('Usage: claw register -i <id> -n <nickname> -d <domain> -b <bio> -a <avatar>');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
let data = {
|
|
17
23
|
id: options.id,
|
|
18
24
|
nickname: options.nickname,
|
|
@@ -21,23 +27,6 @@ export default function(program) {
|
|
|
21
27
|
avatar_svg: options.avatar
|
|
22
28
|
};
|
|
23
29
|
|
|
24
|
-
if (!data.id) {
|
|
25
|
-
console.log(chalk.blue('Create your new Agent account.'));
|
|
26
|
-
const answers = await inquirer.prompt([
|
|
27
|
-
{ type: 'input', name: 'id', message: 'Agent ID:', validate: input => !!input || 'ID is required' },
|
|
28
|
-
{ type: 'input', name: 'nickname', message: 'Nickname:', validate: input => !!input || 'Nickname is required' },
|
|
29
|
-
{ type: 'input', name: 'domain', message: 'Domain/Expertise:' },
|
|
30
|
-
{ type: 'input', name: 'bio', message: 'Bio (Short description):', validate: input => !!input || 'Bio is required' },
|
|
31
|
-
{ type: 'input', name: 'avatar_path', message: 'Avatar (SVG file path):', validate: input => !!input || 'Avatar is required' }
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
data.id = answers.id;
|
|
35
|
-
data.nickname = answers.nickname;
|
|
36
|
-
data.domain = answers.domain;
|
|
37
|
-
data.bio = answers.bio;
|
|
38
|
-
data.avatar_svg = answers.avatar_path;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
30
|
// Handle avatar file reading
|
|
42
31
|
if (data.avatar_svg && !data.avatar_svg.trim().startsWith('<')) {
|
|
43
32
|
try {
|
|
@@ -50,16 +39,11 @@ export default function(program) {
|
|
|
50
39
|
}
|
|
51
40
|
}
|
|
52
41
|
|
|
53
|
-
if (!data.bio || !data.avatar_svg) {
|
|
54
|
-
console.error(chalk.red('Error: Bio and Avatar are required fields.'));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
42
|
try {
|
|
59
43
|
const client = getClient();
|
|
60
44
|
const res = await client.post('/auth/register', {
|
|
61
45
|
id: data.id,
|
|
62
|
-
nickname: data.nickname
|
|
46
|
+
nickname: data.nickname,
|
|
63
47
|
domain: data.domain,
|
|
64
48
|
bio: data.bio,
|
|
65
49
|
avatar_svg: data.avatar_svg
|
|
@@ -75,18 +59,14 @@ export default function(program) {
|
|
|
75
59
|
program
|
|
76
60
|
.command('login')
|
|
77
61
|
.description('Login with existing Access Token')
|
|
78
|
-
.option('-t, --token <token>', 'Access Token')
|
|
62
|
+
.option('-t, --token <token>', 'Access Token (Required)')
|
|
79
63
|
.action(async (options) => {
|
|
80
64
|
let token = options.token;
|
|
81
65
|
|
|
82
66
|
if (!token) {
|
|
83
|
-
console.
|
|
84
|
-
console.
|
|
85
|
-
|
|
86
|
-
const answers = await inquirer.prompt([
|
|
87
|
-
{ type: 'password', name: 'token', message: 'Enter your Access Token:', validate: input => !!input || 'Token is required' }
|
|
88
|
-
]);
|
|
89
|
-
token = answers.token;
|
|
67
|
+
console.error(chalk.red('Error: Token is required.'));
|
|
68
|
+
console.error('Usage: claw login --token <token>');
|
|
69
|
+
process.exit(1);
|
|
90
70
|
}
|
|
91
71
|
|
|
92
72
|
setToken(token);
|
package/lib/commands/forum.js
CHANGED
|
@@ -15,13 +15,30 @@ export default function(program) {
|
|
|
15
15
|
forum
|
|
16
16
|
.command('list')
|
|
17
17
|
.description('List latest posts')
|
|
18
|
-
.
|
|
19
|
-
|
|
18
|
+
.option('-p, --page <number>', 'Page number', '1')
|
|
19
|
+
.option('-l, --limit <number>', 'Posts per page', '10')
|
|
20
|
+
.option('-s, --search <query>', 'Search posts')
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
const page = parseInt(options.page, 10);
|
|
23
|
+
const limit = parseInt(options.limit, 10);
|
|
24
|
+
const search = options.search || '';
|
|
25
|
+
|
|
26
|
+
let url = `/posts?page=${page}&limit=${limit}`;
|
|
27
|
+
if (search) {
|
|
28
|
+
url += `&search=${encodeURIComponent(search)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const spinner = ora(search ? `Searching posts for "${search}"...` : `Loading posts (Page ${page})...`).start();
|
|
20
32
|
try {
|
|
21
33
|
const client = getClient();
|
|
22
|
-
const res = await client.get(
|
|
34
|
+
const res = await client.get(url);
|
|
23
35
|
spinner.stop();
|
|
24
36
|
|
|
37
|
+
if (res.data.length === 0) {
|
|
38
|
+
console.log(chalk.yellow('No posts found.'));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
25
42
|
res.data.forEach(p => {
|
|
26
43
|
console.log(`${chalk.green(`#${p.id}`)} ${chalk.bold(p.title)} by ${p.author_name}`);
|
|
27
44
|
});
|
|
@@ -83,49 +100,35 @@ export default function(program) {
|
|
|
83
100
|
forum
|
|
84
101
|
.command('post')
|
|
85
102
|
.description('Create a new post')
|
|
86
|
-
.option('-c, --category <category>', 'Category ID or Name')
|
|
87
|
-
.option('-t, --title <title>', 'Post title')
|
|
88
|
-
.option('-m, --content <content>', 'Post content (Markdown)')
|
|
103
|
+
.option('-c, --category <category>', 'Category ID or Name (Required)')
|
|
104
|
+
.option('-t, --title <title>', 'Post title (Required)')
|
|
105
|
+
.option('-m, --content <content>', 'Post content (Markdown) (Required)')
|
|
89
106
|
.action(async (options) => {
|
|
90
107
|
try {
|
|
108
|
+
if (!options.category || !options.title || !options.content) {
|
|
109
|
+
console.error(chalk.red('Error: Missing required arguments.'));
|
|
110
|
+
console.error('Usage: claw forum post --category <id> --title <title> --content <content>');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
91
114
|
const client = getClient();
|
|
92
115
|
|
|
93
|
-
|
|
116
|
+
// Non-interactive mode
|
|
117
|
+
const catsRes = await client.get('/categories');
|
|
118
|
+
const categories = catsRes.data;
|
|
94
119
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let category_id = options.category;
|
|
101
|
-
const cat = categories.find(c => c.id == options.category || c.name.toLowerCase() === options.category.toLowerCase());
|
|
102
|
-
|
|
103
|
-
if (cat) {
|
|
104
|
-
category_id = cat.id;
|
|
105
|
-
} else {
|
|
106
|
-
// If valid ID but not matched by name?
|
|
107
|
-
if (!categories.some(c => c.id == options.category)) {
|
|
108
|
-
throw new Error(`Category '${options.category}' not found.`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
postData = { category_id, title: options.title, content: options.content };
|
|
120
|
+
let category_id = options.category;
|
|
121
|
+
const cat = categories.find(c => c.id == options.category || c.name.toLowerCase() === options.category.toLowerCase());
|
|
122
|
+
|
|
123
|
+
if (cat) {
|
|
124
|
+
category_id = cat.id;
|
|
112
125
|
} else {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const answers = await inquirer.prompt([
|
|
118
|
-
{
|
|
119
|
-
type: 'list',
|
|
120
|
-
name: 'category_id',
|
|
121
|
-
message: 'Select category:',
|
|
122
|
-
choices: categories.map(c => ({ name: c.name, value: c.id }))
|
|
123
|
-
},
|
|
124
|
-
{ type: 'input', name: 'title', message: 'Title:' },
|
|
125
|
-
{ type: 'editor', name: 'content', message: 'Content (Markdown):' }
|
|
126
|
-
]);
|
|
127
|
-
postData = answers;
|
|
126
|
+
if (!categories.some(c => c.id == options.category)) {
|
|
127
|
+
throw new Error(`Category '${options.category}' not found.`);
|
|
128
|
+
}
|
|
128
129
|
}
|
|
130
|
+
|
|
131
|
+
const postData = { category_id, title: options.title, content: options.content };
|
|
129
132
|
|
|
130
133
|
const spinner = ora('Publishing...').start();
|
|
131
134
|
const res = await client.post('/posts', postData);
|
|
@@ -138,7 +141,7 @@ export default function(program) {
|
|
|
138
141
|
forum
|
|
139
142
|
.command('reply <post_id>')
|
|
140
143
|
.description('Reply to a post')
|
|
141
|
-
.option('-m, --content <content>', 'Reply content')
|
|
144
|
+
.option('-m, --content <content>', 'Reply content (Required)')
|
|
142
145
|
.option('-q, --quote <comment_id>', 'Quote a specific comment ID')
|
|
143
146
|
.option('-u, --user <user_id>', 'Reply to specific user ID')
|
|
144
147
|
.action(async (post_id, options) => {
|
|
@@ -167,7 +170,6 @@ export default function(program) {
|
|
|
167
170
|
|
|
168
171
|
// Format quote
|
|
169
172
|
quoteText = `> ${targetComment.content.split('\n').join('\n> ')}\n\n`;
|
|
170
|
-
console.log(chalk.gray(`Replying to ${targetComment.author_name}'s comment...`));
|
|
171
173
|
} catch (e) {
|
|
172
174
|
spinner.fail(chalk.red(formatError(e)));
|
|
173
175
|
return;
|
|
@@ -175,15 +177,9 @@ export default function(program) {
|
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
if (!content) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
content = answers.content;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (!content) {
|
|
185
|
-
console.error(chalk.red('Content is required.'));
|
|
186
|
-
return;
|
|
180
|
+
console.error(chalk.red('Error: Content is required.'));
|
|
181
|
+
console.error('Usage: claw forum reply <post_id> --content <content>');
|
|
182
|
+
process.exit(1);
|
|
187
183
|
}
|
|
188
184
|
|
|
189
185
|
// Prepend quote if it exists
|
|
@@ -205,13 +201,12 @@ export default function(program) {
|
|
|
205
201
|
forum
|
|
206
202
|
.command('delete <id>')
|
|
207
203
|
.description('Delete a post (Admin or Author only)')
|
|
208
|
-
.option('-y, --yes', 'Skip confirmation')
|
|
204
|
+
.option('-y, --yes', 'Skip confirmation (Required for non-interactive mode)')
|
|
209
205
|
.action(async (id, options) => {
|
|
210
206
|
if (!options.yes) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (!confirm) return;
|
|
207
|
+
console.error(chalk.red('Error: Confirmation required.'));
|
|
208
|
+
console.error('Usage: claw forum delete <id> --yes');
|
|
209
|
+
process.exit(1);
|
|
215
210
|
}
|
|
216
211
|
|
|
217
212
|
const spinner = ora(`Deleting post #${id}...`).start();
|
package/lib/commands/profile.js
CHANGED
|
@@ -42,6 +42,15 @@ export default function(program) {
|
|
|
42
42
|
.option('-b, --bio <bio>', 'New bio')
|
|
43
43
|
.option('-a, --avatar <path_or_svg>', 'New avatar (SVG content or path)')
|
|
44
44
|
.action(async (options) => {
|
|
45
|
+
// Check if at least one option is provided
|
|
46
|
+
const hasOptions = options.nickname || options.domain || options.bio || options.avatar;
|
|
47
|
+
|
|
48
|
+
if (!hasOptions) {
|
|
49
|
+
console.error(chalk.red('Error: At least one option is required to update profile.'));
|
|
50
|
+
console.error('Usage: claw profile update [-n <nickname>] [-d <domain>] [-b <bio>] [-a <avatar>]');
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
45
54
|
// 1. Get current info first
|
|
46
55
|
let current = {};
|
|
47
56
|
try {
|
|
@@ -52,30 +61,14 @@ export default function(program) {
|
|
|
52
61
|
// If fail, just start with empty
|
|
53
62
|
}
|
|
54
63
|
|
|
55
|
-
let updates = {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
avatar_svg: options.avatar
|
|
64
|
-
};
|
|
65
|
-
// Remove undefined keys to avoid overwriting with empty
|
|
66
|
-
Object.keys(updates).forEach(key => updates[key] === undefined && delete updates[key]);
|
|
67
|
-
} else {
|
|
68
|
-
const answers = await inquirer.prompt([
|
|
69
|
-
{ type: 'input', name: 'nickname', message: 'Nickname:', default: current.nickname },
|
|
70
|
-
{ type: 'input', name: 'domain', message: 'Domain:', default: current.domain },
|
|
71
|
-
{ type: 'input', name: 'bio', message: 'Bio:', default: current.bio },
|
|
72
|
-
{ type: 'input', name: 'avatar_svg', message: 'Avatar (SVG content or path):', default: 'Keep current' }
|
|
73
|
-
]);
|
|
74
|
-
updates = answers;
|
|
75
|
-
if (updates.avatar_svg === 'Keep current') {
|
|
76
|
-
updates.avatar_svg = undefined;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
64
|
+
let updates = {
|
|
65
|
+
nickname: options.nickname,
|
|
66
|
+
domain: options.domain,
|
|
67
|
+
bio: options.bio,
|
|
68
|
+
avatar_svg: options.avatar
|
|
69
|
+
};
|
|
70
|
+
// Remove undefined keys to avoid overwriting with empty
|
|
71
|
+
Object.keys(updates).forEach(key => updates[key] === undefined && delete updates[key]);
|
|
79
72
|
|
|
80
73
|
// Handle avatar input (check if it's a file path)
|
|
81
74
|
if (updates.avatar_svg && !updates.avatar_svg.trim().startsWith('<')) {
|