rivet-design 0.28.1 → 0.28.3

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 (89) hide show
  1. package/dist/cli/commands/libraryOpen.js +1 -0
  2. package/dist/cli/commands/mcpServe.js +5 -1
  3. package/dist/cli/commands/open.js +17 -6
  4. package/dist/cli/commands/profile.js +8 -1
  5. package/dist/cli/commands/profileDisconnect.d.ts +3 -0
  6. package/dist/cli/commands/profileDisconnect.js +34 -0
  7. package/dist/cli/commands/serve.js +2 -0
  8. package/dist/cli/commands/shared.js +4 -1
  9. package/dist/cli/envelope.d.ts +1 -0
  10. package/dist/cli/router.js +8 -2
  11. package/dist/jest.globalSetup.d.ts +3 -0
  12. package/dist/jest.globalSetup.js +19 -0
  13. package/dist/library/browserLaunch.d.ts +2 -1
  14. package/dist/library/browserLaunch.js +3 -2
  15. package/dist/proxy-middleware/proxy-config.d.ts +0 -1
  16. package/dist/proxy-middleware/proxy-config.js +6 -34
  17. package/dist/routes/agentVariants.js +20 -173
  18. package/dist/routes/referenceProfiles.js +3 -3
  19. package/dist/routes/static.js +8 -2
  20. package/dist/server.d.ts +1 -1
  21. package/dist/server.js +15 -26
  22. package/dist/services/AuthService.js +7 -61
  23. package/dist/services/IntegrationsClient.d.ts +2 -1
  24. package/dist/services/IntegrationsClient.js +46 -20
  25. package/dist/services/TelemetryService.d.ts +16 -2
  26. package/dist/services/TelemetryService.js +18 -0
  27. package/dist/services/accessTokenRefresh.js +2 -2
  28. package/dist/services/profiles/DesignProfiles.d.ts +16 -0
  29. package/dist/services/profiles/DesignProfiles.js +78 -17
  30. package/dist/services/profiles/ProfileAnalysis.d.ts +3 -0
  31. package/dist/services/profiles/ProfileAnalysis.js +66 -1
  32. package/dist/services/profiles/ProfileImports.d.ts +2 -0
  33. package/dist/services/profiles/ProfileImports.js +2 -0
  34. package/dist/services/templates/viteReactTs.js +1 -1
  35. package/dist/storage/profiles/ProfileRecords.d.ts +17 -0
  36. package/dist/storage/profiles/ProfileRecords.js +45 -7
  37. package/dist/storage/profiles/migrations.d.ts +2 -2
  38. package/dist/storage/profiles/migrations.js +7 -0
  39. package/dist/storage/profiles/schema.d.ts +48 -0
  40. package/dist/storage/profiles/schema.js +3 -0
  41. package/dist/types/api-responses.d.ts +39 -0
  42. package/dist/types/api-responses.js +12 -1
  43. package/dist/types/design-profile.d.ts +12 -0
  44. package/dist/types/design-profile.js +10 -1
  45. package/dist/types/rivet-page-types.d.ts +48 -0
  46. package/dist/types/rivet-page-types.js +6 -0
  47. package/dist/utils/failureReason.js +1 -1
  48. package/dist/utils/hostedLogPrivacy.js +1 -1
  49. package/dist/utils/launchRuntime.d.ts +2 -0
  50. package/dist/utils/launchRuntime.js +12 -0
  51. package/dist/utils/rivetPage.d.ts +8 -0
  52. package/dist/utils/rivetPage.js +24 -0
  53. package/dist/utils/rivetPage.testHelpers.d.ts +6 -0
  54. package/dist/utils/rivetPage.testHelpers.js +18 -0
  55. package/dist/utils/rivetPageDocument.d.ts +7 -0
  56. package/dist/utils/rivetPageDocument.js +41 -0
  57. package/dist/utils/scriptJson.d.ts +2 -0
  58. package/dist/utils/scriptJson.js +9 -0
  59. package/dist/utils/skills/cli-guidance.d.ts +1 -1
  60. package/dist/utils/skills/cli-guidance.js +2 -1
  61. package/dist/utils/uiDistPath.d.ts +2 -0
  62. package/dist/utils/uiDistPath.js +22 -0
  63. package/package.json +8 -5
  64. package/src/ui/dist/assets/LibraryEntry-CSU5OJwC.js +2 -0
  65. package/src/ui/dist/assets/google-g-CpxN0HWb.png +0 -0
  66. package/src/ui/dist/assets/main-B89lcZEY.css +1 -0
  67. package/src/ui/dist/assets/main-DeCxjHC1.js +204 -0
  68. package/src/ui/dist/index.html +3 -3
  69. package/src/ui/dist/pages/empty-project.html +53 -0
  70. package/src/ui/dist/pages/rivet-page.html +53 -0
  71. package/dist/routes/emptyStatePage.d.ts +0 -2
  72. package/dist/routes/emptyStatePage.js +0 -589
  73. package/src/ui/dist/assets/LibraryEntry-DS6Ce0sW.js +0 -112
  74. package/src/ui/dist/assets/logo-animation/clasp.png +0 -0
  75. package/src/ui/dist/assets/logo-animation/eraser.png +0 -0
  76. package/src/ui/dist/assets/logo-animation/playdough.png +0 -0
  77. package/src/ui/dist/assets/logo-animation/sea/bubblephone.png +0 -0
  78. package/src/ui/dist/assets/logo-animation/sea/cart.png +0 -0
  79. package/src/ui/dist/assets/logo-animation/sea/chair.png +0 -0
  80. package/src/ui/dist/assets/logo-animation/sea/desk.png +0 -0
  81. package/src/ui/dist/assets/logo-animation/sea/mug.png +0 -0
  82. package/src/ui/dist/assets/logo-animation/sea/pitcher.png +0 -0
  83. package/src/ui/dist/assets/logo-animation/sea/pot.png +0 -0
  84. package/src/ui/dist/assets/logo-animation/sea/startac.png +0 -0
  85. package/src/ui/dist/assets/logo-animation/sea/terracotta-1.png +0 -0
  86. package/src/ui/dist/assets/logo-animation/sea/terracotta-2.png +0 -0
  87. package/src/ui/dist/assets/logo-animation/sea/vhsplant.png +0 -0
  88. package/src/ui/dist/assets/main-CQSk-6km.css +0 -1
  89. package/src/ui/dist/assets/main-DkKRuatC.js +0 -218
@@ -93,6 +93,7 @@ const handleLibraryOpen = async (args, io, options = {}) => {
93
93
  const editorUrl = await (0, browserLaunch_1.createLibraryLaunchUrl)({
94
94
  hub,
95
95
  path: `/rivet/library${projectSuffix}`,
96
+ callerAgent: context.handoff?.agent,
96
97
  });
97
98
  const browser = await (0, browser_1.requestBrowserOpen)({
98
99
  url: editorUrl,
@@ -184,6 +184,7 @@ const buildMcpServer = async (options = {}) => {
184
184
  ...(0, telemetry_1.variantContextMetadataForArgs)(command, rest),
185
185
  ...(0, telemetry_1.verificationMetadataForEnvelope)(result.envelope),
186
186
  ...callerFields,
187
+ error: result.cause,
187
188
  source: 'mcp',
188
189
  });
189
190
  }
@@ -455,7 +456,10 @@ const handleMcpServe = async (rest, io) => {
455
456
  await built.mcp.connect(new StdioServerTransport());
456
457
  }
457
458
  catch (error) {
458
- return (0, envelope_1.errorResult)('mcp', 'OPERATION_FAILED', `Could not start the MCP server: ${(0, errorMessage_1.errorMessage)(error)}`);
459
+ return {
460
+ ...(0, envelope_1.errorResult)('mcp', 'OPERATION_FAILED', `Could not start the MCP server: ${(0, errorMessage_1.errorMessage)(error)}`),
461
+ cause: error,
462
+ };
459
463
  }
460
464
  let isClosing = false;
461
465
  const shutdown = () => {
@@ -40,6 +40,7 @@ exports.ensureProjectRuntime = exports.validateProjectOpen = exports.PROJECT_RUN
40
40
  const projectRuntimeUpgrade_1 = require("../projectRuntimeUpgrade");
41
41
  const child_process_1 = require("child_process");
42
42
  const subprocessEnvironment_1 = require("../../utils/subprocessEnvironment");
43
+ const launchRuntime_1 = require("../../utils/launchRuntime");
43
44
  const fs_1 = __importDefault(require("fs"));
44
45
  const path_1 = __importDefault(require("path"));
45
46
  const envelope_1 = require("../envelope");
@@ -70,6 +71,7 @@ const SERVER_START_TIMEOUT_ENV = 'RIVET_SERVER_START_TIMEOUT_MS';
70
71
  const LOCK_WAIT_TIMEOUT_ENV = 'RIVET_LOCK_WAIT_TIMEOUT_MS';
71
72
  const OPEN_RETRY_DELAY_MS = 1_000;
72
73
  const APP_HEALTH_TIMEOUT_MS = 10_000;
74
+ const APP_HEALTH_TIMEOUT_ENV = 'RIVET_APP_HEALTH_TIMEOUT_MS';
73
75
  const RETRY_OPEN_RECOVERY = {
74
76
  isRecoverable: true,
75
77
  nextAction: { action: 'retry', delayMs: OPEN_RETRY_DELAY_MS },
@@ -172,7 +174,7 @@ const serveEnvFor = (handoff, baseEnv) => ({
172
174
  }
173
175
  : {}),
174
176
  });
175
- const openedData = async (attached, wasAlreadyRunning) => {
177
+ const openedData = async ({ attached, wasAlreadyRunning, callerAgent, }) => {
176
178
  let session;
177
179
  try {
178
180
  const status = await (0, client_1.requestServer)(attached, '/api/cli/status');
@@ -185,7 +187,7 @@ const openedData = async (attached, wasAlreadyRunning) => {
185
187
  attached: true,
186
188
  alreadyRunning: wasAlreadyRunning,
187
189
  rivetPort: attached.handshake.rivetPort,
188
- editorUrl: (0, client_1.editorUrlFor)(attached),
190
+ editorUrl: (0, launchRuntime_1.withLaunchRuntime)((0, client_1.editorUrlFor)(attached), callerAgent),
189
191
  sessionId: session?.sessionId ?? attached.handshake.sessionId,
190
192
  applyMode: attached.handshake.applyMode,
191
193
  resolvedRunner: session?.resolvedRunner ?? null,
@@ -247,6 +249,7 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
247
249
  const env = dependencies.env ?? process.env;
248
250
  const serverStartTimeoutMs = timeoutFromEnv(env, SERVER_START_TIMEOUT_ENV, DEFAULT_SERVER_START_TIMEOUT_MS);
249
251
  const lockWaitTimeoutMs = timeoutFromEnv(env, LOCK_WAIT_TIMEOUT_ENV, DEFAULT_LOCK_WAIT_TIMEOUT_MS);
252
+ const appHealthTimeoutMs = timeoutFromEnv(env, APP_HEALTH_TIMEOUT_ENV, Math.min(serverStartTimeoutMs, APP_HEALTH_TIMEOUT_MS));
250
253
  const validation = await (0, exports.validateProjectOpen)({
251
254
  context,
252
255
  io,
@@ -292,9 +295,13 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
292
295
  }, RETRY_OPEN_RECOVERY);
293
296
  }
294
297
  if (replacement.outcome === 'attach') {
295
- const readinessError = await verifyRuntimeReadiness(existing, Math.min(serverStartTimeoutMs, APP_HEALTH_TIMEOUT_MS));
298
+ const readinessError = await verifyRuntimeReadiness(existing, appHealthTimeoutMs);
296
299
  if (!readinessError) {
297
- return finishProjectOpen(await openedData(existing, true), io);
300
+ return finishProjectOpen(await openedData({
301
+ attached: existing,
302
+ wasAlreadyRunning: true,
303
+ callerAgent: context.handoff?.agent,
304
+ }), io);
298
305
  }
299
306
  if ((0, telemetry_1.serverUnavailableReasonForEnvelope)(readinessError.envelope) !==
300
307
  'app_health_failed')
@@ -346,10 +353,14 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
346
353
  ...(0, serverVersion_1.versionEnvelopeFields)(attached.handshake),
347
354
  });
348
355
  }
349
- const readinessError = await verifyRuntimeReadiness(attached, Math.min(serverStartTimeoutMs, APP_HEALTH_TIMEOUT_MS));
356
+ const readinessError = await verifyRuntimeReadiness(attached, appHealthTimeoutMs);
350
357
  if (readinessError)
351
358
  return readinessError;
352
- const data = await openedData(attached, false);
359
+ const data = await openedData({
360
+ attached,
361
+ wasAlreadyRunning: false,
362
+ callerAgent: context.handoff?.agent,
363
+ });
353
364
  return finishProjectOpen({ ...data, ...(interruptedWork ? { interruptedWork } : {}) }, io);
354
365
  }
355
366
  finally {
@@ -16,11 +16,18 @@ const envelope_1 = require("../envelope");
16
16
  const callerRunnerPaths_1 = require("../callerRunnerPaths");
17
17
  const errorMessage_1 = require("../../utils/errorMessage");
18
18
  const subprocessEnvironment_1 = require("../../utils/subprocessEnvironment");
19
+ const profileDisconnect_1 = require("./profileDisconnect");
19
20
  const PROFILE_REQUEST_TIMEOUT_MS = 55_000;
20
21
  const PROFILE_SEARCH_TIMEOUT_MS = 120_000;
21
22
  const handleProfile = async (args) => {
22
23
  const action = args[0] ?? 'status';
23
24
  const command = `profile.${action}`;
25
+ if (action === 'disconnect') {
26
+ const context = (0, shared_1.parseCommandContext)(command, args.slice(1));
27
+ return (0, shared_1.isCommandResult)(context)
28
+ ? context
29
+ : (0, profileDisconnect_1.handleProfileDisconnect)(context.flags.positionals);
30
+ }
24
31
  const context = (0, shared_1.parseCommandContext)(command, args.slice(1), {
25
32
  runtime: { takesValue: true },
26
33
  detail: { takesValue: false },
@@ -266,7 +273,7 @@ const handleProfile = async (args) => {
266
273
  };
267
274
  break;
268
275
  default:
269
- return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', 'Usage: rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest>');
276
+ return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', 'Usage: rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|disconnect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest>');
270
277
  }
271
278
  const hub = await (0, HubClient_1.ensureHub)({
272
279
  root: (0, ProjectLibrary_1.currentLibraryRoot)(),
@@ -0,0 +1,3 @@
1
+ import { type CliCommandResult } from '../envelope';
2
+ export declare const handleProfileDisconnect: (positionals: string[]) => Promise<CliCommandResult>;
3
+ //# sourceMappingURL=profileDisconnect.d.ts.map
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleProfileDisconnect = void 0;
4
+ const zod_1 = require("zod");
5
+ const ConfigManager_1 = require("../../services/ConfigManager");
6
+ const IntegrationsClient_1 = require("../../services/IntegrationsClient");
7
+ const reference_connectors_1 = require("../../types/reference-connectors");
8
+ const envelope_1 = require("../envelope");
9
+ const COMMAND = 'profile.disconnect';
10
+ const handleProfileDisconnect = async (positionals) => {
11
+ const selected = zod_1.z
12
+ .tuple([reference_connectors_1.AuthenticatedReferenceProviderSchema])
13
+ .safeParse(positionals);
14
+ if (!selected.success)
15
+ return (0, envelope_1.errorResult)(COMMAND, 'USAGE_ERROR', 'Usage: rivet profile disconnect <pinterest|arena|x>');
16
+ try {
17
+ const config = (0, ConfigManager_1.getConfigManager)();
18
+ const accountId = config.getUserId();
19
+ if (!accountId || !config.isAuthenticated())
20
+ return (0, envelope_1.errorResult)(COMMAND, 'AUTH_REQUIRED', 'Sign in to Rivet before disconnecting a reference account.');
21
+ const provider = selected.data[0];
22
+ const result = await new IntegrationsClient_1.IntegrationsClient().disconnect(provider, accountId);
23
+ if (result.status === 'ok')
24
+ return (0, envelope_1.okResult)(COMMAND, { provider, isDisconnected: true });
25
+ if (config.getUserId() !== accountId)
26
+ return (0, envelope_1.errorResult)(COMMAND, 'OPERATION_FAILED', 'Rivet account changed. Retry with the intended account.', { reason: 'account_changed' });
27
+ return (0, envelope_1.errorResult)(COMMAND, result.reason === 'auth_required' ? 'AUTH_REQUIRED' : 'OPERATION_FAILED', result.message, { reason: result.reason });
28
+ }
29
+ catch {
30
+ return (0, envelope_1.errorResult)(COMMAND, 'OPERATION_FAILED', 'Could not confirm reference account disconnection. Check your Rivet sign-in and connection, then retry.');
31
+ }
32
+ };
33
+ exports.handleProfileDisconnect = handleProfileDisconnect;
34
+ //# sourceMappingURL=profileDisconnect.js.map
@@ -200,6 +200,7 @@ const handleServe = async (args, io) => {
200
200
  previewPort,
201
201
  agentApplyMode: 'external',
202
202
  rivetPort,
203
+ resolveProjectName: (targetPath) => library.registry.findByPath(targetPath)?.name,
203
204
  resolveLibraryOrigin: () => {
204
205
  const hub = hubDiscovery.read();
205
206
  return hub?.port && (0, pid_1.isPidAlive)(hub.pid)
@@ -212,6 +213,7 @@ const handleServe = async (args, io) => {
212
213
  return null;
213
214
  return (0, browserLaunch_1.createLibraryLaunchUrl)({
214
215
  hub,
216
+ callerAgent: handoff?.agent,
215
217
  path: view === 'references'
216
218
  ? '/rivet/library/references'
217
219
  : '/rivet/library',
@@ -17,7 +17,10 @@ const pluginContext_1 = require("../../hosts/pluginContext");
17
17
  const commandErrorResult = (command, error) => error instanceof pluginContext_1.PluginContextMismatchError ||
18
18
  error instanceof telemetryPolicy_1.TelemetryPolicyMismatchError
19
19
  ? (0, envelope_1.errorResult)(command, 'SERVER_UNAVAILABLE', error.message, { serverUnavailableReason: error.reason }, { isRecoverable: false })
20
- : (0, envelope_1.errorResult)(command, 'OPERATION_FAILED', (0, errorMessage_1.errorMessage)(error));
20
+ : {
21
+ ...(0, envelope_1.errorResult)(command, 'OPERATION_FAILED', (0, errorMessage_1.errorMessage)(error)),
22
+ cause: error,
23
+ };
21
24
  exports.commandErrorResult = commandErrorResult;
22
25
  exports.SHARED_FLAG_SPEC = {
23
26
  project: { takesValue: true },
@@ -55,6 +55,7 @@ export type CliEnvelope<TData = unknown> = CliOkEnvelope<TData> | CliErrorEnvelo
55
55
  export type CliCommandResult = {
56
56
  envelope: CliEnvelope;
57
57
  exitCode: CliExitCode;
58
+ cause?: unknown;
58
59
  };
59
60
  export declare const okResult: (command: string, data: unknown) => CliCommandResult;
60
61
  export declare const loginRecovery: (authUrl?: string) => CliErrorRecovery;
@@ -52,8 +52,9 @@ const COMMAND_USAGE = {
52
52
  'resolve [--guidance auto|off] [--exclude-guidance <JSON IDs>] returns current effective text and native paths without a model call. inspect <workId> --project <path> reads retained generation context. Guidance above 32 KiB emits an advisory warning, not a truncation or rejection. The HTTP request limit remains 50 MiB.',
53
53
  ],
54
54
  profile: [
55
- 'rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest> [options]',
55
+ 'rivet profile <status|diagnostics|discover|plan|import|onboarding|rebuild-index|enable|disable|connect|disconnect|refresh|pause|resume|retry|add-text|add-images|pins|add-variant|inspect|references|reference|search|include|exclude|remove|suggest> [options]',
56
56
  'Search saved references by design intent with rivet profile search "<query>" [--source <sourceId>] [--limit N]. Results include stable keys for exact profile reference lookup and whether each source is included in automatic generation.',
57
+ 'Disconnect a linked account with rivet profile disconnect <pinterest|arena|x>. This removes the signed-in Rivet account’s provider connection and keeps saved references. Exactly one provider is required. It needs no running editor or worker runtime. Provider authorization revocation varies by provider.',
57
58
  'Resolve copied references in one batch with rivet profile reference <profileId> <shortId@revision>... . Default output is compact metadata. Add --detail only when full text, analysis, sources, and validated image paths are needed. No model work.',
58
59
  'Manage saved design references, including Pinterest, Are.na, public Cosmos collections, and X bookmarks (https://x.com/i/bookmarks). A disconnected X account returns an authorization URL; sign in and repeat connect. Connect reference accounts with discover pinterest|arena|x, or discover <public Cosmos profile URL>. Complete OAuth if requested and repeat discovery. Use plan <discoveryId> --collections <JSON>, then import <planId> --revision <revision> --approve after user consent. Onboarding preferences accept --provider cosmos|pinterest|arena|x. Read a saved preview with plan <planId>. Model work uses the selected agent runtime.',
59
60
  ],
@@ -264,6 +265,10 @@ const dispatch = async (command, rest, io, options = {}) => {
264
265
  return (0, envelope_1.errorResult)(command, 'USAGE_ERROR', `Unknown command: ${command}`);
265
266
  };
266
267
  exports.dispatch = dispatch;
268
+ const stdoutReservedForProtocolIO = (io) => ({
269
+ ...io,
270
+ writeEnvelope: (envelope) => io.writeProgress((0, envelope_1.serializeEnvelope)(envelope)),
271
+ });
267
272
  const runCliControlCommand = async (args, io = io_1.processCliIO) => {
268
273
  const { redirectLogsToStderr } = await Promise.resolve().then(() => __importStar(require('../utils/logger')));
269
274
  redirectLogsToStderr();
@@ -290,7 +295,7 @@ const runCliControlCommand = async (args, io = io_1.processCliIO) => {
290
295
  catch (error) {
291
296
  result = (0, shared_1.commandErrorResult)(command, error);
292
297
  }
293
- const exitCode = (0, io_1.emitResult)(io, result);
298
+ const exitCode = (0, io_1.emitResult)(command === 'mcp' ? stdoutReservedForProtocolIO(io) : io, result);
294
299
  if (!rest.includes('--no-telemetry') &&
295
300
  !(command === '__hub' && process.env.RIVET_LIBRARY_TELEMETRY === '0')) {
296
301
  try {
@@ -311,6 +316,7 @@ const runCliControlCommand = async (args, io = io_1.processCliIO) => {
311
316
  ...(0, telemetry_1.browserMetadataForEnvelope)(result.envelope),
312
317
  ...(0, telemetry_1.verificationMetadataForEnvelope)(result.envelope),
313
318
  ...(0, handoff_1.callerTelemetryFieldsFromArgs)(rest),
319
+ error: result.cause,
314
320
  });
315
321
  telemetry.reportInstallRefActivations();
316
322
  await telemetry.shutdown(result.envelope.command === 'variants.get'
@@ -0,0 +1,3 @@
1
+ declare const ensureRivetPageShells: () => void;
2
+ export default ensureRivetPageShells;
3
+ //# sourceMappingURL=jest.globalSetup.d.ts.map
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs_1 = __importDefault(require("fs"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const rivetPage_1 = require("./utils/rivetPage");
9
+ const ensureRivetPageShells = () => {
10
+ fs_1.default.mkdirSync(rivetPage_1.RIVET_PAGE_SHELL_DIRECTORY, { recursive: true });
11
+ for (const shellFile of rivetPage_1.RIVET_PAGE_SHELL_FILES) {
12
+ const builtShell = path_1.default.join(rivetPage_1.RIVET_PAGE_SHELL_DIRECTORY, shellFile);
13
+ if (!fs_1.default.existsSync(builtShell)) {
14
+ fs_1.default.copyFileSync(path_1.default.join(__dirname, 'ui', shellFile), builtShell);
15
+ }
16
+ }
17
+ };
18
+ exports.default = ensureRivetPageShells;
19
+ //# sourceMappingURL=jest.globalSetup.js.map
@@ -1,6 +1,7 @@
1
1
  import { type ConnectedHub } from './HubClient';
2
- export declare const createLibraryLaunchUrl: ({ hub, path, }: {
2
+ export declare const createLibraryLaunchUrl: ({ hub, path, callerAgent, }: {
3
3
  hub: ConnectedHub;
4
4
  path: string;
5
+ callerAgent?: string;
5
6
  }) => Promise<string>;
6
7
  //# sourceMappingURL=browserLaunch.d.ts.map
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createLibraryLaunchUrl = void 0;
4
4
  const HubClient_1 = require("./HubClient");
5
- const createLibraryLaunchUrl = async ({ hub, path, }) => {
5
+ const launchRuntime_1 = require("../utils/launchRuntime");
6
+ const createLibraryLaunchUrl = async ({ hub, path, callerAgent, }) => {
6
7
  const { code } = await (0, HubClient_1.requestHub)({
7
8
  hub,
8
9
  endpoint: '/launch-codes',
@@ -11,7 +12,7 @@ const createLibraryLaunchUrl = async ({ hub, path, }) => {
11
12
  const url = new URL(path, hub.url);
12
13
  url.hostname = 'localhost';
13
14
  url.hash = new URLSearchParams({ code }).toString();
14
- return url.toString();
15
+ return (0, launchRuntime_1.withLaunchRuntime)(url.toString(), callerAgent);
15
16
  };
16
17
  exports.createLibraryLaunchUrl = createLibraryLaunchUrl;
17
18
  //# sourceMappingURL=browserLaunch.js.map
@@ -14,7 +14,6 @@ export declare const resolveTargetAddressedPreview: (args: {
14
14
  resolveVariantPreviewPort?: ResolveVariantPreviewPort;
15
15
  }) => TargetAddressedPreview | null;
16
16
  export declare const markPreviewBridgeDocumentUncacheable: (proxyRes: IncomingMessage) => void;
17
- export declare const buildPreviewHoldingPage: () => string;
18
17
  export declare const createUserDevServerProxy: (userPort: number, userHost?: string, options?: {
19
18
  isPreviewBridgeEnabled?: boolean;
20
19
  expectedPreviewParentOrigin?: string;
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createUserDevServerProxy = exports.buildPreviewHoldingPage = exports.markPreviewBridgeDocumentUncacheable = exports.resolveTargetAddressedPreview = void 0;
3
+ exports.createUserDevServerProxy = exports.markPreviewBridgeDocumentUncacheable = exports.resolveTargetAddressedPreview = void 0;
4
4
  const http_proxy_middleware_1 = require("http-proxy-middleware");
5
5
  const crypto_1 = require("crypto");
6
6
  const logger_1 = require("../utils/logger");
7
+ const rivetPage_1 = require("../utils/rivetPage");
7
8
  const htmlDocument_1 = require("../utils/htmlDocument");
8
9
  const preview_connections_1 = require("./preview-connections");
9
10
  const preview_bridge_1 = require("./preview-bridge");
@@ -74,36 +75,6 @@ const markPreviewBridgeDocumentUncacheable = (proxyRes) => {
74
75
  proxyRes.headers['cache-control'] = 'no-cache, no-store';
75
76
  };
76
77
  exports.markPreviewBridgeDocumentUncacheable = markPreviewBridgeDocumentUncacheable;
77
- const buildPreviewHoldingPage = () => `<!doctype html>
78
- <html lang="en">
79
- <head>
80
- <meta charset="utf-8" />
81
- <meta name="viewport" content="width=device-width, initial-scale=1" />
82
- <title>Preview — waiting for dev server</title>
83
- <style>
84
- html, body { height: 100%; margin: 0; }
85
- body {
86
- display: flex; align-items: center; justify-content: center;
87
- background: #0f0f10; color: #a1a1aa;
88
- font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif;
89
- }
90
- .wrap { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 24px; text-align: center; }
91
- .spinner {
92
- width: 22px; height: 22px; border: 2px solid #2a2a2e; border-top-color: #a1a1aa;
93
- border-radius: 50%; animation: rivet-preview-spin 0.8s linear infinite;
94
- }
95
- @keyframes rivet-preview-spin { to { transform: rotate(360deg); } }
96
- @media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
97
- </style>
98
- </head>
99
- <body>
100
- <div class="wrap">
101
- <div class="spinner" aria-hidden="true"></div>
102
- <div>Waiting for the preview dev server…</div>
103
- </div>
104
- </body>
105
- </html>`;
106
- exports.buildPreviewHoldingPage = buildPreviewHoldingPage;
107
78
  const createUserDevServerProxy = (userPort, userHost = 'localhost', options = {}) => {
108
79
  let variantTarget = null;
109
80
  const requestTargets = new WeakMap();
@@ -311,9 +282,10 @@ const createUserDevServerProxy = (userPort, userHost = 'localhost', options = {}
311
282
  if ('writeHead' in res && !res.headersSent) {
312
283
  if (isPreviewBridgeEnabled && (0, preview_bridge_1.isHtmlDocumentRequest)(req)) {
313
284
  log.debug(`Serving preview holding page — no upstream yet (userPort=${userPort}).`);
314
- const body = (0, preview_bridge_1.injectPreviewBridge)((0, exports.buildPreviewHoldingPage)(), {
315
- expectedParentOrigin: options.expectedPreviewParentOrigin,
316
- });
285
+ const body = (0, preview_bridge_1.injectPreviewBridge)((0, rivetPage_1.renderRivetPage)({
286
+ page: { kind: 'preview-waiting' },
287
+ head: { title: 'Preview — waiting for dev server' },
288
+ }), { expectedParentOrigin: options.expectedPreviewParentOrigin });
317
289
  res.writeHead(200, {
318
290
  'Content-Type': 'text/html; charset=utf-8',
319
291
  'Cache-Control': 'no-cache, no-store',
@@ -23,6 +23,7 @@ const express_1 = require("express");
23
23
  const v3_1 = require("zod/v3");
24
24
  const api_responses_1 = require("../types/api-responses");
25
25
  const logger_1 = require("../utils/logger");
26
+ const rivetPage_1 = require("../utils/rivetPage");
26
27
  const agent_variants_1 = require("../agent-variants");
27
28
  const changeBatchClassification_1 = require("../mcp/changeBatchClassification");
28
29
  const createAgentVariantsOrchestrator_1 = require("../services/createAgentVariantsOrchestrator");
@@ -167,22 +168,6 @@ const HISTORY_STATUSES = new Set([
167
168
  ]);
168
169
  const VARIANT_SHARE_TITLE_FALLBACK = 'Prototype';
169
170
  const CANVAS_SHARE_TITLE_FALLBACK = 'Prototype canvas';
170
- const escapeHtml = (value) => value.replace(/[&<>"']/g, (char) => {
171
- switch (char) {
172
- case '&':
173
- return '&amp;';
174
- case '<':
175
- return '&lt;';
176
- case '>':
177
- return '&gt;';
178
- case '"':
179
- return '&quot;';
180
- case "'":
181
- return '&#39;';
182
- default:
183
- return char;
184
- }
185
- });
186
171
  const getVariantShareTitle = (manifest) => {
187
172
  const title = [manifest.label, manifest.brief, manifest.sessionPrompt].find((candidate) => candidate.trim().length > 0);
188
173
  return (0, PrototypeDeployService_1.normalizePrototypeShareTitle)(title) ?? VARIANT_SHARE_TITLE_FALLBACK;
@@ -190,165 +175,27 @@ const getVariantShareTitle = (manifest) => {
190
175
  const getCanvasShareTitle = (sessionPrompt) => {
191
176
  return ((0, PrototypeDeployService_1.normalizePrototypeShareTitle)(sessionPrompt) ?? CANVAS_SHARE_TITLE_FALLBACK);
192
177
  };
193
- const CANVAS_IFRAME_SANDBOX = 'allow-scripts allow-forms allow-popups';
194
178
  const RIVET_SOCIAL_IMAGE_URL = 'https://rivet.design/images/rivet-social.png';
195
179
  const RIVET_DEFAULT_SHARE_DESCRIPTION = 'Built with Rivet — the visual editor for design';
196
180
  const UNSUPPORTED_PROTOTYPE_DEPLOY_MESSAGE = "This prototype can't be deployed — only buildable app directions or static previews are supported.";
197
- const buildCanvasShareHtml = (args) => {
198
- const prompt = args.sessionPrompt.trim();
199
- const variantCards = args.variants
200
- .map((variant, index) => {
201
- const label = variant.label.trim() || `Direction ${index + 1}`;
202
- const brief = variant.brief.trim();
203
- return `<article class="variant-card">
204
- <header>
205
- <div>
206
- <p class="eyebrow">Direction ${index + 1}</p>
207
- <h2>${escapeHtml(label)}</h2>
208
- </div>
209
- <a href="${escapeHtml(variant.shareUrl)}" target="_blank" rel="noreferrer">Open</a>
210
- </header>
211
- ${brief ? `<p class="brief">${escapeHtml(brief)}</p>` : ''}
212
- <iframe title="${escapeHtml(label)}" src="${escapeHtml(variant.shareUrl)}" loading="lazy" sandbox="${CANVAS_IFRAME_SANDBOX}"></iframe>
213
- </article>`;
214
- })
215
- .join('\n');
216
- const canvasTitle = `Rivet Canvas — ${args.variants.length} directions`;
217
- const escapedTitle = escapeHtml(canvasTitle);
218
- const escapedDesc = escapeHtml(RIVET_DEFAULT_SHARE_DESCRIPTION);
219
- return `<!doctype html>
220
- <html lang="en">
221
- <head>
222
- <meta charset="utf-8">
223
- <meta name="viewport" content="width=device-width, initial-scale=1">
224
- <title>${escapedTitle}</title>
225
- <meta name="description" content="${escapedDesc}" />
226
- <meta property="og:type" content="website" />
227
- <meta property="og:title" content="${escapedTitle}" />
228
- <meta property="og:description" content="${escapedDesc}" />
229
- <meta property="og:image" content="${RIVET_SOCIAL_IMAGE_URL}" />
230
- <meta name="twitter:card" content="summary_large_image" />
231
- <meta name="twitter:title" content="${escapedTitle}" />
232
- <meta name="twitter:description" content="${escapedDesc}" />
233
- <meta name="twitter:image" content="${RIVET_SOCIAL_IMAGE_URL}" />
234
- <style>
235
- :root {
236
- color-scheme: light;
237
- --bg: #f6f4ef;
238
- --card: #ffffff;
239
- --ink: #161615;
240
- --muted: #6f6a60;
241
- --border: #ded8cc;
242
- --accent: #ff5a1f;
243
- }
244
- * { box-sizing: border-box; }
245
- body {
246
- margin: 0;
247
- background: var(--bg);
248
- color: var(--ink);
249
- font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
250
- }
251
- main {
252
- width: min(1440px, calc(100vw - 32px));
253
- margin: 0 auto;
254
- padding: 32px 0 48px;
255
- }
256
- .hero {
257
- display: flex;
258
- align-items: flex-end;
259
- justify-content: space-between;
260
- gap: 24px;
261
- margin-bottom: 24px;
262
- }
263
- h1 {
264
- margin: 0;
265
- font-size: clamp(32px, 5vw, 64px);
266
- letter-spacing: -0.06em;
267
- line-height: 0.95;
268
- }
269
- .prompt {
270
- max-width: 720px;
271
- color: var(--muted);
272
- font-size: 15px;
273
- line-height: 1.5;
274
- }
275
- .grid {
276
- display: grid;
277
- grid-template-columns: repeat(auto-fit, minmax(420px, 1fr));
278
- gap: 18px;
279
- }
280
- .variant-card {
281
- overflow: hidden;
282
- border: 1px solid var(--border);
283
- border-radius: 18px;
284
- background: var(--card);
285
- box-shadow: 0 20px 60px rgba(22, 22, 21, 0.08);
286
- }
287
- .variant-card header {
288
- display: flex;
289
- align-items: flex-start;
290
- justify-content: space-between;
291
- gap: 16px;
292
- padding: 18px 18px 0;
293
- }
294
- .eyebrow {
295
- margin: 0 0 6px;
296
- color: var(--accent);
297
- font-size: 11px;
298
- font-weight: 700;
299
- letter-spacing: 0.12em;
300
- text-transform: uppercase;
301
- }
302
- h2 {
303
- margin: 0;
304
- font-size: 20px;
305
- letter-spacing: -0.03em;
306
- }
307
- a {
308
- color: var(--ink);
309
- font-size: 13px;
310
- font-weight: 700;
311
- text-decoration: none;
312
- border-bottom: 1px solid currentColor;
313
- }
314
- .brief {
315
- margin: 10px 18px 16px;
316
- color: var(--muted);
317
- font-size: 13px;
318
- line-height: 1.45;
319
- }
320
- iframe {
321
- display: block;
322
- width: 100%;
323
- height: 720px;
324
- border: 0;
325
- border-top: 1px solid var(--border);
326
- background: white;
327
- }
328
- @media (max-width: 640px) {
329
- main { width: min(100vw - 20px, 1440px); padding-top: 20px; }
330
- .hero { display: block; }
331
- .grid { grid-template-columns: 1fr; }
332
- iframe { height: 560px; }
333
- }
334
- </style>
335
- </head>
336
- <body>
337
- <main>
338
- <section class="hero">
339
- <div>
340
- <p class="eyebrow">Rivet Canvas</p>
341
- <h1>${args.variants.length} directions</h1>
342
- </div>
343
- ${prompt ? `<p class="prompt">${escapeHtml(prompt)}</p>` : ''}
344
- </section>
345
- <section class="grid">
346
- ${variantCards}
347
- </section>
348
- </main>
349
- </body>
350
- </html>`;
351
- };
181
+ const buildCanvasSharePage = (args) => (0, rivetPage_1.renderRivetPage)({
182
+ page: {
183
+ kind: 'canvas-share',
184
+ prompt: args.sessionPrompt.trim(),
185
+ directions: args.variants.map((variant, index) => ({
186
+ label: variant.label.trim() || `Direction ${index + 1}`,
187
+ brief: variant.brief.trim(),
188
+ shareUrl: variant.shareUrl,
189
+ })),
190
+ },
191
+ head: {
192
+ title: `Rivet Canvas — ${args.variants.length} directions`,
193
+ shareCard: {
194
+ description: RIVET_DEFAULT_SHARE_DESCRIPTION,
195
+ imageUrl: RIVET_SOCIAL_IMAGE_URL,
196
+ },
197
+ },
198
+ });
352
199
  const generatedProjectWorkspaceRoot = (projectPath) => {
353
200
  const normalized = path_1.default.normalize(projectPath);
354
201
  const segments = normalized.split(path_1.default.sep);
@@ -1811,7 +1658,7 @@ const createAgentVariantsRouter = (orchestrator, bridge, telemetry, variantHisto
1811
1658
  }
1812
1659
  deployedVariants.push(deployed.variant);
1813
1660
  }
1814
- const html = buildCanvasShareHtml({
1661
+ const html = buildCanvasSharePage({
1815
1662
  sessionPrompt,
1816
1663
  variants: deployedVariants,
1817
1664
  });
@@ -6,7 +6,7 @@ const zod_1 = require("zod");
6
6
  const HubClient_1 = require("../library/HubClient");
7
7
  const ProjectLibrary_1 = require("../services/ProjectLibrary");
8
8
  const ConfigManager_1 = require("../services/ConfigManager");
9
- const cosmos_1 = require("../types/cosmos");
9
+ const reference_connectors_1 = require("../types/reference-connectors");
10
10
  const reference_onboarding_1 = require("../types/reference-onboarding");
11
11
  const design_profile_1 = require("../types/design-profile");
12
12
  const errorMessage_1 = require("../utils/errorMessage");
@@ -28,11 +28,11 @@ const createReferenceProfilesRouter = () => {
28
28
  }));
29
29
  });
30
30
  router.post('/reference-profiles/discoveries', async (req, res) => {
31
- const url = cosmos_1.CosmosProfileUrlSchema.parse(req.body?.url);
31
+ const input = reference_connectors_1.ReferenceDiscoveryRequestSchema.parse(req.body);
32
32
  res.status(201).json(await (0, HubClient_1.requestHub)({
33
33
  hub: await connectedHub(),
34
34
  endpoint: '/profile/discoveries',
35
- body: { url },
35
+ body: input,
36
36
  }));
37
37
  });
38
38
  router.post('/reference-profiles/import-plans', async (req, res) => {
@@ -42,7 +42,7 @@ const path_1 = __importDefault(require("path"));
42
42
  const fs_1 = __importDefault(require("fs"));
43
43
  const logger_1 = require("../utils/logger");
44
44
  const preview_bridge_1 = require("../proxy-middleware/preview-bridge");
45
- const emptyStatePage_1 = require("./emptyStatePage");
45
+ const rivetPage_1 = require("../utils/rivetPage");
46
46
  const log = (0, logger_1.createLogger)('StaticRoutes');
47
47
  const createStaticRoutes = (staticService, _projectPath, options = {}) => {
48
48
  const router = (0, express_1.Router)();
@@ -62,7 +62,13 @@ const createStaticRoutes = (staticService, _projectPath, options = {}) => {
62
62
  res.sendFile(entryFileName, { root: basePath });
63
63
  };
64
64
  const sendEmptyState = (res) => {
65
- res.status(200).type('html').send((0, emptyStatePage_1.renderEmptyState)());
65
+ res
66
+ .status(200)
67
+ .type('html')
68
+ .send((0, rivetPage_1.renderRivetPage)({
69
+ page: { kind: 'empty-project' },
70
+ head: { title: 'Empty project' },
71
+ }));
66
72
  };
67
73
  router.get('/static', (_req, res) => {
68
74
  const entryPath = path_1.default.join(basePath, entryFileName);