@clinebot/core 0.0.0

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 (200) hide show
  1. package/README.md +88 -0
  2. package/dist/account/cline-account-service.d.ts +34 -0
  3. package/dist/account/index.d.ts +3 -0
  4. package/dist/account/rpc.d.ts +38 -0
  5. package/dist/account/types.d.ts +74 -0
  6. package/dist/agents/agent-config-loader.d.ts +18 -0
  7. package/dist/agents/agent-config-parser.d.ts +25 -0
  8. package/dist/agents/hooks-config-loader.d.ts +23 -0
  9. package/dist/agents/index.d.ts +11 -0
  10. package/dist/agents/plugin-config-loader.d.ts +22 -0
  11. package/dist/agents/plugin-loader.d.ts +9 -0
  12. package/dist/agents/plugin-sandbox.d.ts +12 -0
  13. package/dist/agents/unified-config-file-watcher.d.ts +77 -0
  14. package/dist/agents/user-instruction-config-loader.d.ts +63 -0
  15. package/dist/auth/client.d.ts +11 -0
  16. package/dist/auth/cline.d.ts +41 -0
  17. package/dist/auth/codex.d.ts +39 -0
  18. package/dist/auth/oca.d.ts +22 -0
  19. package/dist/auth/server.d.ts +22 -0
  20. package/dist/auth/types.d.ts +72 -0
  21. package/dist/auth/utils.d.ts +32 -0
  22. package/dist/chat/chat-schema.d.ts +145 -0
  23. package/dist/default-tools/constants.d.ts +23 -0
  24. package/dist/default-tools/definitions.d.ts +96 -0
  25. package/dist/default-tools/executors/apply-patch-parser.d.ts +68 -0
  26. package/dist/default-tools/executors/apply-patch.d.ts +26 -0
  27. package/dist/default-tools/executors/bash.d.ts +49 -0
  28. package/dist/default-tools/executors/editor.d.ts +31 -0
  29. package/dist/default-tools/executors/file-read.d.ts +40 -0
  30. package/dist/default-tools/executors/index.d.ts +44 -0
  31. package/dist/default-tools/executors/search.d.ts +50 -0
  32. package/dist/default-tools/executors/web-fetch.d.ts +58 -0
  33. package/dist/default-tools/index.d.ts +57 -0
  34. package/dist/default-tools/presets.d.ts +124 -0
  35. package/dist/default-tools/schemas.d.ts +121 -0
  36. package/dist/default-tools/types.d.ts +237 -0
  37. package/dist/index.d.ts +23 -0
  38. package/dist/index.js +220 -0
  39. package/dist/input/file-indexer.d.ts +5 -0
  40. package/dist/input/index.d.ts +4 -0
  41. package/dist/input/mention-enricher.d.ts +12 -0
  42. package/dist/mcp/config-loader.d.ts +15 -0
  43. package/dist/mcp/index.d.ts +4 -0
  44. package/dist/mcp/manager.d.ts +24 -0
  45. package/dist/mcp/types.d.ts +66 -0
  46. package/dist/runtime/hook-file-hooks.d.ts +18 -0
  47. package/dist/runtime/rules.d.ts +5 -0
  48. package/dist/runtime/runtime-builder.d.ts +5 -0
  49. package/dist/runtime/sandbox/subprocess-sandbox.d.ts +19 -0
  50. package/dist/runtime/session-runtime.d.ts +36 -0
  51. package/dist/runtime/tool-approval.d.ts +9 -0
  52. package/dist/runtime/workflows.d.ts +13 -0
  53. package/dist/server/index.d.ts +47 -0
  54. package/dist/server/index.js +641 -0
  55. package/dist/session/default-session-manager.d.ts +77 -0
  56. package/dist/session/rpc-session-service.d.ts +12 -0
  57. package/dist/session/runtime-oauth-token-manager.d.ts +28 -0
  58. package/dist/session/session-artifacts.d.ts +19 -0
  59. package/dist/session/session-graph.d.ts +15 -0
  60. package/dist/session/session-host.d.ts +21 -0
  61. package/dist/session/session-manager.d.ts +50 -0
  62. package/dist/session/session-manifest.d.ts +30 -0
  63. package/dist/session/session-service.d.ts +113 -0
  64. package/dist/session/sqlite-rpc-session-backend.d.ts +30 -0
  65. package/dist/session/unified-session-persistence-service.d.ts +93 -0
  66. package/dist/session/workspace-manager.d.ts +28 -0
  67. package/dist/session/workspace-manifest.d.ts +25 -0
  68. package/dist/storage/provider-settings-legacy-migration.d.ts +13 -0
  69. package/dist/storage/provider-settings-manager.d.ts +20 -0
  70. package/dist/storage/sqlite-session-store.d.ts +29 -0
  71. package/dist/storage/sqlite-team-store.d.ts +31 -0
  72. package/dist/storage/team-store.d.ts +2 -0
  73. package/dist/team/index.d.ts +1 -0
  74. package/dist/team/projections.d.ts +8 -0
  75. package/dist/types/common.d.ts +10 -0
  76. package/dist/types/config.d.ts +37 -0
  77. package/dist/types/events.d.ts +54 -0
  78. package/dist/types/provider-settings.d.ts +20 -0
  79. package/dist/types/sessions.d.ts +9 -0
  80. package/dist/types/storage.d.ts +37 -0
  81. package/dist/types/workspace.d.ts +7 -0
  82. package/dist/types.d.ts +26 -0
  83. package/package.json +63 -0
  84. package/src/account/cline-account-service.test.ts +101 -0
  85. package/src/account/cline-account-service.ts +267 -0
  86. package/src/account/index.ts +20 -0
  87. package/src/account/rpc.test.ts +62 -0
  88. package/src/account/rpc.ts +172 -0
  89. package/src/account/types.ts +80 -0
  90. package/src/agents/agent-config-loader.test.ts +234 -0
  91. package/src/agents/agent-config-loader.ts +107 -0
  92. package/src/agents/agent-config-parser.ts +191 -0
  93. package/src/agents/hooks-config-loader.ts +97 -0
  94. package/src/agents/index.ts +84 -0
  95. package/src/agents/plugin-config-loader.test.ts +91 -0
  96. package/src/agents/plugin-config-loader.ts +160 -0
  97. package/src/agents/plugin-loader.test.ts +102 -0
  98. package/src/agents/plugin-loader.ts +105 -0
  99. package/src/agents/plugin-sandbox.test.ts +120 -0
  100. package/src/agents/plugin-sandbox.ts +471 -0
  101. package/src/agents/unified-config-file-watcher.test.ts +196 -0
  102. package/src/agents/unified-config-file-watcher.ts +483 -0
  103. package/src/agents/user-instruction-config-loader.test.ts +158 -0
  104. package/src/agents/user-instruction-config-loader.ts +438 -0
  105. package/src/auth/client.test.ts +40 -0
  106. package/src/auth/client.ts +25 -0
  107. package/src/auth/cline.test.ts +130 -0
  108. package/src/auth/cline.ts +414 -0
  109. package/src/auth/codex.test.ts +170 -0
  110. package/src/auth/codex.ts +466 -0
  111. package/src/auth/oca.test.ts +215 -0
  112. package/src/auth/oca.ts +546 -0
  113. package/src/auth/server.ts +216 -0
  114. package/src/auth/types.ts +78 -0
  115. package/src/auth/utils.test.ts +128 -0
  116. package/src/auth/utils.ts +247 -0
  117. package/src/chat/chat-schema.ts +82 -0
  118. package/src/default-tools/constants.ts +35 -0
  119. package/src/default-tools/definitions.test.ts +233 -0
  120. package/src/default-tools/definitions.ts +632 -0
  121. package/src/default-tools/executors/apply-patch-parser.ts +520 -0
  122. package/src/default-tools/executors/apply-patch.ts +359 -0
  123. package/src/default-tools/executors/bash.ts +205 -0
  124. package/src/default-tools/executors/editor.ts +231 -0
  125. package/src/default-tools/executors/file-read.test.ts +25 -0
  126. package/src/default-tools/executors/file-read.ts +94 -0
  127. package/src/default-tools/executors/index.ts +75 -0
  128. package/src/default-tools/executors/search.ts +278 -0
  129. package/src/default-tools/executors/web-fetch.ts +259 -0
  130. package/src/default-tools/index.ts +161 -0
  131. package/src/default-tools/presets.test.ts +63 -0
  132. package/src/default-tools/presets.ts +168 -0
  133. package/src/default-tools/schemas.ts +228 -0
  134. package/src/default-tools/types.ts +324 -0
  135. package/src/index.ts +119 -0
  136. package/src/input/file-indexer.d.ts +11 -0
  137. package/src/input/file-indexer.test.ts +87 -0
  138. package/src/input/file-indexer.ts +280 -0
  139. package/src/input/index.ts +7 -0
  140. package/src/input/mention-enricher.test.ts +82 -0
  141. package/src/input/mention-enricher.ts +119 -0
  142. package/src/mcp/config-loader.test.ts +238 -0
  143. package/src/mcp/config-loader.ts +219 -0
  144. package/src/mcp/index.ts +26 -0
  145. package/src/mcp/manager.test.ts +106 -0
  146. package/src/mcp/manager.ts +262 -0
  147. package/src/mcp/types.ts +88 -0
  148. package/src/runtime/hook-file-hooks.test.ts +106 -0
  149. package/src/runtime/hook-file-hooks.ts +736 -0
  150. package/src/runtime/index.ts +27 -0
  151. package/src/runtime/rules.ts +34 -0
  152. package/src/runtime/runtime-builder.team-persistence.test.ts +203 -0
  153. package/src/runtime/runtime-builder.test.ts +215 -0
  154. package/src/runtime/runtime-builder.ts +515 -0
  155. package/src/runtime/runtime-parity.test.ts +132 -0
  156. package/src/runtime/sandbox/subprocess-sandbox.ts +207 -0
  157. package/src/runtime/session-runtime.ts +44 -0
  158. package/src/runtime/tool-approval.ts +104 -0
  159. package/src/runtime/workflows.test.ts +119 -0
  160. package/src/runtime/workflows.ts +54 -0
  161. package/src/server/index.ts +282 -0
  162. package/src/session/default-session-manager.e2e.test.ts +354 -0
  163. package/src/session/default-session-manager.test.ts +816 -0
  164. package/src/session/default-session-manager.ts +1286 -0
  165. package/src/session/index.ts +37 -0
  166. package/src/session/rpc-session-service.ts +189 -0
  167. package/src/session/runtime-oauth-token-manager.test.ts +137 -0
  168. package/src/session/runtime-oauth-token-manager.ts +265 -0
  169. package/src/session/session-artifacts.ts +106 -0
  170. package/src/session/session-graph.ts +90 -0
  171. package/src/session/session-host.ts +190 -0
  172. package/src/session/session-manager.ts +56 -0
  173. package/src/session/session-manifest.ts +29 -0
  174. package/src/session/session-service.team-persistence.test.ts +48 -0
  175. package/src/session/session-service.ts +610 -0
  176. package/src/session/sqlite-rpc-session-backend.ts +303 -0
  177. package/src/session/unified-session-persistence-service.ts +781 -0
  178. package/src/session/workspace-manager.ts +98 -0
  179. package/src/session/workspace-manifest.ts +100 -0
  180. package/src/storage/artifact-store.ts +1 -0
  181. package/src/storage/index.ts +11 -0
  182. package/src/storage/provider-settings-legacy-migration.test.ts +175 -0
  183. package/src/storage/provider-settings-legacy-migration.ts +637 -0
  184. package/src/storage/provider-settings-manager.test.ts +111 -0
  185. package/src/storage/provider-settings-manager.ts +129 -0
  186. package/src/storage/session-store.ts +1 -0
  187. package/src/storage/sqlite-session-store.ts +270 -0
  188. package/src/storage/sqlite-team-store.ts +443 -0
  189. package/src/storage/team-store.ts +5 -0
  190. package/src/team/index.ts +4 -0
  191. package/src/team/projections.ts +285 -0
  192. package/src/types/common.ts +14 -0
  193. package/src/types/config.ts +64 -0
  194. package/src/types/events.ts +46 -0
  195. package/src/types/index.ts +24 -0
  196. package/src/types/provider-settings.ts +43 -0
  197. package/src/types/sessions.ts +16 -0
  198. package/src/types/storage.ts +64 -0
  199. package/src/types/workspace.ts +7 -0
  200. package/src/types.ts +127 -0
@@ -0,0 +1,27 @@
1
+ export {
2
+ formatRulesForSystemPrompt,
3
+ isRuleEnabled,
4
+ listEnabledRulesFromWatcher,
5
+ loadRulesForSystemPromptFromWatcher,
6
+ } from "./rules";
7
+ export { createTeamName, DefaultRuntimeBuilder } from "./runtime-builder";
8
+ export {
9
+ type SandboxCallOptions,
10
+ SubprocessSandbox,
11
+ type SubprocessSandboxOptions,
12
+ } from "./sandbox/subprocess-sandbox";
13
+ export type {
14
+ BuiltRuntime,
15
+ RuntimeBuilder,
16
+ RuntimeBuilderInput,
17
+ SessionRuntime,
18
+ } from "./session-runtime";
19
+ export {
20
+ type DesktopToolApprovalOptions,
21
+ requestDesktopToolApproval,
22
+ } from "./tool-approval";
23
+ export {
24
+ type AvailableWorkflow,
25
+ listAvailableWorkflowsFromWatcher,
26
+ resolveWorkflowSlashCommandFromWatcher,
27
+ } from "./workflows";
@@ -0,0 +1,34 @@
1
+ import type { RuleConfig, UserInstructionConfigWatcher } from "../agents";
2
+
3
+ export function isRuleEnabled(rule: RuleConfig): boolean {
4
+ return rule.disabled !== true;
5
+ }
6
+
7
+ export function formatRulesForSystemPrompt(
8
+ rules: ReadonlyArray<RuleConfig>,
9
+ ): string {
10
+ if (rules.length === 0) {
11
+ return "";
12
+ }
13
+
14
+ const renderedRules = rules
15
+ .map((rule) => `## ${rule.name}\n${rule.instructions}`)
16
+ .join("\n\n");
17
+ return `\n\n# Rules\n${renderedRules}`;
18
+ }
19
+
20
+ export function listEnabledRulesFromWatcher(
21
+ watcher: UserInstructionConfigWatcher,
22
+ ): RuleConfig[] {
23
+ const snapshot = watcher.getSnapshot("rule");
24
+ return [...snapshot.values()]
25
+ .map((record) => record.item as RuleConfig)
26
+ .filter(isRuleEnabled)
27
+ .sort((a, b) => a.name.localeCompare(b.name));
28
+ }
29
+
30
+ export function loadRulesForSystemPromptFromWatcher(
31
+ watcher: UserInstructionConfigWatcher,
32
+ ): string {
33
+ return formatRulesForSystemPrompt(listEnabledRulesFromWatcher(watcher));
34
+ }
@@ -0,0 +1,203 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ const createBuiltinToolsMock = vi.fn(() => []);
4
+ const bootstrapAgentTeamsMock = vi.fn(() => ({
5
+ tools: [],
6
+ restoredFromPersistence: true,
7
+ restoredTeammates: ["restored-1"],
8
+ }));
9
+
10
+ let runtimeInstance: MockAgentTeamsRuntime | undefined;
11
+ class MockAgentTeamsRuntime {
12
+ private readonly onTeamEvent?: (event: any) => void;
13
+
14
+ constructor(options: { onTeamEvent?: (event: any) => void }) {
15
+ this.onTeamEvent = options.onTeamEvent;
16
+ runtimeInstance = this;
17
+ }
18
+
19
+ emit(event: any): void {
20
+ this.onTeamEvent?.(event);
21
+ }
22
+
23
+ hydrateState = vi.fn();
24
+ exportState = vi.fn(() => ({
25
+ members: [],
26
+ tasks: [],
27
+ mailbox: [],
28
+ missionLog: [],
29
+ runs: [],
30
+ outcomes: [],
31
+ outcomeFragments: [],
32
+ }));
33
+ markStaleRunsInterrupted = vi.fn();
34
+ getTeammateIds = vi.fn(() => []);
35
+ shutdownTeammate = vi.fn();
36
+ }
37
+
38
+ vi.mock("@clinebot/agents", () => ({
39
+ AgentTeamsRuntime: MockAgentTeamsRuntime,
40
+ bootstrapAgentTeams: bootstrapAgentTeamsMock,
41
+ }));
42
+
43
+ vi.mock("../default-tools", () => ({
44
+ ALL_DEFAULT_TOOL_NAMES: [],
45
+ createBuiltinTools: createBuiltinToolsMock,
46
+ ToolPresets: {
47
+ development: {},
48
+ readonly: {},
49
+ },
50
+ }));
51
+
52
+ let teamStoreInstance: MockSqliteTeamStore | undefined;
53
+ class MockSqliteTeamStore {
54
+ constructor() {
55
+ teamStoreInstance = this;
56
+ }
57
+
58
+ init = vi.fn();
59
+ loadRuntime = vi.fn(() => ({
60
+ state: {
61
+ teamId: "team_1",
62
+ teamName: "test",
63
+ members: [],
64
+ tasks: [],
65
+ mailbox: [],
66
+ missionLog: [],
67
+ runs: [],
68
+ outcomes: [],
69
+ outcomeFragments: [],
70
+ },
71
+ teammates: [
72
+ {
73
+ agentId: "restored-1",
74
+ rolePrompt: "Persisted teammate",
75
+ modelId: "claude-sonnet-4-5-20250929",
76
+ maxIterations: 4,
77
+ },
78
+ ],
79
+ interruptedRunIds: ["run_00001"],
80
+ }));
81
+ handleTeamEvent = vi.fn();
82
+ persistRuntime = vi.fn();
83
+ }
84
+
85
+ vi.mock("../storage/sqlite-team-store", () => ({
86
+ SqliteTeamStore: MockSqliteTeamStore,
87
+ }));
88
+
89
+ describe("DefaultRuntimeBuilder team persistence boundary", () => {
90
+ it("persists teammate specs and runtime state from team events", async () => {
91
+ const { DefaultRuntimeBuilder } = await import("./runtime-builder");
92
+ const onTeamRestored = vi.fn();
93
+
94
+ new DefaultRuntimeBuilder().build({
95
+ config: {
96
+ providerId: "anthropic",
97
+ modelId: "claude-sonnet-4-6",
98
+ apiKey: "key",
99
+ headers: {
100
+ Authorization: "Bearer team-token",
101
+ },
102
+ systemPrompt: "test",
103
+ cwd: process.cwd(),
104
+ enableTools: false,
105
+ enableSpawnAgent: false,
106
+ enableAgentTeams: true,
107
+ },
108
+ onTeamRestored,
109
+ });
110
+
111
+ expect(bootstrapAgentTeamsMock).toHaveBeenCalledWith(
112
+ expect.objectContaining({
113
+ restoredFromPersistence: true,
114
+ restoredTeammates: [expect.objectContaining({ agentId: "restored-1" })],
115
+ teammateRuntime: expect.objectContaining({
116
+ headers: {
117
+ Authorization: "Bearer team-token",
118
+ },
119
+ }),
120
+ }),
121
+ );
122
+ expect(onTeamRestored).toHaveBeenCalledTimes(1);
123
+ expect(runtimeInstance).toBeDefined();
124
+ expect(teamStoreInstance).toBeDefined();
125
+ if (!runtimeInstance || !teamStoreInstance) {
126
+ throw new Error("Expected mocked runtime and team store instances");
127
+ }
128
+
129
+ expect(runtimeInstance.markStaleRunsInterrupted).toHaveBeenCalledWith(
130
+ "runtime_recovered",
131
+ );
132
+
133
+ runtimeInstance.emit({
134
+ type: "teammate_spawned",
135
+ agentId: "python-poet",
136
+ teammate: {
137
+ rolePrompt: "Write concise Python-focused haiku",
138
+ modelId: "claude-sonnet-4-5-20250929",
139
+ maxIterations: 7,
140
+ },
141
+ });
142
+ expect(teamStoreInstance.handleTeamEvent).toHaveBeenCalledWith(
143
+ expect.any(String),
144
+ expect.objectContaining({
145
+ type: "teammate_spawned",
146
+ agentId: "python-poet",
147
+ }),
148
+ );
149
+ expect(teamStoreInstance.persistRuntime).toHaveBeenCalled();
150
+
151
+ runtimeInstance.emit({
152
+ type: "teammate_shutdown",
153
+ agentId: "python-poet",
154
+ });
155
+ expect(teamStoreInstance.handleTeamEvent).toHaveBeenCalledWith(
156
+ expect.any(String),
157
+ expect.objectContaining({
158
+ type: "teammate_shutdown",
159
+ agentId: "python-poet",
160
+ }),
161
+ );
162
+ });
163
+
164
+ it("forwards cline workspace metadata to teammate runtime bootstrap config", async () => {
165
+ const { DefaultRuntimeBuilder } = await import("./runtime-builder");
166
+ bootstrapAgentTeamsMock.mockClear();
167
+
168
+ new DefaultRuntimeBuilder().build({
169
+ config: {
170
+ providerId: "cline",
171
+ modelId: "anthropic/claude-sonnet-4.6",
172
+ apiKey: "key",
173
+ systemPrompt: `Base instructions.
174
+
175
+ # Workspace Configuration
176
+ {
177
+ "workspaces": {
178
+ "/repo/demo": {
179
+ "hint": "demo",
180
+ "latestGitBranchName": "main"
181
+ }
182
+ }
183
+ }`,
184
+ cwd: "/repo/demo",
185
+ enableTools: false,
186
+ enableSpawnAgent: false,
187
+ enableAgentTeams: true,
188
+ },
189
+ });
190
+
191
+ expect(bootstrapAgentTeamsMock).toHaveBeenCalledWith(
192
+ expect.objectContaining({
193
+ teammateRuntime: expect.objectContaining({
194
+ providerId: "cline",
195
+ cwd: "/repo/demo",
196
+ clineWorkspaceMetadata: expect.stringContaining(
197
+ "# Workspace Configuration",
198
+ ),
199
+ }),
200
+ }),
201
+ );
202
+ });
203
+ });
@@ -0,0 +1,215 @@
1
+ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import type { Tool } from "@clinebot/agents";
5
+ import { describe, expect, it } from "vitest";
6
+ import { DefaultRuntimeBuilder } from "./runtime-builder";
7
+
8
+ function makeSpawnTool(): Tool {
9
+ return {
10
+ name: "spawn_agent",
11
+ description: "Spawn a subagent",
12
+ inputSchema: { type: "object", properties: {}, required: [] },
13
+ execute: async () => ({ ok: true }),
14
+ };
15
+ }
16
+
17
+ describe("DefaultRuntimeBuilder", () => {
18
+ it("includes builtin tools when enabled", () => {
19
+ const runtime = new DefaultRuntimeBuilder().build({
20
+ config: {
21
+ providerId: "anthropic",
22
+ modelId: "claude-sonnet-4-6",
23
+ apiKey: "key",
24
+ systemPrompt: "test",
25
+ cwd: process.cwd(),
26
+ enableTools: true,
27
+ enableSpawnAgent: false,
28
+ enableAgentTeams: false,
29
+ },
30
+ });
31
+
32
+ const names = runtime.tools.map((tool) => tool.name);
33
+ expect(names.length).toBeGreaterThan(0);
34
+ expect(names).not.toContain("spawn_agent");
35
+ });
36
+
37
+ it("forwards runtime logger for downstream agent creation", () => {
38
+ const logger = {
39
+ info: () => {},
40
+ };
41
+ const runtime = new DefaultRuntimeBuilder().build({
42
+ config: {
43
+ providerId: "anthropic",
44
+ modelId: "claude-sonnet-4-6",
45
+ apiKey: "key",
46
+ systemPrompt: "test",
47
+ cwd: process.cwd(),
48
+ enableTools: false,
49
+ enableSpawnAgent: false,
50
+ enableAgentTeams: false,
51
+ logger,
52
+ },
53
+ });
54
+
55
+ expect(runtime.logger).toBe(logger);
56
+ });
57
+
58
+ it("uses readonly preset in plan mode", () => {
59
+ const runtime = new DefaultRuntimeBuilder().build({
60
+ config: {
61
+ providerId: "anthropic",
62
+ modelId: "claude-sonnet-4-6",
63
+ apiKey: "key",
64
+ systemPrompt: "test",
65
+ cwd: process.cwd(),
66
+ mode: "plan",
67
+ enableTools: true,
68
+ enableSpawnAgent: false,
69
+ enableAgentTeams: false,
70
+ },
71
+ });
72
+
73
+ const names = runtime.tools.map((tool) => tool.name);
74
+ expect(names).not.toContain("editor");
75
+ });
76
+
77
+ it("omits builtin tools when disabled", () => {
78
+ const runtime = new DefaultRuntimeBuilder().build({
79
+ config: {
80
+ providerId: "anthropic",
81
+ modelId: "claude-sonnet-4-6",
82
+ apiKey: "key",
83
+ systemPrompt: "test",
84
+ cwd: process.cwd(),
85
+ enableTools: false,
86
+ enableSpawnAgent: false,
87
+ enableAgentTeams: false,
88
+ },
89
+ });
90
+
91
+ expect(runtime.tools).toEqual([]);
92
+ });
93
+
94
+ it("adds spawn tool when enabled", () => {
95
+ const runtime = new DefaultRuntimeBuilder().build({
96
+ config: {
97
+ providerId: "anthropic",
98
+ modelId: "claude-sonnet-4-6",
99
+ apiKey: "key",
100
+ systemPrompt: "test",
101
+ cwd: process.cwd(),
102
+ enableTools: false,
103
+ enableSpawnAgent: true,
104
+ enableAgentTeams: false,
105
+ },
106
+ createSpawnTool: makeSpawnTool,
107
+ });
108
+
109
+ expect(runtime.tools.map((tool) => tool.name)).toContain("spawn_agent");
110
+ });
111
+
112
+ it("provides a shutdown helper", () => {
113
+ const runtime = new DefaultRuntimeBuilder().build({
114
+ config: {
115
+ providerId: "anthropic",
116
+ modelId: "claude-sonnet-4-6",
117
+ apiKey: "key",
118
+ systemPrompt: "test",
119
+ cwd: process.cwd(),
120
+ enableTools: false,
121
+ enableSpawnAgent: false,
122
+ enableAgentTeams: false,
123
+ },
124
+ });
125
+
126
+ expect(() => runtime.shutdown("test")).not.toThrow();
127
+ });
128
+
129
+ it("includes skills tool when workspace skills are available", () => {
130
+ const cwd = mkdtempSync(join(tmpdir(), "runtime-builder-skills-"));
131
+ const skillDir = join(cwd, ".cline", "skills", "commit");
132
+ mkdirSync(skillDir, { recursive: true });
133
+ writeFileSync(
134
+ join(skillDir, "SKILL.md"),
135
+ `---
136
+ name: commit
137
+ description: Create commit message
138
+ ---
139
+ Use conventional commits.`,
140
+ "utf8",
141
+ );
142
+
143
+ const runtime = new DefaultRuntimeBuilder().build({
144
+ config: {
145
+ providerId: "anthropic",
146
+ modelId: "claude-sonnet-4-6",
147
+ apiKey: "key",
148
+ systemPrompt: "test",
149
+ cwd,
150
+ enableTools: true,
151
+ enableSpawnAgent: false,
152
+ enableAgentTeams: false,
153
+ },
154
+ });
155
+
156
+ expect(runtime.tools.map((tool) => tool.name)).toContain("skills");
157
+ runtime.shutdown("test");
158
+ });
159
+
160
+ it("marks configured but disabled skills in executor metadata", async () => {
161
+ const cwd = mkdtempSync(join(tmpdir(), "runtime-builder-skills-disabled-"));
162
+ const enabledDir = join(cwd, ".cline", "skills", "commit");
163
+ const disabledDir = join(cwd, ".cline", "skills", "review");
164
+ mkdirSync(enabledDir, { recursive: true });
165
+ mkdirSync(disabledDir, { recursive: true });
166
+ writeFileSync(
167
+ join(enabledDir, "SKILL.md"),
168
+ `---
169
+ name: commit
170
+ ---
171
+ Enabled skill.`,
172
+ "utf8",
173
+ );
174
+ writeFileSync(
175
+ join(disabledDir, "SKILL.md"),
176
+ `---
177
+ name: review
178
+ disabled: true
179
+ ---
180
+ Disabled skill.`,
181
+ "utf8",
182
+ );
183
+
184
+ const runtime = new DefaultRuntimeBuilder().build({
185
+ config: {
186
+ providerId: "anthropic",
187
+ modelId: "claude-sonnet-4-6",
188
+ apiKey: "key",
189
+ systemPrompt: "test",
190
+ cwd,
191
+ enableTools: true,
192
+ enableSpawnAgent: false,
193
+ enableAgentTeams: false,
194
+ },
195
+ });
196
+
197
+ const skillsTool = runtime.tools.find((tool) => tool.name === "skills");
198
+ expect(skillsTool).toBeDefined();
199
+ if (!skillsTool) {
200
+ throw new Error("Expected skills tool.");
201
+ }
202
+
203
+ const disabledResult = await skillsTool.execute(
204
+ { skill: "review" },
205
+ {
206
+ agentId: "agent-1",
207
+ conversationId: "conv-1",
208
+ iteration: 1,
209
+ },
210
+ );
211
+ expect(disabledResult).toContain("configured but disabled");
212
+
213
+ runtime.shutdown("test");
214
+ });
215
+ });