rivet-design 0.10.3 → 0.10.5

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 (43) hide show
  1. package/dist/mcp/agent-variants/SessionStore.d.ts +38 -0
  2. package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
  3. package/dist/mcp/agent-variants/SessionStore.js +89 -2
  4. package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
  5. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +39 -1
  6. package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
  7. package/dist/mcp/agent-variants/WorktreeOrchestrator.js +234 -131
  8. package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
  9. package/dist/mcp/agent-variants/contracts.d.ts +29 -2
  10. package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
  11. package/dist/mcp/agent-variants/contracts.js +17 -5
  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 +11 -0
  21. package/dist/mcp/server.d.ts.map +1 -1
  22. package/dist/mcp/server.js +33 -5
  23. package/dist/mcp/server.js.map +1 -1
  24. package/dist/routes/agentVariants.d.ts.map +1 -1
  25. package/dist/routes/agentVariants.js +125 -2
  26. package/dist/routes/agentVariants.js.map +1 -1
  27. package/dist/server.d.ts.map +1 -1
  28. package/dist/server.js +28 -13
  29. package/dist/server.js.map +1 -1
  30. package/dist/services/VariantHistoryService.d.ts +20 -1
  31. package/dist/services/VariantHistoryService.d.ts.map +1 -1
  32. package/dist/services/VariantHistoryService.js +34 -0
  33. package/dist/services/VariantHistoryService.js.map +1 -1
  34. package/dist/utils/logger.d.ts +5 -5
  35. package/dist/utils/logger.d.ts.map +1 -1
  36. package/dist/utils/logger.js +27 -23
  37. package/dist/utils/logger.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/ui/dist/assets/main-CioUvt6B.css +1 -0
  40. package/src/ui/dist/assets/main-wU_rUu3_.js +646 -0
  41. package/src/ui/dist/index.html +2 -2
  42. package/src/ui/dist/assets/main-C8QYh4jE.css +0 -1
  43. 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,71 @@ 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
+ }
1152
+ /**
1153
+ * Rename a variant's user-visible title. Patches the in-memory work item so
1154
+ * the next snapshot carries the new label, persists it to the variant's
1155
+ * `.rivet/variants/` manifest (best-effort — a never-persisted variant simply
1156
+ * skips the disk write), and pushes the updated snapshot over SSE. Mirrors
1157
+ * `removeVariant`'s shape.
1158
+ */
1159
+ async renameVariant(args) {
1160
+ const result = this.store.renameWorkItem({
1161
+ sessionId: args.sessionId,
1162
+ workItemId: args.variantId,
1163
+ label: args.label,
1164
+ });
1165
+ this.telemetry.track('agent_variants.variant_renamed', {
1166
+ source: 'mcp',
1167
+ sessionId: args.sessionId,
1168
+ variantId: args.variantId,
1169
+ // Telemetry policy: never the raw agent/user label text, only its length.
1170
+ labelLength: args.label.length,
1171
+ sessionStage: result.sessionStage,
1172
+ });
1173
+ void this.markPersistedVariantRenamed(args.sessionId, args.variantId, args.label).catch((err) => {
1174
+ log.warn(`markPersistedVariantRenamed failed for ${args.sessionId}/${args.variantId}`, err);
1175
+ });
1176
+ this.emitChange();
1177
+ return {
1178
+ sessionId: args.sessionId,
1179
+ variantId: args.variantId,
1180
+ label: result.label,
1181
+ sessionStage: result.sessionStage,
1182
+ };
1183
+ }
1118
1184
  /**
1119
1185
  * User has reviewed the rendered variants in chat and picked one. Look up
1120
1186
  * the captured diff, build a VariantPickEnvelope, and enqueue to the
@@ -2223,6 +2289,7 @@ class AgentVariantsOrchestrator {
2223
2289
  label: input.briefLabel,
2224
2290
  brief: input.briefBody,
2225
2291
  sessionPrompt,
2292
+ runLabel: this.store.getRunLabel(args.sessionId),
2226
2293
  kind: 'diff',
2227
2294
  diff: args.diff,
2228
2295
  sourceDir,
@@ -2304,6 +2371,7 @@ class AgentVariantsOrchestrator {
2304
2371
  label: input.briefLabel,
2305
2372
  brief: input.briefBody,
2306
2373
  sessionPrompt,
2374
+ runLabel: this.store.getRunLabel(args.sessionId),
2307
2375
  kind: 'project-created',
2308
2376
  sourceDir,
2309
2377
  preview,
@@ -2388,6 +2456,38 @@ class AgentVariantsOrchestrator {
2388
2456
  status: 'cancelled',
2389
2457
  });
2390
2458
  }
2459
+ async markPersistedVariantRemoved(sessionId, variantId) {
2460
+ if (!this.store.hasSession(sessionId))
2461
+ return;
2462
+ const projectPath = await this.resolveHistoryProjectPath(sessionId);
2463
+ if (!projectPath)
2464
+ return;
2465
+ // No-ops (ENOENT) when the variant was never persisted — e.g. removing a
2466
+ // still-pending variant that produced no artifact. Completed variants have
2467
+ // a manifest, which flips to `removed` and is retained on disk.
2468
+ await this.variantHistory.markStatus({
2469
+ projectPath,
2470
+ sessionId,
2471
+ variantId,
2472
+ status: 'removed',
2473
+ });
2474
+ }
2475
+ async markPersistedVariantRenamed(sessionId, variantId, label) {
2476
+ if (!this.store.hasSession(sessionId))
2477
+ return;
2478
+ const projectPath = await this.resolveHistoryProjectPath(sessionId);
2479
+ if (!projectPath)
2480
+ return;
2481
+ // No-ops (ENOENT) when the variant has no manifest yet — e.g. renaming a
2482
+ // still-generating direction before its artifact lands. The in-memory
2483
+ // label still updates; the disk copy catches up when the variant persists.
2484
+ await this.variantHistory.renameVariant({
2485
+ projectPath,
2486
+ sessionId,
2487
+ variantId,
2488
+ label,
2489
+ });
2490
+ }
2391
2491
  /**
2392
2492
  * Resolve the project path that owns `.rivet/variants/` for a session.
2393
2493
  * Existing sessions: the user's project (via `resolveEnv`). Fresh sessions:
@@ -3205,8 +3305,7 @@ const buildDesignContextViewUrl = (sessionId, artifactId) => {
3205
3305
  };
3206
3306
  const buildDesignContextViewerDocument = (artifact) => {
3207
3307
  const title = `${artifact.label} DESIGN.md`;
3208
- const visualHtml = renderDesignMarkdown(artifact.content);
3209
- const rawMarkdown = escapeHtml(artifact.content);
3308
+ const visualHtml = renderDesignMarkdown(artifact.content, artifact.label);
3210
3309
  return `<!doctype html>
3211
3310
  <html lang="en">
3212
3311
  <head>
@@ -3215,131 +3314,131 @@ const buildDesignContextViewerDocument = (artifact) => {
3215
3314
  <title>${escapeHtml(title)}</title>
3216
3315
  <style>
3217
3316
  :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;
3317
+ color-scheme: dark;
3318
+ --font-main: 'Satoshi', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
3319
+ --font-mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3320
+ --main: #1C1C20;
3321
+ --main-light: #1E1E22;
3322
+ --main-input: #2E2E2E;
3323
+ --main-border: #232328;
3324
+ --main-hover: #404040;
3325
+ --content: #ffffff;
3326
+ --content-muted: #d1d5db;
3327
+ --content-subtle: #9ca3af;
3328
+ --divider: #4b5563;
3329
+ --primary: #FF3300;
3330
+ --primary-border: #ff6b35;
3227
3331
  }
3228
3332
  * { box-sizing: border-box; }
3229
3333
  body {
3230
3334
  margin: 0;
3231
3335
  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;
3336
+ background: var(--main);
3337
+ color: var(--content);
3338
+ font-family: var(--font-main);
3237
3339
  }
3238
- main {
3239
- width: min(1440px, calc(100vw - 40px));
3240
- margin: 0 auto;
3241
- padding: 40px 0;
3340
+ .page-shell {
3341
+ min-height: 100vh;
3342
+ padding: 22px 28px 56px;
3242
3343
  }
3243
- header {
3344
+ .topbar {
3244
3345
  display: flex;
3245
3346
  align-items: center;
3246
3347
  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;
3348
+ margin-bottom: 28px;
3263
3349
  }
3264
- .mode-toggle {
3350
+ .brand {
3265
3351
  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);
3352
+ align-items: center;
3353
+ min-height: 28px;
3290
3354
  }
3291
- .viewer {
3355
+ .brand-logo {
3292
3356
  display: block;
3357
+ width: 64px;
3358
+ height: auto;
3293
3359
  }
3294
- .viewer-panel {
3295
- display: none;
3360
+ .avatar {
3361
+ width: 28px;
3362
+ height: 28px;
3363
+ border: 1px solid var(--main-border);
3364
+ border-radius: 8px;
3365
+ background: var(--main-light);
3296
3366
  }
3297
- main:has(#designmd-visual-mode:checked) .visual-panel,
3298
- main:has(#designmd-raw-mode:checked) .raw-panel {
3299
- display: block;
3367
+ main {
3368
+ width: min(1120px, calc(100vw - 56px));
3369
+ margin: 0 auto;
3300
3370
  }
3301
- .panel {
3371
+ .document {
3302
3372
  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;
3373
+ border: 1px solid var(--main-border);
3374
+ border-radius: 22px;
3375
+ background: var(--main-light);
3376
+ box-shadow: 0 18px 60px rgb(0 0 0 / 18%);
3377
+ }
3378
+ .document-title {
3379
+ padding: 42px 46px 32px;
3380
+ }
3381
+ .eyebrow {
3382
+ margin: 0 0 14px;
3383
+ color: var(--content-subtle);
3384
+ font-size: 0.68rem;
3385
+ font-weight: 700;
3386
+ letter-spacing: 0.16em;
3317
3387
  text-transform: uppercase;
3318
3388
  }
3389
+ .file-title {
3390
+ margin: 0;
3391
+ color: var(--content);
3392
+ font-size: clamp(2.35rem, 6vw, 4.9rem);
3393
+ font-weight: 600;
3394
+ letter-spacing: -0.07em;
3395
+ line-height: 0.94;
3396
+ }
3319
3397
  .visual {
3320
- padding: 24px;
3398
+ border-top: 1px solid var(--main-border);
3399
+ max-width: none;
3400
+ margin: 0 auto;
3401
+ padding: 36px 46px 48px;
3402
+ }
3403
+ .visual-inner {
3404
+ max-width: 720px;
3405
+ margin: 0 auto;
3321
3406
  }
3322
3407
  .visual h1,
3323
3408
  .visual h2,
3324
3409
  .visual h3 {
3325
- margin: 1.3em 0 0.45em;
3326
- letter-spacing: -0.04em;
3327
- line-height: 1;
3410
+ margin: 1.2em 0 0.4em;
3411
+ color: var(--content);
3412
+ font-weight: 600;
3413
+ letter-spacing: -0.02em;
3414
+ line-height: 1.15;
3328
3415
  }
3329
3416
  .visual h1:first-child,
3330
3417
  .visual h2:first-child,
3331
3418
  .visual h3:first-child {
3332
3419
  margin-top: 0;
3333
3420
  }
3334
- .visual h1 { font-size: 2.25rem; }
3335
- .visual h2 { font-size: 1.6rem; }
3336
- .visual h3 { font-size: 1.18rem; }
3421
+ .visual h1 { font-size: 1.25rem; }
3422
+ .visual h2 { font-size: 1.1rem; }
3423
+ .visual h3 { font-size: 1rem; }
3424
+ .visual h2 + p,
3425
+ .visual h2 + ul {
3426
+ border-left: 1px solid var(--main-border);
3427
+ padding-left: 14px;
3428
+ }
3337
3429
  .visual p,
3338
3430
  .visual li,
3339
3431
  .visual blockquote {
3340
- color: #3d342c;
3341
- font-size: 1rem;
3342
- line-height: 1.62;
3432
+ color: var(--content-muted);
3433
+ font-size: 0.88rem;
3434
+ line-height: 1.6;
3435
+ }
3436
+ .visual strong {
3437
+ color: var(--content);
3438
+ font-weight: 650;
3439
+ }
3440
+ .visual a {
3441
+ color: var(--primary-border);
3343
3442
  }
3344
3443
  .visual ul {
3345
3444
  display: grid;
@@ -3348,71 +3447,67 @@ const buildDesignContextViewerDocument = (artifact) => {
3348
3447
  }
3349
3448
  .visual blockquote {
3350
3449
  margin: 18px 0;
3351
- border-left: 4px solid var(--accent);
3450
+ border-left: 3px solid var(--primary);
3352
3451
  padding-left: 14px;
3353
- color: var(--muted);
3452
+ color: var(--content-subtle);
3354
3453
  }
3355
3454
  .visual code {
3356
3455
  border-radius: 6px;
3357
- background: var(--accent-soft);
3456
+ border: 1px solid var(--main-border);
3457
+ background: var(--main-input);
3458
+ color: var(--content);
3358
3459
  padding: 0.12rem 0.34rem;
3359
- font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3460
+ font-family: var(--font-mono);
3360
3461
  font-size: 0.92em;
3361
3462
  }
3362
3463
  pre {
3363
3464
  margin: 0;
3364
- max-height: calc(100vh - 190px);
3365
3465
  overflow: auto;
3366
- background: #181512;
3367
- color: #f9ead7;
3368
- padding: 20px;
3369
- font: 0.78rem/1.55 ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
3466
+ background: var(--main);
3467
+ color: var(--content-muted);
3468
+ padding: 16px;
3469
+ font: 0.78rem/1.55 var(--font-mono);
3370
3470
  white-space: pre-wrap;
3371
3471
  word-break: break-word;
3372
3472
  }
3373
3473
  @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; }
3474
+ .page-shell { padding: 18px 12px 34px; }
3475
+ .topbar { margin-bottom: 18px; padding: 0 4px; }
3476
+ main { width: min(100vw - 24px, 760px); }
3477
+ .document { border-radius: 18px; }
3478
+ .document-title { padding: 30px 24px 24px; }
3479
+ .file-title { font-size: clamp(2rem, 12vw, 3.6rem); }
3480
+ .visual { padding: 26px 24px 34px; }
3377
3481
  }
3378
3482
  </style>
3379
3483
  </head>
3380
3484
  <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>
3485
+ <div class="page-shell">
3486
+ <header class="topbar" aria-label="Rivet">
3487
+ <div class="brand"><img class="brand-logo" src="/assets/logo.png" alt="Rivet" /></div>
3488
+ <div class="avatar" aria-hidden="true"></div>
3394
3489
  </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>
3399
- </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>
3490
+ <main>
3491
+ <article class="document" id="designmd-visual" aria-label="DesignMD artifact">
3492
+ <div class="document-title">
3493
+ <p class="eyebrow">Design Context</p>
3494
+ <h1 class="file-title">${escapeHtml(title)}</h1>
3495
+ </div>
3496
+ <div class="visual"><div class="visual-inner">${visualHtml}</div></div>
3403
3497
  </article>
3404
- </section>
3405
- </main>
3498
+ </main>
3499
+ </div>
3406
3500
  </body>
3407
3501
  </html>`;
3408
3502
  };
3409
- const renderDesignMarkdown = (markdown) => {
3503
+ const renderDesignMarkdown = (markdown, artifactLabel) => {
3410
3504
  const lines = markdown.replace(/\r\n/g, '\n').split('\n');
3411
3505
  const output = [];
3412
3506
  const paragraph = [];
3413
3507
  const listItems = [];
3414
3508
  const codeLines = [];
3415
3509
  let isCodeBlock = false;
3510
+ let skippedFirstH1 = false;
3416
3511
  const flushParagraph = () => {
3417
3512
  if (paragraph.length === 0)
3418
3513
  return;
@@ -3464,7 +3559,15 @@ const renderDesignMarkdown = (markdown) => {
3464
3559
  flushParagraph();
3465
3560
  flushList();
3466
3561
  const level = Math.min(headingMatch[1].length, 3);
3467
- output.push(`<h${level}>${renderInlineMarkdown(headingMatch[2])}</h${level}>`);
3562
+ const headingText = headingMatch[2].trim();
3563
+ const isDuplicateTitle = headingText === artifactLabel ||
3564
+ headingText === `${artifactLabel} DESIGN.md`;
3565
+ // The viewer header already renders the artifact title.
3566
+ if (level === 1 && !skippedFirstH1 && isDuplicateTitle) {
3567
+ skippedFirstH1 = true;
3568
+ return;
3569
+ }
3570
+ output.push(`<h${level}>${renderInlineMarkdown(headingText)}</h${level}>`);
3468
3571
  return;
3469
3572
  }
3470
3573
  const listMatch = trimmed.match(/^[-*]\s+(.+)$/);