@henteko/ccdigest 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 henteko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # ccdigest
2
+
3
+ Format [Claude Code](https://docs.anthropic.com/en/docs/claude-code) session data into readable Markdown for team sharing and code review.
4
+
5
+ Claude Code stores session logs as JSONL files under `~/.claude/projects/`. ccdigest reads these files and converts them into clean, human-readable Markdown.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @henteko/ccdigest
11
+ ```
12
+
13
+ Or run directly with npx:
14
+
15
+ ```bash
16
+ npx @henteko/ccdigest list
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### List sessions
22
+
23
+ ```bash
24
+ ccdigest list
25
+ ccdigest list --branch main
26
+ ccdigest list --json
27
+ ```
28
+
29
+ ### Show session as Markdown
30
+
31
+ ```bash
32
+ ccdigest show <session-id>
33
+ ccdigest show <session-id-1> <session-id-2> # merge multiple sessions
34
+ ```
35
+
36
+ ### Export to file
37
+
38
+ ```bash
39
+ ccdigest export <session-id> -o output.md
40
+ ccdigest export <id-1> <id-2> -o combined.md
41
+ ```
42
+
43
+ ### Options
44
+
45
+ | Option | Description |
46
+ |--------|-------------|
47
+ | `--project <path>` | Project path (defaults to cwd) |
48
+ | `--no-thinking` | Hide thinking blocks |
49
+ | `--show-thinking` | Show thinking blocks expanded |
50
+ | `--no-tools` | Hide tool calls |
51
+ | `--max-tool-lines <n>` | Max lines for tool results (default: 50) |
52
+
53
+ ## Development
54
+
55
+ ```bash
56
+ npm install
57
+ npm run build
58
+ npm test
59
+ ```
60
+
61
+ ## Release
62
+
63
+ 1. Update version in `package.json`:
64
+
65
+ ```bash
66
+ npm version patch # or minor, major
67
+ ```
68
+
69
+ 2. Push the tag:
70
+
71
+ ```bash
72
+ git push origin main --tags
73
+ ```
74
+
75
+ 3. Publish to npm:
76
+
77
+ ```bash
78
+ npm publish --access public
79
+ ```
80
+
81
+ `prepublishOnly` hook will automatically run build and tests before publishing.
82
+
83
+ ## License
84
+
85
+ [MIT](LICENSE)
@@ -0,0 +1,5 @@
1
+ import { type ShowOptions } from '../options.js';
2
+ export declare function runExport(sessionIds: string[], options: ShowOptions & {
3
+ project?: string;
4
+ output: string;
5
+ }): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+ import { findSession } from '../../core/session-store.js';
3
+ import { parseSession } from '../../core/parser.js';
4
+ import { mergeSessions } from '../../core/merger.js';
5
+ import { formatSession } from '../../formatter/markdown.js';
6
+ import { resolveFormatOptions } from '../options.js';
7
+ export async function runExport(sessionIds, options) {
8
+ const projectPath = options.project || process.cwd();
9
+ try {
10
+ const parsedSessions = await Promise.all(sessionIds.map(async (id) => {
11
+ const session = findSession(projectPath, id);
12
+ return parseSession(session.filePath);
13
+ }));
14
+ const merged = parsedSessions.length > 1
15
+ ? mergeSessions(parsedSessions)
16
+ : parsedSessions[0];
17
+ const formatOpts = resolveFormatOptions(options);
18
+ const markdown = formatSession(merged, formatOpts);
19
+ fs.writeFileSync(options.output, markdown, 'utf-8');
20
+ console.error(`Exported to ${options.output}`);
21
+ }
22
+ catch (err) {
23
+ console.error(`Error: ${err.message}`);
24
+ process.exit(1);
25
+ }
26
+ }
27
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAoB,MAAM,eAAe,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,UAAoB,EACpB,OAA2D;IAE3D,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,GAAG,CACtC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC1B,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC;YACtC,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC;YAC/B,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QAEtB,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAEnD,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,eAAe,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,UAAW,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface ListOptions {
2
+ project?: string;
3
+ json?: boolean;
4
+ branch?: string;
5
+ }
6
+ export declare function runList(options: ListOptions): void;
@@ -0,0 +1,41 @@
1
+ import { listSessions } from '../../core/session-store.js';
2
+ export function runList(options) {
3
+ const projectPath = options.project || process.cwd();
4
+ let sessions = listSessions(projectPath);
5
+ if (options.branch) {
6
+ sessions = sessions.filter((s) => s.branch === options.branch);
7
+ }
8
+ if (sessions.length === 0) {
9
+ console.error('No sessions found.');
10
+ process.exit(1);
11
+ }
12
+ if (options.json) {
13
+ console.log(JSON.stringify(sessions.map((s) => ({
14
+ sessionId: s.sessionId,
15
+ modifiedAt: s.modifiedAt.toISOString(),
16
+ sizeBytes: s.sizeBytes,
17
+ branch: s.branch,
18
+ })), null, 2));
19
+ return;
20
+ }
21
+ // Table format
22
+ const maxIdLen = Math.max(...sessions.map((s) => s.sessionId.length), 10);
23
+ const maxBranchLen = Math.max(...sessions.map((s) => s.branch.length), 6);
24
+ console.log(`${'SESSION ID'.padEnd(maxIdLen)} ${'BRANCH'.padEnd(maxBranchLen)} ${'MODIFIED'.padEnd(19)} ${'SIZE'.padStart(10)}`);
25
+ console.log('-'.repeat(maxIdLen + 2 + maxBranchLen + 2 + 19 + 2 + 10));
26
+ for (const s of sessions) {
27
+ const date = s.modifiedAt.toISOString().replace('T', ' ').substring(0, 19);
28
+ const size = formatBytes(s.sizeBytes);
29
+ console.log(`${s.sessionId.padEnd(maxIdLen)} ${s.branch.padEnd(maxBranchLen)} ${date} ${size.padStart(10)}`);
30
+ }
31
+ }
32
+ function formatBytes(bytes) {
33
+ if (bytes < 1024)
34
+ return `${bytes} B`;
35
+ const kb = bytes / 1024;
36
+ if (kb < 1024)
37
+ return `${kb.toFixed(1)} KB`;
38
+ const mb = kb / 1024;
39
+ return `${mb.toFixed(1)} MB`;
40
+ }
41
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type ShowOptions } from '../options.js';
2
+ export declare function runShow(sessionIds: string[], options: ShowOptions & {
3
+ project?: string;
4
+ }): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { findSession } from '../../core/session-store.js';
2
+ import { parseSession } from '../../core/parser.js';
3
+ import { mergeSessions } from '../../core/merger.js';
4
+ import { formatSession } from '../../formatter/markdown.js';
5
+ import { resolveFormatOptions } from '../options.js';
6
+ export async function runShow(sessionIds, options) {
7
+ const projectPath = options.project || process.cwd();
8
+ try {
9
+ const parsedSessions = await Promise.all(sessionIds.map(async (id) => {
10
+ const session = findSession(projectPath, id);
11
+ return parseSession(session.filePath);
12
+ }));
13
+ const merged = parsedSessions.length > 1
14
+ ? mergeSessions(parsedSessions)
15
+ : parsedSessions[0];
16
+ const formatOpts = resolveFormatOptions(options);
17
+ const markdown = formatSession(merged, formatOpts);
18
+ process.stdout.write(markdown);
19
+ }
20
+ catch (err) {
21
+ console.error(`Error: ${err.message}`);
22
+ process.exit(1);
23
+ }
24
+ }
25
+ //# sourceMappingURL=show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/cli/commands/show.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAoB,MAAM,eAAe,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,UAAoB,EACpB,OAA2C;IAE3C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAErD,IAAI,CAAC;QACH,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,GAAG,CACtC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YAC1B,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC7C,OAAO,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC;YACtC,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC;YAC/B,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QAEtB,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAEnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,UAAW,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { FormatOptions } from '../core/types.js';
2
+ export interface ShowOptions {
3
+ thinking?: boolean;
4
+ showThinking?: boolean;
5
+ tools?: boolean;
6
+ maxToolLines?: string;
7
+ }
8
+ export declare function resolveFormatOptions(opts: ShowOptions): FormatOptions;
@@ -0,0 +1,13 @@
1
+ export function resolveFormatOptions(opts) {
2
+ let showThinking = 'collapsed';
3
+ if (opts.thinking === false)
4
+ showThinking = 'hidden';
5
+ if (opts.showThinking)
6
+ showThinking = 'expanded';
7
+ return {
8
+ showThinking,
9
+ showTools: opts.tools !== false,
10
+ maxToolLines: opts.maxToolLines ? parseInt(opts.maxToolLines, 10) : 50,
11
+ };
12
+ }
13
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/cli/options.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,oBAAoB,CAAC,IAAiB;IACpD,IAAI,YAAY,GAAkC,WAAW,CAAC;IAC9D,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK;QAAE,YAAY,GAAG,QAAQ,CAAC;IACrD,IAAI,IAAI,CAAC,YAAY;QAAE,YAAY,GAAG,UAAU,CAAC;IAEjD,OAAO;QACL,YAAY;QACZ,SAAS,EAAE,IAAI,CAAC,KAAK,KAAK,KAAK;QAC/B,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { ParsedSession } from './types.js';
2
+ /**
3
+ * Merge multiple parsed sessions into a single session with turns sorted by timestamp.
4
+ * If only one session is provided, it is returned as-is.
5
+ */
6
+ export declare function mergeSessions(sessions: ParsedSession[]): ParsedSession;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Merge multiple parsed sessions into a single session with turns sorted by timestamp.
3
+ * If only one session is provided, it is returned as-is.
4
+ */
5
+ export function mergeSessions(sessions) {
6
+ if (sessions.length === 0) {
7
+ throw new Error('At least one session is required');
8
+ }
9
+ if (sessions.length === 1) {
10
+ return sessions[0];
11
+ }
12
+ // Collect all turns from all sessions
13
+ const allTurns = sessions.flatMap((s) => s.turns);
14
+ // Sort by timestamp (turns without timestamp go to the end)
15
+ allTurns.sort((a, b) => {
16
+ if (!a.timestamp && !b.timestamp)
17
+ return 0;
18
+ if (!a.timestamp)
19
+ return 1;
20
+ if (!b.timestamp)
21
+ return -1;
22
+ return a.timestamp.localeCompare(b.timestamp);
23
+ });
24
+ // Re-number turns
25
+ for (let i = 0; i < allTurns.length; i++) {
26
+ allTurns[i].turnNumber = i + 1;
27
+ }
28
+ // Merge metadata
29
+ const first = sessions[0].metadata;
30
+ const sessionId = sessions.map((s) => s.metadata.sessionId).join(',');
31
+ let startTime = first.startTime;
32
+ let endTime = first.endTime;
33
+ for (const s of sessions) {
34
+ const m = s.metadata;
35
+ if (m.startTime && (!startTime || m.startTime < startTime)) {
36
+ startTime = m.startTime;
37
+ }
38
+ if (m.endTime && (!endTime || m.endTime > endTime)) {
39
+ endTime = m.endTime;
40
+ }
41
+ }
42
+ return {
43
+ metadata: {
44
+ sessionId,
45
+ project: first.project,
46
+ branch: first.branch,
47
+ claudeVersion: first.claudeVersion,
48
+ startTime,
49
+ endTime,
50
+ model: first.model,
51
+ },
52
+ turns: allTurns,
53
+ };
54
+ }
55
+ //# sourceMappingURL=merger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merger.js","sourceRoot":"","sources":["../../src/core/merger.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAyB;IACrD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IAED,sCAAsC;IACtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAElD,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrB,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,CAAC,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,SAAS;YAAE,OAAO,CAAC,CAAC,CAAC;QAC5B,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,kBAAkB;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,QAAQ,CAAC,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,iBAAiB;IACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IACnC,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEtE,IAAI,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,IAAI,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QACrB,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,GAAG,SAAS,CAAC,EAAE,CAAC;YAC3D,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;QAC1B,CAAC;QACD,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,GAAG,OAAO,CAAC,EAAE,CAAC;YACnD,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC;QACtB,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE;YACR,SAAS;YACT,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,aAAa,EAAE,KAAK,CAAC,aAAa;YAClC,SAAS;YACT,OAAO;YACP,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB;QACD,KAAK,EAAE,QAAQ;KAChB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { SessionEvent, ParsedSession } from './types.js';
2
+ /**
3
+ * Read all events from a JSONL file.
4
+ */
5
+ export declare function readEvents(filePath: string): Promise<SessionEvent[]>;
6
+ /**
7
+ * Parse events into a structured session with conversation turns.
8
+ */
9
+ export declare function parseSession(filePath: string): Promise<ParsedSession>;
@@ -0,0 +1,190 @@
1
+ import fs from 'node:fs';
2
+ import readline from 'node:readline';
3
+ /**
4
+ * Read all events from a JSONL file.
5
+ */
6
+ export async function readEvents(filePath) {
7
+ const events = [];
8
+ const fileStream = fs.createReadStream(filePath, { encoding: 'utf-8' });
9
+ const rl = readline.createInterface({ input: fileStream, crlfDelay: Infinity });
10
+ for await (const line of rl) {
11
+ const trimmed = line.trim();
12
+ if (!trimmed)
13
+ continue;
14
+ try {
15
+ events.push(JSON.parse(trimmed));
16
+ }
17
+ catch {
18
+ // Skip malformed lines
19
+ }
20
+ }
21
+ return events;
22
+ }
23
+ /**
24
+ * Extract session metadata from the events.
25
+ */
26
+ function extractMetadata(events) {
27
+ let sessionId = '';
28
+ let project = '';
29
+ let branch = '';
30
+ let version = '';
31
+ let model = '';
32
+ let startTime = '';
33
+ let endTime = '';
34
+ for (const event of events) {
35
+ if ('sessionId' in event && event.sessionId) {
36
+ sessionId = event.sessionId;
37
+ }
38
+ if ('cwd' in event && event.cwd) {
39
+ project = event.cwd;
40
+ }
41
+ if ('gitBranch' in event && event.gitBranch) {
42
+ branch = event.gitBranch;
43
+ }
44
+ if ('version' in event && event.version) {
45
+ version = event.version;
46
+ }
47
+ if (event.type === 'assistant') {
48
+ const ae = event;
49
+ if (ae.message?.model) {
50
+ model = ae.message.model;
51
+ }
52
+ }
53
+ // Track time range
54
+ const ts = 'timestamp' in event ? event.timestamp : undefined;
55
+ if (ts) {
56
+ if (!startTime || ts < startTime)
57
+ startTime = ts;
58
+ if (!endTime || ts > endTime)
59
+ endTime = ts;
60
+ }
61
+ }
62
+ return { sessionId, project, branch, claudeVersion: version, startTime, endTime, model };
63
+ }
64
+ /**
65
+ * Extract text from a tool result content (string or array).
66
+ */
67
+ function extractToolResultText(content) {
68
+ if (typeof content === 'string')
69
+ return content;
70
+ if (Array.isArray(content)) {
71
+ return content
72
+ .filter((item) => item.type === 'text' && item.text)
73
+ .map((item) => item.text)
74
+ .join('\n');
75
+ }
76
+ return '';
77
+ }
78
+ /**
79
+ * Parse events into a structured session with conversation turns.
80
+ */
81
+ export async function parseSession(filePath) {
82
+ const events = await readEvents(filePath);
83
+ const metadata = extractMetadata(events);
84
+ const turns = [];
85
+ let currentTurn = null;
86
+ // Accumulate assistant message fragments by message.id
87
+ // Each streaming chunk for the same message.id gets merged
88
+ const pendingAssistantChunks = new Map();
89
+ // Map tool_use id -> ToolCall for filling in results later
90
+ const toolCallMap = new Map();
91
+ function flushAssistantMessages() {
92
+ const messages = [];
93
+ for (const [messageId, data] of pendingAssistantChunks) {
94
+ messages.push({
95
+ messageId,
96
+ model: data.model,
97
+ thinkingBlocks: data.thinkingBlocks,
98
+ textBlocks: data.textBlocks,
99
+ toolCalls: data.toolCalls,
100
+ });
101
+ }
102
+ pendingAssistantChunks.clear();
103
+ return messages;
104
+ }
105
+ for (const event of events) {
106
+ if (event.type === 'user') {
107
+ const ue = event;
108
+ const content = ue.message.content;
109
+ if (typeof content === 'string') {
110
+ // New user prompt → new turn
111
+ if (currentTurn) {
112
+ currentTurn.assistantMessages = flushAssistantMessages();
113
+ turns.push(currentTurn);
114
+ }
115
+ currentTurn = {
116
+ turnNumber: turns.length + 1,
117
+ userMessage: content,
118
+ assistantMessages: [],
119
+ timestamp: ue.timestamp,
120
+ };
121
+ }
122
+ else if (Array.isArray(content)) {
123
+ // tool_result → same turn, fill in tool results
124
+ for (const block of content) {
125
+ if (block.type === 'tool_result') {
126
+ const tr = block;
127
+ const tc = toolCallMap.get(tr.tool_use_id);
128
+ if (tc) {
129
+ tc.result = extractToolResultText(tr.content);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ }
135
+ else if (event.type === 'assistant') {
136
+ const ae = event;
137
+ const msgId = ae.message.id;
138
+ if (!msgId)
139
+ continue;
140
+ let accumulated = pendingAssistantChunks.get(msgId);
141
+ if (!accumulated) {
142
+ accumulated = {
143
+ model: ae.message.model,
144
+ thinkingBlocks: [],
145
+ textBlocks: [],
146
+ toolCalls: [],
147
+ };
148
+ pendingAssistantChunks.set(msgId, accumulated);
149
+ }
150
+ for (const block of ae.message.content) {
151
+ switch (block.type) {
152
+ case 'thinking':
153
+ if (block.thinking) {
154
+ accumulated.thinkingBlocks.push(block.thinking);
155
+ }
156
+ break;
157
+ case 'text':
158
+ if (block.text && block.text.trim()) {
159
+ accumulated.textBlocks.push(block.text);
160
+ }
161
+ break;
162
+ case 'tool_use': {
163
+ const tc = {
164
+ name: block.name,
165
+ input: block.input,
166
+ result: '',
167
+ };
168
+ accumulated.toolCalls.push(tc);
169
+ toolCallMap.set(block.id, tc);
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ else if (event.type === 'system') {
176
+ const se = event;
177
+ if (se.subtype === 'turn_duration' && se.durationMs && currentTurn) {
178
+ currentTurn.durationMs = se.durationMs;
179
+ }
180
+ }
181
+ // Skip progress and file-history-snapshot events
182
+ }
183
+ // Flush the last turn
184
+ if (currentTurn) {
185
+ currentTurn.assistantMessages = flushAssistantMessages();
186
+ turns.push(currentTurn);
187
+ }
188
+ return { metadata, turns };
189
+ }
190
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export interface SessionInfo {
2
+ sessionId: string;
3
+ filePath: string;
4
+ modifiedAt: Date;
5
+ sizeBytes: number;
6
+ branch: string;
7
+ }
8
+ /**
9
+ * Encode a filesystem path to the directory name format used by Claude Code.
10
+ * e.g. "/Users/alice/dev/myproject" → "-Users-alice-dev-myproject"
11
+ */
12
+ export declare function encodeProjectPath(projectPath: string): string;
13
+ /**
14
+ * Decode a Claude Code project directory name back to a filesystem path.
15
+ * e.g. "-Users-alice-dev-myproject" → "/Users/alice/dev/myproject"
16
+ */
17
+ export declare function decodeProjectPath(encoded: string): string;
18
+ /**
19
+ * Get the Claude Code project data directory for a given project path.
20
+ */
21
+ export declare function getProjectDir(projectPath: string): string;
22
+ /**
23
+ * Extract the git branch from a JSONL session file by reading the first few lines.
24
+ * Returns an empty string if no gitBranch is found.
25
+ */
26
+ export declare function extractBranch(filePath: string): string;
27
+ /**
28
+ * List all session JSONL files for a project, sorted by modification time (newest first).
29
+ */
30
+ export declare function listSessions(projectPath: string): SessionInfo[];
31
+ /**
32
+ * Find a session by exact ID or prefix match.
33
+ * Returns the matching session, or throws if no match or ambiguous.
34
+ */
35
+ export declare function findSession(projectPath: string, idOrPrefix: string): SessionInfo;
@@ -0,0 +1,104 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import os from 'node:os';
4
+ const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), '.claude', 'projects');
5
+ /**
6
+ * Encode a filesystem path to the directory name format used by Claude Code.
7
+ * e.g. "/Users/alice/dev/myproject" → "-Users-alice-dev-myproject"
8
+ */
9
+ export function encodeProjectPath(projectPath) {
10
+ return projectPath.replace(/\//g, '-');
11
+ }
12
+ /**
13
+ * Decode a Claude Code project directory name back to a filesystem path.
14
+ * e.g. "-Users-alice-dev-myproject" → "/Users/alice/dev/myproject"
15
+ */
16
+ export function decodeProjectPath(encoded) {
17
+ // The encoded string starts with '-' which represents the leading '/'
18
+ // Then each '-' represents a '/'
19
+ return encoded.replace(/-/g, '/');
20
+ }
21
+ /**
22
+ * Get the Claude Code project data directory for a given project path.
23
+ */
24
+ export function getProjectDir(projectPath) {
25
+ const encoded = encodeProjectPath(projectPath);
26
+ return path.join(CLAUDE_PROJECTS_DIR, encoded);
27
+ }
28
+ /**
29
+ * Extract the git branch from a JSONL session file by reading the first few lines.
30
+ * Returns an empty string if no gitBranch is found.
31
+ */
32
+ export function extractBranch(filePath) {
33
+ const MAX_BYTES = 4096;
34
+ const fd = fs.openSync(filePath, 'r');
35
+ try {
36
+ const buf = Buffer.alloc(MAX_BYTES);
37
+ const bytesRead = fs.readSync(fd, buf, 0, MAX_BYTES, 0);
38
+ const chunk = buf.toString('utf8', 0, bytesRead);
39
+ const lines = chunk.split('\n');
40
+ for (const line of lines) {
41
+ if (!line.trim())
42
+ continue;
43
+ try {
44
+ const event = JSON.parse(line);
45
+ if (event.gitBranch) {
46
+ return event.gitBranch;
47
+ }
48
+ }
49
+ catch {
50
+ // skip malformed lines
51
+ }
52
+ }
53
+ }
54
+ finally {
55
+ fs.closeSync(fd);
56
+ }
57
+ return '';
58
+ }
59
+ /**
60
+ * List all session JSONL files for a project, sorted by modification time (newest first).
61
+ */
62
+ export function listSessions(projectPath) {
63
+ const projectDir = getProjectDir(projectPath);
64
+ if (!fs.existsSync(projectDir)) {
65
+ return [];
66
+ }
67
+ const entries = fs.readdirSync(projectDir, { withFileTypes: true });
68
+ const sessions = [];
69
+ for (const entry of entries) {
70
+ if (!entry.isFile() || !entry.name.endsWith('.jsonl')) {
71
+ continue;
72
+ }
73
+ const filePath = path.join(projectDir, entry.name);
74
+ const stat = fs.statSync(filePath);
75
+ const sessionId = entry.name.replace('.jsonl', '');
76
+ sessions.push({
77
+ sessionId,
78
+ filePath,
79
+ modifiedAt: stat.mtime,
80
+ sizeBytes: stat.size,
81
+ branch: extractBranch(filePath),
82
+ });
83
+ }
84
+ // Sort newest first
85
+ sessions.sort((a, b) => b.modifiedAt.getTime() - a.modifiedAt.getTime());
86
+ return sessions;
87
+ }
88
+ /**
89
+ * Find a session by exact ID or prefix match.
90
+ * Returns the matching session, or throws if no match or ambiguous.
91
+ */
92
+ export function findSession(projectPath, idOrPrefix) {
93
+ const sessions = listSessions(projectPath);
94
+ const matches = sessions.filter((s) => s.sessionId.startsWith(idOrPrefix));
95
+ if (matches.length === 0) {
96
+ throw new Error(`No session found matching "${idOrPrefix}"`);
97
+ }
98
+ if (matches.length > 1) {
99
+ const ids = matches.map((s) => s.sessionId).join('\n ');
100
+ throw new Error(`Ambiguous session prefix "${idOrPrefix}". Matches:\n ${ids}`);
101
+ }
102
+ return matches[0];
103
+ }
104
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-store.js","sourceRoot":"","sources":["../../src/core/session-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ /** Common fields present on most JSONL events */
2
+ export interface BaseEvent {
3
+ type: string;
4
+ uuid: string;
5
+ timestamp: string;
6
+ parentUuid: string | null;
7
+ isSidechain: boolean;
8
+ userType: string;
9
+ cwd: string;
10
+ sessionId: string;
11
+ version: string;
12
+ gitBranch: string;
13
+ }
14
+ export interface TextBlock {
15
+ type: 'text';
16
+ text: string;
17
+ }
18
+ export interface ThinkingBlock {
19
+ type: 'thinking';
20
+ thinking: string;
21
+ signature?: string;
22
+ }
23
+ export interface ToolUseBlock {
24
+ type: 'tool_use';
25
+ id: string;
26
+ name: string;
27
+ input: Record<string, unknown>;
28
+ }
29
+ export interface ToolResultBlock {
30
+ type: 'tool_result';
31
+ tool_use_id: string;
32
+ content: string | ToolResultContentItem[];
33
+ }
34
+ export interface ToolResultContentItem {
35
+ type: 'text' | 'image';
36
+ text?: string;
37
+ source?: unknown;
38
+ }
39
+ export type ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock;
40
+ export interface UserEvent extends BaseEvent {
41
+ type: 'user';
42
+ message: {
43
+ role: 'user';
44
+ content: string | ContentBlock[];
45
+ };
46
+ }
47
+ export interface AssistantEvent extends BaseEvent {
48
+ type: 'assistant';
49
+ message: {
50
+ role: 'assistant';
51
+ id: string;
52
+ model: string;
53
+ stop_reason: string | null;
54
+ content: ContentBlock[];
55
+ usage?: {
56
+ input_tokens: number;
57
+ output_tokens: number;
58
+ cache_creation_input_tokens?: number;
59
+ cache_read_input_tokens?: number;
60
+ };
61
+ };
62
+ requestId?: string;
63
+ }
64
+ export interface ProgressEvent extends BaseEvent {
65
+ type: 'progress';
66
+ data: {
67
+ type: string;
68
+ [key: string]: unknown;
69
+ };
70
+ toolUseID: string;
71
+ parentToolUseID: string;
72
+ }
73
+ export interface SystemEvent extends BaseEvent {
74
+ type: 'system';
75
+ subtype: string;
76
+ durationMs?: number;
77
+ hookCount?: number;
78
+ hookInfos?: Array<{
79
+ command: string;
80
+ }>;
81
+ hookErrors?: unknown[];
82
+ stopReason?: string;
83
+ level?: string;
84
+ [key: string]: unknown;
85
+ }
86
+ export interface FileHistorySnapshotEvent {
87
+ type: 'file-history-snapshot';
88
+ messageId: string;
89
+ snapshot: {
90
+ messageId: string;
91
+ trackedFileBackups: Record<string, unknown>;
92
+ timestamp: string;
93
+ };
94
+ isSnapshotUpdate: boolean;
95
+ }
96
+ export type SessionEvent = UserEvent | AssistantEvent | ProgressEvent | SystemEvent | FileHistorySnapshotEvent;
97
+ export interface SessionMetadata {
98
+ sessionId: string;
99
+ project: string;
100
+ branch: string;
101
+ claudeVersion: string;
102
+ startTime: string;
103
+ endTime: string;
104
+ model: string;
105
+ }
106
+ export interface ToolCall {
107
+ name: string;
108
+ input: Record<string, unknown>;
109
+ result: string;
110
+ }
111
+ export interface AssistantMessage {
112
+ messageId: string;
113
+ model: string;
114
+ thinkingBlocks: string[];
115
+ textBlocks: string[];
116
+ toolCalls: ToolCall[];
117
+ }
118
+ export interface ConversationTurn {
119
+ turnNumber: number;
120
+ userMessage: string;
121
+ assistantMessages: AssistantMessage[];
122
+ durationMs?: number;
123
+ timestamp?: string;
124
+ }
125
+ export interface ParsedSession {
126
+ metadata: SessionMetadata;
127
+ turns: ConversationTurn[];
128
+ }
129
+ export interface FormatOptions {
130
+ showThinking: 'collapsed' | 'expanded' | 'hidden';
131
+ showTools: boolean;
132
+ maxToolLines: number;
133
+ }
@@ -0,0 +1,5 @@
1
+ // ============================================================
2
+ // Raw JSONL Event Types (as stored by Claude Code)
3
+ // ============================================================
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,mDAAmD;AACnD,+DAA+D"}
@@ -0,0 +1,5 @@
1
+ import type { ParsedSession, FormatOptions } from '../core/types.js';
2
+ /**
3
+ * Format a parsed session into Markdown.
4
+ */
5
+ export declare function formatSession(session: ParsedSession, options?: Partial<FormatOptions>): string;
@@ -0,0 +1,120 @@
1
+ import { formatDuration, formatTimestamp, truncateLines, details, formatToolInput, } from './templates.js';
2
+ const DEFAULT_OPTIONS = {
3
+ showThinking: 'collapsed',
4
+ showTools: true,
5
+ maxToolLines: 50,
6
+ };
7
+ /**
8
+ * Format a parsed session into Markdown.
9
+ */
10
+ export function formatSession(session, options = {}) {
11
+ const opts = { ...DEFAULT_OPTIONS, ...options };
12
+ const parts = [];
13
+ parts.push(renderHeader(session));
14
+ for (const turn of session.turns) {
15
+ parts.push(renderTurn(turn, opts));
16
+ }
17
+ return parts.join('\n\n---\n\n') + '\n';
18
+ }
19
+ function renderHeader(session) {
20
+ const { metadata } = session;
21
+ const lines = [];
22
+ const isMerged = metadata.sessionId.includes(',');
23
+ if (isMerged) {
24
+ lines.push('# Merged Session Report');
25
+ lines.push('');
26
+ const ids = metadata.sessionId.split(',');
27
+ lines.push(`- **Sessions** (${ids.length}):`);
28
+ for (const id of ids) {
29
+ lines.push(` - \`${id}\``);
30
+ }
31
+ }
32
+ else {
33
+ lines.push('# Session Report');
34
+ lines.push('');
35
+ lines.push(`- **Session ID**: \`${metadata.sessionId}\``);
36
+ }
37
+ lines.push(`- **Project**: \`${metadata.project}\``);
38
+ if (metadata.branch) {
39
+ lines.push(`- **Branch**: \`${metadata.branch}\``);
40
+ }
41
+ if (metadata.model) {
42
+ lines.push(`- **Model**: \`${metadata.model}\``);
43
+ }
44
+ if (metadata.startTime && metadata.endTime) {
45
+ const start = formatTimestamp(metadata.startTime);
46
+ const end = formatTimestamp(metadata.endTime);
47
+ const durationMs = new Date(metadata.endTime).getTime() - new Date(metadata.startTime).getTime();
48
+ const duration = formatDuration(durationMs);
49
+ if (start === end) {
50
+ lines.push(`- **Date**: ${start}`);
51
+ }
52
+ else {
53
+ lines.push(`- **Date**: ${start} - ${end} (${duration})`);
54
+ }
55
+ }
56
+ if (session.turns.length > 0) {
57
+ lines.push(`- **Turns**: ${session.turns.length}`);
58
+ }
59
+ return lines.join('\n');
60
+ }
61
+ function renderTurn(turn, opts) {
62
+ const parts = [];
63
+ // Turn header
64
+ let turnHeader = `## Turn ${turn.turnNumber}`;
65
+ if (turn.durationMs) {
66
+ turnHeader += ` (${formatDuration(turn.durationMs)})`;
67
+ }
68
+ parts.push(turnHeader);
69
+ // User message
70
+ parts.push('### User');
71
+ parts.push(turn.userMessage
72
+ .split('\n')
73
+ .map((line) => `> ${line}`)
74
+ .join('\n'));
75
+ // Assistant messages
76
+ for (const msg of turn.assistantMessages) {
77
+ parts.push(renderAssistantMessage(msg, opts));
78
+ }
79
+ return parts.join('\n\n');
80
+ }
81
+ function renderAssistantMessage(msg, opts) {
82
+ const parts = [];
83
+ parts.push('### Assistant');
84
+ // Thinking blocks
85
+ if (opts.showThinking !== 'hidden' && msg.thinkingBlocks.length > 0) {
86
+ const thinking = msg.thinkingBlocks.join('\n\n');
87
+ if (opts.showThinking === 'expanded') {
88
+ parts.push(details('Thinking', thinking, true));
89
+ }
90
+ else {
91
+ parts.push(details('Thinking', thinking, false));
92
+ }
93
+ }
94
+ // Text blocks
95
+ for (const text of msg.textBlocks) {
96
+ parts.push(text);
97
+ }
98
+ // Tool calls
99
+ if (opts.showTools) {
100
+ for (const tc of msg.toolCalls) {
101
+ parts.push(renderToolCall(tc, opts));
102
+ }
103
+ }
104
+ return parts.join('\n\n');
105
+ }
106
+ function renderToolCall(tc, opts) {
107
+ const inputDisplay = formatToolInput(tc.name, tc.input);
108
+ const header = inputDisplay
109
+ ? `**Tool: ${tc.name}** (${inputDisplay})`
110
+ : `**Tool: ${tc.name}**`;
111
+ if (!tc.result) {
112
+ return header;
113
+ }
114
+ const { text, truncated, totalLines } = truncateLines(tc.result, opts.maxToolLines);
115
+ const summaryExtra = truncated
116
+ ? ` (${totalLines} lines, showing first ${opts.maxToolLines})`
117
+ : ` (${totalLines} lines)`;
118
+ return `${header}\n\n${details(`Result${summaryExtra}`, '```\n' + text + (truncated ? '\n...' : '') + '\n```', false)}`;
119
+ }
120
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/formatter/markdown.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,cAAc,EACd,eAAe,EACf,aAAa,EACb,OAAO,EACP,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,MAAM,eAAe,GAAkB;IACrC,YAAY,EAAE,WAAW;IACzB,SAAS,EAAE,IAAI;IACf,YAAY,EAAE,EAAE;CACjB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAsB,EACtB,UAAkC,EAAE;IAEpC,MAAM,IAAI,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC;IAChD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC;AAC1C,CAAC;AAED,SAAS,YAAY,CAAC,OAAsB;IAC1C,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAElD,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,uBAAuB,QAAQ,CAAC,SAAS,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,oBAAoB,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;IAErD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,CAAC,IAAI,CAAC,mBAAmB,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,CAAC,IAAI,CAAC,kBAAkB,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,UAAU,GACd,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAChF,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAE5C,IAAI,KAAK,KAAK,GAAG,EAAE,CAAC;YAClB,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,eAAe,KAAK,MAAM,GAAG,KAAK,QAAQ,GAAG,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,UAAU,CAAC,IAAsB,EAAE,IAAmB;IAC7D,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,cAAc;IACd,IAAI,UAAU,GAAG,WAAW,IAAI,CAAC,UAAU,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,UAAU,IAAI,KAAK,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;IACxD,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEvB,eAAe;IACf,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,WAAW;SACb,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;IAEF,qBAAqB;IACrB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,sBAAsB,CAC7B,GAAqB,EACrB,IAAmB;IAEnB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAE5B,kBAAkB;IAClB,IAAI,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,GAAG,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAG,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,IAAI,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,cAAc;IACd,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,aAAa;IACb,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,cAAc,CAAC,EAAY,EAAE,IAAmB;IACvD,MAAM,YAAY,GAAG,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,YAAY;QACzB,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,OAAO,YAAY,GAAG;QAC1C,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;IAE3B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;QACf,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,SAAS;QAC5B,CAAC,CAAC,KAAK,UAAU,yBAAyB,IAAI,CAAC,YAAY,GAAG;QAC9D,CAAC,CAAC,KAAK,UAAU,SAAS,CAAC;IAE7B,OAAO,GAAG,MAAM,OAAO,OAAO,CAAC,SAAS,YAAY,EAAE,EAAE,OAAO,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;AAC1H,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Format a duration in milliseconds to a human-readable string.
3
+ */
4
+ export declare function formatDuration(ms: number): string;
5
+ /**
6
+ * Format an ISO timestamp to a localized date-time string.
7
+ */
8
+ export declare function formatTimestamp(iso: string): string;
9
+ /**
10
+ * Truncate text to a maximum number of lines, with a note if truncated.
11
+ */
12
+ export declare function truncateLines(text: string, maxLines: number): {
13
+ text: string;
14
+ truncated: boolean;
15
+ totalLines: number;
16
+ };
17
+ /**
18
+ * Wrap content in a collapsible <details> block.
19
+ */
20
+ export declare function details(summary: string, content: string, open?: boolean): string;
21
+ /**
22
+ * Format a tool input for display. Extracts the most relevant parameter.
23
+ */
24
+ export declare function formatToolInput(name: string, input: Record<string, unknown>): string;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Format a duration in milliseconds to a human-readable string.
3
+ */
4
+ export function formatDuration(ms) {
5
+ const seconds = Math.floor(ms / 1000);
6
+ if (seconds < 60)
7
+ return `${seconds}秒`;
8
+ const minutes = Math.floor(seconds / 60);
9
+ const remainingSeconds = seconds % 60;
10
+ if (minutes < 60) {
11
+ return remainingSeconds > 0 ? `${minutes}分${remainingSeconds}秒` : `${minutes}分`;
12
+ }
13
+ const hours = Math.floor(minutes / 60);
14
+ const remainingMinutes = minutes % 60;
15
+ return remainingMinutes > 0 ? `${hours}時間${remainingMinutes}分` : `${hours}時間`;
16
+ }
17
+ /**
18
+ * Format an ISO timestamp to a localized date-time string.
19
+ */
20
+ export function formatTimestamp(iso) {
21
+ const d = new Date(iso);
22
+ const pad = (n) => String(n).padStart(2, '0');
23
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
24
+ }
25
+ /**
26
+ * Truncate text to a maximum number of lines, with a note if truncated.
27
+ */
28
+ export function truncateLines(text, maxLines) {
29
+ const lines = text.split('\n');
30
+ if (lines.length <= maxLines) {
31
+ return { text, truncated: false, totalLines: lines.length };
32
+ }
33
+ return {
34
+ text: lines.slice(0, maxLines).join('\n'),
35
+ truncated: true,
36
+ totalLines: lines.length,
37
+ };
38
+ }
39
+ /**
40
+ * Wrap content in a collapsible <details> block.
41
+ */
42
+ export function details(summary, content, open = false) {
43
+ const openAttr = open ? ' open' : '';
44
+ return `<details${openAttr}><summary>${summary}</summary>\n\n${content}\n\n</details>`;
45
+ }
46
+ /**
47
+ * Format a tool input for display. Extracts the most relevant parameter.
48
+ */
49
+ export function formatToolInput(name, input) {
50
+ // Show the most relevant parameter based on tool name
51
+ switch (name) {
52
+ case 'Read':
53
+ return input.file_path ? `\`${input.file_path}\`` : '';
54
+ case 'Write':
55
+ return input.file_path ? `\`${input.file_path}\`` : '';
56
+ case 'Edit':
57
+ return input.file_path ? `\`${input.file_path}\`` : '';
58
+ case 'Bash':
59
+ return input.command ? `\`${String(input.command).substring(0, 100)}\`` : '';
60
+ case 'Glob':
61
+ return input.pattern ? `\`${input.pattern}\`` : '';
62
+ case 'Grep':
63
+ return input.pattern ? `\`${input.pattern}\`` : '';
64
+ case 'Task':
65
+ return input.description ? `"${input.description}"` : '';
66
+ case 'WebFetch':
67
+ return input.url ? `\`${input.url}\`` : '';
68
+ case 'WebSearch':
69
+ return input.query ? `"${input.query}"` : '';
70
+ default:
71
+ // Generic: show first string parameter
72
+ for (const [, val] of Object.entries(input)) {
73
+ if (typeof val === 'string' && val.length > 0) {
74
+ return `\`${val.substring(0, 80)}\``;
75
+ }
76
+ }
77
+ return '';
78
+ }
79
+ }
80
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/formatter/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { runList } from './cli/commands/list.js';
4
+ import { runShow } from './cli/commands/show.js';
5
+ import { runExport } from './cli/commands/export.js';
6
+ const program = new Command();
7
+ program
8
+ .name('ccdigest')
9
+ .description('Format Claude Code session data into readable Markdown')
10
+ .version('0.1.0');
11
+ program
12
+ .command('list')
13
+ .description('List available sessions')
14
+ .option('--project <path>', 'Project path (defaults to cwd)')
15
+ .option('--branch <name>', 'Filter by git branch')
16
+ .option('--json', 'Output as JSON')
17
+ .action(runList);
18
+ const showFormatOptions = (cmd) => cmd
19
+ .option('--no-thinking', 'Hide thinking blocks')
20
+ .option('--show-thinking', 'Show thinking blocks expanded')
21
+ .option('--no-tools', 'Hide tool calls')
22
+ .option('--max-tool-lines <n>', 'Max lines for tool results (default: 50)')
23
+ .option('--project <path>', 'Project path (defaults to cwd)');
24
+ showFormatOptions(program
25
+ .command('show <session-ids...>')
26
+ .description('Display session(s) as Markdown (stdout). Multiple IDs are merged chronologically.')).action(runShow);
27
+ showFormatOptions(program
28
+ .command('export <session-ids...>')
29
+ .description('Export session(s) to a Markdown file. Multiple IDs are merged chronologically.')
30
+ .requiredOption('-o, --output <file>', 'Output file path')).action(runExport);
31
+ program.parse();
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,wDAAwD,CAAC;KACrE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,yBAAyB,CAAC;KACtC,MAAM,CAAC,kBAAkB,EAAE,gCAAgC,CAAC;KAC5D,MAAM,CAAC,iBAAiB,EAAE,sBAAsB,CAAC;KACjD,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;KAClC,MAAM,CAAC,OAAO,CAAC,CAAC;AAEnB,MAAM,iBAAiB,GAAG,CAAC,GAAY,EAAE,EAAE,CACzC,GAAG;KACA,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC;KAC/C,MAAM,CAAC,iBAAiB,EAAE,+BAA+B,CAAC;KAC1D,MAAM,CAAC,YAAY,EAAE,iBAAiB,CAAC;KACvC,MAAM,CAAC,sBAAsB,EAAE,0CAA0C,CAAC;KAC1E,MAAM,CAAC,kBAAkB,EAAE,gCAAgC,CAAC,CAAC;AAElE,iBAAiB,CACf,OAAO;KACJ,OAAO,CAAC,uBAAuB,CAAC;KAChC,WAAW,CAAC,mFAAmF,CAAC,CACpG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AAElB,iBAAiB,CACf,OAAO;KACJ,OAAO,CAAC,yBAAyB,CAAC;KAClC,WAAW,CAAC,gFAAgF,CAAC;KAC7F,cAAc,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,CAC7D,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;AAEpB,OAAO,CAAC,KAAK,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@henteko/ccdigest",
3
+ "version": "0.1.0",
4
+ "description": "Format Claude Code session data into readable Markdown for team sharing and code review",
5
+ "license": "MIT",
6
+ "author": "henteko",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/henteko/ccdigest.git"
10
+ },
11
+ "keywords": [
12
+ "claude-code",
13
+ "session",
14
+ "markdown",
15
+ "export",
16
+ "cli"
17
+ ],
18
+ "type": "module",
19
+ "main": "dist/index.js",
20
+ "bin": {
21
+ "ccdigest": "dist/index.js"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "LICENSE",
26
+ "README.md"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc",
33
+ "dev": "tsx src/index.ts",
34
+ "test": "vitest run",
35
+ "test:watch": "vitest",
36
+ "prepublishOnly": "npm run build && npm test"
37
+ },
38
+ "dependencies": {
39
+ "commander": "^13.1.0"
40
+ },
41
+ "devDependencies": {
42
+ "typescript": "^5.7.0",
43
+ "vitest": "^3.0.0",
44
+ "tsx": "^4.19.0",
45
+ "@types/node": "^22.0.0"
46
+ }
47
+ }