Commit Graph
12 Commits
Author SHA1 Message Date
Linus Rath ddbff7aeb7 Merge the assistant's Files (package D)
# Conflicts:
#	components/email/__tests__/composer-plugin-edit.test.tsx
#	lib/__tests__/plugin-projection.test.ts
2026-11-03 01:48:30 +01:00
Linus Rath e9e07ddb64 Merge main into feat/assistant-everywhere 2026-11-03 01:35:57 +01:00
Linus Rath d7cb895ebf Merge branch 'feat/assistant-everywhere' into feat/assistant-d
# Conflicts:
#	lib/__tests__/plugin-permission-coverage.test.ts
2026-11-03 01:19:42 +01:00
Linus Rath 12dc2ce3c8 feat: let plugins find, read, attach, save and create files in Files 2026-11-03 00:17:46 +01:00
Linus Rath fd30fdcd27 feat: let plugins answer invitations, add filter rules, change many messages and change settings, with undo
The AI assistant's "more actions" need host calls today's plugin API
lacks. Area c of lib/plugin-sandbox/assistant adds them:

- `calendar.respond(emailId, status)`, new permission calendar:respond:
  answers an invitation of the user's own account through
  lib/calendar-rsvp.ts, like the reader's banner
- `calendar.deleteEvent` now returns an undo token for a single event;
  `calendar.undoDelete` creates it again from the host's copy
- `filters.list/create/undo` over Settings > Filters' model; forward,
  redirect, reject, discard and keep are refused, and so are folders
  that are shared or not the account's own
- `email.batch/undoBatch`: up to 200 messages through the store's
  batch functions, restore points first, one entry in the undo history
- `vacation.get` also says whether the out-of-office forwards mail
- `app.describeSettings`, `app.setSettings` and `app.undoSettings`, new
  permission settings:change, over the allow-list in
  lib/settings-schema.ts, refusing locked, hidden, restricted and gated
  settings when the change is made

Undo tokens stay in the host for 30 minutes, bound to the plugin and
the account. app.getSettings now shows every setting setSettings may
change. settings:write's text is reworded to what it gates (tags).
plugin-host-api-app-info gains a test; its other assertions are as
they were.
2026-11-02 23:14:23 +01:00
Linus Rath 72117c8a71 Merge branch 'main' into feat/proofreading
# Conflicts:
#	components/admin/admin-shell.tsx
2026-11-02 21:27:17 +01:00
Linus Rath e9c4fb095f feat: let a checker that checks only when asked work with compose:read #1397 2026-11-02 19:52:31 +01:00
Jacob Zeitz 9050724fd1 feat(plugins): task reminders reach plugins, which may show a reminder themselves
onCalendarAlert now fires for a task's display alert too, as
{ id, taskId, taskTitle, triggerTime }, and closing that reminder's toast
fires onCalendarAlertAcknowledge with { alertId, taskId }. A task's
reminder reaches only plugins with tasks:read, an event's only plugins
with calendar:read; either permission registers the hooks, and the host
hands each call only to a plugin holding the one it needs.

onBeforeCalendarAlert, a new intercept, runs before Bulwark shows a
reminder of an event or a task, with the same payload. A plugin that
shows reminders itself returns false: Bulwark then plays no sound, sets
no title alert and shows no toast for that reminder, while
onCalendarAlert still fires. Like the reminder it runs in every open
tab, and each tab follows its own answer. It fails open within five
seconds, so a hung plugin delays a reminder but never drops it. Without
a handler the reminder shows at once, as before.
2026-11-01 20:06:38 +01:00
Jacob Zeitz e2fc2c3c90 feat(plugins): tasks carry alerts
api.tasks.create and update take alerts by id: a trigger from the task's
due (or start) as an ISO 8601 duration, or at an instant in UTC; display
or email; at most five. An update merges by id, each alert written by its
JMAP patch path: an alert given is set, one given null is removed, and
alerts the plugin did not name, such as one another app wrote, stay as
the server holds them; null for the whole map removes every alert.
Whether the map is patched or written whole is decided on the task as the
server holds it, not an older copy. An alert kept with the same trigger
and action stays acknowledged, so a snooze is an update of its trigger,
which then fires again. While a task uses its calendar's default alerts,
a change makes them the task's own under new ids, as the task form does,
an alert under a default's id is refused rather than dropped, and
removing every alert turns the defaults off too.

TaskView returns the alerts, each with when it was acknowledged, and
useDefaultAlerts. api.tasks.acknowledgeAlert dismisses one alert (or
undoes that with null) by writing only its acknowledged. A plugin's
writes to one task go one after another, since Stalwart refuses a set
while another is under way on the same object. The task store applies
patch paths to the task the caller read, so a task the list does not
hold is shown and reported whole.
2026-10-31 19:52:02 +01:00
Linus Rath f6b641c94e feat: let plugins forward a message with its attachments after the user allows the address once 2026-10-29 23:27:15 +01:00
Linus Rath 8ad8f44e78 Merge branch 'feat/plugin-host-apis' into feat/plugin-system-audit
# Conflicts:
#	lib/plugin-sandbox/permission-text.ts
#	lib/plugin-sandbox/permissions.ts
#	lib/protocol-handlers/mailto.ts
#	locales/en/common.json
2026-10-14 04:34:14 +02:00
Linus Rath 437bb1d11a test: require every plugin permission to gate a method, hook or slot 2026-10-14 04:28:24 +02:00