robotrock 1.3.2 → 1.3.4

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 (46) hide show
  1. package/README.md +22 -0
  2. package/dist/ai/index.js +8 -0
  3. package/dist/ai/index.js.map +1 -1
  4. package/dist/ai/trigger.js +8 -0
  5. package/dist/ai/trigger.js.map +1 -1
  6. package/dist/ai/workflow.js +8 -0
  7. package/dist/ai/workflow.js.map +1 -1
  8. package/dist/eve/agent/index.d.ts +67 -3
  9. package/dist/eve/agent/index.js +209 -153
  10. package/dist/eve/agent/index.js.map +1 -1
  11. package/dist/eve/index.d.ts +2 -1
  12. package/dist/eve/index.js +62 -47
  13. package/dist/eve/index.js.map +1 -1
  14. package/dist/eve/tools/admin/assign-tasks.d.ts +15 -4
  15. package/dist/eve/tools/admin/assign-tasks.js +8 -43
  16. package/dist/eve/tools/admin/assign-tasks.js.map +1 -1
  17. package/dist/eve/tools/admin/manage-groups.d.ts +2 -3
  18. package/dist/eve/tools/admin/manage-groups.js +18 -71
  19. package/dist/eve/tools/admin/manage-groups.js.map +1 -1
  20. package/dist/eve/tools/admin/manage-team-members.d.ts +2 -3
  21. package/dist/eve/tools/admin/manage-team-members.js +20 -64
  22. package/dist/eve/tools/admin/manage-team-members.js.map +1 -1
  23. package/dist/eve/tools/admin/query-tasks.d.ts +5 -6
  24. package/dist/eve/tools/admin/query-tasks.js +22 -86
  25. package/dist/eve/tools/admin/query-tasks.js.map +1 -1
  26. package/dist/eve/tools/catalog/search-products.d.ts +4 -5
  27. package/dist/eve/tools/catalog/search-products.js +2 -33
  28. package/dist/eve/tools/catalog/search-products.js.map +1 -1
  29. package/dist/eve/tools/identity/index.d.ts +0 -1
  30. package/dist/eve/tools/identity/index.js +15 -44
  31. package/dist/eve/tools/identity/index.js.map +1 -1
  32. package/dist/eve/tools/identity/my-access.d.ts +2 -3
  33. package/dist/eve/tools/identity/my-access.js +15 -44
  34. package/dist/eve/tools/identity/my-access.js.map +1 -1
  35. package/dist/eve/tools/identity/whoami.js.map +1 -1
  36. package/dist/eve/tools/inbox/create-task.js.map +1 -1
  37. package/dist/eve/tools/inbox/index.js.map +1 -1
  38. package/dist/eve/tools/index.d.ts +1 -1
  39. package/dist/eve/tools/index.js +44 -193
  40. package/dist/eve/tools/index.js.map +1 -1
  41. package/dist/{index-DePyAbTI.d.ts → index-Blq0XoAr.d.ts} +17 -16
  42. package/dist/index.d.ts +2 -1
  43. package/dist/index.js +19 -7
  44. package/dist/index.js.map +1 -1
  45. package/dist/tool-ui-hint-CMpug5sC.d.ts +13 -0
  46. package/package.json +2 -2
@@ -7,13 +7,14 @@ import { TaskPriority } from '../../schemas/index.js';
7
7
  import { HookDefinition } from 'eve/hooks';
8
8
  export { AgentAdminApi, createAgentAdminApi, createBoundAgentAdminClient, requireBoundAgentAdminClient } from '../../agent-admin.js';
9
9
  export { ROBOTROCK_PLATFORM_USER_CONTEXT_PUBLIC_KEY_URL } from '@robotrock/core/eve/platform-user-context-public-key';
10
- export { R as ROBOTROCK_READY_HOOK_SLUG } from '../../index-DePyAbTI.js';
10
+ export { R as ROBOTROCK_READY_HOOK_SLUG } from '../../index-Blq0XoAr.js';
11
11
  export { ROBOTROCK_USER_CONTEXT_AUDIENCE, ROBOTROCK_USER_CONTEXT_ISSUER } from '@robotrock/core/eve/user-context-jwt';
12
12
  import '@robotrock/core';
13
13
  import 'zod';
14
14
  import '../../chat-correlation-BsHD-tOQ.js';
15
15
  import '@robotrock/core/schemas';
16
16
  import '../../tool-reply-guidance-C3qrT1In.js';
17
+ import '../../tool-ui-hint-CMpug5sC.js';
17
18
 
18
19
  /** Header carrying the dashboard user-context JWT on proxied Eve requests. */
19
20
  declare const ROBOTROCK_USER_CONTEXT_HEADER = "x-robotrock-user-token";
@@ -33,9 +34,72 @@ declare function robotrockUserContextAuth(options?: RobotrockUserContextAuthOpti
33
34
  * (`GET /eve/v1/info` during verify and tenant connect).
34
35
  */
35
36
  declare function robotrockAgentServiceAuth(): AuthFn<Request>;
36
- /** Bearer token used by the RobotRock webhook resume self-call. */
37
+ /**
38
+ * Bearer token for RobotRock platform reachability and dashboard proxy calls.
39
+ *
40
+ * When a workspace admin connects a protected single-tenant deployment, they
41
+ * enter a Bearer token in **Settings → Agents**. RobotRock stores it in
42
+ * WorkOS Vault and sends `Authorization: Bearer <token>` on:
43
+ *
44
+ * - `GET /eve/v1/info` and `GET /eve/v1/health` (connect / re-sync)
45
+ * - `POST /eve/v1/session` and `POST /eve/v1/session/:sessionId` (chat + resume)
46
+ * - `GET /eve/v1/session/:sessionId/stream` (chat streaming)
47
+ * - optional icon paths (`/favicon.ico`, `/icon.svg`, `/icon.png`)
48
+ *
49
+ * Set `EVE_SELF_AUTH_TOKEN` on the agent to the same value. Use
50
+ * `robotrockEveChannel()` so this authenticator is registered on the Eve channel.
51
+ */
37
52
  declare function eveSelfServiceAuth(): AuthFn<Request>;
38
53
 
54
+ /**
55
+ * Eve HTTP routes RobotRock reaches when connecting, re-syncing, or proxying
56
+ * dashboard chat. Use these paths when smoke-testing a protected deployment.
57
+ *
58
+ * Self-hosted agents that require deployment access: set `EVE_SELF_AUTH_TOKEN` on
59
+ * the agent to the same value the workspace admin enters under **Settings →
60
+ * Agents → Deployment access → Bearer token**. RobotRock stores that token in
61
+ * WorkOS Vault and sends it as `Authorization: Bearer <token>` on every call
62
+ * below (plus `X-RobotRock-User-Token` during inbox chat).
63
+ */
64
+ /** Routes RobotRock calls directly from the dashboard backend (connect / re-sync). */
65
+ declare const ROBOTROCK_EVE_CONNECT_ROUTES: {
66
+ /** Agent manifest + `robotrock-ready` hook detection. */
67
+ readonly info: {
68
+ readonly method: "GET";
69
+ readonly path: "/eve/v1/info";
70
+ };
71
+ /** Optional health probe (same auth as `/info` when the channel is protected). */
72
+ readonly health: {
73
+ readonly method: "GET";
74
+ readonly path: "/eve/v1/health";
75
+ };
76
+ };
77
+ /** Static assets RobotRock may HEAD/GET for the agent avatar in Settings. */
78
+ declare const ROBOTROCK_EVE_ICON_PATHS: readonly ["/favicon.ico", "/icon.svg", "/icon.png"];
79
+ /**
80
+ * Routes proxied through `/{tenant}/api/eve/{connectionId}/…` during inbox chat
81
+ * and task-handled resume. The Eve client issues these against the proxy host;
82
+ * the proxy forwards them to the deployment with vault credentials attached.
83
+ */
84
+ declare const ROBOTROCK_EVE_CHAT_ROUTES: {
85
+ readonly createSession: {
86
+ readonly method: "POST";
87
+ readonly path: "/eve/v1/session";
88
+ };
89
+ readonly continueSession: {
90
+ readonly method: "POST";
91
+ readonly path: "/eve/v1/session/:sessionId";
92
+ };
93
+ readonly messageStream: {
94
+ readonly method: "GET";
95
+ readonly path: "/eve/v1/session/:sessionId/stream";
96
+ };
97
+ };
98
+ /** Env var on the Eve agent that must match the dashboard Bearer token. */
99
+ declare const EVE_SELF_AUTH_TOKEN_ENV_VAR = "EVE_SELF_AUTH_TOKEN";
100
+ /** All Eve route paths that should accept the dashboard Bearer token on protected deployments. */
101
+ declare const ROBOTROCK_EVE_BEARER_PROTECTED_PATHS: readonly ["/eve/v1/info", "/eve/v1/health", "/eve/v1/session", "/eve/v1/session/:sessionId", "/eve/v1/session/:sessionId/stream", "/favicon.ico", "/icon.svg", "/icon.png"];
102
+
39
103
  /** Resolve the platform RS256 public key used to verify dashboard user-context JWTs. */
40
104
  declare function resolvePlatformUserContextPublicKeyPem(): Promise<string | null>;
41
105
 
@@ -161,4 +225,4 @@ declare const robotrockChatAuditHook: HookDefinition;
161
225
  /** Alias for agents that prefer a factory name. */
162
226
  declare function defineRobotRockChatAuditHook(): HookDefinition;
163
227
 
164
- export { type CreateRobotRockCronChatInput, type CreateRobotRockTaskInput, ROBOTROCK_USER_CONTEXT_HEADER, type RobotRockChatAuditPayload, type RobotRockTaskActionInput, type RobotRockTaskAssignToInput, type RobotRockTaskContextInput, type RobotRockTaskToolInput, type RobotrockEveChannelOptions, type RobotrockUserContextAuthOptions, buildRobotRockTaskPayload, createRobotRockCronChat, createRobotRockTask, defineRobotRockChatAuditHook, defineRobotRockReadyHook, eveSelfServiceAuth, fetchRobotRockStagedHitl, postRobotRockChatInputAudit, postRobotRockLinkChatTask, postRobotRockStageHitl, resetBoundClientAuthWarning, resetChatAuditWarnings, resetRobotrockChatAuditIdempotencyKeys, resolvePlatformUserContextPublicKeyPem, resolveTaskHandledWebhookUrl, robotrockAgentServiceAuth, robotrockChatAuditHook, robotrockEveChannel, robotrockReadyHook, robotrockUserContextAuth, tryCreateBoundRobotRockClient };
228
+ export { type CreateRobotRockCronChatInput, type CreateRobotRockTaskInput, EVE_SELF_AUTH_TOKEN_ENV_VAR, ROBOTROCK_EVE_BEARER_PROTECTED_PATHS, ROBOTROCK_EVE_CHAT_ROUTES, ROBOTROCK_EVE_CONNECT_ROUTES, ROBOTROCK_EVE_ICON_PATHS, ROBOTROCK_USER_CONTEXT_HEADER, type RobotRockChatAuditPayload, type RobotRockTaskActionInput, type RobotRockTaskAssignToInput, type RobotRockTaskContextInput, type RobotRockTaskToolInput, type RobotrockEveChannelOptions, type RobotrockUserContextAuthOptions, buildRobotRockTaskPayload, createRobotRockCronChat, createRobotRockTask, defineRobotRockChatAuditHook, defineRobotRockReadyHook, eveSelfServiceAuth, fetchRobotRockStagedHitl, postRobotRockChatInputAudit, postRobotRockLinkChatTask, postRobotRockStageHitl, resetBoundClientAuthWarning, resetChatAuditWarnings, resetRobotrockChatAuditIdempotencyKeys, resolvePlatformUserContextPublicKeyPem, resolveTaskHandledWebhookUrl, robotrockAgentServiceAuth, robotrockChatAuditHook, robotrockEveChannel, robotrockReadyHook, robotrockUserContextAuth, tryCreateBoundRobotRockClient };
@@ -118,6 +118,158 @@ function verifyRobotRockPlatformUserContextJwt(args) {
118
118
  // ../core/src/eve/platform-user-context-public-key.ts
119
119
  var ROBOTROCK_PLATFORM_USER_CONTEXT_PUBLIC_KEY_URL = "https://app.robotrock.io/.well-known/robotrock-user-context-public-key";
120
120
 
121
+ // ../core/src/utils/decode-html-entities.ts
122
+ function decodeHtmlEntities(value) {
123
+ return value.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#039;/g, "'").replace(/&apos;/g, "'").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(Number(code))).replace(
124
+ /&#x([0-9a-f]+);/gi,
125
+ (_, code) => String.fromCharCode(parseInt(code, 16))
126
+ );
127
+ }
128
+
129
+ // ../core/src/utils/safe-url.ts
130
+ var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
131
+ "localhost",
132
+ "metadata.google.internal",
133
+ "metadata.goog"
134
+ ]);
135
+ function normalizeHostname(hostname) {
136
+ return hostname.toLowerCase().replace(/^\[|\]$/g, "");
137
+ }
138
+ function isBlockedIpv4(host) {
139
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
140
+ if (!match) {
141
+ return false;
142
+ }
143
+ const octets = match.slice(1, 5).map((part) => Number(part));
144
+ if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
145
+ return true;
146
+ }
147
+ const [a, b, _c, _d] = octets;
148
+ if (a === void 0 || b === void 0) {
149
+ return true;
150
+ }
151
+ if (a === 127 || a === 0) return true;
152
+ if (a === 10) return true;
153
+ if (a === 169 && b === 254) return true;
154
+ if (a === 192 && b === 168) return true;
155
+ if (a === 172 && b >= 16 && b <= 31) return true;
156
+ if (a === 100 && b >= 64 && b <= 127) return true;
157
+ return false;
158
+ }
159
+ function ipv4FromNumericHost(host) {
160
+ if (/^\d+$/.test(host)) {
161
+ const num = Number(host);
162
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
163
+ return null;
164
+ }
165
+ const a = num >>> 24 & 255;
166
+ const b = num >>> 16 & 255;
167
+ const c = num >>> 8 & 255;
168
+ const d = num & 255;
169
+ return `${a}.${b}.${c}.${d}`;
170
+ }
171
+ const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
172
+ if (hexMatch) {
173
+ const num = Number.parseInt(hexMatch[1], 16);
174
+ if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
175
+ return null;
176
+ }
177
+ const a = num >>> 24 & 255;
178
+ const b = num >>> 16 & 255;
179
+ const c = num >>> 8 & 255;
180
+ const d = num & 255;
181
+ return `${a}.${b}.${c}.${d}`;
182
+ }
183
+ return null;
184
+ }
185
+ function isBlockedIpv4Mapped(host) {
186
+ const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
187
+ if (mappedDotted) {
188
+ return isBlockedIpv4(mappedDotted[1]);
189
+ }
190
+ const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
191
+ if (mappedHex) {
192
+ const high = Number.parseInt(mappedHex[1], 16);
193
+ const low = Number.parseInt(mappedHex[2], 16);
194
+ if (Number.isFinite(high) && Number.isFinite(low)) {
195
+ const a = high >> 8 & 255;
196
+ const b = high & 255;
197
+ const c = low >> 8 & 255;
198
+ const d = low & 255;
199
+ return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+ function isBlockedIpv6(host) {
205
+ if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
206
+ return true;
207
+ }
208
+ if (host.startsWith("fc") || host.startsWith("fd")) {
209
+ return true;
210
+ }
211
+ if (host.startsWith("fe80:")) {
212
+ return true;
213
+ }
214
+ if (isBlockedIpv4Mapped(host)) {
215
+ return true;
216
+ }
217
+ return false;
218
+ }
219
+ function isBlockedHostname(hostname) {
220
+ const host = normalizeHostname(hostname);
221
+ if (!host) {
222
+ return true;
223
+ }
224
+ if (BLOCKED_HOSTNAMES.has(host)) {
225
+ return true;
226
+ }
227
+ if (host.endsWith(".localhost") || host.endsWith(".local")) {
228
+ return true;
229
+ }
230
+ const numericIpv4 = ipv4FromNumericHost(host);
231
+ if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
232
+ return true;
233
+ }
234
+ return isBlockedIpv4(host) || isBlockedIpv6(host);
235
+ }
236
+ function isLoopbackHandlerUrl(urlString) {
237
+ let url;
238
+ try {
239
+ url = new URL(urlString);
240
+ } catch {
241
+ return false;
242
+ }
243
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
244
+ return false;
245
+ }
246
+ if (url.username || url.password) {
247
+ return false;
248
+ }
249
+ const host = url.hostname.toLowerCase();
250
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
251
+ }
252
+ function isAllowedHandlerUrl(urlString) {
253
+ return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
254
+ }
255
+ function isPublicHttpUrl(urlString) {
256
+ let url;
257
+ try {
258
+ url = new URL(urlString);
259
+ } catch {
260
+ return false;
261
+ }
262
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
263
+ return false;
264
+ }
265
+ if (url.username || url.password) {
266
+ return false;
267
+ }
268
+ return !isBlockedHostname(url.hostname);
269
+ }
270
+ var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
271
+ var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
272
+
121
273
  // src/eve/input-request.ts
122
274
  var EVE_INPUT_SUBMIT_ACTION_ID = "submit";
123
275
  var EVE_INPUT_OTHER_CHOICE_ID = "__other__";
@@ -127,6 +279,9 @@ var CONFIRMATION_DEFAULT_OPTIONS = [
127
279
  { id: "deny", label: "Deny", style: "danger" }
128
280
  ];
129
281
  var SELECT_PER_OPTION_THRESHOLD = 6;
282
+ function decodeDisplayText(value) {
283
+ return decodeHtmlEntities(value);
284
+ }
130
285
  function resolveEveInputDisplay(request, toolName) {
131
286
  if (request.display) {
132
287
  return request.display;
@@ -143,11 +298,12 @@ function confirmationActions(request) {
143
298
  const options = request.options && request.options.length > 0 ? request.options : CONFIRMATION_DEFAULT_OPTIONS;
144
299
  return options.map((option) => ({
145
300
  id: option.id,
146
- title: option.label,
147
- ...option.description ? { description: option.description } : {}
301
+ title: decodeDisplayText(option.label),
302
+ ...option.description ? { description: decodeDisplayText(option.description) } : {}
148
303
  }));
149
304
  }
150
305
  function textSubmitAction(prompt) {
306
+ const decodedPrompt = decodeDisplayText(prompt);
151
307
  return {
152
308
  id: EVE_INPUT_SUBMIT_ACTION_ID,
153
309
  title: "Submit",
@@ -163,7 +319,7 @@ function textSubmitAction(prompt) {
163
319
  },
164
320
  ui: {
165
321
  answer: {
166
- "ui:title": prompt.trim() || "Your answer",
322
+ "ui:title": decodedPrompt.trim() || "Your answer",
167
323
  "ui:widget": "textarea"
168
324
  }
169
325
  }
@@ -172,15 +328,15 @@ function textSubmitAction(prompt) {
172
328
  function selectPerOptionActions(options) {
173
329
  return options.map((option) => ({
174
330
  id: option.id,
175
- title: option.label,
176
- ...option.description ? { description: option.description } : {}
331
+ title: decodeDisplayText(option.label),
332
+ ...option.description ? { description: decodeDisplayText(option.description) } : {}
177
333
  }));
178
334
  }
179
335
  function selectFormAction(request) {
180
336
  const options = request.options ?? [];
181
337
  const allowFreeform = request.allowFreeform === true;
182
338
  const enumValues = options.map((option) => option.id);
183
- const enumNames = options.map((option) => option.label);
339
+ const enumNames = options.map((option) => decodeDisplayText(option.label));
184
340
  if (allowFreeform) {
185
341
  enumValues.push(EVE_INPUT_OTHER_CHOICE_ID);
186
342
  enumNames.push(EVE_INPUT_OTHER_CHOICE_LABEL);
@@ -303,6 +459,12 @@ function isEveApprovalInputRequest(request) {
303
459
  const options = request.options ?? [];
304
460
  return options.length === 2 && options[0]?.id === "approve" && options[1]?.id === "deny";
305
461
  }
462
+ function buildOptionIdFormData(display, optionId) {
463
+ if (display === "select" || display === "confirmation") {
464
+ return { choice: optionId };
465
+ }
466
+ return {};
467
+ }
306
468
  function eveInputResponseToActionSubmission(request, response, options) {
307
469
  const display = resolveEveInputDisplay(request, options?.toolName);
308
470
  const actions = eveInputRequestToActions(request, options);
@@ -312,7 +474,7 @@ function eveInputResponseToActionSubmission(request, response, options) {
312
474
  return {
313
475
  actionId: response.optionId,
314
476
  actionTitle: action.title,
315
- formData: {}
477
+ formData: buildOptionIdFormData(display, response.optionId)
316
478
  };
317
479
  }
318
480
  const option = request.options?.find((entry) => entry.id === response.optionId);
@@ -320,13 +482,13 @@ function eveInputResponseToActionSubmission(request, response, options) {
320
482
  return {
321
483
  actionId: response.optionId,
322
484
  actionTitle: option.label,
323
- formData: {}
485
+ formData: buildOptionIdFormData(display, response.optionId)
324
486
  };
325
487
  }
326
488
  return {
327
489
  actionId: response.optionId,
328
490
  actionTitle: response.optionId,
329
- formData: {}
491
+ formData: buildOptionIdFormData(display, response.optionId)
330
492
  };
331
493
  }
332
494
  const text = response.text?.trim();
@@ -638,6 +800,39 @@ function eveSelfServiceAuth() {
638
800
  };
639
801
  }
640
802
 
803
+ // src/eve/agent/deployment-access.ts
804
+ var ROBOTROCK_EVE_CONNECT_ROUTES = {
805
+ /** Agent manifest + `robotrock-ready` hook detection. */
806
+ info: { method: "GET", path: "/eve/v1/info" },
807
+ /** Optional health probe (same auth as `/info` when the channel is protected). */
808
+ health: { method: "GET", path: "/eve/v1/health" }
809
+ };
810
+ var ROBOTROCK_EVE_ICON_PATHS = [
811
+ "/favicon.ico",
812
+ "/icon.svg",
813
+ "/icon.png"
814
+ ];
815
+ var ROBOTROCK_EVE_CHAT_ROUTES = {
816
+ createSession: { method: "POST", path: "/eve/v1/session" },
817
+ continueSession: {
818
+ method: "POST",
819
+ path: "/eve/v1/session/:sessionId"
820
+ },
821
+ messageStream: {
822
+ method: "GET",
823
+ path: "/eve/v1/session/:sessionId/stream"
824
+ }
825
+ };
826
+ var EVE_SELF_AUTH_TOKEN_ENV_VAR = "EVE_SELF_AUTH_TOKEN";
827
+ var ROBOTROCK_EVE_BEARER_PROTECTED_PATHS = [
828
+ ROBOTROCK_EVE_CONNECT_ROUTES.info.path,
829
+ ROBOTROCK_EVE_CONNECT_ROUTES.health.path,
830
+ ROBOTROCK_EVE_CHAT_ROUTES.createSession.path,
831
+ ROBOTROCK_EVE_CHAT_ROUTES.continueSession.path,
832
+ ROBOTROCK_EVE_CHAT_ROUTES.messageStream.path,
833
+ ...ROBOTROCK_EVE_ICON_PATHS
834
+ ];
835
+
641
836
  // src/eve/agent/channel.ts
642
837
  import { eveChannel } from "eve/channels/eve";
643
838
  import { localDev, vercelOidc } from "eve/channels/auth";
@@ -672,150 +867,6 @@ function robotrockEveChannel(options) {
672
867
  // src/schemas/index.ts
673
868
  import { z as z4 } from "zod";
674
869
 
675
- // ../core/src/utils/safe-url.ts
676
- var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set([
677
- "localhost",
678
- "metadata.google.internal",
679
- "metadata.goog"
680
- ]);
681
- function normalizeHostname(hostname) {
682
- return hostname.toLowerCase().replace(/^\[|\]$/g, "");
683
- }
684
- function isBlockedIpv4(host) {
685
- const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
686
- if (!match) {
687
- return false;
688
- }
689
- const octets = match.slice(1, 5).map((part) => Number(part));
690
- if (octets.some((octet) => Number.isNaN(octet) || octet < 0 || octet > 255)) {
691
- return true;
692
- }
693
- const [a, b, _c, _d] = octets;
694
- if (a === void 0 || b === void 0) {
695
- return true;
696
- }
697
- if (a === 127 || a === 0) return true;
698
- if (a === 10) return true;
699
- if (a === 169 && b === 254) return true;
700
- if (a === 192 && b === 168) return true;
701
- if (a === 172 && b >= 16 && b <= 31) return true;
702
- if (a === 100 && b >= 64 && b <= 127) return true;
703
- return false;
704
- }
705
- function ipv4FromNumericHost(host) {
706
- if (/^\d+$/.test(host)) {
707
- const num = Number(host);
708
- if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
709
- return null;
710
- }
711
- const a = num >>> 24 & 255;
712
- const b = num >>> 16 & 255;
713
- const c = num >>> 8 & 255;
714
- const d = num & 255;
715
- return `${a}.${b}.${c}.${d}`;
716
- }
717
- const hexMatch = /^0x([0-9a-f]{1,8})$/i.exec(host);
718
- if (hexMatch) {
719
- const num = Number.parseInt(hexMatch[1], 16);
720
- if (!Number.isFinite(num) || num < 0 || num > 4294967295) {
721
- return null;
722
- }
723
- const a = num >>> 24 & 255;
724
- const b = num >>> 16 & 255;
725
- const c = num >>> 8 & 255;
726
- const d = num & 255;
727
- return `${a}.${b}.${c}.${d}`;
728
- }
729
- return null;
730
- }
731
- function isBlockedIpv4Mapped(host) {
732
- const mappedDotted = /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/i.exec(host);
733
- if (mappedDotted) {
734
- return isBlockedIpv4(mappedDotted[1]);
735
- }
736
- const mappedHex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(host);
737
- if (mappedHex) {
738
- const high = Number.parseInt(mappedHex[1], 16);
739
- const low = Number.parseInt(mappedHex[2], 16);
740
- if (Number.isFinite(high) && Number.isFinite(low)) {
741
- const a = high >> 8 & 255;
742
- const b = high & 255;
743
- const c = low >> 8 & 255;
744
- const d = low & 255;
745
- return isBlockedIpv4(`${a}.${b}.${c}.${d}`);
746
- }
747
- }
748
- return false;
749
- }
750
- function isBlockedIpv6(host) {
751
- if (host === "::1" || host === "0:0:0:0:0:0:0:1") {
752
- return true;
753
- }
754
- if (host.startsWith("fc") || host.startsWith("fd")) {
755
- return true;
756
- }
757
- if (host.startsWith("fe80:")) {
758
- return true;
759
- }
760
- if (isBlockedIpv4Mapped(host)) {
761
- return true;
762
- }
763
- return false;
764
- }
765
- function isBlockedHostname(hostname) {
766
- const host = normalizeHostname(hostname);
767
- if (!host) {
768
- return true;
769
- }
770
- if (BLOCKED_HOSTNAMES.has(host)) {
771
- return true;
772
- }
773
- if (host.endsWith(".localhost") || host.endsWith(".local")) {
774
- return true;
775
- }
776
- const numericIpv4 = ipv4FromNumericHost(host);
777
- if (numericIpv4 && isBlockedIpv4(numericIpv4)) {
778
- return true;
779
- }
780
- return isBlockedIpv4(host) || isBlockedIpv6(host);
781
- }
782
- function isLoopbackHandlerUrl(urlString) {
783
- let url;
784
- try {
785
- url = new URL(urlString);
786
- } catch {
787
- return false;
788
- }
789
- if (url.protocol !== "http:" && url.protocol !== "https:") {
790
- return false;
791
- }
792
- if (url.username || url.password) {
793
- return false;
794
- }
795
- const host = url.hostname.toLowerCase();
796
- return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]" || host.endsWith(".localhost");
797
- }
798
- function isAllowedHandlerUrl(urlString) {
799
- return isPublicHttpUrl(urlString) || isLoopbackHandlerUrl(urlString);
800
- }
801
- function isPublicHttpUrl(urlString) {
802
- let url;
803
- try {
804
- url = new URL(urlString);
805
- } catch {
806
- return false;
807
- }
808
- if (url.protocol !== "http:" && url.protocol !== "https:") {
809
- return false;
810
- }
811
- if (url.username || url.password) {
812
- return false;
813
- }
814
- return !isBlockedHostname(url.hostname);
815
- }
816
- var PUBLIC_HTTP_URL_ERROR = "URL must be a public http:// or https:// address";
817
- var HANDLER_URL_ERROR = "Handler URL must be a public or loopback http:// or https:// address";
818
-
819
870
  // ../core/src/schemas/task.ts
820
871
  import { z } from "zod";
821
872
 
@@ -2706,6 +2757,11 @@ function requireBoundAgentAdminClient(ctx) {
2706
2757
  return createBoundAgentAdminClient(ctx);
2707
2758
  }
2708
2759
  export {
2760
+ EVE_SELF_AUTH_TOKEN_ENV_VAR,
2761
+ ROBOTROCK_EVE_BEARER_PROTECTED_PATHS,
2762
+ ROBOTROCK_EVE_CHAT_ROUTES,
2763
+ ROBOTROCK_EVE_CONNECT_ROUTES,
2764
+ ROBOTROCK_EVE_ICON_PATHS,
2709
2765
  ROBOTROCK_PLATFORM_USER_CONTEXT_PUBLIC_KEY_URL,
2710
2766
  ROBOTROCK_READY_HOOK_SLUG,
2711
2767
  ROBOTROCK_USER_CONTEXT_AUDIENCE,