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.
- package/dist/mcp/agent-variants/SessionStore.d.ts +23 -0
- package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
- package/dist/mcp/agent-variants/SessionStore.js +71 -2
- package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +21 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.js +186 -131
- package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
- package/dist/mcp/agent-variants/contracts.d.ts +26 -2
- package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
- package/dist/mcp/agent-variants/contracts.js +16 -4
- package/dist/mcp/agent-variants/contracts.js.map +1 -1
- package/dist/mcp/agent-variants/runLabel.d.ts +18 -0
- package/dist/mcp/agent-variants/runLabel.d.ts.map +1 -0
- package/dist/mcp/agent-variants/runLabel.js +146 -0
- package/dist/mcp/agent-variants/runLabel.js.map +1 -0
- package/dist/mcp/agent-variants/tools.d.ts.map +1 -1
- package/dist/mcp/agent-variants/tools.js +14 -5
- package/dist/mcp/agent-variants/tools.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +0 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/routes/agentVariants.d.ts.map +1 -1
- package/dist/routes/agentVariants.js +27 -2
- package/dist/routes/agentVariants.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +12 -13
- package/dist/server.js.map +1 -1
- package/dist/services/VariantHistoryService.d.ts +5 -1
- package/dist/services/VariantHistoryService.d.ts.map +1 -1
- package/dist/services/VariantHistoryService.js +4 -0
- package/dist/services/VariantHistoryService.js.map +1 -1
- package/dist/utils/logger.d.ts +5 -5
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +27 -23
- package/dist/utils/logger.js.map +1 -1
- package/package.json +1 -1
- package/src/ui/dist/assets/main-COggU55U.js +645 -0
- package/src/ui/dist/assets/main-frxzIoK6.css +1 -0
- package/src/ui/dist/index.html +2 -2
- package/src/ui/dist/assets/main-C8QYh4jE.css +0 -1
- 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
|
|
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:
|
|
3219
|
-
--
|
|
3220
|
-
--
|
|
3221
|
-
--
|
|
3222
|
-
--
|
|
3223
|
-
--
|
|
3224
|
-
--
|
|
3225
|
-
--
|
|
3226
|
-
--
|
|
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
|
-
|
|
3234
|
-
|
|
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
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
padding: 40px 0;
|
|
3292
|
+
.page-shell {
|
|
3293
|
+
min-height: 100vh;
|
|
3294
|
+
padding: 22px 28px 56px;
|
|
3242
3295
|
}
|
|
3243
|
-
|
|
3296
|
+
.topbar {
|
|
3244
3297
|
display: flex;
|
|
3245
3298
|
align-items: center;
|
|
3246
3299
|
justify-content: space-between;
|
|
3247
|
-
|
|
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
|
-
.
|
|
3302
|
+
.brand {
|
|
3265
3303
|
display: inline-flex;
|
|
3266
|
-
|
|
3267
|
-
|
|
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
|
-
.
|
|
3307
|
+
.brand-logo {
|
|
3292
3308
|
display: block;
|
|
3309
|
+
width: 64px;
|
|
3310
|
+
height: auto;
|
|
3293
3311
|
}
|
|
3294
|
-
.
|
|
3295
|
-
|
|
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
|
|
3298
|
-
|
|
3299
|
-
|
|
3319
|
+
main {
|
|
3320
|
+
width: min(1120px, calc(100vw - 56px));
|
|
3321
|
+
margin: 0 auto;
|
|
3300
3322
|
}
|
|
3301
|
-
.
|
|
3323
|
+
.document {
|
|
3302
3324
|
overflow: hidden;
|
|
3303
|
-
border: 1px solid var(--
|
|
3304
|
-
border-radius:
|
|
3305
|
-
background:
|
|
3306
|
-
box-shadow: 0
|
|
3307
|
-
}
|
|
3308
|
-
.
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
font: 700
|
|
3316
|
-
letter-spacing: 0.
|
|
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
|
-
|
|
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.
|
|
3326
|
-
|
|
3327
|
-
|
|
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:
|
|
3335
|
-
.visual h2 { font-size: 1.
|
|
3336
|
-
.visual h3 { font-size:
|
|
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:
|
|
3341
|
-
font-size:
|
|
3342
|
-
line-height: 1.
|
|
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:
|
|
3402
|
+
border-left: 3px solid var(--primary);
|
|
3352
3403
|
padding-left: 14px;
|
|
3353
|
-
color: var(--
|
|
3404
|
+
color: var(--content-subtle);
|
|
3354
3405
|
}
|
|
3355
3406
|
.visual code {
|
|
3356
3407
|
border-radius: 6px;
|
|
3357
|
-
|
|
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:
|
|
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:
|
|
3367
|
-
color:
|
|
3368
|
-
padding:
|
|
3369
|
-
font: 0.78rem/1.55
|
|
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
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
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
|
-
<
|
|
3382
|
-
<header>
|
|
3383
|
-
<
|
|
3384
|
-
<div class="
|
|
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
|
-
<
|
|
3396
|
-
<article class="
|
|
3397
|
-
<div class="
|
|
3398
|
-
|
|
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
|
-
|
|
3401
|
-
|
|
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
|
-
|
|
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+(.+)$/);
|