Files
kandev/apps/backend/internal/task/share/gist_markdown_test.go
T
João Salavisa 07a9784d1c fix(share): route share links through gist.githack so big tasks render (#1008)
* fix(share): route share links through gist.githack so big tasks render

gistpreview.github.io fetches gists via the public GitHub API, which returns
`content: ""` for files past GitHub's per-response content budget (~1 MB).
For non-trivial sessions, share.html and snapshot.json land past that
budget and gistpreview's `document.write(content)` renders a blank page.
gist.githack.com proxies the raw file content directly, so multi-MB
share.html renders correctly — at the cost of a one-time Cloudflare
anti-phishing interstitial on first visit, accepted as the price of
fidelity for big tasks.

displayURL now normalises bare gist URLs and unpinned githack URLs to the
canonical `gist.githack.com/<owner>/<id>/raw/share.html` form; legacy
gistpreview URLs pass through unchanged (the owner is not recoverable
from a gistpreview URL, so users can revoke + re-share to get the
githack form going forward).

* fix(share): address PR #1008 review feedback

- displayURL now re-pins legacy gistpreview URLs stored without /share.html
  so they hit the styled view instead of silently falling back to the
  alphabetically-first README.md (flagged by Greptile).
- Spec: unify two stale gistpreview references (API endpoint description
  and the publish scenario) to the canonical githack form, with a note
  that legacy gistpreview rows pass through. Flagged by CodeRabbit and
  Claude — the spec is the public contract; one stale mention undermines
  the migration.

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
2026-05-22 11:40:36 +01:00

91 lines
3.0 KiB
Go

package share
import (
"encoding/json"
"strings"
"testing"
"time"
)
func TestBuildGistREADME_FullConversation(t *testing.T) {
t.Parallel()
completed := time.Date(2026, 5, 21, 12, 0, 0, 0, time.UTC)
snap := &Snapshot{
Version: SnapshotVersion,
ExportedAt: completed,
Task: TaskMeta{Title: "Investigate flaky test"},
Session: SessionMeta{
AgentType: "claude-acp",
Model: "claude-opus-4-7",
ExecutorType: "local_docker",
StartedAt: completed.Add(-time.Minute),
CompletedAt: &completed,
},
Messages: []Message{
{Role: roleUser, Ts: completed, Blocks: []Block{{Kind: blockKindText, Text: "why is X flaky?"}}},
{
Role: roleAssistant, Ts: completed,
Blocks: []Block{
{Kind: blockKindText, Text: "Looking into it."},
{
Kind: blockKindToolCall,
ToolName: "shell",
Text: "ran tests",
Args: json.RawMessage(`{"cmd":"go test ./..."}`),
},
{Kind: blockKindToolResult, Output: "FAIL pkg/foo TestX"},
{
Kind: blockKindDiff,
Path: "src/x.go",
UnifiedDiff: "--- a\n+++ b\n@@\n-old\n+new\n",
},
},
},
},
Redaction: RedactionLog{AppliedRules: []string{RuleAbsPath}},
}
md := BuildGistREADME(snap, "https://gist.githack.com/jane/mock-gist-1/raw/share.html")
assertContains(t, md, "# Investigate flaky test")
assertContains(t, md, "<kbd>claude-acp</kbd>")
assertContains(t, md, "<kbd>claude-opus-4-7</kbd>")
assertContains(t, md, "<kbd>local_docker</kbd>")
assertContains(t, md, "📊 Session details")
assertContains(t, md, "| **Agent** | claude-acp |")
assertContains(t, md, "Redacted before publish:")
assertContains(t, md, "🧑 User")
// User text is wrapped in a blockquote for visual accent.
assertContains(t, md, "> why is X flaky?")
assertContains(t, md, "🤖 Assistant")
assertContains(t, md, "🔧 <strong>shell</strong>")
// Tool args and output render via HTML <pre><code> rather than a
// triple-backtick fence so payloads containing ``` can't break out.
assertContains(t, md, `<pre><code class="language-json">`)
assertContains(t, md, `"cmd": "go test ./..."`)
assertContains(t, md, "📤 Tool output")
assertContains(t, md, "FAIL pkg/foo TestX")
assertContains(t, md, "**📝 `src/x.go`**")
assertContains(t, md, "```diff")
assertContains(t, md, "snapshot.json")
assertContains(t, md, "github.com/kdlbs/kandev")
}
func TestBuildGistREADME_NilAndEmpty(t *testing.T) {
t.Parallel()
if got := BuildGistREADME(nil, ""); got == "" {
t.Fatal("nil snapshot should still produce a non-empty README")
}
empty := &Snapshot{Task: TaskMeta{Title: "Untitled"}}
got := BuildGistREADME(empty, "https://gist.githack.com/jane/g1/raw/share.html")
if !strings.Contains(got, "_(No messages.)_") {
t.Fatalf("expected empty-messages placeholder, got: %s", got)
}
}
func assertContains(t *testing.T, haystack, needle string) {
t.Helper()
if !strings.Contains(haystack, needle) {
t.Fatalf("expected output to contain %q\n--- output ---\n%s", needle, haystack)
}
}