rivet-design 0.28.0 → 0.28.2
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/README.md +2 -6
- package/README.npm.md +2 -6
- package/dist/agent-variants/WorktreeOrchestrator.js +6 -4
- package/dist/cli/commands/open.js +4 -2
- package/dist/cli/commands/serve.js +1 -0
- package/dist/jest.globalSetup.d.ts +3 -0
- package/dist/jest.globalSetup.js +19 -0
- package/dist/proxy-middleware/proxy-config.d.ts +0 -1
- package/dist/proxy-middleware/proxy-config.js +6 -34
- package/dist/routes/agentVariants.js +20 -173
- package/dist/routes/static.js +8 -2
- package/dist/server.d.ts +1 -1
- package/dist/server.js +13 -25
- package/dist/services/AuthService.js +7 -61
- package/dist/services/templates/viteReactTs.js +1 -1
- package/dist/types/rivet-page-types.d.ts +48 -0
- package/dist/types/rivet-page-types.js +6 -0
- package/dist/utils/rivetPage.d.ts +8 -0
- package/dist/utils/rivetPage.js +24 -0
- package/dist/utils/rivetPage.testHelpers.d.ts +6 -0
- package/dist/utils/rivetPage.testHelpers.js +18 -0
- package/dist/utils/rivetPageDocument.d.ts +7 -0
- package/dist/utils/rivetPageDocument.js +41 -0
- package/dist/utils/scriptJson.d.ts +2 -0
- package/dist/utils/scriptJson.js +9 -0
- package/dist/utils/uiDistPath.d.ts +2 -0
- package/dist/utils/uiDistPath.js +22 -0
- package/package.json +21 -28
- package/src/ui/dist/assets/LibraryEntry-B8-RtQpK.js +2 -0
- package/src/ui/dist/assets/google-g-CpxN0HWb.png +0 -0
- package/src/ui/dist/assets/main-11-ME6E3.css +1 -0
- package/src/ui/dist/assets/main-BGCGsyhl.js +204 -0
- package/src/ui/dist/index.html +3 -3
- package/src/ui/dist/pages/empty-project.html +53 -0
- package/src/ui/dist/pages/rivet-page.html +53 -0
- package/dist/routes/emptyStatePage.d.ts +0 -2
- package/dist/routes/emptyStatePage.js +0 -589
- package/src/ui/dist/assets/LibraryEntry-BE8nZneH.js +0 -37
- package/src/ui/dist/assets/logo-animation/clasp.png +0 -0
- package/src/ui/dist/assets/logo-animation/eraser.png +0 -0
- package/src/ui/dist/assets/logo-animation/playdough.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/bubblephone.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/cart.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/chair.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/desk.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/mug.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/pitcher.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/pot.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/startac.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/terracotta-1.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/terracotta-2.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/vhsplant.png +0 -0
- package/src/ui/dist/assets/main-1EDrDqgn.js +0 -498
- package/src/ui/dist/assets/main-qgqnlUkI.css +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rivet
|
|
2
2
|
|
|
3
|
-
Rivet
|
|
3
|
+
Rivet is a design agent for your coding agent. It explores dozens of design directions in parallel so you can pick the one that fits. It opens a local visual editor, generates parallel variants, and lets you refine with comments.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -81,8 +81,6 @@ rivet variants start --project /path/to/app --instruction "try three hero layout
|
|
|
81
81
|
rivet wait <workId> --project /path/to/app --timeout 120
|
|
82
82
|
rivet variants list --project /path/to/app
|
|
83
83
|
rivet variants get <projectId>/<sessionId>:<variantId> --detail
|
|
84
|
-
rivet changes request --project /path/to/app --instruction "make the header coral" --element "#header"
|
|
85
|
-
rivet changes pull --project /path/to/app
|
|
86
84
|
rivet update
|
|
87
85
|
rivet stop --project /path/to/app
|
|
88
86
|
```
|
|
@@ -103,12 +101,10 @@ rivet open --project /path/to/app --caller-agent cursor --caller-model <model> -
|
|
|
103
101
|
## How It Works
|
|
104
102
|
|
|
105
103
|
1. `rivet open` starts or attaches to the local Rivet editor server for a project. It can attach to an existing dev server or start the app's standard `dev`, `start`, or `serve` script when possible.
|
|
106
|
-
2. The editor shows your app and variant previews in the browser. Agents use `rivet variants ...`
|
|
104
|
+
2. The editor shows your app and variant previews in the browser. Agents use `rivet variants ...` to enqueue work.
|
|
107
105
|
3. Use `rivet wait`, `rivet status`, or `rivet status --watch` to observe progress.
|
|
108
106
|
4. Copy the chosen direction’s context and ask your coding agent to implement it in your project. Rivet preserves the prototype; your agent owns integration and verification.
|
|
109
107
|
|
|
110
|
-
If Rivet reports pull mode, staged work can be drained with `rivet changes pull --project <path>`, applied by the agent, then acknowledged with `rivet changes pull --project <path> --ack <leaseId>`.
|
|
111
|
-
|
|
112
108
|
## Supported Frameworks
|
|
113
109
|
|
|
114
110
|
- Next.js
|
package/README.npm.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Rivet
|
|
2
2
|
|
|
3
|
-
Rivet
|
|
3
|
+
Rivet is a design agent for your coding agent. It explores dozens of design directions in parallel so you can pick the one that fits. It opens a local visual editor, generates parallel variants, and lets you refine with comments.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -81,8 +81,6 @@ rivet variants start --project /path/to/app --instruction "try three hero layout
|
|
|
81
81
|
rivet wait <workId> --project /path/to/app --timeout 120
|
|
82
82
|
rivet variants list --project /path/to/app
|
|
83
83
|
rivet variants get <projectId>/<sessionId>:<variantId> --detail
|
|
84
|
-
rivet changes request --project /path/to/app --instruction "make the header coral" --element "#header"
|
|
85
|
-
rivet changes pull --project /path/to/app
|
|
86
84
|
rivet update
|
|
87
85
|
rivet stop --project /path/to/app
|
|
88
86
|
```
|
|
@@ -103,12 +101,10 @@ rivet open --project /path/to/app --caller-agent cursor --caller-model <model> -
|
|
|
103
101
|
## How It Works
|
|
104
102
|
|
|
105
103
|
1. `rivet open` starts or attaches to the local Rivet editor server for a project. It can attach to an existing dev server or start the app's standard `dev`, `start`, or `serve` script when possible.
|
|
106
|
-
2. The editor shows your app and variant previews in the browser. Agents use `rivet variants ...`
|
|
104
|
+
2. The editor shows your app and variant previews in the browser. Agents use `rivet variants ...` to enqueue work.
|
|
107
105
|
3. Use `rivet wait`, `rivet status`, or `rivet status --watch` to observe progress.
|
|
108
106
|
4. Copy the chosen direction’s context and ask your coding agent to implement it in your project. Rivet preserves the prototype; your agent owns integration and verification.
|
|
109
107
|
|
|
110
|
-
If Rivet reports pull mode, staged work can be drained with `rivet changes pull --project <path>`, applied by the agent, then acknowledged with `rivet changes pull --project <path> --ack <leaseId>`.
|
|
111
|
-
|
|
112
108
|
## Supported Frameworks
|
|
113
109
|
|
|
114
110
|
- Next.js
|
|
@@ -2743,10 +2743,12 @@ class AgentVariantsOrchestrator {
|
|
|
2743
2743
|
await Promise.all(this.workspaceInventory
|
|
2744
2744
|
.getWorktrees(sessionId)
|
|
2745
2745
|
.map((record) => DependencyPreparationService_1.previewDependencies.settle(record.worktreePath)));
|
|
2746
|
-
await Promise
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2746
|
+
await new Promise((resolve) => {
|
|
2747
|
+
const timer = setTimeout(resolve, SETTLE_PERSISTS_TEARDOWN_TIMEOUT_MS);
|
|
2748
|
+
void this.settleHistoryPersists()
|
|
2749
|
+
.finally(() => clearTimeout(timer))
|
|
2750
|
+
.then(resolve);
|
|
2751
|
+
});
|
|
2750
2752
|
await this.previewRuntime.closeSession(sessionId);
|
|
2751
2753
|
await this.workspaceInventory.disposeAssignments({ sessionId });
|
|
2752
2754
|
this.resources.delete(sessionId);
|
|
@@ -70,6 +70,7 @@ const SERVER_START_TIMEOUT_ENV = 'RIVET_SERVER_START_TIMEOUT_MS';
|
|
|
70
70
|
const LOCK_WAIT_TIMEOUT_ENV = 'RIVET_LOCK_WAIT_TIMEOUT_MS';
|
|
71
71
|
const OPEN_RETRY_DELAY_MS = 1_000;
|
|
72
72
|
const APP_HEALTH_TIMEOUT_MS = 10_000;
|
|
73
|
+
const APP_HEALTH_TIMEOUT_ENV = 'RIVET_APP_HEALTH_TIMEOUT_MS';
|
|
73
74
|
const RETRY_OPEN_RECOVERY = {
|
|
74
75
|
isRecoverable: true,
|
|
75
76
|
nextAction: { action: 'retry', delayMs: OPEN_RETRY_DELAY_MS },
|
|
@@ -247,6 +248,7 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
|
|
|
247
248
|
const env = dependencies.env ?? process.env;
|
|
248
249
|
const serverStartTimeoutMs = timeoutFromEnv(env, SERVER_START_TIMEOUT_ENV, DEFAULT_SERVER_START_TIMEOUT_MS);
|
|
249
250
|
const lockWaitTimeoutMs = timeoutFromEnv(env, LOCK_WAIT_TIMEOUT_ENV, DEFAULT_LOCK_WAIT_TIMEOUT_MS);
|
|
251
|
+
const appHealthTimeoutMs = timeoutFromEnv(env, APP_HEALTH_TIMEOUT_ENV, Math.min(serverStartTimeoutMs, APP_HEALTH_TIMEOUT_MS));
|
|
250
252
|
const validation = await (0, exports.validateProjectOpen)({
|
|
251
253
|
context,
|
|
252
254
|
io,
|
|
@@ -292,7 +294,7 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
|
|
|
292
294
|
}, RETRY_OPEN_RECOVERY);
|
|
293
295
|
}
|
|
294
296
|
if (replacement.outcome === 'attach') {
|
|
295
|
-
const readinessError = await verifyRuntimeReadiness(existing,
|
|
297
|
+
const readinessError = await verifyRuntimeReadiness(existing, appHealthTimeoutMs);
|
|
296
298
|
if (!readinessError) {
|
|
297
299
|
return finishProjectOpen(await openedData(existing, true), io);
|
|
298
300
|
}
|
|
@@ -346,7 +348,7 @@ const ensureProjectRuntime = async (context, io, dependencies = {}) => {
|
|
|
346
348
|
...(0, serverVersion_1.versionEnvelopeFields)(attached.handshake),
|
|
347
349
|
});
|
|
348
350
|
}
|
|
349
|
-
const readinessError = await verifyRuntimeReadiness(attached,
|
|
351
|
+
const readinessError = await verifyRuntimeReadiness(attached, appHealthTimeoutMs);
|
|
350
352
|
if (readinessError)
|
|
351
353
|
return readinessError;
|
|
352
354
|
const data = await openedData(attached, false);
|
|
@@ -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)
|
|
@@ -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
|
|
@@ -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.
|
|
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,
|
|
315
|
-
|
|
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 '&';
|
|
174
|
-
case '<':
|
|
175
|
-
return '<';
|
|
176
|
-
case '>':
|
|
177
|
-
return '>';
|
|
178
|
-
case '"':
|
|
179
|
-
return '"';
|
|
180
|
-
case "'":
|
|
181
|
-
return ''';
|
|
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
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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 =
|
|
1661
|
+
const html = buildCanvasSharePage({
|
|
1815
1662
|
sessionPrompt,
|
|
1816
1663
|
variants: deployedVariants,
|
|
1817
1664
|
});
|
package/dist/routes/static.js
CHANGED
|
@@ -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
|
|
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
|
|
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);
|
package/dist/server.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ import type { VariantRunService } from './services/VariantRunService';
|
|
|
7
7
|
import type { VariantsRuntime } from './services/VariantsRuntime';
|
|
8
8
|
export declare const INACTIVE_VARIANTS_EVENT_HEARTBEAT_MS = 30000;
|
|
9
9
|
export declare const RIVET_CORS_ALLOWED_HEADERS: string[];
|
|
10
|
-
export declare const DIST_UI_PATH: string;
|
|
11
10
|
type RivetUiBootstrap = {
|
|
12
11
|
agentApplyMode: 'embedded' | 'external' | null;
|
|
13
12
|
queueAccessToken: string | null;
|
|
@@ -58,6 +57,7 @@ export type ServerOptions = Omit<CLIOptions, 'help' | 'version' | 'debug'> & {
|
|
|
58
57
|
userHost?: string;
|
|
59
58
|
beforeShutdown?: () => Promise<void>;
|
|
60
59
|
resolveLibraryOrigin?: () => string | undefined;
|
|
60
|
+
resolveProjectName?: (projectPath: string) => string | undefined;
|
|
61
61
|
createLibraryViewUrl?: (view: 'projects' | 'references') => Promise<string | null>;
|
|
62
62
|
};
|
|
63
63
|
export type ServerHandle = {
|
package/dist/server.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.startServer = exports.runServerShutdownTasks = exports.isRivetCorsOriginAllowed = exports.isRivetUiStaticAssetPath = exports.isEmbeddedAgentUiHost = exports.resolveEmbeddedAgentUiOrigin = exports.resolveRivetListenHost = exports.sendInactiveVariantsEventStream = exports.readRivetUiIndexHtml = exports.injectRivetUiBootstrap = exports.
|
|
39
|
+
exports.startServer = exports.runServerShutdownTasks = exports.isRivetCorsOriginAllowed = exports.isRivetUiStaticAssetPath = exports.isEmbeddedAgentUiHost = exports.resolveEmbeddedAgentUiOrigin = exports.resolveRivetListenHost = exports.sendInactiveVariantsEventStream = exports.readRivetUiIndexHtml = exports.injectRivetUiBootstrap = exports.RIVET_CORS_ALLOWED_HEADERS = exports.INACTIVE_VARIANTS_EVENT_HEARTBEAT_MS = void 0;
|
|
40
40
|
const editorSession_1 = require("./cli/editorSession");
|
|
41
41
|
const editorAccess_1 = require("./routes/editorAccess");
|
|
42
42
|
const editorAccess_2 = require("./utils/editorAccess");
|
|
@@ -77,6 +77,8 @@ const VariantHistoryService_1 = require("./services/VariantHistoryService");
|
|
|
77
77
|
const RequestAuthContext_1 = require("./services/RequestAuthContext");
|
|
78
78
|
const middleware_1 = require("./routes/library/middleware");
|
|
79
79
|
const errorMessage_1 = require("./utils/errorMessage");
|
|
80
|
+
const scriptJson_1 = require("./utils/scriptJson");
|
|
81
|
+
const uiDistPath_1 = require("./utils/uiDistPath");
|
|
80
82
|
const pluginContext_1 = require("./hosts/pluginContext");
|
|
81
83
|
const log = (0, index_core_1.createLogger)('RivetServer');
|
|
82
84
|
const QUEUE_ACCESS_TOKEN_BYTES = 32;
|
|
@@ -93,36 +95,21 @@ exports.RIVET_CORS_ALLOWED_HEADERS = [
|
|
|
93
95
|
'x-rivet-queue-token',
|
|
94
96
|
editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER,
|
|
95
97
|
];
|
|
96
|
-
const resolveUiPath = () => {
|
|
97
|
-
const bundledPath = path_1.default.join(__dirname, 'ui/dist');
|
|
98
|
-
const devPath = path_1.default.join(__dirname, '../src/ui/dist');
|
|
99
|
-
if (fs_1.default.existsSync(bundledPath)) {
|
|
100
|
-
log.debug(`Using bundled UI path: ${bundledPath}`);
|
|
101
|
-
return bundledPath;
|
|
102
|
-
}
|
|
103
|
-
log.debug(`Using development UI path: ${devPath}`);
|
|
104
|
-
return devPath;
|
|
105
|
-
};
|
|
106
|
-
exports.DIST_UI_PATH = resolveUiPath();
|
|
107
98
|
const NO_USER_DEV_SERVER_PORT = 0;
|
|
108
99
|
const setNoStoreHeaders = (res) => {
|
|
109
100
|
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
|
|
110
101
|
res.setHeader('Pragma', 'no-cache');
|
|
111
102
|
res.setHeader('Expires', '0');
|
|
112
103
|
};
|
|
113
|
-
const escapeScriptJson = (value) => JSON.stringify(value)
|
|
114
|
-
.replace(/</g, '\\u003c')
|
|
115
|
-
.replace(/\u2028/g, '\\u2028')
|
|
116
|
-
.replace(/\u2029/g, '\\u2029');
|
|
117
104
|
const injectRivetUiBootstrap = (html, bootstrap) => {
|
|
118
|
-
const script = `<script id="${RIVET_BOOTSTRAP_SCRIPT_ID}">window.__RIVET_BOOTSTRAP__=${escapeScriptJson(bootstrap)};</script>`;
|
|
105
|
+
const script = `<script id="${RIVET_BOOTSTRAP_SCRIPT_ID}">window.__RIVET_BOOTSTRAP__=${(0, scriptJson_1.escapeScriptJson)(bootstrap)};</script>`;
|
|
119
106
|
if (html.includes('</head>')) {
|
|
120
107
|
return html.replace('</head>', `${script}</head>`);
|
|
121
108
|
}
|
|
122
109
|
return `${script}${html}`;
|
|
123
110
|
};
|
|
124
111
|
exports.injectRivetUiBootstrap = injectRivetUiBootstrap;
|
|
125
|
-
const readRivetUiIndexHtml = () => fs_1.default.readFileSync(path_1.default.join(
|
|
112
|
+
const readRivetUiIndexHtml = () => fs_1.default.readFileSync(path_1.default.join(uiDistPath_1.DIST_UI_PATH, RIVET_UI_INDEX_FILENAME), 'utf8');
|
|
126
113
|
exports.readRivetUiIndexHtml = readRivetUiIndexHtml;
|
|
127
114
|
const sendInactiveVariantsEventStream = (req, res) => {
|
|
128
115
|
res.set({
|
|
@@ -366,15 +353,15 @@ const startServer = async (options) => {
|
|
|
366
353
|
const serve = express_1.default.static(directory, uiStaticOptions);
|
|
367
354
|
return (req, res, next) => isPreviewRequest(req) ? next() : serve(req, res, next);
|
|
368
355
|
};
|
|
369
|
-
app.use('/assets', serveEditorAssets(path_1.default.join(
|
|
370
|
-
app.use('/rivet/assets', serveEditorAssets(path_1.default.join(
|
|
371
|
-
app.use('/fonts', serveEditorAssets(path_1.default.join(
|
|
372
|
-
app.use('/rivet/fonts', serveEditorAssets(path_1.default.join(
|
|
356
|
+
app.use('/assets', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'assets')));
|
|
357
|
+
app.use('/rivet/assets', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'assets')));
|
|
358
|
+
app.use('/fonts', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'fonts')));
|
|
359
|
+
app.use('/rivet/fonts', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'fonts')));
|
|
373
360
|
app.get('/favicon.ico', (_req, res) => {
|
|
374
|
-
res.sendFile('favicon.ico', { root:
|
|
361
|
+
res.sendFile('favicon.ico', { root: uiDistPath_1.DIST_UI_PATH });
|
|
375
362
|
});
|
|
376
363
|
app.get('/rivet/favicon.ico', (_req, res) => {
|
|
377
|
-
res.sendFile('favicon.ico', { root:
|
|
364
|
+
res.sendFile('favicon.ico', { root: uiDistPath_1.DIST_UI_PATH });
|
|
378
365
|
});
|
|
379
366
|
app.get(/^\/rivet\/library(?:\/.*)?$/, (req, res) => {
|
|
380
367
|
const resolvedLibraryOrigin = options.resolveLibraryOrigin?.();
|
|
@@ -391,7 +378,7 @@ const startServer = async (options) => {
|
|
|
391
378
|
}
|
|
392
379
|
sendRivetUiIndex(req, res);
|
|
393
380
|
});
|
|
394
|
-
log.info(`Serving UI assets from: ${
|
|
381
|
+
log.info(`Serving UI assets from: ${uiDistPath_1.DIST_UI_PATH}`);
|
|
395
382
|
if (framework === 'static' && !hasUserDevServer) {
|
|
396
383
|
app.get('/', (req, res, next) => {
|
|
397
384
|
if (isPreviewRequest(req)) {
|
|
@@ -511,6 +498,7 @@ const startServer = async (options) => {
|
|
|
511
498
|
? (agentApplyMode ?? 'external')
|
|
512
499
|
: null,
|
|
513
500
|
projectPath: livePath,
|
|
501
|
+
projectName: options.resolveProjectName?.(livePath) ?? path_1.default.basename(livePath),
|
|
514
502
|
projectId: options.projectId ?? null,
|
|
515
503
|
libraryOrigin: options.resolveLibraryOrigin?.() ?? null,
|
|
516
504
|
});
|