@workclaw/openclaw-workclaw 1.0.13 → 1.0.16
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 +4 -5
- package/src/gateway/message-context.ts +422 -422
- package/src/gateway/message-dispatcher.ts +2 -2
- package/src/gateway/skills-handler.ts +126 -80
- package/src/gateway/skills-list-handler.ts +332 -332
- package/src/gateway/workclaw-gateway.ts +5 -1
- package/src/tools/openclaw-workclaw-cron/api/index.ts +326 -326
- package/src/tools/openclaw-workclaw-system/index.ts +17 -17
- package/src/tools/openclaw-workclaw-system/src/get/index.ts +77 -77
- package/src/tools/openclaw-workclaw-system/src/token/index.ts +93 -93
|
@@ -134,7 +134,7 @@ async function handleAgentEvent(
|
|
|
134
134
|
|
|
135
135
|
async function handleSkillsProcessingEvent(ctx: MessageDispatcherContext, result: ParseWorkClawResult): Promise<void> {
|
|
136
136
|
const { accountId, baseConfig, log } = ctx
|
|
137
|
-
if (!result.
|
|
137
|
+
if (!result.eventData)
|
|
138
138
|
return
|
|
139
139
|
try {
|
|
140
140
|
const { handleSkillsEvent } = await import('./skills-handler.js')
|
|
@@ -149,7 +149,7 @@ async function handleSkillsProcessingEvent(ctx: MessageDispatcherContext, result
|
|
|
149
149
|
}
|
|
150
150
|
const tokenCacheKey = baseConfig.appKey || accountId
|
|
151
151
|
const token = await getOpenclawWorkclawAccessToken(tokenCacheKey, connConfig)
|
|
152
|
-
await handleSkillsEvent(result.
|
|
152
|
+
await handleSkillsEvent(result.eventData, token, connConfig.baseUrl, connConfig.appKey || accountId, log)
|
|
153
153
|
}
|
|
154
154
|
catch (err) {
|
|
155
155
|
logError(log, 'handleSkillsEvent failed', err)
|
|
@@ -231,7 +231,7 @@ async function sendCallback(
|
|
|
231
231
|
/**
|
|
232
232
|
* 从 URL 下载文件内容
|
|
233
233
|
*/
|
|
234
|
-
async function downloadFromUrl(url: string
|
|
234
|
+
async function downloadFromUrl(url: string): Promise<Buffer> {
|
|
235
235
|
return new Promise((resolve, reject) => {
|
|
236
236
|
const client = url.startsWith('https:') ? https : http
|
|
237
237
|
|
|
@@ -275,11 +275,11 @@ function getOpenClawConfigDir(): string {
|
|
|
275
275
|
*/
|
|
276
276
|
async function getSkillsDir(agentId?: string, log?: any): Promise<string> {
|
|
277
277
|
const openclawDir = getOpenClawConfigDir()
|
|
278
|
-
let skillsDir = path.join(openclawDir, 'skills')
|
|
278
|
+
let skillsDir = path.join(openclawDir, 'workspace', 'skills')
|
|
279
279
|
|
|
280
280
|
// 如果有 agentId,添加到对应目录
|
|
281
281
|
if (agentId && agentId.trim()) {
|
|
282
|
-
skillsDir = path.join(openclawDir,
|
|
282
|
+
skillsDir = path.join(openclawDir, `workspace-${agentId}`, 'skills')
|
|
283
283
|
}
|
|
284
284
|
|
|
285
285
|
try {
|
|
@@ -410,6 +410,22 @@ async function installSkillToClaw(
|
|
|
410
410
|
/**
|
|
411
411
|
* 创建 Skill
|
|
412
412
|
*/
|
|
413
|
+
async function installSkillToLocations(skillName: string, skillContent: Buffer, locations: (string | undefined)[], log?: any): Promise<any[]> {
|
|
414
|
+
const installResults = []
|
|
415
|
+
|
|
416
|
+
for (const agentId of locations) {
|
|
417
|
+
const installResult = await installSkillToClaw(skillName, skillContent, agentId, log)
|
|
418
|
+
if (!installResult.success) {
|
|
419
|
+
const error: any = new Error(`Failed to install skill to ${agentId ? `agent ${agentId}` : 'default location'}: ${installResult.message}`)
|
|
420
|
+
error.code = 'INSTALL_FAILED'
|
|
421
|
+
throw error
|
|
422
|
+
}
|
|
423
|
+
installResults.push(installResult)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return installResults
|
|
427
|
+
}
|
|
428
|
+
|
|
413
429
|
async function handleCreateSkill(
|
|
414
430
|
data: any,
|
|
415
431
|
log?: {
|
|
@@ -417,7 +433,7 @@ async function handleCreateSkill(
|
|
|
417
433
|
error?: (msg: string) => void
|
|
418
434
|
},
|
|
419
435
|
): Promise<any> {
|
|
420
|
-
const { userId, skillName, unloadUrl } = data
|
|
436
|
+
const { userId, skillName, unloadUrl, mainId } = data
|
|
421
437
|
const agentIds = Array.isArray(data?.agentIds) ? data.agentIds : (data?.agentIds ? [data.agentIds] : [])
|
|
422
438
|
|
|
423
439
|
if (!userId || !skillName) {
|
|
@@ -427,6 +443,7 @@ async function handleCreateSkill(
|
|
|
427
443
|
}
|
|
428
444
|
|
|
429
445
|
log?.info?.(`[SkillsHandler] Creating skill: ${skillName}`)
|
|
446
|
+
log?.info?.(`[SkillsHandler] mainId: ${mainId}`)
|
|
430
447
|
if (agentIds.length > 0) {
|
|
431
448
|
log?.info?.(`[SkillsHandler] Target agents: ${agentIds.join(', ')}`)
|
|
432
449
|
}
|
|
@@ -437,31 +454,42 @@ async function handleCreateSkill(
|
|
|
437
454
|
|
|
438
455
|
try {
|
|
439
456
|
// 下载 skill 定义
|
|
440
|
-
const skillContent = await downloadFromUrl(unloadUrl
|
|
457
|
+
const skillContent = await downloadFromUrl(unloadUrl)
|
|
441
458
|
log?.info?.(`[SkillsHandler] Downloaded skill content, length: ${skillContent.length} bytes`)
|
|
442
459
|
|
|
443
|
-
//
|
|
444
|
-
const
|
|
445
|
-
for (const agentId of agentIds) {
|
|
446
|
-
const installResult = await installSkillToClaw(skillName, skillContent, agentId, log)
|
|
447
|
-
if (!installResult.success) {
|
|
448
|
-
const error: any = new Error(`Failed to install skill to agent ${agentId}: ${installResult.message}`)
|
|
449
|
-
error.code = 'INSTALL_FAILED'
|
|
450
|
-
throw error
|
|
451
|
-
}
|
|
452
|
-
installResults.push(installResult)
|
|
453
|
-
}
|
|
460
|
+
// 确定安装位置
|
|
461
|
+
const installLocations: (string | undefined)[] = []
|
|
454
462
|
|
|
455
|
-
//
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
463
|
+
// 检查 agentIds 是否只包含 mainId
|
|
464
|
+
const hasOnlyMainId = agentIds.length === 1 && agentIds[0] === mainId
|
|
465
|
+
// 检查 agentIds 是否包含 mainId 和其他 id
|
|
466
|
+
const hasMainIdAndOthers = agentIds.includes(mainId) && agentIds.length > 1
|
|
467
|
+
|
|
468
|
+
if (hasOnlyMainId) {
|
|
469
|
+
// 如果只有 mainId,安装到默认位置
|
|
470
|
+
log?.info?.(`[SkillsHandler] Only mainId found, installing to default location`)
|
|
471
|
+
installLocations.push(undefined)
|
|
472
|
+
}
|
|
473
|
+
else if (hasMainIdAndOthers) {
|
|
474
|
+
// 如果有 mainId 和其他 id,安装到默认位置和其他 id 位置
|
|
475
|
+
log?.info?.(`[SkillsHandler] mainId and other agents found, installing to default location and other agents`)
|
|
476
|
+
installLocations.push(undefined)
|
|
477
|
+
// 添加其他 id 位置(排除 mainId)
|
|
478
|
+
installLocations.push(...agentIds.filter((id: any) => id !== mainId))
|
|
464
479
|
}
|
|
480
|
+
else if (agentIds.length > 0) {
|
|
481
|
+
// 如果没有 mainId,安装到所有指定的 agentId 位置
|
|
482
|
+
log?.info?.(`[SkillsHandler] No mainId found, installing to all specified agents`)
|
|
483
|
+
installLocations.push(...agentIds)
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
// 如果没有指定智能体,安装到默认位置
|
|
487
|
+
log?.info?.(`[SkillsHandler] No agents specified, installing to default location`)
|
|
488
|
+
installLocations.push(undefined)
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// 安装技能到所有位置
|
|
492
|
+
const installResults = await installSkillToLocations(skillName, skillContent, installLocations, log)
|
|
465
493
|
|
|
466
494
|
log?.info?.(`[SkillsHandler] Skill installed to ${installResults.length} locations`)
|
|
467
495
|
|
|
@@ -521,6 +549,43 @@ async function handleUpdateSkill(
|
|
|
521
549
|
/**
|
|
522
550
|
* 删除 Skill
|
|
523
551
|
*/
|
|
552
|
+
async function deleteSkillAtLocation(skillName: string, agentId: string | undefined, log?: any): Promise<boolean> {
|
|
553
|
+
try {
|
|
554
|
+
const skillsDir = await getSkillsDir(agentId, log)
|
|
555
|
+
|
|
556
|
+
const skillFilePath = path.join(skillsDir, `${skillName}.json`)
|
|
557
|
+
const skillDirPath = path.join(skillsDir, skillName)
|
|
558
|
+
|
|
559
|
+
let deleted = false
|
|
560
|
+
|
|
561
|
+
// 尝试删除技能文件
|
|
562
|
+
try {
|
|
563
|
+
await fs.unlink(skillFilePath)
|
|
564
|
+
log?.info?.(`[SkillsHandler] Skill file deleted: ${skillFilePath}`)
|
|
565
|
+
deleted = true
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
// 文件不存在,继续尝试删除目录
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// 尝试删除技能目录(ZIP 安装的技能)
|
|
572
|
+
try {
|
|
573
|
+
await fs.rm(skillDirPath, { recursive: true, force: true })
|
|
574
|
+
log?.info?.(`[SkillsHandler] Skill directory deleted: ${skillDirPath}`)
|
|
575
|
+
deleted = true
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
// 目录不存在,继续
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return deleted
|
|
582
|
+
}
|
|
583
|
+
catch (err: any) {
|
|
584
|
+
log?.error?.(`[SkillsHandler] Failed to delete skill at location: ${err.message}`)
|
|
585
|
+
return false
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
524
589
|
async function handleDeleteSkill(
|
|
525
590
|
data: any,
|
|
526
591
|
log?: {
|
|
@@ -528,7 +593,7 @@ async function handleDeleteSkill(
|
|
|
528
593
|
error?: (msg: string) => void
|
|
529
594
|
},
|
|
530
595
|
): Promise<any> {
|
|
531
|
-
const { userId, skillName, agentIds } = data
|
|
596
|
+
const { userId, skillName, agentIds, mainId } = data
|
|
532
597
|
const agentIdsList = Array.isArray(agentIds) ? agentIds : (agentIds ? [agentIds] : [])
|
|
533
598
|
|
|
534
599
|
if (!skillName) {
|
|
@@ -538,6 +603,7 @@ async function handleDeleteSkill(
|
|
|
538
603
|
}
|
|
539
604
|
|
|
540
605
|
log?.info?.(`[SkillsHandler] Deleting skill: ${skillName}`)
|
|
606
|
+
log?.info?.(`[SkillsHandler] mainId: ${mainId}`)
|
|
541
607
|
if (agentIdsList.length > 0) {
|
|
542
608
|
log?.info?.(`[SkillsHandler] Target agents: ${agentIdsList.join(', ')}`)
|
|
543
609
|
}
|
|
@@ -545,65 +611,45 @@ async function handleDeleteSkill(
|
|
|
545
611
|
try {
|
|
546
612
|
let deleted = false
|
|
547
613
|
|
|
548
|
-
//
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
// 检查技能文件和目录
|
|
554
|
-
const skillFilePath = path.join(skillsDir, `${skillName}.json`)
|
|
555
|
-
const skillDirPath = path.join(skillsDir, skillName)
|
|
556
|
-
|
|
557
|
-
// 尝试删除技能文件
|
|
558
|
-
try {
|
|
559
|
-
await fs.unlink(skillFilePath)
|
|
560
|
-
log?.info?.(`[SkillsHandler] Skill file deleted: ${skillFilePath}`)
|
|
561
|
-
deleted = true
|
|
562
|
-
}
|
|
563
|
-
catch {
|
|
564
|
-
// 文件不存在,继续尝试删除目录
|
|
565
|
-
}
|
|
614
|
+
// 检查 agentIds 是否只包含 mainId
|
|
615
|
+
const hasOnlyMainId = agentIdsList.length === 1 && agentIdsList[0] === mainId
|
|
616
|
+
// 检查 agentIds 是否包含 mainId 和其他 id
|
|
617
|
+
const hasMainIdAndOthers = agentIdsList.includes(mainId) && agentIdsList.length > 1
|
|
566
618
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
deleted = true
|
|
572
|
-
}
|
|
573
|
-
catch {
|
|
574
|
-
// 目录不存在,继续
|
|
575
|
-
}
|
|
619
|
+
if (hasOnlyMainId) {
|
|
620
|
+
// 如果只有 mainId,从默认位置删除
|
|
621
|
+
log?.info?.(`[SkillsHandler] Only mainId found, deleting from default location`)
|
|
622
|
+
deleted = await deleteSkillAtLocation(skillName, undefined, log)
|
|
576
623
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
deleted = true
|
|
592
|
-
}
|
|
593
|
-
catch {
|
|
594
|
-
// 文件不存在,继续尝试删除目录
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// 尝试删除技能目录(ZIP 安装的技能)
|
|
598
|
-
try {
|
|
599
|
-
await fs.rm(skillDirPath, { recursive: true, force: true })
|
|
600
|
-
log?.info?.(`[SkillsHandler] Skill directory deleted: ${skillDirPath}`)
|
|
601
|
-
deleted = true
|
|
624
|
+
else if (hasMainIdAndOthers) {
|
|
625
|
+
// 如果有 mainId 和其他 id,从默认位置和其他 id 位置删除
|
|
626
|
+
log?.info?.(`[SkillsHandler] mainId and other agents found, deleting from default location and other agents`)
|
|
627
|
+
|
|
628
|
+
// 从默认位置删除
|
|
629
|
+
const defaultDeleted = await deleteSkillAtLocation(skillName, undefined, log)
|
|
630
|
+
deleted = deleted || defaultDeleted
|
|
631
|
+
|
|
632
|
+
// 从其他 id 位置删除(排除 mainId)
|
|
633
|
+
for (const agentId of agentIdsList) {
|
|
634
|
+
if (agentId !== mainId) {
|
|
635
|
+
const agentDeleted = await deleteSkillAtLocation(skillName, agentId, log)
|
|
636
|
+
deleted = deleted || agentDeleted
|
|
637
|
+
}
|
|
602
638
|
}
|
|
603
|
-
|
|
604
|
-
|
|
639
|
+
}
|
|
640
|
+
else if (agentIdsList.length > 0) {
|
|
641
|
+
// 如果没有 mainId,从所有指定的 agentId 位置删除
|
|
642
|
+
log?.info?.(`[SkillsHandler] No mainId found, deleting from all specified agents`)
|
|
643
|
+
for (const agentId of agentIdsList) {
|
|
644
|
+
const agentDeleted = await deleteSkillAtLocation(skillName, agentId, log)
|
|
645
|
+
deleted = deleted || agentDeleted
|
|
605
646
|
}
|
|
606
647
|
}
|
|
648
|
+
else {
|
|
649
|
+
// 如果没有指定智能体,从默认位置删除
|
|
650
|
+
log?.info?.(`[SkillsHandler] No agents specified, deleting from default location`)
|
|
651
|
+
deleted = await deleteSkillAtLocation(skillName, undefined, log)
|
|
652
|
+
}
|
|
607
653
|
|
|
608
654
|
if (!deleted) {
|
|
609
655
|
const error: any = new Error(`Skill not found: ${skillName}`)
|