@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.
- package/README.md +69 -0
- package/install-notice.mjs +29 -0
- package/package.json +58 -5
- package/packages/server/dist/adoptable.d.ts +127 -0
- package/packages/server/dist/adoptable.js +315 -0
- package/packages/server/dist/app.d.ts +67 -0
- package/packages/server/dist/app.js +325 -0
- package/packages/server/dist/archive.d.ts +42 -0
- package/packages/server/dist/archive.js +125 -0
- package/packages/server/dist/attachments-config.d.ts +114 -0
- package/packages/server/dist/attachments-config.js +165 -0
- package/packages/server/dist/attachments-hint.d.ts +53 -0
- package/packages/server/dist/attachments-hint.js +140 -0
- package/packages/server/dist/attachments.d.ts +33 -0
- package/packages/server/dist/attachments.js +117 -0
- package/packages/server/dist/auth.d.ts +84 -0
- package/packages/server/dist/auth.js +247 -0
- package/packages/server/dist/background.d.ts +36 -0
- package/packages/server/dist/background.js +137 -0
- package/packages/server/dist/bind-safety.d.ts +56 -0
- package/packages/server/dist/bind-safety.js +51 -0
- package/packages/server/dist/brand.d.ts +44 -0
- package/packages/server/dist/brand.js +88 -0
- package/packages/server/dist/chat-dto.d.ts +210 -0
- package/packages/server/dist/chat-dto.js +308 -0
- package/packages/server/dist/cli/import-chats.d.ts +21 -0
- package/packages/server/dist/cli/import-chats.js +197 -0
- package/packages/server/dist/cli/paddock.d.ts +2 -0
- package/packages/server/dist/cli/paddock.js +247 -0
- package/packages/server/dist/concurrency.d.ts +57 -0
- package/packages/server/dist/concurrency.js +71 -0
- package/packages/server/dist/config.d.ts +538 -0
- package/packages/server/dist/config.js +625 -0
- package/packages/server/dist/curation-config.d.ts +55 -0
- package/packages/server/dist/curation-config.js +64 -0
- package/packages/server/dist/environment-prompt.d.ts +52 -0
- package/packages/server/dist/environment-prompt.js +61 -0
- package/packages/server/dist/event-bus.d.ts +87 -0
- package/packages/server/dist/event-bus.js +48 -0
- package/packages/server/dist/git.d.ts +128 -0
- package/packages/server/dist/git.js +446 -0
- package/packages/server/dist/github-auth.d.ts +44 -0
- package/packages/server/dist/github-auth.js +169 -0
- package/packages/server/dist/herdctl-agent-config.d.ts +98 -0
- package/packages/server/dist/herdctl-agent-config.js +331 -0
- package/packages/server/dist/herdctl-agent-names.d.ts +172 -0
- package/packages/server/dist/herdctl-agent-names.js +228 -0
- package/packages/server/dist/herdctl-jobs-index.d.ts +65 -0
- package/packages/server/dist/herdctl-jobs-index.js +225 -0
- package/packages/server/dist/herdctl-jobs.d.ts +98 -0
- package/packages/server/dist/herdctl-jobs.js +225 -0
- package/packages/server/dist/herdctl.d.ts +623 -0
- package/packages/server/dist/herdctl.js +1279 -0
- package/packages/server/dist/hook-config.d.ts +217 -0
- package/packages/server/dist/hook-config.js +224 -0
- package/packages/server/dist/http-bytes.d.ts +24 -0
- package/packages/server/dist/http-bytes.js +52 -0
- package/packages/server/dist/index.d.ts +1 -0
- package/packages/server/dist/index.js +14 -0
- package/packages/server/dist/instance-config.d.ts +143 -0
- package/packages/server/dist/instance-config.js +385 -0
- package/packages/server/dist/localcommand.d.ts +23 -0
- package/packages/server/dist/localcommand.js +140 -0
- package/packages/server/dist/management-auth.d.ts +99 -0
- package/packages/server/dist/management-auth.js +165 -0
- package/packages/server/dist/management-config.d.ts +164 -0
- package/packages/server/dist/management-config.js +286 -0
- package/packages/server/dist/management-mcp-server.d.ts +20 -0
- package/packages/server/dist/management-mcp-server.js +95 -0
- package/packages/server/dist/management-metadata.d.ts +67 -0
- package/packages/server/dist/management-metadata.js +56 -0
- package/packages/server/dist/management-ops.d.ts +110 -0
- package/packages/server/dist/management-ops.js +449 -0
- package/packages/server/dist/management-policy.d.ts +172 -0
- package/packages/server/dist/management-policy.js +259 -0
- package/packages/server/dist/message-provenance.d.ts +112 -0
- package/packages/server/dist/message-provenance.js +260 -0
- package/packages/server/dist/models.d.ts +164 -0
- package/packages/server/dist/models.js +208 -0
- package/packages/server/dist/openapi.d.ts +66 -0
- package/packages/server/dist/openapi.js +183 -0
- package/packages/server/dist/parent-detach.d.ts +30 -0
- package/packages/server/dist/parent-detach.js +109 -0
- package/packages/server/dist/preload.d.ts +43 -0
- package/packages/server/dist/preload.js +55 -0
- package/packages/server/dist/project-files.d.ts +76 -0
- package/packages/server/dist/project-files.js +191 -0
- package/packages/server/dist/project-mime.d.ts +35 -0
- package/packages/server/dist/project-mime.js +55 -0
- package/packages/server/dist/project-paths.d.ts +88 -0
- package/packages/server/dist/project-paths.js +126 -0
- package/packages/server/dist/project-types.d.ts +316 -0
- package/packages/server/dist/project-types.js +48 -0
- package/packages/server/dist/projects.d.ts +202 -0
- package/packages/server/dist/projects.js +894 -0
- package/packages/server/dist/queued-message.d.ts +35 -0
- package/packages/server/dist/queued-message.js +116 -0
- package/packages/server/dist/read-state.d.ts +46 -0
- package/packages/server/dist/read-state.js +139 -0
- package/packages/server/dist/recovery-config.d.ts +111 -0
- package/packages/server/dist/recovery-config.js +105 -0
- package/packages/server/dist/recovery.d.ts +262 -0
- package/packages/server/dist/recovery.js +490 -0
- package/packages/server/dist/resume-drain.d.ts +122 -0
- package/packages/server/dist/resume-drain.js +158 -0
- package/packages/server/dist/route-context.d.ts +168 -0
- package/packages/server/dist/route-context.js +39 -0
- package/packages/server/dist/route-errors.d.ts +8 -0
- package/packages/server/dist/route-errors.js +13 -0
- package/packages/server/dist/routes/chats.d.ts +12 -0
- package/packages/server/dist/routes/chats.js +1406 -0
- package/packages/server/dist/routes/git.d.ts +13 -0
- package/packages/server/dist/routes/git.js +236 -0
- package/packages/server/dist/routes/mcp.d.ts +83 -0
- package/packages/server/dist/routes/mcp.js +250 -0
- package/packages/server/dist/routes/meta.d.ts +15 -0
- package/packages/server/dist/routes/meta.js +447 -0
- package/packages/server/dist/routes/projects.d.ts +25 -0
- package/packages/server/dist/routes/projects.js +736 -0
- package/packages/server/dist/routes/triggers.d.ts +21 -0
- package/packages/server/dist/routes/triggers.js +324 -0
- package/packages/server/dist/routes/workspace-mount.d.ts +48 -0
- package/packages/server/dist/routes/workspace-mount.js +32 -0
- package/packages/server/dist/routes.d.ts +26 -0
- package/packages/server/dist/routes.js +29 -0
- package/packages/server/dist/run-provenance.d.ts +109 -0
- package/packages/server/dist/run-provenance.js +206 -0
- package/packages/server/dist/runs.d.ts +92 -0
- package/packages/server/dist/runs.js +72 -0
- package/packages/server/dist/schedule-config.d.ts +68 -0
- package/packages/server/dist/schedule-config.js +75 -0
- package/packages/server/dist/schedule-session.d.ts +34 -0
- package/packages/server/dist/schedule-session.js +120 -0
- package/packages/server/dist/self-mcp-descriptions.d.ts +20 -0
- package/packages/server/dist/self-mcp-descriptions.js +145 -0
- package/packages/server/dist/self-mcp-read.d.ts +15 -0
- package/packages/server/dist/self-mcp-read.js +97 -0
- package/packages/server/dist/self-mcp-triggers.d.ts +30 -0
- package/packages/server/dist/self-mcp-triggers.js +144 -0
- package/packages/server/dist/self-mcp-types.d.ts +248 -0
- package/packages/server/dist/self-mcp-types.js +10 -0
- package/packages/server/dist/self-mcp-util.d.ts +73 -0
- package/packages/server/dist/self-mcp-util.js +157 -0
- package/packages/server/dist/self-mcp-write.d.ts +35 -0
- package/packages/server/dist/self-mcp-write.js +215 -0
- package/packages/server/dist/self-mcp.d.ts +95 -0
- package/packages/server/dist/self-mcp.js +448 -0
- package/packages/server/dist/send-file-mcp.d.ts +46 -0
- package/packages/server/dist/send-file-mcp.js +281 -0
- package/packages/server/dist/session-hub.d.ts +186 -0
- package/packages/server/dist/session-hub.js +291 -0
- package/packages/server/dist/spawn-capability.d.ts +99 -0
- package/packages/server/dist/spawn-capability.js +106 -0
- package/packages/server/dist/star.d.ts +26 -0
- package/packages/server/dist/star.js +94 -0
- package/packages/server/dist/start.d.ts +1 -0
- package/packages/server/dist/start.js +21 -0
- package/packages/server/dist/subagents.d.ts +337 -0
- package/packages/server/dist/subagents.js +626 -0
- package/packages/server/dist/sweep.d.ts +122 -0
- package/packages/server/dist/sweep.js +696 -0
- package/packages/server/dist/tooldetails.d.ts +33 -0
- package/packages/server/dist/tooldetails.js +466 -0
- package/packages/server/dist/transcribe.d.ts +69 -0
- package/packages/server/dist/transcribe.js +119 -0
- package/packages/server/dist/transcripts.d.ts +42 -0
- package/packages/server/dist/transcripts.js +164 -0
- package/packages/server/dist/trigger-config.d.ts +278 -0
- package/packages/server/dist/trigger-config.js +417 -0
- package/packages/server/dist/trigger-runtime.d.ts +94 -0
- package/packages/server/dist/trigger-runtime.js +82 -0
- package/packages/server/dist/trigger-session.d.ts +34 -0
- package/packages/server/dist/trigger-session.js +122 -0
- package/packages/server/dist/triggers.d.ts +83 -0
- package/packages/server/dist/triggers.js +124 -0
- package/packages/server/dist/trusted-proxy.d.ts +57 -0
- package/packages/server/dist/trusted-proxy.js +157 -0
- package/packages/server/dist/turn-notice.d.ts +154 -0
- package/packages/server/dist/turn-notice.js +271 -0
- package/packages/server/dist/unread.d.ts +36 -0
- package/packages/server/dist/unread.js +123 -0
- package/packages/server/dist/usage.d.ts +66 -0
- package/packages/server/dist/usage.js +243 -0
- package/packages/server/dist/wake-injection.d.ts +156 -0
- package/packages/server/dist/wake-injection.js +136 -0
- package/packages/server/dist/whisper-local.d.ts +9 -0
- package/packages/server/dist/whisper-local.js +122 -0
- package/packages/server/dist/ws-context.d.ts +158 -0
- package/packages/server/dist/ws-context.js +1 -0
- package/packages/server/dist/ws-protocol.d.ts +423 -0
- package/packages/server/dist/ws-protocol.js +251 -0
- package/packages/server/dist/ws-self-mcp.d.ts +52 -0
- package/packages/server/dist/ws-self-mcp.js +28 -0
- package/packages/server/dist/ws-triggers.d.ts +29 -0
- package/packages/server/dist/ws-triggers.js +261 -0
- package/packages/server/dist/ws-turn.d.ts +86 -0
- package/packages/server/dist/ws-turn.js +751 -0
- package/packages/server/dist/ws.d.ts +62 -0
- package/packages/server/dist/ws.js +1024 -0
- package/packages/server/package.json +6 -0
- package/packages/web/dist/assets/InstanceConfigPage-Bypd_quL.js +2 -0
- package/packages/web/dist/assets/MarkdownRenderer-Co8w9iuX.js +30 -0
- package/packages/web/dist/assets/ProjectRedirect-DXrA24Cy.js +2 -0
- package/packages/web/dist/assets/ProjectView-B9opP7Sv.js +13 -0
- package/packages/web/dist/assets/ProjectsGrid-D2cwb2jY.js +2 -0
- package/packages/web/dist/assets/arc-B--FIRB8.js +2 -0
- package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-B6dRWZZ6.js +37 -0
- package/packages/web/dist/assets/bash-I8pq0VWm.js +2 -0
- package/packages/web/dist/assets/blockDiagram-GPEHLZMM-DLxFAvvf.js +133 -0
- package/packages/web/dist/assets/c-D2F1sQUL.js +2 -0
- package/packages/web/dist/assets/c4Diagram-AAUBKEIU-CNee5ks4.js +11 -0
- package/packages/web/dist/assets/channel-Bw0A52CB.js +2 -0
- package/packages/web/dist/assets/chunk-2J33WTMH-DObw03Xl.js +2 -0
- package/packages/web/dist/assets/chunk-4BX2VUAB-CH2SR6nN.js +2 -0
- package/packages/web/dist/assets/chunk-55IACEB6-WlVpegT3.js +2 -0
- package/packages/web/dist/assets/chunk-727SXJPM-g8GT9Rgd.js +207 -0
- package/packages/web/dist/assets/chunk-AQP2D5EJ-DbN4PsDF.js +232 -0
- package/packages/web/dist/assets/chunk-FMBD7UC4-DSN3BjFG.js +16 -0
- package/packages/web/dist/assets/chunk-ND2GUHAM-D9R4le0z.js +2 -0
- package/packages/web/dist/assets/chunk-QZHKN3VN-D4YgRaKH.js +2 -0
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-itf_kt-q.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-itf_kt-q.js +2 -0
- package/packages/web/dist/assets/core-CysJ2gLj.js +4 -0
- package/packages/web/dist/assets/cose-bilkent-S5V4N54A-D1PB0KNu.js +2 -0
- package/packages/web/dist/assets/cpp-Bm3ii6kY.js +2 -0
- package/packages/web/dist/assets/csharp-BNpuYZMG.js +2 -0
- package/packages/web/dist/assets/css-DazXZka4.js +2 -0
- package/packages/web/dist/assets/cytoscape.esm-CUqq0XTU.js +332 -0
- package/packages/web/dist/assets/dagre-BM42HDAG-C6Uuq-dq.js +5 -0
- package/packages/web/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/packages/web/dist/assets/diagram-2AECGRRQ-C9JvQ425.js +44 -0
- package/packages/web/dist/assets/diagram-5GNKFQAL-Cu6pdh2d.js +11 -0
- package/packages/web/dist/assets/diagram-KO2AKTUF-PmXcUQhY.js +4 -0
- package/packages/web/dist/assets/diagram-LMA3HP47-9ww6_9Iq.js +25 -0
- package/packages/web/dist/assets/diagram-OG6HWLK6-DWQVjv_n.js +25 -0
- package/packages/web/dist/assets/erDiagram-TEJ5UH35-6F7xTuff.js +86 -0
- package/packages/web/dist/assets/flowDiagram-I6XJVG4X-SCiGu7m6.js +163 -0
- package/packages/web/dist/assets/format-yf7Vf9kR.js +2 -0
- package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-BNpPwxkL.js +293 -0
- package/packages/web/dist/assets/gitGraphDiagram-PVQCEYII-C0gyAJjW.js +107 -0
- package/packages/web/dist/assets/go-BPx_y7j8.js +2 -0
- package/packages/web/dist/assets/graph-BlwPajkw.js +2 -0
- package/packages/web/dist/assets/index-B-YuzkF6.js +71 -0
- package/packages/web/dist/assets/index-CvGiQddO.css +1 -0
- package/packages/web/dist/assets/infoDiagram-5YYISTIA-CJ2CFPfy.js +3 -0
- package/packages/web/dist/assets/ini-B3BVgEsG.js +2 -0
- package/packages/web/dist/assets/init-Gi6I4Gst.js +2 -0
- package/packages/web/dist/assets/ishikawaDiagram-YF4QCWOH-Cs0D32Ry.js +71 -0
- package/packages/web/dist/assets/java-B5VKqtH2.js +2 -0
- package/packages/web/dist/assets/javascript-BKRaQes9.js +2 -0
- package/packages/web/dist/assets/journeyDiagram-JHISSGLW-Bc9fuI2i.js +140 -0
- package/packages/web/dist/assets/json-DIYVocXf.js +2 -0
- package/packages/web/dist/assets/kanban-definition-UN3LZRKU-D_tC7QfC.js +90 -0
- package/packages/web/dist/assets/katex-C5jXJg4s.js +258 -0
- package/packages/web/dist/assets/kotlin-Cw-eF_bm.js +3 -0
- package/packages/web/dist/assets/lastTab-CU1zsF0j.js +2 -0
- package/packages/web/dist/assets/layout-Boy8vhSP.js +2 -0
- package/packages/web/dist/assets/linear-BzGHkF9K.js +2 -0
- package/packages/web/dist/assets/mermaid.core-DlbsYzE-.js +310 -0
- package/packages/web/dist/assets/mindmap-definition-RKZ34NQL-Bxeh-ToD.js +97 -0
- package/packages/web/dist/assets/ordinal-Cboi1Yqb.js +2 -0
- package/packages/web/dist/assets/php-CRdd4dfS.js +3 -0
- package/packages/web/dist/assets/pieDiagram-4H26LBE5-CDmilo8S.js +31 -0
- package/packages/web/dist/assets/python-kSlZHhJb.js +2 -0
- package/packages/web/dist/assets/quadrantDiagram-W4KKPZXB-D14-JyE9.js +8 -0
- package/packages/web/dist/assets/queued-LamEU0GH.js +2 -0
- package/packages/web/dist/assets/requirementDiagram-4Y6WPE33-CJ1PUGu-.js +85 -0
- package/packages/web/dist/assets/ruby-7T4ktxyv.js +2 -0
- package/packages/web/dist/assets/rust-HC3MBUhY.js +2 -0
- package/packages/web/dist/assets/sankeyDiagram-5OEKKPKP-BkUK73W0.js +41 -0
- package/packages/web/dist/assets/scss-DZLA7YXz.js +2 -0
- package/packages/web/dist/assets/sequenceDiagram-3UESZ5HK-sbcvsuLp.js +163 -0
- package/packages/web/dist/assets/sql-BC88IN-V.js +2 -0
- package/packages/web/dist/assets/stateDiagram-AJRCARHV-DV-7BdHK.js +2 -0
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-BlkGdXKW.js +2 -0
- package/packages/web/dist/assets/swift-Dn8kKO_1.js +2 -0
- package/packages/web/dist/assets/timeline-definition-PNZ67QCA-C5su21G_.js +121 -0
- package/packages/web/dist/assets/typescript-C2FFdlUC.js +2 -0
- package/packages/web/dist/assets/vennDiagram-CIIHVFJN-JNkIJAaQ.js +35 -0
- package/packages/web/dist/assets/wardley-L42UT6IY-qcz6t2vR.js +174 -0
- package/packages/web/dist/assets/wardleyDiagram-YWT4CUSO-CMrOIZ-c.js +79 -0
- package/packages/web/dist/assets/xml-BXBhIUeX.js +2 -0
- package/packages/web/dist/assets/xychartDiagram-2RQKCTM6-C9q6Oy9u.js +8 -0
- package/packages/web/dist/assets/yaml-drsDnIKT.js +2 -0
- package/packages/web/dist/favicon.ico +0 -0
- package/packages/web/dist/fonts/inter-latin.woff2 +0 -0
- package/packages/web/dist/fonts/jetbrains-mono-latin.woff2 +0 -0
- package/packages/web/dist/icons/apple-touch-icon.png +0 -0
- package/packages/web/dist/icons/favicon-16.png +0 -0
- package/packages/web/dist/icons/favicon-32.png +0 -0
- package/packages/web/dist/icons/icon-192.png +0 -0
- package/packages/web/dist/icons/icon-512.png +0 -0
- package/packages/web/dist/icons/maskable-512.png +0 -0
- package/packages/web/dist/index.html +56 -0
- package/packages/web/dist/manifest.webmanifest +32 -0
- package/packages/web/dist/sw.js +139 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the Paddock self-management MCP (issue #214).
|
|
3
|
+
*
|
|
4
|
+
* The agent-facing DTOs (`SelfMcpProject`/`SelfMcpChat`/`SelfMcpMessage`/
|
|
5
|
+
* `SelfMcpTrigger`) plus the two per-turn context bags (`SelfMcpContext` read-side,
|
|
6
|
+
* `SelfMcpWriteContext` write-side) the caller wires to ProjectStore/HerdctlService.
|
|
7
|
+
* Pure declarations — no runtime code — re-exported from `self-mcp.ts` so existing
|
|
8
|
+
* importers keep working.
|
|
9
|
+
*/
|
|
10
|
+
/** A project as surfaced to the agent. */
|
|
11
|
+
export interface SelfMcpProject {
|
|
12
|
+
slug: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** The project's area ("Unsorted" when empty); omitted when blank. */
|
|
15
|
+
area?: string;
|
|
16
|
+
status: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The arguments `create_project` passes through to the create path (issue #467) —
|
|
20
|
+
* the subset of {@link import("./project-types.js").CreateProjectInput} the tool
|
|
21
|
+
* exposes, already trimmed + shape-validated by the handler. Deliberately a local
|
|
22
|
+
* declaration (not an import of `CreateProjectInput`) so this module keeps zero
|
|
23
|
+
* runtime coupling; the caller widens it back to the real input at the boundary.
|
|
24
|
+
*/
|
|
25
|
+
export interface SelfMcpCreateProjectInput {
|
|
26
|
+
name: string;
|
|
27
|
+
/** Explicit kebab-case slug; absent ⇒ the store derives one from `name`. */
|
|
28
|
+
slug?: string;
|
|
29
|
+
/** Git URL ⇒ a REPO-BACKED project (#187): cloned into a nested checkout. */
|
|
30
|
+
repo?: string;
|
|
31
|
+
summary?: string;
|
|
32
|
+
/** The project's area (persisted as `group`; `list_projects` reports it as `area`). */
|
|
33
|
+
group?: string;
|
|
34
|
+
status?: string;
|
|
35
|
+
}
|
|
36
|
+
/** A newly-created project as surfaced back to the agent (issue #467). */
|
|
37
|
+
export interface SelfMcpCreatedProject {
|
|
38
|
+
slug: string;
|
|
39
|
+
name: string;
|
|
40
|
+
/** The project's metadata dir (OVERVIEW/CHANGELOG/`.chats` live here). */
|
|
41
|
+
dir: string;
|
|
42
|
+
/** The keeper's cwd — the nested checkout when repo-backed, else `dir`. */
|
|
43
|
+
workingDir: string;
|
|
44
|
+
/** Whether the project is backed by a cloned external repo (#187). */
|
|
45
|
+
repoBacked: boolean;
|
|
46
|
+
/** The repo URL when repo-backed, else undefined. */
|
|
47
|
+
repo?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Whether the keeper agent registered. The REST create path treats a registration
|
|
50
|
+
* failure as non-fatal (the project IS created), so this mirrors it — but reports
|
|
51
|
+
* it, because a project with no live keeper can't take a `create_chat` yet.
|
|
52
|
+
*/
|
|
53
|
+
agentRegistered: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** A chat as surfaced to the agent. */
|
|
56
|
+
export interface SelfMcpChat {
|
|
57
|
+
/** Owning project slug. */
|
|
58
|
+
project: string;
|
|
59
|
+
sessionId: string;
|
|
60
|
+
/** Display name (custom name, else auto-name, else a short id). */
|
|
61
|
+
name: string;
|
|
62
|
+
/** ISO timestamp of the last transcript write (mtime). */
|
|
63
|
+
updatedAt: string;
|
|
64
|
+
/** Whether a turn is currently in flight for this chat. */
|
|
65
|
+
running: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Whether the chat is filed away in the UI's "Archived" section (#489). Always
|
|
68
|
+
* present — `list_chats` hides archived chats by default, so the flag is what
|
|
69
|
+
* lets a caller that passed `include_archived: true` tell the two apart, and it
|
|
70
|
+
* mirrors the REST DTO (`chat-dto.ts`), which has always carried it.
|
|
71
|
+
*/
|
|
72
|
+
archived: boolean;
|
|
73
|
+
}
|
|
74
|
+
/** One transcript message as surfaced to the agent. */
|
|
75
|
+
export interface SelfMcpMessage {
|
|
76
|
+
role: "user" | "assistant" | "tool";
|
|
77
|
+
text: string;
|
|
78
|
+
timestamp: string;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A unified project TRIGGER as surfaced to the agent (Epic T "Unify Triggers" / T3
|
|
82
|
+
* — the successor that collapses `SelfMcpSchedule` + `SelfMcpHook`). Flattens the
|
|
83
|
+
* persisted {@link import("./trigger-config.js").TriggerDto} — the discriminated
|
|
84
|
+
* `trigger` (WHEN: `schedule|event|webhook`) + the shared `run` (WHAT) + `enabled`
|
|
85
|
+
* — plus the `trigger-<slug>-<name>` agent an event/webhook trigger registers as.
|
|
86
|
+
* Nested `trigger`/`run` fields are flattened + null-normalised so the agent reads
|
|
87
|
+
* ONE flat record regardless of type. For a `schedule` trigger, best-effort live
|
|
88
|
+
* runtime state (`status`/`lastRunAt`/`nextRunAt`/`lastError`) is merged in when the
|
|
89
|
+
* keeper has armed it (absent otherwise — and always absent for event/webhook).
|
|
90
|
+
*/
|
|
91
|
+
export interface SelfMcpTrigger {
|
|
92
|
+
/** The trigger's stable key (the `project.yaml` map key + `<name>` in its agent). */
|
|
93
|
+
name: string;
|
|
94
|
+
/** The herdctl agent an event/webhook trigger registers as (`trigger-<slug>-<name>`). */
|
|
95
|
+
agentName: string;
|
|
96
|
+
/** WHEN: the discriminant — `schedule` (cron/interval), `event` (on), or `webhook` (path). */
|
|
97
|
+
type: "schedule" | "event" | "webhook";
|
|
98
|
+
/** The cron expression (schedule), else null. */
|
|
99
|
+
cron: string | null;
|
|
100
|
+
/** The interval string (schedule), else null. */
|
|
101
|
+
interval: string | null;
|
|
102
|
+
/** The lifecycle event this fires on (event trigger, e.g. `onArchive`), else null. */
|
|
103
|
+
event: string | null;
|
|
104
|
+
/** The ingress path (webhook trigger — reserved, unbuilt), else null. */
|
|
105
|
+
path: string | null;
|
|
106
|
+
/** WHAT: the inline prompt, or null when a `promptFile` drives it. */
|
|
107
|
+
prompt: string | null;
|
|
108
|
+
/** The `.paddock/triggers/` prompt-file name, or null. */
|
|
109
|
+
promptFile: string | null;
|
|
110
|
+
/** `new` = a fresh chat each fire; `resume` = one owned accreting session. */
|
|
111
|
+
session: "new" | "resume";
|
|
112
|
+
/** The tools the fired agent may use (its capability grant); `[]` = tool-less. */
|
|
113
|
+
tools: string[];
|
|
114
|
+
/** Recursion bound for internal spawning (0 = may not spawn), or null (default). */
|
|
115
|
+
maxSpawnDepth: number | null;
|
|
116
|
+
/** The permission mode the fired agent's turns run under, or null (fleet default). */
|
|
117
|
+
permissionMode: string | null;
|
|
118
|
+
/** Model override for the fired agent, or null (keeper default). */
|
|
119
|
+
model: string | null;
|
|
120
|
+
/** Max agent turns bounding a runaway trigger, or null (trigger default). */
|
|
121
|
+
maxTurns: number | null;
|
|
122
|
+
/** Whether the trigger is armed. New triggers default `false` (GG-3). */
|
|
123
|
+
enabled: boolean;
|
|
124
|
+
/** Live status for an armed schedule trigger (`idle`/`running`/`disabled`), else null. */
|
|
125
|
+
status?: string | null;
|
|
126
|
+
/** ISO time of the last fire (schedule trigger), or null. */
|
|
127
|
+
lastRunAt?: string | null;
|
|
128
|
+
/** ISO time of the next scheduled fire (schedule trigger), or null. */
|
|
129
|
+
nextRunAt?: string | null;
|
|
130
|
+
/** The last fire's error message (schedule trigger), or null. */
|
|
131
|
+
lastError?: string | null;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Per-turn context: narrow async callbacks the caller wires to the real stores.
|
|
135
|
+
* `readChat` returns the FULL ordered message list; this module applies the
|
|
136
|
+
* tail/limit + per-message truncation so that logic stays testable here.
|
|
137
|
+
*/
|
|
138
|
+
export interface SelfMcpContext {
|
|
139
|
+
listProjects: () => Promise<SelfMcpProject[]>;
|
|
140
|
+
listChats: (projectSlug?: string) => Promise<SelfMcpChat[]>;
|
|
141
|
+
readChat: (projectSlug: string, sessionId: string) => Promise<SelfMcpMessage[]>;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Write-side per-turn context. Present only when the write flag is on. These
|
|
145
|
+
* callbacks START real keeper turns; this module only validates/normalizes args
|
|
146
|
+
* and delegates. The caller wires them to HerdctlService/ProjectStore.
|
|
147
|
+
*
|
|
148
|
+
* NOTE (guard-ready): these write tools deliberately have NO recursion/depth
|
|
149
|
+
* guard in this phase (per the product owner) — a keeper can create/fork chats
|
|
150
|
+
* that themselves have the self-MCP injected. The injection path is intentionally
|
|
151
|
+
* left guard-ready: a later phase can thread a depth/origin marker through the
|
|
152
|
+
* caller-supplied callbacks below without changing this module's shape.
|
|
153
|
+
*/
|
|
154
|
+
export interface SelfMcpWriteContext {
|
|
155
|
+
/** Slug of the project the calling keeper is in (fork/create default target). */
|
|
156
|
+
currentProjectSlug: string;
|
|
157
|
+
/** Resolved sessionId of the CURRENT chat, or null if not yet known this turn. */
|
|
158
|
+
currentSessionId: () => string | null;
|
|
159
|
+
/**
|
|
160
|
+
* Start a brand-new chat in `projectSlug` kicked off with `prompt`. Returns its
|
|
161
|
+
* new sessionId. `opts.model` (issue #336) is a per-chat model override for the
|
|
162
|
+
* spawned chat's kickoff turn ONLY — already validated against the picker
|
|
163
|
+
* allow-list by the handler; absent ⇒ inherit the project/box default.
|
|
164
|
+
*/
|
|
165
|
+
createChat: (projectSlug: string, prompt: string, opts?: {
|
|
166
|
+
name?: string;
|
|
167
|
+
preloadContext?: boolean;
|
|
168
|
+
model?: string;
|
|
169
|
+
}) => Promise<{
|
|
170
|
+
sessionId: string;
|
|
171
|
+
}>;
|
|
172
|
+
/**
|
|
173
|
+
* Eager-fork `sourceSessionId` (in `projectSlug`) into a new chat, optionally
|
|
174
|
+
* kicked off with `prompt`. Returns the new sessionId. `model` (issue #336) is a
|
|
175
|
+
* per-chat override applied to the kickoff turn ONLY (a fork with no `prompt`
|
|
176
|
+
* runs no turn, so a `model` without a `prompt` has no effect); absent ⇒ inherit
|
|
177
|
+
* the project/box default.
|
|
178
|
+
*/
|
|
179
|
+
forkChat: (args: {
|
|
180
|
+
projectSlug: string;
|
|
181
|
+
sourceSessionId: string;
|
|
182
|
+
prompt?: string;
|
|
183
|
+
name?: string;
|
|
184
|
+
model?: string;
|
|
185
|
+
}) => Promise<{
|
|
186
|
+
sessionId: string;
|
|
187
|
+
}>;
|
|
188
|
+
/** Send `prompt` as a new turn to an existing chat. */
|
|
189
|
+
sendMessage: (projectSlug: string, sessionId: string, prompt: string) => Promise<void>;
|
|
190
|
+
/** Set (or clear) a chat's archived flag (presentational metadata only). */
|
|
191
|
+
setArchived: (projectSlug: string, sessionId: string, archived: boolean) => Promise<void>;
|
|
192
|
+
/**
|
|
193
|
+
* Whether the PROJECT tools (`create_project`, issue #467) are enabled for this
|
|
194
|
+
* instance — the `selfMcpProjectsEnabled` gate, resolved by the caller. When false
|
|
195
|
+
* the tool is NOT injected at all (absent, not present-but-refusing), the same
|
|
196
|
+
* binary discipline as {@link triggersMcpEnabled}.
|
|
197
|
+
*/
|
|
198
|
+
projectsMcpEnabled: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Provision a whole new project and register its keeper agent — the SAME two steps
|
|
201
|
+
* `POST /api/projects` performs, in the same order (`ProjectStore.create` then
|
|
202
|
+
* `ensureProjectAgent`), so the REST and MCP paths cannot drift. All the real work
|
|
203
|
+
* (slug/repo validation, `project.yaml`, seeded CHANGELOG/CLAUDE.md, the #187
|
|
204
|
+
* repo-backed clone into a nested `.gitignore`d checkout WITH rollback on failure)
|
|
205
|
+
* stays in the store. Throws on a create failure; a keeper-registration failure is
|
|
206
|
+
* non-fatal (mirroring the route) and reported via `agentRegistered`.
|
|
207
|
+
*/
|
|
208
|
+
createProject: (input: SelfMcpCreateProjectInput) => Promise<SelfMcpCreatedProject>;
|
|
209
|
+
/**
|
|
210
|
+
* Whether the unified trigger-management MCP is enabled for THIS turn's project
|
|
211
|
+
* (Epic T / T3 — the successor to the G5 hook-MCP gate, resolved from the SAME
|
|
212
|
+
* per-project `hooksMcpEnabled` opt-in against the instance default; the gate is
|
|
213
|
+
* REUSED, not reinvented). When false the trigger tools (`list_triggers`/
|
|
214
|
+
* `set_trigger`/`remove_trigger`) are NOT injected at all (absent, not present-
|
|
215
|
+
* but-refusing) — the design's binary "does this project agent get the trigger
|
|
216
|
+
* MCP at all" gate. The caller resolves this per project (see
|
|
217
|
+
* {@link import("./hook-config.js").resolveHooksMcpEnabled}).
|
|
218
|
+
*/
|
|
219
|
+
triggersMcpEnabled: boolean;
|
|
220
|
+
/**
|
|
221
|
+
* List a project's unified triggers (Epic T / T3). Read-only; reads the live
|
|
222
|
+
* project record (merging best-effort schedule runtime state). Present regardless
|
|
223
|
+
* of {@link triggersMcpEnabled} on the context, but the tools are only injected
|
|
224
|
+
* when that flag is on.
|
|
225
|
+
*/
|
|
226
|
+
listTriggers: (projectSlug: string) => Promise<SelfMcpTrigger[]>;
|
|
227
|
+
/**
|
|
228
|
+
* Create or update a trigger (keyed by `name`) — persists to `project.yaml`'s
|
|
229
|
+
* single `triggers` block and arms it. `trigger` is a PARTIAL structured record
|
|
230
|
+
* (`{ trigger?, run?, enabled? }`, camelCase) the caller merges over the existing
|
|
231
|
+
* trigger (via `mergeTriggerUpdate`) then validates + sanitises (throwing on a
|
|
232
|
+
* malformed record), defaulting a brand-new trigger to `enabled: false` (GG-3).
|
|
233
|
+
* Enable/disable is just this call with `enabled` flipped (GG-3) — no separate
|
|
234
|
+
* verb. Returns the saved trigger.
|
|
235
|
+
*/
|
|
236
|
+
setTrigger: (projectSlug: string, name: string, trigger: Record<string, unknown>) => Promise<SelfMcpTrigger>;
|
|
237
|
+
/**
|
|
238
|
+
* Remove a trigger by `name` — persisted removal + disarming its agent/schedule.
|
|
239
|
+
* Returns `true` when a trigger existed, `false` when it was already absent.
|
|
240
|
+
*/
|
|
241
|
+
removeTrigger: (projectSlug: string, name: string) => Promise<boolean>;
|
|
242
|
+
/**
|
|
243
|
+
* Fire a trigger by `name` NOW (Epic T follow-up / #327) — through the same hub
|
|
244
|
+
* path a cron / event fire uses. Returns the started chat's sessionId, or `null` if
|
|
245
|
+
* the project/trigger is gone or the turn never produced a session.
|
|
246
|
+
*/
|
|
247
|
+
runTrigger: (projectSlug: string, name: string) => Promise<string | null>;
|
|
248
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type declarations for the Paddock self-management MCP (issue #214).
|
|
3
|
+
*
|
|
4
|
+
* The agent-facing DTOs (`SelfMcpProject`/`SelfMcpChat`/`SelfMcpMessage`/
|
|
5
|
+
* `SelfMcpTrigger`) plus the two per-turn context bags (`SelfMcpContext` read-side,
|
|
6
|
+
* `SelfMcpWriteContext` write-side) the caller wires to ProjectStore/HerdctlService.
|
|
7
|
+
* Pure declarations — no runtime code — re-exported from `self-mcp.ts` so existing
|
|
8
|
+
* importers keep working.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers + numeric caps for the Paddock self-management MCP (issue #214).
|
|
3
|
+
*
|
|
4
|
+
* These are the deliberately-testable primitives the handler factories build on:
|
|
5
|
+
* the `ok`/`fail` result envelopes, `errText` normalisation, the read_chat
|
|
6
|
+
* tail/limit + per-message truncation clamps, and the arg-coercion helpers that
|
|
7
|
+
* tolerate the CLI-runtime MCP transport dropping array-typed args. Several are
|
|
8
|
+
* unit-test-exported and re-exported from `self-mcp.ts` for the public surface.
|
|
9
|
+
*/
|
|
10
|
+
import type { McpToolCallResult } from "@herdctl/core";
|
|
11
|
+
/** fork_chat_batch: hard cap on how many forks a single fan-out call may spawn. */
|
|
12
|
+
export declare const FORK_BATCH_MAX = 20;
|
|
13
|
+
/** read_chat: default and hard-cap on how many trailing messages to return. */
|
|
14
|
+
export declare const READ_CHAT_DEFAULT_LIMIT = 30;
|
|
15
|
+
export declare const READ_CHAT_MAX_LIMIT = 200;
|
|
16
|
+
/** read_chat: per-message character cap so one huge message can't flood the result. */
|
|
17
|
+
export declare const READ_CHAT_MAX_TEXT = 2000;
|
|
18
|
+
export declare function ok(payload: unknown): McpToolCallResult;
|
|
19
|
+
export declare function fail(text: string): McpToolCallResult;
|
|
20
|
+
export declare function errText(error: unknown): string;
|
|
21
|
+
/**
|
|
22
|
+
* Strip server filesystem paths out of an error message before it reaches the agent
|
|
23
|
+
* (issue #467). Motivating case: `create_project` on an unreachable repo surfaces
|
|
24
|
+
* git's failure through `promisify(execFile)`, whose message is the WHOLE argv —
|
|
25
|
+
* `Command failed: git clone -- <url> /srv/data/projects/foo/foo` — i.e. the server's
|
|
26
|
+
* internal layout. The repo URL is the actionable part and is preserved (URLs are
|
|
27
|
+
* skipped by {@link ABS_PATH_RE}); bare absolute paths become `<path>`.
|
|
28
|
+
*
|
|
29
|
+
* A hygiene measure, not a security boundary: a keeper can see its own cwd anyway.
|
|
30
|
+
* The point is that a tool error reads as a clean, actionable message rather than a
|
|
31
|
+
* raw subprocess dump — the same cleanup applied to the other write tools' errors.
|
|
32
|
+
*/
|
|
33
|
+
export declare function redactPaths(text: string): string;
|
|
34
|
+
/** Clamp a caller-supplied limit into [1, MAX], defaulting when absent/invalid. */
|
|
35
|
+
export declare function clampLimit(raw: unknown): number;
|
|
36
|
+
/**
|
|
37
|
+
* Normalize a BOOLEAN tool argument, defaulting when absent/unusable. A real
|
|
38
|
+
* boolean is taken as-is; `"true"`/`"false"` (any case, padded) are accepted too
|
|
39
|
+
* because the CLI-runtime MCP transport has proven lossy with non-string args
|
|
40
|
+
* (see {@link coercePrompts}) — the same defensive parse, one type down. Anything
|
|
41
|
+
* else falls back rather than erroring: a mistyped flag shouldn't fail a read.
|
|
42
|
+
*/
|
|
43
|
+
export declare function coerceBoolean(raw: unknown, fallback: boolean): boolean;
|
|
44
|
+
/** Truncate a single message's text with an explicit marker. */
|
|
45
|
+
export declare function truncateText(text: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Validate the optional `model` argument on the spawn tools (create_chat /
|
|
48
|
+
* fork_chat / fork_chat_batch, issue #336) against the SAME picker allow-list the
|
|
49
|
+
* web model-picker uses ({@link isKnownModel}). Returns `{}` when absent/blank (the
|
|
50
|
+
* spawned chat inherits the project/box default, the unchanged behaviour), `{ model }`
|
|
51
|
+
* for a recognised id, or an error STRING (listing the valid ids) for a non-blank
|
|
52
|
+
* unknown id — the handler turns that into an `isError` tool result so the agent
|
|
53
|
+
* gets an actionable message rather than a silently-ignored override.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveModelArg(raw: unknown): {
|
|
56
|
+
model?: string;
|
|
57
|
+
} | string;
|
|
58
|
+
/**
|
|
59
|
+
* Normalize the `prompts` argument to a string array. The CLI-runtime MCP path
|
|
60
|
+
* has proven unreliable at carrying an ARRAY-typed argument to the tool handler
|
|
61
|
+
* (string args work; the array arrives dropped) — so we ALSO accept the list as a
|
|
62
|
+
* string: a JSON array (`["a","b"]`) or newline-separated directives. Returns []
|
|
63
|
+
* when nothing usable is present (handler then reports the required-arg error).
|
|
64
|
+
*/
|
|
65
|
+
export declare function coercePrompts(raw: unknown): string[];
|
|
66
|
+
/**
|
|
67
|
+
* Normalize a tool-list argument (a hook's `allowed_tools`/`denied_tools`) to a
|
|
68
|
+
* string array. Like {@link coercePrompts}, tolerant of the CLI-runtime MCP
|
|
69
|
+
* transport dropping ARRAY-typed args: accepts a real array, a JSON array string,
|
|
70
|
+
* or a comma/newline-separated string (tool names never contain commas). Blanks
|
|
71
|
+
* are dropped; returns [] when nothing usable is present (a tool-less hook).
|
|
72
|
+
*/
|
|
73
|
+
export declare function coerceToolList(raw: unknown): string[];
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { MODELS, isKnownModel } from "./models.js";
|
|
2
|
+
/** fork_chat_batch: hard cap on how many forks a single fan-out call may spawn. */
|
|
3
|
+
export const FORK_BATCH_MAX = 20;
|
|
4
|
+
/** read_chat: default and hard-cap on how many trailing messages to return. */
|
|
5
|
+
export const READ_CHAT_DEFAULT_LIMIT = 30;
|
|
6
|
+
export const READ_CHAT_MAX_LIMIT = 200;
|
|
7
|
+
/** read_chat: per-message character cap so one huge message can't flood the result. */
|
|
8
|
+
export const READ_CHAT_MAX_TEXT = 2000;
|
|
9
|
+
export function ok(payload) {
|
|
10
|
+
return { content: [{ type: "text", text: JSON.stringify(payload) }] };
|
|
11
|
+
}
|
|
12
|
+
export function fail(text) {
|
|
13
|
+
return { content: [{ type: "text", text }], isError: true };
|
|
14
|
+
}
|
|
15
|
+
export function errText(error) {
|
|
16
|
+
return error instanceof Error ? error.message : String(error);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Absolute POSIX paths of two-or-more segments (`/var/lib/paddock/projects/x`), NOT
|
|
20
|
+
* preceded by `:` or `/` so the path component of a URL (`https://host/owner/repo`)
|
|
21
|
+
* is left alone. Used by {@link redactPaths}.
|
|
22
|
+
*/
|
|
23
|
+
const ABS_PATH_RE = /(?<![:/\w])\/[\w.@%+-]+(?:\/[\w.@%+-]+)+\/?/g;
|
|
24
|
+
/**
|
|
25
|
+
* Strip server filesystem paths out of an error message before it reaches the agent
|
|
26
|
+
* (issue #467). Motivating case: `create_project` on an unreachable repo surfaces
|
|
27
|
+
* git's failure through `promisify(execFile)`, whose message is the WHOLE argv —
|
|
28
|
+
* `Command failed: git clone -- <url> /srv/data/projects/foo/foo` — i.e. the server's
|
|
29
|
+
* internal layout. The repo URL is the actionable part and is preserved (URLs are
|
|
30
|
+
* skipped by {@link ABS_PATH_RE}); bare absolute paths become `<path>`.
|
|
31
|
+
*
|
|
32
|
+
* A hygiene measure, not a security boundary: a keeper can see its own cwd anyway.
|
|
33
|
+
* The point is that a tool error reads as a clean, actionable message rather than a
|
|
34
|
+
* raw subprocess dump — the same cleanup applied to the other write tools' errors.
|
|
35
|
+
*/
|
|
36
|
+
export function redactPaths(text) {
|
|
37
|
+
return text.replace(ABS_PATH_RE, "<path>");
|
|
38
|
+
}
|
|
39
|
+
/** Clamp a caller-supplied limit into [1, MAX], defaulting when absent/invalid. */
|
|
40
|
+
export function clampLimit(raw) {
|
|
41
|
+
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
42
|
+
return READ_CHAT_DEFAULT_LIMIT;
|
|
43
|
+
const n = Math.floor(raw);
|
|
44
|
+
if (n < 1)
|
|
45
|
+
return 1;
|
|
46
|
+
if (n > READ_CHAT_MAX_LIMIT)
|
|
47
|
+
return READ_CHAT_MAX_LIMIT;
|
|
48
|
+
return n;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Normalize a BOOLEAN tool argument, defaulting when absent/unusable. A real
|
|
52
|
+
* boolean is taken as-is; `"true"`/`"false"` (any case, padded) are accepted too
|
|
53
|
+
* because the CLI-runtime MCP transport has proven lossy with non-string args
|
|
54
|
+
* (see {@link coercePrompts}) — the same defensive parse, one type down. Anything
|
|
55
|
+
* else falls back rather than erroring: a mistyped flag shouldn't fail a read.
|
|
56
|
+
*/
|
|
57
|
+
export function coerceBoolean(raw, fallback) {
|
|
58
|
+
if (typeof raw === "boolean")
|
|
59
|
+
return raw;
|
|
60
|
+
if (typeof raw === "string") {
|
|
61
|
+
const s = raw.trim().toLowerCase();
|
|
62
|
+
if (s === "true")
|
|
63
|
+
return true;
|
|
64
|
+
if (s === "false")
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return fallback;
|
|
68
|
+
}
|
|
69
|
+
/** Truncate a single message's text with an explicit marker. */
|
|
70
|
+
export function truncateText(text) {
|
|
71
|
+
if (text.length <= READ_CHAT_MAX_TEXT)
|
|
72
|
+
return text;
|
|
73
|
+
const omitted = text.length - READ_CHAT_MAX_TEXT;
|
|
74
|
+
return `${text.slice(0, READ_CHAT_MAX_TEXT)}… [truncated ${omitted} chars]`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate the optional `model` argument on the spawn tools (create_chat /
|
|
78
|
+
* fork_chat / fork_chat_batch, issue #336) against the SAME picker allow-list the
|
|
79
|
+
* web model-picker uses ({@link isKnownModel}). Returns `{}` when absent/blank (the
|
|
80
|
+
* spawned chat inherits the project/box default, the unchanged behaviour), `{ model }`
|
|
81
|
+
* for a recognised id, or an error STRING (listing the valid ids) for a non-blank
|
|
82
|
+
* unknown id — the handler turns that into an `isError` tool result so the agent
|
|
83
|
+
* gets an actionable message rather than a silently-ignored override.
|
|
84
|
+
*/
|
|
85
|
+
export function resolveModelArg(raw) {
|
|
86
|
+
if (typeof raw !== "string")
|
|
87
|
+
return {};
|
|
88
|
+
const m = raw.trim();
|
|
89
|
+
if (m.length === 0)
|
|
90
|
+
return {};
|
|
91
|
+
if (!isKnownModel(m)) {
|
|
92
|
+
return `Error: unknown model "${m}". Valid models: ${MODELS.map((x) => x.id).join(", ")}.`;
|
|
93
|
+
}
|
|
94
|
+
return { model: m };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Normalize the `prompts` argument to a string array. The CLI-runtime MCP path
|
|
98
|
+
* has proven unreliable at carrying an ARRAY-typed argument to the tool handler
|
|
99
|
+
* (string args work; the array arrives dropped) — so we ALSO accept the list as a
|
|
100
|
+
* string: a JSON array (`["a","b"]`) or newline-separated directives. Returns []
|
|
101
|
+
* when nothing usable is present (handler then reports the required-arg error).
|
|
102
|
+
*/
|
|
103
|
+
export function coercePrompts(raw) {
|
|
104
|
+
if (Array.isArray(raw)) {
|
|
105
|
+
return raw.map((p) => (typeof p === "string" ? p : "")).map((p) => p.trim());
|
|
106
|
+
}
|
|
107
|
+
if (typeof raw === "string") {
|
|
108
|
+
const s = raw.trim();
|
|
109
|
+
if (s.length === 0)
|
|
110
|
+
return [];
|
|
111
|
+
if (s.startsWith("[")) {
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(s);
|
|
114
|
+
if (Array.isArray(parsed)) {
|
|
115
|
+
return parsed.map((p) => (typeof p === "string" ? p : "")).map((p) => p.trim());
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
/* fall through to newline split */
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return s
|
|
123
|
+
.split("\n")
|
|
124
|
+
.map((line) => line.trim())
|
|
125
|
+
.filter((line) => line.length > 0);
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Normalize a tool-list argument (a hook's `allowed_tools`/`denied_tools`) to a
|
|
131
|
+
* string array. Like {@link coercePrompts}, tolerant of the CLI-runtime MCP
|
|
132
|
+
* transport dropping ARRAY-typed args: accepts a real array, a JSON array string,
|
|
133
|
+
* or a comma/newline-separated string (tool names never contain commas). Blanks
|
|
134
|
+
* are dropped; returns [] when nothing usable is present (a tool-less hook).
|
|
135
|
+
*/
|
|
136
|
+
export function coerceToolList(raw) {
|
|
137
|
+
const clean = (arr) => arr.map((t) => (typeof t === "string" ? t.trim() : "")).filter((t) => t.length > 0);
|
|
138
|
+
if (Array.isArray(raw))
|
|
139
|
+
return clean(raw);
|
|
140
|
+
if (typeof raw === "string") {
|
|
141
|
+
const s = raw.trim();
|
|
142
|
+
if (s.length === 0)
|
|
143
|
+
return [];
|
|
144
|
+
if (s.startsWith("[")) {
|
|
145
|
+
try {
|
|
146
|
+
const parsed = JSON.parse(s);
|
|
147
|
+
if (Array.isArray(parsed))
|
|
148
|
+
return clean(parsed);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* fall through to delimiter split */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return clean(s.split(/[\n,]/));
|
|
155
|
+
}
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write-side handler factories for the Paddock self-management MCP — Phase 2
|
|
3
|
+
* (issue #214). The create/fork/send/archive/fork-batch tools, each bound to a
|
|
4
|
+
* per-turn {@link SelfMcpWriteContext}. Every factory returns an async handler
|
|
5
|
+
* that validates/normalizes args (including the #336 per-chat `model` override and
|
|
6
|
+
* the CLI-transport-tolerant `prompts` coercion) and delegates to the write
|
|
7
|
+
* callbacks, which START real keeper turns. Present only when the write flag is on.
|
|
8
|
+
*/
|
|
9
|
+
import type { McpToolCallResult } from "@herdctl/core";
|
|
10
|
+
import type { SelfMcpWriteContext } from "./self-mcp-types.js";
|
|
11
|
+
export declare function createChatHandler(write: SelfMcpWriteContext): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|
|
12
|
+
export declare function forkChatHandler(write: SelfMcpWriteContext): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|
|
13
|
+
export declare function sendMessageHandler(write: SelfMcpWriteContext): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|
|
14
|
+
/**
|
|
15
|
+
* Handler factory for archive_chat / unarchive_chat. Both resolve the target the
|
|
16
|
+
* same way — `session_id` OPTIONAL, defaulting to the CURRENT chat so an agent can
|
|
17
|
+
* archive ITSELF without knowing its own id (mirrors fork_chat's self-default) —
|
|
18
|
+
* and differ only in the boolean they set. `archived` selects which tool this is.
|
|
19
|
+
*/
|
|
20
|
+
export declare function archiveChatHandler(write: SelfMcpWriteContext, archived: boolean): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|
|
21
|
+
/**
|
|
22
|
+
* `create_project` (issue #467) — provision a whole new project. The one write tool
|
|
23
|
+
* that does NOT act inside an existing project, which is why it sits behind its own
|
|
24
|
+
* `projectsMcpEnabled` gate.
|
|
25
|
+
*
|
|
26
|
+
* Pure, like its siblings: it trims + SHAPE-validates the args (using the very same
|
|
27
|
+
* `SLUG_RE` / `isValidRepoUrl` / `PROJECT_STATUSES` the store and DTO use, so there
|
|
28
|
+
* is no second definition of "valid") and delegates to `write.createProject`, which
|
|
29
|
+
* runs `ProjectStore.create` + `ensureProjectAgent` — literally the REST create path.
|
|
30
|
+
* The up-front checks are a fast, actionable-error convenience, NOT a replacement for
|
|
31
|
+
* the store's own validation: the store still rejects a duplicate slug, a bad URL and
|
|
32
|
+
* an unclonable repo, and still rolls the whole project dir back on a clone failure.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createProjectHandler(write: SelfMcpWriteContext): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|
|
35
|
+
export declare function forkChatBatchHandler(write: SelfMcpWriteContext): (args: Record<string, unknown>) => Promise<McpToolCallResult>;
|