replit-tools 1.2.28 → 1.2.29

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.
Files changed (2) hide show
  1. package/index.js +55 -0
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -147,6 +147,7 @@ function main() {
147
147
  const claudeVersionsDir = path.join(REPLIT_TOOLS, '.claude-versions');
148
148
  const logsDir = path.join(REPLIT_TOOLS, '.logs');
149
149
  const scriptsDir = path.join(REPLIT_TOOLS, 'scripts');
150
+ const sshPersistentDir = path.join(REPLIT_TOOLS, '.ssh-persistent');
150
151
 
151
152
  // Old locations (for migration)
152
153
  const oldLocations = {
@@ -504,6 +505,55 @@ function main() {
504
505
  console.log(` ⚠️ Could not create Codex symlink: ${err.message}`);
505
506
  }
506
507
 
508
+ // SSH symlink (~/.ssh -> persistent dir, preserves keys/known_hosts/config)
509
+ const sshLink = path.join(HOME, '.ssh');
510
+ try {
511
+ if (!fs.existsSync(sshPersistentDir)) {
512
+ fs.mkdirSync(sshPersistentDir, { recursive: true, mode: 0o700 });
513
+ }
514
+ fs.chmodSync(sshPersistentDir, 0o700);
515
+
516
+ let needsLink = false;
517
+ try {
518
+ const stat = fs.lstatSync(sshLink);
519
+ if (stat.isSymbolicLink()) {
520
+ const current = fs.readlinkSync(sshLink);
521
+ if (current !== sshPersistentDir) {
522
+ fs.unlinkSync(sshLink);
523
+ needsLink = true;
524
+ }
525
+ } else if (stat.isDirectory()) {
526
+ console.log(' Moving existing ~/.ssh data to persistent storage...');
527
+ execSync(`cp -rn "${sshLink}"/. "${sshPersistentDir}/" 2>/dev/null || true`, { shell: '/bin/bash' });
528
+ execSync(`rm -rf "${sshLink}"`, { shell: '/bin/bash' });
529
+ needsLink = true;
530
+ }
531
+ } catch {
532
+ needsLink = true;
533
+ }
534
+
535
+ if (needsLink) {
536
+ fs.symlinkSync(sshPersistentDir, sshLink);
537
+ }
538
+
539
+ // Re-tighten perms on key files (SSH refuses keys with loose perms)
540
+ try {
541
+ for (const f of fs.readdirSync(sshPersistentDir)) {
542
+ const full = path.join(sshPersistentDir, f);
543
+ if (f === 'known_hosts' || f === 'config' || f.endsWith('.pub')) {
544
+ fs.chmodSync(full, 0o644);
545
+ } else if (fs.statSync(full).isFile()) {
546
+ fs.chmodSync(full, 0o600);
547
+ }
548
+ }
549
+ } catch {}
550
+
551
+ const displayPath = sshPersistentDir.replace(WORKSPACE + '/', '');
552
+ console.log(` ~/.ssh → ${displayPath}/`);
553
+ } catch (err) {
554
+ console.log(` ⚠️ Could not create SSH symlink: ${err.message}`);
555
+ }
556
+
507
557
  // Claude binary symlinks
508
558
  const localBin = path.join(HOME, '.local/bin');
509
559
  const localShare = path.join(HOME, '.local/share');
@@ -609,6 +659,11 @@ SETUP_SCRIPT="${scriptsDir}/setup-claude-code.sh"
609
659
  mkdir -p "${codexPersistentDir}"
610
660
  [ ! -L "\${HOME}/.codex" ] && ln -sf "${codexPersistentDir}" "\${HOME}/.codex"
611
661
 
662
+ # SSH Persistence (keys, known_hosts, config)
663
+ mkdir -p "${sshPersistentDir}"
664
+ chmod 700 "${sshPersistentDir}"
665
+ [ ! -L "\${HOME}/.ssh" ] && ln -sf "${sshPersistentDir}" "\${HOME}/.ssh"
666
+
612
667
  # Bash History Persistence
613
668
  PERSISTENT_HOME="${persistentHomeDir}"
614
669
  mkdir -p "\${PERSISTENT_HOME}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replit-tools",
3
- "version": "1.2.28",
3
+ "version": "1.2.29",
4
4
  "description": "DATA Tools - One command to set up Claude Code and Codex CLI on Replit with full persistence",
5
5
  "main": "index.js",
6
6
  "bin": {