pi-forge 1.2.4 → 1.3.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 (86) hide show
  1. package/README.md +1 -1
  2. package/dist/client/assets/{CodeMirrorEditor-M7HIAKX2.js → CodeMirrorEditor-BuLFJjB1.js} +13 -13
  3. package/dist/client/assets/CodeMirrorEditor-BuLFJjB1.js.map +1 -0
  4. package/dist/client/assets/index-CEqSkIuy.css +1 -0
  5. package/dist/client/assets/index-GubcPYw6.js +375 -0
  6. package/dist/client/assets/index-GubcPYw6.js.map +1 -0
  7. package/dist/client/assets/{workbox-window.prod.es5-Cch4wiA5.js → workbox-window.prod.es5-Bd17z0YL.js} +2 -2
  8. package/dist/client/assets/{workbox-window.prod.es5-Cch4wiA5.js.map → workbox-window.prod.es5-Bd17z0YL.js.map} +1 -1
  9. package/dist/client/index.html +2 -2
  10. package/dist/client/sw.js +1 -1
  11. package/dist/client/sw.js.map +1 -1
  12. package/dist/server/agent-extensions/compaction-continuation.js +65 -0
  13. package/dist/server/agent-extensions/compaction-continuation.js.map +1 -0
  14. package/dist/server/agent-resource-loader.js +10 -0
  15. package/dist/server/agent-resource-loader.js.map +1 -1
  16. package/dist/server/git-clone.js +364 -0
  17. package/dist/server/git-clone.js.map +1 -0
  18. package/dist/server/index.js +26 -1
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/mcp/tool-bridge.js +14 -8
  21. package/dist/server/mcp/tool-bridge.js.map +1 -1
  22. package/dist/server/orchestration/config.js +61 -0
  23. package/dist/server/orchestration/config.js.map +1 -0
  24. package/dist/server/orchestration/event-bridge.js +93 -0
  25. package/dist/server/orchestration/event-bridge.js.map +1 -0
  26. package/dist/server/orchestration/inbox.js +199 -0
  27. package/dist/server/orchestration/inbox.js.map +1 -0
  28. package/dist/server/orchestration/init.js +39 -0
  29. package/dist/server/orchestration/init.js.map +1 -0
  30. package/dist/server/orchestration/store.js +352 -0
  31. package/dist/server/orchestration/store.js.map +1 -0
  32. package/dist/server/orchestration/tools.js +769 -0
  33. package/dist/server/orchestration/tools.js.map +1 -0
  34. package/dist/server/orchestration/types.js +57 -0
  35. package/dist/server/orchestration/types.js.map +1 -0
  36. package/dist/server/processes/envelope.js +60 -0
  37. package/dist/server/processes/envelope.js.map +1 -0
  38. package/dist/server/processes/log-store.js +132 -0
  39. package/dist/server/processes/log-store.js.map +1 -0
  40. package/dist/server/processes/manager.js +370 -0
  41. package/dist/server/processes/manager.js.map +1 -0
  42. package/dist/server/processes/prompt-strings.js +43 -0
  43. package/dist/server/processes/prompt-strings.js.map +1 -0
  44. package/dist/server/processes/tool.js +273 -0
  45. package/dist/server/processes/tool.js.map +1 -0
  46. package/dist/server/processes/types.js +21 -0
  47. package/dist/server/processes/types.js.map +1 -0
  48. package/dist/server/processes/watches.js +59 -0
  49. package/dist/server/processes/watches.js.map +1 -0
  50. package/dist/server/project-manager.js +46 -32
  51. package/dist/server/project-manager.js.map +1 -1
  52. package/dist/server/routes/config.js +5 -0
  53. package/dist/server/routes/config.js.map +1 -1
  54. package/dist/server/routes/control.js +9 -0
  55. package/dist/server/routes/control.js.map +1 -1
  56. package/dist/server/routes/health.js +14 -1
  57. package/dist/server/routes/health.js.map +1 -1
  58. package/dist/server/routes/orchestration.js +464 -0
  59. package/dist/server/routes/orchestration.js.map +1 -0
  60. package/dist/server/routes/processes.js +228 -0
  61. package/dist/server/routes/processes.js.map +1 -0
  62. package/dist/server/routes/projects.js +239 -14
  63. package/dist/server/routes/projects.js.map +1 -1
  64. package/dist/server/routes/sessions.js +53 -34
  65. package/dist/server/routes/sessions.js.map +1 -1
  66. package/dist/server/routes/webhooks.js +362 -0
  67. package/dist/server/routes/webhooks.js.map +1 -0
  68. package/dist/server/session-registry.js +246 -3
  69. package/dist/server/session-registry.js.map +1 -1
  70. package/dist/server/sse-bridge.js +226 -18
  71. package/dist/server/sse-bridge.js.map +1 -1
  72. package/dist/server/webhooks/dispatcher.js +254 -0
  73. package/dist/server/webhooks/dispatcher.js.map +1 -0
  74. package/dist/server/webhooks/event-bridge.js +185 -0
  75. package/dist/server/webhooks/event-bridge.js.map +1 -0
  76. package/dist/server/webhooks/init.js +55 -0
  77. package/dist/server/webhooks/init.js.map +1 -0
  78. package/dist/server/webhooks/store.js +394 -0
  79. package/dist/server/webhooks/store.js.map +1 -0
  80. package/dist/server/webhooks/types.js +32 -0
  81. package/dist/server/webhooks/types.js.map +1 -0
  82. package/package.json +4 -4
  83. package/dist/client/assets/CodeMirrorEditor-M7HIAKX2.js.map +0 -1
  84. package/dist/client/assets/index-DFDpaYie.css +0 -1
  85. package/dist/client/assets/index-DjYKKZRm.js +0 -363
  86. package/dist/client/assets/index-DjYKKZRm.js.map +0 -1
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { getSession } from "./session-registry.js";
3
3
  import { getPendingForSession as getPendingAskQuestions, subscribe as subscribeAskQuestions, } from "./ask-user-question/registry.js";
4
4
  import { peekCached as peekCachedTodo, subscribe as subscribeTodo } from "./todo/store.js";
5
+ import { processManager } from "./processes/manager.js";
5
6
  /**
6
7
  * Per-client outbound-buffer cap. When Node's internal socket buffer
7
8
  * for a given client exceeds this many bytes, we drop the client
@@ -10,23 +11,82 @@ import { peekCached as peekCachedTodo, subscribe as subscribeTodo } from "./todo
10
11
  * can otherwise balloon resident memory by hundreds of MB during a
11
12
  * verbose tool execution before the kernel forces socket close.
12
13
  *
13
- * 256 KB matches roughly 50-100 typical events worth of unflushed
14
- * data well above any legitimate transient buffering and below
15
- * the threshold where memory pressure starts mattering.
14
+ * 8 MB is well above any realistic transient burst: a `tool_result`
15
+ * for an 11k-token tool output serializes to ~80-150 KB, and the
16
+ * subsequent stream of `message_update` token deltas can pile more
17
+ * on top before the client drains. The earlier 256 KB cap was
18
+ * tripping mid-session on legitimate slow consumers (mobile, slow
19
+ * Wi-Fi) and producing a misleading "Reconnecting — server closed
20
+ * stream" banner. The cap still bounds the wedged-tab case — at a
21
+ * sustained 1 MB/s of events it fires within ~8s of zero consumption.
16
22
  */
17
- const BACKPRESSURE_LIMIT_BYTES = 256 * 1024;
23
+ const BACKPRESSURE_LIMIT_BYTES = 8 * 1024 * 1024;
18
24
  /**
19
- * Cadence at which we send an SSE comment line (`: heartbeat\n\n`) on
20
- * every open stream. EventSource ignores comment lines silently, so the
21
- * browser sees nothing — but the bytes reset any idle-connection timer
22
- * sitting between us and the client. OpenShift's HAProxy router defaults
25
+ * Cadence at which we send an SSE keepalive on every open stream.
26
+ * EventSource ignores comment lines silently, so the browser sees
27
+ * nothing — but the bytes reset any idle-connection timer sitting
28
+ * between us and the client. OpenShift's HAProxy router defaults
23
29
  * `timeout server` to 30s for HTTP routes, and any L7 proxy / load
24
- * balancer enforces a similar window; with no agent activity between
25
- * turns, an idle SSE stream gets killed by the middlebox and the
26
- * browser shows "reconnecting." 20s gives us comfortable margin under
27
- * the typical 30s default.
30
+ * balancer enforces a similar window; with no agent activity
31
+ * between turns, an idle SSE stream gets killed by the middlebox
32
+ * and the browser shows "reconnecting." 20s gives us comfortable
33
+ * margin under the typical 30s default.
28
34
  */
29
35
  const HEARTBEAT_INTERVAL_MS = 20_000;
36
+ /**
37
+ * Heartbeat payload, padded to 2KB.
38
+ *
39
+ * The earlier ~13-byte `: heartbeat\n\n` payload kept the *connection*
40
+ * alive (any byte resets the idle timer) but didn't help with L7
41
+ * proxies (most painfully OpenShift's HAProxy router) that buffer
42
+ * small writes until either a threshold is reached or the connection
43
+ * closes. During a long-running agent turn with no token output (a
44
+ * slow LLM call, a long-running tool, a multi-second compaction
45
+ * prefill), the symptom was: heartbeats sit in HAProxy's response
46
+ * buffer, the browser sees nothing for 30+ seconds, the connection
47
+ * times out somewhere on the path, and the user gets a misleading
48
+ * "Reconnecting — server closed stream" banner.
49
+ *
50
+ * Padding the heartbeat to 2KB pushes past the buffer-flush
51
+ * threshold so every heartbeat actually reaches the client. Same
52
+ * mechanism as the compaction-start one-shot padding flush, but
53
+ * applied every 20s instead of per-turn.
54
+ *
55
+ * Bandwidth cost: ~100 bytes/sec/client sustained. Negligible.
56
+ *
57
+ * Marker text `heartbeat` is kept so an operator inspecting raw SSE
58
+ * frames in `tcpdump` / `curl -N` can identify what they're looking
59
+ * at; the underscore padding is just deliberate filler.
60
+ */
61
+ const HEARTBEAT_PADDING_BYTES = 2048;
62
+ const HEARTBEAT_LINE = `: heartbeat ${"_".repeat(HEARTBEAT_PADDING_BYTES - 14)}\n\n`;
63
+ /**
64
+ * One-shot padding flush we send right after the `compaction_start`
65
+ * event. Defeats response buffering at L7 proxies (OpenShift's
66
+ * HAProxy router most painfully) that hold small writes until either
67
+ * an internal buffer threshold is hit or the connection closes.
68
+ *
69
+ * The `compaction_start` event itself is ~150 bytes, well below any
70
+ * proxy's flush threshold. Without padding, that event sits in the
71
+ * router's response buffer for the entire duration of the compaction
72
+ * LLM call (several seconds) — by which point `compaction_end`
73
+ * arrives and the client sees both events fire back-to-back with no
74
+ * banner in between. With padding, the cumulative write pushes past
75
+ * HAProxy's default ~2KB threshold and the router flushes everything
76
+ * (including the compaction_start frame) immediately.
77
+ *
78
+ * Comment-line format (`: <bytes>\n\n`) — EventSource ignores
79
+ * comment lines silently, so the browser sees nothing visible. The
80
+ * `pad-flush` marker is included so an operator inspecting raw SSE
81
+ * frames in `tcpdump` / `curl -N` can tell what they're looking at.
82
+ *
83
+ * 2KB is the smallest size that reliably crosses the HAProxy default;
84
+ * tuning higher costs more bytes per compaction but doesn't change
85
+ * correctness. Only emitted on compaction_start (a per-turn event,
86
+ * not per-token), so the bandwidth impact is negligible.
87
+ */
88
+ const COMPACTION_START_PADDING_BYTES = 2048;
89
+ const COMPACTION_START_PADDING_LINE = `: pad-flush ${"_".repeat(COMPACTION_START_PADDING_BYTES - 14)}\n\n`;
30
90
  /**
31
91
  * Event types we forward to browser clients. Anything else from the SDK is
32
92
  * dropped on the floor — keeps the wire stream stable across SDK upgrades and
@@ -61,6 +121,15 @@ const ALLOWED_EVENT_TYPES = new Set([
61
121
  // store after every successful tool call so the UI panel updates
62
122
  // live. Also re-emitted on SSE snapshot with the cached state.
63
123
  "todo_update",
124
+ // Forge-native events for the `process` tool. process_update
125
+ // fans out the full snapshot on any lifecycle change (start /
126
+ // exit / kill / clear) and re-emits on snapshot connect.
127
+ // process_output is throttled per process to avoid flooding
128
+ // SSE on chatty processes. process_watch is the agent-alerting
129
+ // channel for log-watch matches.
130
+ "process_update",
131
+ "process_output",
132
+ "process_watch",
64
133
  ]);
65
134
  export function isAllowedEvent(event) {
66
135
  return ALLOWED_EVENT_TYPES.has(event.type);
@@ -85,6 +154,111 @@ export function initAskUserQuestionFanout() {
85
154
  }
86
155
  });
87
156
  }
157
+ /**
158
+ * Wire the processes manager's per-session events into the SSE
159
+ * bridge. Called once at server boot. `process_update` carries
160
+ * the full per-session snapshot — clients don't have to
161
+ * reconcile partial updates. `process_output` is a thin pointer
162
+ * (just the changed process's id) so the client can decide
163
+ * whether to refetch a tail; flooding the full output on every
164
+ * write would saturate SSE for chatty processes. `process_watch`
165
+ * forwards the watch-match event verbatim for the agent-alerting
166
+ * UI to render.
167
+ */
168
+ export function initProcessesFanout() {
169
+ return processManager.subscribe((event) => {
170
+ const live = getSession(event.sessionId);
171
+ if (live === undefined)
172
+ return;
173
+ if (event.type === "process_watch_matched") {
174
+ const frame = {
175
+ type: "process_watch",
176
+ sessionId: event.sessionId,
177
+ match: event.match,
178
+ };
179
+ for (const c of live.clients) {
180
+ try {
181
+ c.send(frame);
182
+ }
183
+ catch {
184
+ // best-effort fanout
185
+ }
186
+ }
187
+ return;
188
+ }
189
+ if (event.type === "process_output_changed") {
190
+ const frame = {
191
+ type: "process_output",
192
+ sessionId: event.sessionId,
193
+ id: event.id,
194
+ };
195
+ for (const c of live.clients) {
196
+ try {
197
+ c.send(frame);
198
+ }
199
+ catch {
200
+ // best-effort fanout
201
+ }
202
+ }
203
+ return;
204
+ }
205
+ if (event.type === "process_alert") {
206
+ // Inject a user-shaped message into the live session so the
207
+ // agent gets a turn to react to the process finishing. The
208
+ // alertOn* flags were set at start() time and already filtered
209
+ // in the manager — by the time we get here, the alert is
210
+ // wanted. Best-effort: `sendUserMessage` returns a Promise but
211
+ // we don't await it (the SSE fanout shouldn't block on a
212
+ // round-trip; agent processing happens in the background and
213
+ // the result lands in the session JSONL like any other turn).
214
+ //
215
+ // deliverAs: "followUp" — if the agent is mid-turn, queue the
216
+ // alert until that turn completes. If idle, sendUserMessage
217
+ // kicks off a fresh turn immediately. Either way the user
218
+ // sees the alert message in the chat as a normal user bubble
219
+ // (with the `[process alert]` prefix making it obvious it's
220
+ // automated).
221
+ const reasonText = event.reason === "success"
222
+ ? `finished successfully (exit ${event.info.exitCode ?? "?"})`
223
+ : event.reason === "failure"
224
+ ? `failed with exit code ${event.info.exitCode ?? "?"}`
225
+ : "was killed externally";
226
+ const message = `[process alert] "${event.info.name}" (id=${event.info.id}) ${reasonText}. ` +
227
+ `Use \`process output\` to inspect what it produced if you need to react.`;
228
+ void live.session
229
+ .sendUserMessage(message, { deliverAs: "followUp" })
230
+ .catch((err) => {
231
+ // Swallow — most likely failure mode is "session was
232
+ // disposed between fanout and queue-write," which is benign.
233
+ process.stderr.write(JSON.stringify({
234
+ level: "warn",
235
+ time: new Date().toISOString(),
236
+ msg: "process-alert sendUserMessage failed",
237
+ sessionId: event.sessionId,
238
+ processId: event.info.id,
239
+ reason: event.reason,
240
+ err: err instanceof Error ? err.message : String(err),
241
+ }) + "\n");
242
+ });
243
+ return;
244
+ }
245
+ // Lifecycle events all carry a full-snapshot update on the
246
+ // wire — clients only need this one type to render the panel.
247
+ const snapshot = {
248
+ type: "process_update",
249
+ sessionId: event.sessionId,
250
+ processes: processManager.list(event.sessionId),
251
+ };
252
+ for (const c of live.clients) {
253
+ try {
254
+ c.send(snapshot);
255
+ }
256
+ catch {
257
+ // best-effort fanout
258
+ }
259
+ }
260
+ });
261
+ }
88
262
  /**
89
263
  * Wire the todo store's per-session change-listener into the SSE
90
264
  * bridge. Called once at server boot from index.ts. Mirrors the
@@ -206,6 +380,18 @@ export function createSSEClient(reply, live) {
206
380
  // verbose tool execution can balloon resident memory by hundreds
207
381
  // of MB before the kernel forces the close.
208
382
  if (raw.writableLength > BACKPRESSURE_LIMIT_BYTES) {
383
+ // Operator-visible: this is the only reason the client sees a
384
+ // "server closed stream" mid-session despite no socket-level
385
+ // error. Bypass pino (same rationale as session-registry's
386
+ // logAgentEvent) so a LOG_LEVEL=warn deploy still surfaces it.
387
+ process.stderr.write(JSON.stringify({
388
+ level: "warn",
389
+ time: new Date().toISOString(),
390
+ msg: "sse-client-dropped-backpressure",
391
+ sessionId: live.sessionId,
392
+ bufferedBytes: raw.writableLength,
393
+ limitBytes: BACKPRESSURE_LIMIT_BYTES,
394
+ }) + "\n");
209
395
  close();
210
396
  return;
211
397
  }
@@ -224,6 +410,15 @@ export function createSSEClient(reply, live) {
224
410
  if (!isAllowedEvent(event))
225
411
  return;
226
412
  writeRaw(serializeSSE(event));
413
+ // After compaction_start, follow with a padding flush so L7
414
+ // proxies (notably the OpenShift HAProxy router) release the
415
+ // event immediately rather than holding it through the
416
+ // multi-second compaction LLM call. See
417
+ // COMPACTION_START_PADDING_LINE doc-comment for the rationale.
418
+ // Cheap — fires at most once per compaction, ~2KB on the wire.
419
+ if (event.type === "compaction_start") {
420
+ writeRaw(COMPACTION_START_PADDING_LINE);
421
+ }
227
422
  };
228
423
  const client = { id, send, close };
229
424
  registeredClient = client;
@@ -267,19 +462,32 @@ export function createSSEClient(reply, live) {
267
462
  tasks: cachedTodo.tasks,
268
463
  nextId: cachedTodo.nextId,
269
464
  }));
465
+ // Same re-deliver for processes — empty list is still sent so
466
+ // the client knows to hide the chat-input badge if a prior
467
+ // tab left it visible. Manager.list() is cheap (in-memory
468
+ // map walk + clone).
469
+ writeRaw(serializeSSE({
470
+ type: "process_update",
471
+ sessionId: live.sessionId,
472
+ processes: processManager.list(live.sessionId),
473
+ }));
270
474
  // Wire close listeners AFTER the snapshot write so an immediate socket
271
475
  // close can't double-fire close() before the registry is in a coherent
272
476
  // state. Node's 'close' event fires next-tick anyway, but explicit
273
477
  // ordering is cheap insurance.
274
478
  raw.on("close", close);
275
479
  raw.on("error", close);
276
- // Idle-timer reset for L7 proxies (OpenShift HAProxy router, nginx,
277
- // ALB, etc.). Comment line, no `data:` field — EventSource skips it.
278
- // Uses writeRaw so the same backpressure guard applies; if the socket
279
- // is wedged the heartbeat will trip the limit and call close(), which
280
- // tears the timer down.
480
+ // Idle-timer reset + buffer-flush for L7 proxies (OpenShift
481
+ // HAProxy router, nginx, ALB, etc.). Comment line, no `data:`
482
+ // field EventSource skips it. HEARTBEAT_LINE is padded to 2KB
483
+ // to defeat HAProxy's small-write buffering so heartbeats
484
+ // actually reach the client during long idle gaps; see the
485
+ // HEARTBEAT_LINE doc-comment for the full rationale. Uses
486
+ // writeRaw so the same backpressure guard applies; if the
487
+ // socket is wedged the heartbeat will trip the limit and call
488
+ // close(), which tears the timer down.
281
489
  heartbeatTimer = setInterval(() => {
282
- writeRaw(": heartbeat\n\n");
490
+ writeRaw(HEARTBEAT_LINE);
283
491
  }, HEARTBEAT_INTERVAL_MS);
284
492
  // Don't keep the Node event loop alive just for heartbeats — when
285
493
  // the socket closes the close handler clears the timer anyway.
@@ -1 +1 @@
1
- {"version":3,"file":"sse-bridge.js","sourceRoot":"","sources":["../src/sse-bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sse-bridge.js","sourceRoot":"","sources":["../src/sse-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Webhook delivery: takes a candidate event, finds every webhook
3
+ * that subscribes to it (matching events + scope + enabled), and
4
+ * fires an HTTP POST per match with retry + delivery recording.
5
+ *
6
+ * Per-webhook fire-and-forget — the function returns as soon as
7
+ * the deliveries are kicked off. Retries run in the background.
8
+ * The event source (event-bridge.ts) doesn't block on webhook
9
+ * outcomes.
10
+ *
11
+ * Retry policy:
12
+ * - 2xx → "delivered", no retry.
13
+ * - 4xx → "failed", no retry (consumer's
14
+ * problem; retrying won't help).
15
+ * - 5xx / network error → "error", retry with exponential
16
+ * backoff (1s, 5s, 30s — 3 attempts
17
+ * total counting the initial fire).
18
+ *
19
+ * HMAC: when `webhook.secret` is set, every request includes
20
+ * `X-Pi-Forge-Signature: sha256=<hex of HMAC-SHA256(secret, body)>`.
21
+ * The hex digest is the same convention GitHub webhooks use.
22
+ *
23
+ * `insecureTls: true` swaps the `https.Agent` for one with
24
+ * `rejectUnauthorized: false`. Logged to stderr on every fire
25
+ * so the relaxed security is visible in `docker logs`.
26
+ */
27
+ import { createHmac, randomUUID } from "node:crypto";
28
+ import { Agent as HttpsAgent } from "node:https";
29
+ import { recordDelivery, readWebhooks, SECRET_PLACEHOLDER } from "./store.js";
30
+ /**
31
+ * Reusable agents. The insecure one is allocated lazily — most
32
+ * deployments never set `insecureTls` on any webhook, and we'd
33
+ * rather not have a permissive agent sitting around unless asked.
34
+ */
35
+ const SECURE_AGENT = new HttpsAgent({ keepAlive: true });
36
+ let insecureAgent;
37
+ function getInsecureAgent() {
38
+ if (insecureAgent === undefined) {
39
+ insecureAgent = new HttpsAgent({ keepAlive: true, rejectUnauthorized: false });
40
+ }
41
+ return insecureAgent;
42
+ }
43
+ const BACKOFF_MS = [1_000, 5_000, 30_000];
44
+ const MAX_ATTEMPTS = BACKOFF_MS.length;
45
+ const REQUEST_TIMEOUT_MS = 30_000;
46
+ const ERROR_PREVIEW_LIMIT = 200;
47
+ /**
48
+ * Reserved headers we always set ourselves. User-supplied custom
49
+ * headers for these names are silently overridden — letting a
50
+ * webhook config rewrite `X-Pi-Forge-Signature` would defeat the
51
+ * point of HMAC.
52
+ */
53
+ const RESERVED_HEADERS = new Set([
54
+ "content-type",
55
+ "x-pi-forge-event",
56
+ "x-pi-forge-delivery",
57
+ "x-pi-forge-signature",
58
+ "user-agent",
59
+ ]);
60
+ /**
61
+ * Public entry point. Resolves once all matching webhooks have
62
+ * been queued (kicks off the first attempt synchronously per
63
+ * webhook so the operator can observe failures immediately, then
64
+ * retries continue in the background).
65
+ *
66
+ * Returns the number of webhooks targeted — useful for the test
67
+ * route to surface "0 webhooks matched" feedback.
68
+ */
69
+ export async function dispatch(opts, targeting) {
70
+ const webhooks = await readWebhooks();
71
+ const matches = webhooks.filter((w) => isMatch(w, opts, targeting));
72
+ if (matches.length === 0)
73
+ return 0;
74
+ // Build the payload ONCE — same body across all matching
75
+ // webhooks. Each webhook gets its own deliveryId since each is
76
+ // independently retryable.
77
+ const timestamp = new Date().toISOString();
78
+ for (const webhook of matches) {
79
+ const payload = {
80
+ deliveryId: randomUUID(),
81
+ event: opts.event,
82
+ timestamp,
83
+ ...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),
84
+ ...(opts.projectId !== undefined ? { projectId: opts.projectId } : {}),
85
+ data: opts.data,
86
+ };
87
+ // Fire-and-forget. Retries handled inside; we don't await the
88
+ // full chain.
89
+ void deliverWithRetries(webhook, payload);
90
+ }
91
+ return matches.length;
92
+ }
93
+ function isMatch(webhook, opts, targeting) {
94
+ if (targeting?.onlyWebhookId !== undefined) {
95
+ return webhook.id === targeting.onlyWebhookId;
96
+ }
97
+ if (!webhook.enabled)
98
+ return false;
99
+ // Event subscription. `webhook.test` always matches if the test
100
+ // route invoked us (handled by targeting above); the real-event
101
+ // dispatch path goes through here and filters strictly.
102
+ if (opts.event === "webhook.test")
103
+ return false;
104
+ if (!webhook.events.includes(opts.event))
105
+ return false;
106
+ // Scope. Global webhooks match every event with a projectId or
107
+ // none. Per-project webhooks only fire when the event carries a
108
+ // matching projectId.
109
+ if (webhook.scope.kind === "project") {
110
+ return opts.projectId !== undefined && opts.projectId === webhook.scope.projectId;
111
+ }
112
+ return true;
113
+ }
114
+ async function deliverWithRetries(webhook, payload) {
115
+ for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
116
+ const outcome = await deliverOnce(webhook, payload, attempt);
117
+ const record = {
118
+ id: randomUUID(),
119
+ webhookId: webhook.id,
120
+ deliveryId: payload.deliveryId,
121
+ event: payload.event,
122
+ attempt,
123
+ status: outcome.status,
124
+ durationMs: outcome.durationMs,
125
+ requestedAt: outcome.requestedAt,
126
+ ...(payload.sessionId !== undefined ? { sessionId: payload.sessionId } : {}),
127
+ ...(payload.projectId !== undefined ? { projectId: payload.projectId } : {}),
128
+ ...(outcome.statusCode !== undefined ? { statusCode: outcome.statusCode } : {}),
129
+ ...(outcome.errorPreview !== undefined ? { errorPreview: outcome.errorPreview } : {}),
130
+ };
131
+ await recordDelivery(record).catch(() => undefined);
132
+ // Stop on success or terminal-4xx; retry on error.
133
+ if (outcome.status === "delivered" || outcome.status === "failed")
134
+ return;
135
+ if (attempt < MAX_ATTEMPTS) {
136
+ const backoff = BACKOFF_MS[attempt - 1] ?? BACKOFF_MS[BACKOFF_MS.length - 1] ?? 1000;
137
+ await new Promise((resolve) => setTimeout(resolve, backoff));
138
+ }
139
+ }
140
+ }
141
+ async function deliverOnce(webhook, payload, attempt) {
142
+ const body = JSON.stringify(payload);
143
+ const headers = {
144
+ "Content-Type": "application/json; charset=utf-8",
145
+ "User-Agent": "pi-forge-webhook/1.0",
146
+ "X-Pi-Forge-Event": payload.event,
147
+ "X-Pi-Forge-Delivery": payload.deliveryId,
148
+ };
149
+ if (webhook.secret !== undefined && webhook.secret.length > 0) {
150
+ const sig = createHmac("sha256", webhook.secret).update(body).digest("hex");
151
+ headers["X-Pi-Forge-Signature"] = `sha256=${sig}`;
152
+ }
153
+ if (webhook.headers !== undefined) {
154
+ for (const [name, value] of Object.entries(webhook.headers)) {
155
+ if (RESERVED_HEADERS.has(name.toLowerCase()))
156
+ continue;
157
+ // Defense in depth: the CRUD path round-trips header values
158
+ // through the SECRET_PLACEHOLDER sentinel so the wire never
159
+ // exposes them. A hand-edited webhooks.json (or a future
160
+ // bug) could leak the sentinel into stored config — skip
161
+ // here so we never POST literally `Authorization: ***REDACTED***`
162
+ // to the consumer.
163
+ if (value === SECRET_PLACEHOLDER)
164
+ continue;
165
+ headers[name] = value;
166
+ }
167
+ }
168
+ const requestedAt = new Date().toISOString();
169
+ const t0 = Date.now();
170
+ const controller = new AbortController();
171
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
172
+ timeout.unref();
173
+ if (webhook.insecureTls === true) {
174
+ process.stderr.write(JSON.stringify({
175
+ level: "warn",
176
+ time: requestedAt,
177
+ msg: "webhook-insecure-tls",
178
+ webhookId: webhook.id,
179
+ url: webhook.url,
180
+ event: payload.event,
181
+ attempt,
182
+ }) + "\n");
183
+ }
184
+ try {
185
+ // Node's global fetch routes through undici. We pass the
186
+ // agent via the `dispatcher` undici-extension field — TS's
187
+ // standard RequestInit doesn't know about it, hence the cast.
188
+ // Falls back gracefully on runtimes that ignore the field.
189
+ const agent = webhook.insecureTls === true ? getInsecureAgent() : SECURE_AGENT;
190
+ const init = {
191
+ method: "POST",
192
+ headers,
193
+ body,
194
+ signal: controller.signal,
195
+ agent,
196
+ };
197
+ const res = await fetch(webhook.url, init);
198
+ const durationMs = Date.now() - t0;
199
+ const statusCode = res.status;
200
+ if (statusCode >= 200 && statusCode < 300) {
201
+ return { status: "delivered", statusCode, durationMs, requestedAt };
202
+ }
203
+ if (statusCode >= 400 && statusCode < 500) {
204
+ const text = await safeReadErrorBody(res);
205
+ return {
206
+ status: "failed",
207
+ statusCode,
208
+ durationMs,
209
+ requestedAt,
210
+ ...(text !== undefined ? { errorPreview: text } : {}),
211
+ };
212
+ }
213
+ // 5xx or other non-2xx — retryable.
214
+ const text = await safeReadErrorBody(res);
215
+ return {
216
+ status: "error",
217
+ statusCode,
218
+ durationMs,
219
+ requestedAt,
220
+ ...(text !== undefined ? { errorPreview: text } : {}),
221
+ };
222
+ }
223
+ catch (err) {
224
+ const durationMs = Date.now() - t0;
225
+ const message = err instanceof Error ? err.message : String(err);
226
+ return {
227
+ status: "error",
228
+ durationMs,
229
+ requestedAt,
230
+ errorPreview: message.slice(0, ERROR_PREVIEW_LIMIT),
231
+ };
232
+ }
233
+ finally {
234
+ clearTimeout(timeout);
235
+ }
236
+ }
237
+ /**
238
+ * Read a small slice of the response body for diagnostics.
239
+ * Bounded so a runaway server returning megabytes doesn't blow
240
+ * memory. Body bytes themselves are not persisted in
241
+ * DeliveryRecord — only this preview makes it through.
242
+ */
243
+ async function safeReadErrorBody(res) {
244
+ try {
245
+ const text = await res.text();
246
+ if (text.length === 0)
247
+ return undefined;
248
+ return text.slice(0, ERROR_PREVIEW_LIMIT);
249
+ }
250
+ catch {
251
+ return undefined;
252
+ }
253
+ }
254
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/webhooks/dispatcher.ts"],"names":[],"mappings":"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"}