@opengoat/core 2026.2.9 → 2026.2.14

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.
Files changed (199) hide show
  1. package/README.md +3 -3
  2. package/dist/core/acp/application/acp-agent.js +4 -8
  3. package/dist/core/acp/application/acp-agent.js.map +1 -1
  4. package/dist/core/agents/application/agent-manifest.service.d.ts +1 -4
  5. package/dist/core/agents/application/agent-manifest.service.js +39 -52
  6. package/dist/core/agents/application/agent-manifest.service.js.map +1 -1
  7. package/dist/core/agents/application/agent.service.d.ts +43 -4
  8. package/dist/core/agents/application/agent.service.js +476 -55
  9. package/dist/core/agents/application/agent.service.js.map +1 -1
  10. package/dist/core/agents/domain/agent-manifest.d.ts +10 -4
  11. package/dist/core/agents/domain/agent-manifest.js +118 -25
  12. package/dist/core/agents/domain/agent-manifest.js.map +1 -1
  13. package/dist/core/agents/index.d.ts +1 -3
  14. package/dist/core/agents/index.js +1 -3
  15. package/dist/core/agents/index.js.map +1 -1
  16. package/dist/core/boards/application/board.service.d.ts +64 -0
  17. package/dist/core/boards/application/board.service.js +590 -0
  18. package/dist/core/boards/application/board.service.js.map +1 -0
  19. package/dist/core/boards/domain/board.d.ts +30 -0
  20. package/dist/core/boards/domain/board.js +2 -0
  21. package/dist/core/boards/domain/board.js.map +1 -0
  22. package/dist/core/boards/index.d.ts +2 -0
  23. package/dist/core/boards/index.js +2 -0
  24. package/dist/core/boards/index.js.map +1 -0
  25. package/dist/core/bootstrap/application/bootstrap.service.d.ts +5 -2
  26. package/dist/core/bootstrap/application/bootstrap.service.js +32 -17
  27. package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
  28. package/dist/core/domain/agent-id.d.ts +1 -1
  29. package/dist/core/domain/agent-id.js +1 -1
  30. package/dist/core/domain/agent-id.js.map +1 -1
  31. package/dist/core/domain/agent.d.ts +31 -8
  32. package/dist/core/domain/opengoat-paths.d.ts +1 -0
  33. package/dist/core/opengoat/application/opengoat.service.d.ts +111 -27
  34. package/dist/core/opengoat/application/opengoat.service.js +1048 -136
  35. package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
  36. package/dist/core/opengoat/index.d.ts +1 -0
  37. package/dist/core/orchestration/application/orchestration.service.d.ts +8 -21
  38. package/dist/core/orchestration/application/orchestration.service.js +59 -871
  39. package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
  40. package/dist/core/orchestration/application/routing.service.js +10 -8
  41. package/dist/core/orchestration/application/routing.service.js.map +1 -1
  42. package/dist/core/orchestration/domain/routing.d.ts +0 -17
  43. package/dist/core/orchestration/domain/run-events.d.ts +1 -1
  44. package/dist/core/orchestration/index.d.ts +0 -2
  45. package/dist/core/orchestration/index.js +0 -1
  46. package/dist/core/orchestration/index.js.map +1 -1
  47. package/dist/core/providers/application/provider.service.d.ts +16 -32
  48. package/dist/core/providers/application/provider.service.js +178 -202
  49. package/dist/core/providers/application/provider.service.js.map +1 -1
  50. package/dist/core/providers/cli-provider.d.ts +1 -0
  51. package/dist/core/providers/cli-provider.js +66 -1
  52. package/dist/core/providers/cli-provider.js.map +1 -1
  53. package/dist/core/providers/image-input.d.ts +16 -0
  54. package/dist/core/providers/image-input.js +158 -0
  55. package/dist/core/providers/image-input.js.map +1 -0
  56. package/dist/core/providers/index.d.ts +1 -7
  57. package/dist/core/providers/index.js +0 -13
  58. package/dist/core/providers/index.js.map +1 -1
  59. package/dist/core/providers/loader.js +1 -95
  60. package/dist/core/providers/loader.js.map +1 -1
  61. package/dist/core/providers/providers/openclaw/provider.js +213 -32
  62. package/dist/core/providers/providers/openclaw/provider.js.map +1 -1
  63. package/dist/core/providers/types.d.ts +8 -3
  64. package/dist/core/scenarios/application/scenario-runner.service.d.ts +0 -1
  65. package/dist/core/scenarios/application/scenario-runner.service.js +30 -87
  66. package/dist/core/scenarios/application/scenario-runner.service.js.map +1 -1
  67. package/dist/core/scenarios/domain/scenario.d.ts +0 -15
  68. package/dist/core/sessions/application/session.service.d.ts +10 -4
  69. package/dist/core/sessions/application/session.service.js +87 -89
  70. package/dist/core/sessions/application/session.service.js.map +1 -1
  71. package/dist/core/sessions/domain/session.d.ts +3 -3
  72. package/dist/core/sessions/domain/transcript.d.ts +1 -1
  73. package/dist/core/sessions/index.d.ts +1 -1
  74. package/dist/core/sessions/index.js.map +1 -1
  75. package/dist/core/skills/application/skill.service.d.ts +2 -3
  76. package/dist/core/skills/application/skill.service.js +153 -56
  77. package/dist/core/skills/application/skill.service.js.map +1 -1
  78. package/dist/core/skills/domain/skill.d.ts +2 -2
  79. package/dist/core/skills/domain/skill.js +4 -2
  80. package/dist/core/skills/domain/skill.js.map +1 -1
  81. package/dist/core/templates/assets/ceo/BOOTSTRAP.md +41 -0
  82. package/dist/core/templates/assets/ceo/ROLE.md +15 -0
  83. package/dist/core/templates/assets/organization/MISSION.md +73 -0
  84. package/dist/core/templates/assets/organization/STRATEGY.md +107 -0
  85. package/dist/core/templates/assets/organization/VISION.md +80 -0
  86. package/dist/core/templates/assets/organization/wiki/index.md +15 -0
  87. package/dist/core/templates/assets/skills/og-board-individual/SKILL.md +148 -0
  88. package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +140 -0
  89. package/dist/core/templates/default-templates.d.ts +17 -14
  90. package/dist/core/templates/default-templates.js +115 -212
  91. package/dist/core/templates/default-templates.js.map +1 -1
  92. package/dist/index.d.ts +1 -4
  93. package/dist/index.js +1 -4
  94. package/dist/index.js.map +1 -1
  95. package/dist/platform/node/node-path.port.js +1 -0
  96. package/dist/platform/node/node-path.port.js.map +1 -1
  97. package/package.json +16 -13
  98. package/dist/core/agents/application/workspace-context.service.d.ts +0 -28
  99. package/dist/core/agents/application/workspace-context.service.js +0 -157
  100. package/dist/core/agents/application/workspace-context.service.js.map +0 -1
  101. package/dist/core/agents/domain/workspace-context.d.ts +0 -13
  102. package/dist/core/agents/domain/workspace-context.js +0 -14
  103. package/dist/core/agents/domain/workspace-context.js.map +0 -1
  104. package/dist/core/gateway/domain/protocol.d.ts +0 -113
  105. package/dist/core/gateway/domain/protocol.js +0 -394
  106. package/dist/core/gateway/domain/protocol.js.map +0 -1
  107. package/dist/core/gateway/index.d.ts +0 -2
  108. package/dist/core/gateway/index.js +0 -2
  109. package/dist/core/gateway/index.js.map +0 -1
  110. package/dist/core/llm/application/vercel-ai-text-runtime.d.ts +0 -26
  111. package/dist/core/llm/application/vercel-ai-text-runtime.js +0 -223
  112. package/dist/core/llm/application/vercel-ai-text-runtime.js.map +0 -1
  113. package/dist/core/llm/domain/text-runtime.d.ts +0 -22
  114. package/dist/core/llm/domain/text-runtime.js +0 -2
  115. package/dist/core/llm/domain/text-runtime.js.map +0 -1
  116. package/dist/core/llm/index.d.ts +0 -2
  117. package/dist/core/llm/index.js +0 -2
  118. package/dist/core/llm/index.js.map +0 -1
  119. package/dist/core/orchestration/application/orchestration-planner.service.d.ts +0 -28
  120. package/dist/core/orchestration/application/orchestration-planner.service.js +0 -279
  121. package/dist/core/orchestration/application/orchestration-planner.service.js.map +0 -1
  122. package/dist/core/orchestration/domain/loop.d.ts +0 -119
  123. package/dist/core/orchestration/domain/loop.js +0 -2
  124. package/dist/core/orchestration/domain/loop.js.map +0 -1
  125. package/dist/core/plugins/application/plugin.service.d.ts +0 -32
  126. package/dist/core/plugins/application/plugin.service.js +0 -236
  127. package/dist/core/plugins/application/plugin.service.js.map +0 -1
  128. package/dist/core/plugins/domain/openclaw-compat.d.ts +0 -60
  129. package/dist/core/plugins/domain/openclaw-compat.js +0 -9
  130. package/dist/core/plugins/domain/openclaw-compat.js.map +0 -1
  131. package/dist/core/plugins/index.d.ts +0 -3
  132. package/dist/core/plugins/index.js +0 -3
  133. package/dist/core/plugins/index.js.map +0 -1
  134. package/dist/core/providers/onboarding.d.ts +0 -13
  135. package/dist/core/providers/onboarding.js +0 -149
  136. package/dist/core/providers/onboarding.js.map +0 -1
  137. package/dist/core/providers/providers/claude/index.d.ts +0 -4
  138. package/dist/core/providers/providers/claude/index.js +0 -19
  139. package/dist/core/providers/providers/claude/index.js.map +0 -1
  140. package/dist/core/providers/providers/claude/provider.d.ts +0 -8
  141. package/dist/core/providers/providers/claude/provider.js +0 -106
  142. package/dist/core/providers/providers/claude/provider.js.map +0 -1
  143. package/dist/core/providers/providers/codex/index.d.ts +0 -4
  144. package/dist/core/providers/providers/codex/index.js +0 -19
  145. package/dist/core/providers/providers/codex/index.js.map +0 -1
  146. package/dist/core/providers/providers/codex/provider.d.ts +0 -7
  147. package/dist/core/providers/providers/codex/provider.js +0 -31
  148. package/dist/core/providers/providers/codex/provider.js.map +0 -1
  149. package/dist/core/providers/providers/cursor/index.d.ts +0 -4
  150. package/dist/core/providers/providers/cursor/index.js +0 -19
  151. package/dist/core/providers/providers/cursor/index.js.map +0 -1
  152. package/dist/core/providers/providers/cursor/provider.d.ts +0 -11
  153. package/dist/core/providers/providers/cursor/provider.js +0 -90
  154. package/dist/core/providers/providers/cursor/provider.js.map +0 -1
  155. package/dist/core/providers/providers/extended-http/catalog.d.ts +0 -40
  156. package/dist/core/providers/providers/extended-http/catalog.js +0 -728
  157. package/dist/core/providers/providers/extended-http/catalog.js.map +0 -1
  158. package/dist/core/providers/providers/extended-http/index.d.ts +0 -5
  159. package/dist/core/providers/providers/extended-http/index.js +0 -13
  160. package/dist/core/providers/providers/extended-http/index.js.map +0 -1
  161. package/dist/core/providers/providers/extended-http/provider.d.ts +0 -31
  162. package/dist/core/providers/providers/extended-http/provider.js +0 -580
  163. package/dist/core/providers/providers/extended-http/provider.js.map +0 -1
  164. package/dist/core/providers/providers/gemini/index.d.ts +0 -4
  165. package/dist/core/providers/providers/gemini/index.js +0 -37
  166. package/dist/core/providers/providers/gemini/index.js.map +0 -1
  167. package/dist/core/providers/providers/gemini/provider.d.ts +0 -7
  168. package/dist/core/providers/providers/gemini/provider.js +0 -59
  169. package/dist/core/providers/providers/gemini/provider.js.map +0 -1
  170. package/dist/core/providers/providers/grok/index.d.ts +0 -4
  171. package/dist/core/providers/providers/grok/index.js +0 -41
  172. package/dist/core/providers/providers/grok/index.js.map +0 -1
  173. package/dist/core/providers/providers/grok/provider.d.ts +0 -13
  174. package/dist/core/providers/providers/grok/provider.js +0 -95
  175. package/dist/core/providers/providers/grok/provider.js.map +0 -1
  176. package/dist/core/providers/providers/openai/index.d.ts +0 -4
  177. package/dist/core/providers/providers/openai/index.js +0 -45
  178. package/dist/core/providers/providers/openai/index.js.map +0 -1
  179. package/dist/core/providers/providers/openai/provider.d.ts +0 -14
  180. package/dist/core/providers/providers/openai/provider.js +0 -203
  181. package/dist/core/providers/providers/openai/provider.js.map +0 -1
  182. package/dist/core/providers/providers/opencode/index.d.ts +0 -4
  183. package/dist/core/providers/providers/opencode/index.js +0 -23
  184. package/dist/core/providers/providers/opencode/index.js.map +0 -1
  185. package/dist/core/providers/providers/opencode/provider.d.ts +0 -11
  186. package/dist/core/providers/providers/opencode/provider.js +0 -215
  187. package/dist/core/providers/providers/opencode/provider.js.map +0 -1
  188. package/dist/core/providers/providers/openrouter/index.d.ts +0 -4
  189. package/dist/core/providers/providers/openrouter/index.js +0 -37
  190. package/dist/core/providers/providers/openrouter/index.js.map +0 -1
  191. package/dist/core/providers/providers/openrouter/provider.d.ts +0 -13
  192. package/dist/core/providers/providers/openrouter/provider.js +0 -80
  193. package/dist/core/providers/providers/openrouter/provider.js.map +0 -1
  194. package/dist/platform/node/opengoat-gateway-client.d.ts +0 -19
  195. package/dist/platform/node/opengoat-gateway-client.js +0 -194
  196. package/dist/platform/node/opengoat-gateway-client.js.map +0 -1
  197. package/dist/platform/node/opengoat-gateway-server.d.ts +0 -53
  198. package/dist/platform/node/opengoat-gateway-server.js +0 -906
  199. package/dist/platform/node/opengoat-gateway-server.js.map +0 -1
@@ -1,5 +1,5 @@
1
- import { isDefaultAgentId, normalizeAgentId } from "../../domain/agent-id.js";
2
- import { renderAgentsIndex, renderInternalAgentConfig, renderInternalAgentMemoryMarkdown, renderInternalAgentState, renderWorkspaceAgentsMarkdown, renderWorkspaceBootstrapMarkdown, renderWorkspaceContextMarkdown, renderWorkspaceHeartbeatMarkdown, renderWorkspaceIdentityMarkdown, renderDefaultOrchestratorSkillMarkdown, renderWorkspaceSoulMarkdown, renderWorkspaceToolsMarkdown, renderWorkspaceUserMarkdown, renderWorkspaceMetadata } from "../../templates/default-templates.js";
1
+ import { DEFAULT_AGENT_ID, isDefaultAgentId, normalizeAgentId, } from "../../domain/agent-id.js";
2
+ import { renderAgentsIndex, renderBoardIndividualSkillMarkdown, renderBoardManagerSkillMarkdown, renderCeoBootstrapMarkdown, renderCeoRoleMarkdown, renderInternalAgentConfig, resolveAgentRole, } from "../../templates/default-templates.js";
3
3
  export class AgentService {
4
4
  fileSystem;
5
5
  pathPort;
@@ -20,41 +20,17 @@ export class AgentService {
20
20
  }
21
21
  return { id, displayName };
22
22
  }
23
- async ensureAgent(paths, identity) {
23
+ async ensureAgent(paths, identity, options = {}) {
24
24
  const workspaceDir = this.pathPort.join(paths.workspacesDir, identity.id);
25
- const workspaceSkillsDir = this.pathPort.join(workspaceDir, "skills");
26
25
  const internalConfigDir = this.pathPort.join(paths.agentsDir, identity.id);
27
- const sessionsDir = this.pathPort.join(internalConfigDir, "sessions");
26
+ const configPath = this.pathPort.join(internalConfigDir, "config.json");
27
+ const templateOptions = toAgentTemplateOptions(identity.id, options);
28
28
  const createdPaths = [];
29
29
  const skippedPaths = [];
30
- await this.ensureDirectory(workspaceDir, createdPaths, skippedPaths);
31
- await this.ensureDirectory(workspaceSkillsDir, createdPaths, skippedPaths);
30
+ const configExisted = await this.fileSystem.exists(configPath);
32
31
  await this.ensureDirectory(internalConfigDir, createdPaths, skippedPaths);
33
- await this.ensureDirectory(sessionsDir, createdPaths, skippedPaths);
34
- const shouldCreateBootstrapFile = await this.isBrandNewWorkspace(workspaceDir);
35
- await this.writeJsonIfMissing(this.pathPort.join(workspaceDir, "workspace.json"), renderWorkspaceMetadata(identity), createdPaths, skippedPaths);
36
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "AGENTS.md"), renderWorkspaceAgentsMarkdown(identity), createdPaths, skippedPaths);
37
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "CONTEXT.md"), renderWorkspaceContextMarkdown(identity), createdPaths, skippedPaths);
38
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "SOUL.md"), renderWorkspaceSoulMarkdown(identity), createdPaths, skippedPaths);
39
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "TOOLS.md"), renderWorkspaceToolsMarkdown(), createdPaths, skippedPaths);
40
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "IDENTITY.md"), renderWorkspaceIdentityMarkdown(identity), createdPaths, skippedPaths);
41
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "USER.md"), renderWorkspaceUserMarkdown(), createdPaths, skippedPaths);
42
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "HEARTBEAT.md"), renderWorkspaceHeartbeatMarkdown(), createdPaths, skippedPaths);
43
- if (shouldCreateBootstrapFile) {
44
- await this.writeMarkdownIfMissing(this.pathPort.join(workspaceDir, "BOOTSTRAP.md"), renderWorkspaceBootstrapMarkdown(identity), createdPaths, skippedPaths);
45
- }
46
- if (isDefaultAgentId(identity.id)) {
47
- const orchestratorSkillDir = this.pathPort.join(workspaceSkillsDir, "opengoat-skill");
48
- await this.ensureDirectory(orchestratorSkillDir, createdPaths, skippedPaths);
49
- await this.writeMarkdownIfMissing(this.pathPort.join(orchestratorSkillDir, "SKILL.md"), renderDefaultOrchestratorSkillMarkdown(), createdPaths, skippedPaths);
50
- }
51
- await this.writeJsonIfMissing(this.pathPort.join(internalConfigDir, "config.json"), renderInternalAgentConfig(identity), createdPaths, skippedPaths);
52
- await this.writeJsonIfMissing(this.pathPort.join(internalConfigDir, "state.json"), renderInternalAgentState(), createdPaths, skippedPaths);
53
- await this.writeMarkdownIfMissing(this.pathPort.join(internalConfigDir, "memory.md"), renderInternalAgentMemoryMarkdown(identity), createdPaths, skippedPaths);
54
- await this.writeJsonIfMissing(this.pathPort.join(sessionsDir, "sessions.json"), {
55
- schemaVersion: 1,
56
- sessions: {}
57
- }, createdPaths, skippedPaths);
32
+ await this.writeJsonIfMissing(configPath, renderInternalAgentConfig(identity, templateOptions), createdPaths, skippedPaths);
33
+ const role = await this.readAgentRole(paths, identity.id);
58
34
  const existingIndex = await this.readJsonIfPresent(paths.agentsIndexJsonPath);
59
35
  const agents = dedupe([...(existingIndex?.agents ?? []), identity.id]);
60
36
  const nextIndex = renderAgentsIndex(this.nowIso(), agents);
@@ -62,37 +38,183 @@ export class AgentService {
62
38
  return {
63
39
  agent: {
64
40
  ...identity,
41
+ role,
65
42
  workspaceDir,
66
- internalConfigDir
43
+ internalConfigDir,
67
44
  },
45
+ alreadyExisted: configExisted,
68
46
  createdPaths,
69
- skippedPaths
47
+ skippedPaths,
70
48
  };
71
49
  }
72
50
  async listAgents(paths) {
73
- const ids = await this.fileSystem.listDirectories(paths.workspacesDir);
51
+ const ids = await this.fileSystem.listDirectories(paths.agentsDir);
74
52
  const descriptors = [];
75
53
  for (const id of ids) {
76
54
  const workspaceDir = this.pathPort.join(paths.workspacesDir, id);
77
55
  const internalConfigDir = this.pathPort.join(paths.agentsDir, id);
78
- const metadataPath = this.pathPort.join(workspaceDir, "workspace.json");
79
- const metadata = await this.readJsonIfPresent(metadataPath);
56
+ const displayName = await this.readAgentDisplayName(paths, id);
57
+ const role = await this.readAgentRole(paths, id);
80
58
  descriptors.push({
81
59
  id,
82
- displayName: metadata?.displayName ?? id,
60
+ displayName,
61
+ role,
83
62
  workspaceDir,
84
- internalConfigDir
63
+ internalConfigDir,
85
64
  });
86
65
  }
87
66
  return descriptors.sort((left, right) => left.id.localeCompare(right.id));
88
67
  }
68
+ async ensureCeoWorkspaceBootstrap(paths) {
69
+ const displayName = await this.readAgentDisplayName(paths, DEFAULT_AGENT_ID);
70
+ const role = await this.readAgentRole(paths, DEFAULT_AGENT_ID);
71
+ return this.ensureAgentWorkspaceBootstrap(paths, {
72
+ agentId: DEFAULT_AGENT_ID,
73
+ displayName,
74
+ role,
75
+ });
76
+ }
77
+ async ensureAgentWorkspaceBootstrap(paths, input) {
78
+ const normalizedAgentId = normalizeAgentId(input.agentId);
79
+ if (!normalizedAgentId) {
80
+ throw new Error("Agent id cannot be empty.");
81
+ }
82
+ const workspaceDir = this.pathPort.join(paths.workspacesDir, normalizedAgentId);
83
+ const agentsPath = this.pathPort.join(workspaceDir, "AGENTS.md");
84
+ const rolePath = this.pathPort.join(workspaceDir, "ROLE.md");
85
+ const bootstrapPath = this.pathPort.join(workspaceDir, "BOOTSTRAP.md");
86
+ const createdPaths = [];
87
+ const skippedPaths = [];
88
+ const removedPaths = [];
89
+ await this.ensureDirectory(workspaceDir, createdPaths, skippedPaths);
90
+ await this.rewriteAgentsMarkdown(agentsPath, normalizedAgentId, createdPaths, skippedPaths);
91
+ await this.writeRoleMarkdown(rolePath, {
92
+ agentId: normalizedAgentId,
93
+ displayName: input.displayName.trim() || normalizedAgentId,
94
+ role: input.role.trim(),
95
+ }, createdPaths, skippedPaths);
96
+ const workspaceSkillSync = await this.ensureAgentWorkspaceRoleSkills(paths, normalizedAgentId);
97
+ createdPaths.push(...workspaceSkillSync.createdPaths);
98
+ skippedPaths.push(...workspaceSkillSync.skippedPaths);
99
+ removedPaths.push(...workspaceSkillSync.removedPaths);
100
+ if (isDefaultAgentId(normalizedAgentId)) {
101
+ await this.writeBootstrapMarkdown(bootstrapPath, createdPaths, skippedPaths);
102
+ }
103
+ else if (await this.fileSystem.exists(bootstrapPath)) {
104
+ await this.fileSystem.removeDir(bootstrapPath);
105
+ removedPaths.push(bootstrapPath);
106
+ }
107
+ else {
108
+ skippedPaths.push(bootstrapPath);
109
+ }
110
+ return {
111
+ createdPaths,
112
+ skippedPaths,
113
+ removedPaths,
114
+ };
115
+ }
116
+ async ensureAgentWorkspaceRoleSkills(paths, agentId) {
117
+ const normalizedAgentId = normalizeAgentId(agentId);
118
+ if (!normalizedAgentId) {
119
+ throw new Error("Agent id cannot be empty.");
120
+ }
121
+ const type = await this.readAgentType(paths, normalizedAgentId);
122
+ const requiredSkillIds = type === "manager" ? MANAGER_ROLE_SKILLS : INDIVIDUAL_ROLE_SKILLS;
123
+ const managedRoleSkillIds = [
124
+ ...new Set([
125
+ ...MANAGER_ROLE_SKILLS,
126
+ ...INDIVIDUAL_ROLE_SKILLS,
127
+ ...LEGACY_MANAGER_ROLE_SKILLS,
128
+ ...LEGACY_INDIVIDUAL_ROLE_SKILLS,
129
+ ]),
130
+ ];
131
+ const workspaceDir = this.pathPort.join(paths.workspacesDir, normalizedAgentId);
132
+ const skillsDir = this.pathPort.join(workspaceDir, "skills");
133
+ const createdPaths = [];
134
+ const skippedPaths = [];
135
+ const removedPaths = [];
136
+ await this.ensureDirectory(workspaceDir, createdPaths, skippedPaths);
137
+ await this.ensureDirectory(skillsDir, createdPaths, skippedPaths);
138
+ for (const skillId of requiredSkillIds) {
139
+ const skillDir = this.pathPort.join(skillsDir, skillId);
140
+ const skillFile = this.pathPort.join(skillDir, "SKILL.md");
141
+ await this.ensureDirectory(skillDir, createdPaths, skippedPaths);
142
+ await this.writeMarkdown(skillFile, this.renderWorkspaceSkill(skillId), createdPaths, skippedPaths, { overwrite: true });
143
+ }
144
+ for (const skillId of managedRoleSkillIds) {
145
+ if (requiredSkillIds.includes(skillId)) {
146
+ continue;
147
+ }
148
+ const staleSkillDir = this.pathPort.join(skillsDir, skillId);
149
+ if (await this.fileSystem.exists(staleSkillDir)) {
150
+ await this.fileSystem.removeDir(staleSkillDir);
151
+ removedPaths.push(staleSkillDir);
152
+ }
153
+ else {
154
+ skippedPaths.push(staleSkillDir);
155
+ }
156
+ }
157
+ return {
158
+ createdPaths,
159
+ skippedPaths,
160
+ removedPaths,
161
+ };
162
+ }
163
+ async syncAgentRoleAssignments(paths, agentId) {
164
+ const normalizedAgentId = normalizeAgentId(agentId);
165
+ if (!normalizedAgentId) {
166
+ throw new Error("Agent id cannot be empty.");
167
+ }
168
+ const configPath = this.pathPort.join(paths.agentsDir, normalizedAgentId, "config.json");
169
+ const config = await this.readJsonIfPresent(configPath);
170
+ if (!config) {
171
+ return {
172
+ updatedPaths: [],
173
+ skippedPaths: [configPath],
174
+ };
175
+ }
176
+ const type = await this.readAgentType(paths, normalizedAgentId);
177
+ const requiredSkillIds = type === "manager" ? MANAGER_ROLE_SKILLS : INDIVIDUAL_ROLE_SKILLS;
178
+ const roleSkillIds = new Set([
179
+ ...MANAGER_ROLE_SKILLS,
180
+ ...INDIVIDUAL_ROLE_SKILLS,
181
+ ...LEGACY_MANAGER_ROLE_SKILLS,
182
+ ...LEGACY_INDIVIDUAL_ROLE_SKILLS,
183
+ ]);
184
+ const runtimeRecord = toObject(config.runtime);
185
+ const skillsRecord = toObject(runtimeRecord.skills);
186
+ const assignedRaw = Array.isArray(skillsRecord.assigned)
187
+ ? skillsRecord.assigned
188
+ : [];
189
+ const assigned = [
190
+ ...new Set(assignedRaw
191
+ .map((value) => String(value).trim().toLowerCase())
192
+ .filter(Boolean)),
193
+ ];
194
+ const preserved = assigned.filter((skillId) => !roleSkillIds.has(skillId));
195
+ const nextAssigned = [...new Set([...preserved, ...requiredSkillIds])];
196
+ if (sameStringArray(assigned, nextAssigned)) {
197
+ return {
198
+ updatedPaths: [],
199
+ skippedPaths: [configPath],
200
+ };
201
+ }
202
+ skillsRecord.assigned = nextAssigned;
203
+ runtimeRecord.skills = skillsRecord;
204
+ config.runtime = runtimeRecord;
205
+ await this.fileSystem.writeFile(configPath, toJson(config));
206
+ return {
207
+ updatedPaths: [configPath],
208
+ skippedPaths: [],
209
+ };
210
+ }
89
211
  async removeAgent(paths, rawAgentId) {
90
212
  const agentId = normalizeAgentId(rawAgentId);
91
213
  if (!agentId) {
92
214
  throw new Error("Agent id cannot be empty.");
93
215
  }
94
216
  if (isDefaultAgentId(agentId)) {
95
- throw new Error("Cannot delete orchestrator. It is the immutable default entry agent.");
217
+ throw new Error("Cannot delete ceo. It is the immutable default entry agent.");
96
218
  }
97
219
  const workspaceDir = this.pathPort.join(paths.workspacesDir, agentId);
98
220
  const internalConfigDir = this.pathPort.join(paths.agentsDir, agentId);
@@ -124,21 +246,59 @@ export class AgentService {
124
246
  agentId,
125
247
  existed: workspaceExists || internalConfigExists,
126
248
  removedPaths,
127
- skippedPaths
249
+ skippedPaths,
128
250
  };
129
251
  }
130
- async isBrandNewWorkspace(workspaceDir) {
131
- const firstRunFiles = [
132
- "AGENTS.md",
133
- "CONTEXT.md",
134
- "SOUL.md",
135
- "TOOLS.md",
136
- "IDENTITY.md",
137
- "USER.md",
138
- "HEARTBEAT.md"
139
- ];
140
- const existence = await Promise.all(firstRunFiles.map((fileName) => this.fileSystem.exists(this.pathPort.join(workspaceDir, fileName))));
141
- return existence.every((value) => !value);
252
+ async setAgentManager(paths, rawAgentId, rawReportsTo) {
253
+ const agentId = normalizeAgentId(rawAgentId);
254
+ if (!agentId) {
255
+ throw new Error("Agent id cannot be empty.");
256
+ }
257
+ const explicitReportsTo = rawReportsTo === null || rawReportsTo === undefined
258
+ ? null
259
+ : normalizeAgentId(rawReportsTo);
260
+ if (explicitReportsTo === agentId) {
261
+ throw new Error(`Agent "${agentId}" cannot report to itself.`);
262
+ }
263
+ if (isDefaultAgentId(agentId) && explicitReportsTo) {
264
+ throw new Error("ceo is the head of the organization and cannot report to another agent.");
265
+ }
266
+ const reportsTo = resolveReportsTo(agentId, rawReportsTo);
267
+ const knownAgents = await this.fileSystem.listDirectories(paths.agentsDir);
268
+ if (!knownAgents.includes(agentId)) {
269
+ throw new Error(`Agent "${agentId}" does not exist.`);
270
+ }
271
+ if (reportsTo && !knownAgents.includes(reportsTo)) {
272
+ throw new Error(`Manager "${reportsTo}" does not exist.`);
273
+ }
274
+ await this.assertNoReportingCycle(paths, agentId, reportsTo, knownAgents);
275
+ const configPath = this.pathPort.join(paths.agentsDir, agentId, "config.json");
276
+ const displayName = await this.readAgentDisplayName(paths, agentId);
277
+ const role = await this.readAgentRole(paths, agentId);
278
+ const existingConfig = (await this.readJsonIfPresent(configPath)) ??
279
+ renderInternalAgentConfig({ id: agentId, displayName, role });
280
+ const existingOrganization = toObject(existingConfig.organization);
281
+ const previousReportsTo = normalizeReportsToValue(existingOrganization.reportsTo);
282
+ const nextOrganization = {
283
+ ...existingOrganization,
284
+ reportsTo,
285
+ };
286
+ if (typeof existingOrganization.type !== "string") {
287
+ nextOrganization.type = isDefaultAgentId(agentId)
288
+ ? "manager"
289
+ : "individual";
290
+ }
291
+ const nextConfig = {
292
+ ...existingConfig,
293
+ organization: nextOrganization,
294
+ };
295
+ await this.fileSystem.writeFile(configPath, toJson(nextConfig));
296
+ return {
297
+ agentId,
298
+ previousReportsTo: previousReportsTo ?? null,
299
+ reportsTo,
300
+ updatedPaths: [configPath],
301
+ };
142
302
  }
143
303
  async ensureDirectory(directoryPath, createdPaths, skippedPaths) {
144
304
  const existed = await this.fileSystem.exists(directoryPath);
@@ -158,16 +318,43 @@ export class AgentService {
158
318
  await this.fileSystem.writeFile(filePath, toJson(payload));
159
319
  createdPaths.push(filePath);
160
320
  }
161
- async writeMarkdownIfMissing(filePath, content, createdPaths, skippedPaths) {
321
+ async writeMarkdown(filePath, content, createdPaths, skippedPaths, options = {}) {
162
322
  const exists = await this.fileSystem.exists(filePath);
163
- if (exists) {
323
+ if (exists && !options.overwrite) {
164
324
  skippedPaths.push(filePath);
165
325
  return;
166
326
  }
167
327
  const markdown = content.endsWith("\n") ? content : `${content}\n`;
168
328
  await this.fileSystem.writeFile(filePath, markdown);
329
+ if (exists) {
330
+ skippedPaths.push(filePath);
331
+ return;
332
+ }
169
333
  createdPaths.push(filePath);
170
334
  }
335
+ async rewriteAgentsMarkdown(filePath, agentId, createdPaths, skippedPaths) {
336
+ const exists = await this.fileSystem.exists(filePath);
337
+ if (!exists) {
338
+ skippedPaths.push(filePath);
339
+ return;
340
+ }
341
+ const source = await this.fileSystem.readFile(filePath);
342
+ const next = normalizeAgentsMarkdown(source, {
343
+ keepFirstRunSection: isDefaultAgentId(agentId),
344
+ });
345
+ if (source === next) {
346
+ skippedPaths.push(filePath);
347
+ return;
348
+ }
349
+ await this.fileSystem.writeFile(filePath, next);
350
+ skippedPaths.push(filePath);
351
+ }
352
+ async writeRoleMarkdown(filePath, profile, createdPaths, skippedPaths) {
353
+ await this.writeMarkdown(filePath, renderRoleMarkdown(profile), createdPaths, skippedPaths, { overwrite: true });
354
+ }
355
+ async writeBootstrapMarkdown(filePath, createdPaths, skippedPaths) {
356
+ await this.writeMarkdown(filePath, renderCeoBootstrapMarkdown(), createdPaths, skippedPaths, { overwrite: true });
357
+ }
171
358
  async readJsonIfPresent(filePath) {
172
359
  const exists = await this.fileSystem.exists(filePath);
173
360
  if (!exists) {
@@ -181,6 +368,140 @@ export class AgentService {
181
368
  return null;
182
369
  }
183
370
  }
371
+ async readAgentDisplayName(paths, agentId) {
372
+ const configPath = this.pathPort.join(paths.agentsDir, agentId, "config.json");
373
+ const config = await this.readJsonIfPresent(configPath);
374
+ return config?.displayName?.trim() || agentId;
375
+ }
376
+ async readAgentRole(paths, agentId) {
377
+ const configPath = this.pathPort.join(paths.agentsDir, agentId, "config.json");
378
+ const config = await this.readJsonIfPresent(configPath);
379
+ const type = config?.organization?.type ??
380
+ (isDefaultAgentId(agentId) ? "manager" : "individual");
381
+ return resolveAgentRole(agentId, type, config?.role);
382
+ }
383
+ async readAgentType(paths, agentId) {
384
+ const configPath = this.pathPort.join(paths.agentsDir, agentId, "config.json");
385
+ const config = await this.readJsonIfPresent(configPath);
386
+ const type = config?.organization?.type;
387
+ const hasDirectReportees = await this.hasDirectReportees(paths, agentId);
388
+ if (type === "manager") {
389
+ return type;
390
+ }
391
+ if (type === "individual") {
392
+ return hasDirectReportees ? "manager" : "individual";
393
+ }
394
+ if (isDefaultAgentId(agentId)) {
395
+ return "manager";
396
+ }
397
+ return hasDirectReportees ? "manager" : "individual";
398
+ }
399
+ renderWorkspaceSkill(skillId) {
400
+ if (skillId === "og-board-manager") {
401
+ return renderBoardManagerSkillMarkdown();
402
+ }
403
+ if (skillId === "og-board-individual") {
404
+ return renderBoardIndividualSkillMarkdown();
405
+ }
406
+ throw new Error(`Unsupported workspace skill id: ${skillId}`);
407
+ }
408
+ async assertNoReportingCycle(paths, agentId, reportsTo, knownAgentIds) {
409
+ if (!reportsTo) {
410
+ return;
411
+ }
412
+ const reportsToByAgent = new Map();
413
+ await Promise.all(knownAgentIds.map(async (candidateAgentId) => {
414
+ reportsToByAgent.set(candidateAgentId, await this.readAgentReportsTo(paths, candidateAgentId));
415
+ }));
416
+ reportsToByAgent.set(agentId, reportsTo);
417
+ const visited = new Set([agentId]);
418
+ let cursor = reportsTo;
419
+ while (cursor) {
420
+ if (visited.has(cursor)) {
421
+ throw new Error(`Cannot set "${agentId}" to report to "${reportsTo}" because it would create a cycle.`);
422
+ }
423
+ visited.add(cursor);
424
+ cursor = reportsToByAgent.get(cursor) ?? null;
425
+ }
426
+ }
427
+ async readAgentReportsTo(paths, agentId) {
428
+ const configPath = this.pathPort.join(paths.agentsDir, agentId, "config.json");
429
+ const config = await this.readJsonIfPresent(configPath);
430
+ const reportsTo = normalizeReportsToValue(config?.organization?.reportsTo);
431
+ if (isDefaultAgentId(agentId)) {
432
+ return null;
433
+ }
434
+ if (reportsTo === undefined) {
435
+ return DEFAULT_AGENT_ID;
436
+ }
437
+ return reportsTo;
438
+ }
439
+ async hasDirectReportees(paths, managerAgentId) {
440
+ const normalizedManagerId = normalizeAgentId(managerAgentId);
441
+ if (!normalizedManagerId) {
442
+ return false;
443
+ }
444
+ const knownAgents = await this.fileSystem.listDirectories(paths.agentsDir);
445
+ for (const agentId of knownAgents) {
446
+ if (agentId === normalizedManagerId) {
447
+ continue;
448
+ }
449
+ const reportsTo = await this.readAgentReportsTo(paths, agentId);
450
+ if (reportsTo === normalizedManagerId) {
451
+ return true;
452
+ }
453
+ }
454
+ return false;
455
+ }
456
+ }
457
+ const MANAGER_ROLE_SKILLS = ["og-board-manager"];
458
+ const INDIVIDUAL_ROLE_SKILLS = ["og-board-individual"];
459
+ const LEGACY_MANAGER_ROLE_SKILLS = ["board-manager"];
460
+ const LEGACY_INDIVIDUAL_ROLE_SKILLS = ["board-individual"];
461
+ function toAgentTemplateOptions(agentId, options) {
462
+ const type = options.type ?? (isDefaultAgentId(agentId) ? "manager" : "individual");
463
+ const reportsTo = resolveReportsTo(agentId, options.reportsTo);
464
+ const providedSkills = options.skills ?? [];
465
+ const roleSkillIds = new Set([
466
+ ...MANAGER_ROLE_SKILLS,
467
+ ...INDIVIDUAL_ROLE_SKILLS,
468
+ ...LEGACY_MANAGER_ROLE_SKILLS,
469
+ ...LEGACY_INDIVIDUAL_ROLE_SKILLS,
470
+ ]);
471
+ const skills = dedupe(providedSkills.filter((skillId) => !roleSkillIds.has(skillId)));
472
+ const role = resolveAgentRole(agentId, type, options.role);
473
+ return {
474
+ type,
475
+ reportsTo,
476
+ skills,
477
+ role,
478
+ };
479
+ }
480
+ function resolveReportsTo(agentId, reportsTo) {
481
+ if (isDefaultAgentId(agentId)) {
482
+ return null;
483
+ }
484
+ if (reportsTo === null || reportsTo === undefined) {
485
+ return DEFAULT_AGENT_ID;
486
+ }
487
+ const normalized = normalizeAgentId(reportsTo);
488
+ if (!normalized || normalized === agentId) {
489
+ return DEFAULT_AGENT_ID;
490
+ }
491
+ return normalized;
492
+ }
493
+ function normalizeReportsToValue(value) {
494
+ if (value === null) {
495
+ return null;
496
+ }
497
+ if (typeof value !== "string") {
498
+ return undefined;
499
+ }
500
+ const normalized = normalizeAgentId(value);
501
+ if (!normalized) {
502
+ return null;
503
+ }
504
+ return normalized;
184
505
  }
185
506
  function dedupe(values) {
186
507
  return [...new Set(values)].sort((left, right) => left.localeCompare(right));
@@ -188,4 +509,104 @@ function dedupe(values) {
188
509
  function toJson(payload) {
189
510
  return `${JSON.stringify(payload, null, 2)}\n`;
190
511
  }
512
+ function toObject(value) {
513
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
514
+ return {};
515
+ }
516
+ return value;
517
+ }
518
+ function sameStringArray(left, right) {
519
+ if (left.length !== right.length) {
520
+ return false;
521
+ }
522
+ return left.every((value, index) => value === right[index]);
523
+ }
524
+ function normalizeAgentsMarkdown(markdown, options) {
525
+ const withFirstRunApplied = options.keepFirstRunSection
526
+ ? markdown
527
+ : rewriteSecondLevelSection(markdown, /^##\s+first run\s*$/i, null);
528
+ return rewriteSecondLevelSection(withFirstRunApplied, /^##\s+every session\s*$/i, EVERY_SESSION_SECTION_LINES);
529
+ }
530
+ function rewriteSecondLevelSection(markdown, headingPattern, replacementLines) {
531
+ const lineBreak = markdown.includes("\r\n") ? "\r\n" : "\n";
532
+ const lines = markdown.split(/\r?\n/);
533
+ const hasTrailingLineBreak = /\r?\n$/.test(markdown);
534
+ const kept = [];
535
+ let index = 0;
536
+ let replaced = false;
537
+ while (index < lines.length) {
538
+ const line = lines[index];
539
+ if (line === undefined) {
540
+ index += 1;
541
+ continue;
542
+ }
543
+ const trimmed = line.trim();
544
+ if (headingPattern.test(trimmed)) {
545
+ replaced = true;
546
+ if (replacementLines) {
547
+ kept.push(...replacementLines);
548
+ }
549
+ index += 1;
550
+ while (index < lines.length) {
551
+ const nextLine = lines[index];
552
+ if (nextLine !== undefined && /^##\s+/.test(nextLine.trim())) {
553
+ break;
554
+ }
555
+ index += 1;
556
+ }
557
+ continue;
558
+ }
559
+ kept.push(line);
560
+ index += 1;
561
+ }
562
+ if (!replaced) {
563
+ return markdown;
564
+ }
565
+ let next = kept.join(lineBreak);
566
+ if (hasTrailingLineBreak && !next.endsWith(lineBreak)) {
567
+ next = `${next}${lineBreak}`;
568
+ }
569
+ return next;
570
+ }
571
+ const EVERY_SESSION_SECTION_LINES = [
572
+ "## Every Session",
573
+ "",
574
+ "You are part of an organization run by AI agents.",
575
+ "",
576
+ "Before doing anything else:",
577
+ "",
578
+ "1. Read `SOUL.md` — this is who you are",
579
+ "2. Read `ROLE.md` — this is your role in the organization",
580
+ "3. Read `memory/YYYY-MM-DD.md` (today + yesterday) for recent context",
581
+ "4. **If in MAIN SESSION**: Also read `MEMORY.md`",
582
+ "",
583
+ "Don't ask permission. Just do it.",
584
+ "",
585
+ "## The Organization",
586
+ "",
587
+ "You are part of an organization run by AI agents. You have access to the organization's context and wiki on `../../organization`",
588
+ "",
589
+ ];
590
+ function renderRoleMarkdown(profile) {
591
+ if (isDefaultAgentId(profile.agentId)) {
592
+ return renderCeoRoleMarkdown();
593
+ }
594
+ return [
595
+ "# ROLE.md - Your position in the organization",
596
+ "",
597
+ "You are part of an organization fully run by AI agents.",
598
+ "",
599
+ `- Your id: ${profile.agentId} (agent id)`,
600
+ `- Your name: ${profile.displayName}`,
601
+ `- Role: ${profile.role}`,
602
+ `- For info about your level on the organiztion, run \`opengoat agent info ${profile.agentId}\`.`,
603
+ "- To delegate and coordinate work, use `og-*` skills.",
604
+ "- Organization context is available in `../../organization` - read them",
605
+ "- You can view and edit the wiki in `../../organization/wiki`",
606
+ "",
607
+ "---",
608
+ "",
609
+ "_This file is yours to evolve. Update it as you learn your role and responsibilities in the organization._",
610
+ ].join("\n");
611
+ }
191
612
  //# sourceMappingURL=agent.service.js.map