@sentry/junior 0.177.0 → 0.179.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 (102) hide show
  1. package/dist/{agent-hooks-IYHCN7CO.js → agent-hooks-32IDCLMW.js} +12 -12
  2. package/dist/api/conversations/archive.d.ts +5 -2
  3. package/dist/api/conversations/list.d.ts +0 -1
  4. package/dist/api/conversations/membership.d.ts +14 -0
  5. package/dist/api/conversations/projection.d.ts +2 -1
  6. package/dist/api/locations/detail.d.ts +1 -1
  7. package/dist/api/people/shared.d.ts +2 -2
  8. package/dist/api/schema/conversation.d.ts +4 -4
  9. package/dist/api/schema/location.d.ts +1 -1
  10. package/dist/api/schema/person.d.ts +1 -1
  11. package/dist/api/schema.js +1 -1
  12. package/dist/api.js +399 -287
  13. package/dist/app.js +573 -198
  14. package/dist/{catalog-runtime-2TD4CXSB.js → catalog-runtime-FBVA6WAQ.js} +5 -5
  15. package/dist/chat/agent/sandbox.d.ts +2 -0
  16. package/dist/chat/conversations/sql/participants.d.ts +1 -0
  17. package/dist/chat/conversations/store.d.ts +0 -1
  18. package/dist/chat/sandbox/errors.d.ts +4 -0
  19. package/dist/chat/sandbox/noninteractive-command.d.ts +1 -0
  20. package/dist/chat/sandbox/prepare-workspace.d.ts +27 -3
  21. package/dist/chat/sandbox/sandbox.d.ts +2 -0
  22. package/dist/chat/sandbox/session.d.ts +2 -0
  23. package/dist/chat/sandbox/snapshot/builder-sandbox.d.ts +5 -0
  24. package/dist/chat/sandbox/snapshot/install.d.ts +2 -2
  25. package/dist/chat/sandbox/snapshot/span.d.ts +3 -0
  26. package/dist/chat/sandbox/snapshot/store.d.ts +20 -17
  27. package/dist/chat/sandbox/snapshot/waiting-error.d.ts +15 -0
  28. package/dist/chat/sandbox/snapshot/workspace.d.ts +17 -0
  29. package/dist/chat/scheduled-tasks/personal.d.ts +5 -8
  30. package/dist/chat/scheduled-tasks/runs.d.ts +49 -0
  31. package/dist/chat/scheduled-tasks/schedule-intent.d.ts +1 -1
  32. package/dist/chat/scheduled-tasks/tasks.d.ts +27 -0
  33. package/dist/chat/scheduled-tasks/tool-support.d.ts +0 -4
  34. package/dist/chat/scheduled-tasks/tools/create.d.ts +1 -1
  35. package/dist/chat/scheduled-tasks/tools/update.d.ts +1 -1
  36. package/dist/chat/scheduled-tasks/types.d.ts +127 -78
  37. package/dist/chat/services/workspace-snapshot-wait.d.ts +27 -0
  38. package/dist/chat/workspaces/types.d.ts +1 -0
  39. package/dist/{chunk-CAWBLVBY.js → chunk-2HIPYNQI.js} +6 -6
  40. package/dist/{chunk-ZCYABD7N.js → chunk-3AFVR5UC.js} +5 -5
  41. package/dist/{chunk-PA7QDS7P.js → chunk-3I7XE3PA.js} +204 -100
  42. package/dist/{chunk-VGDOEKO2.js → chunk-3TM3FYLQ.js} +1 -1
  43. package/dist/{chunk-6NZRKJWU.js → chunk-4GWXAILB.js} +1 -1
  44. package/dist/{chunk-LFZODSAY.js → chunk-5IRROPA5.js} +4 -4
  45. package/dist/{chunk-N4YEVOEC.js → chunk-B6ECUSVX.js} +45 -276
  46. package/dist/{chunk-4TWDRU64.js → chunk-CJLBLELR.js} +5 -5
  47. package/dist/{chunk-3FWXQZJJ.js → chunk-FAS6AIMF.js} +1 -1
  48. package/dist/{chunk-I7PKGMKI.js → chunk-FIDMHAO6.js} +6 -6
  49. package/dist/{chunk-4SVAFAI2.js → chunk-FTGD2FBP.js} +1 -1
  50. package/dist/{chunk-LVL5NG5G.js → chunk-G2CAC4CV.js} +19 -19
  51. package/dist/{chunk-DLTP6TUJ.js → chunk-GENV6KF2.js} +2 -2
  52. package/dist/{chunk-FVVYHML7.js → chunk-GPLAT6H7.js} +6 -6
  53. package/dist/{chunk-7CVYXUOJ.js → chunk-HQNE5APD.js} +1 -1
  54. package/dist/{chunk-Q362TECJ.js → chunk-JMJNFEDC.js} +331 -2
  55. package/dist/{chunk-AFOFVEXP.js → chunk-JT4WMD3C.js} +124 -13
  56. package/dist/{chunk-7ZFESKJ2.js → chunk-KJLHIHFF.js} +9 -9
  57. package/dist/{chunk-QLLOX7JY.js → chunk-Q5B3WTGG.js} +8 -8
  58. package/dist/{chunk-DGGIKWYQ.js → chunk-R5NWWYIS.js} +1 -1
  59. package/dist/{chunk-WCQUKX74.js → chunk-R6U7N4FS.js} +14 -5
  60. package/dist/{chunk-WYO2HXY5.js → chunk-RTRBYSF3.js} +1 -1
  61. package/dist/{chunk-2IMQLZHS.js → chunk-RZRYOLCE.js} +1144 -136
  62. package/dist/{chunk-7B6NW4P7.js → chunk-SLGGOASN.js} +1 -1
  63. package/dist/{chunk-SNPQGTHJ.js → chunk-TIEKUH4Q.js} +1 -1
  64. package/dist/{chunk-ELEAIRTG.js → chunk-TKB25A3L.js} +2 -2
  65. package/dist/{chunk-UB5YB2ED.js → chunk-U4TKB6F6.js} +6 -6
  66. package/dist/{chunk-ORMJY4RG.js → chunk-UT6X7XN7.js} +1 -1
  67. package/dist/{chunk-LPMLAJYR.js → chunk-VP4OVRDD.js} +11 -17
  68. package/dist/{chunk-7PZDAXIK.js → chunk-XSPSCWLH.js} +1 -1
  69. package/dist/chunk-XZY6G5YZ.js +1088 -0
  70. package/dist/{chunk-J2EWL6GJ.js → chunk-YFNAMRGE.js} +1 -1
  71. package/dist/{chunk-6KGMMVHF.js → chunk-ZQMG3CL5.js} +2 -2
  72. package/dist/cli/chat.js +31 -30
  73. package/dist/cli/check.js +6 -6
  74. package/dist/cli/plugins.js +13 -13
  75. package/dist/cli/snapshot-create.js +10 -10
  76. package/dist/cli/upgrade.js +7 -7
  77. package/dist/db/schema/conversation-participants.d.ts +17 -0
  78. package/dist/db/schema/conversations.d.ts +629 -1
  79. package/dist/db/schema/scheduled-tasks.d.ts +29 -5
  80. package/dist/db/schema/snapshots.d.ts +1 -1
  81. package/dist/db/schema.d.ts +46 -5
  82. package/dist/{db-A3CB76US.js → db-EJAV7JL6.js} +7 -7
  83. package/dist/instrumentation.js +4 -4
  84. package/dist/nitro.js +2 -2
  85. package/dist/{oauth-callback-server-64QMI3IB.js → oauth-callback-server-GAVSUBTQ.js} +23 -23
  86. package/dist/{runner-EIAE2BGD.js → runner-34JL64JF.js} +15 -15
  87. package/dist/{skills-ZADWFKDG.js → skills-U545HALM.js} +6 -6
  88. package/dist/spawn-I2S4IDUQ.js +37 -0
  89. package/dist/{validation-4I6AF4CV.js → validation-EVXVGA44.js} +6 -6
  90. package/dist/version.js +1 -1
  91. package/dist/{work-BS6BZ66U.js → work-QOAUPDBU.js} +18 -18
  92. package/dist/worker-5GX2IKLZ.js +24 -0
  93. package/migrations/0033_workspace_snapshot_active_build.sql +1 -0
  94. package/migrations/0034_strong_randall.sql +31 -0
  95. package/migrations/meta/0033_snapshot.json +2914 -0
  96. package/migrations/meta/0034_snapshot.json +3038 -0
  97. package/migrations/meta/_journal.json +15 -1
  98. package/package.json +4 -4
  99. package/dist/chat/scheduled-tasks/store.d.ts +0 -78
  100. package/dist/chunk-4TRHPYTL.js +0 -1944
  101. package/dist/spawn-DVUOUFFC.js +0 -37
  102. package/dist/worker-RS5PWTCE.js +0 -24
package/dist/api.js CHANGED
@@ -41,12 +41,17 @@ import {
41
41
  workspaceListSchema,
42
42
  workspaceParamsSchema,
43
43
  workspaceSchema
44
- } from "./chunk-ELEAIRTG.js";
44
+ } from "./chunk-TKB25A3L.js";
45
45
  import {
46
46
  appendAndEnqueueApiConversationMessage,
47
47
  authenticatePersonalToken,
48
+ conversationArchiveTimes,
49
+ conversationArchivedForEmail,
50
+ conversationArchivedForUser,
48
51
  conversationHasParticipantEmail,
49
52
  conversationHasParticipantUser,
53
+ conversationNotArchivedForEmail,
54
+ conversationNotArchivedForUser,
50
55
  createAndEnqueueApiConversation,
51
56
  createPersonalToken,
52
57
  createVercelAttachmentStorage,
@@ -59,15 +64,15 @@ import {
59
64
  revokePersonalToken,
60
65
  viewerConversationMembership,
61
66
  webActorFromEmail
62
- } from "./chunk-AFOFVEXP.js";
67
+ } from "./chunk-JT4WMD3C.js";
63
68
  import {
64
69
  buildSentryConversationUrl,
65
70
  getWebAuthorization
66
- } from "./chunk-4SVAFAI2.js";
71
+ } from "./chunk-FTGD2FBP.js";
67
72
  import {
68
73
  cancelHumanFacingPendingMessages,
69
74
  getConversation
70
- } from "./chunk-LFZODSAY.js";
75
+ } from "./chunk-5IRROPA5.js";
71
76
  import {
72
77
  readTaskExecutionByConversationId,
73
78
  readTaskExecutionDays,
@@ -75,8 +80,8 @@ import {
75
80
  readTaskExecutionSummaries,
76
81
  readTaskExecutions,
77
82
  readTaskRuns
78
- } from "./chunk-7ZFESKJ2.js";
79
- import "./chunk-4TWDRU64.js";
83
+ } from "./chunk-KJLHIHFF.js";
84
+ import "./chunk-CJLBLELR.js";
80
85
  import {
81
86
  healthReportSchema,
82
87
  pluginOperationalReportFeedSchema,
@@ -90,30 +95,33 @@ import {
90
95
  import "./chunk-JAL3CH4G.js";
91
96
  import "./chunk-5I6ORJUY.js";
92
97
  import {
93
- createSchedulerSqlStore,
94
98
  deleteEventTask,
95
99
  eventTaskBelongsToUser,
96
100
  eventTaskTriggerAvailable,
97
101
  getEventTask,
98
102
  getResourceEventCatalog,
103
+ isListedScheduledTask,
99
104
  listEventTasksCreatedBy,
100
105
  listPublicEventTasksForTeams,
101
106
  listPublicScheduledTasksForTeams,
107
+ parseScheduledTaskRow,
102
108
  readLiveAttachment,
103
- readStats
104
- } from "./chunk-4TRHPYTL.js";
109
+ readScheduledTask,
110
+ readStats,
111
+ saveScheduledTask
112
+ } from "./chunk-XZY6G5YZ.js";
105
113
  import {
106
114
  parseSlackThreadId
107
- } from "./chunk-3FWXQZJJ.js";
115
+ } from "./chunk-FAS6AIMF.js";
108
116
  import {
109
117
  agentTurnUsageSchema,
110
118
  fallbackShortTitle,
111
119
  hasAgentTurnUsage,
112
120
  renderJuniorNativeConversationEvent
113
- } from "./chunk-I7PKGMKI.js";
121
+ } from "./chunk-FIDMHAO6.js";
114
122
  import {
115
123
  getCachedSnapshot
116
- } from "./chunk-N4YEVOEC.js";
124
+ } from "./chunk-B6ECUSVX.js";
117
125
  import "./chunk-PDO5BLNM.js";
118
126
  import {
119
127
  SANDBOX_RUNTIME,
@@ -134,7 +142,7 @@ import {
134
142
  updateWorkspace,
135
143
  withSlackRetries,
136
144
  workspaceRepoCheckoutPath
137
- } from "./chunk-PA7QDS7P.js";
145
+ } from "./chunk-3I7XE3PA.js";
138
146
  import "./chunk-3Y47VMHV.js";
139
147
  import {
140
148
  decodeStoredConversationEvent,
@@ -142,26 +150,30 @@ import {
142
150
  getDb,
143
151
  getSqlExecutor,
144
152
  locationFromRow,
145
- parseSessionSource
146
- } from "./chunk-LPMLAJYR.js";
153
+ parseSessionSource,
154
+ resolveRootConversationId
155
+ } from "./chunk-VP4OVRDD.js";
147
156
  import {
157
+ conversationReadColumns,
148
158
  juniorConversationEvents,
159
+ juniorConversationParticipants,
149
160
  juniorConversations,
150
161
  juniorIdentities,
162
+ juniorSchedulerTasks,
151
163
  juniorUsers
152
- } from "./chunk-WCQUKX74.js";
164
+ } from "./chunk-R6U7N4FS.js";
153
165
  import {
154
166
  create,
155
167
  hash
156
- } from "./chunk-Q362TECJ.js";
157
- import "./chunk-VGDOEKO2.js";
158
- import "./chunk-DLTP6TUJ.js";
168
+ } from "./chunk-JMJNFEDC.js";
169
+ import "./chunk-3TM3FYLQ.js";
170
+ import "./chunk-GENV6KF2.js";
159
171
  import {
160
172
  juniorDestinations
161
173
  } from "./chunk-VFUK3X5B.js";
162
- import "./chunk-7PZDAXIK.js";
163
- import "./chunk-J2EWL6GJ.js";
164
- import "./chunk-7B6NW4P7.js";
174
+ import "./chunk-XSPSCWLH.js";
175
+ import "./chunk-YFNAMRGE.js";
176
+ import "./chunk-SLGGOASN.js";
165
177
  import "./chunk-CGA4ERJ5.js";
166
178
  import {
167
179
  parseSlackChannelId,
@@ -171,12 +183,12 @@ import {
171
183
  import {
172
184
  logException,
173
185
  logWarn
174
- } from "./chunk-7CVYXUOJ.js";
186
+ } from "./chunk-HQNE5APD.js";
175
187
  import "./chunk-6GWA276C.js";
176
188
  import "./chunk-OOUNJNMR.js";
177
189
  import "./chunk-H4HBKISO.js";
178
- import "./chunk-ORMJY4RG.js";
179
- import "./chunk-SNPQGTHJ.js";
190
+ import "./chunk-UT6X7XN7.js";
191
+ import "./chunk-TIEKUH4Q.js";
180
192
  import "./chunk-MLKGABMK.js";
181
193
 
182
194
  // src/api.ts
@@ -231,33 +243,91 @@ var requireViewer = createMiddleware(
231
243
  );
232
244
 
233
245
  // src/api/conversations/archive.ts
234
- import { and, eq, isNotNull } from "drizzle-orm";
235
- async function archiveIfUnchanged(args) {
236
- const db = getDb();
237
- const rows = await db.update(juniorConversations).set({ archivedAt: args.archived ? /* @__PURE__ */ new Date() : null }).where(
246
+ import { and, eq, isNotNull, sql } from "drizzle-orm";
247
+ async function setViewerArchive(args) {
248
+ const executor = getSqlExecutor();
249
+ return await executor.transaction(async () => {
250
+ const db = executor.db();
251
+ const [root] = await db.select({ lastActivityAt: juniorConversations.lastActivityAt }).from(juniorConversations).where(eq(juniorConversations.conversationId, args.rootConversationId)).limit(1).for("update");
252
+ if (!root) return { status: "missing" };
253
+ if (args.archived) {
254
+ if (root.lastActivityAt.getTime() !== Date.parse(args.lastSeenAt)) {
255
+ return { status: "conflict" };
256
+ }
257
+ const archivedAt = /* @__PURE__ */ new Date();
258
+ const lastMessageAt = new Date(args.lastSeenAt);
259
+ await db.insert(juniorConversationParticipants).values({
260
+ archivedAt,
261
+ lastMessageAt,
262
+ rootConversationId: args.rootConversationId,
263
+ userId: args.userId
264
+ }).onConflictDoUpdate({
265
+ target: [
266
+ juniorConversationParticipants.userId,
267
+ juniorConversationParticipants.rootConversationId
268
+ ],
269
+ set: {
270
+ archivedAt,
271
+ lastMessageAt: sql`greatest(${juniorConversationParticipants.lastMessageAt}, excluded.last_message_at)`
272
+ }
273
+ });
274
+ return { archivedAt: archivedAt.toISOString(), status: "updated" };
275
+ }
276
+ await db.update(juniorConversationParticipants).set({ archivedAt: null }).where(
277
+ and(
278
+ eq(juniorConversationParticipants.userId, args.userId),
279
+ eq(
280
+ juniorConversationParticipants.rootConversationId,
281
+ args.rootConversationId
282
+ ),
283
+ isNotNull(juniorConversationParticipants.archivedAt)
284
+ )
285
+ );
286
+ return { archivedAt: null, status: "updated" };
287
+ });
288
+ }
289
+ async function readConversationArchivedAt(viewer, conversationId) {
290
+ const rootConversationId = await resolveRootConversationId(
291
+ getSqlExecutor(),
292
+ conversationId
293
+ );
294
+ const [row] = await getDb().select({ archivedAt: juniorConversationParticipants.archivedAt }).from(juniorConversationParticipants).where(
238
295
  and(
239
- eq(juniorConversations.conversationId, args.conversationId),
240
- args.archived ? eq(juniorConversations.lastActivityAt, new Date(args.lastSeenAt)) : isNotNull(juniorConversations.archivedAt)
296
+ eq(juniorConversationParticipants.userId, viewer.id),
297
+ eq(
298
+ juniorConversationParticipants.rootConversationId,
299
+ rootConversationId
300
+ )
241
301
  )
242
- ).returning({ conversationId: juniorConversations.conversationId });
243
- if (rows.length > 0) return "updated";
244
- const [existing] = await db.select({
245
- archivedAt: juniorConversations.archivedAt,
246
- conversationId: juniorConversations.conversationId
247
- }).from(juniorConversations).where(eq(juniorConversations.conversationId, args.conversationId)).limit(1);
248
- if (!existing) return "not_found";
249
- if (!args.archived && existing.archivedAt === null) return "updated";
250
- return "conflict";
251
- }
252
- async function archiveConversation(conversationId, body) {
253
- const result = await archiveIfUnchanged({ ...body, conversationId });
254
- if (result === "not_found") {
302
+ ).limit(1);
303
+ return row?.archivedAt?.getTime();
304
+ }
305
+ async function archiveConversation(viewer, conversationId, body) {
306
+ const access = await readConversationAccessFromSql(
307
+ getDb(),
308
+ [conversationId],
309
+ viewer
310
+ );
311
+ if (!access.get(conversationId)?.isParticipant) {
255
312
  throwApiError(404, "Conversation not found.");
256
313
  }
257
- if (result === "conflict") {
258
- throwApiError(409, "Conversation received new activity.");
314
+ const rootConversationId = await resolveRootConversationId(
315
+ getSqlExecutor(),
316
+ conversationId
317
+ );
318
+ const result = await setViewerArchive({
319
+ archived: body.archived,
320
+ lastSeenAt: body.lastSeenAt,
321
+ rootConversationId,
322
+ userId: viewer.id
323
+ });
324
+ if (result.status === "updated") {
325
+ return { archivedAt: result.archivedAt };
259
326
  }
260
- return { archived: body.archived };
327
+ if (result.status === "missing") {
328
+ throwApiError(404, "Conversation not found.");
329
+ }
330
+ throwApiError(409, "Conversation received new activity.");
261
331
  }
262
332
 
263
333
  // src/api/conversations/attachments.ts
@@ -480,31 +550,31 @@ async function resolveSlackTeamDomains(teamIds) {
480
550
  }
481
551
 
482
552
  // src/chat/pi/sql-model-usage.ts
483
- import { and as and2, eq as eq2, sql } from "drizzle-orm";
484
- var message = sql`${juniorConversationEvents.payload}`;
485
- var usage = sql`${message}->'usage'`;
486
- var cost = sql`${usage}->'cost'`;
553
+ import { and as and2, eq as eq2, sql as sql2 } from "drizzle-orm";
554
+ var message = sql2`${juniorConversationEvents.payload}`;
555
+ var usage = sql2`${message}->'usage'`;
556
+ var cost = sql2`${usage}->'cost'`;
487
557
  function nonnegativeNumber(source, field, fallbackField, floor = false) {
488
- const value = (name) => sql`case
558
+ const value = (name) => sql2`case
489
559
  when jsonb_typeof(${source}->${name}) = 'number'
490
560
  and (${source}->>${name})::numeric >= 0
491
- then ${floor ? sql`floor((${source}->>${name})::numeric)` : sql`(${source}->>${name})::numeric`}
561
+ then ${floor ? sql2`floor((${source}->>${name})::numeric)` : sql2`(${source}->>${name})::numeric`}
492
562
  end`;
493
563
  const primary = value(field);
494
- return fallbackField ? sql`coalesce(${primary}, ${value(fallbackField)})` : sql`${primary}`;
564
+ return fallbackField ? sql2`coalesce(${primary}, ${value(fallbackField)})` : sql2`${primary}`;
495
565
  }
496
566
  function token(field, fallbackField) {
497
567
  return nonnegativeNumber(usage, field, fallbackField, true);
498
568
  }
499
569
  function summed(value) {
500
- return sql`sum(${value})::double precision`;
570
+ return sql2`sum(${value})::double precision`;
501
571
  }
502
572
  function summedCost(value) {
503
- return sql`round(sum(${value}), 12)::double precision`;
573
+ return sql2`round(sum(${value}), 12)::double precision`;
504
574
  }
505
575
  function messageTotalTokens(args) {
506
576
  const { input, output, cacheRead, cacheWrite } = args;
507
- return sql`case
577
+ return sql2`case
508
578
  when ${input} is not null
509
579
  or ${output} is not null
510
580
  or ${cacheRead} is not null
@@ -547,7 +617,7 @@ function usageFromRow(row) {
547
617
  return hasAgentTurnUsage(result) ? agentTurnUsageSchema.parse(result) : void 0;
548
618
  }
549
619
  async function readConversationModelUsageFromSql(executor, options) {
550
- const modelId = sql`case
620
+ const modelId = sql2`case
551
621
  when position('/' in coalesce(${message}->>'model', '')) > 0
552
622
  then ${message}->>'model'
553
623
  else concat(${message}->>'provider', '/', ${message}->>'model')
@@ -586,10 +656,10 @@ async function readConversationModelUsageFromSql(executor, options) {
586
656
  and2(
587
657
  options.includeDescendants ? eq2(juniorConversations.rootConversationId, options.conversationId) : eq2(juniorConversationEvents.conversationId, options.conversationId),
588
658
  eq2(juniorConversationEvents.type, "assistant_message"),
589
- sql`jsonb_typeof(${message}->'provider') = 'string'`,
590
- sql`jsonb_typeof(${message}->'model') = 'string'`,
591
- sql`coalesce(${message}->>'provider', '') <> ''`,
592
- sql`coalesce(${message}->>'model', '') <> ''`
659
+ sql2`jsonb_typeof(${message}->'provider') = 'string'`,
660
+ sql2`jsonb_typeof(${message}->'model') = 'string'`,
661
+ sql2`coalesce(${message}->>'provider', '') <> ''`,
662
+ sql2`coalesce(${message}->>'model', '') <> ''`
593
663
  )
594
664
  ).groupBy(modelId).orderBy(modelId);
595
665
  return rows.flatMap((row) => {
@@ -654,7 +724,7 @@ import {
654
724
  getTableColumns,
655
725
  inArray,
656
726
  lt,
657
- sql as sql2
727
+ sql as sql3
658
728
  } from "drizzle-orm";
659
729
 
660
730
  // src/api/conversations/events.ts
@@ -1065,7 +1135,7 @@ async function readConversationEventRows(executor, args) {
1065
1135
  return executor.db().select({
1066
1136
  ...conversationEventColumns,
1067
1137
  // Replacement history is model context, never dashboard report data.
1068
- payload: sql2`case
1138
+ payload: sql3`case
1069
1139
  when ${juniorConversationEvents.type} in ('compaction', 'handoff')
1070
1140
  then jsonb_set(
1071
1141
  ${juniorConversationEvents.payload},
@@ -1083,11 +1153,11 @@ async function readConversationEventRows(executor, args) {
1083
1153
  args.types ?? [...conversationReportSourceEventTypes]
1084
1154
  ),
1085
1155
  args.subagentInvocationIds === void 0 ? void 0 : inArray(
1086
- sql2`${juniorConversationEvents.payload}->>'subagentInvocationId'`,
1156
+ sql3`${juniorConversationEvents.payload}->>'subagentInvocationId'`,
1087
1157
  args.subagentInvocationIds
1088
1158
  ),
1089
1159
  args.toolCallIds === void 0 ? void 0 : inArray(
1090
- sql2`${juniorConversationEvents.payload}->>'toolCallId'`,
1160
+ sql3`${juniorConversationEvents.payload}->>'toolCallId'`,
1091
1161
  args.toolCallIds
1092
1162
  )
1093
1163
  )
@@ -1167,7 +1237,7 @@ async function readConversationEventPage(executor, args) {
1167
1237
  }
1168
1238
 
1169
1239
  // src/api/conversations/list.ts
1170
- import { and as and7, asc as asc2, desc as desc2, eq as eq7, isNotNull as isNotNull4, isNull as isNull3 } from "drizzle-orm";
1240
+ import { and as and7, asc as asc2, desc as desc2, eq as eq7, isNull as isNull3, sql as sql7 } from "drizzle-orm";
1171
1241
 
1172
1242
  // src/api/conversations/shared.ts
1173
1243
  function slackStatsLocationLabel(input) {
@@ -1341,7 +1411,7 @@ function conversationSummaryFromStoredConversation(args) {
1341
1411
  ...usage3 ? { cumulativeUsage: usage3 } : {},
1342
1412
  ...actorIdentity ? { actorIdentity } : {},
1343
1413
  ...sourceUrl ? { sourceUrl } : {},
1344
- ...conversation.archivedAtMs ? { archivedAt: new Date(conversation.archivedAtMs).toISOString() } : {},
1414
+ archivedAt: args.archivedAtMs === void 0 ? null : new Date(args.archivedAtMs).toISOString(),
1345
1415
  ...slackThread ? { channel: slackThread.channelId } : {},
1346
1416
  ...channelName ? { channelName } : {},
1347
1417
  ...channelNameRedacted ? { channelNameRedacted: true } : {},
@@ -1350,7 +1420,7 @@ function conversationSummaryFromStoredConversation(args) {
1350
1420
  }
1351
1421
 
1352
1422
  // src/api/conversations/usage.ts
1353
- import { and as and4, eq as eq4, inArray as inArray2, isNull, sql as sql3 } from "drizzle-orm";
1423
+ import { and as and4, eq as eq4, inArray as inArray2, isNull, sql as sql4 } from "drizzle-orm";
1354
1424
  import { alias } from "drizzle-orm/pg-core";
1355
1425
  var usage2 = juniorConversations.usage;
1356
1426
  var metricRootConversation = alias(
@@ -1364,10 +1434,10 @@ var componentFields = [
1364
1434
  "cacheCreationTokens"
1365
1435
  ];
1366
1436
  function summedUsageNumber(field) {
1367
- return sql3`sum((${usage2}->>${field})::double precision)::double precision`;
1437
+ return sql4`sum((${usage2}->>${field})::double precision)::double precision`;
1368
1438
  }
1369
1439
  function summedCostNumber(field) {
1370
- return sql3`round(
1440
+ return sql4`round(
1371
1441
  sum((${usage2}->'cost'->>${field})::numeric),
1372
1442
  12
1373
1443
  )::double precision`;
@@ -1397,7 +1467,7 @@ function usageFromAggregate(row) {
1397
1467
  }
1398
1468
  async function readRootConversationMetricsFromSql(db, rootConversationIds) {
1399
1469
  if (rootConversationIds.length === 0) return /* @__PURE__ */ new Map();
1400
- const hasComponents = sql3`coalesce(
1470
+ const hasComponents = sql4`coalesce(
1401
1471
  ${usage2}->>'inputTokens',
1402
1472
  ${usage2}->>'outputTokens',
1403
1473
  ${usage2}->>'cachedInputTokens',
@@ -1405,12 +1475,12 @@ async function readRootConversationMetricsFromSql(db, rootConversationIds) {
1405
1475
  ) is not null`;
1406
1476
  const rows = await db.select({
1407
1477
  rootConversationId: juniorConversations.rootConversationId,
1408
- durationMs: sql3`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
1478
+ durationMs: sql4`coalesce(sum(${juniorConversations.durationMs}), 0)::double precision`,
1409
1479
  inputTokens: summedUsageNumber("inputTokens"),
1410
1480
  outputTokens: summedUsageNumber("outputTokens"),
1411
1481
  cachedInputTokens: summedUsageNumber("cachedInputTokens"),
1412
1482
  cacheCreationTokens: summedUsageNumber("cacheCreationTokens"),
1413
- totalOnlyTokens: sql3`sum(
1483
+ totalOnlyTokens: sql4`sum(
1414
1484
  case
1415
1485
  when not (${hasComponents})
1416
1486
  then (${usage2}->>'totalTokens')::double precision
@@ -1460,7 +1530,7 @@ import {
1460
1530
  isNotNull as isNotNull2,
1461
1531
  isNull as isNull2,
1462
1532
  or,
1463
- sql as sql4
1533
+ sql as sql5
1464
1534
  } from "drizzle-orm";
1465
1535
  import { alias as alias2 } from "drizzle-orm/pg-core";
1466
1536
  var auxiliaryRootConversation = alias2(
@@ -1468,7 +1538,7 @@ var auxiliaryRootConversation = alias2(
1468
1538
  "auxiliary_root_conversation"
1469
1539
  );
1470
1540
  function eventCost() {
1471
- return sql4`CASE
1541
+ return sql5`CASE
1472
1542
  WHEN ${juniorConversationEvents.type} = 'structured_event'
1473
1543
  AND jsonb_typeof(${juniorConversationEvents.payload}->'content'->'costUsd') = 'number'
1474
1544
  THEN (${juniorConversationEvents.payload}->'content'->>'costUsd')::numeric
@@ -1481,16 +1551,16 @@ function eventCost() {
1481
1551
  async function readConversationAuxiliaryCostsFromSql(db, conversationIds, options) {
1482
1552
  if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
1483
1553
  const selectedIds = [...conversationIds];
1484
- const conversationId = options.includeDescendants ? sql4`coalesce(
1554
+ const conversationId = options.includeDescendants ? sql5`coalesce(
1485
1555
  ${auxiliaryRootConversation.conversationId},
1486
1556
  ${juniorConversations.conversationId}
1487
- )` : sql4`${juniorConversations.conversationId}`;
1488
- const namespace = sql4`CASE
1557
+ )` : sql5`${juniorConversations.conversationId}`;
1558
+ const namespace = sql5`CASE
1489
1559
  WHEN ${juniorConversationEvents.type} = 'structured_event'
1490
1560
  THEN ${juniorConversationEvents.payload}->>'namespace'
1491
1561
  ELSE 'junior'
1492
1562
  END`;
1493
- const name = sql4`CASE
1563
+ const name = sql5`CASE
1494
1564
  WHEN ${juniorConversationEvents.type} = 'structured_event'
1495
1565
  THEN ${juniorConversationEvents.payload}->>'name'
1496
1566
  ELSE ${juniorConversationEvents.type}
@@ -1505,10 +1575,10 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
1505
1575
  ) : inArray3(juniorConversations.conversationId, selectedIds);
1506
1576
  const rows = await db.select({
1507
1577
  conversationId,
1508
- costUsd: sql4`round(sum(${cost2}), 12)::double precision`.mapWith(
1578
+ costUsd: sql5`round(sum(${cost2}), 12)::double precision`.mapWith(
1509
1579
  Number
1510
1580
  ),
1511
- events: sql4`count(*)::integer`.mapWith(Number),
1581
+ events: sql5`count(*)::integer`.mapWith(Number),
1512
1582
  name,
1513
1583
  namespace
1514
1584
  }).from(juniorConversationEvents).innerJoin(
@@ -1540,7 +1610,7 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
1540
1610
  "turn_routed"
1541
1611
  ])
1542
1612
  ),
1543
- sql4`${cost2} >= 0`
1613
+ sql5`${cost2} >= 0`
1544
1614
  )
1545
1615
  ).groupBy(conversationId, namespace, name).orderBy(conversationId, namespace, name);
1546
1616
  const result = /* @__PURE__ */ new Map();
@@ -1687,15 +1757,15 @@ function isConversationPriority(conversation, nowMs) {
1687
1757
  }
1688
1758
 
1689
1759
  // src/api/conversations/user-message-activity.ts
1690
- import { and as and6, eq as eq6, inArray as inArray4, isNotNull as isNotNull3, or as or2, sql as sql5 } from "drizzle-orm";
1760
+ import { and as and6, eq as eq6, inArray as inArray4, isNotNull as isNotNull3, or as or2, sql as sql6 } from "drizzle-orm";
1691
1761
  async function readLastUserMessageAtByConversation(db, conversationIds) {
1692
1762
  if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
1693
- const authority = sql5`${juniorConversationEvents.payload}->'provenance'->>'authority'`;
1694
- const actorPlatform = sql5`${juniorConversationEvents.payload}->'provenance'->'actor'->>'platform'`;
1695
- const role = sql5`${juniorConversationEvents.payload}->>'role'`;
1763
+ const authority = sql6`${juniorConversationEvents.payload}->'provenance'->>'authority'`;
1764
+ const actorPlatform = sql6`${juniorConversationEvents.payload}->'provenance'->'actor'->>'platform'`;
1765
+ const role = sql6`${juniorConversationEvents.payload}->>'role'`;
1696
1766
  const rows = await db.select({
1697
1767
  conversationId: juniorConversationEvents.conversationId,
1698
- lastUserMessageAt: sql5`max(${juniorConversationEvents.createdAt})`
1768
+ lastUserMessageAt: sql6`max(${juniorConversationEvents.createdAt})`
1699
1769
  }).from(juniorConversationEvents).where(
1700
1770
  and6(
1701
1771
  inArray4(juniorConversationEvents.conversationId, conversationIds),
@@ -1703,7 +1773,7 @@ async function readLastUserMessageAtByConversation(db, conversationIds) {
1703
1773
  and6(
1704
1774
  eq6(juniorConversationEvents.type, "user_message"),
1705
1775
  eq6(authority, "instruction"),
1706
- sql5`${actorPlatform} in ('slack', 'local', 'web')`
1776
+ sql6`${actorPlatform} in ('slack', 'local', 'web')`
1707
1777
  ),
1708
1778
  and6(
1709
1779
  eq6(juniorConversationEvents.type, "message"),
@@ -1723,22 +1793,28 @@ async function readLastUserMessageAtByConversation(db, conversationIds) {
1723
1793
 
1724
1794
  // src/api/conversations/list.ts
1725
1795
  var CONVERSATION_FEED_LIMIT = 50;
1726
- function conversationFeedMembershipFilter(filter) {
1727
- if (!filter) return void 0;
1796
+ function conversationFeedMembershipFilter(status, filter) {
1797
+ if (!filter) return status === "archived" ? sql7`false` : void 0;
1728
1798
  if (filter.kind === "viewer") {
1729
- return viewerConversationMembership({
1730
- actorMatch: eq7(juniorIdentities.userId, filter.userId),
1731
- participantMatch: conversationHasParticipantUser(filter.userId)
1732
- });
1799
+ return and7(
1800
+ viewerConversationMembership({
1801
+ actorMatch: eq7(juniorIdentities.userId, filter.userId),
1802
+ participantMatch: conversationHasParticipantUser(filter.userId)
1803
+ }),
1804
+ status === "archived" ? conversationArchivedForUser(filter.userId) : conversationNotArchivedForUser(filter.userId)
1805
+ );
1733
1806
  }
1734
- return viewerConversationMembership({
1735
- actorMatch: eq7(juniorUsers.primaryEmailNormalized, filter.email),
1736
- participantMatch: conversationHasParticipantEmail(filter.email)
1737
- });
1807
+ return and7(
1808
+ viewerConversationMembership({
1809
+ actorMatch: eq7(juniorUsers.primaryEmailNormalized, filter.email),
1810
+ participantMatch: conversationHasParticipantEmail(filter.email)
1811
+ }),
1812
+ status === "archived" ? conversationArchivedForEmail(filter.email) : conversationNotArchivedForEmail(filter.email)
1813
+ );
1738
1814
  }
1739
1815
  async function conversationRows(db, limit, status, filter) {
1740
1816
  return db.select({
1741
- conversation: juniorConversations,
1817
+ conversation: conversationReadColumns(),
1742
1818
  destination: juniorDestinations,
1743
1819
  identityDisplayName: juniorIdentities.displayName,
1744
1820
  identityEmail: juniorIdentities.email,
@@ -1756,8 +1832,7 @@ async function conversationRows(db, limit, status, filter) {
1756
1832
  ).leftJoin(juniorUsers, eq7(juniorUsers.id, juniorIdentities.userId)).where(
1757
1833
  and7(
1758
1834
  isNull3(juniorConversations.parentConversationId),
1759
- status === "archived" ? isNotNull4(juniorConversations.archivedAt) : isNull3(juniorConversations.archivedAt),
1760
- conversationFeedMembershipFilter(filter)
1835
+ conversationFeedMembershipFilter(status, filter)
1761
1836
  )
1762
1837
  ).orderBy(
1763
1838
  desc2(juniorConversations.lastActivityAt),
@@ -1793,7 +1868,6 @@ function conversationFromRow(row) {
1793
1868
  },
1794
1869
  ...actor ? { actor } : {},
1795
1870
  ...location ? { location } : {},
1796
- ...value.archivedAt ? { archivedAtMs: value.archivedAt.getTime() } : {},
1797
1871
  ...value.channelName ? { channelName: value.channelName } : {},
1798
1872
  ...value.source ? { source: value.source } : {},
1799
1873
  ...sessionSource ? { sessionSource } : {},
@@ -1804,7 +1878,7 @@ function conversationFromRow(row) {
1804
1878
  async function readConversationRecordFromSql(conversationId) {
1805
1879
  const db = getDb();
1806
1880
  const rows = await db.select({
1807
- conversation: juniorConversations,
1881
+ conversation: conversationReadColumns(),
1808
1882
  destination: juniorDestinations,
1809
1883
  identityDisplayName: juniorIdentities.displayName,
1810
1884
  identityEmail: juniorIdentities.email,
@@ -1847,11 +1921,12 @@ function conversationFeedFilter(options) {
1847
1921
  async function readConversationFeedFromSql(options = {}) {
1848
1922
  const nowMs = Date.now();
1849
1923
  const db = getDb();
1924
+ const filter = conversationFeedFilter(options);
1850
1925
  const rows = await conversationRows(
1851
1926
  db,
1852
1927
  options.limit ?? CONVERSATION_FEED_LIMIT,
1853
1928
  options.status ?? "active",
1854
- conversationFeedFilter(options)
1929
+ filter
1855
1930
  );
1856
1931
  const conversations = rows.map((row) => conversationFromRow(row));
1857
1932
  const conversationIds = conversations.map(
@@ -1859,6 +1934,7 @@ async function readConversationFeedFromSql(options = {}) {
1859
1934
  );
1860
1935
  const [
1861
1936
  accessByConversation,
1937
+ archiveTimesByConversation,
1862
1938
  annotationsByConversation,
1863
1939
  auxiliaryCostsByRoot,
1864
1940
  metricsByRoot,
@@ -1867,6 +1943,11 @@ async function readConversationFeedFromSql(options = {}) {
1867
1943
  lastUserMessageAtByConversation
1868
1944
  ] = await Promise.all([
1869
1945
  readConversationAccessFromSql(db, conversationIds, options.viewer),
1946
+ conversationArchiveTimes(
1947
+ db,
1948
+ conversationIds,
1949
+ filter?.kind === "viewer" ? { userId: filter.userId } : filter?.kind === "actorEmail" ? { email: filter.email } : void 0
1950
+ ),
1870
1951
  listConversationAnnotationsById(db, conversationIds),
1871
1952
  readConversationAuxiliaryCostsFromSql(db, conversationIds, {
1872
1953
  includeDescendants: true
@@ -1897,7 +1978,11 @@ async function readConversationFeedFromSql(options = {}) {
1897
1978
  const row = rows[index];
1898
1979
  const access = accessByConversation.get(conversation.conversationId);
1899
1980
  const metrics = metricsByRoot.get(conversation.conversationId);
1981
+ const archivedAtMs = archiveTimesByConversation.get(
1982
+ conversation.conversationId
1983
+ );
1900
1984
  const summary = conversationSummaryFromStoredConversation({
1985
+ ...archivedAtMs === void 0 ? {} : { archivedAtMs },
1901
1986
  conversation,
1902
1987
  access,
1903
1988
  auxiliaryCosts: auxiliaryCostsByRoot.get(conversation.conversationId),
@@ -1944,9 +2029,10 @@ async function readConversationFeed(options = {}) {
1944
2029
  }
1945
2030
 
1946
2031
  // src/chat/tasks/read.ts
1947
- import { and as and8, eq as eq8, or as or3 } from "drizzle-orm";
2032
+ import { and as and9, eq as eq9, or as or4 } from "drizzle-orm";
1948
2033
 
1949
2034
  // src/chat/scheduled-tasks/personal.ts
2035
+ import { and as and8, desc as desc3, eq as eq8, inArray as inArray5, lt as lt2, notInArray, or as or3, sql as sql8 } from "drizzle-orm";
1950
2036
  import { z as z3 } from "zod";
1951
2037
  var cursorSchema = z3.object({
1952
2038
  createdAtMs: z3.number().finite(),
@@ -1994,37 +2080,71 @@ function encodeCursor(task, query) {
1994
2080
  "utf8"
1995
2081
  ).toString("base64url");
1996
2082
  }
1997
- function createViewerScheduledTasks(store, user) {
2083
+ async function deleteViewerScheduledTask(db, user, id, nowMs = Date.now()) {
1998
2084
  const identityIds = new Set(user.identities.map((identity) => identity.id));
2085
+ const task = await readScheduledTask(db, id);
2086
+ if (!task || task.status === "deleted" || !identityIds.has(task.creatorIdentityId)) {
2087
+ throw new PersonalScheduledTaskNotFoundError();
2088
+ }
2089
+ await saveScheduledTask(db, {
2090
+ ...task,
2091
+ nextRunAtMs: void 0,
2092
+ runNowAtMs: void 0,
2093
+ status: "deleted",
2094
+ updatedAtMs: nowMs
2095
+ });
2096
+ }
2097
+ async function listViewerScheduledTasks(db, user, input) {
2098
+ const identityIds = user.identities.map((identity) => identity.id);
2099
+ if (identityIds.length === 0) return { tasks: [] };
2100
+ const query = normalizeQuery(input.query);
2101
+ const cursor = decodeCursor(input.cursor, query);
2102
+ const tasks = [];
2103
+ let before = cursor;
2104
+ const fetchLimit = input.limit + 1;
2105
+ while (tasks.length < fetchLimit) {
2106
+ const cursorFilter = before ? or3(
2107
+ lt2(juniorSchedulerTasks.createdAtMs, before.createdAtMs),
2108
+ and8(
2109
+ eq8(juniorSchedulerTasks.createdAtMs, before.createdAtMs),
2110
+ lt2(juniorSchedulerTasks.id, before.id)
2111
+ )
2112
+ ) : void 0;
2113
+ const search = query ? or3(
2114
+ sql8`strpos(lower(${juniorSchedulerTasks.title}), ${query}) > 0`,
2115
+ sql8`strpos(lower(${juniorSchedulerTasks.record}->'task'->>'text'), ${query}) > 0`,
2116
+ sql8`strpos(lower(${juniorSchedulerTasks.record}->'schedule'->>'description'), ${query}) > 0`,
2117
+ sql8`strpos(lower(${juniorSchedulerTasks.record}->'schedule'->>'timezone'), ${query}) > 0`,
2118
+ sql8`strpos(lower(${juniorSchedulerTasks.status}), ${query}) > 0`
2119
+ ) : void 0;
2120
+ const rows = await db.select({
2121
+ createdAtMs: juniorSchedulerTasks.createdAtMs,
2122
+ creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
2123
+ id: juniorSchedulerTasks.id,
2124
+ record: juniorSchedulerTasks.record,
2125
+ title: juniorSchedulerTasks.title
2126
+ }).from(juniorSchedulerTasks).where(
2127
+ and8(
2128
+ notInArray(juniorSchedulerTasks.status, ["deleted", "paused"]),
2129
+ inArray5(juniorSchedulerTasks.creatorIdentityId, identityIds),
2130
+ cursorFilter,
2131
+ search
2132
+ )
2133
+ ).orderBy(
2134
+ desc3(juniorSchedulerTasks.createdAtMs),
2135
+ desc3(juniorSchedulerTasks.id)
2136
+ ).limit(fetchLimit);
2137
+ tasks.push(
2138
+ ...rows.map(parseScheduledTaskRow).filter(isListedScheduledTask)
2139
+ );
2140
+ if (rows.length < fetchLimit) break;
2141
+ const last = rows.at(-1);
2142
+ before = { createdAtMs: last.createdAtMs, id: last.id };
2143
+ }
2144
+ const page = tasks.slice(0, input.limit);
1999
2145
  return {
2000
- async delete(id, nowMs = Date.now()) {
2001
- const task = await store.getTask(id);
2002
- if (!task || task.status === "deleted" || !identityIds.has(task.creatorIdentityId)) {
2003
- throw new PersonalScheduledTaskNotFoundError();
2004
- }
2005
- await store.saveTask({
2006
- ...task,
2007
- nextRunAtMs: void 0,
2008
- runNowAtMs: void 0,
2009
- status: "deleted",
2010
- updatedAtMs: nowMs
2011
- });
2012
- },
2013
- async list(input) {
2014
- const query = normalizeQuery(input.query);
2015
- const cursor = decodeCursor(input.cursor, query);
2016
- const matching = await store.listTasksCreatedBy({
2017
- ...cursor ? { before: cursor } : {},
2018
- identityIds: [...identityIds],
2019
- limit: input.limit + 1,
2020
- ...query ? { query } : {}
2021
- });
2022
- const tasks = matching.slice(0, input.limit);
2023
- return {
2024
- tasks,
2025
- ...matching.length > input.limit && tasks.length > 0 ? { nextCursor: encodeCursor(tasks.at(-1), query) } : {}
2026
- };
2027
- }
2146
+ tasks: page,
2147
+ ...tasks.length > input.limit && page.length > 0 ? { nextCursor: encodeCursor(page.at(-1), query) } : {}
2028
2148
  };
2029
2149
  }
2030
2150
 
@@ -2054,16 +2174,16 @@ async function creatorProfileEmails(candidates) {
2054
2174
  email: juniorUsers.primaryEmailNormalized,
2055
2175
  slackUserId: juniorIdentities.providerSubjectId,
2056
2176
  teamId: juniorIdentities.providerTenantId
2057
- }).from(juniorIdentities).innerJoin(juniorUsers, eq8(juniorUsers.id, juniorIdentities.userId)).where(
2058
- and8(
2059
- eq8(juniorIdentities.kind, "user"),
2060
- eq8(juniorIdentities.provider, "slack"),
2061
- eq8(juniorIdentities.emailVerified, true),
2062
- or3(
2177
+ }).from(juniorIdentities).innerJoin(juniorUsers, eq9(juniorUsers.id, juniorIdentities.userId)).where(
2178
+ and9(
2179
+ eq9(juniorIdentities.kind, "user"),
2180
+ eq9(juniorIdentities.provider, "slack"),
2181
+ eq9(juniorIdentities.emailVerified, true),
2182
+ or4(
2063
2183
  ...[...selectors.values()].map(
2064
- (selector) => and8(
2065
- eq8(juniorIdentities.providerTenantId, selector.teamId),
2066
- eq8(juniorIdentities.providerSubjectId, selector.slackUserId)
2184
+ (selector) => and9(
2185
+ eq9(juniorIdentities.providerTenantId, selector.teamId),
2186
+ eq9(juniorIdentities.providerSubjectId, selector.slackUserId)
2067
2187
  )
2068
2188
  )
2069
2189
  )
@@ -2099,12 +2219,12 @@ async function destinationDetails(destinations) {
2099
2219
  providerTenantId: juniorDestinations.providerTenantId,
2100
2220
  visibility: juniorDestinations.visibility
2101
2221
  }).from(juniorDestinations).where(
2102
- or3(
2222
+ or4(
2103
2223
  ...[...selectors.values()].map(
2104
- (destination) => and8(
2105
- eq8(juniorDestinations.provider, "slack"),
2106
- eq8(juniorDestinations.providerTenantId, destination.teamId),
2107
- eq8(juniorDestinations.providerDestinationId, destination.channelId)
2224
+ (destination) => and9(
2225
+ eq9(juniorDestinations.provider, "slack"),
2226
+ eq9(juniorDestinations.providerTenantId, destination.teamId),
2227
+ eq9(juniorDestinations.providerDestinationId, destination.channelId)
2108
2228
  )
2109
2229
  )
2110
2230
  )
@@ -2197,7 +2317,7 @@ async function resolveViewerTaskCandidate(user, kind, id) {
2197
2317
  const identityIds = new Set(user.identities.map((identity) => identity.id));
2198
2318
  const teamIds = viewerTeamIds(user);
2199
2319
  if (kind === "scheduled") {
2200
- const task2 = await createSchedulerSqlStore(db).getTask(id);
2320
+ const task2 = await readScheduledTask(db, id);
2201
2321
  if (!task2 || task2.status === "deleted") return void 0;
2202
2322
  const ownedByViewer2 = identityIds.has(task2.creatorIdentityId);
2203
2323
  const destinations2 = await destinationDetails([task2.destination]);
@@ -2262,13 +2382,10 @@ async function taskSummaryForCandidate(candidate) {
2262
2382
  }
2263
2383
  async function readViewerTasks(user) {
2264
2384
  const db = getDb();
2265
- const schedulerStore = createSchedulerSqlStore(db);
2266
2385
  const identityIds = new Set(user.identities.map((identity) => identity.id));
2267
2386
  const teamIds = viewerTeamIds(user);
2268
2387
  const [scheduledPage, publicScheduled, eventTasks, publicEventTasks] = await Promise.all([
2269
- createViewerScheduledTasks(schedulerStore, user).list({
2270
- limit: TASK_FETCH_LIMIT
2271
- }),
2388
+ listViewerScheduledTasks(db, user, { limit: TASK_FETCH_LIMIT }),
2272
2389
  listPublicScheduledTasksForTeams(db, teamIds, TASK_FETCH_LIMIT),
2273
2390
  listEventTasksCreatedBy(db, user, TASK_FETCH_LIMIT),
2274
2391
  listPublicEventTasksForTeams(db, teamIds, TASK_FETCH_LIMIT)
@@ -2450,10 +2567,7 @@ async function readConversationSourceTask(args) {
2450
2567
  async function deleteViewerTask(user, kind, id) {
2451
2568
  if (kind === "scheduled") {
2452
2569
  try {
2453
- await createViewerScheduledTasks(
2454
- createSchedulerSqlStore(getDb()),
2455
- user
2456
- ).delete(id);
2570
+ await deleteViewerScheduledTask(getDb(), user, id);
2457
2571
  return;
2458
2572
  } catch (error) {
2459
2573
  if (error instanceof PersonalScheduledTaskNotFoundError) {
@@ -2480,6 +2594,7 @@ function projectConversationDetail(args) {
2480
2594
  return {
2481
2595
  ...conversationSummaryFromStoredConversation({
2482
2596
  access: args.access,
2597
+ ...args.archivedAtMs === void 0 ? {} : { archivedAtMs: args.archivedAtMs },
2483
2598
  auxiliaryCosts: args.auxiliaryCosts,
2484
2599
  conversation,
2485
2600
  durationMs: args.durationMs,
@@ -2508,6 +2623,7 @@ function projectConversationDetail(args) {
2508
2623
  async function readConversationDetailFromSql(conversationId, options) {
2509
2624
  const record = await readConversationRecordFromSql(conversationId);
2510
2625
  if (!record) return void 0;
2626
+ const archivedAtMs = options.viewer ? await readConversationArchivedAt(options.viewer, conversationId) : void 0;
2511
2627
  const executor = getSqlExecutor();
2512
2628
  const includeDescendantMetrics = record.rootConversationId === conversationId;
2513
2629
  const [
@@ -2550,6 +2666,7 @@ async function readConversationDetailFromSql(conversationId, options) {
2550
2666
  return projectConversationDetail({
2551
2667
  ...record,
2552
2668
  access,
2669
+ ...archivedAtMs === void 0 ? {} : { archivedAtMs },
2553
2670
  annotations,
2554
2671
  auxiliaryCosts: auxiliaryCostsByConversation.get(conversationId),
2555
2672
  durationMs: metrics?.durationMs ?? record.durationMs,
@@ -2791,20 +2908,20 @@ async function requireConversationPendingMessages(conversationId, options = {})
2791
2908
  }
2792
2909
 
2793
2910
  // src/api/conversations/stats.query.ts
2794
- import { and as and9, eq as eq9, gte, isNull as isNull4, lte, sql as sql7 } from "drizzle-orm";
2911
+ import { and as and10, eq as eq10, gte, isNull as isNull4, lte, sql as sql10 } from "drizzle-orm";
2795
2912
  import { alias as alias3 } from "drizzle-orm/pg-core";
2796
2913
 
2797
2914
  // src/api/conversations/aggregate.ts
2798
- import { sql as sql6 } from "drizzle-orm";
2915
+ import { sql as sql9 } from "drizzle-orm";
2799
2916
  function usageTokenValue(source, field) {
2800
- return sql6`CASE
2917
+ return sql9`CASE
2801
2918
  WHEN ${source.usage}->>${field} IS NOT NULL
2802
2919
  THEN (${source.usage}->>${field})::double precision
2803
2920
  ELSE NULL
2804
2921
  END`;
2805
2922
  }
2806
2923
  function tokenValue(source) {
2807
- return sql6`
2924
+ return sql9`
2808
2925
  CASE
2809
2926
  WHEN COALESCE(
2810
2927
  ${source.usage}->>'inputTokens',
@@ -2823,7 +2940,7 @@ function tokenValue(source) {
2823
2940
  `;
2824
2941
  }
2825
2942
  function costValue(source) {
2826
- return sql6`
2943
+ return sql9`
2827
2944
  CASE
2828
2945
  WHEN ${source.usage}->'cost'->>'total' IS NOT NULL
2829
2946
  THEN (${source.usage}->'cost'->>'total')::double precision
@@ -2844,34 +2961,34 @@ function costValue(source) {
2844
2961
  function conversationAggregateColumns(sources) {
2845
2962
  const metrics = sources?.metrics ?? juniorConversations;
2846
2963
  const roots = sources?.roots ?? juniorConversations;
2847
- const conversationCount = sources ? sql6`COUNT(DISTINCT ${roots.conversationId})` : sql6`COUNT(*)`;
2964
+ const conversationCount = sources ? sql9`COUNT(DISTINCT ${roots.conversationId})` : sql9`COUNT(*)`;
2848
2965
  return {
2849
- active: sql6`${conversationCount} FILTER (
2966
+ active: sql9`${conversationCount} FILTER (
2850
2967
  WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
2851
2968
  )::integer`,
2852
- conversations: sql6`${conversationCount}::integer`,
2853
- cachedInputTokens: sql6`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
2854
- costUsd: sql6`SUM(${costValue(metrics)})::double precision`,
2855
- durationMs: sql6`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
2856
- failed: sql6`${conversationCount} FILTER (
2969
+ conversations: sql9`${conversationCount}::integer`,
2970
+ cachedInputTokens: sql9`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
2971
+ costUsd: sql9`SUM(${costValue(metrics)})::double precision`,
2972
+ durationMs: sql9`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
2973
+ failed: sql9`${conversationCount} FILTER (
2857
2974
  WHERE ${roots.executionStatus} = 'failed'
2858
2975
  )::integer`,
2859
- inputTokens: sql6`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
2860
- tokens: sql6`SUM(${tokenValue(metrics)})::double precision`
2976
+ inputTokens: sql9`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
2977
+ tokens: sql9`SUM(${tokenValue(metrics)})::double precision`
2861
2978
  };
2862
2979
  }
2863
2980
  function conversationRangeColumns() {
2864
2981
  return {
2865
- firstSeenAt: sql6`MIN(${juniorConversations.createdAt})`.mapWith(
2982
+ firstSeenAt: sql9`MIN(${juniorConversations.createdAt})`.mapWith(
2866
2983
  juniorConversations.createdAt
2867
2984
  ),
2868
- lastSeenAt: sql6`MAX(${juniorConversations.lastActivityAt})`.mapWith(
2985
+ lastSeenAt: sql9`MAX(${juniorConversations.lastActivityAt})`.mapWith(
2869
2986
  juniorConversations.lastActivityAt
2870
2987
  )
2871
2988
  };
2872
2989
  }
2873
2990
  function conversationActiveDaysColumn() {
2874
- return sql6`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
2991
+ return sql9`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
2875
2992
  }
2876
2993
 
2877
2994
  // src/api/conversations/stats.query.ts
@@ -2935,7 +3052,7 @@ function statsItems(map) {
2935
3052
  );
2936
3053
  }
2937
3054
  function statsWhere(start, end) {
2938
- return and9(
3055
+ return and10(
2939
3056
  isNull4(juniorConversations.parentConversationId),
2940
3057
  gte(juniorConversations.lastActivityAt, start),
2941
3058
  lte(juniorConversations.lastActivityAt, end)
@@ -3012,14 +3129,14 @@ function guardianStats(rows, endMs) {
3012
3129
  }
3013
3130
  async function aggregateStats(db, start, end) {
3014
3131
  const where = statsWhere(start, end);
3015
- const activityDate = sql7`TO_CHAR(
3132
+ const activityDate = sql10`TO_CHAR(
3016
3133
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
3017
3134
  'YYYY-MM-DD'
3018
3135
  )`;
3019
3136
  const [totalsRows, actorRows, locationRows, metricRows] = await Promise.all([
3020
3137
  db.select(treeAggregateColumns).from(juniorConversations).innerJoin(
3021
3138
  treeConversation,
3022
- eq9(
3139
+ eq10(
3023
3140
  treeConversation.rootConversationId,
3024
3141
  juniorConversations.conversationId
3025
3142
  )
@@ -3034,14 +3151,14 @@ async function aggregateStats(db, start, end) {
3034
3151
  ...treeAggregateColumns
3035
3152
  }).from(juniorConversations).innerJoin(
3036
3153
  treeConversation,
3037
- eq9(
3154
+ eq10(
3038
3155
  treeConversation.rootConversationId,
3039
3156
  juniorConversations.conversationId
3040
3157
  )
3041
3158
  ).leftJoin(
3042
3159
  juniorIdentities,
3043
- eq9(juniorIdentities.id, juniorConversations.actorIdentityId)
3044
- ).leftJoin(juniorUsers, eq9(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
3160
+ eq10(juniorIdentities.id, juniorConversations.actorIdentityId)
3161
+ ).leftJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
3045
3162
  juniorIdentities.displayName,
3046
3163
  juniorIdentities.emailNormalized,
3047
3164
  juniorIdentities.handle,
@@ -3059,13 +3176,13 @@ async function aggregateStats(db, start, end) {
3059
3176
  ...treeAggregateColumns
3060
3177
  }).from(juniorConversations).innerJoin(
3061
3178
  treeConversation,
3062
- eq9(
3179
+ eq10(
3063
3180
  treeConversation.rootConversationId,
3064
3181
  juniorConversations.conversationId
3065
3182
  )
3066
3183
  ).leftJoin(
3067
3184
  juniorDestinations,
3068
- eq9(juniorDestinations.id, juniorConversations.destinationId)
3185
+ eq10(juniorDestinations.id, juniorConversations.destinationId)
3069
3186
  ).where(where).groupBy(
3070
3187
  juniorConversations.channelName,
3071
3188
  juniorConversations.source,
@@ -3084,7 +3201,7 @@ async function aggregateStats(db, start, end) {
3084
3201
  tokens: treeAggregateColumns.tokens
3085
3202
  }).from(juniorConversations).innerJoin(
3086
3203
  treeConversation,
3087
- eq9(
3204
+ eq10(
3088
3205
  treeConversation.rootConversationId,
3089
3206
  juniorConversations.conversationId
3090
3207
  )
@@ -3093,26 +3210,26 @@ async function aggregateStats(db, start, end) {
3093
3210
  return { actorRows, locationRows, metricRows, totals: totalsRows[0] };
3094
3211
  }
3095
3212
  async function aggregateGuardianStats(db, start, end) {
3096
- const date = sql7`TO_CHAR(
3213
+ const date = sql10`TO_CHAR(
3097
3214
  ${juniorConversationEvents.createdAt} AT TIME ZONE 'UTC',
3098
3215
  'YYYY-MM-DD'
3099
3216
  )`;
3100
- const decision = sql7`${juniorConversationEvents.payload}->>'decision'`;
3101
- const cost2 = sql7`CASE
3217
+ const decision = sql10`${juniorConversationEvents.payload}->>'decision'`;
3218
+ const cost2 = sql10`CASE
3102
3219
  WHEN jsonb_typeof(${juniorConversationEvents.payload}->'costUsd') = 'number'
3103
3220
  THEN (${juniorConversationEvents.payload}->>'costUsd')::double precision
3104
3221
  ELSE NULL
3105
3222
  END`;
3106
3223
  return await db.select({
3107
- allow: sql7`COUNT(*) FILTER (WHERE ${decision} = 'allow')::integer`,
3108
- ask: sql7`COUNT(*) FILTER (WHERE ${decision} = 'ask')::integer`,
3109
- costUsd: sql7`SUM(${cost2})::double precision`,
3224
+ allow: sql10`COUNT(*) FILTER (WHERE ${decision} = 'allow')::integer`,
3225
+ ask: sql10`COUNT(*) FILTER (WHERE ${decision} = 'ask')::integer`,
3226
+ costUsd: sql10`SUM(${cost2})::double precision`,
3110
3227
  date,
3111
- deny: sql7`COUNT(*) FILTER (WHERE ${decision} = 'deny')::integer`,
3112
- requests: sql7`COUNT(*)::integer`
3228
+ deny: sql10`COUNT(*) FILTER (WHERE ${decision} = 'deny')::integer`,
3229
+ requests: sql10`COUNT(*)::integer`
3113
3230
  }).from(juniorConversationEvents).where(
3114
- and9(
3115
- eq9(juniorConversationEvents.type, "guardian_action_reviewed"),
3231
+ and10(
3232
+ eq10(juniorConversationEvents.type, "guardian_action_reviewed"),
3116
3233
  gte(juniorConversationEvents.createdAt, start),
3117
3234
  lte(juniorConversationEvents.createdAt, end)
3118
3235
  )
@@ -3230,6 +3347,7 @@ function createConversationRoutes(options) {
3230
3347
  );
3231
3348
  app.patch(
3232
3349
  "/:conversationId/archive",
3350
+ requireViewer,
3233
3351
  validateRequest(
3234
3352
  "param",
3235
3353
  conversationParamsSchema,
@@ -3241,11 +3359,12 @@ function createConversationRoutes(options) {
3241
3359
  "Invalid request body."
3242
3360
  ),
3243
3361
  async (context) => {
3362
+ const viewer = context.get("viewer");
3244
3363
  const { conversationId } = context.req.valid("param");
3245
3364
  const body = context.req.valid("json");
3246
3365
  return jsonResponse(
3247
3366
  archiveConversationResponseSchema,
3248
- await archiveConversation(conversationId, body)
3367
+ await archiveConversation(viewer, conversationId, body)
3249
3368
  );
3250
3369
  }
3251
3370
  );
@@ -3374,7 +3493,7 @@ function createConversationRoutes(options) {
3374
3493
  import { Hono as Hono2 } from "hono";
3375
3494
 
3376
3495
  // src/api/locations/query.ts
3377
- import { and as and10, asc as asc3, desc as desc3, eq as eq10, gte as gte2, isNull as isNull5, sql as sql8 } from "drizzle-orm";
3496
+ import { and as and11, asc as asc3, desc as desc4, eq as eq11, gte as gte2, isNull as isNull5, sql as sql11 } from "drizzle-orm";
3378
3497
  import { alias as alias4 } from "drizzle-orm/pg-core";
3379
3498
 
3380
3499
  // src/api/conversations/reporting.ts
@@ -3482,10 +3601,10 @@ function topLevelWhere() {
3482
3601
  return isNull5(juniorConversations.parentConversationId);
3483
3602
  }
3484
3603
  function publicLocationWhere(destinationId) {
3485
- return and10(
3604
+ return and11(
3486
3605
  topLevelWhere(),
3487
- eq10(juniorDestinations.id, destinationId),
3488
- eq10(juniorDestinations.visibility, "public")
3606
+ eq11(juniorDestinations.id, destinationId),
3607
+ eq11(juniorDestinations.visibility, "public")
3489
3608
  );
3490
3609
  }
3491
3610
  function locationColumns() {
@@ -3536,28 +3655,28 @@ async function directoryRows(db) {
3536
3655
  ...conversationRangeColumns()
3537
3656
  }).from(juniorConversations).innerJoin(
3538
3657
  treeConversation2,
3539
- eq10(
3658
+ eq11(
3540
3659
  treeConversation2.rootConversationId,
3541
3660
  juniorConversations.conversationId
3542
3661
  )
3543
3662
  ).leftJoin(
3544
3663
  juniorDestinations,
3545
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3664
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3546
3665
  ).where(topLevelWhere()).groupBy(...locationGroupBy());
3547
3666
  }
3548
3667
  async function directoryActivityRows(db, start) {
3549
- const date = sql8`TO_CHAR(
3668
+ const date = sql11`TO_CHAR(
3550
3669
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
3551
3670
  'YYYY-MM-DD'
3552
3671
  )`;
3553
3672
  return db.select({
3554
- conversations: sql8`COUNT(*)::integer`,
3673
+ conversations: sql11`COUNT(*)::integer`,
3555
3674
  date,
3556
3675
  visibility: juniorDestinations.visibility
3557
3676
  }).from(juniorConversations).leftJoin(
3558
3677
  juniorDestinations,
3559
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3560
- ).where(and10(topLevelWhere(), gte2(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
3678
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3679
+ ).where(and11(topLevelWhere(), gte2(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
3561
3680
  }
3562
3681
  function directoryActivityDays(rows, nowMs) {
3563
3682
  const days = /* @__PURE__ */ new Map();
@@ -3630,7 +3749,7 @@ async function recentLocationRows(db, locationId) {
3630
3749
  createdAt: juniorConversations.createdAt,
3631
3750
  destinationId: juniorDestinations.id,
3632
3751
  durationMs: juniorConversations.durationMs,
3633
- email: sql8`COALESCE(
3752
+ email: sql11`COALESCE(
3634
3753
  ${juniorUsers.primaryEmailNormalized},
3635
3754
  ${juniorIdentities.email}
3636
3755
  )`,
@@ -3639,7 +3758,7 @@ async function recentLocationRows(db, locationId) {
3639
3758
  fullName: juniorUsers.displayName,
3640
3759
  handle: juniorIdentities.handle,
3641
3760
  lastActivityAt: juniorConversations.lastActivityAt,
3642
- providerSubjectId: sql8`CASE
3761
+ providerSubjectId: sql11`CASE
3643
3762
  WHEN ${juniorIdentities.provider} = 'slack'
3644
3763
  THEN ${juniorIdentities.providerSubjectId}
3645
3764
  ELSE NULL
@@ -3650,17 +3769,12 @@ async function recentLocationRows(db, locationId) {
3650
3769
  usage: juniorConversations.usage
3651
3770
  }).from(juniorConversations).innerJoin(
3652
3771
  juniorDestinations,
3653
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3772
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3654
3773
  ).leftJoin(
3655
3774
  juniorIdentities,
3656
- eq10(juniorIdentities.id, juniorConversations.actorIdentityId)
3657
- ).leftJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(
3658
- and10(
3659
- publicLocationWhere(locationId),
3660
- isNull5(juniorConversations.archivedAt)
3661
- )
3662
- ).orderBy(
3663
- desc3(juniorConversations.lastActivityAt),
3775
+ eq11(juniorIdentities.id, juniorConversations.actorIdentityId)
3776
+ ).leftJoin(juniorUsers, eq11(juniorUsers.id, juniorIdentities.userId)).where(publicLocationWhere(locationId)).orderBy(
3777
+ desc4(juniorConversations.lastActivityAt),
3664
3778
  asc3(juniorConversations.conversationId)
3665
3779
  ).limit(RECENT_LIMIT);
3666
3780
  }
@@ -3671,7 +3785,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3671
3785
  const start = new Date(end);
3672
3786
  start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
3673
3787
  const where = publicLocationWhere(locationId);
3674
- const activityDate = sql8`TO_CHAR(
3788
+ const activityDate = sql11`TO_CHAR(
3675
3789
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
3676
3790
  'YYYY-MM-DD'
3677
3791
  )`;
@@ -3682,27 +3796,27 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3682
3796
  ...conversationRangeColumns()
3683
3797
  }).from(juniorConversations).innerJoin(
3684
3798
  treeConversation2,
3685
- eq10(
3799
+ eq11(
3686
3800
  treeConversation2.rootConversationId,
3687
3801
  juniorConversations.conversationId
3688
3802
  )
3689
3803
  ).innerJoin(
3690
3804
  juniorDestinations,
3691
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3805
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3692
3806
  ).where(where).groupBy(...locationGroupBy()),
3693
3807
  getDb().select({
3694
3808
  date: activityDate,
3695
3809
  ...treeAggregateColumns2
3696
3810
  }).from(juniorConversations).innerJoin(
3697
3811
  treeConversation2,
3698
- eq10(
3812
+ eq11(
3699
3813
  treeConversation2.rootConversationId,
3700
3814
  juniorConversations.conversationId
3701
3815
  )
3702
3816
  ).innerJoin(
3703
3817
  juniorDestinations,
3704
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3705
- ).where(and10(where, gte2(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
3818
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3819
+ ).where(and11(where, gte2(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
3706
3820
  getDb().select({
3707
3821
  actorIdentityId: juniorConversations.actorIdentityId,
3708
3822
  email: juniorUsers.primaryEmailNormalized,
@@ -3714,17 +3828,17 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3714
3828
  ...treeAggregateColumns2
3715
3829
  }).from(juniorConversations).innerJoin(
3716
3830
  treeConversation2,
3717
- eq10(
3831
+ eq11(
3718
3832
  treeConversation2.rootConversationId,
3719
3833
  juniorConversations.conversationId
3720
3834
  )
3721
3835
  ).innerJoin(
3722
3836
  juniorDestinations,
3723
- eq10(juniorDestinations.id, juniorConversations.destinationId)
3837
+ eq11(juniorDestinations.id, juniorConversations.destinationId)
3724
3838
  ).leftJoin(
3725
3839
  juniorIdentities,
3726
- eq10(juniorIdentities.id, juniorConversations.actorIdentityId)
3727
- ).leftJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
3840
+ eq11(juniorIdentities.id, juniorConversations.actorIdentityId)
3841
+ ).leftJoin(juniorUsers, eq11(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
3728
3842
  juniorConversations.actorIdentityId,
3729
3843
  juniorUsers.primaryEmailNormalized,
3730
3844
  juniorUsers.displayName,
@@ -3837,10 +3951,10 @@ function createLocationRoutes() {
3837
3951
  import { Hono as Hono3 } from "hono";
3838
3952
 
3839
3953
  // src/api/people/list.query.ts
3840
- import { and as and12, eq as eq12, gte as gte3, sql as sql10 } from "drizzle-orm";
3954
+ import { and as and13, eq as eq13, gte as gte3, sql as sql13 } from "drizzle-orm";
3841
3955
 
3842
3956
  // src/api/people/shared.ts
3843
- import { and as and11, asc as asc4, desc as desc4, eq as eq11, isNull as isNull6, notExists, or as or4, sql as sql9 } from "drizzle-orm";
3957
+ import { and as and12, asc as asc4, desc as desc5, eq as eq12, isNull as isNull6, notExists, or as or5, sql as sql12 } from "drizzle-orm";
3844
3958
  import { alias as alias5 } from "drizzle-orm/pg-core";
3845
3959
  var RECENT_LIMIT2 = 25;
3846
3960
  var ACTIVITY_DAYS2 = 365;
@@ -3860,37 +3974,37 @@ var peopleTreeAggregateColumns = conversationAggregateColumns({
3860
3974
  function peopleTreeMetricsJoin() {
3861
3975
  const rootOwnedByActor = getDb().select({ conversationId: peopleRootConversation.conversationId }).from(peopleRootConversation).innerJoin(
3862
3976
  peopleRootIdentity,
3863
- eq11(peopleRootIdentity.id, peopleRootConversation.actorIdentityId)
3977
+ eq12(peopleRootIdentity.id, peopleRootConversation.actorIdentityId)
3864
3978
  ).where(
3865
- and11(
3866
- eq11(
3979
+ and12(
3980
+ eq12(
3867
3981
  peopleRootConversation.conversationId,
3868
3982
  juniorConversations.rootConversationId
3869
3983
  ),
3870
3984
  isNull6(peopleRootConversation.parentConversationId),
3871
- eq11(
3985
+ eq12(
3872
3986
  peopleRootConversation.rootConversationId,
3873
3987
  peopleRootConversation.conversationId
3874
3988
  ),
3875
- eq11(
3989
+ eq12(
3876
3990
  peopleRootIdentity.emailNormalized,
3877
3991
  juniorUsers.primaryEmailNormalized
3878
3992
  ),
3879
- eq11(peopleRootIdentity.emailVerified, true)
3993
+ eq12(peopleRootIdentity.emailVerified, true)
3880
3994
  )
3881
3995
  );
3882
- return and11(
3883
- eq11(
3996
+ return and12(
3997
+ eq12(
3884
3998
  peopleTreeConversation.rootConversationId,
3885
3999
  juniorConversations.rootConversationId
3886
4000
  ),
3887
- or4(
3888
- eq11(
4001
+ or5(
4002
+ eq12(
3889
4003
  juniorConversations.rootConversationId,
3890
4004
  juniorConversations.conversationId
3891
4005
  ),
3892
- and11(
3893
- eq11(
4006
+ and12(
4007
+ eq12(
3894
4008
  peopleTreeConversation.conversationId,
3895
4009
  juniorConversations.conversationId
3896
4010
  ),
@@ -3940,11 +4054,11 @@ function statsItems2(map) {
3940
4054
  }
3941
4055
  function verifiedActorWhere(email) {
3942
4056
  const normalizedEmail = normalizeEmail(email);
3943
- return and11(
3944
- eq11(juniorIdentities.provider, "slack"),
3945
- eq11(juniorIdentities.emailVerified, true),
3946
- sql9`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
3947
- normalizedEmail ? eq11(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
4057
+ return and12(
4058
+ eq12(juniorIdentities.provider, "slack"),
4059
+ eq12(juniorIdentities.emailVerified, true),
4060
+ sql12`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
4061
+ normalizedEmail ? eq12(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
3948
4062
  );
3949
4063
  }
3950
4064
  async function recentActorRows(email) {
@@ -3967,14 +4081,12 @@ async function recentActorRows(email) {
3967
4081
  usage: juniorConversations.usage
3968
4082
  }).from(juniorConversations).innerJoin(
3969
4083
  juniorIdentities,
3970
- eq11(juniorIdentities.id, juniorConversations.actorIdentityId)
3971
- ).innerJoin(juniorUsers, eq11(juniorUsers.id, juniorIdentities.userId)).leftJoin(
4084
+ eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
4085
+ ).innerJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).leftJoin(
3972
4086
  juniorDestinations,
3973
- eq11(juniorDestinations.id, juniorConversations.destinationId)
3974
- ).where(
3975
- and11(verifiedActorWhere(email), isNull6(juniorConversations.archivedAt))
3976
- ).orderBy(
3977
- desc4(juniorConversations.lastActivityAt),
4087
+ eq12(juniorDestinations.id, juniorConversations.destinationId)
4088
+ ).where(verifiedActorWhere(email)).orderBy(
4089
+ desc5(juniorConversations.lastActivityAt),
3978
4090
  asc4(juniorConversations.conversationId)
3979
4091
  ).limit(RECENT_LIMIT2);
3980
4092
  }
@@ -4001,7 +4113,7 @@ function directoryActivityDays2(rows, nowMs) {
4001
4113
  async function readPeopleListFromSql() {
4002
4114
  const nowMs = Date.now();
4003
4115
  const { end, start } = activityWindow(nowMs);
4004
- const activityDate = sql10`TO_CHAR(
4116
+ const activityDate = sql13`TO_CHAR(
4005
4117
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
4006
4118
  'YYYY-MM-DD'
4007
4119
  )`;
@@ -4009,24 +4121,24 @@ async function readPeopleListFromSql() {
4009
4121
  getDb().select({
4010
4122
  email: juniorUsers.primaryEmailNormalized,
4011
4123
  fullName: juniorUsers.displayName,
4012
- slackUserId: sql10`MAX(${juniorIdentities.providerSubjectId})`,
4013
- slackUserName: sql10`MAX(${juniorIdentities.handle})`,
4124
+ slackUserId: sql13`MAX(${juniorIdentities.providerSubjectId})`,
4125
+ slackUserName: sql13`MAX(${juniorIdentities.handle})`,
4014
4126
  activeDays: conversationActiveDaysColumn(),
4015
4127
  ...peopleTreeAggregateColumns,
4016
4128
  ...conversationRangeColumns()
4017
4129
  }).from(juniorConversations).innerJoin(
4018
4130
  juniorIdentities,
4019
- eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
4020
- ).innerJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, peopleTreeMetricsJoin()).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
4131
+ eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4132
+ ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, peopleTreeMetricsJoin()).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
4021
4133
  getDb().select({
4022
- activePeople: sql10`COUNT(DISTINCT ${juniorUsers.id})::int`,
4023
- conversations: sql10`COUNT(*)::int`,
4134
+ activePeople: sql13`COUNT(DISTINCT ${juniorUsers.id})::int`,
4135
+ conversations: sql13`COUNT(*)::int`,
4024
4136
  date: activityDate
4025
4137
  }).from(juniorConversations).innerJoin(
4026
4138
  juniorIdentities,
4027
- eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
4028
- ).innerJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).where(
4029
- and12(
4139
+ eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4140
+ ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).where(
4141
+ and13(
4030
4142
  verifiedActorWhere(),
4031
4143
  gte3(juniorConversations.lastActivityAt, start)
4032
4144
  )
@@ -4079,7 +4191,7 @@ async function readPeoplePluginReports(args) {
4079
4191
  source: "plugins"
4080
4192
  });
4081
4193
  }
4082
- const { getPluginProfileReports } = await import("./agent-hooks-IYHCN7CO.js");
4194
+ const { getPluginProfileReports } = await import("./agent-hooks-32IDCLMW.js");
4083
4195
  return pluginOperationalReportFeedSchema.parse({
4084
4196
  generatedAt: new Date(nowMs).toISOString(),
4085
4197
  reports: await getPluginProfileReports({
@@ -4092,7 +4204,7 @@ async function readPeoplePluginReports(args) {
4092
4204
  }
4093
4205
 
4094
4206
  // src/api/people/profile.query.ts
4095
- import { and as and13, eq as eq13, gte as gte4, sql as sql11 } from "drizzle-orm";
4207
+ import { and as and14, eq as eq14, gte as gte4, sql as sql14 } from "drizzle-orm";
4096
4208
  function emptyProfile(email, nowMs) {
4097
4209
  const end = new Date(nowMs);
4098
4210
  end.setUTCHours(0, 0, 0, 0);
@@ -4127,7 +4239,7 @@ function addAggregate2(map, label, row) {
4127
4239
  map.set(label, item);
4128
4240
  }
4129
4241
  function surfaceExpression() {
4130
- return sql11`CASE
4242
+ return sql14`CASE
4131
4243
  WHEN ${juniorConversations.source} IN ('api', 'scheduler', 'slack')
4132
4244
  THEN ${juniorConversations.source}
4133
4245
  WHEN ${juniorConversations.conversationId} LIKE 'slack:%' THEN 'slack'
@@ -4156,30 +4268,30 @@ async function readPeopleProfileFromSql(email, options = {}) {
4156
4268
  const where = verifiedActorWhere(normalizedEmail);
4157
4269
  const metricsJoin = peopleTreeMetricsJoin();
4158
4270
  const surface = surfaceExpression();
4159
- const activityDate = sql11`TO_CHAR(
4271
+ const activityDate = sql14`TO_CHAR(
4160
4272
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
4161
4273
  'YYYY-MM-DD'
4162
4274
  )`;
4163
- const channel = sql11`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
4275
+ const channel = sql14`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
4164
4276
  const [totalsRows, dayRows, locationRows, surfaceRows, recentRows] = await Promise.all([
4165
4277
  getDb().select({
4166
4278
  email: juniorUsers.primaryEmailNormalized,
4167
4279
  fullName: juniorUsers.displayName,
4168
- slackUserId: sql11`MAX(${juniorIdentities.providerSubjectId})`,
4169
- slackUserName: sql11`MAX(${juniorIdentities.handle})`,
4280
+ slackUserId: sql14`MAX(${juniorIdentities.providerSubjectId})`,
4281
+ slackUserName: sql14`MAX(${juniorIdentities.handle})`,
4170
4282
  activeDays: conversationActiveDaysColumn(),
4171
4283
  ...peopleTreeAggregateColumns
4172
4284
  }).from(juniorConversations).innerJoin(
4173
4285
  juniorIdentities,
4174
- eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4175
- ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
4286
+ eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
4287
+ ).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
4176
4288
  getDb().select({
4177
4289
  date: activityDate,
4178
4290
  ...peopleTreeAggregateColumns
4179
4291
  }).from(juniorConversations).innerJoin(
4180
4292
  juniorIdentities,
4181
- eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4182
- ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(and13(where, gte4(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
4293
+ eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
4294
+ ).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(and14(where, gte4(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
4183
4295
  getDb().select({
4184
4296
  channel,
4185
4297
  channelName: juniorConversations.channelName,
@@ -4188,10 +4300,10 @@ async function readPeopleProfileFromSql(email, options = {}) {
4188
4300
  ...peopleTreeAggregateColumns
4189
4301
  }).from(juniorConversations).innerJoin(
4190
4302
  juniorIdentities,
4191
- eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4192
- ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).leftJoin(
4303
+ eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
4304
+ ).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).leftJoin(
4193
4305
  juniorDestinations,
4194
- eq13(juniorDestinations.id, juniorConversations.destinationId)
4306
+ eq14(juniorDestinations.id, juniorConversations.destinationId)
4195
4307
  ).where(where).groupBy(
4196
4308
  channel,
4197
4309
  juniorConversations.channelName,
@@ -4200,8 +4312,8 @@ async function readPeopleProfileFromSql(email, options = {}) {
4200
4312
  ),
4201
4313
  getDb().select({ surface, ...peopleTreeAggregateColumns }).from(juniorConversations).innerJoin(
4202
4314
  juniorIdentities,
4203
- eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
4204
- ).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(surface),
4315
+ eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
4316
+ ).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(surface),
4205
4317
  recentActorRows(normalizedEmail)
4206
4318
  ]);
4207
4319
  const totalsRow = totalsRows[0];
@@ -4279,7 +4391,7 @@ async function readPeopleProfile(email, options = {}) {
4279
4391
  }
4280
4392
 
4281
4393
  // src/api/people/spend.query.ts
4282
- import { and as and14, eq as eq14, gte as gte5, lte as lte2, sql as sql12 } from "drizzle-orm";
4394
+ import { and as and15, eq as eq15, gte as gte5, lte as lte2, sql as sql15 } from "drizzle-orm";
4283
4395
  var SEVEN_DAY_OFFSET = 6;
4284
4396
  var THIRTY_DAY_OFFSET = 29;
4285
4397
  function addUsd2(current, next) {
@@ -4298,7 +4410,7 @@ function spendWindow(nowMs) {
4298
4410
  async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
4299
4411
  const normalizedEmail = normalizeEmail(email);
4300
4412
  const { end, sevenDayStart, thirtyDayStart } = spendWindow(nowMs);
4301
- const activityDate = sql12`TO_CHAR(
4413
+ const activityDate = sql15`TO_CHAR(
4302
4414
  ${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
4303
4415
  'YYYY-MM-DD'
4304
4416
  )`;
@@ -4308,9 +4420,9 @@ async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
4308
4420
  date: activityDate
4309
4421
  }).from(juniorConversations).innerJoin(
4310
4422
  juniorIdentities,
4311
- eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
4312
- ).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(
4313
- and14(
4423
+ eq15(juniorIdentities.id, juniorConversations.actorIdentityId)
4424
+ ).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(
4425
+ and15(
4314
4426
  verifiedActorWhere(normalizedEmail),
4315
4427
  gte5(juniorConversations.lastActivityAt, thirtyDayStart),
4316
4428
  lte2(juniorConversations.lastActivityAt, end)
@@ -4798,7 +4910,7 @@ function readDescriptionText(home) {
4798
4910
  }
4799
4911
  }
4800
4912
  async function readSkillReports() {
4801
- const { discoverSkills } = await import("./skills-ZADWFKDG.js");
4913
+ const { discoverSkills } = await import("./skills-U545HALM.js");
4802
4914
  const skills = await discoverSkills();
4803
4915
  return skillReportsSchema.parse(
4804
4916
  skills.map((skill) => ({
@@ -4808,7 +4920,7 @@ async function readSkillReports() {
4808
4920
  );
4809
4921
  }
4810
4922
  async function readPlugins() {
4811
- const { pluginCatalogRuntime } = await import("./catalog-runtime-2TD4CXSB.js");
4923
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-FBVA6WAQ.js");
4812
4924
  return pluginsSchema.parse(
4813
4925
  pluginCatalogRuntime.getProviders().map((plugin) => ({
4814
4926
  configKeys: plugin.manifest.configKeys ?? [],
@@ -4821,7 +4933,7 @@ async function readPlugins() {
4821
4933
  async function readRuntimeInfoReport() {
4822
4934
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
4823
4935
  import("./discovery-GUFTFBTL.js"),
4824
- import("./catalog-runtime-2TD4CXSB.js"),
4936
+ import("./catalog-runtime-FBVA6WAQ.js"),
4825
4937
  readPlugins(),
4826
4938
  readSkillReports()
4827
4939
  ]);
@@ -4837,7 +4949,7 @@ async function readRuntimeInfoReport() {
4837
4949
  }
4838
4950
  async function readPluginOperationalReportFeed() {
4839
4951
  const nowMs = Date.now();
4840
- const { getPluginOperationalReports } = await import("./agent-hooks-IYHCN7CO.js");
4952
+ const { getPluginOperationalReports } = await import("./agent-hooks-32IDCLMW.js");
4841
4953
  return pluginOperationalReportFeedSchema.parse({
4842
4954
  source: "plugins",
4843
4955
  generatedAt: new Date(nowMs).toISOString(),