replit-tools 1.2.39 → 1.2.41
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
|
@@ -301,16 +301,25 @@ get_terminal_last_session() {
|
|
|
301
301
|
fi
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
# Recent sessions within
|
|
304
|
+
# Recent sessions within configured window (max 9). Prints "NUM|TOOL|ID|AGO|SNIPPET" per line.
|
|
305
|
+
# Window read from ${REPLIT_TOOLS}/config.json: recentWindowHours (default 48)
|
|
305
306
|
get_recent_24h_sessions() {
|
|
306
307
|
local history="${HOME}/.claude/history.jsonl"
|
|
307
308
|
local projects_dir="${HOME}/.claude/projects/-home-runner-workspace"
|
|
308
309
|
local codex_sessions_dir="${HOME}/.codex/sessions"
|
|
310
|
+
local config_path="${REPLIT_TOOLS}/config.json"
|
|
309
311
|
|
|
310
312
|
node -e "
|
|
311
313
|
const fs = require('fs');
|
|
312
314
|
const path = require('path');
|
|
313
|
-
|
|
315
|
+
let hours = 48;
|
|
316
|
+
try {
|
|
317
|
+
if (fs.existsSync('${config_path}')) {
|
|
318
|
+
const cfg = JSON.parse(fs.readFileSync('${config_path}', 'utf8'));
|
|
319
|
+
if (typeof cfg.recentWindowHours === 'number' && cfg.recentWindowHours > 0) hours = cfg.recentWindowHours;
|
|
320
|
+
}
|
|
321
|
+
} catch(e) {}
|
|
322
|
+
const cutoff = Date.now() - hours*60*60*1000;
|
|
314
323
|
const cwd = '/home/runner/workspace';
|
|
315
324
|
const sessions = new Map();
|
|
316
325
|
|
|
@@ -563,8 +572,25 @@ claude_prompt() {
|
|
|
563
572
|
local recent_tools=()
|
|
564
573
|
local recent_ids=()
|
|
565
574
|
if [ -n "$recent_24h" ]; then
|
|
575
|
+
# Read configured window for label
|
|
576
|
+
local window_hours=48
|
|
577
|
+
if [ -f "${REPLIT_TOOLS}/config.json" ] && command -v node &>/dev/null; then
|
|
578
|
+
window_hours=$(node -e "try{const c=require('${REPLIT_TOOLS}/config.json');console.log(c.recentWindowHours||48)}catch(e){console.log(48)}" 2>/dev/null)
|
|
579
|
+
fi
|
|
580
|
+
local window_label
|
|
581
|
+
if [ "$window_hours" -ge 8760 ]; then
|
|
582
|
+
window_label="$((window_hours / 8760))y"
|
|
583
|
+
elif [ "$window_hours" -ge 720 ]; then
|
|
584
|
+
window_label="$((window_hours / 720))mo"
|
|
585
|
+
elif [ "$window_hours" -ge 168 ]; then
|
|
586
|
+
window_label="$((window_hours / 168))w"
|
|
587
|
+
elif [ "$window_hours" -ge 24 ]; then
|
|
588
|
+
window_label="$((window_hours / 24))d"
|
|
589
|
+
else
|
|
590
|
+
window_label="${window_hours}h"
|
|
591
|
+
fi
|
|
566
592
|
echo ""
|
|
567
|
-
echo -e " \033[1mRecent (last
|
|
593
|
+
echo -e " \033[1mRecent (last $window_label):\033[0m"
|
|
568
594
|
while IFS='|' read -r num tool id when snippet; do
|
|
569
595
|
[ -z "$num" ] && continue
|
|
570
596
|
recent_tools[$num]="$tool"
|
|
@@ -39,7 +39,7 @@ LOCAL_SHARE_CLAUDE="${HOME}/.local/share/claude"
|
|
|
39
39
|
|
|
40
40
|
# Version file
|
|
41
41
|
VERSION_FILE="${REPLIT_TOOLS}/.version"
|
|
42
|
-
PACKAGE_NAME="
|
|
42
|
+
PACKAGE_NAME="data-remote"
|
|
43
43
|
|
|
44
44
|
# Logging helper
|
|
45
45
|
log() {
|
|
@@ -170,6 +170,128 @@ for f in "${SSH_PERSISTENT}"/*; do
|
|
|
170
170
|
esac
|
|
171
171
|
done
|
|
172
172
|
|
|
173
|
+
# =============================================================================
|
|
174
|
+
# Step 2.6: Apply user-config persistence + sync append-only mirror archive
|
|
175
|
+
# =============================================================================
|
|
176
|
+
# Config at ${REPLIT_TOOLS}/config.json:
|
|
177
|
+
# {
|
|
178
|
+
# "recentWindowHours": 48, // recent sessions list window
|
|
179
|
+
# "persistenceDays": 365250, // Claude cleanupPeriodDays + Codex history bytes
|
|
180
|
+
# "mirror": { "enabled": true } // append-only backup mirror of sessions
|
|
181
|
+
# }
|
|
182
|
+
# The mirror is at ${REPLIT_TOOLS}/.session-archive/ — append-only: files only grow,
|
|
183
|
+
# never shrink. If Claude/Codex deletes a session, the mirror still has it.
|
|
184
|
+
if command -v node &>/dev/null; then
|
|
185
|
+
PERSIST_OUTPUT=$(REPLIT_TOOLS_DIR="${REPLIT_TOOLS}" CLAUDE_PERSISTENT_DIR="${CLAUDE_PERSISTENT}" CODEX_PERSISTENT_DIR="${CODEX_PERSISTENT}" node -e '
|
|
186
|
+
const fs = require("fs");
|
|
187
|
+
const path = require("path");
|
|
188
|
+
|
|
189
|
+
// Load config with defaults
|
|
190
|
+
const configPath = process.env.REPLIT_TOOLS_DIR + "/config.json";
|
|
191
|
+
const defaults = { recentWindowHours: 48, persistenceDays: 365250, mirror: { enabled: true } };
|
|
192
|
+
let config = defaults;
|
|
193
|
+
try {
|
|
194
|
+
if (fs.existsSync(configPath)) {
|
|
195
|
+
const loaded = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
196
|
+
config = { ...defaults, ...loaded, mirror: { ...defaults.mirror, ...(loaded.mirror || {}) } };
|
|
197
|
+
} else {
|
|
198
|
+
fs.writeFileSync(configPath, JSON.stringify(defaults, null, 2) + "\n");
|
|
199
|
+
console.log("Created config at " + configPath);
|
|
200
|
+
}
|
|
201
|
+
} catch(e) { config = defaults; }
|
|
202
|
+
|
|
203
|
+
const persistDays = Math.max(1, parseInt(config.persistenceDays, 10) || 365250);
|
|
204
|
+
// Claude needs days; Codex max_bytes scales with days (rough: 1 MiB per day, min 100 MiB)
|
|
205
|
+
const codexMaxBytes = Math.max(104857600, persistDays * 1048576);
|
|
206
|
+
|
|
207
|
+
// --- Claude settings.json ---
|
|
208
|
+
const claudeSettingsPath = process.env.CLAUDE_PERSISTENT_DIR + "/settings.json";
|
|
209
|
+
try {
|
|
210
|
+
let s = {};
|
|
211
|
+
if (fs.existsSync(claudeSettingsPath)) {
|
|
212
|
+
try { s = JSON.parse(fs.readFileSync(claudeSettingsPath, "utf8")); } catch(e) { s = {}; }
|
|
213
|
+
}
|
|
214
|
+
if (s.cleanupPeriodDays !== persistDays) {
|
|
215
|
+
s.cleanupPeriodDays = persistDays;
|
|
216
|
+
fs.writeFileSync(claudeSettingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
217
|
+
console.log("Claude cleanupPeriodDays = " + persistDays);
|
|
218
|
+
}
|
|
219
|
+
} catch(e) { console.error("Could not update Claude settings: " + e.message); }
|
|
220
|
+
|
|
221
|
+
// --- Codex config.toml ---
|
|
222
|
+
const codexConfigPath = process.env.CODEX_PERSISTENT_DIR + "/config.toml";
|
|
223
|
+
try {
|
|
224
|
+
let c = "";
|
|
225
|
+
if (fs.existsSync(codexConfigPath)) c = fs.readFileSync(codexConfigPath, "utf8");
|
|
226
|
+
const desired = String(codexMaxBytes);
|
|
227
|
+
let updated = false;
|
|
228
|
+
if (!/\[history\]/.test(c)) {
|
|
229
|
+
c = (c.trimEnd() + "\n\n[history]\nmax_bytes = " + desired + "\n").trimStart();
|
|
230
|
+
updated = true;
|
|
231
|
+
} else if (/max_bytes\s*=\s*(\d+)/.test(c)) {
|
|
232
|
+
const cur = c.match(/max_bytes\s*=\s*(\d+)/)[1];
|
|
233
|
+
if (cur !== desired) {
|
|
234
|
+
c = c.replace(/(\[history\][\s\S]*?max_bytes\s*=\s*)\d+/, "$1" + desired);
|
|
235
|
+
updated = true;
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
c = c.replace(/\[history\](\s*)/, "[history]$1max_bytes = " + desired + "\n");
|
|
239
|
+
updated = true;
|
|
240
|
+
}
|
|
241
|
+
if (updated) {
|
|
242
|
+
fs.writeFileSync(codexConfigPath, c);
|
|
243
|
+
console.log("Codex history.max_bytes = " + desired);
|
|
244
|
+
}
|
|
245
|
+
} catch(e) { console.error("Could not update Codex config: " + e.message); }
|
|
246
|
+
|
|
247
|
+
// --- Append-only mirror sync ---
|
|
248
|
+
if (config.mirror && config.mirror.enabled) {
|
|
249
|
+
const mirrorBase = process.env.REPLIT_TOOLS_DIR + "/.session-archive";
|
|
250
|
+
const syncTree = (srcDir, mirrorDir) => {
|
|
251
|
+
if (!fs.existsSync(srcDir)) return { copied: 0, grew: 0 };
|
|
252
|
+
let copied = 0, grew = 0;
|
|
253
|
+
const walk = (rel) => {
|
|
254
|
+
const srcPath = rel ? path.join(srcDir, rel) : srcDir;
|
|
255
|
+
const mirrorPath = rel ? path.join(mirrorDir, rel) : mirrorDir;
|
|
256
|
+
let stat;
|
|
257
|
+
try { stat = fs.statSync(srcPath); } catch(e) { return; }
|
|
258
|
+
if (stat.isDirectory()) {
|
|
259
|
+
try { fs.mkdirSync(mirrorPath, { recursive: true }); } catch(e){}
|
|
260
|
+
let entries = [];
|
|
261
|
+
try { entries = fs.readdirSync(srcPath); } catch(e) { return; }
|
|
262
|
+
for (const e of entries) walk(rel ? path.join(rel, e) : e);
|
|
263
|
+
} else if (stat.isFile()) {
|
|
264
|
+
let mirrorSize = 0;
|
|
265
|
+
if (fs.existsSync(mirrorPath)) mirrorSize = fs.statSync(mirrorPath).size;
|
|
266
|
+
if (stat.size > mirrorSize) {
|
|
267
|
+
try {
|
|
268
|
+
fs.mkdirSync(path.dirname(mirrorPath), { recursive: true });
|
|
269
|
+
fs.copyFileSync(srcPath, mirrorPath);
|
|
270
|
+
if (mirrorSize === 0) copied++; else grew++;
|
|
271
|
+
} catch(e){}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
walk("");
|
|
276
|
+
return { copied, grew };
|
|
277
|
+
};
|
|
278
|
+
try {
|
|
279
|
+
fs.mkdirSync(mirrorBase, { recursive: true });
|
|
280
|
+
const c1 = syncTree(process.env.CLAUDE_PERSISTENT_DIR + "/projects", mirrorBase + "/claude/projects");
|
|
281
|
+
const c2 = syncTree(process.env.CLAUDE_PERSISTENT_DIR + "/history.jsonl", mirrorBase + "/claude/history.jsonl");
|
|
282
|
+
const c3 = syncTree(process.env.CODEX_PERSISTENT_DIR + "/sessions", mirrorBase + "/codex/sessions");
|
|
283
|
+
const c4 = syncTree(process.env.CODEX_PERSISTENT_DIR + "/history.jsonl", mirrorBase + "/codex/history.jsonl");
|
|
284
|
+
const total = c1.copied + c2.copied + c3.copied + c4.copied;
|
|
285
|
+
const grew = c1.grew + c2.grew + c3.grew + c4.grew;
|
|
286
|
+
if (total > 0 || grew > 0) console.log("Archive mirror: +" + total + " new, " + grew + " updated");
|
|
287
|
+
} catch(e) { console.error("Mirror sync failed: " + e.message); }
|
|
288
|
+
}
|
|
289
|
+
' 2>&1)
|
|
290
|
+
if [ -n "${PERSIST_OUTPUT}" ]; then
|
|
291
|
+
while IFS= read -r line; do log "✅ ${line}"; done <<< "${PERSIST_OUTPUT}"
|
|
292
|
+
fi
|
|
293
|
+
fi
|
|
294
|
+
|
|
173
295
|
# =============================================================================
|
|
174
296
|
# Step 3: Create ~/.local/share/claude symlink for installed versions
|
|
175
297
|
# =============================================================================
|