Skip to content

Commit 8a4b201

Browse files
feat(parser): add reusable source-set bases and functional options
Introduce the SourceSet bases (JSONL, directory JSONL, single-file, multi-session container, sibling-metadata, SQLite fan-out), the functional with*() option set, the generic SourceSet provider/factory plumbing, and the virtual-path and source-identity helpers up front, so every provider migration constructs its source set through options instead of a struct literal.
1 parent cb005c7 commit 8a4b201

13 files changed

Lines changed: 2578 additions & 0 deletions
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package parser
2+
3+
import (
4+
"path/filepath"
5+
"strings"
6+
)
7+
8+
// DirectoryJSONLSourceSet constrains JSONL sources to the common
9+
// <root>/<project>/<session>.<ext> shape while keeping JSONLSourceSet's source
10+
// methods available through embedding.
11+
type DirectoryJSONLSourceSet struct {
12+
JSONLSourceSet
13+
}
14+
15+
// newDirectoryJSONLSourceSet returns a JSONL source helper for providers whose
16+
// transcripts live one project directory below each configured root. The
17+
// returned helper is always recursive enough to classify watched project files,
18+
// but it rejects root-level and deeper nested files through IncludePath.
19+
func newDirectoryJSONLSourceSet(
20+
provider AgentType,
21+
roots []string,
22+
opts ...jsonlOption,
23+
) DirectoryJSONLSourceSet {
24+
var options JSONLSourceSetOptions
25+
for _, opt := range opts {
26+
opt(&options)
27+
}
28+
userIncludePath := options.IncludePath
29+
options.Recursive = true
30+
options.IncludePath = func(root, path string) bool {
31+
if !isDirectoryJSONLPath(root, path) {
32+
return false
33+
}
34+
return userIncludePath == nil || userIncludePath(root, path)
35+
}
36+
if options.ProjectHint == nil {
37+
options.ProjectHint = func(root, path string) string {
38+
return directoryJSONLProjectFromPath(path)
39+
}
40+
}
41+
return DirectoryJSONLSourceSet{
42+
JSONLSourceSet: jsonlSourceSetFromOptions(provider, roots, options),
43+
}
44+
}
45+
46+
func isDirectoryJSONLPath(root, path string) bool {
47+
rel, err := filepath.Rel(root, path)
48+
if err != nil {
49+
return false
50+
}
51+
parts := strings.Split(rel, string(filepath.Separator))
52+
return len(parts) == 2 &&
53+
parts[0] != "" && parts[0] != "." && parts[0] != ".." &&
54+
parts[1] != "" && parts[1] != "." && parts[1] != ".."
55+
}
56+
57+
func directoryJSONLProjectFromPath(path string) string {
58+
return filepath.Base(filepath.Dir(path))
59+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:build unix
2+
3+
package parser
4+
5+
import (
6+
"os"
7+
"syscall"
8+
)
9+
10+
func sourceFileIdentity(info os.FileInfo) (inode, device uint64) {
11+
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
12+
return uint64(stat.Ino), uint64(stat.Dev)
13+
}
14+
return 0, 0
15+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//go:build windows
2+
3+
package parser
4+
5+
import "os"
6+
7+
func sourceFileIdentity(info os.FileInfo) (inode, device uint64) {
8+
return 0, 0
9+
}

0 commit comments

Comments
 (0)