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.
- package/dist/mcp/agent-variants/SessionStore.d.ts +38 -0
- package/dist/mcp/agent-variants/SessionStore.d.ts.map +1 -1
- package/dist/mcp/agent-variants/SessionStore.js +89 -2
- package/dist/mcp/agent-variants/SessionStore.js.map +1 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts +39 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.d.ts.map +1 -1
- package/dist/mcp/agent-variants/WorktreeOrchestrator.js +234 -131
- package/dist/mcp/agent-variants/WorktreeOrchestrator.js.map +1 -1
- package/dist/mcp/agent-variants/contracts.d.ts +29 -2
- package/dist/mcp/agent-variants/contracts.d.ts.map +1 -1
- package/dist/mcp/agent-variants/contracts.js +17 -5
- 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 +11 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +33 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/routes/agentVariants.d.ts.map +1 -1
- package/dist/routes/agentVariants.js +125 -2
- package/dist/routes/agentVariants.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +28 -13
- package/dist/server.js.map +1 -1
- package/dist/services/VariantHistoryService.d.ts +20 -1
- package/dist/services/VariantHistoryService.d.ts.map +1 -1
- package/dist/services/VariantHistoryService.js +34 -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-CioUvt6B.css +1 -0
- package/src/ui/dist/assets/main-wU_rUu3_.js +646 -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,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:
|
|
3219
|
-
--
|
|
3220
|
-
--
|
|
3221
|
-
--
|
|
3222
|
-
--
|
|
3223
|
-
--
|
|
3224
|
-
--
|
|
3225
|
-
--
|
|
3226
|
-
--
|
|
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
|
-
|
|
3234
|
-
|
|
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
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
padding: 40px 0;
|
|
3340
|
+
.page-shell {
|
|
3341
|
+
min-height: 100vh;
|
|
3342
|
+
padding: 22px 28px 56px;
|
|
3242
3343
|
}
|
|
3243
|
-
|
|
3344
|
+
.topbar {
|
|
3244
3345
|
display: flex;
|
|
3245
3346
|
align-items: center;
|
|
3246
3347
|
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;
|
|
3348
|
+
margin-bottom: 28px;
|
|
3263
3349
|
}
|
|
3264
|
-
.
|
|
3350
|
+
.brand {
|
|
3265
3351
|
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);
|
|
3352
|
+
align-items: center;
|
|
3353
|
+
min-height: 28px;
|
|
3290
3354
|
}
|
|
3291
|
-
.
|
|
3355
|
+
.brand-logo {
|
|
3292
3356
|
display: block;
|
|
3357
|
+
width: 64px;
|
|
3358
|
+
height: auto;
|
|
3293
3359
|
}
|
|
3294
|
-
.
|
|
3295
|
-
|
|
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
|
|
3298
|
-
|
|
3299
|
-
|
|
3367
|
+
main {
|
|
3368
|
+
width: min(1120px, calc(100vw - 56px));
|
|
3369
|
+
margin: 0 auto;
|
|
3300
3370
|
}
|
|
3301
|
-
.
|
|
3371
|
+
.document {
|
|
3302
3372
|
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.
|
|
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
|
-
|
|
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.
|
|
3326
|
-
|
|
3327
|
-
|
|
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:
|
|
3335
|
-
.visual h2 { font-size: 1.
|
|
3336
|
-
.visual h3 { font-size:
|
|
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:
|
|
3341
|
-
font-size:
|
|
3342
|
-
line-height: 1.
|
|
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:
|
|
3450
|
+
border-left: 3px solid var(--primary);
|
|
3352
3451
|
padding-left: 14px;
|
|
3353
|
-
color: var(--
|
|
3452
|
+
color: var(--content-subtle);
|
|
3354
3453
|
}
|
|
3355
3454
|
.visual code {
|
|
3356
3455
|
border-radius: 6px;
|
|
3357
|
-
|
|
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:
|
|
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:
|
|
3367
|
-
color:
|
|
3368
|
-
padding:
|
|
3369
|
-
font: 0.78rem/1.55
|
|
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
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
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
|
-
<
|
|
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>
|
|
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
|
-
<
|
|
3396
|
-
<article class="
|
|
3397
|
-
<div class="
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
<div class="
|
|
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
|
-
</
|
|
3405
|
-
</
|
|
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
|
-
|
|
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+(.+)$/);
|