@elhu/pit 0.1.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 +21 -0
- package/README.md +380 -0
- package/dist/adapters/claude-code.d.ts +70 -0
- package/dist/adapters/claude-code.d.ts.map +1 -0
- package/dist/adapters/claude-code.js +166 -0
- package/dist/adapters/claude-code.js.map +1 -0
- package/dist/adapters/index.d.ts +16 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +49 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/opencode.d.ts +53 -0
- package/dist/adapters/opencode.d.ts.map +1 -0
- package/dist/adapters/opencode.js +120 -0
- package/dist/adapters/opencode.js.map +1 -0
- package/dist/adapters/process-utils.d.ts +29 -0
- package/dist/adapters/process-utils.d.ts.map +1 -0
- package/dist/adapters/process-utils.js +96 -0
- package/dist/adapters/process-utils.js.map +1 -0
- package/dist/adapters/types.d.ts +41 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +6 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/assets.generated.d.ts +13 -0
- package/dist/assets.generated.d.ts.map +1 -0
- package/dist/assets.generated.js +162 -0
- package/dist/assets.generated.js.map +1 -0
- package/dist/beads.d.ts +85 -0
- package/dist/beads.d.ts.map +1 -0
- package/dist/beads.js +120 -0
- package/dist/beads.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +10 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +58 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/cleanup.d.ts +13 -0
- package/dist/commands/cleanup.d.ts.map +1 -0
- package/dist/commands/cleanup.js +174 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/daemon.d.ts +3 -0
- package/dist/commands/daemon.d.ts.map +1 -0
- package/dist/commands/daemon.js +162 -0
- package/dist/commands/daemon.js.map +1 -0
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install-keybinding.d.ts +61 -0
- package/dist/commands/install-keybinding.d.ts.map +1 -0
- package/dist/commands/install-keybinding.js +138 -0
- package/dist/commands/install-keybinding.js.map +1 -0
- package/dist/commands/install-status.d.ts +35 -0
- package/dist/commands/install-status.d.ts.map +1 -0
- package/dist/commands/install-status.js +115 -0
- package/dist/commands/install-status.js.map +1 -0
- package/dist/commands/log.d.ts +7 -0
- package/dist/commands/log.d.ts.map +1 -0
- package/dist/commands/log.js +60 -0
- package/dist/commands/log.js.map +1 -0
- package/dist/commands/pause.d.ts +12 -0
- package/dist/commands/pause.d.ts.map +1 -0
- package/dist/commands/pause.js +47 -0
- package/dist/commands/pause.js.map +1 -0
- package/dist/commands/resume.d.ts +12 -0
- package/dist/commands/resume.d.ts.map +1 -0
- package/dist/commands/resume.js +59 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/shared.d.ts +7 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +56 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/start.d.ts +12 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +274 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +24 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +101 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +11 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +52 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/teardown.d.ts +15 -0
- package/dist/commands/teardown.d.ts.map +1 -0
- package/dist/commands/teardown.js +72 -0
- package/dist/commands/teardown.js.map +1 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +129 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +38 -0
- package/dist/daemon/client.d.ts.map +1 -0
- package/dist/daemon/client.js +254 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/context.d.ts +63 -0
- package/dist/daemon/context.d.ts.map +1 -0
- package/dist/daemon/context.js +14 -0
- package/dist/daemon/context.js.map +1 -0
- package/dist/daemon/handlers.d.ts +79 -0
- package/dist/daemon/handlers.d.ts.map +1 -0
- package/dist/daemon/handlers.js +1260 -0
- package/dist/daemon/handlers.js.map +1 -0
- package/dist/daemon/index.d.ts +6 -0
- package/dist/daemon/index.d.ts.map +1 -0
- package/dist/daemon/index.js +7 -0
- package/dist/daemon/index.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +56 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +341 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/protocol.d.ts +174 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +3 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/recovery.d.ts +37 -0
- package/dist/daemon/recovery.d.ts.map +1 -0
- package/dist/daemon/recovery.js +197 -0
- package/dist/daemon/recovery.js.map +1 -0
- package/dist/daemon/server.d.ts +31 -0
- package/dist/daemon/server.d.ts.map +1 -0
- package/dist/daemon/server.js +294 -0
- package/dist/daemon/server.js.map +1 -0
- package/dist/daemon/socket.d.ts +18 -0
- package/dist/daemon/socket.d.ts.map +1 -0
- package/dist/daemon/socket.js +36 -0
- package/dist/daemon/socket.js.map +1 -0
- package/dist/daemon/state.d.ts +60 -0
- package/dist/daemon/state.d.ts.map +1 -0
- package/dist/daemon/state.js +156 -0
- package/dist/daemon/state.js.map +1 -0
- package/dist/daemon/systemd.d.ts +19 -0
- package/dist/daemon/systemd.d.ts.map +1 -0
- package/dist/daemon/systemd.js +131 -0
- package/dist/daemon/systemd.js.map +1 -0
- package/dist/hooks/claude-code-hook.d.ts +32 -0
- package/dist/hooks/claude-code-hook.d.ts.map +1 -0
- package/dist/hooks/claude-code-hook.js +112 -0
- package/dist/hooks/claude-code-hook.js.map +1 -0
- package/dist/instructions-template.d.ts +9 -0
- package/dist/instructions-template.d.ts.map +1 -0
- package/dist/instructions-template.js +123 -0
- package/dist/instructions-template.js.map +1 -0
- package/dist/logger.d.ts +25 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +44 -0
- package/dist/logger.js.map +1 -0
- package/dist/loop.d.ts +88 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +161 -0
- package/dist/loop.js.map +1 -0
- package/dist/orchestrator-instructions-template.d.ts +13 -0
- package/dist/orchestrator-instructions-template.d.ts.map +1 -0
- package/dist/orchestrator-instructions-template.js +147 -0
- package/dist/orchestrator-instructions-template.js.map +1 -0
- package/dist/output.d.ts +12 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +25 -0
- package/dist/output.js.map +1 -0
- package/dist/plugin/pit.js +57 -0
- package/dist/session.d.ts +55 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +135 -0
- package/dist/session.js.map +1 -0
- package/dist/setup.d.ts +92 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +382 -0
- package/dist/setup.js.map +1 -0
- package/dist/shell-quote.d.ts +16 -0
- package/dist/shell-quote.d.ts.map +1 -0
- package/dist/shell-quote.js +18 -0
- package/dist/shell-quote.js.map +1 -0
- package/dist/signals.d.ts +17 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +26 -0
- package/dist/signals.js.map +1 -0
- package/dist/state-machine.d.ts +74 -0
- package/dist/state-machine.d.ts.map +1 -0
- package/dist/state-machine.js +153 -0
- package/dist/state-machine.js.map +1 -0
- package/dist/tmux.d.ts +101 -0
- package/dist/tmux.d.ts.map +1 -0
- package/dist/tmux.js +208 -0
- package/dist/tmux.js.map +1 -0
- package/dist/worktree.d.ts +33 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +116 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 pit contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# pit
|
|
2
|
+
|
|
3
|
+
[](https://github.com/elhu/pit/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
A tmux-based orchestrator that automates parallel AI coding agent sessions.
|
|
6
|
+
|
|
7
|
+
`pit` manages git worktrees, tmux windows, and agent TUIs (Claude Code or opencode),
|
|
8
|
+
driving each agent through a ticket loop powered by [beads](https://github.com/anomalyco/beads)
|
|
9
|
+
for issue tracking. The primary consumer of `pit` is an LLM in an orchestrator session --
|
|
10
|
+
the human talks to the model, the model calls `pit`.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
+-----------------+
|
|
14
|
+
| Orchestrator |
|
|
15
|
+
| (LLM session) |
|
|
16
|
+
+--------+--------+
|
|
17
|
+
|
|
|
18
|
+
pit CLI
|
|
19
|
+
|
|
|
20
|
+
+--------+--------+
|
|
21
|
+
| Daemon |
|
|
22
|
+
| (Unix socket) |
|
|
23
|
+
+--------+--------+
|
|
24
|
+
|
|
|
25
|
+
+--------------+--------------+
|
|
26
|
+
| | |
|
|
27
|
+
+-----+-----+ +-----+-----+ +-----+-----+
|
|
28
|
+
| Worktree 1 | | Worktree 2 | | Worktree 3 |
|
|
29
|
+
| tmux win 1 | | tmux win 2 | | tmux win 3 |
|
|
30
|
+
| Agent TUI | | Agent TUI | | Agent TUI |
|
|
31
|
+
+------------+ +------------+ +------------+
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
> **WARNING: EXPERIMENTAL SOFTWARE**
|
|
37
|
+
>
|
|
38
|
+
> ```
|
|
39
|
+
> _____
|
|
40
|
+
> / \
|
|
41
|
+
> | () () |
|
|
42
|
+
> \ ^ /
|
|
43
|
+
> |||||
|
|
44
|
+
> |||||
|
|
45
|
+
> ```
|
|
46
|
+
>
|
|
47
|
+
> **This software is highly experimental.** It is under active development, APIs will
|
|
48
|
+
> change without notice, and things will break.
|
|
49
|
+
>
|
|
50
|
+
> **This software deliberately bypasses AI agent security features.** `pit` launches
|
|
51
|
+
> Claude Code with `--dangerously-skip-permissions`, which disables ALL permission
|
|
52
|
+
> checks -- file writes, shell commands, network access, everything. Agents execute
|
|
53
|
+
> arbitrary commands without human confirmation.
|
|
54
|
+
>
|
|
55
|
+
> **This software is for people who like taking risks.** If you are not comfortable
|
|
56
|
+
> with autonomous AI agents running shell commands in your codebase without asking
|
|
57
|
+
> first, this is not for you. If "move fast and break things" makes you nervous
|
|
58
|
+
> rather than excited, look elsewhere.
|
|
59
|
+
>
|
|
60
|
+
> **This software is built using itself.** `pit` is developed with `pit` -- the
|
|
61
|
+
> codebase is almost entirely written by AI coding agents orchestrated by `pit`. If
|
|
62
|
+
> running AI-generated code makes you uncomfortable, this is not for you.
|
|
63
|
+
>
|
|
64
|
+
> **This software will burn through tokens.** `pit` runs autonomous agents that work
|
|
65
|
+
> fast but are not frugal. Multiple agents running in parallel, each looping through
|
|
66
|
+
> tickets, each with full context windows. Monitor your API usage. You have been
|
|
67
|
+
> warned twice now.
|
|
68
|
+
>
|
|
69
|
+
> **Do NOT use `pit` on untrusted repositories or with untrusted ticket content.** The
|
|
70
|
+
> agents will execute whatever they're told to, without confirmation. You have been
|
|
71
|
+
> warned.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Philosophy
|
|
76
|
+
|
|
77
|
+
`pit` is opinionated software. It encodes a specific workflow for AI-assisted development
|
|
78
|
+
and does not try to be all things to all people.
|
|
79
|
+
|
|
80
|
+
**The core belief:** the quality of autonomous AI coding comes down to the quality of
|
|
81
|
+
the tickets. `pit`'s prompt loop is deliberately simplistic -- "find the next ticket and
|
|
82
|
+
work on it" -- because all the nuance, context, and constraints should live in the
|
|
83
|
+
tickets themselves. If you write vague tickets, you get vague results. If you write
|
|
84
|
+
detailed, unambiguous tickets with clear acceptance criteria, agents can execute
|
|
85
|
+
independently.
|
|
86
|
+
|
|
87
|
+
**Context is cleared between tickets.** When an agent finishes a ticket, `pit` clears
|
|
88
|
+
its conversation context before sending the next one. Each ticket starts fresh -- the
|
|
89
|
+
agent has no memory of previous tickets. This means tickets must be self-contained:
|
|
90
|
+
include all relevant context, file paths, and constraints in the ticket itself. In
|
|
91
|
+
practice this is rarely a problem if your tickets are well-written, and it prevents
|
|
92
|
+
context window pollution from accumulating over a long epic.
|
|
93
|
+
|
|
94
|
+
### The Intended Workflow
|
|
95
|
+
|
|
96
|
+
1. **Write requirements.** Start with a set of high-level requirements for the feature
|
|
97
|
+
or project you want to build.
|
|
98
|
+
|
|
99
|
+
2. **Refine into detailed beads.** Break the requirements down into highly detailed
|
|
100
|
+
beads tickets. Each ticket should contain enough context for a coding agent to pick
|
|
101
|
+
it up and execute independently -- the problem statement, relevant file paths,
|
|
102
|
+
expected behavior, edge cases, and constraints. This is where you invest your time.
|
|
103
|
+
|
|
104
|
+
3. **Set up your AGENTS.md.** Your project's AGENTS.md (or equivalent agent
|
|
105
|
+
instructions file) should contain the "landing the plane" instructions -- quality
|
|
106
|
+
gates to run, what to commit, when to push, coding conventions. This is the
|
|
107
|
+
persistent context every agent session gets. `pit` injects its orchestrator
|
|
108
|
+
instructions here via `pit init`.
|
|
109
|
+
|
|
110
|
+
4. **Let `pit` run.** `pit start --epics <epic-id>` spins up agents and they work through
|
|
111
|
+
tickets autonomously. Monitor with `pit status`, intervene when agents pause.
|
|
112
|
+
|
|
113
|
+
5. **Merge and clean up.** Once an epic is done, the human operator (or an agent you
|
|
114
|
+
instruct) merges the worktree branch back to main, runs quality gates, pushes, and
|
|
115
|
+
calls `pit teardown` to clean up all `pit` artifacts.
|
|
116
|
+
|
|
117
|
+
`pit` does not try to be smart about what agents do. It manages the plumbing -- worktrees,
|
|
118
|
+
tmux sessions, idle detection, ticket cycling -- and gets out of the way. The
|
|
119
|
+
intelligence lives in your tickets and your AGENTS.md.
|
|
120
|
+
|
|
121
|
+
## How It Works
|
|
122
|
+
|
|
123
|
+
1. You set up an epic (a group of tickets) using [beads](https://github.com/anomalyco/beads)
|
|
124
|
+
2. You run `pit start --epics <epic-id>`
|
|
125
|
+
3. `pit` creates one git worktree + tmux window + agent TUI per epic
|
|
126
|
+
4. Each agent autonomously loops: pick ticket, work on it, commit, push, pick next
|
|
127
|
+
5. You monitor with `pit status`, intervene with `pit pause`/`pit resume`
|
|
128
|
+
6. When an epic completes, you merge the worktree branch back
|
|
129
|
+
|
|
130
|
+
Agents work in isolated git worktrees so they don't interfere with each other or your
|
|
131
|
+
main checkout. Each agent has its own branch, its own files, its own tmux window.
|
|
132
|
+
|
|
133
|
+
## Watching and Intervening
|
|
134
|
+
|
|
135
|
+
`pit` runs agents inside a tmux session (named `pit` by default). You can attach to it
|
|
136
|
+
at any time to watch agents work in real time:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
tmux attach -t pit
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Use tmux's normal window-switching keys (`Ctrl-b n` / `Ctrl-b p`) to move between
|
|
143
|
+
epic windows. Each window is named `epic-<id>` and shows the agent's TUI.
|
|
144
|
+
|
|
145
|
+
From any terminal (you don't need to be attached to tmux), you can:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Check what all agents are doing
|
|
149
|
+
pit status --pretty
|
|
150
|
+
|
|
151
|
+
# Read an agent's recent output without attaching to tmux
|
|
152
|
+
pit log my-epic --lines 100
|
|
153
|
+
|
|
154
|
+
# Pause an agent that's going in circles
|
|
155
|
+
pit pause my-epic
|
|
156
|
+
|
|
157
|
+
# Resume with specific guidance
|
|
158
|
+
pit resume my-epic --message "The config file is in src/config.ts, not lib/config.ts"
|
|
159
|
+
|
|
160
|
+
# Resume without a message (re-prompts with the next ticket)
|
|
161
|
+
pit resume my-epic
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
You can also install tmux integrations for quicker access:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pit install-keybinding # Binds prefix+R to resume and prefix+H to pause the current epic
|
|
168
|
+
pit install-status # Appends #{@pit-status} to the tmux status bar
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Prerequisites
|
|
172
|
+
|
|
173
|
+
- **Node.js** >= 24
|
|
174
|
+
- **tmux** installed and available in PATH
|
|
175
|
+
- **beads** (`bd`) installed and available in PATH
|
|
176
|
+
- **An AI coding agent**: [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`) or [opencode](https://opencode.ai) (`opencode`)
|
|
177
|
+
- A git repository with beads epics and tickets set up
|
|
178
|
+
|
|
179
|
+
## Install
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install -g pit
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Or clone and build from source:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
git clone https://github.com/anomalyco/pit.git
|
|
189
|
+
cd pit
|
|
190
|
+
npm install
|
|
191
|
+
npm run build
|
|
192
|
+
npm link
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Quick Start
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# 1. Initialize pit in your project (injects orchestrator instructions into AGENTS.md)
|
|
199
|
+
pit init
|
|
200
|
+
|
|
201
|
+
# 2. Optionally configure pit (or just use defaults)
|
|
202
|
+
cat > .pit.json << 'EOF'
|
|
203
|
+
{
|
|
204
|
+
"agent": "auto",
|
|
205
|
+
"baseBranch": "main"
|
|
206
|
+
}
|
|
207
|
+
EOF
|
|
208
|
+
|
|
209
|
+
# 3. Make sure you have beads epics set up
|
|
210
|
+
bd list
|
|
211
|
+
|
|
212
|
+
# 4. Start agents for one or more epics
|
|
213
|
+
pit start --epics my-epic-id
|
|
214
|
+
|
|
215
|
+
# 5. Monitor progress
|
|
216
|
+
pit status
|
|
217
|
+
pit status --pretty
|
|
218
|
+
|
|
219
|
+
# 6. Read agent output
|
|
220
|
+
pit log my-epic-id
|
|
221
|
+
|
|
222
|
+
# 7. Pause/resume as needed
|
|
223
|
+
pit pause my-epic-id
|
|
224
|
+
pit resume my-epic-id --message "Try a different approach for the auth module"
|
|
225
|
+
|
|
226
|
+
# 8. Clean up when done
|
|
227
|
+
pit teardown
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## CLI Reference
|
|
231
|
+
|
|
232
|
+
All commands output JSON by default (for LLM consumption). Add `--pretty` for
|
|
233
|
+
human-readable output.
|
|
234
|
+
|
|
235
|
+
| Command | Description |
|
|
236
|
+
| ------------------------- | ----------------------------------------------------------- |
|
|
237
|
+
| `pit init` | Inject orchestrator instructions into AGENTS.md |
|
|
238
|
+
| `pit start --epics <ids>` | Start agent sessions for given epic IDs |
|
|
239
|
+
| `pit status` | Show status of all running epics |
|
|
240
|
+
| `pit log <epic>` | Capture agent's recent terminal output |
|
|
241
|
+
| `pit pause <epic>` | Pause a running epic |
|
|
242
|
+
| `pit resume <epic>` | Resume a paused epic (optionally with `--message`) |
|
|
243
|
+
| `pit stop [epic]` | Stop epic(s), transition to done |
|
|
244
|
+
| `pit add <epic>` | Add an epic to a running session |
|
|
245
|
+
| `pit teardown [epic]` | Tear down epics and clean up resources |
|
|
246
|
+
| `pit cleanup` | Garbage-collect stale session directories |
|
|
247
|
+
| `pit daemon <cmd>` | Manage the background daemon (start/stop/status/restart) |
|
|
248
|
+
| `pit install-keybinding` | Install tmux keybindings for quick resume (R) and pause (H) |
|
|
249
|
+
| `pit install-status` | Append `#{@pit-status}` to the tmux status bar |
|
|
250
|
+
|
|
251
|
+
For detailed flag reference, examples, and edge cases, see [docs/cli.md](docs/cli.md).
|
|
252
|
+
|
|
253
|
+
## Configuration
|
|
254
|
+
|
|
255
|
+
`pit` reads `.pit.json` from the project root. CLI flags override file values.
|
|
256
|
+
|
|
257
|
+
```jsonc
|
|
258
|
+
{
|
|
259
|
+
// Which coding agent to run in each tmux window.
|
|
260
|
+
// "auto" - tries opencode first, falls back to claude-code
|
|
261
|
+
// "opencode" - use opencode (https://opencode.ai)
|
|
262
|
+
// "claude-code" - use Claude Code (https://docs.anthropic.com/en/docs/claude-code)
|
|
263
|
+
"agent": "auto",
|
|
264
|
+
|
|
265
|
+
// Model passed to the agent CLI. Format depends on the agent:
|
|
266
|
+
// Claude Code: "claude-sonnet-4-20250514", "claude-opus-4-20250514", etc.
|
|
267
|
+
// opencode: "anthropic/claude-sonnet-4-20250514", etc.
|
|
268
|
+
// null = let the agent use its default model.
|
|
269
|
+
"model": null,
|
|
270
|
+
|
|
271
|
+
"worktreeDir": ".worktrees", // Where git worktrees are created
|
|
272
|
+
"baseBranch": "main", // Branch worktrees are created from
|
|
273
|
+
"tmuxSession": "pit", // tmux session name
|
|
274
|
+
|
|
275
|
+
"clearDelay": 2000, // Ms to wait after clearing agent context
|
|
276
|
+
"initDelay": 5000, // Ms to wait for agent TUI to start
|
|
277
|
+
"ticketTimeout": null, // Minutes before auto-pausing a ticket (null = no limit)
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
| Field | Default | Description |
|
|
282
|
+
| --------------- | -------------- | ---------------------------------------------------------------- |
|
|
283
|
+
| `agent` | `"auto"` | Agent type: `auto`, `opencode`, or `claude-code` |
|
|
284
|
+
| `model` | `null` | Model to pass to the agent CLI (null = agent default) |
|
|
285
|
+
| `worktreeDir` | `".worktrees"` | Directory for git worktrees |
|
|
286
|
+
| `baseBranch` | `"main"` | Base branch for worktrees |
|
|
287
|
+
| `tmuxSession` | `"pit"` | tmux session name |
|
|
288
|
+
| `clearDelay` | `2000` | Ms to wait before clearing agent context after ticket completion |
|
|
289
|
+
| `initDelay` | `5000` | Ms to wait before starting the agent after setup |
|
|
290
|
+
| `ticketTimeout` | `null` | Minutes before a ticket auto-pauses the agent (null = disabled) |
|
|
291
|
+
|
|
292
|
+
## Security Model
|
|
293
|
+
|
|
294
|
+
`pit` is designed for autonomous agent operation. This comes with deliberate trade-offs:
|
|
295
|
+
|
|
296
|
+
- **Claude Code** is launched with `--dangerously-skip-permissions`, bypassing all
|
|
297
|
+
permission checks. The agent can read/write any file, run any shell command, and
|
|
298
|
+
make network requests without human approval.
|
|
299
|
+
- **opencode** uses its plugin system for event detection. Permission handling is
|
|
300
|
+
managed through the plugin bridge.
|
|
301
|
+
- Each agent runs in an **isolated git worktree**, not your main checkout. The
|
|
302
|
+
worktree is disposable and can be recreated from the base branch.
|
|
303
|
+
- The daemon communicates over a **Unix domain socket** in `/tmp/pit/`. No network
|
|
304
|
+
exposure.
|
|
305
|
+
|
|
306
|
+
**This is intentional.** `pit` exists to let agents work autonomously. If you need
|
|
307
|
+
human-in-the-loop approval for every file write, `pit` is the wrong tool.
|
|
308
|
+
|
|
309
|
+
**Mitigations:**
|
|
310
|
+
|
|
311
|
+
- Worktree isolation limits blast radius
|
|
312
|
+
- Worktrees are on branches, not main -- you review before merging
|
|
313
|
+
- `pit pause` lets you halt an agent at any time
|
|
314
|
+
- `pit teardown` cleans everything up
|
|
315
|
+
|
|
316
|
+
## Documentation
|
|
317
|
+
|
|
318
|
+
| Document | Audience | Description |
|
|
319
|
+
| ---------------------------------------------- | ----------------- | ----------------------------------------------------------- |
|
|
320
|
+
| [docs/cli.md](docs/cli.md) | Agents + humans | Detailed per-command reference |
|
|
321
|
+
| [docs/architecture.md](docs/architecture.md) | Agents + humans | Internal architecture and design |
|
|
322
|
+
| [docs/orchestration.md](docs/orchestration.md) | Orchestrator LLMs | How to drive `pit` from an LLM session |
|
|
323
|
+
| [AGENTS.md](AGENTS.md) | Coding agents | Conventions and workflow for agents working on `pit` itself |
|
|
324
|
+
|
|
325
|
+
## Releasing
|
|
326
|
+
|
|
327
|
+
Releases are published to npm and GitHub Releases automatically by CI when a version
|
|
328
|
+
tag is pushed. Use the release script to bump the version and push the tag:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
# Patch release (e.g. 1.2.3 -> 1.2.4)
|
|
332
|
+
npm run release -- patch
|
|
333
|
+
|
|
334
|
+
# Minor release (e.g. 1.2.3 -> 1.3.0)
|
|
335
|
+
npm run release -- minor
|
|
336
|
+
|
|
337
|
+
# Major release (e.g. 1.2.3 -> 2.0.0)
|
|
338
|
+
npm run release -- major
|
|
339
|
+
|
|
340
|
+
# Explicit version
|
|
341
|
+
npm run release -- 1.2.3
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
The script will:
|
|
345
|
+
|
|
346
|
+
1. Verify a clean working tree and that you're on `main`
|
|
347
|
+
2. Pull latest from origin
|
|
348
|
+
3. Run local quality gates (`npm test`, `npm run test:e2e`, `npm run lint`, `npm run build`)
|
|
349
|
+
4. Bump the version and create a git commit + tag via `npm version`
|
|
350
|
+
5. Push the commit and tag (`git push --follow-tags`), triggering the CI publish workflow
|
|
351
|
+
6. Print a link to GitHub Actions so you can monitor the publish
|
|
352
|
+
|
|
353
|
+
CI handles the actual `npm publish` and GitHub Release creation — you do not need to
|
|
354
|
+
run `npm publish` manually.
|
|
355
|
+
|
|
356
|
+
### What CI does automatically
|
|
357
|
+
|
|
358
|
+
When a `v*` tag is pushed, the [Publish workflow](.github/workflows/publish.yml):
|
|
359
|
+
|
|
360
|
+
1. Verifies the tag matches the version in `package.json`
|
|
361
|
+
2. Runs quality gates (lint, build, unit tests, E2E tests)
|
|
362
|
+
3. Publishes the package to npm (`npm publish --access public`)
|
|
363
|
+
4. Creates a GitHub Release with auto-generated release notes
|
|
364
|
+
|
|
365
|
+
### Required secrets
|
|
366
|
+
|
|
367
|
+
The repository must have an `NPM_TOKEN` secret set in GitHub Actions:
|
|
368
|
+
|
|
369
|
+
1. Go to [npmjs.com](https://www.npmjs.com) → Account → Access Tokens → Generate New Token
|
|
370
|
+
2. Choose **Automation** token type (bypasses 2FA requirement for CI publishing)
|
|
371
|
+
3. Add the token to GitHub: Repository → Settings → Secrets and variables → Actions → `NPM_TOKEN`
|
|
372
|
+
|
|
373
|
+
### Verifying a release
|
|
374
|
+
|
|
375
|
+
Monitor the publish workflow at:
|
|
376
|
+
[https://github.com/elhu/pit/actions/workflows/publish.yml](https://github.com/elhu/pit/actions/workflows/publish.yml)
|
|
377
|
+
|
|
378
|
+
## License
|
|
379
|
+
|
|
380
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeCodeAdapter — implements AgentAdapter for the Claude Code CLI agent.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code is a CLI tool (`claude`) that reads instructions from CLAUDE.md
|
|
5
|
+
* in the worktree. Hooks are installed into .claude/hooks/ and registered in
|
|
6
|
+
* .claude/settings.local.json for Stop events.
|
|
7
|
+
*
|
|
8
|
+
* ## Permission handling
|
|
9
|
+
*
|
|
10
|
+
* Claude Code is launched with `--dangerously-skip-permissions` so that the
|
|
11
|
+
* agent can work autonomously without interactive permission prompts blocking
|
|
12
|
+
* the tmux session. This flag bypasses **all** permission checks — file writes,
|
|
13
|
+
* shell commands, network access, etc. — which is acceptable because:
|
|
14
|
+
*
|
|
15
|
+
* 1. Each agent runs in an isolated git worktree, not the main checkout.
|
|
16
|
+
* 2. The worktree is disposable and can be recreated from the base branch.
|
|
17
|
+
* 3. pit is designed for autonomous agent operation where human approval
|
|
18
|
+
* for every tool call would defeat the purpose.
|
|
19
|
+
*
|
|
20
|
+
* **Security note:** Do NOT use pit (or this flag) on untrusted repositories
|
|
21
|
+
* or with untrusted ticket content. The agent will execute arbitrary commands
|
|
22
|
+
* without confirmation.
|
|
23
|
+
*/
|
|
24
|
+
import type { AgentAdapter } from "./types.js";
|
|
25
|
+
export declare class ClaudeCodeAdapter implements AgentAdapter {
|
|
26
|
+
readonly name = "claude-code";
|
|
27
|
+
startCommand(_worktree: string, _env: Record<string, string>, model?: string): string;
|
|
28
|
+
/** Claude Code is a full-screen TUI; use timeout-based readiness. */
|
|
29
|
+
readonly readinessPattern: undefined;
|
|
30
|
+
readonly clearCommand = "/clear";
|
|
31
|
+
/**
|
|
32
|
+
* Install the pit hook into the worktree's .claude/hooks/ directory and
|
|
33
|
+
* register it in .claude/settings.local.json for the Stop event (idle
|
|
34
|
+
* detection). PermissionRequest hooks are not needed because the agent is
|
|
35
|
+
* launched with --dangerously-skip-permissions.
|
|
36
|
+
*
|
|
37
|
+
* The hook content is embedded as an inline string (CLAUDE_CODE_HOOK_JS) at
|
|
38
|
+
* build time, so it is always the correct version regardless of where pit is
|
|
39
|
+
* installed globally (npm link, npm install -g, etc.). Resolving via __dirname
|
|
40
|
+
* was unreliable because it pointed to the global install's dist directory
|
|
41
|
+
* rather than the worktree's bundled copy.
|
|
42
|
+
*/
|
|
43
|
+
installEventBridge(worktreeDir: string, _epic: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Write agent instructions to CLAUDE.md using PIT:MANAGED markers.
|
|
46
|
+
* Creates the section if absent; replaces it if present (idempotent).
|
|
47
|
+
* Preserves any content outside the managed section.
|
|
48
|
+
*/
|
|
49
|
+
writeInstructions(worktreeDir: string, content: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Check whether the claude CLI is available on PATH.
|
|
52
|
+
* Returns true if `which claude` exits 0, false otherwise.
|
|
53
|
+
*/
|
|
54
|
+
checkInstalled(): Promise<boolean>;
|
|
55
|
+
/**
|
|
56
|
+
* Wait for Claude Code to be ready using a simple timeout.
|
|
57
|
+
*/
|
|
58
|
+
waitForReady({ timeoutMs }: {
|
|
59
|
+
timeoutMs: number;
|
|
60
|
+
}): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Verify the Claude Code process is running in the given tmux window.
|
|
63
|
+
*
|
|
64
|
+
* The tmux pane PID is the shell (zsh/bash), not claude itself.
|
|
65
|
+
* We walk the process tree rooted at the pane PID and check whether any
|
|
66
|
+
* descendant process has a comm of "claude" or "node".
|
|
67
|
+
*/
|
|
68
|
+
verifyRunning(tmuxSession: string, windowName: string): Promise<boolean>;
|
|
69
|
+
}
|
|
70
|
+
//# 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;;;;;;;;;;;;;;;;;;;;;;GAsBG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAc/C,qBAAa,iBAAkB,YAAW,YAAY;IACpD,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAKrF,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,YAAa;IAEtC,QAAQ,CAAC,YAAY,YAAY;IAEjC;;;;;;;;;;;OAWG;IACG,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA2C3E;;;;OAIG;IACG,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC5E;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAQxC;;OAEG;IACG,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;;;;;OAMG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAkB/E"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeCodeAdapter — implements AgentAdapter for the Claude Code CLI agent.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code is a CLI tool (`claude`) that reads instructions from CLAUDE.md
|
|
5
|
+
* in the worktree. Hooks are installed into .claude/hooks/ and registered in
|
|
6
|
+
* .claude/settings.local.json for Stop events.
|
|
7
|
+
*
|
|
8
|
+
* ## Permission handling
|
|
9
|
+
*
|
|
10
|
+
* Claude Code is launched with `--dangerously-skip-permissions` so that the
|
|
11
|
+
* agent can work autonomously without interactive permission prompts blocking
|
|
12
|
+
* the tmux session. This flag bypasses **all** permission checks — file writes,
|
|
13
|
+
* shell commands, network access, etc. — which is acceptable because:
|
|
14
|
+
*
|
|
15
|
+
* 1. Each agent runs in an isolated git worktree, not the main checkout.
|
|
16
|
+
* 2. The worktree is disposable and can be recreated from the base branch.
|
|
17
|
+
* 3. pit is designed for autonomous agent operation where human approval
|
|
18
|
+
* for every tool call would defeat the purpose.
|
|
19
|
+
*
|
|
20
|
+
* **Security note:** Do NOT use pit (or this flag) on untrusted repositories
|
|
21
|
+
* or with untrusted ticket content. The agent will execute arbitrary commands
|
|
22
|
+
* without confirmation.
|
|
23
|
+
*/
|
|
24
|
+
import { execFile } from "node:child_process";
|
|
25
|
+
import fs from "node:fs/promises";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { execTmux } from "../tmux.js";
|
|
28
|
+
import { shellQuote } from "../shell-quote.js";
|
|
29
|
+
import { CLAUDE_CODE_HOOK_JS } from "../assets.generated.js";
|
|
30
|
+
import { hasAgentDescendant } from "./process-utils.js";
|
|
31
|
+
/**
|
|
32
|
+
* Names that indicate Claude Code is running as a descendant process.
|
|
33
|
+
* Claude Code is distributed as "claude" CLI, but may run via Node.js.
|
|
34
|
+
*/
|
|
35
|
+
const CLAUDE_CODE_COMM_NAMES = new Set(["claude", "node"]);
|
|
36
|
+
const PIT_HOOK_COMMAND = `node "$CLAUDE_PROJECT_DIR/.claude/hooks/pit-hook.js"`;
|
|
37
|
+
const PIT_HOOK_MARKER = "pit-hook.js";
|
|
38
|
+
const MANAGED_BEGIN = "<!-- PIT:MANAGED:BEGIN -->";
|
|
39
|
+
const MANAGED_END = "<!-- PIT:MANAGED:END -->";
|
|
40
|
+
export class ClaudeCodeAdapter {
|
|
41
|
+
name = "claude-code";
|
|
42
|
+
startCommand(_worktree, _env, model) {
|
|
43
|
+
const base = "claude --dangerously-skip-permissions";
|
|
44
|
+
return model ? `${base} --model ${shellQuote(model)}` : base;
|
|
45
|
+
}
|
|
46
|
+
/** Claude Code is a full-screen TUI; use timeout-based readiness. */
|
|
47
|
+
readinessPattern = undefined;
|
|
48
|
+
clearCommand = "/clear";
|
|
49
|
+
/**
|
|
50
|
+
* Install the pit hook into the worktree's .claude/hooks/ directory and
|
|
51
|
+
* register it in .claude/settings.local.json for the Stop event (idle
|
|
52
|
+
* detection). PermissionRequest hooks are not needed because the agent is
|
|
53
|
+
* launched with --dangerously-skip-permissions.
|
|
54
|
+
*
|
|
55
|
+
* The hook content is embedded as an inline string (CLAUDE_CODE_HOOK_JS) at
|
|
56
|
+
* build time, so it is always the correct version regardless of where pit is
|
|
57
|
+
* installed globally (npm link, npm install -g, etc.). Resolving via __dirname
|
|
58
|
+
* was unreliable because it pointed to the global install's dist directory
|
|
59
|
+
* rather than the worktree's bundled copy.
|
|
60
|
+
*/
|
|
61
|
+
async installEventBridge(worktreeDir, _epic) {
|
|
62
|
+
const hooksDir = path.join(worktreeDir, ".claude", "hooks");
|
|
63
|
+
await fs.mkdir(hooksDir, { recursive: true });
|
|
64
|
+
const destPath = path.join(hooksDir, "pit-hook.js");
|
|
65
|
+
await fs.writeFile(destPath, CLAUDE_CODE_HOOK_JS, "utf8");
|
|
66
|
+
const settingsPath = path.join(worktreeDir, ".claude", "settings.local.json");
|
|
67
|
+
let config = {};
|
|
68
|
+
try {
|
|
69
|
+
const raw = await fs.readFile(settingsPath, "utf8");
|
|
70
|
+
config = JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// File does not exist or is invalid JSON — start fresh
|
|
74
|
+
}
|
|
75
|
+
// Register the pit hook for the Stop event (agent-idle detection).
|
|
76
|
+
// PermissionRequest hooks are not needed because Claude Code is launched
|
|
77
|
+
// with --dangerously-skip-permissions (see startCommand / class doc).
|
|
78
|
+
const hooks = (config.hooks ?? {});
|
|
79
|
+
config.hooks = hooks;
|
|
80
|
+
const pitMatcher = {
|
|
81
|
+
hooks: [{ type: "command", command: PIT_HOOK_COMMAND }],
|
|
82
|
+
};
|
|
83
|
+
for (const event of ["Stop"]) {
|
|
84
|
+
if (!Array.isArray(hooks[event])) {
|
|
85
|
+
hooks[event] = [];
|
|
86
|
+
}
|
|
87
|
+
const existingEntries = hooks[event];
|
|
88
|
+
const alreadyInstalled = JSON.stringify(existingEntries).includes(PIT_HOOK_MARKER);
|
|
89
|
+
if (!alreadyInstalled) {
|
|
90
|
+
existingEntries.push(pitMatcher);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Write agent instructions to CLAUDE.md using PIT:MANAGED markers.
|
|
97
|
+
* Creates the section if absent; replaces it if present (idempotent).
|
|
98
|
+
* Preserves any content outside the managed section.
|
|
99
|
+
*/
|
|
100
|
+
async writeInstructions(worktreeDir, content) {
|
|
101
|
+
const mdPath = path.join(worktreeDir, "CLAUDE.md");
|
|
102
|
+
let existing = "";
|
|
103
|
+
try {
|
|
104
|
+
existing = await fs.readFile(mdPath, "utf8");
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// File does not exist — will create it
|
|
108
|
+
}
|
|
109
|
+
const managedSection = `${MANAGED_BEGIN}\n${content}\n${MANAGED_END}\n`;
|
|
110
|
+
let updated;
|
|
111
|
+
if (existing.includes(MANAGED_BEGIN) && existing.includes(MANAGED_END)) {
|
|
112
|
+
// Replace existing managed section (inclusive of markers)
|
|
113
|
+
const beginIdx = existing.indexOf(MANAGED_BEGIN);
|
|
114
|
+
const endIdx = existing.indexOf(MANAGED_END) + MANAGED_END.length;
|
|
115
|
+
// Include trailing newline if present
|
|
116
|
+
const afterEnd = existing[endIdx] === "\n" ? endIdx + 1 : endIdx;
|
|
117
|
+
updated = existing.slice(0, beginIdx) + managedSection + existing.slice(afterEnd);
|
|
118
|
+
}
|
|
119
|
+
else if (existing === "") {
|
|
120
|
+
// Empty file — write managed section directly without leading newlines
|
|
121
|
+
updated = managedSection;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// Non-empty file without markers — append
|
|
125
|
+
updated = existing + "\n\n" + managedSection;
|
|
126
|
+
}
|
|
127
|
+
await fs.writeFile(mdPath, updated, "utf8");
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check whether the claude CLI is available on PATH.
|
|
131
|
+
* Returns true if `which claude` exits 0, false otherwise.
|
|
132
|
+
*/
|
|
133
|
+
async checkInstalled() {
|
|
134
|
+
return new Promise((resolve) => {
|
|
135
|
+
execFile("which", ["claude"], (err) => {
|
|
136
|
+
resolve(!err);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Wait for Claude Code to be ready using a simple timeout.
|
|
142
|
+
*/
|
|
143
|
+
async waitForReady({ timeoutMs }) {
|
|
144
|
+
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Verify the Claude Code process is running in the given tmux window.
|
|
148
|
+
*
|
|
149
|
+
* The tmux pane PID is the shell (zsh/bash), not claude itself.
|
|
150
|
+
* We walk the process tree rooted at the pane PID and check whether any
|
|
151
|
+
* descendant process has a comm of "claude" or "node".
|
|
152
|
+
*/
|
|
153
|
+
async verifyRunning(tmuxSession, windowName) {
|
|
154
|
+
try {
|
|
155
|
+
const { stdout } = await execTmux("list-panes", "-t", `${tmuxSession}:${windowName}`, "-F", "#{pane_pid}");
|
|
156
|
+
const panePid = stdout.trim();
|
|
157
|
+
if (!panePid)
|
|
158
|
+
return false;
|
|
159
|
+
return await hasAgentDescendant(panePid, CLAUDE_CODE_COMM_NAMES);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=claude-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter factory — resolves the correct AgentAdapter based on the requested
|
|
3
|
+
* agent name, or auto-detects based on what is installed.
|
|
4
|
+
*/
|
|
5
|
+
import type { AgentAdapter } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve an AgentAdapter by name.
|
|
8
|
+
*
|
|
9
|
+
* @param agent - "auto" | "opencode" | "claude-code"
|
|
10
|
+
* @returns The resolved adapter (Promise<AgentAdapter>)
|
|
11
|
+
*
|
|
12
|
+
* "auto" tries opencode first, then claude-code. Throws if neither is installed.
|
|
13
|
+
* Named agents throw if not installed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveAdapter(agent: string): Promise<AgentAdapter>;
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAW/C;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAiCzE"}
|