@sentry/junior 0.146.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 (227) hide show
  1. package/dist/{agent-hooks-SLJADYE5.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 -295
  6. package/dist/api/conversations/event-list.d.ts +2 -192
  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 +64 -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 +630 -564
  33. package/dist/app.js +369 -309
  34. package/dist/{catalog-runtime-RQIMSDPR.js → catalog-runtime-WADOZVTB.js} +5 -5
  35. package/dist/chat/actor.d.ts +4 -1
  36. package/dist/chat/agent/prompt.d.ts +0 -2
  37. package/dist/chat/agent/request.d.ts +4 -5
  38. package/dist/chat/agent/resume.d.ts +1 -0
  39. package/dist/chat/agent/sandbox.d.ts +2 -2
  40. package/dist/chat/agent/tools.d.ts +0 -2
  41. package/dist/chat/agent-dispatch/context.d.ts +2 -2
  42. package/dist/chat/agent-dispatch/types.d.ts +2 -2
  43. package/dist/chat/agent-invocations/types.d.ts +52 -0
  44. package/dist/chat/api-turns/work.d.ts +103 -0
  45. package/dist/chat/capabilities/jr-rpc-command.d.ts +2 -2
  46. package/dist/chat/configuration/service.d.ts +5 -2
  47. package/dist/chat/configuration/sql.d.ts +9 -0
  48. package/dist/chat/configuration/types.d.ts +17 -13
  49. package/dist/chat/conversations/history.d.ts +63 -0
  50. package/dist/chat/conversations/projection.d.ts +10 -0
  51. package/dist/chat/conversations/provenance.d.ts +6 -0
  52. package/dist/chat/conversations/sql/actor-identity.d.ts +19 -0
  53. package/dist/chat/conversations/store.d.ts +1 -1
  54. package/dist/chat/credentials/unlink-provider.d.ts +2 -1
  55. package/dist/chat/credentials/user-token-store.d.ts +2 -0
  56. package/dist/chat/event-tasks/tool-support.d.ts +2 -0
  57. package/dist/chat/identities/sql.d.ts +8 -0
  58. package/dist/chat/logging.d.ts +2 -0
  59. package/dist/chat/mcp/auth-store.d.ts +0 -2
  60. package/dist/chat/mcp/oauth.d.ts +0 -2
  61. package/dist/chat/oauth-flow.d.ts +3 -1
  62. package/dist/chat/pi/client.d.ts +2 -0
  63. package/dist/chat/plugins/credential-hooks.d.ts +2 -0
  64. package/dist/chat/prompt.d.ts +0 -2
  65. package/dist/chat/resource-events/notification.d.ts +2 -1
  66. package/dist/chat/resource-events/store.d.ts +1 -1
  67. package/dist/chat/runtime/delivered-turn-state.d.ts +1 -4
  68. package/dist/chat/runtime/reply-executor.d.ts +1 -1
  69. package/dist/chat/runtime/slack-runtime.d.ts +2 -1
  70. package/dist/chat/runtime/thread-state.d.ts +8 -11
  71. package/dist/chat/runtime/turn-input.d.ts +4 -2
  72. package/dist/chat/runtime/turn-preparation.d.ts +11 -4
  73. package/dist/chat/sandbox/command-result.d.ts +2 -0
  74. package/dist/chat/sandbox/egress/schemas.d.ts +6 -0
  75. package/dist/chat/scheduled-tasks/tool-support.d.ts +7 -5
  76. package/dist/chat/scheduled-tasks/tools/create.d.ts +4 -2
  77. package/dist/chat/scheduled-tasks/tools/delete.d.ts +4 -2
  78. package/dist/chat/scheduled-tasks/tools/list.d.ts +4 -2
  79. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +4 -2
  80. package/dist/chat/scheduled-tasks/tools/update.d.ts +4 -2
  81. package/dist/chat/services/mcp-auth-orchestration.d.ts +0 -3
  82. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -1
  83. package/dist/chat/services/provider-default-config.d.ts +2 -2
  84. package/dist/chat/services/subscribed-decision.d.ts +3 -0
  85. package/dist/chat/services/subscribed-reply-policy.d.ts +1 -0
  86. package/dist/chat/services/turn-result.d.ts +0 -3
  87. package/dist/chat/services/turn-router.d.ts +3 -0
  88. package/dist/chat/slack/assistant-thread/lifecycle.d.ts +0 -1
  89. package/dist/chat/slack/assistant-thread/title.d.ts +0 -3
  90. package/dist/chat/slack/channel.d.ts +26 -0
  91. package/dist/chat/slack/dispatch-turn.d.ts +2 -1
  92. package/dist/chat/slack/timestamp-param.d.ts +0 -2
  93. package/dist/chat/slack/{tools → tool-support}/canvas/api.d.ts +1 -1
  94. package/dist/chat/slack/tool-support/canvas/context.d.ts +11 -0
  95. package/dist/chat/slack/tool-support/channel-access.d.ts +42 -0
  96. package/dist/chat/slack/tool-support/channel-target.d.ts +27 -0
  97. package/dist/chat/slack/{tools → tool-support}/list/api.d.ts +8 -1
  98. package/dist/chat/slack/tool-support/list/params.d.ts +5 -0
  99. package/dist/chat/slack/tools/canvas/create.d.ts +3 -1
  100. package/dist/chat/slack/tools/canvas/edit.d.ts +2 -0
  101. package/dist/chat/slack/tools/canvas/read.d.ts +2 -0
  102. package/dist/chat/slack/tools/canvas/write.d.ts +2 -0
  103. package/dist/chat/slack/tools/{user-lookup.d.ts → channel-join.d.ts} +6 -5
  104. package/dist/chat/slack/tools/channel-list-messages.d.ts +5 -2
  105. package/dist/chat/slack/tools/conversation-message-search.d.ts +4 -8
  106. package/dist/chat/slack/tools/list/add-items.d.ts +4 -1
  107. package/dist/chat/slack/tools/list/create.d.ts +2 -0
  108. package/dist/chat/slack/tools/list/get-items.d.ts +5 -3
  109. package/dist/chat/slack/tools/list/update-item.d.ts +5 -1
  110. package/dist/chat/slack/tools/message-add-reaction.d.ts +3 -1
  111. package/dist/chat/slack/tools/public-search.d.ts +65 -2
  112. package/dist/chat/slack/tools/send-files.d.ts +3 -1
  113. package/dist/chat/slack/tools/thread-read.d.ts +4 -5
  114. package/dist/chat/slack/vision-cache.d.ts +5 -0
  115. package/dist/chat/source.d.ts +2 -0
  116. package/dist/chat/state/conversation.d.ts +4 -5
  117. package/dist/chat/task-execution/checkpoint.d.ts +1 -0
  118. package/dist/chat/task-execution/state.d.ts +9 -4
  119. package/dist/chat/task-execution/store.d.ts +3 -2
  120. package/dist/chat/task-execution/turn-cursor.d.ts +2 -0
  121. package/dist/chat/task-execution/worker.d.ts +2 -0
  122. package/dist/chat/tasks/read.d.ts +1 -1
  123. package/dist/chat/tool-support/structured-result.d.ts +1 -0
  124. package/dist/chat/tool-support/timed-out-tool-result.d.ts +11 -0
  125. package/dist/chat/tools/create-event-task.d.ts +2 -0
  126. package/dist/chat/tools/delete-event-task.d.ts +2 -0
  127. package/dist/chat/tools/handoff/tool.d.ts +2 -0
  128. package/dist/chat/tools/list-event-tasks.d.ts +2 -0
  129. package/dist/chat/tools/list-resource-event-subscriptions.d.ts +2 -0
  130. package/dist/chat/tools/runtime/report-progress.d.ts +2 -0
  131. package/dist/chat/tools/runtime/spawn-agent.d.ts +2 -0
  132. package/dist/chat/tools/search-conversation-events.d.ts +3 -1
  133. package/dist/chat/tools/search-resource-event-types.d.ts +2 -0
  134. package/dist/chat/tools/search-tools.d.ts +2 -0
  135. package/dist/chat/tools/skill/load-skill.d.ts +2 -0
  136. package/dist/chat/tools/skill/search-mcp-tools.d.ts +2 -0
  137. package/dist/chat/tools/stop-watching-resources.d.ts +2 -0
  138. package/dist/chat/tools/system-time.d.ts +2 -0
  139. package/dist/chat/tools/types.d.ts +11 -10
  140. package/dist/chat/tools/update-event-task.d.ts +2 -0
  141. package/dist/chat/tools/user-lookup.d.ts +29 -0
  142. package/dist/chat/tools/watch-resource-events.d.ts +4 -2
  143. package/dist/chat/tools/web/fetch-tool.d.ts +2 -0
  144. package/dist/chat/tools/web/image-generate.d.ts +2 -0
  145. package/dist/chat/tools/web/search.d.ts +2 -0
  146. package/dist/{chunk-GYEKOX7N.js → chunk-2B3PT3V2.js} +1 -1
  147. package/dist/{chunk-JLMVCNXL.js → chunk-45LOR4PU.js} +22 -4
  148. package/dist/{chunk-FGHADGIC.js → chunk-4AQZYNHM.js} +2 -2
  149. package/dist/{chunk-W65V465O.js → chunk-4EA2SFK2.js} +66 -4
  150. package/dist/{chunk-MKRIZ4VG.js → chunk-4GXJUYJV.js} +4 -2
  151. package/dist/{chunk-F7REGDKO.js → chunk-55F4QU2V.js} +2 -1
  152. package/dist/{chunk-M6ZWP4RI.js → chunk-7OEIXFC3.js} +2 -2
  153. package/dist/{chunk-MCFIXAV5.js → chunk-D3WPMGEX.js} +55 -37
  154. package/dist/{chunk-AISNSNDV.js → chunk-D6YX4NNN.js} +22 -10
  155. package/dist/chunk-DUY5CDAM.js +36 -0
  156. package/dist/{chunk-B63BF443.js → chunk-EAI67NTM.js} +9 -1
  157. package/dist/{chunk-FEKQHPVA.js → chunk-EINWQFXI.js} +9 -8
  158. package/dist/chunk-GDFF3BQG.js +136 -0
  159. package/dist/{chunk-X22KCSCO.js → chunk-GXYDVZKM.js} +7 -5
  160. package/dist/{chunk-X2WMBTS3.js → chunk-HLPLT3NY.js} +8 -5
  161. package/dist/{chunk-PB222GIA.js → chunk-HWQGBIH7.js} +1 -1
  162. package/dist/chunk-IL4EDBMV.js +566 -0
  163. package/dist/{chunk-HQE6EJS5.js → chunk-LAZGHEYU.js} +1 -1
  164. package/dist/{chunk-QG7OOKIN.js → chunk-LE5H7LMT.js} +1 -1
  165. package/dist/chunk-LNVEIJ2L.js +48 -0
  166. package/dist/{chunk-JUA6VU2Z.js → chunk-OJCP3C3J.js} +12 -23
  167. package/dist/{chunk-37JJDS4H.js → chunk-POSZWRGL.js} +1 -1
  168. package/dist/{chunk-TCEJ7XXM.js → chunk-QOWHHM3F.js} +1 -1
  169. package/dist/{chunk-H6U2U3EP.js → chunk-RRJV5UR5.js} +304 -65
  170. package/dist/{chunk-OFPYOC3M.js → chunk-ULAU5ZGU.js} +127 -120
  171. package/dist/{chunk-V6SRLKUB.js → chunk-V2FXMOEA.js} +2 -2
  172. package/dist/{chunk-GDQEU4I7.js → chunk-VCYSOXON.js} +296 -526
  173. package/dist/{chunk-BLETMLRX.js → chunk-VMNRXKAH.js} +1374 -989
  174. package/dist/{chunk-37EVZP66.js → chunk-VRHTNBA6.js} +167 -92
  175. package/dist/{chunk-FXDDDSPL.js → chunk-VY6W3T43.js} +4 -4
  176. package/dist/{chunk-ZDGHGY74.js → chunk-WCN4YSH7.js} +13 -6
  177. package/dist/{chunk-PH4Q3A6W.js → chunk-WOONT5ZP.js} +1 -1
  178. package/dist/{chunk-47OSH2ZO.js → chunk-XJ42NBP5.js} +395 -206
  179. package/dist/{chunk-SCGVWUZX.js → chunk-ZCHIC2GM.js} +92 -75
  180. package/dist/chunk-ZPL2RR7F.js +798 -0
  181. package/dist/cli/chat.js +33 -35
  182. package/dist/cli/check.js +6 -6
  183. package/dist/cli/plugins.js +13 -13
  184. package/dist/cli/snapshot-create.js +9 -9
  185. package/dist/cli/upgrade.js +7 -7
  186. package/dist/db/schema/agent-invocations.d.ts +20 -0
  187. package/dist/db/schema/conversation-annotations.d.ts +2 -2
  188. package/dist/db/schema/location-configurations.d.ts +127 -0
  189. package/dist/db/schema.d.ts +150 -3
  190. package/dist/{db-WWOMXWTT.js → db-XUKZRFFK.js} +7 -7
  191. package/dist/instrumentation.js +4 -4
  192. package/dist/nitro.js +2 -2
  193. package/dist/{oauth-callback-server-A6ZZX74U.js → oauth-callback-server-LPZMMGFI.js} +25 -26
  194. package/dist/{runner-KSGB2UAV.js → runner-DGKUTMPX.js} +22 -41
  195. package/dist/{skills-26QPWKVS.js → skills-P7YUFSXM.js} +6 -6
  196. package/dist/spawn-DSK3ZEVD.js +38 -0
  197. package/dist/{validation-OPSRGFGH.js → validation-S7U5M5NR.js} +6 -6
  198. package/dist/version.js +1 -1
  199. package/dist/{work-VMSW7STJ.js → work-GAA7TVAD.js} +18 -19
  200. package/dist/{worker-2JNFB7C7.js → worker-JXPJH3QB.js} +11 -10
  201. package/migrations/0024_misty_typhoid_mary.sql +12 -0
  202. package/migrations/meta/0024_snapshot.json +2275 -0
  203. package/migrations/meta/_journal.json +7 -0
  204. package/package.json +6 -5
  205. package/dist/api/health.d.ts +0 -7
  206. package/dist/api/personal-tokens/create.d.ts +0 -11
  207. package/dist/api/personal-tokens/list.d.ts +0 -12
  208. package/dist/api/personal-tokens/revoke.d.ts +0 -5
  209. package/dist/api/plugin-reports.d.ts +0 -63
  210. package/dist/api/plugins.d.ts +0 -8
  211. package/dist/api/runtime.d.ts +0 -24
  212. package/dist/api/skills.d.ts +0 -6
  213. package/dist/chat/slack/tools/canvas/context.d.ts +0 -18
  214. package/dist/chat/slack/tools/channel-access.d.ts +0 -30
  215. package/dist/chat/state/artifacts.d.ts +0 -30
  216. package/dist/chat/tool-support/turn-deadline-result.d.ts +0 -3
  217. package/dist/chunk-HLXXQI5Q.js +0 -238
  218. package/dist/chunk-LVW7BLLT.js +0 -115
  219. package/dist/chunk-Q6QZTTLS.js +0 -55
  220. package/dist/chunk-QSXZ42KX.js +0 -285
  221. package/dist/chunk-R776HKPK.js +0 -81
  222. package/dist/chunk-T5GXFFLA.js +0 -67
  223. package/dist/spawn-5LAJXZ2P.js +0 -39
  224. /package/dist/chat/slack/{tools → tool-support}/canvas/markdown.d.ts +0 -0
  225. /package/dist/chat/slack/{tools → tool-support}/channel-capabilities.d.ts +0 -0
  226. /package/dist/chat/slack/{tools → tool-support}/context.d.ts +0 -0
  227. /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-JLMVCNXL.js";
35
+ } from "./chunk-45LOR4PU.js";
33
36
  import {
37
+ appendAndEnqueueApiConversationMessage,
38
+ createAndEnqueueApiConversation,
34
39
  formatSlackConversationRedactedLabel,
35
40
  readHealthReport,
36
- resolveSlackConversationContextFromThreadId
37
- } from "./chunk-LVW7BLLT.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-QSXZ42KX.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-X22KCSCO.js";
80
+ } from "./chunk-GXYDVZKM.js";
68
81
  import {
69
82
  parseSlackThreadId
70
- } from "./chunk-PH4Q3A6W.js";
83
+ } from "./chunk-WOONT5ZP.js";
71
84
  import {
72
85
  fallbackShortTitle
73
- } from "./chunk-W65V465O.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-SCGVWUZX.js";
100
+ } from "./chunk-ZCHIC2GM.js";
87
101
  import {
88
102
  getSlackClient,
89
103
  withSlackRetries
90
- } from "./chunk-V6SRLKUB.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-37EVZP66.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-MCFIXAV5.js";
119
+ } from "./chunk-D3WPMGEX.js";
105
120
  import "./chunk-EM225ITJ.js";
106
- import "./chunk-GYEKOX7N.js";
107
- import "./chunk-MKRIZ4VG.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-QG7OOKIN.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-B63BF443.js";
136
+ import {
137
+ logException
138
+ } from "./chunk-EAI67NTM.js";
121
139
  import "./chunk-6GWA276C.js";
122
- import "./chunk-HQE6EJS5.js";
123
- import "./chunk-F7REGDKO.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";
@@ -739,6 +861,7 @@ function reportEventData(args) {
739
861
  turnId: data.turnId,
740
862
  modelProfile: data.modelProfile,
741
863
  modelId: data.modelId,
864
+ ...data.costUsd !== void 0 ? { costUsd: data.costUsd } : {},
742
865
  reasoningLevel: data.reasoningLevel,
743
866
  ...data.confidence !== void 0 ? { confidence: data.confidence } : {},
744
867
  source: data.source
@@ -911,17 +1034,17 @@ async function readConversationEventRows(executor, args) {
911
1034
  end`
912
1035
  }).from(juniorConversationEvents).where(
913
1036
  and3(
914
- eq3(juniorConversationEvents.conversationId, args.conversationId),
1037
+ eq4(juniorConversationEvents.conversationId, args.conversationId),
915
1038
  args.beforeSeq === void 0 ? void 0 : lt(juniorConversationEvents.seq, args.beforeSeq),
916
- inArray(
1039
+ inArray2(
917
1040
  juniorConversationEvents.type,
918
1041
  args.types ?? [...conversationReportSourceEventTypes]
919
1042
  ),
920
- args.subagentInvocationIds === void 0 ? void 0 : inArray(
1043
+ args.subagentInvocationIds === void 0 ? void 0 : inArray2(
921
1044
  sql2`${juniorConversationEvents.payload}->>'subagentInvocationId'`,
922
1045
  args.subagentInvocationIds
923
1046
  ),
924
- args.toolCallIds === void 0 ? void 0 : inArray(
1047
+ args.toolCallIds === void 0 ? void 0 : inArray2(
925
1048
  sql2`${juniorConversationEvents.payload}->>'toolCallId'`,
926
1049
  args.toolCallIds
927
1050
  )
@@ -1042,8 +1165,8 @@ function surfaceFromConversationId(conversationId) {
1042
1165
  return "internal";
1043
1166
  }
1044
1167
  function surfaceFromSource(source, conversationId) {
1045
- if (source === "slack" || source === "api" || source === "scheduler") {
1046
- return source;
1168
+ if (source === "slack" || source === "api" || source === "web" || source === "scheduler") {
1169
+ return source === "web" ? "api" : source;
1047
1170
  }
1048
1171
  return surfaceFromConversationId(conversationId);
1049
1172
  }
@@ -1164,6 +1287,7 @@ function conversationSummaryFromStoredConversation(args) {
1164
1287
  visibility
1165
1288
  }),
1166
1289
  isParticipant: args.access?.isParticipant ?? false,
1290
+ ...visibility ? { visibility } : {},
1167
1291
  lastProgressAt: new Date(
1168
1292
  conversation.execution.updatedAtMs ?? conversation.updatedAtMs
1169
1293
  ).toISOString(),
@@ -1183,59 +1307,6 @@ function conversationSummaryFromStoredConversation(args) {
1183
1307
  };
1184
1308
  }
1185
1309
 
1186
- // src/api/conversations/access.ts
1187
- import { eq as eq4, inArray as inArray2 } from "drizzle-orm";
1188
- import { alias } from "drizzle-orm/pg-core";
1189
- var rootConversation = alias(juniorConversations, "access_root_conversation");
1190
- var rootDestination = alias(juniorDestinations, "access_root_destination");
1191
- var rootIdentity = alias(juniorIdentities, "access_root_identity");
1192
- async function readConversationAccessFromSql(db, conversationIds, verifiedViewerEmail) {
1193
- if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
1194
- const normalizedViewerEmail = verifiedViewerEmail?.trim().toLowerCase() || void 0;
1195
- const rows = await db.select({
1196
- conversationId: juniorConversations.conversationId,
1197
- parentConversationId: juniorConversations.parentConversationId,
1198
- storedRootConversationId: juniorConversations.rootConversationId,
1199
- rootConversationId: rootConversation.conversationId,
1200
- rootParentConversationId: rootConversation.parentConversationId,
1201
- rootRootConversationId: rootConversation.rootConversationId,
1202
- visibility: rootDestination.visibility,
1203
- rootEmailNormalized: rootIdentity.emailNormalized,
1204
- rootEmailVerified: rootIdentity.emailVerified
1205
- }).from(juniorConversations).leftJoin(
1206
- rootConversation,
1207
- eq4(
1208
- rootConversation.conversationId,
1209
- juniorConversations.rootConversationId
1210
- )
1211
- ).leftJoin(
1212
- rootDestination,
1213
- eq4(rootDestination.id, rootConversation.destinationId)
1214
- ).leftJoin(
1215
- rootIdentity,
1216
- eq4(rootIdentity.id, rootConversation.actorIdentityId)
1217
- ).where(inArray2(juniorConversations.conversationId, [...conversationIds]));
1218
- return new Map(
1219
- rows.map((row) => {
1220
- const hasValidRoot = row.rootConversationId !== null && row.rootConversationId === row.storedRootConversationId && row.rootRootConversationId === row.rootConversationId && row.rootParentConversationId === null && (row.parentConversationId !== null || row.storedRootConversationId === row.conversationId);
1221
- const validRootConversationId = hasValidRoot ? row.rootConversationId ?? void 0 : void 0;
1222
- const visibility = validRootConversationId === void 0 ? null : row.visibility;
1223
- const isParticipant = validRootConversationId !== void 0 && normalizedViewerEmail !== void 0 && row.rootEmailVerified === true && row.rootEmailNormalized === normalizedViewerEmail;
1224
- const canViewPrivateContent = isParticipant || validRootConversationId !== void 0 && canExposeConversationPayload({
1225
- visibility: visibility ?? void 0
1226
- });
1227
- return [
1228
- row.conversationId,
1229
- {
1230
- canViewPrivateContent,
1231
- isParticipant,
1232
- visibility
1233
- }
1234
- ];
1235
- })
1236
- );
1237
- }
1238
-
1239
1310
  // src/api/conversations/usage.ts
1240
1311
  import { and as and4, eq as eq5, inArray as inArray3, isNull, sql as sql3 } from "drizzle-orm";
1241
1312
  import { alias as alias2 } from "drizzle-orm/pg-core";
@@ -1359,7 +1430,7 @@ function eventCost() {
1359
1430
  WHEN ${juniorConversationEvents.type} = 'structured_event'
1360
1431
  AND jsonb_typeof(${juniorConversationEvents.payload}->'content'->'costUsd') = 'number'
1361
1432
  THEN (${juniorConversationEvents.payload}->'content'->>'costUsd')::numeric
1362
- WHEN ${juniorConversationEvents.type} = 'guardian_action_reviewed'
1433
+ WHEN ${juniorConversationEvents.type} IN ('guardian_action_reviewed', 'turn_routed')
1363
1434
  AND jsonb_typeof(${juniorConversationEvents.payload}->'costUsd') = 'number'
1364
1435
  THEN (${juniorConversationEvents.payload}->>'costUsd')::numeric
1365
1436
  ELSE NULL
@@ -1422,7 +1493,10 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
1422
1493
  selectedConversation,
1423
1494
  or(
1424
1495
  eq6(juniorConversationEvents.type, "structured_event"),
1425
- eq6(juniorConversationEvents.type, "guardian_action_reviewed")
1496
+ inArray4(juniorConversationEvents.type, [
1497
+ "guardian_action_reviewed",
1498
+ "turn_routed"
1499
+ ])
1426
1500
  ),
1427
1501
  sql4`${cost2} >= 0`
1428
1502
  )
@@ -1561,11 +1635,7 @@ async function readConversationFeedFromSql(options = {}) {
1561
1635
  metricsByRoot,
1562
1636
  teamDomainByTeamId
1563
1637
  ] = await Promise.all([
1564
- readConversationAccessFromSql(
1565
- db,
1566
- conversationIds,
1567
- options.verifiedViewerEmail
1568
- ),
1638
+ readConversationAccessFromSql(db, conversationIds, options.viewer),
1569
1639
  readConversationAuxiliaryCostsFromSql(db, conversationIds, {
1570
1640
  includeDescendants: true
1571
1641
  }),
@@ -1599,22 +1669,6 @@ async function readConversationFeed(options = {}) {
1599
1669
  await readConversationFeedFromSql(options)
1600
1670
  );
1601
1671
  }
1602
- var list_default = defineApiRoute({
1603
- method: "get",
1604
- path: "/",
1605
- responseSchema: conversationFeedSchema,
1606
- handler: async (c) => {
1607
- const { actorEmail } = parseQuery(
1608
- conversationFeedQuerySchema,
1609
- c.req.query()
1610
- );
1611
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
1612
- return readConversationFeed({
1613
- ...actorEmail ? { actorEmail } : {},
1614
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
1615
- });
1616
- }
1617
- });
1618
1672
 
1619
1673
  // src/chat/tasks/read.ts
1620
1674
  import { and as and7, eq as eq8, or as or2 } from "drizzle-orm";
@@ -2082,12 +2136,9 @@ async function readConversationSourceTask(args) {
2082
2136
  conversationId: args.conversationId
2083
2137
  });
2084
2138
  if (!execution) return void 0;
2085
- const email = args.verifiedViewerEmail?.trim();
2086
- if (!email) return { kind: execution.kind };
2087
- const user = await resolveViewerUser(email);
2088
- if (!user) return { kind: execution.kind };
2139
+ if (!args.viewer) return { kind: execution.kind };
2089
2140
  const candidate = await resolveViewerTaskCandidate(
2090
- user,
2141
+ args.viewer,
2091
2142
  execution.kind,
2092
2143
  execution.taskId
2093
2144
  );
@@ -2195,11 +2246,7 @@ async function readConversationDetailFromSql(conversationId, options) {
2195
2246
  sourceTask,
2196
2247
  teamDomainByTeamId
2197
2248
  ] = await Promise.all([
2198
- readConversationAccessFromSql(
2199
- getDb(),
2200
- [conversationId],
2201
- options.verifiedViewerEmail
2202
- ),
2249
+ readConversationAccessFromSql(getDb(), [conversationId], options.viewer),
2203
2250
  listConversationAnnotations(getDb(), conversationId),
2204
2251
  readConversationAuxiliaryCostsFromSql(getDb(), [conversationId], {
2205
2252
  includeDescendants: includeDescendantMetrics
@@ -2214,7 +2261,7 @@ async function readConversationDetailFromSql(conversationId, options) {
2214
2261
  ),
2215
2262
  readConversationSourceTask({
2216
2263
  conversationId,
2217
- ...options.verifiedViewerEmail ? { verifiedViewerEmail: options.verifiedViewerEmail } : {}
2264
+ ...options.viewer ? { viewer: options.viewer } : {}
2218
2265
  }),
2219
2266
  resolveSlackTeamDomains(
2220
2267
  record.conversation.sessionSource?.platform === "slack" ? [record.conversation.sessionSource.teamId] : []
@@ -2248,25 +2295,6 @@ async function readConversationDetail(conversationId, options = {}) {
2248
2295
  });
2249
2296
  return report ? conversationDetailReportSchema.parse(report) : void 0;
2250
2297
  }
2251
- var detail_default = defineApiRoute({
2252
- method: "get",
2253
- path: "/:conversationId",
2254
- responseSchema: conversationDetailReportSchema,
2255
- handler: async (c) => {
2256
- const { conversationId } = parseParams(
2257
- conversationParamsSchema,
2258
- c.req.param()
2259
- );
2260
- const query = parseQuery(conversationDetailQuerySchema, c.req.query());
2261
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
2262
- const report = await readConversationDetail(conversationId, {
2263
- ...query,
2264
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
2265
- });
2266
- if (!report) throwApiError(404, "Conversation not found.");
2267
- return report;
2268
- }
2269
- });
2270
2298
 
2271
2299
  // src/api/conversations/event-list.ts
2272
2300
  async function readConversationEvents(conversationId, beforeValue, options = {}) {
@@ -2280,7 +2308,7 @@ async function readConversationEvents(conversationId, beforeValue, options = {})
2280
2308
  const accessByConversation = await readConversationAccessFromSql(
2281
2309
  getDb(),
2282
2310
  [conversationId],
2283
- options.verifiedViewerEmail
2311
+ options.viewer
2284
2312
  );
2285
2313
  const access = accessByConversation.get(conversationId);
2286
2314
  const canExposePayload = access?.canViewPrivateContent ?? false;
@@ -2306,28 +2334,6 @@ async function readConversationEvents(conversationId, beforeValue, options = {})
2306
2334
  generatedAt: (/* @__PURE__ */ new Date()).toISOString()
2307
2335
  });
2308
2336
  }
2309
- var event_list_default = defineApiRoute({
2310
- method: "get",
2311
- path: "/:conversationId/events",
2312
- responseSchema: conversationEventPageSchema,
2313
- handler: async (c) => {
2314
- const { conversationId } = parseParams(
2315
- conversationParamsSchema,
2316
- c.req.param()
2317
- );
2318
- const { before, limit } = parseQuery(
2319
- conversationEventsQuerySchema,
2320
- c.req.query()
2321
- );
2322
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
2323
- const report = await readConversationEvents(conversationId, before, {
2324
- limit,
2325
- ...verifiedViewerEmail ? { verifiedViewerEmail } : {}
2326
- });
2327
- if (!report) throwApiError(404, "Conversation not found.");
2328
- return report;
2329
- }
2330
- });
2331
2337
 
2332
2338
  // src/api/conversations/stats.query.ts
2333
2339
  import { and as and8, eq as eq9, gte, isNull as isNull4, lte, sql as sql6 } from "drizzle-orm";
@@ -2428,7 +2434,7 @@ function actorLabel(row) {
2428
2434
  }
2429
2435
  function surfaceLabel(source) {
2430
2436
  if (source === "scheduler") return "Scheduler";
2431
- if (source === "api") return "API";
2437
+ if (source === "api" || source === "web") return "Web";
2432
2438
  if (source === "internal" || source === "local") return "Internal";
2433
2439
  return "Conversation";
2434
2440
  }
@@ -2684,93 +2690,144 @@ async function readConversationStats() {
2684
2690
  await readConversationStatsFromSql()
2685
2691
  );
2686
2692
  }
2687
- var stats_default = defineApiRoute({
2688
- method: "get",
2689
- path: "/stats",
2690
- responseSchema: conversationStatsReportSchema,
2691
- handler: readConversationStats
2692
- });
2693
2693
 
2694
2694
  // src/api/conversations/routes.ts
2695
- var routes = [
2696
- list_default,
2697
- stats_default,
2698
- archive_default,
2699
- event_list_default,
2700
- detail_default
2701
- ];
2702
2695
  function createConversationRoutes() {
2703
2696
  const app = new Hono();
2704
- registerApiRoutes(app, routes);
2705
- return app;
2706
- }
2707
-
2708
- // src/reporting.ts
2709
- import { readFileSync } from "fs";
2710
- import path from "path";
2711
- function readDescriptionText(home) {
2712
- try {
2713
- const raw = readFileSync(path.join(home, "DESCRIPTION.md"), "utf8").trim();
2714
- return raw || void 0;
2715
- } catch {
2716
- return void 0;
2717
- }
2718
- }
2719
- async function readSkillReports() {
2720
- const { discoverSkills } = await import("./skills-26QPWKVS.js");
2721
- const skills = await discoverSkills();
2722
- return skillReportsSchema.parse(
2723
- skills.map((skill) => ({
2724
- name: skill.name,
2725
- pluginProvider: skill.pluginProvider
2726
- }))
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
+ }
2727
2715
  );
2728
- }
2729
- async function readPlugins() {
2730
- const { pluginCatalogRuntime } = await import("./catalog-runtime-RQIMSDPR.js");
2731
- return pluginsSchema.parse(
2732
- pluginCatalogRuntime.getProviders().map((plugin) => ({
2733
- configKeys: plugin.manifest.configKeys ?? [],
2734
- description: plugin.manifest.description,
2735
- displayName: plugin.manifest.displayName,
2736
- name: plugin.manifest.name
2737
- }))
2716
+ app.get(
2717
+ "/stats",
2718
+ async () => jsonResponse(conversationStatsReportSchema, await readConversationStats())
2738
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;
2739
2830
  }
2740
- async function readRuntimeInfoReport() {
2741
- const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
2742
- import("./discovery-GUFTFBTL.js"),
2743
- import("./catalog-runtime-RQIMSDPR.js"),
2744
- readPlugins(),
2745
- readSkillReports()
2746
- ]);
2747
- const home = homeDir();
2748
- return runtimeInfoReportSchema.parse({
2749
- cwd: process.cwd(),
2750
- homeDir: home,
2751
- descriptionText: readDescriptionText(home),
2752
- providers: plugins.map((plugin) => plugin.name),
2753
- skills,
2754
- packagedContent: pluginCatalogRuntime.getPackageContent()
2755
- });
2756
- }
2757
- async function readPluginOperationalReportFeed() {
2758
- const nowMs = Date.now();
2759
- const { getPluginOperationalReports } = await import("./agent-hooks-SLJADYE5.js");
2760
- return pluginOperationalReportFeedSchema.parse({
2761
- source: "plugins",
2762
- generatedAt: new Date(nowMs).toISOString(),
2763
- reports: await getPluginOperationalReports(nowMs)
2764
- });
2765
- }
2766
-
2767
- // src/api/health.ts
2768
- var health_default = defineApiRoute({
2769
- method: "get",
2770
- path: "/api/health",
2771
- responseSchema: healthReportSchema,
2772
- handler: readHealthReport
2773
- });
2774
2831
 
2775
2832
  // src/api/locations/routes.ts
2776
2833
  import { Hono as Hono2 } from "hono";
@@ -3171,7 +3228,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
3171
3228
  readConversationAccessFromSql(
3172
3229
  getDb(),
3173
3230
  recentConversationIds,
3174
- options.verifiedViewerEmail
3231
+ options.viewer
3175
3232
  ),
3176
3233
  readRootConversationMetricsFromSql(getDb(), recentConversationIds)
3177
3234
  ]);
@@ -3199,21 +3256,6 @@ async function readLocationDetail(locationId, options = {}) {
3199
3256
  const report = await readLocationDetailFromSql(locationId, options);
3200
3257
  return report ? locationDetailReportSchema.parse(report) : void 0;
3201
3258
  }
3202
- var detail_default2 = defineApiRoute({
3203
- method: "get",
3204
- path: "/:locationId",
3205
- responseSchema: locationDetailReportSchema,
3206
- handler: async (c) => {
3207
- const { locationId } = parseParams(locationParamsSchema, c.req.param());
3208
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
3209
- const report = await readLocationDetail(
3210
- locationId,
3211
- verifiedViewerEmail ? { verifiedViewerEmail } : {}
3212
- );
3213
- if (!report) throwApiError(404, "Location not found.");
3214
- return report;
3215
- }
3216
- });
3217
3259
 
3218
3260
  // src/api/locations/list.ts
3219
3261
  async function readLocationDirectory() {
@@ -3221,18 +3263,32 @@ async function readLocationDirectory() {
3221
3263
  await readLocationDirectoryFromSql()
3222
3264
  );
3223
3265
  }
3224
- var list_default2 = defineApiRoute({
3225
- method: "get",
3226
- path: "/",
3227
- responseSchema: locationDirectoryReportSchema,
3228
- handler: readLocationDirectory
3229
- });
3230
3266
 
3231
3267
  // src/api/locations/routes.ts
3232
- var routes2 = [list_default2, detail_default2];
3233
3268
  function createLocationRoutes() {
3234
3269
  const app = new Hono2();
3235
- 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
+ );
3236
3292
  return app;
3237
3293
  }
3238
3294
 
@@ -3470,12 +3526,6 @@ async function readPeopleListFromSql() {
3470
3526
  async function readPeopleList() {
3471
3527
  return actorDirectoryReportSchema.parse(await readPeopleListFromSql());
3472
3528
  }
3473
- var list_default3 = defineApiRoute({
3474
- method: "get",
3475
- path: "/",
3476
- responseSchema: actorDirectoryReportSchema,
3477
- handler: readPeopleList
3478
- });
3479
3529
 
3480
3530
  // src/api/people/profile.query.ts
3481
3531
  import { and as and12, eq as eq13, gte as gte4, sql as sql10 } from "drizzle-orm";
@@ -3627,7 +3677,7 @@ async function readPeopleProfileFromSql(email, options = {}) {
3627
3677
  readConversationAccessFromSql(
3628
3678
  getDb(),
3629
3679
  recentConversationIds,
3630
- options.verifiedViewerEmail
3680
+ options.viewer
3631
3681
  ),
3632
3682
  readRootConversationMetricsFromSql(getDb(), recentConversationIds)
3633
3683
  ]);
@@ -3663,19 +3713,6 @@ async function readPeopleProfile(email, options = {}) {
3663
3713
  await readPeopleProfileFromSql(email, options)
3664
3714
  );
3665
3715
  }
3666
- var profile_default = defineApiRoute({
3667
- method: "get",
3668
- path: "/:email",
3669
- responseSchema: actorProfileReportSchema,
3670
- handler: async (c) => {
3671
- const { email } = parseParams(personParamsSchema, c.req.param());
3672
- const verifiedViewerEmail = c.get("verifiedViewerEmail");
3673
- return readPeopleProfile(
3674
- email,
3675
- verifiedViewerEmail ? { verifiedViewerEmail } : {}
3676
- );
3677
- }
3678
- });
3679
3716
 
3680
3717
  // src/api/people/spend.query.ts
3681
3718
  import { and as and13, eq as eq14, gte as gte5, lte as lte2, sql as sql11 } from "drizzle-orm";
@@ -3737,9 +3774,9 @@ async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
3737
3774
 
3738
3775
  // src/api/people/spend.ts
3739
3776
  var PERSONAL_SPEND_CACHE_TTL_MS = 5 * 6e4;
3740
- function createPersonalSpendRoute() {
3777
+ function createPersonalSpendReader() {
3741
3778
  const cache = /* @__PURE__ */ new Map();
3742
- async function read(email) {
3779
+ return async function readPersonalSpend(email) {
3743
3780
  const normalizedEmail = email.trim().toLowerCase();
3744
3781
  const nowMs = Date.now();
3745
3782
  const cached = cache.get(normalizedEmail);
@@ -3759,39 +3796,39 @@ function createPersonalSpendRoute() {
3759
3796
  if (cache.get(normalizedEmail) === entry) cache.delete(normalizedEmail);
3760
3797
  throw error;
3761
3798
  }
3762
- }
3763
- return defineApiRoute({
3764
- method: "get",
3765
- path: "/me/spend",
3766
- responseSchema: personalSpendReportSchema,
3767
- handler: async (context) => {
3768
- const email = context.get("verifiedViewerEmail");
3769
- if (!email) throwApiError(403, "Verified viewer email required.");
3770
- return read(email);
3771
- }
3772
- });
3799
+ };
3773
3800
  }
3774
3801
 
3775
3802
  // src/api/people/routes.ts
3776
3803
  function createPeopleRoutes() {
3777
3804
  const app = new Hono3();
3778
- const routes5 = [
3779
- createPersonalSpendRoute(),
3780
- list_default3,
3781
- profile_default
3782
- ];
3783
- 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
+ );
3784
3829
  return app;
3785
3830
  }
3786
3831
 
3787
- // src/api/plugin-reports.ts
3788
- var plugin_reports_default = defineApiRoute({
3789
- method: "get",
3790
- path: "/api/plugin-reports",
3791
- responseSchema: pluginOperationalReportFeedSchema,
3792
- handler: readPluginOperationalReportFeed
3793
- });
3794
-
3795
3832
  // src/api/personal-tokens/routes.ts
3796
3833
  import { Hono as Hono4 } from "hono";
3797
3834
 
@@ -3870,63 +3907,57 @@ async function authenticatePersonalToken(token2, now = /* @__PURE__ */ new Date(
3870
3907
  return match.ownerEmailNormalized;
3871
3908
  }
3872
3909
 
3873
- // src/api/personal-tokens/create.ts
3874
- var create_default = defineApiRoute({
3875
- method: "post",
3876
- path: "/",
3877
- responseSchema: createdPersonalTokenSchema,
3878
- handler: async (c) => {
3879
- const email = c.get("verifiedViewerEmail");
3880
- if (!email) throwApiError(403, "Verified viewer email required.");
3881
- let input;
3882
- try {
3883
- input = await c.req.json();
3884
- } catch (error) {
3885
- throwApiError(400, "Invalid request body.", error);
3886
- }
3887
- const body = parseBody(createPersonalTokenBodySchema, input);
3888
- return createPersonalToken({ email, name: body.name });
3889
- }
3890
- });
3891
-
3892
- // src/api/personal-tokens/list.ts
3893
- var list_default4 = defineApiRoute({
3894
- method: "get",
3895
- path: "/",
3896
- responseSchema: personalTokenListSchema,
3897
- handler: async (c) => {
3898
- const email = c.get("verifiedViewerEmail");
3899
- if (!email) throwApiError(403, "Verified viewer email required.");
3900
- return { tokens: await listPersonalTokens(email) };
3901
- }
3902
- });
3903
-
3904
- // src/api/personal-tokens/revoke.ts
3905
- var revoke_default = defineApiRoute({
3906
- method: "delete",
3907
- path: "/:id",
3908
- responseSchema: revokePersonalTokenResponseSchema,
3909
- handler: async (c) => {
3910
- const email = c.get("verifiedViewerEmail");
3911
- if (!email) throwApiError(403, "Verified viewer email required.");
3912
- const { id } = parseParams(personalTokenParamsSchema, c.req.param());
3913
- if (!await revokePersonalToken({ email, id })) {
3914
- throwApiError(404, "Personal API token not found.");
3915
- }
3916
- return { revoked: true };
3917
- }
3918
- });
3919
-
3920
3910
  // src/api/personal-tokens/routes.ts
3921
- var routes3 = [list_default4, create_default, revoke_default];
3922
3911
  function createPersonalTokenRoutes() {
3923
3912
  const app = new Hono4();
3924
- 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
+ );
3925
3955
  return app;
3926
3956
  }
3927
3957
 
3928
3958
  // src/api/user-pages/routes.ts
3929
3959
  import { Hono as Hono5 } from "hono";
3960
+ import { z as z4 } from "zod";
3930
3961
  import {
3931
3962
  pluginUserPageContentSchema as pluginUserPageContentSchema2,
3932
3963
  pluginUserPageInputSchema,
@@ -3964,8 +3995,8 @@ async function readPluginUserPage(input) {
3964
3995
  (candidate) => candidate.id === input.pageId
3965
3996
  );
3966
3997
  if (!plugin || !page) return void 0;
3967
- const viewer2 = await resolveViewerUser(input.email);
3968
- if (!viewer2) {
3998
+ const viewer = await resolveViewerUser(input.email);
3999
+ if (!viewer) {
3969
4000
  throw new Error("Authenticated viewer user could not be resolved");
3970
4001
  }
3971
4002
  const content = pluginUserPageContentSchema.parse(
@@ -3974,7 +4005,7 @@ async function readPluginUserPage(input) {
3974
4005
  db: getDb(),
3975
4006
  log: createPluginLogger(plugin.manifest.name),
3976
4007
  plugin: { name: plugin.manifest.name },
3977
- viewer: viewer2
4008
+ viewer
3978
4009
  },
3979
4010
  input.query
3980
4011
  )
@@ -3992,167 +4023,114 @@ async function readPluginUserPage(input) {
3992
4023
  }
3993
4024
 
3994
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
+ });
3995
4044
  function createUserPageRoutes() {
3996
4045
  const app = new Hono5();
3997
4046
  app.get(
3998
4047
  "/",
3999
4048
  () => jsonResponse(pluginUserPageLinksSchema2, readPluginUserPageLinks())
4000
4049
  );
4001
- app.get("/:pluginName/:pageId", async (context) => {
4002
- const email = context.get("verifiedViewerEmail")?.trim();
4003
- if (!email) {
4004
- return jsonResponse(
4005
- apiErrorSchema,
4006
- { error: "Authentication required." },
4007
- { status: 401 }
4008
- );
4009
- }
4010
- const pageInput = pluginUserPageInputSchema.safeParse({
4011
- cursor: context.req.query("cursor") || void 0,
4012
- filter: context.req.query("filter") || void 0,
4013
- limit: context.req.query("limit") ? Number(context.req.query("limit")) : 20,
4014
- query: context.req.query("q") || void 0
4015
- });
4016
- if (!pageInput.success) {
4017
- 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(
4018
4064
  apiErrorSchema,
4019
- { error: "Invalid user page query." },
4020
- { status: 400 }
4065
+ { error: "User page not found." },
4066
+ { status: 404 }
4021
4067
  );
4022
4068
  }
4023
- const page = await readPluginUserPage({
4024
- email,
4025
- pageId: context.req.param("pageId"),
4026
- pluginName: context.req.param("pluginName"),
4027
- query: pageInput.data
4028
- });
4029
- return page ? jsonResponse(pluginUserPageContentSchema2, page) : jsonResponse(
4030
- apiErrorSchema,
4031
- { error: "User page not found." },
4032
- { status: 404 }
4033
- );
4034
- });
4069
+ );
4035
4070
  return app;
4036
4071
  }
4037
4072
 
4038
4073
  // src/api/tasks/routes.ts
4039
4074
  import { Hono as Hono6 } from "hono";
4040
- async function viewer(context) {
4041
- const email = context.get("verifiedViewerEmail")?.trim();
4042
- return email ? await resolveViewerUser(email) : void 0;
4043
- }
4044
4075
  function createTaskRoutes() {
4045
4076
  const app = new Hono6();
4046
- app.get("/", async (context) => {
4047
- const user = await viewer(context);
4048
- return user ? jsonResponse(taskListSchema, await readViewerTasks(user)) : jsonResponse(
4049
- apiErrorSchema,
4050
- { error: "Authentication required." },
4051
- { status: 401 }
4052
- );
4077
+ app.get("/", requireViewer, async (context) => {
4078
+ const user = context.get("viewer");
4079
+ return jsonResponse(taskListSchema, await readViewerTasks(user));
4053
4080
  });
4054
- app.get("/runs", async (context) => {
4055
- const user = await viewer(context);
4056
- return user ? jsonResponse(taskRunListSchema, await readViewerTaskRuns(user)) : jsonResponse(
4057
- apiErrorSchema,
4058
- { error: "Authentication required." },
4059
- { status: 401 }
4060
- );
4081
+ app.get("/runs", requireViewer, async (context) => {
4082
+ const user = context.get("viewer");
4083
+ return jsonResponse(taskRunListSchema, await readViewerTaskRuns(user));
4061
4084
  });
4062
- app.get("/:kind/:id/executions", async (context) => {
4063
- const user = await viewer(context);
4064
- if (!user) {
4065
- return jsonResponse(
4066
- apiErrorSchema,
4067
- { error: "Authentication required." },
4068
- { status: 401 }
4069
- );
4070
- }
4071
- const params = taskParamsSchema.safeParse(context.req.param());
4072
- if (!params.success) {
4073
- return jsonResponse(
4074
- apiErrorSchema,
4075
- { error: "Invalid task." },
4076
- { status: 400 }
4077
- );
4078
- }
4079
- try {
4080
- return jsonResponse(
4081
- taskExecutionListSchema,
4082
- await readViewerTaskExecutions(user, params.data.kind, params.data.id)
4083
- );
4084
- } catch (error) {
4085
- 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 {
4086
4093
  return jsonResponse(
4087
- apiErrorSchema,
4088
- { error: error.message },
4089
- { status: 404 }
4094
+ taskExecutionListSchema,
4095
+ await readViewerTaskExecutions(user, params.kind, params.id)
4090
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;
4091
4106
  }
4092
- throw error;
4093
4107
  }
4094
- });
4095
- app.delete("/:kind/:id", async (context) => {
4096
- const user = await viewer(context);
4097
- if (!user) {
4098
- return jsonResponse(
4099
- apiErrorSchema,
4100
- { error: "Authentication required." },
4101
- { status: 401 }
4102
- );
4103
- }
4104
- const params = taskParamsSchema.safeParse(context.req.param());
4105
- if (!params.success) {
4106
- return jsonResponse(
4107
- apiErrorSchema,
4108
- { error: "Invalid task." },
4109
- { status: 400 }
4110
- );
4111
- }
4112
- try {
4113
- await deleteViewerTask(user, params.data.kind, params.data.id);
4114
- return new Response(null, {
4115
- headers: { "cache-control": "no-store" },
4116
- status: 204
4117
- });
4118
- } catch (error) {
4119
- if (error instanceof ViewerTaskNotFoundError) {
4120
- return jsonResponse(
4121
- apiErrorSchema,
4122
- { error: error.message },
4123
- { status: 404 }
4124
- );
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;
4125
4128
  }
4126
- throw error;
4127
4129
  }
4128
- });
4130
+ );
4129
4131
  return app;
4130
4132
  }
4131
4133
 
4132
- // src/api/plugins.ts
4133
- var plugins_default = defineApiRoute({
4134
- method: "get",
4135
- path: "/api/plugins",
4136
- responseSchema: pluginsSchema,
4137
- handler: readPlugins
4138
- });
4139
-
4140
- // src/api/runtime.ts
4141
- var runtime_default = defineApiRoute({
4142
- method: "get",
4143
- path: "/api/runtime",
4144
- responseSchema: runtimeInfoReportSchema,
4145
- handler: readRuntimeInfoReport
4146
- });
4147
-
4148
- // src/api/skills.ts
4149
- var skills_default = defineApiRoute({
4150
- method: "get",
4151
- path: "/api/skills",
4152
- responseSchema: skillReportsSchema,
4153
- handler: readSkillReports
4154
- });
4155
-
4156
4134
  // src/api/stats.ts
4157
4135
  var WINDOW_DAYS2 = 90;
4158
4136
  async function readStatsReport() {
@@ -4169,25 +4147,96 @@ async function readStatsReport() {
4169
4147
  windowStart: start
4170
4148
  });
4171
4149
  }
4172
- var stats_default2 = defineApiRoute({
4173
- method: "get",
4174
- path: "/api/stats",
4175
- responseSchema: statsReportSchema,
4176
- handler: readStatsReport
4177
- });
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
+ }
4178
4209
 
4179
4210
  // src/api.ts
4180
- var routes4 = [
4181
- health_default,
4182
- runtime_default,
4183
- plugins_default,
4184
- skills_default,
4185
- plugin_reports_default,
4186
- stats_default2
4187
- ];
4188
4211
  function createJuniorApi() {
4189
4212
  const app = new Hono7();
4190
- 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
+ );
4191
4240
  app.route("/api/conversations", createConversationRoutes());
4192
4241
  app.route("/api/personal-tokens", createPersonalTokenRoutes());
4193
4242
  app.route("/api/people", createPeopleRoutes());
@@ -4203,10 +4252,27 @@ function createJuniorApi() {
4203
4252
  }
4204
4253
  )
4205
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
+ });
4206
4271
  return app;
4207
4272
  }
4208
4273
  export {
4209
4274
  authenticatePersonalToken,
4210
4275
  createJuniorApi,
4211
- jsonResponse
4276
+ jsonResponse,
4277
+ resolveViewerUser
4212
4278
  };