@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,42 @@
1
+ /**
2
+ * Encode a working directory the way Claude Code names its transcript dir.
3
+ * For paths under 200 chars this is just the non-alphanumeric→'-' replacement
4
+ * (paddock's project dirs are always short, so the truncate+hash branch Claude
5
+ * Code uses for very long paths never applies here).
6
+ */
7
+ export declare function encodeProjectDir(dir: string): string;
8
+ /** Absolute path to the project's local transcript directory. */
9
+ export declare function projectChatsDir(projectDir: string): string;
10
+ /**
11
+ * Ensure `<chatsHostDir>/.chats/` exists and that Claude Code's encoded
12
+ * transcript path for `workingDir` is a symlink pointing at it (migrating an
13
+ * existing real transcript dir in the process). Safe to call on every agent
14
+ * registration. Never throws — a failure here must not block agent registration
15
+ * or chat.
16
+ *
17
+ * `workingDir` is the agent's cwd (which Claude encodes into the transcript dir
18
+ * name); `chatsHostDir` is where the `.chats/` store actually lives. For a
19
+ * notebook project these are the same dir (the default). For a REPO-BACKED
20
+ * project (issue #187) the keeper's cwd is the nested checkout but the `.chats/`
21
+ * store stays in the project's metadata dir (the data repo) — so transcripts
22
+ * never pollute the external repo's working tree — hence the two are split.
23
+ *
24
+ * `claudeHomePath` is the Claude home to plant the symlink in. Callers holding a
25
+ * config MUST pass `cfg.claudeHome` (#588): the engine is constructed with that
26
+ * same resolved value, and a symlink planted in a different home than the one
27
+ * the engine reads is exactly the "chats list but open empty" failure. The
28
+ * env-derived default is kept only for callers with no config (unit tests).
29
+ */
30
+ export declare function ensureProjectChats(workingDir: string, chatsHostDir?: string, claudeHomePath?: string): Promise<void>;
31
+ /**
32
+ * Read a session's FIRST user message text, untruncated, straight from its
33
+ * transcript JSONL (issue #62). Claude Code's own `preview` is capped at 100
34
+ * chars — for a preload chat that cap falls inside the injected OVERVIEW block,
35
+ * so the preview can't be un-wrapped. Reading the full first user message lets
36
+ * the chat-list strip the wrapper and show the user's real request.
37
+ *
38
+ * Streams line-by-line and stops at the first user text, so it only reads the
39
+ * head of the file. Returns undefined if the transcript is missing/unreadable or
40
+ * has no user text. The sessionId is validated to keep it inside `.chats/`.
41
+ */
42
+ export declare function readFirstUserText(projectDir: string, sessionId: string): Promise<string | undefined>;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Transcript relocation (backing-store Phase 3).
3
+ *
4
+ * Claude Code writes a session transcript to `~/.claude/projects/<encoded-cwd>/`,
5
+ * where `<encoded-cwd>` is the agent's absolute working directory with every
6
+ * non-[A-Za-z0-9] char replaced by '-'. That makes transcripts path-coupled and
7
+ * not portable. We relocate them INTO the project by making the encoded path a
8
+ * **symlink to `<projectDir>/.chats/`** — Claude then writes through the symlink
9
+ * into the project dir (validated empirically), and herdctl's discovery, resume,
10
+ * delete and rename all resolve through it transparently. The project dir becomes
11
+ * self-contained and travels with the repo / NAS.
12
+ *
13
+ * `ensureProjectChats` is idempotent and self-healing: on first run for a project
14
+ * whose encoded path is still a real directory (existing transcripts), it migrates
15
+ * those files into `.chats/` and replaces the directory with the symlink.
16
+ */
17
+ import { promises as fs, createReadStream } from "node:fs";
18
+ import { createInterface } from "node:readline";
19
+ import path from "node:path";
20
+ import { claudeHome } from "./config.js";
21
+ /**
22
+ * Encode a working directory the way Claude Code names its transcript dir.
23
+ * For paths under 200 chars this is just the non-alphanumeric→'-' replacement
24
+ * (paddock's project dirs are always short, so the truncate+hash branch Claude
25
+ * Code uses for very long paths never applies here).
26
+ */
27
+ export function encodeProjectDir(dir) {
28
+ return dir.replace(/[^a-zA-Z0-9]/g, "-");
29
+ }
30
+ /** Absolute path to the project's local transcript directory. */
31
+ export function projectChatsDir(projectDir) {
32
+ return path.join(projectDir, ".chats");
33
+ }
34
+ /**
35
+ * Ensure `<chatsHostDir>/.chats/` exists and that Claude Code's encoded
36
+ * transcript path for `workingDir` is a symlink pointing at it (migrating an
37
+ * existing real transcript dir in the process). Safe to call on every agent
38
+ * registration. Never throws — a failure here must not block agent registration
39
+ * or chat.
40
+ *
41
+ * `workingDir` is the agent's cwd (which Claude encodes into the transcript dir
42
+ * name); `chatsHostDir` is where the `.chats/` store actually lives. For a
43
+ * notebook project these are the same dir (the default). For a REPO-BACKED
44
+ * project (issue #187) the keeper's cwd is the nested checkout but the `.chats/`
45
+ * store stays in the project's metadata dir (the data repo) — so transcripts
46
+ * never pollute the external repo's working tree — hence the two are split.
47
+ *
48
+ * `claudeHomePath` is the Claude home to plant the symlink in. Callers holding a
49
+ * config MUST pass `cfg.claudeHome` (#588): the engine is constructed with that
50
+ * same resolved value, and a symlink planted in a different home than the one
51
+ * the engine reads is exactly the "chats list but open empty" failure. The
52
+ * env-derived default is kept only for callers with no config (unit tests).
53
+ */
54
+ export async function ensureProjectChats(workingDir, chatsHostDir = workingDir, claudeHomePath = claudeHome()) {
55
+ try {
56
+ const chatsDir = projectChatsDir(chatsHostDir);
57
+ await fs.mkdir(chatsDir, { recursive: true });
58
+ const encoded = path.join(claudeHomePath, "projects", encodeProjectDir(workingDir));
59
+ await fs.mkdir(path.dirname(encoded), { recursive: true });
60
+ const st = await fs.lstat(encoded).catch(() => null);
61
+ // Already a symlink — point it at .chats if it drifted, else done.
62
+ if (st?.isSymbolicLink()) {
63
+ const target = await fs.readlink(encoded).catch(() => "");
64
+ const resolved = path.resolve(path.dirname(encoded), target);
65
+ if (resolved !== path.resolve(chatsDir)) {
66
+ await fs.rm(encoded, { force: true });
67
+ await fs.symlink(chatsDir, encoded);
68
+ }
69
+ return;
70
+ }
71
+ // A real directory of existing transcripts — migrate into .chats, then link.
72
+ if (st?.isDirectory()) {
73
+ for (const entry of await fs.readdir(encoded)) {
74
+ const from = path.join(encoded, entry);
75
+ const to = path.join(chatsDir, entry);
76
+ if (await fs.lstat(to).then(() => true).catch(() => false))
77
+ continue; // don't clobber
78
+ // cp+rm is robust across filesystems (rename would EXDEV across mounts).
79
+ // `preserveTimestamps` is load-bearing, not cosmetic (#588): fs.cp
80
+ // defaults to stamping the copy with NOW, and a transcript's mtime is
81
+ // both the chat-list sort key and the cache key for auto-name / preview /
82
+ // sidechain detection — so without it, relocating a months-old archive
83
+ // collapses every one of those chats to "today".
84
+ await fs.cp(from, to, { recursive: true, preserveTimestamps: true });
85
+ await fs.rm(from, { recursive: true, force: true });
86
+ }
87
+ await fs.rmdir(encoded).catch(() => undefined);
88
+ await fs.symlink(chatsDir, encoded);
89
+ return;
90
+ }
91
+ // Nothing there yet — just create the symlink so future turns land in .chats.
92
+ await fs.symlink(chatsDir, encoded);
93
+ }
94
+ catch {
95
+ /* non-fatal: fall back to Claude Code's default location for this project */
96
+ }
97
+ }
98
+ /**
99
+ * Read a session's FIRST user message text, untruncated, straight from its
100
+ * transcript JSONL (issue #62). Claude Code's own `preview` is capped at 100
101
+ * chars — for a preload chat that cap falls inside the injected OVERVIEW block,
102
+ * so the preview can't be un-wrapped. Reading the full first user message lets
103
+ * the chat-list strip the wrapper and show the user's real request.
104
+ *
105
+ * Streams line-by-line and stops at the first user text, so it only reads the
106
+ * head of the file. Returns undefined if the transcript is missing/unreadable or
107
+ * has no user text. The sessionId is validated to keep it inside `.chats/`.
108
+ */
109
+ export async function readFirstUserText(projectDir, sessionId) {
110
+ if (!/^[A-Za-z0-9._-]+$/.test(sessionId))
111
+ return undefined;
112
+ const file = path.join(projectChatsDir(projectDir), `${sessionId}.jsonl`);
113
+ const stream = createReadStream(file, { encoding: "utf8" });
114
+ // A missing/unreadable file rejects on the stream; swallow and return undefined.
115
+ stream.on("error", () => undefined);
116
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
117
+ try {
118
+ for await (const line of rl) {
119
+ const trimmed = line.trim();
120
+ if (!trimmed)
121
+ continue;
122
+ let parsed;
123
+ try {
124
+ parsed = JSON.parse(trimmed);
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ if (parsed.type !== "user")
130
+ continue;
131
+ const text = extractUserText(parsed.message?.content);
132
+ if (text)
133
+ return text;
134
+ }
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ finally {
140
+ rl.close();
141
+ stream.destroy();
142
+ }
143
+ return undefined;
144
+ }
145
+ /**
146
+ * Text of a transcript user message's `content` (string, or an array of blocks).
147
+ * A message carrying tool_result blocks isn't a real prompt — return "" so the
148
+ * caller skips it.
149
+ */
150
+ function extractUserText(content) {
151
+ if (typeof content === "string")
152
+ return content;
153
+ if (!Array.isArray(content))
154
+ return "";
155
+ if (content.some((b) => b?.type === "tool_result"))
156
+ return "";
157
+ return content
158
+ .filter((b) => {
159
+ const blk = b;
160
+ return blk?.type === "text" && typeof blk.text === "string";
161
+ })
162
+ .map((b) => b.text)
163
+ .join("");
164
+ }
@@ -0,0 +1,278 @@
1
+ import { z } from "zod";
2
+ /** The trigger kinds. `webhook` is shape-reserved (no ingress in T1 — deferred T6). */
3
+ export declare const TRIGGER_TYPES: readonly ["schedule", "event", "webhook"];
4
+ export type TriggerType = (typeof TRIGGER_TYPES)[number];
5
+ /**
6
+ * The lifecycle events an `event`-type trigger may fire on. `onArchive` is wired
7
+ * (fired after a chat-archive commits — the Epic G motivating cleanup). `afterTurn`
8
+ * is a KNOWN value (validation accepts it) reserved for the sweeper fold-in (T5) —
9
+ * it validates + persists now but isn't emitted until then, exactly as `webhook` is
10
+ * shape-reserved. Adding a sibling event stays a ~3-line change (new value here + a
11
+ * payload + one `emit()` at the commit site).
12
+ */
13
+ export declare const TRIGGER_EVENTS: readonly ["onArchive", "afterTurn"];
14
+ export type TriggerEvent = (typeof TRIGGER_EVENTS)[number];
15
+ /** New-vs-accrete for a fired trigger (design §2.3). */
16
+ export type TriggerSession = "new" | "resume";
17
+ /** Claude Code permission mode a trigger agent's turns run under. */
18
+ export type TriggerPermissionMode = "default" | "acceptEdits" | "bypassPermissions" | "plan";
19
+ /** The dir (relative to a project's working dir) holding keeper-editable prompts. */
20
+ export declare const TRIGGER_PROMPT_DIR: string;
21
+ /** Default max agent turns for a trigger when its run doesn't set one. */
22
+ export declare const TRIGGER_DEFAULT_MAX_TURNS = 30;
23
+ /**
24
+ * The canonical name of the built-in post-turn CURATOR trigger — the sweeper folded
25
+ * in as the default `event`/`afterTurn` trigger (T5, design §2.1 #4). A project need
26
+ * NOT declare it: absent, the curator runs with default behaviour (exactly the shipped
27
+ * sweeper). Declaring a `curate-overview` trigger only CUSTOMISES that default (extend
28
+ * its prompt, override its model, or `enabled: false` to switch curation off). Resolved
29
+ * by NAME as a convenience, but recognised structurally by {@link isCuratorTrigger}.
30
+ */
31
+ export declare const CURATE_TRIGGER_NAME = "curate-overview";
32
+ /**
33
+ * The frozen trigger schema: `trigger` (discriminated union) + `run` + `enabled`.
34
+ * Two cross-field refinements the discriminatedUnion can't express inline:
35
+ * - a `schedule` trigger requires EXACTLY ONE of `cron` / `interval`;
36
+ * - `run` requires EXACTLY ONE of `prompt` / `promptFile`.
37
+ *
38
+ * `enabled` **defaults `false`** — a trigger created programmatically (or via a
39
+ * hand-edit that omits it) is inert until deliberately switched on (design §2.3,
40
+ * mirroring the Epic G safe-create default).
41
+ */
42
+ export declare const PaddockTriggerSchema: z.ZodObject<{
43
+ trigger: z.ZodDiscriminatedUnion<[z.ZodObject<{
44
+ type: z.ZodLiteral<"schedule">;
45
+ cron: z.ZodOptional<z.ZodString>;
46
+ interval: z.ZodOptional<z.ZodString>;
47
+ }, z.core.$strip>, z.ZodObject<{
48
+ type: z.ZodLiteral<"event">;
49
+ on: z.ZodEnum<{
50
+ onArchive: "onArchive";
51
+ afterTurn: "afterTurn";
52
+ }>;
53
+ }, z.core.$strip>, z.ZodObject<{
54
+ type: z.ZodLiteral<"webhook">;
55
+ path: z.ZodString;
56
+ }, z.core.$strip>], "type">;
57
+ run: z.ZodObject<{
58
+ prompt: z.ZodOptional<z.ZodString>;
59
+ promptFile: z.ZodOptional<z.ZodString>;
60
+ session: z.ZodDefault<z.ZodEnum<{
61
+ new: "new";
62
+ resume: "resume";
63
+ }>>;
64
+ model: z.ZodOptional<z.ZodString>;
65
+ tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
66
+ maxSpawnDepth: z.ZodOptional<z.ZodNumber>;
67
+ permissionMode: z.ZodOptional<z.ZodEnum<{
68
+ default: "default";
69
+ acceptEdits: "acceptEdits";
70
+ plan: "plan";
71
+ bypassPermissions: "bypassPermissions";
72
+ }>>;
73
+ maxTurns: z.ZodOptional<z.ZodNumber>;
74
+ }, z.core.$strip>;
75
+ enabled: z.ZodDefault<z.ZodBoolean>;
76
+ }, z.core.$strip>;
77
+ /** A validated trigger — the persisted per-project record (`project.yaml` `triggers`). */
78
+ export type PaddockTrigger = z.infer<typeof PaddockTriggerSchema>;
79
+ /** The `when` discriminated union, on its own (WHEN a trigger fires). */
80
+ export type TriggerWhen = PaddockTrigger["trigger"];
81
+ /** The `schedule` variant of {@link TriggerWhen}. */
82
+ export type ScheduleTriggerWhen = Extract<TriggerWhen, {
83
+ type: "schedule";
84
+ }>;
85
+ /** The `event` variant of {@link TriggerWhen}. */
86
+ export type EventTriggerWhen = Extract<TriggerWhen, {
87
+ type: "event";
88
+ }>;
89
+ /** The `webhook` variant of {@link TriggerWhen}. */
90
+ export type WebhookTriggerWhen = Extract<TriggerWhen, {
91
+ type: "webhook";
92
+ }>;
93
+ /** The shared agent-run definition (WHAT a fired trigger does). */
94
+ export type TriggerRun = PaddockTrigger["run"];
95
+ /**
96
+ * The CRUD/DTO shape the trigger service ({@link import("./triggers.js").TriggerService})
97
+ * returns — a {@link PaddockTrigger} plus its map key `name` and the deterministic
98
+ * herdctl agent it registers as (`trigger-<slug>-<name>`). This is the frozen contract
99
+ * T2–T5 build against (the analogue of the shipped `HookDto`).
100
+ */
101
+ export type TriggerDto = PaddockTrigger & {
102
+ /** The trigger's name — the `project.yaml` map key + the `<name>` in its agent name. */
103
+ name: string;
104
+ /** The herdctl agent this trigger registers as (`trigger-<slug>-<name>`). */
105
+ agentName: string;
106
+ };
107
+ /** A trigger name we're willing to key on (also a safe herdctl agent-name segment). */
108
+ export declare function isValidTriggerName(name: string): boolean;
109
+ /**
110
+ * Validate + normalise one untrusted trigger record into a {@link PaddockTrigger},
111
+ * or `null` if it's malformed (bad discriminant, both/neither cron+interval, unknown
112
+ * `on`, both/neither prompt+promptFile, …). Defaults are applied (`enabled: false`,
113
+ * `session: "new"`, `tools: []`). Unknown fields are stripped (Zod default).
114
+ */
115
+ export declare function sanitizeTrigger(raw: unknown): PaddockTrigger | null;
116
+ /**
117
+ * Sanitise a whole `triggers` map, DROPPING malformed entries and entries with an
118
+ * unsafe name — so one bad hand-edit can't brick the project's agent registration
119
+ * (an invalid trigger agent config would throw in `addAgent`). Returns `undefined`
120
+ * when nothing survives (so it stays absent on disk / off the project record),
121
+ * exactly like its `sanitizeHooks` / `sanitizeSchedules` ancestors.
122
+ */
123
+ export declare function sanitizeTriggers(raw: unknown): Record<string, PaddockTrigger> | undefined;
124
+ /**
125
+ * Overlay a PARTIAL trigger update onto an existing trigger, producing an untrusted
126
+ * record for {@link sanitizeTrigger} to validate — the unified successor to
127
+ * {@link import("./hook-config.js").mergeHookUpdate}, used by the self-MCP `set_trigger`
128
+ * tool so an edit that supplies only some fields (the classic being "enable/disable",
129
+ * an `enabled`-only set — GG-3) preserves everything else rather than wiping it.
130
+ *
131
+ * The three parts merge independently:
132
+ * - `trigger` (the WHEN discriminant): supplied wholesale or inherited. Because the
133
+ * variants carry different fields (`cron`/`interval` vs `on` vs `path`), a partial
134
+ * trigger can't be merged field-by-field — so `incoming.trigger` is taken WHOLE
135
+ * when the caller supplies one (i.e. re-specifies `type` + its fields), else the
136
+ * existing `trigger` is inherited unchanged.
137
+ * - `run` (the WHAT): merged field-by-field over the existing run, so an edit that
138
+ * touches only `enabled`/`model`/`tools` keeps the rest. `prompt` and `promptFile`
139
+ * are MUTUALLY EXCLUSIVE, so supplying one clears the inherited counterpart —
140
+ * otherwise switching a file-backed trigger to an inline prompt would leave the
141
+ * stale `promptFile` and the merged record would carry BOTH (rejected by the
142
+ * schema's prompt-xor-promptFile refinement). Supplying neither leaves the prompt
143
+ * source untouched.
144
+ * - `enabled`: the supplied value, else the existing flag, else `false` (safe-create).
145
+ *
146
+ * A brand-new trigger (`existing` null) starts from the incoming record verbatim
147
+ * (its `trigger`/`run` must be complete — the schema rejects it otherwise).
148
+ */
149
+ export declare function mergeTriggerUpdate(existing: PaddockTrigger | null | undefined, incoming: {
150
+ trigger?: Record<string, unknown>;
151
+ run?: Record<string, unknown>;
152
+ enabled?: boolean;
153
+ }): Record<string, unknown>;
154
+ /**
155
+ * Whether a trigger runs on its OWN scoped `trigger-<slug>-<name>` agent (so
156
+ * {@link triggerToAgentToolConfig} governs its capability) rather than as the keeper.
157
+ *
158
+ * - **event** → ALWAYS its own agent (Epic G / T1). Its `tools` allow-list IS the
159
+ * capability; an empty `[]` means a deliberately tool-less curator.
160
+ * - **schedule** → its own scoped agent ONLY when it declares a NON-EMPTY `run.tools`
161
+ * allow-list (T2 — the per-trigger tool-scoping this ticket adds). A schedule with NO
162
+ * tools inherits the project agent's default toolset by running as the keeper,
163
+ * preserving the pre-T2 behaviour (ticket #307: "a schedule with no tools inherits
164
+ * the project-agent default"). This is the one asymmetry with events — a schedule's
165
+ * empty `tools` reads as "unscoped, run as keeper", NOT "tool-less curator", because
166
+ * schedules historically ran with the keeper's full tools and there are no users to
167
+ * migrate off that default.
168
+ * - **webhook** → reserved (never fired in T1), so it registers no agent.
169
+ *
170
+ * The ONE place the keeper-vs-own-agent routing decision lives, shared by the herdctl
171
+ * agent registration ({@link import("./herdctl.js").HerdctlService.registerTriggerAgents})
172
+ * and the fire path (`fireTriggerForProject` in `ws.ts`) so arming and firing always agree.
173
+ */
174
+ export declare function triggerRunsOnOwnAgent(trigger: PaddockTrigger): boolean;
175
+ /**
176
+ * Whether a trigger is the post-turn CURATOR (the folded-in sweeper, T5): an
177
+ * `event`/`afterTurn` trigger. The curator is SPECIAL — it does NOT run as a generic
178
+ * `trigger-<slug>-<name>` agent turn. It is tool-less by nature (returns marked text,
179
+ * Paddock's `SweepService` parses it and writes OVERVIEW.md/CHANGELOG.md), so it is
180
+ * executed by the SweepService via the project's `sweeper-<slug>` agent, NOT by the
181
+ * event dispatcher and NOT by its own herdctl agent. Its `run` therefore only tunes the
182
+ * sweep (prompt extension, model, `enabled`), which is why (unlike every OTHER event
183
+ * trigger — see {@link triggerRunsOnOwnAgent}) a curator trigger registers NO scoped
184
+ * agent and is skipped by the generic fire path. This keeps the sweeper's single
185
+ * dispatch (no double-curation): the `afterTurn` event → SweepService, once.
186
+ */
187
+ export declare function isCuratorTrigger(trigger: PaddockTrigger): boolean;
188
+ /**
189
+ * Resolve a project's post-turn CURATOR trigger from its `triggers` map (T5) — the
190
+ * canonical {@link CURATE_TRIGGER_NAME} if it IS a curator, else the first structural
191
+ * curator ({@link isCuratorTrigger}) declared. `null` when the project declares none
192
+ * (the IMPLICIT built-in default — an un-customised project sweeps exactly as the
193
+ * shipped sweeper). Pure, so both `SweepService` (enabled gate + prompt extension) and
194
+ * `HerdctlService` (sweeper model override) resolve the ONE curator the same way.
195
+ */
196
+ export declare function curatorTriggerOf(triggers: Record<string, PaddockTrigger> | undefined): PaddockTrigger | null;
197
+ /**
198
+ * Project a trigger's {@link TriggerRun} onto the exact herdctl agent tool-config
199
+ * fields (snake_case), so an event/webhook trigger's OWN `trigger-<slug>-<name>`
200
+ * agent enforces the capability BY CONSTRUCTION. Always sets `allowed_tools` +
201
+ * `max_turns` so a trigger agent never silently inherits the keeper's broad default
202
+ * toolset; a tool-less trigger yields `allowed_tools: []` (the CLI runtime then
203
+ * denies every tool). The ONE place run→agent-config translation lives. (The exact
204
+ * analogue of `hookToAgentToolConfig`.)
205
+ */
206
+ export declare function triggerToAgentToolConfig(run: TriggerRun): Record<string, unknown>;
207
+ /**
208
+ * Project ONE schedule-type trigger onto the herdctl `ScheduleSchema` fields the
209
+ * cron engine reads (`type` `cron`|`interval`, the timer field, `resume_session`,
210
+ * `enabled`), for forwarding into the keeper agent's `schedules` block. The
211
+ * Paddock-only prompt (inline/`promptFile`) is resolved at fire time by the trigger
212
+ * handler, so herdctl only ever sees a plain `prompt` (or none) — kept pure. The
213
+ * `resume_session` flag is derived from `run.session` so herdctl's own new-vs-accrete
214
+ * stays in agreement with Paddock's (the handler still owns the OWNED-session sidecar).
215
+ */
216
+ export declare function scheduleTriggerToHerdctl(when: ScheduleTriggerWhen, run: TriggerRun, enabled: boolean): Record<string, unknown>;
217
+ /**
218
+ * Build the `schedules` block to forward into the keeper agent config from a
219
+ * project's SCHEDULE-type triggers, or `undefined` when it declares none. Non-schedule
220
+ * triggers (event/webhook) are skipped — they don't arm the cron engine. Keyed by
221
+ * trigger name (the same key the fire handler resolves back to a trigger).
222
+ */
223
+ export declare function triggersToHerdctlSchedules(map: Record<string, PaddockTrigger> | undefined): Record<string, Record<string, unknown>> | undefined;
224
+ /**
225
+ * The compact, web-facing capability descriptor for a TRIGGER chat (Epic T / T4 —
226
+ * the unified successor to {@link import("./hook-config.js").ChatHookInfo}). Rides on
227
+ * the chat DTO whenever a chat's attributed agent is a `trigger-<slug>-<name>` agent,
228
+ * so the floating capability banner can state — TRUTHFULLY FROM CONFIG — what the
229
+ * trigger agent is: its trigger {@link type} (schedule / event / webhook) and WHEN it
230
+ * fires (an event `on`, a `cron`/`interval`, or a webhook `path`), its herdctl agent
231
+ * name, whether it's armed, and the exact tool grant herdctl enforces on its turns.
232
+ * Built by {@link toChatTriggerInfo} from the same {@link TriggerRun} that
233
+ * {@link triggerToAgentToolConfig} projects onto the registered agent, so the banner
234
+ * and the enforced capability can never disagree.
235
+ */
236
+ export interface ChatTriggerInfo {
237
+ /** The trigger's name (`project.yaml` map key + the `<name>` in its agent name). */
238
+ name: string;
239
+ /** WHICH kind of trigger fires this chat (schedule / event / webhook). */
240
+ type: TriggerType;
241
+ /** For an `event` trigger: the lifecycle event that fires it (`onArchive`/`afterTurn`). */
242
+ event?: TriggerEvent;
243
+ /** For a `schedule` trigger: the cron expression, when timer-driven by cron. */
244
+ cron?: string;
245
+ /** For a `schedule` trigger: the interval string, when timer-driven by interval. */
246
+ interval?: string;
247
+ /** For a `webhook` trigger: the reserved ingress path. */
248
+ path?: string;
249
+ /** The herdctl agent enforcing the capability (`trigger-<slug>-<name>`). */
250
+ agentName: string;
251
+ /** Whether the trigger is armed (a disabled trigger's past chats are still shown). */
252
+ enabled: boolean;
253
+ /** The exact tool grant (herdctl `allowed_tools`); `[]` = a tool-less trigger. */
254
+ allowedTools: string[];
255
+ /** The permission mode the trigger's turns run under, when it sets one. */
256
+ permissionMode?: TriggerPermissionMode;
257
+ /** The trigger agent's model override, when set (else the keeper default applies). */
258
+ model?: string;
259
+ /** The trigger's max agent turns (its runaway bound). */
260
+ maxTurns: number;
261
+ }
262
+ /**
263
+ * Project a persisted trigger ({@link TriggerDto} fields) onto the web-facing
264
+ * {@link ChatTriggerInfo}, resolving the SAME capability defaults
265
+ * {@link triggerToAgentToolConfig} uses so the banner mirrors the enforced grant
266
+ * exactly: an absent/empty allow-list surfaces as a tool-less `[]`, and an unset
267
+ * `maxTurns` surfaces the {@link TRIGGER_DEFAULT_MAX_TURNS} bound herdctl applies.
268
+ * The WHEN fields are read off the discriminated `trigger` so the banner can state
269
+ * the trigger type and the exact firing condition.
270
+ */
271
+ export declare function toChatTriggerInfo(dto: TriggerDto): ChatTriggerInfo;
272
+ /**
273
+ * Resolve a `promptFile` to an absolute path under the project's `.paddock/triggers/`
274
+ * dir, or `null` if it escapes that dir, is absolute, or isn't a `.md` file. The name
275
+ * is treated as relative to the triggers dir (so a bare `"daily.md"` resolves to
276
+ * `<workingDir>/.paddock/triggers/daily.md`). Byte-for-byte the hook/schedule twin's guard.
277
+ */
278
+ export declare function triggerPromptFileAbsPath(workingDir: string, promptFile: string): string | null;