@workclaw/openclaw-workclaw 1.0.13 → 1.0.15

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.
@@ -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.skillsEvent)
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.skillsEvent, token, connConfig.baseUrl, connConfig.appKey || accountId, log)
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, _log?: any): Promise<Buffer> {
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, 'agents', `openclaw-workclaw-${agentId}`, 'skills')
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, log)
457
+ const skillContent = await downloadFromUrl(unloadUrl)
441
458
  log?.info?.(`[SkillsHandler] Downloaded skill content, length: ${skillContent.length} bytes`)
442
459
 
443
- // 安装 skill 到多个智能体
444
- const installResults = []
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
- if (agentIds.length === 0) {
457
- const installResult = await installSkillToClaw(skillName, skillContent, undefined, log)
458
- if (!installResult.success) {
459
- const error: any = new Error(installResult.message)
460
- error.code = 'INSTALL_FAILED'
461
- throw error
462
- }
463
- installResults.push(installResult)
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
- for (const agentId of agentIdsList) {
550
- // 获取技能目录
551
- const skillsDir = await getSkillsDir(agentId, log)
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
- // 尝试删除技能目录(ZIP 安装的技能)
568
- try {
569
- await fs.rm(skillDirPath, { recursive: true, force: true })
570
- log?.info?.(`[SkillsHandler] Skill directory deleted: ${skillDirPath}`)
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
- if (agentIdsList.length === 0) {
580
- // 获取默认技能目录
581
- const skillsDir = await getSkillsDir(undefined, log)
582
-
583
- // 检查技能文件和目录
584
- const skillFilePath = path.join(skillsDir, `${skillName}.json`)
585
- const skillDirPath = path.join(skillsDir, skillName)
586
-
587
- // 尝试删除技能文件
588
- try {
589
- await fs.unlink(skillFilePath)
590
- log?.info?.(`[SkillsHandler] Skill file deleted: ${skillFilePath}`)
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
- catch {
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}`)