@sigloch/graph-view-edit 0.1.0 → 0.2.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
.gve-ctx{position:absolute;z-index:30;min-width:220px;max-width:320px;max-height:60vh;overflow-y:auto;display:flex;flex-direction:column;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-1);font-family:var(--font-ui);font-size:var(--text-sm)}.gve-ctx-head{padding:var(--space-1) var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim);border-bottom:1px solid var(--color-border);margin-bottom:var(--space-1)}.gve-ctx-item{text-align:left;padding:var(--space-1) var(--space-2);background:none;border:none;border-radius:var(--radius-sm);color:var(--color-text);cursor:pointer}.gve-ctx-item:hover:not(:disabled){background:var(--color-accent-soft)}.gve-ctx-item:disabled{color:var(--color-text-dim);cursor:not-allowed}.gve-ctx-form{display:flex;flex-direction:column;gap:var(--space-1);padding:var(--space-2)}.gve-ctx-form label{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-ctx-form input,.gve-ctx-form textarea{font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2)}.gve-ctx-empty{padding:var(--space-1) var(--space-2);color:var(--color-text-dim);font-size:var(--text-xs)}.gve-genesis{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:20;display:flex;flex-direction:column;gap:var(--space-2);min-width:240px;padding:var(--space-3);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);text-align:center}.gve-genesis-title{font-family:var(--font-mono);font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-dim)}.gve-genesis-hint{margin:0;color:var(--color-text-dim)}.gve-genesis-input{font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2)}.gve-genesis-create{padding:var(--space-1) var(--space-2);background:var(--color-accent-soft);border:1px solid var(--color-border);border-radius:var(--radius-sm);color:var(--color-text);cursor:pointer}.gve-genesis-create:disabled{color:var(--color-text-dim);cursor:not-allowed}.gve-doc{font-family:var(--font-ui);font-size:var(--text-base);line-height:1.55;color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-8) var(--space-6);margin:var(--space-3) auto;max-width:820px}.gve-doc h1{font-size:var(--text-xl);margin:0 0 var(--space-3)}.gve-doc h2{font-size:var(--text-lg);margin:var(--space-6) 0 var(--space-3);padding-bottom:var(--space-1);border-bottom:1px solid var(--color-border)}.gve-doc h3{font-size:var(--text-base);margin:var(--space-4) 0 var(--space-2)}.gve-doc h4,.gve-doc h5,.gve-doc h6{font-size:var(--text-sm);margin:var(--space-3) 0 var(--space-1)}.gve-doc h5 code,.gve-doc h6 code{color:var(--color-text-dim)}.gve-doc p{margin:0 0 var(--space-2)}.gve-doc code{font-family:var(--font-mono);font-size:.92em;background:var(--color-surface-2);border-radius:var(--radius-sm);padding:0 var(--space-1)}.gve-doc blockquote{margin:0 0 var(--space-2);padding-left:var(--space-3);border-left:2px solid var(--color-border);color:var(--color-text-dim);font-size:var(--text-sm)}.gve-doc hr{border:0;border-top:1px solid var(--color-border);margin:var(--space-4) 0}.gve-doc pre.md-code{font-family:var(--font-mono);font-size:var(--text-sm);background:var(--color-surface-2);border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);overflow-x:auto}.edit-pen{margin-left:var(--space-2);font-size:var(--text-xs);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-sm);cursor:pointer}.edit-box{margin:var(--space-2) 0;padding:var(--space-3);background:var(--color-surface-2);border:1px solid var(--color-accent);border-radius:var(--radius-md)}.edit-box textarea{width:100%;box-sizing:border-box;font-family:var(--font-mono);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-2)}.cmd-preview{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim);background:var(--color-surface);border:1px dashed var(--color-border);border-radius:var(--radius-sm);padding:var(--space-2);overflow-x:auto;white-space:pre-wrap}.edit-actions{display:flex;gap:var(--space-2);align-items:center;margin-top:var(--space-2)}.edit-actions .btn-primary{background:var(--color-accent);color:var(--color-text-inverse);border:1px solid var(--color-accent);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-3);cursor:pointer}.edit-actions .btn-primary:disabled{opacity:.5;cursor:not-allowed}[data-testid=edit-errors],[data-testid=formate-errors]{color:var(--color-error);font-size:var(--text-xs)}[data-testid=edit-verdict][data-tier=block]{color:var(--color-error)}[data-testid=edit-verdict]{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-cards{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:var(--space-4);padding:var(--space-4);align-content:start}.gve-card{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-4)}.gve-card-wide{grid-column:1 / -1}.gve-card h3{font-size:var(--text-xs);font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--color-text-dim);margin-bottom:var(--space-3);display:flex;align-items:center;gap:var(--space-2)}.gve-card h4{font-size:var(--text-xs);font-weight:600;color:var(--color-text-dim);margin-bottom:var(--space-2);display:flex;align-items:center;gap:var(--space-2)}.gve-count{font-size:var(--text-xs);font-weight:600;color:var(--color-text-inverse);background:var(--color-accent);border-radius:999px;padding:0 var(--space-2)}.gve-kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:var(--space-3);margin-bottom:var(--space-4)}.gve-kpi-tile{display:flex;flex-direction:column;gap:var(--space-1);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-3)}.gve-kpi-value{font-size:var(--text-xl);font-weight:600;line-height:1.1}.gve-kpi-label{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-kpi-tile[data-tone=ok] .gve-kpi-value{color:var(--color-ok)}.gve-kpi-tile[data-tone=warn] .gve-kpi-value{color:var(--color-warn)}.gve-kpi-tile[data-tone=error] .gve-kpi-value{color:var(--color-error)}.gve-gate-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--space-4)}.gve-gates{list-style:none;padding:0;display:flex;flex-direction:column;gap:var(--space-2)}.gve-gate{display:grid;grid-template-columns:auto 44px 1fr auto 44px;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.gve-light{width:10px;height:10px;border-radius:50%;flex-shrink:0}.gve-light[data-state=passed]{background:var(--color-ok)}.gve-light[data-state=open]{background:var(--color-warn)}.gve-gate-id{font-family:var(--font-mono);font-weight:600}.gve-gate-label{color:var(--color-text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gve-gate-track{grid-column:4;width:90px;height:12px;background:var(--color-surface-2);border-radius:999px;overflow:hidden}.gve-gate-fill{display:block;height:100%;border-radius:999px}.gve-gate-fill[data-state=passed]{background:var(--color-ok)}.gve-gate-fill[data-state=open]{background:var(--color-warn)}.gve-gate-pct{font-family:var(--font-mono);text-align:right}.gve-gate-blk{grid-column:1 / -1;font-size:var(--text-xs);color:var(--color-warn)}.gve-legend{margin-top:var(--space-3);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-rec-group{margin-bottom:var(--space-4)}.gve-rec-group h4[data-severity=error] .gve-count{background:var(--color-error)}.gve-rec-group h4[data-severity=warning] .gve-count{background:var(--color-warn)}.gve-rec-group h4[data-severity=info] .gve-count{background:var(--color-accent)}.gve-rec{border:1px solid var(--color-border);border-left-width:3px;border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);margin-bottom:var(--space-2);background:var(--color-surface-2)}.gve-rec[data-severity=error]{border-left-color:var(--color-error)}.gve-rec[data-severity=warning]{border-left-color:var(--color-warn)}.gve-rec[data-severity=info]{border-left-color:var(--color-accent)}.gve-rec-head{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-1)}.gve-rid{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-rec-el{color:var(--color-accent)}.gve-sev{font-size:var(--text-xs);font-weight:600;text-transform:uppercase;border-radius:var(--radius-sm);padding:0 var(--space-2)}.gve-sev[data-severity=error]{color:var(--color-error)}.gve-sev[data-severity=warning]{color:var(--color-warn)}.gve-sev[data-severity=info]{color:var(--color-accent)}.gve-rec-msg{font-size:var(--text-sm)}.gve-hint{margin-top:var(--space-1);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-empty{font-size:var(--text-sm);color:var(--color-text-dim)}.gve-rollup summary{cursor:pointer;font-size:var(--text-sm);color:var(--color-text-dim);padding:var(--space-1) 0;-webkit-user-select:none;user-select:none}.gve-rollup summary:hover{color:var(--color-text)}.gve-rollup[open] summary{margin-bottom:var(--space-2)}.gve-fresh-list{list-style:none;padding:0;display:flex;flex-direction:column;gap:var(--space-2)}.gve-fresh-2col{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--space-4)}.gve-fresh-list li{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.gve-fresh-label{flex:1}.gve-fresh-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.gve-fresh-dot[data-freshness=live]{background:var(--color-ok)}.gve-fresh-dot[data-freshness=stale]{background:var(--color-warn)}.gve-fresh-dot[data-freshness=absent]{background:var(--color-error)}.gve-pill{font-size:var(--text-xs);border:1px solid var(--color-border);border-radius:999px;padding:0 var(--space-2)}.gve-pill[data-freshness=live]{border-color:var(--color-ok);color:var(--color-ok)}.gve-pill[data-freshness=stale]{border-color:var(--color-warn);color:var(--color-warn)}.gve-pill[data-freshness=absent]{border-color:var(--color-error);color:var(--color-error)}.gve-health-status{margin-bottom:var(--space-3);text-transform:uppercase}.gve-health-status[data-state=ok]{color:var(--color-ok)}.gve-health-status[data-state=error]{color:var(--color-error)}.gve-vtable{width:100%;border-collapse:collapse;font-size:var(--text-sm)}.gve-vtable td{padding:var(--space-1) var(--space-2);border-bottom:1px solid var(--color-border)}.gve-vtable td:first-child{font-family:var(--font-mono);color:var(--color-text-dim);white-space:nowrap}a.gve-btn{text-decoration:none;display:inline-block}.gve-appbar .title{font-size:var(--text-base)}.gve .gve{height:auto;flex:1;min-height:0}.gve-chip .dash{width:12px;height:0;border-top:2px solid var(--color-text-dim)}.gve .gve-body{flex:1;min-height:0}.gve-canvas,.gve-explorer .exp-tree,.gve-details{overflow:auto}.gve-tree .tw{cursor:pointer;-webkit-user-select:none;user-select:none}.gve-tree .row.sel{box-shadow:inset 2px 0 0 var(--color-accent)}.gve-tree .row.dim{opacity:.45;cursor:default}.gve-tree .det-tw{margin-left:var(--space-2);cursor:pointer;-webkit-user-select:none;user-select:none;background:none;border:0;padding:0 var(--space-1);color:var(--color-text-dim);font-size:var(--text-sm)}.gve-tree .det-tw.open,.gve-tree .det-tw:hover{color:var(--color-accent)}.gve-tree .row-details{margin:var(--space-1) 0 var(--space-2) 28px;padding:var(--space-2);border-left:2px solid var(--color-border);display:flex;flex-direction:column;gap:var(--space-1)}.gve-tree .row-details .det-desc{margin:0 0 var(--space-1);color:var(--color-text-dim);font-size:var(--text-sm)}.gve-tree .det-group{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1) var(--space-2)}.gve-tree .det-type{font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--color-accent);min-width:64px}.gve-tree .det-neighbor{display:inline-flex;align-items:center;gap:var(--space-1);font-size:var(--text-sm);padding:0 var(--space-2);border:1px solid var(--color-border);border-radius:var(--radius-sm)}.gve-tree .det-neighbor .kind{font-style:normal;color:var(--color-text-dim);font-size:var(--text-xs)}.gve-grid-scroll{overflow:auto;flex:1;min-height:0}.gve-grid{border-collapse:collapse;font-size:var(--text-sm)}.gve-grid th,.gve-grid td{border:1px solid var(--color-border);padding:var(--space-1) var(--space-2);text-align:left;white-space:nowrap}.gve-grid thead th{position:sticky;top:0;z-index:1;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--color-surface-alt, var(--color-surface));color:var(--color-text)}.gve-grid thead th.corner{left:0;z-index:2}.gve-grid td.rowhead,.gve-grid th.corner{font-weight:600}.gve-grid td.rowhead{position:sticky;left:0;background:var(--color-surface)}.gve-grid td.hit{background:var(--color-accent-soft);color:var(--color-accent);text-align:center;font-weight:600}.tabular-grid th,.tabular-grid td{max-width:20rem}.tabular-grid:not(.wrap) th,.tabular-grid:not(.wrap) td{overflow:hidden;text-overflow:ellipsis}.tabular-grid.wrap th,.tabular-grid.wrap td{white-space:normal;word-break:break-word;vertical-align:top}.gve-group.tabs .gve-chip.active{background:var(--color-accent-soft);color:var(--color-accent);border-color:var(--color-accent)}:root{--color-bg: #f6f7f9;--color-surface: #ffffff;--color-surface-2: #eef0f3;--color-border: #d7dbe0;--color-text: #1a1d21;--color-text-dim: #5c6470;--color-text-inverse: #ffffff;--color-accent: #2563eb;--color-accent-soft: #dbeafe;--color-ok: #16a34a;--color-warn: #d97706;--color-error: #dc2626;--color-hotspot: #e11d48;--color-type-1: #2563eb;--color-type-2: #7c3aed;--color-type-3: #0891b2;--color-type-4: #16a34a;--color-type-5: #d97706;--color-type-6: #64748b;--color-type-7: #db2777;--color-type-8: #0d9488;--color-type-func: #0d9488;--color-type-flow: #2dd4bf;--fchain-1: #8b5cf6;--fchain-2: #f59e0b;--fchain-3: #ec4899;--fchain-4: #0284c7;--fchain-5: #84cc16;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: 32px;--text-xs: 11px;--text-sm: 12.5px;--text-base: 14px;--text-lg: 16px;--text-xl: 20px;--font-ui: -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono: ui-monospace, "SF Mono", Menlo, monospace;--radius-sm: 4px;--radius-md: 8px;--shadow-1: 0 1px 3px rgba(0,0,0,.12)}@media (prefers-color-scheme: dark){:root{--color-bg: #14161a;--color-surface: #1e2126;--color-surface-2: #262a31;--color-border: #363c45;--color-text: #e8eaed;--color-text-dim: #9aa3af;--color-text-inverse: #14161a;--color-accent: #60a5fa;--color-accent-soft: #1e3a5f;--color-type-2: #8b5cf6;--shadow-1: 0 1px 3px rgba(0,0,0,.5)}}*{box-sizing:border-box;margin:0}.gve{font-family:var(--font-ui);font-size:var(--text-base);background:var(--color-bg);color:var(--color-text);display:flex;flex-direction:column;height:100vh;overflow:hidden}.gve-bar{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-4);background:var(--color-surface);border-bottom:1px solid var(--color-border);flex-wrap:wrap}.gve-bar .title{font-size:var(--text-lg);font-weight:600;margin-right:var(--space-4)}.gve-bar .title small{color:var(--color-text-dim);font-weight:400;margin-left:var(--space-2)}.gve-group{display:flex;align-items:center;gap:var(--space-1);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:2px var(--space-2)}.gve-group label{font-size:var(--text-xs);color:var(--color-text-dim);margin-right:var(--space-1)}.gve-btn{font:inherit;font-size:var(--text-sm);color:var(--color-text);background:transparent;border:none;border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2);cursor:pointer}.gve-btn:hover{background:var(--color-accent-soft)}.gve-btn.active{background:var(--color-accent);color:var(--color-text-inverse)}.gve-input{font:inherit;font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2);width:160px}.gve-select{font:inherit;font-size:var(--text-sm);background:var(--color-surface);color:var(--color-text);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1)}.gve-chip{display:inline-flex;align-items:center;gap:4px;font-size:var(--text-xs);border:1px solid var(--color-border);border-radius:999px;padding:2px var(--space-2);cursor:pointer;background:var(--color-surface);color:var(--color-text)}.gve-chip .dot{width:8px;height:8px;border-radius:50%}.gve-chip.off{opacity:.35}.gve-crumbs{font-size:var(--text-sm);color:var(--color-text-dim)}.gve-crumbs a{color:var(--color-accent);text-decoration:none}.gve-body{flex:1;display:flex;min-height:0}.gve-canvas{flex:1;overflow:auto;position:relative;min-width:0}.gve-explorer{width:260px;flex:0 0 260px;display:flex;flex-direction:column;background:var(--color-surface);border-right:1px solid var(--color-border);overflow:hidden;resize:horizontal}.gve-explorer .exp-tabs{display:flex;border-bottom:1px solid var(--color-border)}.gve-explorer .exp-tab{flex:1;font:inherit;font-size:var(--text-sm);cursor:pointer;background:transparent;border:none;padding:var(--space-2);color:var(--color-text-dim);border-bottom:2px solid transparent}.gve-explorer .exp-tab.active{color:var(--color-text);border-bottom-color:var(--color-accent);font-weight:600}.gve-explorer .exp-tree{flex:1;overflow:auto;padding:var(--space-2) 0;font-size:var(--text-sm)}.gve-tree,.gve-tree ul{list-style:none;margin:0;padding:0}.gve-tree ul{margin-left:14px;border-left:1px solid var(--color-border)}.gve-tree li{position:relative}.gve-tree .row{display:flex;align-items:center;gap:6px;padding:2px var(--space-2);white-space:nowrap;cursor:pointer;border-radius:var(--radius-sm)}.gve-tree .row:hover,.gve-tree .row.sel{background:var(--color-accent-soft)}.gve-tree .tw{width:10px;color:var(--color-text-dim);font-size:10px;flex:none}.gve-tree .ic{width:8px;height:8px;border-radius:2px;flex:none}.gve-tree .ic.ell{border-radius:50%}.gve-tree .lbl{overflow:hidden;text-overflow:ellipsis}.gve-tree .kind{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-details{width:240px;flex:0 0 240px;overflow:auto;background:var(--color-surface);border-left:1px solid var(--color-border);padding:var(--space-3);font-size:var(--text-sm)}.gve-details h4{font-size:var(--text-sm);margin-bottom:var(--space-2)}.gve-details dt{font-size:var(--text-xs);color:var(--color-text-dim);margin-top:var(--space-2)}.gve-details dd{margin:0}.gve-status{display:flex;gap:var(--space-6);align-items:center;padding:var(--space-1) var(--space-4);font-size:var(--text-xs);color:var(--color-text-dim);background:var(--color-surface);border-top:1px solid var(--color-border)}.gve-node rect,.gve-node ellipse{fill:var(--color-surface);stroke:var(--t, var(--color-border));stroke-width:1.5}.gve-node text{font-family:var(--font-ui);font-size:var(--text-sm);fill:var(--color-text)}.gve-node .pill{fill:var(--t)}.gve-node .pill-text{fill:var(--color-text-inverse);font-size:var(--text-xs);font-weight:600}.gve-node.hotspot rect,.gve-node.hotspot ellipse{stroke:var(--color-hotspot);stroke-width:3}.gve-edge{stroke:var(--color-text-dim);fill:none;opacity:.55}.gve-edge.emph{stroke:var(--color-accent);opacity:1}.gve-edge-label{font-size:var(--text-xs);fill:var(--color-text-dim)}.gve-grid{border-collapse:collapse;margin:var(--space-4);font-size:var(--text-sm)}.gve-grid th,.gve-grid td{border:1px solid var(--color-border);padding:var(--space-1) var(--space-2);text-align:left}.gve-grid th{background:var(--color-surface-2);position:sticky;top:0}.gve-grid td.hit{background:var(--color-accent-soft);text-align:center}.gve-grid td.miss{color:var(--color-error);text-align:center}.gve-toast{position:absolute;right:var(--space-4);bottom:var(--space-4);background:var(--color-surface);border:1px solid var(--color-border);border-left:4px solid var(--color-warn);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-3) var(--space-4);font-size:var(--text-sm);max-width:360px}
|
|
1
|
+
.gve-ctx{position:absolute;z-index:30;min-width:220px;max-width:320px;max-height:60vh;overflow-y:auto;display:flex;flex-direction:column;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-1);font-family:var(--font-ui);font-size:var(--text-sm)}.gve-ctx-head{padding:var(--space-1) var(--space-2);font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim);border-bottom:1px solid var(--color-border);margin-bottom:var(--space-1)}.gve-ctx-item{text-align:left;padding:var(--space-1) var(--space-2);background:none;border:none;border-radius:var(--radius-sm);color:var(--color-text);cursor:pointer}.gve-ctx-item:hover:not(:disabled){background:var(--color-accent-soft)}.gve-ctx-item:disabled{color:var(--color-text-dim);cursor:not-allowed}.gve-ctx-form{display:flex;flex-direction:column;gap:var(--space-1);padding:var(--space-2)}.gve-ctx-form label{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-ctx-form input,.gve-ctx-form textarea{font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2)}.gve-ctx-empty{padding:var(--space-1) var(--space-2);color:var(--color-text-dim);font-size:var(--text-xs)}.gve-genesis{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:20;display:flex;flex-direction:column;gap:var(--space-2);min-width:240px;padding:var(--space-3);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);text-align:center}.gve-genesis-title{font-family:var(--font-mono);font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-dim)}.gve-genesis-hint{margin:0;color:var(--color-text-dim)}.gve-genesis-input{font-family:var(--font-ui);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2)}.gve-genesis-create{padding:var(--space-1) var(--space-2);background:var(--color-accent-soft);border:1px solid var(--color-border);border-radius:var(--radius-sm);color:var(--color-text);cursor:pointer}.gve-genesis-create:disabled{color:var(--color-text-dim);cursor:not-allowed}.gve-doc{font-family:var(--font-ui);font-size:var(--text-base);line-height:1.55;color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:var(--space-8) var(--space-6);margin:var(--space-3) auto;max-width:820px}.gve-doc h1{font-size:var(--text-xl);margin:0 0 var(--space-3)}.gve-doc h2{font-size:var(--text-lg);margin:var(--space-6) 0 var(--space-3);padding-bottom:var(--space-1);border-bottom:1px solid var(--color-border)}.gve-doc h3{font-size:var(--text-base);margin:var(--space-4) 0 var(--space-2)}.gve-doc h4,.gve-doc h5,.gve-doc h6{font-size:var(--text-sm);margin:var(--space-3) 0 var(--space-1)}.gve-doc h5 code,.gve-doc h6 code{color:var(--color-text-dim)}.gve-doc p{margin:0 0 var(--space-2)}.gve-doc code{font-family:var(--font-mono);font-size:.92em;background:var(--color-surface-2);border-radius:var(--radius-sm);padding:0 var(--space-1)}.gve-doc blockquote{margin:0 0 var(--space-2);padding-left:var(--space-3);border-left:2px solid var(--color-border);color:var(--color-text-dim);font-size:var(--text-sm)}.gve-doc hr{border:0;border-top:1px solid var(--color-border);margin:var(--space-4) 0}.gve-doc pre.md-code{font-family:var(--font-mono);font-size:var(--text-sm);background:var(--color-surface-2);border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);overflow-x:auto}.edit-pen{margin-left:var(--space-2);font-size:var(--text-xs);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-sm);cursor:pointer}.edit-box{margin:var(--space-2) 0;padding:var(--space-3);background:var(--color-surface-2);border:1px solid var(--color-accent);border-radius:var(--radius-md)}.edit-box textarea{width:100%;box-sizing:border-box;font-family:var(--font-mono);font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-2)}.cmd-preview{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim);background:var(--color-surface);border:1px dashed var(--color-border);border-radius:var(--radius-sm);padding:var(--space-2);overflow-x:auto;white-space:pre-wrap}.edit-actions{display:flex;gap:var(--space-2);align-items:center;margin-top:var(--space-2)}.edit-actions .btn-primary{background:var(--color-accent);color:var(--color-text-inverse);border:1px solid var(--color-accent);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-3);cursor:pointer}.edit-actions .btn-primary:disabled{opacity:.5;cursor:not-allowed}[data-testid=edit-errors],[data-testid=formate-errors]{color:var(--color-error);font-size:var(--text-xs)}[data-testid=edit-verdict][data-tier=block]{color:var(--color-error)}[data-testid=edit-verdict]{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-cards{flex:1;overflow:auto;display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:var(--space-4);padding:var(--space-4);align-content:start}.gve-card{background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-4)}.gve-card-wide{grid-column:1 / -1}.gve-card h3{font-size:var(--text-xs);font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--color-text-dim);margin-bottom:var(--space-3);display:flex;align-items:center;gap:var(--space-2)}.gve-card h4{font-size:var(--text-xs);font-weight:600;color:var(--color-text-dim);margin-bottom:var(--space-2);display:flex;align-items:center;gap:var(--space-2)}.gve-count{font-size:var(--text-xs);font-weight:600;color:var(--color-text-inverse);background:var(--color-accent);border-radius:999px;padding:0 var(--space-2)}.gve-kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:var(--space-3);margin-bottom:var(--space-4)}.gve-kpi-tile{display:flex;flex-direction:column;gap:var(--space-1);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-3)}.gve-kpi-value{font-size:var(--text-xl);font-weight:600;line-height:1.1}.gve-kpi-label{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-kpi-tile[data-tone=ok] .gve-kpi-value{color:var(--color-ok)}.gve-kpi-tile[data-tone=warn] .gve-kpi-value{color:var(--color-warn)}.gve-kpi-tile[data-tone=error] .gve-kpi-value{color:var(--color-error)}.gve-gate-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--space-4)}.gve-gates{list-style:none;padding:0;display:flex;flex-direction:column;gap:var(--space-2)}.gve-gate{display:grid;grid-template-columns:auto 44px 1fr auto 44px;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.gve-light{width:10px;height:10px;border-radius:50%;flex-shrink:0}.gve-light[data-state=passed]{background:var(--color-ok)}.gve-light[data-state=open]{background:var(--color-warn)}.gve-gate-id{font-family:var(--font-mono);font-weight:600}.gve-gate-label{color:var(--color-text-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gve-gate-track{grid-column:4;width:90px;height:12px;background:var(--color-surface-2);border-radius:999px;overflow:hidden}.gve-gate-fill{display:block;height:100%;border-radius:999px}.gve-gate-fill[data-state=passed]{background:var(--color-ok)}.gve-gate-fill[data-state=open]{background:var(--color-warn)}.gve-gate-pct{font-family:var(--font-mono);text-align:right}.gve-gate-blk{grid-column:1 / -1;font-size:var(--text-xs);color:var(--color-warn)}.gve-legend{margin-top:var(--space-3);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-rec-group{margin-bottom:var(--space-4)}.gve-rec-group h4[data-severity=error] .gve-count{background:var(--color-error)}.gve-rec-group h4[data-severity=warning] .gve-count{background:var(--color-warn)}.gve-rec-group h4[data-severity=info] .gve-count{background:var(--color-accent)}.gve-rec{border:1px solid var(--color-border);border-left-width:3px;border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);margin-bottom:var(--space-2);background:var(--color-surface-2)}.gve-rec[data-severity=error]{border-left-color:var(--color-error)}.gve-rec[data-severity=warning]{border-left-color:var(--color-warn)}.gve-rec[data-severity=info]{border-left-color:var(--color-accent)}.gve-rec-head{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-1)}.gve-rid{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-rec-el{color:var(--color-accent)}.gve-sev{font-size:var(--text-xs);font-weight:600;text-transform:uppercase;border-radius:var(--radius-sm);padding:0 var(--space-2)}.gve-sev[data-severity=error]{color:var(--color-error)}.gve-sev[data-severity=warning]{color:var(--color-warn)}.gve-sev[data-severity=info]{color:var(--color-accent)}.gve-rec-msg{font-size:var(--text-sm)}.gve-hint{margin-top:var(--space-1);font-size:var(--text-xs);color:var(--color-text-dim)}.gve-empty{font-size:var(--text-sm);color:var(--color-text-dim)}.gve-rollup summary{cursor:pointer;font-size:var(--text-sm);color:var(--color-text-dim);padding:var(--space-1) 0;-webkit-user-select:none;user-select:none}.gve-rollup summary:hover{color:var(--color-text)}.gve-rollup[open] summary{margin-bottom:var(--space-2)}.gve-fresh-list{list-style:none;padding:0;display:flex;flex-direction:column;gap:var(--space-2)}.gve-fresh-2col{display:grid;grid-template-columns:1fr 1fr;column-gap:var(--space-4)}.gve-fresh-list li{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm)}.gve-fresh-label{flex:1}.gve-fresh-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.gve-fresh-dot[data-freshness=live]{background:var(--color-ok)}.gve-fresh-dot[data-freshness=stale]{background:var(--color-warn)}.gve-fresh-dot[data-freshness=absent]{background:var(--color-error)}.gve-pill{font-size:var(--text-xs);border:1px solid var(--color-border);border-radius:999px;padding:0 var(--space-2)}.gve-pill[data-freshness=live]{border-color:var(--color-ok);color:var(--color-ok)}.gve-pill[data-freshness=stale]{border-color:var(--color-warn);color:var(--color-warn)}.gve-pill[data-freshness=absent]{border-color:var(--color-error);color:var(--color-error)}.gve-health-status{margin-bottom:var(--space-3);text-transform:uppercase}.gve-health-status[data-state=ok]{color:var(--color-ok)}.gve-health-status[data-state=error]{color:var(--color-error)}.gve-vtable{width:100%;border-collapse:collapse;font-size:var(--text-sm)}.gve-vtable td{padding:var(--space-1) var(--space-2);border-bottom:1px solid var(--color-border)}.gve-vtable td:first-child{font-family:var(--font-mono);color:var(--color-text-dim);white-space:nowrap}a.gve-btn{text-decoration:none;display:inline-block}.gve-appbar .title{font-size:var(--text-base)}.gve .gve{height:auto;flex:1;min-height:0}.gve-chip .dash{width:12px;height:0;border-top:2px solid var(--color-text-dim)}.gve .gve-body{flex:1;min-height:0}.gve-canvas,.gve-explorer .exp-tree,.gve-details{overflow:auto}.gve-tree .tw{cursor:pointer;-webkit-user-select:none;user-select:none}.gve-tree .row.sel{box-shadow:inset 2px 0 0 var(--color-accent)}.gve-tree .row.dim{opacity:.45;cursor:default}.gve-grid-scroll{overflow:auto;flex:1;min-height:0}.gve-grid{border-collapse:collapse;font-size:var(--text-sm)}.gve-grid th,.gve-grid td{border:1px solid var(--color-border);padding:var(--space-1) var(--space-2);text-align:left;white-space:nowrap}.gve-grid thead th{position:sticky;top:0;z-index:1;cursor:pointer;-webkit-user-select:none;user-select:none;background:var(--color-surface-alt, var(--color-surface));color:var(--color-text)}.gve-grid thead th.corner{left:0;z-index:2}.gve-grid td.rowhead,.gve-grid th.corner{font-weight:600}.gve-grid td.rowhead{position:sticky;left:0;background:var(--color-surface)}.gve-grid td.hit{background:var(--color-accent-soft);color:var(--color-accent);text-align:center;font-weight:600}.tabular-grid th,.tabular-grid td{max-width:20rem}.tabular-grid:not(.wrap) th,.tabular-grid:not(.wrap) td{overflow:hidden;text-overflow:ellipsis}.tabular-grid.wrap th,.tabular-grid.wrap td{white-space:normal;word-break:break-word;vertical-align:top}.gve-group.tabs .gve-chip.active{background:var(--color-accent-soft);color:var(--color-accent);border-color:var(--color-accent)}:root{--color-bg: #f6f7f9;--color-surface: #ffffff;--color-surface-2: #eef0f3;--color-border: #d7dbe0;--color-text: #1a1d21;--color-text-dim: #5c6470;--color-text-inverse: #ffffff;--color-accent: #2563eb;--color-accent-soft: #dbeafe;--color-ok: #16a34a;--color-warn: #d97706;--color-error: #dc2626;--color-hotspot: #e11d48;--color-type-1: #2563eb;--color-type-2: #7c3aed;--color-type-3: #0891b2;--color-type-4: #16a34a;--color-type-5: #d97706;--color-type-6: #64748b;--color-type-7: #db2777;--color-type-8: #0d9488;--color-type-func: #0d9488;--color-type-flow: #2dd4bf;--color-type-schema: #4f46e5;--fchain-1: #8b5cf6;--fchain-2: #f59e0b;--fchain-3: #ec4899;--fchain-4: #0284c7;--fchain-5: #84cc16;--space-1: 4px;--space-2: 8px;--space-3: 12px;--space-4: 16px;--space-6: 24px;--space-8: 32px;--text-xs: 11px;--text-sm: 12.5px;--text-base: 14px;--text-lg: 16px;--text-xl: 20px;--font-ui: -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono: ui-monospace, "SF Mono", Menlo, monospace;--radius-sm: 4px;--radius-md: 8px;--shadow-1: 0 1px 3px rgba(0,0,0,.12)}@media (prefers-color-scheme: dark){:root{--color-bg: #14161a;--color-surface: #1e2126;--color-surface-2: #262a31;--color-border: #363c45;--color-text: #e8eaed;--color-text-dim: #9aa3af;--color-text-inverse: #14161a;--color-accent: #60a5fa;--color-accent-soft: #1e3a5f;--color-type-2: #8b5cf6;--color-type-schema: #6366f1;--shadow-1: 0 1px 3px rgba(0,0,0,.5)}}*{box-sizing:border-box;margin:0}.gve{font-family:var(--font-ui);font-size:var(--text-base);background:var(--color-bg);color:var(--color-text);display:flex;flex-direction:column;height:100vh;overflow:hidden}.gve-bar{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-4);background:var(--color-surface);border-bottom:1px solid var(--color-border);flex-wrap:wrap}.gve-bar .title{font-size:var(--text-lg);font-weight:600;margin-right:var(--space-4)}.gve-bar .title small{color:var(--color-text-dim);font-weight:400;margin-left:var(--space-2)}.gve-group{display:flex;align-items:center;gap:var(--space-1);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--radius-md);padding:2px var(--space-2)}.gve-group label{font-size:var(--text-xs);color:var(--color-text-dim);margin-right:var(--space-1)}.gve-btn{font:inherit;font-size:var(--text-sm);color:var(--color-text);background:transparent;border:none;border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2);cursor:pointer}.gve-btn:hover{background:var(--color-accent-soft)}.gve-btn.active{background:var(--color-accent);color:var(--color-text-inverse)}.gve-input{font:inherit;font-size:var(--text-sm);color:var(--color-text);background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1) var(--space-2);width:160px}.gve-select{font:inherit;font-size:var(--text-sm);background:var(--color-surface);color:var(--color-text);border:1px solid var(--color-border);border-radius:var(--radius-sm);padding:var(--space-1)}.gve-chip{display:inline-flex;align-items:center;gap:4px;font-size:var(--text-xs);border:1px solid var(--color-border);border-radius:999px;padding:2px var(--space-2);cursor:pointer;background:var(--color-surface);color:var(--color-text)}.gve-chip .dot{width:8px;height:8px;border-radius:50%}.gve-chip.off{opacity:.35}.gve-crumbs{font-size:var(--text-sm);color:var(--color-text-dim)}.gve-crumbs a{color:var(--color-accent);text-decoration:none}.gve-body{flex:1;display:flex;min-height:0}.gve-canvas{flex:1;overflow:auto;position:relative;min-width:0}.gve-explorer{width:260px;flex:0 0 260px;display:flex;flex-direction:column;background:var(--color-surface);border-right:1px solid var(--color-border);overflow:hidden;resize:horizontal}.gve-explorer .exp-tabs{display:flex;border-bottom:1px solid var(--color-border)}.gve-explorer .exp-tab{flex:1;font:inherit;font-size:var(--text-sm);cursor:pointer;background:transparent;border:none;padding:var(--space-2);color:var(--color-text-dim);border-bottom:2px solid transparent}.gve-explorer .exp-tab.active{color:var(--color-text);border-bottom-color:var(--color-accent);font-weight:600}.gve-explorer .exp-tree{flex:1;overflow:auto;padding:var(--space-2) 0;font-size:var(--text-sm)}.gve-tree,.gve-tree ul{list-style:none;margin:0;padding:0}.gve-tree ul{margin-left:14px;border-left:1px solid var(--color-border)}.gve-tree li{position:relative}.gve-tree .row{display:flex;align-items:center;gap:6px;padding:2px var(--space-2);white-space:nowrap;cursor:pointer;border-radius:var(--radius-sm)}.gve-tree .row:hover,.gve-tree .row.sel{background:var(--color-accent-soft)}.gve-tree .tw{width:10px;color:var(--color-text-dim);font-size:10px;flex:none}.gve-tree .ic{width:8px;height:8px;border-radius:2px;flex:none}.gve-tree .ic.ell{border-radius:50%}.gve-tree .lbl{overflow:hidden;text-overflow:ellipsis}.gve-tree .kind{font-size:var(--text-xs);color:var(--color-text-dim)}.gve-details{width:240px;flex:0 0 240px;overflow:auto;background:var(--color-surface);border-left:1px solid var(--color-border);padding:var(--space-3);font-size:var(--text-sm)}.gve-details h4{font-size:var(--text-sm);margin-bottom:var(--space-2)}.gve-details dt{font-size:var(--text-xs);color:var(--color-text-dim);margin-top:var(--space-2)}.gve-details dd{margin:0}.gve-status{display:flex;gap:var(--space-6);align-items:center;padding:var(--space-1) var(--space-4);font-size:var(--text-xs);color:var(--color-text-dim);background:var(--color-surface);border-top:1px solid var(--color-border)}.gve-node rect,.gve-node ellipse{fill:var(--color-surface);stroke:var(--t, var(--color-border));stroke-width:1.5}.gve-node text{font-family:var(--font-ui);font-size:var(--text-sm);fill:var(--color-text)}.gve-node .pill{fill:var(--t)}.gve-node .pill-text{fill:var(--color-text-inverse);font-size:var(--text-xs);font-weight:600}.gve-node.hotspot rect,.gve-node.hotspot ellipse{stroke:var(--color-hotspot);stroke-width:3}.gve-edge{stroke:var(--color-text-dim);fill:none;opacity:.55}.gve-edge.emph{stroke:var(--color-accent);opacity:1}.gve-edge-label{font-size:var(--text-xs);fill:var(--color-text-dim)}.gve-grid{border-collapse:collapse;margin:var(--space-4);font-size:var(--text-sm)}.gve-grid th,.gve-grid td{border:1px solid var(--color-border);padding:var(--space-1) var(--space-2);text-align:left}.gve-grid th{background:var(--color-surface-2);position:sticky;top:0}.gve-grid td.hit{background:var(--color-accent-soft);text-align:center}.gve-grid td.miss{color:var(--color-error);text-align:center}.gve-toast{position:absolute;right:var(--space-4);bottom:var(--space-4);background:var(--color-surface);border:1px solid var(--color-border);border-left:4px solid var(--color-warn);border-radius:var(--radius-md);box-shadow:var(--shadow-1);padding:var(--space-3) var(--space-4);font-size:var(--text-sm);max-width:360px}
|
package/dist/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>graph-view-edit</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-2y8UZ103.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-P7N8B6D1.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sigloch/graph-view-edit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React/Vite viewer+editor over @sigloch/graphcode — 12 graph-views + 16 doc-views via a declarative View-Registry, plus an SE-Dashboard sibling route. Reads docs/graph/<member>.graph.json client-side (no 2nd Kuzu handle).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,15 +21,16 @@
|
|
|
21
21
|
},
|
|
22
22
|
"comment:deps": "Runtime = what vite.config.js + bin/gve.mjs load at Node level when serving the prebuilt dist/. The UI libs (react, react-dom, elkjs, @tanstack/react-table, zustand) are bundled INTO dist/ by vite and must stay devDependencies — shipping them would make consumers download the whole UI stack twice.",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@sigloch/contracts": "^
|
|
25
|
-
"@sigloch/graph-api-core": "^0.
|
|
26
|
-
"@sigloch/graphcode-client": "^0.
|
|
24
|
+
"@sigloch/contracts": "^4.1.0",
|
|
25
|
+
"@sigloch/graph-api-core": "^3.0.0",
|
|
26
|
+
"@sigloch/graphcode-client": "^0.9.0",
|
|
27
27
|
"@vitejs/plugin-react": "^4.3.4",
|
|
28
28
|
"vite": "^5.4.11",
|
|
29
29
|
"zod": "^4.3.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@playwright/test": "^1.58.2",
|
|
33
|
+
"@sigloch/graphcode": "^0.13.0",
|
|
33
34
|
"@tanstack/react-table": "^8.20.5",
|
|
34
35
|
"@testing-library/react": "^16.0.1",
|
|
35
36
|
"elkjs": "^0.11.1",
|
package/vite.config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { readFileSync, existsSync, readdirSync, statSync, watch } from 'node:fs';
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, unlinkSync, existsSync, readdirSync, realpathSync, statSync, watch } from 'node:fs';
|
|
2
2
|
import { join, basename } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import { defineConfig } from 'vite';
|
|
4
5
|
import react from '@vitejs/plugin-react';
|
|
5
6
|
import { DefaultRuleEngine, SE_DESCRIPTOR } from '@sigloch/graph-api-core';
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
artifactsPanel,
|
|
16
17
|
healthPanel,
|
|
17
18
|
VIEW_FILENAMES,
|
|
19
|
+
ARTIFACT_CATALOG,
|
|
20
|
+
analysisCreationCurrencyProvider,
|
|
18
21
|
callHost,
|
|
19
22
|
HOST_SOCK_BASENAME,
|
|
20
23
|
} from '@sigloch/graphcode-client';
|
|
@@ -50,6 +53,40 @@ function resolveRepoRoot() {
|
|
|
50
53
|
return process.env.GVE_REPO_ROOT || process.cwd();
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* The repo this instance serves, as a PHYSICAL path — the identity signal a
|
|
58
|
+
* launcher needs to tell "the viewer already serving MY repo" apart from "some
|
|
59
|
+
* other repo's viewer that happens to answer on this port".
|
|
60
|
+
*
|
|
61
|
+
* Why it must be published: every GVE defaults to the SAME port (config.port),
|
|
62
|
+
* and Vite bumps on conflict — so a docs/views/dashboard.url written when this
|
|
63
|
+
* repo held the default port is routinely answered LATER by a foreign instance
|
|
64
|
+
* that took it. graphcode's autostart could only compare `member` (the graph
|
|
65
|
+
* filename), which is empty for a repo that has no graph yet and identical for
|
|
66
|
+
* two repos of the same name. Real path, not the raw argument, so a symlinked
|
|
67
|
+
* launch path (/var vs /private/var on macOS) still compares equal.
|
|
68
|
+
*/
|
|
69
|
+
function servedRepoRoot() {
|
|
70
|
+
const root = resolveRepoRoot();
|
|
71
|
+
try {
|
|
72
|
+
return realpathSync(root);
|
|
73
|
+
} catch {
|
|
74
|
+
return root; // never let identity reporting break the dashboard
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The viewer's OWN version for the Health-Versionstabelle — read from THIS
|
|
80
|
+
* package's package.json via import.meta.url, deliberately NOT from
|
|
81
|
+
* resolveRepoRoot(): under GVE_REPO_ROOT the viewer serves a foreign repo,
|
|
82
|
+
* whose package.json version is that repo's, not the viewer's. The table
|
|
83
|
+
* listed ontology/rules/engine but never the app rendering them, so a bug
|
|
84
|
+
* report could not say WHICH GVE produced the screen.
|
|
85
|
+
*/
|
|
86
|
+
const GVE_VERSION = JSON.parse(
|
|
87
|
+
readFileSync(fileURLToPath(new URL('./package.json', import.meta.url)), 'utf8'),
|
|
88
|
+
).version;
|
|
89
|
+
|
|
53
90
|
/**
|
|
54
91
|
* Serves docs/graph/*.json from the resolved repo root (CR-GVE-127) instead
|
|
55
92
|
* of relying on Vite's default static passthrough from its OWN project
|
|
@@ -121,6 +158,52 @@ function configApiPlugin() {
|
|
|
121
158
|
* middleware is the safe place for that computation; the React dashboard
|
|
122
159
|
* just fetches the JSON like any other static resource.
|
|
123
160
|
*/
|
|
161
|
+
/**
|
|
162
|
+
* docs/graph/*.graph.json ⇄ graph-api-core's Graph{nodes,edges} — the ONE
|
|
163
|
+
* definition of this repo's wire format (audit F5). graph-api-core/browser
|
|
164
|
+
* exports only the forward direction (`projectToOntologyGraph`: Graph →
|
|
165
|
+
* OntologyGraph, what graph_export itself uses to WRITE this file) — no
|
|
166
|
+
* inverse is published, so this is that function's exact mirror image,
|
|
167
|
+
* derived by reading its field-lift contract (se-descriptor.ts) rather than
|
|
168
|
+
* re-guessing the shape: status/asil/method/kinds live inside `attributes`
|
|
169
|
+
* (that's where projectToOntologyGraph reads them back out of), created_at/
|
|
170
|
+
* updated_at are GraphNode's own top-level camelCase fields (never inside
|
|
171
|
+
* attributes, or `projectToOntologyGraph` would read them back as '').
|
|
172
|
+
* `tests/vite-config-load-graph.test.mjs` pins the round trip against the
|
|
173
|
+
* REAL projectToOntologyGraph, so a drift in either direction fails loud.
|
|
174
|
+
*/
|
|
175
|
+
export function loadGraph(file) {
|
|
176
|
+
const json = JSON.parse(readFileSync(file, 'utf8'));
|
|
177
|
+
const nodes = (json.elements ?? []).map((e) => ({
|
|
178
|
+
uid: e.id,
|
|
179
|
+
type: e.type,
|
|
180
|
+
name: e.name,
|
|
181
|
+
description: e.description ?? '',
|
|
182
|
+
createdAt: e.created_at,
|
|
183
|
+
updatedAt: e.updated_at,
|
|
184
|
+
attributes: { ...(e.attributes ?? {}), status: e.status, asil: e.asil, method: e.method, kinds: e.kinds },
|
|
185
|
+
}));
|
|
186
|
+
const edges = (json.traces ?? []).map((t) => ({
|
|
187
|
+
sourceId: t.source,
|
|
188
|
+
targetId: t.target,
|
|
189
|
+
edgeType: t.type,
|
|
190
|
+
attributes: {
|
|
191
|
+
...(t.attributes ?? {}),
|
|
192
|
+
category: t.category,
|
|
193
|
+
label: t.label,
|
|
194
|
+
weight: t.weight,
|
|
195
|
+
created_at: t.created_at,
|
|
196
|
+
verified_at: t.verified_at,
|
|
197
|
+
},
|
|
198
|
+
}));
|
|
199
|
+
// CR-GC-300: graph_export now stamps graphVersion at write time — the live
|
|
200
|
+
// comparison value computeAnalysisCurrency() needs against each analysis
|
|
201
|
+
// artifact's SYS.attributes.analysisFreshness.<id>.graphVersion stamp
|
|
202
|
+
// (CR-GVE-229). Missing on a pre-CR-GC-300 export → 0, which reads every
|
|
203
|
+
// stamp as stale/current per its own value rather than crashing.
|
|
204
|
+
return { nodes, edges, graphVersion: json.graphVersion ?? 0 };
|
|
205
|
+
}
|
|
206
|
+
|
|
124
207
|
function dashboardApiPlugin() {
|
|
125
208
|
const cwd = resolveRepoRoot();
|
|
126
209
|
const GRAPH_DIR = join(cwd, 'docs', 'graph');
|
|
@@ -134,26 +217,29 @@ function dashboardApiPlugin() {
|
|
|
134
217
|
return hit ? join(GRAPH_DIR, hit) : null;
|
|
135
218
|
}
|
|
136
219
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const { source, target, type, ...rest } = t;
|
|
145
|
-
return { sourceId: source, targetId: target, edgeType: type, attributes: rest };
|
|
146
|
-
});
|
|
147
|
-
return { nodes, edges };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function scanArtifacts(graphFile) {
|
|
220
|
+
/**
|
|
221
|
+
* Artifact set = ARTIFACT_CATALOG (CR-GVE-225/F10), not VIEW_FILENAMES —
|
|
222
|
+
* the catalog also carries the 5 `kind:'analysis'` creations (conops/fmea/
|
|
223
|
+
* trade/implplan/assumption-review), which VIEW_FILENAMES's markdown-view
|
|
224
|
+
* vocabulary never listed, so they never reached the dashboard before.
|
|
225
|
+
*/
|
|
226
|
+
function scanArtifacts(graphFile, graph) {
|
|
151
227
|
const graphMtime = existsSync(graphFile) ? statSync(graphFile).mtimeMs : 0;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
228
|
+
// Real scope-currency (CR-SM-227/CR-GVE-229): each analysis artifact's
|
|
229
|
+
// SYS.attributes.analysisFreshness.<id> stamp vs. the live graphVersion
|
|
230
|
+
// graph_export now writes (CR-GC-300) — never via mtime (CR-GC-222's
|
|
231
|
+
// mtime-for-judgment-work conflation artifactsPanel's kind split guards
|
|
232
|
+
// against).
|
|
233
|
+
const analysisCurrency = analysisCreationCurrencyProvider(graph, graph.graphVersion);
|
|
234
|
+
const items = ARTIFACT_CATALOG.map((entry) => {
|
|
235
|
+
if (entry.kind === 'analysis') {
|
|
236
|
+
return { id: entry.id, currency: analysisCurrency(entry.id) };
|
|
237
|
+
}
|
|
238
|
+
const fname = VIEW_FILENAMES[entry.id];
|
|
239
|
+
const p = fname ? join(VIEWS_DIR, fname) : null;
|
|
240
|
+
const exists = !!p && existsSync(p);
|
|
155
241
|
const staleVsGraph = exists ? statSync(p).mtimeMs < graphMtime : false;
|
|
156
|
-
return { id
|
|
242
|
+
return { id: entry.id, exists, staleVsGraph };
|
|
157
243
|
});
|
|
158
244
|
return artifactsPanel(items);
|
|
159
245
|
}
|
|
@@ -164,6 +250,7 @@ function dashboardApiPlugin() {
|
|
|
164
250
|
store: 'committed graph.json (read-only)',
|
|
165
251
|
gate: 'n/a — dashboard is read-only (writes go through MCP mutate())',
|
|
166
252
|
versions: {
|
|
253
|
+
gve: GVE_VERSION,
|
|
167
254
|
ontology: ONTOLOGY_VERSION,
|
|
168
255
|
rules: RULES_VERSION,
|
|
169
256
|
engine: SE_DESCRIPTOR.version,
|
|
@@ -175,16 +262,17 @@ function dashboardApiPlugin() {
|
|
|
175
262
|
|
|
176
263
|
function buildDashboard() {
|
|
177
264
|
const file = findGraphFile();
|
|
178
|
-
if (!file) return { member: null, empty: true, error: 'no docs/graph/*.graph.json found', computedAt: new Date().toISOString() };
|
|
265
|
+
if (!file) return { member: null, repoRoot: servedRepoRoot(), empty: true, error: 'no docs/graph/*.graph.json found', computedAt: new Date().toISOString() };
|
|
179
266
|
const graph = loadGraph(file);
|
|
180
267
|
const violations = engine.evaluate(graph);
|
|
181
268
|
const report = computeReadiness(violations, graph);
|
|
182
269
|
return {
|
|
183
270
|
member: basename(file).replace(/\.graph\.json$/, ''),
|
|
271
|
+
repoRoot: servedRepoRoot(),
|
|
184
272
|
empty: graph.nodes.length === 0,
|
|
185
273
|
readiness: readinessPanel(report),
|
|
186
274
|
recommendations: recommendationsPanel(violations, 50),
|
|
187
|
-
artifacts: scanArtifacts(file),
|
|
275
|
+
artifacts: scanArtifacts(file, graph),
|
|
188
276
|
health: synthHealth(graph),
|
|
189
277
|
computedAt: new Date().toISOString(),
|
|
190
278
|
};
|
|
@@ -391,13 +479,61 @@ function eventsApiPlugin() {
|
|
|
391
479
|
};
|
|
392
480
|
}
|
|
393
481
|
|
|
482
|
+
/**
|
|
483
|
+
* docs/views/dashboard.url — announce the ACTUAL bound address in the target
|
|
484
|
+
* repo once the server is listening. The port is dynamic (Vite bumps on
|
|
485
|
+
* conflict), so no static link can carry it — agents/parallel sessions read
|
|
486
|
+
* this one-line file instead of probing ports. Written at listen, removed at
|
|
487
|
+
* close; the close handler only deletes the file while it still carries THIS
|
|
488
|
+
* instance's URL, so shutting down an old instance never deletes the file a
|
|
489
|
+
* newer instance just wrote.
|
|
490
|
+
*/
|
|
491
|
+
function dashboardUrlPlugin() {
|
|
492
|
+
let file = null;
|
|
493
|
+
let url = null;
|
|
494
|
+
const wire = (server) => {
|
|
495
|
+
const httpServer = server.httpServer;
|
|
496
|
+
if (!httpServer) return;
|
|
497
|
+
httpServer.once('listening', () => {
|
|
498
|
+
const addr = httpServer.address();
|
|
499
|
+
if (!addr || typeof addr === 'string') return;
|
|
500
|
+
url = `http://localhost:${addr.port}/`;
|
|
501
|
+
const dir = join(resolveRepoRoot(), 'docs', 'views');
|
|
502
|
+
mkdirSync(dir, { recursive: true });
|
|
503
|
+
file = join(dir, 'dashboard.url');
|
|
504
|
+
writeFileSync(file, `${url}\n`);
|
|
505
|
+
});
|
|
506
|
+
httpServer.once('close', () => {
|
|
507
|
+
if (!file) return;
|
|
508
|
+
try {
|
|
509
|
+
if (readFileSync(file, 'utf8').trim() === url.trim()) unlinkSync(file);
|
|
510
|
+
} catch {
|
|
511
|
+
/* already gone */
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
};
|
|
515
|
+
return {
|
|
516
|
+
name: 'gve-dashboard-url',
|
|
517
|
+
configureServer: wire,
|
|
518
|
+
configurePreviewServer: wire,
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
|
|
394
522
|
export default defineConfig({
|
|
395
|
-
plugins: [react(), graphStaticPlugin(), configApiPlugin(), dashboardApiPlugin(), mutateApiPlugin(), eventsApiPlugin()],
|
|
523
|
+
plugins: [react(), graphStaticPlugin(), configApiPlugin(), dashboardApiPlugin(), mutateApiPlugin(), eventsApiPlugin(), dashboardUrlPlugin()],
|
|
396
524
|
// config.port is the default; an explicit CLI --port (e.g. the test suites'
|
|
397
525
|
// tests/helpers/dev-server.mjs, which picks a free OS-assigned port with
|
|
398
526
|
// --strictPort) still overrides it, per Vite's precedence.
|
|
399
527
|
server: { port: APP_CONFIG.port },
|
|
400
528
|
preview: { port: APP_CONFIG.port },
|
|
529
|
+
// Kein resolve.alias mehr (CR-GVE-230): bis graphcode-client@0.8.x gab es nur
|
|
530
|
+
// den Barrel-Entry ("exports": {".": "./dist/index.js"}), dessen Kette über
|
|
531
|
+
// host-client.js (`node:net`) und readiness.js in graph-api-core's audit.js
|
|
532
|
+
// (`node:fs`/`node:path`) lief — im Browser-Build ein harter Fehlschlag an
|
|
533
|
+
// Vites `node:*`-Stubs. Seit 0.9.0 sind view-catalog und panels eigene
|
|
534
|
+
// Subpaths, transitiv frei von `node:` und dort per Purity-Test abgesichert.
|
|
535
|
+
// Ein Alias in fremdes dist/ hinein war das Symptom eines kaputten Pakets;
|
|
536
|
+
// ihn zu löschen ist die Gegenprobe (CR-SM-230, Akzeptanzkriterium 2).
|
|
401
537
|
test: {
|
|
402
538
|
// Vitest's own default (test/spec files) plus the NFR regression guards
|
|
403
539
|
// (CR-GVE-115), which intentionally use .bench.mjs/.smoke.mjs names to
|