Files
wehub-resource-sync f99010fae1
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
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:36 +08:00

384 lines
12 KiB
Go

package parser
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestOpenClaudeProviderCapabilities(t *testing.T) {
caps := openClaudeProviderCapabilities()
require.True(t, caps.Source.DiscoverSources == CapabilitySupported)
require.True(t, caps.Source.WatchSources == CapabilitySupported)
require.True(t, caps.Source.ClassifyChangedPath == CapabilitySupported)
require.True(t, caps.Source.FindSource == CapabilitySupported)
require.True(t, caps.Source.ForceReplaceOnParse == CapabilitySupported)
def, ok := AgentByType(AgentOpenClaude)
require.True(t, ok, "AgentOpenClaude missing from Registry")
assert.True(t, def.FileBased)
assert.Equal(t, "OPENCLAUDE_PROJECTS_DIR", def.EnvVar)
assert.Equal(t, "OPENCLAUDE_CONFIG_DIR", def.DefaultRootEnvVar)
assert.Equal(t, "openclaude_project_dirs", def.ConfigKey)
assert.Equal(t, []string{".openclaude/projects"}, def.DefaultDirs)
assert.Equal(t, "openclaude:", def.IDPrefix)
assert.Empty(t, def.WatchSubdirs)
assert.Nil(t, def.WatchRootsFunc)
}
func TestOpenClaudeDiscoverParseAndFindSource(t *testing.T) {
root := t.TempDir()
projectDir := filepath.Join(root, "my-project")
require.NoError(t, os.MkdirAll(projectDir, 0o755))
path := filepath.Join(projectDir, "session-123.jsonl")
content := strings.Join([]string{
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": tsEarly,
"uuid": "u1",
"parentUuid": "",
"cwd": "/workspace/my-project",
"gitBranch": "main",
"message": map[string]any{
"role": "user",
"content": "hello from openclaude",
},
}),
buildMetadataLine(map[string]any{
"type": "assistant",
"timestamp": tsEarlyS1,
"uuid": "u2",
"parentUuid": "u1",
"message": map[string]any{
"role": "assistant",
"stop_reason": "end_turn",
"usage": map[string]any{
"input_tokens": 12,
"cache_creation_input_tokens": 3,
"cache_read_input_tokens": 2,
"output_tokens": 7,
},
"content": []map[string]any{
{"type": "text", "text": "reply"},
},
},
}),
buildMetadataLine(map[string]any{
"type": "ai-title",
"timestamp": tsEarlyS1,
"aiTitle": "AI title",
}),
buildMetadataLine(map[string]any{
"type": "custom-title",
"timestamp": tsEarlyS5,
"customTitle": "User title",
}),
buildMetadataLine(map[string]any{
"type": "system",
"subtype": "compact_boundary",
"timestamp": tsEarlyS5,
"uuid": "u3",
"parentUuid": "u2",
"message": map[string]any{
"content": []map[string]any{
{"type": "text", "text": "Compact summary"},
},
},
}),
}, "\n") + "\n"
require.NoError(t, os.WriteFile(path, []byte(content), 0o644))
provider, ok := NewProvider(AgentOpenClaude, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 1)
assert.Equal(t, path, discovered[0].Key)
assert.Equal(t, "my-project", discovered[0].ProjectHint)
found, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
FullSessionID: "openclaude:session-123",
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, path, found.Key)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: discovered[0],
Fingerprint: SourceFingerprint{Hash: "hash-123"},
Machine: "devbox",
})
require.NoError(t, err)
require.True(t, outcome.ResultSetComplete)
require.True(t, outcome.ForceReplace)
require.Len(t, outcome.Results, 1)
result := outcome.Results[0].Result
assert.Equal(t, AgentOpenClaude, result.Session.Agent)
assert.Equal(t, "openclaude:session-123", result.Session.ID)
assert.Equal(t, "my_project", result.Session.Project)
assert.Equal(t, "hello from openclaude", result.Session.FirstMessage)
assert.Equal(t, "User title", result.Session.SessionName)
assert.Equal(t, 1, result.Session.UserMessageCount)
assert.Equal(t, TerminationAwaitingUser, result.Session.TerminationStatus)
assert.Equal(t, 7, result.Session.TotalOutputTokens)
assert.Equal(t, 17, result.Session.PeakContextTokens)
assert.True(t, result.Session.HasTotalOutputTokens)
assert.True(t, result.Session.HasPeakContextTokens)
assert.Equal(t, "hash-123", result.Session.File.Hash)
require.Len(t, result.Messages, 3)
assert.Equal(t, RoleUser, result.Messages[0].Role)
assert.Equal(t, RoleAssistant, result.Messages[1].Role)
assert.Equal(t, "end_turn", result.Messages[1].StopReason)
assert.Equal(t, 7, result.Messages[1].OutputTokens)
assert.Equal(t, 17, result.Messages[1].ContextTokens)
assert.True(t, result.Messages[1].HasOutputTokens)
assert.True(t, result.Messages[1].HasContextTokens)
assert.Equal(t, RoleAssistant, result.Messages[2].Role)
assert.True(t, result.Messages[2].IsSystem)
assert.True(t, result.Messages[2].IsCompactBoundary)
assert.Equal(t, "compact_boundary", result.Messages[2].SourceSubtype)
assert.Contains(t, result.Messages[2].Content, "Compact summary")
}
func TestOpenClaudeQueuedCommandAttachment(t *testing.T) {
root := t.TempDir()
projectDir := filepath.Join(root, "queue-project")
require.NoError(t, os.MkdirAll(projectDir, 0o755))
path := filepath.Join(projectDir, "session-queue.jsonl")
content := strings.Join([]string{
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": tsEarly,
"uuid": "u1",
"message": map[string]any{
"role": "user",
"content": "first prompt",
},
}),
buildMetadataLine(map[string]any{
"type": "attachment",
"timestamp": tsEarlyS1,
"attachment": map[string]any{
"type": "queued_command",
"commandMode": "prompt",
"prompt": []map[string]any{
{"type": "text", "text": "/resume next step"},
{"type": "text", "text": "with context"},
},
},
}),
buildMetadataLine(map[string]any{
"type": "attachment",
"timestamp": "2024-01-01T10:00:01.500Z",
"attachment": map[string]any{
"type": "queued_command",
"commandMode": "task-notification",
"prompt": "ignored non-prompt queued command",
},
}),
buildMetadataLine(map[string]any{
"type": "attachment",
"timestamp": "2024-01-01T10:00:01.750Z",
"attachment": map[string]any{
"type": "queued_command",
"commandMode": "prompt",
"isMeta": true,
"prompt": "ignored meta queued command",
},
}),
buildMetadataLine(map[string]any{
"type": "attachment",
"timestamp": "2024-01-01T10:00:02Z",
"attachment": map[string]any{
"type": "queued_command",
"commandMode": "prompt",
"origin": "task-notification",
"prompt": "ignored queued prompt",
},
}),
buildMetadataLine(map[string]any{
"type": "assistant",
"timestamp": tsEarlyS5,
"uuid": "u2",
"parentUuid": "u1",
"message": map[string]any{
"role": "assistant",
"content": []map[string]any{
{"type": "text", "text": "reply"},
},
},
}),
}, "\n") + "\n"
require.NoError(t, os.WriteFile(path, []byte(content), 0o644))
provider, ok := NewProvider(AgentOpenClaude, ProviderConfig{
Roots: []string{root},
})
require.True(t, ok)
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 1)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: discovered[0],
})
require.NoError(t, err)
require.Len(t, outcome.Results, 1)
result := outcome.Results[0].Result
require.Len(t, result.Messages, 3)
assert.Equal(t, "/resume next step\nwith context", result.Messages[1].Content)
assert.Equal(t, "queued_command", result.Messages[1].SourceSubtype)
assert.Equal(t, RoleUser, result.Messages[1].Role)
assert.Equal(t, 2, result.Session.UserMessageCount)
assert.Equal(t, "first prompt", result.Session.FirstMessage)
}
func TestOpenClaudeSkipsMetaUserMessages(t *testing.T) {
root := t.TempDir()
projectDir := filepath.Join(root, "meta-project")
require.NoError(t, os.MkdirAll(projectDir, 0o755))
path := filepath.Join(projectDir, "session-meta.jsonl")
content := strings.Join([]string{
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": tsEarly,
"isMeta": true,
"uuid": "m1",
"message": map[string]any{
"role": "user",
"content": "hidden meta prompt",
},
}),
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": tsEarlyS1,
"uuid": "u1",
"message": map[string]any{
"role": "user",
"content": "real prompt",
},
}),
buildMetadataLine(map[string]any{
"type": "assistant",
"timestamp": "2024-01-01T10:00:02Z",
"uuid": "a1",
"message": map[string]any{
"role": "assistant",
"stop_reason": "end_turn",
"content": []map[string]any{
{"type": "text", "text": "real reply"},
},
},
}),
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": "2024-01-01T10:00:03Z",
"isMeta": true,
"uuid": "m2",
"message": map[string]any{
"role": "user",
"content": "hidden trailing meta",
},
}),
}, "\n") + "\n"
require.NoError(t, os.WriteFile(path, []byte(content), 0o644))
provider, ok := NewProvider(AgentOpenClaude, ProviderConfig{
Roots: []string{root},
})
require.True(t, ok)
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 1)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: discovered[0],
})
require.NoError(t, err)
require.Len(t, outcome.Results, 1)
result := outcome.Results[0].Result
require.Len(t, result.Messages, 2)
assert.Equal(t, "real prompt", result.Session.FirstMessage)
assert.Equal(t, 1, result.Session.UserMessageCount)
assert.Equal(t, TerminationAwaitingUser, result.Session.TerminationStatus)
assert.Equal(t, RoleUser, result.Messages[0].Role)
assert.Equal(t, "real prompt", result.Messages[0].Content)
assert.Equal(t, RoleAssistant, result.Messages[1].Role)
}
func TestOpenClaudeDiscoverParseSubagentRelationship(t *testing.T) {
root := t.TempDir()
path := filepath.Join(
root,
"proj-name",
"parent-123",
"subagents",
"tasks",
"agent-worker.jsonl",
)
require.NoError(t, os.MkdirAll(filepath.Dir(path), 0o755))
require.NoError(t, os.WriteFile(path, []byte(strings.Join([]string{
buildMetadataLine(map[string]any{
"type": "user",
"timestamp": tsEarly,
"uuid": "u1",
"message": map[string]any{
"role": "user",
"content": "subagent prompt",
},
}),
buildMetadataLine(map[string]any{
"type": "assistant",
"timestamp": tsEarlyS1,
"uuid": "u2",
"parentUuid": "u1",
"message": map[string]any{
"role": "assistant",
"content": []map[string]any{
{"type": "text", "text": "subagent reply"},
},
},
}),
}, "\n")+"\n"), 0o644))
provider, ok := NewProvider(AgentOpenClaude, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 1)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: discovered[0],
Machine: "devbox",
})
require.NoError(t, err)
require.Len(t, outcome.Results, 1)
result := outcome.Results[0].Result
assert.Equal(t, "openclaude:agent-worker", result.Session.ID)
assert.Equal(t, "openclaude:parent-123", result.Session.ParentSessionID)
assert.Equal(t, RelSubagent, result.Session.RelationshipType)
}