replit-tools 1.2.41 → 1.2.43
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 +1 -1
- package/scripts/setup-claude-code.sh +151 -83
package/package.json
CHANGED
|
@@ -41,9 +41,13 @@ LOCAL_SHARE_CLAUDE="${HOME}/.local/share/claude"
|
|
|
41
41
|
VERSION_FILE="${REPLIT_TOOLS}/.version"
|
|
42
42
|
PACKAGE_NAME="data-remote"
|
|
43
43
|
|
|
44
|
-
#
|
|
44
|
+
# Force Claude re-detection: bash setup-claude-code.sh --refresh OR CLAUDE_FORCE_REFRESH=1
|
|
45
|
+
CLAUDE_FORCE_REFRESH="${CLAUDE_FORCE_REFRESH:-0}"
|
|
46
|
+
[ "${1:-}" = "--refresh" ] && CLAUDE_FORCE_REFRESH=1
|
|
47
|
+
|
|
48
|
+
# Logging helper - prints in interactive shells, or when run manually with --refresh
|
|
45
49
|
log() {
|
|
46
|
-
if [[ $- == *i* ]]; then
|
|
50
|
+
if [[ $- == *i* ]] || [ "${CLAUDE_FORCE_REFRESH:-0}" = "1" ]; then
|
|
47
51
|
echo "$1"
|
|
48
52
|
fi
|
|
49
53
|
}
|
|
@@ -225,18 +229,27 @@ if command -v node &>/dev/null; then
|
|
|
225
229
|
if (fs.existsSync(codexConfigPath)) c = fs.readFileSync(codexConfigPath, "utf8");
|
|
226
230
|
const desired = String(codexMaxBytes);
|
|
227
231
|
let updated = false;
|
|
232
|
+
// Codex requires persistence field when [history] section is present
|
|
228
233
|
if (!/\[history\]/.test(c)) {
|
|
229
|
-
c = (c.trimEnd() + "\n\n[history]\nmax_bytes = " + desired + "\n").trimStart();
|
|
234
|
+
c = (c.trimEnd() + "\n\n[history]\npersistence = \"save-all\"\nmax_bytes = " + desired + "\n").trimStart();
|
|
230
235
|
updated = true;
|
|
231
|
-
} else
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
c = c.replace(
|
|
236
|
+
} else {
|
|
237
|
+
// Ensure persistence field exists
|
|
238
|
+
if (!/(\[history\][\s\S]*?)persistence\s*=/.test(c)) {
|
|
239
|
+
c = c.replace(/\[history\](\s*)/, "[history]$1persistence = \"save-all\"\n");
|
|
240
|
+
updated = true;
|
|
241
|
+
}
|
|
242
|
+
// Ensure max_bytes is set correctly
|
|
243
|
+
if (/max_bytes\s*=\s*(\d+)/.test(c)) {
|
|
244
|
+
const cur = c.match(/max_bytes\s*=\s*(\d+)/)[1];
|
|
245
|
+
if (cur !== desired) {
|
|
246
|
+
c = c.replace(/(\[history\][\s\S]*?max_bytes\s*=\s*)\d+/, "$1" + desired);
|
|
247
|
+
updated = true;
|
|
248
|
+
}
|
|
249
|
+
} else {
|
|
250
|
+
c = c.replace(/(\[history\][\s\S]*?persistence\s*=\s*"[^"]*"\s*\n)/, "$1max_bytes = " + desired + "\n");
|
|
235
251
|
updated = true;
|
|
236
252
|
}
|
|
237
|
-
} else {
|
|
238
|
-
c = c.replace(/\[history\](\s*)/, "[history]$1max_bytes = " + desired + "\n");
|
|
239
|
-
updated = true;
|
|
240
253
|
}
|
|
241
254
|
if (updated) {
|
|
242
255
|
fs.writeFileSync(codexConfigPath, c);
|
|
@@ -305,97 +318,152 @@ if [ ! -L "${SHARE_VERSIONS}" ] || [ "$(readlink -f "${SHARE_VERSIONS}")" != "${
|
|
|
305
318
|
fi
|
|
306
319
|
|
|
307
320
|
# =============================================================================
|
|
308
|
-
# Step 4:
|
|
321
|
+
# Step 4: Detect newest Claude binary across ALL install locations, promote it
|
|
309
322
|
# =============================================================================
|
|
323
|
+
# Bug history: npm installs claude to node_modules/@anthropic-ai/claude-code/
|
|
324
|
+
# which the old finder never checked, so ~/.local/bin/claude stayed pinned to an
|
|
325
|
+
# old .claude-versions entry while Replit's agent UI launched the newer
|
|
326
|
+
# node_modules binary directly. Now we scan everything, compare by real
|
|
327
|
+
# --version output (not filename), promote the winner, and GC stale copies.
|
|
328
|
+
|
|
329
|
+
CLAUDE_DETECT_CACHE="${CLAUDE_VERSIONS}/.detect-cache"
|
|
330
|
+
|
|
331
|
+
# Get semver by EXECUTING the binary (never trust filenames). Empty if invalid.
|
|
332
|
+
claude_bin_version() {
|
|
333
|
+
local bin="$1"
|
|
334
|
+
[ -f "$bin" ] || return 1
|
|
335
|
+
local v
|
|
336
|
+
v=$("$bin" --version 2>/dev/null | awk '{print $1}')
|
|
337
|
+
if [[ "$v" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
338
|
+
echo "$v"; return 0
|
|
339
|
+
fi
|
|
340
|
+
return 1
|
|
341
|
+
}
|
|
310
342
|
|
|
311
|
-
#
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
343
|
+
# All places a Claude binary might live (npm, bun, official installer, our store)
|
|
344
|
+
claude_candidate_paths() {
|
|
345
|
+
echo "${WORKSPACE}/node_modules/@anthropic-ai/claude-code/bin/claude.exe"
|
|
346
|
+
echo "${WORKSPACE}/node_modules/.bin/claude"
|
|
347
|
+
echo "${HOME}/.npm-global/bin/claude"
|
|
348
|
+
echo "${HOME}/.bun/bin/claude"
|
|
349
|
+
if [ -d "${HOME}/.local/share/claude/versions" ] && [ ! -L "${HOME}/.local/share/claude/versions" ]; then
|
|
350
|
+
find "${HOME}/.local/share/claude/versions" -maxdepth 1 -type f 2>/dev/null
|
|
351
|
+
fi
|
|
317
352
|
if [ -d "${CLAUDE_VERSIONS}" ]; then
|
|
318
|
-
|
|
319
|
-
if [ -n "${ver}" ] && [ -f "${CLAUDE_VERSIONS}/${ver}" ]; then
|
|
320
|
-
found_binary="${CLAUDE_VERSIONS}/${ver}"
|
|
321
|
-
found_version="${ver}"
|
|
322
|
-
fi
|
|
353
|
+
find "${CLAUDE_VERSIONS}" -maxdepth 1 -type f ! -name '.*' 2>/dev/null
|
|
323
354
|
fi
|
|
355
|
+
# command -v claude, but ONLY if it does not resolve to our own managed symlink
|
|
356
|
+
local cmdclaude our_target real
|
|
357
|
+
cmdclaude=$(command -v claude 2>/dev/null)
|
|
358
|
+
our_target=$(readlink -f "${LOCAL_BIN}/claude" 2>/dev/null)
|
|
359
|
+
if [ -n "$cmdclaude" ]; then
|
|
360
|
+
real=$(readlink -f "$cmdclaude" 2>/dev/null)
|
|
361
|
+
[ -n "$real" ] && [ "$real" != "$our_target" ] && echo "$real"
|
|
362
|
+
fi
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
# Cheap fingerprint of candidate paths (mtime+size) to short-circuit unchanged runs
|
|
366
|
+
claude_detect_fingerprint() {
|
|
367
|
+
{
|
|
368
|
+
local rp
|
|
369
|
+
while IFS= read -r c; do
|
|
370
|
+
[ -z "$c" ] && continue
|
|
371
|
+
rp=$(readlink -f "$c" 2>/dev/null)
|
|
372
|
+
[ -f "$rp" ] && stat -c '%n:%Y:%s' "$rp" 2>/dev/null
|
|
373
|
+
done < <(claude_candidate_paths)
|
|
374
|
+
readlink -f "${LOCAL_BIN}/claude" 2>/dev/null
|
|
375
|
+
} | md5sum 2>/dev/null | awk '{print $1}'
|
|
376
|
+
}
|
|
324
377
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
378
|
+
# Detect newest version across all candidates, promote into .claude-versions, relink
|
|
379
|
+
detect_and_promote_claude() {
|
|
380
|
+
local best_ver="" best_path="" seen="" rp v
|
|
381
|
+
while IFS= read -r c; do
|
|
382
|
+
[ -z "$c" ] && continue
|
|
383
|
+
rp=$(readlink -f "$c" 2>/dev/null)
|
|
384
|
+
[ -z "$rp" ] && continue
|
|
385
|
+
[ -f "$rp" ] || continue
|
|
386
|
+
case "$seen" in *"|${rp}|"*) continue ;; esac
|
|
387
|
+
seen="${seen}|${rp}|"
|
|
388
|
+
v=$(claude_bin_version "$rp") || continue
|
|
389
|
+
if [ -z "$best_ver" ] || [ "$(printf '%s\n%s\n' "$best_ver" "$v" | sort -V | tail -n1)" = "$v" ]; then
|
|
390
|
+
if [ "$v" != "$best_ver" ] || [ -z "$best_path" ]; then
|
|
391
|
+
best_ver="$v"; best_path="$rp"
|
|
334
392
|
fi
|
|
335
393
|
fi
|
|
394
|
+
done < <(claude_candidate_paths)
|
|
395
|
+
|
|
396
|
+
[ -z "$best_ver" ] && return 1
|
|
397
|
+
|
|
398
|
+
mkdir -p "${CLAUDE_VERSIONS}"
|
|
399
|
+
if [ ! -f "${CLAUDE_VERSIONS}/${best_ver}" ]; then
|
|
400
|
+
cp -p "${best_path}" "${CLAUDE_VERSIONS}/${best_ver}" 2>/dev/null || true
|
|
401
|
+
chmod 755 "${CLAUDE_VERSIONS}/${best_ver}" 2>/dev/null || true
|
|
336
402
|
fi
|
|
337
403
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
404
|
+
local new_target="${CLAUDE_VERSIONS}/${best_ver}"
|
|
405
|
+
local cur_target
|
|
406
|
+
cur_target=$(readlink -f "${LOCAL_BIN}/claude" 2>/dev/null)
|
|
407
|
+
if [ "$cur_target" != "$new_target" ]; then
|
|
408
|
+
mkdir -p "${LOCAL_BIN}"
|
|
409
|
+
ln -sfn "${new_target}" "${LOCAL_BIN}/claude"
|
|
410
|
+
if [ -n "$cur_target" ] && [ -f "$cur_target" ]; then
|
|
411
|
+
log "✅ Claude $(basename "$cur_target") → ${best_ver}"
|
|
412
|
+
else
|
|
413
|
+
log "✅ Claude ${best_ver} active (~/.local/bin/claude)"
|
|
348
414
|
fi
|
|
349
415
|
fi
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
FOUND_CLAUDE_BINARY="${found_binary}"
|
|
353
|
-
FOUND_CLAUDE_VERSION="${found_version}"
|
|
416
|
+
LATEST_VERSION="${best_ver}"
|
|
417
|
+
return 0
|
|
354
418
|
}
|
|
355
419
|
|
|
356
|
-
#
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
420
|
+
# Keep only the newest 3 versions in our store (each binary is ~230 MB)
|
|
421
|
+
gc_claude_versions() {
|
|
422
|
+
[ -d "${CLAUDE_VERSIONS}" ] || return 0
|
|
423
|
+
local cur_target all count to_delete v p
|
|
424
|
+
cur_target=$(readlink -f "${LOCAL_BIN}/claude" 2>/dev/null)
|
|
425
|
+
all=$(find "${CLAUDE_VERSIONS}" -maxdepth 1 -type f -printf '%f\n' 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V)
|
|
426
|
+
count=$(printf '%s\n' "$all" | grep -c .)
|
|
427
|
+
[ "$count" -le 3 ] && return 0
|
|
428
|
+
to_delete=$(printf '%s\n' "$all" | head -n $((count - 3)))
|
|
429
|
+
for v in $to_delete; do
|
|
430
|
+
p="${CLAUDE_VERSIONS}/${v}"
|
|
431
|
+
[ "$(readlink -f "$p")" = "$cur_target" ] && continue
|
|
432
|
+
rm -f "$p" 2>/dev/null && log "🗑️ Removed old Claude ${v}"
|
|
433
|
+
done
|
|
434
|
+
}
|
|
362
435
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
436
|
+
# Run detection (cheap short-circuit unless paths changed or --refresh given)
|
|
437
|
+
run_claude_detection() {
|
|
438
|
+
local fp cached cur
|
|
439
|
+
fp=$(claude_detect_fingerprint)
|
|
440
|
+
cached=""
|
|
441
|
+
[ -f "${CLAUDE_DETECT_CACHE}" ] && cached=$(cat "${CLAUDE_DETECT_CACHE}" 2>/dev/null)
|
|
442
|
+
|
|
443
|
+
if [ "${CLAUDE_FORCE_REFRESH}" != "1" ] && [ -n "$fp" ] && [ "$fp" = "$cached" ]; then
|
|
444
|
+
cur=$(readlink -f "${LOCAL_BIN}/claude" 2>/dev/null)
|
|
445
|
+
if [ -f "$cur" ]; then
|
|
446
|
+
LATEST_VERSION=$(basename "$cur")
|
|
447
|
+
return 0 # nothing changed since last run
|
|
448
|
+
fi
|
|
369
449
|
fi
|
|
370
450
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
rm -f "${LOCAL_BIN}/claude" 2>/dev/null || true
|
|
374
|
-
ln -sf "${CLAUDE_VERSIONS}/${LATEST_VERSION}" "${LOCAL_BIN}/claude"
|
|
375
|
-
log "✅ Claude binary symlink: ~/.local/bin/claude -> ${CLAUDE_VERSIONS}/${LATEST_VERSION}"
|
|
376
|
-
fi
|
|
377
|
-
else
|
|
378
|
-
# Claude not installed - install it
|
|
379
|
-
log "⚠️ Claude Code not found, installing..."
|
|
380
|
-
|
|
381
|
-
# Install Claude Code using the official installer
|
|
382
|
-
if curl -fsSL https://claude.ai/install.sh | bash 2>/dev/null; then
|
|
383
|
-
# After install, find and sync the binary
|
|
384
|
-
find_claude_binary
|
|
385
|
-
if [ -n "${FOUND_CLAUDE_BINARY}" ]; then
|
|
386
|
-
LATEST_VERSION="${FOUND_CLAUDE_VERSION}"
|
|
387
|
-
if [ ! -f "${CLAUDE_VERSIONS}/${LATEST_VERSION}" ]; then
|
|
388
|
-
cp -p "${FOUND_CLAUDE_BINARY}" "${CLAUDE_VERSIONS}/${LATEST_VERSION}" 2>/dev/null || true
|
|
389
|
-
chmod 755 "${CLAUDE_VERSIONS}/${LATEST_VERSION}" 2>/dev/null || true
|
|
390
|
-
fi
|
|
391
|
-
ln -sf "${CLAUDE_VERSIONS}/${LATEST_VERSION}" "${LOCAL_BIN}/claude"
|
|
392
|
-
log "✅ Claude Code ${LATEST_VERSION} installed"
|
|
393
|
-
fi
|
|
451
|
+
if detect_and_promote_claude; then
|
|
452
|
+
gc_claude_versions
|
|
394
453
|
else
|
|
395
|
-
log "
|
|
396
|
-
|
|
454
|
+
log "⚠️ Claude Code not found, installing..."
|
|
455
|
+
if curl -fsSL https://claude.ai/install.sh | bash 2>/dev/null; then
|
|
456
|
+
detect_and_promote_claude && gc_claude_versions
|
|
457
|
+
else
|
|
458
|
+
log "❌ Failed to install Claude Code"
|
|
459
|
+
log " Try running: curl -fsSL https://claude.ai/install.sh | bash"
|
|
460
|
+
fi
|
|
397
461
|
fi
|
|
398
|
-
|
|
462
|
+
# Persist post-promotion fingerprint so the next shell short-circuits
|
|
463
|
+
claude_detect_fingerprint > "${CLAUDE_DETECT_CACHE}" 2>/dev/null
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
run_claude_detection
|
|
399
467
|
|
|
400
468
|
# =============================================================================
|
|
401
469
|
# Step 5: Ensure PATH includes ~/.local/bin
|