trailhound 0.2.1
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 +118 -0
- package/README.md +325 -0
- package/dist/adapters/claude-code.d.ts +25 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +88 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/codex.d.ts +25 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +72 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/openclaw.d.ts +49 -0
- package/dist/adapters/openclaw.d.ts.map +1 -0
- package/dist/adapters/openclaw.js +180 -0
- package/dist/adapters/openclaw.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +226 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/run-store.d.ts +15 -0
- package/dist/core/run-store.d.ts.map +1 -0
- package/dist/core/run-store.js +88 -0
- package/dist/core/run-store.js.map +1 -0
- package/dist/core/trace-writer.d.ts +22 -0
- package/dist/core/trace-writer.d.ts.map +1 -0
- package/dist/core/trace-writer.js +91 -0
- package/dist/core/trace-writer.js.map +1 -0
- package/dist/core/trailhound.d.ts +42 -0
- package/dist/core/trailhound.d.ts.map +1 -0
- package/dist/core/trailhound.js +351 -0
- package/dist/core/trailhound.js.map +1 -0
- package/dist/policies/policy-engine.d.ts +15 -0
- package/dist/policies/policy-engine.d.ts.map +1 -0
- package/dist/policies/policy-engine.js +205 -0
- package/dist/policies/policy-engine.js.map +1 -0
- package/dist/recorders/filesystem-monitor.d.ts +33 -0
- package/dist/recorders/filesystem-monitor.d.ts.map +1 -0
- package/dist/recorders/filesystem-monitor.js +262 -0
- package/dist/recorders/filesystem-monitor.js.map +1 -0
- package/dist/recorders/git-snapshotter.d.ts +17 -0
- package/dist/recorders/git-snapshotter.d.ts.map +1 -0
- package/dist/recorders/git-snapshotter.js +116 -0
- package/dist/recorders/git-snapshotter.js.map +1 -0
- package/dist/recorders/network-monitor.d.ts +18 -0
- package/dist/recorders/network-monitor.d.ts.map +1 -0
- package/dist/recorders/network-monitor.js +67 -0
- package/dist/recorders/network-monitor.js.map +1 -0
- package/dist/recorders/network-proxy.d.ts +31 -0
- package/dist/recorders/network-proxy.d.ts.map +1 -0
- package/dist/recorders/network-proxy.js +163 -0
- package/dist/recorders/network-proxy.js.map +1 -0
- package/dist/recorders/process-monitor.d.ts +14 -0
- package/dist/recorders/process-monitor.d.ts.map +1 -0
- package/dist/recorders/process-monitor.js +47 -0
- package/dist/recorders/process-monitor.js.map +1 -0
- package/dist/recorders/process-wrapper.d.ts +37 -0
- package/dist/recorders/process-wrapper.d.ts.map +1 -0
- package/dist/recorders/process-wrapper.js +152 -0
- package/dist/recorders/process-wrapper.js.map +1 -0
- package/dist/recorders/secret-detector.d.ts +26 -0
- package/dist/recorders/secret-detector.d.ts.map +1 -0
- package/dist/recorders/secret-detector.js +148 -0
- package/dist/recorders/secret-detector.js.map +1 -0
- package/dist/reports/report-generator.d.ts +19 -0
- package/dist/reports/report-generator.d.ts.map +1 -0
- package/dist/reports/report-generator.js +274 -0
- package/dist/reports/report-generator.js.map +1 -0
- package/dist/types/index.d.ts +132 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/exec.d.ts +6 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +10 -0
- package/dist/utils/exec.js.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# PolyForm Noncommercial License 1.0.0
|
|
2
|
+
|
|
3
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
In order to get any license under these terms, you must agree
|
|
8
|
+
to them as both strict obligations and conditions to all
|
|
9
|
+
your licenses.
|
|
10
|
+
|
|
11
|
+
## Copyright License
|
|
12
|
+
|
|
13
|
+
The licensor grants you a copyright license for the software
|
|
14
|
+
to do everything you might do with the software that would
|
|
15
|
+
otherwise infringe the licensor's copyright, except
|
|
16
|
+
limitations described below.
|
|
17
|
+
|
|
18
|
+
## Noncommercial Purposes
|
|
19
|
+
|
|
20
|
+
Any noncommercial purpose is a permitted purpose.
|
|
21
|
+
|
|
22
|
+
## Commercial Purposes
|
|
23
|
+
|
|
24
|
+
Any commercial purpose is a **separate purpose** from
|
|
25
|
+
noncommercial purposes. A separate purpose requires a
|
|
26
|
+
separate agreement with the licensor.
|
|
27
|
+
|
|
28
|
+
Commercial purposes include any use of the software that
|
|
29
|
+
primarily aims at or results in:
|
|
30
|
+
|
|
31
|
+
* **commercial advantage** or **private monetary compensation**
|
|
32
|
+
* **advertising or marketing** for commercial products or services
|
|
33
|
+
* use in any product or service sold, licensed, or provided for a fee
|
|
34
|
+
* use to provide **software as a service** or **platform as a service**
|
|
35
|
+
* use in research or development for a commercial product or service
|
|
36
|
+
|
|
37
|
+
Noncommercial purposes include:
|
|
38
|
+
|
|
39
|
+
* personal use, study, or hobby projects
|
|
40
|
+
* **teaching and academic research** at educational institutions
|
|
41
|
+
* **government use** by government agencies and departments
|
|
42
|
+
* use by **registered charities and non-profit organizations**
|
|
43
|
+
* use in **open source projects** that are themselves noncommercial
|
|
44
|
+
* **journalism and news reporting**
|
|
45
|
+
|
|
46
|
+
## Personal Uses
|
|
47
|
+
|
|
48
|
+
Personal use for research, experiment, and testing for
|
|
49
|
+
the benefit of public knowledge, personal study, private
|
|
50
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
51
|
+
observance, without any anticipated commercial application,
|
|
52
|
+
is use for noncommercial purposes.
|
|
53
|
+
|
|
54
|
+
## Small-Scale Production
|
|
55
|
+
|
|
56
|
+
You may use the software to develop, produce, or create
|
|
57
|
+
products or services for up to ten (10) individual end
|
|
58
|
+
users per month without triggering commercial purposes.
|
|
59
|
+
|
|
60
|
+
## No Other Rights
|
|
61
|
+
|
|
62
|
+
These terms do not allow you to sublicense or transfer any
|
|
63
|
+
of your licenses to anyone else, or try to use them to
|
|
64
|
+
make any legal claim against anyone else.
|
|
65
|
+
|
|
66
|
+
## Defensive Termination
|
|
67
|
+
|
|
68
|
+
If you make any legal claim against anyone accusing the software
|
|
69
|
+
of infringing any patent you have, or of infringing any other
|
|
70
|
+
intellectual property right you have:
|
|
71
|
+
|
|
72
|
+
* your copyright license for the software ends automatically
|
|
73
|
+
* your patent license for the software ends automatically
|
|
74
|
+
|
|
75
|
+
Even if your legal claim is withdrawn or settled, your licenses
|
|
76
|
+
terminate and do not automatically resume.
|
|
77
|
+
|
|
78
|
+
## No Liability
|
|
79
|
+
|
|
80
|
+
***As far as the law allows, the software comes as is, without
|
|
81
|
+
any warranty or condition, and the licensor will not be
|
|
82
|
+
liable to anyone for any damages related to the software or
|
|
83
|
+
this license, under any kind of legal claim.***
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Commercial Licensing
|
|
88
|
+
|
|
89
|
+
For commercial use, please contact:
|
|
90
|
+
|
|
91
|
+
Samuel Gorzalnik
|
|
92
|
+
gorzalniksamuel@gmail.com
|
|
93
|
+
|
|
94
|
+
A separate commercial license agreement is required for:
|
|
95
|
+
- Commercial products or services
|
|
96
|
+
- SaaS/PaaS offerings
|
|
97
|
+
- Internal corporate use
|
|
98
|
+
- Any for-profit application
|
|
99
|
+
|
|
100
|
+
Commercial licenses are available on a case-by-case basis.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Summary
|
|
105
|
+
|
|
106
|
+
| Use Case | Allowed? |
|
|
107
|
+
|----------|----------|
|
|
108
|
+
| Personal projects | ✅ Yes |
|
|
109
|
+
| Open source (noncommercial) | ✅ Yes |
|
|
110
|
+
| Education & research | ✅ Yes |
|
|
111
|
+
| Government use | ✅ Yes |
|
|
112
|
+
| Non-profits & charities | ✅ Yes |
|
|
113
|
+
| Small scale (<10 users/month) | ✅ Yes |
|
|
114
|
+
| Commercial products/services | ❌ Requires license |
|
|
115
|
+
| SaaS/PaaS | ❌ Requires license |
|
|
116
|
+
| Corporate internal use | ❌ Requires license |
|
|
117
|
+
|
|
118
|
+
Contact for commercial licensing options.
|
package/README.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# Trailhound 🐕
|
|
2
|
+
|
|
3
|
+
> **Sniff out what your AI agent is doing.**
|
|
4
|
+
|
|
5
|
+
Know exactly what your AI agent did—before you review the diff.
|
|
6
|
+
|
|
7
|
+
[](https://github.com/gorzalniksamuel/trailhound/actions)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Why Trailhound?
|
|
13
|
+
|
|
14
|
+
AI coding agents are evolving from autocomplete into autonomous operators. You tell them "fix the bug," and they:
|
|
15
|
+
|
|
16
|
+
- Touch files you didn't expect
|
|
17
|
+
- Install dependencies without asking
|
|
18
|
+
- Call external APIs and domains
|
|
19
|
+
- Access secrets and credentials
|
|
20
|
+
- Run shell commands in your environment
|
|
21
|
+
|
|
22
|
+
**Trailhound tracks everything:**
|
|
23
|
+
|
|
24
|
+
- 📁 **Files touched** - Reads, writes, deletes across your repo
|
|
25
|
+
- 🖥️ **Commands run** - Shell executions with args and exit codes
|
|
26
|
+
- 📦 **Packages installed** - npm, pip, cargo, and more
|
|
27
|
+
- 🌐 **Network calls** - External domains and APIs contacted
|
|
28
|
+
- 🔐 **Secrets accessed** - .env, SSH keys, credentials
|
|
29
|
+
- 📝 **Git changes** - Complete before/after diffs
|
|
30
|
+
- ⚠️ **Risk analysis** - Behavioral anomalies and policy violations
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Install
|
|
38
|
+
npm install -g trailhound
|
|
39
|
+
|
|
40
|
+
# Record a Codex session
|
|
41
|
+
trailhound run -- codex
|
|
42
|
+
|
|
43
|
+
# Record Claude Code
|
|
44
|
+
trailhound run -- claude-code
|
|
45
|
+
|
|
46
|
+
# View the report
|
|
47
|
+
trailhound report
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Example Report
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Run: fix-auth-bug
|
|
56
|
+
Agent: codex
|
|
57
|
+
Duration: 14m 22s
|
|
58
|
+
Risk Score: Medium ⚠️
|
|
59
|
+
Tracked By: Trailhound
|
|
60
|
+
|
|
61
|
+
Summary:
|
|
62
|
+
- Modified 6 files
|
|
63
|
+
- Ran 18 shell commands
|
|
64
|
+
- Installed 2 npm packages
|
|
65
|
+
- Contacted 4 external domains
|
|
66
|
+
- ⚠️ Read sensitive file: .env.local
|
|
67
|
+
- ✅ Tests passed
|
|
68
|
+
|
|
69
|
+
Notable Events:
|
|
70
|
+
🔴 [WARN] Agent read .env.local after task prompt did not mention secrets
|
|
71
|
+
🔴 [WARN] New dependency added: jsonwebtoken@latest
|
|
72
|
+
✅ [OK] Tests passed: npm test
|
|
73
|
+
✅ [OK] Final git diff limited to src/auth/* and package-lock.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Sniffing Out Agent Behavior
|
|
79
|
+
|
|
80
|
+
Like a bloodhound tracking a scent, **Trailhound follows the trail** your AI agent leaves behind:
|
|
81
|
+
|
|
82
|
+
- Which files were sniffed before the fix?
|
|
83
|
+
- What commands were run in the background?
|
|
84
|
+
- Where did the agent wander on the network?
|
|
85
|
+
- Did it dig into any secrets?
|
|
86
|
+
|
|
87
|
+
**Full trace visibility. No more blind trust.**
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Supported Agents
|
|
92
|
+
|
|
93
|
+
| Agent | Status | Notes |
|
|
94
|
+
|-------|--------|-------|
|
|
95
|
+
| [OpenAI Codex](https://github.com/openai/codex) | ✅ Works | CLI wrapper mode |
|
|
96
|
+
| [Claude Code](https://github.com/anthropics/claude-code) | ✅ Works | Native PTY capture |
|
|
97
|
+
| [OpenCode](https://github.com/opencode-ai/opencode) | ✅ Works | Generic process wrapper |
|
|
98
|
+
| [OpenClaw](https://github.com/openclaw/openclaw) | ✅ Works | Detects delegated sub-agents |
|
|
99
|
+
| Pipedream / Pi | 🔄 Planned | Via OpenClaw integration |
|
|
100
|
+
| Custom agents | ✅ Works | Any CLI-process agent |
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## What's Recorded?
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
.trailhound/
|
|
108
|
+
└── runs/
|
|
109
|
+
└── 2026-05-08T10-22-31Z_fix-auth-bug/
|
|
110
|
+
├── manifest.json # Run metadata
|
|
111
|
+
├── events.jsonl # Time-ordered event stream
|
|
112
|
+
├── terminal.cast # Terminal transcript (asciicast v2)
|
|
113
|
+
├── git-before.patch # Git state before
|
|
114
|
+
├── git-after.patch # Git state after
|
|
115
|
+
├── files/ # Snapshots of modified files
|
|
116
|
+
├── network.json # Domain/connection log
|
|
117
|
+
├── packages.json # Dependency changes
|
|
118
|
+
├── report.md # Human-readable summary
|
|
119
|
+
└── report.html # Interactive HTML report
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Features
|
|
125
|
+
|
|
126
|
+
- 🔍 **Universal Agent Support** - Works with any agent via process wrapper
|
|
127
|
+
- 📊 **Rich Reports** - Markdown, HTML, and terminal output
|
|
128
|
+
- 🔐 **Secret Detection** - Warns when agents access sensitive files
|
|
129
|
+
- 📈 **Risk Scoring** - Explainable, rule-based risk assessment
|
|
130
|
+
- 🎬 **Replay Mode** - Step through what the agent did
|
|
131
|
+
- 🔄 **Git Integration** - Pre/post snapshots and diff tracking
|
|
132
|
+
- 🛡️ **Policy Engine** - Optional blocking/warning for risky actions
|
|
133
|
+
- 🧩 **MCP Proxy** - Intercept and log MCP tool calls
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Policy Configuration
|
|
138
|
+
|
|
139
|
+
Create `.trailhound/policy.yml` to set boundaries:
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
mode: warn # off | record | warn | enforce
|
|
143
|
+
|
|
144
|
+
allowed_paths:
|
|
145
|
+
- src/**
|
|
146
|
+
- tests/**
|
|
147
|
+
- package.json
|
|
148
|
+
- package-lock.json
|
|
149
|
+
|
|
150
|
+
blocked_paths:
|
|
151
|
+
- .env*
|
|
152
|
+
- ~/.ssh/**
|
|
153
|
+
- ~/.aws/**
|
|
154
|
+
|
|
155
|
+
groups:
|
|
156
|
+
secrets:
|
|
157
|
+
warn: true
|
|
158
|
+
network:
|
|
159
|
+
unknown_domains: warn
|
|
160
|
+
packages:
|
|
161
|
+
require_approval: true
|
|
162
|
+
block_latest: true
|
|
163
|
+
|
|
164
|
+
commands:
|
|
165
|
+
block:
|
|
166
|
+
- "rm -rf /"
|
|
167
|
+
- "curl * | sh"
|
|
168
|
+
require_approval:
|
|
169
|
+
- "npm install *"
|
|
170
|
+
- "pip install *"
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Installation
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# From npm (coming soon)
|
|
179
|
+
npm install -g trailhound
|
|
180
|
+
|
|
181
|
+
# From source
|
|
182
|
+
git clone https://github.com/gorzalniksamuel/trailhound.git
|
|
183
|
+
cd trailhound
|
|
184
|
+
npm install
|
|
185
|
+
npm run build
|
|
186
|
+
npm link
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## CLI Usage
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
trailhound run -- <agent-command> # Record a session
|
|
195
|
+
trailhound report [run-id] # Generate report
|
|
196
|
+
trailhound list # List recorded runs
|
|
197
|
+
trailhound replay <run-id> # Replay session
|
|
198
|
+
trailhound compare <run-a> <run-b> # Compare runs
|
|
199
|
+
trailhound tui # Interactive TUI
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Usage
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Record a session
|
|
208
|
+
trailhound run -- <command>
|
|
209
|
+
|
|
210
|
+
# Examples:
|
|
211
|
+
trailhound run -- codex
|
|
212
|
+
trailhound run -- claude-code
|
|
213
|
+
trailhound run -- openclaw coding-agent
|
|
214
|
+
trailhound run -- npx opencode
|
|
215
|
+
|
|
216
|
+
# View reports
|
|
217
|
+
trailhound report # Last run
|
|
218
|
+
trailhound report --last # Same
|
|
219
|
+
trailhound report <run-id> # Specific run
|
|
220
|
+
trailhound report --html # Open HTML report
|
|
221
|
+
|
|
222
|
+
# List runs
|
|
223
|
+
trailhound list
|
|
224
|
+
trailhound list --json
|
|
225
|
+
|
|
226
|
+
# Replay a session
|
|
227
|
+
trailhound replay <run-id>
|
|
228
|
+
|
|
229
|
+
# Compare two runs
|
|
230
|
+
trailhound compare <run-id-1> <run-id-2>
|
|
231
|
+
|
|
232
|
+
# TUI viewer
|
|
233
|
+
trailhound tui
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Architecture
|
|
239
|
+
|
|
240
|
+
Trailhound uses a lightweight supervisor process that wraps your agent:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
trailhound run -- codex
|
|
244
|
+
|
|
|
245
|
+
v
|
|
246
|
+
+------------------+
|
|
247
|
+
| Supervisor |
|
|
248
|
+
+------------------+
|
|
249
|
+
| | | | |
|
|
250
|
+
v v v v v
|
|
251
|
+
PTY Process Filesystem Git Network
|
|
252
|
+
Recorder Monitor Monitor Snapshotter Proxy
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Key Components:**
|
|
256
|
+
|
|
257
|
+
- **Supervisor** - Owns the agent process tree
|
|
258
|
+
- **PTY Recorder** - Captures terminal I/O
|
|
259
|
+
- **Process Monitor** - Tracks spawned processes
|
|
260
|
+
- **Filesystem Monitor** - Watches file reads/writes
|
|
261
|
+
- **Git Snapshotter** - Pre/post run state
|
|
262
|
+
- **Network Proxy** - Logs external connections
|
|
263
|
+
- **Policy Engine** - Evaluates and enforces rules
|
|
264
|
+
- **Trace Writer** - Streams events to disk
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Documentation
|
|
269
|
+
|
|
270
|
+
- [Architecture](./docs/architecture.md)
|
|
271
|
+
- [Policy Reference](./docs/policy.md)
|
|
272
|
+
- [Trace Format](./docs/trace-format.md)
|
|
273
|
+
- [Contributing](./CONTRIBUTING.md)
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Roadmap
|
|
278
|
+
|
|
279
|
+
- [x] MVP: Basic recording and reporting
|
|
280
|
+
- [ ] Policy engine with warn/block modes
|
|
281
|
+
- [ ] GitHub Action for PR audits
|
|
282
|
+
- [ ] Agent-specific adapters (Codex, Claude)
|
|
283
|
+
- [ ] MCP proxy support
|
|
284
|
+
- [ ] TUI session viewer
|
|
285
|
+
- [ ] Trace replay
|
|
286
|
+
- [ ] Team dashboards
|
|
287
|
+
- [ ] SARIF export
|
|
288
|
+
- [ ] OpenTelemetry integration
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Contributing
|
|
293
|
+
|
|
294
|
+
We welcome contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## License
|
|
299
|
+
|
|
300
|
+
MIT © [Samuel Gorzalnik](https://github.com/gorzalniksamuel)
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Why "Trailhound"?
|
|
305
|
+
|
|
306
|
+
A **bloodhound** is a dog breed famous for its ability to follow a scent trail over great distances, even days old.
|
|
307
|
+
|
|
308
|
+
**Trailhound** applies the same principle to AI agents:
|
|
309
|
+
- Follows the trail of what happened
|
|
310
|
+
- Sniffs out secrets and anomalies
|
|
311
|
+
- Tracks network connections
|
|
312
|
+
- Never loses the scent
|
|
313
|
+
|
|
314
|
+
> *"Like a bloodhound on the trail—Trailhound always knows where your agent has been."*
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Related
|
|
319
|
+
|
|
320
|
+
- [OpenAI Codex](https://github.com/openai/codex) - The agent we're tracking
|
|
321
|
+
- [Claude Code](https://github.com/anthropics/claude-code) - Another agent we follow
|
|
322
|
+
- [OpenClaw](https://github.com/openclaw/openclaw) - Local AI assistant platform
|
|
323
|
+
- [Model Context Protocol (MCP)](https://modelcontextprotocol.io) - Interoperability for agent tools
|
|
324
|
+
|
|
325
|
+
> *"Sniff out what your AI agent is doing."*
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code Adapter
|
|
3
|
+
* Specific handling for Anthropic Claude Code sessions
|
|
4
|
+
*/
|
|
5
|
+
import { AgentEvent } from "../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Claude Code provides rich structured output:
|
|
8
|
+
* - Tool call boundaries
|
|
9
|
+
* - Command approvals
|
|
10
|
+
* - File edits with context
|
|
11
|
+
* - Transcript mapping
|
|
12
|
+
*/
|
|
13
|
+
export declare class ClaudeCodeAdapter {
|
|
14
|
+
private currentToolCall?;
|
|
15
|
+
private edits;
|
|
16
|
+
/**
|
|
17
|
+
* Parse Claude Code output
|
|
18
|
+
*/
|
|
19
|
+
parseOutput(line: string): AgentEvent | null;
|
|
20
|
+
/**
|
|
21
|
+
* Enrich metadata with Claude Code specific info
|
|
22
|
+
*/
|
|
23
|
+
enrichMetadata(metadata: Record<string, unknown>): Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=claude-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAS;IACjC,OAAO,CAAC,KAAK,CAAqD;IAElE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IA0D5C;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAS3E"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code Adapter
|
|
4
|
+
* Specific handling for Anthropic Claude Code sessions
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ClaudeCodeAdapter = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Claude Code provides rich structured output:
|
|
10
|
+
* - Tool call boundaries
|
|
11
|
+
* - Command approvals
|
|
12
|
+
* - File edits with context
|
|
13
|
+
* - Transcript mapping
|
|
14
|
+
*/
|
|
15
|
+
class ClaudeCodeAdapter {
|
|
16
|
+
currentToolCall;
|
|
17
|
+
edits = [];
|
|
18
|
+
/**
|
|
19
|
+
* Parse Claude Code output
|
|
20
|
+
*/
|
|
21
|
+
parseOutput(line) {
|
|
22
|
+
// Detect tool call boundaries
|
|
23
|
+
const toolStart = line.match(/\[Tool:\s*([\w_]+)\]/);
|
|
24
|
+
if (toolStart) {
|
|
25
|
+
this.currentToolCall = toolStart[1];
|
|
26
|
+
return {
|
|
27
|
+
ts: new Date().toISOString(),
|
|
28
|
+
type: "process.exec",
|
|
29
|
+
runId: "",
|
|
30
|
+
toolName: this.currentToolCall,
|
|
31
|
+
agent: "claude-code",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Detect FileRead
|
|
35
|
+
if (line.includes("I'll read")) {
|
|
36
|
+
const fileMatch = line.match(/read\s+([\w/.-]+)/);
|
|
37
|
+
if (fileMatch) {
|
|
38
|
+
return {
|
|
39
|
+
ts: new Date().toISOString(),
|
|
40
|
+
type: "file.read",
|
|
41
|
+
runId: "",
|
|
42
|
+
path: fileMatch[1],
|
|
43
|
+
agent: "claude-code",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Detect Bash command
|
|
48
|
+
if (line.includes("I'll run")) {
|
|
49
|
+
const cmdMatch = line.match(/run[:\s]+(.+)/);
|
|
50
|
+
if (cmdMatch) {
|
|
51
|
+
return {
|
|
52
|
+
ts: new Date().toISOString(),
|
|
53
|
+
type: "process.exec",
|
|
54
|
+
runId: "",
|
|
55
|
+
command: cmdMatch[1].trim(),
|
|
56
|
+
agent: "claude-code",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Detect file edits
|
|
61
|
+
const editMatch = line.match(/Now I'll (?:update|modify|change|edit)\s+([\w/.-]+)/);
|
|
62
|
+
if (editMatch) {
|
|
63
|
+
this.edits.push({ path: editMatch[1] });
|
|
64
|
+
return {
|
|
65
|
+
ts: new Date().toISOString(),
|
|
66
|
+
type: "file.write",
|
|
67
|
+
runId: "",
|
|
68
|
+
path: editMatch[1],
|
|
69
|
+
agent: "claude-code",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Enrich metadata with Claude Code specific info
|
|
76
|
+
*/
|
|
77
|
+
enrichMetadata(metadata) {
|
|
78
|
+
return {
|
|
79
|
+
...metadata,
|
|
80
|
+
claudeCode: {
|
|
81
|
+
edits: this.edits,
|
|
82
|
+
currentTool: this.currentToolCall,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.ClaudeCodeAdapter = ClaudeCodeAdapter;
|
|
88
|
+
//# sourceMappingURL=claude-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH;;;;;;GAMG;AACH,MAAa,iBAAiB;IACpB,eAAe,CAAU;IACzB,KAAK,GAAkD,EAAE,CAAC;IAElE;;OAEG;IACH,WAAW,CAAC,IAAY;QACtB,8BAA8B;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACrD,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YACpC,OAAO;gBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,EAAE;gBACT,QAAQ,EAAE,IAAI,CAAC,eAAe;gBAC9B,KAAK,EAAE,aAAa;aACrB,CAAC;QACJ,CAAC;QAED,kBAAkB;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YAClD,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO;oBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC5B,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE,EAAE;oBACT,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;oBAClB,KAAK,EAAE,aAAa;iBACrB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAC7C,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO;oBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC5B,IAAI,EAAE,cAAc;oBACpB,KAAK,EAAE,EAAE;oBACT,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;oBAC3B,KAAK,EAAE,aAAa;iBACrB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,oBAAoB;QACpB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACpF,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxC,OAAO;gBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;gBAClB,KAAK,EAAE,aAAa;aACrB,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,QAAiC;QAC9C,OAAO;YACL,GAAG,QAAQ;YACX,UAAU,EAAE;gBACV,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,eAAe;aAClC;SACF,CAAC;IACJ,CAAC;CACF;AA7ED,8CA6EC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex Adapter
|
|
3
|
+
* Specific handling for OpenAI Codex sessions
|
|
4
|
+
*/
|
|
5
|
+
import { AgentEvent } from "../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Codex emits structured output that we can parse:
|
|
8
|
+
* - Session/thread IDs
|
|
9
|
+
* - Command/tool calls
|
|
10
|
+
* - File edits
|
|
11
|
+
* - Diff checkpoints
|
|
12
|
+
*/
|
|
13
|
+
export declare class CodexAdapter {
|
|
14
|
+
private currentSessionId?;
|
|
15
|
+
private currentThreadId?;
|
|
16
|
+
/**
|
|
17
|
+
* Parse Codex-specific output
|
|
18
|
+
*/
|
|
19
|
+
parseOutput(line: string): AgentEvent | null;
|
|
20
|
+
/**
|
|
21
|
+
* Enrich metadata with Codex-specific info
|
|
22
|
+
*/
|
|
23
|
+
enrichMetadata(metadata: Record<string, unknown>): Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,eAAe,CAAC,CAAS;IAEjC;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAyC5C;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAS3E"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Codex Adapter
|
|
4
|
+
* Specific handling for OpenAI Codex sessions
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CodexAdapter = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Codex emits structured output that we can parse:
|
|
10
|
+
* - Session/thread IDs
|
|
11
|
+
* - Command/tool calls
|
|
12
|
+
* - File edits
|
|
13
|
+
* - Diff checkpoints
|
|
14
|
+
*/
|
|
15
|
+
class CodexAdapter {
|
|
16
|
+
currentSessionId;
|
|
17
|
+
currentThreadId;
|
|
18
|
+
/**
|
|
19
|
+
* Parse Codex-specific output
|
|
20
|
+
*/
|
|
21
|
+
parseOutput(line) {
|
|
22
|
+
// Detect Codex session start
|
|
23
|
+
const sessionMatch = line.match(/Session:\s+([a-zA-Z0-9-]+)/);
|
|
24
|
+
if (sessionMatch) {
|
|
25
|
+
this.currentSessionId = sessionMatch[1];
|
|
26
|
+
return {
|
|
27
|
+
ts: new Date().toISOString(),
|
|
28
|
+
type: "session.start",
|
|
29
|
+
runId: "",
|
|
30
|
+
sessionId: this.currentSessionId,
|
|
31
|
+
agent: "codex",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Detect command/tool calls
|
|
35
|
+
const toolCallMatch = line.match(/▶\s+(\w+)\s*\(([^)]*)\)/);
|
|
36
|
+
if (toolCallMatch) {
|
|
37
|
+
return {
|
|
38
|
+
ts: new Date().toISOString(),
|
|
39
|
+
type: "process.exec",
|
|
40
|
+
runId: "",
|
|
41
|
+
toolName: toolCallMatch[1],
|
|
42
|
+
args: toolCallMatch[2].split(",").map(s => s.trim()),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Detect file edits
|
|
46
|
+
const fileEditMatch = line.match(/(✓|✗)\s+([\w/.-]+)/);
|
|
47
|
+
if (fileEditMatch) {
|
|
48
|
+
return {
|
|
49
|
+
ts: new Date().toISOString(),
|
|
50
|
+
type: "file.write",
|
|
51
|
+
runId: "",
|
|
52
|
+
path: fileEditMatch[2],
|
|
53
|
+
action: fileEditMatch[1] === "✓" ? "modified" : "error",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Enrich metadata with Codex-specific info
|
|
60
|
+
*/
|
|
61
|
+
enrichMetadata(metadata) {
|
|
62
|
+
return {
|
|
63
|
+
...metadata,
|
|
64
|
+
codex: {
|
|
65
|
+
sessionId: this.currentSessionId,
|
|
66
|
+
threadId: this.currentThreadId,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.CodexAdapter = CodexAdapter;
|
|
72
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH;;;;;;GAMG;AACH,MAAa,YAAY;IACf,gBAAgB,CAAU;IAC1B,eAAe,CAAU;IAEjC;;OAEG;IACH,WAAW,CAAC,IAAY;QACtB,6BAA6B;QAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC9D,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,gBAAgB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YACxC,OAAO;gBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,IAAI,EAAE,eAAe;gBACrB,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,IAAI,CAAC,gBAAgB;gBAChC,KAAK,EAAE,OAAO;aACf,CAAC;QACJ,CAAC;QAED,4BAA4B;QAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC5D,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO;gBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,EAAE;gBACT,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC;gBAC1B,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACrD,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACvD,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO;gBACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBAC5B,IAAI,EAAE,YAAY;gBAClB,KAAK,EAAE,EAAE;gBACT,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;gBACtB,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO;aACxD,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,QAAiC;QAC9C,OAAO;YACL,GAAG,QAAQ;YACX,KAAK,EAAE;gBACL,SAAS,EAAE,IAAI,CAAC,gBAAgB;gBAChC,QAAQ,EAAE,IAAI,CAAC,eAAe;aAC/B;SACF,CAAC;IACJ,CAAC;CACF;AA5DD,oCA4DC"}
|