replit-tools 1.1.9 → 1.1.11
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/package.json
CHANGED
|
@@ -3,20 +3,21 @@
|
|
|
3
3
|
# Automatically refreshes Claude Code OAuth tokens before expiration
|
|
4
4
|
# Part of DATA Tools - https://github.com/stevemoraco/DATAtools
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Paths - credentials are at workspace root, not inside .replit-tools
|
|
7
7
|
WORKSPACE="/home/runner/workspace"
|
|
8
8
|
REPLIT_TOOLS="${WORKSPACE}/.replit-tools"
|
|
9
|
-
|
|
9
|
+
# Credentials are stored at /home/runner/workspace/.claude-persistent (NOT inside .replit-tools)
|
|
10
|
+
CREDENTIALS_FILE="${CLAUDE_CONFIG_DIR:-${WORKSPACE}/.claude-persistent}/.credentials.json"
|
|
10
11
|
LOG_FILE="${REPLIT_TOOLS}/.logs/auth-refresh.log"
|
|
11
12
|
|
|
13
|
+
# Ensure log directory exists
|
|
14
|
+
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
|
|
15
|
+
|
|
12
16
|
# OAuth configuration
|
|
13
17
|
OAUTH_ENDPOINT="https://console.anthropic.com/v1/oauth/token"
|
|
14
18
|
CLIENT_ID="9d1c250a-e61b-44d9-88ed-5944d1962f5e"
|
|
15
19
|
REFRESH_THRESHOLD_HOURS=2 # Refresh when less than 2 hours remaining
|
|
16
20
|
|
|
17
|
-
# Ensure log directory exists
|
|
18
|
-
mkdir -p "${REPLIT_TOOLS}/.logs" 2>/dev/null
|
|
19
|
-
|
|
20
21
|
# Logging function
|
|
21
22
|
log() {
|
|
22
23
|
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
@@ -97,8 +98,8 @@ refresh_token() {
|
|
|
97
98
|
|
|
98
99
|
log "Attempting token refresh..."
|
|
99
100
|
|
|
100
|
-
# Make the refresh request
|
|
101
|
-
local response=$(curl -s -X POST "$OAUTH_ENDPOINT" \
|
|
101
|
+
# Make the refresh request (5 second timeout to fail fast)
|
|
102
|
+
local response=$(curl -s --max-time 5 -X POST "$OAUTH_ENDPOINT" \
|
|
102
103
|
-H "Content-Type: application/json" \
|
|
103
104
|
-d "{\"grant_type\":\"refresh_token\",\"refresh_token\":\"$refresh_token\",\"client_id\":\"$CLIENT_ID\"}" \
|
|
104
105
|
2>/dev/null)
|
|
@@ -225,7 +225,27 @@ get_terminal_last_session() {
|
|
|
225
225
|
fi
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
#
|
|
228
|
+
# Run Claude and handle exit codes (returns to menu on failure)
|
|
229
|
+
run_claude_with_retry() {
|
|
230
|
+
local cmd="$1"
|
|
231
|
+
local session_desc="$2"
|
|
232
|
+
|
|
233
|
+
echo ""
|
|
234
|
+
echo " ${session_desc}..."
|
|
235
|
+
|
|
236
|
+
# Run Claude
|
|
237
|
+
eval "$cmd"
|
|
238
|
+
local exit_code=$?
|
|
239
|
+
|
|
240
|
+
# Save session state on success
|
|
241
|
+
if [ $exit_code -eq 0 ]; then
|
|
242
|
+
save_session_state "$(tail -1 "${HOME}/.claude/history.jsonl" 2>/dev/null | grep -oP '"sessionId":"[^"]+"' | cut -d'"' -f4)"
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
return $exit_code
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
# Interactive session picker (loops until user exits to shell)
|
|
229
249
|
claude_prompt() {
|
|
230
250
|
# Only in interactive shells
|
|
231
251
|
[[ $- != *i* ]] && return 0
|
|
@@ -236,104 +256,140 @@ claude_prompt() {
|
|
|
236
256
|
fi
|
|
237
257
|
|
|
238
258
|
# LOOP PREVENTION: Track if we've already prompted this terminal session
|
|
239
|
-
|
|
259
|
+
# Include the shell PID so new shells always get the menu
|
|
260
|
+
local prompt_marker="${REPLIT_TOOLS}/.prompt-active-${TERMINAL_ID}-$$"
|
|
261
|
+
|
|
262
|
+
# Clean up old markers from crashed/closed shells
|
|
263
|
+
# Remove markers older than 1 hour or from PIDs that no longer exist
|
|
264
|
+
find "${REPLIT_TOOLS}" -name ".prompt-active-*" -mmin +60 -delete 2>/dev/null
|
|
265
|
+
for marker in "${REPLIT_TOOLS}"/.prompt-active-*; do
|
|
266
|
+
if [ -f "$marker" ]; then
|
|
267
|
+
local marker_pid=$(basename "$marker" | rev | cut -d'-' -f1 | rev)
|
|
268
|
+
if [ -n "$marker_pid" ] && ! kill -0 "$marker_pid" 2>/dev/null; then
|
|
269
|
+
rm -f "$marker" 2>/dev/null
|
|
270
|
+
fi
|
|
271
|
+
fi
|
|
272
|
+
done
|
|
240
273
|
|
|
241
|
-
# If
|
|
274
|
+
# If THIS shell already showed the prompt, skip (prevents re-sourcing issues)
|
|
242
275
|
if [ -f "$prompt_marker" ]; then
|
|
243
|
-
# Clear old markers (older than 12 hours)
|
|
244
|
-
find "${REPLIT_TOOLS}" -name ".prompt-shown-*" -mmin +720 -delete 2>/dev/null
|
|
245
276
|
return 0
|
|
246
277
|
fi
|
|
247
278
|
|
|
248
|
-
# Mark that we're showing the prompt
|
|
279
|
+
# Mark that we're showing the prompt for THIS shell session
|
|
249
280
|
touch "$prompt_marker" 2>/dev/null
|
|
250
281
|
|
|
251
|
-
|
|
252
|
-
|
|
282
|
+
# Cleanup function to remove marker when shell exits
|
|
283
|
+
trap "rm -f '$prompt_marker' 2>/dev/null" EXIT
|
|
284
|
+
|
|
285
|
+
# Main menu loop - keeps showing until user chooses shell
|
|
286
|
+
while true; do
|
|
287
|
+
local running=$(count_claude_instances)
|
|
288
|
+
local last_session=$(get_terminal_last_session)
|
|
289
|
+
|
|
290
|
+
echo ""
|
|
291
|
+
echo "╭─────────────────────────────────────────────────────────╮"
|
|
292
|
+
echo "│ Claude Session Manager │"
|
|
293
|
+
echo "╰─────────────────────────────────────────────────────────╯"
|
|
294
|
+
|
|
295
|
+
if [ "$running" -gt 0 ]; then
|
|
296
|
+
echo " ($running Claude instance(s) running in other terminals)"
|
|
297
|
+
fi
|
|
298
|
+
echo ""
|
|
299
|
+
|
|
300
|
+
# Show options
|
|
301
|
+
echo " [c] Continue last session for this terminal"
|
|
302
|
+
if [ -n "$last_session" ]; then
|
|
303
|
+
echo " └─ ${last_session:0:8}..."
|
|
304
|
+
fi
|
|
305
|
+
echo " [r] Resume a specific session (pick from list)"
|
|
306
|
+
echo " [n] Start new session"
|
|
307
|
+
echo " [l] Login to Claude (authenticate)"
|
|
308
|
+
echo " [s] Skip - just give me a shell"
|
|
309
|
+
echo ""
|
|
310
|
+
|
|
311
|
+
# Read choice with timeout
|
|
312
|
+
local choice
|
|
313
|
+
read -t 60 -n 1 -p " Choice [c/r/n/l/s]: " choice
|
|
314
|
+
echo ""
|
|
315
|
+
|
|
316
|
+
case "$choice" in
|
|
317
|
+
c|C|"")
|
|
318
|
+
# Continue last session (default on Enter or timeout)
|
|
319
|
+
if [ -n "$last_session" ]; then
|
|
320
|
+
run_claude_with_retry "claude -r '$last_session' --dangerously-skip-permissions" "Resuming session ${last_session:0:8}"
|
|
321
|
+
else
|
|
322
|
+
run_claude_with_retry "claude --dangerously-skip-permissions" "No previous session, starting new"
|
|
323
|
+
fi
|
|
324
|
+
# After Claude exits, loop back to menu
|
|
325
|
+
echo ""
|
|
326
|
+
echo " Claude exited. Returning to menu..."
|
|
327
|
+
sleep 1
|
|
328
|
+
;;
|
|
329
|
+
r|R)
|
|
330
|
+
# Show session list with full details
|
|
331
|
+
echo ""
|
|
332
|
+
echo " Recent Sessions"
|
|
333
|
+
show_sessions
|
|
253
334
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
echo "│ Claude Session Manager │"
|
|
257
|
-
echo "╰─────────────────────────────────────────────────────────╯"
|
|
335
|
+
# Get session IDs for selection
|
|
336
|
+
local session_ids=$(get_recent_sessions | grep "^ID|" | cut -d'|' -f2)
|
|
258
337
|
|
|
259
|
-
|
|
260
|
-
echo " ($running Claude instance(s) running in other terminals)"
|
|
261
|
-
fi
|
|
262
|
-
echo ""
|
|
338
|
+
read -t 60 -p " Enter number (or 'q' to cancel): " session_num
|
|
263
339
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
fi
|
|
269
|
-
echo " [r] Resume a specific session (pick from list)"
|
|
270
|
-
echo " [n] Start new session"
|
|
271
|
-
echo " [s] Skip - just give me a shell"
|
|
272
|
-
echo ""
|
|
273
|
-
|
|
274
|
-
# Read choice with timeout
|
|
275
|
-
local choice
|
|
276
|
-
read -t 30 -n 1 -p " Choice [c/r/n/s]: " choice
|
|
277
|
-
echo ""
|
|
340
|
+
if [ "$session_num" = "q" ] || [ -z "$session_num" ]; then
|
|
341
|
+
echo " Cancelled, returning to menu..."
|
|
342
|
+
continue
|
|
343
|
+
fi
|
|
278
344
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
345
|
+
local selected_id=$(echo "$session_ids" | sed -n "${session_num}p")
|
|
346
|
+
if [ -n "$selected_id" ]; then
|
|
347
|
+
run_claude_with_retry "claude -r '$selected_id' --dangerously-skip-permissions" "Resuming session $selected_id"
|
|
348
|
+
echo ""
|
|
349
|
+
echo " Claude exited. Returning to menu..."
|
|
350
|
+
sleep 1
|
|
351
|
+
else
|
|
352
|
+
echo " Invalid selection."
|
|
353
|
+
fi
|
|
354
|
+
;;
|
|
355
|
+
n|N)
|
|
356
|
+
# Start new session
|
|
357
|
+
run_claude_with_retry "claude --dangerously-skip-permissions" "Starting new Claude session"
|
|
283
358
|
echo ""
|
|
284
|
-
echo "
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
359
|
+
echo " Claude exited. Returning to menu..."
|
|
360
|
+
sleep 1
|
|
361
|
+
;;
|
|
362
|
+
l|L)
|
|
363
|
+
# Login to Claude
|
|
364
|
+
echo ""
|
|
365
|
+
echo " Starting Claude login..."
|
|
366
|
+
echo " (This will open a browser or show a URL to authenticate)"
|
|
288
367
|
echo ""
|
|
289
|
-
echo " No previous session for this terminal, starting new..."
|
|
290
|
-
claude --dangerously-skip-permissions
|
|
291
|
-
save_session_state "$(tail -1 "${HOME}/.claude/history.jsonl" 2>/dev/null | grep -oP '"sessionId":"[^"]+"' | cut -d'"' -f4)"
|
|
292
|
-
fi
|
|
293
|
-
;;
|
|
294
|
-
r|R)
|
|
295
|
-
# Show session list with full details
|
|
296
|
-
echo ""
|
|
297
|
-
echo " Recent Sessions"
|
|
298
|
-
show_sessions
|
|
299
368
|
|
|
300
|
-
|
|
301
|
-
|
|
369
|
+
# Clear the auth failed marker so setup script will retry
|
|
370
|
+
rm -f "${REPLIT_TOOLS}/.auth-refresh-failed" 2>/dev/null
|
|
302
371
|
|
|
303
|
-
|
|
372
|
+
claude login
|
|
304
373
|
|
|
305
|
-
|
|
306
|
-
echo "
|
|
374
|
+
echo ""
|
|
375
|
+
echo " Login complete. Returning to menu..."
|
|
376
|
+
sleep 1
|
|
377
|
+
;;
|
|
378
|
+
s|S)
|
|
379
|
+
# Skip - just shell
|
|
380
|
+
echo ""
|
|
381
|
+
echo " Okay, just a shell. Type 'claude-menu' to return here."
|
|
382
|
+
# Keep the marker so re-sourcing bashrc won't re-show menu
|
|
383
|
+
# The trap will clean it up when shell exits
|
|
307
384
|
return 0
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
local selected_id=$(echo "$session_ids" | sed -n "${session_num}p")
|
|
311
|
-
if [ -n "$selected_id" ]; then
|
|
385
|
+
;;
|
|
386
|
+
*)
|
|
312
387
|
echo ""
|
|
313
|
-
echo "
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
fi
|
|
319
|
-
;;
|
|
320
|
-
n|N)
|
|
321
|
-
# Start new session
|
|
322
|
-
echo ""
|
|
323
|
-
echo " Starting new Claude session..."
|
|
324
|
-
claude --dangerously-skip-permissions
|
|
325
|
-
save_session_state "$(tail -1 "${HOME}/.claude/history.jsonl" 2>/dev/null | grep -oP '"sessionId":"[^"]+"' | cut -d'"' -f4)"
|
|
326
|
-
;;
|
|
327
|
-
s|S)
|
|
328
|
-
# Skip - just shell
|
|
329
|
-
echo ""
|
|
330
|
-
echo " Okay, just a shell. Type 'claude' or 'cr' when you want Claude."
|
|
331
|
-
;;
|
|
332
|
-
*)
|
|
333
|
-
echo ""
|
|
334
|
-
echo " Unknown option. Type 'claude' to start manually."
|
|
335
|
-
;;
|
|
336
|
-
esac
|
|
388
|
+
echo " Unknown option. Please choose c, r, n, l, or s."
|
|
389
|
+
sleep 1
|
|
390
|
+
;;
|
|
391
|
+
esac
|
|
392
|
+
done
|
|
337
393
|
}
|
|
338
394
|
|
|
339
395
|
# Aliases for manual use
|
|
@@ -353,11 +409,17 @@ export TERMINAL_ID
|
|
|
353
409
|
|
|
354
410
|
# Reset prompt marker and show menu
|
|
355
411
|
claude_menu() {
|
|
356
|
-
|
|
412
|
+
# Clear the marker that claude_prompt uses to prevent re-showing
|
|
413
|
+
# This allows manual invocation to always show the menu
|
|
414
|
+
local prompt_marker="${REPLIT_TOOLS}/.prompt-active-${TERMINAL_ID}-$$"
|
|
357
415
|
rm -f "$prompt_marker" 2>/dev/null
|
|
416
|
+
# Also clear any old-style markers for this terminal
|
|
417
|
+
rm -f "${REPLIT_TOOLS}/.prompt-shown-${TERMINAL_ID}" 2>/dev/null
|
|
418
|
+
rm -f "${REPLIT_TOOLS}/.prompt-active-${TERMINAL_ID}-"* 2>/dev/null
|
|
358
419
|
claude_prompt
|
|
359
420
|
}
|
|
360
421
|
alias claude-menu='claude_menu'
|
|
422
|
+
alias cm='claude_menu'
|
|
361
423
|
|
|
362
424
|
if [ "${CLAUDE_NO_PROMPT}" != "true" ]; then
|
|
363
425
|
claude_prompt
|
|
@@ -21,7 +21,8 @@ WORKSPACE="/home/runner/workspace"
|
|
|
21
21
|
REPLIT_TOOLS="${WORKSPACE}/.replit-tools"
|
|
22
22
|
|
|
23
23
|
# Allow env vars to override (for custom config locations)
|
|
24
|
-
|
|
24
|
+
# Note: Credentials are at workspace root (.claude-persistent), NOT inside .replit-tools
|
|
25
|
+
CLAUDE_PERSISTENT="${CLAUDE_CONFIG_DIR:-${WORKSPACE}/.claude-persistent}"
|
|
25
26
|
CLAUDE_VERSIONS="${REPLIT_TOOLS}/.claude-versions"
|
|
26
27
|
LOGS_DIR="${REPLIT_TOOLS}/.logs"
|
|
27
28
|
SCRIPTS_DIR="${REPLIT_TOOLS}/scripts"
|