Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,14 @@ func (o *Orchestrator) Run(ctx context.Context) error {

// Prompt builders

const commitMessageInstructionTemplate = `If you create commits, use a concise subject and include these git trailers:
Nightshift-Task: %s
Nightshift-Ref: https://github.com/marcus/nightshift`

func commitMessageInstruction(taskType tasks.TaskType) string {
return fmt.Sprintf(commitMessageInstructionTemplate, taskType)
}

// PlanPrompt returns the planning prompt for a task.
func (o *Orchestrator) PlanPrompt(task *tasks.Task) string {
return o.buildPlanPrompt(task)
Expand All @@ -728,9 +736,7 @@ Description: %s
0. You are running autonomously. If the task is broad or ambiguous, choose a concrete, minimal scope that delivers value and state any assumptions in the description.
1. Work on a new branch and plan to submit a PR. Never work directly on the primary branch.%s
2. Before creating your branch, record the current branch name and plan to switch back after the PR is opened.
3. If you create commits, include a concise message with these git trailers:
Nightshift-Task: %s
Nightshift-Ref: https://github.com/marcus/nightshift
3. %s
4. Analyze the task requirements
5. Identify files that need to be modified
6. Create step-by-step implementation plan
Expand All @@ -741,7 +747,7 @@ Description: %s
"files": ["file1.go", "file2.go", ...],
"description": "overall approach"
}
`, task.ID, task.Title, task.Description, branchInstruction, task.Type)
`, task.ID, task.Title, task.Description, branchInstruction, commitMessageInstruction(task.Type))
}

func (o *Orchestrator) buildImplementPrompt(task *tasks.Task, plan *PlanOutput, iteration int) string {
Expand Down Expand Up @@ -771,9 +777,7 @@ Description: %s
## Instructions
0. Before creating your branch, record the current branch name. Create and work on a new branch. Never modify or commit directly to the primary branch.%s
When finished, open a PR. After the PR is submitted, switch back to the original branch. If you cannot open a PR, leave the branch and explain next steps.
1. If you create commits, include a concise message with these git trailers:
Nightshift-Task: %s
Nightshift-Ref: https://github.com/marcus/nightshift
1. %s
2. Implement the plan step by step
3. Make all necessary code changes
4. Ensure tests pass
Expand All @@ -783,7 +787,7 @@ Description: %s
"files_modified": ["file1.go", ...],
"summary": "what was done"
}
`, task.ID, task.Title, task.Description, plan.Description, plan.Steps, iterationNote, branchInstruction, task.Type)
`, task.ID, task.Title, task.Description, plan.Description, plan.Steps, iterationNote, branchInstruction, commitMessageInstruction(task.Type))
}

func (o *Orchestrator) buildReviewPrompt(task *tasks.Task, impl *ImplementOutput) string {
Expand Down
57 changes: 57 additions & 0 deletions internal/orchestrator/orchestrator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,63 @@ func TestBuildPrompts(t *testing.T) {
}
}

func TestBuildPrompts_NormalizedCommitInstructionsWithBranch(t *testing.T) {
o := New()
o.SetRunMetadata(&RunMetadata{Branch: "develop"})

task := &tasks.Task{
ID: "commit-normalize:/repo",
Title: "Commit Message Normalizer",
Description: "Standardize future generated commit guidance",
Type: tasks.TaskCommitNormalize,
}
plan := &PlanOutput{
Steps: []string{"step1"},
Description: "test plan",
}

tests := []struct {
name string
prompt string
branchInstruction string
}{
{
name: "plan",
prompt: o.buildPlanPrompt(task),
branchInstruction: "Create your feature branch from `develop`.",
},
{
name: "implement",
prompt: o.buildImplementPrompt(task, plan, 1),
branchInstruction: "Checkout `develop` before creating your feature branch.",
},
}

expectedCommitInstruction := `If you create commits, use a concise subject and include these git trailers:
Nightshift-Task: commit-normalize
Nightshift-Ref: https://github.com/marcus/nightshift`

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := strings.Count(tt.prompt, expectedCommitInstruction); got != 1 {
t.Fatalf("normalized commit instruction count = %d, want 1\nGot:\n%s", got, tt.prompt)
}
for _, want := range []string{
"Nightshift-Task: commit-normalize",
"Nightshift-Ref: https://github.com/marcus/nightshift",
tt.branchInstruction,
} {
if got := strings.Count(tt.prompt, want); got != 1 {
t.Errorf("%q count = %d, want 1\nGot:\n%s", want, got, tt.prompt)
}
}
if strings.Contains(tt.prompt, "include a concise message with these git trailers") {
t.Errorf("prompt contains old commit instruction wording\nGot:\n%s", tt.prompt)
}
})
}
}

func TestExtractPRURL(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion internal/tasks/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ Apply safe updates directly, and leave concise follow-ups for anything uncertain
Type: TaskCommitNormalize,
Category: CategoryPR,
Name: "Commit Message Normalizer",
Description: "Standardize commit message format",
Description: "Standardize future Nightshift-generated commit guidance without rewriting history",
CostTier: CostLow,
RiskLevel: RiskLow,
DefaultInterval: 24 * time.Hour,
Expand Down
19 changes: 19 additions & 0 deletions internal/tasks/tasks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,25 @@ func TestGetDefinition(t *testing.T) {
}
}

func TestCommitNormalizeDefinitionScope(t *testing.T) {
def, err := GetDefinition(TaskCommitNormalize)
if err != nil {
t.Fatalf("GetDefinition(TaskCommitNormalize) returned error: %v", err)
}
if def.Description != "Standardize future Nightshift-generated commit guidance without rewriting history" {
t.Errorf("Description = %q", def.Description)
}
if def.Category != CategoryPR {
t.Errorf("Category = %d, want %d", def.Category, CategoryPR)
}
if def.CostTier != CostLow {
t.Errorf("CostTier = %d, want %d", def.CostTier, CostLow)
}
if def.RiskLevel != RiskLow {
t.Errorf("RiskLevel = %d, want %d", def.RiskLevel, RiskLow)
}
}

func TestGetCostEstimate(t *testing.T) {
// Low cost task
min, max, err := GetCostEstimate(TaskLintFix)
Expand Down
2 changes: 1 addition & 1 deletion website/docs/task-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Fully formed, review-ready artifacts. These tasks create branches and open pull
| `backward-compat` | Backward-Compatibility Checks | Check and ensure backward compatibility | Medium | Low | 7d |
| `build-optimize` | Build Time Optimization | Optimize build configuration for faster builds | High | Medium | 7d |
| `docs-backfill` | Documentation Backfiller | Generate missing documentation | Low | Low | 7d |
| `commit-normalize` | Commit Message Normalizer | Standardize commit message format | Low | Low | 24h |
| `commit-normalize` | Commit Message Normalizer | Standardize future Nightshift-generated commit guidance without rewriting history | Low | Low | 24h |
| `changelog-synth` | Changelog Synthesizer | Generate changelog from commits | Low | Low | 7d |
| `release-notes` | Release Note Drafter | Draft release notes from changes | Low | Low | 7d |
| `adr-draft` | ADR Drafter | Draft Architecture Decision Records | Medium | Low | 7d |
Expand Down