acstack 0.0.0-stage → 0.47.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/.claude-plugin/plugin.json +19 -0
- package/LICENSE +21 -0
- package/README.md +389 -2
- package/THIRD_PARTY_NOTICES +14 -0
- package/TROUBLESHOOTING.md +225 -0
- package/agents/codex/frontend-verifier.toml +352 -0
- package/agents/codex/task-checker.toml +345 -0
- package/agents/codex/task-executor.toml +157 -0
- package/agents/codex/test-writer.toml +149 -0
- package/agents/frontend-verifier.md +351 -0
- package/agents/task-checker.md +344 -0
- package/agents/task-executor.md +156 -0
- package/agents/test-writer.md +148 -0
- package/assets/playwriter-bridge/build-launcher.ps1 +32 -0
- package/assets/playwriter-bridge/doctor.ps1 +450 -0
- package/assets/playwriter-bridge/launcher-src.cs +131 -0
- package/assets/playwriter-bridge/opener.js +330 -0
- package/assets/playwriter-bridge/opener.ps1 +63 -0
- package/assets/playwriter-bridge/register-tasks.ps1 +328 -0
- package/assets/playwriter-bridge/relay.ps1 +50 -0
- package/assets/playwriter-bridge/stop.ps1 +125 -0
- package/assets/playwriter-bridge/sync.ps1 +271 -0
- package/assets/playwriter-bridge/tunnel.ps1 +325 -0
- package/assets/playwriter-bridge/vm-free-port.sh +166 -0
- package/assets/terminal-workspace/client-keybindings.md +87 -0
- package/assets/terminal-workspace/config.example.yaml +334 -0
- package/assets/terminal-workspace/setup.sh +4404 -0
- package/cli/README.md +47 -0
- package/cli/bin/acstack.js +3 -0
- package/cli/dist/index.js +25984 -0
- package/cli/dist/index.js.map +7 -0
- package/cli/package.json +59 -0
- package/docs/adr/0001-ste-writing-standard.md +16 -0
- package/docs/adr/0002-version-gate-not-auto-bump.md +35 -0
- package/docs/adr/0003-handoff-ack-command.md +19 -0
- package/docs/adr/0004-dev-setup-per-host.md +13 -0
- package/docs/adr/0005-two-orchestrators-per-host.md +25 -0
- package/docs/adr/0006-document-opener-service.md +89 -0
- package/docs/adr/0007-lead-check-reads-the-transcript.md +87 -0
- package/docs/adr/0008-cli-audits-skill-interviews.md +37 -0
- package/docs/adr/0009-verify-the-write-not-the-writer.md +51 -0
- package/docs/adr/0010-promote-dev-to-main-by-fast-forward.md +115 -0
- package/docs/adr/0011-node-header-is-the-edge-encoding.md +20 -0
- package/docs/adr/0012-node-kind-is-a-closed-set-of-five.md +31 -0
- package/docs/adr/0013-the-diagram-renderer-is-pure.md +23 -0
- package/docs/adr/0014-reading-a-node-hides-its-generated-diagram.md +29 -0
- package/docs/adr/0015-a-node-id-links-to-its-issue-through-an-anchor.md +37 -0
- package/docs/adr/0016-the-map-root-carries-no-status-of-its-own.md +21 -0
- package/docs/adr/0017-call-impeccable-copy-only-its-questions.md +13 -0
- package/docs/adr/index.md +17 -0
- package/docs/config-reference.md +572 -0
- package/docs/dev-setups.md +164 -0
- package/docs/migrate-0.8.md +28 -0
- package/docs/playwriter-bridge-windows.md +15 -0
- package/docs/terminal-workspace-keys.md +137 -0
- package/docs/terminal-workspace.md +1780 -0
- package/docs/workflows.md +309 -0
- package/hooks/ac-writing-style-reminder.sh +86 -0
- package/hooks/context-pressure.sh +583 -0
- package/hooks/hooks.json +50 -0
- package/hooks/session-start-handoff.sh +165 -0
- package/hooks/session-start.sh +214 -0
- package/orchestrator/AGENTS.md +532 -0
- package/output-styles/ac-writing-style.md +286 -0
- package/package.json +50 -4
- package/pi/agents/frontend-verifier.md +357 -0
- package/pi/agents/task-checker.md +348 -0
- package/pi/agents/task-executor.md +160 -0
- package/pi/agents/test-writer.md +154 -0
- package/pi/extension.ts +723 -0
- package/profiles/fullstack-python.yaml +29 -0
- package/profiles/node-typescript.yaml +23 -0
- package/profiles/python.yaml +24 -0
- package/skills/archive/SKILL.md +160 -0
- package/skills/bootstrap/SKILL.md +109 -0
- package/skills/bridge/HANDOFF.md +93 -0
- package/skills/bridge/SKILL-VM.md +292 -0
- package/skills/bridge/SKILL-WINDOWS.md +526 -0
- package/skills/bridge/SKILL.md +121 -0
- package/skills/browser-verify/SKILL.md +229 -0
- package/skills/code-review/SKILL.md +44 -0
- package/skills/commit/SKILL.md +106 -0
- package/skills/compact-and-continue/SKILL.md +241 -0
- package/skills/explore/SKILL.md +149 -0
- package/skills/grilling/SKILL.md +134 -0
- package/skills/handoff/SKILL.md +250 -0
- package/skills/handoff/launch-herdr.md +197 -0
- package/skills/handoff/launch-without-herdr.md +30 -0
- package/skills/handoff/lead-check.md +59 -0
- package/skills/handoff/outcomes.md +162 -0
- package/skills/handoff/running-agent.md +50 -0
- package/skills/handoff/watch.md +115 -0
- package/skills/host/SKILL.md +247 -0
- package/skills/host/detect-host.sh +297 -0
- package/skills/host/herdr.md +79 -0
- package/skills/host/install-herdr-block.sh +467 -0
- package/skills/host/install-orca.sh +512 -0
- package/skills/host/notes.md +97 -0
- package/skills/host/orca.md +160 -0
- package/skills/host/questions.md +163 -0
- package/skills/host/report.md +42 -0
- package/skills/implement/SKILL.md +230 -0
- package/skills/implement/decision-log.md +62 -0
- package/skills/implement/design-pass.md +32 -0
- package/skills/implement/relaxed-tdd.md +28 -0
- package/skills/map/SKILL.md +250 -0
- package/skills/map/frontend.md +227 -0
- package/skills/map/trackers/files.md +74 -0
- package/skills/map/trackers/github.md +180 -0
- package/skills/map/visuals.md +387 -0
- package/skills/new-worktree/SKILL.md +155 -0
- package/skills/new-worktree/detect-orchestrator.sh +328 -0
- package/skills/new-worktree/detect-orchestrator.test.sh +894 -0
- package/skills/new-worktree/herdr.md +84 -0
- package/skills/new-worktree/orca.md +101 -0
- package/skills/pre-commit-review/SKILL.md +242 -0
- package/skills/pre-commit-review/auto-fix.md +19 -0
- package/skills/pre-commit-review/interactive.md +35 -0
- package/skills/quick-fix/SKILL.md +125 -0
- package/skills/record-context/SKILL.md +106 -0
- package/skills/setup/SKILL.md +250 -0
- package/skills/setup/browser.md +123 -0
- package/skills/setup/design-review.md +97 -0
- package/skills/setup/first-run.md +114 -0
- package/skills/setup/report.md +68 -0
- package/skills/setup/row-fixes.md +196 -0
- package/skills/setup/terminal-workspace.md +153 -0
- package/skills/sync/SKILL.md +171 -0
- package/skills/teardown-worktree/SKILL.md +245 -0
- package/skills/teardown-worktree/detector.md +39 -0
- package/skills/teardown-worktree/herdr.md +113 -0
- package/skills/teardown-worktree/orca.md +61 -0
- package/skills/terminal-workspace/SKILL.md +249 -0
- package/skills/terminal-workspace/components.md +36 -0
- package/skills/terminal-workspace/config-choices.md +69 -0
- package/skills/terminal-workspace/emulator-keys.md +48 -0
- package/skills/terminal-workspace/headless-clipboard.md +175 -0
- package/skills/terminal-workspace/turn-off-and-update.md +104 -0
- package/skills/test-conventions/SKILL.md +59 -0
- package/skills/visual-docs/SKILL.md +246 -0
- package/skills/writing/SKILL.md +231 -0
- package/skills/writing/examples.md +153 -0
- package/skills/writing/vocabulary.md +96 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# vm-free-port.sh – VM-side cleanup for a stuck reverse-forward port.
|
|
3
|
+
#
|
|
4
|
+
# When the Windows tunnel repeatedly hits "remote port forwarding failed
|
|
5
|
+
# for listen port 19988", this script identifies what holds 127.0.0.1:19988
|
|
6
|
+
# on the VM and – if safe – kills it.
|
|
7
|
+
#
|
|
8
|
+
# Guardrail: refuses to kill if the socket is held by the current user's
|
|
9
|
+
# own interactive SSH session. Killing that would drop the shell running
|
|
10
|
+
# the script.
|
|
11
|
+
#
|
|
12
|
+
# Guardrail: refuses to kill anything that still answers HTTP on the port. A
|
|
13
|
+
# forward that is serving is the bridge, not litter, and the operator who runs
|
|
14
|
+
# this out of habit would be taking the browser away from whoever is using it.
|
|
15
|
+
#
|
|
16
|
+
# Scoped strictly to the two ports this setup owns: 19988 (the bridge's CDP
|
|
17
|
+
# port) and 19989 (the document opener). Any other port is refused. This is an
|
|
18
|
+
# allowlist rather than a free --port flag on purpose - the guardrails below
|
|
19
|
+
# reason about what a holder is, and that reasoning is only valid for sockets
|
|
20
|
+
# we put there. Exits non-zero with a clear message on any ambiguous or unsafe
|
|
21
|
+
# situation.
|
|
22
|
+
#
|
|
23
|
+
# Intended to be invoked via the handoff block produced by Windows-side
|
|
24
|
+
# doctor.ps1. Safe to run at any time; no-ops if the port is already free.
|
|
25
|
+
|
|
26
|
+
set -u
|
|
27
|
+
|
|
28
|
+
PORT=19988
|
|
29
|
+
# 64 for a bad argument (the conventional EX_USAGE), because 2 already means
|
|
30
|
+
# something specific here: the port is held by something this script may not
|
|
31
|
+
# kill. Reusing it would make "you typed it wrong" indistinguishable from "the
|
|
32
|
+
# port is genuinely stuck".
|
|
33
|
+
case "${1:-}" in
|
|
34
|
+
--port)
|
|
35
|
+
case "${2:-}" in
|
|
36
|
+
19988|19989) PORT="$2" ;;
|
|
37
|
+
*) printf 'ERROR: --port accepts only 19988 (bridge) or 19989 (opener), not "%s".\n' "${2:-}" >&2; exit 64 ;;
|
|
38
|
+
esac
|
|
39
|
+
;;
|
|
40
|
+
"") ;;
|
|
41
|
+
*) printf 'usage: vm-free-port.sh [--port 19988|19989]\n' >&2; exit 64 ;;
|
|
42
|
+
esac
|
|
43
|
+
|
|
44
|
+
log() { printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"; }
|
|
45
|
+
err() { log "ERROR: $*" >&2; }
|
|
46
|
+
|
|
47
|
+
# Inspect 127.0.0.1:$PORT – print owner PID, process name, and parent PID.
|
|
48
|
+
find_holder() {
|
|
49
|
+
ss -H -lntp "sport = :$PORT" 2>/dev/null | head -n1
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
line=$(find_holder)
|
|
53
|
+
if [ -z "$line" ]; then
|
|
54
|
+
log "port $PORT is already free. Nothing to do."
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
log "current holder: $line"
|
|
59
|
+
|
|
60
|
+
# Guardrail: is the forward still carrying traffic? A holder on this port is not
|
|
61
|
+
# garbage by default - while the tunnel is up it is the bridge, and this is the
|
|
62
|
+
# socket agent-browser drives Chrome through. The question is asked of the port
|
|
63
|
+
# rather than of the process, and asked first, because a non-root ss cannot name
|
|
64
|
+
# the owner of someone else's socket: the checks below would give up at "could
|
|
65
|
+
# not parse PID" and never reach the one guardrail that matters most. doctor.ps1 prints this
|
|
66
|
+
# script as the remedy for an amber "Tunnel logs" row, and that row trails for
|
|
67
|
+
# five minutes after the tunnel has already healed itself, so running the
|
|
68
|
+
# clearer against a healthy forward is the ordinary mistake, not the rare one.
|
|
69
|
+
#
|
|
70
|
+
# Any HTTP answer counts as alive. A 401 or a 404 comes from a CDP endpoint
|
|
71
|
+
# that is serving and merely guarded, or asked for a path it does not have, so
|
|
72
|
+
# --fail is deliberately absent: it would read those as dead and kill them. The
|
|
73
|
+
# probe is bounded at 3 seconds, because a genuinely wedged socket is exactly
|
|
74
|
+
# the one that would otherwise hang the clearer called to free it.
|
|
75
|
+
#
|
|
76
|
+
# There is no override flag for this refusal, on purpose. A live tunnel is
|
|
77
|
+
# released by closing the session holding it, and a switch that skipped the
|
|
78
|
+
# probe would just be the habit the probe exists to stop.
|
|
79
|
+
if curl -s -o /dev/null -m 3 "http://127.0.0.1:$PORT/" 2>/dev/null; then
|
|
80
|
+
err "port $PORT is carrying a live tunnel: something answered HTTP on it just now."
|
|
81
|
+
err "Killing the holder would take the browser away from whoever is using it."
|
|
82
|
+
err "If the tunnel really is finished with, close the SSH session holding the"
|
|
83
|
+
err "forward - on the laptop that is stop.ps1 - and this port frees itself."
|
|
84
|
+
exit 7
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
# ss -lntp line format includes users:(("<name>",pid=<pid>,fd=<fd>))
|
|
88
|
+
pid=$(printf '%s' "$line" | grep -oE 'pid=[0-9]+' | head -n1 | cut -d= -f2)
|
|
89
|
+
if [ -z "${pid:-}" ]; then
|
|
90
|
+
err "could not parse PID from ss output. Run: sudo ss -lntp 'sport = :$PORT'"
|
|
91
|
+
exit 2
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
pname=$(ps -o comm= -p "$pid" 2>/dev/null || true)
|
|
95
|
+
ppid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ' || true)
|
|
96
|
+
log "PID $pid ($pname), parent PID $ppid"
|
|
97
|
+
|
|
98
|
+
# Guardrail: is this process part of the current user's active SSH session?
|
|
99
|
+
# If the holder (or any ancestor) is our own sshd session leader, refuse.
|
|
100
|
+
current_sid=$(loginctl show-session "$(loginctl | awk -v u="$(id -un)" '$3==u {print $1; exit}')" -p Leader --value 2>/dev/null || true)
|
|
101
|
+
|
|
102
|
+
# Walk ancestors of the holder. If we meet $$ (this script's own shell) or
|
|
103
|
+
# its session leader, it's us.
|
|
104
|
+
own_tree=0
|
|
105
|
+
cursor=$pid
|
|
106
|
+
for _ in 1 2 3 4 5 6 7 8; do
|
|
107
|
+
[ -z "$cursor" ] && break
|
|
108
|
+
[ "$cursor" = "1" ] && break
|
|
109
|
+
if [ "$cursor" = "$$" ] || [ "$cursor" = "$PPID" ]; then
|
|
110
|
+
own_tree=1
|
|
111
|
+
break
|
|
112
|
+
fi
|
|
113
|
+
if [ -n "${current_sid:-}" ] && [ "$cursor" = "$current_sid" ]; then
|
|
114
|
+
own_tree=1
|
|
115
|
+
break
|
|
116
|
+
fi
|
|
117
|
+
cursor=$(ps -o ppid= -p "$cursor" 2>/dev/null | tr -d ' ' || true)
|
|
118
|
+
done
|
|
119
|
+
|
|
120
|
+
if [ "$own_tree" = "1" ]; then
|
|
121
|
+
err "port $PORT is held by your own interactive session (PID $pid, ancestor of this shell)."
|
|
122
|
+
err "Killing it would drop the SSH session running this script."
|
|
123
|
+
err "Exit this SSH session from another shell, or close the client, then retry."
|
|
124
|
+
exit 3
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
# Prefer not to kill anything that is not sshd – surface it for review.
|
|
128
|
+
if [ "$pname" != "sshd" ] && [ "$pname" != "sshd-session" ]; then
|
|
129
|
+
err "holder is '$pname', not sshd. Refusing to kill a non-sshd process on port $PORT."
|
|
130
|
+
err "If this is expected (e.g. a local test server), stop it manually."
|
|
131
|
+
exit 4
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# Check parent liveness: an orphan sshd forward channel typically has a
|
|
135
|
+
# parent that has exited or has been re-parented.
|
|
136
|
+
if [ -n "${ppid:-}" ] && [ "$ppid" != "1" ]; then
|
|
137
|
+
if ! kill -0 "$ppid" 2>/dev/null; then
|
|
138
|
+
log "parent PID $ppid is gone – holder is an orphan sshd forward channel."
|
|
139
|
+
else
|
|
140
|
+
log "parent PID $ppid is alive – holder is an active sshd session, likely a stale tunnel that has not yet been reaped by ClientAlive."
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
log "killing PID $pid ..."
|
|
145
|
+
if kill "$pid" 2>/dev/null; then
|
|
146
|
+
:
|
|
147
|
+
else
|
|
148
|
+
log "kill failed without privilege; retrying with sudo."
|
|
149
|
+
if ! sudo -n kill "$pid" 2>/dev/null; then
|
|
150
|
+
err "could not kill PID $pid. Re-run with sudo, or ask the admin to kill it."
|
|
151
|
+
exit 5
|
|
152
|
+
fi
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# Give the kernel a moment to release the socket.
|
|
156
|
+
for _ in 1 2 3 4 5; do
|
|
157
|
+
sleep 1
|
|
158
|
+
if [ -z "$(find_holder)" ]; then
|
|
159
|
+
log "port $PORT is now free."
|
|
160
|
+
exit 0
|
|
161
|
+
fi
|
|
162
|
+
done
|
|
163
|
+
|
|
164
|
+
err "port $PORT still held after kill. Current state:"
|
|
165
|
+
ss -lntp "sport = :$PORT" >&2 || true
|
|
166
|
+
exit 6
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Free the keys your terminal emulator swallows
|
|
2
|
+
|
|
3
|
+
Hand this to a coding agent running **on the machine you type on** – the
|
|
4
|
+
Windows, macOS, or Linux desktop you SSH *from*. You cannot do this from the
|
|
5
|
+
remote host. The local terminal emulator intercepts the keys before they ever
|
|
6
|
+
reach the other end.
|
|
7
|
+
|
|
8
|
+
## 1. The emulator claims the same alt chords the remote host binds
|
|
9
|
+
|
|
10
|
+
On the remote host the user runs herdr, a terminal multiplexer. One program
|
|
11
|
+
holds many terminal sessions and keeps them running after the user
|
|
12
|
+
disconnects. Its setup binds `alt` key combinations, called chords, for panes,
|
|
13
|
+
tabs and popups.
|
|
14
|
+
|
|
15
|
+
Some terminal emulators bind the same chords locally. They swallow the
|
|
16
|
+
keypress, or they act on it **and** forward it, so one press does two things.
|
|
17
|
+
|
|
18
|
+
The known collision is **`alt+shift+d`**, which Windows Terminal binds to
|
|
19
|
+
"duplicate pane" by default. It splits the tab on your own machine and never
|
|
20
|
+
forwards the key, so the remote host sees nothing.
|
|
21
|
+
|
|
22
|
+
The remote setup avoids this one by putting its diff viewer on `alt+f` and
|
|
23
|
+
`alt+shift+f`. Other emulators claim other chords, so the table below still
|
|
24
|
+
has to be free.
|
|
25
|
+
|
|
26
|
+
To tell an emulator collision from a remote misconfiguration, run `cat -v` in
|
|
27
|
+
any pane and press the chord. One that arrives prints an escape sequence such
|
|
28
|
+
as `^[Z`. One that prints nothing never left your machine.
|
|
29
|
+
|
|
30
|
+
## 2. Unbind, in the terminal emulator only
|
|
31
|
+
|
|
32
|
+
Work in the terminal emulator config only. Unbind every chord in the table
|
|
33
|
+
below that the emulator currently claims. Change nothing on the remote host,
|
|
34
|
+
and do not touch the remote configuration.
|
|
35
|
+
|
|
36
|
+
| Chord | Used remotely for |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `alt+f` / `alt+shift+f` | diff viewer, popup and tab |
|
|
39
|
+
| `alt+x` / `alt+shift+x` | diff comparison picker, popup and tab |
|
|
40
|
+
| `alt+i` / `alt+shift+i` | pull request dashboard, popup and tab |
|
|
41
|
+
| `alt+y` / `alt+shift+y` | file manager, popup and tab |
|
|
42
|
+
| `alt+g` / `alt+shift+g` | git TUI, popup and tab |
|
|
43
|
+
| `alt+h` `alt+j` `alt+k` `alt+l` | move between panes |
|
|
44
|
+
| `alt+left` / `alt+right` | previous and next tab |
|
|
45
|
+
| `alt+up` / `alt+down` | previous and next workspace |
|
|
46
|
+
| `alt+1` ... `alt+9` | jump to an agent |
|
|
47
|
+
| `alt+c` `alt+e` `alt+minus` `alt+z` `alt+s` `alt+a` `alt+n` `alt+u` `alt+w` `alt+r` | new tab, splits, zoom, sidebar, last pane, agent and workspace navigation |
|
|
48
|
+
|
|
49
|
+
A workspace is one herdr container holding tabs and panes.
|
|
50
|
+
|
|
51
|
+
### Windows Terminal
|
|
52
|
+
|
|
53
|
+
Settings, then "Open JSON file". Add to the `actions` array:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{ "command": "unbound", "keys": "alt+shift+d" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Windows Terminal binds three more chords from the same family. Check
|
|
60
|
+
`alt+shift+plus`, `alt+shift+minus` and `alt+shift+<arrow>` in the same pass.
|
|
61
|
+
|
|
62
|
+
### Other emulators
|
|
63
|
+
|
|
64
|
+
- **WezTerm**: `keys` in `.wezterm.lua`, with `action = wezterm.action.DisableDefaultAssignment`
|
|
65
|
+
- **iTerm2**: Preferences, Keys, Key Bindings, or the profile's own Keys tab
|
|
66
|
+
- **kitty**: `map alt+shift+d no_op` in `kitty.conf`
|
|
67
|
+
- **Ghostty**: `keybind = alt+shift+d=ignore` in the config
|
|
68
|
+
- **GNOME Terminal / Konsole**: check the shortcut editor for the chord
|
|
69
|
+
|
|
70
|
+
## 3. What never to change
|
|
71
|
+
|
|
72
|
+
- **Back up the config before editing**, and show the change before saving.
|
|
73
|
+
- Unbind only. Do not remap these chords to something else, and do not touch
|
|
74
|
+
bindings unrelated to the table above.
|
|
75
|
+
|
|
76
|
+
- Leave a chord alone when the terminal emulator does not bind it locally.
|
|
77
|
+
|
|
78
|
+
## 4. Confirm exactly one thing happens
|
|
79
|
+
|
|
80
|
+
Reload or restart the terminal, then SSH in and press `alt+shift+f`. Exactly
|
|
81
|
+
one thing should happen.
|
|
82
|
+
|
|
83
|
+
A tab opens on the remote host. A local split, or both at once, means the
|
|
84
|
+
unbind did not take.
|
|
85
|
+
|
|
86
|
+
Report which chords the terminal emulator had bound, what changed, and how to
|
|
87
|
+
undo it.
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# ACStack terminal workspace.
|
|
2
|
+
# Copy to ~/.config/acstack/terminal-workspace.yaml, edit, then run
|
|
3
|
+
# setup.sh apply.
|
|
4
|
+
#
|
|
5
|
+
# This is machine-level, not per-project. It installs binaries and writes
|
|
6
|
+
# keybindings for your user, so it does not belong in acstack/project.yaml.
|
|
7
|
+
#
|
|
8
|
+
# What each component is, every key, and the traps worth knowing:
|
|
9
|
+
# docs/terminal-workspace.md in the ACStack plugin.
|
|
10
|
+
#
|
|
11
|
+
# A key here never carries a hyphen, so gh-dash is gh_dash. The last two
|
|
12
|
+
# blocks name a feature rather than a binary: markdown is acstack-md, and
|
|
13
|
+
# remote is acstack-clip plus acstack-open.
|
|
14
|
+
|
|
15
|
+
# Master switch. With this false, apply exits without installing anything.
|
|
16
|
+
# It removes nothing either. Use setup.sh uninstall for that.
|
|
17
|
+
enabled: true
|
|
18
|
+
|
|
19
|
+
herdr:
|
|
20
|
+
enabled: true
|
|
21
|
+
# A terminal multiplexer. One program holds many terminal sessions and keeps
|
|
22
|
+
# them running after you disconnect.
|
|
23
|
+
#
|
|
24
|
+
# A chord is one key combination, such as alt+f. herdr normally wants a
|
|
25
|
+
# prefix key first. You press the prefix, release it, then press the second
|
|
26
|
+
# key. A chord modifier replaces those two steps with one combination.
|
|
27
|
+
#
|
|
28
|
+
# Keep "alt". It is the only family measured to work on both attach paths.
|
|
29
|
+
# ctrl+alt does reach herdr when you SSH in and run it on the remote host.
|
|
30
|
+
# But a Windows client attaching with `herdr --remote` never delivers it, so
|
|
31
|
+
# those chords go silently dead.
|
|
32
|
+
# Set "none" to keep herdr's default prefix-only keymap.
|
|
33
|
+
chord_modifier: alt
|
|
34
|
+
# A pane's scrollbar costs it a column. herdr counts that column inside the
|
|
35
|
+
# pane rect but tells the program in the pane it has the full width, so a
|
|
36
|
+
# full-screen app wraps one column early and every row drifts one column
|
|
37
|
+
# left of the row above it. Set true to take the scrollbar back; scrolling
|
|
38
|
+
# itself is unaffected either way, because the mouse wheel and copy mode do
|
|
39
|
+
# not use it.
|
|
40
|
+
pane_scrollbars: false
|
|
41
|
+
# A pane border carries the name of the agent running in it. Several agents
|
|
42
|
+
# in several panes is what this workspace is for, and an unlabelled pane does
|
|
43
|
+
# not say which agent it holds. Set false to take the labels off.
|
|
44
|
+
agent_labels_on_pane_borders: true
|
|
45
|
+
# How the agent panel orders its rows: "priority" puts the agents waiting on
|
|
46
|
+
# you at the top. Empty leaves herdr's own order alone.
|
|
47
|
+
agent_panel_sort: ""
|
|
48
|
+
# Where herdr draws a toast, its own short status message. "herdr" draws it
|
|
49
|
+
# in the terminal itself, which is the only route that survives SSH. Empty
|
|
50
|
+
# leaves herdr's own choice alone.
|
|
51
|
+
toast_delivery: ""
|
|
52
|
+
theme:
|
|
53
|
+
# The colour theme herdr paints. Empty writes no theme at all, so herdr
|
|
54
|
+
# keeps whatever it already uses.
|
|
55
|
+
name: ""
|
|
56
|
+
# One herdr server, two devices, two backgrounds. auto_switch asks the
|
|
57
|
+
# attached client for its background colour over OSC 11 - an escape
|
|
58
|
+
# sequence a terminal answers with the colour it is painting - and picks
|
|
59
|
+
# the dark or the light theme from the answer. So a dark terminal on one
|
|
60
|
+
# device and a light one on another, such as an e-ink panel, each get the
|
|
61
|
+
# right theme without either changing the other.
|
|
62
|
+
#
|
|
63
|
+
# Both keys below are read only when `light` names a theme. Without one
|
|
64
|
+
# there is nothing to switch to, so `name` is written on its own.
|
|
65
|
+
auto_switch: true
|
|
66
|
+
# The theme a light client gets. `name` is what a dark one gets, and what
|
|
67
|
+
# a client that answers nothing at all falls back to.
|
|
68
|
+
light: ""
|
|
69
|
+
worktrees_directory: "~/.herdr/worktrees"
|
|
70
|
+
# Agent state hook, so herdr reads state from the agent instead of the
|
|
71
|
+
# screen. One of: claude, codex, opencode, copilot, none.
|
|
72
|
+
integration: claude
|
|
73
|
+
# Link a small herdr plugin that keeps the sidebar numbers matching the keys
|
|
74
|
+
# you press for them. Opening or closing a workspace or a worktree moves the
|
|
75
|
+
# rows, so without this the number beside a row stops being the number that
|
|
76
|
+
# jumps to it.
|
|
77
|
+
renumber_plugin: true
|
|
78
|
+
|
|
79
|
+
gh_dash:
|
|
80
|
+
enabled: true
|
|
81
|
+
# A pull request dashboard. It lists pull requests in the sections you
|
|
82
|
+
# define below, and hands the selected one to tuicr or to an agent.
|
|
83
|
+
popup_key: "alt+i"
|
|
84
|
+
tab_key: "alt+shift+i"
|
|
85
|
+
sections:
|
|
86
|
+
- title: Mine
|
|
87
|
+
filters: "is:open author:@me"
|
|
88
|
+
- title: Needs review
|
|
89
|
+
filters: "is:open review-requested:@me"
|
|
90
|
+
- title: Failing
|
|
91
|
+
filters: "is:open author:@me status:failure"
|
|
92
|
+
# Local clones. Needed for checkout and for {{.RepoPath}} in keybindings.
|
|
93
|
+
repo_paths: {}
|
|
94
|
+
# Bind PageUp and PageDown to scroll the preview. gh-dash uses ctrl+u and
|
|
95
|
+
# ctrl+d by default, which is fine in vim and awkward everywhere else.
|
|
96
|
+
page_keys: true
|
|
97
|
+
keybindings:
|
|
98
|
+
# Both keys below are what apply binds anyway with no config file present.
|
|
99
|
+
# Change either to move it, or set it to "" to leave the key unbound.
|
|
100
|
+
#
|
|
101
|
+
# Open the selected pull request in tuicr, which reviews it in place.
|
|
102
|
+
review: "D"
|
|
103
|
+
# Hand the selected pull request to an agent. Empty disables it.
|
|
104
|
+
agent_review: "S"
|
|
105
|
+
|
|
106
|
+
diffnav:
|
|
107
|
+
enabled: true
|
|
108
|
+
# A diff viewer with a file tree. The popup compares the branch you are on
|
|
109
|
+
# against origin/dev, committed work only, and names both sides in a banner.
|
|
110
|
+
# Repos without a dev branch fall back to the default branch.
|
|
111
|
+
popup_key: "alt+f"
|
|
112
|
+
# Same comparison, a new tab instead of a popup.
|
|
113
|
+
tab_key: "alt+shift+f"
|
|
114
|
+
# An fzf menu of comparisons: against dev or the default branch, with or
|
|
115
|
+
# without uncommitted work, one commit, or any branch against any branch.
|
|
116
|
+
pick_key: "alt+x"
|
|
117
|
+
# Same menu, a new tab instead of a popup.
|
|
118
|
+
pick_tab_key: "alt+shift+x"
|
|
119
|
+
|
|
120
|
+
delta:
|
|
121
|
+
enabled: true
|
|
122
|
+
# The diff renderer git pages through. Sets core.pager and
|
|
123
|
+
# interactive.diffFilter. This does not change what agents see, because git
|
|
124
|
+
# only pages to a terminal.
|
|
125
|
+
set_git_pager: true
|
|
126
|
+
|
|
127
|
+
tuicr:
|
|
128
|
+
enabled: true
|
|
129
|
+
# Reviews a pull request inside the terminal. gh-dash hands pull requests to
|
|
130
|
+
# it. It is not the file manager, which is yazi below.
|
|
131
|
+
# Starting width of the file list, as a percentage of the content area.
|
|
132
|
+
file_list_width: 30
|
|
133
|
+
# Per-file +added -removed counts in the tree.
|
|
134
|
+
show_file_line_stats: true
|
|
135
|
+
# "dark", "light", or empty to let tuicr work it out for itself.
|
|
136
|
+
#
|
|
137
|
+
# Detection asks the terminal for its background colour over OSC 11 - an
|
|
138
|
+
# escape sequence a terminal answers with the colour it is painting. Under
|
|
139
|
+
# `herdr --remote` nothing answers, so tuicr falls back to a desktop setting
|
|
140
|
+
# that a headless machine reports as light, then paints dark text on a black
|
|
141
|
+
# terminal. Pin the value on any machine you reach over the network.
|
|
142
|
+
appearance: ""
|
|
143
|
+
#
|
|
144
|
+
# TEMPORARY. Two upstream pull requests are still open, plus one local fix
|
|
145
|
+
# with none yet:
|
|
146
|
+
# agavra/tuicr#607 configurable file line stats (antonio2368)
|
|
147
|
+
# agavra/tuicr#633 <leader>L / <leader>H resize (ours)
|
|
148
|
+
# (none yet) blank +/- counts in pull request review mode (ours)
|
|
149
|
+
# Until both merge, the two settings above only exist in a fork build.
|
|
150
|
+
# `setup.sh status` checks both and tells you when to switch this off.
|
|
151
|
+
# With it false, the stock release installs and ignores those two settings.
|
|
152
|
+
build_from_fork: false
|
|
153
|
+
fork: "https://github.com/ac8318740/tuicr"
|
|
154
|
+
fork_branch: "local/daily"
|
|
155
|
+
|
|
156
|
+
lazygit:
|
|
157
|
+
enabled: true
|
|
158
|
+
# A git TUI: stage with space, commit with c, amend with A, push with P.
|
|
159
|
+
# g is reserved for it, so herdr's goto sits on prefix+t instead.
|
|
160
|
+
popup_key: "alt+g"
|
|
161
|
+
# Same tool, a new tab instead of a popup.
|
|
162
|
+
tab_key: "alt+shift+g"
|
|
163
|
+
|
|
164
|
+
harlequin:
|
|
165
|
+
enabled: true
|
|
166
|
+
# A SQL editor in the terminal. Write a query on the left, read the rows on
|
|
167
|
+
# the right, and browse the schema in a tree beside both.
|
|
168
|
+
#
|
|
169
|
+
# It is the one component that is not a downloaded binary. harlequin is a
|
|
170
|
+
# python program, so uv installs it into an environment of its own and puts
|
|
171
|
+
# one command on your PATH. A machine without uv skips this component and
|
|
172
|
+
# apply says so.
|
|
173
|
+
popup_key: "alt+q"
|
|
174
|
+
# Same editor, a new tab instead of a popup.
|
|
175
|
+
tab_key: "alt+shift+q"
|
|
176
|
+
# The databases harlequin can talk to. Each name here installs the
|
|
177
|
+
# harlequin-<name> package alongside it. Adding one and running apply again
|
|
178
|
+
# reinstalls harlequin with the new set.
|
|
179
|
+
adapters: [postgres, snowflake]
|
|
180
|
+
# Your connection profiles. acstack writes a starter file here the first time
|
|
181
|
+
# you press the key, and never writes it again - what is in it is yours.
|
|
182
|
+
#
|
|
183
|
+
# default_profile = "local"
|
|
184
|
+
#
|
|
185
|
+
# [profiles.local]
|
|
186
|
+
# adapter = "postgres"
|
|
187
|
+
# conn_str = "postgres://localhost:5432/postgres"
|
|
188
|
+
#
|
|
189
|
+
# A snowflake profile names an account, user, role, warehouse, database and
|
|
190
|
+
# schema, or a single connection_name pointing at a connection in
|
|
191
|
+
# ~/.snowflake/connections.toml. Prefer the second: it keeps the secret out
|
|
192
|
+
# of this file.
|
|
193
|
+
config_path: "~/.config/acstack/harlequin.toml"
|
|
194
|
+
|
|
195
|
+
pi:
|
|
196
|
+
# Off by default, because it writes into pi's own config in ~/.pi/agent.
|
|
197
|
+
# pi is a coding agent in the terminal. Turning this on installs it with npm
|
|
198
|
+
# if it is missing, then installs ACStack into it, pinned to this plugin's
|
|
199
|
+
# version, with pi-subagents, which ACStack needs to launch a subagent.
|
|
200
|
+
#
|
|
201
|
+
# It also writes one line into pi's context file in ~/.pi/agent (AGENTS.md
|
|
202
|
+
# by default) that lets pi delegate when an ACStack skill says to.
|
|
203
|
+
# It sets "toolActivation": "eager" in
|
|
204
|
+
# ~/.pi/agent/extensions/subagent/config.json. It binds
|
|
205
|
+
# "app.message.dequeue" to "ctrl+enter" in ~/.pi/agent/keybindings.json.
|
|
206
|
+
# These changes sit beside your own settings, which stay.
|
|
207
|
+
#
|
|
208
|
+
# Logging in is yours: run pi, then /login.
|
|
209
|
+
enabled: false
|
|
210
|
+
# pi-compact-tools, which shortens how pi draws each tool call.
|
|
211
|
+
compact_tools: true
|
|
212
|
+
# billion-context, which adds context compression to pi. When bili is on
|
|
213
|
+
# PATH, apply also runs bili's native plugin setup for pi. Claude Code and
|
|
214
|
+
# Codex stay off bili.
|
|
215
|
+
billion_context: true
|
|
216
|
+
# Pi's question tool. rpiv-ask-user-question is used because it can show
|
|
217
|
+
# markdown, code and artifact previews beside a decision, accepts freeform
|
|
218
|
+
# answers and notes, and does not require a full-event telemetry env var.
|
|
219
|
+
question_tool: true
|
|
220
|
+
# rpiv-todo, which adds a todo tool to pi.
|
|
221
|
+
todo: true
|
|
222
|
+
# pi-plugin-manager, which adds pi plugin management commands.
|
|
223
|
+
plugin_manager: true
|
|
224
|
+
# pi-web-access, which adds web search, URL fetching, GitHub repo cloning,
|
|
225
|
+
# PDF extraction and media understanding tools to pi. This is separate from
|
|
226
|
+
# pi.settings.install_telemetry, which controls pi's anonymous install and
|
|
227
|
+
# update reporting and stays false in this example.
|
|
228
|
+
web_access: true
|
|
229
|
+
# pi-lens, which adds diagnostics, code-intelligence tools and local
|
|
230
|
+
# observability logs to pi. Off by default because it is a heavier dev-tool
|
|
231
|
+
# layer and may download helper tools when pi-lens needs them.
|
|
232
|
+
lens: false
|
|
233
|
+
# pi-slash-anywhere, which lets slash commands run from any prompt.
|
|
234
|
+
slash_anywhere: true
|
|
235
|
+
# agentic-retro's pi extension, which queues each finished pi session for a
|
|
236
|
+
# retro. Needs the agentic-retro plugin installed first, and apply says so
|
|
237
|
+
# when it is not.
|
|
238
|
+
agentic_retro: true
|
|
239
|
+
# Written into ~/.pi/agent/settings.json. Empty leaves pi's own value alone.
|
|
240
|
+
# Every other key in that file stays as you set it, and disable puts back
|
|
241
|
+
# any value of yours that apply replaced.
|
|
242
|
+
settings:
|
|
243
|
+
# Hide the model's thinking in the transcript.
|
|
244
|
+
hide_thinking_block: true
|
|
245
|
+
# How pi draws a mermaid diagram: "off", "final", or "streaming".
|
|
246
|
+
# Quote it, because YAML reads a bare off as false.
|
|
247
|
+
mermaid: streaming
|
|
248
|
+
# pi's anonymous install and update reporting. Kept off by this setup.
|
|
249
|
+
install_telemetry: false
|
|
250
|
+
# A pi theme name. "system" takes its colours from the terminal.
|
|
251
|
+
theme: system
|
|
252
|
+
|
|
253
|
+
neovim:
|
|
254
|
+
# The one component that is off by default, because it writes into a neovim
|
|
255
|
+
# config you built yourself. Every other one owns its files outright.
|
|
256
|
+
enabled: false
|
|
257
|
+
# LazyVim marks an unsaved buffer by recolouring the filename and nothing
|
|
258
|
+
# else, so a glance at the statusline cannot tell you a buffer is modified.
|
|
259
|
+
# Turning this on writes ~/.config/nvim/lua/plugins/acstack.lua, a whole
|
|
260
|
+
# file of acstack's own, which appends a dot to the statusline for a
|
|
261
|
+
# modified buffer, and makes copy work over SSH (osc52_clipboard below).
|
|
262
|
+
# It never edits a file you wrote, and
|
|
263
|
+
# `setup.sh disable neovim` deletes it again.
|
|
264
|
+
# Skipped on a machine with no LazyVim config, because both parts rely on
|
|
265
|
+
# LazyVim.
|
|
266
|
+
#
|
|
267
|
+
# The colour of the dot. The default is the catppuccin red.
|
|
268
|
+
unsaved_dot_color: "#f38ba8"
|
|
269
|
+
# Over SSH, :%y+ fails because neovim finds no clipboard. This sends every
|
|
270
|
+
# copy to the machine you sit at over OSC 52. Section 3.5 of
|
|
271
|
+
# docs/terminal-workspace.md covers paste. Left out when a file of yours
|
|
272
|
+
# already sets vim.g.clipboard.
|
|
273
|
+
osc52_clipboard: true
|
|
274
|
+
|
|
275
|
+
yazi:
|
|
276
|
+
enabled: true
|
|
277
|
+
# A file manager. Markdown renders live in the preview pane through
|
|
278
|
+
# acstack-md, so a document draws as the cursor moves over it. Enter opens
|
|
279
|
+
# the same renderer full width, where more of a diagram fits.
|
|
280
|
+
# A popup, leaving the tab layout alone.
|
|
281
|
+
popup_key: "alt+y"
|
|
282
|
+
# Opens a real tab instead.
|
|
283
|
+
tab_key: "alt+shift+y"
|
|
284
|
+
# Opens the hovered file in $EDITOR. tuicr puts the editor on the same key
|
|
285
|
+
# in both its panels, so one key means edit across the workspace.
|
|
286
|
+
edit_key: "e"
|
|
287
|
+
# Sends the hovered file to your own browser.
|
|
288
|
+
browser_key: "b"
|
|
289
|
+
# Previews markdown as source, with line numbers down the left.
|
|
290
|
+
line_numbers_key: "#"
|
|
291
|
+
# Sends the hovered file to the machine you sit at, over Tailscale Taildrop.
|
|
292
|
+
# Set it to that machine's Tailscale node name, as `tailscale status` on this
|
|
293
|
+
# machine spells it. Empty writes no key at all.
|
|
294
|
+
# Both machines must sit on one tailnet under one Tailscale user account,
|
|
295
|
+
# because Taildrop refuses to cross either boundary.
|
|
296
|
+
download_target: ""
|
|
297
|
+
# The key that sends it. Only read when download_target is set.
|
|
298
|
+
download_key: "D"
|
|
299
|
+
show_hidden: true
|
|
300
|
+
|
|
301
|
+
markdown:
|
|
302
|
+
enabled: true
|
|
303
|
+
# This component installs three tools: acstack-md, mermaid-ascii and glow.
|
|
304
|
+
# acstack-md draws a markdown file in the terminal, calling glow for the
|
|
305
|
+
# prose and mermaid-ascii for the diagrams. A mermaid diagram is a diagram
|
|
306
|
+
# written as text in the file itself. acstack-md can also serve the same
|
|
307
|
+
# file to a real browser, for the diagrams worth studying.
|
|
308
|
+
#
|
|
309
|
+
# Text rather than inline images is deliberate. herdr emits the kitty
|
|
310
|
+
# graphics protocol, and no terminal reachable over SSH from Windows or
|
|
311
|
+
# Android renders it, so an image never arrives. e-ink panels also render
|
|
312
|
+
# text far better than bitmaps. The fast refresh modes an interactive
|
|
313
|
+
# terminal needs are the ones that drop the greyscale depth an image needs.
|
|
314
|
+
#
|
|
315
|
+
# acstack-md --serve takes its port from $ACSTACK_MD_PORT and falls back to
|
|
316
|
+
# 6419. Forward whichever port you serve on, or the link --serve prints is
|
|
317
|
+
# unreachable from your laptop.
|
|
318
|
+
|
|
319
|
+
remote:
|
|
320
|
+
enabled: true
|
|
321
|
+
# Copy and open, on a machine you reach over SSH.
|
|
322
|
+
#
|
|
323
|
+
# The dev machine – the remote machine your agents run on, a virtual machine
|
|
324
|
+
# in this setup – has no display and no clipboard. Anything that shells out
|
|
325
|
+
# to xclip fails, and xdg-open exits 1. Two programs close the gap.
|
|
326
|
+
# acstack-clip sends text to your own terminal's clipboard over OSC 52, an
|
|
327
|
+
# escape sequence a terminal reads as "put this text on the clipboard of the
|
|
328
|
+
# machine I am running on". acstack-open finds whatever browser is actually
|
|
329
|
+
# reachable.
|
|
330
|
+
#
|
|
331
|
+
# Install an xclip stand-in backed by acstack-clip. Programs that only know
|
|
332
|
+
# how to shell out – gh-dash's y and Y among them – then copy correctly.
|
|
333
|
+
# Skipped when the machine has a real xclip or a display of its own.
|
|
334
|
+
clipboard_shim: true
|