@herdctl/core 0.0.1 → 0.1.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 (284) hide show
  1. package/dist/config/__tests__/agent.test.js +61 -13
  2. package/dist/config/__tests__/agent.test.js.map +1 -1
  3. package/dist/config/__tests__/merge.test.js +10 -3
  4. package/dist/config/__tests__/merge.test.js.map +1 -1
  5. package/dist/config/__tests__/schema.test.js +350 -1
  6. package/dist/config/__tests__/schema.test.js.map +1 -1
  7. package/dist/config/index.d.ts +1 -1
  8. package/dist/config/index.d.ts.map +1 -1
  9. package/dist/config/index.js +3 -1
  10. package/dist/config/index.js.map +1 -1
  11. package/dist/config/schema.d.ts +841 -27
  12. package/dist/config/schema.d.ts.map +1 -1
  13. package/dist/config/schema.js +129 -10
  14. package/dist/config/schema.js.map +1 -1
  15. package/dist/fleet-manager/__tests__/coverage.test.js +14 -331
  16. package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -1
  17. package/dist/fleet-manager/__tests__/errors.test.js +1 -49
  18. package/dist/fleet-manager/__tests__/errors.test.js.map +1 -1
  19. package/dist/fleet-manager/__tests__/integration.test.js +114 -0
  20. package/dist/fleet-manager/__tests__/integration.test.js.map +1 -1
  21. package/dist/fleet-manager/__tests__/job-control.test.js +13 -14
  22. package/dist/fleet-manager/__tests__/job-control.test.js.map +1 -1
  23. package/dist/fleet-manager/__tests__/reload.test.js +12 -2
  24. package/dist/fleet-manager/__tests__/reload.test.js.map +1 -1
  25. package/dist/fleet-manager/__tests__/status-queries.test.js +6 -0
  26. package/dist/fleet-manager/__tests__/status-queries.test.js.map +1 -1
  27. package/dist/fleet-manager/__tests__/trigger.test.js +10 -2
  28. package/dist/fleet-manager/__tests__/trigger.test.js.map +1 -1
  29. package/dist/fleet-manager/config-reload.d.ts +164 -0
  30. package/dist/fleet-manager/config-reload.d.ts.map +1 -0
  31. package/dist/fleet-manager/config-reload.js +445 -0
  32. package/dist/fleet-manager/config-reload.js.map +1 -0
  33. package/dist/fleet-manager/context.d.ts +76 -0
  34. package/dist/fleet-manager/context.d.ts.map +1 -0
  35. package/dist/fleet-manager/context.js +11 -0
  36. package/dist/fleet-manager/context.js.map +1 -0
  37. package/dist/fleet-manager/errors.d.ts +0 -25
  38. package/dist/fleet-manager/errors.d.ts.map +1 -1
  39. package/dist/fleet-manager/errors.js +0 -38
  40. package/dist/fleet-manager/errors.js.map +1 -1
  41. package/dist/fleet-manager/event-emitters.d.ts +123 -0
  42. package/dist/fleet-manager/event-emitters.d.ts.map +1 -0
  43. package/dist/fleet-manager/event-emitters.js +136 -0
  44. package/dist/fleet-manager/event-emitters.js.map +1 -0
  45. package/dist/fleet-manager/event-types.d.ts +0 -15
  46. package/dist/fleet-manager/event-types.d.ts.map +1 -1
  47. package/dist/fleet-manager/fleet-manager.d.ts +40 -653
  48. package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
  49. package/dist/fleet-manager/fleet-manager.js +95 -1720
  50. package/dist/fleet-manager/fleet-manager.js.map +1 -1
  51. package/dist/fleet-manager/index.d.ts +13 -2
  52. package/dist/fleet-manager/index.d.ts.map +1 -1
  53. package/dist/fleet-manager/index.js +19 -6
  54. package/dist/fleet-manager/index.js.map +1 -1
  55. package/dist/fleet-manager/job-control.d.ts +67 -0
  56. package/dist/fleet-manager/job-control.d.ts.map +1 -0
  57. package/dist/fleet-manager/job-control.js +333 -0
  58. package/dist/fleet-manager/job-control.js.map +1 -0
  59. package/dist/fleet-manager/log-streaming.d.ts +171 -0
  60. package/dist/fleet-manager/log-streaming.d.ts.map +1 -0
  61. package/dist/fleet-manager/log-streaming.js +503 -0
  62. package/dist/fleet-manager/log-streaming.js.map +1 -0
  63. package/dist/fleet-manager/schedule-executor.d.ts +63 -0
  64. package/dist/fleet-manager/schedule-executor.d.ts.map +1 -0
  65. package/dist/fleet-manager/schedule-executor.js +209 -0
  66. package/dist/fleet-manager/schedule-executor.js.map +1 -0
  67. package/dist/fleet-manager/schedule-management.d.ts +71 -0
  68. package/dist/fleet-manager/schedule-management.d.ts.map +1 -0
  69. package/dist/fleet-manager/schedule-management.js +171 -0
  70. package/dist/fleet-manager/schedule-management.js.map +1 -0
  71. package/dist/fleet-manager/status-queries.d.ts +105 -0
  72. package/dist/fleet-manager/status-queries.d.ts.map +1 -0
  73. package/dist/fleet-manager/status-queries.js +247 -0
  74. package/dist/fleet-manager/status-queries.js.map +1 -0
  75. package/dist/fleet-manager/types.d.ts +0 -39
  76. package/dist/fleet-manager/types.d.ts.map +1 -1
  77. package/dist/runner/__tests__/job-executor.test.js +206 -1
  78. package/dist/runner/__tests__/job-executor.test.js.map +1 -1
  79. package/dist/runner/job-executor.d.ts +9 -0
  80. package/dist/runner/job-executor.d.ts.map +1 -1
  81. package/dist/runner/job-executor.js +78 -4
  82. package/dist/runner/job-executor.js.map +1 -1
  83. package/dist/runner/message-processor.d.ts.map +1 -1
  84. package/dist/runner/message-processor.js +53 -0
  85. package/dist/runner/message-processor.js.map +1 -1
  86. package/dist/runner/types.d.ts +3 -1
  87. package/dist/runner/types.d.ts.map +1 -1
  88. package/dist/scheduler/__tests__/cron.test.d.ts +2 -0
  89. package/dist/scheduler/__tests__/cron.test.d.ts.map +1 -0
  90. package/dist/scheduler/__tests__/cron.test.js +867 -0
  91. package/dist/scheduler/__tests__/cron.test.js.map +1 -0
  92. package/dist/scheduler/__tests__/scheduler.test.js +164 -5
  93. package/dist/scheduler/__tests__/scheduler.test.js.map +1 -1
  94. package/dist/scheduler/cron.d.ts +126 -0
  95. package/dist/scheduler/cron.d.ts.map +1 -0
  96. package/dist/scheduler/cron.js +390 -0
  97. package/dist/scheduler/cron.js.map +1 -0
  98. package/dist/scheduler/errors.d.ts +81 -1
  99. package/dist/scheduler/errors.d.ts.map +1 -1
  100. package/dist/scheduler/errors.js +81 -6
  101. package/dist/scheduler/errors.js.map +1 -1
  102. package/dist/scheduler/index.d.ts +1 -0
  103. package/dist/scheduler/index.d.ts.map +1 -1
  104. package/dist/scheduler/index.js +2 -0
  105. package/dist/scheduler/index.js.map +1 -1
  106. package/dist/scheduler/schedule-runner.d.ts +2 -2
  107. package/dist/scheduler/schedule-runner.d.ts.map +1 -1
  108. package/dist/scheduler/schedule-runner.js +20 -8
  109. package/dist/scheduler/schedule-runner.js.map +1 -1
  110. package/dist/scheduler/scheduler.d.ts +4 -4
  111. package/dist/scheduler/scheduler.d.ts.map +1 -1
  112. package/dist/scheduler/scheduler.js +95 -20
  113. package/dist/scheduler/scheduler.js.map +1 -1
  114. package/dist/scheduler/types.d.ts +1 -1
  115. package/dist/scheduler/types.d.ts.map +1 -1
  116. package/dist/state/schemas/job-metadata.d.ts +2 -2
  117. package/package.json +33 -8
  118. package/.turbo/turbo-build.log +0 -4
  119. package/.turbo/turbo-test.log +0 -219
  120. package/.turbo/turbo-typecheck.log +0 -4
  121. package/coverage/base.css +0 -224
  122. package/coverage/block-navigation.js +0 -87
  123. package/coverage/coverage-final.json +0 -51
  124. package/coverage/favicon.png +0 -0
  125. package/coverage/index.html +0 -251
  126. package/coverage/prettify.css +0 -1
  127. package/coverage/prettify.js +0 -2
  128. package/coverage/sort-arrow-sprite.png +0 -0
  129. package/coverage/sorter.js +0 -210
  130. package/coverage/src/config/index.html +0 -191
  131. package/coverage/src/config/index.ts.html +0 -442
  132. package/coverage/src/config/interpolate.ts.html +0 -652
  133. package/coverage/src/config/loader.ts.html +0 -1501
  134. package/coverage/src/config/merge.ts.html +0 -823
  135. package/coverage/src/config/parser.ts.html +0 -1213
  136. package/coverage/src/config/schema.ts.html +0 -1123
  137. package/coverage/src/fleet-manager/errors.ts.html +0 -2326
  138. package/coverage/src/fleet-manager/event-types.ts.html +0 -1219
  139. package/coverage/src/fleet-manager/fleet-manager.ts.html +0 -7030
  140. package/coverage/src/fleet-manager/index.html +0 -206
  141. package/coverage/src/fleet-manager/index.ts.html +0 -469
  142. package/coverage/src/fleet-manager/job-manager.ts.html +0 -2074
  143. package/coverage/src/fleet-manager/job-queue.ts.html +0 -2479
  144. package/coverage/src/fleet-manager/types.ts.html +0 -2602
  145. package/coverage/src/index.html +0 -116
  146. package/coverage/src/index.ts.html +0 -181
  147. package/coverage/src/runner/errors.ts.html +0 -1006
  148. package/coverage/src/runner/index.html +0 -191
  149. package/coverage/src/runner/index.ts.html +0 -256
  150. package/coverage/src/runner/job-executor.ts.html +0 -1429
  151. package/coverage/src/runner/message-processor.ts.html +0 -1150
  152. package/coverage/src/runner/sdk-adapter.ts.html +0 -658
  153. package/coverage/src/runner/types.ts.html +0 -559
  154. package/coverage/src/scheduler/errors.ts.html +0 -388
  155. package/coverage/src/scheduler/index.html +0 -206
  156. package/coverage/src/scheduler/index.ts.html +0 -244
  157. package/coverage/src/scheduler/interval.ts.html +0 -652
  158. package/coverage/src/scheduler/schedule-runner.ts.html +0 -1411
  159. package/coverage/src/scheduler/schedule-state.ts.html +0 -718
  160. package/coverage/src/scheduler/scheduler.ts.html +0 -1795
  161. package/coverage/src/scheduler/types.ts.html +0 -733
  162. package/coverage/src/state/directory.ts.html +0 -736
  163. package/coverage/src/state/errors.ts.html +0 -376
  164. package/coverage/src/state/fleet-state.ts.html +0 -937
  165. package/coverage/src/state/index.html +0 -221
  166. package/coverage/src/state/index.ts.html +0 -322
  167. package/coverage/src/state/job-metadata.ts.html +0 -1420
  168. package/coverage/src/state/job-output.ts.html +0 -1033
  169. package/coverage/src/state/schemas/fleet-state.ts.html +0 -445
  170. package/coverage/src/state/schemas/index.html +0 -176
  171. package/coverage/src/state/schemas/index.ts.html +0 -286
  172. package/coverage/src/state/schemas/job-metadata.ts.html +0 -628
  173. package/coverage/src/state/schemas/job-output.ts.html +0 -616
  174. package/coverage/src/state/schemas/session-info.ts.html +0 -361
  175. package/coverage/src/state/session.ts.html +0 -844
  176. package/coverage/src/state/types.ts.html +0 -262
  177. package/coverage/src/state/utils/atomic.ts.html +0 -748
  178. package/coverage/src/state/utils/index.html +0 -146
  179. package/coverage/src/state/utils/index.ts.html +0 -103
  180. package/coverage/src/state/utils/reads.ts.html +0 -1621
  181. package/coverage/src/work-sources/adapters/github.ts.html +0 -3583
  182. package/coverage/src/work-sources/adapters/index.html +0 -131
  183. package/coverage/src/work-sources/adapters/index.ts.html +0 -277
  184. package/coverage/src/work-sources/errors.ts.html +0 -298
  185. package/coverage/src/work-sources/index.html +0 -176
  186. package/coverage/src/work-sources/index.ts.html +0 -529
  187. package/coverage/src/work-sources/manager.ts.html +0 -1324
  188. package/coverage/src/work-sources/registry.ts.html +0 -619
  189. package/coverage/src/work-sources/types.ts.html +0 -568
  190. package/dist/fleet-manager/__tests__/event-helpers.test.d.ts +0 -7
  191. package/dist/fleet-manager/__tests__/event-helpers.test.d.ts.map +0 -1
  192. package/dist/fleet-manager/__tests__/event-helpers.test.js +0 -368
  193. package/dist/fleet-manager/__tests__/event-helpers.test.js.map +0 -1
  194. package/src/config/__tests__/agent.test.ts +0 -864
  195. package/src/config/__tests__/interpolate.test.ts +0 -644
  196. package/src/config/__tests__/loader.test.ts +0 -784
  197. package/src/config/__tests__/merge.test.ts +0 -751
  198. package/src/config/__tests__/parser.test.ts +0 -533
  199. package/src/config/__tests__/schema.test.ts +0 -873
  200. package/src/config/index.ts +0 -119
  201. package/src/config/interpolate.ts +0 -189
  202. package/src/config/loader.ts +0 -472
  203. package/src/config/merge.ts +0 -246
  204. package/src/config/parser.ts +0 -376
  205. package/src/config/schema.ts +0 -346
  206. package/src/fleet-manager/__tests__/coverage.test.ts +0 -2869
  207. package/src/fleet-manager/__tests__/errors.test.ts +0 -660
  208. package/src/fleet-manager/__tests__/event-helpers.test.ts +0 -448
  209. package/src/fleet-manager/__tests__/integration.test.ts +0 -1209
  210. package/src/fleet-manager/__tests__/job-control.test.ts +0 -283
  211. package/src/fleet-manager/__tests__/job-manager.test.ts +0 -869
  212. package/src/fleet-manager/__tests__/job-queue.test.ts +0 -401
  213. package/src/fleet-manager/__tests__/reload.test.ts +0 -751
  214. package/src/fleet-manager/__tests__/status-queries.test.ts +0 -595
  215. package/src/fleet-manager/__tests__/trigger.test.ts +0 -601
  216. package/src/fleet-manager/errors.ts +0 -747
  217. package/src/fleet-manager/event-types.ts +0 -378
  218. package/src/fleet-manager/fleet-manager.ts +0 -2315
  219. package/src/fleet-manager/index.ts +0 -128
  220. package/src/fleet-manager/job-manager.ts +0 -663
  221. package/src/fleet-manager/job-queue.ts +0 -798
  222. package/src/fleet-manager/types.ts +0 -839
  223. package/src/index.ts +0 -32
  224. package/src/runner/__tests__/errors.test.ts +0 -382
  225. package/src/runner/__tests__/job-executor.test.ts +0 -1708
  226. package/src/runner/__tests__/message-processor.test.ts +0 -960
  227. package/src/runner/__tests__/sdk-adapter.test.ts +0 -626
  228. package/src/runner/errors.ts +0 -307
  229. package/src/runner/index.ts +0 -57
  230. package/src/runner/job-executor.ts +0 -448
  231. package/src/runner/message-processor.ts +0 -355
  232. package/src/runner/sdk-adapter.ts +0 -191
  233. package/src/runner/types.ts +0 -158
  234. package/src/scheduler/__tests__/errors.test.ts +0 -159
  235. package/src/scheduler/__tests__/interval.test.ts +0 -515
  236. package/src/scheduler/__tests__/schedule-runner.test.ts +0 -798
  237. package/src/scheduler/__tests__/schedule-state.test.ts +0 -671
  238. package/src/scheduler/__tests__/scheduler.test.ts +0 -1280
  239. package/src/scheduler/errors.ts +0 -101
  240. package/src/scheduler/index.ts +0 -53
  241. package/src/scheduler/interval.ts +0 -189
  242. package/src/scheduler/schedule-runner.ts +0 -442
  243. package/src/scheduler/schedule-state.ts +0 -211
  244. package/src/scheduler/scheduler.ts +0 -570
  245. package/src/scheduler/types.ts +0 -216
  246. package/src/state/__tests__/directory.test.ts +0 -595
  247. package/src/state/__tests__/fleet-state.test.ts +0 -868
  248. package/src/state/__tests__/job-metadata-schema.test.ts +0 -414
  249. package/src/state/__tests__/job-metadata.test.ts +0 -831
  250. package/src/state/__tests__/job-output.test.ts +0 -856
  251. package/src/state/__tests__/session-schema.test.ts +0 -378
  252. package/src/state/__tests__/session.test.ts +0 -604
  253. package/src/state/directory.ts +0 -217
  254. package/src/state/errors.ts +0 -97
  255. package/src/state/fleet-state.ts +0 -284
  256. package/src/state/index.ts +0 -79
  257. package/src/state/job-metadata.ts +0 -445
  258. package/src/state/job-output.ts +0 -316
  259. package/src/state/schemas/__tests__/job-output.test.ts +0 -338
  260. package/src/state/schemas/fleet-state.ts +0 -120
  261. package/src/state/schemas/index.ts +0 -67
  262. package/src/state/schemas/job-metadata.ts +0 -181
  263. package/src/state/schemas/job-output.ts +0 -177
  264. package/src/state/schemas/session-info.ts +0 -92
  265. package/src/state/session.ts +0 -253
  266. package/src/state/types.ts +0 -59
  267. package/src/state/utils/__tests__/atomic.test.ts +0 -723
  268. package/src/state/utils/__tests__/reads.test.ts +0 -1071
  269. package/src/state/utils/atomic.ts +0 -221
  270. package/src/state/utils/index.ts +0 -6
  271. package/src/state/utils/reads.ts +0 -512
  272. package/src/work-sources/__tests__/github.test.ts +0 -1800
  273. package/src/work-sources/__tests__/manager.test.ts +0 -529
  274. package/src/work-sources/__tests__/registry.test.ts +0 -477
  275. package/src/work-sources/__tests__/types.test.ts +0 -479
  276. package/src/work-sources/adapters/github.ts +0 -1166
  277. package/src/work-sources/adapters/index.ts +0 -64
  278. package/src/work-sources/errors.ts +0 -71
  279. package/src/work-sources/index.ts +0 -148
  280. package/src/work-sources/manager.ts +0 -413
  281. package/src/work-sources/registry.ts +0 -178
  282. package/src/work-sources/types.ts +0 -161
  283. package/tsconfig.json +0 -9
  284. package/vitest.config.ts +0 -19
@@ -1,626 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import {
3
- toSDKOptions,
4
- transformMcpServers,
5
- transformMcpServer,
6
- buildSystemPrompt,
7
- } from "../sdk-adapter.js";
8
- import type { ResolvedAgent, McpServer } from "../../config/index.js";
9
-
10
- // =============================================================================
11
- // Helper to create a minimal ResolvedAgent
12
- // =============================================================================
13
-
14
- function createTestAgent(overrides: Partial<ResolvedAgent> = {}): ResolvedAgent {
15
- return {
16
- name: "test-agent",
17
- configPath: "/path/to/agent.yaml",
18
- ...overrides,
19
- };
20
- }
21
-
22
- // =============================================================================
23
- // toSDKOptions tests
24
- // =============================================================================
25
-
26
- describe("toSDKOptions", () => {
27
- describe("permission mode mapping", () => {
28
- it("maps permission mode correctly when set in permissions.mode", () => {
29
- const agent = createTestAgent({
30
- permissions: { mode: "bypassPermissions" },
31
- });
32
- const result = toSDKOptions(agent);
33
- expect(result.permissionMode).toBe("bypassPermissions");
34
- });
35
-
36
- it("maps permission mode from permission_mode field", () => {
37
- const agent = createTestAgent({
38
- permission_mode: "plan",
39
- });
40
- const result = toSDKOptions(agent);
41
- expect(result.permissionMode).toBe("plan");
42
- });
43
-
44
- it("prefers permissions.mode over permission_mode", () => {
45
- const agent = createTestAgent({
46
- permissions: { mode: "bypassPermissions" },
47
- permission_mode: "plan",
48
- });
49
- const result = toSDKOptions(agent);
50
- expect(result.permissionMode).toBe("bypassPermissions");
51
- });
52
-
53
- it("defaults to acceptEdits when mode not specified", () => {
54
- const agent = createTestAgent();
55
- const result = toSDKOptions(agent);
56
- expect(result.permissionMode).toBe("acceptEdits");
57
- });
58
-
59
- it("supports default mode", () => {
60
- const agent = createTestAgent({
61
- permissions: { mode: "default" },
62
- });
63
- const result = toSDKOptions(agent);
64
- expect(result.permissionMode).toBe("default");
65
- });
66
-
67
- it("supports acceptEdits mode", () => {
68
- const agent = createTestAgent({
69
- permissions: { mode: "acceptEdits" },
70
- });
71
- const result = toSDKOptions(agent);
72
- expect(result.permissionMode).toBe("acceptEdits");
73
- });
74
-
75
- it("supports bypassPermissions mode", () => {
76
- const agent = createTestAgent({
77
- permissions: { mode: "bypassPermissions" },
78
- });
79
- const result = toSDKOptions(agent);
80
- expect(result.permissionMode).toBe("bypassPermissions");
81
- });
82
-
83
- it("supports plan mode", () => {
84
- const agent = createTestAgent({
85
- permissions: { mode: "plan" },
86
- });
87
- const result = toSDKOptions(agent);
88
- expect(result.permissionMode).toBe("plan");
89
- });
90
- });
91
-
92
- describe("allowed and denied tools", () => {
93
- it("passes allowed_tools as allowedTools", () => {
94
- const agent = createTestAgent({
95
- permissions: {
96
- mode: "acceptEdits",
97
- allowed_tools: ["Read", "Write", "Edit"],
98
- },
99
- });
100
- const result = toSDKOptions(agent);
101
- expect(result.allowedTools).toEqual(["Read", "Write", "Edit"]);
102
- });
103
-
104
- it("passes denied_tools as deniedTools", () => {
105
- const agent = createTestAgent({
106
- permissions: {
107
- mode: "acceptEdits",
108
- denied_tools: ["Bash", "WebFetch"],
109
- },
110
- });
111
- const result = toSDKOptions(agent);
112
- expect(result.deniedTools).toEqual(["Bash", "WebFetch"]);
113
- });
114
-
115
- it("does not include allowedTools when empty array", () => {
116
- const agent = createTestAgent({
117
- permissions: {
118
- mode: "acceptEdits",
119
- allowed_tools: [],
120
- },
121
- });
122
- const result = toSDKOptions(agent);
123
- expect(result.allowedTools).toBeUndefined();
124
- });
125
-
126
- it("does not include deniedTools when empty array", () => {
127
- const agent = createTestAgent({
128
- permissions: {
129
- mode: "acceptEdits",
130
- denied_tools: [],
131
- },
132
- });
133
- const result = toSDKOptions(agent);
134
- expect(result.deniedTools).toBeUndefined();
135
- });
136
-
137
- it("does not include allowedTools when not specified", () => {
138
- const agent = createTestAgent({
139
- permissions: { mode: "acceptEdits" },
140
- });
141
- const result = toSDKOptions(agent);
142
- expect(result.allowedTools).toBeUndefined();
143
- });
144
-
145
- it("supports MCP tool wildcards", () => {
146
- const agent = createTestAgent({
147
- permissions: {
148
- mode: "acceptEdits",
149
- allowed_tools: ["Read", "mcp__posthog__*", "mcp__github__*"],
150
- },
151
- });
152
- const result = toSDKOptions(agent);
153
- expect(result.allowedTools).toContain("mcp__posthog__*");
154
- expect(result.allowedTools).toContain("mcp__github__*");
155
- });
156
- });
157
-
158
- describe("system prompt", () => {
159
- it("uses claude_code preset for system prompt by default", () => {
160
- const agent = createTestAgent();
161
- const result = toSDKOptions(agent);
162
- expect(result.systemPrompt).toEqual({
163
- type: "preset",
164
- preset: "claude_code",
165
- });
166
- });
167
-
168
- it("uses custom system prompt when specified in agent config", () => {
169
- const agent = createTestAgent({
170
- system_prompt: "You are a helpful assistant specialized in testing.",
171
- });
172
- const result = toSDKOptions(agent);
173
- expect(result.systemPrompt).toEqual({
174
- type: "custom",
175
- content: "You are a helpful assistant specialized in testing.",
176
- });
177
- });
178
-
179
- it("handles empty system prompt by using preset", () => {
180
- const agent = createTestAgent({
181
- system_prompt: "",
182
- });
183
- const result = toSDKOptions(agent);
184
- // Empty string is falsy, so it should fall back to preset
185
- expect(result.systemPrompt).toEqual({
186
- type: "preset",
187
- preset: "claude_code",
188
- });
189
- });
190
- });
191
-
192
- describe("setting sources", () => {
193
- it("sets settingSources to project and local", () => {
194
- const agent = createTestAgent();
195
- const result = toSDKOptions(agent);
196
- expect(result.settingSources).toEqual(["project", "local"]);
197
- });
198
- });
199
-
200
- describe("session resume and fork", () => {
201
- it("passes resume option when provided", () => {
202
- const agent = createTestAgent();
203
- const result = toSDKOptions(agent, { resume: "session-abc123" });
204
- expect(result.resume).toBe("session-abc123");
205
- });
206
-
207
- it("sets forkSession true when fork option provided", () => {
208
- const agent = createTestAgent();
209
- const result = toSDKOptions(agent, { fork: true });
210
- expect(result.forkSession).toBe(true);
211
- });
212
-
213
- it("does not include resume when not provided", () => {
214
- const agent = createTestAgent();
215
- const result = toSDKOptions(agent);
216
- expect(result.resume).toBeUndefined();
217
- });
218
-
219
- it("does not include forkSession when not forking", () => {
220
- const agent = createTestAgent();
221
- const result = toSDKOptions(agent, { fork: false });
222
- expect(result.forkSession).toBeUndefined();
223
- });
224
-
225
- it("supports both resume and fork together", () => {
226
- const agent = createTestAgent();
227
- const result = toSDKOptions(agent, { resume: "session-abc123", fork: true });
228
- expect(result.resume).toBe("session-abc123");
229
- expect(result.forkSession).toBe(true);
230
- });
231
- });
232
-
233
- describe("MCP servers", () => {
234
- it("includes mcpServers when agent has MCP servers configured", () => {
235
- const agent = createTestAgent({
236
- mcp_servers: {
237
- github: {
238
- command: "npx",
239
- args: ["-y", "@modelcontextprotocol/server-github"],
240
- },
241
- },
242
- });
243
- const result = toSDKOptions(agent);
244
- expect(result.mcpServers).toBeDefined();
245
- expect(result.mcpServers?.github).toBeDefined();
246
- });
247
-
248
- it("includes empty mcpServers object when not configured", () => {
249
- const agent = createTestAgent();
250
- const result = toSDKOptions(agent);
251
- expect(result.mcpServers).toEqual({});
252
- });
253
-
254
- it("includes empty mcpServers object for empty mcp_servers object", () => {
255
- const agent = createTestAgent({
256
- mcp_servers: {},
257
- });
258
- const result = toSDKOptions(agent);
259
- expect(result.mcpServers).toEqual({});
260
- });
261
- });
262
-
263
- describe("complete configuration", () => {
264
- it("produces correct SDK options for a fully configured agent", () => {
265
- const agent = createTestAgent({
266
- name: "full-agent",
267
- system_prompt: "You are a specialized test agent.",
268
- permissions: {
269
- mode: "bypassPermissions",
270
- allowed_tools: ["Read", "Write", "Bash"],
271
- denied_tools: ["WebFetch"],
272
- },
273
- mcp_servers: {
274
- posthog: {
275
- url: "https://mcp.posthog.com",
276
- },
277
- filesystem: {
278
- command: "npx",
279
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
280
- env: { SAFE_MODE: "true" },
281
- },
282
- },
283
- });
284
-
285
- const result = toSDKOptions(agent, { resume: "session-123" });
286
-
287
- expect(result).toEqual({
288
- permissionMode: "bypassPermissions",
289
- allowedTools: ["Read", "Write", "Bash"],
290
- deniedTools: ["WebFetch"],
291
- systemPrompt: {
292
- type: "custom",
293
- content: "You are a specialized test agent.",
294
- },
295
- settingSources: ["project", "local"],
296
- mcpServers: {
297
- posthog: {
298
- type: "http",
299
- url: "https://mcp.posthog.com",
300
- },
301
- filesystem: {
302
- command: "npx",
303
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
304
- env: { SAFE_MODE: "true" },
305
- },
306
- },
307
- resume: "session-123",
308
- });
309
- });
310
- });
311
- });
312
-
313
- // =============================================================================
314
- // transformMcpServer tests
315
- // =============================================================================
316
-
317
- describe("transformMcpServer", () => {
318
- it("transforms HTTP MCP server config", () => {
319
- const server: McpServer = {
320
- url: "https://mcp.example.com",
321
- };
322
- const result = transformMcpServer(server);
323
- expect(result).toEqual({
324
- type: "http",
325
- url: "https://mcp.example.com",
326
- });
327
- });
328
-
329
- it("transforms process MCP server config", () => {
330
- const server: McpServer = {
331
- command: "npx",
332
- args: ["-y", "@modelcontextprotocol/server-github"],
333
- };
334
- const result = transformMcpServer(server);
335
- expect(result).toEqual({
336
- command: "npx",
337
- args: ["-y", "@modelcontextprotocol/server-github"],
338
- });
339
- });
340
-
341
- it("transforms MCP server with env vars", () => {
342
- const server: McpServer = {
343
- command: "node",
344
- args: ["server.js"],
345
- env: {
346
- API_KEY: "secret123",
347
- DEBUG: "true",
348
- },
349
- };
350
- const result = transformMcpServer(server);
351
- expect(result).toEqual({
352
- command: "node",
353
- args: ["server.js"],
354
- env: {
355
- API_KEY: "secret123",
356
- DEBUG: "true",
357
- },
358
- });
359
- });
360
-
361
- it("handles mixed HTTP and process config (HTTP takes precedence)", () => {
362
- const server: McpServer = {
363
- url: "https://mcp.example.com",
364
- command: "npx",
365
- args: ["something"],
366
- };
367
- const result = transformMcpServer(server);
368
- // Both URL and command are included
369
- expect(result.type).toBe("http");
370
- expect(result.url).toBe("https://mcp.example.com");
371
- expect(result.command).toBe("npx");
372
- });
373
-
374
- it("does not include empty env object", () => {
375
- const server: McpServer = {
376
- command: "node",
377
- env: {},
378
- };
379
- const result = transformMcpServer(server);
380
- expect(result.env).toBeUndefined();
381
- });
382
-
383
- it("does not include empty args array", () => {
384
- const server: McpServer = {
385
- command: "node",
386
- args: [],
387
- };
388
- const result = transformMcpServer(server);
389
- expect(result.args).toBeUndefined();
390
- });
391
-
392
- it("handles server with only command", () => {
393
- const server: McpServer = {
394
- command: "my-mcp-server",
395
- };
396
- const result = transformMcpServer(server);
397
- expect(result).toEqual({
398
- command: "my-mcp-server",
399
- });
400
- });
401
- });
402
-
403
- // =============================================================================
404
- // transformMcpServers tests
405
- // =============================================================================
406
-
407
- describe("transformMcpServers", () => {
408
- it("transforms multiple MCP server configs", () => {
409
- const servers: Record<string, McpServer> = {
410
- github: {
411
- command: "npx",
412
- args: ["-y", "@modelcontextprotocol/server-github"],
413
- env: { GITHUB_TOKEN: "token123" },
414
- },
415
- posthog: {
416
- url: "https://mcp.posthog.com",
417
- },
418
- };
419
- const result = transformMcpServers(servers);
420
-
421
- expect(result).toBeDefined();
422
- expect(result?.github).toEqual({
423
- command: "npx",
424
- args: ["-y", "@modelcontextprotocol/server-github"],
425
- env: { GITHUB_TOKEN: "token123" },
426
- });
427
- expect(result?.posthog).toEqual({
428
- type: "http",
429
- url: "https://mcp.posthog.com",
430
- });
431
- });
432
-
433
- it("returns empty object for empty config", () => {
434
- const result = transformMcpServers({});
435
- expect(result).toEqual({});
436
- });
437
-
438
- it("returns empty object for undefined config", () => {
439
- const result = transformMcpServers(undefined);
440
- expect(result).toEqual({});
441
- });
442
-
443
- it("handles single server", () => {
444
- const servers: Record<string, McpServer> = {
445
- solo: { command: "mcp-server" },
446
- };
447
- const result = transformMcpServers(servers);
448
- expect(result).toEqual({
449
- solo: { command: "mcp-server" },
450
- });
451
- });
452
-
453
- it("handles mixed HTTP and process servers", () => {
454
- const servers: Record<string, McpServer> = {
455
- http1: { url: "https://a.com" },
456
- process1: { command: "cmd1" },
457
- http2: { url: "https://b.com" },
458
- process2: { command: "cmd2", args: ["-v"] },
459
- };
460
- const result = transformMcpServers(servers);
461
-
462
- expect(result?.http1?.type).toBe("http");
463
- expect(result?.http1?.url).toBe("https://a.com");
464
- expect(result?.process1?.command).toBe("cmd1");
465
- expect(result?.http2?.type).toBe("http");
466
- expect(result?.process2?.command).toBe("cmd2");
467
- });
468
- });
469
-
470
- // =============================================================================
471
- // buildSystemPrompt tests
472
- // =============================================================================
473
-
474
- // =============================================================================
475
- // MCP Server Environment Variable Interpolation tests
476
- // =============================================================================
477
-
478
- describe("MCP server environment variable interpolation", () => {
479
- it("accepts pre-interpolated env vars in MCP server config", () => {
480
- // This test verifies that interpolation happens BEFORE toSDKOptions is called
481
- // (in loader.ts via interpolateConfig), so the SDK adapter receives
482
- // already-resolved values
483
- const agent = createTestAgent({
484
- mcp_servers: {
485
- github: {
486
- command: "npx",
487
- args: ["-y", "@modelcontextprotocol/server-github"],
488
- env: {
489
- GITHUB_TOKEN: "ghp_already_interpolated_token",
490
- },
491
- },
492
- },
493
- });
494
- const result = toSDKOptions(agent);
495
- expect(result.mcpServers?.github.env?.GITHUB_TOKEN).toBe(
496
- "ghp_already_interpolated_token"
497
- );
498
- });
499
-
500
- it("passes URL with pre-interpolated env vars for HTTP MCP server", () => {
501
- // Environment variables in URLs should be interpolated before SDK transformation
502
- const agent = createTestAgent({
503
- mcp_servers: {
504
- analytics: {
505
- url: "https://mcp.example.com/api?key=resolved_api_key",
506
- },
507
- },
508
- });
509
- const result = toSDKOptions(agent);
510
- expect(result.mcpServers?.analytics.url).toBe(
511
- "https://mcp.example.com/api?key=resolved_api_key"
512
- );
513
- });
514
-
515
- it("passes multiple env vars in process-based MCP server", () => {
516
- const agent = createTestAgent({
517
- mcp_servers: {
518
- custom: {
519
- command: "my-mcp-server",
520
- args: ["--verbose"],
521
- env: {
522
- API_KEY: "key123",
523
- API_SECRET: "secret456",
524
- DEBUG: "true",
525
- },
526
- },
527
- },
528
- });
529
- const result = toSDKOptions(agent);
530
- expect(result.mcpServers?.custom.env).toEqual({
531
- API_KEY: "key123",
532
- API_SECRET: "secret456",
533
- DEBUG: "true",
534
- });
535
- });
536
-
537
- it("handles mixed MCP servers with different interpolated values", () => {
538
- const agent = createTestAgent({
539
- mcp_servers: {
540
- github: {
541
- command: "npx",
542
- args: ["-y", "@modelcontextprotocol/server-github"],
543
- env: { GITHUB_TOKEN: "ghp_token123" },
544
- },
545
- posthog: {
546
- url: "https://mcp.posthog.com",
547
- },
548
- filesystem: {
549
- command: "npx",
550
- args: ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"],
551
- env: { ALLOWED_PATHS: "/workspace,/home/user" },
552
- },
553
- },
554
- });
555
- const result = toSDKOptions(agent);
556
-
557
- expect(result.mcpServers?.github.env?.GITHUB_TOKEN).toBe("ghp_token123");
558
- expect(result.mcpServers?.posthog.type).toBe("http");
559
- expect(result.mcpServers?.posthog.url).toBe("https://mcp.posthog.com");
560
- expect(result.mcpServers?.filesystem.env?.ALLOWED_PATHS).toBe(
561
- "/workspace,/home/user"
562
- );
563
- });
564
- });
565
-
566
- // =============================================================================
567
- // buildSystemPrompt tests
568
- // =============================================================================
569
-
570
- describe("buildSystemPrompt", () => {
571
- it("returns preset when no system_prompt specified", () => {
572
- const agent = createTestAgent();
573
- const result = buildSystemPrompt(agent);
574
- expect(result).toEqual({
575
- type: "preset",
576
- preset: "claude_code",
577
- });
578
- });
579
-
580
- it("returns custom when system_prompt is specified", () => {
581
- const agent = createTestAgent({
582
- system_prompt: "Custom instructions for the agent.",
583
- });
584
- const result = buildSystemPrompt(agent);
585
- expect(result).toEqual({
586
- type: "custom",
587
- content: "Custom instructions for the agent.",
588
- });
589
- });
590
-
591
- it("returns preset for empty string system_prompt", () => {
592
- const agent = createTestAgent({
593
- system_prompt: "",
594
- });
595
- const result = buildSystemPrompt(agent);
596
- expect(result).toEqual({
597
- type: "preset",
598
- preset: "claude_code",
599
- });
600
- });
601
-
602
- it("preserves multiline system prompts", () => {
603
- const multilinePrompt = `You are a helpful assistant.
604
- You specialize in code review.
605
- Always be thorough and constructive.`;
606
- const agent = createTestAgent({
607
- system_prompt: multilinePrompt,
608
- });
609
- const result = buildSystemPrompt(agent);
610
- expect(result).toEqual({
611
- type: "custom",
612
- content: multilinePrompt,
613
- });
614
- });
615
-
616
- it("handles system prompt with special characters", () => {
617
- const agent = createTestAgent({
618
- system_prompt: "Handle ${VARIABLES} and 'quotes' correctly",
619
- });
620
- const result = buildSystemPrompt(agent);
621
- expect(result).toEqual({
622
- type: "custom",
623
- content: "Handle ${VARIABLES} and 'quotes' correctly",
624
- });
625
- });
626
- });