@aiyiran/myclaw 1.1.171 → 1.1.172
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/create_agent.js +65 -11
- package/index.js +37 -21
- package/package.json +1 -1
package/create_agent.js
CHANGED
|
@@ -55,11 +55,17 @@ function fail(msg, code = 1) {
|
|
|
55
55
|
* - 非法字符替换为连字符
|
|
56
56
|
* - 去除多余连字符
|
|
57
57
|
*/
|
|
58
|
+
// 与 OpenClaw 本体的 normalizeAgentId 逐字对齐(dist 里的实现):
|
|
59
|
+
// 允许 a-z 0-9 _ - ;连续非法字符压成一个 - ;去首尾 - ;不再压缩内部重复 -
|
|
60
|
+
// 故意不像旧版那样压 `-{2,}`,以保证「标准化后 === 原输入」这个判据
|
|
61
|
+
// 与 OpenClaw 真实落库结果一致,从而准确判断输入是否「天生满足」。
|
|
58
62
|
function normalizeAgentId(raw) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
return (raw == null ? '' : String(raw))
|
|
64
|
+
.trim()
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
67
|
+
.replace(/^-+/g, '')
|
|
68
|
+
.replace(/-+$/g, '');
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
/**
|
|
@@ -72,11 +78,47 @@ function validateAgentId(agentId) {
|
|
|
72
78
|
if (agentId.length > 64) {
|
|
73
79
|
fail('Agent ID 太长,请保持在 64 个字符以内。');
|
|
74
80
|
}
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
// 放宽到与 OpenClaw 一致:允许下划线,首尾必须是字母/数字
|
|
82
|
+
if (!/^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$/.test(agentId)) {
|
|
83
|
+
fail('Agent ID 只能包含小写字母、数字、连字符和下划线(不能以连字符/下划线开头或结尾)。');
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
|
|
87
|
+
// ── 中文/非法输入时的兜底 key 生成 ──────────────────────────────
|
|
88
|
+
// 格式:MMDD_<三个随机英文单词>_MMSS (北京时间),如 0630_brave-lunar-otter_1207
|
|
89
|
+
// 全小写 + 连字符 + 下划线,天然满足 validateAgentId;带日期/分秒 + 随机词,几乎不可能撞名。
|
|
90
|
+
const FALLBACK_WORDS = [
|
|
91
|
+
'brave', 'lunar', 'otter', 'maple', 'pixel', 'comet', 'river', 'ember',
|
|
92
|
+
'tiger', 'cloud', 'quartz', 'mango', 'panda', 'fox', 'willow', 'cedar',
|
|
93
|
+
'orbit', 'frost', 'sunny', 'cocoa', 'pearl', 'raven', 'lotus', 'noble',
|
|
94
|
+
'jade', 'amber', 'breeze', 'crisp', 'dawn', 'echo', 'flint', 'glow',
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
function pad2(n) { return String(n).padStart(2, '0'); }
|
|
98
|
+
|
|
99
|
+
function generateFallbackKey() {
|
|
100
|
+
// 北京时间(UTC+8),与 buildBirthMessage 保持一致
|
|
101
|
+
const bj = new Date(Date.now() + 8 * 60 * 60 * 1000);
|
|
102
|
+
const MMDD = pad2(bj.getUTCMonth() + 1) + pad2(bj.getUTCDate());
|
|
103
|
+
const MMSS = pad2(bj.getUTCMinutes()) + pad2(bj.getUTCSeconds());
|
|
104
|
+
const pick = () => FALLBACK_WORDS[Math.floor(Math.random() * FALLBACK_WORDS.length)];
|
|
105
|
+
const words = pick() + '-' + pick() + '-' + pick();
|
|
106
|
+
return MMDD + '_' + words + '_' + MMSS;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ── 命名决策:判断输入是否「天生满足」key 格式 ───────────────────
|
|
110
|
+
// 天生满足(标准化后与原输入完全一致)→ 直接用作 id,不另设显示名。
|
|
111
|
+
// 不满足(含中文/空格/大写等)→ 生成兜底 key,原始输入作为 identity.name(中文显示)。
|
|
112
|
+
function resolveAgentNaming(rawName) {
|
|
113
|
+
const trimmed = (rawName == null ? '' : String(rawName)).trim();
|
|
114
|
+
const normalized = normalizeAgentId(trimmed);
|
|
115
|
+
const isNative = !!normalized && normalized === trimmed;
|
|
116
|
+
if (isNative) {
|
|
117
|
+
return { agentId: normalized, displayName: null, isNative: true };
|
|
118
|
+
}
|
|
119
|
+
return { agentId: generateFallbackKey(), displayName: trimmed, isNative: false };
|
|
120
|
+
}
|
|
121
|
+
|
|
80
122
|
/**
|
|
81
123
|
* 生成北京时间出生消息
|
|
82
124
|
*/
|
|
@@ -138,8 +180,13 @@ function defaultWorkspaceFiles(agentId) {
|
|
|
138
180
|
*/
|
|
139
181
|
function createAgent(rawName, opts) {
|
|
140
182
|
opts = opts || {};
|
|
141
|
-
//
|
|
142
|
-
|
|
183
|
+
// 命名决策:优先用调用方(index.js)已解析好的结果,避免重复生成导致 id 漂移;
|
|
184
|
+
// 否则在此内部解析。
|
|
185
|
+
const naming = opts.agentId
|
|
186
|
+
? { agentId: opts.agentId, displayName: opts.displayName != null ? opts.displayName : null }
|
|
187
|
+
: resolveAgentNaming(rawName);
|
|
188
|
+
const agentId = naming.agentId;
|
|
189
|
+
const displayName = naming.displayName; // 非 null 时写入 identity.name(中文显示名)
|
|
143
190
|
validateAgentId(agentId);
|
|
144
191
|
|
|
145
192
|
// 确定 OpenClaw 配置目录
|
|
@@ -208,12 +255,18 @@ function createAgent(rawName, opts) {
|
|
|
208
255
|
fs.copyFileSync(configPath, backupPath);
|
|
209
256
|
|
|
210
257
|
// 添加 Agent 条目
|
|
211
|
-
|
|
258
|
+
// 顶层 name 保持 ascii id(OpenClaw 不拿它当 UI 显示名);
|
|
259
|
+
// 中文/非法输入时,把原始输入写进 identity.name —— 这才是 UI 真正显示的名字。
|
|
260
|
+
const entry = {
|
|
212
261
|
id: agentId,
|
|
213
262
|
name: agentId,
|
|
214
263
|
workspace: workspaceDir,
|
|
215
264
|
agentDir: agentDir,
|
|
216
|
-
}
|
|
265
|
+
};
|
|
266
|
+
if (displayName) {
|
|
267
|
+
entry.identity = { name: displayName };
|
|
268
|
+
}
|
|
269
|
+
configData.agents.list.push(entry);
|
|
217
270
|
|
|
218
271
|
// 写入配置
|
|
219
272
|
try {
|
|
@@ -242,6 +295,7 @@ function createAgent(rawName, opts) {
|
|
|
242
295
|
return {
|
|
243
296
|
ok: true,
|
|
244
297
|
agentId: agentId,
|
|
298
|
+
displayName: displayName,
|
|
245
299
|
sessionKey: 'agent:' + agentId + ':main',
|
|
246
300
|
workspace: normalizePath(workspaceDir),
|
|
247
301
|
agentDir: normalizePath(agentDir),
|
|
@@ -251,4 +305,4 @@ function createAgent(rawName, opts) {
|
|
|
251
305
|
};
|
|
252
306
|
}
|
|
253
307
|
|
|
254
|
-
module.exports = { createAgent, normalizeAgentId, validateAgentId };
|
|
308
|
+
module.exports = { createAgent, normalizeAgentId, validateAgentId, resolveAgentNaming, generateFallbackKey };
|
package/index.js
CHANGED
|
@@ -335,7 +335,7 @@ function runNew() {
|
|
|
335
335
|
|
|
336
336
|
function askName() {
|
|
337
337
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
338
|
-
rl.question(B + '请输入 Agent
|
|
338
|
+
rl.question(B + '请输入 Agent 名字(中文 / 英文均可): ' + NC, function (answer) {
|
|
339
339
|
rl.close();
|
|
340
340
|
const name = (answer || '').trim();
|
|
341
341
|
if (!name) {
|
|
@@ -343,30 +343,27 @@ function runNew() {
|
|
|
343
343
|
askName();
|
|
344
344
|
return;
|
|
345
345
|
}
|
|
346
|
-
// 预检:必须包含英文字母或数字
|
|
347
|
-
if (!/[a-zA-Z0-9]/.test(name)) {
|
|
348
|
-
console.log(R + '名字必须包含英文或数字,请重新输入(如 my-agent)。' + NC);
|
|
349
|
-
askName();
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
346
|
doCreate(name);
|
|
353
347
|
});
|
|
354
348
|
}
|
|
355
349
|
|
|
356
350
|
function doCreate(input) {
|
|
357
|
-
const {
|
|
351
|
+
const { resolveAgentNaming } = require('./create_agent');
|
|
352
|
+
|
|
353
|
+
// 命名决策:天生满足 key 格式 → 直接用作 id;否则生成 ascii key + 中文显示名
|
|
354
|
+
var naming = resolveAgentNaming(input);
|
|
355
|
+
var agentId = naming.agentId;
|
|
356
|
+
var displayName = naming.displayName;
|
|
358
357
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
if (!agentId || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agentId)) {
|
|
362
|
-
console.log(R + '名字必须是英文、数字或连字符(如 my-agent),请重新输入。' + NC);
|
|
358
|
+
if (!agentId) {
|
|
359
|
+
console.log(R + '名字无效,请重新输入。' + NC);
|
|
363
360
|
console.log('');
|
|
364
361
|
if (rawName) { process.exit(1); return; }
|
|
365
362
|
askName();
|
|
366
363
|
return;
|
|
367
364
|
}
|
|
368
365
|
|
|
369
|
-
//
|
|
366
|
+
// 重名检查(不依赖 createAgent,避免它内部 process.exit)
|
|
370
367
|
const fs = require('fs');
|
|
371
368
|
const path = require('path');
|
|
372
369
|
const os = require('os');
|
|
@@ -375,23 +372,36 @@ function runNew() {
|
|
|
375
372
|
var configData = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
376
373
|
var list = (configData.agents && configData.agents.list) || [];
|
|
377
374
|
if (list.some(function (a) { return a && a.id === agentId; })) {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
375
|
+
if (naming.isNative) {
|
|
376
|
+
// 用户直接输入的 ascii 名撞了 → 友好提示并重试
|
|
377
|
+
console.log(R + 'Agent "' + agentId + '" 已存在,请换一个名字。' + NC);
|
|
378
|
+
console.log('');
|
|
379
|
+
if (rawName) { process.exit(1); return; }
|
|
380
|
+
askName();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// 生成的兜底 key 撞名(极罕见)→ 重新生成一次
|
|
384
|
+
naming = resolveAgentNaming(input);
|
|
385
|
+
agentId = naming.agentId;
|
|
386
|
+
displayName = naming.displayName;
|
|
383
387
|
}
|
|
384
388
|
} catch (e) {
|
|
385
389
|
// 配置文件读不到就算了,交给 createAgent 处理
|
|
386
390
|
}
|
|
387
391
|
|
|
388
392
|
// 校验通过,开始创建
|
|
389
|
-
|
|
393
|
+
if (displayName) {
|
|
394
|
+
console.log(Y + '正在创建 "' + displayName + '"(ID: ' + agentId + ')...' + NC);
|
|
395
|
+
} else {
|
|
396
|
+
console.log(Y + '正在创建 Agent "' + agentId + '"...' + NC);
|
|
397
|
+
}
|
|
390
398
|
console.log('');
|
|
391
399
|
|
|
392
400
|
var result;
|
|
393
401
|
try {
|
|
394
402
|
const createOpts = customFirstMessage ? { firstMessage: customFirstMessage } : {};
|
|
403
|
+
createOpts.agentId = agentId;
|
|
404
|
+
createOpts.displayName = displayName;
|
|
395
405
|
result = require('./create_agent').createAgent(input, createOpts);
|
|
396
406
|
} catch (err) {
|
|
397
407
|
console.log(R + '创建失败: ' + err.message + NC);
|
|
@@ -399,9 +409,15 @@ function runNew() {
|
|
|
399
409
|
}
|
|
400
410
|
|
|
401
411
|
// 打印结果
|
|
402
|
-
|
|
412
|
+
var shownName = displayName ? (displayName + '(' + agentId + ')') : agentId;
|
|
413
|
+
console.log(G + '✅' + NC + ' Agent "' + shownName + '" 创建完成');
|
|
403
414
|
console.log('');
|
|
404
|
-
|
|
415
|
+
if (displayName) {
|
|
416
|
+
console.log(' ' + G + '✅' + NC + ' 显示名 ' + displayName);
|
|
417
|
+
console.log(' ' + G + '✅' + NC + ' 生成 ID ' + agentId);
|
|
418
|
+
} else {
|
|
419
|
+
console.log(' ' + G + '✅' + NC + ' 名称标准化 ' + agentId);
|
|
420
|
+
}
|
|
405
421
|
console.log(' ' + G + '✅' + NC + ' 环境检查 无冲突');
|
|
406
422
|
console.log(' ' + G + '✅' + NC + ' 创建工作空间 已就绪');
|
|
407
423
|
console.log(' ' + G + '✅' + NC + ' 注册配置 已写入');
|