replit-tools 1.0.2 → 1.0.4
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/README.md +148 -46
- package/index.js +100 -41
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,46 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DATA Tools
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**One command to set up Claude Code and Codex CLI on Replit with full persistence.**
|
|
4
4
|
|
|
5
|
-
When Replit containers restart, everything outside `/home/runner/workspace/` is wiped - including
|
|
5
|
+
When Replit containers restart, everything outside `/home/runner/workspace/` is wiped - including installed CLIs, conversations, auth tokens, and command history. DATA Tools fixes all of that.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Quick Start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- **Auth Persistence** - Keep your Claude authentication working
|
|
13
|
-
- **Binary Caching** - Claude binary persists (faster startup)
|
|
14
|
-
- **Bash History** - Command history survives restarts too
|
|
9
|
+
```bash
|
|
10
|
+
npx replit-tools
|
|
11
|
+
```
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
That's it. The installer will:
|
|
17
14
|
|
|
18
|
-
|
|
15
|
+
1. **Install Claude Code** (if not already installed)
|
|
16
|
+
2. **Install OpenAI Codex CLI** (if not already installed)
|
|
17
|
+
3. **Detect existing config** and preserve your data
|
|
18
|
+
4. **Set up persistence** so everything survives restarts
|
|
19
|
+
5. **Launch the session picker** so you can start working immediately
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
npx replit-claude-persist
|
|
22
|
-
```
|
|
21
|
+
## What Gets Installed
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
| Tool | Source | Purpose |
|
|
24
|
+
|------|--------|---------|
|
|
25
|
+
| **Claude Code** | `curl https://claude.ai/install.sh` | Anthropic's CLI for Claude |
|
|
26
|
+
| **Codex CLI** | `npm i -g @openai/codex` | OpenAI's coding assistant |
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
curl -fsSL https://raw.githubusercontent.com/stevemoraco/DATAtools/main/install.sh | bash
|
|
28
|
-
```
|
|
28
|
+
Both are installed only if not already present. Existing installations are preserved.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## What Gets Persisted
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
| Data | Location | Survives Restart? |
|
|
33
|
+
|------|----------|-------------------|
|
|
34
|
+
| Claude conversations | `.claude-persistent/` | Yes |
|
|
35
|
+
| Claude credentials | `.claude-persistent/` | Yes |
|
|
36
|
+
| Claude binary | `.local/share/claude/versions/` | Yes |
|
|
37
|
+
| Codex data | `.codex-persistent/` | Yes |
|
|
38
|
+
| Bash history | `.persistent-home/` | Yes |
|
|
39
|
+
| Per-terminal sessions | `.claude-sessions/` | Yes |
|
|
36
40
|
|
|
37
|
-
##
|
|
41
|
+
## The Session Picker
|
|
38
42
|
|
|
39
|
-
After installation
|
|
43
|
+
After installation (and on every new shell), you'll see:
|
|
40
44
|
|
|
41
45
|
```
|
|
46
|
+
✅ Claude Code already installed (1.0.17)
|
|
47
|
+
✅ Codex CLI already installed
|
|
48
|
+
|
|
42
49
|
✅ Claude authentication: valid (23h remaining)
|
|
43
|
-
✅ Claude Code ready: 2.0.71 (Claude Code)
|
|
44
50
|
|
|
45
51
|
╭─────────────────────────────────────────────────────────╮
|
|
46
52
|
│ Claude Session Manager │
|
|
@@ -56,7 +62,9 @@ After installation, opening a new shell shows:
|
|
|
56
62
|
Choice [c/r/n/s]: _
|
|
57
63
|
```
|
|
58
64
|
|
|
59
|
-
|
|
65
|
+
### Session Details
|
|
66
|
+
|
|
67
|
+
Press `r` to see full session metadata:
|
|
60
68
|
|
|
61
69
|
```
|
|
62
70
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -69,30 +77,99 @@ Press `r` to see detailed session info:
|
|
|
69
77
|
Latest: "Thanks, that worked!"
|
|
70
78
|
```
|
|
71
79
|
|
|
80
|
+
Each session shows:
|
|
81
|
+
- Full UUID
|
|
82
|
+
- Message count and file size
|
|
83
|
+
- Time since last activity
|
|
84
|
+
- Start and last activity timestamps
|
|
85
|
+
- First and latest prompts (truncated)
|
|
86
|
+
|
|
87
|
+
## Multi-Terminal Support
|
|
88
|
+
|
|
89
|
+
Each terminal tracks its own session independently:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Terminal pts/0 → Session abc123... (your migration work)
|
|
93
|
+
Terminal pts/1 → Session def456... (your docs work)
|
|
94
|
+
Terminal pts/2 → Session ghi789... (your debugging)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Press `c` to continue YOUR terminal's last session. Other terminals are unaffected.
|
|
98
|
+
|
|
72
99
|
## How It Works
|
|
73
100
|
|
|
74
|
-
The
|
|
101
|
+
The installer creates symlinks from ephemeral locations to persistent workspace storage:
|
|
75
102
|
|
|
76
103
|
```
|
|
77
|
-
~/.claude
|
|
78
|
-
~/.codex
|
|
79
|
-
~/.local/
|
|
104
|
+
~/.claude → /workspace/.claude-persistent/
|
|
105
|
+
~/.codex → /workspace/.codex-persistent/
|
|
106
|
+
~/.local/share/claude → /workspace/.local/share/claude/
|
|
107
|
+
~/.local/bin/claude → /workspace/.local/share/claude/versions/X.X.X
|
|
80
108
|
```
|
|
81
109
|
|
|
82
|
-
|
|
110
|
+
Three layers ensure setup runs on every restart:
|
|
111
|
+
1. `.replit` onBoot hook (runs at container boot)
|
|
112
|
+
2. `.config/bashrc` (runs on every shell start)
|
|
113
|
+
3. Scripts in `workspace/scripts/` (called by above)
|
|
114
|
+
|
|
115
|
+
## Smart Detection
|
|
116
|
+
|
|
117
|
+
The installer checks for:
|
|
118
|
+
|
|
119
|
+
- **`CLAUDE_CONFIG_DIR`** - Respects custom Claude config directory if set in Replit Secrets
|
|
120
|
+
- **Existing persistent config** - Uses your existing `.claude-persistent/` if present
|
|
121
|
+
- **Replit Secrets** - Detects `ANTHROPIC_API_KEY` and `OPENAI_API_KEY`
|
|
122
|
+
- **Existing installations** - Won't reinstall Claude or Codex if already present
|
|
123
|
+
- **Existing data in ~/.claude** - Moves it to persistent storage instead of overwriting
|
|
124
|
+
|
|
125
|
+
### Supported Environment Variables
|
|
126
|
+
|
|
127
|
+
| Variable | Purpose |
|
|
128
|
+
|----------|---------|
|
|
129
|
+
| `CLAUDE_CONFIG_DIR` | Custom directory for Claude config/data (recommended) |
|
|
130
|
+
| `CLAUDE_WORKSPACE_DIR` | Alternative name for config directory |
|
|
131
|
+
| `CLAUDE_DATA_DIR` | Alternative name for config directory |
|
|
132
|
+
| `CLAUDE_HOME` | Alternative name for config directory |
|
|
133
|
+
| `ANTHROPIC_API_KEY` | Claude API authentication |
|
|
134
|
+
| `OPENAI_API_KEY` | Codex API authentication |
|
|
135
|
+
|
|
136
|
+
If you set `CLAUDE_CONFIG_DIR` in your Replit Secrets to a path inside `/home/runner/workspace/`, DATA Tools will use that directory for persistence instead of the default `.claude-persistent/`.
|
|
137
|
+
|
|
138
|
+
## Installation Options
|
|
139
|
+
|
|
140
|
+
### Option 1: npx (recommended)
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx replit-tools
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Option 2: curl
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
curl -fsSL https://raw.githubusercontent.com/stevemoraco/DATAtools/main/install.sh | bash
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Option 3: Global install
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npm install -g replit-tools
|
|
156
|
+
replit-tools
|
|
157
|
+
```
|
|
83
158
|
|
|
84
159
|
## Commands
|
|
85
160
|
|
|
161
|
+
After installation, these aliases are available:
|
|
162
|
+
|
|
86
163
|
| Command | Description |
|
|
87
164
|
|---------|-------------|
|
|
88
|
-
| `cr` | Continue last session |
|
|
89
|
-
| `claude-
|
|
90
|
-
| `claude-
|
|
91
|
-
| `claude-
|
|
165
|
+
| `cr` | Continue last Claude session |
|
|
166
|
+
| `claude-resume` | Same as `cr` |
|
|
167
|
+
| `claude-pick` | Claude's built-in session picker |
|
|
168
|
+
| `claude-menu` | Show the session manager menu again |
|
|
92
169
|
|
|
93
170
|
## Configuration
|
|
94
171
|
|
|
95
|
-
### Disable the menu
|
|
172
|
+
### Disable the session picker menu
|
|
96
173
|
|
|
97
174
|
```bash
|
|
98
175
|
export CLAUDE_NO_PROMPT=true
|
|
@@ -100,32 +177,39 @@ export CLAUDE_NO_PROMPT=true
|
|
|
100
177
|
|
|
101
178
|
Add to `.config/bashrc` to make permanent.
|
|
102
179
|
|
|
103
|
-
### Fix
|
|
180
|
+
### Fix authentication permanently
|
|
104
181
|
|
|
105
182
|
```bash
|
|
106
183
|
claude setup-token
|
|
107
184
|
```
|
|
108
185
|
|
|
109
|
-
Creates a long-lived token that doesn't expire.
|
|
186
|
+
Creates a long-lived API token that doesn't expire (OAuth tokens expire every ~24h).
|
|
110
187
|
|
|
111
188
|
## Files Created
|
|
112
189
|
|
|
113
190
|
```
|
|
114
191
|
workspace/
|
|
115
|
-
├── .claude-persistent/ #
|
|
192
|
+
├── .claude-persistent/ # Claude conversations & credentials
|
|
116
193
|
├── .codex-persistent/ # Codex CLI data
|
|
117
194
|
├── .claude-sessions/ # Per-terminal session tracking
|
|
118
195
|
├── .local/share/claude/ # Claude binary versions
|
|
119
196
|
├── .persistent-home/ # Bash history
|
|
120
197
|
├── .config/bashrc # Shell startup config
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
198
|
+
├── scripts/
|
|
199
|
+
│ ├── setup-claude-code.sh
|
|
200
|
+
│ └── claude-session-manager.sh
|
|
201
|
+
└── .gitignore # Updated to ignore credential dirs
|
|
124
202
|
```
|
|
125
203
|
|
|
126
204
|
## Troubleshooting
|
|
127
205
|
|
|
128
|
-
###
|
|
206
|
+
### Claude or Codex not found after restart
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
source /home/runner/workspace/scripts/setup-claude-code.sh
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Session picker not appearing
|
|
129
213
|
|
|
130
214
|
```bash
|
|
131
215
|
source /home/runner/workspace/.config/bashrc
|
|
@@ -142,9 +226,27 @@ claude setup-token
|
|
|
142
226
|
### Symlinks broken
|
|
143
227
|
|
|
144
228
|
```bash
|
|
145
|
-
|
|
229
|
+
npx replit-tools
|
|
146
230
|
```
|
|
147
231
|
|
|
232
|
+
Running the installer again is safe - it preserves existing data.
|
|
233
|
+
|
|
234
|
+
## Security
|
|
235
|
+
|
|
236
|
+
The installer adds these to `.gitignore`:
|
|
237
|
+
- `.claude-persistent/` (contains credentials)
|
|
238
|
+
- `.codex-persistent/` (contains credentials)
|
|
239
|
+
|
|
240
|
+
Your API keys and conversation history won't be committed to git.
|
|
241
|
+
|
|
242
|
+
## Why "DATA Tools"?
|
|
243
|
+
|
|
244
|
+
**D**eveloper **A**ssistant **T**ool **A**utomation - everything you need to run AI coding assistants on Replit, persisted and ready to go.
|
|
245
|
+
|
|
246
|
+
## Repository
|
|
247
|
+
|
|
248
|
+
GitHub: [stevemoraco/DATAtools](https://github.com/stevemoraco/DATAtools)
|
|
249
|
+
|
|
148
250
|
## License
|
|
149
251
|
|
|
150
252
|
MIT
|
package/index.js
CHANGED
|
@@ -17,7 +17,7 @@ if (!fs.existsSync(WORKSPACE)) {
|
|
|
17
17
|
|
|
18
18
|
console.log('');
|
|
19
19
|
console.log('╭─────────────────────────────────────────────────────────╮');
|
|
20
|
-
console.log('│
|
|
20
|
+
console.log('│ DATA Tools - Claude & Codex Persistence │');
|
|
21
21
|
console.log('╰─────────────────────────────────────────────────────────╯');
|
|
22
22
|
console.log('');
|
|
23
23
|
|
|
@@ -31,33 +31,66 @@ function commandExists(cmd) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Helper to
|
|
35
|
-
function
|
|
36
|
-
return process.env[name]
|
|
34
|
+
// Helper to get Replit secret value
|
|
35
|
+
function getReplitSecret(name) {
|
|
36
|
+
return process.env[name] || null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check for CLAUDE_CONFIG_DIR or similar env vars that specify custom Claude location
|
|
40
|
+
const claudeConfigEnvVars = [
|
|
41
|
+
'CLAUDE_CONFIG_DIR',
|
|
42
|
+
'CLAUDE_WORKSPACE_DIR',
|
|
43
|
+
'CLAUDE_DATA_DIR',
|
|
44
|
+
'CLAUDE_HOME'
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
let customClaudeDir = null;
|
|
48
|
+
for (const envVar of claudeConfigEnvVars) {
|
|
49
|
+
const value = getReplitSecret(envVar);
|
|
50
|
+
if (value) {
|
|
51
|
+
customClaudeDir = value;
|
|
52
|
+
console.log(`✅ Found ${envVar} = ${value}`);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Determine Claude persistent directory
|
|
58
|
+
// Priority: 1) CLAUDE_CONFIG_DIR from env, 2) existing .claude-persistent, 3) default
|
|
59
|
+
let claudePersistentDir = path.join(WORKSPACE, '.claude-persistent');
|
|
60
|
+
|
|
61
|
+
if (customClaudeDir) {
|
|
62
|
+
// User has specified a custom directory via env var
|
|
63
|
+
if (customClaudeDir.startsWith(WORKSPACE)) {
|
|
64
|
+
// It's already in workspace - use it directly
|
|
65
|
+
claudePersistentDir = customClaudeDir;
|
|
66
|
+
console.log(` Using custom Claude directory: ${claudePersistentDir}`);
|
|
67
|
+
} else {
|
|
68
|
+
// It's outside workspace - we'll symlink to it but also ensure persistence
|
|
69
|
+
console.log(` Custom dir outside workspace - will set up persistence`);
|
|
70
|
+
}
|
|
37
71
|
}
|
|
38
72
|
|
|
39
73
|
// Check for existing persistent config
|
|
40
|
-
const existingClaudeConfig = fs.existsSync(
|
|
74
|
+
const existingClaudeConfig = fs.existsSync(claudePersistentDir);
|
|
41
75
|
const existingCodexConfig = fs.existsSync(path.join(WORKSPACE, '.codex-persistent'));
|
|
42
76
|
|
|
43
77
|
if (existingClaudeConfig) {
|
|
44
|
-
console.log(
|
|
78
|
+
console.log(`✅ Found existing Claude config at ${claudePersistentDir}`);
|
|
45
79
|
}
|
|
46
80
|
if (existingCodexConfig) {
|
|
47
81
|
console.log('✅ Found existing Codex config in workspace');
|
|
48
82
|
}
|
|
49
83
|
|
|
50
|
-
// Check for
|
|
51
|
-
if (
|
|
84
|
+
// Check for API key secrets
|
|
85
|
+
if (getReplitSecret('ANTHROPIC_API_KEY')) {
|
|
52
86
|
console.log('✅ Found ANTHROPIC_API_KEY in Replit secrets');
|
|
53
87
|
}
|
|
54
|
-
if (
|
|
88
|
+
if (getReplitSecret('OPENAI_API_KEY')) {
|
|
55
89
|
console.log('✅ Found OPENAI_API_KEY in Replit secrets');
|
|
56
90
|
}
|
|
57
91
|
|
|
58
92
|
// Create directories (preserving existing data)
|
|
59
93
|
const dirs = [
|
|
60
|
-
'.claude-persistent',
|
|
61
94
|
'.codex-persistent',
|
|
62
95
|
'.claude-sessions',
|
|
63
96
|
'.local/share/claude/versions',
|
|
@@ -67,6 +100,14 @@ const dirs = [
|
|
|
67
100
|
'logs'
|
|
68
101
|
];
|
|
69
102
|
|
|
103
|
+
// Add Claude persistent dir if it's relative to workspace
|
|
104
|
+
if (claudePersistentDir.startsWith(WORKSPACE)) {
|
|
105
|
+
const relativePath = claudePersistentDir.replace(WORKSPACE + '/', '');
|
|
106
|
+
if (!dirs.includes(relativePath)) {
|
|
107
|
+
dirs.unshift(relativePath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
70
111
|
console.log('');
|
|
71
112
|
console.log('📁 Creating directories...');
|
|
72
113
|
dirs.forEach(dir => {
|
|
@@ -84,15 +125,19 @@ const claudeInstalled = commandExists('claude') ||
|
|
|
84
125
|
|
|
85
126
|
let claudeVersions = [];
|
|
86
127
|
try {
|
|
87
|
-
claudeVersions = fs.readdirSync(path.join(WORKSPACE, '.local/share/claude/versions'))
|
|
128
|
+
claudeVersions = fs.readdirSync(path.join(WORKSPACE, '.local/share/claude/versions'))
|
|
129
|
+
.filter(f => !f.startsWith('.'));
|
|
88
130
|
} catch {}
|
|
89
131
|
|
|
90
132
|
if (!claudeInstalled || claudeVersions.length === 0) {
|
|
91
133
|
console.log('📦 Installing Claude Code...');
|
|
92
134
|
try {
|
|
135
|
+
// Set CLAUDE_CONFIG_DIR before install so it installs to the right place
|
|
136
|
+
const installEnv = { ...process.env, CLAUDE_CONFIG_DIR: claudePersistentDir };
|
|
93
137
|
execSync('curl -fsSL https://claude.ai/install.sh | bash', {
|
|
94
138
|
stdio: 'inherit',
|
|
95
|
-
shell: '/bin/bash'
|
|
139
|
+
shell: '/bin/bash',
|
|
140
|
+
env: installEnv
|
|
96
141
|
});
|
|
97
142
|
console.log('✅ Claude Code installed');
|
|
98
143
|
} catch (err) {
|
|
@@ -125,29 +170,30 @@ if (!codexInstalled) {
|
|
|
125
170
|
console.log('');
|
|
126
171
|
console.log('🔗 Setting up symlinks...');
|
|
127
172
|
|
|
128
|
-
// Claude symlink
|
|
129
|
-
const claudeTarget = path.join(WORKSPACE, '.claude-persistent');
|
|
173
|
+
// Claude symlink - only if we're using default location
|
|
130
174
|
const claudeLink = path.join(HOME, '.claude');
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
175
|
+
if (!customClaudeDir || customClaudeDir.startsWith(WORKSPACE)) {
|
|
176
|
+
try {
|
|
177
|
+
const stat = fs.lstatSync(claudeLink);
|
|
178
|
+
if (stat.isSymbolicLink()) {
|
|
179
|
+
const current = fs.readlinkSync(claudeLink);
|
|
180
|
+
if (current !== claudePersistentDir) {
|
|
181
|
+
fs.unlinkSync(claudeLink);
|
|
182
|
+
fs.symlinkSync(claudePersistentDir, claudeLink);
|
|
183
|
+
}
|
|
184
|
+
} else if (stat.isDirectory()) {
|
|
185
|
+
// Move existing data to persistent location
|
|
186
|
+
console.log(' Moving existing ~/.claude data to persistent storage...');
|
|
187
|
+
execSync(`cp -rn ${claudeLink}/* ${claudePersistentDir}/ 2>/dev/null || true`, { shell: '/bin/bash' });
|
|
188
|
+
execSync(`rm -rf ${claudeLink}`, { shell: '/bin/bash' });
|
|
189
|
+
fs.symlinkSync(claudePersistentDir, claudeLink);
|
|
138
190
|
}
|
|
139
|
-
}
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
execSync(`cp -rn ${claudeLink}/* ${claudeTarget}/ 2>/dev/null || true`, { shell: '/bin/bash' });
|
|
143
|
-
execSync(`rm -rf ${claudeLink}`, { shell: '/bin/bash' });
|
|
144
|
-
fs.symlinkSync(claudeTarget, claudeLink);
|
|
191
|
+
} catch {
|
|
192
|
+
// Doesn't exist, create it
|
|
193
|
+
fs.symlinkSync(claudePersistentDir, claudeLink);
|
|
145
194
|
}
|
|
146
|
-
|
|
147
|
-
// Doesn't exist, create it
|
|
148
|
-
fs.symlinkSync(claudeTarget, claudeLink);
|
|
195
|
+
console.log(` ~/.claude → ${claudePersistentDir.replace(WORKSPACE + '/', '')}/`);
|
|
149
196
|
}
|
|
150
|
-
console.log(' ~/.claude → .claude-persistent/');
|
|
151
197
|
|
|
152
198
|
// Codex symlink
|
|
153
199
|
const codexTarget = path.join(WORKSPACE, '.codex-persistent');
|
|
@@ -198,7 +244,9 @@ console.log(' ~/.local/share/claude → .local/share/claude/');
|
|
|
198
244
|
|
|
199
245
|
// Link binary to latest version
|
|
200
246
|
try {
|
|
201
|
-
const versions = fs.readdirSync(path.join(WORKSPACE, '.local/share/claude/versions'))
|
|
247
|
+
const versions = fs.readdirSync(path.join(WORKSPACE, '.local/share/claude/versions'))
|
|
248
|
+
.filter(f => !f.startsWith('.'))
|
|
249
|
+
.sort();
|
|
202
250
|
if (versions.length > 0) {
|
|
203
251
|
const latest = versions[versions.length - 1];
|
|
204
252
|
const binaryPath = path.join(WORKSPACE, '.local/share/claude/versions', latest);
|
|
@@ -228,11 +276,15 @@ scripts.forEach(script => {
|
|
|
228
276
|
}
|
|
229
277
|
});
|
|
230
278
|
|
|
231
|
-
// Create/update .config/bashrc
|
|
279
|
+
// Create/update .config/bashrc with CLAUDE_CONFIG_DIR export
|
|
232
280
|
console.log('');
|
|
233
281
|
console.log('📝 Creating .config/bashrc...');
|
|
234
282
|
const bashrcContent = `#!/bin/bash
|
|
235
|
-
# Replit Claude
|
|
283
|
+
# DATA Tools - Replit Claude & Codex Persistence
|
|
284
|
+
# Auto-generated bashrc
|
|
285
|
+
|
|
286
|
+
# Claude Config Directory (tells Claude where to store data)
|
|
287
|
+
export CLAUDE_CONFIG_DIR="${claudePersistentDir}"
|
|
236
288
|
|
|
237
289
|
# Claude Code Setup
|
|
238
290
|
SETUP_SCRIPT="/home/runner/workspace/scripts/setup-claude-code.sh"
|
|
@@ -272,17 +324,17 @@ const onBootLine = 'onBoot = "source /home/runner/workspace/scripts/setup-claude
|
|
|
272
324
|
if (fs.existsSync(replitPath)) {
|
|
273
325
|
let content = fs.readFileSync(replitPath, 'utf8');
|
|
274
326
|
if (!content.includes('setup-claude-code.sh')) {
|
|
275
|
-
content += '\n\n# Claude persistence (added by
|
|
327
|
+
content += '\n\n# Claude persistence (added by DATA Tools)\n' + onBootLine + '\n';
|
|
276
328
|
fs.writeFileSync(replitPath, content);
|
|
277
329
|
}
|
|
278
330
|
} else {
|
|
279
|
-
fs.writeFileSync(replitPath, '# Claude persistence\n' + onBootLine + '\n');
|
|
331
|
+
fs.writeFileSync(replitPath, '# Claude persistence (DATA Tools)\n' + onBootLine + '\n');
|
|
280
332
|
}
|
|
281
333
|
|
|
282
334
|
// Update .gitignore (only essential sensitive dirs)
|
|
283
335
|
console.log('📝 Updating .gitignore...');
|
|
284
336
|
const gitignorePath = path.join(WORKSPACE, '.gitignore');
|
|
285
|
-
const gitignoreEntries = '\n# Claude/Codex credentials (added by
|
|
337
|
+
const gitignoreEntries = '\n# Claude/Codex credentials (added by DATA Tools)\n.claude-persistent/\n.codex-persistent/\n';
|
|
286
338
|
|
|
287
339
|
if (fs.existsSync(gitignorePath)) {
|
|
288
340
|
let content = fs.readFileSync(gitignorePath, 'utf8');
|
|
@@ -293,8 +345,9 @@ if (fs.existsSync(gitignorePath)) {
|
|
|
293
345
|
fs.writeFileSync(gitignorePath, gitignoreEntries.trim() + '\n');
|
|
294
346
|
}
|
|
295
347
|
|
|
296
|
-
// Add PATH to current process
|
|
348
|
+
// Add PATH and CLAUDE_CONFIG_DIR to current process
|
|
297
349
|
process.env.PATH = `${localBin}:${process.env.PATH}`;
|
|
350
|
+
process.env.CLAUDE_CONFIG_DIR = claudePersistentDir;
|
|
298
351
|
|
|
299
352
|
console.log('');
|
|
300
353
|
console.log('╭─────────────────────────────────────────────────────────╮');
|
|
@@ -302,18 +355,23 @@ console.log('│ ✅ Installation complete! │');
|
|
|
302
355
|
console.log('╰─────────────────────────────────────────────────────────╯');
|
|
303
356
|
console.log('');
|
|
304
357
|
console.log('Your conversations and credentials now persist across restarts.');
|
|
358
|
+
console.log(`Claude config directory: ${claudePersistentDir}`);
|
|
305
359
|
console.log('');
|
|
306
360
|
|
|
307
361
|
// Check if Claude needs login
|
|
308
362
|
let needsLogin = true;
|
|
309
363
|
try {
|
|
310
|
-
const authCheck = execSync('claude auth status 2>&1 || true', {
|
|
364
|
+
const authCheck = execSync('claude auth status 2>&1 || true', {
|
|
365
|
+
encoding: 'utf8',
|
|
366
|
+
shell: '/bin/bash',
|
|
367
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: claudePersistentDir }
|
|
368
|
+
});
|
|
311
369
|
if (authCheck.includes('Logged in') || authCheck.includes('valid')) {
|
|
312
370
|
needsLogin = false;
|
|
313
371
|
}
|
|
314
372
|
} catch {}
|
|
315
373
|
|
|
316
|
-
if (needsLogin && !
|
|
374
|
+
if (needsLogin && !getReplitSecret('ANTHROPIC_API_KEY')) {
|
|
317
375
|
console.log('⚠️ Claude needs authentication. Run: claude login');
|
|
318
376
|
console.log('');
|
|
319
377
|
}
|
|
@@ -325,7 +383,8 @@ console.log('');
|
|
|
325
383
|
// Use spawn to run bash interactively with our session manager
|
|
326
384
|
const sessionManager = spawn('bash', ['--rcfile', path.join(WORKSPACE, '.config/bashrc'), '-i'], {
|
|
327
385
|
stdio: 'inherit',
|
|
328
|
-
cwd: WORKSPACE
|
|
386
|
+
cwd: WORKSPACE,
|
|
387
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: claudePersistentDir }
|
|
329
388
|
});
|
|
330
389
|
|
|
331
390
|
sessionManager.on('exit', (code) => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replit-tools",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.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": {
|
|
7
7
|
"replit-tools": "./index.js"
|