@junghanacs/entwurf 0.12.0
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/AGENTS.md +240 -0
- package/BASELINE.md +227 -0
- package/CHANGELOG.md +1210 -0
- package/CONTRIBUTING.md +63 -0
- package/DELIVERY.md +209 -0
- package/LICENSE +21 -0
- package/README.md +504 -0
- package/VERIFY.md +260 -0
- package/demo/README.md +188 -0
- package/demo/demo-baseline.sh +156 -0
- package/demo/demo.sh +183 -0
- package/docs/assets/entwurf-demo.gif +0 -0
- package/docs/assets/entwurf-doomemacs.gif +0 -0
- package/docs/assets/entwurf-entwurf.gif +0 -0
- package/docs/assets/entwurf-hero.jpg +0 -0
- package/docs/setup-clean-host.md +305 -0
- package/mcp/entwurf-bridge/src/index.ts +513 -0
- package/mcp/entwurf-bridge/start.sh +25 -0
- package/mcp/entwurf-bridge/test.sh +54 -0
- package/mcp/tsconfig.json +29 -0
- package/package.json +130 -0
- package/pi/entwurf-capabilities.json +9 -0
- package/pi/entwurf-targets.json +20 -0
- package/pi/meta-bridge/.claude-plugin/marketplace.json +12 -0
- package/pi/meta-bridge/entwurf-meta-receive/.claude-plugin/plugin.json +5 -0
- package/pi/meta-bridge/entwurf-meta-receive/hooks/hooks.json +50 -0
- package/pi/meta-bridge/entwurf-meta-receive/scripts/doorbell.sh +54 -0
- package/pi/settings.reference.json +43 -0
- package/pi/skill-plugin-example/.claude-plugin/plugin.json +4 -0
- package/pi/skill-plugin-example/skills/hello/SKILL.md +18 -0
- package/pi-extensions/acp-provider.ts +63 -0
- package/pi-extensions/entwurf-control.ts +1692 -0
- package/pi-extensions/lib/acp/acp-client.ts +90 -0
- package/pi-extensions/lib/acp/augment.ts +238 -0
- package/pi-extensions/lib/acp/backend-adapter.ts +319 -0
- package/pi-extensions/lib/acp/backend.ts +873 -0
- package/pi-extensions/lib/acp/config.ts +552 -0
- package/pi-extensions/lib/acp/context.ts +177 -0
- package/pi-extensions/lib/acp/engraving.ts +123 -0
- package/pi-extensions/lib/acp/event-mapper.ts +339 -0
- package/pi-extensions/lib/acp/models.ts +102 -0
- package/pi-extensions/lib/acp/overlay.ts +220 -0
- package/pi-extensions/lib/acp/prompts/engraving.md +1 -0
- package/pi-extensions/lib/acp/session-store.ts +418 -0
- package/pi-extensions/lib/acp/tool-surface.ts +184 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +208 -0
- package/pi-extensions/lib/entwurf-core.ts +2033 -0
- package/pi-extensions/lib/entwurf-deliverability.ts +123 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +158 -0
- package/pi-extensions/lib/entwurf-facts.ts +251 -0
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +100 -0
- package/pi-extensions/lib/entwurf-peers-render.ts +154 -0
- package/pi-extensions/lib/entwurf-preflight.ts +247 -0
- package/pi-extensions/lib/entwurf-resume-args.ts +88 -0
- package/pi-extensions/lib/entwurf-self-address.ts +117 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +427 -0
- package/pi-extensions/lib/entwurf-v2-decider.ts +441 -0
- package/pi-extensions/lib/entwurf-v2-lock.ts +412 -0
- package/pi-extensions/lib/entwurf-v2-mailbox.ts +87 -0
- package/pi-extensions/lib/entwurf-v2-production.ts +326 -0
- package/pi-extensions/lib/entwurf-v2-release.ts +149 -0
- package/pi-extensions/lib/entwurf-v2-resume-marker.ts +34 -0
- package/pi-extensions/lib/entwurf-v2-runner.ts +196 -0
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +166 -0
- package/pi-extensions/lib/entwurf-v2-send.ts +271 -0
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +337 -0
- package/pi-extensions/lib/entwurf-v2-spawn.ts +323 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +205 -0
- package/pi-extensions/lib/meta-mailbox-body.ts +80 -0
- package/pi-extensions/lib/meta-session.ts +1951 -0
- package/pi-extensions/lib/project-trust-handler.ts +154 -0
- package/pi-extensions/lib/session-id.js +57 -0
- package/pi-extensions/lib/socket-discovery.ts +346 -0
- package/pi-extensions/lib/socket-probe.ts +92 -0
- package/pi-extensions/meta-bridge-hook.ts +250 -0
- package/pi-extensions/model-lock.ts +235 -0
- package/prompts/engraving.md +27 -0
- package/protocol.js +31 -0
- package/run.sh +2832 -0
- package/scripts/check-acp-backend-preflight.ts +130 -0
- package/scripts/check-acp-carrier-augment.ts +297 -0
- package/scripts/check-acp-config.ts +322 -0
- package/scripts/check-acp-event-mapper.ts +253 -0
- package/scripts/check-acp-overlay.ts +154 -0
- package/scripts/check-acp-prompt-builder.ts +191 -0
- package/scripts/check-acp-provider-surface.ts +159 -0
- package/scripts/check-acp-sdk-surface.ts +211 -0
- package/scripts/check-acp-session-reuse.ts +756 -0
- package/scripts/check-acp-session-store.ts +387 -0
- package/scripts/check-acp-tool-surface.ts +159 -0
- package/scripts/check-entwurf-bridge-boot.ts +199 -0
- package/scripts/check-entwurf-capabilities.ts +123 -0
- package/scripts/check-entwurf-control-rpc.ts +187 -0
- package/scripts/check-entwurf-deliverability.ts +158 -0
- package/scripts/check-entwurf-fact-provider.ts +316 -0
- package/scripts/check-entwurf-facts.ts +358 -0
- package/scripts/check-entwurf-mailbox-guard.ts +264 -0
- package/scripts/check-entwurf-peers-surface.ts +235 -0
- package/scripts/check-entwurf-resume-args.ts +149 -0
- package/scripts/check-entwurf-self-address.ts +209 -0
- package/scripts/check-entwurf-session-identity.ts +703 -0
- package/scripts/check-entwurf-v2-contract.ts +536 -0
- package/scripts/check-entwurf-v2-decider.ts +795 -0
- package/scripts/check-entwurf-v2-lock.ts +368 -0
- package/scripts/check-entwurf-v2-mailbox.ts +228 -0
- package/scripts/check-entwurf-v2-matrix.ts +437 -0
- package/scripts/check-entwurf-v2-production.ts +406 -0
- package/scripts/check-entwurf-v2-release.ts +245 -0
- package/scripts/check-entwurf-v2-runner.ts +452 -0
- package/scripts/check-entwurf-v2-send-fallback.ts +371 -0
- package/scripts/check-entwurf-v2-send.ts +454 -0
- package/scripts/check-entwurf-v2-spawn-production.ts +452 -0
- package/scripts/check-entwurf-v2-spawn.ts +398 -0
- package/scripts/check-entwurf-v2-surface.ts +352 -0
- package/scripts/check-keyset-overlap.py +120 -0
- package/scripts/check-mailbox-receipt-state.ts +170 -0
- package/scripts/check-meta-capability-source.ts +112 -0
- package/scripts/check-meta-dual-consumers.ts +154 -0
- package/scripts/check-meta-dual-read.ts +158 -0
- package/scripts/check-meta-listing.ts +138 -0
- package/scripts/check-meta-mailbox-state-write.ts +135 -0
- package/scripts/check-meta-migration.ts +212 -0
- package/scripts/check-meta-receiver-marker.ts +185 -0
- package/scripts/check-meta-record-v2.ts +191 -0
- package/scripts/check-meta-session.ts +673 -0
- package/scripts/check-model-lock.ts +408 -0
- package/scripts/check-package-source-routing.ts +253 -0
- package/scripts/check-pi-preflight.ts +304 -0
- package/scripts/check-project-trust-handler.ts +265 -0
- package/scripts/check-shell-quote.ts +121 -0
- package/scripts/check-socket-discovery.ts +428 -0
- package/scripts/check-socket-probe.ts +106 -0
- package/scripts/fixtures/probe-mcp-server.ts +33 -0
- package/scripts/gnew-rpc-drive.ts +211 -0
- package/scripts/lib/acp-child-cleanup.ts +116 -0
- package/scripts/meta-bridge-doctor.sh +315 -0
- package/scripts/meta-bridge-hook-log.sh +26 -0
- package/scripts/meta-bridge-install.sh +135 -0
- package/scripts/meta-bridge-prune.ts +199 -0
- package/scripts/meta-bridge-state.py +549 -0
- package/scripts/meta-bridge-statusline.sh +192 -0
- package/scripts/meta-bridge-store-doctor.ts +64 -0
- package/scripts/meta-bridge-uninstall.sh +39 -0
- package/scripts/new-session-id.ts +25 -0
- package/scripts/postinstall-chmod.cjs +58 -0
- package/scripts/raw-async-delivery/README.md +258 -0
- package/scripts/raw-async-delivery/cc-enqueue-addressed.sh +35 -0
- package/scripts/raw-async-delivery/cc-mailbox-rewake.sh +38 -0
- package/scripts/raw-async-delivery/cc-watch-filechanged.sh +19 -0
- package/scripts/raw-async-delivery/cc-watch-sessionstart.sh +15 -0
- package/scripts/raw-async-delivery/codex-local-appserver.sh +39 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/.claude-plugin/plugin.json +5 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/hooks/hooks.json +28 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-filechanged.sh +28 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-sessionstart.sh +27 -0
- package/scripts/raw-async-delivery/raw-agy-send.sh +29 -0
- package/scripts/raw-async-delivery/raw-claude-enqueue.sh +30 -0
- package/scripts/raw-async-delivery/raw-codex-ws-turn-start.py +164 -0
- package/scripts/raw-async-delivery/repro-addressed-routing.sh +96 -0
- package/scripts/raw-async-delivery/repro-plugin-idle-wake.sh +104 -0
- package/scripts/resolve-acp-bridge.ts +25 -0
- package/scripts/smoke-acp-bundled-mcp-live.ts +292 -0
- package/scripts/smoke-acp-carrier-augment-live.ts +192 -0
- package/scripts/smoke-acp-mcp-live.ts +129 -0
- package/scripts/smoke-acp-memory-containment-live.ts +389 -0
- package/scripts/smoke-acp-overlay-live.ts +314 -0
- package/scripts/smoke-acp-provider-live.ts +162 -0
- package/scripts/smoke-acp-raw-turn-live.ts +261 -0
- package/scripts/smoke-acp-session-reuse-live.ts +172 -0
- package/scripts/smoke-acp-skill-live.ts +144 -0
- package/scripts/smoke-acp-socket-citizen-live.ts +168 -0
- package/scripts/smoke-claude-native-resume-live.sh +198 -0
- package/scripts/smoke-entwurf-v2-matrix-live.ts +398 -0
- package/scripts/smoke-entwurf-v2-spawn-live.ts +175 -0
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +428 -0
- package/scripts/smoke-meta-async-drift.sh +171 -0
- package/scripts/smoke-meta-honesty.sh +147 -0
- package/scripts/smoke-meta-install-state.sh +403 -0
- package/scripts/smoke-meta-keyset-guard.sh +111 -0
- package/scripts/smoke-meta-prune.sh +174 -0
- package/scripts/smoke-resident-garden-guard.sh +433 -0
- package/scripts/smoke-session-id-name.ts +187 -0
- package/scripts/tsconfig.json +34 -0
package/demo/demo.sh
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# entwurf-demo.sh — one-shot recorded demo of entwurf entwurf flow.
|
|
3
|
+
#
|
|
4
|
+
# Layout (tmux, 220x50):
|
|
5
|
+
# pane 0 (top) — peer pi (codex, gpt-5.4) — idle, waits for greeting
|
|
6
|
+
# pane 1 (bottom) — sender pi (claude-sonnet-4-6) — driven by send-keys
|
|
7
|
+
#
|
|
8
|
+
# Scenes (driven into sender pane):
|
|
9
|
+
# 1. Spawn a sonnet sibling, store one fact.
|
|
10
|
+
# 2. Resume that sibling, recall the fact.
|
|
11
|
+
# 3. entwurf_peers → pick a peer → entwurf_send greeting (wants_reply).
|
|
12
|
+
#
|
|
13
|
+
# Recording: asciinema → demo.cast → agg → demo.gif
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# ---------- config ----------
|
|
18
|
+
SESSION=${SESSION:-entwurf-demo}
|
|
19
|
+
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
20
|
+
REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd)
|
|
21
|
+
# Recording artifacts land in the publish surface (docs/assets/) so the cast
|
|
22
|
+
# + gif are versioned alongside the README/gallery references. The *.cast
|
|
23
|
+
# file remains gitignored (global `*.cast` rule); only the .gif is tracked
|
|
24
|
+
# via the `files` allowlist in package.json. Debug logs stay next to the
|
|
25
|
+
# script (gitignored via `demo/*.log`).
|
|
26
|
+
OUTDIR=${OUTDIR:-$SCRIPT_DIR} # debug log dir (local)
|
|
27
|
+
PUBLISH_DIR=${PUBLISH_DIR:-$REPO_ROOT/docs/assets} # cast + gif (publish surface)
|
|
28
|
+
CAST="$PUBLISH_DIR/entwurf-entwurf.cast"
|
|
29
|
+
GIF="$PUBLISH_DIR/entwurf-entwurf.gif"
|
|
30
|
+
PEER_LOG="$OUTDIR/peer-debug.log"
|
|
31
|
+
SENDER_LOG="$OUTDIR/sender-debug.log"
|
|
32
|
+
|
|
33
|
+
# Models match the user's piat / pias aliases.
|
|
34
|
+
PEER_MODEL=${PEER_MODEL:-entwurf/gpt-5.4} # piat
|
|
35
|
+
SENDER_MODEL=${SENDER_MODEL:-entwurf/claude-sonnet-4-6} # pias
|
|
36
|
+
|
|
37
|
+
# Pacing in seconds. Tuned from real runs: each scene's actual agent work
|
|
38
|
+
# completes in ~5–15 s (Scene 1 sibling cold-spawn is the slowest; resume +
|
|
39
|
+
# entwurf_send are faster). 25 s gives a small safety margin without long
|
|
40
|
+
# idle stretches in the GIF.
|
|
41
|
+
WARMUP=${WARMUP:-3}
|
|
42
|
+
SCENE_DELAY=${SCENE_DELAY:-25}
|
|
43
|
+
FINAL_PAUSE=${FINAL_PAUSE:-5}
|
|
44
|
+
|
|
45
|
+
# GIF playback speed multiplier applied at agg conversion time.
|
|
46
|
+
GIF_SPEED=${GIF_SPEED:-2.8}
|
|
47
|
+
|
|
48
|
+
EMACS_SOCKET=${PI_EMACS_AGENT_SOCKET:-server}
|
|
49
|
+
|
|
50
|
+
# Debug output: ENTWURF_DEBUG=1 is always on inside the panes. Each pane's
|
|
51
|
+
# stderr is appended to its own log file so the GIF stays clean. To watch live,
|
|
52
|
+
# open a separate terminal:
|
|
53
|
+
# tail -f ~/tmp/entwurf-demo/sender-debug.log
|
|
54
|
+
# tail -f ~/tmp/entwurf-demo/peer-debug.log
|
|
55
|
+
|
|
56
|
+
# ---------- prep ----------
|
|
57
|
+
mkdir -p "$OUTDIR" "$PUBLISH_DIR"
|
|
58
|
+
|
|
59
|
+
cleanup() {
|
|
60
|
+
tmux kill-session -t "$SESSION" 2>/dev/null || true
|
|
61
|
+
}
|
|
62
|
+
trap cleanup EXIT
|
|
63
|
+
|
|
64
|
+
tmux kill-session -t "$SESSION" 2>/dev/null || true
|
|
65
|
+
|
|
66
|
+
# Reset debug log files for this run.
|
|
67
|
+
: > "$PEER_LOG"
|
|
68
|
+
: > "$SENDER_LOG"
|
|
69
|
+
|
|
70
|
+
# Each pane runs with ENTWURF_DEBUG=1; stderr appended to its own log file.
|
|
71
|
+
# Plain `2>>` is POSIX sh — works under tmux's default /bin/sh.
|
|
72
|
+
COMMON_ENV="ENTWURF_DEBUG=1 PI_EMACS_AGENT_SOCKET=$EMACS_SOCKET"
|
|
73
|
+
COMMON_ARGS="--entwurf-control --emacs-agent-socket $EMACS_SOCKET"
|
|
74
|
+
new_session_id() { bash "$REPO_ROOT/run.sh" new-session-id; }
|
|
75
|
+
|
|
76
|
+
# Snapshot pre-existing control sockets so we can detect which one this demo's
|
|
77
|
+
# peer pane creates. Without this, Scene 3 could greet an unrelated live pi
|
|
78
|
+
# session on the operator's machine.
|
|
79
|
+
SOCK_DIR="$HOME/.pi/entwurf-control"
|
|
80
|
+
PRE_SOCKETS=$(ls "$SOCK_DIR"/*.sock 2>/dev/null | sort || true)
|
|
81
|
+
|
|
82
|
+
wait_for_new_socket() {
|
|
83
|
+
# Args: <baseline-list> → echoes the first sessionId not in baseline. Times
|
|
84
|
+
# out after 30 s.
|
|
85
|
+
local baseline="$1"
|
|
86
|
+
for _ in $(seq 1 30); do
|
|
87
|
+
local current
|
|
88
|
+
current=$(ls "$SOCK_DIR"/*.sock 2>/dev/null | sort || true)
|
|
89
|
+
local fresh
|
|
90
|
+
fresh=$(comm -23 <(printf "%s\n" "$current") <(printf "%s\n" "$baseline") | head -1)
|
|
91
|
+
if [ -n "$fresh" ]; then
|
|
92
|
+
basename "$fresh" .sock
|
|
93
|
+
return 0
|
|
94
|
+
fi
|
|
95
|
+
sleep 1
|
|
96
|
+
done
|
|
97
|
+
return 1
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Pane targeting uses absolute pane IDs (%N) so this script is independent of
|
|
101
|
+
# the operator's tmux `base-index` / `pane-base-index` settings.
|
|
102
|
+
|
|
103
|
+
# ---------- start peer (top pane) — equivalent to: piat / piag / piat5 ----------
|
|
104
|
+
PEER_LAUNCH_ID=$(new_session_id)
|
|
105
|
+
tmux new-session -d -s "$SESSION" -n demo -x 220 -y 50 \
|
|
106
|
+
"$COMMON_ENV pi --session-id $PEER_LAUNCH_ID --model $PEER_MODEL $COMMON_ARGS 2>>$PEER_LOG"
|
|
107
|
+
PEER_PANE=$(tmux list-panes -s -t "$SESSION" -F '#{pane_id}' | head -1)
|
|
108
|
+
|
|
109
|
+
PEER_ID=$(wait_for_new_socket "$PRE_SOCKETS") || {
|
|
110
|
+
echo "ERROR: peer session never registered a control socket. Check $PEER_LOG." >&2
|
|
111
|
+
exit 1
|
|
112
|
+
}
|
|
113
|
+
echo "Peer sessionId: $PEER_ID pane=$PEER_PANE"
|
|
114
|
+
|
|
115
|
+
# Update baseline before launching sender so we can isolate the sender's id too.
|
|
116
|
+
POST_PEER_SOCKETS=$(ls "$SOCK_DIR"/*.sock 2>/dev/null | sort || true)
|
|
117
|
+
|
|
118
|
+
# ---------- start sender (bottom pane, split below) — equivalent to: pias / piao ----------
|
|
119
|
+
SENDER_LAUNCH_ID=$(new_session_id)
|
|
120
|
+
SENDER_PANE=$(tmux split-window -t "$PEER_PANE" -v -P -F '#{pane_id}' \
|
|
121
|
+
"$COMMON_ENV pi --session-id $SENDER_LAUNCH_ID --model $SENDER_MODEL $COMMON_ARGS 2>>$SENDER_LOG")
|
|
122
|
+
|
|
123
|
+
SENDER_ID=$(wait_for_new_socket "$POST_PEER_SOCKETS") || {
|
|
124
|
+
echo "ERROR: sender session never registered a control socket. Check $SENDER_LOG." >&2
|
|
125
|
+
exit 1
|
|
126
|
+
}
|
|
127
|
+
echo "Sender sessionId: $SENDER_ID pane=$SENDER_PANE"
|
|
128
|
+
|
|
129
|
+
# Give both processes time to finish printing their banners and reach the prompt.
|
|
130
|
+
sleep "$WARMUP"
|
|
131
|
+
|
|
132
|
+
# ---------- driver (background): types prompts into sender pane ----------
|
|
133
|
+
# SENDER_PANE was captured above as a tmux pane id (%N), which is stable across
|
|
134
|
+
# window/pane base-index configs.
|
|
135
|
+
drive() {
|
|
136
|
+
# Scene 1 — spawn + memory write
|
|
137
|
+
tmux send-keys -t "$SENDER_PANE" -l 'Demo scene 1. Spawn a claude-sonnet-4-6 sibling via the entwurf tool. provider: entwurf, model: claude-sonnet-4-6, cwd: /home/junghan/repos/gh/entwurf, mode: sync. Task body: "You are a sibling for a recorded demo. Remember one fact only — my favorite forge color is tempered indigo. Reply with one short sentence acknowledging. No tool calls, no repo exploration." After it returns, print only the Session ID line so I can see it.'
|
|
138
|
+
tmux send-keys -t "$SENDER_PANE" Enter
|
|
139
|
+
sleep "$SCENE_DELAY"
|
|
140
|
+
|
|
141
|
+
# Scene 2 — resume + memory recall
|
|
142
|
+
tmux send-keys -t "$SENDER_PANE" -l 'Demo scene 2. Resume the sibling you just spawned using entwurf_resume with the Session ID from scene 1. Prompt body: "Recall test. No tool calls. One short sentence only. What is my favorite forge color? Answer with just the color phrase."'
|
|
143
|
+
tmux send-keys -t "$SENDER_PANE" Enter
|
|
144
|
+
sleep "$SCENE_DELAY"
|
|
145
|
+
|
|
146
|
+
# Scene 3 — cross-session greeting via entwurf_send (sessionId hardcoded to
|
|
147
|
+
# the demo's peer pane so we never accidentally greet an unrelated live pi
|
|
148
|
+
# session on the operator's machine).
|
|
149
|
+
tmux send-keys -t "$SENDER_PANE" -l "Demo scene 3. Call entwurf_send with sessionId=\"$PEER_ID\", wants_reply=true, mode=follow_up, message body: \"Hi peer — sonnet sibling speaking from the entwurf recorded demo. One-line reply only please: what model are you running on?\". Print the delivery confirmation."
|
|
150
|
+
tmux send-keys -t "$SENDER_PANE" Enter
|
|
151
|
+
sleep $((SCENE_DELAY + FINAL_PAUSE))
|
|
152
|
+
|
|
153
|
+
# End: detach asciinema by killing tmux session
|
|
154
|
+
tmux kill-session -t "$SESSION" 2>/dev/null || true
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
drive &
|
|
158
|
+
DRIVE_PID=$!
|
|
159
|
+
|
|
160
|
+
# ---------- record ----------
|
|
161
|
+
asciinema rec --overwrite --quiet \
|
|
162
|
+
--command "tmux attach -t $SESSION" \
|
|
163
|
+
"$CAST" || true
|
|
164
|
+
|
|
165
|
+
wait "$DRIVE_PID" 2>/dev/null || true
|
|
166
|
+
|
|
167
|
+
# ---------- convert to gif ----------
|
|
168
|
+
if command -v agg >/dev/null 2>&1; then
|
|
169
|
+
echo "Converting cast → gif via agg (speed=${GIF_SPEED})..."
|
|
170
|
+
agg --speed "$GIF_SPEED" --theme monokai "$CAST" "$GIF"
|
|
171
|
+
echo "GIF: $GIF"
|
|
172
|
+
else
|
|
173
|
+
echo "agg not found; keeping cast only: $CAST"
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
# ---------- summary ----------
|
|
177
|
+
echo "Cast: $CAST"
|
|
178
|
+
echo "Peer log: $PEER_LOG ($(wc -l < "$PEER_LOG" 2>/dev/null || echo 0) lines)"
|
|
179
|
+
echo "Sender log: $SENDER_LOG ($(wc -l < "$SENDER_LOG" 2>/dev/null || echo 0) lines)"
|
|
180
|
+
echo
|
|
181
|
+
echo "Quick debug peek:"
|
|
182
|
+
echo " grep 'entwurf:debug' $SENDER_LOG | head -20"
|
|
183
|
+
echo " grep -E '(entwurf|model-switch)' $SENDER_LOG | head -20"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Clean-host setup walk-through
|
|
2
|
+
|
|
3
|
+
End-to-end install of **entwurf** on a host with only `git` available — no
|
|
4
|
+
node, no pnpm, no pi binary, no dotfiles. The point is to validate the public
|
|
5
|
+
install surface as an outside user would experience it.
|
|
6
|
+
|
|
7
|
+
> **Scope.** This is the entwurf 0.12.0 install recipe. The earlier per-command
|
|
8
|
+
> cleanhost evidence dumps (recorded 2026-05-18, pi-shell-acp era) are not
|
|
9
|
+
> carried forward here — they live in git history. The command *shape* below is
|
|
10
|
+
> the current one; substitute your own host.
|
|
11
|
+
|
|
12
|
+
`entwurf` is a thin meta-bridge. It does not provide, copy, or mediate any
|
|
13
|
+
backend credential — it spawns the official backend CLI and lets it read
|
|
14
|
+
whatever auth the user already trusts on the host (AGENTS.md Hard Rule #9).
|
|
15
|
+
|
|
16
|
+
## Reference target
|
|
17
|
+
|
|
18
|
+
Written against a clean Ubuntu / Debian / macOS host reachable via SSH, here
|
|
19
|
+
called `cleanhost`. `nvm` + `corepack` keep the path identical across them.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ssh cleanhost 'uname -a; whoami; which git node pnpm pi 2>/dev/null'
|
|
23
|
+
# expect: git present, node/pnpm/pi absent
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Pin matrix
|
|
27
|
+
|
|
28
|
+
These pins are the verification axis — drift from them moves you off the
|
|
29
|
+
walk-through and onto your own integration.
|
|
30
|
+
|
|
31
|
+
| Component | Pin | Source of truth |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| Node | **24** (LTS line) | `engines.node` is `>=22.6.0` (minimum, for TypeScript strip-types); verification axis is **24** |
|
|
34
|
+
| pnpm | **10.33.0** (via corepack) | matches the version entwurf's `pnpm check` chain runs under |
|
|
35
|
+
| pi binary | **`@earendil-works/pi-coding-agent` 0.80.2 or newer** | npm registry; binary name `pi`; garden-native session identity needs `--session-id` / `--name` |
|
|
36
|
+
| entwurf install path | `npm:@junghanacs/entwurf` (published release path) | the `git:github.com/junghan0611/entwurf` source path remains the alternative for tracking `main` |
|
|
37
|
+
|
|
38
|
+
## Stage 0 — Node 24 + pnpm via nvm
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
ssh cleanhost
|
|
42
|
+
|
|
43
|
+
# nvm (user-scope, no global root)
|
|
44
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
|
45
|
+
source ~/.nvm/nvm.sh
|
|
46
|
+
|
|
47
|
+
# Node 24 explicit — not --lts (re-runnable across calendar drift)
|
|
48
|
+
nvm install 24
|
|
49
|
+
nvm alias default 24
|
|
50
|
+
node -v # expect: v24.x.y
|
|
51
|
+
|
|
52
|
+
# pnpm via corepack (user-scope, no -g)
|
|
53
|
+
corepack enable
|
|
54
|
+
corepack prepare pnpm@10.33.0 --activate
|
|
55
|
+
pnpm -v # expect: 10.33.0
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Drift points:
|
|
59
|
+
- corporate proxy / sudo policy may block `curl | bash`. Fallback: clone `nvm` via git and source `~/.nvm/nvm.sh` directly.
|
|
60
|
+
- `corepack enable` needs Node 24's bundled corepack — confirm with `corepack -v` before activate.
|
|
61
|
+
- **Subshell trap**: `nvm install 24 | tail` runs the install inside a pipe-subshell, so PATH changes do not reach the parent shell and `node -v` fails right after. Drop the pipe, or follow with an explicit `nvm use 24` in the same shell (the recipe above already does).
|
|
62
|
+
|
|
63
|
+
## Stage 1 — pi binary
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# global install with the user's nvm shim (no system-wide root)
|
|
67
|
+
npm i -g @earendil-works/pi-coding-agent
|
|
68
|
+
pi --version # expect: 0.80.2 or newer
|
|
69
|
+
|
|
70
|
+
# pi's data dir is created lazily on first run
|
|
71
|
+
pi --help | head -5
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Drift points:
|
|
75
|
+
- if `npm i -g` lands outside the nvm shim, `pi` may not be on `$PATH` after a shell reload. `which pi` should resolve under `~/.nvm/versions/node/v24.*/bin/pi`.
|
|
76
|
+
- backend ACP server packages (e.g. `claude-agent-acp`) ship as pinned `dependencies` of entwurf and get installed in the next stage — **do not install them globally yourself**.
|
|
77
|
+
|
|
78
|
+
## Stage 2 — entwurf install (npm path)
|
|
79
|
+
|
|
80
|
+
Install the bridge from the published npm package. `pi install` lands it under
|
|
81
|
+
`~/.pi/agent/npm/node_modules/@junghanacs/entwurf/`, then `run.sh install` wires
|
|
82
|
+
it into a target project's `.pi/` directory.
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# package-side install — populates ~/.pi/agent/npm/node_modules/...
|
|
86
|
+
pi install npm:@junghanacs/entwurf
|
|
87
|
+
|
|
88
|
+
# verify the package landed where pi expects it
|
|
89
|
+
ls ~/.pi/agent/npm/node_modules/@junghanacs/entwurf/
|
|
90
|
+
|
|
91
|
+
# project-side wire-up — pick an empty cwd for the smoke
|
|
92
|
+
mkdir -p ~/entwurf-smoke
|
|
93
|
+
cd ~/entwurf-smoke
|
|
94
|
+
~/.pi/agent/npm/node_modules/@junghanacs/entwurf/run.sh install .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`run.sh install .` runs the one-shot wiring the consumer-project README
|
|
98
|
+
documents: writes `.pi/` config, registers the extensions (provider,
|
|
99
|
+
`entwurf-control`, `model-lock`), adds `entwurfProvider.mcpServers.entwurf-bridge`,
|
|
100
|
+
and links `~/.pi/agent/entwurf-targets.json` to the package's
|
|
101
|
+
`pi/entwurf-targets.json`. Expected log lines:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
install: added entwurfProvider.mcpServers.entwurf-bridge
|
|
105
|
+
install: updated <cwd>/.pi/settings.json
|
|
106
|
+
install: package source -> ~/.pi/agent/npm/node_modules/@junghanacs/entwurf
|
|
107
|
+
install: linked ~/.pi/agent/entwurf-targets.json -> .../pi/entwurf-targets.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Drift points:
|
|
111
|
+
- with no backend credentials yet, `run.sh install .` still completes — it does not validate backend auth, only registers the bridge.
|
|
112
|
+
- `~/.pi/agent/npm/...` is fixed by pi's install scanner. Use `pi install -l npm:...` to land it inside the project cwd instead.
|
|
113
|
+
- the `git:github.com/junghan0611/entwurf` source path is the alternative for tracking `main` or hacking on the bridge; it clones into `~/.pi/agent/git/...` with the same `run.sh install .` wire-up.
|
|
114
|
+
- `pi install` runs `npm install` inside the package; `husky` is dev-only and absent on a target host, so its `prepare` hook silently exits 0.
|
|
115
|
+
|
|
116
|
+
## Stage 3 — package-surface verification (auth-free)
|
|
117
|
+
|
|
118
|
+
Proves the bridge is registered and visible to pi, without touching any
|
|
119
|
+
backend.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cd ~/entwurf-smoke
|
|
123
|
+
|
|
124
|
+
# the entwurf provider should now appear in pi's catalog
|
|
125
|
+
pi --list-models entwurf
|
|
126
|
+
# expect: curated model ids under provider entwurf
|
|
127
|
+
# (claude-opus-4-8, claude-sonnet-4-6, ...), exit code 0
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Deterministic gates (no live backend) from the clone:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
cd ~/.pi/agent/git/github.com/junghan0611/entwurf
|
|
134
|
+
pnpm install
|
|
135
|
+
pnpm typecheck
|
|
136
|
+
./run.sh check-bridge # MCP tool contract (tools/list + negatives)
|
|
137
|
+
./run.sh check-package-source-routing # install-root resolver, fail-fast routing
|
|
138
|
+
# full deterministic floor (longer, ~60 gates): pnpm check
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Drift points:
|
|
142
|
+
- `pi --list-models entwurf` failing here means the install scanner did not register the extension — most often a node engines mismatch or a permission issue under `~/.pi/`. Re-run Stage 2 after fixing.
|
|
143
|
+
- the `pnpm install` step may emit an `Ignored build scripts` warning for transitive deps (pnpm refuses postinstall hooks by default). Our surface does not need them; the warning is informational.
|
|
144
|
+
|
|
145
|
+
## Stage 4 — runtime smoke (backend auth required)
|
|
146
|
+
|
|
147
|
+
Backend authentication is **the operator's responsibility** and lives entirely
|
|
148
|
+
outside entwurf. The 0.12.0 runtime floor is **Claude-first** — the
|
|
149
|
+
`smoke-acp-*-live` floor inside `release-gate` exercises the Claude ACP backend
|
|
150
|
+
only (there is no standalone per-backend smoke command). Codex reaches the
|
|
151
|
+
garden as a native citizen (ACP only via the `ENTWURF_ACP_FOR_CODEX=1` opt-in,
|
|
152
|
+
off the live floor); the Gemini path is deprecated.
|
|
153
|
+
|
|
154
|
+
### Stage 4 prep — Claude CLI install + login
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# Claude — official install script (writes into ~/.local/bin, no sudo).
|
|
158
|
+
curl -fsSL https://claude.ai/install.sh | bash
|
|
159
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
|
|
160
|
+
source ~/.bashrc
|
|
161
|
+
which claude && claude --version
|
|
162
|
+
|
|
163
|
+
# interactive login (opens browser or prints a token-paste URL)
|
|
164
|
+
claude login
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`claude login` writes into Claude's own state directory. entwurf does not
|
|
168
|
+
provide, copy, decrypt, or mediate these credentials. If a smoke fails, run the
|
|
169
|
+
backend CLI directly first (`claude -p "ping"`); if that also fails, the
|
|
170
|
+
missing piece is upstream of entwurf.
|
|
171
|
+
|
|
172
|
+
> **Codex / Gemini (optional).** `npm i -g @openai/codex` + `codex login` for
|
|
173
|
+
> the Codex lane; `npm i -g @google/gemini-cli` + `gemini auth` for the
|
|
174
|
+
> deprecated Gemini probe. Neither is on the 0.12.0 live floor — the
|
|
175
|
+
> `smoke-acp-*-live` gates run the Claude ACP backend only; Codex/agy delivery
|
|
176
|
+
> is captured as raw probes in [DELIVERY.md](../DELIVERY.md).
|
|
177
|
+
|
|
178
|
+
### Stage 4 prep — interactive setting (optional)
|
|
179
|
+
|
|
180
|
+
For live interactive use (vs. headless CI), pin tool-progress visibility:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
node -e '
|
|
184
|
+
const fs = require("fs");
|
|
185
|
+
const path = process.env.HOME + "/entwurf-smoke/.pi/settings.json";
|
|
186
|
+
const cur = JSON.parse(fs.readFileSync(path, "utf8"));
|
|
187
|
+
cur.entwurfProvider = cur.entwurfProvider || {};
|
|
188
|
+
cur.entwurfProvider.showToolNotifications = true;
|
|
189
|
+
fs.writeFileSync(path, JSON.stringify(cur, null, 2) + "\n");
|
|
190
|
+
'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
`showToolNotifications` defaults to `true` already; setting it explicitly pins
|
|
194
|
+
the value for reproducibility. **No operator config is needed to make tool
|
|
195
|
+
calls flow without prompts when a backend is invoked through entwurf** — the
|
|
196
|
+
bridge runs the backend YOLO inside its own isolated overlay
|
|
197
|
+
(`~/.pi/agent/*-config-overlay/`, AGENTS.md Hard Rule #10), so native backend
|
|
198
|
+
config is neither read nor required on the bridged path.
|
|
199
|
+
|
|
200
|
+
### Stage 4 — runtime smoke
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
ENTWURF=~/.pi/agent/git/github.com/junghan0611/entwurf
|
|
204
|
+
cd ~/entwurf-smoke
|
|
205
|
+
|
|
206
|
+
# lightweight: one Claude turn through entwurf (proves auth + bridge round-trip)
|
|
207
|
+
pi --provider entwurf --model claude-sonnet-4-6 -p "reply with ok only"
|
|
208
|
+
|
|
209
|
+
# full live floor (LIVE=1 required): pnpm check + the v2-native live gates
|
|
210
|
+
# + the ACP plugin acceptance floor (10 smoke-acp-*-live smokes). Two-tier
|
|
211
|
+
# MUST/BEHAVIOR summary; MUST owns the exit code. GLG authorizes the cut.
|
|
212
|
+
LIVE=1 $ENTWURF/run.sh release-gate .
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
A passing turn is a full round-trip: bootstrap → ACP session → bridge response
|
|
216
|
+
→ clean shutdown.
|
|
217
|
+
|
|
218
|
+
Drift points:
|
|
219
|
+
- a backend you have not authenticated fails loudly with `Authentication required` (Claude/Codex shape) or an early `EPIPE` (Gemini-CLI shape). **That is not an entwurf failure** — the bridge surfaces missing auth, it does not fix it. Add the credential and re-run.
|
|
220
|
+
- `release-gate` honest-skips its LIVE-gated MUST steps when `LIVE!=1`; a real cut needs `LIVE=1` with `SKIP=0`.
|
|
221
|
+
|
|
222
|
+
## Stage 5 — entwurf surface (optional)
|
|
223
|
+
|
|
224
|
+
> Do not run Stage 5 until at least one authenticated `smoke-*` is green — a
|
|
225
|
+
> live entwurf flow drives a real backend turn, so an unauthenticated host just
|
|
226
|
+
> re-surfaces the Stage 4 auth noise.
|
|
227
|
+
|
|
228
|
+
### Package-source ACP routing — auth-free, run this first
|
|
229
|
+
|
|
230
|
+
Covers the boundary where a package-installed bridge (a `git:` / `npm:`
|
|
231
|
+
settings source, not a local checkout) must still resolve so a
|
|
232
|
+
`provider=entwurf` child does not die with `Unknown provider`:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# from the installed bridge root (auth-free, also in pnpm check)
|
|
236
|
+
./run.sh check-package-source-routing
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
It pins the package-source → install-root resolver math across the full install
|
|
240
|
+
matrix (local / git / npm / missing × local + remote). The live ACP routing
|
|
241
|
+
itself is exercised by the `smoke-acp-*-live` floor under `release-gate`.
|
|
242
|
+
|
|
243
|
+
### Resident control session
|
|
244
|
+
|
|
245
|
+
To address a long-lived pi session from another session (or an external MCP
|
|
246
|
+
host like Claude Code), open it with `--entwurf-control`. A garden-native
|
|
247
|
+
`--session-id` is **required** — a raw `pi --entwurf-control` (pi-assigned
|
|
248
|
+
uuid) hard-exits at `session_start` before any model turn. Mint the id from the
|
|
249
|
+
SSOT:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pi --session-id "$(/path/to/entwurf/run.sh new-session-id)" \
|
|
253
|
+
--entwurf-control --provider entwurf --model claude-sonnet-4-6
|
|
254
|
+
# control socket: ~/.pi/entwurf-control/<sessionId>.sock
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Inside such a session, builtin `/new` / `/fork` / `/clone` are blocked (they
|
|
258
|
+
would mint a non-garden uuid); use `/gnew` (alias `/garden-new`) for a
|
|
259
|
+
same-terminal fresh garden session (a zero-token switch into a pre-created
|
|
260
|
+
garden file).
|
|
261
|
+
|
|
262
|
+
The bridge exposes four MCP tools — `entwurf_v2` (canonical dispatch /
|
|
263
|
+
delivery verb), `entwurf_peers` (discover live citizens), `entwurf_self`
|
|
264
|
+
(identity envelope), `entwurf_inbox_read` (drain meta-bridge inbox). From any
|
|
265
|
+
other pi session on the same host, call `entwurf_peers` to list live targets
|
|
266
|
+
and `entwurf_v2` to message/hand off by garden id. Dispatch is fire-and-forget
|
|
267
|
+
on a live target; set `wants_reply` if you need an answer. See AGENTS.md
|
|
268
|
+
`Send-is-throw` for the full rule.
|
|
269
|
+
|
|
270
|
+
### Native-harness wake (optional)
|
|
271
|
+
|
|
272
|
+
For an external Claude Code session to receive async messages, install the
|
|
273
|
+
meta-bridge plugin globally (Claude Code only):
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
./run.sh install-meta-bridge # plugin + USER-scope entwurf-bridge MCP
|
|
277
|
+
./run.sh doctor-meta-bridge # fail-loud health check
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Teardown
|
|
281
|
+
|
|
282
|
+
The bridge has no daemon. To remove everything installed:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# entwurf clone
|
|
286
|
+
rm -rf ~/.pi/agent/git/github.com/junghan0611/entwurf
|
|
287
|
+
|
|
288
|
+
# project wiring (per-project)
|
|
289
|
+
rm -rf ~/entwurf-smoke/.pi
|
|
290
|
+
|
|
291
|
+
# meta-bridge plugin (if installed)
|
|
292
|
+
~/.pi/agent/git/github.com/junghan0611/entwurf/run.sh uninstall-meta-bridge 2>/dev/null || true
|
|
293
|
+
|
|
294
|
+
# pi binary
|
|
295
|
+
npm uninstall -g @earendil-works/pi-coding-agent
|
|
296
|
+
|
|
297
|
+
# node + pnpm via nvm
|
|
298
|
+
nvm uninstall 24
|
|
299
|
+
rm -rf ~/.nvm
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
This walk-through is the **verification floor** underneath every downstream
|
|
303
|
+
publish step — install, package surface, and at least one authenticated
|
|
304
|
+
runtime smoke green — not the publish trigger itself. GLG owns the publish/tag
|
|
305
|
+
decision.
|