Create, show, update and delete timesheet entries
Why
The CLI reads timesheets through the three reports (timesheet report, project, item) but can't log, change or remove time. SDK v0.29.1, the CLI's pin, has had TimesheetService Get, Create, Update and Destroy for a while; the CLI called none of them, while API-COVERAGE.md claimed "list, show, create, update, delete". The operation coverage report from basecamp/basecamp-sdk#1055 found the gap.
What changed
A timesheet entry group. bc3 routes entries by account alone, so no verb takes or needs a project.
| SDK operation | Command |
|---|---|
CreateTimesheetEntry (POST /recordings/{id}/timesheet/entries.json) | basecamp timesheet entry create <item-id|url> --hours 1.5 [--date] [--description] [--person] |
GetTimesheetEntry (GET /timesheet_entries/{id}) | basecamp timesheet entry show <id|url> |
UpdateTimesheetEntry (PUT /timesheet_entries/{id}) | basecamp timesheet entry update <id|url> [--hours] [--date] [--description] [--person] |
DestroyTimesheetEntry (DELETE /timesheet_entries/{id}) | basecamp timesheet entry delete <id|url> [--force] |
--hoursis checked locally as a decimal orh:mm, the two forms bc3 takes.--dategoes throughdateparseand must come out as a real ISO date; on create it defaults to today.--persontakes an ID, name, email orme.deleteis permanent: bc3 never trashes or archives an entry. So it asks for confirmation, and machine output needs--force, the same assubtasks delete.- The per-entry verbs take only a bare ID or the entry's own URL (
…/timesheet/entries/<id>, or either API form). Any other URL, such as the to-do the time is logged against, is refused rather than read as an entry ID, sodeletecan't aim at the wrong thing.createrefuses a project's timesheet URL, which carries the project's ID and not the timesheet recording's. - Also updated: the catalog (
entryaction),.surface, theAPI-COVERAGE.mdrow (now 7 endpoints, listed), a "Timesheet entries" section in the basecamp skill, the timesheet group's agent notes (they named abasecamp clockshortcut that no longer exists), and a smoke lifecycle file. basecamp mcpneeds nothing: its model already servescreate_timesheet_entry,get_timesheet_entry,update_timesheet_entryanddestroy_timesheet_entry.
Tests
internal/commands/timesheet_entries_test.go: each verb's method, path and body over the recording transport. Covers entry URLs in all three forms, a default date of today,--person meresolution, fields left out when unset, local refusals that send no request (bad hours, bad dates, empty values, nothing to update, non-IDs, item and project-timesheet URLs on every per-entry verb),deleteneeding--forcewithout a terminal, and a 403 on delete returned as an error.e2e/timesheet.bats: the local refusals through the built binary.e2e/smoke/smoke_timesheet_write.bats: create, show, update, delete against a real account. A 403 from an account without timesheets counts as unverifiable.bin/cipasses.
Gap card: https://app.basecamp.com/2914079/buckets/48521764/card_tables/cards/10447986600
Summary by cubic
Adds a timesheet entry command group so the CLI can log, view, change, and delete timesheet entries. The CLI previously read timesheets only through the three report commands; the pinned SDK's entry operations went unused while API-COVERAGE.md claimed them.
createlogs hours against an item (--hoursrequired,--datedefaults to today,--persontakes an ID, name, email, orme).createtakes only the item kinds bc3 logs time against; project, listing, and person URLs are refused too.show,update, anddeletetake the entry ID or its own URL; any other URL is refused sodeletecan't target the item the time is logged against.- Pasted URLs must be http(s) on a trusted Basecamp host and name the configured account (compared numerically); anything else is refused before any request, and follow-up commands carry an account adopted from a pasted URL.
deleteis permanent, so it prompts for confirmation and needs--forcein machine-output or non-interactive sessions; the delete breadcrumb carries--forcefor machine readers.- Also updates the command catalog,
.surface,API-COVERAGE.md, the skill file, and the timesheet group's agent notes, and adds unit, e2e, and a serial smoke lifecycle whose timesheets-off gaps are allowlisted. The entry summary carries the person's name and ID, which styled and Markdown output would otherwise skip.