@openspecui/web 3.5.1 → 3.6.0
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/assets/CanvasRenderer-DdAQFilo.js +1 -0
- package/dist/assets/WebGLRenderer-D0xPb_sN.js +1 -0
- package/dist/assets/WebGPURenderer-DOHdaBx2.js +1 -0
- package/dist/assets/browserAll-r2hAe-_H.js +1 -0
- package/dist/assets/{dist-BdfEVdSD.js → dist-BCNuV7xG.js} +1 -1
- package/dist/assets/dist-BIdWjo7l.js +1 -0
- package/dist/assets/{dist-Bhy8KkMf.js → dist-BVK0Rssu.js} +1 -1
- package/dist/assets/{dist-DcDz_e4d.js → dist-BozUQC43.js} +1 -1
- package/dist/assets/{dist-C5q6KJx5.js → dist-CDVL3YEX.js} +1 -1
- package/dist/assets/{dist-Bi2cQNT3.js → dist-CLV0HJPY.js} +1 -1
- package/dist/assets/{dist-BbID--pe.js → dist-CTzhdbTq.js} +1 -1
- package/dist/assets/dist-CaLzADt5.js +1 -0
- package/dist/assets/{dist-CwQDZ7pq.js → dist-CiOmMqf9.js} +1 -1
- package/dist/assets/{dist-BPxWbdzo.js → dist-CnERwHuC.js} +1 -1
- package/dist/assets/dist-DOlIviuv.js +1 -0
- package/dist/assets/{dist-CsiaRd98.js → dist-YiF0YY_U.js} +1 -1
- package/dist/assets/{ghostty-web-DsRWwk5O.js → ghostty-web-CZWq-tLQ.js} +1 -1
- package/dist/assets/{index-Cu3RSC5X.js → index-4c2vKipy.js} +257 -192
- package/dist/assets/index-BWGHsSSL.css +1 -0
- package/dist/assets/{init-CHYX1BvT.js → init-DIWiFCrW.js} +1 -1
- package/dist/assets/trpc-sHsseX53.js +1 -0
- package/dist/assets/webworkerAll-C2ADhLOV.js +1 -0
- package/dist/index.html +2 -2
- package/dist-ssg/client/.vite/ssr-manifest.json +33 -15
- package/dist-ssg/client/assets/CanvasRenderer-BnHuf5TM.js +1 -0
- package/dist-ssg/client/assets/WebGLRenderer-QYh372d6.js +1 -0
- package/dist-ssg/client/assets/WebGPURenderer-By0AaAH2.js +1 -0
- package/dist-ssg/client/assets/browserAll-DPwpu3rh.js +1 -0
- package/dist-ssg/client/assets/dist-BEN6F4c9.js +1 -0
- package/dist-ssg/client/assets/{dist-CnuoVdCe.js → dist-B_W8Dqsb.js} +1 -1
- package/dist-ssg/client/assets/{dist-BcmGqqhm.js → dist-BcdNCEyE.js} +1 -1
- package/dist-ssg/client/assets/{dist-BBxB0BsU.js → dist-Be-EJt6Y.js} +1 -1
- package/dist-ssg/client/assets/{dist-Cc-hzu-d.js → dist-ByMJ_rO0.js} +1 -1
- package/dist-ssg/client/assets/{dist-B7BRp2AD.js → dist-CMm3Nmq-.js} +1 -1
- package/dist-ssg/client/assets/{dist-C-b45p6-.js → dist-CcH1wf1k.js} +1 -1
- package/dist-ssg/client/assets/dist-D1b5s3ht.js +1 -0
- package/dist-ssg/client/assets/dist-DPvPfazk.js +1 -0
- package/dist-ssg/client/assets/{dist-D5h2ifzs.js → dist-DVuQHEv_.js} +1 -1
- package/dist-ssg/client/assets/{dist-CEnArSkR.js → dist-fM5ujDIS.js} +1 -1
- package/dist-ssg/client/assets/{dist-B0OSa9m8.js → dist-oT5Lx9wx.js} +1 -1
- package/dist-ssg/client/assets/{ghostty-web-Cuh3nJnk.js → ghostty-web-DSO4nFSe.js} +1 -1
- package/dist-ssg/client/assets/index-CGJJczvl.css +1 -0
- package/dist-ssg/client/assets/{index.ssg-C4AALSK6.js → index.ssg-ph-ofjeJ.js} +231 -166
- package/dist-ssg/client/assets/{init-DSQMJRar.js → init-DOhQsgqw.js} +1 -1
- package/dist-ssg/client/assets/trpc-DvRhEguu.js +1 -0
- package/dist-ssg/client/assets/webworkerAll-J8DER0Bd.js +1 -0
- package/dist-ssg/client/index.ssg.html +2 -2
- package/dist-ssg/server/entry-server.js +1651 -163
- package/package.json +1 -1
- package/dist/assets/CanvasRenderer-4LnzB23C.js +0 -1
- package/dist/assets/WebGLRenderer-C7T0ni7u.js +0 -1
- package/dist/assets/WebGPURenderer-Bfz3G3Ra.js +0 -1
- package/dist/assets/browserAll-D1GPsRxQ.js +0 -1
- package/dist/assets/dist-BbOkQMo2.js +0 -1
- package/dist/assets/dist-Cndawm3q.js +0 -1
- package/dist/assets/dist-tU6RymPC.js +0 -1
- package/dist/assets/index-DYcfk_P1.css +0 -1
- package/dist/assets/trpc-BwqMLlvD.js +0 -1
- package/dist/assets/webworkerAll-DTZDj7Ch.js +0 -1
- package/dist-ssg/client/assets/CanvasRenderer-BRusEeYW.js +0 -1
- package/dist-ssg/client/assets/WebGLRenderer-CYFxsByj.js +0 -1
- package/dist-ssg/client/assets/WebGPURenderer-BC6Mc9fr.js +0 -1
- package/dist-ssg/client/assets/browserAll-DwGvMVOE.js +0 -1
- package/dist-ssg/client/assets/dist-B-JL-RdI.js +0 -1
- package/dist-ssg/client/assets/dist-D6Kcyhv0.js +0 -1
- package/dist-ssg/client/assets/dist-iGOlT260.js +0 -1
- package/dist-ssg/client/assets/index-D3bHMPOK.css +0 -1
- package/dist-ssg/client/assets/trpc-38H3yLz8.js +0 -1
- package/dist-ssg/client/assets/webworkerAll-C6L_ZFEk.js +0 -1
|
@@ -38436,13 +38436,6 @@ function writeLocalStorage(layout, key = getLocalStorageKey()) {
|
|
|
38436
38436
|
localStorage.setItem(key, JSON.stringify(layout));
|
|
38437
38437
|
} catch {}
|
|
38438
38438
|
}
|
|
38439
|
-
function collapseProjectDetailLocation(location) {
|
|
38440
|
-
const tabId = pathToTabId(location.pathname);
|
|
38441
|
-
if (!tabId) return location;
|
|
38442
|
-
if (location.pathname === tabId) return location;
|
|
38443
|
-
if (tabId === "/changes" || tabId === "/specs" || tabId === "/archive") return parseHref(tabId, location.state);
|
|
38444
|
-
return location;
|
|
38445
|
-
}
|
|
38446
38439
|
var carryActiveOnMovePlugin = ({ prevState, nextState, event }) => {
|
|
38447
38440
|
if (event.type !== "MOVE_TAB") return nextState;
|
|
38448
38441
|
const sourceArea = prevState.bottomTabs.includes(event.tabId) ? "bottom" : "main";
|
|
@@ -39078,8 +39071,6 @@ var NavController = class {
|
|
|
39078
39071
|
}
|
|
39079
39072
|
this.state = normalizeState({
|
|
39080
39073
|
...this.state,
|
|
39081
|
-
mainLocation: collapseProjectDetailLocation(this.state.mainLocation),
|
|
39082
|
-
bottomLocation: collapseProjectDetailLocation(this.state.bottomLocation),
|
|
39083
39074
|
updatedAt: 0
|
|
39084
39075
|
});
|
|
39085
39076
|
this.normalizeUrl();
|
|
@@ -50003,6 +49994,15 @@ async function getSpec(id) {
|
|
|
50003
49994
|
return snapshotSpecToSpec(snapSpec);
|
|
50004
49995
|
}
|
|
50005
49996
|
/**
|
|
49997
|
+
* Get raw spec content (markdown)
|
|
49998
|
+
*/
|
|
49999
|
+
async function getSpecRaw(id) {
|
|
50000
|
+
const snapshot = await loadSnapshot();
|
|
50001
|
+
if (!snapshot) return null;
|
|
50002
|
+
const spec = snapshot.specs.find((s) => s.id === id);
|
|
50003
|
+
return spec?.content ?? spec?.sourceContent ?? null;
|
|
50004
|
+
}
|
|
50005
|
+
/**
|
|
50006
50006
|
* Get all changes metadata
|
|
50007
50007
|
*/
|
|
50008
50008
|
async function getChanges() {
|
|
@@ -52924,6 +52924,12 @@ function useSpecSubscription(id) {
|
|
|
52924
52924
|
onError: callbacks.onError
|
|
52925
52925
|
}), () => getSpec(id), [id], getSpecSubscriptionCacheKey(id));
|
|
52926
52926
|
}
|
|
52927
|
+
function useSpecRawSubscription(id) {
|
|
52928
|
+
return useSubscription((callbacks) => trpcClient.spec.subscribeRaw.subscribe({ id }, {
|
|
52929
|
+
onData: callbacks.onData,
|
|
52930
|
+
onError: callbacks.onError
|
|
52931
|
+
}), () => getSpecRaw(id), [id], `spec.subscribeRaw:${id}`);
|
|
52932
|
+
}
|
|
52927
52933
|
function useChangesSubscription() {
|
|
52928
52934
|
return useSubscription((callbacks) => trpcClient.change.subscribe.subscribe(void 0, {
|
|
52929
52935
|
onData: callbacks.onData,
|
|
@@ -55415,6 +55421,42 @@ function useManualReconnect() {
|
|
|
55415
55421
|
}, []);
|
|
55416
55422
|
}
|
|
55417
55423
|
//#endregion
|
|
55424
|
+
//#region src/components/badge.tsx
|
|
55425
|
+
var toneClassNames = {
|
|
55426
|
+
primary: "bg-primary text-primary-foreground",
|
|
55427
|
+
subtle: "border border-primary/35 bg-primary/10 text-primary",
|
|
55428
|
+
muted: "border border-border bg-muted text-muted-foreground",
|
|
55429
|
+
custom: ""
|
|
55430
|
+
};
|
|
55431
|
+
var sizeClassNames$1 = {
|
|
55432
|
+
dot: "h-1.5 w-1.5 min-w-0 p-0",
|
|
55433
|
+
xs: "h-4 min-w-4 px-1 text-[10px] leading-none",
|
|
55434
|
+
sm: "h-5 min-w-5 px-1.5 text-[11px] leading-none"
|
|
55435
|
+
};
|
|
55436
|
+
var shapeClassNames = {
|
|
55437
|
+
pill: "rounded-full",
|
|
55438
|
+
box: "rounded"
|
|
55439
|
+
};
|
|
55440
|
+
function Badge({ tone = "primary", size = "xs", shape = "pill", className, ...props }) {
|
|
55441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
55442
|
+
"data-ui-badge": "true",
|
|
55443
|
+
className: cn$1("inline-flex shrink-0 items-center justify-center gap-0.5 whitespace-nowrap font-semibold", toneClassNames[tone], sizeClassNames$1[size], shapeClassNames[shape], className),
|
|
55444
|
+
...props
|
|
55445
|
+
});
|
|
55446
|
+
}
|
|
55447
|
+
function formatCountBadgeValue(count, max = 99) {
|
|
55448
|
+
return count > max ? `${max}+` : String(count);
|
|
55449
|
+
}
|
|
55450
|
+
function CountBadge({ count, max = 99, hideWhenZero = false, title, ...props }) {
|
|
55451
|
+
if (hideWhenZero && count <= 0) return null;
|
|
55452
|
+
const value = formatCountBadgeValue(count, max);
|
|
55453
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
55454
|
+
title,
|
|
55455
|
+
...props,
|
|
55456
|
+
children: value
|
|
55457
|
+
});
|
|
55458
|
+
}
|
|
55459
|
+
//#endregion
|
|
55418
55460
|
//#region ../core/src/pty-protocol.ts
|
|
55419
55461
|
var PositiveInt = numberType().int().positive();
|
|
55420
55462
|
var PtyPlatformSchema = enumType([
|
|
@@ -67053,6 +67095,7 @@ var MIN_WIDTH_PX = 300;
|
|
|
67053
67095
|
var MIN_HEIGHT_PX = 150;
|
|
67054
67096
|
var MAX_WIDTH_PCT = 95;
|
|
67055
67097
|
var MAX_HEIGHT_PCT = 85;
|
|
67098
|
+
var MOVE_BAR_PROTRUSION_PX = 10;
|
|
67056
67099
|
var SETTINGS_KEY$1 = "xtermInputPanelSettings";
|
|
67057
67100
|
function mergeSettings(updates) {
|
|
67058
67101
|
try {
|
|
@@ -67129,6 +67172,8 @@ var InputPanel = class extends i {
|
|
|
67129
67172
|
--muted-foreground: var(--_ip-muted-fg);
|
|
67130
67173
|
--terminal: var(--_ip-bg);
|
|
67131
67174
|
--terminal-foreground: var(--_ip-fg);
|
|
67175
|
+
--move-bar-height: 10px;
|
|
67176
|
+
--move-bar-protrusion: 10px;
|
|
67132
67177
|
font-family: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
67133
67178
|
font-size: 13px;
|
|
67134
67179
|
color: var(--foreground, #fff);
|
|
@@ -67251,7 +67296,7 @@ var InputPanel = class extends i {
|
|
|
67251
67296
|
border-radius: 8px;
|
|
67252
67297
|
background: var(--background, #1a1a1a);
|
|
67253
67298
|
color: var(--foreground, #fff);
|
|
67254
|
-
overflow:
|
|
67299
|
+
overflow: visible;
|
|
67255
67300
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
|
|
67256
67301
|
display: flex;
|
|
67257
67302
|
flex-direction: column;
|
|
@@ -67263,6 +67308,54 @@ var InputPanel = class extends i {
|
|
|
67263
67308
|
z-index: 9999;
|
|
67264
67309
|
}
|
|
67265
67310
|
|
|
67311
|
+
.panel-body {
|
|
67312
|
+
width: 100%;
|
|
67313
|
+
height: 100%;
|
|
67314
|
+
display: flex;
|
|
67315
|
+
flex-direction: column;
|
|
67316
|
+
overflow: hidden;
|
|
67317
|
+
border-radius: inherit;
|
|
67318
|
+
}
|
|
67319
|
+
|
|
67320
|
+
.move-bar {
|
|
67321
|
+
position: absolute;
|
|
67322
|
+
top: calc(-1 * var(--move-bar-protrusion));
|
|
67323
|
+
left: 50%;
|
|
67324
|
+
width: 68px;
|
|
67325
|
+
height: var(--move-bar-height);
|
|
67326
|
+
transform: translateX(-50%);
|
|
67327
|
+
border: 1px solid var(--primary, #e04a2f);
|
|
67328
|
+
border-bottom: 0;
|
|
67329
|
+
border-radius: 10px 10px 0 0;
|
|
67330
|
+
background: var(--background, #1a1a1a);
|
|
67331
|
+
color: var(--muted-foreground, #888);
|
|
67332
|
+
touch-action: none;
|
|
67333
|
+
cursor: grab;
|
|
67334
|
+
z-index: 12;
|
|
67335
|
+
display: flex;
|
|
67336
|
+
align-items: center;
|
|
67337
|
+
justify-content: center;
|
|
67338
|
+
box-shadow: 0 -6px 12px rgba(0, 0, 0, 0.12);
|
|
67339
|
+
}
|
|
67340
|
+
|
|
67341
|
+
.move-bar::before {
|
|
67342
|
+
content: '';
|
|
67343
|
+
width: 34px;
|
|
67344
|
+
height: 4px;
|
|
67345
|
+
border-radius: 999px;
|
|
67346
|
+
background: currentColor;
|
|
67347
|
+
opacity: 0.72;
|
|
67348
|
+
}
|
|
67349
|
+
|
|
67350
|
+
.move-bar:hover,
|
|
67351
|
+
:host([data-interacting]) .move-bar {
|
|
67352
|
+
color: var(--primary, #e04a2f);
|
|
67353
|
+
}
|
|
67354
|
+
|
|
67355
|
+
:host([data-interacting]) .move-bar {
|
|
67356
|
+
cursor: grabbing;
|
|
67357
|
+
}
|
|
67358
|
+
|
|
67266
67359
|
/* --- Resize handles --- */
|
|
67267
67360
|
.resize-handle {
|
|
67268
67361
|
position: absolute;
|
|
@@ -67360,6 +67453,7 @@ var InputPanel = class extends i {
|
|
|
67360
67453
|
}
|
|
67361
67454
|
disconnectedCallback() {
|
|
67362
67455
|
super.disconnectedCallback();
|
|
67456
|
+
this._closeFloatingDialog();
|
|
67363
67457
|
this.dispatchEvent(new CustomEvent("input-panel:disconnected", {
|
|
67364
67458
|
bubbles: true,
|
|
67365
67459
|
composed: true
|
|
@@ -67416,7 +67510,7 @@ var InputPanel = class extends i {
|
|
|
67416
67510
|
const maxOverX = wPx / 3, maxOverY = hPx / 3;
|
|
67417
67511
|
return {
|
|
67418
67512
|
left: Math.max(-maxOverX, Math.min(vw - wPx + maxOverX, leftPx)),
|
|
67419
|
-
top: Math.max(
|
|
67513
|
+
top: Math.max(MOVE_BAR_PROTRUSION_PX, Math.min(vh - hPx + maxOverY, topPx))
|
|
67420
67514
|
};
|
|
67421
67515
|
}
|
|
67422
67516
|
_applyGeometry(dialog) {
|
|
@@ -67444,6 +67538,43 @@ var InputPanel = class extends i {
|
|
|
67444
67538
|
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
67445
67539
|
if (dialog) this._applyGeometry(dialog);
|
|
67446
67540
|
}
|
|
67541
|
+
_isPopoverOpen(dialog) {
|
|
67542
|
+
try {
|
|
67543
|
+
return dialog.matches(":popover-open");
|
|
67544
|
+
} catch {
|
|
67545
|
+
return false;
|
|
67546
|
+
}
|
|
67547
|
+
}
|
|
67548
|
+
_isFloatingDialogOpen(dialog) {
|
|
67549
|
+
return dialog.open || this._isPopoverOpen(dialog);
|
|
67550
|
+
}
|
|
67551
|
+
_showFloatingDialog(dialog) {
|
|
67552
|
+
if (this._isFloatingDialogOpen(dialog)) return;
|
|
67553
|
+
if (!dialog.isConnected) {
|
|
67554
|
+
requestAnimationFrame(() => {
|
|
67555
|
+
if (this.layout === "floating" && dialog.isConnected && !this._isFloatingDialogOpen(dialog)) {
|
|
67556
|
+
this._showFloatingDialog(dialog);
|
|
67557
|
+
this._applyGeometry(dialog);
|
|
67558
|
+
}
|
|
67559
|
+
});
|
|
67560
|
+
return;
|
|
67561
|
+
}
|
|
67562
|
+
const popoverDialog = dialog;
|
|
67563
|
+
if (typeof popoverDialog.showPopover === "function") {
|
|
67564
|
+
popoverDialog.showPopover();
|
|
67565
|
+
return;
|
|
67566
|
+
}
|
|
67567
|
+
dialog.show();
|
|
67568
|
+
}
|
|
67569
|
+
_closeFloatingDialog() {
|
|
67570
|
+
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
67571
|
+
if (!dialog) return;
|
|
67572
|
+
if (this._isPopoverOpen(dialog) && typeof dialog.hidePopover === "function") {
|
|
67573
|
+
dialog.hidePopover();
|
|
67574
|
+
return;
|
|
67575
|
+
}
|
|
67576
|
+
if (dialog.open) dialog.close();
|
|
67577
|
+
}
|
|
67447
67578
|
_switchTab(tab) {
|
|
67448
67579
|
this.activeTab = tab;
|
|
67449
67580
|
this.dispatchEvent(new CustomEvent("input-panel:tab-change", {
|
|
@@ -67455,6 +67586,7 @@ var InputPanel = class extends i {
|
|
|
67455
67586
|
}
|
|
67456
67587
|
_toggleLayout() {
|
|
67457
67588
|
this.layout = this.layout === "fixed" ? "floating" : "fixed";
|
|
67589
|
+
if (this.layout === "fixed") this._closeFloatingDialog();
|
|
67458
67590
|
this.dispatchEvent(new CustomEvent("input-panel:layout-change", {
|
|
67459
67591
|
detail: { layout: this.layout },
|
|
67460
67592
|
bubbles: true,
|
|
@@ -67463,8 +67595,7 @@ var InputPanel = class extends i {
|
|
|
67463
67595
|
this.requestUpdate();
|
|
67464
67596
|
}
|
|
67465
67597
|
_close() {
|
|
67466
|
-
|
|
67467
|
-
if (dialog?.open) dialog.close();
|
|
67598
|
+
this._closeFloatingDialog();
|
|
67468
67599
|
this.dispatchEvent(new CustomEvent("input-panel:close", {
|
|
67469
67600
|
bubbles: true,
|
|
67470
67601
|
composed: true
|
|
@@ -67474,8 +67605,8 @@ var InputPanel = class extends i {
|
|
|
67474
67605
|
super.firstUpdated(changed);
|
|
67475
67606
|
if (this.layout === "floating") {
|
|
67476
67607
|
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
67477
|
-
if (dialog && !dialog
|
|
67478
|
-
|
|
67608
|
+
if (dialog && !this._isFloatingDialogOpen(dialog)) {
|
|
67609
|
+
this._showFloatingDialog(dialog);
|
|
67479
67610
|
this._applyGeometry(dialog);
|
|
67480
67611
|
}
|
|
67481
67612
|
}
|
|
@@ -67486,14 +67617,17 @@ var InputPanel = class extends i {
|
|
|
67486
67617
|
if (this.layout === "floating") {
|
|
67487
67618
|
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
67488
67619
|
if (dialog) {
|
|
67489
|
-
if (changed.has("layout") && !dialog
|
|
67490
|
-
if (dialog
|
|
67620
|
+
if (changed.has("layout") && !this._isFloatingDialogOpen(dialog)) this._showFloatingDialog(dialog);
|
|
67621
|
+
if (this._isFloatingDialogOpen(dialog)) this._applyGeometry(dialog);
|
|
67491
67622
|
}
|
|
67492
67623
|
}
|
|
67493
67624
|
}
|
|
67494
67625
|
_onToolbarPointerDown(e) {
|
|
67495
|
-
if (this.layout !== "floating") return;
|
|
67496
67626
|
if (e.target.closest("button")) return;
|
|
67627
|
+
this._onDragPointerDown(e);
|
|
67628
|
+
}
|
|
67629
|
+
_onDragPointerDown(e) {
|
|
67630
|
+
if (this.layout !== "floating") return;
|
|
67497
67631
|
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
67498
67632
|
if (!dialog) return;
|
|
67499
67633
|
e.stopPropagation();
|
|
@@ -67506,9 +67640,12 @@ var InputPanel = class extends i {
|
|
|
67506
67640
|
origTop: rect.top
|
|
67507
67641
|
};
|
|
67508
67642
|
this.setAttribute("data-interacting", "");
|
|
67509
|
-
e.
|
|
67643
|
+
const handle = e.currentTarget;
|
|
67644
|
+
try {
|
|
67645
|
+
handle.setPointerCapture(e.pointerId);
|
|
67646
|
+
} catch {}
|
|
67510
67647
|
}
|
|
67511
|
-
|
|
67648
|
+
_onDragPointerMove(e) {
|
|
67512
67649
|
if (!this._dragState) return;
|
|
67513
67650
|
e.stopPropagation();
|
|
67514
67651
|
e.preventDefault();
|
|
@@ -67524,8 +67661,10 @@ var InputPanel = class extends i {
|
|
|
67524
67661
|
dialog.style.top = `${top}px`;
|
|
67525
67662
|
dialog.style.bottom = "auto";
|
|
67526
67663
|
}
|
|
67527
|
-
|
|
67664
|
+
_onDragPointerUp(e) {
|
|
67528
67665
|
if (!this._dragState) return;
|
|
67666
|
+
e.stopPropagation();
|
|
67667
|
+
e.preventDefault();
|
|
67529
67668
|
this._dragState = null;
|
|
67530
67669
|
this.removeAttribute("data-interacting");
|
|
67531
67670
|
const dialog = this.shadowRoot?.querySelector(".panel-dialog");
|
|
@@ -67645,8 +67784,9 @@ var InputPanel = class extends i {
|
|
|
67645
67784
|
class="toolbar"
|
|
67646
67785
|
part="toolbar"
|
|
67647
67786
|
@pointerdown=${(e) => this._onToolbarPointerDown(e)}
|
|
67648
|
-
@pointermove=${(e) => this.
|
|
67649
|
-
@pointerup=${() => this.
|
|
67787
|
+
@pointermove=${(e) => this._onDragPointerMove(e)}
|
|
67788
|
+
@pointerup=${(e) => this._onDragPointerUp(e)}
|
|
67789
|
+
@pointercancel=${(e) => this._onDragPointerUp(e)}
|
|
67650
67790
|
>
|
|
67651
67791
|
<div class="tab-group">
|
|
67652
67792
|
${[
|
|
@@ -67706,7 +67846,16 @@ var InputPanel = class extends i {
|
|
|
67706
67846
|
></input-panel-settings>` : T`<slot name=${this.activeTab}></slot>`}
|
|
67707
67847
|
</div>
|
|
67708
67848
|
`;
|
|
67709
|
-
if (this.layout === "floating") return T` <dialog class="panel-dialog">
|
|
67849
|
+
if (this.layout === "floating") return T` <dialog class="panel-dialog" popover="manual">
|
|
67850
|
+
<div
|
|
67851
|
+
class="move-bar"
|
|
67852
|
+
part="move-bar"
|
|
67853
|
+
aria-label="Move input panel"
|
|
67854
|
+
@pointerdown=${(e) => this._onDragPointerDown(e)}
|
|
67855
|
+
@pointermove=${(e) => this._onDragPointerMove(e)}
|
|
67856
|
+
@pointerup=${(e) => this._onDragPointerUp(e)}
|
|
67857
|
+
@pointercancel=${(e) => this._onDragPointerUp(e)}
|
|
67858
|
+
></div>
|
|
67710
67859
|
<div
|
|
67711
67860
|
class="resize-handle resize-tl"
|
|
67712
67861
|
@pointerdown=${(e) => this._onResizeStart(e, "tl")}
|
|
@@ -67723,7 +67872,7 @@ var InputPanel = class extends i {
|
|
|
67723
67872
|
class="resize-handle resize-br"
|
|
67724
67873
|
@pointerdown=${(e) => this._onResizeStart(e, "br")}
|
|
67725
67874
|
></div>
|
|
67726
|
-
|
|
67875
|
+
<div class="panel-body">${inner}</div>
|
|
67727
67876
|
</dialog>`;
|
|
67728
67877
|
return inner;
|
|
67729
67878
|
}
|
|
@@ -68341,11 +68490,11 @@ function assertPath$1(path2) {
|
|
|
68341
68490
|
function removeUrlParams(url) {
|
|
68342
68491
|
return url.split("?")[0].split("#")[0];
|
|
68343
68492
|
}
|
|
68344
|
-
function escapeRegExp(string) {
|
|
68493
|
+
function escapeRegExp$1(string) {
|
|
68345
68494
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
68346
68495
|
}
|
|
68347
68496
|
function replaceAll$1(str, find, replace) {
|
|
68348
|
-
return str.replace(new RegExp(escapeRegExp(find), "g"), replace);
|
|
68497
|
+
return str.replace(new RegExp(escapeRegExp$1(find), "g"), replace);
|
|
68349
68498
|
}
|
|
68350
68499
|
function normalizeStringPosix(path2, allowAboveRoot) {
|
|
68351
68500
|
let res = "";
|
|
@@ -94320,10 +94469,10 @@ function NotificationEntryButton({ className, badgeClassName, iconClassName }) {
|
|
|
94320
94469
|
"aria-label": label,
|
|
94321
94470
|
title: label,
|
|
94322
94471
|
"data-notification-entry-button": "true",
|
|
94323
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Bell, { className: cn$1("h-4 w-4", iconClassName) }), unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
94324
|
-
|
|
94325
|
-
"
|
|
94326
|
-
|
|
94472
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Bell, { className: cn$1("h-4 w-4", iconClassName) }), unreadCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountBadge, {
|
|
94473
|
+
count: unreadCount,
|
|
94474
|
+
className: cn$1("ring-background absolute -right-1.5 -top-1.5 ring-2", badgeClassName),
|
|
94475
|
+
"aria-hidden": "true"
|
|
94327
94476
|
})]
|
|
94328
94477
|
})
|
|
94329
94478
|
});
|
|
@@ -126052,12 +126201,15 @@ var { codeToHtml, codeToHast, codeToTokens, codeToTokensBase, codeToTokensWithTh
|
|
|
126052
126201
|
* Simple markdown renderer with GFM support and shiki code highlighting.
|
|
126053
126202
|
* For full markdown viewing with ToC, use MarkdownViewer instead.
|
|
126054
126203
|
*/
|
|
126055
|
-
function MarkdownContent({ children, className = "", components }) {
|
|
126204
|
+
function MarkdownContent({ children, className = "", components, inlineTextAnnotations = [], blockAnnotations = [] }) {
|
|
126205
|
+
const blockAnnotationByOffset = (0, import_react.useMemo)(() => new Map(blockAnnotations.map((annotation) => [createBlockAnnotationKey$1(annotation), annotation])), [blockAnnotations]);
|
|
126206
|
+
const annotationComponents = (0, import_react.useMemo)(() => createAnnotationComponents(inlineTextAnnotations, blockAnnotationByOffset), [inlineTextAnnotations, blockAnnotationByOffset]);
|
|
126056
126207
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
126057
126208
|
className: `markdown-content ${className}`,
|
|
126058
126209
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Markdown, {
|
|
126059
126210
|
remarkPlugins: [remarkGfm],
|
|
126060
126211
|
components: {
|
|
126212
|
+
...annotationComponents,
|
|
126061
126213
|
code: CodeBlock,
|
|
126062
126214
|
pre: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children }),
|
|
126063
126215
|
...components
|
|
@@ -126066,6 +126218,156 @@ function MarkdownContent({ children, className = "", components }) {
|
|
|
126066
126218
|
})
|
|
126067
126219
|
});
|
|
126068
126220
|
}
|
|
126221
|
+
function renderInlineAnnotatedChildren(children, annotations) {
|
|
126222
|
+
if (annotations.length === 0) return children;
|
|
126223
|
+
if (typeof children === "string" || typeof children === "number") return renderInlineAnnotatedText(String(children), annotations);
|
|
126224
|
+
if (Array.isArray(children)) return children.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Fragment, { children: renderInlineAnnotatedChildren(child, annotations) }, `inline-node-${index}`));
|
|
126225
|
+
return children;
|
|
126226
|
+
}
|
|
126227
|
+
function renderInlineAnnotatedText(text, annotations) {
|
|
126228
|
+
const pattern = createInlineAnnotationPattern(annotations);
|
|
126229
|
+
if (!pattern) return text;
|
|
126230
|
+
const annotationByText = new Map(annotations.map((annotation) => [annotation.text, annotation]));
|
|
126231
|
+
const nodes = [];
|
|
126232
|
+
let lastIndex = 0;
|
|
126233
|
+
for (const match of text.matchAll(pattern)) {
|
|
126234
|
+
const matchText = match[0];
|
|
126235
|
+
const start = match.index ?? 0;
|
|
126236
|
+
const annotation = annotationByText.get(matchText);
|
|
126237
|
+
if (!annotation) continue;
|
|
126238
|
+
if (start > lastIndex) nodes.push(text.slice(lastIndex, start));
|
|
126239
|
+
nodes.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126240
|
+
className: annotation.className,
|
|
126241
|
+
...annotation.dataAttributes,
|
|
126242
|
+
children: matchText
|
|
126243
|
+
}, `inline-annotation-${start}-${matchText}`));
|
|
126244
|
+
lastIndex = start + matchText.length;
|
|
126245
|
+
}
|
|
126246
|
+
if (lastIndex === 0) return text;
|
|
126247
|
+
if (lastIndex < text.length) nodes.push(text.slice(lastIndex));
|
|
126248
|
+
return nodes;
|
|
126249
|
+
}
|
|
126250
|
+
function createInlineAnnotationPattern(annotations) {
|
|
126251
|
+
const terms = Array.from(new Set(annotations.map((annotation) => annotation.text.trim()))).filter(Boolean).sort((left, right) => right.length - left.length);
|
|
126252
|
+
if (terms.length === 0) return void 0;
|
|
126253
|
+
return new RegExp(`\\b(${terms.map(escapeRegExp).join("|")})\\b`, "g");
|
|
126254
|
+
}
|
|
126255
|
+
function escapeRegExp(value) {
|
|
126256
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
126257
|
+
}
|
|
126258
|
+
function getMarkdownNodeSourceStartOffset(node) {
|
|
126259
|
+
if (!node || typeof node !== "object" || !("position" in node)) return void 0;
|
|
126260
|
+
const position = node.position;
|
|
126261
|
+
if (!position || typeof position !== "object" || !("start" in position)) return void 0;
|
|
126262
|
+
const start = position.start;
|
|
126263
|
+
if (!start || typeof start !== "object" || !("offset" in start)) return void 0;
|
|
126264
|
+
const offset = start.offset;
|
|
126265
|
+
return typeof offset === "number" ? offset : void 0;
|
|
126266
|
+
}
|
|
126267
|
+
function getBlockAnnotation(node, annotationByOffset, sourceKind) {
|
|
126268
|
+
const sourceStartOffset = getMarkdownNodeSourceStartOffset(node);
|
|
126269
|
+
if (sourceStartOffset === void 0) return void 0;
|
|
126270
|
+
return (sourceKind ? annotationByOffset.get(createBlockAnnotationKey$1({
|
|
126271
|
+
sourceStartOffset,
|
|
126272
|
+
sourceKind
|
|
126273
|
+
})) : void 0) ?? annotationByOffset.get(createBlockAnnotationKey$1({ sourceStartOffset }));
|
|
126274
|
+
}
|
|
126275
|
+
function createBlockAnnotationKey$1(annotation) {
|
|
126276
|
+
return `${annotation.sourceStartOffset}:${annotation.sourceKind ?? "*"}`;
|
|
126277
|
+
}
|
|
126278
|
+
function mergeClassName(...classNames) {
|
|
126279
|
+
return classNames.filter(Boolean).join(" ") || void 0;
|
|
126280
|
+
}
|
|
126281
|
+
function createAnnotationComponents(inlineAnnotations, blockAnnotationByOffset) {
|
|
126282
|
+
if (inlineAnnotations.length === 0 && blockAnnotationByOffset.size === 0) return {};
|
|
126283
|
+
const render = (children) => renderInlineAnnotatedChildren(children, inlineAnnotations);
|
|
126284
|
+
return {
|
|
126285
|
+
p: ({ children, node, ...props }) => {
|
|
126286
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "paragraph");
|
|
126287
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
126288
|
+
...props,
|
|
126289
|
+
...annotation?.dataAttributes,
|
|
126290
|
+
className: mergeClassName(props.className, annotation?.className),
|
|
126291
|
+
children: render(children)
|
|
126292
|
+
});
|
|
126293
|
+
},
|
|
126294
|
+
ul: ({ children, node, ...props }) => {
|
|
126295
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "list");
|
|
126296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", {
|
|
126297
|
+
...props,
|
|
126298
|
+
...annotation?.dataAttributes,
|
|
126299
|
+
className: mergeClassName(props.className, annotation?.className),
|
|
126300
|
+
children
|
|
126301
|
+
});
|
|
126302
|
+
},
|
|
126303
|
+
ol: ({ children, node, ...props }) => {
|
|
126304
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "list");
|
|
126305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", {
|
|
126306
|
+
...props,
|
|
126307
|
+
...annotation?.dataAttributes,
|
|
126308
|
+
className: mergeClassName(props.className, annotation?.className),
|
|
126309
|
+
children
|
|
126310
|
+
});
|
|
126311
|
+
},
|
|
126312
|
+
li: ({ children, node, className, ...props }) => {
|
|
126313
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "listItem");
|
|
126314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", {
|
|
126315
|
+
...props,
|
|
126316
|
+
...annotation?.dataAttributes,
|
|
126317
|
+
className: mergeClassName(className, annotation?.className),
|
|
126318
|
+
children: render(children)
|
|
126319
|
+
});
|
|
126320
|
+
},
|
|
126321
|
+
strong: ({ children, node, ...props }) => {
|
|
126322
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", {
|
|
126323
|
+
...props,
|
|
126324
|
+
children: render(children)
|
|
126325
|
+
});
|
|
126326
|
+
},
|
|
126327
|
+
em: ({ children, node, ...props }) => {
|
|
126328
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("em", {
|
|
126329
|
+
...props,
|
|
126330
|
+
children: render(children)
|
|
126331
|
+
});
|
|
126332
|
+
},
|
|
126333
|
+
a: ({ children, node, ...props }) => {
|
|
126334
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", {
|
|
126335
|
+
...props,
|
|
126336
|
+
children: render(children)
|
|
126337
|
+
});
|
|
126338
|
+
},
|
|
126339
|
+
blockquote: ({ children, node, ...props }) => {
|
|
126340
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "blockquote");
|
|
126341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("blockquote", {
|
|
126342
|
+
...props,
|
|
126343
|
+
...annotation?.dataAttributes,
|
|
126344
|
+
className: mergeClassName(props.className, annotation?.className),
|
|
126345
|
+
children
|
|
126346
|
+
});
|
|
126347
|
+
},
|
|
126348
|
+
table: ({ children, node, ...props }) => {
|
|
126349
|
+
const annotation = getBlockAnnotation(node, blockAnnotationByOffset, "table");
|
|
126350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("table", {
|
|
126351
|
+
...props,
|
|
126352
|
+
...annotation?.dataAttributes,
|
|
126353
|
+
className: mergeClassName(props.className, annotation?.className),
|
|
126354
|
+
children
|
|
126355
|
+
});
|
|
126356
|
+
},
|
|
126357
|
+
th: ({ children, node, ...props }) => {
|
|
126358
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", {
|
|
126359
|
+
...props,
|
|
126360
|
+
children: render(children)
|
|
126361
|
+
});
|
|
126362
|
+
},
|
|
126363
|
+
td: ({ children, node, ...props }) => {
|
|
126364
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", {
|
|
126365
|
+
...props,
|
|
126366
|
+
children: render(children)
|
|
126367
|
+
});
|
|
126368
|
+
}
|
|
126369
|
+
};
|
|
126370
|
+
}
|
|
126069
126371
|
/** Shared code block component with shiki syntax highlighting */
|
|
126070
126372
|
function CodeBlock({ children, className }) {
|
|
126071
126373
|
const [html, setHtml] = (0, import_react.useState)(null);
|
|
@@ -126169,32 +126471,38 @@ function Toc({ items, defaultCollapsed = true, className = "" }) {
|
|
|
126169
126471
|
const tree = (0, import_react.useMemo)(() => buildTocTree(items), [items]);
|
|
126170
126472
|
if (items.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("aside", { className: `hidden ${className}` });
|
|
126171
126473
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
126172
|
-
className: `toc-root
|
|
126474
|
+
className: `toc-root sticky top-0 z-10 h-10 w-full min-w-0 max-w-full self-start ${className}`,
|
|
126173
126475
|
children: [
|
|
126174
126476
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: tocStyles }),
|
|
126175
126477
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
126176
|
-
className: "toc-narrow border-border bg-background overflow-hidden rounded border",
|
|
126478
|
+
className: "toc-narrow border-border bg-background/60 overflow-hidden rounded border backdrop-blur-sm",
|
|
126177
126479
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
126178
126480
|
onClick: () => setCollapsed(!collapsed),
|
|
126179
|
-
className: `text-foreground flex w-full items-center gap-2 px-3 py-2 ${collapsed ? "" : "border-border border-b"}`,
|
|
126481
|
+
className: `text-foreground flex w-full min-w-0 items-center gap-2 px-3 py-2 ${collapsed ? "" : "border-border border-b"}`,
|
|
126180
126482
|
"aria-label": collapsed ? "Show table of contents" : "Hide table of contents",
|
|
126181
126483
|
children: [
|
|
126182
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { className: "h-4 w-4" }),
|
|
126484
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { className: "h-4 w-4 shrink-0" }),
|
|
126183
126485
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126184
|
-
className: "text-sm",
|
|
126486
|
+
className: "min-w-0 truncate text-sm",
|
|
126185
126487
|
children: "Contents"
|
|
126186
126488
|
}),
|
|
126187
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: `ml-auto h-4 w-4 transition-transform ${collapsed ? "" : "rotate-180"}` })
|
|
126489
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: `ml-auto h-4 w-4 shrink-0 transition-transform ${collapsed ? "" : "rotate-180"}` })
|
|
126188
126490
|
]
|
|
126189
|
-
}), !collapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
126491
|
+
}), !collapsed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
126492
|
+
className: "toc-scroll toc-narrow-scroll scrollbar-thin scrollbar-track-transparent min-h-0 overflow-y-auto overscroll-contain p-2",
|
|
126493
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TocTree, { nodes: tree })
|
|
126494
|
+
})]
|
|
126190
126495
|
}),
|
|
126191
126496
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("nav", {
|
|
126192
|
-
className: "toc-wide
|
|
126497
|
+
className: "toc-wide min-w-0 max-w-full flex-col overflow-hidden",
|
|
126193
126498
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
126194
|
-
className: "text-muted-foreground flex items-center gap-2 px-3 py-2 text-xs font-medium uppercase tracking-wide",
|
|
126195
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126499
|
+
className: "text-muted-foreground flex min-w-0 items-center gap-2 px-3 py-2 text-xs font-medium uppercase tracking-wide",
|
|
126500
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(List, { className: "h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126501
|
+
className: "min-w-0 truncate",
|
|
126502
|
+
children: "On this page"
|
|
126503
|
+
})]
|
|
126196
126504
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
126197
|
-
className: "scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-y-auto p-2",
|
|
126505
|
+
className: "toc-scroll toc-wide-scroll scrollbar-thin scrollbar-track-transparent min-h-0 flex-1 overflow-y-auto overscroll-contain p-2",
|
|
126198
126506
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TocTree, { nodes: tree })
|
|
126199
126507
|
})]
|
|
126200
126508
|
})
|
|
@@ -126205,7 +126513,7 @@ function Toc({ items, defaultCollapsed = true, className = "" }) {
|
|
|
126205
126513
|
* Find the nearest scrollable ancestor element.
|
|
126206
126514
|
*/
|
|
126207
126515
|
function findScrollableParent(element) {
|
|
126208
|
-
return element.closest(".toc-root");
|
|
126516
|
+
return element.closest(".toc-scroll") ?? element.closest(".toc-root");
|
|
126209
126517
|
}
|
|
126210
126518
|
/**
|
|
126211
126519
|
* Scroll element into view within its scrollable container using scrollTo.
|
|
@@ -126267,10 +126575,18 @@ function TocTree({ nodes, depth = 0 }) {
|
|
|
126267
126575
|
var tocStyles = String.raw`
|
|
126268
126576
|
/* Default: narrow mode (collapsible) */
|
|
126269
126577
|
.toc-narrow {
|
|
126270
|
-
display:
|
|
126578
|
+
display: flex;
|
|
126579
|
+
flex-direction: column;
|
|
126580
|
+
max-height: min(20rem, calc(100cqh - 2rem), calc(100svh - 2rem));
|
|
126581
|
+
max-width: 100%;
|
|
126582
|
+
min-width: 0;
|
|
126583
|
+
}
|
|
126584
|
+
.toc-narrow-scroll {
|
|
126585
|
+
max-height: min(18rem, calc(100cqh - 5rem), calc(100svh - 5rem));
|
|
126271
126586
|
}
|
|
126272
126587
|
.toc-wide {
|
|
126273
126588
|
display: none;
|
|
126589
|
+
max-height: min(calc(100cqh - 3rem), calc(100svh - 3rem));
|
|
126274
126590
|
}
|
|
126275
126591
|
|
|
126276
126592
|
/* Wide container: show sidebar mode */
|
|
@@ -126279,7 +126595,19 @@ var tocStyles = String.raw`
|
|
|
126279
126595
|
display: none;
|
|
126280
126596
|
}
|
|
126281
126597
|
.toc-wide {
|
|
126282
|
-
display:
|
|
126598
|
+
display: flex;
|
|
126599
|
+
}
|
|
126600
|
+
}
|
|
126601
|
+
|
|
126602
|
+
@supports not (height: 100cqh) {
|
|
126603
|
+
.toc-narrow {
|
|
126604
|
+
max-height: min(20rem, calc(100svh - 2rem));
|
|
126605
|
+
}
|
|
126606
|
+
.toc-narrow-scroll {
|
|
126607
|
+
max-height: min(18rem, calc(100svh - 5rem));
|
|
126608
|
+
}
|
|
126609
|
+
.toc-wide {
|
|
126610
|
+
max-height: calc(100svh - 3rem);
|
|
126283
126611
|
}
|
|
126284
126612
|
}
|
|
126285
126613
|
|
|
@@ -126475,26 +126803,41 @@ function useSectionTimeline() {
|
|
|
126475
126803
|
*
|
|
126476
126804
|
* 嵌套时自动检测父级 Context,只渲染内容不显示 ToC sidebar。
|
|
126477
126805
|
*/
|
|
126478
|
-
function MarkdownViewer({ markdown, className = "", onReady, collectToc = true }) {
|
|
126806
|
+
function MarkdownViewer({ markdown, className = "", onReady, collectToc = true, headingTransform, inlineTextAnnotations, blockAnnotations }) {
|
|
126479
126807
|
const isNested = !!useTocContext();
|
|
126480
126808
|
if (!collectToc) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlainMarkdownViewer, {
|
|
126481
126809
|
markdown,
|
|
126482
|
-
className
|
|
126810
|
+
className,
|
|
126811
|
+
headingTransform,
|
|
126812
|
+
inlineTextAnnotations,
|
|
126813
|
+
blockAnnotations
|
|
126483
126814
|
});
|
|
126484
126815
|
if (isNested) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NestedMarkdownViewer, {
|
|
126485
126816
|
markdown,
|
|
126486
|
-
className
|
|
126817
|
+
className,
|
|
126818
|
+
headingTransform,
|
|
126819
|
+
inlineTextAnnotations,
|
|
126820
|
+
blockAnnotations
|
|
126487
126821
|
});
|
|
126488
126822
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RootMarkdownViewer, {
|
|
126489
126823
|
markdown,
|
|
126490
126824
|
className,
|
|
126491
|
-
onReady
|
|
126825
|
+
onReady,
|
|
126826
|
+
headingTransform,
|
|
126827
|
+
inlineTextAnnotations,
|
|
126828
|
+
blockAnnotations
|
|
126492
126829
|
});
|
|
126493
126830
|
}
|
|
126494
|
-
function PlainMarkdownViewer({ markdown, className = "" }) {
|
|
126495
|
-
if (typeof markdown === "string") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
126831
|
+
function PlainMarkdownViewer({ markdown, className = "", headingTransform, inlineTextAnnotations, blockAnnotations }) {
|
|
126832
|
+
if (typeof markdown === "string") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StringMarkdownContent, {
|
|
126833
|
+
markdown,
|
|
126496
126834
|
className,
|
|
126497
|
-
|
|
126835
|
+
collector: new TocCollector(),
|
|
126836
|
+
levelOffset: 0,
|
|
126837
|
+
headingTransform,
|
|
126838
|
+
inlineTextAnnotations,
|
|
126839
|
+
blockAnnotations,
|
|
126840
|
+
collectToc: false
|
|
126498
126841
|
});
|
|
126499
126842
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlainBuilderMarkdownContent, {
|
|
126500
126843
|
builder: markdown,
|
|
@@ -126537,7 +126880,7 @@ function PlainBuilderMarkdownContent({ builder, className }) {
|
|
|
126537
126880
|
children: builder(components)
|
|
126538
126881
|
});
|
|
126539
126882
|
}
|
|
126540
|
-
function RootMarkdownViewer({ markdown, className, onReady }) {
|
|
126883
|
+
function RootMarkdownViewer({ markdown, className, onReady, headingTransform, inlineTextAnnotations, blockAnnotations }) {
|
|
126541
126884
|
const [tocItems, setTocItems] = (0, import_react.useState)([]);
|
|
126542
126885
|
const collectorRef = (0, import_react.useRef)(null);
|
|
126543
126886
|
const readyCalledRef = (0, import_react.useRef)(false);
|
|
@@ -126559,7 +126902,10 @@ function RootMarkdownViewer({ markdown, className, onReady }) {
|
|
|
126559
126902
|
const content = typeof markdown === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StringMarkdownContent, {
|
|
126560
126903
|
markdown,
|
|
126561
126904
|
collector,
|
|
126562
|
-
levelOffset: 0
|
|
126905
|
+
levelOffset: 0,
|
|
126906
|
+
headingTransform,
|
|
126907
|
+
inlineTextAnnotations,
|
|
126908
|
+
blockAnnotations
|
|
126563
126909
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderMarkdownContent, {
|
|
126564
126910
|
builder: markdown,
|
|
126565
126911
|
collector,
|
|
@@ -126572,27 +126918,30 @@ function RootMarkdownViewer({ markdown, className, onReady }) {
|
|
|
126572
126918
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
126573
126919
|
className: `@container-[size] h-full ${className}`,
|
|
126574
126920
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: viewerStyles }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(MarkdownContainer, {
|
|
126575
|
-
className: "viewer-scroll viewer-layout gap-6",
|
|
126921
|
+
className: "viewer-scroll toc-page-layout viewer-layout gap-6",
|
|
126576
126922
|
timelineScope,
|
|
126577
126923
|
enableHashNavigation: true,
|
|
126578
126924
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Toc, {
|
|
126579
126925
|
items: tocItems,
|
|
126580
|
-
className: "viewer-toc"
|
|
126926
|
+
className: "toc-page-sidebar viewer-toc"
|
|
126581
126927
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
126582
|
-
className: "viewer-content min-w-0",
|
|
126928
|
+
className: "toc-page-content viewer-content min-w-0",
|
|
126583
126929
|
children: content
|
|
126584
126930
|
})]
|
|
126585
126931
|
})]
|
|
126586
126932
|
})
|
|
126587
126933
|
});
|
|
126588
126934
|
}
|
|
126589
|
-
function NestedMarkdownViewer({ markdown, className }) {
|
|
126935
|
+
function NestedMarkdownViewer({ markdown, className, headingTransform, inlineTextAnnotations, blockAnnotations }) {
|
|
126590
126936
|
const { collector, levelOffset } = useTocContext();
|
|
126591
126937
|
return typeof markdown === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StringMarkdownContent, {
|
|
126592
126938
|
markdown,
|
|
126593
126939
|
className,
|
|
126594
126940
|
collector,
|
|
126595
|
-
levelOffset
|
|
126941
|
+
levelOffset,
|
|
126942
|
+
headingTransform,
|
|
126943
|
+
inlineTextAnnotations,
|
|
126944
|
+
blockAnnotations
|
|
126596
126945
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BuilderMarkdownContent, {
|
|
126597
126946
|
builder: markdown,
|
|
126598
126947
|
className,
|
|
@@ -126600,21 +126949,33 @@ function NestedMarkdownViewer({ markdown, className }) {
|
|
|
126600
126949
|
levelOffset
|
|
126601
126950
|
});
|
|
126602
126951
|
}
|
|
126603
|
-
function StringMarkdownContent({ markdown, collector, levelOffset, className }) {
|
|
126952
|
+
function StringMarkdownContent({ markdown, collector, levelOffset, className, headingTransform, inlineTextAnnotations, blockAnnotations, collectToc = true }) {
|
|
126604
126953
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownContent, {
|
|
126605
126954
|
className,
|
|
126606
126955
|
components: (0, import_react.useMemo)(() => {
|
|
126607
126956
|
const createHeading = (level) => {
|
|
126608
|
-
return function Heading({ children }) {
|
|
126957
|
+
return function Heading({ children, node }) {
|
|
126609
126958
|
const text = extractTextFromChildren(children);
|
|
126610
126959
|
const sectionTimelineIndex = useSectionTimeline();
|
|
126960
|
+
const sourceRange = getMarkdownNodeSourceRange(node);
|
|
126611
126961
|
const adjustedLevel = Math.min(level + levelOffset, 6);
|
|
126612
|
-
const
|
|
126962
|
+
const transform = headingTransform?.({
|
|
126963
|
+
sourceLevel: level,
|
|
126964
|
+
level: adjustedLevel,
|
|
126965
|
+
text,
|
|
126966
|
+
...sourceRange.start !== void 0 ? { sourceStartOffset: sourceRange.start } : {},
|
|
126967
|
+
...sourceRange.end !== void 0 ? { sourceEndOffset: sourceRange.end } : {}
|
|
126968
|
+
});
|
|
126969
|
+
const tocLabel = transform?.tocLabel ?? text;
|
|
126970
|
+
const registration = collectToc === false ? collector.add(tocLabel, adjustedLevel, transform?.id) : sectionTimelineIndex === null ? collector.add(tocLabel, adjustedLevel, transform?.id) : collector.bindSectionHeading(sectionTimelineIndex, tocLabel, adjustedLevel, transform?.id);
|
|
126613
126971
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeadingElement, {
|
|
126614
126972
|
level: adjustedLevel,
|
|
126615
126973
|
id: registration.id,
|
|
126616
126974
|
timelineIndex: registration.timelineIndex,
|
|
126617
|
-
bindTimeline: registration.binding === "heading",
|
|
126975
|
+
bindTimeline: collectToc !== false && registration.binding === "heading",
|
|
126976
|
+
className: transform?.className,
|
|
126977
|
+
dataAttributes: transform?.dataAttributes,
|
|
126978
|
+
suffix: transform?.suffix,
|
|
126618
126979
|
children
|
|
126619
126980
|
});
|
|
126620
126981
|
};
|
|
@@ -126627,19 +126988,27 @@ function StringMarkdownContent({ markdown, collector, levelOffset, className })
|
|
|
126627
126988
|
h5: createHeading(5),
|
|
126628
126989
|
h6: createHeading(6)
|
|
126629
126990
|
};
|
|
126630
|
-
}, [
|
|
126991
|
+
}, [
|
|
126992
|
+
collector,
|
|
126993
|
+
levelOffset,
|
|
126994
|
+
headingTransform,
|
|
126995
|
+
collectToc
|
|
126996
|
+
]),
|
|
126997
|
+
inlineTextAnnotations,
|
|
126998
|
+
blockAnnotations,
|
|
126631
126999
|
children: markdown
|
|
126632
127000
|
});
|
|
126633
127001
|
}
|
|
126634
127002
|
function BuilderMarkdownContent({ builder, collector, levelOffset, className }) {
|
|
126635
127003
|
const components = (0, import_react.useMemo)(() => {
|
|
126636
127004
|
const createHeading = (level) => {
|
|
126637
|
-
return function Heading({ id: fixedId, className, children }) {
|
|
127005
|
+
return function Heading({ id: fixedId, className, children, tocLabel }) {
|
|
126638
127006
|
const currentLevelOffset = useTocContext()?.levelOffset ?? levelOffset;
|
|
126639
127007
|
const sectionTimelineIndex = useSectionTimeline();
|
|
126640
127008
|
const text = extractTextFromChildren(children);
|
|
127009
|
+
const label = tocLabel ?? text;
|
|
126641
127010
|
const adjustedLevel = Math.min(level + currentLevelOffset, 6);
|
|
126642
|
-
const registration = sectionTimelineIndex === null ? collector.add(
|
|
127011
|
+
const registration = sectionTimelineIndex === null ? collector.add(label, adjustedLevel, fixedId) : collector.bindSectionHeading(sectionTimelineIndex, label, adjustedLevel, fixedId);
|
|
126643
127012
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(HeadingElement, {
|
|
126644
127013
|
level: adjustedLevel,
|
|
126645
127014
|
id: registration.id,
|
|
@@ -126686,44 +127055,74 @@ function SectionElement({ timelineIndex, children, className }) {
|
|
|
126686
127055
|
children
|
|
126687
127056
|
});
|
|
126688
127057
|
}
|
|
126689
|
-
function HeadingElement({ level, id, timelineIndex, bindTimeline = false, children, className }) {
|
|
127058
|
+
function HeadingElement({ level, id, timelineIndex, bindTimeline = false, children, suffix, className, dataAttributes }) {
|
|
126690
127059
|
const style = bindTimeline && timelineIndex !== void 0 ? { viewTimelineName: `--toc-${timelineIndex}` } : void 0;
|
|
126691
127060
|
switch (level) {
|
|
126692
|
-
case 1: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127061
|
+
case 1: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h1", {
|
|
126693
127062
|
id,
|
|
126694
127063
|
className,
|
|
126695
127064
|
style,
|
|
126696
|
-
|
|
127065
|
+
...dataAttributes,
|
|
127066
|
+
children: [
|
|
127067
|
+
children,
|
|
127068
|
+
suffix ? " " : null,
|
|
127069
|
+
suffix
|
|
127070
|
+
]
|
|
126697
127071
|
});
|
|
126698
|
-
case 2: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127072
|
+
case 2: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h2", {
|
|
126699
127073
|
id,
|
|
126700
127074
|
className,
|
|
126701
127075
|
style,
|
|
126702
|
-
|
|
127076
|
+
...dataAttributes,
|
|
127077
|
+
children: [
|
|
127078
|
+
children,
|
|
127079
|
+
suffix ? " " : null,
|
|
127080
|
+
suffix
|
|
127081
|
+
]
|
|
126703
127082
|
});
|
|
126704
|
-
case 3: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127083
|
+
case 3: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h3", {
|
|
126705
127084
|
id,
|
|
126706
127085
|
className,
|
|
126707
127086
|
style,
|
|
126708
|
-
|
|
127087
|
+
...dataAttributes,
|
|
127088
|
+
children: [
|
|
127089
|
+
children,
|
|
127090
|
+
suffix ? " " : null,
|
|
127091
|
+
suffix
|
|
127092
|
+
]
|
|
126709
127093
|
});
|
|
126710
|
-
case 4: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127094
|
+
case 4: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h4", {
|
|
126711
127095
|
id,
|
|
126712
127096
|
className,
|
|
126713
127097
|
style,
|
|
126714
|
-
|
|
127098
|
+
...dataAttributes,
|
|
127099
|
+
children: [
|
|
127100
|
+
children,
|
|
127101
|
+
suffix ? " " : null,
|
|
127102
|
+
suffix
|
|
127103
|
+
]
|
|
126715
127104
|
});
|
|
126716
|
-
case 5: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127105
|
+
case 5: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h5", {
|
|
126717
127106
|
id,
|
|
126718
127107
|
className,
|
|
126719
127108
|
style,
|
|
126720
|
-
|
|
127109
|
+
...dataAttributes,
|
|
127110
|
+
children: [
|
|
127111
|
+
children,
|
|
127112
|
+
suffix ? " " : null,
|
|
127113
|
+
suffix
|
|
127114
|
+
]
|
|
126721
127115
|
});
|
|
126722
|
-
case 6: return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
127116
|
+
case 6: return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("h6", {
|
|
126723
127117
|
id,
|
|
126724
127118
|
className,
|
|
126725
127119
|
style,
|
|
126726
|
-
|
|
127120
|
+
...dataAttributes,
|
|
127121
|
+
children: [
|
|
127122
|
+
children,
|
|
127123
|
+
suffix ? " " : null,
|
|
127124
|
+
suffix
|
|
127125
|
+
]
|
|
126727
127126
|
});
|
|
126728
127127
|
}
|
|
126729
127128
|
}
|
|
@@ -126759,6 +127158,24 @@ function extractTextFromChildren(children) {
|
|
|
126759
127158
|
if (typeof children === "object" && "props" in children) return extractTextFromChildren(children.props?.children);
|
|
126760
127159
|
return "";
|
|
126761
127160
|
}
|
|
127161
|
+
function getMarkdownNodeSourceRange(node) {
|
|
127162
|
+
if (!node || typeof node !== "object" || !("position" in node)) return {};
|
|
127163
|
+
const position = node.position;
|
|
127164
|
+
if (!position || typeof position !== "object") return {};
|
|
127165
|
+
const start = readMarkdownNodeOffset(position, "start");
|
|
127166
|
+
const end = readMarkdownNodeOffset(position, "end");
|
|
127167
|
+
return {
|
|
127168
|
+
...start !== void 0 ? { start } : {},
|
|
127169
|
+
...end !== void 0 ? { end } : {}
|
|
127170
|
+
};
|
|
127171
|
+
}
|
|
127172
|
+
function readMarkdownNodeOffset(position, key) {
|
|
127173
|
+
if (!(key in position)) return void 0;
|
|
127174
|
+
const point = position[key];
|
|
127175
|
+
if (!point || typeof point !== "object" || !("offset" in point)) return void 0;
|
|
127176
|
+
const offset = point.offset;
|
|
127177
|
+
return typeof offset === "number" ? offset : void 0;
|
|
127178
|
+
}
|
|
126762
127179
|
/** 比较两个 TocItem 数组是否相等 */
|
|
126763
127180
|
function arraysEqual(a, b) {
|
|
126764
127181
|
if (a.length !== b.length) return false;
|
|
@@ -126766,28 +127183,7 @@ function arraysEqual(a, b) {
|
|
|
126766
127183
|
}
|
|
126767
127184
|
/** CSS for container queries layout */
|
|
126768
127185
|
var viewerStyles = String.raw`
|
|
126769
|
-
/*
|
|
126770
|
-
.viewer-layout {
|
|
126771
|
-
display: block;
|
|
126772
|
-
}
|
|
126773
|
-
.viewer-toc {
|
|
126774
|
-
margin-bottom: 1rem;
|
|
126775
|
-
}
|
|
126776
|
-
|
|
126777
|
-
/* Wide container: grid layout with ToC on right */
|
|
126778
|
-
@container (min-width: 768px) {
|
|
126779
|
-
.viewer-layout {
|
|
126780
|
-
display: grid;
|
|
126781
|
-
grid-template-columns: minmax(0, 1fr) 180px;
|
|
126782
|
-
}
|
|
126783
|
-
.viewer-toc {
|
|
126784
|
-
order: 2;
|
|
126785
|
-
margin-bottom: 0;
|
|
126786
|
-
}
|
|
126787
|
-
.viewer-content {
|
|
126788
|
-
order: 1;
|
|
126789
|
-
}
|
|
126790
|
-
}
|
|
127186
|
+
/* MarkdownViewer keeps layout hooks local; shared ToC geometry lives in index.css. */
|
|
126791
127187
|
`;
|
|
126792
127188
|
//#endregion
|
|
126793
127189
|
//#region src/components/tabs.tsx
|
|
@@ -146156,8 +146552,11 @@ function ChangeList() {
|
|
|
146156
146552
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
146157
146553
|
className: "flex flex-col items-end gap-1 text-right text-sm",
|
|
146158
146554
|
children: [
|
|
146159
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
146160
|
-
|
|
146555
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
146556
|
+
tone: "custom",
|
|
146557
|
+
size: "sm",
|
|
146558
|
+
shape: "box",
|
|
146559
|
+
className: `border ${phase.toneClass}`,
|
|
146161
146560
|
children: phase.label
|
|
146162
146561
|
}),
|
|
146163
146562
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -149566,7 +149965,7 @@ function Switch({ checked, onCheckedChange, ariaLabel, id, name, required, disab
|
|
|
149566
149965
|
className: cn$1("inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border border-transparent p-0.5 outline-none transition-colors", "focus-visible:ring-primary focus-visible:ring-1", checked ? "border-primary bg-primary" : "bg-muted-foreground/30 hover:bg-muted-foreground/40", disabled && "cursor-not-allowed opacity-50", readOnly && !disabled && "cursor-default", className),
|
|
149567
149966
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
149568
149967
|
"aria-hidden": "true",
|
|
149569
|
-
className: cn$1("pointer-events-none block h-5 w-5 rounded-full bg-white
|
|
149968
|
+
className: cn$1("pointer-events-none block h-5 w-5 rounded-full bg-white transition-transform", checked ? "translate-x-5" : "translate-x-0", thumbClassName)
|
|
149570
149969
|
})
|
|
149571
149970
|
})] });
|
|
149572
149971
|
}
|
|
@@ -152565,8 +152964,11 @@ function DiffStat({ diff, className = "" }) {
|
|
|
152565
152964
|
}
|
|
152566
152965
|
function GitFilesBadge({ files }) {
|
|
152567
152966
|
if (files <= 0) return null;
|
|
152568
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
152569
|
-
|
|
152967
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
152968
|
+
tone: "custom",
|
|
152969
|
+
size: "xs",
|
|
152970
|
+
shape: "box",
|
|
152971
|
+
className: "h-auto min-w-0 border border-zinc-500/35 bg-zinc-500/10 px-[0.15rem] py-0 font-mono text-[10px] font-normal text-zinc-700 dark:border-zinc-300/40 dark:bg-zinc-300/15 dark:text-zinc-100",
|
|
152570
152972
|
children: [files, "f"]
|
|
152571
152973
|
});
|
|
152572
152974
|
}
|
|
@@ -153054,8 +153456,11 @@ function Dashboard() {
|
|
|
153054
153456
|
className: "text-xs font-semibold",
|
|
153055
153457
|
children: schema.schemaName
|
|
153056
153458
|
})
|
|
153057
|
-
}), schema.readyToArchive > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
153058
|
-
|
|
153459
|
+
}), schema.readyToArchive > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Badge, {
|
|
153460
|
+
tone: "custom",
|
|
153461
|
+
size: "xs",
|
|
153462
|
+
shape: "box",
|
|
153463
|
+
className: "text-muted-foreground border",
|
|
153059
153464
|
children: ["archive-ready ", schema.readyToArchive]
|
|
153060
153465
|
}) : null]
|
|
153061
153466
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -153351,8 +153756,11 @@ function Dashboard() {
|
|
|
153351
153756
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153352
153757
|
className: "shrink-0 text-right text-sm",
|
|
153353
153758
|
children: [
|
|
153354
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
153355
|
-
|
|
153759
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
153760
|
+
tone: "custom",
|
|
153761
|
+
size: "sm",
|
|
153762
|
+
shape: "box",
|
|
153763
|
+
className: `border ${phase.toneClass}`,
|
|
153356
153764
|
children: phase.label
|
|
153357
153765
|
}),
|
|
153358
153766
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -153802,6 +154210,1129 @@ function SpecList() {
|
|
|
153802
154210
|
});
|
|
153803
154211
|
}
|
|
153804
154212
|
//#endregion
|
|
154213
|
+
//#region ../core/src/markdown-facts.ts
|
|
154214
|
+
function toMarkdownFactKind(type) {
|
|
154215
|
+
switch (type) {
|
|
154216
|
+
case "root":
|
|
154217
|
+
case "heading":
|
|
154218
|
+
case "paragraph":
|
|
154219
|
+
case "list":
|
|
154220
|
+
case "listItem":
|
|
154221
|
+
case "blockquote":
|
|
154222
|
+
case "table":
|
|
154223
|
+
case "tableRow":
|
|
154224
|
+
case "tableCell":
|
|
154225
|
+
case "code":
|
|
154226
|
+
case "thematicBreak":
|
|
154227
|
+
case "html":
|
|
154228
|
+
case "definition":
|
|
154229
|
+
case "footnoteDefinition": return type;
|
|
154230
|
+
default: return "unknown";
|
|
154231
|
+
}
|
|
154232
|
+
}
|
|
154233
|
+
function parseMarkdownFacts(sourceMarkdown) {
|
|
154234
|
+
const root = fromMarkdown(sourceMarkdown, {
|
|
154235
|
+
extensions: [gfm()],
|
|
154236
|
+
mdastExtensions: [gfmFromMarkdown()]
|
|
154237
|
+
});
|
|
154238
|
+
const facts = [];
|
|
154239
|
+
const nodeIdByNode = /* @__PURE__ */ new Map();
|
|
154240
|
+
const visit = (node, parentId) => {
|
|
154241
|
+
const fact = createFact(node, sourceMarkdown, facts.length, parentId);
|
|
154242
|
+
facts.push(fact);
|
|
154243
|
+
nodeIdByNode.set(node, fact.id);
|
|
154244
|
+
if (isParentNode(node)) for (const child of node.children) {
|
|
154245
|
+
if (!isSupportedNode(child)) continue;
|
|
154246
|
+
visit(child, fact.id);
|
|
154247
|
+
const childId = nodeIdByNode.get(child);
|
|
154248
|
+
if (childId) fact.children.push(childId);
|
|
154249
|
+
}
|
|
154250
|
+
};
|
|
154251
|
+
visit(root);
|
|
154252
|
+
return {
|
|
154253
|
+
sourceMarkdown,
|
|
154254
|
+
rootId: "md-1",
|
|
154255
|
+
facts
|
|
154256
|
+
};
|
|
154257
|
+
}
|
|
154258
|
+
function createFact(node, sourceMarkdown, index, parentId) {
|
|
154259
|
+
const base = {
|
|
154260
|
+
id: `md-${index + 1}`,
|
|
154261
|
+
kind: toMarkdownFactKind(node.type),
|
|
154262
|
+
mdastType: node.type,
|
|
154263
|
+
text: getNodeText(node),
|
|
154264
|
+
children: [],
|
|
154265
|
+
range: toSourceRange(sourceMarkdown, node.position),
|
|
154266
|
+
...parentId ? { parentId } : {}
|
|
154267
|
+
};
|
|
154268
|
+
switch (node.type) {
|
|
154269
|
+
case "heading": return {
|
|
154270
|
+
...base,
|
|
154271
|
+
depth: node.depth
|
|
154272
|
+
};
|
|
154273
|
+
case "list": return {
|
|
154274
|
+
...base,
|
|
154275
|
+
ordered: Boolean(node.ordered)
|
|
154276
|
+
};
|
|
154277
|
+
case "listItem": return {
|
|
154278
|
+
...base,
|
|
154279
|
+
...typeof node.checked === "boolean" ? { checked: node.checked } : {}
|
|
154280
|
+
};
|
|
154281
|
+
case "code": return {
|
|
154282
|
+
...base,
|
|
154283
|
+
text: node.value,
|
|
154284
|
+
value: node.value,
|
|
154285
|
+
...node.lang ? { language: node.lang } : {}
|
|
154286
|
+
};
|
|
154287
|
+
case "html": return {
|
|
154288
|
+
...base,
|
|
154289
|
+
value: node.value
|
|
154290
|
+
};
|
|
154291
|
+
default: return base;
|
|
154292
|
+
}
|
|
154293
|
+
}
|
|
154294
|
+
function toSourceRange(sourceMarkdown, position) {
|
|
154295
|
+
if (!position) return void 0;
|
|
154296
|
+
const startOffset = position.start.offset;
|
|
154297
|
+
const endOffset = position.end.offset;
|
|
154298
|
+
const rawMarkdown = typeof startOffset === "number" && typeof endOffset === "number" ? sourceMarkdown.slice(startOffset, endOffset) : "";
|
|
154299
|
+
return {
|
|
154300
|
+
start: {
|
|
154301
|
+
line: position.start.line,
|
|
154302
|
+
column: position.start.column,
|
|
154303
|
+
...typeof startOffset === "number" ? { offset: startOffset } : {}
|
|
154304
|
+
},
|
|
154305
|
+
end: {
|
|
154306
|
+
line: position.end.line,
|
|
154307
|
+
column: position.end.column,
|
|
154308
|
+
...typeof endOffset === "number" ? { offset: endOffset } : {}
|
|
154309
|
+
},
|
|
154310
|
+
rawMarkdown
|
|
154311
|
+
};
|
|
154312
|
+
}
|
|
154313
|
+
function getNodeText(node) {
|
|
154314
|
+
if (node.type === "code" || node.type === "html") return node.value;
|
|
154315
|
+
return toString$1(node, {
|
|
154316
|
+
includeHtml: true,
|
|
154317
|
+
includeImageAlt: true
|
|
154318
|
+
}).trim();
|
|
154319
|
+
}
|
|
154320
|
+
function isParentNode(node) {
|
|
154321
|
+
return Array.isArray(node.children);
|
|
154322
|
+
}
|
|
154323
|
+
function isSupportedNode(node) {
|
|
154324
|
+
switch (node.type) {
|
|
154325
|
+
case "blockquote":
|
|
154326
|
+
case "code":
|
|
154327
|
+
case "definition":
|
|
154328
|
+
case "footnoteDefinition":
|
|
154329
|
+
case "heading":
|
|
154330
|
+
case "html":
|
|
154331
|
+
case "list":
|
|
154332
|
+
case "listItem":
|
|
154333
|
+
case "paragraph":
|
|
154334
|
+
case "table":
|
|
154335
|
+
case "tableRow":
|
|
154336
|
+
case "tableCell":
|
|
154337
|
+
case "thematicBreak": return true;
|
|
154338
|
+
default: return isParentNode(node);
|
|
154339
|
+
}
|
|
154340
|
+
}
|
|
154341
|
+
//#endregion
|
|
154342
|
+
//#region ../core/src/markdown-reading.ts
|
|
154343
|
+
function createMarkdownReadingDocument(sourceMarkdown, plugins = []) {
|
|
154344
|
+
return createMarkdownReadingDocumentFromFacts(parseMarkdownFacts(sourceMarkdown), plugins);
|
|
154345
|
+
}
|
|
154346
|
+
function createMarkdownReadingDocumentFromFacts(factsDocument, plugins = []) {
|
|
154347
|
+
const lookup = createLookup(factsDocument);
|
|
154348
|
+
const annotations = [];
|
|
154349
|
+
for (const rule of plugins.flatMap((plugin) => plugin.annotationRules ?? [])) {
|
|
154350
|
+
const context = createAnnotationContext(lookup, annotations);
|
|
154351
|
+
for (const input of rule.annotate(context)) annotations.push({
|
|
154352
|
+
id: `${rule.id}:${annotations.length + 1}`,
|
|
154353
|
+
ruleId: rule.id,
|
|
154354
|
+
kind: input.kind,
|
|
154355
|
+
targetFactId: input.targetFactId,
|
|
154356
|
+
...input.sourceSpan ? { sourceSpan: input.sourceSpan } : {},
|
|
154357
|
+
...input.textSpan ? { textSpan: input.textSpan } : {},
|
|
154358
|
+
confidence: input.confidence,
|
|
154359
|
+
...input.metadata ? { metadata: input.metadata } : {}
|
|
154360
|
+
});
|
|
154361
|
+
}
|
|
154362
|
+
const projections = {};
|
|
154363
|
+
for (const rule of plugins.flatMap((plugin) => plugin.projectionRules ?? [])) {
|
|
154364
|
+
const context = createProjectionContext(lookup, annotations, projections);
|
|
154365
|
+
const output = rule.project(context);
|
|
154366
|
+
if (output !== void 0) projections[rule.id] = output;
|
|
154367
|
+
}
|
|
154368
|
+
return {
|
|
154369
|
+
...factsDocument,
|
|
154370
|
+
annotations,
|
|
154371
|
+
projections
|
|
154372
|
+
};
|
|
154373
|
+
}
|
|
154374
|
+
function getMarkdownFactSpan(fact) {
|
|
154375
|
+
const start = fact.range?.start.offset;
|
|
154376
|
+
const end = fact.range?.end.offset;
|
|
154377
|
+
if (typeof start !== "number" || typeof end !== "number") return void 0;
|
|
154378
|
+
return {
|
|
154379
|
+
start,
|
|
154380
|
+
end
|
|
154381
|
+
};
|
|
154382
|
+
}
|
|
154383
|
+
function trimMarkdownSlice(sourceMarkdown, start, end) {
|
|
154384
|
+
return sourceMarkdown.slice(start, Math.max(start, end)).trim();
|
|
154385
|
+
}
|
|
154386
|
+
function getMarkdownHeadingFacts(document) {
|
|
154387
|
+
return document.facts.filter((fact) => fact.kind === "heading" && typeof fact.depth === "number");
|
|
154388
|
+
}
|
|
154389
|
+
function getMarkdownHeadingEnd(headings, index, sourceLength) {
|
|
154390
|
+
const heading = headings[index];
|
|
154391
|
+
if (!heading) return sourceLength;
|
|
154392
|
+
const headingDepth = heading.depth ?? 6;
|
|
154393
|
+
for (let i = index + 1; i < headings.length; i++) {
|
|
154394
|
+
const next = headings[i];
|
|
154395
|
+
if (next && (next.depth ?? 6) <= headingDepth) return getMarkdownFactSpan(next)?.start ?? sourceLength;
|
|
154396
|
+
}
|
|
154397
|
+
return sourceLength;
|
|
154398
|
+
}
|
|
154399
|
+
function getMarkdownAnnotationsForFact(annotations, factId, kind) {
|
|
154400
|
+
return annotations.filter((annotation) => annotation.targetFactId === factId && (!kind || annotation.kind === kind));
|
|
154401
|
+
}
|
|
154402
|
+
function getMarkdownAnnotation(annotations, factId, kind) {
|
|
154403
|
+
return annotations.find((annotation) => annotation.targetFactId === factId && annotation.kind === kind);
|
|
154404
|
+
}
|
|
154405
|
+
function buildMarkdownParentMap(facts) {
|
|
154406
|
+
const factById = new Map(facts.map((fact) => [fact.id, fact]));
|
|
154407
|
+
const parentById = /* @__PURE__ */ new Map();
|
|
154408
|
+
for (const fact of facts) {
|
|
154409
|
+
if (!fact.parentId) continue;
|
|
154410
|
+
const parent = factById.get(fact.parentId);
|
|
154411
|
+
if (parent) parentById.set(fact.id, parent);
|
|
154412
|
+
}
|
|
154413
|
+
return parentById;
|
|
154414
|
+
}
|
|
154415
|
+
function createLookup(document) {
|
|
154416
|
+
return {
|
|
154417
|
+
sourceMarkdown: document.sourceMarkdown,
|
|
154418
|
+
rootId: document.rootId,
|
|
154419
|
+
facts: document.facts,
|
|
154420
|
+
factById: new Map(document.facts.map((fact) => [fact.id, fact])),
|
|
154421
|
+
parentById: buildMarkdownParentMap(document.facts)
|
|
154422
|
+
};
|
|
154423
|
+
}
|
|
154424
|
+
function createAnnotationContext(lookup, previousAnnotations) {
|
|
154425
|
+
return {
|
|
154426
|
+
...lookup,
|
|
154427
|
+
previousAnnotations,
|
|
154428
|
+
getAnnotationsForFact: (factId, kind) => getMarkdownAnnotationsForFact(previousAnnotations, factId, kind),
|
|
154429
|
+
getAnnotation: (factId, kind) => getMarkdownAnnotation(previousAnnotations, factId, kind)
|
|
154430
|
+
};
|
|
154431
|
+
}
|
|
154432
|
+
function createProjectionContext(lookup, annotations, projections) {
|
|
154433
|
+
return {
|
|
154434
|
+
...lookup,
|
|
154435
|
+
annotations,
|
|
154436
|
+
projections,
|
|
154437
|
+
getAnnotationsForFact: (factId, kind) => getMarkdownAnnotationsForFact(annotations, factId, kind),
|
|
154438
|
+
getAnnotation: (factId, kind) => getMarkdownAnnotation(annotations, factId, kind)
|
|
154439
|
+
};
|
|
154440
|
+
}
|
|
154441
|
+
//#endregion
|
|
154442
|
+
//#region ../core/src/openspec-annotations.ts
|
|
154443
|
+
var OPEN_SPEC_ANNOTATION_RULES = {
|
|
154444
|
+
documentTitle: "openspec.heading.document-title.v2",
|
|
154445
|
+
purposeSection: "openspec.heading.purpose-section.v2",
|
|
154446
|
+
requirementsSection: "openspec.heading.requirements-section.v2",
|
|
154447
|
+
requirementPrefix: "openspec.heading.requirement-prefix.v2",
|
|
154448
|
+
requirementUnderSection: "openspec.heading.requirement-under-section.v2",
|
|
154449
|
+
requirementCapabilityPrefix: "openspec.heading.capability-prefix.v2",
|
|
154450
|
+
requirementCapabilityText: "openspec.heading.capability-text.v2",
|
|
154451
|
+
scenarioPrefix: "openspec.heading.scenario-prefix.v2",
|
|
154452
|
+
scenarioExamplePrefix: "openspec.heading.example-prefix.v2",
|
|
154453
|
+
scenarioStepHeading: "openspec.heading.step-backed-scenario.v2",
|
|
154454
|
+
scenarioStep: "openspec.list-item.scenario-step.v2",
|
|
154455
|
+
keyword: "openspec.inline.keyword.v2"
|
|
154456
|
+
};
|
|
154457
|
+
var REQUIREMENT_PREFIX_PATTERN = /^(?:Requirement|Capability):\s*/i;
|
|
154458
|
+
var SCENARIO_PREFIX_PATTERN = /^(?:Scenario|Example):\s*/i;
|
|
154459
|
+
var SCENARIO_STEP_KEYWORDS = [
|
|
154460
|
+
"GIVEN",
|
|
154461
|
+
"WHEN",
|
|
154462
|
+
"THEN",
|
|
154463
|
+
"AND",
|
|
154464
|
+
"BUT"
|
|
154465
|
+
];
|
|
154466
|
+
var REQUIREMENT_KEYWORD_PATTERN = new RegExp(`\\b(${[
|
|
154467
|
+
"SHALL",
|
|
154468
|
+
"MUST",
|
|
154469
|
+
"SHOULD",
|
|
154470
|
+
"MAY"
|
|
154471
|
+
].join("|")})\\b`, "g");
|
|
154472
|
+
var SCENARIO_STEP_PATTERN = new RegExp(`^\\s*(?:[-*+]\\s+)?(?:\\[[ xX]\\]\\s+)?(?:\\*\\*)?(${SCENARIO_STEP_KEYWORDS.join("|")})\\b(?:\\*\\*)?\\s*:?\\s*(.+?)\\s*$`, "i");
|
|
154473
|
+
var REQUIREMENT_SECTION_TERMS = [
|
|
154474
|
+
"requirement",
|
|
154475
|
+
"specification",
|
|
154476
|
+
"capability",
|
|
154477
|
+
"capabilities"
|
|
154478
|
+
];
|
|
154479
|
+
var PURPOSE_SECTION_TERMS = [
|
|
154480
|
+
"purpose",
|
|
154481
|
+
"overview",
|
|
154482
|
+
"objective",
|
|
154483
|
+
"goal",
|
|
154484
|
+
"goals"
|
|
154485
|
+
];
|
|
154486
|
+
var REQUIREMENT_BODY_SIGNAL_PATTERN = /\b(SHALL|MUST|SHOULD|MAY|CAN|WILL)\b/i;
|
|
154487
|
+
var NON_SCENARIO_HEADING_PATTERN = /^(notes?|details?|rationale|reason|migration|examples?|open questions?)$/i;
|
|
154488
|
+
var builtinOpenSpecReadingPlugin = {
|
|
154489
|
+
id: "openspec.builtin-reading.v2",
|
|
154490
|
+
annotationRules: [
|
|
154491
|
+
{
|
|
154492
|
+
id: OPEN_SPEC_ANNOTATION_RULES.documentTitle,
|
|
154493
|
+
annotate(context) {
|
|
154494
|
+
return context.facts.flatMap((fact) => {
|
|
154495
|
+
if (fact.kind !== "heading" || fact.depth !== 1) return [];
|
|
154496
|
+
return [{
|
|
154497
|
+
kind: "document-title",
|
|
154498
|
+
targetFactId: fact.id,
|
|
154499
|
+
confidence: "strong",
|
|
154500
|
+
metadata: { title: fact.text }
|
|
154501
|
+
}];
|
|
154502
|
+
});
|
|
154503
|
+
}
|
|
154504
|
+
},
|
|
154505
|
+
{
|
|
154506
|
+
id: OPEN_SPEC_ANNOTATION_RULES.purposeSection,
|
|
154507
|
+
annotate(context) {
|
|
154508
|
+
return context.facts.flatMap((fact) => {
|
|
154509
|
+
if (fact.kind !== "heading" || fact.depth !== 2) return [];
|
|
154510
|
+
if (!matchesAnyTerm(fact.text, PURPOSE_SECTION_TERMS)) return [];
|
|
154511
|
+
return [{
|
|
154512
|
+
kind: "purpose-section",
|
|
154513
|
+
targetFactId: fact.id,
|
|
154514
|
+
confidence: isExactTerm(fact.text, ["Purpose", "Overview"]) ? "strong" : "weak",
|
|
154515
|
+
metadata: { title: fact.text }
|
|
154516
|
+
}];
|
|
154517
|
+
});
|
|
154518
|
+
}
|
|
154519
|
+
},
|
|
154520
|
+
{
|
|
154521
|
+
id: OPEN_SPEC_ANNOTATION_RULES.requirementsSection,
|
|
154522
|
+
annotate(context) {
|
|
154523
|
+
return context.facts.flatMap((fact) => {
|
|
154524
|
+
if (fact.kind !== "heading" || fact.depth !== 2) return [];
|
|
154525
|
+
if (!matchesAnyTerm(fact.text, REQUIREMENT_SECTION_TERMS)) return [];
|
|
154526
|
+
return [{
|
|
154527
|
+
kind: "requirements-section",
|
|
154528
|
+
targetFactId: fact.id,
|
|
154529
|
+
confidence: fact.text.toLowerCase().includes("requirement") ? "strong" : "weak",
|
|
154530
|
+
metadata: { title: fact.text }
|
|
154531
|
+
}];
|
|
154532
|
+
});
|
|
154533
|
+
}
|
|
154534
|
+
},
|
|
154535
|
+
{
|
|
154536
|
+
id: OPEN_SPEC_ANNOTATION_RULES.requirementPrefix,
|
|
154537
|
+
annotate(context) {
|
|
154538
|
+
return context.facts.flatMap((fact) => {
|
|
154539
|
+
if (fact.kind !== "heading" || fact.depth !== 3) return [];
|
|
154540
|
+
if (!/^Requirement:\s*/i.test(fact.text)) return [];
|
|
154541
|
+
return [createRequirementAnnotation(fact, "strong")];
|
|
154542
|
+
});
|
|
154543
|
+
}
|
|
154544
|
+
},
|
|
154545
|
+
{
|
|
154546
|
+
id: OPEN_SPEC_ANNOTATION_RULES.requirementCapabilityPrefix,
|
|
154547
|
+
annotate(context) {
|
|
154548
|
+
return context.facts.flatMap((fact) => {
|
|
154549
|
+
if (fact.kind !== "heading" || fact.depth !== 3) return [];
|
|
154550
|
+
if (!/^Capability:\s*/i.test(fact.text)) return [];
|
|
154551
|
+
return [createRequirementAnnotation(fact, "weak")];
|
|
154552
|
+
});
|
|
154553
|
+
}
|
|
154554
|
+
},
|
|
154555
|
+
{
|
|
154556
|
+
id: OPEN_SPEC_ANNOTATION_RULES.requirementUnderSection,
|
|
154557
|
+
annotate(context) {
|
|
154558
|
+
return getRequirementSections(context).flatMap((section) => {
|
|
154559
|
+
return getChildHeadings(context, section, 3).flatMap((fact) => {
|
|
154560
|
+
if (context.getAnnotation(fact.id, "requirement")) return [];
|
|
154561
|
+
if (REQUIREMENT_PREFIX_PATTERN.test(fact.text)) return [];
|
|
154562
|
+
if (!hasRequirementBodySignals(context, fact, section.end)) return [];
|
|
154563
|
+
return [{
|
|
154564
|
+
kind: "requirement",
|
|
154565
|
+
targetFactId: fact.id,
|
|
154566
|
+
confidence: "weak",
|
|
154567
|
+
metadata: { title: fact.text }
|
|
154568
|
+
}];
|
|
154569
|
+
});
|
|
154570
|
+
});
|
|
154571
|
+
}
|
|
154572
|
+
},
|
|
154573
|
+
{
|
|
154574
|
+
id: OPEN_SPEC_ANNOTATION_RULES.requirementCapabilityText,
|
|
154575
|
+
annotate(context) {
|
|
154576
|
+
return getRequirementSections(context).flatMap((section) => {
|
|
154577
|
+
return getChildHeadings(context, section, 3).flatMap((fact) => {
|
|
154578
|
+
if (context.getAnnotation(fact.id, "requirement")) return [];
|
|
154579
|
+
if (!matchesAnyTerm(fact.text, [
|
|
154580
|
+
"capability",
|
|
154581
|
+
"feature",
|
|
154582
|
+
"behavior"
|
|
154583
|
+
])) return [];
|
|
154584
|
+
return [{
|
|
154585
|
+
kind: "requirement",
|
|
154586
|
+
targetFactId: fact.id,
|
|
154587
|
+
confidence: "weak",
|
|
154588
|
+
metadata: { title: stripRequirementPrefix(fact.text) || fact.text }
|
|
154589
|
+
}];
|
|
154590
|
+
});
|
|
154591
|
+
});
|
|
154592
|
+
}
|
|
154593
|
+
},
|
|
154594
|
+
{
|
|
154595
|
+
id: OPEN_SPEC_ANNOTATION_RULES.scenarioPrefix,
|
|
154596
|
+
annotate(context) {
|
|
154597
|
+
return getRequirementHeadings(context).flatMap((requirement) => {
|
|
154598
|
+
return getNestedHeadings(context, requirement).flatMap((fact) => {
|
|
154599
|
+
if (fact.depth !== 4 || !/^Scenario:\s*/i.test(fact.text)) return [];
|
|
154600
|
+
return [createScenarioAnnotation(fact, "strong")];
|
|
154601
|
+
});
|
|
154602
|
+
});
|
|
154603
|
+
}
|
|
154604
|
+
},
|
|
154605
|
+
{
|
|
154606
|
+
id: OPEN_SPEC_ANNOTATION_RULES.scenarioExamplePrefix,
|
|
154607
|
+
annotate(context) {
|
|
154608
|
+
return getRequirementHeadings(context).flatMap((requirement) => {
|
|
154609
|
+
return getNestedHeadings(context, requirement).flatMap((fact) => {
|
|
154610
|
+
if (fact.depth !== 4 || !/^Example:\s*/i.test(fact.text)) return [];
|
|
154611
|
+
return [createScenarioAnnotation(fact, "weak")];
|
|
154612
|
+
});
|
|
154613
|
+
});
|
|
154614
|
+
}
|
|
154615
|
+
},
|
|
154616
|
+
{
|
|
154617
|
+
id: OPEN_SPEC_ANNOTATION_RULES.scenarioStepHeading,
|
|
154618
|
+
annotate(context) {
|
|
154619
|
+
return getRequirementHeadings(context).flatMap((requirement) => {
|
|
154620
|
+
return getNestedHeadings(context, requirement).flatMap((fact) => {
|
|
154621
|
+
if (fact.depth !== 4) return [];
|
|
154622
|
+
if (context.getAnnotation(fact.id, "scenario")) return [];
|
|
154623
|
+
if (NON_SCENARIO_HEADING_PATTERN.test(fact.text)) return [];
|
|
154624
|
+
if (!hasScenarioStepSignals(context, fact)) return [];
|
|
154625
|
+
return [{
|
|
154626
|
+
kind: "scenario",
|
|
154627
|
+
targetFactId: fact.id,
|
|
154628
|
+
confidence: "weak",
|
|
154629
|
+
metadata: { title: stripScenarioPrefix(fact.text) || fact.text }
|
|
154630
|
+
}];
|
|
154631
|
+
});
|
|
154632
|
+
});
|
|
154633
|
+
}
|
|
154634
|
+
},
|
|
154635
|
+
{
|
|
154636
|
+
id: OPEN_SPEC_ANNOTATION_RULES.scenarioStep,
|
|
154637
|
+
annotate(context) {
|
|
154638
|
+
const scenarioSections = getScenarioSections(context);
|
|
154639
|
+
return context.facts.flatMap((fact) => {
|
|
154640
|
+
if (fact.kind !== "listItem") return [];
|
|
154641
|
+
if (!isWithinAnySection(fact, scenarioSections)) return [];
|
|
154642
|
+
const metadata = parseScenarioStepFact(fact);
|
|
154643
|
+
if (!metadata) return [];
|
|
154644
|
+
return [{
|
|
154645
|
+
kind: "scenario-step",
|
|
154646
|
+
targetFactId: fact.id,
|
|
154647
|
+
confidence: "strong",
|
|
154648
|
+
metadata
|
|
154649
|
+
}];
|
|
154650
|
+
});
|
|
154651
|
+
}
|
|
154652
|
+
},
|
|
154653
|
+
{
|
|
154654
|
+
id: OPEN_SPEC_ANNOTATION_RULES.keyword,
|
|
154655
|
+
annotate(context) {
|
|
154656
|
+
const scenarioKeywordAnnotations = context.previousAnnotations.flatMap((annotation) => {
|
|
154657
|
+
if (annotation.kind !== "scenario-step") return [];
|
|
154658
|
+
const fact = context.factById.get(annotation.targetFactId);
|
|
154659
|
+
if (!fact) return [];
|
|
154660
|
+
return findScenarioStepKeyword(fact, readAnnotationKeyword(annotation.metadata));
|
|
154661
|
+
});
|
|
154662
|
+
const requirementKeywordAnnotations = context.facts.flatMap((fact) => {
|
|
154663
|
+
if (!canAnnotateInlineKeywords(fact)) return [];
|
|
154664
|
+
return findRequirementKeywords(fact);
|
|
154665
|
+
});
|
|
154666
|
+
return [...scenarioKeywordAnnotations, ...requirementKeywordAnnotations];
|
|
154667
|
+
}
|
|
154668
|
+
}
|
|
154669
|
+
]
|
|
154670
|
+
};
|
|
154671
|
+
function createRequirementAnnotation(fact, confidence) {
|
|
154672
|
+
return {
|
|
154673
|
+
kind: "requirement",
|
|
154674
|
+
targetFactId: fact.id,
|
|
154675
|
+
confidence,
|
|
154676
|
+
metadata: { title: stripRequirementPrefix(fact.text) || fact.text }
|
|
154677
|
+
};
|
|
154678
|
+
}
|
|
154679
|
+
function createScenarioAnnotation(fact, confidence) {
|
|
154680
|
+
return {
|
|
154681
|
+
kind: "scenario",
|
|
154682
|
+
targetFactId: fact.id,
|
|
154683
|
+
confidence,
|
|
154684
|
+
metadata: { title: stripScenarioPrefix(fact.text) || "Scenario" }
|
|
154685
|
+
};
|
|
154686
|
+
}
|
|
154687
|
+
function matchesAnyTerm(text, terms) {
|
|
154688
|
+
const normalized = text.toLowerCase();
|
|
154689
|
+
return terms.some((term) => normalized.includes(term));
|
|
154690
|
+
}
|
|
154691
|
+
function isExactTerm(text, terms) {
|
|
154692
|
+
const normalized = text.trim().toLowerCase();
|
|
154693
|
+
return terms.some((term) => normalized === term.toLowerCase());
|
|
154694
|
+
}
|
|
154695
|
+
function stripRequirementPrefix(text) {
|
|
154696
|
+
return text.replace(REQUIREMENT_PREFIX_PATTERN, "").trim();
|
|
154697
|
+
}
|
|
154698
|
+
function stripScenarioPrefix(text) {
|
|
154699
|
+
return text.replace(SCENARIO_PREFIX_PATTERN, "").trim();
|
|
154700
|
+
}
|
|
154701
|
+
function getHeadingSections(context) {
|
|
154702
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154703
|
+
return headings.reduce((sections, fact, index) => {
|
|
154704
|
+
const span = getMarkdownFactSpan(fact);
|
|
154705
|
+
if (!span) return sections;
|
|
154706
|
+
sections.push({
|
|
154707
|
+
fact,
|
|
154708
|
+
start: span.start,
|
|
154709
|
+
end: getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length)
|
|
154710
|
+
});
|
|
154711
|
+
return sections;
|
|
154712
|
+
}, []);
|
|
154713
|
+
}
|
|
154714
|
+
function getRequirementSections(context) {
|
|
154715
|
+
return getHeadingSections(context).filter((section) => context.getAnnotation(section.fact.id, "requirements-section"));
|
|
154716
|
+
}
|
|
154717
|
+
function getChildHeadings(context, section, depth) {
|
|
154718
|
+
return getMarkdownHeadingFacts(context).filter((fact) => {
|
|
154719
|
+
if (fact.depth !== depth) return false;
|
|
154720
|
+
const span = getMarkdownFactSpan(fact);
|
|
154721
|
+
return !!span && span.start > section.start && span.start < section.end;
|
|
154722
|
+
});
|
|
154723
|
+
}
|
|
154724
|
+
function getRequirementHeadings(context) {
|
|
154725
|
+
return getMarkdownHeadingFacts(context).filter((fact) => context.getAnnotation(fact.id, "requirement"));
|
|
154726
|
+
}
|
|
154727
|
+
function getNestedHeadings(context, parentHeading) {
|
|
154728
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154729
|
+
const parentIndex = headings.findIndex((fact) => fact.id === parentHeading.id);
|
|
154730
|
+
const parentSpan = getMarkdownFactSpan(parentHeading);
|
|
154731
|
+
if (parentIndex < 0 || !parentSpan) return [];
|
|
154732
|
+
const end = getMarkdownHeadingEnd(headings, parentIndex, context.sourceMarkdown.length);
|
|
154733
|
+
return headings.filter((fact) => {
|
|
154734
|
+
const span = getMarkdownFactSpan(fact);
|
|
154735
|
+
return !!span && span.start > parentSpan.start && span.start < end;
|
|
154736
|
+
});
|
|
154737
|
+
}
|
|
154738
|
+
function getScenarioSections(context) {
|
|
154739
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154740
|
+
return getHeadingSections(context).filter((section) => {
|
|
154741
|
+
if (!context.getAnnotation(section.fact.id, "scenario")) return false;
|
|
154742
|
+
if (NON_SCENARIO_HEADING_PATTERN.test(section.fact.text)) return false;
|
|
154743
|
+
return headings.findIndex((fact) => fact.id === section.fact.id) >= 0;
|
|
154744
|
+
});
|
|
154745
|
+
}
|
|
154746
|
+
function hasRequirementBodySignals(context, requirementHeading, sectionEnd) {
|
|
154747
|
+
const span = getMarkdownFactSpan(requirementHeading);
|
|
154748
|
+
if (!span) return false;
|
|
154749
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154750
|
+
const index = headings.findIndex((fact) => fact.id === requirementHeading.id);
|
|
154751
|
+
const end = index >= 0 ? getMarkdownHeadingEnd(headings, index, sectionEnd) : sectionEnd;
|
|
154752
|
+
const body = context.sourceMarkdown.slice(span.end, Math.min(end, sectionEnd));
|
|
154753
|
+
return REQUIREMENT_BODY_SIGNAL_PATTERN.test(body);
|
|
154754
|
+
}
|
|
154755
|
+
function hasScenarioStepSignals(context, scenarioHeading) {
|
|
154756
|
+
const span = getMarkdownFactSpan(scenarioHeading);
|
|
154757
|
+
if (!span) return false;
|
|
154758
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154759
|
+
const index = headings.findIndex((fact) => fact.id === scenarioHeading.id);
|
|
154760
|
+
const end = index >= 0 ? getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length) : context.sourceMarkdown.length;
|
|
154761
|
+
return context.sourceMarkdown.slice(span.end, end).split("\n").some((line) => SCENARIO_STEP_PATTERN.test(line));
|
|
154762
|
+
}
|
|
154763
|
+
function isWithinAnySection(fact, sections) {
|
|
154764
|
+
const span = getMarkdownFactSpan(fact);
|
|
154765
|
+
if (!span) return false;
|
|
154766
|
+
return sections.some((section) => span.start > section.start && span.start < section.end);
|
|
154767
|
+
}
|
|
154768
|
+
function parseScenarioStepFact(fact) {
|
|
154769
|
+
const rawMarkdown = fact.range?.rawMarkdown.trim() || fact.text;
|
|
154770
|
+
const match = rawMarkdown.match(SCENARIO_STEP_PATTERN) ?? fact.text.match(SCENARIO_STEP_PATTERN);
|
|
154771
|
+
if (!match) return void 0;
|
|
154772
|
+
return {
|
|
154773
|
+
keyword: match[1].toUpperCase(),
|
|
154774
|
+
contentMarkdown: match[2].trim(),
|
|
154775
|
+
rawMarkdown
|
|
154776
|
+
};
|
|
154777
|
+
}
|
|
154778
|
+
function canAnnotateInlineKeywords(fact) {
|
|
154779
|
+
return fact.kind === "paragraph" || fact.kind === "listItem" || fact.kind === "heading" || fact.kind === "tableCell";
|
|
154780
|
+
}
|
|
154781
|
+
function findScenarioStepKeyword(fact, keyword) {
|
|
154782
|
+
if (!isScenarioStepKeywordValue(keyword)) return [];
|
|
154783
|
+
const match = fact.text.match(new RegExp(`^\\s*(${SCENARIO_STEP_KEYWORDS.join("|")})\\b`, "i"));
|
|
154784
|
+
if (!match) return [];
|
|
154785
|
+
const text = match[1];
|
|
154786
|
+
const textStart = match.index ?? 0;
|
|
154787
|
+
const sourceSpan = findSourceSpanForFactText(fact, text);
|
|
154788
|
+
return [{
|
|
154789
|
+
kind: "keyword",
|
|
154790
|
+
targetFactId: fact.id,
|
|
154791
|
+
...sourceSpan ? { sourceSpan } : {},
|
|
154792
|
+
textSpan: {
|
|
154793
|
+
start: textStart,
|
|
154794
|
+
end: textStart + text.length
|
|
154795
|
+
},
|
|
154796
|
+
confidence: "strong",
|
|
154797
|
+
metadata: {
|
|
154798
|
+
keyword,
|
|
154799
|
+
keywordText: text,
|
|
154800
|
+
keywordRole: "scenario-step"
|
|
154801
|
+
}
|
|
154802
|
+
}];
|
|
154803
|
+
}
|
|
154804
|
+
function findRequirementKeywords(fact) {
|
|
154805
|
+
const span = getMarkdownFactSpan(fact);
|
|
154806
|
+
const text = fact.text;
|
|
154807
|
+
if (!span || !text) return [];
|
|
154808
|
+
return Array.from(text.matchAll(REQUIREMENT_KEYWORD_PATTERN), (match) => {
|
|
154809
|
+
const keyword = match[1].toUpperCase();
|
|
154810
|
+
const textStart = match.index;
|
|
154811
|
+
const textEnd = textStart + match[1].length;
|
|
154812
|
+
const sourceSpan = findSourceSpanForFactText(fact, match[1], textStart);
|
|
154813
|
+
return {
|
|
154814
|
+
kind: "keyword",
|
|
154815
|
+
targetFactId: fact.id,
|
|
154816
|
+
...sourceSpan ? { sourceSpan } : {},
|
|
154817
|
+
textSpan: {
|
|
154818
|
+
start: textStart,
|
|
154819
|
+
end: textEnd
|
|
154820
|
+
},
|
|
154821
|
+
confidence: "strong",
|
|
154822
|
+
metadata: {
|
|
154823
|
+
keyword,
|
|
154824
|
+
keywordText: match[1],
|
|
154825
|
+
keywordRole: isScenarioStepKeyword$1(keyword) ? "scenario-step" : "requirement-modal"
|
|
154826
|
+
}
|
|
154827
|
+
};
|
|
154828
|
+
});
|
|
154829
|
+
}
|
|
154830
|
+
function isScenarioStepKeywordValue(value) {
|
|
154831
|
+
return typeof value === "string" && SCENARIO_STEP_KEYWORDS.some((stepKeyword) => stepKeyword === value);
|
|
154832
|
+
}
|
|
154833
|
+
function isScenarioStepKeyword$1(keyword) {
|
|
154834
|
+
return SCENARIO_STEP_KEYWORDS.some((stepKeyword) => stepKeyword === keyword);
|
|
154835
|
+
}
|
|
154836
|
+
function readAnnotationKeyword(metadata) {
|
|
154837
|
+
return metadata && "keyword" in metadata ? metadata.keyword : void 0;
|
|
154838
|
+
}
|
|
154839
|
+
function findSourceSpanForFactText(fact, text, textStart = 0) {
|
|
154840
|
+
const factSpan = getMarkdownFactSpan(fact);
|
|
154841
|
+
const rawMarkdown = fact.range?.rawMarkdown;
|
|
154842
|
+
if (!factSpan || !rawMarkdown) return void 0;
|
|
154843
|
+
const rawStart = rawMarkdown.indexOf(text, Math.min(textStart, rawMarkdown.length));
|
|
154844
|
+
const index = rawStart >= 0 ? rawStart : rawMarkdown.indexOf(text);
|
|
154845
|
+
if (index < 0) return void 0;
|
|
154846
|
+
const start = factSpan.start + index;
|
|
154847
|
+
return {
|
|
154848
|
+
start,
|
|
154849
|
+
end: start + text.length
|
|
154850
|
+
};
|
|
154851
|
+
}
|
|
154852
|
+
//#endregion
|
|
154853
|
+
//#region ../core/src/openspec-projection.ts
|
|
154854
|
+
var OPEN_SPEC_SPEC_PROJECTION_ID = "openspec.projection.spec.v2";
|
|
154855
|
+
var OPEN_SPEC_READING_SECTIONS_PROJECTION_ID = "openspec.projection.reading-sections.v2";
|
|
154856
|
+
function createOpenSpecReadingPlugin(options) {
|
|
154857
|
+
return {
|
|
154858
|
+
...builtinOpenSpecReadingPlugin,
|
|
154859
|
+
id: "openspec.builtin-reading-with-projections.v2",
|
|
154860
|
+
projectionRules: [createOpenSpecReadingSectionsProjectionRule(), createOpenSpecSpecProjectionRule(options)]
|
|
154861
|
+
};
|
|
154862
|
+
}
|
|
154863
|
+
function projectOpenSpecMarkdown(sourceMarkdown, options, plugins = [createOpenSpecReadingPlugin(options)]) {
|
|
154864
|
+
return toProjectedOpenSpecDocument(createMarkdownReadingDocument(sourceMarkdown, plugins));
|
|
154865
|
+
}
|
|
154866
|
+
function getOpenSpecProjectionAnnotation(annotations, factId, kind) {
|
|
154867
|
+
return annotations.find((annotation) => annotation.targetFactId === factId && annotation.kind === kind);
|
|
154868
|
+
}
|
|
154869
|
+
function createOpenSpecReadingSectionsProjectionRule() {
|
|
154870
|
+
return {
|
|
154871
|
+
id: OPEN_SPEC_READING_SECTIONS_PROJECTION_ID,
|
|
154872
|
+
project(context) {
|
|
154873
|
+
return {
|
|
154874
|
+
sections: collectSpecSections(toOpenSpecProjectionContext(context)),
|
|
154875
|
+
requirements: collectRequirementBlocks(toOpenSpecProjectionContext(context))
|
|
154876
|
+
};
|
|
154877
|
+
}
|
|
154878
|
+
};
|
|
154879
|
+
}
|
|
154880
|
+
function createOpenSpecSpecProjectionRule(options) {
|
|
154881
|
+
return {
|
|
154882
|
+
id: OPEN_SPEC_SPEC_PROJECTION_ID,
|
|
154883
|
+
project(context) {
|
|
154884
|
+
return projectOpenSpecContextToSpec(toOpenSpecProjectionContext(context), options);
|
|
154885
|
+
}
|
|
154886
|
+
};
|
|
154887
|
+
}
|
|
154888
|
+
function projectOpenSpecContextToSpec(context, options) {
|
|
154889
|
+
const name = context.annotations.find((annotation) => annotation.kind === "document-title")?.metadata?.title || options.specId;
|
|
154890
|
+
const overviewSection = collectSpecSections(context).find((section) => section.kind === "overview");
|
|
154891
|
+
const overview = overviewSection ? trimMarkdownSlice(context.sourceMarkdown, getContentStartAfterHeading(context, overviewSection.factId, overviewSection.start), overviewSection.end) : "";
|
|
154892
|
+
const requirements = collectRequirementBlocks(context).map((requirement) => projectRequirement(context, requirement));
|
|
154893
|
+
return {
|
|
154894
|
+
id: options.specId,
|
|
154895
|
+
name: name || options.specId,
|
|
154896
|
+
overview: overview.trim(),
|
|
154897
|
+
requirements,
|
|
154898
|
+
metadata: {
|
|
154899
|
+
version: "1.0.0",
|
|
154900
|
+
format: "openspec"
|
|
154901
|
+
}
|
|
154902
|
+
};
|
|
154903
|
+
}
|
|
154904
|
+
function createRequirementText(title, bodyMarkdown, scenarioText) {
|
|
154905
|
+
return [
|
|
154906
|
+
title,
|
|
154907
|
+
bodyMarkdown,
|
|
154908
|
+
scenarioText
|
|
154909
|
+
].filter((part) => part.trim()).join("\n\n");
|
|
154910
|
+
}
|
|
154911
|
+
function collectSpecSections(context) {
|
|
154912
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154913
|
+
return headings.reduce((sections, fact, index) => {
|
|
154914
|
+
if (fact.depth !== 2) return sections;
|
|
154915
|
+
const span = getFactSpan(fact);
|
|
154916
|
+
if (!span) return sections;
|
|
154917
|
+
sections.push({
|
|
154918
|
+
id: fact.id,
|
|
154919
|
+
title: fact.text,
|
|
154920
|
+
kind: getSectionKind(context.annotations, fact.id),
|
|
154921
|
+
factId: fact.id,
|
|
154922
|
+
start: span.start,
|
|
154923
|
+
end: getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length)
|
|
154924
|
+
});
|
|
154925
|
+
return sections;
|
|
154926
|
+
}, []);
|
|
154927
|
+
}
|
|
154928
|
+
function collectRequirementBlocks(context) {
|
|
154929
|
+
const headings = getMarkdownHeadingFacts(context);
|
|
154930
|
+
let reqIndex = 0;
|
|
154931
|
+
return headings.reduce((requirements, fact, index) => {
|
|
154932
|
+
const annotation = getOpenSpecProjectionAnnotation(context.annotations, fact.id, "requirement");
|
|
154933
|
+
if (!annotation) return requirements;
|
|
154934
|
+
const span = getFactSpan(fact);
|
|
154935
|
+
if (!span) return requirements;
|
|
154936
|
+
reqIndex++;
|
|
154937
|
+
const end = getMarkdownHeadingEnd(headings, index, context.sourceMarkdown.length);
|
|
154938
|
+
const title = annotation.metadata?.title?.trim() || fact.text;
|
|
154939
|
+
requirements.push({
|
|
154940
|
+
id: `req-${reqIndex}`,
|
|
154941
|
+
title,
|
|
154942
|
+
factId: fact.id,
|
|
154943
|
+
start: span.start,
|
|
154944
|
+
end,
|
|
154945
|
+
scenarios: collectScenarioBlocks(context, headings, fact, end)
|
|
154946
|
+
});
|
|
154947
|
+
return requirements;
|
|
154948
|
+
}, []);
|
|
154949
|
+
}
|
|
154950
|
+
function collectScenarioBlocks(context, headings, requirementFact, requirementEnd) {
|
|
154951
|
+
const requirementSpan = getFactSpan(requirementFact);
|
|
154952
|
+
if (!requirementSpan) return [];
|
|
154953
|
+
return headings.reduce((scenarios, fact, index) => {
|
|
154954
|
+
const annotation = getOpenSpecProjectionAnnotation(context.annotations, fact.id, "scenario");
|
|
154955
|
+
if (!annotation) return scenarios;
|
|
154956
|
+
const span = getFactSpan(fact);
|
|
154957
|
+
if (!span || span.start <= requirementSpan.start || span.start >= requirementEnd) return scenarios;
|
|
154958
|
+
scenarios.push({
|
|
154959
|
+
title: annotation.metadata?.title?.trim() || fact.text,
|
|
154960
|
+
factId: fact.id,
|
|
154961
|
+
start: span.start,
|
|
154962
|
+
end: Math.min(getScenarioEnd(context, headings, index, requirementEnd), requirementEnd)
|
|
154963
|
+
});
|
|
154964
|
+
return scenarios;
|
|
154965
|
+
}, []);
|
|
154966
|
+
}
|
|
154967
|
+
function getScenarioEnd(context, headings, scenarioIndex, requirementEnd) {
|
|
154968
|
+
for (let i = scenarioIndex + 1; i < headings.length; i++) {
|
|
154969
|
+
const next = headings[i];
|
|
154970
|
+
const nextSpan = getFactSpan(next);
|
|
154971
|
+
if (!nextSpan || nextSpan.start >= requirementEnd) return requirementEnd;
|
|
154972
|
+
if ((next.depth ?? 6) <= 3 || getOpenSpecProjectionAnnotation(context.annotations, next.id, "scenario")) return nextSpan.start;
|
|
154973
|
+
}
|
|
154974
|
+
return requirementEnd;
|
|
154975
|
+
}
|
|
154976
|
+
function getContentStartAfterHeading(context, factId, fallback) {
|
|
154977
|
+
const fact = context.factById.get(factId);
|
|
154978
|
+
return fact ? getFactSpan(fact)?.end ?? fallback : fallback;
|
|
154979
|
+
}
|
|
154980
|
+
function projectScenario(context, scenario) {
|
|
154981
|
+
const bodyMarkdown = trimMarkdownSlice(context.sourceMarkdown, getContentStartAfterHeading(context, scenario.factId, scenario.start), scenario.end);
|
|
154982
|
+
const rawText = [scenario.title, bodyMarkdown].filter((part) => part.trim()).join("\n");
|
|
154983
|
+
return {
|
|
154984
|
+
title: scenario.title,
|
|
154985
|
+
bodyMarkdown,
|
|
154986
|
+
rawText,
|
|
154987
|
+
steps: getScenarioStepsFromAnnotations(context, scenario)
|
|
154988
|
+
};
|
|
154989
|
+
}
|
|
154990
|
+
function getScenarioStepsFromAnnotations(context, scenario) {
|
|
154991
|
+
return context.annotations.reduce((steps, annotation) => {
|
|
154992
|
+
if (annotation.kind !== "scenario-step") return steps;
|
|
154993
|
+
const fact = context.factById.get(annotation.targetFactId);
|
|
154994
|
+
const span = fact ? getFactSpan(fact) : void 0;
|
|
154995
|
+
if (!span || span.start <= scenario.start || span.start >= scenario.end) return steps;
|
|
154996
|
+
const keyword = annotation.metadata?.keyword;
|
|
154997
|
+
const contentMarkdown = annotation.metadata?.contentMarkdown;
|
|
154998
|
+
const rawText = annotation.metadata?.rawMarkdown;
|
|
154999
|
+
if (!isScenarioStepKeyword(keyword) || !contentMarkdown || !rawText) return steps;
|
|
155000
|
+
steps.push({
|
|
155001
|
+
keyword,
|
|
155002
|
+
contentMarkdown,
|
|
155003
|
+
rawText
|
|
155004
|
+
});
|
|
155005
|
+
return steps;
|
|
155006
|
+
}, []);
|
|
155007
|
+
}
|
|
155008
|
+
function isScenarioStepKeyword(value) {
|
|
155009
|
+
return value === "GIVEN" || value === "WHEN" || value === "THEN" || value === "AND" || value === "BUT";
|
|
155010
|
+
}
|
|
155011
|
+
function projectRequirement(context, requirement) {
|
|
155012
|
+
const bodyEnd = requirement.scenarios.map((scenario) => scenario.start).sort((left, right) => left - right)[0] ?? requirement.end;
|
|
155013
|
+
const bodyMarkdown = trimMarkdownSlice(context.sourceMarkdown, getContentStartAfterHeading(context, requirement.factId, requirement.start), bodyEnd);
|
|
155014
|
+
const scenarios = requirement.scenarios.map((scenario) => projectScenario(context, scenario));
|
|
155015
|
+
const scenarioText = scenarios.map((scenario) => scenario.rawText).join("\n\n");
|
|
155016
|
+
return {
|
|
155017
|
+
id: requirement.id,
|
|
155018
|
+
title: requirement.title,
|
|
155019
|
+
bodyMarkdown,
|
|
155020
|
+
text: createRequirementText(requirement.title, bodyMarkdown, scenarioText),
|
|
155021
|
+
scenarios
|
|
155022
|
+
};
|
|
155023
|
+
}
|
|
155024
|
+
function getFactSpan(fact) {
|
|
155025
|
+
return getMarkdownFactSpan(fact);
|
|
155026
|
+
}
|
|
155027
|
+
function getSectionKind(annotations, factId) {
|
|
155028
|
+
if (getOpenSpecProjectionAnnotation(annotations, factId, "purpose-section")) return "overview";
|
|
155029
|
+
if (getOpenSpecProjectionAnnotation(annotations, factId, "requirements-section")) return "requirements";
|
|
155030
|
+
return "other";
|
|
155031
|
+
}
|
|
155032
|
+
function toOpenSpecProjectionContext(context) {
|
|
155033
|
+
return {
|
|
155034
|
+
sourceMarkdown: context.sourceMarkdown,
|
|
155035
|
+
facts: context.facts,
|
|
155036
|
+
factById: context.factById,
|
|
155037
|
+
annotations: context.annotations.filter(isOpenSpecAnnotation)
|
|
155038
|
+
};
|
|
155039
|
+
}
|
|
155040
|
+
function toProjectedOpenSpecDocument(document) {
|
|
155041
|
+
return {
|
|
155042
|
+
...document,
|
|
155043
|
+
annotations: document.annotations.filter(isOpenSpecAnnotation)
|
|
155044
|
+
};
|
|
155045
|
+
}
|
|
155046
|
+
function isOpenSpecAnnotation(annotation) {
|
|
155047
|
+
return annotation.kind === "document-title" || annotation.kind === "purpose-section" || annotation.kind === "requirements-section" || annotation.kind === "requirement" || annotation.kind === "scenario" || annotation.kind === "scenario-step" || annotation.kind === "keyword";
|
|
155048
|
+
}
|
|
155049
|
+
//#endregion
|
|
155050
|
+
//#region src/components/spec-markdown-document.tsx
|
|
155051
|
+
var OPENSPEC_PREFIXES = {
|
|
155052
|
+
requirement: /^(?:Requirement|Capability):\s*/i,
|
|
155053
|
+
scenario: /^(?:Scenario|Example):\s*/i
|
|
155054
|
+
};
|
|
155055
|
+
var OPENSPEC_INLINE_KEYWORD_CLASS = "openspec-inline-keyword";
|
|
155056
|
+
var OPENSPEC_SCENARIO_STEP_CLASS = "spec-scenario-step";
|
|
155057
|
+
var OPENSPEC_BLOCK_FACT_KINDS = new Set([
|
|
155058
|
+
"paragraph",
|
|
155059
|
+
"list",
|
|
155060
|
+
"listItem",
|
|
155061
|
+
"blockquote",
|
|
155062
|
+
"table"
|
|
155063
|
+
]);
|
|
155064
|
+
function stripPrefix(text, prefix) {
|
|
155065
|
+
return text.replace(prefix, "").trim();
|
|
155066
|
+
}
|
|
155067
|
+
function describeOpenSpecHeading(sourceLevel, text) {
|
|
155068
|
+
if (sourceLevel === 1) return {
|
|
155069
|
+
kind: "spec",
|
|
155070
|
+
id: slugify(text) || "spec",
|
|
155071
|
+
title: text,
|
|
155072
|
+
tocLabel: text
|
|
155073
|
+
};
|
|
155074
|
+
if (sourceLevel === 2) return {
|
|
155075
|
+
kind: "section",
|
|
155076
|
+
id: slugify(text) || "section",
|
|
155077
|
+
title: text,
|
|
155078
|
+
tocLabel: text
|
|
155079
|
+
};
|
|
155080
|
+
if (sourceLevel === 3 && OPENSPEC_PREFIXES.requirement.test(text)) {
|
|
155081
|
+
const title = stripPrefix(text, OPENSPEC_PREFIXES.requirement);
|
|
155082
|
+
return {
|
|
155083
|
+
kind: "requirement",
|
|
155084
|
+
id: `requirement-${slugify(title) || "item"}`,
|
|
155085
|
+
title,
|
|
155086
|
+
tocLabel: title
|
|
155087
|
+
};
|
|
155088
|
+
}
|
|
155089
|
+
if (sourceLevel === 4 && OPENSPEC_PREFIXES.scenario.test(text)) {
|
|
155090
|
+
const title = stripPrefix(text, OPENSPEC_PREFIXES.scenario);
|
|
155091
|
+
return {
|
|
155092
|
+
kind: "scenario",
|
|
155093
|
+
id: `scenario-${slugify(title) || "item"}`,
|
|
155094
|
+
title,
|
|
155095
|
+
tocLabel: title
|
|
155096
|
+
};
|
|
155097
|
+
}
|
|
155098
|
+
}
|
|
155099
|
+
function describeAnnotatedOpenSpecHeading(document, headingFact, sourceLevel, text) {
|
|
155100
|
+
if (!headingFact) return describeOpenSpecHeading(sourceLevel, text);
|
|
155101
|
+
const readingProjection = document.projections[OPEN_SPEC_READING_SECTIONS_PROJECTION_ID];
|
|
155102
|
+
if (sourceLevel === 2) {
|
|
155103
|
+
const section = readingProjection?.sections.find((section) => section.factId === headingFact.id);
|
|
155104
|
+
return {
|
|
155105
|
+
kind: "section",
|
|
155106
|
+
id: slugify(text) || "section",
|
|
155107
|
+
title: text,
|
|
155108
|
+
tocLabel: text,
|
|
155109
|
+
...section ? { sectionKind: section.kind } : {}
|
|
155110
|
+
};
|
|
155111
|
+
}
|
|
155112
|
+
const requirement = getOpenSpecProjectionAnnotation(document.annotations, headingFact.id, "requirement");
|
|
155113
|
+
if (requirement) {
|
|
155114
|
+
const title = requirement.metadata?.title?.trim() || text;
|
|
155115
|
+
const requirementIndex = readingProjection?.requirements.findIndex((block) => block.factId === headingFact.id) ?? -1;
|
|
155116
|
+
return {
|
|
155117
|
+
kind: "requirement",
|
|
155118
|
+
id: `requirement-${slugify(title) || "item"}`,
|
|
155119
|
+
title,
|
|
155120
|
+
tocLabel: title,
|
|
155121
|
+
label: requirementIndex >= 0 ? formatRequirementLabel(requirementIndex + 1) : "Requirement"
|
|
155122
|
+
};
|
|
155123
|
+
}
|
|
155124
|
+
const scenario = getOpenSpecProjectionAnnotation(document.annotations, headingFact.id, "scenario");
|
|
155125
|
+
if (scenario) {
|
|
155126
|
+
const title = scenario.metadata?.title?.trim() || text;
|
|
155127
|
+
return {
|
|
155128
|
+
kind: "scenario",
|
|
155129
|
+
id: `scenario-${slugify(title) || "item"}`,
|
|
155130
|
+
title,
|
|
155131
|
+
tocLabel: title,
|
|
155132
|
+
label: "Scenario"
|
|
155133
|
+
};
|
|
155134
|
+
}
|
|
155135
|
+
return describeOpenSpecHeading(sourceLevel, text);
|
|
155136
|
+
}
|
|
155137
|
+
function createAnnotatedHeadingTransform(document, requirementCount) {
|
|
155138
|
+
const headingByStartOffset = /* @__PURE__ */ new Map();
|
|
155139
|
+
for (const fact of document.facts) {
|
|
155140
|
+
if (fact.kind !== "heading" || typeof fact.depth !== "number") continue;
|
|
155141
|
+
const span = getMarkdownFactSpan(fact);
|
|
155142
|
+
if (span) headingByStartOffset.set(span.start, fact);
|
|
155143
|
+
}
|
|
155144
|
+
return ({ sourceLevel, text, sourceStartOffset }) => {
|
|
155145
|
+
const heading = describeAnnotatedOpenSpecHeading(document, sourceStartOffset === void 0 ? void 0 : headingByStartOffset.get(sourceStartOffset), sourceLevel, text);
|
|
155146
|
+
if (!heading) return void 0;
|
|
155147
|
+
return {
|
|
155148
|
+
id: heading.id,
|
|
155149
|
+
tocLabel: heading.tocLabel,
|
|
155150
|
+
className: createHeadingClassName(heading, requirementCount),
|
|
155151
|
+
suffix: createHeadingSuffix(heading, requirementCount),
|
|
155152
|
+
dataAttributes: {
|
|
155153
|
+
"data-openspec-kind": heading.kind,
|
|
155154
|
+
"data-openspec-title": heading.title,
|
|
155155
|
+
...heading.label ? { "data-openspec-label": heading.label } : {},
|
|
155156
|
+
...heading.sectionKind ? { "data-openspec-section-kind": heading.sectionKind } : {}
|
|
155157
|
+
}
|
|
155158
|
+
};
|
|
155159
|
+
};
|
|
155160
|
+
}
|
|
155161
|
+
function createHeadingClassName(heading, requirementCount) {
|
|
155162
|
+
if (heading.kind !== "section" || heading.title !== "Requirements") return void 0;
|
|
155163
|
+
if (requirementCount === void 0) return void 0;
|
|
155164
|
+
return "openspec-heading-with-chip";
|
|
155165
|
+
}
|
|
155166
|
+
function createHeadingSuffix(heading, requirementCount) {
|
|
155167
|
+
if (heading.kind !== "section" || heading.title !== "Requirements") return void 0;
|
|
155168
|
+
if (requirementCount === void 0) return void 0;
|
|
155169
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CountBadge, {
|
|
155170
|
+
count: requirementCount,
|
|
155171
|
+
tone: "subtle",
|
|
155172
|
+
size: "sm",
|
|
155173
|
+
shape: "box",
|
|
155174
|
+
className: "openspec-heading-chip",
|
|
155175
|
+
"aria-label": String(requirementCount),
|
|
155176
|
+
title: `${requirementCount} requirements`
|
|
155177
|
+
});
|
|
155178
|
+
}
|
|
155179
|
+
/**
|
|
155180
|
+
* Renders the processed spec Markdown as the visual source while attaching
|
|
155181
|
+
* OpenSpec structure metadata for styling, anchors, and ToC alignment.
|
|
155182
|
+
*/
|
|
155183
|
+
function SpecMarkdownDocument({ markdown, spec, requirementCount, className = "" }) {
|
|
155184
|
+
const resolvedRequirementCount = requirementCount ?? spec?.requirements.length;
|
|
155185
|
+
const document = (0, import_react.useMemo)(() => projectOpenSpecMarkdown(markdown, { specId: spec?.id ?? "inline" }), [markdown, spec?.id]);
|
|
155186
|
+
const headingTransform = (0, import_react.useMemo)(() => createAnnotatedHeadingTransform(document, resolvedRequirementCount), [document, resolvedRequirementCount]);
|
|
155187
|
+
const inlineTextAnnotations = (0, import_react.useMemo)(() => createOpenSpecInlineTextAnnotations(document), [document]);
|
|
155188
|
+
const blockAnnotations = (0, import_react.useMemo)(() => createOpenSpecBlockAnnotations(document), [document]);
|
|
155189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, {
|
|
155190
|
+
className: `spec-markdown-document spec-reading-document ${className}`,
|
|
155191
|
+
markdown,
|
|
155192
|
+
headingTransform,
|
|
155193
|
+
inlineTextAnnotations,
|
|
155194
|
+
blockAnnotations
|
|
155195
|
+
});
|
|
155196
|
+
}
|
|
155197
|
+
function createOpenSpecBlockAnnotations(document) {
|
|
155198
|
+
const factById = new Map(document.facts.map((fact) => [fact.id, fact]));
|
|
155199
|
+
const annotationByOffset = /* @__PURE__ */ new Map();
|
|
155200
|
+
const readingProjection = document.projections[OPEN_SPEC_READING_SECTIONS_PROJECTION_ID];
|
|
155201
|
+
if (readingProjection) {
|
|
155202
|
+
for (const section of readingProjection.sections) {
|
|
155203
|
+
if (section.kind !== "overview") continue;
|
|
155204
|
+
addRangeBlockAnnotations(document, annotationByOffset, {
|
|
155205
|
+
start: getFactEnd(factById, section.factId, section.start),
|
|
155206
|
+
end: section.end,
|
|
155207
|
+
dataAttributes: {
|
|
155208
|
+
"data-openspec-zone": "purpose",
|
|
155209
|
+
"data-openspec-section-kind": section.kind,
|
|
155210
|
+
"data-openspec-section-title": section.title
|
|
155211
|
+
}
|
|
155212
|
+
});
|
|
155213
|
+
}
|
|
155214
|
+
const requirementsSection = readingProjection.sections.find((section) => section.kind === "requirements");
|
|
155215
|
+
if (requirementsSection) {
|
|
155216
|
+
const firstRequirementStart = readingProjection.requirements.map((requirement) => requirement.start).sort((left, right) => left - right)[0];
|
|
155217
|
+
addRangeBlockAnnotations(document, annotationByOffset, {
|
|
155218
|
+
start: getFactEnd(factById, requirementsSection.factId, requirementsSection.start),
|
|
155219
|
+
end: firstRequirementStart ?? requirementsSection.end,
|
|
155220
|
+
dataAttributes: {
|
|
155221
|
+
"data-openspec-zone": "requirements-intro",
|
|
155222
|
+
"data-openspec-section-kind": requirementsSection.kind,
|
|
155223
|
+
"data-openspec-section-title": requirementsSection.title
|
|
155224
|
+
}
|
|
155225
|
+
});
|
|
155226
|
+
}
|
|
155227
|
+
for (const [index, requirement] of readingProjection.requirements.entries()) {
|
|
155228
|
+
const requirementLabel = formatRequirementLabel(index + 1);
|
|
155229
|
+
const firstScenarioStart = requirement.scenarios.map((scenario) => scenario.start).sort((left, right) => left - right)[0];
|
|
155230
|
+
const requirementData = {
|
|
155231
|
+
"data-openspec-requirement-id": requirement.id,
|
|
155232
|
+
"data-openspec-requirement-label": requirementLabel,
|
|
155233
|
+
"data-openspec-requirement-title": requirement.title
|
|
155234
|
+
};
|
|
155235
|
+
addRangeBlockAnnotations(document, annotationByOffset, {
|
|
155236
|
+
start: getFactEnd(factById, requirement.factId, requirement.start),
|
|
155237
|
+
end: firstScenarioStart ?? requirement.end,
|
|
155238
|
+
dataAttributes: {
|
|
155239
|
+
"data-openspec-zone": "requirement-body",
|
|
155240
|
+
...requirementData
|
|
155241
|
+
}
|
|
155242
|
+
});
|
|
155243
|
+
for (const scenario of requirement.scenarios) addRangeBlockAnnotations(document, annotationByOffset, {
|
|
155244
|
+
start: getFactEnd(factById, scenario.factId, scenario.start),
|
|
155245
|
+
end: scenario.end,
|
|
155246
|
+
dataAttributes: {
|
|
155247
|
+
"data-openspec-zone": "scenario-body",
|
|
155248
|
+
...requirementData,
|
|
155249
|
+
"data-openspec-scenario-title": scenario.title
|
|
155250
|
+
}
|
|
155251
|
+
});
|
|
155252
|
+
}
|
|
155253
|
+
}
|
|
155254
|
+
for (const annotation of document.annotations) {
|
|
155255
|
+
if (annotation.kind !== "scenario-step") continue;
|
|
155256
|
+
const fact = factById.get(annotation.targetFactId);
|
|
155257
|
+
const span = fact ? getMarkdownFactSpan(fact) : void 0;
|
|
155258
|
+
if (!fact || !span) continue;
|
|
155259
|
+
const keyword = annotation.metadata?.keyword;
|
|
155260
|
+
upsertBlockAnnotation(annotationByOffset, {
|
|
155261
|
+
sourceStartOffset: span.start,
|
|
155262
|
+
sourceKind: fact.mdastType,
|
|
155263
|
+
className: OPENSPEC_SCENARIO_STEP_CLASS,
|
|
155264
|
+
dataAttributes: {
|
|
155265
|
+
"data-openspec-kind": "scenario-step",
|
|
155266
|
+
...keyword ? { "data-openspec-step-keyword": keyword } : {}
|
|
155267
|
+
}
|
|
155268
|
+
});
|
|
155269
|
+
}
|
|
155270
|
+
return Array.from(annotationByOffset.values());
|
|
155271
|
+
}
|
|
155272
|
+
function addRangeBlockAnnotations(document, annotationByOffset, range) {
|
|
155273
|
+
for (const fact of document.facts) {
|
|
155274
|
+
if (!OPENSPEC_BLOCK_FACT_KINDS.has(fact.kind)) continue;
|
|
155275
|
+
const span = getMarkdownFactSpan(fact);
|
|
155276
|
+
if (!span || span.start < range.start || span.start >= range.end) continue;
|
|
155277
|
+
upsertBlockAnnotation(annotationByOffset, {
|
|
155278
|
+
sourceStartOffset: span.start,
|
|
155279
|
+
sourceKind: fact.mdastType,
|
|
155280
|
+
dataAttributes: {
|
|
155281
|
+
"data-openspec-block-kind": fact.kind,
|
|
155282
|
+
...range.dataAttributes
|
|
155283
|
+
}
|
|
155284
|
+
});
|
|
155285
|
+
}
|
|
155286
|
+
}
|
|
155287
|
+
function upsertBlockAnnotation(annotationByOffset, annotation) {
|
|
155288
|
+
const key = createBlockAnnotationKey(annotation);
|
|
155289
|
+
const previous = annotationByOffset.get(key);
|
|
155290
|
+
if (!previous) {
|
|
155291
|
+
annotationByOffset.set(key, annotation);
|
|
155292
|
+
return;
|
|
155293
|
+
}
|
|
155294
|
+
annotationByOffset.set(key, {
|
|
155295
|
+
sourceStartOffset: annotation.sourceStartOffset,
|
|
155296
|
+
sourceKind: annotation.sourceKind,
|
|
155297
|
+
className: [previous.className, annotation.className].filter(Boolean).join(" ") || void 0,
|
|
155298
|
+
dataAttributes: {
|
|
155299
|
+
...previous.dataAttributes,
|
|
155300
|
+
...annotation.dataAttributes
|
|
155301
|
+
}
|
|
155302
|
+
});
|
|
155303
|
+
}
|
|
155304
|
+
function createBlockAnnotationKey(annotation) {
|
|
155305
|
+
return `${annotation.sourceStartOffset}:${annotation.sourceKind ?? "*"}`;
|
|
155306
|
+
}
|
|
155307
|
+
function getFactEnd(factById, factId, fallback) {
|
|
155308
|
+
const fact = factById.get(factId);
|
|
155309
|
+
return fact ? getMarkdownFactSpan(fact)?.end ?? fallback : fallback;
|
|
155310
|
+
}
|
|
155311
|
+
function formatRequirementLabel(index) {
|
|
155312
|
+
return `REQ-${String(index).padStart(2, "0")}`;
|
|
155313
|
+
}
|
|
155314
|
+
function createOpenSpecInlineTextAnnotations(document) {
|
|
155315
|
+
const terms = /* @__PURE__ */ new Map();
|
|
155316
|
+
for (const annotation of document.annotations) {
|
|
155317
|
+
if (annotation.kind !== "keyword") continue;
|
|
155318
|
+
const { keyword, keywordText, keywordRole } = annotation.metadata ?? {};
|
|
155319
|
+
const text = keywordText ?? keyword;
|
|
155320
|
+
if (!keyword || !text) continue;
|
|
155321
|
+
terms.set(text, {
|
|
155322
|
+
text,
|
|
155323
|
+
className: OPENSPEC_INLINE_KEYWORD_CLASS,
|
|
155324
|
+
dataAttributes: createOpenSpecKeywordDataAttributes(keyword, keywordRole)
|
|
155325
|
+
});
|
|
155326
|
+
}
|
|
155327
|
+
return Array.from(terms.values());
|
|
155328
|
+
}
|
|
155329
|
+
function createOpenSpecKeywordDataAttributes(keyword, keywordRole) {
|
|
155330
|
+
return {
|
|
155331
|
+
"data-openspec-keyword": keyword,
|
|
155332
|
+
...keywordRole ? { "data-openspec-keyword-role": keywordRole } : {}
|
|
155333
|
+
};
|
|
155334
|
+
}
|
|
155335
|
+
//#endregion
|
|
153805
155336
|
//#region src/routes/spec-view.tsx
|
|
153806
155337
|
function SpecView() {
|
|
153807
155338
|
const { specId } = useParams({ from: "/specs/$specId" });
|
|
@@ -153811,8 +155342,9 @@ function SpecView() {
|
|
|
153811
155342
|
entityId: specId
|
|
153812
155343
|
}), [specId]);
|
|
153813
155344
|
const { data: spec, isLoading } = useSpecSubscription(specId);
|
|
155345
|
+
const { data: rawMarkdown, isLoading: isRawLoading } = useSpecRawSubscription(specId);
|
|
153814
155346
|
const validation = null;
|
|
153815
|
-
if (isLoading && !spec) {
|
|
155347
|
+
if (isLoading && !spec || isRawLoading && !rawMarkdown) {
|
|
153816
155348
|
if (handoff) return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153817
155349
|
className: "flex min-h-0 flex-1 flex-col gap-6 p-4",
|
|
153818
155350
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -153854,10 +155386,11 @@ function SpecView() {
|
|
|
153854
155386
|
});
|
|
153855
155387
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpecContent, {
|
|
153856
155388
|
spec,
|
|
155389
|
+
rawMarkdown: rawMarkdown ?? "",
|
|
153857
155390
|
validation
|
|
153858
155391
|
});
|
|
153859
155392
|
}
|
|
153860
|
-
function SpecContent({ spec, validation }) {
|
|
155393
|
+
function SpecContent({ spec, rawMarkdown, validation }) {
|
|
153861
155394
|
const headerRef = (0, import_react.useRef)(null);
|
|
153862
155395
|
const sharedDescriptor = (0, import_react.useMemo)(() => ({
|
|
153863
155396
|
family: "specs",
|
|
@@ -153895,56 +155428,11 @@ function SpecContent({ spec, validation }) {
|
|
|
153895
155428
|
})]
|
|
153896
155429
|
}),
|
|
153897
155430
|
validation && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ValidationStatus, { validation }),
|
|
153898
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
153899
|
-
|
|
153900
|
-
|
|
153901
|
-
|
|
153902
|
-
|
|
153903
|
-
id: "overview",
|
|
153904
|
-
children: "Overview"
|
|
153905
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153906
|
-
className: "bg-muted/30 mt-2 rounded-lg p-4",
|
|
153907
|
-
children: spec.overview ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, { markdown: spec.overview }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
153908
|
-
className: "text-muted-foreground",
|
|
153909
|
-
children: "No overview"
|
|
153910
|
-
})
|
|
153911
|
-
})] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(H1, {
|
|
153912
|
-
id: "requirements",
|
|
153913
|
-
children: [
|
|
153914
|
-
"Requirements (",
|
|
153915
|
-
spec.requirements.length,
|
|
153916
|
-
")"
|
|
153917
|
-
]
|
|
153918
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153919
|
-
className: "mt-3 space-y-4",
|
|
153920
|
-
children: [spec.requirements.map((req) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Section, {
|
|
153921
|
-
className: "border-border rounded-lg border p-4",
|
|
153922
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(H2, {
|
|
153923
|
-
className: "text-base",
|
|
153924
|
-
id: `req-${req.id}`,
|
|
153925
|
-
children: req.text
|
|
153926
|
-
}), req.scenarios.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153927
|
-
className: "mt-3",
|
|
153928
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
153929
|
-
className: "text-muted-foreground mb-2 text-sm font-medium",
|
|
153930
|
-
children: [
|
|
153931
|
-
"Scenarios (",
|
|
153932
|
-
req.scenarios.length,
|
|
153933
|
-
")"
|
|
153934
|
-
]
|
|
153935
|
-
}), req.scenarios.map((scenario, i) => {
|
|
153936
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153937
|
-
className: "bg-muted/50 rounded-md p-3",
|
|
153938
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MarkdownViewer, { markdown: scenario.rawText.replace(/^---\n?/, "").replace(/\n?---$/, "").trim() })
|
|
153939
|
-
}, i);
|
|
153940
|
-
})]
|
|
153941
|
-
})]
|
|
153942
|
-
}, req.id)), spec.requirements.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
153943
|
-
className: "text-muted-foreground",
|
|
153944
|
-
children: "No requirements defined"
|
|
153945
|
-
})]
|
|
153946
|
-
})] })]
|
|
153947
|
-
})
|
|
155431
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpecMarkdownDocument, {
|
|
155432
|
+
markdown: rawMarkdown,
|
|
155433
|
+
spec,
|
|
155434
|
+
requirementCount: spec.requirements.length,
|
|
155435
|
+
className: "vt-detail-content min-h-0 flex-1"
|
|
153948
155436
|
})
|
|
153949
155437
|
]
|
|
153950
155438
|
});
|