@sentry/junior 0.225.0 → 0.227.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 (65) hide show
  1. package/dist/{agent-hooks-CRuRcOg9.js → agent-hooks-bEwEJhlg.js} +231 -17
  2. package/dist/{agent-runner-Cad1RtWn.js → agent-runner-BGDSjciH.js} +2899 -159
  3. package/dist/api/schema.d.ts +417 -15
  4. package/dist/api/schema.js +4 -4
  5. package/dist/api.js +57 -32
  6. package/dist/{app-BbSD6EtD.d.ts → app-CjRIKZb5.d.ts} +1 -1
  7. package/dist/app.d.ts +1 -1
  8. package/dist/app.js +971 -7685
  9. package/dist/{briefs-BtnkPWT5.js → briefs-BkM_ZW4B.js} +4 -4
  10. package/dist/{catalog-runtime-pv4grNNb.js → catalog-runtime-Cw9V2jpn.js} +1 -1
  11. package/dist/{checkpoint-6fkAdB3g.js → checkpoint-oZYD3-Ar.js} +77 -11
  12. package/dist/cli/chat.js +13 -13
  13. package/dist/cli/check.js +3 -3
  14. package/dist/cli/main.js +1 -1
  15. package/dist/cli/plugins.js +3 -3
  16. package/dist/cli/snapshot-create.js +3 -3
  17. package/dist/cli/upgrade.js +3 -3
  18. package/dist/{client-ihmkx60d.js → client-Pcxo3lGn.js} +2 -2
  19. package/dist/{config-DMg679BW.js → config-CYvEow1F.js} +2 -2
  20. package/dist/{context-Bplcgypl.js → context-0Et9iVSB.js} +1 -1
  21. package/dist/{conversation-Bygi39Xj.js → conversation-BnhOMfEB.js} +113 -25
  22. package/dist/{conversation-privacy-ZYy05Y3q.js → conversation-privacy-hQmyZbOC.js} +1 -1
  23. package/dist/{credential-sync-DCB2SwnQ.js → credential-sync-CUGbiiCM.js} +15 -135
  24. package/dist/{executor-B9R4cHte.js → executor-BXMlFrV6.js} +1 -1
  25. package/dist/history-nukv1YN8.d.ts +127 -0
  26. package/dist/images-8siTAUNW.js +82 -0
  27. package/dist/instrumentation.js +2 -2
  28. package/dist/{vercel-queue-DIkVcfK4.js → job-queue-AI0_QAgc.js} +61 -2
  29. package/dist/{logging-CcTvYQ8A.js → logging-BPBx6WF-.js} +1 -1
  30. package/dist/nitro.d.ts +1 -1
  31. package/dist/nitro.js +3 -4
  32. package/dist/{oauth-authorization-BS4vPJmu.js → oauth-authorization-Cq1GaLIP.js} +1 -1
  33. package/dist/{oauth-callback-server-DnlQsGBJ.js → oauth-callback-server-CnF03VYh.js} +2 -2
  34. package/dist/pending-auth-CHUjr_6d.js +59 -0
  35. package/dist/{profile-CV97YuiL.js → profile-upzC-wN1.js} +4 -4
  36. package/dist/{prompt-CL8zxsmm.js → prompt-CZIQcPHy.js} +1 -1
  37. package/dist/{registry-C8I4IejN.js → registry-DM5aMhjm.js} +2 -2
  38. package/dist/{resolve-DXVAzYa3.js → resolve-sF6Lg7Ay.js} +2 -2
  39. package/dist/{runner-Die1RJ_z.js → runner-Bu2wYpK8.js} +10 -10
  40. package/dist/{sandbox-egress-signals-BZepyVh1.js → sandbox-egress-signals-Dgerhizb.js} +1 -1
  41. package/dist/{schema-BE4uso4i.js → schema-BSiwcvjm.js} +2 -2
  42. package/dist/{skills-DUcDEgDI.js → skills-CAI5s___.js} +2 -2
  43. package/dist/{spawn-o15i3tJu.js → spawn-DRK9TBgY.js} +2 -2
  44. package/dist/{task-queue-D3PLY59C.js → task-queue-iuDAqfZg.js} +3 -4
  45. package/dist/{task-runner-BMl2aM2v.js → task-runner-S3QtH38c.js} +381 -12
  46. package/dist/{thread-state-CAR6gdAm.js → thread-state-C_arVuaN.js} +5 -5
  47. package/dist/{turn-failure-response-CZyoUMkD.js → turn-failure-response-DarwGYgC.js} +9 -10
  48. package/dist/{turn-lifecycle-DPDHKi2U.js → turn-lifecycle-CdiIejXH.js} +1 -1
  49. package/dist/{turn-session-routing-Jkmmxpp-.js → turn-session-routing-DyLGd_wU.js} +1 -1
  50. package/dist/{validation-BcGGxOa6.js → validation-BMig74Zp.js} +1 -1
  51. package/dist/{version-DYcuOFQb.js → version-lhQSfLjx.js} +1 -1
  52. package/dist/version.js +1 -1
  53. package/dist/web-authorization-r2lKYKJ2.js +162 -0
  54. package/dist/web-input-BU-Fu7iq.js +7784 -0
  55. package/dist/{reporting-window-DbUqng0P.js → web-message-id-xPI_EFSC.js} +11 -1
  56. package/dist/{work-Bm90pR9P.js → work-B9koS8sW.js} +7 -8
  57. package/dist/{worker-BvHr6JhE.js → worker-C_iJSRgG.js} +5 -6
  58. package/package.json +5 -4
  59. package/dist/execution-stats-CR9CYpyj.js +0 -373
  60. package/dist/history-yaSjGMD_.d.ts +0 -65
  61. package/dist/job-queue-D2SiTrnt.js +0 -63
  62. package/dist/short-title-3wYH3ipl.js +0 -71
  63. package/dist/stats-DawHjcTw.js +0 -2758
  64. package/dist/web-authorization-B09B8A8R.js +0 -38
  65. package/dist/web-input-CGE58TpK.js +0 -899
@@ -1,144 +1,24 @@
1
- import { C as resolvePluginOAuthAccount, D as lookupSlackUserProfile, V as getMcpProviderErrorAttributes, _ as putMcpStoredOAuthCredentials, at as parseOAuthStatePayload, b as getConversationPendingAuth, d as deleteMcpAuthSession, g as getMcpStoredOAuthCredentials, h as getMcpAuthSession, it as formatProviderLabel, mt as postSlackMessage, ot as resolveBaseUrl, u as finalizeMcpAuthorization, vt as createUserTokenStore } from "./agent-runner-Cad1RtWn.js";
2
- import { m as escapeXml } from "./client-ihmkx60d.js";
3
- import { d as logException, h as runBestEffort, p as logWarn } from "./logging-CcTvYQ8A.js";
4
- import { n as botConfig, o as getRuntimeMetadata } from "./config-DMg679BW.js";
5
- import { g as parseSlackUserId } from "./context-Bplcgypl.js";
6
- import { Jt as getSqlExecutor, U as getSlackClient, Wt as getConversationEventStore, ln as upsertIdentity, un as upsertLinkedIdentity } from "./agent-hooks-CRuRcOg9.js";
1
+ import { Cn as createUserTokenStore, T as lookupSlackUserProfile, _ as putMcpStoredOAuthCredentials, d as deleteMcpAuthSession, dn as resolveBaseUrl, ft as getMcpProviderErrorAttributes, g as getMcpStoredOAuthCredentials, h as getMcpAuthSession, ln as formatProviderLabel, u as finalizeMcpAuthorization, un as parseOAuthStatePayload, x as resolvePluginOAuthAccount, yn as postSlackMessage } from "./agent-runner-BGDSjciH.js";
2
+ import { m as escapeXml } from "./client-Pcxo3lGn.js";
3
+ import { d as logException, h as runBestEffort, p as logWarn } from "./logging-BPBx6WF-.js";
4
+ import { n as botConfig, o as getRuntimeMetadata } from "./config-CYvEow1F.js";
5
+ import { g as parseSlackUserId } from "./context-0Et9iVSB.js";
6
+ import { U as getSlackClient, en as getSqlExecutor, hn as upsertLinkedIdentity, mn as upsertIdentity } from "./agent-hooks-bEwEJhlg.js";
7
7
  import { i as homeDir } from "./package-discovery-7a9YqLhE.js";
8
- import { n as buildOAuthTokenRequest, r as parseOAuthTokenResponse, u as hasRequiredOAuthScope } from "./registry-C8I4IejN.js";
9
- import { n as pluginCatalogRuntime } from "./catalog-runtime-pv4grNNb.js";
10
- import { t as discoverSkills } from "./skills-DUcDEgDI.js";
11
- import { B as recordAuthorizationCompleted, n as loadTurnCheckpoint, o as failTurnRecord, s as getTurnRecord, z as recordAuthenticationLinked } from "./checkpoint-6fkAdB3g.js";
12
- import { E as acquireActiveLock, w as getStateAdapter } from "./profile-CV97YuiL.js";
13
- import { Pt as requestConversationWork, wt as ensureConversationWake } from "./stats-DawHjcTw.js";
14
- import { t as getVercelConversationWorkQueue } from "./vercel-queue-DIkVcfK4.js";
15
- import { r as getPersistedThreadState, s as coerceThreadConversationState } from "./thread-state-CAR6gdAm.js";
16
- import { n as resolveTurnSessionRouting } from "./turn-session-routing-Jkmmxpp-.js";
8
+ import { n as buildOAuthTokenRequest, r as parseOAuthTokenResponse, u as hasRequiredOAuthScope } from "./registry-DM5aMhjm.js";
9
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-Cw9V2jpn.js";
10
+ import { t as discoverSkills } from "./skills-CAI5s___.js";
11
+ import { B as recordAuthorizationCompleted, s as getTurnRecord, z as recordAuthenticationLinked } from "./checkpoint-oZYD3-Ar.js";
12
+ import { E as acquireActiveLock, w as getStateAdapter } from "./profile-upzC-wN1.js";
13
+ import { i as getConversationPendingAuth } from "./pending-auth-CHUjr_6d.js";
14
+ import { r as getPersistedThreadState, s as coerceThreadConversationState } from "./thread-state-C_arVuaN.js";
15
+ import { n as deleteWebAuthorization, o as wakeAuthorizedTurn, s as wakePausedTurn } from "./web-authorization-r2lKYKJ2.js";
17
16
  import { n as relayLocalOAuthCallback } from "./oauth-relay-CdCnu80W.js";
18
- import { n as deleteWebAuthorization } from "./web-authorization-B09B8A8R.js";
19
17
  import path from "node:path";
20
18
  import { z } from "zod";
21
19
  import { createHmac, createSecretKey, timingSafeEqual } from "node:crypto";
22
20
  import { pluginStoredTokensSchema } from "@sentry/junior-plugin-api";
23
21
  import fs from "node:fs";
24
- //#region src/chat/task-execution/authorized-turn.ts
25
- /**
26
- * OAuth callbacks save readiness, not agent history. The conversation worker
27
- * consumes this event under its lease before it resumes the paused Turn.
28
- */
29
- const authorizationSchema = z.object({
30
- kind: z.enum(["mcp", "plugin"]),
31
- provider: z.string().min(1),
32
- actorId: z.string().min(1),
33
- authorizationId: z.string().min(1),
34
- authSessionId: z.string().optional(),
35
- scope: z.string().optional(),
36
- configuration: z.record(z.string(), z.unknown()).optional(),
37
- toolChannelId: z.string().optional()
38
- });
39
- function authorizationKey(turn) {
40
- return `turn:${turn.turnId}:authorization:${turn.version}`;
41
- }
42
- /** Save authorization for this parked boundary without changing model history. */
43
- async function recordTurnAuthorization(args) {
44
- const turn = await getTurnRecord(args.conversationId, args.turnId);
45
- if (!turn || turn.state !== "paused" || turn.resumeReason !== "auth") return;
46
- await getConversationEventStore().append(args.conversationId, [{
47
- idempotencyKey: authorizationKey(turn),
48
- createdAtMs: Date.now(),
49
- data: {
50
- type: "structured_event",
51
- namespace: "junior",
52
- name: "turn_authorized",
53
- version: 1,
54
- turnId: turn.turnId,
55
- content: authorizationSchema.parse(args)
56
- }
57
- }], { activity: "preserve" });
58
- return {
59
- conversationId: args.conversationId,
60
- destination: args.destination,
61
- turnId: turn.turnId,
62
- expectedVersion: turn.version
63
- };
64
- }
65
- /** Read authorization for the exact pause; a later auth pause needs its own callback. */
66
- async function getTurnAuthorization(turn) {
67
- const event = await getConversationEventStore().loadByIdempotencyKey(turn.conversationId, authorizationKey(turn));
68
- if (event?.data.type !== "structured_event") return void 0;
69
- return authorizationSchema.parse(event.data.content);
70
- }
71
- //#endregion
72
- //#region src/chat/task-execution/turn-wake.ts
73
- /** Build the worker input for a paused turn. */
74
- async function getPausedTurnRequest(args) {
75
- const turn = (await loadTurnCheckpoint({
76
- conversationId: args.conversationId,
77
- turnId: args.turnId
78
- })).record;
79
- if (!turn || turn.state !== "paused" || turn.resumeReason !== "timeout" && turn.resumeReason !== "yield" && turn.resumeReason !== "retry" && !(turn.resumeReason === "auth" && await getTurnAuthorization(turn)) || turn.resumeReason === "timeout" && turn.sliceId < 2) return;
80
- let routing;
81
- try {
82
- routing = await resolveTurnSessionRouting({
83
- conversationId: args.conversationId,
84
- conversationStore: args.conversationStore
85
- });
86
- } catch (error) {
87
- await failTurnRecord({
88
- conversationId: args.conversationId,
89
- expectedVersion: turn.version,
90
- turnId: args.turnId,
91
- errorMessage: error instanceof Error ? error.message : String(error)
92
- });
93
- return;
94
- }
95
- return {
96
- conversationId: args.conversationId,
97
- destination: routing.destination,
98
- turnId: args.turnId,
99
- expectedVersion: turn.version
100
- };
101
- }
102
- /** Wake the conversation worker for a paused turn. */
103
- async function wakePausedTurn(request, options = {}) {
104
- const nowMs = options.nowMs ?? Date.now();
105
- await requestConversationWork({
106
- conversationId: request.conversationId,
107
- destination: request.destination,
108
- nowMs,
109
- state: options.state
110
- });
111
- const queue = options.queue ?? getVercelConversationWorkQueue();
112
- await ensureConversationWake({
113
- conversationId: request.conversationId,
114
- idempotencyKey: [
115
- "agent-continue",
116
- request.conversationId,
117
- request.turnId,
118
- request.expectedVersion,
119
- nowMs
120
- ].join(":"),
121
- nowMs,
122
- queue,
123
- state: options.state
124
- });
125
- }
126
- /** Create paused Turn operations for one app. */
127
- function createPausedTurns(options = {}) {
128
- return {
129
- get: (args) => getPausedTurnRequest({
130
- ...args,
131
- conversationStore: options.conversationStore
132
- }),
133
- wake: (request) => wakePausedTurn(request, options)
134
- };
135
- }
136
- /** Record completed authorization and wake the sole execution owner. */
137
- async function wakeAuthorizedTurn(args, queue) {
138
- const request = await recordTurnAuthorization(args);
139
- if (request) await wakePausedTurn(request, { queue });
140
- }
141
- //#endregion
142
22
  //#region src/handlers/oauth-html.ts
143
23
  /** Build pre-escaped callback HTML with the shared response security policy. */
144
24
  function htmlCallbackResponse(title, message, status, options = {}) {
@@ -937,4 +817,4 @@ async function receiveLocalOAuthCredential(request) {
937
817
  return new Response(null, { status: 204 });
938
818
  }
939
819
  //#endregion
940
- export { GET$1 as a, wakePausedTurn as c, publishAppHomeView as i, getTurnAuthorization as l, syncLocalOAuthCredential as n, createPausedTurns as o, GET as r, getPausedTurnRequest as s, receiveLocalOAuthCredential as t };
820
+ export { GET$1 as a, publishAppHomeView as i, syncLocalOAuthCredential as n, GET as r, receiveLocalOAuthCredential as t };
@@ -1,5 +1,5 @@
1
1
  import { g as startSpanManual } from "./sentry-CgWZM_kV.js";
2
- import "./config-DMg679BW.js";
2
+ import "./config-CYvEow1F.js";
3
3
  import { n as juniorDestinations, r as timestamptz } from "./destinations-BeBiJeEM.js";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { getTableColumns, sql } from "drizzle-orm";
@@ -0,0 +1,127 @@
1
+ import { z } from "zod";
2
+ import "@sentry/junior-plugin-api";
3
+ //#region src/chat/attachments/input.d.ts
4
+ /** Bound JSON image input below the hosting platform's request size limit. */
5
+ declare const MAX_INPUT_IMAGE_BYTES: number;
6
+ declare const MAX_INPUT_IMAGES = 3;
7
+ /** Image bytes accepted with a web message, never stored in its mailbox row. */
8
+ declare const inputImageSchema: z.ZodObject<{
9
+ filename: z.ZodString;
10
+ contentType: z.ZodEnum<{
11
+ "image/png": "image/png";
12
+ "image/jpeg": "image/jpeg";
13
+ "image/gif": "image/gif";
14
+ "image/webp": "image/webp";
15
+ }>;
16
+ data: z.ZodString;
17
+ }, z.core.$strict>;
18
+ type InputImage = z.output<typeof inputImageSchema>;
19
+ /** Safe attachment facts shared by mailbox input and transcript messages. */
20
+ declare const messageAttachmentSchema: z.ZodObject<{
21
+ id: z.ZodString;
22
+ filename: z.ZodString;
23
+ contentType: z.ZodString;
24
+ bytes: z.ZodNumber;
25
+ }, z.core.$strict>;
26
+ type MessageAttachment = z.output<typeof messageAttachmentSchema>;
27
+ //#endregion
28
+ //#region src/chat/conversations/cards.d.ts
29
+ /** Built-in response types accepted by Message storage and delivery. */
30
+ declare const messageCardSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
31
+ kind: z.ZodLiteral<"automation">;
32
+ id: z.ZodString;
33
+ title: z.ZodString;
34
+ url: z.ZodNullable<z.ZodString>;
35
+ instruction: z.ZodString;
36
+ trigger: z.ZodString;
37
+ warning: z.ZodNullable<z.ZodString>;
38
+ }, z.core.$strict>, z.ZodObject<{
39
+ kind: z.ZodLiteral<"object">;
40
+ key: z.ZodString;
41
+ label: z.ZodString;
42
+ objectType: z.ZodEnum<{
43
+ code_change: "code_change";
44
+ task: "task";
45
+ automation: "automation";
46
+ item: "item";
47
+ }>;
48
+ title: z.ZodString;
49
+ url: z.ZodNullable<z.ZodURL>;
50
+ description: z.ZodOptional<z.ZodString>;
51
+ status: z.ZodOptional<z.ZodString>;
52
+ trigger: z.ZodOptional<z.ZodString>;
53
+ warning: z.ZodOptional<z.ZodString>;
54
+ displayType: z.ZodOptional<z.ZodString>;
55
+ sourceUpdatedAt: z.ZodOptional<z.ZodISODateTime>;
56
+ facts: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
57
+ type: z.ZodLiteral<"code_change">;
58
+ author: z.ZodOptional<z.ZodString>;
59
+ sourceBranch: z.ZodOptional<z.ZodString>;
60
+ targetBranch: z.ZodOptional<z.ZodString>;
61
+ reviewers: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
+ review: z.ZodOptional<z.ZodEnum<{
63
+ required: "required";
64
+ approved: "approved";
65
+ changes_requested: "changes_requested";
66
+ }>>;
67
+ checks: z.ZodOptional<z.ZodObject<{
68
+ passed: z.ZodNumber;
69
+ failed: z.ZodNumber;
70
+ pending: z.ZodNumber;
71
+ }, z.core.$strict>>;
72
+ mergeable: z.ZodOptional<z.ZodBoolean>;
73
+ changedFiles: z.ZodOptional<z.ZodNumber>;
74
+ additions: z.ZodOptional<z.ZodNumber>;
75
+ deletions: z.ZodOptional<z.ZodNumber>;
76
+ }, z.core.$strict>, z.ZodObject<{
77
+ type: z.ZodLiteral<"task">;
78
+ assignees: z.ZodOptional<z.ZodArray<z.ZodString>>;
79
+ priority: z.ZodOptional<z.ZodString>;
80
+ project: z.ZodOptional<z.ZodString>;
81
+ cycle: z.ZodOptional<z.ZodString>;
82
+ dueDate: z.ZodOptional<z.ZodISODate>;
83
+ labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
84
+ }, z.core.$strict>, z.ZodObject<{
85
+ type: z.ZodLiteral<"deployment">;
86
+ project: z.ZodOptional<z.ZodString>;
87
+ environment: z.ZodOptional<z.ZodString>;
88
+ revision: z.ZodOptional<z.ZodString>;
89
+ branch: z.ZodOptional<z.ZodString>;
90
+ }, z.core.$strict>], "type">>;
91
+ plugin: z.ZodString;
92
+ }, z.core.$strict>], "kind">;
93
+ type MessageCard = z.output<typeof messageCardSchema>;
94
+ /** Render each built-in card with its own text format. */
95
+ declare function messageCardText(card: MessageCard): string;
96
+ //#endregion
97
+ //#region src/chat/conversations/history.d.ts
98
+ /** Where a failed turn stopped. */
99
+ declare const conversationTurnFailureCodeSchema: z.ZodEnum<{
100
+ agent_run_failed: "agent_run_failed";
101
+ delivery_failed: "delivery_failed";
102
+ model_execution_failed: "model_execution_failed";
103
+ persistence_failed: "persistence_failed";
104
+ }>;
105
+ /**
106
+ * Why a failed turn stopped.
107
+ * Values are fixed labels only. Do not store raw exception text.
108
+ */
109
+ declare const conversationTurnFailureReasonSchema: z.ZodEnum<{
110
+ unknown: "unknown";
111
+ capacity: "capacity";
112
+ auth: "auth";
113
+ permission: "permission";
114
+ rate_limit: "rate_limit";
115
+ timeout: "timeout";
116
+ network: "network";
117
+ server: "server";
118
+ invalid_request: "invalid_request";
119
+ invalid_response: "invalid_response";
120
+ quota: "quota";
121
+ content_policy: "content_policy";
122
+ empty_output: "empty_output";
123
+ tool_errors: "tool_errors";
124
+ suppressed_output: "suppressed_output";
125
+ }>;
126
+ //#endregion
127
+ export { InputImage as a, MessageAttachment as c, messageCardText as i, conversationTurnFailureReasonSchema as n, MAX_INPUT_IMAGES as o, MessageCard as r, MAX_INPUT_IMAGE_BYTES as s, conversationTurnFailureCodeSchema as t };
@@ -0,0 +1,82 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
2
+ import { j as storeAttachment, k as readLiveAttachment } from "./agent-runner-BGDSjciH.js";
3
+ import { en as getSqlExecutor } from "./agent-hooks-bEwEJhlg.js";
4
+ import "./conversation-BnhOMfEB.js";
5
+ //#region src/chat/attachments/images.ts
6
+ var images_exports = /* @__PURE__ */ __exportAll({
7
+ decodeInputImages: () => decodeInputImages,
8
+ loadInputImages: () => loadInputImages,
9
+ storeInputImages: () => storeInputImages
10
+ });
11
+ function matchesImageType(data, contentType) {
12
+ switch (contentType) {
13
+ case "image/png": return data.subarray(0, 8).equals(Buffer.from([
14
+ 137,
15
+ 80,
16
+ 78,
17
+ 71,
18
+ 13,
19
+ 10,
20
+ 26,
21
+ 10
22
+ ]));
23
+ case "image/jpeg": return data[0] === 255 && data[1] === 216 && data[2] === 255;
24
+ case "image/gif": return ["GIF87a", "GIF89a"].includes(data.toString("ascii", 0, 6));
25
+ case "image/webp": return data.toString("ascii", 0, 4) === "RIFF" && data.toString("ascii", 8, 12) === "WEBP";
26
+ }
27
+ }
28
+ /** Check declared image types against file signatures before storing uploads. */
29
+ function decodeInputImages(images) {
30
+ const files = images.map((image) => {
31
+ const data = Buffer.from(image.data, "base64");
32
+ if (!matchesImageType(data, image.contentType) || data.toString("base64") !== image.data) throw new Error("Use PNG, JPEG, GIF, or WebP image files.");
33
+ return {
34
+ data,
35
+ bytes: data.byteLength,
36
+ filename: image.filename,
37
+ mimeType: image.contentType,
38
+ path: image.filename
39
+ };
40
+ });
41
+ if (files.reduce((sum, file) => sum + file.bytes, 0) > 3145728) throw new Error("Images must total 3 MB or less.");
42
+ return files;
43
+ }
44
+ /** Store image bytes before accepting a message into the mailbox. */
45
+ async function storeInputImages(args) {
46
+ return await Promise.all(args.files.map(async (file) => {
47
+ return {
48
+ id: (await storeAttachment({
49
+ conversationId: args.conversationId,
50
+ db: getSqlExecutor(),
51
+ file,
52
+ storage: args.storage
53
+ })).id,
54
+ filename: file.filename,
55
+ contentType: file.mimeType,
56
+ bytes: file.bytes
57
+ };
58
+ }));
59
+ }
60
+ /** Load stored images for model input. */
61
+ async function loadInputImages(args) {
62
+ return await Promise.all(args.attachments.map(async (ref) => {
63
+ const attachment = await readLiveAttachment({
64
+ attachmentId: ref.id,
65
+ conversationId: args.conversationId,
66
+ db: getSqlExecutor()
67
+ });
68
+ if (!attachment || attachment.storageProvider !== args.storage.provider) throw new Error("Input image is no longer available.");
69
+ const body = await args.storage.get(attachment.storageKey);
70
+ if (!body) throw new Error("Input image contents are unavailable.");
71
+ const data = Buffer.from(await new Response(body).arrayBuffer());
72
+ if (data.byteLength !== attachment.bytes) throw new Error("Input image size does not match stored metadata.");
73
+ return {
74
+ attachmentId: ref.id,
75
+ filename: attachment.filename,
76
+ mediaType: attachment.contentType,
77
+ data
78
+ };
79
+ }));
80
+ }
81
+ //#endregion
82
+ export { images_exports as n, storeInputImages as r, decodeInputImages as t };
@@ -1,6 +1,6 @@
1
- import { N as getDeploymentServiceVersion, P as getDeploymentTelemetryAttributes } from "./logging-CcTvYQ8A.js";
1
+ import { N as getDeploymentServiceVersion, P as getDeploymentTelemetryAttributes } from "./logging-BPBx6WF-.js";
2
2
  import { _ as vercelAIIntegration, a as getClient, b as withStreamedSpan, c as init, o as getGlobalScope } from "./sentry-CgWZM_kV.js";
3
- import { n as getCurrentConversationPrivacy } from "./conversation-privacy-ZYy05Y3q.js";
3
+ import { n as getCurrentConversationPrivacy } from "./conversation-privacy-hQmyZbOC.js";
4
4
  import { t as consumePrivateTraceResultMarker } from "./private-trace-result-BLvBjy_e.js";
5
5
  //#region src/chat/sentry-payload-filter.ts
6
6
  const PAYLOAD_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set([
@@ -1,5 +1,7 @@
1
+ import { a as getChatConfig } from "./config-CYvEow1F.js";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
1
3
  import { z } from "zod";
2
- import { createHmac, timingSafeEqual } from "node:crypto";
4
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
3
5
  import { QueueClient } from "@vercel/queue";
4
6
  /** Validate the v2 conversation work hint sent through Vercel Queue. */
5
7
  const conversationQueueMessageSchema = z.object({
@@ -21,6 +23,24 @@ function isConversationQueueMessageRejectedError(error) {
21
23
  return error instanceof ConversationQueueMessageRejectedError;
22
24
  }
23
25
  //#endregion
26
+ //#region src/chat/runtime/request-deadline.ts
27
+ const requestDeadlineStorage = new AsyncLocalStorage();
28
+ function createTurnRequestDeadline(startedAtMs) {
29
+ return {
30
+ startedAtMs,
31
+ deadlineAtMs: startedAtMs + Math.max(1, getChatConfig().functionMaxDurationSeconds * 1e3 - 2e4)
32
+ };
33
+ }
34
+ /** Return the host request deadline inherited by the current async turn. */
35
+ function getTurnRequestDeadline() {
36
+ return requestDeadlineStorage.getStore();
37
+ }
38
+ /** Run work with one host request deadline shared by nested queued turns. */
39
+ function runWithTurnRequestDeadline(callback, startedAtMs = Date.now()) {
40
+ if (requestDeadlineStorage.getStore()) return callback();
41
+ return requestDeadlineStorage.run(createTurnRequestDeadline(startedAtMs), callback);
42
+ }
43
+ //#endregion
24
44
  //#region src/chat/vercel-queue-client.ts
25
45
  function defaultQueueClientOptions() {
26
46
  if (process.env.VERCEL_DEPLOYMENT_ID?.trim()) return {};
@@ -164,4 +184,43 @@ function getVercelConversationWorkQueue() {
164
184
  return defaultQueue;
165
185
  }
166
186
  //#endregion
167
- export { signQueueMessage as a, ConversationQueueMessageRejectedError as c, QUEUE_SIGNATURE_MAX_AGE_MS as i, conversationQueueMessageSchema as l, resolveConversationWorkQueueTopic as n, verifyQueueMessage as o, verifyConversationQueueMessage as r, createVercelQueueClient as s, getVercelConversationWorkQueue as t, isConversationQueueMessageRejectedError as u };
187
+ //#region src/chat/sandbox/snapshot/job-queue.ts
188
+ /** Send Workspace snapshot build messages. */
189
+ const SIGNATURE_CONTEXT = "junior.workspace_snapshot_queue.v1";
190
+ const SIGNATURE_VERSION = "v1";
191
+ const WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC = "junior_workspace_snapshots";
192
+ const workspaceSnapshotJobSign = {
193
+ context: SIGNATURE_CONTEXT,
194
+ schema: z.object({
195
+ workspaceId: z.string().uuid(),
196
+ profileHash: z.string().min(1)
197
+ }).strict(),
198
+ signatureVersion: SIGNATURE_VERSION,
199
+ parts: (message) => [message.workspaceId, message.profileHash]
200
+ };
201
+ function jobId(message) {
202
+ return `workspace-snapshot_${createHash("sha256").update(message.workspaceId).update("\0").update(message.profileHash).digest("hex").slice(0, 32)}`;
203
+ }
204
+ /** Sign a Workspace snapshot job for tests and local checks. */
205
+ function signWorkspaceSnapshotJobMessage(message, nowMs = Date.now()) {
206
+ return signQueueMessage(workspaceSnapshotJobSign, message, nowMs);
207
+ }
208
+ /** Check that a recent queue message came from Junior. */
209
+ function verifyWorkspaceSnapshotJobMessage(value, nowMs = Date.now()) {
210
+ return verifyQueueMessage(workspaceSnapshotJobSign, value, nowMs);
211
+ }
212
+ async function send(message, idempotencyKey) {
213
+ const options = { retentionSeconds: QUEUE_SIGNATURE_MAX_AGE_MS / 1e3 };
214
+ if (idempotencyKey) options.idempotencyKey = idempotencyKey;
215
+ await createVercelQueueClient().send(WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC, signWorkspaceSnapshotJobMessage(message), options);
216
+ }
217
+ /** Send a job unless the same Workspace build already has one. */
218
+ async function sendWorkspaceSnapshotJob(message) {
219
+ await send(message, jobId(message));
220
+ }
221
+ /** Send the next job for a Workspace build that is still running. */
222
+ async function sendNextWorkspaceSnapshotJob(message) {
223
+ await send(message);
224
+ }
225
+ //#endregion
226
+ export { getVercelConversationWorkQueue as a, QUEUE_SIGNATURE_MAX_AGE_MS as c, createVercelQueueClient as d, getTurnRequestDeadline as f, isConversationQueueMessageRejectedError as g, conversationQueueMessageSchema as h, verifyWorkspaceSnapshotJobMessage as i, signQueueMessage as l, ConversationQueueMessageRejectedError as m, sendNextWorkspaceSnapshotJob as n, resolveConversationWorkQueueTopic as o, runWithTurnRequestDeadline as p, sendWorkspaceSnapshotJob as r, verifyConversationQueueMessage as s, WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC as t, verifyQueueMessage as u };
@@ -1,5 +1,5 @@
1
1
  import { d as setTag, f as setUser, h as startSpan, i as getActiveSpan, l as logger, n as captureMessage, p as spanToJSON, s as getTraceData, t as captureException, y as withScope } from "./sentry-CgWZM_kV.js";
2
- import { t as JUNIOR_VERSION } from "./version-DYcuOFQb.js";
2
+ import { t as JUNIOR_VERSION } from "./version-lhQSfLjx.js";
3
3
  import path from "node:path";
4
4
  import { styleText } from "node:util";
5
5
  import { ConfigError, configureSync, getConfig, getLogger } from "@logtape/logtape";
package/dist/nitro.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as JuniorDashboardOptions } from "./app-BbSD6EtD.js";
1
+ import { n as JuniorDashboardOptions } from "./app-CjRIKZb5.js";
2
2
  import { n as JuniorPluginSet } from "./plugins-BT2l4We3.js";
3
3
  //#region src/nitro.d.ts
4
4
  export type JuniorNitroDashboardOptions = JuniorDashboardOptions;
package/dist/nitro.js CHANGED
@@ -1,9 +1,8 @@
1
- import { A as JUNIOR_RETENTION_ROUTE, D as JUNIOR_HEARTBEAT_ROUTE, E as JUNIOR_HEARTBEAT_CRON_SCHEDULE, O as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, T as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE, j as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, k as JUNIOR_RETENTION_CRON_SCHEDULE } from "./logging-CcTvYQ8A.js";
1
+ import { A as JUNIOR_RETENTION_ROUTE, D as JUNIOR_HEARTBEAT_ROUTE, E as JUNIOR_HEARTBEAT_CRON_SCHEDULE, O as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, T as JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE, j as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, k as JUNIOR_RETENTION_CRON_SCHEDULE } from "./logging-BPBx6WF-.js";
2
2
  import { d as resolvePackageDir, t as discoverInstalledPluginPackageContent, u as isValidPackageName } from "./package-discovery-7a9YqLhE.js";
3
- import { n as resolveConversationWorkQueueTopic } from "./vercel-queue-DIkVcfK4.js";
4
- import { t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-D2SiTrnt.js";
3
+ import { o as resolveConversationWorkQueueTopic, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-AI0_QAgc.js";
5
4
  import { a as pluginRuntimeRegistrationsFromPluginSet, r as pluginCatalogConfigFromPluginSet } from "./plugins-egKWjgue.js";
6
- import { t as PLUGIN_TASK_QUEUE_TOPIC } from "./task-queue-D3PLY59C.js";
5
+ import { t as PLUGIN_TASK_QUEUE_TOPIC } from "./task-queue-iuDAqfZg.js";
7
6
  import { n as loadPluginSetFromModule, r as resolvePluginModule } from "./plugin-module-BKGOXca2.js";
8
7
  import path from "node:path";
9
8
  import { cpSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs";
@@ -1,4 +1,4 @@
1
- import { h as extractAssistantText } from "./checkpoint-6fkAdB3g.js";
1
+ import { h as extractAssistantText } from "./checkpoint-oZYD3-Ar.js";
2
2
  //#region src/chat/runtime/turn.ts
3
3
  /** Classified Slack turn failure carrying the owning Sentry capture outward. */
4
4
  var ConversationTurnBoundaryError = class extends Error {
@@ -1,5 +1,5 @@
1
- import { vt as createUserTokenStore } from "./agent-runner-Cad1RtWn.js";
2
- import { a as GET, n as syncLocalOAuthCredential, r as GET$1 } from "./credential-sync-DCB2SwnQ.js";
1
+ import { Cn as createUserTokenStore } from "./agent-runner-BGDSjciH.js";
2
+ import { a as GET, n as syncLocalOAuthCredential, r as GET$1 } from "./credential-sync-CUGbiiCM.js";
3
3
  import { createServer } from "node:http";
4
4
  //#region src/chat/local/oauth-callback-server.ts
5
5
  const LOCAL_OAUTH_TIMEOUT_MS = 6e5;
@@ -0,0 +1,59 @@
1
+ import { i as abandonTurnRecord } from "./checkpoint-oZYD3-Ar.js";
2
+ //#region src/chat/state/turn-id.ts
3
+ /** Build a stable turn identifier from a message ID. */
4
+ function buildDeterministicTurnId(messageId) {
5
+ return `turn_${messageId.replace(/[^a-zA-Z0-9_-]/g, "_")}`;
6
+ }
7
+ /** Build the stable visible assistant-message identity for one logical turn. */
8
+ function buildDeterministicAssistantMessageId(turnId) {
9
+ return `${turnId}:assistant:1`;
10
+ }
11
+ //#endregion
12
+ //#region src/chat/services/pending-auth.ts
13
+ const AUTH_LINK_REUSE_WINDOW_MS = 6e5;
14
+ const NON_REQUEST_SKIPPED_REASON_PREFIXES = ["directed_to_other_party:", "side_conversation:"];
15
+ function isSkippedNonRequest(reason) {
16
+ return NON_REQUEST_SKIPPED_REASON_PREFIXES.some((prefix) => reason?.startsWith(prefix));
17
+ }
18
+ /** Decide whether the same agent-run session can reuse its fresh auth link. */
19
+ function canReusePendingAuthLink(args) {
20
+ const { pendingAuth } = args;
21
+ if (!pendingAuth) return false;
22
+ return pendingAuth.kind === args.kind && pendingAuth.provider === args.provider && pendingAuth.actorId === args.actorId && pendingAuth.scope === args.scope && pendingAuth.sessionId === args.sessionId && pendingAuth.linkSentAtMs + AUTH_LINK_REUSE_WINDOW_MS > (args.nowMs ?? Date.now());
23
+ }
24
+ function getConversationPendingAuth(args) {
25
+ const pendingAuth = args.conversation.processing.pendingAuth;
26
+ if (!pendingAuth) return;
27
+ if (pendingAuth.kind !== args.kind || pendingAuth.provider !== args.provider || pendingAuth.actorId !== args.actorId || pendingAuth.scope !== args.scope) return;
28
+ return pendingAuth;
29
+ }
30
+ function clearPendingAuth(conversation, sessionId) {
31
+ if (!conversation.processing.pendingAuth) return;
32
+ if (sessionId && conversation.processing.pendingAuth.sessionId !== sessionId) return;
33
+ conversation.processing.pendingAuth = void 0;
34
+ }
35
+ /** Mark the prior blocked turn abandoned after a new auth attempt replaces it. */
36
+ async function abandonReplacedPendingAuth(args) {
37
+ if (args.previousPendingAuth && args.previousPendingAuth.sessionId !== args.nextPendingAuth.sessionId && args.conversationId) await abandonTurnRecord({
38
+ conversationId: args.conversationId,
39
+ turnId: args.previousPendingAuth.sessionId,
40
+ errorMessage: "Abandoned by a newer auth-blocked request in the same conversation."
41
+ });
42
+ }
43
+ /**
44
+ * Decide whether an auth callback still belongs to the latest real human
45
+ * request, ignoring bot-authored and passive bystander rows while treating
46
+ * failed human turns and opt-outs as newer freshness blockers.
47
+ */
48
+ function isPendingAuthLatestRequest(conversation, pendingAuth) {
49
+ for (let index = conversation.messages.length - 1; index >= 0; index -= 1) {
50
+ const message = conversation.messages[index];
51
+ if (message?.role !== "user") continue;
52
+ if (message.author?.isBot) continue;
53
+ if (isSkippedNonRequest(message.meta?.skippedReason)) continue;
54
+ return buildDeterministicTurnId(message.id) === pendingAuth.sessionId;
55
+ }
56
+ return false;
57
+ }
58
+ //#endregion
59
+ export { isPendingAuthLatestRequest as a, getConversationPendingAuth as i, canReusePendingAuthLink as n, buildDeterministicAssistantMessageId as o, clearPendingAuth as r, buildDeterministicTurnId as s, abandonReplacedPendingAuth as t };
@@ -1,7 +1,7 @@
1
- import { w as toOptionalTrimmed } from "./client-ihmkx60d.js";
2
- import { v as setSpanAttributes, y as setSpanStatus } from "./logging-CcTvYQ8A.js";
3
- import { a as getChatConfig } from "./config-DMg679BW.js";
4
- import { n as pluginCatalogRuntime } from "./catalog-runtime-pv4grNNb.js";
1
+ import { w as toOptionalTrimmed } from "./client-Pcxo3lGn.js";
2
+ import { v as setSpanAttributes, y as setSpanStatus } from "./logging-BPBx6WF-.js";
3
+ import { a as getChatConfig } from "./config-CYvEow1F.js";
4
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-Cw9V2jpn.js";
5
5
  import { createHash } from "node:crypto";
6
6
  import { createMemoryState } from "@chat-adapter/state-memory";
7
7
  import { createRedisState } from "@chat-adapter/state-redis";
@@ -1,4 +1,4 @@
1
- import { I as briefOutcomeStatusSchema, L as conversationBriefSchema, R as parseBriefInput } from "./conversation-Bygi39Xj.js";
1
+ import { H as conversationBriefSchema, U as parseBriefInput, V as briefOutcomeStatusSchema } from "./conversation-BnhOMfEB.js";
2
2
  import { z } from "zod";
3
3
  //#region src/chat/briefs/generate.ts
4
4
  const MAX_INPUT_CHARS = 6e4;
@@ -1,5 +1,5 @@
1
- import { f as logInfo, p as logWarn, v as setSpanAttributes } from "./logging-CcTvYQ8A.js";
2
- import { i as credentialUserSubjectId } from "./context-Bplcgypl.js";
1
+ import { f as logInfo, p as logWarn, v as setSpanAttributes } from "./logging-BPBx6WF-.js";
2
+ import { i as credentialUserSubjectId } from "./context-0Et9iVSB.js";
3
3
  import { n as normalizePluginPackageNames, o as pluginRoots, t as discoverInstalledPluginPackageContent } from "./package-discovery-7a9YqLhE.js";
4
4
  import path from "node:path";
5
5
  import { z } from "zod";
@@ -1,5 +1,5 @@
1
- import { v as setSpanAttributes, w as withSpan } from "./logging-CcTvYQ8A.js";
2
- import { N as SANDBOX_WORKSPACE_ROOT, k as sleep, r as isStale, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand } from "./profile-CV97YuiL.js";
1
+ import { v as setSpanAttributes, w as withSpan } from "./logging-BPBx6WF-.js";
2
+ import { N as SANDBOX_WORKSPACE_ROOT, k as sleep, r as isStale, t as create, u as isSandboxUnavailableError, v as getVercelSandboxCredentials, w as getStateAdapter, x as runNonInteractiveCommand } from "./profile-upzC-wN1.js";
3
3
  import { z } from "zod";
4
4
  import { FileSystem, Sandbox } from "@vercel/sandbox";
5
5
  //#region src/chat/sandbox/resources.ts
@@ -1,13 +1,13 @@
1
- import { C as withLogContext, b as setTags, d as logException } from "./logging-CcTvYQ8A.js";
2
- import { t as credentialContextForActor } from "./context-Bplcgypl.js";
3
- import { Kt as getConversationStore, Wt as getConversationEventStore } from "./agent-hooks-CRuRcOg9.js";
4
- import { M as messageCardText } from "./conversation-Bygi39Xj.js";
5
- import { A as commitAcceptedReply, B as recordAuthorizationCompleted, J as hydrateConversationMessages, P as loadProjection, Y as persistConversationMessages, at as markConversationMessage, et as buildConversationContext, lt as upsertConversationMessage, ot as normalizeConversationText, r as saveTurnCheckpoint, st as recordDeliveredAssistantMessage, u as persistWithRetry } from "./checkpoint-6fkAdB3g.js";
6
- import { _ as markTurnFailed, r as getAssistantReplyText, t as authorizationId, v as startActiveTurn } from "./oauth-authorization-BS4vPJmu.js";
7
- import { n as scheduleSessionCompletedPluginTasks, t as processPluginTask } from "./task-runner-BMl2aM2v.js";
8
- import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-DPDHKi2U.js";
9
- import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState, s as coerceThreadConversationState } from "./thread-state-CAR6gdAm.js";
10
- import { d as loadPendingMessageCards, i as completeAuthPauseTurn, l as buildDeliveredTurnStatePatch, t as finalizeFailedTurnReplyWithEvent } from "./turn-failure-response-CZyoUMkD.js";
1
+ import { C as withLogContext, b as setTags, d as logException } from "./logging-BPBx6WF-.js";
2
+ import { t as credentialContextForActor } from "./context-0Et9iVSB.js";
3
+ import { Qt as getConversationStore, Xt as getConversationEventStore } from "./agent-hooks-bEwEJhlg.js";
4
+ import { M as messageCardText } from "./conversation-BnhOMfEB.js";
5
+ import { A as commitAcceptedReply, B as recordAuthorizationCompleted, J as hydrateConversationMessages, P as loadProjection, Y as persistConversationMessages, ct as markConversationMessage, ft as upsertConversationMessage, lt as normalizeConversationText, r as saveTurnCheckpoint, rt as buildConversationContext, u as persistWithRetry, ut as recordDeliveredAssistantMessage } from "./checkpoint-oZYD3-Ar.js";
6
+ import { _ as markTurnFailed, r as getAssistantReplyText, t as authorizationId, v as startActiveTurn } from "./oauth-authorization-Cq1GaLIP.js";
7
+ import { n as scheduleSessionCompletedPluginTasks, t as processPluginTask } from "./task-runner-S3QtH38c.js";
8
+ import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-CdiIejXH.js";
9
+ import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState, s as coerceThreadConversationState } from "./thread-state-C_arVuaN.js";
10
+ import { d as loadPendingMessageCards, i as completeAuthPauseTurn, l as buildDeliveredTurnStatePatch, t as finalizeFailedTurnReplyWithEvent } from "./turn-failure-response-DarwGYgC.js";
11
11
  import { randomUUID } from "node:crypto";
12
12
  import { createLocalSource, localDestinationSchema } from "@sentry/junior-plugin-api";
13
13
  //#region src/chat/local/runner.ts