f99010fae1
Desktop Artifacts / Desktop Build (Linux) (push) Waiting to run
Desktop Artifacts / Desktop Build (Windows) (push) Waiting to run
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Waiting to run
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Waiting to run
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
153 lines
3.8 KiB
Go
153 lines
3.8 KiB
Go
package parser
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
func newQoderProviderFactory(def AgentDef) ProviderFactory {
|
|
return NewSourceSetFactory(
|
|
def,
|
|
qoderProviderCapabilities(),
|
|
func(cfg ProviderConfig) SourceSet { return newQoderSourceSet(cfg.Roots) },
|
|
)
|
|
}
|
|
|
|
func newQoderSourceSet(roots []string) JSONLSourceSet {
|
|
return NewJSONLSourceSet(AgentQoder, roots,
|
|
WithRecursive(),
|
|
WithSymlinkFollowing(),
|
|
WithContentHashing(),
|
|
WithIncludePath(isQoderSourcePath),
|
|
WithProjectHint(qoderProjectHintFromPath),
|
|
WithSessionIDFromPath(qoderSessionIDFromPath),
|
|
WithLookupIDValid(isQoderLookupID),
|
|
WithParseFile(qoderParseFile),
|
|
WithForceReplace(),
|
|
WithCompanionFiles(qoderCompanionFiles),
|
|
)
|
|
}
|
|
|
|
func qoderParseFile(
|
|
_ context.Context, path string, req ParseRequest,
|
|
) ([]ParseResult, []string, error) {
|
|
results, excluded, err := ParseQoderSessionWithExclusions(
|
|
path, req.Source.ProjectHint, req.Machine,
|
|
)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
for i := range results {
|
|
if req.Fingerprint.Size > 0 {
|
|
results[i].Session.File.Size = req.Fingerprint.Size
|
|
}
|
|
if req.Fingerprint.MTimeNS > 0 {
|
|
results[i].Session.File.Mtime = req.Fingerprint.MTimeNS
|
|
}
|
|
if req.Fingerprint.Hash != "" {
|
|
results[i].Session.File.Hash = req.Fingerprint.Hash
|
|
}
|
|
}
|
|
return results, excluded, nil
|
|
}
|
|
|
|
func isQoderSourcePath(root, path string) bool {
|
|
parts, ok := qoderPathParts(root, path)
|
|
if !ok {
|
|
return false
|
|
}
|
|
switch len(parts) {
|
|
case 2:
|
|
stem, ok := strings.CutSuffix(parts[1], ".jsonl")
|
|
return ok &&
|
|
!strings.HasPrefix(stem, "agent-") &&
|
|
IsValidSessionID(stem)
|
|
case 4:
|
|
stem, ok := strings.CutSuffix(parts[3], ".jsonl")
|
|
return ok &&
|
|
IsValidSessionID(parts[1]) &&
|
|
parts[2] == "subagents" &&
|
|
strings.HasPrefix(stem, "agent-") &&
|
|
IsValidSessionID(stem)
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func qoderProjectHintFromPath(root, path string) string {
|
|
parts, ok := qoderPathParts(root, path)
|
|
if !ok || len(parts) < 2 {
|
|
return ""
|
|
}
|
|
return DecodeQoderProjectDir(parts[0])
|
|
}
|
|
|
|
func qoderSessionIDFromPath(root, path string) string {
|
|
if !isQoderSourcePath(root, path) {
|
|
return ""
|
|
}
|
|
parts, _ := qoderPathParts(root, path)
|
|
stem := strings.TrimSuffix(filepath.Base(path), ".jsonl")
|
|
if len(parts) == 4 {
|
|
return parts[1] + ":subagent:" + stem
|
|
}
|
|
return stem
|
|
}
|
|
|
|
func isQoderLookupID(rawID string) bool {
|
|
if rawID == "" {
|
|
return false
|
|
}
|
|
sessionID, subagentID, hasSubagent := strings.Cut(rawID, ":subagent:")
|
|
if !IsValidSessionID(sessionID) {
|
|
return false
|
|
}
|
|
return !hasSubagent ||
|
|
strings.HasPrefix(subagentID, "agent-") &&
|
|
IsValidSessionID(subagentID)
|
|
}
|
|
|
|
func qoderPathParts(root, path string) ([]string, bool) {
|
|
rel, err := filepath.Rel(root, path)
|
|
if err != nil {
|
|
return nil, false
|
|
}
|
|
parts := strings.Split(rel, string(filepath.Separator))
|
|
for _, part := range parts {
|
|
if part == "" || part == "." || part == ".." {
|
|
return nil, false
|
|
}
|
|
}
|
|
return parts, true
|
|
}
|
|
|
|
func qoderCompanionFiles(path string) []string {
|
|
stem, ok := strings.CutSuffix(path, ".jsonl")
|
|
if ok {
|
|
return []string{stem + "-session.json"}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func qoderProviderCapabilities() Capabilities {
|
|
source := jsonlFileProviderSourceCapabilities()
|
|
source.MultiSessionSource = CapabilitySupported
|
|
source.ExcludedSessions = CapabilitySupported
|
|
source.ForceReplaceOnParse = CapabilitySupported
|
|
return Capabilities{
|
|
Source: source,
|
|
Content: ContentCapabilities{
|
|
FirstMessage: CapabilitySupported,
|
|
Cwd: CapabilitySupported,
|
|
Relationships: CapabilitySupported,
|
|
Subagents: CapabilitySupported,
|
|
ToolCalls: CapabilitySupported,
|
|
ToolResults: CapabilitySupported,
|
|
PerMessageTokenUsage: CapabilitySupported,
|
|
MalformedLineCount: CapabilitySupported,
|
|
Model: CapabilitySupported,
|
|
},
|
|
}
|
|
}
|