@rackbops/plugin-tracker 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +73 -0
  2. package/dist/plugin.js +3631 -0
  3. package/package.json +34 -4
package/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # tracker
2
+
3
+ The task tracker for Rackbops Clerk: the host of [`Rackbops/docket`](https://github.com/Rackbops/docket)
4
+ on a rackbops-discord-bot instance. Plan of record: Rackbops/Tooling
5
+ `research/city-hall-task-tracker.md` (sections 0, 5.1-5.3, 5.5, 5.8). This version is the core
6
+ (rackbops-bot-plugins#78) and the Discord surface of the first slice (#79): reminders by slash
7
+ command, delivered by DM, answered by button, with history.
8
+
9
+ ## Commands
10
+
11
+ Every answer is ephemeral. The commands register globally, so they work in the bot's DMs as well
12
+ as in a server (plan 5.5, item 39).
13
+
14
+ | Command | Who | What |
15
+ |---|---|---|
16
+ | `/allow user` | a tracker admin | Admits a person: they can now `/register`. |
17
+ | `/register [hour] [zone]` | an admitted person | Signs up, or changes the preferred hour (0-23, default 9) and time zone (default `America/New_York`). The reply says an admin can see every task. |
18
+ | `/remind text [when] [repeat]` | a registered person | A reminder by DM. `when` is docket's `parseWhen` grammar (`in 20 minutes`, `tomorrow 9am`, `fri at 17:30`); `repeat` is once (the default), daily, weekly or monthly. A repeating one with no `when` starts today at the preferred hour. |
19
+ | `/tasks` | registered | Your active tasks and the ones you receive, each with its next run; then your paused ones. |
20
+ | `/task done task` / `/task snooze task [until]` | the task's owner | Answers the task's latest reminder (snooze: an hour, or until `until`). |
21
+ | `/task history task` | the owner, an accepted recipient, or an admin | Every run -- due, status, how it was answered, text replies -- and the task's changes. |
22
+ | `/task share task user` | the task's owner | Invites an admitted, registered member who can be DMed: they get one consent DM with accept and decline. |
23
+ | `/task resume task` | the task's owner | Resumes a task paused because a recipient could not be DMed, taking that recipient off it. |
24
+ | `/settings hour hour` | registered | The preferred hour; recurring reminders with no time of their own move to it. |
25
+
26
+ **Gates.** Every command and button checks, in order: membership of the `TRACKER_GUILD_ID`
27
+ server (when set), admission (in the tracker's store), then what the action needs (an admin for
28
+ `/allow`, admission for `/register`, registration for the rest). A person nobody admitted is told
29
+ to ask an admin to `/allow` them. Decline and opt-out skip the membership and registration gates,
30
+ so anyone can always stop the messages; the Reply button checks membership when its modal is sent.
31
+
32
+ **Buttons.** The owner's DM carries Done, Snooze 1h and Reply; a recipient's copy carries the
33
+ opt-out and Reply; the consent DM carries Accept and Decline. Reply opens a modal whose text is
34
+ kept on the task. docket decides who may answer what (the owner alone answers a run, item 34).
35
+ A pressed DM is edited to say what happened.
36
+
37
+ **Pause after failed DMs** (plan 5.5). Three DMs in a row that the host says cannot be delivered
38
+ pause the person's delivery and every active task that would DM them, theirs and the ones they
39
+ receive (a `paused` event in each task's history); their other runs due in that tick are held, not
40
+ failed. The owner of a task paused for a recipient is DMed once and sees why in `/tasks`; the task
41
+ resumes when the recipient next uses the tracker, or `/task resume` goes on without them. A person
42
+ paused for their own DMs is told, and resumed, the next time they use a command or button. A DM
43
+ that goes through clears the count.
44
+
45
+ ## What it does
46
+
47
+ | Piece | File | Notes |
48
+ |---|---|---|
49
+ | Store | `src/store.ts`, `src/schema.ts` | docket's `Store` port on `bun:sqlite`, in `<dataDir>/tracker/tracker.sqlite` (WAL). A Discord id belongs to at most one user. Schema versioned by `PRAGMA user_version`; a shipped migration is never edited. `store.test.ts` runs docket's `STORE_CONTRACT` against it. |
50
+ | Notify lane | `src/notify-lane.ts` | docket's `Lanes.tickNotify` on the host tick `notify` (every 60 s), through a view of the store that skips a paused task's due runs. Registers only `reminder` and `renewal`. The execute lane is not ticked. |
51
+ | Delivery | `src/notifier.ts`, `src/claims.ts`, `src/buttons.ts` | docket's `Notifier` over `host.dm`, with the buttons. Each (occurrence, person) is claimed in `delivery_claims` before the DM is sent and settled after; a claim never settled is not resent -- it is logged once, as unconfirmed. |
52
+ | Pause | `src/delivery-health.ts` | The per-person failure count, the pause and the resume. |
53
+ | People | `src/people.ts`, `src/admissions.ts` | Discord id, time zone, preferred hour, admin flag -- in the tracker's store, never usr; who admitted each person and when they registered. `TRACKER_ADMIN_DISCORD_IDS` only ever grants admin. |
54
+ | Commands | `src/discord.ts`, `src/interactions.ts`, `src/discord-common.ts` (discord.js); `src/actions.ts`, `src/press.ts`, `src/history.ts`, `src/access.ts` | The discord.js files read options and render; the rest is Discord-free over the injected store, clock and notifier. Store writes are handled one at a time; Discord lookups and DMs run outside that queue. |
55
+ | Health | `src/health.ts` | `GET /tracker/healthz` (through the bot's HTTP router): `200` `ok`/`starting`, `503` `inactive`/`stale`/`blocked`. |
56
+
57
+ ## Configuration
58
+
59
+ | Env key | Secret | Meaning |
60
+ |---|---|---|
61
+ | `TRACKER_ADMIN_DISCORD_IDS` | no | Comma-separated Discord user ids (spaces around commas allowed; an empty entry, as from a trailing comma, is refused and the plugin does not load) made admin at start. Unset = none. Removing an id does not revoke it. |
62
+ | `TRACKER_GUILD_ID` | no | The Discord server whose members may use the tracker. Checked through the interaction's client with a single-member lookup (no privileged intent). Unset = no membership gate, and a warning is logged each time the plugin activates; a malformed value refuses to load. |
63
+
64
+ `/tracker/healthz` needs the bot's `HTTP_PORT` set; without it there is no HTTP at all.
65
+
66
+ ## Not yet
67
+
68
+ - The web area (E5): editing tasks, the admin view, lifting a decline block, forget-me.
69
+ - The `Fetch` port (then `price` is registered) and the city-hall Executor adapter (the execute lane).
70
+ - An optional Discord-role gate (plan 5.5), and showing unconfirmed deliveries to admins anywhere but the log.
71
+
72
+ docket-core and docket-types are `devDependencies`: `bun build` bundles them into `dist/plugin.js`,
73
+ and the bot loads that file without installing anything.