@a5c-ai/babysitter-cursor 5.0.1-staging.5cd43600 → 5.0.1-staging.6e094dee

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.
@@ -0,0 +1,196 @@
1
+ # Unified Session Start Hook for Cursor IDE/CLI (PowerShell)
2
+ # Routes through hooks-proxy for all hook execution.
3
+ #
4
+ # Ensures the babysitter SDK CLI and hooks-proxy are installed (from versions.json
5
+ # sdkVersion), then delegates to the SDK hook handler via hooks-proxy.
6
+ #
7
+ # Protocol:
8
+ # Input: JSON via stdin (contains session_id, cwd, etc.)
9
+ # Output: JSON via stdout ({} on success)
10
+ # Stderr: debug/log output only
11
+ # Exit 0: success
12
+ # Exit 2: block (fatal error)
13
+
14
+ $ErrorActionPreference = "Stop"
15
+
16
+ $PluginRoot = if ($env:CURSOR_PLUGIN_ROOT) { $env:CURSOR_PLUGIN_ROOT } else { Split-Path -Parent $PSScriptRoot }
17
+ $GlobalRoot = if ($env:BABYSITTER_GLOBAL_STATE_DIR) { $env:BABYSITTER_GLOBAL_STATE_DIR } else { Join-Path $HOME ".a5c" }
18
+ $StateDir = if ($env:BABYSITTER_STATE_DIR) { $env:BABYSITTER_STATE_DIR } else { Join-Path $GlobalRoot "state" }
19
+ $SdkMarkerFile = Join-Path $PluginRoot ".babysitter-install-attempted"
20
+ $ProxyMarkerFile = Join-Path $PluginRoot ".hooks-proxy-install-attempted"
21
+
22
+ $env:CURSOR_PLUGIN_ROOT = $PluginRoot
23
+ $env:BABYSITTER_STATE_DIR = $StateDir
24
+
25
+ $LogDir = if ($env:BABYSITTER_LOG_DIR) { $env:BABYSITTER_LOG_DIR } else { Join-Path $GlobalRoot "logs" }
26
+ $LogFile = Join-Path $LogDir "babysitter-session-start-hook.log"
27
+ New-Item -ItemType Directory -Path $LogDir -Force -ErrorAction SilentlyContinue | Out-Null
28
+
29
+ function Write-Blog {
30
+ param([string]$Message)
31
+ $ts = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
32
+ Add-Content -Path $LogFile -Value "[INFO] $ts $Message" -ErrorAction SilentlyContinue
33
+ if (Get-Command babysitter -ErrorAction SilentlyContinue) {
34
+ & babysitter log --type hook --label "hook:session-start" --message $Message --source shell-hook 2>$null
35
+ }
36
+ }
37
+
38
+ Write-Blog "Unified hook script invoked"
39
+ Write-Blog "PLUGIN_ROOT=$PluginRoot"
40
+ Write-Blog "STATE_DIR=$StateDir"
41
+
42
+ # Get required SDK version from versions.json (used for both SDK and hooks-proxy)
43
+ $versionsFile = Join-Path $PluginRoot "versions.json"
44
+ try {
45
+ $SdkVersion = (Get-Content $versionsFile -Raw | ConvertFrom-Json).sdkVersion
46
+ if (-not $SdkVersion) { $SdkVersion = "latest" }
47
+ } catch {
48
+ $SdkVersion = "latest"
49
+ }
50
+
51
+ # ---------------------------------------------------------------------------
52
+ # SDK install/upgrade
53
+ # ---------------------------------------------------------------------------
54
+
55
+ function Install-Sdk {
56
+ param([string]$TargetVersion)
57
+ try {
58
+ & npm i -g "@a5c-ai/babysitter-sdk@$TargetVersion" --loglevel=error 2>$null
59
+ if ($LASTEXITCODE -eq 0) {
60
+ Write-Blog "Installed SDK globally ($TargetVersion)"
61
+ return $true
62
+ }
63
+ } catch {}
64
+ try {
65
+ $prefix = Join-Path $env:USERPROFILE ".local"
66
+ & npm i -g "@a5c-ai/babysitter-sdk@$TargetVersion" --prefix $prefix --loglevel=error 2>$null
67
+ if ($LASTEXITCODE -eq 0) {
68
+ $env:PATH = "$prefix\bin;$env:PATH"
69
+ Write-Blog "Installed SDK to user prefix ($TargetVersion)"
70
+ return $true
71
+ }
72
+ } catch {}
73
+ return $false
74
+ }
75
+
76
+ $NeedsSdkInstall = $false
77
+ if (Get-Command babysitter -ErrorAction SilentlyContinue) {
78
+ $CurrentVersion = & babysitter --version 2>$null
79
+ if ($CurrentVersion -ne $SdkVersion) {
80
+ Write-Blog "SDK version mismatch: installed=$CurrentVersion, required=$SdkVersion"
81
+ $NeedsSdkInstall = $true
82
+ } else {
83
+ Write-Blog "SDK version OK: $CurrentVersion"
84
+ }
85
+ } else {
86
+ Write-Blog "SDK CLI not found, will install"
87
+ $NeedsSdkInstall = $true
88
+ }
89
+
90
+ if ($NeedsSdkInstall -and -not (Test-Path $SdkMarkerFile)) {
91
+ Install-Sdk $SdkVersion | Out-Null
92
+ Set-Content -Path $SdkMarkerFile -Value $SdkVersion -ErrorAction SilentlyContinue
93
+ }
94
+
95
+ $useSdkFallback = $false
96
+ if (-not (Get-Command babysitter -ErrorAction SilentlyContinue)) {
97
+ Write-Blog "CLI not found after install, using npx fallback"
98
+ $useSdkFallback = $true
99
+ }
100
+
101
+ # ---------------------------------------------------------------------------
102
+ # Hooks-proxy install/upgrade (same pattern as SDK)
103
+ # ---------------------------------------------------------------------------
104
+
105
+ function Install-HooksProxy {
106
+ param([string]$TargetVersion)
107
+ try {
108
+ & npm i -g "@a5c-ai/hooks-proxy-cli@$TargetVersion" --loglevel=error 2>$null
109
+ if ($LASTEXITCODE -eq 0) {
110
+ Write-Blog "Installed hooks-proxy globally ($TargetVersion)"
111
+ return $true
112
+ }
113
+ } catch {}
114
+ try {
115
+ $prefix = Join-Path $env:USERPROFILE ".local"
116
+ & npm i -g "@a5c-ai/hooks-proxy-cli@$TargetVersion" --prefix $prefix --loglevel=error 2>$null
117
+ if ($LASTEXITCODE -eq 0) {
118
+ $env:PATH = "$prefix\bin;$env:PATH"
119
+ Write-Blog "Installed hooks-proxy to user prefix ($TargetVersion)"
120
+ return $true
121
+ }
122
+ } catch {}
123
+ return $false
124
+ }
125
+
126
+ $NeedsProxyInstall = $false
127
+ $Proxy = $null
128
+ if (Get-Command a5c-hooks-proxy -ErrorAction SilentlyContinue) {
129
+ $ProxyVersion = & a5c-hooks-proxy --version 2>$null
130
+ if ($ProxyVersion -ne $SdkVersion) {
131
+ Write-Blog "hooks-proxy version mismatch: installed=$ProxyVersion, required=$SdkVersion"
132
+ $NeedsProxyInstall = $true
133
+ } else {
134
+ Write-Blog "hooks-proxy version OK: $ProxyVersion"
135
+ $Proxy = "a5c-hooks-proxy"
136
+ }
137
+ } else {
138
+ $localProxy = Join-Path $env:USERPROFILE ".local\bin\a5c-hooks-proxy.exe"
139
+ if (Test-Path $localProxy) {
140
+ $ProxyVersion = & $localProxy --version 2>$null
141
+ if ($ProxyVersion -ne $SdkVersion) {
142
+ Write-Blog "hooks-proxy version mismatch: installed=$ProxyVersion, required=$SdkVersion"
143
+ $NeedsProxyInstall = $true
144
+ } else {
145
+ Write-Blog "hooks-proxy version OK: $ProxyVersion"
146
+ $Proxy = $localProxy
147
+ }
148
+ } else {
149
+ Write-Blog "hooks-proxy not found, will install"
150
+ $NeedsProxyInstall = $true
151
+ }
152
+ }
153
+
154
+ if ($NeedsProxyInstall -and -not (Test-Path $ProxyMarkerFile)) {
155
+ Install-HooksProxy $SdkVersion | Out-Null
156
+ Set-Content -Path $ProxyMarkerFile -Value $SdkVersion -ErrorAction SilentlyContinue
157
+ }
158
+
159
+ # Re-resolve after potential install
160
+ if (-not $Proxy) {
161
+ if (Get-Command a5c-hooks-proxy -ErrorAction SilentlyContinue) {
162
+ $Proxy = "a5c-hooks-proxy"
163
+ } else {
164
+ $localProxy = Join-Path $env:USERPROFILE ".local\bin\a5c-hooks-proxy.exe"
165
+ if (Test-Path $localProxy) {
166
+ $Proxy = $localProxy
167
+ }
168
+ }
169
+ }
170
+
171
+ # ---------------------------------------------------------------------------
172
+ # Capture stdin and delegate to hooks-proxy
173
+ # ---------------------------------------------------------------------------
174
+
175
+ $InputFile = [System.IO.Path]::GetTempFileName()
176
+ $input | Out-File -FilePath $InputFile -Encoding utf8
177
+
178
+ Write-Blog "Hook input received"
179
+
180
+ $stderrLog = Join-Path $LogDir "babysitter-session-start-hook-stderr.log"
181
+
182
+ if ($Proxy) {
183
+ Write-Blog "Using hooks-proxy: $Proxy"
184
+ $Result = Get-Content $InputFile | & $Proxy invoke --adapter cursor --handler "babysitter hook:run --harness unified --hook-type session-start --plugin-root $PluginRoot --state-dir $StateDir --json" --json 2>$stderrLog
185
+ $ExitCode = $LASTEXITCODE
186
+ } else {
187
+ Write-Blog "hooks-proxy not found after install, using npx fallback"
188
+ $Result = Get-Content $InputFile | & npx -y "@a5c-ai/hooks-proxy-cli@$SdkVersion" invoke --adapter cursor --handler "babysitter hook:run --harness unified --hook-type session-start --plugin-root $PluginRoot --state-dir $StateDir --json" --json 2>$stderrLog
189
+ $ExitCode = $LASTEXITCODE
190
+ }
191
+
192
+ Write-Blog "CLI exit code=$ExitCode"
193
+
194
+ Remove-Item $InputFile -Force -ErrorAction SilentlyContinue
195
+ Write-Output $Result
196
+ exit $ExitCode
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env bash
2
+ # Unified Session Start Hook - routes through hooks-proxy for all hook execution.
3
+ #
4
+ # Ensures the babysitter SDK CLI and hooks-proxy are installed (from versions.json
5
+ # sdkVersion), then delegates to the SDK hook handler via hooks-proxy.
6
+ #
7
+ # Protocol:
8
+ # Input: JSON via stdin (contains session_id, cwd, etc.)
9
+ # Output: JSON via stdout ({} on success)
10
+ # Stderr: debug/log output only
11
+ # Exit 0: success
12
+ # Exit 2: block (fatal error)
13
+
14
+ set -euo pipefail
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
18
+ GLOBAL_ROOT="${BABYSITTER_GLOBAL_STATE_DIR:-$HOME/.a5c}"
19
+ STATE_DIR="${BABYSITTER_STATE_DIR:-${GLOBAL_ROOT}/state}"
20
+ LOG_DIR="${BABYSITTER_LOG_DIR:-${GLOBAL_ROOT}/logs}"
21
+ LOG_FILE="$LOG_DIR/babysitter-session-start-hook.log"
22
+ SDK_MARKER_FILE="${PLUGIN_ROOT}/.babysitter-install-attempted"
23
+ PROXY_MARKER_FILE="${PLUGIN_ROOT}/.hooks-proxy-install-attempted"
24
+
25
+ export CURSOR_PLUGIN_ROOT="${CURSOR_PLUGIN_ROOT:-${PLUGIN_ROOT}}"
26
+ export BABYSITTER_STATE_DIR="${STATE_DIR}"
27
+
28
+ mkdir -p "$LOG_DIR" 2>/dev/null
29
+
30
+ blog() {
31
+ local msg="$1"
32
+ local ts
33
+ ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
34
+ echo "[INFO] $ts $msg" >> "$LOG_FILE" 2>/dev/null
35
+ if command -v babysitter &>/dev/null; then
36
+ babysitter log --type hook --label "hook:session-start" --message "$msg" --source shell-hook 2>/dev/null || true
37
+ fi
38
+ }
39
+
40
+ blog "Unified hook script invoked"
41
+ blog "PLUGIN_ROOT=$PLUGIN_ROOT"
42
+ blog "STATE_DIR=$STATE_DIR"
43
+
44
+ # Get required SDK version from versions.json (used for both SDK and hooks-proxy)
45
+ SDK_VERSION=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('${PLUGIN_ROOT}/versions.json','utf8')).sdkVersion||'latest')}catch{console.log('latest')}" 2>/dev/null || echo "latest")
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # SDK install/upgrade
49
+ # ---------------------------------------------------------------------------
50
+
51
+ install_sdk() {
52
+ local target_version="$1"
53
+ if npm i -g "@a5c-ai/babysitter-sdk@${target_version}" --loglevel=error 2>/dev/null; then
54
+ blog "Installed SDK globally (${target_version})"
55
+ return 0
56
+ else
57
+ if npm i -g "@a5c-ai/babysitter-sdk@${target_version}" --prefix "$HOME/.local" --loglevel=error 2>/dev/null; then
58
+ export PATH="$HOME/.local/bin:$PATH"
59
+ blog "Installed SDK to user prefix (${target_version})"
60
+ return 0
61
+ fi
62
+ fi
63
+ return 1
64
+ }
65
+
66
+ NEEDS_SDK_INSTALL=false
67
+ if command -v babysitter &>/dev/null; then
68
+ CURRENT_VERSION=$(babysitter --version 2>/dev/null || echo "unknown")
69
+ if [ "$CURRENT_VERSION" != "$SDK_VERSION" ]; then
70
+ blog "SDK version mismatch: installed=${CURRENT_VERSION}, required=${SDK_VERSION}"
71
+ NEEDS_SDK_INSTALL=true
72
+ else
73
+ blog "SDK version OK: ${CURRENT_VERSION}"
74
+ fi
75
+ else
76
+ blog "SDK CLI not found, will install"
77
+ NEEDS_SDK_INSTALL=true
78
+ fi
79
+
80
+ if [ "$NEEDS_SDK_INSTALL" = true ] && [ ! -f "$SDK_MARKER_FILE" ]; then
81
+ install_sdk "$SDK_VERSION"
82
+ echo "$SDK_VERSION" > "$SDK_MARKER_FILE" 2>/dev/null
83
+ fi
84
+
85
+ if ! command -v babysitter &>/dev/null; then
86
+ blog "CLI not found after install, using npx fallback"
87
+ babysitter() { npx -y "@a5c-ai/babysitter-sdk@${SDK_VERSION}" "$@"; }
88
+ export -f babysitter
89
+ fi
90
+
91
+ # ---------------------------------------------------------------------------
92
+ # Hooks-proxy install/upgrade (same pattern as SDK)
93
+ # ---------------------------------------------------------------------------
94
+
95
+ install_hooks_proxy() {
96
+ local target_version="$1"
97
+ if npm i -g "@a5c-ai/hooks-proxy-cli@${target_version}" --loglevel=error 2>/dev/null; then
98
+ blog "Installed hooks-proxy globally (${target_version})"
99
+ return 0
100
+ else
101
+ if npm i -g "@a5c-ai/hooks-proxy-cli@${target_version}" --prefix "$HOME/.local" --loglevel=error 2>/dev/null; then
102
+ export PATH="$HOME/.local/bin:$PATH"
103
+ blog "Installed hooks-proxy to user prefix (${target_version})"
104
+ return 0
105
+ fi
106
+ fi
107
+ return 1
108
+ }
109
+
110
+ NEEDS_PROXY_INSTALL=false
111
+ if command -v a5c-hooks-proxy &>/dev/null; then
112
+ PROXY_VERSION=$(a5c-hooks-proxy --version 2>/dev/null || echo "unknown")
113
+ if [ "$PROXY_VERSION" != "$SDK_VERSION" ]; then
114
+ blog "hooks-proxy version mismatch: installed=${PROXY_VERSION}, required=${SDK_VERSION}"
115
+ NEEDS_PROXY_INSTALL=true
116
+ else
117
+ blog "hooks-proxy version OK: ${PROXY_VERSION}"
118
+ fi
119
+ elif [ -f "$HOME/.local/bin/a5c-hooks-proxy" ]; then
120
+ export PATH="$HOME/.local/bin:$PATH"
121
+ PROXY_VERSION=$(a5c-hooks-proxy --version 2>/dev/null || echo "unknown")
122
+ if [ "$PROXY_VERSION" != "$SDK_VERSION" ]; then
123
+ blog "hooks-proxy version mismatch: installed=${PROXY_VERSION}, required=${SDK_VERSION}"
124
+ NEEDS_PROXY_INSTALL=true
125
+ else
126
+ blog "hooks-proxy version OK: ${PROXY_VERSION}"
127
+ fi
128
+ else
129
+ blog "hooks-proxy not found, will install"
130
+ NEEDS_PROXY_INSTALL=true
131
+ fi
132
+
133
+ if [ "$NEEDS_PROXY_INSTALL" = true ] && [ ! -f "$PROXY_MARKER_FILE" ]; then
134
+ install_hooks_proxy "$SDK_VERSION"
135
+ echo "$SDK_VERSION" > "$PROXY_MARKER_FILE" 2>/dev/null
136
+ fi
137
+
138
+ # Resolve hooks-proxy binary (npx fallback if still not found)
139
+ PROXY=""
140
+ if command -v a5c-hooks-proxy &>/dev/null; then
141
+ PROXY="a5c-hooks-proxy"
142
+ elif [ -f "$HOME/.local/bin/a5c-hooks-proxy" ]; then
143
+ PROXY="$HOME/.local/bin/a5c-hooks-proxy"
144
+ fi
145
+
146
+ if [ -z "$PROXY" ]; then
147
+ blog "hooks-proxy not found after install, using npx fallback"
148
+ PROXY="npx -y @a5c-ai/hooks-proxy-cli@${SDK_VERSION} "
149
+ fi
150
+
151
+ # ---------------------------------------------------------------------------
152
+ # Capture stdin and delegate to hooks-proxy
153
+ # ---------------------------------------------------------------------------
154
+
155
+ INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/cursor-session-start-hook-$$.json")
156
+ cat > "$INPUT_FILE"
157
+
158
+ blog "Hook input received ($(wc -c < "$INPUT_FILE") bytes)"
159
+
160
+ STDERR_LOG="$LOG_DIR/babysitter-session-start-hook-stderr.log"
161
+
162
+ blog "Using hooks-proxy: $PROXY"
163
+ RESULT=$($PROXY invoke \
164
+ --adapter cursor \
165
+ --handler "babysitter hook:run --harness unified --hook-type session-start --plugin-root ${CURSOR_PLUGIN_ROOT} --state-dir ${BABYSITTER_STATE_DIR} --json" \
166
+ --json \
167
+ < "$INPUT_FILE" 2>"$STDERR_LOG")
168
+ EXIT_CODE=$?
169
+
170
+ blog "CLI exit code=$EXIT_CODE"
171
+
172
+ rm -f "$INPUT_FILE" 2>/dev/null
173
+ printf '%s\n' "$RESULT"
174
+ exit $EXIT_CODE
@@ -0,0 +1,125 @@
1
+ # Unified Stop Hook for Cursor IDE/CLI (PowerShell)
2
+ # Routes through hooks-proxy for all hook execution.
3
+ #
4
+ # Drives the orchestration loop by checking run state on session stop.
5
+ #
6
+ # Protocol:
7
+ # Input: JSON via stdin (session context)
8
+ # Output: JSON via stdout (with optional continue/stop signal)
9
+ # Stderr: debug/log output only
10
+ # Exit 0: success
11
+
12
+ $ErrorActionPreference = "Stop"
13
+
14
+ $PluginRoot = if ($env:CURSOR_PLUGIN_ROOT) { $env:CURSOR_PLUGIN_ROOT } else { Split-Path -Parent $PSScriptRoot }
15
+ $GlobalRoot = if ($env:BABYSITTER_GLOBAL_STATE_DIR) { $env:BABYSITTER_GLOBAL_STATE_DIR } else { Join-Path $HOME ".a5c" }
16
+ $StateDir = if ($env:BABYSITTER_STATE_DIR) { $env:BABYSITTER_STATE_DIR } else { Join-Path $GlobalRoot "state" }
17
+ $ProxyMarkerFile = Join-Path $PluginRoot ".hooks-proxy-install-attempted"
18
+
19
+ $env:CURSOR_PLUGIN_ROOT = $PluginRoot
20
+ $env:BABYSITTER_STATE_DIR = $StateDir
21
+
22
+ $LogDir = if ($env:BABYSITTER_LOG_DIR) { $env:BABYSITTER_LOG_DIR } else { Join-Path $GlobalRoot "logs" }
23
+ $LogFile = Join-Path $LogDir "babysitter-stop-hook.log"
24
+ New-Item -ItemType Directory -Path $LogDir -Force -ErrorAction SilentlyContinue | Out-Null
25
+
26
+ function Write-Blog {
27
+ param([string]$Message)
28
+ $ts = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
29
+ Add-Content -Path $LogFile -Value "[INFO] $ts $Message" -ErrorAction SilentlyContinue
30
+ if (Get-Command babysitter -ErrorAction SilentlyContinue) {
31
+ & babysitter log --type hook --label "hook:stop" --message $Message --source shell-hook 2>$null
32
+ }
33
+ }
34
+
35
+ Write-Blog "Unified hook script invoked"
36
+ Write-Blog "PLUGIN_ROOT=$PluginRoot"
37
+ Write-Blog "STATE_DIR=$StateDir"
38
+
39
+ # Get required version from versions.json (used for hooks-proxy)
40
+ $versionsFile = Join-Path $PluginRoot "versions.json"
41
+ try {
42
+ $SdkVersion = (Get-Content $versionsFile -Raw | ConvertFrom-Json).sdkVersion
43
+ if (-not $SdkVersion) { $SdkVersion = "latest" }
44
+ } catch {
45
+ $SdkVersion = "latest"
46
+ }
47
+
48
+ # ---------------------------------------------------------------------------
49
+ # Hooks-proxy install (same pattern as SDK install in session-start)
50
+ # ---------------------------------------------------------------------------
51
+
52
+ function Install-HooksProxy {
53
+ param([string]$TargetVersion)
54
+ try {
55
+ & npm i -g "@a5c-ai/hooks-proxy-cli@$TargetVersion" --loglevel=error 2>$null
56
+ if ($LASTEXITCODE -eq 0) {
57
+ Write-Blog "Installed hooks-proxy globally ($TargetVersion)"
58
+ return $true
59
+ }
60
+ } catch {}
61
+ try {
62
+ $prefix = Join-Path $env:USERPROFILE ".local"
63
+ & npm i -g "@a5c-ai/hooks-proxy-cli@$TargetVersion" --prefix $prefix --loglevel=error 2>$null
64
+ if ($LASTEXITCODE -eq 0) {
65
+ $env:PATH = "$prefix\bin;$env:PATH"
66
+ Write-Blog "Installed hooks-proxy to user prefix ($TargetVersion)"
67
+ return $true
68
+ }
69
+ } catch {}
70
+ return $false
71
+ }
72
+
73
+ # Resolve hooks-proxy binary
74
+ $Proxy = $null
75
+ if (Get-Command a5c-hooks-proxy -ErrorAction SilentlyContinue) {
76
+ $Proxy = "a5c-hooks-proxy"
77
+ } else {
78
+ $localProxy = Join-Path $env:USERPROFILE ".local\bin\a5c-hooks-proxy.exe"
79
+ if (Test-Path $localProxy) {
80
+ $Proxy = $localProxy
81
+ }
82
+ }
83
+
84
+ # Install if not found (only attempt once per plugin version)
85
+ if (-not $Proxy -and -not (Test-Path $ProxyMarkerFile)) {
86
+ Write-Blog "hooks-proxy not found, attempting install"
87
+ Install-HooksProxy $SdkVersion | Out-Null
88
+ Set-Content -Path $ProxyMarkerFile -Value $SdkVersion -ErrorAction SilentlyContinue
89
+ # Re-resolve after install
90
+ if (Get-Command a5c-hooks-proxy -ErrorAction SilentlyContinue) {
91
+ $Proxy = "a5c-hooks-proxy"
92
+ } else {
93
+ $localProxy = Join-Path $env:USERPROFILE ".local\bin\a5c-hooks-proxy.exe"
94
+ if (Test-Path $localProxy) {
95
+ $Proxy = $localProxy
96
+ }
97
+ }
98
+ }
99
+
100
+ # ---------------------------------------------------------------------------
101
+ # Capture stdin and delegate to hooks-proxy
102
+ # ---------------------------------------------------------------------------
103
+
104
+ $InputFile = [System.IO.Path]::GetTempFileName()
105
+ $input | Out-File -FilePath $InputFile -Encoding utf8
106
+
107
+ Write-Blog "Hook input received"
108
+
109
+ $stderrLog = Join-Path $LogDir "babysitter-stop-hook-stderr.log"
110
+
111
+ if ($Proxy) {
112
+ Write-Blog "Using hooks-proxy: $Proxy"
113
+ $Result = Get-Content $InputFile | & $Proxy invoke --adapter cursor --handler "babysitter hook:run --harness unified --hook-type stop --plugin-root $PluginRoot --state-dir $StateDir --json" --json 2>$stderrLog
114
+ $ExitCode = $LASTEXITCODE
115
+ } else {
116
+ Write-Blog "hooks-proxy not found after install, using npx fallback"
117
+ $Result = Get-Content $InputFile | & npx -y "@a5c-ai/hooks-proxy-cli@$SdkVersion" invoke --adapter cursor --handler "babysitter hook:run --harness unified --hook-type stop --plugin-root $PluginRoot --state-dir $StateDir --json" --json 2>$stderrLog
118
+ $ExitCode = $LASTEXITCODE
119
+ }
120
+
121
+ Write-Blog "CLI exit code=$ExitCode"
122
+
123
+ Remove-Item $InputFile -Force -ErrorAction SilentlyContinue
124
+ Write-Output $Result
125
+ exit $ExitCode
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+ # Unified Stop Hook - routes through hooks-proxy for all hook execution.
3
+ #
4
+ # Drives the orchestration loop by checking run state on session stop.
5
+ #
6
+ # Protocol:
7
+ # Input: JSON via stdin (session context)
8
+ # Output: JSON via stdout (with optional continue/stop signal)
9
+ # Stderr: debug/log output only
10
+ # Exit 0: success
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
16
+ GLOBAL_ROOT="${BABYSITTER_GLOBAL_STATE_DIR:-$HOME/.a5c}"
17
+ STATE_DIR="${BABYSITTER_STATE_DIR:-${GLOBAL_ROOT}/state}"
18
+ LOG_DIR="${BABYSITTER_LOG_DIR:-${GLOBAL_ROOT}/logs}"
19
+ LOG_FILE="$LOG_DIR/babysitter-stop-hook.log"
20
+ PROXY_MARKER_FILE="${PLUGIN_ROOT}/.hooks-proxy-install-attempted"
21
+
22
+ export CURSOR_PLUGIN_ROOT="${CURSOR_PLUGIN_ROOT:-${PLUGIN_ROOT}}"
23
+ export BABYSITTER_STATE_DIR="${STATE_DIR}"
24
+
25
+ mkdir -p "$LOG_DIR" 2>/dev/null
26
+
27
+ blog() {
28
+ local msg="$1"
29
+ local ts
30
+ ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
31
+ echo "[INFO] $ts $msg" >> "$LOG_FILE" 2>/dev/null
32
+ if command -v babysitter &>/dev/null; then
33
+ babysitter log --type hook --label "hook:stop" --message "$msg" --source shell-hook 2>/dev/null || true
34
+ fi
35
+ }
36
+
37
+ blog "Unified hook script invoked"
38
+ blog "PLUGIN_ROOT=$PLUGIN_ROOT"
39
+ blog "STATE_DIR=$STATE_DIR"
40
+
41
+ # Get required version from versions.json (used for hooks-proxy)
42
+ SDK_VERSION=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('${PLUGIN_ROOT}/versions.json','utf8')).sdkVersion||'latest')}catch{console.log('latest')}" 2>/dev/null || echo "latest")
43
+
44
+ # ---------------------------------------------------------------------------
45
+ # Hooks-proxy install (same pattern as SDK install in session-start)
46
+ # ---------------------------------------------------------------------------
47
+
48
+ install_hooks_proxy() {
49
+ local target_version="$1"
50
+ if npm i -g "@a5c-ai/hooks-proxy-cli@${target_version}" --loglevel=error 2>/dev/null; then
51
+ blog "Installed hooks-proxy globally (${target_version})"
52
+ return 0
53
+ else
54
+ if npm i -g "@a5c-ai/hooks-proxy-cli@${target_version}" --prefix "$HOME/.local" --loglevel=error 2>/dev/null; then
55
+ export PATH="$HOME/.local/bin:$PATH"
56
+ blog "Installed hooks-proxy to user prefix (${target_version})"
57
+ return 0
58
+ fi
59
+ fi
60
+ return 1
61
+ }
62
+
63
+ # Resolve hooks-proxy binary
64
+ PROXY=""
65
+ if command -v a5c-hooks-proxy &>/dev/null; then
66
+ PROXY="a5c-hooks-proxy"
67
+ elif [ -f "$HOME/.local/bin/a5c-hooks-proxy" ]; then
68
+ PROXY="$HOME/.local/bin/a5c-hooks-proxy"
69
+ fi
70
+
71
+ # Install if not found (only attempt once per plugin version)
72
+ if [ -z "$PROXY" ] && [ ! -f "$PROXY_MARKER_FILE" ]; then
73
+ blog "hooks-proxy not found, attempting install"
74
+ install_hooks_proxy "$SDK_VERSION"
75
+ echo "$SDK_VERSION" > "$PROXY_MARKER_FILE" 2>/dev/null
76
+ if command -v a5c-hooks-proxy &>/dev/null; then
77
+ PROXY="a5c-hooks-proxy"
78
+ elif [ -f "$HOME/.local/bin/a5c-hooks-proxy" ]; then
79
+ PROXY="$HOME/.local/bin/a5c-hooks-proxy"
80
+ fi
81
+ fi
82
+
83
+ # npx fallback if still not found
84
+ if [ -z "$PROXY" ]; then
85
+ blog "hooks-proxy not found after install, using npx fallback"
86
+ PROXY="npx -y @a5c-ai/hooks-proxy-cli@${SDK_VERSION} "
87
+ fi
88
+
89
+ # ---------------------------------------------------------------------------
90
+ # Capture stdin and delegate to hooks-proxy
91
+ # ---------------------------------------------------------------------------
92
+
93
+ INPUT_FILE=$(mktemp 2>/dev/null || echo "/tmp/cursor-stop-hook-$$.json")
94
+ cat > "$INPUT_FILE"
95
+
96
+ blog "Hook input received ($(wc -c < "$INPUT_FILE") bytes)"
97
+
98
+ STDERR_LOG="$LOG_DIR/babysitter-stop-hook-stderr.log"
99
+
100
+ blog "Using hooks-proxy: $PROXY"
101
+ RESULT=$($PROXY invoke \
102
+ --adapter cursor \
103
+ --handler "babysitter hook:run --harness unified --hook-type stop --plugin-root ${CURSOR_PLUGIN_ROOT} --state-dir ${BABYSITTER_STATE_DIR} --json" \
104
+ --json \
105
+ < "$INPUT_FILE" 2>"$STDERR_LOG")
106
+ EXIT_CODE=$?
107
+
108
+ blog "CLI exit code=$EXIT_CODE"
109
+
110
+ rm -f "$INPUT_FILE" 2>/dev/null
111
+ printf '%s\n' "$RESULT"
112
+ exit $EXIT_CODE
@@ -4,16 +4,16 @@
4
4
  "sessionStart": [
5
5
  {
6
6
  "type": "command",
7
- "bash": "bash \"./hooks/session-start.sh\"",
8
- "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/session-start.ps1\"",
7
+ "bash": "bash \"./hooks/babysitter-proxied-session-start.sh\"",
8
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-session-start.ps1\"",
9
9
  "timeoutSec": 30
10
10
  }
11
11
  ],
12
12
  "stop": [
13
13
  {
14
14
  "type": "command",
15
- "bash": "bash \"./hooks/stop-hook.sh\"",
16
- "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/stop-hook.ps1\"",
15
+ "bash": "bash \"./hooks/babysitter-proxied-stop-hook.sh\"",
16
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-stop-hook.ps1\"",
17
17
  "loop_limit": null
18
18
  }
19
19
  ]
@@ -0,0 +1,21 @@
1
+ {
2
+ "version": 1,
3
+ "hooks": {
4
+ "sessionStart": [
5
+ {
6
+ "type": "command",
7
+ "bash": "bash \"./hooks/session-start.sh\"",
8
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/session-start.ps1\"",
9
+ "timeoutSec": 30
10
+ }
11
+ ],
12
+ "stop": [
13
+ {
14
+ "type": "command",
15
+ "bash": "bash \"./hooks/stop-hook.sh\"",
16
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/stop-hook.ps1\"",
17
+ "loop_limit": null
18
+ }
19
+ ]
20
+ }
21
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "_comment": "NOT ACTIVE — Alternative hooks-cursor.json using per-hook unified scripts with hooks-proxy support. To activate, replace hooks-cursor.json with this file.",
3
+ "version": 1,
4
+ "hooks": {
5
+ "sessionStart": [
6
+ {
7
+ "type": "command",
8
+ "bash": "bash \"./hooks/babysitter-proxied-session-start.sh\"",
9
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-session-start.ps1\"",
10
+ "timeoutSec": 30
11
+ }
12
+ ],
13
+ "stop": [
14
+ {
15
+ "type": "command",
16
+ "bash": "bash \"./hooks/babysitter-proxied-stop-hook.sh\"",
17
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-stop-hook.ps1\"",
18
+ "loop_limit": null
19
+ }
20
+ ]
21
+ }
22
+ }
package/hooks.json CHANGED
@@ -4,16 +4,16 @@
4
4
  "sessionStart": [
5
5
  {
6
6
  "type": "command",
7
- "bash": "bash \"./hooks/session-start.sh\"",
8
- "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/session-start.ps1\"",
7
+ "bash": "bash \"./hooks/babysitter-proxied-session-start.sh\"",
8
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-session-start.ps1\"",
9
9
  "timeoutSec": 30
10
10
  }
11
11
  ],
12
12
  "stop": [
13
13
  {
14
14
  "type": "command",
15
- "bash": "bash \"./hooks/stop-hook.sh\"",
16
- "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/stop-hook.ps1\"",
15
+ "bash": "bash \"./hooks/babysitter-proxied-stop-hook.sh\"",
16
+ "powershell": "powershell -NoProfile -ExecutionPolicy Bypass -File \"./hooks/babysitter-proxied-stop-hook.ps1\"",
17
17
  "loop_limit": null
18
18
  }
19
19
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a5c-ai/babysitter-cursor",
3
- "version": "5.0.1-staging.5cd43600",
3
+ "version": "5.0.1-staging.6e094dee",
4
4
  "description": "Babysitter orchestration plugin for Cursor IDE with SDK-managed process-library bootstrapping and in-turn iteration model",
5
5
  "scripts": {
6
6
  "test": "node scripts/sync-command-surfaces.js --check",
@@ -44,6 +44,6 @@
44
44
  },
45
45
  "homepage": "https://github.com/a5c-ai/babysitter/tree/main/plugins/babysitter-cursor#readme",
46
46
  "dependencies": {
47
- "@a5c-ai/babysitter-sdk": "5.0.1-staging.5cd43600"
47
+ "@a5c-ai/babysitter-sdk": "5.0.1-staging.6e094dee"
48
48
  }
49
49
  }
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "babysitter",
3
- "version": "5.0.1-staging.5cd43600",
3
+ "version": "5.0.1-staging.6e094dee",
4
4
  "description": "Orchestrate complex, multi-step workflows with event-sourced state management, hook-based extensibility, and human-in-the-loop approval -- powered by the Babysitter SDK",
5
5
  "author": "a5c.ai",
6
6
  "license": "MIT",
package/versions.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "sdkVersion": "5.0.1-staging.5cd43600"
2
+ "sdkVersion": "5.0.1-staging.6e094dee"
3
3
  }