@aptol/openclaw-persona 1.0.0 → 1.1.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/bin/create.mjs +139 -12
- package/package.json +1 -1
package/bin/create.mjs
CHANGED
|
@@ -51,6 +51,73 @@ const MODULE_MAP = {
|
|
|
51
51
|
'선제 대화 (Proactive Chat)': 'proactive-chat.md',
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
+
const DISCORD_POLICIES = {
|
|
55
|
+
'모든 서버에서 멘션(@봇) 시 반응 (추천, 설정 불필요)': 'mention',
|
|
56
|
+
'모든 서버에서 항상 반응': 'all',
|
|
57
|
+
'특정 서버/채널만 허용 (ID 직접 입력)': 'allowlist',
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
async function askServerChannels() {
|
|
61
|
+
const servers = [];
|
|
62
|
+
let addMore = true;
|
|
63
|
+
|
|
64
|
+
while (addMore) {
|
|
65
|
+
const { guildId } = await inquirer.prompt([{
|
|
66
|
+
type: 'input',
|
|
67
|
+
name: 'guildId',
|
|
68
|
+
message: '서버 ID:',
|
|
69
|
+
validate: (v) => /^\d+$/.test(v.trim()) ? true : '숫자만 입력해주세요.',
|
|
70
|
+
}]);
|
|
71
|
+
|
|
72
|
+
const { requireMention } = await inquirer.prompt([{
|
|
73
|
+
type: 'list',
|
|
74
|
+
name: 'requireMention',
|
|
75
|
+
message: `이 서버에서 멘션 필요?`,
|
|
76
|
+
choices: [
|
|
77
|
+
{ name: '아니오 — 모든 메시지에 반응', value: false },
|
|
78
|
+
{ name: '예 — 멘션(@봇)할 때만 반응', value: true },
|
|
79
|
+
],
|
|
80
|
+
}]);
|
|
81
|
+
|
|
82
|
+
const channels = [];
|
|
83
|
+
let addChannels = true;
|
|
84
|
+
|
|
85
|
+
while (addChannels) {
|
|
86
|
+
const { channelId } = await inquirer.prompt([{
|
|
87
|
+
type: 'input',
|
|
88
|
+
name: 'channelId',
|
|
89
|
+
message: '채널 ID (비워두면 서버 전체):',
|
|
90
|
+
default: '',
|
|
91
|
+
}]);
|
|
92
|
+
|
|
93
|
+
if (channelId.trim()) {
|
|
94
|
+
channels.push(channelId.trim());
|
|
95
|
+
const { more } = await inquirer.prompt([{
|
|
96
|
+
type: 'confirm',
|
|
97
|
+
name: 'more',
|
|
98
|
+
message: '채널 더 추가?',
|
|
99
|
+
default: false,
|
|
100
|
+
}]);
|
|
101
|
+
addChannels = more;
|
|
102
|
+
} else {
|
|
103
|
+
addChannels = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
servers.push({ guildId: guildId.trim(), requireMention, channels });
|
|
108
|
+
|
|
109
|
+
const { more } = await inquirer.prompt([{
|
|
110
|
+
type: 'confirm',
|
|
111
|
+
name: 'more',
|
|
112
|
+
message: '서버 더 추가?',
|
|
113
|
+
default: false,
|
|
114
|
+
}]);
|
|
115
|
+
addMore = more;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return servers;
|
|
119
|
+
}
|
|
120
|
+
|
|
54
121
|
async function main() {
|
|
55
122
|
console.log('\n🎭 OpenClaw Persona Creator\n');
|
|
56
123
|
console.log('나만의 AI 캐릭터를 만들어보세요!\n');
|
|
@@ -114,6 +181,24 @@ async function main() {
|
|
|
114
181
|
message: 'Discord 봇 토큰 (나중에 설정하려면 빈칸):',
|
|
115
182
|
default: '',
|
|
116
183
|
},
|
|
184
|
+
{
|
|
185
|
+
type: 'list',
|
|
186
|
+
name: 'discordPolicyKey',
|
|
187
|
+
message: '디스코드 서버 정책:',
|
|
188
|
+
choices: Object.keys(DISCORD_POLICIES),
|
|
189
|
+
},
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
const discordPolicy = DISCORD_POLICIES[answers.discordPolicyKey];
|
|
193
|
+
|
|
194
|
+
// If allowlist, ask for server/channel IDs
|
|
195
|
+
let serverConfigs = [];
|
|
196
|
+
if (discordPolicy === 'allowlist') {
|
|
197
|
+
console.log('\n📋 활동할 서버와 채널을 설정합니다.\n');
|
|
198
|
+
serverConfigs = await askServerChannels();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const answers2 = await inquirer.prompt([
|
|
117
202
|
{
|
|
118
203
|
type: 'list',
|
|
119
204
|
name: 'presetKey',
|
|
@@ -130,7 +215,7 @@ async function main() {
|
|
|
130
215
|
type: 'input',
|
|
131
216
|
name: 'outputDir',
|
|
132
217
|
message: '출력 디렉토리:',
|
|
133
|
-
default:
|
|
218
|
+
default: `./output/${answers.name.trim()}`,
|
|
134
219
|
},
|
|
135
220
|
]);
|
|
136
221
|
|
|
@@ -144,8 +229,8 @@ async function main() {
|
|
|
144
229
|
creator: answers.creator.trim(),
|
|
145
230
|
};
|
|
146
231
|
|
|
147
|
-
const preset = PRESET_NAMES[
|
|
148
|
-
const outputDir =
|
|
232
|
+
const preset = PRESET_NAMES[answers2.presetKey];
|
|
233
|
+
const outputDir = answers2.outputDir;
|
|
149
234
|
|
|
150
235
|
// Create output directories
|
|
151
236
|
mkdirSync(join(outputDir, 'memory'), { recursive: true });
|
|
@@ -153,7 +238,6 @@ async function main() {
|
|
|
153
238
|
|
|
154
239
|
// Generate files
|
|
155
240
|
if (preset) {
|
|
156
|
-
// Preset-based: copy preset files with variable replacement
|
|
157
241
|
const presetDir = join(ROOT, 'presets', preset);
|
|
158
242
|
const soulContent = replaceVars(readTemplate(join(presetDir, 'SOUL.md')), vars);
|
|
159
243
|
const agentsContent = readTemplate(join(presetDir, 'AGENTS.md'));
|
|
@@ -163,7 +247,6 @@ async function main() {
|
|
|
163
247
|
writeOutput(outputDir, 'AGENTS.md', agentsContent);
|
|
164
248
|
writeOutput(outputDir, 'IDENTITY.md', identityContent);
|
|
165
249
|
} else {
|
|
166
|
-
// From scratch: use templates
|
|
167
250
|
const soulContent = replaceVars(readTemplate(join(ROOT, 'templates', 'SOUL.template.md')), vars);
|
|
168
251
|
const agentsContent = readTemplate(join(ROOT, 'templates', 'AGENTS.template.md'));
|
|
169
252
|
const identityContent = replaceVars(readTemplate(join(ROOT, 'templates', 'IDENTITY.template.md')), vars);
|
|
@@ -183,7 +266,7 @@ async function main() {
|
|
|
183
266
|
|
|
184
267
|
// Copy selected modules
|
|
185
268
|
let hasProactiveChat = false;
|
|
186
|
-
for (const moduleKey of
|
|
269
|
+
for (const moduleKey of answers2.moduleKeys) {
|
|
187
270
|
const moduleFile = MODULE_MAP[moduleKey];
|
|
188
271
|
const src = join(ROOT, 'modules', moduleFile);
|
|
189
272
|
const dest = join(outputDir, 'modules', moduleFile);
|
|
@@ -224,21 +307,53 @@ async function main() {
|
|
|
224
307
|
`);
|
|
225
308
|
}
|
|
226
309
|
|
|
227
|
-
//
|
|
310
|
+
// Build openclaw config
|
|
228
311
|
const config = JSON.parse(readFileSync(join(ROOT, 'config', 'openclaw.template.json'), 'utf-8'));
|
|
229
312
|
config.agents.defaults.workspace = outputDir;
|
|
230
313
|
const discordId = answers.discordId.trim();
|
|
231
314
|
const discordToken = answers.discordToken.trim();
|
|
232
|
-
config.channels.discord.token = discordToken || '
|
|
315
|
+
config.channels.discord.token = discordToken || '';
|
|
233
316
|
config.channels.discord.dmPolicy = 'allowlist';
|
|
234
317
|
config.channels.discord.allowFrom = [discordId];
|
|
235
318
|
config.commands = { ownerAllowFrom: [discordId] };
|
|
319
|
+
|
|
320
|
+
// Discord server policy
|
|
321
|
+
if (discordPolicy === 'mention') {
|
|
322
|
+
config.channels.discord.groupPolicy = 'mention';
|
|
323
|
+
} else if (discordPolicy === 'all') {
|
|
324
|
+
config.channels.discord.groupPolicy = 'all';
|
|
325
|
+
} else {
|
|
326
|
+
// allowlist with specific servers/channels
|
|
327
|
+
config.channels.discord.groupPolicy = 'allowlist';
|
|
328
|
+
const guilds = {};
|
|
329
|
+
for (const server of serverConfigs) {
|
|
330
|
+
const guild = {
|
|
331
|
+
requireMention: server.requireMention,
|
|
332
|
+
channels: {},
|
|
333
|
+
};
|
|
334
|
+
if (server.channels.length > 0) {
|
|
335
|
+
for (const chId of server.channels) {
|
|
336
|
+
guild.channels[chId] = {
|
|
337
|
+
allow: true,
|
|
338
|
+
requireMention: server.requireMention,
|
|
339
|
+
enabled: true,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
// No specific channels = server-wide (empty channels object means all channels)
|
|
344
|
+
guild.channels = {};
|
|
345
|
+
}
|
|
346
|
+
guilds[server.guildId] = guild;
|
|
347
|
+
}
|
|
348
|
+
config.channels.discord.guilds = guilds;
|
|
349
|
+
}
|
|
350
|
+
|
|
236
351
|
writeOutput(outputDir, 'openclaw.json', JSON.stringify(config, null, 2) + '\n');
|
|
237
352
|
|
|
238
353
|
// Create empty .gitkeep in memory folder
|
|
239
354
|
writeFileSync(join(outputDir, 'memory', '.gitkeep'), '', 'utf-8');
|
|
240
355
|
|
|
241
|
-
console.log(`\n✅ ${vars.name} 생성
|
|
356
|
+
console.log(`\n✅ ${vars.name} 생성 완료!`);
|
|
242
357
|
console.log(`📁 위치: ${outputDir}`);
|
|
243
358
|
console.log('\n생성된 파일:');
|
|
244
359
|
console.log(' - SOUL.md (캐릭터 영혼)');
|
|
@@ -248,14 +363,26 @@ async function main() {
|
|
|
248
363
|
console.log(' - MEMORY.md (장기 기억)');
|
|
249
364
|
console.log(' - openclaw.json (설정)');
|
|
250
365
|
console.log(' - memory/ (일별 기억 폴더)');
|
|
251
|
-
if (
|
|
366
|
+
if (answers2.moduleKeys.length > 0) {
|
|
252
367
|
console.log(' - modules/ (선택한 시스템 모듈)');
|
|
253
368
|
}
|
|
254
|
-
|
|
369
|
+
|
|
370
|
+
console.log('\n🚀 구동 방법:');
|
|
371
|
+
if (discordPolicy === 'mention') {
|
|
372
|
+
console.log(' 서버 정책: 멘션(@봇) 시에만 반응');
|
|
373
|
+
} else if (discordPolicy === 'all') {
|
|
374
|
+
console.log(' 서버 정책: 모든 서버에서 항상 반응');
|
|
375
|
+
} else {
|
|
376
|
+
console.log(` 서버 정책: ${serverConfigs.length}개 서버 허용목록`);
|
|
377
|
+
}
|
|
378
|
+
console.log('');
|
|
255
379
|
console.log(' 1. openclaw.json에서 API 키와 Discord 토큰을 설정하세요');
|
|
256
380
|
console.log(' 2. USER.md에 주인 정보를 추가하세요');
|
|
257
381
|
console.log(' 3. SOUL.md를 원하는 대로 커스텀하세요');
|
|
258
|
-
console.log(' 4.
|
|
382
|
+
console.log(' 4. 구동:');
|
|
383
|
+
console.log(` $env:OPENCLAW_HOME = "${outputDir}"`);
|
|
384
|
+
console.log(' openclaw gateway run');
|
|
385
|
+
console.log('');
|
|
259
386
|
}
|
|
260
387
|
|
|
261
388
|
main().catch((err) => {
|
package/package.json
CHANGED