replit-tools 1.2.40 → 1.2.42
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() {
|
|
@@ -171,54 +171,130 @@ for f in "${SSH_PERSISTENT}"/*; do
|
|
|
171
171
|
done
|
|
172
172
|
|
|
173
173
|
# =============================================================================
|
|
174
|
-
# Step 2.6:
|
|
174
|
+
# Step 2.6: Apply user-config persistence + sync append-only mirror archive
|
|
175
175
|
# =============================================================================
|
|
176
|
-
#
|
|
177
|
-
#
|
|
178
|
-
#
|
|
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.
|
|
179
184
|
if command -v node &>/dev/null; then
|
|
180
|
-
PERSIST_OUTPUT=$(CLAUDE_PERSISTENT_DIR="${CLAUDE_PERSISTENT}" CODEX_PERSISTENT_DIR="${CODEX_PERSISTENT}" node -e '
|
|
185
|
+
PERSIST_OUTPUT=$(REPLIT_TOOLS_DIR="${REPLIT_TOOLS}" CLAUDE_PERSISTENT_DIR="${CLAUDE_PERSISTENT}" CODEX_PERSISTENT_DIR="${CODEX_PERSISTENT}" node -e '
|
|
181
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 ---
|
|
182
208
|
const claudeSettingsPath = process.env.CLAUDE_PERSISTENT_DIR + "/settings.json";
|
|
183
209
|
try {
|
|
184
210
|
let s = {};
|
|
185
211
|
if (fs.existsSync(claudeSettingsPath)) {
|
|
186
212
|
try { s = JSON.parse(fs.readFileSync(claudeSettingsPath, "utf8")); } catch(e) { s = {}; }
|
|
187
213
|
}
|
|
188
|
-
if (s.cleanupPeriodDays !==
|
|
189
|
-
s.cleanupPeriodDays =
|
|
214
|
+
if (s.cleanupPeriodDays !== persistDays) {
|
|
215
|
+
s.cleanupPeriodDays = persistDays;
|
|
190
216
|
fs.writeFileSync(claudeSettingsPath, JSON.stringify(s, null, 2) + "\n");
|
|
191
|
-
console.log("Claude cleanupPeriodDays
|
|
217
|
+
console.log("Claude cleanupPeriodDays = " + persistDays);
|
|
192
218
|
}
|
|
193
219
|
} catch(e) { console.error("Could not update Claude settings: " + e.message); }
|
|
194
220
|
|
|
221
|
+
// --- Codex config.toml ---
|
|
195
222
|
const codexConfigPath = process.env.CODEX_PERSISTENT_DIR + "/config.toml";
|
|
196
223
|
try {
|
|
197
224
|
let c = "";
|
|
198
225
|
if (fs.existsSync(codexConfigPath)) c = fs.readFileSync(codexConfigPath, "utf8");
|
|
199
|
-
const desired =
|
|
200
|
-
const hasHistory = /\[history\]/.test(c);
|
|
226
|
+
const desired = String(codexMaxBytes);
|
|
201
227
|
let updated = false;
|
|
202
|
-
|
|
203
|
-
|
|
228
|
+
// Codex requires persistence field when [history] section is present
|
|
229
|
+
if (!/\[history\]/.test(c)) {
|
|
230
|
+
c = (c.trimEnd() + "\n\n[history]\npersistence = \"save-all\"\nmax_bytes = " + desired + "\n").trimStart();
|
|
204
231
|
updated = true;
|
|
205
232
|
} else {
|
|
206
|
-
|
|
207
|
-
if (
|
|
208
|
-
|
|
233
|
+
// Ensure persistence field exists
|
|
234
|
+
if (!/(\[history\][\s\S]*?)persistence\s*=/.test(c)) {
|
|
235
|
+
c = c.replace(/\[history\](\s*)/, "[history]$1persistence = \"save-all\"\n");
|
|
236
|
+
updated = true;
|
|
237
|
+
}
|
|
238
|
+
// Ensure max_bytes is set correctly
|
|
239
|
+
if (/max_bytes\s*=\s*(\d+)/.test(c)) {
|
|
240
|
+
const cur = c.match(/max_bytes\s*=\s*(\d+)/)[1];
|
|
241
|
+
if (cur !== desired) {
|
|
209
242
|
c = c.replace(/(\[history\][\s\S]*?max_bytes\s*=\s*)\d+/, "$1" + desired);
|
|
210
243
|
updated = true;
|
|
211
244
|
}
|
|
212
245
|
} else {
|
|
213
|
-
c = c.replace(
|
|
246
|
+
c = c.replace(/(\[history\][\s\S]*?persistence\s*=\s*"[^"]*"\s*\n)/, "$1max_bytes = " + desired + "\n");
|
|
214
247
|
updated = true;
|
|
215
248
|
}
|
|
216
249
|
}
|
|
217
250
|
if (updated) {
|
|
218
251
|
fs.writeFileSync(codexConfigPath, c);
|
|
219
|
-
console.log("Codex history.max_bytes
|
|
252
|
+
console.log("Codex history.max_bytes = " + desired);
|
|
220
253
|
}
|
|
221
254
|
} catch(e) { console.error("Could not update Codex config: " + e.message); }
|
|
255
|
+
|
|
256
|
+
// --- Append-only mirror sync ---
|
|
257
|
+
if (config.mirror && config.mirror.enabled) {
|
|
258
|
+
const mirrorBase = process.env.REPLIT_TOOLS_DIR + "/.session-archive";
|
|
259
|
+
const syncTree = (srcDir, mirrorDir) => {
|
|
260
|
+
if (!fs.existsSync(srcDir)) return { copied: 0, grew: 0 };
|
|
261
|
+
let copied = 0, grew = 0;
|
|
262
|
+
const walk = (rel) => {
|
|
263
|
+
const srcPath = rel ? path.join(srcDir, rel) : srcDir;
|
|
264
|
+
const mirrorPath = rel ? path.join(mirrorDir, rel) : mirrorDir;
|
|
265
|
+
let stat;
|
|
266
|
+
try { stat = fs.statSync(srcPath); } catch(e) { return; }
|
|
267
|
+
if (stat.isDirectory()) {
|
|
268
|
+
try { fs.mkdirSync(mirrorPath, { recursive: true }); } catch(e){}
|
|
269
|
+
let entries = [];
|
|
270
|
+
try { entries = fs.readdirSync(srcPath); } catch(e) { return; }
|
|
271
|
+
for (const e of entries) walk(rel ? path.join(rel, e) : e);
|
|
272
|
+
} else if (stat.isFile()) {
|
|
273
|
+
let mirrorSize = 0;
|
|
274
|
+
if (fs.existsSync(mirrorPath)) mirrorSize = fs.statSync(mirrorPath).size;
|
|
275
|
+
if (stat.size > mirrorSize) {
|
|
276
|
+
try {
|
|
277
|
+
fs.mkdirSync(path.dirname(mirrorPath), { recursive: true });
|
|
278
|
+
fs.copyFileSync(srcPath, mirrorPath);
|
|
279
|
+
if (mirrorSize === 0) copied++; else grew++;
|
|
280
|
+
} catch(e){}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
walk("");
|
|
285
|
+
return { copied, grew };
|
|
286
|
+
};
|
|
287
|
+
try {
|
|
288
|
+
fs.mkdirSync(mirrorBase, { recursive: true });
|
|
289
|
+
const c1 = syncTree(process.env.CLAUDE_PERSISTENT_DIR + "/projects", mirrorBase + "/claude/projects");
|
|
290
|
+
const c2 = syncTree(process.env.CLAUDE_PERSISTENT_DIR + "/history.jsonl", mirrorBase + "/claude/history.jsonl");
|
|
291
|
+
const c3 = syncTree(process.env.CODEX_PERSISTENT_DIR + "/sessions", mirrorBase + "/codex/sessions");
|
|
292
|
+
const c4 = syncTree(process.env.CODEX_PERSISTENT_DIR + "/history.jsonl", mirrorBase + "/codex/history.jsonl");
|
|
293
|
+
const total = c1.copied + c2.copied + c3.copied + c4.copied;
|
|
294
|
+
const grew = c1.grew + c2.grew + c3.grew + c4.grew;
|
|
295
|
+
if (total > 0 || grew > 0) console.log("Archive mirror: +" + total + " new, " + grew + " updated");
|
|
296
|
+
} catch(e) { console.error("Mirror sync failed: " + e.message); }
|
|
297
|
+
}
|
|
222
298
|
' 2>&1)
|
|
223
299
|
if [ -n "${PERSIST_OUTPUT}" ]; then
|
|
224
300
|
while IFS= read -r line; do log "✅ ${line}"; done <<< "${PERSIST_OUTPUT}"
|