Skip to content

0.3.0

Choose a tag to compare

@github-actions github-actions released this 31 Oct 02:22
· 60 commits to main since this release
3eba1e1

Added

  • gcal models list and gcal models download <model> fetch the model that search by meaning uses. The search's
    hint named gcal models download e5-small, which did not exist. The model goes into the folder every WireCat tool
    shares, so one already downloaded by another WireCat tool is used as it is.
  • events move <event> --to-calendar <id> moves an event, with its id, to another calendar of the same account.
    It refuses a calendar you cannot write to, the same calendar, an event Google does not move (focus time, out of
    office, working location, birthdays) and an occurrence without --series. Over MCP it is the events move command.
  • events update --following and events delete --following change or delete "this and all following"
    occurrences.
    An update ends the series just before the occurrence and starts a new series there with the change,
    keeping the attendees; a delete only ends the series. A series that ends after a number of times needs --repeat
    for the new part.
  • events list changed:<date> lists what changed since a date, from the store: each event says change (new,
    moved or cancelled) and changed_at, and a moved one where it was.
  • events list overlapping lists the meetings that clash, each with overlaps, the other events. Only events that
    take your time count: not cancelled, not all-day, not declined or marked free.

Changed — may break callers

  • Creating, changing, moving and answering events go ahead without a question by default. events.create,
    events.update, events.respond and the new events.move are allow (were ask); a script no longer needs --yes
    for them. events.delete stays ask, --following included. To be asked again, set a key to ask, such as
    gcal personal config set permissions.events.create ask. The api.calendar.events.* keys stop the event writes
    once you set them; their built-in ask holds for the api commands only.
  • A series update whose new rule ends it sooner also needs events.delete.series, which is deny by default. A
    new COUNT, an earlier UNTIL, or a bound on a series that had none removed the later occurrences under
    events.update alone.
  • A sync where a calendar fails prints nothing on stdout and fails with sync.partial. Its message names each
    failed calendar and its error, details.calendars holds every calendar's result (error on the failed ones), and
    the error says a retry is safe. The calendars that synced are saved. A sync stopped by its time or request budget
    still answers state: "partial" and succeeds.
  • search answers a list: the events under items, with page in cursor mode, as every other list does. It
    answered one item holding hits, has_more and untrusted (WC-OUT-4). A script reads items in place of
    item.hits, and page.next_cursor is the value for --cursor. Each event names its own untrusted fields, and why
    meaning was not searched is under missing. query and by are gone; each event still says found_by.
  • links review answers its reviews under items, without accounts: "all". It answered one item holding the
    list. Link choices are still kept per store, so every account's reviews are listed.
  • search --backend server refuses --newest. Google returns its matches in no stated order and gcal reads only
    the first page of each calendar, so the newest event could be missing from a "newest first" answer. Its matches
    are listed earliest first, and each event's found_by is ["google"], as a store search writes it.

Fixed

  • gcal --help no longer offers a --read-only option, which does not exist. GCAL_READ_ONLY=1 is how a run
    refuses every change.
  • events delete of an event already deleted at Google succeeds and removes the stored copy. Google answers such a
    delete with 410, and 404 once it no longer shows the event; gcal failed on both and kept the event in the store
    until the next sync.
  • The daily full sync no longer marks events outside its window as deleted. Older and later single events, moved
    occurrences and ended series were marked deleted and their events cancelled. A store this damaged heals on its next
    sync.
  • A repeating event moved to another time no longer keeps its occurrences at the old time after an incremental
    sync.
  • A sync --rescan stopped by its budget no longer leaves the calendars it did not reach on incremental rounds.
  • A create Google made but the store failed to save names the event's id, so a repeat with --id finds it.
  • sync writes to the store in far fewer transactions, and the daily full round asks only changed series for their
    occurrences.
    events list by time and people list read the store faster.
  • A refusal from Google for a missing or forbidden item names a reason: google.not-found or google.denied,
    so a script can branch on it instead of the message.
  • A sign-in cut short by a timeout or Ctrl-C still closes the store it opened.
  • gcal api call --help no longer shows Default: [object Object] for --params. Left out, it still sends no
    parameters.
  • gcal starts in about half the time (gcal --help: 0.40 s before, 0.19 s now, on a laptop with Node 24). The
    package ships one bundled program instead of hundreds of modules. A sync also maps each event faster.

Security

  • search --backend server marks the right fields as written by others. Its untrusted list named title and
    location, while the answer held them under hits, so an agent that follows the list did not treat them as data.
    Each event now names title and location itself.
  • gcal api refuses an empty, . or .. id in a request's address (api.bad-path-id). Such an id made the
    address point at another Google endpoint, calendars/primary/events/.. at the calendar itself; nothing is sent now.
  • session end in a run with moved folders keeps the owner's sign-in in the system keyring, and says so. A run
    with GCAL_CONFIG_DIR, GCAL_STATE_DIR or a moved HOME uses the keyring entry every run of gcal shares; ending
    the session there would have signed the owner out everywhere. It now answers kept: "keyring" and says the run is
    still signed in; ended is true only when the run had a sign-in of its own to remove. A run in the normal folders
    ends the sign-in as before.
  • A sign-in in a run with moved folders no longer replaces the owner's sign-in in the system keyring. It goes to
    the run's own entry, gcal-cli:<config folder>, which the run reads first and its session end removes; the run
    otherwise reads the owner's entry and never changes it. So a test sign-in with another Google account can no longer
    switch the owner's profile.