* refactor: Reduce continuation prompt token usage by 95 lines Removed redundant instructions from continuation prompt that were originally added to mitigate a session continuity issue. That issue has since been resolved, making these detailed instructions unnecessary on every continuation. Changes: - Reduced continuation prompt from ~106 lines to ~11 lines (~95 line reduction) - Changed "User's Goal:" to "Next Prompt in Session:" (more accurate framing) - Removed redundant WHAT TO RECORD, WHEN TO SKIP, and OUTPUT FORMAT sections - Kept concise reminder: "Continue generating observations and progress summaries..." - Initial prompt still contains all detailed instructions Impact: - Significant token savings on every continuation prompt - Faster context injection with no loss of functionality - Instructions remain comprehensive in initial prompt Files modified: - src/sdk/prompts.ts (buildContinuationPrompt function) - plugin/scripts/worker-service.cjs (compiled output) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: Enhance observation and summary prompts for clarity and token efficiency * Enhance prompt clarity and instructions in prompts.ts - Added a reminder to think about instructions before starting work. - Simplified the continuation prompt instruction by removing "for this ongoing session." * feat: Enhance settings.json with permissions and deny access to sensitive files refactor: Remove PLAN-full-observation-display.md and PR_SUMMARY.md as they are no longer needed chore: Delete SECURITY_SUMMARY.md since it is redundant after recent changes fix: Update worker-service.cjs to streamline observation generation instructions cleanup: Remove src-analysis.md and src-tree.md for a cleaner codebase refactor: Modify prompts.ts to clarify instructions for memory processing * refactor: Remove legacy worker service implementation * feat: Enhance summary hook to extract last assistant message and improve logging - Added function to extract the last assistant message from the transcript. - Updated summary hook to include last assistant message in the summary request. - Modified SDKSession interface to store last assistant message. - Adjusted buildSummaryPrompt to utilize last assistant message for generating summaries. - Updated worker service and session manager to handle last assistant message in summarize requests. - Introduced silentDebug utility for improved logging and diagnostics throughout the summary process. * docs: Add comprehensive implementation plan for ROI metrics feature Added detailed implementation plan covering: - Token usage capture from Agent SDK - Database schema changes (migration #8) - Discovery cost tracking per observation - Context hook display with ROI metrics - Testing and rollout strategy Timeline: ~20 hours over 4 days Goal: Empirical data for YC application amendment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: Add transcript processing scripts for analysis and formatting - Implemented `dump-transcript-readable.ts` to generate a readable markdown dump of transcripts, excluding certain entry types. - Created `extract-rich-context-examples.ts` to extract and showcase rich context examples from transcripts, highlighting user requests and assistant reasoning. - Developed `format-transcript-context.ts` to format transcript context into a structured markdown format for improved observation generation. - Added `test-transcript-parser.ts` for validating data extraction from transcript JSONL files, including statistics and error reporting. - Introduced `transcript-to-markdown.ts` for a complete representation of transcript data in markdown format, showing all context data. - Enhanced type definitions in `transcript.ts` to support new features and ensure type safety. - Built `transcript-parser.ts` to handle parsing of transcript JSONL files, including error handling and data extraction methods. * Refactor hooks and SDKAgent for improved observation handling - Updated `new-hook.ts` to clean user prompts by stripping leading slashes for better semantic clarity. - Enhanced `save-hook.ts` to include additional tools in the SKIP_TOOLS set, preventing unnecessary observations from certain command invocations. - Modified `prompts.ts` to change the structure of observation prompts, emphasizing the observational role and providing a detailed XML output format for observations. - Adjusted `SDKAgent.ts` to enforce stricter tool usage restrictions, ensuring the memory agent operates solely as an observer without any tool access. * feat: Enhance session initialization to accept user prompts and prompt numbers - Updated `handleSessionInit` in `worker-service.ts` to extract `userPrompt` and `promptNumber` from the request body and pass them to `initializeSession`. - Modified `initializeSession` in `SessionManager.ts` to handle optional `currentUserPrompt` and `promptNumber` parameters. - Added logic to update the existing session's `userPrompt` and `lastPromptNumber` if a `currentUserPrompt` is provided. - Implemented debug logging for session initialization and updates to track user prompts and prompt numbers. --------- Co-authored-by: Claude <noreply@anthropic.com>
168 lines
5.6 KiB
TypeScript
168 lines
5.6 KiB
TypeScript
#!/usr/bin/env tsx
|
|
/**
|
|
* Test script for TranscriptParser
|
|
* Validates data extraction from Claude Code transcript JSONL files
|
|
*
|
|
* Usage: npx tsx scripts/test-transcript-parser.ts <path-to-transcript.jsonl>
|
|
*/
|
|
|
|
import { TranscriptParser } from '../src/utils/transcript-parser.js';
|
|
import { existsSync } from 'fs';
|
|
import { resolve } from 'path';
|
|
|
|
function formatTokens(num: number): string {
|
|
return num.toLocaleString();
|
|
}
|
|
|
|
function formatPercentage(num: number): string {
|
|
return `${(num * 100).toFixed(2)}%`;
|
|
}
|
|
|
|
function main() {
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length === 0) {
|
|
console.error('Usage: npx tsx scripts/test-transcript-parser.ts <path-to-transcript.jsonl>');
|
|
console.error('\nExample: npx tsx scripts/test-transcript-parser.ts ~/.cache/claude-code/transcripts/latest.jsonl');
|
|
process.exit(1);
|
|
}
|
|
|
|
const transcriptPath = resolve(args[0]);
|
|
|
|
if (!existsSync(transcriptPath)) {
|
|
console.error(`Error: Transcript file not found: ${transcriptPath}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`\n🔍 Parsing transcript: ${transcriptPath}\n`);
|
|
|
|
try {
|
|
const parser = new TranscriptParser(transcriptPath);
|
|
|
|
// Get parse statistics
|
|
const stats = parser.getParseStats();
|
|
|
|
console.log('📊 Parse Statistics:');
|
|
console.log('─'.repeat(60));
|
|
console.log(`Total lines: ${stats.totalLines}`);
|
|
console.log(`Parsed entries: ${stats.parsedEntries}`);
|
|
console.log(`Failed lines: ${stats.failedLines}`);
|
|
console.log(`Failure rate: ${formatPercentage(stats.failureRate)}`);
|
|
console.log();
|
|
|
|
console.log('📋 Entries by Type:');
|
|
console.log('─'.repeat(60));
|
|
for (const [type, count] of Object.entries(stats.entriesByType)) {
|
|
console.log(` ${type.padEnd(20)} ${count}`);
|
|
}
|
|
console.log();
|
|
|
|
// Show parse errors if any
|
|
if (stats.failedLines > 0) {
|
|
console.log('❌ Parse Errors:');
|
|
console.log('─'.repeat(60));
|
|
const errors = parser.getParseErrors();
|
|
errors.slice(0, 5).forEach(err => {
|
|
console.log(` Line ${err.lineNumber}: ${err.error}`);
|
|
});
|
|
if (errors.length > 5) {
|
|
console.log(` ... and ${errors.length - 5} more errors`);
|
|
}
|
|
console.log();
|
|
}
|
|
|
|
// Test data extraction methods
|
|
console.log('💬 Message Extraction:');
|
|
console.log('─'.repeat(60));
|
|
|
|
const lastUserMessage = parser.getLastUserMessage();
|
|
console.log(`Last user message: ${lastUserMessage ? `"${lastUserMessage.substring(0, 100)}..."` : '(none)'}`);
|
|
console.log();
|
|
|
|
const lastAssistantMessage = parser.getLastAssistantMessage();
|
|
console.log(`Last assistant message: ${lastAssistantMessage ? `"${lastAssistantMessage.substring(0, 100)}..."` : '(none)'}`);
|
|
console.log();
|
|
|
|
// Token usage
|
|
const tokenUsage = parser.getTotalTokenUsage();
|
|
console.log('💰 Token Usage:');
|
|
console.log('─'.repeat(60));
|
|
console.log(`Input tokens: ${formatTokens(tokenUsage.inputTokens)}`);
|
|
console.log(`Output tokens: ${formatTokens(tokenUsage.outputTokens)}`);
|
|
console.log(`Cache creation tokens: ${formatTokens(tokenUsage.cacheCreationTokens)}`);
|
|
console.log(`Cache read tokens: ${formatTokens(tokenUsage.cacheReadTokens)}`);
|
|
console.log(`Total tokens: ${formatTokens(tokenUsage.inputTokens + tokenUsage.outputTokens)}`);
|
|
console.log();
|
|
|
|
// Tool use history
|
|
const toolUses = parser.getToolUseHistory();
|
|
console.log('🔧 Tool Use History:');
|
|
console.log('─'.repeat(60));
|
|
if (toolUses.length > 0) {
|
|
console.log(`Total tool uses: ${toolUses.length}\n`);
|
|
|
|
// Group by tool name
|
|
const toolCounts = toolUses.reduce((acc, tool) => {
|
|
acc[tool.name] = (acc[tool.name] || 0) + 1;
|
|
return acc;
|
|
}, {} as Record<string, number>);
|
|
|
|
console.log('Tools used:');
|
|
for (const [name, count] of Object.entries(toolCounts).sort((a, b) => b[1] - a[1])) {
|
|
console.log(` ${name.padEnd(30)} ${count}x`);
|
|
}
|
|
} else {
|
|
console.log('(no tool uses found)');
|
|
}
|
|
console.log();
|
|
|
|
// System entries
|
|
const systemEntries = parser.getSystemEntries();
|
|
if (systemEntries.length > 0) {
|
|
console.log('⚠️ System Entries:');
|
|
console.log('─'.repeat(60));
|
|
console.log(`Found ${systemEntries.length} system entries`);
|
|
systemEntries.slice(0, 3).forEach(entry => {
|
|
console.log(` [${entry.level || 'info'}] ${entry.content.substring(0, 80)}...`);
|
|
});
|
|
if (systemEntries.length > 3) {
|
|
console.log(` ... and ${systemEntries.length - 3} more`);
|
|
}
|
|
console.log();
|
|
}
|
|
|
|
// Summary entries
|
|
const summaryEntries = parser.getSummaryEntries();
|
|
if (summaryEntries.length > 0) {
|
|
console.log('📝 Summary Entries:');
|
|
console.log('─'.repeat(60));
|
|
console.log(`Found ${summaryEntries.length} summary entries`);
|
|
summaryEntries.forEach((entry, i) => {
|
|
console.log(`\nSummary ${i + 1}:`);
|
|
console.log(entry.summary.substring(0, 200) + '...');
|
|
});
|
|
console.log();
|
|
}
|
|
|
|
// Queue operations
|
|
const queueOps = parser.getQueueOperationEntries();
|
|
if (queueOps.length > 0) {
|
|
console.log('🔄 Queue Operations:');
|
|
console.log('─'.repeat(60));
|
|
const enqueues = queueOps.filter(op => op.operation === 'enqueue').length;
|
|
const dequeues = queueOps.filter(op => op.operation === 'dequeue').length;
|
|
console.log(`Enqueue operations: ${enqueues}`);
|
|
console.log(`Dequeue operations: ${dequeues}`);
|
|
console.log();
|
|
}
|
|
|
|
console.log('✅ Validation complete!\n');
|
|
|
|
} catch (error) {
|
|
console.error('❌ Error parsing transcript:', error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|