mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 09:01:14 +00:00
Breaking Changes: - Timestamps now use Slack format - run migrate-timestamps.ts for existing logs Added: - Channel/user ID mappings in system prompt - Skills documentation in system prompt - Debug last_prompt.txt output - Bash working directory info - Token-efficient log queries filtering tool calls Changed: - Turn-based message context (groups consecutive bot messages as one turn) - Messages sorted by Slack timestamp - Condensed system prompt (~5k → ~2.7k chars) - Simplified user prompt - Selective logging (skip UI status labels) Fixed: - Duplicate message logging from app_mention handler - Username obfuscation in thread messages
121 lines
3.4 KiB
TypeScript
121 lines
3.4 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
/**
|
|
* Migrate log.jsonl timestamps from milliseconds to Slack format (seconds.microseconds)
|
|
*
|
|
* Usage: npx tsx scripts/migrate-timestamps.ts <data-dir>
|
|
* Example: npx tsx scripts/migrate-timestamps.ts ./data
|
|
*/
|
|
|
|
import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from "fs";
|
|
import { join } from "path";
|
|
|
|
function isMillisecondTimestamp(ts: string): boolean {
|
|
// Slack timestamps are seconds.microseconds, like "1764279530.533489"
|
|
// Millisecond timestamps are just big numbers, like "1764279320398"
|
|
//
|
|
// Key insight:
|
|
// - Slack ts from 2025: ~1.7 billion (10 digits before decimal)
|
|
// - Millisecond ts from 2025: ~1.7 trillion (13 digits)
|
|
|
|
// If it has a decimal and the integer part is < 10^12, it's Slack format
|
|
if (ts.includes(".")) {
|
|
const intPart = parseInt(ts.split(".")[0], 10);
|
|
return intPart > 1e12; // Unlikely to have decimal AND be millis, but check anyway
|
|
}
|
|
|
|
// No decimal - check if it's too big to be seconds
|
|
const num = parseInt(ts, 10);
|
|
return num > 1e12; // If > 1 trillion, it's milliseconds
|
|
}
|
|
|
|
function convertToSlackTs(msTs: string): string {
|
|
const ms = parseInt(msTs, 10);
|
|
const seconds = Math.floor(ms / 1000);
|
|
const micros = (ms % 1000) * 1000;
|
|
return `${seconds}.${micros.toString().padStart(6, "0")}`;
|
|
}
|
|
|
|
function migrateFile(filePath: string): { total: number; migrated: number } {
|
|
const content = readFileSync(filePath, "utf-8");
|
|
const lines = content.split("\n").filter(Boolean);
|
|
|
|
let migrated = 0;
|
|
const newLines: string[] = [];
|
|
|
|
for (const line of lines) {
|
|
try {
|
|
const msg = JSON.parse(line);
|
|
if (msg.ts && isMillisecondTimestamp(msg.ts)) {
|
|
const oldTs = msg.ts;
|
|
msg.ts = convertToSlackTs(msg.ts);
|
|
console.log(` Converted: ${oldTs} -> ${msg.ts}`);
|
|
migrated++;
|
|
}
|
|
newLines.push(JSON.stringify(msg));
|
|
} catch (e) {
|
|
// Keep malformed lines as-is
|
|
console.log(` Warning: Could not parse line: ${line.substring(0, 50)}...`);
|
|
newLines.push(line);
|
|
}
|
|
}
|
|
|
|
if (migrated > 0) {
|
|
writeFileSync(filePath, newLines.join("\n") + "\n", "utf-8");
|
|
}
|
|
|
|
return { total: lines.length, migrated };
|
|
}
|
|
|
|
function findLogFiles(dir: string): string[] {
|
|
const logFiles: string[] = [];
|
|
|
|
if (!existsSync(dir)) {
|
|
console.error(`Directory not found: ${dir}`);
|
|
return [];
|
|
}
|
|
|
|
const entries = readdirSync(dir);
|
|
for (const entry of entries) {
|
|
const fullPath = join(dir, entry);
|
|
const stat = statSync(fullPath);
|
|
|
|
if (stat.isDirectory()) {
|
|
// Check for log.jsonl in subdirectory
|
|
const logPath = join(fullPath, "log.jsonl");
|
|
if (existsSync(logPath)) {
|
|
logFiles.push(logPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
return logFiles;
|
|
}
|
|
|
|
// Main
|
|
const dataDir = process.argv[2];
|
|
if (!dataDir) {
|
|
console.error("Usage: npx tsx scripts/migrate-timestamps.ts <data-dir>");
|
|
console.error("Example: npx tsx scripts/migrate-timestamps.ts ./data");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Scanning for log.jsonl files in: ${dataDir}\n`);
|
|
|
|
const logFiles = findLogFiles(dataDir);
|
|
if (logFiles.length === 0) {
|
|
console.log("No log.jsonl files found.");
|
|
process.exit(0);
|
|
}
|
|
|
|
let totalMigrated = 0;
|
|
let totalMessages = 0;
|
|
|
|
for (const logFile of logFiles) {
|
|
console.log(`Processing: ${logFile}`);
|
|
const { total, migrated } = migrateFile(logFile);
|
|
totalMessages += total;
|
|
totalMigrated += migrated;
|
|
console.log(` ${migrated}/${total} messages migrated\n`);
|
|
}
|
|
|
|
console.log(`Done! Migrated ${totalMigrated}/${totalMessages} total messages across ${logFiles.length} files.`);
|