diff options
27 files changed, 369 insertions, 367 deletions
@@ -1,4 +1,6 @@ -/ask +/do +/cmd/do/do +/cmd/do/ask /hexai /hexai-lsp-server /hexai-mcp-server diff --git a/Magefile.go b/Magefile.go index 65748fd..fb19689 100644 --- a/Magefile.go +++ b/Magefile.go @@ -25,15 +25,15 @@ var ( // Build builds binaries. func Build() error { - mg.Deps(BuildAsk, BuildHexaiLSP, BuildHexaiCLI, BuildHexaiTmuxAction, BuildHexaiTmuxEdit, BuildHexaiMCPServer) + mg.Deps(BuildDo, BuildHexaiLSP, BuildHexaiCLI, BuildHexaiTmuxAction, BuildHexaiTmuxEdit, BuildHexaiMCPServer) printCoverage() return nil } -// BuildAsk builds the Taskwarrior proxy wrapper. -func BuildAsk() error { +// BuildDo builds the Taskwarrior proxy wrapper. +func BuildDo() error { printCoverage() - return sh.RunV("go", "build", "-o", "ask", "./cmd/ask") + return sh.RunV("go", "build", "-o", "do", "./cmd/do") } // BuildHexaiLSP builds the LSP server binary. @@ -70,7 +70,7 @@ func BuildHexaiMCPServer() error { func Dev() error { printCoverage() mg.Deps(Test, Vet, Lint) - if err := sh.RunV("go", "build", "-race", "-o", "ask", "./cmd/ask"); err != nil { + if err := sh.RunV("go", "build", "-race", "-o", "do", "./cmd/do"); err != nil { return err } if err := sh.RunV("go", "build", "-race", "-o", "hexai-lsp-server", "./cmd/hexai-lsp-server"); err != nil { @@ -120,7 +120,7 @@ func Install() error { return err } for _, name := range []string{ - "ask", + "do", "hexai-lsp-server", "hexai", "hexai-tmux-action", @@ -14,12 +14,12 @@ It has got improved capabilities for Go code understanding (for example, create * Stand-alone command line tool for LLM interaction - Includes `--tps-simulation` to preview how fast a model would feel by streaming placeholder text or piped stdin at a chosen token-per-second rate * Task management CLI for agent-managed project work - - Entrypoint: `ask` + - Entrypoint: `do` - Auto-scopes to `project:<repo> +agent` (derived from git repo root) - Never exposes numeric task IDs — uses UUIDs only - Machine-friendly output: UUID-only tables, suppressed decorative text - - Subcommands: `ask add`, `ask list`, `ask info`, `ask annotate`, `ask start`, `ask stop`, `ask done`, `ask priority`, `ask tag`, `ask dep`, `ask urgency`, `ask modify`, `ask denotate`, `ask delete`, `ask fish`, `ask help` - - Fish completion generator: `ask fish` + - Subcommands: `do add`, `do list`, `do info`, `do annotate`, `do start`, `do stop`, `do done`, `do priority`, `do tag`, `do dep`, `do urgency`, `do modify`, `do denotate`, `do delete`, `do fish`, `do help` + - Fish completion generator: `do fish` * Parallel completions and CLI responses from multiple providers/models for side-by-side comparison * **MCP server for prompt/runbook management** (`hexai-mcp-server`) - **⚠️ DEPRECATED/EXPERIMENTAL** - Create, update, delete, and retrieve prompts via MCP protocol diff --git a/cmd/ask/ask b/cmd/ask/ask Binary files differdeleted file mode 100755 index cffc885..0000000 --- a/cmd/ask/ask +++ /dev/null diff --git a/cmd/ask/main.go b/cmd/do/main.go index afab992..afab992 100644 --- a/cmd/ask/main.go +++ b/cmd/do/main.go diff --git a/cmd/ask/main_test.go b/cmd/do/main_test.go index db6b436..db6b436 100644 --- a/cmd/ask/main_test.go +++ b/cmd/do/main_test.go diff --git a/docs/buildandinstall.md b/docs/buildandinstall.md index a707faa..abca741 100644 --- a/docs/buildandinstall.md +++ b/docs/buildandinstall.md @@ -3,7 +3,7 @@ Hexai uses Mage for developer tasks. Install Mage, then run targets like build, dev, test, and install. - Install Mage: `go install github.com/magefile/mage@latest` -- Build binaries: `mage build` (produces `ask`, `hexai`, `hexai-lsp-server`, `hexai-tmux-action`, and `hexai-tmux-edit`) +- Build binaries: `mage build` (produces `do`, `hexai`, `hexai-lsp-server`, `hexai-tmux-action`, and `hexai-tmux-edit`) - Dev build (+ tests, vet, lint): `mage dev` - Run tests: `mage test` - Run tests with coverage: `go test ./... -cover` @@ -11,7 +11,7 @@ Hexai uses Mage for developer tasks. Install Mage, then run targets like build, - In restricted sandboxes/CI (no sockets), skip network-based tests: - `HEXAI_TEST_SKIP_NET=1 go test ./... -cover` - Install binaries to `GOPATH/bin`: `mage install` -- Load Fish completions in the current shell: `~/go/bin/ask fish | source` +- Load Fish completions in the current shell: `~/go/bin/do fish | source` Note: `mage lint` uses `golangci-lint`. Install via `mage devinstall` if needed. @@ -19,7 +19,7 @@ Note: `mage lint` uses `golangci-lint`. Install via `mage devinstall` if needed. Either use the Mage method as mentioned above, or install directly with: -- Taskwarrior proxy: `go install codeberg.org/snonux/hexai/cmd/ask@latest` +- Taskwarrior proxy: `go install codeberg.org/snonux/hexai/cmd/do@latest` - CLI: `go install codeberg.org/snonux/hexai/cmd/hexai@latest` - LSP: `go install codeberg.org/snonux/hexai/cmd/hexai-lsp-server@latest` - Action runner: `go install codeberg.org/snonux/hexai/cmd/hexai-tmux-action@latest` diff --git a/docs/fish-completion.md b/docs/fish-completion.md index d707b77..f55e4cf 100644 --- a/docs/fish-completion.md +++ b/docs/fish-completion.md @@ -1,34 +1,34 @@ # Fish Completion -The `ask` task-management CLI embeds its Fish completion script in the binary and prints it with `ask fish`. +The `do` task-management CLI embeds its Fish completion script in the binary and prints it with `do fish`. -It completes the top-level `ask` subcommands and the nested `ask dep` operations. -It also completes task selectors for UUID-taking commands by reading pending tasks through `ask complete-uuids`, which uses the local alias cache for stable short IDs. +It completes the top-level `do` subcommands and the nested `do dep` operations. +It also completes task selectors for UUID-taking commands by reading pending tasks through `do complete-uuids`, which uses the local alias cache for stable short IDs. Fish suggests each task's alias ID first and also keeps the raw UUID available as a fallback selector. -Selector suggestions stop once a command has consumed its selector argument, and `ask dep add` / `ask dep rm` suggest selectors for both task positions. -When typing `ask add depends:...`, Fish also completes the comma-separated dependency selector list inside the `depends:` modifier. +Selector suggestions stop once a command has consumed its selector argument, and `do dep add` / `do dep rm` suggest selectors for both task positions. +When typing `do add depends:...`, Fish also completes the comma-separated dependency selector list inside the `depends:` modifier. The script preserves the global `--json` flag. Load it into the current Fish session: ```sh -ask fish | source +do fish | source ``` If you installed with `mage install` and `~/go/bin` is not on your `PATH` yet, use: ```sh -~/go/bin/ask fish | source +~/go/bin/do fish | source ``` To enable it automatically for new Fish sessions, add this to your Fish config or a file in `~/.config/fish/conf.d/`: ```fish -set -l ask_bin ~/go/bin/ask +set -l do_bin ~/go/bin/do -if test -x $ask_bin - $ask_bin fish | source +if test -x $do_bin + $do_bin fish | source end ``` -No external `ask.fish` file is required. +No external `do.fish` file is required. diff --git a/docs/plan-ask-uuid-wrapper.md b/docs/plan-ask-uuid-wrapper.md index dcaf44c..31d719b 100644 --- a/docs/plan-ask-uuid-wrapper.md +++ b/docs/plan-ask-uuid-wrapper.md @@ -1,8 +1,8 @@ -# Plan: `ask` as UUID-only Taskwarrior Wrapper +# Plan: `do` as UUID-only Taskwarrior Wrapper ## Goal -Rewrite the `ask` command from a thin pass-through proxy into a **subcommand-based CLI** that wraps Taskwarrior. The wrapper never exposes numeric task IDs to the caller — only UUIDs. Output is minimal and machine-friendly for coding agents. +Rewrite the `do` command from a thin pass-through proxy into a **subcommand-based CLI** that wraps Taskwarrior. The wrapper never exposes numeric task IDs to the caller — only UUIDs. Output is minimal and machine-friendly for coding agents. The existing `project:<repo> +agent` auto-injection is preserved. @@ -10,39 +10,39 @@ The existing `project:<repo> +agent` auto-injection is preserved. | Subcommand | Example | Taskwarrior equivalent | |---|---|---| -| `ask add "Implement X"` | create task | `task project:P +agent add "Implement X"` | -| `ask add priority:H +cli "Fix bug"` | create with priority & tag | same + `priority:H +cli` | -| `ask list` | list pending tasks | `task project:P +agent status:pending export` → reformat | -| `ask info <uuid>` | show one task | `task uuid:<uuid> export` → filtered fields | -| `ask annotate <uuid> "note"` | add annotation | `task uuid:<uuid> annotate "note"` | -| `ask start <uuid>` | start work | `task uuid:<uuid> start` | -| `ask stop <uuid>` | stop work | `task uuid:<uuid> stop` | -| `ask done <uuid>` | mark complete | `task uuid:<uuid> done` | -| `ask priority <uuid> H` | set priority | `task uuid:<uuid> modify priority:H` | -| `ask tag <uuid> +foo` | add tag | `task uuid:<uuid> modify +foo` | -| `ask tag <uuid> -foo` | remove tag | `task uuid:<uuid> modify -foo` | -| `ask dep add <uuid> <dep-uuid>` | add dependency | `task uuid:<uuid> modify depends:<dep-uuid>` | -| `ask dep rm <uuid> <dep-uuid>` | remove dependency | `task uuid:<uuid> modify depends:-<dep-uuid>` | -| `ask dep list <uuid>` | show dependencies | `task uuid:<uuid> export` → `depends` field | -| `ask urgency` | list by urgency | `task project:P +agent export` → sort by urgency | -| `ask modify <uuid> <args...>` | general modify | `task uuid:<uuid> modify <args...>` (priority, tags, depends, /old/new/) | -| `ask denotate <uuid> "text"` | remove annotation | `task uuid:<uuid> denotate "text"` | -| `ask delete <uuid>` | delete task | `task uuid:<uuid> delete` | -| `ask export` | raw JSON dump | `task project:P +agent export` → pass through | +| `do add "Implement X"` | create task | `task project:P +agent add "Implement X"` | +| `do add priority:H +cli "Fix bug"` | create with priority & tag | same + `priority:H +cli` | +| `do list` | list pending tasks | `task project:P +agent status:pending export` → reformat | +| `do info <uuid>` | show one task | `task uuid:<uuid> export` → filtered fields | +| `do annotate <uuid> "note"` | add annotation | `task uuid:<uuid> annotate "note"` | +| `do start <uuid>` | start work | `task uuid:<uuid> start` | +| `do stop <uuid>` | stop work | `task uuid:<uuid> stop` | +| `do done <uuid>` | mark complete | `task uuid:<uuid> done` | +| `do priority <uuid> H` | set priority | `task uuid:<uuid> modify priority:H` | +| `do tag <uuid> +foo` | add tag | `task uuid:<uuid> modify +foo` | +| `do tag <uuid> -foo` | remove tag | `task uuid:<uuid> modify -foo` | +| `do dep add <uuid> <dep-uuid>` | add dependency | `task uuid:<uuid> modify depends:<dep-uuid>` | +| `do dep rm <uuid> <dep-uuid>` | remove dependency | `task uuid:<uuid> modify depends:-<dep-uuid>` | +| `do dep list <uuid>` | show dependencies | `task uuid:<uuid> export` → `depends` field | +| `do urgency` | list by urgency | `task project:P +agent export` → sort by urgency | +| `do modify <uuid> <args...>` | general modify | `task uuid:<uuid> modify <args...>` (priority, tags, depends, /old/new/) | +| `do denotate <uuid> "text"` | remove annotation | `task uuid:<uuid> denotate "text"` | +| `do delete <uuid>` | delete task | `task uuid:<uuid> delete` | +| `do export` | raw JSON dump | `task project:P +agent export` → pass through | ### List filters, sort, and limit -`ask list` accepts optional filters, sort, and limit arguments: +`do list` accepts optional filters, sort, and limit arguments: | Example | Taskwarrior equivalent | |---|---| -| `ask list` | `task project:P +agent status:pending export` (default sort: priority-, urgency-) | -| `ask list +READY` | `task project:P +agent +READY export` | -| `ask list +BLOCKED` | `task project:P +agent +BLOCKED export` | -| `ask list +frontend` | `task project:P +agent +frontend export` | -| `ask list started` | `task project:P +agent start.any: export` | -| `ask list limit:3` | show only first 3 results | -| `ask list +READY limit:1` | next ready task | +| `do list` | `task project:P +agent status:pending export` (default sort: priority-, urgency-) | +| `do list +READY` | `task project:P +agent +READY export` | +| `do list +BLOCKED` | `task project:P +agent +BLOCKED export` | +| `do list +frontend` | `task project:P +agent +frontend export` | +| `do list started` | `task project:P +agent start.any: export` | +| `do list limit:3` | show only first 3 results | +| `do list +READY limit:1` | next ready task | ## Data Retrieval: `task export` @@ -81,7 +81,7 @@ If an argument looks like a bare numeric ID where a UUID is expected, reject wit ## Package Layout ``` -cmd/ask/main.go — parse subcommand, dispatch to askcli +cmd/do/main.go — parse subcommand, dispatch to askcli internal/askcli/ — NEW package ├── dispatch.go — subcommand router (switch args[0]) ├── taskexec.go — wraps Taskwarrior execution (binary lookup, repo detection, run) @@ -108,45 +108,45 @@ Each `command_*.go` file gets a corresponding `command_*_test.go`. ## Changes to Existing Code -- **`cmd/ask/main.go`** — stops calling `taskproxy.Runner.Run` directly; delegates to `askcli.Dispatch()`. +- **`cmd/do/main.go`** — stops calling `taskproxy.Runner.Run` directly; delegates to `askcli.Dispatch()`. - **`internal/taskproxy/`** — reused by `askcli/taskexec.go` for binary lookup (`findTaskBinary`) and repo root detection (`detectRepoRoot`). The `Runner.Run` pass-through method becomes unused and can be removed. ## Task Breakdown 1. Scaffold `internal/askcli/` — dispatch, taskexec, taskexport, formatter -2. Implement `ask add` (UUID extraction from Taskwarrior stdout) -3. Implement `ask list` (export → UUID-only table) -4. Implement `ask info <uuid>` (export → filtered fields) -5. Implement `ask annotate <uuid> "note"` -6. Implement `ask start <uuid>` / `ask stop <uuid>` -7. Implement `ask done <uuid>` -8. Implement `ask priority <uuid> <P>` -9. Implement `ask tag <uuid> +/-tag` -10. Implement `ask dep add/rm/list` -11. Implement `ask urgency` -12. Implement `ask modify <uuid> <args...>` (general-purpose modify) -13. Implement `ask denotate <uuid> "text"` (remove annotation) -14. Implement `ask delete <uuid>` -15. Implement `ask export` (raw JSON) -16. Add filter/sort/limit support to `ask list` (+READY, +BLOCKED, +tag, started, limit:N) -17. Wire `cmd/ask/main.go` to `askcli.Dispatch`, remove old pass-through +2. Implement `do add` (UUID extraction from Taskwarrior stdout) +3. Implement `do list` (export → UUID-only table) +4. Implement `do info <uuid>` (export → filtered fields) +5. Implement `do annotate <uuid> "note"` +6. Implement `do start <uuid>` / `do stop <uuid>` +7. Implement `do done <uuid>` +8. Implement `do priority <uuid> <P>` +9. Implement `do tag <uuid> +/-tag` +10. Implement `do dep add/rm/list` +11. Implement `do urgency` +12. Implement `do modify <uuid> <args...>` (general-purpose modify) +13. Implement `do denotate <uuid> "text"` (remove annotation) +14. Implement `do delete <uuid>` +15. Implement `do export` (raw JSON) +16. Add filter/sort/limit support to `do list` (+READY, +BLOCKED, +tag, started, limit:N) +17. Wire `cmd/do/main.go` to `askcli.Dispatch`, remove old pass-through 18. Update docs and README -19. Create `agent-task-management` skill (replacement for `taskwarrior-task-management`) — uses only `ask` subcommands, no Taskwarrior references -20. Update Pi coding agent: rename `taskwarrior-plan-mode` extension → `agent-plan-mode`, rewrite to use `ask` subcommands only -21. Audit `agent-task-management` skill and `agent-plan-mode` extension: ensure zero Taskwarrior leakage — agents must see `ask` as the native task system, not a wrapper +19. Create `agent-task-management` skill (replacement for `taskwarrior-task-management`) — uses only `do` subcommands, no Taskwarrior references +20. Update Pi coding agent: rename `taskwarrior-plan-mode` extension → `agent-plan-mode`, rewrite to use `do` subcommands only +21. Audit `agent-task-management` skill and `agent-plan-mode` extension: ensure zero Taskwarrior leakage — agents must see `do` as the native task system, not a wrapper ## Skill & Extension Migration -After the `ask` CLI is complete and documented, three follow-up tasks abstract away the Taskwarrior implementation detail: +After the `do` CLI is complete and documented, three follow-up tasks abstract away the Taskwarrior implementation detail: ### 19. `agent-task-management` skill -Create a new skill at `~/.agents/skills/agent-task-management/` by copying the structure from `taskwarrior-task-management` (SKILL.md + references/00-context.md through 5-review-overview-tasks.md). Rewrite all content to use `ask` subcommands (`ask add`, `ask list`, `ask info`, `ask start`, `ask stop`, `ask done`, `ask annotate`, `ask denotate`, `ask modify`, `ask priority`, `ask tag`, `ask dep`, `ask urgency`, `ask delete`, `ask export`). Remove all mentions of Taskwarrior, raw `task` command, numeric IDs, and `_uuid` lookups. +Create a new skill at `~/.agents/skills/agent-task-management/` by copying the structure from `taskwarrior-task-management` (SKILL.md + references/00-context.md through 5-review-overview-tasks.md). Rewrite all content to use `do` subcommands (`do add`, `do list`, `do info`, `do start`, `do stop`, `do done`, `do annotate`, `do denotate`, `do modify`, `do priority`, `do tag`, `do dep`, `do urgency`, `do delete`, `do export`). Remove all mentions of Taskwarrior, raw `task` command, numeric IDs, and `_uuid` lookups. ### 20. `agent-plan-mode` Pi extension -Rename `~/git/hyperstack/pi/agent/extensions/taskwarrior-plan-mode/` → `agent-plan-mode/`. Update `index.ts`, `utils.ts`, `README.md` to use new `ask` subcommands instead of raw pass-through calls. Rename `TaskwarriorTask` type, update state keys, command names, descriptions, and UI messages. +Rename `~/git/hyperstack/pi/agent/extensions/taskwarrior-plan-mode/` → `agent-plan-mode/`. Update `index.ts`, `utils.ts`, `README.md` to use new `do` subcommands instead of raw pass-through calls. Rename `TaskwarriorTask` type, update state keys, command names, descriptions, and UI messages. ### 21. Taskwarrior leakage audit -Grep all files in the new skill and extension for `taskwarrior` (any casing), `task warrior`, raw `task ` command patterns, numeric task ID usage, `_uuid` lookups, and any hint that `ask` wraps another tool. **Agents must believe `ask` IS the task management system — not a proxy.** This prevents agents from attempting raw Taskwarrior commands or mentioning Taskwarrior in annotations/descriptions. +Grep all files in the new skill and extension for `taskwarrior` (any casing), `task warrior`, raw `task ` command patterns, numeric task ID usage, `_uuid` lookups, and any hint that `do` wraps another tool. **Agents must believe `do` IS the task management system — not a proxy.** This prevents agents from attempting raw Taskwarrior commands or mentioning Taskwarrior in annotations/descriptions. diff --git a/docs/usage.md b/docs/usage.md index 0786a00..cc78300 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -125,77 +125,77 @@ cat SOMEFILE.txt | hexai --tps-simulation 20 ## Task management -`ask` is a task management CLI for the current git project. By default it auto-scopes to `project:<repo> +agent` so operations are confined to agent-managed project tasks. +`do` is a task management CLI for the current git project. By default it auto-scopes to `project:<repo> +agent` so operations are confined to agent-managed project tasks. -Use `ask na <subcommand...>` or `ask no-agent <subcommand...>` to run the same subcommands against project tasks without the `+agent` tag. Those prefixes keep the project scope but replace the default tag filter with `-agent`. +Use `do na <subcommand...>` or `do no-agent <subcommand...>` to run the same subcommands against project tasks without the `+agent` tag. Those prefixes keep the project scope but replace the default tag filter with `-agent`. -`ask` never exposes Taskwarrior numeric task IDs. Human-facing output uses stable local alias IDs where practical, while `ask info` shows both the alias ID and the UUID. Commands that accept a task selector support either the alias ID or the UUID. +`do` never exposes Taskwarrior numeric task IDs. Human-facing output uses stable local alias IDs where practical, while `do info` shows both the alias ID and the UUID. Commands that accept a task selector support either the alias ID or the UUID. -`ask` must be run inside a git repository so the project name can be derived from the repo root. +`do` must be run inside a git repository so the project name can be derived from the repo root. ### Subcommands | Subcommand | Description | |---|---| -| `ask add "description"` | Create a new task and print `created task <alias-id>` | -| `ask add depends:<id\|uuid>,<id\|uuid> "description"` | Create task with inline dependencies | -| `ask add priority:H "description"` | Create task with priority | -| `ask add +tag "description"` | Create task with tag | -| `ask na add "description"` | Create a project task without the `+agent` tag | -| `ask list` | List pending tasks only (alias-ID table) | -| `ask na list` | List pending project tasks without the `+agent` tag | -| `ask all` | List all tasks including completed/deleted | -| `ask list +READY` | List only ready tasks | -| `ask list +BLOCKED` | List blocked tasks | -| `ask list +tag` | Filter by tag | -| `ask list started` | List started tasks | -| `ask list limit:N` | Limit results | -| `ask list sort:priority-,urgency-` | Sort by priority then urgency | -| `ask info [id\|uuid]` | Show task details, or the current started task if no selector is provided | -| `ask annotate <id\|uuid> "note"` | Add annotation | -| `ask start <id\|uuid>` | Start working on a task | -| `ask stop <id\|uuid>` | Stop work on a task | -| `ask done <id\|uuid>` | Mark task complete | -| `ask priority <id\|uuid> H\|M\|L` | Set priority | -| `ask tag <id\|uuid> +tag` | Add tag | -| `ask tag <id\|uuid> -tag` | Remove tag | -| `ask dep add <id\|uuid> <dep-id\|dep-uuid>` | Add dependency | -| `ask dep rm <id\|uuid> <dep-id\|dep-uuid>` | Remove dependency | -| `ask dep list <id\|uuid>` | List dependencies | -| `ask urgency` | List tasks by urgency | -| `ask modify <id\|uuid> <args...>` | General-purpose modify | -| `ask denotate <id\|uuid> "text"` | Remove annotation | -| `ask delete <id\|uuid>` | Delete a task | +| `do add "description"` | Create a new task and print `created task <alias-id>` | +| `do add depends:<id\|uuid>,<id\|uuid> "description"` | Create task with inline dependencies | +| `do add priority:H "description"` | Create task with priority | +| `do add +tag "description"` | Create task with tag | +| `do na add "description"` | Create a project task without the `+agent` tag | +| `do list` | List pending tasks only (alias-ID table) | +| `do na list` | List pending project tasks without the `+agent` tag | +| `do all` | List all tasks including completed/deleted | +| `do list +READY` | List only ready tasks | +| `do list +BLOCKED` | List blocked tasks | +| `do list +tag` | Filter by tag | +| `do list started` | List started tasks | +| `do list limit:N` | Limit results | +| `do list sort:priority-,urgency-` | Sort by priority then urgency | +| `do info [id\|uuid]` | Show task details, or the current started task if no selector is provided | +| `do annotate <id\|uuid> "note"` | Add annotation | +| `do start <id\|uuid>` | Start working on a task | +| `do stop <id\|uuid>` | Stop work on a task | +| `do done <id\|uuid>` | Mark task complete | +| `do priority <id\|uuid> H\|M\|L` | Set priority | +| `do tag <id\|uuid> +tag` | Add tag | +| `do tag <id\|uuid> -tag` | Remove tag | +| `do dep add <id\|uuid> <dep-id\|dep-uuid>` | Add dependency | +| `do dep rm <id\|uuid> <dep-id\|dep-uuid>` | Remove dependency | +| `do dep list <id\|uuid>` | List dependencies | +| `do urgency` | List tasks by urgency | +| `do modify <id\|uuid> <args...>` | General-purpose modify | +| `do denotate <id\|uuid> "text"` | Remove annotation | +| `do delete <id\|uuid>` | Delete a task | ### Examples ```sh # Create a task -ask add priority:H "Implement new feature" +do add priority:H "Implement new feature" # Create a non-agent task -ask na add "Follow up manually" +do na add "Follow up manually" # Create a task with dependencies -ask add +cli depends:0,1 "Implement dependent feature" +do add +cli depends:0,1 "Implement dependent feature" # List tasks -ask list +READY limit:5 +do list +READY limit:5 # List non-agent tasks -ask no-agent list +do no-agent list # Show alias and UUID for a task -ask info 0 +do info 0 # Show a non-agent task -ask na info 0 +do na info 0 # Start working -ask start 0 +do start 0 # Done -ask done 0 +do done 0 ``` ## Hexai Action (TUI) diff --git a/integrationtests/ask_scope_test.go b/integrationtests/do_scope_test.go index a328881..f24f5ca 100644 --- a/integrationtests/ask_scope_test.go +++ b/integrationtests/do_scope_test.go @@ -13,7 +13,7 @@ import ( "codeberg.org/snonux/hexai/internal/askcli" ) -func scopedAskArgs(scopePrefix string, args ...string) []string { +func scopedDoArgs(scopePrefix string, args ...string) []string { if strings.TrimSpace(scopePrefix) == "" { return append([]string(nil), args...) } @@ -22,28 +22,28 @@ func scopedAskArgs(scopePrefix string, args ...string) []string { } func createTaskInScope(ctx context.Context, scopePrefix, desc string) (taskInfo, error) { - stdout, stderr, code := runAsk(ctx, scopedAskArgs(scopePrefix, "add", "+integrationtest", desc)) + stdout, stderr, code := runDo(ctx, scopedDoArgs(scopePrefix, "add", "+integrationtest", desc)) if code != 0 { return taskInfo{}, fmt.Errorf("create task failed (code %d): stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } id := extractTaskIDFromAddOutput(stdout.String()) if id == "" { - return taskInfo{}, fmt.Errorf("could not extract task ID from ask add output: %s", stdout.String()) + return taskInfo{}, fmt.Errorf("could not extract task ID from do add output: %s", stdout.String()) } info, ok := getTaskInfoInScope(ctx, scopePrefix, id) if !ok { - return taskInfo{}, fmt.Errorf("could not resolve task ID %q after ask %s add", id, scopePrefix) + return taskInfo{}, fmt.Errorf("could not resolve task ID %q after do %s add", id, scopePrefix) } if info.UUID == "" { - return taskInfo{}, fmt.Errorf("ask %s info %q did not return a UUID", scopePrefix, id) + return taskInfo{}, fmt.Errorf("do %s info %q did not return a UUID", scopePrefix, id) } return info, nil } func getTaskInfoInScope(ctx context.Context, scopePrefix, selector string) (taskInfo, bool) { - stdout, _, code := runAsk(ctx, scopedAskArgs(scopePrefix, "info", selector)) + stdout, _, code := runDo(ctx, scopedDoArgs(scopePrefix, "info", selector)) if code != 0 { return taskInfo{}, false } @@ -143,28 +143,28 @@ func TestNoAgentListSeparatesScopedTasks(t *testing.T) { } defer deleteTask(ctx, noAgentInfo.UUID) - stdout, stderr, code := runAsk(ctx, []string{"list"}) + stdout, stderr, code := runDo(ctx, []string{"list"}) if code != 0 { - t.Fatalf("ask list failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) + t.Fatalf("do list failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } if !strings.Contains(stdout.String(), agentDesc) { - t.Fatalf("ask list should contain agent task %q: %s", agentDesc, stdout.String()) + t.Fatalf("do list should contain agent task %q: %s", agentDesc, stdout.String()) } if strings.Contains(stdout.String(), noAgentDesc) { - t.Fatalf("ask list should not contain no-agent task %q: %s", noAgentDesc, stdout.String()) + t.Fatalf("do list should not contain no-agent task %q: %s", noAgentDesc, stdout.String()) } for _, prefix := range []string{"na", "no-agent"} { t.Run(prefix, func(t *testing.T) { - scopedStdout, scopedStderr, scopedCode := runAsk(ctx, []string{prefix, "list"}) + scopedStdout, scopedStderr, scopedCode := runDo(ctx, []string{prefix, "list"}) if scopedCode != 0 { - t.Fatalf("ask %s list failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, scopedStdout.String(), scopedStderr.String()) + t.Fatalf("do %s list failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, scopedStdout.String(), scopedStderr.String()) } if !strings.Contains(scopedStdout.String(), noAgentDesc) { - t.Fatalf("ask %s list should contain no-agent task %q: %s", prefix, noAgentDesc, scopedStdout.String()) + t.Fatalf("do %s list should contain no-agent task %q: %s", prefix, noAgentDesc, scopedStdout.String()) } if strings.Contains(scopedStdout.String(), agentDesc) { - t.Fatalf("ask %s list should not contain agent task %q: %s", prefix, agentDesc, scopedStdout.String()) + t.Fatalf("do %s list should not contain agent task %q: %s", prefix, agentDesc, scopedStdout.String()) } }) } @@ -182,9 +182,9 @@ func TestNoAgentSelectorCommandsUseScopedTasks(t *testing.T) { } defer deleteTask(ctx, info.UUID) - _, stderr, code := runAsk(ctx, []string{"info", info.ID}) + _, stderr, code := runDo(ctx, []string{"info", info.ID}) if code == 0 { - t.Fatalf("ask info %s unexpectedly succeeded outside no-agent scope", info.ID) + t.Fatalf("do info %s unexpectedly succeeded outside no-agent scope", info.ID) } if !strings.Contains(stderr.String(), "current scope") { t.Fatalf("stderr = %q, want current-scope guidance", stderr.String()) @@ -192,19 +192,19 @@ func TestNoAgentSelectorCommandsUseScopedTasks(t *testing.T) { for _, prefix := range []string{"na", "no-agent"} { t.Run(prefix, func(t *testing.T) { - stdout, scopedStderr, scopedCode := runAsk(ctx, []string{prefix, "info", info.ID}) + stdout, scopedStderr, scopedCode := runDo(ctx, []string{prefix, "info", info.ID}) if scopedCode != 0 { - t.Fatalf("ask %s info failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, stdout.String(), scopedStderr.String()) + t.Fatalf("do %s info failed with code %d: stdout=%s stderr=%s", prefix, scopedCode, stdout.String(), scopedStderr.String()) } if !strings.Contains(stdout.String(), "UUID: "+info.UUID) { - t.Fatalf("ask %s info output missing UUID %q: %s", prefix, info.UUID, stdout.String()) + t.Fatalf("do %s info output missing UUID %q: %s", prefix, info.UUID, stdout.String()) } }) } - stdout, stderr, code := runAsk(ctx, []string{"na", "done", info.ID}) + stdout, stderr, code := runDo(ctx, []string{"na", "done", info.ID}) if code != 0 { - t.Fatalf("ask na done failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) + t.Fatalf("do na done failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } task, err := exportTaskByUUID(ctx, info.UUID) @@ -234,9 +234,9 @@ func TestNoAgentCompleteUUIDsUsesScopedTasks(t *testing.T) { } defer deleteTask(ctx, noAgentInfo.UUID) - defaultStdout, defaultStderr, defaultCode := runAsk(ctx, []string{"complete-uuids"}) + defaultStdout, defaultStderr, defaultCode := runDo(ctx, []string{"complete-uuids"}) if defaultCode != 0 { - t.Fatalf("ask complete-uuids failed with code %d: stdout=%s stderr=%s", defaultCode, defaultStdout.String(), defaultStderr.String()) + t.Fatalf("do complete-uuids failed with code %d: stdout=%s stderr=%s", defaultCode, defaultStdout.String(), defaultStderr.String()) } if !hasSelectorLine(defaultStdout.String(), agentAlias) || !hasSelectorLine(defaultStdout.String(), agentUUID) { t.Fatalf("default complete-uuids should contain agent selectors: %s", defaultStdout.String()) @@ -247,15 +247,15 @@ func TestNoAgentCompleteUUIDsUsesScopedTasks(t *testing.T) { for _, prefix := range []string{"na", "no-agent"} { t.Run(prefix, func(t *testing.T) { - stdout, stderr, code := runAsk(ctx, []string{prefix, "complete-uuids"}) + stdout, stderr, code := runDo(ctx, []string{prefix, "complete-uuids"}) if code != 0 { - t.Fatalf("ask %s complete-uuids failed with code %d: stdout=%s stderr=%s", prefix, code, stdout.String(), stderr.String()) + t.Fatalf("do %s complete-uuids failed with code %d: stdout=%s stderr=%s", prefix, code, stdout.String(), stderr.String()) } if !hasSelectorLine(stdout.String(), noAgentInfo.ID) || !hasSelectorLine(stdout.String(), noAgentInfo.UUID) { - t.Fatalf("ask %s complete-uuids should contain no-agent selectors: %s", prefix, stdout.String()) + t.Fatalf("do %s complete-uuids should contain no-agent selectors: %s", prefix, stdout.String()) } if hasSelectorLine(stdout.String(), agentAlias) || hasSelectorLine(stdout.String(), agentUUID) { - t.Fatalf("ask %s complete-uuids should not contain agent selectors: %s", prefix, stdout.String()) + t.Fatalf("do %s complete-uuids should not contain agent selectors: %s", prefix, stdout.String()) } }) } diff --git a/integrationtests/ask_test.go b/integrationtests/do_test.go index 0ebdb01..8462f3f 100644 --- a/integrationtests/ask_test.go +++ b/integrationtests/do_test.go @@ -44,12 +44,12 @@ func findRepoRoot() string { return "" } -func askBinaryPath() string { - return filepath.Join(repoRoot, "cmd", "ask", "ask") +func doBinaryPath() string { + return filepath.Join(repoRoot, "cmd", "do", "do") } -func runAsk(ctx context.Context, args []string) (stdout, stderr bytes.Buffer, exitCode int) { - cmd := exec.CommandContext(ctx, askBinaryPath(), args...) +func runDo(ctx context.Context, args []string) (stdout, stderr bytes.Buffer, exitCode int) { + cmd := exec.CommandContext(ctx, doBinaryPath(), args...) cmd.Dir = repoRoot cmd.Stdout = &stdout cmd.Stderr = &stderr @@ -64,10 +64,10 @@ func runAsk(ctx context.Context, args []string) (stdout, stderr bytes.Buffer, ex return stdout, stderr, ee.ExitCode() } -// runAskWithStdin runs ask with the given stdin. Only use this for commands +// runDoWithStdin runs do with the given stdin. Only use this for commands // that actually forward stdin to taskwarrior (currently only: delete). -func runAskWithStdin(ctx context.Context, args []string, stdin string) (stdout, stderr bytes.Buffer, exitCode int) { - cmd := exec.CommandContext(ctx, askBinaryPath(), args...) +func runDoWithStdin(ctx context.Context, args []string, stdin string) (stdout, stderr bytes.Buffer, exitCode int) { + cmd := exec.CommandContext(ctx, doBinaryPath(), args...) cmd.Dir = repoRoot cmd.Stdin = strings.NewReader(stdin) cmd.Stdout = &stdout @@ -116,23 +116,23 @@ func runTaskWithStdin(ctx context.Context, args []string, stdin string) (stdout, return stdout, stderr, ee.ExitCode() } -// createTask creates a new task via ask add and returns its UUID. -// ask add prints a human-facing created-task message, so we resolve the created UUID via ask info. +// createTask creates a new task via do add and returns its UUID. +// do add prints a human-facing created-task message, so we resolve the created UUID via do info. func createTask(ctx context.Context, desc string) (string, error) { - stdout, stderr, code := runAsk(ctx, []string{"add", "+integrationtest", desc}) + stdout, stderr, code := runDo(ctx, []string{"add", "+integrationtest", desc}) if code != 0 { return "", fmt.Errorf("create task failed (code %d): stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } id := extractTaskIDFromAddOutput(stdout.String()) if id == "" { - return "", fmt.Errorf("could not extract task ID from ask add output: %s", stdout.String()) + return "", fmt.Errorf("could not extract task ID from do add output: %s", stdout.String()) } info, ok := getTaskInfoFast(ctx, id) if !ok { - return "", fmt.Errorf("could not resolve task ID %q after ask add", id) + return "", fmt.Errorf("could not resolve task ID %q after do add", id) } if info.UUID == "" { - return "", fmt.Errorf("ask info %q did not return a UUID", id) + return "", fmt.Errorf("do info %q did not return a UUID", id) } return info.UUID, nil } @@ -241,16 +241,16 @@ func parseTaskInfoText(output string, uuid string) taskInfo { } func getTaskInfoFast(ctx context.Context, uuid string) (taskInfo, bool) { - stdout, _, code := runAsk(ctx, []string{"info", uuid}) + stdout, _, code := runDo(ctx, []string{"info", uuid}) if code != 0 { return taskInfo{}, false } return parseTaskInfoText(stdout.String(), uuid), true } -// getTaskInfoRaw returns the raw text output of ask info for a given UUID. +// getTaskInfoRaw returns the raw text output of do info for a given UUID. func getTaskInfoRaw(ctx context.Context, uuid string) (string, bool) { - stdout, _, code := runAsk(ctx, []string{"info", uuid}) + stdout, _, code := runDo(ctx, []string{"info", uuid}) if code != 0 { return "", false } @@ -272,7 +272,7 @@ func mustTaskAlias(t *testing.T, ctx context.Context, uuid string) string { func aliasCachePath(t *testing.T, cacheRoot string) string { t.Helper() - return filepath.Join(cacheRoot, "hexai", "ask", "task-aliases-v2.json") + return filepath.Join(cacheRoot, "hexai", "do", "task-aliases-v2.json") } // cleanupOrphanedIntegrationTasks deletes any tasks with the +integrationtest @@ -306,11 +306,11 @@ func TestMain(m *testing.M) { os.Exit(1) } // Always rebuild the binary so tests reflect the current source. - askBin := askBinaryPath() - cmd := exec.Command("go", "build", "-o", askBin, "./cmd/ask/") + doBin := doBinaryPath() + cmd := exec.Command("go", "build", "-o", doBin, "./cmd/do/") cmd.Dir = repoRoot if out, err := cmd.CombinedOutput(); err != nil { - fmt.Fprintf(os.Stderr, "failed to build ask binary: %v\n%s\n", err, out) + fmt.Fprintf(os.Stderr, "failed to build do binary: %v\n%s\n", err, out) os.Exit(1) } // Remove any tasks left over from previous integration test runs to avoid @@ -342,37 +342,37 @@ func TestAdd(t *testing.T) { } } -// TestAddReturnsAlias verifies that ask add outputs the human-facing alias ID in its creation message. +// TestAddReturnsAlias verifies that do add outputs the human-facing alias ID in its creation message. func TestAddReturnsAlias(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - stdout, _, code := runAsk(ctx, []string{"add", "+integrationtest", "uuid format check"}) + stdout, _, code := runDo(ctx, []string{"add", "+integrationtest", "uuid format check"}) if code != 0 { - t.Fatalf("ask add failed with code %d", code) + t.Fatalf("do add failed with code %d", code) } rawOutput := strings.TrimSpace(stdout.String()) id := extractTaskIDFromAddOutput(rawOutput) info, ok := getTaskInfoFast(ctx, id) if !ok { - t.Fatalf("ask info %q failed after add", id) + t.Fatalf("do info %q failed after add", id) } defer deleteTask(ctx, info.UUID) if id == "" { - t.Fatal("ask add returned an empty task ID") + t.Fatal("do add returned an empty task ID") } if rawOutput != "created task "+id { - t.Fatalf("ask add output = %q, want %q", rawOutput, "created task "+id) + t.Fatalf("do add output = %q, want %q", rawOutput, "created task "+id) } if uuidFormatRx.MatchString(id) { - t.Fatalf("ask add output %q leaked a UUID, want alias ID", id) + t.Fatalf("do add output %q leaked a UUID, want alias ID", id) } if info.ID != id { - t.Fatalf("ask info ID = %q, want %q", info.ID, id) + t.Fatalf("do info ID = %q, want %q", info.ID, id) } if !uuidFormatRx.MatchString(info.UUID) { - t.Fatalf("ask info UUID = %q, want valid UUID", info.UUID) + t.Fatalf("do info UUID = %q, want valid UUID", info.UUID) } } @@ -396,7 +396,7 @@ func TestAddWithDependsModifier(t *testing.T) { dep1Alias := mustTaskAlias(t, ctx, dep1UUID) dep2Alias := mustTaskAlias(t, ctx, dep2UUID) - stdout, stderr, code := runAsk(ctx, []string{ + stdout, stderr, code := runDo(ctx, []string{ "add", "+integrationtest", "depends:" + dep1Alias + "," + dep2Alias, @@ -408,13 +408,13 @@ func TestAddWithDependsModifier(t *testing.T) { "depends", }) if code != 0 { - t.Fatalf("ask add with depends modifier failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) + t.Fatalf("do add with depends modifier failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } id := extractTaskIDFromAddOutput(stdout.String()) info, ok := getTaskInfoFast(ctx, id) if !ok { - t.Fatalf("ask info %q failed after add", id) + t.Fatalf("do info %q failed after add", id) } defer deleteTask(ctx, info.UUID) @@ -439,7 +439,7 @@ func TestList(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"list"}) + stdout, _, code := runDo(ctx, []string{"list"}) if code != 0 { t.Fatalf("list failed with code %d: %s", code, stdout.String()) } @@ -465,7 +465,7 @@ func TestAll(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"all"}) + stdout, _, code := runDo(ctx, []string{"all"}) if code != 0 { t.Fatalf("all failed with code %d: %s", code, stdout.String()) } @@ -484,7 +484,7 @@ func TestReady(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"ready"}) + stdout, _, code := runDo(ctx, []string{"ready"}) if code != 0 { t.Fatalf("ready failed with code %d: %s", code, stdout.String()) } @@ -553,10 +553,10 @@ func TestInfoShowsAllDependencies(t *testing.T) { } defer deleteTask(ctx, dependent) - if stdout, stderr, code := runAsk(ctx, []string{"dep", "add", dependent, dependency2}); code != 0 { + if stdout, stderr, code := runDo(ctx, []string{"dep", "add", dependent, dependency2}); code != 0 { t.Fatalf("dep add for second dependency failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } - if stdout, stderr, code := runAsk(ctx, []string{"dep", "add", dependent, dependency1}); code != 0 { + if stdout, stderr, code := runDo(ctx, []string{"dep", "add", dependent, dependency1}); code != 0 { t.Fatalf("dep add for first dependency failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } @@ -591,7 +591,7 @@ func TestAnnotate(t *testing.T) { defer deleteTask(ctx, uuid) note := "this is a test annotation" - stdout, _, code := runAsk(ctx, []string{"annotate", uuid, note}) + stdout, _, code := runDo(ctx, []string{"annotate", uuid, note}) if code != 0 { t.Fatalf("annotate failed with code %d: %s", code, stdout.String()) } @@ -615,7 +615,7 @@ func TestStart(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"start", uuid}) + stdout, _, code := runDo(ctx, []string{"start", uuid}) if code != 0 { t.Fatalf("start failed with code %d: %s", code, stdout.String()) } @@ -642,9 +642,9 @@ func TestStop(t *testing.T) { } defer deleteTask(ctx, uuid) - runAsk(ctx, []string{"start", uuid}) + runDo(ctx, []string{"start", uuid}) - stdout, _, code := runAsk(ctx, []string{"stop", uuid}) + stdout, _, code := runDo(ctx, []string{"stop", uuid}) if code != 0 { t.Fatalf("stop failed with code %d: %s", code, stdout.String()) } @@ -670,7 +670,7 @@ func TestDone(t *testing.T) { t.Fatalf("failed to create task: %v", err) } - stdout, _, code := runAsk(ctx, []string{"done", uuid}) + stdout, _, code := runDo(ctx, []string{"done", uuid}) if code != 0 { t.Fatalf("done failed with code %d: %s", code, stdout.String()) } @@ -696,7 +696,7 @@ func TestPriority(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"priority", uuid, "H"}) + stdout, _, code := runDo(ctx, []string{"priority", uuid, "H"}) if code != 0 { t.Fatalf("priority failed with code %d: %s", code, stdout.String()) } @@ -720,7 +720,7 @@ func TestTag(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"tag", uuid, "+cli"}) + stdout, _, code := runDo(ctx, []string{"tag", uuid, "+cli"}) if code != 0 { t.Fatalf("tag add failed with code %d: %s", code, stdout.String()) } @@ -740,7 +740,7 @@ func TestTag(t *testing.T) { t.Errorf("tag cli not found on task: %+v", ti.Tags) } - runAsk(ctx, []string{"tag", uuid, "-cli"}) + runDo(ctx, []string{"tag", uuid, "-cli"}) ti2, _ := getTaskInfoFast(ctx, uuid) for _, tg := range ti2.Tags { @@ -767,7 +767,7 @@ func TestDepAdd(t *testing.T) { } defer deleteTask(ctx, uuid2) - stdout, _, code := runAsk(ctx, []string{"dep", "add", uuid2, uuid1}) + stdout, _, code := runDo(ctx, []string{"dep", "add", uuid2, uuid1}) if code != 0 { t.Fatalf("dep add failed with code %d: %s", code, stdout.String()) } @@ -807,9 +807,9 @@ func TestDepList(t *testing.T) { } defer deleteTask(ctx, uuid2) - runAsk(ctx, []string{"dep", "add", uuid2, uuid1}) + runDo(ctx, []string{"dep", "add", uuid2, uuid1}) - stdout, _, code := runAsk(ctx, []string{"dep", "list", uuid2}) + stdout, _, code := runDo(ctx, []string{"dep", "list", uuid2}) if code != 0 { t.Fatalf("dep list failed with code %d: %s", code, stdout.String()) } @@ -838,9 +838,9 @@ func TestDepRm(t *testing.T) { } defer deleteTask(ctx, uuid2) - runAsk(ctx, []string{"dep", "add", uuid2, uuid1}) + runDo(ctx, []string{"dep", "add", uuid2, uuid1}) - stdout, _, code := runAsk(ctx, []string{"dep", "rm", uuid2, uuid1}) + stdout, _, code := runDo(ctx, []string{"dep", "rm", uuid2, uuid1}) if code != 0 { t.Fatalf("dep rm failed with code %d: %s", code, stdout.String()) } @@ -869,7 +869,7 @@ func TestModify(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"modify", uuid, "priority:H"}) + stdout, _, code := runDo(ctx, []string{"modify", uuid, "priority:H"}) if code != 0 { t.Fatalf("modify failed with code %d: %s", code, stdout.String()) } @@ -894,7 +894,7 @@ func TestDenotate(t *testing.T) { defer deleteTask(ctx, uuid) note := "annotation to remove" - runAsk(ctx, []string{"annotate", uuid, note}) + runDo(ctx, []string{"annotate", uuid, note}) // Verify the annotation is present before denotating. rawBefore, _ := getTaskInfoRaw(ctx, uuid) @@ -902,7 +902,7 @@ func TestDenotate(t *testing.T) { t.Fatalf("annotation %q not found before denotate", note) } - _, _, code := runAsk(ctx, []string{"denotate", uuid, note}) + _, _, code := runDo(ctx, []string{"denotate", uuid, note}) if code != 0 { t.Fatalf("denotate returned non-zero code: %d", code) } @@ -924,7 +924,7 @@ func TestDelete(t *testing.T) { } // delete forwards stdin to taskwarrior for confirmation. - stdout, _, code := runAskWithStdin(ctx, []string{"delete", uuid}, "yes\n") + stdout, _, code := runDoWithStdin(ctx, []string{"delete", uuid}, "yes\n") if code != 0 { t.Fatalf("delete failed with code %d: %s", code, stdout.String()) } @@ -948,7 +948,7 @@ func TestUrgency(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{"urgency"}) + stdout, _, code := runDo(ctx, []string{"urgency"}) if code != 0 { t.Fatalf("urgency failed with code %d: %s", code, stdout.String()) } @@ -967,7 +967,7 @@ func TestDefaultCommand(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, _, code := runAsk(ctx, []string{}) + stdout, _, code := runDo(ctx, []string{}) if code != 0 { t.Fatalf("default command (list) failed with code %d: %s", code, stdout.String()) } @@ -980,7 +980,7 @@ func TestHelp(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - stdout, _, code := runAsk(ctx, []string{"help"}) + stdout, _, code := runDo(ctx, []string{"help"}) if code != 0 { t.Fatalf("help returned non-zero exit code %d", code) } @@ -996,13 +996,13 @@ func TestFish(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - stdout, stderr, code := runAsk(ctx, []string{"fish"}) + stdout, stderr, code := runDo(ctx, []string{"fish"}) if code != 0 { t.Fatalf("fish returned non-zero exit code %d: stderr=%s", code, stderr.String()) } out := stdout.String() for _, fragment := range []string{ - "# Source with: ask fish | source", + "# Source with: do fish | source", "complete -c", "complete-uuids", "annotate", @@ -1021,14 +1021,14 @@ func TestFishRejectsExtraArgs(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - stdout, stderr, code := runAsk(ctx, []string{"fish", "extra"}) + stdout, stderr, code := runDo(ctx, []string{"fish", "extra"}) if code == 0 { t.Fatalf("expected non-zero exit code for fish extra args, got 0") } if stdout.Len() != 0 { t.Errorf("fish with extra args wrote unexpected stdout: %s", stdout.String()) } - if !strings.Contains(stderr.String(), "usage: ask fish") { + if !strings.Contains(stderr.String(), "usage: do fish") { t.Errorf("fish with extra args stderr missing usage text: %s", stderr.String()) } } @@ -1044,7 +1044,7 @@ func TestCompleteUUIDs(t *testing.T) { } defer deleteTask(ctx, uuid) - stdout, stderr, code := runAsk(ctx, []string{"complete-uuids"}) + stdout, stderr, code := runDo(ctx, []string{"complete-uuids"}) if code != 0 { t.Fatalf("complete-uuids returned non-zero exit code %d: stderr=%s", code, stderr.String()) } @@ -1079,7 +1079,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { } note := "integration alias annotation" - stdout, _, code := runAsk(ctx, []string{"annotate", alias, note}) + stdout, _, code := runDo(ctx, []string{"annotate", alias, note}) if code != 0 { t.Fatalf("annotate by alias failed with code %d: %s", code, stdout.String()) } @@ -1093,10 +1093,10 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { } note2 := "remove me via alias" - if _, _, code = runAsk(ctx, []string{"annotate", alias, note2}); code != 0 { + if _, _, code = runDo(ctx, []string{"annotate", alias, note2}); code != 0 { t.Fatalf("setup annotate for denotate failed with code %d", code) } - stdout, _, code = runAsk(ctx, []string{"denotate", alias, note2}) + stdout, _, code = runDo(ctx, []string{"denotate", alias, note2}) if code != 0 { t.Fatalf("denotate by alias failed with code %d: %s", code, stdout.String()) } @@ -1105,7 +1105,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("annotation %q still present after alias denotate: %s", note2, raw) } - stdout, _, code = runAsk(ctx, []string{"start", alias}) + stdout, _, code = runDo(ctx, []string{"start", alias}) if code != 0 { t.Fatalf("start by alias failed with code %d: %s", code, stdout.String()) } @@ -1114,7 +1114,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("task not started after alias start: %+v", ti) } - stdout, _, code = runAsk(ctx, []string{"stop", alias}) + stdout, _, code = runDo(ctx, []string{"stop", alias}) if code != 0 { t.Fatalf("stop by alias failed with code %d: %s", code, stdout.String()) } @@ -1123,7 +1123,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("task not stopped after alias stop: %+v", ti) } - stdout, _, code = runAsk(ctx, []string{"priority", alias, "H"}) + stdout, _, code = runDo(ctx, []string{"priority", alias, "H"}) if code != 0 { t.Fatalf("priority by alias failed with code %d: %s", code, stdout.String()) } @@ -1132,7 +1132,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("task priority not updated after alias priority: %+v", ti) } - stdout, _, code = runAsk(ctx, []string{"modify", alias, "priority:L"}) + stdout, _, code = runDo(ctx, []string{"modify", alias, "priority:L"}) if code != 0 { t.Fatalf("modify by alias failed with code %d: %s", code, stdout.String()) } @@ -1141,7 +1141,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("task priority not updated after alias modify: %+v", ti) } - stdout, _, code = runAsk(ctx, []string{"tag", alias, "+aliascheck"}) + stdout, _, code = runDo(ctx, []string{"tag", alias, "+aliascheck"}) if code != 0 { t.Fatalf("tag by alias failed with code %d: %s", code, stdout.String()) } @@ -1157,12 +1157,12 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { defer deleteTask(ctx, depUUID) depAlias := mustTaskAlias(t, ctx, depUUID) - stdout, _, code = runAsk(ctx, []string{"dep", "add", alias, depAlias}) + stdout, _, code = runDo(ctx, []string{"dep", "add", alias, depAlias}) if code != 0 { t.Fatalf("dep add by alias failed with code %d: %s", code, stdout.String()) } - stdout, _, code = runAsk(ctx, []string{"dep", "list", alias}) + stdout, _, code = runDo(ctx, []string{"dep", "list", alias}) if code != 0 { t.Fatalf("dep list by alias failed with code %d: %s", code, stdout.String()) } @@ -1170,11 +1170,11 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("dep list by alias output = %q, want alias %q without raw UUID", stdout.String(), depAlias) } - stdout, _, code = runAsk(ctx, []string{"dep", "rm", alias, depAlias}) + stdout, _, code = runDo(ctx, []string{"dep", "rm", alias, depAlias}) if code != 0 { t.Fatalf("dep rm by alias failed with code %d: %s", code, stdout.String()) } - stdout, _, code = runAsk(ctx, []string{"dep", "list", alias}) + stdout, _, code = runDo(ctx, []string{"dep", "list", alias}) if code != 0 { t.Fatalf("dep list after rm failed with code %d: %s", code, stdout.String()) } @@ -1187,7 +1187,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("failed to create done task: %v", err) } doneAlias := mustTaskAlias(t, ctx, doneUUID) - stdout, _, code = runAsk(ctx, []string{"done", doneAlias}) + stdout, _, code = runDo(ctx, []string{"done", doneAlias}) if code != 0 { t.Fatalf("done by alias failed with code %d: %s", code, stdout.String()) } @@ -1202,7 +1202,7 @@ func TestAliasSelectorsAcrossUUIDCommands(t *testing.T) { t.Fatalf("failed to create delete task: %v", err) } deleteAlias := mustTaskAlias(t, ctx, deleteUUID) - stdout, _, code = runAskWithStdin(ctx, []string{"delete", deleteAlias}, "yes\n") + stdout, _, code = runDoWithStdin(ctx, []string{"delete", deleteAlias}, "yes\n") if code != 0 { t.Fatalf("delete by alias failed with code %d: %s", code, stdout.String()) } @@ -1246,7 +1246,7 @@ func TestAliasCachePrunesExpiredEntriesOlderThan120Days(t *testing.T) { t.Fatalf("WriteFile(%s): %v", cachePath, err) } - stdout, stderr, code := runAsk(ctx, []string{"info", uuid}) + stdout, stderr, code := runDo(ctx, []string{"info", uuid}) if code != 0 { t.Fatalf("info failed with code %d: stdout=%s stderr=%s", code, stdout.String(), stderr.String()) } @@ -1273,7 +1273,7 @@ func TestUnknownCommand(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - _, stderr, code := runAsk(ctx, []string{"notacommand"}) + _, stderr, code := runDo(ctx, []string{"notacommand"}) if code == 0 { t.Fatalf("expected non-zero exit code for unknown command, got 0") } diff --git a/internal/askcli/command_add.go b/internal/askcli/command_add.go index b94fe89..d2fb2ea 100644 --- a/internal/askcli/command_add.go +++ b/internal/askcli/command_add.go @@ -10,7 +10,7 @@ import ( func (d *Dispatcher) handleAdd(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask add requires a description\n") + _, _ = io.WriteString(stderr, "error: do add requires a description\n") return 1, nil } modifiers, description, dependencySelectors, err := parseAddArgs(args[1:]) @@ -19,7 +19,7 @@ func (d *Dispatcher) handleAdd(ctx context.Context, args []string, stdout, stder return 1, nil } if strings.TrimSpace(description) == "" { - _, _ = io.WriteString(stderr, "error: ask add requires a description\n") + _, _ = io.WriteString(stderr, "error: do add requires a description\n") return 1, nil } dependencyUUIDs, code, err := d.resolveAddDependencyUUIDs(ctx, dependencySelectors, stderr) @@ -112,14 +112,14 @@ func parseAddArgs(args []string) (modifiers []string, description string, depend func parseAddDependencySelectors(arg string) ([]string, error) { raw := strings.TrimSpace(strings.TrimPrefix(arg, "depends:")) if raw == "" { - return nil, fmt.Errorf("ask add depends:<id|uuid>[,<id|uuid>...] requires at least one dependency ID or UUID") + return nil, fmt.Errorf("do add depends:<id|uuid>[,<id|uuid>...] requires at least one dependency ID or UUID") } parts := strings.Split(raw, ",") selectors := make([]string, 0, len(parts)) for _, part := range parts { selector := strings.TrimSpace(part) if selector == "" { - return nil, fmt.Errorf("ask add dependency selector list contains an empty item") + return nil, fmt.Errorf("do add dependency selector list contains an empty item") } selectors = append(selectors, selector) } diff --git a/internal/askcli/command_delete.go b/internal/askcli/command_delete.go index 801d4cf..7356753 100644 --- a/internal/askcli/command_delete.go +++ b/internal/askcli/command_delete.go @@ -8,7 +8,7 @@ import ( func (d *Dispatcher) handleDelete(ctx context.Context, args []string, stdin io.Reader, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask delete requires an ID or UUID argument\n") + _, _ = io.WriteString(stderr, "error: do delete requires an ID or UUID argument\n") return 1, nil } resolved, _, code, err := d.resolveTaskSelector(ctx, args[1], stderr) diff --git a/internal/askcli/command_dep.go b/internal/askcli/command_dep.go index aa28df8..b6fb2b9 100644 --- a/internal/askcli/command_dep.go +++ b/internal/askcli/command_dep.go @@ -10,7 +10,7 @@ import ( func (d *Dispatcher) handleDep(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask dep requires an operation (add/rm/list) and arguments\n") + _, _ = io.WriteString(stderr, "error: do dep requires an operation (add/rm/list) and arguments\n") return 1, nil } op := args[1] @@ -20,14 +20,14 @@ func (d *Dispatcher) handleDep(ctx context.Context, args []string, stdout, stder case "list": return d.handleDepList(ctx, args, stdout, stderr) default: - fmt.Fprintf(stderr, "error: ask dep: unknown operation %q (use add, rm, or list)\n", op) + fmt.Fprintf(stderr, "error: do dep: unknown operation %q (use add, rm, or list)\n", op) return 1, nil } } func (d *Dispatcher) handleDepAddRm(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 4 { - _, _ = io.WriteString(stderr, "error: ask dep add/rm requires <id|uuid> <dep-id|dep-uuid>\n") + _, _ = io.WriteString(stderr, "error: do dep add/rm requires <id|uuid> <dep-id|dep-uuid>\n") return 1, nil } resolved, _, code, err := d.resolveTaskSelector(ctx, args[2], stderr) @@ -59,7 +59,7 @@ func (d *Dispatcher) handleDepAddRm(ctx context.Context, args []string, stdout, func (d *Dispatcher) handleDepList(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask dep list requires <id|uuid>\n") + _, _ = io.WriteString(stderr, "error: do dep list requires <id|uuid>\n") return 1, nil } _, tasks, code, err := d.resolveTaskSelector(ctx, args[2], stderr) diff --git a/internal/askcli/command_fish.go b/internal/askcli/command_fish.go index f4ca9e0..401a9e2 100644 --- a/internal/askcli/command_fish.go +++ b/internal/askcli/command_fish.go @@ -10,12 +10,12 @@ import ( func (d *Dispatcher) handleFish(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { _ = ctx if len(args) != 1 { - fmt.Fprintln(stderr, "usage: ask fish") + fmt.Fprintln(stderr, "usage: do fish") return 1, nil } binaryPath, err := os.Executable() if err != nil { - binaryPath = "ask" + binaryPath = "do" } if _, err := io.WriteString(stdout, FishCompletionFor(binaryPath)); err != nil { return 1, err diff --git a/internal/askcli/command_info_add_test.go b/internal/askcli/command_info_add_test.go index 74b2380..0a07479 100644 --- a/internal/askcli/command_info_add_test.go +++ b/internal/askcli/command_info_add_test.go @@ -334,7 +334,7 @@ func TestHandleAdd_DependsModifierWithoutSelectors(t *testing.T) { if code != 1 { t.Fatalf("add code = %d, want 1", code) } - if got := stderr.String(); !strings.Contains(got, "ask add depends:<id|uuid>[,<id|uuid>...] requires at least one dependency ID or UUID") { + if got := stderr.String(); !strings.Contains(got, "do add depends:<id|uuid>[,<id|uuid>...] requires at least one dependency ID or UUID") { t.Fatalf("stderr = %q, want depends: selector error", got) } } diff --git a/internal/askcli/command_write.go b/internal/askcli/command_write.go index d8dbf5b..31a3f39 100644 --- a/internal/askcli/command_write.go +++ b/internal/askcli/command_write.go @@ -31,7 +31,7 @@ func (d *Dispatcher) runSingleTaskCommand( func (d *Dispatcher) handleDenotate(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask denotate requires an ID or UUID and text argument\n") + _, _ = io.WriteString(stderr, "error: do denotate requires an ID or UUID and text argument\n") return 1, nil } text := args[2] @@ -42,7 +42,7 @@ func (d *Dispatcher) handleDenotate(ctx context.Context, args []string, stdout, func (d *Dispatcher) handleModify(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask modify requires an ID or UUID and modification args\n") + _, _ = io.WriteString(stderr, "error: do modify requires an ID or UUID and modification args\n") return 1, nil } modArgs := args[2:] @@ -53,7 +53,7 @@ func (d *Dispatcher) handleModify(ctx context.Context, args []string, stdout, st func (d *Dispatcher) handleAnnotate(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask annotate requires an ID or UUID and note argument\n") + _, _ = io.WriteString(stderr, "error: do annotate requires an ID or UUID and note argument\n") return 1, nil } note := strings.Join(args[2:], " ") @@ -64,7 +64,7 @@ func (d *Dispatcher) handleAnnotate(ctx context.Context, args []string, stdout, func (d *Dispatcher) handleStart(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask start requires an ID or UUID argument\n") + _, _ = io.WriteString(stderr, "error: do start requires an ID or UUID argument\n") return 1, nil } return d.runSingleTaskCommand(ctx, args[1], stdout, stderr, func(resolved resolvedTaskSelector) []string { @@ -76,7 +76,7 @@ func (d *Dispatcher) handleStart(ctx context.Context, args []string, stdout, std func (d *Dispatcher) handleStop(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask stop requires an ID or UUID argument\n") + _, _ = io.WriteString(stderr, "error: do stop requires an ID or UUID argument\n") return 1, nil } return d.runSingleTaskCommand(ctx, args[1], stdout, stderr, func(resolved resolvedTaskSelector) []string { @@ -86,7 +86,7 @@ func (d *Dispatcher) handleStop(ctx context.Context, args []string, stdout, stde func (d *Dispatcher) handleDone(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 2 { - _, _ = io.WriteString(stderr, "error: ask done requires an ID or UUID argument\n") + _, _ = io.WriteString(stderr, "error: do done requires an ID or UUID argument\n") return 1, nil } return d.runSingleTaskCommand(ctx, args[1], stdout, stderr, func(resolved resolvedTaskSelector) []string { @@ -96,7 +96,7 @@ func (d *Dispatcher) handleDone(ctx context.Context, args []string, stdout, stde func (d *Dispatcher) handlePriority(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask priority requires an ID or UUID and priority (H/M/L)\n") + _, _ = io.WriteString(stderr, "error: do priority requires an ID or UUID and priority (H/M/L)\n") return 1, nil } priority := args[2] @@ -107,7 +107,7 @@ func (d *Dispatcher) handlePriority(ctx context.Context, args []string, stdout, func (d *Dispatcher) handleTag(ctx context.Context, args []string, stdout, stderr io.Writer) (int, error) { if len(args) < 3 { - _, _ = io.WriteString(stderr, "error: ask tag requires an ID or UUID and +/-tag\n") + _, _ = io.WriteString(stderr, "error: do tag requires an ID or UUID and +/-tag\n") return 1, nil } tag := args[2] diff --git a/internal/askcli/completion.go b/internal/askcli/completion.go index 0d8b584..3e30c6c 100644 --- a/internal/askcli/completion.go +++ b/internal/askcli/completion.go @@ -54,9 +54,9 @@ func fishAddDependencyModifierCompletionContext(positional []string, current str return current == "depends" || strings.HasPrefix(current, "depends:") } -// FishCompletion returns the default Fish completion script for the ask CLI. +// FishCompletion returns the default Fish completion script for the do CLI. func FishCompletion() string { - return FishCompletionFor("ask") + return FishCompletionFor("do") } // FishCompletionFor returns a Fish completion script that points to the provided binary path. @@ -66,30 +66,30 @@ func FishCompletionFor(binaryPath string) string { writeFishContextFunctions(&b) writeFishTaskSelectorFunction(&b, binaryPath) writeFishAddDependencyModifierFunction(&b) - b.WriteString("complete -c ask -f\n") - b.WriteString("complete -c ask -s j -l json -d 'Emit JSON output'\n") + b.WriteString("complete -c do -f\n") + b.WriteString("complete -c do -s j -l json -d 'Emit JSON output'\n") for _, item := range []fishCompletionItem{ {name: "na", description: "Run against project tasks without +agent"}, {name: "no-agent", description: "Run against project tasks without +agent"}, } { - writeFishCompletionLine(&b, "__ask_needs_root_completion", item) + writeFishCompletionLine(&b, "__do_needs_root_completion", item) } for _, entry := range commandRegistry.rootCompletionEntries() { item := fishCompletionItem{name: entry.name, description: entry.description} - writeFishCompletionLine(&b, "__ask_needs_command_completion", item) + writeFishCompletionLine(&b, "__do_needs_command_completion", item) } for _, item := range askDepCompletionItems { - writeFishCompletionLine(&b, "__ask_in_dep_context", item) + writeFishCompletionLine(&b, "__do_in_dep_context", item) } - writeFishUUIDCompletionLine(&b, "__ask_in_uuid_context", "Task selector") - writeFishUUIDCompletionLine(&b, "__ask_in_dep_uuid_context", "Task selector") - writeFishFunctionCompletionLine(&b, "__ask_in_add_dep_modifier_context", "__ask_add_dependency_modifiers", "Task dependency") + writeFishUUIDCompletionLine(&b, "__do_in_uuid_context", "Task selector") + writeFishUUIDCompletionLine(&b, "__do_in_dep_uuid_context", "Task selector") + writeFishFunctionCompletionLine(&b, "__do_in_add_dep_modifier_context", "__do_add_dependency_modifiers", "Task dependency") return b.String() } func writeFishPreamble(b *strings.Builder) { - b.WriteString("# Fish completion for ask.\n") - b.WriteString("# Source with: ask fish | source\n\n") + b.WriteString("# Fish completion for do.\n") + b.WriteString("# Source with: do fish | source\n\n") } func writeFishContextFunctions(b *strings.Builder) { @@ -105,7 +105,7 @@ func writeFishContextFunctions(b *strings.Builder) { } func writeFishPositionalTokensFunction(b *strings.Builder) { - b.WriteString("function __ask_positional_tokens\n") + b.WriteString("function __do_positional_tokens\n") b.WriteString(" set -l tokens (commandline -opc)\n") b.WriteString(" set -l positional\n") b.WriteString(" for token in $tokens[2..-1]\n") @@ -121,8 +121,8 @@ func writeFishPositionalTokensFunction(b *strings.Builder) { } func writeFishCommandPositionalsFunction(b *strings.Builder) { - b.WriteString("function __ask_command_positionals\n") - b.WriteString(" set -l positional (__ask_positional_tokens)\n") + b.WriteString("function __do_command_positionals\n") + b.WriteString(" set -l positional (__do_positional_tokens)\n") b.WriteString(" if test (count $positional) -gt 0\n") b.WriteString(" switch $positional[1]\n") b.WriteString(" case na no-agent\n") @@ -139,8 +139,8 @@ func writeFishCommandPositionalsFunction(b *strings.Builder) { } func writeFishScopePrefixFunction(b *strings.Builder) { - b.WriteString("function __ask_scope_prefix\n") - b.WriteString(" set -l positional (__ask_positional_tokens)\n") + b.WriteString("function __do_scope_prefix\n") + b.WriteString(" set -l positional (__do_positional_tokens)\n") b.WriteString(" if test (count $positional) -eq 0\n") b.WriteString(" return 1\n") b.WriteString(" end\n") @@ -156,8 +156,8 @@ func writeFishScopePrefixFunction(b *strings.Builder) { } func writeFishNeedsRootCompletionFunction(b *strings.Builder) { - b.WriteString("function __ask_needs_root_completion\n") - b.WriteString(" set -l positional (__ask_positional_tokens)\n") + b.WriteString("function __do_needs_root_completion\n") + b.WriteString(" set -l positional (__do_positional_tokens)\n") b.WriteString(" if test (count $positional) -eq 0\n") b.WriteString(" return 0\n") b.WriteString(" end\n") @@ -166,8 +166,8 @@ func writeFishNeedsRootCompletionFunction(b *strings.Builder) { } func writeFishNeedsCommandCompletionFunction(b *strings.Builder) { - b.WriteString("function __ask_needs_command_completion\n") - b.WriteString(" set -l positional (__ask_positional_tokens)\n") + b.WriteString("function __do_needs_command_completion\n") + b.WriteString(" set -l positional (__do_positional_tokens)\n") b.WriteString(" if test (count $positional) -eq 0\n") b.WriteString(" return 0\n") b.WriteString(" end\n") @@ -182,8 +182,8 @@ func writeFishNeedsCommandCompletionFunction(b *strings.Builder) { } func writeFishDepContextFunction(b *strings.Builder) { - b.WriteString("function __ask_in_dep_context\n") - b.WriteString(" set -l positional (__ask_command_positionals)\n") + b.WriteString("function __do_in_dep_context\n") + b.WriteString(" set -l positional (__do_command_positionals)\n") b.WriteString(" if test (count $positional) -lt 1\n") b.WriteString(" return 1\n") b.WriteString(" end\n") @@ -195,8 +195,8 @@ func writeFishDepContextFunction(b *strings.Builder) { } func writeFishUUIDContextFunction(b *strings.Builder) { - b.WriteString("function __ask_in_uuid_context\n") - b.WriteString(" set -l positional (__ask_command_positionals)\n") + b.WriteString("function __do_in_uuid_context\n") + b.WriteString(" set -l positional (__do_command_positionals)\n") b.WriteString(" if test (count $positional) -eq 0\n") b.WriteString(" return 1\n") b.WriteString(" end\n") @@ -216,8 +216,8 @@ func writeFishUUIDContextFunction(b *strings.Builder) { } func writeFishDepUUIDContextFunction(b *strings.Builder) { - b.WriteString("function __ask_in_dep_uuid_context\n") - b.WriteString(" set -l positional (__ask_command_positionals)\n") + b.WriteString("function __do_in_dep_uuid_context\n") + b.WriteString(" set -l positional (__do_command_positionals)\n") b.WriteString(" if test (count $positional) -lt 2\n") b.WriteString(" return 1\n") b.WriteString(" end\n") @@ -241,8 +241,8 @@ func writeFishDepUUIDContextFunction(b *strings.Builder) { } func writeFishAddDependencyModifierContextFunction(b *strings.Builder) { - b.WriteString("function __ask_in_add_dep_modifier_context\n") - b.WriteString(" set -l positional (__ask_command_positionals)\n") + b.WriteString("function __do_in_add_dep_modifier_context\n") + b.WriteString(" set -l positional (__do_command_positionals)\n") b.WriteString(" if test (count $positional) -lt 1\n") b.WriteString(" return 1\n") b.WriteString(" end\n") @@ -258,38 +258,38 @@ func writeFishAddDependencyModifierContextFunction(b *strings.Builder) { } func writeFishTaskSelectorFunction(b *strings.Builder, binaryPath string) { - b.WriteString("function __ask_task_selectors\n") - b.WriteString(" set -l ask_bin ") + b.WriteString("function __do_task_selectors\n") + b.WriteString(" set -l do_bin ") b.WriteString(quoteFishString(binaryPath)) b.WriteString("\n") - b.WriteString(" set -l scope_prefix (__ask_scope_prefix)\n") + b.WriteString(" set -l scope_prefix (__do_scope_prefix)\n") b.WriteString(" set -l cache_key default\n") b.WriteString(" if test -n \"$scope_prefix\"\n") b.WriteString(" set cache_key $scope_prefix\n") b.WriteString(" end\n") b.WriteString(" set -l now (date +%s)\n") - b.WriteString(" if set -q __ask_task_selector_cache_until; and test $__ask_task_selector_cache_until -ge $now; and set -q __ask_task_selector_cache_key; and test \"$__ask_task_selector_cache_key\" = \"$cache_key\"\n") - b.WriteString(" printf '%s\\n' $__ask_task_selector_cache\n") + b.WriteString(" if set -q __do_task_selector_cache_until; and test $__do_task_selector_cache_until -ge $now; and set -q __do_task_selector_cache_key; and test \"$__do_task_selector_cache_key\" = \"$cache_key\"\n") + b.WriteString(" printf '%s\\n' $__do_task_selector_cache\n") b.WriteString(" return 0\n") b.WriteString(" end\n") b.WriteString(" set -l selectors\n") b.WriteString(" if test -n \"$scope_prefix\"\n") - b.WriteString(" set selectors (command $ask_bin $scope_prefix complete-uuids 2>/dev/null)\n") + b.WriteString(" set selectors (command $do_bin $scope_prefix complete-uuids 2>/dev/null)\n") b.WriteString(" else\n") - b.WriteString(" set selectors (command $ask_bin complete-uuids 2>/dev/null)\n") + b.WriteString(" set selectors (command $do_bin complete-uuids 2>/dev/null)\n") b.WriteString(" end\n") b.WriteString(" if test $status -ne 0\n") b.WriteString(" return 1\n") b.WriteString(" end\n") - b.WriteString(" set -g __ask_task_selector_cache $selectors\n") - b.WriteString(" set -g __ask_task_selector_cache_until (math $now + 2)\n") - b.WriteString(" set -g __ask_task_selector_cache_key $cache_key\n") + b.WriteString(" set -g __do_task_selector_cache $selectors\n") + b.WriteString(" set -g __do_task_selector_cache_until (math $now + 2)\n") + b.WriteString(" set -g __do_task_selector_cache_key $cache_key\n") b.WriteString(" printf '%s\\n' $selectors\n") b.WriteString("end\n\n") } func writeFishAddDependencyModifierFunction(b *strings.Builder) { - b.WriteString("function __ask_add_dependency_modifiers\n") + b.WriteString("function __do_add_dependency_modifiers\n") b.WriteString(" set -l current (commandline -ct)\n") b.WriteString(" if test $current = depends\n") b.WriteString(" printf '%s\\n' 'depends:'\n") @@ -308,9 +308,9 @@ func writeFishAddDependencyModifierFunction(b *strings.Builder) { b.WriteString(" set chosen $pieces[1..-2]\n") b.WriteString(" end\n") b.WriteString(" end\n") - // Each item from __ask_task_selectors is "selector\tdescription"; extract + // Each item from __do_task_selectors is "selector\tdescription"; extract // just the selector (before the tab) for matching and output purposes. - b.WriteString(" for item in (__ask_task_selectors)\n") + b.WriteString(" for item in (__do_task_selectors)\n") b.WriteString(" set -l selector (string split -m1 '\\t' -- $item)[1]\n") b.WriteString(" if contains -- $selector $chosen\n") b.WriteString(" continue\n") @@ -328,7 +328,7 @@ func writeFishAddDependencyModifierFunction(b *strings.Builder) { } func writeFishCompletionLine(b *strings.Builder, condition string, item fishCompletionItem) { - b.WriteString("complete -c ask -n '") + b.WriteString("complete -c do -n '") b.WriteString(condition) b.WriteString("' -a '") b.WriteString(item.name) @@ -338,15 +338,15 @@ func writeFishCompletionLine(b *strings.Builder, condition string, item fishComp } func writeFishUUIDCompletionLine(b *strings.Builder, condition, description string) { - b.WriteString("complete -c ask -n '") + b.WriteString("complete -c do -n '") b.WriteString(condition) - b.WriteString("' -a '(__ask_task_selectors)' -d '") + b.WriteString("' -a '(__do_task_selectors)' -d '") b.WriteString(strings.ReplaceAll(description, "'", "\\'")) b.WriteString("'\n") } func writeFishFunctionCompletionLine(b *strings.Builder, condition, functionName, description string) { - b.WriteString("complete -c ask -n '") + b.WriteString("complete -c do -n '") b.WriteString(condition) b.WriteString("' -a '(") b.WriteString(functionName) diff --git a/internal/askcli/completion_test.go b/internal/askcli/completion_test.go index baa3d84..012927d 100644 --- a/internal/askcli/completion_test.go +++ b/internal/askcli/completion_test.go @@ -18,38 +18,38 @@ func TestFishCompletion_IncludesCommandsAndExcludesExport(t *testing.T) { } } for _, line := range []string{ - "# Source with: ask fish | source", - "complete -c ask -n '__ask_in_dep_context' -a 'add' -d 'Add a dependency'", - "complete -c ask -n '__ask_in_dep_context' -a 'rm' -d 'Remove a dependency'", - "complete -c ask -n '__ask_in_dep_context' -a 'list' -d 'List dependencies'", - "function __ask_command_positionals", - "function __ask_scope_prefix", - "function __ask_task_selectors", - "function __ask_add_dependency_modifiers", - `set -l ask_bin "ask"`, + "# Source with: do fish | source", + "complete -c do -n '__do_in_dep_context' -a 'add' -d 'Add a dependency'", + "complete -c do -n '__do_in_dep_context' -a 'rm' -d 'Remove a dependency'", + "complete -c do -n '__do_in_dep_context' -a 'list' -d 'List dependencies'", + "function __do_command_positionals", + "function __do_scope_prefix", + "function __do_task_selectors", + "function __do_add_dependency_modifiers", + `set -l do_bin "do"`, "set -l selectors", - "set selectors (command $ask_bin complete-uuids 2>/dev/null)", - "set selectors (command $ask_bin $scope_prefix complete-uuids 2>/dev/null)", - "complete -c ask -n '__ask_in_uuid_context' -a '(__ask_task_selectors)' -d 'Task selector'", - "complete -c ask -n '__ask_in_dep_uuid_context' -a '(__ask_task_selectors)' -d 'Task selector'", - "complete -c ask -n '__ask_in_add_dep_modifier_context' -a '(__ask_add_dependency_modifiers)' -d 'Task dependency'", + "set selectors (command $do_bin complete-uuids 2>/dev/null)", + "set selectors (command $do_bin $scope_prefix complete-uuids 2>/dev/null)", + "complete -c do -n '__do_in_uuid_context' -a '(__do_task_selectors)' -d 'Task selector'", + "complete -c do -n '__do_in_dep_uuid_context' -a '(__do_task_selectors)' -d 'Task selector'", + "complete -c do -n '__do_in_add_dep_modifier_context' -a '(__do_add_dependency_modifiers)' -d 'Task dependency'", // The dep modifier function must extract just the selector (before the // tab) from each tab-separated "selector\tdescription" completion item. - "for item in (__ask_task_selectors)", + "for item in (__do_task_selectors)", "set -l selector (string split -m1 '\\t' -- $item)[1]", } { if !strings.Contains(script, line) { t.Fatalf("script missing dep completion line %q", line) } } - if strings.Contains(script, "ask export") { + if strings.Contains(script, "do export") { t.Fatalf("script should not advertise non-existent export command") } - if strings.Contains(script, "assets/ask.fish") { + if strings.Contains(script, "assets/do.fish") { t.Fatalf("script should not reference a static asset") } for _, name := range []string{"info", "annotate", "start", "stop", "done", "priority", "tag", "modify", "denotate", "delete"} { - if strings.Contains(script, "complete -c ask -n '__ask_in_uuid_context' -a '"+name+"'") { + if strings.Contains(script, "complete -c do -n '__do_in_uuid_context' -a '"+name+"'") { t.Fatalf("script should not hard-code UUID completion item %q", name) } } @@ -136,10 +136,10 @@ func TestFishAddDependencyModifierCompletionContext(t *testing.T) { } func TestFishCompletionFor_EmbedsBinaryPath(t *testing.T) { - script := FishCompletionFor(`/tmp/ask "$HOME"`) + script := FishCompletionFor(`/tmp/do "$HOME"`) for _, line := range []string{ - `set -l ask_bin "/tmp/ask \"\$HOME\""`, - "set selectors (command $ask_bin complete-uuids 2>/dev/null)", + `set -l do_bin "/tmp/do \"\$HOME\""`, + "set selectors (command $do_bin complete-uuids 2>/dev/null)", } { if !strings.Contains(script, line) { t.Fatalf("script missing %q", line) diff --git a/internal/askcli/dispatch.go b/internal/askcli/dispatch.go index eab793b..3167421 100644 --- a/internal/askcli/dispatch.go +++ b/internal/askcli/dispatch.go @@ -6,7 +6,7 @@ import ( "io" ) -// Runner performs CLI work that would otherwise be handled by ask itself. +// Runner performs CLI work that would otherwise be handled by the do CLI itself. // // The interface is implemented by the executor that ultimately proxies commands to Taskwarrior. type Runner interface { @@ -22,7 +22,7 @@ type Dispatcher struct { // NewDispatcher creates a Dispatcher backed by the provided Runner or a default executor when nil. func NewDispatcher(runner Runner) *Dispatcher { if runner == nil { - e := NewExecutor("ask") + e := NewExecutor("do") runner = &e } return &Dispatcher{runner: runner} @@ -65,34 +65,34 @@ func (d *Dispatcher) Dispatch(ctx context.Context, args []string, stdin io.Reade } func (d *Dispatcher) help(w io.Writer) (int, error) { - _, _ = io.WriteString(w, "ask - task management CLI\n") + _, _ = io.WriteString(w, "do - task management CLI\n") _, _ = io.WriteString(w, "\nScope prefixes:\n") - _, _ = io.WriteString(w, " ask na <subcommand...> Run a subcommand against project tasks without +agent\n") - _, _ = io.WriteString(w, " ask no-agent <subcommand...> Alias for ask na\n") + _, _ = io.WriteString(w, " do na <subcommand...> Run a subcommand against project tasks without +agent\n") + _, _ = io.WriteString(w, " do no-agent <subcommand...> Alias for do na\n") _, _ = io.WriteString(w, "\nSubcommands:\n") - _, _ = io.WriteString(w, " ask add [mods...] [depends:<id|uuid>,...] <description...> Create a new task and print created task <id>\n") - _, _ = io.WriteString(w, " ask list [filters] List active tasks (default)\n") - _, _ = io.WriteString(w, " ask ready List READY tasks (not blocked)\n") - _, _ = io.WriteString(w, " ask all [filters] List all tasks including completed/deleted\n") - _, _ = io.WriteString(w, " ask info [id|uuid] Show task details or current started task\n") - _, _ = io.WriteString(w, " ask annotate <id|uuid> \"note\" Add annotation to task\n") - _, _ = io.WriteString(w, " ask start <id|uuid> Start working on task\n") - _, _ = io.WriteString(w, " ask stop <id|uuid> Stop work on a task\n") - _, _ = io.WriteString(w, " ask done <id|uuid> Mark task complete\n") - _, _ = io.WriteString(w, " ask priority <id|uuid> <P> Set priority (H/M/L)\n") - _, _ = io.WriteString(w, " ask tag <id|uuid> +/-<tag> Add or remove tag\n") - _, _ = io.WriteString(w, " ask dep add <id|uuid> <dep> Add dependency\n") - _, _ = io.WriteString(w, " ask dep rm <id|uuid> <dep> Remove dependency\n") - _, _ = io.WriteString(w, " ask dep list <id|uuid> List dependencies\n") - _, _ = io.WriteString(w, " ask urgency List tasks sorted by urgency\n") - _, _ = io.WriteString(w, " ask modify <id|uuid> <args...> Modify task fields\n") - _, _ = io.WriteString(w, " ask denotate <id|uuid> \"text\" Remove annotation\n") - _, _ = io.WriteString(w, " ask delete <id|uuid> Delete a task\n") - _, _ = io.WriteString(w, " ask fish Emit Fish shell completion script\n") + _, _ = io.WriteString(w, " do add [mods...] [depends:<id|uuid>,...] <description...> Create a new task and print created task <id>\n") + _, _ = io.WriteString(w, " do list [filters] List active tasks (default)\n") + _, _ = io.WriteString(w, " do ready List READY tasks (not blocked)\n") + _, _ = io.WriteString(w, " do all [filters] List all tasks including completed/deleted\n") + _, _ = io.WriteString(w, " do info [id|uuid] Show task details or current started task\n") + _, _ = io.WriteString(w, " do annotate <id|uuid> \"note\" Add annotation to task\n") + _, _ = io.WriteString(w, " do start <id|uuid> Start working on task\n") + _, _ = io.WriteString(w, " do stop <id|uuid> Stop work on a task\n") + _, _ = io.WriteString(w, " do done <id|uuid> Mark task complete\n") + _, _ = io.WriteString(w, " do priority <id|uuid> <P> Set priority (H/M/L)\n") + _, _ = io.WriteString(w, " do tag <id|uuid> +/-<tag> Add or remove tag\n") + _, _ = io.WriteString(w, " do dep add <id|uuid> <dep> Add dependency\n") + _, _ = io.WriteString(w, " do dep rm <id|uuid> <dep> Remove dependency\n") + _, _ = io.WriteString(w, " do dep list <id|uuid> List dependencies\n") + _, _ = io.WriteString(w, " do urgency List tasks sorted by urgency\n") + _, _ = io.WriteString(w, " do modify <id|uuid> <args...> Modify task fields\n") + _, _ = io.WriteString(w, " do denotate <id|uuid> \"text\" Remove annotation\n") + _, _ = io.WriteString(w, " do delete <id|uuid> Delete a task\n") + _, _ = io.WriteString(w, " do fish Emit Fish shell completion script\n") return 0, nil } func (d *Dispatcher) unknownCommand(w io.Writer, subcommand string) (int, error) { - fmt.Fprintf(w, "ask: unknown subcommand %q\n", subcommand) + fmt.Fprintf(w, "do: unknown subcommand %q\n", subcommand) return 1, nil } diff --git a/internal/askcli/dispatch_test.go b/internal/askcli/dispatch_test.go index e027b43..90c1b99 100644 --- a/internal/askcli/dispatch_test.go +++ b/internal/askcli/dispatch_test.go @@ -23,19 +23,19 @@ func TestDispatcher_Help(t *testing.T) { t.Fatalf("help returned error: %v", err) } output := stdout.String() - if !strings.Contains(output, "ask - task management CLI") { + if !strings.Contains(output, "do - task management CLI") { t.Fatalf("help missing title: %s", output) } - if !strings.Contains(output, "ask na <subcommand...>") || !strings.Contains(output, "ask no-agent <subcommand...>") { + if !strings.Contains(output, "do na <subcommand...>") || !strings.Contains(output, "do no-agent <subcommand...>") { t.Fatalf("help missing no-agent scope prefixes: %s", output) } - if !strings.Contains(output, "ask list") { + if !strings.Contains(output, "do list") { t.Fatalf("help missing list subcommand: %s", output) } - if !strings.Contains(output, "ask all") { + if !strings.Contains(output, "do all") { t.Fatalf("help missing all subcommand: %s", output) } - if !strings.Contains(output, "ask fish") { + if !strings.Contains(output, "do fish") { t.Fatalf("help missing fish subcommand: %s", output) } } @@ -96,8 +96,8 @@ func TestDispatcher_LongHelp(t *testing.T) { d.Dispatch(context.Background(), []string{"help"}, nil, &stdout, io.Discard) output := stdout.String() for _, sub := range []string{"add", "list", "all", "ready", "info", "annotate", "start", "stop", "done", "priority", "tag", "dep", "urgency", "modify", "denotate", "delete", "fish"} { - if !strings.Contains(output, "ask "+sub) { - t.Errorf("help missing subcommand: ask %s", sub) + if !strings.Contains(output, "do "+sub) { + t.Errorf("help missing subcommand: do %s", sub) } } } @@ -137,7 +137,7 @@ func TestDispatcher_FishSubcommandRejectsExtraArgs(t *testing.T) { if stdout.Len() != 0 { t.Fatalf("fish extra args wrote unexpected stdout: %q", stdout.String()) } - if got := stderr.String(); !strings.Contains(got, "usage: ask fish") { + if got := stderr.String(); !strings.Contains(got, "usage: do fish") { t.Fatalf("fish extra args stderr = %q, want usage", got) } } diff --git a/internal/askcli/formatter.go b/internal/askcli/formatter.go index d801f8a..fc4a1d9 100644 --- a/internal/askcli/formatter.go +++ b/internal/askcli/formatter.go @@ -168,7 +168,7 @@ func FormatSuccess(alias string) string { return fmt.Sprintf("ok %s\n", alias) } -// FormatCreatedTask returns the success string written to stdout after ask add creates a task. +// FormatCreatedTask returns the success string written to stdout after do add creates a task. func FormatCreatedTask(alias string) string { return fmt.Sprintf("created task %s\n", alias) } diff --git a/internal/askcli/task_alias_cache.go b/internal/askcli/task_alias_cache.go index e89dbb5..ff682d6 100644 --- a/internal/askcli/task_alias_cache.go +++ b/internal/askcli/task_alias_cache.go @@ -114,7 +114,7 @@ func taskAliasCachePath() (string, error) { // v2 uses reversed alias strings (e.g. "10" instead of "01") so that the // first character varies more often, improving shell auto-completion. The // old v1 file is intentionally abandoned so the mapping starts fresh. - return filepath.Join(dir, "ask", "task-aliases-v2.json"), nil + return filepath.Join(dir, "do", "task-aliases-v2.json"), nil } func (c *taskAliasCache) validate() error { diff --git a/internal/askcli/taskexec.go b/internal/askcli/taskexec.go index a1ede37..e3915d9 100644 --- a/internal/askcli/taskexec.go +++ b/internal/askcli/taskexec.go @@ -16,7 +16,7 @@ type repoTopLevelDetector func(context.Context) (string, error) type commandRunner func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error -// Executor encapsulates how ask communicates with the Taskwarrior binary. +// Executor encapsulates how the do CLI communicates with the Taskwarrior binary. type Executor struct { commandName string findBinary binaryFinder @@ -86,14 +86,14 @@ func (e Executor) Run(ctx context.Context, args []string, stdin io.Reader, stdou func (e Executor) label() string { label := strings.TrimSpace(e.commandName) if label == "" { - return "ask" + return "do" } return label } func normalizeExecutor(e Executor) Executor { if e.commandName == "" { - e.commandName = "ask" + e.commandName = "do" } if e.findBinary == nil { e.findBinary = findTaskBinary diff --git a/internal/askcli/taskexec_test.go b/internal/askcli/taskexec_test.go index 90da61a..4db988b 100644 --- a/internal/askcli/taskexec_test.go +++ b/internal/askcli/taskexec_test.go @@ -12,7 +12,7 @@ import ( ) func TestExecutorTaskArgs(t *testing.T) { - exec_ := NewExecutor("ask") + exec_ := NewExecutor("do") args, err := exec_.taskArgs(context.Background(), "/tmp/work/hexai", []string{"list", "limit:1"}) if err != nil { t.Fatalf("taskArgs returned error: %v", err) @@ -24,7 +24,7 @@ func TestExecutorTaskArgs(t *testing.T) { } func TestExecutorTaskArgs_NoAgentScope(t *testing.T) { - exec_ := NewExecutor("ask") + exec_ := NewExecutor("do") ctx := contextWithTaskScope(context.Background(), taskScopeNoAgent) args, err := exec_.taskArgs(ctx, "/tmp/work/hexai", []string{"list", "limit:1"}) if err != nil { @@ -37,7 +37,7 @@ func TestExecutorTaskArgs_NoAgentScope(t *testing.T) { } func TestExecutorTaskArgs_AddDefaultScope(t *testing.T) { - exec_ := NewExecutor("ask") + exec_ := NewExecutor("do") args, err := exec_.taskArgs(context.Background(), "/tmp/work/hexai", []string{"add", "rc.verbose=nothing", "rc.verbose=new-uuid", "new task"}) if err != nil { t.Fatalf("taskArgs returned error: %v", err) @@ -49,7 +49,7 @@ func TestExecutorTaskArgs_AddDefaultScope(t *testing.T) { } func TestExecutorTaskArgs_AddNoAgentScope(t *testing.T) { - exec_ := NewExecutor("ask") + exec_ := NewExecutor("do") ctx := contextWithTaskScope(context.Background(), taskScopeNoAgent) args, err := exec_.taskArgs(ctx, "/tmp/work/hexai", []string{"add", "rc.verbose=nothing", "rc.verbose=new-uuid", "new task"}) if err != nil { @@ -65,7 +65,7 @@ func TestExecutorRun_InjectsProjectFilterAndAgentTag(t *testing.T) { var gotName string var gotArgs []string exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(_ context.Context, name string, args []string, stdin io.Reader, stdout, stderr io.Writer) error { @@ -94,7 +94,7 @@ func TestExecutorRun_InjectsProjectFilterAndAgentTag(t *testing.T) { func TestExecutorRun_InjectsProjectFilterAndNoAgentTag(t *testing.T) { var gotArgs []string exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(_ context.Context, name string, args []string, stdin io.Reader, stdout, stderr io.Writer) error { @@ -119,7 +119,7 @@ func TestExecutorRun_InjectsProjectFilterAndNoAgentTag(t *testing.T) { func TestExecutorRun_OutsideGitRepo_IsActionable(t *testing.T) { exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "", errors.New("git failed") }, runCommand: func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error { @@ -139,7 +139,7 @@ func TestExecutorRun_OutsideGitRepo_IsActionable(t *testing.T) { func TestExecutorRun_PreservesTaskwarriorExitCode(t *testing.T) { exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error { @@ -160,7 +160,7 @@ func TestExecutorRun_PreservesStdoutAndStderr(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(_ context.Context, name string, args []string, stdin io.Reader, out, errOut io.Writer) error { @@ -187,7 +187,7 @@ func TestExecutorRun_PreservesStdoutAndStderr(t *testing.T) { func TestExecutorRun_TaskLookupFailure_IsActionable(t *testing.T) { exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "", errors.New("not found") }, } @@ -202,7 +202,7 @@ func TestExecutorRun_TaskLookupFailure_IsActionable(t *testing.T) { func TestExecutorRun_EmptyRepoName_IsActionable(t *testing.T) { exec_ := Executor{ - commandName: "ask", + commandName: "do", findBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/", nil }, } diff --git a/internal/taskproxy/run_test.go b/internal/taskproxy/run_test.go index 15c5fbb..2414d6a 100644 --- a/internal/taskproxy/run_test.go +++ b/internal/taskproxy/run_test.go @@ -15,7 +15,7 @@ func TestRunnerRun_InjectsProjectFilterAndAgentTag(t *testing.T) { var gotName string var gotArgs []string runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(_ context.Context, name string, args []string, stdin io.Reader, stdout, stderr io.Writer) error { @@ -43,7 +43,7 @@ func TestRunnerRun_InjectsProjectFilterAndAgentTag(t *testing.T) { func TestRunnerRun_OutsideGitRepo_IsActionable(t *testing.T) { runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "", errors.New("git failed") }, runCommand: func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error { @@ -63,7 +63,7 @@ func TestRunnerRun_OutsideGitRepo_IsActionable(t *testing.T) { func TestRunnerRun_PreservesTaskwarriorExitCode(t *testing.T) { runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(context.Context, string, []string, io.Reader, io.Writer, io.Writer) error { @@ -84,7 +84,7 @@ func TestRunnerRun_PreservesStdoutAndStderr(t *testing.T) { var stdout bytes.Buffer var stderr bytes.Buffer runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/tmp/work/hexai", nil }, runCommand: func(_ context.Context, name string, args []string, stdin io.Reader, out, errOut io.Writer) error { @@ -111,7 +111,7 @@ func TestRunnerRun_PreservesStdoutAndStderr(t *testing.T) { func TestRunnerRun_TaskLookupFailure_IsActionable(t *testing.T) { runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "", errors.New("not found") }, } @@ -126,7 +126,7 @@ func TestRunnerRun_TaskLookupFailure_IsActionable(t *testing.T) { func TestRunnerRun_EmptyRepoName_IsActionable(t *testing.T) { runner := Runner{ - CommandName: "ask", + CommandName: "do", findTaskBinary: func() (string, error) { return "/usr/bin/task", nil }, detectRepoRoot: func(context.Context) (string, error) { return "/", nil }, } |
