@sentry/junior 0.147.0 → 0.148.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 (155) hide show
  1. package/dist/{agent-hooks-HS6VGUPM.js → agent-hooks-VAUYT6PD.js} +10 -10
  2. package/dist/api/conversations/access.d.ts +2 -1
  3. package/dist/api/conversations/archive.d.ts +3 -5
  4. package/dist/api/conversations/create.d.ts +6 -0
  5. package/dist/api/conversations/detail.d.ts +2 -296
  6. package/dist/api/conversations/event-list.d.ts +2 -193
  7. package/dist/api/conversations/list.d.ts +4 -66
  8. package/dist/api/conversations/routes.d.ts +1 -1
  9. package/dist/api/conversations/stats.d.ts +0 -54
  10. package/dist/api/http.d.ts +2 -6
  11. package/dist/api/locations/detail.d.ts +3 -111
  12. package/dist/api/locations/list.d.ts +0 -45
  13. package/dist/api/locations/query.d.ts +2 -1
  14. package/dist/api/locations/routes.d.ts +1 -1
  15. package/dist/api/people/list.d.ts +0 -29
  16. package/dist/api/people/profile.d.ts +2 -106
  17. package/dist/api/people/profile.query.d.ts +2 -1
  18. package/dist/api/people/routes.d.ts +1 -1
  19. package/dist/api/people/shared.d.ts +1 -1
  20. package/dist/api/people/spend.d.ts +3 -4
  21. package/dist/api/personal-tokens/routes.d.ts +2 -2
  22. package/dist/api/route.d.ts +8 -14
  23. package/dist/api/schema/conversation.d.ts +60 -29
  24. package/dist/api/schema/location.d.ts +4 -0
  25. package/dist/api/schema/person.d.ts +7 -3
  26. package/dist/api/schema.d.ts +2 -2
  27. package/dist/api/schema.js +7 -1
  28. package/dist/api/stats.d.ts +0 -13
  29. package/dist/api/validation.d.ts +7 -0
  30. package/dist/api/viewer.d.ts +3 -0
  31. package/dist/api.d.ts +2 -1
  32. package/dist/api.js +624 -562
  33. package/dist/app.js +183 -105
  34. package/dist/{catalog-runtime-M6ZTPYRV.js → catalog-runtime-WADOZVTB.js} +5 -5
  35. package/dist/chat/actor.d.ts +4 -1
  36. package/dist/chat/agent/request.d.ts +2 -0
  37. package/dist/chat/agent/resume.d.ts +1 -0
  38. package/dist/chat/agent-dispatch/context.d.ts +2 -2
  39. package/dist/chat/agent-invocations/types.d.ts +52 -0
  40. package/dist/chat/api-turns/work.d.ts +103 -0
  41. package/dist/chat/conversations/history.d.ts +60 -0
  42. package/dist/chat/conversations/provenance.d.ts +6 -0
  43. package/dist/chat/conversations/sql/actor-identity.d.ts +19 -0
  44. package/dist/chat/conversations/store.d.ts +1 -1
  45. package/dist/chat/resource-events/store.d.ts +1 -1
  46. package/dist/chat/runtime/reply-executor.d.ts +1 -1
  47. package/dist/chat/runtime/slack-runtime.d.ts +2 -1
  48. package/dist/chat/runtime/turn-preparation.d.ts +9 -0
  49. package/dist/chat/scheduled-tasks/tool-support.d.ts +5 -5
  50. package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -2
  51. package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -2
  52. package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -2
  53. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -2
  54. package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -2
  55. package/dist/chat/slack/channel.d.ts +26 -0
  56. package/dist/chat/slack/dispatch-turn.d.ts +1 -0
  57. package/dist/chat/slack/timestamp-param.d.ts +0 -2
  58. package/dist/chat/slack/{tools → tool-support}/canvas/api.d.ts +1 -1
  59. package/dist/chat/slack/{tools → tool-support}/canvas/context.d.ts +3 -0
  60. package/dist/chat/slack/tool-support/channel-access.d.ts +42 -0
  61. package/dist/chat/slack/tool-support/channel-target.d.ts +27 -0
  62. package/dist/chat/slack/tool-support/list/params.d.ts +5 -0
  63. package/dist/chat/slack/tools/canvas/create.d.ts +1 -1
  64. package/dist/chat/slack/tools/channel-join.d.ts +28 -0
  65. package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -2
  66. package/dist/chat/slack/tools/conversation-message-search.d.ts +2 -8
  67. package/dist/chat/slack/tools/message-add-reaction.d.ts +1 -1
  68. package/dist/chat/slack/tools/public-search.d.ts +63 -2
  69. package/dist/chat/slack/tools/send-files.d.ts +1 -1
  70. package/dist/chat/slack/tools/thread-read.d.ts +2 -5
  71. package/dist/chat/source.d.ts +2 -0
  72. package/dist/chat/task-execution/checkpoint.d.ts +1 -0
  73. package/dist/chat/task-execution/state.d.ts +9 -4
  74. package/dist/chat/task-execution/store.d.ts +3 -2
  75. package/dist/chat/task-execution/turn-cursor.d.ts +2 -0
  76. package/dist/chat/task-execution/worker.d.ts +2 -0
  77. package/dist/chat/tasks/read.d.ts +1 -1
  78. package/dist/chat/tools/search-conversation-events.d.ts +1 -1
  79. package/dist/chat/tools/types.d.ts +11 -4
  80. package/dist/chat/tools/watch-resource-events.d.ts +2 -2
  81. package/dist/{chunk-ORO3PWKQ.js → chunk-2B3PT3V2.js} +1 -1
  82. package/dist/{chunk-SVHUEHUL.js → chunk-45LOR4PU.js} +21 -4
  83. package/dist/{chunk-YBVXBNSV.js → chunk-4AQZYNHM.js} +2 -2
  84. package/dist/{chunk-Z4YU7Z4L.js → chunk-4EA2SFK2.js} +65 -4
  85. package/dist/{chunk-7NVJVJID.js → chunk-4GXJUYJV.js} +2 -2
  86. package/dist/{chunk-IIOOO4FQ.js → chunk-55F4QU2V.js} +2 -1
  87. package/dist/{chunk-745QJ3ZA.js → chunk-7OEIXFC3.js} +2 -2
  88. package/dist/{chunk-DU74WPIC.js → chunk-D3WPMGEX.js} +1 -1
  89. package/dist/{chunk-PVNG6UMU.js → chunk-D6YX4NNN.js} +22 -10
  90. package/dist/chunk-DUY5CDAM.js +36 -0
  91. package/dist/{chunk-4LJO56OJ.js → chunk-EAI67NTM.js} +1 -1
  92. package/dist/{chunk-X5UY34KT.js → chunk-EINWQFXI.js} +8 -8
  93. package/dist/chunk-GDFF3BQG.js +136 -0
  94. package/dist/{chunk-EFLJ2WJH.js → chunk-GXYDVZKM.js} +5 -5
  95. package/dist/{chunk-CWP5RHVX.js → chunk-HLPLT3NY.js} +8 -5
  96. package/dist/{chunk-JUUKWRBE.js → chunk-HWQGBIH7.js} +1 -1
  97. package/dist/{chunk-AZ7EAOBE.js → chunk-IL4EDBMV.js} +5 -5
  98. package/dist/{chunk-DLDRQHG5.js → chunk-LAZGHEYU.js} +1 -1
  99. package/dist/{chunk-RXBVB2JM.js → chunk-LE5H7LMT.js} +1 -1
  100. package/dist/chunk-LNVEIJ2L.js +48 -0
  101. package/dist/{chunk-YEO3VX72.js → chunk-OJCP3C3J.js} +8 -6
  102. package/dist/{chunk-GGB4WL5A.js → chunk-POSZWRGL.js} +1 -1
  103. package/dist/{chunk-YNTTROJT.js → chunk-QOWHHM3F.js} +1 -1
  104. package/dist/{chunk-6H5SZR24.js → chunk-RRJV5UR5.js} +302 -59
  105. package/dist/{chunk-AYU72WO7.js → chunk-ULAU5ZGU.js} +41 -64
  106. package/dist/{chunk-SGZO7UWH.js → chunk-V2FXMOEA.js} +2 -2
  107. package/dist/{chunk-AIOK6LAG.js → chunk-VCYSOXON.js} +272 -41
  108. package/dist/{chunk-7A4M7PCV.js → chunk-VMNRXKAH.js} +1166 -540
  109. package/dist/{chunk-YSB2N563.js → chunk-VRHTNBA6.js} +121 -87
  110. package/dist/{chunk-AVZDSUFB.js → chunk-VY6W3T43.js} +4 -4
  111. package/dist/{chunk-7UQIVT6G.js → chunk-WCN4YSH7.js} +6 -6
  112. package/dist/{chunk-CSZINQJ2.js → chunk-WOONT5ZP.js} +1 -1
  113. package/dist/{chunk-Q4R73I43.js → chunk-XJ42NBP5.js} +58 -28
  114. package/dist/{chunk-YHDERDRO.js → chunk-ZCHIC2GM.js} +91 -75
  115. package/dist/chunk-ZPL2RR7F.js +798 -0
  116. package/dist/cli/chat.js +33 -35
  117. package/dist/cli/check.js +6 -6
  118. package/dist/cli/plugins.js +13 -13
  119. package/dist/cli/snapshot-create.js +9 -9
  120. package/dist/cli/upgrade.js +7 -7
  121. package/dist/db/schema/agent-invocations.d.ts +20 -0
  122. package/dist/db/schema/conversation-annotations.d.ts +2 -2
  123. package/dist/db/schema.d.ts +22 -2
  124. package/dist/{db-CSEW4RII.js → db-XUKZRFFK.js} +7 -7
  125. package/dist/instrumentation.js +4 -4
  126. package/dist/nitro.js +2 -2
  127. package/dist/{oauth-callback-server-FUEV5HNG.js → oauth-callback-server-LPZMMGFI.js} +25 -26
  128. package/dist/{runner-U3XHSKSH.js → runner-DGKUTMPX.js} +17 -18
  129. package/dist/{skills-AKE6W3WI.js → skills-P7YUFSXM.js} +6 -6
  130. package/dist/spawn-DSK3ZEVD.js +38 -0
  131. package/dist/{validation-WDTAULUF.js → validation-S7U5M5NR.js} +6 -6
  132. package/dist/version.js +1 -1
  133. package/dist/{work-C3HAO2BG.js → work-GAA7TVAD.js} +18 -19
  134. package/dist/{worker-LNP4YKBM.js → worker-JXPJH3QB.js} +11 -10
  135. package/package.json +5 -4
  136. package/dist/api/health.d.ts +0 -7
  137. package/dist/api/personal-tokens/create.d.ts +0 -11
  138. package/dist/api/personal-tokens/list.d.ts +0 -12
  139. package/dist/api/personal-tokens/revoke.d.ts +0 -5
  140. package/dist/api/plugin-reports.d.ts +0 -63
  141. package/dist/api/plugins.d.ts +0 -8
  142. package/dist/api/runtime.d.ts +0 -24
  143. package/dist/api/skills.d.ts +0 -6
  144. package/dist/chat/slack/tools/channel-access.d.ts +0 -30
  145. package/dist/chunk-34GS7B6L.js +0 -115
  146. package/dist/chunk-AVOCH2Z5.js +0 -285
  147. package/dist/chunk-HLXXQI5Q.js +0 -238
  148. package/dist/chunk-K4SZAP3K.js +0 -67
  149. package/dist/chunk-R776HKPK.js +0 -81
  150. package/dist/spawn-B6GDTWJ4.js +0 -39
  151. /package/dist/chat/slack/{tools → tool-support}/canvas/markdown.d.ts +0 -0
  152. /package/dist/chat/slack/{tools → tool-support}/channel-capabilities.d.ts +0 -0
  153. /package/dist/chat/slack/{tools → tool-support}/context.d.ts +0 -0
  154. /package/dist/chat/slack/{tools → tool-support}/list/api.d.ts +0 -0
  155. /package/dist/chat/slack/{tools → tool-support}/slack-message-url.d.ts +0 -0
package/dist/api.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ acceptedConversationMessageSchema,
2
3
  activityDays,
3
4
  actorDirectoryReportSchema,
4
5
  actorProfileReportSchema,
@@ -14,6 +15,8 @@ import {
14
15
  conversationParamsSchema,
15
16
  conversationReportEventSchema,
16
17
  conversationStatsReportSchema,
18
+ createConversationBodySchema,
19
+ createConversationMessageBodySchema,
17
20
  createPersonalTokenBodySchema,
18
21
  createdPersonalTokenSchema,
19
22
  locationDetailReportSchema,
@@ -29,15 +32,19 @@ import {
29
32
  taskListSchema,
30
33
  taskParamsSchema,
31
34
  taskRunListSchema
32
- } from "./chunk-SVHUEHUL.js";
35
+ } from "./chunk-45LOR4PU.js";
33
36
  import {
37
+ appendAndEnqueueApiConversationMessage,
38
+ createAndEnqueueApiConversation,
34
39
  formatSlackConversationRedactedLabel,
35
40
  readHealthReport,
36
- resolveSlackConversationContextFromThreadId
37
- } from "./chunk-34GS7B6L.js";
41
+ resolveSlackConversationContextFromThreadId,
42
+ webActorFromEmail
43
+ } from "./chunk-ZPL2RR7F.js";
38
44
  import {
39
45
  buildSentryConversationUrl
40
46
  } from "./chunk-4CODA7P5.js";
47
+ import "./chunk-HLPLT3NY.js";
41
48
  import {
42
49
  readTaskExecutionByConversationId,
43
50
  readTaskExecutionDays,
@@ -45,7 +52,8 @@ import {
45
52
  readTaskExecutionSummaries,
46
53
  readTaskExecutions,
47
54
  readTaskRuns
48
- } from "./chunk-AVOCH2Z5.js";
55
+ } from "./chunk-RRJV5UR5.js";
56
+ import "./chunk-IL4EDBMV.js";
49
57
  import {
50
58
  healthReportSchema,
51
59
  pluginOperationalReportFeedSchema,
@@ -53,6 +61,11 @@ import {
53
61
  runtimeInfoReportSchema,
54
62
  skillReportsSchema
55
63
  } from "./chunk-UTL3MHPC.js";
64
+ import {
65
+ getVercelConversationWorkQueue
66
+ } from "./chunk-WR76IVA5.js";
67
+ import "./chunk-JAL3CH4G.js";
68
+ import "./chunk-5I6ORJUY.js";
56
69
  import {
57
70
  createSchedulerSqlStore,
58
71
  deleteEventTask,
@@ -64,18 +77,19 @@ import {
64
77
  listPublicEventTasksForTeams,
65
78
  listPublicScheduledTasksForTeams,
66
79
  readStats
67
- } from "./chunk-EFLJ2WJH.js";
80
+ } from "./chunk-GXYDVZKM.js";
68
81
  import {
69
82
  parseSlackThreadId
70
- } from "./chunk-CSZINQJ2.js";
83
+ } from "./chunk-WOONT5ZP.js";
71
84
  import {
72
85
  fallbackShortTitle
73
- } from "./chunk-Z4YU7Z4L.js";
86
+ } from "./chunk-4EA2SFK2.js";
74
87
  import {
75
88
  agentTurnUsageSchema,
76
89
  hasAgentTurnUsage,
77
90
  renderJuniorNativeConversationEvent
78
- } from "./chunk-HLXXQI5Q.js";
91
+ } from "./chunk-VCYSOXON.js";
92
+ import "./chunk-3Y47VMHV.js";
79
93
  import "./chunk-PDO5BLNM.js";
80
94
  import {
81
95
  createPluginLogger,
@@ -83,56 +97,73 @@ import {
83
97
  listConversationAnnotations,
84
98
  renderPluginConversationEvent,
85
99
  resolveViewerUser
86
- } from "./chunk-YHDERDRO.js";
100
+ } from "./chunk-ZCHIC2GM.js";
87
101
  import {
88
102
  getSlackClient,
89
103
  withSlackRetries
90
- } from "./chunk-SGZO7UWH.js";
104
+ } from "./chunk-V2FXMOEA.js";
91
105
  import {
92
106
  decodeStoredConversationEvent,
107
+ getConversationStore,
93
108
  getDb,
94
109
  getSqlExecutor,
95
110
  locationFromRow,
96
111
  parseSessionSource
97
- } from "./chunk-YSB2N563.js";
112
+ } from "./chunk-VRHTNBA6.js";
98
113
  import {
99
114
  juniorApiTokens,
100
115
  juniorConversationEvents,
101
116
  juniorConversations,
102
117
  juniorIdentities,
103
118
  juniorUsers
104
- } from "./chunk-DU74WPIC.js";
119
+ } from "./chunk-D3WPMGEX.js";
105
120
  import "./chunk-EM225ITJ.js";
106
- import "./chunk-ORO3PWKQ.js";
107
- import "./chunk-7NVJVJID.js";
121
+ import "./chunk-2B3PT3V2.js";
122
+ import "./chunk-4GXJUYJV.js";
108
123
  import {
109
124
  juniorDestinations
110
125
  } from "./chunk-VFUK3X5B.js";
111
126
  import {
112
127
  canExposeConversationPayload
113
- } from "./chunk-RXBVB2JM.js";
128
+ } from "./chunk-LE5H7LMT.js";
129
+ import "./chunk-RUIXF3YQ.js";
114
130
  import "./chunk-HZF5P5UN.js";
115
131
  import {
116
132
  parseSlackChannelId,
117
133
  parseSlackMessageTs,
118
134
  parseSlackTeamId
119
135
  } from "./chunk-F3B2YJ76.js";
120
- import "./chunk-4LJO56OJ.js";
136
+ import {
137
+ logException
138
+ } from "./chunk-EAI67NTM.js";
121
139
  import "./chunk-6GWA276C.js";
122
- import "./chunk-DLDRQHG5.js";
123
- import "./chunk-IIOOO4FQ.js";
140
+ import "./chunk-LAZGHEYU.js";
141
+ import "./chunk-55F4QU2V.js";
124
142
  import "./chunk-MLKGABMK.js";
125
143
 
126
144
  // src/api.ts
127
145
  import { Hono as Hono7 } from "hono";
146
+ import { HTTPException as HTTPException2 } from "hono/http-exception";
128
147
 
129
148
  // src/api/conversations/routes.ts
130
149
  import { Hono } from "hono";
131
150
 
132
151
  // src/api/http.ts
133
152
  import { HTTPException } from "hono/http-exception";
153
+ var NO_STORE_HEADERS = { "cache-control": "no-store" };
154
+ function noStoreInit(init) {
155
+ if (!init) return { headers: NO_STORE_HEADERS };
156
+ const headers = new Headers(init.headers);
157
+ if (!headers.has("cache-control")) {
158
+ headers.set("cache-control", "no-store");
159
+ }
160
+ return { ...init, headers };
161
+ }
134
162
  function jsonResponse(schema, value, init) {
135
- return Response.json(schema.parse(value), init);
163
+ return Response.json(schema.parse(value), noStoreInit(init));
164
+ }
165
+ function emptyResponse(status = 204) {
166
+ return new Response(null, noStoreInit({ status }));
136
167
  }
137
168
  function throwApiError(status, message2, cause) {
138
169
  throw new HTTPException(status, {
@@ -141,35 +172,25 @@ function throwApiError(status, message2, cause) {
141
172
  res: jsonResponse(apiErrorSchema, { error: message2 }, { status })
142
173
  });
143
174
  }
144
- function parseParams(schema, params) {
145
- const result = schema.safeParse(params);
146
- if (result.success) return result.data;
147
- return throwApiError(400, "Invalid route parameters.", result.error);
148
- }
149
- function parseQuery(schema, query) {
150
- const result = schema.safeParse(query);
151
- if (result.success) return result.data;
152
- return throwApiError(400, "Invalid query parameters.", result.error);
153
- }
154
- function parseBody(schema, body) {
155
- const result = schema.safeParse(body);
156
- if (result.success) return result.data;
157
- return throwApiError(400, "Invalid request body.", result.error);
175
+
176
+ // src/api/validation.ts
177
+ import { zValidator } from "@hono/zod-validator";
178
+ function validateRequest(target, schema, message2) {
179
+ return zValidator(target, schema, (result) => {
180
+ if (!result.success) throwApiError(400, message2, result.error);
181
+ });
158
182
  }
159
183
 
160
- // src/api/route.ts
161
- function defineApiRoute(route) {
162
- return route;
163
- }
164
- function registerApiRoutes(app, routes5) {
165
- for (const route of routes5) {
166
- app.on(
167
- route.method,
168
- route.path,
169
- async (context) => jsonResponse(route.responseSchema, await route.handler(context))
170
- );
184
+ // src/api/viewer.ts
185
+ import { createMiddleware } from "hono/factory";
186
+ var requireViewer = createMiddleware(
187
+ async (context, next) => {
188
+ if (!context.get("viewer")) {
189
+ throwApiError(401, "Authentication required.");
190
+ }
191
+ await next();
171
192
  }
172
- }
193
+ );
173
194
 
174
195
  // src/api/conversations/archive.ts
175
196
  import { and, eq, isNotNull } from "drizzle-orm";
@@ -190,32 +211,133 @@ async function archiveIfUnchanged(args) {
190
211
  if (!args.archived && existing.archivedAt === null) return "updated";
191
212
  return "conflict";
192
213
  }
193
- var archive_default = defineApiRoute({
194
- method: "patch",
195
- path: "/:conversationId/archive",
196
- responseSchema: archiveConversationResponseSchema,
197
- handler: async (c) => {
198
- const { conversationId } = parseParams(
199
- conversationParamsSchema,
200
- c.req.param()
214
+ async function archiveConversation(conversationId, body) {
215
+ const result = await archiveIfUnchanged({ ...body, conversationId });
216
+ if (result === "not_found") {
217
+ throwApiError(404, "Conversation not found.");
218
+ }
219
+ if (result === "conflict") {
220
+ throwApiError(409, "Conversation received new activity.");
221
+ }
222
+ return { archived: body.archived };
223
+ }
224
+
225
+ // src/api/conversations/access.ts
226
+ import { eq as eq2, inArray } from "drizzle-orm";
227
+ import { alias } from "drizzle-orm/pg-core";
228
+ var rootConversation = alias(juniorConversations, "access_root_conversation");
229
+ var rootDestination = alias(juniorDestinations, "access_root_destination");
230
+ var rootIdentity = alias(juniorIdentities, "access_root_identity");
231
+ async function readConversationAccessFromSql(db, conversationIds, viewer) {
232
+ if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
233
+ const normalizedViewerEmail = viewer?.email.trim().toLowerCase() || void 0;
234
+ const rows = await db.select({
235
+ conversationId: juniorConversations.conversationId,
236
+ parentConversationId: juniorConversations.parentConversationId,
237
+ storedRootConversationId: juniorConversations.rootConversationId,
238
+ rootConversationId: rootConversation.conversationId,
239
+ rootParentConversationId: rootConversation.parentConversationId,
240
+ rootRootConversationId: rootConversation.rootConversationId,
241
+ visibility: rootDestination.visibility,
242
+ rootEmailNormalized: rootIdentity.emailNormalized,
243
+ rootEmailVerified: rootIdentity.emailVerified,
244
+ rootUserId: rootIdentity.userId
245
+ }).from(juniorConversations).leftJoin(
246
+ rootConversation,
247
+ eq2(
248
+ rootConversation.conversationId,
249
+ juniorConversations.rootConversationId
250
+ )
251
+ ).leftJoin(
252
+ rootDestination,
253
+ eq2(rootDestination.id, rootConversation.destinationId)
254
+ ).leftJoin(
255
+ rootIdentity,
256
+ eq2(rootIdentity.id, rootConversation.actorIdentityId)
257
+ ).where(inArray(juniorConversations.conversationId, [...conversationIds]));
258
+ return new Map(
259
+ rows.map((row) => {
260
+ const hasValidRoot = row.rootConversationId !== null && row.rootConversationId === row.storedRootConversationId && row.rootRootConversationId === row.rootConversationId && row.rootParentConversationId === null && (row.parentConversationId !== null || row.storedRootConversationId === row.conversationId);
261
+ const validRootConversationId = hasValidRoot ? row.rootConversationId ?? void 0 : void 0;
262
+ const visibility = validRootConversationId === void 0 ? null : row.visibility;
263
+ const isParticipant = validRootConversationId !== void 0 && viewer !== void 0 && (row.rootUserId === viewer.id || normalizedViewerEmail !== void 0 && row.rootEmailVerified === true && row.rootEmailNormalized === normalizedViewerEmail);
264
+ const canViewPrivateContent = isParticipant || validRootConversationId !== void 0 && canExposeConversationPayload({
265
+ visibility: visibility ?? void 0
266
+ });
267
+ return [
268
+ row.conversationId,
269
+ {
270
+ canViewPrivateContent,
271
+ isParticipant,
272
+ visibility
273
+ }
274
+ ];
275
+ })
276
+ );
277
+ }
278
+
279
+ // src/api/conversations/create.ts
280
+ function actorFromViewer(viewer) {
281
+ const normalized = viewer.email.trim().toLowerCase();
282
+ return webActorFromEmail(normalized, {
283
+ ...viewer.displayName ? { fullName: viewer.displayName } : {},
284
+ userName: normalized.split("@")[0] || normalized
285
+ });
286
+ }
287
+ async function createConversationForViewer(viewer, body) {
288
+ try {
289
+ return await createAndEnqueueApiConversation(
290
+ {
291
+ actor: actorFromViewer(viewer),
292
+ idempotencyKey: body.idempotencyKey,
293
+ message: body.message
294
+ },
295
+ {
296
+ conversationStore: getConversationStore(),
297
+ queue: getVercelConversationWorkQueue()
298
+ }
201
299
  );
202
- let input;
203
- try {
204
- input = await c.req.json();
205
- } catch (error) {
206
- throwApiError(400, "Invalid request body.", error);
207
- }
208
- const body = parseBody(archiveConversationBodySchema, input);
209
- const result = await archiveIfUnchanged({ ...body, conversationId });
210
- if (result === "not_found") {
211
- throwApiError(404, "Conversation not found.");
212
- }
213
- if (result === "conflict") {
214
- throwApiError(409, "Conversation received new activity.");
215
- }
216
- return { archived: body.archived };
300
+ } catch (error) {
301
+ throwApiError(500, "Unable to create conversation.", error);
217
302
  }
218
- });
303
+ }
304
+ async function appendConversationMessageForViewer(viewer, conversationId, body) {
305
+ const conversation = await getConversationStore().get({
306
+ conversationId
307
+ });
308
+ if (!conversation) {
309
+ throwApiError(404, "Conversation not found.");
310
+ }
311
+ const destinationPlatform = conversation.destination?.platform;
312
+ const acceptsApiMessages = destinationPlatform === "local" && conversationId.startsWith("local:web:") || destinationPlatform === "slack";
313
+ if (!acceptsApiMessages) {
314
+ throwApiError(409, "Conversation does not accept API messages.");
315
+ }
316
+ const access = await readConversationAccessFromSql(
317
+ getDb(),
318
+ [conversationId],
319
+ viewer
320
+ );
321
+ if (!access.get(conversationId)?.isParticipant) {
322
+ throwApiError(403, "Only conversation participants can add messages.");
323
+ }
324
+ try {
325
+ return await appendAndEnqueueApiConversationMessage(
326
+ {
327
+ actor: actorFromViewer(viewer),
328
+ conversationId,
329
+ idempotencyKey: body.idempotencyKey,
330
+ message: body.message
331
+ },
332
+ {
333
+ conversationStore: getConversationStore(),
334
+ queue: getVercelConversationWorkQueue()
335
+ }
336
+ );
337
+ } catch (error) {
338
+ throwApiError(500, "Unable to append message.", error);
339
+ }
340
+ }
219
341
 
220
342
  // src/chat/slack/source-link.ts
221
343
  function parseSlackTeamDomain(value) {
@@ -332,7 +454,7 @@ async function resolveSlackTeamDomains(teamIds) {
332
454
  }
333
455
 
334
456
  // src/chat/pi/sql-model-usage.ts
335
- import { and as and2, eq as eq2, sql } from "drizzle-orm";
457
+ import { and as and2, eq as eq3, sql } from "drizzle-orm";
336
458
  var message = sql`${juniorConversationEvents.payload}`;
337
459
  var usage = sql`${message}->'usage'`;
338
460
  var cost = sql`${usage}->'cost'`;
@@ -426,14 +548,14 @@ async function readConversationModelUsageFromSql(executor, options) {
426
548
  costTotal: summedCost(nonnegativeNumber(cost, "total"))
427
549
  }).from(juniorConversationEvents).innerJoin(
428
550
  juniorConversations,
429
- eq2(
551
+ eq3(
430
552
  juniorConversations.conversationId,
431
553
  juniorConversationEvents.conversationId
432
554
  )
433
555
  ).where(
434
556
  and2(
435
- options.includeDescendants ? eq2(juniorConversations.rootConversationId, options.conversationId) : eq2(juniorConversationEvents.conversationId, options.conversationId),
436
- eq2(juniorConversationEvents.type, "assistant_message"),
557
+ options.includeDescendants ? eq3(juniorConversations.rootConversationId, options.conversationId) : eq3(juniorConversationEvents.conversationId, options.conversationId),
558
+ eq3(juniorConversationEvents.type, "assistant_message"),
437
559
  sql`jsonb_typeof(${message}->'provider') = 'string'`,
438
560
  sql`jsonb_typeof(${message}->'model') = 'string'`,
439
561
  sql`coalesce(${message}->>'provider', '') <> ''`,
@@ -498,9 +620,9 @@ import {
498
620
  and as and3,
499
621
  asc,
500
622
  desc,
501
- eq as eq3,
623
+ eq as eq4,
502
624
  getTableColumns,
503
- inArray,
625
+ inArray as inArray2,
504
626
  lt,
505
627
  sql as sql2
506
628
  } from "drizzle-orm";
@@ -912,17 +1034,17 @@ async function readConversationEventRows(executor, args) {
912
1034
  end`
913
1035
  }).from(juniorConversationEvents).where(
914
1036
  and3(
915
- eq3(juniorConversationEvents.conversationId, args.conversationId),
1037
+ eq4(juniorConversationEvents.conversationId, args.conversationId),
916
1038
  args.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, args.beforeSeq),
917
- inArray(
1039
+ inArray2(
918
1040
  juniorConversationEvents.type,
919
1041
  args.types ?? [...conversationReportSourceEventTypes]
920
1042
  ),
921
- args.subagentInvocationIds === void 0 ? void 0 : inArray(
1043
+ args.subagentInvocationIds === void 0 ? void 0 : inArray2(
922
1044
  sql2`${juniorConversationEvents.payload}->>'subagentInvocationId'`,
923
1045
  args.subagentInvocationIds
924
1046
  ),
925
- args.toolCallIds === void 0 ? void 0 : inArray(
1047
+ args.toolCallIds === void 0 ? void 0 : inArray2(
926
1048
  sql2`${juniorConversationEvents.payload}->>'toolCallId'`,
927
1049
  args.toolCallIds
928
1050
  )
@@ -1043,8 +1165,8 @@ function surfaceFromConversationId(conversationId) {
1043
1165
  return "internal";
1044
1166
  }
1045
1167
  function surfaceFromSource(source, conversationId) {
1046
- if (source === "slack" || source === "api" || source === "scheduler") {
1047
- return source;
1168
+ if (source === "slack" || source === "api" || source === "web" || source === "scheduler") {
1169
+ return source === "web" ? "api" : source;
1048
1170
  }
1049
1171
  return surfaceFromConversationId(conversationId);
1050
1172
  }
@@ -1165,6 +1287,7 @@ function conversationSummaryFromStoredConversation(args) {
1165
1287
  visibility
1166
1288
  }),
1167
1289
  isParticipant: args.access?.isParticipant ?? false,
1290
+ ...visibility ? { visibility } : {},
1168
1291
  lastProgressAt: new Date(
1169
1292
  conversation.execution.updatedAtMs ?? conversation.updatedAtMs
1170
1293
  ).toISOString(),
@@ -1184,59 +1307,6 @@ function conversationSummaryFromStoredConversation(args) {
1184
1307
  };
1185
1308
  }
1186
1309
 
1187
- // src/api/conversations/access.ts
1188
- import { eq as eq4, inArray as inArray2 } from "drizzle-orm";
1189
- import { alias } from "drizzle-orm/pg-core";
1190
- var rootConversation = alias(juniorConversations, "access_root_conversation");
1191
- var rootDestination = alias(juniorDestinations, "access_root_destination");
1192
- var rootIdentity = alias(juniorIdentities, "access_root_identity");
1193
- async function readConversationAccessFromSql(db, conversationIds, verifiedViewerEmail) {
1194
- if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
1195
- const normalizedViewerEmail = verifiedViewerEmail?.trim().toLowerCase() || void 0;
1196
- const rows = await db.select({
1197
- conversationId: juniorConversations.conversationId,
1198
- parentConversationId: juniorConversations.parentConversationId,
1199
- storedRootConversationId: juniorConversations.rootConversationId,
1200
- rootConversationId: rootConversation.conversationId,
1201
- rootParentConversationId: rootConversation.parentConversationId,
1202
- rootRootConversationId: rootConversation.rootConversationId,
1203
- visibility: rootDestination.visibility,
1204
- rootEmailNormalized: rootIdentity.emailNormalized,
1205
- rootEmailVerified: rootIdentity.emailVerified
1206
- }).from(juniorConversations).leftJoin(
1207
- rootConversation,
1208
- eq4(
1209
- rootConversation.conversationId,
1210
- juniorConversations.rootConversationId
1211
- )
1212
- ).leftJoin(
1213
- rootDestination,
1214
- eq4(rootDestination.id, rootConversation.destinationId)
1215
- ).leftJoin(
1216
- rootIdentity,
1217
- eq4(rootIdentity.id, rootConversation.actorIdentityId)
1218
- ).where(inArray2(juniorConversations.conversationId, [...conversationIds]));
1219
- return new Map(
1220
- rows.map((row) => {
1221
- const hasValidRoot = row.rootConversationId !== null && row.rootConversationId === row.storedRootConversationId && row.rootRootConversationId === row.rootConversationId && row.rootParentConversationId === null && (row.parentConversationId !== null || row.storedRootConversationId === row.conversationId);
1222
- const validRootConversationId = hasValidRoot ? row.rootConversationId ?? void 0 : void 0;
1223
- const visibility = validRootConversationId === void 0 ? null : row.visibility;
1224
- const isParticipant = validRootConversationId !== void 0 && normalizedViewerEmail !== void 0 && row.rootEmailVerified === true && row.rootEmailNormalized === normalizedViewerEmail;
1225
- const canViewPrivateContent = isParticipant || validRootConversationId !== void 0 && canExposeConversationPayload({
1226
- visibility: visibility ?? void 0
1227
- });
1228
- return [
1229
- row.conversationId,
1230
- {
1231
- canViewPrivateContent,
1232
- isParticipant,
1233
- visibility
1234
- }
1235
- ];
1236
- })
1237
- );
1238
- }
1239
-
1240
1310
  // src/api/conversations/usage.ts
1241
1311
  import { and as and4, eq as eq5, inArray as inArray3, isNull, sql as sql3 } from "drizzle-orm";
1242
1312
  import { alias as alias2 } from "drizzle-orm/pg-core";
@@ -1565,11 +1635,7 @@ async function readConversationFeedFromSql(options = {}) {
1565
1635
  metricsByRoot,
1566
1636
  teamDomainByTeamId
1567
1637
  ] = await Promise.all([
1568
- readConversationAccessFromSql(
1569
- db,
1570
- conversationIds,
1571
- options.verifiedViewerEmail
1572
- ),
1638
+ readConversationAccessFromSql(db, conversationIds, options.viewer),
1573
1639
  readConversationAuxiliaryCostsFromSql(db, conversationIds, {
1574
1640
  includeDescendants: true
1575
1641
  }),
@@ -1603,22 +1669,6 @@ async function readConversationFeed(options = {}) {
1603
1669
  await readConversationFeedFromSql(options)
1604
1670
  );
1605
1671
  }
1606
- var list_default = defineApiRoute({
1607
- method: "get",
1608
- path: "/",
1609
- responseSchema: conversationFeedSchema,
1610
- handler: async (c) => {
1611
- const { actorEmail } = parseQuery(
1612
- conversationFeedQuerySchema,
1613
- c.req.query()
1614
- );
1615
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
1616
- return readConversationFeed({
1617
- ...actorEmail ? { actorEmail } : {},
1618
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
1619
- });
1620
- }
1621
- });
1622
1672
 
1623
1673
  // src/chat/tasks/read.ts
1624
1674
  import { and as and7, eq as eq8, or as or2 } from "drizzle-orm";
@@ -2086,12 +2136,9 @@ async function readConversationSourceTask(args) {
2086
2136
  conversationId: args.conversationId
2087
2137
  });
2088
2138
  if (!execution) return void 0;
2089
- const email = args.verifiedViewerEmail?.trim();
2090
- if (!email) return { kind: execution.kind };
2091
- const user = await resolveViewerUser(email);
2092
- if (!user) return { kind: execution.kind };
2139
+ if (!args.viewer) return { kind: execution.kind };
2093
2140
  const candidate = await resolveViewerTaskCandidate(
2094
- user,
2141
+ args.viewer,
2095
2142
  execution.kind,
2096
2143
  execution.taskId
2097
2144
  );
@@ -2199,11 +2246,7 @@ async function readConversationDetailFromSql(conversationId, options) {
2199
2246
  sourceTask,
2200
2247
  teamDomainByTeamId
2201
2248
  ] = await Promise.all([
2202
- readConversationAccessFromSql(
2203
- getDb(),
2204
- [conversationId],
2205
- options.verifiedViewerEmail
2206
- ),
2249
+ readConversationAccessFromSql(getDb(), [conversationId], options.viewer),
2207
2250
  listConversationAnnotations(getDb(), conversationId),
2208
2251
  readConversationAuxiliaryCostsFromSql(getDb(), [conversationId], {
2209
2252
  includeDescendants: includeDescendantMetrics
@@ -2218,7 +2261,7 @@ async function readConversationDetailFromSql(conversationId, options) {
2218
2261
  ),
2219
2262
  readConversationSourceTask({
2220
2263
  conversationId,
2221
- ...options.verifiedViewerEmail ? { verifiedViewerEmail: options.verifiedViewerEmail } : {}
2264
+ ...options.viewer ? { viewer: options.viewer } : {}
2222
2265
  }),
2223
2266
  resolveSlackTeamDomains(
2224
2267
  record.conversation.sessionSource?.platform === "slack" ? [record.conversation.sessionSource.teamId] : []
@@ -2252,25 +2295,6 @@ async function readConversationDetail(conversationId, options = {}) {
2252
2295
  });
2253
2296
  return report ? conversationDetailReportSchema.parse(report) : void 0;
2254
2297
  }
2255
- var detail_default = defineApiRoute({
2256
- method: "get",
2257
- path: "/:conversationId",
2258
- responseSchema: conversationDetailReportSchema,
2259
- handler: async (c) => {
2260
- const { conversationId } = parseParams(
2261
- conversationParamsSchema,
2262
- c.req.param()
2263
- );
2264
- const query = parseQuery(conversationDetailQuerySchema, c.req.query());
2265
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
2266
- const report = await readConversationDetail(conversationId, {
2267
- ...query,
2268
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
2269
- });
2270
- if (!report) throwApiError(404, "Conversation not found.");
2271
- return report;
2272
- }
2273
- });
2274
2298
 
2275
2299
  // src/api/conversations/event-list.ts
2276
2300
  async function readConversationEvents(conversationId, beforeValue, options = {}) {
@@ -2284,7 +2308,7 @@ async function readConversationEvents(conversationId, beforeValue, options = {})
2284
2308
  const accessByConversation = await readConversationAccessFromSql(
2285
2309
  getDb(),
2286
2310
  [conversationId],
2287
- options.verifiedViewerEmail
2311
+ options.viewer
2288
2312
  );
2289
2313
  const access = accessByConversation.get(conversationId);
2290
2314
  const canExposePayload = access?.canViewPrivateContent ?? false;
@@ -2310,28 +2334,6 @@ async function readConversationEvents(conversationId, beforeValue, options = {})
2310
2334
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
2311
2335
  });
2312
2336
  }
2313
- var event_list_default = defineApiRoute({
2314
- method: "get",
2315
- path: "/:conversationId/events",
2316
- responseSchema: conversationEventPageSchema,
2317
- handler: async (c) => {
2318
- const { conversationId } = parseParams(
2319
- conversationParamsSchema,
2320
- c.req.param()
2321
- );
2322
- const { before, limit } = parseQuery(
2323
- conversationEventsQuerySchema,
2324
- c.req.query()
2325
- );
2326
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
2327
- const report = await readConversationEvents(conversationId, before, {
2328
- limit,
2329
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
2330
- });
2331
- if (!report) throwApiError(404, "Conversation not found.");
2332
- return report;
2333
- }
2334
- });
2335
2337
 
2336
2338
  // src/api/conversations/stats.query.ts
2337
2339
  import { and as and8, eq as eq9, gte, isNull as isNull4, lte, sql as sql6 } from "drizzle-orm";
@@ -2432,7 +2434,7 @@ function actorLabel(row) {
2432
2434
  }
2433
2435
  function surfaceLabel(source) {
2434
2436
  if (source === "scheduler") return "Scheduler";
2435
- if (source === "api") return "API";
2437
+ if (source === "api" || source === "web") return "Web";
2436
2438
  if (source === "internal" || source === "local") return "Internal";
2437
2439
  return "Conversation";
2438
2440
  }
@@ -2688,93 +2690,144 @@ async function readConversationStats() {
2688
2690
  await readConversationStatsFromSql()
2689
2691
  );
2690
2692
  }
2691
- var stats_default = defineApiRoute({
2692
- method: "get",
2693
- path: "/stats",
2694
- responseSchema: conversationStatsReportSchema,
2695
- handler: readConversationStats
2696
- });
2697
2693
 
2698
2694
  // src/api/conversations/routes.ts
2699
- var routes = [
2700
- list_default,
2701
- stats_default,
2702
- archive_default,
2703
- event_list_default,
2704
- detail_default
2705
- ];
2706
2695
  function createConversationRoutes() {
2707
2696
  const app = new Hono();
2708
- registerApiRoutes(app, routes);
2709
- return app;
2710
- }
2711
-
2712
- // src/reporting.ts
2713
- import { readFileSync } from "fs";
2714
- import path from "path";
2715
- function readDescriptionText(home) {
2716
- try {
2717
- const raw = readFileSync(path.join(home, "DESCRIPTION.md"), "utf8").trim();
2718
- return raw || void 0;
2719
- } catch {
2720
- return void 0;
2721
- }
2722
- }
2723
- async function readSkillReports() {
2724
- const { discoverSkills } = await import("./skills-AKE6W3WI.js");
2725
- const skills = await discoverSkills();
2726
- return skillReportsSchema.parse(
2727
- skills.map((skill) => ({
2728
- name: skill.name,
2729
- pluginProvider: skill.pluginProvider
2730
- }))
2697
+ app.get(
2698
+ "/",
2699
+ validateRequest(
2700
+ "query",
2701
+ conversationFeedQuerySchema,
2702
+ "Invalid query parameters."
2703
+ ),
2704
+ async (context) => {
2705
+ const { actorEmail } = context.req.valid("query");
2706
+ const viewer = context.get("viewer");
2707
+ return jsonResponse(
2708
+ conversationFeedSchema,
2709
+ await readConversationFeed({
2710
+ ...actorEmail ? { actorEmail } : {},
2711
+ ...viewer ? { viewer } : {}
2712
+ })
2713
+ );
2714
+ }
2731
2715
  );
2732
- }
2733
- async function readPlugins() {
2734
- const { pluginCatalogRuntime } = await import("./catalog-runtime-M6ZTPYRV.js");
2735
- return pluginsSchema.parse(
2736
- pluginCatalogRuntime.getProviders().map((plugin) => ({
2737
- configKeys: plugin.manifest.configKeys ?? [],
2738
- description: plugin.manifest.description,
2739
- displayName: plugin.manifest.displayName,
2740
- name: plugin.manifest.name
2741
- }))
2716
+ app.get(
2717
+ "/stats",
2718
+ async () => jsonResponse(conversationStatsReportSchema, await readConversationStats())
2742
2719
  );
2720
+ app.post(
2721
+ "/",
2722
+ requireViewer,
2723
+ validateRequest(
2724
+ "json",
2725
+ createConversationBodySchema,
2726
+ "Invalid request body."
2727
+ ),
2728
+ async (context) => {
2729
+ const viewer = context.get("viewer");
2730
+ const body = context.req.valid("json");
2731
+ return jsonResponse(
2732
+ acceptedConversationMessageSchema,
2733
+ await createConversationForViewer(viewer, body)
2734
+ );
2735
+ }
2736
+ );
2737
+ app.post(
2738
+ "/:conversationId/messages",
2739
+ requireViewer,
2740
+ validateRequest(
2741
+ "param",
2742
+ conversationParamsSchema,
2743
+ "Invalid route parameters."
2744
+ ),
2745
+ validateRequest(
2746
+ "json",
2747
+ createConversationMessageBodySchema,
2748
+ "Invalid request body."
2749
+ ),
2750
+ async (context) => {
2751
+ const viewer = context.get("viewer");
2752
+ const { conversationId } = context.req.valid("param");
2753
+ const body = context.req.valid("json");
2754
+ return jsonResponse(
2755
+ acceptedConversationMessageSchema,
2756
+ await appendConversationMessageForViewer(viewer, conversationId, body)
2757
+ );
2758
+ }
2759
+ );
2760
+ app.patch(
2761
+ "/:conversationId/archive",
2762
+ validateRequest(
2763
+ "param",
2764
+ conversationParamsSchema,
2765
+ "Invalid route parameters."
2766
+ ),
2767
+ validateRequest(
2768
+ "json",
2769
+ archiveConversationBodySchema,
2770
+ "Invalid request body."
2771
+ ),
2772
+ async (context) => {
2773
+ const { conversationId } = context.req.valid("param");
2774
+ const body = context.req.valid("json");
2775
+ return jsonResponse(
2776
+ archiveConversationResponseSchema,
2777
+ await archiveConversation(conversationId, body)
2778
+ );
2779
+ }
2780
+ );
2781
+ app.get(
2782
+ "/:conversationId/events",
2783
+ validateRequest(
2784
+ "param",
2785
+ conversationParamsSchema,
2786
+ "Invalid route parameters."
2787
+ ),
2788
+ validateRequest(
2789
+ "query",
2790
+ conversationEventsQuerySchema,
2791
+ "Invalid query parameters."
2792
+ ),
2793
+ async (context) => {
2794
+ const { conversationId } = context.req.valid("param");
2795
+ const { before, limit } = context.req.valid("query");
2796
+ const viewer = context.get("viewer");
2797
+ const report = await readConversationEvents(conversationId, before, {
2798
+ limit,
2799
+ ...viewer ? { viewer } : {}
2800
+ });
2801
+ if (!report) throwApiError(404, "Conversation not found.");
2802
+ return jsonResponse(conversationEventPageSchema, report);
2803
+ }
2804
+ );
2805
+ app.get(
2806
+ "/:conversationId",
2807
+ validateRequest(
2808
+ "param",
2809
+ conversationParamsSchema,
2810
+ "Invalid route parameters."
2811
+ ),
2812
+ validateRequest(
2813
+ "query",
2814
+ conversationDetailQuerySchema,
2815
+ "Invalid query parameters."
2816
+ ),
2817
+ async (context) => {
2818
+ const { conversationId } = context.req.valid("param");
2819
+ const query = context.req.valid("query");
2820
+ const viewer = context.get("viewer");
2821
+ const report = await readConversationDetail(conversationId, {
2822
+ ...query,
2823
+ ...viewer ? { viewer } : {}
2824
+ });
2825
+ if (!report) throwApiError(404, "Conversation not found.");
2826
+ return jsonResponse(conversationDetailReportSchema, report);
2827
+ }
2828
+ );
2829
+ return app;
2743
2830
  }
2744
- async function readRuntimeInfoReport() {
2745
- const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
2746
- import("./discovery-GUFTFBTL.js"),
2747
- import("./catalog-runtime-M6ZTPYRV.js"),
2748
- readPlugins(),
2749
- readSkillReports()
2750
- ]);
2751
- const home = homeDir();
2752
- return runtimeInfoReportSchema.parse({
2753
- cwd: process.cwd(),
2754
- homeDir: home,
2755
- descriptionText: readDescriptionText(home),
2756
- providers: plugins.map((plugin) => plugin.name),
2757
- skills,
2758
- packagedContent: pluginCatalogRuntime.getPackageContent()
2759
- });
2760
- }
2761
- async function readPluginOperationalReportFeed() {
2762
- const nowMs = Date.now();
2763
- const { getPluginOperationalReports } = await import("./agent-hooks-HS6VGUPM.js");
2764
- return pluginOperationalReportFeedSchema.parse({
2765
- source: "plugins",
2766
- generatedAt: new Date(nowMs).toISOString(),
2767
- reports: await getPluginOperationalReports(nowMs)
2768
- });
2769
- }
2770
-
2771
- // src/api/health.ts
2772
- var health_default = defineApiRoute({
2773
- method: "get",
2774
- path: "/api/health",
2775
- responseSchema: healthReportSchema,
2776
- handler: readHealthReport
2777
- });
2778
2831
 
2779
2832
  // src/api/locations/routes.ts
2780
2833
  import { Hono as Hono2 } from "hono";
@@ -3175,7 +3228,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3175
3228
  readConversationAccessFromSql(
3176
3229
  getDb(),
3177
3230
  recentConversationIds,
3178
- options.verifiedViewerEmail
3231
+ options.viewer
3179
3232
  ),
3180
3233
  readRootConversationMetricsFromSql(getDb(), recentConversationIds)
3181
3234
  ]);
@@ -3203,21 +3256,6 @@ async function readLocationDetail(locationId, options = {}) {
3203
3256
  const report = await readLocationDetailFromSql(locationId, options);
3204
3257
  return report ? locationDetailReportSchema.parse(report) : void 0;
3205
3258
  }
3206
- var detail_default2 = defineApiRoute({
3207
- method: "get",
3208
- path: "/:locationId",
3209
- responseSchema: locationDetailReportSchema,
3210
- handler: async (c) => {
3211
- const { locationId } = parseParams(locationParamsSchema, c.req.param());
3212
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
3213
- const report = await readLocationDetail(
3214
- locationId,
3215
- verifiedViewerEmail ? { verifiedViewerEmail } : {}
3216
- );
3217
- if (!report) throwApiError(404, "Location not found.");
3218
- return report;
3219
- }
3220
- });
3221
3259
 
3222
3260
  // src/api/locations/list.ts
3223
3261
  async function readLocationDirectory() {
@@ -3225,18 +3263,32 @@ async function readLocationDirectory() {
3225
3263
  await readLocationDirectoryFromSql()
3226
3264
  );
3227
3265
  }
3228
- var list_default2 = defineApiRoute({
3229
- method: "get",
3230
- path: "/",
3231
- responseSchema: locationDirectoryReportSchema,
3232
- handler: readLocationDirectory
3233
- });
3234
3266
 
3235
3267
  // src/api/locations/routes.ts
3236
- var routes2 = [list_default2, detail_default2];
3237
3268
  function createLocationRoutes() {
3238
3269
  const app = new Hono2();
3239
- registerApiRoutes(app, routes2);
3270
+ app.get(
3271
+ "/",
3272
+ async () => jsonResponse(locationDirectoryReportSchema, await readLocationDirectory())
3273
+ );
3274
+ app.get(
3275
+ "/:locationId",
3276
+ validateRequest(
3277
+ "param",
3278
+ locationParamsSchema,
3279
+ "Invalid route parameters."
3280
+ ),
3281
+ async (context) => {
3282
+ const { locationId } = context.req.valid("param");
3283
+ const viewer = context.get("viewer");
3284
+ const report = await readLocationDetail(
3285
+ locationId,
3286
+ viewer ? { viewer } : {}
3287
+ );
3288
+ if (!report) throwApiError(404, "Location not found.");
3289
+ return jsonResponse(locationDetailReportSchema, report);
3290
+ }
3291
+ );
3240
3292
  return app;
3241
3293
  }
3242
3294
 
@@ -3474,12 +3526,6 @@ async function readPeopleListFromSql() {
3474
3526
  async function readPeopleList() {
3475
3527
  return actorDirectoryReportSchema.parse(await readPeopleListFromSql());
3476
3528
  }
3477
- var list_default3 = defineApiRoute({
3478
- method: "get",
3479
- path: "/",
3480
- responseSchema: actorDirectoryReportSchema,
3481
- handler: readPeopleList
3482
- });
3483
3529
 
3484
3530
  // src/api/people/profile.query.ts
3485
3531
  import { and as and12, eq as eq13, gte as gte4, sql as sql10 } from "drizzle-orm";
@@ -3631,7 +3677,7 @@ async function readPeopleProfileFromSql(email, options = {}) {
3631
3677
  readConversationAccessFromSql(
3632
3678
  getDb(),
3633
3679
  recentConversationIds,
3634
- options.verifiedViewerEmail
3680
+ options.viewer
3635
3681
  ),
3636
3682
  readRootConversationMetricsFromSql(getDb(), recentConversationIds)
3637
3683
  ]);
@@ -3667,19 +3713,6 @@ async function readPeopleProfile(email, options = {}) {
3667
3713
  await readPeopleProfileFromSql(email, options)
3668
3714
  );
3669
3715
  }
3670
- var profile_default = defineApiRoute({
3671
- method: "get",
3672
- path: "/:email",
3673
- responseSchema: actorProfileReportSchema,
3674
- handler: async (c) => {
3675
- const { email } = parseParams(personParamsSchema, c.req.param());
3676
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
3677
- return readPeopleProfile(
3678
- email,
3679
- verifiedViewerEmail ? { verifiedViewerEmail } : {}
3680
- );
3681
- }
3682
- });
3683
3716
 
3684
3717
  // src/api/people/spend.query.ts
3685
3718
  import { and as and13, eq as eq14, gte as gte5, lte as lte2, sql as sql11 } from "drizzle-orm";
@@ -3741,9 +3774,9 @@ async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
3741
3774
 
3742
3775
  // src/api/people/spend.ts
3743
3776
  var PERSONAL_SPEND_CACHE_TTL_MS = 5 * 6e4;
3744
- function createPersonalSpendRoute() {
3777
+ function createPersonalSpendReader() {
3745
3778
  const cache = /* @__PURE__ */ new Map();
3746
- async function read(email) {
3779
+ return async function readPersonalSpend(email) {
3747
3780
  const normalizedEmail = email.trim().toLowerCase();
3748
3781
  const nowMs = Date.now();
3749
3782
  const cached = cache.get(normalizedEmail);
@@ -3763,39 +3796,39 @@ function createPersonalSpendRoute() {
3763
3796
  if (cache.get(normalizedEmail) === entry) cache.delete(normalizedEmail);
3764
3797
  throw error;
3765
3798
  }
3766
- }
3767
- return defineApiRoute({
3768
- method: "get",
3769
- path: "/me/spend",
3770
- responseSchema: personalSpendReportSchema,
3771
- handler: async (context) => {
3772
- const email = context.get("verifiedViewerEmail");
3773
- if (!email) throwApiError(403, "Verified viewer email required.");
3774
- return read(email);
3775
- }
3776
- });
3799
+ };
3777
3800
  }
3778
3801
 
3779
3802
  // src/api/people/routes.ts
3780
3803
  function createPeopleRoutes() {
3781
3804
  const app = new Hono3();
3782
- const routes5 = [
3783
- createPersonalSpendRoute(),
3784
- list_default3,
3785
- profile_default
3786
- ];
3787
- registerApiRoutes(app, routes5);
3805
+ const readPersonalSpend = createPersonalSpendReader();
3806
+ app.get("/me/spend", requireViewer, async (context) => {
3807
+ const viewer = context.get("viewer");
3808
+ return jsonResponse(
3809
+ personalSpendReportSchema,
3810
+ await readPersonalSpend(viewer.email)
3811
+ );
3812
+ });
3813
+ app.get(
3814
+ "/",
3815
+ async () => jsonResponse(actorDirectoryReportSchema, await readPeopleList())
3816
+ );
3817
+ app.get(
3818
+ "/:email",
3819
+ validateRequest("param", personParamsSchema, "Invalid route parameters."),
3820
+ async (context) => {
3821
+ const { email } = context.req.valid("param");
3822
+ const viewer = context.get("viewer");
3823
+ return jsonResponse(
3824
+ actorProfileReportSchema,
3825
+ await readPeopleProfile(email, viewer ? { viewer } : {})
3826
+ );
3827
+ }
3828
+ );
3788
3829
  return app;
3789
3830
  }
3790
3831
 
3791
- // src/api/plugin-reports.ts
3792
- var plugin_reports_default = defineApiRoute({
3793
- method: "get",
3794
- path: "/api/plugin-reports",
3795
- responseSchema: pluginOperationalReportFeedSchema,
3796
- handler: readPluginOperationalReportFeed
3797
- });
3798
-
3799
3832
  // src/api/personal-tokens/routes.ts
3800
3833
  import { Hono as Hono4 } from "hono";
3801
3834
 
@@ -3874,63 +3907,57 @@ async function authenticatePersonalToken(token2, now = /* @__PURE__ */ new Date(
3874
3907
  return match.ownerEmailNormalized;
3875
3908
  }
3876
3909
 
3877
- // src/api/personal-tokens/create.ts
3878
- var create_default = defineApiRoute({
3879
- method: "post",
3880
- path: "/",
3881
- responseSchema: createdPersonalTokenSchema,
3882
- handler: async (c) => {
3883
- const email = c.get("verifiedViewerEmail");
3884
- if (!email) throwApiError(403, "Verified viewer email required.");
3885
- let input;
3886
- try {
3887
- input = await c.req.json();
3888
- } catch (error) {
3889
- throwApiError(400, "Invalid request body.", error);
3890
- }
3891
- const body = parseBody(createPersonalTokenBodySchema, input);
3892
- return createPersonalToken({ email, name: body.name });
3893
- }
3894
- });
3895
-
3896
- // src/api/personal-tokens/list.ts
3897
- var list_default4 = defineApiRoute({
3898
- method: "get",
3899
- path: "/",
3900
- responseSchema: personalTokenListSchema,
3901
- handler: async (c) => {
3902
- const email = c.get("verifiedViewerEmail");
3903
- if (!email) throwApiError(403, "Verified viewer email required.");
3904
- return { tokens: await listPersonalTokens(email) };
3905
- }
3906
- });
3907
-
3908
- // src/api/personal-tokens/revoke.ts
3909
- var revoke_default = defineApiRoute({
3910
- method: "delete",
3911
- path: "/:id",
3912
- responseSchema: revokePersonalTokenResponseSchema,
3913
- handler: async (c) => {
3914
- const email = c.get("verifiedViewerEmail");
3915
- if (!email) throwApiError(403, "Verified viewer email required.");
3916
- const { id } = parseParams(personalTokenParamsSchema, c.req.param());
3917
- if (!await revokePersonalToken({ email, id })) {
3918
- throwApiError(404, "Personal API token not found.");
3919
- }
3920
- return { revoked: true };
3921
- }
3922
- });
3923
-
3924
3910
  // src/api/personal-tokens/routes.ts
3925
- var routes3 = [list_default4, create_default, revoke_default];
3926
3911
  function createPersonalTokenRoutes() {
3927
3912
  const app = new Hono4();
3928
- registerApiRoutes(app, routes3);
3913
+ app.get("/", requireViewer, async (context) => {
3914
+ const viewer = context.get("viewer");
3915
+ return jsonResponse(personalTokenListSchema, {
3916
+ tokens: await listPersonalTokens(viewer.email)
3917
+ });
3918
+ });
3919
+ app.post(
3920
+ "/",
3921
+ requireViewer,
3922
+ validateRequest(
3923
+ "json",
3924
+ createPersonalTokenBodySchema,
3925
+ "Invalid request body."
3926
+ ),
3927
+ async (context) => {
3928
+ const viewer = context.get("viewer");
3929
+ const body = context.req.valid("json");
3930
+ return jsonResponse(
3931
+ createdPersonalTokenSchema,
3932
+ await createPersonalToken({ email: viewer.email, name: body.name })
3933
+ );
3934
+ }
3935
+ );
3936
+ app.delete(
3937
+ "/:id",
3938
+ requireViewer,
3939
+ validateRequest(
3940
+ "param",
3941
+ personalTokenParamsSchema,
3942
+ "Invalid route parameters."
3943
+ ),
3944
+ async (context) => {
3945
+ const viewer = context.get("viewer");
3946
+ const { id } = context.req.valid("param");
3947
+ if (!await revokePersonalToken({ email: viewer.email, id })) {
3948
+ throwApiError(404, "Personal API token not found.");
3949
+ }
3950
+ return jsonResponse(revokePersonalTokenResponseSchema, {
3951
+ revoked: true
3952
+ });
3953
+ }
3954
+ );
3929
3955
  return app;
3930
3956
  }
3931
3957
 
3932
3958
  // src/api/user-pages/routes.ts
3933
3959
  import { Hono as Hono5 } from "hono";
3960
+ import { z as z4 } from "zod";
3934
3961
  import {
3935
3962
  pluginUserPageContentSchema as pluginUserPageContentSchema2,
3936
3963
  pluginUserPageInputSchema,
@@ -3968,8 +3995,8 @@ async function readPluginUserPage(input) {
3968
3995
  (candidate) => candidate.id === input.pageId
3969
3996
  );
3970
3997
  if (!plugin || !page) return void 0;
3971
- const viewer2 = await resolveViewerUser(input.email);
3972
- if (!viewer2) {
3998
+ const viewer = await resolveViewerUser(input.email);
3999
+ if (!viewer) {
3973
4000
  throw new Error("Authenticated viewer user could not be resolved");
3974
4001
  }
3975
4002
  const content = pluginUserPageContentSchema.parse(
@@ -3978,7 +4005,7 @@ async function readPluginUserPage(input) {
3978
4005
  db: getDb(),
3979
4006
  log: createPluginLogger(plugin.manifest.name),
3980
4007
  plugin: { name: plugin.manifest.name },
3981
- viewer: viewer2
4008
+ viewer
3982
4009
  },
3983
4010
  input.query
3984
4011
  )
@@ -3996,167 +4023,114 @@ async function readPluginUserPage(input) {
3996
4023
  }
3997
4024
 
3998
4025
  // src/api/user-pages/routes.ts
4026
+ var userPageQuerySchema = z4.object({
4027
+ cursor: z4.preprocess(
4028
+ (value) => value || void 0,
4029
+ pluginUserPageInputSchema.shape.cursor
4030
+ ),
4031
+ filter: z4.preprocess(
4032
+ (value) => value || void 0,
4033
+ pluginUserPageInputSchema.shape.filter
4034
+ ),
4035
+ limit: z4.preprocess(
4036
+ (value) => value === "" ? void 0 : value,
4037
+ z4.coerce.number().int().min(1).max(50).default(20)
4038
+ ),
4039
+ q: z4.preprocess(
4040
+ (value) => value || void 0,
4041
+ pluginUserPageInputSchema.shape.query
4042
+ )
4043
+ });
3999
4044
  function createUserPageRoutes() {
4000
4045
  const app = new Hono5();
4001
4046
  app.get(
4002
4047
  "/",
4003
4048
  () => jsonResponse(pluginUserPageLinksSchema2, readPluginUserPageLinks())
4004
4049
  );
4005
- app.get("/:pluginName/:pageId", async (context) => {
4006
- const email = context.get("verifiedViewerEmail")?.trim();
4007
- if (!email) {
4008
- return jsonResponse(
4009
- apiErrorSchema,
4010
- { error: "Authentication required." },
4011
- { status: 401 }
4012
- );
4013
- }
4014
- const pageInput = pluginUserPageInputSchema.safeParse({
4015
- cursor: context.req.query("cursor") || void 0,
4016
- filter: context.req.query("filter") || void 0,
4017
- limit: context.req.query("limit") ? Number(context.req.query("limit")) : 20,
4018
- query: context.req.query("q") || void 0
4019
- });
4020
- if (!pageInput.success) {
4021
- return jsonResponse(
4050
+ app.get(
4051
+ "/:pluginName/:pageId",
4052
+ requireViewer,
4053
+ validateRequest("query", userPageQuerySchema, "Invalid user page query."),
4054
+ async (context) => {
4055
+ const viewer = context.get("viewer");
4056
+ const { q, ...query } = context.req.valid("query");
4057
+ const page = await readPluginUserPage({
4058
+ email: viewer.email,
4059
+ pageId: context.req.param("pageId"),
4060
+ pluginName: context.req.param("pluginName"),
4061
+ query: { ...query, ...q === void 0 ? {} : { query: q } }
4062
+ });
4063
+ return page ? jsonResponse(pluginUserPageContentSchema2, page) : jsonResponse(
4022
4064
  apiErrorSchema,
4023
- { error: "Invalid user page query." },
4024
- { status: 400 }
4065
+ { error: "User page not found." },
4066
+ { status: 404 }
4025
4067
  );
4026
4068
  }
4027
- const page = await readPluginUserPage({
4028
- email,
4029
- pageId: context.req.param("pageId"),
4030
- pluginName: context.req.param("pluginName"),
4031
- query: pageInput.data
4032
- });
4033
- return page ? jsonResponse(pluginUserPageContentSchema2, page) : jsonResponse(
4034
- apiErrorSchema,
4035
- { error: "User page not found." },
4036
- { status: 404 }
4037
- );
4038
- });
4069
+ );
4039
4070
  return app;
4040
4071
  }
4041
4072
 
4042
4073
  // src/api/tasks/routes.ts
4043
4074
  import { Hono as Hono6 } from "hono";
4044
- async function viewer(context) {
4045
- const email = context.get("verifiedViewerEmail")?.trim();
4046
- return email ? await resolveViewerUser(email) : void 0;
4047
- }
4048
4075
  function createTaskRoutes() {
4049
4076
  const app = new Hono6();
4050
- app.get("/", async (context) => {
4051
- const user = await viewer(context);
4052
- return user ? jsonResponse(taskListSchema, await readViewerTasks(user)) : jsonResponse(
4053
- apiErrorSchema,
4054
- { error: "Authentication required." },
4055
- { status: 401 }
4056
- );
4077
+ app.get("/", requireViewer, async (context) => {
4078
+ const user = context.get("viewer");
4079
+ return jsonResponse(taskListSchema, await readViewerTasks(user));
4057
4080
  });
4058
- app.get("/runs", async (context) => {
4059
- const user = await viewer(context);
4060
- return user ? jsonResponse(taskRunListSchema, await readViewerTaskRuns(user)) : jsonResponse(
4061
- apiErrorSchema,
4062
- { error: "Authentication required." },
4063
- { status: 401 }
4064
- );
4081
+ app.get("/runs", requireViewer, async (context) => {
4082
+ const user = context.get("viewer");
4083
+ return jsonResponse(taskRunListSchema, await readViewerTaskRuns(user));
4065
4084
  });
4066
- app.get("/:kind/:id/executions", async (context) => {
4067
- const user = await viewer(context);
4068
- if (!user) {
4069
- return jsonResponse(
4070
- apiErrorSchema,
4071
- { error: "Authentication required." },
4072
- { status: 401 }
4073
- );
4074
- }
4075
- const params = taskParamsSchema.safeParse(context.req.param());
4076
- if (!params.success) {
4077
- return jsonResponse(
4078
- apiErrorSchema,
4079
- { error: "Invalid task." },
4080
- { status: 400 }
4081
- );
4082
- }
4083
- try {
4084
- return jsonResponse(
4085
- taskExecutionListSchema,
4086
- await readViewerTaskExecutions(user, params.data.kind, params.data.id)
4087
- );
4088
- } catch (error) {
4089
- if (error instanceof ViewerTaskNotFoundError) {
4085
+ app.get(
4086
+ "/:kind/:id/executions",
4087
+ requireViewer,
4088
+ validateRequest("param", taskParamsSchema, "Invalid task."),
4089
+ async (context) => {
4090
+ const user = context.get("viewer");
4091
+ const params = context.req.valid("param");
4092
+ try {
4090
4093
  return jsonResponse(
4091
- apiErrorSchema,
4092
- { error: error.message },
4093
- { status: 404 }
4094
+ taskExecutionListSchema,
4095
+ await readViewerTaskExecutions(user, params.kind, params.id)
4094
4096
  );
4097
+ } catch (error) {
4098
+ if (error instanceof ViewerTaskNotFoundError) {
4099
+ return jsonResponse(
4100
+ apiErrorSchema,
4101
+ { error: error.message },
4102
+ { status: 404 }
4103
+ );
4104
+ }
4105
+ throw error;
4095
4106
  }
4096
- throw error;
4097
4107
  }
4098
- });
4099
- app.delete("/:kind/:id", async (context) => {
4100
- const user = await viewer(context);
4101
- if (!user) {
4102
- return jsonResponse(
4103
- apiErrorSchema,
4104
- { error: "Authentication required." },
4105
- { status: 401 }
4106
- );
4107
- }
4108
- const params = taskParamsSchema.safeParse(context.req.param());
4109
- if (!params.success) {
4110
- return jsonResponse(
4111
- apiErrorSchema,
4112
- { error: "Invalid task." },
4113
- { status: 400 }
4114
- );
4115
- }
4116
- try {
4117
- await deleteViewerTask(user, params.data.kind, params.data.id);
4118
- return new Response(null, {
4119
- headers: { "cache-control": "no-store" },
4120
- status: 204
4121
- });
4122
- } catch (error) {
4123
- if (error instanceof ViewerTaskNotFoundError) {
4124
- return jsonResponse(
4125
- apiErrorSchema,
4126
- { error: error.message },
4127
- { status: 404 }
4128
- );
4108
+ );
4109
+ app.delete(
4110
+ "/:kind/:id",
4111
+ requireViewer,
4112
+ validateRequest("param", taskParamsSchema, "Invalid task."),
4113
+ async (context) => {
4114
+ const user = context.get("viewer");
4115
+ const params = context.req.valid("param");
4116
+ try {
4117
+ await deleteViewerTask(user, params.kind, params.id);
4118
+ return emptyResponse();
4119
+ } catch (error) {
4120
+ if (error instanceof ViewerTaskNotFoundError) {
4121
+ return jsonResponse(
4122
+ apiErrorSchema,
4123
+ { error: error.message },
4124
+ { status: 404 }
4125
+ );
4126
+ }
4127
+ throw error;
4129
4128
  }
4130
- throw error;
4131
4129
  }
4132
- });
4130
+ );
4133
4131
  return app;
4134
4132
  }
4135
4133
 
4136
- // src/api/plugins.ts
4137
- var plugins_default = defineApiRoute({
4138
- method: "get",
4139
- path: "/api/plugins",
4140
- responseSchema: pluginsSchema,
4141
- handler: readPlugins
4142
- });
4143
-
4144
- // src/api/runtime.ts
4145
- var runtime_default = defineApiRoute({
4146
- method: "get",
4147
- path: "/api/runtime",
4148
- responseSchema: runtimeInfoReportSchema,
4149
- handler: readRuntimeInfoReport
4150
- });
4151
-
4152
- // src/api/skills.ts
4153
- var skills_default = defineApiRoute({
4154
- method: "get",
4155
- path: "/api/skills",
4156
- responseSchema: skillReportsSchema,
4157
- handler: readSkillReports
4158
- });
4159
-
4160
4134
  // src/api/stats.ts
4161
4135
  var WINDOW_DAYS2 = 90;
4162
4136
  async function readStatsReport() {
@@ -4173,25 +4147,96 @@ async function readStatsReport() {
4173
4147
  windowStart: start
4174
4148
  });
4175
4149
  }
4176
- var stats_default2 = defineApiRoute({
4177
- method: "get",
4178
- path: "/api/stats",
4179
- responseSchema: statsReportSchema,
4180
- handler: readStatsReport
4181
- });
4150
+
4151
+ // src/reporting.ts
4152
+ import { readFileSync } from "fs";
4153
+ import path from "path";
4154
+ function readDescriptionText(home) {
4155
+ try {
4156
+ const raw = readFileSync(path.join(home, "DESCRIPTION.md"), "utf8").trim();
4157
+ return raw || void 0;
4158
+ } catch {
4159
+ return void 0;
4160
+ }
4161
+ }
4162
+ async function readSkillReports() {
4163
+ const { discoverSkills } = await import("./skills-P7YUFSXM.js");
4164
+ const skills = await discoverSkills();
4165
+ return skillReportsSchema.parse(
4166
+ skills.map((skill) => ({
4167
+ name: skill.name,
4168
+ pluginProvider: skill.pluginProvider
4169
+ }))
4170
+ );
4171
+ }
4172
+ async function readPlugins() {
4173
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-WADOZVTB.js");
4174
+ return pluginsSchema.parse(
4175
+ pluginCatalogRuntime.getProviders().map((plugin) => ({
4176
+ configKeys: plugin.manifest.configKeys ?? [],
4177
+ description: plugin.manifest.description,
4178
+ displayName: plugin.manifest.displayName,
4179
+ name: plugin.manifest.name
4180
+ }))
4181
+ );
4182
+ }
4183
+ async function readRuntimeInfoReport() {
4184
+ const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
4185
+ import("./discovery-GUFTFBTL.js"),
4186
+ import("./catalog-runtime-WADOZVTB.js"),
4187
+ readPlugins(),
4188
+ readSkillReports()
4189
+ ]);
4190
+ const home = homeDir();
4191
+ return runtimeInfoReportSchema.parse({
4192
+ cwd: process.cwd(),
4193
+ homeDir: home,
4194
+ descriptionText: readDescriptionText(home),
4195
+ providers: plugins.map((plugin) => plugin.name),
4196
+ skills,
4197
+ packagedContent: pluginCatalogRuntime.getPackageContent()
4198
+ });
4199
+ }
4200
+ async function readPluginOperationalReportFeed() {
4201
+ const nowMs = Date.now();
4202
+ const { getPluginOperationalReports } = await import("./agent-hooks-VAUYT6PD.js");
4203
+ return pluginOperationalReportFeedSchema.parse({
4204
+ source: "plugins",
4205
+ generatedAt: new Date(nowMs).toISOString(),
4206
+ reports: await getPluginOperationalReports(nowMs)
4207
+ });
4208
+ }
4182
4209
 
4183
4210
  // src/api.ts
4184
- var routes4 = [
4185
- health_default,
4186
- runtime_default,
4187
- plugins_default,
4188
- skills_default,
4189
- plugin_reports_default,
4190
- stats_default2
4191
- ];
4192
4211
  function createJuniorApi() {
4193
4212
  const app = new Hono7();
4194
- registerApiRoutes(app, routes4);
4213
+ app.get(
4214
+ "/api/health",
4215
+ async () => jsonResponse(healthReportSchema, readHealthReport())
4216
+ );
4217
+ app.get(
4218
+ "/api/runtime",
4219
+ async () => jsonResponse(runtimeInfoReportSchema, await readRuntimeInfoReport())
4220
+ );
4221
+ app.get(
4222
+ "/api/plugins",
4223
+ async () => jsonResponse(pluginsSchema, await readPlugins())
4224
+ );
4225
+ app.get(
4226
+ "/api/skills",
4227
+ async () => jsonResponse(skillReportsSchema, await readSkillReports())
4228
+ );
4229
+ app.get(
4230
+ "/api/plugin-reports",
4231
+ async () => jsonResponse(
4232
+ pluginOperationalReportFeedSchema,
4233
+ await readPluginOperationalReportFeed()
4234
+ )
4235
+ );
4236
+ app.get(
4237
+ "/api/stats",
4238
+ async () => jsonResponse(statsReportSchema, await readStatsReport())
4239
+ );
4195
4240
  app.route("/api/conversations", createConversationRoutes());
4196
4241
  app.route("/api/personal-tokens", createPersonalTokenRoutes());
4197
4242
  app.route("/api/people", createPeopleRoutes());
@@ -4207,10 +4252,27 @@ function createJuniorApi() {
4207
4252
  }
4208
4253
  )
4209
4254
  );
4255
+ app.onError((error, _context) => {
4256
+ if (error instanceof HTTPException2) {
4257
+ if (error.res) return error.res;
4258
+ return jsonResponse(
4259
+ apiErrorSchema,
4260
+ { error: error.message || "Request failed." },
4261
+ { status: error.status }
4262
+ );
4263
+ }
4264
+ logException(error, "api.unhandled.exception");
4265
+ return jsonResponse(
4266
+ apiErrorSchema,
4267
+ { error: "Internal Server Error" },
4268
+ { status: 500 }
4269
+ );
4270
+ });
4210
4271
  return app;
4211
4272
  }
4212
4273
  export {
4213
4274
  authenticatePersonalToken,
4214
4275
  createJuniorApi,
4215
- jsonResponse
4276
+ jsonResponse,
4277
+ resolveViewerUser
4216
4278
  };