diff --git a/easel/src/tui.mjs b/easel/src/tui.mjs index b4d5d08a1..da96f4bf2 100755 --- a/easel/src/tui.mjs +++ b/easel/src/tui.mjs @@ -284,11 +284,13 @@ const state = { // so the prompt is the whole boundary again and it starts closed. autoAllow: !pro, entries: [ - { + // Pro opens onto nothing but the bar: the mode and the model sit under + // it, and the agreement was the disclosure. + ...(pro ? [] : [{ id: "privacy", kind: "notice", text: "REMOTE INFERENCE · prompt content may leave this machine", - }, + }]), // Say why the session is not the default one, once. A piece session // opened by default has nothing to explain. // Pro says nothing about itself here; the status line under the bar @@ -318,7 +320,7 @@ if (!profile.private) try { metadata:{medium:state.medium},version:currentVersion(),session}); await transcriptJournal.init(); const status=await transcriptJournal.enableSharing({userSub:sharingAcknowledgment.owner,acknowledged:true,disclosureVersion:DISCLOSURE_VERSION});transcriptSharing=status.sharing; - state.entries.push({id:'transcript-status',kind:'notice',text:`Transcript: ${status.label} · /sharing`}); + if (!pro) state.entries.push({id:'transcript-status',kind:'notice',text:`Transcript: ${status.label} · /sharing`}); } catch(error) { transcriptJournal=null; state.entries.push({id:'transcript-error',kind:'error',text:`Local transcript unavailable: ${error.message}`}); @@ -646,6 +648,9 @@ function openEngine({ resume = "" } = {}) { } }, environment: { + // The engine is this session's, not a rock of its own: Slab's Claude + // hooks see this and leave the marker to Easel. + EASEL_SESSION_ID: slabSession.sessionId, SLAB_PROMPT_SESSION_ID: slabSession.sessionId, SLAB_TERMINAL_TTY: slabSession.tty, SLAB_AGENT_TYPE: "easel", @@ -2604,8 +2609,10 @@ try { state.status = "ready"; state.model = connection?.model || model; await rememberProvider(); - if (desktopRestored) { - // Restoring an existing thread is silent. + if (desktopRestored || pro) { + // Restoring an existing thread is silent, and so is pro: the status line + // under the bar already says the engine is there. + if (pro && resumeThreadId) restoreThread(connection.thread); } else if (resumeThreadId && !restoreThread(connection.thread)) { addEntry("notice", `Resumed thread · ${engineLabel()}`); } else { diff --git a/slab/bin/claude-notify.sh b/slab/bin/claude-notify.sh index bcab5bd2d..9770b38b3 100755 --- a/slab/bin/claude-notify.sh +++ b/slab/bin/claude-notify.sh @@ -9,6 +9,9 @@ # 3. Speak "help me" with a short fade tail (claude-help.py). # The pause flag is cleared by the next UserPromptSubmit (user responded) # or by Stop (work ended). Does NOT sleep the Mac. +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-ping-repeat.sh b/slab/bin/claude-ping-repeat.sh index f2832c567..c34a0ab03 100755 --- a/slab/bin/claude-ping-repeat.sh +++ b/slab/bin/claude-ping-repeat.sh @@ -1,6 +1,9 @@ #!/bin/bash # Random high-pitched major-chord ping every INTERVAL seconds while lid is CLOSED. # Exits automatically once the lid is reopened. +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-prompt-log.sh b/slab/bin/claude-prompt-log.sh index 3214b6378..b042beacb 100755 --- a/slab/bin/claude-prompt-log.sh +++ b/slab/bin/claude-prompt-log.sh @@ -2,6 +2,9 @@ # UserPromptSubmit hook: log prompt, mark session as active, set awake. # Writes JSON metadata to active-prompts/ so the menubar can # render per-session status (subject, cwd, tty, claude pid). +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-sleep-schedule.sh b/slab/bin/claude-sleep-schedule.sh index e63c4d62b..ac0092e3a 100755 --- a/slab/bin/claude-sleep-schedule.sh +++ b/slab/bin/claude-sleep-schedule.sh @@ -1,6 +1,9 @@ #!/bin/bash # Sleeps the Mac after DELAY seconds if the lid is still closed at that point. # Plays the sleep tone first for a dreamy auditory cue. +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-stop.sh b/slab/bin/claude-stop.sh index a022cf913..7fef747c8 100755 --- a/slab/bin/claude-stop.sh +++ b/slab/bin/claude-stop.sh @@ -14,6 +14,9 @@ # others = 0 → "all done" chime (lid open) OR TTS "i'm tired" with fade-out # tail → `pmset sleepnow` (lid closed: stops ambient first, so # the transition to sleep is a gentle dissolve instead of a cut). +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-subagent-stop.sh b/slab/bin/claude-subagent-stop.sh index 1cea730ef..c895694ef 100755 --- a/slab/bin/claude-subagent-stop.sh +++ b/slab/bin/claude-subagent-stop.sh @@ -3,6 +3,9 @@ # ping. FIFO-per-session removal keeps each session's count accurate even when # subagents finish out of order. Falls back to the globally-oldest marker if # the session subdir is empty, so counts can never leak upward. +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SLAB_BIN=${SLAB_BIN:-$HOME/.local/bin} diff --git a/slab/bin/claude-tool-heartbeat.sh b/slab/bin/claude-tool-heartbeat.sh index 953949467..437a3d41d 100755 --- a/slab/bin/claude-tool-heartbeat.sh +++ b/slab/bin/claude-tool-heartbeat.sh @@ -10,6 +10,9 @@ # marker mtime ages). See ClaudeSession.swift isInterrupted(). # # Usage: claude-tool-heartbeat.sh (hook JSON on stdin) +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u MODE="${1:-pre}" SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} diff --git a/slab/bin/claude-tool-pre.sh b/slab/bin/claude-tool-pre.sh index 5e45007ba..617332b3b 100755 --- a/slab/bin/claude-tool-pre.sh +++ b/slab/bin/claude-tool-pre.sh @@ -4,6 +4,9 @@ # THAT session's polygon edge. SubagentStop removes the session's oldest marker. # (Workflow-tool agents don't fire this hook — the menubar counts those live # from the workflow transcript dir instead.) +# A Claude that Easel is driving is that session's engine, not a rock of its +# own; Easel keeps the marker, so this hook has nothing to say. +[[ -n "${EASEL_SESSION_ID:-}" ]] && exit 0 set -u SLAB_HOME=${SLAB_HOME:-$HOME/.local/share/slab} SUBAGENT_DIR="$SLAB_HOME/state/active-subagents"