@bondsmith/bondsmithd 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -4
- package/dist/index.js +2690 -2051
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ pair it with.
|
|
|
11
11
|
npm install -g @bondsmith/bondsmithd
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Requires Node >=24 and `tmux` (`brew install tmux` on macOS). `node-pty`, the one native
|
|
14
|
+
Requires Node >=24 and `tmux` 3.2 or newer (`brew install tmux` on macOS). `node-pty`, the one native
|
|
15
15
|
dependency, ships prebuilt binaries for macOS (Intel and Apple Silicon) and installs without
|
|
16
16
|
compiling anything on supported platforms.
|
|
17
17
|
|
|
@@ -88,8 +88,85 @@ a report dated in the future. A `waiting` or `done` report is dropped once the p
|
|
|
88
88
|
than 2 seconds after it, since that means the agent moved on. A `working` report is dropped once the
|
|
89
89
|
pane has been silent for 2 minutes, since an interrupted or crashed agent never reports again.
|
|
90
90
|
|
|
91
|
+
Claude Code sessions that Bondsmith starts as plain `claude` report this on their own (see the end of the
|
|
92
|
+
plan section below): `working` when a prompt is sent, `waiting` when it asks for permission, finishes a
|
|
93
|
+
turn or fails with an API error. Nothing needs installing for those.
|
|
94
|
+
|
|
95
|
+
For an agent the daemon does not set up (a wrapper, `npx claude`, another agent), note that every session
|
|
96
|
+
Bondsmith starts has `BONDSMITH_SESSION` set to its id, so a hook installed once for all your projects can
|
|
97
|
+
stay silent everywhere else. This entry in `~/.claude/settings.json` reports a Claude Code session as
|
|
98
|
+
waiting the moment it asks for permission or finishes a turn:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"hooks": {
|
|
103
|
+
"PermissionRequest": [
|
|
104
|
+
{
|
|
105
|
+
"matcher": "*",
|
|
106
|
+
"hooks": [
|
|
107
|
+
{
|
|
108
|
+
"type": "command",
|
|
109
|
+
"command": "[ -n \"$BONDSMITH_SESSION\" ] && tmux set-option -t \"$TMUX_PANE\" -q @bondsmith-agent-state \"waiting:$(date +%s)\"; exit 0"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"Stop": [
|
|
115
|
+
{
|
|
116
|
+
"hooks": [
|
|
117
|
+
{
|
|
118
|
+
"type": "command",
|
|
119
|
+
"command": "[ -n \"$BONDSMITH_SESSION\" ] && tmux set-option -t \"$TMUX_PANE\" -q @bondsmith-agent-state \"waiting:$(date +%s)\"; exit 0"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
This is optional, and nothing edits your settings for you. The command does nothing outside a Bondsmith
|
|
129
|
+
session, and sessions started before the daemon set the variable are skipped by it. It reports only
|
|
130
|
+
`waiting`. A `working` report is dropped after the pane has been silent for 2 minutes, so one that an
|
|
131
|
+
interrupted Claude Code never clears (it does not run `Stop` then, and has no hook for Escape) expires on
|
|
132
|
+
its own.
|
|
133
|
+
|
|
91
134
|
An agent can also share the plan it is working against, which Bondsmith shows above the session's
|
|
92
|
-
changes.
|
|
135
|
+
changes. Write it as markdown to `.bondsmith/plan.md` in the session's folder once the plan is agreed,
|
|
136
|
+
and again whenever it changes. The file is read as it is, cut at 32,768 characters; a symlink, or a
|
|
137
|
+
path that leaves the session's folder, is ignored. Changes does not list the file while it is untracked.
|
|
138
|
+
The daemon never writes to your repository, so `git status` still shows it and `git add .` would commit it;
|
|
139
|
+
add `.bondsmith/plan.md` to your `.gitignore` or `.git/info/exclude` to prevent that.
|
|
140
|
+
|
|
141
|
+
A hook can store the plan outside the repository instead, in `~/.bondsmith/plans/<session id>.md`, where
|
|
142
|
+
`<session id>` is `$BONDSMITH_SESSION`. It is read the same way and wins over the folder's file and the tmux
|
|
143
|
+
option, so a plan written there is never left over from an earlier session.
|
|
144
|
+
|
|
145
|
+
For Claude Code the daemon sets this up itself. When a session's command is `claude` (that word alone, not
|
|
146
|
+
behind `npx`, an environment variable or a wrapper), the daemon starts it as
|
|
147
|
+
`claude --settings ~/.bondsmith/hooks/claude-settings.json …`. That file adds hooks to the ones you
|
|
148
|
+
already have: after you approve a plan in plan mode, one stores the plan as above, and four report the agent
|
|
149
|
+
state (`working` on a prompt; `waiting` on a permission request, the end of a turn, or a turn that fails with
|
|
150
|
+
an API error). Nothing in `~/.claude` changes, the session still shows the command you typed, and the hooks
|
|
151
|
+
do nothing outside a Bondsmith session. Claude Code's `/hooks` menu does not list hooks passed with
|
|
152
|
+
`--settings`, though they run.
|
|
153
|
+
|
|
154
|
+
A fifth hook stores the latest prompt as the session's headline, which the sessions list and the session bar
|
|
155
|
+
show. It is the prompt on one line, cut at 200 characters, in the tmux option `@bondsmith-headline`. A reply
|
|
156
|
+
that only answers the agent (`yes`, `continue`, `ok`, `thanks`, and a few like them) or a prompt under 4
|
|
157
|
+
characters leaves the earlier headline in place; a built-in slash command such as `/help` sends no prompt to
|
|
158
|
+
the hook, so it does too. The prompt is stored as typed, so a secret in a prompt is in the headline.
|
|
159
|
+
|
|
160
|
+
The daemon leaves the command alone if it already has `--settings`, if the installed `claude` does not list
|
|
161
|
+
`--settings` in `claude --help` (asked once per daemon run; if `claude` cannot be run at all, that is logged
|
|
162
|
+
and asked again after a minute), or if `BONDSMITH_AGENT_HOOKS` is set to `off`, `0`, `false` or `no` where
|
|
163
|
+
the daemon starts. Each hook has a timeout (5 seconds for a state report or the headline, 10 for the plan), so a stuck command
|
|
164
|
+
cannot hold up the agent. Plans are written to `~/.bondsmith/plans` readable only by you, and a symlink in
|
|
165
|
+
the way is replaced, not followed. A plan the agent changes later without going back through plan mode is
|
|
166
|
+
not seen; the hook's plan keeps winning over the folder's file until the next approval.
|
|
167
|
+
|
|
168
|
+
An agent that cannot write files can set a tmux option instead, from inside the session's pane. The file
|
|
169
|
+
wins when both exist:
|
|
93
170
|
|
|
94
171
|
```sh
|
|
95
172
|
tmux set-option -t "$TMUX_PANE" -q @bondsmith-plan "$(cat <<'EOF'
|
|
@@ -100,14 +177,29 @@ EOF
|
|
|
100
177
|
)"
|
|
101
178
|
```
|
|
102
179
|
|
|
103
|
-
|
|
104
|
-
|
|
180
|
+
Keep that one short: tmux refuses a command over about 16,000 bytes (measured: 16,000 works, 17,000
|
|
181
|
+
fails with "command too long"), so a longer plan is not stored and the panel keeps showing the previous
|
|
182
|
+
one. The file has no such limit.
|
|
183
|
+
|
|
184
|
+
The daemon reads the plan only when the browser asks, so unlike the state report it has no timestamp
|
|
185
|
+
and is not dropped when the pane writes output.
|
|
105
186
|
|
|
106
187
|
An agent with no hook can still get attention by ringing the terminal bell (`printf '\a'`). A bell
|
|
107
188
|
rung in a session nobody has looked at marks it as waiting, whatever its last report said, until tmux
|
|
108
189
|
clears the flag when someone attaches to the session. Agents that can ring the bell for approvals or
|
|
109
190
|
a finished turn work this way with nothing to install.
|
|
110
191
|
|
|
192
|
+
With no hook and no bell, a session still shows as `waiting` once its pane has written something and then
|
|
193
|
+
gone silent for 8 seconds. Agents animate while they work and stop when they need you, so this needs no
|
|
194
|
+
setup for any agent. It cannot tell an approval prompt from a finished turn, and a long silent command
|
|
195
|
+
looks the same. A `working` hook report takes precedence over this while the agent keeps writing, and stops counting
|
|
196
|
+
once the pane has been silent for 2 minutes.
|
|
197
|
+
|
|
198
|
+
Attaching to a session, typing in it, resizing it, or inserting text into it counts as the user looking,
|
|
199
|
+
so the redraw that causes is ignored (output within 3 seconds of it), and the session reads as waiting
|
|
200
|
+
again only after new output goes quiet. When the daemon starts, the sessions it finds count as already
|
|
201
|
+
seen, so one that was waiting before a restart shows as waiting again only after it writes more.
|
|
202
|
+
|
|
111
203
|
tmux only flags a bell when no client is attached to the session or the bell is in a window other than
|
|
112
204
|
the one the attached client has open. A session whose terminal is open in a browser tab, even a hidden
|
|
113
205
|
one, counts as being looked at, so a bell in it is not flagged; use the hook report for that case.
|