From de0fa9ee76cc5c0b00859e7c0951b18176117caf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:10:10 +0000 Subject: [PATCH 1/4] Initial plan From dde8ddee6404b3b895cb304e03efb60fa3869d96 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:16:00 +0000 Subject: [PATCH 2/4] Add Prompt field to Result struct with combined rules and task content Co-authored-by: alexec <1142830+alexec@users.noreply.github.com> --- main.go | 9 ++--- pkg/codingcontext/context.go | 9 +++++ pkg/codingcontext/result.go | 1 + pkg/codingcontext/result_test.go | 61 ++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index 58e4279..2adcc7e 100644 --- a/main.go +++ b/main.go @@ -166,12 +166,7 @@ func main() { fmt.Println("---") } - // Output all rules - for _, rule := range result.Rules { - fmt.Println(rule.Content) - } - - // Output task - fmt.Println(result.Task.Content) + // Output the combined prompt (rules + task) + fmt.Print(result.Prompt) } } diff --git a/pkg/codingcontext/context.go b/pkg/codingcontext/context.go index 9ce9ac1..c08c16c 100644 --- a/pkg/codingcontext/context.go +++ b/pkg/codingcontext/context.go @@ -314,12 +314,21 @@ func (cc *Context) Run(ctx context.Context, taskName string) (*Result, error) { // Estimate tokens for task cc.logger.Info("Total estimated tokens", "tokens", cc.totalTokens) + // Build the combined prompt from all rules and task content + var promptBuilder strings.Builder + for _, rule := range cc.rules { + promptBuilder.WriteString(rule.Content) + promptBuilder.WriteString("\n") + } + promptBuilder.WriteString(cc.task.Content) + // Build and return the result result := &Result{ Rules: cc.rules, Task: cc.task, Tokens: cc.totalTokens, Agent: cc.agent, + Prompt: promptBuilder.String(), } return result, nil diff --git a/pkg/codingcontext/result.go b/pkg/codingcontext/result.go index af5433b..e4bd923 100644 --- a/pkg/codingcontext/result.go +++ b/pkg/codingcontext/result.go @@ -11,6 +11,7 @@ type Result struct { Task markdown.Markdown[markdown.TaskFrontMatter] // Task file with frontmatter and content Tokens int // Total token count Agent Agent // The agent used (from task or -a flag) + Prompt string // Combined prompt: all rules and task content } // MCPServers returns all MCP server configurations from rules. diff --git a/pkg/codingcontext/result_test.go b/pkg/codingcontext/result_test.go index 65a6891..3a05d10 100644 --- a/pkg/codingcontext/result_test.go +++ b/pkg/codingcontext/result_test.go @@ -7,6 +7,67 @@ import ( "github.com/kitproj/coding-context-cli/pkg/codingcontext/mcp" ) +func TestResult_Prompt(t *testing.T) { + tests := []struct { + name string + result Result + want string + }{ + { + name: "empty result", + result: Result{ + Rules: []markdown.Markdown[markdown.RuleFrontMatter]{}, + Task: markdown.Markdown[markdown.TaskFrontMatter]{ + Content: "Task content", + }, + Prompt: "Task content", + }, + want: "Task content", + }, + { + name: "single rule and task", + result: Result{ + Rules: []markdown.Markdown[markdown.RuleFrontMatter]{ + { + Content: "Rule 1 content", + }, + }, + Task: markdown.Markdown[markdown.TaskFrontMatter]{ + Content: "Task content", + }, + Prompt: "Rule 1 content\nTask content", + }, + want: "Rule 1 content\nTask content", + }, + { + name: "multiple rules and task", + result: Result{ + Rules: []markdown.Markdown[markdown.RuleFrontMatter]{ + { + Content: "Rule 1 content", + }, + { + Content: "Rule 2 content", + }, + }, + Task: markdown.Markdown[markdown.TaskFrontMatter]{ + Content: "Task content", + }, + Prompt: "Rule 1 content\nRule 2 content\nTask content", + }, + want: "Rule 1 content\nRule 2 content\nTask content", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.result.Prompt != tt.want { + t.Errorf("Result.Prompt = %q, want %q", tt.result.Prompt, tt.want) + } + }) + } +} + func TestResult_MCPServers(t *testing.T) { tests := []struct { name string From fd04ceb37bf75cf4c6dd697cb348978ce1149ae7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 20:20:22 +0000 Subject: [PATCH 3/4] Fix output formatting to match original behavior with trailing newline Co-authored-by: alexec <1142830+alexec@users.noreply.github.com> --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 2adcc7e..5fbfc04 100644 --- a/main.go +++ b/main.go @@ -167,6 +167,6 @@ func main() { } // Output the combined prompt (rules + task) - fmt.Print(result.Prompt) + fmt.Println(result.Prompt) } } From 70d7d48970d68d2b7a30a643bff1db4eb741f059 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 21:26:57 +0000 Subject: [PATCH 4/4] Fix TestResult_Prompt to actually test Context.Run() behavior The test now creates temporary files and calls Context.Run() to verify that the Prompt field is correctly populated by the context assembly logic, instead of manually setting the Prompt field and checking it equals itself. Co-authored-by: alexec <1142830+alexec@users.noreply.github.com> --- pkg/codingcontext/result_test.go | 76 ++++++++++++++++---------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/pkg/codingcontext/result_test.go b/pkg/codingcontext/result_test.go index 3a05d10..88a0041 100644 --- a/pkg/codingcontext/result_test.go +++ b/pkg/codingcontext/result_test.go @@ -1,6 +1,9 @@ package codingcontext import ( + "context" + "log/slog" + "os" "testing" "github.com/kitproj/coding-context-cli/pkg/codingcontext/markdown" @@ -9,60 +12,57 @@ import ( func TestResult_Prompt(t *testing.T) { tests := []struct { - name string - result Result - want string + name string + setup func(t *testing.T, dir string) + taskName string + want string }{ { - name: "empty result", - result: Result{ - Rules: []markdown.Markdown[markdown.RuleFrontMatter]{}, - Task: markdown.Markdown[markdown.TaskFrontMatter]{ - Content: "Task content", - }, - Prompt: "Task content", + name: "task only without rules", + setup: func(t *testing.T, dir string) { + createTask(t, dir, "test-task", "task_name: test-task", "Task content\n") }, - want: "Task content", + taskName: "test-task", + want: "Task content\n", }, { name: "single rule and task", - result: Result{ - Rules: []markdown.Markdown[markdown.RuleFrontMatter]{ - { - Content: "Rule 1 content", - }, - }, - Task: markdown.Markdown[markdown.TaskFrontMatter]{ - Content: "Task content", - }, - Prompt: "Rule 1 content\nTask content", + setup: func(t *testing.T, dir string) { + createTask(t, dir, "test-task", "task_name: test-task", "Task content\n") + createRule(t, dir, ".agents/rules/rule1.md", "", "Rule 1 content\n") }, - want: "Rule 1 content\nTask content", + taskName: "test-task", + want: "Rule 1 content\n\nTask content\n", }, { name: "multiple rules and task", - result: Result{ - Rules: []markdown.Markdown[markdown.RuleFrontMatter]{ - { - Content: "Rule 1 content", - }, - { - Content: "Rule 2 content", - }, - }, - Task: markdown.Markdown[markdown.TaskFrontMatter]{ - Content: "Task content", - }, - Prompt: "Rule 1 content\nRule 2 content\nTask content", + setup: func(t *testing.T, dir string) { + createTask(t, dir, "test-task", "task_name: test-task", "Task content\n") + createRule(t, dir, ".agents/rules/rule1.md", "", "Rule 1 content\n") + createRule(t, dir, ".agents/rules/rule2.md", "", "Rule 2 content\n") }, - want: "Rule 1 content\nRule 2 content\nTask content", + taskName: "test-task", + want: "Rule 1 content\n\nRule 2 content\n\nTask content\n", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if tt.result.Prompt != tt.want { - t.Errorf("Result.Prompt = %q, want %q", tt.result.Prompt, tt.want) + tmpDir := t.TempDir() + tt.setup(t, tmpDir) + + ctx := New( + WithSearchPaths("file://"+tmpDir), + WithLogger(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))), + ) + + result, err := ctx.Run(context.Background(), tt.taskName) + if err != nil { + t.Fatalf("Run() error = %v", err) + } + + if result.Prompt != tt.want { + t.Errorf("Result.Prompt = %q, want %q", result.Prompt, tt.want) } }) }