@rtrvr-ai/rover 3.0.1 → 4.0.1

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.
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
1
  import type { RoverPageCaptureConfig } from '@rover/shared/lib/types/index.js';
2
2
  import { type RoverAskUserQuestion, type RoverShortcut, type RoverVoiceConfig } from '@rover/ui';
3
+ import { normalizePendingRunResumeReason } from './resumeReasons.js';
3
4
  import { createRoverBookmarklet, createRoverConsoleSnippet, createRoverScriptTagSnippet, readRoverScriptDataAttributes, type RoverPreviewAttachLaunch } from './previewBootstrap.js';
5
+ import { createRoverOwnerInstallBundle, type RoverOwnerInstallBootConfig, type RoverOwnerInstallBundle, type RoverOwnerInstallBundleInput, type RoverOwnerInstallRoverBookConfig } from './ownerInstall.js';
6
+ import { createRoverAgentCard, createRoverAgentCardJson, createRoverAgentDiscoveryTags, createRoverSiteProfile, createRoverSiteProfileJson, createRoverServiceDescLinkHeader, createRoverWellKnownAgentCard, createRoverWellKnownSiteProfile, type RoverAgentCard, type RoverAgentDiscoveryRuntimeConfig } from './agentDiscovery.js';
4
7
  import { type RoverCloudCheckpointState } from './cloudCheckpoint.js';
5
8
  import type { PersistedRuntimeState, PersistedWorkerState } from './runtimeTypes.js';
6
- import { type RoverLaunchAttachResponse } from './serverRuntime.js';
9
+ import { type RoverLaunchAttachResponse, type RoverServerExperienceConfig } from './serverRuntime.js';
7
10
  import { type FollowupChatEntry } from './followupChatHeuristics.js';
8
11
  export type RoverWebToolsConfig = {
9
12
  enableExternalWebContext?: boolean;
@@ -75,6 +78,7 @@ export type RoverInit = {
75
78
  activation?: 'on_demand';
76
79
  idleCloseMs?: number;
77
80
  };
81
+ agentDiscovery?: RoverAgentDiscoveryRuntimeConfig;
78
82
  stability?: {
79
83
  maxPersistBytes?: number;
80
84
  maxSnapshotBytes?: number;
@@ -161,8 +165,10 @@ export type RoverInit = {
161
165
  };
162
166
  mascot?: {
163
167
  disabled?: boolean;
168
+ imageUrl?: string;
164
169
  mp4Url?: string;
165
170
  webmUrl?: string;
171
+ soundEnabled?: boolean;
166
172
  };
167
173
  shortcuts?: RoverShortcut[];
168
174
  muted?: boolean;
@@ -171,6 +177,7 @@ export type RoverInit = {
171
177
  resizable?: boolean;
172
178
  };
173
179
  showTaskControls?: boolean;
180
+ experience?: RoverServerExperienceConfig;
174
181
  greeting?: {
175
182
  text?: string;
176
183
  delay?: number;
@@ -195,10 +202,13 @@ export type RoverInit = {
195
202
  };
196
203
  export type ClientToolDefinition = {
197
204
  name: string;
205
+ title?: string;
198
206
  description?: string;
199
207
  parameters?: Record<string, any>;
200
208
  required?: string[];
201
209
  schema?: any;
210
+ outputSchema?: any;
211
+ annotations?: Record<string, any>;
202
212
  llmCallable?: boolean;
203
213
  };
204
214
  export type RoverEventName = 'ready' | 'updated' | 'status' | 'run_started' | 'run_state_transition' | 'run_completed' | 'tool_start' | 'tool_result' | 'error' | 'auth_required' | 'navigation_guardrail' | 'mode_change' | 'task_started' | 'task_ended' | 'task_suggested_reset' | 'context_restored' | 'checkpoint_state' | 'checkpoint_error' | 'tab_event_conflict_retry' | 'tab_event_conflict_exhausted' | 'checkpoint_token_missing' | 'open' | 'close';
@@ -240,6 +250,7 @@ export type RoverInstance = {
240
250
  reason?: string;
241
251
  }) => void;
242
252
  getState: () => any;
253
+ getAgentCard: () => RoverAgentCard | null;
243
254
  requestSigned: (input: string | URL, init?: RequestInit) => Promise<Response>;
244
255
  attachLaunch: (params: RoverPreviewAttachLaunch) => Promise<RoverLaunchAttachResponse | null>;
245
256
  registerPromptContextProvider: (provider: RoverPromptContextProvider) => () => void;
@@ -254,6 +265,7 @@ type TelemetryEventName = RoverEventName | RoverVoiceTelemetryEventName;
254
265
  declare function normalizePromptContextEntry(input: string | RoverPromptContextEntry): FollowupChatEntry | null;
255
266
  declare function buildPublicRunStartedPayload(msg: any): Record<string, unknown>;
256
267
  declare function buildPublicRunLifecyclePayload(msg: any, completionState: ReturnType<typeof normalizeRunCompletionState>): Record<string, unknown>;
268
+ export declare function getAgentCard(): RoverAgentCard | null;
257
269
  declare function normalizeRunCompletionState(msg: any): {
258
270
  taskComplete: boolean;
259
271
  needsUserInput: boolean;
@@ -290,6 +302,7 @@ export declare function endTask(options?: {
290
302
  export declare function getState(): any;
291
303
  export declare function registerTool(nameOrDef: string | ClientToolDefinition, handler: (args: any) => any | Promise<any>): void;
292
304
  export declare const __roverInternalsForTests: {
305
+ normalizePendingRunResumeReason: typeof normalizePendingRunResumeReason;
293
306
  sanitizeWorkerState: typeof sanitizeWorkerState;
294
307
  cloneRuntimeStateForCheckpoint: typeof cloneRuntimeStateForCheckpoint;
295
308
  getPersistGovernorConfig: () => {
@@ -301,5 +314,6 @@ export declare const __roverInternalsForTests: {
301
314
  buildPublicRunStartedPayload: typeof buildPublicRunStartedPayload;
302
315
  buildPublicRunLifecyclePayload: typeof buildPublicRunLifecyclePayload;
303
316
  };
304
- export { createRoverBookmarklet, createRoverConsoleSnippet, createRoverScriptTagSnippet, readRoverScriptDataAttributes, };
317
+ export { createRoverAgentCard, createRoverAgentCardJson, createRoverAgentDiscoveryTags, createRoverBookmarklet, createRoverConsoleSnippet, createRoverOwnerInstallBundle, createRoverSiteProfile, createRoverSiteProfileJson, createRoverServiceDescLinkHeader, createRoverScriptTagSnippet, createRoverWellKnownAgentCard, createRoverWellKnownSiteProfile, readRoverScriptDataAttributes, };
318
+ export type { RoverOwnerInstallBootConfig, RoverOwnerInstallBundle, RoverOwnerInstallBundleInput, RoverOwnerInstallRoverBookConfig, };
305
319
  export declare function installGlobal(): void;
@@ -0,0 +1,152 @@
1
+ import type { RoverPageCaptureConfig } from '@rover/shared/lib/types/index.js';
2
+ import type { RoverShortcut, RoverVoiceConfig } from '@rover/ui';
3
+ import { type RoverAgentCard, type RoverAgentDiscoveryConfig, type RoverAgentDiscoveryRuntimeConfig, type RoverSiteProfile } from './agentDiscovery.js';
4
+ type JsonRecord = Record<string, unknown>;
5
+ export type RoverOwnerInstallBootConfig = {
6
+ siteId: string;
7
+ publicKey?: string;
8
+ sessionToken?: string;
9
+ sessionId?: string;
10
+ siteKeyId?: string;
11
+ apiBase?: string;
12
+ visitorId?: string;
13
+ workerUrl?: string;
14
+ allowedDomains?: string[];
15
+ domainScopeMode?: 'host_only' | 'registrable_domain';
16
+ externalNavigationPolicy?: 'open_new_tab_notice' | 'block' | 'allow';
17
+ cloudSandboxEnabled?: boolean;
18
+ sessionScope?: 'shared_site' | 'tab';
19
+ openOnInit?: boolean;
20
+ mode?: 'safe' | 'full';
21
+ allowActions?: boolean;
22
+ deepLink?: {
23
+ enabled?: boolean;
24
+ promptParam?: string;
25
+ shortcutParam?: string;
26
+ consume?: boolean;
27
+ };
28
+ pageConfig?: RoverPageCaptureConfig | null;
29
+ navigation?: {
30
+ crossHostPolicy?: 'open_new_tab' | 'same_tab';
31
+ };
32
+ tabPolicy?: {
33
+ observerByDefault?: boolean;
34
+ actionLeaseMs?: number;
35
+ };
36
+ taskRouting?: {
37
+ mode?: 'auto' | 'act' | 'planner';
38
+ actHeuristicThreshold?: number;
39
+ plannerOnActError?: boolean;
40
+ };
41
+ taskContext?: {
42
+ resetMode?: 'auto' | 'ask' | 'off';
43
+ inactivityMs?: number;
44
+ suggestReset?: boolean;
45
+ semanticSimilarityThreshold?: number;
46
+ };
47
+ checkpointing?: {
48
+ enabled?: boolean;
49
+ autoVisitorId?: boolean;
50
+ flushIntervalMs?: number;
51
+ pullIntervalMs?: number;
52
+ minFlushIntervalMs?: number;
53
+ ttlHours?: number;
54
+ };
55
+ apiMode?: boolean;
56
+ apiToolsConfig?: {
57
+ mode?: 'allowlist' | 'profile' | 'none';
58
+ enableAdditionalTools?: string[];
59
+ userDefined?: string[];
60
+ };
61
+ telemetry?: {
62
+ enabled?: boolean;
63
+ sampleRate?: number;
64
+ flushIntervalMs?: number;
65
+ maxBatchSize?: number;
66
+ includePayloads?: boolean;
67
+ };
68
+ ui?: {
69
+ agent?: {
70
+ name?: string;
71
+ };
72
+ mascot?: {
73
+ disabled?: boolean;
74
+ imageUrl?: string;
75
+ mp4Url?: string;
76
+ webmUrl?: string;
77
+ soundEnabled?: boolean;
78
+ };
79
+ shortcuts?: RoverShortcut[];
80
+ greeting?: {
81
+ text?: string;
82
+ delay?: number;
83
+ duration?: number;
84
+ disabled?: boolean;
85
+ };
86
+ voice?: RoverVoiceConfig | JsonRecord | null;
87
+ experience?: JsonRecord | null;
88
+ muted?: boolean;
89
+ thoughtStyle?: 'concise_cards' | 'minimal';
90
+ panel?: {
91
+ resizable?: boolean;
92
+ };
93
+ showTaskControls?: boolean;
94
+ };
95
+ tools?: {
96
+ web?: {
97
+ enableExternalWebContext?: boolean;
98
+ allowDomains?: string[];
99
+ denyDomains?: string[];
100
+ scrapeMode?: 'off' | 'on_demand';
101
+ };
102
+ };
103
+ agentDiscovery?: RoverAgentDiscoveryRuntimeConfig;
104
+ siteMode?: 'agent' | 'analytics_only' | string;
105
+ };
106
+ export type RoverOwnerInstallRoverBookConfig = {
107
+ enabled?: boolean;
108
+ scriptUrl?: string;
109
+ config?: JsonRecord | null;
110
+ attachPollIntervalMs?: number;
111
+ attachMaxAttempts?: number;
112
+ };
113
+ export type RoverOwnerInstallBundleInput = {
114
+ bootConfig: RoverOwnerInstallBootConfig;
115
+ discovery?: RoverAgentDiscoveryConfig | null;
116
+ embedScriptUrl?: string;
117
+ roverBook?: RoverOwnerInstallRoverBookConfig | null;
118
+ emitLlmsTxt?: boolean;
119
+ llmsTxt?: string;
120
+ };
121
+ export type RoverOwnerInstallBundleMetadata = {
122
+ discoveryEnabled: boolean;
123
+ llmsPublished: boolean;
124
+ embedScriptUrl: string;
125
+ roverBookEnabled: boolean;
126
+ roverBookScriptUrl?: string;
127
+ publishedAgentCardUrl?: string;
128
+ publishedRoverSiteUrl?: string;
129
+ publishedLlmsUrl?: string;
130
+ serviceDescLinkTag?: string;
131
+ serviceDocLinkTag?: string;
132
+ markerJson?: string;
133
+ markerScript?: string;
134
+ inlineAgentCardScript?: string;
135
+ roverSiteJson?: string;
136
+ inlineRoverSiteScript?: string;
137
+ pageManifestJson?: string;
138
+ pageManifestScript?: string;
139
+ };
140
+ export type RoverOwnerInstallBundle = {
141
+ bodyInstallHtml: string;
142
+ headDiscoveryHtml: string;
143
+ agentCard?: RoverAgentCard;
144
+ agentCardJson?: string;
145
+ roverSite?: RoverSiteProfile;
146
+ roverSiteJson?: string;
147
+ serviceDescLinkHeader?: string;
148
+ llmsTxt?: string;
149
+ metadata: RoverOwnerInstallBundleMetadata;
150
+ };
151
+ export declare function createRoverOwnerInstallBundle(input: RoverOwnerInstallBundleInput): RoverOwnerInstallBundle;
152
+ export {};
@@ -0,0 +1,357 @@
1
+ import { DEFAULT_AGENT_CARD_PATH, DEFAULT_ROVER_SITE_PATH, createRoverAgentCard, createRoverAgentCardJson, createRoverSiteProfile, createRoverSiteProfileJson, createRoverServiceDescLinkHeader, } from './agentDiscovery.js';
2
+ const DEFAULT_EMBED_SCRIPT_URL = 'https://rover.rtrvr.ai/embed.js';
3
+ const DEFAULT_ROVERBOOK_SCRIPT_URL = 'https://rover.rtrvr.ai/roverbook.js';
4
+ function text(value) {
5
+ return String(value || '').trim();
6
+ }
7
+ function escapeHtmlAttr(value) {
8
+ return String(value || '')
9
+ .replace(/&/g, '&amp;')
10
+ .replace(/"/g, '&quot;')
11
+ .replace(/</g, '&lt;')
12
+ .replace(/>/g, '&gt;');
13
+ }
14
+ function escapeScriptJson(value) {
15
+ return String(value || '')
16
+ .replace(/</g, '\\u003c')
17
+ .replace(/>/g, '\\u003e')
18
+ .replace(/&/g, '\\u0026');
19
+ }
20
+ function replaceInlineDiscoveryScript(html, marker, script) {
21
+ if (!script)
22
+ return html;
23
+ const pattern = new RegExp(`<script[^>]+data-rover-agent-discovery="${marker}"[^>]*>[\\s\\S]*?<\\/script>`);
24
+ if (pattern.test(html)) {
25
+ return html.replace(pattern, script);
26
+ }
27
+ return [html, script].filter(Boolean).join('\n');
28
+ }
29
+ function decorateBundleWithExperience(bundle, bootConfig) {
30
+ const experience = isObject(bootConfig.ui?.experience) ? bootConfig.ui?.experience : null;
31
+ if (!experience)
32
+ return bundle;
33
+ const presence = isObject(experience.presence) ? experience.presence : {};
34
+ const inputs = isObject(experience.inputs) ? experience.inputs : {};
35
+ const shell = isObject(experience.shell) ? experience.shell : {};
36
+ const stream = isObject(experience.stream) ? experience.stream : {};
37
+ const ctaText = text(presence.ctaText) || `Do it with ${text(bootConfig.ui?.agent?.name) || 'Rover'}`;
38
+ const assistantName = text(presence.assistantName) || text(bootConfig.ui?.agent?.name) || 'Rover';
39
+ const agentCard = bundle.agentCard ? JSON.parse(JSON.stringify(bundle.agentCard)) : undefined;
40
+ if (agentCard?.extensions?.rover) {
41
+ agentCard.extensions.rover.discoverySurface = {
42
+ ...(agentCard.extensions.rover.discoverySurface || {}),
43
+ mode: 'beacon',
44
+ hostSurface: 'floating-corner',
45
+ actionReveal: 'click',
46
+ beaconLabel: ctaText,
47
+ };
48
+ agentCard.extensions.rover.presence = {
49
+ assistantName,
50
+ ctaText,
51
+ draggable: presence.draggable !== false,
52
+ };
53
+ agentCard.extensions.rover.experience = experience;
54
+ agentCard.extensions.rover.inputs = {
55
+ filesEnabled: inputs.files !== false,
56
+ acceptedMimeGroups: Array.isArray(inputs.acceptedMimeGroups) ? inputs.acceptedMimeGroups : ['images', 'pdfs', 'office', 'text'],
57
+ allowMultipleFiles: inputs.allowMultipleFiles !== false,
58
+ };
59
+ }
60
+ const roverSite = bundle.roverSite ? JSON.parse(JSON.stringify(bundle.roverSite)) : undefined;
61
+ if (roverSite) {
62
+ roverSite.display = {
63
+ ...(roverSite.display || {}),
64
+ mode: 'beacon',
65
+ hostSurface: 'floating-corner',
66
+ actionReveal: 'click',
67
+ beaconLabel: ctaText,
68
+ presence: 'draggable_pill',
69
+ openMode: text(shell.openMode) || 'center_stage',
70
+ mobileMode: text(shell.mobileMode) || 'fullscreen_sheet',
71
+ streamMode: text(stream.layout) || 'single_column',
72
+ focusView: 'focus_stream',
73
+ };
74
+ roverSite.experience = experience;
75
+ roverSite.inputs = {
76
+ ...(roverSite.inputs || {}),
77
+ filesEnabled: inputs.files !== false,
78
+ acceptedMimeGroups: Array.isArray(inputs.acceptedMimeGroups) ? inputs.acceptedMimeGroups : ['images', 'pdfs', 'office', 'text'],
79
+ allowMultipleFiles: inputs.allowMultipleFiles !== false,
80
+ };
81
+ }
82
+ const agentCardJson = agentCard ? JSON.stringify(agentCard, null, 2) : bundle.agentCardJson;
83
+ const roverSiteJson = roverSite ? JSON.stringify(roverSite, null, 2) : bundle.roverSiteJson;
84
+ const inlineAgentCardScript = agentCardJson
85
+ ? `<script type="application/agent-card+json" data-rover-agent-discovery="agent-card">${escapeScriptJson(agentCardJson)}</script>`
86
+ : bundle.metadata.inlineAgentCardScript;
87
+ const inlineRoverSiteScript = roverSiteJson
88
+ ? `<script type="application/rover-site+json" data-rover-agent-discovery="rover-site">${escapeScriptJson(roverSiteJson)}</script>`
89
+ : bundle.metadata.inlineRoverSiteScript;
90
+ return {
91
+ ...bundle,
92
+ agentCard,
93
+ agentCardJson,
94
+ roverSite,
95
+ roverSiteJson,
96
+ bodyInstallHtml: replaceInlineDiscoveryScript(replaceInlineDiscoveryScript(bundle.bodyInstallHtml, 'agent-card', inlineAgentCardScript), 'rover-site', inlineRoverSiteScript),
97
+ metadata: {
98
+ ...bundle.metadata,
99
+ roverSiteJson,
100
+ inlineAgentCardScript,
101
+ inlineRoverSiteScript,
102
+ },
103
+ };
104
+ }
105
+ function indentJson(value) {
106
+ return JSON.stringify(value, null, 2)
107
+ .split('\n')
108
+ .map(line => ` ${line}`)
109
+ .join('\n');
110
+ }
111
+ function isObject(value) {
112
+ return !!value && typeof value === 'object' && !Array.isArray(value);
113
+ }
114
+ function hasObjectEntries(value) {
115
+ return isObject(value) && Object.keys(value).length > 0;
116
+ }
117
+ function normalizeAttachPollIntervalMs(value) {
118
+ const parsed = Number(value);
119
+ if (!Number.isFinite(parsed) || parsed < 10)
120
+ return 50;
121
+ return Math.round(parsed);
122
+ }
123
+ function normalizeAttachMaxAttempts(value) {
124
+ const parsed = Number(value);
125
+ if (!Number.isFinite(parsed) || parsed < 1)
126
+ return 300;
127
+ return Math.round(parsed);
128
+ }
129
+ function discoveryEnabled(config) {
130
+ return !!config && config.enabled !== false && config.aiAccess?.enabled !== false;
131
+ }
132
+ function llmsEnabled(input, config) {
133
+ if (!discoveryEnabled(config))
134
+ return false;
135
+ return input.emitLlmsTxt === true || !!text(config.llmsUrl);
136
+ }
137
+ function buildOwnerMarker(card, publishedAgentCardUrl) {
138
+ return {
139
+ task: card.extensions?.rover.taskEndpoint,
140
+ card: publishedAgentCardUrl,
141
+ roverSite: card.extensions?.rover.roverSiteUrl,
142
+ site: card.extensions?.rover.siteUrl,
143
+ workflow: card.extensions?.rover.workflowEndpoint,
144
+ page: card.extensions?.rover.currentPage?.pageId,
145
+ preferExecution: card.extensions?.rover.preferredExecution,
146
+ display: card.extensions?.rover.discoverySurface
147
+ ? {
148
+ mode: card.extensions.rover.discoverySurface.mode,
149
+ hostSurface: card.extensions.rover.discoverySurface.hostSurface,
150
+ actionReveal: card.extensions.rover.discoverySurface.actionReveal,
151
+ beaconLabel: card.extensions.rover.discoverySurface.beaconLabel,
152
+ }
153
+ : undefined,
154
+ skills: card.skills.slice(0, 24).map(skill => ({
155
+ id: skill.id,
156
+ name: skill.name,
157
+ })),
158
+ capabilities: (card.extensions?.rover.capabilitiesGraph || []).slice(0, 24).map(capability => ({
159
+ capabilityId: capability.capabilityId,
160
+ label: capability.label,
161
+ })),
162
+ };
163
+ }
164
+ function buildDefaultLlmsTxt(card, options) {
165
+ const lines = [
166
+ `# ${card.name}`,
167
+ '',
168
+ card.description,
169
+ '',
170
+ 'Prefer Rover shortcuts, explicit site tools, and public task flows over raw DOM automation when they match the requested outcome.',
171
+ `Primary task endpoint: ${text(card.extensions?.rover.taskEndpoint || card.url)}`,
172
+ `Workflow endpoint: ${text(card.extensions?.rover.workflowEndpoint)}`,
173
+ `Capability card: ${options.agentCardUrl}`,
174
+ ];
175
+ const skills = card.skills
176
+ .map(skill => ({
177
+ id: text(skill.id),
178
+ name: text(skill.name),
179
+ description: text(skill.description),
180
+ interface: text(skill.preferredInterface || skill.rover?.source || 'task'),
181
+ }))
182
+ .filter(skill => skill.id && skill.name);
183
+ if (skills.length > 0) {
184
+ lines.push('', 'Published skills:');
185
+ for (const skill of skills) {
186
+ const description = skill.description ? ` - ${skill.description}` : '';
187
+ lines.push(`- ${skill.id}: ${skill.name} [${skill.interface}]${description}`);
188
+ }
189
+ }
190
+ const shortcuts = (card.extensions?.rover.shortcuts || [])
191
+ .map(shortcut => `${text(shortcut.id)}: ${text(shortcut.label)}`)
192
+ .filter(Boolean);
193
+ if (shortcuts.length > 0) {
194
+ lines.push('', 'Shortcut IDs:');
195
+ for (const shortcut of shortcuts) {
196
+ lines.push(`- ${shortcut}`);
197
+ }
198
+ }
199
+ return lines.join('\n');
200
+ }
201
+ function buildQueueStubLines() {
202
+ return [
203
+ '(function(){ var r = window.rover = window.rover || function(){ (r.q = r.q || []).push(arguments); }; r.l = +new Date(); })();',
204
+ ];
205
+ }
206
+ function materializeCloudSandboxBootConfig(bootConfig) {
207
+ if (bootConfig.cloudSandboxEnabled !== true) {
208
+ return bootConfig;
209
+ }
210
+ return {
211
+ ...bootConfig,
212
+ tools: {
213
+ ...(bootConfig.tools || {}),
214
+ web: {
215
+ ...(bootConfig.tools?.web || {}),
216
+ enableExternalWebContext: true,
217
+ scrapeMode: 'on_demand',
218
+ },
219
+ },
220
+ };
221
+ }
222
+ function buildBootScript(bootConfig) {
223
+ const normalizedBootConfig = materializeCloudSandboxBootConfig(bootConfig);
224
+ const lines = [
225
+ '<script>',
226
+ ...buildQueueStubLines().map(line => ` ${line}`),
227
+ ` rover('boot', ${indentJson(normalizedBootConfig)});`,
228
+ '</script>',
229
+ ];
230
+ return lines.join('\n');
231
+ }
232
+ function buildRoverBookAttachScript(config, options) {
233
+ const pollIntervalMs = normalizeAttachPollIntervalMs(options?.pollIntervalMs);
234
+ const maxAttempts = normalizeAttachMaxAttempts(options?.maxAttempts);
235
+ return [
236
+ '<script>',
237
+ ' (function(){',
238
+ ` var roverBookConfig = ${indentJson(config)};`,
239
+ ' function attachRoverBook(){',
240
+ ' if (window.__ROVERBOOK_INSTANCE__) return true;',
241
+ ' var roverApi = window.rover;',
242
+ ' var roverBook = window.RoverBook;',
243
+ " if (!roverApi || typeof roverApi.on !== 'function' || typeof roverApi.requestSigned !== 'function') return false;",
244
+ " if (!roverBook || typeof roverBook.enableRoverBook !== 'function') return false;",
245
+ ' window.__ROVERBOOK_INSTANCE__ = roverBook.enableRoverBook(roverApi, roverBookConfig);',
246
+ ' return true;',
247
+ ' }',
248
+ ' if (attachRoverBook()) return;',
249
+ ' var attempts = 0;',
250
+ ' var timer = setInterval(function(){',
251
+ ' attempts += 1;',
252
+ ` if (attachRoverBook() || attempts >= ${maxAttempts}) clearInterval(timer);`,
253
+ ` }, ${pollIntervalMs});`,
254
+ ' })();',
255
+ '</script>',
256
+ ].join('\n');
257
+ }
258
+ export function createRoverOwnerInstallBundle(input) {
259
+ const bootConfig = materializeCloudSandboxBootConfig(input.bootConfig);
260
+ const discoveryConfig = discoveryEnabled(input.discovery) ? input.discovery : null;
261
+ const publishedAgentCardUrl = discoveryConfig ? text(discoveryConfig.agentCardUrl) || DEFAULT_AGENT_CARD_PATH : '';
262
+ const publishedRoverSiteUrl = discoveryConfig ? text(discoveryConfig.roverSiteUrl) || DEFAULT_ROVER_SITE_PATH : '';
263
+ const publishLlmsTxt = llmsEnabled(input, discoveryConfig);
264
+ const publishedLlmsUrl = discoveryConfig ? text(discoveryConfig.llmsUrl) : '';
265
+ const embedScriptUrl = text(input.embedScriptUrl) || DEFAULT_EMBED_SCRIPT_URL;
266
+ const roverBookEnabled = input.roverBook?.enabled !== false && hasObjectEntries(input.roverBook?.config);
267
+ const roverBookScriptUrl = roverBookEnabled
268
+ ? (text(input.roverBook?.scriptUrl) || DEFAULT_ROVERBOOK_SCRIPT_URL)
269
+ : '';
270
+ const agentCard = discoveryConfig ? createRoverAgentCard(discoveryConfig) : undefined;
271
+ const agentCardJson = discoveryConfig ? createRoverAgentCardJson(discoveryConfig) : undefined;
272
+ const roverSite = discoveryConfig ? createRoverSiteProfile(discoveryConfig) : undefined;
273
+ const roverSiteJson = discoveryConfig ? createRoverSiteProfileJson(discoveryConfig) : undefined;
274
+ const pageManifestJson = discoveryConfig
275
+ ? JSON.stringify(agentCard?.extensions?.rover.currentPage || null, null, 2)
276
+ : undefined;
277
+ const marker = agentCard && publishedAgentCardUrl
278
+ ? buildOwnerMarker(agentCard, publishedAgentCardUrl)
279
+ : undefined;
280
+ const markerJson = marker ? escapeScriptJson(JSON.stringify(marker)) : undefined;
281
+ const escapedAgentCardJson = agentCardJson ? escapeScriptJson(agentCardJson) : undefined;
282
+ const escapedRoverSiteJson = roverSiteJson ? escapeScriptJson(roverSiteJson) : undefined;
283
+ const escapedPageManifestJson = pageManifestJson ? escapeScriptJson(pageManifestJson) : undefined;
284
+ const serviceDescLinkTag = discoveryConfig && publishedAgentCardUrl
285
+ ? `<link rel="service-desc" href="${escapeHtmlAttr(publishedAgentCardUrl)}" type="application/json" />`
286
+ : undefined;
287
+ const serviceDocLinkTag = discoveryConfig && publishedLlmsUrl
288
+ ? `<link rel="service-doc" href="${escapeHtmlAttr(publishedLlmsUrl)}" type="text/markdown" />`
289
+ : undefined;
290
+ const bodyLines = [];
291
+ if (markerJson) {
292
+ bodyLines.push(`<script type="application/agent+json" data-rover-agent-discovery="marker">${markerJson}</script>`);
293
+ }
294
+ if (escapedRoverSiteJson) {
295
+ bodyLines.push(`<script type="application/rover-site+json" data-rover-agent-discovery="rover-site">${escapedRoverSiteJson}</script>`);
296
+ }
297
+ if (escapedPageManifestJson) {
298
+ bodyLines.push(`<script type="application/rover-page+json" data-rover-agent-discovery="page">${escapedPageManifestJson}</script>`);
299
+ }
300
+ if (escapedAgentCardJson) {
301
+ bodyLines.push(`<script type="application/agent-card+json" data-rover-agent-discovery="agent-card">${escapedAgentCardJson}</script>`);
302
+ }
303
+ bodyLines.push(buildBootScript(bootConfig));
304
+ bodyLines.push(`<script src="${escapeHtmlAttr(embedScriptUrl)}" async></script>`);
305
+ if (roverBookEnabled && roverBookScriptUrl) {
306
+ bodyLines.push(`<script src="${escapeHtmlAttr(roverBookScriptUrl)}" async></script>`);
307
+ bodyLines.push(buildRoverBookAttachScript(input.roverBook?.config || {}, {
308
+ pollIntervalMs: input.roverBook?.attachPollIntervalMs,
309
+ maxAttempts: input.roverBook?.attachMaxAttempts,
310
+ }));
311
+ }
312
+ const llmsTxt = publishLlmsTxt && agentCard
313
+ ? (text(input.llmsTxt) ? input.llmsTxt : buildDefaultLlmsTxt(agentCard, { agentCardUrl: publishedAgentCardUrl || DEFAULT_AGENT_CARD_PATH }))
314
+ : undefined;
315
+ return decorateBundleWithExperience({
316
+ bodyInstallHtml: bodyLines.join('\n'),
317
+ headDiscoveryHtml: [serviceDescLinkTag, serviceDocLinkTag].filter(Boolean).join('\n'),
318
+ agentCard,
319
+ agentCardJson,
320
+ roverSite,
321
+ roverSiteJson,
322
+ serviceDescLinkHeader: discoveryConfig
323
+ ? createRoverServiceDescLinkHeader({
324
+ agentCardUrl: publishedAgentCardUrl || DEFAULT_AGENT_CARD_PATH,
325
+ ...(publishedLlmsUrl ? { llmsUrl: publishedLlmsUrl } : {}),
326
+ })
327
+ : undefined,
328
+ llmsTxt,
329
+ metadata: {
330
+ discoveryEnabled: !!discoveryConfig,
331
+ llmsPublished: !!serviceDocLinkTag,
332
+ embedScriptUrl,
333
+ roverBookEnabled,
334
+ roverBookScriptUrl: roverBookScriptUrl || undefined,
335
+ publishedAgentCardUrl: publishedAgentCardUrl || undefined,
336
+ publishedRoverSiteUrl: publishedRoverSiteUrl || undefined,
337
+ publishedLlmsUrl: publishedLlmsUrl || undefined,
338
+ serviceDescLinkTag,
339
+ serviceDocLinkTag,
340
+ markerJson,
341
+ markerScript: markerJson
342
+ ? `<script type="application/agent+json" data-rover-agent-discovery="marker">${markerJson}</script>`
343
+ : undefined,
344
+ inlineAgentCardScript: escapedAgentCardJson
345
+ ? `<script type="application/agent-card+json" data-rover-agent-discovery="agent-card">${escapedAgentCardJson}</script>`
346
+ : undefined,
347
+ roverSiteJson,
348
+ inlineRoverSiteScript: escapedRoverSiteJson
349
+ ? `<script type="application/rover-site+json" data-rover-agent-discovery="rover-site">${escapedRoverSiteJson}</script>`
350
+ : undefined,
351
+ pageManifestJson,
352
+ pageManifestScript: escapedPageManifestJson
353
+ ? `<script type="application/rover-page+json" data-rover-agent-discovery="page">${escapedPageManifestJson}</script>`
354
+ : undefined,
355
+ },
356
+ }, input.bootConfig);
357
+ }
@@ -2,6 +2,14 @@ export type RoverPreviewAttachLaunch = {
2
2
  requestId: string;
3
3
  attachToken: string;
4
4
  };
5
+ export type RoverPreviewBootstrapVoiceConfig = {
6
+ enabled?: boolean;
7
+ language?: string;
8
+ autoStopMs?: number;
9
+ };
10
+ export type RoverPreviewBootstrapUiConfig = {
11
+ voice?: RoverPreviewBootstrapVoiceConfig;
12
+ };
5
13
  export type RoverPreviewBootstrapConfig = {
6
14
  scriptUrl?: string;
7
15
  siteId: string;
@@ -18,6 +26,7 @@ export type RoverPreviewBootstrapConfig = {
18
26
  openOnInit?: boolean;
19
27
  mode?: 'safe' | 'full';
20
28
  allowActions?: boolean;
29
+ ui?: RoverPreviewBootstrapUiConfig;
21
30
  attachLaunch?: RoverPreviewAttachLaunch;
22
31
  };
23
32
  export type RoverScriptAttributeSource = Pick<HTMLScriptElement, 'getAttribute'>;