@arcreflex/agent-transcripts 0.1.10 → 0.1.12
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/CLAUDE.md +3 -1
- package/README.md +60 -53
- package/package.json +1 -1
- package/src/adapters/claude-code.ts +1 -0
- package/src/adapters/index.ts +0 -6
- package/src/archive.ts +267 -0
- package/src/cli.ts +96 -63
- package/src/convert.ts +19 -86
- package/src/parse.ts +0 -3
- package/src/render-html.ts +38 -195
- package/src/render-index.ts +15 -178
- package/src/render.ts +25 -88
- package/src/serve.ts +124 -215
- package/src/title.ts +24 -102
- package/src/types.ts +3 -0
- package/src/utils/naming.ts +8 -13
- package/src/utils/summary.ts +1 -4
- package/src/utils/text.ts +5 -0
- package/src/utils/theme.ts +152 -0
- package/src/utils/tree.ts +85 -1
- package/src/watch.ts +111 -0
- package/test/archive.test.ts +264 -0
- package/test/fixtures/claude/branching.input.jsonl +6 -0
- package/test/fixtures/claude/branching.output.md +25 -0
- package/test/naming.test.ts +98 -0
- package/test/summary.test.ts +144 -0
- package/test/tree.test.ts +217 -0
- package/tsconfig.json +1 -1
- package/src/cache.ts +0 -129
- package/src/sync.ts +0 -295
- package/src/utils/provenance.ts +0 -212
package/src/utils/provenance.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provenance tracking utilities.
|
|
3
|
-
*
|
|
4
|
-
* Tracks the relationship between source files and output transcripts
|
|
5
|
-
* via transcripts.json index (primary) and YAML front matter (for self-documenting files).
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { join, resolve } from "path";
|
|
9
|
-
import { rename, unlink } from "fs/promises";
|
|
10
|
-
|
|
11
|
-
const INDEX_FILENAME = "transcripts.json";
|
|
12
|
-
|
|
13
|
-
// ============================================================================
|
|
14
|
-
// Index Types
|
|
15
|
-
// ============================================================================
|
|
16
|
-
|
|
17
|
-
export interface TranscriptEntry {
|
|
18
|
-
source: string; // absolute path to source
|
|
19
|
-
sessionId: string; // full session ID from source filename
|
|
20
|
-
segmentIndex?: number; // for multi-transcript sources (1-indexed)
|
|
21
|
-
syncedAt: string; // ISO timestamp
|
|
22
|
-
firstUserMessage: string; // first user message content (for display)
|
|
23
|
-
title?: string; // copied from cache for index.html convenience
|
|
24
|
-
messageCount: number;
|
|
25
|
-
startTime: string; // ISO timestamp
|
|
26
|
-
endTime: string; // ISO timestamp
|
|
27
|
-
cwd?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface TranscriptsIndex {
|
|
31
|
-
version: 1;
|
|
32
|
-
entries: Record<string, TranscriptEntry>; // outputFilename → entry
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ============================================================================
|
|
36
|
-
// Path Utilities
|
|
37
|
-
// ============================================================================
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Normalize a source path to absolute for consistent index keys.
|
|
41
|
-
*/
|
|
42
|
-
export function normalizeSourcePath(sourcePath: string): string {
|
|
43
|
-
if (sourcePath === "<stdin>") return sourcePath;
|
|
44
|
-
return resolve(sourcePath);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// ============================================================================
|
|
48
|
-
// Index I/O
|
|
49
|
-
// ============================================================================
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Load transcripts.json index from output directory.
|
|
53
|
-
* Returns empty index if file doesn't exist. Warns on corrupt file.
|
|
54
|
-
*/
|
|
55
|
-
export async function loadIndex(outputDir: string): Promise<TranscriptsIndex> {
|
|
56
|
-
const indexPath = join(outputDir, INDEX_FILENAME);
|
|
57
|
-
try {
|
|
58
|
-
const content = await Bun.file(indexPath).text();
|
|
59
|
-
const data = JSON.parse(content) as TranscriptsIndex;
|
|
60
|
-
// Validate version
|
|
61
|
-
if (data.version !== 1) {
|
|
62
|
-
console.error(
|
|
63
|
-
`Warning: Unknown index version ${data.version}, creating fresh index`,
|
|
64
|
-
);
|
|
65
|
-
return { version: 1, entries: {} };
|
|
66
|
-
}
|
|
67
|
-
return data;
|
|
68
|
-
} catch (err) {
|
|
69
|
-
// Distinguish between missing file (expected) and corrupt file (unexpected)
|
|
70
|
-
const isEnoent =
|
|
71
|
-
err instanceof Error && (err as NodeJS.ErrnoException).code === "ENOENT";
|
|
72
|
-
if (!isEnoent) {
|
|
73
|
-
console.error(
|
|
74
|
-
`Warning: Could not parse index file, starting fresh: ${err instanceof Error ? err.message : String(err)}`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
return { version: 1, entries: {} };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Save transcripts.json index to output directory.
|
|
83
|
-
* Uses atomic write (write to .tmp, then rename) to prevent corruption.
|
|
84
|
-
*/
|
|
85
|
-
export async function saveIndex(
|
|
86
|
-
outputDir: string,
|
|
87
|
-
index: TranscriptsIndex,
|
|
88
|
-
): Promise<void> {
|
|
89
|
-
const indexPath = join(outputDir, INDEX_FILENAME);
|
|
90
|
-
const tmpPath = `${indexPath}.tmp`;
|
|
91
|
-
|
|
92
|
-
const content = JSON.stringify(index, null, 2) + "\n";
|
|
93
|
-
await Bun.write(tmpPath, content);
|
|
94
|
-
try {
|
|
95
|
-
await rename(tmpPath, indexPath);
|
|
96
|
-
} catch (err) {
|
|
97
|
-
// Clean up temp file on failure
|
|
98
|
-
try {
|
|
99
|
-
await unlink(tmpPath);
|
|
100
|
-
} catch {
|
|
101
|
-
// Ignore cleanup errors
|
|
102
|
-
}
|
|
103
|
-
throw err;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// ============================================================================
|
|
108
|
-
// Index Operations
|
|
109
|
-
// ============================================================================
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get all output filenames for a given source path.
|
|
113
|
-
*/
|
|
114
|
-
export function getOutputsForSource(
|
|
115
|
-
index: TranscriptsIndex,
|
|
116
|
-
sourcePath: string,
|
|
117
|
-
): string[] {
|
|
118
|
-
const outputs: string[] = [];
|
|
119
|
-
for (const [filename, entry] of Object.entries(index.entries)) {
|
|
120
|
-
if (entry.source === sourcePath) {
|
|
121
|
-
outputs.push(filename);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
return outputs;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Set or update an entry in the index.
|
|
129
|
-
* outputPath should be relative to the output directory.
|
|
130
|
-
*/
|
|
131
|
-
export function setEntry(
|
|
132
|
-
index: TranscriptsIndex,
|
|
133
|
-
outputPath: string,
|
|
134
|
-
entry: TranscriptEntry,
|
|
135
|
-
): void {
|
|
136
|
-
index.entries[outputPath] = entry;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Remove all entries for a given source path.
|
|
141
|
-
* Returns the removed entries (for potential restoration on error).
|
|
142
|
-
*/
|
|
143
|
-
export function removeEntriesForSource(
|
|
144
|
-
index: TranscriptsIndex,
|
|
145
|
-
sourcePath: string,
|
|
146
|
-
): Array<{ filename: string; entry: TranscriptEntry }> {
|
|
147
|
-
const removed: Array<{ filename: string; entry: TranscriptEntry }> = [];
|
|
148
|
-
for (const [filename, entry] of Object.entries(index.entries)) {
|
|
149
|
-
if (entry.source === sourcePath) {
|
|
150
|
-
removed.push({ filename, entry });
|
|
151
|
-
delete index.entries[filename];
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return removed;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Restore previously removed entries to the index.
|
|
159
|
-
*/
|
|
160
|
-
export function restoreEntries(
|
|
161
|
-
index: TranscriptsIndex,
|
|
162
|
-
entries: Array<{ filename: string; entry: TranscriptEntry }>,
|
|
163
|
-
): void {
|
|
164
|
-
for (const { filename, entry } of entries) {
|
|
165
|
-
index.entries[filename] = entry;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// ============================================================================
|
|
170
|
-
// File Operations
|
|
171
|
-
// ============================================================================
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Delete output files, with warnings on failure.
|
|
175
|
-
*/
|
|
176
|
-
export async function deleteOutputFiles(
|
|
177
|
-
outputDir: string,
|
|
178
|
-
filenames: string[],
|
|
179
|
-
quiet = false,
|
|
180
|
-
): Promise<void> {
|
|
181
|
-
for (const filename of filenames) {
|
|
182
|
-
const fullPath = join(outputDir, filename);
|
|
183
|
-
try {
|
|
184
|
-
await unlink(fullPath);
|
|
185
|
-
if (!quiet) {
|
|
186
|
-
console.error(`Deleted: ${fullPath}`);
|
|
187
|
-
}
|
|
188
|
-
} catch (err) {
|
|
189
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
190
|
-
console.error(`Warning: could not delete ${fullPath}: ${msg}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ============================================================================
|
|
196
|
-
// Transcript Metadata Extraction
|
|
197
|
-
// ============================================================================
|
|
198
|
-
|
|
199
|
-
import type { Transcript } from "../types.ts";
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Extract the first user message from a transcript.
|
|
203
|
-
* Returns empty string if no user message found.
|
|
204
|
-
*/
|
|
205
|
-
export function extractFirstUserMessage(transcript: Transcript): string {
|
|
206
|
-
for (const msg of transcript.messages) {
|
|
207
|
-
if (msg.type === "user") {
|
|
208
|
-
return msg.content;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return "";
|
|
212
|
-
}
|