@opengoat/core 2026.2.15 → 2026.2.17
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/dist/core/agents/application/agent.service.d.ts +12 -3
- package/dist/core/agents/application/agent.service.js +98 -48
- package/dist/core/agents/application/agent.service.js.map +1 -1
- package/dist/core/boards/application/board.service.d.ts +2 -0
- package/dist/core/boards/application/board.service.js +36 -2
- package/dist/core/boards/application/board.service.js.map +1 -1
- package/dist/core/bootstrap/application/bootstrap.service.js +4 -1
- package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
- package/dist/core/opengoat/application/opengoat.service.d.ts +5 -3
- package/dist/core/opengoat/application/opengoat.service.helpers.d.ts +12 -2
- package/dist/core/opengoat/application/opengoat.service.helpers.js +86 -8
- package/dist/core/opengoat/application/opengoat.service.helpers.js.map +1 -1
- package/dist/core/opengoat/application/opengoat.service.js +238 -89
- package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
- package/dist/core/orchestration/application/orchestration.service.d.ts +1 -0
- package/dist/core/orchestration/application/orchestration.service.js +42 -29
- package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
- package/dist/core/providers/application/provider.service.d.ts +34 -4
- package/dist/core/providers/application/provider.service.js +799 -82
- package/dist/core/providers/application/provider.service.js.map +1 -1
- package/dist/core/providers/index.d.ts +1 -1
- package/dist/core/providers/index.js.map +1 -1
- package/dist/core/providers/loader.js +4 -2
- package/dist/core/providers/loader.js.map +1 -1
- package/dist/core/providers/openclaw-gateway-rpc.d.ts +20 -0
- package/dist/core/providers/openclaw-gateway-rpc.js +629 -0
- package/dist/core/providers/openclaw-gateway-rpc.js.map +1 -0
- package/dist/core/providers/provider-module.d.ts +11 -0
- package/dist/core/providers/provider-module.js +8 -1
- package/dist/core/providers/provider-module.js.map +1 -1
- package/dist/core/providers/providers/claude-code/index.d.ts +4 -0
- package/dist/core/providers/providers/claude-code/index.js +32 -0
- package/dist/core/providers/providers/claude-code/index.js.map +1 -0
- package/dist/core/providers/providers/claude-code/provider.d.ts +13 -0
- package/dist/core/providers/providers/claude-code/provider.js +152 -0
- package/dist/core/providers/providers/claude-code/provider.js.map +1 -0
- package/dist/core/providers/providers/codex/index.d.ts +4 -0
- package/dist/core/providers/providers/codex/index.js +32 -0
- package/dist/core/providers/providers/codex/index.js.map +1 -0
- package/dist/core/providers/providers/codex/provider.d.ts +12 -0
- package/dist/core/providers/providers/codex/provider.js +156 -0
- package/dist/core/providers/providers/codex/provider.js.map +1 -0
- package/dist/core/providers/providers/cursor/index.d.ts +4 -0
- package/dist/core/providers/providers/cursor/index.js +32 -0
- package/dist/core/providers/providers/cursor/index.js.map +1 -0
- package/dist/core/providers/providers/cursor/provider.d.ts +12 -0
- package/dist/core/providers/providers/cursor/provider.js +161 -0
- package/dist/core/providers/providers/cursor/provider.js.map +1 -0
- package/dist/core/providers/providers/gemini-cli/index.d.ts +4 -0
- package/dist/core/providers/providers/gemini-cli/index.js +36 -0
- package/dist/core/providers/providers/gemini-cli/index.js.map +1 -0
- package/dist/core/providers/providers/gemini-cli/provider.d.ts +11 -0
- package/dist/core/providers/providers/gemini-cli/provider.js +122 -0
- package/dist/core/providers/providers/gemini-cli/provider.js.map +1 -0
- package/dist/core/providers/providers/openclaw/index.js +8 -0
- package/dist/core/providers/providers/openclaw/index.js.map +1 -1
- package/dist/core/providers/providers/openclaw/provider.js +1 -0
- package/dist/core/providers/providers/openclaw/provider.js.map +1 -1
- package/dist/core/providers/providers/opencode/index.d.ts +4 -0
- package/dist/core/providers/providers/opencode/index.js +27 -0
- package/dist/core/providers/providers/opencode/index.js.map +1 -0
- package/dist/core/providers/providers/opencode/provider.d.ts +12 -0
- package/dist/core/providers/providers/opencode/provider.js +130 -0
- package/dist/core/providers/providers/opencode/provider.js.map +1 -0
- package/dist/core/providers/providers/registry.d.ts +2 -0
- package/dist/core/providers/providers/registry.js +17 -0
- package/dist/core/providers/providers/registry.js.map +1 -0
- package/dist/core/providers/registry.d.ts +2 -1
- package/dist/core/providers/registry.js +40 -0
- package/dist/core/providers/registry.js.map +1 -1
- package/dist/core/providers/types.d.ts +1 -0
- package/dist/core/scenarios/application/scenario-runner.service.js +2 -1
- package/dist/core/scenarios/application/scenario-runner.service.js.map +1 -1
- package/dist/core/sessions/application/session.service.d.ts +0 -2
- package/dist/core/sessions/application/session.service.js +10 -73
- package/dist/core/sessions/application/session.service.js.map +1 -1
- package/dist/core/sessions/domain/session.d.ts +0 -3
- package/dist/core/sessions/domain/session.js.map +1 -1
- package/dist/core/skills/application/skill.service.js +4 -1
- package/dist/core/skills/application/skill.service.js.map +1 -1
- package/dist/core/templates/assets/ceo/BOOTSTRAP.md +3 -3
- package/dist/core/templates/assets/ceo/ROLE.md +3 -2
- package/dist/core/templates/assets/skills/og-boards/SKILL.md +65 -0
- package/dist/core/templates/default-templates.d.ts +1 -2
- package/dist/core/templates/default-templates.js +7 -7
- package/dist/core/templates/default-templates.js.map +1 -1
- package/package.json +3 -2
|
@@ -2,7 +2,7 @@ import { AgentManifestService } from "../../agents/application/agent-manifest.se
|
|
|
2
2
|
import { AgentService } from "../../agents/application/agent.service.js";
|
|
3
3
|
import { BoardService, } from "../../boards/index.js";
|
|
4
4
|
import { BootstrapService } from "../../bootstrap/application/bootstrap.service.js";
|
|
5
|
-
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../../domain/agent-id.js";
|
|
5
|
+
import { DEFAULT_AGENT_ID, isDefaultAgentId, normalizeAgentId, } from "../../domain/agent-id.js";
|
|
6
6
|
import { createNoopLogger } from "../../logging/index.js";
|
|
7
7
|
import { OrchestrationService, } from "../../orchestration/index.js";
|
|
8
8
|
import { ProviderService } from "../../providers/application/provider.service.js";
|
|
@@ -10,7 +10,7 @@ import { ProviderCommandNotFoundError, createDefaultProviderRegistry, } from "..
|
|
|
10
10
|
import { dirname, resolve as resolvePath } from "node:path";
|
|
11
11
|
import { SessionService, } from "../../sessions/index.js";
|
|
12
12
|
import { SkillService, } from "../../skills/index.js";
|
|
13
|
-
import { assertAgentExists, buildBlockedTaskMessage, buildInactiveAgentMessage,
|
|
13
|
+
import { assertAgentExists, buildBlockedTaskMessage, buildInactiveAgentMessage, buildNotificationSessionRef, buildPendingTaskMessage, buildReporteeStats, buildTodoTaskMessage, collectAllReportees, containsAgentNotFoundMessage, containsAlreadyExistsMessage, extractManagedSkillsDir, extractOpenClawAgents, isSpawnPermissionOrMissing, pathIsWithin, pathMatches, prepareOpenClawCommandEnv, resolveInactiveAgentNotificationTarget, resolveInactiveMinutes, resolveMaxParallelFlows, toErrorMessage, } from "./opengoat.service.helpers.js";
|
|
14
14
|
const OPENCLAW_PROVIDER_ID = "openclaw";
|
|
15
15
|
const OPENCLAW_DEFAULT_AGENT_ID = "main";
|
|
16
16
|
const OPENCLAW_AGENT_SANDBOX_MODE = "off";
|
|
@@ -255,6 +255,10 @@ export class OpenGoatService {
|
|
|
255
255
|
}
|
|
256
256
|
async createAgent(rawName, options = {}) {
|
|
257
257
|
const identity = this.agentService.normalizeAgentName(rawName);
|
|
258
|
+
const managerAgentId = resolveCreateAgentManagerId(identity.id, options.reportsTo);
|
|
259
|
+
if (managerAgentId) {
|
|
260
|
+
await this.assertManagerSupportsReportees(managerAgentId);
|
|
261
|
+
}
|
|
258
262
|
const paths = this.pathsProvider.getPaths();
|
|
259
263
|
const created = await this.agentService.ensureAgent(paths, identity, {
|
|
260
264
|
type: options.type,
|
|
@@ -308,6 +312,8 @@ export class OpenGoatService {
|
|
|
308
312
|
displayName: created.agent.displayName,
|
|
309
313
|
role: options.role?.trim() ??
|
|
310
314
|
(created.alreadyExisted ? created.agent.role : ""),
|
|
315
|
+
}, {
|
|
316
|
+
syncBootstrapMarkdown: false,
|
|
311
317
|
});
|
|
312
318
|
created.createdPaths.push(...workspaceBootstrap.createdPaths);
|
|
313
319
|
created.skippedPaths.push(...workspaceBootstrap.skippedPaths);
|
|
@@ -460,7 +466,9 @@ export class OpenGoatService {
|
|
|
460
466
|
}
|
|
461
467
|
async setAgentProvider(agentId, providerId) {
|
|
462
468
|
const paths = this.pathsProvider.getPaths();
|
|
463
|
-
|
|
469
|
+
const binding = await this.providerService.setAgentProvider(paths, agentId, providerId);
|
|
470
|
+
await this.ensureAgentProviderRoleSkills(paths, binding.agentId);
|
|
471
|
+
return binding;
|
|
464
472
|
}
|
|
465
473
|
async getOpenClawGatewayConfig() {
|
|
466
474
|
const paths = this.pathsProvider.getPaths();
|
|
@@ -518,6 +526,22 @@ export class OpenGoatService {
|
|
|
518
526
|
const paths = this.pathsProvider.getPaths();
|
|
519
527
|
return this.boardService.addTaskWorklog(paths, actorId, taskId, content);
|
|
520
528
|
}
|
|
529
|
+
async assertManagerSupportsReportees(managerAgentId) {
|
|
530
|
+
const paths = this.pathsProvider.getPaths();
|
|
531
|
+
const agents = await this.agentService.listAgents(paths);
|
|
532
|
+
if (!agents.some((agent) => agent.id === managerAgentId)) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const managerBinding = await this.providerService.getAgentProvider(paths, managerAgentId);
|
|
536
|
+
const providers = await this.providerService.listProviders();
|
|
537
|
+
const provider = providers.find((candidate) => candidate.id === managerBinding.providerId);
|
|
538
|
+
if (!provider) {
|
|
539
|
+
throw new Error(`Provider "${managerBinding.providerId}" is not available for manager "${managerAgentId}".`);
|
|
540
|
+
}
|
|
541
|
+
if (!provider.capabilities.reportees) {
|
|
542
|
+
throw new Error(`Cannot assign "${managerAgentId}" as manager because provider "${provider.displayName}" does not support reportees.`);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
521
545
|
async runTaskCronCycle(options = {}) {
|
|
522
546
|
const paths = this.pathsProvider.getPaths();
|
|
523
547
|
const ranAt = this.resolveNowIso();
|
|
@@ -525,15 +549,14 @@ export class OpenGoatService {
|
|
|
525
549
|
const inactiveMinutes = resolveInactiveMinutes(options.inactiveMinutes);
|
|
526
550
|
const notificationTarget = resolveInactiveAgentNotificationTarget(options.notificationTarget);
|
|
527
551
|
const notifyInactiveAgents = options.notifyInactiveAgents ?? true;
|
|
552
|
+
const maxParallelFlows = resolveMaxParallelFlows(options.maxParallelFlows);
|
|
528
553
|
const inactiveCandidates = notifyInactiveAgents
|
|
529
554
|
? await this.collectInactiveAgents(paths, manifests, inactiveMinutes, notificationTarget)
|
|
530
555
|
: [];
|
|
531
|
-
const latestCeoProjectPath = notifyInactiveAgents
|
|
532
|
-
? await this.resolveLatestProjectPathForAgent(paths, DEFAULT_AGENT_ID)
|
|
533
|
-
: undefined;
|
|
534
556
|
const tasks = await this.boardService.listTasks(paths, { limit: 10_000 });
|
|
535
|
-
const
|
|
536
|
-
const
|
|
557
|
+
const pendingTaskIds = new Set(await this.boardService.listPendingTaskIdsOlderThan(paths, inactiveMinutes));
|
|
558
|
+
const taskStatusDispatch = await this.dispatchTaskStatusAutomations(paths, tasks, manifests, pendingTaskIds, inactiveMinutes, ranAt, maxParallelFlows);
|
|
559
|
+
const inactiveDispatches = await this.dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes, ranAt, maxParallelFlows);
|
|
537
560
|
const dispatches = [
|
|
538
561
|
...taskStatusDispatch.dispatches,
|
|
539
562
|
...inactiveDispatches,
|
|
@@ -550,57 +573,92 @@ export class OpenGoatService {
|
|
|
550
573
|
dispatches,
|
|
551
574
|
};
|
|
552
575
|
}
|
|
553
|
-
async dispatchTaskStatusAutomations(paths, tasks, manifests) {
|
|
576
|
+
async dispatchTaskStatusAutomations(paths, tasks, manifests, pendingTaskIds, pendingMinutes, notificationTimestamp, maxParallelFlows) {
|
|
554
577
|
const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
|
|
555
|
-
const
|
|
578
|
+
const requests = [];
|
|
556
579
|
let todoTasks = 0;
|
|
580
|
+
let pendingTasks = 0;
|
|
557
581
|
let blockedTasks = 0;
|
|
558
582
|
for (const task of tasks) {
|
|
559
|
-
if (task.status !== "todo" && task.status !== "blocked") {
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
583
|
if (task.status === "todo") {
|
|
563
584
|
todoTasks += 1;
|
|
564
585
|
const targetAgentId = task.assignedTo;
|
|
565
|
-
const sessionRef =
|
|
566
|
-
const message = buildTodoTaskMessage({
|
|
567
|
-
|
|
568
|
-
|
|
586
|
+
const sessionRef = buildNotificationSessionRef(targetAgentId);
|
|
587
|
+
const message = buildTodoTaskMessage({
|
|
588
|
+
task,
|
|
589
|
+
notificationTimestamp,
|
|
590
|
+
});
|
|
591
|
+
requests.push({
|
|
569
592
|
kind: "todo",
|
|
570
593
|
targetAgentId,
|
|
571
594
|
sessionRef,
|
|
572
595
|
taskId: task.taskId,
|
|
573
|
-
|
|
574
|
-
error: result.error,
|
|
596
|
+
message,
|
|
575
597
|
});
|
|
576
598
|
continue;
|
|
577
599
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
600
|
+
if (task.status === "pending") {
|
|
601
|
+
if (!pendingTaskIds.has(task.taskId)) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
pendingTasks += 1;
|
|
605
|
+
const targetAgentId = task.assignedTo;
|
|
606
|
+
const sessionRef = buildNotificationSessionRef(targetAgentId);
|
|
607
|
+
const message = buildPendingTaskMessage({
|
|
608
|
+
task,
|
|
609
|
+
pendingMinutes,
|
|
610
|
+
notificationTimestamp,
|
|
611
|
+
});
|
|
612
|
+
requests.push({
|
|
613
|
+
kind: "pending",
|
|
614
|
+
targetAgentId,
|
|
615
|
+
sessionRef,
|
|
616
|
+
taskId: task.taskId,
|
|
617
|
+
message,
|
|
618
|
+
});
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (task.status === "blocked") {
|
|
622
|
+
blockedTasks += 1;
|
|
623
|
+
const assigneeManifest = manifestsById.get(task.assignedTo);
|
|
624
|
+
const managerAgentId = normalizeAgentId(assigneeManifest?.metadata.reportsTo ?? "") ||
|
|
625
|
+
DEFAULT_AGENT_ID;
|
|
626
|
+
const sessionRef = buildNotificationSessionRef(managerAgentId);
|
|
627
|
+
const message = buildBlockedTaskMessage({
|
|
628
|
+
task,
|
|
629
|
+
notificationTimestamp,
|
|
630
|
+
});
|
|
631
|
+
requests.push({
|
|
632
|
+
kind: "blocked",
|
|
633
|
+
targetAgentId: managerAgentId,
|
|
634
|
+
sessionRef,
|
|
635
|
+
taskId: task.taskId,
|
|
636
|
+
message,
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
const dispatches = await runWithConcurrencyByKey(requests, maxParallelFlows, (request) => normalizeAgentId(request.targetAgentId) || DEFAULT_AGENT_ID, async (request) => {
|
|
641
|
+
const result = await this.dispatchAutomationMessage(paths, request.targetAgentId, request.sessionRef, request.message);
|
|
642
|
+
return {
|
|
643
|
+
kind: request.kind,
|
|
644
|
+
targetAgentId: request.targetAgentId,
|
|
645
|
+
sessionRef: request.sessionRef,
|
|
646
|
+
taskId: request.taskId,
|
|
647
|
+
message: request.message,
|
|
590
648
|
ok: result.ok,
|
|
591
649
|
error: result.error,
|
|
592
|
-
}
|
|
593
|
-
}
|
|
650
|
+
};
|
|
651
|
+
});
|
|
594
652
|
return {
|
|
595
653
|
dispatches,
|
|
596
654
|
todoTasks,
|
|
655
|
+
pendingTasks,
|
|
597
656
|
blockedTasks,
|
|
598
657
|
};
|
|
599
658
|
}
|
|
600
|
-
async dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes,
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const sessionRef = buildInactiveSessionRef(candidate.managerAgentId, candidate.subjectAgentId);
|
|
659
|
+
async dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes, notificationTimestamp, maxParallelFlows = 1) {
|
|
660
|
+
return runWithConcurrencyByKey(inactiveCandidates, maxParallelFlows, (candidate) => normalizeAgentId(candidate.managerAgentId) || DEFAULT_AGENT_ID, async (candidate) => {
|
|
661
|
+
const sessionRef = buildNotificationSessionRef(candidate.managerAgentId);
|
|
604
662
|
const message = buildInactiveAgentMessage({
|
|
605
663
|
managerAgentId: candidate.managerAgentId,
|
|
606
664
|
subjectAgentId: candidate.subjectAgentId,
|
|
@@ -609,21 +667,20 @@ export class OpenGoatService {
|
|
|
609
667
|
directReporteesCount: candidate.directReporteesCount,
|
|
610
668
|
indirectReporteesCount: candidate.indirectReporteesCount,
|
|
611
669
|
inactiveMinutes,
|
|
670
|
+
notificationTimestamp,
|
|
612
671
|
lastActionTimestamp: candidate.lastActionTimestamp,
|
|
613
672
|
});
|
|
614
|
-
const result = await this.dispatchAutomationMessage(paths, candidate.managerAgentId, sessionRef, message
|
|
615
|
-
|
|
616
|
-
});
|
|
617
|
-
dispatches.push({
|
|
673
|
+
const result = await this.dispatchAutomationMessage(paths, candidate.managerAgentId, sessionRef, message);
|
|
674
|
+
return {
|
|
618
675
|
kind: "inactive",
|
|
619
676
|
targetAgentId: candidate.managerAgentId,
|
|
620
677
|
sessionRef,
|
|
621
678
|
subjectAgentId: candidate.subjectAgentId,
|
|
679
|
+
message,
|
|
622
680
|
ok: result.ok,
|
|
623
681
|
error: result.error,
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
return dispatches;
|
|
682
|
+
};
|
|
683
|
+
});
|
|
627
684
|
}
|
|
628
685
|
async listSkills(agentId = DEFAULT_AGENT_ID) {
|
|
629
686
|
const paths = this.pathsProvider.getPaths();
|
|
@@ -678,7 +735,6 @@ export class OpenGoatService {
|
|
|
678
735
|
const paths = this.pathsProvider.getPaths();
|
|
679
736
|
const prepared = await this.sessionService.prepareRunSession(paths, agentId, {
|
|
680
737
|
sessionRef: options.sessionRef,
|
|
681
|
-
projectPath: options.projectPath,
|
|
682
738
|
forceNew: options.forceNew,
|
|
683
739
|
userMessage: "",
|
|
684
740
|
});
|
|
@@ -722,7 +778,7 @@ export class OpenGoatService {
|
|
|
722
778
|
const result = await this.orchestrationService.runAgent(paths, agentId, {
|
|
723
779
|
message,
|
|
724
780
|
sessionRef,
|
|
725
|
-
disableSession: options.disableSession ??
|
|
781
|
+
disableSession: options.disableSession ?? false,
|
|
726
782
|
cwd: options.cwd,
|
|
727
783
|
env: process.env,
|
|
728
784
|
});
|
|
@@ -777,7 +833,7 @@ export class OpenGoatService {
|
|
|
777
833
|
return;
|
|
778
834
|
}
|
|
779
835
|
syncedAgents.add(targetAgentId);
|
|
780
|
-
const sync = await this.
|
|
836
|
+
const sync = await this.ensureAgentProviderRoleSkills(paths, targetAgentId);
|
|
781
837
|
createdPaths.push(...sync.createdPaths);
|
|
782
838
|
skippedPaths.push(...sync.skippedPaths);
|
|
783
839
|
removedPaths.push(...sync.removedPaths);
|
|
@@ -815,6 +871,7 @@ export class OpenGoatService {
|
|
|
815
871
|
for (const legacySkillId of [
|
|
816
872
|
"board-manager",
|
|
817
873
|
"board-individual",
|
|
874
|
+
"og-boards",
|
|
818
875
|
"og-board-manager",
|
|
819
876
|
"og-board-individual",
|
|
820
877
|
"manager",
|
|
@@ -834,6 +891,18 @@ export class OpenGoatService {
|
|
|
834
891
|
removedPaths,
|
|
835
892
|
};
|
|
836
893
|
}
|
|
894
|
+
async ensureAgentProviderRoleSkills(paths, rawAgentId) {
|
|
895
|
+
const agentId = normalizeAgentId(rawAgentId);
|
|
896
|
+
if (!agentId) {
|
|
897
|
+
throw new Error("Agent id cannot be empty.");
|
|
898
|
+
}
|
|
899
|
+
const runtimeProfile = await this.providerService.getAgentRuntimeProfile(paths, agentId);
|
|
900
|
+
const managedRoleSkillDirectories = await this.providerService.listProviderRoleSkillDirectories();
|
|
901
|
+
return this.agentService.ensureAgentWorkspaceRoleSkills(paths, agentId, {
|
|
902
|
+
requiredSkillDirectories: runtimeProfile.roleSkillDirectories,
|
|
903
|
+
managedSkillDirectories: managedRoleSkillDirectories,
|
|
904
|
+
});
|
|
905
|
+
}
|
|
837
906
|
async resolveOpenClawManagedSkillsDir(paths) {
|
|
838
907
|
if (this.openClawManagedSkillsDirCache !== undefined) {
|
|
839
908
|
return this.openClawManagedSkillsDirCache;
|
|
@@ -843,17 +912,28 @@ export class OpenGoatService {
|
|
|
843
912
|
...process.env,
|
|
844
913
|
...(providerConfig?.env ?? {}),
|
|
845
914
|
};
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
915
|
+
try {
|
|
916
|
+
const skillsList = await this.runOpenClaw(["skills", "list", "--json"], {
|
|
917
|
+
env,
|
|
918
|
+
});
|
|
919
|
+
if (skillsList.code !== 0) {
|
|
920
|
+
throw new Error(`OpenClaw skills list failed (exit ${skillsList.code}). ${skillsList.stderr.trim() || skillsList.stdout.trim() || ""}`.trim());
|
|
921
|
+
}
|
|
922
|
+
const parsed = parseLooseJson(skillsList.stdout);
|
|
923
|
+
if (parsed === undefined) {
|
|
924
|
+
throw new Error("OpenClaw skills list returned non-JSON output; cannot resolve managed skills directory.");
|
|
925
|
+
}
|
|
926
|
+
const managedSkillsDir = extractManagedSkillsDir(parsed);
|
|
927
|
+
this.openClawManagedSkillsDirCache = managedSkillsDir;
|
|
928
|
+
return managedSkillsDir;
|
|
851
929
|
}
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
930
|
+
catch (error) {
|
|
931
|
+
if (!(error instanceof ProviderCommandNotFoundError)) {
|
|
932
|
+
throw error;
|
|
933
|
+
}
|
|
855
934
|
}
|
|
856
|
-
const
|
|
935
|
+
const skillsStatus = await this.providerService.getOpenClawSkillsStatusViaGateway(paths, env);
|
|
936
|
+
const managedSkillsDir = extractManagedSkillsDir(skillsStatus);
|
|
857
937
|
this.openClawManagedSkillsDirCache = managedSkillsDir;
|
|
858
938
|
return managedSkillsDir;
|
|
859
939
|
}
|
|
@@ -862,17 +942,30 @@ export class OpenGoatService {
|
|
|
862
942
|
return [];
|
|
863
943
|
}
|
|
864
944
|
const env = await this.resolveOpenClawEnv(paths);
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
945
|
+
try {
|
|
946
|
+
const listed = await this.runOpenClaw(["agents", "list", "--json"], {
|
|
947
|
+
env,
|
|
948
|
+
});
|
|
949
|
+
if (listed.code !== 0) {
|
|
950
|
+
throw new Error(`OpenClaw agents list failed (exit ${listed.code}). ${listed.stderr.trim() || listed.stdout.trim() || ""}`.trim());
|
|
951
|
+
}
|
|
952
|
+
const parsed = parseLooseJson(listed.stdout);
|
|
953
|
+
if (parsed === undefined) {
|
|
954
|
+
throw new Error("OpenClaw agents list returned non-JSON output; cannot inspect agents.");
|
|
955
|
+
}
|
|
956
|
+
return extractOpenClawAgents(parsed);
|
|
870
957
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
958
|
+
catch (error) {
|
|
959
|
+
if (!(error instanceof ProviderCommandNotFoundError)) {
|
|
960
|
+
throw error;
|
|
961
|
+
}
|
|
874
962
|
}
|
|
875
|
-
|
|
963
|
+
const entries = await this.providerService.listOpenClawAgentsViaGateway(paths, env);
|
|
964
|
+
return entries.map((entry) => ({
|
|
965
|
+
id: entry.id,
|
|
966
|
+
workspace: entry.workspace,
|
|
967
|
+
agentDir: entry.agentDir,
|
|
968
|
+
}));
|
|
876
969
|
}
|
|
877
970
|
async addWorkspaceAgentCandidates(paths, candidates, warnings) {
|
|
878
971
|
try {
|
|
@@ -985,23 +1078,32 @@ export class OpenGoatService {
|
|
|
985
1078
|
}
|
|
986
1079
|
const warnings = [];
|
|
987
1080
|
const env = await this.resolveOpenClawEnv(paths);
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1081
|
+
let entries;
|
|
1082
|
+
try {
|
|
1083
|
+
const listResult = await this.runOpenClaw(["config", "get", "agents.list"], {
|
|
1084
|
+
env,
|
|
1085
|
+
});
|
|
1086
|
+
if (listResult.code !== 0) {
|
|
1087
|
+
warnings.push(`OpenClaw config read failed (agents.list, code ${listResult.code}). ${listResult.stderr.trim() || listResult.stdout.trim() || ""}`.trim());
|
|
1088
|
+
return warnings;
|
|
1089
|
+
}
|
|
1090
|
+
const parsed = parseLooseJson(listResult.stdout);
|
|
1091
|
+
if (parsed === undefined) {
|
|
1092
|
+
warnings.push("OpenClaw config read returned non-JSON for agents.list; skipping sandbox/tools policy sync.");
|
|
1093
|
+
return warnings;
|
|
1094
|
+
}
|
|
1095
|
+
if (!Array.isArray(parsed)) {
|
|
1096
|
+
warnings.push("OpenClaw config agents.list is not an array; skipping sandbox/tools policy sync.");
|
|
1097
|
+
return warnings;
|
|
1098
|
+
}
|
|
1099
|
+
entries = parsed;
|
|
999
1100
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1101
|
+
catch (error) {
|
|
1102
|
+
if (!(error instanceof ProviderCommandNotFoundError)) {
|
|
1103
|
+
throw error;
|
|
1104
|
+
}
|
|
1105
|
+
return this.providerService.syncOpenClawAgentExecutionPoliciesViaGateway(paths, agentIds, env);
|
|
1003
1106
|
}
|
|
1004
|
-
const entries = parsed;
|
|
1005
1107
|
const indexById = new Map();
|
|
1006
1108
|
for (let index = 0; index < entries.length; index += 1) {
|
|
1007
1109
|
const entry = entries[index];
|
|
@@ -1215,15 +1317,6 @@ export class OpenGoatService {
|
|
|
1215
1317
|
}
|
|
1216
1318
|
return inactive;
|
|
1217
1319
|
}
|
|
1218
|
-
async resolveLatestProjectPathForAgent(paths, rawAgentId) {
|
|
1219
|
-
const agentId = normalizeAgentId(rawAgentId);
|
|
1220
|
-
if (!agentId) {
|
|
1221
|
-
return undefined;
|
|
1222
|
-
}
|
|
1223
|
-
const sessions = await this.sessionService.listSessions(paths, agentId);
|
|
1224
|
-
const latestProjectPath = sessions[0]?.projectPath?.trim();
|
|
1225
|
-
return latestProjectPath || undefined;
|
|
1226
|
-
}
|
|
1227
1320
|
}
|
|
1228
1321
|
function asRecord(value) {
|
|
1229
1322
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -1264,6 +1357,48 @@ function readStringArray(value) {
|
|
|
1264
1357
|
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
|
|
1265
1358
|
.filter((entry) => entry.length > 0);
|
|
1266
1359
|
}
|
|
1360
|
+
async function runWithConcurrency(items, rawConcurrency, worker) {
|
|
1361
|
+
if (items.length === 0) {
|
|
1362
|
+
return [];
|
|
1363
|
+
}
|
|
1364
|
+
const concurrency = Math.max(1, Math.floor(rawConcurrency));
|
|
1365
|
+
const results = new Array(items.length);
|
|
1366
|
+
let nextIndex = 0;
|
|
1367
|
+
const runWorker = async () => {
|
|
1368
|
+
while (true) {
|
|
1369
|
+
const currentIndex = nextIndex;
|
|
1370
|
+
nextIndex += 1;
|
|
1371
|
+
if (currentIndex >= items.length) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
results[currentIndex] = await worker(items[currentIndex], currentIndex);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
const workerCount = Math.min(concurrency, items.length);
|
|
1378
|
+
const workers = Array.from({ length: workerCount }, () => runWorker());
|
|
1379
|
+
await Promise.all(workers);
|
|
1380
|
+
return results;
|
|
1381
|
+
}
|
|
1382
|
+
async function runWithConcurrencyByKey(items, rawConcurrency, resolveKey, worker) {
|
|
1383
|
+
if (items.length === 0) {
|
|
1384
|
+
return [];
|
|
1385
|
+
}
|
|
1386
|
+
const grouped = new Map();
|
|
1387
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
1388
|
+
const item = items[index];
|
|
1389
|
+
const key = resolveKey(item, index).trim().toLowerCase() || "default";
|
|
1390
|
+
const bucket = grouped.get(key) ?? [];
|
|
1391
|
+
bucket.push({ item, index });
|
|
1392
|
+
grouped.set(key, bucket);
|
|
1393
|
+
}
|
|
1394
|
+
const results = new Array(items.length);
|
|
1395
|
+
await runWithConcurrency([...grouped.values()], rawConcurrency, async (entries) => {
|
|
1396
|
+
for (const entry of entries) {
|
|
1397
|
+
results[entry.index] = await worker(entry.item, entry.index);
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
return results;
|
|
1401
|
+
}
|
|
1267
1402
|
function parseLooseJson(raw) {
|
|
1268
1403
|
const trimmed = raw.trim();
|
|
1269
1404
|
if (!trimmed) {
|
|
@@ -1298,6 +1433,20 @@ function parseLooseJson(raw) {
|
|
|
1298
1433
|
function dedupeNumbers(values) {
|
|
1299
1434
|
return [...new Set(values)];
|
|
1300
1435
|
}
|
|
1436
|
+
function resolveCreateAgentManagerId(agentId, reportsTo) {
|
|
1437
|
+
const normalizedAgentId = normalizeAgentId(agentId);
|
|
1438
|
+
if (isDefaultAgentId(normalizedAgentId)) {
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
if (reportsTo === null || reportsTo === undefined) {
|
|
1442
|
+
return DEFAULT_AGENT_ID;
|
|
1443
|
+
}
|
|
1444
|
+
const normalizedManagerId = normalizeAgentId(reportsTo);
|
|
1445
|
+
if (!normalizedManagerId || normalizedManagerId === normalizedAgentId) {
|
|
1446
|
+
return DEFAULT_AGENT_ID;
|
|
1447
|
+
}
|
|
1448
|
+
return normalizedManagerId;
|
|
1449
|
+
}
|
|
1301
1450
|
function collectPluginPathCandidatesFromArgvDir(argvDir) {
|
|
1302
1451
|
const maxDepth = 8;
|
|
1303
1452
|
const candidates = [];
|