@edspencer/paddock 0.0.1 → 0.57.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 (296) hide show
  1. package/README.md +69 -0
  2. package/install-notice.mjs +29 -0
  3. package/package.json +58 -5
  4. package/packages/server/dist/adoptable.d.ts +127 -0
  5. package/packages/server/dist/adoptable.js +315 -0
  6. package/packages/server/dist/app.d.ts +67 -0
  7. package/packages/server/dist/app.js +325 -0
  8. package/packages/server/dist/archive.d.ts +42 -0
  9. package/packages/server/dist/archive.js +125 -0
  10. package/packages/server/dist/attachments-config.d.ts +114 -0
  11. package/packages/server/dist/attachments-config.js +165 -0
  12. package/packages/server/dist/attachments-hint.d.ts +53 -0
  13. package/packages/server/dist/attachments-hint.js +140 -0
  14. package/packages/server/dist/attachments.d.ts +33 -0
  15. package/packages/server/dist/attachments.js +117 -0
  16. package/packages/server/dist/auth.d.ts +84 -0
  17. package/packages/server/dist/auth.js +247 -0
  18. package/packages/server/dist/background.d.ts +36 -0
  19. package/packages/server/dist/background.js +137 -0
  20. package/packages/server/dist/bind-safety.d.ts +56 -0
  21. package/packages/server/dist/bind-safety.js +51 -0
  22. package/packages/server/dist/brand.d.ts +44 -0
  23. package/packages/server/dist/brand.js +88 -0
  24. package/packages/server/dist/chat-dto.d.ts +210 -0
  25. package/packages/server/dist/chat-dto.js +308 -0
  26. package/packages/server/dist/cli/import-chats.d.ts +21 -0
  27. package/packages/server/dist/cli/import-chats.js +197 -0
  28. package/packages/server/dist/cli/paddock.d.ts +2 -0
  29. package/packages/server/dist/cli/paddock.js +247 -0
  30. package/packages/server/dist/concurrency.d.ts +57 -0
  31. package/packages/server/dist/concurrency.js +71 -0
  32. package/packages/server/dist/config.d.ts +538 -0
  33. package/packages/server/dist/config.js +625 -0
  34. package/packages/server/dist/curation-config.d.ts +55 -0
  35. package/packages/server/dist/curation-config.js +64 -0
  36. package/packages/server/dist/environment-prompt.d.ts +52 -0
  37. package/packages/server/dist/environment-prompt.js +61 -0
  38. package/packages/server/dist/event-bus.d.ts +87 -0
  39. package/packages/server/dist/event-bus.js +48 -0
  40. package/packages/server/dist/git.d.ts +128 -0
  41. package/packages/server/dist/git.js +446 -0
  42. package/packages/server/dist/github-auth.d.ts +44 -0
  43. package/packages/server/dist/github-auth.js +169 -0
  44. package/packages/server/dist/herdctl-agent-config.d.ts +98 -0
  45. package/packages/server/dist/herdctl-agent-config.js +331 -0
  46. package/packages/server/dist/herdctl-agent-names.d.ts +172 -0
  47. package/packages/server/dist/herdctl-agent-names.js +228 -0
  48. package/packages/server/dist/herdctl-jobs-index.d.ts +65 -0
  49. package/packages/server/dist/herdctl-jobs-index.js +225 -0
  50. package/packages/server/dist/herdctl-jobs.d.ts +98 -0
  51. package/packages/server/dist/herdctl-jobs.js +225 -0
  52. package/packages/server/dist/herdctl.d.ts +623 -0
  53. package/packages/server/dist/herdctl.js +1279 -0
  54. package/packages/server/dist/hook-config.d.ts +217 -0
  55. package/packages/server/dist/hook-config.js +224 -0
  56. package/packages/server/dist/http-bytes.d.ts +24 -0
  57. package/packages/server/dist/http-bytes.js +52 -0
  58. package/packages/server/dist/index.d.ts +1 -0
  59. package/packages/server/dist/index.js +14 -0
  60. package/packages/server/dist/instance-config.d.ts +143 -0
  61. package/packages/server/dist/instance-config.js +385 -0
  62. package/packages/server/dist/localcommand.d.ts +23 -0
  63. package/packages/server/dist/localcommand.js +140 -0
  64. package/packages/server/dist/management-auth.d.ts +99 -0
  65. package/packages/server/dist/management-auth.js +165 -0
  66. package/packages/server/dist/management-config.d.ts +164 -0
  67. package/packages/server/dist/management-config.js +286 -0
  68. package/packages/server/dist/management-mcp-server.d.ts +20 -0
  69. package/packages/server/dist/management-mcp-server.js +95 -0
  70. package/packages/server/dist/management-metadata.d.ts +67 -0
  71. package/packages/server/dist/management-metadata.js +56 -0
  72. package/packages/server/dist/management-ops.d.ts +110 -0
  73. package/packages/server/dist/management-ops.js +449 -0
  74. package/packages/server/dist/management-policy.d.ts +172 -0
  75. package/packages/server/dist/management-policy.js +259 -0
  76. package/packages/server/dist/message-provenance.d.ts +112 -0
  77. package/packages/server/dist/message-provenance.js +260 -0
  78. package/packages/server/dist/models.d.ts +164 -0
  79. package/packages/server/dist/models.js +208 -0
  80. package/packages/server/dist/openapi.d.ts +66 -0
  81. package/packages/server/dist/openapi.js +183 -0
  82. package/packages/server/dist/parent-detach.d.ts +30 -0
  83. package/packages/server/dist/parent-detach.js +109 -0
  84. package/packages/server/dist/preload.d.ts +43 -0
  85. package/packages/server/dist/preload.js +55 -0
  86. package/packages/server/dist/project-files.d.ts +76 -0
  87. package/packages/server/dist/project-files.js +191 -0
  88. package/packages/server/dist/project-mime.d.ts +35 -0
  89. package/packages/server/dist/project-mime.js +55 -0
  90. package/packages/server/dist/project-paths.d.ts +88 -0
  91. package/packages/server/dist/project-paths.js +126 -0
  92. package/packages/server/dist/project-types.d.ts +316 -0
  93. package/packages/server/dist/project-types.js +48 -0
  94. package/packages/server/dist/projects.d.ts +202 -0
  95. package/packages/server/dist/projects.js +894 -0
  96. package/packages/server/dist/queued-message.d.ts +35 -0
  97. package/packages/server/dist/queued-message.js +116 -0
  98. package/packages/server/dist/read-state.d.ts +46 -0
  99. package/packages/server/dist/read-state.js +139 -0
  100. package/packages/server/dist/recovery-config.d.ts +111 -0
  101. package/packages/server/dist/recovery-config.js +105 -0
  102. package/packages/server/dist/recovery.d.ts +262 -0
  103. package/packages/server/dist/recovery.js +490 -0
  104. package/packages/server/dist/resume-drain.d.ts +122 -0
  105. package/packages/server/dist/resume-drain.js +158 -0
  106. package/packages/server/dist/route-context.d.ts +168 -0
  107. package/packages/server/dist/route-context.js +39 -0
  108. package/packages/server/dist/route-errors.d.ts +8 -0
  109. package/packages/server/dist/route-errors.js +13 -0
  110. package/packages/server/dist/routes/chats.d.ts +12 -0
  111. package/packages/server/dist/routes/chats.js +1406 -0
  112. package/packages/server/dist/routes/git.d.ts +13 -0
  113. package/packages/server/dist/routes/git.js +236 -0
  114. package/packages/server/dist/routes/mcp.d.ts +83 -0
  115. package/packages/server/dist/routes/mcp.js +250 -0
  116. package/packages/server/dist/routes/meta.d.ts +15 -0
  117. package/packages/server/dist/routes/meta.js +447 -0
  118. package/packages/server/dist/routes/projects.d.ts +25 -0
  119. package/packages/server/dist/routes/projects.js +736 -0
  120. package/packages/server/dist/routes/triggers.d.ts +21 -0
  121. package/packages/server/dist/routes/triggers.js +324 -0
  122. package/packages/server/dist/routes/workspace-mount.d.ts +48 -0
  123. package/packages/server/dist/routes/workspace-mount.js +32 -0
  124. package/packages/server/dist/routes.d.ts +26 -0
  125. package/packages/server/dist/routes.js +29 -0
  126. package/packages/server/dist/run-provenance.d.ts +109 -0
  127. package/packages/server/dist/run-provenance.js +206 -0
  128. package/packages/server/dist/runs.d.ts +92 -0
  129. package/packages/server/dist/runs.js +72 -0
  130. package/packages/server/dist/schedule-config.d.ts +68 -0
  131. package/packages/server/dist/schedule-config.js +75 -0
  132. package/packages/server/dist/schedule-session.d.ts +34 -0
  133. package/packages/server/dist/schedule-session.js +120 -0
  134. package/packages/server/dist/self-mcp-descriptions.d.ts +20 -0
  135. package/packages/server/dist/self-mcp-descriptions.js +145 -0
  136. package/packages/server/dist/self-mcp-read.d.ts +15 -0
  137. package/packages/server/dist/self-mcp-read.js +97 -0
  138. package/packages/server/dist/self-mcp-triggers.d.ts +30 -0
  139. package/packages/server/dist/self-mcp-triggers.js +144 -0
  140. package/packages/server/dist/self-mcp-types.d.ts +248 -0
  141. package/packages/server/dist/self-mcp-types.js +10 -0
  142. package/packages/server/dist/self-mcp-util.d.ts +73 -0
  143. package/packages/server/dist/self-mcp-util.js +157 -0
  144. package/packages/server/dist/self-mcp-write.d.ts +35 -0
  145. package/packages/server/dist/self-mcp-write.js +215 -0
  146. package/packages/server/dist/self-mcp.d.ts +95 -0
  147. package/packages/server/dist/self-mcp.js +448 -0
  148. package/packages/server/dist/send-file-mcp.d.ts +46 -0
  149. package/packages/server/dist/send-file-mcp.js +281 -0
  150. package/packages/server/dist/session-hub.d.ts +186 -0
  151. package/packages/server/dist/session-hub.js +291 -0
  152. package/packages/server/dist/spawn-capability.d.ts +99 -0
  153. package/packages/server/dist/spawn-capability.js +106 -0
  154. package/packages/server/dist/star.d.ts +26 -0
  155. package/packages/server/dist/star.js +94 -0
  156. package/packages/server/dist/start.d.ts +1 -0
  157. package/packages/server/dist/start.js +21 -0
  158. package/packages/server/dist/subagents.d.ts +337 -0
  159. package/packages/server/dist/subagents.js +626 -0
  160. package/packages/server/dist/sweep.d.ts +122 -0
  161. package/packages/server/dist/sweep.js +696 -0
  162. package/packages/server/dist/tooldetails.d.ts +33 -0
  163. package/packages/server/dist/tooldetails.js +466 -0
  164. package/packages/server/dist/transcribe.d.ts +69 -0
  165. package/packages/server/dist/transcribe.js +119 -0
  166. package/packages/server/dist/transcripts.d.ts +42 -0
  167. package/packages/server/dist/transcripts.js +164 -0
  168. package/packages/server/dist/trigger-config.d.ts +278 -0
  169. package/packages/server/dist/trigger-config.js +417 -0
  170. package/packages/server/dist/trigger-runtime.d.ts +94 -0
  171. package/packages/server/dist/trigger-runtime.js +82 -0
  172. package/packages/server/dist/trigger-session.d.ts +34 -0
  173. package/packages/server/dist/trigger-session.js +122 -0
  174. package/packages/server/dist/triggers.d.ts +83 -0
  175. package/packages/server/dist/triggers.js +124 -0
  176. package/packages/server/dist/trusted-proxy.d.ts +57 -0
  177. package/packages/server/dist/trusted-proxy.js +157 -0
  178. package/packages/server/dist/turn-notice.d.ts +154 -0
  179. package/packages/server/dist/turn-notice.js +271 -0
  180. package/packages/server/dist/unread.d.ts +36 -0
  181. package/packages/server/dist/unread.js +123 -0
  182. package/packages/server/dist/usage.d.ts +66 -0
  183. package/packages/server/dist/usage.js +243 -0
  184. package/packages/server/dist/wake-injection.d.ts +156 -0
  185. package/packages/server/dist/wake-injection.js +136 -0
  186. package/packages/server/dist/whisper-local.d.ts +9 -0
  187. package/packages/server/dist/whisper-local.js +122 -0
  188. package/packages/server/dist/ws-context.d.ts +158 -0
  189. package/packages/server/dist/ws-context.js +1 -0
  190. package/packages/server/dist/ws-protocol.d.ts +423 -0
  191. package/packages/server/dist/ws-protocol.js +251 -0
  192. package/packages/server/dist/ws-self-mcp.d.ts +52 -0
  193. package/packages/server/dist/ws-self-mcp.js +28 -0
  194. package/packages/server/dist/ws-triggers.d.ts +29 -0
  195. package/packages/server/dist/ws-triggers.js +261 -0
  196. package/packages/server/dist/ws-turn.d.ts +86 -0
  197. package/packages/server/dist/ws-turn.js +751 -0
  198. package/packages/server/dist/ws.d.ts +62 -0
  199. package/packages/server/dist/ws.js +1024 -0
  200. package/packages/server/package.json +6 -0
  201. package/packages/web/dist/assets/InstanceConfigPage-Bypd_quL.js +2 -0
  202. package/packages/web/dist/assets/MarkdownRenderer-Co8w9iuX.js +30 -0
  203. package/packages/web/dist/assets/ProjectRedirect-DXrA24Cy.js +2 -0
  204. package/packages/web/dist/assets/ProjectView-B9opP7Sv.js +13 -0
  205. package/packages/web/dist/assets/ProjectsGrid-D2cwb2jY.js +2 -0
  206. package/packages/web/dist/assets/arc-B--FIRB8.js +2 -0
  207. package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-B6dRWZZ6.js +37 -0
  208. package/packages/web/dist/assets/bash-I8pq0VWm.js +2 -0
  209. package/packages/web/dist/assets/blockDiagram-GPEHLZMM-DLxFAvvf.js +133 -0
  210. package/packages/web/dist/assets/c-D2F1sQUL.js +2 -0
  211. package/packages/web/dist/assets/c4Diagram-AAUBKEIU-CNee5ks4.js +11 -0
  212. package/packages/web/dist/assets/channel-Bw0A52CB.js +2 -0
  213. package/packages/web/dist/assets/chunk-2J33WTMH-DObw03Xl.js +2 -0
  214. package/packages/web/dist/assets/chunk-4BX2VUAB-CH2SR6nN.js +2 -0
  215. package/packages/web/dist/assets/chunk-55IACEB6-WlVpegT3.js +2 -0
  216. package/packages/web/dist/assets/chunk-727SXJPM-g8GT9Rgd.js +207 -0
  217. package/packages/web/dist/assets/chunk-AQP2D5EJ-DbN4PsDF.js +232 -0
  218. package/packages/web/dist/assets/chunk-FMBD7UC4-DSN3BjFG.js +16 -0
  219. package/packages/web/dist/assets/chunk-ND2GUHAM-D9R4le0z.js +2 -0
  220. package/packages/web/dist/assets/chunk-QZHKN3VN-D4YgRaKH.js +2 -0
  221. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-itf_kt-q.js +2 -0
  222. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-itf_kt-q.js +2 -0
  223. package/packages/web/dist/assets/core-CysJ2gLj.js +4 -0
  224. package/packages/web/dist/assets/cose-bilkent-S5V4N54A-D1PB0KNu.js +2 -0
  225. package/packages/web/dist/assets/cpp-Bm3ii6kY.js +2 -0
  226. package/packages/web/dist/assets/csharp-BNpuYZMG.js +2 -0
  227. package/packages/web/dist/assets/css-DazXZka4.js +2 -0
  228. package/packages/web/dist/assets/cytoscape.esm-CUqq0XTU.js +332 -0
  229. package/packages/web/dist/assets/dagre-BM42HDAG-C6Uuq-dq.js +5 -0
  230. package/packages/web/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  231. package/packages/web/dist/assets/diagram-2AECGRRQ-C9JvQ425.js +44 -0
  232. package/packages/web/dist/assets/diagram-5GNKFQAL-Cu6pdh2d.js +11 -0
  233. package/packages/web/dist/assets/diagram-KO2AKTUF-PmXcUQhY.js +4 -0
  234. package/packages/web/dist/assets/diagram-LMA3HP47-9ww6_9Iq.js +25 -0
  235. package/packages/web/dist/assets/diagram-OG6HWLK6-DWQVjv_n.js +25 -0
  236. package/packages/web/dist/assets/erDiagram-TEJ5UH35-6F7xTuff.js +86 -0
  237. package/packages/web/dist/assets/flowDiagram-I6XJVG4X-SCiGu7m6.js +163 -0
  238. package/packages/web/dist/assets/format-yf7Vf9kR.js +2 -0
  239. package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-BNpPwxkL.js +293 -0
  240. package/packages/web/dist/assets/gitGraphDiagram-PVQCEYII-C0gyAJjW.js +107 -0
  241. package/packages/web/dist/assets/go-BPx_y7j8.js +2 -0
  242. package/packages/web/dist/assets/graph-BlwPajkw.js +2 -0
  243. package/packages/web/dist/assets/index-B-YuzkF6.js +71 -0
  244. package/packages/web/dist/assets/index-CvGiQddO.css +1 -0
  245. package/packages/web/dist/assets/infoDiagram-5YYISTIA-CJ2CFPfy.js +3 -0
  246. package/packages/web/dist/assets/ini-B3BVgEsG.js +2 -0
  247. package/packages/web/dist/assets/init-Gi6I4Gst.js +2 -0
  248. package/packages/web/dist/assets/ishikawaDiagram-YF4QCWOH-Cs0D32Ry.js +71 -0
  249. package/packages/web/dist/assets/java-B5VKqtH2.js +2 -0
  250. package/packages/web/dist/assets/javascript-BKRaQes9.js +2 -0
  251. package/packages/web/dist/assets/journeyDiagram-JHISSGLW-Bc9fuI2i.js +140 -0
  252. package/packages/web/dist/assets/json-DIYVocXf.js +2 -0
  253. package/packages/web/dist/assets/kanban-definition-UN3LZRKU-D_tC7QfC.js +90 -0
  254. package/packages/web/dist/assets/katex-C5jXJg4s.js +258 -0
  255. package/packages/web/dist/assets/kotlin-Cw-eF_bm.js +3 -0
  256. package/packages/web/dist/assets/lastTab-CU1zsF0j.js +2 -0
  257. package/packages/web/dist/assets/layout-Boy8vhSP.js +2 -0
  258. package/packages/web/dist/assets/linear-BzGHkF9K.js +2 -0
  259. package/packages/web/dist/assets/mermaid.core-DlbsYzE-.js +310 -0
  260. package/packages/web/dist/assets/mindmap-definition-RKZ34NQL-Bxeh-ToD.js +97 -0
  261. package/packages/web/dist/assets/ordinal-Cboi1Yqb.js +2 -0
  262. package/packages/web/dist/assets/php-CRdd4dfS.js +3 -0
  263. package/packages/web/dist/assets/pieDiagram-4H26LBE5-CDmilo8S.js +31 -0
  264. package/packages/web/dist/assets/python-kSlZHhJb.js +2 -0
  265. package/packages/web/dist/assets/quadrantDiagram-W4KKPZXB-D14-JyE9.js +8 -0
  266. package/packages/web/dist/assets/queued-LamEU0GH.js +2 -0
  267. package/packages/web/dist/assets/requirementDiagram-4Y6WPE33-CJ1PUGu-.js +85 -0
  268. package/packages/web/dist/assets/ruby-7T4ktxyv.js +2 -0
  269. package/packages/web/dist/assets/rust-HC3MBUhY.js +2 -0
  270. package/packages/web/dist/assets/sankeyDiagram-5OEKKPKP-BkUK73W0.js +41 -0
  271. package/packages/web/dist/assets/scss-DZLA7YXz.js +2 -0
  272. package/packages/web/dist/assets/sequenceDiagram-3UESZ5HK-sbcvsuLp.js +163 -0
  273. package/packages/web/dist/assets/sql-BC88IN-V.js +2 -0
  274. package/packages/web/dist/assets/stateDiagram-AJRCARHV-DV-7BdHK.js +2 -0
  275. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BlkGdXKW.js +2 -0
  276. package/packages/web/dist/assets/swift-Dn8kKO_1.js +2 -0
  277. package/packages/web/dist/assets/timeline-definition-PNZ67QCA-C5su21G_.js +121 -0
  278. package/packages/web/dist/assets/typescript-C2FFdlUC.js +2 -0
  279. package/packages/web/dist/assets/vennDiagram-CIIHVFJN-JNkIJAaQ.js +35 -0
  280. package/packages/web/dist/assets/wardley-L42UT6IY-qcz6t2vR.js +174 -0
  281. package/packages/web/dist/assets/wardleyDiagram-YWT4CUSO-CMrOIZ-c.js +79 -0
  282. package/packages/web/dist/assets/xml-BXBhIUeX.js +2 -0
  283. package/packages/web/dist/assets/xychartDiagram-2RQKCTM6-C9q6Oy9u.js +8 -0
  284. package/packages/web/dist/assets/yaml-drsDnIKT.js +2 -0
  285. package/packages/web/dist/favicon.ico +0 -0
  286. package/packages/web/dist/fonts/inter-latin.woff2 +0 -0
  287. package/packages/web/dist/fonts/jetbrains-mono-latin.woff2 +0 -0
  288. package/packages/web/dist/icons/apple-touch-icon.png +0 -0
  289. package/packages/web/dist/icons/favicon-16.png +0 -0
  290. package/packages/web/dist/icons/favicon-32.png +0 -0
  291. package/packages/web/dist/icons/icon-192.png +0 -0
  292. package/packages/web/dist/icons/icon-512.png +0 -0
  293. package/packages/web/dist/icons/maskable-512.png +0 -0
  294. package/packages/web/dist/index.html +56 -0
  295. package/packages/web/dist/manifest.webmanifest +32 -0
  296. package/packages/web/dist/sw.js +139 -0
@@ -0,0 +1,538 @@
1
+ import { type DriveMode } from "./models.js";
2
+ import { type RecoveryConfig } from "./recovery-config.js";
3
+ import { type CurationConfig } from "./curation-config.js";
4
+ import { type ManagementApiConfig, type ManagementApiConfigFile } from "./management-config.js";
5
+ import { type AttachmentsConfig } from "./attachments-config.js";
6
+ /**
7
+ * User-authentication strategy.
8
+ *
9
+ * - `none` — no auth; every request is anonymous (default, fully open).
10
+ * - `trusted-header` — trust a reverse proxy to have authenticated the user and
11
+ * pass identity in headers. Spoofable unless the proxy is
12
+ * the only path to paddock (network-level trust).
13
+ * - `jwt` — verify a signed JWT (issued by the proxy/IdP) against a
14
+ * remote JWKS. Self-contained / zero-trust: spoof-proof
15
+ * even if a request reaches paddock directly.
16
+ */
17
+ export type AuthMode = "none" | "trusted-header" | "jwt";
18
+ /**
19
+ * Resolved authentication configuration (provider-agnostic).
20
+ *
21
+ * Driven entirely by `PADDOCK_AUTH_*` env vars so paddock is not coupled to any
22
+ * single proxy/IdP (Authentik, oauth2-proxy, Authelia, Cloudflare Access,
23
+ * Keycloak, …). See AUTH.md for the modes and provider examples.
24
+ */
25
+ export interface AuthConfig {
26
+ mode: AuthMode;
27
+ /** trusted-header: header carrying the username (required in that mode). */
28
+ userHeader: string;
29
+ /** trusted-header: optional header carrying the user's email. */
30
+ emailHeader?: string;
31
+ /**
32
+ * trusted-header / jwt: optional header carrying group membership. In
33
+ * trusted-header mode the value is split on comma; in jwt mode this overrides
34
+ * the claim source only when the proxy passes groups as a header (rare).
35
+ */
36
+ groupsHeader?: string;
37
+ /** jwt: header carrying the token. `Authorization` strips a leading `Bearer `. */
38
+ jwtHeader: string;
39
+ /** jwt: JWKS endpoint used to verify the token signature (required in jwt mode). */
40
+ jwksUrl?: string;
41
+ /** jwt: expected `iss` claim (validated when set). */
42
+ jwtIssuer?: string;
43
+ /** jwt: expected `aud` claim (validated when set). */
44
+ jwtAudience?: string;
45
+ /** jwt: claim to read the username from (falls back preferred_username→email→sub). */
46
+ usernameClaim?: string;
47
+ /** jwt: claim to read groups from (default `groups`). */
48
+ groupsClaim: string;
49
+ }
50
+ /**
51
+ * Per-instance branding (issue #34). Lets several Paddock instances (Projects,
52
+ * Homelab, House, …) be told apart at a glance. All optional; the defaults
53
+ * preserve today's look (🐎 / "Paddock" / terracotta). Injected into index.html
54
+ * at serve time (so there's no title/color flash) and read by the SPA from a
55
+ * `window.__PADDOCK_CONFIG__` global.
56
+ */
57
+ export interface BrandConfig {
58
+ /** Wordmark shown top-left and as the browser tab title. */
59
+ name: string;
60
+ /** Logo: an emoji/glyph, OR a URL/absolute path to an image (rendered as <img>). */
61
+ logo: string;
62
+ /** Accent color as a hex string driving the primary buttons + logo chip. */
63
+ accent: string;
64
+ }
65
+ /** OpenAPI / Swagger-UI reference surface config (see PaddockConfig.openapi). */
66
+ export interface OpenApiConfig {
67
+ /** Mount the `/open-api` UI + `/open-api.json` spec. Opt-in — defaults false. */
68
+ enabled: boolean;
69
+ /** Route prefix the UI is served under (raw spec at `<path>.json`). */
70
+ path: string;
71
+ }
72
+ export interface PaddockConfig {
73
+ /** HTTP/WS port. */
74
+ port: number;
75
+ /** Bind host. Defaults to loopback (`127.0.0.1`) — safe by default (#435). */
76
+ host: string;
77
+ /**
78
+ * Dangerously opt in to an OPEN, unauthenticated server: allow a non-loopback
79
+ * bind while `auth.mode === "none"` (which the bind-safety guard otherwise
80
+ * refuses). Driven by `PADDOCK_DANGEROUSLY_ALLOW_OPEN`; accepts 1/true/yes.
81
+ */
82
+ dangerouslyAllowOpen: boolean;
83
+ /** Absolute (canonical) path to the data root. Holds state files (e.g. sweep). */
84
+ dataDir: string;
85
+ /** Absolute path to the root that contains per-project directories. */
86
+ projectsRoot: string;
87
+ /** Absolute path to the herdctl state directory (.herdctl). */
88
+ stateDir: string;
89
+ /**
90
+ * Absolute path to the generated herdctl.yaml that the FleetManager loads.
91
+ * Paddock owns/regenerates this file (one keeper agent per project).
92
+ */
93
+ herdctlConfigPath: string;
94
+ /** Absolute path to the built web SPA (served in production). */
95
+ webDist: string;
96
+ /**
97
+ * Absolute path to the Claude home (`~/.claude`, unless `CLAUDE_HOME` says
98
+ * otherwise) — the directory whose `projects/<encoded-cwd>/` folders hold
99
+ * Claude Code's session transcripts.
100
+ *
101
+ * Resolved ONCE here (#588) rather than re-read from `process.env` at each call
102
+ * site, because it must be the SAME value everywhere: paddock's transcript
103
+ * relocation (`ensureProjectChats`) symlinks `<claudeHome>/projects/<encoded>`
104
+ * at the project's `.chats/`, and the engine's session discovery / adoption
105
+ * resolves transcripts under `FleetManagerOptions.claudeHomePath`. If paddock
106
+ * honoured `CLAUDE_HOME` while the engine fell back to `os.homedir()/.claude`,
107
+ * detection would scan one home while reads came from another — chats LIST but
108
+ * open EMPTY (herdctl#423 / #588 gotcha 1). The divergence is invisible
109
+ * whenever `CLAUDE_HOME` equals `$HOME/.claude`, which is exactly why it is
110
+ * threaded explicitly instead of being left to a shared default.
111
+ */
112
+ claudeHome: string;
113
+ /** Provider-agnostic user-authentication config (see AUTH.md). */
114
+ auth: AuthConfig;
115
+ /** Voice-dictation (Whisper) capability (per-instance; default off). */
116
+ transcription: TranscriptionConfig;
117
+ /** Per-instance branding (title/logo/accent; defaults preserve today's look). */
118
+ brand: BrandConfig;
119
+ /**
120
+ * OpenAPI / Swagger-UI reference (the `/open-api` docs + `/open-api.json`
121
+ * spec, derived from the route schemas). `enabled` mounts or omits the whole
122
+ * surface. Driven by `PADDOCK_OPENAPI_ENABLED` (1/true/yes/on enable);
123
+ * default OFF (opt-in) — publishing the API surface map is a deliberate
124
+ * choice. Gated by the instance auth mode like any other route when enabled.
125
+ */
126
+ openapi: OpenApiConfig;
127
+ /**
128
+ * Global default for how keeper chat turns are driven (Paddock#111), used when
129
+ * a project doesn't override `driveMode`. `session` by default (#316) — the
130
+ * persistent `openChatSession` path, so cross-turn autonomy (ScheduleWakeup /
131
+ * `/loop`) and SDK streaming work out of the box; set
132
+ * `PADDOCK_DRIVE_MODE=batch` for the legacy one-shot `trigger()` path.
133
+ */
134
+ driveMode: DriveMode;
135
+ /**
136
+ * The instance ALLOW-LIST of offered models (issue #457 Step 2), by catalog id
137
+ * — which of the built-in {@link import("./models.js").MODELS} catalog the model
138
+ * picker + per-project default offer. `undefined` (the default, when neither
139
+ * `PADDOCK_MODELS` nor a YAML `models:` list is set) means "offer every catalog
140
+ * model" — fully backward-compatible. When set it is a validated, de-duped subset
141
+ * (unknown ids dropped; an empty result collapses back to the full catalog, so an
142
+ * instance never offers zero models). The catalog itself stays the source of each
143
+ * model's metadata and of {@link import("./models.js").isKnownModel}; this only
144
+ * narrows what's OFFERED. Resolved to concrete {@link ModelInfo} via
145
+ * {@link import("./models.js").resolveModels}. A per-project `models` override can
146
+ * narrow it further (never widen beyond this list).
147
+ */
148
+ models?: string[];
149
+ /**
150
+ * Whether keeper agents use the native Claude Code system prompt +
151
+ * project CLAUDE.md hierarchy (true, the default) instead of a terse Paddock
152
+ * "replace" system prompt (false). Driven by `PADDOCK_NATIVE_PROMPT`.
153
+ *
154
+ * This is its own decision (issue #176) governing only which system prompt an
155
+ * agent gets. When native (the default on every instance) Paddock sets NO
156
+ * `system_prompt`, so 100% of an agent's standing instructions come from
157
+ * Claude Code's own `CLAUDE.md` walk-up from its cwd — which is what makes the
158
+ * cwd load-bearing. Set `PADDOCK_NATIVE_PROMPT=false` to fall back to
159
+ * the terse replace prompt (e.g. an instance with no CLAUDE.md files).
160
+ *
161
+ * **The canonical instance-wide `CLAUDE.md` is `<projectsRoot>/CLAUDE.md`**
162
+ * (issue #512). `projectsRoot` IS the instance's backing repo, so that file is
163
+ * version-controlled and pushed with everything else, whereas a
164
+ * `<dataDir>/CLAUDE.md` would sit outside the repo. It reaches every project
165
+ * keeper by walk-up (a project dir is a child of `projectsRoot`) and the ROOT
166
+ * keeper too — the root workspace's cwd IS `projectsRoot`. There is no longer
167
+ * any agent whose cwd sits outside that tree, so every keeper picks the
168
+ * instance CLAUDE.md up by walk-up. That closes #512.
169
+ */
170
+ nativeSystemPrompt: boolean;
171
+ /**
172
+ * The **environment** prompt appended to every keeper turn's system prompt
173
+ * (issue #635) — the short note telling the agent it renders into a browser as
174
+ * GFM, not a terminal. Resolved from `PADDOCK_ENVIRONMENT_PROMPT` over the
175
+ * `environmentPrompt:` file key over
176
+ * {@link import("./environment-prompt.js").DEFAULT_ENVIRONMENT_PROMPT}.
177
+ *
178
+ * This is the RESOLVED, effective text, so it has only two meaningful states
179
+ * at the point of use: non-empty (append it) and `""` (append nothing — the
180
+ * instance opted out). The three *authoring* states — unset, a string, an
181
+ * empty string — collapse here, which is deliberate: every consumer just asks
182
+ * "is there anything to append?" and the Settings screen shows the text that
183
+ * is actually in force rather than a tri-state it would have to explain.
184
+ *
185
+ * Orthogonal to {@link nativeSystemPrompt}: that switch chooses the agent's
186
+ * *role* prompt (native preset vs Paddock's terse replace text); this states
187
+ * environmental fact about the deployment and applies on top of either.
188
+ */
189
+ environmentPrompt: string;
190
+ /**
191
+ * Whether keeper turns are handed the read-only self-management MCP server
192
+ * (issue #214 Phase 1) — the `mcp__paddock_manage__*` tools that let a keeper
193
+ * enumerate projects/chats and read another chat's transcript. Driven by
194
+ * `PADDOCK_SELF_MCP`; default OFF (opt-in per instance). The write tools
195
+ * (create/fork/message) are gated separately by
196
+ * {@link selfMcpWriteEnabled}.
197
+ */
198
+ selfMcpEnabled: boolean;
199
+ /**
200
+ * Whether keepers additionally get the self-management MCP **write** tools
201
+ * (issue #214 Phase 2) — `create_chat`, `fork_chat`, `send_message`,
202
+ * `fork_chat_batch` (fan-out). Driven by `PADDOCK_SELF_MCP_WRITE`; default OFF
203
+ * and only honored when {@link selfMcpEnabled} is also on (write implies read).
204
+ * Gated behind its own flag because these START real keeper turns — an instance
205
+ * can offer read-only introspection without the write blast radius.
206
+ */
207
+ selfMcpWriteEnabled: boolean;
208
+ /**
209
+ * Whether keepers additionally get the self-management MCP **project** tools
210
+ * (issue #467) — `create_project`, which provisions a whole new project
211
+ * (directory + `project.yaml`, optionally a cloned repo-backed checkout) and
212
+ * registers its keeper agent. Driven by `PADDOCK_SELF_MCP_PROJECTS`; default OFF
213
+ * and only honored when {@link selfMcpWriteEnabled} is also on (the tool lives in
214
+ * the write block).
215
+ *
216
+ * Gated behind its OWN flag rather than folded into `selfMcpWriteEnabled` because
217
+ * every other write tool acts WITHIN an existing project, whereas this one mutates
218
+ * instance-level state (a new dir in the projects root, new long-lived agents) and
219
+ * runs `git clone` on a CALLER-SUPPLIED url. It is an operator-intent boundary, not
220
+ * a hard security one (a keeper with Bash in a write-enabled project can already
221
+ * clone what it likes) — but provisioning infrastructure should be opt-in.
222
+ */
223
+ selfMcpProjectsEnabled: boolean;
224
+ /**
225
+ * Instance default for how deep a spawn tree may grow before spawned children
226
+ * stop receiving the self-management MCP (issue #262 / DD-3). A spawned turn at
227
+ * depth `d` gets the self-MCP (incl. write tools, so `send_message` exists and a
228
+ * child can report back to its parent) iff `d <= maxSpawnDepth`. Driven by
229
+ * `PADDOCK_MAX_SPAWN_DEPTH`; default {@link DEFAULT_MAX_SPAWN_DEPTH} (`1` — a
230
+ * manager's direct children work, grandchildren are blocked). `0` restores
231
+ * today's behaviour (no spawned child gets it). A per-project `maxSpawnDepth`
232
+ * overrides this at dispatch (the `driveMode` pattern). Only meaningful when
233
+ * {@link selfMcpWriteEnabled} is on — spawning needs the write tools.
234
+ */
235
+ maxSpawnDepth: number;
236
+ /**
237
+ * Per-deployment gate for programmatic schedule mutation (issue #265 / DD-7).
238
+ * When ON, the FleetManager is constructed with `allowScheduleMutation: true`,
239
+ * so herdctl's runtime schedule add/remove APIs (the
240
+ * seam the D4 schedules UI calls) are permitted; OFF (default) makes them throw.
241
+ * Declaring schedules statically in `project.yaml` is unaffected either way.
242
+ * Driven by `PADDOCK_SCHEDULE_MUTATION`; accepts 1/true/yes.
243
+ */
244
+ scheduleMutationEnabled: boolean;
245
+ /**
246
+ * External Management API clients (issue #312 M1) — the `/mcp` surface for
247
+ * callers OUTSIDE this instance (a laptop Claude Code session, a peer Paddock).
248
+ *
249
+ * Self-contained and INDEPENDENT of {@link auth}: `/mcp` authenticates itself,
250
+ * so it stays credential-gated even at `auth.mode: none`, and needs no reverse
251
+ * proxy. An EMPTY client list means the surface is off entirely and `/mcp`
252
+ * 404s — the endpoint does not exist until deliberately configured.
253
+ */
254
+ managementApi: ManagementApiConfig;
255
+ /**
256
+ * Operator-facing problems found while resolving {@link managementApi} — a
257
+ * malformed client (`errors`) or one dropped because its credential wouldn't
258
+ * resolve (`warnings`). Carried on the config rather than logged at parse time
259
+ * because config loading has no logger; app.ts logs these at boot.
260
+ */
261
+ managementApiDiagnostics: {
262
+ errors: string[];
263
+ warnings: string[];
264
+ };
265
+ /**
266
+ * Instance default for the hook-management MCP (Epic G / G5, GG-4) — the
267
+ * `mcp__paddock_manage__{list,set,remove}_hook` tools that let a project agent
268
+ * declare/edit/delete its own event hooks. A sibling of {@link selfMcpWriteEnabled}:
269
+ * OFF by default (opt-in), and only surfaces when the self-MCP write tools are also
270
+ * present (the hook tools live on the same injected server, appended in the write
271
+ * block). Driven by `PADDOCK_HOOKS_MCP`; accepts 1/true/yes. A per-project
272
+ * `hooksMcpEnabled` override wins at dispatch (resolved via
273
+ * {@link import("./hook-config.js").resolveHooksMcpEnabled}), the same
274
+ * inherit/override discipline as `maxSpawnDepth`. The gate is BINARY access to the
275
+ * MCP — an agent that has it can create hooks at any capability (GG-4: no
276
+ * per-capability gating).
277
+ */
278
+ hooksMcpEnabled: boolean;
279
+ /**
280
+ * Keeper-chat recovery config (issue #301) — the two independently-toggleable
281
+ * layers that unstick a keeper whose background task is killed at the turn
282
+ * boundary (see recovery-config.ts / edspencer/herdctl#374). Instance defaults
283
+ * here (`PADDOCK_RECOVERY_*` env, YAML beneath); a per-project `recovery`
284
+ * override wins at dispatch via
285
+ * {@link import("./recovery-config.js").resolveRecoveryConfig}. Layer 2
286
+ * (`surfaceKilledTask`) defaults ON; Layer 3 (`autoReDrive`) defaults OFF.
287
+ */
288
+ recovery: RecoveryConfig;
289
+ /**
290
+ * Inbound composer-attachment config (issue #328) — whether users can upload
291
+ * files/images into the composer, and the size/count/type caps. Instance
292
+ * defaults here (`PADDOCK_ATTACHMENTS_*` env, YAML beneath); a per-project
293
+ * `attachments` override wins at request time via
294
+ * {@link import("./attachments-config.js").resolveAttachmentsConfig}. Enabled +
295
+ * allow-all by default.
296
+ */
297
+ attachments: AttachmentsConfig;
298
+ /**
299
+ * Per-file token budgets the post-turn sweeper (curation) must keep its three
300
+ * curated files under (issue #379). These bound the context every keeper chat
301
+ * pays for — CHANGELOG.md + OVERVIEW.md are injected into the project-context
302
+ * preload, and CLAUDE.md auto-loads every turn. The sweeper is told each budget
303
+ * (so it prunes/dedups to fit) and `SweepService` enforces it as a backstop.
304
+ * Instance defaults here (`PADDOCK_CURATION_*` env, YAML beneath).
305
+ */
306
+ curation: CurationConfig;
307
+ /**
308
+ * Log level for the server's structured logger (Fastify/pino). Driven by
309
+ * `LOG_LEVEL`; default `info`.
310
+ */
311
+ logLevel: string;
312
+ /**
313
+ * Whether keeper agents receive the Playwright browser MCP server
314
+ * (headless Chromium) so Claude Code can drive a browser (navigate / click /
315
+ * snapshot / screenshot). Driven by `PADDOCK_BROWSER_MCP` (`1` enables);
316
+ * default false. Scoped PER INSTANCE — a box without the browser stack leaves
317
+ * it off so there are no failed spawns, and enabling it is a per-box env flip.
318
+ */
319
+ browserMcp: boolean;
320
+ /**
321
+ * Minimum ms between post-turn curation sweeps for a single project, or
322
+ * `undefined` to use the SweepService default (5 min). Driven by
323
+ * `PADDOCK_SWEEP_MIN_INTERVAL_MS`; a non-finite or negative value is ignored
324
+ * (falls back to the default).
325
+ */
326
+ sweepMinIntervalMs?: number;
327
+ /**
328
+ * Git commit identity used when Paddock commits on a project's behalf, so no
329
+ * global git config is needed. Driven by `PADDOCK_GIT_AUTHOR_NAME` /
330
+ * `PADDOCK_GIT_AUTHOR_EMAIL`; defaults `Paddock` / `paddock@localhost`.
331
+ */
332
+ gitAuthor: {
333
+ name: string;
334
+ email: string;
335
+ };
336
+ /**
337
+ * The GitHub OAuth/App client id for the git-backing-store device flow
338
+ * (github-auth.ts). Driven by `PADDOCK_GITHUB_CLIENT_ID`; `undefined` when
339
+ * unset, in which case the GitHub connect feature reports "not configured".
340
+ */
341
+ githubClientId?: string;
342
+ }
343
+ /**
344
+ * On-disk shape of the optional YAML instance-config file (issue #270 / DD-5).
345
+ *
346
+ * This is the BASE layer for {@link PaddockConfig}: every field is optional and
347
+ * a matching `PADDOCK_*` env var still overrides it (precedence file < env), so
348
+ * an env-only deployment is unaffected when no file is present. Values mirror
349
+ * the resolved config's structure; scalars accept their natural YAML type (and
350
+ * also a string, since each value is coerced through the same env-parsing path).
351
+ * Unknown keys are ignored — later epics (schedules, hooks) will add their own
352
+ * top-level record sections here.
353
+ */
354
+ export interface PaddockConfigFile {
355
+ port?: number | string;
356
+ host?: string;
357
+ dataDir?: string;
358
+ projectsRoot?: string;
359
+ stateDir?: string;
360
+ herdctlConfigPath?: string;
361
+ webDist?: string;
362
+ auth?: {
363
+ mode?: string;
364
+ userHeader?: string;
365
+ emailHeader?: string;
366
+ groupsHeader?: string;
367
+ jwtHeader?: string;
368
+ jwksUrl?: string;
369
+ jwtIssuer?: string;
370
+ jwtAudience?: string;
371
+ usernameClaim?: string;
372
+ groupsClaim?: string;
373
+ };
374
+ transcription?: {
375
+ mode?: string;
376
+ model?: string;
377
+ endpoint?: string;
378
+ apiKey?: string;
379
+ language?: string;
380
+ maxUploadBytes?: number | string;
381
+ };
382
+ brand?: {
383
+ name?: string;
384
+ logo?: string;
385
+ accent?: string;
386
+ };
387
+ openapi?: {
388
+ enabled?: boolean | string;
389
+ path?: string;
390
+ };
391
+ /**
392
+ * Instance allow-list of offered models (issue #457 Step 2). A real array of
393
+ * catalog ids (or a comma-separated string, coerced the same way); a matching
394
+ * `PADDOCK_MODELS` env var (comma-separated) still overrides it (file < env).
395
+ * Absent ⇒ every catalog model is offered (unchanged behaviour).
396
+ */
397
+ models?: string[] | string;
398
+ driveMode?: string;
399
+ nativeSystemPrompt?: boolean | string;
400
+ /**
401
+ * Environment system prompt override (issue #635). Absent ⇒ Paddock's built-in
402
+ * text; a non-empty string ⇒ that text instead; an EMPTY string ⇒ append
403
+ * nothing. Unlike almost every other key here, blank is meaningful and is NOT
404
+ * folded to the default — see {@link loadEnvironmentPrompt}.
405
+ */
406
+ environmentPrompt?: string;
407
+ selfMcpEnabled?: boolean | string;
408
+ selfMcpWriteEnabled?: boolean | string;
409
+ selfMcpProjectsEnabled?: boolean | string;
410
+ maxSpawnDepth?: number | string;
411
+ scheduleMutationEnabled?: boolean | string;
412
+ hooksMcpEnabled?: boolean | string;
413
+ /**
414
+ * External Management API config (issue #312 M1). Token material is given as
415
+ * an `env:VAR_NAME` REFERENCE — never inlined, because this file is
416
+ * git-tracked. Absent ⇒ no external clients ⇒ `/mcp` 404s (fail closed).
417
+ */
418
+ managementApi?: ManagementApiConfigFile;
419
+ /**
420
+ * Keeper-chat recovery config (issue #301). Every field optional; a matching
421
+ * `PADDOCK_RECOVERY_*` env var still overrides it (precedence file < env).
422
+ */
423
+ recovery?: {
424
+ surfaceKilledTask?: boolean | string;
425
+ autoReDrive?: boolean | string;
426
+ debounceMs?: number | string;
427
+ maxRetries?: number | string;
428
+ limboTimeoutMs?: number | string;
429
+ };
430
+ /**
431
+ * Inbound composer-attachment config (issue #328). Every field optional; a
432
+ * matching `PADDOCK_ATTACHMENTS_*` env var still overrides it (file < env).
433
+ * `allowedTypes` is a real array here (env is comma-separated).
434
+ */
435
+ attachments?: {
436
+ enabled?: boolean | string;
437
+ maxFileSizeMb?: number | string;
438
+ maxFilesPerMessage?: number | string;
439
+ allowedTypes?: string[] | string;
440
+ };
441
+ /**
442
+ * Per-file curation token budgets (issue #379). Every field optional; a
443
+ * matching `PADDOCK_CURATION_*` env var still overrides it (file < env).
444
+ */
445
+ curation?: {
446
+ overviewMaxTokens?: number | string;
447
+ changelogMaxTokens?: number | string;
448
+ claudeMaxTokens?: number | string;
449
+ };
450
+ logLevel?: string;
451
+ browserMcp?: boolean | string;
452
+ sweepMinIntervalMs?: number | string;
453
+ gitAuthor?: {
454
+ name?: string;
455
+ email?: string;
456
+ };
457
+ githubClientId?: string;
458
+ }
459
+ /**
460
+ * Voice-dictation (Whisper) capability. Mirrors HushPod's whisper config so the
461
+ * two can share a transcription backend (e.g. Ed's laptop whisper server). Driven
462
+ * entirely by `PADDOCK_WHISPER_*` env so it is scoped PER INSTANCE and defaults
463
+ * to `off` — a plain instance advertises no mic button.
464
+ *
465
+ * - `off` — dictation disabled (default). No mic button in the composer.
466
+ * - `remote` — POST audio to an OpenAI-compatible `/audio/transcriptions`
467
+ * endpoint (e.g. `http://whisper.local:8385/v1`). The same kind of
468
+ * server HushPod points at.
469
+ * - `local` — run whisper.cpp on this box via nodejs-whisper (CPU; slower).
470
+ */
471
+ export type WhisperMode = "off" | "local" | "remote";
472
+ export interface TranscriptionConfig {
473
+ /** Dictation backend. `off` disables the composer mic button. */
474
+ mode: WhisperMode;
475
+ /** Whisper model name (e.g. `base`, `base.en`, `small`). */
476
+ model: string;
477
+ /**
478
+ * remote: OpenAI-compatible base URL, e.g. `http://whisper.local:8385/v1`.
479
+ * `/audio/transcriptions` is appended. Required in `remote` mode.
480
+ */
481
+ endpoint?: string;
482
+ /** remote: optional bearer token sent as `Authorization: Bearer …`. */
483
+ apiKey?: string;
484
+ /** Optional spoken-language hint (ISO-639-1, e.g. `en`). Unset ⇒ auto-detect. */
485
+ language?: string;
486
+ /** Max accepted upload size in bytes (guards the transcribe route). */
487
+ maxUploadBytes: number;
488
+ }
489
+ /**
490
+ * Load the optional YAML instance-config file that provides the BASE layer for
491
+ * {@link PaddockConfig} (issue #270 / DD-5). Env vars still override every value
492
+ * (precedence file < env).
493
+ *
494
+ * Path resolution: an explicit `PADDOCK_CONFIG` env var wins; otherwise
495
+ * `<dataDir>/paddock.config.yaml`. When no file exists at the default location
496
+ * the result is an empty object, so an env-only deployment behaves exactly as
497
+ * before — this is a no-op for existing installs. An explicit `PADDOCK_CONFIG`
498
+ * that points at a missing file is treated as a misconfiguration (a clear error)
499
+ * rather than silently ignored.
500
+ *
501
+ * A present-but-malformed file (unparseable YAML, or a top-level scalar/list
502
+ * instead of a mapping) throws a clear Error rather than starting up with a
503
+ * half-empty config.
504
+ */
505
+ export declare function loadConfigFile(dataDir: string): PaddockConfigFile;
506
+ /**
507
+ * Default location of the built web SPA, resolved RELATIVE TO THIS MODULE:
508
+ * `packages/server/{src,dist}/config.js` -> `packages/web/dist`. The same hop
509
+ * works from both the `tsx src/` and `node dist/` layouts, so neither needs a
510
+ * `PADDOCK_WEB_DIST` override.
511
+ *
512
+ * Takes the module URL as a parameter purely so a test can exercise install
513
+ * paths this repo's own checkout does not have.
514
+ *
515
+ * **`fileURLToPath`, NOT `new URL(url).pathname`.** The raw pathname is
516
+ * percent-ENCODED, so an install path containing a space or any non-ASCII
517
+ * character (`/opt/my paddock/`, `~/Développement/`) yields a literal `%20`
518
+ * that resolves to a directory which does not exist. The failure is SILENT:
519
+ * `app.ts` degrades to API-only mode with only a log warning, so the user gets
520
+ * a blank page and no explanation of why. `fileURLToPath` also decodes the
521
+ * `/C:/...` drive-letter form on Windows. This is irrelevant when the path is
522
+ * the Docker image's fixed `/app`, and load-bearing the moment the package is
523
+ * installed under an arbitrary user directory (`npx`, global install).
524
+ */
525
+ export declare function resolveDefaultWebDist(moduleUrl: string): string;
526
+ export declare function loadPaddockConfig(): PaddockConfig;
527
+ /**
528
+ * Resolve the Claude home from the environment — `CLAUDE_HOME`, else
529
+ * `~/.claude`.
530
+ *
531
+ * This is the RESOLVER, not the accessor. It is read once by
532
+ * {@link loadPaddockConfig} into {@link PaddockConfig.claudeHome}; runtime code
533
+ * should thread `cfg.claudeHome` rather than call this again, so paddock and the
534
+ * engine can never end up resolving two different homes (#588). It stays a
535
+ * function (not a constant) because `os.homedir()` must be read at call time —
536
+ * tests and processes that mutate `HOME` depend on that.
537
+ */
538
+ export declare function claudeHome(): string;