Replace the frozen context snapshot pattern with a CLI-driven approach: agents now use `multica` CLI commands to fetch issue details, comments, and workspace context on demand, always getting the latest data. - Remove buildContextSnapshot and snapshot generation from enqueue - Claim endpoint now returns fresh agent name + skills from DB - Daemon resolves provider from local runtimeIndex, not snapshot - Prompt instructs agent to use `multica issue get` / `comment list` - Meta skill (CLAUDE.md/AGENTS.md) documents all available CLI commands - Skills still injected as filesystem files (static agent config) - Simplify daemon types: remove TaskContext/IssueContext/RuntimeContext Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
package daemon
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNormalizeServerBaseURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
got, err := NormalizeServerBaseURL("ws://localhost:8080/ws")
|
|
if err != nil {
|
|
t.Fatalf("NormalizeServerBaseURL returned error: %v", err)
|
|
}
|
|
if got != "http://localhost:8080" {
|
|
t.Fatalf("expected http://localhost:8080, got %s", got)
|
|
}
|
|
}
|
|
|
|
func TestBuildPromptContainsIssueID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
issueID := "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
|
prompt := BuildPrompt(Task{
|
|
IssueID: issueID,
|
|
Agent: &AgentData{
|
|
Name: "Local Codex",
|
|
Skills: []SkillData{
|
|
{Name: "Concise", Content: "Be concise."},
|
|
},
|
|
},
|
|
})
|
|
|
|
// Prompt should contain the issue ID and CLI instructions.
|
|
for _, want := range []string{
|
|
issueID,
|
|
"multica issue get",
|
|
"multica issue comment list",
|
|
} {
|
|
if !strings.Contains(prompt, want) {
|
|
t.Fatalf("prompt missing %q", want)
|
|
}
|
|
}
|
|
|
|
// Skills should NOT be inlined in the prompt (they're in runtime config).
|
|
for _, absent := range []string{"## Agent Skills", "Be concise."} {
|
|
if strings.Contains(prompt, absent) {
|
|
t.Fatalf("prompt should NOT contain %q (skills are in runtime config)", absent)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuildPromptNoIssueDetails(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
prompt := BuildPrompt(Task{
|
|
IssueID: "test-id",
|
|
Agent: &AgentData{Name: "Test"},
|
|
})
|
|
|
|
// Prompt should not contain issue title/description (agent fetches via CLI).
|
|
for _, absent := range []string{"**Issue:**", "**Summary:**"} {
|
|
if strings.Contains(prompt, absent) {
|
|
t.Fatalf("prompt should NOT contain %q — agent fetches details via CLI", absent)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestIsWorkspaceNotFoundError(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := &requestError{
|
|
Method: http.MethodPost,
|
|
Path: "/api/daemon/register",
|
|
StatusCode: http.StatusNotFound,
|
|
Body: `{"error":"workspace not found"}`,
|
|
}
|
|
if !isWorkspaceNotFoundError(err) {
|
|
t.Fatal("expected workspace not found error to be recognized")
|
|
}
|
|
|
|
if isWorkspaceNotFoundError(&requestError{StatusCode: http.StatusInternalServerError, Body: `{"error":"workspace not found"}`}) {
|
|
t.Fatal("did not expect 500 to be treated as workspace not found")
|
|
}
|
|
}
|