Skip to content
Merged
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: 20 additions & 0 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,26 @@ file:///path/to/local/rules

Define a parameter for substitution in task prompts. Variables in task files using `${key}` syntax will be replaced with the specified value.

**Parameter Parsing Features:**

The `-p` flag supports flexible parameter parsing with the following features:

- **Basic key-value pairs**: `key=value`
- **Multiple values per key**: Duplicate keys are collected into a list (e.g., `-p tag=frontend -p tag=backend` results in `tag` having both values)
- **Quoted values**: Use single (`'`) or double (`"`) quotes for values containing spaces or special characters
- `-p description="Application crashes on startup"`
- `-p name='John Doe'`
- **Escape sequences**: Supported in both quoted and unquoted values
- Standard: `\n` (newline), `\t` (tab), `\r` (carriage return), `\\` (backslash)
- Quotes: `\"` (double quote), `\'` (single quote)
- Unicode: `\uXXXX` where XXXX are four hexadecimal digits
- Hex: `\xHH` where HH are two hexadecimal digits
- Octal: `\OOO` where OOO are up to three octal digits
- **Case-insensitive keys**: Keys are automatically converted to lowercase
- **UTF-8 support**: Full Unicode support in keys and values
- **Flexible separators**: Multiple `-p` flags can be used, or a single flag can contain comma or whitespace-separated pairs
- **Empty values**: Unquoted empty values (`key=`) result in empty parameter, quoted empty values (`key=""`) result in empty string

**Examples:**
```bash
# Single parameter
Expand Down
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
module github.com/kitproj/coding-context-cli

go 1.24.4
go 1.24.5

require (
github.com/alecthomas/participle/v2 v2.1.4
github.com/goccy/go-yaml v1.18.0
github.com/hashicorp/go-getter/v2 v2.2.3
github.com/stretchr/testify v1.10.0
)

require (
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.1.0 // indirect
github.com/klauspost/compress v1.11.2 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/mitchellh/go-homedir v1.0.0 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
14 changes: 12 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas=
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
Expand All @@ -24,11 +26,19 @@ github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PF
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/klauspost/compress v1.11.2 h1:MiK62aErc3gIiVEtyzKfeOHgW7atJb5g/KNX5m3c2nQ=
github.com/klauspost/compress v1.11.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
6 changes: 4 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (

yaml "github.com/goccy/go-yaml"
"github.com/kitproj/coding-context-cli/pkg/codingcontext"
"github.com/kitproj/coding-context-cli/pkg/codingcontext/selectors"
"github.com/kitproj/coding-context-cli/pkg/codingcontext/taskparser"
)

func main() {
Expand All @@ -25,8 +27,8 @@ func main() {
var resume bool
var writeRules bool
var agent codingcontext.Agent
params := make(codingcontext.Params)
includes := make(codingcontext.Selectors)
params := make(taskparser.Params)
includes := make(selectors.Selectors)
var searchPaths []string
var manifestURL string

Expand Down
48 changes: 28 additions & 20 deletions pkg/codingcontext/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ import (
"os"

"github.com/kitproj/coding-context-cli/pkg/codingcontext"
"github.com/kitproj/coding-context-cli/pkg/codingcontext/taskparams"
)

func main() {
// Create a new context with options
ctx := codingcontext.New(
codingcontext.WithSearchPaths("file://.", "file://"+os.Getenv("HOME")),
codingcontext.WithParams(codingcontext.Params{
"issue_number": "123",
"feature": "authentication",
codingcontext.WithParams(taskparams.Params{
"issue_number": []string{"123"},
"feature": []string{"authentication"},
}),
codingcontext.WithLogger(slog.New(slog.NewTextHandler(os.Stderr, nil))),
)
Expand Down Expand Up @@ -63,24 +64,26 @@ import (
"os"

"github.com/kitproj/coding-context-cli/pkg/codingcontext"
"github.com/kitproj/coding-context-cli/pkg/codingcontext/selectors"
"github.com/kitproj/coding-context-cli/pkg/codingcontext/taskparams"
)

func main() {
// Create selectors for filtering rules
selectors := make(codingcontext.Selectors)
selectors.SetValue("language", "go")
selectors.SetValue("stage", "implementation")
sel := make(selectors.Selectors)
sel.SetValue("language", "go")
sel.SetValue("stage", "implementation")

// Create context with all options
ctx := codingcontext.New(
codingcontext.WithSearchPaths(
"file://.",
"git::https://github.com/org/repo//path/to/rules",
),
codingcontext.WithParams(codingcontext.Params{
"issue_number": "123",
codingcontext.WithParams(taskparams.Params{
"issue_number": []string{"123"},
}),
codingcontext.WithSelectors(selectors),
codingcontext.WithSelectors(sel),
codingcontext.WithAgent(codingcontext.AgentCursor),
codingcontext.WithResume(false),
codingcontext.WithUserPrompt("Additional context or instructions"),
Expand Down Expand Up @@ -232,11 +235,14 @@ Type representing MCP transport protocol (string type):

#### `Params`

Map of parameter key-value pairs for template substitution: `map[string]string`
Map of parameter key-value pairs for template substitution: `map[string][]string`

**Methods:**
- `String() string` - Returns string representation
- `Set(value string) error` - Parses and sets key=value pair (implements flag.Value)
- `Value(key string) string` - Returns the first value for the given key
- `Lookup(key string) (string, bool)` - Returns the first value and whether the key exists
- `Values(key string) []string` - Returns all values for the given key

#### `Selectors`

Expand All @@ -262,7 +268,7 @@ Types for parsing task content with slash commands:
- `Argument` - Slash command argument (can be positional or named key=value)

**Methods:**
- `(*SlashCommand) Params() map[string]string` - Returns parsed parameters as map
- `(*SlashCommand) Params() taskparams.Params` - Returns parsed parameters as map
- `(*Text) Content() string` - Returns text content as string
- Various `String()` methods for formatting each type

Expand All @@ -284,8 +290,8 @@ Creates a new Context with the given options.

**Options:**
- `WithSearchPaths(paths ...string)` - Add search paths (supports go-getter URLs)
- `WithParams(params Params)` - Set parameters for substitution
- `WithSelectors(selectors Selectors)` - Set selectors for filtering rules
- `WithParams(params taskparams.Params)` - Set parameters for substitution (import `taskparams` package)
- `WithSelectors(selectors selectors.Selectors)` - Set selectors for filtering rules (import `selectors` package)
- `WithAgent(agent Agent)` - Set target agent (excludes that agent's own rules)
- `WithResume(resume bool)` - Enable resume mode (skips rules)
- `WithUserPrompt(userPrompt string)` - Set user prompt to append to task
Expand All @@ -304,23 +310,25 @@ Parses a markdown file into frontmatter and content. Generic function that works

Parses task text content into blocks of text and slash commands.

#### `ParseParams(s string) (Params, error)`
#### `taskparams.Parse(s string) (taskparams.Params, error)`

Parses a string containing key=value pairs with quoted values.

**Examples:**
```go
import "github.com/kitproj/coding-context-cli/pkg/codingcontext/taskparams"

// Parse quoted key-value pairs
params, _ := ParseParams(`key1="value1" key2="value2"`)
// Result: map[string]string{"key1": "value1", "key2": "value2"}
params, _ := taskparams.Parse(`key1="value1" key2="value2"`)
// Result: taskparams.Params{"key1": []string{"value1"}, "key2": []string{"value2"}}

// Parse with spaces in values
params, _ := ParseParams(`key1="value with spaces" key2="value2"`)
// Result: map[string]string{"key1": "value with spaces", "key2": "value2"}
params, _ := taskparams.Parse(`key1="value with spaces" key2="value2"`)
// Result: taskparams.Params{"key1": []string{"value with spaces"}, "key2": []string{"value2"}}

// Parse with escaped quotes
params, _ := ParseParams(`key1="value with \"escaped\" quotes"`)
// Result: map[string]string{"key1": "value with \"escaped\" quotes"}
params, _ := taskparams.Parse(`key1="value with \"escaped\" quotes"`)
// Result: taskparams.Params{"key1": []string{"value with \"escaped\" quotes"}}
```

#### `ParseAgent(s string) (Agent, error)`
Expand Down
38 changes: 0 additions & 38 deletions pkg/codingcontext/command_frontmatter.go

This file was deleted.

Loading