@sentry/junior 0.145.0 → 0.147.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 (171) hide show
  1. package/dist/{agent-hooks-L7D2BDVV.js → agent-hooks-HS6VGUPM.js} +10 -10
  2. package/dist/api/conversations/detail.d.ts +1 -0
  3. package/dist/api/conversations/event-list.d.ts +1 -0
  4. package/dist/api/schema/conversation.d.ts +4 -0
  5. package/dist/api/schema.js +1 -1
  6. package/dist/api.js +26 -22
  7. package/dist/app.js +285 -290
  8. package/dist/{catalog-runtime-QLAC4Q3W.js → catalog-runtime-M6ZTPYRV.js} +5 -5
  9. package/dist/chat/agent/prompt.d.ts +0 -2
  10. package/dist/chat/agent/request.d.ts +2 -5
  11. package/dist/chat/agent/resume.d.ts +0 -3
  12. package/dist/chat/agent/sandbox.d.ts +2 -2
  13. package/dist/chat/agent/skills.d.ts +0 -1
  14. package/dist/chat/agent/tools.d.ts +0 -3
  15. package/dist/chat/agent-dispatch/types.d.ts +2 -2
  16. package/dist/chat/capabilities/jr-rpc-command.d.ts +2 -2
  17. package/dist/chat/configuration/service.d.ts +5 -2
  18. package/dist/chat/configuration/sql.d.ts +9 -0
  19. package/dist/chat/configuration/types.d.ts +17 -13
  20. package/dist/chat/conversations/history.d.ts +3 -0
  21. package/dist/chat/conversations/message-search.d.ts +32 -0
  22. package/dist/chat/conversations/projection.d.ts +10 -0
  23. package/dist/chat/conversations/sql/message-search.d.ts +4 -0
  24. package/dist/chat/conversations/tool-source.d.ts +5 -0
  25. package/dist/chat/credentials/unlink-provider.d.ts +2 -1
  26. package/dist/chat/credentials/user-token-store.d.ts +2 -0
  27. package/dist/chat/db.d.ts +2 -2
  28. package/dist/chat/event-tasks/tool-support.d.ts +2 -0
  29. package/dist/chat/identities/sql.d.ts +8 -0
  30. package/dist/chat/logging.d.ts +2 -0
  31. package/dist/chat/mcp/auth-store.d.ts +0 -2
  32. package/dist/chat/mcp/oauth.d.ts +0 -2
  33. package/dist/chat/oauth-flow.d.ts +3 -1
  34. package/dist/chat/pi/client.d.ts +2 -0
  35. package/dist/chat/plugins/credential-hooks.d.ts +2 -0
  36. package/dist/chat/prompt.d.ts +0 -2
  37. package/dist/chat/resource-events/notification.d.ts +2 -1
  38. package/dist/chat/runtime/delivered-turn-state.d.ts +1 -4
  39. package/dist/chat/runtime/thread-state.d.ts +8 -11
  40. package/dist/chat/runtime/turn-input.d.ts +4 -2
  41. package/dist/chat/runtime/turn-preparation.d.ts +2 -4
  42. package/dist/chat/sandbox/command-result.d.ts +2 -0
  43. package/dist/chat/sandbox/egress/schemas.d.ts +6 -0
  44. package/dist/chat/scheduled-tasks/tool-support.d.ts +2 -0
  45. package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -0
  46. package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -0
  47. package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -0
  48. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -0
  49. package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -0
  50. package/dist/chat/services/mcp-auth-orchestration.d.ts +0 -3
  51. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  52. package/dist/chat/services/provider-default-config.d.ts +2 -2
  53. package/dist/chat/services/subscribed-decision.d.ts +3 -0
  54. package/dist/chat/services/subscribed-reply-policy.d.ts +1 -0
  55. package/dist/chat/services/turn-result.d.ts +0 -3
  56. package/dist/chat/services/turn-router.d.ts +3 -0
  57. package/dist/chat/slack/assistant-thread/lifecycle.d.ts +0 -1
  58. package/dist/chat/slack/assistant-thread/title.d.ts +0 -3
  59. package/dist/chat/slack/dispatch-turn.d.ts +1 -1
  60. package/dist/chat/slack/message/attachments.d.ts +2 -0
  61. package/dist/chat/slack/message/blocks.d.ts +2 -0
  62. package/dist/chat/slack/message/content.d.ts +18 -0
  63. package/dist/chat/slack/message/identity.d.ts +7 -0
  64. package/dist/chat/slack/tools/canvas/context.d.ts +0 -10
  65. package/dist/chat/slack/tools/canvas/create.d.ts +2 -0
  66. package/dist/chat/slack/tools/canvas/edit.d.ts +2 -0
  67. package/dist/chat/slack/tools/canvas/read.d.ts +2 -0
  68. package/dist/chat/slack/tools/canvas/write.d.ts +2 -0
  69. package/dist/chat/slack/tools/channel-list-messages.d.ts +2 -0
  70. package/dist/chat/slack/tools/{conversation-search.d.ts → conversation-message-search.d.ts} +23 -14
  71. package/dist/chat/slack/tools/list/add-items.d.ts +4 -1
  72. package/dist/chat/slack/tools/list/api.d.ts +8 -1
  73. package/dist/chat/slack/tools/list/create.d.ts +2 -0
  74. package/dist/chat/slack/tools/list/get-items.d.ts +5 -3
  75. package/dist/chat/slack/tools/list/update-item.d.ts +5 -1
  76. package/dist/chat/slack/tools/message-add-reaction.d.ts +2 -0
  77. package/dist/chat/slack/tools/public-search.d.ts +2 -0
  78. package/dist/chat/slack/tools/send-files.d.ts +2 -0
  79. package/dist/chat/slack/tools/thread-read.d.ts +2 -0
  80. package/dist/chat/slack/vision-cache.d.ts +5 -0
  81. package/dist/chat/state/conversation.d.ts +4 -5
  82. package/dist/chat/task-execution/checkpoint.d.ts +1 -3
  83. package/dist/chat/task-execution/turn-cursor.d.ts +0 -9
  84. package/dist/chat/tool-support/structured-result.d.ts +1 -0
  85. package/dist/chat/tool-support/timed-out-tool-result.d.ts +11 -0
  86. package/dist/chat/tools/create-event-task.d.ts +2 -0
  87. package/dist/chat/tools/delete-event-task.d.ts +2 -0
  88. package/dist/chat/tools/handoff/tool.d.ts +2 -0
  89. package/dist/chat/tools/list-event-tasks.d.ts +2 -0
  90. package/dist/chat/tools/list-resource-event-subscriptions.d.ts +2 -0
  91. package/dist/chat/tools/runtime/report-progress.d.ts +2 -0
  92. package/dist/chat/tools/runtime/spawn-agent.d.ts +2 -0
  93. package/dist/chat/tools/{query-conversation-events.d.ts → search-conversation-events.d.ts} +5 -3
  94. package/dist/chat/tools/search-resource-event-types.d.ts +2 -0
  95. package/dist/chat/tools/search-tools.d.ts +2 -0
  96. package/dist/chat/tools/skill/load-skill.d.ts +2 -0
  97. package/dist/chat/tools/skill/search-mcp-tools.d.ts +2 -0
  98. package/dist/chat/tools/stop-watching-resources.d.ts +2 -0
  99. package/dist/chat/tools/system-time.d.ts +2 -0
  100. package/dist/chat/tools/types.d.ts +0 -6
  101. package/dist/chat/tools/update-event-task.d.ts +2 -0
  102. package/dist/chat/tools/user-lookup.d.ts +29 -0
  103. package/dist/chat/tools/watch-resource-events.d.ts +2 -0
  104. package/dist/chat/tools/web/fetch-tool.d.ts +2 -0
  105. package/dist/chat/tools/web/image-generate.d.ts +2 -0
  106. package/dist/chat/tools/web/search.d.ts +2 -0
  107. package/dist/{chunk-PJ4NMVQB.js → chunk-34GS7B6L.js} +2 -2
  108. package/dist/{chunk-2LWPFSB4.js → chunk-4LJO56OJ.js} +9 -1
  109. package/dist/{chunk-QJBDABQA.js → chunk-6H5SZR24.js} +16 -20
  110. package/dist/{chunk-LVVSIMBB.js → chunk-745QJ3ZA.js} +1 -1
  111. package/dist/{chunk-64SBYW2O.js → chunk-7A4M7PCV.js} +613 -561
  112. package/dist/{chunk-XFKIRN3Q.js → chunk-7NVJVJID.js} +4 -3
  113. package/dist/{chunk-FUBRJA5F.js → chunk-7UQIVT6G.js} +13 -6
  114. package/dist/{chunk-ZIAMN2UW.js → chunk-AIOK6LAG.js} +40 -513
  115. package/dist/{chunk-EIX2LQ6L.js → chunk-AVOCH2Z5.js} +3 -3
  116. package/dist/{chunk-GUWLDMGF.js → chunk-AVZDSUFB.js} +4 -4
  117. package/dist/{chunk-2XET6PKP.js → chunk-AYU72WO7.js} +102 -73
  118. package/dist/chunk-AZ7EAOBE.js +566 -0
  119. package/dist/{chunk-DXEQAIUV.js → chunk-CSZINQJ2.js} +1 -1
  120. package/dist/{chunk-HLOUZC5C.js → chunk-CWP5RHVX.js} +4 -4
  121. package/dist/{chunk-DS3J6WGY.js → chunk-DLDRQHG5.js} +1 -1
  122. package/dist/{chunk-27TEJTZO.js → chunk-DU74WPIC.js} +55 -37
  123. package/dist/{chunk-YD54Q45G.js → chunk-EFLJ2WJH.js} +6 -4
  124. package/dist/{chunk-CD2XFGYQ.js → chunk-GGB4WL5A.js} +1 -1
  125. package/dist/{chunk-GDV5LXRA.js → chunk-IIOOO4FQ.js} +1 -1
  126. package/dist/{chunk-SIN3MXH6.js → chunk-JUUKWRBE.js} +1 -1
  127. package/dist/{chunk-VTDMB7XX.js → chunk-K4SZAP3K.js} +1 -1
  128. package/dist/{chunk-QUG4JSZK.js → chunk-ORO3PWKQ.js} +1 -1
  129. package/dist/{chunk-RUSS62EN.js → chunk-PVNG6UMU.js} +3 -3
  130. package/dist/{chunk-I47UGQPJ.js → chunk-Q4R73I43.js} +365 -206
  131. package/dist/{chunk-JTGS3ZZE.js → chunk-RXBVB2JM.js} +1 -1
  132. package/dist/{chunk-TZRXYWRE.js → chunk-SGZO7UWH.js} +2 -2
  133. package/dist/{chunk-JLMVCNXL.js → chunk-SVHUEHUL.js} +1 -0
  134. package/dist/{chunk-B46ZMVOV.js → chunk-X5UY34KT.js} +6 -5
  135. package/dist/{chunk-5PNPQYTO.js → chunk-YBVXBNSV.js} +2 -2
  136. package/dist/{chunk-HISR3DTV.js → chunk-YEO3VX72.js} +10 -25
  137. package/dist/{chunk-ZIMRGFYL.js → chunk-YHDERDRO.js} +7 -6
  138. package/dist/{chunk-WF5HVH3M.js → chunk-YNTTROJT.js} +1 -1
  139. package/dist/{chunk-2UH3JI64.js → chunk-YSB2N563.js} +87 -34
  140. package/dist/{chunk-ZYAJMESY.js → chunk-Z4YU7Z4L.js} +3 -2
  141. package/dist/cli/chat.js +32 -32
  142. package/dist/cli/check.js +6 -6
  143. package/dist/cli/plugins.js +13 -13
  144. package/dist/cli/snapshot-create.js +9 -9
  145. package/dist/cli/upgrade.js +7 -7
  146. package/dist/db/schema/location-configurations.d.ts +127 -0
  147. package/dist/db/schema.d.ts +128 -1
  148. package/dist/{db-62PW6LM3.js → db-CSEW4RII.js} +9 -9
  149. package/dist/instrumentation.js +4 -4
  150. package/dist/nitro.js +2 -2
  151. package/dist/{oauth-callback-server-6NZNHJAM.js → oauth-callback-server-FUEV5HNG.js} +24 -24
  152. package/dist/{runner-GCRPG3GQ.js → runner-U3XHSKSH.js} +21 -41
  153. package/dist/{skills-2S3MDFIQ.js → skills-AKE6W3WI.js} +6 -6
  154. package/dist/spawn-B6GDTWJ4.js +39 -0
  155. package/dist/{validation-HAOLCJ5A.js → validation-WDTAULUF.js} +6 -6
  156. package/dist/version.js +1 -1
  157. package/dist/{work-R4XYKMUW.js → work-C3HAO2BG.js} +17 -17
  158. package/dist/{worker-U2UCVR7M.js → worker-LNP4YKBM.js} +10 -10
  159. package/migrations/0024_misty_typhoid_mary.sql +12 -0
  160. package/migrations/meta/0024_snapshot.json +2275 -0
  161. package/migrations/meta/_journal.json +7 -0
  162. package/package.json +4 -4
  163. package/dist/chat/conversations/search.d.ts +0 -24
  164. package/dist/chat/conversations/sql/search.d.ts +0 -4
  165. package/dist/chat/slack/legacy-attachments.d.ts +0 -4
  166. package/dist/chat/slack/message.d.ts +0 -12
  167. package/dist/chat/slack/tools/user-lookup.d.ts +0 -26
  168. package/dist/chat/state/artifacts.d.ts +0 -30
  169. package/dist/chat/tool-support/turn-deadline-result.d.ts +0 -3
  170. package/dist/chunk-Q6QZTTLS.js +0 -55
  171. package/dist/spawn-7WK37BTD.js +0 -39
@@ -0,0 +1,566 @@
1
+ import {
2
+ persistConversationMessages
3
+ } from "./chunk-AIOK6LAG.js";
4
+ import {
5
+ JUNIOR_THREAD_STATE_TTL_MS
6
+ } from "./chunk-3Y47VMHV.js";
7
+ import {
8
+ getDb
9
+ } from "./chunk-YSB2N563.js";
10
+ import {
11
+ juniorLocationConfigurations
12
+ } from "./chunk-DU74WPIC.js";
13
+ import {
14
+ getStateAdapter
15
+ } from "./chunk-ORO3PWKQ.js";
16
+ import {
17
+ juniorDestinations
18
+ } from "./chunk-VFUK3X5B.js";
19
+ import {
20
+ isRecord,
21
+ toOptionalNumber,
22
+ toOptionalString
23
+ } from "./chunk-4LJO56OJ.js";
24
+
25
+ // src/chat/conversations/turn-lifecycle.ts
26
+ var ConversationTurnLifecycleService = class {
27
+ constructor(events) {
28
+ this.events = events;
29
+ }
30
+ events;
31
+ /** Record the turn start once after every input message is durable. */
32
+ async start(input) {
33
+ await this.events.append(input.conversationId, [
34
+ {
35
+ idempotencyKey: `turn:${input.turnId}:started`,
36
+ createdAtMs: input.createdAtMs,
37
+ data: {
38
+ type: "turn_started",
39
+ turnId: input.turnId,
40
+ inputMessageIds: input.inputMessageIds,
41
+ surface: input.surface
42
+ }
43
+ }
44
+ ]);
45
+ }
46
+ /** Record successful or intentional-silence completion once. */
47
+ async complete(input) {
48
+ await this.events.append(input.conversationId, [
49
+ {
50
+ idempotencyKey: `turn:${input.turnId}:terminal`,
51
+ createdAtMs: input.createdAtMs,
52
+ data: {
53
+ type: "turn_completed",
54
+ turnId: input.turnId,
55
+ outcome: input.outcome
56
+ }
57
+ }
58
+ ]);
59
+ }
60
+ /** Record a classified failure once without accepting raw error details. */
61
+ async fail(input) {
62
+ await this.events.append(input.conversationId, [
63
+ {
64
+ idempotencyKey: `turn:${input.turnId}:terminal`,
65
+ createdAtMs: input.createdAtMs,
66
+ data: {
67
+ type: "turn_failed",
68
+ turnId: input.turnId,
69
+ failureCode: input.failureCode,
70
+ ...input.eventId ? { eventId: input.eventId } : {}
71
+ }
72
+ }
73
+ ]);
74
+ }
75
+ };
76
+
77
+ // src/chat/state/conversation.ts
78
+ function defaultConversationState() {
79
+ return {
80
+ schemaVersion: 1,
81
+ messages: [],
82
+ compactions: [],
83
+ processing: {},
84
+ vision: {
85
+ byFileId: {}
86
+ }
87
+ };
88
+ }
89
+ function coercePendingAuthState(value) {
90
+ if (!isRecord(value)) {
91
+ return void 0;
92
+ }
93
+ const kind = value.kind;
94
+ const provider = toOptionalString(value.provider);
95
+ const actorId = toOptionalString(value.actorId);
96
+ const authSessionId = toOptionalString(value.authSessionId);
97
+ const scope = toOptionalString(value.scope);
98
+ const sessionId = toOptionalString(value.sessionId);
99
+ const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
100
+ if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || kind === "mcp" && !authSessionId || !sessionId || typeof linkSentAtMs !== "number") {
101
+ return void 0;
102
+ }
103
+ const base = {
104
+ provider,
105
+ actorId,
106
+ ...scope ? { scope } : {},
107
+ sessionId,
108
+ linkSentAtMs
109
+ };
110
+ return kind === "mcp" ? { ...base, authSessionId, kind } : { ...base, kind };
111
+ }
112
+ function coerceThreadConversationState(value) {
113
+ if (!isRecord(value)) {
114
+ return defaultConversationState();
115
+ }
116
+ const root = value;
117
+ const rawConversation = isRecord(root.conversation) ? root.conversation : {};
118
+ const messages = [];
119
+ const compactions = [];
120
+ const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
121
+ const processing = {
122
+ activeTurnId: toOptionalString(rawProcessing.activeTurnId),
123
+ lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
124
+ pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
125
+ };
126
+ const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
127
+ const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
128
+ const byFileId = {};
129
+ for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
130
+ if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
131
+ if (!isRecord(value2)) continue;
132
+ const summary = toOptionalString(value2.summary);
133
+ const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
134
+ if (!summary || !analyzedAtMs) continue;
135
+ byFileId[fileId] = {
136
+ summary,
137
+ analyzedAtMs
138
+ };
139
+ }
140
+ return {
141
+ schemaVersion: 1,
142
+ messages,
143
+ compactions,
144
+ processing,
145
+ vision: {
146
+ backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
147
+ byFileId
148
+ }
149
+ };
150
+ }
151
+ function buildConversationStatePatch(conversation) {
152
+ return {
153
+ conversation: {
154
+ schemaVersion: 1,
155
+ processing: { ...conversation.processing }
156
+ }
157
+ };
158
+ }
159
+
160
+ // src/chat/configuration/sql.ts
161
+ import { randomUUID } from "crypto";
162
+ import { and, eq, sql } from "drizzle-orm";
163
+
164
+ // src/chat/configuration/types.ts
165
+ import { z } from "zod";
166
+ var configValueSchema = z.json();
167
+
168
+ // src/chat/configuration/validation.ts
169
+ var CONFIG_KEY_RE = /^[a-z0-9]+(?:\.[a-z0-9-]+)+$/;
170
+ var SECRET_KEY_RE = /(?:^|[_.-])(token|secret|password|passphrase|api[-_]?key|private[-_]?key|credential|auth)(?:$|[_.-])/i;
171
+ var SECRET_VALUE_PATTERNS = [
172
+ /\bBearer\s+[A-Za-z0-9._-]{16,}\b/i,
173
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
174
+ /\b(?:ghp|ghs|github_pat)_[A-Za-z0-9_]{20,}\b/,
175
+ /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/i,
176
+ /\bsk-[A-Za-z0-9]{20,}\b/,
177
+ /\bAIza[0-9A-Za-z\-_]{30,}\b/,
178
+ /\bAKIA[0-9A-Z]{16}\b/,
179
+ /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/
180
+ ];
181
+ function validateConfigKey(key) {
182
+ const trimmed = key.trim();
183
+ if (!trimmed) {
184
+ return "Configuration key must not be empty";
185
+ }
186
+ if (!CONFIG_KEY_RE.test(trimmed)) {
187
+ return `Invalid configuration key "${key}"; expected dotted lowercase namespace (for example "provider.repo")`;
188
+ }
189
+ if (SECRET_KEY_RE.test(trimmed)) {
190
+ return `Configuration key "${key}" appears to be secret-related and is not allowed`;
191
+ }
192
+ return void 0;
193
+ }
194
+ function collectStringValues(value, output, depth = 0) {
195
+ if (depth > 5) {
196
+ return;
197
+ }
198
+ if (typeof value === "string") {
199
+ output.push(value);
200
+ return;
201
+ }
202
+ if (Array.isArray(value)) {
203
+ for (const item of value) {
204
+ collectStringValues(item, output, depth + 1);
205
+ }
206
+ return;
207
+ }
208
+ if (value && typeof value === "object") {
209
+ for (const [key, nested] of Object.entries(
210
+ value
211
+ )) {
212
+ output.push(key);
213
+ collectStringValues(nested, output, depth + 1);
214
+ }
215
+ }
216
+ }
217
+ function validateConfigValue(value) {
218
+ const stringValues = [];
219
+ collectStringValues(value, stringValues);
220
+ for (const text of stringValues) {
221
+ for (const pattern of SECRET_VALUE_PATTERNS) {
222
+ if (pattern.test(text)) {
223
+ return "Configuration value appears to contain secret material and is not allowed";
224
+ }
225
+ }
226
+ }
227
+ return void 0;
228
+ }
229
+
230
+ // src/chat/configuration/service.ts
231
+ function sanitizeEntry(value) {
232
+ if (!isRecord(value)) {
233
+ return void 0;
234
+ }
235
+ const key = toOptionalString(value.key);
236
+ if (!key || validateConfigKey(key)) {
237
+ return void 0;
238
+ }
239
+ const updatedAt = toOptionalString(value.updatedAt);
240
+ if (!updatedAt) {
241
+ return void 0;
242
+ }
243
+ if (value.scope !== "channel" && value.scope !== "conversation" && value.scope !== "location") {
244
+ return void 0;
245
+ }
246
+ const parsedValue = configValueSchema.safeParse(value.value);
247
+ if (!parsedValue.success) {
248
+ return void 0;
249
+ }
250
+ return {
251
+ key,
252
+ value: parsedValue.data,
253
+ scope: "location",
254
+ updatedAt,
255
+ updatedBy: toOptionalString(value.updatedBy),
256
+ source: toOptionalString(value.source),
257
+ expiresAt: toOptionalString(value.expiresAt)
258
+ };
259
+ }
260
+ function coerceLegacyLocationConfig(raw) {
261
+ const rawConfig = isRecord(raw) && isRecord(raw.configuration) ? raw.configuration : {};
262
+ const rawEntries = isRecord(rawConfig.entries) ? rawConfig.entries : {};
263
+ return Object.values(rawEntries).flatMap((value) => {
264
+ const entry = sanitizeEntry(value);
265
+ return entry ? [entry] : [];
266
+ });
267
+ }
268
+ function createLocationConfigurationService(storage) {
269
+ const get = async (key) => await storage.get(key.trim());
270
+ const set = async (input) => {
271
+ const normalizedKey = input.key.trim();
272
+ const keyError = validateConfigKey(normalizedKey);
273
+ if (keyError) {
274
+ throw new Error(keyError);
275
+ }
276
+ const value = configValueSchema.parse(input.value);
277
+ const valueError = validateConfigValue(value);
278
+ if (valueError) {
279
+ throw new Error(valueError);
280
+ }
281
+ const entry = {
282
+ key: normalizedKey,
283
+ value,
284
+ scope: "location",
285
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
286
+ updatedBy: toOptionalString(input.updatedBy),
287
+ source: toOptionalString(input.source),
288
+ expiresAt: toOptionalString(input.expiresAt)
289
+ };
290
+ await storage.set(entry);
291
+ return entry;
292
+ };
293
+ const unset = async (key) => await storage.unset(key.trim());
294
+ const list = async (options = {}) => {
295
+ const prefix = options.prefix?.trim();
296
+ return (await storage.list()).filter((entry) => prefix ? entry.key.startsWith(prefix) : true).sort((a, b) => a.key.localeCompare(b.key));
297
+ };
298
+ const resolve = async (key) => (await get(key))?.value;
299
+ const resolveValues = async (options = {}) => {
300
+ const keys = options.keys?.map((key) => key.trim()).filter(Boolean);
301
+ const entries = await list(options.prefix ? { prefix: options.prefix } : {});
302
+ return Object.fromEntries(
303
+ entries.filter((entry) => !keys || keys.includes(entry.key)).map((entry) => [entry.key, entry.value])
304
+ );
305
+ };
306
+ return { get, set, unset, list, resolve, resolveValues };
307
+ }
308
+
309
+ // src/chat/configuration/sql.ts
310
+ async function resolveLocationId(db, destination) {
311
+ const channelId = destination.channelId;
312
+ const now = /* @__PURE__ */ new Date();
313
+ const rows = await db.insert(juniorDestinations).values({
314
+ id: randomUUID(),
315
+ provider: "slack",
316
+ providerTenantId: destination.teamId,
317
+ providerDestinationId: channelId,
318
+ kind: channelId.startsWith("D") ? "dm" : channelId.startsWith("G") ? "group" : "channel",
319
+ parentDestinationId: null,
320
+ displayName: null,
321
+ visibility: "unknown",
322
+ metadata: { platform: "slack" },
323
+ createdAt: now,
324
+ updatedAt: now
325
+ }).onConflictDoUpdate({
326
+ target: [
327
+ juniorDestinations.provider,
328
+ juniorDestinations.providerTenantId,
329
+ juniorDestinations.providerDestinationId
330
+ ],
331
+ set: { id: sql`${juniorDestinations.id}` }
332
+ }).returning({ id: juniorDestinations.id });
333
+ const location = rows[0];
334
+ if (!location) {
335
+ throw new Error("Location upsert returned no row");
336
+ }
337
+ return location.id;
338
+ }
339
+ function createSqlLocationConfigurationStorage(db, destination) {
340
+ const locationWhere = and(
341
+ eq(juniorDestinations.provider, "slack"),
342
+ eq(juniorDestinations.providerTenantId, destination.teamId),
343
+ eq(juniorDestinations.providerDestinationId, destination.channelId)
344
+ );
345
+ const selectEntries = () => db.select({
346
+ key: juniorLocationConfigurations.key,
347
+ value: juniorLocationConfigurations.value,
348
+ updatedAt: juniorLocationConfigurations.updatedAt,
349
+ updatedBy: juniorLocationConfigurations.updatedBy,
350
+ source: juniorLocationConfigurations.source,
351
+ expiresAt: juniorLocationConfigurations.expiresAt
352
+ }).from(juniorLocationConfigurations).innerJoin(
353
+ juniorDestinations,
354
+ eq(juniorDestinations.id, juniorLocationConfigurations.locationId)
355
+ );
356
+ const entryFromRow = (row) => ({
357
+ key: row.key,
358
+ value: configValueSchema.parse(JSON.parse(row.value)),
359
+ scope: "location",
360
+ updatedAt: row.updatedAt.toISOString(),
361
+ updatedBy: row.updatedBy ?? void 0,
362
+ source: row.source ?? void 0,
363
+ expiresAt: row.expiresAt ?? void 0
364
+ });
365
+ const list = async () => (await selectEntries().where(locationWhere)).map(entryFromRow);
366
+ const set = async (entry) => {
367
+ const locationId = await resolveLocationId(db, destination);
368
+ await db.insert(juniorLocationConfigurations).values({
369
+ locationId,
370
+ key: entry.key,
371
+ value: JSON.stringify(entry.value),
372
+ updatedAt: new Date(entry.updatedAt),
373
+ updatedBy: entry.updatedBy,
374
+ source: entry.source,
375
+ expiresAt: entry.expiresAt
376
+ }).onConflictDoUpdate({
377
+ target: [
378
+ juniorLocationConfigurations.locationId,
379
+ juniorLocationConfigurations.key
380
+ ],
381
+ set: {
382
+ value: JSON.stringify(entry.value),
383
+ updatedAt: new Date(entry.updatedAt),
384
+ updatedBy: entry.updatedBy,
385
+ source: entry.source,
386
+ expiresAt: entry.expiresAt
387
+ }
388
+ });
389
+ };
390
+ return {
391
+ get: async (key) => {
392
+ const rows = await selectEntries().where(and(locationWhere, eq(juniorLocationConfigurations.key, key))).limit(1);
393
+ return rows[0] ? entryFromRow(rows[0]) : void 0;
394
+ },
395
+ list,
396
+ set,
397
+ unset: async (key) => {
398
+ const locationId = await resolveLocationId(db, destination);
399
+ const rows = await db.delete(juniorLocationConfigurations).where(
400
+ and(
401
+ eq(juniorLocationConfigurations.locationId, locationId),
402
+ eq(juniorLocationConfigurations.key, key)
403
+ )
404
+ ).returning({ key: juniorLocationConfigurations.key });
405
+ return rows.length > 0;
406
+ },
407
+ insertLegacy: async (entries) => {
408
+ if (entries.length === 0) {
409
+ return;
410
+ }
411
+ const locationId = await resolveLocationId(db, destination);
412
+ await db.insert(juniorLocationConfigurations).values(
413
+ entries.map((entry) => ({
414
+ locationId,
415
+ key: entry.key,
416
+ value: JSON.stringify(entry.value),
417
+ updatedAt: new Date(entry.updatedAt),
418
+ updatedBy: entry.updatedBy,
419
+ source: entry.source,
420
+ expiresAt: entry.expiresAt
421
+ }))
422
+ ).onConflictDoNothing();
423
+ }
424
+ };
425
+ }
426
+ function createDurableLocationConfigurationService(args) {
427
+ const storage = createSqlLocationConfigurationStorage(args.db, args.destination);
428
+ let cutover;
429
+ const ensureCutover = () => cutover ??= (async () => {
430
+ if ((await storage.list()).length > 0) {
431
+ return;
432
+ }
433
+ const legacy = coerceLegacyLocationConfig(await args.loadLegacy());
434
+ await storage.insertLegacy(legacy);
435
+ })();
436
+ return createLocationConfigurationService({
437
+ get: async (key) => {
438
+ await ensureCutover();
439
+ return await storage.get(key);
440
+ },
441
+ list: async () => {
442
+ await ensureCutover();
443
+ return await storage.list();
444
+ },
445
+ set: async (entry) => {
446
+ await ensureCutover();
447
+ await storage.set(entry);
448
+ },
449
+ unset: async (key) => {
450
+ await ensureCutover();
451
+ return await storage.unset(key);
452
+ }
453
+ });
454
+ }
455
+
456
+ // src/chat/runtime/thread-state.ts
457
+ function threadStateKey(threadId) {
458
+ return `thread-state:${threadId}`;
459
+ }
460
+ function channelStateKey(channelId) {
461
+ return `channel-state:${channelId}`;
462
+ }
463
+ function buildThreadStatePayload(patch) {
464
+ const payload = {};
465
+ if (patch.conversation) {
466
+ Object.assign(payload, buildConversationStatePatch(patch.conversation));
467
+ }
468
+ if (patch.sandboxRef !== void 0) {
469
+ payload.app_sandbox_id = patch.sandboxRef?.id ?? "";
470
+ payload.app_sandbox_dependency_profile_hash = patch.sandboxRef?.profileHash ?? "";
471
+ }
472
+ return payload;
473
+ }
474
+ async function mergePersistedState(key, payload) {
475
+ if (Object.keys(payload).length === 0) {
476
+ return;
477
+ }
478
+ const stateAdapter = getStateAdapter();
479
+ await stateAdapter.connect();
480
+ const existing = await stateAdapter.get(key) ?? {};
481
+ await stateAdapter.set(
482
+ key,
483
+ { ...existing, ...payload },
484
+ JUNIOR_THREAD_STATE_TTL_MS
485
+ );
486
+ }
487
+ function getPersistedSandboxState(state) {
488
+ const id = toOptionalString(state.app_sandbox_id);
489
+ if (!id) {
490
+ return void 0;
491
+ }
492
+ const profileHash = toOptionalString(
493
+ state.app_sandbox_dependency_profile_hash
494
+ );
495
+ return {
496
+ id,
497
+ ...profileHash ? { profileHash } : {}
498
+ };
499
+ }
500
+ async function persistThreadState(thread, patch) {
501
+ if (patch.conversation) {
502
+ await persistConversationMessages({
503
+ conversation: patch.conversation,
504
+ conversationId: toOptionalString(thread.id) ?? toOptionalString(thread.runId)
505
+ });
506
+ }
507
+ await persistThreadRuntimeState(thread, patch);
508
+ }
509
+ async function persistThreadRuntimeState(thread, patch) {
510
+ const threadId = toOptionalString(thread.id) ?? toOptionalString(thread.runId);
511
+ if (!threadId) {
512
+ throw new Error("thread id is required to persist runtime scratch");
513
+ }
514
+ await mergePersistedState(
515
+ threadStateKey(threadId),
516
+ buildThreadStatePayload(patch)
517
+ );
518
+ }
519
+ async function getPersistedThreadState(threadId) {
520
+ const stateAdapter = getStateAdapter();
521
+ await stateAdapter.connect();
522
+ return await stateAdapter.get(
523
+ threadStateKey(threadId)
524
+ ) ?? {};
525
+ }
526
+ async function persistThreadStateById(threadId, patch) {
527
+ if (patch.conversation) {
528
+ await persistConversationMessages({
529
+ conversation: patch.conversation,
530
+ conversationId: threadId
531
+ });
532
+ }
533
+ await mergePersistedState(
534
+ threadStateKey(threadId),
535
+ buildThreadStatePayload(patch)
536
+ );
537
+ }
538
+ async function getLegacyChannelState(channelId) {
539
+ const stateAdapter = getStateAdapter();
540
+ await stateAdapter.connect();
541
+ return await stateAdapter.get(
542
+ channelStateKey(channelId)
543
+ ) ?? {};
544
+ }
545
+ function getLocationConfigurationService(destination) {
546
+ if (destination.platform !== "slack") {
547
+ throw new Error("Location configuration requires a Slack Location");
548
+ }
549
+ return createDurableLocationConfigurationService({
550
+ destination,
551
+ db: getDb(),
552
+ loadLegacy: async () => await getLegacyChannelState(destination.channelId)
553
+ });
554
+ }
555
+
556
+ export {
557
+ ConversationTurnLifecycleService,
558
+ configValueSchema,
559
+ coerceThreadConversationState,
560
+ getPersistedSandboxState,
561
+ persistThreadState,
562
+ persistThreadRuntimeState,
563
+ getPersistedThreadState,
564
+ persistThreadStateById,
565
+ getLocationConfigurationService
566
+ };
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-F3B2YJ76.js";
6
6
  import {
7
7
  toOptionalString
8
- } from "./chunk-2LWPFSB4.js";
8
+ } from "./chunk-4LJO56OJ.js";
9
9
 
10
10
  // src/chat/slack/context.ts
11
11
  import { z } from "zod";
@@ -8,14 +8,14 @@ import {
8
8
  getConversationStore,
9
9
  parseDestination,
10
10
  sameDestination
11
- } from "./chunk-2UH3JI64.js";
11
+ } from "./chunk-YSB2N563.js";
12
12
  import {
13
13
  getDefaultRedisStateAdapterFor,
14
14
  getStateAdapter
15
- } from "./chunk-QUG4JSZK.js";
15
+ } from "./chunk-ORO3PWKQ.js";
16
16
  import {
17
17
  getChatConfig
18
- } from "./chunk-XFKIRN3Q.js";
18
+ } from "./chunk-7NVJVJID.js";
19
19
  import {
20
20
  parseStoredSlackActor
21
21
  } from "./chunk-HZF5P5UN.js";
@@ -23,7 +23,7 @@ import {
23
23
  isRecord,
24
24
  toOptionalNumber,
25
25
  toOptionalString
26
- } from "./chunk-2LWPFSB4.js";
26
+ } from "./chunk-4LJO56OJ.js";
27
27
 
28
28
  // src/chat/task-execution/state.ts
29
29
  import { randomUUID } from "crypto";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  JUNIOR_VERSION
3
- } from "./chunk-GDV5LXRA.js";
3
+ } from "./chunk-IIOOO4FQ.js";
4
4
 
5
5
  // src/deployment.ts
6
6
  var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";