refactor(module): migrate module paths from forge.lthn.ai to dappco.re
All checks were successful
Security Scan / security (pull_request) Successful in 12s
Test / test (pull_request) Successful in 1m18s

Update module path to dappco.re/go/core/session, dependency to
dappco.re/go/core/log v0.1.0, all Go import paths, and documentation
references. Remove duplicate test functions found during migration.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-22 01:37:11 +00:00
parent fb672f3b3a
commit 7f2fd424cf
19 changed files with 175 additions and 254 deletions

4
.gitignore vendored
View file

@ -1,2 +1,4 @@
.core/
.idea/
.vscode/
*.log
.core/

View file

@ -2,7 +2,7 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Claude Code JSONL transcript parser, analytics engine, and HTML/video renderer. Module: `forge.lthn.ai/core/go-session`
Claude Code JSONL transcript parser, analytics engine, and HTML/video renderer. Module: `dappco.re/go/core/session`
## Commands
@ -45,6 +45,6 @@ Coverage target: maintain ≥90.9%.
- Explicit types on all function signatures and struct fields
- `go test ./...` and `go vet ./...` must pass before commit
- SPDX header on all source files: `// SPDX-Licence-Identifier: EUPL-1.2`
- Error handling: all errors must use `coreerr.E(op, msg, err)` from `forge.lthn.ai/core/go-log`, never `fmt.Errorf` or `errors.New`
- Error handling: all errors must use `coreerr.E(op, msg, err)` from `dappco.re/go/core/log`, never `fmt.Errorf` or `errors.New`
- Conventional commits: `type(scope): description`
- Co-Author trailer: `Co-Authored-By: Virgil <virgil@lethean.io>`

View file

@ -2,22 +2,111 @@
> Relevant knowledge from OpenBrain.
## 1. go-session [convention] (score: 0.636)
### 1. go-session [service] (score: 0.080)
Documentation
[go-session] Licence
- `/Users/snider/Code/go-session/docs/architecture.md` — JSONL format, parsing pipeline, event types, analytics, HTML rendering, XSS protection
- `/Users/snider/Code/go-session/docs/development.md` — prerequisites, build/test commands, test patterns, coding standards
- `/Users/snider/Code/go-session/docs/history.md` — completed phases, known limitations, future considerations
EUPL-1.2
## 2. go-session [service] (score: 0.604)
### 2. go-session [convention] (score: 0.021)
[go-session] Pages
Coding Standards
- [[Session-Format]] -- JSONL structure, parsing logic, and event types
- [[Rendering]] -- HTML timeline and MP4 video output
- UK English throughout (colour, licence, initialise)
- `declare(strict_types=1)` equivalent: explicit types on all signatures
- `go test ./...` must pass before commit
- `go vet ./...` must be clean before commit
- SPDX-Licence-Identifier: EUPL-1.2 header on all source files
- Conventional commits: `type(scope): description`
- Co-Author: `Co-Authored-By: Virgil <virgil@lethean.io>`
- Test naming: `TestFunctionName_Context_Good/Bad/Ugly`
- New tool types: add struct in `parser.go`, case in `extractToolInput`, label in `html.go`, tape entry in `video.go`, and tests in `parser_test.go`
## 3. go-session [service] (score: 0.563)
### 3. go-session [service] (score: 0.006)
[go-session] Labels
The input label adapts to the tool type:
- **Bash**: "Command"
- **Read, Glob, Grep**: "Target"
- **Edit, Write**: "File"
- **User messages**: "Message"
- **Assistant**: "Response"
### 4. go-session [service] (score: -0.002)
[go-session] Installation
```bash
go get dappco.re/go/core/session@latest
```
### 5. go-session [convention] (score: -0.004)
Commands
```bash
go test ./... # Run all tests
go test -v -run Name # Run single test
go vet ./... # Vet the package
```
### 6. go-session [service] (score: -0.023)
[go-session] Event Card Layout
Each card displays:
| Element | Description |
|---------|-------------|
| Timestamp | `HH:MM:SS` of the event |
| Tool badge | Colour-coded tool name |
| Input summary | Truncated to 120 characters |
| Duration | Formatted as ms/s/min/hr |
| Status icon | Green tick or red cross for tool calls |
Clicking a card expands it to show the full input (labelled contextually as Command, Message, File, or Target) and the complete output.
### 7. go-session [service] (score: -0.024)
[go-session] Tape Configuration
The generated tape uses these defaults:
```
FontSize 16
Width 1400
Height 800
TypingSpeed 30ms
Theme "Catppuccin Mocha"
Shell bash
```
See also: [[Home]] | [[Session-Format]]
### 8. go-session [service] (score: -0.031)
[go-session] Prerequisites
```bash
go install github.com/charmbracelet/vhs@latest
```
### 9. go-session [service] (score: -0.040)
[go-session] How It Works
1. A VHS `.tape` script is generated from the session events
2. The tape uses the Catppuccin Mocha theme at 1400x800 resolution
3. Only `tool_use` events are rendered:
- **Bash**: Shows the command being typed, abbreviated output, and a status indicator
- **Read/Edit/Write**: Shows a comment line with the file path
- **Task**: Shows an "Agent:" comment with the task description
4. Each event includes a brief pause for readability
5. VHS renders the tape to the specified MP4 path
### 10. go-session [service] (score: -0.044)
[go-session] Core Types
@ -45,99 +134,3 @@ type Event struct {
}
```
## 4. go-session [service] (score: 0.560)
[go-session] Installation
```bash
go get forge.lthn.ai/core/go-session@latest
```
## 5. go-session [service] (score: 0.557)
[go-session] API Summary
| Function | Description |
|----------|-------------|
| `ListSessions(dir)` | List all `.jsonl` sessions in a directory, sorted newest first |
| `ParseTranscript(path)` | Parse a JSONL file into a structured `*Session` |
| `Search(dir, query)` | Search tool events across all sessions |
| `RenderHTML(sess, path)` | Generate self-contained HTML timeline |
| `RenderMP4(sess, path)` | Generate MP4 video via VHS (Charmbracelet) |
## 6. go-session [service] (score: 0.536)
[go-session] Prerequisites
```bash
go install github.com/charmbracelet/vhs@latest
```
## 7. go-session [service] (score: 0.524)
[go-session] Quick Start
```go
package main
import (
"fmt"
"log"
"forge.lthn.ai/core/go-session"
)
func main() {
// Parse a single transcript
sess, err := session.ParseTranscript("~/.claude/projects/abc123.jsonl")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Session %s: %d events over %s\n",
sess.ID, len(sess.Events), sess.EndTime.Sub(sess.StartTime))
// Render to interactive HTML
if err := session.RenderHTML(sess, "timeline.html"); err != nil {
log.Fatal(err)
}
}
```
## 8. go-session [service] (score: 0.523)
[go-session] Usage
```go
sess, err := session.ParseTranscript("session.jsonl")
if err != nil {
log.Fatal(err)
}
if err := session.RenderMP4(sess, "output/session.mp4"); err != nil {
log.Fatal(err)
}
```
## 9. go-session [service] (score: 0.520)
[go-session] Tape Configuration
The generated tape uses these defaults:
```
FontSize 16
Width 1400
Height 800
TypingSpeed 30ms
Theme "Catppuccin Mocha"
Shell bash
```
See also: [[Home]] | [[Session-Format]]
## 10. go-session [service] (score: 0.509)
[go-session] Rendering
go-session provides two output formats for visualising parsed sessions: a self-contained HTML timeline and an MP4 video rendered via Charmbracelet VHS.

View file

@ -8,11 +8,21 @@ Read RECENT.md for recent changes.
Work in the src/ directory. Follow the conventions in CLAUDE.md.
## SANDBOX BOUNDARY (HARD LIMIT)
You are restricted to the current directory and its subdirectories ONLY.
- Do NOT use absolute paths (e.g., /Users/..., /home/...)
- Do NOT navigate with cd .. or cd /
- Do NOT edit files outside this repository
- Do NOT access parent directories or other repos
- Any path in Edit/Write tool calls MUST be relative to the current directory
Violation of these rules will cause your work to be rejected.
## Workflow
If PLAN.md exists, you MUST work through it phase by phase:
1. Complete all tasks in the current phase
2. STOP and commit before moving on: type(scope): phase N - description
2. STOP and commit before moving on: `type(scope): phase N - description`
3. Only then start the next phase
4. If you are blocked or unsure, write BLOCKED.md explaining the question and stop
5. Do NOT skip phases or combine multiple phases into one commit
@ -21,9 +31,27 @@ Each phase = one commit. This is not optional.
If no PLAN.md, complete TODO.md as a single unit of work.
## Closeout Sequence (MANDATORY before final commit)
After completing your work, you MUST run this polish cycle using the core plugin agents:
### Pass 1: Code Review
Use the Agent tool to launch the `core:agent-task-code-review` agent. It will review all your changes for bugs, security issues, and convention violations. Fix ALL findings rated >= 50 confidence before proceeding.
### Pass 2: Build + Test
Run the test suite (`go test ./...` or `composer test`). Fix any failures.
### Pass 3: Simplify
Use the Agent tool to launch the `core:agent-task-code-simplifier` agent. It will consolidate duplicates, remove dead code, and flatten complexity. Let it work, then verify the build still passes.
### Pass 4: Final Review
Run the `core:agent-task-code-review` agent ONE MORE TIME on the simplified code. If clean, commit. If findings remain, fix and re-check.
Each pass catches things the previous one introduced. Do NOT skip passes. The goal: zero findings on the final review.
## Commit Convention
Commit message format: type(scope): description
Co-Author: Co-Authored-By: Virgil <virgil@lethean.io>
Commit message format: `type(scope): description`
Co-Author: `Co-Authored-By: Virgil <virgil@lethean.io>`
Do NOT push. Commit only — a reviewer will verify and push.

View file

@ -1,4 +1,4 @@
[![Go Reference](https://pkg.go.dev/badge/forge.lthn.ai/core/go-session.svg)](https://pkg.go.dev/forge.lthn.ai/core/go-session)
[![Go Reference](https://pkg.go.dev/badge/dappco.re/go/core/session.svg)](https://pkg.go.dev/dappco.re/go/core/session)
[![License: EUPL-1.2](https://img.shields.io/badge/License-EUPL--1.2-blue.svg)](LICENSE.md)
[![Go Version](https://img.shields.io/badge/Go-1.26-00ADD8?style=flat&logo=go)](go.mod)
@ -6,14 +6,14 @@
Claude Code JSONL transcript parser, analytics engine, and HTML timeline renderer. Parses Claude Code session files into structured event arrays (tool calls with round-trip durations, user and assistant messages), computes per-tool analytics (call counts, error rates, average and peak latency, estimated token usage), renders self-contained HTML timelines with collapsible panels and client-side search, and generates VHS tape scripts for MP4 video output. No external runtime dependencies — stdlib only.
**Module**: `forge.lthn.ai/core/go-session`
**Module**: `dappco.re/go/core/session`
**Licence**: EUPL-1.2
**Language**: Go 1.25
**Language**: Go 1.26
## Quick Start
```go
import "forge.lthn.ai/core/go-session"
import "dappco.re/go/core/session"
sess, stats, err := session.ParseTranscript("/path/to/session.jsonl")
analytics := session.Analyse(sess)

View file

@ -1,6 +1,12 @@
# Recent Changes
```text
```
fb672f3 Merge pull request '[agent/claude:sonnet] Fix CodeRabbit findings. These are mostly markdown linting i...' (#3) from agent/fix-coderabbit-findings--these-are-mostl into main
73e627f fix(coderabbit): address markdown linting findings
66fbb42 Merge pull request '[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate...' (#2) from agent/dx-audit-and-fix--1--review-claude-md into main
7f0a7ed fix(dx): audit and fix error handling, SPDX headers, coverage, and CLAUDE.md
11e3bb3 Merge pull request '[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate...' (#1) from agent/dx-audit-and-fix--1--review-claude-md into main
c769692 fix(dx): fix coreerr.E() signatures, add SPDX headers and tests
55ceab4 refactor(error-handling): replace fmt.Errorf and errors.New with coreerr.E()
a07e41a chore: add .core/ and .idea/ to .gitignore
50d1c3f docs: add CLAUDE.md project instructions
@ -15,10 +21,4 @@ cb7b5de chore: sync workspace dependency versions
1458694 refactor: apply go fix modernizers for Go 1.26
5dc4078 chore: bump go directive to 1.26.0
325fddd docs: add README with quick start and docs links
91e7cdb Merge remote-tracking branch 'origin/main'
3e00791 docs: graduate TODO/FINDINGS into production documentation
1031905 feat(parser): add robustness for truncated JSONL and malformed lines
8e91626 docs: mark Phase 3 timeline UI as complete
9b32678 docs(todo): mark Phase 1+2 complete with commit hash a6fb934
a6fb934 feat(parser): Phase 1+2 — parse stats, truncation detection, session analytics
```

18
TODO.md
View file

@ -1,8 +1,16 @@
# TASK: Replace ALL fmt.Errorf and errors.New in production code with coreerr.E() from go-log. ~8 instances. Import coreerr "forge.lthn.ai/core/go-log". Run tests after.
# TODO
**Repo:** core/go-session
**Status:** ready
## Task
Update go.mod require lines from forge.lthn.ai to dappco.re paths. Update versions: core v0.5.0, log v0.1.0, io v0.2.0. Update all .go import paths. Run go mod tidy and go build ./...
## Objective
> **Status:** Complete. All module paths migrated to `dappco.re/go/core/...`.
## Checklist
- [x] Read and understand the codebase
- [x] Implement the required changes
- [x] Run build: `go build ./...`
- [x] Run tests: `go test ./...`
- [ ] Commit with conventional commit message
## Context
Replace ALL fmt.Errorf and errors.New in production code with coreerr.E() from go-log. ~8 instances. Import coreerr "forge.lthn.ai/core/go-log". Run tests after.

View file

@ -5,7 +5,7 @@ description: Internals of go-session -- JSONL format, parsing pipeline, event mo
# Architecture
Module: `forge.lthn.ai/core/go-session`
Module: `dappco.re/go/core/session`
## Overview

View file

@ -210,7 +210,7 @@ Co-Authored-By: Virgil <virgil@lethean.io>
## Module Path and Go Workspace
The module path is `forge.lthn.ai/core/go-session`. If this package is used within a Go workspace, add it with:
The module path is `dappco.re/go/core/session`. If this package is used within a Go workspace, add it with:
```bash
go work use ./go-session

View file

@ -2,7 +2,7 @@
## Origin
Extracted from `forge.lthn.ai/core/go` (`pkg/session/`) on 19 February 2026. The initial extraction provided a working parser that read Claude Code JSONL transcripts into `Event` arrays and identified the seven supported tool types: Bash, Read, Edit, Write, Grep, Glob, and Task.
Extracted from `dappco.re/go/core` (`pkg/session/`) on 19 February 2026. The initial extraction provided a working parser that read Claude Code JSONL transcripts into `Event` arrays and identified the seven supported tool types: Bash, Read, Edit, Write, Grep, Glob, and Task.
## Completed Phases

View file

@ -7,14 +7,14 @@ description: Claude Code JSONL transcript parser, analytics engine, and HTML tim
`go-session` parses Claude Code JSONL session transcripts into structured event arrays, computes per-tool analytics, renders self-contained HTML timelines with client-side search, and generates VHS tape scripts for MP4 video output. It has no external runtime dependencies -- stdlib only.
**Module path:** `forge.lthn.ai/core/go-session`
**Module path:** `dappco.re/go/core/session`
**Go version:** 1.26
**Licence:** EUPL-1.2
## Quick Start
```go
import "forge.lthn.ai/core/go-session"
import "dappco.re/go/core/session"
// Parse a single session file
sess, stats, err := session.ParseTranscript("/path/to/session.jsonl")

4
go.mod
View file

@ -1,9 +1,9 @@
module forge.lthn.ai/core/go-session
module dappco.re/go/core/session
go 1.26.0
require (
forge.lthn.ai/core/go-log v0.0.4
dappco.re/go/core/log v0.1.0
github.com/stretchr/testify v1.11.1
)

4
go.sum
View file

@ -1,5 +1,5 @@
forge.lthn.ai/core/go-log v0.0.4 h1:KTuCEPgFmuM8KJfnyQ8vPOU1Jg654W74h8IJvfQMfv0=
forge.lthn.ai/core/go-log v0.0.4/go.mod h1:r14MXKOD3LF/sI8XUJQhRk/SZHBE7jAFVuCfgkXoZPw=
dappco.re/go/core/log v0.1.0 h1:pa71Vq2TD2aoEUQWFKwNcaJ3GBY8HbaNGqtE688Unyc=
dappco.re/go/core/log v0.1.0/go.mod h1:Nkqb8gsXhZAO8VLpx7B8i1iAmohhzqA20b9Zr8VUcJs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View file

@ -8,7 +8,7 @@ import (
"strings"
"time"
coreerr "forge.lthn.ai/core/go-log"
coreerr "dappco.re/go/core/log"
)
// RenderHTML generates a self-contained HTML timeline from a session.

View file

@ -1,13 +1,13 @@
# go-session
`forge.lthn.ai/core/go-session` -- Claude Code session parser and visualiser.
`dappco.re/go/core/session` -- Claude Code session parser and visualiser.
Reads JSONL transcript files produced by Claude Code, extracts structured events, and renders them as interactive HTML timelines or MP4 videos. Zero external dependencies (stdlib only).
## Installation
```bash
go get forge.lthn.ai/core/go-session@latest
go get dappco.re/go/core/session@latest
```
## Core Types
@ -45,7 +45,7 @@ import (
"fmt"
"log"
"forge.lthn.ai/core/go-session"
"dappco.re/go/core/session"
)
func main() {

View file

@ -92,7 +92,7 @@ if err := session.RenderMP4(sess, "output/session.mp4"); err != nil {
The generated tape uses these defaults:
```text
```
FontSize 16
Width 1400
Height 800

View file

@ -14,7 +14,7 @@ import (
"strings"
"time"
coreerr "forge.lthn.ai/core/go-log"
coreerr "dappco.re/go/core/log"
)
// maxScannerBuffer is the maximum line length the scanner will accept.

View file

@ -1454,114 +1454,4 @@ func TestListSessions_TruncatedFile_Good(t *testing.T) {
// --- PruneSessions tests ---
func TestPruneSessions_DeletesOld_Good(t *testing.T) {
dir := t.TempDir()
writeJSONL(t, dir, "old-session.jsonl", userTextEntry(ts(0), "old"))
writeJSONL(t, dir, "new-session.jsonl", userTextEntry(ts(0), "new"))
// Touch old-session to make it appear old (1 hour ago).
oldPath := filepath.Join(dir, "old-session.jsonl")
past := time.Now().Add(-2 * time.Hour)
require.NoError(t, os.Chtimes(oldPath, past, past))
deleted, err := PruneSessions(dir, 1*time.Hour)
require.NoError(t, err)
assert.Equal(t, 1, deleted)
// Only new-session should remain.
sessions, err := ListSessions(dir)
require.NoError(t, err)
require.Len(t, sessions, 1)
assert.Equal(t, "new-session", sessions[0].ID)
}
func TestPruneSessions_NoneExpired_Good(t *testing.T) {
dir := t.TempDir()
writeJSONL(t, dir, "fresh.jsonl", userTextEntry(ts(0), "fresh"))
deleted, err := PruneSessions(dir, 24*time.Hour)
require.NoError(t, err)
assert.Equal(t, 0, deleted)
sessions, err := ListSessions(dir)
require.NoError(t, err)
require.Len(t, sessions, 1)
}
func TestPruneSessions_EmptyDir_Good(t *testing.T) {
dir := t.TempDir()
deleted, err := PruneSessions(dir, 1*time.Hour)
require.NoError(t, err)
assert.Equal(t, 0, deleted)
}
// --- IsExpired tests ---
func TestIsExpired_Expired_Good(t *testing.T) {
s := &Session{
EndTime: time.Now().Add(-2 * time.Hour),
}
assert.True(t, s.IsExpired(1*time.Hour))
}
func TestIsExpired_NotExpired_Good(t *testing.T) {
s := &Session{
EndTime: time.Now().Add(-30 * time.Minute),
}
assert.False(t, s.IsExpired(1*time.Hour))
}
func TestIsExpired_ZeroEndTime_Bad(t *testing.T) {
s := &Session{}
assert.False(t, s.IsExpired(1*time.Hour))
}
// --- FetchSession tests ---
func TestFetchSession_ValidID_Good(t *testing.T) {
dir := t.TempDir()
writeJSONL(t, dir, "abc123.jsonl",
userTextEntry(ts(0), "Hello"),
assistantTextEntry(ts(1), "Hi"),
)
sess, stats, err := FetchSession(dir, "abc123")
require.NoError(t, err)
require.NotNil(t, sess)
require.NotNil(t, stats)
assert.Equal(t, "abc123", sess.ID)
assert.Len(t, sess.Events, 2)
}
func TestFetchSession_PathTraversal_Bad(t *testing.T) {
dir := t.TempDir()
_, _, err := FetchSession(dir, "../etc/passwd")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid session id")
}
func TestFetchSession_BackslashTraversal_Bad(t *testing.T) {
dir := t.TempDir()
_, _, err := FetchSession(dir, `..\\windows\\system32`)
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid session id")
}
func TestFetchSession_SlashInID_Bad(t *testing.T) {
dir := t.TempDir()
_, _, err := FetchSession(dir, "sub/dir")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid session id")
}
func TestFetchSession_NotFound_Bad(t *testing.T) {
dir := t.TempDir()
_, _, err := FetchSession(dir, "nonexistent")
require.Error(t, err)
assert.Contains(t, err.Error(), "open transcript")
}

View file

@ -7,7 +7,7 @@ import (
"os/exec"
"strings"
coreerr "forge.lthn.ai/core/go-log"
coreerr "dappco.re/go/core/log"
)
// RenderMP4 generates an MP4 video from session events using VHS (charmbracelet).