@dorokuma/herdsman 0.6.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/LICENSE +23 -0
- package/README.ja.md +143 -0
- package/README.md +150 -0
- package/dist/drizzle.config.d.ts +3 -0
- package/dist/drizzle.config.d.ts.map +1 -0
- package/dist/drizzle.config.js +7 -0
- package/dist/drizzle.config.js.map +1 -0
- package/dist/src/agent-history/claude-reader.d.ts +10 -0
- package/dist/src/agent-history/claude-reader.d.ts.map +1 -0
- package/dist/src/agent-history/claude-reader.js +90 -0
- package/dist/src/agent-history/claude-reader.js.map +1 -0
- package/dist/src/agent-history/codex-reader.d.ts +10 -0
- package/dist/src/agent-history/codex-reader.d.ts.map +1 -0
- package/dist/src/agent-history/codex-reader.js +119 -0
- package/dist/src/agent-history/codex-reader.js.map +1 -0
- package/dist/src/agent-history/discovery.d.ts +13 -0
- package/dist/src/agent-history/discovery.d.ts.map +1 -0
- package/dist/src/agent-history/discovery.js +220 -0
- package/dist/src/agent-history/discovery.js.map +1 -0
- package/dist/src/agent-history/gemini-reader.d.ts +10 -0
- package/dist/src/agent-history/gemini-reader.d.ts.map +1 -0
- package/dist/src/agent-history/gemini-reader.js +96 -0
- package/dist/src/agent-history/gemini-reader.js.map +1 -0
- package/dist/src/agent-history/opencode-reader.d.ts +10 -0
- package/dist/src/agent-history/opencode-reader.d.ts.map +1 -0
- package/dist/src/agent-history/opencode-reader.js +90 -0
- package/dist/src/agent-history/opencode-reader.js.map +1 -0
- package/dist/src/agent-history/pi-reader.d.ts +10 -0
- package/dist/src/agent-history/pi-reader.d.ts.map +1 -0
- package/dist/src/agent-history/pi-reader.js +59 -0
- package/dist/src/agent-history/pi-reader.js.map +1 -0
- package/dist/src/agent-history/readers.d.ts +16 -0
- package/dist/src/agent-history/readers.d.ts.map +1 -0
- package/dist/src/agent-history/readers.js +45 -0
- package/dist/src/agent-history/readers.js.map +1 -0
- package/dist/src/agent-history/service.d.ts +43 -0
- package/dist/src/agent-history/service.d.ts.map +1 -0
- package/dist/src/agent-history/service.js +124 -0
- package/dist/src/agent-history/service.js.map +1 -0
- package/dist/src/agent-history/text.d.ts +10 -0
- package/dist/src/agent-history/text.d.ts.map +1 -0
- package/dist/src/agent-history/text.js +64 -0
- package/dist/src/agent-history/text.js.map +1 -0
- package/dist/src/agent-history/tool-compaction.d.ts +8 -0
- package/dist/src/agent-history/tool-compaction.d.ts.map +1 -0
- package/dist/src/agent-history/tool-compaction.js +134 -0
- package/dist/src/agent-history/tool-compaction.js.map +1 -0
- package/dist/src/cli/herdsman-daemon.d.ts +3 -0
- package/dist/src/cli/herdsman-daemon.d.ts.map +1 -0
- package/dist/src/cli/herdsman-daemon.js +18 -0
- package/dist/src/cli/herdsman-daemon.js.map +1 -0
- package/dist/src/cli/herdsman.d.ts +42 -0
- package/dist/src/cli/herdsman.d.ts.map +1 -0
- package/dist/src/cli/herdsman.js +338 -0
- package/dist/src/cli/herdsman.js.map +1 -0
- package/dist/src/config/load.d.ts +14 -0
- package/dist/src/config/load.d.ts.map +1 -0
- package/dist/src/config/load.js +28 -0
- package/dist/src/config/load.js.map +1 -0
- package/dist/src/config/runtime.d.ts +40 -0
- package/dist/src/config/runtime.d.ts.map +1 -0
- package/dist/src/config/runtime.js +111 -0
- package/dist/src/config/runtime.js.map +1 -0
- package/dist/src/config/schema.d.ts +25 -0
- package/dist/src/config/schema.d.ts.map +1 -0
- package/dist/src/config/schema.js +26 -0
- package/dist/src/config/schema.js.map +1 -0
- package/dist/src/daemon/client.d.ts +9 -0
- package/dist/src/daemon/client.d.ts.map +1 -0
- package/dist/src/daemon/client.js +51 -0
- package/dist/src/daemon/client.js.map +1 -0
- package/dist/src/daemon/herdr-session-watch-manager.d.ts +33 -0
- package/dist/src/daemon/herdr-session-watch-manager.d.ts.map +1 -0
- package/dist/src/daemon/herdr-session-watch-manager.js +245 -0
- package/dist/src/daemon/herdr-session-watch-manager.js.map +1 -0
- package/dist/src/daemon/observability-server.d.ts +60 -0
- package/dist/src/daemon/observability-server.d.ts.map +1 -0
- package/dist/src/daemon/observability-server.js +501 -0
- package/dist/src/daemon/observability-server.js.map +1 -0
- package/dist/src/daemon/process-manager.d.ts +80 -0
- package/dist/src/daemon/process-manager.d.ts.map +1 -0
- package/dist/src/daemon/process-manager.js +178 -0
- package/dist/src/daemon/process-manager.js.map +1 -0
- package/dist/src/daemon/service.d.ts +5 -0
- package/dist/src/daemon/service.d.ts.map +1 -0
- package/dist/src/daemon/service.js +104 -0
- package/dist/src/daemon/service.js.map +1 -0
- package/dist/src/db/agent-context-snapshots.d.ts +11 -0
- package/dist/src/db/agent-context-snapshots.d.ts.map +1 -0
- package/dist/src/db/agent-context-snapshots.js +129 -0
- package/dist/src/db/agent-context-snapshots.js.map +1 -0
- package/dist/src/db/agent-events.d.ts +54 -0
- package/dist/src/db/agent-events.d.ts.map +1 -0
- package/dist/src/db/agent-events.js +124 -0
- package/dist/src/db/agent-events.js.map +1 -0
- package/dist/src/db/agent-history-cache.d.ts +31 -0
- package/dist/src/db/agent-history-cache.d.ts.map +1 -0
- package/dist/src/db/agent-history-cache.js +46 -0
- package/dist/src/db/agent-history-cache.js.map +1 -0
- package/dist/src/db/agent-orchestrator-scopes.d.ts +40 -0
- package/dist/src/db/agent-orchestrator-scopes.d.ts.map +1 -0
- package/dist/src/db/agent-orchestrator-scopes.js +148 -0
- package/dist/src/db/agent-orchestrator-scopes.js.map +1 -0
- package/dist/src/db/agents.d.ts +34 -0
- package/dist/src/db/agents.d.ts.map +1 -0
- package/dist/src/db/agents.js +295 -0
- package/dist/src/db/agents.js.map +1 -0
- package/dist/src/db/apply-migrations.d.ts +4 -0
- package/dist/src/db/apply-migrations.d.ts.map +1 -0
- package/dist/src/db/apply-migrations.js +37 -0
- package/dist/src/db/apply-migrations.js.map +1 -0
- package/dist/src/db/client.d.ts +5 -0
- package/dist/src/db/client.d.ts.map +1 -0
- package/dist/src/db/client.js +6 -0
- package/dist/src/db/client.js.map +1 -0
- package/dist/src/db/herdr-sessions.d.ts +18 -0
- package/dist/src/db/herdr-sessions.d.ts.map +1 -0
- package/dist/src/db/herdr-sessions.js +67 -0
- package/dist/src/db/herdr-sessions.js.map +1 -0
- package/dist/src/db/herdr-workspaces.d.ts +14 -0
- package/dist/src/db/herdr-workspaces.d.ts.map +1 -0
- package/dist/src/db/herdr-workspaces.js +53 -0
- package/dist/src/db/herdr-workspaces.js.map +1 -0
- package/dist/src/db/migrate.d.ts +2 -0
- package/dist/src/db/migrate.d.ts.map +1 -0
- package/dist/src/db/migrate.js +8 -0
- package/dist/src/db/migrate.js.map +1 -0
- package/dist/src/db/schema.d.ts +1258 -0
- package/dist/src/db/schema.d.ts.map +1 -0
- package/dist/src/db/schema.js +102 -0
- package/dist/src/db/schema.js.map +1 -0
- package/dist/src/herdr/pane-identity-resolver.d.ts +14 -0
- package/dist/src/herdr/pane-identity-resolver.d.ts.map +1 -0
- package/dist/src/herdr/pane-identity-resolver.js +34 -0
- package/dist/src/herdr/pane-identity-resolver.js.map +1 -0
- package/dist/src/herdr/session-list.d.ts +14 -0
- package/dist/src/herdr/session-list.d.ts.map +1 -0
- package/dist/src/herdr/session-list.js +44 -0
- package/dist/src/herdr/session-list.js.map +1 -0
- package/dist/src/herdr/session-snapshot.d.ts +10 -0
- package/dist/src/herdr/session-snapshot.d.ts.map +1 -0
- package/dist/src/herdr/session-snapshot.js +19 -0
- package/dist/src/herdr/session-snapshot.js.map +1 -0
- package/dist/src/herdr/socket-client.d.ts +19 -0
- package/dist/src/herdr/socket-client.d.ts.map +1 -0
- package/dist/src/herdr/socket-client.js +230 -0
- package/dist/src/herdr/socket-client.js.map +1 -0
- package/dist/src/observability/agent-context-service.d.ts +29 -0
- package/dist/src/observability/agent-context-service.d.ts.map +1 -0
- package/dist/src/observability/agent-context-service.js +170 -0
- package/dist/src/observability/agent-context-service.js.map +1 -0
- package/dist/src/observability/agent-index-service.d.ts +60 -0
- package/dist/src/observability/agent-index-service.d.ts.map +1 -0
- package/dist/src/observability/agent-index-service.js +376 -0
- package/dist/src/observability/agent-index-service.js.map +1 -0
- package/dist/src/observability/agent-orchestrator-service.d.ts +42 -0
- package/dist/src/observability/agent-orchestrator-service.d.ts.map +1 -0
- package/dist/src/observability/agent-orchestrator-service.js +95 -0
- package/dist/src/observability/agent-orchestrator-service.js.map +1 -0
- package/dist/src/observability/contracts.d.ts +161 -0
- package/dist/src/observability/contracts.d.ts.map +1 -0
- package/dist/src/observability/contracts.js +10 -0
- package/dist/src/observability/contracts.js.map +1 -0
- package/dist/src/observability/schemas.d.ts +49 -0
- package/dist/src/observability/schemas.d.ts.map +1 -0
- package/dist/src/observability/schemas.js +47 -0
- package/dist/src/observability/schemas.js.map +1 -0
- package/dist/src/shared/json-lines.d.ts +7 -0
- package/dist/src/shared/json-lines.d.ts.map +1 -0
- package/dist/src/shared/json-lines.js +25 -0
- package/dist/src/shared/json-lines.js.map +1 -0
- package/drizzle/0000_rare_robin_chapel.sql +90 -0
- package/drizzle/0001_opposite_toxin.sql +13 -0
- package/drizzle/0002_worthless_energizer.sql +2 -0
- package/drizzle/0003_opposite_tarantula.sql +14 -0
- package/drizzle/0004_serious_lorna_dane.sql +1 -0
- package/drizzle/0005_pane_generation.sql +7 -0
- package/drizzle/meta/0000_snapshot.json +621 -0
- package/drizzle/meta/0001_snapshot.json +709 -0
- package/drizzle/meta/0002_snapshot.json +563 -0
- package/drizzle/meta/0003_snapshot.json +657 -0
- package/drizzle/meta/0004_snapshot.json +664 -0
- package/drizzle/meta/_journal.json +12 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ryo Nakae
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
Copyright (c) 2026 dorokuma (herdsman)
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# Herdsman
|
|
4
|
+
|
|
5
|
+
<!-- README-I18N:START -->
|
|
6
|
+
[English](./README.md) | **日本語**
|
|
7
|
+
<!-- README-I18N:END -->
|
|
8
|
+
|
|
9
|
+
Herdsman は、Herdr で動く coding agent の状態を記録する daemon ベースの観測ツールです。CLI から構造化された履歴を取得でき、Pi では owner だけに cached context と通知を送り、必要なときに自動で wake します。
|
|
10
|
+
|
|
11
|
+
Herdr の `herdr agent read` は terminal stream や scrollback を読みます。Herdsman は agent の session data から作業状況、message の抜粋、compact tool result、未読の outcome を取得します。Herdsman は agent を操作しません。agent の start、prompt、wait、pane 操作、terminal control には公式 Herdr CLI または skill を使います。
|
|
12
|
+
|
|
13
|
+
現在は Claude Code、Codex、Gemini CLI、OpenCode、Pi のセッション履歴の取得に対応しています。
|
|
14
|
+
|
|
15
|
+
## 要件
|
|
16
|
+
|
|
17
|
+
- Node.js >= 24.18.0
|
|
18
|
+
- Herdr >= 0.7.0
|
|
19
|
+
- `herdsman-pi` を使う場合は Pi >= 0.80.6
|
|
20
|
+
|
|
21
|
+
## インストール
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install --global @dorokuma/herdsman
|
|
25
|
+
herdsman help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### ソースからインストールする
|
|
29
|
+
|
|
30
|
+
ソースからbuildする場合はpnpm >= 11.9.0も必要です。
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/ryonakae/herdsman.git
|
|
34
|
+
cd herdsman
|
|
35
|
+
pnpm install
|
|
36
|
+
pnpm build
|
|
37
|
+
npm install --global . --ignore-scripts
|
|
38
|
+
herdsman help
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## daemon を起動する
|
|
42
|
+
|
|
43
|
+
Herdsman のagent commandとPi notificationはdaemonを必要とします。daemon は `herdr session list --json` に出る実行中の Herdr session を監視し、60 秒ごとに再スキャンします。停止した Herdr session は index しません。runtime file は標準で `~/.herdsman` に置きます。別の directory を使う場合は `SHEPHERD_HOME` を設定します。
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
herdsman daemon start
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 主なコマンド
|
|
50
|
+
|
|
51
|
+
- `herdsman agent list`: 選択した workspace の最新キャッシュから status と最後の user / assistant message の抜粋を返します。鮮度が必要なときは各行の `updatedAt` を確認します。
|
|
52
|
+
- `herdsman agent get <target>`: 明示的に詳細を取得し、1 agent の metadata、compact history、最新の compact tool result を返します。
|
|
53
|
+
- `herdsman agent read <target> --limit N`: 明示的に履歴を読み、直近 N 件の user / assistant / compact `tool_result` message を返します。
|
|
54
|
+
|
|
55
|
+
各 agent record は、`reviewer` のような Herdr の live `name` と、`codex` のような runtime `agent` kind を別々に保持します。通常の list 出力では `name` と `agent` を別の column に表示し、JSON でも両方を返します。Herdr workspace 内では、Herdsman が current workspace を自動で選びます。
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
herdsman agent list --json
|
|
59
|
+
herdsman agent get reviewer --json
|
|
60
|
+
herdsman agent read reviewer --limit 20 --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Herdr の外から読む場合は scope を指定します。
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
herdsman agent list --all --json
|
|
67
|
+
herdsman agent list --workspace wB --json
|
|
68
|
+
herdsman agent get reviewer --workspace wB --json
|
|
69
|
+
herdsman agent read wB:p2 --workspace wB --limit 20 --json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`<target>` は、選択した scope 内で pane id、terminal id、Herdsman agent id の完全一致を最初に探します。次に `reviewer` のような Herdr live name を探し、live name が一致しない場合だけ `codex` のような一意の agent kind を使います。複数の running Herdr session で target が曖昧になる場合は `--session <name>` を付けます。
|
|
73
|
+
|
|
74
|
+
## Agent Skill
|
|
75
|
+
|
|
76
|
+
Agent Skill を追加する前に、Herdsman CLI をインストールして daemon を起動します。次のコマンドで、対応する coding agent に Herdsman の手順を追加します。
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npx skills add ryonakae/herdsman --skill herdsman -g
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Herdsman skill は agent の status、compact history、直近の tool result を構造化データとして読み取ります。agent の確認だけなら、Herdsman skill を単独で使えます。
|
|
83
|
+
|
|
84
|
+
workspace、tab、pane、terminal input/output、wait も agent から操作する場合は、公式 Herdr skill を追加します。
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx skills add ogulcancelik/herdr --skill herdr -g
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Pi extension
|
|
91
|
+
|
|
92
|
+
Piからextensionをインストールします。
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pi install npm:@dorokuma/herdsman-pi
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
extensionにはPi 0.80.6以降が必要です。PiがHerdr内で動くとHerdsman daemonに接続します。接続中のPiはoffの状態でも正確なPi session pathをpresence identityとして登録します。extensionはturnごとのtool resultや最終messageのtelemetryを送信しません。
|
|
99
|
+
|
|
100
|
+
Piで`/herdsman on`を入力すると、そのterminalが現在のHerdr sessionとworkspaceにおける唯一のHerdsman ownerになります。cached current-workspace agent context、pending件数、agent update、自動wakeを受け取るのはownerだけです。contextからowner自身のPi terminalを除き、ほかのPi terminalを含めます。通常のpromptではdaemon RPCや履歴読み込みを待たず、local cacheのsnapshotを挿入します。起動直後、reconnect直後、scope移動直後はsnapshotが届くまでcontextが一時的にない場合があります。
|
|
101
|
+
|
|
102
|
+
agentが完了またはblockedになると、visibleなHerdsman turnを1回開始します。通常のuser runが実行中なら、Herdsmanはsettleを待ちます。themed cardは最大3件を表示し、Piのexpand keyで全outcomeと長さを制限した最終responseを確認できます。nameがあるagentは`reviewer · Codex`、ないagentは`Codex`と表示します。agentの出力は信頼できない参考情報として扱い、Piは既存のuser requestに必要な作業だけを続けます。
|
|
103
|
+
|
|
104
|
+
現在のPiの状態は`/herdsman`または`/herdsman status`で確認し、`/herdsman off`でそのPiのowner動作を解除します。offにしても別のownerへは影響しません。offまたはnon-ownerのPiは後でclaimできるよう接続を保ちますが、hidden agent context、pending件数、update、wakeは受け取りません。onのPiだけがfooterに`◆ Herdsman`を表示し、未処理のoutcomeがある間は`· N agent updates`が付きます。updateを含むturnが最終assistant responseを生成してsettleし、元のeventをacknowledgeすると件数が消えます。直前までonだったPiが接続を失うと、復旧中は`◇ Herdsman · reconnecting`を表示します。ownerがいない間はoutcomeを配信せず、その間に発生したoutcomeは後からclaimしてもreplayしません。reload、reconnect、別Piによる直接のowner交代では、未acknowledgedのoutcomeを保持します。ownershipはPi sessionの切り替えやpaneの移動後も同じHerdr terminalに追従し、そのterminalがgrace periodを超えて切断された場合は解除されます。
|
|
105
|
+
|
|
106
|
+
## Herdr plugin
|
|
107
|
+
|
|
108
|
+
任意のpluginはGitHub Releaseのtagからインストールします。
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
herdr plugin install ryonakae/herdsman/packages/herdsman-herdr-plugin --ref v0.4.0 --yes
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
plugin は Herdsman daemon に接続し、current Herdr workspace の compact agent row を Herdr UI に表示します。row には live name と runtime kind の column、cached history の抜粋が含まれます。Herdrはrepository subdirectoryからpluginをインストールします。npmには公開せず、CLIとPi extensionだけを使う場合は不要です。
|
|
115
|
+
|
|
116
|
+
## パッケージ
|
|
117
|
+
|
|
118
|
+
| Path | 配布方法 | Purpose |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| repository root | npm: `@dorokuma/herdsman` | Herdsman CLIとdaemon。 |
|
|
121
|
+
| `packages/herdsman-pi` | npm: `@dorokuma/herdsman-pi` | agent historyとagent updateのPi extension。 |
|
|
122
|
+
| `packages/herdsman-herdr-plugin` | GitHub Releaseのsubdirectory | 任意のHerdr UI integration。npm packageではありません。 |
|
|
123
|
+
|
|
124
|
+
## 開発
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pnpm install
|
|
128
|
+
pnpm check
|
|
129
|
+
pnpm build
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
package検証、npm公開、GitHub Releaseの手順は[Releasing Herdsman](./docs/releasing.md)に記載しています。
|
|
133
|
+
|
|
134
|
+
DB schema を変えたら次も実行します。
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pnpm db:generate
|
|
138
|
+
pnpm db:check
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## ライセンス
|
|
142
|
+
|
|
143
|
+
[MIT](./LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Credits / Acknowledgements
|
|
5
|
+
|
|
6
|
+
herdsman is forked from ryonakae/shepherd at commit dfdd3a2 (v0.5.1). Thanks to the original author, Ryo Nakae, and the upstream project.
|
|
7
|
+
|
|
8
|
+
Upstream: https://github.com/ryonakae/shepherd
|
|
9
|
+
|
|
10
|
+
# Herdsman
|
|
11
|
+
|
|
12
|
+
<!-- README-I18N:START -->
|
|
13
|
+
**English** | [日本語](./README.ja.md)
|
|
14
|
+
<!-- README-I18N:END -->
|
|
15
|
+
|
|
16
|
+
Herdsman is a daemon-backed observability layer for coding agents running in Herdr. It provides two interfaces over the same durable agent index: pull-based CLI access to structured history, and owner-scoped Pi notifications with cached context and automatic wake.
|
|
17
|
+
|
|
18
|
+
Herdr's `herdr agent read` reads terminal streams or scrollback. Herdsman instead reads agent session data so callers can retrieve work status, structured message excerpts, compact tool results, and unread outcomes without parsing terminal output. Herdsman is read-only; use the official Herdr CLI or skill for agent start, prompts, waits, pane operations, and terminal control.
|
|
19
|
+
|
|
20
|
+
Herdsman currently supports session history from Claude Code, Codex, Gemini CLI, OpenCode, and Pi.
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
- Node.js >= 24.18.0
|
|
25
|
+
- Herdr >= 0.7.0
|
|
26
|
+
- Pi >= 0.80.6 when using `herdsman-pi`
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install --global @dorokuma/herdsman
|
|
32
|
+
herdsman help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Install from source
|
|
36
|
+
|
|
37
|
+
Source builds also require pnpm >= 11.9.0.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/ryonakae/herdsman.git
|
|
41
|
+
cd herdsman
|
|
42
|
+
pnpm install
|
|
43
|
+
pnpm build
|
|
44
|
+
npm install --global . --ignore-scripts
|
|
45
|
+
herdsman help
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Start the daemon
|
|
49
|
+
|
|
50
|
+
Herdsman agent commands and Pi notifications require the daemon. The daemon watches all running Herdr sessions reported by `herdr session list --json`, rescans them every 60 seconds, and does not index stopped Herdr sessions. Runtime files live in `~/.herdsman` by default. Set `SHEPHERD_HOME` to use another directory.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
herdsman daemon start
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Main commands
|
|
57
|
+
|
|
58
|
+
- `herdsman agent list`: returns the daemon's latest cached status and last user / assistant excerpts for the selected workspace. Check each row's `updatedAt` when freshness matters.
|
|
59
|
+
- `herdsman agent get <target>`: performs an explicit detail lookup and returns one agent's metadata, compact history, and latest compact tool result.
|
|
60
|
+
- `herdsman agent read <target> --limit N`: performs an explicit history read and returns the latest N user / assistant / compact `tool_result` messages.
|
|
61
|
+
|
|
62
|
+
Each agent record keeps Herdr's optional live `name`, such as `reviewer`, separate from its runtime `agent` kind, such as `codex`. Human list output uses distinct `name` and `agent` columns, and JSON returns both fields. Inside a Herdr workspace, Herdsman selects the current workspace automatically.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
herdsman agent list --json
|
|
66
|
+
herdsman agent get reviewer --json
|
|
67
|
+
herdsman agent read reviewer --limit 20 --json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
From outside Herdr, pass a scope.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
herdsman agent list --all --json
|
|
74
|
+
herdsman agent list --workspace wB --json
|
|
75
|
+
herdsman agent get reviewer --workspace wB --json
|
|
76
|
+
herdsman agent read wB:p2 --workspace wB --limit 20 --json
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`<target>` first matches an exact pane id, terminal id, or Herdsman agent id in the selected scope. It then matches an exact Herdr live name such as `reviewer`; when no live name matches, it falls back to a unique agent kind such as `codex`. Use `--session <name>` when a target is ambiguous across running Herdr sessions.
|
|
80
|
+
|
|
81
|
+
## Agent Skill
|
|
82
|
+
|
|
83
|
+
Install the Herdsman CLI and start its daemon before adding the Agent Skill. Then add the Herdsman instructions to supported coding agents:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npx skills add ryonakae/herdsman --skill herdsman -g
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The Herdsman skill reads structured agent status, compact history, and recent tool results. Use it alone for agent inspection.
|
|
90
|
+
|
|
91
|
+
Add the official Herdr skill when an agent needs to control workspaces, tabs, panes, terminal input/output, or waits:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx skills add ogulcancelik/herdr --skill herdr -g
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Pi extension
|
|
98
|
+
|
|
99
|
+
Install the extension through Pi:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pi install npm:@dorokuma/herdsman-pi
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The extension requires Pi 0.80.6 or newer and connects to the Herdsman daemon when Pi runs inside Herdr. Each connected Pi registers its exact Pi session path as presence identity, including while off. The extension does not send per-turn tool-result or final-message telemetry.
|
|
106
|
+
|
|
107
|
+
Enter `/herdsman on` in Pi to make this terminal the sole Herdsman owner for its current Herdr session and workspace. Only the owner receives cached current-workspace agent context, pending counts, agent updates, and automatic wake. Its context excludes its own Pi terminal and includes other Pi terminals. A normal prompt injects the locally cached snapshot without daemon RPC or history reads, so context can be temporarily absent after startup, reconnect, or scope movement until a snapshot arrives.
|
|
108
|
+
|
|
109
|
+
Completed or blocked agent outcomes start one visible Herdsman turn. If a normal user run is active, Herdsman waits for it to settle. The themed card shows up to three agents; use Pi's expand key to see every outcome and its bounded final response. Named agents appear as `reviewer · Codex`, with `Codex` as the unnamed fallback. Agent output is untrusted evidence: Pi may continue only the existing user request and must not expand its scope.
|
|
110
|
+
|
|
111
|
+
Use `/herdsman` or `/herdsman status` to inspect the current Pi, and `/herdsman off` to release owner behavior for that Pi. Turning one Pi off does not affect another owner. An off or non-owner Pi remains connected for a later claim, but receives no hidden agent context, pending counts, updates, or wake. The active Pi shows `◆ Herdsman`; pending outcomes add `· N agent updates` until a turn containing them produces a final assistant response, settles, and acknowledges every underlying event. A previously active Pi shows `◇ Herdsman · reconnecting` during transport recovery. With no owner, outcomes are not delivered, and outcomes created during the ownerless period are not replayed by a later claim. Reloads, reconnects, and direct replacement by another Pi preserve unacknowledged outcomes. Ownership follows the Herdr terminal across Pi session replacement and pane movement, and clears when that terminal remains disconnected beyond the grace period.
|
|
112
|
+
|
|
113
|
+
## Herdr plugin
|
|
114
|
+
|
|
115
|
+
Install the optional plugin from the GitHub release tag:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
herdr plugin install ryonakae/herdsman/packages/herdsman-herdr-plugin --ref v0.4.0 --yes
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The plugin connects to the Herdsman daemon and shows compact agent rows for the current Herdr workspace, including separate live-name and runtime-kind columns plus cached history excerpts. Herdr installs it from the repository subdirectory; it is not published to npm or required for the CLI and Pi extension.
|
|
122
|
+
|
|
123
|
+
## Packages
|
|
124
|
+
|
|
125
|
+
| Path | Distribution | Purpose |
|
|
126
|
+
| --- | --- | --- |
|
|
127
|
+
| repository root | npm: `@dorokuma/herdsman` | Herdsman CLI and daemon. |
|
|
128
|
+
| `packages/herdsman-pi` | npm: `@dorokuma/herdsman-pi` | Pi extension for agent history and agent updates. |
|
|
129
|
+
| `packages/herdsman-herdr-plugin` | GitHub release subdirectory | Optional Herdr UI integration; not an npm package. |
|
|
130
|
+
|
|
131
|
+
## Development
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pnpm install
|
|
135
|
+
pnpm check
|
|
136
|
+
pnpm build
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
See [Releasing Herdsman](./docs/releasing.md) for package validation, npm publication, and GitHub Release steps.
|
|
140
|
+
|
|
141
|
+
DB schema changes require:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
pnpm db:generate
|
|
145
|
+
pnpm db:check
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## License
|
|
149
|
+
|
|
150
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.config.d.ts","sourceRoot":"","sources":["../drizzle.config.ts"],"names":[],"mappings":";AAEA,wBAIG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.config.js","sourceRoot":"","sources":["../drizzle.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,eAAe,YAAY,CAAC;IAC1B,OAAO,EAAE,QAAQ;IACjB,GAAG,EAAE,WAAW;IAChB,MAAM,EAAE,oBAAoB;CAC7B,CAAC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentHistoryMessage, AgentHistoryRef } from "../observability/contracts.js";
|
|
2
|
+
import { type AgentHistoryReader } from "./readers.js";
|
|
3
|
+
export declare class ClaudeHistoryReader implements AgentHistoryReader {
|
|
4
|
+
canRead(ref: AgentHistoryRef): boolean;
|
|
5
|
+
read(ref: AgentHistoryRef, options?: {
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): Promise<AgentHistoryMessage[]>;
|
|
8
|
+
readCompact(ref: AgentHistoryRef): Promise<import("../observability/contracts.js").CompactAgentHistory>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=claude-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-reader.d.ts","sourceRoot":"","sources":["../../../src/agent-history/claude-reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACzF,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,cAAc,CAAC;AAItB,qBAAa,mBAAoB,YAAW,kBAAkB;IAC5D,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;IAIhC,IAAI,CACR,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/B,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAwC3B,WAAW,CAAC,GAAG,EAAE,eAAe;CAGvC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { compactFromMessages, limitMessages, readJsonl, } from "./readers.js";
|
|
2
|
+
import { messageRef, textFromContent, timestampFrom } from "./text.js";
|
|
3
|
+
import { compactToolResult } from "./tool-compaction.js";
|
|
4
|
+
export class ClaudeHistoryReader {
|
|
5
|
+
canRead(ref) {
|
|
6
|
+
return ref.source === "claude-jsonl" && Boolean(ref.path ?? ref.value);
|
|
7
|
+
}
|
|
8
|
+
async read(ref, options = {}) {
|
|
9
|
+
const path = ref.path ?? ref.value;
|
|
10
|
+
const messages = [];
|
|
11
|
+
for (const entry of await readJsonl(path)) {
|
|
12
|
+
const type = stringValue(entry.value.type);
|
|
13
|
+
if (!type || ignoredTypes.has(type))
|
|
14
|
+
continue;
|
|
15
|
+
const message = record(entry.value.message);
|
|
16
|
+
const uuid = stringValue(entry.value.uuid) ?? stringValue(entry.value.id);
|
|
17
|
+
const timestamp = timestampFrom(entry.value.timestamp) ?? timestampFrom(message.timestamp);
|
|
18
|
+
const refValue = messageRef(path, uuid ?? undefined, entry.line);
|
|
19
|
+
const role = stringValue(message.role) ?? (type === "assistant" || type === "user" ? type : null);
|
|
20
|
+
const toolResult = toolResultFrom(entry.value, message);
|
|
21
|
+
if (toolResult) {
|
|
22
|
+
const compact = compactToolResult({
|
|
23
|
+
isError: toolResult.isError,
|
|
24
|
+
ref: refValue,
|
|
25
|
+
text: toolResult.text,
|
|
26
|
+
toolName: toolResult.toolName,
|
|
27
|
+
});
|
|
28
|
+
messages.push({
|
|
29
|
+
compact,
|
|
30
|
+
ref: refValue,
|
|
31
|
+
role: "tool_result",
|
|
32
|
+
text: compact.text,
|
|
33
|
+
timestamp,
|
|
34
|
+
toolName: toolResult.toolName,
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (role === "user" || role === "assistant") {
|
|
39
|
+
const text = textFromContent(message.content);
|
|
40
|
+
if (text)
|
|
41
|
+
messages.push({ ref: refValue, role, text, timestamp });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return limitMessages(messages, options.limit);
|
|
45
|
+
}
|
|
46
|
+
async readCompact(ref) {
|
|
47
|
+
return compactFromMessages(ref, await this.read(ref));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const ignoredTypes = new Set(["attachment", "file-history-snapshot", "mode", "permission-mode"]);
|
|
51
|
+
function toolResultFrom(entry, message) {
|
|
52
|
+
const topToolUseResult = entry.toolUseResult;
|
|
53
|
+
if (topToolUseResult !== undefined && topToolUseResult !== null) {
|
|
54
|
+
return {
|
|
55
|
+
isError: entry.isError === true || message.isError === true,
|
|
56
|
+
text: typeof topToolUseResult === "string" ? topToolUseResult : JSON.stringify(topToolUseResult),
|
|
57
|
+
toolName: stringValue(entry.toolName) ?? stringValue(message.toolName) ?? "unknown",
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const content = message.content;
|
|
61
|
+
if (Array.isArray(content)) {
|
|
62
|
+
const toolBlocks = content.filter((block) => {
|
|
63
|
+
if (typeof block !== "object" || block === null)
|
|
64
|
+
return false;
|
|
65
|
+
const record = block;
|
|
66
|
+
return record.type === "tool_result" || record.type === "tool_result_delta";
|
|
67
|
+
});
|
|
68
|
+
if (toolBlocks.length > 0) {
|
|
69
|
+
return {
|
|
70
|
+
isError: toolBlocks.some((block) => typeof block === "object" &&
|
|
71
|
+
block !== null &&
|
|
72
|
+
block.is_error === true),
|
|
73
|
+
text: toolBlocks
|
|
74
|
+
.map((block) => textFromContent(record(block).content) ?? JSON.stringify(block))
|
|
75
|
+
.join("\n"),
|
|
76
|
+
toolName: stringValue(record(toolBlocks[0]).name) ??
|
|
77
|
+
stringValue(record(toolBlocks[0]).toolName) ??
|
|
78
|
+
"unknown",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function record(value) {
|
|
85
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
86
|
+
}
|
|
87
|
+
function stringValue(value) {
|
|
88
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=claude-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-reader.js","sourceRoot":"","sources":["../../../src/agent-history/claude-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentHistoryMessage, AgentHistoryRef } from "../observability/contracts.js";
|
|
2
|
+
import { type AgentHistoryReader } from "./readers.js";
|
|
3
|
+
export declare class CodexHistoryReader implements AgentHistoryReader {
|
|
4
|
+
canRead(ref: AgentHistoryRef): boolean;
|
|
5
|
+
read(ref: AgentHistoryRef, options?: {
|
|
6
|
+
limit?: number;
|
|
7
|
+
}): Promise<AgentHistoryMessage[]>;
|
|
8
|
+
readCompact(ref: AgentHistoryRef): Promise<import("../observability/contracts.js").CompactAgentHistory>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=codex-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-reader.d.ts","sourceRoot":"","sources":["../../../src/agent-history/codex-reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACzF,OAAO,EACL,KAAK,kBAAkB,EAIxB,MAAM,cAAc,CAAC;AAItB,qBAAa,kBAAmB,YAAW,kBAAkB;IAC3D,OAAO,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO;IAIhC,IAAI,CACR,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAC/B,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAoF3B,WAAW,CAAC,GAAG,EAAE,eAAe;CAGvC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { compactFromMessages, limitMessages, readJsonl, } from "./readers.js";
|
|
2
|
+
import { messageRef, textFromContent, timestampFrom } from "./text.js";
|
|
3
|
+
import { compactToolResult } from "./tool-compaction.js";
|
|
4
|
+
export class CodexHistoryReader {
|
|
5
|
+
canRead(ref) {
|
|
6
|
+
return ref.source === "codex-jsonl" && Boolean(ref.path ?? ref.value);
|
|
7
|
+
}
|
|
8
|
+
async read(ref, options = {}) {
|
|
9
|
+
const path = ref.path ?? ref.value;
|
|
10
|
+
const messages = [];
|
|
11
|
+
const toolNamesByCallId = new Map();
|
|
12
|
+
for (const entry of await readJsonl(path)) {
|
|
13
|
+
const type = stringValue(entry.value.type);
|
|
14
|
+
const payload = record(entry.value.payload);
|
|
15
|
+
const payloadType = stringValue(payload.type);
|
|
16
|
+
const id = stringValue(payload.id) ?? stringValue(payload.call_id) ?? stringValue(entry.value.id);
|
|
17
|
+
const timestamp = timestampFrom(payload.timestamp) ??
|
|
18
|
+
timestampFrom(payload.started_at) ??
|
|
19
|
+
timestampFrom(entry.value.timestamp);
|
|
20
|
+
const refValue = messageRef(path, id ?? undefined, entry.line);
|
|
21
|
+
if (type === "event_msg") {
|
|
22
|
+
if (payloadType === "user_message") {
|
|
23
|
+
const text = stringValue(payload.message);
|
|
24
|
+
if (text && !isSystemCodexMessage(text)) {
|
|
25
|
+
messages.push({ ref: refValue, role: "user", text, timestamp });
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (payloadType === "agent_message") {
|
|
30
|
+
const text = stringValue(payload.message);
|
|
31
|
+
if (text)
|
|
32
|
+
messages.push({ ref: refValue, role: "assistant", text, timestamp });
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (payloadType === "task_complete") {
|
|
36
|
+
const text = stringValue(payload.last_agent_message);
|
|
37
|
+
if (text)
|
|
38
|
+
messages.push({ ref: refValue, role: "assistant", text, timestamp });
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (type !== "response_item")
|
|
43
|
+
continue;
|
|
44
|
+
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
45
|
+
const callId = stringValue(payload.call_id);
|
|
46
|
+
const name = stringValue(payload.name);
|
|
47
|
+
if (callId && name)
|
|
48
|
+
toolNamesByCallId.set(callId, name);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
52
|
+
const callId = stringValue(payload.call_id);
|
|
53
|
+
const toolName = (callId ? toolNamesByCallId.get(callId) : null) ?? "unknown";
|
|
54
|
+
const text = textFromCodexOutput(payload.output);
|
|
55
|
+
const compact = compactToolResult({ isError: false, ref: refValue, text, toolName });
|
|
56
|
+
messages.push({
|
|
57
|
+
compact,
|
|
58
|
+
ref: refValue,
|
|
59
|
+
role: "tool_result",
|
|
60
|
+
text: compact.text,
|
|
61
|
+
timestamp,
|
|
62
|
+
toolName,
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (payloadType === "message") {
|
|
67
|
+
const role = stringValue(payload.role);
|
|
68
|
+
if (role === "developer")
|
|
69
|
+
continue;
|
|
70
|
+
if (role === "user") {
|
|
71
|
+
const text = textFromCodexContent(payload.content, "input_text");
|
|
72
|
+
if (text && !isSystemCodexMessage(text)) {
|
|
73
|
+
messages.push({ ref: refValue, role: "user", text, timestamp });
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (role === "assistant") {
|
|
78
|
+
const text = textFromCodexContent(payload.content, "output_text") ??
|
|
79
|
+
textFromContent(payload.content);
|
|
80
|
+
if (text)
|
|
81
|
+
messages.push({ ref: refValue, role: "assistant", text, timestamp });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return limitMessages(messages, options.limit);
|
|
86
|
+
}
|
|
87
|
+
async readCompact(ref) {
|
|
88
|
+
return compactFromMessages(ref, await this.read(ref));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function textFromCodexContent(content, blockType) {
|
|
92
|
+
if (!Array.isArray(content))
|
|
93
|
+
return typeof content === "string" ? content : null;
|
|
94
|
+
const parts = content
|
|
95
|
+
.map((block) => {
|
|
96
|
+
const item = record(block);
|
|
97
|
+
if (item.type !== blockType)
|
|
98
|
+
return "";
|
|
99
|
+
return stringValue(item.text) ?? "";
|
|
100
|
+
})
|
|
101
|
+
.filter((part) => part.trim().length > 0);
|
|
102
|
+
return parts.length > 0 ? parts.join("\n") : null;
|
|
103
|
+
}
|
|
104
|
+
function textFromCodexOutput(value) {
|
|
105
|
+
if (typeof value === "string")
|
|
106
|
+
return value;
|
|
107
|
+
return JSON.stringify(value ?? "");
|
|
108
|
+
}
|
|
109
|
+
function isSystemCodexMessage(text) {
|
|
110
|
+
const trimmed = text.trim();
|
|
111
|
+
return trimmed.startsWith("<environment_context>") || trimmed.startsWith("<user_instructions>");
|
|
112
|
+
}
|
|
113
|
+
function record(value) {
|
|
114
|
+
return typeof value === "object" && value !== null ? value : {};
|
|
115
|
+
}
|
|
116
|
+
function stringValue(value) {
|
|
117
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=codex-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-reader.js","sourceRoot":"","sources":["../../../src/agent-history/codex-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AgentHistoryRef, AgentSessionRef } from "../observability/contracts.js";
|
|
2
|
+
export declare const DISCOVERY_RECENCY_GRACE_MS: number;
|
|
3
|
+
export type AgentHistoryLookupInput = {
|
|
4
|
+
agent: string | null;
|
|
5
|
+
agentSession: AgentSessionRef | null;
|
|
6
|
+
cwd: string | null;
|
|
7
|
+
foregroundCwd: string | null;
|
|
8
|
+
firstSeenAtMs?: number;
|
|
9
|
+
homeDir?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function discoverAgentHistory(input: AgentHistoryLookupInput): Promise<AgentHistoryRef | null>;
|
|
12
|
+
export declare function historySourceFromSessionRef(ref: AgentSessionRef): AgentHistoryRef["source"];
|
|
13
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/agent-history/discovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AASrF,eAAO,MAAM,0BAA0B,QAAc,CAAC;AAEtD,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AASF,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAyDjC;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,eAAe,GAAG,eAAe,CAAC,QAAQ,CAAC,CAS3F"}
|