rivet-design 0.10.3 → 0.10.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/mcp/agent-variants/SessionStore.d.ts +23 -0
  2. package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
  3. package/dist/mcp/agent-variants/SessionStore.js +71 -2
  4. package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
  5. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +21 -1
  6. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
  7. package/dist/mcp/agent-variants/WorktreeOrchestrator.js +186 -131
  8. package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
  9. package/dist/mcp/agent-variants/contracts.d.ts +26 -2
  10. package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
  11. package/dist/mcp/agent-variants/contracts.js +16 -4
  12. package/dist/mcp/agent-variants/contracts.js.map +1 -1
  13. package/dist/mcp/agent-variants/runLabel.d.ts +18 -0
  14. package/dist/mcp/agent-variants/runLabel.d.ts.map +1 -0
  15. package/dist/mcp/agent-variants/runLabel.js +146 -0
  16. package/dist/mcp/agent-variants/runLabel.js.map +1 -0
  17. package/dist/mcp/agent-variants/tools.d.ts.map +1 -1
  18. package/dist/mcp/agent-variants/tools.js +14 -5
  19. package/dist/mcp/agent-variants/tools.js.map +1 -1
  20. package/dist/mcp/server.d.ts.map +1 -1
  21. package/dist/mcp/server.js +0 -4
  22. package/dist/mcp/server.js.map +1 -1
  23. package/dist/routes/agentVariants.d.ts.map +1 -1
  24. package/dist/routes/agentVariants.js +27 -2
  25. package/dist/routes/agentVariants.js.map +1 -1
  26. package/dist/server.d.ts.map +1 -1
  27. package/dist/server.js +12 -13
  28. package/dist/server.js.map +1 -1
  29. package/dist/services/VariantHistoryService.d.ts +5 -1
  30. package/dist/services/VariantHistoryService.d.ts.map +1 -1
  31. package/dist/services/VariantHistoryService.js +4 -0
  32. package/dist/services/VariantHistoryService.js.map +1 -1
  33. package/dist/utils/logger.d.ts +5 -5
  34. package/dist/utils/logger.d.ts.map +1 -1
  35. package/dist/utils/logger.js +27 -23
  36. package/dist/utils/logger.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/ui/dist/assets/main-COggU55U.js +645 -0
  39. package/src/ui/dist/assets/main-frxzIoK6.css +1 -0
  40. package/src/ui/dist/index.html +2 -2
  41. package/src/ui/dist/assets/main-C8QYh4jE.css +0 -1
  42. package/src/ui/dist/assets/main-DshwLV4N.js +0 -645
@@ -691,7 +691,7 @@ class AgentVariantsOrchestrator {
691
691
  const artifact = findDesignContextArtifact(this.store.getProjectContext(sessionId), artifactId);
692
692
  return artifact?.content;
693
693
  }
694
- /** Build the raw-plus-rendered DesignMD document for an artifact link. */
694
+ /** Build the rendered DesignMD document for an artifact link. */
695
695
  getDesignContextViewerHtml(sessionId, artifactId) {
696
696
  const artifact = findDesignContextArtifact(this.store.getProjectContext(sessionId), artifactId);
697
697
  return artifact ? buildDesignContextViewerDocument(artifact) : undefined;
@@ -846,6 +846,7 @@ class AgentVariantsOrchestrator {
846
846
  count,
847
847
  target: args.target,
848
848
  projectContext,
849
+ runLabel: args.runLabel,
849
850
  });
850
851
  if (proposeResult.stage !== 'awaiting_briefs' ||
851
852
  !proposeResult.briefWorkItem) {
@@ -1115,6 +1116,39 @@ class AgentVariantsOrchestrator {
1115
1116
  alreadyTerminal: result.alreadyTerminal,
1116
1117
  };
1117
1118
  }
1119
+ /**
1120
+ * Remove a variant from the UI. Hides it from the active snapshot for good
1121
+ * (it's filtered out of progress/summary/terminal accounting too) while
1122
+ * retaining it in `.rivet/variants/` with status `removed` so the work is
1123
+ * kept, never rendered again. Mirrors `cancelVariant`'s shape; idempotent.
1124
+ */
1125
+ async removeVariant(args) {
1126
+ const result = this.store.removeWorkItem({
1127
+ sessionId: args.sessionId,
1128
+ workItemId: args.variantId,
1129
+ });
1130
+ this.telemetry.track('agent_variants.variant_removed', {
1131
+ source: 'mcp',
1132
+ sessionId: args.sessionId,
1133
+ variantId: args.variantId,
1134
+ finalStatus: result.finalStatus,
1135
+ sessionStage: result.sessionStage,
1136
+ alreadyRemoved: result.alreadyRemoved,
1137
+ });
1138
+ if (!result.alreadyRemoved) {
1139
+ void this.markPersistedVariantRemoved(args.sessionId, args.variantId).catch((err) => {
1140
+ log.warn(`markPersistedVariantRemoved failed for ${args.sessionId}/${args.variantId}`, err);
1141
+ });
1142
+ }
1143
+ this.emitChange();
1144
+ return {
1145
+ sessionId: args.sessionId,
1146
+ variantId: args.variantId,
1147
+ finalStatus: result.finalStatus,
1148
+ sessionStage: result.sessionStage,
1149
+ alreadyRemoved: result.alreadyRemoved,
1150
+ };
1151
+ }
1118
1152
  /**
1119
1153
  * User has reviewed the rendered variants in chat and picked one. Look up
1120
1154
  * the captured diff, build a VariantPickEnvelope, and enqueue to the
@@ -2223,6 +2257,7 @@ class AgentVariantsOrchestrator {
2223
2257
  label: input.briefLabel,
2224
2258
  brief: input.briefBody,
2225
2259
  sessionPrompt,
2260
+ runLabel: this.store.getRunLabel(args.sessionId),
2226
2261
  kind: 'diff',
2227
2262
  diff: args.diff,
2228
2263
  sourceDir,
@@ -2304,6 +2339,7 @@ class AgentVariantsOrchestrator {
2304
2339
  label: input.briefLabel,
2305
2340
  brief: input.briefBody,
2306
2341
  sessionPrompt,
2342
+ runLabel: this.store.getRunLabel(args.sessionId),
2307
2343
  kind: 'project-created',
2308
2344
  sourceDir,
2309
2345
  preview,
@@ -2388,6 +2424,22 @@ class AgentVariantsOrchestrator {
2388
2424
  status: 'cancelled',
2389
2425
  });
2390
2426
  }
2427
+ async markPersistedVariantRemoved(sessionId, variantId) {
2428
+ if (!this.store.hasSession(sessionId))
2429
+ return;
2430
+ const projectPath = await this.resolveHistoryProjectPath(sessionId);
2431
+ if (!projectPath)
2432
+ return;
2433
+ // No-ops (ENOENT) when the variant was never persisted — e.g. removing a
2434
+ // still-pending variant that produced no artifact. Completed variants have
2435
+ // a manifest, which flips to `removed` and is retained on disk.
2436
+ await this.variantHistory.markStatus({
2437
+ projectPath,
2438
+ sessionId,
2439
+ variantId,
2440
+ status: 'removed',
2441
+ });
2442
+ }
2391
2443
  /**
2392
2444
  * Resolve the project path that owns `.rivet/variants/` for a session.
2393
2445
  * Existing sessions: the user's project (via `resolveEnv`). Fresh sessions:
@@ -3205,8 +3257,7 @@ const buildDesignContextViewUrl = (sessionId, artifactId) => {
3205
3257
  };
3206
3258
  const buildDesignContextViewerDocument = (artifact) => {
3207
3259
  const title = `${artifact.label} DESIGN.md`;
3208
- const visualHtml = renderDesignMarkdown(artifact.content);
3209
- const rawMarkdown = escapeHtml(artifact.content);
3260
+ const visualHtml = renderDesignMarkdown(artifact.content, artifact.label);
3210
3261
  return `<!doctype html>
3211
3262
  <html lang="en">
3212
3263
  <head>
@@ -3215,131 +3266,131 @@ const buildDesignContextViewerDocument = (artifact) => {
3215
3266
  <title>${escapeHtml(title)}</title>
3216
3267
  <style>
3217
3268
  :root {
3218
- color-scheme: light;
3219
- --ink: #201b16;
3220
- --muted: #75695e;
3221
- --paper: #fbf7ef;
3222
- --panel: #fffdf8;
3223
- --rule: #eadfcf;
3224
- --accent: #e45d2f;
3225
- --accent-soft: #ffe0d3;
3226
- --code: #2a2521;
3269
+ color-scheme: dark;
3270
+ --font-main: 'Satoshi', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
3271
+ --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3272
+ --main: #1C1C20;
3273
+ --main-light: #1E1E22;
3274
+ --main-input: #2E2E2E;
3275
+ --main-border: #232328;
3276
+ --main-hover: #404040;
3277
+ --content: #ffffff;
3278
+ --content-muted: #d1d5db;
3279
+ --content-subtle: #9ca3af;
3280
+ --divider: #4b5563;
3281
+ --primary: #FF3300;
3282
+ --primary-border: #ff6b35;
3227
3283
  }
3228
3284
  * { box-sizing: border-box; }
3229
3285
  body {
3230
3286
  margin: 0;
3231
3287
  min-height: 100vh;
3232
- background:
3233
- radial-gradient(circle at top left, rgba(228, 93, 47, 0.18), transparent 36rem),
3234
- linear-gradient(135deg, #fbf7ef 0%, #f2eadc 100%);
3235
- color: var(--ink);
3236
- font-family: ui-serif, Georgia, Cambria, "Times New Roman", serif;
3288
+ background: var(--main);
3289
+ color: var(--content);
3290
+ font-family: var(--font-main);
3237
3291
  }
3238
- main {
3239
- width: min(1440px, calc(100vw - 40px));
3240
- margin: 0 auto;
3241
- padding: 40px 0;
3292
+ .page-shell {
3293
+ min-height: 100vh;
3294
+ padding: 22px 28px 56px;
3242
3295
  }
3243
- header {
3296
+ .topbar {
3244
3297
  display: flex;
3245
3298
  align-items: center;
3246
3299
  justify-content: space-between;
3247
- gap: 24px;
3248
- margin-bottom: 24px;
3249
- border-bottom: 1px solid var(--rule);
3250
- padding-bottom: 18px;
3251
- }
3252
- h1 {
3253
- margin: 0;
3254
- max-width: 780px;
3255
- font-size: clamp(2rem, 5vw, 4.5rem);
3256
- letter-spacing: -0.06em;
3257
- line-height: 0.92;
3258
- }
3259
- .mode-input {
3260
- position: absolute;
3261
- opacity: 0;
3262
- pointer-events: none;
3300
+ margin-bottom: 28px;
3263
3301
  }
3264
- .mode-toggle {
3302
+ .brand {
3265
3303
  display: inline-flex;
3266
- flex-shrink: 0;
3267
- gap: 4px;
3268
- border: 1px solid var(--rule);
3269
- border-radius: 999px;
3270
- background: rgba(255, 253, 248, 0.72);
3271
- padding: 4px;
3272
- box-shadow: 0 12px 30px rgba(61, 44, 26, 0.08);
3273
- }
3274
- .mode-toggle label {
3275
- position: relative;
3276
- cursor: pointer;
3277
- border-radius: 999px;
3278
- padding: 8px 14px;
3279
- color: var(--muted);
3280
- font: 600 0.74rem/1.2 ui-sans-serif, system-ui, sans-serif;
3281
- letter-spacing: 0.12em;
3282
- text-transform: uppercase;
3283
- transition:
3284
- background 160ms ease,
3285
- color 160ms ease;
3286
- }
3287
- .mode-toggle label:has(input:checked) {
3288
- background: var(--ink);
3289
- color: var(--paper);
3304
+ align-items: center;
3305
+ min-height: 28px;
3290
3306
  }
3291
- .viewer {
3307
+ .brand-logo {
3292
3308
  display: block;
3309
+ width: 64px;
3310
+ height: auto;
3293
3311
  }
3294
- .viewer-panel {
3295
- display: none;
3312
+ .avatar {
3313
+ width: 28px;
3314
+ height: 28px;
3315
+ border: 1px solid var(--main-border);
3316
+ border-radius: 8px;
3317
+ background: var(--main-light);
3296
3318
  }
3297
- main:has(#designmd-visual-mode:checked) .visual-panel,
3298
- main:has(#designmd-raw-mode:checked) .raw-panel {
3299
- display: block;
3319
+ main {
3320
+ width: min(1120px, calc(100vw - 56px));
3321
+ margin: 0 auto;
3300
3322
  }
3301
- .panel {
3323
+ .document {
3302
3324
  overflow: hidden;
3303
- border: 1px solid var(--rule);
3304
- border-radius: 18px;
3305
- background: color-mix(in srgb, var(--panel) 92%, white);
3306
- box-shadow: 0 20px 60px rgba(61, 44, 26, 0.12);
3307
- }
3308
- .panel-title {
3309
- display: flex;
3310
- align-items: center;
3311
- justify-content: space-between;
3312
- border-bottom: 1px solid var(--rule);
3313
- padding: 12px 16px;
3314
- color: var(--muted);
3315
- font: 700 0.72rem/1 ui-sans-serif, system-ui, sans-serif;
3316
- letter-spacing: 0.12em;
3325
+ border: 1px solid var(--main-border);
3326
+ border-radius: 22px;
3327
+ background: var(--main-light);
3328
+ box-shadow: 0 18px 60px rgb(0 0 0 / 18%);
3329
+ }
3330
+ .document-title {
3331
+ padding: 42px 46px 32px;
3332
+ }
3333
+ .eyebrow {
3334
+ margin: 0 0 14px;
3335
+ color: var(--content-subtle);
3336
+ font-size: 0.68rem;
3337
+ font-weight: 700;
3338
+ letter-spacing: 0.16em;
3317
3339
  text-transform: uppercase;
3318
3340
  }
3341
+ .file-title {
3342
+ margin: 0;
3343
+ color: var(--content);
3344
+ font-size: clamp(2.35rem, 6vw, 4.9rem);
3345
+ font-weight: 600;
3346
+ letter-spacing: -0.07em;
3347
+ line-height: 0.94;
3348
+ }
3319
3349
  .visual {
3320
- padding: 24px;
3350
+ border-top: 1px solid var(--main-border);
3351
+ max-width: none;
3352
+ margin: 0 auto;
3353
+ padding: 36px 46px 48px;
3354
+ }
3355
+ .visual-inner {
3356
+ max-width: 720px;
3357
+ margin: 0 auto;
3321
3358
  }
3322
3359
  .visual h1,
3323
3360
  .visual h2,
3324
3361
  .visual h3 {
3325
- margin: 1.3em 0 0.45em;
3326
- letter-spacing: -0.04em;
3327
- line-height: 1;
3362
+ margin: 1.2em 0 0.4em;
3363
+ color: var(--content);
3364
+ font-weight: 600;
3365
+ letter-spacing: -0.02em;
3366
+ line-height: 1.15;
3328
3367
  }
3329
3368
  .visual h1:first-child,
3330
3369
  .visual h2:first-child,
3331
3370
  .visual h3:first-child {
3332
3371
  margin-top: 0;
3333
3372
  }
3334
- .visual h1 { font-size: 2.25rem; }
3335
- .visual h2 { font-size: 1.6rem; }
3336
- .visual h3 { font-size: 1.18rem; }
3373
+ .visual h1 { font-size: 1.25rem; }
3374
+ .visual h2 { font-size: 1.1rem; }
3375
+ .visual h3 { font-size: 1rem; }
3376
+ .visual h2 + p,
3377
+ .visual h2 + ul {
3378
+ border-left: 1px solid var(--main-border);
3379
+ padding-left: 14px;
3380
+ }
3337
3381
  .visual p,
3338
3382
  .visual li,
3339
3383
  .visual blockquote {
3340
- color: #3d342c;
3341
- font-size: 1rem;
3342
- line-height: 1.62;
3384
+ color: var(--content-muted);
3385
+ font-size: 0.88rem;
3386
+ line-height: 1.6;
3387
+ }
3388
+ .visual strong {
3389
+ color: var(--content);
3390
+ font-weight: 650;
3391
+ }
3392
+ .visual a {
3393
+ color: var(--primary-border);
3343
3394
  }
3344
3395
  .visual ul {
3345
3396
  display: grid;
@@ -3348,71 +3399,67 @@ const buildDesignContextViewerDocument = (artifact) => {
3348
3399
  }
3349
3400
  .visual blockquote {
3350
3401
  margin: 18px 0;
3351
- border-left: 4px solid var(--accent);
3402
+ border-left: 3px solid var(--primary);
3352
3403
  padding-left: 14px;
3353
- color: var(--muted);
3404
+ color: var(--content-subtle);
3354
3405
  }
3355
3406
  .visual code {
3356
3407
  border-radius: 6px;
3357
- background: var(--accent-soft);
3408
+ border: 1px solid var(--main-border);
3409
+ background: var(--main-input);
3410
+ color: var(--content);
3358
3411
  padding: 0.12rem 0.34rem;
3359
- font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3412
+ font-family: var(--font-mono);
3360
3413
  font-size: 0.92em;
3361
3414
  }
3362
3415
  pre {
3363
3416
  margin: 0;
3364
- max-height: calc(100vh - 190px);
3365
3417
  overflow: auto;
3366
- background: #181512;
3367
- color: #f9ead7;
3368
- padding: 20px;
3369
- font: 0.78rem/1.55 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3418
+ background: var(--main);
3419
+ color: var(--content-muted);
3420
+ padding: 16px;
3421
+ font: 0.78rem/1.55 var(--font-mono);
3370
3422
  white-space: pre-wrap;
3371
3423
  word-break: break-word;
3372
3424
  }
3373
3425
  @media (max-width: 900px) {
3374
- main { width: min(100vw - 24px, 760px); padding: 24px 0; }
3375
- header { align-items: start; flex-direction: column; }
3376
- pre { max-height: 520px; }
3426
+ .page-shell { padding: 18px 12px 34px; }
3427
+ .topbar { margin-bottom: 18px; padding: 0 4px; }
3428
+ main { width: min(100vw - 24px, 760px); }
3429
+ .document { border-radius: 18px; }
3430
+ .document-title { padding: 30px 24px 24px; }
3431
+ .file-title { font-size: clamp(2rem, 12vw, 3.6rem); }
3432
+ .visual { padding: 26px 24px 34px; }
3377
3433
  }
3378
3434
  </style>
3379
3435
  </head>
3380
3436
  <body>
3381
- <main>
3382
- <header>
3383
- <h1>${escapeHtml(title)}</h1>
3384
- <div class="mode-toggle" aria-label="DesignMD view mode">
3385
- <label>
3386
- <input class="mode-input" type="radio" name="designmd-view-mode" id="designmd-visual-mode" checked />
3387
- <span>Visual</span>
3388
- </label>
3389
- <label>
3390
- <input class="mode-input" type="radio" name="designmd-view-mode" id="designmd-raw-mode" />
3391
- <span>Raw</span>
3392
- </label>
3393
- </div>
3437
+ <div class="page-shell">
3438
+ <header class="topbar" aria-label="Rivet">
3439
+ <div class="brand"><img class="brand-logo" src="/assets/logo.png" alt="Rivet" /></div>
3440
+ <div class="avatar" aria-hidden="true"></div>
3394
3441
  </header>
3395
- <section class="viewer" aria-label="DesignMD artifact">
3396
- <article class="panel viewer-panel visual-panel" id="designmd-visual">
3397
- <div class="panel-title"><span>Visual</span><span>Rendered DESIGN.md</span></div>
3398
- <div class="visual">${visualHtml}</div>
3442
+ <main>
3443
+ <article class="document" id="designmd-visual" aria-label="DesignMD artifact">
3444
+ <div class="document-title">
3445
+ <p class="eyebrow">Design Context</p>
3446
+ <h1 class="file-title">${escapeHtml(title)}</h1>
3447
+ </div>
3448
+ <div class="visual"><div class="visual-inner">${visualHtml}</div></div>
3399
3449
  </article>
3400
- <article class="panel viewer-panel raw-panel" id="designmd-raw">
3401
- <div class="panel-title"><span>Raw</span><span>Markdown source</span></div>
3402
- <pre>${rawMarkdown}</pre>
3403
- </article>
3404
- </section>
3405
- </main>
3450
+ </main>
3451
+ </div>
3406
3452
  </body>
3407
3453
  </html>`;
3408
3454
  };
3409
- const renderDesignMarkdown = (markdown) => {
3455
+ const renderDesignMarkdown = (markdown, artifactLabel) => {
3410
3456
  const lines = markdown.replace(/\r\n/g, '\n').split('\n');
3411
3457
  const output = [];
3412
3458
  const paragraph = [];
3413
3459
  const listItems = [];
3414
3460
  const codeLines = [];
3415
3461
  let isCodeBlock = false;
3462
+ let skippedFirstH1 = false;
3416
3463
  const flushParagraph = () => {
3417
3464
  if (paragraph.length === 0)
3418
3465
  return;
@@ -3464,7 +3511,15 @@ const renderDesignMarkdown = (markdown) => {
3464
3511
  flushParagraph();
3465
3512
  flushList();
3466
3513
  const level = Math.min(headingMatch[1].length, 3);
3467
- output.push(`<h${level}>${renderInlineMarkdown(headingMatch[2])}</h${level}>`);
3514
+ const headingText = headingMatch[2].trim();
3515
+ const isDuplicateTitle = headingText === artifactLabel ||
3516
+ headingText === `${artifactLabel} DESIGN.md`;
3517
+ // The viewer header already renders the artifact title.
3518
+ if (level === 1 && !skippedFirstH1 && isDuplicateTitle) {
3519
+ skippedFirstH1 = true;
3520
+ return;
3521
+ }
3522
+ output.push(`<h${level}>${renderInlineMarkdown(headingText)}</h${level}>`);
3468
3523
  return;
3469
3524
  }
3470
3525
  const listMatch = trimmed.match(/^[-*]\s+(.+)$/);