replit-tools 1.2.36 → 1.2.38

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replit-tools",
3
- "version": "1.2.36",
3
+ "version": "1.2.38",
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": {
@@ -42,39 +42,52 @@ get_recent_sessions() {
42
42
 
43
43
  const sessionData = new Map();
44
44
 
45
+ const isRealPrompt = (txt) => {
46
+ if (!txt) return false;
47
+ const t = txt.trim();
48
+ if (!t) return false;
49
+ if (/^[✅❌📦🔗⚠️🚀🎉🔧📝]/.test(t)) return false;
50
+ if (/Claude (history|binary|versions) symlink/.test(t)) return false;
51
+ if (t.startsWith('# AGENTS.md')) return false;
52
+ return true;
53
+ };
54
+
45
55
  // --- Claude sessions ---
46
56
  if (fs.existsSync(historyFile)) {
47
57
  const lines = fs.readFileSync(historyFile, 'utf8').trim().split('\n');
58
+ const entries = [];
48
59
  for (const line of lines) {
49
60
  try {
50
61
  const j = JSON.parse(line);
51
- if (!j.sessionId) continue;
52
- const key = 'claude:' + j.sessionId;
53
- if (!sessionData.has(key)) {
54
- sessionData.set(key, {
55
- tool: 'claude',
56
- id: j.sessionId,
57
- firstSeen: j.timestamp,
58
- lastSeen: j.timestamp,
59
- firstPrompt: j.display || '',
60
- lastPrompt: j.display || '',
61
- messageCount: 0
62
- });
63
- }
64
- const data = sessionData.get(key);
65
- if (j.timestamp < data.firstSeen) {
66
- data.firstSeen = j.timestamp;
67
- data.firstPrompt = j.display || data.firstPrompt;
68
- }
69
- if (j.timestamp > data.lastSeen) {
70
- data.lastSeen = j.timestamp;
71
- data.lastPrompt = j.display || data.lastPrompt;
72
- }
62
+ if (j.sessionId && j.timestamp) entries.push(j);
73
63
  } catch(e) {}
74
64
  }
65
+ entries.sort((a, b) => a.timestamp - b.timestamp);
66
+ for (const j of entries) {
67
+ const key = 'claude:' + j.sessionId;
68
+ if (!sessionData.has(key)) {
69
+ sessionData.set(key, {
70
+ tool: 'claude',
71
+ id: j.sessionId,
72
+ firstSeen: j.timestamp,
73
+ lastSeen: j.timestamp,
74
+ firstPrompt: '',
75
+ lastPrompt: '',
76
+ messageCount: 0
77
+ });
78
+ }
79
+ const data = sessionData.get(key);
80
+ if (j.timestamp < data.firstSeen) data.firstSeen = j.timestamp;
81
+ if (j.timestamp > data.lastSeen) data.lastSeen = j.timestamp;
82
+ if (isRealPrompt(j.display)) {
83
+ if (!data.firstPrompt) data.firstPrompt = j.display;
84
+ data.lastPrompt = j.display;
85
+ }
86
+ }
75
87
 
76
- for (const [key, data] of sessionData) {
88
+ for (const [key, data] of Array.from(sessionData)) {
77
89
  if (data.tool !== 'claude') continue;
90
+ if (!data.firstPrompt) { sessionData.delete(key); continue; }
78
91
  const jsonlPath = path.join(projectsDir, data.id + '.jsonl');
79
92
  const agentPath = path.join(projectsDir, 'agent-' + data.id.substring(0,7) + '.jsonl');
80
93
  let filePath = fs.existsSync(jsonlPath) ? jsonlPath : (fs.existsSync(agentPath) ? agentPath : null);
@@ -125,9 +138,10 @@ get_recent_sessions() {
125
138
  try {
126
139
  const j = JSON.parse(ln);
127
140
  if (j.timestamp) lastTs = Math.max(lastTs, Date.parse(j.timestamp));
128
- if (j.type === 'response_item' && j.payload && j.payload.role === 'user' && Array.isArray(j.payload.content)) {
129
- const text = (j.payload.content.find(c => c.type === 'input_text') || {}).text || '';
130
- if (text && !text.startsWith('<user_instructions>') && !text.startsWith('<environment_context>')) {
141
+ // event_msg.user_message = actual user-typed input only (no AGENTS.md, no env_context)
142
+ if (j.type === 'event_msg' && j.payload && j.payload.type === 'user_message') {
143
+ const text = (j.payload.message || '').trim();
144
+ if (text) {
131
145
  if (!firstPrompt) firstPrompt = text;
132
146
  lastPrompt = text;
133
147
  msgCount++;
@@ -136,6 +150,9 @@ get_recent_sessions() {
136
150
  } catch(e) {}
137
151
  }
138
152
 
153
+ // Skip sessions with no real user-typed input (sub-agents, programmatic runs)
154
+ if (msgCount === 0 || !firstPrompt) continue;
155
+
139
156
  const stat = fs.statSync(f);
140
157
  sessionData.set('codex:' + id, {
141
158
  tool: 'codex',
@@ -293,23 +310,46 @@ get_recent_24h_sessions() {
293
310
  const cwd = '/home/runner/workspace';
294
311
  const sessions = new Map();
295
312
 
313
+ // Heuristic: skip captured shell output / non-real prompts
314
+ const isRealPrompt = (txt) => {
315
+ if (!txt) return false;
316
+ const t = txt.trim();
317
+ if (!t) return false;
318
+ // Skip messages that are obviously captured shell output
319
+ if (/^[✅❌📦🔗⚠️🚀🎉🔧📝]/.test(t)) return false;
320
+ if (/Claude (history|binary|versions) symlink/.test(t)) return false;
321
+ if (t.startsWith('# AGENTS.md')) return false;
322
+ return true;
323
+ };
324
+
296
325
  // Claude
297
326
  const historyFile = '${history}';
298
327
  if (fs.existsSync(historyFile)) {
299
328
  const lines = fs.readFileSync(historyFile, 'utf8').trim().split('\n');
329
+ // Sort by timestamp ascending so we can pick first real prompt per session
330
+ const entries = [];
300
331
  for (const line of lines) {
301
332
  try {
302
333
  const j = JSON.parse(line);
303
- if (!j.sessionId || !j.timestamp) continue;
304
- const key = 'claude:' + j.sessionId;
305
- if (!sessions.has(key)) {
306
- sessions.set(key, { tool: 'claude', id: j.sessionId, firstSeen: j.timestamp, lastSeen: j.timestamp, firstPrompt: j.display || '' });
307
- }
308
- const s = sessions.get(key);
309
- if (j.timestamp < s.firstSeen) { s.firstSeen = j.timestamp; s.firstPrompt = j.display || s.firstPrompt; }
310
- if (j.timestamp > s.lastSeen) { s.lastSeen = j.timestamp; }
334
+ if (j.sessionId && j.timestamp) entries.push(j);
311
335
  } catch(e) {}
312
336
  }
337
+ entries.sort((a, b) => a.timestamp - b.timestamp);
338
+ for (const j of entries) {
339
+ const key = 'claude:' + j.sessionId;
340
+ if (!sessions.has(key)) {
341
+ sessions.set(key, { tool: 'claude', id: j.sessionId, firstSeen: j.timestamp, lastSeen: j.timestamp, firstPrompt: '' });
342
+ }
343
+ const s = sessions.get(key);
344
+ if (j.timestamp < s.firstSeen) s.firstSeen = j.timestamp;
345
+ if (j.timestamp > s.lastSeen) s.lastSeen = j.timestamp;
346
+ // Set firstPrompt only on first real user prompt encountered
347
+ if (!s.firstPrompt && isRealPrompt(j.display)) s.firstPrompt = j.display;
348
+ }
349
+ // Drop sessions with no real user prompt
350
+ for (const [key, s] of Array.from(sessions)) {
351
+ if (s.tool === 'claude' && !s.firstPrompt) sessions.delete(key);
352
+ }
313
353
  }
314
354
 
315
355
  // Codex
@@ -338,20 +378,28 @@ get_recent_24h_sessions() {
338
378
  if (meta.payload.cwd !== cwd) continue;
339
379
  const id = meta.payload.id;
340
380
  const firstTs = Date.parse(meta.payload.timestamp || meta.timestamp);
381
+
341
382
  let lastTs = firstTs;
342
383
  let firstPrompt = '';
384
+ let realMsgCount = 0;
343
385
  for (const ln of lns) {
344
386
  try {
345
387
  const j = JSON.parse(ln);
346
388
  if (j.timestamp) lastTs = Math.max(lastTs, Date.parse(j.timestamp));
347
- if (!firstPrompt && j.type === 'response_item' && j.payload && j.payload.role === 'user' && Array.isArray(j.payload.content)) {
348
- const text = (j.payload.content.find(c => c.type === 'input_text') || {}).text || '';
349
- if (text && !text.startsWith('<user_instructions>') && !text.startsWith('<environment_context>')) {
350
- firstPrompt = text;
389
+ // event_msg.user_message = actual user-typed input only
390
+ if (j.type === 'event_msg' && j.payload && j.payload.type === 'user_message') {
391
+ const text = (j.payload.message || '').trim();
392
+ if (text) {
393
+ if (!firstPrompt) firstPrompt = text;
394
+ realMsgCount++;
351
395
  }
352
396
  }
353
397
  } catch(e) {}
354
398
  }
399
+
400
+ // Skip sub-agent / programmatic sessions
401
+ if (realMsgCount === 0 || !firstPrompt) continue;
402
+
355
403
  sessions.set('codex:' + id, { tool: 'codex', id, firstSeen: firstTs, lastSeen: lastTs, firstPrompt });
356
404
  } catch(e) {}
357
405
  }