claude-garage 0.3.2 โ 0.3.4
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 +20 -1
- package/daemon/src/index.js +4 -0
- package/daemon/src/tmux.js +33 -0
- package/package.json +1 -1
- package/wall/dist/garage-wall-darwin-arm64 +0 -0
package/README.md
CHANGED
|
@@ -150,7 +150,7 @@ the features the TUI doesn't have yet:
|
|
|
150
150
|
notification when no page is open (clickable with
|
|
151
151
|
[`terminal-notifier`](https://github.com/julienXX/terminal-notifier)).
|
|
152
152
|
|
|
153
|
-
### The pit pet ๐
|
|
153
|
+
### The pit pet ๐
|
|
154
154
|
|
|
155
155
|
An optional ASCII companion on the key strip whose mood *is* the wall:
|
|
156
156
|
asleep when all is quiet, watching while agents run, **sprinting toward the
|
|
@@ -177,12 +177,31 @@ state in character:
|
|
|
177
177
|
| **Papito** (rubber duck) | deadpan: waddles, **never** bounces, and alerts with a single motionless stare; celebration is exactly one flap |
|
|
178
178
|
| **Segan** (pit pup) | maximum enthusiasm: fastest runner, biggest bounce, and celebrates with zoomies across the strip |
|
|
179
179
|
|
|
180
|
+
**In the TUI** the pet lives at the right end of the bottom strip, beside
|
|
181
|
+
the keys chip, as a one-row sprite (`=o.o=`, `<(o )___`, `(ยทแดฅยท)`), same
|
|
182
|
+
moods, same manners. It speaks right next to itself:
|
|
183
|
+
`you're doing great!! (ยทแดฅยท) keys โ garage`. Press **`P`** to
|
|
184
|
+
cycle Arthur โ Papito โ Segan โ off; the choice is remembered. Click the
|
|
185
|
+
pet while it's alert to jump to the blocked session, click it otherwise to
|
|
186
|
+
pet it. TUI pets also **talk**: every few minutes, in character, the strip
|
|
187
|
+
gets a line like *"water. now. i'm not asking."* (Arthur), *"acceptable."*
|
|
188
|
+
(Papito) or *"you're doing great!!"* (Segan). They notice long days, late
|
|
189
|
+
nights, and a usage window running hot, and they never interrupt a session
|
|
190
|
+
that needs you. Set `GARAGE_PET_ASCII=1` if your font lacks `แดฅ`.
|
|
191
|
+
|
|
180
192
|
## Keybindings
|
|
181
193
|
|
|
182
194
|
The TUI's full keymap (`claude-garage tui`, also shown in-app with `?`).
|
|
183
195
|
Bindings apply at the garage layer; `Enter` hands your keystrokes to the
|
|
184
196
|
focused session byte-exact until `Ctrl+G` takes them back.
|
|
185
197
|
|
|
198
|
+
**Terminal:** Ghostty, iTerm2, kitty and WezTerm pass every Claude Code
|
|
199
|
+
binding through, Shift+Enter included. macOS Terminal.app speaks neither
|
|
200
|
+
the kitty keyboard protocol nor modifyOtherKeys, so Shift+Enter can't be
|
|
201
|
+
told apart from Enter there; either switch terminals or add a Terminal.app
|
|
202
|
+
key mapping (Settings โ Profiles โ Keyboard) for Shift+Return that sends
|
|
203
|
+
`\033[13;2u`. Option+Enter and Ctrl+J work everywhere.
|
|
204
|
+
|
|
186
205
|
| Key | Action |
|
|
187
206
|
|---|---|
|
|
188
207
|
| `1`โ`9` | focus workspace |
|
package/daemon/src/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { attachTermServer } from "./term.js";
|
|
|
17
17
|
import { rejectForeignOrigins } from "./security.js";
|
|
18
18
|
import { startPoller } from "./poller.js";
|
|
19
19
|
import { healthPayload } from "./health.js";
|
|
20
|
+
import { ensureExtendedKeys } from "./tmux.js";
|
|
20
21
|
|
|
21
22
|
const HOST = "127.0.0.1";
|
|
22
23
|
const PORT = Number(process.env.GARAGE_PORT ?? 4747);
|
|
@@ -63,6 +64,9 @@ if (process.env.GARAGE_SERVE_UI === "1") {
|
|
|
63
64
|
// Poller feeds StatusStore (busy/idle baseline); hooks.js and notify.js
|
|
64
65
|
// subscribe to the same store โ see status.js for the single write path.
|
|
65
66
|
const stopPoller = startPoller(app);
|
|
67
|
+
// p14: Shift+Enter needs the tmux server's extended-keys config โ apply it
|
|
68
|
+
// to an already-running server at boot (createSession re-applies later).
|
|
69
|
+
ensureExtendedKeys();
|
|
66
70
|
app.addHook("onClose", async () => {
|
|
67
71
|
stopPoller();
|
|
68
72
|
});
|
package/daemon/src/tmux.js
CHANGED
|
@@ -164,6 +164,9 @@ export async function hasSession(id) {
|
|
|
164
164
|
// must not pre-join them into a single string.
|
|
165
165
|
export async function createSession(id, dir, command, extraArgs = []) {
|
|
166
166
|
await run("tmux", ["new-session", "-d", "-s", id, "-c", dir, command, ...extraArgs]);
|
|
167
|
+
// The new-session call may have just started the server โ (re)apply the
|
|
168
|
+
// extended-keys server config so Shift+Enter works in this pane (p14).
|
|
169
|
+
await ensureExtendedKeys();
|
|
167
170
|
// The pit wall renders its own session title bars, so tmux's status line
|
|
168
171
|
// is visual noise in every grid cell. Per-session option โ a plain
|
|
169
172
|
// `tmux attach` escape-hatch user can restore it with `set status on`.
|
|
@@ -172,6 +175,36 @@ export async function createSession(id, dir, command, extraArgs = []) {
|
|
|
172
175
|
await run("tmux", ["set-option", "-t", id, "status", "off"]).catch(() => {});
|
|
173
176
|
}
|
|
174
177
|
|
|
178
|
+
// p14: Claude Code's Shift+Enter (kitty protocol, ESC[13;2u) only reaches a
|
|
179
|
+
// pane if the tmux server has extended keys on and advertises them (and,
|
|
180
|
+
// since 0.3.4, re-encodes in csi-u form so Option+Enter survives too) โ
|
|
181
|
+
// exactly the tmux config Claude Code's own terminal docs prescribe. Server
|
|
182
|
+
// options survive until the tmux server exits, so this runs at daemon boot
|
|
183
|
+
// AND on every createSession (the server may have been started later by a
|
|
184
|
+
// plain `tmux` user). Idempotent: `set -as terminal-features` appends
|
|
185
|
+
// duplicates, so the extkeys feature is only appended when missing.
|
|
186
|
+
export async function ensureExtendedKeys() {
|
|
187
|
+
try {
|
|
188
|
+
await run("tmux", ["set-option", "-s", "extended-keys", "on"]);
|
|
189
|
+
// csi-u, not the default xterm `CSI 27;m;k~` form: with extended keys
|
|
190
|
+
// on, tmux re-encodes every modified key for a pane that asked for
|
|
191
|
+
// them โ Option+Enter becomes `ESC[27;3;13~`, which Claude Code does
|
|
192
|
+
// not parse, so Option+Enter (its own newline binding on macOS) died
|
|
193
|
+
// inside every garage session. The kitty form (`ESC[13;3u`) is the one
|
|
194
|
+
// Claude Code already understands for Shift+Enter. tmux โฅ 3.5.
|
|
195
|
+
await run("tmux", ["set-option", "-s", "extended-keys-format", "csi-u"]).catch(() => {});
|
|
196
|
+
const { stdout } = await run("tmux", ["show-options", "-s", "terminal-features"]).catch(
|
|
197
|
+
() => ({ stdout: "" })
|
|
198
|
+
);
|
|
199
|
+
if (!/xterm\*?[^\n]*extkeys/.test(stdout)) {
|
|
200
|
+
await run("tmux", ["set-option", "-as", "terminal-features", "xterm*:extkeys"]);
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
// No server running (or ancient tmux) โ nothing to configure; the
|
|
204
|
+
// createSession call path retries once a server exists.
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
175
208
|
export async function killSession(id) {
|
|
176
209
|
await run("tmux", ["kill-session", "-t", exact(id)]);
|
|
177
210
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-garage",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Multiple Claude agents driving you crazy? Park them all in one garage: a needs-input queue that follows you across projects, a full-screen terminal TUI, and a browser wall with diff review. tmux owns the sessions; close the app and nothing dies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Saiful Islam <saifulislamadar@gmail.com>",
|
|
Binary file
|