From 6c1f409a097eb49392150b88bb9412e01dd9b58f Mon Sep 17 00:00:00 2001 From: ysyneu Date: Thu, 11 Jun 2026 13:42:26 +0800 Subject: [PATCH] feat(incident): add --title alias for incident list, fixing doc-vs-code drift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skill reference flashduty-incident-list.md documented and exemplified a `--title` flag on `incident list` that did not exist on the command — only `--query` did. An agent following the skill types `incident list --title "..."`, cobra rejects it (`unknown flag: --title`), and falls back to dumping the full incident list then grepping (a 61K / ~1900-line TOON dump for a one-incident lookup). Make the documented command real: add a `--title` flag that writes to the same `query` backend field as `--query` (an alias). `--query` stays authoritative when both are set, so existing behavior is unchanged. Reconcile the skill doc to list both flags and note the alias relationship. --- internal/cli/incident.go | 8 ++++- internal/cli/incident_short_id_test.go | 29 +++++++++++++++++++ .../references/flashduty-incident-list.md | 3 +- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/internal/cli/incident.go b/internal/cli/incident.go index 52d9908..f14cb7c 100644 --- a/internal/cli/incident.go +++ b/internal/cli/incident.go @@ -75,7 +75,7 @@ func pastIncidentColumns() []output.Column { } func newIncidentListCmd() *cobra.Command { - var progress, severity, query, since, until, nums string + var progress, severity, query, title, since, until, nums string var channelID int64 var limit, page int @@ -101,6 +101,11 @@ func newIncidentListCmd() *cobra.Command { EndTime: endTime, Query: query, } + // --title is a convenience alias for --query (same backend + // "query" field). --query stays authoritative when both are set. + if title != "" && query == "" { + req.Query = title + } req.Page = page req.Limit = limit if channelID != 0 { @@ -126,6 +131,7 @@ func newIncidentListCmd() *cobra.Command { registerEnumFlag(cmd, "severity", severityEnum...) cmd.Flags().Int64Var(&channelID, "channel", 0, "Filter by channel ID") cmd.Flags().StringVar(&query, "query", "", "Free-text search across title/labels/content (also resolves a 24-char incident ID or 6-char incident num to a direct lookup)") + cmd.Flags().StringVar(&title, "title", "", "Search by title/content keyword (alias of --query; --query wins if both set)") cmd.Flags().StringVar(&nums, "nums", "", "Comma-separated short incident ids (num, the 6-char id shown in the UI) to filter by") cmd.Flags().StringVar(&since, "since", "24h", "Start time (duration, date, datetime, or unix timestamp; --since→--until window must be < 31 days)") cmd.Flags().StringVar(&until, "until", "now", "End time") diff --git a/internal/cli/incident_short_id_test.go b/internal/cli/incident_short_id_test.go index 0323978..5bdd3d7 100644 --- a/internal/cli/incident_short_id_test.go +++ b/internal/cli/incident_short_id_test.go @@ -187,6 +187,35 @@ func TestIncidentListNumsReachesWire(t *testing.T) { } } +// TestIncidentListTitleReachesWireAsQuery: --title is sent as the query body field. +func TestIncidentListTitleReachesWireAsQuery(t *testing.T) { + saveAndResetGlobals(t) + stub := newGFStub(t) + stub.data = incidentListData() + if _, err := execCommand("incident", "list", "--title", "test create incident"); err != nil { + t.Fatalf("execCommand: %v", err) + } + if stub.lastPath != "/incident/list" { + t.Fatalf("path = %q, want /incident/list", stub.lastPath) + } + if got, _ := stub.lastBody["query"].(string); got != "test create incident" { + t.Errorf("query = %q, want %q", got, "test create incident") + } +} + +// TestIncidentListQueryWinsOverTitle: when both --query and --title are set, --query is authoritative. +func TestIncidentListQueryWinsOverTitle(t *testing.T) { + saveAndResetGlobals(t) + stub := newGFStub(t) + stub.data = incidentListData() + if _, err := execCommand("incident", "list", "--query", "q", "--title", "t"); err != nil { + t.Fatalf("execCommand: %v", err) + } + if got, _ := stub.lastBody["query"].(string); got != "q" { + t.Errorf("query = %q, want %q (--query must win)", got, "q") + } +} + func equalStrings(a, b []string) bool { if len(a) != len(b) { return false diff --git a/skills/flashduty-incident/references/flashduty-incident-list.md b/skills/flashduty-incident/references/flashduty-incident-list.md index 054256a..a15591a 100644 --- a/skills/flashduty-incident/references/flashduty-incident-list.md +++ b/skills/flashduty-incident/references/flashduty-incident-list.md @@ -15,7 +15,8 @@ flashduty incident list [flags] | `--progress` | string | | Filter by state: `Triggered`, `Processing`, `Closed` | | `--severity` | string | | Filter by severity: `Critical`, `Warning`, `Info` | | `--channel` | int | | Filter by channel ID | -| `--title` | string | | Search by title keyword | +| `--query` | string | | Free-text search across title/labels/content | +| `--title` | string | | Search by title/content keyword (alias of `--query`; `--query` wins if both set) | | `--since` | string | `24h` | Start time (duration like `24h`, date, datetime, or unix timestamp) | | `--until` | string | `now` | End time | | `--limit` | int | `20` | Max results (max 100) |