@opengoat/core 2026.2.9 → 2026.2.13
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/README.md +3 -3
- package/dist/core/acp/application/acp-agent.js +4 -8
- package/dist/core/acp/application/acp-agent.js.map +1 -1
- package/dist/core/agents/application/agent-manifest.service.d.ts +1 -4
- package/dist/core/agents/application/agent-manifest.service.js +39 -52
- package/dist/core/agents/application/agent-manifest.service.js.map +1 -1
- package/dist/core/agents/application/agent.service.d.ts +42 -4
- package/dist/core/agents/application/agent.service.js +439 -55
- package/dist/core/agents/application/agent.service.js.map +1 -1
- package/dist/core/agents/domain/agent-manifest.d.ts +10 -4
- package/dist/core/agents/domain/agent-manifest.js +118 -25
- package/dist/core/agents/domain/agent-manifest.js.map +1 -1
- package/dist/core/agents/index.d.ts +1 -3
- package/dist/core/agents/index.js +1 -3
- package/dist/core/agents/index.js.map +1 -1
- package/dist/core/boards/application/board.service.d.ts +64 -0
- package/dist/core/boards/application/board.service.js +590 -0
- package/dist/core/boards/application/board.service.js.map +1 -0
- package/dist/core/boards/domain/board.d.ts +30 -0
- package/dist/core/boards/domain/board.js +2 -0
- package/dist/core/boards/domain/board.js.map +1 -0
- package/dist/core/boards/index.d.ts +2 -0
- package/dist/core/boards/index.js +2 -0
- package/dist/core/boards/index.js.map +1 -0
- package/dist/core/bootstrap/application/bootstrap.service.d.ts +1 -2
- package/dist/core/bootstrap/application/bootstrap.service.js +14 -19
- package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
- package/dist/core/domain/agent-id.d.ts +1 -1
- package/dist/core/domain/agent-id.js +1 -1
- package/dist/core/domain/agent-id.js.map +1 -1
- package/dist/core/domain/agent.d.ts +31 -8
- package/dist/core/opengoat/application/opengoat.service.d.ts +106 -27
- package/dist/core/opengoat/application/opengoat.service.js +1006 -136
- package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
- package/dist/core/opengoat/index.d.ts +1 -0
- package/dist/core/orchestration/application/orchestration.service.d.ts +8 -21
- package/dist/core/orchestration/application/orchestration.service.js +59 -871
- package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
- package/dist/core/orchestration/application/routing.service.js +10 -8
- package/dist/core/orchestration/application/routing.service.js.map +1 -1
- package/dist/core/orchestration/domain/routing.d.ts +0 -17
- package/dist/core/orchestration/domain/run-events.d.ts +1 -1
- package/dist/core/orchestration/index.d.ts +0 -2
- package/dist/core/orchestration/index.js +0 -1
- package/dist/core/orchestration/index.js.map +1 -1
- package/dist/core/providers/application/provider.service.d.ts +15 -32
- package/dist/core/providers/application/provider.service.js +115 -201
- package/dist/core/providers/application/provider.service.js.map +1 -1
- package/dist/core/providers/cli-provider.d.ts +1 -0
- package/dist/core/providers/cli-provider.js +66 -1
- package/dist/core/providers/cli-provider.js.map +1 -1
- package/dist/core/providers/image-input.d.ts +16 -0
- package/dist/core/providers/image-input.js +158 -0
- package/dist/core/providers/image-input.js.map +1 -0
- package/dist/core/providers/index.d.ts +1 -7
- package/dist/core/providers/index.js +0 -13
- package/dist/core/providers/index.js.map +1 -1
- package/dist/core/providers/loader.js +1 -95
- package/dist/core/providers/loader.js.map +1 -1
- package/dist/core/providers/providers/openclaw/provider.js +213 -32
- package/dist/core/providers/providers/openclaw/provider.js.map +1 -1
- package/dist/core/providers/types.d.ts +8 -3
- package/dist/core/scenarios/application/scenario-runner.service.d.ts +0 -1
- package/dist/core/scenarios/application/scenario-runner.service.js +30 -87
- package/dist/core/scenarios/application/scenario-runner.service.js.map +1 -1
- package/dist/core/scenarios/domain/scenario.d.ts +0 -15
- package/dist/core/sessions/application/session.service.d.ts +10 -4
- package/dist/core/sessions/application/session.service.js +87 -89
- package/dist/core/sessions/application/session.service.js.map +1 -1
- package/dist/core/sessions/domain/session.d.ts +3 -3
- package/dist/core/sessions/domain/transcript.d.ts +1 -1
- package/dist/core/sessions/index.d.ts +1 -1
- package/dist/core/sessions/index.js.map +1 -1
- package/dist/core/skills/application/skill.service.d.ts +2 -3
- package/dist/core/skills/application/skill.service.js +153 -56
- package/dist/core/skills/application/skill.service.js.map +1 -1
- package/dist/core/skills/domain/skill.d.ts +2 -2
- package/dist/core/skills/domain/skill.js +4 -2
- package/dist/core/skills/domain/skill.js.map +1 -1
- package/dist/core/templates/assets/ceo/AGENTS.md +20 -0
- package/dist/core/templates/assets/ceo/ROLE.md +13 -0
- package/dist/core/templates/assets/ceo/SOUL.md +15 -0
- package/dist/core/templates/assets/skills/og-board-individual/SKILL.md +148 -0
- package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +140 -0
- package/dist/core/templates/default-templates.d.ts +12 -14
- package/dist/core/templates/default-templates.js +81 -213
- package/dist/core/templates/default-templates.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/package.json +16 -13
- package/dist/core/agents/application/workspace-context.service.d.ts +0 -28
- package/dist/core/agents/application/workspace-context.service.js +0 -157
- package/dist/core/agents/application/workspace-context.service.js.map +0 -1
- package/dist/core/agents/domain/workspace-context.d.ts +0 -13
- package/dist/core/agents/domain/workspace-context.js +0 -14
- package/dist/core/agents/domain/workspace-context.js.map +0 -1
- package/dist/core/gateway/domain/protocol.d.ts +0 -113
- package/dist/core/gateway/domain/protocol.js +0 -394
- package/dist/core/gateway/domain/protocol.js.map +0 -1
- package/dist/core/gateway/index.d.ts +0 -2
- package/dist/core/gateway/index.js +0 -2
- package/dist/core/gateway/index.js.map +0 -1
- package/dist/core/llm/application/vercel-ai-text-runtime.d.ts +0 -26
- package/dist/core/llm/application/vercel-ai-text-runtime.js +0 -223
- package/dist/core/llm/application/vercel-ai-text-runtime.js.map +0 -1
- package/dist/core/llm/domain/text-runtime.d.ts +0 -22
- package/dist/core/llm/domain/text-runtime.js +0 -2
- package/dist/core/llm/domain/text-runtime.js.map +0 -1
- package/dist/core/llm/index.d.ts +0 -2
- package/dist/core/llm/index.js +0 -2
- package/dist/core/llm/index.js.map +0 -1
- package/dist/core/orchestration/application/orchestration-planner.service.d.ts +0 -28
- package/dist/core/orchestration/application/orchestration-planner.service.js +0 -279
- package/dist/core/orchestration/application/orchestration-planner.service.js.map +0 -1
- package/dist/core/orchestration/domain/loop.d.ts +0 -119
- package/dist/core/orchestration/domain/loop.js +0 -2
- package/dist/core/orchestration/domain/loop.js.map +0 -1
- package/dist/core/plugins/application/plugin.service.d.ts +0 -32
- package/dist/core/plugins/application/plugin.service.js +0 -236
- package/dist/core/plugins/application/plugin.service.js.map +0 -1
- package/dist/core/plugins/domain/openclaw-compat.d.ts +0 -60
- package/dist/core/plugins/domain/openclaw-compat.js +0 -9
- package/dist/core/plugins/domain/openclaw-compat.js.map +0 -1
- package/dist/core/plugins/index.d.ts +0 -3
- package/dist/core/plugins/index.js +0 -3
- package/dist/core/plugins/index.js.map +0 -1
- package/dist/core/providers/onboarding.d.ts +0 -13
- package/dist/core/providers/onboarding.js +0 -149
- package/dist/core/providers/onboarding.js.map +0 -1
- package/dist/core/providers/providers/claude/index.d.ts +0 -4
- package/dist/core/providers/providers/claude/index.js +0 -19
- package/dist/core/providers/providers/claude/index.js.map +0 -1
- package/dist/core/providers/providers/claude/provider.d.ts +0 -8
- package/dist/core/providers/providers/claude/provider.js +0 -106
- package/dist/core/providers/providers/claude/provider.js.map +0 -1
- package/dist/core/providers/providers/codex/index.d.ts +0 -4
- package/dist/core/providers/providers/codex/index.js +0 -19
- package/dist/core/providers/providers/codex/index.js.map +0 -1
- package/dist/core/providers/providers/codex/provider.d.ts +0 -7
- package/dist/core/providers/providers/codex/provider.js +0 -31
- package/dist/core/providers/providers/codex/provider.js.map +0 -1
- package/dist/core/providers/providers/cursor/index.d.ts +0 -4
- package/dist/core/providers/providers/cursor/index.js +0 -19
- package/dist/core/providers/providers/cursor/index.js.map +0 -1
- package/dist/core/providers/providers/cursor/provider.d.ts +0 -11
- package/dist/core/providers/providers/cursor/provider.js +0 -90
- package/dist/core/providers/providers/cursor/provider.js.map +0 -1
- package/dist/core/providers/providers/extended-http/catalog.d.ts +0 -40
- package/dist/core/providers/providers/extended-http/catalog.js +0 -728
- package/dist/core/providers/providers/extended-http/catalog.js.map +0 -1
- package/dist/core/providers/providers/extended-http/index.d.ts +0 -5
- package/dist/core/providers/providers/extended-http/index.js +0 -13
- package/dist/core/providers/providers/extended-http/index.js.map +0 -1
- package/dist/core/providers/providers/extended-http/provider.d.ts +0 -31
- package/dist/core/providers/providers/extended-http/provider.js +0 -580
- package/dist/core/providers/providers/extended-http/provider.js.map +0 -1
- package/dist/core/providers/providers/gemini/index.d.ts +0 -4
- package/dist/core/providers/providers/gemini/index.js +0 -37
- package/dist/core/providers/providers/gemini/index.js.map +0 -1
- package/dist/core/providers/providers/gemini/provider.d.ts +0 -7
- package/dist/core/providers/providers/gemini/provider.js +0 -59
- package/dist/core/providers/providers/gemini/provider.js.map +0 -1
- package/dist/core/providers/providers/grok/index.d.ts +0 -4
- package/dist/core/providers/providers/grok/index.js +0 -41
- package/dist/core/providers/providers/grok/index.js.map +0 -1
- package/dist/core/providers/providers/grok/provider.d.ts +0 -13
- package/dist/core/providers/providers/grok/provider.js +0 -95
- package/dist/core/providers/providers/grok/provider.js.map +0 -1
- package/dist/core/providers/providers/openai/index.d.ts +0 -4
- package/dist/core/providers/providers/openai/index.js +0 -45
- package/dist/core/providers/providers/openai/index.js.map +0 -1
- package/dist/core/providers/providers/openai/provider.d.ts +0 -14
- package/dist/core/providers/providers/openai/provider.js +0 -203
- package/dist/core/providers/providers/openai/provider.js.map +0 -1
- package/dist/core/providers/providers/opencode/index.d.ts +0 -4
- package/dist/core/providers/providers/opencode/index.js +0 -23
- package/dist/core/providers/providers/opencode/index.js.map +0 -1
- package/dist/core/providers/providers/opencode/provider.d.ts +0 -11
- package/dist/core/providers/providers/opencode/provider.js +0 -215
- package/dist/core/providers/providers/opencode/provider.js.map +0 -1
- package/dist/core/providers/providers/openrouter/index.d.ts +0 -4
- package/dist/core/providers/providers/openrouter/index.js +0 -37
- package/dist/core/providers/providers/openrouter/index.js.map +0 -1
- package/dist/core/providers/providers/openrouter/provider.d.ts +0 -13
- package/dist/core/providers/providers/openrouter/provider.js +0 -80
- package/dist/core/providers/providers/openrouter/provider.js.map +0 -1
- package/dist/platform/node/opengoat-gateway-client.d.ts +0 -19
- package/dist/platform/node/opengoat-gateway-client.js +0 -194
- package/dist/platform/node/opengoat-gateway-client.js.map +0 -1
- package/dist/platform/node/opengoat-gateway-server.d.ts +0 -53
- package/dist/platform/node/opengoat-gateway-server.js +0 -906
- package/dist/platform/node/opengoat-gateway-server.js.map +0 -1
|
@@ -1,207 +1,424 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { createDefaultProviderRegistry } from "../../providers/index.js";
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { homedir } from "node:os";
|
|
4
3
|
import { AgentManifestService } from "../../agents/application/agent-manifest.service.js";
|
|
5
4
|
import { AgentService } from "../../agents/application/agent.service.js";
|
|
6
|
-
import {
|
|
5
|
+
import { BoardService, } from "../../boards/index.js";
|
|
7
6
|
import { BootstrapService } from "../../bootstrap/application/bootstrap.service.js";
|
|
8
|
-
import {
|
|
7
|
+
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../../domain/agent-id.js";
|
|
8
|
+
import { createNoopLogger } from "../../logging/index.js";
|
|
9
|
+
import { OrchestrationService, } from "../../orchestration/index.js";
|
|
9
10
|
import { ProviderService } from "../../providers/application/provider.service.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { ProviderCommandNotFoundError, createDefaultProviderRegistry, } from "../../providers/index.js";
|
|
12
|
+
import { SessionService, } from "../../sessions/index.js";
|
|
13
|
+
import { SkillService, } from "../../skills/index.js";
|
|
14
|
+
const OPENCLAW_PROVIDER_ID = "openclaw";
|
|
15
|
+
const OPENCLAW_DEFAULT_AGENT_ID = "main";
|
|
13
16
|
export class OpenGoatService {
|
|
17
|
+
fileSystem;
|
|
18
|
+
pathPort;
|
|
14
19
|
pathsProvider;
|
|
15
20
|
agentService;
|
|
16
21
|
agentManifestService;
|
|
17
22
|
bootstrapService;
|
|
18
23
|
providerService;
|
|
19
|
-
pluginService;
|
|
20
24
|
skillService;
|
|
21
25
|
sessionService;
|
|
22
26
|
orchestrationService;
|
|
27
|
+
boardService;
|
|
28
|
+
commandRunner;
|
|
29
|
+
nowIso;
|
|
30
|
+
openClawManagedSkillsDirCache;
|
|
23
31
|
constructor(deps) {
|
|
24
32
|
const nowIso = deps.nowIso ?? (() => new Date().toISOString());
|
|
25
|
-
const rootLogger = (deps.logger ?? createNoopLogger()).child({
|
|
33
|
+
const rootLogger = (deps.logger ?? createNoopLogger()).child({
|
|
34
|
+
scope: "opengoat-service",
|
|
35
|
+
});
|
|
26
36
|
const providerRegistryFactory = deps.providerRegistry
|
|
27
37
|
? () => deps.providerRegistry
|
|
28
38
|
: () => createDefaultProviderRegistry();
|
|
39
|
+
this.fileSystem = deps.fileSystem;
|
|
40
|
+
this.pathPort = deps.pathPort;
|
|
29
41
|
this.pathsProvider = deps.pathsProvider;
|
|
42
|
+
this.nowIso = nowIso;
|
|
30
43
|
this.agentService = new AgentService({
|
|
31
44
|
fileSystem: deps.fileSystem,
|
|
32
45
|
pathPort: deps.pathPort,
|
|
33
|
-
nowIso
|
|
46
|
+
nowIso,
|
|
34
47
|
});
|
|
35
48
|
this.agentManifestService = new AgentManifestService({
|
|
36
49
|
fileSystem: deps.fileSystem,
|
|
37
|
-
pathPort: deps.pathPort
|
|
50
|
+
pathPort: deps.pathPort,
|
|
38
51
|
});
|
|
39
52
|
this.bootstrapService = new BootstrapService({
|
|
40
53
|
fileSystem: deps.fileSystem,
|
|
41
54
|
pathsProvider: deps.pathsProvider,
|
|
42
55
|
agentService: this.agentService,
|
|
43
|
-
nowIso
|
|
44
|
-
});
|
|
45
|
-
const workspaceContextService = new WorkspaceContextService({
|
|
46
|
-
fileSystem: deps.fileSystem,
|
|
47
|
-
pathPort: deps.pathPort
|
|
56
|
+
nowIso,
|
|
48
57
|
});
|
|
49
|
-
this.pluginService =
|
|
50
|
-
deps.pluginService ??
|
|
51
|
-
new PluginService({
|
|
52
|
-
fileSystem: deps.fileSystem,
|
|
53
|
-
pathPort: deps.pathPort,
|
|
54
|
-
commandRunner: deps.commandRunner
|
|
55
|
-
});
|
|
56
58
|
this.skillService = new SkillService({
|
|
57
59
|
fileSystem: deps.fileSystem,
|
|
58
60
|
pathPort: deps.pathPort,
|
|
59
|
-
pluginSkillDirsProvider: (paths) => this.pluginService.resolvePluginSkillDirectories(paths)
|
|
60
61
|
});
|
|
61
62
|
this.providerService = new ProviderService({
|
|
62
63
|
fileSystem: deps.fileSystem,
|
|
63
64
|
pathPort: deps.pathPort,
|
|
64
65
|
providerRegistry: providerRegistryFactory,
|
|
65
|
-
workspaceContextService,
|
|
66
|
-
skillService: this.skillService,
|
|
67
66
|
nowIso,
|
|
68
|
-
logger: rootLogger.child({ scope: "provider" })
|
|
67
|
+
logger: rootLogger.child({ scope: "provider" }),
|
|
69
68
|
});
|
|
70
69
|
this.sessionService = new SessionService({
|
|
71
70
|
fileSystem: deps.fileSystem,
|
|
72
71
|
pathPort: deps.pathPort,
|
|
73
72
|
commandRunner: deps.commandRunner,
|
|
74
73
|
nowIso,
|
|
75
|
-
nowMs: () => Date.now()
|
|
74
|
+
nowMs: () => Date.now(),
|
|
76
75
|
});
|
|
76
|
+
this.commandRunner = deps.commandRunner;
|
|
77
77
|
this.orchestrationService = new OrchestrationService({
|
|
78
78
|
providerService: this.providerService,
|
|
79
|
-
skillService: this.skillService,
|
|
80
79
|
agentManifestService: this.agentManifestService,
|
|
81
80
|
sessionService: this.sessionService,
|
|
82
|
-
commandRunner: deps.commandRunner,
|
|
83
81
|
fileSystem: deps.fileSystem,
|
|
84
82
|
pathPort: deps.pathPort,
|
|
85
83
|
nowIso,
|
|
86
|
-
logger: rootLogger.child({ scope: "orchestration" })
|
|
84
|
+
logger: rootLogger.child({ scope: "orchestration" }),
|
|
85
|
+
});
|
|
86
|
+
this.boardService = new BoardService({
|
|
87
|
+
fileSystem: deps.fileSystem,
|
|
88
|
+
pathPort: deps.pathPort,
|
|
89
|
+
nowIso,
|
|
90
|
+
agentManifestService: this.agentManifestService,
|
|
87
91
|
});
|
|
88
92
|
}
|
|
89
93
|
initialize() {
|
|
90
|
-
return this.
|
|
94
|
+
return this.initializeRuntimeDefaults();
|
|
91
95
|
}
|
|
92
|
-
async
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
async hardReset() {
|
|
97
|
+
const paths = this.pathsProvider.getPaths();
|
|
98
|
+
const warnings = [];
|
|
99
|
+
const deletedOpenClawAgents = [];
|
|
100
|
+
const failedOpenClawAgents = [];
|
|
101
|
+
const removedOpenClawManagedSkillDirs = [];
|
|
102
|
+
const candidateOpenClawAgentIds = new Set();
|
|
103
|
+
const localAgents = await this.agentService.listAgents(paths);
|
|
104
|
+
for (const agent of localAgents) {
|
|
105
|
+
if (agent.id === OPENCLAW_DEFAULT_AGENT_ID) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
candidateOpenClawAgentIds.add(agent.id);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const openClawAgents = await this.listOpenClawAgents(paths);
|
|
112
|
+
for (const entry of openClawAgents) {
|
|
113
|
+
if (entry.id !== OPENCLAW_DEFAULT_AGENT_ID &&
|
|
114
|
+
(pathIsWithin(paths.homeDir, entry.workspace) ||
|
|
115
|
+
pathIsWithin(paths.homeDir, entry.agentDir))) {
|
|
116
|
+
candidateOpenClawAgentIds.add(entry.id);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
warnings.push(`OpenClaw agent discovery failed: ${toErrorMessage(error)}`);
|
|
122
|
+
}
|
|
123
|
+
for (const agentId of [...candidateOpenClawAgentIds].sort((left, right) => left.localeCompare(right))) {
|
|
124
|
+
if (agentId === OPENCLAW_DEFAULT_AGENT_ID) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const deleted = await this.providerService.deleteProviderAgent(paths, agentId, { providerId: OPENCLAW_PROVIDER_ID });
|
|
129
|
+
if (deleted.code === 0 ||
|
|
130
|
+
containsAgentNotFoundMessage(deleted.stdout, deleted.stderr)) {
|
|
131
|
+
deletedOpenClawAgents.push(agentId);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const failureReason = deleted.stderr.trim() || deleted.stdout.trim();
|
|
135
|
+
if (!failureReason) {
|
|
136
|
+
warnings.push(`OpenClaw delete for "${agentId}" failed with code ${deleted.code}.`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
failedOpenClawAgents.push({
|
|
140
|
+
agentId,
|
|
141
|
+
reason: failureReason,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
if (error instanceof ProviderCommandNotFoundError) {
|
|
146
|
+
deletedOpenClawAgents.push(agentId);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
failedOpenClawAgents.push({
|
|
150
|
+
agentId,
|
|
151
|
+
reason: toErrorMessage(error),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const managedSkillsCleanup = await this.removeOpenClawManagedRoleSkills(paths);
|
|
157
|
+
removedOpenClawManagedSkillDirs.push(...managedSkillsCleanup.removedPaths);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
warnings.push(`OpenClaw managed skills cleanup failed: ${toErrorMessage(error)}`);
|
|
161
|
+
}
|
|
162
|
+
await this.fileSystem.removeDir(paths.homeDir);
|
|
163
|
+
this.openClawManagedSkillsDirCache = undefined;
|
|
164
|
+
const homeRemoved = !(await this.fileSystem.exists(paths.homeDir));
|
|
165
|
+
return {
|
|
166
|
+
homeDir: paths.homeDir,
|
|
167
|
+
homeRemoved,
|
|
168
|
+
deletedOpenClawAgents,
|
|
169
|
+
failedOpenClawAgents,
|
|
170
|
+
removedOpenClawManagedSkillDirs,
|
|
171
|
+
warnings,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async syncRuntimeDefaults() {
|
|
175
|
+
const paths = this.pathsProvider.getPaths();
|
|
176
|
+
const warnings = [];
|
|
177
|
+
let ceoSynced = false;
|
|
178
|
+
let ceoSyncCode;
|
|
179
|
+
let ceoDescriptor = (await this.agentService.listAgents(paths)).find((agent) => agent.id === DEFAULT_AGENT_ID);
|
|
180
|
+
if (!ceoDescriptor) {
|
|
181
|
+
const created = await this.agentService.ensureAgent(paths, {
|
|
182
|
+
id: DEFAULT_AGENT_ID,
|
|
183
|
+
displayName: "CEO",
|
|
184
|
+
}, {
|
|
185
|
+
type: "manager",
|
|
186
|
+
reportsTo: null,
|
|
187
|
+
role: "CEO",
|
|
188
|
+
});
|
|
189
|
+
ceoDescriptor = created.agent;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
await this.syncOpenClawRoleSkills(paths, DEFAULT_AGENT_ID);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
warnings.push(`OpenClaw role skill assignment sync for "ceo" failed: ${toErrorMessage(error)}`);
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
const ceoSync = await this.providerService.createProviderAgent(paths, DEFAULT_AGENT_ID, {
|
|
199
|
+
providerId: OPENCLAW_PROVIDER_ID,
|
|
200
|
+
displayName: ceoDescriptor.displayName,
|
|
201
|
+
workspaceDir: ceoDescriptor.workspaceDir,
|
|
202
|
+
internalConfigDir: ceoDescriptor.internalConfigDir,
|
|
203
|
+
});
|
|
204
|
+
ceoSyncCode = ceoSync.code;
|
|
205
|
+
ceoSynced =
|
|
206
|
+
ceoSync.code === 0 ||
|
|
207
|
+
containsAlreadyExistsMessage(ceoSync.stdout, ceoSync.stderr);
|
|
208
|
+
if (!ceoSynced) {
|
|
209
|
+
warnings.push(`OpenClaw sync for "ceo" failed (code ${ceoSync.code}). ${(ceoSync.stderr || ceoSync.stdout).trim()}`);
|
|
98
210
|
}
|
|
99
211
|
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
warnings.push(`OpenClaw sync for "ceo" failed: ${toErrorMessage(error)}`);
|
|
214
|
+
}
|
|
215
|
+
if (ceoSynced) {
|
|
216
|
+
try {
|
|
217
|
+
await this.ensureOpenClawAgentLocation(paths, {
|
|
218
|
+
agentId: DEFAULT_AGENT_ID,
|
|
219
|
+
displayName: ceoDescriptor.displayName,
|
|
220
|
+
workspaceDir: ceoDescriptor.workspaceDir,
|
|
221
|
+
internalConfigDir: ceoDescriptor.internalConfigDir,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
warnings.push(`OpenClaw ceo location sync failed: ${toErrorMessage(error)}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
await this.agentService.ensureCeoWorkspaceBootstrap(paths);
|
|
230
|
+
}
|
|
231
|
+
catch (error) {
|
|
232
|
+
warnings.push(`OpenGoat workspace bootstrap for "ceo" failed: ${toErrorMessage(error)}`);
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
ceoSyncCode,
|
|
236
|
+
ceoSynced,
|
|
237
|
+
warnings,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
async createAgent(rawName, options = {}) {
|
|
100
241
|
const identity = this.agentService.normalizeAgentName(rawName);
|
|
101
242
|
const paths = this.pathsProvider.getPaths();
|
|
102
|
-
const created = await this.agentService.ensureAgent(paths, identity
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
throw new Error(`
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
const externalAgentCreation = await this.providerService.createProviderAgent(paths, created.agent.id, {
|
|
124
|
-
providerId: resolvedBinding.providerId,
|
|
243
|
+
const created = await this.agentService.ensureAgent(paths, identity, {
|
|
244
|
+
type: options.type,
|
|
245
|
+
reportsTo: options.reportsTo,
|
|
246
|
+
skills: options.skills,
|
|
247
|
+
role: options.role,
|
|
248
|
+
});
|
|
249
|
+
try {
|
|
250
|
+
const workspaceSkillSync = await this.syncOpenClawRoleSkills(paths, created.agent.id);
|
|
251
|
+
created.createdPaths.push(...workspaceSkillSync.createdPaths);
|
|
252
|
+
created.skippedPaths.push(...workspaceSkillSync.skippedPaths);
|
|
253
|
+
created.skippedPaths.push(...workspaceSkillSync.removedPaths);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
if (!created.alreadyExisted) {
|
|
257
|
+
await this.agentService.removeAgent(paths, created.agent.id);
|
|
258
|
+
}
|
|
259
|
+
throw new Error(`Failed to sync OpenClaw role skills for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
260
|
+
}
|
|
261
|
+
const runtimeSync = await this.providerService.createProviderAgent(paths, created.agent.id, {
|
|
262
|
+
providerId: OPENCLAW_PROVIDER_ID,
|
|
125
263
|
displayName: created.agent.displayName,
|
|
126
264
|
workspaceDir: created.agent.workspaceDir,
|
|
127
|
-
internalConfigDir: created.agent.internalConfigDir
|
|
265
|
+
internalConfigDir: created.agent.internalConfigDir,
|
|
128
266
|
});
|
|
267
|
+
if (runtimeSync.code !== 0 &&
|
|
268
|
+
!containsAlreadyExistsMessage(runtimeSync.stdout, runtimeSync.stderr)) {
|
|
269
|
+
if (!created.alreadyExisted) {
|
|
270
|
+
await this.agentService.removeAgent(paths, created.agent.id);
|
|
271
|
+
}
|
|
272
|
+
throw new Error(`OpenClaw agent creation failed for "${created.agent.id}" (exit ${runtimeSync.code}). ${runtimeSync.stderr.trim() || runtimeSync.stdout.trim() || ""}`.trim());
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
await this.ensureOpenClawAgentLocation(paths, {
|
|
276
|
+
agentId: created.agent.id,
|
|
277
|
+
displayName: created.agent.displayName,
|
|
278
|
+
workspaceDir: created.agent.workspaceDir,
|
|
279
|
+
internalConfigDir: created.agent.internalConfigDir,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
if (!created.alreadyExisted) {
|
|
284
|
+
await this.agentService.removeAgent(paths, created.agent.id);
|
|
285
|
+
}
|
|
286
|
+
throw new Error(`OpenClaw agent location sync failed for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const workspaceBootstrap = await this.agentService.ensureAgentWorkspaceBootstrap(paths, {
|
|
290
|
+
agentId: created.agent.id,
|
|
291
|
+
displayName: created.agent.displayName,
|
|
292
|
+
role: options.role?.trim() ??
|
|
293
|
+
(created.alreadyExisted ? created.agent.role : ""),
|
|
294
|
+
});
|
|
295
|
+
created.createdPaths.push(...workspaceBootstrap.createdPaths);
|
|
296
|
+
created.skippedPaths.push(...workspaceBootstrap.skippedPaths);
|
|
297
|
+
created.skippedPaths.push(...workspaceBootstrap.removedPaths);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
if (!created.alreadyExisted) {
|
|
301
|
+
await this.agentService.removeAgent(paths, created.agent.id);
|
|
302
|
+
}
|
|
303
|
+
throw new Error(`Failed to update workspace bootstrap for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
304
|
+
}
|
|
129
305
|
return {
|
|
130
306
|
...created,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
code:
|
|
134
|
-
stdout:
|
|
135
|
-
stderr:
|
|
136
|
-
}
|
|
307
|
+
runtimeSync: {
|
|
308
|
+
runtimeId: runtimeSync.providerId,
|
|
309
|
+
code: runtimeSync.code,
|
|
310
|
+
stdout: runtimeSync.stdout,
|
|
311
|
+
stderr: runtimeSync.stderr,
|
|
312
|
+
},
|
|
137
313
|
};
|
|
138
314
|
}
|
|
139
|
-
async
|
|
315
|
+
async deleteAgent(rawAgentId, options = {}) {
|
|
140
316
|
const paths = this.pathsProvider.getPaths();
|
|
141
317
|
const agentId = normalizeAgentId(rawAgentId);
|
|
142
318
|
if (!agentId) {
|
|
143
319
|
throw new Error("Agent id cannot be empty.");
|
|
144
320
|
}
|
|
145
|
-
const
|
|
146
|
-
if (!
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
const supportsExternalAgentCreation = await this.providerSupportsExternalAgentCreation(resolvedProviderId);
|
|
152
|
-
if (!supportsExternalAgentCreation) {
|
|
153
|
-
throw new Error(`Provider "${resolvedProviderId}" does not support external agent creation.`);
|
|
154
|
-
}
|
|
155
|
-
const externalAgentCreation = await this.providerService.createProviderAgent(paths, agentId, {
|
|
156
|
-
providerId: resolvedProviderId,
|
|
157
|
-
displayName: agent.displayName,
|
|
158
|
-
workspaceDir: agent.workspaceDir,
|
|
159
|
-
internalConfigDir: agent.internalConfigDir
|
|
321
|
+
const existing = (await this.agentService.listAgents(paths)).find((entry) => entry.id === agentId);
|
|
322
|
+
if (!existing) {
|
|
323
|
+
return this.agentService.removeAgent(paths, agentId);
|
|
324
|
+
}
|
|
325
|
+
const runtimeSync = await this.providerService.deleteProviderAgent(paths, agentId, {
|
|
326
|
+
providerId: OPENCLAW_PROVIDER_ID,
|
|
160
327
|
});
|
|
328
|
+
if (runtimeSync.code !== 0 && !options.force) {
|
|
329
|
+
throw new Error(`OpenClaw agent deletion failed for "${agentId}" (exit ${runtimeSync.code}). ${runtimeSync.stderr.trim() || runtimeSync.stdout.trim() || ""}`.trim());
|
|
330
|
+
}
|
|
331
|
+
const removed = await this.agentService.removeAgent(paths, agentId);
|
|
161
332
|
return {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
333
|
+
...removed,
|
|
334
|
+
runtimeSync: {
|
|
335
|
+
runtimeId: runtimeSync.providerId,
|
|
336
|
+
code: runtimeSync.code,
|
|
337
|
+
stdout: runtimeSync.stdout,
|
|
338
|
+
stderr: runtimeSync.stderr,
|
|
339
|
+
},
|
|
166
340
|
};
|
|
167
341
|
}
|
|
168
|
-
async
|
|
169
|
-
const
|
|
170
|
-
const
|
|
171
|
-
|
|
342
|
+
async setAgentManager(rawAgentId, rawReportsTo) {
|
|
343
|
+
const paths = this.pathsProvider.getPaths();
|
|
344
|
+
const updated = await this.agentService.setAgentManager(paths, rawAgentId, rawReportsTo);
|
|
345
|
+
await this.syncOpenClawRoleSkills(paths, updated.agentId);
|
|
346
|
+
if (updated.previousReportsTo) {
|
|
347
|
+
await this.syncOpenClawRoleSkills(paths, updated.previousReportsTo);
|
|
348
|
+
}
|
|
349
|
+
if (updated.reportsTo) {
|
|
350
|
+
await this.syncOpenClawRoleSkills(paths, updated.reportsTo);
|
|
351
|
+
}
|
|
352
|
+
return updated;
|
|
172
353
|
}
|
|
173
|
-
async
|
|
354
|
+
async listAgents() {
|
|
174
355
|
const paths = this.pathsProvider.getPaths();
|
|
356
|
+
return this.agentService.listAgents(paths);
|
|
357
|
+
}
|
|
358
|
+
async listDirectReportees(rawAgentId) {
|
|
175
359
|
const agentId = normalizeAgentId(rawAgentId);
|
|
176
360
|
if (!agentId) {
|
|
177
361
|
throw new Error("Agent id cannot be empty.");
|
|
178
362
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
363
|
+
const paths = this.pathsProvider.getPaths();
|
|
364
|
+
const manifests = await this.agentManifestService.listManifests(paths);
|
|
365
|
+
assertAgentExists(manifests, agentId);
|
|
366
|
+
return manifests
|
|
367
|
+
.filter((manifest) => manifest.metadata.reportsTo === agentId)
|
|
368
|
+
.map((manifest) => manifest.agentId)
|
|
369
|
+
.sort((left, right) => left.localeCompare(right));
|
|
370
|
+
}
|
|
371
|
+
async listAllReportees(rawAgentId) {
|
|
372
|
+
const agentId = normalizeAgentId(rawAgentId);
|
|
373
|
+
if (!agentId) {
|
|
374
|
+
throw new Error("Agent id cannot be empty.");
|
|
183
375
|
}
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
376
|
+
const paths = this.pathsProvider.getPaths();
|
|
377
|
+
const manifests = await this.agentManifestService.listManifests(paths);
|
|
378
|
+
assertAgentExists(manifests, agentId);
|
|
379
|
+
return collectAllReportees(manifests, agentId);
|
|
380
|
+
}
|
|
381
|
+
async getAgentInfo(rawAgentId) {
|
|
382
|
+
const agentId = normalizeAgentId(rawAgentId);
|
|
383
|
+
if (!agentId) {
|
|
384
|
+
throw new Error("Agent id cannot be empty.");
|
|
187
385
|
}
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
386
|
+
const paths = this.pathsProvider.getPaths();
|
|
387
|
+
const [agents, manifests] = await Promise.all([
|
|
388
|
+
this.agentService.listAgents(paths),
|
|
389
|
+
this.agentManifestService.listManifests(paths),
|
|
390
|
+
]);
|
|
391
|
+
const descriptorsById = new Map(agents.map((agent) => [agent.id, agent]));
|
|
392
|
+
const agent = descriptorsById.get(agentId);
|
|
393
|
+
if (!agent) {
|
|
394
|
+
throw new Error(`Agent "${agentId}" does not exist.`);
|
|
395
|
+
}
|
|
396
|
+
const totalReportees = collectAllReportees(manifests, agentId).length;
|
|
397
|
+
const directReportees = manifests
|
|
398
|
+
.filter((manifest) => manifest.metadata.reportsTo === agentId)
|
|
399
|
+
.map((manifest) => {
|
|
400
|
+
const descriptor = descriptorsById.get(manifest.agentId);
|
|
401
|
+
const name = descriptor?.displayName?.trim() ||
|
|
402
|
+
manifest.metadata.name ||
|
|
403
|
+
manifest.agentId;
|
|
404
|
+
const role = descriptor?.role?.trim() || manifest.metadata.description || "Agent";
|
|
405
|
+
return {
|
|
406
|
+
id: manifest.agentId,
|
|
407
|
+
name,
|
|
408
|
+
role,
|
|
409
|
+
totalReportees: collectAllReportees(manifests, manifest.agentId)
|
|
410
|
+
.length,
|
|
411
|
+
};
|
|
412
|
+
})
|
|
413
|
+
.sort((left, right) => left.id.localeCompare(right.id));
|
|
191
414
|
return {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
stderr: externalAgentDeletion.stderr
|
|
198
|
-
}
|
|
415
|
+
id: agent.id,
|
|
416
|
+
name: agent.displayName,
|
|
417
|
+
role: agent.role,
|
|
418
|
+
totalReportees,
|
|
419
|
+
directReportees,
|
|
199
420
|
};
|
|
200
421
|
}
|
|
201
|
-
async listAgents() {
|
|
202
|
-
const paths = this.pathsProvider.getPaths();
|
|
203
|
-
return this.agentService.listAgents(paths);
|
|
204
|
-
}
|
|
205
422
|
listProviders() {
|
|
206
423
|
return this.providerService.listProviders();
|
|
207
424
|
}
|
|
@@ -226,9 +443,15 @@ export class OpenGoatService {
|
|
|
226
443
|
}
|
|
227
444
|
async setAgentProvider(agentId, providerId) {
|
|
228
445
|
const paths = this.pathsProvider.getPaths();
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
446
|
+
return this.providerService.setAgentProvider(paths, agentId, providerId);
|
|
447
|
+
}
|
|
448
|
+
async getOpenClawGatewayConfig() {
|
|
449
|
+
const paths = this.pathsProvider.getPaths();
|
|
450
|
+
return this.providerService.getOpenClawGatewayConfig(paths, process.env);
|
|
451
|
+
}
|
|
452
|
+
async setOpenClawGatewayConfig(config) {
|
|
453
|
+
const paths = this.pathsProvider.getPaths();
|
|
454
|
+
return this.providerService.setOpenClawGatewayConfig(paths, config);
|
|
232
455
|
}
|
|
233
456
|
async routeMessage(agentId, message) {
|
|
234
457
|
const paths = this.pathsProvider.getPaths();
|
|
@@ -238,46 +461,192 @@ export class OpenGoatService {
|
|
|
238
461
|
const paths = this.pathsProvider.getPaths();
|
|
239
462
|
return this.orchestrationService.runAgent(paths, agentId, options);
|
|
240
463
|
}
|
|
241
|
-
async
|
|
464
|
+
async createTask(actorId, options) {
|
|
242
465
|
const paths = this.pathsProvider.getPaths();
|
|
243
|
-
return this.
|
|
466
|
+
return this.boardService.createTask(paths, actorId, options);
|
|
244
467
|
}
|
|
245
|
-
async
|
|
468
|
+
async listTasks(options = {}) {
|
|
246
469
|
const paths = this.pathsProvider.getPaths();
|
|
247
|
-
return this.
|
|
470
|
+
return this.boardService.listTasks(paths, options);
|
|
248
471
|
}
|
|
249
|
-
async
|
|
472
|
+
async listLatestTasks(options = {}) {
|
|
473
|
+
const paths = this.pathsProvider.getPaths();
|
|
474
|
+
return this.boardService.listLatestTasks(paths, options);
|
|
475
|
+
}
|
|
476
|
+
async listLatestTasksPage(options = {}) {
|
|
250
477
|
const paths = this.pathsProvider.getPaths();
|
|
251
|
-
return this.
|
|
478
|
+
return this.boardService.listLatestTasksPage(paths, options);
|
|
252
479
|
}
|
|
253
|
-
async
|
|
480
|
+
async getTask(taskId) {
|
|
254
481
|
const paths = this.pathsProvider.getPaths();
|
|
255
|
-
return this.
|
|
482
|
+
return this.boardService.getTask(paths, taskId);
|
|
256
483
|
}
|
|
257
|
-
async
|
|
484
|
+
async deleteTasks(actorId, taskIds) {
|
|
258
485
|
const paths = this.pathsProvider.getPaths();
|
|
259
|
-
return this.
|
|
486
|
+
return this.boardService.deleteTasks(paths, actorId, taskIds);
|
|
260
487
|
}
|
|
261
|
-
async
|
|
488
|
+
async updateTaskStatus(actorId, taskId, status, reason) {
|
|
262
489
|
const paths = this.pathsProvider.getPaths();
|
|
263
|
-
return this.
|
|
490
|
+
return this.boardService.updateTaskStatus(paths, actorId, taskId, status, reason);
|
|
264
491
|
}
|
|
265
|
-
async
|
|
492
|
+
async addTaskBlocker(actorId, taskId, blocker) {
|
|
266
493
|
const paths = this.pathsProvider.getPaths();
|
|
267
|
-
|
|
494
|
+
return this.boardService.addTaskBlocker(paths, actorId, taskId, blocker);
|
|
268
495
|
}
|
|
269
|
-
async
|
|
496
|
+
async addTaskArtifact(actorId, taskId, content) {
|
|
270
497
|
const paths = this.pathsProvider.getPaths();
|
|
271
|
-
|
|
498
|
+
return this.boardService.addTaskArtifact(paths, actorId, taskId, content);
|
|
272
499
|
}
|
|
273
|
-
async
|
|
500
|
+
async addTaskWorklog(actorId, taskId, content) {
|
|
274
501
|
const paths = this.pathsProvider.getPaths();
|
|
275
|
-
return this.
|
|
502
|
+
return this.boardService.addTaskWorklog(paths, actorId, taskId, content);
|
|
503
|
+
}
|
|
504
|
+
async runTaskCronCycle(options = {}) {
|
|
505
|
+
const paths = this.pathsProvider.getPaths();
|
|
506
|
+
const ranAt = this.resolveNowIso();
|
|
507
|
+
const manifests = await this.agentManifestService.listManifests(paths);
|
|
508
|
+
const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
|
|
509
|
+
const inactiveMinutes = resolveInactiveMinutes(options.inactiveMinutes);
|
|
510
|
+
const inactiveCandidates = await this.collectInactiveAgents(paths, manifests, inactiveMinutes);
|
|
511
|
+
const tasks = await this.boardService.listTasks(paths, { limit: 10_000 });
|
|
512
|
+
const dispatches = [];
|
|
513
|
+
let scannedTasks = tasks.length;
|
|
514
|
+
let todoTasks = 0;
|
|
515
|
+
let blockedTasks = 0;
|
|
516
|
+
for (const task of tasks) {
|
|
517
|
+
if (task.status !== "todo" && task.status !== "blocked") {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (task.status === "todo") {
|
|
521
|
+
todoTasks += 1;
|
|
522
|
+
const targetAgentId = task.assignedTo;
|
|
523
|
+
const sessionRef = buildTaskSessionRef(targetAgentId, task.taskId);
|
|
524
|
+
const message = buildTodoTaskMessage({ task });
|
|
525
|
+
const result = await this.dispatchAutomationMessage(paths, targetAgentId, sessionRef, message);
|
|
526
|
+
dispatches.push({
|
|
527
|
+
kind: "todo",
|
|
528
|
+
targetAgentId,
|
|
529
|
+
sessionRef,
|
|
530
|
+
taskId: task.taskId,
|
|
531
|
+
ok: result.ok,
|
|
532
|
+
error: result.error,
|
|
533
|
+
});
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
blockedTasks += 1;
|
|
537
|
+
const assigneeManifest = manifestsById.get(task.assignedTo);
|
|
538
|
+
const managerAgentId = normalizeAgentId(assigneeManifest?.metadata.reportsTo ?? "") ||
|
|
539
|
+
DEFAULT_AGENT_ID;
|
|
540
|
+
const sessionRef = buildTaskSessionRef(managerAgentId, task.taskId);
|
|
541
|
+
const message = buildBlockedTaskMessage({ task });
|
|
542
|
+
const result = await this.dispatchAutomationMessage(paths, managerAgentId, sessionRef, message);
|
|
543
|
+
dispatches.push({
|
|
544
|
+
kind: "blocked",
|
|
545
|
+
targetAgentId: managerAgentId,
|
|
546
|
+
sessionRef,
|
|
547
|
+
taskId: task.taskId,
|
|
548
|
+
ok: result.ok,
|
|
549
|
+
error: result.error,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
for (const candidate of inactiveCandidates) {
|
|
553
|
+
const sessionRef = buildInactiveSessionRef(candidate.managerAgentId, candidate.subjectAgentId);
|
|
554
|
+
const message = buildInactiveAgentMessage({
|
|
555
|
+
managerAgentId: candidate.managerAgentId,
|
|
556
|
+
subjectAgentId: candidate.subjectAgentId,
|
|
557
|
+
subjectName: candidate.subjectName,
|
|
558
|
+
role: candidate.role,
|
|
559
|
+
inactiveMinutes,
|
|
560
|
+
lastActionTimestamp: candidate.lastActionTimestamp,
|
|
561
|
+
});
|
|
562
|
+
const result = await this.dispatchAutomationMessage(paths, candidate.managerAgentId, sessionRef, message);
|
|
563
|
+
dispatches.push({
|
|
564
|
+
kind: "inactive",
|
|
565
|
+
targetAgentId: candidate.managerAgentId,
|
|
566
|
+
sessionRef,
|
|
567
|
+
subjectAgentId: candidate.subjectAgentId,
|
|
568
|
+
ok: result.ok,
|
|
569
|
+
error: result.error,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
const failed = dispatches.filter((entry) => !entry.ok).length;
|
|
573
|
+
return {
|
|
574
|
+
ranAt,
|
|
575
|
+
scannedTasks,
|
|
576
|
+
todoTasks,
|
|
577
|
+
blockedTasks,
|
|
578
|
+
inactiveAgents: inactiveCandidates.length,
|
|
579
|
+
sent: dispatches.length - failed,
|
|
580
|
+
failed,
|
|
581
|
+
dispatches,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
async listSkills(agentId = DEFAULT_AGENT_ID) {
|
|
585
|
+
const paths = this.pathsProvider.getPaths();
|
|
586
|
+
return this.skillService.listSkills(paths, agentId);
|
|
587
|
+
}
|
|
588
|
+
async listGlobalSkills() {
|
|
589
|
+
const paths = this.pathsProvider.getPaths();
|
|
590
|
+
return this.skillService.listGlobalSkills(paths);
|
|
591
|
+
}
|
|
592
|
+
async installSkill(request) {
|
|
593
|
+
const paths = this.pathsProvider.getPaths();
|
|
594
|
+
const result = await this.skillService.installSkill(paths, request);
|
|
595
|
+
if (result.scope === "agent" && result.agentId) {
|
|
596
|
+
await this.syncOpenClawRoleSkills(paths, result.agentId);
|
|
597
|
+
}
|
|
598
|
+
return result;
|
|
599
|
+
}
|
|
600
|
+
async runOpenClaw(args, options = {}) {
|
|
601
|
+
if (!this.commandRunner) {
|
|
602
|
+
throw new Error("OpenClaw passthrough is unavailable: command runner was not configured.");
|
|
603
|
+
}
|
|
604
|
+
const sanitized = args.map((value) => value.trim()).filter(Boolean);
|
|
605
|
+
if (sanitized.length === 0) {
|
|
606
|
+
throw new Error("OpenClaw passthrough requires at least one argument.");
|
|
607
|
+
}
|
|
608
|
+
const executionEnv = prepareOpenClawCommandEnv(options.env ?? process.env);
|
|
609
|
+
const command = executionEnv.OPENGOAT_OPENCLAW_CMD?.trim() ||
|
|
610
|
+
executionEnv.OPENCLAW_CMD?.trim() ||
|
|
611
|
+
process.env.OPENGOAT_OPENCLAW_CMD?.trim() ||
|
|
612
|
+
process.env.OPENCLAW_CMD?.trim() ||
|
|
613
|
+
"openclaw";
|
|
614
|
+
try {
|
|
615
|
+
return await this.commandRunner.run({
|
|
616
|
+
command,
|
|
617
|
+
args: sanitized,
|
|
618
|
+
cwd: options.cwd,
|
|
619
|
+
env: executionEnv,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
if (isSpawnPermissionOrMissing(error)) {
|
|
624
|
+
throw new ProviderCommandNotFoundError(OPENCLAW_PROVIDER_ID, command);
|
|
625
|
+
}
|
|
626
|
+
throw error;
|
|
627
|
+
}
|
|
276
628
|
}
|
|
277
629
|
async listSessions(agentId = DEFAULT_AGENT_ID, options = {}) {
|
|
278
630
|
const paths = this.pathsProvider.getPaths();
|
|
279
631
|
return this.sessionService.listSessions(paths, agentId, options);
|
|
280
632
|
}
|
|
633
|
+
async prepareSession(agentId = DEFAULT_AGENT_ID, options = {}) {
|
|
634
|
+
const paths = this.pathsProvider.getPaths();
|
|
635
|
+
const prepared = await this.sessionService.prepareRunSession(paths, agentId, {
|
|
636
|
+
sessionRef: options.sessionRef,
|
|
637
|
+
projectPath: options.projectPath,
|
|
638
|
+
forceNew: options.forceNew,
|
|
639
|
+
userMessage: "",
|
|
640
|
+
});
|
|
641
|
+
if (!prepared.enabled) {
|
|
642
|
+
throw new Error("Session preparation was disabled.");
|
|
643
|
+
}
|
|
644
|
+
return prepared.info;
|
|
645
|
+
}
|
|
646
|
+
async getAgentLastAction(agentId = DEFAULT_AGENT_ID) {
|
|
647
|
+
const paths = this.pathsProvider.getPaths();
|
|
648
|
+
return this.sessionService.getLastAgentAction(paths, agentId);
|
|
649
|
+
}
|
|
281
650
|
async getSessionHistory(agentId = DEFAULT_AGENT_ID, options = {}) {
|
|
282
651
|
const paths = this.pathsProvider.getPaths();
|
|
283
652
|
return this.sessionService.getSessionHistory(paths, agentId, options);
|
|
@@ -304,5 +673,506 @@ export class OpenGoatService {
|
|
|
304
673
|
getPaths() {
|
|
305
674
|
return this.pathsProvider.getPaths();
|
|
306
675
|
}
|
|
676
|
+
async dispatchAutomationMessage(paths, agentId, sessionRef, message) {
|
|
677
|
+
try {
|
|
678
|
+
const result = await this.orchestrationService.runAgent(paths, agentId, {
|
|
679
|
+
message,
|
|
680
|
+
sessionRef,
|
|
681
|
+
env: process.env,
|
|
682
|
+
});
|
|
683
|
+
if (result.code !== 0) {
|
|
684
|
+
return {
|
|
685
|
+
ok: false,
|
|
686
|
+
error: (result.stderr ||
|
|
687
|
+
result.stdout ||
|
|
688
|
+
`Runtime exited with code ${result.code}.`).trim(),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
return { ok: true };
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
return {
|
|
695
|
+
ok: false,
|
|
696
|
+
error: toErrorMessage(error),
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
resolveNowIso() {
|
|
701
|
+
return this.nowIso();
|
|
702
|
+
}
|
|
703
|
+
async initializeRuntimeDefaults() {
|
|
704
|
+
const initialization = await this.bootstrapService.initialize();
|
|
705
|
+
try {
|
|
706
|
+
await this.syncRuntimeDefaults();
|
|
707
|
+
}
|
|
708
|
+
catch {
|
|
709
|
+
// Startup remains functional even if OpenClaw CLI/runtime is unavailable.
|
|
710
|
+
}
|
|
711
|
+
return initialization;
|
|
712
|
+
}
|
|
713
|
+
resolveNowMs() {
|
|
714
|
+
return Date.now();
|
|
715
|
+
}
|
|
716
|
+
async syncOpenClawRoleSkills(paths, rawAgentId) {
|
|
717
|
+
const agentId = normalizeAgentId(rawAgentId);
|
|
718
|
+
if (!agentId) {
|
|
719
|
+
throw new Error("Agent id cannot be empty.");
|
|
720
|
+
}
|
|
721
|
+
const createdPaths = [];
|
|
722
|
+
const skippedPaths = [];
|
|
723
|
+
const removedPaths = [];
|
|
724
|
+
const managedSkillsSync = await this.removeOpenClawManagedRoleSkills(paths);
|
|
725
|
+
createdPaths.push(...managedSkillsSync.createdPaths);
|
|
726
|
+
skippedPaths.push(...managedSkillsSync.skippedPaths);
|
|
727
|
+
removedPaths.push(...managedSkillsSync.removedPaths);
|
|
728
|
+
const syncedAgents = new Set();
|
|
729
|
+
const syncAgent = async (targetAgentId) => {
|
|
730
|
+
if (syncedAgents.has(targetAgentId)) {
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
syncedAgents.add(targetAgentId);
|
|
734
|
+
const sync = await this.agentService.ensureAgentWorkspaceRoleSkills(paths, targetAgentId);
|
|
735
|
+
createdPaths.push(...sync.createdPaths);
|
|
736
|
+
skippedPaths.push(...sync.skippedPaths);
|
|
737
|
+
removedPaths.push(...sync.removedPaths);
|
|
738
|
+
};
|
|
739
|
+
await syncAgent(agentId);
|
|
740
|
+
const manifest = await this.agentManifestService.getManifest(paths, agentId);
|
|
741
|
+
const managerAgentId = normalizeAgentId(manifest.metadata.reportsTo ?? "");
|
|
742
|
+
if (managerAgentId) {
|
|
743
|
+
await syncAgent(managerAgentId);
|
|
744
|
+
}
|
|
745
|
+
return {
|
|
746
|
+
createdPaths,
|
|
747
|
+
skippedPaths,
|
|
748
|
+
removedPaths,
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
async removeOpenClawManagedRoleSkills(paths) {
|
|
752
|
+
if (!this.commandRunner) {
|
|
753
|
+
return {
|
|
754
|
+
createdPaths: [],
|
|
755
|
+
skippedPaths: ["openclaw-managed-skills:command-runner-unavailable"],
|
|
756
|
+
removedPaths: [],
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
const managedSkillsDir = await this.resolveOpenClawManagedSkillsDir(paths);
|
|
760
|
+
if (!managedSkillsDir) {
|
|
761
|
+
return {
|
|
762
|
+
createdPaths: [],
|
|
763
|
+
skippedPaths: ["openclaw-managed-skills:unresolved"],
|
|
764
|
+
removedPaths: [],
|
|
765
|
+
};
|
|
766
|
+
}
|
|
767
|
+
const skippedPaths = [];
|
|
768
|
+
const removedPaths = [];
|
|
769
|
+
for (const legacySkillId of [
|
|
770
|
+
"board-manager",
|
|
771
|
+
"board-individual",
|
|
772
|
+
"og-board-manager",
|
|
773
|
+
"og-board-individual",
|
|
774
|
+
"manager",
|
|
775
|
+
"board-user",
|
|
776
|
+
]) {
|
|
777
|
+
const legacyDir = this.pathPort.join(managedSkillsDir, legacySkillId);
|
|
778
|
+
if (!(await this.fileSystem.exists(legacyDir))) {
|
|
779
|
+
skippedPaths.push(legacyDir);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
await this.fileSystem.removeDir(legacyDir);
|
|
783
|
+
removedPaths.push(legacyDir);
|
|
784
|
+
}
|
|
785
|
+
return {
|
|
786
|
+
createdPaths: [],
|
|
787
|
+
skippedPaths,
|
|
788
|
+
removedPaths,
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
async resolveOpenClawManagedSkillsDir(paths) {
|
|
792
|
+
if (this.openClawManagedSkillsDirCache !== undefined) {
|
|
793
|
+
return this.openClawManagedSkillsDirCache;
|
|
794
|
+
}
|
|
795
|
+
const providerConfig = await this.providerService.getProviderConfig(paths, OPENCLAW_PROVIDER_ID);
|
|
796
|
+
const env = {
|
|
797
|
+
...process.env,
|
|
798
|
+
...(providerConfig?.env ?? {}),
|
|
799
|
+
};
|
|
800
|
+
const skillsList = await this.runOpenClaw(["skills", "list", "--json"], {
|
|
801
|
+
env,
|
|
802
|
+
});
|
|
803
|
+
if (skillsList.code !== 0) {
|
|
804
|
+
throw new Error(`OpenClaw skills list failed (exit ${skillsList.code}). ${skillsList.stderr.trim() || skillsList.stdout.trim() || ""}`.trim());
|
|
805
|
+
}
|
|
806
|
+
let parsed;
|
|
807
|
+
try {
|
|
808
|
+
parsed = JSON.parse(skillsList.stdout);
|
|
809
|
+
}
|
|
810
|
+
catch {
|
|
811
|
+
throw new Error("OpenClaw skills list returned non-JSON output; cannot resolve managed skills directory.");
|
|
812
|
+
}
|
|
813
|
+
const managedSkillsDir = extractManagedSkillsDir(parsed);
|
|
814
|
+
this.openClawManagedSkillsDirCache = managedSkillsDir;
|
|
815
|
+
return managedSkillsDir;
|
|
816
|
+
}
|
|
817
|
+
async listOpenClawAgents(paths) {
|
|
818
|
+
if (!this.commandRunner) {
|
|
819
|
+
return [];
|
|
820
|
+
}
|
|
821
|
+
const env = await this.resolveOpenClawEnv(paths);
|
|
822
|
+
const listed = await this.runOpenClaw(["agents", "list", "--json"], {
|
|
823
|
+
env,
|
|
824
|
+
});
|
|
825
|
+
if (listed.code !== 0) {
|
|
826
|
+
throw new Error(`OpenClaw agents list failed (exit ${listed.code}). ${listed.stderr.trim() || listed.stdout.trim() || ""}`.trim());
|
|
827
|
+
}
|
|
828
|
+
let parsed;
|
|
829
|
+
try {
|
|
830
|
+
parsed = JSON.parse(listed.stdout);
|
|
831
|
+
}
|
|
832
|
+
catch {
|
|
833
|
+
throw new Error("OpenClaw agents list returned non-JSON output; cannot inspect agents.");
|
|
834
|
+
}
|
|
835
|
+
return extractOpenClawAgents(parsed);
|
|
836
|
+
}
|
|
837
|
+
async ensureOpenClawAgentLocation(paths, params) {
|
|
838
|
+
if (!this.commandRunner) {
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const env = await this.resolveOpenClawEnv(paths);
|
|
842
|
+
const listed = await this.runOpenClaw(["agents", "list", "--json"], {
|
|
843
|
+
env,
|
|
844
|
+
});
|
|
845
|
+
if (listed.code !== 0) {
|
|
846
|
+
throw new Error(`OpenClaw agents list failed (exit ${listed.code}). ${listed.stderr.trim() || listed.stdout.trim() || ""}`.trim());
|
|
847
|
+
}
|
|
848
|
+
let parsed;
|
|
849
|
+
try {
|
|
850
|
+
parsed = JSON.parse(listed.stdout);
|
|
851
|
+
}
|
|
852
|
+
catch {
|
|
853
|
+
throw new Error("OpenClaw agents list returned non-JSON output; cannot verify agent location.");
|
|
854
|
+
}
|
|
855
|
+
const entry = extractOpenClawAgentEntry(parsed, params.agentId);
|
|
856
|
+
if (!entry) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
if (pathMatches(entry.workspace, params.workspaceDir) &&
|
|
860
|
+
pathMatches(entry.agentDir, params.internalConfigDir)) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const deleted = await this.providerService.deleteProviderAgent(paths, params.agentId, { providerId: OPENCLAW_PROVIDER_ID });
|
|
864
|
+
if (deleted.code !== 0) {
|
|
865
|
+
throw new Error(`OpenClaw agent location repair failed deleting "${params.agentId}" (exit ${deleted.code}). ${deleted.stderr.trim() || deleted.stdout.trim() || ""}`.trim());
|
|
866
|
+
}
|
|
867
|
+
const recreated = await this.providerService.createProviderAgent(paths, params.agentId, {
|
|
868
|
+
providerId: OPENCLAW_PROVIDER_ID,
|
|
869
|
+
displayName: params.displayName,
|
|
870
|
+
workspaceDir: params.workspaceDir,
|
|
871
|
+
internalConfigDir: params.internalConfigDir,
|
|
872
|
+
});
|
|
873
|
+
if (recreated.code !== 0 &&
|
|
874
|
+
!containsAlreadyExistsMessage(recreated.stdout, recreated.stderr)) {
|
|
875
|
+
throw new Error(`OpenClaw agent location repair failed creating "${params.agentId}" (exit ${recreated.code}). ${recreated.stderr.trim() || recreated.stdout.trim() || ""}`.trim());
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
async resolveOpenClawEnv(paths) {
|
|
879
|
+
const providerConfig = await this.providerService.getProviderConfig(paths, OPENCLAW_PROVIDER_ID);
|
|
880
|
+
return {
|
|
881
|
+
...(providerConfig?.env ?? {}),
|
|
882
|
+
...process.env,
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
async collectInactiveAgents(paths, manifests, inactiveMinutes) {
|
|
886
|
+
const nowMs = this.resolveNowMs();
|
|
887
|
+
const inactiveCutoffMs = nowMs - inactiveMinutes * 60_000;
|
|
888
|
+
const inactive = [];
|
|
889
|
+
for (const manifest of manifests) {
|
|
890
|
+
const managerAgentId = normalizeAgentId(manifest.metadata.reportsTo ?? "");
|
|
891
|
+
if (!managerAgentId) {
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
const lastAction = await this.sessionService.getLastAgentAction(paths, manifest.agentId);
|
|
895
|
+
if (lastAction && lastAction.timestamp >= inactiveCutoffMs) {
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
inactive.push({
|
|
899
|
+
managerAgentId,
|
|
900
|
+
subjectAgentId: manifest.agentId,
|
|
901
|
+
subjectName: manifest.metadata.name,
|
|
902
|
+
role: manifest.metadata.description,
|
|
903
|
+
lastActionTimestamp: lastAction?.timestamp,
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
return inactive;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function containsAlreadyExistsMessage(stdout, stderr) {
|
|
910
|
+
const text = `${stdout}\n${stderr}`.toLowerCase();
|
|
911
|
+
return /\balready exists?\b/.test(text);
|
|
912
|
+
}
|
|
913
|
+
function containsAgentNotFoundMessage(stdout, stderr) {
|
|
914
|
+
const text = `${stdout}\n${stderr}`.toLowerCase();
|
|
915
|
+
return /\b(not found|does not exist|no such agent|unknown agent|could not find|no agent found|not exist)\b/.test(text);
|
|
916
|
+
}
|
|
917
|
+
function toErrorMessage(error) {
|
|
918
|
+
if (error instanceof Error) {
|
|
919
|
+
return error.message;
|
|
920
|
+
}
|
|
921
|
+
return String(error);
|
|
922
|
+
}
|
|
923
|
+
function resolveInactiveMinutes(value) {
|
|
924
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
925
|
+
return 30;
|
|
926
|
+
}
|
|
927
|
+
return Math.floor(value);
|
|
928
|
+
}
|
|
929
|
+
function extractManagedSkillsDir(payload) {
|
|
930
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
const record = payload;
|
|
934
|
+
if (typeof record.managedSkillsDir !== "string") {
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
const managedSkillsDir = record.managedSkillsDir.trim();
|
|
938
|
+
return managedSkillsDir || null;
|
|
939
|
+
}
|
|
940
|
+
function extractOpenClawAgents(payload) {
|
|
941
|
+
if (!Array.isArray(payload)) {
|
|
942
|
+
return [];
|
|
943
|
+
}
|
|
944
|
+
const entries = [];
|
|
945
|
+
for (const entry of payload) {
|
|
946
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
const record = entry;
|
|
950
|
+
const id = normalizeAgentId(String(record.id ?? ""));
|
|
951
|
+
if (!id) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
entries.push({
|
|
955
|
+
id,
|
|
956
|
+
workspace: typeof record.workspace === "string" ? record.workspace : "",
|
|
957
|
+
agentDir: typeof record.agentDir === "string" ? record.agentDir : "",
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return entries;
|
|
961
|
+
}
|
|
962
|
+
function extractOpenClawAgentEntry(payload, agentId) {
|
|
963
|
+
const normalizedAgentId = normalizeAgentId(agentId);
|
|
964
|
+
if (!normalizedAgentId) {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
for (const entry of extractOpenClawAgents(payload)) {
|
|
968
|
+
if (entry.id !== normalizedAgentId) {
|
|
969
|
+
continue;
|
|
970
|
+
}
|
|
971
|
+
return {
|
|
972
|
+
workspace: entry.workspace,
|
|
973
|
+
agentDir: entry.agentDir,
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
function pathMatches(left, right) {
|
|
979
|
+
const leftNormalized = normalizePathForCompare(left);
|
|
980
|
+
const rightNormalized = normalizePathForCompare(right);
|
|
981
|
+
if (!leftNormalized || !rightNormalized) {
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
return leftNormalized === rightNormalized;
|
|
985
|
+
}
|
|
986
|
+
function pathIsWithin(containerPath, candidatePath) {
|
|
987
|
+
const normalizedContainer = normalizePathForCompare(containerPath);
|
|
988
|
+
const normalizedCandidate = normalizePathForCompare(candidatePath);
|
|
989
|
+
if (!normalizedContainer || !normalizedCandidate) {
|
|
990
|
+
return false;
|
|
991
|
+
}
|
|
992
|
+
const relative = path.relative(normalizedContainer, normalizedCandidate);
|
|
993
|
+
if (!relative) {
|
|
994
|
+
return true;
|
|
995
|
+
}
|
|
996
|
+
return !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
997
|
+
}
|
|
998
|
+
function normalizePathForCompare(value) {
|
|
999
|
+
const trimmed = value.trim();
|
|
1000
|
+
if (!trimmed) {
|
|
1001
|
+
return "";
|
|
1002
|
+
}
|
|
1003
|
+
const resolved = path.resolve(trimmed);
|
|
1004
|
+
if (process.platform === "win32") {
|
|
1005
|
+
return resolved.toLowerCase();
|
|
1006
|
+
}
|
|
1007
|
+
return resolved;
|
|
1008
|
+
}
|
|
1009
|
+
function buildTaskSessionRef(agentId, taskId) {
|
|
1010
|
+
const normalizedAgentId = normalizeAgentId(agentId) || DEFAULT_AGENT_ID;
|
|
1011
|
+
const normalizedTaskId = normalizeAgentId(taskId) || "task";
|
|
1012
|
+
return `agent:${normalizedAgentId}:agent_${normalizedAgentId}_task_${normalizedTaskId}`;
|
|
1013
|
+
}
|
|
1014
|
+
function buildInactiveSessionRef(managerAgentId, subjectAgentId) {
|
|
1015
|
+
const manager = normalizeAgentId(managerAgentId) || DEFAULT_AGENT_ID;
|
|
1016
|
+
const subject = normalizeAgentId(subjectAgentId) || "agent";
|
|
1017
|
+
return `agent:${manager}:agent_${manager}_inactive_${subject}`;
|
|
1018
|
+
}
|
|
1019
|
+
function buildTodoTaskMessage(params) {
|
|
1020
|
+
const blockers = params.task.blockers.length > 0 ? params.task.blockers.join("; ") : "None";
|
|
1021
|
+
const artifacts = params.task.artifacts.length > 0
|
|
1022
|
+
? params.task.artifacts
|
|
1023
|
+
.map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
|
|
1024
|
+
.join("\n")
|
|
1025
|
+
: "- None";
|
|
1026
|
+
const worklog = params.task.worklog.length > 0
|
|
1027
|
+
? params.task.worklog
|
|
1028
|
+
.map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
|
|
1029
|
+
.join("\n")
|
|
1030
|
+
: "- None";
|
|
1031
|
+
return [
|
|
1032
|
+
`Task #${params.task.taskId} is assigned to you and currently in TODO. Please work on it now.`,
|
|
1033
|
+
"",
|
|
1034
|
+
`Task ID: ${params.task.taskId}`,
|
|
1035
|
+
`Title: ${params.task.title}`,
|
|
1036
|
+
`Description: ${params.task.description}`,
|
|
1037
|
+
`Project: ${params.task.project}`,
|
|
1038
|
+
`Status: ${params.task.status}`,
|
|
1039
|
+
`Owner: @${params.task.owner}`,
|
|
1040
|
+
`Assigned to: @${params.task.assignedTo}`,
|
|
1041
|
+
`Created at: ${params.task.createdAt}`,
|
|
1042
|
+
`Blockers: ${blockers}`,
|
|
1043
|
+
"Artifacts:",
|
|
1044
|
+
artifacts,
|
|
1045
|
+
"Worklog:",
|
|
1046
|
+
worklog,
|
|
1047
|
+
].join("\n");
|
|
1048
|
+
}
|
|
1049
|
+
function buildBlockedTaskMessage(params) {
|
|
1050
|
+
const blockerReason = params.task.blockers.length > 0
|
|
1051
|
+
? params.task.blockers.join("; ")
|
|
1052
|
+
: params.task.statusReason?.trim() || "no blocker details were provided";
|
|
1053
|
+
const artifacts = params.task.artifacts.length > 0
|
|
1054
|
+
? params.task.artifacts
|
|
1055
|
+
.map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
|
|
1056
|
+
.join("\n")
|
|
1057
|
+
: "- None";
|
|
1058
|
+
const worklog = params.task.worklog.length > 0
|
|
1059
|
+
? params.task.worklog
|
|
1060
|
+
.map((entry) => `- ${entry.createdAt} @${entry.createdBy}: ${entry.content}`)
|
|
1061
|
+
.join("\n")
|
|
1062
|
+
: "- None";
|
|
1063
|
+
return [
|
|
1064
|
+
`Task #${params.task.taskId}, assigned to your reportee "@${params.task.assignedTo}" is blocked because of ${blockerReason}. Help unblocking it.`,
|
|
1065
|
+
"",
|
|
1066
|
+
`Task ID: ${params.task.taskId}`,
|
|
1067
|
+
`Title: ${params.task.title}`,
|
|
1068
|
+
`Description: ${params.task.description}`,
|
|
1069
|
+
`Project: ${params.task.project}`,
|
|
1070
|
+
`Status: ${params.task.status}`,
|
|
1071
|
+
`Owner: @${params.task.owner}`,
|
|
1072
|
+
`Assigned to: @${params.task.assignedTo}`,
|
|
1073
|
+
`Created at: ${params.task.createdAt}`,
|
|
1074
|
+
"Artifacts:",
|
|
1075
|
+
artifacts,
|
|
1076
|
+
"Worklog:",
|
|
1077
|
+
worklog,
|
|
1078
|
+
].join("\n");
|
|
1079
|
+
}
|
|
1080
|
+
function buildInactiveAgentMessage(params) {
|
|
1081
|
+
const lastAction = typeof params.lastActionTimestamp === "number" &&
|
|
1082
|
+
Number.isFinite(params.lastActionTimestamp)
|
|
1083
|
+
? new Date(params.lastActionTimestamp).toISOString()
|
|
1084
|
+
: "No recorded assistant actions yet";
|
|
1085
|
+
return [
|
|
1086
|
+
`Your reportee "@${params.subjectAgentId}" (${params.subjectName}) has no activity in the last ${params.inactiveMinutes} minutes.`,
|
|
1087
|
+
`Role: ${params.role}`,
|
|
1088
|
+
`Last action: ${lastAction}`,
|
|
1089
|
+
`Manager: @${params.managerAgentId}`,
|
|
1090
|
+
"Please check in and unblock progress.",
|
|
1091
|
+
].join("\n");
|
|
1092
|
+
}
|
|
1093
|
+
function assertAgentExists(manifests, agentId) {
|
|
1094
|
+
if (manifests.some((manifest) => manifest.agentId === agentId)) {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
throw new Error(`Agent "${agentId}" does not exist.`);
|
|
1098
|
+
}
|
|
1099
|
+
function collectAllReportees(manifests, managerAgentId) {
|
|
1100
|
+
const byManager = new Map();
|
|
1101
|
+
for (const manifest of manifests) {
|
|
1102
|
+
const reportsTo = manifest.metadata.reportsTo;
|
|
1103
|
+
if (!reportsTo) {
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
const reportees = byManager.get(reportsTo) ?? [];
|
|
1107
|
+
reportees.push(manifest.agentId);
|
|
1108
|
+
byManager.set(reportsTo, reportees);
|
|
1109
|
+
}
|
|
1110
|
+
const visited = new Set();
|
|
1111
|
+
const queue = [...(byManager.get(managerAgentId) ?? [])];
|
|
1112
|
+
while (queue.length > 0) {
|
|
1113
|
+
const current = queue.shift();
|
|
1114
|
+
if (!current || current === managerAgentId || visited.has(current)) {
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
visited.add(current);
|
|
1118
|
+
queue.push(...(byManager.get(current) ?? []));
|
|
1119
|
+
}
|
|
1120
|
+
return [...visited].sort((left, right) => left.localeCompare(right));
|
|
1121
|
+
}
|
|
1122
|
+
function prepareOpenClawCommandEnv(env) {
|
|
1123
|
+
const mergedPath = dedupePathEntries([
|
|
1124
|
+
...resolvePreferredOpenClawCommandPaths(env),
|
|
1125
|
+
...(env.PATH?.split(path.delimiter) ?? []),
|
|
1126
|
+
]);
|
|
1127
|
+
return {
|
|
1128
|
+
...env,
|
|
1129
|
+
PATH: mergedPath.join(path.delimiter),
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
function resolvePreferredOpenClawCommandPaths(env) {
|
|
1133
|
+
const homeDir = homedir();
|
|
1134
|
+
const preferredPaths = [
|
|
1135
|
+
path.dirname(process.execPath),
|
|
1136
|
+
path.join(homeDir, ".npm-global", "bin"),
|
|
1137
|
+
path.join(homeDir, ".npm", "bin"),
|
|
1138
|
+
path.join(homeDir, ".local", "bin"),
|
|
1139
|
+
path.join(homeDir, ".volta", "bin"),
|
|
1140
|
+
path.join(homeDir, ".fnm", "current", "bin"),
|
|
1141
|
+
path.join(homeDir, ".asdf", "shims"),
|
|
1142
|
+
path.join(homeDir, "bin"),
|
|
1143
|
+
];
|
|
1144
|
+
const npmPrefixCandidates = dedupePathEntries([
|
|
1145
|
+
env.npm_config_prefix ?? "",
|
|
1146
|
+
env.NPM_CONFIG_PREFIX ?? "",
|
|
1147
|
+
process.env.npm_config_prefix ?? "",
|
|
1148
|
+
process.env.NPM_CONFIG_PREFIX ?? "",
|
|
1149
|
+
]);
|
|
1150
|
+
for (const prefix of npmPrefixCandidates) {
|
|
1151
|
+
preferredPaths.push(path.join(prefix, "bin"));
|
|
1152
|
+
}
|
|
1153
|
+
if (process.platform === "darwin") {
|
|
1154
|
+
preferredPaths.push("/opt/homebrew/bin", "/opt/homebrew/opt/node@22/bin", "/usr/local/opt/node@22/bin");
|
|
1155
|
+
}
|
|
1156
|
+
return preferredPaths;
|
|
1157
|
+
}
|
|
1158
|
+
function dedupePathEntries(entries) {
|
|
1159
|
+
const seen = new Set();
|
|
1160
|
+
const deduped = [];
|
|
1161
|
+
for (const rawEntry of entries) {
|
|
1162
|
+
const entry = rawEntry.trim();
|
|
1163
|
+
if (!entry || seen.has(entry)) {
|
|
1164
|
+
continue;
|
|
1165
|
+
}
|
|
1166
|
+
seen.add(entry);
|
|
1167
|
+
deduped.push(entry);
|
|
1168
|
+
}
|
|
1169
|
+
return deduped;
|
|
1170
|
+
}
|
|
1171
|
+
function isSpawnPermissionOrMissing(error) {
|
|
1172
|
+
return (typeof error === "object" &&
|
|
1173
|
+
error !== null &&
|
|
1174
|
+
"code" in error &&
|
|
1175
|
+
((error.code ?? "") === "ENOENT" ||
|
|
1176
|
+
(error.code ?? "") === "EACCES"));
|
|
307
1177
|
}
|
|
308
1178
|
//# sourceMappingURL=opengoat.service.js.map
|