summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xcmd/ask/askbin3528465 -> 3536143 bytes
-rw-r--r--internal/askcli/command_info_add.go11
-rw-r--r--internal/askcli/command_info_add_test.go22
-rw-r--r--internal/askcli/taskexec.go4
-rw-r--r--internal/askcli/taskexec_test.go4
-rw-r--r--internal/version.go2
6 files changed, 37 insertions, 6 deletions
diff --git a/cmd/ask/ask b/cmd/ask/ask
index 3dce495..9d4efad 100755
--- a/cmd/ask/ask
+++ b/cmd/ask/ask
Binary files differ
diff --git a/internal/askcli/command_info_add.go b/internal/askcli/command_info_add.go
index 0de9be5..2680163 100644
--- a/internal/askcli/command_info_add.go
+++ b/internal/askcli/command_info_add.go
@@ -70,15 +70,22 @@ func extractUUIDFromAddOutput(output string) string {
return ""
}
+// parseAddArgs splits args into taskwarrior modifier tokens and the description.
+// Modifier tokens are args that start with "priority:", "+", or "-" AND contain
+// no spaces (tags and priority flags cannot have spaces). The first arg that is
+// not a modifier begins the description; all remaining args are joined with spaces.
+// If all args are modifiers the description is empty.
func parseAddArgs(args []string) (modifiers []string, description string) {
for i, arg := range args {
- if strings.HasPrefix(arg, "priority:") || strings.HasPrefix(arg, "+") || strings.HasPrefix(arg, "-") {
+ isModifier := !strings.Contains(arg, " ") &&
+ (strings.HasPrefix(arg, "priority:") || strings.HasPrefix(arg, "+") || strings.HasPrefix(arg, "-"))
+ if isModifier {
modifiers = append(modifiers, arg)
} else {
description = strings.Join(args[i:], " ")
return
}
}
- description = strings.Join(args, " ")
+ // All args were modifiers; no description provided.
return
}
diff --git a/internal/askcli/command_info_add_test.go b/internal/askcli/command_info_add_test.go
index ce821ca..f4dc5c1 100644
--- a/internal/askcli/command_info_add_test.go
+++ b/internal/askcli/command_info_add_test.go
@@ -185,4 +185,26 @@ func TestParseAddArgs(t *testing.T) {
if desc != "Old task" || len(mods) != 1 || mods[0] != "-deprecated" {
t.Fatalf("parseAddArgs([\"-deprecated\", \"Old task\"]) = mods=%v, desc=%q", mods, desc)
}
+
+ // An arg starting with "+" but containing spaces is NOT a modifier — it is
+ // the start of the description. This prevents agents from quoting tag+desc
+ // together (e.g. "+code-quality Fix foo") and having them land in the wrong
+ // place.
+ mods, desc = parseAddArgs([]string{"+code-quality Fix foo bar"})
+ if desc != "+code-quality Fix foo bar" || len(mods) != 0 {
+ t.Fatalf("space-containing +arg should be description, got mods=%v, desc=%q", mods, desc)
+ }
+
+ // Same issue when mixed: a proper tag precedes a space-containing arg.
+ mods, desc = parseAddArgs([]string{"+cli", "+code-quality Fix foo bar"})
+ if desc != "+code-quality Fix foo bar" || len(mods) != 1 || mods[0] != "+cli" {
+ t.Fatalf("mixed case: mods=%v, desc=%q", mods, desc)
+ }
+
+ // All-modifier args (no description) should return empty description, not a
+ // duplicate of the modifiers.
+ mods, desc = parseAddArgs([]string{"+cli", "+agent"})
+ if desc != "" || len(mods) != 2 {
+ t.Fatalf("all-modifier case: mods=%v, desc=%q, want empty desc", mods, desc)
+ }
}
diff --git a/internal/askcli/taskexec.go b/internal/askcli/taskexec.go
index 9c9aa69..0553070 100644
--- a/internal/askcli/taskexec.go
+++ b/internal/askcli/taskexec.go
@@ -37,7 +37,9 @@ func (e Executor) taskArgs(repoRoot string, args []string) ([]string, error) {
if err != nil {
return nil, err
}
- return append([]string{"project:" + projectName, "+agent"}, args...), nil
+ // rc.confirmation=off suppresses interactive prompts so the CLI works
+ // non-interactively (stdin is never available when called from an agent).
+ return append([]string{"rc.confirmation=off", "project:" + projectName, "+agent"}, args...), nil
}
func (e Executor) Run(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) {
diff --git a/internal/askcli/taskexec_test.go b/internal/askcli/taskexec_test.go
index 4450a28..5cbb7f1 100644
--- a/internal/askcli/taskexec_test.go
+++ b/internal/askcli/taskexec_test.go
@@ -17,7 +17,7 @@ func TestExecutorTaskArgs(t *testing.T) {
if err != nil {
t.Fatalf("taskArgs returned error: %v", err)
}
- want := []string{"project:hexai", "+agent", "list", "limit:1"}
+ want := []string{"rc.confirmation=off", "project:hexai", "+agent", "list", "limit:1"}
if !reflect.DeepEqual(args, want) {
t.Fatalf("task args = %v, want %v", args, want)
}
@@ -47,7 +47,7 @@ func TestExecutorRun_InjectsProjectFilterAndAgentTag(t *testing.T) {
if gotName != "/usr/bin/task" {
t.Fatalf("task binary = %q, want /usr/bin/task", gotName)
}
- wantArgs := []string{"project:hexai", "+agent", "list", "limit:1"}
+ wantArgs := []string{"rc.confirmation=off", "project:hexai", "+agent", "list", "limit:1"}
if !reflect.DeepEqual(gotArgs, wantArgs) {
t.Fatalf("task args = %v, want %v", gotArgs, wantArgs)
}
diff --git a/internal/version.go b/internal/version.go
index 54e3b55..30b7ba7 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -1,4 +1,4 @@
// Package internal provides the Hexai semantic version identifier used by CLI and LSP binaries.
package internal
-const Version = "0.25.10"
+const Version = "0.25.11"