aibroker 0.10.0 → 0.12.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.
@@ -0,0 +1,287 @@
1
+ /**
2
+ * daemon/todoist-webhook.ts — Todoist as an inbound channel.
3
+ *
4
+ * File a task from a phone or a watch and it reaches the session that owns the
5
+ * project, without a poller. Todoist pushes; the daemon routes it to `dispatch`.
6
+ *
7
+ * ── Why webhooks rather than polling ────────────────────────────────────────
8
+ *
9
+ * Polling forces a choice between latency and cost, and gets both wrong. The
10
+ * decisive detail is that `reminder:fired` is a webhook event: a task with a
11
+ * reminder pushes AT the reminder time. Due dates do NOT push — a task merely
12
+ * becoming due fires nothing — so scheduling is expressed as a reminder, and
13
+ * "run the sweep at 09:00" needs no timer anywhere in this system.
14
+ *
15
+ * ── This is an execution ingress, so it is deliberately narrow ──────────────
16
+ *
17
+ * A task arriving here becomes an instruction a session acts on with the
18
+ * user's full rights. Todoist's own payload documents that `initiator` "may be
19
+ * the same user indicated in user_id OR A COLLABORATOR FROM A SHARED PROJECT",
20
+ * which is precisely the exposure: without a boundary, anyone on any shared
21
+ * project has a path to this machine. Hence:
22
+ *
23
+ * - Only tasks under a configured ingress project (or its children) are
24
+ * considered. Everything else is acknowledged and dropped.
25
+ * - Every request must carry a valid HMAC signature.
26
+ * - Everything — accepted, ignored, refused — goes through the audit trail.
27
+ *
28
+ * ── Echo loops ──────────────────────────────────────────────────────────────
29
+ *
30
+ * `note:added` is an event, so an agent commenting on a task triggers a webhook
31
+ * that could route back to an agent that comments again. `initiator` cannot
32
+ * break the cycle: when agents act as the user, the initiator IS the user. Our
33
+ * own writes are therefore marked, and marked content is ignored on the way in.
34
+ */
35
+ import { createServer } from "node:http";
36
+ import { createHmac, timingSafeEqual } from "node:crypto";
37
+ import { log } from "../core/log.js";
38
+ import { audit } from "./audit.js";
39
+ /** Prefix on anything an agent writes back to Todoist, so we ignore our own echo. */
40
+ export const AGENT_MARK = "🤖";
41
+ /**
42
+ * Verify Todoist's HMAC over the RAW body.
43
+ *
44
+ * Must run against the exact bytes received: re-serialising parsed JSON changes
45
+ * key order and whitespace and the signature will never match.
46
+ */
47
+ export function verifySignature(raw, header, secret) {
48
+ if (!header || !secret)
49
+ return false;
50
+ const expected = createHmac("sha256", secret).update(raw).digest();
51
+ let got;
52
+ try {
53
+ got = Buffer.from(header, "base64");
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ if (got.length !== expected.length)
59
+ return false;
60
+ return timingSafeEqual(got, expected);
61
+ }
62
+ /** Stable identity for an event, for replay/duplicate suppression. */
63
+ export function eventKey(e) {
64
+ const id = e.event_data?.id ?? "?";
65
+ return `${e.event_name}:${id}:${e.triggered_at ?? ""}`;
66
+ }
67
+ /**
68
+ * Decide whether an event should reach a session, and as what.
69
+ *
70
+ * Pure, so the routing rules are testable without a socket: this function is
71
+ * the entire security boundary of the ingress.
72
+ */
73
+ export function route(e, cfg) {
74
+ const data = e.event_data ?? {};
75
+ const content = typeof data.content === "string" ? data.content : "";
76
+ const description = typeof data.description === "string" ? data.description : "";
77
+ const taskId = typeof data.id === "string" ? data.id : String(data.id ?? "");
78
+ // Our own writes come back as events. Drop them before anything else, or an
79
+ // agent's comment becomes an instruction to an agent.
80
+ if (content.startsWith(AGENT_MARK) || description.startsWith(AGENT_MARK)) {
81
+ return { act: false, reason: "agent-authored content, ignored to avoid an echo loop" };
82
+ }
83
+ const ACTIONABLE = new Set(["item:added", "item:completed", "reminder:fired"]);
84
+ if (!ACTIONABLE.has(e.event_name)) {
85
+ return { act: false, reason: `event ${e.event_name} is not actionable` };
86
+ }
87
+ // Completion is the human saying "done"; it must never start work.
88
+ if (e.event_name === "item:completed") {
89
+ return { act: false, reason: "task completed — recorded, no action taken" };
90
+ }
91
+ const projectId = typeof data.project_id === "string" ? data.project_id : "";
92
+ if (!cfg.ingressProjectIds.has(projectId)) {
93
+ // The boundary. Anything outside the allowlist is acknowledged and dropped,
94
+ // so a task filed into a shared project cannot reach a session.
95
+ return { act: false, reason: `project ${projectId || "?"} is not an ingress project` };
96
+ }
97
+ if (!content.trim()) {
98
+ return { act: false, reason: "task has no content" };
99
+ }
100
+ // Owner, most explicit first:
101
+ // 1. a `pai:<name>` label — say exactly where it goes
102
+ // 2. the project it was filed in — "put it in the Whazaa list"
103
+ // 3. the configured default — the watch case: Inbox, no label, no project
104
+ const labels = Array.isArray(data.labels) ? data.labels.map(String) : [];
105
+ const labelled = labels.map((l) => l.trim())
106
+ .find((l) => l.toLowerCase().startsWith("pai:"))?.slice(4).trim();
107
+ const owner = labelled || cfg.projectOwners.get(projectId) || cfg.defaultOwner;
108
+ if (!owner) {
109
+ return {
110
+ act: false,
111
+ reason: "no pai:<name> label, no owner for this project, and no default owner configured",
112
+ };
113
+ }
114
+ const body = description.trim() ? `${content}\n\n${description}` : content;
115
+ return { act: true, project: owner, body, taskId };
116
+ }
117
+ /** Bounded replay guard: Todoist retries, and a retry must not run work twice. */
118
+ class SeenSet {
119
+ max;
120
+ seen = new Set();
121
+ order = [];
122
+ constructor(max = 2_000) {
123
+ this.max = max;
124
+ }
125
+ has(k) { return this.seen.has(k); }
126
+ add(k) {
127
+ if (this.seen.has(k))
128
+ return;
129
+ this.seen.add(k);
130
+ this.order.push(k);
131
+ if (this.order.length > this.max) {
132
+ const drop = this.order.shift();
133
+ if (drop)
134
+ this.seen.delete(drop);
135
+ }
136
+ }
137
+ }
138
+ function readBody(req, limit = 1_000_000) {
139
+ return new Promise((resolve, reject) => {
140
+ const chunks = [];
141
+ let size = 0;
142
+ req.on("data", (c) => {
143
+ size += c.length;
144
+ if (size > limit) {
145
+ reject(new Error("payload too large"));
146
+ req.destroy();
147
+ return;
148
+ }
149
+ chunks.push(c);
150
+ });
151
+ req.on("end", () => resolve(Buffer.concat(chunks)));
152
+ req.on("error", reject);
153
+ });
154
+ }
155
+ export function createWebhookServer(cfg, deps) {
156
+ const seen = new SeenSet();
157
+ return createServer((req, res) => {
158
+ void (async () => {
159
+ if (req.method !== "POST") {
160
+ res.writeHead(405).end();
161
+ return;
162
+ }
163
+ // Ignore query strings; a proxy may append them.
164
+ const reqPath = (req.url ?? "/").split("?")[0];
165
+ if (reqPath !== cfg.path) {
166
+ res.writeHead(404).end();
167
+ return;
168
+ }
169
+ let raw;
170
+ try {
171
+ raw = await readBody(req);
172
+ }
173
+ catch {
174
+ res.writeHead(413).end();
175
+ return;
176
+ }
177
+ if (!verifySignature(raw, req.headers["x-todoist-hmac-sha256"], cfg.secret)) {
178
+ // Unsigned or wrongly signed: someone found the endpoint. Worth a record.
179
+ audit({
180
+ action: "webhook", actor: "todoist", target: "aibroker",
181
+ outcome: "rejected", reason: "invalid or missing HMAC signature",
182
+ });
183
+ log("todoist-webhook: rejected a request with an invalid signature");
184
+ res.writeHead(401).end();
185
+ return;
186
+ }
187
+ let event;
188
+ try {
189
+ event = JSON.parse(raw.toString("utf-8"));
190
+ }
191
+ catch {
192
+ res.writeHead(400).end();
193
+ return;
194
+ }
195
+ // Acknowledge immediately, then work. Todoist retries on a slow or failed
196
+ // response, and a dispatch can take a minute — without this, every slow
197
+ // delivery is retried and the work runs more than once.
198
+ res.writeHead(200, { "content-type": "application/json" }).end('{"ok":true}');
199
+ const key = eventKey(event);
200
+ if (seen.has(key)) {
201
+ log(`todoist-webhook: duplicate ${key}, ignored`);
202
+ return;
203
+ }
204
+ seen.add(key);
205
+ const decision = route(event, cfg);
206
+ const who = event.initiator?.email ?? event.initiator?.full_name ?? "todoist";
207
+ if (!decision.act) {
208
+ audit({
209
+ action: "webhook", actor: who, target: "aibroker",
210
+ outcome: "ignored", reason: decision.reason,
211
+ meta: { event: event.event_name, task: event.event_data?.content ?? undefined },
212
+ });
213
+ return;
214
+ }
215
+ try {
216
+ const r = await deps.deliver(decision.project, decision.body);
217
+ audit({
218
+ action: "webhook", actor: who, target: r.session || decision.project,
219
+ outcome: r.outcome, body: decision.body, reason: r.reason,
220
+ meta: { event: event.event_name, taskId: decision.taskId },
221
+ });
222
+ }
223
+ catch (err) {
224
+ const reason = err instanceof Error ? err.message : String(err);
225
+ audit({
226
+ action: "webhook", actor: who, target: decision.project,
227
+ outcome: "failed", body: decision.body, reason,
228
+ meta: { event: event.event_name, taskId: decision.taskId },
229
+ });
230
+ log(`todoist-webhook: delivery failed — ${reason}`);
231
+ }
232
+ })();
233
+ });
234
+ }
235
+ /** Read config from the environment. Returns null when not configured. */
236
+ export function webhookConfigFromEnv() {
237
+ const secret = process.env.TODOIST_CLIENT_SECRET;
238
+ if (!secret)
239
+ return null;
240
+ // "id" or "id=owner", comma-separated. The owner half is optional and maps a
241
+ // project to the session that owns work filed there.
242
+ const ids = new Set();
243
+ const owners = new Map();
244
+ for (const entry of (process.env.TODOIST_INGRESS_PROJECTS ?? "").split(",")) {
245
+ const [id, owner] = entry.split("=").map((s) => s.trim());
246
+ if (!id)
247
+ continue;
248
+ ids.add(id);
249
+ if (owner)
250
+ owners.set(id, owner);
251
+ }
252
+ return {
253
+ secret,
254
+ port: Number(process.env.TODOIST_WEBHOOK_PORT) || 8766,
255
+ bind: process.env.TODOIST_WEBHOOK_BIND ?? "127.0.0.1",
256
+ path: process.env.TODOIST_WEBHOOK_PATH ?? "/todoist",
257
+ ingressProjectIds: ids,
258
+ projectOwners: owners,
259
+ defaultOwner: process.env.TODOIST_DEFAULT_OWNER,
260
+ };
261
+ }
262
+ /** Start the receiver if configured. No-op otherwise. */
263
+ export function startTodoistWebhook(deps) {
264
+ const cfg = webhookConfigFromEnv();
265
+ if (!cfg) {
266
+ log("todoist-webhook: not configured (set TODOIST_CLIENT_SECRET to enable)");
267
+ return null;
268
+ }
269
+ if (cfg.ingressProjectIds.size === 0) {
270
+ // Refusing here is deliberate: with an empty allowlist the ingress would
271
+ // accept work from every project on the account, including shared ones.
272
+ log("todoist-webhook: TODOIST_INGRESS_PROJECTS is empty — refusing to accept every project");
273
+ return null;
274
+ }
275
+ const server = createWebhookServer(cfg, deps);
276
+ if (cfg.bind !== "127.0.0.1" && cfg.bind !== "localhost") {
277
+ log(`todoist-webhook: WARNING binding ${cfg.bind}, not loopback — this puts an execution ingress ` +
278
+ `directly on the network. Prefer loopback with a TLS proxy (Tailscale Funnel, Cloudflare Tunnel, Caddy) in front.`);
279
+ }
280
+ server.listen(cfg.port, cfg.bind, () => {
281
+ log(`todoist-webhook: listening on ${cfg.bind}:${cfg.port}${cfg.path}, ` +
282
+ `${cfg.ingressProjectIds.size} ingress project(s), default owner ${cfg.defaultOwner ?? "(none)"}`);
283
+ });
284
+ server.on("error", (err) => log(`todoist-webhook: server error — ${err.message}`));
285
+ return server;
286
+ }
287
+ //# sourceMappingURL=todoist-webhook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todoist-webhook.js","sourceRoot":"","sources":["../../src/daemon/todoist-webhook.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aibroker",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Platform-agnostic AI message broker — routes between user channels and AI backends",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",