@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.
- 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 +512 -0
- package/packages/server/dist/config.js +593 -0
- package/packages/server/dist/curation-config.d.ts +55 -0
- package/packages/server/dist/curation-config.js +64 -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 +572 -0
- package/packages/server/dist/herdctl.js +1218 -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 +135 -0
- package/packages/server/dist/instance-config.js +345 -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-4cQGTj9Y.js +2 -0
- package/packages/web/dist/assets/MarkdownRenderer-CJZFLj_8.js +30 -0
- package/packages/web/dist/assets/ProjectRedirect-BHwVbbqB.js +2 -0
- package/packages/web/dist/assets/ProjectView-BOvuAITg.js +13 -0
- package/packages/web/dist/assets/ProjectsGrid-BCojZOGY.js +2 -0
- package/packages/web/dist/assets/arc-BVyxvnkl.js +2 -0
- package/packages/web/dist/assets/architectureDiagram-3BPJPVTR-Cd9Puqg1.js +37 -0
- package/packages/web/dist/assets/bash-I8pq0VWm.js +2 -0
- package/packages/web/dist/assets/blockDiagram-GPEHLZMM-B_AQt_Rx.js +133 -0
- package/packages/web/dist/assets/c-D2F1sQUL.js +2 -0
- package/packages/web/dist/assets/c4Diagram-AAUBKEIU-7e0TQtXB.js +11 -0
- package/packages/web/dist/assets/channel-C_1aISNn.js +2 -0
- package/packages/web/dist/assets/chunk-2J33WTMH-Dz4WZmUZ.js +2 -0
- package/packages/web/dist/assets/chunk-4BX2VUAB-DVWYldo6.js +2 -0
- package/packages/web/dist/assets/chunk-55IACEB6-BIMrizQd.js +2 -0
- package/packages/web/dist/assets/chunk-727SXJPM-CL2q9fF1.js +207 -0
- package/packages/web/dist/assets/chunk-AQP2D5EJ-BSq3HlQ9.js +232 -0
- package/packages/web/dist/assets/chunk-FMBD7UC4-Bgt64pLE.js +16 -0
- package/packages/web/dist/assets/chunk-ND2GUHAM-C8Pr2A38.js +2 -0
- package/packages/web/dist/assets/chunk-QZHKN3VN-BAOqh-MN.js +2 -0
- package/packages/web/dist/assets/classDiagram-4FO5ZUOK-B8JE7cHJ.js +2 -0
- package/packages/web/dist/assets/classDiagram-v2-Q7XG4LA2-B8JE7cHJ.js +2 -0
- package/packages/web/dist/assets/core-lJeGACQg.js +4 -0
- package/packages/web/dist/assets/cose-bilkent-S5V4N54A-BF4tameA.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-DdsLM6ql.js +5 -0
- package/packages/web/dist/assets/defaultLocale-DX6XiGOO.js +2 -0
- package/packages/web/dist/assets/diagram-2AECGRRQ-BQ78S_RM.js +44 -0
- package/packages/web/dist/assets/diagram-5GNKFQAL-CAKE6nHE.js +11 -0
- package/packages/web/dist/assets/diagram-KO2AKTUF-fEvHRXgr.js +4 -0
- package/packages/web/dist/assets/diagram-LMA3HP47-CtWsgeSm.js +25 -0
- package/packages/web/dist/assets/diagram-OG6HWLK6-Buog8k7_.js +25 -0
- package/packages/web/dist/assets/erDiagram-TEJ5UH35-CWvVVPZS.js +86 -0
- package/packages/web/dist/assets/flowDiagram-I6XJVG4X-DsCGXtp4.js +163 -0
- package/packages/web/dist/assets/format-DamJQ9LO.js +2 -0
- package/packages/web/dist/assets/ganttDiagram-6RSMTGT7-CsdwIvvC.js +293 -0
- package/packages/web/dist/assets/gitGraphDiagram-PVQCEYII-hZvrX1sD.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-CGbZdrm8.js +71 -0
- package/packages/web/dist/assets/index-DJDQ210-.css +1 -0
- package/packages/web/dist/assets/infoDiagram-5YYISTIA-nE_Vtz_l.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-2Nlqs0oH.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-mjU1fMc4.js +140 -0
- package/packages/web/dist/assets/json-DIYVocXf.js +2 -0
- package/packages/web/dist/assets/kanban-definition-UN3LZRKU-C_9xNaa3.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-BxKd91ho.js +2 -0
- package/packages/web/dist/assets/mermaid.core-C-CuhD8I.js +310 -0
- package/packages/web/dist/assets/mindmap-definition-RKZ34NQL-Bs6yfcZv.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-DNdqX7O5.js +31 -0
- package/packages/web/dist/assets/python-kSlZHhJb.js +2 -0
- package/packages/web/dist/assets/quadrantDiagram-W4KKPZXB-ZMJl9OdZ.js +8 -0
- package/packages/web/dist/assets/queued-LamEU0GH.js +2 -0
- package/packages/web/dist/assets/requirementDiagram-4Y6WPE33-RmxMdm2q.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-OAAhWcfK.js +41 -0
- package/packages/web/dist/assets/scss-DZLA7YXz.js +2 -0
- package/packages/web/dist/assets/sequenceDiagram-3UESZ5HK-BWF7rCyN.js +163 -0
- package/packages/web/dist/assets/sql-BC88IN-V.js +2 -0
- package/packages/web/dist/assets/stateDiagram-AJRCARHV-M3b_zqqo.js +2 -0
- package/packages/web/dist/assets/stateDiagram-v2-BHNVJYJU-CI7saFDa.js +2 -0
- package/packages/web/dist/assets/swift-Dn8kKO_1.js +2 -0
- package/packages/web/dist/assets/timeline-definition-PNZ67QCA-BpOCh63N.js +121 -0
- package/packages/web/dist/assets/typescript-C2FFdlUC.js +2 -0
- package/packages/web/dist/assets/vennDiagram-CIIHVFJN-D_iPH45Q.js +35 -0
- package/packages/web/dist/assets/wardley-L42UT6IY-DVD9I2Om.js +174 -0
- package/packages/web/dist/assets/wardleyDiagram-YWT4CUSO-Bn1IKwjn.js +79 -0
- package/packages/web/dist/assets/xml-BXBhIUeX.js +2 -0
- package/packages/web/dist/assets/xychartDiagram-2RQKCTM6-DwtI0bkR.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,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* herdctl-jobs — the on-disk `job-*.yaml` reads (run history + the unread badge)
|
|
3
|
+
* and the adoption/attribution writes, split out of {@link HerdctlService}
|
|
4
|
+
* (issue #403).
|
|
5
|
+
*
|
|
6
|
+
* Every function here depends only on the shared jobs directory (`<stateDir>/jobs`)
|
|
7
|
+
* plus fs/YAML and the pure agent-name helpers — NO `fleet`/live-session state —
|
|
8
|
+
* so the cluster is isolated + testable on its own. {@link HerdctlService} keeps
|
|
9
|
+
* thin public wrappers (`lastTurnCompletedAt`, `listProjectRuns`, …) that thread
|
|
10
|
+
* `this.cfg.stateDir`, and its internal fork/promote/attribute methods call the
|
|
11
|
+
* write helpers here directly.
|
|
12
|
+
*
|
|
13
|
+
* The two unread-badge reads take a {@link JobsDirIndex} instead of a `stateDir`
|
|
14
|
+
* (#529): they run on nearly every request, and re-parsing every record each time
|
|
15
|
+
* was 61% of all busy server CPU. The index owns the directory and keeps the parse
|
|
16
|
+
* incremental; these functions are pure folds over it. The write helpers below
|
|
17
|
+
* still take `stateDir` — they are rare, and the index self-heals from their
|
|
18
|
+
* mtime changes (`HerdctlService` also invalidates it explicitly at each site).
|
|
19
|
+
*/
|
|
20
|
+
import { promises as fs } from "node:fs";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import YAML from "yaml";
|
|
23
|
+
import { listJobs } from "@herdctl/core";
|
|
24
|
+
import { keeperAgentName, keeperSlugFromAgent } from "./herdctl-agent-names.js";
|
|
25
|
+
import { jobsDirOf } from "./herdctl-jobs-index.js";
|
|
26
|
+
/**
|
|
27
|
+
* Map each chat session id to the ISO timestamp of its most recent COMPLETED
|
|
28
|
+
* turn, read cheaply from herdctl's job-metadata records (NOT by parsing
|
|
29
|
+
* transcripts). In `batch` drive mode every keeper turn runs via `trigger()`,
|
|
30
|
+
* which writes a `job-*.yaml` whose `finished_at` is stamped when the turn
|
|
31
|
+
* finishes and whose `session_id` is filled in on completion — so the latest
|
|
32
|
+
* `finished_at` across a session's records is exactly "the agent last finished a
|
|
33
|
+
* turn." NOTE the default drive mode is `session`, whose turns write NO job
|
|
34
|
+
* record (see the caveat on {@link listProjectRuns}); on that path this map is
|
|
35
|
+
* fed only by paddock's synthetic adoption records. This is the server signal
|
|
36
|
+
* for the unread affordance (#160, reused per-project by #161): unlike the
|
|
37
|
+
* transcript mtime (`DiscoveredSession.mtime`) it does NOT tick on the user's
|
|
38
|
+
* own sends.
|
|
39
|
+
*
|
|
40
|
+
* Records still running (no `finished_at`) or not yet session-resolved (no
|
|
41
|
+
* `session_id`) are skipped. The synthetic adoption records paddock writes
|
|
42
|
+
* carry an earlier, mid-turn `finished_at`, so the max naturally prefers the
|
|
43
|
+
* real completion. Session-mode turns (`openChatSession`) write no job record,
|
|
44
|
+
* so their chats have no server timestamp and rely on the client live event.
|
|
45
|
+
*
|
|
46
|
+
* Reads through {@link JobsDirIndex}, which keeps the parse incremental
|
|
47
|
+
* (mtime+size keyed, completed records only) — see there for why that is safe
|
|
48
|
+
* and what it is worth. This function itself is a pure fold over the index.
|
|
49
|
+
*/
|
|
50
|
+
export async function lastTurnCompletedAt(index) {
|
|
51
|
+
const out = new Map();
|
|
52
|
+
for (const { sessionId, finishedAt } of await index.read()) {
|
|
53
|
+
// ISO-8601 UTC strings sort lexicographically in chronological order.
|
|
54
|
+
const prev = out.get(sessionId);
|
|
55
|
+
if (!prev || finishedAt > prev)
|
|
56
|
+
out.set(sessionId, finishedAt);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Per-project variant of {@link lastTurnCompletedAt} for the sidebar unread
|
|
62
|
+
* badge (#161): group the same cheap job-record scan by the KEEPER agent that
|
|
63
|
+
* owns each session, so the projects-list payload can carry a compact
|
|
64
|
+
* `{ sessionId, lastTurnCompletedAt }` list per project WITHOUT the N+1
|
|
65
|
+
* `listSessions` fan-out or any transcript parse. Returns `slug -> (sessionId
|
|
66
|
+
* -> latest finished_at)`.
|
|
67
|
+
*
|
|
68
|
+
* Only keeper-attributed records (`agent: keeper-<slug>`) are kept — sweeper,
|
|
69
|
+
* trigger and hook records carry their own session ids that are not chats, so
|
|
70
|
+
* `keeperSlugFromAgent` returning `null` naturally filters them out. A promoted
|
|
71
|
+
* chat is grouped under its keeper slug (its keeper record).
|
|
72
|
+
*/
|
|
73
|
+
export async function lastTurnCompletedAtByProject(index) {
|
|
74
|
+
const out = new Map();
|
|
75
|
+
for (const { sessionId, finishedAt, agent } of await index.read()) {
|
|
76
|
+
if (agent === null)
|
|
77
|
+
continue;
|
|
78
|
+
const slug = keeperSlugFromAgent(agent);
|
|
79
|
+
// only keeper (workspace) chats — skip sweeper/hook/trigger agents.
|
|
80
|
+
// `""` is the ROOT workspace's key, so compare against null explicitly: a
|
|
81
|
+
// falsy check would drop every root chat from the unread badge.
|
|
82
|
+
if (slug === null)
|
|
83
|
+
continue;
|
|
84
|
+
let bySession = out.get(slug);
|
|
85
|
+
if (!bySession) {
|
|
86
|
+
bySession = new Map();
|
|
87
|
+
out.set(slug, bySession);
|
|
88
|
+
}
|
|
89
|
+
// ISO-8601 UTC strings sort lexicographically in chronological order.
|
|
90
|
+
const prev = bySession.get(sessionId);
|
|
91
|
+
if (!prev || finishedAt > prev)
|
|
92
|
+
bySession.set(sessionId, finishedAt);
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The raw herdctl job records for one project's keeper agent, most-recent
|
|
98
|
+
* first — the data source for the "while you were away" run-history view (E3 /
|
|
99
|
+
* #268 / DD-6). Each `trigger()` (batch drive mode) turn writes one
|
|
100
|
+
* `job-*.yaml` carrying `trigger_type`, `status`, `started_at`/`finished_at`,
|
|
101
|
+
* `duration_seconds`, `session_id`, `schedule` and `forked_from`; this reads
|
|
102
|
+
* them via core's `listJobs` (importable from `@herdctl/core`, sorted by
|
|
103
|
+
* `started_at` descending) filtered to `keeper-<slug>`, so sweeper/trigger
|
|
104
|
+
* records are excluded.
|
|
105
|
+
*
|
|
106
|
+
* The true human/scheduled/spawned provenance is carried by Paddock's
|
|
107
|
+
* {@link RunProvenanceStore} (origin/depth keyed by `session_id`), NOT by
|
|
108
|
+
* `trigger_type` — paddock-initiated turns still write `trigger_type:"manual"`
|
|
109
|
+
* (see ws.ts). The caller joins the two.
|
|
110
|
+
*
|
|
111
|
+
* Caveat (documented at {@link lastTurnCompletedAt}): session-mode turns
|
|
112
|
+
* (`openChatSession`) write NO job record, so runs driven that way don't
|
|
113
|
+
* appear here — only batch `trigger()` turns and paddock's synthetic adoption
|
|
114
|
+
* records do. Cost columns (DD-4) are P3 and not yet on the record.
|
|
115
|
+
*/
|
|
116
|
+
export async function listProjectRuns(stateDir, project, limit = 100) {
|
|
117
|
+
const jobsDir = jobsDirOf(stateDir);
|
|
118
|
+
const agent = keeperAgentName(project.slug);
|
|
119
|
+
const { jobs } = await listJobs(jobsDir, { agent }).catch(() => ({ jobs: [], errors: 0 }));
|
|
120
|
+
return limit > 0 ? jobs.slice(0, limit) : jobs;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Job records for a SET of agents, most-recent first (Epic T follow-up / #327) —
|
|
124
|
+
* the data source for the Triggers tab's per-trigger last-run column. Used to pull
|
|
125
|
+
* one project's keeper AND every scoped `trigger-<slug>-<name>` agent in a single
|
|
126
|
+
* pass so {@link import("./trigger-runtime.js").buildTriggerRuntime} can attribute a
|
|
127
|
+
* scoped trigger's newest run by agent name. `listJobs` has no multi-agent filter,
|
|
128
|
+
* so this scans the jobs dir once (unfiltered) and keeps only the requested agents;
|
|
129
|
+
* order (started_at descending) is preserved. Errors swallow to `[]` so the runtime
|
|
130
|
+
* view degrades to config-only rather than failing to render.
|
|
131
|
+
*/
|
|
132
|
+
export async function listRunsForAgents(stateDir, agents, limit = 200) {
|
|
133
|
+
if (agents.length === 0)
|
|
134
|
+
return [];
|
|
135
|
+
const jobsDir = jobsDirOf(stateDir);
|
|
136
|
+
const wanted = new Set(agents);
|
|
137
|
+
const { jobs } = await listJobs(jobsDir).catch(() => ({ jobs: [], errors: 0 }));
|
|
138
|
+
const filtered = jobs.filter((j) => wanted.has(j.agent));
|
|
139
|
+
return limit > 0 ? filtered.slice(0, limit) : filtered;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Point every herdctl job record for `sessionId` at the project's keeper so
|
|
143
|
+
* the core attribution index (last-write-wins per session) lists the session
|
|
144
|
+
* under the project. A session can already have MANY job records (one per
|
|
145
|
+
* turn) attributed elsewhere; simply adding a keeper record alongside them is
|
|
146
|
+
* not enough — whichever record the index visits last wins. So we rewrite the
|
|
147
|
+
* `agent` field of all existing records for the session. When none exist
|
|
148
|
+
* (e.g. a transcript migrated from outside paddock), we synthesize one.
|
|
149
|
+
*/
|
|
150
|
+
export async function reattributeSession(stateDir, sessionId, project, when) {
|
|
151
|
+
const jobsDir = jobsDirOf(stateDir);
|
|
152
|
+
await fs.mkdir(jobsDir, { recursive: true });
|
|
153
|
+
const keeper = keeperAgentName(project.slug);
|
|
154
|
+
let entries = [];
|
|
155
|
+
try {
|
|
156
|
+
entries = await fs.readdir(jobsDir);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
entries = [];
|
|
160
|
+
}
|
|
161
|
+
let matched = 0;
|
|
162
|
+
for (const name of entries) {
|
|
163
|
+
if (!name.endsWith(".yaml"))
|
|
164
|
+
continue;
|
|
165
|
+
const file = path.join(jobsDir, name);
|
|
166
|
+
let parsed = null;
|
|
167
|
+
try {
|
|
168
|
+
parsed = YAML.parse(await fs.readFile(file, "utf8"));
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (!parsed || parsed.session_id !== sessionId)
|
|
174
|
+
continue;
|
|
175
|
+
matched++;
|
|
176
|
+
if (parsed.agent === keeper)
|
|
177
|
+
continue;
|
|
178
|
+
parsed.agent = keeper;
|
|
179
|
+
await fs.writeFile(file, YAML.stringify(parsed), "utf8");
|
|
180
|
+
}
|
|
181
|
+
// No existing job records for the session — synthesize one (migration path).
|
|
182
|
+
if (matched === 0)
|
|
183
|
+
await writeAdoptionJob(stateDir, sessionId, project, when);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Write a herdctl job-metadata YAML mapping `sessionId -> keeper agent` so the
|
|
187
|
+
* core attribution index lists the session under the project. Mirrors the shape
|
|
188
|
+
* of a real job record (and the JobMetadataSchema: the id must match
|
|
189
|
+
* `job-YYYY-MM-DD-[a-z0-9]{6}`).
|
|
190
|
+
*/
|
|
191
|
+
export async function writeAdoptionJob(stateDir, sessionId, project, when) {
|
|
192
|
+
await writeAgentAdoptionJob(stateDir, sessionId, keeperAgentName(project.slug), when);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Underlying adoption-record writer, parametrized by the target agent name so
|
|
196
|
+
* every caller (fork/promote/adopt — see {@link attributeRunningSession}) shares
|
|
197
|
+
* one implementation. Writes a `<jobId>.yaml` mapping the
|
|
198
|
+
* session id to `agentName` plus a matching empty `.jsonl` output file.
|
|
199
|
+
*/
|
|
200
|
+
export async function writeAgentAdoptionJob(stateDir, sessionId, agentName, when) {
|
|
201
|
+
const jobsDir = jobsDirOf(stateDir);
|
|
202
|
+
await fs.mkdir(jobsDir, { recursive: true });
|
|
203
|
+
const iso = (Number.isNaN(when.getTime()) ? new Date() : when).toISOString();
|
|
204
|
+
const date = iso.slice(0, 10);
|
|
205
|
+
const jobId = `job-${date}-${sessionId.slice(0, 6).toLowerCase()}`;
|
|
206
|
+
const outputFile = path.join(jobsDir, `${jobId}.jsonl`);
|
|
207
|
+
const record = {
|
|
208
|
+
id: jobId,
|
|
209
|
+
agent: agentName,
|
|
210
|
+
schedule: null,
|
|
211
|
+
trigger_type: "web",
|
|
212
|
+
status: "completed",
|
|
213
|
+
exit_reason: "success",
|
|
214
|
+
session_id: sessionId,
|
|
215
|
+
forked_from: null,
|
|
216
|
+
started_at: iso,
|
|
217
|
+
finished_at: iso,
|
|
218
|
+
duration_seconds: 0,
|
|
219
|
+
output_file: outputFile,
|
|
220
|
+
};
|
|
221
|
+
await fs.writeFile(path.join(jobsDir, `${jobId}.yaml`), YAML.stringify(record), "utf8");
|
|
222
|
+
// herdctl's listJobs tolerates a missing output file, but keep parity with
|
|
223
|
+
// a real job record by touching an empty one.
|
|
224
|
+
await fs.writeFile(outputFile, "", "utf8").catch(() => undefined);
|
|
225
|
+
}
|