Compare commits

...

4 Commits

Author SHA1 Message Date
e2d70667f9 Update .grokkit/recipes/result-refactor.md
All checks were successful
CI / Test (push) Successful in 40s
CI / Lint (push) Successful in 26s
CI / Build (push) Successful in 20s
2026-03-09 13:31:32 +00:00
4e334c7d24 docs(changelog): add entry for v0.2.0
All checks were successful
CI / Test (push) Successful in 33s
CI / Lint (push) Successful in 26s
CI / Build (push) Successful in 21s
Summarize changes including new features like recipe support, safe shell commands, and refactoring improvements; updates to configurations and security; fixes for various bugs and handling.
2026-03-08 12:59:34 +00:00
b0fcd2ce42 docs(readme): update test coverage badge and details
All checks were successful
CI / Test (push) Successful in 35s
CI / Lint (push) Successful in 25s
CI / Build (push) Successful in 21s
Release / Create Release (push) Successful in 41s
- Change coverage badge from 68% (brightgreen) to 54% (orange)
- Update quality section from 68%+ to 54%+
- Lower CI coverage gate from 65% to 50%
2026-03-08 12:58:04 +00:00
d377e6b345 test: add tests for recipe package and disable parallelism in cmd tests
All checks were successful
CI / Test (push) Successful in 41s
CI / Lint (push) Successful in 27s
CI / Build (push) Successful in 21s
- Introduce new test suite in internal/recipe/recipe_test.go covering recipe loading, parameter overrides, safety checks, work dir resolution, file discovery, and unified patch creation.
- Remove t.Parallel() from tests in cmd/changelog_test.go, cmd/root_test.go, and cmd/scaffold_test.go that modify global state (e.g., os.Args, HOME, or use os.Chdir()) to avoid race conditions and ensure test isolation.
2026-03-08 12:53:01 +00:00
7 changed files with 255 additions and 7 deletions

View File

@ -67,6 +67,7 @@ Refactors all error handling in the target package to use the new Result[T] patt
### Step 4: Apply or patch
**Objective:**
Safely write changes or create reviewable output.
**Instructions:**
- If dry_run is true → create a unified diff patch file for review.
- If false → write the new files (backup originals as .bak).

View File

@ -1,3 +1,63 @@
## [v0.2.0] - 2026-03-08
Version 0.2.0: Recipes are cooking—now with extra safety and a dash of refactoring flair.
### Added
- Add tests for recipe package covering loading, parameters, safety, and patches.
- Add read-only shell support with user confirmation and whitelisting.
- Add configurable safe shell commands from YAML with fallback.
- Add project exploration step using safe read-only commands.
- Add numeric argument support in read-only shell commands.
- Add logging for safe commands config loading.
- Add smart defaults for package_path in file discovery.
- Add --param flag for passing key=value parameters to recipes.
- Add refactorJSONs to collect JSON from refactor steps.
- Add one-file-at-a-time refactoring handler.
- Add file discovery and special step handling in runner.
- Add apply/patch step handling with code extraction and application.
- Add LLM-powered recipe execution with parameters and streaming.
- Add recipe run command with path resolution.
- Add recipe system for Result[T] refactoring.
- Add --base flag to prdescribe for custom base branch.
- Add admin tool entry to TODO.
### Changed
- Change coverage badge from 68% to 54% and update quality section.
- Lower CI coverage gate from 65% to 50%.
- Remove t.Parallel() from cmd tests modifying global state.
- Refactor README and docs structure into user-guide and developer-guide.
- Remove root command addition from query init.
- Reorganize commit commands and add sections for new features.
- Enhance shell command security with global safe list and prefix checking.
- Update allowed shell command validation to exact match or space-separated.
- Tighten trigger conditions for read-only shell steps.
- Expand safe shell commands to include GNU utilities and test runners.
- Consolidate resolveWorkDir and remove resolvePackagePath.
- Rename and expand resolvePackagePath to resolveWorkDir.
- Update .gitignore to add .grok/ and *.patch ignores.
- Add template recipe and update final summary heading.
- Make search pattern configurable in file discovery.
- Make file discovery generic using recipe metadata.
- Improve boolean param handling and refine project root detection.
- Change default package_path to internal/git.
- Switch refactor step to strict JSON output.
- Update regex for Grok output matching.
- Improve regex flexibility and simplify patch creation.
- Enhance parsing for multi-line step content.
- Simplify apply step to dry-run only.
- Update result-refactor recipe for broader package path.
- Improve recipe loading and execution logic.
- Clean up comments, error handling, and output formatting.
- Simplify golangci-lint configuration.
- Remove priorities from queued TODO items.
- Remove auto-complete TODO workflow.
### Fixed
- Fix unsafe shell command error message.
- Fix recipe by adding error handling to unified patch creation.
- Fix import path and add error handling for user input in cmd/recipe.
- Fix testgen to distinguish C and C++ based on file extension.
- Fix regex to match Grok's current output style.
## [v0.1.9] - 2026-03-04
Grokkit gets a quick-query upgrade—because who has time for chit-chat?

View File

@ -3,7 +3,7 @@
Grokkit is a fast Go CLI integrating Grok AI with git workflows and general chat/edit functionality.
[![Test Coverage](https://img.shields.io/badge/coverage-68%25-brightgreen)]()
[![Test Coverage](https://img.shields.io/badge/coverage-54%25-orange)]()
[![Go Version](https://img.shields.io/badge/go-1.24.2-blue)]()
[![License](https://img.shields.io/badge/license-Unlicense-lightgrey)]()
@ -149,8 +149,8 @@ grokkit review -v
- ✅ **Transactional Recipes** - Markdown-based multi-step AI workflows
### Quality & Testing
- ✅ **Test coverage 68%+** - Comprehensive unit tests including all command message builders
- ✅ **Coverage gate in CI** - Builds fail if coverage drops below 65%
- ✅ **Test coverage 54%+** - Comprehensive unit tests including all command message builders
- ✅ **Coverage gate in CI** - Builds fail if coverage drops below 50%
- ✅ **CI/CD with Gitea Actions** - Tests must pass before lint and build jobs run
- ✅ **Golangci-lint configured** - `.golangci.yml` with govet, errcheck, staticcheck, and more
- ✅ **Interface-based design** - Testable and maintainable

View File

@ -34,12 +34,9 @@ fix: typo in docs
}
func TestBuildFullChangelog(t *testing.T) {
t.Parallel()
newSection := "## [v0.2.0] - 2026-03-03\n\n### Added\n- changelog command\n"
t.Run("creates new file with header", func(t *testing.T) {
t.Parallel()
// nolint:tparallel // os.Chdir affects the entire process
tmpDir := t.TempDir()
@ -58,7 +55,6 @@ func TestBuildFullChangelog(t *testing.T) {
})
t.Run("prepends to existing file", func(t *testing.T) {
t.Parallel()
// nolint:tparallel // os.Chdir affects the entire process
tmpDir := t.TempDir()

View File

@ -16,6 +16,7 @@ func rootSetHomeForTest(t *testing.T, dir string) {
}
func TestExecute(t *testing.T) {
// Not using t.Parallel() because it modifies os.Args and environment variables (HOME)
tests := []struct {
name string
args []string

View File

@ -53,6 +53,7 @@ func TestScaffoldCmd_Live(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Not using t.Parallel() because it uses os.Chdir()
t.Logf("Live test: %s", tt.name)
tmpDir := t.TempDir()

View File

@ -0,0 +1,189 @@
package recipe
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLoad(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
recipePath := filepath.Join(tmpDir, "test.yaml")
content := `---
name: Test Recipe
description: A recipe for testing
version: 1.0.0
parameters:
target_file:
type: string
default: "main.go"
description: File to process
allowed_shell_commands:
- ls -la
- pwd
project_languages:
- go
extensions:
go: [".go"]
search_pattern: "func main"
---
## Execution Steps
### Step 1: Discover
**Objective:** Find files.
**Instructions:** Use discovery.
**Expected output:** List of files.
### Step 2: Refactor
**Objective:** Refactor files.
**Instructions:** Use refactoring.
**Expected output:** JSON.
This is the final summary prompt.
`
err := os.WriteFile(recipePath, []byte(content), 0600)
require.NoError(t, err)
t.Run("successful load with defaults", func(t *testing.T) {
r, err := Load(recipePath, nil)
require.NoError(t, err)
assert.Equal(t, "Test Recipe", r.Name)
assert.Equal(t, "1.0.0", r.Version)
assert.Equal(t, "main.go", r.ResolvedParams["target_file"])
assert.Len(t, r.Steps, 2)
assert.Equal(t, 1, r.Steps[0].Number)
assert.Equal(t, "Discover", r.Steps[0].Title)
assert.Equal(t, "Find files.", r.Steps[0].Objective)
assert.Equal(t, "Use discovery.", r.Steps[0].Instructions)
assert.Equal(t, "List of files.", r.Steps[0].Expected)
assert.Contains(t, r.FinalSummaryPrompt, "This is the final summary prompt.")
})
t.Run("load with parameter override", func(t *testing.T) {
params := map[string]any{"target_file": "app.go"}
r, err := Load(recipePath, params)
require.NoError(t, err)
assert.Equal(t, "app.go", r.ResolvedParams["target_file"])
})
t.Run("load unsafe command", func(t *testing.T) {
unsafeContent := `---
name: Unsafe Recipe
allowed_shell_commands:
- rm -rf /
---
## Execution Steps
### Step 1: Bad
`
unsafePath := filepath.Join(tmpDir, "unsafe.yaml")
err := os.WriteFile(unsafePath, []byte(unsafeContent), 0600)
require.NoError(t, err)
_, err = Load(unsafePath, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "unsafe shell command")
})
t.Run("missing frontmatter", func(t *testing.T) {
badPath := filepath.Join(tmpDir, "bad.yaml")
err := os.WriteFile(badPath, []byte("no frontmatter here"), 0600)
require.NoError(t, err)
_, err = Load(badPath, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "missing YAML frontmatter")
})
}
func TestResolveWorkDir(t *testing.T) {
// Not using t.Parallel() because it might depend on HOME env which we might want to mock if needed.
r := &Recipe{
ResolvedParams: make(map[string]any),
}
runner := &Runner{Recipe: r}
t.Run("default to dot", func(t *testing.T) {
dir := runner.resolveWorkDir()
absDot, _ := filepath.Abs(".")
assert.Equal(t, absDot, dir)
})
t.Run("explicit path", func(t *testing.T) {
tmpDir := t.TempDir()
r.ResolvedParams["package_path"] = tmpDir
dir := runner.resolveWorkDir()
absTmp, _ := filepath.Abs(tmpDir)
assert.Equal(t, absTmp, dir)
})
t.Run("tilde expansion", func(t *testing.T) {
r.ResolvedParams["package_path"] = "~/projects"
dir := runner.resolveWorkDir()
home, _ := os.UserHomeDir()
expected := filepath.Join(home, "projects")
assert.Equal(t, expected, dir)
})
}
func TestDiscoverFiles(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
// Create some files
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "main.go"), []byte("func main() { if err != nil { return } }"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "app.go"), []byte("package main"), 0600))
require.NoError(t, os.WriteFile(filepath.Join(tmpDir, "README.md"), []byte("if err != nil"), 0600))
r := &Recipe{
ProjectLanguages: []string{"go"},
Extensions: map[string][]string{"go": {".go"}},
SearchPattern: "if err != nil",
}
runner := &Runner{Recipe: r}
t.Run("finds matching files", func(t *testing.T) {
files := runner.discoverFiles(tmpDir)
assert.Len(t, files, 1)
assert.Contains(t, files[0], "main.go")
})
t.Run("no matching files", func(t *testing.T) {
r.SearchPattern = "nonexistent"
files := runner.discoverFiles(tmpDir)
assert.Len(t, files, 1)
assert.Equal(t, "No files found matching the criteria.", files[0])
})
}
func TestCreateUnifiedPatch(t *testing.T) {
t.Parallel()
tmpDir := t.TempDir()
patchPath := filepath.Join(tmpDir, "test.patch")
changes := []FileChange{
{
File: "main.go",
Content: "package main\n\nfunc main() {}\n",
},
}
err := createUnifiedPatch(changes, patchPath)
require.NoError(t, err)
content, err := os.ReadFile(patchPath)
require.NoError(t, err)
assert.Contains(t, string(content), "--- main.go")
assert.Contains(t, string(content), "+++ main.go")
assert.Contains(t, string(content), "+package main")
assert.Contains(t, string(content), "+func main() {}")
}