rivet-design 0.11.6 → 0.11.7

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 (40) hide show
  1. package/dist/mcp/agent-variants/SessionStore.d.ts +39 -9
  2. package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
  3. package/dist/mcp/agent-variants/SessionStore.js +36 -16
  4. package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
  5. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +1 -1
  6. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
  7. package/dist/mcp/agent-variants/WorktreeOrchestrator.js +40 -20
  8. package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
  9. package/dist/mcp/agent-variants/contracts.d.ts +18 -2
  10. package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
  11. package/dist/mcp/agent-variants/contracts.js +6 -3
  12. package/dist/mcp/agent-variants/contracts.js.map +1 -1
  13. package/dist/mcp/agent-variants/createZeroToOneTool.d.ts.map +1 -1
  14. package/dist/mcp/agent-variants/createZeroToOneTool.js +26 -1
  15. package/dist/mcp/agent-variants/createZeroToOneTool.js.map +1 -1
  16. package/dist/mcp/agent-variants/designCritique.d.ts.map +1 -1
  17. package/dist/mcp/agent-variants/designCritique.js +57 -0
  18. package/dist/mcp/agent-variants/designCritique.js.map +1 -1
  19. package/dist/mcp/agent-variants/tools.d.ts +7 -0
  20. package/dist/mcp/agent-variants/tools.d.ts.map +1 -1
  21. package/dist/mcp/agent-variants/tools.js +40 -4
  22. package/dist/mcp/agent-variants/tools.js.map +1 -1
  23. package/dist/mcp/agent-variants/variantContext.d.ts +1 -0
  24. package/dist/mcp/agent-variants/variantContext.d.ts.map +1 -1
  25. package/dist/mcp/agent-variants/variantContext.js +3 -3
  26. package/dist/mcp/agent-variants/variantContext.js.map +1 -1
  27. package/dist/mcp/server.d.ts +9 -0
  28. package/dist/mcp/server.d.ts.map +1 -1
  29. package/dist/mcp/server.js +14 -4
  30. package/dist/mcp/server.js.map +1 -1
  31. package/dist/services/createAgentVariantsOrchestrator.d.ts +8 -0
  32. package/dist/services/createAgentVariantsOrchestrator.d.ts.map +1 -1
  33. package/dist/services/createAgentVariantsOrchestrator.js +18 -8
  34. package/dist/services/createAgentVariantsOrchestrator.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/ui/dist/assets/main-CtRINpOq.css +1 -0
  37. package/src/ui/dist/assets/main-DM4pFbJk.js +641 -0
  38. package/src/ui/dist/index.html +2 -2
  39. package/src/ui/dist/assets/main-DtQqp2Ey.js +0 -641
  40. package/src/ui/dist/assets/main-E5hevKg2.css +0 -1
@@ -42,7 +42,7 @@ const DESIGN_CONTEXT_VIEW_SEGMENT = 'view';
42
42
  // fast and legibly instead. Per-git-op hangs are already caught by simple-git's
43
43
  // block timeout in WorktreeManager; this is the cross-op backstop. Override via
44
44
  // env for unusually large repos.
45
- const DEFAULT_PROVISION_TIMEOUT_MS = 180_000;
45
+ const DEFAULT_PROVISION_TIMEOUT_MS = 540_000;
46
46
  const PROVISION_TIMEOUT_MS = (() => {
47
47
  const raw = process.env.RIVET_VARIANTS_PROVISION_TIMEOUT_MS;
48
48
  const parsed = raw ? Number.parseInt(raw, 10) : NaN;
@@ -188,10 +188,18 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
188
188
  if (!path_1.default.isAbsolute(assetSourceRoot)) {
189
189
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetSourceRoot must be an absolute path, got '${assetSourceRoot}'`);
190
190
  }
191
- if (!path_1.default.isAbsolute(entry.source)) {
192
- throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source must be an absolute path, got '${entry.source}'`);
193
- }
194
- const ext = path_1.default.extname(entry.source).toLowerCase();
191
+ // A relative source is resolved against the approved asset root. The
192
+ // agent-facing protocol requires the source to live under that root but not
193
+ // to be absolute, and the root path is internal to Rivet (a staged context
194
+ // bundle) so a relative name such as 'avatar.glb' is the natural, safe
195
+ // form. Every downstream guard (symlink, extension, within-root, sensitive
196
+ // segments) runs against this resolved absolute path, so the resolution
197
+ // cannot widen what is copyable: a relative `..` escape still fails the
198
+ // within-root check below.
199
+ const absoluteSource = path_1.default.isAbsolute(entry.source)
200
+ ? entry.source
201
+ : path_1.default.resolve(assetSourceRoot, entry.source);
202
+ const ext = path_1.default.extname(absoluteSource).toLowerCase();
195
203
  if (!ALLOWED_ASSET_EXTENSIONS.has(ext)) {
196
204
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source extension '${ext || '(none)'}' is not on the allowlist (got '${entry.source}'). Only inert media/font/document assets may be copied.`);
197
205
  }
@@ -201,7 +209,7 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
201
209
  // assetPlan entry is to name a concrete file.
202
210
  let lstat;
203
211
  try {
204
- lstat = fs_1.default.lstatSync(entry.source);
212
+ lstat = fs_1.default.lstatSync(absoluteSource);
205
213
  }
206
214
  catch {
207
215
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source not found on disk: ${entry.source}`);
@@ -217,7 +225,7 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
217
225
  // file kind on the resolved path.
218
226
  let resolvedSource;
219
227
  try {
220
- resolvedSource = fs_1.default.realpathSync(entry.source);
228
+ resolvedSource = fs_1.default.realpathSync(absoluteSource);
221
229
  }
222
230
  catch {
223
231
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source could not be resolved: ${entry.source}`);
@@ -233,21 +241,28 @@ function copyAssetIntoWorktree(worktreePath, entry, assetSourceRoot) {
233
241
  if (!resolvedStat.isFile()) {
234
242
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source resolved target must be a regular file: ${entry.source}`);
235
243
  }
236
- // Symlinked parent directory defense: even though we rejected a symlink
237
- // leaf and confirmed the resolved file is regular, an intermediate dir
238
- // could have been a symlink that quietly forwards into a sensitive
239
- // ancestor (e.g. `<asset-root>/avatar -> ~/.ssh`). Cross-check that
240
- // NEITHER the user-supplied path NOR its realpath traverses a known
241
- // sensitive segment such as `.ssh`, `.aws`, `credentials`, etc. Also
242
- // re-verify the extension on the resolved path so a `.glb` symlink
243
- // chain cannot smuggle in a `.json` realpath.
244
- if (hasSensitivePathSegment(entry.source) ||
245
- hasSensitivePathSegment(resolvedSource)) {
246
- throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source traverses a sensitive directory and is refused: ${entry.source}`);
247
- }
244
+ // Containment is the security boundary and must be checked before any
245
+ // sensitive-segment scan. The approved asset root is system-chosen and
246
+ // trusted (a staged context bundle), and its realpath can legitimately
247
+ // pass through a "sensitive" segment that is NOT agent-controlled — on
248
+ // macOS `fs.realpathSync(os.tmpdir())` resolves to `/private/var/folders/...`,
249
+ // so the temp-staged root contains `private`. A symlinked intermediate dir
250
+ // that forwards into a sensitive ancestor (e.g. `<asset-root>/avatar -> ~/.ssh`)
251
+ // pushes the realpath OUTSIDE the root and is rejected here.
248
252
  if (!isPathWithinRoot(resolvedSource, resolvedAssetSourceRoot)) {
249
253
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source must stay inside the approved asset root: ${entry.source}`);
250
254
  }
255
+ // Sensitive-segment defense, scoped to the agent-controlled portion BELOW
256
+ // the trusted root. Only this relative remainder is chosen by the agent's
257
+ // source plan, so a sensitive segment it introduces under the root (a real
258
+ // `<asset-root>/.ssh/key.glb`, or a within-root symlink that realpaths into
259
+ // one) is still refused, while the trusted root prefix is never scanned.
260
+ // `resolvedSource` is the fully symlink-resolved real path, so the scan
261
+ // covers what the file actually resolves to, not just its literal name.
262
+ const relativeResolvedSource = path_1.default.relative(resolvedAssetSourceRoot, resolvedSource);
263
+ if (hasSensitivePathSegment(relativeResolvedSource)) {
264
+ throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source traverses a sensitive directory and is refused: ${entry.source}`);
265
+ }
251
266
  const resolvedExt = path_1.default.extname(resolvedSource).toLowerCase();
252
267
  if (!ALLOWED_ASSET_EXTENSIONS.has(resolvedExt)) {
253
268
  throw new errors_1.AgentVariantsError('RUNTIME_VALIDATION_FAILED', `assetPlan.source resolved extension '${resolvedExt || '(none)'}' is not on the allowlist (resolved from '${entry.source}').`);
@@ -2532,7 +2547,12 @@ class AgentVariantsOrchestrator {
2532
2547
  overall: qa.dimensionScores?.overall ?? null,
2533
2548
  });
2534
2549
  this.emitChange();
2535
- return result;
2550
+ // Carry the requeue signal + critique so the tool layer can tell the agent
2551
+ // to re-lease and regenerate. The store result is an opaque
2552
+ // `waiting_for_results` (the variant is pending again); on its own that is
2553
+ // indistinguishable from a sibling still in flight, so the agent would
2554
+ // otherwise abandon the variant and the session would stall at ready:0.
2555
+ return { ...result, requeuedForRegeneration: true, qa };
2536
2556
  }
2537
2557
  async startVariantDevServer(args) {
2538
2558
  if (args.record.port !== undefined && args.record.devServerProcess) {