Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/cli/oncall.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func newOncallWhoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "who",
Short: "Show who is currently on call",
Long: curatedLong("Show who is currently on call across schedules within a time window, optionally filtered by team or schedule name. Returns person_ids (numeric) only; resolve names/phones by dumping 'fduty member list' and joining client-side (member list has no by-id lookup).", "Schedules", "List"),
Long: curatedLong("Show who is currently on call across schedules within a time window, optionally filtered by team or schedule name. The table output already resolves person_ids to display names; when you have raw person_ids elsewhere, batch-resolve them with 'fduty person infos <person_id> ...' (NOT by paginating 'fduty member list' — person_id and member_id are different id namespaces).", "Schedules", "List"),
RunE: func(cmd *cobra.Command, args []string) error {
return runCommand(cmd, args, func(ctx *RunContext) error {
startTime, err := timeutil.Parse(since)
Expand Down
3 changes: 2 additions & 1 deletion skills/flashduty/reference/member.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Prereq: `SKILL.md` read. `invite` sends invitation emails immediately (up to 20

## Route here when

"成员 / 邀请 / 用户 / 角色 / member / invite / user profile / role assignment / org roster" → **member**. Sibling domains: `team` (team membership lists, not org-level members); `role` (role definitions — get role IDs here first). Key IDs: **`member_id` (int)** from `member list`; **`role_id` (int)** from `fduty role list`.
"成员 / 邀请 / 用户 / 角色 / member / invite / user profile / role assignment / org roster" → **member**. Sibling domains: `team` (team membership lists, not org-level members); `role` (role definitions — get role IDs here first); `person` (resolve a `person_id` → name with `fduty person infos <person_id> …`, e.g. ids returned by `schedule`/`oncall`/`incident`/`alert` output). Key IDs: **`member_id` (int)** from `member list`; **`role_id` (int)** from `fduty role list`.

## Intent → verb

Expand Down Expand Up @@ -119,6 +119,7 @@ Update member roles

## Gotchas

- **Resolving a `person_id` → name: use `fduty person infos <person_id> …`, NOT `member list`.** `schedule`/`oncall`/`incident`/`alert` output returns `person_id`s, a **different namespace from `member_id`**. `fduty person infos` (the sibling `person` group) batch-resolves any number of `person_id`s to `person_name` in one call (rows under `.items[]`). Matching `member list` rows on `member_id == <person_id>` is wrong, and paginating the full roster to find them silently misses people on later pages.
- **`invite` members array is body-only — use `--data`.** Individual members cannot be passed as flat flags; the `members` array (with nested `role_ids`, `email`, `phone`, etc.) lives only in the JSON body. Up to 20 members per call.
- **`info-reset <member-id>` is POSITIONAL.** Pass the member ID as the first bare argument, not `--member-id`: `fduty member info-reset <member_id> --member-name "New Name"`. The `--member-id` flag exists but the positional form is required per the `use` field.
- **`role-grant / role-revoke / role-update` — role IDs are POSITIONAL.** All three verbs take role IDs as positional args: `fduty member role-grant <role_id> [<role_id2>...] --member-id <member_id>`. The `--role-ids` flag also exists but the positional form is authoritative.
Expand Down
11 changes: 6 additions & 5 deletions skills/flashduty/reference/schedule.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,16 @@ fduty schedule info <schedule-id> --start now --end +1h --output-format toon
fduty oncall who --output-format toon
```

Both return `person_ids` (integers), not names. Resolve names by joining `member list` client-side — its rows live under `.items[]` keyed by `member_id` (+ `member_name`):
Both return `person_ids` (integers), not names. Resolve every id in **one batch call** with `fduty person infos` (the sibling `person` group — takes positional ids or `--person-ids`):

```bash
members=$(fduty member list --json)
fduty schedule info <schedule-id> --start now --end +1h --json | jq --argjson m "$members" '
[.. | .person_ids? // empty | .[]] | unique | map(. as $id | ($m.items[]? | select(.member_id==$id) | .member_name))'
# If the join is fiddly, just report person_ids — do NOT loop refining jq.
# person_ids come straight from the schedule/oncall output above
fduty person infos <person-id> [<person-id2> …] --output-format toon
# → rows under .items[] with person_id + person_name; join on person_id client-side
```

**`person_id` ≠ `member_id` — do NOT resolve schedule/oncall people via `member list`.** They are different id namespaces, so matching `member list` rows on `member_id == <person_id>` is wrong, and paginating the full roster (often 20+ pages) silently drops people who land on later pages — a real prod miss. Always feed the `person_id`s to `fduty person infos`. If a lookup genuinely fails, report the bare `person_id` rather than guessing.

## Hot flow — inspect a schedule's upcoming shifts

```bash
Expand Down
Loading