@edspencer/paddock 0.0.1 → 0.56.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 (294) 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 +512 -0
  33. package/packages/server/dist/config.js +593 -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/event-bus.d.ts +87 -0
  37. package/packages/server/dist/event-bus.js +48 -0
  38. package/packages/server/dist/git.d.ts +128 -0
  39. package/packages/server/dist/git.js +446 -0
  40. package/packages/server/dist/github-auth.d.ts +44 -0
  41. package/packages/server/dist/github-auth.js +169 -0
  42. package/packages/server/dist/herdctl-agent-config.d.ts +98 -0
  43. package/packages/server/dist/herdctl-agent-config.js +331 -0
  44. package/packages/server/dist/herdctl-agent-names.d.ts +172 -0
  45. package/packages/server/dist/herdctl-agent-names.js +228 -0
  46. package/packages/server/dist/herdctl-jobs-index.d.ts +65 -0
  47. package/packages/server/dist/herdctl-jobs-index.js +225 -0
  48. package/packages/server/dist/herdctl-jobs.d.ts +98 -0
  49. package/packages/server/dist/herdctl-jobs.js +225 -0
  50. package/packages/server/dist/herdctl.d.ts +572 -0
  51. package/packages/server/dist/herdctl.js +1218 -0
  52. package/packages/server/dist/hook-config.d.ts +217 -0
  53. package/packages/server/dist/hook-config.js +224 -0
  54. package/packages/server/dist/http-bytes.d.ts +24 -0
  55. package/packages/server/dist/http-bytes.js +52 -0
  56. package/packages/server/dist/index.d.ts +1 -0
  57. package/packages/server/dist/index.js +14 -0
  58. package/packages/server/dist/instance-config.d.ts +135 -0
  59. package/packages/server/dist/instance-config.js +345 -0
  60. package/packages/server/dist/localcommand.d.ts +23 -0
  61. package/packages/server/dist/localcommand.js +140 -0
  62. package/packages/server/dist/management-auth.d.ts +99 -0
  63. package/packages/server/dist/management-auth.js +165 -0
  64. package/packages/server/dist/management-config.d.ts +164 -0
  65. package/packages/server/dist/management-config.js +286 -0
  66. package/packages/server/dist/management-mcp-server.d.ts +20 -0
  67. package/packages/server/dist/management-mcp-server.js +95 -0
  68. package/packages/server/dist/management-metadata.d.ts +67 -0
  69. package/packages/server/dist/management-metadata.js +56 -0
  70. package/packages/server/dist/management-ops.d.ts +110 -0
  71. package/packages/server/dist/management-ops.js +449 -0
  72. package/packages/server/dist/management-policy.d.ts +172 -0
  73. package/packages/server/dist/management-policy.js +259 -0
  74. package/packages/server/dist/message-provenance.d.ts +112 -0
  75. package/packages/server/dist/message-provenance.js +260 -0
  76. package/packages/server/dist/models.d.ts +164 -0
  77. package/packages/server/dist/models.js +208 -0
  78. package/packages/server/dist/openapi.d.ts +66 -0
  79. package/packages/server/dist/openapi.js +183 -0
  80. package/packages/server/dist/parent-detach.d.ts +30 -0
  81. package/packages/server/dist/parent-detach.js +109 -0
  82. package/packages/server/dist/preload.d.ts +43 -0
  83. package/packages/server/dist/preload.js +55 -0
  84. package/packages/server/dist/project-files.d.ts +76 -0
  85. package/packages/server/dist/project-files.js +191 -0
  86. package/packages/server/dist/project-mime.d.ts +35 -0
  87. package/packages/server/dist/project-mime.js +55 -0
  88. package/packages/server/dist/project-paths.d.ts +88 -0
  89. package/packages/server/dist/project-paths.js +126 -0
  90. package/packages/server/dist/project-types.d.ts +316 -0
  91. package/packages/server/dist/project-types.js +48 -0
  92. package/packages/server/dist/projects.d.ts +202 -0
  93. package/packages/server/dist/projects.js +894 -0
  94. package/packages/server/dist/queued-message.d.ts +35 -0
  95. package/packages/server/dist/queued-message.js +116 -0
  96. package/packages/server/dist/read-state.d.ts +46 -0
  97. package/packages/server/dist/read-state.js +139 -0
  98. package/packages/server/dist/recovery-config.d.ts +111 -0
  99. package/packages/server/dist/recovery-config.js +105 -0
  100. package/packages/server/dist/recovery.d.ts +262 -0
  101. package/packages/server/dist/recovery.js +490 -0
  102. package/packages/server/dist/resume-drain.d.ts +122 -0
  103. package/packages/server/dist/resume-drain.js +158 -0
  104. package/packages/server/dist/route-context.d.ts +168 -0
  105. package/packages/server/dist/route-context.js +39 -0
  106. package/packages/server/dist/route-errors.d.ts +8 -0
  107. package/packages/server/dist/route-errors.js +13 -0
  108. package/packages/server/dist/routes/chats.d.ts +12 -0
  109. package/packages/server/dist/routes/chats.js +1406 -0
  110. package/packages/server/dist/routes/git.d.ts +13 -0
  111. package/packages/server/dist/routes/git.js +236 -0
  112. package/packages/server/dist/routes/mcp.d.ts +83 -0
  113. package/packages/server/dist/routes/mcp.js +250 -0
  114. package/packages/server/dist/routes/meta.d.ts +15 -0
  115. package/packages/server/dist/routes/meta.js +447 -0
  116. package/packages/server/dist/routes/projects.d.ts +25 -0
  117. package/packages/server/dist/routes/projects.js +736 -0
  118. package/packages/server/dist/routes/triggers.d.ts +21 -0
  119. package/packages/server/dist/routes/triggers.js +324 -0
  120. package/packages/server/dist/routes/workspace-mount.d.ts +48 -0
  121. package/packages/server/dist/routes/workspace-mount.js +32 -0
  122. package/packages/server/dist/routes.d.ts +26 -0
  123. package/packages/server/dist/routes.js +29 -0
  124. package/packages/server/dist/run-provenance.d.ts +109 -0
  125. package/packages/server/dist/run-provenance.js +206 -0
  126. package/packages/server/dist/runs.d.ts +92 -0
  127. package/packages/server/dist/runs.js +72 -0
  128. package/packages/server/dist/schedule-config.d.ts +68 -0
  129. package/packages/server/dist/schedule-config.js +75 -0
  130. package/packages/server/dist/schedule-session.d.ts +34 -0
  131. package/packages/server/dist/schedule-session.js +120 -0
  132. package/packages/server/dist/self-mcp-descriptions.d.ts +20 -0
  133. package/packages/server/dist/self-mcp-descriptions.js +145 -0
  134. package/packages/server/dist/self-mcp-read.d.ts +15 -0
  135. package/packages/server/dist/self-mcp-read.js +97 -0
  136. package/packages/server/dist/self-mcp-triggers.d.ts +30 -0
  137. package/packages/server/dist/self-mcp-triggers.js +144 -0
  138. package/packages/server/dist/self-mcp-types.d.ts +248 -0
  139. package/packages/server/dist/self-mcp-types.js +10 -0
  140. package/packages/server/dist/self-mcp-util.d.ts +73 -0
  141. package/packages/server/dist/self-mcp-util.js +157 -0
  142. package/packages/server/dist/self-mcp-write.d.ts +35 -0
  143. package/packages/server/dist/self-mcp-write.js +215 -0
  144. package/packages/server/dist/self-mcp.d.ts +95 -0
  145. package/packages/server/dist/self-mcp.js +448 -0
  146. package/packages/server/dist/send-file-mcp.d.ts +46 -0
  147. package/packages/server/dist/send-file-mcp.js +281 -0
  148. package/packages/server/dist/session-hub.d.ts +186 -0
  149. package/packages/server/dist/session-hub.js +291 -0
  150. package/packages/server/dist/spawn-capability.d.ts +99 -0
  151. package/packages/server/dist/spawn-capability.js +106 -0
  152. package/packages/server/dist/star.d.ts +26 -0
  153. package/packages/server/dist/star.js +94 -0
  154. package/packages/server/dist/start.d.ts +1 -0
  155. package/packages/server/dist/start.js +21 -0
  156. package/packages/server/dist/subagents.d.ts +337 -0
  157. package/packages/server/dist/subagents.js +626 -0
  158. package/packages/server/dist/sweep.d.ts +122 -0
  159. package/packages/server/dist/sweep.js +696 -0
  160. package/packages/server/dist/tooldetails.d.ts +33 -0
  161. package/packages/server/dist/tooldetails.js +466 -0
  162. package/packages/server/dist/transcribe.d.ts +69 -0
  163. package/packages/server/dist/transcribe.js +119 -0
  164. package/packages/server/dist/transcripts.d.ts +42 -0
  165. package/packages/server/dist/transcripts.js +164 -0
  166. package/packages/server/dist/trigger-config.d.ts +278 -0
  167. package/packages/server/dist/trigger-config.js +417 -0
  168. package/packages/server/dist/trigger-runtime.d.ts +94 -0
  169. package/packages/server/dist/trigger-runtime.js +82 -0
  170. package/packages/server/dist/trigger-session.d.ts +34 -0
  171. package/packages/server/dist/trigger-session.js +122 -0
  172. package/packages/server/dist/triggers.d.ts +83 -0
  173. package/packages/server/dist/triggers.js +124 -0
  174. package/packages/server/dist/trusted-proxy.d.ts +57 -0
  175. package/packages/server/dist/trusted-proxy.js +157 -0
  176. package/packages/server/dist/turn-notice.d.ts +154 -0
  177. package/packages/server/dist/turn-notice.js +271 -0
  178. package/packages/server/dist/unread.d.ts +36 -0
  179. package/packages/server/dist/unread.js +123 -0
  180. package/packages/server/dist/usage.d.ts +66 -0
  181. package/packages/server/dist/usage.js +243 -0
  182. package/packages/server/dist/wake-injection.d.ts +156 -0
  183. package/packages/server/dist/wake-injection.js +136 -0
  184. package/packages/server/dist/whisper-local.d.ts +9 -0
  185. package/packages/server/dist/whisper-local.js +122 -0
  186. package/packages/server/dist/ws-context.d.ts +158 -0
  187. package/packages/server/dist/ws-context.js +1 -0
  188. package/packages/server/dist/ws-protocol.d.ts +423 -0
  189. package/packages/server/dist/ws-protocol.js +251 -0
  190. package/packages/server/dist/ws-self-mcp.d.ts +52 -0
  191. package/packages/server/dist/ws-self-mcp.js +28 -0
  192. package/packages/server/dist/ws-triggers.d.ts +29 -0
  193. package/packages/server/dist/ws-triggers.js +261 -0
  194. package/packages/server/dist/ws-turn.d.ts +86 -0
  195. package/packages/server/dist/ws-turn.js +751 -0
  196. package/packages/server/dist/ws.d.ts +62 -0
  197. package/packages/server/dist/ws.js +1024 -0
  198. package/packages/server/package.json +6 -0
  199. package/packages/web/dist/assets/InstanceConfigPage-4cQGTj9Y.js +2 -0
  200. package/packages/web/dist/assets/MarkdownRenderer-CJZFLj_8.js +30 -0
  201. package/packages/web/dist/assets/ProjectRedirect-BHwVbbqB.js +2 -0
  202. package/packages/web/dist/assets/ProjectView-BOvuAITg.js +13 -0
  203. package/packages/web/dist/assets/ProjectsGrid-BCojZOGY.js +2 -0
  204. package/packages/web/dist/assets/arc-BVyxvnkl.js +2 -0
  205. package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-Cd9Puqg1.js +37 -0
  206. package/packages/web/dist/assets/bash-I8pq0VWm.js +2 -0
  207. package/packages/web/dist/assets/blockDiagram-GPEHLZMM-B_AQt_Rx.js +133 -0
  208. package/packages/web/dist/assets/c-D2F1sQUL.js +2 -0
  209. package/packages/web/dist/assets/c4Diagram-AAUBKEIU-7e0TQtXB.js +11 -0
  210. package/packages/web/dist/assets/channel-C_1aISNn.js +2 -0
  211. package/packages/web/dist/assets/chunk-2J33WTMH-Dz4WZmUZ.js +2 -0
  212. package/packages/web/dist/assets/chunk-4BX2VUAB-DVWYldo6.js +2 -0
  213. package/packages/web/dist/assets/chunk-55IACEB6-BIMrizQd.js +2 -0
  214. package/packages/web/dist/assets/chunk-727SXJPM-CL2q9fF1.js +207 -0
  215. package/packages/web/dist/assets/chunk-AQP2D5EJ-BSq3HlQ9.js +232 -0
  216. package/packages/web/dist/assets/chunk-FMBD7UC4-Bgt64pLE.js +16 -0
  217. package/packages/web/dist/assets/chunk-ND2GUHAM-C8Pr2A38.js +2 -0
  218. package/packages/web/dist/assets/chunk-QZHKN3VN-BAOqh-MN.js +2 -0
  219. package/packages/web/dist/assets/classDiagram-4FO5ZUOK-B8JE7cHJ.js +2 -0
  220. package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-B8JE7cHJ.js +2 -0
  221. package/packages/web/dist/assets/core-lJeGACQg.js +4 -0
  222. package/packages/web/dist/assets/cose-bilkent-S5V4N54A-BF4tameA.js +2 -0
  223. package/packages/web/dist/assets/cpp-Bm3ii6kY.js +2 -0
  224. package/packages/web/dist/assets/csharp-BNpuYZMG.js +2 -0
  225. package/packages/web/dist/assets/css-DazXZka4.js +2 -0
  226. package/packages/web/dist/assets/cytoscape.esm-CUqq0XTU.js +332 -0
  227. package/packages/web/dist/assets/dagre-BM42HDAG-DdsLM6ql.js +5 -0
  228. package/packages/web/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
  229. package/packages/web/dist/assets/diagram-2AECGRRQ-BQ78S_RM.js +44 -0
  230. package/packages/web/dist/assets/diagram-5GNKFQAL-CAKE6nHE.js +11 -0
  231. package/packages/web/dist/assets/diagram-KO2AKTUF-fEvHRXgr.js +4 -0
  232. package/packages/web/dist/assets/diagram-LMA3HP47-CtWsgeSm.js +25 -0
  233. package/packages/web/dist/assets/diagram-OG6HWLK6-Buog8k7_.js +25 -0
  234. package/packages/web/dist/assets/erDiagram-TEJ5UH35-CWvVVPZS.js +86 -0
  235. package/packages/web/dist/assets/flowDiagram-I6XJVG4X-DsCGXtp4.js +163 -0
  236. package/packages/web/dist/assets/format-DamJQ9LO.js +2 -0
  237. package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-CsdwIvvC.js +293 -0
  238. package/packages/web/dist/assets/gitGraphDiagram-PVQCEYII-hZvrX1sD.js +107 -0
  239. package/packages/web/dist/assets/go-BPx_y7j8.js +2 -0
  240. package/packages/web/dist/assets/graph-BlwPajkw.js +2 -0
  241. package/packages/web/dist/assets/index-CGbZdrm8.js +71 -0
  242. package/packages/web/dist/assets/index-DJDQ210-.css +1 -0
  243. package/packages/web/dist/assets/infoDiagram-5YYISTIA-nE_Vtz_l.js +3 -0
  244. package/packages/web/dist/assets/ini-B3BVgEsG.js +2 -0
  245. package/packages/web/dist/assets/init-Gi6I4Gst.js +2 -0
  246. package/packages/web/dist/assets/ishikawaDiagram-YF4QCWOH-2Nlqs0oH.js +71 -0
  247. package/packages/web/dist/assets/java-B5VKqtH2.js +2 -0
  248. package/packages/web/dist/assets/javascript-BKRaQes9.js +2 -0
  249. package/packages/web/dist/assets/journeyDiagram-JHISSGLW-mjU1fMc4.js +140 -0
  250. package/packages/web/dist/assets/json-DIYVocXf.js +2 -0
  251. package/packages/web/dist/assets/kanban-definition-UN3LZRKU-C_9xNaa3.js +90 -0
  252. package/packages/web/dist/assets/katex-C5jXJg4s.js +258 -0
  253. package/packages/web/dist/assets/kotlin-Cw-eF_bm.js +3 -0
  254. package/packages/web/dist/assets/lastTab-CU1zsF0j.js +2 -0
  255. package/packages/web/dist/assets/layout-Boy8vhSP.js +2 -0
  256. package/packages/web/dist/assets/linear-BxKd91ho.js +2 -0
  257. package/packages/web/dist/assets/mermaid.core-C-CuhD8I.js +310 -0
  258. package/packages/web/dist/assets/mindmap-definition-RKZ34NQL-Bs6yfcZv.js +97 -0
  259. package/packages/web/dist/assets/ordinal-Cboi1Yqb.js +2 -0
  260. package/packages/web/dist/assets/php-CRdd4dfS.js +3 -0
  261. package/packages/web/dist/assets/pieDiagram-4H26LBE5-DNdqX7O5.js +31 -0
  262. package/packages/web/dist/assets/python-kSlZHhJb.js +2 -0
  263. package/packages/web/dist/assets/quadrantDiagram-W4KKPZXB-ZMJl9OdZ.js +8 -0
  264. package/packages/web/dist/assets/queued-LamEU0GH.js +2 -0
  265. package/packages/web/dist/assets/requirementDiagram-4Y6WPE33-RmxMdm2q.js +85 -0
  266. package/packages/web/dist/assets/ruby-7T4ktxyv.js +2 -0
  267. package/packages/web/dist/assets/rust-HC3MBUhY.js +2 -0
  268. package/packages/web/dist/assets/sankeyDiagram-5OEKKPKP-OAAhWcfK.js +41 -0
  269. package/packages/web/dist/assets/scss-DZLA7YXz.js +2 -0
  270. package/packages/web/dist/assets/sequenceDiagram-3UESZ5HK-BWF7rCyN.js +163 -0
  271. package/packages/web/dist/assets/sql-BC88IN-V.js +2 -0
  272. package/packages/web/dist/assets/stateDiagram-AJRCARHV-M3b_zqqo.js +2 -0
  273. package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CI7saFDa.js +2 -0
  274. package/packages/web/dist/assets/swift-Dn8kKO_1.js +2 -0
  275. package/packages/web/dist/assets/timeline-definition-PNZ67QCA-BpOCh63N.js +121 -0
  276. package/packages/web/dist/assets/typescript-C2FFdlUC.js +2 -0
  277. package/packages/web/dist/assets/vennDiagram-CIIHVFJN-D_iPH45Q.js +35 -0
  278. package/packages/web/dist/assets/wardley-L42UT6IY-DVD9I2Om.js +174 -0
  279. package/packages/web/dist/assets/wardleyDiagram-YWT4CUSO-Bn1IKwjn.js +79 -0
  280. package/packages/web/dist/assets/xml-BXBhIUeX.js +2 -0
  281. package/packages/web/dist/assets/xychartDiagram-2RQKCTM6-DwtI0bkR.js +8 -0
  282. package/packages/web/dist/assets/yaml-drsDnIKT.js +2 -0
  283. package/packages/web/dist/favicon.ico +0 -0
  284. package/packages/web/dist/fonts/inter-latin.woff2 +0 -0
  285. package/packages/web/dist/fonts/jetbrains-mono-latin.woff2 +0 -0
  286. package/packages/web/dist/icons/apple-touch-icon.png +0 -0
  287. package/packages/web/dist/icons/favicon-16.png +0 -0
  288. package/packages/web/dist/icons/favicon-32.png +0 -0
  289. package/packages/web/dist/icons/icon-192.png +0 -0
  290. package/packages/web/dist/icons/icon-512.png +0 -0
  291. package/packages/web/dist/icons/maskable-512.png +0 -0
  292. package/packages/web/dist/index.html +56 -0
  293. package/packages/web/dist/manifest.webmanifest +32 -0
  294. package/packages/web/dist/sw.js +139 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Sweeper curation budgets — the per-file token limits the post-turn curator
3
+ * keeps OVERVIEW.md / CHANGELOG.md / CLAUDE.md under (issue #379), with a
4
+ * per-project override layer (issue #384).
5
+ *
6
+ * ── Config discipline (the `recovery`/`driveMode` pattern) ────────────────────
7
+ * Every budget is an instance default (`PADDOCK_CURATION_*` env, YAML instance
8
+ * file beneath it — resolved in config.ts's `loadCurationConfig`) with an
9
+ * optional PER-PROJECT override (`project.yaml` →
10
+ * {@link import("./projects.js").ProjectYaml.curation}). An absent/invalid
11
+ * override inherits the instance default, resolved at sweep time by
12
+ * {@link resolveCurationConfig} — never baked into the DTO (mirrors how
13
+ * `recovery` resolves via `resolveRecoveryConfig`). A malformed override is
14
+ * ignored rather than fatal so a hand-edited `project.yaml` can't wedge a sweep.
15
+ *
16
+ * #379 shipped these instance-only; #384 adds the override so a docs-heavy
17
+ * project can raise its CHANGELOG budget (or a lean project tighten it) without
18
+ * changing the fleet-wide default.
19
+ */
20
+ /** Built-in defaults when neither env nor YAML nor a project override sets a budget. */
21
+ export const DEFAULT_CURATION = Object.freeze({
22
+ overviewMaxTokens: 2000,
23
+ changelogMaxTokens: 8000,
24
+ claudeMaxTokens: 6000,
25
+ });
26
+ /** True when `n` is a usable budget: a positive, finite integer. */
27
+ function isPositiveInt(n) {
28
+ return typeof n === "number" && Number.isInteger(n) && n > 0 && Number.isFinite(n);
29
+ }
30
+ /**
31
+ * Validate + normalise an untrusted value (from `project.yaml` or a PATCH body)
32
+ * into a {@link CurationOverride}, dropping any field that is missing or invalid,
33
+ * and returning `undefined` when nothing valid remains (so an empty override is
34
+ * never persisted). Each budget must be a positive integer. Defensive by design —
35
+ * a malformed hand-edit degrades to "inherit the instance default", never a
36
+ * sweep crash.
37
+ */
38
+ export function sanitizeCurationOverride(value) {
39
+ if (!value || typeof value !== "object" || Array.isArray(value))
40
+ return undefined;
41
+ const o = value;
42
+ const out = {};
43
+ if (isPositiveInt(o.overviewMaxTokens))
44
+ out.overviewMaxTokens = o.overviewMaxTokens;
45
+ if (isPositiveInt(o.changelogMaxTokens))
46
+ out.changelogMaxTokens = o.changelogMaxTokens;
47
+ if (isPositiveInt(o.claudeMaxTokens))
48
+ out.claudeMaxTokens = o.claudeMaxTokens;
49
+ return Object.keys(out).length > 0 ? out : undefined;
50
+ }
51
+ /**
52
+ * Resolve the effective curation budgets for a sweep: a valid per-project
53
+ * override wins field-by-field; every absent field inherits the instance default
54
+ * (which is itself `env > paddock.config.yaml > built-in default`). The override
55
+ * is re-sanitised so a corrupt on-disk value can't leak through.
56
+ */
57
+ export function resolveCurationConfig(override, instanceDefault) {
58
+ const clean = sanitizeCurationOverride(override) ?? {};
59
+ return {
60
+ overviewMaxTokens: clean.overviewMaxTokens ?? instanceDefault.overviewMaxTokens,
61
+ changelogMaxTokens: clean.changelogMaxTokens ?? instanceDefault.changelogMaxTokens,
62
+ claudeMaxTokens: clean.claudeMaxTokens ?? instanceDefault.claudeMaxTokens,
63
+ };
64
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * In-process lifecycle event bus (Epic G, ticket G1 — hook foundation).
3
+ *
4
+ * Paddock lifecycle events (a chat archived, later: created/forked/unarchived) fire
5
+ * INSIDE Paddock's own server — unlike schedules (Epic D), there is no herdctl seam
6
+ * to add. This tiny typed emitter is that seam: the place that COMMITS a lifecycle
7
+ * action ({@link ArchiveEvent}, from the archive route / the self-MCP archive tool)
8
+ * `emit`s the event AFTER it commits, and the hook dispatcher (wired in `ws.ts`)
9
+ * `on`s it to fire each of the project's enabled hooks via `startAgentTurn`.
10
+ *
11
+ * Two invariants make this safe as a foundation (GG-2, non-blocking after-commit):
12
+ *
13
+ * 1. **`emit` never throws into its caller and never blocks it.** Listeners run
14
+ * fire-and-forget; a listener that throws (sync or async) is swallowed so the
15
+ * triggering action (the archive) can NEVER fail or hang because of a hook. This
16
+ * is the whole point — a buggy hook must not break the thing that triggered it.
17
+ * 2. **The bus event name IS a hook/trigger `event` value.** So a dispatcher is a
18
+ * trivial `bus.on("onArchive", …)` that matches hooks/triggers with that `event`.
19
+ * v1 wired `onArchive` (hooks + event triggers); T5 adds `afterTurn`, which drives
20
+ * the folded-in sweeper (the default post-turn curator trigger).
21
+ *
22
+ * Kept deliberately minimal (no Node `EventEmitter`: its `error`-event footgun and
23
+ * default max-listener warnings are noise here) and dependency-free, matching the
24
+ * hand-rolled sidecar style of the rest of the server.
25
+ */
26
+ /**
27
+ * Payload for the `onArchive` event: which chat, in which project, was archived.
28
+ * The dispatcher passes `slug` to resolve the project's hooks and `sessionId` into
29
+ * the fired hook's prompt so the hook knows WHAT was archived (e.g. which pm server
30
+ * / clone to tear down).
31
+ */
32
+ export interface ArchiveEvent {
33
+ /** The project slug whose chat was archived. */
34
+ slug: string;
35
+ /** The archived chat's session id. */
36
+ sessionId: string;
37
+ }
38
+ /**
39
+ * Payload for the `afterTurn` event (Epic T / T5): a turn just completed in `slug`.
40
+ * Emitted at every post-turn commit site (a human chat turn, a session-mode wake, and
41
+ * every server-initiated `startAgentTurn`) so the folded-in sweeper — the default
42
+ * `curate-overview` `event`/`afterTurn` trigger — dispatches EXACTLY ONCE per turn.
43
+ * `sessionId` is the chat whose turn completed (`null` when none was resolved), carried
44
+ * for parity with `onArchive`; the curator only needs the `slug` to sweep.
45
+ */
46
+ export interface AfterTurnEvent {
47
+ /** The project slug whose chat turn just completed. */
48
+ slug: string;
49
+ /** The completed turn's session id, or `null` if none was resolved. */
50
+ sessionId: string | null;
51
+ }
52
+ /**
53
+ * The typed event map. The bus event name IS a trigger/hook `event` value, so
54
+ * `on`/`emit` line up with the dispatchers. `onArchive` fires the enabled onArchive
55
+ * hooks + event triggers (Epic G/T); `afterTurn` (T5) drives the post-turn curator
56
+ * (the sweeper). Adding a sibling event is: a new value here + its payload + an `emit`
57
+ * at the commit site.
58
+ */
59
+ export interface PaddockEventMap {
60
+ onArchive: ArchiveEvent;
61
+ afterTurn: AfterTurnEvent;
62
+ }
63
+ /** A lifecycle event name — a key of {@link PaddockEventMap}, matching a trigger/hook event. */
64
+ export type PaddockEventName = keyof PaddockEventMap;
65
+ /** A listener for event `E`; may be async — its result is awaited-and-swallowed. */
66
+ export type EventListener<E extends PaddockEventName> = (payload: PaddockEventMap[E]) => void | Promise<void>;
67
+ /**
68
+ * A minimal typed publish/subscribe hub. One instance is constructed in `app.ts` and
69
+ * shared by the commit sites (archive route / self-MCP archive tool → `emit`) and the
70
+ * hook dispatcher in `ws.ts` (→ `on`).
71
+ */
72
+ export declare class PaddockEventBus {
73
+ private readonly listeners;
74
+ /**
75
+ * Subscribe `listener` to `event`. Returns an unsubscribe function. Multiple
76
+ * listeners per event are supported (v1 registers one — the hook dispatcher).
77
+ */
78
+ on<E extends PaddockEventName>(event: E, listener: EventListener<E>): () => void;
79
+ /**
80
+ * Fire `event` to every subscribed listener, FIRE-AND-FORGET. Returns immediately
81
+ * (never awaits a listener) and never throws into the caller — a listener that
82
+ * throws synchronously or rejects asynchronously is swallowed. So the action that
83
+ * emitted the event (an archive commit) is fully decoupled from hook execution: it
84
+ * neither waits on hooks nor fails because of them (GG-2).
85
+ */
86
+ emit<E extends PaddockEventName>(event: E, payload: PaddockEventMap[E]): void;
87
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * A minimal typed publish/subscribe hub. One instance is constructed in `app.ts` and
3
+ * shared by the commit sites (archive route / self-MCP archive tool → `emit`) and the
4
+ * hook dispatcher in `ws.ts` (→ `on`).
5
+ */
6
+ export class PaddockEventBus {
7
+ listeners = new Map();
8
+ /**
9
+ * Subscribe `listener` to `event`. Returns an unsubscribe function. Multiple
10
+ * listeners per event are supported (v1 registers one — the hook dispatcher).
11
+ */
12
+ on(event, listener) {
13
+ let set = this.listeners.get(event);
14
+ if (!set) {
15
+ set = new Set();
16
+ this.listeners.set(event, set);
17
+ }
18
+ set.add(listener);
19
+ return () => {
20
+ this.listeners.get(event)?.delete(listener);
21
+ };
22
+ }
23
+ /**
24
+ * Fire `event` to every subscribed listener, FIRE-AND-FORGET. Returns immediately
25
+ * (never awaits a listener) and never throws into the caller — a listener that
26
+ * throws synchronously or rejects asynchronously is swallowed. So the action that
27
+ * emitted the event (an archive commit) is fully decoupled from hook execution: it
28
+ * neither waits on hooks nor fails because of them (GG-2).
29
+ */
30
+ emit(event, payload) {
31
+ const set = this.listeners.get(event);
32
+ if (!set || set.size === 0)
33
+ return;
34
+ for (const listener of set) {
35
+ try {
36
+ // A listener may be sync or async. Wrap in Promise.resolve so a synchronous
37
+ // throw and an async rejection are both funneled into the same swallow — the
38
+ // emitter's caller is never affected either way.
39
+ void Promise.resolve()
40
+ .then(() => listener(payload))
41
+ .catch(() => undefined);
42
+ }
43
+ catch {
44
+ /* a synchronous throw before the microtask — swallow too */
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Clone an external git repo into `dest` — the checkout that becomes a
3
+ * repo-backed project's working directory (issue #187). Shells out to the `git`
4
+ * binary via execFile (arg array, no shell → no injection surface), the same
5
+ * discipline as {@link GitService}.
6
+ *
7
+ * A FULL clone (not `--depth 1`): a repo-backed project is where you *do
8
+ * engineering*, so the keeper wants real history — `git log`, blame, bisect, and
9
+ * a non-shallow base for branches/PRs — from the start. Credentials are the
10
+ * ambient git environment's job (a public URL needs none; a private repo needs a
11
+ * box-level credential helper / token — per-project scoped credentials are a
12
+ * documented #187 follow-up). Throws with git's stderr on failure so the caller
13
+ * can surface a clean error and roll back the half-created project.
14
+ */
15
+ export declare function cloneRepo(url: string, dest: string): Promise<void>;
16
+ /** A single changed path within a project (porcelain v1 semantics). */
17
+ export interface GitFileChange {
18
+ /** Path relative to the project directory. */
19
+ path: string;
20
+ /** Two-letter porcelain code, trimmed (e.g. "M", "??", "A", "RM"). */
21
+ status: string;
22
+ /** Whether the change is staged (index differs from HEAD). */
23
+ staged: boolean;
24
+ /** True for an untracked ("??") path. */
25
+ untracked: boolean;
26
+ /** Lines added (undefined for a binary change). Untracked text files count as all-added. */
27
+ added?: number;
28
+ /** Lines removed (undefined for a binary change / an untracked file). */
29
+ removed?: number;
30
+ /** True when the change is binary (no line-level stat). */
31
+ binary?: boolean;
32
+ }
33
+ /** A project's git status (or `repo: false` when the store isn't a repo). */
34
+ export interface GitProjectStatus {
35
+ /** Whether `projectsRoot` is a git working tree at all. */
36
+ repo: boolean;
37
+ /** Current branch (omitted when not a repo / detached). */
38
+ branch?: string;
39
+ /** Changes confined to this project's subtree. */
40
+ files: GitFileChange[];
41
+ /** True when the project subtree has no pending changes. */
42
+ clean: boolean;
43
+ }
44
+ export declare class GitService {
45
+ private readonly projectsRoot;
46
+ private readonly author;
47
+ /** Cached repo-detection result for `projectsRoot` (null = not yet checked). */
48
+ private repoFlag;
49
+ /**
50
+ * @param projectsRoot Absolute path to the projects root the service operates on.
51
+ * @param author Commit identity used when Paddock commits on a project's behalf.
52
+ * Folded into PaddockConfig from `PADDOCK_GIT_AUTHOR_*` (issue #269); defaults
53
+ * preserve the pre-fold values so a bare `new GitService(root)` is unchanged.
54
+ */
55
+ constructor(projectsRoot: string, author?: {
56
+ name: string;
57
+ email: string;
58
+ });
59
+ /** Run git in a directory, returning stdout. Throws on non-zero exit. */
60
+ private git;
61
+ /**
62
+ * Whether the backing store is a git working tree. Cached after the first
63
+ * successful check (repo-ness doesn't change under a running server); a thrown
64
+ * git / missing-binary error resolves to `false`.
65
+ */
66
+ isRepo(): Promise<boolean>;
67
+ /** Force the next `isRepo()` to re-check (e.g. after `git init` at runtime). */
68
+ resetRepoCache(): void;
69
+ /**
70
+ * Status for one project's subtree. Returns `{ repo: false }` when the store
71
+ * isn't a repo (the UI then hides the git affordance). Paths are relative to
72
+ * `projectDir`.
73
+ */
74
+ projectStatus(projectDir: string): Promise<GitProjectStatus>;
75
+ /**
76
+ * `git diff --numstat` for a project's tracked working-tree changes, keyed by
77
+ * PROJECT-relative path (`--relative` makes git emit paths relative to the
78
+ * project dir, matching the porcelain paths). Binary changes report `-\t-` and
79
+ * are flagged `binary`. Returns an empty map on any failure.
80
+ */
81
+ private trackedNumstat;
82
+ /**
83
+ * Unified diff for a project's tracked changes (working tree vs HEAD), or for
84
+ * a single file when `file` is given. Untracked files don't appear in a diff
85
+ * (they're listed by `projectStatus`). Returns "" when not a repo / no diff.
86
+ */
87
+ projectDiff(projectDir: string, file?: string): Promise<string>;
88
+ /** Commit identity (from config, no global git config needed). */
89
+ private identity;
90
+ /** Origin remote info + ahead/behind vs upstream (best-effort). */
91
+ remote(): Promise<{
92
+ repo: boolean;
93
+ configured: boolean;
94
+ url?: string;
95
+ branch?: string;
96
+ ahead?: number;
97
+ behind?: number;
98
+ }>;
99
+ /**
100
+ * Stage + commit a single project's changes (tracked mods, deletions, and
101
+ * untracked files within its subtree). `committed: false` when nothing was
102
+ * pending. Explicit identity so the LXC needs no global git config.
103
+ *
104
+ * When `paths` (project-relative) is given, commit ONLY those files — the
105
+ * pathspec scopes both the staging and the commit, so unselected changes stay
106
+ * uncommitted (issue #258). Paths are validated to stay inside the subtree; an
107
+ * all-invalid selection is an error rather than a silent commit-everything.
108
+ * Omitting `paths` keeps the legacy commit-the-whole-subtree behavior.
109
+ */
110
+ commitProject(projectDir: string, message: string, paths?: string[]): Promise<{
111
+ committed: boolean;
112
+ hash?: string;
113
+ error?: string;
114
+ }>;
115
+ /**
116
+ * Uncommitted-file counts per top-level project subtree, in ONE `git status`
117
+ * over the whole store (cheap — no per-project fan-out) so the projects grid
118
+ * can flag "N uncommitted" without opening each project (issue #258). Keyed by
119
+ * the first path segment (= project slug); only dirty projects appear. `{}`
120
+ * when the store isn't a repo.
121
+ */
122
+ dirtyCounts(): Promise<Record<string, number>>;
123
+ /** Push the current branch to origin (sets upstream on first push). */
124
+ push(): Promise<{
125
+ pushed: boolean;
126
+ error?: string;
127
+ }>;
128
+ }