🔧 telemetry aid tools
This commit is contained in:
31
scripts/fix-wpm.mjs
Normal file
31
scripts/fix-wpm.mjs
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env node
|
||||
// One-time migration: zero out WPM for sessions that are clearly paste artifacts.
|
||||
// A session is flagged when activeMs < 5000 (sub-5-second burst) and the resulting
|
||||
// WPM exceeds 300 — no human types that fast.
|
||||
|
||||
import { readFileSync, writeFileSync, cpSync } from 'fs'
|
||||
|
||||
const TELEMETRY = `${process.env.HOME}/Library/Application Support/Borges/.borges/telemetry.json`
|
||||
const BACKUP = TELEMETRY + '.bak'
|
||||
|
||||
const sessions = JSON.parse(readFileSync(TELEMETRY, 'utf-8'))
|
||||
|
||||
let fixed = 0
|
||||
const patched = sessions.map(s => {
|
||||
if (s.wpm > 300 && s.activeMs < 5000) {
|
||||
fixed++
|
||||
console.log(`Fixing session ${s.id} (${s.storyId}): wpm ${s.wpm} → 0 [activeMs=${s.activeMs}, words ${s.wordsStart}→${s.wordsEnd}]`)
|
||||
return { ...s, wpm: 0 }
|
||||
}
|
||||
return s
|
||||
})
|
||||
|
||||
if (fixed === 0) {
|
||||
console.log('No sessions to fix.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
cpSync(TELEMETRY, BACKUP)
|
||||
console.log(`Backed up to ${BACKUP}`)
|
||||
writeFileSync(TELEMETRY, JSON.stringify(patched, null, 2), 'utf-8')
|
||||
console.log(`Done. Fixed ${fixed} session(s).`)
|
||||
58
scripts/merge-sessions.mjs
Normal file
58
scripts/merge-sessions.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env node
|
||||
// One-time migration: merge consecutive same-story sessions that were split by
|
||||
// the blur-flush bug (every tab-out ended the session prematurely).
|
||||
// Sessions of the same story on the same date with a gap < GAP_MS are merged.
|
||||
|
||||
import { readFileSync, writeFileSync, copyFileSync } from 'fs'
|
||||
|
||||
const GAP_MS = 10 * 60 * 1000 // 10-minute gap = new session
|
||||
const TELEMETRY = `${process.env.HOME}/Library/Application Support/Borges/.borges/telemetry.json`
|
||||
const BACKUP = TELEMETRY + '.merge-bak'
|
||||
|
||||
const sessions = JSON.parse(readFileSync(TELEMETRY, 'utf-8'))
|
||||
|
||||
// Sort chronologically so we can walk them in order
|
||||
const sorted = [...sessions].sort((a, b) => a.startedAt - b.startedAt)
|
||||
|
||||
const merged = []
|
||||
let mergeCount = 0
|
||||
|
||||
for (const s of sorted) {
|
||||
const prev = merged[merged.length - 1]
|
||||
|
||||
const sameStory = prev && prev.storyId === s.storyId
|
||||
const sameDate = prev && prev.date === s.date
|
||||
const gapMs = prev ? s.startedAt - prev.endedAt : Infinity
|
||||
|
||||
if (sameStory && sameDate && gapMs < GAP_MS) {
|
||||
// Merge s into prev
|
||||
const combinedActiveMs = prev.activeMs + s.activeMs
|
||||
const typedWords = s.wordsEnd - prev.wordsStart
|
||||
const wpm = combinedActiveMs > 0
|
||||
? Math.round(Math.max(0, typedWords) / (combinedActiveMs / 60_000))
|
||||
: 0
|
||||
|
||||
console.log(
|
||||
`Merging ${s.id} into ${prev.id} (${prev.storyId}) ` +
|
||||
`gap=${(gapMs / 60000).toFixed(1)}m words ${prev.wordsStart}→${s.wordsEnd} wpm ${prev.wpm}→${wpm}`
|
||||
)
|
||||
|
||||
prev.endedAt = s.endedAt
|
||||
prev.wordsEnd = s.wordsEnd
|
||||
prev.activeMs = combinedActiveMs
|
||||
prev.wpm = wpm
|
||||
mergeCount++
|
||||
} else {
|
||||
merged.push({ ...s })
|
||||
}
|
||||
}
|
||||
|
||||
if (mergeCount === 0) {
|
||||
console.log('No sessions to merge.')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
copyFileSync(TELEMETRY, BACKUP)
|
||||
console.log(`\nBacked up to ${BACKUP}`)
|
||||
writeFileSync(TELEMETRY, JSON.stringify(merged, null, 2), 'utf-8')
|
||||
console.log(`Done. Merged ${mergeCount} session(s) → ${merged.length} total (was ${sessions.length}).`)
|
||||
Reference in New Issue
Block a user