@sentry/junior 0.53.0 → 0.55.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 (239) hide show
  1. package/README.md +4 -3
  2. package/dist/api-reference.d.ts +7 -0
  3. package/dist/app.d.ts +14 -12
  4. package/dist/app.js +12977 -10333
  5. package/dist/build/copy-build-content.d.ts +4 -0
  6. package/dist/build/glob-to-regex.d.ts +2 -0
  7. package/dist/build/rolldown-workarounds.d.ts +14 -0
  8. package/dist/build/virtual-config.d.ts +4 -0
  9. package/dist/chat/agent-dispatch/context.d.ts +6 -0
  10. package/dist/chat/agent-dispatch/heartbeat.d.ts +14 -0
  11. package/dist/chat/agent-dispatch/runner.d.ts +9 -0
  12. package/dist/chat/agent-dispatch/signing.d.ts +5 -0
  13. package/dist/chat/agent-dispatch/store.d.ts +29 -0
  14. package/dist/chat/agent-dispatch/types.d.ts +57 -0
  15. package/dist/chat/agent-dispatch/validation.d.ts +3 -0
  16. package/dist/chat/app/factory.d.ts +10 -0
  17. package/dist/chat/app/production.d.ts +6 -0
  18. package/dist/chat/app/services.d.ts +17 -0
  19. package/dist/chat/capabilities/catalog.d.ts +16 -0
  20. package/dist/chat/capabilities/factory.d.ts +10 -0
  21. package/dist/chat/capabilities/jr-rpc-command.d.ts +26 -0
  22. package/dist/chat/capabilities/router.d.ts +19 -0
  23. package/dist/chat/coerce.d.ts +6 -0
  24. package/dist/chat/config.d.ts +47 -0
  25. package/dist/chat/configuration/defaults.d.ts +4 -0
  26. package/dist/chat/configuration/service.d.ts +2 -0
  27. package/dist/chat/configuration/types.d.ts +37 -0
  28. package/dist/chat/configuration/validation.d.ts +2 -0
  29. package/dist/chat/credentials/broker.d.ts +22 -0
  30. package/dist/chat/credentials/header-transforms.d.ts +3 -0
  31. package/dist/chat/credentials/oauth-scope.d.ts +4 -0
  32. package/dist/chat/credentials/state-adapter-token-store.d.ts +9 -0
  33. package/dist/chat/credentials/unlink-provider.d.ts +2 -0
  34. package/dist/chat/credentials/user-token-store.d.ts +11 -0
  35. package/dist/chat/discovery.d.ts +47 -0
  36. package/dist/chat/ingress/junior-chat.d.ts +26 -0
  37. package/dist/chat/ingress/message-changed.d.ts +50 -0
  38. package/dist/chat/ingress/message-router.d.ts +9 -0
  39. package/dist/chat/ingress/slash-command.d.ts +3 -0
  40. package/dist/chat/ingress/workspace-membership.d.ts +9 -0
  41. package/dist/chat/interruption-marker.d.ts +2 -0
  42. package/dist/chat/logging.d.ts +90 -0
  43. package/dist/chat/mcp/auth-store.d.ts +41 -0
  44. package/dist/chat/mcp/client.d.ts +34 -0
  45. package/dist/chat/mcp/errors.d.ts +8 -0
  46. package/dist/chat/mcp/oauth-provider.d.ts +27 -0
  47. package/dist/chat/mcp/oauth.d.ts +17 -0
  48. package/dist/chat/mcp/tool-manager.d.ts +60 -0
  49. package/dist/chat/oauth-flow.d.ts +45 -0
  50. package/dist/chat/optional-string.d.ts +5 -0
  51. package/dist/chat/pi/client.d.ts +49 -0
  52. package/dist/chat/pi/messages.d.ts +3 -0
  53. package/dist/chat/pi/traced-stream.d.ts +9 -0
  54. package/dist/chat/plugins/agent-hooks.d.ts +32 -0
  55. package/dist/chat/plugins/auth/api-headers-broker.d.ts +6 -0
  56. package/dist/chat/plugins/auth/auth-token-placeholder.d.ts +3 -0
  57. package/dist/chat/plugins/auth/github-app-broker.d.ts +4 -0
  58. package/dist/chat/plugins/auth/oauth-bearer-broker.d.ts +6 -0
  59. package/dist/chat/plugins/auth/oauth-request.d.ts +18 -0
  60. package/dist/chat/plugins/command-env.d.ts +3 -0
  61. package/dist/chat/plugins/logging.d.ts +3 -0
  62. package/dist/chat/plugins/manifest.d.ts +3 -0
  63. package/dist/chat/plugins/package-discovery.d.ts +14 -0
  64. package/dist/chat/plugins/registry.d.ts +23 -0
  65. package/dist/chat/plugins/state.d.ts +3 -0
  66. package/dist/chat/plugins/types.d.ts +146 -0
  67. package/dist/chat/prompt.d.ts +39 -0
  68. package/dist/chat/queue/thread-message-dispatcher.d.ts +33 -0
  69. package/dist/chat/respond-helpers.d.ts +77 -0
  70. package/dist/chat/respond.d.ts +75 -0
  71. package/dist/chat/runtime/auth-pause-state.d.ts +11 -0
  72. package/dist/chat/runtime/delivered-turn-state.d.ts +15 -0
  73. package/dist/chat/runtime/dev-agent-trace.d.ts +1 -0
  74. package/dist/chat/runtime/processing-reaction.d.ts +25 -0
  75. package/dist/chat/runtime/reply-executor.d.ts +56 -0
  76. package/dist/chat/runtime/report-progress.d.ts +3 -0
  77. package/dist/chat/runtime/slack-resume.d.ts +50 -0
  78. package/dist/chat/runtime/slack-runtime.d.ts +100 -0
  79. package/dist/chat/runtime/thread-context.d.ts +24 -0
  80. package/dist/chat/runtime/thread-state.d.ts +28 -0
  81. package/dist/chat/runtime/turn-preparation.d.ts +43 -0
  82. package/dist/chat/runtime/turn-user-message.d.ts +12 -0
  83. package/dist/chat/runtime/turn.d.ts +69 -0
  84. package/dist/chat/sandbox/credentials.d.ts +11 -0
  85. package/dist/chat/sandbox/egress-oidc.d.ts +3 -0
  86. package/dist/chat/sandbox/egress-policy.d.ts +11 -0
  87. package/dist/chat/sandbox/egress-proxy.d.ts +17 -0
  88. package/dist/chat/sandbox/egress-session.d.ts +27 -0
  89. package/dist/chat/sandbox/errors.d.ts +12 -0
  90. package/dist/chat/sandbox/http-error-details.d.ts +18 -0
  91. package/dist/chat/sandbox/noninteractive-command.d.ts +17 -0
  92. package/dist/chat/sandbox/paths.d.ts +5 -0
  93. package/dist/chat/sandbox/runtime-dependency-snapshots.d.ts +20 -0
  94. package/dist/chat/sandbox/sandbox.d.ts +54 -0
  95. package/dist/chat/sandbox/session.d.ts +54 -0
  96. package/dist/chat/sandbox/skill-sandbox.d.ts +42 -0
  97. package/dist/chat/sandbox/skill-sync.d.ts +16 -0
  98. package/dist/chat/sandbox/workspace.d.ts +55 -0
  99. package/dist/chat/scheduler/cadence.d.ts +24 -0
  100. package/dist/chat/scheduler/plugin.d.ts +2 -0
  101. package/dist/chat/scheduler/prompt.d.ts +7 -0
  102. package/dist/chat/scheduler/store.d.ts +49 -0
  103. package/dist/chat/scheduler/types.d.ts +86 -0
  104. package/dist/chat/sentry.d.ts +2 -0
  105. package/dist/chat/services/attachment-claims.d.ts +2 -0
  106. package/dist/chat/services/auth-pause-response.d.ts +2 -0
  107. package/dist/chat/services/auth-pause.d.ts +19 -0
  108. package/dist/chat/services/channel-intent.d.ts +2 -0
  109. package/dist/chat/services/conversation-memory.d.ts +33 -0
  110. package/dist/chat/services/mcp-auth-orchestration.d.ts +30 -0
  111. package/dist/chat/services/pending-auth.d.ts +27 -0
  112. package/dist/chat/services/plugin-auth-orchestration.d.ts +37 -0
  113. package/dist/chat/services/provider-default-config.d.ts +9 -0
  114. package/dist/chat/services/provider-retry.d.ts +6 -0
  115. package/dist/chat/services/reply-delivery-plan.d.ts +17 -0
  116. package/dist/chat/services/subscribed-decision.d.ts +63 -0
  117. package/dist/chat/services/subscribed-reply-policy.d.ts +23 -0
  118. package/dist/chat/services/timeout-resume.d.ts +17 -0
  119. package/dist/chat/services/turn-checkpoint.d.ts +74 -0
  120. package/dist/chat/services/turn-continuation-response.d.ts +2 -0
  121. package/dist/chat/services/turn-failure-response.d.ts +15 -0
  122. package/dist/chat/services/turn-result.d.ts +55 -0
  123. package/dist/chat/services/turn-thinking-level.d.ts +49 -0
  124. package/dist/chat/services/vision-context.d.ts +61 -0
  125. package/dist/chat/skills.d.ts +48 -0
  126. package/dist/chat/slack/adapter.d.ts +9 -0
  127. package/dist/chat/slack/app-home.d.ts +11 -0
  128. package/dist/chat/slack/assistant-thread/lifecycle.d.ts +13 -0
  129. package/dist/chat/slack/assistant-thread/status-render.d.ts +28 -0
  130. package/dist/chat/slack/assistant-thread/status-scheduler.d.ts +23 -0
  131. package/dist/chat/slack/assistant-thread/status-send.d.ts +31 -0
  132. package/dist/chat/slack/assistant-thread/status.d.ts +36 -0
  133. package/dist/chat/slack/assistant-thread/title.d.ts +28 -0
  134. package/dist/chat/slack/canvas-references.d.ts +2 -0
  135. package/dist/chat/slack/channel.d.ts +48 -0
  136. package/dist/chat/slack/client.d.ts +52 -0
  137. package/dist/chat/slack/context.d.ts +9 -0
  138. package/dist/chat/slack/emoji.d.ts +1 -0
  139. package/dist/chat/slack/errors.d.ts +6 -0
  140. package/dist/chat/slack/footer.d.ts +42 -0
  141. package/dist/chat/slack/ids.d.ts +4 -0
  142. package/dist/chat/slack/legacy-attachments.d.ts +4 -0
  143. package/dist/chat/slack/message.d.ts +6 -0
  144. package/dist/chat/slack/mrkdwn.d.ts +12 -0
  145. package/dist/chat/slack/outbound.d.ts +57 -0
  146. package/dist/chat/slack/output.d.ts +54 -0
  147. package/dist/chat/slack/reply.d.ts +33 -0
  148. package/dist/chat/slack/status-format.d.ts +2 -0
  149. package/dist/chat/slack/turn-continuation-notice.d.ts +8 -0
  150. package/dist/chat/slack/user.d.ts +8 -0
  151. package/dist/chat/slack/users.d.ts +39 -0
  152. package/dist/chat/slack/workspace-context.d.ts +4 -0
  153. package/dist/chat/state/adapter.d.ts +9 -0
  154. package/dist/chat/state/artifacts.d.ts +29 -0
  155. package/dist/chat/state/conversation.d.ts +81 -0
  156. package/dist/chat/state/pi-session-message-store.d.ts +15 -0
  157. package/dist/chat/state/turn-id.d.ts +2 -0
  158. package/dist/chat/state/turn-session-store.d.ts +49 -0
  159. package/dist/chat/tools/advisor/session-store.d.ts +9 -0
  160. package/dist/chat/tools/advisor/tool.d.ts +33 -0
  161. package/dist/chat/tools/agent-tools.d.ts +10 -0
  162. package/dist/chat/tools/channel-capabilities.d.ts +11 -0
  163. package/dist/chat/tools/definition.d.ts +17 -0
  164. package/dist/chat/tools/execution/build-sandbox-input.d.ts +2 -0
  165. package/dist/chat/tools/execution/normalize-result.d.ts +6 -0
  166. package/dist/chat/tools/execution/tool-error-handler.d.ts +3 -0
  167. package/dist/chat/tools/execution/tool-input-error.d.ts +6 -0
  168. package/dist/chat/tools/idempotency.d.ts +1 -0
  169. package/dist/chat/tools/index.d.ts +5 -0
  170. package/dist/chat/tools/runtime/report-progress.d.ts +4 -0
  171. package/dist/chat/tools/sandbox/attach-file.d.ts +7 -0
  172. package/dist/chat/tools/sandbox/bash.d.ts +5 -0
  173. package/dist/chat/tools/sandbox/edit-file.d.ts +37 -0
  174. package/dist/chat/tools/sandbox/file-utils.d.ts +52 -0
  175. package/dist/chat/tools/sandbox/find-files.d.ts +24 -0
  176. package/dist/chat/tools/sandbox/grep.d.ts +33 -0
  177. package/dist/chat/tools/sandbox/list-dir.d.ts +22 -0
  178. package/dist/chat/tools/sandbox/read-file.d.ts +32 -0
  179. package/dist/chat/tools/sandbox/text-edits.d.ts +28 -0
  180. package/dist/chat/tools/sandbox/write-file.d.ts +5 -0
  181. package/dist/chat/tools/skill/call-mcp-tool.d.ts +7 -0
  182. package/dist/chat/tools/skill/load-skill.d.ts +22 -0
  183. package/dist/chat/tools/skill/mcp-tool-summary.d.ts +31 -0
  184. package/dist/chat/tools/skill/search-mcp-tools.d.ts +8 -0
  185. package/dist/chat/tools/slack/canvas-tools.d.ts +29 -0
  186. package/dist/chat/tools/slack/canvases.d.ts +45 -0
  187. package/dist/chat/tools/slack/channel-list-messages.d.ts +9 -0
  188. package/dist/chat/tools/slack/channel-post-message.d.ts +4 -0
  189. package/dist/chat/tools/slack/list-tools.d.ts +21 -0
  190. package/dist/chat/tools/slack/lists.d.ts +42 -0
  191. package/dist/chat/tools/slack/message-add-reaction.d.ts +4 -0
  192. package/dist/chat/tools/slack/schedule-tools.d.ts +29 -0
  193. package/dist/chat/tools/slack/slack-message-url.d.ts +18 -0
  194. package/dist/chat/tools/slack/thread-read.d.ts +9 -0
  195. package/dist/chat/tools/slack/user-lookup.d.ts +8 -0
  196. package/dist/chat/tools/system-time.d.ts +1 -0
  197. package/dist/chat/tools/types.d.ts +61 -0
  198. package/dist/chat/tools/web/constants.d.ts +6 -0
  199. package/dist/chat/tools/web/fetch-content.d.ts +23 -0
  200. package/dist/chat/tools/web/fetch-tool.d.ts +5 -0
  201. package/dist/chat/tools/web/image-generate.d.ts +4 -0
  202. package/dist/chat/tools/web/network.d.ts +6 -0
  203. package/dist/chat/tools/web/search.d.ts +5 -0
  204. package/dist/chat/turn-context-tag.d.ts +6 -0
  205. package/dist/chat/usage.d.ts +24 -0
  206. package/dist/chat/xml.d.ts +1 -0
  207. package/dist/{chunk-XPXD3FCE.js → chunk-5LUISFEY.js} +189 -35
  208. package/dist/{chunk-ZNFNY53B.js → chunk-D3G3YOU4.js} +2 -2
  209. package/dist/chunk-SCQPBJAU.js +21 -0
  210. package/dist/{chunk-Q3FDONU7.js → chunk-TTUY467K.js} +47 -37
  211. package/dist/{chunk-KCOKQLBF.js → chunk-XI3CFWTA.js} +168 -15
  212. package/dist/cli/check.js +3 -3
  213. package/dist/cli/init.js +6 -1
  214. package/dist/cli/snapshot-warmup.js +3 -3
  215. package/dist/handlers/agent-dispatch.d.ts +3 -0
  216. package/dist/handlers/diagnostics-dashboard.d.ts +2 -0
  217. package/dist/handlers/diagnostics.d.ts +2 -0
  218. package/dist/handlers/health.d.ts +4 -0
  219. package/dist/handlers/heartbeat.d.ts +3 -0
  220. package/dist/handlers/mcp-oauth-callback.d.ts +2 -0
  221. package/dist/handlers/oauth-callback.d.ts +2 -0
  222. package/dist/handlers/oauth-html.d.ts +2 -0
  223. package/dist/handlers/sandbox-egress-proxy.d.ts +9 -0
  224. package/dist/handlers/turn-resume.d.ts +3 -0
  225. package/dist/handlers/types.d.ts +2 -0
  226. package/dist/handlers/webhooks.d.ts +15 -0
  227. package/dist/instrumentation.d.ts +1 -3
  228. package/dist/nitro.d.ts +4 -7
  229. package/dist/nitro.js +112 -54
  230. package/dist/package-resolution.d.ts +13 -0
  231. package/dist/vercel.d.ts +2 -4
  232. package/dist/vercel.js +3 -12
  233. package/package.json +32 -26
  234. package/dist/cli/check.d.ts +0 -8
  235. package/dist/cli/env.d.ts +0 -7
  236. package/dist/cli/init.d.ts +0 -3
  237. package/dist/cli/run.d.ts +0 -12
  238. package/dist/cli/snapshot-warmup.d.ts +0 -3
  239. package/dist/types-X_iCClPb.d.ts +0 -75
@@ -7,14 +7,14 @@ import {
7
7
  serializeGenAiAttribute,
8
8
  setSpanAttributes,
9
9
  withSpan
10
- } from "./chunk-Q3FDONU7.js";
10
+ } from "./chunk-TTUY467K.js";
11
11
 
12
12
  // src/chat/state/adapter.ts
13
13
  import { createMemoryState } from "@chat-adapter/state-memory";
14
14
  import { createRedisState } from "@chat-adapter/state-redis";
15
15
 
16
16
  // src/chat/config.ts
17
- import { getModel } from "@mariozechner/pi-ai";
17
+ import { getModel } from "@earendil-works/pi-ai";
18
18
 
19
19
  // src/chat/optional-string.ts
20
20
  function toOptionalTrimmed(value) {
@@ -31,11 +31,11 @@ import {
31
31
  getEnvApiKey,
32
32
  getModels,
33
33
  registerApiProvider
34
- } from "@mariozechner/pi-ai";
34
+ } from "@earendil-works/pi-ai";
35
35
  import {
36
36
  streamAnthropic,
37
37
  streamSimpleAnthropic
38
- } from "@mariozechner/pi-ai/anthropic";
38
+ } from "@earendil-works/pi-ai/anthropic";
39
39
  registerApiProvider({
40
40
  api: "anthropic-messages",
41
41
  stream: streamAnthropic,
@@ -385,6 +385,7 @@ function readChatConfig(env = process.env) {
385
385
  },
386
386
  state: {
387
387
  adapter: env.JUNIOR_STATE_ADAPTER?.trim().toLowerCase() === "memory" ? "memory" : "redis",
388
+ keyPrefix: toOptionalTrimmed(env.JUNIOR_STATE_KEY_PREFIX),
388
389
  redisUrl: toOptionalTrimmed(env.REDIS_URL)
389
390
  }
390
391
  };
@@ -413,25 +414,166 @@ function getRuntimeMetadata() {
413
414
  }
414
415
 
415
416
  // src/chat/state/adapter.ts
416
- var MIN_LOCK_TTL_MS = 1e3 * 60 * 5;
417
+ var ACTIVE_LOCK_TTL_MS = 9e4;
418
+ var ACTIVE_LOCK_HEARTBEAT_MS = 3e4;
417
419
  var stateAdapter;
418
420
  var redisStateAdapter;
419
- function createQueuedStateAdapter(base) {
421
+ function createPrefixedStateAdapter(base, prefix) {
422
+ const prefixed = (value) => `${prefix}:${value}`;
423
+ const unprefixed = (value) => value.startsWith(`${prefix}:`) ? value.slice(prefix.length + 1) : value;
424
+ const prefixLock = (lock) => ({
425
+ ...lock,
426
+ threadId: prefixed(lock.threadId)
427
+ });
428
+ const unprefixLock = (lock) => ({
429
+ ...lock,
430
+ threadId: unprefixed(lock.threadId)
431
+ });
432
+ return {
433
+ appendToList: (key, value, options) => base.appendToList(prefixed(key), value, options),
434
+ connect: () => base.connect(),
435
+ disconnect: () => base.disconnect(),
436
+ subscribe: (threadId) => base.subscribe(prefixed(threadId)),
437
+ unsubscribe: (threadId) => base.unsubscribe(prefixed(threadId)),
438
+ isSubscribed: (threadId) => base.isSubscribed(prefixed(threadId)),
439
+ acquireLock: async (threadId, ttlMs) => {
440
+ const lock = await base.acquireLock(prefixed(threadId), ttlMs);
441
+ return lock ? unprefixLock(lock) : null;
442
+ },
443
+ releaseLock: (lock) => base.releaseLock(prefixLock(lock)),
444
+ extendLock: async (lock, ttlMs) => {
445
+ const prefixedLock = prefixLock(lock);
446
+ const extended = await base.extendLock(prefixedLock, ttlMs);
447
+ if (extended) {
448
+ lock.expiresAt = prefixedLock.expiresAt;
449
+ }
450
+ return extended;
451
+ },
452
+ forceReleaseLock: (threadId) => base.forceReleaseLock(prefixed(threadId)),
453
+ enqueue: (threadId, entry, maxSize) => base.enqueue(prefixed(threadId), entry, maxSize),
454
+ dequeue: (threadId) => base.dequeue(prefixed(threadId)),
455
+ queueDepth: (threadId) => base.queueDepth(prefixed(threadId)),
456
+ get: (key) => base.get(prefixed(key)),
457
+ getList: (key) => base.getList(prefixed(key)),
458
+ set: (key, value, ttlMs) => base.set(prefixed(key), value, ttlMs),
459
+ setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(prefixed(key), value, ttlMs),
460
+ delete: (key) => base.delete(prefixed(key))
461
+ };
462
+ }
463
+ function createQueuedStateAdapter(base, options) {
464
+ const heartbeats = /* @__PURE__ */ new Map();
465
+ const effectiveLockTtlMs = (ttlMs) => Math.max(ttlMs, ACTIVE_LOCK_TTL_MS);
466
+ const shouldHeartbeatLock = (ttlMs) => ttlMs <= ACTIVE_LOCK_TTL_MS;
467
+ const heartbeatKey = (lock) => `${lock.threadId}:${lock.token}`;
468
+ const stopHeartbeatByKey = (key) => {
469
+ const heartbeat = heartbeats.get(key);
470
+ if (!heartbeat) {
471
+ return;
472
+ }
473
+ clearInterval(heartbeat.timer);
474
+ heartbeats.delete(key);
475
+ };
476
+ const stopHeartbeat = (lock) => {
477
+ stopHeartbeatByKey(heartbeatKey(lock));
478
+ };
479
+ const stopHeartbeatsForThread = (threadId) => {
480
+ for (const [key, heartbeat] of heartbeats) {
481
+ if (heartbeat.lock.threadId === threadId) {
482
+ stopHeartbeatByKey(key);
483
+ }
484
+ }
485
+ };
486
+ const stopAllHeartbeats = () => {
487
+ for (const key of heartbeats.keys()) {
488
+ stopHeartbeatByKey(key);
489
+ }
490
+ };
491
+ const runHeartbeat = async (key) => {
492
+ const heartbeat = heartbeats.get(key);
493
+ if (!heartbeat || heartbeat.inFlight) {
494
+ return;
495
+ }
496
+ heartbeat.inFlight = true;
497
+ try {
498
+ if (Date.now() - heartbeat.startedAtMs >= options.activeLockMaxAgeMs) {
499
+ stopHeartbeatByKey(key);
500
+ return;
501
+ }
502
+ const extended = await base.extendLock(heartbeat.lock, heartbeat.ttlMs);
503
+ if (!extended) {
504
+ stopHeartbeatByKey(key);
505
+ return;
506
+ }
507
+ heartbeat.lock.expiresAt = Date.now() + heartbeat.ttlMs;
508
+ } catch {
509
+ } finally {
510
+ const current = heartbeats.get(key);
511
+ if (current === heartbeat) {
512
+ current.inFlight = false;
513
+ }
514
+ }
515
+ };
516
+ const startOrUpdateHeartbeat = (lock, ttlMs) => {
517
+ const key = heartbeatKey(lock);
518
+ const existing = heartbeats.get(key);
519
+ if (existing) {
520
+ existing.ttlMs = ttlMs;
521
+ return;
522
+ }
523
+ const timer = setInterval(() => {
524
+ void runHeartbeat(key);
525
+ }, ACTIVE_LOCK_HEARTBEAT_MS);
526
+ timer.unref?.();
527
+ heartbeats.set(key, {
528
+ inFlight: false,
529
+ lock,
530
+ startedAtMs: Date.now(),
531
+ timer,
532
+ ttlMs
533
+ });
534
+ };
420
535
  const acquireLock = async (threadId, ttlMs) => {
421
- const effectiveTtlMs = Math.max(ttlMs, MIN_LOCK_TTL_MS);
422
- return await base.acquireLock(threadId, effectiveTtlMs);
536
+ const effectiveTtlMs = effectiveLockTtlMs(ttlMs);
537
+ const lock = await base.acquireLock(threadId, effectiveTtlMs);
538
+ if (lock && shouldHeartbeatLock(ttlMs)) {
539
+ startOrUpdateHeartbeat(lock, effectiveTtlMs);
540
+ }
541
+ return lock;
423
542
  };
424
543
  return {
425
- appendToList: (key, value, options) => base.appendToList(key, value, options),
544
+ appendToList: (key, value, options2) => base.appendToList(key, value, options2),
426
545
  connect: () => base.connect(),
427
- disconnect: () => base.disconnect(),
546
+ disconnect: async () => {
547
+ stopAllHeartbeats();
548
+ await base.disconnect();
549
+ },
428
550
  subscribe: (threadId) => base.subscribe(threadId),
429
551
  unsubscribe: (threadId) => base.unsubscribe(threadId),
430
552
  isSubscribed: (threadId) => base.isSubscribed(threadId),
431
553
  acquireLock,
432
- releaseLock: (lock) => base.releaseLock(lock),
433
- extendLock: (lock, ttlMs) => base.extendLock(lock, Math.max(ttlMs, MIN_LOCK_TTL_MS)),
434
- forceReleaseLock: (threadId) => base.forceReleaseLock(threadId),
554
+ releaseLock: async (lock) => {
555
+ stopHeartbeat(lock);
556
+ await base.releaseLock(lock);
557
+ },
558
+ extendLock: async (lock, ttlMs) => {
559
+ const effectiveTtlMs = effectiveLockTtlMs(ttlMs);
560
+ const extended = await base.extendLock(lock, effectiveTtlMs);
561
+ if (extended) {
562
+ lock.expiresAt = Date.now() + effectiveTtlMs;
563
+ if (shouldHeartbeatLock(ttlMs)) {
564
+ startOrUpdateHeartbeat(lock, effectiveTtlMs);
565
+ } else {
566
+ stopHeartbeat(lock);
567
+ }
568
+ } else {
569
+ stopHeartbeat(lock);
570
+ }
571
+ return extended;
572
+ },
573
+ forceReleaseLock: async (threadId) => {
574
+ stopHeartbeatsForThread(threadId);
575
+ await base.forceReleaseLock(threadId);
576
+ },
435
577
  enqueue: (threadId, entry, maxSize) => base.enqueue(threadId, entry, maxSize),
436
578
  dequeue: (threadId) => base.dequeue(threadId),
437
579
  queueDepth: (threadId) => base.queueDepth(threadId),
@@ -442,11 +584,18 @@ function createQueuedStateAdapter(base) {
442
584
  delete: (key) => base.delete(key)
443
585
  };
444
586
  }
587
+ function withOptionalPrefix(base, prefix) {
588
+ return prefix ? createPrefixedStateAdapter(base, prefix) : base;
589
+ }
445
590
  function createStateAdapter() {
446
591
  const config = getChatConfig();
592
+ const activeLockMaxAgeMs = config.bot.turnTimeoutMs + ACTIVE_LOCK_TTL_MS;
447
593
  if (config.state.adapter === "memory") {
448
594
  redisStateAdapter = void 0;
449
- return createQueuedStateAdapter(createMemoryState());
595
+ return createQueuedStateAdapter(
596
+ withOptionalPrefix(createMemoryState(), config.state.keyPrefix),
597
+ { activeLockMaxAgeMs }
598
+ );
450
599
  }
451
600
  if (!config.state.redisUrl) {
452
601
  throw new Error("REDIS_URL is required for durable Slack thread state");
@@ -455,7 +604,10 @@ function createStateAdapter() {
455
604
  url: config.state.redisUrl
456
605
  });
457
606
  redisStateAdapter = redisState;
458
- return createQueuedStateAdapter(redisState);
607
+ return createQueuedStateAdapter(
608
+ withOptionalPrefix(redisState, config.state.keyPrefix),
609
+ { activeLockMaxAgeMs }
610
+ );
459
611
  }
460
612
  function getStateAdapter() {
461
613
  if (!stateAdapter) {
@@ -1173,6 +1325,7 @@ export {
1173
1325
  getSlackClientId,
1174
1326
  getSlackClientSecret,
1175
1327
  getRuntimeMetadata,
1328
+ ACTIVE_LOCK_TTL_MS,
1176
1329
  getStateAdapter,
1177
1330
  disconnectStateAdapter,
1178
1331
  SANDBOX_WORKSPACE_ROOT,
package/dist/cli/check.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  parseSkillFile
3
- } from "../chunk-ZNFNY53B.js";
3
+ } from "../chunk-D3G3YOU4.js";
4
4
  import {
5
5
  parsePluginManifest
6
- } from "../chunk-Q3FDONU7.js";
6
+ } from "../chunk-TTUY467K.js";
7
7
  import "../chunk-Z3YD6NHK.js";
8
- import "../chunk-XPXD3FCE.js";
8
+ import "../chunk-5LUISFEY.js";
9
9
  import "../chunk-2KG3PWR4.js";
10
10
 
11
11
  // src/cli/check.ts
package/dist/cli/init.js CHANGED
@@ -1,3 +1,6 @@
1
+ import {
2
+ juniorVercelConfig
3
+ } from "../chunk-SCQPBJAU.js";
1
4
  import "../chunk-2KG3PWR4.js";
2
5
 
3
6
  // src/cli/init.ts
@@ -51,7 +54,7 @@ export default defineConfig({
51
54
  function writeVercelJson(targetDir) {
52
55
  fs.writeFileSync(
53
56
  path.join(targetDir, "vercel.json"),
54
- `${JSON.stringify({ framework: "nitro", buildCommand: "pnpm build" }, null, 2)}
57
+ `${JSON.stringify(juniorVercelConfig(), null, 2)}
55
58
  `
56
59
  );
57
60
  }
@@ -171,12 +174,14 @@ Operational context and domain knowledge for ${name}.
171
174
  path.join(target, ".env.example"),
172
175
  `SLACK_BOT_TOKEN=
173
176
  SLACK_SIGNING_SECRET=
177
+ JUNIOR_SECRET=
174
178
  JUNIOR_BOT_NAME=
175
179
  AI_MODEL=
176
180
  AI_FAST_MODEL=
177
181
  AI_VISION_MODEL=
178
182
  AI_WEB_SEARCH_MODEL=
179
183
  REDIS_URL=
184
+ CRON_SECRET=
180
185
  SENTRY_DSN=
181
186
  SENTRY_ORG_SLUG=
182
187
  `
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  disconnectStateAdapter,
3
3
  resolveRuntimeDependencySnapshot
4
- } from "../chunk-KCOKQLBF.js";
4
+ } from "../chunk-XI3CFWTA.js";
5
5
  import {
6
6
  getPluginProviders,
7
7
  getPluginRuntimeDependencies,
8
8
  getPluginRuntimePostinstall
9
- } from "../chunk-Q3FDONU7.js";
9
+ } from "../chunk-TTUY467K.js";
10
10
  import "../chunk-Z3YD6NHK.js";
11
- import "../chunk-XPXD3FCE.js";
11
+ import "../chunk-5LUISFEY.js";
12
12
  import "../chunk-2KG3PWR4.js";
13
13
 
14
14
  // src/cli/snapshot-warmup.ts
@@ -0,0 +1,3 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /** Handle the authenticated internal agent-dispatch callback. */
3
+ export declare function POST(request: Request, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ /** Serve an HTML diagnostics dashboard showing health, plugins, and skills. */
2
+ export declare function GET(): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ /** Return a runtime discovery snapshot for built-app diagnostics. */
2
+ export declare function GET(): Promise<Response>;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Returns a minimal JSON health response for runtime health checks.
3
+ */
4
+ export declare function GET(): Response;
@@ -0,0 +1,3 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /** Handle the authenticated internal heartbeat. */
3
+ export declare function GET(request: Request, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ export declare function GET(request: Request, provider: string, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ export declare function GET(request: Request, provider: string, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ /** Build a simple centered HTML callback page. Callers must pre-escape dynamic strings. */
2
+ export declare function htmlCallbackResponse(title: string, message: string, status: number): Response;
@@ -0,0 +1,9 @@
1
+ import { type SandboxEgressHttpInterceptor } from "@/chat/sandbox/egress-proxy";
2
+ interface SandboxEgressProxyOptions {
3
+ interceptHttp?: SandboxEgressHttpInterceptor;
4
+ }
5
+ /** Handles Vercel Sandbox firewall egress proxy requests. */
6
+ export declare function ALL(request: Request, options?: SandboxEgressProxyOptions): Promise<Response>;
7
+ /** Return whether a request should be routed through sandbox egress proxying. */
8
+ export declare function isSandboxEgressRequest(request: Request): boolean;
9
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /** Handle the authenticated internal timeout-resume callback. */
3
+ export declare function POST(request: Request, waitUntil: WaitUntilFn): Promise<Response>;
@@ -0,0 +1,2 @@
1
+ /** Callback to schedule background work that must finish before the function exits. */
2
+ export type WaitUntilFn = (task: Promise<unknown> | (() => Promise<unknown>)) => void;
@@ -0,0 +1,15 @@
1
+ import type { WaitUntilFn } from "@/handlers/types";
2
+ /**
3
+ * Handles `POST /api/webhooks/:platform`.
4
+ *
5
+ * The router only resolves the platform and delegates to the adapter webhook
6
+ * implementation; request semantics stay owned by the adapter package.
7
+ *
8
+ * For Slack, the body is read once and used to detect `message_changed` events
9
+ * that introduce a new bot @mention, which the Slack adapter silently ignores.
10
+ * The request is then reconstructed so the adapter can consume it normally.
11
+ */
12
+ export declare function handlePlatformWebhook(request: Request, platform: string, waitUntil: WaitUntilFn, bot?: import("../chat/ingress/junior-chat").JuniorChat<{
13
+ slack: import("@chat-adapter/slack").SlackAdapter;
14
+ }>): Promise<Response>;
15
+ export declare function POST(request: Request, platform: string, waitUntil: WaitUntilFn): Promise<Response>;
@@ -1,4 +1,2 @@
1
1
  /** Initialize Sentry for the Junior runtime. Call at the top of your entry point. */
2
- declare function initSentry(): void;
3
-
4
- export { initSentry };
2
+ export declare function initSentry(): void;
package/dist/nitro.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { P as PluginConfig } from './types-X_iCClPb.js';
2
-
3
- interface JuniorNitroOptions {
1
+ import type { PluginConfig } from "@/chat/plugins/types";
2
+ export interface JuniorNitroOptions {
4
3
  cwd?: string;
5
4
  maxDuration?: number;
6
5
  /** Plugin packages and manifest overrides bundled into the app. */
@@ -9,15 +8,13 @@ interface JuniorNitroOptions {
9
8
  * Extra file patterns to copy into the server output for files that the
10
9
  * bundler cannot trace (e.g. dynamically imported providers).
11
10
  * Each entry is `"<package-name>/<subpath-glob>"`, resolved via Node
12
- * module resolution. Example: `"@mariozechner/pi-ai/dist/providers/*.js"`
11
+ * module resolution. Example: `"@earendil-works/pi-ai/dist/providers/*.js"`
13
12
  */
14
13
  includeFiles?: string[];
15
14
  }
16
15
  /** Nitro module that copies app and plugin content into the Vercel build output. */
17
- declare function juniorNitro(options?: JuniorNitroOptions): {
16
+ export declare function juniorNitro(options?: JuniorNitroOptions): {
18
17
  nitro: {
19
18
  setup(nitro: unknown): void;
20
19
  };
21
20
  };
22
-
23
- export { type JuniorNitroOptions, juniorNitro };
package/dist/nitro.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
- discoverInstalledPluginPackageContent
3
- } from "./chunk-XPXD3FCE.js";
2
+ discoverInstalledPluginPackageContent,
3
+ isValidPackageName,
4
+ resolvePackageDir
5
+ } from "./chunk-5LUISFEY.js";
4
6
  import "./chunk-2KG3PWR4.js";
5
7
 
6
8
  // src/nitro.ts
7
- import path3 from "path";
9
+ import path2 from "path";
8
10
 
9
11
  // src/build/rolldown-workarounds.ts
10
12
  function applyRolldownTreeshakeWorkaround(nitro) {
@@ -18,8 +20,8 @@ function applyRolldownTreeshakeWorkaround(nitro) {
18
20
  }
19
21
 
20
22
  // src/build/copy-build-content.ts
21
- import { cpSync, existsSync as existsSync2, mkdirSync, readdirSync } from "fs";
22
- import path2 from "path";
23
+ import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
24
+ import path from "path";
23
25
 
24
26
  // src/build/glob-to-regex.ts
25
27
  function globToRegex(pattern) {
@@ -27,39 +29,18 @@ function globToRegex(pattern) {
27
29
  return new RegExp(`^${escaped}$`);
28
30
  }
29
31
 
30
- // src/build/resolve-package.ts
31
- import { existsSync } from "fs";
32
- import path from "path";
33
- import { fileURLToPath } from "url";
34
- function resolvePackageDir(pkgName) {
35
- try {
36
- const resolved = import.meta.resolve(pkgName);
37
- const entry = resolved.startsWith("file://") ? fileURLToPath(resolved) : resolved;
38
- let dir = path.dirname(entry);
39
- while (dir !== path.dirname(dir)) {
40
- if (existsSync(path.join(dir, "package.json"))) return dir;
41
- dir = path.dirname(dir);
42
- }
43
- } catch {
44
- }
45
- return void 0;
46
- }
47
-
48
32
  // src/build/copy-build-content.ts
49
33
  function copyAppAndPluginContent(cwd, serverRoot, packageNames) {
50
- copyIfExists(path2.join(cwd, "app"), path2.join(serverRoot, "app"));
34
+ copyIfExists(path.join(cwd, "app"), path.join(serverRoot, "app"));
51
35
  const packagedContent = discoverInstalledPluginPackageContent(cwd, {
52
36
  packageNames
53
37
  });
54
38
  for (const root of packagedContent.manifestRoots) {
55
- if (existsSync2(path2.join(root, "plugin.yaml"))) {
56
- const relative = path2.relative(cwd, root);
57
- if (!relative || path2.isAbsolute(relative) || relative.startsWith("..")) {
58
- continue;
59
- }
39
+ if (existsSync(path.join(root, "plugin.yaml"))) {
40
+ const manifestPath = path.join(root, "plugin.yaml");
60
41
  copyIfExists(
61
- path2.join(root, "plugin.yaml"),
62
- path2.join(serverRoot, relative, "plugin.yaml")
42
+ manifestPath,
43
+ resolveServerOutputPath(cwd, serverRoot, manifestPath)
63
44
  );
64
45
  continue;
65
46
  }
@@ -69,43 +50,119 @@ function copyAppAndPluginContent(cwd, serverRoot, packageNames) {
69
50
  copyRootIntoServerOutput(cwd, serverRoot, root);
70
51
  }
71
52
  }
72
- function copyIncludedFiles(serverRoot, patterns) {
73
- if (!patterns?.length) return;
53
+ function copyIncludedFiles(cwd, serverRoot, patterns) {
54
+ if (patterns === void 0) return;
55
+ if (!Array.isArray(patterns)) {
56
+ throw new Error(
57
+ "includeFiles must be an array of package subpath patterns"
58
+ );
59
+ }
60
+ if (patterns.length === 0) return;
74
61
  for (const pattern of patterns) {
75
- const normalized = pattern.replace(/^node_modules\//, "");
76
- const parts = normalized.split("/");
77
- const pkgName = parts[0].startsWith("@") ? `${parts[0]}/${parts[1]}` : parts[0];
78
- const subpath = parts.slice(pkgName.includes("/") ? 2 : 1).join("/");
79
- const fileGlob = path2.basename(subpath);
80
- const subDir = path2.dirname(subpath);
81
- const pkgDir = resolvePackageDir(pkgName);
82
- if (!pkgDir) continue;
83
- const sourceDir = path2.join(pkgDir, subDir);
84
- if (!existsSync2(sourceDir)) continue;
62
+ if (typeof pattern !== "string" || !pattern.trim()) {
63
+ throw new Error("includeFiles entries must be package subpath patterns");
64
+ }
65
+ const { pkgName, subDir, fileGlob } = parseIncludePattern(pattern);
66
+ const pkgDir = resolvePackageDir(cwd, pkgName);
67
+ if (!pkgDir) {
68
+ throw new Error(
69
+ `includeFiles entry "${pattern}" references package "${pkgName}", but it could not be resolved`
70
+ );
71
+ }
72
+ const sourceDir = path.join(pkgDir, subDir);
73
+ if (!isDirectory(sourceDir)) {
74
+ throw new Error(
75
+ `includeFiles entry "${pattern}" references missing directory ${sourceDir}`
76
+ );
77
+ }
85
78
  const entries = readdirSync(sourceDir);
86
79
  const re = fileGlob.includes("*") ? globToRegex(fileGlob) : null;
80
+ let matched = false;
81
+ let copied = false;
87
82
  for (const entry of entries) {
88
83
  if (re ? !re.test(entry) : entry !== fileGlob) continue;
89
- copyIfExists(
90
- path2.join(sourceDir, entry),
91
- path2.join(serverRoot, "node_modules", pkgName, subDir, entry)
84
+ matched = true;
85
+ copied = copyIfExists(
86
+ path.join(sourceDir, entry),
87
+ path.join(serverRoot, "node_modules", pkgName, subDir, entry)
88
+ ) || copied;
89
+ }
90
+ if (!matched) {
91
+ throw new Error(
92
+ `includeFiles entry "${pattern}" did not match any files in ${sourceDir}`
93
+ );
94
+ }
95
+ if (!copied) {
96
+ throw new Error(
97
+ `includeFiles entry "${pattern}" matched files in ${sourceDir} but did not copy any existing files`
92
98
  );
93
99
  }
94
100
  }
95
101
  }
102
+ function parseIncludePattern(pattern) {
103
+ const normalized = pattern.trim().replace(/^node_modules\//, "");
104
+ const parts = normalized.split("/");
105
+ if (!normalized || path.isAbsolute(normalized) || parts.some((part) => !part || part === "." || part === "..")) {
106
+ throw new Error(
107
+ `includeFiles entry "${pattern}" must be a package subpath pattern`
108
+ );
109
+ }
110
+ const isScopedPackage = parts[0].startsWith("@");
111
+ const packagePartCount = isScopedPackage ? 2 : 1;
112
+ const pkgName = parts.slice(0, packagePartCount).join("/");
113
+ const subpath = parts.slice(packagePartCount).join("/");
114
+ if (!pkgName || !isValidPackageName(pkgName) || !subpath) {
115
+ throw new Error(
116
+ `includeFiles entry "${pattern}" must include a package subpath`
117
+ );
118
+ }
119
+ return {
120
+ pkgName,
121
+ subDir: path.dirname(subpath),
122
+ fileGlob: path.basename(subpath)
123
+ };
124
+ }
125
+ function isDirectory(targetPath) {
126
+ try {
127
+ return statSync(targetPath).isDirectory();
128
+ } catch {
129
+ return false;
130
+ }
131
+ }
96
132
  function copyIfExists(source, target) {
97
- if (!existsSync2(source)) {
98
- return;
133
+ if (!existsSync(source)) {
134
+ return false;
99
135
  }
100
- mkdirSync(path2.dirname(target), { recursive: true });
136
+ mkdirSync(path.dirname(target), { recursive: true });
101
137
  cpSync(source, target, { recursive: true });
138
+ return true;
102
139
  }
103
140
  function copyRootIntoServerOutput(cwd, serverRoot, root) {
104
- const relative = path2.relative(cwd, root);
105
- if (!relative || path2.isAbsolute(relative) || relative.startsWith("..")) {
106
- return;
141
+ copyIfExists(root, resolveServerOutputPath(cwd, serverRoot, root));
142
+ }
143
+ function resolveServerOutputPath(cwd, serverRoot, sourcePath) {
144
+ const relative = path.relative(cwd, sourcePath);
145
+ if (isLocalRelativePath(relative)) {
146
+ return path.join(serverRoot, relative);
147
+ }
148
+ const nodeModulesRelative = nodeModulesRelativePath(sourcePath);
149
+ if (nodeModulesRelative) {
150
+ return path.join(serverRoot, nodeModulesRelative);
107
151
  }
108
- copyIfExists(root, path2.join(serverRoot, relative));
152
+ throw new Error(
153
+ `Cannot copy configured plugin content outside the app root or node_modules: ${sourcePath}`
154
+ );
155
+ }
156
+ function isLocalRelativePath(relativePath) {
157
+ return Boolean(relativePath) && !path.isAbsolute(relativePath) && relativePath !== ".." && !relativePath.startsWith(`..${path.sep}`);
158
+ }
159
+ function nodeModulesRelativePath(sourcePath) {
160
+ const parts = path.resolve(sourcePath).split(path.sep);
161
+ const nodeModulesIndex = parts.lastIndexOf("node_modules");
162
+ if (nodeModulesIndex === -1 || nodeModulesIndex === parts.length - 1) {
163
+ return null;
164
+ }
165
+ return path.join("node_modules", ...parts.slice(nodeModulesIndex + 1));
109
166
  }
110
167
 
111
168
  // src/build/virtual-config.ts
@@ -118,7 +175,7 @@ function juniorNitro(options = {}) {
118
175
  return {
119
176
  nitro: {
120
177
  setup(nitro) {
121
- const cwd = path3.resolve(
178
+ const cwd = path2.resolve(
122
179
  options.cwd ?? nitro.options.rootDir ?? process.cwd()
123
180
  );
124
181
  nitro.options.vercel ??= {};
@@ -133,6 +190,7 @@ function juniorNitro(options = {}) {
133
190
  options.plugins?.packages
134
191
  );
135
192
  copyIncludedFiles(
193
+ cwd,
136
194
  nitro.options.output.serverDir,
137
195
  options.includeFiles
138
196
  );
@@ -0,0 +1,13 @@
1
+ export interface ResolvedPackageLocation {
2
+ dir: string;
3
+ nodeModulesDir?: string;
4
+ }
5
+ export interface ResolvePackageLocationOptions {
6
+ nodeModulesDirs?: string[];
7
+ }
8
+ /** Return whether a string is shaped like an npm package name. */
9
+ export declare function isValidPackageName(packageName: string): boolean;
10
+ /** Resolve a package root from an app cwd without requiring the package to expose a JS entry point. */
11
+ export declare function resolvePackageLocation(cwd: string, packageName: string, options?: ResolvePackageLocationOptions): ResolvedPackageLocation | undefined;
12
+ /** Resolve a package root directory from an app cwd. */
13
+ export declare function resolvePackageDir(cwd: string, packageName: string): string | undefined;